diff --git a/assets/audio/sfx/door_close.wav b/assets/audio/sfx/door_close.wav new file mode 100644 index 0000000..38a583f Binary files /dev/null and b/assets/audio/sfx/door_close.wav differ diff --git a/assets/audio/sfx/enemy_shoot.wav b/assets/audio/sfx/enemy_shoot.wav new file mode 100644 index 0000000..e92eb42 Binary files /dev/null and b/assets/audio/sfx/enemy_shoot.wav differ diff --git a/assets/audio/sfx/room_clear.wav b/assets/audio/sfx/room_clear.wav new file mode 100644 index 0000000..3445b91 Binary files /dev/null and b/assets/audio/sfx/room_clear.wav differ diff --git a/scripts/autoload/audio_manager.gd b/scripts/autoload/audio_manager.gd index 10d62a5..2f607a6 100644 --- a/scripts/autoload/audio_manager.gd +++ b/scripts/autoload/audio_manager.gd @@ -10,6 +10,8 @@ const POOL_SIZE := 8 # Preloaded sound effects var _sounds: Dictionary = { "enemy_hit": preload("res://assets/audio/sfx/enemy_hit.wav"), + "enemy_death": preload("res://assets/audio/sfx/enemy_death.wav"), + "enemy_shoot": preload("res://assets/audio/sfx/enemy_shoot.wav"), "player_hit": preload("res://assets/audio/sfx/player_hit.wav"), "player_shoot": preload("res://assets/audio/sfx/player_shoot.wav"), "explosion": preload("res://assets/audio/sfx/explosion.wav"), @@ -17,6 +19,9 @@ var _sounds: Dictionary = { "item_pickup": preload("res://assets/audio/sfx/item_pickup.wav"), "ui_click": preload("res://assets/audio/sfx/ui_click.wav"), "ui_select": preload("res://assets/audio/sfx/ui_select.wav"), + "door_close": preload("res://assets/audio/sfx/door_close.wav"), + "room_clear": preload("res://assets/audio/sfx/room_clear.wav"), + "teleport": preload("res://assets/audio/sfx/teleport.wav"), } var _pool: Array[AudioStreamPlayer] = [] diff --git a/scripts/enemies/enemy_base.gd b/scripts/enemies/enemy_base.gd index 200849f..35a59a0 100644 --- a/scripts/enemies/enemy_base.gd +++ b/scripts/enemies/enemy_base.gd @@ -91,6 +91,7 @@ func take_damage(amount: float) -> void: _die() func _die() -> void: + AudioManager.play("enemy_death") _spawn_drop() queue_free() diff --git a/scripts/enemies/hivemind.gd b/scripts/enemies/hivemind.gd index 9c3a515..d9bcd0b 100644 --- a/scripts/enemies/hivemind.gd +++ b/scripts/enemies/hivemind.gd @@ -863,6 +863,7 @@ func take_damage(amount: float) -> void: current_health -= amount _flash_timer = 0.1 + AudioManager.play("enemy_hit") EventBus.boss_health_changed.emit(maxf(current_health, 0.0), max_health, "THE HIVEMIND") if current_health <= 0.0: @@ -907,6 +908,7 @@ func _tick_climax(delta: float) -> void: func _die() -> void: + AudioManager.play("enemy_death") _clear_orbiters() _end_beam() diff --git a/scripts/enemies/relay.gd b/scripts/enemies/relay.gd index f18dfe5..3b158f8 100644 --- a/scripts/enemies/relay.gd +++ b/scripts/enemies/relay.gd @@ -369,6 +369,7 @@ func take_damage(amount: float) -> void: return current_health -= amount + AudioManager.play("enemy_hit") EventBus.boss_health_changed.emit(current_health, max_health, "THE RELAY") if current_health <= 5.0 and _phase != Phase.CLIMAX: @@ -412,6 +413,7 @@ func _tick_climax(delta: float) -> void: _die() func _die() -> void: + AudioManager.play("enemy_death") EventBus.boss_died.emit() # Cleanup burst projectiles diff --git a/scripts/enemies/repeater.gd b/scripts/enemies/repeater.gd index 5444a76..503dbf5 100644 --- a/scripts/enemies/repeater.gd +++ b/scripts/enemies/repeater.gd @@ -86,6 +86,7 @@ func _do_fire(delta: float) -> void: _shot_timer = BURST_PAUSE func _fire_projectile() -> void: + AudioManager.play("enemy_shoot") var proj = ENEMY_PROJECTILE.instantiate() proj.position = (get_parent() as Node2D).to_local(global_position) proj.direction = Vector2.from_angle(_fire_angle) diff --git a/scripts/enemies/warden.gd b/scripts/enemies/warden.gd index 8cccc03..6042027 100644 --- a/scripts/enemies/warden.gd +++ b/scripts/enemies/warden.gd @@ -370,12 +370,14 @@ func take_damage(amount: float) -> void: return # already dying current_health -= amount _flash_timer = 0.1 + AudioManager.play("enemy_hit") EventBus.boss_health_changed.emit(maxf(current_health, 0.0), max_health, "THE WARDEN") if current_health <= 0.0: _enter_climax() func _die() -> void: + AudioManager.play("enemy_death") _clear_mines() for entry in _sweep_projs: if is_instance_valid(entry["node"]): diff --git a/scripts/rooms/room.gd b/scripts/rooms/room.gd index cc60a10..bb0c7cf 100644 --- a/scripts/rooms/room.gd +++ b/scripts/rooms/room.gd @@ -327,6 +327,7 @@ func _on_enemy_died() -> void: _enemy_count -= 1 if _enemy_count <= 0: data.cleared = true + AudioManager.play("room_clear") if data.type == RoomData.RoomType.BOSS: _spawn_body_part_drop() _spawn_floor_exit() @@ -566,11 +567,18 @@ func _update_door_locks() -> void: (area as Area2D).monitoring = not locked # Update physical door barriers + var was_unlocked := false + for door in _physical_doors.values(): + if not door.is_locked(): + was_unlocked = true + break for door in _physical_doors.values(): if locked: door.lock() else: door.unlock() + if locked and was_unlocked: + AudioManager.play("door_close") # --------------------------------------------------------------------------- # Explicit signal cleanup on exit (safer than relying on Godot auto-cleanup)