New flying game turkey added. Zombie swarms added. Enemies from areas can now be encountered in those areas they do not leave the area unless invading.

This commit is contained in:
Storm Dragon
2026-02-06 18:51:36 -05:00
parent 1220cfefe2
commit 8cd2e1d5a9
10 changed files with 546 additions and 57 deletions

View File

@@ -38,6 +38,15 @@ bool invasion_triggered_today = false;
bool invasion_roll_done_today = false;
int invasion_scheduled_hour = -1;
string invasion_enemy_type = "bandit";
bool invasion_started_once = false;
// Zombie swarm tracking
bool zombie_swarm_active = false;
int zombie_swarm_start_hour = -1;
int zombie_swarm_scheduled_hour = -1;
bool zombie_swarm_triggered_today = false;
bool zombie_swarm_roll_done_today = false;
int zombie_swarm_duration_hours = 0;
// Invasion mapping: "terrain=enemy" (defaults to bandits when no match)
// Terrain keys: "mountain" for mountain ranges, or regular types like "grass", "snow", "forest", "deep_forest", "stone".
@@ -61,6 +70,13 @@ void init_time() {
invasion_roll_done_today = false;
invasion_scheduled_hour = -1;
invasion_enemy_type = "bandit";
invasion_started_once = false;
zombie_swarm_active = false;
zombie_swarm_start_hour = -1;
zombie_swarm_scheduled_hour = -1;
zombie_swarm_triggered_today = false;
zombie_swarm_roll_done_today = false;
zombie_swarm_duration_hours = 0;
reset_player_item_break_state();
update_ambience(true); // Force start
}
@@ -311,6 +327,7 @@ void start_invasion() {
invasion_active = true;
invasion_start_hour = current_hour;
invasion_enemy_type = get_invasion_enemy_type_for_terrain(expansion_terrain);
invasion_started_once = true;
string source = (expansion_terrain == "mountain") ? "the mountains" : "the new area";
string enemy_plural = get_invasion_enemy_plural(invasion_enemy_type);
notify(enemy_plural + " are invading from " + source + "!");
@@ -377,6 +394,144 @@ void attempt_daily_invasion() {
check_scheduled_invasion();
}
bool can_roll_zombie_swarm_today() {
return current_day >= ZOMBIE_SWARM_START_DAY;
}
int get_zombie_swarm_duration_hours() {
int offset = current_day - ZOMBIE_SWARM_START_DAY;
if (offset < 0) offset = 0;
int cycles = offset / ZOMBIE_SWARM_INTERVAL_DAYS;
int duration = ZOMBIE_SWARM_BASE_DURATION_HOURS + (cycles * ZOMBIE_SWARM_DURATION_STEP_HOURS);
if (duration < 1) duration = 1;
return duration;
}
int get_zombie_swarm_chance_for_day() {
int offset = current_day - ZOMBIE_SWARM_START_DAY;
if (offset < 0) offset = 0;
int cycles = offset / ZOMBIE_SWARM_CHANCE_INTERVAL_DAYS;
int chance = ZOMBIE_SWARM_CHANCE_START + (cycles * ZOMBIE_SWARM_CHANCE_STEP);
if (chance > ZOMBIE_SWARM_CHANCE_CAP) chance = ZOMBIE_SWARM_CHANCE_CAP;
if (chance < 0) chance = 0;
return chance;
}
void start_zombie_swarm() {
zombie_swarm_active = true;
zombie_swarm_start_hour = current_hour;
zombie_swarm_duration_hours = get_zombie_swarm_duration_hours();
speak_with_history("A swarm of zombies has been spotted.", true);
}
void end_zombie_swarm() {
zombie_swarm_active = false;
zombie_swarm_start_hour = -1;
zombie_swarm_duration_hours = 0;
}
void check_zombie_swarm_status() {
if (!zombie_swarm_active) return;
int hours_elapsed = current_hour - zombie_swarm_start_hour;
if (hours_elapsed < 0) {
hours_elapsed += 24;
}
if (hours_elapsed >= zombie_swarm_duration_hours) {
end_zombie_swarm();
}
}
void schedule_zombie_swarm() {
if (zombie_swarm_scheduled_hour != -1) return;
int hour = get_random_invasion_hour(current_hour);
if (hour == -1) return;
zombie_swarm_scheduled_hour = hour;
}
void check_scheduled_zombie_swarm() {
if (zombie_swarm_active) return;
if (zombie_swarm_scheduled_hour != -1) {
if (current_hour == zombie_swarm_scheduled_hour) {
zombie_swarm_scheduled_hour = -1;
zombie_swarm_triggered_today = true;
start_zombie_swarm();
} else if (current_hour > 11) {
zombie_swarm_scheduled_hour = -1;
}
return;
}
if (zombie_swarm_triggered_today) return;
}
void attempt_daily_zombie_swarm() {
if (!can_roll_zombie_swarm_today()) return;
if (zombie_swarm_roll_done_today || zombie_swarm_triggered_today || zombie_swarm_active) return;
if (current_hour < 6) return;
zombie_swarm_roll_done_today = true;
int chance = get_zombie_swarm_chance_for_day();
int roll = random(1, 100);
if (roll > chance) {
return;
}
if (current_hour > 11) {
zombie_swarm_triggered_today = true;
start_zombie_swarm();
return;
}
schedule_zombie_swarm();
check_scheduled_zombie_swarm();
}
void get_expanded_area_segments(int[]@ areaStarts, int[]@ areaEnds, string[]@ areaTypes) {
areaStarts.resize(0);
areaEnds.resize(0);
areaTypes.resize(0);
if (expanded_area_start == -1) return;
int total = int(expanded_terrain_types.length());
if (total <= 0) return;
string current_type = get_expanded_area_type(0);
int segment_start = 0;
for (int i = 1; i < total; i++) {
string segment_type = get_expanded_area_type(i);
if (segment_type != current_type) {
areaStarts.insert_last(expanded_area_start + segment_start);
areaEnds.insert_last(expanded_area_start + i - 1);
areaTypes.insert_last(current_type);
segment_start = i;
current_type = segment_type;
}
}
areaStarts.insert_last(expanded_area_start + segment_start);
areaEnds.insert_last(expanded_area_start + total - 1);
areaTypes.insert_last(current_type);
}
void attempt_expansion_roamer_spawn() {
if (!is_daytime) return;
if (invasion_active) return;
if (!invasion_started_once) return;
if (expanded_area_start == -1) return;
if (current_hour % EXPANSION_ROAMER_SPAWN_INTERVAL_HOURS != 0) return;
int[] areaStarts;
int[] areaEnds;
string[] areaTypes;
get_expanded_area_segments(areaStarts, areaEnds, areaTypes);
if (areaStarts.length() == 0) return;
for (uint i = 0; i < areaStarts.length(); i++) {
int count = count_bandits_in_range(areaStarts[i], areaEnds[i]);
if (count >= EXPANSION_ROAMER_MAX_PER_AREA) continue;
string invader_type = get_invasion_enemy_type_for_terrain(areaTypes[i]);
spawn_bandit(areaStarts[i], areaEnds[i], invader_type);
}
}
void attempt_resident_recruitment() {
if (barricade_health <= 0) {
return;
@@ -561,6 +716,9 @@ void update_time() {
invasion_triggered_today = false;
invasion_roll_done_today = false;
invasion_scheduled_hour = -1;
zombie_swarm_triggered_today = false;
zombie_swarm_scheduled_hour = -1;
zombie_swarm_roll_done_today = false;
quest_roll_done_today = false;
playerItemBreaksToday = 0;
}
@@ -585,6 +743,7 @@ void update_time() {
// Check invasion status
check_invasion_status();
check_zombie_swarm_status();
check_ambience_transition();
// Safety: if crossfade failed or was skipped, align day/night with the current hour.
@@ -629,6 +788,7 @@ void update_time() {
attempt_resident_foraging();
}
attempt_daily_invasion();
attempt_daily_zombie_swarm();
keep_base_fires_fed();
attempt_player_item_break_check();
update_incense_burning();
@@ -637,6 +797,8 @@ void update_time() {
attempt_hourly_wight_spawn();
attempt_hourly_vampyr_spawn();
check_scheduled_invasion();
check_scheduled_zombie_swarm();
attempt_expansion_roamer_spawn();
attempt_blessing();
check_weather_transition();
attempt_resident_collection();