Add support for warp points in the dev tools, as well as a boot to warp point option (#6037)
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
#include <libultraship/bridge.h>
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
#include "functions.h"
|
||||
|
||||
extern "C" {
|
||||
#include "z64.h"
|
||||
#include "overlays/gamestates/ovl_file_choose/file_choose.h"
|
||||
}
|
||||
|
||||
static constexpr int32_t CVAR_DEBUG_ENABLED_DEFAULT = 0;
|
||||
#define CVAR_DEBUG_ENABLED_NAME CVAR_DEVELOPER_TOOLS("DebugEnabled")
|
||||
#define CVAR_DEBUG_ENABLED_VALUE CVarGetInteger(CVAR_DEBUG_ENABLED_NAME, CVAR_DEBUG_ENABLED_DEFAULT)
|
||||
|
||||
static constexpr int32_t CVAR_BOOT_TO_DEBUG_WARP_SCREEN_DEFAULT = 0;
|
||||
#define CVAR_BOOT_TO_DEBUG_WARP_SCREEN_NAME CVAR_DEVELOPER_TOOLS("BootToDebugWarpScreen")
|
||||
#define CVAR_BOOT_TO_DEBUG_WARP_SCREEN_VALUE \
|
||||
CVarGetInteger(CVAR_BOOT_TO_DEBUG_WARP_SCREEN_NAME, CVAR_BOOT_TO_DEBUG_WARP_SCREEN_DEFAULT)
|
||||
|
||||
void OnFileChooseMainBootToDebugWarpScreen(void* gameState) {
|
||||
FileChooseContext* fileChooseContext = (FileChooseContext*)gameState;
|
||||
fileChooseContext->buttonIndex = 0xFF;
|
||||
fileChooseContext->menuMode = FS_MENU_MODE_SELECT;
|
||||
fileChooseContext->selectMode = SM_LOAD_GAME;
|
||||
}
|
||||
|
||||
void OnZTitleUpdateBootToDebugWarpScreen(void* gameState) {
|
||||
TitleContext* titleContext = (TitleContext*)gameState;
|
||||
|
||||
gSaveContext.seqId = (u8)NA_BGM_DISABLED;
|
||||
gSaveContext.natureAmbienceId = 0xFF;
|
||||
gSaveContext.gameMode = GAMEMODE_FILE_SELECT;
|
||||
titleContext->state.running = false;
|
||||
|
||||
SET_NEXT_GAMESTATE(&titleContext->state, FileChoose_Init, FileChooseContext);
|
||||
}
|
||||
|
||||
void RegisterBootToDebugWarpScreen() {
|
||||
COND_HOOK(OnFileChooseMain, CVAR_DEBUG_ENABLED_VALUE && CVAR_BOOT_TO_DEBUG_WARP_SCREEN_VALUE,
|
||||
OnFileChooseMainBootToDebugWarpScreen);
|
||||
COND_HOOK(OnZTitleUpdate, CVAR_DEBUG_ENABLED_VALUE && CVAR_BOOT_TO_DEBUG_WARP_SCREEN_VALUE,
|
||||
OnZTitleUpdateBootToDebugWarpScreen);
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc(RegisterBootToDebugWarpScreen,
|
||||
{ CVAR_DEBUG_ENABLED_NAME, CVAR_BOOT_TO_DEBUG_WARP_SCREEN_NAME });
|
||||
207
soh/soh/Enhancements/Warping.cpp
Normal file
207
soh/soh/Enhancements/Warping.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
#include <libultraship/bridge.h>
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
#include "functions.h"
|
||||
#include "soh/SohGui/MenuTypes.h"
|
||||
#include "soh/util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "z64.h"
|
||||
#include "overlays/gamestates/ovl_file_choose/file_choose.h"
|
||||
void Sram_InitDebugSave(void);
|
||||
void Select_LoadGame(SelectContext* selectContext, s32 entranceIndex);
|
||||
}
|
||||
|
||||
static constexpr int32_t CVAR_DEBUG_ENABLED_DEFAULT = 0;
|
||||
#define CVAR_DEBUG_ENABLED_NAME CVAR_DEVELOPER_TOOLS("DebugEnabled")
|
||||
#define CVAR_DEBUG_ENABLED_VALUE CVarGetInteger(CVAR_DEBUG_ENABLED_NAME, CVAR_DEBUG_ENABLED_DEFAULT)
|
||||
|
||||
static constexpr int32_t CVAR_BOOT_TO_DEBUG_WARP_SCREEN_DEFAULT = 0;
|
||||
#define CVAR_BOOT_TO_DEBUG_WARP_SCREEN_NAME CVAR_DEVELOPER_TOOLS("BootToDebugWarpScreen")
|
||||
#define CVAR_BOOT_TO_DEBUG_WARP_SCREEN_VALUE \
|
||||
CVarGetInteger(CVAR_BOOT_TO_DEBUG_WARP_SCREEN_NAME, CVAR_BOOT_TO_DEBUG_WARP_SCREEN_DEFAULT)
|
||||
|
||||
typedef struct WarpPoint {
|
||||
s32 entranceId;
|
||||
s8 roomNum;
|
||||
Vec3f pos;
|
||||
s16 rotY;
|
||||
bool bootToPoint;
|
||||
} WarpPoint;
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Vec3f, x, y, z)
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(WarpPoint, entranceId, roomNum, pos, rotY, bootToPoint)
|
||||
std::map<std::string, WarpPoint> warpPoints;
|
||||
|
||||
void LoadConfig() {
|
||||
auto allConfig = Ship::Context::GetInstance()->GetConfig()->GetNestedJson();
|
||||
if (allConfig.find("WarpPoints") == allConfig.end() || !allConfig["WarpPoints"].is_object()) {
|
||||
allConfig["WarpPoints"] = nlohmann::json::object();
|
||||
}
|
||||
warpPoints = allConfig["WarpPoints"];
|
||||
}
|
||||
|
||||
void SaveConfig() {
|
||||
auto allConfig = Ship::Context::GetInstance()->GetConfig()->GetNestedJson();
|
||||
allConfig["WarpPoints"] = warpPoints;
|
||||
Ship::Context::GetInstance()->GetConfig()->SetBlock("WarpPoints", warpPoints);
|
||||
Ship::Context::GetInstance()->GetConfig()->Save();
|
||||
}
|
||||
|
||||
void Warp(WarpPoint& warpPoint) {
|
||||
SPDLOG_INFO("PLAYSTATE IS NULL: {}", gPlayState == NULL);
|
||||
if (gPlayState == NULL) {
|
||||
// If gPlayState is NULL, it means the the user opted into BootToWarpPoint and the game is starting up.
|
||||
gSaveContext.gameMode = GAMEMODE_NORMAL;
|
||||
gSaveContext.fileNum = 0xFE; // temporary file so that this will respect debug save file option
|
||||
Sram_InitDebugSave();
|
||||
gSaveContext.fileNum = 0xFF;
|
||||
gSaveContext.sceneSetupIndex = 0;
|
||||
gSaveContext.cutsceneIndex = 0;
|
||||
|
||||
// Copied from Select_LoadGame
|
||||
for (int buttonIndex = 0; buttonIndex < ARRAY_COUNT(gSaveContext.buttonStatus); buttonIndex++) {
|
||||
gSaveContext.buttonStatus[buttonIndex] = BTN_ENABLED;
|
||||
}
|
||||
gSaveContext.forceRisingButtonAlphas = gSaveContext.unk_13E8 = gSaveContext.unk_13EA = gSaveContext.unk_13EC =
|
||||
0;
|
||||
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_STOP);
|
||||
gSaveContext.entranceIndex = warpPoint.entranceId;
|
||||
|
||||
gSaveContext.seqId = (u8)NA_BGM_DISABLED;
|
||||
gSaveContext.natureAmbienceId = 0xFF;
|
||||
gSaveContext.showTitleCard = true;
|
||||
gWeatherMode = 0;
|
||||
gGameState->running = false;
|
||||
SET_NEXT_GAMESTATE(gGameState, Play_Init, PlayState);
|
||||
|
||||
GameInteractor_ExecuteOnLoadGame(gSaveContext.fileNum);
|
||||
} else {
|
||||
gPlayState->nextEntranceIndex = warpPoint.entranceId;
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->transitionType = TRANS_TYPE_INSTANT;
|
||||
}
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].entranceIndex = warpPoint.entranceId;
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].roomIndex = warpPoint.roomNum;
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].pos = warpPoint.pos;
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].yaw = warpPoint.rotY;
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].playerParams = 0xDFF;
|
||||
gSaveContext.nextTransitionType = TRANS_TYPE_FADE_BLACK_FAST;
|
||||
gSaveContext.respawnFlag = 1;
|
||||
static HOOK_ID hookId = 0;
|
||||
hookId = REGISTER_VB_SHOULD(VB_INFLICT_VOID_DAMAGE, {
|
||||
*should = false;
|
||||
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::OnVanillaBehavior>(hookId);
|
||||
});
|
||||
}
|
||||
|
||||
static std::string warpNameInput = "";
|
||||
|
||||
void WarpPointsWidget(WidgetInfo& info) {
|
||||
ImGui::SeparatorText("Warp Points");
|
||||
if (gPlayState != NULL && GET_PLAYER(gPlayState) != NULL) {
|
||||
UIWidgets::InputString("##WarpPointNameInput", &warpNameInput,
|
||||
{
|
||||
.size = ImVec2(ImGui::GetContentRegionAvail().x - 50.0f, 0.0f),
|
||||
.placeholder = "Enter warp point name...",
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
bool isEmpty = warpNameInput.empty();
|
||||
if (isEmpty) {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
|
||||
if (UIWidgets::Button(ICON_FA_PLUS)) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
|
||||
std::string warpName = SohUtils::GetSceneName(gPlayState->sceneNum);
|
||||
if (gPlayState->roomCtx.curRoom.num != 0) {
|
||||
warpName += " (" + std::to_string(gPlayState->roomCtx.curRoom.num) + ")";
|
||||
}
|
||||
|
||||
warpPoints[warpNameInput] = WarpPoint{
|
||||
.entranceId = gSaveContext.entranceIndex,
|
||||
.roomNum = gPlayState->roomCtx.curRoom.num,
|
||||
.pos = player->actor.world.pos,
|
||||
.rotY = player->actor.shape.rot.y,
|
||||
};
|
||||
SaveConfig();
|
||||
warpNameInput = "";
|
||||
}
|
||||
if (isEmpty) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
}
|
||||
// List of warp points, showing just their name, a button to warp and a button to delete
|
||||
for (auto it = warpPoints.begin(); it != warpPoints.end();) {
|
||||
ImGui::PushID(it->first.c_str());
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("%s", it->first.c_str());
|
||||
if (it->second.bootToPoint) {
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(0.85f, 0.55f, 0.0f, 1.0f), "[Boot]");
|
||||
}
|
||||
ImGui::SameLine(ImGui::GetContentRegionAvail().x - 115.0f);
|
||||
if (gPlayState == NULL)
|
||||
ImGui::BeginDisabled();
|
||||
if (UIWidgets::Button(ICON_FA_PLANE, { .size = UIWidgets::Sizes::Inline })) {
|
||||
// Warp to this point
|
||||
Warp(it->second);
|
||||
}
|
||||
if (gPlayState == NULL)
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
if (UIWidgets::Button(ICON_FA_REFRESH,
|
||||
{ .size = UIWidgets::Sizes::Inline, .color = UIWidgets::Colors::Orange })) {
|
||||
for (auto& wp : warpPoints) {
|
||||
wp.second.bootToPoint = false;
|
||||
}
|
||||
it->second.bootToPoint = true;
|
||||
SaveConfig();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (UIWidgets::Button(ICON_FA_TRASH, { .size = UIWidgets::Sizes::Inline, .color = UIWidgets::Colors::Red })) {
|
||||
it = warpPoints.erase(it);
|
||||
SaveConfig();
|
||||
ImGui::PopID();
|
||||
continue;
|
||||
;
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterWarping() {
|
||||
static bool loadedConfig = false;
|
||||
if (!loadedConfig) {
|
||||
LoadConfig();
|
||||
loadedConfig = true;
|
||||
}
|
||||
|
||||
COND_HOOK(OnZTitleUpdate, CVAR_DEBUG_ENABLED_VALUE && CVAR_BOOT_TO_DEBUG_WARP_SCREEN_VALUE == 1,
|
||||
[](void* gameState) {
|
||||
TitleContext* titleContext = (TitleContext*)gameState;
|
||||
|
||||
gSaveContext.seqId = (u8)NA_BGM_DISABLED;
|
||||
gSaveContext.natureAmbienceId = 0xFF;
|
||||
gSaveContext.gameMode = GAMEMODE_NORMAL;
|
||||
titleContext->state.running = false;
|
||||
SET_NEXT_GAMESTATE(&titleContext->state, Select_Init, SelectContext);
|
||||
});
|
||||
|
||||
COND_HOOK(OnZTitleUpdate, CVAR_DEBUG_ENABLED_VALUE && CVAR_BOOT_TO_DEBUG_WARP_SCREEN_VALUE == 2,
|
||||
[](void* gameState) {
|
||||
for (auto& wp : warpPoints) {
|
||||
if (wp.second.bootToPoint) {
|
||||
Warp(wp.second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc(RegisterWarping, { CVAR_DEBUG_ENABLED_NAME, CVAR_BOOT_TO_DEBUG_WARP_SCREEN_NAME });
|
||||
@@ -213,10 +213,15 @@ void OnZTitleUpdateSkipToFileSelect(void* gameState) {
|
||||
}
|
||||
|
||||
void RegisterCustomLogoTitleBootsequence() {
|
||||
COND_HOOK(OnZTitleUpdate, CVAR_BOOTSEQUENCE_VALUE == BOOTSEQUENCE_FILESELECT, OnZTitleUpdateSkipToFileSelect);
|
||||
COND_HOOK(OnZTitleUpdate,
|
||||
CVAR_BOOTSEQUENCE_VALUE == BOOTSEQUENCE_FILESELECT &&
|
||||
CVarGetInteger(CVAR_DEVELOPER_TOOLS("BootToDebugWarpScreen"), 0) == 0,
|
||||
OnZTitleUpdateSkipToFileSelect);
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc registerTitleBootSequence(RegisterCustomLogoTitleBootsequence, { CVAR_BOOTSEQUENCE_NAME });
|
||||
static RegisterShipInitFunc registerTitleBootSequence(RegisterCustomLogoTitleBootsequence,
|
||||
{ CVAR_BOOTSEQUENCE_NAME,
|
||||
CVAR_DEVELOPER_TOOLS("BootToDebugWarpScreen") });
|
||||
|
||||
// // // // // //
|
||||
// Let it Snow
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#include "SohMenu.h"
|
||||
#include "SohGui.hpp"
|
||||
|
||||
void WarpPointsWidget(WidgetInfo& info);
|
||||
|
||||
namespace SohGui {
|
||||
|
||||
@@ -10,6 +13,11 @@ static const std::unordered_map<int32_t, const char*> logLevels = {
|
||||
{ DEBUG_LOG_WARN, "Warn" }, { DEBUG_LOG_ERROR, "Error" }, { DEBUG_LOG_CRITICAL, "Critical" },
|
||||
{ DEBUG_LOG_OFF, "Off" },
|
||||
};
|
||||
static std::unordered_map<int32_t, const char*> bootToOptions = {
|
||||
{ 0, "Disabled" },
|
||||
{ 1, "Debug Warp Screen" },
|
||||
{ 2, "Warp Point" },
|
||||
};
|
||||
|
||||
#ifdef _DEBUG
|
||||
DebugLogOption defaultLogLevel = DEBUG_LOG_TRACE;
|
||||
@@ -39,12 +47,6 @@ void SohMenu::AddMenuDevTools() {
|
||||
.Options(
|
||||
CheckboxOptions().Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip "
|
||||
"with L + D-pad Right, and open the debug menu with L on the pause screen."));
|
||||
AddWidget(path, "Boot To Debug Warp Screen", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_DEVELOPER_TOOLS("BootToDebugWarpScreen"))
|
||||
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); })
|
||||
.Options(
|
||||
CheckboxOptions().Tooltip("Automatically shows Debug Warp Screen when starting or resetting the game.\n"
|
||||
"This option takes precedence over \"Boot Sequence\" option."));
|
||||
AddWidget(path, "OoT Registry Editor", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_DEVELOPER_TOOLS("RegEditEnabled"))
|
||||
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); })
|
||||
@@ -61,19 +63,10 @@ void SohMenu::AddMenuDevTools() {
|
||||
.ComboMap(debugSaveFileModes));
|
||||
AddWidget(path, "OoT Skulltula Debug", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_DEVELOPER_TOOLS("SkulltulaDebugEnabled"))
|
||||
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); })
|
||||
.Options(CheckboxOptions().Tooltip("Enables Skulltula Debug, when moving the cursor in the menu above various "
|
||||
"map icons (boss key, compass, map screen locations, etc.) will set the GS "
|
||||
"bits in that area.\nUSE WITH CAUTION AS IT DOES NOT UPDATE THE GS COUNT!"));
|
||||
AddWidget(path, "Better Debug Warp Screen", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_DEVELOPER_TOOLS("BetterDebugWarpScreen"))
|
||||
.Options(CheckboxOptions()
|
||||
.Tooltip("Optimized Debug Warp Screen, with the added ability to chose entrances and time of day.")
|
||||
.DefaultValue(true));
|
||||
AddWidget(path, "Debug Warp Screen Translation", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_DEVELOPER_TOOLS("DebugWarpScreenTranslation"))
|
||||
.Options(CheckboxOptions()
|
||||
.Tooltip("Translate the Debug Warp Screen based on the game language.")
|
||||
.DefaultValue(true));
|
||||
AddWidget(path, "Resource logging", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_DEVELOPER_TOOLS("ResourceLogging"))
|
||||
.Options(CheckboxOptions().Tooltip("Logs some resources as XML when they're loaded in binary format."));
|
||||
@@ -124,6 +117,36 @@ void SohMenu::AddMenuDevTools() {
|
||||
})
|
||||
.PreFunc([](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active; });
|
||||
|
||||
path.column = SECTION_COLUMN_2;
|
||||
AddWidget(path, "Warping", WIDGET_SEPARATOR_TEXT).PreFunc([](WidgetInfo& info) {
|
||||
info.isHidden = !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0);
|
||||
});
|
||||
AddWidget(path, "Better Debug Warp Screen", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_DEVELOPER_TOOLS("BetterDebugWarpScreen"))
|
||||
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); })
|
||||
.Options(CheckboxOptions()
|
||||
.Tooltip("Optimized Debug Warp Screen, with the added ability to chose entrances and time of day.")
|
||||
.DefaultValue(true));
|
||||
AddWidget(path, "Debug Warp Screen Translation", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_DEVELOPER_TOOLS("DebugWarpScreenTranslation"))
|
||||
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); })
|
||||
.Options(CheckboxOptions()
|
||||
.Tooltip("Translate the Debug Warp Screen based on the game language.")
|
||||
.DefaultValue(true));
|
||||
AddWidget(path, "Boot To:", WIDGET_CVAR_COMBOBOX)
|
||||
.CVar(CVAR_DEVELOPER_TOOLS("BootToDebugWarpScreen"))
|
||||
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); })
|
||||
.Options(ComboboxOptions()
|
||||
.DefaultIndex(0)
|
||||
.ComponentAlignment(ComponentAlignments::Right)
|
||||
.LabelPosition(LabelPositions::Far)
|
||||
.Color(THEME_COLOR)
|
||||
.ComboMap(bootToOptions)
|
||||
.Tooltip("Automatically boots to Debug Warp Screen or custom Warp Point when starting or "
|
||||
"resetting the game.\n"
|
||||
"This option takes precedence over \"Boot Sequence\" option."));
|
||||
AddWidget(path, "Warp Points", WIDGET_CUSTOM).CustomFunction(WarpPointsWidget).HideInSearch(true);
|
||||
|
||||
// Stats
|
||||
path.sidebarName = "Stats";
|
||||
AddSidebarEntry("Dev Tools", path.sidebarName, 1);
|
||||
|
||||
Reference in New Issue
Block a user