Moved make_escapes() and remove_escapes() to support.c.
[freeciv.git] / server / ruleset.c
blob33416f09e5fd198f464a0006d271507f5a41af3a
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 "rssanity.h"
69 #include "settings.h"
70 #include "srv_main.h"
72 /* server/advisors */
73 #include "advruleset.h"
75 /* server/scripting */
76 #include "script_server.h"
78 #include "ruleset.h"
80 /* RULESET_SUFFIX already used, no leading dot here */
81 #define RULES_SUFFIX "ruleset"
82 #define SCRIPT_SUFFIX "lua"
84 #define ADVANCE_SECTION_PREFIX "advance_"
85 #define BUILDING_SECTION_PREFIX "building_"
86 #define CITYSTYLE_SECTION_PREFIX "citystyle_"
87 #define MUSICSTYLE_SECTION_PREFIX "musicstyle_"
88 #define EFFECT_SECTION_PREFIX "effect_"
89 #define GOVERNMENT_SECTION_PREFIX "government_"
90 #define NATION_SET_SECTION_PREFIX "nset" /* without underscore? */
91 #define NATION_GROUP_SECTION_PREFIX "ngroup" /* without underscore? */
92 #define NATION_SECTION_PREFIX "nation" /* without underscore? */
93 #define STYLE_SECTION_PREFIX "style_"
94 #define RESOURCE_SECTION_PREFIX "resource_"
95 #define EXTRA_SECTION_PREFIX "extra_"
96 #define BASE_SECTION_PREFIX "base_"
97 #define ROAD_SECTION_PREFIX "road_"
98 #define SPECIALIST_SECTION_PREFIX "specialist_"
99 #define TERRAIN_SECTION_PREFIX "terrain_"
100 #define UNIT_CLASS_SECTION_PREFIX "unitclass_"
101 #define UNIT_SECTION_PREFIX "unit_"
102 #define DISASTER_SECTION_PREFIX "disaster_"
103 #define ACHIEVEMENT_SECTION_PREFIX "achievement_"
104 #define ACTION_ENABLER_SECTION_PREFIX "actionenabler_"
105 #define MULTIPLIER_SECTION_PREFIX "multiplier_"
107 #define check_name(name) (check_strlen(name, MAX_LEN_NAME, NULL))
109 /* avoid re-reading files */
110 static const char name_too_long[] = "Name \"%s\" too long; truncating.";
111 #define MAX_SECTION_LABEL 64
112 #define section_strlcpy(dst, src) \
113 (void) loud_strlcpy(dst, src, MAX_SECTION_LABEL, name_too_long)
114 static char *resource_sections = NULL;
115 static char *terrain_sections = NULL;
116 static char *extra_sections = NULL;
117 static char *base_sections = NULL;
118 static char *road_sections = NULL;
120 static struct requirement_vector reqs_list;
122 static bool load_rulesetdir(const char *rsdir, bool act, bool buffer_script);
123 static struct section_file *openload_ruleset_file(const char *whichset,
124 const char *rsdir);
125 static const char *check_ruleset_capabilities(struct section_file *file,
126 const char *us_capstr,
127 const char *filename);
129 static bool load_game_names(struct section_file *file);
130 static bool load_tech_names(struct section_file *file);
131 static bool load_unit_names(struct section_file *file);
132 static bool load_building_names(struct section_file *file);
133 static bool load_government_names(struct section_file *file);
134 static bool load_terrain_names(struct section_file *file);
135 static bool load_style_names(struct section_file *file);
136 static bool load_nation_names(struct section_file *file);
137 static bool load_city_name_list(struct section_file *file,
138 struct nation_type *pnation,
139 const char *secfile_str1,
140 const char *secfile_str2,
141 const char **allowed_terrains,
142 size_t atcount);
144 static bool load_ruleset_techs(struct section_file *file);
145 static bool load_ruleset_units(struct section_file *file);
146 static bool load_ruleset_buildings(struct section_file *file);
147 static bool load_ruleset_governments(struct section_file *file);
148 static bool load_ruleset_terrain(struct section_file *file);
149 static bool load_ruleset_styles(struct section_file *file);
150 static bool load_ruleset_cities(struct section_file *file);
151 static bool load_ruleset_effects(struct section_file *file);
153 static bool load_ruleset_game(struct section_file *file, bool act);
155 static void send_ruleset_techs(struct conn_list *dest);
156 static void send_ruleset_unit_classes(struct conn_list *dest);
157 static void send_ruleset_units(struct conn_list *dest);
158 static void send_ruleset_buildings(struct conn_list *dest);
159 static void send_ruleset_terrain(struct conn_list *dest);
160 static void send_ruleset_resources(struct conn_list *dest);
161 static void send_ruleset_extras(struct conn_list *dest);
162 static void send_ruleset_bases(struct conn_list *dest);
163 static void send_ruleset_roads(struct conn_list *dest);
164 static void send_ruleset_governments(struct conn_list *dest);
165 static void send_ruleset_styles(struct conn_list *dest);
166 static void send_ruleset_musics(struct conn_list *dest);
167 static void send_ruleset_cities(struct conn_list *dest);
168 static void send_ruleset_game(struct conn_list *dest);
169 static void send_ruleset_team_names(struct conn_list *dest);
171 static bool load_ruleset_veteran(struct section_file *file,
172 const char *path,
173 struct veteran_system **vsystem, char *err,
174 size_t err_len);
176 char *script_buffer = NULL;
178 /**************************************************************************
179 Notifications about ruleset errors to clients. Especially important in
180 case of internal server crashing.
181 **************************************************************************/
182 void ruleset_error_real(const char *file, const char *function,
183 int line, enum log_level level,
184 const char *format, ...)
186 va_list args;
187 char buf[1024];
189 va_start(args, format);
190 vdo_log(file, function, line, FALSE, level, buf, sizeof(buf), format, args);
191 va_end(args);
193 if (LOG_FATAL >= level) {
194 exit(EXIT_FAILURE);
198 /**************************************************************************
199 datafilename() wrapper: tries to match in two ways.
200 Returns NULL on failure, the (statically allocated) filename on success.
201 **************************************************************************/
202 static const char *valid_ruleset_filename(const char *subdir,
203 const char *name,
204 const char *extension)
206 char filename[512];
207 const char *dfilename;
209 fc_assert_ret_val(subdir && name && extension, NULL);
211 fc_snprintf(filename, sizeof(filename), "%s" DIR_SEPARATOR "%s.%s",
212 subdir, name, extension);
213 log_verbose("Trying \"%s\".", filename);
214 dfilename = fileinfoname(get_data_dirs(), filename);
215 if (dfilename) {
216 return dfilename;
219 fc_snprintf(filename, sizeof(filename), "default" DIR_SEPARATOR "%s.%s", name, extension);
220 log_verbose("Trying \"%s\": default ruleset directory.", filename);
221 dfilename = fileinfoname(get_data_dirs(), filename);
222 if (dfilename) {
223 return dfilename;
226 fc_snprintf(filename, sizeof(filename), "%s_%s.%s",
227 subdir, name, extension);
228 log_verbose("Trying \"%s\": alternative ruleset filename syntax.",
229 filename);
230 dfilename = fileinfoname(get_data_dirs(), filename);
231 if (dfilename) {
232 return dfilename;
233 } else {
234 ruleset_error(LOG_ERROR,
235 /* TRANS: message about an installation error. */
236 _("Could not find a readable \"%s.%s\" ruleset file."),
237 name, extension);
240 return NULL;
243 /**************************************************************************
244 Return current script.lua buffer.
245 **************************************************************************/
246 char *get_script_buffer(void)
248 return script_buffer;
251 /**************************************************************************
252 Do initial section_file_load on a ruleset file.
253 "whichset" = "techs", "units", "buildings", "terrain", ...
254 **************************************************************************/
255 static struct section_file *openload_ruleset_file(const char *whichset,
256 const char *rsdir)
258 char sfilename[512];
259 const char *dfilename = valid_ruleset_filename(rsdir, whichset,
260 RULES_SUFFIX);
261 struct section_file *secfile;
263 if (dfilename == NULL) {
264 return NULL;
267 /* Need to save a copy of the filename for following message, since
268 section_file_load() may call datafilename() for includes. */
269 sz_strlcpy(sfilename, dfilename);
270 secfile = secfile_load(sfilename, FALSE);
272 if (secfile == NULL) {
273 ruleset_error(LOG_ERROR, "Could not load ruleset '%s':\n%s",
274 sfilename, secfile_error());
277 return secfile;
280 /**************************************************************************
281 Parse script file.
282 **************************************************************************/
283 static bool openload_script_file(const char *whichset, const char *rsdir,
284 char **buffer)
286 const char *dfilename = valid_ruleset_filename(rsdir, whichset,
287 SCRIPT_SUFFIX);
289 if (dfilename == NULL) {
290 return FALSE;
293 if (buffer == NULL) {
294 if (!script_server_do_file(NULL, dfilename)) {
295 ruleset_error(LOG_ERROR, "\"%s\": could not load ruleset script.",
296 dfilename);
298 return FALSE;
300 } else {
301 script_server_load_file(dfilename, buffer);
304 return TRUE;
307 /**************************************************************************
308 Ruleset files should have a capabilities string datafile.options
309 This gets and returns that string, and checks that the required
310 capabilities specified are satisified.
311 **************************************************************************/
312 static const char *check_ruleset_capabilities(struct section_file *file,
313 const char *us_capstr,
314 const char *filename)
316 const char *datafile_options;
318 if (!(datafile_options = secfile_lookup_str(file, "datafile.options"))) {
319 log_fatal("\"%s\": ruleset capability problem:", filename);
320 ruleset_error(LOG_ERROR, "%s", secfile_error());
322 return NULL;
324 if (!has_capabilities(us_capstr, datafile_options)) {
325 log_fatal("\"%s\": ruleset datafile appears incompatible:", filename);
326 log_fatal(" datafile options: %s", datafile_options);
327 log_fatal(" supported options: %s", us_capstr);
328 ruleset_error(LOG_ERROR, "Capability problem");
330 return NULL;
332 if (!has_capabilities(datafile_options, us_capstr)) {
333 log_fatal("\"%s\": ruleset datafile claims required option(s)"
334 " that we don't support:", filename);
335 log_fatal(" datafile options: %s", datafile_options);
336 log_fatal(" supported options: %s", us_capstr);
337 ruleset_error(LOG_ERROR, "Capability problem");
339 return NULL;
341 return datafile_options;
344 /**************************************************************************
345 Load a requirement list. The list is returned as a static vector
346 (callers need not worry about freeing anything).
347 **************************************************************************/
348 static struct requirement_vector *lookup_req_list(struct section_file *file,
349 const char *sec,
350 const char *sub,
351 const char *rfor)
353 const char *type, *name;
354 int j;
355 const char *filename;
357 filename = secfile_name(file);
359 requirement_vector_reserve(&reqs_list, 0);
361 for (j = 0; (type = secfile_lookup_str_default(file, NULL, "%s.%s%d.type",
362 sec, sub, j)); j++) {
363 char buf[MAX_LEN_NAME];
364 const char *range;
365 bool survives, present, quiet;
366 struct entry *pentry;
367 struct requirement req;
369 if (!(pentry = secfile_entry_lookup(file, "%s.%s%d.name",
370 sec, sub, j))) {
371 ruleset_error(LOG_ERROR, "%s", secfile_error());
373 return NULL;
375 name = NULL;
376 switch (entry_type(pentry)) {
377 case ENTRY_BOOL:
379 bool val;
381 if (entry_bool_get(pentry, &val)) {
382 fc_snprintf(buf, sizeof(buf), "%d", val);
383 name = buf;
386 break;
387 case ENTRY_INT:
389 int val;
391 if (entry_int_get(pentry, &val)) {
392 fc_snprintf(buf, sizeof(buf), "%d", val);
393 name = buf;
396 break;
397 case ENTRY_STR:
398 (void) entry_str_get(pentry, &name);
399 break;
400 case ENTRY_FLOAT:
401 fc_assert(entry_type(pentry) != ENTRY_FLOAT);
402 ruleset_error(LOG_ERROR,
403 "\"%s\": trying to have an floating point entry as a requirement name in '%s.%s%d'.",
404 filename, sec, sub, j);
405 break;
406 case ENTRY_FILEREFERENCE:
407 fc_assert(entry_type(pentry) != ENTRY_FILEREFERENCE);
409 if (NULL == name) {
410 ruleset_error(LOG_ERROR,
411 "\"%s\": error in handling requirement name for '%s.%s%d'.",
412 filename, sec, sub, j);
413 return NULL;
416 if (!(range = secfile_lookup_str(file, "%s.%s%d.range", sec, sub, j))) {
417 ruleset_error(LOG_ERROR, "%s", secfile_error());
419 return NULL;
422 survives = FALSE;
423 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.survives",
424 sec, sub, j))
425 && !entry_bool_get(pentry, &survives)) {
426 ruleset_error(LOG_ERROR,
427 "\"%s\": invalid boolean value for survives for "
428 "'%s.%s%d'.", filename, sec, sub, j);
431 present = TRUE;
432 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.present",
433 sec, sub, j))
434 && !entry_bool_get(pentry, &present)) {
435 ruleset_error(LOG_ERROR,
436 "\"%s\": invalid boolean value for present for "
437 "'%s.%s%d'.", filename, sec, sub, j);
439 quiet = FALSE;
440 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.quiet",
441 sec, sub, j))
442 && !entry_bool_get(pentry, &quiet)) {
443 ruleset_error(LOG_ERROR,
444 "\"%s\": invalid boolean value for quiet for "
445 "'%s.%s%d'.", filename, sec, sub, j);
448 req = req_from_str(type, range, survives, present, quiet, name);
449 if (req.source.kind == universals_n_invalid()) {
450 ruleset_error(LOG_ERROR, "\"%s\" [%s] has invalid or unknown req: "
451 "\"%s\" \"%s\".",
452 filename, sec, type, name);
454 return NULL;
457 requirement_vector_append(&reqs_list, req);
460 if (j > MAX_NUM_REQS) {
461 ruleset_error(LOG_ERROR, "Too many (%d) requirements for %s. Max is %d",
462 j, rfor, MAX_NUM_REQS);
464 return NULL;
467 return &reqs_list;
470 /**************************************************************************
471 Load combat bonus list
472 **************************************************************************/
473 static bool lookup_cbonus_list(struct combat_bonus_list *list,
474 struct section_file *file,
475 const char *sec,
476 const char *sub)
478 const char *flag;
479 int j;
480 const char *filename;
481 bool success = TRUE;
483 filename = secfile_name(file);
485 for (j = 0; (flag = secfile_lookup_str_default(file, NULL, "%s.%s%d.flag",
486 sec, sub, j)); j++) {
487 struct combat_bonus *bonus = fc_malloc(sizeof(*bonus));
488 const char *type;
490 bonus->flag = unit_type_flag_id_by_name(flag, fc_strcasecmp);
491 if (!unit_type_flag_id_is_valid(bonus->flag)) {
492 log_error("\"%s\": unknown flag name \"%s\" in '%s.%s'.",
493 filename, flag, sec, sub);
494 FC_FREE(bonus);
495 success = FALSE;
496 continue;
498 type = secfile_lookup_str(file, "%s.%s%d.type", sec, sub, j);
499 bonus->type = combat_bonus_type_by_name(type, fc_strcasecmp);
500 if (!combat_bonus_type_is_valid(bonus->type)) {
501 log_error("\"%s\": unknown bonus type \"%s\" in '%s.%s'.",
502 filename, type, sec, sub);
503 FC_FREE(bonus);
504 success = FALSE;
505 continue;
507 if (!secfile_lookup_int(file, &bonus->value, "%s.%s%d.value",
508 sec, sub, j)) {
509 log_error("\"%s\": failed to get value from '%s.%s%d'.",
510 filename, sec, sub, j);
511 FC_FREE(bonus);
512 success = FALSE;
513 continue;
515 bonus->quiet = secfile_lookup_bool_default(file, FALSE,
516 "%s.%s%d.quiet",
517 sec, sub, j);
518 combat_bonus_list_append(list, bonus);
521 return success;
524 /**************************************************************************
525 Lookup a string prefix.entry in the file and return the corresponding
526 advances pointer. If (!required), return A_NEVER for match "Never" or
527 can't match. If (required), die when can't match. Note the first tech
528 should have name "None" so that will always match.
529 If description is not NULL, it is used in the warning message
530 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
531 **************************************************************************/
532 static bool lookup_tech(struct section_file *file,
533 struct advance **result,
534 const char *prefix, const char *entry,
535 const char *filename,
536 const char *description)
538 const char *sval;
540 sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
541 if (!sval || !strcmp(sval, "Never")) {
542 *result = A_NEVER;
543 } else {
544 *result = advance_by_rule_name(sval);
546 if (A_NEVER == *result) {
547 ruleset_error(LOG_ERROR,
548 "\"%s\" %s %s: couldn't match \"%s\".",
549 filename, (description ? description : prefix), entry, sval);
550 return FALSE;
554 return TRUE;
557 /**************************************************************************
558 Lookup a string prefix.entry in the file and return the corresponding
559 improvement pointer. Return B_NEVER for match "None" or
560 can't match.
561 If description is not NULL, it is used in the warning message
562 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
563 **************************************************************************/
564 static bool lookup_building(struct section_file *file,
565 const char *prefix, const char *entry,
566 struct impr_type **result,
567 const char *filename,
568 const char *description)
570 const char *sval;
571 bool ok = TRUE;
573 sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
574 if (!sval || strcmp(sval, "None") == 0) {
575 *result = B_NEVER;
576 } else {
577 *result = improvement_by_rule_name(sval);
579 if (B_NEVER == *result) {
580 ruleset_error(LOG_ERROR,
581 "\"%s\" %s %s: couldn't match \"%s\".",
582 filename, (description ? description : prefix), entry, sval);
583 ok = FALSE;
587 return ok;
590 /**************************************************************************
591 Lookup a prefix.entry string vector in the file and fill in the
592 array, which should hold MAX_NUM_UNIT_LIST items. The output array is
593 either NULL terminated or full (contains MAX_NUM_UNIT_LIST
594 items). If the vector is not found and the required parameter is set,
595 we report it as an error, otherwise we just punt.
596 **************************************************************************/
597 static bool lookup_unit_list(struct section_file *file, const char *prefix,
598 const char *entry,
599 struct unit_type **output,
600 const char *filename)
602 const char **slist;
603 size_t nval;
604 int i;
605 bool ok = TRUE;
607 /* pre-fill with NULL: */
608 for(i = 0; i < MAX_NUM_UNIT_LIST; i++) {
609 output[i] = NULL;
611 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
612 if (nval == 0) {
613 /* 'No vector' is considered same as empty vector */
614 if (slist != NULL) {
615 free(slist);
617 return TRUE;
619 if (nval > MAX_NUM_UNIT_LIST) {
620 ruleset_error(LOG_ERROR,
621 "\"%s\": string vector %s.%s too long (%d, max %d)",
622 filename, prefix, entry, (int) nval, MAX_NUM_UNIT_LIST);
623 ok = FALSE;
624 } else if (nval == 1 && strcmp(slist[0], "") == 0) {
625 free(slist);
626 return TRUE;
628 if (ok) {
629 for (i = 0; i < nval; i++) {
630 const char *sval = slist[i];
631 struct unit_type *punittype = unit_type_by_rule_name(sval);
633 if (!punittype) {
634 ruleset_error(LOG_ERROR,
635 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
636 filename, prefix, entry, i, sval);
637 ok = FALSE;
638 break;
640 output[i] = punittype;
641 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
642 utype_number(punittype));
645 free(slist);
647 return ok;
650 /**************************************************************************
651 Lookup a prefix.entry string vector in the file and fill in the
652 array, which should hold MAX_NUM_TECH_LIST items. The output array is
653 either A_LAST terminated or full (contains MAX_NUM_TECH_LIST
654 items). All valid entries of the output array are guaranteed to
655 exist.
656 **************************************************************************/
657 static bool lookup_tech_list(struct section_file *file, const char *prefix,
658 const char *entry, int *output,
659 const char *filename)
661 const char **slist;
662 size_t nval;
663 int i;
664 bool ok = TRUE;
666 /* pre-fill with A_LAST: */
667 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
668 output[i] = A_LAST;
670 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
671 if (slist == NULL || nval == 0) {
672 return TRUE;
673 } else if (nval > MAX_NUM_TECH_LIST) {
674 ruleset_error(LOG_ERROR,
675 "\"%s\": string vector %s.%s too long (%d, max %d)",
676 filename, prefix, entry, (int) nval, MAX_NUM_TECH_LIST);
677 ok = FALSE;
680 if (ok) {
681 if (nval == 1 && strcmp(slist[0], "") == 0) {
682 FC_FREE(slist);
683 return TRUE;
685 for (i = 0; i < nval && ok; i++) {
686 const char *sval = slist[i];
687 struct advance *padvance = advance_by_rule_name(sval);
689 if (NULL == padvance) {
690 ruleset_error(LOG_ERROR,
691 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
692 filename, prefix, entry, i, sval);
693 ok = FALSE;
695 if (!valid_advance(padvance)) {
696 ruleset_error(LOG_ERROR, "\"%s\" %s.%s (%d): \"%s\" is removed.",
697 filename, prefix, entry, i, sval);
698 ok = FALSE;
701 if (ok) {
702 output[i] = advance_number(padvance);
703 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
704 advance_number(padvance));
708 FC_FREE(slist);
710 return ok;
713 /**************************************************************************
714 Lookup a prefix.entry string vector in the file and fill in the
715 array, which should hold MAX_NUM_BUILDING_LIST items. The output array is
716 either B_LAST terminated or full (contains MAX_NUM_BUILDING_LIST
717 items). [All valid entries of the output array are guaranteed to pass
718 improvement_exist()?]
719 **************************************************************************/
720 static bool lookup_building_list(struct section_file *file,
721 const char *prefix, const char *entry,
722 int *output, const char *filename)
724 const char **slist;
725 size_t nval;
726 int i;
727 bool ok = TRUE;
729 /* pre-fill with B_LAST: */
730 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
731 output[i] = B_LAST;
733 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
734 if (nval > MAX_NUM_BUILDING_LIST) {
735 ruleset_error(LOG_ERROR,
736 "\"%s\": string vector %s.%s too long (%d, max %d)",
737 filename, prefix, entry, (int) nval, MAX_NUM_BUILDING_LIST);
738 ok = FALSE;
739 } else if (nval == 0 || (nval == 1 && strcmp(slist[0], "") == 0)) {
740 if (slist != NULL) {
741 FC_FREE(slist);
743 return TRUE;
745 if (ok) {
746 for (i = 0; i < nval; i++) {
747 const char *sval = slist[i];
748 struct impr_type *pimprove = improvement_by_rule_name(sval);
750 if (NULL == pimprove) {
751 ruleset_error(LOG_ERROR,
752 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
753 filename, prefix, entry, i, sval);
754 ok = FALSE;
755 break;
757 output[i] = improvement_number(pimprove);
758 log_debug("%s.%s,%d %s %d", prefix, entry, i, sval, output[i]);
761 free(slist);
763 return ok;
766 /**************************************************************************
767 Lookup a string prefix.entry in the file and set result to the corresponding
768 unit_type.
769 If description is not NULL, it is used in the warning message
770 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
771 **************************************************************************/
772 static bool lookup_unit_type(struct section_file *file,
773 const char *prefix,
774 const char *entry,
775 struct unit_type **result,
776 const char *filename,
777 const char *description)
779 const char *sval;
781 sval = secfile_lookup_str_default(file, "None", "%s.%s", prefix, entry);
783 if (strcmp(sval, "None") == 0) {
784 *result = NULL;
785 } else {
786 *result = unit_type_by_rule_name(sval);
787 if (*result == NULL) {
788 ruleset_error(LOG_ERROR,
789 "\"%s\" %s %s: couldn't match \"%s\".",
790 filename, (description ? description : prefix), entry, sval);
792 return FALSE;
796 return TRUE;
799 /**************************************************************************
800 Lookup entry in the file and return the corresponding government index.
801 filename is for error message.
802 **************************************************************************/
803 static struct government *lookup_government(struct section_file *file,
804 const char *entry,
805 const char *filename,
806 struct government *fallback)
808 const char *sval;
809 struct government *gov;
811 sval = secfile_lookup_str_default(file, NULL, "%s", entry);
812 if (!sval) {
813 gov = fallback;
814 } else {
815 gov = government_by_rule_name(sval);
817 if (!gov) {
818 ruleset_error(LOG_ERROR,
819 "\"%s\" %s: couldn't match \"%s\".",
820 filename, entry, sval);
822 return gov;
825 /****************************************************************************
826 Lookup optional string, returning allocated memory or NULL.
827 ****************************************************************************/
828 static char *lookup_string(struct section_file *file, const char *prefix,
829 const char *suffix)
831 const char *sval = secfile_lookup_str(file, "%s.%s", prefix, suffix);
833 if (NULL != sval) {
834 char copy[strlen(sval) + 1];
836 strcpy(copy, sval);
837 remove_leading_trailing_spaces(copy);
838 if (strlen(copy) > 0) {
839 return fc_strdup(copy);
842 return NULL;
845 /****************************************************************************
846 Lookup optional string vector, returning allocated memory or NULL.
847 ****************************************************************************/
848 static struct strvec *lookup_strvec(struct section_file *file,
849 const char *prefix, const char *suffix)
851 size_t dim;
852 const char **vec = secfile_lookup_str_vec(file, &dim,
853 "%s.%s", prefix, suffix);
855 if (NULL != vec) {
856 struct strvec *dest = strvec_new();
858 strvec_store(dest, vec, dim);
859 free(vec);
860 return dest;
862 return NULL;
865 /**************************************************************************
866 Look up the resource section name and return its pointer.
867 **************************************************************************/
868 static struct resource *lookup_resource(const char *filename,
869 const char *name,
870 const char *jsection)
872 struct resource *pres;
874 pres = resource_by_rule_name(name);
876 if (pres == NULL) {
877 ruleset_error(LOG_ERROR,
878 "\"%s\" [%s] has unknown \"%s\".",
879 filename,
880 jsection,
881 name);
884 return pres;
887 /**************************************************************************
888 Look up the terrain by name and return its pointer.
889 filename is for error message.
890 **************************************************************************/
891 static bool lookup_terrain(struct section_file *file,
892 const char *entry,
893 const char *filename,
894 struct terrain *pthis,
895 struct terrain **result)
897 const int j = terrain_index(pthis);
898 const char *jsection = &terrain_sections[j * MAX_SECTION_LABEL];
899 const char *name = secfile_lookup_str(file, "%s.%s", jsection, entry);
900 struct terrain *pterr;
902 if (NULL == name
903 || *name == '\0'
904 || (0 == strcmp(name, "none"))
905 || (0 == strcmp(name, "no"))) {
906 *result = T_NONE;
908 return TRUE;
910 if (0 == strcmp(name, "yes")) {
911 *result = pthis;
913 return TRUE;
916 pterr = terrain_by_rule_name(name);
917 *result = pterr;
919 if (pterr == NULL) {
920 ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown \"%s\".",
921 secfile_name(file), jsection, name);
922 return FALSE;
925 return TRUE;
928 /**************************************************************************
929 Look up a value comparable to activity_count (road_time, etc).
930 item_name describes the thing which has the time property, if non-NULL,
931 for any error message.
932 Returns FALSE if not found in secfile, but TRUE even if validation failed.
933 Sets *ok to FALSE if validation failed, leaves it alone otherwise.
934 **************************************************************************/
935 static bool lookup_time(const struct section_file *secfile, int *turns,
936 const char *sec_name, const char *property_name,
937 const char *filename, const char *item_name,
938 bool *ok)
940 /* Assumes that PACKET_UNIT_INFO.activity_count in packets.def is UINT16 */
941 const int max_turns = 65535 / ACTIVITY_FACTOR;
943 if (!secfile_lookup_int(secfile, turns, "%s.%s", sec_name, property_name)) {
944 return FALSE;
947 if (*turns > max_turns) {
948 ruleset_error(LOG_ERROR,
949 "\"%s\": \"%s\": \"%s\" value %d too large (max %d)",
950 filename, item_name ? item_name : sec_name,
951 property_name, *turns, max_turns);
952 *ok = FALSE;
955 return TRUE; /* we found _something */
958 /**************************************************************************
959 Load "name" and (optionally) "rule_name" into a struct name_translation.
960 **************************************************************************/
961 static bool ruleset_load_names(struct name_translation *pname,
962 const char *domain,
963 struct section_file *file,
964 const char *sec_name)
966 const char *name = secfile_lookup_str(file, "%s.name", sec_name);
967 const char *rule_name = secfile_lookup_str(file, "%s.rule_name", sec_name);
969 if (!name) {
970 ruleset_error(LOG_ERROR,
971 "\"%s\" [%s]: no \"name\" specified.",
972 secfile_name(file), sec_name);
973 return FALSE;
976 names_set(pname, domain, name, rule_name);
978 return TRUE;
981 /**************************************************************************
982 Load trait values to array.
983 **************************************************************************/
984 static void ruleset_load_traits(struct trait_limits *out,
985 struct section_file *file,
986 const char *secname, const char *field_prefix)
988 enum trait tr;
990 /* FIXME: Use specenum trait names without duplicating them here.
991 * Just needs to take care of case. */
992 const char *trait_names[] = {
993 "expansionist",
994 "trader",
995 "aggressive",
996 NULL
999 for (tr = trait_begin(); tr != trait_end() && trait_names[tr] != NULL; tr = trait_next(tr)) {
1000 out[tr].min = secfile_lookup_int_default(file, -1, "%s.%s%s_min",
1001 secname,
1002 field_prefix,
1003 trait_names[tr]);
1004 out[tr].max = secfile_lookup_int_default(file, -1, "%s.%s%s_max",
1005 secname,
1006 field_prefix,
1007 trait_names[tr]);
1008 out[tr].fixed = secfile_lookup_int_default(file, -1, "%s.%s%s_default",
1009 secname,
1010 field_prefix,
1011 trait_names[tr]);
1014 fc_assert(tr == trait_end()); /* number of trait_names correct */
1017 /**************************************************************************
1018 Load names from game.ruleset so other rulesets can refer to objects
1019 with their name.
1020 **************************************************************************/
1021 static bool load_game_names(struct section_file *file)
1023 struct section_list *sec;
1024 int nval;
1025 const char *filename = secfile_name(file);
1026 bool ok = TRUE;
1028 sec = secfile_sections_by_name_prefix(file, ACHIEVEMENT_SECTION_PREFIX);
1029 nval = (NULL != sec ? section_list_size(sec) : 0);
1030 if (nval > MAX_ACHIEVEMENT_TYPES) {
1031 int num = nval; /* No "size_t" to printf */
1033 ruleset_error(LOG_ERROR, "\"%s\": Too many achievement types (%d, max %d)",
1034 filename, num, MAX_ACHIEVEMENT_TYPES);
1035 ok = FALSE;
1036 } else {
1037 game.control.num_achievement_types = nval;
1040 if (ok) {
1041 achievements_iterate(pach) {
1042 const char *sec_name = section_name(section_list_get(sec, achievement_index(pach)));
1044 if (!ruleset_load_names(&pach->name, NULL, file, sec_name)) {
1045 ruleset_error(LOG_ERROR, "\"%s\": Cannot load achievement names",
1046 filename);
1047 ok = FALSE;
1048 break;
1050 } achievements_iterate_end;
1053 section_list_destroy(sec);
1055 return ok;
1059 /**************************************************************************
1060 Load names of technologies so other rulesets can refer to techs with
1061 their name.
1062 **************************************************************************/
1063 static bool load_tech_names(struct section_file *file)
1065 struct section_list *sec = NULL;
1066 /* Number of techs in the ruleset (means without A_NONE). */
1067 int num_techs = 0;
1068 int i;
1069 const char *filename = secfile_name(file);
1070 bool ok = TRUE;
1071 const char *flag;
1073 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
1074 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
1076 /* User tech flag names */
1077 for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
1078 i++) {
1079 const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
1081 if (tech_flag_id_by_name(flag, fc_strcasecmp) != tech_flag_id_invalid()) {
1082 ruleset_error(LOG_ERROR, "\"%s\": Duplicate tech flag name '%s'",
1083 filename, flag);
1084 ok = FALSE;
1085 break;
1087 if (i > MAX_NUM_USER_TECH_FLAGS) {
1088 ruleset_error(LOG_ERROR, "\"%s\": Too many user tech flags!",
1089 filename);
1090 ok = FALSE;
1091 break;
1094 set_user_tech_flag_name(TECH_USER_1 + i, flag, helptxt);
1097 if (ok) {
1098 for (; i < MAX_NUM_USER_TECH_FLAGS; i++) {
1099 set_user_tech_flag_name(TECH_USER_1 + i, NULL, NULL);
1102 /* The techs: */
1103 sec = secfile_sections_by_name_prefix(file, ADVANCE_SECTION_PREFIX);
1104 if (NULL == sec || 0 == (num_techs = section_list_size(sec))) {
1105 ruleset_error(LOG_ERROR, "\"%s\": No Advances?!?", filename);
1106 ok = FALSE;
1107 } else {
1108 log_verbose("%d advances (including possibly unused)", num_techs);
1109 if (num_techs + A_FIRST > A_LAST) {
1110 ruleset_error(LOG_ERROR, "\"%s\": Too many advances (%d, max %d)",
1111 filename, num_techs, A_LAST - A_FIRST);
1112 ok = FALSE;
1117 if (ok) {
1118 game.control.num_tech_types = num_techs + A_FIRST; /* includes A_NONE */
1120 i = 0;
1121 advance_iterate(A_FIRST, a) {
1122 if (!ruleset_load_names(&a->name, NULL, file, section_name(section_list_get(sec, i)))) {
1123 ok = FALSE;
1124 break;
1126 i++;
1127 } advance_iterate_end;
1129 section_list_destroy(sec);
1131 return ok;
1134 /**************************************************************************
1135 Load technologies related ruleset data
1136 **************************************************************************/
1137 static bool load_ruleset_techs(struct section_file *file)
1139 struct section_list *sec;
1140 int i;
1141 struct advance *a_none = advance_by_number(A_NONE);
1142 const char *filename = secfile_name(file);
1143 bool ok = TRUE;
1145 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
1146 return FALSE;
1148 sec = secfile_sections_by_name_prefix(file, ADVANCE_SECTION_PREFIX);
1150 i = 0;
1151 advance_iterate(A_FIRST, a) {
1152 const char *sec_name = section_name(section_list_get(sec, i));
1153 const char *sval, **slist;
1154 size_t nval;
1155 int j, ival;
1157 if (!lookup_tech(file, &a->require[AR_ONE], sec_name, "req1",
1158 filename, rule_name_get(&a->name))
1159 || !lookup_tech(file, &a->require[AR_TWO], sec_name, "req2",
1160 filename, rule_name_get(&a->name))
1161 || !lookup_tech(file, &a->require[AR_ROOT], sec_name, "root_req",
1162 filename, rule_name_get(&a->name))) {
1163 ok = FALSE;
1164 break;
1167 if ((A_NEVER == a->require[AR_ONE] && A_NEVER != a->require[AR_TWO])
1168 || (A_NEVER != a->require[AR_ONE] && A_NEVER == a->require[AR_TWO])) {
1169 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": \"Never\" with non-\"Never\".",
1170 filename, sec_name, rule_name_get(&a->name));
1171 ok = FALSE;
1172 break;
1174 if (a_none == a->require[AR_ONE] && a_none != a->require[AR_TWO]) {
1175 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": should have \"None\" second.",
1176 filename, sec_name, rule_name_get(&a->name));
1177 ok = FALSE;
1178 break;
1181 BV_CLR_ALL(a->flags);
1183 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1184 for (j = 0; j < nval; j++) {
1185 sval = slist[j];
1186 if (strcmp(sval, "") == 0) {
1187 continue;
1189 ival = tech_flag_id_by_name(sval, fc_strcasecmp);
1190 if (!tech_flag_id_is_valid(ival)) {
1191 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": bad flag name \"%s\".",
1192 filename, sec_name, rule_name_get(&a->name), sval);
1193 ok = FALSE;
1194 break;
1195 } else {
1196 BV_SET(a->flags, ival);
1199 free(slist);
1201 if (!ok) {
1202 break;
1205 sz_strlcpy(a->graphic_str,
1206 secfile_lookup_str_default(file, "-", "%s.graphic", sec_name));
1207 sz_strlcpy(a->graphic_alt,
1208 secfile_lookup_str_default(file, "-",
1209 "%s.graphic_alt", sec_name));
1211 a->helptext = lookup_strvec(file, sec_name, "helptext");
1212 a->bonus_message = lookup_string(file, sec_name, "bonus_message");
1213 a->cost = secfile_lookup_int_default(file, -1, "%s.%s",
1214 sec_name, "cost");
1215 a->num_reqs = 0;
1217 i++;
1218 } advance_iterate_end;
1220 /* Propagate a root tech up into the tech tree. Thus if a technology
1221 * X has Y has a root tech, then any technology requiring X also has
1222 * Y as a root tech. */
1223 restart:
1225 if (ok) {
1226 advance_iterate(A_FIRST, a) {
1227 if (valid_advance(a)
1228 && A_NEVER != a->require[AR_ROOT]) {
1229 bool out_of_order = FALSE;
1231 /* Now find any tech depending on this technology and update its
1232 * root_req. */
1233 advance_iterate(A_FIRST, b) {
1234 if (valid_advance(b)
1235 && A_NEVER == b->require[AR_ROOT]
1236 && (a == b->require[AR_ONE] || a == b->require[AR_TWO])) {
1237 b->require[AR_ROOT] = a->require[AR_ROOT];
1238 if (b < a) {
1239 out_of_order = TRUE;
1242 } advance_iterate_end;
1244 if (out_of_order) {
1245 /* HACK: If we just changed the root_tech of a lower-numbered
1246 * technology, we need to go back so that we can propagate the
1247 * root_tech up to that technology's parents... */
1248 goto restart;
1251 } advance_iterate_end;
1253 /* Now rename A_NEVER to A_NONE for consistency */
1254 advance_iterate(A_NONE, a) {
1255 if (A_NEVER == a->require[AR_ROOT]) {
1256 a->require[AR_ROOT] = a_none;
1258 } advance_iterate_end;
1260 /* Some more consistency checking:
1261 Non-removed techs depending on removed techs is too
1262 broken to fix by default, so die.
1264 advance_iterate(A_FIRST, a) {
1265 if (valid_advance(a)) {
1266 /* We check for recursive tech loops later,
1267 * in build_required_techs_helper. */
1268 if (!valid_advance(a->require[AR_ONE])) {
1269 ruleset_error(LOG_ERROR,
1270 "\"%s\" tech \"%s\": req1 leads to removed tech.",
1271 filename,
1272 advance_rule_name(a));
1273 ok = FALSE;
1274 break;
1276 if (!valid_advance(a->require[AR_TWO])) {
1277 ruleset_error(LOG_ERROR,
1278 "\"%s\" tech \"%s\": req2 leads to removed tech.",
1279 filename,
1280 advance_rule_name(a));
1281 ok = FALSE;
1282 break;
1285 } advance_iterate_end;
1288 section_list_destroy(sec);
1289 if (ok) {
1290 secfile_check_unused(file);
1293 return ok;
1296 /**************************************************************************
1297 Load names of units so other rulesets can refer to units with
1298 their name.
1299 **************************************************************************/
1300 static bool load_unit_names(struct section_file *file)
1302 struct section_list *sec = NULL;
1303 int nval = 0;
1304 int i;
1305 const char *filename = secfile_name(file);
1306 const char *flag;
1307 bool ok = TRUE;
1309 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
1310 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
1312 /* User unit flag names */
1313 for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
1314 i++) {
1315 const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
1318 if (unit_type_flag_id_by_name(flag, fc_strcasecmp)
1319 != unit_type_flag_id_invalid()) {
1320 ruleset_error(LOG_ERROR, "\"%s\": Duplicate unit flag name '%s'",
1321 filename, flag);
1322 ok = FALSE;
1323 break;
1325 if (i > MAX_NUM_USER_UNIT_FLAGS) {
1326 ruleset_error(LOG_ERROR, "\"%s\": Too many user unit type flags!",
1327 filename);
1328 ok = FALSE;
1329 break;
1332 set_user_unit_type_flag_name(UTYF_USER_FLAG_1 + i, flag, helptxt);
1335 if (ok) {
1336 for (; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
1337 set_user_unit_type_flag_name(UTYF_USER_FLAG_1 + i, NULL, NULL);
1340 /* Unit classes */
1341 sec = secfile_sections_by_name_prefix(file, UNIT_CLASS_SECTION_PREFIX);
1342 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
1343 ruleset_error(LOG_ERROR, "\"%s\": No unit classes?!?", filename);
1344 ok = FALSE;
1345 } else {
1346 log_verbose("%d unit classes", nval);
1347 if (nval > UCL_LAST) {
1348 ruleset_error(LOG_ERROR, "\"%s\": Too many unit classes (%d, max %d)",
1349 filename, nval, UCL_LAST);
1350 ok = FALSE;
1355 if (ok) {
1356 game.control.num_unit_classes = nval;
1358 unit_class_iterate(punitclass) {
1359 const int pci = uclass_index(punitclass);
1361 if (!ruleset_load_names(&punitclass->name, NULL, file,
1362 section_name(section_list_get(sec, pci)))) {
1363 ok = FALSE;
1364 break;
1366 } unit_class_iterate_end;
1368 section_list_destroy(sec);
1369 sec = NULL;
1371 /* The names: */
1372 if (ok) {
1373 sec = secfile_sections_by_name_prefix(file, UNIT_SECTION_PREFIX);
1374 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
1375 ruleset_error(LOG_ERROR, "\"%s\": No unit types?!?", filename);
1376 ok = FALSE;
1377 } else {
1378 log_verbose("%d unit types (including possibly unused)", nval);
1379 if (nval > U_LAST) {
1380 ruleset_error(LOG_ERROR, "\"%s\": Too many unit types (%d, max %d)",
1381 filename, nval, U_LAST);
1382 ok = FALSE;
1387 if (ok) {
1388 game.control.num_unit_types = nval;
1390 unit_type_iterate(punittype) {
1391 const int utypei = utype_index(punittype);
1392 if (!ruleset_load_names(&punittype->name, NULL, file,
1393 section_name(section_list_get(sec, utypei)))) {
1394 ok = FALSE;
1395 break;
1397 } unit_type_iterate_end;
1399 section_list_destroy(sec);
1401 return ok;
1404 /**************************************************************************
1405 Load veteran levels.
1406 **************************************************************************/
1407 static bool load_ruleset_veteran(struct section_file *file,
1408 const char *path,
1409 struct veteran_system **vsystem, char *err,
1410 size_t err_len)
1412 const char **vlist_name;
1413 int *vlist_power, *vlist_raise, *vlist_wraise, *vlist_move;
1414 size_t count_name, count_power, count_raise, count_wraise, count_move;
1415 int i;
1416 bool ret = TRUE;
1418 /* The pointer should be uninitialised. */
1419 if (*vsystem != NULL) {
1420 fc_snprintf(err, err_len, "Veteran system is defined?!");
1421 return FALSE;
1424 /* Load data. */
1425 vlist_name = secfile_lookup_str_vec(file, &count_name,
1426 "%s.veteran_names", path);
1427 vlist_power = secfile_lookup_int_vec(file, &count_power,
1428 "%s.veteran_power_fact", path);
1429 vlist_raise = secfile_lookup_int_vec(file, &count_raise,
1430 "%s.veteran_raise_chance", path);
1431 vlist_wraise = secfile_lookup_int_vec(file, &count_wraise,
1432 "%s.veteran_work_raise_chance",
1433 path);
1434 vlist_move = secfile_lookup_int_vec(file, &count_move,
1435 "%s.veteran_move_bonus", path);
1437 if (count_name > MAX_VET_LEVELS) {
1438 ret = FALSE;
1439 fc_snprintf(err, err_len, "\"%s\": Too many veteran levels (section "
1440 "'%s': %lu, max %d)", secfile_name(file), path,
1441 (long unsigned)count_name, MAX_VET_LEVELS);
1442 } else if (count_name != count_power
1443 || count_name != count_raise
1444 || count_name != count_wraise
1445 || count_name != count_move) {
1446 ret = FALSE;
1447 fc_snprintf(err, err_len, "\"%s\": Different lengths for the veteran "
1448 "settings in section '%s'", secfile_name(file),
1449 path);
1450 } else if (count_name == 0) {
1451 /* Nothing defined. */
1452 *vsystem = NULL;
1453 } else {
1454 /* Generate the veteran system. */
1455 *vsystem = veteran_system_new((int)count_name);
1457 #define rs_sanity_veteran(_path, _entry, _i, _condition, _action) \
1458 if (_condition) { \
1459 log_error("Invalid veteran definition '%s.%s[%d]'!", \
1460 _path, _entry, _i); \
1461 log_debug("Failed check: '%s'. Update value: '%s'.", \
1462 #_condition, #_action); \
1463 _action; \
1465 for (i = 0; i < count_name; i++) {
1466 /* Some sanity checks. */
1467 rs_sanity_veteran(path, "veteran_power_fact", i,
1468 (vlist_power[i] < 0), vlist_power[i] = 0);
1469 rs_sanity_veteran(path, "veteran_raise_chance", i,
1470 (vlist_raise[i] < 0), vlist_raise[i] = 0);
1471 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1472 (vlist_wraise[i] < 0), vlist_wraise[i] = 0);
1473 rs_sanity_veteran(path, "veteran_move_bonus", i,
1474 (vlist_move[i] < 0), vlist_move[i] = 0);
1475 if (i == 0) {
1476 /* First element.*/
1477 rs_sanity_veteran(path, "veteran_power_fact", i,
1478 (vlist_power[i] != 100), vlist_power[i] = 100);
1479 } else if (i == count_name - 1) {
1480 /* Last element. */
1481 rs_sanity_veteran(path, "veteran_power_fact", i,
1482 (vlist_power[i] < vlist_power[i - 1]),
1483 vlist_power[i] = vlist_power[i - 1]);
1484 rs_sanity_veteran(path, "veteran_raise_chance", i,
1485 (vlist_raise[i] != 0), vlist_raise[i] = 0);
1486 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1487 (vlist_wraise[i] != 0), vlist_wraise[i] = 0);
1488 } else {
1489 /* All elements inbetween. */
1490 rs_sanity_veteran(path, "veteran_power_fact", i,
1491 (vlist_power[i] < vlist_power[i - 1]),
1492 vlist_power[i] = vlist_power[i - 1]);
1493 rs_sanity_veteran(path, "veteran_raise_chance", i,
1494 (vlist_raise[i] > 100), vlist_raise[i] = 100);
1495 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1496 (vlist_wraise[i] > 100), vlist_wraise[i] = 100);
1499 veteran_system_definition(*vsystem, i, vlist_name[i], vlist_power[i],
1500 vlist_move[i], vlist_raise[i],
1501 vlist_wraise[i]);
1503 #undef rs_sanity_veteran
1506 if (vlist_name) {
1507 free(vlist_name);
1509 if (vlist_power) {
1510 free(vlist_power);
1512 if (vlist_raise) {
1513 free(vlist_raise);
1515 if (vlist_wraise) {
1516 free(vlist_wraise);
1518 if (vlist_move) {
1519 free(vlist_move);
1522 return ret;
1525 /**************************************************************************
1526 Load units related ruleset data.
1527 **************************************************************************/
1528 static bool load_ruleset_units(struct section_file *file)
1530 int j, ival;
1531 size_t nval;
1532 struct section_list *sec, *csec;
1533 const char *sval, **slist;
1534 const char *filename = secfile_name(file);
1535 char msg[MAX_LEN_MSG];
1536 bool ok = TRUE;
1538 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
1539 return FALSE;
1542 if (!load_ruleset_veteran(file, "veteran_system", &game.veteran, msg,
1543 sizeof(msg)) || game.veteran == NULL) {
1544 ruleset_error(LOG_ERROR, "Error loading the default veteran system: %s",
1545 msg);
1546 ok = FALSE;
1549 sec = secfile_sections_by_name_prefix(file, UNIT_SECTION_PREFIX);
1550 nval = (NULL != sec ? section_list_size(sec) : 0);
1552 csec = secfile_sections_by_name_prefix(file, UNIT_CLASS_SECTION_PREFIX);
1553 nval = (NULL != csec ? section_list_size(csec) : 0);
1555 if (ok) {
1556 unit_class_iterate(uc) {
1557 int i = uclass_index(uc);
1558 const char *hut_str;
1559 const char *sec_name = section_name(section_list_get(csec, i));
1561 if (secfile_lookup_int(file, &uc->min_speed, "%s.min_speed", sec_name)) {
1562 uc->min_speed *= SINGLE_MOVE;
1563 } else {
1564 ruleset_error(LOG_ERROR, "%s", secfile_error());
1565 ok = FALSE;
1566 break;
1568 if (!secfile_lookup_int(file, &uc->hp_loss_pct,
1569 "%s.hp_loss_pct", sec_name)) {
1570 ruleset_error(LOG_ERROR, "%s", secfile_error());
1571 ok = FALSE;
1572 break;
1575 uc->non_native_def_pct = secfile_lookup_int_default(file, 100,
1576 "%s.non_native_def_pct",
1577 sec_name);
1579 hut_str = secfile_lookup_str_default(file, "Normal", "%s.hut_behavior", sec_name);
1580 if (fc_strcasecmp(hut_str, "Normal") == 0) {
1581 uc->hut_behavior = HUT_NORMAL;
1582 } else if (fc_strcasecmp(hut_str, "Nothing") == 0) {
1583 uc->hut_behavior = HUT_NOTHING;
1584 } else if (fc_strcasecmp(hut_str, "Frighten") == 0) {
1585 uc->hut_behavior = HUT_FRIGHTEN;
1586 } else {
1587 ruleset_error(LOG_ERROR,
1588 "\"%s\" unit_class \"%s\":"
1589 " Illegal hut behavior \"%s\".",
1590 filename,
1591 uclass_rule_name(uc),
1592 hut_str);
1593 ok = FALSE;
1594 break;
1597 BV_CLR_ALL(uc->flags);
1598 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1599 for(j = 0; j < nval; j++) {
1600 sval = slist[j];
1601 if(strcmp(sval,"") == 0) {
1602 continue;
1604 ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
1605 if (!unit_class_flag_id_is_valid(ival)) {
1606 ok = FALSE;
1607 ival = unit_type_flag_id_by_name(sval, fc_strcasecmp);
1608 if (unit_type_flag_id_is_valid(ival)) {
1609 ruleset_error(LOG_ERROR,
1610 "\"%s\" unit_class \"%s\": unit_type flag \"%s\"!",
1611 filename, uclass_rule_name(uc), sval);
1612 } else {
1613 ruleset_error(LOG_ERROR,
1614 "\"%s\" unit_class \"%s\": bad flag name \"%s\".",
1615 filename, uclass_rule_name(uc), sval);
1617 break;
1618 } else {
1619 BV_SET(uc->flags, ival);
1622 free(slist);
1624 uc->helptext = lookup_strvec(file, sec_name, "helptext");
1626 if (!ok) {
1627 break;
1629 } unit_class_iterate_end;
1632 if (ok) {
1633 /* Tech and Gov requirements; per unit veteran system */
1634 unit_type_iterate(u) {
1635 const int i = utype_index(u);
1636 const struct section *psection = section_list_get(sec, i);
1637 const char *sec_name = section_name(psection);
1639 if (!lookup_tech(file, &u->require_advance, sec_name,
1640 "tech_req", filename,
1641 rule_name_get(&u->name))) {
1642 ok = FALSE;
1643 break;
1645 if (NULL != section_entry_by_name(psection, "gov_req")) {
1646 char tmp[200] = "\0";
1647 fc_strlcat(tmp, section_name(psection), sizeof(tmp));
1648 fc_strlcat(tmp, ".gov_req", sizeof(tmp));
1649 u->need_government = lookup_government(file, tmp, filename, NULL);
1650 if (u->need_government == NULL) {
1651 ok = FALSE;
1652 break;
1654 } else {
1655 u->need_government = NULL; /* no requirement */
1658 if (!load_ruleset_veteran(file, sec_name, &u->veteran,
1659 msg, sizeof(msg))) {
1660 ruleset_error(LOG_ERROR, "Error loading the veteran system: %s",
1661 msg);
1662 ok = FALSE;
1663 break;
1666 if (!lookup_unit_type(file, sec_name, "obsolete_by",
1667 &u->obsoleted_by, filename,
1668 rule_name_get(&u->name))
1669 || !lookup_unit_type(file, sec_name, "convert_to",
1670 &u->converted_to, filename,
1671 rule_name_get(&u->name))) {
1672 ok = FALSE;
1673 break;
1675 u->convert_time = 1; /* default */
1676 lookup_time(file, &u->convert_time, sec_name, "convert_time",
1677 filename, rule_name_get(&u->name), &ok);
1678 } unit_type_iterate_end;
1681 if (ok) {
1682 /* main stats: */
1683 unit_type_iterate(u) {
1684 const int i = utype_index(u);
1685 struct unit_class *pclass;
1686 const char *sec_name = section_name(section_list_get(sec, i));
1687 const char *string;
1689 if (!lookup_building(file, sec_name, "impr_req",
1690 &u->need_improvement, filename,
1691 rule_name_get(&u->name))) {
1692 ok = FALSE;
1693 break;
1696 sval = secfile_lookup_str(file, "%s.class", sec_name);
1697 pclass = unit_class_by_rule_name(sval);
1698 if (!pclass) {
1699 ruleset_error(LOG_ERROR,
1700 "\"%s\" unit_type \"%s\":"
1701 " bad class \"%s\".",
1702 filename,
1703 utype_rule_name(u),
1704 sval);
1705 ok = FALSE;
1706 break;
1708 u->uclass = pclass;
1710 sz_strlcpy(u->sound_move,
1711 secfile_lookup_str_default(file, "-", "%s.sound_move",
1712 sec_name));
1713 sz_strlcpy(u->sound_move_alt,
1714 secfile_lookup_str_default(file, "-", "%s.sound_move_alt",
1715 sec_name));
1716 sz_strlcpy(u->sound_fight,
1717 secfile_lookup_str_default(file, "-", "%s.sound_fight",
1718 sec_name));
1719 sz_strlcpy(u->sound_fight_alt,
1720 secfile_lookup_str_default(file, "-", "%s.sound_fight_alt",
1721 sec_name));
1723 if ((string = secfile_lookup_str(file, "%s.graphic", sec_name))) {
1724 sz_strlcpy(u->graphic_str, string);
1725 } else {
1726 ruleset_error(LOG_ERROR, "%s", secfile_error());
1727 ok = FALSE;
1728 break;
1730 sz_strlcpy(u->graphic_alt,
1731 secfile_lookup_str_default(file, "-", "%s.graphic_alt",
1732 sec_name));
1734 if (!secfile_lookup_int(file, &u->build_cost,
1735 "%s.build_cost", sec_name)
1736 || !secfile_lookup_int(file, &u->pop_cost,
1737 "%s.pop_cost", sec_name)
1738 || !secfile_lookup_int(file, &u->attack_strength,
1739 "%s.attack", sec_name)
1740 || !secfile_lookup_int(file, &u->defense_strength,
1741 "%s.defense", sec_name)
1742 || !secfile_lookup_int(file, &u->move_rate,
1743 "%s.move_rate", sec_name)
1744 || !secfile_lookup_int(file, &u->vision_radius_sq,
1745 "%s.vision_radius_sq", sec_name)
1746 || !secfile_lookup_int(file, &u->transport_capacity,
1747 "%s.transport_cap", sec_name)
1748 || !secfile_lookup_int(file, &u->hp,
1749 "%s.hitpoints", sec_name)
1750 || !secfile_lookup_int(file, &u->firepower,
1751 "%s.firepower", sec_name)
1752 || !secfile_lookup_int(file, &u->fuel,
1753 "%s.fuel", sec_name)
1754 || !secfile_lookup_int(file, &u->happy_cost,
1755 "%s.uk_happy", sec_name)) {
1756 ruleset_error(LOG_ERROR, "%s", secfile_error());
1757 ok = FALSE;
1758 break;
1760 u->move_rate *= SINGLE_MOVE;
1762 if (u->firepower <= 0) {
1763 ruleset_error(LOG_ERROR,
1764 "\"%s\" unit_type \"%s\":"
1765 " firepower is %d,"
1766 " but must be at least 1. "
1767 " If you want no attack ability,"
1768 " set the unit's attack strength to 0.",
1769 filename,
1770 utype_rule_name(u),
1771 u->firepower);
1772 ok = FALSE;
1773 break;
1776 lookup_cbonus_list(u->bonuses, file, sec_name, "bonuses");
1778 output_type_iterate(o) {
1779 u->upkeep[o] = secfile_lookup_int_default(file, 0, "%s.uk_%s",
1780 sec_name,
1781 get_output_identifier(o));
1782 } output_type_iterate_end;
1784 slist = secfile_lookup_str_vec(file, &nval, "%s.cargo", sec_name);
1785 BV_CLR_ALL(u->cargo);
1786 for (j = 0; j < nval; j++) {
1787 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1789 if (!uclass) {
1790 ruleset_error(LOG_ERROR,
1791 "\"%s\" unit_type \"%s\":"
1792 "has unknown unit class %s as cargo.",
1793 filename,
1794 utype_rule_name(u),
1795 slist[j]);
1796 ok = FALSE;
1797 break;
1800 BV_SET(u->cargo, uclass_index(uclass));
1802 free(slist);
1804 if (!ok) {
1805 break;
1808 slist = secfile_lookup_str_vec(file, &nval, "%s.targets", sec_name);
1809 BV_CLR_ALL(u->targets);
1810 for (j = 0; j < nval; j++) {
1811 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1813 if (!uclass) {
1814 ruleset_error(LOG_ERROR,
1815 "\"%s\" unit_type \"%s\":"
1816 "has unknown unit class %s as target.",
1817 filename,
1818 utype_rule_name(u),
1819 slist[j]);
1820 ok = FALSE;
1821 break;
1824 BV_SET(u->targets, uclass_index(uclass));
1826 free(slist);
1828 if (!ok) {
1829 break;
1832 slist = secfile_lookup_str_vec(file, &nval, "%s.embarks", sec_name);
1833 BV_CLR_ALL(u->embarks);
1834 for (j = 0; j < nval; j++) {
1835 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1837 if (!uclass) {
1838 ruleset_error(LOG_ERROR,
1839 "\"%s\" unit_type \"%s\":"
1840 "has unknown unit class %s as embarkable.",
1841 filename,
1842 utype_rule_name(u),
1843 slist[j]);
1844 ok = FALSE;
1845 break;
1848 BV_SET(u->embarks, uclass_index(uclass));
1850 free(slist);
1852 if (!ok) {
1853 break;
1856 slist = secfile_lookup_str_vec(file, &nval, "%s.disembarks", sec_name);
1857 BV_CLR_ALL(u->disembarks);
1858 for (j = 0; j < nval; j++) {
1859 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1861 if (!uclass) {
1862 ruleset_error(LOG_ERROR,
1863 "\"%s\" unit_type \"%s\":"
1864 "has unknown unit class %s as disembarkable.",
1865 filename,
1866 utype_rule_name(u),
1867 slist[j]);
1868 ok = FALSE;
1869 break;
1872 BV_SET(u->disembarks, uclass_index(uclass));
1874 free(slist);
1876 if (!ok) {
1877 break;
1880 /* Set also all classes that are never unreachable as targets,
1881 * embarks, and disembarks. */
1882 unit_class_iterate(preachable) {
1883 if (!uclass_has_flag(preachable, UCF_UNREACHABLE)) {
1884 BV_SET(u->targets, uclass_index(preachable));
1885 BV_SET(u->embarks, uclass_index(preachable));
1886 BV_SET(u->disembarks, uclass_index(preachable));
1888 } unit_class_iterate_end;
1890 u->helptext = lookup_strvec(file, sec_name, "helptext");
1892 u->paratroopers_range = secfile_lookup_int_default(file,
1893 0, "%s.paratroopers_range", sec_name);
1894 u->paratroopers_mr_req = SINGLE_MOVE * secfile_lookup_int_default(file,
1895 0, "%s.paratroopers_mr_req", sec_name);
1896 u->paratroopers_mr_sub = SINGLE_MOVE * secfile_lookup_int_default(file,
1897 0, "%s.paratroopers_mr_sub", sec_name);
1898 u->bombard_rate = secfile_lookup_int_default(file,
1899 0, "%s.bombard_rate", sec_name);
1900 u->city_size = secfile_lookup_int_default(file,
1901 1, "%s.city_size", sec_name);
1902 } unit_type_iterate_end;
1905 if (ok) {
1906 /* flags */
1907 unit_type_iterate(u) {
1908 const int i = utype_index(u);
1910 BV_CLR_ALL(u->flags);
1911 fc_assert(!utype_has_flag(u, UTYF_LAST_USER_FLAG - 1));
1913 slist = secfile_lookup_str_vec(file, &nval, "%s.flags",
1914 section_name(section_list_get(sec, i)));
1915 for(j = 0; j < nval; j++) {
1916 sval = slist[j];
1917 if (0 == strcmp(sval, "")) {
1918 continue;
1920 ival = unit_type_flag_id_by_name(sval, fc_strcasecmp);
1921 if (!unit_type_flag_id_is_valid(ival)) {
1922 ok = FALSE;
1923 ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
1924 if (unit_class_flag_id_is_valid(ival)) {
1925 ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": unit_class flag!",
1926 filename, utype_rule_name(u));
1927 } else {
1928 ruleset_error(LOG_ERROR,
1929 "\"%s\" unit_type \"%s\": bad flag name \"%s\".",
1930 filename, utype_rule_name(u), sval);
1932 break;
1933 } else {
1934 BV_SET(u->flags, ival);
1936 fc_assert(utype_has_flag(u, ival));
1938 free(slist);
1940 if (!ok) {
1941 break;
1943 } unit_type_iterate_end;
1946 /* roles */
1947 if (ok) {
1948 unit_type_iterate(u) {
1949 const int i = utype_index(u);
1951 BV_CLR_ALL(u->roles);
1953 slist = secfile_lookup_str_vec(file, &nval, "%s.roles",
1954 section_name(section_list_get(sec, i)));
1955 for (j = 0; j < nval; j++) {
1956 sval = slist[j];
1957 if (strcmp(sval, "") == 0) {
1958 continue;
1960 ival = unit_role_id_by_name(sval, fc_strcasecmp);
1961 if (!unit_role_id_is_valid(ival)) {
1962 ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": bad role name \"%s\".",
1963 filename, utype_rule_name(u), sval);
1964 ok = FALSE;
1965 break;
1966 } else {
1967 BV_SET(u->roles, ival - L_FIRST);
1969 fc_assert(utype_has_role(u, ival));
1971 free(slist);
1972 } unit_type_iterate_end;
1975 if (ok) {
1976 /* Some more consistency checking: */
1977 unit_type_iterate(u) {
1978 if (!valid_advance(u->require_advance)) {
1979 ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": depends on removed tech \"%s\".",
1980 filename, utype_rule_name(u),
1981 advance_rule_name(u->require_advance));
1982 u->require_advance = A_NEVER;
1983 ok = FALSE;
1984 break;
1987 if (utype_has_flag(u, UTYF_SETTLERS)
1988 && u->city_size <= 0) {
1989 ruleset_error(LOG_ERROR, "\"%s\": Unit %s would build size %d cities",
1990 filename, utype_rule_name(u), u->city_size);
1991 u->city_size = 1;
1992 ok = FALSE;
1993 break;
1995 } unit_type_iterate_end;
1998 section_list_destroy(csec);
1999 section_list_destroy(sec);
2001 if (ok) {
2002 secfile_check_unused(file);
2005 return ok;
2008 /**************************************************************************
2009 Load names of buildings so other rulesets can refer to buildings with
2010 their name.
2011 **************************************************************************/
2012 static bool load_building_names(struct section_file *file)
2014 struct section_list *sec;
2015 int i, nval = 0;
2016 const char *filename = secfile_name(file);
2017 bool ok = TRUE;
2019 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
2020 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
2022 /* The names: */
2023 sec = secfile_sections_by_name_prefix(file, BUILDING_SECTION_PREFIX);
2024 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
2025 ruleset_error(LOG_ERROR, "\"%s\": No improvements?!?", filename);
2026 ok = FALSE;
2027 } else {
2028 log_verbose("%d improvement types (including possibly unused)", nval);
2029 if (nval > B_LAST) {
2030 ruleset_error(LOG_ERROR, "\"%s\": Too many improvements (%d, max %d)",
2031 filename, nval, B_LAST);
2032 ok = FALSE;
2036 if (ok) {
2037 game.control.num_impr_types = nval;
2039 for (i = 0; i < nval; i++) {
2040 struct impr_type *b = improvement_by_number(i);
2042 if (!ruleset_load_names(&b->name, NULL, file, section_name(section_list_get(sec, i)))) {
2043 ok = FALSE;
2044 break;
2049 section_list_destroy(sec);
2051 return ok;
2054 /**************************************************************************
2055 Load buildings related ruleset data
2056 **************************************************************************/
2057 static bool load_ruleset_buildings(struct section_file *file)
2059 struct section_list *sec;
2060 const char *item;
2061 int i, nval;
2062 const char *filename = secfile_name(file);
2063 bool ok = TRUE;
2065 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
2066 return FALSE;
2069 sec = secfile_sections_by_name_prefix(file, BUILDING_SECTION_PREFIX);
2070 nval = (NULL != sec ? section_list_size(sec) : 0);
2072 for (i = 0; i < nval && ok; i++) {
2073 struct impr_type *b = improvement_by_number(i);
2074 const char *sec_name = section_name(section_list_get(sec, i));
2075 struct requirement_vector *reqs =
2076 lookup_req_list(file, sec_name, "reqs",
2077 improvement_rule_name(b));
2079 if (reqs == NULL) {
2080 ok = FALSE;
2081 break;
2082 } else {
2083 const char *sval, **slist;
2084 int j, ival;
2085 size_t nflags;
2087 item = secfile_lookup_str(file, "%s.genus", sec_name);
2088 b->genus = impr_genus_id_by_name(item, fc_strcasecmp);
2089 if (!impr_genus_id_is_valid(b->genus)) {
2090 ruleset_error(LOG_ERROR, "\"%s\" improvement \"%s\": couldn't match "
2091 "genus \"%s\".", filename,
2092 improvement_rule_name(b), item);
2093 ok = FALSE;
2094 break;
2097 slist = secfile_lookup_str_vec(file, &nflags, "%s.flags", sec_name);
2098 BV_CLR_ALL(b->flags);
2100 for (j = 0; j < nflags; j++) {
2101 sval = slist[j];
2102 if (strcmp(sval,"") == 0) {
2103 continue;
2105 ival = impr_flag_id_by_name(sval, fc_strcasecmp);
2106 if (!impr_flag_id_is_valid(ival)) {
2107 ruleset_error(LOG_ERROR,
2108 "\"%s\" improvement \"%s\": bad flag name \"%s\".",
2109 filename, improvement_rule_name(b), sval);
2110 ok = FALSE;
2111 break;
2112 } else {
2113 BV_SET(b->flags, ival);
2116 free(slist);
2118 if (!ok) {
2119 break;
2122 requirement_vector_copy(&b->reqs, reqs);
2125 struct requirement_vector *obs_reqs =
2126 lookup_req_list(file, sec_name, "obsolete_by",
2127 improvement_rule_name(b));
2129 if (obs_reqs == NULL) {
2130 ok = FALSE;
2131 break;
2132 } else {
2133 requirement_vector_copy(&b->obsolete_by, obs_reqs);
2137 if (!secfile_lookup_int(file, &b->build_cost,
2138 "%s.build_cost", sec_name)
2139 || !secfile_lookup_int(file, &b->upkeep,
2140 "%s.upkeep", sec_name)
2141 || !secfile_lookup_int(file, &b->sabotage,
2142 "%s.sabotage", sec_name)) {
2143 ruleset_error(LOG_ERROR, "%s", secfile_error());
2144 ok = FALSE;
2145 break;
2148 sz_strlcpy(b->graphic_str,
2149 secfile_lookup_str_default(file, "-",
2150 "%s.graphic", sec_name));
2151 sz_strlcpy(b->graphic_alt,
2152 secfile_lookup_str_default(file, "-",
2153 "%s.graphic_alt", sec_name));
2155 sz_strlcpy(b->soundtag,
2156 secfile_lookup_str_default(file, "-",
2157 "%s.sound", sec_name));
2158 sz_strlcpy(b->soundtag_alt,
2159 secfile_lookup_str_default(file, "-",
2160 "%s.sound_alt", sec_name));
2161 b->helptext = lookup_strvec(file, sec_name, "helptext");
2165 section_list_destroy(sec);
2166 if (ok) {
2167 secfile_check_unused(file);
2170 return ok;
2173 /**************************************************************************
2174 Load names of terrain types so other rulesets can refer to terrains with
2175 their name.
2176 **************************************************************************/
2177 static bool load_terrain_names(struct section_file *file)
2179 int nval = 0;
2180 struct section_list *sec = NULL;
2181 const char *flag;
2182 int i;
2183 const char *filename = secfile_name(file);
2184 bool ok = TRUE;
2186 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
2187 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
2189 /* User terrain flag names */
2190 for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
2191 i++) {
2192 const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
2195 if (terrain_flag_id_by_name(flag, fc_strcasecmp)
2196 != terrain_flag_id_invalid()) {
2197 ruleset_error(LOG_ERROR, "\"%s\": Duplicate terrain flag name '%s'",
2198 filename, flag);
2199 ok = FALSE;
2200 break;
2202 if (i > MAX_NUM_USER_TER_FLAGS) {
2203 ruleset_error(LOG_ERROR, "\"%s\": Too many user terrain flags!",
2204 filename);
2205 ok = FALSE;
2206 break;
2209 set_user_terrain_flag_name(TER_USER_1 + i, flag, helptxt);
2212 if (ok) {
2213 for (; i < MAX_NUM_USER_TER_FLAGS; i++) {
2214 set_user_terrain_flag_name(TER_USER_1 + i, NULL, NULL);
2217 /* terrain names */
2219 sec = secfile_sections_by_name_prefix(file, TERRAIN_SECTION_PREFIX);
2220 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
2221 ruleset_error(LOG_ERROR, "\"%s\": ruleset doesn't have any terrains.",
2222 filename);
2223 ok = FALSE;
2224 } else {
2225 if (nval > MAX_NUM_TERRAINS) {
2226 ruleset_error(LOG_ERROR, "\"%s\": Too many terrains (%d, max %d)",
2227 filename, nval, MAX_NUM_TERRAINS);
2228 ok = FALSE;
2233 if (ok) {
2234 game.control.terrain_count = nval;
2236 /* avoid re-reading files */
2237 if (terrain_sections) {
2238 free(terrain_sections);
2240 terrain_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2242 terrain_type_iterate(pterrain) {
2243 const int terri = terrain_index(pterrain);
2244 const char *sec_name = section_name(section_list_get(sec, terri));
2246 if (!ruleset_load_names(&pterrain->name, NULL, file, sec_name)) {
2247 ok = FALSE;
2248 break;
2251 if (0 == strcmp(rule_name_get(&pterrain->name), "unused")) {
2252 name_set(&pterrain->name, NULL, "");
2255 section_strlcpy(&terrain_sections[terri * MAX_SECTION_LABEL], sec_name);
2256 } terrain_type_iterate_end;
2259 section_list_destroy(sec);
2260 sec = NULL;
2262 /* resource names */
2263 if (ok) {
2264 sec = secfile_sections_by_name_prefix(file, RESOURCE_SECTION_PREFIX);
2265 nval = (NULL != sec ? section_list_size(sec) : 0);
2266 if (nval > MAX_NUM_RESOURCES) {
2267 ruleset_error(LOG_ERROR, "\"%s\": Too many resources (%d, max %d)",
2268 filename, nval, MAX_NUM_RESOURCES);
2269 ok = FALSE;
2273 if (ok) {
2274 game.control.resource_count = nval;
2276 /* avoid re-reading files */
2277 if (resource_sections) {
2278 free(resource_sections);
2280 resource_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2282 resource_type_iterate(presource) {
2283 const int resi = resource_index(presource);
2284 const char *sec_name = section_name(section_list_get(sec, resi));
2286 if (!ruleset_load_names(&presource->name, NULL, file, sec_name)) {
2287 ok = FALSE;
2288 break;
2291 if (!strcmp(rule_name_get(&presource->name), "unused")) {
2292 name_set(&presource->name, NULL, "");
2295 section_strlcpy(&resource_sections[resi * MAX_SECTION_LABEL], sec_name);
2296 } resource_type_iterate_end;
2299 section_list_destroy(sec);
2300 sec = NULL;
2302 /* extra names */
2304 if (ok) {
2305 sec = secfile_sections_by_name_prefix(file, EXTRA_SECTION_PREFIX);
2306 nval = (NULL != sec ? section_list_size(sec) : 0);
2307 if (nval > MAX_EXTRA_TYPES) {
2308 ruleset_error(LOG_ERROR, "\"%s\": Too many extra types (%d, max %d)",
2309 filename, nval, MAX_EXTRA_TYPES);
2310 ok = FALSE;
2314 if (ok) {
2315 int idx;
2317 game.control.num_extra_types = nval;
2319 if (extra_sections) {
2320 free(extra_sections);
2322 extra_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2324 if (ok) {
2325 for (idx = 0; idx < nval; idx++) {
2326 const char *sec_name = section_name(section_list_get(sec, idx));
2327 struct extra_type *pextra = extra_by_number(idx);
2329 if (!ruleset_load_names(&pextra->name, NULL, file, sec_name)) {
2330 ok = FALSE;
2331 break;
2333 section_strlcpy(&extra_sections[idx * MAX_SECTION_LABEL], sec_name);
2338 section_list_destroy(sec);
2339 sec = NULL;
2341 /* base names */
2343 if (ok) {
2344 sec = secfile_sections_by_name_prefix(file, BASE_SECTION_PREFIX);
2345 nval = (NULL != sec ? section_list_size(sec) : 0);
2346 if (nval > MAX_BASE_TYPES) {
2347 ruleset_error(LOG_ERROR, "\"%s\": Too many base types (%d, max %d)",
2348 filename, nval, MAX_BASE_TYPES);
2349 ok = FALSE;
2352 game.control.num_base_types = nval;
2355 if (ok) {
2356 int idx;
2358 if (base_sections) {
2359 free(base_sections);
2361 base_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2363 /* Cannot use base_type_iterate() before bases are added to
2364 * EC_BASE caused_by list. Have to get them by extra_type_by_rule_name() */
2365 for (idx = 0; idx < nval; idx++) {
2366 const char *sec_name = section_name(section_list_get(sec, idx));
2367 const char *base_name = secfile_lookup_str(file, "%s.extra", sec_name);
2369 if (base_name != NULL) {
2370 struct extra_type *pextra = extra_type_by_rule_name(base_name);
2372 if (pextra != NULL) {
2373 base_type_init(pextra, idx);
2374 section_strlcpy(&base_sections[idx * MAX_SECTION_LABEL], sec_name);
2375 } else {
2376 ruleset_error(LOG_ERROR,
2377 "No extra definition matching base definition \"%s\"",
2378 base_name);
2379 ok = FALSE;
2381 } else {
2382 ruleset_error(LOG_ERROR,
2383 "Base section \"%s\" does not associate base with any extra",
2384 sec_name);
2385 ok = FALSE;
2390 section_list_destroy(sec);
2391 sec = NULL;
2393 /* road names */
2395 if (ok) {
2396 sec = secfile_sections_by_name_prefix(file, ROAD_SECTION_PREFIX);
2397 nval = (NULL != sec ? section_list_size(sec) : 0);
2398 if (nval > MAX_ROAD_TYPES) {
2399 ruleset_error(LOG_ERROR, "\"%s\": Too many road types (%d, max %d)",
2400 filename, nval, MAX_ROAD_TYPES);
2401 ok = FALSE;
2404 game.control.num_road_types = nval;
2407 if (ok) {
2408 int idx;
2410 if (road_sections) {
2411 free(road_sections);
2413 road_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2415 /* Cannot use extra_type_by_cause_iterate(EC_ROAD) before roads are added to
2416 * EC_ROAD caused_by list. Have to get them by extra_type_by_rule_name() */
2417 for (idx = 0; idx < nval; idx++) {
2418 const char *sec_name = section_name(section_list_get(sec, idx));
2419 const char *road_name = secfile_lookup_str(file, "%s.extra", sec_name);
2421 if (road_name != NULL) {
2422 struct extra_type *pextra = extra_type_by_rule_name(road_name);
2424 if (pextra != NULL) {
2425 road_type_init(pextra, idx);
2426 section_strlcpy(&road_sections[idx * MAX_SECTION_LABEL], sec_name);
2427 } else {
2428 ruleset_error(LOG_ERROR,
2429 "No extra definition matching road definition \"%s\"",
2430 road_name);
2431 ok = FALSE;
2433 } else {
2434 ruleset_error(LOG_ERROR,
2435 "Road section \"%s\" does not associate road with any extra",
2436 sec_name);
2437 ok = FALSE;
2442 section_list_destroy(sec);
2444 return ok;
2447 /**************************************************************************
2448 Load terrain types related ruleset data
2449 **************************************************************************/
2450 static bool load_ruleset_terrain(struct section_file *file)
2452 size_t nval;
2453 int j;
2454 bool compat_road = FALSE;
2455 bool compat_rail = FALSE;
2456 bool compat_river = FALSE;
2457 const char **res;
2458 const char *filename = secfile_name(file);
2459 const char *text;
2460 bool ok = TRUE;
2462 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
2463 return FALSE;
2466 /* parameters */
2468 terrain_control.ocean_reclaim_requirement_pct
2469 = secfile_lookup_int_default(file, 101,
2470 "parameters.ocean_reclaim_requirement");
2471 terrain_control.land_channel_requirement_pct
2472 = secfile_lookup_int_default(file, 101,
2473 "parameters.land_channel_requirement");
2474 terrain_control.terrain_thaw_requirement_pct
2475 = secfile_lookup_int_default(file, 101,
2476 "parameters.thaw_requirement");
2477 terrain_control.terrain_freeze_requirement_pct
2478 = secfile_lookup_int_default(file, 101,
2479 "parameters.freeze_requirement");
2480 terrain_control.lake_max_size
2481 = secfile_lookup_int_default(file, 0,
2482 "parameters.lake_max_size");
2483 terrain_control.min_start_native_area
2484 = secfile_lookup_int_default(file, 0,
2485 "parameters.min_start_native_area");
2486 terrain_control.move_fragments
2487 = secfile_lookup_int_default(file, 3,
2488 "parameters.move_fragments");
2489 if (terrain_control.move_fragments < 1) {
2490 ruleset_error(LOG_ERROR, "\"%s\": move_fragments must be at least 1",
2491 filename);
2492 ok = FALSE;
2494 init_move_fragments();
2495 terrain_control.igter_cost
2496 = secfile_lookup_int_default(file, 1,
2497 "parameters.igter_cost");
2498 if (terrain_control.igter_cost < 1) {
2499 ruleset_error(LOG_ERROR, "\"%s\": igter_cost must be at least 1",
2500 filename);
2501 ok = FALSE;
2503 terrain_control.pythagorean_diagonal
2504 = secfile_lookup_bool_default(file, RS_DEFAULT_PYTHAGOREAN_DIAGONAL,
2505 "parameters.pythagorean_diagonal");
2507 game.map.server.ocean_resources
2508 = secfile_lookup_bool_default(file, FALSE,
2509 "parameters.ocean_resources");
2511 text = secfile_lookup_str_default(file,
2512 N_("?gui_type:Build Type A Base"),
2513 "extraui.ui_name_base_fortress");
2514 sz_strlcpy(terrain_control.gui_type_base0, text);
2516 text = secfile_lookup_str_default(file,
2517 N_("?gui_type:Build Type B Base"),
2518 "extraui.ui_name_base_airbase");
2519 sz_strlcpy(terrain_control.gui_type_base1, text);
2521 if (ok) {
2522 /* terrain details */
2524 terrain_type_iterate(pterrain) {
2525 const char **slist;
2526 const int i = terrain_index(pterrain);
2527 const char *tsection = &terrain_sections[i * MAX_SECTION_LABEL];
2528 const char *cstr;
2530 sz_strlcpy(pterrain->graphic_str,
2531 secfile_lookup_str(file,"%s.graphic", tsection));
2532 sz_strlcpy(pterrain->graphic_alt,
2533 secfile_lookup_str(file,"%s.graphic_alt", tsection));
2535 pterrain->identifier
2536 = secfile_lookup_str(file, "%s.identifier", tsection)[0];
2537 if ('\0' == pterrain->identifier) {
2538 ruleset_error(LOG_ERROR, "\"%s\" [%s] identifier missing value.",
2539 filename, tsection);
2540 ok = FALSE;
2541 break;
2543 if (TERRAIN_UNKNOWN_IDENTIFIER == pterrain->identifier) {
2544 ruleset_error(LOG_ERROR,
2545 "\"%s\" [%s] cannot use '%c' as an identifier;"
2546 " it is reserved for unknown terrain.",
2547 filename, tsection, pterrain->identifier);
2548 ok = FALSE;
2549 break;
2551 for (j = T_FIRST; j < i; j++) {
2552 if (pterrain->identifier == terrain_by_number(j)->identifier) {
2553 ruleset_error(LOG_ERROR,
2554 "\"%s\" [%s] has the same identifier as [%s].",
2555 filename,
2556 tsection,
2557 &terrain_sections[j * MAX_SECTION_LABEL]);
2558 ok = FALSE;
2559 break;
2563 if (!ok) {
2564 break;
2567 cstr = secfile_lookup_str(file, "%s.class", tsection);
2568 pterrain->tclass = terrain_class_by_name(cstr, fc_strcasecmp);
2569 if (!terrain_class_is_valid(pterrain->tclass)) {
2570 ruleset_error(LOG_ERROR, "\"%s\": [%s] unknown class \"%s\"",
2571 filename, tsection, cstr);
2572 ok = FALSE;
2573 break;
2576 if (!secfile_lookup_int(file, &pterrain->movement_cost,
2577 "%s.movement_cost", tsection)
2578 || !secfile_lookup_int(file, &pterrain->defense_bonus,
2579 "%s.defense_bonus", tsection)) {
2580 ruleset_error(LOG_ERROR, "%s", secfile_error());
2581 ok = FALSE;
2582 break;
2585 output_type_iterate(o) {
2586 pterrain->output[o]
2587 = secfile_lookup_int_default(file, 0, "%s.%s", tsection,
2588 get_output_identifier(o));
2589 } output_type_iterate_end;
2591 res = secfile_lookup_str_vec(file, &nval, "%s.resources", tsection);
2592 pterrain->resources = fc_calloc(nval + 1, sizeof(*pterrain->resources));
2593 for (j = 0; j < nval; j++) {
2594 pterrain->resources[j] = lookup_resource(filename, res[j], tsection);
2595 if (pterrain->resources[j] == NULL) {
2596 ok = FALSE;
2597 break;
2600 pterrain->resources[nval] = NULL;
2601 free(res);
2602 res = NULL;
2604 if (!ok) {
2605 break;
2608 output_type_iterate(o) {
2609 pterrain->road_output_incr_pct[o]
2610 = secfile_lookup_int_default(file, 0, "%s.road_%s_incr_pct",
2611 tsection, get_output_identifier(o));
2612 } output_type_iterate_end;
2614 if (!lookup_time(file, &pterrain->base_time, tsection, "base_time",
2615 filename, NULL, &ok)
2616 || !lookup_time(file, &pterrain->road_time, tsection, "road_time",
2617 filename, NULL, &ok)) {
2618 ruleset_error(LOG_ERROR, "%s", secfile_error());
2619 ok = FALSE;
2620 break;
2623 if (!lookup_terrain(file, "irrigation_result", filename, pterrain,
2624 &pterrain->irrigation_result)) {
2625 ok = FALSE;
2626 break;
2628 if (!secfile_lookup_int(file, &pterrain->irrigation_food_incr,
2629 "%s.irrigation_food_incr", tsection)
2630 || !lookup_time(file, &pterrain->irrigation_time,
2631 tsection, "irrigation_time", filename, NULL, &ok)) {
2632 ruleset_error(LOG_ERROR, "%s", secfile_error());
2633 ok = FALSE;
2634 break;
2637 if (!lookup_terrain(file, "mining_result", filename, pterrain,
2638 &pterrain->mining_result)) {
2639 ok = FALSE;
2640 break;
2642 if (!secfile_lookup_int(file, &pterrain->mining_shield_incr,
2643 "%s.mining_shield_incr", tsection)
2644 || !lookup_time(file, &pterrain->mining_time,
2645 tsection, "mining_time", filename, NULL, &ok)) {
2646 ruleset_error(LOG_ERROR, "%s", secfile_error());
2647 ok = FALSE;
2648 break;
2651 if (!lookup_unit_type(file, tsection, "animal",
2652 &pterrain->animal, filename,
2653 rule_name_get(&pterrain->name))) {
2654 ok = FALSE;
2655 break;
2658 if (!lookup_terrain(file, "transform_result", filename, pterrain,
2659 &pterrain->transform_result)) {
2660 ok = FALSE;
2661 break;
2663 if (!lookup_time(file, &pterrain->transform_time,
2664 tsection, "transform_time", filename, NULL, &ok)) {
2665 ruleset_error(LOG_ERROR, "%s", secfile_error());
2666 ok = FALSE;
2667 break;
2669 pterrain->pillage_time = 1; /* default */
2670 lookup_time(file, &pterrain->pillage_time,
2671 tsection, "pillage_time", filename, NULL, &ok);
2672 pterrain->clean_pollution_time = 3; /* default */
2673 lookup_time(file, &pterrain->clean_pollution_time,
2674 tsection, "clean_pollution_time", filename, NULL, &ok);
2675 pterrain->clean_fallout_time = 3; /* default */
2676 lookup_time(file, &pterrain->clean_fallout_time,
2677 tsection, "clean_fallout_time", filename, NULL, &ok);
2679 if (!lookup_terrain(file, "warmer_wetter_result", filename, pterrain,
2680 &pterrain->warmer_wetter_result)
2681 || !lookup_terrain(file, "warmer_drier_result", filename, pterrain,
2682 &pterrain->warmer_drier_result)
2683 || !lookup_terrain(file, "cooler_wetter_result", filename, pterrain,
2684 &pterrain->cooler_wetter_result)
2685 || !lookup_terrain(file, "cooler_drier_result", filename, pterrain,
2686 &pterrain->cooler_drier_result)) {
2687 ok = FALSE;
2688 break;
2691 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", tsection);
2692 BV_CLR_ALL(pterrain->flags);
2693 for (j = 0; j < nval; j++) {
2694 const char *sval = slist[j];
2695 enum terrain_flag_id flag
2696 = terrain_flag_id_by_name(sval, fc_strcasecmp);
2698 if (!terrain_flag_id_is_valid(flag)) {
2699 ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown flag \"%s\".",
2700 filename, tsection, sval);
2701 ok = FALSE;
2702 break;
2703 } else {
2704 BV_SET(pterrain->flags, flag);
2707 free(slist);
2709 if (!ok) {
2710 break;
2714 enum mapgen_terrain_property mtp;
2715 for (mtp = mapgen_terrain_property_begin();
2716 mtp != mapgen_terrain_property_end();
2717 mtp = mapgen_terrain_property_next(mtp)) {
2718 pterrain->property[mtp]
2719 = secfile_lookup_int_default(file, 0, "%s.property_%s", tsection,
2720 mapgen_terrain_property_name(mtp));
2724 slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", tsection);
2725 BV_CLR_ALL(pterrain->native_to);
2726 for (j = 0; j < nval; j++) {
2727 struct unit_class *class = unit_class_by_rule_name(slist[j]);
2729 if (!class) {
2730 ruleset_error(LOG_ERROR,
2731 "\"%s\" [%s] is native to unknown unit class \"%s\".",
2732 filename, tsection, slist[j]);
2733 ok = FALSE;
2734 break;
2735 } else {
2736 BV_SET(pterrain->native_to, uclass_index(class));
2739 free(slist);
2741 if (!ok) {
2742 break;
2745 /* get terrain color */
2747 fc_assert_ret_val(pterrain->rgb == NULL, FALSE);
2748 if (!rgbcolor_load(file, &pterrain->rgb, "%s.color", tsection)) {
2749 ruleset_error(LOG_ERROR, "Missing terrain color definition: %s",
2750 secfile_error());
2751 ok = FALSE;
2752 break;
2756 pterrain->helptext = lookup_strvec(file, tsection, "helptext");
2757 } terrain_type_iterate_end;
2760 if (ok) {
2761 /* resource details */
2763 resource_type_iterate(presource) {
2764 char identifier[MAX_LEN_NAME];
2765 const int i = resource_index(presource);
2766 const char *rsection = &resource_sections[i * MAX_SECTION_LABEL];
2768 output_type_iterate (o) {
2769 presource->output[o] =
2770 secfile_lookup_int_default(file, 0, "%s.%s", rsection,
2771 get_output_identifier(o));
2772 } output_type_iterate_end;
2773 sz_strlcpy(presource->graphic_str,
2774 secfile_lookup_str(file,"%s.graphic", rsection));
2775 sz_strlcpy(presource->graphic_alt,
2776 secfile_lookup_str(file,"%s.graphic_alt", rsection));
2778 sz_strlcpy(identifier,
2779 secfile_lookup_str(file,"%s.identifier", rsection));
2780 presource->identifier = identifier[0];
2781 if (RESOURCE_NULL_IDENTIFIER == presource->identifier) {
2782 ruleset_error(LOG_ERROR, "\"%s\" [%s] identifier missing value.",
2783 filename, rsection);
2784 ok = FALSE;
2785 break;
2787 if (RESOURCE_NONE_IDENTIFIER == presource->identifier) {
2788 ruleset_error(LOG_ERROR,
2789 "\"%s\" [%s] cannot use '%c' as an identifier;"
2790 " it is reserved.",
2791 filename, rsection, presource->identifier);
2792 ok = FALSE;
2793 break;
2795 for (j = 0; j < i; j++) {
2796 if (presource->identifier == resource_by_number(j)->identifier) {
2797 ruleset_error(LOG_ERROR,
2798 "\"%s\" [%s] has the same identifier as [%s].",
2799 filename,
2800 rsection,
2801 &resource_sections[j * MAX_SECTION_LABEL]);
2802 ok = FALSE;
2803 break;
2807 if (!ok) {
2808 break;
2811 } resource_type_iterate_end;
2814 if (ok) {
2815 /* extra details */
2816 extra_type_iterate(pextra) {
2817 BV_CLR_ALL(pextra->conflicts);
2818 } extra_type_iterate_end;
2820 extra_type_iterate(pextra) {
2821 const char *section = &extra_sections[extra_index(pextra) * MAX_SECTION_LABEL];
2822 const char **slist;
2823 struct requirement_vector *reqs;
2824 const char *catname;
2825 int cj;
2826 enum extra_cause cause;
2827 enum extra_rmcause rmcause;
2829 catname = secfile_lookup_str(file, "%s.category", section);
2830 if (catname == NULL) {
2831 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\" has no category.",
2832 filename,
2833 extra_rule_name(pextra));
2834 ok = FALSE;
2835 break;
2837 pextra->category = extra_category_by_name(catname, fc_strcasecmp);
2838 if (!extra_category_is_valid(pextra->category)) {
2839 ruleset_error(LOG_ERROR,
2840 "\"%s\" extra \"%s\" has invalid category \"%s\".",
2841 filename, extra_rule_name(pextra), catname);
2842 ok = FALSE;
2843 break;
2846 slist = secfile_lookup_str_vec(file, &nval, "%s.causes", section);
2847 pextra->causes = 0;
2848 for (cj = 0; cj < nval; cj++) {
2849 const char *sval = slist[cj];
2850 cause = extra_cause_by_name(sval, fc_strcasecmp);
2852 if (!extra_cause_is_valid(cause)) {
2853 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown cause \"%s\".",
2854 filename,
2855 extra_rule_name(pextra),
2856 sval);
2857 ok = FALSE;
2858 break;
2859 } else {
2860 pextra->causes |= (1 << cause);
2861 extra_to_caused_by_list(pextra, cause);
2865 extra_to_category_list(pextra, pextra->category);
2867 if (pextra->causes == 0) {
2868 /* Extras that do not have any causes added to EC_NONE list */
2869 extra_to_caused_by_list(pextra, EC_NONE);
2872 if (!is_extra_caused_by(pextra, EC_BASE)
2873 && !is_extra_caused_by(pextra, EC_ROAD)) {
2874 /* Not a base nor road, so special */
2875 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
2876 extra_to_caused_by_list(pextra, EC_SPECIAL);
2879 free(slist);
2881 slist = secfile_lookup_str_vec(file, &nval, "%s.rmcauses", section);
2882 pextra->rmcauses = 0;
2883 for (j = 0; j < nval; j++) {
2884 const char *sval = slist[j];
2885 rmcause = extra_rmcause_by_name(sval, fc_strcasecmp);
2887 if (!extra_rmcause_is_valid(rmcause)) {
2888 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown rmcause \"%s\".",
2889 filename,
2890 extra_rule_name(pextra),
2891 sval);
2892 ok = FALSE;
2893 break;
2894 } else {
2895 pextra->rmcauses |= (1 << rmcause);
2896 extra_to_removed_by_list(pextra, rmcause);
2900 free(slist);
2902 sz_strlcpy(pextra->activity_gfx,
2903 secfile_lookup_str_default(file, "-",
2904 "%s.activity_gfx", section));
2905 sz_strlcpy(pextra->act_gfx_alt,
2906 secfile_lookup_str_default(file, "-",
2907 "%s.act_gfx_alt", section));
2908 sz_strlcpy(pextra->act_gfx_alt2,
2909 secfile_lookup_str_default(file, "-",
2910 "%s.act_gfx_alt2", section));
2911 sz_strlcpy(pextra->rmact_gfx,
2912 secfile_lookup_str_default(file, "-",
2913 "%s.rmact_gfx", section));
2914 sz_strlcpy(pextra->rmact_gfx_alt,
2915 secfile_lookup_str_default(file, "-",
2916 "%s.rmact_gfx_alt", section));
2917 sz_strlcpy(pextra->graphic_str,
2918 secfile_lookup_str_default(file, "-", "%s.graphic", section));
2919 sz_strlcpy(pextra->graphic_alt,
2920 secfile_lookup_str_default(file, "-",
2921 "%s.graphic_alt", section));
2923 reqs = lookup_req_list(file, section, "reqs", extra_rule_name(pextra));
2924 if (reqs == NULL) {
2925 ok = FALSE;
2926 break;
2928 requirement_vector_copy(&pextra->reqs, reqs);
2930 reqs = lookup_req_list(file, section, "rmreqs", extra_rule_name(pextra));
2931 if (reqs == NULL) {
2932 ok = FALSE;
2933 break;
2935 requirement_vector_copy(&pextra->rmreqs, reqs);
2937 pextra->buildable = secfile_lookup_bool_default(file, TRUE,
2938 "%s.buildable", section);
2940 pextra->build_time = 0; /* default */
2941 lookup_time(file, &pextra->build_time, section, "build_time",
2942 filename, extra_rule_name(pextra), &ok);
2943 pextra->build_time_factor = secfile_lookup_int_default(file, 1,
2944 "%s.build_time_factor", section);
2945 pextra->removal_time = 0; /* default */
2946 lookup_time(file, &pextra->removal_time, section, "removal_time",
2947 filename, extra_rule_name(pextra), &ok);
2948 pextra->removal_time_factor = secfile_lookup_int_default(file, 1,
2949 "%s.removal_time_factor", section);
2951 pextra->defense_bonus = secfile_lookup_int_default(file, 0,
2952 "%s.defense_bonus",
2953 section);
2954 if (pextra->defense_bonus != 0) {
2955 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
2956 extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
2957 } else {
2958 extra_to_caused_by_list(pextra, EC_DEFENSIVE);
2962 slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", section);
2963 BV_CLR_ALL(pextra->native_to);
2964 for (j = 0; j < nval; j++) {
2965 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2967 if (uclass == NULL) {
2968 ruleset_error(LOG_ERROR,
2969 "\"%s\" extra \"%s\" is native to unknown unit class \"%s\".",
2970 filename,
2971 extra_rule_name(pextra),
2972 slist[j]);
2973 ok = FALSE;
2974 break;
2975 } else {
2976 BV_SET(pextra->native_to, uclass_index(uclass));
2979 free(slist);
2981 if (!ok) {
2982 break;
2985 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
2986 BV_CLR_ALL(pextra->flags);
2987 for (j = 0; j < nval; j++) {
2988 const char *sval = slist[j];
2989 enum extra_flag_id flag = extra_flag_id_by_name(sval, fc_strcasecmp);
2991 if (!extra_flag_id_is_valid(flag)) {
2992 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown flag \"%s\".",
2993 filename,
2994 extra_rule_name(pextra),
2995 sval);
2996 ok = FALSE;
2997 break;
2998 } else {
2999 BV_SET(pextra->flags, flag);
3002 free(slist);
3004 if (!ok) {
3005 break;
3008 slist = secfile_lookup_str_vec(file, &nval, "%s.conflicts", section);
3009 for (j = 0; j < nval; j++) {
3010 const char *sval = slist[j];
3011 struct extra_type *pextra2 = extra_type_by_rule_name(sval);
3013 if (pextra2 == NULL) {
3014 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown conflict extra \"%s\".",
3015 filename,
3016 extra_rule_name(pextra),
3017 sval);
3018 ok = FALSE;
3019 break;
3020 } else {
3021 BV_SET(pextra->conflicts, extra_index(pextra2));
3022 BV_SET(pextra2->conflicts, extra_index(pextra));
3026 free(slist);
3028 if (!ok) {
3029 break;
3032 slist = secfile_lookup_str_vec(file, &nval, "%s.hidden_by", section);
3033 BV_CLR_ALL(pextra->hidden_by);
3034 for (j = 0; j < nval; j++) {
3035 const char *sval = slist[j];
3036 const struct extra_type *top = extra_type_by_rule_name(sval);
3038 if (top == NULL) {
3039 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\" hidden by unknown extra \"%s\".",
3040 filename,
3041 extra_rule_name(pextra),
3042 sval);
3043 ok = FALSE;
3044 break;
3045 } else {
3046 BV_SET(pextra->hidden_by, extra_index(top));
3049 free(slist);
3051 if (!ok) {
3052 break;
3055 pextra->helptext = lookup_strvec(file, section, "helptext");
3057 } extra_type_iterate_end;
3060 if (ok) {
3061 /* base details */
3062 extra_type_by_cause_iterate(EC_BASE, pextra) {
3063 struct base_type *pbase = extra_base_get(pextra);
3064 const char *section = &base_sections[base_index(pbase) * MAX_SECTION_LABEL];
3065 int bj;
3066 const char **slist;
3067 const char *gui_str;
3069 gui_str = secfile_lookup_str(file,"%s.gui_type", section);
3070 pbase->gui_type = base_gui_type_by_name(gui_str, fc_strcasecmp);
3071 if (!base_gui_type_is_valid(pbase->gui_type)) {
3072 ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": unknown gui_type \"%s\".",
3073 filename,
3074 extra_rule_name(pextra),
3075 gui_str);
3076 ok = FALSE;
3077 break;
3080 pbase->border_sq = secfile_lookup_int_default(file, -1, "%s.border_sq",
3081 section);
3082 pbase->vision_main_sq = secfile_lookup_int_default(file, -1,
3083 "%s.vision_main_sq",
3084 section);
3085 pbase->vision_invis_sq = secfile_lookup_int_default(file, -1,
3086 "%s.vision_invis_sq",
3087 section);
3089 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3090 BV_CLR_ALL(pbase->flags);
3091 for (bj = 0; bj < nval; bj++) {
3092 const char *sval = slist[bj];
3093 enum base_flag_id flag = base_flag_id_by_name(sval, fc_strcasecmp);
3095 if (!base_flag_id_is_valid(flag)) {
3096 ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": unknown flag \"%s\".",
3097 filename,
3098 extra_rule_name(pextra),
3099 sval);
3100 ok = FALSE;
3101 break;
3102 } else {
3103 BV_SET(pbase->flags, flag);
3107 free(slist);
3109 if (!ok) {
3110 break;
3113 if (territory_claiming_base(pbase)) {
3114 extra_type_by_cause_iterate(EC_BASE, pextra2) {
3115 struct base_type *pbase2;
3117 if (pextra == pextra2) {
3118 /* End of the fully initialized bases iteration. */
3119 break;
3122 pbase2 = extra_base_get(pextra2);
3123 if (territory_claiming_base(pbase2)) {
3124 BV_SET(pextra->conflicts, extra_index(pextra2));
3125 BV_SET(pextra2->conflicts, extra_index(pextra));
3127 } extra_type_by_cause_iterate_end;
3129 } extra_type_by_cause_iterate_end;
3132 if (ok) {
3133 extra_type_by_cause_iterate(EC_ROAD, pextra) {
3134 struct road_type *proad = extra_road_get(pextra);
3135 const char *section = &road_sections[road_index(proad) * MAX_SECTION_LABEL];
3136 const char **slist;
3137 const char *special;
3138 const char *modestr;
3139 struct requirement_vector *reqs;
3141 reqs = lookup_req_list(file, section, "first_reqs", extra_rule_name(pextra));
3142 if (reqs == NULL) {
3143 ok = FALSE;
3144 break;
3146 requirement_vector_copy(&proad->first_reqs, reqs);
3148 if (!secfile_lookup_int(file, &proad->move_cost,
3149 "%s.move_cost", section)) {
3150 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3151 ok = FALSE;
3152 break;
3155 modestr = secfile_lookup_str_default(file, "FastAlways", "%s.move_mode",
3156 section);
3157 proad->move_mode = road_move_mode_by_name(modestr, fc_strcasecmp);
3158 if (!road_move_mode_is_valid(proad->move_mode)) {
3159 ruleset_error(LOG_ERROR, "Illegal move_mode \"%s\" for road \"%s\"",
3160 modestr, extra_rule_name(pextra));
3161 ok = FALSE;
3162 break;
3165 output_type_iterate(o) {
3166 proad->tile_incr_const[o] =
3167 secfile_lookup_int_default(file, 0, "%s.%s_incr_const",
3168 section, get_output_identifier(o));
3169 proad->tile_incr[o] =
3170 secfile_lookup_int_default(file, 0, "%s.%s_incr",
3171 section, get_output_identifier(o));
3172 proad->tile_bonus[o] =
3173 secfile_lookup_int_default(file, 0, "%s.%s_bonus",
3174 section, get_output_identifier(o));
3175 } output_type_iterate_end;
3177 special = secfile_lookup_str_default(file, "None", "%s.compat_special", section);
3178 if (!fc_strcasecmp(special, "Road")) {
3179 if (compat_road) {
3180 ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"Road\"");
3181 ok = FALSE;
3183 compat_road = TRUE;
3184 proad->compat = ROCO_ROAD;
3185 } else if (!fc_strcasecmp(special, "Railroad")) {
3186 if (compat_rail) {
3187 ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"Railroad\"");
3188 ok = FALSE;
3190 compat_rail = TRUE;
3191 proad->compat = ROCO_RAILROAD;
3192 } else if (!fc_strcasecmp(special, "River")) {
3193 if (compat_river) {
3194 ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"River\"");
3195 ok = FALSE;
3197 compat_river = TRUE;
3198 proad->compat = ROCO_RIVER;
3199 } else if (!fc_strcasecmp(special, "None")) {
3200 proad->compat = ROCO_NONE;
3201 } else {
3202 ruleset_error(LOG_ERROR, "Illegal compatibility special \"%s\" for road %s",
3203 special, extra_rule_name(pextra));
3204 ok = FALSE;
3207 if (!ok) {
3208 break;
3211 slist = secfile_lookup_str_vec(file, &nval, "%s.integrates", section);
3212 BV_CLR_ALL(proad->integrates);
3213 for (j = 0; j < nval; j++) {
3214 const char *sval = slist[j];
3215 struct extra_type *textra = extra_type_by_rule_name(sval);
3216 struct road_type *top = NULL;
3218 if (textra != NULL) {
3219 top = extra_road_get(textra);
3222 if (top == NULL) {
3223 ruleset_error(LOG_ERROR, "\"%s\" road \"%s\" integrates with unknown road \"%s\".",
3224 filename,
3225 extra_rule_name(pextra),
3226 sval);
3227 ok = FALSE;
3228 break;
3229 } else {
3230 BV_SET(proad->integrates, road_index(top));
3233 free(slist);
3235 if (!ok) {
3236 break;
3239 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3240 BV_CLR_ALL(proad->flags);
3241 for (j = 0; j < nval; j++) {
3242 const char *sval = slist[j];
3243 enum road_flag_id flag = road_flag_id_by_name(sval, fc_strcasecmp);
3245 if (!road_flag_id_is_valid(flag)) {
3246 ruleset_error(LOG_ERROR, "\"%s\" road \"%s\": unknown flag \"%s\".",
3247 filename,
3248 extra_rule_name(pextra),
3249 sval);
3250 ok = FALSE;
3251 break;
3252 } else {
3253 BV_SET(proad->flags, flag);
3256 free(slist);
3258 if (!ok) {
3259 break;
3261 } extra_type_by_cause_iterate_end;
3264 if (ok) {
3265 secfile_check_unused(file);
3268 return ok;
3271 /**************************************************************************
3272 Load names of governments so other rulesets can refer to governments with
3273 their name. Also load multiplier names/count from governments.ruleset.
3274 **************************************************************************/
3275 static bool load_government_names(struct section_file *file)
3277 int nval = 0;
3278 struct section_list *sec;
3279 const char *filename = secfile_name(file);
3280 bool ok = TRUE;
3282 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
3283 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
3285 sec = secfile_sections_by_name_prefix(file, GOVERNMENT_SECTION_PREFIX);
3286 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
3287 ruleset_error(LOG_ERROR, "\"%s\": No governments?!?", filename);
3288 ok = FALSE;
3289 } else if (nval > G_LAST) {
3290 ruleset_error(LOG_ERROR, "\"%s\": Too many governments (%d, max %d)",
3291 filename, nval, G_LAST);
3292 ok = FALSE;
3295 if (ok) {
3296 governments_alloc(nval);
3298 /* Government names are needed early so that get_government_by_name will
3299 * work. */
3300 governments_iterate(gov) {
3301 const char *sec_name =
3302 section_name(section_list_get(sec, government_index(gov)));
3304 if (!ruleset_load_names(&gov->name, NULL, file, sec_name)) {
3305 ok = FALSE;
3306 break;
3308 } governments_iterate_end;
3311 section_list_destroy(sec);
3313 if (ok) {
3314 sec = secfile_sections_by_name_prefix(file, MULTIPLIER_SECTION_PREFIX);
3315 nval = (NULL != sec ? section_list_size(sec) : 0);
3317 if (nval > MAX_NUM_MULTIPLIERS) {
3318 ruleset_error(LOG_ERROR, "\"%s\": Too many multipliers (%d, max %d)",
3319 filename, nval, MAX_NUM_MULTIPLIERS);
3321 ok = FALSE;
3322 } else {
3323 game.control.num_multipliers = nval;
3326 if (ok) {
3327 multipliers_iterate(pmul) {
3328 const char *sec_name =
3329 section_name(section_list_get(sec, multiplier_index(pmul)));
3331 if (!ruleset_load_names(&pmul->name, NULL, file, sec_name)) {
3332 ruleset_error(LOG_ERROR, "\"%s\": Cannot load multiplier names",
3333 filename);
3334 ok = FALSE;
3335 break;
3337 } multipliers_iterate_end;
3341 section_list_destroy(sec);
3343 return ok;
3346 /**************************************************************************
3347 This loads information from given governments.ruleset
3348 **************************************************************************/
3349 static bool load_ruleset_governments(struct section_file *file)
3351 struct section_list *sec;
3352 const char *filename = secfile_name(file);
3353 bool ok = TRUE;
3355 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
3356 return FALSE;
3359 sec = secfile_sections_by_name_prefix(file, GOVERNMENT_SECTION_PREFIX);
3361 game.government_during_revolution
3362 = lookup_government(file, "governments.during_revolution", filename, NULL);
3363 if (game.government_during_revolution == NULL) {
3364 ok = FALSE;
3367 if (ok) {
3368 game.info.government_during_revolution_id =
3369 government_number(game.government_during_revolution);
3371 /* easy ones: */
3372 governments_iterate(g) {
3373 const int i = government_index(g);
3374 const char *sec_name = section_name(section_list_get(sec, i));
3375 struct requirement_vector *reqs =
3376 lookup_req_list(file, sec_name, "reqs", government_rule_name(g));
3378 if (reqs == NULL) {
3379 ok = FALSE;
3380 break;
3383 if (NULL != secfile_entry_lookup(file, "%s.ai_better", sec_name)) {
3384 char entry[100];
3386 fc_snprintf(entry, sizeof(entry), "%s.ai_better", sec_name);
3387 g->ai.better = lookup_government(file, entry, filename, NULL);
3388 if (g->ai.better == NULL) {
3389 ok = FALSE;
3390 break;
3392 } else {
3393 g->ai.better = NULL;
3395 requirement_vector_copy(&g->reqs, reqs);
3397 sz_strlcpy(g->graphic_str,
3398 secfile_lookup_str(file, "%s.graphic", sec_name));
3399 sz_strlcpy(g->graphic_alt,
3400 secfile_lookup_str(file, "%s.graphic_alt", sec_name));
3402 g->helptext = lookup_strvec(file, sec_name, "helptext");
3403 } governments_iterate_end;
3407 if (ok) {
3408 /* titles */
3409 governments_iterate(g) {
3410 const char *sec_name =
3411 section_name(section_list_get(sec, government_index(g)));
3412 const char *male, *female;
3414 if (!(male = secfile_lookup_str(file, "%s.ruler_male_title", sec_name))
3415 || !(female = secfile_lookup_str(file, "%s.ruler_female_title",
3416 sec_name))) {
3417 ruleset_error(LOG_ERROR, "Lack of default ruler titles for "
3418 "government \"%s\" (nb %d): %s",
3419 government_rule_name(g), government_number(g),
3420 secfile_error());
3421 ok = FALSE;
3422 break;
3423 } else if (NULL == government_ruler_title_new(g, NULL, male, female)) {
3424 ruleset_error(LOG_ERROR, "Lack of default ruler titles for "
3425 "government \"%s\" (nb %d).",
3426 government_rule_name(g), government_number(g));
3427 ok = FALSE;
3428 break;
3430 } governments_iterate_end;
3433 section_list_destroy(sec);
3435 if (ok) {
3436 sec = secfile_sections_by_name_prefix(file, MULTIPLIER_SECTION_PREFIX);
3437 multipliers_iterate(pmul) {
3438 int id = multiplier_index(pmul);
3439 const char *sec_name = section_name(section_list_get(sec, id));
3441 if (!secfile_lookup_int(file, &pmul->start, "%s.start", sec_name)) {
3442 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3443 ok = FALSE;
3444 break;
3446 if (!secfile_lookup_int(file, &pmul->stop, "%s.stop", sec_name)) {
3447 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3448 ok = FALSE;
3449 break;
3451 if (pmul->stop <= pmul->start) {
3452 ruleset_error(LOG_ERROR, "Multiplier \"%s\" stop (%d) must be greater "
3453 "than start (%d)", multiplier_rule_name(pmul),
3454 pmul->stop, pmul->start);
3455 ok = FALSE;
3456 break;
3458 if (!secfile_lookup_int(file, &pmul->step, "%s.step", sec_name)) {
3459 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3460 ok = FALSE;
3461 break;
3463 if (((pmul->stop - pmul->start) % pmul->step) != 0) {
3464 ruleset_error(LOG_ERROR, "Multiplier \"%s\" step (%d) does not fit "
3465 "exactly into interval start-stop (%d to %d)",
3466 multiplier_rule_name(pmul), pmul->step,
3467 pmul->start, pmul->stop);
3468 ok = FALSE;
3469 break;
3471 if (!secfile_lookup_int(file, &pmul->def, "%s.default", sec_name)) {
3472 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3473 ok = FALSE;
3474 break;
3476 if (pmul->def < pmul->start || pmul->def > pmul->stop) {
3477 ruleset_error(LOG_ERROR, "Multiplier \"%s\" default (%d) not within "
3478 "legal range (%d to %d)", multiplier_rule_name(pmul),
3479 pmul->def, pmul->start, pmul->stop);
3480 ok = FALSE;
3481 break;
3483 if (((pmul->def - pmul->start) % pmul->step) != 0) {
3484 ruleset_error(LOG_ERROR, "Multiplier \"%s\" default (%d) not legal "
3485 "with respect to step size %d",
3486 multiplier_rule_name(pmul), pmul->def, pmul->step);
3487 ok = FALSE;
3488 break;
3490 pmul->offset = secfile_lookup_int_default(file, 0,
3491 "%s.offset", sec_name);
3492 pmul->factor = secfile_lookup_int_default(file, 100,
3493 "%s.factor", sec_name);
3494 if (pmul->factor == 0) {
3495 ruleset_error(LOG_ERROR, "Multiplier \"%s\" scaling factor must "
3496 "not be zero", multiplier_rule_name(pmul));
3497 ok = FALSE;
3498 break;
3501 pmul->helptext = lookup_strvec(file, sec_name, "helptext");
3502 } multipliers_iterate_end;
3503 section_list_destroy(sec);
3506 if (ok) {
3507 secfile_check_unused(file);
3510 return ok;
3513 /**************************************************************************
3514 Send information in packet_ruleset_control (numbers of units etc, and
3515 other miscellany) to specified connections.
3517 The client assumes that exactly one ruleset control packet is sent as
3518 a part of each ruleset send. So after sending this packet we have to
3519 resend every other part of the rulesets (and none of them should be
3520 is-info in the network code!). The client frees ruleset data when
3521 receiving this packet and then re-initializes as it receives the
3522 individual ruleset packets. See packhand.c.
3523 **************************************************************************/
3524 static void send_ruleset_control(struct conn_list *dest)
3526 int desc_left = game.control.desc_length;
3527 int idx = 0;
3529 lsend_packet_ruleset_control(dest, &(game.control));
3531 if (game.ruleset_summary != NULL) {
3532 struct packet_ruleset_summary summary;
3534 strncpy(summary.text, game.ruleset_summary, MAX_LEN_CONTENT);
3536 lsend_packet_ruleset_summary(dest, &summary);
3539 while (desc_left > 0) {
3540 struct packet_ruleset_description_part part;
3541 int this_len = desc_left;
3543 if (this_len > MAX_LEN_CONTENT - 21) {
3544 this_len = MAX_LEN_CONTENT - 1;
3547 part.text[this_len] = '\0';
3549 strncpy(part.text, &game.ruleset_description[idx], this_len);
3550 idx += this_len;
3551 desc_left -= this_len;
3553 lsend_packet_ruleset_description_part(dest, &part);
3557 /****************************************************************************
3558 Check for duplicate leader names in nation.
3559 If no duplicates return NULL; if yes return pointer to name which is
3560 repeated.
3561 ****************************************************************************/
3562 static const char *check_leader_names(struct nation_type *pnation)
3564 nation_leader_list_iterate(nation_leaders(pnation), pleader) {
3565 const char *name = nation_leader_name(pleader);
3567 nation_leader_list_iterate(nation_leaders(pnation), prev_leader) {
3568 if (prev_leader == pleader) {
3569 break;
3570 } else if (0 == fc_strcasecmp(name, nation_leader_name(prev_leader))) {
3571 return name;
3573 } nation_leader_list_iterate_end;
3574 } nation_leader_list_iterate_end;
3575 return NULL;
3578 /**************************************************************************
3579 Load names of nations so other rulesets can refer to nations with
3580 their name.
3581 **************************************************************************/
3582 static bool load_nation_names(struct section_file *file)
3584 struct section_list *sec;
3585 int j;
3586 bool ok = TRUE;
3588 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
3589 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
3591 sec = secfile_sections_by_name_prefix(file, NATION_SECTION_PREFIX);
3592 if (NULL == sec) {
3593 ruleset_error(LOG_ERROR, "No available nations in this ruleset!");
3594 ok = FALSE;
3595 } else if (section_list_size(sec) > MAX_NUM_NATIONS) {
3596 ruleset_error(LOG_ERROR, "Too many nations (max %d, we have %d)!",
3597 MAX_NUM_NATIONS, section_list_size(sec));
3598 ok = FALSE;
3599 } else {
3600 game.control.nation_count = section_list_size(sec);
3601 nations_alloc(game.control.nation_count);
3603 nations_iterate(pl) {
3604 const int i = nation_index(pl);
3605 const char *sec_name = section_name(section_list_get(sec, i));
3606 const char *domain = secfile_lookup_str_default(file, NULL,
3607 "%s.translation_domain", sec_name);
3608 const char *noun_plural = secfile_lookup_str(file,
3609 "%s.plural", sec_name);
3612 if (domain == NULL) {
3613 domain = "freeciv-nations";
3616 if (!strcmp("freeciv", domain)) {
3617 pl->translation_domain = NULL;
3618 } else if (!strcmp("freeciv-nations", domain)) {
3619 pl->translation_domain = fc_malloc(strlen(domain) + 1);
3620 strcpy(pl->translation_domain, domain);
3621 } else {
3622 ruleset_error(LOG_ERROR, "Unsupported translation domain \"%s\" for %s",
3623 domain, sec_name);
3624 ok = FALSE;
3625 break;
3628 if (!ruleset_load_names(&pl->adjective, domain, file, sec_name)) {
3629 ok = FALSE;
3630 break;
3632 name_set(&pl->noun_plural, domain, noun_plural);
3634 /* Check if nation name is already defined. */
3635 for (j = 0; j < i && ok; j++) {
3636 struct nation_type *n2 = nation_by_number(j);
3638 /* Compare strings after stripping off qualifiers -- we don't want
3639 * two nations to end up with identical adjectives displayed to users.
3640 * (This check only catches English, not localisations, of course.) */
3641 if (0 == strcmp(Qn_(untranslated_name(&n2->adjective)),
3642 Qn_(untranslated_name(&pl->adjective)))) {
3643 ruleset_error(LOG_ERROR,
3644 "Two nations defined with the same adjective \"%s\": "
3645 "in section \'%s\' and section \'%s\'",
3646 Qn_(untranslated_name(&pl->adjective)),
3647 section_name(section_list_get(sec, j)), sec_name);
3648 ok = FALSE;
3649 } else if (!strcmp(rule_name_get(&n2->adjective),
3650 rule_name_get(&pl->adjective))) {
3651 /* We cannot have the same rule name, as the game needs them to be
3652 * distinct. */
3653 ruleset_error(LOG_ERROR,
3654 "Two nations defined with the same rule_name \"%s\": "
3655 "in section \'%s\' and section \'%s\'",
3656 rule_name_get(&pl->adjective),
3657 section_name(section_list_get(sec, j)), sec_name);
3658 ok = FALSE;
3659 } else if (0 == strcmp(Qn_(untranslated_name(&n2->noun_plural)),
3660 Qn_(untranslated_name(&pl->noun_plural)))) {
3661 /* We don't want identical English plural names either. */
3662 ruleset_error(LOG_ERROR,
3663 "Two nations defined with the same plural name \"%s\": "
3664 "in section \'%s\' and section \'%s\'",
3665 Qn_(untranslated_name(&pl->noun_plural)),
3666 section_name(section_list_get(sec, j)), sec_name);
3667 ok = FALSE;
3670 if (!ok) {
3671 break;
3673 } nations_iterate_end;
3676 section_list_destroy(sec);
3678 if (ok) {
3679 sec = secfile_sections_by_name_prefix(file, NATION_GROUP_SECTION_PREFIX);
3680 if (sec) {
3681 section_list_iterate(sec, psection) {
3682 struct nation_group *pgroup;
3683 const char *name;
3685 name = secfile_lookup_str(file, "%s.name", section_name(psection));
3686 if (NULL == name) {
3687 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3688 ok = FALSE;
3689 break;
3691 pgroup = nation_group_new(name);
3692 if (pgroup == NULL) {
3693 ok = FALSE;
3694 break;
3696 } section_list_iterate_end;
3697 section_list_destroy(sec);
3698 sec = NULL;
3702 return ok;
3705 /**************************************************************************
3706 Check if a string is in a vector (case-insensitively).
3707 **************************************************************************/
3708 static bool is_on_allowed_list(const char *name, const char **list, size_t len)
3710 int i;
3712 for (i = 0; i < len; i++) {
3713 if (!fc_strcasecmp(name, list[i])) {
3714 return TRUE;
3717 return FALSE;
3720 /****************************************************************************
3721 This function loads a city name list from a section file. The file and
3722 two section names (which will be concatenated) are passed in.
3723 ****************************************************************************/
3724 static bool load_city_name_list(struct section_file *file,
3725 struct nation_type *pnation,
3726 const char *secfile_str1,
3727 const char *secfile_str2,
3728 const char **allowed_terrains,
3729 size_t atcount)
3731 size_t dim, j;
3732 bool ok = TRUE;
3733 const char **cities = secfile_lookup_str_vec(file, &dim, "%s.%s",
3734 secfile_str1, secfile_str2);
3736 /* Each string will be of the form "<cityname> (<label>, <label>, ...)".
3737 * The cityname is just the name for this city, while each "label" matches
3738 * a terrain type for the city (or "river"), with a preceeding ! to negate
3739 * it. The parentheses are optional (but necessary to have the settings,
3740 * of course). Our job is now to parse it. */
3741 for (j = 0; j < dim; j++) {
3742 size_t len = strlen(cities[j]);
3743 char city_name[len + 1], *p, *next, *end;
3744 struct nation_city *pncity;
3746 sz_strlcpy(city_name, cities[j]);
3748 /* Now we wish to determine values for all of the city labels. A value
3749 * of NCP_NONE means no preference (which is necessary so that the use
3750 * of this is optional); NCP_DISLIKE means the label is negated and
3751 * NCP_LIKE means it's labelled. Mostly the parsing just involves
3752 * a lot of ugly string handling... */
3753 if ((p = strchr(city_name, '('))) {
3754 *p++ = '\0';
3756 if (!(end = strchr(p, ')'))) {
3757 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
3758 "unmatched parenthesis.", secfile_name(file),
3759 secfile_str1, secfile_str2, cities[j]);
3760 ok = FALSE;
3761 } else {
3762 for (*end++ = '\0'; '\0' != *end; end++) {
3763 if (!fc_isspace(*end)) {
3764 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
3765 "contains characters after last parenthesis.",
3766 secfile_name(file), secfile_str1, secfile_str2,
3767 cities[j]);
3768 ok = FALSE;
3769 break;
3775 /* Build the nation_city. */
3776 remove_leading_trailing_spaces(city_name);
3777 if (check_name(city_name)) {
3778 /* The ruleset contains a name that is too long. This shouldn't
3779 * happen - if it does, the author should get immediate feedback. */
3780 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
3781 "is too long.", secfile_name(file),
3782 secfile_str1, secfile_str2, city_name);
3783 ok = FALSE;
3784 city_name[MAX_LEN_NAME - 1] = '\0';
3786 pncity = nation_city_new(pnation, city_name);
3788 if (NULL != p) {
3789 /* Handle the labels one at a time. */
3790 do {
3791 enum nation_city_preference prefer;
3793 if ((next = strchr(p, ','))) {
3794 *next = '\0';
3796 remove_leading_trailing_spaces(p);
3798 /* The ! is used to mark a negative, which is recorded with
3799 * NCP_DISLIKE. Otherwise we use a NCP_LIKE.
3801 if (*p == '!') {
3802 p++;
3803 prefer = NCP_DISLIKE;
3804 } else {
3805 prefer = NCP_LIKE;
3808 if (0 == fc_strcasecmp(p, "river")) {
3809 if (game.server.ruledit.allowed_terrains != NULL
3810 && !is_on_allowed_list(p,
3811 game.server.ruledit.allowed_terrains, atcount)) {
3812 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
3813 "has terrain hint \"%s\" not in allowed_terrains.",
3814 secfile_name(file), secfile_str1, secfile_str2,
3815 city_name, p);
3816 ok = FALSE;
3817 } else {
3818 nation_city_set_river_preference(pncity, prefer);
3820 } else {
3821 const struct terrain *pterrain = terrain_by_rule_name(p);
3823 if (NULL == pterrain) {
3824 /* Try with removing frequent trailing 's'. */
3825 size_t l = strlen(p);
3827 if (0 < l && 's' == fc_tolower(p[l - 1])) {
3828 p[l - 1] = '\0';
3830 pterrain = terrain_by_rule_name(p);
3833 /* Nationset may have been devised with a specific set of terrains
3834 * in mind which don't quite match this ruleset, in which case we
3835 * (a) quietly ignore any hints mentioned that don't happen to be in
3836 * the current ruleset, (b) enforce that terrains mentioned by nations
3837 * must be on the list */
3838 if (pterrain != NULL && game.server.ruledit.allowed_terrains != NULL) {
3839 if (!is_on_allowed_list(p,
3840 game.server.ruledit.allowed_terrains, atcount)) {
3841 /* Terrain exists, but not intended for these nations */
3842 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
3843 "has terrain hint \"%s\" not in allowed_terrains.",
3844 secfile_name(file), secfile_str1, secfile_str2,
3845 city_name, p);
3846 ok = FALSE;
3847 break;
3849 } else if (!pterrain) {
3850 /* Terrain doesn't exist; only complain if it's not on any list */
3851 if (game.server.ruledit.allowed_terrains == NULL
3852 || !is_on_allowed_list(p,
3853 game.server.ruledit.allowed_terrains, atcount)) {
3854 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
3855 "has unknown terrain hint \"%s\".",
3856 secfile_name(file), secfile_str1, secfile_str2,
3857 city_name, p);
3858 ok = FALSE;
3859 break;
3862 if (NULL != pterrain) {
3863 nation_city_set_terrain_preference(pncity, pterrain, prefer);
3867 p = next ? next + 1 : NULL;
3868 } while (NULL != p && '\0' != *p);
3872 if (NULL != cities) {
3873 free(cities);
3876 return ok;
3879 /**************************************************************************
3880 Load nations.ruleset file
3881 **************************************************************************/
3882 static bool load_ruleset_nations(struct section_file *file)
3884 struct government *gov;
3885 int j;
3886 size_t dim;
3887 char temp_name[MAX_LEN_NAME];
3888 const char **vec;
3889 const char *name, *bad_leader;
3890 const char *sval;
3891 int default_set;
3892 const char *filename = secfile_name(file);
3893 struct section_list *sec;
3894 enum trait tr;
3895 bool ok = TRUE;
3897 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
3898 return FALSE;
3901 name = secfile_lookup_str_default(file, NULL, "ruledit.nationlist");
3902 if (name != NULL) {
3903 game.server.ruledit.nationlist = fc_strdup(name);
3905 vec = secfile_lookup_str_vec(file, &game.server.ruledit.embedded_nations_count,
3906 "ruledit.embedded_nations");
3908 if (vec != NULL) {
3909 /* Copy to persistent vector */
3910 game.server.ruledit.embedded_nations
3911 = fc_malloc(game.server.ruledit.embedded_nations_count * sizeof(char *));
3913 for (j = 0; j < game.server.ruledit.embedded_nations_count; j++) {
3914 game.server.ruledit.embedded_nations[j] = fc_strdup(vec[j]);
3917 free(vec);
3920 game.default_government = NULL;
3922 ruleset_load_traits(game.server.default_traits, file, "default_traits", "");
3923 for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
3924 if (game.server.default_traits[tr].min < 0) {
3925 game.server.default_traits[tr].min = TRAIT_DEFAULT_VALUE;
3927 if (game.server.default_traits[tr].max < 0) {
3928 game.server.default_traits[tr].max = TRAIT_DEFAULT_VALUE;
3930 if (game.server.default_traits[tr].fixed < 0) {
3931 int diff = game.server.default_traits[tr].max - game.server.default_traits[tr].min;
3933 /* TODO: Should sometimes round the a / 2 = x.5 results up */
3934 game.server.default_traits[tr].fixed = diff / 2 + game.server.default_traits[tr].min;
3936 if (game.server.default_traits[tr].max < game.server.default_traits[tr].min) {
3937 ruleset_error(LOG_ERROR, "Default values for trait %s not sane.",
3938 trait_name(tr));
3939 ok = FALSE;
3940 break;
3944 if (ok) {
3945 vec = secfile_lookup_str_vec(file, &game.server.ruledit.ag_count,
3946 "compatibility.allowed_govs");
3947 if (vec != NULL) {
3948 /* Copy to persistent vector */
3949 game.server.ruledit.nc_agovs
3950 = fc_malloc(game.server.ruledit.ag_count * sizeof(char *));
3951 game.server.ruledit.allowed_govs =
3952 (const char **)game.server.ruledit.nc_agovs;
3954 for (j = 0; j < game.server.ruledit.ag_count; j++) {
3955 game.server.ruledit.allowed_govs[j] = fc_strdup(vec[j]);
3958 free(vec);
3961 vec = secfile_lookup_str_vec(file, &game.server.ruledit.at_count,
3962 "compatibility.allowed_terrains");
3963 if (vec != NULL) {
3964 /* Copy to persistent vector */
3965 game.server.ruledit.nc_aterrs
3966 = fc_malloc(game.server.ruledit.at_count * sizeof(char *));
3967 game.server.ruledit.allowed_terrains =
3968 (const char **)game.server.ruledit.nc_aterrs;
3970 for (j = 0; j < game.server.ruledit.at_count; j++) {
3971 game.server.ruledit.allowed_terrains[j] = fc_strdup(vec[j]);
3974 free(vec);
3977 vec = secfile_lookup_str_vec(file, &game.server.ruledit.as_count,
3978 "compatibility.allowed_styles");
3979 if (vec != NULL) {
3980 /* Copy to persistent vector */
3981 game.server.ruledit.nc_astyles
3982 = fc_malloc(game.server.ruledit.as_count * sizeof(char *));
3983 game.server.ruledit.allowed_styles =
3984 (const char **)game.server.ruledit.nc_astyles;
3986 for (j = 0; j < game.server.ruledit.as_count; j++) {
3987 game.server.ruledit.allowed_styles[j] = fc_strdup(vec[j]);
3990 free(vec);
3993 sval = secfile_lookup_str_default(file, NULL,
3994 "compatibility.default_government");
3995 /* We deliberately don't check this against allowed_govs. It's only
3996 * specified once so not vulnerable to typos, and may usefully be set in
3997 * a specific ruleset to a gov not explicitly known by the nation set. */
3998 if (sval != NULL) {
3999 game.default_government = government_by_rule_name(sval);
4000 if (game.default_government == NULL) {
4001 ruleset_error(LOG_ERROR,
4002 "Tried to set unknown government type \"%s\" as default_government!",
4003 sval);
4004 ok = FALSE;
4005 } else {
4006 game.info.default_government_id
4007 = government_number(game.default_government);
4012 if (ok) {
4013 sec = secfile_sections_by_name_prefix(file, NATION_SET_SECTION_PREFIX);
4014 if (sec) {
4015 section_list_iterate(sec, psection) {
4016 const char *set_name, *set_rule_name, *set_description;
4018 set_name = secfile_lookup_str(file, "%s.name", section_name(psection));
4019 set_rule_name =
4020 secfile_lookup_str(file, "%s.rule_name", section_name(psection));
4021 set_description = secfile_lookup_str_default(file, "", "%s.description",
4022 section_name(psection));
4023 if (NULL == set_name || NULL == set_rule_name) {
4024 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4025 ok = FALSE;
4026 break;
4028 if (nation_set_new(set_name, set_rule_name, set_description) == NULL) {
4029 ok = FALSE;
4030 break;
4032 } section_list_iterate_end;
4033 section_list_destroy(sec);
4034 sec = NULL;
4035 } else {
4036 ruleset_error(LOG_ERROR,
4037 "At least one nation set [" NATION_SET_SECTION_PREFIX "_*] "
4038 "must be defined.");
4039 ok = FALSE;
4043 if (ok) {
4044 /* Default set that every nation is a member of. */
4045 sval = secfile_lookup_str_default(file, NULL,
4046 "compatibility.default_nationset");
4047 if (sval != NULL) {
4048 const struct nation_set *pset = nation_set_by_rule_name(sval);
4049 if (pset != NULL) {
4050 default_set = nation_set_number(pset);
4051 } else {
4052 ruleset_error(LOG_ERROR,
4053 "Unknown default_nationset \"%s\".", sval);
4054 ok = FALSE;
4056 } else if (nation_set_count() == 1) {
4057 /* If there's only one set defined, every nation is implicitly a
4058 * member of that set. */
4059 default_set = 0;
4060 } else {
4061 /* No default nation set; every nation must explicitly specify at
4062 * least one set to be a member of. */
4063 default_set = -1;
4067 if (ok) {
4068 sec = secfile_sections_by_name_prefix(file, NATION_GROUP_SECTION_PREFIX);
4069 if (sec) {
4070 section_list_iterate(sec, psection) {
4071 struct nation_group *pgroup;
4072 bool hidden;
4074 name = secfile_lookup_str(file, "%s.name", section_name(psection));
4075 pgroup = nation_group_by_rule_name(name);
4076 if (pgroup == NULL) {
4077 ok = FALSE;
4078 break;
4081 hidden = secfile_lookup_bool_default(file, FALSE, "%s.hidden",
4082 section_name(psection));
4083 nation_group_set_hidden(pgroup, hidden);
4085 if (!secfile_lookup_int(file, &j, "%s.match", section_name(psection))) {
4086 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4087 ok = FALSE;
4088 break;
4090 nation_group_set_match(pgroup, j);
4091 } section_list_iterate_end;
4092 section_list_destroy(sec);
4093 sec = NULL;
4097 if (ok) {
4098 sec = secfile_sections_by_name_prefix(file, NATION_SECTION_PREFIX);
4099 nations_iterate(pnation) {
4100 struct nation_type *pconflict;
4101 const int i = nation_index(pnation);
4102 char tmp[200] = "\0";
4103 const char *barb_type;
4104 const char *sec_name = section_name(section_list_get(sec, i));
4105 const char *legend;
4107 /* Nation sets and groups. */
4108 if (default_set >= 0) {
4109 nation_set_list_append(pnation->sets,
4110 nation_set_by_number(default_set));
4112 vec = secfile_lookup_str_vec(file, &dim, "%s.groups", sec_name);
4113 for (j = 0; j < dim; j++) {
4114 struct nation_set *pset = nation_set_by_rule_name(vec[j]);
4115 struct nation_group *pgroup = nation_group_by_rule_name(vec[j]);
4117 fc_assert(pset == NULL || pgroup == NULL);
4119 if (NULL != pset) {
4120 nation_set_list_append(pnation->sets, pset);
4121 } else if (NULL != pgroup) {
4122 nation_group_list_append(pnation->groups, pgroup);
4123 } else {
4124 /* For nation authors, this would probably be considered an error.
4125 * But it can happen normally. The civ1 compatibility ruleset only
4126 * uses the nations that were in civ1, so not all of the links will
4127 * exist. */
4128 log_verbose("Nation %s: Unknown set/group \"%s\".",
4129 nation_rule_name(pnation), vec[j]);
4132 if (NULL != vec) {
4133 free(vec);
4135 if (nation_set_list_size(pnation->sets) < 1) {
4136 ruleset_error(LOG_ERROR,
4137 "Nation %s is not a member of any nation set",
4138 nation_rule_name(pnation));
4139 ok = FALSE;
4140 break;
4143 /* Nation conflicts. */
4144 vec = secfile_lookup_str_vec(file, &dim, "%s.conflicts_with", sec_name);
4145 for (j = 0; j < dim; j++) {
4146 pconflict = nation_by_rule_name(vec[j]);
4148 if (pnation == pconflict) {
4149 ruleset_error(LOG_ERROR, "Nation %s conflicts with itself",
4150 nation_rule_name(pnation));
4151 ok = FALSE;
4152 break;
4153 } else if (NULL != pconflict) {
4154 nation_list_append(pnation->server.conflicts_with, pconflict);
4155 } else {
4156 /* For nation authors, this would probably be considered an error.
4157 * But it can happen normally. The civ1 compatibility ruleset only
4158 * uses the nations that were in civ1, so not all of the links will
4159 * exist. */
4160 log_verbose("Nation %s: conflicts_with nation \"%s\" is unknown.",
4161 nation_rule_name(pnation), vec[j]);
4164 if (NULL != vec) {
4165 free(vec);
4167 if (!ok) {
4168 break;
4171 /* Nation leaders. */
4172 for (j = 0; j < MAX_NUM_LEADERS; j++) {
4173 const char *sex;
4174 bool is_male = FALSE;
4176 name = secfile_lookup_str(file, "%s.leaders%d.name", sec_name, j);
4177 if (NULL == name) {
4178 /* No more to read. */
4179 break;
4182 if (check_name(name)) {
4183 /* The ruleset contains a name that is too long. This shouldn't
4184 * happen - if it does, the author should get immediate feedback */
4185 sz_strlcpy(temp_name, name);
4186 ruleset_error(LOG_ERROR, "Nation %s: leader name \"%s\" "
4187 "is too long.",
4188 nation_rule_name(pnation), name);
4189 ok = FALSE;
4190 break;
4193 sex = secfile_lookup_str(file, "%s.leaders%d.sex", sec_name, j);
4194 if (NULL == sex) {
4195 ruleset_error(LOG_ERROR, "Nation %s: leader \"%s\": %s.",
4196 nation_rule_name(pnation), name, secfile_error());
4197 ok = FALSE;
4198 break;
4199 } else if (0 == fc_strcasecmp("Male", sex)) {
4200 is_male = TRUE;
4201 } else if (0 != fc_strcasecmp("Female", sex)) {
4202 ruleset_error(LOG_ERROR, "Nation %s: leader \"%s\" has unsupported "
4203 "sex variant \"%s\".",
4204 nation_rule_name(pnation), name, sex);
4205 ok = FALSE;
4206 break;
4208 (void) nation_leader_new(pnation, name, is_male);
4210 if (!ok) {
4211 break;
4214 /* Check the number of leaders. */
4215 if (MAX_NUM_LEADERS == j) {
4216 /* Too much leaders, get the real number defined in the ruleset. */
4217 while (NULL != secfile_entry_lookup(file, "%s.leaders%d.name",
4218 sec_name, j)) {
4219 j++;
4221 ruleset_error(LOG_ERROR, "Nation %s: Too many leaders; max is %d",
4222 nation_rule_name(pnation), MAX_NUM_LEADERS);
4223 ok = FALSE;
4224 break;
4225 } else if (0 == j) {
4226 ruleset_error(LOG_ERROR,
4227 "Nation %s: no leaders; at least one is required.",
4228 nation_rule_name(pnation));
4229 ok = FALSE;
4230 break;
4233 /* Check if leader name is not already defined in this nation. */
4234 if ((bad_leader = check_leader_names(pnation))) {
4235 ruleset_error(LOG_ERROR,
4236 "Nation %s: leader \"%s\" defined more than once.",
4237 nation_rule_name(pnation), bad_leader);
4238 ok = FALSE;
4239 break;
4242 /* Nation player color preference, if any */
4243 fc_assert_ret_val(pnation->server.rgb == NULL, FALSE);
4244 (void) rgbcolor_load(file, &pnation->server.rgb, "%s.color", sec_name);
4246 /* Load nation traits */
4247 ruleset_load_traits(pnation->server.traits, file, sec_name, "trait_");
4248 for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
4249 bool server_traits_used = TRUE;
4251 if (pnation->server.traits[tr].min < 0) {
4252 pnation->server.traits[tr].min = game.server.default_traits[tr].min;
4253 } else {
4254 server_traits_used = FALSE;
4256 if (pnation->server.traits[tr].max < 0) {
4257 pnation->server.traits[tr].max = game.server.default_traits[tr].max;
4258 } else {
4259 server_traits_used = FALSE;
4261 if (pnation->server.traits[tr].fixed < 0) {
4262 if (server_traits_used) {
4263 pnation->server.traits[tr].fixed = game.server.default_traits[tr].fixed;
4264 } else {
4265 int diff = pnation->server.traits[tr].max - pnation->server.traits[tr].min;
4267 /* TODO: Should sometimes round the a / 2 = x.5 results up */
4268 pnation->server.traits[tr].fixed = diff / 2 + pnation->server.traits[tr].min;
4271 if (pnation->server.traits[tr].max < pnation->server.traits[tr].min) {
4272 ruleset_error(LOG_ERROR, "%s values for trait %s not sane.",
4273 nation_rule_name(pnation), trait_name(tr));
4274 ok = FALSE;
4275 break;
4279 if (!ok) {
4280 break;
4283 pnation->is_playable =
4284 secfile_lookup_bool_default(file, TRUE, "%s.is_playable", sec_name);
4286 /* Check barbarian type. Default is "None" meaning not a barbarian */
4287 barb_type = secfile_lookup_str_default(file, "None",
4288 "%s.barbarian_type", sec_name);
4289 pnation->barb_type = barbarian_type_by_name(barb_type, fc_strcasecmp);
4290 if (!barbarian_type_is_valid(pnation->barb_type)) {
4291 ruleset_error(LOG_ERROR,
4292 "Nation %s, barbarian_type is invalid (\"%s\")",
4293 nation_rule_name(pnation), barb_type);
4294 ok = FALSE;
4295 break;
4298 if (pnation->barb_type != NOT_A_BARBARIAN
4299 && pnation->is_playable) {
4300 /* We can't allow players to use barbarian nations, barbarians
4301 * may run out of nations */
4302 ruleset_error(LOG_ERROR,
4303 "Nation %s marked both barbarian and playable.",
4304 nation_rule_name(pnation));
4305 ok = FALSE;
4306 break;
4309 /* Flags */
4310 sz_strlcpy(pnation->flag_graphic_str,
4311 secfile_lookup_str_default(file, "-", "%s.flag", sec_name));
4312 sz_strlcpy(pnation->flag_graphic_alt,
4313 secfile_lookup_str_default(file, "-",
4314 "%s.flag_alt", sec_name));
4316 /* Ruler titles */
4317 for (j = 0;; j++) {
4318 const char *male, *female;
4320 name = secfile_lookup_str_default(file, NULL,
4321 "%s.ruler_titles%d.government",
4322 sec_name, j);
4323 if (NULL == name) {
4324 /* End of the list of ruler titles. */
4325 break;
4328 /* NB: even if the government doesn't exist, we load the entries for
4329 * the ruler titles to avoid warnings about unused entries. */
4330 male = secfile_lookup_str(file, "%s.ruler_titles%d.male_title",
4331 sec_name, j);
4332 female = secfile_lookup_str(file, "%s.ruler_titles%d.female_title",
4333 sec_name, j);
4334 gov = government_by_rule_name(name);
4336 /* Nationset may have been devised with a specific set of govs in
4337 * mind which don't quite match this ruleset, in which case we
4338 * (a) quietly ignore any govs mentioned that don't happen to be in
4339 * the current ruleset, (b) enforce that govs mentioned by nations
4340 * must be on the list */
4341 if (gov != NULL && game.server.ruledit.allowed_govs != NULL) {
4342 if (!is_on_allowed_list(name,
4343 game.server.ruledit.allowed_govs,
4344 game.server.ruledit.ag_count)) {
4345 /* Gov exists, but not intended for these nations */
4346 gov = NULL;
4347 ruleset_error(LOG_ERROR,
4348 "Nation %s: government \"%s\" not in allowed_govs.",
4349 nation_rule_name(pnation), name);
4350 ok = FALSE;
4351 break;
4353 } else if (!gov) {
4354 /* Gov doesn't exist; only complain if it's not on any list */
4355 if (game.server.ruledit.allowed_govs == NULL
4356 || !is_on_allowed_list(name,
4357 game.server.ruledit.allowed_govs,
4358 game.server.ruledit.ag_count)) {
4359 ruleset_error(LOG_ERROR, "Nation %s: government \"%s\" not found.",
4360 nation_rule_name(pnation), name);
4361 ok = FALSE;
4362 break;
4365 if (NULL != male && NULL != female) {
4366 if (gov) {
4367 (void) government_ruler_title_new(gov, pnation, male, female);
4369 } else {
4370 ruleset_error(LOG_ERROR, "%s", secfile_error());
4371 ok = FALSE;
4372 break;
4375 if (!ok) {
4376 break;
4379 /* City styles */
4380 name = secfile_lookup_str(file, "%s.style", sec_name);
4381 if (!name) {
4382 ruleset_error(LOG_ERROR, "%s", secfile_error());
4383 ok = FALSE;
4384 break;
4386 pnation->style = style_by_rule_name(name);
4387 if (pnation->style == NULL) {
4388 if (game.server.ruledit.allowed_styles == NULL
4389 || !is_on_allowed_list(name,
4390 game.server.ruledit.allowed_styles,
4391 game.server.ruledit.as_count)) {
4392 ruleset_error(LOG_ERROR, "Nation %s: Illegal style \"%s\"",
4393 nation_rule_name(pnation), name);
4394 ok = FALSE;
4395 break;
4396 } else {
4397 log_verbose("Nation %s: style \"%s\" not supported in this "
4398 "ruleset; using default.",
4399 nation_rule_name(pnation), name);
4400 pnation->style = style_by_number(0);
4404 /* Civilwar nations */
4405 vec = secfile_lookup_str_vec(file, &dim,
4406 "%s.civilwar_nations", sec_name);
4407 for (j = 0; j < dim; j++) {
4408 pconflict = nation_by_rule_name(vec[j]);
4410 /* No test for duplicate nations is performed. If there is a duplicate
4411 * entry it will just cause that nation to have an increased
4412 * probability of being chosen. */
4413 if (pconflict == pnation) {
4414 ruleset_error(LOG_ERROR, "Nation %s is its own civil war nation",
4415 nation_rule_name(pnation));
4416 ok = FALSE;
4417 break;
4418 } else if (NULL != pconflict) {
4419 nation_list_append(pnation->server.civilwar_nations, pconflict);
4420 nation_list_append(pconflict->server.parent_nations, pnation);
4421 } else {
4422 /* For nation authors, this would probably be considered an error.
4423 * But it can happen normally. The civ1 compatability ruleset only
4424 * uses the nations that were in civ1, so not all of the links will
4425 * exist. */
4426 log_verbose("Nation %s: civil war nation \"%s\" is unknown.",
4427 nation_rule_name(pnation), vec[j]);
4430 if (NULL != vec) {
4431 free(vec);
4433 if (!ok) {
4434 break;
4437 /* Load nation specific initial items */
4438 if (!lookup_tech_list(file, sec_name, "init_techs",
4439 pnation->init_techs, filename)) {
4440 ok = FALSE;
4441 break;
4443 if (!lookup_building_list(file, sec_name, "init_buildings",
4444 pnation->init_buildings, filename)) {
4445 ok = FALSE;
4446 break;
4448 if (!lookup_unit_list(file, sec_name, "init_units",
4449 pnation->init_units, filename)) {
4450 ok = FALSE;
4451 break;
4453 fc_strlcat(tmp, sec_name, 200);
4454 fc_strlcat(tmp, ".init_government", 200);
4455 if (secfile_entry_by_path(file, tmp)) {
4456 pnation->init_government = lookup_government(file, tmp, filename,
4457 NULL);
4458 /* If specified, init_government has to be in this specific ruleset,
4459 * not just allowed_govs */
4460 if (pnation->init_government == NULL) {
4461 ok = FALSE;
4462 break;
4464 /* ...but if a list of govs has been specified, enforce that this
4465 * nation's init_government is on the list. */
4466 if (game.server.ruledit.allowed_govs != NULL
4467 && !is_on_allowed_list(government_rule_name(pnation->init_government),
4468 game.server.ruledit.allowed_govs,
4469 game.server.ruledit.ag_count)) {
4470 ruleset_error(LOG_ERROR,
4471 "Nation %s: init_government \"%s\" not allowed.",
4472 nation_rule_name(pnation),
4473 government_rule_name(pnation->init_government));
4474 ok = FALSE;
4475 break;
4479 /* Read default city names. */
4480 if (!load_city_name_list(file, pnation, sec_name, "cities",
4481 game.server.ruledit.allowed_terrains,
4482 game.server.ruledit.at_count)) {
4483 ok = FALSE;
4484 break;
4487 legend = secfile_lookup_str_default(file, "", "%s.legend", sec_name);
4488 pnation->legend = fc_strdup(legend);
4489 if (check_strlen(pnation->legend, MAX_LEN_MSG, NULL)) {
4490 ruleset_error(LOG_ERROR,
4491 "Nation %s: legend \"%s\" is too long.",
4492 nation_rule_name(pnation),
4493 pnation->legend);
4494 ok = FALSE;
4495 break;
4498 pnation->player = NULL;
4499 } nations_iterate_end;
4500 section_list_destroy(sec);
4501 sec = NULL;
4504 /* Clean up on aborted load */
4505 if (sec) {
4506 fc_assert(!ok);
4507 section_list_destroy(sec);
4510 if (ok) {
4511 secfile_check_unused(file);
4514 if (ok) {
4515 /* Update cached number of playable nations in the current set */
4516 count_playable_nations();
4518 /* Sanity checks on all sets */
4519 nation_sets_iterate(pset) {
4520 int num_playable = 0, barb_land_count = 0, barb_sea_count = 0;
4521 nations_iterate(pnation) {
4522 if (nation_is_in_set(pnation, pset)) {
4523 switch (nation_barbarian_type(pnation)) {
4524 case NOT_A_BARBARIAN:
4525 if (is_nation_playable(pnation)) {
4526 num_playable++;
4528 break;
4529 case LAND_BARBARIAN:
4530 barb_land_count++;
4531 break;
4532 case SEA_BARBARIAN:
4533 barb_sea_count++;
4534 break;
4535 case ANIMAL_BARBARIAN:
4536 /* Animals are optional */
4537 break;
4538 default:
4539 fc_assert_ret_val(FALSE, FALSE);
4542 } nations_iterate_end;
4543 if (num_playable < 1) {
4544 ruleset_error(LOG_ERROR,
4545 "Nation set \"%s\" has no playable nations. "
4546 "At least one required!", nation_set_rule_name(pset));
4547 ok = FALSE;
4548 break;
4550 if (barb_land_count == 0) {
4551 ruleset_error(LOG_ERROR,
4552 "No land barbarian nation defined in set \"%s\". "
4553 "At least one required!", nation_set_rule_name(pset));
4554 ok = FALSE;
4555 break;
4557 if (barb_sea_count == 0) {
4558 ruleset_error(LOG_ERROR,
4559 "No sea barbarian nation defined in set \"%s\". "
4560 "At least one required!", nation_set_rule_name(pset));
4561 ok = FALSE;
4562 break;
4564 } nation_sets_iterate_end;
4567 return ok;
4570 /**************************************************************************
4571 Load names of nation styles so other rulesets can refer to styles with
4572 their name.
4573 **************************************************************************/
4574 static bool load_style_names(struct section_file *file)
4576 bool ok = TRUE;
4577 struct section_list *sec;
4579 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
4580 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
4582 sec = secfile_sections_by_name_prefix(file, STYLE_SECTION_PREFIX);
4583 if (NULL == sec) {
4584 ruleset_error(LOG_ERROR, "No available nation styles in this ruleset!");
4585 ok = FALSE;
4586 } else {
4587 game.control.num_styles = section_list_size(sec);
4589 styles_alloc(game.control.num_styles);
4591 styles_iterate(ps) {
4592 const int i = style_index(ps);
4593 const char *sec_name = section_name(section_list_get(sec, i));
4595 ruleset_load_names(&ps->name, NULL, file, sec_name);
4596 } styles_iterate_end;
4599 section_list_destroy(sec);
4601 if (ok) {
4602 /* The citystyle sections: */
4603 int i = 0;
4605 sec = secfile_sections_by_name_prefix(file, CITYSTYLE_SECTION_PREFIX);
4606 if (NULL != sec) {
4607 city_styles_alloc(section_list_size(sec));
4608 section_list_iterate(sec, style) {
4609 if (!ruleset_load_names(&city_styles[i].name, NULL, file, section_name(style))) {
4610 ok = FALSE;
4611 break;
4613 i++;
4614 } section_list_iterate_end;
4616 section_list_destroy(sec);
4617 } else {
4618 city_styles_alloc(0);
4622 return ok;
4625 /**************************************************************************
4626 Load styles.ruleset file
4627 **************************************************************************/
4628 static bool load_ruleset_styles(struct section_file *file)
4630 const char *filename = secfile_name(file);
4631 struct section_list *sec;
4632 int i;
4633 bool ok = TRUE;
4635 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
4636 return FALSE;
4639 /* City Styles ... */
4641 sec = secfile_sections_by_name_prefix(file, CITYSTYLE_SECTION_PREFIX);
4643 /* Get rest: */
4644 for (i = 0; i < game.control.styles_count; i++) {
4645 struct requirement_vector *reqs;
4646 const char *sec_name = section_name(section_list_get(sec, i));
4648 sz_strlcpy(city_styles[i].graphic,
4649 secfile_lookup_str(file, "%s.graphic", sec_name));
4650 sz_strlcpy(city_styles[i].graphic_alt,
4651 secfile_lookup_str(file, "%s.graphic_alt", sec_name));
4652 sz_strlcpy(city_styles[i].citizens_graphic,
4653 secfile_lookup_str_default(file, "-",
4654 "%s.citizens_graphic", sec_name));
4655 sz_strlcpy(city_styles[i].citizens_graphic_alt,
4656 secfile_lookup_str_default(file, "generic",
4657 "%s.citizens_graphic_alt", sec_name));
4659 reqs = lookup_req_list(file, sec_name, "reqs", city_style_rule_name(i));
4660 if (reqs == NULL) {
4661 ok = FALSE;
4662 break;
4664 requirement_vector_copy(&city_styles[i].reqs, reqs);
4667 section_list_destroy(sec);
4669 if (ok) {
4670 sec = secfile_sections_by_name_prefix(file, MUSICSTYLE_SECTION_PREFIX);
4672 if (sec != NULL) {
4673 int musi;
4675 game.control.num_music_styles = section_list_size(sec);
4676 music_styles_alloc(game.control.num_music_styles);
4677 musi = 0;
4679 section_list_iterate(sec, psection) {
4680 struct requirement_vector *reqs;
4681 struct music_style *pmus = music_style_by_number(musi);
4682 const char *sec_name = section_name(psection);
4684 sz_strlcpy(pmus->music_peaceful,
4685 secfile_lookup_str_default(file, "-",
4686 "%s.music_peaceful", sec_name));
4687 sz_strlcpy(pmus->music_combat,
4688 secfile_lookup_str_default(file, "-",
4689 "%s.music_combat", sec_name));
4691 reqs = lookup_req_list(file, sec_name, "reqs", "Music Style");
4692 if (reqs == NULL) {
4693 ok = FALSE;
4694 break;
4696 requirement_vector_copy(&pmus->reqs, reqs);
4698 musi++;
4699 } section_list_iterate_end;
4702 section_list_destroy(sec);
4705 return ok;
4708 /**************************************************************************
4709 Load cities.ruleset file
4710 **************************************************************************/
4711 static bool load_ruleset_cities(struct section_file *file)
4713 const char *filename = secfile_name(file);
4714 const char *item;
4715 struct section_list *sec;
4716 bool ok = TRUE;
4718 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
4719 return FALSE;
4722 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
4723 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
4725 /* Specialist options */
4726 sec = secfile_sections_by_name_prefix(file, SPECIALIST_SECTION_PREFIX);
4727 if (section_list_size(sec) >= SP_MAX) {
4728 ruleset_error(LOG_ERROR, "\"%s\": Too many specialists (%d, max %d).",
4729 filename, section_list_size(sec), SP_MAX);
4730 ok = FALSE;
4733 if (ok) {
4734 int i = 0;
4736 game.control.num_specialist_types = section_list_size(sec);
4738 section_list_iterate(sec, psection) {
4739 struct specialist *s = specialist_by_number(i);
4740 struct requirement_vector *reqs;
4741 const char *sec_name = section_name(psection);
4743 if (!ruleset_load_names(&s->name, NULL, file, sec_name)) {
4744 ok = FALSE;
4745 break;
4748 item = secfile_lookup_str_default(file, untranslated_name(&s->name),
4749 "%s.short_name", sec_name);
4750 name_set(&s->abbreviation, NULL, item);
4752 sz_strlcpy(s->graphic_alt,
4753 secfile_lookup_str_default(file, "-",
4754 "%s.graphic_alt", sec_name));
4756 reqs = lookup_req_list(file, sec_name, "reqs", specialist_rule_name(s));
4757 if (reqs == NULL) {
4758 ok = FALSE;
4759 break;
4761 requirement_vector_copy(&s->reqs, reqs);
4763 s->helptext = lookup_strvec(file, sec_name, "helptext");
4765 if (requirement_vector_size(&s->reqs) == 0 && DEFAULT_SPECIALIST == -1) {
4766 DEFAULT_SPECIALIST = i;
4768 i++;
4769 } section_list_iterate_end;
4772 if (ok && DEFAULT_SPECIALIST == -1) {
4773 ruleset_error(LOG_ERROR,
4774 "\"%s\": must give a min_size of 0 for at least one "
4775 "specialist type.", filename);
4776 ok = FALSE;
4778 section_list_destroy(sec);
4779 sec = NULL;
4781 if (ok) {
4782 /* City Parameters */
4784 game.info.celebratesize =
4785 secfile_lookup_int_default(file, GAME_DEFAULT_CELEBRATESIZE,
4786 "parameters.celebrate_size_limit");
4787 game.info.add_to_size_limit =
4788 secfile_lookup_int_default(file, GAME_DEFAULT_ADDTOSIZE, "parameters.add_to_size_limit");
4789 game.info.angrycitizen =
4790 secfile_lookup_bool_default(file, GAME_DEFAULT_ANGRYCITIZEN,
4791 "parameters.angry_citizens");
4793 game.info.changable_tax =
4794 secfile_lookup_bool_default(file, GAME_DEFAULT_CHANGABLE_TAX, "parameters.changable_tax");
4795 game.info.forced_science =
4796 secfile_lookup_int_default(file, 0, "parameters.forced_science");
4797 game.info.forced_luxury =
4798 secfile_lookup_int_default(file, 100, "parameters.forced_luxury");
4799 game.info.forced_gold =
4800 secfile_lookup_int_default(file, 0, "parameters.forced_gold");
4801 if (game.info.forced_science + game.info.forced_luxury
4802 + game.info.forced_gold != 100) {
4803 ruleset_error(LOG_ERROR,
4804 "\"%s\": Forced taxes do not add up in ruleset!",
4805 filename);
4806 ok = FALSE;
4810 if (ok) {
4811 /* civ1 & 2 didn't reveal tiles */
4812 game.server.vision_reveal_tiles =
4813 secfile_lookup_bool_default(file, GAME_DEFAULT_VISION_REVEAL_TILES,
4814 "parameters.vision_reveal_tiles");
4816 game.info.pop_report_zeroes =
4817 secfile_lookup_int_default(file, 1, "parameters.pop_report_zeroes");
4819 /* Citizens configuration. */
4820 game.info.citizen_nationality =
4821 secfile_lookup_bool_default(file, GAME_DEFAULT_NATIONALITY,
4822 "citizen.nationality");
4823 game.info.citizen_convert_speed =
4824 secfile_lookup_int_default(file, GAME_DEFAULT_CONVERT_SPEED,
4825 "citizen.convert_speed");
4826 game.info.citizen_partisans_pct =
4827 secfile_lookup_int_default(file, 0, "citizen.partisans_pct");
4830 if (ok) {
4831 secfile_check_unused(file);
4834 return ok;
4837 /**************************************************************************
4838 Load effects.ruleset file
4839 **************************************************************************/
4840 static bool load_ruleset_effects(struct section_file *file)
4842 struct section_list *sec;
4843 const char *type;
4844 const char *filename;
4845 bool ok = TRUE;
4846 bool effect_type_warned = FALSE;
4848 filename = secfile_name(file);
4849 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
4850 return FALSE;
4852 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
4853 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
4855 /* Parse effects and add them to the effects ruleset cache. */
4856 sec = secfile_sections_by_name_prefix(file, EFFECT_SECTION_PREFIX);
4857 section_list_iterate(sec, psection) {
4858 enum effect_type eff;
4859 int value;
4860 struct multiplier *pmul;
4861 struct effect *peffect;
4862 const char *sec_name = section_name(psection);
4863 struct requirement_vector *reqs;
4865 type = secfile_lookup_str(file, "%s.type", sec_name);
4866 if (type == NULL) {
4867 /* Backward compatibility. Field used to be named "name" */
4868 type = secfile_lookup_str(file, "%s.name", sec_name);
4869 if (type != NULL && !effect_type_warned) {
4870 log_deprecation(_("Effects should have \"type\", not the same field with old name \"name\"."));
4871 effect_type_warned = TRUE;
4874 if (type == NULL) {
4875 ruleset_error(LOG_ERROR, "\"%s\" [%s] missing effect name.", filename, sec_name);
4876 ok = FALSE;
4877 break;
4880 eff = effect_type_by_name(type, fc_strcasecmp);
4881 if (!effect_type_is_valid(eff)) {
4882 ruleset_error(LOG_ERROR, "\"%s\" [%s] lists unknown effect type \"%s\".",
4883 filename, sec_name, type);
4884 ok = FALSE;
4885 break;
4888 value = secfile_lookup_int_default(file, 1, "%s.value", sec_name);
4891 const char *multiplier_name
4892 = secfile_lookup_str(file, "%s.multiplier", sec_name);
4894 if (multiplier_name) {
4895 pmul = multiplier_by_rule_name(multiplier_name);
4896 if (!pmul) {
4897 ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown multiplier \"%s\".",
4898 filename, sec_name, multiplier_name);
4899 ok = FALSE;
4900 break;
4902 } else {
4903 pmul = NULL;
4907 peffect = effect_new(eff, value, pmul);
4909 reqs = lookup_req_list(file, sec_name, "reqs", type);
4910 if (reqs == NULL) {
4911 ok = FALSE;
4912 break;
4915 requirement_vector_iterate(reqs, preq) {
4916 effect_req_append(peffect, *preq);
4917 } requirement_vector_iterate_end;
4919 reqs = lookup_req_list(file, sec_name, "nreqs", type);
4920 if (reqs == NULL) {
4921 ok = FALSE;
4922 break;
4924 requirement_vector_iterate(reqs, preq) {
4925 preq->present = !preq->present;
4926 effect_req_append(peffect, *preq);
4927 } requirement_vector_iterate_end;
4928 } section_list_iterate_end;
4929 section_list_destroy(sec);
4931 if (ok) {
4932 secfile_check_unused(file);
4935 return ok;
4938 /**************************************************************************
4939 Print an error message if the value is out of range.
4940 **************************************************************************/
4941 static int secfile_lookup_int_default_min_max(struct section_file *file,
4942 int def, int min, int max,
4943 const char *path, ...)
4944 fc__attribute((__format__ (__printf__, 5, 6)));
4945 static int secfile_lookup_int_default_min_max(struct section_file *file,
4946 int def, int min, int max,
4947 const char *path, ...)
4949 char fullpath[256];
4950 int ival;
4951 va_list args;
4953 va_start(args, path);
4954 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
4955 va_end(args);
4957 if (!secfile_lookup_int(file, &ival, "%s", fullpath)) {
4958 ival = def;
4961 if (ival < min) {
4962 ruleset_error(LOG_ERROR,"\"%s\" should be in the interval [%d, %d] "
4963 "but is %d; using the minimal value.",
4964 fullpath, min, max, ival);
4965 ival = min;
4968 if (ival > max) {
4969 ruleset_error(LOG_ERROR,"\"%s\" should be in the interval [%d, %d] "
4970 "but is %d; using the maximal value.",
4971 fullpath, min, max, ival);
4972 ival = max;
4975 return ival;
4978 /**************************************************************************
4979 Load ruleset file.
4980 **************************************************************************/
4981 static bool load_ruleset_game(struct section_file *file, bool act)
4983 const char *sval, **svec;
4984 const char *filename;
4985 int *food_ini;
4986 int i;
4987 size_t teams;
4988 const char *pref_text;
4989 size_t gni_tmp;
4990 struct section_list *sec;
4991 size_t nval;
4992 const char *name;
4993 bool ok = TRUE;
4995 if (file == NULL) {
4996 return FALSE;
4998 filename = secfile_name(file);
5000 /* section: datafile */
5001 if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
5002 return FALSE;
5004 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
5005 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
5007 name = secfile_lookup_str_default(file, NULL, "ruledit.description_file");
5008 if (name != NULL) {
5009 game.server.ruledit.description_file = fc_strdup(name);
5012 /* section: tileset */
5013 pref_text = secfile_lookup_str_default(file, "", "tileset.prefered");
5014 if (pref_text[0] != '\0') {
5015 log_deprecation("Entry tileset.prefered in game.ruleset."
5016 " Use correct spelling tileset.preferred instead");
5018 pref_text = secfile_lookup_str_default(file, pref_text, "tileset.preferred");
5019 if (pref_text[0] != '\0') {
5020 /* There was tileset suggestion */
5021 sz_strlcpy(game.control.preferred_tileset, pref_text);
5022 } else {
5023 /* No tileset suggestions */
5024 game.control.preferred_tileset[0] = '\0';
5027 /* section: soundset */
5028 pref_text = secfile_lookup_str_default(file, "", "soundset.prefered");
5029 if (pref_text[0] != '\0') {
5030 log_deprecation("Entry soundset.prefered in game.ruleset."
5031 " Use correct spelling soundset.preferred instead");
5033 pref_text = secfile_lookup_str_default(file, pref_text, "soundset.preferred");
5034 if (pref_text[0] != '\0') {
5035 /* There was soundset suggestion */
5036 sz_strlcpy(game.control.preferred_soundset, pref_text);
5037 } else {
5038 /* No soundset suggestions */
5039 game.control.preferred_soundset[0] = '\0';
5042 /* section: musicset */
5043 pref_text = secfile_lookup_str_default(file, "", "musicset.prefered");
5044 if (pref_text[0] != '\0') {
5045 log_deprecation("Entry musicset.prefered in game.ruleset."
5046 " Use correct spelling musicset.preferred instead");
5048 pref_text = secfile_lookup_str_default(file, pref_text, "musicset.preferred");
5049 if (pref_text[0] != '\0') {
5050 /* There was musicset suggestion */
5051 sz_strlcpy(game.control.preferred_musicset, pref_text);
5052 } else {
5053 /* No musicset suggestions */
5054 game.control.preferred_musicset[0] = '\0';
5057 /* section: about */
5058 pref_text = secfile_lookup_str(file, "about.name");
5059 /* Ruleset/modpack name found */
5060 sz_strlcpy(game.control.name, pref_text);
5062 pref_text = secfile_lookup_str_default(file, "", "about.version");
5063 if (pref_text[0] != '\0') {
5064 /* Ruleset/modpack version found */
5065 sz_strlcpy(game.control.version, pref_text);
5066 } else {
5067 /* No version information */
5068 game.control.version[0] = '\0';
5071 pref_text = secfile_lookup_str_default(file, "", "about.summary");
5072 if (pref_text[0] != '\0') {
5073 int len;
5075 /* Ruleset/modpack summary found */
5076 len = strlen(pref_text);
5077 game.ruleset_summary = fc_malloc(len + 1);
5078 fc_strlcpy(game.ruleset_summary, pref_text, len + 1);
5079 } else {
5080 /* No summary */
5081 if (game.ruleset_summary != NULL) {
5082 free(game.ruleset_summary);
5083 game.ruleset_summary = NULL;
5087 pref_text = secfile_lookup_str_default(file, "", "about.description");
5088 if (pref_text[0] != '\0') {
5089 int len;
5091 /* Ruleset/modpack description found */
5092 len = strlen(pref_text);
5093 game.ruleset_description = fc_malloc(len + 1);
5094 fc_strlcpy(game.ruleset_description, pref_text, len + 1);
5095 game.control.desc_length = len;
5096 } else {
5097 /* No description */
5098 if (game.ruleset_description != NULL) {
5099 free(game.ruleset_description);
5100 game.ruleset_description = NULL;
5102 game.control.desc_length = 0;
5105 /* section: options */
5106 if (!lookup_tech_list(file, "options", "global_init_techs",
5107 game.rgame.global_init_techs, filename)) {
5108 ok = FALSE;
5111 if (ok) {
5112 if (!lookup_building_list(file, "options", "global_init_buildings",
5113 game.rgame.global_init_buildings, filename)) {
5114 ok = FALSE;
5118 if (ok) {
5119 const char **slist;
5120 int j;
5122 game.control.popup_tech_help = secfile_lookup_bool_default(file, FALSE,
5123 "options.popup_tech_help");
5125 /* section: civstyle */
5126 game.info.base_pollution
5127 = secfile_lookup_int_default(file, RS_DEFAULT_BASE_POLLUTION,
5128 "civstyle.base_pollution");
5130 game.info.gameloss_style = GAMELOSS_STYLE_CLASSICAL;
5132 slist = secfile_lookup_str_vec(file, &nval, "civstyle.gameloss_style");
5133 for (j = 0; j < nval; j++) {
5134 enum gameloss_style style;
5136 sval = slist[j];
5137 if (strcmp(sval, "") == 0) {
5138 continue;
5140 style = gameloss_style_by_name(sval, fc_strcasecmp);
5141 if (!gameloss_style_is_valid(style)) {
5142 ruleset_error(LOG_ERROR, "\"%s\": bad value \"%s\" for gameloss_style.",
5143 filename, sval);
5144 ok = FALSE;
5145 break;
5146 } else {
5147 game.info.gameloss_style |= style;
5150 free(slist);
5153 if (ok) {
5154 game.info.happy_cost
5155 = secfile_lookup_int_def_min_max(file,
5156 RS_DEFAULT_HAPPY_COST,
5157 RS_MIN_HAPPY_COST,
5158 RS_MAX_HAPPY_COST,
5159 "civstyle.happy_cost");
5160 game.info.food_cost
5161 = secfile_lookup_int_default_min_max(file,
5162 RS_DEFAULT_FOOD_COST,
5163 RS_MIN_FOOD_COST,
5164 RS_MAX_FOOD_COST,
5165 "civstyle.food_cost");
5166 game.info.civil_war_enabled
5167 = secfile_lookup_bool_default(file, TRUE, "civstyle.civil_war_enabled");
5169 game.info.paradrop_to_transport
5170 = secfile_lookup_bool_default(file, FALSE,
5171 "civstyle.paradrop_to_transport");
5173 /* TODO: move to global_unit_options */
5174 game.info.base_bribe_cost
5175 = secfile_lookup_int_default_min_max(file,
5176 RS_DEFAULT_BASE_BRIBE_COST,
5177 RS_MIN_BASE_BRIBE_COST,
5178 RS_MAX_BASE_BRIBE_COST,
5179 "civstyle.base_bribe_cost");
5180 /* TODO: move to global_unit_options */
5181 game.server.ransom_gold
5182 = secfile_lookup_int_default_min_max(file,
5183 RS_DEFAULT_RANSOM_GOLD,
5184 RS_MIN_RANSOM_GOLD,
5185 RS_MAX_RANSOM_GOLD,
5186 "civstyle.ransom_gold");
5187 /* TODO: move to global_unit_options */
5188 game.info.pillage_select
5189 = secfile_lookup_bool_default(file, RS_DEFAULT_PILLAGE_SELECT,
5190 "civstyle.pillage_select");
5192 game.info.tech_steal_allow_holes
5193 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_STEAL_HOLES,
5194 "civstyle.tech_steal_allow_holes");
5195 game.info.tech_trade_allow_holes
5196 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_TRADE_HOLES,
5197 "civstyle.tech_trade_allow_holes");
5198 game.info.tech_trade_loss_allow_holes
5199 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_TRADE_LOSS_HOLES,
5200 "civstyle.tech_trade_loss_allow_holes");
5201 game.info.tech_parasite_allow_holes
5202 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_PARASITE_HOLES,
5203 "civstyle.tech_parasite_allow_holes");
5204 game.info.tech_loss_allow_holes
5205 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_LOSS_HOLES,
5206 "civstyle.tech_loss_allow_holes");
5208 /* TODO: move to global_unit_options */
5209 game.server.upgrade_veteran_loss
5210 = secfile_lookup_int_default_min_max(file,
5211 RS_DEFAULT_UPGRADE_VETERAN_LOSS,
5212 RS_MIN_UPGRADE_VETERAN_LOSS,
5213 RS_MAX_UPGRADE_VETERAN_LOSS,
5214 "civstyle.upgrade_veteran_loss");
5215 /* TODO: move to global_unit_options */
5216 game.server.autoupgrade_veteran_loss
5217 = secfile_lookup_int_default_min_max(file,
5218 RS_DEFAULT_UPGRADE_VETERAN_LOSS,
5219 RS_MIN_UPGRADE_VETERAN_LOSS,
5220 RS_MAX_UPGRADE_VETERAN_LOSS,
5221 "civstyle.autoupgrade_veteran_loss");
5223 game.info.base_tech_cost
5224 = secfile_lookup_int_default_min_max(file,
5225 RS_DEFAULT_BASE_TECH_COST,
5226 RS_MIN_BASE_TECH_COST,
5227 RS_MAX_BASE_TECH_COST,
5228 "research.base_tech_cost");
5230 food_ini = secfile_lookup_int_vec(file, &gni_tmp,
5231 "civstyle.granary_food_ini");
5232 game.info.granary_num_inis = (int) gni_tmp;
5234 if (game.info.granary_num_inis > MAX_GRANARY_INIS) {
5235 ruleset_error(LOG_ERROR,
5236 "Too many granary_food_ini entries (%d, max %d)",
5237 game.info.granary_num_inis, MAX_GRANARY_INIS);
5238 ok = FALSE;
5239 } else if (game.info.granary_num_inis == 0) {
5240 log_error("No values for granary_food_ini. Using default "
5241 "value %d.", RS_DEFAULT_GRANARY_FOOD_INI);
5242 game.info.granary_num_inis = 1;
5243 game.info.granary_food_ini[0] = RS_DEFAULT_GRANARY_FOOD_INI;
5244 } else {
5245 int gi;
5247 /* check for <= 0 entries */
5248 for (gi = 0; gi < game.info.granary_num_inis; gi++) {
5249 if (food_ini[gi] <= 0) {
5250 if (gi == 0) {
5251 food_ini[gi] = RS_DEFAULT_GRANARY_FOOD_INI;
5252 } else {
5253 food_ini[gi] = food_ini[gi - 1];
5255 log_error("Bad value for granary_food_ini[%i]. Using %i.",
5256 gi, food_ini[gi]);
5258 game.info.granary_food_ini[gi] = food_ini[gi];
5261 free(food_ini);
5264 if (ok) {
5265 game.info.granary_food_inc
5266 = secfile_lookup_int_default_min_max(file,
5267 RS_DEFAULT_GRANARY_FOOD_INC,
5268 RS_MIN_GRANARY_FOOD_INC,
5269 RS_MAX_GRANARY_FOOD_INC,
5270 "civstyle.granary_food_inc");
5272 output_type_iterate(o) {
5273 game.info.min_city_center_output[o]
5274 = secfile_lookup_int_default_min_max(file,
5275 RS_DEFAULT_CITY_CENTER_OUTPUT,
5276 RS_MIN_CITY_CENTER_OUTPUT,
5277 RS_MAX_CITY_CENTER_OUTPUT,
5278 "civstyle.min_city_center_%s",
5279 get_output_identifier(o));
5280 } output_type_iterate_end;
5283 if (ok) {
5284 const char *tus_text;
5286 game.server.init_vis_radius_sq
5287 = secfile_lookup_int_default_min_max(file,
5288 RS_DEFAULT_VIS_RADIUS_SQ,
5289 RS_MIN_VIS_RADIUS_SQ,
5290 RS_MAX_VIS_RADIUS_SQ,
5291 "civstyle.init_vis_radius_sq");
5293 game.info.init_city_radius_sq
5294 = secfile_lookup_int_default_min_max(file,
5295 RS_DEFAULT_CITY_RADIUS_SQ,
5296 RS_MIN_CITY_RADIUS_SQ,
5297 RS_MAX_CITY_RADIUS_SQ,
5298 "civstyle.init_city_radius_sq");
5300 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_GOLD_UPKEEP_STYLE,
5301 "civstyle.gold_upkeep_style");
5302 game.info.gold_upkeep_style = gold_upkeep_style_by_name(tus_text,
5303 fc_strcasecmp);
5304 if (!gold_upkeep_style_is_valid(game.info.gold_upkeep_style)) {
5305 ruleset_error(LOG_ERROR, "Unknown gold upkeep style \"%s\"",
5306 tus_text);
5307 ok = FALSE;
5310 /* section: illness */
5311 game.info.illness_on
5312 = secfile_lookup_bool_default(file, RS_DEFAULT_ILLNESS_ON,
5313 "illness.illness_on");
5314 game.info.illness_base_factor
5315 = secfile_lookup_int_default_min_max(file,
5316 RS_DEFAULT_ILLNESS_BASE_FACTOR,
5317 RS_MIN_ILLNESS_BASE_FACTOR,
5318 RS_MAX_ILLNESS_BASE_FACTOR,
5319 "illness.illness_base_factor");
5320 game.info.illness_min_size
5321 = secfile_lookup_int_default_min_max(file,
5322 RS_DEFAULT_ILLNESS_MIN_SIZE,
5323 RS_MIN_ILLNESS_MIN_SIZE,
5324 RS_MAX_ILLNESS_MIN_SIZE,
5325 "illness.illness_min_size");
5326 game.info.illness_trade_infection
5327 = secfile_lookup_int_default_min_max(file,
5328 RS_DEFAULT_ILLNESS_TRADE_INFECTION_PCT,
5329 RS_MIN_ILLNESS_TRADE_INFECTION_PCT,
5330 RS_MAX_ILLNESS_TRADE_INFECTION_PCT,
5331 "illness.illness_trade_infection");
5332 game.info.illness_pollution_factor
5333 = secfile_lookup_int_default_min_max(file,
5334 RS_DEFAULT_ILLNESS_POLLUTION_PCT,
5335 RS_MIN_ILLNESS_POLLUTION_PCT,
5336 RS_MAX_ILLNESS_POLLUTION_PCT,
5337 "illness.illness_pollution_factor");
5339 /* section: incite_cost */
5340 game.server.base_incite_cost
5341 = secfile_lookup_int_default_min_max(file,
5342 RS_DEFAULT_INCITE_BASE_COST,
5343 RS_MIN_INCITE_BASE_COST,
5344 RS_MAX_INCITE_BASE_COST,
5345 "incite_cost.base_incite_cost");
5346 game.server.incite_improvement_factor
5347 = secfile_lookup_int_default_min_max(file,
5348 RS_DEFAULT_INCITE_IMPROVEMENT_FCT,
5349 RS_MIN_INCITE_IMPROVEMENT_FCT,
5350 RS_MAX_INCITE_IMPROVEMENT_FCT,
5351 "incite_cost.improvement_factor");
5352 game.server.incite_unit_factor
5353 = secfile_lookup_int_default_min_max(file,
5354 RS_DEFAULT_INCITE_UNIT_FCT,
5355 RS_MIN_INCITE_UNIT_FCT,
5356 RS_MAX_INCITE_UNIT_FCT,
5357 "incite_cost.unit_factor");
5358 game.server.incite_total_factor
5359 = secfile_lookup_int_default_min_max(file,
5360 RS_DEFAULT_INCITE_TOTAL_FCT,
5361 RS_MIN_INCITE_TOTAL_FCT,
5362 RS_MAX_INCITE_TOTAL_FCT,
5363 "incite_cost.total_factor");
5365 /* section: global_unit_options */
5366 game.info.slow_invasions
5367 = secfile_lookup_bool_default(file, RS_DEFAULT_SLOW_INVASIONS,
5368 "global_unit_options.slow_invasions");
5370 /* section: actions */
5371 if (ok) {
5372 const char *text;
5374 /* Forbid entering the marketplace when a trade route can be
5375 * established. */
5376 game.info.force_trade_route
5377 = secfile_lookup_bool_default(file, RS_DEFAULT_FORCE_TRADE_ROUTE,
5378 "actions.force_trade_route");
5380 text = secfile_lookup_str_default(file,
5381 /* TRANS: _Poison City (3% chance of success). */
5382 N_("%sPoison City%s"),
5383 "actions.ui_name_poison_city");
5384 sz_strlcpy(action_by_number(ACTION_SPY_POISON)->ui_name,
5385 text);
5387 text = secfile_lookup_str_default(file,
5388 /* TRANS: S_abotage Enemy Unit (3% chance of success). */
5389 N_("S%sabotage Enemy Unit%s"),
5390 "actions.ui_name_sabotage_unit");
5391 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_UNIT)->ui_name,
5392 text);
5394 text = secfile_lookup_str_default(file,
5395 /* TRANS: Bribe Enemy _Unit (3% chance of success). */
5396 N_("Bribe Enemy %sUnit%s"),
5397 "actions.ui_name_bribe_unit");
5398 sz_strlcpy(action_by_number(ACTION_SPY_BRIBE_UNIT)->ui_name,
5399 text);
5401 text = secfile_lookup_str_default(file,
5402 /* TRANS: _Sabotage City (3% chance of success). */
5403 N_("%sSabotage City%s"),
5404 "actions.ui_name_sabotage_city");
5405 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_CITY)->ui_name,
5406 text);
5408 text = secfile_lookup_str_default(file,
5409 /* TRANS: Industria_l Sabotage (3% chance of success). */
5410 N_("Industria%sl Sabotage%s"),
5411 "actions.ui_name_targeted_sabotage_city");
5412 sz_strlcpy(
5413 action_by_number(ACTION_SPY_TARGETED_SABOTAGE_CITY)->ui_name,
5414 text);
5416 text = secfile_lookup_str_default(file,
5417 /* TRANS: Incite a Re_volt (3% chance of success). */
5418 N_("Incite a Re%svolt%s"),
5419 "actions.ui_name_incite_city");
5420 sz_strlcpy(action_by_number(ACTION_SPY_INCITE_CITY)->ui_name,
5421 text);
5423 text = secfile_lookup_str_default(file,
5424 /* TRANS: Establish _Embassy (100% chance of success). */
5425 N_("Establish %sEmbassy%s"),
5426 "actions.ui_name_establish_embassy");
5427 sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY)->ui_name,
5428 text);
5430 text = secfile_lookup_str_default(file,
5431 /* TRANS: Steal _Technology (3% chance of success). */
5432 N_("Steal %sTechnology%s"),
5433 "actions.ui_name_steal_tech");
5434 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_TECH)->ui_name,
5435 text);
5437 text = secfile_lookup_str_default(file,
5438 /* TRANS: In_dustrial Espionage (3% chance of success). */
5439 N_("In%sdustrial Espionage%s"),
5440 "actions.ui_name_targeted_steal_tech");
5441 sz_strlcpy(action_by_number(ACTION_SPY_TARGETED_STEAL_TECH)->ui_name,
5442 text);
5444 text = secfile_lookup_str_default(file,
5445 /* TRANS: _Investigate City (100% chance of success). */
5446 N_("%sInvestigate City%s"),
5447 "actions.ui_name_investigate_city");
5448 sz_strlcpy(action_by_number(ACTION_SPY_INVESTIGATE_CITY)->ui_name,
5449 text);
5451 text = secfile_lookup_str_default(file,
5452 /* TRANS: Steal _Gold (100% chance of success). */
5453 N_("Steal %sGold%s"),
5454 "actions.ui_name_steal_gold");
5455 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_GOLD)->ui_name,
5456 text);
5458 text = secfile_lookup_str_default(file,
5459 /* TRANS: Establish Trade _Route (100% chance of success). */
5460 N_("Establish Trade %sRoute%s"),
5461 "actions.ui_name_establish_trade_route");
5462 sz_strlcpy(action_by_number(ACTION_TRADE_ROUTE)->ui_name,
5463 text);
5465 text = secfile_lookup_str_default(file,
5466 /* TRANS: Enter _Marketplace (100% chance of success). */
5467 N_("Enter %sMarketplace%s"),
5468 "actions.ui_name_enter_marketplace");
5469 sz_strlcpy(action_by_number(ACTION_MARKETPLACE)->ui_name,
5470 text);
5472 text = secfile_lookup_str_default(file,
5473 /* TRANS: Help _build Wonder (100% chance of success). */
5474 N_("Help %sbuild Wonder%s"),
5475 "actions.ui_name_help_wonder");
5476 sz_strlcpy(action_by_number(ACTION_HELP_WONDER)->ui_name,
5477 text);
5479 /* The quiet (don't auto generate help for) property of all actions
5480 * live in a single enum vector. This avoids generic action
5481 * expectations. */
5482 if (secfile_entry_by_path(file, "actions.quiet_actions")) {
5483 enum gen_action *quiet_actions;
5484 size_t asize;
5485 int j;
5487 quiet_actions =
5488 secfile_lookup_enum_vec(file, &asize, gen_action,
5489 "actions.quiet_actions");
5491 if (!quiet_actions) {
5492 /* Entity exists but couldn't read it. */
5493 ruleset_error(LOG_ERROR,
5494 "\"%s\": actions.quiet_actions: bad action list",
5495 filename);
5497 ok = FALSE;
5500 for (j = 0; j < asize; j++) {
5501 /* Don't auto generate help text for this action. */
5502 action_by_number(quiet_actions[j])->quiet = TRUE;
5505 free(quiet_actions);
5509 if (ok) {
5510 sec = secfile_sections_by_name_prefix(file,
5511 ACTION_ENABLER_SECTION_PREFIX);
5513 if (sec) {
5514 section_list_iterate(sec, psection) {
5515 struct action_enabler *enabler;
5516 const char *sec_name = section_name(psection);
5517 enum gen_action action;
5518 struct requirement_vector *actor_reqs;
5519 struct requirement_vector *target_reqs;
5520 const char *action_text;
5522 enabler = action_enabler_new();
5524 action_text = secfile_lookup_str(file, "%s.action", sec_name);
5526 if (action_text == NULL) {
5527 ruleset_error(LOG_ERROR, "\"%s\" [%s] missing action to enable.",
5528 filename, sec_name);
5529 ok = FALSE;
5530 break;
5533 action = gen_action_by_name(action_text, fc_strcasecmp);
5534 if (!action_id_is_valid(action)) {
5535 ruleset_error(LOG_ERROR, "\"%s\" [%s] lists unknown action type \"%s\".",
5536 filename, sec_name, action_text);
5537 ok = FALSE;
5538 break;
5541 enabler->action = action;
5543 actor_reqs = lookup_req_list(file, sec_name, "actor_reqs", action_text);
5544 if (actor_reqs == NULL) {
5545 ok = FALSE;
5546 break;
5549 requirement_vector_copy(&enabler->actor_reqs, actor_reqs);
5551 target_reqs = lookup_req_list(file, sec_name, "target_reqs", action_text);
5552 if (target_reqs == NULL) {
5553 ok = FALSE;
5554 break;
5557 requirement_vector_copy(&enabler->target_reqs, target_reqs);
5559 action_enabler_add(enabler);
5560 } section_list_iterate_end;
5561 section_list_destroy(sec);
5566 if (ok) {
5567 const char *tus_text;
5569 /* section: combat_rules */
5570 game.info.tired_attack
5571 = secfile_lookup_bool_default(file, RS_DEFAULT_TIRED_ATTACK,
5572 "combat_rules.tired_attack");
5574 /* section: borders */
5575 game.info.border_city_radius_sq
5576 = secfile_lookup_int_default_min_max(file,
5577 RS_DEFAULT_BORDER_RADIUS_SQ_CITY,
5578 RS_MIN_BORDER_RADIUS_SQ_CITY,
5579 RS_MAX_BORDER_RADIUS_SQ_CITY,
5580 "borders.radius_sq_city");
5581 game.info.border_size_effect
5582 = secfile_lookup_int_default_min_max(file,
5583 RS_DEFAULT_BORDER_SIZE_EFFECT,
5584 RS_MIN_BORDER_SIZE_EFFECT,
5585 RS_MAX_BORDER_SIZE_EFFECT,
5586 "borders.size_effect");
5588 game.info.border_city_permanent_radius_sq
5589 = secfile_lookup_int_default_min_max(file,
5590 RS_DEFAULT_BORDER_RADIUS_SQ_CITY_PERMANENT,
5591 RS_MIN_BORDER_RADIUS_SQ_CITY_PERMANENT,
5592 RS_MAX_BORDER_RADIUS_SQ_CITY_PERMANENT,
5593 "borders.radius_sq_city_permanent");
5595 /* section: research */
5596 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_COST_STYLE,
5597 "research.tech_cost_style");
5598 game.info.tech_cost_style = tech_cost_style_by_name(tus_text,
5599 fc_strcasecmp);
5600 if (!tech_cost_style_is_valid(game.info.tech_cost_style)) {
5601 ruleset_error(LOG_ERROR, "Unknown tech cost style \"%s\"",
5602 tus_text);
5603 ok = FALSE;
5606 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_LEAKAGE,
5607 "research.tech_leakage");
5608 game.info.tech_leakage = tech_leakage_style_by_name(tus_text,
5609 fc_strcasecmp);
5610 if (!tech_leakage_style_is_valid(game.info.tech_leakage)) {
5611 ruleset_error(LOG_ERROR, "Unknown tech leakage \"%s\"",
5612 tus_text);
5613 ok = FALSE;
5615 if (game.info.tech_cost_style == TECH_COST_CIV1CIV2
5616 && game.info.tech_leakage != TECH_LEAKAGE_NONE) {
5617 log_error("Only tech_leakage \"%s\" supported with "
5618 "tech_cost_style \"%s\". ",
5619 tech_leakage_style_name(TECH_LEAKAGE_NONE),
5620 tech_cost_style_name(TECH_COST_CIV1CIV2));
5621 log_error("Switching to tech_leakage \"%s\".",
5622 tech_leakage_style_name(TECH_LEAKAGE_NONE));
5623 game.info.tech_leakage = TECH_LEAKAGE_NONE;
5625 game.info.base_tech_cost
5626 = secfile_lookup_int_default_min_max(file,
5627 RS_DEFAULT_BASE_TECH_COST,
5628 RS_MIN_BASE_TECH_COST,
5629 RS_MAX_BASE_TECH_COST,
5630 "research.base_tech_cost");
5632 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_UPKEEP_STYLE,
5633 "research.tech_upkeep_style");
5635 game.info.tech_upkeep_style = tech_upkeep_style_by_name(tus_text, fc_strcasecmp);
5637 if (!tech_upkeep_style_is_valid(game.info.tech_upkeep_style)) {
5638 ruleset_error(LOG_ERROR, "Unknown tech upkeep style \"%s\"",
5639 tus_text);
5640 ok = FALSE;
5644 if (ok) {
5645 game.info.tech_upkeep_divider
5646 = secfile_lookup_int_default_min_max(file,
5647 RS_DEFAULT_TECH_UPKEEP_DIVIDER,
5648 RS_MIN_TECH_UPKEEP_DIVIDER,
5649 RS_MAX_TECH_UPKEEP_DIVIDER,
5650 "research.tech_upkeep_divider");
5652 sval = secfile_lookup_str_default(file, NULL, "research.free_tech_method");
5653 if (sval == NULL) {
5654 ruleset_error(LOG_ERROR, "No free_tech_method given");
5655 ok = FALSE;
5656 } else {
5657 game.info.free_tech_method = free_tech_method_by_name(sval, fc_strcasecmp);
5658 if (!free_tech_method_is_valid(game.info.free_tech_method)) {
5659 ruleset_error(LOG_ERROR, "Bad value %s for free_tech_method.", sval);
5660 ok = FALSE;
5665 if (ok) {
5666 int cf;
5668 /* section: culture */
5669 game.info.culture_vic_points
5670 = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_VIC_POINTS,
5671 "culture.victory_min_points");
5672 game.info.culture_vic_lead
5673 = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_VIC_LEAD,
5674 "culture.victory_lead_pct");
5675 game.info.culture_migration_pml
5676 = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_MIGRATION_PML,
5677 "culture.migration_pml");
5679 /* section: calendar */
5680 game.info.calendar_skip_0
5681 = secfile_lookup_bool_default(file, RS_DEFAULT_CALENDAR_SKIP_0,
5682 "calendar.skip_year_0");
5683 game.server.start_year
5684 = secfile_lookup_int_default(file, GAME_START_YEAR,
5685 "calendar.start_year");
5686 game.info.calendar_fragments
5687 = secfile_lookup_int_default(file, 0, "calendar.fragments");
5689 if (game.info.calendar_fragments > MAX_CALENDAR_FRAGMENTS) {
5690 ruleset_error(LOG_ERROR, "Too many calendar fragments. Max is %d",
5691 MAX_CALENDAR_FRAGMENTS);
5692 ok = FALSE;
5693 game.info.calendar_fragments = 0;
5695 sz_strlcpy(game.info.positive_year_label,
5696 secfile_lookup_str_default(file,
5697 RS_DEFAULT_POS_YEAR_LABEL,
5698 "calendar.positive_label"));
5699 sz_strlcpy(game.info.negative_year_label,
5700 secfile_lookup_str_default(file,
5701 RS_DEFAULT_NEG_YEAR_LABEL,
5702 "calendar.negative_label"));
5704 for (cf = 0; cf < game.info.calendar_fragments; cf++) {
5705 const char *fname;
5707 fname = secfile_lookup_str_default(file, NULL, "calendar.fragment_name%d", cf);
5708 if (fname != NULL) {
5709 strncpy(game.info.calendar_fragment_name[cf], fname,
5710 sizeof(game.info.calendar_fragment_name[cf]));
5715 if (ok) {
5716 /* section playercolors */
5717 struct rgbcolor *prgbcolor = NULL;
5718 bool color_read = TRUE;
5720 /* Check if the player list is defined and empty. */
5721 if (playercolor_count() != 0) {
5722 ok = FALSE;
5723 } else {
5724 i = 0;
5726 while (color_read) {
5727 prgbcolor = NULL;
5729 color_read = rgbcolor_load(file, &prgbcolor, "playercolors.colorlist%d", i);
5730 if (color_read) {
5731 playercolor_add(prgbcolor);
5734 i++;
5737 if (playercolor_count() == 0) {
5738 ruleset_error(LOG_ERROR, "No player colors defined!");
5739 ok = FALSE;
5742 if (ok) {
5743 fc_assert(game.plr_bg_color == NULL);
5744 if (!rgbcolor_load(file, &game.plr_bg_color, "playercolors.background")) {
5745 ruleset_error(LOG_ERROR, "No background player color defined! (%s)",
5746 secfile_error());
5747 ok = FALSE;
5753 if (ok) {
5754 /* section: teams */
5755 svec = secfile_lookup_str_vec(file, &teams, "teams.names");
5756 if (team_slot_count() < teams) {
5757 teams = team_slot_count();
5759 game.server.ruledit.named_teams = teams;
5760 for (i = 0; i < teams; i++) {
5761 team_slot_set_defined_name(team_slot_by_number(i), svec[i]);
5763 free(svec);
5765 sec = secfile_sections_by_name_prefix(file, DISASTER_SECTION_PREFIX);
5766 nval = (NULL != sec ? section_list_size(sec) : 0);
5767 if (nval > MAX_DISASTER_TYPES) {
5768 int num = nval; /* No "size_t" to printf */
5770 ruleset_error(LOG_ERROR, "\"%s\": Too many disaster types (%d, max %d)",
5771 filename, num, MAX_DISASTER_TYPES);
5772 section_list_destroy(sec);
5773 ok = FALSE;
5774 } else {
5775 game.control.num_disaster_types = nval;
5779 if (ok) {
5780 disaster_type_iterate(pdis) {
5781 int id = disaster_index(pdis);
5782 int j;
5783 size_t eff_count;
5784 struct requirement_vector *reqs;
5785 const char *sec_name = section_name(section_list_get(sec, id));
5787 if (!ruleset_load_names(&pdis->name, NULL, file, sec_name)) {
5788 ruleset_error(LOG_ERROR, "\"%s\": Cannot load disaster names",
5789 filename);
5790 ok = FALSE;
5791 break;
5794 reqs = lookup_req_list(file, sec_name, "reqs", disaster_rule_name(pdis));
5795 if (reqs == NULL) {
5796 ok = FALSE;
5797 break;
5799 requirement_vector_copy(&pdis->reqs, reqs);
5801 pdis->frequency = secfile_lookup_int_default(file, GAME_DEFAULT_DISASTER_FREQ,
5802 "%s.frequency", sec_name);
5804 svec = secfile_lookup_str_vec(file, &eff_count, "%s.effects", sec_name);
5806 BV_CLR_ALL(pdis->effects);
5807 for (j = 0; j < eff_count; j++) {
5808 const char *dsval = svec[j];
5809 enum disaster_effect_id effect;
5811 effect = disaster_effect_id_by_name(dsval, fc_strcasecmp);
5813 if (!disaster_effect_id_is_valid(effect)) {
5814 ruleset_error(LOG_ERROR,
5815 "\"%s\" disaster \"%s\": unknown effect \"%s\".",
5816 filename,
5817 disaster_rule_name(pdis),
5818 dsval);
5819 ok = FALSE;
5820 break;
5821 } else {
5822 BV_SET(pdis->effects, effect);
5826 free(svec);
5828 if (!ok) {
5829 break;
5831 } disaster_type_iterate_end;
5832 section_list_destroy(sec);
5835 if (ok) {
5836 sec = secfile_sections_by_name_prefix(file, ACHIEVEMENT_SECTION_PREFIX);
5838 achievements_iterate(pach) {
5839 int id = achievement_index(pach);
5840 const char *sec_name = section_name(section_list_get(sec, id));
5841 const char *typename;
5842 const char *msg;
5844 typename = secfile_lookup_str_default(file, NULL, "%s.type", sec_name);
5846 pach->type = achievement_type_by_name(typename, fc_strcasecmp);
5847 if (!achievement_type_is_valid(pach->type)) {
5848 ruleset_error(LOG_ERROR, "Achievement has unknown type \"%s\".",
5849 typename != NULL ? typename : "(NULL)");
5850 ok = FALSE;
5853 if (ok) {
5854 pach->unique = secfile_lookup_bool_default(file, GAME_DEFAULT_ACH_UNIQUE,
5855 "%s.unique", sec_name);
5857 pach->value = secfile_lookup_int_default(file, GAME_DEFAULT_ACH_VALUE,
5858 "%s.value", sec_name);
5859 pach->culture = secfile_lookup_int_default(file, 0,
5860 "%s.culture", sec_name);
5862 msg = secfile_lookup_str_default(file, NULL, "%s.first_msg", sec_name);
5863 if (msg == NULL) {
5864 ruleset_error(LOG_ERROR, "Achievement %s has no first msg!", sec_name);
5865 ok = FALSE;
5866 } else {
5867 pach->first_msg = fc_strdup(msg);
5871 if (ok) {
5872 msg = secfile_lookup_str_default(file, NULL, "%s.cons_msg", sec_name);
5873 if (msg == NULL) {
5874 if (!pach->unique) {
5875 ruleset_error(LOG_ERROR, "Achievement %s has no msg for consecutive gainers!", sec_name);
5876 ok = FALSE;
5878 } else {
5879 pach->cons_msg = fc_strdup(msg);
5883 if (!ok) {
5884 break;
5886 } achievements_iterate_end;
5889 if (ok) {
5890 for (i = 0; (name = secfile_lookup_str_default(file, NULL,
5891 "trade.settings%d.type",
5892 i)); i++) {
5893 enum trade_route_type type = trade_route_type_by_name(name);
5895 if (type == TRT_LAST) {
5896 ruleset_error(LOG_ERROR,
5897 "\"%s\" unknown trade route type \"%s\".",
5898 filename, name);
5899 ok = FALSE;
5900 } else {
5901 struct trade_route_settings *set = trade_route_settings_by_type(type);
5902 const char *cancelling;
5903 const char *bonus;
5905 set->trade_pct = secfile_lookup_int_default(file, 100,
5906 "trade.settings%d.pct", i);
5907 cancelling = secfile_lookup_str_default(file, "Active",
5908 "trade.settings%d.cancelling", i);
5909 set->cancelling = traderoute_cancelling_type_by_name(cancelling);
5910 if (set->cancelling == TRI_LAST) {
5911 ruleset_error(LOG_ERROR,
5912 "\"%s\" unknown traderoute cancelling type \"%s\".",
5913 filename, cancelling);
5914 ok = FALSE;
5917 bonus = secfile_lookup_str_default(file, "None", "trade.settings%d.bonus", i);
5919 set->bonus_type = traderoute_bonus_type_by_name(bonus, fc_strcasecmp);
5921 if (!traderoute_bonus_type_is_valid(set->bonus_type)) {
5922 ruleset_error(LOG_ERROR,
5923 "\"%s\" unknown traderoute bonus type \"%s\".",
5924 filename, bonus);
5925 ok = FALSE;
5931 /* secfile_check_unused() is not here, but only after also settings section
5932 * has been loaded. */
5934 return ok;
5937 /**************************************************************************
5938 Send the units ruleset information (all individual unit classes) to the
5939 specified connections.
5940 **************************************************************************/
5941 static void send_ruleset_unit_classes(struct conn_list *dest)
5943 struct packet_ruleset_unit_class packet;
5945 unit_class_iterate(c) {
5946 packet.id = uclass_number(c);
5947 sz_strlcpy(packet.name, untranslated_name(&c->name));
5948 sz_strlcpy(packet.rule_name, rule_name_get(&c->name));
5949 packet.min_speed = c->min_speed;
5950 packet.hp_loss_pct = c->hp_loss_pct;
5951 packet.hut_behavior = c->hut_behavior;
5952 packet.non_native_def_pct = c->non_native_def_pct;
5953 packet.flags = c->flags;
5955 PACKET_STRVEC_COMPUTE(packet.helptext, c->helptext);
5957 lsend_packet_ruleset_unit_class(dest, &packet);
5958 } unit_class_iterate_end;
5961 /**************************************************************************
5962 Send the units ruleset information (all individual units) to the
5963 specified connections.
5964 **************************************************************************/
5965 static void send_ruleset_units(struct conn_list *dest)
5967 struct packet_ruleset_unit packet;
5968 struct packet_ruleset_unit_flag fpacket;
5969 int i;
5971 for (i = 0; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
5972 const char *flagname;
5973 const char *helptxt;
5975 fpacket.id = i + UTYF_USER_FLAG_1;
5977 flagname = unit_type_flag_id_name(i + UTYF_USER_FLAG_1);
5978 if (flagname == NULL) {
5979 fpacket.name[0] = '\0';
5980 } else {
5981 sz_strlcpy(fpacket.name, flagname);
5984 helptxt = unit_type_flag_helptxt(i + UTYF_USER_FLAG_1);
5985 if (helptxt == NULL) {
5986 fpacket.helptxt[0] = '\0';
5987 } else {
5988 sz_strlcpy(fpacket.helptxt, helptxt);
5991 lsend_packet_ruleset_unit_flag(dest, &fpacket);
5994 unit_type_iterate(u) {
5995 packet.id = utype_number(u);
5996 sz_strlcpy(packet.name, untranslated_name(&u->name));
5997 sz_strlcpy(packet.rule_name, rule_name_get(&u->name));
5998 sz_strlcpy(packet.sound_move, u->sound_move);
5999 sz_strlcpy(packet.sound_move_alt, u->sound_move_alt);
6000 sz_strlcpy(packet.sound_fight, u->sound_fight);
6001 sz_strlcpy(packet.sound_fight_alt, u->sound_fight_alt);
6002 sz_strlcpy(packet.graphic_str, u->graphic_str);
6003 sz_strlcpy(packet.graphic_alt, u->graphic_alt);
6004 packet.unit_class_id = uclass_number(utype_class(u));
6005 packet.build_cost = u->build_cost;
6006 packet.pop_cost = u->pop_cost;
6007 packet.attack_strength = u->attack_strength;
6008 packet.defense_strength = u->defense_strength;
6009 packet.move_rate = u->move_rate;
6010 packet.tech_requirement = u->require_advance
6011 ? advance_number(u->require_advance)
6012 : advance_count();
6013 packet.impr_requirement = u->need_improvement
6014 ? improvement_number(u->need_improvement)
6015 : improvement_count();
6016 packet.gov_requirement = u->need_government
6017 ? government_number(u->need_government)
6018 : government_count();
6019 packet.vision_radius_sq = u->vision_radius_sq;
6020 packet.transport_capacity = u->transport_capacity;
6021 packet.hp = u->hp;
6022 packet.firepower = u->firepower;
6023 packet.obsoleted_by = u->obsoleted_by
6024 ? utype_number(u->obsoleted_by)
6025 : utype_count();
6026 packet.converted_to = u->converted_to
6027 ? utype_number(u->converted_to)
6028 : utype_count();
6029 packet.convert_time = u->convert_time;
6030 packet.fuel = u->fuel;
6031 packet.flags = u->flags;
6032 packet.roles = u->roles;
6033 packet.happy_cost = u->happy_cost;
6034 output_type_iterate(o) {
6035 packet.upkeep[o] = u->upkeep[o];
6036 } output_type_iterate_end;
6037 packet.paratroopers_range = u->paratroopers_range;
6038 packet.paratroopers_mr_req = u->paratroopers_mr_req;
6039 packet.paratroopers_mr_sub = u->paratroopers_mr_sub;
6040 packet.bombard_rate = u->bombard_rate;
6041 packet.city_size = u->city_size;
6042 packet.cargo = u->cargo;
6043 packet.targets = u->targets;
6044 packet.embarks = u->embarks;
6045 packet.disembarks = u->disembarks;
6047 if (u->veteran == NULL) {
6048 /* Use the default veteran system. */
6049 packet.veteran_levels = 0;
6050 } else {
6051 /* Per unit veteran system definition. */
6052 packet.veteran_levels = utype_veteran_levels(u);
6054 for (i = 0; i < packet.veteran_levels; i++) {
6055 const struct veteran_level *vlevel = utype_veteran_level(u, i);
6057 sz_strlcpy(packet.veteran_name[i], untranslated_name(&vlevel->name));
6058 packet.power_fact[i] = vlevel->power_fact;
6059 packet.move_bonus[i] = vlevel->move_bonus;
6062 PACKET_STRVEC_COMPUTE(packet.helptext, u->helptext);
6064 lsend_packet_ruleset_unit(dest, &packet);
6066 combat_bonus_list_iterate(u->bonuses, pbonus) {
6067 struct packet_ruleset_unit_bonus bonuspacket;
6069 bonuspacket.unit = packet.id;
6070 bonuspacket.flag = pbonus->flag;
6071 bonuspacket.type = pbonus->type;
6072 bonuspacket.value = pbonus->value;
6073 bonuspacket.quiet = pbonus->quiet;
6075 lsend_packet_ruleset_unit_bonus(dest, &bonuspacket);
6076 } combat_bonus_list_iterate_end;
6077 } unit_type_iterate_end;
6080 /**************************************************************************
6081 Send the specialists ruleset information (all individual specialist
6082 types) to the specified connections.
6083 **************************************************************************/
6084 static void send_ruleset_specialists(struct conn_list *dest)
6086 struct packet_ruleset_specialist packet;
6088 specialist_type_iterate(spec_id) {
6089 struct specialist *s = specialist_by_number(spec_id);
6090 int j;
6092 packet.id = spec_id;
6093 sz_strlcpy(packet.plural_name, untranslated_name(&s->name));
6094 sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
6095 sz_strlcpy(packet.short_name, untranslated_name(&s->abbreviation));
6096 sz_strlcpy(packet.graphic_alt, s->graphic_alt);
6097 j = 0;
6098 requirement_vector_iterate(&s->reqs, preq) {
6099 packet.reqs[j++] = *preq;
6100 } requirement_vector_iterate_end;
6101 packet.reqs_count = j;
6103 PACKET_STRVEC_COMPUTE(packet.helptext, s->helptext);
6105 lsend_packet_ruleset_specialist(dest, &packet);
6106 } specialist_type_iterate_end;
6109 /**************************************************************************
6110 Send the techs ruleset information (all individual advances) to the
6111 specified connections.
6112 **************************************************************************/
6113 static void send_ruleset_techs(struct conn_list *dest)
6115 struct packet_ruleset_tech packet;
6116 struct packet_ruleset_tech_flag fpacket;
6117 int i;
6119 for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
6120 const char *flagname;
6121 const char *helptxt;
6123 fpacket.id = i + TECH_USER_1;
6125 flagname = tech_flag_id_name_cb(i + TECH_USER_1);
6126 if (flagname == NULL) {
6127 fpacket.name[0] = '\0';
6128 } else {
6129 sz_strlcpy(fpacket.name, flagname);
6132 helptxt = tech_flag_helptxt(i + TECH_USER_1);
6133 if (helptxt == NULL) {
6134 fpacket.helptxt[0] = '\0';
6135 } else {
6136 sz_strlcpy(fpacket.helptxt, helptxt);
6139 lsend_packet_ruleset_tech_flag(dest, &fpacket);
6142 advance_iterate(A_FIRST, a) {
6143 packet.id = advance_number(a);
6144 sz_strlcpy(packet.name, untranslated_name(&a->name));
6145 sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
6146 sz_strlcpy(packet.graphic_str, a->graphic_str);
6147 sz_strlcpy(packet.graphic_alt, a->graphic_alt);
6149 packet.req[AR_ONE] = a->require[AR_ONE]
6150 ? advance_number(a->require[AR_ONE])
6151 : advance_count();
6152 packet.req[AR_TWO] = a->require[AR_TWO]
6153 ? advance_number(a->require[AR_TWO])
6154 : advance_count();
6155 packet.root_req = a->require[AR_ROOT]
6156 ? advance_number(a->require[AR_ROOT])
6157 : advance_count();
6159 packet.flags = a->flags;
6160 packet.cost = a->cost;
6161 packet.num_reqs = a->num_reqs;
6162 PACKET_STRVEC_COMPUTE(packet.helptext, a->helptext);
6164 lsend_packet_ruleset_tech(dest, &packet);
6165 } advance_iterate_end;
6168 /**************************************************************************
6169 Send the buildings ruleset information (all individual improvements and
6170 wonders) to the specified connections.
6171 **************************************************************************/
6172 static void send_ruleset_buildings(struct conn_list *dest)
6174 improvement_iterate(b) {
6175 struct packet_ruleset_building packet;
6176 int j;
6178 packet.id = improvement_number(b);
6179 packet.genus = b->genus;
6180 sz_strlcpy(packet.name, untranslated_name(&b->name));
6181 sz_strlcpy(packet.rule_name, rule_name_get(&b->name));
6182 sz_strlcpy(packet.graphic_str, b->graphic_str);
6183 sz_strlcpy(packet.graphic_alt, b->graphic_alt);
6184 j = 0;
6185 requirement_vector_iterate(&b->reqs, preq) {
6186 packet.reqs[j++] = *preq;
6187 } requirement_vector_iterate_end;
6188 packet.reqs_count = j;
6189 j = 0;
6190 requirement_vector_iterate(&b->obsolete_by, pobs) {
6191 packet.obs_reqs[j++] = *pobs;
6192 } requirement_vector_iterate_end;
6193 packet.obs_count = j;
6194 packet.build_cost = b->build_cost;
6195 packet.upkeep = b->upkeep;
6196 packet.sabotage = b->sabotage;
6197 packet.flags = b->flags;
6198 sz_strlcpy(packet.soundtag, b->soundtag);
6199 sz_strlcpy(packet.soundtag_alt, b->soundtag_alt);
6200 PACKET_STRVEC_COMPUTE(packet.helptext, b->helptext);
6202 lsend_packet_ruleset_building(dest, &packet);
6203 } improvement_iterate_end;
6206 /**************************************************************************
6207 Send the terrain ruleset information (terrain_control, and the individual
6208 terrain types) to the specified connections.
6209 **************************************************************************/
6210 static void send_ruleset_terrain(struct conn_list *dest)
6212 struct packet_ruleset_terrain packet;
6213 struct packet_ruleset_terrain_flag fpacket;
6214 int i;
6216 lsend_packet_ruleset_terrain_control(dest, &terrain_control);
6218 for (i = 0; i < MAX_NUM_USER_TER_FLAGS; i++) {
6219 const char *flagname;
6220 const char *helptxt;
6222 fpacket.id = i + TER_USER_1;
6224 flagname = terrain_flag_id_name_cb(i + TER_USER_1);
6225 if (flagname == NULL) {
6226 fpacket.name[0] = '\0';
6227 } else {
6228 sz_strlcpy(fpacket.name, flagname);
6231 helptxt = terrain_flag_helptxt(i + TER_USER_1);
6232 if (helptxt == NULL) {
6233 fpacket.helptxt[0] = '\0';
6234 } else {
6235 sz_strlcpy(fpacket.helptxt, helptxt);
6238 lsend_packet_ruleset_terrain_flag(dest, &fpacket);
6241 terrain_type_iterate(pterrain) {
6242 struct resource **r;
6244 packet.id = terrain_number(pterrain);
6245 packet.tclass = pterrain->tclass;
6246 packet.native_to = pterrain->native_to;
6248 sz_strlcpy(packet.name, untranslated_name(&pterrain->name));
6249 sz_strlcpy(packet.rule_name, rule_name_get(&pterrain->name));
6250 sz_strlcpy(packet.graphic_str, pterrain->graphic_str);
6251 sz_strlcpy(packet.graphic_alt, pterrain->graphic_alt);
6253 packet.movement_cost = pterrain->movement_cost;
6254 packet.defense_bonus = pterrain->defense_bonus;
6256 output_type_iterate(o) {
6257 packet.output[o] = pterrain->output[o];
6258 } output_type_iterate_end;
6260 packet.num_resources = 0;
6261 for (r = pterrain->resources; *r; r++) {
6262 packet.resources[packet.num_resources++] = resource_number(*r);
6265 output_type_iterate(o) {
6266 packet.road_output_incr_pct[o] = pterrain->road_output_incr_pct[o];
6267 } output_type_iterate_end;
6269 packet.base_time = pterrain->base_time;
6270 packet.road_time = pterrain->road_time;
6272 packet.irrigation_result = (pterrain->irrigation_result
6273 ? terrain_number(pterrain->irrigation_result)
6274 : terrain_count());
6275 packet.irrigation_food_incr = pterrain->irrigation_food_incr;
6276 packet.irrigation_time = pterrain->irrigation_time;
6278 packet.mining_result = (pterrain->mining_result
6279 ? terrain_number(pterrain->mining_result)
6280 : terrain_count());
6281 packet.mining_shield_incr = pterrain->mining_shield_incr;
6282 packet.mining_time = pterrain->mining_time;
6284 packet.animal = (pterrain->animal == NULL ? -1 : utype_number(pterrain->animal));
6285 packet.transform_result = (pterrain->transform_result
6286 ? terrain_number(pterrain->transform_result)
6287 : terrain_count());
6288 packet.pillage_time = pterrain->pillage_time;
6289 packet.transform_time = pterrain->transform_time;
6290 packet.clean_pollution_time = pterrain->clean_pollution_time;
6291 packet.clean_fallout_time = pterrain->clean_fallout_time;
6293 packet.flags = pterrain->flags;
6295 packet.color_red = pterrain->rgb->r;
6296 packet.color_green = pterrain->rgb->g;
6297 packet.color_blue = pterrain->rgb->b;
6299 PACKET_STRVEC_COMPUTE(packet.helptext, pterrain->helptext);
6301 lsend_packet_ruleset_terrain(dest, &packet);
6302 } terrain_type_iterate_end;
6305 /****************************************************************************
6306 Send the resource ruleset information to the specified connections.
6307 ****************************************************************************/
6308 static void send_ruleset_resources(struct conn_list *dest)
6310 struct packet_ruleset_resource packet;
6312 resource_type_iterate (presource) {
6313 packet.id = resource_number(presource);
6315 sz_strlcpy(packet.name, untranslated_name(&presource->name));
6316 sz_strlcpy(packet.rule_name, rule_name_get(&presource->name));
6317 sz_strlcpy(packet.graphic_str, presource->graphic_str);
6318 sz_strlcpy(packet.graphic_alt, presource->graphic_alt);
6320 output_type_iterate(o) {
6321 packet.output[o] = presource->output[o];
6322 } output_type_iterate_end;
6324 lsend_packet_ruleset_resource(dest, &packet);
6325 } resource_type_iterate_end;
6328 /**************************************************************************
6329 Send the extra ruleset information (all individual extra types) to the
6330 specified connections.
6331 **************************************************************************/
6332 static void send_ruleset_extras(struct conn_list *dest)
6334 struct packet_ruleset_extra packet;
6336 extra_type_iterate(e) {
6337 int j;
6339 packet.id = extra_number(e);
6340 sz_strlcpy(packet.name, untranslated_name(&e->name));
6341 sz_strlcpy(packet.rule_name, rule_name_get(&e->name));
6343 packet.category = e->category;
6344 packet.causes = e->causes;
6345 packet.rmcauses = e->rmcauses;
6347 sz_strlcpy(packet.activity_gfx, e->activity_gfx);
6348 sz_strlcpy(packet.act_gfx_alt, e->act_gfx_alt);
6349 sz_strlcpy(packet.act_gfx_alt2, e->act_gfx_alt2);
6350 sz_strlcpy(packet.rmact_gfx, e->rmact_gfx);
6351 sz_strlcpy(packet.rmact_gfx_alt, e->rmact_gfx_alt);
6352 sz_strlcpy(packet.graphic_str, e->graphic_str);
6353 sz_strlcpy(packet.graphic_alt, e->graphic_alt);
6355 j = 0;
6356 requirement_vector_iterate(&e->reqs, preq) {
6357 packet.reqs[j++] = *preq;
6358 } requirement_vector_iterate_end;
6359 packet.reqs_count = j;
6361 j = 0;
6362 requirement_vector_iterate(&e->rmreqs, preq) {
6363 packet.rmreqs[j++] = *preq;
6364 } requirement_vector_iterate_end;
6365 packet.rmreqs_count = j;
6367 packet.buildable = e->buildable;
6368 packet.build_time = e->build_time;
6369 packet.build_time_factor = e->build_time_factor;
6370 packet.removal_time = e->removal_time;
6371 packet.removal_time_factor = e->removal_time_factor;
6372 packet.defense_bonus = e->defense_bonus;
6374 packet.native_to = e->native_to;
6376 packet.flags = e->flags;
6377 packet.hidden_by = e->hidden_by;
6378 packet.conflicts = e->conflicts;
6380 PACKET_STRVEC_COMPUTE(packet.helptext, e->helptext);
6382 lsend_packet_ruleset_extra(dest, &packet);
6383 } extra_type_iterate_end;
6386 /**************************************************************************
6387 Send the base ruleset information (all individual base types) to the
6388 specified connections.
6389 **************************************************************************/
6390 static void send_ruleset_bases(struct conn_list *dest)
6392 extra_type_by_cause_iterate(EC_BASE, pextra) {
6393 struct base_type *b = extra_base_get(pextra);
6394 struct packet_ruleset_base packet;
6396 packet.id = base_number(b);
6398 packet.gui_type = b->gui_type;
6399 packet.border_sq = b->border_sq;
6400 packet.vision_main_sq = b->vision_main_sq;
6401 packet.vision_invis_sq = b->vision_invis_sq;
6403 packet.flags = b->flags;
6405 lsend_packet_ruleset_base(dest, &packet);
6406 } extra_type_by_cause_iterate_end;
6409 /**************************************************************************
6410 Send the road ruleset information (all individual road types) to the
6411 specified connections.
6412 **************************************************************************/
6413 static void send_ruleset_roads(struct conn_list *dest)
6415 struct packet_ruleset_road packet;
6417 extra_type_by_cause_iterate(EC_ROAD, pextra) {
6418 struct road_type *r = extra_road_get(pextra);
6419 int j;
6421 packet.id = road_number(r);
6423 j = 0;
6424 requirement_vector_iterate(&r->first_reqs, preq) {
6425 packet.first_reqs[j++] = *preq;
6426 } requirement_vector_iterate_end;
6427 packet.first_reqs_count = j;
6429 packet.move_cost = r->move_cost;
6430 packet.move_mode = r->move_mode;
6432 output_type_iterate(o) {
6433 packet.tile_incr_const[o] = r->tile_incr_const[o];
6434 packet.tile_incr[o] = r->tile_incr[o];
6435 packet.tile_bonus[o] = r->tile_bonus[o];
6436 } output_type_iterate_end;
6438 packet.compat = r->compat;
6440 packet.integrates = r->integrates;
6441 packet.flags = r->flags;
6443 lsend_packet_ruleset_road(dest, &packet);
6444 } extra_type_by_cause_iterate_end;
6447 /**************************************************************************
6448 Send the disaster ruleset information (all individual disaster types) to the
6449 specified connections.
6450 **************************************************************************/
6451 static void send_ruleset_disasters(struct conn_list *dest)
6453 struct packet_ruleset_disaster packet;
6455 disaster_type_iterate(d) {
6456 int j;
6457 packet.id = disaster_number(d);
6459 sz_strlcpy(packet.name, untranslated_name(&d->name));
6460 sz_strlcpy(packet.rule_name, rule_name_get(&d->name));
6462 j = 0;
6463 requirement_vector_iterate(&d->reqs, preq) {
6464 packet.reqs[j++] = *preq;
6465 } requirement_vector_iterate_end;
6466 packet.reqs_count = j;
6468 packet.frequency = d->frequency;
6470 packet.effects = d->effects;
6472 lsend_packet_ruleset_disaster(dest, &packet);
6473 } disaster_type_iterate_end;
6476 /**************************************************************************
6477 Send the achievement ruleset information (all individual achievement types)
6478 to the specified connections.
6479 **************************************************************************/
6480 static void send_ruleset_achievements(struct conn_list *dest)
6482 struct packet_ruleset_achievement packet;
6484 achievements_iterate(a) {
6485 packet.id = achievement_number(a);
6487 sz_strlcpy(packet.name, untranslated_name(&a->name));
6488 sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
6490 packet.type = a->type;
6491 packet.unique = a->unique;
6492 packet.value = a->value;
6494 lsend_packet_ruleset_achievement(dest, &packet);
6495 } achievements_iterate_end;
6498 /**************************************************************************
6499 Send action ruleset information to the specified connections.
6500 **************************************************************************/
6501 static void send_ruleset_actions(struct conn_list *dest)
6503 struct packet_ruleset_action packet;
6505 action_iterate(act) {
6506 packet.id = act;
6507 sz_strlcpy(packet.ui_name, action_by_number(act)->ui_name);
6508 packet.quiet = action_by_number(act)->quiet;
6510 lsend_packet_ruleset_action(dest, &packet);
6511 } action_iterate_end;
6514 /**************************************************************************
6515 Send the action enabler ruleset information to the specified connections.
6516 **************************************************************************/
6517 static void send_ruleset_action_enablers(struct conn_list *dest)
6519 int counter;
6520 struct packet_ruleset_action_enabler packet;
6522 action_enablers_iterate(enabler) {
6523 packet.enabled_action = enabler->action;
6525 counter = 0;
6526 requirement_vector_iterate(&enabler->actor_reqs, req) {
6527 packet.actor_reqs[counter++] = *req;
6528 } requirement_vector_iterate_end;
6529 packet.actor_reqs_count = counter;
6531 counter = 0;
6532 requirement_vector_iterate(&enabler->target_reqs, req) {
6533 packet.target_reqs[counter++] = *req;
6534 } requirement_vector_iterate_end;
6535 packet.target_reqs_count = counter;
6537 lsend_packet_ruleset_action_enabler(dest, &packet);
6538 } action_enablers_iterate_end;
6541 /**************************************************************************
6542 Send the disaster ruleset information (all individual disaster types) to the
6543 specified connections.
6544 **************************************************************************/
6545 static void send_ruleset_trade_routes(struct conn_list *dest)
6547 struct packet_ruleset_trade packet;
6548 enum trade_route_type type;
6550 for (type = TRT_NATIONAL; type < TRT_LAST; type++) {
6551 struct trade_route_settings *set = trade_route_settings_by_type(type);
6553 packet.id = type;
6554 packet.trade_pct = set->trade_pct;
6555 packet.cancelling = set->cancelling;
6556 packet.bonus_type = set->bonus_type;
6558 lsend_packet_ruleset_trade(dest, &packet);
6562 /**************************************************************************
6563 Send the government ruleset information to the specified connections.
6564 One packet per government type, and for each type one per ruler title.
6565 **************************************************************************/
6566 static void send_ruleset_governments(struct conn_list *dest)
6568 struct packet_ruleset_government gov;
6569 struct packet_ruleset_government_ruler_title title;
6570 int j;
6572 governments_iterate(g) {
6573 /* send one packet_government */
6574 gov.id = government_number(g);
6576 j = 0;
6577 requirement_vector_iterate(&g->reqs, preq) {
6578 gov.reqs[j++] = *preq;
6579 } requirement_vector_iterate_end;
6580 gov.reqs_count = j;
6582 sz_strlcpy(gov.name, untranslated_name(&g->name));
6583 sz_strlcpy(gov.rule_name, rule_name_get(&g->name));
6584 sz_strlcpy(gov.graphic_str, g->graphic_str);
6585 sz_strlcpy(gov.graphic_alt, g->graphic_alt);
6586 PACKET_STRVEC_COMPUTE(gov.helptext, g->helptext);
6588 lsend_packet_ruleset_government(dest, &gov);
6590 /* Send one packet_government_ruler_title per ruler title. */
6591 ruler_titles_iterate(government_ruler_titles(g), pruler_title) {
6592 const struct nation_type *pnation = ruler_title_nation(pruler_title);
6594 title.gov = government_number(g);
6595 title.nation = pnation ? nation_number(pnation) : nation_count();
6596 sz_strlcpy(title.male_title,
6597 ruler_title_male_untranslated_name(pruler_title));
6598 sz_strlcpy(title.female_title,
6599 ruler_title_female_untranslated_name(pruler_title));
6600 lsend_packet_ruleset_government_ruler_title(dest, &title);
6601 } ruler_titles_iterate_end;
6602 } governments_iterate_end;
6605 /**************************************************************************
6606 Send the nations ruleset information (info on each nation) to the
6607 specified connections.
6608 **************************************************************************/
6609 static void send_ruleset_nations(struct conn_list *dest)
6611 struct packet_ruleset_nation_sets sets_packet;
6612 struct packet_ruleset_nation_groups groups_packet;
6613 struct packet_ruleset_nation packet;
6614 int i;
6616 sets_packet.nsets = nation_set_count();
6617 i = 0;
6618 nation_sets_iterate(pset) {
6619 sz_strlcpy(sets_packet.names[i], nation_set_untranslated_name(pset));
6620 sz_strlcpy(sets_packet.rule_names[i], nation_set_rule_name(pset));
6621 sz_strlcpy(sets_packet.descriptions[i], nation_set_description(pset));
6622 i++;
6623 } nation_sets_iterate_end;
6624 lsend_packet_ruleset_nation_sets(dest, &sets_packet);
6626 groups_packet.ngroups = nation_group_count();
6627 i = 0;
6628 nation_groups_iterate(pgroup) {
6629 sz_strlcpy(groups_packet.groups[i],
6630 nation_group_untranslated_name(pgroup));
6631 groups_packet.hidden[i] = pgroup->hidden;
6632 i++;
6633 } nation_groups_iterate_end;
6634 lsend_packet_ruleset_nation_groups(dest, &groups_packet);
6636 nations_iterate(n) {
6637 packet.id = nation_number(n);
6638 if (n->translation_domain == NULL) {
6639 packet.translation_domain[0] = '\0';
6640 } else {
6641 sz_strlcpy(packet.translation_domain, n->translation_domain);
6643 sz_strlcpy(packet.adjective, untranslated_name(&n->adjective));
6644 sz_strlcpy(packet.rule_name, rule_name_get(&n->adjective));
6645 sz_strlcpy(packet.noun_plural, untranslated_name(&n->noun_plural));
6646 sz_strlcpy(packet.graphic_str, n->flag_graphic_str);
6647 sz_strlcpy(packet.graphic_alt, n->flag_graphic_alt);
6649 i = 0;
6650 nation_leader_list_iterate(nation_leaders(n), pleader) {
6651 sz_strlcpy(packet.leader_name[i], nation_leader_name(pleader));
6652 packet.leader_is_male[i] = nation_leader_is_male(pleader);
6653 i++;
6654 } nation_leader_list_iterate_end;
6655 packet.leader_count = i;
6657 packet.style = style_number(n->style);
6658 packet.is_playable = n->is_playable;
6659 packet.barbarian_type = n->barb_type;
6661 sz_strlcpy(packet.legend, n->legend);
6663 i = 0;
6664 nation_set_list_iterate(n->sets, pset) {
6665 packet.sets[i++] = nation_set_number(pset);
6666 } nation_set_list_iterate_end;
6667 packet.nsets = i;
6669 i = 0;
6670 nation_group_list_iterate(n->groups, pgroup) {
6671 packet.groups[i++] = nation_group_number(pgroup);
6672 } nation_group_list_iterate_end;
6673 packet.ngroups = i;
6675 packet.init_government_id = n->init_government
6676 ? government_number(n->init_government) : government_count();
6677 fc_assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n->init_techs));
6678 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
6679 packet.init_techs[i] = n->init_techs[i];
6681 fc_assert(ARRAY_SIZE(packet.init_units) == ARRAY_SIZE(n->init_units));
6682 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
6683 const struct unit_type *t = n->init_units[i];
6684 packet.init_units[i] = t ? utype_number(t) : U_LAST;
6686 fc_assert(ARRAY_SIZE(packet.init_buildings)
6687 == ARRAY_SIZE(n->init_buildings));
6688 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
6689 /* Impr_type_id to int */
6690 packet.init_buildings[i] = n->init_buildings[i];
6693 lsend_packet_ruleset_nation(dest, &packet);
6694 } nations_iterate_end;
6696 /* Send initial values of is_pickable */
6697 send_nation_availability(dest, FALSE);
6700 /**************************************************************************
6701 Send the nation style ruleset information (each style) to the specified
6702 connections.
6703 **************************************************************************/
6704 static void send_ruleset_styles(struct conn_list *dest)
6706 struct packet_ruleset_style packet;
6708 styles_iterate(s) {
6709 packet.id = style_index(s);
6710 sz_strlcpy(packet.name, untranslated_name(&s->name));
6711 sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
6713 lsend_packet_ruleset_style(dest, &packet);
6714 } styles_iterate_end;
6717 /**************************************************************************
6718 Send the multiplier ruleset information to the specified
6719 connections.
6720 **************************************************************************/
6721 static void send_ruleset_multipliers(struct conn_list *dest)
6723 char helptext[MAX_LEN_PACKET];
6725 multipliers_iterate(pmul) {
6726 PACKET_STRVEC_COMPUTE(helptext, pmul->helptext);
6728 dlsend_packet_ruleset_multiplier(dest, multiplier_number(pmul),
6729 pmul->start, pmul->stop,
6730 pmul->step, pmul->def,
6731 pmul->offset, pmul->factor,
6732 untranslated_name(&pmul->name),
6733 rule_name_get(&pmul->name),
6734 helptext);
6735 } multipliers_iterate_end;
6738 /**************************************************************************
6739 Send the city-style ruleset information (each style) to the specified
6740 connections.
6741 **************************************************************************/
6742 static void send_ruleset_cities(struct conn_list *dest)
6744 struct packet_ruleset_city city_p;
6745 int k, j;
6747 for (k = 0; k < game.control.styles_count; k++) {
6748 city_p.style_id = k;
6750 j = 0;
6751 requirement_vector_iterate(&city_styles[k].reqs, preq) {
6752 city_p.reqs[j++] = *preq;
6753 } requirement_vector_iterate_end;
6754 city_p.reqs_count = j;
6756 sz_strlcpy(city_p.name, untranslated_name(&city_styles[k].name));
6757 sz_strlcpy(city_p.rule_name, rule_name_get(&city_styles[k].name));
6758 sz_strlcpy(city_p.graphic, city_styles[k].graphic);
6759 sz_strlcpy(city_p.graphic_alt, city_styles[k].graphic_alt);
6760 sz_strlcpy(city_p.citizens_graphic, city_styles[k].citizens_graphic);
6761 sz_strlcpy(city_p.citizens_graphic_alt,
6762 city_styles[k].citizens_graphic_alt);
6764 lsend_packet_ruleset_city(dest, &city_p);
6768 /**************************************************************************
6769 Send the music-style ruleset information (each style) to the specified
6770 connections.
6771 **************************************************************************/
6772 static void send_ruleset_musics(struct conn_list *dest)
6774 struct packet_ruleset_music packet;
6776 music_styles_iterate(pmus) {
6777 int j;
6779 packet.id = pmus->id;
6781 sz_strlcpy(packet.music_peaceful, pmus->music_peaceful);
6782 sz_strlcpy(packet.music_combat, pmus->music_combat);
6784 j = 0;
6785 requirement_vector_iterate(&(pmus->reqs), preq) {
6786 packet.reqs[j++] = *preq;
6787 } requirement_vector_iterate_end;
6788 packet.reqs_count = j;
6790 lsend_packet_ruleset_music(dest, &packet);
6791 } music_styles_iterate_end;
6794 /**************************************************************************
6795 Send information in packet_ruleset_game (miscellaneous rules) to the
6796 specified connections.
6797 **************************************************************************/
6798 static void send_ruleset_game(struct conn_list *dest)
6800 struct packet_ruleset_game misc_p;
6801 int i;
6803 fc_assert_ret(game.veteran != NULL);
6805 /* Per unit veteran system definition. */
6806 misc_p.veteran_levels = game.veteran->levels;
6808 for (i = 0; i < misc_p.veteran_levels; i++) {
6809 const struct veteran_level *vlevel = game.veteran->definitions + i;
6811 sz_strlcpy(misc_p.veteran_name[i], untranslated_name(&vlevel->name));
6812 misc_p.power_fact[i] = vlevel->power_fact;
6813 misc_p.move_bonus[i] = vlevel->move_bonus;
6816 fc_assert(sizeof(misc_p.global_init_techs)
6817 == sizeof(game.rgame.global_init_techs));
6818 fc_assert(ARRAY_SIZE(misc_p.global_init_techs)
6819 == ARRAY_SIZE(game.rgame.global_init_techs));
6820 memcpy(misc_p.global_init_techs, game.rgame.global_init_techs,
6821 sizeof(misc_p.global_init_techs));
6823 fc_assert(ARRAY_SIZE(misc_p.global_init_buildings)
6824 == ARRAY_SIZE(game.rgame.global_init_buildings));
6825 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
6826 /* Impr_type_id to int */
6827 misc_p.global_init_buildings[i] =
6828 game.rgame.global_init_buildings[i];
6831 misc_p.default_specialist = DEFAULT_SPECIALIST;
6833 fc_assert_ret(game.plr_bg_color != NULL);
6835 misc_p.background_red = game.plr_bg_color->r;
6836 misc_p.background_green = game.plr_bg_color->g;
6837 misc_p.background_blue = game.plr_bg_color->b;
6839 lsend_packet_ruleset_game(dest, &misc_p);
6842 /**************************************************************************
6843 Send all team names defined in the ruleset file(s) to the
6844 specified connections.
6845 **************************************************************************/
6846 static void send_ruleset_team_names(struct conn_list *dest)
6848 struct packet_team_name_info team_name_info_p;
6850 team_slots_iterate(tslot) {
6851 const char *name = team_slot_defined_name(tslot);
6853 if (NULL == name) {
6854 /* End of defined names. */
6855 break;
6858 team_name_info_p.team_id = team_slot_index(tslot);
6859 sz_strlcpy(team_name_info_p.team_name, name);
6861 lsend_packet_team_name_info(dest, &team_name_info_p);
6862 } team_slots_iterate_end;
6865 /**************************************************************************
6866 Make it clear to everyone that requested ruleset has not been loaded.
6867 **************************************************************************/
6868 static void notify_ruleset_fallback(const char *msg)
6870 notify_conn(NULL, NULL, E_LOG_FATAL, ftc_warning, "%s", msg);
6873 /**************************************************************************
6874 Loads the rulesets.
6875 **************************************************************************/
6876 bool load_rulesets(const char *restore, bool act, bool buffer_script)
6878 if (load_rulesetdir(game.server.rulesetdir, act, buffer_script)) {
6879 return TRUE;
6882 /* Fallback to previous one. */
6883 if (restore != NULL) {
6884 if (load_rulesetdir(restore, act, buffer_script)) {
6885 sz_strlcpy(game.server.rulesetdir, restore);
6887 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Keeping previous one."));
6889 /* We're in sane state as restoring previous ruleset succeeded,
6890 * but return failure to indicate that this is not what caller
6891 * wanted. */
6892 return FALSE;
6896 /* Fallback to default one, but not if that's what we tried already */
6897 if (strcmp(GAME_DEFAULT_RULESETDIR, game.server.rulesetdir)
6898 && (restore == NULL || strcmp(GAME_DEFAULT_RULESETDIR, restore))) {
6899 if (load_rulesetdir(GAME_DEFAULT_RULESETDIR, act, buffer_script)) {
6900 /* We're in sane state as fallback ruleset loading succeeded,
6901 * but return failure to indicate that this is not what caller
6902 * wanted. */
6903 sz_strlcpy(game.server.rulesetdir, GAME_DEFAULT_RULESETDIR);
6905 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Switching to default one."));
6907 return FALSE;
6911 #ifdef FREECIV_WEB
6912 log_normal(_("Cannot load any ruleset. Freeciv-web ruleset is available from "
6913 "https://github.com/freeciv/freeciv-web"));
6914 #endif /* FREECIV_WEB */
6916 /* Cannot load even default ruleset, we're in completely unusable state */
6917 exit(EXIT_FAILURE);
6920 /**************************************************************************
6921 destroy secfile. Handle NULL parameter gracefully.
6922 **************************************************************************/
6923 static void nullcheck_secfile_destroy(struct section_file *file)
6925 if (file != NULL) {
6926 secfile_destroy(file);
6930 /**************************************************************************
6931 Completely deinitialize ruleset system. Server is not in usable
6932 state after this.
6933 **************************************************************************/
6934 void rulesets_deinit(void)
6936 script_server_free();
6937 requirement_vector_free(&reqs_list);
6940 /**************************************************************************
6941 Loads the rulesets from directory.
6942 This may be called more than once and it will free any stale data.
6943 **************************************************************************/
6944 static bool load_rulesetdir(const char *rsdir, bool act, bool buffer_script)
6946 struct section_file *techfile, *unitfile, *buildfile, *govfile, *terrfile;
6947 struct section_file *stylefile, *cityfile, *nationfile, *effectfile, *gamefile;
6948 bool ok = TRUE;
6950 log_normal(_("Loading rulesets."));
6952 game_ruleset_free();
6953 /* Reset the list of available player colors. */
6954 playercolor_free();
6955 playercolor_init();
6956 game_ruleset_init();
6958 if (script_buffer != NULL) {
6959 FC_FREE(script_buffer);
6960 script_buffer = NULL;
6963 server.playable_nations = 0;
6965 techfile = openload_ruleset_file("techs", rsdir);
6966 buildfile = openload_ruleset_file("buildings", rsdir);
6967 govfile = openload_ruleset_file("governments", rsdir);
6968 unitfile = openload_ruleset_file("units", rsdir);
6969 terrfile = openload_ruleset_file("terrain", rsdir);
6970 stylefile = openload_ruleset_file("styles", rsdir);
6971 cityfile = openload_ruleset_file("cities", rsdir);
6972 nationfile = openload_ruleset_file("nations", rsdir);
6973 effectfile = openload_ruleset_file("effects", rsdir);
6974 gamefile = openload_ruleset_file("game", rsdir);
6976 if (techfile == NULL
6977 || buildfile == NULL
6978 || govfile == NULL
6979 || unitfile == NULL
6980 || terrfile == NULL
6981 || stylefile == NULL
6982 || cityfile == NULL
6983 || nationfile == NULL
6984 || effectfile == NULL
6985 || gamefile == NULL) {
6986 ok = FALSE;
6989 if (ok) {
6990 ok = load_game_names(gamefile)
6991 && load_tech_names(techfile)
6992 && load_building_names(buildfile)
6993 && load_government_names(govfile)
6994 && load_unit_names(unitfile)
6995 && load_terrain_names(terrfile)
6996 && load_style_names(stylefile)
6997 && load_nation_names(nationfile);
7000 if (ok) {
7001 ok = load_ruleset_techs(techfile);
7003 if (ok) {
7004 ok = load_ruleset_styles(stylefile);
7006 if (ok) {
7007 ok = load_ruleset_cities(cityfile);
7009 if (ok) {
7010 ok = load_ruleset_governments(govfile);
7012 if (ok) {
7013 ok = load_ruleset_terrain(terrfile); /* terrain must precede nations and units */
7015 if (ok) {
7016 ok = load_ruleset_units(unitfile);
7018 if (ok) {
7019 ok = load_ruleset_buildings(buildfile);
7021 if (ok) {
7022 ok = load_ruleset_nations(nationfile);
7024 if (ok) {
7025 ok = load_ruleset_effects(effectfile);
7027 if (ok) {
7028 ok = load_ruleset_game(gamefile, act);
7031 if (ok) {
7032 /* Init nations we just loaded. */
7033 update_nations_with_startpos();
7035 /* Needed by role_unit_precalcs(). */
7036 unit_type_action_cache_init();
7038 /* Prepare caches we want to sanity check. */
7039 role_unit_precalcs();
7040 road_integrators_cache_init();
7042 ok = sanity_check_ruleset_data();
7045 if (ok) {
7046 /* Only load settings for a sane ruleset */
7047 ok = settings_ruleset(gamefile, "settings", act);
7049 if (ok) {
7050 secfile_check_unused(gamefile);
7054 nullcheck_secfile_destroy(techfile);
7055 nullcheck_secfile_destroy(stylefile);
7056 nullcheck_secfile_destroy(cityfile);
7057 nullcheck_secfile_destroy(govfile);
7058 nullcheck_secfile_destroy(terrfile);
7059 nullcheck_secfile_destroy(unitfile);
7060 nullcheck_secfile_destroy(buildfile);
7061 nullcheck_secfile_destroy(nationfile);
7062 nullcheck_secfile_destroy(effectfile);
7063 nullcheck_secfile_destroy(gamefile);
7065 if (extra_sections) {
7066 free(extra_sections);
7067 extra_sections = NULL;
7069 if (base_sections) {
7070 free(base_sections);
7071 base_sections = NULL;
7073 if (road_sections) {
7074 free(road_sections);
7075 road_sections = NULL;
7077 if (resource_sections) {
7078 free(resource_sections);
7079 resource_sections = NULL;
7081 if (terrain_sections) {
7082 free(terrain_sections);
7083 terrain_sections = NULL;
7086 if (ok) {
7087 char **buffer = buffer_script ? &script_buffer : NULL;
7089 script_server_free();
7091 script_server_init();
7093 ok = openload_script_file("script", rsdir, buffer);
7096 if (ok && !buffer_script) {
7097 ok = openload_script_file("default", rsdir, NULL);
7100 if (ok && act) {
7101 /* Populate remaining caches. */
7102 techs_precalc_data();
7103 improvement_feature_cache_init();
7104 unit_class_iterate(pclass) {
7105 set_unit_class_caches(pclass);
7106 } unit_class_iterate_end;
7107 unit_type_iterate(ptype) {
7108 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
7109 set_unit_type_caches(ptype);
7110 } unit_type_iterate_end;
7112 /* Build advisors unit class cache corresponding to loaded rulesets */
7113 adv_units_ruleset_init();
7114 CALL_FUNC_EACH_AI(units_ruleset_init);
7116 /* We may need to adjust the number of AI players
7117 * if the number of available nations changed. */
7118 (void) aifill(game.info.aifill);
7121 return ok;
7124 /**************************************************************************
7125 Reload the game settings saved in the ruleset file.
7126 **************************************************************************/
7127 bool reload_rulesets_settings(void)
7129 struct section_file *file;
7130 bool ok = TRUE;
7132 file = openload_ruleset_file("game", game.server.rulesetdir);
7133 if (file == NULL) {
7134 ruleset_error(LOG_ERROR, "Could not load game.ruleset:\n%s",
7135 secfile_error());
7136 ok = FALSE;
7138 if (ok) {
7139 settings_ruleset(file, "settings", TRUE);
7140 secfile_destroy(file);
7143 return ok;
7146 /**************************************************************************
7147 Send all ruleset information to the specified connections.
7148 **************************************************************************/
7149 void send_rulesets(struct conn_list *dest)
7151 conn_list_compression_freeze(dest);
7153 /* ruleset_control also indicates to client that ruleset sending starts. */
7154 send_ruleset_control(dest);
7156 send_ruleset_game(dest);
7157 send_ruleset_disasters(dest);
7158 send_ruleset_achievements(dest);
7159 send_ruleset_trade_routes(dest);
7160 send_ruleset_team_names(dest);
7161 send_ruleset_actions(dest);
7162 send_ruleset_action_enablers(dest);
7163 send_ruleset_techs(dest);
7164 send_ruleset_governments(dest);
7165 send_ruleset_unit_classes(dest);
7166 send_ruleset_units(dest);
7167 send_ruleset_specialists(dest);
7168 send_ruleset_resources(dest);
7169 send_ruleset_terrain(dest);
7170 send_ruleset_extras(dest);
7171 send_ruleset_bases(dest);
7172 send_ruleset_roads(dest);
7173 send_ruleset_buildings(dest);
7174 send_ruleset_nations(dest);
7175 send_ruleset_styles(dest);
7176 send_ruleset_cities(dest);
7177 send_ruleset_multipliers(dest);
7178 send_ruleset_musics(dest);
7179 send_ruleset_cache(dest);
7181 /* Indicate client that all rulesets have now been sent. */
7182 lsend_packet_rulesets_ready(dest);
7184 /* changed game settings will be send in
7185 * connecthand.c:establish_new_connection() */
7187 conn_list_compression_thaw(dest);