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