From 237515787ff7684902b887b8cbdf26876247c488 Mon Sep 17 00:00:00 2001 From: Dino Date: Mon, 6 Oct 2025 23:22:44 -0400 Subject: [PATCH] #1677 - allow terrain to have > 1 animal --- client/packhand.c | 13 +++++++++--- common/fc_types.h | 1 + common/movement.c | 28 +++++++++++++++++++------ common/networking/packets.def | 3 ++- common/terrain.c | 1 - common/terrain.h | 15 +++++++++++++- data/alien/terrain.ruleset | 18 ++++++++-------- data/civ1/terrain.ruleset | 24 +++++++++++----------- data/civ2/terrain.ruleset | 24 +++++++++++----------- data/civ2civ3/terrain.ruleset | 30 +++++++++++++-------------- data/classic/terrain.ruleset | 30 +++++++++++++-------------- data/goldkeep/terrain.ruleset | 30 +++++++++++++-------------- data/granularity/terrain.ruleset | 14 ++++++------- data/multiplayer/terrain.ruleset | 30 +++++++++++++-------------- data/ruledit/comments-3.4.txt | 2 +- data/sandbox/terrain.ruleset | 30 +++++++++++++-------------- data/stub/terrain.ruleset | 6 +++--- data/webperimental/terrain.ruleset | 30 +++++++++++++-------------- server/animals.c | 11 ++++++++-- server/ruleset/rssanity.c | 9 ++++---- server/ruleset/ruleload.c | 33 +++++++++++++++++++++++++----- tools/ruledit/validity.c | 10 +++++---- tools/ruleutil/rulesave.c | 16 ++++++++++----- 23 files changed, 242 insertions(+), 166 deletions(-) diff --git a/client/packhand.c b/client/packhand.c index ed37707188..fcda1d84aa 100644 --- a/client/packhand.c +++ b/client/packhand.c @@ -4233,11 +4233,18 @@ void handle_ruleset_terrain(const struct packet_ruleset_terrain *p) pterrain->irrigation_time = p->irrigation_time; pterrain->mining_shield_incr = p->mining_shield_incr; pterrain->mining_time = p->mining_time; - if (p->animal < 0) { - pterrain->animal = NULL; + + pterrain->num_animals = p->num_animals; + if (p->num_animals == 0) { + pterrain->animals = nullptr; } else { - pterrain->animal = utype_by_number(p->animal); + pterrain->animals = fc_calloc(p->num_animals, + sizeof(*pterrain->animals)); + for (j = 0; j < p->num_animals; j++) { + pterrain->animals[j] = utype_by_number(p->animals[j]); + } } + pterrain->transform_result = terrain_by_number(p->transform_result); pterrain->transform_time = p->transform_time; pterrain->placing_time = p->placing_time; diff --git a/common/fc_types.h b/common/fc_types.h index d9f20cab9b..e22ce22fa6 100644 --- a/common/fc_types.h +++ b/common/fc_types.h @@ -64,6 +64,7 @@ extern "C" { #define MAX_NUM_STARTPOS_NATIONS 1024 /* Used in the network protocol. */ #define MAX_CALENDAR_FRAGMENTS 52 /* Used in the network protocol. */ #define MAX_NUM_TECH_CLASSES 16 /* Used in the network protocol. */ +#define MAX_NUM_ANIMALS 32 /* Used in the network protocol. */ /* Changing these will probably break network compatibility. */ #define MAX_LEN_NAME 48 diff --git a/common/movement.c b/common/movement.c index 50c9a54f31..b03d1413d6 100644 --- a/common/movement.c +++ b/common/movement.c @@ -704,9 +704,17 @@ unit_move_to_tile_test(const struct civ_map *nmap, } /* 6) */ - if (puowner->ai_common.barbarian_type == ANIMAL_BARBARIAN - && dst_tile->terrain->animal != punittype) { - return MR_ANIMAL_DISALLOWED; + if (puowner->ai_common.barbarian_type == ANIMAL_BARBARIAN) { + bool ok = FALSE; + terrain_animals_iterate(dst_tile->terrain, panimal) { + if (panimal == punittype) { + ok = TRUE; + break; + } + } terrain_animals_iterate_end; + if (!ok) { + return MR_ANIMAL_DISALLOWED; + } } /* 7) */ @@ -824,9 +832,17 @@ unit_teleport_to_tile_test(const struct civ_map *nmap, } /* 2) */ - if (puowner->ai_common.barbarian_type == ANIMAL_BARBARIAN - && dst_tile->terrain->animal != punittype) { - return MR_ANIMAL_DISALLOWED; + if (puowner->ai_common.barbarian_type == ANIMAL_BARBARIAN) { + bool ok = FALSE; + terrain_animals_iterate(dst_tile->terrain, panimal) { + if (panimal == punittype) { + ok = TRUE; + break; + } + } terrain_animals_iterate_end; + if (!ok) { + return MR_ANIMAL_DISALLOWED; + } } /* 3) */ diff --git a/common/networking/packets.def b/common/networking/packets.def index bccaca066a..e16b20aac0 100644 --- a/common/networking/packets.def +++ b/common/networking/packets.def @@ -1736,7 +1736,8 @@ PACKET_RULESET_TERRAIN = 151; sc, lsend UINT8 mining_shield_incr; UINT8 mining_time; - SINT16 animal; + UINT8 num_animals; + SINT16 animals[MAX_NUM_ANIMALS:num_animals]; TERRAIN transform_result; UINT8 transform_time; diff --git a/common/terrain.c b/common/terrain.c index 08f3ad9031..b9866304e2 100644 --- a/common/terrain.c +++ b/common/terrain.c @@ -51,7 +51,6 @@ void terrains_init(void) civ_terrains[i].ruledit_disabled = FALSE; civ_terrains[i].ruledit_dlg = nullptr; civ_terrains[i].rgb = nullptr; - civ_terrains[i].animal = nullptr; for (j = 0; j < MAX_EXTRA_TYPES; j++) { civ_terrains[i].extra_removal_times[j] = 0; diff --git a/common/terrain.h b/common/terrain.h index a1c2e1d119..13129ff195 100644 --- a/common/terrain.h +++ b/common/terrain.h @@ -127,7 +127,8 @@ struct terrain { /* Currently only clean times, but named for future */ int extra_removal_times[MAX_EXTRA_TYPES]; - const struct unit_type *animal; + int num_animals; + const struct unit_type **animals; /* May be nullptr if the transformation is impossible. */ struct terrain *warmer_wetter_result, *warmer_drier_result; @@ -295,6 +296,18 @@ const struct terrain *terrain_array_last(void); } \ } +#define terrain_animals_iterate(pterrain, _animal) \ + if (NULL != pterrain && pterrain->num_animals > 0) { \ + int _animal##_index; \ + for (_animal##_index = 0; \ + _animal##_index < pterrain->num_animals; \ + _animal##_index++) { \ + const struct unit_type *_animal = pterrain->animals[_animal##_index]; \ + +#define terrain_animals_iterate_end \ + } \ + } + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/data/alien/terrain.ruleset b/data/alien/terrain.ruleset index b3b4fbb504..3a93a8d781 100644 --- a/data/alien/terrain.ruleset +++ b/data/alien/terrain.ruleset @@ -155,7 +155,7 @@ ocean_resources = TRUE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; doesn''t count for warming ; "yes" -- no change; counts for warming @@ -245,7 +245,7 @@ transform_result = "no" transform_time = 0 placing_time = 0 pillage_time = 0 -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -291,7 +291,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -340,7 +340,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -392,7 +392,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -443,7 +443,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -491,7 +491,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -540,7 +540,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -588,7 +588,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" diff --git a/data/civ1/terrain.ruleset b/data/civ1/terrain.ruleset index 4a4d98ea79..be136bd158 100644 --- a/data/civ1/terrain.ruleset +++ b/data/civ1/terrain.ruleset @@ -149,7 +149,7 @@ igter_cost = 1 ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; does not count for warming ; "yes" -- no change; counts for warming @@ -242,7 +242,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -293,7 +293,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -342,7 +342,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -391,7 +391,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Jungle" warmer_drier_result = "Desert" cooler_wetter_result = "no" @@ -442,7 +442,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Desert" cooler_wetter_result = "Desert" @@ -490,7 +490,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -543,7 +543,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "Desert" @@ -591,7 +591,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -642,7 +642,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Desert" cooler_wetter_result = "Desert" @@ -691,7 +691,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Desert" cooler_wetter_result = "no" @@ -741,7 +741,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "Arctic" diff --git a/data/civ2/terrain.ruleset b/data/civ2/terrain.ruleset index 623ffdc783..43699c40df 100644 --- a/data/civ2/terrain.ruleset +++ b/data/civ2/terrain.ruleset @@ -149,7 +149,7 @@ pythagorean_diagonal = FALSE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; does not count for warming ; "yes" -- no change; counts for warming @@ -242,7 +242,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -289,7 +289,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -338,7 +338,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -388,7 +388,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Jungle" warmer_drier_result = "Desert" cooler_wetter_result = "no" @@ -439,7 +439,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Desert" cooler_wetter_result = "Desert" @@ -487,7 +487,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -536,7 +536,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "Desert" @@ -586,7 +586,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -634,7 +634,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Desert" cooler_wetter_result = "Desert" @@ -684,7 +684,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Desert" cooler_wetter_result = "no" @@ -735,7 +735,7 @@ extra_settings = { "extra", "removal_time" "Pollution", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "Glacier" diff --git a/data/civ2civ3/terrain.ruleset b/data/civ2civ3/terrain.ruleset index 8d13c72aa6..57119a7a42 100644 --- a/data/civ2civ3/terrain.ruleset +++ b/data/civ2civ3/terrain.ruleset @@ -161,7 +161,7 @@ ocean_resources = FALSE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; does not count for warming ; "yes" -- no change; counts for warming @@ -251,7 +251,7 @@ transform_result = "no" transform_time = 0 placing_time = 0 pillage_time = 0 -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -299,7 +299,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "no" cooler_wetter_result = "Glacier" @@ -349,7 +349,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "Storm" +animals = "Storm" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "Glacier" @@ -400,7 +400,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "Storm" +animals = "Storm" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -451,7 +451,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Tundra" cooler_wetter_result = "no" @@ -503,7 +503,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "no" cooler_wetter_result = "Tundra" @@ -564,7 +564,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Jungle" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -618,7 +618,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Swamp" cooler_wetter_result = "Swamp" @@ -669,7 +669,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -724,7 +724,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -778,7 +778,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -834,7 +834,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Desert" cooler_wetter_result = "Desert" @@ -886,7 +886,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Desert" warmer_drier_result = "no" cooler_wetter_result = "Tundra" @@ -941,7 +941,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" diff --git a/data/classic/terrain.ruleset b/data/classic/terrain.ruleset index 3aaf901828..50496a8cb7 100644 --- a/data/classic/terrain.ruleset +++ b/data/classic/terrain.ruleset @@ -154,7 +154,7 @@ ocean_resources = FALSE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; does not count for warming ; "yes" -- no change; counts for warming @@ -244,7 +244,7 @@ transform_result = "no" transform_time = 0 placing_time = 0 pillage_time = 0 -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -292,7 +292,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" @@ -342,7 +342,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" @@ -393,7 +393,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -444,7 +444,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Tundra" warmer_drier_result = "Tundra" cooler_wetter_result = "no" @@ -498,7 +498,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Grassland" warmer_drier_result = "no" cooler_wetter_result = "Plains" @@ -553,7 +553,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Jungle" warmer_drier_result = "Plains" cooler_wetter_result = "Swamp" @@ -607,7 +607,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -658,7 +658,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -710,7 +710,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Swamp" @@ -763,7 +763,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -814,7 +814,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -866,7 +866,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -920,7 +920,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" diff --git a/data/goldkeep/terrain.ruleset b/data/goldkeep/terrain.ruleset index d1cc57f540..98006194f1 100644 --- a/data/goldkeep/terrain.ruleset +++ b/data/goldkeep/terrain.ruleset @@ -156,7 +156,7 @@ ocean_resources = FALSE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; does not count for warming ; "yes" -- no change; counts for warming @@ -246,7 +246,7 @@ transform_result = "no" transform_time = 0 placing_time = 0 pillage_time = 0 -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -292,7 +292,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" @@ -340,7 +340,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" @@ -389,7 +389,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -438,7 +438,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Tundra" warmer_drier_result = "Tundra" cooler_wetter_result = "no" @@ -490,7 +490,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Grassland" warmer_drier_result = "no" cooler_wetter_result = "Plains" @@ -543,7 +543,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Jungle" warmer_drier_result = "Plains" cooler_wetter_result = "Swamp" @@ -595,7 +595,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -644,7 +644,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -694,7 +694,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Swamp" @@ -745,7 +745,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -794,7 +794,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -844,7 +844,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -896,7 +896,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" diff --git a/data/granularity/terrain.ruleset b/data/granularity/terrain.ruleset index 3c388fa7d3..a142189e14 100644 --- a/data/granularity/terrain.ruleset +++ b/data/granularity/terrain.ruleset @@ -151,7 +151,7 @@ ocean_resources = FALSE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; doesn''t count for warming ; "yes" -- no change; counts for warming @@ -243,7 +243,7 @@ pillage_time = 1 extra_settings = { "extra", "removal_time" } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -292,7 +292,7 @@ pillage_time = 1 extra_settings = { "extra", "removal_time" } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -341,7 +341,7 @@ pillage_time = 1 extra_settings = { "extra", "removal_time" } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -389,7 +389,7 @@ pillage_time = 1 extra_settings = { "extra", "removal_time" } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -439,7 +439,7 @@ pillage_time = 1 extra_settings = { "extra", "removal_time" } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -487,7 +487,7 @@ pillage_time = 1 extra_settings = { "extra", "removal_time" } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" diff --git a/data/multiplayer/terrain.ruleset b/data/multiplayer/terrain.ruleset index cd9ad07110..80a23780e5 100644 --- a/data/multiplayer/terrain.ruleset +++ b/data/multiplayer/terrain.ruleset @@ -154,7 +154,7 @@ ocean_resources = FALSE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; does not count for warming ; "yes" -- no change; counts for warming @@ -244,7 +244,7 @@ transform_result = "no" transform_time = 0 placing_time = 0 pillage_time = 0 -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -290,7 +290,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" @@ -338,7 +338,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" @@ -387,7 +387,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -436,7 +436,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Tundra" warmer_drier_result = "Tundra" cooler_wetter_result = "no" @@ -488,7 +488,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Grassland" warmer_drier_result = "no" cooler_wetter_result = "Plains" @@ -541,7 +541,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Jungle" warmer_drier_result = "Plains" cooler_wetter_result = "Swamp" @@ -593,7 +593,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -642,7 +642,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -692,7 +692,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Swamp" @@ -743,7 +743,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -792,7 +792,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -842,7 +842,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -894,7 +894,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" diff --git a/data/ruledit/comments-3.4.txt b/data/ruledit/comments-3.4.txt index 70a3ce5cef..295cc493d8 100644 --- a/data/ruledit/comments-3.4.txt +++ b/data/ruledit/comments-3.4.txt @@ -643,7 +643,7 @@ terrains = "\ ; - \"extra\" - Name of the extra\n\ ; - \"removal_time\" - Time for cleaning activities (0 = impossible)\n\ ; Nonzero values only affect extras with removal_time 0.\n\ -; animal = unit type that can appear as animal on the terrain\n\ +; animals = list of unit types that can appear as animal on the terrain\n\ ; warmer_wetter_result = result of global warming for wet terrains; one of:\n\ ; \"no\" -- no change; does not count for warming\n\ ; \"yes\" -- no change; counts for warming\n\ diff --git a/data/sandbox/terrain.ruleset b/data/sandbox/terrain.ruleset index 6e0c247699..b283b8c1d4 100644 --- a/data/sandbox/terrain.ruleset +++ b/data/sandbox/terrain.ruleset @@ -162,7 +162,7 @@ ocean_resources = FALSE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; does not count for warming ; "yes" -- no change; counts for warming @@ -252,7 +252,7 @@ transform_result = "no" transform_time = 0 placing_time = 0 pillage_time = 0 -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -300,7 +300,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "no" cooler_wetter_result = "Glacier" @@ -350,7 +350,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "Storm" +animals = "Storm" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "Glacier" @@ -401,7 +401,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "Storm" +animals = "Storm" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -452,7 +452,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Tundra" cooler_wetter_result = "no" @@ -504,7 +504,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "no" cooler_wetter_result = "Tundra" @@ -565,7 +565,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Jungle" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -619,7 +619,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Swamp" cooler_wetter_result = "Swamp" @@ -670,7 +670,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -725,7 +725,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -779,7 +779,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -835,7 +835,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Desert" cooler_wetter_result = "Desert" @@ -887,7 +887,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Desert" warmer_drier_result = "no" cooler_wetter_result = "Tundra" @@ -942,7 +942,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Swamp" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" diff --git a/data/stub/terrain.ruleset b/data/stub/terrain.ruleset index c7e12070d1..23b3f5550c 100644 --- a/data/stub/terrain.ruleset +++ b/data/stub/terrain.ruleset @@ -142,7 +142,7 @@ ocean_resources = FALSE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; doesn''t count for warming ; "yes" -- no change; counts for warming @@ -234,7 +234,7 @@ pillage_time = 1 extra_settings = { "extra", "removal_time" } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -283,7 +283,7 @@ pillage_time = 1 extra_settings = { "extra", "removal_time" } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" diff --git a/data/webperimental/terrain.ruleset b/data/webperimental/terrain.ruleset index c9482686f2..a1bdcef9e7 100644 --- a/data/webperimental/terrain.ruleset +++ b/data/webperimental/terrain.ruleset @@ -154,7 +154,7 @@ ocean_resources = FALSE ; - "extra" - Name of the extra ; - "removal_time" - Time for cleaning activities (0 = impossible) ; Nonzero values only affect extras with removal_time 0. -; animal = unit type that can appear as animal on the terrain +; animals = list of unit types that can appear as animal on the terrain ; warmer_wetter_result = result of global warming for wet terrains; one of: ; "no" -- no change; does not count for warming ; "yes" -- no change; counts for warming @@ -244,7 +244,7 @@ transform_result = "no" transform_time = 0 placing_time = 0 pillage_time = 0 -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -292,7 +292,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" @@ -342,7 +342,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "Swamp" cooler_wetter_result = "Glacier" @@ -393,7 +393,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -444,7 +444,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Tundra" warmer_drier_result = "Tundra" cooler_wetter_result = "no" @@ -498,7 +498,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Grassland" warmer_drier_result = "no" cooler_wetter_result = "Plains" @@ -553,7 +553,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Jungle" warmer_drier_result = "Plains" cooler_wetter_result = "Swamp" @@ -607,7 +607,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -658,7 +658,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -710,7 +710,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Swamp" @@ -763,7 +763,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "no" warmer_drier_result = "no" cooler_wetter_result = "no" @@ -814,7 +814,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -866,7 +866,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" @@ -920,7 +920,7 @@ extra_settings = "Pollution", 3 "Fallout", 3 } -animal = "None" +animals = "None" warmer_wetter_result = "Lake" warmer_drier_result = "Desert" cooler_wetter_result = "Glacier" diff --git a/server/animals.c b/server/animals.c index 9ce7f6528f..59cf6ed532 100644 --- a/server/animals.c +++ b/server/animals.c @@ -15,6 +15,9 @@ #include #endif +/* utility */ +#include "rand.h" /* fc_rand() */ + /* common */ #include "ai.h" #include "game.h" @@ -41,11 +44,15 @@ #include "animals.h" /************************************************************************//** - Return suitable animal type for the terrain + Return a randon suitable animal type for the terrain ****************************************************************************/ static const struct unit_type *animal_for_terrain(struct terrain *pterr) { - return pterr->animal; + if (pterr->num_animals == 0) { + return nullptr; + } else { + return pterr->animals[fc_rand(pterr->num_animals)]; + } } /************************************************************************//** diff --git a/server/ruleset/rssanity.c b/server/ruleset/rssanity.c index 0c3d5490f6..e3ad31adcf 100644 --- a/server/ruleset/rssanity.c +++ b/server/ruleset/rssanity.c @@ -1521,14 +1521,15 @@ bool sanity_check_ruleset_data(struct rscompat_info *compat) } music_styles_re_active_iterate_end; terrain_re_active_iterate(pterr) { - if (pterr->animal != NULL) { - if (!is_native_to_class(utype_class(pterr->animal), pterr, NULL)) { + terrain_animals_iterate(pterr, panimal) { + if (!is_native_to_class(utype_class(panimal), pterr, nullptr)) { ruleset_error(logger, LOG_ERROR, _("%s has %s as animal to appear, but it's not native to the terrain."), - terrain_rule_name(pterr), utype_rule_name(pterr->animal)); + terrain_rule_name(pterr), utype_rule_name(panimal)); ok = FALSE; + break; } - } + } terrain_animals_iterate_end terrain_resources_iterate(pterr, pres, freq) { (void) freq; diff --git a/server/ruleset/ruleload.c b/server/ruleset/ruleload.c index 108ab5f17e..7ebbf4cfa4 100644 --- a/server/ruleset/ruleload.c +++ b/server/ruleset/ruleload.c @@ -3413,10 +3413,29 @@ static bool load_ruleset_terrain(struct section_file *file, break; } - if (!lookup_unit_type(file, tsection, "animal", - &pterrain->animal, filename, - rule_name_get(&pterrain->name))) { - ok = FALSE; + res = secfile_lookup_str_vec(file, &nval, "%s.animals", tsection); + /* if "None", adjust */ + if (nval == 1 && strcmp(res[0], "None") == 0) { + pterrain->num_animals = 0; + } else { + pterrain->num_animals = nval; + } + if (pterrain->num_animals == 0) { + pterrain->animals = nullptr; + } else { + pterrain->animals = fc_calloc(pterrain->num_animals, + sizeof(*pterrain->animals)); + for (j = 0; j < pterrain->num_animals; j++) { + pterrain->animals[j] = unit_type_by_rule_name(res[j]); + if (pterrain->animals[j] == NULL) { + ok = FALSE; + break; + } + } + } + free(res); + res = NULL; + if (!ok) { break; } @@ -8613,7 +8632,11 @@ static void send_ruleset_terrain(struct conn_list *dest) packet.mining_shield_incr = pterrain->mining_shield_incr; packet.mining_time = pterrain->mining_time; - packet.animal = (pterrain->animal == NULL ? -1 : utype_number(pterrain->animal)); + packet.num_animals = pterrain->num_animals; + terrain_animals_iterate(pterrain, panimal) { + packet.animals[packet.num_animals] = utype_number(panimal); + } terrain_animals_iterate_end; + packet.transform_result = (pterrain->transform_result ? terrain_number(pterrain->transform_result) : terrain_count()); diff --git a/tools/ruledit/validity.c b/tools/ruledit/validity.c index 20bb36faf6..73f565a618 100644 --- a/tools/ruledit/validity.c +++ b/tools/ruledit/validity.c @@ -259,10 +259,12 @@ bool is_utype_needed(struct unit_type *ptype, requirers_cb cb, needed |= is_universal_needed(&uni, cb, data); terrain_re_active_iterate(pterr) { - if (pterr->animal == ptype) { - cb(terrain_rule_name(pterr), data); - needed = TRUE; - } + terrain_animals_iterate(pterr, panimal) { + if (panimal == ptype) { + cb(terrain_rule_name(pterr), data); + needed = TRUE; + } + } terrain_animals_iterate_end } terrain_re_active_iterate_end; return needed; diff --git a/tools/ruleutil/rulesave.c b/tools/ruleutil/rulesave.c index 7b9eb61a3a..8309bd606a 100644 --- a/tools/ruleutil/rulesave.c +++ b/tools/ruleutil/rulesave.c @@ -2636,7 +2636,7 @@ static bool save_terrain_ruleset(const char *filename, const char *name) /* Check resource count */ for (r = 0; pterr->resources[r] != nullptr; r++) { - /* Just increasing r as long as there is resources */ + /* Just increasing r as long as there are resources */ } { @@ -2696,12 +2696,18 @@ static bool save_terrain_ruleset(const char *filename, const char *name) secfile_insert_int(sfile, pterr->transform_time, "%s.transform_time", path); - if (pterr->animal != nullptr) { - secfile_insert_str(sfile, utype_rule_name(pterr->animal), - "%s.animal", path); + if (pterr->num_animals > 0) { + const char *animal_names[pterr->num_animals]; + int count = 0; + + terrain_animals_iterate(pterr, panimal) { + animal_names[count++] = utype_rule_name(panimal); + } terrain_animals_iterate_end + secfile_insert_str_vec(sfile, animal_names, count, + "%s.animals", path); } else { secfile_insert_str(sfile, "None", - "%s.animal", path); + "%s.animals", path); } secfile_insert_int(sfile, pterr->placing_time, -- 2.31.0