diff --git a/src/base_system.nvgt b/src/base_system.nvgt index ca843a7..4ef32a6 100644 --- a/src/base_system.nvgt +++ b/src/base_system.nvgt @@ -31,6 +31,41 @@ bool has_burning_fire_in_base() { return false; } +int get_resident_effect_multiplier() { + return blessing_resident_active ? 2 : 1; +} + +int get_resident_success_chance(int base_chance) { + int chance = base_chance * get_resident_effect_multiplier(); + if (chance > 100) chance = 100; + return chance; +} + +int get_resident_break_chance(int base_chance) { + if (!blessing_resident_active) return base_chance; + int reduced = base_chance / get_resident_effect_multiplier(); + if (reduced < 1 && base_chance > 0) reduced = 1; + return reduced; +} + +int get_resident_escape_chance(int base_chance) { + if (!blessing_resident_active) return base_chance; + int reduced = base_chance / get_resident_effect_multiplier(); + if (reduced < 1 && base_chance > 0) reduced = 1; + return reduced; +} + +int get_resident_cooldown(int base_cooldown) { + int cooldown = base_cooldown / get_resident_effect_multiplier(); + if (cooldown < 1) cooldown = 1; + return cooldown; +} + +int apply_resident_damage_bonus(int damage) { + if (!blessing_resident_active) return damage; + return damage * get_resident_effect_multiplier(); +} + void consume_food_for_residents() { int needed = get_food_requirement(); if (needed <= 0) return; @@ -77,13 +112,15 @@ void attempt_resident_fishing() { int caught = 0; int poles_broken = 0; + int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE); + int fishing_chance = get_resident_success_chance(RESIDENT_FISHING_CHANCE); for (int i = 0; i < active_fishers; i++) { // Check for pole breakage during use - if (random(1, 100) <= RESIDENT_TOOL_BREAK_CHANCE) { + if (random(1, 100) <= break_chance) { poles_broken++; continue; } - if (random(1, 100) > RESIDENT_FISHING_CHANCE) continue; + if (random(1, 100) > fishing_chance) continue; if (get_storage_count(ITEM_FISH) >= BASE_STORAGE_MAX) break; add_storage_count(ITEM_FISH, 1); add_storage_fish_weight(random(FISH_WEIGHT_MIN, FISH_WEIGHT_MAX)); @@ -116,19 +153,26 @@ void attempt_resident_fish_smoking() { if (get_storage_count(ITEM_FISH) <= 0) return; if (get_storage_count(ITEM_STICKS) <= 0) return; if (!has_burning_fire_in_base()) return; - if (random(1, 100) > RESIDENT_SMOKE_FISH_CHANCE) return; - int weight = (storage_fish_weights.length() > 0) ? storage_fish_weights[0] : get_default_fish_weight(); - int yield = get_smoked_fish_yield(weight); - if (get_storage_count(ITEM_SMOKED_FISH) + yield > BASE_STORAGE_MAX) return; + int attempts = get_resident_effect_multiplier(); + int smoke_chance = get_resident_success_chance(RESIDENT_SMOKE_FISH_CHANCE); + for (int attempt = 0; attempt < attempts; attempt++) { + if (get_storage_count(ITEM_FISH) <= 0) return; + if (get_storage_count(ITEM_STICKS) <= 0) return; + if (random(1, 100) > smoke_chance) continue; - pop_storage_fish_weight(); - add_storage_count(ITEM_FISH, -1); - add_storage_count(ITEM_STICKS, -1); - add_storage_count(ITEM_SMOKED_FISH, yield); + int weight = (storage_fish_weights.length() > 0) ? storage_fish_weights[0] : get_default_fish_weight(); + int yield = get_smoked_fish_yield(weight); + if (get_storage_count(ITEM_SMOKED_FISH) + yield > BASE_STORAGE_MAX) return; - if (x <= BASE_END) { - speak_with_history("Resident smoked a fish into " + yield + " smoked fish.", true); + pop_storage_fish_weight(); + add_storage_count(ITEM_FISH, -1); + add_storage_count(ITEM_STICKS, -1); + add_storage_count(ITEM_SMOKED_FISH, yield); + + if (x <= BASE_END) { + speak_with_history("Resident smoked a fish into " + yield + " smoked fish.", true); + } } } @@ -190,12 +234,12 @@ int perform_resident_defense() { int damage = 0; if (useSpear && get_storage_count(ITEM_SPEARS) > 0) { - damage = RESIDENT_SPEAR_DAMAGE; + damage = apply_resident_damage_bonus(RESIDENT_SPEAR_DAMAGE); // Weapons don't get consumed on use - they break via daily breakage check // Just play the sound play_1d_with_volume_step("sounds/weapons/spear_swing.ogg", x, BASE_END + 1, false, RESIDENT_DEFENSE_VOLUME_STEP); } else if (get_storage_count(ITEM_SLINGS) > 0 && get_storage_count(ITEM_STONES) > 0) { - damage = random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX); + damage = apply_resident_damage_bonus(random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX)); // Slings use stones as ammo, so consume a stone add_storage_count(ITEM_STONES, -1); play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", x, BASE_END + 1, false, RESIDENT_DEFENSE_VOLUME_STEP); @@ -213,7 +257,7 @@ void attempt_resident_sling_defense() { if (get_storage_count(ITEM_SLINGS) <= 0 || get_storage_count(ITEM_STONES) <= 0) return; // Cooldown between shots - if (resident_sling_timer.elapsed < RESIDENT_SLING_COOLDOWN) return; + if (resident_sling_timer.elapsed < get_resident_cooldown(RESIDENT_SLING_COOLDOWN)) return; // Find nearest enemy within sling range int nearestDistance = SLING_RANGE + 1; @@ -249,7 +293,7 @@ void attempt_resident_sling_defense() { resident_sling_timer.restart(); add_storage_count(ITEM_STONES, -1); - int damage = random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX); + int damage = apply_resident_damage_bonus(random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX)); play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", x, targetPos, false, RESIDENT_DEFENSE_VOLUME_STEP); if (targetIsBandit) { @@ -293,15 +337,16 @@ void process_daily_weapon_breakage() { // Perform breakage checks int spearsBroken = 0; int slingsBroken = 0; + int break_chance = get_resident_break_chance(RESIDENT_WEAPON_BREAK_CHANCE); for (int i = 0; i < spearChecks; i++) { - if (random(1, 100) <= RESIDENT_WEAPON_BREAK_CHANCE) { + if (random(1, 100) <= break_chance) { spearsBroken++; } } for (int i = 0; i < slingChecks; i++) { - if (random(1, 100) <= RESIDENT_WEAPON_BREAK_CHANCE) { + if (random(1, 100) <= break_chance) { slingsBroken++; } } @@ -337,6 +382,9 @@ void attempt_resident_snare_retrieval() { // Need food in storage (same limitation as other resident tasks) if (!has_any_storage_food()) return; + int check_chance = get_resident_success_chance(RESIDENT_SNARE_CHECK_CHANCE); + int escape_chance = get_resident_escape_chance(RESIDENT_SNARE_ESCAPE_CHANCE); + // Check each snare that has a catch for (int i = int(world_snares.length()) - 1; i >= 0; i--) { WorldSnare@ snare = world_snares[i]; @@ -344,10 +392,10 @@ void attempt_resident_snare_retrieval() { if (!snare.active) continue; // Each snare has a chance to be checked by a resident this hour - if (random(1, 100) > RESIDENT_SNARE_CHECK_CHANCE) continue; + if (random(1, 100) > check_chance) continue; // Small chance the game escapes during retrieval (like normal) - if (random(1, 100) <= RESIDENT_SNARE_ESCAPE_CHANCE) { + if (random(1, 100) <= escape_chance) { notify("A " + snare.catch_type + " escaped while a resident checked the snare at x " + snare.position + "."); remove_snare_at(snare.position); continue; @@ -376,7 +424,7 @@ void attempt_resident_snare_retrieval() { } } -// Resident butchering - processes one game per day from storage +// Resident butchering - processes up to two games per day when blessed void attempt_resident_butchering() { // Need residents if (residents_count <= 0) return; @@ -391,100 +439,101 @@ void attempt_resident_butchering() { if (get_storage_count(ITEM_KNIVES) <= 0) return; // Need a fire in base - bool has_fire = false; - for (uint i = 0; i < world_fires.length(); i++) { - if (world_fires[i].position <= BASE_END && world_fires[i].is_burning()) { - has_fire = true; - break; + if (!has_burning_fire_in_base()) return; + + int attempts = get_resident_effect_multiplier(); + int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE); + for (int attempt = 0; attempt < attempts; attempt++) { + // Need game in storage + if (get_storage_count(ITEM_SMALL_GAME) <= 0 && get_storage_count(ITEM_BOAR_CARCASSES) <= 0) return; + if (get_storage_count(ITEM_KNIVES) <= 0) return; + + // Determine what to butcher (prioritize boar carcasses) + string game_type = ""; + bool is_boar = false; + + if (get_storage_count(ITEM_BOAR_CARCASSES) > 0) { + game_type = "boar carcass"; + is_boar = true; + } else if (storage_small_game_types.length() > 0) { + game_type = storage_small_game_types[0]; + } else { + game_type = "small game"; } - } - if (!has_fire) return; - // Determine what to butcher (prioritize boar carcasses) - string game_type = ""; - bool is_boar = false; + // Calculate outputs and check storage capacity + int meat_yield = 0; + int skins_yield = 0; + int feathers_yield = 0; + int down_yield = 0; + int sinew_yield = 0; - if (get_storage_count(ITEM_BOAR_CARCASSES) > 0) { - game_type = "boar carcass"; - is_boar = true; - } else if (storage_small_game_types.length() > 0) { - game_type = storage_small_game_types[0]; - } else { - game_type = "small game"; - } - - // Calculate outputs and check storage capacity - int meat_yield = 0; - int skins_yield = 0; - int feathers_yield = 0; - int down_yield = 0; - int sinew_yield = 0; - - if (game_type == "goose") { - meat_yield = 1; - feathers_yield = random(3, 6); - down_yield = random(1, 3); - } else if (is_boar) { - meat_yield = random(2, 3); - skins_yield = 3; - sinew_yield = 2; - } else { - meat_yield = 1; - skins_yield = 1; - } - - // Check storage capacity for outputs - if (meat_yield > 0 && get_storage_count(ITEM_MEAT) + meat_yield > BASE_STORAGE_MAX) return; - if (skins_yield > 0 && get_storage_count(ITEM_SKINS) + skins_yield > BASE_STORAGE_MAX) return; - if (feathers_yield > 0 && get_storage_count(ITEM_FEATHERS) + feathers_yield > BASE_STORAGE_MAX) return; - if (down_yield > 0 && get_storage_count(ITEM_DOWN) + down_yield > BASE_STORAGE_MAX) return; - if (sinew_yield > 0 && get_storage_count(ITEM_SINEW) + sinew_yield > BASE_STORAGE_MAX) return; - - // Consume the game - if (is_boar) { - add_storage_count(ITEM_BOAR_CARCASSES, -1); - } else { - add_storage_count(ITEM_SMALL_GAME, -1); - if (storage_small_game_types.length() > 0) { - storage_small_game_types.remove_at(0); + if (game_type == "goose") { + meat_yield = 1; + feathers_yield = random(3, 6); + down_yield = random(1, 3); + } else if (is_boar) { + meat_yield = random(2, 3); + skins_yield = 3; + sinew_yield = 2; + } else { + meat_yield = 1; + skins_yield = 1; } - } - // Check for knife breakage - if (random(1, 100) <= RESIDENT_TOOL_BREAK_CHANCE) { - add_storage_count(ITEM_KNIVES, -1); - notify("A resident's knife broke while butchering."); - } + // Check storage capacity for outputs + if (meat_yield > 0 && get_storage_count(ITEM_MEAT) + meat_yield > BASE_STORAGE_MAX) return; + if (skins_yield > 0 && get_storage_count(ITEM_SKINS) + skins_yield > BASE_STORAGE_MAX) return; + if (feathers_yield > 0 && get_storage_count(ITEM_FEATHERS) + feathers_yield > BASE_STORAGE_MAX) return; + if (down_yield > 0 && get_storage_count(ITEM_DOWN) + down_yield > BASE_STORAGE_MAX) return; + if (sinew_yield > 0 && get_storage_count(ITEM_SINEW) + sinew_yield > BASE_STORAGE_MAX) return; - // Add outputs to storage - if (meat_yield > 0) add_storage_count(ITEM_MEAT, meat_yield); - if (skins_yield > 0) add_storage_count(ITEM_SKINS, skins_yield); - if (feathers_yield > 0) add_storage_count(ITEM_FEATHERS, feathers_yield); - if (down_yield > 0) add_storage_count(ITEM_DOWN, down_yield); - if (sinew_yield > 0) add_storage_count(ITEM_SINEW, sinew_yield); - - // Build notification message - string result = "Resident butchered " + game_type + ". Added "; - string[] outputs; - if (meat_yield > 0) outputs.insert_last(meat_yield + " meat"); - if (skins_yield > 0) outputs.insert_last(skins_yield + " skins"); - if (feathers_yield > 0) outputs.insert_last(feathers_yield + " feathers"); - if (down_yield > 0) outputs.insert_last(down_yield + " down"); - if (sinew_yield > 0) outputs.insert_last(sinew_yield + " sinew"); - - for (uint i = 0; i < outputs.length(); i++) { - if (i > 0) { - if (i == outputs.length() - 1) { - result += " and "; - } else { - result += ", "; + // Consume the game + if (is_boar) { + add_storage_count(ITEM_BOAR_CARCASSES, -1); + } else { + add_storage_count(ITEM_SMALL_GAME, -1); + if (storage_small_game_types.length() > 0) { + storage_small_game_types.remove_at(0); } } - result += outputs[i]; - } - result += " to storage."; - notify(result); + // Check for knife breakage + if (random(1, 100) <= break_chance) { + add_storage_count(ITEM_KNIVES, -1); + notify("A resident's knife broke while butchering."); + } + + // Add outputs to storage + if (meat_yield > 0) add_storage_count(ITEM_MEAT, meat_yield); + if (skins_yield > 0) add_storage_count(ITEM_SKINS, skins_yield); + if (feathers_yield > 0) add_storage_count(ITEM_FEATHERS, feathers_yield); + if (down_yield > 0) add_storage_count(ITEM_DOWN, down_yield); + if (sinew_yield > 0) add_storage_count(ITEM_SINEW, sinew_yield); + + // Build notification message + string result = "Resident butchered " + game_type + ". Added "; + string[] outputs; + if (meat_yield > 0) outputs.insert_last(meat_yield + " meat"); + if (skins_yield > 0) outputs.insert_last(skins_yield + " skins"); + if (feathers_yield > 0) outputs.insert_last(feathers_yield + " feathers"); + if (down_yield > 0) outputs.insert_last(down_yield + " down"); + if (sinew_yield > 0) outputs.insert_last(sinew_yield + " sinew"); + + for (uint i = 0; i < outputs.length(); i++) { + if (i > 0) { + if (i == outputs.length() - 1) { + result += " and "; + } else { + result += ", "; + } + } + result += outputs[i]; + } + result += " to storage."; + + notify(result); + } } // Resident resource collection @@ -504,14 +553,16 @@ void attempt_resident_collection() { // Each active collector has a 10% chance to collect something int baskets_broken = 0; + int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE); + int collection_chance = get_resident_success_chance(RESIDENT_COLLECTION_CHANCE); for (int i = 0; i < active_collectors; i++) { // Check for basket breakage during use - if (random(1, 100) <= RESIDENT_TOOL_BREAK_CHANCE) { + if (random(1, 100) <= break_chance) { baskets_broken++; continue; } - if (random(1, 100) > RESIDENT_COLLECTION_CHANCE) continue; + if (random(1, 100) > collection_chance) continue; // Determine what to collect (weighted random) // Sticks and vines more common, logs and stones less common @@ -573,16 +624,18 @@ void attempt_resident_foraging() { int baskets_produced = 0; int baskets_broken = 0; + int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE); + int forage_chance = get_resident_success_chance(RESIDENT_FORAGING_CHANCE); for (int i = 0; i < active_foragers; i++) { // Check for basket breakage during foraging - if (random(1, 100) <= RESIDENT_TOOL_BREAK_CHANCE) { + if (random(1, 100) <= break_chance) { baskets_broken++; continue; } // Check if foraging succeeds - if (random(1, 100) > RESIDENT_FORAGING_CHANCE) continue; + if (random(1, 100) > forage_chance) continue; // Check storage capacity if (get_storage_count(ITEM_BASKET_FOOD) >= BASE_STORAGE_MAX) break; diff --git a/src/constants.nvgt b/src/constants.nvgt index 52ce5a0..81e7cab 100644 --- a/src/constants.nvgt +++ b/src/constants.nvgt @@ -23,6 +23,7 @@ const int BASE_STORAGE_MAX = 50; const int BLESSING_HEAL_AMOUNT = 3; const int BLESSING_BARRICADE_REPAIR = 20; const int BLESSING_SPEED_DURATION = 300000; +const int BLESSING_RESIDENT_DURATION = 300000; const int BLESSING_TRIGGER_CHANCE = 10; const int BLESSING_WALK_SPEED = 320; const int FISH_WEIGHT_MIN = 1; diff --git a/src/enemies/bandit.nvgt b/src/enemies/bandit.nvgt index 3f18305..492f169 100644 --- a/src/enemies/bandit.nvgt +++ b/src/enemies/bandit.nvgt @@ -84,7 +84,12 @@ void spawn_bandit(int expansion_start, int expansion_end) { Bandit@ b = Bandit(spawn_x, expansion_start, expansion_end); bandits.insert_last(b); // Play looping sound that follows the bandit - b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, spawn_x, true, BANDIT_SOUND_VOLUME_STEP); + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + if (areaStarts.length() == 0 || range_overlaps_active_areas(spawn_x, spawn_x, areaStarts, areaEnds)) { + b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, spawn_x, true, BANDIT_SOUND_VOLUME_STEP); + } } bool can_bandit_attack_player(Bandit@ bandit) { @@ -174,9 +179,14 @@ void try_attack_barricade_bandit(Bandit@ bandit) { } } -void update_bandit(Bandit@ bandit) { +void update_bandit(Bandit@ bandit, bool audio_active) { // Update looping sound position - if (bandit.sound_handle != -1 && p.sound_is_active(bandit.sound_handle)) { + if (!audio_active) { + if (bandit.sound_handle != -1) { + p.destroy_sound(bandit.sound_handle); + bandit.sound_handle = -1; + } + } else if (bandit.sound_handle != -1 && p.sound_is_active(bandit.sound_handle)) { p.update_sound_1d(bandit.sound_handle, bandit.position); } else if (bandit.sound_handle == -1 || !p.sound_is_active(bandit.sound_handle)) { // Restart looping sound if it stopped @@ -227,7 +237,9 @@ void update_bandit(Bandit@ bandit) { bandit.wander_direction = -bandit.wander_direction; } else { bandit.position = target_x; - play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP); + if (audio_active) { + play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP); + } } } else { // Hit map boundary, reverse direction @@ -270,13 +282,21 @@ void update_bandit(Bandit@ bandit) { } bandit.position = target_x; - play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP); + if (audio_active) { + play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP); + } } } void update_bandits() { + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + bool limit_audio = (areaStarts.length() > 0); + for (uint i = 0; i < bandits.length(); i++) { - update_bandit(bandits[i]); + bool audio_active = !limit_audio || range_overlaps_active_areas(bandits[i].position, bandits[i].position, areaStarts, areaEnds); + update_bandit(bandits[i], audio_active); } } diff --git a/src/enemies/flying_creatures.nvgt b/src/enemies/flying_creatures.nvgt index 1f69d4e..7691b03 100644 --- a/src/enemies/flying_creatures.nvgt +++ b/src/enemies/flying_creatures.nvgt @@ -226,11 +226,16 @@ bool spawn_flying_creature(string creature_type) { FlyingCreature@ c = FlyingCreature(creature_type, spawn_x, area_start, area_end, cfg); flying_creatures.insert_last(c); // Play looping sound that follows the flying creature - c.sound_handle = play_1d_with_volume_step(c.voice_sound, x, spawn_x, true, cfg.sound_volume_step); + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + if (areaStarts.length() == 0 || range_overlaps_active_areas(spawn_x, spawn_x, areaStarts, areaEnds)) { + c.sound_handle = play_1d_with_volume_step(c.voice_sound, x, spawn_x, true, cfg.sound_volume_step); + } return true; } -void update_flying_creature(FlyingCreature@ creature) { +void update_flying_creature(FlyingCreature@ creature, bool audio_active) { FlyingCreatureConfig@ cfg = get_flying_creature_config(creature.creature_type); if (cfg is null) return; @@ -240,7 +245,11 @@ void update_flying_creature(FlyingCreature@ creature) { creature.fade_timer.restart(); } - if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) { + if (!audio_active && creature.sound_handle != -1) { + p.destroy_sound(creature.sound_handle); + creature.sound_handle = -1; + creature.ready_to_remove = true; + } else if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) { float progress = float(creature.fade_timer.elapsed) / float(FLYING_CREATURE_FADE_OUT_DURATION); if (progress < 0.0) progress = 0.0; if (progress > 1.0) progress = 1.0; @@ -265,7 +274,12 @@ void update_flying_creature(FlyingCreature@ creature) { } // Update looping sound position - if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) { + if (!audio_active) { + if (creature.sound_handle != -1) { + p.destroy_sound(creature.sound_handle); + creature.sound_handle = -1; + } + } else if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) { p.update_sound_1d(creature.sound_handle, creature.position); } else if (creature.sound_handle == -1 || !p.sound_is_active(creature.sound_handle)) { // Restart looping sound if it stopped @@ -301,7 +315,7 @@ void update_flying_creature(FlyingCreature@ creature) { } if (target_x >= 0 && target_x < MAP_SIZE) { creature.position = target_x; - if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) { + if (audio_active && creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) { p.update_sound_1d(creature.sound_handle, creature.position); } } @@ -314,15 +328,18 @@ void update_flying_creature(FlyingCreature@ creature) { if (creature.fall_sound_handle != -1) { p.destroy_sound(creature.fall_sound_handle); + creature.fall_sound_handle = -1; } float pitch_percent = 50.0 + (50.0 * (float(creature.height) / float(cfg.max_height))); if (pitch_percent < 50.0) pitch_percent = 50.0; if (pitch_percent > 100.0) pitch_percent = 100.0; - creature.fall_sound_handle = p.play_extended_1d(cfg.fall_sound, x, creature.position, 0, 0, true, 0, 0.0, 0.0, pitch_percent); - if (creature.fall_sound_handle != -1) { - p.update_sound_positioning_values(creature.fall_sound_handle, -1.0, cfg.sound_volume_step, true); + if (audio_active) { + creature.fall_sound_handle = p.play_extended_1d(cfg.fall_sound, x, creature.position, 0, 0, true, 0, 0.0, 0.0, pitch_percent); + if (creature.fall_sound_handle != -1) { + p.update_sound_positioning_values(creature.fall_sound_handle, -1.0, cfg.sound_volume_step, true); + } } if (creature.height <= 0) { @@ -340,8 +357,14 @@ void update_flying_creature(FlyingCreature@ creature) { } void update_flying_creatures() { + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + bool limit_audio = (areaStarts.length() > 0); + for (uint i = 0; i < flying_creatures.length(); i++) { - update_flying_creature(flying_creatures[i]); + bool audio_active = !limit_audio || range_overlaps_active_areas(flying_creatures[i].position, flying_creatures[i].position, areaStarts, areaEnds); + update_flying_creature(flying_creatures[i], audio_active); if (flying_creatures[i].health <= 0) { if (flying_creatures[i].state == "falling" && flying_creatures[i].height <= 0) { diff --git a/src/enemies/ground_game.nvgt b/src/enemies/ground_game.nvgt index b0d691b..0bfe196 100644 --- a/src/enemies/ground_game.nvgt +++ b/src/enemies/ground_game.nvgt @@ -77,7 +77,12 @@ void spawn_ground_game(int expansion_start, int expansion_end) { GroundGame@ b = GroundGame(spawn_x, expansion_start, expansion_end, "boar"); ground_games.insert_last(b); // Play looping sound that follows the boar - b.sound_handle = play_1d_with_volume_step(b.voice_sound, x, spawn_x, true, BOAR_SOUND_VOLUME_STEP); + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + if (areaStarts.length() == 0 || range_overlaps_active_areas(spawn_x, spawn_x, areaStarts, areaEnds)) { + b.sound_handle = play_1d_with_volume_step(b.voice_sound, x, spawn_x, true, BOAR_SOUND_VOLUME_STEP); + } } bool can_ground_game_attack_player(GroundGame@ game) { @@ -109,9 +114,14 @@ bool try_attack_player_ground_game(GroundGame@ game) { return true; } -void update_ground_game(GroundGame@ game) { +void update_ground_game(GroundGame@ game, bool audio_active) { // Update looping sound position - if (game.sound_handle != -1 && p.sound_is_active(game.sound_handle)) { + if (!audio_active) { + if (game.sound_handle != -1) { + p.destroy_sound(game.sound_handle); + game.sound_handle = -1; + } + } else if (game.sound_handle != -1 && p.sound_is_active(game.sound_handle)) { p.update_sound_1d(game.sound_handle, game.position); } else if (game.sound_handle == -1 || !p.sound_is_active(game.sound_handle)) { // Restart looping sound if it stopped for some reason @@ -153,7 +163,9 @@ void update_ground_game(GroundGame@ game) { // Don't leave area or enter base if (target >= game.area_start && target <= game.area_end && target > BASE_END) { game.position = target; - play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP); + if (audio_active) { + play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP); + } } } else { // Wandering @@ -166,7 +178,9 @@ void update_ground_game(GroundGame@ game) { // Don't leave area or enter base if (target >= game.area_start && target <= game.area_end && target > BASE_END) { game.position = target; - play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP); + if (audio_active) { + play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP); + } } else { game.wander_direction = -game.wander_direction; // Turn around } @@ -175,8 +189,14 @@ void update_ground_game(GroundGame@ game) { } void update_ground_games() { + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + bool limit_audio = (areaStarts.length() > 0); + for (uint i = 0; i < ground_games.length(); i++) { - update_ground_game(ground_games[i]); + bool audio_active = !limit_audio || range_overlaps_active_areas(ground_games[i].position, ground_games[i].position, areaStarts, areaEnds); + update_ground_game(ground_games[i], audio_active); } } diff --git a/src/enemies/undead.nvgt b/src/enemies/undead.nvgt index 0cbe989..1d2d299 100644 --- a/src/enemies/undead.nvgt +++ b/src/enemies/undead.nvgt @@ -62,7 +62,12 @@ void spawn_undead() { Undead@ z = Undead(spawn_x, "zombie"); undeads.insert_last(z); // Play looping sound that follows the zombie - z.sound_handle = play_1d_with_volume_step(z.voice_sound, x, spawn_x, true, ZOMBIE_SOUND_VOLUME_STEP); + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + if (areaStarts.length() == 0 || range_overlaps_active_areas(spawn_x, spawn_x, areaStarts, areaEnds)) { + z.sound_handle = play_1d_with_volume_step(z.voice_sound, x, spawn_x, true, ZOMBIE_SOUND_VOLUME_STEP); + } } void try_attack_barricade_undead(Undead@ undead) { @@ -128,9 +133,14 @@ bool try_attack_player_undead(Undead@ undead) { return true; } -void update_undead(Undead@ undead) { +void update_undead(Undead@ undead, bool audio_active) { // Update looping sound position - if (undead.sound_handle != -1 && p.sound_is_active(undead.sound_handle)) { + if (!audio_active) { + if (undead.sound_handle != -1) { + p.destroy_sound(undead.sound_handle); + undead.sound_handle = -1; + } + } else if (undead.sound_handle != -1 && p.sound_is_active(undead.sound_handle)) { p.update_sound_1d(undead.sound_handle, undead.position); } else if (undead.sound_handle == -1 || !p.sound_is_active(undead.sound_handle)) { // Restart looping sound if it stopped for some reason @@ -175,7 +185,9 @@ void update_undead(Undead@ undead) { } undead.position = target_x; - play_creature_footstep(x, undead.position, BASE_END, GRASS_END, ZOMBIE_FOOTSTEP_MAX_DISTANCE, ZOMBIE_SOUND_VOLUME_STEP); + if (audio_active) { + play_creature_footstep(x, undead.position, BASE_END, GRASS_END, ZOMBIE_FOOTSTEP_MAX_DISTANCE, ZOMBIE_SOUND_VOLUME_STEP); + } } void update_undeads() { @@ -195,8 +207,14 @@ void update_undeads() { spawn_undead(); } + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + bool limit_audio = (areaStarts.length() > 0); + for (uint i = 0; i < undeads.length(); i++) { - update_undead(undeads[i]); + bool audio_active = !limit_audio || range_overlaps_active_areas(undeads[i].position, undeads[i].position, areaStarts, areaEnds); + update_undead(undeads[i], audio_active); } } diff --git a/src/environment.nvgt b/src/environment.nvgt index b4e457e..1c9975f 100644 --- a/src/environment.nvgt +++ b/src/environment.nvgt @@ -481,9 +481,22 @@ void normalize_tree_positions() { } void update_environment() { + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + bool limit_audio = (areaStarts.length() > 0); + for(uint i = 0; i < trees.length(); i++) { - trees[i].update(); trees[i].try_regen(); + + if (limit_audio && !range_overlaps_active_areas(trees[i].position, trees[i].position, areaStarts, areaEnds)) { + if (trees[i].sound_handle != -1) { + p.destroy_sound(trees[i].sound_handle); + trees[i].sound_handle = -1; + } + continue; + } + trees[i].update(); } } diff --git a/src/menus/action_menu.nvgt b/src/menus/action_menu.nvgt index a9a3dcb..3c0a494 100644 --- a/src/menus/action_menu.nvgt +++ b/src/menus/action_menu.nvgt @@ -7,6 +7,65 @@ void check_action_menu(int x) { } } +WorldSnare@ get_snare_within_range(int pos, int range) { + WorldSnare@ nearest = null; + int nearest_distance = range + 1; + for (uint i = 0; i < world_snares.length(); i++) { + int dist = abs(world_snares[i].position - pos); + if (dist <= range && dist < nearest_distance) { + nearest_distance = dist; + @nearest = @world_snares[i]; + } + } + return nearest; +} + +string get_fire_intensity_label(int fuel_remaining) { + int hours_remaining = fuel_remaining / 60000; + if (hours_remaining >= 8) return "Giant blaze"; + if (hours_remaining >= 2) return "Small fire"; + return "A few glowing coals"; +} + +string get_fire_time_estimate(int fuel_remaining) { + int approx_hours = (fuel_remaining + 30000) / 60000; + if (approx_hours <= 0) return "less than 1 hour"; + if (approx_hours == 1) return "approximately 1 hour"; + return "approximately " + approx_hours + " hours"; +} + +void check_fire_status(WorldFire@ fire) { + if (fire == null) { + speak_with_history("No fire nearby.", true); + return; + } + string label = get_fire_intensity_label(fire.fuel_remaining); + string estimate = get_fire_time_estimate(fire.fuel_remaining); + speak_with_history(label + ". " + estimate + " remaining.", true); +} + +void check_snare_status(WorldSnare@ snare) { + if (snare == null) { + speak_with_history("No snare nearby.", true); + return; + } + if (snare.has_catch) { + speak_with_history("Snare holds a " + snare.catch_type + ".", true); + } else if (!snare.active) { + speak_with_history("Snare is set but not active yet.", true); + } else { + speak_with_history("Snare is set and empty.", true); + } +} + +void check_fishing_status() { + if (fish_on_line) { + speak_with_history("Fish on the line.", true); + return; + } + speak_with_history("No fish on the line.", true); +} + void try_place_snare(int x) { if (get_personal_count(ITEM_SNARES) > 0) { // Prevent placing in base area @@ -153,10 +212,13 @@ void run_action_menu(int x) { int selection = 0; string[] options; int[] action_types; // Track what action each option corresponds to + const int check_range = 2; // Check if fire is nearby WorldFire@ nearby_fire = get_fire_near(x); bool can_feed_fire = nearby_fire != null; + WorldFire@ check_fire = get_fire_within_range(x, check_range); + WorldSnare@ check_snare = get_snare_within_range(x, check_range); // Build menu options dynamically options.insert_last("Place Snare"); @@ -182,6 +244,19 @@ void run_action_menu(int x) { action_types.insert_last(4); } + if (check_fire != null) { + options.insert_last("Check fire"); + action_types.insert_last(5); + } + if (check_snare != null) { + options.insert_last("Check snare"); + action_types.insert_last(6); + } + if (line_in_water || fish_on_line || is_reeling || is_casting) { + options.insert_last("Check fishing pole"); + action_types.insert_last(7); + } + while(true) { wait(5); menu_background_tick(); @@ -214,6 +289,12 @@ void run_action_menu(int x) { try_feed_fire_log(nearby_fire); } else if (action == 4) { try_burn_incense(); + } else if (action == 5) { + check_fire_status(check_fire); + } else if (action == 6) { + check_snare_status(check_snare); + } else if (action == 7) { + check_fishing_status(); } break; } @@ -230,6 +311,12 @@ void run_action_menu(int x) { try_feed_fire_log_max(nearby_fire); } else if (action == 4) { try_burn_incense_max(); + } else if (action == 5) { + check_fire_status(check_fire); + } else if (action == 6) { + check_snare_status(check_snare); + } else if (action == 7) { + check_fishing_status(); } break; } diff --git a/src/menus/base_info.nvgt b/src/menus/base_info.nvgt index 4a99b6f..c2d3a50 100644 --- a/src/menus/base_info.nvgt +++ b/src/menus/base_info.nvgt @@ -12,7 +12,11 @@ void run_base_info_menu() { int selection = 0; string[] options; options.insert_last("Barricade health " + barricade_health + " of " + BARRICADE_MAX_HEALTH); - options.insert_last("Residents " + residents_count); + string resident_status = "Residents " + residents_count; + if (blessing_resident_active) { + resident_status += " (blessed)"; + } + options.insert_last(resident_status); if (world_storages.length() > 0) { options.insert_last("Storage built. Total items " + get_storage_total_items()); diff --git a/src/notify.nvgt b/src/notify.nvgt index 728e641..88a4a12 100644 --- a/src/notify.nvgt +++ b/src/notify.nvgt @@ -26,7 +26,9 @@ void notify(string message) { void update_notifications() { if (notification_queue.length() == 0) { - notification_active = false; + if (notification_active && notification_timer.elapsed >= NOTIFICATION_DELAY) { + notification_active = false; + } notification_sound_handle = -1; return; } diff --git a/src/player.nvgt b/src/player.nvgt index 0774a3c..0a82f64 100644 --- a/src/player.nvgt +++ b/src/player.nvgt @@ -62,6 +62,8 @@ int incense_hours_remaining = 0; bool incense_burning = false; bool blessing_speed_active = false; timer blessing_speed_timer; +bool blessing_resident_active = false; +timer blessing_resident_timer; // Timers timer walktimer; diff --git a/src/save_system.nvgt b/src/save_system.nvgt index f42565b..09659f3 100644 --- a/src/save_system.nvgt +++ b/src/save_system.nvgt @@ -202,6 +202,7 @@ void reset_game_state() { incense_hours_remaining = 0; incense_burning = false; blessing_speed_active = false; + blessing_resident_active = false; // Reset inventory using the registry system reset_inventory(); @@ -978,7 +979,12 @@ bool load_game_state() { bandits.insert_last(b); // Start looping sound for loaded bandit - b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, b.position, true, BANDIT_SOUND_VOLUME_STEP); + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + if (areaStarts.length() == 0 || range_overlaps_active_areas(b.position, b.position, areaStarts, areaEnds)) { + b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, b.position, true, BANDIT_SOUND_VOLUME_STEP); + } } string[] mountainData = get_string_list_or_split(saveData, "mountains_data"); diff --git a/src/time_system.nvgt b/src/time_system.nvgt index 4c38245..d297dba 100644 --- a/src/time_system.nvgt +++ b/src/time_system.nvgt @@ -317,6 +317,10 @@ void update_blessings() { update_max_health_from_equipment(); speak_with_history("The speed blessing fades.", true); } + if (blessing_resident_active && blessing_resident_timer.elapsed >= BLESSING_RESIDENT_DURATION) { + blessing_resident_active = false; + speak_with_history("The residents' purpose fades.", true); + } } void attempt_blessing() { @@ -328,6 +332,7 @@ void attempt_blessing() { if (player_health < max_health) options.insert_last(0); if (!blessing_speed_active) options.insert_last(1); if (barricade_health < BARRICADE_MAX_HEALTH) options.insert_last(2); + if (residents_count > 0 && !blessing_resident_active) options.insert_last(3); if (options.length() == 0) return; int choice = options[random(0, options.length() - 1)]; @@ -358,6 +363,10 @@ void attempt_blessing() { ? "A divine force repairs the barricade. +" + gained + " health." : "A divine force surrounds the barricade."; notify(god_name + " favor shines upon you. " + bonus); + } else if (choice == 3) { + blessing_resident_active = true; + blessing_resident_timer.restart(); + notify(god_name + " radiance fills residents with purpose."); } } @@ -401,7 +410,7 @@ void update_time() { if (is_daytime && residents_count > 0 && barricade_health < BARRICADE_MAX_HEALTH && current_hour % 4 == 0) { if (has_any_storage_food()) { - int gained = add_barricade_health(residents_count); + int gained = add_barricade_health(residents_count * get_resident_effect_multiplier()); if (gained > 0 && x <= BASE_END) { speak_with_history("Residents repaired the barricade. +" + gained + " health.", true); } @@ -527,6 +536,31 @@ void start_crossfade(bool to_night) { void update_crossfade() { if (!crossfade_active) return; + // If a handle went inactive mid-fade, cancel and restart ambience to avoid fading unrelated sounds. + if (crossfade_to_night) { + if (day_sound_handle == -1 || !p.sound_is_active(day_sound_handle)) { + crossfade_active = false; + update_ambience(true); + return; + } + if (night_sound_handle == -1 || !p.sound_is_active(night_sound_handle)) { + crossfade_active = false; + update_ambience(true); + return; + } + } else { + if (night_sound_handle == -1 || !p.sound_is_active(night_sound_handle)) { + crossfade_active = false; + update_ambience(true); + return; + } + if (day_sound_handle == -1 || !p.sound_is_active(day_sound_handle)) { + crossfade_active = false; + update_ambience(true); + return; + } + } + float progress = float(crossfade_timer.elapsed) / float(CROSSFADE_DURATION); if (progress > 1.0) progress = 1.0; diff --git a/src/world/mountains.nvgt b/src/world/mountains.nvgt index 6fbaf4d..4477e0a 100644 --- a/src/world/mountains.nvgt +++ b/src/world/mountains.nvgt @@ -360,12 +360,24 @@ bool is_mountain_stream_at(int world_x) { return mountain.is_stream_at(world_x); } -void update_mountains() { +void update_mountains_with_audio_areas(int[]@ areaStarts, int[]@ areaEnds) { + bool limit_audio = (areaStarts.length() > 0); for (uint i = 0; i < world_mountains.length(); i++) { + if (limit_audio && !range_overlaps_active_areas(world_mountains[i].start_position, world_mountains[i].end_position, areaStarts, areaEnds)) { + world_mountains[i].destroy(); + continue; + } world_mountains[i].update(); } } +void update_mountains() { + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + update_mountains_with_audio_areas(areaStarts, areaEnds); +} + void clear_mountains() { for (uint i = 0; i < world_mountains.length(); i++) { world_mountains[i].destroy(); diff --git a/src/world/world_drops.nvgt b/src/world/world_drops.nvgt index c57a046..0588e3a 100644 --- a/src/world/world_drops.nvgt +++ b/src/world/world_drops.nvgt @@ -49,7 +49,16 @@ void add_world_drop(int pos, string type) { } void update_world_drops() { + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + bool limit_audio = (areaStarts.length() > 0); + for (uint i = 0; i < world_drops.length(); i++) { + if (limit_audio && !range_overlaps_active_areas(world_drops[i].position, world_drops[i].position, areaStarts, areaEnds)) { + world_drops[i].destroy(); + continue; + } world_drops[i].update(); } } diff --git a/src/world/world_fires.nvgt b/src/world/world_fires.nvgt index 1c76006..25de87d 100644 --- a/src/world/world_fires.nvgt +++ b/src/world/world_fires.nvgt @@ -87,9 +87,20 @@ void add_world_fire(int pos) { } void update_fires() { + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + bool limit_audio = (areaStarts.length() > 0); + // Update all fires and remove any that have burned out for (uint i = 0; i < world_fires.length(); i++) { world_fires[i].update(); + if (limit_audio && !range_overlaps_active_areas(world_fires[i].position, world_fires[i].position, areaStarts, areaEnds)) { + if (world_fires[i].sound_handle != -1) { + p.destroy_sound(world_fires[i].sound_handle); + world_fires[i].sound_handle = -1; + } + } } // Remove dead fires diff --git a/src/world/world_snares.nvgt b/src/world/world_snares.nvgt index f4f3bb6..3959111 100644 --- a/src/world/world_snares.nvgt +++ b/src/world/world_snares.nvgt @@ -149,7 +149,19 @@ void check_snare_collision(int player_x) { } void update_snares() { + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + bool limit_audio = (areaStarts.length() > 0); + for (int i = int(world_snares.length()) - 1; i >= 0; i--) { - world_snares[i].update(); + WorldSnare@ snare = world_snares[i]; + snare.update(); + if (limit_audio && !range_overlaps_active_areas(snare.position, snare.position, areaStarts, areaEnds)) { + if (snare.sound_handle != -1) { + p.destroy_sound(snare.sound_handle); + snare.sound_handle = -1; + } + } } } diff --git a/src/world/world_streams.nvgt b/src/world/world_streams.nvgt index 34f0234..4548157 100644 --- a/src/world/world_streams.nvgt +++ b/src/world/world_streams.nvgt @@ -66,15 +66,120 @@ class WorldStream { } WorldStream@[] world_streams; +string get_expanded_area_type(int index) { + string terrain = expanded_terrain_types[index]; + if (terrain.find("mountain:") == 0) { + return "mountain"; + } + return terrain; +} + +bool get_audio_area_bounds_for_position(int pos, int &out areaStart, int &out areaEnd) { + if (pos <= BASE_END) { + areaStart = 0; + areaEnd = BASE_END; + return true; + } + if (pos <= GRASS_END) { + areaStart = BASE_END + 1; + areaEnd = GRASS_END; + return true; + } + if (pos <= GRAVEL_END) { + areaStart = GRAVEL_START; + areaEnd = GRAVEL_END; + return true; + } + + if (expanded_area_start == -1 || pos < expanded_area_start || pos > expanded_area_end) { + return false; + } + + int index = pos - expanded_area_start; + int total = int(expanded_terrain_types.length()); + if (index < 0 || index >= total) return false; + + string areaType = get_expanded_area_type(index); + int left = index; + while (left > 0) { + if (get_expanded_area_type(left - 1) != areaType) break; + left--; + } + + int right = index; + while (right + 1 < total) { + if (get_expanded_area_type(right + 1) != areaType) break; + right++; + } + + areaStart = expanded_area_start + left; + areaEnd = expanded_area_start + right; + return true; +} + +void get_active_audio_areas(int[]@ areaStarts, int[]@ areaEnds) { + areaStarts.resize(0); + areaEnds.resize(0); + + int currentStart = 0; + int currentEnd = 0; + if (!get_audio_area_bounds_for_position(x, currentStart, currentEnd)) return; + + areaStarts.insert_last(currentStart); + areaEnds.insert_last(currentEnd); + + if (currentStart > 0) { + int prevStart = 0; + int prevEnd = 0; + if (get_audio_area_bounds_for_position(currentStart - 1, prevStart, prevEnd)) { + if (prevStart != currentStart || prevEnd != currentEnd) { + areaStarts.insert_last(prevStart); + areaEnds.insert_last(prevEnd); + } + } + } + + if (currentEnd + 1 < MAP_SIZE) { + int nextStart = 0; + int nextEnd = 0; + if (get_audio_area_bounds_for_position(currentEnd + 1, nextStart, nextEnd)) { + if (nextStart != currentStart || nextEnd != currentEnd) { + areaStarts.insert_last(nextStart); + areaEnds.insert_last(nextEnd); + } + } + } +} + +bool range_overlaps_active_areas(int rangeStart, int rangeEnd, int[]@ areaStarts, int[]@ areaEnds) { + for (uint i = 0; i < areaStarts.length(); i++) { + if (rangeEnd >= areaStarts[i] && rangeStart <= areaEnds[i]) { + return true; + } + } + return false; +} + void add_world_stream(int start_pos, int width) { WorldStream@ s = WorldStream(start_pos, width); world_streams.insert_last(s); } void update_streams() { + int[] areaStarts; + int[] areaEnds; + get_active_audio_areas(areaStarts, areaEnds); + bool limit_audio = areaStarts.length() > 0; + for (uint i = 0; i < world_streams.length(); i++) { + if (limit_audio && !range_overlaps_active_areas(world_streams[i].start_position, world_streams[i].end_position, areaStarts, areaEnds)) { + world_streams[i].destroy(); + continue; + } world_streams[i].update(); } + + update_mountains_with_audio_areas(areaStarts, areaEnds); } WorldStream@ get_stream_at(int pos) { diff --git a/src/world_state.nvgt b/src/world_state.nvgt index cafdb35..e918582 100644 --- a/src/world_state.nvgt +++ b/src/world_state.nvgt @@ -17,14 +17,3 @@ // - world_streams.nvgt - Streams for fishing and creature spawning // - mountains.nvgt - Mountain ranges with procedural terrain generation // - barricade.nvgt - Base defense system - -// Legacy update function - retained for compatibility -// Note: This is largely obsolete as individual update functions are called from main loop -void update_world_objects() { - for (uint i = 0; i < world_snares.length(); i++) { - world_snares[i].update(); - } - for (uint i = 0; i < world_fires.length(); i++) { - world_fires[i].update(); - } -}