Remove the per-array type category so arrays can mix types like structs.
Add 13 passing and 125 expected-failure duskscript test fixtures with a
table-driven runner. Also includes the in-progress entity/physics and
archive moves from the working tree.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
assets/init.ds is compiled and packed as init.dsb like any other script, and
engineInit() runs it as the very last init step - after scriptInit() and
sceneInit(), right before the initial scene is set - so it's free to use any
engine system (display, audio, save, rpg, ui, scenes, ...) without having to
special-case startup ordering. A syntax error or runtime failure in init.ds
is fatal, same as every other errorChain()'d init step.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
scriptLoadHandler used fopen/fread directly, but every .ds a script include()s
is packed into dusk.dsk (compiled to .dsb) like every other asset now, not a
loose file next to the binary - raw filesystem reads never found them outside
a dev checkout. It now goes through assetFileInit/Open/Read/Close like the
rest of the engine's asset loaders, failing the load the same way (returning
SCRIPT_LOAD_FAILED) for a missing entry or one bigger than capacity.
test_duskscript's fixtures moved to their own assets/ subfolder and pack into
a small test.dsk with the same tools.asset.pack used for the real dusk.dsk,
and the test opens that archive straight into ASSET.zip (skipping the full
assetInit()/assetInitPlatform(), which expects a launched engine) so the
tests exercise the real compile -> pack -> asset -> runtime pipeline instead
of a filesystem shortcut around it.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
core/CMakeLists.txt and vm/CMakeLists.txt each listed every .c file across
every sub-folder in one flat target_sources() call. Split that into one
add_subdirectory() per folder (array, bytecode, call, coroutine, error, gc,
heap, number, ops, promise, runtime, scope, string, struct, text, value and
builtin/{array,core,math,string} under core/; execute, image and ops under
vm/), each with its own small CMakeLists.txt listing just that folder's
sources - matching the convention already used in src/dusk/display/.
Verified the Dusk binary and the duskscript test suite still build and pass
identically; test_battle and test_entityinteract already failed the same
way before this change (stale against unrelated rpg/battle API changes), so
left untouched here.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
tools/asset/pack now special-cases .ds files: each one is compiled with
duskscriptcc to a temp .dsb (no .map, nothing reads one yet) and that gets
packed under the same path with the extension swapped - the raw .ds source
never ends up in the archive. Every other asset type is unchanged, packed
byte for byte as before.
CMake passes --duskscriptcc "$<TARGET_FILE:duskscriptcc>" and adds a DEPENDS
on it, but only on the linux/knulli host target where duskscriptcc is
actually built (see its own gating in src/CMakeLists.txt) - a cross-compiled
console target has no host-built compiler to point at, so for now it can
only pack an assets/ with no .ds in it; the packer raises a clear error
rather than silently skipping or mis-packing one if it finds one anyway.
The manifest's cache-skip check also now folds in duskscriptcc's own mtime,
so a compiler rebuild invalidates every .ds's cached result even when none
of their own source files changed.
Verified by hand: a .ds under assets/scripts/ packs as the matching .dsb
(confirmed by unzipping the resulting dusk.dsk), an unrelated rebuild
correctly skips re-packing, touching duskscriptcc correctly forces a
re-pack, and a syntax error in the .ds fails the build loudly with
duskscriptcc's own error message rather than silently succeeding.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Folds what used to be duskscriptnative.h's includes (builtin/value/array/
struct/promise helpers a native function needs) directly into script.h,
alongside the runtime and VM includes already there. scriptnativeconsole.h
now just includes "script/script.h" instead of enumerating the same list
itself - any new native function bindings can do the same.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Scripting is now a standard part of the engine rather than an optional
feature: removes the DUSK_SCRIPT CMake option and its compile definition,
makes src/dusk/CMakeLists.txt add_subdirectory(script) unconditionally, and
drops the #ifdef DUSK_SCRIPT guards around scriptInit()/scriptDispose() in
engine.c. duskscriptcc and its test still only build on the linux/knulli
host target (it's a dev tool, not part of the runtime), now gated on that
alone instead of DUSK_SCRIPT AND that.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
duskscriptnative.h had exactly one consumer (scriptnativeconsole.h) left
after the duskscriptvm.h removal; folds its includes in directly rather than
keeping a single-consumer indirection.
Moves scriptnativeconsole.c/.h into their own native/ subdirectory, giving
it the same add_subdirectory(native) + CMakeLists.txt treatment as core/
and vm/, so future native function bindings have an obvious home.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
It had exactly one consumer (script.h) and added nothing of its own beyond
re-including duskscript.h + image/scriptvmattach.h + image/scriptvmrun.h -
a pointless indirection now that it's not a standalone embedding SDK with
multiple external consumers.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
scriptvmtypes.h, scriptcompiletypes.h and scriptnode.h each crammed several
unrelated struct definitions into one file, unlike the rest of dusk (see
src/dusk/display or src/dusk/rpg/battle), which always gives a type its own
file named after it, with other types reached by an explicit include or a
forward declaration.
- scriptvmtypes.h: scriptvmfunction_t moves into scriptvmfunction.h (next to
the functions that already work with it), scriptvmname_t into
scriptvmname.h, scriptvmhandler_t into scriptvmtable.h, and scriptvmimage_t
gets a new scriptvmimage.h. scriptvmtypes.h keeps working as a thin
re-include umbrella for the ~45 vm files that reach into several of these
at once, the same role scripttypes.h already plays for the base types.
- scriptcompiletypes.h: scriptlabel_t moves into scriptbuilderlabel.h,
scriptloopcontext_t into scriptcompileloopcontext.h, scriptincluderesolver_t
into scriptcompile.h, and the big scriptbuilder_t gets a new scriptbuilder.h.
Breaking the resulting include cycle needed scriptbuilderlabel.h and
scriptcompileloopcontext.h to forward-declare scriptbuilder_t/scriptlabel_t
rather than pull in full definitions they only ever use by pointer, and
scriptcompile.h to define scriptincluderesolver_t before including
scriptcompiletypes.h instead of after.
- scriptnode.h: scriptfuncnode_t (a function declaration, not a kind of
expression/statement node) moves into a new scriptfuncnode.h.
Also gives scriptbuilder_t and scriptlabel_t proper struct tags (previously
anonymous, which doesn't allow forward declaration) to match the project's
_s tag / _t typedef convention from the previous pass.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Struct tags throughout duskscript reused the typedef name itself (struct
foo_t { ... }), unlike the rest of dusk which always tags with foo_s and
typedefs foo_t - renames all 15 tagged structs in src/dusk/script and
src/duskscriptcc to match. Also drops a vestigial duplicate forward
declaration of scriptsource_t left over from the port.
Unifies all 144 #ifndef/#define/#endif include guards in the ported code to
#pragma once, matching the rest of the codebase (which was already a mix of
25 files doing it the house way and 144 not).
Packs scriptvmfunction_t's isAsync/isRoot/isScript and scriptfuncnode_t's
isAsync/isInline/isNoInline/isRoot/isScript into single uint8_t flags
fields with bit constants, mirroring the SCRIPT_BINARY_FLAG_ASYNC pattern
the bytecode format already uses and the flags-byte convention used
elsewhere in dusk (animation, display). While there, zero-initializes both
scriptfuncnode_t allocation sites (scriptAlloc never zeroes memory, so
several of its fields - not just the ones being packed here - were
previously read uninitialized before their first explicit write), and
removes scriptfunction_t's dead `plain` field, which was always the exact
inverse of isAsync and never actually read anywhere.
Converts the couple of struct-level doc comments that used the ported
project's Javadoc-with-@param style to dusk's plain // prose convention,
and adds missing rationale comments to scriptruntime_t and scriptstring_t,
which had none at all.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
util/memory.h had landed as the very first #include in ~30 files from the
mechanical memcpy/memcmp conversion, ahead of each file's own umbrella type
header - moves it back after, matching the rest of the codebase's ordering.
Also updates a scriptplatform.h comment left over from the int/fixed/bignum
split, and drops an unused util/string.h include in scriptcompile.c.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Brings over the duskscript VM and compiler from dusk-vm: the runtime
(core/vm) lives under src/dusk/script, gated by DUSK_SCRIPT and wired into
the engine lifecycle with print()/consolePrint() routed to the console; the
standalone duskscriptcc compiler stays a lean host tool (linux/knulli only).
Collapses int/fixed/bignum into a single float-backed SCRIPT_VALUE_NUMBER
throughout the lexer, compiler, bytecode format and VM, removing the old
int16-rollover fast paths and the type-conversion builtins they needed.
Fixes a real big-endian bug in the bytecode's 32-bit number reader (found
while adding GameCube/Wii endian support via util/endian.h) and converts
src/dusk/script and duskscriptcc to dusk's memory/string/assert utilities,
which surfaced two more latent bugs: a conservative GC stack scan reading
its own local variable's address, and an uninitialized path buffer in
scriptReadScript when the caller path has no directory component.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Save slots now track the currently-active cutscene file (defaulting to a
new placeholder new_game.jsonc intro) so loading a save resumes it;
cutsceneSystemStartCutsceneWith persists this on every cutscene start, and
a cutsceneSystemLoad ordering bug (loadedFile stamped after starting) is
fixed so the persisted path is always correct. Also adds a
battlefighterspecies_t/battlespeciesid_t stub for upcoming species data.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Replaces three independently hand-rolled battlefighter_t JSON readers/
writers (party.jsonc roster loading, BATTLE_START enemy definitions, and
the v1 save-file party member format) with one generic pair in
battlefighter.c: battleFighterParse(fighter, obj) and its inverse
battleFighterSerialize(fighter, doc). Covers team/controller/status
(optional, default ally/player/normal), the 7 base stats (required),
current health/mp (optional, default to max), and an optional abilities
name array.
- party.c: partyInit now parses each roster member via battleFighterParse
directly, dropping the old partyParseStats/partyParseStatField.
- cutscenebattlestart.c/.h: cutscenebattlestartenemy_t now embeds a full
battlefighter_t, parsed once at Load time; Start just copies it into the
enemy pool instead of re-initializing. battletest.jsonc's enemies are
now flat (dropped the "stats" wrapper) to match.
- saveslotver1.c/.h: rewritten in place to use the shared parser/
serializer, changing the v1 on-disk field names/shape (no migration -
acceptable pre-release, documented in saveslotver1.h).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- party.jsonc's "members" is now a key/value object (e.g. "hero",
"companion") instead of an array - partyInit seeds party_t.keys
alongside members, and partyGetMemberIndexByKey/partyGetMemberKey do the
lookups. Cutscene items (PARTY_ADD_MEMBER/PARTY_REMOVE_MEMBER/
PARTY_HEAL_MEMBER) now take a "key" JSON field, resolved to a roster
index at load time, instead of a raw index.
- Battle UI shows who's acting: uibattlemenu.c draws the current fighter's
party key above the action menu, and uibattlehud.c draws each ally
fighter's key as an extra line above their HP/MP.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Battle selection menu can now go back a fighter to re-decide their move,
and battle win/loss no longer leaks the round's remaining queued move
cutscenes into the ending state (cutsceneSystemDiscardQueued).
- Party roster is now driven by party.jsonc: every defined member always
exists (partyInit), while party->order alone determines who's currently
active - partyAddMember/partyRemoveMember (and their cutscene items) now
activate/deactivate an existing roster member by index instead of
creating/destroying one, with removal compacting order to stay packed.
- New PARTY_ADD_MEMBER/PARTY_REMOVE_MEMBER/PARTY_HEAL_MEMBER/PARTY_HEAL_ALL
cutscene items.
- saveSlotInit/partyInit now return errorret_t and take their target
struct directly (saveslot_t*/party_t*) instead of implicitly operating
on SAVE.slot; saveSlotReadJSON resets through saveSlotInit rather than
duplicating the reset logic.
- Test coverage: stub the JSON asset loader in save test fixtures so
partyInit's real party.jsonc load runs against an in-memory doc instead
of hanging with no asset system initialized.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
cutsceneCutsceneResolve and cutsceneSystemLoad could be called with a
name/path pointer that aliases into CUTSCENE_SYSTEM.loadedItems (e.g. a
CUTSCENE item's own name field). cutsceneLoadParse then overwrites that
same buffer while loading the target cutscene, so the subsequent
stringCopy into loadedFile read stale, corrupted memory. Copy the
name/path into a local buffer before use in both functions.
- battleStateSelectionAiDecide: AI-controlled fighters now actually
queue a basic attack against the first living enemy instead of doing
nothing every round.
- battleStateEndingInit: disposes the battle and switches back to
SCENE_TYPE_OVERWORLD instead of leaving the game stuck in the battle
scene forever.
- cutsceneSystemNext now pops each finished item off the front of the
running cutscene (cutsceneRemoveFront) instead of leaving it in place
forever, so a long-running cutscene (many battle rounds splicing
items in repeatedly) no longer grows scene->items unboundedly.
- cutsceneGoTo reworked to match: since consumed items are evicted, a
marker behind the current position can't be found in the live queue
anymore, so it now re-parses the cutscene fresh from its source file
(cutsceneLoadParse, into a persistent scratch buffer, not the stack)
and replaces the live queue with marker-onward from that fresh parse.
Only supported when the running cutscene is the one
cutsceneSystemLoad/cutsceneCutsceneResolve populated.
- Fixed a real bug this surfaced: cutsceneSystemPrepare unconditionally
cleared loadedFile, which ran *after* cutsceneCutsceneResolve had
just stamped it but *before* the cutscene started - wiping it out
immediately and breaking cutsceneGoTo for any cutscene entered via a
CUTSCENE item or cutsceneCutsceneResolve (e.g. the main menu's
NEW_GAME/OPTIONS/QUIT navigation). Now only cleared when switching
away from loadedScene entirely.
- Added cutsceneLoadParse, the shared "lock asset, require loaded,
parse items, unlock" sequence, replacing four near-identical copies
across cutsceneSystemLoad/cutsceneCutsceneResolve/
cutsceneInsertResolveAndSplice/battleStateExecutingInit. Each call
site handles its own fatal-error display; cutsceneLoadParse itself
just propagates.
- Added test_cutscene.c (cutsceneRemoveFront) and a regression test for
the loadedFile bug. Writing the zero-count RemoveFront test caught a
real self-move bug (count == 0 passed dest == src into memoryMove).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
BATTLE_FIGHTER_DAMAGE/BATTLE_FIGHTER_HEAL let a move's own cutscene
apply damage/healing to "target" or "user", resolved from
BATTLE_FIGHTER_POS_TARGET/USER sentinels against the current action by
battleStateExecutingInit. fire/slash now call BATTLE_FIGHTER_DAMAGE on
their target.
BATTLE_POST_MOVE checks fighter health after each move and sets
BATTLE.result (now a real field, previously commented out) to
win/loss, transitioning into BATTLE_STATE_WON/LOST; fleeing sets
BATTLE_RESULT_FLED. All three end states now show a textbox before
moving on to BATTLE_STATE_ENDING.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Each queued action now resolves to its move's cutscene
(cutscenes/battle/moves/<name>.jsonc), spliced into the executing state
with a BATTLE_POST_MOVE checkpoint after each one. Fighter turn order is
tracked via fighterOrder/fighterOrderCount, and resolved actions/pending
counts are cleared so fighters aren't skipped in later rounds. Also fixes
a BATTLE_WAIT_SELECTION deadlock and adds an optional "blocking" flag to
MODAL cutscene items.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Adds BATTLE_START, BATTLE_SET_STATE and BATTLE_WAIT_SELECTION cutscene
items so a battle's state transitions (opening -> pre-round -> selection
-> executing) are chained through the running cutscene, with
cutsceneSystemInsertItemsNext/InsertItems splitting "splice" from
"splice and advance immediately". Adds battlestateselection's
get-current-fighter/player-attack/player-flee API backing the battle UI,
and battleMoveGetIdByName for JSON-authored ability lookups.
Fixes: off-by-one in battleMoveInit that let the first-defined move
alias BATTLE_MOVE_ID_NULL; a segfault in scenebattle.c from rendering
unfilled (NULL) fighter slots; stale battleGetCurrentFighter/
battlePlayerAttack/battlePlayerFlee references in the battle UI.
Adds assertions across the battle/scene/UI code for fighter-index
bounds and non-null invariants. Updates battletest.jsonc for the new
BATTLE_START item schema.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Splits battlemoveaction_t into its own header, adds a per-state
struct/init/update/dispose file under rpg/battle/state driven by a
dispatch table, switches BATTLE.fighters to battlefighter_t* backed by a
pool, folds current/max health and mp into battlefighterstats_t, and adds
battleFighterDamage/Heal/AbilityAdd. Removes the now-unused battle
cutscene items (START_BATTLE, BATTLE_WAIT_STATE, BATTLE_FORCE_MOVE,
REGULAR_BATTLE) and their JSON lookup helpers, and adds JSON validation
to battleMoveInit. battle.h/battle.c are mid-rewrite around the new state
machine, so some UI consumers (uibattlehud.c, uibattlemenu.c) and
test_battle.c are currently out of sync with the new API.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
cutsceneCutsceneResolve/cutsceneInsertResolveAndSplice no longer inject
a "cutscenes/%s.jsonc" prefix/suffix around an item's "name" field -
matching cutsceneSystemLoad, which already takes a full path. Fixes a
latent double-prefix bug in initial.jsonc's CUTSCENE reference (also had
a "jsonsc" typo) that this change would otherwise have exposed.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
uiLabelInit now marks a fresh label dirty itself, instead of every call
site having to remember to do it. Adds uiLabelSetWrap (NULL buffer
disables wrapping, otherwise requires a positive width) built on the
existing textWrap(), and wires the fatal error overlay's message label
up to wrap at 80% of screen width.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Implements storyInit/storyGetFlagByName/storyGetFlagValue/etc, moves flag
storage into saveslot_t (persisted keyed by name so save files survive
flag reordering), and adds STORY_SET_FLAG/STORY_WAIT_FLAG cutscene items.
Also removes the now-superseded storyflag.c/h stub.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Comments-only change - drops implementation rationale/cross-referencing
detail in favor of shorter one-liners, matching the simplified style
already applied to part of the file.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
cutsceneSystemLoad, cutsceneCutsceneResolve and
cutsceneInsertResolveAndSplice all used to steal ownership of the
asset entry's parsed yyjson_doc (nulling entry->data.json) and force
an immediate assetReapUnused() to avoid handing back a corrupted
cache entry on a later load of the same file - which doubled as a
latent crash if that reap was ever skipped (as it briefly was),
since a stale cache hit would then have a NULL doc.
Turns out none of that was needed: every cutsceneitem_t field that
could reference the doc's memory already copies its string data by
value (cutsceneJsonCopyString into fixed buffers), so the parsed
items don't depend on the doc surviving past cutsceneParseDoc. All
three call sites now parse straight out of entry->data.json while
still locked, then unlock normally - the asset entry stays a normal,
correctly-cached resource, and CUTSCENE_LOADED_DOC/cutsceneLoadedSetDoc
are gone entirely.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Adds CUTSCENE_SYSTEM.loadedFile, set by cutsceneSystemLoad and cleared
by cutsceneSystemPrepare. cutsceneRestart now re-reads and re-parses
that file via cutsceneSystemLoad instead of just rerunning whatever's
still resident in loadedScene/loadedItems, so restarting a file-loaded
cutscene always reflects its current on-disk contents - restart of a
C-authored cutscene is unchanged.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Matches the existing assertNotNull convention in cutscene.c
(cutsceneAppend/cutsceneParseDoc etc.) - these are internal-API
preconditions on trusted callers, not untrusted input.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Nothing ever wrote to it - it only ever passed its own address through
to onComplete/CUTSCENE_CALLBACK/modal-option callbacks, so every call
site now passes NULL directly and the 8KB buffer is gone.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Replaces the separate insert buffer/scene and insertStack return-frame
mechanism with cutsceneAppend/cutsceneAppendNext, so an inserted
cutscene's items become part of the running scene's own array instead
of a jump-and-return. Moves the loaded-items buffer/scene from file-scope
globals into cutscenesystem_t, and extracts shared start-cutscene setup
into cutsceneSystemPrepare.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
cutsceneAppend adds items to the end of a cutscene_t's item array;
cutsceneAppendNext inserts them at a given index instead (e.g.
CUTSCENE_SYSTEM.currentItem + 1, to run immediately after the
currently-executing item), shifting everything from that index
onward to make room. Both are capacity-bounded against the caller-
supplied itemsMax, matching cutsceneParseDoc's convention of never
assuming ownership of the backing buffer's size.
cutscene_t.items drops its const qualifier to allow this in-place
mutation; cutsceneitem_t backing arrays in the test fixtures that get
assigned into a mutable cutscene_t.items are no longer declared const
either, since a const source would otherwise silently violate the
field's new type.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Matches the existing battleability.h/battlefighter.h split - keeps
battle.h focused on the overall battle_t state machine rather than
also owning the action data shape.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Lets a move reference a cutscene to play when used, resolved by name
the same way a CUTSCENE item's "name" field is. Still just a schema
placeholder - no loader consumes moves.jsonc yet.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Groups item data under assets/items/ to match the cutscenes/ folder
convention, updating itemInit()'s asset path accordingly. Also adds
assets/battle/moves.jsonc as a starting point for move data - there's
no JSON loader consuming it yet (battleability_t is still just a bare
enum), so its field shape is a placeholder rather than a contract.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Every CUTSCENE_XXX(...) shorthand (CUTSCENE_WAIT, CUTSCENE_TEXT,
CUTSCENE_ENTITY_WALK_TO, etc.) existed to build a cutsceneitem_t literal
in C; real cutscenes are now authored exclusively as .jsonc files, and
the only other users were test fixtures. Deletes all ~55 of these
macros (and the shared CUTSCENE_ITEM(...) helper they built on) along
with their doc comments, leaving each item's struct/enum/Start/Update/
Load declarations untouched.
test_battle.c, test_cutscenecontrol.c, test_cutscenemaparea.c,
test_cutscenesystem.c and test_entityinteract.c now build their
cutsceneitem_t fixtures as plain struct literals instead.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
CUTSCENE(...)/CUTSCENE_REFERENCE/CUTSCENE_CUTSCENE/CUTSCENE_INSERT
existed to build a cutscene_t and its item array directly in C; real
cutscenes are now authored exclusively as .jsonc files parsed via
cutsceneParseDoc, so these are dead weight in production. Deletes the
demo scene that still used them (testcutscene.h, wired to NPC #3) along
with its now-dead include in npc.c. test_cutscenesystem.c - the only
other user, building cutscenes in-memory for tests - now writes the
equivalent struct literals directly, matching the convention already
used by test_battle.c/test_entityinteract.c.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Cutscenes now load through the generic ASSET_LOADER_TYPE_JSON loader
and parse straight into fixed static buffers via new cutsceneParseDoc/
cutsceneParseItem/cutsceneCountItems helpers (cutscene.c), removing the
bespoke ASSET_LOADER_TYPE_CUTSCENE pipeline entirely. Only one cutscene
(plus one INSERT target) is ever resident, so each resolve locks,
steals the parsed doc, unlocks, and force-reaps immediately - fixing a
stale-cache-reuse bug where revisiting a cutscene name after a
different one could return data from the shared buffer's previous
occupant.
ENTITY_WALK_TO and MAP_AREA_WAIT now store their waypoints/area ids in
fixed-size arrays inline on their own item struct instead of a shared
bump-allocated pool, so pool/poolOffset are gone from every item type's
Load callback. cutscene_t.dataSize (and the CUTSCENE(...) macro's SIZE
parameter) is removed along with it - it sized entries out of that same
now-deleted pool and had no other reader.
NPC #4's battletest cutscene and the main menu's cutscene now resolve
their target by name on interact instead of eagerly at init, so a
resolved-once pointer is never held past the point its backing buffer
can be reused for something else.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Replaces the build-time item.json/tools.item.py code generator with a
single item_t ITEM registry populated at runtime by parsing
assets/items.jsonc, so items/types can grow without a rebuild. Adds
itemGetDefById/itemGetTypeById/itemGetIdByName/itemTypeGetOrCreate,
updates inventory/backpack to size off the new *_DEF_COUNT_MAX caps
and look up types dynamically, and reorders engine init so rpgInit
(which loads items) runs before uiInit (which needs the item type
count to size the backpack's tabs).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Splicing a JSON-authored INSERT target by name previously resolved
through the same shared CUTSCENE_LOADED_ITEMS/POOL buffer as whatever
outer cutscene was currently running, so loading it would clobber the
outer cutscene's own items mid-playback - that's why it was reverted.
Gives INSERT its own smaller CUTSCENE_INSERT_ITEMS/POOL buffer and lets
the cutscene asset loader be told which buffer set to parse into, so an
INSERT's dynamic load no longer stomps the running cutscene.
Co-Authored-By: Claude Sonnet 5 <[email protected]>