e630827b34
New ASSET_LOADER_TYPE_CUTSCENE (assetcutsceneloader.c) reads a versioned binary .cts format decoded into a heap-allocated cutsceneitem_t array + a string/data pool, both sized to the file's actual content rather than a fixed capacity, so the shared assetloaderoutput_t union doesn't bloat for every asset slot regardless of type. Authoring pipeline mirrors the chunk asset pattern: assetsraw/cutscenes/*.jsonc (JSON plus // and /* */ comments) -> tools/asset/cutscene -> assets/cutscenes/*.cts. cutsceneSystemSetOnComplete() lets the caller arm a native callback that fires when a cutscene finishes normally, so a file (which can't store a function pointer) can end plainly and still hand off to native code - cutsceneRestart() preserves it across a retry loop rather than clearing it, since a restart is the same logical run trying again. The initial and main-menu start-game cutscenes are now loaded from files instead of compiled in via the CUTSCENE(...) macro. Fixed a real bug found while converting these: the sync loader read the file's total size from assetfile_t.size to locate the trailing pool region, but assetFileDispose() (called at the end of the async phase) zeroes that whole struct first, so the size was always 0 and the pool offset computation underflowed into an out-of-bounds read - intermittent depending on heap layout. Fixed by saving the size before disposal; also fixed the read-completeness assert being checked after that same zeroing (a no-op 0 == 0 check). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
70 lines
1.3 KiB
JSON
70 lines
1.3 KiB
JSON
{
|
|
"items": [
|
|
// Boot check: make sure a save device is available before handing off
|
|
// to the main menu.
|
|
{
|
|
"type": "MODAL",
|
|
"title": "initial.checking_save.title",
|
|
"message": "initial.checking_save.message"
|
|
},
|
|
{
|
|
"type": "WAIT",
|
|
"seconds": 0.2
|
|
},
|
|
{
|
|
"type": "SAVE_DEVICE_CHECK",
|
|
"successMarker": "CONTINUE",
|
|
"failureMarker": "NO_DEVICE"
|
|
},
|
|
|
|
// No save device found - offer to retry or continue without saving.
|
|
{
|
|
"type": "MARKER",
|
|
"name": "NO_DEVICE"
|
|
},
|
|
{
|
|
"type": "MODAL_CLOSE"
|
|
},
|
|
{
|
|
"type": "MODAL_OPTIONS_MARKERS",
|
|
"title": "initial.no_device.title",
|
|
"message": "initial.no_device.message",
|
|
"options": [
|
|
{
|
|
"text": "initial.no_device.retry",
|
|
"marker": "RETRY"
|
|
},
|
|
{
|
|
"text": "initial.no_device.continue",
|
|
"marker": "CONTINUE"
|
|
}
|
|
]
|
|
},
|
|
|
|
{
|
|
"type": "MARKER",
|
|
"name": "RETRY"
|
|
},
|
|
{
|
|
"type": "MODAL_CLOSE"
|
|
},
|
|
{
|
|
"type": "RESTART"
|
|
},
|
|
|
|
// Save device found (or continuing without one) - hand off to the
|
|
// main menu scene.
|
|
{
|
|
"type": "MARKER",
|
|
"name": "CONTINUE"
|
|
},
|
|
{
|
|
"type": "MODAL_CLOSE"
|
|
},
|
|
{
|
|
"type": "SCENE",
|
|
"sceneType": "MAIN_MENU"
|
|
}
|
|
]
|
|
}
|