// World Objects // Small game types that can be caught in snares string[] small_game_types = {"rabbit", "squirrel", "raccoon", "opossum", "groundhog"}; int barricade_health = 0; bool barricade_initialized = false; int residents_count = 0; string[] zombie_sounds = {"sounds/enemies/zombie1.ogg"}; string[] bandit_sounds = {"sounds/enemies/bandit1.ogg", "sounds/enemies/bandit2.ogg"}; class Zombie { int position; int health; string voice_sound; int sound_handle; timer move_timer; timer groan_timer; timer attack_timer; int next_groan_delay; Zombie(int pos) { position = pos; health = ZOMBIE_HEALTH; int sound_index = random(0, zombie_sounds.length() - 1); voice_sound = zombie_sounds[sound_index]; sound_handle = -1; move_timer.restart(); groan_timer.restart(); attack_timer.restart(); next_groan_delay = random(ZOMBIE_GROAN_MIN_DELAY, ZOMBIE_GROAN_MAX_DELAY); } } Zombie@[] zombies; class Bandit { int position; int health; string alert_sound; string weapon_type; // "spear" or "axe" timer move_timer; timer alert_timer; timer attack_timer; int next_alert_delay; int move_interval; // Wandering behavior properties string behavior_state; // "aggressive" or "wandering" int wander_direction; // -1, 0, or 1 timer wander_direction_timer; int wander_direction_change_interval; Bandit(int pos, int expansion_start, int expansion_end) { // Spawn somewhere in the expanded area position = random(expansion_start, expansion_end); health = BANDIT_HEALTH; // Choose random alert sound int sound_index = random(0, bandit_sounds.length() - 1); alert_sound = bandit_sounds[sound_index]; // Choose random weapon weapon_type = (random(0, 1) == 0) ? "spear" : "axe"; // Random movement speed within range move_interval = random(BANDIT_MOVE_INTERVAL_MIN, BANDIT_MOVE_INTERVAL_MAX); move_timer.restart(); alert_timer.restart(); attack_timer.restart(); next_alert_delay = random(BANDIT_ALERT_MIN_DELAY, BANDIT_ALERT_MAX_DELAY); // Initialize wandering behavior (start aggressive during invasion) behavior_state = "aggressive"; wander_direction = 0; wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX); wander_direction_timer.restart(); } } Bandit@[] bandits; string get_random_small_game() { int index = random(0, small_game_types.length() - 1); return small_game_types[index]; } class WorldSnare { int position; bool has_catch; string catch_type; // What type of small game was caught int catch_chance; int escape_chance; int sound_handle; timer minute_timer; bool active; // To prevent immediate breakage on placement WorldSnare(int pos) { position = pos; has_catch = false; catch_type = ""; catch_chance = 5; escape_chance = 5; active = false; // Becomes active when player steps off sound_handle = -1; minute_timer.restart(); } void update() { // Activate if player moves away if (!active && x != position) { active = true; minute_timer.restart(); } // Limit snare sound to 2 tiles distance if (abs(x - position) <= 2) { if (sound_handle == -1 || !p.sound_is_active(sound_handle)) { sound_handle = p.play_1d("sounds/actions/set_snare.ogg", x, position, true); } } else { if (sound_handle != -1) { p.destroy_sound(sound_handle); sound_handle = -1; } } // Every minute logic (only when active) if (active && minute_timer.elapsed >= 60000) { minute_timer.restart(); if (has_catch) { // Animal trying to escape if (escape_chance < 95) escape_chance += 5; int roll = random(1, 100); if (roll <= escape_chance) { // Animal escaped! notify("A " + catch_type + " escaped from your snare at x " + position + " y 0!"); remove_snare_at(position); return; } } else { // Trying to catch small game if (catch_chance < 75) catch_chance += 5; int roll = random(1, 100); if (roll <= catch_chance) { // Caught something! has_catch = true; catch_type = get_random_small_game(); escape_chance = 5; // Reset escape chance notify(catch_type + " caught in snare at x " + position + " y 0!"); } } } } void destroy() { if (sound_handle != -1) { p.destroy_sound(sound_handle); sound_handle = -1; } } } WorldSnare@[] world_snares; class WorldFire { int position; int sound_handle; timer fuel_timer; int fuel_remaining; bool low_fuel_warned; WorldFire(int pos) { position = pos; sound_handle = -1; fuel_remaining = 720000; // Start with 12 minutes (12 hours in-game) low_fuel_warned = false; fuel_timer.restart(); } void add_fuel(int amount) { fuel_remaining += amount; low_fuel_warned = false; } bool is_burning() { return fuel_remaining > 0; } void update() { // Update fuel if (fuel_remaining > 0) { int elapsed = fuel_timer.elapsed; fuel_timer.restart(); fuel_remaining -= elapsed; // Warn when fuel is low (30 seconds remaining) if (!low_fuel_warned && fuel_remaining <= 30000 && fuel_remaining > 0) { low_fuel_warned = true; notify("Fire at " + position + " is getting low!"); } // Fire went out if (fuel_remaining <= 0) { fuel_remaining = 0; notify("Fire at " + position + " has gone out."); if (sound_handle != -1) { p.destroy_sound(sound_handle); sound_handle = -1; } return; } } // Limit fire sound to 2 tiles distance (only if burning) if (is_burning()) { if (abs(x - position) <= 2) { if (sound_handle == -1 || !p.sound_is_active(sound_handle)) { sound_handle = p.play_1d("sounds/items/fire.ogg", x, position, true); } } else { if (sound_handle != -1) { p.destroy_sound(sound_handle); sound_handle = -1; } } } } void destroy() { if (sound_handle != -1) { p.destroy_sound(sound_handle); sound_handle = -1; } } } WorldFire@[] world_fires; class WorldFirepit { int position; WorldFirepit(int pos) { position = pos; } } WorldFirepit@[] world_firepits; class WorldHerbGarden { int position; WorldHerbGarden(int pos) { position = pos; } } WorldHerbGarden@[] world_herb_gardens; class WorldStorage { int position; WorldStorage(int pos) { position = pos; } } WorldStorage@[] world_storages; class WorldPasture { int position; WorldPasture(int pos) { position = pos; } } WorldPasture@[] world_pastures; class WorldStable { int position; WorldStable(int pos) { position = pos; } } WorldStable@[] world_stables; class WorldAltar { int position; WorldAltar(int pos) { position = pos; } } WorldAltar@[] world_altars; class WorldStream { int start_position; int end_position; int sound_handle; WorldStream(int start_pos, int width) { start_position = start_pos; end_position = start_pos + width - 1; sound_handle = -1; } bool contains_position(int pos) { return pos >= start_position && pos <= end_position; } int get_width() { return end_position - start_position + 1; } int get_center_position() { return (start_position + end_position) / 2; } void update() { int center = get_center_position(); // Play stream sound within range of center if (abs(x - center) <= STREAM_SOUND_RANGE) { if (sound_handle == -1 || !p.sound_is_active(sound_handle)) { sound_handle = p.play_1d("sounds/terrain/stream.ogg", x, center, true); if (sound_handle != -1) { p.update_sound_positioning_values(sound_handle, -1.0, STREAM_SOUND_VOLUME_STEP, true); p.update_sound_range_1d(sound_handle, STREAM_SOUND_RANGE, STREAM_SOUND_RANGE); } } } else { if (sound_handle != -1) { p.destroy_sound(sound_handle); sound_handle = -1; } } } void destroy() { if (sound_handle != -1) { p.destroy_sound(sound_handle); sound_handle = -1; } } } WorldStream@[] world_streams; void add_world_snare(int pos) { WorldSnare@ s = WorldSnare(pos); world_snares.insert_last(s); } void add_world_fire(int pos) { WorldFire@ f = WorldFire(pos); world_fires.insert_last(f); } void add_world_firepit(int pos) { WorldFirepit@ fp = WorldFirepit(pos); world_firepits.insert_last(fp); } void add_world_storage(int pos) { WorldStorage@ s = WorldStorage(pos); world_storages.insert_last(s); } void add_world_pasture(int pos) { WorldPasture@ p = WorldPasture(pos); world_pastures.insert_last(p); } void add_world_stable(int pos) { WorldStable@ s = WorldStable(pos); world_stables.insert_last(s); } void add_world_altar(int pos) { WorldAltar@ a = WorldAltar(pos); world_altars.insert_last(a); } WorldStorage@ get_storage_at(int pos) { for (uint i = 0; i < world_storages.length(); i++) { if (world_storages[i].position == pos) { return @world_storages[i]; } } return null; } WorldPasture@ get_pasture_at(int pos) { for (uint i = 0; i < world_pastures.length(); i++) { if (world_pastures[i].position == pos) { return @world_pastures[i]; } } return null; } WorldStable@ get_stable_at(int pos) { for (uint i = 0; i < world_stables.length(); i++) { if (world_stables[i].position == pos) { return @world_stables[i]; } } return null; } WorldAltar@ get_altar_at(int pos) { for (uint i = 0; i < world_altars.length(); i++) { if (world_altars[i].position == pos) { return @world_altars[i]; } } return null; } 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(); } } WorldSnare@ get_snare_at(int pos) { for (uint i = 0; i < world_snares.length(); i++) { if (world_snares[i].position == pos) { return @world_snares[i]; } } return null; } void remove_snare_at(int pos) { for (uint i = 0; i < world_snares.length(); i++) { if (world_snares[i].position == pos) { world_snares[i].destroy(); world_snares.remove_at(i); return; } } } // Called when player moves onto a tile void check_snare_collision(int player_x) { WorldSnare@ s = get_snare_at(player_x); if (s != null && s.active) { // Break the snare p.play_stationary("sounds/actions/break_snare.ogg", false); if (s.has_catch) { screen_reader_speak("You stepped on your snare! The " + s.catch_type + " escaped.", true); } else { screen_reader_speak("You stepped on your snare and broke it!", true); } remove_snare_at(player_x); } } void update_snares() { for (int i = int(world_snares.length()) - 1; i >= 0; i--) { world_snares[i].update(); } } void update_streams() { for (uint i = 0; i < world_streams.length(); i++) { world_streams[i].update(); } } void update_fires() { // Update all fires and remove any that have burned out for (uint i = 0; i < world_fires.length(); i++) { world_fires[i].update(); } // Remove dead fires for (uint i = 0; i < world_fires.length(); i++) { if (!world_fires[i].is_burning()) { world_fires[i].destroy(); world_fires.remove_at(i); i--; } } } WorldFire@ get_fire_at(int pos) { for (uint i = 0; i < world_fires.length(); i++) { if (world_fires[i].position == pos) { return @world_fires[i]; } } return null; } WorldFire@ get_fire_near(int pos) { // Check for fire at current position or adjacent tiles for (int check_x = pos - 1; check_x <= pos + 1; check_x++) { WorldFire@ fire = get_fire_at(check_x); if (fire != null && fire.is_burning()) { return @fire; } } return null; } WorldFire@ get_fire_within_range(int pos, int range) { // Check for fire within specified range for (int check_x = pos - range; check_x <= pos + range; check_x++) { WorldFire@ fire = get_fire_at(check_x); if (fire != null && fire.is_burning()) { return @fire; } } return null; } WorldFirepit@ get_firepit_at(int pos) { for (uint i = 0; i < world_firepits.length(); i++) { if (world_firepits[i].position == pos) { return @world_firepits[i]; } } return null; } WorldFirepit@ get_firepit_near(int pos, int range) { // Check for firepit within specified range for (int check_x = pos - range; check_x <= pos + range; check_x++) { WorldFirepit@ firepit = get_firepit_at(check_x); if (firepit != null) { return @firepit; } } return null; } void add_world_herb_garden(int pos) { WorldHerbGarden@ hg = WorldHerbGarden(pos); world_herb_gardens.insert_last(hg); } void init_barricade() { if (barricade_initialized) { return; } barricade_health = BARRICADE_BASE_HEALTH; barricade_initialized = true; } int add_barricade_health(int amount) { if (amount <= 0) { return 0; } int before = barricade_health; barricade_health += amount; if (barricade_health > BARRICADE_MAX_HEALTH) { barricade_health = BARRICADE_MAX_HEALTH; } return barricade_health - before; } void clear_zombies() { if (zombies.length() == 0) return; for (uint i = 0; i < zombies.length(); i++) { if (zombies[i].sound_handle != -1) { p.destroy_sound(zombies[i].sound_handle); zombies[i].sound_handle = -1; } } zombies.resize(0); } Zombie@ get_zombie_at(int pos) { for (uint i = 0; i < zombies.length(); i++) { if (zombies[i].position == pos) { return @zombies[i]; } } return null; } void spawn_zombie() { int spawn_x = -1; for (int attempts = 0; attempts < 20; attempts++) { int candidate = random(BASE_END + 1, MAP_SIZE - 1); if (get_zombie_at(candidate) == null) { spawn_x = candidate; break; } } if (spawn_x == -1) { spawn_x = random(BASE_END + 1, MAP_SIZE - 1); } Zombie@ z = Zombie(spawn_x); zombies.insert_last(z); z.sound_handle = play_1d_with_volume_step(z.voice_sound, x, spawn_x, false, ZOMBIE_SOUND_VOLUME_STEP); } void try_attack_barricade(Zombie@ zombie) { if (barricade_health <= 0) return; if (zombie.attack_timer.elapsed < ZOMBIE_ATTACK_INTERVAL) return; zombie.attack_timer.restart(); int damage = random(ZOMBIE_DAMAGE_MIN, ZOMBIE_DAMAGE_MAX); barricade_health -= damage; if (barricade_health < 0) barricade_health = 0; play_1d_with_volume_step("sounds/enemies/zombie_hits_player.ogg", x, zombie.position, false, ZOMBIE_SOUND_VOLUME_STEP); // Resident defense counter-attack if (can_residents_defend()) { int counterDamage = perform_resident_defense(); if (counterDamage > 0) { zombie.health -= counterDamage; if (zombie.health <= 0 && x <= BASE_END) { screen_reader_speak("Residents killed an attacking zombie.", true); } } } if (barricade_health == 0) { notify("The barricade has fallen!"); } } bool can_zombie_attack_player(Zombie@ zombie) { if (player_health <= 0) { return false; } if (barricade_health > 0 && x <= BASE_END) { return false; } if (abs(zombie.position - x) > 1) { return false; } return y <= ZOMBIE_ATTACK_MAX_HEIGHT; } bool try_attack_player(Zombie@ zombie) { if (!can_zombie_attack_player(zombie)) { return false; } if (zombie.attack_timer.elapsed < ZOMBIE_ATTACK_INTERVAL) { return false; } zombie.attack_timer.restart(); int damage = random(ZOMBIE_DAMAGE_MIN, ZOMBIE_DAMAGE_MAX); player_health -= damage; if (player_health < 0) { player_health = 0; } play_1d_with_volume_step("sounds/enemies/zombie_hits_player.ogg", x, zombie.position, false, ZOMBIE_SOUND_VOLUME_STEP); return true; } void update_zombie(Zombie@ zombie) { if (zombie.groan_timer.elapsed > zombie.next_groan_delay) { zombie.groan_timer.restart(); zombie.next_groan_delay = random(ZOMBIE_GROAN_MIN_DELAY, ZOMBIE_GROAN_MAX_DELAY); zombie.sound_handle = play_1d_with_volume_step(zombie.voice_sound, x, zombie.position, false, ZOMBIE_SOUND_VOLUME_STEP); } if (try_attack_player(zombie)) { return; } if (zombie.move_timer.elapsed < ZOMBIE_MOVE_INTERVAL) return; zombie.move_timer.restart(); if (barricade_health > 0 && zombie.position == BASE_END + 1) { try_attack_barricade(zombie); return; } int direction = 0; if (x > BASE_END) { if (x > zombie.position) { direction = 1; } else if (x < zombie.position) { direction = -1; } else { return; } } else { direction = random(-1, 1); if (direction == 0) return; } int target_x = zombie.position + direction; if (target_x < 0 || target_x >= MAP_SIZE) return; if (target_x <= BASE_END && barricade_health > 0) { try_attack_barricade(zombie); return; } zombie.position = target_x; play_positional_footstep(x, zombie.position, BASE_END, GRASS_END, ZOMBIE_FOOTSTEP_MAX_DISTANCE, ZOMBIE_SOUND_VOLUME_STEP); } void update_zombies() { if (is_daytime) { clear_zombies(); return; } while (zombies.length() < ZOMBIE_MAX_COUNT) { spawn_zombie(); } for (uint i = 0; i < zombies.length(); i++) { update_zombie(zombies[i]); } } bool damage_zombie_at(int pos, int damage) { for (uint i = 0; i < zombies.length(); i++) { if (zombies[i].position == pos) { zombies[i].health -= damage; if (zombies[i].health <= 0) { if (zombies[i].sound_handle != -1) { p.destroy_sound(zombies[i].sound_handle); zombies[i].sound_handle = -1; } play_1d_with_volume_step("sounds/enemies/enemy_falls.ogg", x, pos, false, ZOMBIE_SOUND_VOLUME_STEP); zombies.remove_at(i); } return true; } } return false; } WorldHerbGarden@ get_herb_garden_at(int pos) { for (uint i = 0; i < world_herb_gardens.length(); i++) { if (world_herb_gardens[i].position == pos) { return @world_herb_gardens[i]; } } return null; } WorldHerbGarden@ get_herb_garden_at_base() { // Check if herb garden exists anywhere in base area (0-4) for (uint i = 0; i < world_herb_gardens.length(); i++) { if (world_herb_gardens[i].position <= BASE_END) { return @world_herb_gardens[i]; } } return null; } // Bandit Functions void clear_bandits() { if (bandits.length() == 0) return; bandits.resize(0); } Bandit@ get_bandit_at(int pos) { for (uint i = 0; i < bandits.length(); i++) { if (bandits[i].position == pos) { return @bandits[i]; } } return null; } void spawn_bandit(int expansion_start, int expansion_end) { int spawn_x = -1; for (int attempts = 0; attempts < 20; attempts++) { int candidate = random(expansion_start, expansion_end); if (get_bandit_at(candidate) == null) { spawn_x = candidate; break; } } if (spawn_x == -1) { spawn_x = random(expansion_start, expansion_end); } Bandit@ b = Bandit(spawn_x, expansion_start, expansion_end); bandits.insert_last(b); play_1d_with_volume_step(b.alert_sound, x, spawn_x, false, BANDIT_SOUND_VOLUME_STEP); } bool can_bandit_attack_player(Bandit@ bandit) { if (player_health <= 0) { return false; } // Cannot attack player if barricade is up and player is in base if (barricade_health > 0 && x <= BASE_END) { return false; } if (abs(bandit.position - x) > 1) { return false; } return y <= BANDIT_ATTACK_MAX_HEIGHT; } bool try_attack_player_bandit(Bandit@ bandit) { if (!can_bandit_attack_player(bandit)) { return false; } if (bandit.attack_timer.elapsed < BANDIT_ATTACK_INTERVAL) { return false; } bandit.attack_timer.restart(); // Play weapon swing sound based on bandit's weapon if (bandit.weapon_type == "spear") { p.play_stationary("sounds/weapons/spear_swing.ogg", false); } else if (bandit.weapon_type == "axe") { p.play_stationary("sounds/weapons/axe_swing.ogg", false); } int damage = random(BANDIT_DAMAGE_MIN, BANDIT_DAMAGE_MAX); player_health -= damage; if (player_health < 0) { player_health = 0; } // Play hit sound if (bandit.weapon_type == "spear") { p.play_stationary("sounds/weapons/spear_hit.ogg", false); } else if (bandit.weapon_type == "axe") { p.play_stationary("sounds/weapons/axe_hit.ogg", false); } return true; } void try_attack_barricade_bandit(Bandit@ bandit) { if (barricade_health <= 0) return; if (bandit.attack_timer.elapsed < BANDIT_ATTACK_INTERVAL) return; bandit.attack_timer.restart(); // Bandits do 1-2 damage to barricade int damage = random(BANDIT_DAMAGE_MIN, BANDIT_DAMAGE_MAX); barricade_health -= damage; if (barricade_health < 0) barricade_health = 0; // Play weapon swing sound if (bandit.weapon_type == "spear") { p.play_stationary("sounds/weapons/spear_swing.ogg", false); p.play_stationary("sounds/weapons/spear_hit.ogg", false); } else if (bandit.weapon_type == "axe") { p.play_stationary("sounds/weapons/axe_swing.ogg", false); p.play_stationary("sounds/weapons/axe_hit.ogg", false); } // Resident defense counter-attack if (can_residents_defend()) { int counterDamage = perform_resident_defense(); if (counterDamage > 0) { bandit.health -= counterDamage; if (bandit.health <= 0 && x <= BASE_END) { screen_reader_speak("Residents killed an attacking bandit.", true); } } } if (barricade_health == 0) { notify("The barricade has fallen!"); } } void update_bandit(Bandit@ bandit) { // Play alert sound at intervals if (bandit.alert_timer.elapsed > bandit.next_alert_delay) { bandit.alert_timer.restart(); bandit.next_alert_delay = random(BANDIT_ALERT_MIN_DELAY, BANDIT_ALERT_MAX_DELAY); play_1d_with_volume_step(bandit.alert_sound, x, bandit.position, false, BANDIT_SOUND_VOLUME_STEP); } if (try_attack_player_bandit(bandit)) { return; } if (bandit.move_timer.elapsed < bandit.move_interval) return; bandit.move_timer.restart(); // If barricade is up and bandit is at the edge of base, attack barricade if (barricade_health > 0 && bandit.position == BASE_END + 1) { try_attack_barricade_bandit(bandit); return; } // State-based behavior if (bandit.behavior_state == "wandering") { // Check if player is within detection radius int distance = abs(bandit.position - x); if (distance <= BANDIT_DETECTION_RADIUS) { // Player detected! Switch to aggressive bandit.behavior_state = "aggressive"; } else { // Continue wandering if (bandit.wander_direction_timer.elapsed > bandit.wander_direction_change_interval) { // Time to change direction bandit.wander_direction = random(-1, 1); bandit.wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX); bandit.wander_direction_timer.restart(); } // Move in wander direction (if not 0) if (bandit.wander_direction != 0) { int target_x = bandit.position + bandit.wander_direction; // Check bounds if (target_x >= 0 && target_x < MAP_SIZE) { // Don't wander into base if barricade is up if (target_x <= BASE_END && barricade_health > 0) { // Change direction instead bandit.wander_direction = -bandit.wander_direction; } else { bandit.position = target_x; play_positional_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP); } } else { // Hit map boundary, reverse direction bandit.wander_direction = -bandit.wander_direction; } } return; } } // Aggressive behavior (original logic) if (bandit.behavior_state == "aggressive") { // Move toward player int direction = 0; if (x > BASE_END) { // Player is outside base, move toward them if (x > bandit.position) { direction = 1; } else if (x < bandit.position) { direction = -1; } else { return; } } else { // Player is in base, move toward base edge if (bandit.position > BASE_END + 1) { direction = -1; } else { return; // Already at base edge } } int target_x = bandit.position + direction; if (target_x < 0 || target_x >= MAP_SIZE) return; // Don't enter base if barricade is up if (target_x <= BASE_END && barricade_health > 0) { try_attack_barricade_bandit(bandit); return; } bandit.position = target_x; play_positional_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP); } } void update_bandits() { for (uint i = 0; i < bandits.length(); i++) { update_bandit(bandits[i]); } } bool damage_bandit_at(int pos, int damage) { for (uint i = 0; i < bandits.length(); i++) { if (bandits[i].position == pos) { bandits[i].health -= damage; if (bandits[i].health <= 0) { play_1d_with_volume_step("sounds/enemies/enemy_falls.ogg", x, pos, false, BANDIT_SOUND_VOLUME_STEP); bandits.remove_at(i); } else { } return true; } } return false; } // Stream Functions void add_world_stream(int start_pos, int width) { WorldStream@ s = WorldStream(start_pos, width); world_streams.insert_last(s); } WorldStream@ get_stream_at(int pos) { for (uint i = 0; i < world_streams.length(); i++) { if (world_streams[i].contains_position(pos)) { return @world_streams[i]; } } return null; } bool is_position_in_water(int pos) { return get_stream_at(pos) != null; }