ScriptProcessor command queueImplemented in src/lua/luafilesystemapi.cpp and src/lua/luascriptingapi.cpp.
Also implemented in SunLight::Scripting::ScriptProcessor
(sunlight engine).
Stage scripts don't drive gameplay by calling functions
directly and waiting for them to return — they push
commands onto a queue, and the engine drains that queue
one command at a time, once per frame, from
EngineHost::RunStageStateHandler. This is what lets
sp_wait(2000) mean "pause the queue, not the whole
engine" — sprites keep moving, input keeps being read,
only the next queued command waits.
Every sp_* function in this file just appends to that
queue; none of them block or take effect immediately.
sp_wait(milliseconds)Pause queue processing for milliseconds before the next
queued command runs. Purely queue-side — rendering,
physics, and every other per-frame system keep running.
sp_wait(2000) -- 2 second pause, non-blocking
sp_clear()Empty the entire command queue immediately, discarding
everything not yet processed. Used once at startup
(main.lua) before the first sp_load_stage, to
guarantee a clean queue regardless of what earlier
dofiles may have queued.
sp_clear()
sp_wait_queue_empty()Queue a command that blocks all later queued commands
until the engine reports the screen is clear of active
enemies (EngineHost::CheckSpritesQueueEmpty, driven by
the game's own get_active_enemy_count() — see
callbacks.md). The classic "don't spawn wave 2 until wave
1 is dead" gate.
sp_move_sprites_to_screen(STATE_MOVE_SATELLITES_TO_SCREEN_RANDOM)
sp_wait_queue_empty()
sp_move_sprites_to_screen(STATE_MOVE_CYLINDER_SHIP_TO_SCREEN_LEFT_SIDE) -- only starts once wave 1 is gone
sp_move_sprites_to_screen(stateId)Queue a wave-spawn command. stateId is an opaque
integer — Caravellius defines its own meaningful names for
these in caravellius/src/wavestates.lua
(STATE_MOVE_SATELLITES_TO_SCREEN_RANDOM, etc.); the
engine itself doesn't know or care what any specific id
means; it's forwarded verbatim to the game's own
on_move_sprites_to_screen(stateId) hook (see
callbacks.md).
sp_move_sprites_to_screen(STATE_MOVE_SATELLITES_TO_SCREEN_RANDOM)
sp_add_label(id) / sp_goto_label(id)Mark a position in the queue (sp_add_label) and later
jump the queue's read position back (or forward) to it
(sp_goto_label) — the queue's only looping construct,
since it's a linear command sequence otherwise. id is
any integer you choose; it just has to match between the
label and the goto.
sp_add_label(1)
sp_move_sprites_to_screen(STATE_MOVE_SATELLITES_TO_SCREEN_RANDOM)
sp_wait_queue_empty()
sp_goto_label(1) -- repeats the wave forever
sp_load_stage(stageId)Queue a stage load. stageId is opaque to the engine the
same way wave-spawn ids are — Caravellius defines
STAGE_FIRST/STAGE_LAST in
caravellius/src/stageids.lua. When the queue reaches
this command, the engine calls the game's
on_load_stage(stageId) hook (see callbacks.md), which is
expected to load a map and dofile a stage script. There
is no built-in stage concept beyond this — the engine only
ferries the id through.
sp_load_stage(STAGE_FIRST)
dofile(filename)Scarab overrides Lua's own built-in dofile to load and
run the named file through SunLight::FileSystem instead
of a raw fopen() — otherwise it behaves exactly like the
standard function: loads the file as a Lua chunk and runs
it, returning whatever the chunk itself returns, and
raises a genuine Lua error (not a silent nil) if the
file is missing or fails to compile.
This is what lets dofile calls reach into a mounted
.zip archive the same way every other resource load in
the engine does — a loose directory or an archived build
both work identically, with no path-construction code
anywhere needing to know the difference.
Transparently runs content encrypted by
crypto_encrypt_data/tools/pack.lua too — nothing to
opt into on the calling side; this build's own
SCARAB_CONTENT_KEY is tried automatically, falling back
to the file as plain Lua source if it doesn't apply (no
key configured, or the file just isn't encrypted).
-- runs identically whether the game is a loose directory or a mounted .zip
dofile( BASE_PATH .. "scripts/stages/1st_stage_corsair.lua" )
sp_play_song/sp_pause_song/sp_stop_song/
sp_resume_song are documented in sound.md alongside
their non-queued (play_song/pause_song/...)
counterparts, since the two forms only differ in when
they take effect (queued vs. immediate), not in what they
do.