Add initial support for optional luadata.txt datafile
[freeciv.git] / server / ruleset.c
blob78fb9d8055562689c346386cd0d062d3b1a7d2fa
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,
225 bool optional)
227 char filename[512];
228 const char *dfilename;
230 fc_assert_ret_val(subdir && name && extension, NULL);
232 fc_snprintf(filename, sizeof(filename), "%s" DIR_SEPARATOR "%s.%s",
233 subdir, name, extension);
234 log_verbose("Trying \"%s\".", filename);
235 dfilename = fileinfoname(get_data_dirs(), filename);
236 if (dfilename) {
237 return dfilename;
240 fc_snprintf(filename, sizeof(filename), "default" DIR_SEPARATOR "%s.%s", name, extension);
241 log_verbose("Trying \"%s\": default ruleset directory.", filename);
242 dfilename = fileinfoname(get_data_dirs(), filename);
243 if (dfilename) {
244 return dfilename;
247 fc_snprintf(filename, sizeof(filename), "%s_%s.%s",
248 subdir, name, extension);
249 log_verbose("Trying \"%s\": alternative ruleset filename syntax.",
250 filename);
251 dfilename = fileinfoname(get_data_dirs(), filename);
252 if (dfilename) {
253 return dfilename;
254 } else if (!optional) {
255 ruleset_error(LOG_ERROR,
256 /* TRANS: message about an installation error. */
257 _("Could not find a readable \"%s.%s\" ruleset file."),
258 name, extension);
261 return NULL;
264 /**************************************************************************
265 Return current script.lua buffer.
266 **************************************************************************/
267 char *get_script_buffer(void)
269 return script_buffer;
272 /**************************************************************************
273 Do initial section_file_load on a ruleset file.
274 "whichset" = "techs", "units", "buildings", "terrain", ...
275 **************************************************************************/
276 static struct section_file *openload_ruleset_file(const char *whichset,
277 const char *rsdir)
279 char sfilename[512];
280 const char *dfilename = valid_ruleset_filename(rsdir, whichset,
281 RULES_SUFFIX, FALSE);
282 struct section_file *secfile;
284 if (dfilename == NULL) {
285 return NULL;
288 /* Need to save a copy of the filename for following message, since
289 section_file_load() may call datafilename() for includes. */
290 sz_strlcpy(sfilename, dfilename);
291 secfile = secfile_load(sfilename, FALSE);
293 if (secfile == NULL) {
294 ruleset_error(LOG_ERROR, "Could not load ruleset '%s':\n%s",
295 sfilename, secfile_error());
298 return secfile;
301 /**************************************************************************
302 Parse script file.
303 **************************************************************************/
304 static bool openload_script_file(const char *whichset, const char *rsdir,
305 char **buffer)
307 const char *dfilename = valid_ruleset_filename(rsdir, whichset,
308 SCRIPT_SUFFIX, FALSE);
310 if (dfilename == NULL) {
311 return FALSE;
314 if (buffer == NULL) {
315 if (!script_server_do_file(NULL, dfilename)) {
316 ruleset_error(LOG_ERROR, "\"%s\": could not load ruleset script.",
317 dfilename);
319 return FALSE;
321 } else {
322 script_server_load_file(dfilename, buffer);
325 return TRUE;
328 /**************************************************************************
329 Load optional luadata.txt
330 **************************************************************************/
331 static struct section_file *openload_luadata_file(const char *rsdir)
333 struct section_file *secfile;
334 char sfilename[512];
335 const char *dfilename = valid_ruleset_filename(rsdir, "luadata",
336 "txt", TRUE);
338 if (dfilename == NULL) {
339 return NULL;
342 /* Need to save a copy of the filename for following message, since
343 section_file_load() may call datafilename() for includes. */
344 sz_strlcpy(sfilename, dfilename);
345 secfile = secfile_load(sfilename, FALSE);
347 if (secfile == NULL) {
348 ruleset_error(LOG_ERROR, "Could not load luadata '%s':\n%s",
349 sfilename, secfile_error());
352 return secfile;
355 /**************************************************************************
356 Load a requirement list. The list is returned as a static vector
357 (callers need not worry about freeing anything).
358 **************************************************************************/
359 static struct requirement_vector *lookup_req_list(struct section_file *file,
360 struct rscompat_info *compat,
361 const char *sec,
362 const char *sub,
363 const char *rfor)
365 const char *type, *name;
366 int j;
367 const char *filename;
369 filename = secfile_name(file);
371 requirement_vector_reserve(&reqs_list, 0);
373 for (j = 0; (type = secfile_lookup_str_default(file, NULL, "%s.%s%d.type",
374 sec, sub, j)); j++) {
375 char buf[MAX_LEN_NAME];
376 const char *range;
377 bool survives, present, quiet;
378 struct entry *pentry;
379 struct requirement req;
381 if (!(pentry = secfile_entry_lookup(file, "%s.%s%d.name",
382 sec, sub, j))) {
383 ruleset_error(LOG_ERROR, "%s", secfile_error());
385 return NULL;
387 name = NULL;
388 switch (entry_type(pentry)) {
389 case ENTRY_BOOL:
391 bool val;
393 if (entry_bool_get(pentry, &val)) {
394 fc_snprintf(buf, sizeof(buf), "%d", val);
395 name = buf;
398 break;
399 case ENTRY_INT:
401 int val;
403 if (entry_int_get(pentry, &val)) {
404 fc_snprintf(buf, sizeof(buf), "%d", val);
405 name = buf;
408 break;
409 case ENTRY_STR:
410 (void) entry_str_get(pentry, &name);
411 break;
412 case ENTRY_FLOAT:
413 fc_assert(entry_type(pentry) != ENTRY_FLOAT);
414 ruleset_error(LOG_ERROR,
415 "\"%s\": trying to have an floating point entry as a requirement name in '%s.%s%d'.",
416 filename, sec, sub, j);
417 break;
418 case ENTRY_FILEREFERENCE:
419 fc_assert(entry_type(pentry) != ENTRY_FILEREFERENCE);
421 if (NULL == name) {
422 ruleset_error(LOG_ERROR,
423 "\"%s\": error in handling requirement name for '%s.%s%d'.",
424 filename, sec, sub, j);
425 return NULL;
428 if (!(range = secfile_lookup_str(file, "%s.%s%d.range", sec, sub, j))) {
429 ruleset_error(LOG_ERROR, "%s", secfile_error());
431 return NULL;
434 survives = FALSE;
435 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.survives",
436 sec, sub, j))
437 && !entry_bool_get(pentry, &survives)) {
438 ruleset_error(LOG_ERROR,
439 "\"%s\": invalid boolean value for survives for "
440 "'%s.%s%d'.", filename, sec, sub, j);
443 present = TRUE;
444 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.present",
445 sec, sub, j))
446 && !entry_bool_get(pentry, &present)) {
447 ruleset_error(LOG_ERROR,
448 "\"%s\": invalid boolean value for present for "
449 "'%s.%s%d'.", filename, sec, sub, j);
451 quiet = FALSE;
452 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.quiet",
453 sec, sub, j))
454 && !entry_bool_get(pentry, &quiet)) {
455 ruleset_error(LOG_ERROR,
456 "\"%s\": invalid boolean value for quiet for "
457 "'%s.%s%d'.", filename, sec, sub, j);
460 if (compat->compat_mode) {
461 if (!fc_strcasecmp(type, universals_n_name(VUT_UTFLAG))) {
462 name = rscompat_utype_flag_name_3_1(compat, name);
466 if (compat->compat_mode) {
467 name = rscompat_req_name_3_1(type, name);
470 req = req_from_str(type, range, survives, present, quiet, name);
471 if (req.source.kind == universals_n_invalid()) {
472 ruleset_error(LOG_ERROR, "\"%s\" [%s] has invalid or unknown req: "
473 "\"%s\" \"%s\".",
474 filename, sec, type, name);
476 return NULL;
479 requirement_vector_append(&reqs_list, req);
482 if (j > MAX_NUM_REQS) {
483 ruleset_error(LOG_ERROR, "Too many (%d) requirements for %s. Max is %d",
484 j, rfor, MAX_NUM_REQS);
486 return NULL;
489 return &reqs_list;
492 /**************************************************************************
493 Load combat bonus list
494 **************************************************************************/
495 static bool lookup_cbonus_list(struct rscompat_info *compat,
496 struct combat_bonus_list *list,
497 struct section_file *file,
498 const char *sec,
499 const char *sub)
501 const char *flag;
502 int j;
503 const char *filename;
504 bool success = TRUE;
506 filename = secfile_name(file);
508 for (j = 0; (flag = secfile_lookup_str_default(file, NULL, "%s.%s%d.flag",
509 sec, sub, j)); j++) {
510 struct combat_bonus *bonus = fc_malloc(sizeof(*bonus));
511 const char *type;
513 bonus->flag = unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat, flag),
514 fc_strcasecmp);
515 if (!unit_type_flag_id_is_valid(bonus->flag)) {
516 log_error("\"%s\": unknown flag name \"%s\" in '%s.%s'.",
517 filename, flag, sec, sub);
518 FC_FREE(bonus);
519 success = FALSE;
520 continue;
522 type = secfile_lookup_str(file, "%s.%s%d.type", sec, sub, j);
523 bonus->type = combat_bonus_type_by_name(type, fc_strcasecmp);
524 if (!combat_bonus_type_is_valid(bonus->type)) {
525 log_error("\"%s\": unknown bonus type \"%s\" in '%s.%s'.",
526 filename, type, sec, sub);
527 FC_FREE(bonus);
528 success = FALSE;
529 continue;
531 if (!secfile_lookup_int(file, &bonus->value, "%s.%s%d.value",
532 sec, sub, j)) {
533 log_error("\"%s\": failed to get value from '%s.%s%d'.",
534 filename, sec, sub, j);
535 FC_FREE(bonus);
536 success = FALSE;
537 continue;
539 bonus->quiet = secfile_lookup_bool_default(file, FALSE,
540 "%s.%s%d.quiet",
541 sec, sub, j);
542 combat_bonus_list_append(list, bonus);
545 return success;
548 /**************************************************************************
549 Lookup a string prefix.entry in the file and return the corresponding
550 advances pointer. If (!required), return A_NEVER for match "Never" or
551 can't match. If (required), die when can't match. Note the first tech
552 should have name "None" so that will always match.
553 If description is not NULL, it is used in the warning message
554 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
555 **************************************************************************/
556 static bool lookup_tech(struct section_file *file,
557 struct advance **result,
558 const char *prefix, const char *entry,
559 const char *filename,
560 const char *description)
562 const char *sval;
564 sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
565 if (!sval || !strcmp(sval, "Never")) {
566 *result = A_NEVER;
567 } else {
568 *result = advance_by_rule_name(sval);
570 if (A_NEVER == *result) {
571 ruleset_error(LOG_ERROR,
572 "\"%s\" %s %s: couldn't match \"%s\".",
573 filename, (description ? description : prefix), entry, sval);
574 return FALSE;
578 return TRUE;
581 /**************************************************************************
582 Lookup a string prefix.entry in the file and return the corresponding
583 improvement pointer. Return B_NEVER for match "None" or
584 can't match.
585 If description is not NULL, it is used in the warning message
586 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
587 **************************************************************************/
588 static bool lookup_building(struct section_file *file,
589 const char *prefix, const char *entry,
590 struct impr_type **result,
591 const char *filename,
592 const char *description)
594 const char *sval;
595 bool ok = TRUE;
597 sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
598 if (!sval || strcmp(sval, "None") == 0) {
599 *result = B_NEVER;
600 } else {
601 *result = improvement_by_rule_name(sval);
603 if (B_NEVER == *result) {
604 ruleset_error(LOG_ERROR,
605 "\"%s\" %s %s: couldn't match \"%s\".",
606 filename, (description ? description : prefix), entry, sval);
607 ok = FALSE;
611 return ok;
614 /**************************************************************************
615 Lookup a prefix.entry string vector in the file and fill in the
616 array, which should hold MAX_NUM_UNIT_LIST items. The output array is
617 either NULL terminated or full (contains MAX_NUM_UNIT_LIST
618 items). If the vector is not found and the required parameter is set,
619 we report it as an error, otherwise we just punt.
620 **************************************************************************/
621 static bool lookup_unit_list(struct section_file *file, const char *prefix,
622 const char *entry,
623 struct unit_type **output,
624 const char *filename)
626 const char **slist;
627 size_t nval;
628 int i;
629 bool ok = TRUE;
631 /* pre-fill with NULL: */
632 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
633 output[i] = NULL;
635 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
636 if (nval == 0) {
637 /* 'No vector' is considered same as empty vector */
638 if (slist != NULL) {
639 free(slist);
641 return TRUE;
643 if (nval > MAX_NUM_UNIT_LIST) {
644 ruleset_error(LOG_ERROR,
645 "\"%s\": string vector %s.%s too long (%d, max %d)",
646 filename, prefix, entry, (int) nval, MAX_NUM_UNIT_LIST);
647 ok = FALSE;
648 } else if (nval == 1 && strcmp(slist[0], "") == 0) {
649 free(slist);
650 return TRUE;
652 if (ok) {
653 for (i = 0; i < nval; i++) {
654 const char *sval = slist[i];
655 struct unit_type *punittype = unit_type_by_rule_name(sval);
657 if (!punittype) {
658 ruleset_error(LOG_ERROR,
659 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
660 filename, prefix, entry, i, sval);
661 ok = FALSE;
662 break;
664 output[i] = punittype;
665 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
666 utype_number(punittype));
669 free(slist);
671 return ok;
674 /**************************************************************************
675 Lookup a prefix.entry string vector in the file and fill in the
676 array, which should hold MAX_NUM_TECH_LIST items. The output array is
677 either A_LAST terminated or full (contains MAX_NUM_TECH_LIST
678 items). All valid entries of the output array are guaranteed to
679 exist.
680 **************************************************************************/
681 static bool lookup_tech_list(struct section_file *file, const char *prefix,
682 const char *entry, int *output,
683 const char *filename)
685 const char **slist;
686 size_t nval;
687 int i;
688 bool ok = TRUE;
690 /* pre-fill with A_LAST: */
691 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
692 output[i] = A_LAST;
694 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
695 if (slist == NULL || nval == 0) {
696 return TRUE;
697 } else if (nval > MAX_NUM_TECH_LIST) {
698 ruleset_error(LOG_ERROR,
699 "\"%s\": string vector %s.%s too long (%d, max %d)",
700 filename, prefix, entry, (int) nval, MAX_NUM_TECH_LIST);
701 ok = FALSE;
704 if (ok) {
705 if (nval == 1 && strcmp(slist[0], "") == 0) {
706 FC_FREE(slist);
707 return TRUE;
709 for (i = 0; i < nval && ok; i++) {
710 const char *sval = slist[i];
711 struct advance *padvance = advance_by_rule_name(sval);
713 if (NULL == padvance) {
714 ruleset_error(LOG_ERROR,
715 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
716 filename, prefix, entry, i, sval);
717 ok = FALSE;
719 if (!valid_advance(padvance)) {
720 ruleset_error(LOG_ERROR, "\"%s\" %s.%s (%d): \"%s\" is removed.",
721 filename, prefix, entry, i, sval);
722 ok = FALSE;
725 if (ok) {
726 output[i] = advance_number(padvance);
727 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
728 advance_number(padvance));
732 FC_FREE(slist);
734 return ok;
737 /**************************************************************************
738 Lookup a prefix.entry string vector in the file and fill in the
739 array, which should hold MAX_NUM_BUILDING_LIST items. The output array is
740 either B_LAST terminated or full (contains MAX_NUM_BUILDING_LIST
741 items). [All valid entries of the output array are guaranteed to pass
742 improvement_exist()?]
743 **************************************************************************/
744 static bool lookup_building_list(struct section_file *file,
745 const char *prefix, const char *entry,
746 int *output, const char *filename)
748 const char **slist;
749 size_t nval;
750 int i;
751 bool ok = TRUE;
753 /* pre-fill with B_LAST: */
754 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
755 output[i] = B_LAST;
757 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
758 if (nval > MAX_NUM_BUILDING_LIST) {
759 ruleset_error(LOG_ERROR,
760 "\"%s\": string vector %s.%s too long (%d, max %d)",
761 filename, prefix, entry, (int) nval, MAX_NUM_BUILDING_LIST);
762 ok = FALSE;
763 } else if (nval == 0 || (nval == 1 && strcmp(slist[0], "") == 0)) {
764 if (slist != NULL) {
765 FC_FREE(slist);
767 return TRUE;
769 if (ok) {
770 for (i = 0; i < nval; i++) {
771 const char *sval = slist[i];
772 struct impr_type *pimprove = improvement_by_rule_name(sval);
774 if (NULL == pimprove) {
775 ruleset_error(LOG_ERROR,
776 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
777 filename, prefix, entry, i, sval);
778 ok = FALSE;
779 break;
781 output[i] = improvement_number(pimprove);
782 log_debug("%s.%s,%d %s %d", prefix, entry, i, sval, output[i]);
785 free(slist);
787 return ok;
790 /**************************************************************************
791 Lookup a string prefix.entry in the file and set result to the corresponding
792 unit_type.
793 If description is not NULL, it is used in the warning message
794 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
795 **************************************************************************/
796 static bool lookup_unit_type(struct section_file *file,
797 const char *prefix,
798 const char *entry,
799 struct unit_type **result,
800 const char *filename,
801 const char *description)
803 const char *sval;
805 sval = secfile_lookup_str_default(file, "None", "%s.%s", prefix, entry);
807 if (strcmp(sval, "None") == 0) {
808 *result = NULL;
809 } else {
810 *result = unit_type_by_rule_name(sval);
811 if (*result == NULL) {
812 ruleset_error(LOG_ERROR,
813 "\"%s\" %s %s: couldn't match \"%s\".",
814 filename, (description ? description : prefix), entry, sval);
816 return FALSE;
820 return TRUE;
823 /**************************************************************************
824 Lookup entry in the file and return the corresponding government index.
825 filename is for error message.
826 **************************************************************************/
827 static struct government *lookup_government(struct section_file *file,
828 const char *entry,
829 const char *filename,
830 struct government *fallback)
832 const char *sval;
833 struct government *gov;
835 sval = secfile_lookup_str_default(file, NULL, "%s", entry);
836 if (!sval) {
837 gov = fallback;
838 } else {
839 gov = government_by_rule_name(sval);
841 if (!gov) {
842 ruleset_error(LOG_ERROR,
843 "\"%s\" %s: couldn't match \"%s\".",
844 filename, entry, sval);
846 return gov;
849 /****************************************************************************
850 Lookup optional string, returning allocated memory or NULL.
851 ****************************************************************************/
852 static char *lookup_string(struct section_file *file, const char *prefix,
853 const char *suffix)
855 const char *sval = secfile_lookup_str(file, "%s.%s", prefix, suffix);
857 if (NULL != sval) {
858 char copy[strlen(sval) + 1];
860 strcpy(copy, sval);
861 remove_leading_trailing_spaces(copy);
862 if (strlen(copy) > 0) {
863 return fc_strdup(copy);
866 return NULL;
869 /****************************************************************************
870 Lookup optional string vector, returning allocated memory or NULL.
871 ****************************************************************************/
872 static struct strvec *lookup_strvec(struct section_file *file,
873 const char *prefix, const char *suffix)
875 size_t dim;
876 const char **vec = secfile_lookup_str_vec(file, &dim,
877 "%s.%s", prefix, suffix);
879 if (NULL != vec) {
880 struct strvec *dest = strvec_new();
882 strvec_store(dest, vec, dim);
883 free(vec);
884 return dest;
886 return NULL;
889 /**************************************************************************
890 Look up the resource section name and return its pointer.
891 **************************************************************************/
892 static struct extra_type *lookup_resource(const char *filename,
893 const char *name,
894 const char *jsection)
896 struct extra_type *pres;
898 pres = extra_type_by_rule_name(name);
900 if (pres == NULL) {
901 ruleset_error(LOG_ERROR,
902 "\"%s\" [%s] has unknown \"%s\".",
903 filename,
904 jsection,
905 name);
908 return pres;
911 /**************************************************************************
912 Look up the terrain by name and return its pointer.
913 filename is for error message.
914 **************************************************************************/
915 static bool lookup_terrain(struct section_file *file,
916 const char *entry,
917 const char *filename,
918 struct terrain *pthis,
919 struct terrain **result)
921 const int j = terrain_index(pthis);
922 const char *jsection = &terrain_sections[j * MAX_SECTION_LABEL];
923 const char *name = secfile_lookup_str(file, "%s.%s", jsection, entry);
924 struct terrain *pterr;
926 if (NULL == name
927 || *name == '\0'
928 || (0 == strcmp(name, "none"))
929 || (0 == strcmp(name, "no"))) {
930 *result = T_NONE;
932 return TRUE;
934 if (0 == strcmp(name, "yes")) {
935 *result = pthis;
937 return TRUE;
940 pterr = terrain_by_rule_name(name);
941 *result = pterr;
943 if (pterr == NULL) {
944 ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown \"%s\".",
945 secfile_name(file), jsection, name);
946 return FALSE;
949 return TRUE;
952 /**************************************************************************
953 Look up a value comparable to activity_count (road_time, etc).
954 item_name describes the thing which has the time property, if non-NULL,
955 for any error message.
956 Returns FALSE if not found in secfile, but TRUE even if validation failed.
957 Sets *ok to FALSE if validation failed, leaves it alone otherwise.
958 **************************************************************************/
959 static bool lookup_time(const struct section_file *secfile, int *turns,
960 const char *sec_name, const char *property_name,
961 const char *filename, const char *item_name,
962 bool *ok)
964 /* Assumes that PACKET_UNIT_INFO.activity_count in packets.def is UINT16 */
965 const int max_turns = 65535 / ACTIVITY_FACTOR;
967 if (!secfile_lookup_int(secfile, turns, "%s.%s", sec_name, property_name)) {
968 return FALSE;
971 if (*turns > max_turns) {
972 ruleset_error(LOG_ERROR,
973 "\"%s\": \"%s\": \"%s\" value %d too large (max %d)",
974 filename, item_name ? item_name : sec_name,
975 property_name, *turns, max_turns);
976 *ok = FALSE;
979 return TRUE; /* we found _something */
982 /**************************************************************************
983 Load "name" and (optionally) "rule_name" into a struct name_translation.
984 **************************************************************************/
985 static bool ruleset_load_names(struct name_translation *pname,
986 const char *domain,
987 struct section_file *file,
988 const char *sec_name)
990 const char *name = secfile_lookup_str(file, "%s.name", sec_name);
991 const char *rule_name = secfile_lookup_str(file, "%s.rule_name", sec_name);
993 if (!name) {
994 ruleset_error(LOG_ERROR,
995 "\"%s\" [%s]: no \"name\" specified.",
996 secfile_name(file), sec_name);
997 return FALSE;
1000 names_set(pname, domain, name, rule_name);
1002 return TRUE;
1005 /**************************************************************************
1006 Load trait values to array.
1007 **************************************************************************/
1008 static void ruleset_load_traits(struct trait_limits *out,
1009 struct section_file *file,
1010 const char *secname, const char *field_prefix)
1012 enum trait tr;
1014 /* FIXME: Use specenum trait names without duplicating them here.
1015 * Just needs to take care of case. */
1016 const char *trait_names[] = {
1017 "expansionist",
1018 "trader",
1019 "aggressive",
1020 NULL
1023 for (tr = trait_begin(); tr != trait_end() && trait_names[tr] != NULL; tr = trait_next(tr)) {
1024 out[tr].min = secfile_lookup_int_default(file, -1, "%s.%s%s_min",
1025 secname,
1026 field_prefix,
1027 trait_names[tr]);
1028 out[tr].max = secfile_lookup_int_default(file, -1, "%s.%s%s_max",
1029 secname,
1030 field_prefix,
1031 trait_names[tr]);
1032 out[tr].fixed = secfile_lookup_int_default(file, -1, "%s.%s%s_default",
1033 secname,
1034 field_prefix,
1035 trait_names[tr]);
1038 fc_assert(tr == trait_end()); /* number of trait_names correct */
1041 /**************************************************************************
1042 Load names from game.ruleset so other rulesets can refer to objects
1043 with their name.
1044 **************************************************************************/
1045 static bool load_game_names(struct section_file *file,
1046 struct rscompat_info *compat)
1048 struct section_list *sec;
1049 int nval;
1050 const char *filename = secfile_name(file);
1051 bool ok = TRUE;
1053 /* section: datafile */
1054 compat->ver_game = rscompat_check_capabilities(file, filename, compat);
1055 if (compat->ver_game <= 0) {
1056 return FALSE;
1059 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
1060 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
1062 sec = secfile_sections_by_name_prefix(file, ACHIEVEMENT_SECTION_PREFIX);
1063 nval = (NULL != sec ? section_list_size(sec) : 0);
1064 if (nval > MAX_ACHIEVEMENT_TYPES) {
1065 int num = nval; /* No "size_t" to printf */
1067 ruleset_error(LOG_ERROR, "\"%s\": Too many achievement types (%d, max %d)",
1068 filename, num, MAX_ACHIEVEMENT_TYPES);
1069 ok = FALSE;
1070 } else {
1071 game.control.num_achievement_types = nval;
1074 if (ok) {
1075 achievements_iterate(pach) {
1076 const char *sec_name = section_name(section_list_get(sec, achievement_index(pach)));
1078 if (!ruleset_load_names(&pach->name, NULL, file, sec_name)) {
1079 ruleset_error(LOG_ERROR, "\"%s\": Cannot load achievement names",
1080 filename);
1081 ok = FALSE;
1082 break;
1084 } achievements_iterate_end;
1087 section_list_destroy(sec);
1089 if (compat->ver_game >= 10) {
1090 if (ok) {
1091 sec = secfile_sections_by_name_prefix(file, GOODS_SECTION_PREFIX);
1093 nval = (NULL != sec ? section_list_size(sec) : 0);
1094 if (nval > MAX_GOODS_TYPES) {
1095 int num = nval; /* No "size_t" to printf */
1097 ruleset_error(LOG_ERROR,
1098 "\"%s\": Too many goods types (%d, max %d)",
1099 filename, num, MAX_GOODS_TYPES);
1100 section_list_destroy(sec);
1101 ok = FALSE;
1102 } else if (nval < 1) {
1103 ruleset_error(LOG_ERROR, "\"%s\": At least one goods type needed",
1104 filename);
1105 section_list_destroy(sec);
1106 ok = FALSE;
1107 } else {
1108 game.control.num_goods_types = nval;
1111 if (ok) {
1112 goods_type_iterate(pgood) {
1113 const char *sec_name
1114 = section_name(section_list_get(sec, goods_index(pgood)));
1116 if (!ruleset_load_names(&pgood->name, NULL, file, sec_name)) {
1117 ruleset_error(LOG_ERROR, "\"%s\": Cannot load goods names",
1118 filename);
1119 ok = FALSE;
1120 break;
1122 } goods_type_iterate_end;
1124 section_list_destroy(sec);
1128 return ok;
1132 /**************************************************************************
1133 Load names of technologies so other rulesets can refer to techs with
1134 their name.
1135 **************************************************************************/
1136 static bool load_tech_names(struct section_file *file,
1137 struct rscompat_info *compat)
1139 struct section_list *sec = NULL;
1140 /* Number of techs in the ruleset (means without A_NONE). */
1141 int num_techs = 0;
1142 int i;
1143 const char *filename = secfile_name(file);
1144 bool ok = TRUE;
1145 const char *flag;
1147 compat->ver_techs = rscompat_check_capabilities(file, filename, compat);
1148 if (compat->ver_techs <= 0) {
1149 return FALSE;
1152 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
1153 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
1155 /* User tech flag names */
1156 for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
1157 i++) {
1158 const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
1160 if (tech_flag_id_by_name(flag, fc_strcasecmp) != tech_flag_id_invalid()) {
1161 ruleset_error(LOG_ERROR, "\"%s\": Duplicate tech flag name '%s'",
1162 filename, flag);
1163 ok = FALSE;
1164 break;
1166 if (i > MAX_NUM_USER_TECH_FLAGS) {
1167 ruleset_error(LOG_ERROR, "\"%s\": Too many user tech flags!",
1168 filename);
1169 ok = FALSE;
1170 break;
1173 set_user_tech_flag_name(TECH_USER_1 + i, flag, helptxt);
1176 if (ok) {
1177 size_t nval;
1179 for (; i < MAX_NUM_USER_TECH_FLAGS; i++) {
1180 set_user_tech_flag_name(TECH_USER_1 + i, NULL, NULL);
1183 /* Tech classes */
1184 sec = secfile_sections_by_name_prefix(file, TECH_CLASS_SECTION_PREFIX);
1186 nval = (NULL != sec ? section_list_size(sec) : 0);
1187 if (nval > MAX_NUM_TECH_CLASSES) {
1188 int num = nval; /* No "size_t" to printf */
1190 ruleset_error(LOG_ERROR,
1191 "\"%s\": Too many tech classes (%d, max %d)",
1192 filename, num, MAX_NUM_TECH_CLASSES);
1193 section_list_destroy(sec);
1194 ok = FALSE;
1195 } else {
1196 game.control.num_tech_classes = nval;
1199 if (ok) {
1200 tech_class_iterate(ptclass) {
1201 const char *sec_name
1202 = section_name(section_list_get(sec, tech_class_index(ptclass)));
1204 if (!ruleset_load_names(&ptclass->name, NULL, file, sec_name)) {
1205 ruleset_error(LOG_ERROR, "\"%s\": Cannot load tech class names",
1206 filename);
1207 ok = FALSE;
1208 break;
1210 } tech_class_iterate_end;
1214 if (ok) {
1215 /* The techs: */
1216 sec = secfile_sections_by_name_prefix(file, ADVANCE_SECTION_PREFIX);
1217 if (NULL == sec || 0 == (num_techs = section_list_size(sec))) {
1218 ruleset_error(LOG_ERROR, "\"%s\": No Advances?!?", filename);
1219 ok = FALSE;
1220 } else {
1221 log_verbose("%d advances (including possibly unused)", num_techs);
1222 if (num_techs + A_FIRST > A_LAST) {
1223 ruleset_error(LOG_ERROR, "\"%s\": Too many advances (%d, max %d)",
1224 filename, num_techs, A_LAST - A_FIRST);
1225 ok = FALSE;
1230 if (ok) {
1231 game.control.num_tech_types = num_techs + A_FIRST; /* includes A_NONE */
1233 i = 0;
1234 advance_iterate(A_FIRST, a) {
1235 if (!ruleset_load_names(&a->name, NULL, file, section_name(section_list_get(sec, i)))) {
1236 ok = FALSE;
1237 break;
1239 i++;
1240 } advance_iterate_end;
1242 section_list_destroy(sec);
1244 return ok;
1247 /**************************************************************************
1248 Load technologies related ruleset data
1249 **************************************************************************/
1250 static bool load_ruleset_techs(struct section_file *file,
1251 struct rscompat_info *compat)
1253 struct section_list *sec;
1254 const char **slist;
1255 int i;
1256 size_t nval;
1257 struct advance *a_none = advance_by_number(A_NONE);
1258 const char *filename = secfile_name(file);
1259 bool ok = TRUE;
1261 sec = secfile_sections_by_name_prefix(file, TECH_CLASS_SECTION_PREFIX);
1263 i = 0;
1264 tech_class_iterate(ptclass) {
1265 const char *sec_name = section_name(section_list_get(sec, i));
1267 ptclass->cost_pct = secfile_lookup_int_default(file, 100, "%s.%s",
1268 sec_name, "cost_pct");
1270 i++;
1271 } tech_class_iterate_end;
1273 sec = secfile_sections_by_name_prefix(file, ADVANCE_SECTION_PREFIX);
1275 i = 0;
1276 advance_iterate(A_FIRST, a) {
1277 const char *sec_name = section_name(section_list_get(sec, i));
1278 const char *sval;
1279 int j, ival;
1280 struct requirement_vector *research_reqs;
1282 if (!lookup_tech(file, &a->require[AR_ONE], sec_name, "req1",
1283 filename, rule_name_get(&a->name))
1284 || !lookup_tech(file, &a->require[AR_TWO], sec_name, "req2",
1285 filename, rule_name_get(&a->name))
1286 || !lookup_tech(file, &a->require[AR_ROOT], sec_name, "root_req",
1287 filename, rule_name_get(&a->name))) {
1288 ok = FALSE;
1289 break;
1292 if ((A_NEVER == a->require[AR_ONE] && A_NEVER != a->require[AR_TWO])
1293 || (A_NEVER != a->require[AR_ONE] && A_NEVER == a->require[AR_TWO])) {
1294 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": \"Never\" with non-\"Never\".",
1295 filename, sec_name, rule_name_get(&a->name));
1296 ok = FALSE;
1297 break;
1299 if (a_none == a->require[AR_ONE] && a_none != a->require[AR_TWO]) {
1300 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": should have \"None\" second.",
1301 filename, sec_name, rule_name_get(&a->name));
1302 ok = FALSE;
1303 break;
1306 if (game.control.num_tech_classes == 0) {
1307 a->tclass = NULL;
1308 } else {
1309 const char *classname;
1311 classname = lookup_string(file, sec_name, "class");
1312 if (classname != NULL) {
1313 classname = Q_(classname);
1314 a->tclass = tech_class_by_rule_name(classname);
1315 if (a->tclass == NULL) {
1316 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": Uknown tech class \"%s\".",
1317 filename, sec_name, rule_name_get(&a->name), classname);
1318 ok = FALSE;
1319 break;
1321 } else {
1322 a->tclass = NULL; /* Default */
1326 research_reqs = lookup_req_list(file, compat, sec_name, "research_reqs",
1327 rule_name_get(&a->name));
1328 if (research_reqs == NULL) {
1329 ok = FALSE;
1330 break;
1333 requirement_vector_copy(&a->research_reqs, research_reqs);
1335 BV_CLR_ALL(a->flags);
1337 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1338 for (j = 0; j < nval; j++) {
1339 sval = slist[j];
1340 if (strcmp(sval, "") == 0) {
1341 continue;
1343 ival = tech_flag_id_by_name(sval, fc_strcasecmp);
1344 if (!tech_flag_id_is_valid(ival)) {
1345 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": bad flag name \"%s\".",
1346 filename, sec_name, rule_name_get(&a->name), sval);
1347 ok = FALSE;
1348 break;
1349 } else {
1350 BV_SET(a->flags, ival);
1353 free(slist);
1355 if (!ok) {
1356 break;
1359 sz_strlcpy(a->graphic_str,
1360 secfile_lookup_str_default(file, "-", "%s.graphic", sec_name));
1361 sz_strlcpy(a->graphic_alt,
1362 secfile_lookup_str_default(file, "-",
1363 "%s.graphic_alt", sec_name));
1365 a->helptext = lookup_strvec(file, sec_name, "helptext");
1366 a->bonus_message = lookup_string(file, sec_name, "bonus_message");
1367 a->cost = secfile_lookup_int_default(file, -1, "%s.%s",
1368 sec_name, "cost");
1369 a->num_reqs = 0;
1371 i++;
1372 } advance_iterate_end;
1374 /* Propagate a root tech up into the tech tree. Thus if a technology
1375 * X has Y has a root tech, then any technology requiring X also has
1376 * Y as a root tech. */
1377 restart:
1379 if (ok) {
1380 advance_iterate(A_FIRST, a) {
1381 if (valid_advance(a)
1382 && A_NEVER != a->require[AR_ROOT]) {
1383 bool out_of_order = FALSE;
1385 /* Now find any tech depending on this technology and update its
1386 * root_req. */
1387 advance_iterate(A_FIRST, b) {
1388 if (valid_advance(b)
1389 && A_NEVER == b->require[AR_ROOT]
1390 && (a == b->require[AR_ONE] || a == b->require[AR_TWO])) {
1391 b->require[AR_ROOT] = a->require[AR_ROOT];
1392 if (b < a) {
1393 out_of_order = TRUE;
1396 } advance_iterate_end;
1398 if (out_of_order) {
1399 /* HACK: If we just changed the root_tech of a lower-numbered
1400 * technology, we need to go back so that we can propagate the
1401 * root_tech up to that technology's parents... */
1402 goto restart;
1405 } advance_iterate_end;
1407 /* Now rename A_NEVER to A_NONE for consistency */
1408 advance_iterate(A_NONE, a) {
1409 if (A_NEVER == a->require[AR_ROOT]) {
1410 a->require[AR_ROOT] = a_none;
1412 } advance_iterate_end;
1414 /* Some more consistency checking:
1415 Non-removed techs depending on removed techs is too
1416 broken to fix by default, so die.
1418 advance_iterate(A_FIRST, a) {
1419 if (valid_advance(a)) {
1420 /* We check for recursive tech loops later,
1421 * in build_required_techs_helper. */
1422 if (!valid_advance(a->require[AR_ONE])) {
1423 ruleset_error(LOG_ERROR,
1424 "\"%s\" tech \"%s\": req1 leads to removed tech.",
1425 filename,
1426 advance_rule_name(a));
1427 ok = FALSE;
1428 break;
1430 if (!valid_advance(a->require[AR_TWO])) {
1431 ruleset_error(LOG_ERROR,
1432 "\"%s\" tech \"%s\": req2 leads to removed tech.",
1433 filename,
1434 advance_rule_name(a));
1435 ok = FALSE;
1436 break;
1439 } advance_iterate_end;
1442 section_list_destroy(sec);
1443 if (ok) {
1444 secfile_check_unused(file);
1447 return ok;
1450 /**************************************************************************
1451 Load names of units so other rulesets can refer to units with
1452 their name.
1453 **************************************************************************/
1454 static bool load_unit_names(struct section_file *file,
1455 struct rscompat_info *compat)
1457 struct section_list *sec = NULL;
1458 int nval = 0;
1459 int i;
1460 const char *filename = secfile_name(file);
1461 const char *flag;
1462 bool ok = TRUE;
1464 compat->ver_units = rscompat_check_capabilities(file, filename, compat);
1465 if (compat->ver_units <= 0) {
1466 return FALSE;
1469 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
1470 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
1472 /* User unit flag names */
1473 for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
1474 i++) {
1475 const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
1478 if (unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat, flag),
1479 fc_strcasecmp)
1480 != unit_type_flag_id_invalid()) {
1481 ruleset_error(LOG_ERROR, "\"%s\": Duplicate unit flag name '%s'",
1482 filename, flag);
1483 ok = FALSE;
1484 break;
1486 if (i > MAX_NUM_USER_UNIT_FLAGS) {
1487 ruleset_error(LOG_ERROR, "\"%s\": Too many user unit type flags!",
1488 filename);
1489 ok = FALSE;
1490 break;
1493 set_user_unit_type_flag_name(UTYF_USER_FLAG_1 + i, flag, helptxt);
1496 if (ok) {
1497 /* Blank the remaining unit type user flags. */
1498 for (; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
1499 set_user_unit_type_flag_name(UTYF_USER_FLAG_1 + i, NULL, NULL);
1503 if (ok) {
1504 /* User unit class flag names */
1505 for (i = 0;
1506 (flag = secfile_lookup_str_default(file, NULL,
1507 "control.class_flags%d.name",
1508 i));
1509 i++) {
1510 const char *helptxt = secfile_lookup_str_default(file, NULL,
1511 "control.class_flags%d.helptxt", i);
1513 if (unit_class_flag_id_by_name(flag, fc_strcasecmp)
1514 != unit_class_flag_id_invalid()) {
1515 ruleset_error(LOG_ERROR, "\"%s\": Duplicate unit class flag name "
1516 "'%s'",
1517 filename, flag);
1518 ok = FALSE;
1519 break;
1521 if (i > MAX_NUM_USER_UCLASS_FLAGS) {
1522 ruleset_error(LOG_ERROR, "\"%s\": Too many user unit class flags!",
1523 filename);
1524 ok = FALSE;
1525 break;
1528 set_user_unit_class_flag_name(UCF_USER_FLAG_1 + i, flag, helptxt);
1532 if (ok) {
1533 /* Blank the remaining unit class user flags. */
1534 for (; i < MAX_NUM_USER_UCLASS_FLAGS; i++) {
1535 set_user_unit_class_flag_name(UCF_USER_FLAG_1 + i, NULL, NULL);
1539 if (ok) {
1540 /* Unit classes */
1541 sec = secfile_sections_by_name_prefix(file, UNIT_CLASS_SECTION_PREFIX);
1542 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
1543 ruleset_error(LOG_ERROR, "\"%s\": No unit classes?!?", filename);
1544 ok = FALSE;
1545 } else {
1546 log_verbose("%d unit classes", nval);
1547 if (nval > UCL_LAST) {
1548 ruleset_error(LOG_ERROR, "\"%s\": Too many unit classes (%d, max %d)",
1549 filename, nval, UCL_LAST);
1550 ok = FALSE;
1555 if (ok) {
1556 game.control.num_unit_classes = nval;
1558 unit_class_iterate(punitclass) {
1559 const int pci = uclass_index(punitclass);
1561 if (!ruleset_load_names(&punitclass->name, NULL, file,
1562 section_name(section_list_get(sec, pci)))) {
1563 ok = FALSE;
1564 break;
1566 } unit_class_iterate_end;
1568 section_list_destroy(sec);
1569 sec = NULL;
1571 /* The names: */
1572 if (ok) {
1573 sec = secfile_sections_by_name_prefix(file, UNIT_SECTION_PREFIX);
1574 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
1575 ruleset_error(LOG_ERROR, "\"%s\": No unit types?!?", filename);
1576 ok = FALSE;
1577 } else {
1578 log_verbose("%d unit types (including possibly unused)", nval);
1579 if (nval > U_LAST) {
1580 ruleset_error(LOG_ERROR, "\"%s\": Too many unit types (%d, max %d)",
1581 filename, nval, U_LAST);
1582 ok = FALSE;
1587 if (ok) {
1588 game.control.num_unit_types = nval;
1590 unit_type_iterate(punittype) {
1591 const int utypei = utype_index(punittype);
1592 if (!ruleset_load_names(&punittype->name, NULL, file,
1593 section_name(section_list_get(sec, utypei)))) {
1594 ok = FALSE;
1595 break;
1597 } unit_type_iterate_end;
1599 section_list_destroy(sec);
1601 return ok;
1604 /**************************************************************************
1605 Load veteran levels.
1606 **************************************************************************/
1607 static bool load_ruleset_veteran(struct section_file *file,
1608 const char *path,
1609 struct veteran_system **vsystem, char *err,
1610 size_t err_len)
1612 const char **vlist_name;
1613 int *vlist_power, *vlist_raise, *vlist_wraise, *vlist_move;
1614 size_t count_name, count_power, count_raise, count_wraise, count_move;
1615 int i;
1616 bool ret = TRUE;
1618 /* The pointer should be uninitialised. */
1619 if (*vsystem != NULL) {
1620 fc_snprintf(err, err_len, "Veteran system is defined?!");
1621 return FALSE;
1624 /* Load data. */
1625 vlist_name = secfile_lookup_str_vec(file, &count_name,
1626 "%s.veteran_names", path);
1627 vlist_power = secfile_lookup_int_vec(file, &count_power,
1628 "%s.veteran_power_fact", path);
1629 vlist_raise = secfile_lookup_int_vec(file, &count_raise,
1630 "%s.veteran_raise_chance", path);
1631 vlist_wraise = secfile_lookup_int_vec(file, &count_wraise,
1632 "%s.veteran_work_raise_chance",
1633 path);
1634 vlist_move = secfile_lookup_int_vec(file, &count_move,
1635 "%s.veteran_move_bonus", path);
1637 if (count_name > MAX_VET_LEVELS) {
1638 ret = FALSE;
1639 fc_snprintf(err, err_len, "\"%s\": Too many veteran levels (section "
1640 "'%s': %lu, max %d)", secfile_name(file), path,
1641 (long unsigned)count_name, MAX_VET_LEVELS);
1642 } else if (count_name != count_power
1643 || count_name != count_raise
1644 || count_name != count_wraise
1645 || count_name != count_move) {
1646 ret = FALSE;
1647 fc_snprintf(err, err_len, "\"%s\": Different lengths for the veteran "
1648 "settings in section '%s'", secfile_name(file),
1649 path);
1650 } else if (count_name == 0) {
1651 /* Nothing defined. */
1652 *vsystem = NULL;
1653 } else {
1654 /* Generate the veteran system. */
1655 *vsystem = veteran_system_new((int)count_name);
1657 #define rs_sanity_veteran(_path, _entry, _i, _condition, _action) \
1658 if (_condition) { \
1659 log_error("Invalid veteran definition '%s.%s[%d]'!", \
1660 _path, _entry, _i); \
1661 log_debug("Failed check: '%s'. Update value: '%s'.", \
1662 #_condition, #_action); \
1663 _action; \
1665 for (i = 0; i < count_name; i++) {
1666 /* Some sanity checks. */
1667 rs_sanity_veteran(path, "veteran_power_fact", i,
1668 (vlist_power[i] < 0), vlist_power[i] = 0);
1669 rs_sanity_veteran(path, "veteran_raise_chance", i,
1670 (vlist_raise[i] < 0), vlist_raise[i] = 0);
1671 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1672 (vlist_wraise[i] < 0), vlist_wraise[i] = 0);
1673 rs_sanity_veteran(path, "veteran_move_bonus", i,
1674 (vlist_move[i] < 0), vlist_move[i] = 0);
1675 if (i == 0) {
1676 /* First element.*/
1677 rs_sanity_veteran(path, "veteran_power_fact", i,
1678 (vlist_power[i] != 100), vlist_power[i] = 100);
1679 } else if (i == count_name - 1) {
1680 /* Last element. */
1681 rs_sanity_veteran(path, "veteran_power_fact", i,
1682 (vlist_power[i] < vlist_power[i - 1]),
1683 vlist_power[i] = vlist_power[i - 1]);
1684 rs_sanity_veteran(path, "veteran_raise_chance", i,
1685 (vlist_raise[i] != 0), vlist_raise[i] = 0);
1686 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1687 (vlist_wraise[i] != 0), vlist_wraise[i] = 0);
1688 } else {
1689 /* All elements inbetween. */
1690 rs_sanity_veteran(path, "veteran_power_fact", i,
1691 (vlist_power[i] < vlist_power[i - 1]),
1692 vlist_power[i] = vlist_power[i - 1]);
1693 rs_sanity_veteran(path, "veteran_raise_chance", i,
1694 (vlist_raise[i] > 100), vlist_raise[i] = 100);
1695 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1696 (vlist_wraise[i] > 100), vlist_wraise[i] = 100);
1699 veteran_system_definition(*vsystem, i, vlist_name[i], vlist_power[i],
1700 vlist_move[i], vlist_raise[i],
1701 vlist_wraise[i]);
1703 #undef rs_sanity_veteran
1706 if (vlist_name) {
1707 free(vlist_name);
1709 if (vlist_power) {
1710 free(vlist_power);
1712 if (vlist_raise) {
1713 free(vlist_raise);
1715 if (vlist_wraise) {
1716 free(vlist_wraise);
1718 if (vlist_move) {
1719 free(vlist_move);
1722 return ret;
1725 /**************************************************************************
1726 Load units related ruleset data.
1727 **************************************************************************/
1728 static bool load_ruleset_units(struct section_file *file,
1729 struct rscompat_info *compat)
1731 int j, ival;
1732 size_t nval;
1733 struct section_list *sec, *csec;
1734 const char *sval, **slist;
1735 const char *filename = secfile_name(file);
1736 char msg[MAX_LEN_MSG];
1737 bool ok = TRUE;
1739 if (!load_ruleset_veteran(file, "veteran_system", &game.veteran, msg,
1740 sizeof(msg)) || game.veteran == NULL) {
1741 ruleset_error(LOG_ERROR, "Error loading the default veteran system: %s",
1742 msg);
1743 ok = FALSE;
1746 sec = secfile_sections_by_name_prefix(file, UNIT_SECTION_PREFIX);
1747 nval = (NULL != sec ? section_list_size(sec) : 0);
1749 csec = secfile_sections_by_name_prefix(file, UNIT_CLASS_SECTION_PREFIX);
1750 nval = (NULL != csec ? section_list_size(csec) : 0);
1752 if (ok) {
1753 unit_class_iterate(uc) {
1754 int i = uclass_index(uc);
1755 const char *hut_str;
1756 const char *sec_name = section_name(section_list_get(csec, i));
1758 if (secfile_lookup_int(file, &uc->min_speed, "%s.min_speed", sec_name)) {
1759 uc->min_speed *= SINGLE_MOVE;
1760 } else {
1761 ruleset_error(LOG_ERROR, "%s", secfile_error());
1762 ok = FALSE;
1763 break;
1765 if (!secfile_lookup_int(file, &uc->hp_loss_pct,
1766 "%s.hp_loss_pct", sec_name)) {
1767 ruleset_error(LOG_ERROR, "%s", secfile_error());
1768 ok = FALSE;
1769 break;
1772 uc->non_native_def_pct = secfile_lookup_int_default(file, 100,
1773 "%s.non_native_def_pct",
1774 sec_name);
1776 hut_str = secfile_lookup_str_default(file, "Normal", "%s.hut_behavior", sec_name);
1777 if (fc_strcasecmp(hut_str, "Normal") == 0) {
1778 uc->hut_behavior = HUT_NORMAL;
1779 } else if (fc_strcasecmp(hut_str, "Nothing") == 0) {
1780 uc->hut_behavior = HUT_NOTHING;
1781 } else if (fc_strcasecmp(hut_str, "Frighten") == 0) {
1782 uc->hut_behavior = HUT_FRIGHTEN;
1783 } else {
1784 ruleset_error(LOG_ERROR,
1785 "\"%s\" unit_class \"%s\":"
1786 " Illegal hut behavior \"%s\".",
1787 filename,
1788 uclass_rule_name(uc),
1789 hut_str);
1790 ok = FALSE;
1791 break;
1794 BV_CLR_ALL(uc->flags);
1795 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1796 for (j = 0; j < nval; j++) {
1797 sval = slist[j];
1798 if (strcmp(sval, "") == 0) {
1799 continue;
1801 ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
1802 if (!unit_class_flag_id_is_valid(ival)) {
1803 ok = FALSE;
1804 ival = unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat, sval),
1805 fc_strcasecmp);
1806 if (unit_type_flag_id_is_valid(ival)) {
1807 ruleset_error(LOG_ERROR,
1808 "\"%s\" unit_class \"%s\": unit_type flag \"%s\"!",
1809 filename, uclass_rule_name(uc), sval);
1810 } else {
1811 ruleset_error(LOG_ERROR,
1812 "\"%s\" unit_class \"%s\": bad flag name \"%s\".",
1813 filename, uclass_rule_name(uc), sval);
1815 break;
1816 } else {
1817 BV_SET(uc->flags, ival);
1820 free(slist);
1822 uc->helptext = lookup_strvec(file, sec_name, "helptext");
1824 if (!ok) {
1825 break;
1827 } unit_class_iterate_end;
1830 if (ok) {
1831 /* Tech and Gov requirements; per unit veteran system */
1832 unit_type_iterate(u) {
1833 const int i = utype_index(u);
1834 const struct section *psection = section_list_get(sec, i);
1835 const char *sec_name = section_name(psection);
1837 if (!lookup_tech(file, &u->require_advance, sec_name,
1838 "tech_req", filename,
1839 rule_name_get(&u->name))) {
1840 ok = FALSE;
1841 break;
1843 if (NULL != section_entry_by_name(psection, "gov_req")) {
1844 char tmp[200] = "\0";
1845 fc_strlcat(tmp, section_name(psection), sizeof(tmp));
1846 fc_strlcat(tmp, ".gov_req", sizeof(tmp));
1847 u->need_government = lookup_government(file, tmp, filename, NULL);
1848 if (u->need_government == NULL) {
1849 ok = FALSE;
1850 break;
1852 } else {
1853 u->need_government = NULL; /* no requirement */
1856 if (!load_ruleset_veteran(file, sec_name, &u->veteran,
1857 msg, sizeof(msg))) {
1858 ruleset_error(LOG_ERROR, "Error loading the veteran system: %s",
1859 msg);
1860 ok = FALSE;
1861 break;
1864 if (!lookup_unit_type(file, sec_name, "obsolete_by",
1865 &u->obsoleted_by, filename,
1866 rule_name_get(&u->name))
1867 || !lookup_unit_type(file, sec_name, "convert_to",
1868 &u->converted_to, filename,
1869 rule_name_get(&u->name))) {
1870 ok = FALSE;
1871 break;
1873 u->convert_time = 1; /* default */
1874 lookup_time(file, &u->convert_time, sec_name, "convert_time",
1875 filename, rule_name_get(&u->name), &ok);
1876 } unit_type_iterate_end;
1879 if (ok) {
1880 /* main stats: */
1881 unit_type_iterate(u) {
1882 const int i = utype_index(u);
1883 struct unit_class *pclass;
1884 const char *sec_name = section_name(section_list_get(sec, i));
1885 const char *string;
1887 if (!lookup_building(file, sec_name, "impr_req",
1888 &u->need_improvement, filename,
1889 rule_name_get(&u->name))) {
1890 ok = FALSE;
1891 break;
1894 sval = secfile_lookup_str(file, "%s.class", sec_name);
1895 pclass = unit_class_by_rule_name(sval);
1896 if (!pclass) {
1897 ruleset_error(LOG_ERROR,
1898 "\"%s\" unit_type \"%s\":"
1899 " bad class \"%s\".",
1900 filename,
1901 utype_rule_name(u),
1902 sval);
1903 ok = FALSE;
1904 break;
1906 u->uclass = pclass;
1908 sz_strlcpy(u->sound_move,
1909 secfile_lookup_str_default(file, "-", "%s.sound_move",
1910 sec_name));
1911 sz_strlcpy(u->sound_move_alt,
1912 secfile_lookup_str_default(file, "-", "%s.sound_move_alt",
1913 sec_name));
1914 sz_strlcpy(u->sound_fight,
1915 secfile_lookup_str_default(file, "-", "%s.sound_fight",
1916 sec_name));
1917 sz_strlcpy(u->sound_fight_alt,
1918 secfile_lookup_str_default(file, "-", "%s.sound_fight_alt",
1919 sec_name));
1921 if ((string = secfile_lookup_str(file, "%s.graphic", sec_name))) {
1922 sz_strlcpy(u->graphic_str, string);
1923 } else {
1924 ruleset_error(LOG_ERROR, "%s", secfile_error());
1925 ok = FALSE;
1926 break;
1928 sz_strlcpy(u->graphic_alt,
1929 secfile_lookup_str_default(file, "-", "%s.graphic_alt",
1930 sec_name));
1932 if (!secfile_lookup_int(file, &u->build_cost,
1933 "%s.build_cost", sec_name)
1934 || !secfile_lookup_int(file, &u->pop_cost,
1935 "%s.pop_cost", sec_name)
1936 || !secfile_lookup_int(file, &u->attack_strength,
1937 "%s.attack", sec_name)
1938 || !secfile_lookup_int(file, &u->defense_strength,
1939 "%s.defense", sec_name)
1940 || !secfile_lookup_int(file, &u->move_rate,
1941 "%s.move_rate", sec_name)
1942 || !secfile_lookup_int(file, &u->vision_radius_sq,
1943 "%s.vision_radius_sq", sec_name)
1944 || !secfile_lookup_int(file, &u->transport_capacity,
1945 "%s.transport_cap", sec_name)
1946 || !secfile_lookup_int(file, &u->hp,
1947 "%s.hitpoints", sec_name)
1948 || !secfile_lookup_int(file, &u->firepower,
1949 "%s.firepower", sec_name)
1950 || !secfile_lookup_int(file, &u->fuel,
1951 "%s.fuel", sec_name)
1952 || !secfile_lookup_int(file, &u->happy_cost,
1953 "%s.uk_happy", sec_name)) {
1954 ruleset_error(LOG_ERROR, "%s", secfile_error());
1955 ok = FALSE;
1956 break;
1958 u->move_rate *= SINGLE_MOVE;
1960 if (u->firepower <= 0) {
1961 ruleset_error(LOG_ERROR,
1962 "\"%s\" unit_type \"%s\":"
1963 " firepower is %d,"
1964 " but must be at least 1. "
1965 " If you want no attack ability,"
1966 " set the unit's attack strength to 0.",
1967 filename,
1968 utype_rule_name(u),
1969 u->firepower);
1970 ok = FALSE;
1971 break;
1974 lookup_cbonus_list(compat, u->bonuses, file, sec_name, "bonuses");
1976 output_type_iterate(o) {
1977 u->upkeep[o] = secfile_lookup_int_default(file, 0, "%s.uk_%s",
1978 sec_name,
1979 get_output_identifier(o));
1980 } output_type_iterate_end;
1982 slist = secfile_lookup_str_vec(file, &nval, "%s.cargo", sec_name);
1983 BV_CLR_ALL(u->cargo);
1984 for (j = 0; j < nval; j++) {
1985 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1987 if (!uclass) {
1988 ruleset_error(LOG_ERROR,
1989 "\"%s\" unit_type \"%s\":"
1990 "has unknown unit class %s as cargo.",
1991 filename,
1992 utype_rule_name(u),
1993 slist[j]);
1994 ok = FALSE;
1995 break;
1998 BV_SET(u->cargo, uclass_index(uclass));
2000 free(slist);
2002 if (!ok) {
2003 break;
2006 slist = secfile_lookup_str_vec(file, &nval, "%s.targets", sec_name);
2007 BV_CLR_ALL(u->targets);
2008 for (j = 0; j < nval; j++) {
2009 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2011 if (!uclass) {
2012 ruleset_error(LOG_ERROR,
2013 "\"%s\" unit_type \"%s\":"
2014 "has unknown unit class %s as target.",
2015 filename,
2016 utype_rule_name(u),
2017 slist[j]);
2018 ok = FALSE;
2019 break;
2022 BV_SET(u->targets, uclass_index(uclass));
2024 free(slist);
2026 if (!ok) {
2027 break;
2030 slist = secfile_lookup_str_vec(file, &nval, "%s.embarks", sec_name);
2031 BV_CLR_ALL(u->embarks);
2032 for (j = 0; j < nval; j++) {
2033 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2035 if (!uclass) {
2036 ruleset_error(LOG_ERROR,
2037 "\"%s\" unit_type \"%s\":"
2038 "has unknown unit class %s as embarkable.",
2039 filename,
2040 utype_rule_name(u),
2041 slist[j]);
2042 ok = FALSE;
2043 break;
2046 BV_SET(u->embarks, uclass_index(uclass));
2048 free(slist);
2050 if (!ok) {
2051 break;
2054 slist = secfile_lookup_str_vec(file, &nval, "%s.disembarks", sec_name);
2055 BV_CLR_ALL(u->disembarks);
2056 for (j = 0; j < nval; j++) {
2057 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2059 if (!uclass) {
2060 ruleset_error(LOG_ERROR,
2061 "\"%s\" unit_type \"%s\":"
2062 "has unknown unit class %s as disembarkable.",
2063 filename,
2064 utype_rule_name(u),
2065 slist[j]);
2066 ok = FALSE;
2067 break;
2070 BV_SET(u->disembarks, uclass_index(uclass));
2072 free(slist);
2074 if (!ok) {
2075 break;
2078 /* Set also all classes that are never unreachable as targets,
2079 * embarks, and disembarks. */
2080 unit_class_iterate(preachable) {
2081 if (!uclass_has_flag(preachable, UCF_UNREACHABLE)) {
2082 BV_SET(u->targets, uclass_index(preachable));
2083 BV_SET(u->embarks, uclass_index(preachable));
2084 BV_SET(u->disembarks, uclass_index(preachable));
2086 } unit_class_iterate_end;
2088 u->helptext = lookup_strvec(file, sec_name, "helptext");
2090 u->paratroopers_range = secfile_lookup_int_default(file,
2091 0, "%s.paratroopers_range", sec_name);
2092 u->paratroopers_mr_req = SINGLE_MOVE * secfile_lookup_int_default(file,
2093 0, "%s.paratroopers_mr_req", sec_name);
2094 u->paratroopers_mr_sub = SINGLE_MOVE * secfile_lookup_int_default(file,
2095 0, "%s.paratroopers_mr_sub", sec_name);
2096 u->bombard_rate = secfile_lookup_int_default(file, 0,
2097 "%s.bombard_rate", sec_name);
2098 u->city_slots = secfile_lookup_int_default(file, 0,
2099 "%s.city_slots", sec_name);
2100 u->city_size = secfile_lookup_int_default(file, 1,
2101 "%s.city_size", sec_name);
2102 } unit_type_iterate_end;
2105 if (ok) {
2106 /* flags */
2107 unit_type_iterate(u) {
2108 const int i = utype_index(u);
2110 BV_CLR_ALL(u->flags);
2111 fc_assert(!utype_has_flag(u, UTYF_LAST_USER_FLAG - 1));
2113 slist = secfile_lookup_str_vec(file, &nval, "%s.flags",
2114 section_name(section_list_get(sec, i)));
2115 for (j = 0; j < nval; j++) {
2116 sval = slist[j];
2117 if (0 == strcmp(sval, "")) {
2118 continue;
2120 ival = unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat, sval),
2121 fc_strcasecmp);
2122 if (!unit_type_flag_id_is_valid(ival)) {
2123 ok = FALSE;
2124 ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
2125 if (unit_class_flag_id_is_valid(ival)) {
2126 ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": unit_class flag!",
2127 filename, utype_rule_name(u));
2128 } else {
2129 ruleset_error(LOG_ERROR,
2130 "\"%s\" unit_type \"%s\": bad flag name \"%s\".",
2131 filename, utype_rule_name(u), sval);
2133 break;
2134 } else {
2135 BV_SET(u->flags, ival);
2137 fc_assert(utype_has_flag(u, ival));
2139 free(slist);
2141 if (!ok) {
2142 break;
2144 } unit_type_iterate_end;
2147 /* roles */
2148 if (ok) {
2149 unit_type_iterate(u) {
2150 const int i = utype_index(u);
2152 BV_CLR_ALL(u->roles);
2154 slist = secfile_lookup_str_vec(file, &nval, "%s.roles",
2155 section_name(section_list_get(sec, i)));
2156 for (j = 0; j < nval; j++) {
2157 sval = slist[j];
2158 if (strcmp(sval, "") == 0) {
2159 continue;
2161 ival = unit_role_id_by_name(sval, fc_strcasecmp);
2162 if (!unit_role_id_is_valid(ival)) {
2163 ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": bad role name \"%s\".",
2164 filename, utype_rule_name(u), sval);
2165 ok = FALSE;
2166 break;
2167 } else {
2168 BV_SET(u->roles, ival - L_FIRST);
2170 fc_assert(utype_has_role(u, ival));
2172 free(slist);
2173 } unit_type_iterate_end;
2176 if (ok) {
2177 /* Some more consistency checking: */
2178 unit_type_iterate(u) {
2179 if (!valid_advance(u->require_advance)) {
2180 ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": depends on removed tech \"%s\".",
2181 filename, utype_rule_name(u),
2182 advance_rule_name(u->require_advance));
2183 u->require_advance = A_NEVER;
2184 ok = FALSE;
2185 break;
2188 if (utype_has_flag(u, UTYF_SETTLERS)
2189 && u->city_size <= 0) {
2190 ruleset_error(LOG_ERROR, "\"%s\": Unit %s would build size %d cities",
2191 filename, utype_rule_name(u), u->city_size);
2192 u->city_size = 1;
2193 ok = FALSE;
2194 break;
2196 } unit_type_iterate_end;
2199 section_list_destroy(csec);
2200 section_list_destroy(sec);
2202 if (ok) {
2203 secfile_check_unused(file);
2206 return ok;
2209 /**************************************************************************
2210 Load names of buildings so other rulesets can refer to buildings with
2211 their name.
2212 **************************************************************************/
2213 static bool load_building_names(struct section_file *file,
2214 struct rscompat_info *compat)
2216 struct section_list *sec;
2217 int i, nval = 0;
2218 const char *filename = secfile_name(file);
2219 bool ok = TRUE;
2221 compat->ver_buildings = rscompat_check_capabilities(file, filename,
2222 compat);
2223 if (compat->ver_buildings <= 0) {
2224 return FALSE;
2227 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
2228 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
2230 /* The names: */
2231 sec = secfile_sections_by_name_prefix(file, BUILDING_SECTION_PREFIX);
2232 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
2233 ruleset_error(LOG_ERROR, "\"%s\": No improvements?!?", filename);
2234 ok = FALSE;
2235 } else {
2236 log_verbose("%d improvement types (including possibly unused)", nval);
2237 if (nval > B_LAST) {
2238 ruleset_error(LOG_ERROR, "\"%s\": Too many improvements (%d, max %d)",
2239 filename, nval, B_LAST);
2240 ok = FALSE;
2244 if (ok) {
2245 game.control.num_impr_types = nval;
2247 for (i = 0; i < nval; i++) {
2248 struct impr_type *b = improvement_by_number(i);
2250 if (!ruleset_load_names(&b->name, NULL, file, section_name(section_list_get(sec, i)))) {
2251 ok = FALSE;
2252 break;
2257 section_list_destroy(sec);
2259 return ok;
2262 /**************************************************************************
2263 Load buildings related ruleset data
2264 **************************************************************************/
2265 static bool load_ruleset_buildings(struct section_file *file,
2266 struct rscompat_info *compat)
2268 struct section_list *sec;
2269 const char *item;
2270 int i, nval;
2271 const char *filename = secfile_name(file);
2272 bool ok = TRUE;
2274 sec = secfile_sections_by_name_prefix(file, BUILDING_SECTION_PREFIX);
2275 nval = (NULL != sec ? section_list_size(sec) : 0);
2277 for (i = 0; i < nval && ok; i++) {
2278 struct impr_type *b = improvement_by_number(i);
2279 const char *sec_name = section_name(section_list_get(sec, i));
2280 struct requirement_vector *reqs =
2281 lookup_req_list(file, compat, sec_name, "reqs",
2282 improvement_rule_name(b));
2284 if (reqs == NULL) {
2285 ok = FALSE;
2286 break;
2287 } else {
2288 const char *sval, **slist;
2289 int j, ival;
2290 size_t nflags;
2292 item = secfile_lookup_str(file, "%s.genus", sec_name);
2293 b->genus = impr_genus_id_by_name(item, fc_strcasecmp);
2294 if (!impr_genus_id_is_valid(b->genus)) {
2295 ruleset_error(LOG_ERROR, "\"%s\" improvement \"%s\": couldn't match "
2296 "genus \"%s\".", filename,
2297 improvement_rule_name(b), item);
2298 ok = FALSE;
2299 break;
2302 slist = secfile_lookup_str_vec(file, &nflags, "%s.flags", sec_name);
2303 BV_CLR_ALL(b->flags);
2305 for (j = 0; j < nflags; j++) {
2306 sval = slist[j];
2307 if (strcmp(sval,"") == 0) {
2308 continue;
2310 ival = impr_flag_id_by_name(sval, fc_strcasecmp);
2311 if (!impr_flag_id_is_valid(ival)) {
2312 ruleset_error(LOG_ERROR,
2313 "\"%s\" improvement \"%s\": bad flag name \"%s\".",
2314 filename, improvement_rule_name(b), sval);
2315 ok = FALSE;
2316 break;
2317 } else {
2318 BV_SET(b->flags, ival);
2321 free(slist);
2323 if (!ok) {
2324 break;
2327 requirement_vector_copy(&b->reqs, reqs);
2330 struct requirement_vector *obs_reqs =
2331 lookup_req_list(file, compat, sec_name, "obsolete_by",
2332 improvement_rule_name(b));
2334 if (obs_reqs == NULL) {
2335 ok = FALSE;
2336 break;
2337 } else {
2338 requirement_vector_copy(&b->obsolete_by, obs_reqs);
2342 if (!secfile_lookup_int(file, &b->build_cost,
2343 "%s.build_cost", sec_name)
2344 || !secfile_lookup_int(file, &b->upkeep,
2345 "%s.upkeep", sec_name)
2346 || !secfile_lookup_int(file, &b->sabotage,
2347 "%s.sabotage", sec_name)) {
2348 ruleset_error(LOG_ERROR, "%s", secfile_error());
2349 ok = FALSE;
2350 break;
2353 sz_strlcpy(b->graphic_str,
2354 secfile_lookup_str_default(file, "-",
2355 "%s.graphic", sec_name));
2356 sz_strlcpy(b->graphic_alt,
2357 secfile_lookup_str_default(file, "-",
2358 "%s.graphic_alt", sec_name));
2360 sz_strlcpy(b->soundtag,
2361 secfile_lookup_str_default(file, "-",
2362 "%s.sound", sec_name));
2363 sz_strlcpy(b->soundtag_alt,
2364 secfile_lookup_str_default(file, "-",
2365 "%s.sound_alt", sec_name));
2366 b->helptext = lookup_strvec(file, sec_name, "helptext");
2370 section_list_destroy(sec);
2371 if (ok) {
2372 secfile_check_unused(file);
2375 return ok;
2378 /**************************************************************************
2379 Load names of terrain types so other rulesets can refer to terrains with
2380 their name.
2381 **************************************************************************/
2382 static bool load_terrain_names(struct section_file *file,
2383 struct rscompat_info *compat)
2385 int nval = 0;
2386 struct section_list *sec = NULL;
2387 const char *flag;
2388 int i;
2389 const char *filename = secfile_name(file);
2390 bool ok = TRUE;
2392 compat->ver_terrain = rscompat_check_capabilities(file, filename,
2393 compat);
2394 if (compat->ver_terrain <= 0) {
2395 return FALSE;
2398 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
2399 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
2401 /* User terrain flag names */
2402 for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
2403 i++) {
2404 const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
2407 if (terrain_flag_id_by_name(flag, fc_strcasecmp)
2408 != terrain_flag_id_invalid()) {
2409 ruleset_error(LOG_ERROR, "\"%s\": Duplicate terrain flag name '%s'",
2410 filename, flag);
2411 ok = FALSE;
2412 break;
2414 if (i > MAX_NUM_USER_TER_FLAGS) {
2415 ruleset_error(LOG_ERROR, "\"%s\": Too many user terrain flags!",
2416 filename);
2417 ok = FALSE;
2418 break;
2421 set_user_terrain_flag_name(TER_USER_1 + i, flag, helptxt);
2424 if (ok) {
2425 /* Blank the remaining terrain user flag slots. */
2426 for (; i < MAX_NUM_USER_TER_FLAGS; i++) {
2427 set_user_terrain_flag_name(TER_USER_1 + i, NULL, NULL);
2431 /* User extra flag names */
2432 for (i = 0;
2433 (flag = secfile_lookup_str_default(file, NULL,
2434 "control.extra_flags%d.name",
2435 i));
2436 i++) {
2437 const char *helptxt = secfile_lookup_str_default(file, NULL,
2438 "control.extra_flags%d.helptxt", i);
2440 if (extra_flag_id_by_name(flag, fc_strcasecmp)
2441 != extra_flag_id_invalid()) {
2442 ruleset_error(LOG_ERROR, "\"%s\": Duplicate extra flag name '%s'",
2443 filename, flag);
2444 ok = FALSE;
2445 break;
2447 if (i > MAX_NUM_USER_EXTRA_FLAGS) {
2448 ruleset_error(LOG_ERROR, "\"%s\": Too many user extra flags!",
2449 filename);
2450 ok = FALSE;
2451 break;
2454 set_user_extra_flag_name(EF_USER_FLAG_1 + i, flag, helptxt);
2457 if (ok) {
2458 /* Blank the remaining extra user flag slots. */
2459 for (; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
2460 set_user_extra_flag_name(EF_USER_FLAG_1 + i, NULL, NULL);
2463 /* terrain names */
2465 sec = secfile_sections_by_name_prefix(file, TERRAIN_SECTION_PREFIX);
2466 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
2467 ruleset_error(LOG_ERROR, "\"%s\": ruleset doesn't have any terrains.",
2468 filename);
2469 ok = FALSE;
2470 } else {
2471 if (nval > MAX_NUM_TERRAINS) {
2472 ruleset_error(LOG_ERROR, "\"%s\": Too many terrains (%d, max %d)",
2473 filename, nval, MAX_NUM_TERRAINS);
2474 ok = FALSE;
2479 if (ok) {
2480 game.control.terrain_count = nval;
2482 /* avoid re-reading files */
2483 if (terrain_sections) {
2484 free(terrain_sections);
2486 terrain_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2488 terrain_type_iterate(pterrain) {
2489 const int terri = terrain_index(pterrain);
2490 const char *sec_name = section_name(section_list_get(sec, terri));
2492 if (!ruleset_load_names(&pterrain->name, NULL, file, sec_name)) {
2493 ok = FALSE;
2494 break;
2497 if (0 == strcmp(rule_name_get(&pterrain->name), "unused")) {
2498 name_set(&pterrain->name, NULL, "");
2501 section_strlcpy(&terrain_sections[terri * MAX_SECTION_LABEL], sec_name);
2502 } terrain_type_iterate_end;
2505 section_list_destroy(sec);
2506 sec = NULL;
2508 /* extra names */
2510 if (ok) {
2511 sec = secfile_sections_by_name_prefix(file, EXTRA_SECTION_PREFIX);
2512 nval = (NULL != sec ? section_list_size(sec) : 0);
2513 if (nval > MAX_EXTRA_TYPES) {
2514 ruleset_error(LOG_ERROR, "\"%s\": Too many extra types (%d, max %d)",
2515 filename, nval, MAX_EXTRA_TYPES);
2516 ok = FALSE;
2520 if (ok) {
2521 int idx;
2523 game.control.num_extra_types = nval;
2525 if (extra_sections) {
2526 free(extra_sections);
2528 extra_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2530 if (ok) {
2531 for (idx = 0; idx < nval; idx++) {
2532 const char *sec_name = section_name(section_list_get(sec, idx));
2533 struct extra_type *pextra = extra_by_number(idx);
2535 if (!ruleset_load_names(&pextra->name, NULL, file, sec_name)) {
2536 ok = FALSE;
2537 break;
2539 section_strlcpy(&extra_sections[idx * MAX_SECTION_LABEL], sec_name);
2544 section_list_destroy(sec);
2545 sec = NULL;
2547 /* base names */
2549 if (ok) {
2550 sec = secfile_sections_by_name_prefix(file, BASE_SECTION_PREFIX);
2551 nval = (NULL != sec ? section_list_size(sec) : 0);
2552 if (nval > MAX_BASE_TYPES) {
2553 ruleset_error(LOG_ERROR, "\"%s\": Too many base types (%d, max %d)",
2554 filename, nval, MAX_BASE_TYPES);
2555 ok = FALSE;
2558 game.control.num_base_types = nval;
2561 if (ok) {
2562 int idx;
2564 if (base_sections) {
2565 free(base_sections);
2567 base_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2569 /* Cannot use base_type_iterate() before bases are added to
2570 * EC_BASE caused_by list. Have to get them by extra_type_by_rule_name() */
2571 for (idx = 0; idx < nval; idx++) {
2572 const char *sec_name = section_name(section_list_get(sec, idx));
2573 const char *base_name = secfile_lookup_str(file, "%s.extra", sec_name);
2575 if (base_name != NULL) {
2576 struct extra_type *pextra = extra_type_by_rule_name(base_name);
2578 if (pextra != NULL) {
2579 base_type_init(pextra, idx);
2580 section_strlcpy(&base_sections[idx * MAX_SECTION_LABEL], sec_name);
2581 } else {
2582 ruleset_error(LOG_ERROR,
2583 "No extra definition matching base definition \"%s\"",
2584 base_name);
2585 ok = FALSE;
2587 } else {
2588 ruleset_error(LOG_ERROR,
2589 "Base section \"%s\" does not associate base with any extra",
2590 sec_name);
2591 ok = FALSE;
2596 section_list_destroy(sec);
2597 sec = NULL;
2599 /* road names */
2601 if (ok) {
2602 sec = secfile_sections_by_name_prefix(file, ROAD_SECTION_PREFIX);
2603 nval = (NULL != sec ? section_list_size(sec) : 0);
2604 if (nval > MAX_ROAD_TYPES) {
2605 ruleset_error(LOG_ERROR, "\"%s\": Too many road types (%d, max %d)",
2606 filename, nval, MAX_ROAD_TYPES);
2607 ok = FALSE;
2610 game.control.num_road_types = nval;
2613 if (ok) {
2614 int idx;
2616 if (road_sections) {
2617 free(road_sections);
2619 road_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2621 /* Cannot use extra_type_by_cause_iterate(EC_ROAD) before roads are added to
2622 * EC_ROAD caused_by list. Have to get them by extra_type_by_rule_name() */
2623 for (idx = 0; idx < nval; idx++) {
2624 const char *sec_name = section_name(section_list_get(sec, idx));
2625 const char *road_name = secfile_lookup_str(file, "%s.extra", sec_name);
2627 if (road_name != NULL) {
2628 struct extra_type *pextra = extra_type_by_rule_name(road_name);
2630 if (pextra != NULL) {
2631 road_type_init(pextra, idx);
2632 section_strlcpy(&road_sections[idx * MAX_SECTION_LABEL], sec_name);
2633 } else {
2634 ruleset_error(LOG_ERROR,
2635 "No extra definition matching road definition \"%s\"",
2636 road_name);
2637 ok = FALSE;
2639 } else {
2640 ruleset_error(LOG_ERROR,
2641 "Road section \"%s\" does not associate road with any extra",
2642 sec_name);
2643 ok = FALSE;
2648 section_list_destroy(sec);
2649 sec = NULL;
2651 /* resource names */
2653 if (ok) {
2654 sec = secfile_sections_by_name_prefix(file, RESOURCE_SECTION_PREFIX);
2655 nval = (NULL != sec ? section_list_size(sec) : 0);
2656 if (nval > MAX_RESOURCE_TYPES) {
2657 ruleset_error(LOG_ERROR, "\"%s\": Too many resource types (%d, max %d)",
2658 filename, nval, MAX_RESOURCE_TYPES);
2659 ok = FALSE;
2662 game.control.num_resource_types = nval;
2665 if (ok) {
2666 int idx;
2668 if (resource_sections) {
2669 free(resource_sections);
2671 resource_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2673 /* Cannot use resource_type_iterate() before resource are added to
2674 * EC_RESOURCE caused_by list. Have to get them by extra_type_by_rule_name() */
2675 for (idx = 0; idx < nval; idx++) {
2676 const char *sec_name = section_name(section_list_get(sec, idx));
2677 const char *resource_name;
2678 struct extra_type *pextra = NULL;
2680 resource_name = secfile_lookup_str_default(file, NULL, "%s.extra", sec_name);
2682 if (resource_name != NULL) {
2683 pextra = extra_type_by_rule_name(resource_name);
2685 if (pextra != NULL) {
2686 resource_type_init(pextra);
2687 section_strlcpy(&resource_sections[idx * MAX_SECTION_LABEL], sec_name);
2688 } else {
2689 ruleset_error(LOG_ERROR,
2690 "No extra definition matching resource definition \"%s\"",
2691 resource_name);
2692 ok = FALSE;
2694 } else {
2695 ruleset_error(LOG_ERROR,
2696 "Resource section %s does not list extra this resource belongs to.",
2697 sec_name);
2698 ok = FALSE;
2703 section_list_destroy(sec);
2705 return ok;
2708 /**************************************************************************
2709 Load terrain types related ruleset data
2710 **************************************************************************/
2711 static bool load_ruleset_terrain(struct section_file *file,
2712 struct rscompat_info *compat)
2714 size_t nval;
2715 int j;
2716 bool compat_road = FALSE;
2717 bool compat_rail = FALSE;
2718 bool compat_river = FALSE;
2719 const char **res;
2720 const char *filename = secfile_name(file);
2721 const char *text;
2722 bool ok = TRUE;
2724 /* parameters */
2726 terrain_control.ocean_reclaim_requirement_pct
2727 = secfile_lookup_int_default(file, 101,
2728 "parameters.ocean_reclaim_requirement");
2729 terrain_control.land_channel_requirement_pct
2730 = secfile_lookup_int_default(file, 101,
2731 "parameters.land_channel_requirement");
2732 terrain_control.terrain_thaw_requirement_pct
2733 = secfile_lookup_int_default(file, 101,
2734 "parameters.thaw_requirement");
2735 terrain_control.terrain_freeze_requirement_pct
2736 = secfile_lookup_int_default(file, 101,
2737 "parameters.freeze_requirement");
2738 terrain_control.lake_max_size
2739 = secfile_lookup_int_default(file, 0,
2740 "parameters.lake_max_size");
2741 terrain_control.min_start_native_area
2742 = secfile_lookup_int_default(file, 0,
2743 "parameters.min_start_native_area");
2744 terrain_control.move_fragments
2745 = secfile_lookup_int_default(file, 3,
2746 "parameters.move_fragments");
2747 if (terrain_control.move_fragments < 1) {
2748 ruleset_error(LOG_ERROR, "\"%s\": move_fragments must be at least 1",
2749 filename);
2750 ok = FALSE;
2752 init_move_fragments();
2753 terrain_control.igter_cost
2754 = secfile_lookup_int_default(file, 1,
2755 "parameters.igter_cost");
2756 if (terrain_control.igter_cost < 1) {
2757 ruleset_error(LOG_ERROR, "\"%s\": igter_cost must be at least 1",
2758 filename);
2759 ok = FALSE;
2761 terrain_control.pythagorean_diagonal
2762 = secfile_lookup_bool_default(file, RS_DEFAULT_PYTHAGOREAN_DIAGONAL,
2763 "parameters.pythagorean_diagonal");
2765 wld.map.server.ocean_resources
2766 = secfile_lookup_bool_default(file, FALSE,
2767 "parameters.ocean_resources");
2769 text = secfile_lookup_str_default(file,
2770 N_("?gui_type:Build Type A Base"),
2771 "extraui.ui_name_base_fortress");
2772 sz_strlcpy(terrain_control.gui_type_base0, text);
2774 text = secfile_lookup_str_default(file,
2775 N_("?gui_type:Build Type B Base"),
2776 "extraui.ui_name_base_airbase");
2777 sz_strlcpy(terrain_control.gui_type_base1, text);
2779 if (ok) {
2780 /* terrain details */
2782 terrain_type_iterate(pterrain) {
2783 const char **slist;
2784 const int i = terrain_index(pterrain);
2785 const char *tsection = &terrain_sections[i * MAX_SECTION_LABEL];
2786 const char *cstr;
2788 sz_strlcpy(pterrain->graphic_str,
2789 secfile_lookup_str(file,"%s.graphic", tsection));
2790 sz_strlcpy(pterrain->graphic_alt,
2791 secfile_lookup_str(file,"%s.graphic_alt", tsection));
2793 pterrain->identifier
2794 = secfile_lookup_str(file, "%s.identifier", tsection)[0];
2795 if ('\0' == pterrain->identifier) {
2796 ruleset_error(LOG_ERROR, "\"%s\" [%s] identifier missing value.",
2797 filename, tsection);
2798 ok = FALSE;
2799 break;
2801 if (TERRAIN_UNKNOWN_IDENTIFIER == pterrain->identifier) {
2802 ruleset_error(LOG_ERROR,
2803 "\"%s\" [%s] cannot use '%c' as an identifier;"
2804 " it is reserved for unknown terrain.",
2805 filename, tsection, pterrain->identifier);
2806 ok = FALSE;
2807 break;
2809 for (j = T_FIRST; j < i; j++) {
2810 if (pterrain->identifier == terrain_by_number(j)->identifier) {
2811 ruleset_error(LOG_ERROR,
2812 "\"%s\" [%s] has the same identifier as [%s].",
2813 filename,
2814 tsection,
2815 &terrain_sections[j * MAX_SECTION_LABEL]);
2816 ok = FALSE;
2817 break;
2821 if (!ok) {
2822 break;
2825 cstr = secfile_lookup_str(file, "%s.class", tsection);
2826 pterrain->tclass = terrain_class_by_name(cstr, fc_strcasecmp);
2827 if (!terrain_class_is_valid(pterrain->tclass)) {
2828 ruleset_error(LOG_ERROR, "\"%s\": [%s] unknown class \"%s\"",
2829 filename, tsection, cstr);
2830 ok = FALSE;
2831 break;
2834 if (!secfile_lookup_int(file, &pterrain->movement_cost,
2835 "%s.movement_cost", tsection)
2836 || !secfile_lookup_int(file, &pterrain->defense_bonus,
2837 "%s.defense_bonus", tsection)) {
2838 ruleset_error(LOG_ERROR, "%s", secfile_error());
2839 ok = FALSE;
2840 break;
2843 output_type_iterate(o) {
2844 pterrain->output[o]
2845 = secfile_lookup_int_default(file, 0, "%s.%s", tsection,
2846 get_output_identifier(o));
2847 } output_type_iterate_end;
2849 res = secfile_lookup_str_vec(file, &nval, "%s.resources", tsection);
2850 pterrain->resources = fc_calloc(nval + 1, sizeof(*pterrain->resources));
2851 for (j = 0; j < nval; j++) {
2852 pterrain->resources[j] = lookup_resource(filename, res[j], tsection);
2853 if (pterrain->resources[j] == NULL) {
2854 ok = FALSE;
2855 break;
2858 pterrain->resources[nval] = NULL;
2859 free(res);
2860 res = NULL;
2862 if (!ok) {
2863 break;
2866 output_type_iterate(o) {
2867 pterrain->road_output_incr_pct[o]
2868 = secfile_lookup_int_default(file, 0, "%s.road_%s_incr_pct",
2869 tsection, get_output_identifier(o));
2870 } output_type_iterate_end;
2872 if (!lookup_time(file, &pterrain->base_time, tsection, "base_time",
2873 filename, NULL, &ok)
2874 || !lookup_time(file, &pterrain->road_time, tsection, "road_time",
2875 filename, NULL, &ok)) {
2876 ruleset_error(LOG_ERROR, "%s", secfile_error());
2877 ok = FALSE;
2878 break;
2881 if (!lookup_terrain(file, "irrigation_result", filename, pterrain,
2882 &pterrain->irrigation_result)) {
2883 ok = FALSE;
2884 break;
2886 if (!secfile_lookup_int(file, &pterrain->irrigation_food_incr,
2887 "%s.irrigation_food_incr", tsection)
2888 || !lookup_time(file, &pterrain->irrigation_time,
2889 tsection, "irrigation_time", filename, NULL, &ok)) {
2890 ruleset_error(LOG_ERROR, "%s", secfile_error());
2891 ok = FALSE;
2892 break;
2895 if (!lookup_terrain(file, "mining_result", filename, pterrain,
2896 &pterrain->mining_result)) {
2897 ok = FALSE;
2898 break;
2900 if (!secfile_lookup_int(file, &pterrain->mining_shield_incr,
2901 "%s.mining_shield_incr", tsection)
2902 || !lookup_time(file, &pterrain->mining_time,
2903 tsection, "mining_time", filename, NULL, &ok)) {
2904 ruleset_error(LOG_ERROR, "%s", secfile_error());
2905 ok = FALSE;
2906 break;
2909 if (!lookup_unit_type(file, tsection, "animal",
2910 &pterrain->animal, filename,
2911 rule_name_get(&pterrain->name))) {
2912 ok = FALSE;
2913 break;
2916 if (!lookup_terrain(file, "transform_result", filename, pterrain,
2917 &pterrain->transform_result)) {
2918 ok = FALSE;
2919 break;
2921 if (!lookup_time(file, &pterrain->transform_time,
2922 tsection, "transform_time", filename, NULL, &ok)) {
2923 ruleset_error(LOG_ERROR, "%s", secfile_error());
2924 ok = FALSE;
2925 break;
2927 pterrain->pillage_time = 1; /* default */
2928 lookup_time(file, &pterrain->pillage_time,
2929 tsection, "pillage_time", filename, NULL, &ok);
2930 pterrain->clean_pollution_time = 3; /* default */
2931 lookup_time(file, &pterrain->clean_pollution_time,
2932 tsection, "clean_pollution_time", filename, NULL, &ok);
2933 pterrain->clean_fallout_time = 3; /* default */
2934 lookup_time(file, &pterrain->clean_fallout_time,
2935 tsection, "clean_fallout_time", filename, NULL, &ok);
2937 if (!lookup_terrain(file, "warmer_wetter_result", filename, pterrain,
2938 &pterrain->warmer_wetter_result)
2939 || !lookup_terrain(file, "warmer_drier_result", filename, pterrain,
2940 &pterrain->warmer_drier_result)
2941 || !lookup_terrain(file, "cooler_wetter_result", filename, pterrain,
2942 &pterrain->cooler_wetter_result)
2943 || !lookup_terrain(file, "cooler_drier_result", filename, pterrain,
2944 &pterrain->cooler_drier_result)) {
2945 ok = FALSE;
2946 break;
2949 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", tsection);
2950 BV_CLR_ALL(pterrain->flags);
2951 for (j = 0; j < nval; j++) {
2952 const char *sval = slist[j];
2953 enum terrain_flag_id flag
2954 = terrain_flag_id_by_name(sval, fc_strcasecmp);
2956 if (!terrain_flag_id_is_valid(flag)) {
2957 ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown flag \"%s\".",
2958 filename, tsection, sval);
2959 ok = FALSE;
2960 break;
2961 } else {
2962 BV_SET(pterrain->flags, flag);
2965 free(slist);
2967 if (!ok) {
2968 break;
2972 enum mapgen_terrain_property mtp;
2973 for (mtp = mapgen_terrain_property_begin();
2974 mtp != mapgen_terrain_property_end();
2975 mtp = mapgen_terrain_property_next(mtp)) {
2976 pterrain->property[mtp]
2977 = secfile_lookup_int_default(file, 0, "%s.property_%s", tsection,
2978 mapgen_terrain_property_name(mtp));
2982 slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", tsection);
2983 BV_CLR_ALL(pterrain->native_to);
2984 for (j = 0; j < nval; j++) {
2985 struct unit_class *class = unit_class_by_rule_name(slist[j]);
2987 if (!class) {
2988 ruleset_error(LOG_ERROR,
2989 "\"%s\" [%s] is native to unknown unit class \"%s\".",
2990 filename, tsection, slist[j]);
2991 ok = FALSE;
2992 break;
2993 } else {
2994 BV_SET(pterrain->native_to, uclass_index(class));
2997 free(slist);
2999 if (!ok) {
3000 break;
3003 /* get terrain color */
3005 fc_assert_ret_val(pterrain->rgb == NULL, FALSE);
3006 if (!rgbcolor_load(file, &pterrain->rgb, "%s.color", tsection)) {
3007 ruleset_error(LOG_ERROR, "Missing terrain color definition: %s",
3008 secfile_error());
3009 ok = FALSE;
3010 break;
3014 pterrain->helptext = lookup_strvec(file, tsection, "helptext");
3015 } terrain_type_iterate_end;
3018 if (ok) {
3019 /* extra details */
3020 extra_type_iterate(pextra) {
3021 BV_CLR_ALL(pextra->conflicts);
3022 } extra_type_iterate_end;
3024 extra_type_iterate(pextra) {
3025 if (!compat->compat_mode || compat->ver_terrain >= 10 || pextra->category != ECAT_RESOURCE) {
3026 const char *section = &extra_sections[extra_index(pextra) * MAX_SECTION_LABEL];
3027 const char **slist;
3028 struct requirement_vector *reqs;
3029 const char *catname;
3030 int cj;
3031 enum extra_cause cause;
3032 enum extra_rmcause rmcause;
3033 const char *eus_name;
3034 const char *vis_req_name;
3035 const struct advance *vis_req;
3037 catname = secfile_lookup_str(file, "%s.category", section);
3038 if (catname == NULL) {
3039 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\" has no category.",
3040 filename,
3041 extra_rule_name(pextra));
3042 ok = FALSE;
3043 break;
3045 pextra->category = extra_category_by_name(catname, fc_strcasecmp);
3046 if (!extra_category_is_valid(pextra->category)) {
3047 ruleset_error(LOG_ERROR,
3048 "\"%s\" extra \"%s\" has invalid category \"%s\".",
3049 filename, extra_rule_name(pextra), catname);
3050 ok = FALSE;
3051 break;
3054 slist = secfile_lookup_str_vec(file, &nval, "%s.causes", section);
3055 pextra->causes = 0;
3056 for (cj = 0; cj < nval; cj++) {
3057 const char *sval = slist[cj];
3058 cause = extra_cause_by_name(sval, fc_strcasecmp);
3060 if (!extra_cause_is_valid(cause)) {
3061 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown cause \"%s\".",
3062 filename,
3063 extra_rule_name(pextra),
3064 sval);
3065 ok = FALSE;
3066 break;
3067 } else {
3068 pextra->causes |= (1 << cause);
3069 extra_to_caused_by_list(pextra, cause);
3073 extra_to_category_list(pextra, pextra->category);
3075 if (pextra->causes == 0) {
3076 /* Extras that do not have any causes added to EC_NONE list */
3077 extra_to_caused_by_list(pextra, EC_NONE);
3080 if (!is_extra_caused_by(pextra, EC_BASE)
3081 && !is_extra_caused_by(pextra, EC_ROAD)
3082 && !is_extra_caused_by(pextra, EC_RESOURCE)) {
3083 /* Not a base, road, nor resource, so special */
3084 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3085 extra_to_caused_by_list(pextra, EC_SPECIAL);
3088 free(slist);
3090 slist = secfile_lookup_str_vec(file, &nval, "%s.rmcauses", section);
3091 pextra->rmcauses = 0;
3092 for (j = 0; j < nval; j++) {
3093 const char *sval = slist[j];
3094 rmcause = extra_rmcause_by_name(sval, fc_strcasecmp);
3096 if (!extra_rmcause_is_valid(rmcause)) {
3097 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown rmcause \"%s\".",
3098 filename,
3099 extra_rule_name(pextra),
3100 sval);
3101 ok = FALSE;
3102 break;
3103 } else {
3104 pextra->rmcauses |= (1 << rmcause);
3105 extra_to_removed_by_list(pextra, rmcause);
3109 free(slist);
3111 sz_strlcpy(pextra->activity_gfx,
3112 secfile_lookup_str_default(file, "-",
3113 "%s.activity_gfx", section));
3114 sz_strlcpy(pextra->act_gfx_alt,
3115 secfile_lookup_str_default(file, "-",
3116 "%s.act_gfx_alt", section));
3117 sz_strlcpy(pextra->act_gfx_alt2,
3118 secfile_lookup_str_default(file, "-",
3119 "%s.act_gfx_alt2", section));
3120 sz_strlcpy(pextra->rmact_gfx,
3121 secfile_lookup_str_default(file, "-",
3122 "%s.rmact_gfx", section));
3123 sz_strlcpy(pextra->rmact_gfx_alt,
3124 secfile_lookup_str_default(file, "-",
3125 "%s.rmact_gfx_alt", section));
3126 sz_strlcpy(pextra->graphic_str,
3127 secfile_lookup_str_default(file, "-", "%s.graphic", section));
3128 sz_strlcpy(pextra->graphic_alt,
3129 secfile_lookup_str_default(file, "-",
3130 "%s.graphic_alt", section));
3132 reqs = lookup_req_list(file, compat, section, "reqs", extra_rule_name(pextra));
3133 if (reqs == NULL) {
3134 ok = FALSE;
3135 break;
3137 requirement_vector_copy(&pextra->reqs, reqs);
3139 reqs = lookup_req_list(file, compat, section, "rmreqs", extra_rule_name(pextra));
3140 if (reqs == NULL) {
3141 ok = FALSE;
3142 break;
3144 requirement_vector_copy(&pextra->rmreqs, reqs);
3146 reqs = lookup_req_list(file, compat, section, "appearance_reqs", extra_rule_name(pextra));
3147 if (reqs == NULL) {
3148 ok = FALSE;
3149 break;
3151 requirement_vector_copy(&pextra->appearance_reqs, reqs);
3153 reqs = lookup_req_list(file, compat, section, "disappearance_reqs", extra_rule_name(pextra));
3154 if (reqs == NULL) {
3155 ok = FALSE;
3156 break;
3158 requirement_vector_copy(&pextra->disappearance_reqs, reqs);
3160 pextra->buildable = secfile_lookup_bool_default(file,
3161 is_extra_caused_by_worker_action(pextra),
3162 "%s.buildable", section);
3164 pextra->build_time = 0; /* default */
3165 lookup_time(file, &pextra->build_time, section, "build_time",
3166 filename, extra_rule_name(pextra), &ok);
3167 pextra->build_time_factor = secfile_lookup_int_default(file, 1,
3168 "%s.build_time_factor", section);
3169 pextra->removal_time = 0; /* default */
3170 lookup_time(file, &pextra->removal_time, section, "removal_time",
3171 filename, extra_rule_name(pextra), &ok);
3172 pextra->removal_time_factor = secfile_lookup_int_default(file, 1,
3173 "%s.removal_time_factor", section);
3175 pextra->defense_bonus = secfile_lookup_int_default(file, 0,
3176 "%s.defense_bonus",
3177 section);
3178 if (pextra->defense_bonus != 0) {
3179 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3180 extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
3181 } else {
3182 extra_to_caused_by_list(pextra, EC_DEFENSIVE);
3186 eus_name = secfile_lookup_str_default(file, "Normal", "%s.unit_seen", section);
3187 pextra->eus = extra_unit_seen_type_by_name(eus_name, fc_strcasecmp);
3188 if (!extra_unit_seen_type_is_valid(pextra->eus)) {
3189 ruleset_error(LOG_ERROR,
3190 "\"%s\" extra \"%s\" has illegal unit_seen value \"%s\".",
3191 filename, extra_rule_name(pextra),
3192 eus_name);
3193 ok = FALSE;
3194 break;
3196 if (pextra->eus == EUS_HIDDEN) {
3197 extra_type_list_append(extra_type_list_of_unit_hiders(), pextra);
3200 pextra->appearance_chance = secfile_lookup_int_default(file, RS_DEFAULT_EXTRA_APPEARANCE,
3201 "%s.appearance_chance",
3202 section);
3203 pextra->disappearance_chance = secfile_lookup_int_default(file,
3204 RS_DEFAULT_EXTRA_DISAPPEARANCE,
3205 "%s.disappearance_chance",
3206 section);
3208 slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", section);
3209 BV_CLR_ALL(pextra->native_to);
3210 for (j = 0; j < nval; j++) {
3211 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
3213 if (uclass == NULL) {
3214 ruleset_error(LOG_ERROR,
3215 "\"%s\" extra \"%s\" is native to unknown unit class \"%s\".",
3216 filename,
3217 extra_rule_name(pextra),
3218 slist[j]);
3219 ok = FALSE;
3220 break;
3221 } else {
3222 BV_SET(pextra->native_to, uclass_index(uclass));
3225 free(slist);
3227 if (!ok) {
3228 break;
3231 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3232 BV_CLR_ALL(pextra->flags);
3233 for (j = 0; j < nval; j++) {
3234 const char *sval = slist[j];
3235 enum extra_flag_id flag = extra_flag_id_by_name(sval, fc_strcasecmp);
3237 if (!extra_flag_id_is_valid(flag)) {
3238 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown flag \"%s\".",
3239 filename,
3240 extra_rule_name(pextra),
3241 sval);
3242 ok = FALSE;
3243 break;
3244 } else {
3245 BV_SET(pextra->flags, flag);
3248 free(slist);
3250 if (!ok) {
3251 break;
3254 slist = secfile_lookup_str_vec(file, &nval, "%s.conflicts", section);
3255 for (j = 0; j < nval; j++) {
3256 const char *sval = slist[j];
3257 struct extra_type *pextra2 = extra_type_by_rule_name(sval);
3259 if (pextra2 == NULL) {
3260 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown conflict extra \"%s\".",
3261 filename,
3262 extra_rule_name(pextra),
3263 sval);
3264 ok = FALSE;
3265 break;
3266 } else {
3267 BV_SET(pextra->conflicts, extra_index(pextra2));
3268 BV_SET(pextra2->conflicts, extra_index(pextra));
3272 free(slist);
3274 if (!ok) {
3275 break;
3278 slist = secfile_lookup_str_vec(file, &nval, "%s.hidden_by", section);
3279 BV_CLR_ALL(pextra->hidden_by);
3280 for (j = 0; j < nval; j++) {
3281 const char *sval = slist[j];
3282 const struct extra_type *top = extra_type_by_rule_name(sval);
3284 if (top == NULL) {
3285 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\" hidden by unknown extra \"%s\".",
3286 filename,
3287 extra_rule_name(pextra),
3288 sval);
3289 ok = FALSE;
3290 break;
3291 } else {
3292 BV_SET(pextra->hidden_by, extra_index(top));
3295 free(slist);
3297 if (!ok) {
3298 break;
3301 vis_req_name = secfile_lookup_str_default(file, "None",
3302 "%s.visibility_req", section);
3303 vis_req = advance_by_rule_name(vis_req_name);
3305 if (vis_req == NULL) {
3306 ruleset_error(LOG_ERROR, "\%s\" %s: unknown visibility_req %s.",
3307 filename, section, vis_req_name);
3308 ok = FALSE;
3309 break;
3312 pextra->visibility_req = advance_number(vis_req);
3314 pextra->helptext = lookup_strvec(file, section, "helptext");
3316 } extra_type_iterate_end;
3319 if (ok) {
3320 int i = 0;
3321 /* resource details */
3323 extra_type_by_cause_iterate(EC_RESOURCE, presource) {
3324 char identifier[MAX_LEN_NAME];
3325 const char *rsection = &resource_sections[i * MAX_SECTION_LABEL];
3327 output_type_iterate (o) {
3328 presource->data.resource->output[o] =
3329 secfile_lookup_int_default(file, 0, "%s.%s", rsection,
3330 get_output_identifier(o));
3331 } output_type_iterate_end;
3333 sz_strlcpy(identifier,
3334 secfile_lookup_str(file,"%s.identifier", rsection));
3335 presource->data.resource->id_old_save = identifier[0];
3336 if (RESOURCE_NULL_IDENTIFIER == presource->data.resource->id_old_save) {
3337 ruleset_error(LOG_ERROR, "\"%s\" [%s] identifier missing value.",
3338 filename, rsection);
3339 ok = FALSE;
3340 break;
3342 if (RESOURCE_NONE_IDENTIFIER == presource->data.resource->id_old_save) {
3343 ruleset_error(LOG_ERROR,
3344 "\"%s\" [%s] cannot use '%c' as an identifier;"
3345 " it is reserved.",
3346 filename, rsection, presource->data.resource->id_old_save);
3347 ok = FALSE;
3348 break;
3351 if (!ok) {
3352 break;
3355 i++;
3356 } extra_type_by_cause_iterate_end;
3359 if (ok) {
3360 /* This can't be part of previous loop as we don't want random data from previous
3361 * ruleset to play havoc on us when we have only some resource identifiers loaded
3362 * from the new ruleset. */
3363 extra_type_by_cause_iterate(EC_RESOURCE, pres) {
3364 extra_type_by_cause_iterate(EC_RESOURCE, pres2) {
3365 if (pres->data.resource->id_old_save == pres2->data.resource->id_old_save
3366 && pres != pres2) {
3367 ruleset_error(LOG_ERROR,
3368 "\"%s\" [%s] has the same identifier as [%s].",
3369 filename,
3370 extra_rule_name(pres),
3371 extra_rule_name(pres2));
3372 ok = FALSE;
3373 break;
3375 } extra_type_by_cause_iterate_end;
3377 if (!ok) {
3378 break;
3380 } extra_type_by_cause_iterate_end;
3383 if (ok) {
3384 /* base details */
3385 extra_type_by_cause_iterate(EC_BASE, pextra) {
3386 struct base_type *pbase = extra_base_get(pextra);
3387 const char *section = &base_sections[base_number(pbase) * MAX_SECTION_LABEL];
3388 int bj;
3389 const char **slist;
3390 const char *gui_str;
3392 gui_str = secfile_lookup_str(file,"%s.gui_type", section);
3393 pbase->gui_type = base_gui_type_by_name(gui_str, fc_strcasecmp);
3394 if (!base_gui_type_is_valid(pbase->gui_type)) {
3395 ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": unknown gui_type \"%s\".",
3396 filename,
3397 extra_rule_name(pextra),
3398 gui_str);
3399 ok = FALSE;
3400 break;
3403 pbase->border_sq = secfile_lookup_int_default(file, -1, "%s.border_sq",
3404 section);
3405 pbase->vision_main_sq = secfile_lookup_int_default(file, -1,
3406 "%s.vision_main_sq",
3407 section);
3408 pbase->vision_invis_sq = secfile_lookup_int_default(file, -1,
3409 "%s.vision_invis_sq",
3410 section);
3412 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3413 BV_CLR_ALL(pbase->flags);
3414 for (bj = 0; bj < nval; bj++) {
3415 const char *sval = slist[bj];
3416 enum base_flag_id flag = base_flag_id_by_name(sval, fc_strcasecmp);
3418 if (!base_flag_id_is_valid(flag)) {
3419 ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": unknown flag \"%s\".",
3420 filename,
3421 extra_rule_name(pextra),
3422 sval);
3423 ok = FALSE;
3424 break;
3425 } else if ((!compat->compat_mode || compat->ver_terrain >= 10)
3426 && base_flag_is_retired(flag)) {
3427 ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": retired flag "
3428 "\"%s\". Please update the ruleset.",
3429 filename,
3430 extra_rule_name(pextra),
3431 sval);
3432 ok = FALSE;
3433 } else {
3434 BV_SET(pbase->flags, flag);
3438 free(slist);
3440 if (!ok) {
3441 break;
3444 if (territory_claiming_base(pbase)) {
3445 extra_type_by_cause_iterate(EC_BASE, pextra2) {
3446 struct base_type *pbase2;
3448 if (pextra == pextra2) {
3449 /* End of the fully initialized bases iteration. */
3450 break;
3453 pbase2 = extra_base_get(pextra2);
3454 if (territory_claiming_base(pbase2)) {
3455 BV_SET(pextra->conflicts, extra_index(pextra2));
3456 BV_SET(pextra2->conflicts, extra_index(pextra));
3458 } extra_type_by_cause_iterate_end;
3460 } extra_type_by_cause_iterate_end;
3463 if (ok) {
3464 extra_type_by_cause_iterate(EC_ROAD, pextra) {
3465 struct road_type *proad = extra_road_get(pextra);
3466 const char *section = &road_sections[road_number(proad) * MAX_SECTION_LABEL];
3467 const char **slist;
3468 const char *special;
3469 const char *modestr;
3470 struct requirement_vector *reqs;
3472 reqs = lookup_req_list(file, compat, section, "first_reqs", extra_rule_name(pextra));
3473 if (reqs == NULL) {
3474 ok = FALSE;
3475 break;
3477 requirement_vector_copy(&proad->first_reqs, reqs);
3479 if (!secfile_lookup_int(file, &proad->move_cost,
3480 "%s.move_cost", section)) {
3481 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3482 ok = FALSE;
3483 break;
3486 modestr = secfile_lookup_str_default(file, "FastAlways", "%s.move_mode",
3487 section);
3488 proad->move_mode = road_move_mode_by_name(modestr, fc_strcasecmp);
3489 if (!road_move_mode_is_valid(proad->move_mode)) {
3490 ruleset_error(LOG_ERROR, "Illegal move_mode \"%s\" for road \"%s\"",
3491 modestr, extra_rule_name(pextra));
3492 ok = FALSE;
3493 break;
3496 output_type_iterate(o) {
3497 proad->tile_incr_const[o] =
3498 secfile_lookup_int_default(file, 0, "%s.%s_incr_const",
3499 section, get_output_identifier(o));
3500 proad->tile_incr[o] =
3501 secfile_lookup_int_default(file, 0, "%s.%s_incr",
3502 section, get_output_identifier(o));
3503 proad->tile_bonus[o] =
3504 secfile_lookup_int_default(file, 0, "%s.%s_bonus",
3505 section, get_output_identifier(o));
3506 } output_type_iterate_end;
3508 special = secfile_lookup_str_default(file, "None", "%s.compat_special", section);
3509 if (!fc_strcasecmp(special, "Road")) {
3510 if (compat_road) {
3511 ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"Road\"");
3512 ok = FALSE;
3514 compat_road = TRUE;
3515 proad->compat = ROCO_ROAD;
3516 } else if (!fc_strcasecmp(special, "Railroad")) {
3517 if (compat_rail) {
3518 ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"Railroad\"");
3519 ok = FALSE;
3521 compat_rail = TRUE;
3522 proad->compat = ROCO_RAILROAD;
3523 } else if (!fc_strcasecmp(special, "River")) {
3524 if (compat_river) {
3525 ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"River\"");
3526 ok = FALSE;
3528 compat_river = TRUE;
3529 proad->compat = ROCO_RIVER;
3530 } else if (!fc_strcasecmp(special, "None")) {
3531 proad->compat = ROCO_NONE;
3532 } else {
3533 ruleset_error(LOG_ERROR, "Illegal compatibility special \"%s\" for road %s",
3534 special, extra_rule_name(pextra));
3535 ok = FALSE;
3538 if (!ok) {
3539 break;
3542 slist = secfile_lookup_str_vec(file, &nval, "%s.integrates", section);
3543 BV_CLR_ALL(proad->integrates);
3544 for (j = 0; j < nval; j++) {
3545 const char *sval = slist[j];
3546 struct extra_type *textra = extra_type_by_rule_name(sval);
3547 struct road_type *top = NULL;
3549 if (textra != NULL) {
3550 top = extra_road_get(textra);
3553 if (top == NULL) {
3554 ruleset_error(LOG_ERROR, "\"%s\" road \"%s\" integrates with unknown road \"%s\".",
3555 filename,
3556 extra_rule_name(pextra),
3557 sval);
3558 ok = FALSE;
3559 break;
3560 } else {
3561 BV_SET(proad->integrates, road_number(top));
3564 free(slist);
3566 if (!ok) {
3567 break;
3570 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3571 BV_CLR_ALL(proad->flags);
3572 for (j = 0; j < nval; j++) {
3573 const char *sval = slist[j];
3574 enum road_flag_id flag = road_flag_id_by_name(sval, fc_strcasecmp);
3576 if (!road_flag_id_is_valid(flag)) {
3577 ruleset_error(LOG_ERROR, "\"%s\" road \"%s\": unknown flag \"%s\".",
3578 filename,
3579 extra_rule_name(pextra),
3580 sval);
3581 ok = FALSE;
3582 break;
3583 } else {
3584 BV_SET(proad->flags, flag);
3587 free(slist);
3589 if (!ok) {
3590 break;
3592 } extra_type_by_cause_iterate_end;
3595 if (ok) {
3596 secfile_check_unused(file);
3599 return ok;
3602 /**************************************************************************
3603 Load names of governments so other rulesets can refer to governments with
3604 their name. Also load multiplier names/count from governments.ruleset.
3605 **************************************************************************/
3606 static bool load_government_names(struct section_file *file,
3607 struct rscompat_info *compat)
3609 int nval = 0;
3610 struct section_list *sec;
3611 const char *filename = secfile_name(file);
3612 bool ok = TRUE;
3614 compat->ver_governments = rscompat_check_capabilities(file, filename,
3615 compat);
3616 if (compat->ver_governments <= 0) {
3617 return FALSE;
3620 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
3621 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
3623 sec = secfile_sections_by_name_prefix(file, GOVERNMENT_SECTION_PREFIX);
3624 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
3625 ruleset_error(LOG_ERROR, "\"%s\": No governments?!?", filename);
3626 ok = FALSE;
3627 } else if (nval > G_LAST) {
3628 ruleset_error(LOG_ERROR, "\"%s\": Too many governments (%d, max %d)",
3629 filename, nval, G_LAST);
3630 ok = FALSE;
3633 if (ok) {
3634 governments_alloc(nval);
3636 /* Government names are needed early so that get_government_by_name will
3637 * work. */
3638 governments_iterate(gov) {
3639 const char *sec_name =
3640 section_name(section_list_get(sec, government_index(gov)));
3642 if (!ruleset_load_names(&gov->name, NULL, file, sec_name)) {
3643 ok = FALSE;
3644 break;
3646 } governments_iterate_end;
3649 section_list_destroy(sec);
3651 if (ok) {
3652 sec = secfile_sections_by_name_prefix(file, MULTIPLIER_SECTION_PREFIX);
3653 nval = (NULL != sec ? section_list_size(sec) : 0);
3655 if (nval > MAX_NUM_MULTIPLIERS) {
3656 ruleset_error(LOG_ERROR, "\"%s\": Too many multipliers (%d, max %d)",
3657 filename, nval, MAX_NUM_MULTIPLIERS);
3659 ok = FALSE;
3660 } else {
3661 game.control.num_multipliers = nval;
3664 if (ok) {
3665 multipliers_iterate(pmul) {
3666 const char *sec_name =
3667 section_name(section_list_get(sec, multiplier_index(pmul)));
3669 if (!ruleset_load_names(&pmul->name, NULL, file, sec_name)) {
3670 ruleset_error(LOG_ERROR, "\"%s\": Cannot load multiplier names",
3671 filename);
3672 ok = FALSE;
3673 break;
3675 } multipliers_iterate_end;
3679 section_list_destroy(sec);
3681 return ok;
3684 /**************************************************************************
3685 This loads information from given governments.ruleset
3686 **************************************************************************/
3687 static bool load_ruleset_governments(struct section_file *file,
3688 struct rscompat_info *compat)
3690 struct section_list *sec;
3691 const char *filename = secfile_name(file);
3692 bool ok = TRUE;
3694 sec = secfile_sections_by_name_prefix(file, GOVERNMENT_SECTION_PREFIX);
3696 game.government_during_revolution
3697 = lookup_government(file, "governments.during_revolution", filename, NULL);
3698 if (game.government_during_revolution == NULL) {
3699 ok = FALSE;
3702 if (ok) {
3703 game.info.government_during_revolution_id =
3704 government_number(game.government_during_revolution);
3706 /* easy ones: */
3707 governments_iterate(g) {
3708 const int i = government_index(g);
3709 const char *sec_name = section_name(section_list_get(sec, i));
3710 struct requirement_vector *reqs =
3711 lookup_req_list(file, compat, sec_name, "reqs", government_rule_name(g));
3713 if (reqs == NULL) {
3714 ok = FALSE;
3715 break;
3718 if (NULL != secfile_entry_lookup(file, "%s.ai_better", sec_name)) {
3719 char entry[100];
3721 fc_snprintf(entry, sizeof(entry), "%s.ai_better", sec_name);
3722 g->ai.better = lookup_government(file, entry, filename, NULL);
3723 if (g->ai.better == NULL) {
3724 ok = FALSE;
3725 break;
3727 } else {
3728 g->ai.better = NULL;
3730 requirement_vector_copy(&g->reqs, reqs);
3732 sz_strlcpy(g->graphic_str,
3733 secfile_lookup_str(file, "%s.graphic", sec_name));
3734 sz_strlcpy(g->graphic_alt,
3735 secfile_lookup_str(file, "%s.graphic_alt", sec_name));
3737 g->helptext = lookup_strvec(file, sec_name, "helptext");
3738 } governments_iterate_end;
3742 if (ok) {
3743 /* titles */
3744 governments_iterate(g) {
3745 const char *sec_name =
3746 section_name(section_list_get(sec, government_index(g)));
3747 const char *male, *female;
3749 if (!(male = secfile_lookup_str(file, "%s.ruler_male_title", sec_name))
3750 || !(female = secfile_lookup_str(file, "%s.ruler_female_title",
3751 sec_name))) {
3752 ruleset_error(LOG_ERROR, "Lack of default ruler titles for "
3753 "government \"%s\" (nb %d): %s",
3754 government_rule_name(g), government_number(g),
3755 secfile_error());
3756 ok = FALSE;
3757 break;
3758 } else if (NULL == government_ruler_title_new(g, NULL, male, female)) {
3759 ruleset_error(LOG_ERROR, "Lack of default ruler titles for "
3760 "government \"%s\" (nb %d).",
3761 government_rule_name(g), government_number(g));
3762 ok = FALSE;
3763 break;
3765 } governments_iterate_end;
3768 section_list_destroy(sec);
3770 if (ok) {
3771 sec = secfile_sections_by_name_prefix(file, MULTIPLIER_SECTION_PREFIX);
3772 multipliers_iterate(pmul) {
3773 int id = multiplier_index(pmul);
3774 const char *sec_name = section_name(section_list_get(sec, id));
3776 if (!secfile_lookup_int(file, &pmul->start, "%s.start", sec_name)) {
3777 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3778 ok = FALSE;
3779 break;
3781 if (!secfile_lookup_int(file, &pmul->stop, "%s.stop", sec_name)) {
3782 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3783 ok = FALSE;
3784 break;
3786 if (pmul->stop <= pmul->start) {
3787 ruleset_error(LOG_ERROR, "Multiplier \"%s\" stop (%d) must be greater "
3788 "than start (%d)", multiplier_rule_name(pmul),
3789 pmul->stop, pmul->start);
3790 ok = FALSE;
3791 break;
3793 if (!secfile_lookup_int(file, &pmul->step, "%s.step", sec_name)) {
3794 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3795 ok = FALSE;
3796 break;
3798 if (((pmul->stop - pmul->start) % pmul->step) != 0) {
3799 ruleset_error(LOG_ERROR, "Multiplier \"%s\" step (%d) does not fit "
3800 "exactly into interval start-stop (%d to %d)",
3801 multiplier_rule_name(pmul), pmul->step,
3802 pmul->start, pmul->stop);
3803 ok = FALSE;
3804 break;
3806 if (!secfile_lookup_int(file, &pmul->def, "%s.default", sec_name)) {
3807 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3808 ok = FALSE;
3809 break;
3811 if (pmul->def < pmul->start || pmul->def > pmul->stop) {
3812 ruleset_error(LOG_ERROR, "Multiplier \"%s\" default (%d) not within "
3813 "legal range (%d to %d)", multiplier_rule_name(pmul),
3814 pmul->def, pmul->start, pmul->stop);
3815 ok = FALSE;
3816 break;
3818 if (((pmul->def - pmul->start) % pmul->step) != 0) {
3819 ruleset_error(LOG_ERROR, "Multiplier \"%s\" default (%d) not legal "
3820 "with respect to step size %d",
3821 multiplier_rule_name(pmul), pmul->def, pmul->step);
3822 ok = FALSE;
3823 break;
3825 pmul->offset = secfile_lookup_int_default(file, 0,
3826 "%s.offset", sec_name);
3827 pmul->factor = secfile_lookup_int_default(file, 100,
3828 "%s.factor", sec_name);
3829 if (pmul->factor == 0) {
3830 ruleset_error(LOG_ERROR, "Multiplier \"%s\" scaling factor must "
3831 "not be zero", multiplier_rule_name(pmul));
3832 ok = FALSE;
3833 break;
3836 pmul->helptext = lookup_strvec(file, sec_name, "helptext");
3837 } multipliers_iterate_end;
3838 section_list_destroy(sec);
3841 if (ok) {
3842 secfile_check_unused(file);
3845 return ok;
3848 /**************************************************************************
3849 Send information in packet_ruleset_control (numbers of units etc, and
3850 other miscellany) to specified connections.
3852 The client assumes that exactly one ruleset control packet is sent as
3853 a part of each ruleset send. So after sending this packet we have to
3854 resend every other part of the rulesets (and none of them should be
3855 is-info in the network code!). The client frees ruleset data when
3856 receiving this packet and then re-initializes as it receives the
3857 individual ruleset packets. See packhand.c.
3858 **************************************************************************/
3859 static void send_ruleset_control(struct conn_list *dest)
3861 int desc_left = game.control.desc_length;
3862 int idx = 0;
3864 lsend_packet_ruleset_control(dest, &(game.control));
3866 if (game.ruleset_summary != NULL) {
3867 struct packet_ruleset_summary summary;
3869 strncpy(summary.text, game.ruleset_summary, MAX_LEN_CONTENT);
3871 lsend_packet_ruleset_summary(dest, &summary);
3874 while (desc_left > 0) {
3875 struct packet_ruleset_description_part part;
3876 int this_len = desc_left;
3878 if (this_len > MAX_LEN_CONTENT - 21) {
3879 this_len = MAX_LEN_CONTENT - 1;
3882 part.text[this_len] = '\0';
3884 strncpy(part.text, &game.ruleset_description[idx], this_len);
3885 idx += this_len;
3886 desc_left -= this_len;
3888 lsend_packet_ruleset_description_part(dest, &part);
3892 /****************************************************************************
3893 Check for duplicate leader names in nation.
3894 If no duplicates return NULL; if yes return pointer to name which is
3895 repeated.
3896 ****************************************************************************/
3897 static const char *check_leader_names(struct nation_type *pnation)
3899 nation_leader_list_iterate(nation_leaders(pnation), pleader) {
3900 const char *name = nation_leader_name(pleader);
3902 nation_leader_list_iterate(nation_leaders(pnation), prev_leader) {
3903 if (prev_leader == pleader) {
3904 break;
3905 } else if (0 == fc_strcasecmp(name, nation_leader_name(prev_leader))) {
3906 return name;
3908 } nation_leader_list_iterate_end;
3909 } nation_leader_list_iterate_end;
3910 return NULL;
3913 /**************************************************************************
3914 Load names of nations so other rulesets can refer to nations with
3915 their name.
3916 **************************************************************************/
3917 static bool load_nation_names(struct section_file *file,
3918 struct rscompat_info *compat)
3920 struct section_list *sec;
3921 int j;
3922 bool ok = TRUE;
3923 const char *filename = secfile_name(file);
3925 compat->ver_nations = rscompat_check_capabilities(file, filename,
3926 compat);
3927 if (compat->ver_nations <= 0) {
3928 return FALSE;
3931 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
3932 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
3934 sec = secfile_sections_by_name_prefix(file, NATION_SECTION_PREFIX);
3935 if (NULL == sec) {
3936 ruleset_error(LOG_ERROR, "No available nations in this ruleset!");
3937 ok = FALSE;
3938 } else if (section_list_size(sec) > MAX_NUM_NATIONS) {
3939 ruleset_error(LOG_ERROR, "Too many nations (max %d, we have %d)!",
3940 MAX_NUM_NATIONS, section_list_size(sec));
3941 ok = FALSE;
3942 } else {
3943 game.control.nation_count = section_list_size(sec);
3944 nations_alloc(game.control.nation_count);
3946 nations_iterate(pl) {
3947 const int i = nation_index(pl);
3948 const char *sec_name = section_name(section_list_get(sec, i));
3949 const char *domain = secfile_lookup_str_default(file, NULL,
3950 "%s.translation_domain", sec_name);
3951 const char *noun_plural = secfile_lookup_str(file,
3952 "%s.plural", sec_name);
3955 if (domain == NULL) {
3956 domain = "freeciv-nations";
3959 if (!strcmp("freeciv", domain)) {
3960 pl->translation_domain = NULL;
3961 } else if (!strcmp("freeciv-nations", domain)) {
3962 pl->translation_domain = fc_malloc(strlen(domain) + 1);
3963 strcpy(pl->translation_domain, domain);
3964 } else {
3965 ruleset_error(LOG_ERROR, "Unsupported translation domain \"%s\" for %s",
3966 domain, sec_name);
3967 ok = FALSE;
3968 break;
3971 if (!ruleset_load_names(&pl->adjective, domain, file, sec_name)) {
3972 ok = FALSE;
3973 break;
3975 name_set(&pl->noun_plural, domain, noun_plural);
3977 /* Check if nation name is already defined. */
3978 for (j = 0; j < i && ok; j++) {
3979 struct nation_type *n2 = nation_by_number(j);
3981 /* Compare strings after stripping off qualifiers -- we don't want
3982 * two nations to end up with identical adjectives displayed to users.
3983 * (This check only catches English, not localisations, of course.) */
3984 if (0 == strcmp(Qn_(untranslated_name(&n2->adjective)),
3985 Qn_(untranslated_name(&pl->adjective)))) {
3986 ruleset_error(LOG_ERROR,
3987 "Two nations defined with the same adjective \"%s\": "
3988 "in section \'%s\' and section \'%s\'",
3989 Qn_(untranslated_name(&pl->adjective)),
3990 section_name(section_list_get(sec, j)), sec_name);
3991 ok = FALSE;
3992 } else if (!strcmp(rule_name_get(&n2->adjective),
3993 rule_name_get(&pl->adjective))) {
3994 /* We cannot have the same rule name, as the game needs them to be
3995 * distinct. */
3996 ruleset_error(LOG_ERROR,
3997 "Two nations defined with the same rule_name \"%s\": "
3998 "in section \'%s\' and section \'%s\'",
3999 rule_name_get(&pl->adjective),
4000 section_name(section_list_get(sec, j)), sec_name);
4001 ok = FALSE;
4002 } else if (0 == strcmp(Qn_(untranslated_name(&n2->noun_plural)),
4003 Qn_(untranslated_name(&pl->noun_plural)))) {
4004 /* We don't want identical English plural names either. */
4005 ruleset_error(LOG_ERROR,
4006 "Two nations defined with the same plural name \"%s\": "
4007 "in section \'%s\' and section \'%s\'",
4008 Qn_(untranslated_name(&pl->noun_plural)),
4009 section_name(section_list_get(sec, j)), sec_name);
4010 ok = FALSE;
4013 if (!ok) {
4014 break;
4016 } nations_iterate_end;
4019 section_list_destroy(sec);
4021 if (ok) {
4022 sec = secfile_sections_by_name_prefix(file, NATION_GROUP_SECTION_PREFIX);
4023 if (sec) {
4024 section_list_iterate(sec, psection) {
4025 struct nation_group *pgroup;
4026 const char *name;
4028 name = secfile_lookup_str(file, "%s.name", section_name(psection));
4029 if (NULL == name) {
4030 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4031 ok = FALSE;
4032 break;
4034 pgroup = nation_group_new(name);
4035 if (pgroup == NULL) {
4036 ok = FALSE;
4037 break;
4039 } section_list_iterate_end;
4040 section_list_destroy(sec);
4041 sec = NULL;
4045 return ok;
4048 /**************************************************************************
4049 Check if a string is in a vector (case-insensitively).
4050 **************************************************************************/
4051 static bool is_on_allowed_list(const char *name, const char **list, size_t len)
4053 int i;
4055 for (i = 0; i < len; i++) {
4056 if (!fc_strcasecmp(name, list[i])) {
4057 return TRUE;
4060 return FALSE;
4063 /****************************************************************************
4064 This function loads a city name list from a section file. The file and
4065 two section names (which will be concatenated) are passed in.
4066 ****************************************************************************/
4067 static bool load_city_name_list(struct section_file *file,
4068 struct nation_type *pnation,
4069 const char *secfile_str1,
4070 const char *secfile_str2,
4071 const char **allowed_terrains,
4072 size_t atcount)
4074 size_t dim, j;
4075 bool ok = TRUE;
4076 const char **cities = secfile_lookup_str_vec(file, &dim, "%s.%s",
4077 secfile_str1, secfile_str2);
4079 /* Each string will be of the form "<cityname> (<label>, <label>, ...)".
4080 * The cityname is just the name for this city, while each "label" matches
4081 * a terrain type for the city (or "river"), with a preceeding ! to negate
4082 * it. The parentheses are optional (but necessary to have the settings,
4083 * of course). Our job is now to parse it. */
4084 for (j = 0; j < dim; j++) {
4085 size_t len = strlen(cities[j]);
4086 char city_name[len + 1], *p, *next, *end;
4087 struct nation_city *pncity;
4089 sz_strlcpy(city_name, cities[j]);
4091 /* Now we wish to determine values for all of the city labels. A value
4092 * of NCP_NONE means no preference (which is necessary so that the use
4093 * of this is optional); NCP_DISLIKE means the label is negated and
4094 * NCP_LIKE means it's labelled. Mostly the parsing just involves
4095 * a lot of ugly string handling... */
4096 if ((p = strchr(city_name, '('))) {
4097 *p++ = '\0';
4099 if (!(end = strchr(p, ')'))) {
4100 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
4101 "unmatched parenthesis.", secfile_name(file),
4102 secfile_str1, secfile_str2, cities[j]);
4103 ok = FALSE;
4104 } else {
4105 for (*end++ = '\0'; '\0' != *end; end++) {
4106 if (!fc_isspace(*end)) {
4107 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
4108 "contains characters after last parenthesis.",
4109 secfile_name(file), secfile_str1, secfile_str2,
4110 cities[j]);
4111 ok = FALSE;
4112 break;
4118 /* Build the nation_city. */
4119 remove_leading_trailing_spaces(city_name);
4120 if (check_cityname(city_name)) {
4121 /* The ruleset contains a name that is too long. This shouldn't
4122 * happen - if it does, the author should get immediate feedback. */
4123 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
4124 "is too long.", secfile_name(file),
4125 secfile_str1, secfile_str2, city_name);
4126 ok = FALSE;
4127 city_name[MAX_LEN_CITYNAME - 1] = '\0';
4129 pncity = nation_city_new(pnation, city_name);
4131 if (NULL != p) {
4132 /* Handle the labels one at a time. */
4133 do {
4134 enum nation_city_preference prefer;
4136 if ((next = strchr(p, ','))) {
4137 *next = '\0';
4139 remove_leading_trailing_spaces(p);
4141 /* The ! is used to mark a negative, which is recorded with
4142 * NCP_DISLIKE. Otherwise we use a NCP_LIKE.
4144 if (*p == '!') {
4145 p++;
4146 prefer = NCP_DISLIKE;
4147 } else {
4148 prefer = NCP_LIKE;
4151 if (0 == fc_strcasecmp(p, "river")) {
4152 if (game.server.ruledit.allowed_terrains != NULL
4153 && !is_on_allowed_list(p,
4154 game.server.ruledit.allowed_terrains, atcount)) {
4155 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
4156 "has terrain hint \"%s\" not in allowed_terrains.",
4157 secfile_name(file), secfile_str1, secfile_str2,
4158 city_name, p);
4159 ok = FALSE;
4160 } else {
4161 nation_city_set_river_preference(pncity, prefer);
4163 } else {
4164 const struct terrain *pterrain = terrain_by_rule_name(p);
4166 if (NULL == pterrain) {
4167 /* Try with removing frequent trailing 's'. */
4168 size_t l = strlen(p);
4170 if (0 < l && 's' == fc_tolower(p[l - 1])) {
4171 p[l - 1] = '\0';
4173 pterrain = terrain_by_rule_name(p);
4176 /* Nationset may have been devised with a specific set of terrains
4177 * in mind which don't quite match this ruleset, in which case we
4178 * (a) quietly ignore any hints mentioned that don't happen to be in
4179 * the current ruleset, (b) enforce that terrains mentioned by nations
4180 * must be on the list */
4181 if (pterrain != NULL && game.server.ruledit.allowed_terrains != NULL) {
4182 if (!is_on_allowed_list(p,
4183 game.server.ruledit.allowed_terrains, atcount)) {
4184 /* Terrain exists, but not intended for these nations */
4185 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
4186 "has terrain hint \"%s\" not in allowed_terrains.",
4187 secfile_name(file), secfile_str1, secfile_str2,
4188 city_name, p);
4189 ok = FALSE;
4190 break;
4192 } else if (!pterrain) {
4193 /* Terrain doesn't exist; only complain if it's not on any list */
4194 if (game.server.ruledit.allowed_terrains == NULL
4195 || !is_on_allowed_list(p,
4196 game.server.ruledit.allowed_terrains, atcount)) {
4197 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
4198 "has unknown terrain hint \"%s\".",
4199 secfile_name(file), secfile_str1, secfile_str2,
4200 city_name, p);
4201 ok = FALSE;
4202 break;
4205 if (NULL != pterrain) {
4206 nation_city_set_terrain_preference(pncity, pterrain, prefer);
4210 p = next ? next + 1 : NULL;
4211 } while (NULL != p && '\0' != *p);
4215 if (NULL != cities) {
4216 free(cities);
4219 return ok;
4222 /**************************************************************************
4223 Load nations.ruleset file
4224 **************************************************************************/
4225 static bool load_ruleset_nations(struct section_file *file,
4226 struct rscompat_info *compat)
4228 struct government *gov;
4229 int j;
4230 size_t dim;
4231 char temp_name[MAX_LEN_NAME];
4232 const char **vec;
4233 const char *name, *bad_leader;
4234 const char *sval;
4235 int default_set;
4236 const char *filename = secfile_name(file);
4237 struct section_list *sec;
4238 enum trait tr;
4239 bool ok = TRUE;
4241 name = secfile_lookup_str_default(file, NULL, "ruledit.nationlist");
4242 if (name != NULL) {
4243 game.server.ruledit.nationlist = fc_strdup(name);
4245 vec = secfile_lookup_str_vec(file, &game.server.ruledit.embedded_nations_count,
4246 "ruledit.embedded_nations");
4248 if (vec != NULL) {
4249 /* Copy to persistent vector */
4250 game.server.ruledit.embedded_nations
4251 = fc_malloc(game.server.ruledit.embedded_nations_count * sizeof(char *));
4253 for (j = 0; j < game.server.ruledit.embedded_nations_count; j++) {
4254 game.server.ruledit.embedded_nations[j] = fc_strdup(vec[j]);
4257 free(vec);
4260 game.default_government = NULL;
4262 ruleset_load_traits(game.server.default_traits, file, "default_traits", "");
4263 for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
4264 if (game.server.default_traits[tr].min < 0) {
4265 game.server.default_traits[tr].min = TRAIT_DEFAULT_VALUE;
4267 if (game.server.default_traits[tr].max < 0) {
4268 game.server.default_traits[tr].max = TRAIT_DEFAULT_VALUE;
4270 if (game.server.default_traits[tr].fixed < 0) {
4271 int diff = game.server.default_traits[tr].max - game.server.default_traits[tr].min;
4273 /* TODO: Should sometimes round the a / 2 = x.5 results up */
4274 game.server.default_traits[tr].fixed = diff / 2 + game.server.default_traits[tr].min;
4276 if (game.server.default_traits[tr].max < game.server.default_traits[tr].min) {
4277 ruleset_error(LOG_ERROR, "Default values for trait %s not sane.",
4278 trait_name(tr));
4279 ok = FALSE;
4280 break;
4284 if (ok) {
4285 vec = secfile_lookup_str_vec(file, &game.server.ruledit.ag_count,
4286 "compatibility.allowed_govs");
4287 if (vec != NULL) {
4288 /* Copy to persistent vector */
4289 game.server.ruledit.nc_agovs
4290 = fc_malloc(game.server.ruledit.ag_count * sizeof(char *));
4291 game.server.ruledit.allowed_govs =
4292 (const char **)game.server.ruledit.nc_agovs;
4294 for (j = 0; j < game.server.ruledit.ag_count; j++) {
4295 game.server.ruledit.allowed_govs[j] = fc_strdup(vec[j]);
4298 free(vec);
4301 vec = secfile_lookup_str_vec(file, &game.server.ruledit.at_count,
4302 "compatibility.allowed_terrains");
4303 if (vec != NULL) {
4304 /* Copy to persistent vector */
4305 game.server.ruledit.nc_aterrs
4306 = fc_malloc(game.server.ruledit.at_count * sizeof(char *));
4307 game.server.ruledit.allowed_terrains =
4308 (const char **)game.server.ruledit.nc_aterrs;
4310 for (j = 0; j < game.server.ruledit.at_count; j++) {
4311 game.server.ruledit.allowed_terrains[j] = fc_strdup(vec[j]);
4314 free(vec);
4317 vec = secfile_lookup_str_vec(file, &game.server.ruledit.as_count,
4318 "compatibility.allowed_styles");
4319 if (vec != NULL) {
4320 /* Copy to persistent vector */
4321 game.server.ruledit.nc_astyles
4322 = fc_malloc(game.server.ruledit.as_count * sizeof(char *));
4323 game.server.ruledit.allowed_styles =
4324 (const char **)game.server.ruledit.nc_astyles;
4326 for (j = 0; j < game.server.ruledit.as_count; j++) {
4327 game.server.ruledit.allowed_styles[j] = fc_strdup(vec[j]);
4330 free(vec);
4333 sval = secfile_lookup_str_default(file, NULL,
4334 "compatibility.default_government");
4335 /* We deliberately don't check this against allowed_govs. It's only
4336 * specified once so not vulnerable to typos, and may usefully be set in
4337 * a specific ruleset to a gov not explicitly known by the nation set. */
4338 if (sval != NULL) {
4339 game.default_government = government_by_rule_name(sval);
4340 if (game.default_government == NULL) {
4341 ruleset_error(LOG_ERROR,
4342 "Tried to set unknown government type \"%s\" as default_government!",
4343 sval);
4344 ok = FALSE;
4345 } else {
4346 game.info.default_government_id
4347 = government_number(game.default_government);
4352 if (ok) {
4353 sec = secfile_sections_by_name_prefix(file, NATION_SET_SECTION_PREFIX);
4354 if (sec) {
4355 section_list_iterate(sec, psection) {
4356 const char *set_name, *set_rule_name, *set_description;
4358 set_name = secfile_lookup_str(file, "%s.name", section_name(psection));
4359 set_rule_name =
4360 secfile_lookup_str(file, "%s.rule_name", section_name(psection));
4361 set_description = secfile_lookup_str_default(file, "", "%s.description",
4362 section_name(psection));
4363 if (NULL == set_name || NULL == set_rule_name) {
4364 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4365 ok = FALSE;
4366 break;
4368 if (nation_set_new(set_name, set_rule_name, set_description) == NULL) {
4369 ok = FALSE;
4370 break;
4372 } section_list_iterate_end;
4373 section_list_destroy(sec);
4374 sec = NULL;
4375 } else {
4376 ruleset_error(LOG_ERROR,
4377 "At least one nation set [" NATION_SET_SECTION_PREFIX "_*] "
4378 "must be defined.");
4379 ok = FALSE;
4383 if (ok) {
4384 /* Default set that every nation is a member of. */
4385 sval = secfile_lookup_str_default(file, NULL,
4386 "compatibility.default_nationset");
4387 if (sval != NULL) {
4388 const struct nation_set *pset = nation_set_by_rule_name(sval);
4389 if (pset != NULL) {
4390 default_set = nation_set_number(pset);
4391 } else {
4392 ruleset_error(LOG_ERROR,
4393 "Unknown default_nationset \"%s\".", sval);
4394 ok = FALSE;
4396 } else if (nation_set_count() == 1) {
4397 /* If there's only one set defined, every nation is implicitly a
4398 * member of that set. */
4399 default_set = 0;
4400 } else {
4401 /* No default nation set; every nation must explicitly specify at
4402 * least one set to be a member of. */
4403 default_set = -1;
4407 if (ok) {
4408 sec = secfile_sections_by_name_prefix(file, NATION_GROUP_SECTION_PREFIX);
4409 if (sec) {
4410 section_list_iterate(sec, psection) {
4411 struct nation_group *pgroup;
4412 bool hidden;
4414 name = secfile_lookup_str(file, "%s.name", section_name(psection));
4415 pgroup = nation_group_by_rule_name(name);
4416 if (pgroup == NULL) {
4417 ok = FALSE;
4418 break;
4421 hidden = secfile_lookup_bool_default(file, FALSE, "%s.hidden",
4422 section_name(psection));
4423 nation_group_set_hidden(pgroup, hidden);
4425 if (!secfile_lookup_int(file, &j, "%s.match", section_name(psection))) {
4426 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4427 ok = FALSE;
4428 break;
4430 nation_group_set_match(pgroup, j);
4431 } section_list_iterate_end;
4432 section_list_destroy(sec);
4433 sec = NULL;
4437 if (ok) {
4438 sec = secfile_sections_by_name_prefix(file, NATION_SECTION_PREFIX);
4439 nations_iterate(pnation) {
4440 struct nation_type *pconflict;
4441 const int i = nation_index(pnation);
4442 char tmp[200] = "\0";
4443 const char *barb_type;
4444 const char *sec_name = section_name(section_list_get(sec, i));
4445 const char *legend;
4447 /* Nation sets and groups. */
4448 if (default_set >= 0) {
4449 nation_set_list_append(pnation->sets,
4450 nation_set_by_number(default_set));
4452 vec = secfile_lookup_str_vec(file, &dim, "%s.groups", sec_name);
4453 for (j = 0; j < dim; j++) {
4454 struct nation_set *pset = nation_set_by_rule_name(vec[j]);
4455 struct nation_group *pgroup = nation_group_by_rule_name(vec[j]);
4457 fc_assert(pset == NULL || pgroup == NULL);
4459 if (NULL != pset) {
4460 nation_set_list_append(pnation->sets, pset);
4461 } else if (NULL != pgroup) {
4462 nation_group_list_append(pnation->groups, pgroup);
4463 } else {
4464 /* For nation authors, this would probably be considered an error.
4465 * But it can happen normally. The civ1 compatibility ruleset only
4466 * uses the nations that were in civ1, so not all of the links will
4467 * exist. */
4468 log_verbose("Nation %s: Unknown set/group \"%s\".",
4469 nation_rule_name(pnation), vec[j]);
4472 if (NULL != vec) {
4473 free(vec);
4475 if (nation_set_list_size(pnation->sets) < 1) {
4476 ruleset_error(LOG_ERROR,
4477 "Nation %s is not a member of any nation set",
4478 nation_rule_name(pnation));
4479 ok = FALSE;
4480 break;
4483 /* Nation conflicts. */
4484 vec = secfile_lookup_str_vec(file, &dim, "%s.conflicts_with", sec_name);
4485 for (j = 0; j < dim; j++) {
4486 pconflict = nation_by_rule_name(vec[j]);
4488 if (pnation == pconflict) {
4489 ruleset_error(LOG_ERROR, "Nation %s conflicts with itself",
4490 nation_rule_name(pnation));
4491 ok = FALSE;
4492 break;
4493 } else if (NULL != pconflict) {
4494 nation_list_append(pnation->server.conflicts_with, pconflict);
4495 } else {
4496 /* For nation authors, this would probably be considered an error.
4497 * But it can happen normally. The civ1 compatibility ruleset only
4498 * uses the nations that were in civ1, so not all of the links will
4499 * exist. */
4500 log_verbose("Nation %s: conflicts_with nation \"%s\" is unknown.",
4501 nation_rule_name(pnation), vec[j]);
4504 if (NULL != vec) {
4505 free(vec);
4507 if (!ok) {
4508 break;
4511 /* Nation leaders. */
4512 for (j = 0; j < MAX_NUM_LEADERS; j++) {
4513 const char *sex;
4514 bool is_male = FALSE;
4516 name = secfile_lookup_str(file, "%s.leaders%d.name", sec_name, j);
4517 if (NULL == name) {
4518 /* No more to read. */
4519 break;
4522 if (check_name(name)) {
4523 /* The ruleset contains a name that is too long. This shouldn't
4524 * happen - if it does, the author should get immediate feedback */
4525 sz_strlcpy(temp_name, name);
4526 ruleset_error(LOG_ERROR, "Nation %s: leader name \"%s\" "
4527 "is too long.",
4528 nation_rule_name(pnation), name);
4529 ok = FALSE;
4530 break;
4533 sex = secfile_lookup_str(file, "%s.leaders%d.sex", sec_name, j);
4534 if (NULL == sex) {
4535 ruleset_error(LOG_ERROR, "Nation %s: leader \"%s\": %s.",
4536 nation_rule_name(pnation), name, secfile_error());
4537 ok = FALSE;
4538 break;
4539 } else if (0 == fc_strcasecmp("Male", sex)) {
4540 is_male = TRUE;
4541 } else if (0 != fc_strcasecmp("Female", sex)) {
4542 ruleset_error(LOG_ERROR, "Nation %s: leader \"%s\" has unsupported "
4543 "sex variant \"%s\".",
4544 nation_rule_name(pnation), name, sex);
4545 ok = FALSE;
4546 break;
4548 (void) nation_leader_new(pnation, name, is_male);
4550 if (!ok) {
4551 break;
4554 /* Check the number of leaders. */
4555 if (MAX_NUM_LEADERS == j) {
4556 /* Too much leaders, get the real number defined in the ruleset. */
4557 while (NULL != secfile_entry_lookup(file, "%s.leaders%d.name",
4558 sec_name, j)) {
4559 j++;
4561 ruleset_error(LOG_ERROR, "Nation %s: Too many leaders; max is %d",
4562 nation_rule_name(pnation), MAX_NUM_LEADERS);
4563 ok = FALSE;
4564 break;
4565 } else if (0 == j) {
4566 ruleset_error(LOG_ERROR,
4567 "Nation %s: no leaders; at least one is required.",
4568 nation_rule_name(pnation));
4569 ok = FALSE;
4570 break;
4573 /* Check if leader name is not already defined in this nation. */
4574 if ((bad_leader = check_leader_names(pnation))) {
4575 ruleset_error(LOG_ERROR,
4576 "Nation %s: leader \"%s\" defined more than once.",
4577 nation_rule_name(pnation), bad_leader);
4578 ok = FALSE;
4579 break;
4582 /* Nation player color preference, if any */
4583 fc_assert_ret_val(pnation->server.rgb == NULL, FALSE);
4584 (void) rgbcolor_load(file, &pnation->server.rgb, "%s.color", sec_name);
4586 /* Load nation traits */
4587 ruleset_load_traits(pnation->server.traits, file, sec_name, "trait_");
4588 for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
4589 bool server_traits_used = TRUE;
4591 if (pnation->server.traits[tr].min < 0) {
4592 pnation->server.traits[tr].min = game.server.default_traits[tr].min;
4593 } else {
4594 server_traits_used = FALSE;
4596 if (pnation->server.traits[tr].max < 0) {
4597 pnation->server.traits[tr].max = game.server.default_traits[tr].max;
4598 } else {
4599 server_traits_used = FALSE;
4601 if (pnation->server.traits[tr].fixed < 0) {
4602 if (server_traits_used) {
4603 pnation->server.traits[tr].fixed = game.server.default_traits[tr].fixed;
4604 } else {
4605 int diff = pnation->server.traits[tr].max - pnation->server.traits[tr].min;
4607 /* TODO: Should sometimes round the a / 2 = x.5 results up */
4608 pnation->server.traits[tr].fixed = diff / 2 + pnation->server.traits[tr].min;
4611 if (pnation->server.traits[tr].max < pnation->server.traits[tr].min) {
4612 ruleset_error(LOG_ERROR, "%s values for trait %s not sane.",
4613 nation_rule_name(pnation), trait_name(tr));
4614 ok = FALSE;
4615 break;
4619 if (!ok) {
4620 break;
4623 pnation->is_playable =
4624 secfile_lookup_bool_default(file, TRUE, "%s.is_playable", sec_name);
4626 /* Check barbarian type. Default is "None" meaning not a barbarian */
4627 barb_type = secfile_lookup_str_default(file, "None",
4628 "%s.barbarian_type", sec_name);
4629 pnation->barb_type = barbarian_type_by_name(barb_type, fc_strcasecmp);
4630 if (!barbarian_type_is_valid(pnation->barb_type)) {
4631 ruleset_error(LOG_ERROR,
4632 "Nation %s, barbarian_type is invalid (\"%s\")",
4633 nation_rule_name(pnation), barb_type);
4634 ok = FALSE;
4635 break;
4638 if (pnation->barb_type != NOT_A_BARBARIAN
4639 && pnation->is_playable) {
4640 /* We can't allow players to use barbarian nations, barbarians
4641 * may run out of nations */
4642 ruleset_error(LOG_ERROR,
4643 "Nation %s marked both barbarian and playable.",
4644 nation_rule_name(pnation));
4645 ok = FALSE;
4646 break;
4649 /* Flags */
4650 sz_strlcpy(pnation->flag_graphic_str,
4651 secfile_lookup_str_default(file, "-", "%s.flag", sec_name));
4652 sz_strlcpy(pnation->flag_graphic_alt,
4653 secfile_lookup_str_default(file, "-",
4654 "%s.flag_alt", sec_name));
4656 /* Ruler titles */
4657 for (j = 0;; j++) {
4658 const char *male, *female;
4660 name = secfile_lookup_str_default(file, NULL,
4661 "%s.ruler_titles%d.government",
4662 sec_name, j);
4663 if (NULL == name) {
4664 /* End of the list of ruler titles. */
4665 break;
4668 /* NB: even if the government doesn't exist, we load the entries for
4669 * the ruler titles to avoid warnings about unused entries. */
4670 male = secfile_lookup_str(file, "%s.ruler_titles%d.male_title",
4671 sec_name, j);
4672 female = secfile_lookup_str(file, "%s.ruler_titles%d.female_title",
4673 sec_name, j);
4674 gov = government_by_rule_name(name);
4676 /* Nationset may have been devised with a specific set of govs in
4677 * mind which don't quite match this ruleset, in which case we
4678 * (a) quietly ignore any govs mentioned that don't happen to be in
4679 * the current ruleset, (b) enforce that govs mentioned by nations
4680 * must be on the list */
4681 if (gov != NULL && game.server.ruledit.allowed_govs != NULL) {
4682 if (!is_on_allowed_list(name,
4683 game.server.ruledit.allowed_govs,
4684 game.server.ruledit.ag_count)) {
4685 /* Gov exists, but not intended for these nations */
4686 gov = NULL;
4687 ruleset_error(LOG_ERROR,
4688 "Nation %s: government \"%s\" not in allowed_govs.",
4689 nation_rule_name(pnation), name);
4690 ok = FALSE;
4691 break;
4693 } else if (!gov) {
4694 /* Gov doesn't exist; only complain if it's not on any list */
4695 if (game.server.ruledit.allowed_govs == NULL
4696 || !is_on_allowed_list(name,
4697 game.server.ruledit.allowed_govs,
4698 game.server.ruledit.ag_count)) {
4699 ruleset_error(LOG_ERROR, "Nation %s: government \"%s\" not found.",
4700 nation_rule_name(pnation), name);
4701 ok = FALSE;
4702 break;
4705 if (NULL != male && NULL != female) {
4706 if (gov) {
4707 (void) government_ruler_title_new(gov, pnation, male, female);
4709 } else {
4710 ruleset_error(LOG_ERROR, "%s", secfile_error());
4711 ok = FALSE;
4712 break;
4715 if (!ok) {
4716 break;
4719 /* City styles */
4720 name = secfile_lookup_str(file, "%s.style", sec_name);
4721 if (!name) {
4722 ruleset_error(LOG_ERROR, "%s", secfile_error());
4723 ok = FALSE;
4724 break;
4726 pnation->style = style_by_rule_name(name);
4727 if (pnation->style == NULL) {
4728 if (game.server.ruledit.allowed_styles == NULL
4729 || !is_on_allowed_list(name,
4730 game.server.ruledit.allowed_styles,
4731 game.server.ruledit.as_count)) {
4732 ruleset_error(LOG_ERROR, "Nation %s: Illegal style \"%s\"",
4733 nation_rule_name(pnation), name);
4734 ok = FALSE;
4735 break;
4736 } else {
4737 log_verbose("Nation %s: style \"%s\" not supported in this "
4738 "ruleset; using default.",
4739 nation_rule_name(pnation), name);
4740 pnation->style = style_by_number(0);
4744 /* Civilwar nations */
4745 vec = secfile_lookup_str_vec(file, &dim,
4746 "%s.civilwar_nations", sec_name);
4747 for (j = 0; j < dim; j++) {
4748 pconflict = nation_by_rule_name(vec[j]);
4750 /* No test for duplicate nations is performed. If there is a duplicate
4751 * entry it will just cause that nation to have an increased
4752 * probability of being chosen. */
4753 if (pconflict == pnation) {
4754 ruleset_error(LOG_ERROR, "Nation %s is its own civil war nation",
4755 nation_rule_name(pnation));
4756 ok = FALSE;
4757 break;
4758 } else if (NULL != pconflict) {
4759 nation_list_append(pnation->server.civilwar_nations, pconflict);
4760 nation_list_append(pconflict->server.parent_nations, pnation);
4761 } else {
4762 /* For nation authors, this would probably be considered an error.
4763 * But it can happen normally. The civ1 compatability ruleset only
4764 * uses the nations that were in civ1, so not all of the links will
4765 * exist. */
4766 log_verbose("Nation %s: civil war nation \"%s\" is unknown.",
4767 nation_rule_name(pnation), vec[j]);
4770 if (NULL != vec) {
4771 free(vec);
4773 if (!ok) {
4774 break;
4777 /* Load nation specific initial items */
4778 if (!lookup_tech_list(file, sec_name, "init_techs",
4779 pnation->init_techs, filename)) {
4780 ok = FALSE;
4781 break;
4783 if (!lookup_building_list(file, sec_name, "init_buildings",
4784 pnation->init_buildings, filename)) {
4785 ok = FALSE;
4786 break;
4788 if (!lookup_unit_list(file, sec_name, "init_units",
4789 pnation->init_units, filename)) {
4790 ok = FALSE;
4791 break;
4793 fc_strlcat(tmp, sec_name, 200);
4794 fc_strlcat(tmp, ".init_government", 200);
4795 if (secfile_entry_by_path(file, tmp)) {
4796 pnation->init_government = lookup_government(file, tmp, filename,
4797 NULL);
4798 /* If specified, init_government has to be in this specific ruleset,
4799 * not just allowed_govs */
4800 if (pnation->init_government == NULL) {
4801 ok = FALSE;
4802 break;
4804 /* ...but if a list of govs has been specified, enforce that this
4805 * nation's init_government is on the list. */
4806 if (game.server.ruledit.allowed_govs != NULL
4807 && !is_on_allowed_list(government_rule_name(pnation->init_government),
4808 game.server.ruledit.allowed_govs,
4809 game.server.ruledit.ag_count)) {
4810 ruleset_error(LOG_ERROR,
4811 "Nation %s: init_government \"%s\" not allowed.",
4812 nation_rule_name(pnation),
4813 government_rule_name(pnation->init_government));
4814 ok = FALSE;
4815 break;
4819 /* Read default city names. */
4820 if (!load_city_name_list(file, pnation, sec_name, "cities",
4821 game.server.ruledit.allowed_terrains,
4822 game.server.ruledit.at_count)) {
4823 ok = FALSE;
4824 break;
4827 legend = secfile_lookup_str_default(file, "", "%s.legend", sec_name);
4828 pnation->legend = fc_strdup(legend);
4829 if (check_strlen(pnation->legend, MAX_LEN_MSG, NULL)) {
4830 ruleset_error(LOG_ERROR,
4831 "Nation %s: legend \"%s\" is too long.",
4832 nation_rule_name(pnation),
4833 pnation->legend);
4834 ok = FALSE;
4835 break;
4838 pnation->player = NULL;
4839 } nations_iterate_end;
4840 section_list_destroy(sec);
4841 sec = NULL;
4844 /* Clean up on aborted load */
4845 if (sec) {
4846 fc_assert(!ok);
4847 section_list_destroy(sec);
4850 if (ok) {
4851 secfile_check_unused(file);
4854 if (ok) {
4855 /* Update cached number of playable nations in the current set */
4856 count_playable_nations();
4858 /* Sanity checks on all sets */
4859 nation_sets_iterate(pset) {
4860 int num_playable = 0, barb_land_count = 0, barb_sea_count = 0, barb_both_count = 0;
4862 nations_iterate(pnation) {
4863 if (nation_is_in_set(pnation, pset)) {
4864 switch (nation_barbarian_type(pnation)) {
4865 case NOT_A_BARBARIAN:
4866 if (is_nation_playable(pnation)) {
4867 num_playable++;
4869 break;
4870 case LAND_BARBARIAN:
4871 barb_land_count++;
4872 break;
4873 case SEA_BARBARIAN:
4874 barb_sea_count++;
4875 break;
4876 case ANIMAL_BARBARIAN:
4877 /* Animals are optional */
4878 break;
4879 case LAND_AND_SEA_BARBARIAN:
4880 barb_both_count++;
4881 break;
4882 default:
4883 fc_assert_ret_val(FALSE, FALSE);
4886 } nations_iterate_end;
4887 if (num_playable < 1) {
4888 ruleset_error(LOG_ERROR,
4889 "Nation set \"%s\" has no playable nations. "
4890 "At least one required!", nation_set_rule_name(pset));
4891 ok = FALSE;
4892 break;
4894 if (barb_land_count == 0 && barb_both_count == 0) {
4895 ruleset_error(LOG_ERROR,
4896 "No land barbarian nation defined in set \"%s\". "
4897 "At least one required!", nation_set_rule_name(pset));
4898 ok = FALSE;
4899 break;
4901 if (barb_sea_count == 0 && barb_both_count == 0) {
4902 ruleset_error(LOG_ERROR,
4903 "No sea barbarian nation defined in set \"%s\". "
4904 "At least one required!", nation_set_rule_name(pset));
4905 ok = FALSE;
4906 break;
4908 } nation_sets_iterate_end;
4911 return ok;
4914 /**************************************************************************
4915 Load names of nation styles so other rulesets can refer to styles with
4916 their name.
4917 **************************************************************************/
4918 static bool load_style_names(struct section_file *file,
4919 struct rscompat_info *compat)
4921 bool ok = TRUE;
4922 struct section_list *sec;
4923 const char *filename = secfile_name(file);
4925 compat->ver_styles = rscompat_check_capabilities(file, filename, compat);
4926 if (compat->ver_styles <= 0) {
4927 return FALSE;
4930 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
4931 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
4933 sec = secfile_sections_by_name_prefix(file, STYLE_SECTION_PREFIX);
4934 if (NULL == sec) {
4935 ruleset_error(LOG_ERROR, "No available nation styles in this ruleset!");
4936 ok = FALSE;
4937 } else {
4938 game.control.num_styles = section_list_size(sec);
4940 styles_alloc(game.control.num_styles);
4942 styles_iterate(ps) {
4943 const int i = style_index(ps);
4944 const char *sec_name = section_name(section_list_get(sec, i));
4946 ruleset_load_names(&ps->name, NULL, file, sec_name);
4947 } styles_iterate_end;
4950 section_list_destroy(sec);
4952 if (ok) {
4953 /* The citystyle sections: */
4954 int i = 0;
4956 sec = secfile_sections_by_name_prefix(file, CITYSTYLE_SECTION_PREFIX);
4957 if (NULL != sec) {
4958 city_styles_alloc(section_list_size(sec));
4959 section_list_iterate(sec, style) {
4960 if (!ruleset_load_names(&city_styles[i].name, NULL, file, section_name(style))) {
4961 ok = FALSE;
4962 break;
4964 i++;
4965 } section_list_iterate_end;
4967 section_list_destroy(sec);
4968 } else {
4969 city_styles_alloc(0);
4973 return ok;
4976 /**************************************************************************
4977 Load styles.ruleset file
4978 **************************************************************************/
4979 static bool load_ruleset_styles(struct section_file *file,
4980 struct rscompat_info *compat)
4982 struct section_list *sec;
4983 int i;
4984 bool ok = TRUE;
4986 /* City Styles ... */
4988 sec = secfile_sections_by_name_prefix(file, CITYSTYLE_SECTION_PREFIX);
4990 /* Get rest: */
4991 for (i = 0; i < game.control.styles_count; i++) {
4992 struct requirement_vector *reqs;
4993 const char *sec_name = section_name(section_list_get(sec, i));
4995 sz_strlcpy(city_styles[i].graphic,
4996 secfile_lookup_str(file, "%s.graphic", sec_name));
4997 sz_strlcpy(city_styles[i].graphic_alt,
4998 secfile_lookup_str(file, "%s.graphic_alt", sec_name));
4999 sz_strlcpy(city_styles[i].citizens_graphic,
5000 secfile_lookup_str_default(file, "-",
5001 "%s.citizens_graphic", sec_name));
5002 sz_strlcpy(city_styles[i].citizens_graphic_alt,
5003 secfile_lookup_str_default(file, "generic",
5004 "%s.citizens_graphic_alt", sec_name));
5006 reqs = lookup_req_list(file, compat, sec_name, "reqs", city_style_rule_name(i));
5007 if (reqs == NULL) {
5008 ok = FALSE;
5009 break;
5011 requirement_vector_copy(&city_styles[i].reqs, reqs);
5014 section_list_destroy(sec);
5016 if (ok) {
5017 sec = secfile_sections_by_name_prefix(file, MUSICSTYLE_SECTION_PREFIX);
5019 if (sec != NULL) {
5020 int musi;
5022 game.control.num_music_styles = section_list_size(sec);
5023 music_styles_alloc(game.control.num_music_styles);
5024 musi = 0;
5026 section_list_iterate(sec, psection) {
5027 struct requirement_vector *reqs;
5028 struct music_style *pmus = music_style_by_number(musi);
5029 const char *sec_name = section_name(psection);
5031 sz_strlcpy(pmus->music_peaceful,
5032 secfile_lookup_str_default(file, "-",
5033 "%s.music_peaceful", sec_name));
5034 sz_strlcpy(pmus->music_combat,
5035 secfile_lookup_str_default(file, "-",
5036 "%s.music_combat", sec_name));
5038 reqs = lookup_req_list(file, compat, sec_name, "reqs", "Music Style");
5039 if (reqs == NULL) {
5040 ok = FALSE;
5041 break;
5043 requirement_vector_copy(&pmus->reqs, reqs);
5045 musi++;
5046 } section_list_iterate_end;
5049 section_list_destroy(sec);
5052 return ok;
5055 /**************************************************************************
5056 Load a list of unit type flags that must be absent from the actor unit
5057 if an action auto performer should be triggered into an action auto
5058 performer.
5059 **************************************************************************/
5060 static bool load_action_auto_uflag_block(struct section_file *file,
5061 struct action_auto_perf *auto_perf,
5062 const char *uflags_path,
5063 const char *filename)
5065 /* Add each listed protected unit type flag as a !present
5066 * requirement. */
5067 if (secfile_entry_lookup(file, "%s", uflags_path)) {
5068 enum unit_type_flag_id *protecor_flag;
5069 size_t psize;
5070 int i;
5072 protecor_flag =
5073 secfile_lookup_enum_vec(file, &psize, unit_type_flag_id,
5074 "%s", uflags_path);
5076 if (!protecor_flag) {
5077 /* Entity exists but couldn't read it. */
5078 ruleset_error(LOG_ERROR,
5079 "\"%s\": %s: bad unit type flag list.",
5080 filename, uflags_path);
5082 return FALSE;
5085 for (i = 0; i < psize; i++) {
5086 requirement_vector_append(&auto_perf->reqs,
5087 req_from_values(VUT_UTFLAG,
5088 REQ_RANGE_LOCAL,
5089 FALSE, FALSE, TRUE,
5090 protecor_flag[i]));
5093 free(protecor_flag);
5096 return TRUE;
5099 /**************************************************************************
5100 Load the list of actions an action auto performer should try. The
5101 actions will be tried in the given order.
5102 **************************************************************************/
5103 static bool load_action_auto_actions(struct section_file *file,
5104 struct action_auto_perf *auto_perf,
5105 const char *actions_path,
5106 const char *filename)
5108 /* Read the alternative actions. */
5109 if (secfile_entry_lookup(file, "%s", actions_path)) {
5110 enum gen_action *unit_acts;
5111 size_t asize;
5112 int i;
5114 unit_acts = secfile_lookup_enum_vec(file, &asize, gen_action,
5115 "%s", actions_path);
5117 if (!unit_acts) {
5118 /* Entity exists but couldn't read it. */
5119 ruleset_error(LOG_ERROR,
5120 "\"%s\": %s: bad action list",
5121 filename, actions_path);
5123 return FALSE;
5126 for (i = 0; i < asize; i++) {
5127 auto_perf->alternatives[i] = unit_acts[i];
5130 free(unit_acts);
5133 return TRUE;
5136 /**************************************************************************
5137 Load missing unit upkeep ruleset settings as action auto performers.
5138 **************************************************************************/
5139 static bool load_muuk_as_action_auto(struct section_file *file,
5140 struct action_auto_perf *auto_perf,
5141 const char *item,
5142 const char *filename)
5144 char uflags_path[100];
5145 char action_path[100];
5147 fc_snprintf(uflags_path, sizeof(uflags_path),
5148 "missing_unit_upkeep.%s_protected", item);
5149 fc_snprintf(action_path, sizeof(action_path),
5150 "missing_unit_upkeep.%s_unit_act", item);
5152 return (load_action_auto_uflag_block(file, auto_perf, uflags_path,
5153 filename)
5154 && load_action_auto_actions(file, auto_perf, action_path,
5155 filename));
5158 /**************************************************************************
5159 Load cities.ruleset file
5160 **************************************************************************/
5161 static bool load_ruleset_cities(struct section_file *file,
5162 struct rscompat_info *compat)
5164 const char *filename = secfile_name(file);
5165 const char *item;
5166 struct section_list *sec;
5167 bool ok = TRUE;
5169 compat->ver_cities = rscompat_check_capabilities(file, filename, compat);
5170 if (compat->ver_cities <= 0) {
5171 return FALSE;
5174 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
5175 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
5177 /* Specialist options */
5178 sec = secfile_sections_by_name_prefix(file, SPECIALIST_SECTION_PREFIX);
5179 if (section_list_size(sec) >= SP_MAX) {
5180 ruleset_error(LOG_ERROR, "\"%s\": Too many specialists (%d, max %d).",
5181 filename, section_list_size(sec), SP_MAX);
5182 ok = FALSE;
5185 if (ok) {
5186 int i = 0;
5188 game.control.num_specialist_types = section_list_size(sec);
5190 section_list_iterate(sec, psection) {
5191 struct specialist *s = specialist_by_number(i);
5192 struct requirement_vector *reqs;
5193 const char *sec_name = section_name(psection);
5195 if (!ruleset_load_names(&s->name, NULL, file, sec_name)) {
5196 ok = FALSE;
5197 break;
5200 item = secfile_lookup_str_default(file, untranslated_name(&s->name),
5201 "%s.short_name", sec_name);
5202 name_set(&s->abbreviation, NULL, item);
5204 sz_strlcpy(s->graphic_alt,
5205 secfile_lookup_str_default(file, "-",
5206 "%s.graphic_alt", sec_name));
5208 reqs = lookup_req_list(file, compat, sec_name, "reqs", specialist_rule_name(s));
5209 if (reqs == NULL) {
5210 ok = FALSE;
5211 break;
5213 requirement_vector_copy(&s->reqs, reqs);
5215 s->helptext = lookup_strvec(file, sec_name, "helptext");
5217 if (requirement_vector_size(&s->reqs) == 0 && DEFAULT_SPECIALIST == -1) {
5218 DEFAULT_SPECIALIST = i;
5220 i++;
5221 } section_list_iterate_end;
5224 if (ok && DEFAULT_SPECIALIST == -1) {
5225 ruleset_error(LOG_ERROR,
5226 "\"%s\": must give a min_size of 0 for at least one "
5227 "specialist type.", filename);
5228 ok = FALSE;
5230 section_list_destroy(sec);
5231 sec = NULL;
5233 if (ok) {
5234 /* City Parameters */
5236 game.info.celebratesize =
5237 secfile_lookup_int_default(file, GAME_DEFAULT_CELEBRATESIZE,
5238 "parameters.celebrate_size_limit");
5239 game.info.add_to_size_limit =
5240 secfile_lookup_int_default(file, GAME_DEFAULT_ADDTOSIZE, "parameters.add_to_size_limit");
5241 game.info.angrycitizen =
5242 secfile_lookup_bool_default(file, GAME_DEFAULT_ANGRYCITIZEN,
5243 "parameters.angry_citizens");
5245 game.info.changable_tax =
5246 secfile_lookup_bool_default(file, GAME_DEFAULT_CHANGABLE_TAX, "parameters.changable_tax");
5247 game.info.forced_science =
5248 secfile_lookup_int_default(file, 0, "parameters.forced_science");
5249 game.info.forced_luxury =
5250 secfile_lookup_int_default(file, 100, "parameters.forced_luxury");
5251 game.info.forced_gold =
5252 secfile_lookup_int_default(file, 0, "parameters.forced_gold");
5253 if (game.info.forced_science + game.info.forced_luxury
5254 + game.info.forced_gold != 100) {
5255 ruleset_error(LOG_ERROR,
5256 "\"%s\": Forced taxes do not add up in ruleset!",
5257 filename);
5258 ok = FALSE;
5262 if (ok) {
5263 /* civ1 & 2 didn't reveal tiles */
5264 game.server.vision_reveal_tiles =
5265 secfile_lookup_bool_default(file, GAME_DEFAULT_VISION_REVEAL_TILES,
5266 "parameters.vision_reveal_tiles");
5268 game.info.pop_report_zeroes =
5269 secfile_lookup_int_default(file, 1, "parameters.pop_report_zeroes");
5271 /* Citizens configuration. */
5272 game.info.citizen_nationality =
5273 secfile_lookup_bool_default(file, GAME_DEFAULT_NATIONALITY,
5274 "citizen.nationality");
5275 game.info.citizen_convert_speed =
5276 secfile_lookup_int_default(file, GAME_DEFAULT_CONVERT_SPEED,
5277 "citizen.convert_speed");
5278 game.info.citizen_partisans_pct =
5279 secfile_lookup_int_default(file, 0, "citizen.partisans_pct");
5282 if (ok) {
5283 /* Missing unit upkeep. */
5284 struct action_auto_perf *auto_perf;
5286 /* Can't pay food upkeep! */
5287 auto_perf = action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_FOOD);
5288 auto_perf->cause = AAPC_UNIT_UPKEEP;
5290 /* This is about food upkeep. */
5291 requirement_vector_append(&auto_perf->reqs,
5292 req_from_str("OutputType", "Local",
5293 FALSE, TRUE, TRUE,
5294 "Food"));
5296 /* Internally represented as an action auto performer rule. */
5297 if (!load_muuk_as_action_auto(file, auto_perf, "food", filename)) {
5298 ok = FALSE;
5301 game.info.muuk_food_wipe =
5302 secfile_lookup_bool_default(file, RS_DEFAULT_MUUK_FOOD_WIPE,
5303 "missing_unit_upkeep.food_wipe");
5305 /* Can't pay gold upkeep! */
5306 auto_perf = action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_GOLD);
5307 auto_perf->cause = AAPC_UNIT_UPKEEP;
5309 /* This is about gold upkeep. */
5310 requirement_vector_append(&auto_perf->reqs,
5311 req_from_str("OutputType", "Local",
5312 FALSE, TRUE, TRUE,
5313 "Gold"));
5315 /* Internally represented as an action auto performer rule. */
5316 if (!load_muuk_as_action_auto(file, auto_perf, "gold", filename)) {
5317 ok = FALSE;
5320 game.info.muuk_gold_wipe =
5321 secfile_lookup_bool_default(file, RS_DEFAULT_MUUK_GOLD_WIPE,
5322 "missing_unit_upkeep.gold_wipe");
5324 /* Can't pay shield upkeep! */
5325 auto_perf = action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_SHIELD);
5326 auto_perf->cause = AAPC_UNIT_UPKEEP;
5328 /* This is about shield upkeep. */
5329 requirement_vector_append(&auto_perf->reqs,
5330 req_from_str("OutputType", "Local",
5331 FALSE, TRUE, TRUE,
5332 "Shield"));
5334 /* Internally represented as an action auto performer rule. */
5335 if (!load_muuk_as_action_auto(file, auto_perf, "shield", filename)) {
5336 ok = FALSE;
5339 game.info.muuk_shield_wipe =
5340 secfile_lookup_bool_default(file, RS_DEFAULT_MUUK_SHIELD_WIPE,
5341 "missing_unit_upkeep.shield_wipe");
5344 if (ok) {
5345 secfile_check_unused(file);
5348 return ok;
5351 /**************************************************************************
5352 Load effects.ruleset file
5353 **************************************************************************/
5354 static bool load_ruleset_effects(struct section_file *file,
5355 struct rscompat_info *compat)
5357 struct section_list *sec;
5358 const char *type;
5359 const char *filename;
5360 bool ok = TRUE;
5361 bool effect_type_warned = FALSE;
5363 filename = secfile_name(file);
5365 compat->ver_effects = rscompat_check_capabilities(file, filename, compat);
5366 if (compat->ver_effects <= 0) {
5367 return FALSE;
5369 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
5370 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
5372 /* Parse effects and add them to the effects ruleset cache. */
5373 sec = secfile_sections_by_name_prefix(file, EFFECT_SECTION_PREFIX);
5374 section_list_iterate(sec, psection) {
5375 enum effect_type eff;
5376 int value;
5377 struct multiplier *pmul;
5378 struct effect *peffect;
5379 const char *sec_name = section_name(psection);
5380 struct requirement_vector *reqs;
5382 type = secfile_lookup_str(file, "%s.type", sec_name);
5383 if (type == NULL && compat->compat_mode) {
5384 /* Backward compatibility. Field used to be named "name" */
5385 type = secfile_lookup_str(file, "%s.name", sec_name);
5386 if (type != NULL && !effect_type_warned) {
5387 log_deprecation(_("Effects should have \"type\", not the same field with old name \"name\"."));
5388 effect_type_warned = TRUE;
5391 if (type == NULL) {
5392 ruleset_error(LOG_ERROR, "\"%s\" [%s] missing effect type.", filename, sec_name);
5393 ok = FALSE;
5394 break;
5397 eff = effect_type_by_name(type, fc_strcasecmp);
5398 if (!effect_type_is_valid(eff)) {
5399 ruleset_error(LOG_ERROR, "\"%s\" [%s] lists unknown effect type \"%s\".",
5400 filename, sec_name, type);
5401 ok = FALSE;
5402 break;
5405 value = secfile_lookup_int_default(file, 1, "%s.value", sec_name);
5408 const char *multiplier_name
5409 = secfile_lookup_str(file, "%s.multiplier", sec_name);
5411 if (multiplier_name) {
5412 pmul = multiplier_by_rule_name(multiplier_name);
5413 if (!pmul) {
5414 ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown multiplier \"%s\".",
5415 filename, sec_name, multiplier_name);
5416 ok = FALSE;
5417 break;
5419 } else {
5420 pmul = NULL;
5424 peffect = effect_new(eff, value, pmul);
5426 reqs = lookup_req_list(file, compat, sec_name, "reqs", type);
5427 if (reqs == NULL) {
5428 ok = FALSE;
5429 break;
5432 requirement_vector_iterate(reqs, preq) {
5433 effect_req_append(peffect, *preq);
5434 } requirement_vector_iterate_end;
5436 if (compat->compat_mode) {
5437 reqs = lookup_req_list(file, compat, sec_name, "nreqs", type);
5438 if (reqs == NULL) {
5439 ok = FALSE;
5440 break;
5442 requirement_vector_iterate(reqs, preq) {
5443 preq->present = !preq->present;
5444 effect_req_append(peffect, *preq);
5445 } requirement_vector_iterate_end;
5447 } section_list_iterate_end;
5448 section_list_destroy(sec);
5450 if (ok) {
5451 secfile_check_unused(file);
5454 return ok;
5457 /**************************************************************************
5458 Print an error message if the value is out of range.
5459 **************************************************************************/
5460 static int secfile_lookup_int_default_min_max(struct section_file *file,
5461 int def, int min, int max,
5462 const char *path, ...)
5463 fc__attribute((__format__ (__printf__, 5, 6)));
5464 static int secfile_lookup_int_default_min_max(struct section_file *file,
5465 int def, int min, int max,
5466 const char *path, ...)
5468 char fullpath[256];
5469 int ival;
5470 va_list args;
5472 va_start(args, path);
5473 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
5474 va_end(args);
5476 if (!secfile_lookup_int(file, &ival, "%s", fullpath)) {
5477 ival = def;
5480 if (ival < min) {
5481 ruleset_error(LOG_ERROR,"\"%s\" should be in the interval [%d, %d] "
5482 "but is %d; using the minimal value.",
5483 fullpath, min, max, ival);
5484 ival = min;
5487 if (ival > max) {
5488 ruleset_error(LOG_ERROR,"\"%s\" should be in the interval [%d, %d] "
5489 "but is %d; using the maximal value.",
5490 fullpath, min, max, ival);
5491 ival = max;
5494 return ival;
5497 /**************************************************************************
5498 Load ruleset file.
5499 **************************************************************************/
5500 static bool load_ruleset_game(struct section_file *file, bool act,
5501 struct rscompat_info *compat)
5503 const char *sval, **svec;
5504 const char *filename;
5505 int *food_ini;
5506 int i;
5507 size_t teams;
5508 const char *pref_text;
5509 size_t gni_tmp;
5510 struct section_list *sec;
5511 size_t nval;
5512 const char *name;
5513 bool ok = TRUE;
5515 if (file == NULL) {
5516 return FALSE;
5518 filename = secfile_name(file);
5520 name = secfile_lookup_str_default(file, NULL, "ruledit.description_file");
5521 if (name != NULL) {
5522 game.server.ruledit.description_file = fc_strdup(name);
5525 /* section: tileset */
5526 pref_text = secfile_lookup_str_default(file, "", "tileset.prefered");
5527 if (pref_text[0] != '\0') {
5528 log_deprecation("Entry tileset.prefered in game.ruleset."
5529 " Use correct spelling tileset.preferred instead");
5531 pref_text = secfile_lookup_str_default(file, pref_text, "tileset.preferred");
5532 if (pref_text[0] != '\0') {
5533 /* There was tileset suggestion */
5534 sz_strlcpy(game.control.preferred_tileset, pref_text);
5535 } else {
5536 /* No tileset suggestions */
5537 game.control.preferred_tileset[0] = '\0';
5540 /* section: soundset */
5541 pref_text = secfile_lookup_str_default(file, "", "soundset.prefered");
5542 if (pref_text[0] != '\0') {
5543 log_deprecation("Entry soundset.prefered in game.ruleset."
5544 " Use correct spelling soundset.preferred instead");
5546 pref_text = secfile_lookup_str_default(file, pref_text, "soundset.preferred");
5547 if (pref_text[0] != '\0') {
5548 /* There was soundset suggestion */
5549 sz_strlcpy(game.control.preferred_soundset, pref_text);
5550 } else {
5551 /* No soundset suggestions */
5552 game.control.preferred_soundset[0] = '\0';
5555 /* section: musicset */
5556 pref_text = secfile_lookup_str_default(file, "", "musicset.prefered");
5557 if (pref_text[0] != '\0') {
5558 log_deprecation("Entry musicset.prefered in game.ruleset."
5559 " Use correct spelling musicset.preferred instead");
5561 pref_text = secfile_lookup_str_default(file, pref_text, "musicset.preferred");
5562 if (pref_text[0] != '\0') {
5563 /* There was musicset suggestion */
5564 sz_strlcpy(game.control.preferred_musicset, pref_text);
5565 } else {
5566 /* No musicset suggestions */
5567 game.control.preferred_musicset[0] = '\0';
5570 /* section: about */
5571 pref_text = secfile_lookup_str(file, "about.name");
5572 /* Ruleset/modpack name found */
5573 sz_strlcpy(game.control.name, pref_text);
5575 pref_text = secfile_lookup_str_default(file, "", "about.version");
5576 if (pref_text[0] != '\0') {
5577 /* Ruleset/modpack version found */
5578 sz_strlcpy(game.control.version, pref_text);
5579 } else {
5580 /* No version information */
5581 game.control.version[0] = '\0';
5584 pref_text = secfile_lookup_str_default(file, "", "about.summary");
5585 if (pref_text[0] != '\0') {
5586 int len;
5588 /* Ruleset/modpack summary found */
5589 len = strlen(pref_text);
5590 game.ruleset_summary = fc_malloc(len + 1);
5591 fc_strlcpy(game.ruleset_summary, pref_text, len + 1);
5592 } else {
5593 /* No summary */
5594 if (game.ruleset_summary != NULL) {
5595 free(game.ruleset_summary);
5596 game.ruleset_summary = NULL;
5600 pref_text = secfile_lookup_str_default(file, "", "about.description");
5601 if (pref_text[0] != '\0') {
5602 int len;
5604 /* Ruleset/modpack description found */
5605 len = strlen(pref_text);
5606 game.ruleset_description = fc_malloc(len + 1);
5607 fc_strlcpy(game.ruleset_description, pref_text, len + 1);
5608 game.control.desc_length = len;
5609 } else {
5610 /* No description */
5611 if (game.ruleset_description != NULL) {
5612 free(game.ruleset_description);
5613 game.ruleset_description = NULL;
5615 game.control.desc_length = 0;
5618 pref_text = secfile_lookup_str_default(file, "", "about.capabilities");
5619 if (pref_text[0] != '\0') {
5620 int len = strlen(pref_text);
5622 game.ruleset_capabilities = fc_malloc(len + 1);
5623 fc_strlcpy(game.ruleset_capabilities, pref_text, len +1);
5624 } else {
5625 game.ruleset_capabilities = fc_malloc(1);
5626 game.ruleset_capabilities[0] = '\0';
5629 /* section: options */
5630 if (!lookup_tech_list(file, "options", "global_init_techs",
5631 game.rgame.global_init_techs, filename)) {
5632 ok = FALSE;
5635 if (ok) {
5636 if (!lookup_building_list(file, "options", "global_init_buildings",
5637 game.rgame.global_init_buildings, filename)) {
5638 ok = FALSE;
5642 if (ok) {
5643 const char **slist;
5644 int j;
5646 game.control.popup_tech_help = secfile_lookup_bool_default(file, FALSE,
5647 "options.popup_tech_help");
5649 /* section: civstyle */
5650 game.info.base_pollution
5651 = secfile_lookup_int_default(file, RS_DEFAULT_BASE_POLLUTION,
5652 "civstyle.base_pollution");
5654 game.info.gameloss_style = GAMELOSS_STYLE_CLASSICAL;
5656 slist = secfile_lookup_str_vec(file, &nval, "civstyle.gameloss_style");
5657 for (j = 0; j < nval; j++) {
5658 enum gameloss_style style;
5660 sval = slist[j];
5661 if (strcmp(sval, "") == 0) {
5662 continue;
5664 style = gameloss_style_by_name(sval, fc_strcasecmp);
5665 if (!gameloss_style_is_valid(style)) {
5666 ruleset_error(LOG_ERROR, "\"%s\": bad value \"%s\" for gameloss_style.",
5667 filename, sval);
5668 ok = FALSE;
5669 break;
5670 } else {
5671 game.info.gameloss_style |= style;
5674 free(slist);
5677 if (ok) {
5678 game.info.happy_cost
5679 = secfile_lookup_int_def_min_max(file,
5680 RS_DEFAULT_HAPPY_COST,
5681 RS_MIN_HAPPY_COST,
5682 RS_MAX_HAPPY_COST,
5683 "civstyle.happy_cost");
5684 game.info.food_cost
5685 = secfile_lookup_int_default_min_max(file,
5686 RS_DEFAULT_FOOD_COST,
5687 RS_MIN_FOOD_COST,
5688 RS_MAX_FOOD_COST,
5689 "civstyle.food_cost");
5690 game.info.civil_war_enabled
5691 = secfile_lookup_bool_default(file, TRUE, "civstyle.civil_war_enabled");
5693 game.info.paradrop_to_transport
5694 = secfile_lookup_bool_default(file, FALSE,
5695 "civstyle.paradrop_to_transport");
5697 /* TODO: move to global_unit_options */
5698 game.info.base_bribe_cost
5699 = secfile_lookup_int_default_min_max(file,
5700 RS_DEFAULT_BASE_BRIBE_COST,
5701 RS_MIN_BASE_BRIBE_COST,
5702 RS_MAX_BASE_BRIBE_COST,
5703 "civstyle.base_bribe_cost");
5704 /* TODO: move to global_unit_options */
5705 game.server.ransom_gold
5706 = secfile_lookup_int_default_min_max(file,
5707 RS_DEFAULT_RANSOM_GOLD,
5708 RS_MIN_RANSOM_GOLD,
5709 RS_MAX_RANSOM_GOLD,
5710 "civstyle.ransom_gold");
5711 /* TODO: move to global_unit_options */
5712 game.info.pillage_select
5713 = secfile_lookup_bool_default(file, RS_DEFAULT_PILLAGE_SELECT,
5714 "civstyle.pillage_select");
5716 game.info.tech_steal_allow_holes
5717 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_STEAL_HOLES,
5718 "civstyle.tech_steal_allow_holes");
5719 game.info.tech_trade_allow_holes
5720 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_TRADE_HOLES,
5721 "civstyle.tech_trade_allow_holes");
5722 game.info.tech_trade_loss_allow_holes
5723 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_TRADE_LOSS_HOLES,
5724 "civstyle.tech_trade_loss_allow_holes");
5725 game.info.tech_parasite_allow_holes
5726 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_PARASITE_HOLES,
5727 "civstyle.tech_parasite_allow_holes");
5728 game.info.tech_loss_allow_holes
5729 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_LOSS_HOLES,
5730 "civstyle.tech_loss_allow_holes");
5732 /* TODO: move to global_unit_options */
5733 game.server.upgrade_veteran_loss
5734 = secfile_lookup_int_default_min_max(file,
5735 RS_DEFAULT_UPGRADE_VETERAN_LOSS,
5736 RS_MIN_UPGRADE_VETERAN_LOSS,
5737 RS_MAX_UPGRADE_VETERAN_LOSS,
5738 "civstyle.upgrade_veteran_loss");
5739 /* TODO: move to global_unit_options */
5740 game.server.autoupgrade_veteran_loss
5741 = secfile_lookup_int_default_min_max(file,
5742 RS_DEFAULT_UPGRADE_VETERAN_LOSS,
5743 RS_MIN_UPGRADE_VETERAN_LOSS,
5744 RS_MAX_UPGRADE_VETERAN_LOSS,
5745 "civstyle.autoupgrade_veteran_loss");
5747 game.info.base_tech_cost
5748 = secfile_lookup_int_default_min_max(file,
5749 RS_DEFAULT_BASE_TECH_COST,
5750 RS_MIN_BASE_TECH_COST,
5751 RS_MAX_BASE_TECH_COST,
5752 "research.base_tech_cost");
5754 food_ini = secfile_lookup_int_vec(file, &gni_tmp,
5755 "civstyle.granary_food_ini");
5756 game.info.granary_num_inis = (int) gni_tmp;
5758 if (game.info.granary_num_inis > MAX_GRANARY_INIS) {
5759 ruleset_error(LOG_ERROR,
5760 "Too many granary_food_ini entries (%d, max %d)",
5761 game.info.granary_num_inis, MAX_GRANARY_INIS);
5762 ok = FALSE;
5763 } else if (game.info.granary_num_inis == 0) {
5764 log_error("No values for granary_food_ini. Using default "
5765 "value %d.", RS_DEFAULT_GRANARY_FOOD_INI);
5766 game.info.granary_num_inis = 1;
5767 game.info.granary_food_ini[0] = RS_DEFAULT_GRANARY_FOOD_INI;
5768 } else {
5769 int gi;
5771 /* check for <= 0 entries */
5772 for (gi = 0; gi < game.info.granary_num_inis; gi++) {
5773 if (food_ini[gi] <= 0) {
5774 if (gi == 0) {
5775 food_ini[gi] = RS_DEFAULT_GRANARY_FOOD_INI;
5776 } else {
5777 food_ini[gi] = food_ini[gi - 1];
5779 log_error("Bad value for granary_food_ini[%i]. Using %i.",
5780 gi, food_ini[gi]);
5782 game.info.granary_food_ini[gi] = food_ini[gi];
5785 free(food_ini);
5788 if (ok) {
5789 game.info.granary_food_inc
5790 = secfile_lookup_int_default_min_max(file,
5791 RS_DEFAULT_GRANARY_FOOD_INC,
5792 RS_MIN_GRANARY_FOOD_INC,
5793 RS_MAX_GRANARY_FOOD_INC,
5794 "civstyle.granary_food_inc");
5796 output_type_iterate(o) {
5797 game.info.min_city_center_output[o]
5798 = secfile_lookup_int_default_min_max(file,
5799 RS_DEFAULT_CITY_CENTER_OUTPUT,
5800 RS_MIN_CITY_CENTER_OUTPUT,
5801 RS_MAX_CITY_CENTER_OUTPUT,
5802 "civstyle.min_city_center_%s",
5803 get_output_identifier(o));
5804 } output_type_iterate_end;
5807 if (ok) {
5808 const char *tus_text;
5810 game.server.init_vis_radius_sq
5811 = secfile_lookup_int_default_min_max(file,
5812 RS_DEFAULT_VIS_RADIUS_SQ,
5813 RS_MIN_VIS_RADIUS_SQ,
5814 RS_MAX_VIS_RADIUS_SQ,
5815 "civstyle.init_vis_radius_sq");
5817 game.info.init_city_radius_sq
5818 = secfile_lookup_int_default_min_max(file,
5819 RS_DEFAULT_CITY_RADIUS_SQ,
5820 RS_MIN_CITY_RADIUS_SQ,
5821 RS_MAX_CITY_RADIUS_SQ,
5822 "civstyle.init_city_radius_sq");
5824 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_GOLD_UPKEEP_STYLE,
5825 "civstyle.gold_upkeep_style");
5826 game.info.gold_upkeep_style = gold_upkeep_style_by_name(tus_text,
5827 fc_strcasecmp);
5828 if (!gold_upkeep_style_is_valid(game.info.gold_upkeep_style)) {
5829 ruleset_error(LOG_ERROR, "Unknown gold upkeep style \"%s\"",
5830 tus_text);
5831 ok = FALSE;
5834 /* section: illness */
5835 game.info.illness_on
5836 = secfile_lookup_bool_default(file, RS_DEFAULT_ILLNESS_ON,
5837 "illness.illness_on");
5838 game.info.illness_base_factor
5839 = secfile_lookup_int_default_min_max(file,
5840 RS_DEFAULT_ILLNESS_BASE_FACTOR,
5841 RS_MIN_ILLNESS_BASE_FACTOR,
5842 RS_MAX_ILLNESS_BASE_FACTOR,
5843 "illness.illness_base_factor");
5844 game.info.illness_min_size
5845 = secfile_lookup_int_default_min_max(file,
5846 RS_DEFAULT_ILLNESS_MIN_SIZE,
5847 RS_MIN_ILLNESS_MIN_SIZE,
5848 RS_MAX_ILLNESS_MIN_SIZE,
5849 "illness.illness_min_size");
5850 game.info.illness_trade_infection
5851 = secfile_lookup_int_default_min_max(file,
5852 RS_DEFAULT_ILLNESS_TRADE_INFECTION_PCT,
5853 RS_MIN_ILLNESS_TRADE_INFECTION_PCT,
5854 RS_MAX_ILLNESS_TRADE_INFECTION_PCT,
5855 "illness.illness_trade_infection");
5856 game.info.illness_pollution_factor
5857 = secfile_lookup_int_default_min_max(file,
5858 RS_DEFAULT_ILLNESS_POLLUTION_PCT,
5859 RS_MIN_ILLNESS_POLLUTION_PCT,
5860 RS_MAX_ILLNESS_POLLUTION_PCT,
5861 "illness.illness_pollution_factor");
5863 /* section: incite_cost */
5864 game.server.base_incite_cost
5865 = secfile_lookup_int_default_min_max(file,
5866 RS_DEFAULT_INCITE_BASE_COST,
5867 RS_MIN_INCITE_BASE_COST,
5868 RS_MAX_INCITE_BASE_COST,
5869 "incite_cost.base_incite_cost");
5870 game.server.incite_improvement_factor
5871 = secfile_lookup_int_default_min_max(file,
5872 RS_DEFAULT_INCITE_IMPROVEMENT_FCT,
5873 RS_MIN_INCITE_IMPROVEMENT_FCT,
5874 RS_MAX_INCITE_IMPROVEMENT_FCT,
5875 "incite_cost.improvement_factor");
5876 game.server.incite_unit_factor
5877 = secfile_lookup_int_default_min_max(file,
5878 RS_DEFAULT_INCITE_UNIT_FCT,
5879 RS_MIN_INCITE_UNIT_FCT,
5880 RS_MAX_INCITE_UNIT_FCT,
5881 "incite_cost.unit_factor");
5882 game.server.incite_total_factor
5883 = secfile_lookup_int_default_min_max(file,
5884 RS_DEFAULT_INCITE_TOTAL_FCT,
5885 RS_MIN_INCITE_TOTAL_FCT,
5886 RS_MAX_INCITE_TOTAL_FCT,
5887 "incite_cost.total_factor");
5889 /* section: global_unit_options */
5890 game.info.slow_invasions
5891 = secfile_lookup_bool_default(file, RS_DEFAULT_SLOW_INVASIONS,
5892 "global_unit_options.slow_invasions");
5894 if (ok) {
5895 /* Auto attack. */
5896 struct action_auto_perf *auto_perf;
5898 /* A unit moved next to this unit and the autoattack server setting
5899 * is enabled. */
5900 auto_perf = action_auto_perf_slot_number(ACTION_AUTO_MOVED_ADJ);
5901 auto_perf->cause = AAPC_UNIT_MOVED_ADJ;
5903 /* Auto attack happens during war. */
5904 requirement_vector_append(&auto_perf->reqs,
5905 req_from_values(VUT_DIPLREL,
5906 REQ_RANGE_LOCAL,
5907 FALSE, TRUE, TRUE, DS_WAR));
5909 /* Needs a movement point to auto attack. */
5910 requirement_vector_append(&auto_perf->reqs,
5911 req_from_values(VUT_MINMOVES,
5912 REQ_RANGE_LOCAL,
5913 FALSE, TRUE, TRUE, 1));
5915 /* Internally represented as an action auto performer rule. */
5916 if (!load_action_auto_uflag_block(file, auto_perf,
5917 "auto_attack.will_never",
5918 filename)) {
5919 ok = FALSE;
5922 /* TODO: It would be great if unit_survive_autoattack() could be made
5923 * flexible enough to also handle diplomatic actions etc. */
5924 auto_perf->alternatives[0] = ACTION_CAPTURE_UNITS;
5925 auto_perf->alternatives[1] = ACTION_BOMBARD;
5926 auto_perf->alternatives[2] = ACTION_ATTACK;
5929 /* section: actions */
5930 if (ok) {
5931 const char *text;
5932 int force_capture_units, force_bombard, force_explode_nuclear;
5934 if (secfile_lookup_bool_default(file, RS_DEFAULT_FORCE_TRADE_ROUTE,
5935 "actions.force_trade_route")) {
5936 /* Forbid entering the marketplace when a trade route can be
5937 * established. */
5938 BV_SET(action_by_number(ACTION_MARKETPLACE)->blocked_by,
5939 ACTION_TRADE_ROUTE);
5942 /* Forbid bombarding, exploading nuclear or attacking when it is
5943 * legal to capture units. */
5944 force_capture_units
5945 = secfile_lookup_bool_default(file, RS_DEFAULT_FORCE_CAPTURE_UNITS,
5946 "actions.force_capture_units");
5948 if (force_capture_units) {
5949 BV_SET(action_by_number(ACTION_BOMBARD)->blocked_by,
5950 ACTION_CAPTURE_UNITS);
5951 BV_SET(action_by_number(ACTION_NUKE)->blocked_by,
5952 ACTION_CAPTURE_UNITS);
5953 BV_SET(action_by_number(ACTION_ATTACK)->blocked_by,
5954 ACTION_CAPTURE_UNITS);
5955 BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
5956 ACTION_CAPTURE_UNITS);
5959 /* Forbid exploding nuclear or attacking when it is legal to
5960 * bombard. */
5961 force_bombard
5962 = secfile_lookup_bool_default(file, RS_DEFAULT_FORCE_BOMBARD,
5963 "actions.force_bombard");
5965 if (force_bombard) {
5966 BV_SET(action_by_number(ACTION_NUKE)->blocked_by,
5967 ACTION_BOMBARD);
5968 BV_SET(action_by_number(ACTION_ATTACK)->blocked_by,
5969 ACTION_BOMBARD);
5970 BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
5971 ACTION_BOMBARD);
5974 /* Forbid attacking when it is legal to do explode nuclear. */
5975 force_explode_nuclear
5976 = secfile_lookup_bool_default(file,
5977 RS_DEFAULT_FORCE_EXPLODE_NUCLEAR,
5978 "actions.force_explode_nuclear");
5980 if (force_explode_nuclear) {
5981 BV_SET(action_by_number(ACTION_ATTACK)->blocked_by,
5982 ACTION_NUKE);
5983 BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
5984 ACTION_NUKE);
5987 /* If the poison city action should empty the granary. */
5988 /* TODO: empty granary and reduce population should become separate
5989 * action effect flags when actions are generalized. */
5990 game.info.poison_empties_food_stock
5991 = secfile_lookup_bool_default(file,
5992 RS_DEFAULT_POISON_EMPTIES_FOOD_STOCK,
5993 "actions.poison_empties_food_stock");
5995 /* Allow setting max distance for bombardment before generalized
5996 * actions. */
5998 struct entry *pentry;
5999 int max_range;
6001 pentry = secfile_entry_lookup(file, "actions.bombard_max_range");
6003 if (!pentry) {
6004 max_range = RS_DEFAULT_BOMBARD_MAX_RANGE;
6005 } else {
6006 switch (entry_type(pentry)) {
6007 case ENTRY_INT:
6008 if (entry_int_get(pentry, &max_range)) {
6009 break;
6011 /* Fall through to error handling. */
6012 case ENTRY_STR:
6014 const char *custom;
6016 if (entry_str_get(pentry, &custom)
6017 && !fc_strcasecmp(custom, RS_ACTION_NO_MAX_DISTANCE)) {
6018 max_range = ACTION_DISTANCE_UNLIMITED;
6019 break;
6022 /* Fall through to error handling. */
6023 default:
6024 ruleset_error(LOG_ERROR, "Bad actions.bombard_max_range");
6025 ok = FALSE;
6026 max_range = RS_DEFAULT_BOMBARD_MAX_RANGE;
6027 break;
6031 action_by_number(ACTION_BOMBARD)->max_distance = max_range;
6034 text = secfile_lookup_str_default(file,
6035 /* TRANS: _Poison City (3% chance of success). */
6036 N_("%sPoison City%s"),
6037 "actions.ui_name_poison_city");
6038 sz_strlcpy(action_by_number(ACTION_SPY_POISON)->ui_name,
6039 text);
6041 text = secfile_lookup_str_default(file,
6042 /* TRANS: S_abotage Enemy Unit (3% chance of success). */
6043 N_("S%sabotage Enemy Unit%s"),
6044 "actions.ui_name_sabotage_unit");
6045 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_UNIT)->ui_name,
6046 text);
6048 text = secfile_lookup_str_default(file,
6049 /* TRANS: Bribe Enemy _Unit (3% chance of success). */
6050 N_("Bribe Enemy %sUnit%s"),
6051 "actions.ui_name_bribe_unit");
6052 sz_strlcpy(action_by_number(ACTION_SPY_BRIBE_UNIT)->ui_name,
6053 text);
6055 text = secfile_lookup_str_default(file,
6056 /* TRANS: _Sabotage City (3% chance of success). */
6057 N_("%sSabotage City%s"),
6058 "actions.ui_name_sabotage_city");
6059 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_CITY)->ui_name,
6060 text);
6062 text = secfile_lookup_str_default(file,
6063 /* TRANS: Industria_l Sabotage (3% chance of success). */
6064 N_("Industria%sl Sabotage%s"),
6065 "actions.ui_name_targeted_sabotage_city");
6066 sz_strlcpy(
6067 action_by_number(ACTION_SPY_TARGETED_SABOTAGE_CITY)->ui_name,
6068 text);
6070 text = secfile_lookup_str_default(file,
6071 /* TRANS: Incite a Re_volt (3% chance of success). */
6072 N_("Incite a Re%svolt%s"),
6073 "actions.ui_name_incite_city");
6074 sz_strlcpy(action_by_number(ACTION_SPY_INCITE_CITY)->ui_name,
6075 text);
6077 text = secfile_lookup_str_default(file,
6078 /* TRANS: Incite a Re_volt and Escape (3% chance of success). */
6079 N_("Incite a Re%svolt and Escape%s"),
6080 "actions.ui_name_incite_city_escape");
6081 sz_strlcpy(action_by_number(ACTION_SPY_INCITE_CITY_ESC)->ui_name,
6082 text);
6084 text = secfile_lookup_str_default(file,
6085 /* TRANS: Establish _Embassy (100% chance of success). */
6086 N_("Establish %sEmbassy%s"),
6087 "actions.ui_name_establish_embassy");
6088 sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY)->ui_name,
6089 text);
6091 text = secfile_lookup_str_default(file,
6092 /* TRANS: Becom_e Ambassador (100% chance of success). */
6093 N_("Becom%se Ambassador%s"),
6094 "actions.ui_name_establish_embassy_stay");
6095 sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY_STAY)->ui_name,
6096 text);
6098 text = secfile_lookup_str_default(file,
6099 /* TRANS: Steal _Technology (3% chance of success). */
6100 N_("Steal %sTechnology%s"),
6101 "actions.ui_name_steal_tech");
6102 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_TECH)->ui_name,
6103 text);
6105 text = secfile_lookup_str_default(file,
6106 /* TRANS: In_dustrial Espionage (3% chance of success). */
6107 N_("In%sdustrial Espionage%s"),
6108 "actions.ui_name_targeted_steal_tech");
6109 sz_strlcpy(action_by_number(ACTION_SPY_TARGETED_STEAL_TECH)->ui_name,
6110 text);
6112 text = secfile_lookup_str_default(file,
6113 /* TRANS: _Investigate City (100% chance of success). */
6114 N_("%sInvestigate City%s"),
6115 "actions.ui_name_investigate_city");
6116 sz_strlcpy(action_by_number(ACTION_SPY_INVESTIGATE_CITY)->ui_name,
6117 text);
6119 text = secfile_lookup_str_default(file,
6120 /* TRANS: _Investigate City (spends the unit) (100% chance of
6121 * success). */
6122 N_("%sInvestigate City (spends the unit)%s"),
6123 "actions.ui_name_investigate_city_spend_unit");
6124 sz_strlcpy(action_by_number(ACTION_INV_CITY_SPEND)->ui_name,
6125 text);
6127 text = secfile_lookup_str_default(file,
6128 /* TRANS: Steal _Gold (100% chance of success). */
6129 N_("Steal %sGold%s"),
6130 "actions.ui_name_steal_gold");
6131 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_GOLD)->ui_name,
6132 text);
6134 text = secfile_lookup_str_default(file,
6135 /* TRANS: Steal _Maps (100% chance of success). */
6136 N_("Steal %sMaps%s"),
6137 "actions.ui_name_steal_maps");
6138 sz_strlcpy(action_by_number(ACTION_STEAL_MAPS)->ui_name,
6139 text);
6141 text = secfile_lookup_str_default(file,
6142 /* TRANS: Establish Trade _Route (100% chance of success). */
6143 N_("Establish Trade %sRoute%s"),
6144 "actions.ui_name_establish_trade_route");
6145 sz_strlcpy(action_by_number(ACTION_TRADE_ROUTE)->ui_name,
6146 text);
6148 text = secfile_lookup_str_default(file,
6149 /* TRANS: Enter _Marketplace (100% chance of success). */
6150 N_("Enter %sMarketplace%s"),
6151 "actions.ui_name_enter_marketplace");
6152 sz_strlcpy(action_by_number(ACTION_MARKETPLACE)->ui_name,
6153 text);
6155 text = secfile_lookup_str_default(file,
6156 /* TRANS: Help _build Wonder (100% chance of success). */
6157 N_("Help %sbuild Wonder%s"),
6158 "actions.ui_name_help_wonder");
6159 sz_strlcpy(action_by_number(ACTION_HELP_WONDER)->ui_name,
6160 text);
6162 text = secfile_lookup_str_default(file,
6163 /* TRANS: _Capture Units (100% chance of success). */
6164 N_("%sCapture Units%s"),
6165 "actions.ui_name_capture_units");
6166 sz_strlcpy(action_by_number(ACTION_CAPTURE_UNITS)->ui_name,
6167 text);
6169 text = secfile_lookup_str_default(file,
6170 /* TRANS: _Expel Unit (100% chance of success). */
6171 N_("%sExpel Unit%s"),
6172 "actions.ui_name_expel_unit");
6173 sz_strlcpy(action_by_number(ACTION_EXPEL_UNIT)->ui_name,
6174 text);
6176 text = secfile_lookup_str_default(file,
6177 /* TRANS: _Found City (100% chance of success). */
6178 N_("%sFound City%s"),
6179 "actions.ui_name_found_city");
6180 sz_strlcpy(action_by_number(ACTION_FOUND_CITY)->ui_name,
6181 text);
6183 text = secfile_lookup_str_default(file,
6184 /* TRANS: _Join City (100% chance of success). */
6185 N_("%sJoin City%s"),
6186 "actions.ui_name_join_city");
6187 sz_strlcpy(action_by_number(ACTION_JOIN_CITY)->ui_name,
6188 text);
6190 text = secfile_lookup_str_default(file,
6191 /* TRANS: B_ombard (100% chance of success). */
6192 N_("B%sombard%s"),
6193 "actions.ui_name_bombard");
6194 sz_strlcpy(action_by_number(ACTION_BOMBARD)->ui_name,
6195 text);
6197 text = secfile_lookup_str_default(file,
6198 /* TRANS: Suitcase _Nuke (100% chance of success). */
6199 N_("Suitcase %sNuke%s"),
6200 "actions.ui_name_suitcase_nuke");
6201 sz_strlcpy(action_by_number(ACTION_SPY_NUKE)->ui_name,
6202 text);
6204 text = secfile_lookup_str_default(file,
6205 /* TRANS: Suitcase _Nuke and Escape (100% chance of success). */
6206 N_("Suitcase %sNuke and Escape%s"),
6207 "actions.ui_name_suitcase_nuke_escape");
6208 sz_strlcpy(action_by_number(ACTION_SPY_NUKE_ESC)->ui_name,
6209 text);
6211 text = secfile_lookup_str_default(file,
6212 /* TRANS: Explode _Nuclear (100% chance of success). */
6213 N_("Explode %sNuclear%s"),
6214 "actions.ui_name_explode_nuclear");
6215 sz_strlcpy(action_by_number(ACTION_NUKE)->ui_name,
6216 text);
6218 text = secfile_lookup_str_default(file,
6219 /* TRANS: Destroy _City (100% chance of success). */
6220 N_("Destroy %sCity%s"),
6221 "actions.ui_name_destroy_city");
6222 sz_strlcpy(action_by_number(ACTION_DESTROY_CITY)->ui_name,
6223 text);
6225 text = secfile_lookup_str_default(file,
6226 /* TRANS: Rec_ycle Unit (100% chance of success). */
6227 N_("Rec%sycle Unit%s"),
6228 "actions.ui_name_recycle_unit");
6229 sz_strlcpy(action_by_number(ACTION_RECYCLE_UNIT)->ui_name,
6230 text);
6232 text = secfile_lookup_str_default(file,
6233 /* TRANS: _You're Fired (100% chance of success). */
6234 N_("%sYou're Fired%s"),
6235 "actions.ui_name_disband_unit");
6236 sz_strlcpy(action_by_number(ACTION_DISBAND_UNIT)->ui_name,
6237 text);
6239 text = secfile_lookup_str_default(file,
6240 /* TRANS: Set _Home City (100% chance of success). */
6241 N_("Set %sHome City%s"),
6242 "actions.ui_name_home_city");
6243 sz_strlcpy(action_by_number(ACTION_HOME_CITY)->ui_name,
6244 text);
6246 text = secfile_lookup_str_default(file,
6247 /* TRANS: _Upgrade Unit (100% chance of success). */
6248 N_("%sUpgrade Unit%s"),
6249 "actions.ui_upgrade_unit");
6250 sz_strlcpy(action_by_number(ACTION_UPGRADE_UNIT)->ui_name,
6251 text);
6253 text = secfile_lookup_str_default(file,
6254 /* TRANS: Drop _Paratrooper (100% chance of success). */
6255 N_("Drop %sParatrooper%s"),
6256 "actions.ui_paradrop_unit");
6257 sz_strlcpy(action_by_number(ACTION_PARADROP)->ui_name,
6258 text);
6260 text = secfile_lookup_str_default(file,
6261 /* TRANS: _Airlift to City (100% chance of success). */
6262 N_("%sAirlift to City%s"),
6263 "actions.ui_airlift_unit");
6264 sz_strlcpy(action_by_number(ACTION_AIRLIFT)->ui_name,
6265 text);
6267 text = secfile_lookup_str_default(file,
6268 /* TRANS: _Attack (100% chance of success). */
6269 N_("%sAttack%s"),
6270 "actions.ui_name_attack");
6271 sz_strlcpy(action_by_number(ACTION_ATTACK)->ui_name,
6272 text);
6274 text = secfile_lookup_str_default(file,
6275 /* TRANS: _Conquer City (100% chance of success). */
6276 N_("%sConquer City%s"),
6277 "actions.ui_name_conquer_city");
6278 sz_strlcpy(action_by_number(ACTION_CONQUER_CITY)->ui_name,
6279 text);
6281 text = secfile_lookup_str_default(file,
6282 /* TRANS: Heal _Unit (3% chance of success). */
6283 N_("Heal %sUnit%s"),
6284 "actions.ui_name_heal_unit");
6285 sz_strlcpy(action_by_number(ACTION_HEAL_UNIT)->ui_name,
6286 text);
6288 /* The quiet (don't auto generate help for) property of all actions
6289 * live in a single enum vector. This avoids generic action
6290 * expectations. */
6291 if (secfile_entry_by_path(file, "actions.quiet_actions")) {
6292 enum gen_action *quiet_actions;
6293 size_t asize;
6294 int j;
6296 quiet_actions =
6297 secfile_lookup_enum_vec(file, &asize, gen_action,
6298 "actions.quiet_actions");
6300 if (!quiet_actions) {
6301 /* Entity exists but couldn't read it. */
6302 ruleset_error(LOG_ERROR,
6303 "\"%s\": actions.quiet_actions: bad action list",
6304 filename);
6306 ok = FALSE;
6309 for (j = 0; j < asize; j++) {
6310 /* Don't auto generate help text for this action. */
6311 action_by_number(quiet_actions[j])->quiet = TRUE;
6314 free(quiet_actions);
6318 if (ok) {
6319 sec = secfile_sections_by_name_prefix(file,
6320 ACTION_ENABLER_SECTION_PREFIX);
6322 if (sec) {
6323 section_list_iterate(sec, psection) {
6324 struct action_enabler *enabler;
6325 const char *sec_name = section_name(psection);
6326 struct action *paction;
6327 struct requirement_vector *actor_reqs;
6328 struct requirement_vector *target_reqs;
6329 const char *action_text;
6331 enabler = action_enabler_new();
6333 action_text = secfile_lookup_str(file, "%s.action", sec_name);
6335 if (action_text == NULL) {
6336 ruleset_error(LOG_ERROR, "\"%s\" [%s] missing action to enable.",
6337 filename, sec_name);
6338 ok = FALSE;
6339 break;
6342 paction = action_by_rule_name(action_text);
6343 if (!paction) {
6344 ruleset_error(LOG_ERROR, "\"%s\" [%s] lists unknown action type \"%s\".",
6345 filename, sec_name, action_text);
6346 ok = FALSE;
6347 break;
6350 enabler->action = paction->id;
6352 actor_reqs = lookup_req_list(file, compat, sec_name, "actor_reqs", action_text);
6353 if (actor_reqs == NULL) {
6354 ok = FALSE;
6355 break;
6358 requirement_vector_copy(&enabler->actor_reqs, actor_reqs);
6360 target_reqs = lookup_req_list(file, compat, sec_name, "target_reqs", action_text);
6361 if (target_reqs == NULL) {
6362 ok = FALSE;
6363 break;
6366 requirement_vector_copy(&enabler->target_reqs, target_reqs);
6368 action_enabler_add(enabler);
6369 } section_list_iterate_end;
6370 section_list_destroy(sec);
6375 if (ok) {
6376 const char *tus_text;
6378 /* section: combat_rules */
6379 game.info.tired_attack
6380 = secfile_lookup_bool_default(file, RS_DEFAULT_TIRED_ATTACK,
6381 "combat_rules.tired_attack");
6383 /* section: borders */
6384 game.info.border_city_radius_sq
6385 = secfile_lookup_int_default_min_max(file,
6386 RS_DEFAULT_BORDER_RADIUS_SQ_CITY,
6387 RS_MIN_BORDER_RADIUS_SQ_CITY,
6388 RS_MAX_BORDER_RADIUS_SQ_CITY,
6389 "borders.radius_sq_city");
6390 game.info.border_size_effect
6391 = secfile_lookup_int_default_min_max(file,
6392 RS_DEFAULT_BORDER_SIZE_EFFECT,
6393 RS_MIN_BORDER_SIZE_EFFECT,
6394 RS_MAX_BORDER_SIZE_EFFECT,
6395 "borders.size_effect");
6397 game.info.border_city_permanent_radius_sq
6398 = secfile_lookup_int_default_min_max(file,
6399 RS_DEFAULT_BORDER_RADIUS_SQ_CITY_PERMANENT,
6400 RS_MIN_BORDER_RADIUS_SQ_CITY_PERMANENT,
6401 RS_MAX_BORDER_RADIUS_SQ_CITY_PERMANENT,
6402 "borders.radius_sq_city_permanent");
6404 /* section: research */
6405 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_COST_STYLE,
6406 "research.tech_cost_style");
6407 game.info.tech_cost_style = tech_cost_style_by_name(tus_text,
6408 fc_strcasecmp);
6409 if (!tech_cost_style_is_valid(game.info.tech_cost_style)) {
6410 ruleset_error(LOG_ERROR, "Unknown tech cost style \"%s\"",
6411 tus_text);
6412 ok = FALSE;
6415 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_LEAKAGE,
6416 "research.tech_leakage");
6417 game.info.tech_leakage = tech_leakage_style_by_name(tus_text,
6418 fc_strcasecmp);
6419 if (!tech_leakage_style_is_valid(game.info.tech_leakage)) {
6420 ruleset_error(LOG_ERROR, "Unknown tech leakage \"%s\"",
6421 tus_text);
6422 ok = FALSE;
6424 if (game.info.tech_cost_style == TECH_COST_CIV1CIV2
6425 && game.info.tech_leakage != TECH_LEAKAGE_NONE) {
6426 log_error("Only tech_leakage \"%s\" supported with "
6427 "tech_cost_style \"%s\". ",
6428 tech_leakage_style_name(TECH_LEAKAGE_NONE),
6429 tech_cost_style_name(TECH_COST_CIV1CIV2));
6430 log_error("Switching to tech_leakage \"%s\".",
6431 tech_leakage_style_name(TECH_LEAKAGE_NONE));
6432 game.info.tech_leakage = TECH_LEAKAGE_NONE;
6434 game.info.base_tech_cost
6435 = secfile_lookup_int_default_min_max(file,
6436 RS_DEFAULT_BASE_TECH_COST,
6437 RS_MIN_BASE_TECH_COST,
6438 RS_MAX_BASE_TECH_COST,
6439 "research.base_tech_cost");
6441 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_UPKEEP_STYLE,
6442 "research.tech_upkeep_style");
6444 game.info.tech_upkeep_style = tech_upkeep_style_by_name(tus_text, fc_strcasecmp);
6446 if (!tech_upkeep_style_is_valid(game.info.tech_upkeep_style)) {
6447 ruleset_error(LOG_ERROR, "Unknown tech upkeep style \"%s\"",
6448 tus_text);
6449 ok = FALSE;
6453 if (ok) {
6454 game.info.tech_upkeep_divider
6455 = secfile_lookup_int_default_min_max(file,
6456 RS_DEFAULT_TECH_UPKEEP_DIVIDER,
6457 RS_MIN_TECH_UPKEEP_DIVIDER,
6458 RS_MAX_TECH_UPKEEP_DIVIDER,
6459 "research.tech_upkeep_divider");
6461 sval = secfile_lookup_str_default(file, NULL, "research.free_tech_method");
6462 if (sval == NULL) {
6463 ruleset_error(LOG_ERROR, "No free_tech_method given");
6464 ok = FALSE;
6465 } else {
6466 game.info.free_tech_method = free_tech_method_by_name(sval, fc_strcasecmp);
6467 if (!free_tech_method_is_valid(game.info.free_tech_method)) {
6468 ruleset_error(LOG_ERROR, "Bad value %s for free_tech_method.", sval);
6469 ok = FALSE;
6474 if (ok) {
6475 int cf;
6477 /* section: culture */
6478 game.info.culture_vic_points
6479 = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_VIC_POINTS,
6480 "culture.victory_min_points");
6481 game.info.culture_vic_lead
6482 = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_VIC_LEAD,
6483 "culture.victory_lead_pct");
6484 game.info.culture_migration_pml
6485 = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_MIGRATION_PML,
6486 "culture.migration_pml");
6488 /* section: calendar */
6489 game.calendar.calendar_skip_0
6490 = secfile_lookup_bool_default(file, RS_DEFAULT_CALENDAR_SKIP_0,
6491 "calendar.skip_year_0");
6492 game.server.start_year
6493 = secfile_lookup_int_default(file, GAME_START_YEAR,
6494 "calendar.start_year");
6495 game.calendar.calendar_fragments
6496 = secfile_lookup_int_default(file, 0, "calendar.fragments");
6498 if (game.calendar.calendar_fragments > MAX_CALENDAR_FRAGMENTS) {
6499 ruleset_error(LOG_ERROR, "Too many calendar fragments. Max is %d",
6500 MAX_CALENDAR_FRAGMENTS);
6501 ok = FALSE;
6502 game.calendar.calendar_fragments = 0;
6504 sz_strlcpy(game.calendar.positive_year_label,
6505 secfile_lookup_str_default(file,
6506 RS_DEFAULT_POS_YEAR_LABEL,
6507 "calendar.positive_label"));
6508 sz_strlcpy(game.calendar.negative_year_label,
6509 secfile_lookup_str_default(file,
6510 RS_DEFAULT_NEG_YEAR_LABEL,
6511 "calendar.negative_label"));
6513 for (cf = 0; cf < game.calendar.calendar_fragments; cf++) {
6514 const char *fname;
6516 fname = secfile_lookup_str_default(file, NULL, "calendar.fragment_name%d", cf);
6517 if (fname != NULL) {
6518 strncpy(game.calendar.calendar_fragment_name[cf], fname,
6519 sizeof(game.calendar.calendar_fragment_name[cf]));
6524 if (ok) {
6525 /* section playercolors */
6526 struct rgbcolor *prgbcolor = NULL;
6527 bool color_read = TRUE;
6529 /* Check if the player list is defined and empty. */
6530 if (playercolor_count() != 0) {
6531 ok = FALSE;
6532 } else {
6533 i = 0;
6535 while (color_read) {
6536 prgbcolor = NULL;
6538 color_read = rgbcolor_load(file, &prgbcolor, "playercolors.colorlist%d", i);
6539 if (color_read) {
6540 playercolor_add(prgbcolor);
6543 i++;
6546 if (playercolor_count() == 0) {
6547 ruleset_error(LOG_ERROR, "No player colors defined!");
6548 ok = FALSE;
6551 if (ok) {
6552 fc_assert(game.plr_bg_color == NULL);
6553 if (!rgbcolor_load(file, &game.plr_bg_color, "playercolors.background")) {
6554 ruleset_error(LOG_ERROR, "No background player color defined! (%s)",
6555 secfile_error());
6556 ok = FALSE;
6562 if (ok) {
6563 /* section: teams */
6564 svec = secfile_lookup_str_vec(file, &teams, "teams.names");
6565 if (team_slot_count() < teams) {
6566 teams = team_slot_count();
6568 game.server.ruledit.named_teams = teams;
6569 for (i = 0; i < teams; i++) {
6570 team_slot_set_defined_name(team_slot_by_number(i), svec[i]);
6572 free(svec);
6574 sec = secfile_sections_by_name_prefix(file, DISASTER_SECTION_PREFIX);
6575 nval = (NULL != sec ? section_list_size(sec) : 0);
6576 if (nval > MAX_DISASTER_TYPES) {
6577 int num = nval; /* No "size_t" to printf */
6579 ruleset_error(LOG_ERROR, "\"%s\": Too many disaster types (%d, max %d)",
6580 filename, num, MAX_DISASTER_TYPES);
6581 section_list_destroy(sec);
6582 ok = FALSE;
6583 } else {
6584 game.control.num_disaster_types = nval;
6588 if (ok) {
6589 disaster_type_iterate(pdis) {
6590 int id = disaster_index(pdis);
6591 int j;
6592 size_t eff_count;
6593 struct requirement_vector *reqs;
6594 const char *sec_name = section_name(section_list_get(sec, id));
6596 if (!ruleset_load_names(&pdis->name, NULL, file, sec_name)) {
6597 ruleset_error(LOG_ERROR, "\"%s\": Cannot load disaster names",
6598 filename);
6599 ok = FALSE;
6600 break;
6603 reqs = lookup_req_list(file, compat, sec_name, "reqs", disaster_rule_name(pdis));
6604 if (reqs == NULL) {
6605 ok = FALSE;
6606 break;
6608 requirement_vector_copy(&pdis->reqs, reqs);
6610 pdis->frequency = secfile_lookup_int_default(file, GAME_DEFAULT_DISASTER_FREQ,
6611 "%s.frequency", sec_name);
6613 svec = secfile_lookup_str_vec(file, &eff_count, "%s.effects", sec_name);
6615 BV_CLR_ALL(pdis->effects);
6616 for (j = 0; j < eff_count; j++) {
6617 const char *dsval = svec[j];
6618 enum disaster_effect_id effect;
6620 effect = disaster_effect_id_by_name(dsval, fc_strcasecmp);
6622 if (!disaster_effect_id_is_valid(effect)) {
6623 ruleset_error(LOG_ERROR,
6624 "\"%s\" disaster \"%s\": unknown effect \"%s\".",
6625 filename,
6626 disaster_rule_name(pdis),
6627 dsval);
6628 ok = FALSE;
6629 break;
6630 } else {
6631 BV_SET(pdis->effects, effect);
6635 free(svec);
6637 if (!ok) {
6638 break;
6640 } disaster_type_iterate_end;
6641 section_list_destroy(sec);
6644 if (ok) {
6645 sec = secfile_sections_by_name_prefix(file, ACHIEVEMENT_SECTION_PREFIX);
6647 achievements_iterate(pach) {
6648 int id = achievement_index(pach);
6649 const char *sec_name = section_name(section_list_get(sec, id));
6650 const char *typename;
6651 const char *msg;
6653 typename = secfile_lookup_str_default(file, NULL, "%s.type", sec_name);
6655 pach->type = achievement_type_by_name(typename, fc_strcasecmp);
6656 if (!achievement_type_is_valid(pach->type)) {
6657 ruleset_error(LOG_ERROR, "Achievement has unknown type \"%s\".",
6658 typename != NULL ? typename : "(NULL)");
6659 ok = FALSE;
6662 if (ok) {
6663 pach->unique = secfile_lookup_bool_default(file, GAME_DEFAULT_ACH_UNIQUE,
6664 "%s.unique", sec_name);
6666 pach->value = secfile_lookup_int_default(file, GAME_DEFAULT_ACH_VALUE,
6667 "%s.value", sec_name);
6668 pach->culture = secfile_lookup_int_default(file, 0,
6669 "%s.culture", sec_name);
6671 msg = secfile_lookup_str_default(file, NULL, "%s.first_msg", sec_name);
6672 if (msg == NULL) {
6673 ruleset_error(LOG_ERROR, "Achievement %s has no first msg!", sec_name);
6674 ok = FALSE;
6675 } else {
6676 pach->first_msg = fc_strdup(msg);
6680 if (ok) {
6681 msg = secfile_lookup_str_default(file, NULL, "%s.cons_msg", sec_name);
6682 if (msg == NULL) {
6683 if (!pach->unique) {
6684 ruleset_error(LOG_ERROR, "Achievement %s has no msg for consecutive gainers!", sec_name);
6685 ok = FALSE;
6687 } else {
6688 pach->cons_msg = fc_strdup(msg);
6692 if (!ok) {
6693 break;
6695 } achievements_iterate_end;
6696 section_list_destroy(sec);
6699 if (ok) {
6700 for (i = 0; (name = secfile_lookup_str_default(file, NULL,
6701 "trade.settings%d.type",
6702 i)); i++) {
6703 enum trade_route_type type = trade_route_type_by_name(name);
6705 if (type == TRT_LAST) {
6706 ruleset_error(LOG_ERROR,
6707 "\"%s\" unknown trade route type \"%s\".",
6708 filename, name);
6709 ok = FALSE;
6710 } else {
6711 struct trade_route_settings *set = trade_route_settings_by_type(type);
6712 const char *cancelling;
6713 const char *bonus;
6715 set->trade_pct = secfile_lookup_int_default(file, 100,
6716 "trade.settings%d.pct", i);
6717 cancelling = secfile_lookup_str_default(file, "Active",
6718 "trade.settings%d.cancelling", i);
6719 set->cancelling = traderoute_cancelling_type_by_name(cancelling);
6720 if (set->cancelling == TRI_LAST) {
6721 ruleset_error(LOG_ERROR,
6722 "\"%s\" unknown traderoute cancelling type \"%s\".",
6723 filename, cancelling);
6724 ok = FALSE;
6727 bonus = secfile_lookup_str_default(file, "None", "trade.settings%d.bonus", i);
6729 set->bonus_type = traderoute_bonus_type_by_name(bonus, fc_strcasecmp);
6731 if (!traderoute_bonus_type_is_valid(set->bonus_type)) {
6732 ruleset_error(LOG_ERROR,
6733 "\"%s\" unknown traderoute bonus type \"%s\".",
6734 filename, bonus);
6735 ok = FALSE;
6741 if (ok) {
6742 const char *str = secfile_lookup_str_default(file, "Leaving", "trade.goods_selection");
6744 game.info.goods_selection = goods_selection_method_by_name(str, fc_strcasecmp);
6746 if (!goods_selection_method_is_valid(game.info.goods_selection)) {
6747 ruleset_error(LOG_ERROR,
6748 "\"%s\" goods selection method \"%s\" unknown.",
6749 filename, str);
6750 ok = FALSE;
6754 if (ok) {
6755 sec = secfile_sections_by_name_prefix(file, GOODS_SECTION_PREFIX);
6757 goods_type_iterate(pgood) {
6758 int id = goods_index(pgood);
6759 const char *sec_name = section_name(section_list_get(sec, id));
6760 struct requirement_vector *reqs;
6761 const char **slist;
6762 int j;
6764 reqs = lookup_req_list(file, compat, sec_name, "reqs", goods_rule_name(pgood));
6765 if (reqs == NULL) {
6766 ok = FALSE;
6767 break;
6769 requirement_vector_copy(&pgood->reqs, reqs);
6771 pgood->from_pct = secfile_lookup_int_default(file, 100,
6772 "%s.from_pct", sec_name);
6773 pgood->to_pct = secfile_lookup_int_default(file, 100,
6774 "%s.to_pct", sec_name);
6776 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
6777 BV_CLR_ALL(pgood->flags);
6778 for (j = 0; j < nval; j++) {
6779 enum goods_flag_id flag;
6781 sval = slist[j];
6782 flag = goods_flag_id_by_name(sval, fc_strcasecmp);
6783 if (!goods_flag_id_is_valid(flag)) {
6784 ruleset_error(LOG_ERROR, "\"%s\" good \"%s\": unknown flag \"%s\".",
6785 filename,
6786 goods_rule_name(pgood),
6787 sval);
6788 ok = FALSE;
6789 break;
6790 } else {
6791 BV_SET(pgood->flags, flag);
6794 free(slist);
6796 pgood->helptext = lookup_strvec(file, sec_name, "helptext");
6797 } goods_type_iterate_end;
6798 section_list_destroy(sec);
6801 /* secfile_check_unused() is not here, but only after also settings section
6802 * has been loaded. */
6804 return ok;
6807 /**************************************************************************
6808 Send the units ruleset information (all individual unit classes) to the
6809 specified connections.
6810 **************************************************************************/
6811 static void send_ruleset_unit_classes(struct conn_list *dest)
6813 struct packet_ruleset_unit_class packet;
6814 struct packet_ruleset_unit_class_flag fpacket;
6815 int i;
6817 for (i = 0; i < MAX_NUM_USER_UCLASS_FLAGS; i++) {
6818 const char *flagname;
6819 const char *helptxt;
6821 fpacket.id = i + UCF_USER_FLAG_1;
6823 flagname = unit_class_flag_id_name(i + UCF_USER_FLAG_1);
6824 if (flagname == NULL) {
6825 fpacket.name[0] = '\0';
6826 } else {
6827 sz_strlcpy(fpacket.name, flagname);
6830 helptxt = unit_class_flag_helptxt(i + UCF_USER_FLAG_1);
6831 if (helptxt == NULL) {
6832 fpacket.helptxt[0] = '\0';
6833 } else {
6834 sz_strlcpy(fpacket.helptxt, helptxt);
6837 lsend_packet_ruleset_unit_class_flag(dest, &fpacket);
6840 unit_class_iterate(c) {
6841 packet.id = uclass_number(c);
6842 sz_strlcpy(packet.name, untranslated_name(&c->name));
6843 sz_strlcpy(packet.rule_name, rule_name_get(&c->name));
6844 packet.min_speed = c->min_speed;
6845 packet.hp_loss_pct = c->hp_loss_pct;
6846 packet.hut_behavior = c->hut_behavior;
6847 packet.non_native_def_pct = c->non_native_def_pct;
6848 packet.flags = c->flags;
6850 PACKET_STRVEC_COMPUTE(packet.helptext, c->helptext);
6852 lsend_packet_ruleset_unit_class(dest, &packet);
6853 } unit_class_iterate_end;
6856 /**************************************************************************
6857 Send the units ruleset information (all individual units) to the
6858 specified connections.
6859 **************************************************************************/
6860 static void send_ruleset_units(struct conn_list *dest)
6862 struct packet_ruleset_unit packet;
6863 struct packet_ruleset_unit_flag fpacket;
6864 int i;
6866 for (i = 0; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
6867 const char *flagname;
6868 const char *helptxt;
6870 fpacket.id = i + UTYF_USER_FLAG_1;
6872 flagname = unit_type_flag_id_name(i + UTYF_USER_FLAG_1);
6873 if (flagname == NULL) {
6874 fpacket.name[0] = '\0';
6875 } else {
6876 sz_strlcpy(fpacket.name, flagname);
6879 helptxt = unit_type_flag_helptxt(i + UTYF_USER_FLAG_1);
6880 if (helptxt == NULL) {
6881 fpacket.helptxt[0] = '\0';
6882 } else {
6883 sz_strlcpy(fpacket.helptxt, helptxt);
6886 lsend_packet_ruleset_unit_flag(dest, &fpacket);
6889 unit_type_iterate(u) {
6890 packet.id = utype_number(u);
6891 sz_strlcpy(packet.name, untranslated_name(&u->name));
6892 sz_strlcpy(packet.rule_name, rule_name_get(&u->name));
6893 sz_strlcpy(packet.sound_move, u->sound_move);
6894 sz_strlcpy(packet.sound_move_alt, u->sound_move_alt);
6895 sz_strlcpy(packet.sound_fight, u->sound_fight);
6896 sz_strlcpy(packet.sound_fight_alt, u->sound_fight_alt);
6897 sz_strlcpy(packet.graphic_str, u->graphic_str);
6898 sz_strlcpy(packet.graphic_alt, u->graphic_alt);
6899 packet.unit_class_id = uclass_number(utype_class(u));
6900 packet.build_cost = u->build_cost;
6901 packet.pop_cost = u->pop_cost;
6902 packet.attack_strength = u->attack_strength;
6903 packet.defense_strength = u->defense_strength;
6904 packet.move_rate = u->move_rate;
6905 packet.tech_requirement = u->require_advance
6906 ? advance_number(u->require_advance)
6907 : advance_count();
6908 packet.impr_requirement = u->need_improvement
6909 ? improvement_number(u->need_improvement)
6910 : improvement_count();
6911 packet.gov_requirement = u->need_government
6912 ? government_number(u->need_government)
6913 : government_count();
6914 packet.vision_radius_sq = u->vision_radius_sq;
6915 packet.transport_capacity = u->transport_capacity;
6916 packet.hp = u->hp;
6917 packet.firepower = u->firepower;
6918 packet.obsoleted_by = u->obsoleted_by
6919 ? utype_number(u->obsoleted_by)
6920 : utype_count();
6921 packet.converted_to = u->converted_to
6922 ? utype_number(u->converted_to)
6923 : utype_count();
6924 packet.convert_time = u->convert_time;
6925 packet.fuel = u->fuel;
6926 packet.flags = u->flags;
6927 packet.roles = u->roles;
6928 packet.happy_cost = u->happy_cost;
6929 output_type_iterate(o) {
6930 packet.upkeep[o] = u->upkeep[o];
6931 } output_type_iterate_end;
6932 packet.paratroopers_range = u->paratroopers_range;
6933 packet.paratroopers_mr_req = u->paratroopers_mr_req;
6934 packet.paratroopers_mr_sub = u->paratroopers_mr_sub;
6935 packet.bombard_rate = u->bombard_rate;
6936 packet.city_size = u->city_size;
6937 packet.city_slots = u->city_slots;
6938 packet.cargo = u->cargo;
6939 packet.targets = u->targets;
6940 packet.embarks = u->embarks;
6941 packet.disembarks = u->disembarks;
6943 if (u->veteran == NULL) {
6944 /* Use the default veteran system. */
6945 packet.veteran_levels = 0;
6946 } else {
6947 /* Per unit veteran system definition. */
6948 packet.veteran_levels = utype_veteran_levels(u);
6950 for (i = 0; i < packet.veteran_levels; i++) {
6951 const struct veteran_level *vlevel = utype_veteran_level(u, i);
6953 sz_strlcpy(packet.veteran_name[i], untranslated_name(&vlevel->name));
6954 packet.power_fact[i] = vlevel->power_fact;
6955 packet.move_bonus[i] = vlevel->move_bonus;
6958 PACKET_STRVEC_COMPUTE(packet.helptext, u->helptext);
6960 lsend_packet_ruleset_unit(dest, &packet);
6962 combat_bonus_list_iterate(u->bonuses, pbonus) {
6963 struct packet_ruleset_unit_bonus bonuspacket;
6965 bonuspacket.unit = packet.id;
6966 bonuspacket.flag = pbonus->flag;
6967 bonuspacket.type = pbonus->type;
6968 bonuspacket.value = pbonus->value;
6969 bonuspacket.quiet = pbonus->quiet;
6971 lsend_packet_ruleset_unit_bonus(dest, &bonuspacket);
6972 } combat_bonus_list_iterate_end;
6973 } unit_type_iterate_end;
6976 /**************************************************************************
6977 Send the specialists ruleset information (all individual specialist
6978 types) to the specified connections.
6979 **************************************************************************/
6980 static void send_ruleset_specialists(struct conn_list *dest)
6982 struct packet_ruleset_specialist packet;
6984 specialist_type_iterate(spec_id) {
6985 struct specialist *s = specialist_by_number(spec_id);
6986 int j;
6988 packet.id = spec_id;
6989 sz_strlcpy(packet.plural_name, untranslated_name(&s->name));
6990 sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
6991 sz_strlcpy(packet.short_name, untranslated_name(&s->abbreviation));
6992 sz_strlcpy(packet.graphic_alt, s->graphic_alt);
6993 j = 0;
6994 requirement_vector_iterate(&s->reqs, preq) {
6995 packet.reqs[j++] = *preq;
6996 } requirement_vector_iterate_end;
6997 packet.reqs_count = j;
6999 PACKET_STRVEC_COMPUTE(packet.helptext, s->helptext);
7001 lsend_packet_ruleset_specialist(dest, &packet);
7002 } specialist_type_iterate_end;
7004 /**************************************************************************
7005 Send the techs class information to the specified connections.
7006 **************************************************************************/
7007 static void send_ruleset_tech_classes(struct conn_list *dest)
7009 struct packet_ruleset_tech_class packet;
7011 tech_class_iterate(ptclass) {
7012 packet.id = ptclass->idx;
7013 sz_strlcpy(packet.name, untranslated_name(&ptclass->name));
7014 sz_strlcpy(packet.rule_name, rule_name_get(&ptclass->name));
7015 packet.cost_pct = ptclass->cost_pct;
7017 lsend_packet_ruleset_tech_class(dest, &packet);
7018 } tech_class_iterate_end;
7021 /**************************************************************************
7022 Send the techs ruleset information (all individual advances) to the
7023 specified connections.
7024 **************************************************************************/
7025 static void send_ruleset_techs(struct conn_list *dest)
7027 struct packet_ruleset_tech packet;
7028 struct packet_ruleset_tech_flag fpacket;
7029 int i;
7031 for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
7032 const char *flagname;
7033 const char *helptxt;
7035 fpacket.id = i + TECH_USER_1;
7037 flagname = tech_flag_id_name_cb(i + TECH_USER_1);
7038 if (flagname == NULL) {
7039 fpacket.name[0] = '\0';
7040 } else {
7041 sz_strlcpy(fpacket.name, flagname);
7044 helptxt = tech_flag_helptxt(i + TECH_USER_1);
7045 if (helptxt == NULL) {
7046 fpacket.helptxt[0] = '\0';
7047 } else {
7048 sz_strlcpy(fpacket.helptxt, helptxt);
7051 lsend_packet_ruleset_tech_flag(dest, &fpacket);
7054 advance_iterate(A_FIRST, a) {
7055 packet.id = advance_number(a);
7056 packet.removed = !valid_advance(a);
7057 if (a->tclass == NULL) {
7058 packet.tclass = 0;
7059 } else {
7060 packet.tclass = a->tclass->idx;
7062 sz_strlcpy(packet.name, untranslated_name(&a->name));
7063 sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
7064 sz_strlcpy(packet.graphic_str, a->graphic_str);
7065 sz_strlcpy(packet.graphic_alt, a->graphic_alt);
7067 /* Current size of the packet's research_reqs requirement vector. */
7068 i = 0;
7070 /* The requirements req1 and req2 are needed to research a tech. Send
7071 * them in the research_reqs requirement vector. Range is set to player
7072 * since pooled research is configurable. */
7074 if ((a->require[AR_ONE] != A_NEVER)
7075 && advance_number(a->require[AR_ONE]) > A_NONE) {
7076 packet.research_reqs[i++]
7077 = req_from_values(VUT_ADVANCE, REQ_RANGE_PLAYER,
7078 FALSE, TRUE, FALSE,
7079 advance_number(a->require[AR_ONE]));
7082 if ((a->require[AR_TWO] != A_NEVER)
7083 && advance_number(a->require[AR_TWO]) > A_NONE) {
7084 packet.research_reqs[i++]
7085 = req_from_values(VUT_ADVANCE, REQ_RANGE_PLAYER,
7086 FALSE, TRUE, FALSE,
7087 advance_number(a->require[AR_TWO]));;
7090 /* The requirements of the tech's research_reqs also goes in the
7091 * packet's research_reqs requirement vector. */
7092 requirement_vector_iterate(&a->research_reqs, req) {
7093 packet.research_reqs[i++] = *req;
7094 } requirement_vector_iterate_end;
7096 /* The packet's research_reqs should contain req1, req2 and the
7097 * requirements of the tech's research_reqs. */
7098 packet.research_reqs_count = i;
7100 packet.root_req = a->require[AR_ROOT]
7101 ? advance_number(a->require[AR_ROOT])
7102 : advance_count();
7104 packet.flags = a->flags;
7105 packet.cost = a->cost;
7106 packet.num_reqs = a->num_reqs;
7107 PACKET_STRVEC_COMPUTE(packet.helptext, a->helptext);
7109 lsend_packet_ruleset_tech(dest, &packet);
7110 } advance_iterate_end;
7113 /**************************************************************************
7114 Send the buildings ruleset information (all individual improvements and
7115 wonders) to the specified connections.
7116 **************************************************************************/
7117 static void send_ruleset_buildings(struct conn_list *dest)
7119 improvement_iterate(b) {
7120 struct packet_ruleset_building packet;
7121 int j;
7123 packet.id = improvement_number(b);
7124 packet.genus = b->genus;
7125 sz_strlcpy(packet.name, untranslated_name(&b->name));
7126 sz_strlcpy(packet.rule_name, rule_name_get(&b->name));
7127 sz_strlcpy(packet.graphic_str, b->graphic_str);
7128 sz_strlcpy(packet.graphic_alt, b->graphic_alt);
7129 j = 0;
7130 requirement_vector_iterate(&b->reqs, preq) {
7131 packet.reqs[j++] = *preq;
7132 } requirement_vector_iterate_end;
7133 packet.reqs_count = j;
7134 j = 0;
7135 requirement_vector_iterate(&b->obsolete_by, pobs) {
7136 packet.obs_reqs[j++] = *pobs;
7137 } requirement_vector_iterate_end;
7138 packet.obs_count = j;
7139 packet.build_cost = b->build_cost;
7140 packet.upkeep = b->upkeep;
7141 packet.sabotage = b->sabotage;
7142 packet.flags = b->flags;
7143 sz_strlcpy(packet.soundtag, b->soundtag);
7144 sz_strlcpy(packet.soundtag_alt, b->soundtag_alt);
7145 PACKET_STRVEC_COMPUTE(packet.helptext, b->helptext);
7147 lsend_packet_ruleset_building(dest, &packet);
7148 } improvement_iterate_end;
7151 /**************************************************************************
7152 Send the terrain ruleset information (terrain_control, and the individual
7153 terrain types) to the specified connections.
7154 **************************************************************************/
7155 static void send_ruleset_terrain(struct conn_list *dest)
7157 struct packet_ruleset_terrain packet;
7158 struct packet_ruleset_terrain_flag fpacket;
7159 int i;
7161 lsend_packet_ruleset_terrain_control(dest, &terrain_control);
7163 for (i = 0; i < MAX_NUM_USER_TER_FLAGS; i++) {
7164 const char *flagname;
7165 const char *helptxt;
7167 fpacket.id = i + TER_USER_1;
7169 flagname = terrain_flag_id_name_cb(i + TER_USER_1);
7170 if (flagname == NULL) {
7171 fpacket.name[0] = '\0';
7172 } else {
7173 sz_strlcpy(fpacket.name, flagname);
7176 helptxt = terrain_flag_helptxt(i + TER_USER_1);
7177 if (helptxt == NULL) {
7178 fpacket.helptxt[0] = '\0';
7179 } else {
7180 sz_strlcpy(fpacket.helptxt, helptxt);
7183 lsend_packet_ruleset_terrain_flag(dest, &fpacket);
7186 terrain_type_iterate(pterrain) {
7187 struct extra_type **r;
7189 packet.id = terrain_number(pterrain);
7190 packet.tclass = pterrain->tclass;
7191 packet.native_to = pterrain->native_to;
7193 sz_strlcpy(packet.name, untranslated_name(&pterrain->name));
7194 sz_strlcpy(packet.rule_name, rule_name_get(&pterrain->name));
7195 sz_strlcpy(packet.graphic_str, pterrain->graphic_str);
7196 sz_strlcpy(packet.graphic_alt, pterrain->graphic_alt);
7198 packet.movement_cost = pterrain->movement_cost;
7199 packet.defense_bonus = pterrain->defense_bonus;
7201 output_type_iterate(o) {
7202 packet.output[o] = pterrain->output[o];
7203 } output_type_iterate_end;
7205 packet.num_resources = 0;
7206 for (r = pterrain->resources; *r; r++) {
7207 packet.resources[packet.num_resources++] = extra_number(*r);
7210 output_type_iterate(o) {
7211 packet.road_output_incr_pct[o] = pterrain->road_output_incr_pct[o];
7212 } output_type_iterate_end;
7214 packet.base_time = pterrain->base_time;
7215 packet.road_time = pterrain->road_time;
7217 packet.irrigation_result = (pterrain->irrigation_result
7218 ? terrain_number(pterrain->irrigation_result)
7219 : terrain_count());
7220 packet.irrigation_food_incr = pterrain->irrigation_food_incr;
7221 packet.irrigation_time = pterrain->irrigation_time;
7223 packet.mining_result = (pterrain->mining_result
7224 ? terrain_number(pterrain->mining_result)
7225 : terrain_count());
7226 packet.mining_shield_incr = pterrain->mining_shield_incr;
7227 packet.mining_time = pterrain->mining_time;
7229 packet.animal = (pterrain->animal == NULL ? -1 : utype_number(pterrain->animal));
7230 packet.transform_result = (pterrain->transform_result
7231 ? terrain_number(pterrain->transform_result)
7232 : terrain_count());
7233 packet.pillage_time = pterrain->pillage_time;
7234 packet.transform_time = pterrain->transform_time;
7235 packet.clean_pollution_time = pterrain->clean_pollution_time;
7236 packet.clean_fallout_time = pterrain->clean_fallout_time;
7238 packet.flags = pterrain->flags;
7240 packet.color_red = pterrain->rgb->r;
7241 packet.color_green = pterrain->rgb->g;
7242 packet.color_blue = pterrain->rgb->b;
7244 PACKET_STRVEC_COMPUTE(packet.helptext, pterrain->helptext);
7246 lsend_packet_ruleset_terrain(dest, &packet);
7247 } terrain_type_iterate_end;
7250 /****************************************************************************
7251 Send the resource ruleset information to the specified connections.
7252 ****************************************************************************/
7253 static void send_ruleset_resources(struct conn_list *dest)
7255 struct packet_ruleset_resource packet;
7257 extra_type_by_cause_iterate(EC_RESOURCE, presource) {
7258 packet.id = extra_index(presource);
7260 output_type_iterate(o) {
7261 packet.output[o] = presource->data.resource->output[o];
7262 } output_type_iterate_end;
7264 lsend_packet_ruleset_resource(dest, &packet);
7265 } extra_type_by_cause_iterate_end;
7268 /**************************************************************************
7269 Send the extra ruleset information (all individual extra types) to the
7270 specified connections.
7271 **************************************************************************/
7272 static void send_ruleset_extras(struct conn_list *dest)
7274 struct packet_ruleset_extra packet;
7275 struct packet_ruleset_extra_flag fpacket;
7276 int i;
7278 for (i = 0; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
7279 const char *flagname;
7280 const char *helptxt;
7282 fpacket.id = i + EF_USER_FLAG_1;
7284 flagname = extra_flag_id_name(i + EF_USER_FLAG_1);
7285 if (flagname == NULL) {
7286 fpacket.name[0] = '\0';
7287 } else {
7288 sz_strlcpy(fpacket.name, flagname);
7291 helptxt = extra_flag_helptxt(i + EF_USER_FLAG_1);
7292 if (helptxt == NULL) {
7293 fpacket.helptxt[0] = '\0';
7294 } else {
7295 sz_strlcpy(fpacket.helptxt, helptxt);
7298 lsend_packet_ruleset_extra_flag(dest, &fpacket);
7301 extra_type_iterate(e) {
7302 int j;
7304 packet.id = extra_number(e);
7305 sz_strlcpy(packet.name, untranslated_name(&e->name));
7306 sz_strlcpy(packet.rule_name, rule_name_get(&e->name));
7308 packet.category = e->category;
7309 packet.causes = e->causes;
7310 packet.rmcauses = e->rmcauses;
7312 sz_strlcpy(packet.activity_gfx, e->activity_gfx);
7313 sz_strlcpy(packet.act_gfx_alt, e->act_gfx_alt);
7314 sz_strlcpy(packet.act_gfx_alt2, e->act_gfx_alt2);
7315 sz_strlcpy(packet.rmact_gfx, e->rmact_gfx);
7316 sz_strlcpy(packet.rmact_gfx_alt, e->rmact_gfx_alt);
7317 sz_strlcpy(packet.graphic_str, e->graphic_str);
7318 sz_strlcpy(packet.graphic_alt, e->graphic_alt);
7320 j = 0;
7321 requirement_vector_iterate(&e->reqs, preq) {
7322 packet.reqs[j++] = *preq;
7323 } requirement_vector_iterate_end;
7324 packet.reqs_count = j;
7326 j = 0;
7327 requirement_vector_iterate(&e->rmreqs, preq) {
7328 packet.rmreqs[j++] = *preq;
7329 } requirement_vector_iterate_end;
7330 packet.rmreqs_count = j;
7332 packet.appearance_chance = e->appearance_chance;
7333 j = 0;
7334 requirement_vector_iterate(&e->appearance_reqs, preq) {
7335 packet.appearance_reqs[j++] = *preq;
7336 } requirement_vector_iterate_end;
7337 packet.appearance_reqs_count = j;
7339 packet.disappearance_chance = e->disappearance_chance;
7340 j = 0;
7341 requirement_vector_iterate(&e->disappearance_reqs, preq) {
7342 packet.disappearance_reqs[j++] = *preq;
7343 } requirement_vector_iterate_end;
7344 packet.disappearance_reqs_count = j;
7346 packet.visibility_req = e->visibility_req;
7347 packet.buildable = e->buildable;
7348 packet.build_time = e->build_time;
7349 packet.build_time_factor = e->build_time_factor;
7350 packet.removal_time = e->removal_time;
7351 packet.removal_time_factor = e->removal_time_factor;
7352 packet.defense_bonus = e->defense_bonus;
7353 packet.eus = e->eus;
7355 packet.native_to = e->native_to;
7357 packet.flags = e->flags;
7358 packet.hidden_by = e->hidden_by;
7359 packet.conflicts = e->conflicts;
7361 PACKET_STRVEC_COMPUTE(packet.helptext, e->helptext);
7363 lsend_packet_ruleset_extra(dest, &packet);
7364 } extra_type_iterate_end;
7367 /**************************************************************************
7368 Send the base ruleset information (all individual base types) to the
7369 specified connections.
7370 **************************************************************************/
7371 static void send_ruleset_bases(struct conn_list *dest)
7373 extra_type_by_cause_iterate(EC_BASE, pextra) {
7374 struct base_type *b = extra_base_get(pextra);
7375 struct packet_ruleset_base packet;
7377 packet.id = base_number(b);
7379 packet.gui_type = b->gui_type;
7380 packet.border_sq = b->border_sq;
7381 packet.vision_main_sq = b->vision_main_sq;
7382 packet.vision_invis_sq = b->vision_invis_sq;
7384 packet.flags = b->flags;
7386 lsend_packet_ruleset_base(dest, &packet);
7387 } extra_type_by_cause_iterate_end;
7390 /**************************************************************************
7391 Send the road ruleset information (all individual road types) to the
7392 specified connections.
7393 **************************************************************************/
7394 static void send_ruleset_roads(struct conn_list *dest)
7396 struct packet_ruleset_road packet;
7398 extra_type_by_cause_iterate(EC_ROAD, pextra) {
7399 struct road_type *r = extra_road_get(pextra);
7400 int j;
7402 packet.id = road_number(r);
7404 j = 0;
7405 requirement_vector_iterate(&r->first_reqs, preq) {
7406 packet.first_reqs[j++] = *preq;
7407 } requirement_vector_iterate_end;
7408 packet.first_reqs_count = j;
7410 packet.move_cost = r->move_cost;
7411 packet.move_mode = r->move_mode;
7413 output_type_iterate(o) {
7414 packet.tile_incr_const[o] = r->tile_incr_const[o];
7415 packet.tile_incr[o] = r->tile_incr[o];
7416 packet.tile_bonus[o] = r->tile_bonus[o];
7417 } output_type_iterate_end;
7419 packet.compat = r->compat;
7421 packet.integrates = r->integrates;
7422 packet.flags = r->flags;
7424 lsend_packet_ruleset_road(dest, &packet);
7425 } extra_type_by_cause_iterate_end;
7428 /**************************************************************************
7429 Send the goods ruleset information (all individual goods types) to the
7430 specified connections.
7431 **************************************************************************/
7432 static void send_ruleset_goods(struct conn_list *dest)
7434 struct packet_ruleset_goods packet;
7436 goods_type_iterate(g) {
7437 int j;
7439 packet.id = goods_number(g);
7440 sz_strlcpy(packet.name, untranslated_name(&g->name));
7441 sz_strlcpy(packet.rule_name, rule_name_get(&g->name));
7443 j = 0;
7444 requirement_vector_iterate(&g->reqs, preq) {
7445 packet.reqs[j++] = *preq;
7446 } requirement_vector_iterate_end;
7447 packet.reqs_count = j;
7449 packet.from_pct = g->from_pct;
7450 packet.to_pct = g->to_pct;
7451 packet.flags = g->flags;
7453 PACKET_STRVEC_COMPUTE(packet.helptext, g->helptext);
7455 lsend_packet_ruleset_goods(dest, &packet);
7456 } goods_type_iterate_end;
7459 /**************************************************************************
7460 Send the disaster ruleset information (all individual disaster types) to the
7461 specified connections.
7462 **************************************************************************/
7463 static void send_ruleset_disasters(struct conn_list *dest)
7465 struct packet_ruleset_disaster packet;
7467 disaster_type_iterate(d) {
7468 int j;
7470 packet.id = disaster_number(d);
7472 sz_strlcpy(packet.name, untranslated_name(&d->name));
7473 sz_strlcpy(packet.rule_name, rule_name_get(&d->name));
7475 j = 0;
7476 requirement_vector_iterate(&d->reqs, preq) {
7477 packet.reqs[j++] = *preq;
7478 } requirement_vector_iterate_end;
7479 packet.reqs_count = j;
7481 packet.frequency = d->frequency;
7483 packet.effects = d->effects;
7485 lsend_packet_ruleset_disaster(dest, &packet);
7486 } disaster_type_iterate_end;
7489 /**************************************************************************
7490 Send the achievement ruleset information (all individual achievement types)
7491 to the specified connections.
7492 **************************************************************************/
7493 static void send_ruleset_achievements(struct conn_list *dest)
7495 struct packet_ruleset_achievement packet;
7497 achievements_iterate(a) {
7498 packet.id = achievement_number(a);
7500 sz_strlcpy(packet.name, untranslated_name(&a->name));
7501 sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
7503 packet.type = a->type;
7504 packet.unique = a->unique;
7505 packet.value = a->value;
7507 lsend_packet_ruleset_achievement(dest, &packet);
7508 } achievements_iterate_end;
7511 /**************************************************************************
7512 Send action ruleset information to the specified connections.
7513 **************************************************************************/
7514 static void send_ruleset_actions(struct conn_list *dest)
7516 struct packet_ruleset_action packet;
7518 action_iterate(act) {
7519 packet.id = act;
7520 sz_strlcpy(packet.ui_name, action_by_number(act)->ui_name);
7521 packet.quiet = action_by_number(act)->quiet;
7523 packet.act_kind = action_by_number(act)->actor_kind;
7524 packet.tgt_kind = action_by_number(act)->target_kind;
7526 packet.min_distance = action_by_number(act)->min_distance;
7527 packet.max_distance = action_by_number(act)->max_distance;
7528 packet.blocked_by = action_by_number(act)->blocked_by;
7530 lsend_packet_ruleset_action(dest, &packet);
7531 } action_iterate_end;
7534 /**************************************************************************
7535 Send the action enabler ruleset information to the specified connections.
7536 **************************************************************************/
7537 static void send_ruleset_action_enablers(struct conn_list *dest)
7539 int counter;
7540 struct packet_ruleset_action_enabler packet;
7542 action_enablers_iterate(enabler) {
7543 packet.enabled_action = enabler->action;
7545 counter = 0;
7546 requirement_vector_iterate(&enabler->actor_reqs, req) {
7547 packet.actor_reqs[counter++] = *req;
7548 } requirement_vector_iterate_end;
7549 packet.actor_reqs_count = counter;
7551 counter = 0;
7552 requirement_vector_iterate(&enabler->target_reqs, req) {
7553 packet.target_reqs[counter++] = *req;
7554 } requirement_vector_iterate_end;
7555 packet.target_reqs_count = counter;
7557 lsend_packet_ruleset_action_enabler(dest, &packet);
7558 } action_enablers_iterate_end;
7561 /**************************************************************************
7562 Send action auto performer ruleset information to the specified
7563 connections.
7564 **************************************************************************/
7565 static void send_ruleset_action_auto_performers(struct conn_list *dest)
7567 int counter;
7568 int id;
7569 struct packet_ruleset_action_auto packet;
7571 id = 0;
7572 action_auto_perf_iterate(aperf) {
7573 packet.id = id++;
7575 packet.cause = aperf->cause;
7577 counter = 0;
7578 requirement_vector_iterate(&aperf->reqs, req) {
7579 packet.reqs[counter++] = *req;
7580 } requirement_vector_iterate_end;
7581 packet.reqs_count = counter;
7583 for (counter = 0;
7584 /* Can't list more actions than all actions. */
7585 counter < NUM_ACTIONS
7586 /* ACTION_NONE terminates the list. */
7587 && aperf->alternatives[counter] != ACTION_NONE;
7588 counter++) {
7589 packet.alternatives[counter] = aperf->alternatives[counter];
7591 packet.alternatives_count = counter;
7593 lsend_packet_ruleset_action_auto(dest, &packet);
7594 } action_auto_perf_iterate_end;
7597 /**************************************************************************
7598 Send the disaster ruleset information (all individual disaster types) to the
7599 specified connections.
7600 **************************************************************************/
7601 static void send_ruleset_trade_routes(struct conn_list *dest)
7603 struct packet_ruleset_trade packet;
7604 enum trade_route_type type;
7606 for (type = TRT_NATIONAL; type < TRT_LAST; type++) {
7607 struct trade_route_settings *set = trade_route_settings_by_type(type);
7609 packet.id = type;
7610 packet.trade_pct = set->trade_pct;
7611 packet.cancelling = set->cancelling;
7612 packet.bonus_type = set->bonus_type;
7614 lsend_packet_ruleset_trade(dest, &packet);
7618 /**************************************************************************
7619 Send the government ruleset information to the specified connections.
7620 One packet per government type, and for each type one per ruler title.
7621 **************************************************************************/
7622 static void send_ruleset_governments(struct conn_list *dest)
7624 struct packet_ruleset_government gov;
7625 struct packet_ruleset_government_ruler_title title;
7626 int j;
7628 governments_iterate(g) {
7629 /* send one packet_government */
7630 gov.id = government_number(g);
7632 j = 0;
7633 requirement_vector_iterate(&g->reqs, preq) {
7634 gov.reqs[j++] = *preq;
7635 } requirement_vector_iterate_end;
7636 gov.reqs_count = j;
7638 sz_strlcpy(gov.name, untranslated_name(&g->name));
7639 sz_strlcpy(gov.rule_name, rule_name_get(&g->name));
7640 sz_strlcpy(gov.graphic_str, g->graphic_str);
7641 sz_strlcpy(gov.graphic_alt, g->graphic_alt);
7642 PACKET_STRVEC_COMPUTE(gov.helptext, g->helptext);
7644 lsend_packet_ruleset_government(dest, &gov);
7646 /* Send one packet_government_ruler_title per ruler title. */
7647 ruler_titles_iterate(government_ruler_titles(g), pruler_title) {
7648 const struct nation_type *pnation = ruler_title_nation(pruler_title);
7650 title.gov = government_number(g);
7651 title.nation = pnation ? nation_number(pnation) : nation_count();
7652 sz_strlcpy(title.male_title,
7653 ruler_title_male_untranslated_name(pruler_title));
7654 sz_strlcpy(title.female_title,
7655 ruler_title_female_untranslated_name(pruler_title));
7656 lsend_packet_ruleset_government_ruler_title(dest, &title);
7657 } ruler_titles_iterate_end;
7658 } governments_iterate_end;
7661 /**************************************************************************
7662 Send the nations ruleset information (info on each nation) to the
7663 specified connections.
7664 **************************************************************************/
7665 static void send_ruleset_nations(struct conn_list *dest)
7667 struct packet_ruleset_nation_sets sets_packet;
7668 struct packet_ruleset_nation_groups groups_packet;
7669 struct packet_ruleset_nation packet;
7670 int i;
7672 sets_packet.nsets = nation_set_count();
7673 i = 0;
7674 nation_sets_iterate(pset) {
7675 sz_strlcpy(sets_packet.names[i], nation_set_untranslated_name(pset));
7676 sz_strlcpy(sets_packet.rule_names[i], nation_set_rule_name(pset));
7677 sz_strlcpy(sets_packet.descriptions[i], nation_set_description(pset));
7678 i++;
7679 } nation_sets_iterate_end;
7680 lsend_packet_ruleset_nation_sets(dest, &sets_packet);
7682 groups_packet.ngroups = nation_group_count();
7683 i = 0;
7684 nation_groups_iterate(pgroup) {
7685 sz_strlcpy(groups_packet.groups[i],
7686 nation_group_untranslated_name(pgroup));
7687 groups_packet.hidden[i] = pgroup->hidden;
7688 i++;
7689 } nation_groups_iterate_end;
7690 lsend_packet_ruleset_nation_groups(dest, &groups_packet);
7692 nations_iterate(n) {
7693 packet.id = nation_number(n);
7694 if (n->translation_domain == NULL) {
7695 packet.translation_domain[0] = '\0';
7696 } else {
7697 sz_strlcpy(packet.translation_domain, n->translation_domain);
7699 sz_strlcpy(packet.adjective, untranslated_name(&n->adjective));
7700 sz_strlcpy(packet.rule_name, rule_name_get(&n->adjective));
7701 sz_strlcpy(packet.noun_plural, untranslated_name(&n->noun_plural));
7702 sz_strlcpy(packet.graphic_str, n->flag_graphic_str);
7703 sz_strlcpy(packet.graphic_alt, n->flag_graphic_alt);
7705 i = 0;
7706 nation_leader_list_iterate(nation_leaders(n), pleader) {
7707 sz_strlcpy(packet.leader_name[i], nation_leader_name(pleader));
7708 packet.leader_is_male[i] = nation_leader_is_male(pleader);
7709 i++;
7710 } nation_leader_list_iterate_end;
7711 packet.leader_count = i;
7713 packet.style = style_number(n->style);
7714 packet.is_playable = n->is_playable;
7715 packet.barbarian_type = n->barb_type;
7717 sz_strlcpy(packet.legend, n->legend);
7719 i = 0;
7720 nation_set_list_iterate(n->sets, pset) {
7721 packet.sets[i++] = nation_set_number(pset);
7722 } nation_set_list_iterate_end;
7723 packet.nsets = i;
7725 i = 0;
7726 nation_group_list_iterate(n->groups, pgroup) {
7727 packet.groups[i++] = nation_group_number(pgroup);
7728 } nation_group_list_iterate_end;
7729 packet.ngroups = i;
7731 packet.init_government_id = n->init_government
7732 ? government_number(n->init_government) : government_count();
7733 fc_assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n->init_techs));
7734 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
7735 packet.init_techs[i] = n->init_techs[i];
7737 fc_assert(ARRAY_SIZE(packet.init_units) == ARRAY_SIZE(n->init_units));
7738 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
7739 const struct unit_type *t = n->init_units[i];
7740 packet.init_units[i] = t ? utype_number(t) : U_LAST;
7742 fc_assert(ARRAY_SIZE(packet.init_buildings)
7743 == ARRAY_SIZE(n->init_buildings));
7744 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
7745 /* Impr_type_id to int */
7746 packet.init_buildings[i] = n->init_buildings[i];
7749 lsend_packet_ruleset_nation(dest, &packet);
7750 } nations_iterate_end;
7752 /* Send initial values of is_pickable */
7753 send_nation_availability(dest, FALSE);
7756 /**************************************************************************
7757 Send the nation style ruleset information (each style) to the specified
7758 connections.
7759 **************************************************************************/
7760 static void send_ruleset_styles(struct conn_list *dest)
7762 struct packet_ruleset_style packet;
7764 styles_iterate(s) {
7765 packet.id = style_index(s);
7766 sz_strlcpy(packet.name, untranslated_name(&s->name));
7767 sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
7769 lsend_packet_ruleset_style(dest, &packet);
7770 } styles_iterate_end;
7773 /**************************************************************************
7774 Send the multiplier ruleset information to the specified
7775 connections.
7776 **************************************************************************/
7777 static void send_ruleset_multipliers(struct conn_list *dest)
7779 char helptext[MAX_LEN_PACKET];
7781 multipliers_iterate(pmul) {
7782 PACKET_STRVEC_COMPUTE(helptext, pmul->helptext);
7784 dlsend_packet_ruleset_multiplier(dest, multiplier_number(pmul),
7785 pmul->start, pmul->stop,
7786 pmul->step, pmul->def,
7787 pmul->offset, pmul->factor,
7788 untranslated_name(&pmul->name),
7789 rule_name_get(&pmul->name),
7790 helptext);
7791 } multipliers_iterate_end;
7794 /**************************************************************************
7795 Send the city-style ruleset information (each style) to the specified
7796 connections.
7797 **************************************************************************/
7798 static void send_ruleset_cities(struct conn_list *dest)
7800 struct packet_ruleset_city city_p;
7801 int k, j;
7803 for (k = 0; k < game.control.styles_count; k++) {
7804 city_p.style_id = k;
7806 j = 0;
7807 requirement_vector_iterate(&city_styles[k].reqs, preq) {
7808 city_p.reqs[j++] = *preq;
7809 } requirement_vector_iterate_end;
7810 city_p.reqs_count = j;
7812 sz_strlcpy(city_p.name, untranslated_name(&city_styles[k].name));
7813 sz_strlcpy(city_p.rule_name, rule_name_get(&city_styles[k].name));
7814 sz_strlcpy(city_p.graphic, city_styles[k].graphic);
7815 sz_strlcpy(city_p.graphic_alt, city_styles[k].graphic_alt);
7816 sz_strlcpy(city_p.citizens_graphic, city_styles[k].citizens_graphic);
7817 sz_strlcpy(city_p.citizens_graphic_alt,
7818 city_styles[k].citizens_graphic_alt);
7820 lsend_packet_ruleset_city(dest, &city_p);
7824 /**************************************************************************
7825 Send the music-style ruleset information (each style) to the specified
7826 connections.
7827 **************************************************************************/
7828 static void send_ruleset_musics(struct conn_list *dest)
7830 struct packet_ruleset_music packet;
7832 music_styles_iterate(pmus) {
7833 int j;
7835 packet.id = pmus->id;
7837 sz_strlcpy(packet.music_peaceful, pmus->music_peaceful);
7838 sz_strlcpy(packet.music_combat, pmus->music_combat);
7840 j = 0;
7841 requirement_vector_iterate(&(pmus->reqs), preq) {
7842 packet.reqs[j++] = *preq;
7843 } requirement_vector_iterate_end;
7844 packet.reqs_count = j;
7846 lsend_packet_ruleset_music(dest, &packet);
7847 } music_styles_iterate_end;
7850 /**************************************************************************
7851 Send information in packet_ruleset_game (miscellaneous rules) to the
7852 specified connections.
7853 **************************************************************************/
7854 static void send_ruleset_game(struct conn_list *dest)
7856 struct packet_ruleset_game misc_p;
7857 int i;
7859 fc_assert_ret(game.veteran != NULL);
7861 /* Per unit veteran system definition. */
7862 misc_p.veteran_levels = game.veteran->levels;
7864 for (i = 0; i < misc_p.veteran_levels; i++) {
7865 const struct veteran_level *vlevel = game.veteran->definitions + i;
7867 sz_strlcpy(misc_p.veteran_name[i], untranslated_name(&vlevel->name));
7868 misc_p.power_fact[i] = vlevel->power_fact;
7869 misc_p.move_bonus[i] = vlevel->move_bonus;
7872 fc_assert(sizeof(misc_p.global_init_techs)
7873 == sizeof(game.rgame.global_init_techs));
7874 fc_assert(ARRAY_SIZE(misc_p.global_init_techs)
7875 == ARRAY_SIZE(game.rgame.global_init_techs));
7876 memcpy(misc_p.global_init_techs, game.rgame.global_init_techs,
7877 sizeof(misc_p.global_init_techs));
7879 fc_assert(ARRAY_SIZE(misc_p.global_init_buildings)
7880 == ARRAY_SIZE(game.rgame.global_init_buildings));
7881 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
7882 /* Impr_type_id to int */
7883 misc_p.global_init_buildings[i] =
7884 game.rgame.global_init_buildings[i];
7887 misc_p.default_specialist = DEFAULT_SPECIALIST;
7889 fc_assert_ret(game.plr_bg_color != NULL);
7891 misc_p.background_red = game.plr_bg_color->r;
7892 misc_p.background_green = game.plr_bg_color->g;
7893 misc_p.background_blue = game.plr_bg_color->b;
7895 lsend_packet_ruleset_game(dest, &misc_p);
7898 /**************************************************************************
7899 Send all team names defined in the ruleset file(s) to the
7900 specified connections.
7901 **************************************************************************/
7902 static void send_ruleset_team_names(struct conn_list *dest)
7904 struct packet_team_name_info team_name_info_p;
7906 team_slots_iterate(tslot) {
7907 const char *name = team_slot_defined_name(tslot);
7909 if (NULL == name) {
7910 /* End of defined names. */
7911 break;
7914 team_name_info_p.team_id = team_slot_index(tslot);
7915 sz_strlcpy(team_name_info_p.team_name, name);
7917 lsend_packet_team_name_info(dest, &team_name_info_p);
7918 } team_slots_iterate_end;
7921 /**************************************************************************
7922 Make it clear to everyone that requested ruleset has not been loaded.
7923 **************************************************************************/
7924 static void notify_ruleset_fallback(const char *msg)
7926 notify_conn(NULL, NULL, E_LOG_FATAL, ftc_warning, "%s", msg);
7929 /**************************************************************************
7930 Loads the rulesets.
7931 **************************************************************************/
7932 bool load_rulesets(const char *restore, bool compat_mode,
7933 bool act, bool buffer_script)
7935 if (load_rulesetdir(game.server.rulesetdir, compat_mode, act, buffer_script)) {
7936 return TRUE;
7939 /* Fallback to previous one. */
7940 if (restore != NULL) {
7941 if (load_rulesetdir(restore, compat_mode, act, buffer_script)) {
7942 sz_strlcpy(game.server.rulesetdir, restore);
7944 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Keeping previous one."));
7946 /* We're in sane state as restoring previous ruleset succeeded,
7947 * but return failure to indicate that this is not what caller
7948 * wanted. */
7949 return FALSE;
7953 /* Fallback to default one, but not if that's what we tried already */
7954 if (strcmp(GAME_DEFAULT_RULESETDIR, game.server.rulesetdir)
7955 && (restore == NULL || strcmp(GAME_DEFAULT_RULESETDIR, restore))) {
7956 if (load_rulesetdir(GAME_DEFAULT_RULESETDIR, FALSE, act, buffer_script)) {
7957 /* We're in sane state as fallback ruleset loading succeeded,
7958 * but return failure to indicate that this is not what caller
7959 * wanted. */
7960 sz_strlcpy(game.server.rulesetdir, GAME_DEFAULT_RULESETDIR);
7962 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Switching to default one."));
7964 return FALSE;
7968 #ifdef FREECIV_WEB
7969 log_normal(_("Cannot load any ruleset. Freeciv-web ruleset is available from "
7970 "https://github.com/freeciv/freeciv-web"));
7971 #endif /* FREECIV_WEB */
7973 /* Cannot load even default ruleset, we're in completely unusable state */
7974 exit(EXIT_FAILURE);
7977 /**************************************************************************
7978 destroy secfile. Handle NULL parameter gracefully.
7979 **************************************************************************/
7980 static void nullcheck_secfile_destroy(struct section_file *file)
7982 if (file != NULL) {
7983 secfile_destroy(file);
7987 /**************************************************************************
7988 Completely deinitialize ruleset system. Server is not in usable
7989 state after this.
7990 **************************************************************************/
7991 void rulesets_deinit(void)
7993 script_server_free();
7994 requirement_vector_free(&reqs_list);
7997 /**************************************************************************
7998 Loads the rulesets from directory.
7999 This may be called more than once and it will free any stale data.
8000 **************************************************************************/
8001 static bool load_rulesetdir(const char *rsdir, bool compat_mode,
8002 bool act, bool buffer_script)
8004 struct section_file *techfile, *unitfile, *buildfile, *govfile, *terrfile;
8005 struct section_file *stylefile, *cityfile, *nationfile, *effectfile, *gamefile;
8006 bool ok = TRUE;
8007 struct rscompat_info compat_info;
8009 log_normal(_("Loading rulesets."));
8011 rscompat_init_info(&compat_info);
8012 compat_info.compat_mode = compat_mode;
8014 game_ruleset_free();
8015 /* Reset the list of available player colors. */
8016 playercolor_free();
8017 playercolor_init();
8018 game_ruleset_init();
8020 if (script_buffer != NULL) {
8021 FC_FREE(script_buffer);
8022 script_buffer = NULL;
8025 server.playable_nations = 0;
8027 techfile = openload_ruleset_file("techs", rsdir);
8028 buildfile = openload_ruleset_file("buildings", rsdir);
8029 govfile = openload_ruleset_file("governments", rsdir);
8030 unitfile = openload_ruleset_file("units", rsdir);
8031 terrfile = openload_ruleset_file("terrain", rsdir);
8032 stylefile = openload_ruleset_file("styles", rsdir);
8033 cityfile = openload_ruleset_file("cities", rsdir);
8034 nationfile = openload_ruleset_file("nations", rsdir);
8035 effectfile = openload_ruleset_file("effects", rsdir);
8036 gamefile = openload_ruleset_file("game", rsdir);
8037 game.server.luadata = openload_luadata_file(rsdir);
8039 if (techfile == NULL
8040 || buildfile == NULL
8041 || govfile == NULL
8042 || unitfile == NULL
8043 || terrfile == NULL
8044 || stylefile == NULL
8045 || cityfile == NULL
8046 || nationfile == NULL
8047 || effectfile == NULL
8048 || gamefile == NULL) {
8049 ok = FALSE;
8052 if (ok) {
8053 ok = load_game_names(gamefile, &compat_info)
8054 && load_tech_names(techfile, &compat_info)
8055 && load_building_names(buildfile, &compat_info)
8056 && load_government_names(govfile, &compat_info)
8057 && load_unit_names(unitfile, &compat_info)
8058 && load_terrain_names(terrfile, &compat_info)
8059 && load_style_names(stylefile, &compat_info)
8060 && load_nation_names(nationfile, &compat_info);
8063 if (ok) {
8064 ok = rscompat_names(&compat_info);
8067 if (ok) {
8068 ok = load_ruleset_techs(techfile, &compat_info);
8070 if (ok) {
8071 ok = load_ruleset_styles(stylefile, &compat_info);
8073 if (ok) {
8074 ok = load_ruleset_cities(cityfile, &compat_info);
8076 if (ok) {
8077 ok = load_ruleset_governments(govfile, &compat_info);
8079 if (ok) {
8080 /* terrain must precede nations and units */
8081 ok = load_ruleset_terrain(terrfile, &compat_info);
8083 if (ok) {
8084 ok = load_ruleset_units(unitfile, &compat_info);
8086 if (ok) {
8087 ok = load_ruleset_buildings(buildfile, &compat_info);
8089 if (ok) {
8090 ok = load_ruleset_nations(nationfile, &compat_info);
8092 if (ok) {
8093 ok = load_ruleset_effects(effectfile, &compat_info);
8095 if (ok) {
8096 ok = load_ruleset_game(gamefile, act, &compat_info);
8099 if (ok) {
8100 /* Init nations we just loaded. */
8101 update_nations_with_startpos();
8103 /* Needed by role_unit_precalcs(). */
8104 unit_type_action_cache_init();
8106 /* Prepare caches we want to sanity check. */
8107 role_unit_precalcs();
8108 road_integrators_cache_init();
8109 actions_rs_pre_san_gen();
8111 ok = autoadjust_ruleset_data()
8112 && sanity_check_ruleset_data(compat_info.compat_mode);
8115 if (ok) {
8116 /* Only load settings for a sane ruleset */
8117 ok = settings_ruleset(gamefile, "settings", act);
8119 if (ok) {
8120 secfile_check_unused(gamefile);
8124 nullcheck_secfile_destroy(techfile);
8125 nullcheck_secfile_destroy(stylefile);
8126 nullcheck_secfile_destroy(cityfile);
8127 nullcheck_secfile_destroy(govfile);
8128 nullcheck_secfile_destroy(terrfile);
8129 nullcheck_secfile_destroy(unitfile);
8130 nullcheck_secfile_destroy(buildfile);
8131 nullcheck_secfile_destroy(nationfile);
8132 nullcheck_secfile_destroy(effectfile);
8133 nullcheck_secfile_destroy(gamefile);
8135 if (extra_sections) {
8136 free(extra_sections);
8137 extra_sections = NULL;
8139 if (base_sections) {
8140 free(base_sections);
8141 base_sections = NULL;
8143 if (road_sections) {
8144 free(road_sections);
8145 road_sections = NULL;
8147 if (resource_sections) {
8148 free(resource_sections);
8149 resource_sections = NULL;
8151 if (terrain_sections) {
8152 free(terrain_sections);
8153 terrain_sections = NULL;
8156 if (ok) {
8157 rscompat_postprocess(&compat_info);
8160 if (ok) {
8162 char **buffer = buffer_script ? &script_buffer : NULL;
8164 script_server_free();
8166 script_server_init();
8168 ok = openload_script_file("script", rsdir, buffer);
8171 if (ok && !buffer_script) {
8172 ok = openload_script_file("default", rsdir, NULL);
8175 if (ok && act) {
8176 /* Populate remaining caches. */
8177 techs_precalc_data();
8178 improvement_feature_cache_init();
8179 unit_class_iterate(pclass) {
8180 set_unit_class_caches(pclass);
8181 } unit_class_iterate_end;
8182 unit_type_iterate(ptype) {
8183 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
8184 set_unit_type_caches(ptype);
8185 } unit_type_iterate_end;
8186 city_production_caravan_shields_init();
8188 /* Build advisors unit class cache corresponding to loaded rulesets */
8189 adv_units_ruleset_init();
8190 CALL_FUNC_EACH_AI(units_ruleset_init);
8192 /* We may need to adjust the number of AI players
8193 * if the number of available nations changed. */
8194 (void) aifill(game.info.aifill);
8197 return ok;
8200 /**************************************************************************
8201 Reload the game settings saved in the ruleset file.
8202 **************************************************************************/
8203 bool reload_rulesets_settings(void)
8205 struct section_file *file;
8206 bool ok = TRUE;
8208 file = openload_ruleset_file("game", game.server.rulesetdir);
8209 if (file == NULL) {
8210 ruleset_error(LOG_ERROR, "Could not load game.ruleset:\n%s",
8211 secfile_error());
8212 ok = FALSE;
8214 if (ok) {
8215 settings_ruleset(file, "settings", TRUE);
8216 secfile_destroy(file);
8219 return ok;
8222 /**************************************************************************
8223 Send all ruleset information to the specified connections.
8224 **************************************************************************/
8225 void send_rulesets(struct conn_list *dest)
8227 conn_list_compression_freeze(dest);
8229 /* ruleset_control also indicates to client that ruleset sending starts. */
8230 send_ruleset_control(dest);
8232 send_ruleset_game(dest);
8233 send_ruleset_disasters(dest);
8234 send_ruleset_achievements(dest);
8235 send_ruleset_trade_routes(dest);
8236 send_ruleset_team_names(dest);
8237 send_ruleset_actions(dest);
8238 send_ruleset_action_enablers(dest);
8239 send_ruleset_action_auto_performers(dest);
8240 send_ruleset_tech_classes(dest);
8241 send_ruleset_techs(dest);
8242 send_ruleset_governments(dest);
8243 send_ruleset_unit_classes(dest);
8244 send_ruleset_units(dest);
8245 send_ruleset_specialists(dest);
8246 send_ruleset_extras(dest);
8247 send_ruleset_bases(dest);
8248 send_ruleset_roads(dest);
8249 send_ruleset_resources(dest);
8250 send_ruleset_terrain(dest);
8251 send_ruleset_goods(dest);
8252 send_ruleset_buildings(dest);
8253 send_ruleset_nations(dest);
8254 send_ruleset_styles(dest);
8255 send_ruleset_cities(dest);
8256 send_ruleset_multipliers(dest);
8257 send_ruleset_musics(dest);
8258 send_ruleset_cache(dest);
8260 /* Indicate client that all rulesets have now been sent. */
8261 lsend_packet_rulesets_ready(dest);
8263 /* changed game settings will be send in
8264 * connecthand.c:establish_new_connection() */
8266 conn_list_compression_thaw(dest);