mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-20 13:24:40 -04:00
Allow Gamemodes to interrupt flow on file creation
This commit is contained in:
+68
-2
@@ -692,19 +692,85 @@ const GamemodeDesc gamemodeDesc = {
|
||||
.gamemodeId = MY_GAMEMODE_ID,
|
||||
.fullName = "Gamemode Name",
|
||||
// The save name should be something that other gamemodes will not try to use, so appending your name to it
|
||||
// is reccomended
|
||||
.saveName = "my-unique-save-name_developer-name",
|
||||
// is reccomended. Note: it is limited to 31 characters long
|
||||
.saveName = "my-unique-save_developer-name",
|
||||
.onActivatedFunction = onGamemodeActivated, // Called when the gamemode is selected on the prelaunch menu (or is launched)
|
||||
.onDeactivatedFunction = onGamemodeDeactivated, // Called when the gamemode is deselected on the prelaunch menu (or the mod is disabled)
|
||||
.onPlayFunction = nullptr, // Called when "Play" is pressed on the prelaunch menu
|
||||
.onSaveLoadedFunction = onSaveLoaded, // Called when a save is loaded
|
||||
.onNewSaveFunction = nullptr, // Called after a new savefile is created
|
||||
.onNewSaveSelectFunction = nullptr, // Called while the flow before the file name select is ran (see below)
|
||||
.onGameResetFunction = nullptr, // Called when the game is reset
|
||||
.onTickFunction = nullptr, // Called every game tick while the gamemode is active
|
||||
};
|
||||
svc_gamemode->register_gamemode(mod_ctx, &gamemodeDesc);
|
||||
```
|
||||
|
||||
Within the gamemode service, a gamemode can also request to load a UI for per-save file settings when the button to
|
||||
create a new file is pressed.
|
||||
|
||||
```cpp
|
||||
#include "d/d_file_select.h" // Requires game feature
|
||||
IMPORT_SERVICE(GamemodeService, svc_gamemode);
|
||||
IMPORT_SERVICE(UiService, svc_ui);
|
||||
|
||||
bool proceedUI = false;
|
||||
UiWindowHandle windowHandle;
|
||||
|
||||
bool onNewSaveSelect(dFile_select_c *fileSelect) {
|
||||
if (fileSelect->mGamemodeSaveStartBuildUi) {
|
||||
proceedUI = false;
|
||||
UiTabDesc tabs[1]{};
|
||||
|
||||
tabs[0].struct_size = sizeof(UiTabDesc);
|
||||
tabs[0].title = "Play";
|
||||
tabs[0].build = [](ModContext* ctx, UiWindowHandle, UiElementHandle leftPane, UiElementHandle rightPane, void*, ModError*) {
|
||||
UiControlDesc desc = UI_CONTROL_DESC_INIT;
|
||||
desc.kind = UI_CONTROL_BUTTON;
|
||||
desc.label = "Play";
|
||||
desc.help_rml = "Play Button";
|
||||
desc.on_pressed = [](ModContext* ctx, void* userdata) {
|
||||
proceedUI = true;
|
||||
svc_ui->window_close(ctx, *static_cast<UiWindowHandle*>(userdata));
|
||||
};
|
||||
desc.user_data = &windowHandle;
|
||||
svc_ui->pane_add_control(mod_ctx, leftPane, &desc, &windowHandle);
|
||||
return MOD_OK;
|
||||
};
|
||||
|
||||
UiWindowDesc desc = UI_WINDOW_DESC_INIT;
|
||||
desc.tabs = tabs;
|
||||
desc.tab_count = 1;
|
||||
desc.user_data = fileSelect;
|
||||
desc.on_closed = [](ModContext *, UiWindowHandle, void *userdata) {
|
||||
dFile_select_c *i_this = static_cast<dFile_select_c *>(userdata);
|
||||
|
||||
// if closing the window through backing out, return to file select
|
||||
if (!proceedUI) {
|
||||
i_this->backToDataSelectMove();
|
||||
}
|
||||
};
|
||||
|
||||
svc_ui->window_push(mod_ctx, &desc, &windowHandle);
|
||||
}
|
||||
|
||||
// When we hit play in the UI, return true (tells the file select that we can proceed)
|
||||
if (proceedUI) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const GamemodeDesc gamemodeDesc = {
|
||||
.gamemodeId = "my-gamemode-id",
|
||||
.fullName = "My Gamemode",
|
||||
.saveName = "my-gamemode-save",
|
||||
.onNewSaveSelectFunction = onNewSaveSelect,
|
||||
};
|
||||
svc_gamemode->register_gamemode(mod_ctx, &gamemodeDesc);
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hooking Game Functions
|
||||
|
||||
@@ -420,6 +420,14 @@ public:
|
||||
bool pointerMenuSelect();
|
||||
bool pointerCopyDataToSelect();
|
||||
bool pointerYesNoSelect(bool errorSelect);
|
||||
void backToDataSelectMove() {
|
||||
headerTxtSet(0x43, 1, 0);
|
||||
fileRecScaleAnmInitSet2(0.0f, 1.0f);
|
||||
nameMoveAnmInitSet(0xd29, 0xd1f);
|
||||
modoruTxtDispAnmInit(0);
|
||||
mDataSelProc = DATASELPROC_NAME_TO_DATA_SELECT_MOVE;
|
||||
mGamemodeSaveStartBuildUi = true;
|
||||
}
|
||||
#endif
|
||||
void _draw();
|
||||
void errorMoveAnmInitSet(int, int);
|
||||
@@ -733,6 +741,7 @@ public:
|
||||
#endif
|
||||
#ifdef TARGET_PC
|
||||
dDlst_FileSelFade_c mFadeDlst;
|
||||
bool mGamemodeSaveStartBuildUi = true;
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WII || PLATFORM_SHIELD
|
||||
|
||||
@@ -7,15 +7,18 @@
|
||||
#define GAMEMODE_SERVICE_MAJOR 1u
|
||||
#define GAMEMODE_SERVICE_MINOR 0u
|
||||
|
||||
struct dFile_select_c;
|
||||
|
||||
typedef struct {
|
||||
const char* gamemodeId;
|
||||
const char* fullName;
|
||||
const char* saveName;
|
||||
const char saveName[32]; // GCI Filenames are limited to 31 characters
|
||||
void (*onActivatedFunction)();
|
||||
void (*onDeactivatedFunction)();
|
||||
void (*onPlayFunction)();
|
||||
void (*onSaveLoadedFunction)();
|
||||
void (*onNewSaveFunction)();
|
||||
bool (*onNewSaveSelectFunction)(dFile_select_c* fileSelect); // Should return true when any custom options flows are finished
|
||||
void (*onGameResetFunction)();
|
||||
void (*onTickFunction)();
|
||||
} GamemodeDesc;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "dusk/menu_pointer.h"
|
||||
#include "helpers/string.hpp"
|
||||
#include "dusk/mods/svc/save.hpp"
|
||||
#include "dusk/gamemode.hpp"
|
||||
|
||||
namespace {
|
||||
constexpr u8 pointer_target(u8 group, u8 index) noexcept {
|
||||
@@ -1313,6 +1314,24 @@ void dFile_select_c::selectDataNameMove() {
|
||||
bool isNameMove = nameMoveAnm();
|
||||
bool isModoruTxtDisp = modoruTxtDispAnm();
|
||||
|
||||
#ifdef TARGET_PC
|
||||
const dusk::gamemode::Gamemode* gamemode = dusk::gamemode::getGamemodeManager().getCurrentGamemode();
|
||||
if (gamemode) {
|
||||
if (isHeaderTxtChange == true && isFileRecScale == true && isModoruTxtDisp == true) {
|
||||
bool gamemodeFlowClosed = gamemode->invokeOnNewSaveSelectFunction(this);
|
||||
if (mGamemodeSaveStartBuildUi == true) {
|
||||
mGamemodeSaveStartBuildUi = false;
|
||||
}
|
||||
if (!gamemodeFlowClosed) {
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
mGamemodeSaveStartBuildUi = true;
|
||||
#endif
|
||||
|
||||
if (isHeaderTxtChange == true && isFileRecScale == true && isNameMove == true &&
|
||||
isModoruTxtDisp == true)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include "d/d_file_select.h"
|
||||
|
||||
namespace dusk::gamemode {
|
||||
using GamemodeId = std::string;
|
||||
@@ -50,6 +51,13 @@ public:
|
||||
mOnNewSaveFunction();
|
||||
}
|
||||
}
|
||||
|
||||
bool invokeOnNewSaveSelectFunction(dFile_select_c* fileSelect) const {
|
||||
if (mOnNewSaveSelectFunction) {
|
||||
return mOnNewSaveSelectFunction(fileSelect);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void invokeOnGameResetFunction() const {
|
||||
if (mOnGameResetFunction) {
|
||||
@@ -68,6 +76,7 @@ public:
|
||||
std::function<void()> mOnPlayFunction;
|
||||
std::function<void()> mOnSaveLoadedFunction;
|
||||
std::function<void()> mOnNewSaveFunction;
|
||||
std::function<bool(dFile_select_c* fileSelect)> mOnNewSaveSelectFunction;
|
||||
std::function<void()> mOnGameResetFunction;
|
||||
std::function<void()> mOnTickFunction;
|
||||
};
|
||||
|
||||
@@ -65,16 +65,10 @@ ModResult register_gamemode(ModContext* ctx, const GamemodeDesc* desc) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string saveName;
|
||||
if (!desc->saveName) {
|
||||
Log.warn("Attempted to register gamemode {} with a null save name! Defaulting to: (gczelda2)",id);
|
||||
std::string saveName = desc->saveName;
|
||||
if (saveName.empty()) {
|
||||
Log.warn("Attempted to register gamemode {} with an empty save name! Defaulting to: (gczelda2)",id);
|
||||
saveName = "gczelda2";
|
||||
}else{
|
||||
saveName = desc->saveName;
|
||||
if (saveName.empty()) {
|
||||
Log.warn("Attempted to register gamemode {} with an empty save name! Defaulting to: (gczelda2)",id);
|
||||
saveName = "gczelda2";
|
||||
}
|
||||
}
|
||||
|
||||
dusk::gamemode::Gamemode gamemode(id, fullName, saveName);
|
||||
@@ -94,6 +88,9 @@ ModResult register_gamemode(ModContext* ctx, const GamemodeDesc* desc) {
|
||||
if (desc->onNewSaveFunction) {
|
||||
gamemode.mOnNewSaveFunction = desc->onNewSaveFunction;
|
||||
}
|
||||
if (desc->onNewSaveSelectFunction) {
|
||||
gamemode.mOnNewSaveSelectFunction = desc->onNewSaveSelectFunction;
|
||||
}
|
||||
if (desc->onGameResetFunction) {
|
||||
gamemode.mOnGameResetFunction = desc->onGameResetFunction;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user