Houses ~8.5 m; chimps capped ~0.85 m with safer axis fitting. Large GLB/PBR packs stay local until Git LFS (Forgejo HTTP 413). Co-authored-by: Cursor <cursoragent@cursor.com>
133 lines
3.4 KiB
GDScript
133 lines
3.4 KiB
GDScript
extends Node
|
|
## Music / SFX / Voice (Piper lines under assets/audio/voice/{lang}/{dialog_key}.wav).
|
|
|
|
signal burger_cham_triggered
|
|
|
|
const BURGER_INTERVAL := 120.0
|
|
|
|
const MUSIC_TITLE := "res://assets/audio/placeholders/music_title.wav"
|
|
const SFX_EXPLOSION := "res://assets/audio/placeholders/sfx_explosion.wav"
|
|
const SFX_HIT := "res://assets/audio/placeholders/sfx_hit.wav"
|
|
const SFX_BURGER := "res://assets/audio/placeholders/sfx_burger.wav"
|
|
|
|
## Fallback language-picker clips if keyed Piper files missing
|
|
const VOICE_DE := "res://assets/audio/placeholders/voice_de.wav"
|
|
const VOICE_EN := "res://assets/audio/placeholders/voice_en.wav"
|
|
const VOICE_BY := "res://assets/audio/placeholders/voice_by.wav"
|
|
|
|
var _music: AudioStreamPlayer
|
|
var _sfx: AudioStreamPlayer
|
|
var _voice: AudioStreamPlayer
|
|
var _burger_timer: float = 0.0
|
|
var burger_cham_enabled: bool = true
|
|
var _last_voice_length: float = 0.0
|
|
|
|
func _ready() -> void:
|
|
process_mode = Node.PROCESS_MODE_ALWAYS
|
|
_music = AudioStreamPlayer.new()
|
|
_music.bus = "Music"
|
|
_music.volume_db = 12.0 # intentionally painfully loud
|
|
add_child(_music)
|
|
_sfx = AudioStreamPlayer.new()
|
|
_sfx.bus = "SFX"
|
|
add_child(_sfx)
|
|
_voice = AudioStreamPlayer.new()
|
|
_voice.bus = "Voice"
|
|
add_child(_voice)
|
|
|
|
func _process(delta: float) -> void:
|
|
if not burger_cham_enabled:
|
|
return
|
|
if GameState.current_scene_id != "title_screen":
|
|
return
|
|
_burger_timer += delta
|
|
if _burger_timer >= BURGER_INTERVAL:
|
|
_burger_timer = 0.0
|
|
trigger_burger_cham()
|
|
|
|
func play_title_music() -> void:
|
|
var stream := _load_stream(MUSIC_TITLE)
|
|
if stream == null:
|
|
return
|
|
_music.stream = stream
|
|
_music.volume_db = 12.0
|
|
if not _music.playing:
|
|
_music.play()
|
|
|
|
func stop_music() -> void:
|
|
_music.stop()
|
|
|
|
func play_sfx(path: String) -> void:
|
|
var stream := _load_stream(path)
|
|
if stream == null:
|
|
return
|
|
_sfx.stream = stream
|
|
_sfx.play()
|
|
|
|
func play_explosion() -> void:
|
|
play_sfx(SFX_EXPLOSION)
|
|
|
|
func play_hit() -> void:
|
|
play_sfx(SFX_HIT)
|
|
|
|
func play_language_voice(lang: String) -> void:
|
|
var key := "lang_voice_%s" % lang
|
|
if play_dialog_line(key) > 0.0:
|
|
return
|
|
var path := VOICE_DE
|
|
match lang:
|
|
"en":
|
|
path = VOICE_EN
|
|
"by":
|
|
path = VOICE_BY
|
|
var stream := _load_stream(path)
|
|
if stream == null:
|
|
return
|
|
_voice.stream = stream
|
|
_voice.play()
|
|
_last_voice_length = _stream_length(stream)
|
|
|
|
## Plays Piper line for locale key. Returns clip length in seconds (0 if missing).
|
|
func play_dialog_line(key: String) -> float:
|
|
if key == "":
|
|
return 0.0
|
|
if not (key.begins_with("dialog_") or key.begins_with("lang_voice_")):
|
|
return 0.0
|
|
var lang := "de"
|
|
if Settings:
|
|
lang = Settings.language
|
|
var path := "res://assets/audio/voice/%s/%s.wav" % [lang, key]
|
|
var stream := _load_stream(path)
|
|
if stream == null and lang != "de":
|
|
path = "res://assets/audio/voice/de/%s.wav" % key
|
|
stream = _load_stream(path)
|
|
if stream == null:
|
|
_last_voice_length = 0.0
|
|
return 0.0
|
|
_voice.stop()
|
|
_voice.stream = stream
|
|
_voice.play()
|
|
_last_voice_length = _stream_length(stream)
|
|
return _last_voice_length
|
|
|
|
func last_voice_length() -> float:
|
|
return _last_voice_length
|
|
|
|
func stop_voice() -> void:
|
|
_voice.stop()
|
|
|
|
func trigger_burger_cham() -> void:
|
|
play_sfx(SFX_BURGER)
|
|
burger_cham_triggered.emit()
|
|
|
|
func _stream_length(stream: AudioStream) -> float:
|
|
if stream == null:
|
|
return 0.0
|
|
if stream.has_method("get_length"):
|
|
return float(stream.get_length())
|
|
return 0.0
|
|
|
|
func _load_stream(path: String) -> AudioStream:
|
|
if ResourceLoader.exists(path):
|
|
return load(path)
|
|
return null
|