extends AudioStreamPlayer const MUTE_VOLUME := -80.0 @export var volume_increment := 0.618 @export var base_volume := -18.0 @export var boosted_volume := -2.0 @export_category("Beast Proximity Boost") @export var proximity_cutoff := 20.0 @export var proximity_scale := 17.0 var target_volume := MUTE_VOLUME var suppressed := false var boosted := false func _ready() -> void: Game.manager.alert_raised.connect(_on_alert_raised) func get_target_volume() -> float: if suppressed: return MUTE_VOLUME if boosted: return boosted_volume return target_volume + beast_proximity_boost(closest_beast_distance()) ## Calculate the volume gain from proximity to a beast func beast_proximity_boost(distance: float) -> float: return max(0.0, proximity_scale * (proximity_cutoff - distance) / proximity_cutoff) ## Get the distance from the player to the closest beast func closest_beast_distance() -> float: if not is_instance_valid(Player.instance): return INF var min_dist_sq := INF var nodes := get_tree().get_nodes_in_group("GrunkBeast") for node: Node in nodes: var n3d := node as Node3D if is_instance_valid(n3d): var dist_sq := n3d.global_position.distance_squared_to(Player.instance.global_position) if dist_sq < min_dist_sq: min_dist_sq = dist_sq return sqrt(min_dist_sq) ## Temporarily suppress ambience func suppress(time: float = 5.0) -> void: suppressed = true get_tree().create_timer(time).timeout.connect(_unsuppress) ## Temporarily boost ambience func boost(time: float = 5.0) -> void: boosted = true get_tree().create_timer(time).timeout.connect(_unboost) func _unsuppress() -> void: suppressed = false func _unboost() -> void: boosted = false func _process(delta: float) -> void: volume_db = lerpf(volume_db, get_target_volume(), volume_increment * delta) func _on_player_enters_ship(_body: Node3D) -> void: target_volume = MUTE_VOLUME func _on_player_exits_ship(_body: Node3D) -> void: target_volume = base_volume func _on_alert_raised(new_level: int) -> void: if new_level == Game.manager.MAX_ALERT: suppress(30) else: boost(10.0)