Enhancement: Better Farore's Wind (#2374)

* Updated SaveManager, SaveContext;
lifted restriction from gtg and ganon's castle;
disabled clearing fw during master sword lift;
added checkbox

* increment load version (whoops); clear age fw after use

* beef up fw console handler (for testing)

* Simplify better FW (2 copies > 1 copy)

* Apply suggestions

* whoops
This commit is contained in:
Ralphie Morell 2023-01-25 14:32:21 -05:00 committed by GitHub
parent 21ae445548
commit 6d6c1c8c32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 94 additions and 11 deletions

View File

@ -253,6 +253,7 @@ typedef struct {
/* */ u8 pendingIceTrapCount;
/* */ SohStats sohStats;
/* */ u8 temporaryWeapon;
/* */ FaroresWindData backupFW;
// #endregion
// #region SOH [Randomizer]
// Upstream TODO: Move these to their own struct or name to more obviously specific to Randomizer

View File

@ -389,14 +389,52 @@ static bool ReloadHandler(std::shared_ptr<Ship::Console> Console, const std::vec
return CMD_SUCCESS;
}
const static std::map<std::string, uint16_t> fw_options {
{ "clear", 0}, {"warp", 1}, {"nackup", 2}
};
static bool FWHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() != 2) {
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
const auto& it = fw_options.find(args[1]);
if (it == fw_options.end()) {
SohImGui::GetConsole()->SendErrorMessage("[SOH] Invalid option. Options are 'clear', 'warp', 'backup'");
return CMD_FAILED;
}
if (gPlayState != nullptr) {
if (gSaveContext.respawn[RESPAWN_MODE_TOP].data > 0) {
gPlayState->sceneLoadFlag = 0x14;
gPlayState->nextEntranceIndex = gSaveContext.respawn[RESPAWN_MODE_TOP].entranceIndex;
gPlayState->fadeTransition = 5;
} else {
SohImGui::GetConsole()->SendErrorMessage("Farore's wind not set!");
FaroresWindData clear = {};
switch(it->second) {
case 0: //clear
gSaveContext.fw = clear;
SohImGui::GetConsole()->SendInfoMessage("[SOH] Farore's wind point cleared! Reload scene to take effect.");
return CMD_SUCCESS;
break;
case 1: //warp
if (gSaveContext.respawn[RESPAWN_MODE_TOP].data > 0) {
gPlayState->sceneLoadFlag = 0x14;
gPlayState->nextEntranceIndex = gSaveContext.respawn[RESPAWN_MODE_TOP].entranceIndex;
gPlayState->fadeTransition = 5;
} else {
SohImGui::GetConsole()->SendErrorMessage("Farore's wind not set!");
return CMD_FAILED;
}
return CMD_SUCCESS;
break;
case 2: //backup
if (CVarGetInteger("gBetterFW", 0)) {
gSaveContext.fw = gSaveContext.backupFW;
gSaveContext.fw.set = 1;
SohImGui::GetConsole()->SendInfoMessage("[SOH] Backup FW data copied! Reload scene to take effect.");
return CMD_SUCCESS;
} else {
SohImGui::GetConsole()->SendErrorMessage("Better Farore's Wind isn't turned on!");
return CMD_FAILED;
}
break;
}
}
else {
@ -1046,7 +1084,9 @@ void DebugConsole_Init(void) {
// Map & Location
CMD_REGISTER("void", { VoidHandler, "Voids out of the current map." });
CMD_REGISTER("reload", { ReloadHandler, "Reloads the current map." });
CMD_REGISTER("fw", { FWHandler,"Spawns the player where Farore's Wind is set." });
CMD_REGISTER("fw", { FWHandler,"Spawns the player where Farore's Wind is set." , {
{ "clear|warp|backup", Ship::ArgumentType::TEXT }
}});
CMD_REGISTER("entrance", { EntranceHandler, "Sends player to the entered entrance (hex)", {
{ "entrance", Ship::ArgumentType::NUMBER }
}});

View File

@ -400,6 +400,8 @@ namespace GameMenuBar {
UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers.");
UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false);
UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots");
UIWidgets::PaddedEnhancementCheckbox("Better Farore's Wind", "gBetterFW", true, false);
UIWidgets::Tooltip("Helps FW persist between ages, gives child and adult separate FW points, and can be used in more places.");
UIWidgets::PaddedEnhancementCheckbox("Static Explosion Radius", "gStaticExplosionRadius", true, false);
UIWidgets::Tooltip("Explosions are now a static size, like in Majora's Mask and OoT3D. Makes bombchu hovering much easier.");
ImGui::EndMenu();

View File

@ -502,6 +502,7 @@ void SaveManager::InitFileNormal() {
gSaveContext.fw.set = 0;
gSaveContext.fw.tempSwchFlags = 0;
gSaveContext.fw.tempCollectFlags = 0;
gSaveContext.backupFW = gSaveContext.fw;
for (int flag = 0; flag < ARRAY_COUNT(gSaveContext.gsFlags); flag++) {
gSaveContext.gsFlags[flag] = 0;
}
@ -1334,6 +1335,20 @@ void SaveManager::LoadBaseVersion3() {
SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]);
});
SaveManager::Instance->LoadData("isMasterQuest", gSaveContext.isMasterQuest);
SaveManager::Instance->LoadStruct("backupFW", []() {
SaveManager::Instance->LoadStruct("pos", []() {
SaveManager::Instance->LoadData("x", gSaveContext.backupFW.pos.x);
SaveManager::Instance->LoadData("y", gSaveContext.backupFW.pos.y);
SaveManager::Instance->LoadData("z", gSaveContext.backupFW.pos.z);
});
SaveManager::Instance->LoadData("yaw", gSaveContext.backupFW.yaw);
SaveManager::Instance->LoadData("playerParams", gSaveContext.backupFW.playerParams);
SaveManager::Instance->LoadData("entranceIndex", gSaveContext.backupFW.entranceIndex);
SaveManager::Instance->LoadData("roomIndex", gSaveContext.backupFW.roomIndex);
SaveManager::Instance->LoadData("set", gSaveContext.backupFW.set);
SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.backupFW.tempSwchFlags);
SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags);
});
SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams);
}
@ -1510,6 +1525,20 @@ void SaveManager::SaveBase() {
SaveManager::Instance->SaveData("", gSaveContext.randomizerInf[i]);
});
SaveManager::Instance->SaveData("isMasterQuest", gSaveContext.isMasterQuest);
SaveManager::Instance->SaveStruct("backupFW", []() {
SaveManager::Instance->SaveStruct("pos", []() {
SaveManager::Instance->SaveData("x", gSaveContext.backupFW.pos.x);
SaveManager::Instance->SaveData("y", gSaveContext.backupFW.pos.y);
SaveManager::Instance->SaveData("z", gSaveContext.backupFW.pos.z);
});
SaveManager::Instance->SaveData("yaw", gSaveContext.backupFW.yaw);
SaveManager::Instance->SaveData("playerParams", gSaveContext.backupFW.playerParams);
SaveManager::Instance->SaveData("entranceIndex", gSaveContext.backupFW.entranceIndex);
SaveManager::Instance->SaveData("roomIndex", gSaveContext.backupFW.roomIndex);
SaveManager::Instance->SaveData("set", gSaveContext.backupFW.set);
SaveManager::Instance->SaveData("tempSwchFlags", gSaveContext.backupFW.tempSwchFlags);
SaveManager::Instance->SaveData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags);
});
SaveManager::Instance->SaveData("dogParams", gSaveContext.dogParams);
}

View File

@ -616,8 +616,14 @@ void Cutscene_Command_Terminator(PlayState* play, CutsceneContext* csCtx, CsCmdB
play->fadeTransition = 11;
break;
case 8:
gSaveContext.fw.set = 0;
gSaveContext.respawn[RESPAWN_MODE_TOP].data = 0;
if (CVarGetInteger("gBetterFW", 0)) {
FaroresWindData tempFW = gSaveContext.backupFW;
gSaveContext.backupFW = gSaveContext.fw;
gSaveContext.fw = tempFW;
} else {
gSaveContext.fw.set = 0;
gSaveContext.respawn[RESPAWN_MODE_TOP].data = 0;
}
if (!(gSaveContext.eventChkInf[4] & 0x20)) {
gSaveContext.eventChkInf[4] |= 0x20;
play->nextEntranceIndex = 0x00A0;

View File

@ -1371,6 +1371,11 @@ void Interface_SetSceneRestrictions(PlayState* play) {
interfaceCtx->restrictions.farores, interfaceCtx->restrictions.dinsNayrus,
interfaceCtx->restrictions.all);
osSyncPrintf(VT_RST);
if (CVarGetInteger("gBetterFW", 0)) {
if (currentScene == SCENE_MEN || currentScene == SCENE_GANONTIKA) {
interfaceCtx->restrictions.farores = 0;
}
}
return;
}
i++;

View File

@ -13716,7 +13716,7 @@ void func_8085063C(Player* this, PlayState* play) {
if (Message_GetState(&play->msgCtx) == TEXT_STATE_CLOSING) {
s32 respawnData = gSaveContext.respawn[RESPAWN_MODE_TOP].data;
if (play->msgCtx.choiceIndex == 0) {
if (play->msgCtx.choiceIndex == 0) { //Returns to FW
gSaveContext.respawnFlag = 3;
play->sceneLoadFlag = 0x14;
play->nextEntranceIndex = gSaveContext.respawn[RESPAWN_MODE_TOP].entranceIndex;
@ -13725,7 +13725,7 @@ void func_8085063C(Player* this, PlayState* play) {
return;
}
if (play->msgCtx.choiceIndex == 1) {
if (play->msgCtx.choiceIndex == 1) { //Unsets FW
gSaveContext.respawn[RESPAWN_MODE_TOP].data = -respawnData;
gSaveContext.fw.set = 0;
func_80078914(&gSaveContext.respawn[RESPAWN_MODE_TOP].pos, NA_SE_PL_MAGIC_WIND_VANISH);