SoundDirector
The sound of *First Light: Vagant*, and the library every other part of the game reaches for. It sits on `mount_sound` in `scenes/main.scene` and needs no sibling components: it spawns its own audio sources under a runtime entity called `snd_root`, and despawns that root when it…
SoundDirector
The sound of First Light: Vagant, and the library every other part of the
game reaches for. It sits on mount_sound in scenes/main.scene and needs no
sibling components: it spawns its own audio sources under a runtime entity
called snd_root, and despawns that root when it goes away.
It does four things.
The library. On awake it fills fl.clips from audio.clips, so nothing
else in the game ever holds a .soundClip reference. Everyone asks for a noise
by name — fl.playSfx("lamp.catch", lampEntity) — which arrives here as the
sfx signal. A name with no clip is a quiet game, not a broken one.
The score and the bed. A held D-minor string loops all night; a second, grinding layer fades up as the Jaseys hunt and back down when they lose you; a warm major cue replaces both when the seventh lamp catches. Under all of it the fen's own air runs continuously, thinning as the sky opens. Each lamp that comes back on gets its own small spatial fire.
The voices. say(key) plays the line from audio.voice's script and emits
line(key, text, speaker, seconds) so the subtitle can be shown — whether or
not the clip exists, so a line whose audio failed to generate is spoken quietly
rather than lost. lineEnd(key) follows when it finishes, or immediately if
another line replaces it.
The mix. Five channels — music, ambient, sfx, ui, voice — and a
duck that pulls the score and the air down under anything spoken.
Public fields
master: number— the whole mix, 0..1 (default 1.0).musicLevel: number— themusicchannel (default 0.60).ambientLevel: number— theambientchannel (default 0.80).sfxLevel: number— thesfxchannel (default 0.95).uiLevel: number— theuichannel (default 0.70).voiceLevel: number— thevoicechannel (default 1.0).footsteps: boolean— drive footsteps from the vagant's own movement (default true). It switches itself off the moment another slice emits astep.*orsplash.*sound of its own, so the two never double.
Methods
:playSound(name, where?)— play a library sound by name.wheremay be an entity proxy, an entity id,{x, y, z}or{x = , y = , z = }; omit it for a sound that belongs to the player rather than to a place.:speak(key)— speak a line of the script, the same way thesaysignal does.:currentLine()— the line being spoken right now (key,text,speaker,seconds,elapsed,remaining), or nil.:report()— what the mix is doing: phase, music state, the three layer volumes, whether it is ducked, the live line, and the mixer's own audible voice count.
Signals
Answers sfx, say, and — as a fallback that any slice's own sfx call
suppresses for a third of a second — lampLit, allLamps, dawn, caught,
lantern, wig, oil, hunt and phase. Emits line and lineEnd.
Usage
local snd = entity.find("mount_sound").component.get("SoundDirector")
snd:playSound("lamp.catch", lampEntity)
snd:speak("open_comm_1")
print(snd:report().musicState)
Scoped to this part · feeds back into the world's score.