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.
7 
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 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 /* utility */
24 #include "bitvector.h"
25 #include "deprecations.h"
26 #include "fcintl.h"
27 #include "log.h"
28 #include "mem.h"
29 #include "registry.h"
30 #include "shared.h"
31 #include "string_vector.h"
32 #include "support.h"
33 
34 /* common */
35 #include "achievements.h"
36 #include "actions.h"
37 #include "ai.h"
38 #include "base.h"
39 #include "capability.h"
40 #include "city.h"
41 #include "effects.h"
42 #include "extras.h"
43 #include "fc_types.h"
44 #include "featured_text.h"
45 #include "game.h"
46 #include "government.h"
47 #include "map.h"
48 #include "movement.h"
49 #include "multipliers.h"
50 #include "name_translation.h"
51 #include "nation.h"
52 #include "packets.h"
53 #include "player.h"
54 #include "requirements.h"
55 #include "rgbcolor.h"
56 #include "road.h"
57 #include "specialist.h"
58 #include "style.h"
59 #include "tech.h"
60 #include "traderoutes.h"
61 #include "unit.h"
62 #include "unittype.h"
63 
64 /* server */
65 #include "citytools.h"
66 #include "notify.h"
67 #include "plrhand.h"
68 #include "rssanity.h"
69 #include "settings.h"
70 #include "srv_main.h"
71 
72 /* server/advisors */
73 #include "advruleset.h"
74 
75 /* server/scripting */
76 #include "script_server.h"
77 
78 #include "ruleset.h"
79 
80 /* RULESET_SUFFIX already used, no leading dot here */
81 #define RULES_SUFFIX "ruleset"
82 #define SCRIPT_SUFFIX "lua"
83 
84 #define ADVANCE_SECTION_PREFIX "advance_"
85 #define BUILDING_SECTION_PREFIX "building_"
86 #define CITYSTYLE_SECTION_PREFIX "citystyle_"
87 #define MUSICSTYLE_SECTION_PREFIX "musicstyle_"
88 #define EFFECT_SECTION_PREFIX "effect_"
89 #define GOVERNMENT_SECTION_PREFIX "government_"
90 #define NATION_SET_SECTION_PREFIX "nset" /* without underscore? */
91 #define NATION_GROUP_SECTION_PREFIX "ngroup" /* without underscore? */
92 #define NATION_SECTION_PREFIX "nation" /* without underscore? */
93 #define STYLE_SECTION_PREFIX "style_"
94 #define RESOURCE_SECTION_PREFIX "resource_"
95 #define EXTRA_SECTION_PREFIX "extra_"
96 #define BASE_SECTION_PREFIX "base_"
97 #define ROAD_SECTION_PREFIX "road_"
98 #define SPECIALIST_SECTION_PREFIX "specialist_"
99 #define TERRAIN_SECTION_PREFIX "terrain_"
100 #define UNIT_CLASS_SECTION_PREFIX "unitclass_"
101 #define UNIT_SECTION_PREFIX "unit_"
102 #define DISASTER_SECTION_PREFIX "disaster_"
103 #define ACHIEVEMENT_SECTION_PREFIX "achievement_"
104 #define ACTION_ENABLER_SECTION_PREFIX "actionenabler_"
105 #define MULTIPLIER_SECTION_PREFIX "multiplier_"
106 
107 #define check_name(name) (check_strlen(name, MAX_LEN_NAME, NULL))
108 
109 /* avoid re-reading files */
110 static const char name_too_long[] = "Name \"%s\" too long; truncating.";
111 #define MAX_SECTION_LABEL 64
112 #define section_strlcpy(dst, src) \
113 	(void) loud_strlcpy(dst, src, MAX_SECTION_LABEL, name_too_long)
114 static char *resource_sections = NULL;
115 static char *terrain_sections = NULL;
116 static char *extra_sections = NULL;
117 static char *base_sections = NULL;
118 static char *road_sections = NULL;
119 
120 static struct requirement_vector reqs_list;
121 
122 static bool load_rulesetdir(const char *rsdir, bool act, bool buffer_script);
123 static struct section_file *openload_ruleset_file(const char *whichset,
124                                                   const char *rsdir);
125 static const char *check_ruleset_capabilities(struct section_file *file,
126                                               const char *us_capstr,
127                                               const char *filename);
128 
129 static bool load_game_names(struct section_file *file);
130 static bool load_tech_names(struct section_file *file);
131 static bool load_unit_names(struct section_file *file);
132 static bool load_building_names(struct section_file *file);
133 static bool load_government_names(struct section_file *file);
134 static bool load_terrain_names(struct section_file *file);
135 static bool load_style_names(struct section_file *file);
136 static bool load_nation_names(struct section_file *file);
137 static bool load_city_name_list(struct section_file *file,
138                                 struct nation_type *pnation,
139                                 const char *secfile_str1,
140                                 const char *secfile_str2,
141                                 const char **allowed_terrains,
142                                 size_t atcount);
143 
144 static bool load_ruleset_techs(struct section_file *file);
145 static bool load_ruleset_units(struct section_file *file);
146 static bool load_ruleset_buildings(struct section_file *file);
147 static bool load_ruleset_governments(struct section_file *file);
148 static bool load_ruleset_terrain(struct section_file *file);
149 static bool load_ruleset_styles(struct section_file *file);
150 static bool load_ruleset_cities(struct section_file *file);
151 static bool load_ruleset_effects(struct section_file *file);
152 
153 static bool load_ruleset_game(struct section_file *file, bool act);
154 
155 static void send_ruleset_techs(struct conn_list *dest);
156 static void send_ruleset_unit_classes(struct conn_list *dest);
157 static void send_ruleset_units(struct conn_list *dest);
158 static void send_ruleset_buildings(struct conn_list *dest);
159 static void send_ruleset_terrain(struct conn_list *dest);
160 static void send_ruleset_resources(struct conn_list *dest);
161 static void send_ruleset_extras(struct conn_list *dest);
162 static void send_ruleset_bases(struct conn_list *dest);
163 static void send_ruleset_roads(struct conn_list *dest);
164 static void send_ruleset_governments(struct conn_list *dest);
165 static void send_ruleset_styles(struct conn_list *dest);
166 static void send_ruleset_musics(struct conn_list *dest);
167 static void send_ruleset_cities(struct conn_list *dest);
168 static void send_ruleset_game(struct conn_list *dest);
169 static void send_ruleset_team_names(struct conn_list *dest);
170 
171 static bool load_ruleset_veteran(struct section_file *file,
172                                  const char *path,
173                                  struct veteran_system **vsystem, char *err,
174                                  size_t err_len);
175 
176 char *script_buffer = NULL;
177 
178 /**************************************************************************
179   Notifications about ruleset errors to clients. Especially important in
180   case of internal server crashing.
181 **************************************************************************/
ruleset_error_real(const char * file,const char * function,int line,enum log_level level,const char * format,...)182 void ruleset_error_real(const char *file, const char *function,
183                         int line, enum log_level level,
184                         const char *format, ...)
185 {
186   va_list args;
187   char buf[1024];
188 
189   va_start(args, format);
190   vdo_log(file, function, line, FALSE, level, buf, sizeof(buf), format, args);
191   va_end(args);
192 
193   if (LOG_FATAL >= level) {
194     exit(EXIT_FAILURE);
195   }
196 }
197 
198 /**************************************************************************
199   datafilename() wrapper: tries to match in two ways.
200   Returns NULL on failure, the (statically allocated) filename on success.
201 **************************************************************************/
valid_ruleset_filename(const char * subdir,const char * name,const char * extension)202 static const char *valid_ruleset_filename(const char *subdir,
203                                           const char *name,
204                                           const char *extension)
205 {
206   char filename[512];
207   const char *dfilename;
208 
209   fc_assert_ret_val(subdir && name && extension, NULL);
210 
211   fc_snprintf(filename, sizeof(filename), "%s" DIR_SEPARATOR "%s.%s",
212               subdir, name, extension);
213   log_verbose("Trying \"%s\".", filename);
214   dfilename = fileinfoname(get_data_dirs(), filename);
215   if (dfilename) {
216     return dfilename;
217   }
218 
219   fc_snprintf(filename, sizeof(filename), "default" DIR_SEPARATOR "%s.%s", name, extension);
220   log_verbose("Trying \"%s\": default ruleset directory.", filename);
221   dfilename = fileinfoname(get_data_dirs(), filename);
222   if (dfilename) {
223     return dfilename;
224   }
225 
226   fc_snprintf(filename, sizeof(filename), "%s_%s.%s",
227               subdir, name, extension);
228   log_verbose("Trying \"%s\": alternative ruleset filename syntax.",
229               filename);
230   dfilename = fileinfoname(get_data_dirs(), filename);
231   if (dfilename) {
232     return dfilename;
233   } else {
234     ruleset_error(LOG_ERROR,
235                   /* TRANS: message about an installation error. */
236                   _("Could not find a readable \"%s.%s\" ruleset file."),
237                   name, extension);
238   }
239 
240   return NULL;
241 }
242 
243 /**************************************************************************
244   Return current script.lua buffer.
245 **************************************************************************/
get_script_buffer(void)246 char *get_script_buffer(void)
247 {
248   return script_buffer;
249 }
250 
251 /**************************************************************************
252   Do initial section_file_load on a ruleset file.
253   "whichset" = "techs", "units", "buildings", "terrain", ...
254 **************************************************************************/
openload_ruleset_file(const char * whichset,const char * rsdir)255 static struct section_file *openload_ruleset_file(const char *whichset,
256                                                   const char *rsdir)
257 {
258   char sfilename[512];
259   const char *dfilename = valid_ruleset_filename(rsdir, whichset,
260                                                  RULES_SUFFIX);
261   struct section_file *secfile;
262 
263   if (dfilename == NULL) {
264     return NULL;
265   }
266 
267   /* Need to save a copy of the filename for following message, since
268      section_file_load() may call datafilename() for includes. */
269   sz_strlcpy(sfilename, dfilename);
270   secfile = secfile_load(sfilename, FALSE);
271 
272   if (secfile == NULL) {
273     ruleset_error(LOG_ERROR, "Could not load ruleset '%s':\n%s",
274                   sfilename, secfile_error());
275   }
276 
277   return secfile;
278 }
279 
280 /**************************************************************************
281   Parse script file.
282 **************************************************************************/
openload_script_file(const char * whichset,const char * rsdir,char ** buffer)283 static bool openload_script_file(const char *whichset, const char *rsdir,
284                                  char **buffer)
285 {
286   const char *dfilename = valid_ruleset_filename(rsdir, whichset,
287                                                  SCRIPT_SUFFIX);
288 
289   if (dfilename == NULL) {
290     return FALSE;
291   }
292 
293   if (buffer == NULL) {
294     if (!script_server_do_file(NULL, dfilename)) {
295       ruleset_error(LOG_ERROR, "\"%s\": could not load ruleset script.",
296                     dfilename);
297 
298       return FALSE;
299     }
300   } else {
301     script_server_load_file(dfilename, buffer);
302   }
303 
304   return TRUE;
305 }
306 
307 /**************************************************************************
308   Ruleset files should have a capabilities string datafile.options
309   This gets and returns that string, and checks that the required
310   capabilities specified are satisified.
311 **************************************************************************/
check_ruleset_capabilities(struct section_file * file,const char * us_capstr,const char * filename)312 static const char *check_ruleset_capabilities(struct section_file *file,
313                                               const char *us_capstr,
314                                               const char *filename)
315 {
316   const char *datafile_options;
317 
318   if (!(datafile_options = secfile_lookup_str(file, "datafile.options"))) {
319     log_fatal("\"%s\": ruleset capability problem:", filename);
320     ruleset_error(LOG_ERROR, "%s", secfile_error());
321 
322     return NULL;
323   }
324   if (!has_capabilities(us_capstr, datafile_options)) {
325     log_fatal("\"%s\": ruleset datafile appears incompatible:", filename);
326     log_fatal("  datafile options: %s", datafile_options);
327     log_fatal("  supported options: %s", us_capstr);
328     ruleset_error(LOG_ERROR, "Capability problem");
329 
330     return NULL;
331   }
332   if (!has_capabilities(datafile_options, us_capstr)) {
333     log_fatal("\"%s\": ruleset datafile claims required option(s)"
334               " that we don't support:", filename);
335     log_fatal("  datafile options: %s", datafile_options);
336     log_fatal("  supported options: %s", us_capstr);
337     ruleset_error(LOG_ERROR, "Capability problem");
338 
339     return NULL;
340   }
341   return datafile_options;
342 }
343 
344 /**************************************************************************
345   Load a requirement list.  The list is returned as a static vector
346   (callers need not worry about freeing anything).
347 **************************************************************************/
lookup_req_list(struct section_file * file,const char * sec,const char * sub,const char * rfor)348 static struct requirement_vector *lookup_req_list(struct section_file *file,
349                                                   const char *sec,
350                                                   const char *sub,
351                                                   const char *rfor)
352 {
353   const char *type, *name;
354   int j;
355   const char *filename;
356 
357   filename = secfile_name(file);
358 
359   requirement_vector_reserve(&reqs_list, 0);
360 
361   for (j = 0; (type = secfile_lookup_str_default(file, NULL, "%s.%s%d.type",
362                                                  sec, sub, j)); j++) {
363     char buf[MAX_LEN_NAME];
364     const char *range;
365     bool survives, present, quiet;
366     struct entry *pentry;
367     struct requirement req;
368 
369     if (!(pentry = secfile_entry_lookup(file, "%s.%s%d.name",
370                                         sec, sub, j))) {
371       ruleset_error(LOG_ERROR, "%s", secfile_error());
372 
373       return NULL;
374     }
375     name = NULL;
376     switch (entry_type(pentry)) {
377     case ENTRY_BOOL:
378       {
379         bool val;
380 
381         if (entry_bool_get(pentry, &val)) {
382           fc_snprintf(buf, sizeof(buf), "%d", val);
383           name = buf;
384         }
385       }
386       break;
387     case ENTRY_INT:
388       {
389         int val;
390 
391         if (entry_int_get(pentry, &val)) {
392           fc_snprintf(buf, sizeof(buf), "%d", val);
393           name = buf;
394         }
395       }
396       break;
397     case ENTRY_STR:
398       (void) entry_str_get(pentry, &name);
399       break;
400     case ENTRY_FLOAT:
401       fc_assert(entry_type(pentry) != ENTRY_FLOAT);
402       ruleset_error(LOG_ERROR,
403                     "\"%s\": trying to have an floating point entry as a requirement name in '%s.%s%d'.",
404                     filename, sec, sub, j);
405       break;
406     case ENTRY_FILEREFERENCE:
407       fc_assert(entry_type(pentry) != ENTRY_FILEREFERENCE);
408       break;
409     case ENTRY_ILLEGAL:
410       fc_assert(entry_type(pentry) != ENTRY_ILLEGAL);
411       break;
412     }
413     if (NULL == name) {
414       ruleset_error(LOG_ERROR,
415                     "\"%s\": error in handling requirement name for '%s.%s%d'.",
416                     filename, sec, sub, j);
417       return NULL;
418     }
419 
420     if (!(range = secfile_lookup_str(file, "%s.%s%d.range", sec, sub, j))) {
421       ruleset_error(LOG_ERROR, "%s", secfile_error());
422 
423       return NULL;
424     }
425 
426     survives = FALSE;
427     if ((pentry = secfile_entry_lookup(file, "%s.%s%d.survives",
428                                         sec, sub, j))
429         && !entry_bool_get(pentry, &survives)) {
430       ruleset_error(LOG_ERROR,
431                     "\"%s\": invalid boolean value for survives for "
432                     "'%s.%s%d'.", filename, sec, sub, j);
433     }
434 
435     present = TRUE;
436     if ((pentry = secfile_entry_lookup(file, "%s.%s%d.present",
437                                         sec, sub, j))
438         && !entry_bool_get(pentry, &present)) {
439       ruleset_error(LOG_ERROR,
440                     "\"%s\": invalid boolean value for present for "
441                     "'%s.%s%d'.", filename, sec, sub, j);
442     }
443     quiet = FALSE;
444     if ((pentry = secfile_entry_lookup(file, "%s.%s%d.quiet",
445                                         sec, sub, j))
446         && !entry_bool_get(pentry, &quiet)) {
447       ruleset_error(LOG_ERROR,
448                     "\"%s\": invalid boolean value for quiet for "
449                     "'%s.%s%d'.", filename, sec, sub, j);
450     }
451 
452     req = req_from_str(type, range, survives, present, quiet, name);
453     if (req.source.kind == universals_n_invalid()) {
454       ruleset_error(LOG_ERROR, "\"%s\" [%s] has invalid or unknown req: "
455                                "\"%s\" \"%s\".",
456                     filename, sec, type, name);
457 
458       return NULL;
459     }
460 
461     requirement_vector_append(&reqs_list, req);
462   }
463 
464   if (j > MAX_NUM_REQS) {
465     ruleset_error(LOG_ERROR, "Too many (%d) requirements for %s. Max is %d",
466                   j, rfor, MAX_NUM_REQS);
467 
468     return NULL;
469   }
470 
471   return &reqs_list;
472 }
473 
474 /**************************************************************************
475   Load combat bonus list
476 **************************************************************************/
lookup_cbonus_list(struct combat_bonus_list * list,struct section_file * file,const char * sec,const char * sub)477 static bool lookup_cbonus_list(struct combat_bonus_list *list,
478                                struct section_file *file,
479                                const char *sec,
480                                const char *sub)
481 {
482   const char *flag;
483   int j;
484   const char *filename;
485   bool success = TRUE;
486 
487   filename = secfile_name(file);
488 
489   for (j = 0; (flag = secfile_lookup_str_default(file, NULL, "%s.%s%d.flag",
490                                                  sec, sub, j)); j++) {
491     struct combat_bonus *bonus = fc_malloc(sizeof(*bonus));
492     const char *type;
493 
494     bonus->flag = unit_type_flag_id_by_name(flag, fc_strcasecmp);
495     if (!unit_type_flag_id_is_valid(bonus->flag)) {
496       log_error("\"%s\": unknown flag name \"%s\" in '%s.%s'.",
497                 filename, flag, sec, sub);
498       FC_FREE(bonus);
499       success = FALSE;
500       continue;
501     }
502     type = secfile_lookup_str(file, "%s.%s%d.type", sec, sub, j);
503     bonus->type = combat_bonus_type_by_name(type, fc_strcasecmp);
504     if (!combat_bonus_type_is_valid(bonus->type)) {
505       log_error("\"%s\": unknown bonus type \"%s\" in '%s.%s'.",
506                 filename, type, sec, sub);
507       FC_FREE(bonus);
508       success = FALSE;
509       continue;
510     }
511     if (!secfile_lookup_int(file, &bonus->value, "%s.%s%d.value",
512                             sec, sub, j)) {
513       log_error("\"%s\": failed to get value from '%s.%s%d'.",
514                 filename, sec, sub, j);
515       FC_FREE(bonus);
516       success = FALSE;
517       continue;
518     }
519     bonus->quiet = secfile_lookup_bool_default(file, FALSE,
520                                                "%s.%s%d.quiet",
521                                                sec, sub, j);
522     combat_bonus_list_append(list, bonus);
523   }
524 
525   return success;
526 }
527 
528 /**************************************************************************
529  Lookup a string prefix.entry in the file and return the corresponding
530  advances pointer.  If (!required), return A_NEVER for match "Never" or
531  can't match.  If (required), die when can't match.  Note the first tech
532  should have name "None" so that will always match.
533  If description is not NULL, it is used in the warning message
534  instead of prefix (eg pass unit->name instead of prefix="units2.u27")
535 **************************************************************************/
lookup_tech(struct section_file * file,struct advance ** result,const char * prefix,const char * entry,const char * filename,const char * description)536 static bool lookup_tech(struct section_file *file,
537                         struct advance **result,
538                         const char *prefix, const char *entry,
539                         const char *filename,
540                         const char *description)
541 {
542   const char *sval;
543 
544   sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
545   if (!sval || !strcmp(sval, "Never")) {
546     *result = A_NEVER;
547   } else {
548     *result = advance_by_rule_name(sval);
549 
550     if (A_NEVER == *result) {
551       ruleset_error(LOG_ERROR,
552                     "\"%s\" %s %s: couldn't match \"%s\".",
553                     filename, (description ? description : prefix), entry, sval);
554       return FALSE;
555     }
556   }
557 
558   return TRUE;
559 }
560 
561 /**************************************************************************
562  Lookup a string prefix.entry in the file and return the corresponding
563  improvement pointer. Return B_NEVER for match "None" or
564  can't match.
565  If description is not NULL, it is used in the warning message
566  instead of prefix (eg pass unit->name instead of prefix="units2.u27")
567 **************************************************************************/
lookup_building(struct section_file * file,const char * prefix,const char * entry,struct impr_type ** result,const char * filename,const char * description)568 static bool lookup_building(struct section_file *file,
569                             const char *prefix, const char *entry,
570                             struct impr_type **result,
571                             const char *filename,
572                             const char *description)
573 {
574   const char *sval;
575   bool ok = TRUE;
576 
577   sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
578   if (!sval || strcmp(sval, "None") == 0) {
579     *result = B_NEVER;
580   } else {
581     *result = improvement_by_rule_name(sval);
582 
583     if (B_NEVER == *result) {
584       ruleset_error(LOG_ERROR,
585                     "\"%s\" %s %s: couldn't match \"%s\".",
586                     filename, (description ? description : prefix), entry, sval);
587       ok = FALSE;
588     }
589   }
590 
591   return ok;
592 }
593 
594 /**************************************************************************
595  Lookup a prefix.entry string vector in the file and fill in the
596  array, which should hold MAX_NUM_UNIT_LIST items. The output array is
597  either NULL terminated or full (contains MAX_NUM_UNIT_LIST
598  items). If the vector is not found and the required parameter is set,
599  we report it as an error, otherwise we just punt.
600 **************************************************************************/
lookup_unit_list(struct section_file * file,const char * prefix,const char * entry,struct unit_type ** output,const char * filename)601 static bool lookup_unit_list(struct section_file *file, const char *prefix,
602                              const char *entry,
603                              struct unit_type **output,
604                              const char *filename)
605 {
606   const char **slist;
607   size_t nval;
608   int i;
609   bool ok = TRUE;
610 
611   /* pre-fill with NULL: */
612   for(i = 0; i < MAX_NUM_UNIT_LIST; i++) {
613     output[i] = NULL;
614   }
615   slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
616   if (nval == 0) {
617     /* 'No vector' is considered same as empty vector */
618     if (slist != NULL) {
619       free(slist);
620     }
621     return TRUE;
622   }
623   if (nval > MAX_NUM_UNIT_LIST) {
624     ruleset_error(LOG_ERROR,
625                   "\"%s\": string vector %s.%s too long (%d, max %d)",
626                   filename, prefix, entry, (int) nval, MAX_NUM_UNIT_LIST);
627     ok = FALSE;
628   } else if (nval == 1 && strcmp(slist[0], "") == 0) {
629     free(slist);
630     return TRUE;
631   }
632   if (ok) {
633     for (i = 0; i < nval; i++) {
634       const char *sval = slist[i];
635       struct unit_type *punittype = unit_type_by_rule_name(sval);
636 
637       if (!punittype) {
638         ruleset_error(LOG_ERROR,
639                       "\"%s\" %s.%s (%d): couldn't match \"%s\".",
640                       filename, prefix, entry, i, sval);
641         ok = FALSE;
642         break;
643       }
644       output[i] = punittype;
645       log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
646                 utype_number(punittype));
647     }
648   }
649   free(slist);
650 
651   return ok;
652 }
653 
654 /**************************************************************************
655  Lookup a prefix.entry string vector in the file and fill in the
656  array, which should hold MAX_NUM_TECH_LIST items. The output array is
657  either A_LAST terminated or full (contains MAX_NUM_TECH_LIST
658  items). All valid entries of the output array are guaranteed to
659  exist.
660 **************************************************************************/
lookup_tech_list(struct section_file * file,const char * prefix,const char * entry,int * output,const char * filename)661 static bool lookup_tech_list(struct section_file *file, const char *prefix,
662                              const char *entry, int *output,
663                              const char *filename)
664 {
665   const char **slist;
666   size_t nval;
667   int i;
668   bool ok = TRUE;
669 
670   /* pre-fill with A_LAST: */
671   for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
672     output[i] = A_LAST;
673   }
674   slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
675   if (slist == NULL || nval == 0) {
676     return TRUE;
677   } else if (nval > MAX_NUM_TECH_LIST) {
678     ruleset_error(LOG_ERROR,
679                   "\"%s\": string vector %s.%s too long (%d, max %d)",
680                   filename, prefix, entry, (int) nval, MAX_NUM_TECH_LIST);
681     ok = FALSE;
682   }
683 
684   if (ok) {
685     if (nval == 1 && strcmp(slist[0], "") == 0) {
686       FC_FREE(slist);
687       return TRUE;
688     }
689     for (i = 0; i < nval && ok; i++) {
690       const char *sval = slist[i];
691       struct advance *padvance = advance_by_rule_name(sval);
692 
693       if (NULL == padvance) {
694         ruleset_error(LOG_ERROR,
695                       "\"%s\" %s.%s (%d): couldn't match \"%s\".",
696                       filename, prefix, entry, i, sval);
697         ok = FALSE;
698       }
699       if (!valid_advance(padvance)) {
700         ruleset_error(LOG_ERROR, "\"%s\" %s.%s (%d): \"%s\" is removed.",
701                       filename, prefix, entry, i, sval);
702         ok = FALSE;
703       }
704 
705       if (ok) {
706         output[i] = advance_number(padvance);
707         log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
708                   advance_number(padvance));
709       }
710     }
711   }
712   FC_FREE(slist);
713 
714   return ok;
715 }
716 
717 /**************************************************************************
718   Lookup a prefix.entry string vector in the file and fill in the
719   array, which should hold MAX_NUM_BUILDING_LIST items. The output array is
720   either B_LAST terminated or full (contains MAX_NUM_BUILDING_LIST
721   items). [All valid entries of the output array are guaranteed to pass
722   improvement_exist()?]
723 **************************************************************************/
lookup_building_list(struct section_file * file,const char * prefix,const char * entry,int * output,const char * filename)724 static bool lookup_building_list(struct section_file *file,
725                                  const char *prefix, const char *entry,
726                                  int *output, const char *filename)
727 {
728   const char **slist;
729   size_t nval;
730   int i;
731   bool ok = TRUE;
732 
733   /* pre-fill with B_LAST: */
734   for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
735     output[i] = B_LAST;
736   }
737   slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
738   if (nval > MAX_NUM_BUILDING_LIST) {
739     ruleset_error(LOG_ERROR,
740                   "\"%s\": string vector %s.%s too long (%d, max %d)",
741                   filename, prefix, entry, (int) nval, MAX_NUM_BUILDING_LIST);
742     ok = FALSE;
743   } else if (nval == 0 || (nval == 1 && strcmp(slist[0], "") == 0)) {
744     if (slist != NULL) {
745       FC_FREE(slist);
746     }
747     return TRUE;
748   }
749   if (ok) {
750     for (i = 0; i < nval; i++) {
751       const char *sval = slist[i];
752       struct impr_type *pimprove = improvement_by_rule_name(sval);
753 
754       if (NULL == pimprove) {
755         ruleset_error(LOG_ERROR,
756                       "\"%s\" %s.%s (%d): couldn't match \"%s\".",
757                       filename, prefix, entry, i, sval);
758         ok = FALSE;
759         break;
760       }
761       output[i] = improvement_number(pimprove);
762       log_debug("%s.%s,%d %s %d", prefix, entry, i, sval, output[i]);
763     }
764   }
765   free(slist);
766 
767   return ok;
768 }
769 
770 /**************************************************************************
771  Lookup a string prefix.entry in the file and set result to the corresponding
772  unit_type.
773  If description is not NULL, it is used in the warning message
774  instead of prefix (eg pass unit->name instead of prefix="units2.u27")
775 **************************************************************************/
lookup_unit_type(struct section_file * file,const char * prefix,const char * entry,struct unit_type ** result,const char * filename,const char * description)776 static bool lookup_unit_type(struct section_file *file,
777                              const char *prefix,
778                              const char *entry,
779                              struct unit_type **result,
780                              const char *filename,
781                              const char *description)
782 {
783   const char *sval;
784 
785   sval = secfile_lookup_str_default(file, "None", "%s.%s", prefix, entry);
786 
787   if (strcmp(sval, "None") == 0) {
788     *result = NULL;
789   } else {
790     *result = unit_type_by_rule_name(sval);
791     if (*result == NULL) {
792       ruleset_error(LOG_ERROR,
793                     "\"%s\" %s %s: couldn't match \"%s\".",
794                     filename, (description ? description : prefix), entry, sval);
795 
796       return FALSE;
797     }
798   }
799 
800   return TRUE;
801 }
802 
803 /**************************************************************************
804   Lookup entry in the file and return the corresponding government index.
805   filename is for error message.
806 **************************************************************************/
lookup_government(struct section_file * file,const char * entry,const char * filename,struct government * fallback)807 static struct government *lookup_government(struct section_file *file,
808 					    const char *entry,
809 					    const char *filename,
810                                             struct government *fallback)
811 {
812   const char *sval;
813   struct government *gov;
814 
815   sval = secfile_lookup_str_default(file, NULL, "%s", entry);
816   if (!sval) {
817     gov = fallback;
818   } else {
819     gov = government_by_rule_name(sval);
820   }
821   if (!gov) {
822     ruleset_error(LOG_ERROR,
823                   "\"%s\" %s: couldn't match \"%s\".",
824                   filename, entry, sval);
825   }
826   return gov;
827 }
828 
829 /****************************************************************************
830   Lookup optional string, returning allocated memory or NULL.
831 ****************************************************************************/
lookup_string(struct section_file * file,const char * prefix,const char * suffix)832 static char *lookup_string(struct section_file *file, const char *prefix,
833                            const char *suffix)
834 {
835   const char *sval = secfile_lookup_str(file, "%s.%s", prefix, suffix);
836 
837   if (NULL != sval) {
838     char copy[strlen(sval) + 1];
839 
840     strcpy(copy, sval);
841     remove_leading_trailing_spaces(copy);
842     if (strlen(copy) > 0) {
843       return fc_strdup(copy);
844     }
845   }
846   return NULL;
847 }
848 
849 /****************************************************************************
850   Lookup optional string vector, returning allocated memory or NULL.
851 ****************************************************************************/
lookup_strvec(struct section_file * file,const char * prefix,const char * suffix)852 static struct strvec *lookup_strvec(struct section_file *file,
853                                     const char *prefix, const char *suffix)
854 {
855   size_t dim;
856   const char **vec = secfile_lookup_str_vec(file, &dim,
857                                             "%s.%s", prefix, suffix);
858 
859   if (NULL != vec) {
860     struct strvec *dest = strvec_new();
861 
862     strvec_store(dest, vec, dim);
863     free(vec);
864     return dest;
865   }
866   return NULL;
867 }
868 
869 /**************************************************************************
870   Look up the resource section name and return its pointer.
871 **************************************************************************/
lookup_resource(const char * filename,const char * name,const char * jsection)872 static struct resource *lookup_resource(const char *filename,
873 					const char *name,
874 					const char *jsection)
875 {
876   struct resource *pres;
877 
878   pres = resource_by_rule_name(name);
879 
880   if (pres == NULL) {
881     ruleset_error(LOG_ERROR,
882                   "\"%s\" [%s] has unknown \"%s\".",
883                   filename,
884                   jsection,
885                   name);
886   }
887 
888   return pres;
889 }
890 
891 /**************************************************************************
892   Look up the terrain by name and return its pointer.
893   filename is for error message.
894 **************************************************************************/
lookup_terrain(struct section_file * file,const char * entry,const char * filename,struct terrain * pthis,struct terrain ** result)895 static bool lookup_terrain(struct section_file *file,
896                            const char *entry,
897                            const char *filename,
898                            struct terrain *pthis,
899                            struct terrain **result)
900 {
901   const int j = terrain_index(pthis);
902   const char *jsection = &terrain_sections[j * MAX_SECTION_LABEL];
903   const char *name = secfile_lookup_str(file, "%s.%s", jsection, entry);
904   struct terrain *pterr;
905 
906   if (NULL == name
907       || *name == '\0'
908       || (0 == strcmp(name, "none"))
909       || (0 == strcmp(name, "no"))) {
910     *result = T_NONE;
911 
912     return TRUE;
913   }
914   if (0 == strcmp(name, "yes")) {
915     *result = pthis;
916 
917     return TRUE;
918   }
919 
920   pterr = terrain_by_rule_name(name);
921   *result = pterr;
922 
923   if (pterr == NULL) {
924     ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown \"%s\".",
925                   secfile_name(file), jsection, name);
926     return FALSE;
927   }
928 
929   return TRUE;
930 }
931 
932 /**************************************************************************
933   Look up a value comparable to activity_count (road_time, etc).
934   item_name describes the thing which has the time property, if non-NULL,
935   for any error message.
936   Returns FALSE if not found in secfile, but TRUE even if validation failed.
937   Sets *ok to FALSE if validation failed, leaves it alone otherwise.
938 **************************************************************************/
lookup_time(const struct section_file * secfile,int * turns,const char * sec_name,const char * property_name,const char * filename,const char * item_name,bool * ok)939 static bool lookup_time(const struct section_file *secfile, int *turns,
940                         const char *sec_name, const char *property_name,
941                         const char *filename, const char *item_name,
942                         bool *ok)
943 {
944   /* Assumes that PACKET_UNIT_INFO.activity_count in packets.def is UINT16 */
945   const int max_turns = 65535 / ACTIVITY_FACTOR;
946 
947   if (!secfile_lookup_int(secfile, turns, "%s.%s", sec_name, property_name)) {
948     return FALSE;
949   }
950 
951   if (*turns > max_turns) {
952     ruleset_error(LOG_ERROR,
953                   "\"%s\": \"%s\": \"%s\" value %d too large (max %d)",
954                   filename, item_name ? item_name : sec_name,
955                   property_name, *turns, max_turns);
956     *ok = FALSE;
957   }
958 
959   return TRUE; /* we found _something */
960 }
961 
962 /**************************************************************************
963   Load "name" and (optionally) "rule_name" into a struct name_translation.
964 **************************************************************************/
ruleset_load_names(struct name_translation * pname,const char * domain,struct section_file * file,const char * sec_name)965 static bool ruleset_load_names(struct name_translation *pname,
966                                const char *domain,
967                                struct section_file *file,
968                                const char *sec_name)
969 {
970   const char *name = secfile_lookup_str(file, "%s.name", sec_name);
971   const char *rule_name = secfile_lookup_str(file, "%s.rule_name", sec_name);
972 
973   if (!name) {
974     ruleset_error(LOG_ERROR,
975                   "\"%s\" [%s]: no \"name\" specified.",
976                   secfile_name(file), sec_name);
977     return FALSE;
978   }
979 
980   names_set(pname, domain, name, rule_name);
981 
982   return TRUE;
983 }
984 
985 /**************************************************************************
986   Load trait values to array.
987 **************************************************************************/
ruleset_load_traits(struct trait_limits * out,struct section_file * file,const char * secname,const char * field_prefix)988 static void ruleset_load_traits(struct trait_limits *out,
989                                 struct section_file *file,
990                                 const char *secname, const char *field_prefix)
991 {
992   enum trait tr;
993 
994   /* FIXME: Use specenum trait names without duplicating them here.
995    *        Just needs to take care of case. */
996   const char *trait_names[] = {
997     "expansionist",
998     "trader",
999     "aggressive",
1000     NULL
1001   };
1002 
1003   for (tr = trait_begin(); tr != trait_end() && trait_names[tr] != NULL; tr = trait_next(tr)) {
1004     out[tr].min = secfile_lookup_int_default(file, -1, "%s.%s%s_min",
1005                                              secname,
1006                                              field_prefix,
1007                                              trait_names[tr]);
1008     out[tr].max = secfile_lookup_int_default(file, -1, "%s.%s%s_max",
1009                                              secname,
1010                                              field_prefix,
1011                                              trait_names[tr]);
1012     out[tr].fixed = secfile_lookup_int_default(file, -1, "%s.%s%s_default",
1013                                                secname,
1014                                                field_prefix,
1015                                                trait_names[tr]);
1016   }
1017 
1018   fc_assert(tr == trait_end()); /* number of trait_names correct */
1019 }
1020 
1021 /**************************************************************************
1022   Load names from game.ruleset so other rulesets can refer to objects
1023   with their name.
1024 **************************************************************************/
load_game_names(struct section_file * file)1025 static bool load_game_names(struct section_file *file)
1026 {
1027   struct section_list *sec;
1028   int nval;
1029   const char *filename = secfile_name(file);
1030   bool ok = TRUE;
1031 
1032   sec = secfile_sections_by_name_prefix(file, ACHIEVEMENT_SECTION_PREFIX);
1033   nval = (NULL != sec ? section_list_size(sec) : 0);
1034   if (nval > MAX_ACHIEVEMENT_TYPES) {
1035     int num = nval; /* No "size_t" to printf */
1036 
1037     ruleset_error(LOG_ERROR, "\"%s\": Too many achievement types (%d, max %d)",
1038                   filename, num, MAX_ACHIEVEMENT_TYPES);
1039     ok = FALSE;
1040   } else {
1041     game.control.num_achievement_types = nval;
1042   }
1043 
1044   if (ok) {
1045     achievements_iterate(pach) {
1046       const char *sec_name = section_name(section_list_get(sec, achievement_index(pach)));
1047 
1048       if (!ruleset_load_names(&pach->name, NULL, file, sec_name)) {
1049         ruleset_error(LOG_ERROR, "\"%s\": Cannot load achievement names",
1050                       filename);
1051         ok = FALSE;
1052         break;
1053       }
1054     } achievements_iterate_end;
1055   }
1056 
1057   section_list_destroy(sec);
1058 
1059   return ok;
1060 }
1061 
1062 
1063 /**************************************************************************
1064   Load names of technologies so other rulesets can refer to techs with
1065   their name.
1066 **************************************************************************/
load_tech_names(struct section_file * file)1067 static bool load_tech_names(struct section_file *file)
1068 {
1069   struct section_list *sec = NULL;
1070   /* Number of techs in the ruleset (means without A_NONE). */
1071   int num_techs = 0;
1072   int i;
1073   const char *filename = secfile_name(file);
1074   bool ok = TRUE;
1075   const char *flag;
1076 
1077   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
1078   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
1079 
1080   /* User tech flag names */
1081   for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
1082        i++) {
1083     const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
1084                                                      i);
1085     if (tech_flag_id_by_name(flag, fc_strcasecmp) != tech_flag_id_invalid()) {
1086       ruleset_error(LOG_ERROR, "\"%s\": Duplicate tech flag name '%s'",
1087                     filename, flag);
1088       ok = FALSE;
1089       break;
1090     }
1091     if (i > MAX_NUM_USER_TECH_FLAGS) {
1092       ruleset_error(LOG_ERROR, "\"%s\": Too many user tech flags!",
1093                     filename);
1094       ok = FALSE;
1095       break;
1096     }
1097 
1098     set_user_tech_flag_name(TECH_USER_1 + i, flag, helptxt);
1099   }
1100 
1101   if (ok) {
1102     for (; i < MAX_NUM_USER_TECH_FLAGS; i++) {
1103       set_user_tech_flag_name(TECH_USER_1 + i, NULL, NULL);
1104     }
1105 
1106     /* The techs: */
1107     sec = secfile_sections_by_name_prefix(file, ADVANCE_SECTION_PREFIX);
1108     if (NULL == sec || 0 == (num_techs = section_list_size(sec))) {
1109       ruleset_error(LOG_ERROR, "\"%s\": No Advances?!?", filename);
1110       ok = FALSE;
1111     } else {
1112       log_verbose("%d advances (including possibly unused)", num_techs);
1113       if (num_techs + A_FIRST > A_LAST) {
1114         ruleset_error(LOG_ERROR, "\"%s\": Too many advances (%d, max %d)",
1115                       filename, num_techs, A_LAST - A_FIRST);
1116         ok = FALSE;
1117       }
1118     }
1119   }
1120 
1121   if (ok) {
1122     game.control.num_tech_types = num_techs + A_FIRST; /* includes A_NONE */
1123 
1124     i = 0;
1125     advance_iterate(A_FIRST, a) {
1126       if (!ruleset_load_names(&a->name, NULL, file, section_name(section_list_get(sec, i)))) {
1127         ok = FALSE;
1128         break;
1129       }
1130       i++;
1131     } advance_iterate_end;
1132   }
1133   section_list_destroy(sec);
1134 
1135   return ok;
1136 }
1137 
1138 /**************************************************************************
1139   Load technologies related ruleset data
1140 **************************************************************************/
load_ruleset_techs(struct section_file * file)1141 static bool load_ruleset_techs(struct section_file *file)
1142 {
1143   struct section_list *sec;
1144   int i;
1145   struct advance *a_none = advance_by_number(A_NONE);
1146   const char *filename = secfile_name(file);
1147   bool ok = TRUE;
1148 
1149   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
1150     return FALSE;
1151   }
1152   sec = secfile_sections_by_name_prefix(file, ADVANCE_SECTION_PREFIX);
1153 
1154   i = 0;
1155   advance_iterate(A_FIRST, a) {
1156     const char *sec_name = section_name(section_list_get(sec, i));
1157     const char *sval, **slist;
1158     size_t nval;
1159     int j, ival;
1160 
1161     if (!lookup_tech(file, &a->require[AR_ONE], sec_name, "req1",
1162                      filename, rule_name_get(&a->name))
1163         || !lookup_tech(file, &a->require[AR_TWO], sec_name, "req2",
1164                         filename, rule_name_get(&a->name))
1165         || !lookup_tech(file, &a->require[AR_ROOT], sec_name, "root_req",
1166                         filename, rule_name_get(&a->name))) {
1167       ok = FALSE;
1168       break;
1169     }
1170 
1171     if ((A_NEVER == a->require[AR_ONE] && A_NEVER != a->require[AR_TWO])
1172         || (A_NEVER != a->require[AR_ONE] && A_NEVER == a->require[AR_TWO])) {
1173       ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": \"Never\" with non-\"Never\".",
1174                     filename, sec_name, rule_name_get(&a->name));
1175       ok = FALSE;
1176       break;
1177     }
1178     if (a_none == a->require[AR_ONE] && a_none != a->require[AR_TWO]) {
1179       ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": should have \"None\" second.",
1180                     filename, sec_name, rule_name_get(&a->name));
1181       ok = FALSE;
1182       break;
1183     }
1184 
1185     BV_CLR_ALL(a->flags);
1186 
1187     slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1188     for (j = 0; j < nval; j++) {
1189       sval = slist[j];
1190       if (strcmp(sval, "") == 0) {
1191         continue;
1192       }
1193       ival = tech_flag_id_by_name(sval, fc_strcasecmp);
1194       if (!tech_flag_id_is_valid(ival)) {
1195         ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": bad flag name \"%s\".",
1196                       filename, sec_name, rule_name_get(&a->name), sval);
1197         ok = FALSE;
1198         break;
1199       } else {
1200         BV_SET(a->flags, ival);
1201       }
1202     }
1203     free(slist);
1204 
1205     if (!ok) {
1206       break;
1207     }
1208 
1209     sz_strlcpy(a->graphic_str,
1210                secfile_lookup_str_default(file, "-", "%s.graphic", sec_name));
1211     sz_strlcpy(a->graphic_alt,
1212                secfile_lookup_str_default(file, "-",
1213                                           "%s.graphic_alt", sec_name));
1214 
1215     a->helptext = lookup_strvec(file, sec_name, "helptext");
1216     a->bonus_message = lookup_string(file, sec_name, "bonus_message");
1217     a->cost = secfile_lookup_int_default(file, -1, "%s.%s",
1218                                          sec_name, "cost");
1219     a->num_reqs = 0;
1220 
1221     i++;
1222   } advance_iterate_end;
1223 
1224   /* Propagate a root tech up into the tech tree. If a technology
1225    * X has Y has a root tech, then any technology requiring X (in the
1226    * normal way or as a root tech) also has Y as a root tech.
1227    * Later techs may gain a whole set of root techs in this way. The one
1228    * we store in AR_ROOT is a more or less arbitrary one of these,
1229    * also signalling that the set is non-empty; after this, you'll still
1230    * have to walk the tech tree to find them all. */
1231 restart:
1232 
1233   if (ok) {
1234     advance_iterate(A_FIRST, a) {
1235       if (valid_advance(a)
1236           && A_NEVER != a->require[AR_ROOT]) {
1237         bool out_of_order = FALSE;
1238 
1239         /* Now find any tech depending on this technology and update its
1240          * root_req. */
1241         advance_iterate(A_FIRST, b) {
1242           if (valid_advance(b)
1243               && A_NEVER == b->require[AR_ROOT]
1244               && (a == b->require[AR_ONE] || a == b->require[AR_TWO])) {
1245             b->require[AR_ROOT] = a->require[AR_ROOT];
1246             b->inherited_root_req = TRUE;
1247             if (b < a) {
1248               out_of_order = TRUE;
1249             }
1250           }
1251         } advance_iterate_end;
1252 
1253         if (out_of_order) {
1254           /* HACK: If we just changed the root_tech of a lower-numbered
1255            * technology, we need to go back so that we can propagate the
1256            * root_tech up to that technology's parents... */
1257           goto restart;
1258         }
1259       }
1260     } advance_iterate_end;
1261 
1262     /* Now rename A_NEVER to A_NONE for consistency */
1263     advance_iterate(A_NONE, a) {
1264       if (A_NEVER == a->require[AR_ROOT]) {
1265         a->require[AR_ROOT] = a_none;
1266       }
1267     } advance_iterate_end;
1268 
1269     /* Some more consistency checking:
1270        Non-removed techs depending on removed techs is too
1271        broken to fix by default, so die.
1272     */
1273     advance_iterate(A_FIRST, a) {
1274       if (valid_advance(a)) {
1275         /* We check for recursive tech loops later,
1276          * in build_required_techs_helper. */
1277         if (!valid_advance(a->require[AR_ONE])) {
1278           ruleset_error(LOG_ERROR,
1279                         "\"%s\" tech \"%s\": req1 leads to removed tech.",
1280                         filename,
1281                         advance_rule_name(a));
1282           ok = FALSE;
1283           break;
1284         }
1285         if (!valid_advance(a->require[AR_TWO])) {
1286           ruleset_error(LOG_ERROR,
1287                         "\"%s\" tech \"%s\": req2 leads to removed tech.",
1288                         filename,
1289                         advance_rule_name(a));
1290           ok = FALSE;
1291           break;
1292         }
1293       }
1294     } advance_iterate_end;
1295   }
1296 
1297   section_list_destroy(sec);
1298   if (ok) {
1299     secfile_check_unused(file);
1300   }
1301 
1302   return ok;
1303 }
1304 
1305 /**************************************************************************
1306   Load names of units so other rulesets can refer to units with
1307   their name.
1308 **************************************************************************/
load_unit_names(struct section_file * file)1309 static bool load_unit_names(struct section_file *file)
1310 {
1311   struct section_list *sec = NULL;
1312   int nval = 0;
1313   int i;
1314   const char *filename = secfile_name(file);
1315   const char *flag;
1316   bool ok = TRUE;
1317 
1318   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
1319   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
1320 
1321   /* User unit flag names */
1322   for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
1323        i++) {
1324     const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
1325                                                      i);
1326 
1327     if (unit_type_flag_id_by_name(flag, fc_strcasecmp)
1328         != unit_type_flag_id_invalid()) {
1329       ruleset_error(LOG_ERROR, "\"%s\": Duplicate unit flag name '%s'",
1330                     filename, flag);
1331       ok = FALSE;
1332       break;
1333     }
1334     if (i > MAX_NUM_USER_UNIT_FLAGS) {
1335       ruleset_error(LOG_ERROR, "\"%s\": Too many user unit type flags!",
1336                     filename);
1337       ok = FALSE;
1338       break;
1339     }
1340 
1341     set_user_unit_type_flag_name(UTYF_USER_FLAG_1 + i, flag, helptxt);
1342   }
1343 
1344   if (ok) {
1345     for (; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
1346       set_user_unit_type_flag_name(UTYF_USER_FLAG_1 + i, NULL, NULL);
1347     }
1348 
1349     /* Unit classes */
1350     sec = secfile_sections_by_name_prefix(file, UNIT_CLASS_SECTION_PREFIX);
1351     if (NULL == sec || 0 == (nval = section_list_size(sec))) {
1352       ruleset_error(LOG_ERROR, "\"%s\": No unit classes?!?", filename);
1353       ok = FALSE;
1354     } else {
1355       log_verbose("%d unit classes", nval);
1356       if (nval > UCL_LAST) {
1357         ruleset_error(LOG_ERROR, "\"%s\": Too many unit classes (%d, max %d)",
1358                   filename, nval, UCL_LAST);
1359         ok = FALSE;
1360       }
1361     }
1362   }
1363 
1364   if (ok) {
1365     game.control.num_unit_classes = nval;
1366 
1367     unit_class_iterate(punitclass) {
1368       const int pci = uclass_index(punitclass);
1369 
1370       if (!ruleset_load_names(&punitclass->name, NULL, file,
1371                               section_name(section_list_get(sec, pci)))) {
1372         ok = FALSE;
1373         break;
1374       }
1375     } unit_class_iterate_end;
1376   }
1377   section_list_destroy(sec);
1378   sec = NULL;
1379 
1380   /* The names: */
1381   if (ok) {
1382     sec = secfile_sections_by_name_prefix(file, UNIT_SECTION_PREFIX);
1383     if (NULL == sec || 0 == (nval = section_list_size(sec))) {
1384       ruleset_error(LOG_ERROR, "\"%s\": No unit types?!?", filename);
1385       ok = FALSE;
1386     } else {
1387       log_verbose("%d unit types (including possibly unused)", nval);
1388       if (nval > U_LAST) {
1389         ruleset_error(LOG_ERROR, "\"%s\": Too many unit types (%d, max %d)",
1390                       filename, nval, U_LAST);
1391         ok = FALSE;
1392       }
1393     }
1394   }
1395 
1396   if (ok) {
1397     game.control.num_unit_types = nval;
1398 
1399     unit_type_iterate(punittype) {
1400       const int utypei = utype_index(punittype);
1401       if (!ruleset_load_names(&punittype->name, NULL, file,
1402                               section_name(section_list_get(sec, utypei)))) {
1403         ok = FALSE;
1404         break;
1405       }
1406     } unit_type_iterate_end;
1407   }
1408   section_list_destroy(sec);
1409 
1410   return ok;
1411 }
1412 
1413 /**************************************************************************
1414   Load veteran levels.
1415 **************************************************************************/
load_ruleset_veteran(struct section_file * file,const char * path,struct veteran_system ** vsystem,char * err,size_t err_len)1416 static bool load_ruleset_veteran(struct section_file *file,
1417                                  const char *path,
1418                                  struct veteran_system **vsystem, char *err,
1419                                  size_t err_len)
1420 {
1421   const char **vlist_name;
1422   int *vlist_power, *vlist_raise, *vlist_wraise, *vlist_move;
1423   size_t count_name, count_power, count_raise, count_wraise, count_move;
1424   int i;
1425   bool ret = TRUE;
1426 
1427   /* The pointer should be uninitialised. */
1428   if (*vsystem != NULL) {
1429     fc_snprintf(err, err_len, "Veteran system is defined?!");
1430     return FALSE;
1431   }
1432 
1433   /* Load data. */
1434   vlist_name = secfile_lookup_str_vec(file, &count_name,
1435                                       "%s.veteran_names", path);
1436   vlist_power = secfile_lookup_int_vec(file, &count_power,
1437                                       "%s.veteran_power_fact", path);
1438   vlist_raise = secfile_lookup_int_vec(file, &count_raise,
1439                                        "%s.veteran_raise_chance", path);
1440   vlist_wraise = secfile_lookup_int_vec(file, &count_wraise,
1441                                         "%s.veteran_work_raise_chance",
1442                                         path);
1443   vlist_move = secfile_lookup_int_vec(file, &count_move,
1444                                       "%s.veteran_move_bonus", path);
1445 
1446   if (count_name > MAX_VET_LEVELS) {
1447     ret = FALSE;
1448     fc_snprintf(err, err_len, "\"%s\": Too many veteran levels (section "
1449                               "'%s': %lu, max %d)", secfile_name(file), path,
1450                 (long unsigned)count_name, MAX_VET_LEVELS);
1451   } else if (count_name != count_power
1452              || count_name != count_raise
1453              || count_name != count_wraise
1454              || count_name != count_move) {
1455     ret = FALSE;
1456     fc_snprintf(err, err_len, "\"%s\": Different lengths for the veteran "
1457                               "settings in section '%s'", secfile_name(file),
1458                 path);
1459   } else if (count_name == 0) {
1460     /* Nothing defined. */
1461     *vsystem = NULL;
1462   } else {
1463     /* Generate the veteran system. */
1464     *vsystem = veteran_system_new((int)count_name);
1465 
1466 #define rs_sanity_veteran(_path, _entry, _i, _condition, _action)            \
1467   if (_condition) {                                                          \
1468     log_error("Invalid veteran definition '%s.%s[%d]'!",                     \
1469               _path, _entry, _i);                                            \
1470     log_debug("Failed check: '%s'. Update value: '%s'.",                     \
1471               #_condition, #_action);                                        \
1472     _action;                                                                 \
1473   }
1474     for (i = 0; i < count_name; i++) {
1475       /* Some sanity checks. */
1476       rs_sanity_veteran(path, "veteran_power_fact", i,
1477                         (vlist_power[i] < 0), vlist_power[i] = 0);
1478       rs_sanity_veteran(path, "veteran_raise_chance", i,
1479                         (vlist_raise[i] < 0), vlist_raise[i] = 0);
1480       rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1481                         (vlist_wraise[i] < 0), vlist_wraise[i] = 0);
1482       rs_sanity_veteran(path, "veteran_move_bonus", i,
1483                         (vlist_move[i] < 0), vlist_move[i] = 0);
1484       if (i == 0) {
1485         /* First element.*/
1486         rs_sanity_veteran(path, "veteran_power_fact", i,
1487                           (vlist_power[i] != 100), vlist_power[i] = 100);
1488       } else if (i == count_name - 1) {
1489         /* Last element. */
1490         rs_sanity_veteran(path, "veteran_power_fact", i,
1491                           (vlist_power[i] < vlist_power[i - 1]),
1492                           vlist_power[i] = vlist_power[i - 1]);
1493         rs_sanity_veteran(path, "veteran_raise_chance", i,
1494                           (vlist_raise[i] != 0), vlist_raise[i] = 0);
1495         rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1496                           (vlist_wraise[i] != 0), vlist_wraise[i] = 0);
1497       } else {
1498         /* All elements inbetween. */
1499         rs_sanity_veteran(path, "veteran_power_fact", i,
1500                           (vlist_power[i] < vlist_power[i - 1]),
1501                           vlist_power[i] = vlist_power[i - 1]);
1502         rs_sanity_veteran(path, "veteran_raise_chance", i,
1503                           (vlist_raise[i] > 100), vlist_raise[i] = 100);
1504         rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1505                           (vlist_wraise[i] > 100), vlist_wraise[i] = 100);
1506       }
1507 
1508       veteran_system_definition(*vsystem, i, vlist_name[i], vlist_power[i],
1509                                 vlist_move[i], vlist_raise[i],
1510                                 vlist_wraise[i]);
1511     }
1512 #undef rs_sanity_veteran
1513   }
1514 
1515   if (vlist_name) {
1516     free(vlist_name);
1517   }
1518   if (vlist_power) {
1519     free(vlist_power);
1520   }
1521   if (vlist_raise) {
1522     free(vlist_raise);
1523   }
1524   if (vlist_wraise) {
1525     free(vlist_wraise);
1526   }
1527   if (vlist_move) {
1528     free(vlist_move);
1529   }
1530 
1531   return ret;
1532 }
1533 
1534 /**************************************************************************
1535   Load units related ruleset data.
1536 **************************************************************************/
load_ruleset_units(struct section_file * file)1537 static bool load_ruleset_units(struct section_file *file)
1538 {
1539   int j, ival;
1540   size_t nval;
1541   struct section_list *sec, *csec;
1542   const char *sval, **slist;
1543   const char *filename = secfile_name(file);
1544   char msg[MAX_LEN_MSG];
1545   bool ok = TRUE;
1546 
1547   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
1548     return FALSE;
1549   }
1550 
1551   if (!load_ruleset_veteran(file, "veteran_system", &game.veteran, msg,
1552                             sizeof(msg)) || game.veteran == NULL) {
1553     ruleset_error(LOG_ERROR, "Error loading the default veteran system: %s",
1554                   msg);
1555     ok = FALSE;
1556   }
1557 
1558   sec = secfile_sections_by_name_prefix(file, UNIT_SECTION_PREFIX);
1559   nval = (NULL != sec ? section_list_size(sec) : 0);
1560 
1561   csec = secfile_sections_by_name_prefix(file, UNIT_CLASS_SECTION_PREFIX);
1562   nval = (NULL != csec ? section_list_size(csec) : 0);
1563 
1564   if (ok) {
1565     unit_class_iterate(uc) {
1566       int i = uclass_index(uc);
1567       const char *hut_str;
1568       const char *sec_name = section_name(section_list_get(csec, i));
1569 
1570       if (secfile_lookup_int(file, &uc->min_speed, "%s.min_speed", sec_name)) {
1571         uc->min_speed *= SINGLE_MOVE;
1572       } else {
1573         ruleset_error(LOG_ERROR, "%s", secfile_error());
1574         ok = FALSE;
1575         break;
1576       }
1577       if (!secfile_lookup_int(file, &uc->hp_loss_pct,
1578                               "%s.hp_loss_pct", sec_name)) {
1579         ruleset_error(LOG_ERROR, "%s", secfile_error());
1580         ok = FALSE;
1581         break;
1582       }
1583 
1584       uc->non_native_def_pct = secfile_lookup_int_default(file, 100,
1585                                                           "%s.non_native_def_pct",
1586                                                           sec_name);
1587 
1588       hut_str = secfile_lookup_str_default(file, "Normal", "%s.hut_behavior", sec_name);
1589       if (fc_strcasecmp(hut_str, "Normal") == 0) {
1590         uc->hut_behavior = HUT_NORMAL;
1591       } else if (fc_strcasecmp(hut_str, "Nothing") == 0) {
1592         uc->hut_behavior = HUT_NOTHING;
1593       } else if (fc_strcasecmp(hut_str, "Frighten") == 0) {
1594         uc->hut_behavior = HUT_FRIGHTEN;
1595       } else {
1596         ruleset_error(LOG_ERROR,
1597                       "\"%s\" unit_class \"%s\":"
1598                       " Illegal hut behavior \"%s\".",
1599                       filename,
1600                       uclass_rule_name(uc),
1601                       hut_str);
1602         ok = FALSE;
1603         break;
1604       }
1605 
1606       BV_CLR_ALL(uc->flags);
1607       slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1608       for(j = 0; j < nval; j++) {
1609         sval = slist[j];
1610         if(strcmp(sval,"") == 0) {
1611           continue;
1612         }
1613         ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
1614         if (!unit_class_flag_id_is_valid(ival)) {
1615           ok = FALSE;
1616           ival = unit_type_flag_id_by_name(sval, fc_strcasecmp);
1617           if (unit_type_flag_id_is_valid(ival)) {
1618             ruleset_error(LOG_ERROR,
1619                           "\"%s\" unit_class \"%s\": unit_type flag \"%s\"!",
1620                           filename, uclass_rule_name(uc), sval);
1621           } else {
1622             ruleset_error(LOG_ERROR,
1623                           "\"%s\" unit_class \"%s\": bad flag name \"%s\".",
1624                           filename, uclass_rule_name(uc), sval);
1625           }
1626           break;
1627         } else {
1628           BV_SET(uc->flags, ival);
1629         }
1630       }
1631       free(slist);
1632 
1633       uc->helptext = lookup_strvec(file, sec_name, "helptext");
1634 
1635       if (!ok) {
1636         break;
1637       }
1638     } unit_class_iterate_end;
1639   }
1640 
1641   if (ok) {
1642     /* Tech and Gov requirements; per unit veteran system */
1643     unit_type_iterate(u) {
1644       const int i = utype_index(u);
1645       const struct section *psection = section_list_get(sec, i);
1646       const char *sec_name = section_name(psection);
1647 
1648       if (!lookup_tech(file, &u->require_advance, sec_name,
1649                        "tech_req", filename,
1650                        rule_name_get(&u->name))) {
1651         ok = FALSE;
1652         break;
1653       }
1654       if (u->require_advance == A_NEVER) {
1655         ruleset_error(LOG_ERROR, "%s lacks valid tech_req.",
1656                       rule_name_get(&u->name));
1657         ok = FALSE;
1658         break;
1659       }
1660       if (NULL != section_entry_by_name(psection, "gov_req")) {
1661         char tmp[200] = "\0";
1662         fc_strlcat(tmp, section_name(psection), sizeof(tmp));
1663         fc_strlcat(tmp, ".gov_req", sizeof(tmp));
1664         u->need_government = lookup_government(file, tmp, filename, NULL);
1665         if (u->need_government == NULL) {
1666           ok = FALSE;
1667           break;
1668         }
1669       } else {
1670         u->need_government = NULL; /* no requirement */
1671       }
1672 
1673       if (!load_ruleset_veteran(file, sec_name, &u->veteran,
1674                                 msg, sizeof(msg))) {
1675         ruleset_error(LOG_ERROR, "Error loading the veteran system: %s",
1676                       msg);
1677         ok = FALSE;
1678         break;
1679       }
1680 
1681       if (!lookup_unit_type(file, sec_name, "obsolete_by",
1682                             &u->obsoleted_by, filename,
1683                             rule_name_get(&u->name))
1684           || !lookup_unit_type(file, sec_name, "convert_to",
1685                                &u->converted_to, filename,
1686                                rule_name_get(&u->name))) {
1687         ok = FALSE;
1688         break;
1689       }
1690       u->convert_time = 1; /* default */
1691       lookup_time(file, &u->convert_time, sec_name, "convert_time",
1692                   filename, rule_name_get(&u->name), &ok);
1693     } unit_type_iterate_end;
1694   }
1695 
1696   if (ok) {
1697     /* main stats: */
1698     unit_type_iterate(u) {
1699       const int i = utype_index(u);
1700       struct unit_class *pclass;
1701       const char *sec_name = section_name(section_list_get(sec, i));
1702       const char *string;
1703 
1704       if (!lookup_building(file, sec_name, "impr_req",
1705                            &u->need_improvement, filename,
1706                            rule_name_get(&u->name))) {
1707         ok = FALSE;
1708         break;
1709       }
1710 
1711       sval = secfile_lookup_str(file, "%s.class", sec_name);
1712       pclass = unit_class_by_rule_name(sval);
1713       if (!pclass) {
1714         ruleset_error(LOG_ERROR,
1715                       "\"%s\" unit_type \"%s\":"
1716                       " bad class \"%s\".",
1717                       filename,
1718                       utype_rule_name(u),
1719                       sval);
1720         ok = FALSE;
1721         break;
1722       }
1723       u->uclass = pclass;
1724 
1725       sz_strlcpy(u->sound_move,
1726                  secfile_lookup_str_default(file, "-", "%s.sound_move",
1727                                             sec_name));
1728       sz_strlcpy(u->sound_move_alt,
1729                  secfile_lookup_str_default(file, "-", "%s.sound_move_alt",
1730                                             sec_name));
1731       sz_strlcpy(u->sound_fight,
1732                  secfile_lookup_str_default(file, "-", "%s.sound_fight",
1733                                             sec_name));
1734       sz_strlcpy(u->sound_fight_alt,
1735                  secfile_lookup_str_default(file, "-", "%s.sound_fight_alt",
1736                                             sec_name));
1737 
1738       if ((string = secfile_lookup_str(file, "%s.graphic", sec_name))) {
1739         sz_strlcpy(u->graphic_str, string);
1740       } else {
1741         ruleset_error(LOG_ERROR, "%s", secfile_error());
1742         ok = FALSE;
1743         break;
1744       }
1745       sz_strlcpy(u->graphic_alt,
1746                  secfile_lookup_str_default(file, "-", "%s.graphic_alt",
1747                                             sec_name));
1748 
1749       if (!secfile_lookup_int(file, &u->build_cost,
1750                               "%s.build_cost", sec_name)
1751           || !secfile_lookup_int(file, &u->pop_cost,
1752                                  "%s.pop_cost", sec_name)
1753           || !secfile_lookup_int(file, &u->attack_strength,
1754                                  "%s.attack", sec_name)
1755           || !secfile_lookup_int(file, &u->defense_strength,
1756                                  "%s.defense", sec_name)
1757           || !secfile_lookup_int(file, &u->move_rate,
1758                                  "%s.move_rate", sec_name)
1759           || !secfile_lookup_int(file, &u->vision_radius_sq,
1760                                  "%s.vision_radius_sq", sec_name)
1761           || !secfile_lookup_int(file, &u->transport_capacity,
1762                                  "%s.transport_cap", sec_name)
1763           || !secfile_lookup_int(file, &u->hp,
1764                                  "%s.hitpoints", sec_name)
1765           || !secfile_lookup_int(file, &u->firepower,
1766                                  "%s.firepower", sec_name)
1767           || !secfile_lookup_int(file, &u->fuel,
1768                                  "%s.fuel", sec_name)
1769           || !secfile_lookup_int(file, &u->happy_cost,
1770                                  "%s.uk_happy", sec_name)) {
1771         ruleset_error(LOG_ERROR, "%s", secfile_error());
1772         ok = FALSE;
1773         break;
1774       }
1775       u->move_rate *= SINGLE_MOVE;
1776 
1777       if (u->firepower <= 0) {
1778         ruleset_error(LOG_ERROR,
1779                       "\"%s\" unit_type \"%s\":"
1780                       " firepower is %d,"
1781                       " but must be at least 1. "
1782                       "  If you want no attack ability,"
1783                       " set the unit's attack strength to 0.",
1784                       filename,
1785                       utype_rule_name(u),
1786                       u->firepower);
1787         ok = FALSE;
1788         break;
1789       }
1790 
1791       lookup_cbonus_list(u->bonuses, file, sec_name, "bonuses");
1792 
1793       output_type_iterate(o) {
1794         u->upkeep[o] = secfile_lookup_int_default(file, 0, "%s.uk_%s",
1795                                                   sec_name,
1796                                                   get_output_identifier(o));
1797       } output_type_iterate_end;
1798 
1799       slist = secfile_lookup_str_vec(file, &nval, "%s.cargo", sec_name);
1800       BV_CLR_ALL(u->cargo);
1801       for (j = 0; j < nval; j++) {
1802         struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1803 
1804         if (!uclass) {
1805           ruleset_error(LOG_ERROR,
1806                         "\"%s\" unit_type \"%s\":"
1807                         "has unknown unit class %s as cargo.",
1808                         filename,
1809                         utype_rule_name(u),
1810                         slist[j]);
1811           ok = FALSE;
1812           break;
1813         }
1814 
1815         BV_SET(u->cargo, uclass_index(uclass));
1816       }
1817       free(slist);
1818 
1819       if (!ok) {
1820         break;
1821       }
1822 
1823       slist = secfile_lookup_str_vec(file, &nval, "%s.targets", sec_name);
1824       BV_CLR_ALL(u->targets);
1825       for (j = 0; j < nval; j++) {
1826         struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1827 
1828         if (!uclass) {
1829           ruleset_error(LOG_ERROR,
1830                         "\"%s\" unit_type \"%s\":"
1831                         "has unknown unit class %s as target.",
1832                         filename,
1833                         utype_rule_name(u),
1834                         slist[j]);
1835           ok = FALSE;
1836           break;
1837         }
1838 
1839         BV_SET(u->targets, uclass_index(uclass));
1840       }
1841       free(slist);
1842 
1843       if (!ok) {
1844         break;
1845       }
1846 
1847       slist = secfile_lookup_str_vec(file, &nval, "%s.embarks", sec_name);
1848       BV_CLR_ALL(u->embarks);
1849       for (j = 0; j < nval; j++) {
1850         struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1851 
1852         if (!uclass) {
1853           ruleset_error(LOG_ERROR,
1854                         "\"%s\" unit_type \"%s\":"
1855                         "has unknown unit class %s as embarkable.",
1856                         filename,
1857                         utype_rule_name(u),
1858                         slist[j]);
1859           ok = FALSE;
1860           break;
1861         }
1862 
1863         BV_SET(u->embarks, uclass_index(uclass));
1864       }
1865       free(slist);
1866 
1867       if (!ok) {
1868         break;
1869       }
1870 
1871       slist = secfile_lookup_str_vec(file, &nval, "%s.disembarks", sec_name);
1872       BV_CLR_ALL(u->disembarks);
1873       for (j = 0; j < nval; j++) {
1874         struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1875 
1876         if (!uclass) {
1877           ruleset_error(LOG_ERROR,
1878                         "\"%s\" unit_type \"%s\":"
1879                         "has unknown unit class %s as disembarkable.",
1880                         filename,
1881                         utype_rule_name(u),
1882                         slist[j]);
1883           ok = FALSE;
1884           break;
1885         }
1886 
1887         BV_SET(u->disembarks, uclass_index(uclass));
1888       }
1889       free(slist);
1890 
1891       if (!ok) {
1892         break;
1893       }
1894 
1895       /* Set also all classes that are never unreachable as targets,
1896        * embarks, and disembarks. */
1897       unit_class_iterate(preachable) {
1898         if (!uclass_has_flag(preachable, UCF_UNREACHABLE)) {
1899           BV_SET(u->targets, uclass_index(preachable));
1900           BV_SET(u->embarks, uclass_index(preachable));
1901           BV_SET(u->disembarks, uclass_index(preachable));
1902         }
1903       } unit_class_iterate_end;
1904 
1905       u->helptext = lookup_strvec(file, sec_name, "helptext");
1906 
1907       u->paratroopers_range = secfile_lookup_int_default(file,
1908           0, "%s.paratroopers_range", sec_name);
1909       u->paratroopers_mr_req = SINGLE_MOVE * secfile_lookup_int_default(file,
1910           0, "%s.paratroopers_mr_req", sec_name);
1911       u->paratroopers_mr_sub = SINGLE_MOVE * secfile_lookup_int_default(file,
1912           0, "%s.paratroopers_mr_sub", sec_name);
1913       u->bombard_rate = secfile_lookup_int_default(file,
1914           0, "%s.bombard_rate", sec_name);
1915       u->city_size = secfile_lookup_int_default(file,
1916           1, "%s.city_size", sec_name);
1917     } unit_type_iterate_end;
1918   }
1919 
1920   if (ok) {
1921     /* flags */
1922     unit_type_iterate(u) {
1923       const int i = utype_index(u);
1924 
1925       BV_CLR_ALL(u->flags);
1926       fc_assert(!utype_has_flag(u, UTYF_LAST_USER_FLAG - 1));
1927 
1928       slist = secfile_lookup_str_vec(file, &nval, "%s.flags",
1929                                      section_name(section_list_get(sec, i)));
1930       for(j = 0; j < nval; j++) {
1931         sval = slist[j];
1932         if (0 == strcmp(sval, "")) {
1933           continue;
1934         }
1935         ival = unit_type_flag_id_by_name(sval, fc_strcasecmp);
1936         if (!unit_type_flag_id_is_valid(ival)) {
1937           ok = FALSE;
1938           ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
1939           if (unit_class_flag_id_is_valid(ival)) {
1940             ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": unit_class flag!",
1941                           filename, utype_rule_name(u));
1942           } else {
1943             ruleset_error(LOG_ERROR,
1944                           "\"%s\" unit_type \"%s\": bad flag name \"%s\".",
1945                           filename, utype_rule_name(u),  sval);
1946           }
1947           break;
1948         } else {
1949           BV_SET(u->flags, ival);
1950         }
1951         fc_assert(utype_has_flag(u, ival));
1952       }
1953       free(slist);
1954 
1955       if (!ok) {
1956         break;
1957       }
1958     } unit_type_iterate_end;
1959   }
1960 
1961   /* roles */
1962   if (ok) {
1963     unit_type_iterate(u) {
1964       const int i = utype_index(u);
1965 
1966       BV_CLR_ALL(u->roles);
1967 
1968       slist = secfile_lookup_str_vec(file, &nval, "%s.roles",
1969                                      section_name(section_list_get(sec, i)));
1970       for (j = 0; j < nval; j++) {
1971         sval = slist[j];
1972         if (strcmp(sval, "") == 0) {
1973           continue;
1974         }
1975         ival = unit_role_id_by_name(sval, fc_strcasecmp);
1976         if (!unit_role_id_is_valid(ival)) {
1977           ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": bad role name \"%s\".",
1978                         filename, utype_rule_name(u), sval);
1979           ok = FALSE;
1980           break;
1981         } else {
1982           BV_SET(u->roles, ival - L_FIRST);
1983         }
1984         fc_assert(utype_has_role(u, ival));
1985       }
1986       free(slist);
1987     } unit_type_iterate_end;
1988   }
1989 
1990   if (ok) {
1991     /* Some more consistency checking: */
1992     unit_type_iterate(u) {
1993       if (!valid_advance(u->require_advance)) {
1994         ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": depends on removed tech \"%s\".",
1995                        filename, utype_rule_name(u),
1996                        advance_rule_name(u->require_advance));
1997         u->require_advance = A_NEVER;
1998         ok = FALSE;
1999         break;
2000       }
2001 
2002       if (utype_has_flag(u, UTYF_SETTLERS)
2003           && u->city_size <= 0) {
2004         ruleset_error(LOG_ERROR, "\"%s\": Unit %s would build size %d cities",
2005                       filename, utype_rule_name(u), u->city_size);
2006         u->city_size = 1;
2007         ok = FALSE;
2008         break;
2009       }
2010     } unit_type_iterate_end;
2011   }
2012 
2013   section_list_destroy(csec);
2014   section_list_destroy(sec);
2015 
2016   if (ok) {
2017     secfile_check_unused(file);
2018   }
2019 
2020   return ok;
2021 }
2022 
2023 /**************************************************************************
2024   Load names of buildings so other rulesets can refer to buildings with
2025   their name.
2026 **************************************************************************/
load_building_names(struct section_file * file)2027 static bool load_building_names(struct section_file *file)
2028 {
2029   struct section_list *sec;
2030   int i, nval = 0;
2031   const char *filename = secfile_name(file);
2032   bool ok = TRUE;
2033 
2034   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
2035   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
2036 
2037   /* The names: */
2038   sec = secfile_sections_by_name_prefix(file, BUILDING_SECTION_PREFIX);
2039   if (NULL == sec || 0 == (nval = section_list_size(sec))) {
2040     ruleset_error(LOG_ERROR, "\"%s\": No improvements?!?", filename);
2041     ok = FALSE;
2042   } else {
2043     log_verbose("%d improvement types (including possibly unused)", nval);
2044     if (nval > B_LAST) {
2045       ruleset_error(LOG_ERROR, "\"%s\": Too many improvements (%d, max %d)",
2046                     filename, nval, B_LAST);
2047       ok = FALSE;
2048     }
2049   }
2050 
2051   if (ok) {
2052     game.control.num_impr_types = nval;
2053 
2054     for (i = 0; i < nval; i++) {
2055       struct impr_type *b = improvement_by_number(i);
2056 
2057       if (!ruleset_load_names(&b->name, NULL, file, section_name(section_list_get(sec, i)))) {
2058         ok = FALSE;
2059         break;
2060       }
2061     }
2062   }
2063 
2064   section_list_destroy(sec);
2065 
2066   return ok;
2067 }
2068 
2069 /**************************************************************************
2070   Load buildings related ruleset data
2071 **************************************************************************/
load_ruleset_buildings(struct section_file * file)2072 static bool load_ruleset_buildings(struct section_file *file)
2073 {
2074   struct section_list *sec;
2075   const char *item;
2076   int i, nval;
2077   const char *filename = secfile_name(file);
2078   bool ok = TRUE;
2079 
2080   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
2081     return FALSE;
2082   }
2083 
2084   sec = secfile_sections_by_name_prefix(file, BUILDING_SECTION_PREFIX);
2085   nval = (NULL != sec ? section_list_size(sec) : 0);
2086 
2087   for (i = 0; i < nval && ok; i++) {
2088     struct impr_type *b = improvement_by_number(i);
2089     const char *sec_name = section_name(section_list_get(sec, i));
2090     struct requirement_vector *reqs =
2091       lookup_req_list(file, sec_name, "reqs",
2092                       improvement_rule_name(b));
2093 
2094     if (reqs == NULL) {
2095       ok = FALSE;
2096       break;
2097     } else {
2098       const char *sval, **slist;
2099       int j, ival;
2100       size_t nflags;
2101 
2102       item = secfile_lookup_str(file, "%s.genus", sec_name);
2103       b->genus = impr_genus_id_by_name(item, fc_strcasecmp);
2104       if (!impr_genus_id_is_valid(b->genus)) {
2105         ruleset_error(LOG_ERROR, "\"%s\" improvement \"%s\": couldn't match "
2106                       "genus \"%s\".", filename,
2107                       improvement_rule_name(b), item);
2108         ok = FALSE;
2109         break;
2110       }
2111 
2112       slist = secfile_lookup_str_vec(file, &nflags, "%s.flags", sec_name);
2113       BV_CLR_ALL(b->flags);
2114 
2115       for (j = 0; j < nflags; j++) {
2116         sval = slist[j];
2117         if (strcmp(sval,"") == 0) {
2118           continue;
2119         }
2120         ival = impr_flag_id_by_name(sval, fc_strcasecmp);
2121         if (!impr_flag_id_is_valid(ival)) {
2122           ruleset_error(LOG_ERROR,
2123                         "\"%s\" improvement \"%s\": bad flag name \"%s\".",
2124                         filename, improvement_rule_name(b), sval);
2125           ok = FALSE;
2126           break;
2127         } else {
2128           BV_SET(b->flags, ival);
2129         }
2130       }
2131       free(slist);
2132 
2133       if (!ok) {
2134         break;
2135       }
2136 
2137       requirement_vector_copy(&b->reqs, reqs);
2138 
2139       {
2140         struct requirement_vector *obs_reqs =
2141           lookup_req_list(file, sec_name, "obsolete_by",
2142                           improvement_rule_name(b));
2143 
2144         if (obs_reqs == NULL) {
2145           ok = FALSE;
2146           break;
2147         } else {
2148           requirement_vector_copy(&b->obsolete_by, obs_reqs);
2149         }
2150       }
2151 
2152       if (!secfile_lookup_int(file, &b->build_cost,
2153                               "%s.build_cost", sec_name)
2154           || !secfile_lookup_int(file, &b->upkeep,
2155                                  "%s.upkeep", sec_name)
2156           || !secfile_lookup_int(file, &b->sabotage,
2157                                  "%s.sabotage", sec_name)) {
2158         ruleset_error(LOG_ERROR, "%s", secfile_error());
2159         ok = FALSE;
2160         break;
2161       }
2162 
2163       sz_strlcpy(b->graphic_str,
2164                  secfile_lookup_str_default(file, "-",
2165                                             "%s.graphic", sec_name));
2166       sz_strlcpy(b->graphic_alt,
2167                  secfile_lookup_str_default(file, "-",
2168                                             "%s.graphic_alt", sec_name));
2169 
2170       sz_strlcpy(b->soundtag,
2171                  secfile_lookup_str_default(file, "-",
2172                                             "%s.sound", sec_name));
2173       sz_strlcpy(b->soundtag_alt,
2174                  secfile_lookup_str_default(file, "-",
2175                                             "%s.sound_alt", sec_name));
2176       b->helptext = lookup_strvec(file, sec_name, "helptext");
2177     }
2178   }
2179 
2180   section_list_destroy(sec);
2181   if (ok) {
2182     secfile_check_unused(file);
2183   }
2184 
2185   return ok;
2186 }
2187 
2188 /**************************************************************************
2189   Load names of terrain types so other rulesets can refer to terrains with
2190   their name.
2191 **************************************************************************/
load_terrain_names(struct section_file * file)2192 static bool load_terrain_names(struct section_file *file)
2193 {
2194   int nval = 0;
2195   struct section_list *sec = NULL;
2196   const char *flag;
2197   int i;
2198   const char *filename = secfile_name(file);
2199   bool ok = TRUE;
2200 
2201   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
2202   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
2203 
2204   /* User terrain flag names */
2205   for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
2206        i++) {
2207     const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
2208                                                      i);
2209 
2210     if (terrain_flag_id_by_name(flag, fc_strcasecmp)
2211         != terrain_flag_id_invalid()) {
2212       ruleset_error(LOG_ERROR, "\"%s\": Duplicate terrain flag name '%s'",
2213                     filename, flag);
2214       ok = FALSE;
2215       break;
2216     }
2217     if (i > MAX_NUM_USER_TER_FLAGS) {
2218       ruleset_error(LOG_ERROR, "\"%s\": Too many user terrain flags!",
2219                     filename);
2220       ok = FALSE;
2221       break;
2222     }
2223 
2224     set_user_terrain_flag_name(TER_USER_1 + i, flag, helptxt);
2225   }
2226 
2227   if (ok) {
2228     for (; i < MAX_NUM_USER_TER_FLAGS; i++) {
2229       set_user_terrain_flag_name(TER_USER_1 + i, NULL, NULL);
2230     }
2231 
2232     /* terrain names */
2233 
2234     sec = secfile_sections_by_name_prefix(file, TERRAIN_SECTION_PREFIX);
2235     if (NULL == sec || 0 == (nval = section_list_size(sec))) {
2236       ruleset_error(LOG_ERROR, "\"%s\": ruleset doesn't have any terrains.",
2237                     filename);
2238       ok = FALSE;
2239     } else {
2240       if (nval > MAX_NUM_TERRAINS) {
2241         ruleset_error(LOG_ERROR, "\"%s\": Too many terrains (%d, max %d)",
2242                       filename, nval, MAX_NUM_TERRAINS);
2243         ok = FALSE;
2244       }
2245     }
2246   }
2247 
2248   if (ok) {
2249     game.control.terrain_count = nval;
2250 
2251     /* avoid re-reading files */
2252     if (terrain_sections) {
2253       free(terrain_sections);
2254     }
2255     terrain_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2256 
2257     terrain_type_iterate(pterrain) {
2258       const int terri = terrain_index(pterrain);
2259       const char *sec_name = section_name(section_list_get(sec, terri));
2260 
2261       if (!ruleset_load_names(&pterrain->name, NULL, file, sec_name)) {
2262         ok = FALSE;
2263         break;
2264       }
2265 
2266       section_strlcpy(&terrain_sections[terri * MAX_SECTION_LABEL], sec_name);
2267     } terrain_type_iterate_end;
2268   }
2269 
2270   section_list_destroy(sec);
2271   sec = NULL;
2272 
2273   /* resource names */
2274   if (ok) {
2275     sec = secfile_sections_by_name_prefix(file, RESOURCE_SECTION_PREFIX);
2276     nval = (NULL != sec ? section_list_size(sec) : 0);
2277     if (nval > MAX_NUM_RESOURCES) {
2278       ruleset_error(LOG_ERROR, "\"%s\": Too many resources (%d, max %d)",
2279                     filename, nval, MAX_NUM_RESOURCES);
2280       ok = FALSE;
2281     }
2282   }
2283 
2284   if (ok) {
2285     game.control.resource_count = nval;
2286 
2287     /* avoid re-reading files */
2288     if (resource_sections) {
2289       free(resource_sections);
2290     }
2291     resource_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2292 
2293     resource_type_iterate(presource) {
2294       const int resi = resource_index(presource);
2295       const char *sec_name = section_name(section_list_get(sec, resi));
2296 
2297       if (!ruleset_load_names(&presource->name, NULL, file, sec_name)) {
2298         ok = FALSE;
2299         break;
2300       }
2301 
2302       section_strlcpy(&resource_sections[resi * MAX_SECTION_LABEL], sec_name);
2303     } resource_type_iterate_end;
2304   }
2305 
2306   section_list_destroy(sec);
2307   sec = NULL;
2308 
2309   /* extra names */
2310 
2311   if (ok) {
2312     sec = secfile_sections_by_name_prefix(file, EXTRA_SECTION_PREFIX);
2313     nval = (NULL != sec ? section_list_size(sec) : 0);
2314     if (nval > MAX_EXTRA_TYPES) {
2315       ruleset_error(LOG_ERROR, "\"%s\": Too many extra types (%d, max %d)",
2316                     filename, nval, MAX_EXTRA_TYPES);
2317       ok = FALSE;
2318     }
2319   }
2320 
2321   if (ok) {
2322     int idx;
2323 
2324     game.control.num_extra_types = nval;
2325 
2326     if (extra_sections) {
2327       free(extra_sections);
2328     }
2329     extra_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2330 
2331     if (ok) {
2332       for (idx = 0; idx < nval; idx++) {
2333         const char *sec_name = section_name(section_list_get(sec, idx));
2334         struct extra_type *pextra = extra_by_number(idx);
2335 
2336         if (!ruleset_load_names(&pextra->name, NULL, file, sec_name)) {
2337           ok = FALSE;
2338           break;
2339         }
2340         section_strlcpy(&extra_sections[idx * MAX_SECTION_LABEL], sec_name);
2341       }
2342     }
2343   }
2344 
2345   section_list_destroy(sec);
2346   sec = NULL;
2347 
2348   /* base names */
2349 
2350   if (ok) {
2351     sec = secfile_sections_by_name_prefix(file, BASE_SECTION_PREFIX);
2352     nval = (NULL != sec ? section_list_size(sec) : 0);
2353     if (nval > MAX_BASE_TYPES) {
2354       ruleset_error(LOG_ERROR, "\"%s\": Too many base types (%d, max %d)",
2355                     filename, nval, MAX_BASE_TYPES);
2356       ok = FALSE;
2357     }
2358 
2359     game.control.num_base_types = nval;
2360   }
2361 
2362   if (ok) {
2363     int idx;
2364 
2365     if (base_sections) {
2366       free(base_sections);
2367     }
2368     base_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2369 
2370     /* Cannot use base_type_iterate() before bases are added to
2371      * EC_BASE caused_by list. Have to get them by extra_type_by_rule_name() */
2372     for (idx = 0; idx < nval; idx++) {
2373       const char *sec_name = section_name(section_list_get(sec, idx));
2374       const char *base_name = secfile_lookup_str(file, "%s.extra", sec_name);
2375 
2376       if (base_name != NULL) {
2377         struct extra_type *pextra = extra_type_by_rule_name(base_name);
2378 
2379         if (pextra != NULL) {
2380           base_type_init(pextra, idx);
2381           section_strlcpy(&base_sections[idx * MAX_SECTION_LABEL], sec_name);
2382         } else {
2383           ruleset_error(LOG_ERROR,
2384                         "No extra definition matching base definition \"%s\"",
2385                         base_name);
2386           ok = FALSE;
2387         }
2388       } else {
2389         ruleset_error(LOG_ERROR,
2390                       "Base section \"%s\" does not associate base with any extra",
2391                       sec_name);
2392         ok = FALSE;
2393       }
2394     }
2395   }
2396 
2397   section_list_destroy(sec);
2398   sec = NULL;
2399 
2400   /* road names */
2401 
2402   if (ok) {
2403     sec = secfile_sections_by_name_prefix(file, ROAD_SECTION_PREFIX);
2404     nval = (NULL != sec ? section_list_size(sec) : 0);
2405     if (nval > MAX_ROAD_TYPES) {
2406       ruleset_error(LOG_ERROR, "\"%s\": Too many road types (%d, max %d)",
2407                     filename, nval, MAX_ROAD_TYPES);
2408       ok = FALSE;
2409     }
2410 
2411     game.control.num_road_types = nval;
2412   }
2413 
2414   if (ok) {
2415     int idx;
2416 
2417     if (road_sections) {
2418       free(road_sections);
2419     }
2420     road_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2421 
2422     /* Cannot use extra_type_by_cause_iterate(EC_ROAD) before roads are added to
2423      * EC_ROAD caused_by list. Have to get them by extra_type_by_rule_name() */
2424     for (idx = 0; idx < nval; idx++) {
2425       const char *sec_name = section_name(section_list_get(sec, idx));
2426       const char *road_name = secfile_lookup_str(file, "%s.extra", sec_name);
2427 
2428       if (road_name != NULL) {
2429         struct extra_type *pextra = extra_type_by_rule_name(road_name);
2430 
2431         if (pextra != NULL) {
2432           road_type_init(pextra, idx);
2433           section_strlcpy(&road_sections[idx * MAX_SECTION_LABEL], sec_name);
2434         } else {
2435           ruleset_error(LOG_ERROR,
2436                         "No extra definition matching road definition \"%s\"",
2437                         road_name);
2438           ok = FALSE;
2439         }
2440       } else {
2441         ruleset_error(LOG_ERROR,
2442                       "Road section \"%s\" does not associate road with any extra",
2443                       sec_name);
2444         ok = FALSE;
2445       }
2446     }
2447   }
2448 
2449   section_list_destroy(sec);
2450 
2451   return ok;
2452 }
2453 
2454 /**************************************************************************
2455   Load terrain types related ruleset data
2456 **************************************************************************/
load_ruleset_terrain(struct section_file * file)2457 static bool load_ruleset_terrain(struct section_file *file)
2458 {
2459   size_t nval;
2460   int j;
2461   bool compat_road = FALSE;
2462   bool compat_rail = FALSE;
2463   bool compat_river = FALSE;
2464   const char **res;
2465   const char *filename = secfile_name(file);
2466   const char *text;
2467   bool ok = TRUE;
2468 
2469   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
2470     return FALSE;
2471   }
2472 
2473   /* parameters */
2474 
2475   terrain_control.ocean_reclaim_requirement_pct
2476     = secfile_lookup_int_default(file, 101,
2477 				 "parameters.ocean_reclaim_requirement");
2478   terrain_control.land_channel_requirement_pct
2479     = secfile_lookup_int_default(file, 101,
2480 				 "parameters.land_channel_requirement");
2481   terrain_control.terrain_thaw_requirement_pct
2482     = secfile_lookup_int_default(file, 101,
2483 				 "parameters.thaw_requirement");
2484   terrain_control.terrain_freeze_requirement_pct
2485     = secfile_lookup_int_default(file, 101,
2486 				 "parameters.freeze_requirement");
2487   terrain_control.lake_max_size
2488     = secfile_lookup_int_default(file, 0,
2489 				 "parameters.lake_max_size");
2490   terrain_control.min_start_native_area
2491     = secfile_lookup_int_default(file, 0,
2492                                  "parameters.min_start_native_area");
2493   terrain_control.move_fragments
2494     = secfile_lookup_int_default(file, 3,
2495                                  "parameters.move_fragments");
2496   if (terrain_control.move_fragments < 1) {
2497     ruleset_error(LOG_ERROR, "\"%s\": move_fragments must be at least 1",
2498                   filename);
2499     ok = FALSE;
2500   }
2501   init_move_fragments();
2502   terrain_control.igter_cost
2503     = secfile_lookup_int_default(file, 1,
2504                                  "parameters.igter_cost");
2505   if (terrain_control.igter_cost < 1) {
2506     ruleset_error(LOG_ERROR, "\"%s\": igter_cost must be at least 1",
2507                   filename);
2508     ok = FALSE;
2509   }
2510   terrain_control.pythagorean_diagonal
2511     = secfile_lookup_bool_default(file, RS_DEFAULT_PYTHAGOREAN_DIAGONAL,
2512                                   "parameters.pythagorean_diagonal");
2513 
2514   game.map.server.ocean_resources
2515     = secfile_lookup_bool_default(file, FALSE,
2516                                   "parameters.ocean_resources");
2517 
2518   text = secfile_lookup_str_default(file,
2519                                     N_("?gui_type:Build Type A Base"),
2520                                     "extraui.ui_name_base_fortress");
2521   sz_strlcpy(terrain_control.gui_type_base0, text);
2522 
2523   text = secfile_lookup_str_default(file,
2524                                     N_("?gui_type:Build Type B Base"),
2525                                     "extraui.ui_name_base_airbase");
2526   sz_strlcpy(terrain_control.gui_type_base1, text);
2527 
2528   if (ok) {
2529     /* terrain details */
2530 
2531     terrain_type_iterate(pterrain) {
2532       const char **slist;
2533       const int i = terrain_index(pterrain);
2534       const char *tsection = &terrain_sections[i * MAX_SECTION_LABEL];
2535       const char *cstr;
2536 
2537       sz_strlcpy(pterrain->graphic_str,
2538                  secfile_lookup_str(file,"%s.graphic", tsection));
2539       sz_strlcpy(pterrain->graphic_alt,
2540                  secfile_lookup_str(file,"%s.graphic_alt", tsection));
2541 
2542       pterrain->identifier
2543         = secfile_lookup_str(file, "%s.identifier", tsection)[0];
2544       if ('\0' == pterrain->identifier) {
2545         ruleset_error(LOG_ERROR, "\"%s\" [%s] identifier missing value.",
2546                       filename, tsection);
2547         ok = FALSE;
2548         break;
2549       }
2550       if (TERRAIN_UNKNOWN_IDENTIFIER == pterrain->identifier) {
2551         ruleset_error(LOG_ERROR,
2552                       "\"%s\" [%s] cannot use '%c' as an identifier;"
2553                       " it is reserved for unknown terrain.",
2554                       filename, tsection, pterrain->identifier);
2555         ok = FALSE;
2556         break;
2557       }
2558       for (j = T_FIRST; j < i; j++) {
2559         if (pterrain->identifier == terrain_by_number(j)->identifier) {
2560           ruleset_error(LOG_ERROR,
2561                         "\"%s\" [%s] has the same identifier as [%s].",
2562                         filename,
2563                         tsection,
2564                         &terrain_sections[j * MAX_SECTION_LABEL]);
2565           ok = FALSE;
2566           break;
2567         }
2568       }
2569 
2570       if (!ok) {
2571         break;
2572       }
2573 
2574       cstr = secfile_lookup_str(file, "%s.class", tsection);
2575       pterrain->tclass = terrain_class_by_name(cstr, fc_strcasecmp);
2576       if (!terrain_class_is_valid(pterrain->tclass)) {
2577         ruleset_error(LOG_ERROR, "\"%s\": [%s] unknown class \"%s\"",
2578                       filename, tsection, cstr);
2579         ok = FALSE;
2580         break;
2581       }
2582 
2583       if (!secfile_lookup_int(file, &pterrain->movement_cost,
2584                               "%s.movement_cost", tsection)
2585           || !secfile_lookup_int(file, &pterrain->defense_bonus,
2586                                  "%s.defense_bonus", tsection)) {
2587         ruleset_error(LOG_ERROR, "%s", secfile_error());
2588         ok = FALSE;
2589         break;
2590       }
2591 
2592       output_type_iterate(o) {
2593         pterrain->output[o]
2594           = secfile_lookup_int_default(file, 0, "%s.%s", tsection,
2595                                        get_output_identifier(o));
2596       } output_type_iterate_end;
2597 
2598       res = secfile_lookup_str_vec(file, &nval, "%s.resources", tsection);
2599       pterrain->resources = fc_calloc(nval + 1, sizeof(*pterrain->resources));
2600       for (j = 0; j < nval; j++) {
2601         pterrain->resources[j] = lookup_resource(filename, res[j], tsection);
2602         if (pterrain->resources[j] == NULL) {
2603           ok = FALSE;
2604           break;
2605         }
2606       }
2607       pterrain->resources[nval] = NULL;
2608       free(res);
2609       res = NULL;
2610 
2611       if (!ok) {
2612         break;
2613       }
2614 
2615       output_type_iterate(o) {
2616         pterrain->road_output_incr_pct[o]
2617           = secfile_lookup_int_default(file, 0, "%s.road_%s_incr_pct",
2618                                        tsection, get_output_identifier(o));
2619       } output_type_iterate_end;
2620 
2621       if (!lookup_time(file, &pterrain->base_time, tsection, "base_time",
2622                        filename, NULL, &ok)
2623           || !lookup_time(file, &pterrain->road_time, tsection, "road_time",
2624                           filename, NULL, &ok)) {
2625         ruleset_error(LOG_ERROR, "%s", secfile_error());
2626         ok = FALSE;
2627         break;
2628       }
2629 
2630       if (!lookup_terrain(file, "irrigation_result", filename, pterrain,
2631                           &pterrain->irrigation_result)) {
2632         ok = FALSE;
2633         break;
2634       }
2635       if (!secfile_lookup_int(file, &pterrain->irrigation_food_incr,
2636                               "%s.irrigation_food_incr", tsection)
2637           || !lookup_time(file, &pterrain->irrigation_time,
2638                           tsection, "irrigation_time", filename, NULL, &ok)) {
2639         ruleset_error(LOG_ERROR, "%s", secfile_error());
2640         ok = FALSE;
2641         break;
2642       }
2643 
2644       if (!lookup_terrain(file, "mining_result", filename, pterrain,
2645                           &pterrain->mining_result)) {
2646         ok = FALSE;
2647         break;
2648       }
2649       if (!secfile_lookup_int(file, &pterrain->mining_shield_incr,
2650                               "%s.mining_shield_incr", tsection)
2651           || !lookup_time(file, &pterrain->mining_time,
2652                           tsection, "mining_time", filename, NULL, &ok)) {
2653         ruleset_error(LOG_ERROR, "%s", secfile_error());
2654         ok = FALSE;
2655         break;
2656       }
2657 
2658       if (!lookup_unit_type(file, tsection, "animal",
2659                             &pterrain->animal, filename,
2660                             rule_name_get(&pterrain->name))) {
2661         ok = FALSE;
2662         break;
2663       }
2664 
2665       if (!lookup_terrain(file, "transform_result", filename, pterrain,
2666                           &pterrain->transform_result)) {
2667         ok = FALSE;
2668         break;
2669       }
2670       if (!lookup_time(file, &pterrain->transform_time,
2671                        tsection, "transform_time", filename, NULL, &ok)) {
2672         ruleset_error(LOG_ERROR, "%s", secfile_error());
2673         ok = FALSE;
2674         break;
2675       }
2676       if (pterrain->transform_time <= 0) {
2677         /* Transform time of zero is documented to disable the transform
2678          * regardless of given transform result. That's fine, but in the
2679          * future we may consider it an error to give combination of
2680          * transform_result and transform_time where one indicates it's
2681          * enabled and the other that it's not. */
2682         pterrain->transform_result = NULL;
2683       }
2684       pterrain->pillage_time = 1; /* default */
2685       lookup_time(file, &pterrain->pillage_time,
2686                   tsection, "pillage_time", filename, NULL, &ok);
2687       pterrain->clean_pollution_time = 3; /* default */
2688       lookup_time(file, &pterrain->clean_pollution_time,
2689                   tsection, "clean_pollution_time", filename, NULL, &ok);
2690       pterrain->clean_fallout_time = 3; /* default */
2691       lookup_time(file, &pterrain->clean_fallout_time,
2692                   tsection, "clean_fallout_time", filename, NULL, &ok);
2693 
2694       if (!lookup_terrain(file, "warmer_wetter_result", filename, pterrain,
2695                          &pterrain->warmer_wetter_result)
2696           || !lookup_terrain(file, "warmer_drier_result", filename, pterrain,
2697                              &pterrain->warmer_drier_result)
2698           || !lookup_terrain(file, "cooler_wetter_result", filename, pterrain,
2699                              &pterrain->cooler_wetter_result)
2700           || !lookup_terrain(file, "cooler_drier_result", filename, pterrain,
2701                              &pterrain->cooler_drier_result)) {
2702         ok = FALSE;
2703         break;
2704       }
2705 
2706       slist = secfile_lookup_str_vec(file, &nval, "%s.flags", tsection);
2707       BV_CLR_ALL(pterrain->flags);
2708       for (j = 0; j < nval; j++) {
2709         const char *sval = slist[j];
2710         enum terrain_flag_id flag
2711           = terrain_flag_id_by_name(sval, fc_strcasecmp);
2712 
2713         if (!terrain_flag_id_is_valid(flag)) {
2714           ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown flag \"%s\".",
2715                         filename, tsection, sval);
2716           ok = FALSE;
2717           break;
2718         } else {
2719           BV_SET(pterrain->flags, flag);
2720         }
2721       }
2722       free(slist);
2723 
2724       if (!ok) {
2725         break;
2726       }
2727 
2728       {
2729         enum mapgen_terrain_property mtp;
2730         for (mtp = mapgen_terrain_property_begin();
2731              mtp != mapgen_terrain_property_end();
2732              mtp = mapgen_terrain_property_next(mtp)) {
2733           pterrain->property[mtp]
2734             = secfile_lookup_int_default(file, 0, "%s.property_%s", tsection,
2735                                          mapgen_terrain_property_name(mtp));
2736         }
2737       }
2738 
2739       slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", tsection);
2740       BV_CLR_ALL(pterrain->native_to);
2741       for (j = 0; j < nval; j++) {
2742         struct unit_class *class = unit_class_by_rule_name(slist[j]);
2743 
2744         if (!class) {
2745           ruleset_error(LOG_ERROR,
2746                         "\"%s\" [%s] is native to unknown unit class \"%s\".",
2747                         filename, tsection, slist[j]);
2748           ok = FALSE;
2749           break;
2750         } else {
2751           BV_SET(pterrain->native_to, uclass_index(class));
2752         }
2753       }
2754       free(slist);
2755 
2756       if (!ok) {
2757         break;
2758       }
2759 
2760       /* get terrain color */
2761       {
2762         fc_assert_ret_val(pterrain->rgb == NULL, FALSE);
2763         if (!rgbcolor_load(file, &pterrain->rgb, "%s.color", tsection)) {
2764           ruleset_error(LOG_ERROR, "Missing terrain color definition: %s",
2765                         secfile_error());
2766           ok = FALSE;
2767           break;
2768         }
2769       }
2770 
2771       pterrain->helptext = lookup_strvec(file, tsection, "helptext");
2772     } terrain_type_iterate_end;
2773   }
2774 
2775   if (ok) {
2776     /* resource details */
2777 
2778     resource_type_iterate(presource) {
2779       char identifier[MAX_LEN_NAME];
2780       const int i = resource_index(presource);
2781       const char *rsection = &resource_sections[i * MAX_SECTION_LABEL];
2782 
2783       output_type_iterate (o) {
2784         presource->output[o] =
2785 	  secfile_lookup_int_default(file, 0, "%s.%s", rsection,
2786                                      get_output_identifier(o));
2787       } output_type_iterate_end;
2788       sz_strlcpy(presource->graphic_str,
2789                  secfile_lookup_str(file,"%s.graphic", rsection));
2790       sz_strlcpy(presource->graphic_alt,
2791                  secfile_lookup_str(file,"%s.graphic_alt", rsection));
2792 
2793       sz_strlcpy(identifier,
2794                  secfile_lookup_str(file,"%s.identifier", rsection));
2795       presource->identifier = identifier[0];
2796       if (RESOURCE_NULL_IDENTIFIER == presource->identifier) {
2797         ruleset_error(LOG_ERROR, "\"%s\" [%s] identifier missing value.",
2798                       filename, rsection);
2799         ok = FALSE;
2800         break;
2801       }
2802       if (RESOURCE_NONE_IDENTIFIER == presource->identifier) {
2803         ruleset_error(LOG_ERROR,
2804                       "\"%s\" [%s] cannot use '%c' as an identifier;"
2805                       " it is reserved.",
2806                       filename, rsection, presource->identifier);
2807         ok = FALSE;
2808         break;
2809       }
2810       for (j = 0; j < i; j++) {
2811         if (presource->identifier == resource_by_number(j)->identifier) {
2812           ruleset_error(LOG_ERROR,
2813                         "\"%s\" [%s] has the same identifier as [%s].",
2814                         filename,
2815                         rsection,
2816                         &resource_sections[j * MAX_SECTION_LABEL]);
2817           ok = FALSE;
2818           break;
2819         }
2820       }
2821 
2822       if (!ok) {
2823         break;
2824       }
2825 
2826     } resource_type_iterate_end;
2827   }
2828 
2829   if (ok) {
2830     /* extra details */
2831     extra_type_iterate(pextra) {
2832       BV_CLR_ALL(pextra->conflicts);
2833     } extra_type_iterate_end;
2834 
2835     extra_type_iterate(pextra) {
2836       const char *section = &extra_sections[extra_index(pextra) * MAX_SECTION_LABEL];
2837       const char **slist;
2838       struct requirement_vector *reqs;
2839       const char *catname;
2840       int cj;
2841       enum extra_cause cause;
2842       enum extra_rmcause rmcause;
2843 
2844       catname = secfile_lookup_str(file, "%s.category", section);
2845       if (catname == NULL) {
2846         ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\" has no category.",
2847                       filename,
2848                       extra_rule_name(pextra));
2849         ok = FALSE;
2850         break;
2851       }
2852       pextra->category = extra_category_by_name(catname, fc_strcasecmp);
2853       if (!extra_category_is_valid(pextra->category)) {
2854         ruleset_error(LOG_ERROR,
2855                       "\"%s\" extra \"%s\" has invalid category \"%s\".",
2856                       filename, extra_rule_name(pextra), catname);
2857         ok = FALSE;
2858         break;
2859       }
2860 
2861       slist = secfile_lookup_str_vec(file, &nval, "%s.causes", section);
2862       pextra->causes = 0;
2863       for (cj = 0; cj < nval; cj++) {
2864         const char *sval = slist[cj];
2865         cause = extra_cause_by_name(sval, fc_strcasecmp);
2866 
2867         if (!extra_cause_is_valid(cause)) {
2868           ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown cause \"%s\".",
2869                         filename,
2870                         extra_rule_name(pextra),
2871                         sval);
2872           ok = FALSE;
2873           break;
2874         } else {
2875           pextra->causes |= (1 << cause);
2876           extra_to_caused_by_list(pextra, cause);
2877         }
2878       }
2879 
2880       if (pextra->causes == 0) {
2881         /* Extras that do not have any causes added to EC_NONE list */
2882         extra_to_caused_by_list(pextra, EC_NONE);
2883       }
2884 
2885       if (!is_extra_caused_by(pextra, EC_BASE)
2886           && !is_extra_caused_by(pextra, EC_ROAD)) {
2887         /* Not a base nor road, so special */
2888         pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
2889         extra_to_caused_by_list(pextra, EC_SPECIAL);
2890       }
2891 
2892       free(slist);
2893 
2894       slist = secfile_lookup_str_vec(file, &nval, "%s.rmcauses", section);
2895       pextra->rmcauses = 0;
2896       for (j = 0; j < nval; j++) {
2897         const char *sval = slist[j];
2898         rmcause = extra_rmcause_by_name(sval, fc_strcasecmp);
2899 
2900         if (!extra_rmcause_is_valid(rmcause)) {
2901           ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown rmcause \"%s\".",
2902                         filename,
2903                         extra_rule_name(pextra),
2904                         sval);
2905           ok = FALSE;
2906           break;
2907         } else {
2908           pextra->rmcauses |= (1 << rmcause);
2909           extra_to_removed_by_list(pextra, rmcause);
2910         }
2911       }
2912 
2913       free(slist);
2914 
2915       sz_strlcpy(pextra->activity_gfx,
2916                  secfile_lookup_str_default(file, "-",
2917                                             "%s.activity_gfx", section));
2918       sz_strlcpy(pextra->act_gfx_alt,
2919                  secfile_lookup_str_default(file, "-",
2920                                             "%s.act_gfx_alt", section));
2921       sz_strlcpy(pextra->act_gfx_alt2,
2922                  secfile_lookup_str_default(file, "-",
2923                                             "%s.act_gfx_alt2", section));
2924       sz_strlcpy(pextra->rmact_gfx,
2925                  secfile_lookup_str_default(file, "-",
2926                                             "%s.rmact_gfx", section));
2927       sz_strlcpy(pextra->rmact_gfx_alt,
2928                  secfile_lookup_str_default(file, "-",
2929                                             "%s.rmact_gfx_alt", section));
2930       sz_strlcpy(pextra->graphic_str,
2931                  secfile_lookup_str_default(file, "-", "%s.graphic", section));
2932       sz_strlcpy(pextra->graphic_alt,
2933                  secfile_lookup_str_default(file, "-",
2934                                             "%s.graphic_alt", section));
2935 
2936       reqs = lookup_req_list(file, section, "reqs", extra_rule_name(pextra));
2937       if (reqs == NULL) {
2938         ok = FALSE;
2939         break;
2940       }
2941       requirement_vector_copy(&pextra->reqs, reqs);
2942 
2943       reqs = lookup_req_list(file, section, "rmreqs", extra_rule_name(pextra));
2944       if (reqs == NULL) {
2945         ok = FALSE;
2946         break;
2947       }
2948       requirement_vector_copy(&pextra->rmreqs, reqs);
2949 
2950       pextra->buildable = secfile_lookup_bool_default(file, TRUE,
2951                                                       "%s.buildable", section);
2952 
2953       pextra->build_time = 0; /* default */
2954       lookup_time(file, &pextra->build_time, section, "build_time",
2955                   filename, extra_rule_name(pextra), &ok);
2956       pextra->build_time_factor = secfile_lookup_int_default(file, 1,
2957                                                              "%s.build_time_factor", section);
2958       pextra->removal_time = 0; /* default */
2959       lookup_time(file, &pextra->removal_time, section, "removal_time",
2960                   filename, extra_rule_name(pextra), &ok);
2961       pextra->removal_time_factor = secfile_lookup_int_default(file, 1,
2962                                                                "%s.removal_time_factor", section);
2963 
2964       pextra->defense_bonus  = secfile_lookup_int_default(file, 0,
2965                                                           "%s.defense_bonus",
2966                                                           section);
2967       if (pextra->defense_bonus != 0) {
2968         if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
2969           extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
2970         } else {
2971           extra_to_caused_by_list(pextra, EC_DEFENSIVE);
2972         }
2973       }
2974 
2975       slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", section);
2976       BV_CLR_ALL(pextra->native_to);
2977       for (j = 0; j < nval; j++) {
2978         struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2979 
2980         if (uclass == NULL) {
2981           ruleset_error(LOG_ERROR,
2982                         "\"%s\" extra \"%s\" is native to unknown unit class \"%s\".",
2983                         filename,
2984                         extra_rule_name(pextra),
2985                         slist[j]);
2986           ok = FALSE;
2987           break;
2988         } else {
2989           BV_SET(pextra->native_to, uclass_index(uclass));
2990         }
2991       }
2992       free(slist);
2993 
2994       if (!ok) {
2995         break;
2996       }
2997 
2998       slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
2999       BV_CLR_ALL(pextra->flags);
3000       for (j = 0; j < nval; j++) {
3001         const char *sval = slist[j];
3002         enum extra_flag_id flag = extra_flag_id_by_name(sval, fc_strcasecmp);
3003 
3004         if (!extra_flag_id_is_valid(flag)) {
3005           ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown flag \"%s\".",
3006                         filename,
3007                         extra_rule_name(pextra),
3008                         sval);
3009           ok = FALSE;
3010           break;
3011         } else {
3012           BV_SET(pextra->flags, flag);
3013         }
3014       }
3015       free(slist);
3016 
3017       if (!ok) {
3018         break;
3019       }
3020 
3021       slist = secfile_lookup_str_vec(file, &nval, "%s.conflicts", section);
3022       for (j = 0; j < nval; j++) {
3023         const char *sval = slist[j];
3024         struct extra_type *pextra2 = extra_type_by_rule_name(sval);
3025 
3026         if (pextra2 == NULL) {
3027           ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown conflict extra \"%s\".",
3028                         filename,
3029                         extra_rule_name(pextra),
3030                         sval);
3031           ok = FALSE;
3032           break;
3033         } else {
3034           BV_SET(pextra->conflicts, extra_index(pextra2));
3035           BV_SET(pextra2->conflicts, extra_index(pextra));
3036         }
3037       }
3038 
3039       free(slist);
3040 
3041       if (!ok) {
3042         break;
3043       }
3044 
3045       slist = secfile_lookup_str_vec(file, &nval, "%s.hidden_by", section);
3046       BV_CLR_ALL(pextra->hidden_by);
3047       for (j = 0; j < nval; j++) {
3048         const char *sval = slist[j];
3049         const struct extra_type *top = extra_type_by_rule_name(sval);
3050 
3051         if (top == NULL) {
3052           ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\" hidden by unknown extra \"%s\".",
3053                         filename,
3054                         extra_rule_name(pextra),
3055                         sval);
3056           ok = FALSE;
3057           break;
3058         } else {
3059           BV_SET(pextra->hidden_by, extra_index(top));
3060         }
3061       }
3062       free(slist);
3063 
3064       if (!ok) {
3065         break;
3066       }
3067 
3068       pextra->helptext = lookup_strvec(file, section, "helptext");
3069 
3070     } extra_type_iterate_end;
3071   }
3072 
3073   if (ok) {
3074     /* base details */
3075     extra_type_by_cause_iterate(EC_BASE, pextra) {
3076       struct base_type *pbase = extra_base_get(pextra);
3077       const char *section;
3078       int bj;
3079       const char **slist;
3080       const char *gui_str;
3081 
3082       if (!pbase) {
3083         ruleset_error(LOG_ERROR,
3084                       "\"%s\" extra \"%s\" has \"Base\" cause but no "
3085                       "corresponding [base_*] section",
3086                       filename, extra_rule_name(pextra));
3087         ok = FALSE;
3088         break;
3089       }
3090       section = &base_sections[base_index(pbase) * MAX_SECTION_LABEL];
3091 
3092       gui_str = secfile_lookup_str(file,"%s.gui_type", section);
3093       pbase->gui_type = base_gui_type_by_name(gui_str, fc_strcasecmp);
3094       if (!base_gui_type_is_valid(pbase->gui_type)) {
3095         ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": unknown gui_type \"%s\".",
3096                       filename,
3097                       extra_rule_name(pextra),
3098                       gui_str);
3099         ok = FALSE;
3100         break;
3101       }
3102 
3103       pbase->border_sq  = secfile_lookup_int_default(file, -1, "%s.border_sq",
3104                                                      section);
3105       pbase->vision_main_sq   = secfile_lookup_int_default(file, -1,
3106                                                            "%s.vision_main_sq",
3107                                                            section);
3108       pbase->vision_invis_sq  = secfile_lookup_int_default(file, -1,
3109                                                            "%s.vision_invis_sq",
3110                                                            section);
3111 
3112       slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3113       BV_CLR_ALL(pbase->flags);
3114       for (bj = 0; bj < nval; bj++) {
3115         const char *sval = slist[bj];
3116         enum base_flag_id flag = base_flag_id_by_name(sval, fc_strcasecmp);
3117 
3118         if (!base_flag_id_is_valid(flag)) {
3119           ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": unknown flag \"%s\".",
3120                         filename,
3121                         extra_rule_name(pextra),
3122                         sval);
3123           ok = FALSE;
3124           break;
3125         } else {
3126           BV_SET(pbase->flags, flag);
3127         }
3128       }
3129 
3130       free(slist);
3131 
3132       if (!ok) {
3133         break;
3134       }
3135 
3136       if (territory_claiming_base(pbase)) {
3137         extra_type_by_cause_iterate(EC_BASE, pextra2) {
3138           struct base_type *pbase2;
3139 
3140           if (pextra == pextra2) {
3141             /* End of the fully initialized bases iteration. */
3142             break;
3143           }
3144 
3145           pbase2 = extra_base_get(pextra2);
3146           if (territory_claiming_base(pbase2)) {
3147             BV_SET(pextra->conflicts, extra_index(pextra2));
3148             BV_SET(pextra2->conflicts, extra_index(pextra));
3149           }
3150         } extra_type_by_cause_iterate_end;
3151       }
3152     } extra_type_by_cause_iterate_end;
3153 
3154     for (j = 0; ok && j < game.control.num_base_types; j++) {
3155       const char *section = &base_sections[j * MAX_SECTION_LABEL];
3156       const char *extra_name = secfile_lookup_str(file, "%s.extra", section);
3157       struct extra_type *pextra = extra_type_by_rule_name(extra_name);
3158 
3159       if (!is_extra_caused_by(pextra, EC_BASE)) {
3160         ruleset_error(LOG_ERROR,
3161                       "\"%s\" base section [%s]: extra \"%s\" does not have "
3162                       "\"Base\" in its causes",
3163                       filename, section, extra_name);
3164         ok = FALSE;
3165       }
3166     }
3167   }
3168 
3169   if (ok) {
3170     extra_type_by_cause_iterate(EC_ROAD, pextra) {
3171       struct road_type *proad = extra_road_get(pextra);
3172       const char *section;
3173       const char **slist;
3174       const char *special;
3175       const char *modestr;
3176       struct requirement_vector *reqs;
3177 
3178       if (!proad) {
3179         ruleset_error(LOG_ERROR,
3180                       "\"%s\" extra \"%s\" has \"Road\" cause but no "
3181                       "corresponding [road_*] section",
3182                       filename, extra_rule_name(pextra));
3183         ok = FALSE;
3184         break;
3185       }
3186       section = &road_sections[road_index(proad) * MAX_SECTION_LABEL];
3187 
3188       reqs = lookup_req_list(file, section, "first_reqs", extra_rule_name(pextra));
3189       if (reqs == NULL) {
3190         ok = FALSE;
3191         break;
3192       }
3193       requirement_vector_copy(&proad->first_reqs, reqs);
3194 
3195       if (!secfile_lookup_int(file, &proad->move_cost,
3196                               "%s.move_cost", section)) {
3197         ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3198         ok = FALSE;
3199         break;
3200       }
3201 
3202       modestr = secfile_lookup_str_default(file, "FastAlways", "%s.move_mode",
3203                                            section);
3204       proad->move_mode = road_move_mode_by_name(modestr, fc_strcasecmp);
3205       if (!road_move_mode_is_valid(proad->move_mode)) {
3206         ruleset_error(LOG_ERROR, "Illegal move_mode \"%s\" for road \"%s\"",
3207                       modestr, extra_rule_name(pextra));
3208         ok = FALSE;
3209         break;
3210       }
3211 
3212       output_type_iterate(o) {
3213         proad->tile_incr_const[o] =
3214           secfile_lookup_int_default(file, 0, "%s.%s_incr_const",
3215                                      section, get_output_identifier(o));
3216         proad->tile_incr[o] =
3217           secfile_lookup_int_default(file, 0, "%s.%s_incr",
3218                                      section, get_output_identifier(o));
3219         proad->tile_bonus[o] =
3220           secfile_lookup_int_default(file, 0, "%s.%s_bonus",
3221                                      section, get_output_identifier(o));
3222       } output_type_iterate_end;
3223 
3224       special = secfile_lookup_str_default(file, "None", "%s.compat_special", section);
3225       if (!fc_strcasecmp(special, "Road")) {
3226         if (compat_road) {
3227           ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"Road\"");
3228           ok = FALSE;
3229         }
3230         compat_road = TRUE;
3231         proad->compat = ROCO_ROAD;
3232       } else if (!fc_strcasecmp(special, "Railroad")) {
3233         if (compat_rail) {
3234           ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"Railroad\"");
3235           ok = FALSE;
3236         }
3237         compat_rail = TRUE;
3238         proad->compat = ROCO_RAILROAD;
3239       } else if (!fc_strcasecmp(special, "River")) {
3240         if (compat_river) {
3241           ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"River\"");
3242           ok = FALSE;
3243         }
3244         compat_river = TRUE;
3245         proad->compat = ROCO_RIVER;
3246       } else if (!fc_strcasecmp(special, "None")) {
3247         proad->compat = ROCO_NONE;
3248       } else {
3249         ruleset_error(LOG_ERROR, "Illegal compatibility special \"%s\" for road %s",
3250                       special, extra_rule_name(pextra));
3251         ok = FALSE;
3252       }
3253 
3254       if (!ok) {
3255         break;
3256       }
3257 
3258       slist = secfile_lookup_str_vec(file, &nval, "%s.integrates", section);
3259       BV_CLR_ALL(proad->integrates);
3260       for (j = 0; j < nval; j++) {
3261         const char *sval = slist[j];
3262         struct extra_type *textra = extra_type_by_rule_name(sval);
3263         struct road_type *top = NULL;
3264 
3265         if (textra != NULL) {
3266           top = extra_road_get(textra);
3267         }
3268 
3269         if (top == NULL) {
3270           ruleset_error(LOG_ERROR, "\"%s\" road \"%s\" integrates with unknown road \"%s\".",
3271                         filename,
3272                         extra_rule_name(pextra),
3273                         sval);
3274           ok = FALSE;
3275           break;
3276         } else {
3277           BV_SET(proad->integrates, road_index(top));
3278         }
3279       }
3280       free(slist);
3281 
3282       if (!ok) {
3283         break;
3284       }
3285 
3286       slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3287       BV_CLR_ALL(proad->flags);
3288       for (j = 0; j < nval; j++) {
3289         const char *sval = slist[j];
3290         enum road_flag_id flag = road_flag_id_by_name(sval, fc_strcasecmp);
3291 
3292         if (!road_flag_id_is_valid(flag)) {
3293           ruleset_error(LOG_ERROR, "\"%s\" road \"%s\": unknown flag \"%s\".",
3294                         filename,
3295                         extra_rule_name(pextra),
3296                         sval);
3297           ok = FALSE;
3298           break;
3299         } else {
3300           BV_SET(proad->flags, flag);
3301         }
3302       }
3303       free(slist);
3304 
3305       if (!ok) {
3306         break;
3307       }
3308     } extra_type_by_cause_iterate_end;
3309 
3310     for (j = 0; ok && j < game.control.num_road_types; j++) {
3311       const char *section = &road_sections[j * MAX_SECTION_LABEL];
3312       const char *extra_name = secfile_lookup_str(file, "%s.extra", section);
3313       struct extra_type *pextra = extra_type_by_rule_name(extra_name);
3314 
3315       if (!is_extra_caused_by(pextra, EC_ROAD)) {
3316         ruleset_error(LOG_ERROR,
3317                       "\"%s\" road section [%s]: extra \"%s\" does not have "
3318                       "\"Road\" in its causes",
3319                       filename, section, extra_name);
3320         ok = FALSE;
3321       }
3322     }
3323   }
3324 
3325   if (ok) {
3326     secfile_check_unused(file);
3327   }
3328 
3329   return ok;
3330 }
3331 
3332 /**************************************************************************
3333   Load names of governments so other rulesets can refer to governments with
3334   their name. Also load multiplier names/count from governments.ruleset.
3335 **************************************************************************/
load_government_names(struct section_file * file)3336 static bool load_government_names(struct section_file *file)
3337 {
3338   int nval = 0;
3339   struct section_list *sec;
3340   const char *filename = secfile_name(file);
3341   bool ok = TRUE;
3342 
3343   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
3344   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
3345 
3346   sec = secfile_sections_by_name_prefix(file, GOVERNMENT_SECTION_PREFIX);
3347   if (NULL == sec || 0 == (nval = section_list_size(sec))) {
3348     ruleset_error(LOG_ERROR, "\"%s\": No governments?!?", filename);
3349     ok = FALSE;
3350   } else if (nval > G_LAST) {
3351     ruleset_error(LOG_ERROR, "\"%s\": Too many governments (%d, max %d)",
3352                   filename, nval, G_LAST);
3353     ok = FALSE;
3354   }
3355 
3356   if (ok) {
3357     governments_alloc(nval);
3358 
3359     /* Government names are needed early so that get_government_by_name will
3360      * work. */
3361     governments_iterate(gov) {
3362       const char *sec_name =
3363         section_name(section_list_get(sec, government_index(gov)));
3364 
3365       if (!ruleset_load_names(&gov->name, NULL, file, sec_name)) {
3366         ok = FALSE;
3367         break;
3368       }
3369     } governments_iterate_end;
3370   }
3371 
3372   section_list_destroy(sec);
3373 
3374   if (ok) {
3375     sec = secfile_sections_by_name_prefix(file, MULTIPLIER_SECTION_PREFIX);
3376     nval = (NULL != sec ? section_list_size(sec) : 0);
3377 
3378     if (nval > MAX_NUM_MULTIPLIERS) {
3379       ruleset_error(LOG_ERROR, "\"%s\": Too many multipliers (%d, max %d)",
3380                     filename, nval, MAX_NUM_MULTIPLIERS);
3381 
3382       ok = FALSE;
3383     } else {
3384       game.control.num_multipliers = nval;
3385     }
3386 
3387     if (ok) {
3388       multipliers_iterate(pmul) {
3389         const char *sec_name =
3390           section_name(section_list_get(sec, multiplier_index(pmul)));
3391 
3392         if (!ruleset_load_names(&pmul->name, NULL, file, sec_name)) {
3393           ruleset_error(LOG_ERROR, "\"%s\": Cannot load multiplier names",
3394                         filename);
3395           ok = FALSE;
3396           break;
3397         }
3398       } multipliers_iterate_end;
3399     }
3400   }
3401 
3402   section_list_destroy(sec);
3403 
3404   return ok;
3405 }
3406 
3407 /**************************************************************************
3408   This loads information from given governments.ruleset
3409 **************************************************************************/
load_ruleset_governments(struct section_file * file)3410 static bool load_ruleset_governments(struct section_file *file)
3411 {
3412   struct section_list *sec;
3413   const char *filename = secfile_name(file);
3414   bool ok = TRUE;
3415 
3416   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
3417     return FALSE;
3418   }
3419 
3420   sec = secfile_sections_by_name_prefix(file, GOVERNMENT_SECTION_PREFIX);
3421 
3422   game.government_during_revolution
3423     = lookup_government(file, "governments.during_revolution", filename, NULL);
3424   if (game.government_during_revolution == NULL) {
3425     ok = FALSE;
3426   }
3427 
3428   if (ok) {
3429     game.info.government_during_revolution_id =
3430       government_number(game.government_during_revolution);
3431 
3432     /* easy ones: */
3433     governments_iterate(g) {
3434       const int i = government_index(g);
3435       const char *sec_name = section_name(section_list_get(sec, i));
3436       struct requirement_vector *reqs =
3437         lookup_req_list(file, sec_name, "reqs", government_rule_name(g));
3438 
3439       if (reqs == NULL) {
3440         ok = FALSE;
3441         break;
3442       }
3443 
3444       if (NULL != secfile_entry_lookup(file, "%s.ai_better", sec_name)) {
3445         char entry[100];
3446 
3447         fc_snprintf(entry, sizeof(entry), "%s.ai_better", sec_name);
3448         g->ai.better = lookup_government(file, entry, filename, NULL);
3449         if (g->ai.better == NULL) {
3450           ok = FALSE;
3451           break;
3452         }
3453       } else {
3454         g->ai.better = NULL;
3455       }
3456       requirement_vector_copy(&g->reqs, reqs);
3457 
3458       sz_strlcpy(g->graphic_str,
3459                  secfile_lookup_str(file, "%s.graphic", sec_name));
3460       sz_strlcpy(g->graphic_alt,
3461                  secfile_lookup_str(file, "%s.graphic_alt", sec_name));
3462 
3463       g->helptext = lookup_strvec(file, sec_name, "helptext");
3464     } governments_iterate_end;
3465   }
3466 
3467 
3468   if (ok) {
3469     /* titles */
3470     governments_iterate(g) {
3471       const char *sec_name =
3472         section_name(section_list_get(sec, government_index(g)));
3473       const char *male, *female;
3474 
3475       if (!(male = secfile_lookup_str(file, "%s.ruler_male_title", sec_name))
3476           || !(female = secfile_lookup_str(file, "%s.ruler_female_title",
3477                                            sec_name))) {
3478         ruleset_error(LOG_ERROR, "Lack of default ruler titles for "
3479                       "government \"%s\" (nb %d): %s",
3480                       government_rule_name(g), government_number(g),
3481                       secfile_error());
3482         ok = FALSE;
3483         break;
3484       } else if (NULL == government_ruler_title_new(g, NULL, male, female)) {
3485         ruleset_error(LOG_ERROR, "Lack of default ruler titles for "
3486                       "government \"%s\" (nb %d).",
3487                       government_rule_name(g), government_number(g));
3488         ok = FALSE;
3489         break;
3490       }
3491     } governments_iterate_end;
3492   }
3493 
3494   section_list_destroy(sec);
3495 
3496   if (ok) {
3497     sec = secfile_sections_by_name_prefix(file, MULTIPLIER_SECTION_PREFIX);
3498     multipliers_iterate(pmul) {
3499       int id = multiplier_index(pmul);
3500       const char *sec_name = section_name(section_list_get(sec, id));
3501 
3502       if (!secfile_lookup_int(file, &pmul->start, "%s.start", sec_name)) {
3503         ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3504         ok = FALSE;
3505         break;
3506       }
3507       if (!secfile_lookup_int(file, &pmul->stop, "%s.stop", sec_name)) {
3508         ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3509         ok = FALSE;
3510         break;
3511       }
3512       if (pmul->stop <= pmul->start) {
3513         ruleset_error(LOG_ERROR, "Multiplier \"%s\" stop (%d) must be greater "
3514                       "than start (%d)", multiplier_rule_name(pmul),
3515                       pmul->stop, pmul->start);
3516         ok = FALSE;
3517         break;
3518       }
3519       if (!secfile_lookup_int(file, &pmul->step, "%s.step", sec_name)) {
3520         ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3521         ok = FALSE;
3522         break;
3523       }
3524       if (((pmul->stop - pmul->start) % pmul->step) != 0) {
3525         ruleset_error(LOG_ERROR, "Multiplier \"%s\" step (%d) does not fit "
3526                       "exactly into interval start-stop (%d to %d)",
3527                       multiplier_rule_name(pmul), pmul->step,
3528                       pmul->start, pmul->stop);
3529         ok = FALSE;
3530         break;
3531       }
3532       if (!secfile_lookup_int(file, &pmul->def, "%s.default", sec_name)) {
3533         ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3534         ok = FALSE;
3535         break;
3536       }
3537       if (pmul->def < pmul->start || pmul->def > pmul->stop) {
3538         ruleset_error(LOG_ERROR, "Multiplier \"%s\" default (%d) not within "
3539                       "legal range (%d to %d)", multiplier_rule_name(pmul),
3540                       pmul->def, pmul->start, pmul->stop);
3541         ok = FALSE;
3542         break;
3543       }
3544       if (((pmul->def - pmul->start) % pmul->step) != 0) {
3545         ruleset_error(LOG_ERROR, "Multiplier \"%s\" default (%d) not legal "
3546                       "with respect to step size %d",
3547                       multiplier_rule_name(pmul), pmul->def, pmul->step);
3548         ok = FALSE;
3549         break;
3550       }
3551       pmul->offset = secfile_lookup_int_default(file, 0,
3552                                                 "%s.offset", sec_name);
3553       pmul->factor = secfile_lookup_int_default(file, 100,
3554                                                 "%s.factor", sec_name);
3555       if (pmul->factor == 0) {
3556         ruleset_error(LOG_ERROR, "Multiplier \"%s\" scaling factor must "
3557                       "not be zero", multiplier_rule_name(pmul));
3558         ok = FALSE;
3559         break;
3560       }
3561 
3562       pmul->helptext = lookup_strvec(file, sec_name, "helptext");
3563     } multipliers_iterate_end;
3564     section_list_destroy(sec);
3565   }
3566 
3567   if (ok) {
3568     secfile_check_unused(file);
3569   }
3570 
3571   return ok;
3572 }
3573 
3574 /**************************************************************************
3575   Send information in packet_ruleset_control (numbers of units etc, and
3576   other miscellany) to specified connections.
3577 
3578   The client assumes that exactly one ruleset control packet is sent as
3579   a part of each ruleset send.  So after sending this packet we have to
3580   resend every other part of the rulesets (and none of them should be
3581   is-info in the network code!).  The client frees ruleset data when
3582   receiving this packet and then re-initializes as it receives the
3583   individual ruleset packets.  See packhand.c.
3584 **************************************************************************/
send_ruleset_control(struct conn_list * dest)3585 static void send_ruleset_control(struct conn_list *dest)
3586 {
3587   int desc_left = game.control.desc_length;
3588   int idx = 0;
3589 
3590   lsend_packet_ruleset_control(dest, &(game.control));
3591 
3592   if (game.ruleset_summary != NULL) {
3593     struct packet_ruleset_summary summary;
3594 
3595     sz_strlcpy(summary.text, game.ruleset_summary);
3596 
3597     lsend_packet_ruleset_summary(dest, &summary);
3598   }
3599 
3600   while (desc_left > 0) {
3601     struct packet_ruleset_description_part part;
3602     int this_len = desc_left;
3603 
3604     if (this_len > MAX_LEN_CONTENT - 21) {
3605       this_len = MAX_LEN_CONTENT - 1;
3606     }
3607 
3608     part.text[this_len] = '\0';
3609 
3610     strncpy(part.text, &game.ruleset_description[idx], this_len);
3611     idx += this_len;
3612     desc_left -= this_len;
3613 
3614     lsend_packet_ruleset_description_part(dest, &part);
3615   }
3616 }
3617 
3618 /****************************************************************************
3619   Check for duplicate leader names in nation.
3620   If no duplicates return NULL; if yes return pointer to name which is
3621   repeated.
3622 ****************************************************************************/
check_leader_names(struct nation_type * pnation)3623 static const char *check_leader_names(struct nation_type *pnation)
3624 {
3625   nation_leader_list_iterate(nation_leaders(pnation), pleader) {
3626     const char *name = nation_leader_name(pleader);
3627 
3628     nation_leader_list_iterate(nation_leaders(pnation), prev_leader) {
3629       if (prev_leader == pleader) {
3630         break;
3631       } else if (0 == fc_strcasecmp(name, nation_leader_name(prev_leader))) {
3632         return name;
3633       }
3634     } nation_leader_list_iterate_end;
3635   } nation_leader_list_iterate_end;
3636   return NULL;
3637 }
3638 
3639 /**************************************************************************
3640   Load names of nations so other rulesets can refer to nations with
3641   their name.
3642 **************************************************************************/
load_nation_names(struct section_file * file)3643 static bool load_nation_names(struct section_file *file)
3644 {
3645   struct section_list *sec;
3646   int j;
3647   bool ok = TRUE;
3648 
3649   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
3650   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
3651 
3652   sec = secfile_sections_by_name_prefix(file, NATION_SECTION_PREFIX);
3653   if (NULL == sec) {
3654     ruleset_error(LOG_ERROR, "No available nations in this ruleset!");
3655     ok = FALSE;
3656   } else if (section_list_size(sec) > MAX_NUM_NATIONS) {
3657     ruleset_error(LOG_ERROR, "Too many nations (max %d, we have %d)!",
3658                   MAX_NUM_NATIONS, section_list_size(sec));
3659     ok = FALSE;
3660   } else {
3661     game.control.nation_count = section_list_size(sec);
3662     nations_alloc(game.control.nation_count);
3663 
3664     nations_iterate(pl) {
3665       const int i = nation_index(pl);
3666       const char *sec_name = section_name(section_list_get(sec, i));
3667       const char *domain = secfile_lookup_str_default(file, NULL,
3668                                                       "%s.translation_domain", sec_name);
3669       const char *noun_plural = secfile_lookup_str(file,
3670                                                    "%s.plural", sec_name);
3671 
3672 
3673       if (domain == NULL) {
3674         domain = "freeciv-nations";
3675       }
3676 
3677       if (!strcmp("freeciv", domain)) {
3678         pl->translation_domain = NULL;
3679       } else if (!strcmp("freeciv-nations", domain)) {
3680         pl->translation_domain = fc_malloc(strlen(domain) + 1);
3681         strcpy(pl->translation_domain, domain);
3682       } else {
3683         ruleset_error(LOG_ERROR, "Unsupported translation domain \"%s\" for %s",
3684                       domain, sec_name);
3685         ok = FALSE;
3686         break;
3687       }
3688 
3689       if (!ruleset_load_names(&pl->adjective, domain, file, sec_name)) {
3690         ok = FALSE;
3691         break;
3692       }
3693       name_set(&pl->noun_plural, domain, noun_plural);
3694 
3695       /* Check if nation name is already defined. */
3696       for (j = 0; j < i && ok; j++) {
3697         struct nation_type *n2 = nation_by_number(j);
3698 
3699         /* Compare strings after stripping off qualifiers -- we don't want
3700          * two nations to end up with identical adjectives displayed to users.
3701          * (This check only catches English, not localisations, of course.) */
3702         if (0 == strcmp(Qn_(untranslated_name(&n2->adjective)),
3703                         Qn_(untranslated_name(&pl->adjective)))) {
3704           ruleset_error(LOG_ERROR,
3705                         "Two nations defined with the same adjective \"%s\": "
3706                         "in section \'%s\' and section \'%s\'",
3707                         Qn_(untranslated_name(&pl->adjective)),
3708                         section_name(section_list_get(sec, j)), sec_name);
3709           ok = FALSE;
3710         } else if (!strcmp(rule_name_get(&n2->adjective),
3711                            rule_name_get(&pl->adjective))) {
3712           /* We cannot have the same rule name, as the game needs them to be
3713            * distinct. */
3714           ruleset_error(LOG_ERROR,
3715                         "Two nations defined with the same rule_name \"%s\": "
3716                         "in section \'%s\' and section \'%s\'",
3717                         rule_name_get(&pl->adjective),
3718                         section_name(section_list_get(sec, j)), sec_name);
3719           ok = FALSE;
3720         } else if (0 == strcmp(Qn_(untranslated_name(&n2->noun_plural)),
3721                                Qn_(untranslated_name(&pl->noun_plural)))) {
3722           /* We don't want identical English plural names either. */
3723           ruleset_error(LOG_ERROR,
3724                         "Two nations defined with the same plural name \"%s\": "
3725                         "in section \'%s\' and section \'%s\'",
3726                         Qn_(untranslated_name(&pl->noun_plural)),
3727                         section_name(section_list_get(sec, j)), sec_name);
3728           ok = FALSE;
3729         }
3730       }
3731       if (!ok) {
3732         break;
3733       }
3734     } nations_iterate_end;
3735   }
3736 
3737   section_list_destroy(sec);
3738 
3739   if (ok) {
3740     sec = secfile_sections_by_name_prefix(file, NATION_GROUP_SECTION_PREFIX);
3741     if (sec) {
3742       section_list_iterate(sec, psection) {
3743         struct nation_group *pgroup;
3744         const char *name;
3745 
3746         name = secfile_lookup_str(file, "%s.name", section_name(psection));
3747         if (NULL == name) {
3748           ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3749           ok = FALSE;
3750           break;
3751         }
3752         pgroup = nation_group_new(name);
3753         if (pgroup == NULL) {
3754           ok = FALSE;
3755           break;
3756         }
3757       } section_list_iterate_end;
3758       section_list_destroy(sec);
3759       sec = NULL;
3760     }
3761   }
3762 
3763   return ok;
3764 }
3765 
3766 /**************************************************************************
3767   Check if a string is in a vector (case-insensitively).
3768 **************************************************************************/
is_on_allowed_list(const char * name,const char ** list,size_t len)3769 static bool is_on_allowed_list(const char *name, const char **list, size_t len)
3770 {
3771   int i;
3772 
3773   for (i = 0; i < len; i++) {
3774     if (!fc_strcasecmp(name, list[i])) {
3775       return TRUE;
3776     }
3777   }
3778   return FALSE;
3779 }
3780 
3781 /****************************************************************************
3782   This function loads a city name list from a section file.  The file and
3783   two section names (which will be concatenated) are passed in.
3784 ****************************************************************************/
load_city_name_list(struct section_file * file,struct nation_type * pnation,const char * secfile_str1,const char * secfile_str2,const char ** allowed_terrains,size_t atcount)3785 static bool load_city_name_list(struct section_file *file,
3786                                 struct nation_type *pnation,
3787                                 const char *secfile_str1,
3788                                 const char *secfile_str2,
3789                                 const char **allowed_terrains,
3790                                 size_t atcount)
3791 {
3792   size_t dim, j;
3793   bool ok = TRUE;
3794   const char **cities = secfile_lookup_str_vec(file, &dim, "%s.%s",
3795                                                secfile_str1, secfile_str2);
3796 
3797   /* Each string will be of the form "<cityname> (<label>, <label>, ...)".
3798    * The cityname is just the name for this city, while each "label" matches
3799    * a terrain type for the city (or "river"), with a preceeding ! to negate
3800    * it. The parentheses are optional (but necessary to have the settings,
3801    * of course). Our job is now to parse it. */
3802   for (j = 0; j < dim; j++) {
3803     size_t len = strlen(cities[j]);
3804     char city_name[len + 1], *p, *next, *end;
3805     struct nation_city *pncity;
3806 
3807     sz_strlcpy(city_name, cities[j]);
3808 
3809     /* Now we wish to determine values for all of the city labels. A value
3810      * of NCP_NONE means no preference (which is necessary so that the use
3811      * of this is optional); NCP_DISLIKE means the label is negated and
3812      * NCP_LIKE means it's labelled. Mostly the parsing just involves
3813      * a lot of ugly string handling... */
3814     if ((p = strchr(city_name, '('))) {
3815       *p++ = '\0';
3816 
3817       if (!(end = strchr(p, ')'))) {
3818         ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
3819                       "unmatched parenthesis.", secfile_name(file),
3820                       secfile_str1, secfile_str2, cities[j]);
3821         ok = FALSE;
3822       } else {
3823         for (*end++ = '\0'; '\0' != *end; end++) {
3824           if (!fc_isspace(*end)) {
3825             ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
3826                           "contains characters after last parenthesis.",
3827                           secfile_name(file), secfile_str1, secfile_str2,
3828                           cities[j]);
3829             ok = FALSE;
3830             break;
3831           }
3832         }
3833       }
3834     }
3835 
3836     /* Build the nation_city. */
3837     remove_leading_trailing_spaces(city_name);
3838     if (check_name(city_name)) {
3839       /* The ruleset contains a name that is too long. This shouldn't
3840        * happen - if it does, the author should get immediate feedback. */
3841       ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
3842                     "is too long.", secfile_name(file),
3843                     secfile_str1, secfile_str2, city_name);
3844       ok = FALSE;
3845       city_name[MAX_LEN_NAME - 1] = '\0';
3846     }
3847     pncity = nation_city_new(pnation, city_name);
3848 
3849     if (NULL != p) {
3850       /* Handle the labels one at a time. */
3851       do {
3852         enum nation_city_preference prefer;
3853 
3854         if ((next = strchr(p, ','))) {
3855           *next = '\0';
3856         }
3857         remove_leading_trailing_spaces(p);
3858 
3859         /* The ! is used to mark a negative, which is recorded with
3860          * NCP_DISLIKE. Otherwise we use a NCP_LIKE.
3861          */
3862         if (*p == '!') {
3863           p++;
3864           prefer = NCP_DISLIKE;
3865         } else {
3866           prefer = NCP_LIKE;
3867         }
3868 
3869         if (0 == fc_strcasecmp(p, "river")) {
3870           if (game.server.ruledit.allowed_terrains != NULL
3871               && !is_on_allowed_list(p,
3872                                      game.server.ruledit.allowed_terrains, atcount)) {
3873             ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
3874                           "has terrain hint \"%s\" not in allowed_terrains.",
3875                           secfile_name(file), secfile_str1, secfile_str2,
3876                           city_name, p);
3877             ok = FALSE;
3878           } else {
3879             nation_city_set_river_preference(pncity, prefer);
3880           }
3881         } else {
3882           const struct terrain *pterrain = terrain_by_rule_name(p);
3883 
3884           if (NULL == pterrain) {
3885             /* Try with removing frequent trailing 's'. */
3886             size_t l = strlen(p);
3887 
3888             if (0 < l && 's' == fc_tolower(p[l - 1])) {
3889               char saved = p[l - 1];
3890 
3891               p[l - 1] = '\0';
3892               pterrain = terrain_by_rule_name(p);
3893               if (pterrain == NULL) {
3894                 /* Didn't help, restore for later allowed_terrains check */
3895                 p[l - 1] = saved;
3896               }
3897             }
3898           }
3899 
3900           /* Nationset may have been devised with a specific set of terrains
3901            * in mind which don't quite match this ruleset, in which case we
3902            * (a) quietly ignore any hints mentioned that don't happen to be in
3903            * the current ruleset, (b) enforce that terrains mentioned by nations
3904            * must be on the list */
3905           if (pterrain != NULL && game.server.ruledit.allowed_terrains != NULL) {
3906             if (!is_on_allowed_list(p,
3907                                     game.server.ruledit.allowed_terrains, atcount)) {
3908               /* Terrain exists, but not intended for these nations */
3909               ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
3910                             "has terrain hint \"%s\" not in allowed_terrains.",
3911                             secfile_name(file), secfile_str1, secfile_str2,
3912                             city_name, p);
3913               ok = FALSE;
3914               break;
3915             }
3916           } else if (!pterrain) {
3917             /* Terrain doesn't exist; only complain if it's not on any list */
3918             if (game.server.ruledit.allowed_terrains == NULL
3919                 || !is_on_allowed_list(p,
3920                                        game.server.ruledit.allowed_terrains, atcount)) {
3921               ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
3922                             "has unknown terrain hint \"%s\".",
3923                             secfile_name(file), secfile_str1, secfile_str2,
3924                             city_name, p);
3925               ok = FALSE;
3926               break;
3927             }
3928           }
3929           if (NULL != pterrain) {
3930             nation_city_set_terrain_preference(pncity, pterrain, prefer);
3931           }
3932         }
3933 
3934         p = next ? next + 1 : NULL;
3935       } while (NULL != p && '\0' != *p);
3936     }
3937   }
3938 
3939   if (NULL != cities) {
3940     free(cities);
3941   }
3942 
3943   return ok;
3944 }
3945 
3946 /**************************************************************************
3947 Load nations.ruleset file
3948 **************************************************************************/
load_ruleset_nations(struct section_file * file)3949 static bool load_ruleset_nations(struct section_file *file)
3950 {
3951   struct government *gov;
3952   int j;
3953   size_t dim;
3954   char temp_name[MAX_LEN_NAME];
3955   const char **vec;
3956   const char *name, *bad_leader;
3957   const char *sval;
3958   int default_set;
3959   const char *filename = secfile_name(file);
3960   struct section_list *sec;
3961   enum trait tr;
3962   bool ok = TRUE;
3963 
3964   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
3965     return FALSE;
3966   }
3967 
3968   name = secfile_lookup_str_default(file, NULL, "ruledit.nationlist");
3969   if (name != NULL) {
3970     game.server.ruledit.nationlist = fc_strdup(name);
3971   }
3972   vec  = secfile_lookup_str_vec(file, &game.server.ruledit.embedded_nations_count,
3973                                 "ruledit.embedded_nations");
3974 
3975   if (vec != NULL) {
3976     /* Copy to persistent vector */
3977     game.server.ruledit.embedded_nations
3978       = fc_malloc(game.server.ruledit.embedded_nations_count * sizeof(char *));
3979 
3980     for (j = 0; j < game.server.ruledit.embedded_nations_count; j++) {
3981       game.server.ruledit.embedded_nations[j] = fc_strdup(vec[j]);
3982     }
3983 
3984     free(vec);
3985   }
3986 
3987   game.default_government = NULL;
3988 
3989   ruleset_load_traits(game.server.default_traits, file, "default_traits", "");
3990   for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
3991     if (game.server.default_traits[tr].min < 0) {
3992       game.server.default_traits[tr].min = TRAIT_DEFAULT_VALUE;
3993     }
3994     if (game.server.default_traits[tr].max < 0) {
3995       game.server.default_traits[tr].max = TRAIT_DEFAULT_VALUE;
3996     }
3997     if (game.server.default_traits[tr].fixed < 0) {
3998       int diff = game.server.default_traits[tr].max - game.server.default_traits[tr].min;
3999 
4000       /* TODO: Should sometimes round the a / 2 = x.5 results up */
4001       game.server.default_traits[tr].fixed = diff / 2 + game.server.default_traits[tr].min;
4002     }
4003     if (game.server.default_traits[tr].max < game.server.default_traits[tr].min) {
4004       ruleset_error(LOG_ERROR, "Default values for trait %s not sane.",
4005                     trait_name(tr));
4006       ok = FALSE;
4007       break;
4008     }
4009   }
4010 
4011   if (ok) {
4012     vec = secfile_lookup_str_vec(file, &game.server.ruledit.ag_count,
4013                                  "compatibility.allowed_govs");
4014     if (vec != NULL) {
4015       /* Copy to persistent vector */
4016       game.server.ruledit.nc_agovs
4017         = fc_malloc(game.server.ruledit.ag_count * sizeof(char *));
4018       game.server.ruledit.allowed_govs =
4019         (const char **)game.server.ruledit.nc_agovs;
4020 
4021       for (j = 0; j < game.server.ruledit.ag_count; j++) {
4022         game.server.ruledit.allowed_govs[j] = fc_strdup(vec[j]);
4023       }
4024 
4025       free(vec);
4026     }
4027 
4028     vec = secfile_lookup_str_vec(file, &game.server.ruledit.at_count,
4029                                  "compatibility.allowed_terrains");
4030     if (vec != NULL) {
4031       /* Copy to persistent vector */
4032       game.server.ruledit.nc_aterrs
4033         = fc_malloc(game.server.ruledit.at_count * sizeof(char *));
4034       game.server.ruledit.allowed_terrains =
4035         (const char **)game.server.ruledit.nc_aterrs;
4036 
4037       for (j = 0; j < game.server.ruledit.at_count; j++) {
4038         game.server.ruledit.allowed_terrains[j] = fc_strdup(vec[j]);
4039       }
4040 
4041       free(vec);
4042     }
4043 
4044     vec = secfile_lookup_str_vec(file, &game.server.ruledit.as_count,
4045                                  "compatibility.allowed_styles");
4046     if (vec != NULL) {
4047       /* Copy to persistent vector */
4048       game.server.ruledit.nc_astyles
4049         = fc_malloc(game.server.ruledit.as_count * sizeof(char *));
4050       game.server.ruledit.allowed_styles =
4051         (const char **)game.server.ruledit.nc_astyles;
4052 
4053       for (j = 0; j < game.server.ruledit.as_count; j++) {
4054         game.server.ruledit.allowed_styles[j] = fc_strdup(vec[j]);
4055       }
4056 
4057       free(vec);
4058     }
4059 
4060     sval = secfile_lookup_str_default(file, NULL,
4061                                       "compatibility.default_government");
4062     /* We deliberately don't check this against allowed_govs. It's only
4063      * specified once so not vulnerable to typos, and may usefully be set in
4064      * a specific ruleset to a gov not explicitly known by the nation set. */
4065     if (sval != NULL) {
4066       game.default_government = government_by_rule_name(sval);
4067       if (game.default_government == NULL) {
4068         ruleset_error(LOG_ERROR,
4069                       "Tried to set unknown government type \"%s\" as default_government!",
4070                       sval);
4071         ok = FALSE;
4072       } else {
4073         game.info.default_government_id
4074           = government_number(game.default_government);
4075       }
4076     }
4077   }
4078 
4079   if (ok) {
4080     sec = secfile_sections_by_name_prefix(file, NATION_SET_SECTION_PREFIX);
4081     if (sec) {
4082       section_list_iterate(sec, psection) {
4083         const char *set_name, *set_rule_name, *set_description;
4084 
4085         set_name = secfile_lookup_str(file, "%s.name", section_name(psection));
4086         set_rule_name =
4087           secfile_lookup_str(file, "%s.rule_name", section_name(psection));
4088         set_description = secfile_lookup_str_default(file, "", "%s.description",
4089                                                    section_name(psection));
4090         if (NULL == set_name || NULL == set_rule_name) {
4091           ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4092           ok = FALSE;
4093           break;
4094         }
4095         if (nation_set_new(set_name, set_rule_name, set_description) == NULL) {
4096           ok = FALSE;
4097           break;
4098         }
4099       } section_list_iterate_end;
4100       section_list_destroy(sec);
4101       sec = NULL;
4102     } else {
4103       ruleset_error(LOG_ERROR,
4104                     "At least one nation set [" NATION_SET_SECTION_PREFIX "_*] "
4105                     "must be defined.");
4106       ok = FALSE;
4107     }
4108   }
4109 
4110   if (ok) {
4111     /* Default set that every nation is a member of. */
4112     sval = secfile_lookup_str_default(file, NULL,
4113                                       "compatibility.default_nationset");
4114     if (sval != NULL) {
4115       const struct nation_set *pset = nation_set_by_rule_name(sval);
4116       if (pset != NULL) {
4117         default_set = nation_set_number(pset);
4118       } else {
4119         ruleset_error(LOG_ERROR,
4120                       "Unknown default_nationset \"%s\".", sval);
4121         ok = FALSE;
4122       }
4123     } else if (nation_set_count() == 1) {
4124       /* If there's only one set defined, every nation is implicitly a
4125        * member of that set. */
4126       default_set = 0;
4127     } else {
4128       /* No default nation set; every nation must explicitly specify at
4129        * least one set to be a member of. */
4130       default_set = -1;
4131     }
4132   }
4133 
4134   if (ok) {
4135     sec = secfile_sections_by_name_prefix(file, NATION_GROUP_SECTION_PREFIX);
4136     if (sec) {
4137       section_list_iterate(sec, psection) {
4138         struct nation_group *pgroup;
4139         bool hidden;
4140 
4141         name = secfile_lookup_str(file, "%s.name", section_name(psection));
4142         pgroup = nation_group_by_rule_name(name);
4143         if (pgroup == NULL) {
4144           ok = FALSE;
4145           break;
4146         }
4147 
4148         hidden = secfile_lookup_bool_default(file, FALSE, "%s.hidden",
4149                                              section_name(psection));
4150         nation_group_set_hidden(pgroup, hidden);
4151 
4152         if (!secfile_lookup_int(file, &j, "%s.match", section_name(psection))) {
4153           ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4154           ok = FALSE;
4155           break;
4156         }
4157         nation_group_set_match(pgroup, j);
4158       } section_list_iterate_end;
4159       section_list_destroy(sec);
4160       sec = NULL;
4161     }
4162   }
4163 
4164   if (ok) {
4165     sec = secfile_sections_by_name_prefix(file, NATION_SECTION_PREFIX);
4166     nations_iterate(pnation) {
4167       struct nation_type *pconflict;
4168       const int i = nation_index(pnation);
4169       char tmp[200] = "\0";
4170       const char *barb_type;
4171       const char *sec_name = section_name(section_list_get(sec, i));
4172       const char *legend;
4173 
4174       /* Nation sets and groups. */
4175       if (default_set >= 0) {
4176         nation_set_list_append(pnation->sets,
4177                                nation_set_by_number(default_set));
4178       }
4179       vec = secfile_lookup_str_vec(file, &dim, "%s.groups", sec_name);
4180       for (j = 0; j < dim; j++) {
4181         struct nation_set *pset = nation_set_by_rule_name(vec[j]);
4182         struct nation_group *pgroup = nation_group_by_rule_name(vec[j]);
4183 
4184         fc_assert(pset == NULL || pgroup == NULL);
4185 
4186         if (NULL != pset) {
4187           nation_set_list_append(pnation->sets, pset);
4188         } else if (NULL != pgroup) {
4189           nation_group_list_append(pnation->groups, pgroup);
4190         } else {
4191           /* For nation authors, this would probably be considered an error.
4192            * But it can happen normally. The civ1 compatibility ruleset only
4193            * uses the nations that were in civ1, so not all of the links will
4194            * exist. */
4195           log_verbose("Nation %s: Unknown set/group \"%s\".",
4196                       nation_rule_name(pnation), vec[j]);
4197         }
4198       }
4199       if (NULL != vec) {
4200         free(vec);
4201       }
4202       if (nation_set_list_size(pnation->sets) < 1) {
4203         ruleset_error(LOG_ERROR,
4204                       "Nation %s is not a member of any nation set",
4205                       nation_rule_name(pnation));
4206         ok = FALSE;
4207         break;
4208       }
4209 
4210       /* Nation conflicts. */
4211       vec = secfile_lookup_str_vec(file, &dim, "%s.conflicts_with", sec_name);
4212       for (j = 0; j < dim; j++) {
4213         pconflict = nation_by_rule_name(vec[j]);
4214 
4215         if (pnation == pconflict) {
4216           ruleset_error(LOG_ERROR, "Nation %s conflicts with itself",
4217                         nation_rule_name(pnation));
4218           ok = FALSE;
4219           break;
4220         } else if (NULL != pconflict) {
4221           nation_list_append(pnation->server.conflicts_with, pconflict);
4222         } else {
4223           /* For nation authors, this would probably be considered an error.
4224            * But it can happen normally. The civ1 compatibility ruleset only
4225            * uses the nations that were in civ1, so not all of the links will
4226            * exist. */
4227           log_verbose("Nation %s: conflicts_with nation \"%s\" is unknown.",
4228                       nation_rule_name(pnation), vec[j]);
4229         }
4230       }
4231       if (NULL != vec) {
4232         free(vec);
4233       }
4234       if (!ok) {
4235         break;
4236       }
4237 
4238       /* Nation leaders. */
4239       for (j = 0; j < MAX_NUM_LEADERS; j++) {
4240         const char *sex;
4241         bool is_male = FALSE;
4242 
4243         name = secfile_lookup_str(file, "%s.leaders%d.name", sec_name, j);
4244         if (NULL == name) {
4245           /* No more to read. */
4246           break;
4247         }
4248 
4249         if (check_name(name)) {
4250           /* The ruleset contains a name that is too long. This shouldn't
4251            * happen - if it does, the author should get immediate feedback */
4252           sz_strlcpy(temp_name, name);
4253           ruleset_error(LOG_ERROR, "Nation %s: leader name \"%s\" "
4254                         "is too long.",
4255                         nation_rule_name(pnation), name);
4256           ok = FALSE;
4257           break;
4258         }
4259 
4260         sex = secfile_lookup_str(file, "%s.leaders%d.sex", sec_name, j);
4261         if (NULL == sex) {
4262           ruleset_error(LOG_ERROR, "Nation %s: leader \"%s\": %s.",
4263                         nation_rule_name(pnation), name, secfile_error());
4264           ok = FALSE;
4265           break;
4266         } else if (0 == fc_strcasecmp("Male", sex)) {
4267           is_male = TRUE;
4268         } else if (0 != fc_strcasecmp("Female", sex)) {
4269           ruleset_error(LOG_ERROR, "Nation %s: leader \"%s\" has unsupported "
4270                         "sex variant \"%s\".",
4271                         nation_rule_name(pnation), name, sex);
4272           ok = FALSE;
4273           break;
4274         }
4275         (void) nation_leader_new(pnation, name, is_male);
4276       }
4277       if (!ok) {
4278         break;
4279       }
4280 
4281       /* Check the number of leaders. */
4282       if (MAX_NUM_LEADERS == j) {
4283         /* Too much leaders, get the real number defined in the ruleset. */
4284         while (NULL != secfile_entry_lookup(file, "%s.leaders%d.name",
4285                                             sec_name, j)) {
4286           j++;
4287         }
4288         ruleset_error(LOG_ERROR, "Nation %s: Too many leaders; max is %d",
4289                       nation_rule_name(pnation), MAX_NUM_LEADERS);
4290         ok = FALSE;
4291         break;
4292       } else if (0 == j) {
4293         ruleset_error(LOG_ERROR,
4294                       "Nation %s: no leaders; at least one is required.",
4295                       nation_rule_name(pnation));
4296         ok = FALSE;
4297         break;
4298       }
4299 
4300       /* Check if leader name is not already defined in this nation. */
4301       if ((bad_leader = check_leader_names(pnation))) {
4302         ruleset_error(LOG_ERROR,
4303                       "Nation %s: leader \"%s\" defined more than once.",
4304                       nation_rule_name(pnation), bad_leader);
4305         ok = FALSE;
4306         break;
4307       }
4308 
4309       /* Nation player color preference, if any */
4310       fc_assert_ret_val(pnation->server.rgb == NULL, FALSE);
4311       (void) rgbcolor_load(file, &pnation->server.rgb, "%s.color", sec_name);
4312 
4313       /* Load nation traits */
4314       ruleset_load_traits(pnation->server.traits, file, sec_name, "trait_");
4315       for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
4316         bool server_traits_used = TRUE;
4317 
4318         if (pnation->server.traits[tr].min < 0) {
4319           pnation->server.traits[tr].min = game.server.default_traits[tr].min;
4320         } else {
4321           server_traits_used = FALSE;
4322         }
4323         if (pnation->server.traits[tr].max < 0) {
4324           pnation->server.traits[tr].max = game.server.default_traits[tr].max;
4325         } else {
4326           server_traits_used = FALSE;
4327         }
4328         if (pnation->server.traits[tr].fixed < 0) {
4329           if (server_traits_used) {
4330             pnation->server.traits[tr].fixed = game.server.default_traits[tr].fixed;
4331           } else {
4332             int diff = pnation->server.traits[tr].max - pnation->server.traits[tr].min;
4333 
4334             /* TODO: Should sometimes round the a / 2 = x.5 results up */
4335             pnation->server.traits[tr].fixed = diff / 2 + pnation->server.traits[tr].min;
4336           }
4337         }
4338         if (pnation->server.traits[tr].max < pnation->server.traits[tr].min) {
4339           ruleset_error(LOG_ERROR, "%s values for trait %s not sane.",
4340                         nation_rule_name(pnation), trait_name(tr));
4341           ok = FALSE;
4342           break;
4343         }
4344       }
4345 
4346       if (!ok) {
4347         break;
4348       }
4349 
4350       pnation->is_playable =
4351         secfile_lookup_bool_default(file, TRUE, "%s.is_playable", sec_name);
4352 
4353       /* Check barbarian type. Default is "None" meaning not a barbarian */
4354       barb_type = secfile_lookup_str_default(file, "None",
4355                                              "%s.barbarian_type", sec_name);
4356       pnation->barb_type = barbarian_type_by_name(barb_type, fc_strcasecmp);
4357       if (!barbarian_type_is_valid(pnation->barb_type)) {
4358         ruleset_error(LOG_ERROR,
4359                       "Nation %s, barbarian_type is invalid (\"%s\")",
4360                       nation_rule_name(pnation), barb_type);
4361         ok = FALSE;
4362         break;
4363       }
4364 
4365       if (pnation->barb_type != NOT_A_BARBARIAN
4366           && pnation->is_playable) {
4367         /* We can't allow players to use barbarian nations, barbarians
4368          * may run out of nations */
4369         ruleset_error(LOG_ERROR,
4370                       "Nation %s marked both barbarian and playable.",
4371                       nation_rule_name(pnation));
4372         ok = FALSE;
4373         break;
4374       }
4375 
4376       /* Flags */
4377       sz_strlcpy(pnation->flag_graphic_str,
4378                  secfile_lookup_str_default(file, "-", "%s.flag", sec_name));
4379       sz_strlcpy(pnation->flag_graphic_alt,
4380                  secfile_lookup_str_default(file, "-",
4381                                             "%s.flag_alt", sec_name));
4382 
4383       /* Ruler titles */
4384       for (j = 0;; j++) {
4385         const char *male, *female;
4386 
4387         name = secfile_lookup_str_default(file, NULL,
4388                                           "%s.ruler_titles%d.government",
4389                                           sec_name, j);
4390         if (NULL == name) {
4391           /* End of the list of ruler titles. */
4392           break;
4393         }
4394 
4395         /* NB: even if the government doesn't exist, we load the entries for
4396          * the ruler titles to avoid warnings about unused entries. */
4397         male = secfile_lookup_str(file, "%s.ruler_titles%d.male_title",
4398                                   sec_name, j);
4399         female = secfile_lookup_str(file, "%s.ruler_titles%d.female_title",
4400                                     sec_name, j);
4401         gov = government_by_rule_name(name);
4402 
4403         /* Nationset may have been devised with a specific set of govs in
4404          * mind which don't quite match this ruleset, in which case we
4405          * (a) quietly ignore any govs mentioned that don't happen to be in
4406          * the current ruleset, (b) enforce that govs mentioned by nations
4407          * must be on the list */
4408         if (gov != NULL && game.server.ruledit.allowed_govs != NULL) {
4409           if (!is_on_allowed_list(name,
4410                                   game.server.ruledit.allowed_govs,
4411                                   game.server.ruledit.ag_count)) {
4412             /* Gov exists, but not intended for these nations */
4413             gov = NULL;
4414             ruleset_error(LOG_ERROR,
4415                           "Nation %s: government \"%s\" not in allowed_govs.",
4416                           nation_rule_name(pnation), name);
4417             ok = FALSE;
4418             break;
4419           }
4420         } else if (!gov) {
4421           /* Gov doesn't exist; only complain if it's not on any list */
4422           if (game.server.ruledit.allowed_govs == NULL
4423               || !is_on_allowed_list(name,
4424                                      game.server.ruledit.allowed_govs,
4425                                      game.server.ruledit.ag_count)) {
4426             ruleset_error(LOG_ERROR, "Nation %s: government \"%s\" not found.",
4427                           nation_rule_name(pnation), name);
4428             ok = FALSE;
4429             break;
4430           }
4431         }
4432         if (NULL != male && NULL != female) {
4433           if (gov) {
4434             (void) government_ruler_title_new(gov, pnation, male, female);
4435           }
4436         } else {
4437           ruleset_error(LOG_ERROR, "%s", secfile_error());
4438           ok = FALSE;
4439           break;
4440         }
4441       }
4442       if (!ok) {
4443         break;
4444       }
4445 
4446       /* City styles */
4447       name = secfile_lookup_str(file, "%s.style", sec_name);
4448       if (!name) {
4449         ruleset_error(LOG_ERROR, "%s", secfile_error());
4450         ok = FALSE;
4451         break;
4452       }
4453       pnation->style = style_by_rule_name(name);
4454       if (pnation->style == NULL) {
4455         if (game.server.ruledit.allowed_styles == NULL
4456             || !is_on_allowed_list(name,
4457                                    game.server.ruledit.allowed_styles,
4458                                    game.server.ruledit.as_count)) {
4459           ruleset_error(LOG_ERROR, "Nation %s: Illegal style \"%s\"",
4460                         nation_rule_name(pnation), name);
4461           ok = FALSE;
4462           break;
4463         } else {
4464           log_verbose("Nation %s: style \"%s\" not supported in this "
4465                       "ruleset; using default.",
4466                       nation_rule_name(pnation), name);
4467           pnation->style = style_by_number(0);
4468         }
4469       }
4470 
4471       /* Civilwar nations */
4472       vec = secfile_lookup_str_vec(file, &dim,
4473                                    "%s.civilwar_nations", sec_name);
4474       for (j = 0; j < dim; j++) {
4475         pconflict = nation_by_rule_name(vec[j]);
4476 
4477         /* No test for duplicate nations is performed.  If there is a duplicate
4478          * entry it will just cause that nation to have an increased
4479          * probability of being chosen. */
4480         if (pconflict == pnation) {
4481           ruleset_error(LOG_ERROR, "Nation %s is its own civil war nation",
4482                         nation_rule_name(pnation));
4483           ok = FALSE;
4484           break;
4485         } else if (NULL != pconflict) {
4486           nation_list_append(pnation->server.civilwar_nations, pconflict);
4487           nation_list_append(pconflict->server.parent_nations, pnation);
4488         } else {
4489           /* For nation authors, this would probably be considered an error.
4490            * But it can happen normally. The civ1 compatibility ruleset only
4491            * uses the nations that were in civ1, so not all of the links will
4492            * exist. */
4493           log_verbose("Nation %s: civil war nation \"%s\" is unknown.",
4494                       nation_rule_name(pnation), vec[j]);
4495         }
4496       }
4497       if (NULL != vec) {
4498         free(vec);
4499       }
4500       if (!ok) {
4501         break;
4502       }
4503 
4504       /* Load nation specific initial items */
4505       if (!lookup_tech_list(file, sec_name, "init_techs",
4506                             pnation->init_techs, filename)) {
4507         ok = FALSE;
4508         break;
4509       }
4510       if (!lookup_building_list(file, sec_name, "init_buildings",
4511                                 pnation->init_buildings, filename)) {
4512         ok = FALSE;
4513         break;
4514       }
4515       if (!lookup_unit_list(file, sec_name, "init_units",
4516                             pnation->init_units, filename)) {
4517         ok = FALSE;
4518         break;
4519       }
4520       fc_strlcat(tmp, sec_name, 200);
4521       fc_strlcat(tmp, ".init_government", 200);
4522       if (secfile_entry_by_path(file, tmp)) {
4523         pnation->init_government = lookup_government(file, tmp, filename,
4524                                                      NULL);
4525         /* If specified, init_government has to be in this specific ruleset,
4526          * not just allowed_govs */
4527         if (pnation->init_government == NULL) {
4528           ok = FALSE;
4529           break;
4530         }
4531         /* ...but if a list of govs has been specified, enforce that this
4532          * nation's init_government is on the list. */
4533         if (game.server.ruledit.allowed_govs != NULL
4534             && !is_on_allowed_list(government_rule_name(pnation->init_government),
4535                                    game.server.ruledit.allowed_govs,
4536                                    game.server.ruledit.ag_count)) {
4537           ruleset_error(LOG_ERROR,
4538                         "Nation %s: init_government \"%s\" not allowed.",
4539                         nation_rule_name(pnation),
4540                         government_rule_name(pnation->init_government));
4541           ok = FALSE;
4542           break;
4543         }
4544       }
4545 
4546       /* Read default city names. */
4547       if (!load_city_name_list(file, pnation, sec_name, "cities",
4548                                game.server.ruledit.allowed_terrains,
4549                                game.server.ruledit.at_count)) {
4550         ok = FALSE;
4551         break;
4552       }
4553 
4554       legend = secfile_lookup_str_default(file, "", "%s.legend", sec_name);
4555       pnation->legend = fc_strdup(legend);
4556       if (check_strlen(pnation->legend, MAX_LEN_MSG, NULL)) {
4557         ruleset_error(LOG_ERROR,
4558                       "Nation %s: legend \"%s\" is too long.",
4559                       nation_rule_name(pnation),
4560                       pnation->legend);
4561         ok = FALSE;
4562         break;
4563       }
4564 
4565       pnation->player = NULL;
4566     } nations_iterate_end;
4567     section_list_destroy(sec);
4568     sec = NULL;
4569   }
4570 
4571   /* Clean up on aborted load */
4572   if (sec) {
4573     fc_assert(!ok);
4574     section_list_destroy(sec);
4575   }
4576 
4577   if (ok) {
4578     secfile_check_unused(file);
4579   }
4580 
4581   if (ok) {
4582     /* Update cached number of playable nations in the current set */
4583     count_playable_nations();
4584 
4585     /* Sanity checks on all sets */
4586     nation_sets_iterate(pset) {
4587       int num_playable = 0, barb_land_count = 0, barb_sea_count = 0;
4588       nations_iterate(pnation) {
4589         if (nation_is_in_set(pnation, pset)) {
4590           switch (nation_barbarian_type(pnation)) {
4591           case NOT_A_BARBARIAN:
4592             if (is_nation_playable(pnation)) {
4593               num_playable++;
4594             }
4595             break;
4596           case LAND_BARBARIAN:
4597             barb_land_count++;
4598             break;
4599           case SEA_BARBARIAN:
4600             barb_sea_count++;
4601             break;
4602           case ANIMAL_BARBARIAN:
4603             /* Animals are optional */
4604             break;
4605           default:
4606             fc_assert_ret_val(FALSE, FALSE);
4607           }
4608         }
4609       } nations_iterate_end;
4610       if (num_playable < 1) {
4611         ruleset_error(LOG_ERROR,
4612                       "Nation set \"%s\" has no playable nations. "
4613                       "At least one required!", nation_set_rule_name(pset));
4614         ok = FALSE;
4615         break;
4616       }
4617       if (barb_land_count == 0) {
4618         ruleset_error(LOG_ERROR,
4619                       "No land barbarian nation defined in set \"%s\". "
4620                       "At least one required!", nation_set_rule_name(pset));
4621         ok = FALSE;
4622         break;
4623       }
4624       if (barb_sea_count == 0) {
4625         ruleset_error(LOG_ERROR,
4626                       "No sea barbarian nation defined in set \"%s\". "
4627                       "At least one required!", nation_set_rule_name(pset));
4628         ok = FALSE;
4629         break;
4630       }
4631     } nation_sets_iterate_end;
4632   }
4633 
4634   return ok;
4635 }
4636 
4637 /**************************************************************************
4638   Load names of nation styles so other rulesets can refer to styles with
4639   their name.
4640 **************************************************************************/
load_style_names(struct section_file * file)4641 static bool load_style_names(struct section_file *file)
4642 {
4643   bool ok = TRUE;
4644   struct section_list *sec;
4645 
4646   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
4647   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
4648 
4649   sec = secfile_sections_by_name_prefix(file, STYLE_SECTION_PREFIX);
4650   if (NULL == sec) {
4651     ruleset_error(LOG_ERROR, "No available nation styles in this ruleset!");
4652     ok = FALSE;
4653   } else {
4654     game.control.num_styles = section_list_size(sec);
4655 
4656     styles_alloc(game.control.num_styles);
4657 
4658     styles_iterate(ps) {
4659       const int i = style_index(ps);
4660       const char *sec_name = section_name(section_list_get(sec, i));
4661 
4662       ruleset_load_names(&ps->name, NULL, file, sec_name);
4663     } styles_iterate_end;
4664   }
4665 
4666   section_list_destroy(sec);
4667 
4668   if (ok) {
4669     /* The citystyle sections: */
4670     int i = 0;
4671 
4672     sec = secfile_sections_by_name_prefix(file, CITYSTYLE_SECTION_PREFIX);
4673     if (NULL != sec) {
4674       city_styles_alloc(section_list_size(sec));
4675       section_list_iterate(sec, style) {
4676         if (!ruleset_load_names(&city_styles[i].name, NULL, file, section_name(style))) {
4677           ok = FALSE;
4678           break;
4679         }
4680         i++;
4681       } section_list_iterate_end;
4682 
4683       section_list_destroy(sec);
4684     } else {
4685       city_styles_alloc(0);
4686     }
4687   }
4688 
4689   return ok;
4690 }
4691 
4692 /**************************************************************************
4693   Load styles.ruleset file
4694 **************************************************************************/
load_ruleset_styles(struct section_file * file)4695 static bool load_ruleset_styles(struct section_file *file)
4696 {
4697   const char *filename = secfile_name(file);
4698   struct section_list *sec;
4699   int i;
4700   bool ok = TRUE;
4701 
4702   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
4703     return FALSE;
4704   }
4705 
4706   /* City Styles ... */
4707 
4708   sec = secfile_sections_by_name_prefix(file, CITYSTYLE_SECTION_PREFIX);
4709 
4710   /* Get rest: */
4711   for (i = 0; i < game.control.styles_count; i++) {
4712     struct requirement_vector *reqs;
4713     const char *sec_name = section_name(section_list_get(sec, i));
4714 
4715     sz_strlcpy(city_styles[i].graphic,
4716                secfile_lookup_str(file, "%s.graphic", sec_name));
4717     sz_strlcpy(city_styles[i].graphic_alt,
4718                secfile_lookup_str(file, "%s.graphic_alt", sec_name));
4719     sz_strlcpy(city_styles[i].citizens_graphic,
4720                secfile_lookup_str_default(file, "-",
4721                                           "%s.citizens_graphic", sec_name));
4722     sz_strlcpy(city_styles[i].citizens_graphic_alt,
4723                secfile_lookup_str_default(file, "generic",
4724                                           "%s.citizens_graphic_alt", sec_name));
4725 
4726     reqs = lookup_req_list(file, sec_name, "reqs", city_style_rule_name(i));
4727     if (reqs == NULL) {
4728       ok = FALSE;
4729       break;
4730     }
4731     requirement_vector_copy(&city_styles[i].reqs, reqs);
4732   }
4733 
4734   section_list_destroy(sec);
4735 
4736   if (ok) {
4737     sec = secfile_sections_by_name_prefix(file, MUSICSTYLE_SECTION_PREFIX);
4738 
4739     if (sec != NULL) {
4740       int musi;
4741 
4742       game.control.num_music_styles = section_list_size(sec);
4743       music_styles_alloc(game.control.num_music_styles);
4744       musi = 0;
4745 
4746       section_list_iterate(sec, psection) {
4747         struct requirement_vector *reqs;
4748         struct music_style *pmus = music_style_by_number(musi);
4749         const char *sec_name = section_name(psection);
4750 
4751         sz_strlcpy(pmus->music_peaceful,
4752                    secfile_lookup_str_default(file, "-",
4753                                               "%s.music_peaceful", sec_name));
4754         sz_strlcpy(pmus->music_combat,
4755                    secfile_lookup_str_default(file, "-",
4756                                               "%s.music_combat", sec_name));
4757 
4758         reqs = lookup_req_list(file, sec_name, "reqs", "Music Style");
4759         if (reqs == NULL) {
4760           ok = FALSE;
4761           break;
4762         }
4763         requirement_vector_copy(&pmus->reqs, reqs);
4764 
4765         musi++;
4766       } section_list_iterate_end;
4767     }
4768 
4769     section_list_destroy(sec);
4770   }
4771 
4772   return ok;
4773 }
4774 
4775 /**************************************************************************
4776   Load cities.ruleset file
4777 **************************************************************************/
load_ruleset_cities(struct section_file * file)4778 static bool load_ruleset_cities(struct section_file *file)
4779 {
4780   const char *filename = secfile_name(file);
4781   const char *item;
4782   struct section_list *sec;
4783   bool ok = TRUE;
4784 
4785   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
4786     return FALSE;
4787   }
4788 
4789   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
4790   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
4791 
4792   /* Specialist options */
4793   sec = secfile_sections_by_name_prefix(file, SPECIALIST_SECTION_PREFIX);
4794   if (section_list_size(sec) >= SP_MAX) {
4795     ruleset_error(LOG_ERROR, "\"%s\": Too many specialists (%d, max %d).",
4796                   filename, section_list_size(sec), SP_MAX);
4797     ok = FALSE;
4798   }
4799 
4800   if (ok) {
4801     int i = 0;
4802 
4803     game.control.num_specialist_types = section_list_size(sec);
4804 
4805     section_list_iterate(sec, psection) {
4806       struct specialist *s = specialist_by_number(i);
4807       struct requirement_vector *reqs;
4808       const char *sec_name = section_name(psection);
4809 
4810       if (!ruleset_load_names(&s->name, NULL, file, sec_name)) {
4811         ok = FALSE;
4812         break;
4813       }
4814 
4815       item = secfile_lookup_str_default(file, untranslated_name(&s->name),
4816                                         "%s.short_name", sec_name);
4817       name_set(&s->abbreviation, NULL, item);
4818 
4819       sz_strlcpy(s->graphic_alt,
4820                  secfile_lookup_str_default(file, "-",
4821                                             "%s.graphic_alt", sec_name));
4822 
4823       reqs = lookup_req_list(file, sec_name, "reqs", specialist_rule_name(s));
4824       if (reqs == NULL) {
4825         ok = FALSE;
4826         break;
4827       }
4828       requirement_vector_copy(&s->reqs, reqs);
4829 
4830       s->helptext = lookup_strvec(file, sec_name, "helptext");
4831 
4832       if (requirement_vector_size(&s->reqs) == 0 && DEFAULT_SPECIALIST == -1) {
4833         DEFAULT_SPECIALIST = i;
4834       }
4835       i++;
4836     } section_list_iterate_end;
4837   }
4838 
4839   if (ok && DEFAULT_SPECIALIST == -1) {
4840     ruleset_error(LOG_ERROR,
4841                   "\"%s\": must give a min_size of 0 for at least one "
4842                   "specialist type.", filename);
4843     ok = FALSE;
4844   }
4845   section_list_destroy(sec);
4846   sec = NULL;
4847 
4848   if (ok) {
4849     /* City Parameters */
4850 
4851     game.info.celebratesize =
4852       secfile_lookup_int_default(file, GAME_DEFAULT_CELEBRATESIZE,
4853                                  "parameters.celebrate_size_limit");
4854     game.info.add_to_size_limit =
4855       secfile_lookup_int_default(file, GAME_DEFAULT_ADDTOSIZE, "parameters.add_to_size_limit");
4856     game.info.angrycitizen =
4857       secfile_lookup_bool_default(file, GAME_DEFAULT_ANGRYCITIZEN,
4858                                   "parameters.angry_citizens");
4859 
4860     game.info.changable_tax =
4861       secfile_lookup_bool_default(file, GAME_DEFAULT_CHANGABLE_TAX, "parameters.changable_tax");
4862     game.info.forced_science =
4863       secfile_lookup_int_default(file, 0, "parameters.forced_science");
4864     game.info.forced_luxury =
4865       secfile_lookup_int_default(file, 100, "parameters.forced_luxury");
4866     game.info.forced_gold =
4867       secfile_lookup_int_default(file, 0, "parameters.forced_gold");
4868     if (game.info.forced_science + game.info.forced_luxury
4869         + game.info.forced_gold != 100) {
4870       ruleset_error(LOG_ERROR,
4871                     "\"%s\": Forced taxes do not add up in ruleset!",
4872                     filename);
4873       ok = FALSE;
4874     }
4875   }
4876 
4877   if (ok) {
4878     /* civ1 & 2 didn't reveal tiles */
4879     game.server.vision_reveal_tiles =
4880       secfile_lookup_bool_default(file, GAME_DEFAULT_VISION_REVEAL_TILES,
4881                                   "parameters.vision_reveal_tiles");
4882 
4883     game.info.pop_report_zeroes =
4884       secfile_lookup_int_default(file, 1, "parameters.pop_report_zeroes");
4885 
4886     /* Citizens configuration. */
4887     game.info.citizen_nationality =
4888       secfile_lookup_bool_default(file, GAME_DEFAULT_NATIONALITY,
4889                                   "citizen.nationality");
4890     game.info.citizen_convert_speed =
4891       secfile_lookup_int_default(file, GAME_DEFAULT_CONVERT_SPEED,
4892                                  "citizen.convert_speed");
4893     game.info.citizen_partisans_pct =
4894       secfile_lookup_int_default(file, 0, "citizen.partisans_pct");
4895   }
4896 
4897   if (ok) {
4898     secfile_check_unused(file);
4899   }
4900 
4901   return ok;
4902 }
4903 
4904 /**************************************************************************
4905 Load effects.ruleset file
4906 **************************************************************************/
load_ruleset_effects(struct section_file * file)4907 static bool load_ruleset_effects(struct section_file *file)
4908 {
4909   struct section_list *sec;
4910   const char *type;
4911   const char *filename;
4912   bool ok = TRUE;
4913   bool effect_type_warned = FALSE;
4914 
4915   filename = secfile_name(file);
4916   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
4917     return FALSE;
4918   }
4919   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
4920   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
4921 
4922   /* Parse effects and add them to the effects ruleset cache. */
4923   sec = secfile_sections_by_name_prefix(file, EFFECT_SECTION_PREFIX);
4924   section_list_iterate(sec, psection) {
4925     enum effect_type eff;
4926     int value;
4927     struct multiplier *pmul;
4928     struct effect *peffect;
4929     const char *sec_name = section_name(psection);
4930     struct requirement_vector *reqs;
4931 
4932     type = secfile_lookup_str(file, "%s.type", sec_name);
4933     if (type == NULL) {
4934       /* Backward compatibility. Field used to be named "name" */
4935       type = secfile_lookup_str(file, "%s.name", sec_name);
4936       if (type != NULL && !effect_type_warned) {
4937         log_deprecation(_("Effects should have \"type\", not the same field with old name \"name\"."));
4938         effect_type_warned = TRUE;
4939       }
4940     }
4941     if (type == NULL) {
4942       ruleset_error(LOG_ERROR, "\"%s\" [%s] missing effect name.", filename, sec_name);
4943       ok = FALSE;
4944       break;
4945     }
4946 
4947     eff = effect_type_by_name(type, fc_strcasecmp);
4948     if (!effect_type_is_valid(eff)) {
4949       ruleset_error(LOG_ERROR, "\"%s\" [%s] lists unknown effect type \"%s\".",
4950                 filename, sec_name, type);
4951       ok = FALSE;
4952       break;
4953     }
4954 
4955     value = secfile_lookup_int_default(file, 1, "%s.value", sec_name);
4956 
4957     {
4958       const char *multiplier_name
4959         = secfile_lookup_str(file, "%s.multiplier", sec_name);
4960 
4961       if (multiplier_name) {
4962         pmul = multiplier_by_rule_name(multiplier_name);
4963         if (!pmul) {
4964           ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown multiplier \"%s\".",
4965                         filename, sec_name, multiplier_name);
4966           ok = FALSE;
4967           break;
4968         }
4969       } else {
4970         pmul = NULL;
4971       }
4972     }
4973 
4974     peffect = effect_new(eff, value, pmul);
4975 
4976     reqs = lookup_req_list(file, sec_name, "reqs", type);
4977     if (reqs == NULL) {
4978       ok = FALSE;
4979       break;
4980     }
4981 
4982     requirement_vector_iterate(reqs, preq) {
4983       effect_req_append(peffect, *preq);
4984     } requirement_vector_iterate_end;
4985 
4986     reqs = lookup_req_list(file, sec_name, "nreqs", type);
4987     if (reqs == NULL) {
4988       ok = FALSE;
4989       break;
4990     }
4991     requirement_vector_iterate(reqs, preq) {
4992       preq->present = !preq->present;
4993       effect_req_append(peffect, *preq);
4994     } requirement_vector_iterate_end;
4995   } section_list_iterate_end;
4996   section_list_destroy(sec);
4997 
4998   if (ok) {
4999     secfile_check_unused(file);
5000   }
5001 
5002   return ok;
5003 }
5004 
5005 /**************************************************************************
5006   Print an error message if the value is out of range.
5007 **************************************************************************/
5008 static int secfile_lookup_int_default_min_max(struct section_file *file,
5009                                               int def, int min, int max,
5010                                               const char *path, ...)
5011                                               fc__attribute((__format__ (__printf__, 5, 6)));
secfile_lookup_int_default_min_max(struct section_file * file,int def,int min,int max,const char * path,...)5012 static int secfile_lookup_int_default_min_max(struct section_file *file,
5013                                               int def, int min, int max,
5014                                               const char *path, ...)
5015 {
5016   char fullpath[256];
5017   int ival;
5018   va_list args;
5019 
5020   va_start(args, path);
5021   fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
5022   va_end(args);
5023 
5024   if (!secfile_lookup_int(file, &ival, "%s", fullpath)) {
5025     ival = def;
5026   }
5027 
5028   if (ival < min) {
5029     ruleset_error(LOG_ERROR,"\"%s\" should be in the interval [%d, %d] "
5030                   "but is %d; using the minimal value.",
5031                   fullpath, min, max, ival);
5032     ival = min;
5033   }
5034 
5035   if (ival > max) {
5036     ruleset_error(LOG_ERROR,"\"%s\" should be in the interval [%d, %d] "
5037                   "but is %d; using the maximal value.",
5038                   fullpath, min, max, ival);
5039     ival = max;
5040   }
5041 
5042   return ival;
5043 }
5044 
5045 /**************************************************************************
5046   Load ruleset file.
5047 **************************************************************************/
load_ruleset_game(struct section_file * file,bool act)5048 static bool load_ruleset_game(struct section_file *file, bool act)
5049 {
5050   const char *sval, **svec;
5051   const char *filename;
5052   int *food_ini;
5053   int i;
5054   size_t teams;
5055   const char *pref_text;
5056   size_t gni_tmp;
5057   struct section_list *sec;
5058   size_t nval;
5059   const char *name;
5060   bool ok = TRUE;
5061 
5062   if (file == NULL) {
5063     return FALSE;
5064   }
5065   filename = secfile_name(file);
5066 
5067   /* section: datafile */
5068   if (check_ruleset_capabilities(file, RULESET_CAPABILITIES, filename) == NULL) {
5069     return FALSE;
5070   }
5071   (void) secfile_entry_by_path(file, "datafile.description");   /* unused */
5072   (void) secfile_entry_by_path(file, "datafile.ruledit");       /* unused */
5073 
5074   name = secfile_lookup_str_default(file, NULL, "ruledit.description_file");
5075   if (name != NULL) {
5076     game.server.ruledit.description_file = fc_strdup(name);
5077   }
5078 
5079   /* section: tileset */
5080   pref_text = secfile_lookup_str_default(file, "", "tileset.prefered");
5081   if (pref_text[0] != '\0') {
5082     log_deprecation("Entry tileset.prefered in game.ruleset."
5083                     " Use correct spelling tileset.preferred instead");
5084   }
5085   pref_text = secfile_lookup_str_default(file, pref_text, "tileset.preferred");
5086   if (pref_text[0] != '\0') {
5087     /* There was tileset suggestion */
5088     sz_strlcpy(game.control.preferred_tileset, pref_text);
5089   } else {
5090     /* No tileset suggestions */
5091     game.control.preferred_tileset[0] = '\0';
5092   }
5093 
5094   /* section: soundset */
5095   pref_text = secfile_lookup_str_default(file, "", "soundset.prefered");
5096   if (pref_text[0] != '\0') {
5097     log_deprecation("Entry soundset.prefered in game.ruleset."
5098                     " Use correct spelling soundset.preferred instead");
5099   }
5100   pref_text = secfile_lookup_str_default(file, pref_text, "soundset.preferred");
5101   if (pref_text[0] != '\0') {
5102     /* There was soundset suggestion */
5103     sz_strlcpy(game.control.preferred_soundset, pref_text);
5104   } else {
5105     /* No soundset suggestions */
5106     game.control.preferred_soundset[0] = '\0';
5107   }
5108 
5109   /* section: musicset */
5110   pref_text = secfile_lookup_str_default(file, "", "musicset.prefered");
5111   if (pref_text[0] != '\0') {
5112     log_deprecation("Entry musicset.prefered in game.ruleset."
5113                     " Use correct spelling musicset.preferred instead");
5114   }
5115   pref_text = secfile_lookup_str_default(file, pref_text, "musicset.preferred");
5116   if (pref_text[0] != '\0') {
5117     /* There was musicset suggestion */
5118     sz_strlcpy(game.control.preferred_musicset, pref_text);
5119   } else {
5120     /* No musicset suggestions */
5121     game.control.preferred_musicset[0] = '\0';
5122   }
5123 
5124   /* section: about */
5125   pref_text = secfile_lookup_str(file, "about.name");
5126   /* Ruleset/modpack name found */
5127   sz_strlcpy(game.control.name, pref_text);
5128 
5129   pref_text = secfile_lookup_str_default(file, "", "about.version");
5130   if (pref_text[0] != '\0') {
5131     /* Ruleset/modpack version found */
5132     sz_strlcpy(game.control.version, pref_text);
5133   } else {
5134     /* No version information */
5135     game.control.version[0] = '\0';
5136   }
5137 
5138   pref_text = secfile_lookup_str_default(file, "", "about.summary");
5139   if (pref_text[0] != '\0') {
5140     int len;
5141 
5142     /* Ruleset/modpack summary found */
5143     len = strlen(pref_text);
5144     game.ruleset_summary = fc_malloc(len + 1);
5145     fc_strlcpy(game.ruleset_summary, pref_text, len + 1);
5146   } else {
5147     /* No summary */
5148     if (game.ruleset_summary != NULL) {
5149       free(game.ruleset_summary);
5150       game.ruleset_summary = NULL;
5151     }
5152   }
5153 
5154   pref_text = secfile_lookup_str_default(file, "", "about.description");
5155   if (pref_text[0] != '\0') {
5156     int len;
5157 
5158     /* Ruleset/modpack description found */
5159     len = strlen(pref_text);
5160     game.ruleset_description = fc_malloc(len + 1);
5161     fc_strlcpy(game.ruleset_description, pref_text, len + 1);
5162     game.control.desc_length = len;
5163   } else {
5164     /* No description */
5165     if (game.ruleset_description != NULL) {
5166       free(game.ruleset_description);
5167       game.ruleset_description = NULL;
5168     }
5169     game.control.desc_length = 0;
5170   }
5171 
5172   /* section: options */
5173   if (!lookup_tech_list(file, "options", "global_init_techs",
5174                         game.rgame.global_init_techs, filename)) {
5175     ok = FALSE;
5176   }
5177 
5178   if (ok) {
5179     if (!lookup_building_list(file, "options", "global_init_buildings",
5180                               game.rgame.global_init_buildings, filename)) {
5181       ok = FALSE;
5182     }
5183   }
5184 
5185   if (ok) {
5186     const char **slist;
5187     int j;
5188 
5189     game.control.popup_tech_help = secfile_lookup_bool_default(file, FALSE,
5190                                                                "options.popup_tech_help");
5191 
5192     /* section: civstyle */
5193     game.info.base_pollution
5194       = secfile_lookup_int_default(file, RS_DEFAULT_BASE_POLLUTION,
5195                                    "civstyle.base_pollution");
5196 
5197     game.info.gameloss_style = GAMELOSS_STYLE_CLASSICAL;
5198 
5199     slist = secfile_lookup_str_vec(file, &nval, "civstyle.gameloss_style");
5200     for (j = 0; j < nval; j++) {
5201       enum gameloss_style style;
5202 
5203       sval = slist[j];
5204       if (strcmp(sval, "") == 0) {
5205         continue;
5206       }
5207       style = gameloss_style_by_name(sval, fc_strcasecmp);
5208       if (!gameloss_style_is_valid(style)) {
5209         ruleset_error(LOG_ERROR, "\"%s\": bad value \"%s\" for gameloss_style.",
5210                       filename, sval);
5211         ok = FALSE;
5212         break;
5213       } else {
5214         game.info.gameloss_style |= style;
5215       }
5216     }
5217     free(slist);
5218   }
5219 
5220   if (ok) {
5221     game.info.happy_cost
5222       = secfile_lookup_int_def_min_max(file,
5223                                        RS_DEFAULT_HAPPY_COST,
5224                                        RS_MIN_HAPPY_COST,
5225                                        RS_MAX_HAPPY_COST,
5226                                        "civstyle.happy_cost");
5227     game.info.food_cost
5228       = secfile_lookup_int_default_min_max(file,
5229                                            RS_DEFAULT_FOOD_COST,
5230                                            RS_MIN_FOOD_COST,
5231                                            RS_MAX_FOOD_COST,
5232                                            "civstyle.food_cost");
5233     game.info.civil_war_enabled
5234       = secfile_lookup_bool_default(file, TRUE, "civstyle.civil_war_enabled");
5235 
5236     game.info.paradrop_to_transport
5237       = secfile_lookup_bool_default(file, FALSE,
5238                                     "civstyle.paradrop_to_transport");
5239 
5240     /* TODO: move to global_unit_options */
5241     game.info.base_bribe_cost
5242       = secfile_lookup_int_default_min_max(file,
5243                                            RS_DEFAULT_BASE_BRIBE_COST,
5244                                            RS_MIN_BASE_BRIBE_COST,
5245                                            RS_MAX_BASE_BRIBE_COST,
5246                                            "civstyle.base_bribe_cost");
5247     /* TODO: move to global_unit_options */
5248     game.server.ransom_gold
5249       = secfile_lookup_int_default_min_max(file,
5250                                            RS_DEFAULT_RANSOM_GOLD,
5251                                            RS_MIN_RANSOM_GOLD,
5252                                            RS_MAX_RANSOM_GOLD,
5253                                            "civstyle.ransom_gold");
5254     /* TODO: move to global_unit_options */
5255     game.info.pillage_select
5256       = secfile_lookup_bool_default(file, RS_DEFAULT_PILLAGE_SELECT,
5257                                     "civstyle.pillage_select");
5258 
5259    game.info.tech_steal_allow_holes
5260       = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_STEAL_HOLES,
5261                                     "civstyle.tech_steal_allow_holes");
5262    game.info.tech_trade_allow_holes
5263       = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_TRADE_HOLES,
5264                                     "civstyle.tech_trade_allow_holes");
5265    game.info.tech_trade_loss_allow_holes
5266       = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_TRADE_LOSS_HOLES,
5267                                     "civstyle.tech_trade_loss_allow_holes");
5268    game.info.tech_parasite_allow_holes
5269       = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_PARASITE_HOLES,
5270                                     "civstyle.tech_parasite_allow_holes");
5271    game.info.tech_loss_allow_holes
5272       = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_LOSS_HOLES,
5273                                     "civstyle.tech_loss_allow_holes");
5274 
5275     /* TODO: move to global_unit_options */
5276     game.server.upgrade_veteran_loss
5277       = secfile_lookup_int_default_min_max(file,
5278                                            RS_DEFAULT_UPGRADE_VETERAN_LOSS,
5279                                            RS_MIN_UPGRADE_VETERAN_LOSS,
5280                                            RS_MAX_UPGRADE_VETERAN_LOSS,
5281                                            "civstyle.upgrade_veteran_loss");
5282     /* TODO: move to global_unit_options */
5283     game.server.autoupgrade_veteran_loss
5284       = secfile_lookup_int_default_min_max(file,
5285                                            RS_DEFAULT_UPGRADE_VETERAN_LOSS,
5286                                            RS_MIN_UPGRADE_VETERAN_LOSS,
5287                                            RS_MAX_UPGRADE_VETERAN_LOSS,
5288                                            "civstyle.autoupgrade_veteran_loss");
5289 
5290     game.info.base_tech_cost
5291       = secfile_lookup_int_default_min_max(file,
5292                                            RS_DEFAULT_BASE_TECH_COST,
5293                                            RS_MIN_BASE_TECH_COST,
5294                                            RS_MAX_BASE_TECH_COST,
5295                                            "research.base_tech_cost");
5296 
5297     food_ini = secfile_lookup_int_vec(file, &gni_tmp,
5298                                       "civstyle.granary_food_ini");
5299     game.info.granary_num_inis = (int) gni_tmp;
5300 
5301     if (game.info.granary_num_inis > MAX_GRANARY_INIS) {
5302       ruleset_error(LOG_ERROR,
5303                     "Too many granary_food_ini entries (%d, max %d)",
5304                     game.info.granary_num_inis, MAX_GRANARY_INIS);
5305       ok = FALSE;
5306     } else if (game.info.granary_num_inis == 0) {
5307       log_error("No values for granary_food_ini. Using default "
5308                 "value %d.", RS_DEFAULT_GRANARY_FOOD_INI);
5309       game.info.granary_num_inis = 1;
5310       game.info.granary_food_ini[0] = RS_DEFAULT_GRANARY_FOOD_INI;
5311     } else {
5312       int gi;
5313 
5314       /* check for <= 0 entries */
5315       for (gi = 0; gi < game.info.granary_num_inis; gi++) {
5316         if (food_ini[gi] <= 0) {
5317           if (gi == 0) {
5318             food_ini[gi] = RS_DEFAULT_GRANARY_FOOD_INI;
5319           } else {
5320             food_ini[gi] = food_ini[gi - 1];
5321           }
5322           log_error("Bad value for granary_food_ini[%i]. Using %i.",
5323                     gi, food_ini[gi]);
5324         }
5325         game.info.granary_food_ini[gi] = food_ini[gi];
5326       }
5327     }
5328     free(food_ini);
5329   }
5330 
5331   if (ok) {
5332     game.info.granary_food_inc
5333       = secfile_lookup_int_default_min_max(file,
5334                                            RS_DEFAULT_GRANARY_FOOD_INC,
5335                                            RS_MIN_GRANARY_FOOD_INC,
5336                                            RS_MAX_GRANARY_FOOD_INC,
5337                                            "civstyle.granary_food_inc");
5338 
5339     output_type_iterate(o) {
5340       game.info.min_city_center_output[o]
5341         = secfile_lookup_int_default_min_max(file,
5342                                              RS_DEFAULT_CITY_CENTER_OUTPUT,
5343                                              RS_MIN_CITY_CENTER_OUTPUT,
5344                                              RS_MAX_CITY_CENTER_OUTPUT,
5345                                              "civstyle.min_city_center_%s",
5346                                              get_output_identifier(o));
5347     } output_type_iterate_end;
5348   }
5349 
5350   if (ok) {
5351     const char *tus_text;
5352 
5353     game.server.init_vis_radius_sq
5354       = secfile_lookup_int_default_min_max(file,
5355                                            RS_DEFAULT_VIS_RADIUS_SQ,
5356                                            RS_MIN_VIS_RADIUS_SQ,
5357                                            RS_MAX_VIS_RADIUS_SQ,
5358                                            "civstyle.init_vis_radius_sq");
5359 
5360     game.info.init_city_radius_sq
5361       = secfile_lookup_int_default_min_max(file,
5362                                            RS_DEFAULT_CITY_RADIUS_SQ,
5363                                            RS_MIN_CITY_RADIUS_SQ,
5364                                            RS_MAX_CITY_RADIUS_SQ,
5365                                            "civstyle.init_city_radius_sq");
5366 
5367     tus_text = secfile_lookup_str_default(file, RS_DEFAULT_GOLD_UPKEEP_STYLE,
5368                                           "civstyle.gold_upkeep_style");
5369     game.info.gold_upkeep_style = gold_upkeep_style_by_name(tus_text,
5370                                                             fc_strcasecmp);
5371     if (!gold_upkeep_style_is_valid(game.info.gold_upkeep_style)) {
5372       ruleset_error(LOG_ERROR, "Unknown gold upkeep style \"%s\"",
5373                     tus_text);
5374       ok = FALSE;
5375     }
5376 
5377     /* section: illness */
5378     game.info.illness_on
5379       = secfile_lookup_bool_default(file, RS_DEFAULT_ILLNESS_ON,
5380                                     "illness.illness_on");
5381     game.info.illness_base_factor
5382       = secfile_lookup_int_default_min_max(file,
5383                                            RS_DEFAULT_ILLNESS_BASE_FACTOR,
5384                                            RS_MIN_ILLNESS_BASE_FACTOR,
5385                                            RS_MAX_ILLNESS_BASE_FACTOR,
5386                                            "illness.illness_base_factor");
5387     game.info.illness_min_size
5388       = secfile_lookup_int_default_min_max(file,
5389                                            RS_DEFAULT_ILLNESS_MIN_SIZE,
5390                                            RS_MIN_ILLNESS_MIN_SIZE,
5391                                            RS_MAX_ILLNESS_MIN_SIZE,
5392                                            "illness.illness_min_size");
5393     game.info.illness_trade_infection
5394       = secfile_lookup_int_default_min_max(file,
5395                                            RS_DEFAULT_ILLNESS_TRADE_INFECTION_PCT,
5396                                            RS_MIN_ILLNESS_TRADE_INFECTION_PCT,
5397                                            RS_MAX_ILLNESS_TRADE_INFECTION_PCT,
5398                                            "illness.illness_trade_infection");
5399     game.info.illness_pollution_factor
5400       = secfile_lookup_int_default_min_max(file,
5401                                            RS_DEFAULT_ILLNESS_POLLUTION_PCT,
5402                                            RS_MIN_ILLNESS_POLLUTION_PCT,
5403                                            RS_MAX_ILLNESS_POLLUTION_PCT,
5404                                            "illness.illness_pollution_factor");
5405 
5406     /* section: incite_cost */
5407     game.server.base_incite_cost
5408       = secfile_lookup_int_default_min_max(file,
5409                                            RS_DEFAULT_INCITE_BASE_COST,
5410                                            RS_MIN_INCITE_BASE_COST,
5411                                            RS_MAX_INCITE_BASE_COST,
5412                                            "incite_cost.base_incite_cost");
5413     game.server.incite_improvement_factor
5414       = secfile_lookup_int_default_min_max(file,
5415                                            RS_DEFAULT_INCITE_IMPROVEMENT_FCT,
5416                                            RS_MIN_INCITE_IMPROVEMENT_FCT,
5417                                            RS_MAX_INCITE_IMPROVEMENT_FCT,
5418                                            "incite_cost.improvement_factor");
5419     game.server.incite_unit_factor
5420       = secfile_lookup_int_default_min_max(file,
5421                                            RS_DEFAULT_INCITE_UNIT_FCT,
5422                                            RS_MIN_INCITE_UNIT_FCT,
5423                                            RS_MAX_INCITE_UNIT_FCT,
5424                                            "incite_cost.unit_factor");
5425     game.server.incite_total_factor
5426       = secfile_lookup_int_default_min_max(file,
5427                                            RS_DEFAULT_INCITE_TOTAL_FCT,
5428                                            RS_MIN_INCITE_TOTAL_FCT,
5429                                            RS_MAX_INCITE_TOTAL_FCT,
5430                                            "incite_cost.total_factor");
5431 
5432     /* section: global_unit_options */
5433     game.info.slow_invasions
5434       = secfile_lookup_bool_default(file, RS_DEFAULT_SLOW_INVASIONS,
5435                                     "global_unit_options.slow_invasions");
5436 
5437     /* section: actions */
5438     if (ok) {
5439       const char *text;
5440 
5441       /* Forbid entering the marketplace when a trade route can be
5442        * established. */
5443       game.info.force_trade_route
5444         = secfile_lookup_bool_default(file, RS_DEFAULT_FORCE_TRADE_ROUTE,
5445                                       "actions.force_trade_route");
5446 
5447       text = secfile_lookup_str_default(file,
5448           /* TRANS: _Poison City (3% chance of success). */
5449           N_("%sPoison City%s"),
5450           "actions.ui_name_poison_city");
5451       sz_strlcpy(action_by_number(ACTION_SPY_POISON)->ui_name,
5452                  text);
5453 
5454       text = secfile_lookup_str_default(file,
5455           /* TRANS: S_abotage Enemy Unit (3% chance of success). */
5456           N_("S%sabotage Enemy Unit%s"),
5457           "actions.ui_name_sabotage_unit");
5458       sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_UNIT)->ui_name,
5459                  text);
5460 
5461       text = secfile_lookup_str_default(file,
5462           /* TRANS: Bribe Enemy _Unit (3% chance of success). */
5463           N_("Bribe Enemy %sUnit%s"),
5464           "actions.ui_name_bribe_unit");
5465       sz_strlcpy(action_by_number(ACTION_SPY_BRIBE_UNIT)->ui_name,
5466                  text);
5467 
5468       text = secfile_lookup_str_default(file,
5469           /* TRANS: _Sabotage City (3% chance of success). */
5470           N_("%sSabotage City%s"),
5471           "actions.ui_name_sabotage_city");
5472       sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_CITY)->ui_name,
5473                  text);
5474 
5475       text = secfile_lookup_str_default(file,
5476           /* TRANS: Industria_l Sabotage (3% chance of success). */
5477           N_("Industria%sl Sabotage%s"),
5478           "actions.ui_name_targeted_sabotage_city");
5479       sz_strlcpy(
5480             action_by_number(ACTION_SPY_TARGETED_SABOTAGE_CITY)->ui_name,
5481             text);
5482 
5483       text = secfile_lookup_str_default(file,
5484           /* TRANS: Incite a Re_volt (3% chance of success). */
5485           N_("Incite a Re%svolt%s"),
5486           "actions.ui_name_incite_city");
5487       sz_strlcpy(action_by_number(ACTION_SPY_INCITE_CITY)->ui_name,
5488                  text);
5489 
5490       text = secfile_lookup_str_default(file,
5491           /* TRANS: Establish _Embassy (100% chance of success). */
5492           N_("Establish %sEmbassy%s"),
5493           "actions.ui_name_establish_embassy");
5494       sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY)->ui_name,
5495                  text);
5496 
5497       text = secfile_lookup_str_default(file,
5498           /* TRANS: Steal _Technology (3% chance of success). */
5499           N_("Steal %sTechnology%s"),
5500           "actions.ui_name_steal_tech");
5501       sz_strlcpy(action_by_number(ACTION_SPY_STEAL_TECH)->ui_name,
5502                  text);
5503 
5504       text = secfile_lookup_str_default(file,
5505           /* TRANS: In_dustrial Espionage (3% chance of success). */
5506           N_("In%sdustrial Espionage%s"),
5507           "actions.ui_name_targeted_steal_tech");
5508       sz_strlcpy(action_by_number(ACTION_SPY_TARGETED_STEAL_TECH)->ui_name,
5509                  text);
5510 
5511       text = secfile_lookup_str_default(file,
5512           /* TRANS: _Investigate City (100% chance of success). */
5513           N_("%sInvestigate City%s"),
5514           "actions.ui_name_investigate_city");
5515       sz_strlcpy(action_by_number(ACTION_SPY_INVESTIGATE_CITY)->ui_name,
5516                  text);
5517 
5518       text = secfile_lookup_str_default(file,
5519           /* TRANS: Steal _Gold (100% chance of success). */
5520           N_("Steal %sGold%s"),
5521           "actions.ui_name_steal_gold");
5522       sz_strlcpy(action_by_number(ACTION_SPY_STEAL_GOLD)->ui_name,
5523                  text);
5524 
5525       text = secfile_lookup_str_default(file,
5526           /* TRANS: Establish Trade _Route (100% chance of success). */
5527           N_("Establish Trade %sRoute%s"),
5528           "actions.ui_name_establish_trade_route");
5529       sz_strlcpy(action_by_number(ACTION_TRADE_ROUTE)->ui_name,
5530                  text);
5531 
5532       text = secfile_lookup_str_default(file,
5533           /* TRANS: Enter _Marketplace (100% chance of success). */
5534           N_("Enter %sMarketplace%s"),
5535           "actions.ui_name_enter_marketplace");
5536       sz_strlcpy(action_by_number(ACTION_MARKETPLACE)->ui_name,
5537                  text);
5538 
5539       text = secfile_lookup_str_default(file,
5540           /* TRANS: Help _build Wonder (100% chance of success). */
5541           N_("Help %sbuild Wonder%s"),
5542           "actions.ui_name_help_wonder");
5543       sz_strlcpy(action_by_number(ACTION_HELP_WONDER)->ui_name,
5544                  text);
5545 
5546       /* The quiet (don't auto generate help for) property of all actions
5547        * live in a single enum vector. This avoids generic action
5548        * expectations. */
5549       if (secfile_entry_by_path(file, "actions.quiet_actions")) {
5550         enum gen_action *quiet_actions;
5551         size_t asize;
5552         int j;
5553 
5554         quiet_actions =
5555             secfile_lookup_enum_vec(file, &asize, gen_action,
5556                                     "actions.quiet_actions");
5557 
5558         if (!quiet_actions) {
5559           /* Entity exists but couldn't read it. */
5560           ruleset_error(LOG_ERROR,
5561                         "\"%s\": actions.quiet_actions: bad action list",
5562                         filename);
5563 
5564           ok = FALSE;
5565         }
5566 
5567         for (j = 0; j < asize; j++) {
5568           /* Don't auto generate help text for this action. */
5569           action_by_number(quiet_actions[j])->quiet = TRUE;
5570         }
5571 
5572         free(quiet_actions);
5573       }
5574     }
5575 
5576     if (ok) {
5577       sec = secfile_sections_by_name_prefix(file,
5578                                             ACTION_ENABLER_SECTION_PREFIX);
5579 
5580       if (sec) {
5581         section_list_iterate(sec, psection) {
5582           struct action_enabler *enabler;
5583           const char *sec_name = section_name(psection);
5584           enum gen_action action;
5585           struct requirement_vector *actor_reqs;
5586           struct requirement_vector *target_reqs;
5587           const char *action_text;
5588 
5589           enabler = action_enabler_new();
5590 
5591           action_text = secfile_lookup_str(file, "%s.action", sec_name);
5592 
5593           if (action_text == NULL) {
5594             ruleset_error(LOG_ERROR, "\"%s\" [%s] missing action to enable.",
5595                           filename, sec_name);
5596             ok = FALSE;
5597             break;
5598           }
5599 
5600           action = gen_action_by_name(action_text, fc_strcasecmp);
5601           if (!action_id_is_valid(action)) {
5602             ruleset_error(LOG_ERROR, "\"%s\" [%s] lists unknown action type \"%s\".",
5603                           filename, sec_name, action_text);
5604             ok = FALSE;
5605             break;
5606           }
5607 
5608           enabler->action = action;
5609 
5610           actor_reqs = lookup_req_list(file, sec_name, "actor_reqs", action_text);
5611           if (actor_reqs == NULL) {
5612             ok = FALSE;
5613             break;
5614           }
5615 
5616           requirement_vector_copy(&enabler->actor_reqs, actor_reqs);
5617 
5618           target_reqs = lookup_req_list(file, sec_name, "target_reqs", action_text);
5619           if (target_reqs == NULL) {
5620             ok = FALSE;
5621             break;
5622           }
5623 
5624           requirement_vector_copy(&enabler->target_reqs, target_reqs);
5625 
5626           action_enabler_add(enabler);
5627         } section_list_iterate_end;
5628         section_list_destroy(sec);
5629       }
5630     }
5631   }
5632 
5633   if (ok) {
5634     const char *tus_text;
5635 
5636     /* section: combat_rules */
5637     game.info.tired_attack
5638       = secfile_lookup_bool_default(file, RS_DEFAULT_TIRED_ATTACK,
5639                                     "combat_rules.tired_attack");
5640 
5641     /* section: borders */
5642     game.info.border_city_radius_sq
5643       = secfile_lookup_int_default_min_max(file,
5644                                            RS_DEFAULT_BORDER_RADIUS_SQ_CITY,
5645                                            RS_MIN_BORDER_RADIUS_SQ_CITY,
5646                                            RS_MAX_BORDER_RADIUS_SQ_CITY,
5647                                            "borders.radius_sq_city");
5648     game.info.border_size_effect
5649       = secfile_lookup_int_default_min_max(file,
5650                                            RS_DEFAULT_BORDER_SIZE_EFFECT,
5651                                            RS_MIN_BORDER_SIZE_EFFECT,
5652                                            RS_MAX_BORDER_SIZE_EFFECT,
5653                                            "borders.size_effect");
5654 
5655     game.info.border_city_permanent_radius_sq
5656       = secfile_lookup_int_default_min_max(file,
5657                                            RS_DEFAULT_BORDER_RADIUS_SQ_CITY_PERMANENT,
5658                                            RS_MIN_BORDER_RADIUS_SQ_CITY_PERMANENT,
5659                                            RS_MAX_BORDER_RADIUS_SQ_CITY_PERMANENT,
5660                                            "borders.radius_sq_city_permanent");
5661 
5662     /* section: research */
5663     tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_COST_STYLE,
5664                                           "research.tech_cost_style");
5665     game.info.tech_cost_style = tech_cost_style_by_name(tus_text,
5666                                                         fc_strcasecmp);
5667     if (!tech_cost_style_is_valid(game.info.tech_cost_style)) {
5668       ruleset_error(LOG_ERROR, "Unknown tech cost style \"%s\"",
5669                     tus_text);
5670       ok = FALSE;
5671     }
5672 
5673     tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_LEAKAGE,
5674                                           "research.tech_leakage");
5675     game.info.tech_leakage = tech_leakage_style_by_name(tus_text,
5676                                                         fc_strcasecmp);
5677     if (!tech_leakage_style_is_valid(game.info.tech_leakage)) {
5678       ruleset_error(LOG_ERROR, "Unknown tech leakage \"%s\"",
5679                     tus_text);
5680       ok = FALSE;
5681     }
5682     if (game.info.tech_cost_style == TECH_COST_CIV1CIV2
5683         && game.info.tech_leakage != TECH_LEAKAGE_NONE) {
5684       log_error("Only tech_leakage \"%s\" supported with "
5685                 "tech_cost_style \"%s\". ",
5686                 tech_leakage_style_name(TECH_LEAKAGE_NONE),
5687                 tech_cost_style_name(TECH_COST_CIV1CIV2));
5688       log_error("Switching to tech_leakage \"%s\".",
5689                 tech_leakage_style_name(TECH_LEAKAGE_NONE));
5690       game.info.tech_leakage = TECH_LEAKAGE_NONE;
5691     }
5692     game.info.base_tech_cost
5693       = secfile_lookup_int_default_min_max(file,
5694                                            RS_DEFAULT_BASE_TECH_COST,
5695                                            RS_MIN_BASE_TECH_COST,
5696                                            RS_MAX_BASE_TECH_COST,
5697                                            "research.base_tech_cost");
5698 
5699     tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_UPKEEP_STYLE,
5700                                           "research.tech_upkeep_style");
5701 
5702     game.info.tech_upkeep_style = tech_upkeep_style_by_name(tus_text, fc_strcasecmp);
5703 
5704     if (!tech_upkeep_style_is_valid(game.info.tech_upkeep_style)) {
5705       ruleset_error(LOG_ERROR, "Unknown tech upkeep style \"%s\"",
5706                     tus_text);
5707       ok = FALSE;
5708     }
5709   }
5710 
5711   if (ok) {
5712     game.info.tech_upkeep_divider
5713       = secfile_lookup_int_default_min_max(file,
5714                                            RS_DEFAULT_TECH_UPKEEP_DIVIDER,
5715                                            RS_MIN_TECH_UPKEEP_DIVIDER,
5716                                            RS_MAX_TECH_UPKEEP_DIVIDER,
5717                                            "research.tech_upkeep_divider");
5718 
5719     sval = secfile_lookup_str_default(file, NULL, "research.free_tech_method");
5720     if (sval == NULL) {
5721       ruleset_error(LOG_ERROR, "No free_tech_method given");
5722       ok = FALSE;
5723     } else {
5724       game.info.free_tech_method = free_tech_method_by_name(sval, fc_strcasecmp);
5725       if (!free_tech_method_is_valid(game.info.free_tech_method)) {
5726         ruleset_error(LOG_ERROR, "Bad value %s for free_tech_method.", sval);
5727         ok = FALSE;
5728       }
5729     }
5730   }
5731 
5732   if (ok) {
5733     int cf;
5734 
5735     /* section: culture */
5736     game.info.culture_vic_points
5737       = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_VIC_POINTS,
5738                                    "culture.victory_min_points");
5739     game.info.culture_vic_lead
5740       = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_VIC_LEAD,
5741                                    "culture.victory_lead_pct");
5742     game.info.culture_migration_pml
5743       = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_MIGRATION_PML,
5744                                    "culture.migration_pml");
5745 
5746     /* section: calendar */
5747     game.info.calendar_skip_0
5748       = secfile_lookup_bool_default(file, RS_DEFAULT_CALENDAR_SKIP_0,
5749                                     "calendar.skip_year_0");
5750     game.server.start_year
5751       = secfile_lookup_int_default(file, GAME_DEFAULT_START_YEAR,
5752                                    "calendar.start_year");
5753     game.info.calendar_fragments
5754       = secfile_lookup_int_default(file, 0, "calendar.fragments");
5755 
5756     if (game.info.calendar_fragments > MAX_CALENDAR_FRAGMENTS) {
5757       ruleset_error(LOG_ERROR, "Too many calendar fragments. Max is %d",
5758                     MAX_CALENDAR_FRAGMENTS);
5759       ok = FALSE;
5760       game.info.calendar_fragments = 0;
5761     }
5762     sz_strlcpy(game.info.positive_year_label,
5763                secfile_lookup_str_default(file,
5764                                           RS_DEFAULT_POS_YEAR_LABEL,
5765                                           "calendar.positive_label"));
5766     sz_strlcpy(game.info.negative_year_label,
5767                secfile_lookup_str_default(file,
5768                                           RS_DEFAULT_NEG_YEAR_LABEL,
5769                                           "calendar.negative_label"));
5770 
5771     for (cf = 0; cf < game.info.calendar_fragments; cf++) {
5772       const char *fname;
5773 
5774       fname = secfile_lookup_str_default(file, NULL, "calendar.fragment_name%d", cf);
5775       if (fname != NULL) {
5776         strncpy(game.info.calendar_fragment_name[cf], fname,
5777                 sizeof(game.info.calendar_fragment_name[cf]));
5778       }
5779     }
5780   }
5781 
5782   if (ok) {
5783     /* section playercolors */
5784     struct rgbcolor *prgbcolor = NULL;
5785     bool color_read = TRUE;
5786 
5787     /* Check if the player list is defined and empty. */
5788     if (playercolor_count() != 0) {
5789       ok = FALSE;
5790     } else {
5791       i = 0;
5792 
5793       while (color_read) {
5794         prgbcolor = NULL;
5795 
5796         color_read = rgbcolor_load(file, &prgbcolor, "playercolors.colorlist%d", i);
5797         if (color_read) {
5798           playercolor_add(prgbcolor);
5799         }
5800 
5801         i++;
5802       }
5803 
5804       if (playercolor_count() == 0) {
5805         ruleset_error(LOG_ERROR, "No player colors defined!");
5806         ok = FALSE;
5807       }
5808 
5809       if (ok) {
5810         fc_assert(game.plr_bg_color == NULL);
5811         if (!rgbcolor_load(file, &game.plr_bg_color, "playercolors.background")) {
5812           ruleset_error(LOG_ERROR, "No background player color defined! (%s)",
5813                         secfile_error());
5814           ok = FALSE;
5815         }
5816       }
5817     }
5818   }
5819 
5820   if (ok) {
5821     /* section: teams */
5822     svec = secfile_lookup_str_vec(file, &teams, "teams.names");
5823     if (team_slot_count() < teams) {
5824       teams = team_slot_count();
5825     }
5826     game.server.ruledit.named_teams = teams;
5827     for (i = 0; i < teams; i++) {
5828       team_slot_set_defined_name(team_slot_by_number(i), svec[i]);
5829     }
5830     free(svec);
5831 
5832     sec = secfile_sections_by_name_prefix(file, DISASTER_SECTION_PREFIX);
5833     nval = (NULL != sec ? section_list_size(sec) : 0);
5834     if (nval > MAX_DISASTER_TYPES) {
5835       int num = nval; /* No "size_t" to printf */
5836 
5837       ruleset_error(LOG_ERROR, "\"%s\": Too many disaster types (%d, max %d)",
5838                     filename, num, MAX_DISASTER_TYPES);
5839       section_list_destroy(sec);
5840       ok = FALSE;
5841     } else {
5842       game.control.num_disaster_types = nval;
5843     }
5844   }
5845 
5846   if (ok) {
5847     disaster_type_iterate(pdis) {
5848       int id = disaster_index(pdis);
5849       int j;
5850       size_t eff_count;
5851       struct requirement_vector *reqs;
5852       const char *sec_name = section_name(section_list_get(sec, id));
5853 
5854       if (!ruleset_load_names(&pdis->name, NULL, file, sec_name)) {
5855         ruleset_error(LOG_ERROR, "\"%s\": Cannot load disaster names",
5856                       filename);
5857         ok = FALSE;
5858         break;
5859       }
5860 
5861       reqs = lookup_req_list(file, sec_name, "reqs", disaster_rule_name(pdis));
5862       if (reqs == NULL) {
5863         ok = FALSE;
5864         break;
5865       }
5866       requirement_vector_copy(&pdis->reqs, reqs);
5867 
5868       pdis->frequency = secfile_lookup_int_default(file, GAME_DEFAULT_DISASTER_FREQ,
5869                                                    "%s.frequency", sec_name);
5870 
5871       svec = secfile_lookup_str_vec(file, &eff_count, "%s.effects", sec_name);
5872 
5873       BV_CLR_ALL(pdis->effects);
5874       for (j = 0; j < eff_count; j++) {
5875         const char *dsval = svec[j];
5876         enum disaster_effect_id effect;
5877 
5878         effect = disaster_effect_id_by_name(dsval, fc_strcasecmp);
5879 
5880         if (!disaster_effect_id_is_valid(effect)) {
5881           ruleset_error(LOG_ERROR,
5882                         "\"%s\" disaster \"%s\": unknown effect \"%s\".",
5883                         filename,
5884                         disaster_rule_name(pdis),
5885                         dsval);
5886           ok = FALSE;
5887           break;
5888         } else {
5889           BV_SET(pdis->effects, effect);
5890         }
5891       }
5892 
5893       free(svec);
5894 
5895       if (!ok) {
5896         break;
5897       }
5898     } disaster_type_iterate_end;
5899     section_list_destroy(sec);
5900   }
5901 
5902   if (ok) {
5903     sec = secfile_sections_by_name_prefix(file, ACHIEVEMENT_SECTION_PREFIX);
5904 
5905     achievements_iterate(pach) {
5906       int id = achievement_index(pach);
5907       const char *sec_name = section_name(section_list_get(sec, id));
5908       const char *typename;
5909       const char *msg;
5910 
5911       typename = secfile_lookup_str_default(file, NULL, "%s.type", sec_name);
5912 
5913       pach->type = achievement_type_by_name(typename, fc_strcasecmp);
5914       if (!achievement_type_is_valid(pach->type)) {
5915         ruleset_error(LOG_ERROR, "Achievement has unknown type \"%s\".",
5916                       typename != NULL ? typename : "(NULL)");
5917         ok = FALSE;
5918       }
5919 
5920       if (ok) {
5921         pach->unique = secfile_lookup_bool_default(file, GAME_DEFAULT_ACH_UNIQUE,
5922                                                    "%s.unique", sec_name);
5923 
5924         pach->value = secfile_lookup_int_default(file, GAME_DEFAULT_ACH_VALUE,
5925                                                  "%s.value", sec_name);
5926         pach->culture = secfile_lookup_int_default(file, 0,
5927                                                    "%s.culture", sec_name);
5928 
5929         msg = secfile_lookup_str_default(file, NULL, "%s.first_msg", sec_name);
5930         if (msg == NULL) {
5931           ruleset_error(LOG_ERROR, "Achievement %s has no first msg!", sec_name);
5932           ok = FALSE;
5933         } else {
5934           pach->first_msg = fc_strdup(msg);
5935         }
5936       }
5937 
5938       if (ok) {
5939         msg = secfile_lookup_str_default(file, NULL, "%s.cons_msg", sec_name);
5940         if (msg == NULL) {
5941           if (!pach->unique) {
5942             ruleset_error(LOG_ERROR, "Achievement %s has no msg for consecutive gainers!", sec_name);
5943             ok = FALSE;
5944           }
5945         } else {
5946           pach->cons_msg = fc_strdup(msg);
5947         }
5948       }
5949 
5950       if (!ok) {
5951         break;
5952       }
5953     } achievements_iterate_end;
5954     section_list_destroy(sec);
5955   }
5956 
5957   if (ok) {
5958     for (i = 0; (name = secfile_lookup_str_default(file, NULL,
5959                                                    "trade.settings%d.type",
5960                                                    i)); i++) {
5961       enum trade_route_type type = trade_route_type_by_name(name);
5962 
5963       if (type == TRT_LAST) {
5964         ruleset_error(LOG_ERROR,
5965                       "\"%s\" unknown trade route type \"%s\".",
5966                       filename, name);
5967         ok = FALSE;
5968       } else {
5969         struct trade_route_settings *set = trade_route_settings_by_type(type);
5970         const char *cancelling;
5971         const char *bonus;
5972 
5973         set->trade_pct = secfile_lookup_int_default(file, 100,
5974                                                     "trade.settings%d.pct", i);
5975         cancelling = secfile_lookup_str_default(file, "Active",
5976                                                 "trade.settings%d.cancelling", i);
5977         set->cancelling = traderoute_cancelling_type_by_name(cancelling);
5978         if (set->cancelling == TRI_LAST) {
5979           ruleset_error(LOG_ERROR,
5980                         "\"%s\" unknown traderoute cancelling type \"%s\".",
5981                         filename, cancelling);
5982           ok = FALSE;
5983         }
5984 
5985         bonus = secfile_lookup_str_default(file, "None", "trade.settings%d.bonus", i);
5986 
5987         set->bonus_type = traderoute_bonus_type_by_name(bonus, fc_strcasecmp);
5988 
5989         if (!traderoute_bonus_type_is_valid(set->bonus_type)) {
5990           ruleset_error(LOG_ERROR,
5991                         "\"%s\" unknown traderoute bonus type \"%s\".",
5992                         filename, bonus);
5993           ok = FALSE;
5994         }
5995       }
5996     }
5997   }
5998 
5999   /* secfile_check_unused() is not here, but only after also settings section
6000    * has been loaded. */
6001 
6002   return ok;
6003 }
6004 
6005 /**************************************************************************
6006   Send the units ruleset information (all individual unit classes) to the
6007   specified connections.
6008 **************************************************************************/
send_ruleset_unit_classes(struct conn_list * dest)6009 static void send_ruleset_unit_classes(struct conn_list *dest)
6010 {
6011   struct packet_ruleset_unit_class packet;
6012 
6013   unit_class_iterate(c) {
6014     packet.id = uclass_number(c);
6015     sz_strlcpy(packet.name, untranslated_name(&c->name));
6016     sz_strlcpy(packet.rule_name, rule_name_get(&c->name));
6017     packet.min_speed = c->min_speed;
6018     packet.hp_loss_pct = c->hp_loss_pct;
6019     packet.hut_behavior = c->hut_behavior;
6020     packet.non_native_def_pct = c->non_native_def_pct;
6021     packet.flags = c->flags;
6022 
6023     PACKET_STRVEC_COMPUTE(packet.helptext, c->helptext);
6024 
6025     lsend_packet_ruleset_unit_class(dest, &packet);
6026   } unit_class_iterate_end;
6027 }
6028 
6029 /**************************************************************************
6030   Send the units ruleset information (all individual units) to the
6031   specified connections.
6032 **************************************************************************/
send_ruleset_units(struct conn_list * dest)6033 static void send_ruleset_units(struct conn_list *dest)
6034 {
6035   struct packet_ruleset_unit packet;
6036   struct packet_ruleset_unit_flag fpacket;
6037   int i;
6038 
6039   for (i = 0; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
6040     const char *flagname;
6041     const char *helptxt;
6042 
6043     fpacket.id = i + UTYF_USER_FLAG_1;
6044 
6045     flagname = unit_type_flag_id_name(i + UTYF_USER_FLAG_1);
6046     if (flagname == NULL) {
6047       fpacket.name[0] = '\0';
6048     } else {
6049       sz_strlcpy(fpacket.name, flagname);
6050     }
6051 
6052     helptxt = unit_type_flag_helptxt(i + UTYF_USER_FLAG_1);
6053     if (helptxt == NULL) {
6054       fpacket.helptxt[0] = '\0';
6055     } else {
6056       sz_strlcpy(fpacket.helptxt, helptxt);
6057     }
6058 
6059     lsend_packet_ruleset_unit_flag(dest, &fpacket);
6060   }
6061 
6062   unit_type_iterate(u) {
6063     packet.id = utype_number(u);
6064     sz_strlcpy(packet.name, untranslated_name(&u->name));
6065     sz_strlcpy(packet.rule_name, rule_name_get(&u->name));
6066     sz_strlcpy(packet.sound_move, u->sound_move);
6067     sz_strlcpy(packet.sound_move_alt, u->sound_move_alt);
6068     sz_strlcpy(packet.sound_fight, u->sound_fight);
6069     sz_strlcpy(packet.sound_fight_alt, u->sound_fight_alt);
6070     sz_strlcpy(packet.graphic_str, u->graphic_str);
6071     sz_strlcpy(packet.graphic_alt, u->graphic_alt);
6072     packet.unit_class_id = uclass_number(utype_class(u));
6073     packet.build_cost = u->build_cost;
6074     packet.pop_cost = u->pop_cost;
6075     packet.attack_strength = u->attack_strength;
6076     packet.defense_strength = u->defense_strength;
6077     packet.move_rate = u->move_rate;
6078     packet.tech_requirement = u->require_advance
6079                               ? advance_number(u->require_advance)
6080                               : advance_count();
6081     packet.impr_requirement = u->need_improvement
6082                               ? improvement_number(u->need_improvement)
6083                               : improvement_count();
6084     packet.gov_requirement = u->need_government
6085                              ? government_number(u->need_government)
6086                              : government_count();
6087     packet.vision_radius_sq = u->vision_radius_sq;
6088     packet.transport_capacity = u->transport_capacity;
6089     packet.hp = u->hp;
6090     packet.firepower = u->firepower;
6091     packet.obsoleted_by = u->obsoleted_by
6092                           ? utype_number(u->obsoleted_by)
6093                           : utype_count();
6094     packet.converted_to = u->converted_to
6095                           ? utype_number(u->converted_to)
6096                           : utype_count();
6097     packet.convert_time = u->convert_time;
6098     packet.fuel = u->fuel;
6099     packet.flags = u->flags;
6100     packet.roles = u->roles;
6101     packet.happy_cost = u->happy_cost;
6102     output_type_iterate(o) {
6103       packet.upkeep[o] = u->upkeep[o];
6104     } output_type_iterate_end;
6105     packet.paratroopers_range = u->paratroopers_range;
6106     packet.paratroopers_mr_req = u->paratroopers_mr_req;
6107     packet.paratroopers_mr_sub = u->paratroopers_mr_sub;
6108     packet.bombard_rate = u->bombard_rate;
6109     packet.city_size = u->city_size;
6110     packet.cargo = u->cargo;
6111     packet.targets = u->targets;
6112     packet.embarks = u->embarks;
6113     packet.disembarks = u->disembarks;
6114 
6115     if (u->veteran == NULL) {
6116       /* Use the default veteran system. */
6117       packet.veteran_levels = 0;
6118     } else {
6119       /* Per unit veteran system definition. */
6120       packet.veteran_levels = utype_veteran_levels(u);
6121 
6122       for (i = 0; i < packet.veteran_levels; i++) {
6123         const struct veteran_level *vlevel = utype_veteran_level(u, i);
6124 
6125         sz_strlcpy(packet.veteran_name[i], untranslated_name(&vlevel->name));
6126         packet.power_fact[i] = vlevel->power_fact;
6127         packet.move_bonus[i] = vlevel->move_bonus;
6128       }
6129     }
6130     PACKET_STRVEC_COMPUTE(packet.helptext, u->helptext);
6131 
6132     lsend_packet_ruleset_unit(dest, &packet);
6133 
6134     combat_bonus_list_iterate(u->bonuses, pbonus) {
6135       struct packet_ruleset_unit_bonus bonuspacket;
6136 
6137       bonuspacket.unit  = packet.id;
6138       bonuspacket.flag  = pbonus->flag;
6139       bonuspacket.type  = pbonus->type;
6140       bonuspacket.value = pbonus->value;
6141       bonuspacket.quiet = pbonus->quiet;
6142 
6143       lsend_packet_ruleset_unit_bonus(dest, &bonuspacket);
6144     } combat_bonus_list_iterate_end;
6145   } unit_type_iterate_end;
6146 }
6147 
6148 /**************************************************************************
6149   Send the specialists ruleset information (all individual specialist
6150   types) to the specified connections.
6151 **************************************************************************/
send_ruleset_specialists(struct conn_list * dest)6152 static void send_ruleset_specialists(struct conn_list *dest)
6153 {
6154   struct packet_ruleset_specialist packet;
6155 
6156   specialist_type_iterate(spec_id) {
6157     struct specialist *s = specialist_by_number(spec_id);
6158     int j;
6159 
6160     packet.id = spec_id;
6161     sz_strlcpy(packet.plural_name, untranslated_name(&s->name));
6162     sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
6163     sz_strlcpy(packet.short_name, untranslated_name(&s->abbreviation));
6164     sz_strlcpy(packet.graphic_alt, s->graphic_alt);
6165     j = 0;
6166     requirement_vector_iterate(&s->reqs, preq) {
6167       packet.reqs[j++] = *preq;
6168     } requirement_vector_iterate_end;
6169     packet.reqs_count = j;
6170 
6171     PACKET_STRVEC_COMPUTE(packet.helptext, s->helptext);
6172 
6173     lsend_packet_ruleset_specialist(dest, &packet);
6174   } specialist_type_iterate_end;
6175 }
6176 
6177 /**************************************************************************
6178   Send the techs ruleset information (all individual advances) to the
6179   specified connections.
6180 **************************************************************************/
send_ruleset_techs(struct conn_list * dest)6181 static void send_ruleset_techs(struct conn_list *dest)
6182 {
6183   struct packet_ruleset_tech packet;
6184   struct packet_ruleset_tech_flag fpacket;
6185   int i;
6186 
6187   for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
6188     const char *flagname;
6189     const char *helptxt;
6190 
6191     fpacket.id = i + TECH_USER_1;
6192 
6193     flagname = tech_flag_id_name_cb(i + TECH_USER_1);
6194     if (flagname == NULL) {
6195       fpacket.name[0] = '\0';
6196     } else {
6197       sz_strlcpy(fpacket.name, flagname);
6198     }
6199 
6200     helptxt = tech_flag_helptxt(i + TECH_USER_1);
6201     if (helptxt == NULL) {
6202       fpacket.helptxt[0] = '\0';
6203     } else {
6204       sz_strlcpy(fpacket.helptxt, helptxt);
6205     }
6206 
6207     lsend_packet_ruleset_tech_flag(dest, &fpacket);
6208   }
6209 
6210   advance_iterate(A_FIRST, a) {
6211     packet.id = advance_number(a);
6212     sz_strlcpy(packet.name, untranslated_name(&a->name));
6213     sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
6214     sz_strlcpy(packet.graphic_str, a->graphic_str);
6215     sz_strlcpy(packet.graphic_alt, a->graphic_alt);
6216 
6217     packet.req[AR_ONE] = a->require[AR_ONE]
6218                          ? advance_number(a->require[AR_ONE])
6219                          : advance_count();
6220     packet.req[AR_TWO] = a->require[AR_TWO]
6221                          ? advance_number(a->require[AR_TWO])
6222                          : advance_count();
6223     packet.root_req = a->require[AR_ROOT]
6224                       ? advance_number(a->require[AR_ROOT])
6225                       : advance_count();
6226 
6227     packet.flags = a->flags;
6228     packet.cost = a->cost;
6229     packet.num_reqs = a->num_reqs;
6230     PACKET_STRVEC_COMPUTE(packet.helptext, a->helptext);
6231 
6232     lsend_packet_ruleset_tech(dest, &packet);
6233   } advance_iterate_end;
6234 }
6235 
6236 /**************************************************************************
6237   Send the buildings ruleset information (all individual improvements and
6238   wonders) to the specified connections.
6239 **************************************************************************/
send_ruleset_buildings(struct conn_list * dest)6240 static void send_ruleset_buildings(struct conn_list *dest)
6241 {
6242   improvement_iterate(b) {
6243     struct packet_ruleset_building packet;
6244     int j;
6245 
6246     packet.id = improvement_number(b);
6247     packet.genus = b->genus;
6248     sz_strlcpy(packet.name, untranslated_name(&b->name));
6249     sz_strlcpy(packet.rule_name, rule_name_get(&b->name));
6250     sz_strlcpy(packet.graphic_str, b->graphic_str);
6251     sz_strlcpy(packet.graphic_alt, b->graphic_alt);
6252     j = 0;
6253     requirement_vector_iterate(&b->reqs, preq) {
6254       packet.reqs[j++] = *preq;
6255     } requirement_vector_iterate_end;
6256     packet.reqs_count = j;
6257     j = 0;
6258     requirement_vector_iterate(&b->obsolete_by, pobs) {
6259       packet.obs_reqs[j++] = *pobs;
6260     } requirement_vector_iterate_end;
6261     packet.obs_count = j;
6262     packet.build_cost = b->build_cost;
6263     packet.upkeep = b->upkeep;
6264     packet.sabotage = b->sabotage;
6265     packet.flags = b->flags;
6266     sz_strlcpy(packet.soundtag, b->soundtag);
6267     sz_strlcpy(packet.soundtag_alt, b->soundtag_alt);
6268     PACKET_STRVEC_COMPUTE(packet.helptext, b->helptext);
6269 
6270     lsend_packet_ruleset_building(dest, &packet);
6271   } improvement_iterate_end;
6272 }
6273 
6274 /**************************************************************************
6275   Send the terrain ruleset information (terrain_control, and the individual
6276   terrain types) to the specified connections.
6277 **************************************************************************/
send_ruleset_terrain(struct conn_list * dest)6278 static void send_ruleset_terrain(struct conn_list *dest)
6279 {
6280   struct packet_ruleset_terrain packet;
6281   struct packet_ruleset_terrain_flag fpacket;
6282   int i;
6283 
6284   lsend_packet_ruleset_terrain_control(dest, &terrain_control);
6285 
6286   for (i = 0; i < MAX_NUM_USER_TER_FLAGS; i++) {
6287     const char *flagname;
6288     const char *helptxt;
6289 
6290     fpacket.id = i + TER_USER_1;
6291 
6292     flagname = terrain_flag_id_name_cb(i + TER_USER_1);
6293     if (flagname == NULL) {
6294       fpacket.name[0] = '\0';
6295     } else {
6296       sz_strlcpy(fpacket.name, flagname);
6297     }
6298 
6299     helptxt = terrain_flag_helptxt(i + TER_USER_1);
6300     if (helptxt == NULL) {
6301       fpacket.helptxt[0] = '\0';
6302     } else {
6303       sz_strlcpy(fpacket.helptxt, helptxt);
6304     }
6305 
6306     lsend_packet_ruleset_terrain_flag(dest, &fpacket);
6307   }
6308 
6309   terrain_type_iterate(pterrain) {
6310     struct resource **r;
6311 
6312     packet.id = terrain_number(pterrain);
6313     packet.tclass = pterrain->tclass;
6314     packet.native_to = pterrain->native_to;
6315 
6316     sz_strlcpy(packet.name, untranslated_name(&pterrain->name));
6317     sz_strlcpy(packet.rule_name, rule_name_get(&pterrain->name));
6318     sz_strlcpy(packet.graphic_str, pterrain->graphic_str);
6319     sz_strlcpy(packet.graphic_alt, pterrain->graphic_alt);
6320 
6321     packet.movement_cost = pterrain->movement_cost;
6322     packet.defense_bonus = pterrain->defense_bonus;
6323 
6324     output_type_iterate(o) {
6325       packet.output[o] = pterrain->output[o];
6326     } output_type_iterate_end;
6327 
6328     packet.num_resources = 0;
6329     for (r = pterrain->resources; *r; r++) {
6330       packet.resources[packet.num_resources++] = resource_number(*r);
6331     }
6332 
6333     output_type_iterate(o) {
6334       packet.road_output_incr_pct[o] = pterrain->road_output_incr_pct[o];
6335     } output_type_iterate_end;
6336 
6337     packet.base_time = pterrain->base_time;
6338     packet.road_time = pterrain->road_time;
6339 
6340     packet.irrigation_result = (pterrain->irrigation_result
6341 				? terrain_number(pterrain->irrigation_result)
6342 				: terrain_count());
6343     packet.irrigation_food_incr = pterrain->irrigation_food_incr;
6344     packet.irrigation_time = pterrain->irrigation_time;
6345 
6346     packet.mining_result = (pterrain->mining_result
6347 			    ? terrain_number(pterrain->mining_result)
6348 			    : terrain_count());
6349     packet.mining_shield_incr = pterrain->mining_shield_incr;
6350     packet.mining_time = pterrain->mining_time;
6351 
6352     packet.animal = (pterrain->animal == NULL ? -1 : utype_number(pterrain->animal));
6353     packet.transform_result = (pterrain->transform_result
6354 			       ? terrain_number(pterrain->transform_result)
6355 			       : terrain_count());
6356     packet.pillage_time = pterrain->pillage_time;
6357     packet.transform_time = pterrain->transform_time;
6358     packet.clean_pollution_time = pterrain->clean_pollution_time;
6359     packet.clean_fallout_time = pterrain->clean_fallout_time;
6360 
6361     packet.flags = pterrain->flags;
6362 
6363     packet.color_red = pterrain->rgb->r;
6364     packet.color_green = pterrain->rgb->g;
6365     packet.color_blue = pterrain->rgb->b;
6366 
6367     PACKET_STRVEC_COMPUTE(packet.helptext, pterrain->helptext);
6368 
6369     lsend_packet_ruleset_terrain(dest, &packet);
6370   } terrain_type_iterate_end;
6371 }
6372 
6373 /****************************************************************************
6374   Send the resource ruleset information to the specified connections.
6375 ****************************************************************************/
send_ruleset_resources(struct conn_list * dest)6376 static void send_ruleset_resources(struct conn_list *dest)
6377 {
6378   struct packet_ruleset_resource packet;
6379 
6380   resource_type_iterate (presource) {
6381     packet.id = resource_number(presource);
6382 
6383     sz_strlcpy(packet.name, untranslated_name(&presource->name));
6384     sz_strlcpy(packet.rule_name, rule_name_get(&presource->name));
6385     sz_strlcpy(packet.graphic_str, presource->graphic_str);
6386     sz_strlcpy(packet.graphic_alt, presource->graphic_alt);
6387 
6388     output_type_iterate(o) {
6389       packet.output[o] = presource->output[o];
6390     } output_type_iterate_end;
6391 
6392     lsend_packet_ruleset_resource(dest, &packet);
6393   } resource_type_iterate_end;
6394 }
6395 
6396 /**************************************************************************
6397   Send the extra ruleset information (all individual extra types) to the
6398   specified connections.
6399 **************************************************************************/
send_ruleset_extras(struct conn_list * dest)6400 static void send_ruleset_extras(struct conn_list *dest)
6401 {
6402   struct packet_ruleset_extra packet;
6403 
6404   extra_type_iterate(e) {
6405     int j;
6406 
6407     packet.id = extra_number(e);
6408     sz_strlcpy(packet.name, untranslated_name(&e->name));
6409     sz_strlcpy(packet.rule_name, rule_name_get(&e->name));
6410 
6411     packet.category = e->category;
6412     packet.causes = e->causes;
6413     packet.rmcauses = e->rmcauses;
6414 
6415     sz_strlcpy(packet.activity_gfx, e->activity_gfx);
6416     sz_strlcpy(packet.act_gfx_alt, e->act_gfx_alt);
6417     sz_strlcpy(packet.act_gfx_alt2, e->act_gfx_alt2);
6418     sz_strlcpy(packet.rmact_gfx, e->rmact_gfx);
6419     sz_strlcpy(packet.rmact_gfx_alt, e->rmact_gfx_alt);
6420     sz_strlcpy(packet.graphic_str, e->graphic_str);
6421     sz_strlcpy(packet.graphic_alt, e->graphic_alt);
6422 
6423     j = 0;
6424     requirement_vector_iterate(&e->reqs, preq) {
6425       packet.reqs[j++] = *preq;
6426     } requirement_vector_iterate_end;
6427     packet.reqs_count = j;
6428 
6429     j = 0;
6430     requirement_vector_iterate(&e->rmreqs, preq) {
6431       packet.rmreqs[j++] = *preq;
6432     } requirement_vector_iterate_end;
6433     packet.rmreqs_count = j;
6434 
6435     packet.buildable = e->buildable;
6436     packet.build_time = e->build_time;
6437     packet.build_time_factor = e->build_time_factor;
6438     packet.removal_time = e->removal_time;
6439     packet.removal_time_factor = e->removal_time_factor;
6440     packet.defense_bonus = e->defense_bonus;
6441 
6442     packet.native_to = e->native_to;
6443 
6444     packet.flags = e->flags;
6445     packet.hidden_by = e->hidden_by;
6446     packet.conflicts = e->conflicts;
6447 
6448     PACKET_STRVEC_COMPUTE(packet.helptext, e->helptext);
6449 
6450     lsend_packet_ruleset_extra(dest, &packet);
6451   } extra_type_iterate_end;
6452 }
6453 
6454 /**************************************************************************
6455   Send the base ruleset information (all individual base types) to the
6456   specified connections.
6457 **************************************************************************/
send_ruleset_bases(struct conn_list * dest)6458 static void send_ruleset_bases(struct conn_list *dest)
6459 {
6460   extra_type_by_cause_iterate(EC_BASE, pextra) {
6461     struct base_type *b = extra_base_get(pextra);
6462     struct packet_ruleset_base packet;
6463 
6464     packet.id = base_number(b);
6465 
6466     packet.gui_type = b->gui_type;
6467     packet.border_sq = b->border_sq;
6468     packet.vision_main_sq = b->vision_main_sq;
6469     packet.vision_invis_sq = b->vision_invis_sq;
6470 
6471     packet.flags = b->flags;
6472 
6473     lsend_packet_ruleset_base(dest, &packet);
6474   } extra_type_by_cause_iterate_end;
6475 }
6476 
6477 /**************************************************************************
6478   Send the road ruleset information (all individual road types) to the
6479   specified connections.
6480 **************************************************************************/
send_ruleset_roads(struct conn_list * dest)6481 static void send_ruleset_roads(struct conn_list *dest)
6482 {
6483   struct packet_ruleset_road packet;
6484 
6485   extra_type_by_cause_iterate(EC_ROAD, pextra) {
6486     struct road_type *r = extra_road_get(pextra);
6487     int j;
6488 
6489     packet.id = road_number(r);
6490 
6491     j = 0;
6492     requirement_vector_iterate(&r->first_reqs, preq) {
6493       packet.first_reqs[j++] = *preq;
6494     } requirement_vector_iterate_end;
6495     packet.first_reqs_count = j;
6496 
6497     packet.move_cost = r->move_cost;
6498     packet.move_mode = r->move_mode;
6499 
6500     output_type_iterate(o) {
6501       packet.tile_incr_const[o] = r->tile_incr_const[o];
6502       packet.tile_incr[o] = r->tile_incr[o];
6503       packet.tile_bonus[o] = r->tile_bonus[o];
6504     } output_type_iterate_end;
6505 
6506     packet.compat = r->compat;
6507 
6508     packet.integrates = r->integrates;
6509     packet.flags = r->flags;
6510 
6511     lsend_packet_ruleset_road(dest, &packet);
6512   } extra_type_by_cause_iterate_end;
6513 }
6514 
6515 /**************************************************************************
6516   Send the disaster ruleset information (all individual disaster types) to the
6517   specified connections.
6518 **************************************************************************/
send_ruleset_disasters(struct conn_list * dest)6519 static void send_ruleset_disasters(struct conn_list *dest)
6520 {
6521   struct packet_ruleset_disaster packet;
6522 
6523   disaster_type_iterate(d) {
6524     int j;
6525     packet.id = disaster_number(d);
6526 
6527     sz_strlcpy(packet.name, untranslated_name(&d->name));
6528     sz_strlcpy(packet.rule_name, rule_name_get(&d->name));
6529 
6530     j = 0;
6531     requirement_vector_iterate(&d->reqs, preq) {
6532       packet.reqs[j++] = *preq;
6533     } requirement_vector_iterate_end;
6534     packet.reqs_count = j;
6535 
6536     packet.frequency = d->frequency;
6537 
6538     packet.effects = d->effects;
6539 
6540     lsend_packet_ruleset_disaster(dest, &packet);
6541   } disaster_type_iterate_end;
6542 }
6543 
6544 /**************************************************************************
6545   Send the achievement ruleset information (all individual achievement types)
6546   to the specified connections.
6547 **************************************************************************/
send_ruleset_achievements(struct conn_list * dest)6548 static void send_ruleset_achievements(struct conn_list *dest)
6549 {
6550   struct packet_ruleset_achievement packet;
6551 
6552   achievements_iterate(a) {
6553     packet.id = achievement_number(a);
6554 
6555     sz_strlcpy(packet.name, untranslated_name(&a->name));
6556     sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
6557 
6558     packet.type = a->type;
6559     packet.unique = a->unique;
6560     packet.value = a->value;
6561 
6562     lsend_packet_ruleset_achievement(dest, &packet);
6563   } achievements_iterate_end;
6564 }
6565 
6566 /**************************************************************************
6567   Send action ruleset information to the specified connections.
6568 **************************************************************************/
send_ruleset_actions(struct conn_list * dest)6569 static void send_ruleset_actions(struct conn_list *dest)
6570 {
6571   struct packet_ruleset_action packet;
6572 
6573   action_iterate(act) {
6574     packet.id = act;
6575     sz_strlcpy(packet.ui_name, action_by_number(act)->ui_name);
6576     packet.quiet = action_by_number(act)->quiet;
6577 
6578     lsend_packet_ruleset_action(dest, &packet);
6579   } action_iterate_end;
6580 }
6581 
6582 /**************************************************************************
6583   Send the action enabler ruleset information to the specified connections.
6584 **************************************************************************/
send_ruleset_action_enablers(struct conn_list * dest)6585 static void send_ruleset_action_enablers(struct conn_list *dest)
6586 {
6587   int counter;
6588   struct packet_ruleset_action_enabler packet;
6589 
6590   action_enablers_iterate(enabler) {
6591     packet.enabled_action = enabler->action;
6592 
6593     counter = 0;
6594     requirement_vector_iterate(&enabler->actor_reqs, req) {
6595       packet.actor_reqs[counter++] = *req;
6596     } requirement_vector_iterate_end;
6597     packet.actor_reqs_count = counter;
6598 
6599     counter = 0;
6600     requirement_vector_iterate(&enabler->target_reqs, req) {
6601       packet.target_reqs[counter++] = *req;
6602     } requirement_vector_iterate_end;
6603     packet.target_reqs_count = counter;
6604 
6605     lsend_packet_ruleset_action_enabler(dest, &packet);
6606   } action_enablers_iterate_end;
6607 }
6608 
6609 /**************************************************************************
6610   Send the trade route types ruleset information (all individual
6611   trade route types) to the specified connections.
6612 **************************************************************************/
send_ruleset_trade_routes(struct conn_list * dest)6613 static void send_ruleset_trade_routes(struct conn_list *dest)
6614 {
6615   struct packet_ruleset_trade packet;
6616   enum trade_route_type type;
6617 
6618   for (type = TRT_NATIONAL; type < TRT_LAST; type++) {
6619     struct trade_route_settings *set = trade_route_settings_by_type(type);
6620 
6621     packet.id = type;
6622     packet.trade_pct = set->trade_pct;
6623     packet.cancelling = set->cancelling;
6624     packet.bonus_type = set->bonus_type;
6625 
6626     lsend_packet_ruleset_trade(dest, &packet);
6627   }
6628 }
6629 
6630 /**************************************************************************
6631   Send the government ruleset information to the specified connections.
6632   One packet per government type, and for each type one per ruler title.
6633 **************************************************************************/
send_ruleset_governments(struct conn_list * dest)6634 static void send_ruleset_governments(struct conn_list *dest)
6635 {
6636   struct packet_ruleset_government gov;
6637   struct packet_ruleset_government_ruler_title title;
6638   int j;
6639 
6640   governments_iterate(g) {
6641     /* send one packet_government */
6642     gov.id = government_number(g);
6643 
6644     j = 0;
6645     requirement_vector_iterate(&g->reqs, preq) {
6646       gov.reqs[j++] = *preq;
6647     } requirement_vector_iterate_end;
6648     gov.reqs_count = j;
6649 
6650     sz_strlcpy(gov.name, untranslated_name(&g->name));
6651     sz_strlcpy(gov.rule_name, rule_name_get(&g->name));
6652     sz_strlcpy(gov.graphic_str, g->graphic_str);
6653     sz_strlcpy(gov.graphic_alt, g->graphic_alt);
6654     PACKET_STRVEC_COMPUTE(gov.helptext, g->helptext);
6655 
6656     lsend_packet_ruleset_government(dest, &gov);
6657 
6658     /* Send one packet_government_ruler_title per ruler title. */
6659     ruler_titles_iterate(government_ruler_titles(g), pruler_title) {
6660       const struct nation_type *pnation = ruler_title_nation(pruler_title);
6661 
6662       title.gov = government_number(g);
6663       title.nation = pnation ? nation_number(pnation) : nation_count();
6664       sz_strlcpy(title.male_title,
6665                  ruler_title_male_untranslated_name(pruler_title));
6666       sz_strlcpy(title.female_title,
6667                  ruler_title_female_untranslated_name(pruler_title));
6668       lsend_packet_ruleset_government_ruler_title(dest, &title);
6669     } ruler_titles_iterate_end;
6670   } governments_iterate_end;
6671 }
6672 
6673 /**************************************************************************
6674   Send the nations ruleset information (info on each nation) to the
6675   specified connections.
6676 **************************************************************************/
send_ruleset_nations(struct conn_list * dest)6677 static void send_ruleset_nations(struct conn_list *dest)
6678 {
6679   struct packet_ruleset_nation_sets sets_packet;
6680   struct packet_ruleset_nation_groups groups_packet;
6681   struct packet_ruleset_nation packet;
6682   int i;
6683 
6684   sets_packet.nsets = nation_set_count();
6685   i = 0;
6686   nation_sets_iterate(pset) {
6687     sz_strlcpy(sets_packet.names[i], nation_set_untranslated_name(pset));
6688     sz_strlcpy(sets_packet.rule_names[i], nation_set_rule_name(pset));
6689     sz_strlcpy(sets_packet.descriptions[i], nation_set_description(pset));
6690     i++;
6691   } nation_sets_iterate_end;
6692   lsend_packet_ruleset_nation_sets(dest, &sets_packet);
6693 
6694   groups_packet.ngroups = nation_group_count();
6695   i = 0;
6696   nation_groups_iterate(pgroup) {
6697     sz_strlcpy(groups_packet.groups[i],
6698                nation_group_untranslated_name(pgroup));
6699     groups_packet.hidden[i] = pgroup->hidden;
6700     i++;
6701   } nation_groups_iterate_end;
6702   lsend_packet_ruleset_nation_groups(dest, &groups_packet);
6703 
6704   nations_iterate(n) {
6705     packet.id = nation_number(n);
6706     if (n->translation_domain == NULL) {
6707       packet.translation_domain[0] = '\0';
6708     } else {
6709       sz_strlcpy(packet.translation_domain, n->translation_domain);
6710     }
6711     sz_strlcpy(packet.adjective, untranslated_name(&n->adjective));
6712     sz_strlcpy(packet.rule_name, rule_name_get(&n->adjective));
6713     sz_strlcpy(packet.noun_plural, untranslated_name(&n->noun_plural));
6714     sz_strlcpy(packet.graphic_str, n->flag_graphic_str);
6715     sz_strlcpy(packet.graphic_alt, n->flag_graphic_alt);
6716 
6717     i = 0;
6718     nation_leader_list_iterate(nation_leaders(n), pleader) {
6719       sz_strlcpy(packet.leader_name[i], nation_leader_name(pleader));
6720       packet.leader_is_male[i] = nation_leader_is_male(pleader);
6721       i++;
6722     } nation_leader_list_iterate_end;
6723     packet.leader_count = i;
6724 
6725     packet.style = style_number(n->style);
6726     packet.is_playable = n->is_playable;
6727     packet.barbarian_type = n->barb_type;
6728 
6729     sz_strlcpy(packet.legend, n->legend);
6730 
6731     i = 0;
6732     nation_set_list_iterate(n->sets, pset) {
6733       packet.sets[i++] = nation_set_number(pset);
6734     } nation_set_list_iterate_end;
6735     packet.nsets = i;
6736 
6737     i = 0;
6738     nation_group_list_iterate(n->groups, pgroup) {
6739       packet.groups[i++] = nation_group_number(pgroup);
6740     } nation_group_list_iterate_end;
6741     packet.ngroups = i;
6742 
6743     packet.init_government_id = n->init_government
6744       ? government_number(n->init_government) : government_count();
6745     fc_assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n->init_techs));
6746     for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
6747       packet.init_techs[i] = n->init_techs[i];
6748     }
6749     fc_assert(ARRAY_SIZE(packet.init_units) == ARRAY_SIZE(n->init_units));
6750     for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
6751       const struct unit_type *t = n->init_units[i];
6752       packet.init_units[i] = t ? utype_number(t) : U_LAST;
6753     }
6754     fc_assert(ARRAY_SIZE(packet.init_buildings)
6755               == ARRAY_SIZE(n->init_buildings));
6756     for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
6757       /* Impr_type_id to int */
6758       packet.init_buildings[i] = n->init_buildings[i];
6759     }
6760 
6761     lsend_packet_ruleset_nation(dest, &packet);
6762   } nations_iterate_end;
6763 
6764   /* Send initial values of is_pickable */
6765   send_nation_availability(dest, FALSE);
6766 }
6767 
6768 /**************************************************************************
6769   Send the nation style ruleset information (each style) to the specified
6770   connections.
6771 **************************************************************************/
send_ruleset_styles(struct conn_list * dest)6772 static void send_ruleset_styles(struct conn_list *dest)
6773 {
6774   struct packet_ruleset_style packet;
6775 
6776   styles_iterate(s) {
6777     packet.id = style_index(s);
6778     sz_strlcpy(packet.name, untranslated_name(&s->name));
6779     sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
6780 
6781     lsend_packet_ruleset_style(dest, &packet);
6782   } styles_iterate_end;
6783 }
6784 
6785 /**************************************************************************
6786   Send the multiplier ruleset information to the specified
6787   connections.
6788 **************************************************************************/
send_ruleset_multipliers(struct conn_list * dest)6789 static void send_ruleset_multipliers(struct conn_list *dest)
6790 {
6791   char helptext[MAX_LEN_PACKET];
6792 
6793   multipliers_iterate(pmul) {
6794     PACKET_STRVEC_COMPUTE(helptext, pmul->helptext);
6795 
6796     dlsend_packet_ruleset_multiplier(dest, multiplier_number(pmul),
6797                                      pmul->start, pmul->stop,
6798                                      pmul->step, pmul->def,
6799                                      pmul->offset, pmul->factor,
6800                                      untranslated_name(&pmul->name),
6801                                      rule_name_get(&pmul->name),
6802                                      helptext);
6803   } multipliers_iterate_end;
6804 }
6805 
6806 /**************************************************************************
6807   Send the city-style ruleset information (each style) to the specified
6808   connections.
6809 **************************************************************************/
send_ruleset_cities(struct conn_list * dest)6810 static void send_ruleset_cities(struct conn_list *dest)
6811 {
6812   struct packet_ruleset_city city_p;
6813   int k, j;
6814 
6815   for (k = 0; k < game.control.styles_count; k++) {
6816     city_p.style_id = k;
6817 
6818     j = 0;
6819     requirement_vector_iterate(&city_styles[k].reqs, preq) {
6820       city_p.reqs[j++] = *preq;
6821     } requirement_vector_iterate_end;
6822     city_p.reqs_count = j;
6823 
6824     sz_strlcpy(city_p.name, untranslated_name(&city_styles[k].name));
6825     sz_strlcpy(city_p.rule_name, rule_name_get(&city_styles[k].name));
6826     sz_strlcpy(city_p.graphic, city_styles[k].graphic);
6827     sz_strlcpy(city_p.graphic_alt, city_styles[k].graphic_alt);
6828     sz_strlcpy(city_p.citizens_graphic, city_styles[k].citizens_graphic);
6829     sz_strlcpy(city_p.citizens_graphic_alt,
6830                city_styles[k].citizens_graphic_alt);
6831 
6832     lsend_packet_ruleset_city(dest, &city_p);
6833   }
6834 }
6835 
6836 /**************************************************************************
6837   Send the music-style ruleset information (each style) to the specified
6838   connections.
6839 **************************************************************************/
send_ruleset_musics(struct conn_list * dest)6840 static void send_ruleset_musics(struct conn_list *dest)
6841 {
6842   struct packet_ruleset_music packet;
6843 
6844   music_styles_iterate(pmus) {
6845     int j;
6846 
6847     packet.id = pmus->id;
6848 
6849     sz_strlcpy(packet.music_peaceful, pmus->music_peaceful);
6850     sz_strlcpy(packet.music_combat, pmus->music_combat);
6851 
6852     j = 0;
6853     requirement_vector_iterate(&(pmus->reqs), preq) {
6854       packet.reqs[j++] = *preq;
6855     } requirement_vector_iterate_end;
6856     packet.reqs_count = j;
6857 
6858     lsend_packet_ruleset_music(dest, &packet);
6859   } music_styles_iterate_end;
6860 }
6861 
6862 /**************************************************************************
6863   Send information in packet_ruleset_game (miscellaneous rules) to the
6864   specified connections.
6865 **************************************************************************/
send_ruleset_game(struct conn_list * dest)6866 static void send_ruleset_game(struct conn_list *dest)
6867 {
6868   struct packet_ruleset_game misc_p;
6869   int i;
6870 
6871   fc_assert_ret(game.veteran != NULL);
6872 
6873   /* Per unit veteran system definition. */
6874   misc_p.veteran_levels = game.veteran->levels;
6875 
6876   for (i = 0; i < misc_p.veteran_levels; i++) {
6877     const struct veteran_level *vlevel = game.veteran->definitions + i;
6878 
6879     sz_strlcpy(misc_p.veteran_name[i], untranslated_name(&vlevel->name));
6880     misc_p.power_fact[i] = vlevel->power_fact;
6881     misc_p.move_bonus[i] = vlevel->move_bonus;
6882   }
6883 
6884   fc_assert(sizeof(misc_p.global_init_techs)
6885             == sizeof(game.rgame.global_init_techs));
6886   fc_assert(ARRAY_SIZE(misc_p.global_init_techs)
6887             == ARRAY_SIZE(game.rgame.global_init_techs));
6888   memcpy(misc_p.global_init_techs, game.rgame.global_init_techs,
6889          sizeof(misc_p.global_init_techs));
6890 
6891   fc_assert(ARRAY_SIZE(misc_p.global_init_buildings)
6892             == ARRAY_SIZE(game.rgame.global_init_buildings));
6893   for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
6894     /* Impr_type_id to int */
6895     misc_p.global_init_buildings[i] =
6896       game.rgame.global_init_buildings[i];
6897   }
6898 
6899   misc_p.default_specialist = DEFAULT_SPECIALIST;
6900 
6901   fc_assert_ret(game.plr_bg_color != NULL);
6902 
6903   misc_p.background_red = game.plr_bg_color->r;
6904   misc_p.background_green = game.plr_bg_color->g;
6905   misc_p.background_blue = game.plr_bg_color->b;
6906 
6907   lsend_packet_ruleset_game(dest, &misc_p);
6908 }
6909 
6910 /**************************************************************************
6911   Send all team names defined in the ruleset file(s) to the
6912   specified connections.
6913 **************************************************************************/
send_ruleset_team_names(struct conn_list * dest)6914 static void send_ruleset_team_names(struct conn_list *dest)
6915 {
6916   struct packet_team_name_info team_name_info_p;
6917 
6918   team_slots_iterate(tslot) {
6919     const char *name = team_slot_defined_name(tslot);
6920 
6921     if (NULL == name) {
6922       /* End of defined names. */
6923       break;
6924     }
6925 
6926     team_name_info_p.team_id = team_slot_index(tslot);
6927     sz_strlcpy(team_name_info_p.team_name, name);
6928 
6929     lsend_packet_team_name_info(dest, &team_name_info_p);
6930   } team_slots_iterate_end;
6931 }
6932 
6933 /**************************************************************************
6934   Make it clear to everyone that requested ruleset has not been loaded.
6935 **************************************************************************/
notify_ruleset_fallback(const char * msg)6936 static void notify_ruleset_fallback(const char *msg)
6937 {
6938   notify_conn(NULL, NULL, E_LOG_FATAL, ftc_warning, "%s", msg);
6939 }
6940 
6941 /**************************************************************************
6942   Loads the rulesets.
6943 **************************************************************************/
load_rulesets(const char * restore,bool act,bool buffer_script)6944 bool load_rulesets(const char *restore, bool act, bool buffer_script)
6945 {
6946   if (load_rulesetdir(game.server.rulesetdir, act, buffer_script)) {
6947     return TRUE;
6948   }
6949 
6950   /* Fallback to previous one. */
6951   if (restore != NULL) {
6952     if (load_rulesetdir(restore, act, buffer_script)) {
6953       sz_strlcpy(game.server.rulesetdir, restore);
6954 
6955       notify_ruleset_fallback(_("Ruleset couldn't be loaded. Keeping previous one."));
6956 
6957       /* We're in sane state as restoring previous ruleset succeeded,
6958        * but return failure to indicate that this is not what caller
6959        * wanted. */
6960       return FALSE;
6961     }
6962   }
6963 
6964   /* Fallback to default one, but not if that's what we tried already */
6965   if (strcmp(GAME_DEFAULT_RULESETDIR, game.server.rulesetdir)
6966       && (restore == NULL || strcmp(GAME_DEFAULT_RULESETDIR, restore))) {
6967     if (load_rulesetdir(GAME_DEFAULT_RULESETDIR, act, buffer_script)) {
6968       /* We're in sane state as fallback ruleset loading succeeded,
6969        * but return failure to indicate that this is not what caller
6970        * wanted. */
6971       sz_strlcpy(game.server.rulesetdir, GAME_DEFAULT_RULESETDIR);
6972 
6973       notify_ruleset_fallback(_("Ruleset couldn't be loaded. Switching to default one."));
6974 
6975       return FALSE;
6976     }
6977   }
6978 
6979 #ifdef FREECIV_WEB
6980   log_normal(_("Cannot load any ruleset. Freeciv-web ruleset is available from "
6981                "https://github.com/freeciv/freeciv-web"));
6982 #endif /* FREECIV_WEB */
6983 
6984   /* Cannot load even default ruleset, we're in completely unusable state */
6985   exit(EXIT_FAILURE);
6986 
6987   RETURN_VALUE_AFTER_EXIT(FALSE);
6988 }
6989 
6990 /**************************************************************************
6991   destroy secfile. Handle NULL parameter gracefully.
6992 **************************************************************************/
nullcheck_secfile_destroy(struct section_file * file)6993 static void nullcheck_secfile_destroy(struct section_file *file)
6994 {
6995   if (file != NULL) {
6996     secfile_destroy(file);
6997   }
6998 }
6999 
7000 /**************************************************************************
7001   Completely deinitialize ruleset system. Server is not in usable
7002   state after this.
7003 **************************************************************************/
rulesets_deinit(void)7004 void rulesets_deinit(void)
7005 {
7006   script_server_free();
7007   requirement_vector_free(&reqs_list);
7008 }
7009 
7010 /**************************************************************************
7011   Loads the rulesets from directory.
7012   This may be called more than once and it will free any stale data.
7013 **************************************************************************/
load_rulesetdir(const char * rsdir,bool act,bool buffer_script)7014 static bool load_rulesetdir(const char *rsdir, bool act, bool buffer_script)
7015 {
7016   struct section_file *techfile, *unitfile, *buildfile, *govfile, *terrfile;
7017   struct section_file *stylefile, *cityfile, *nationfile, *effectfile, *gamefile;
7018   bool ok = TRUE;
7019 
7020   log_normal(_("Loading rulesets."));
7021 
7022   game_ruleset_free();
7023   /* Reset the list of available player colors. */
7024   playercolor_free();
7025   playercolor_init();
7026   game_ruleset_init();
7027 
7028   if (script_buffer != NULL) {
7029     FC_FREE(script_buffer);
7030     script_buffer = NULL;
7031   }
7032 
7033   server.playable_nations = 0;
7034 
7035   techfile = openload_ruleset_file("techs", rsdir);
7036   buildfile = openload_ruleset_file("buildings", rsdir);
7037   govfile = openload_ruleset_file("governments", rsdir);
7038   unitfile = openload_ruleset_file("units", rsdir);
7039   terrfile = openload_ruleset_file("terrain", rsdir);
7040   stylefile = openload_ruleset_file("styles", rsdir);
7041   cityfile = openload_ruleset_file("cities", rsdir);
7042   nationfile = openload_ruleset_file("nations", rsdir);
7043   effectfile = openload_ruleset_file("effects", rsdir);
7044   gamefile = openload_ruleset_file("game", rsdir);
7045 
7046   if (techfile == NULL
7047       || buildfile  == NULL
7048       || govfile    == NULL
7049       || unitfile   == NULL
7050       || terrfile   == NULL
7051       || stylefile  == NULL
7052       || cityfile   == NULL
7053       || nationfile == NULL
7054       || effectfile == NULL
7055       || gamefile == NULL) {
7056     ok = FALSE;
7057   }
7058 
7059   if (ok) {
7060     ok = load_game_names(gamefile)
7061       && load_tech_names(techfile)
7062       && load_building_names(buildfile)
7063       && load_government_names(govfile)
7064       && load_unit_names(unitfile)
7065       && load_terrain_names(terrfile)
7066       && load_style_names(stylefile)
7067       && load_nation_names(nationfile);
7068   }
7069 
7070   if (ok) {
7071     ok = load_ruleset_techs(techfile);
7072   }
7073   if (ok) {
7074     ok = load_ruleset_styles(stylefile);
7075   }
7076   if (ok) {
7077     ok = load_ruleset_cities(cityfile);
7078   }
7079   if (ok) {
7080     ok = load_ruleset_governments(govfile);
7081   }
7082   if (ok) {
7083     ok = load_ruleset_terrain(terrfile);  /* terrain must precede nations and units */
7084   }
7085   if (ok) {
7086     ok = load_ruleset_units(unitfile);
7087   }
7088   if (ok) {
7089     ok = load_ruleset_buildings(buildfile);
7090   }
7091   if (ok) {
7092     ok = load_ruleset_nations(nationfile);
7093   }
7094   if (ok) {
7095     ok = load_ruleset_effects(effectfile);
7096   }
7097   if (ok) {
7098     ok = load_ruleset_game(gamefile, act);
7099   }
7100 
7101   if (ok) {
7102     /* Init nations we just loaded. */
7103     update_nations_with_startpos();
7104 
7105     /* Needed by role_unit_precalcs(). */
7106     unit_type_action_cache_init();
7107 
7108     /* Prepare caches we want to sanity check. */
7109     role_unit_precalcs();
7110     road_integrators_cache_init();
7111 
7112     ok = sanity_check_ruleset_data();
7113   }
7114 
7115   if (ok) {
7116     /* Only load settings for a sane ruleset */
7117     ok = settings_ruleset(gamefile, "settings", act);
7118 
7119     if (ok) {
7120       secfile_check_unused(gamefile);
7121     }
7122   }
7123 
7124   nullcheck_secfile_destroy(techfile);
7125   nullcheck_secfile_destroy(stylefile);
7126   nullcheck_secfile_destroy(cityfile);
7127   nullcheck_secfile_destroy(govfile);
7128   nullcheck_secfile_destroy(terrfile);
7129   nullcheck_secfile_destroy(unitfile);
7130   nullcheck_secfile_destroy(buildfile);
7131   nullcheck_secfile_destroy(nationfile);
7132   nullcheck_secfile_destroy(effectfile);
7133   nullcheck_secfile_destroy(gamefile);
7134 
7135   if (extra_sections) {
7136     free(extra_sections);
7137     extra_sections = NULL;
7138   }
7139   if (base_sections) {
7140     free(base_sections);
7141     base_sections = NULL;
7142   }
7143   if (road_sections) {
7144     free(road_sections);
7145     road_sections = NULL;
7146   }
7147   if (resource_sections) {
7148     free(resource_sections);
7149     resource_sections = NULL;
7150   }
7151   if (terrain_sections) {
7152     free(terrain_sections);
7153     terrain_sections = NULL;
7154   }
7155 
7156   if (ok) {
7157     char **buffer = buffer_script ? &script_buffer : NULL;
7158 
7159     script_server_free();
7160 
7161     script_server_init();
7162 
7163     ok = openload_script_file("script", rsdir, buffer);
7164   }
7165 
7166   if (ok && !buffer_script) {
7167     ok = openload_script_file("default", rsdir, NULL);
7168   }
7169 
7170   if (ok && act) {
7171     /* Populate remaining caches. */
7172     techs_precalc_data();
7173     improvement_feature_cache_init();
7174     unit_class_iterate(pclass) {
7175       set_unit_class_caches(pclass);
7176     } unit_class_iterate_end;
7177     unit_type_iterate(ptype) {
7178       ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
7179       set_unit_type_caches(ptype);
7180     } unit_type_iterate_end;
7181 
7182     /* Build advisors unit class cache corresponding to loaded rulesets */
7183     adv_units_ruleset_init();
7184     CALL_FUNC_EACH_AI(units_ruleset_init);
7185 
7186     /* We may need to adjust the number of AI players
7187      * if the number of available nations changed. */
7188     (void) aifill(game.info.aifill);
7189   }
7190 
7191   return ok;
7192 }
7193 
7194 /**************************************************************************
7195   Reload the game settings saved in the ruleset file.
7196 **************************************************************************/
reload_rulesets_settings(void)7197 bool reload_rulesets_settings(void)
7198 {
7199   struct section_file *file;
7200   bool ok = TRUE;
7201 
7202   file = openload_ruleset_file("game", game.server.rulesetdir);
7203   if (file == NULL) {
7204     ruleset_error(LOG_ERROR, "Could not load game.ruleset:\n%s",
7205                   secfile_error());
7206     ok = FALSE;
7207   }
7208   if (ok) {
7209     settings_ruleset(file, "settings", TRUE);
7210     secfile_destroy(file);
7211   }
7212 
7213   return ok;
7214 }
7215 
7216 /**************************************************************************
7217   Send all ruleset information to the specified connections.
7218 **************************************************************************/
send_rulesets(struct conn_list * dest)7219 void send_rulesets(struct conn_list *dest)
7220 {
7221   conn_list_compression_freeze(dest);
7222 
7223   /* ruleset_control also indicates to client that ruleset sending starts. */
7224   send_ruleset_control(dest);
7225 
7226   send_ruleset_game(dest);
7227   send_ruleset_disasters(dest);
7228   send_ruleset_achievements(dest);
7229   send_ruleset_trade_routes(dest);
7230   send_ruleset_team_names(dest);
7231   send_ruleset_actions(dest);
7232   send_ruleset_action_enablers(dest);
7233   send_ruleset_techs(dest);
7234   send_ruleset_governments(dest);
7235   send_ruleset_unit_classes(dest);
7236   send_ruleset_units(dest);
7237   send_ruleset_specialists(dest);
7238   send_ruleset_resources(dest);
7239   send_ruleset_terrain(dest);
7240   send_ruleset_extras(dest);
7241   send_ruleset_bases(dest);
7242   send_ruleset_roads(dest);
7243   send_ruleset_buildings(dest);
7244   send_ruleset_nations(dest);
7245   send_ruleset_styles(dest);
7246   send_ruleset_cities(dest);
7247   send_ruleset_multipliers(dest);
7248   send_ruleset_musics(dest);
7249   send_ruleset_cache(dest);
7250 
7251   /* Indicate client that all rulesets have now been sent. */
7252   lsend_packet_rulesets_ready(dest);
7253 
7254   /* changed game settings will be send in
7255    * connecthand.c:establish_new_connection() */
7256 
7257   conn_list_compression_thaw(dest);
7258 }
7259