Files
Cinderwild/scripts/core/narrator.gd

67 lines
2.0 KiB
GDScript

extends Node
## Old Tam's voice: the recorded line for a tutorial step, his goodbye or one
## of his tips (assets/audio/voice, made by tools/voice/make_voice.sh). A line
## only plays if it was made from exactly the text on screen (lines.json), so
## after an edit it stays quiet rather than saying the old words. A new line
## cuts off the one before; the music dips while he talks. The Voice volume
## (pause menu) turns him down or off. It pauses with the game.
const DIR := "res://assets/audio/voice/"
var lines: Dictionary = {} ## line id -> the key of the text it was made from
var spoken: Array = [] ## ids said (tests; headless nothing is heard)
var speaking := ""
var _p: AudioStreamPlayer
var _quiet := false
func _ready() -> void:
var d: Variant = JSON.parse_string(FileAccess.get_file_as_string(DIR + "lines.json")) \
if FileAccess.file_exists(DIR + "lines.json") else null
if d is Dictionary:
lines = d
_quiet = DisplayServer.get_name() == "headless"
if _quiet:
return
_p = AudioStreamPlayer.new()
_p.bus = "Voice"
add_child(_p)
_p.finished.connect(_done)
## The same key make_voice.py writes: the first 16 hex digits of the text's SHA-1.
static func text_key(text: String) -> String:
return text.sha1_text().substr(0, 16)
## Whether there's a recording of `text` for `id`.
func has_line(id: String, text: String) -> bool:
return String(lines.get(id, "")) == text_key(text)
## Says line `id` if it's the recording of `text`. True if it's being said.
func say(id: String, text: String) -> bool:
if not has_line(id, text):
return false
spoken.append(id)
speaking = id
if _quiet:
return true
var st: Variant = load(DIR + id + ".ogg")
if not (st is AudioStream):
speaking = ""
return false
_p.stop()
_p.stream = st
_p.play()
Music.duck = true
return true
func stop() -> void:
if _p != null:
_p.stop()
_done()
func is_speaking() -> bool:
return _p != null and _p.playing
func _done() -> void:
speaking = ""
Music.duck = false