Add declarative cutscene items for save checks and marker-based modals
CUTSCENE_SAVE_DEVICE_CHECK and CUTSCENE_SAVE_LOAD_ALL_SLOTS wrap the existing device-lookup/slot-load calls and jump straight to a success/failure marker, and CUTSCENE_MODAL_OPTIONS_ONE/TWO do the same for one/two-option modals, removing the need for a hand-written goTo-only callback per use. Main menu's "Start Game" now runs a cutscene (mirroring the initial scene's save-check flow) that loads all slots before opening the load-game picker, retrying on error; the initial scene's own device check is migrated onto the same items. Backing out of the main menu now returns to the initial scene. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -120,6 +120,42 @@ typedef struct cutscene_s {
|
||||
} \
|
||||
}
|
||||
|
||||
// Same as CUTSCENE_MODAL_OPTIONS, but fixed to exactly one option and
|
||||
// MARKER1 to jump straight to via cutsceneGoTo once it's selected (or
|
||||
// the dialog is backed out of) - no callback function to write. Does
|
||||
// not fall through to whatever follows this item, so MARKER1 must be
|
||||
// scripted elsewhere in the same cutscene.
|
||||
#define CUTSCENE_MODAL_OPTIONS_ONE(TITLE, MESSAGE, OPTION1, MARKER1) \
|
||||
{ \
|
||||
.type = CUTSCENE_ITEM_TYPE_MODAL_OPTIONS_MARKERS, \
|
||||
.modalOptionsMarkers = { \
|
||||
.title = TITLE, .message = MESSAGE, \
|
||||
.options = { OPTION1 }, \
|
||||
.markers = { MARKER1 }, \
|
||||
.optionCount = 1 \
|
||||
} \
|
||||
}
|
||||
|
||||
// Same as CUTSCENE_MODAL_OPTIONS, but fixed to exactly two options,
|
||||
// jumping straight to OPTION1_MARKER or OPTION2_MARKER via cutsceneGoTo
|
||||
// once the corresponding option is selected - no callback function to
|
||||
// write. Backing out without selecting (UI_MODAL_RESULT_NONE) is
|
||||
// treated the same as selecting option 2. Does not fall through to
|
||||
// whatever follows this item, so both markers must be scripted
|
||||
// elsewhere in the same cutscene.
|
||||
#define CUTSCENE_MODAL_OPTIONS_TWO( \
|
||||
TITLE, MESSAGE, OPTION1, OPTION1_MARKER, OPTION2, OPTION2_MARKER \
|
||||
) \
|
||||
{ \
|
||||
.type = CUTSCENE_ITEM_TYPE_MODAL_OPTIONS_MARKERS, \
|
||||
.modalOptionsMarkers = { \
|
||||
.title = TITLE, .message = MESSAGE, \
|
||||
.options = { OPTION1, OPTION2 }, \
|
||||
.markers = { OPTION1_MARKER, OPTION2_MARKER }, \
|
||||
.optionCount = 2 \
|
||||
} \
|
||||
}
|
||||
|
||||
// Closes the currently open modal (if any). Useful when a modal was
|
||||
// opened outside of a blocking CUTSCENE_MODAL item (e.g. directly via
|
||||
// uiModalOpen) and this cutscene just needs to dismiss it and continue
|
||||
@@ -127,6 +163,34 @@ typedef struct cutscene_s {
|
||||
#define CUTSCENE_MODAL_CLOSE() \
|
||||
{ .type = CUTSCENE_ITEM_TYPE_MODAL_CLOSE }
|
||||
|
||||
// (Re)requests an available save device and jumps straight to
|
||||
// SUCCESS_MARKER or FAILURE_MARKER once it resolves, same as a
|
||||
// CUTSCENE_MODAL_OPTIONS callback - it does not fall through to
|
||||
// whatever follows this item, so both markers must be scripted
|
||||
// elsewhere in the same cutscene.
|
||||
#define CUTSCENE_SAVE_DEVICE_CHECK(SUCCESS_MARKER, FAILURE_MARKER) \
|
||||
{ \
|
||||
.type = CUTSCENE_ITEM_TYPE_SAVE_DEVICE_CHECK, \
|
||||
.saveDeviceCheck = { \
|
||||
.successMarker = SUCCESS_MARKER, \
|
||||
.failureMarker = FAILURE_MARKER \
|
||||
} \
|
||||
}
|
||||
|
||||
// (Re)loads every save slot via saveLoadAllSlots() and jumps straight to
|
||||
// SUCCESS_MARKER or FAILURE_MARKER once it resolves, same shape as
|
||||
// CUTSCENE_SAVE_DEVICE_CHECK - it does not fall through to whatever
|
||||
// follows this item, so both markers must be scripted elsewhere in the
|
||||
// same cutscene.
|
||||
#define CUTSCENE_SAVE_LOAD_ALL_SLOTS(SUCCESS_MARKER, FAILURE_MARKER) \
|
||||
{ \
|
||||
.type = CUTSCENE_ITEM_TYPE_SAVE_LOAD_ALL_SLOTS, \
|
||||
.saveLoadAllSlots = { \
|
||||
.successMarker = SUCCESS_MARKER, \
|
||||
.failureMarker = FAILURE_MARKER \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CUTSCENE_ENTITY_WALK_TO(ENTITY_INDEX, X, Y, Z) \
|
||||
{ \
|
||||
.type = CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO, \
|
||||
|
||||
@@ -16,3 +16,4 @@ add_subdirectory(item)
|
||||
add_subdirectory(maparea)
|
||||
add_subdirectory(ui)
|
||||
add_subdirectory(battle)
|
||||
add_subdirectory(save)
|
||||
|
||||
@@ -134,6 +134,11 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
||||
.update = cutsceneModalUpdate
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_MODAL_OPTIONS_MARKERS] = {
|
||||
.init = cutsceneModalOptionsMarkersStart,
|
||||
.update = cutsceneModalOptionsMarkersUpdate
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_MODAL_CLOSE] = {
|
||||
.init = cutsceneModalCloseStart,
|
||||
.update = cutsceneModalCloseUpdate
|
||||
@@ -157,6 +162,16 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
||||
[CUTSCENE_ITEM_TYPE_SCENE] = {
|
||||
.init = cutsceneSceneStart,
|
||||
.update = cutsceneSceneUpdate
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_SAVE_DEVICE_CHECK] = {
|
||||
.init = cutsceneSaveDeviceCheckStart,
|
||||
.update = cutsceneSaveDeviceCheckUpdate
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_SAVE_LOAD_ALL_SLOTS] = {
|
||||
.init = cutsceneSaveLoadAllSlotsStart,
|
||||
.update = cutsceneSaveLoadAllSlotsUpdate
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "ui/cutsceneemoji.h"
|
||||
#include "ui/cutsceneshake.h"
|
||||
#include "ui/cutscenemodal.h"
|
||||
#include "ui/cutscenemodaloptionsmarkers.h"
|
||||
#include "item/cutsceneitemgive.h"
|
||||
#include "maparea/cutscenemapareaadd.h"
|
||||
#include "maparea/cutscenemaparearemove.h"
|
||||
@@ -34,6 +35,8 @@
|
||||
#include "battle/cutscenestartbattle.h"
|
||||
#include "battle/cutscenebattlewaitstate.h"
|
||||
#include "battle/cutscenebattleforceaction.h"
|
||||
#include "save/cutscenesavedevicecheck.h"
|
||||
#include "save/cutscenesaveloadallslots.h"
|
||||
|
||||
typedef struct cutscene_s cutscene_t;
|
||||
|
||||
@@ -65,11 +68,14 @@ typedef enum {
|
||||
CUTSCENE_ITEM_TYPE_BATTLE_WAIT_STATE,
|
||||
CUTSCENE_ITEM_TYPE_BATTLE_FORCE_ACTION,
|
||||
CUTSCENE_ITEM_TYPE_MODAL,
|
||||
CUTSCENE_ITEM_TYPE_MODAL_OPTIONS_MARKERS,
|
||||
CUTSCENE_ITEM_TYPE_MODAL_CLOSE,
|
||||
CUTSCENE_ITEM_TYPE_PRINT,
|
||||
CUTSCENE_ITEM_TYPE_MARKER,
|
||||
CUTSCENE_ITEM_TYPE_RESTART,
|
||||
CUTSCENE_ITEM_TYPE_SCENE,
|
||||
CUTSCENE_ITEM_TYPE_SAVE_DEVICE_CHECK,
|
||||
CUTSCENE_ITEM_TYPE_SAVE_LOAD_ALL_SLOTS,
|
||||
|
||||
CUTSCENE_ITEM_TYPE_COUNT
|
||||
} cutsceneitemtype_t;
|
||||
@@ -103,9 +109,12 @@ struct cutsceneitem_s {
|
||||
cutscenebattlewaitstate_t battleWaitState;
|
||||
cutscenebattleforceaction_t battleForceAction;
|
||||
cutscenemodal_t modal;
|
||||
cutscenemodaloptionsmarkers_t modalOptionsMarkers;
|
||||
cutsceneprint_t print;
|
||||
cutscenemarker_t marker;
|
||||
cutscenescene_t sceneChange;
|
||||
cutscenesavedevicecheck_t saveDeviceCheck;
|
||||
cutscenesaveloadallslots_t saveLoadAllSlots;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
cutscenesavedevicecheck.c
|
||||
cutscenesaveloadallslots.c
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "save/save.h"
|
||||
|
||||
void cutsceneSaveDeviceCheckCallback(savedevice_t *device, void *user) {
|
||||
const cutsceneitem_t *item = cutsceneSystemGetCurrentItem();
|
||||
cutsceneGoTo(
|
||||
device != NULL ?
|
||||
item->saveDeviceCheck.successMarker :
|
||||
item->saveDeviceCheck.failureMarker
|
||||
);
|
||||
}
|
||||
|
||||
void cutsceneSaveDeviceCheckStart(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
) {
|
||||
saveFindAvailableDevice(cutsceneSaveDeviceCheckCallback, NULL);
|
||||
}
|
||||
|
||||
bool_t cutsceneSaveDeviceCheckUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *successMarker;
|
||||
const char_t *failureMarker;
|
||||
} cutscenesavedevicecheck_t;
|
||||
|
||||
/**
|
||||
* Starts a save-device-check item: (re)requests an available save
|
||||
* device via saveFindAvailableDevice. Never completes on its own - see
|
||||
* cutsceneSaveDeviceCheckUpdate.
|
||||
*
|
||||
* @param item The cutscene item.
|
||||
* @param data Runtime data storage.
|
||||
*/
|
||||
void cutsceneSaveDeviceCheckStart(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates a save-device-check item. Like a CUTSCENE_MODAL_OPTIONS item,
|
||||
* this never completes on its own - once saveFindAvailableDevice's
|
||||
* callback fires, it jumps straight to the item's successMarker or
|
||||
* failureMarker via cutsceneGoTo.
|
||||
*
|
||||
* @param item The cutscene item.
|
||||
* @param data Runtime data storage.
|
||||
* @returns false always.
|
||||
*/
|
||||
bool_t cutsceneSaveDeviceCheckUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "save/save.h"
|
||||
|
||||
void cutsceneSaveLoadAllSlotsStart(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
) {
|
||||
errorret_t result = saveLoadAllSlots();
|
||||
if(errorIsNotOk(result)) {
|
||||
errorCatch(errorPrint(result));
|
||||
cutsceneGoTo(item->saveLoadAllSlots.failureMarker);
|
||||
return;
|
||||
}
|
||||
|
||||
cutsceneGoTo(item->saveLoadAllSlots.successMarker);
|
||||
}
|
||||
|
||||
bool_t cutsceneSaveLoadAllSlotsUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *successMarker;
|
||||
const char_t *failureMarker;
|
||||
} cutscenesaveloadallslots_t;
|
||||
|
||||
/**
|
||||
* Starts a save-load-all-slots item: calls saveLoadAllSlots() and jumps
|
||||
* straight to the item's successMarker or failureMarker via
|
||||
* cutsceneGoTo, depending on the result.
|
||||
*
|
||||
* @param item The cutscene item.
|
||||
* @param data Runtime data storage.
|
||||
*/
|
||||
void cutsceneSaveLoadAllSlotsStart(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates a save-load-all-slots item. Never completes on its own -
|
||||
* Start already jumps to whichever marker applies before this would
|
||||
* ever run.
|
||||
*
|
||||
* @param item The cutscene item.
|
||||
* @param data Runtime data storage.
|
||||
* @returns false always.
|
||||
*/
|
||||
bool_t cutsceneSaveLoadAllSlotsUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
@@ -12,4 +12,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
cutsceneemoji.c
|
||||
cutsceneshake.c
|
||||
cutscenemodal.c
|
||||
cutscenemodaloptionsmarkers.c
|
||||
)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "ui/widget/uimodal.h"
|
||||
|
||||
void cutsceneModalOptionsMarkersCallback(
|
||||
const uint8_t optionIndex,
|
||||
void *userData
|
||||
) {
|
||||
const cutscenemodaloptionsmarkers_t *options =
|
||||
&cutsceneSystemGetCurrentItem()->modalOptionsMarkers;
|
||||
|
||||
// A backed-out-of dialog (UI_MODAL_RESULT_NONE) falls back to the
|
||||
// last option's marker, same as a hand-written two-option callback
|
||||
// (e.g. sceneInitialSaveDeviceRetryCallback) treating "backed out" as
|
||||
// the safe/continue choice rather than the destructive one.
|
||||
const uint8_t index =
|
||||
optionIndex < options->optionCount ? optionIndex : options->optionCount - 1;
|
||||
cutsceneGoTo(options->markers[index]);
|
||||
}
|
||||
|
||||
void cutsceneModalOptionsMarkersStart(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
) {
|
||||
const cutscenemodaloptionsmarkers_t *options = &item->modalOptionsMarkers;
|
||||
|
||||
uiModalOpen(
|
||||
options->title,
|
||||
options->message,
|
||||
options->options,
|
||||
options->optionCount,
|
||||
cutsceneModalOptionsMarkersCallback,
|
||||
NULL,
|
||||
CUTSCENE_SYSTEM.userData
|
||||
);
|
||||
}
|
||||
|
||||
bool_t cutsceneModalOptionsMarkersUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
// Backs CUTSCENE_MODAL_OPTIONS_ONE and CUTSCENE_MODAL_OPTIONS_TWO, so two
|
||||
// is the most either macro ever needs.
|
||||
#define CUTSCENE_MODAL_OPTIONS_MARKERS_MAX 2
|
||||
|
||||
typedef struct {
|
||||
// Display text, or a locale message ID to translate - see
|
||||
// uiModalLocalize.
|
||||
char_t title[CUTSCENE_MODAL_TITLE_MAX_CHARS];
|
||||
char_t message[CUTSCENE_MODAL_MESSAGE_MAX_CHARS];
|
||||
|
||||
// Each option's display text/locale message ID, and the marker to
|
||||
// cutsceneGoTo when that option is selected.
|
||||
const char_t *options[CUTSCENE_MODAL_OPTIONS_MARKERS_MAX];
|
||||
const char_t *markers[CUTSCENE_MODAL_OPTIONS_MARKERS_MAX];
|
||||
uint8_t optionCount;
|
||||
} cutscenemodaloptionsmarkers_t;
|
||||
|
||||
/**
|
||||
* Starts a modal-options-markers item (shows the modal dialog with the
|
||||
* item's title, message, and options).
|
||||
*
|
||||
* @param item The cutscene item.
|
||||
* @param data Runtime data storage.
|
||||
*/
|
||||
void cutsceneModalOptionsMarkersStart(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates a modal-options-markers item. Never completes on its own -
|
||||
* the cutscene blocks here indefinitely. Once an option is selected (or
|
||||
* the dialog is backed out of, which is treated as selecting the last
|
||||
* option), it jumps straight to that option's marker via cutsceneGoTo.
|
||||
*
|
||||
* @param item The cutscene item.
|
||||
* @param data Runtime data storage.
|
||||
* @returns false always.
|
||||
*/
|
||||
bool_t cutsceneModalOptionsMarkersUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
@@ -11,29 +11,24 @@
|
||||
#include "error/error.h"
|
||||
#include "display/screen/screen.h"
|
||||
#include "console/console.h"
|
||||
#include "save/save.h"
|
||||
#include "ui/widget/uimodal.h"
|
||||
#include "rpg/cutscene/cutscene.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
|
||||
void sceneInitialAvailableDeviceCallback(savedevice_t *device, void *user);
|
||||
void sceneInitialFindDevices(void *userData);
|
||||
void sceneInitialSaveDeviceRetryCallback(const uint8_t opt, void *u);
|
||||
|
||||
CUTSCENE(INITIAL, 0, DEFAULT,
|
||||
CUTSCENE_MODAL(
|
||||
"initial.checking_save.title", "initial.checking_save.message"
|
||||
),
|
||||
CUTSCENE_WAIT(1.0f),
|
||||
CUTSCENE_CALLBACK(sceneInitialFindDevices),
|
||||
CUTSCENE_SAVE_DEVICE_CHECK("CONTINUE", "NO_DEVICE"),
|
||||
|
||||
CUTSCENE_MARKER("NO_DEVICE"),
|
||||
CUTSCENE_MODAL_CLOSE(),
|
||||
CUTSCENE_MODAL_OPTIONS(
|
||||
CUTSCENE_MODAL_OPTIONS_TWO(
|
||||
"initial.no_device.title",
|
||||
"initial.no_device.message",
|
||||
sceneInitialSaveDeviceRetryCallback,
|
||||
"initial.no_device.retry", "initial.no_device.continue"
|
||||
"initial.no_device.retry", "RETRY",
|
||||
"initial.no_device.continue", "CONTINUE"
|
||||
),
|
||||
|
||||
CUTSCENE_MARKER("RETRY"),
|
||||
@@ -45,18 +40,6 @@ CUTSCENE(INITIAL, 0, DEFAULT,
|
||||
CUTSCENE_SCENE(SCENE_TYPE_MAIN_MENU)
|
||||
);
|
||||
|
||||
void sceneInitialAvailableDeviceCallback(savedevice_t *device, void *user) {
|
||||
cutsceneGoTo(device == NULL ? "NO_DEVICE" : "CONTINUE");
|
||||
}
|
||||
|
||||
void sceneInitialFindDevices(void *userData) {
|
||||
saveFindAvailableDevice(sceneInitialAvailableDeviceCallback, NULL);
|
||||
}
|
||||
|
||||
void sceneInitialSaveDeviceRetryCallback(const uint8_t opt, void *u) {
|
||||
cutsceneGoTo(opt == 0 ? "RETRY" : "CONTINUE");
|
||||
}
|
||||
|
||||
errorret_t sceneInitialInit(scenedata_t *sceneData) {
|
||||
assertNotNull(sceneData, "Scene data cannot be null");
|
||||
memoryZero(&sceneData->initial, sizeof(sceneinitial_t));
|
||||
|
||||
@@ -17,13 +17,57 @@
|
||||
#include "asset/loader/locale/assetlocaleloader.h"
|
||||
#include "ui/dialog/uiconfirm.h"
|
||||
#include "ui/dialog/save/uiselectsave.h"
|
||||
#include "rpg/cutscene/cutscene.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "scene/scene.h"
|
||||
#include "save/save.h"
|
||||
|
||||
#define UI_MAIN_MENU_INDEX_START_GAME 0
|
||||
#define UI_MAIN_MENU_INDEX_OPTIONS 1
|
||||
#define UI_MAIN_MENU_INDEX_QUIT 2
|
||||
|
||||
void uiMainMenuOpenSelectSave(void *userData);
|
||||
|
||||
// Loads every save slot before opening the load-game picker, same
|
||||
// checking/retry-on-error shape as the initial scene's device lookup
|
||||
// (see scene/initial/sceneinitial.c) - the error branch loops back via
|
||||
// CUTSCENE_RESTART.
|
||||
CUTSCENE(MAIN_MENU_START_GAME, 0, DEFAULT,
|
||||
CUTSCENE_MODAL(
|
||||
"main_menu.checking_save.title",
|
||||
"main_menu.checking_save.message"
|
||||
),
|
||||
CUTSCENE_WAIT(1.0f),
|
||||
CUTSCENE_SAVE_DEVICE_CHECK("CONTINUE", "NO_DEVICE"),
|
||||
|
||||
CUTSCENE_MARKER("NO_DEVICE"),
|
||||
CUTSCENE_MODAL_CLOSE(),
|
||||
CUTSCENE_MODAL_OPTIONS_TWO(
|
||||
"main_menu.no_device.title",
|
||||
"main_menu.no_device.message",
|
||||
"main_menu.no_device.retry", "RETRY",
|
||||
"main_menu.no_device.continue", "CONTINUE"
|
||||
),
|
||||
|
||||
CUTSCENE_MARKER("RETRY"),
|
||||
CUTSCENE_MODAL_CLOSE(),
|
||||
CUTSCENE_RESTART(),
|
||||
|
||||
CUTSCENE_MARKER("CONTINUE"),
|
||||
CUTSCENE_MODAL_CLOSE(),
|
||||
CUTSCENE_SAVE_LOAD_ALL_SLOTS("LOADED", "LOAD_ERROR"),
|
||||
|
||||
CUTSCENE_MARKER("LOAD_ERROR"),
|
||||
CUTSCENE_MODAL_OPTIONS_ONE(
|
||||
"main_menu.save_load_error.title",
|
||||
"main_menu.save_load_error.message",
|
||||
"main_menu.save_load_error.retry",
|
||||
"RETRY"
|
||||
),
|
||||
|
||||
CUTSCENE_MARKER("LOADED"),
|
||||
CUTSCENE_CALLBACK(uiMainMenuOpenSelectSave)
|
||||
);
|
||||
|
||||
uimainmenu_t UI_MAIN_MENU;
|
||||
|
||||
void uiMainMenuQuitConfirmed(const bool_t result, void *user) {
|
||||
@@ -40,6 +84,21 @@ void uiMainMenuSelectSaveResult(const uint8_t slotIndex, void *user) {
|
||||
sceneSet(SCENE_TYPE_OVERWORLD);
|
||||
}
|
||||
|
||||
void uiMainMenuOpenSelectSave(void *userData) {
|
||||
uiSelectSaveOpen(
|
||||
UI_SELECT_SAVE_TYPE_LOAD, uiMainMenuSelectSaveResult, NULL
|
||||
);
|
||||
}
|
||||
|
||||
void uiMainMenuClosed(const uimenu_t *menu) {
|
||||
if(UI_MAIN_MENU.suppressClosedSceneChange) {
|
||||
UI_MAIN_MENU.suppressClosedSceneChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
sceneSet(SCENE_TYPE_INITIAL);
|
||||
}
|
||||
|
||||
void uiMainMenuSelected(
|
||||
const uimenu_t *menu,
|
||||
const uint8_t index,
|
||||
@@ -48,13 +107,9 @@ void uiMainMenuSelected(
|
||||
|
||||
switch(index) {
|
||||
case UI_MAIN_MENU_INDEX_START_GAME:
|
||||
UI_MAIN_MENU.suppressClosedSceneChange = true;
|
||||
uiMenuClose(&UI_MAIN_MENU.menu);
|
||||
|
||||
errorCatch(errorPrint(saveLoadAllSlots()));
|
||||
|
||||
uiSelectSaveOpen(
|
||||
UI_SELECT_SAVE_TYPE_LOAD, uiMainMenuSelectSaveResult, NULL
|
||||
);
|
||||
cutsceneSystemStartCutscene(&CUTSCENE_MAIN_MENU_START_GAME);
|
||||
break;
|
||||
|
||||
case UI_MAIN_MENU_INDEX_OPTIONS:
|
||||
@@ -96,7 +151,8 @@ errorret_t uiMainMenuInit(void) {
|
||||
));
|
||||
|
||||
MENU_BEGIN(
|
||||
&UI_MAIN_MENU.menu, UI_MAIN_MENU.items, uiMainMenuSelected, NULL, NULL
|
||||
&UI_MAIN_MENU.menu, UI_MAIN_MENU.items, uiMainMenuSelected,
|
||||
uiMainMenuClosed, NULL
|
||||
);
|
||||
MENU_BUTTON(UI_MAIN_MENU.startGameLabel);
|
||||
MENU_BUTTON(UI_MAIN_MENU.optionsLabel);
|
||||
|
||||
@@ -20,6 +20,12 @@ typedef struct {
|
||||
char_t startGameLabel[UI_MAIN_MENU_LABEL_MAX];
|
||||
char_t optionsLabel[UI_MAIN_MENU_LABEL_MAX];
|
||||
char_t quitLabel[UI_MAIN_MENU_LABEL_MAX];
|
||||
|
||||
// Set right before a uiMenuClose() call that hands off to something
|
||||
// else (e.g. starting the start-game cutscene) rather than backing
|
||||
// all the way out, so the menu's closed handler knows to skip
|
||||
// returning to the initial scene for that one close.
|
||||
bool_t suppressClosedSceneChange;
|
||||
} uimainmenu_t;
|
||||
|
||||
extern uimainmenu_t UI_MAIN_MENU;
|
||||
|
||||
Reference in New Issue
Block a user