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