Total darkness now possible if players survive long enough. Undead raids added if invasion happens in darkness.
This commit is contained in:
+2
-1
@@ -117,6 +117,7 @@ time.event.mountain_discovered='n Bergreeks is in die ooste ontdek!
|
||||
time.event.invasion_source_mountains=die berge
|
||||
time.event.invasion_source_new_area=die nuwe area
|
||||
time.event.invasion_start={enemy_plural} val in vanaf {source}!
|
||||
time.event.undead_resident_raid=Die dooies onthou waar mense nog leef. {count} ondode inwoners kom.
|
||||
time.event.zombie_swarm_spotted='n Swerm zombies is gewaar.
|
||||
time.event.survivor_joins_one='n Oorlewende sluit by jou basis aan.
|
||||
time.event.survivor_joins_many={count} oorlewendes sluit by jou basis aan.
|
||||
@@ -1031,7 +1032,7 @@ system.goals.mastery.crafting.name=Handwerk Bemeestering
|
||||
system.goals.mastery.leadership.level1=Inwoners is versigtig en breek minder gereedskap en wapens.
|
||||
system.goals.mastery.leadership.level2=Inwoners is georganiseer en slaag meer gereeld met werk.
|
||||
system.goals.mastery.leadership.level3=Inwoners tree vinniger op tydens verdediging en dringende werk.
|
||||
system.goals.mastery.leadership.level4=Inwoners rantsoeneer kos en eet elke 12 uur in plaas van elke 8.
|
||||
system.goals.mastery.leadership.level4=Inwoners rantsoeneer kos en bly werk na nagval.
|
||||
system.goals.mastery.leadership.name=Leierskap Bemeestering
|
||||
system.goals.mastery.taming.level1=Troeteldiere kan gevalle items haal.
|
||||
system.goals.mastery.taming.level2=Troeteldiere is sterker en kry een maksimum gesondheid.
|
||||
|
||||
+7
-6
@@ -71,6 +71,7 @@ time.event.mountain_discovered=A mountain range has been discovered to the east!
|
||||
time.event.invasion_source_mountains=the mountains
|
||||
time.event.invasion_source_new_area=the new area
|
||||
time.event.invasion_start={enemy_plural} are invading from {source}!
|
||||
time.event.undead_resident_raid=The dead remember where people still live. {count} undead residents are coming.
|
||||
time.event.zombie_swarm_spotted=A swarm of zombies has been spotted.
|
||||
time.event.survivor_joins_one=A survivor joins your base.
|
||||
time.event.survivor_joins_many={count} survivors join your base.
|
||||
@@ -293,7 +294,7 @@ goals.mastery.crafting.level4=Personal tools, weapons, and clothing no longer we
|
||||
goals.mastery.leadership.level1=Residents are careful and break fewer tools and weapons.
|
||||
goals.mastery.leadership.level2=Residents are organized and succeed at work more often.
|
||||
goals.mastery.leadership.level3=Residents act faster during defense and urgent work.
|
||||
goals.mastery.leadership.level4=Residents ration food, eating every 12 hours instead of every 8.
|
||||
goals.mastery.leadership.level4=Residents ration food and keep working after nightfall.
|
||||
goals.mastery.taming.level1=Pets can retrieve dropped items.
|
||||
goals.mastery.taming.level2=Pets are heartier and gain one maximum health.
|
||||
goals.mastery.taming.level3=Pets recover from knockout faster.
|
||||
@@ -976,7 +977,7 @@ msg.5cac31311668=Pasture is full. No livestock were recovered.
|
||||
msg.5cc7429297c8=that can be destroyed with an axe.
|
||||
; seed:learn_sounds_label:sounds/actions/cast_strength.ogg
|
||||
msg.5dfc869b7588=cast strength
|
||||
; src/time_system.nvgt:801:notify[0]
|
||||
; src/time_system.nvgt:861:notify[0]
|
||||
msg.5ea84b1201bb={arg1} favor grants you the eyes of an eagle.
|
||||
; seed:learn_sounds_label:sounds/menu/menu_select.ogg
|
||||
; seed:learn_sounds_label:sounds/menu.bak/menu_select.ogg
|
||||
@@ -1070,8 +1071,8 @@ msg.803e4c41bbd2=sticks
|
||||
msg.80655da8d80a=tree
|
||||
; src/item_registry.nvgt:item_plural:canoes
|
||||
msg.806baaf8e039=canoes
|
||||
; src/time_system.nvgt:783:notify[0]
|
||||
; src/time_system.nvgt:793:notify[0]
|
||||
; src/time_system.nvgt:843:notify[0]
|
||||
; src/time_system.nvgt:853:notify[0]
|
||||
msg.81df04a81e24={arg1} favor shines upon you. {arg2}
|
||||
; src/quests/catch_the_boomerang_game.nvgt:22:insert_last[0]
|
||||
msg.823be948275f=- Better timing earns more points (up to 4)
|
||||
@@ -1097,7 +1098,7 @@ msg.86e257c3efcb=Oldest notification. {arg1}
|
||||
msg.87383ce4344d=Bowstrings
|
||||
; src/item_registry.nvgt:item_plural:ropes
|
||||
msg.87cdb5c91437=ropes
|
||||
; src/time_system.nvgt:797:notify[0]
|
||||
; src/time_system.nvgt:857:notify[0]
|
||||
msg.8818f1d55166={arg1} radiance fills residents with purpose.
|
||||
; src/quests/bat_invasion_game.nvgt:7:insert_last[0]
|
||||
msg.88749dbbbf09==== Bat Invasion ===
|
||||
@@ -1115,7 +1116,7 @@ msg.8f993ac20023=You enter a narrow mountain pass. A massive Unicorn blocks your
|
||||
msg.917ee46db0cd=bee
|
||||
; seed:learn_sounds_label:sounds/player_male_damage.ogg
|
||||
msg.924e0eb6b6f1=player male damage
|
||||
; src/time_system.nvgt:788:notify[0]
|
||||
; src/time_system.nvgt:848:notify[0]
|
||||
msg.9281d2fe5f08={arg1} favor shines upon you. You feel swift for a while.
|
||||
; seed:learn_sounds_label:sounds/actions/climb_rope.ogg
|
||||
msg.92abc6d6953f=climb rope
|
||||
|
||||
@@ -71,6 +71,7 @@ time.event.mountain_discovered=A mountain range has been discovered to the east!
|
||||
time.event.invasion_source_mountains=the mountains
|
||||
time.event.invasion_source_new_area=the new area
|
||||
time.event.invasion_start={enemy_plural} are invading from {source}!
|
||||
time.event.undead_resident_raid=The dead remember where people still live. {count} undead residents are coming.
|
||||
time.event.zombie_swarm_spotted=A swarm of zombies has been spotted.
|
||||
time.event.survivor_joins_one=A survivor joins your base.
|
||||
time.event.survivor_joins_many={count} survivors join your base.
|
||||
@@ -293,7 +294,7 @@ goals.mastery.crafting.level4=Personal tools, weapons, and clothing no longer we
|
||||
goals.mastery.leadership.level1=Residents are careful and break fewer tools and weapons.
|
||||
goals.mastery.leadership.level2=Residents are organized and succeed at work more often.
|
||||
goals.mastery.leadership.level3=Residents act faster during defense and urgent work.
|
||||
goals.mastery.leadership.level4=Residents ration food, eating every 12 hours instead of every 8.
|
||||
goals.mastery.leadership.level4=Residents ration food and keep working after nightfall.
|
||||
goals.mastery.taming.level1=Pets can retrieve dropped items.
|
||||
goals.mastery.taming.level2=Pets are heartier and gain one maximum health.
|
||||
goals.mastery.taming.level3=Pets recover from knockout faster.
|
||||
@@ -976,7 +977,7 @@ msg.5cac31311668=Pasture is full. No livestock were recovered.
|
||||
msg.5cc7429297c8=that can be destroyed with an axe.
|
||||
; seed:learn_sounds_label:sounds/actions/cast_strength.ogg
|
||||
msg.5dfc869b7588=cast strength
|
||||
; src/time_system.nvgt:801:notify[0]
|
||||
; src/time_system.nvgt:861:notify[0]
|
||||
msg.5ea84b1201bb={arg1} favor grants you the eyes of an eagle.
|
||||
; seed:learn_sounds_label:sounds/menu/menu_select.ogg
|
||||
; seed:learn_sounds_label:sounds/menu.bak/menu_select.ogg
|
||||
@@ -1070,8 +1071,8 @@ msg.803e4c41bbd2=sticks
|
||||
msg.80655da8d80a=tree
|
||||
; src/item_registry.nvgt:item_plural:canoes
|
||||
msg.806baaf8e039=canoes
|
||||
; src/time_system.nvgt:783:notify[0]
|
||||
; src/time_system.nvgt:793:notify[0]
|
||||
; src/time_system.nvgt:843:notify[0]
|
||||
; src/time_system.nvgt:853:notify[0]
|
||||
msg.81df04a81e24={arg1} favor shines upon you. {arg2}
|
||||
; src/quests/catch_the_boomerang_game.nvgt:22:insert_last[0]
|
||||
msg.823be948275f=- Better timing earns more points (up to 4)
|
||||
@@ -1097,7 +1098,7 @@ msg.86e257c3efcb=Oldest notification. {arg1}
|
||||
msg.87383ce4344d=Bowstrings
|
||||
; src/item_registry.nvgt:item_plural:ropes
|
||||
msg.87cdb5c91437=ropes
|
||||
; src/time_system.nvgt:797:notify[0]
|
||||
; src/time_system.nvgt:857:notify[0]
|
||||
msg.8818f1d55166={arg1} radiance fills residents with purpose.
|
||||
; src/quests/bat_invasion_game.nvgt:7:insert_last[0]
|
||||
msg.88749dbbbf09==== Bat Invasion ===
|
||||
@@ -1115,7 +1116,7 @@ msg.8f993ac20023=You enter a narrow mountain pass. A massive Unicorn blocks your
|
||||
msg.917ee46db0cd=bee
|
||||
; seed:learn_sounds_label:sounds/player_male_damage.ogg
|
||||
msg.924e0eb6b6f1=player male damage
|
||||
; src/time_system.nvgt:788:notify[0]
|
||||
; src/time_system.nvgt:848:notify[0]
|
||||
msg.9281d2fe5f08={arg1} favor shines upon you. You feel swift for a while.
|
||||
; seed:learn_sounds_label:sounds/actions/climb_rope.ogg
|
||||
msg.92abc6d6953f=climb rope
|
||||
|
||||
+2
-1
@@ -117,6 +117,7 @@ time.event.mountain_discovered=Se ha descubierto una cordillera al este!
|
||||
time.event.invasion_source_mountains=las montanas
|
||||
time.event.invasion_source_new_area=el area nueva
|
||||
time.event.invasion_start={enemy_plural} estan invadiendo desde {source}!
|
||||
time.event.undead_resident_raid=Los muertos recuerdan donde aun vive la gente. Vienen {count} residentes no muertos.
|
||||
time.event.zombie_swarm_spotted=Se ha detectado una horda de zombis.
|
||||
time.event.survivor_joins_one=Un superviviente se une a tu base.
|
||||
time.event.survivor_joins_many={count} supervivientes se unen a tu base.
|
||||
@@ -1031,7 +1032,7 @@ system.goals.mastery.crafting.name=Maestría de Fabricación
|
||||
system.goals.mastery.leadership.level1=Los residentes son cuidadosos y rompen menos herramientas y armas.
|
||||
system.goals.mastery.leadership.level2=Los residentes son organizados y tienen éxito en el trabajo más a menudo.
|
||||
system.goals.mastery.leadership.level3=Los residentes actúan más rápido durante la defensa y el trabajo urgente.
|
||||
system.goals.mastery.leadership.level4=Los residentes racionan comida y comen cada 12 horas en vez de cada 8.
|
||||
system.goals.mastery.leadership.level4=Los residentes racionan comida y siguen trabajando después del anochecer.
|
||||
system.goals.mastery.leadership.name=Maestría de Liderazgo
|
||||
system.goals.mastery.taming.level1=Las mascotas pueden recuperar objetos caídos.
|
||||
system.goals.mastery.taming.level2=Las mascotas son más resistentes y ganan una salud máxima.
|
||||
|
||||
@@ -562,6 +562,8 @@ def write_catalog(entries: Dict[str, Dict[str, object]], output_path: Path) -> N
|
||||
("system.time.event.invasion_source_mountains", "the mountains"),
|
||||
("system.time.event.invasion_source_new_area", "the new area"),
|
||||
("system.time.event.invasion_start", "{enemy_plural} are invading from {source}!"),
|
||||
("system.time.event.undead_resident_raid",
|
||||
"The dead remember where people still live. {count} undead residents are coming."),
|
||||
("system.time.event.zombie_swarm_spotted", "A swarm of zombies has been spotted."),
|
||||
("system.time.event.survivor_joins_one", "A survivor joins your base."),
|
||||
("system.time.event.survivor_joins_many", "{count} survivors join your base."),
|
||||
@@ -796,7 +798,7 @@ def write_catalog(entries: Dict[str, Dict[str, object]], output_path: Path) -> N
|
||||
("system.goals.mastery.leadership.level1", "Residents are careful and break fewer tools and weapons."),
|
||||
("system.goals.mastery.leadership.level2", "Residents are organized and succeed at work more often."),
|
||||
("system.goals.mastery.leadership.level3", "Residents act faster during defense and urgent work."),
|
||||
("system.goals.mastery.leadership.level4", "Residents ration food, eating every 12 hours instead of every 8."),
|
||||
("system.goals.mastery.leadership.level4", "Residents ration food and keep working after nightfall."),
|
||||
("system.goals.mastery.taming.level1", "Pets can retrieve dropped items."),
|
||||
("system.goals.mastery.taming.level2", "Pets are heartier and gain one maximum health."),
|
||||
("system.goals.mastery.taming.level3", "Pets recover from knockout faster."),
|
||||
|
||||
@@ -155,7 +155,7 @@ void consume_food_for_residents() {
|
||||
}
|
||||
|
||||
void attempt_resident_fishing() {
|
||||
if (!is_daytime)
|
||||
if (!is_daytime && !leadership_mastery_allows_night_work())
|
||||
return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
@@ -216,7 +216,7 @@ void attempt_resident_fishing() {
|
||||
}
|
||||
|
||||
void attempt_resident_fish_smoking() {
|
||||
if (!is_daytime)
|
||||
if (!is_daytime && !leadership_mastery_allows_night_work())
|
||||
return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
@@ -741,8 +741,7 @@ void attempt_resident_clothing_repairs() {
|
||||
|
||||
// Resident snare retrieval
|
||||
void attempt_resident_snare_retrieval() {
|
||||
// Only during daytime
|
||||
if (!is_daytime)
|
||||
if (!is_daytime && !leadership_mastery_allows_night_work())
|
||||
return;
|
||||
|
||||
// Need residents
|
||||
@@ -926,8 +925,7 @@ void attempt_resident_butchering() {
|
||||
// Resident resource collection
|
||||
|
||||
void attempt_resident_collection() {
|
||||
// Only during daytime
|
||||
if (!is_daytime)
|
||||
if (!is_daytime && !leadership_mastery_allows_night_work())
|
||||
return;
|
||||
|
||||
// Need residents
|
||||
@@ -1005,8 +1003,7 @@ void attempt_resident_collection() {
|
||||
|
||||
// Resident foraging - produces baskets of fruits and nuts from reed baskets
|
||||
void attempt_resident_foraging() {
|
||||
// Only during daytime
|
||||
if (!is_daytime)
|
||||
if (!is_daytime && !leadership_mastery_allows_night_work())
|
||||
return;
|
||||
|
||||
// Need residents
|
||||
|
||||
@@ -86,6 +86,9 @@ const int ZOMBIE_ATTACK_MAX_HEIGHT = 6;
|
||||
const int UNDEAD_RESIDENT_HEALTH = 16;
|
||||
const int UNDEAD_RESIDENT_DAMAGE_MIN = 5;
|
||||
const int UNDEAD_RESIDENT_DAMAGE_MAX = 7;
|
||||
const int UNDEAD_RESIDENT_RAID_BASE_COUNT = 2;
|
||||
const int UNDEAD_RESIDENT_RAID_DAYS_PER_EXTRA = 18;
|
||||
const int UNDEAD_RESIDENT_RAID_MAX_COUNT = 8;
|
||||
|
||||
// Wight settings (undead elite)
|
||||
const int WIGHT_HEALTH = 40;
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
// Corpse worms are weak opportunistic enemies that begin appearing after day 1.
|
||||
|
||||
string[] corpse_worm_sounds = {"sounds/enemies/corpse_worm.ogg"};
|
||||
timer corpse_worm_spawn_timer;
|
||||
|
||||
class CorpseWorm {
|
||||
int position;
|
||||
int health;
|
||||
int sound_handle;
|
||||
bool in_weapon_range;
|
||||
timer move_timer;
|
||||
timer attack_timer;
|
||||
string voice_sound;
|
||||
|
||||
CorpseWorm(int pos) {
|
||||
position = pos;
|
||||
health = CORPSE_WORM_HEALTH;
|
||||
sound_handle = -1;
|
||||
in_weapon_range = false;
|
||||
voice_sound = corpse_worm_sounds[random(0, corpse_worm_sounds.length() - 1)];
|
||||
move_timer.restart();
|
||||
attack_timer.restart();
|
||||
}
|
||||
} CorpseWorm @[] corpse_worms;
|
||||
|
||||
void update_corpse_worm_weapon_range_audio() {
|
||||
for (uint i = 0; i < corpse_worms.length(); i++) {
|
||||
update_weapon_range_audio(corpse_worms[i].position, corpse_worms[i].in_weapon_range);
|
||||
}
|
||||
}
|
||||
bool corpse_worm_range_audio_registered = false;
|
||||
|
||||
void ensure_corpse_worm_range_audio_registration() {
|
||||
if (corpse_worm_range_audio_registered)
|
||||
return;
|
||||
corpse_worm_range_audio_registered = register_weapon_range_audio_callback(@update_corpse_worm_weapon_range_audio);
|
||||
}
|
||||
|
||||
void clear_corpse_worms() {
|
||||
for (uint i = 0; i < corpse_worms.length(); i++) {
|
||||
force_weapon_range_exit(corpse_worms[i].position, corpse_worms[i].in_weapon_range);
|
||||
if (corpse_worms[i].sound_handle != -1) {
|
||||
p.destroy_sound(corpse_worms[i].sound_handle);
|
||||
corpse_worms[i].sound_handle = -1;
|
||||
}
|
||||
}
|
||||
corpse_worms.resize(0);
|
||||
corpse_worm_spawn_timer.restart();
|
||||
}
|
||||
|
||||
CorpseWorm @get_corpse_worm_at(int pos) {
|
||||
for (uint i = 0; i < corpse_worms.length(); i++) {
|
||||
if (corpse_worms[i].position == pos) {
|
||||
return @corpse_worms[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool can_spawn_corpse_worm_at(int pos) {
|
||||
if (pos <= BASE_END || pos < 0 || pos >= MAP_SIZE)
|
||||
return false;
|
||||
if (pos == x)
|
||||
return false;
|
||||
if (get_corpse_worm_at(pos) != null)
|
||||
return false;
|
||||
if (get_bandit_at(pos) != null)
|
||||
return false;
|
||||
if (get_boar_at(pos) != null)
|
||||
return false;
|
||||
if (get_zombie_at(pos) != null)
|
||||
return false;
|
||||
if (get_flying_creature_at(pos) != null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int pick_corpse_worm_spawn_position() {
|
||||
for (int attempts = 0; attempts < 20; attempts++) {
|
||||
int distance = random(CORPSE_WORM_SPAWN_MIN_DISTANCE, CORPSE_WORM_SPAWN_MAX_DISTANCE);
|
||||
int direction = (random(0, 1) == 0) ? -1 : 1;
|
||||
int candidate = x + (distance * direction);
|
||||
if (can_spawn_corpse_worm_at(candidate))
|
||||
return candidate;
|
||||
}
|
||||
|
||||
for (int candidate = BASE_END + 1; candidate < MAP_SIZE; candidate++) {
|
||||
if (can_spawn_corpse_worm_at(candidate))
|
||||
return candidate;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void spawn_corpse_worm() {
|
||||
int spawn_x = pick_corpse_worm_spawn_position();
|
||||
if (spawn_x == -1)
|
||||
return;
|
||||
|
||||
CorpseWorm @worm = CorpseWorm(spawn_x);
|
||||
corpse_worms.insert_last(worm);
|
||||
|
||||
int[] areaStarts;
|
||||
int[] areaEnds;
|
||||
get_active_audio_areas(areaStarts, areaEnds);
|
||||
if (areaStarts.length() == 0 || range_overlaps_active_areas(spawn_x, spawn_x, areaStarts, areaEnds)) {
|
||||
worm.sound_handle =
|
||||
play_1d_with_volume_step(worm.voice_sound, x, spawn_x, true, CORPSE_WORM_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
void attempt_corpse_worm_spawn() {
|
||||
if (current_day < CORPSE_WORM_START_DAY)
|
||||
return;
|
||||
if (x <= BASE_END)
|
||||
return;
|
||||
if (corpse_worms.length() >= CORPSE_WORM_MAX_COUNT)
|
||||
return;
|
||||
if (corpse_worm_spawn_timer.elapsed < CORPSE_WORM_SPAWN_ROLL_INTERVAL)
|
||||
return;
|
||||
|
||||
corpse_worm_spawn_timer.restart();
|
||||
if (random(1, 100) <= CORPSE_WORM_SPAWN_CHANCE) {
|
||||
spawn_corpse_worm();
|
||||
}
|
||||
}
|
||||
|
||||
bool try_attack_player_corpse_worm(CorpseWorm @worm) {
|
||||
if (player_health <= 0)
|
||||
return false;
|
||||
if (x <= BASE_END)
|
||||
return false;
|
||||
if (y != 0)
|
||||
return false;
|
||||
if (worm.position != x)
|
||||
return false;
|
||||
if (worm.attack_timer.elapsed < CORPSE_WORM_ATTACK_INTERVAL)
|
||||
return false;
|
||||
|
||||
worm.attack_timer.restart();
|
||||
player_health -= CORPSE_WORM_DAMAGE;
|
||||
if (player_health < 0)
|
||||
player_health = 0;
|
||||
play_player_damage_sound();
|
||||
return true;
|
||||
}
|
||||
|
||||
void update_corpse_worm(CorpseWorm @worm, bool audio_active) {
|
||||
if (!audio_active) {
|
||||
if (worm.sound_handle != -1) {
|
||||
p.destroy_sound(worm.sound_handle);
|
||||
worm.sound_handle = -1;
|
||||
}
|
||||
} else if (worm.sound_handle != -1 && p.sound_is_active(worm.sound_handle)) {
|
||||
p.update_sound_1d(worm.sound_handle, worm.position);
|
||||
} else if (worm.sound_handle == -1 || !p.sound_is_active(worm.sound_handle)) {
|
||||
if (worm.sound_handle != -1) {
|
||||
p.destroy_sound(worm.sound_handle);
|
||||
}
|
||||
worm.sound_handle =
|
||||
play_1d_with_volume_step(worm.voice_sound, x, worm.position, true, CORPSE_WORM_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
if (try_attack_player_corpse_worm(worm))
|
||||
return;
|
||||
if (worm.move_timer.elapsed < CORPSE_WORM_MOVE_INTERVAL)
|
||||
return;
|
||||
|
||||
worm.move_timer.restart();
|
||||
int target_x = (x > BASE_END) ? x : BASE_END + 1;
|
||||
if (target_x == worm.position)
|
||||
return;
|
||||
|
||||
int direction = (target_x > worm.position) ? 1 : -1;
|
||||
int next_pos = worm.position + direction;
|
||||
if (next_pos <= BASE_END || next_pos < 0 || next_pos >= MAP_SIZE)
|
||||
return;
|
||||
if (get_corpse_worm_at(next_pos) != null)
|
||||
return;
|
||||
|
||||
worm.position = next_pos;
|
||||
if (audio_active) {
|
||||
play_creature_footstep(x, worm.position, BASE_END, GRASS_END, CORPSE_WORM_FOOTSTEP_MAX_DISTANCE,
|
||||
CORPSE_WORM_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
void update_corpse_worms() {
|
||||
ensure_corpse_worm_range_audio_registration();
|
||||
attempt_corpse_worm_spawn();
|
||||
|
||||
int[] areaStarts;
|
||||
int[] areaEnds;
|
||||
get_active_audio_areas(areaStarts, areaEnds);
|
||||
bool limit_audio = (areaStarts.length() > 0);
|
||||
for (uint i = 0; i < corpse_worms.length(); i++) {
|
||||
bool audio_active =
|
||||
!limit_audio || range_overlaps_active_areas(corpse_worms[i].position, corpse_worms[i].position, areaStarts,
|
||||
areaEnds);
|
||||
update_corpse_worm(corpse_worms[i], audio_active);
|
||||
}
|
||||
}
|
||||
|
||||
bool damage_corpse_worm_at(int pos, int damage) {
|
||||
for (uint i = 0; i < corpse_worms.length(); i++) {
|
||||
if (corpse_worms[i].position == pos) {
|
||||
corpse_worms[i].health -= damage;
|
||||
if (corpse_worms[i].health <= 0) {
|
||||
force_weapon_range_exit(corpse_worms[i].position, corpse_worms[i].in_weapon_range);
|
||||
if (corpse_worms[i].sound_handle != -1) {
|
||||
p.destroy_sound(corpse_worms[i].sound_handle);
|
||||
corpse_worms[i].sound_handle = -1;
|
||||
}
|
||||
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", corpse_worms[i].voice_sound, x, pos,
|
||||
CORPSE_WORM_SOUND_VOLUME_STEP);
|
||||
corpse_worms.remove_at(i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -79,6 +79,7 @@ class Undead {
|
||||
bool retreating;
|
||||
bool suppress_voice;
|
||||
bool should_despawn;
|
||||
bool counts_as_lost_resident;
|
||||
timer move_timer;
|
||||
timer attack_timer;
|
||||
|
||||
@@ -92,6 +93,7 @@ class Undead {
|
||||
retreating = false;
|
||||
suppress_voice = false;
|
||||
should_despawn = false;
|
||||
counts_as_lost_resident = (undead_type == "undead_resident");
|
||||
move_timer.restart();
|
||||
attack_timer.restart();
|
||||
}
|
||||
@@ -257,7 +259,7 @@ int pick_undead_spawn_near_player(int min_distance, int max_distance) {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
void spawn_undead(const string& in undead_type = "zombie") {
|
||||
void spawn_undead(const string& in undead_type = "zombie", bool counts_as_lost_resident = true) {
|
||||
int spawn_x = -1;
|
||||
if (undead_type == "zombie" || undead_type == "undead_resident") {
|
||||
spawn_x = pick_undead_spawn_near_player(ZOMBIE_SPAWN_MIN_DISTANCE, ZOMBIE_SPAWN_MAX_DISTANCE);
|
||||
@@ -269,6 +271,7 @@ void spawn_undead(const string& in undead_type = "zombie") {
|
||||
return;
|
||||
|
||||
Undead @undead = Undead(spawn_x, undead_type);
|
||||
undead.counts_as_lost_resident = (undead_type == "undead_resident" && counts_as_lost_resident);
|
||||
undeads.insert_last(undead);
|
||||
// Play looping sound that follows the undead
|
||||
int[] areaStarts;
|
||||
@@ -526,7 +529,7 @@ void update_undeads() {
|
||||
for (uint i = 0; i < undeads.length(); i++) {
|
||||
if (undeads[i].undead_type == "zombie") {
|
||||
zombie_count++;
|
||||
} else if (undeads[i].undead_type == "undead_resident") {
|
||||
} else if (undeads[i].undead_type == "undead_resident" && undeads[i].counts_as_lost_resident) {
|
||||
undead_resident_count++;
|
||||
}
|
||||
}
|
||||
@@ -566,7 +569,7 @@ void update_undeads() {
|
||||
}
|
||||
|
||||
void attempt_hourly_wight_spawn() {
|
||||
if (current_hour == 19) {
|
||||
if (current_hour == get_current_night_start_hour()) {
|
||||
wight_spawned_this_night_count = 0;
|
||||
}
|
||||
|
||||
@@ -602,7 +605,7 @@ void attempt_hourly_wight_spawn() {
|
||||
}
|
||||
|
||||
void attempt_hourly_vampyr_spawn() {
|
||||
if (current_hour == 19) {
|
||||
if (current_hour == get_current_night_start_hour()) {
|
||||
vampyr_spawned_this_night_count = 0;
|
||||
}
|
||||
|
||||
@@ -649,7 +652,7 @@ bool damage_undead_at(int pos, int damage) {
|
||||
if (world_altars.length() > 0) {
|
||||
favor += 0.2;
|
||||
}
|
||||
if (undeads[i].undead_type == "undead_resident") {
|
||||
if (undeads[i].undead_type == "undead_resident" && undeads[i].counts_as_lost_resident) {
|
||||
undead_residents_count--;
|
||||
if (undead_residents_count < 0)
|
||||
undead_residents_count = 0;
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ int get_random_stream_tile() {
|
||||
}
|
||||
|
||||
string get_random_fish_type() {
|
||||
bool is_night = (current_hour >= 18 || current_hour < 7);
|
||||
bool is_night = is_night_hour(current_hour);
|
||||
|
||||
if (is_night) {
|
||||
int roll = random(0, 99);
|
||||
|
||||
@@ -484,6 +484,10 @@ int get_resident_food_interval_hours() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
bool leadership_mastery_allows_night_work() {
|
||||
return leadershipMasteryLevel >= 4;
|
||||
}
|
||||
|
||||
bool taming_mastery_allows_retrieval() {
|
||||
return tamingMasteryLevel >= 1;
|
||||
}
|
||||
|
||||
@@ -1638,7 +1638,7 @@ bool load_game_state_from_file(const string& in filename) {
|
||||
if (current_day < 1)
|
||||
current_day = 1;
|
||||
|
||||
is_daytime = (current_hour >= 6 && current_hour < 19);
|
||||
is_daytime = is_day_hour_for_day(current_hour, current_day);
|
||||
hour_timer.restart();
|
||||
|
||||
string weather_data;
|
||||
|
||||
+80
-18
@@ -1,6 +1,9 @@
|
||||
// Time System
|
||||
// 1 real minute = 1 in-game hour
|
||||
const int MS_PER_HOUR = 60000;
|
||||
const int DAY_START_HOUR = 6;
|
||||
const int NIGHT_START_BASE_HOUR = 19;
|
||||
const int NIGHT_START_SHIFT_DAYS = 9;
|
||||
|
||||
int current_hour = 8; // Start at 8 AM
|
||||
int current_day = 1; // Track current day
|
||||
@@ -361,6 +364,24 @@ void start_invasion() {
|
||||
notify(trf("system.time.event.invasion_start", args));
|
||||
}
|
||||
|
||||
int get_undead_resident_raid_count() {
|
||||
int count = UNDEAD_RESIDENT_RAID_BASE_COUNT + (current_day / UNDEAD_RESIDENT_RAID_DAYS_PER_EXTRA);
|
||||
if (count > UNDEAD_RESIDENT_RAID_MAX_COUNT)
|
||||
count = UNDEAD_RESIDENT_RAID_MAX_COUNT;
|
||||
return count;
|
||||
}
|
||||
|
||||
void start_undead_resident_raid() {
|
||||
int count = get_undead_resident_raid_count();
|
||||
for (int i = 0; i < count; i++) {
|
||||
spawn_undead("undead_resident", false);
|
||||
}
|
||||
|
||||
dictionary args;
|
||||
args.set("count", count);
|
||||
notify(trf("system.time.event.undead_resident_raid", args));
|
||||
}
|
||||
|
||||
void update_invasion_chance_for_new_day() {
|
||||
if (current_day == 2) {
|
||||
invasion_chance = 100;
|
||||
@@ -385,17 +406,52 @@ int get_random_invasion_hour(int min_hour) {
|
||||
return random(min_hour, 11);
|
||||
}
|
||||
|
||||
int get_night_start_hour_for_day(int day) {
|
||||
if (day < 1)
|
||||
day = 1;
|
||||
int nightStartHour = NIGHT_START_BASE_HOUR - (day / NIGHT_START_SHIFT_DAYS);
|
||||
if (nightStartHour < DAY_START_HOUR)
|
||||
nightStartHour = DAY_START_HOUR;
|
||||
return nightStartHour;
|
||||
}
|
||||
|
||||
int get_current_night_start_hour() {
|
||||
return get_night_start_hour_for_day(current_day);
|
||||
}
|
||||
|
||||
bool is_night_hour_for_day(int hour, int day) {
|
||||
int nightStartHour = get_night_start_hour_for_day(day);
|
||||
return hour < DAY_START_HOUR || hour >= nightStartHour;
|
||||
}
|
||||
|
||||
bool is_night_hour(int hour) {
|
||||
return hour < 6 || hour >= 19;
|
||||
return is_night_hour_for_day(hour, current_day);
|
||||
}
|
||||
|
||||
bool is_day_hour_for_day(int hour, int day) {
|
||||
return !is_night_hour_for_day(hour, day);
|
||||
}
|
||||
|
||||
bool is_day_hour(int hour) {
|
||||
return !is_night_hour(hour);
|
||||
}
|
||||
|
||||
bool has_daylight_for_day(int day) {
|
||||
return get_night_start_hour_for_day(day) > DAY_START_HOUR;
|
||||
}
|
||||
|
||||
bool has_daylight_today() {
|
||||
return has_daylight_for_day(current_day);
|
||||
}
|
||||
|
||||
int get_random_zombie_swarm_hour(int min_hour) {
|
||||
if (!is_night_hour(min_hour))
|
||||
return -1;
|
||||
if (min_hour >= 19) {
|
||||
int nightStartHour = get_current_night_start_hour();
|
||||
if (min_hour >= nightStartHour) {
|
||||
return random(min_hour, 23);
|
||||
}
|
||||
return random(min_hour, 5);
|
||||
return random(min_hour, DAY_START_HOUR - 1);
|
||||
}
|
||||
|
||||
void schedule_invasion() {
|
||||
@@ -416,7 +472,11 @@ void check_scheduled_invasion() {
|
||||
if (current_hour == invasion_scheduled_hour) {
|
||||
invasion_scheduled_hour = -1;
|
||||
invasion_triggered_today = true;
|
||||
start_invasion();
|
||||
if (is_daytime) {
|
||||
start_invasion();
|
||||
} else {
|
||||
start_undead_resident_raid();
|
||||
}
|
||||
} else if (current_hour > 11) {
|
||||
invasion_scheduled_hour = -1;
|
||||
}
|
||||
@@ -849,16 +909,18 @@ void update_time() {
|
||||
}
|
||||
handle_pet_hourly_update(current_hour);
|
||||
|
||||
if (current_hour == 18 && !sun_setting_warned) {
|
||||
int nightStartHour = get_current_night_start_hour();
|
||||
int sunsetWarningHour = nightStartHour - 1;
|
||||
if (has_daylight_today() && current_hour == sunsetWarningHour && !sun_setting_warned) {
|
||||
notify(tr("system.time.event.sun_setting"));
|
||||
sun_setting_warned = true;
|
||||
} else if (current_hour == 19) {
|
||||
} else if (current_hour == nightStartHour) {
|
||||
sun_setting_warned = false;
|
||||
}
|
||||
if (current_hour == 5 && !sunrise_warned) {
|
||||
if (has_daylight_today() && current_hour == DAY_START_HOUR - 1 && !sunrise_warned) {
|
||||
notify(tr("system.time.event.sky_brightening"));
|
||||
sunrise_warned = true;
|
||||
} else if (current_hour == 6) {
|
||||
} else if (current_hour == DAY_START_HOUR) {
|
||||
sunrise_warned = false;
|
||||
}
|
||||
|
||||
@@ -869,7 +931,7 @@ void update_time() {
|
||||
check_ambience_transition();
|
||||
// Safety: if crossfade failed or was skipped, align day/night with the current hour.
|
||||
if (!crossfade_active) {
|
||||
bool expected_daytime = (current_hour >= 6 && current_hour < 19);
|
||||
bool expected_daytime = is_day_hour(current_hour);
|
||||
if (expected_daytime != is_daytime) {
|
||||
is_daytime = expected_daytime;
|
||||
update_ambience(true);
|
||||
@@ -877,7 +939,7 @@ void update_time() {
|
||||
}
|
||||
|
||||
if (is_daytime && residents_count > 0 && barricade_health < BARRICADE_MAX_HEALTH) {
|
||||
const int day_start_hour = 6;
|
||||
const int day_start_hour = DAY_START_HOUR;
|
||||
const int day_end_hour = 18; // Exclusive for repair scheduling (12-hour window)
|
||||
if (current_hour >= day_start_hour && current_hour < day_end_hour) {
|
||||
int repair_window_hours = day_end_hour - day_start_hour;
|
||||
@@ -898,7 +960,7 @@ void update_time() {
|
||||
}
|
||||
}
|
||||
|
||||
if (current_hour == 6) {
|
||||
if (current_hour == DAY_START_HOUR) {
|
||||
if (undead_residents_pending > 0) {
|
||||
undead_residents_count += undead_residents_pending;
|
||||
undead_residents_pending = 0;
|
||||
@@ -930,7 +992,7 @@ void update_time() {
|
||||
attempt_resident_fishing();
|
||||
attempt_resident_fish_smoking();
|
||||
attempt_livestock_production();
|
||||
if (current_hour == 6) {
|
||||
if (current_hour == DAY_START_HOUR) {
|
||||
save_game_state();
|
||||
}
|
||||
}
|
||||
@@ -1021,16 +1083,16 @@ string get_time_string() {
|
||||
}
|
||||
|
||||
void check_ambience_transition() {
|
||||
// Day is 6 (6AM) to 18 (6PM inclusive, so transition starts at hour 18)
|
||||
// Night is 19 (7PM) to 5 (5AM inclusive, so transition starts at hour 5)
|
||||
// Crossfade begins at hour 18 (sunset) and hour 5 (sunrise)
|
||||
int nightStartHour = get_current_night_start_hour();
|
||||
if (!has_daylight_today())
|
||||
return;
|
||||
|
||||
// Start crossfade to night at hour 18
|
||||
if (current_hour == 18 && is_daytime && !crossfade_active) {
|
||||
// Start crossfade to night one hour before the current day's night boundary.
|
||||
if (current_hour == nightStartHour - 1 && is_daytime && !crossfade_active) {
|
||||
start_crossfade(true); // Fade to night
|
||||
}
|
||||
// Start crossfade to day at hour 5
|
||||
else if (current_hour == 5 && !is_daytime && !crossfade_active) {
|
||||
else if (current_hour == DAY_START_HOUR - 1 && !is_daytime && !crossfade_active) {
|
||||
start_crossfade(false); // Fade to day
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user