Options and Quit now route through main_menu.jsonc markers the same way New Game does, with a new QUIT_GAME cutscene item type ending the process directly once quit is confirmed via MODAL_OPTIONS_MARKERS (whose "message" field is now optional, defaulting to "" like "title"). Fixes two crashes surfaced along the way: - uiModalLocalize asserted on an empty locale key instead of treating it as "nothing to show" - hit as soon as a modal omitted a title or message. - assetLocaleGetString's new empty-message-ID guard broke the PO format's own header-read convention (messageId "") used internally by assetLocaleLoaderAsync, crashing on every boot. Extracted the shared lookup into assetLocaleGetStringLookup and added a dedicated assetLocaleGetHeader for that internal read, leaving assetLocaleGetString's validation untouched for every real caller. Also replaced every raw assetLocaleGetString/WithVA call across the UI with the locale/localemanager.h helpers (adding localeManagerGetString for the plain, non-formatting case), so app code no longer bypasses them. Co-Authored-By: Claude Sonnet 5 <[email protected]>
134 lines
2.8 KiB
JSON
134 lines
2.8 KiB
JSON
{
|
|
"items": [
|
|
{
|
|
"type": "MARKER",
|
|
"name": "MAIN_MENU_IDLE"
|
|
},
|
|
{
|
|
"type": "UI_SHOW",
|
|
"name": "main_menu"
|
|
},
|
|
|
|
// Options button goes here - no options screen yet, so this is just
|
|
// an alias landing right back on the idle loop below.
|
|
{
|
|
"type": "MARKER",
|
|
"name": "OPTIONS"
|
|
},
|
|
{
|
|
"type": "IDLE"
|
|
},
|
|
|
|
// New Game button goes here.
|
|
{
|
|
"type": "MARKER",
|
|
"name": "NEW_GAME"
|
|
},
|
|
{
|
|
"type": "MODAL",
|
|
"title": "main_menu.checking_save.title",
|
|
"message": "main_menu.checking_save.message"
|
|
},
|
|
{
|
|
"type": "WAIT",
|
|
"seconds": 0.2
|
|
},
|
|
{
|
|
"type": "SAVE_DEVICE_CHECK",
|
|
"successMarker": "SAVE_DEVICE_FOUND",
|
|
"failureMarker": "SAVE_DEVICE_NOT_FOUND"
|
|
},
|
|
|
|
// Save device not found
|
|
{
|
|
"type": "MARKER",
|
|
"name": "SAVE_DEVICE_NOT_FOUND"
|
|
},
|
|
{
|
|
"type": "MODAL_CLOSE"
|
|
},
|
|
{
|
|
"type": "MODAL_OPTIONS_MARKERS",
|
|
"title": "main_menu.no_device.title",
|
|
"message": "main_menu.no_device.message",
|
|
"options": [
|
|
{
|
|
"text": "main_menu.no_device.retry",
|
|
"marker": "NEW_GAME"
|
|
},
|
|
{
|
|
"text": "main_menu.no_device.continue",
|
|
"marker": "SAVE_DEVICE_FOUND"
|
|
}
|
|
]
|
|
},
|
|
|
|
// Save device found
|
|
{
|
|
"type": "MARKER",
|
|
"name": "SAVE_DEVICE_FOUND"
|
|
},
|
|
{
|
|
"type": "MODAL_CLOSE"
|
|
},
|
|
{
|
|
"type": "SAVE_LOAD_ALL_SLOTS",
|
|
"successMarker": "LOADED",
|
|
"failureMarker": "LOAD_ERROR"
|
|
},
|
|
|
|
// Save data failed to load (e.g. corrupt/unreadable) - only option is
|
|
// to retry, no "continue without saving" here since we already know a
|
|
// device is present.
|
|
{
|
|
"type": "MARKER",
|
|
"name": "LOAD_ERROR"
|
|
},
|
|
{
|
|
"type": "MODAL_OPTIONS_MARKERS",
|
|
"title": "main_menu.save_load_error.title",
|
|
"message": "main_menu.save_load_error.message",
|
|
"options": [
|
|
{
|
|
"text": "main_menu.save_load_error.retry",
|
|
"marker": "NEW_GAME"
|
|
}
|
|
]
|
|
},
|
|
|
|
{
|
|
"type": "MARKER",
|
|
"name": "LOADED"
|
|
},
|
|
|
|
// Quit Game button goes here. Cancelling jumps back to
|
|
// MAIN_MENU_IDLE; confirming falls through to QUIT_GAME, which
|
|
// ends the process directly.
|
|
{
|
|
"type": "MARKER",
|
|
"name": "QUIT"
|
|
},
|
|
{
|
|
"type": "MODAL_OPTIONS_MARKERS",
|
|
"title": "main_menu.quit_confirm",
|
|
"options": [
|
|
{
|
|
"text": "ui.confirm.confirm",
|
|
"marker": "QUIT_CONFIRMED"
|
|
},
|
|
{
|
|
"text": "ui.confirm.cancel",
|
|
"marker": "MAIN_MENU_IDLE"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "MARKER",
|
|
"name": "QUIT_CONFIRMED"
|
|
},
|
|
{
|
|
"type": "QUIT_GAME"
|
|
}
|
|
]
|
|
}
|