diff --git a/soh/soh/Enhancements/ExtraModes/MirroredWorld.cpp b/soh/soh/Enhancements/ExtraModes/MirroredWorld.cpp new file mode 100644 index 000000000..2f4f9e4d0 --- /dev/null +++ b/soh/soh/Enhancements/ExtraModes/MirroredWorld.cpp @@ -0,0 +1,80 @@ +#include "soh/Enhancements/cosmetics/authenticGfxPatches.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/Enhancements/randomizer/3drando/random.hpp" +#include "soh/Enhancements/randomizer/context.h" +#include "soh/Enhancements/enhancementTypes.h" +#include "soh/Enhancements/mods.h" +#include "soh/ResourceManagerHelpers.h" +#include "soh/ShipInit.hpp" + +extern "C" { +#include "variables.h" +extern SaveContext gSaveContext; +} + +static constexpr MirroredWorldMode CVAR_MIRRORED_WORLD_DEFAULT = MIRRORED_WORLD_OFF; +#define CVAR_MIRRORED_WORLD_NAME CVAR_ENHANCEMENT("MirroredWorld") +#define CVAR_MIRRORED_WORLD_MODE_NAME CVAR_ENHANCEMENT("MirroredWorldMode") +#define CVAR_MIRRORED_WORLD_MODE_VALUE CVarGetInteger(CVAR_MIRRORED_WORLD_MODE_NAME, CVAR_MIRRORED_WORLD_DEFAULT) + +static bool prevMirroredWorld = false; + +static bool MirroredWorld_IsInDungeon(int32_t sceneNum) { + return (sceneNum >= SCENE_DEKU_TREE && sceneNum <= SCENE_INSIDE_GANONS_CASTLE_COLLAPSE && + sceneNum != SCENE_THIEVES_HIDEOUT) || + (sceneNum >= SCENE_DEKU_TREE_BOSS && sceneNum <= SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR) || + (sceneNum == SCENE_GANON_BOSS); +} + +static void MirroredWorld_InitRandomSeed(int32_t sceneNum) { + uint32_t seed = + sceneNum + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt); + Random_Init(seed); +} + +static bool MirroredWorld_ShouldApply(int32_t sceneNum) { + switch (CVAR_MIRRORED_WORLD_MODE_VALUE) { + case MIRRORED_WORLD_ALWAYS: + return true; + case MIRRORED_WORLD_RANDOM_SEEDED: + MirroredWorld_InitRandomSeed(sceneNum); + case MIRRORED_WORLD_RANDOM: + return Random(0, 2) == 1; + case MIRRORED_WORLD_DUNGEONS_ALL: + return MirroredWorld_IsInDungeon(sceneNum); + case MIRRORED_WORLD_DUNGEONS_VANILLA: + return MirroredWorld_IsInDungeon(sceneNum) && !ResourceMgr_IsSceneMasterQuest(sceneNum); + case MIRRORED_WORLD_DUNGEONS_MQ: + return MirroredWorld_IsInDungeon(sceneNum) && ResourceMgr_IsSceneMasterQuest(sceneNum); + case MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED: + MirroredWorld_InitRandomSeed(sceneNum); + case MIRRORED_WORLD_DUNGEONS_RANDOM: + return MirroredWorld_IsInDungeon(sceneNum) && (Random(0, 2) == 1); + default: + return false; + } +} + +static void RegisterMirroredWorld() { + COND_HOOK(OnSceneInit, CVAR_MIRRORED_WORLD_MODE_VALUE, UpdateMirrorModeState); +} + +static RegisterShipInitFunc initFunc(RegisterMirroredWorld, { CVAR_MIRRORED_WORLD_MODE_NAME }); + +void UpdateMirrorModeState(int32_t sceneNum) { + bool nextMirroredWorld = MirroredWorld_ShouldApply(sceneNum); + + if (prevMirroredWorld == nextMirroredWorld) { + return; + } + prevMirroredWorld = nextMirroredWorld; + + if (nextMirroredWorld) { + CVarSetInteger(CVAR_MIRRORED_WORLD_NAME, 1); + } else { + CVarClear(CVAR_MIRRORED_WORLD_NAME); + RegisterMirroredWorld(); + } + + ApplyMirrorWorldGfxPatches(); +} diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 09783aadd..6c38d5de7 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -8,8 +8,6 @@ #include "soh/resource/type/Skeleton.h" #include "soh/Enhancements/boss-rush/BossRush.h" #include "soh/Enhancements/enhancementTypes.h" -#include "soh/Enhancements/randomizer/3drando/random.hpp" -#include "soh/Enhancements/cosmetics/authenticGfxPatches.h" #include #include "soh/Enhancements/timesaver_hook_handlers.h" #include "soh/Enhancements/randomizer/hook_handlers.h" @@ -286,51 +284,6 @@ void UpdateHyperEnemiesState() { } } -void UpdateMirrorModeState(int32_t sceneNum) { - static bool prevMirroredWorld = false; - bool nextMirroredWorld = false; - - int16_t mirroredMode = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorldMode"), MIRRORED_WORLD_OFF); - int16_t inDungeon = (sceneNum >= SCENE_DEKU_TREE && sceneNum <= SCENE_INSIDE_GANONS_CASTLE_COLLAPSE && - sceneNum != SCENE_THIEVES_HIDEOUT) || - (sceneNum >= SCENE_DEKU_TREE_BOSS && sceneNum <= SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR) || - (sceneNum == SCENE_GANON_BOSS); - - if (mirroredMode == MIRRORED_WORLD_RANDOM_SEEDED || mirroredMode == MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED) { - uint32_t seed = - sceneNum + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt); - Random_Init(seed); - } - - bool randomMirror = Random(0, 2) == 1; - - if (mirroredMode == MIRRORED_WORLD_ALWAYS || - ((mirroredMode == MIRRORED_WORLD_RANDOM || mirroredMode == MIRRORED_WORLD_RANDOM_SEEDED) && randomMirror) || - // Dungeon modes - (inDungeon && - (mirroredMode == MIRRORED_WORLD_DUNGEONS_ALL || - (mirroredMode == MIRRORED_WORLD_DUNGEONS_VANILLA && !ResourceMgr_IsSceneMasterQuest(sceneNum)) || - (mirroredMode == MIRRORED_WORLD_DUNGEONS_MQ && ResourceMgr_IsSceneMasterQuest(sceneNum)) || - ((mirroredMode == MIRRORED_WORLD_DUNGEONS_RANDOM || mirroredMode == MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED) && - randomMirror)))) { - nextMirroredWorld = true; - CVarSetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 1); - } else { - nextMirroredWorld = false; - CVarClear(CVAR_ENHANCEMENT("MirroredWorld")); - } - - if (prevMirroredWorld != nextMirroredWorld) { - prevMirroredWorld = nextMirroredWorld; - ApplyMirrorWorldGfxPatches(); - } -} - -void RegisterMirrorModeHandler() { - GameInteractor::Instance->RegisterGameHook( - [](int32_t sceneNum) { UpdateMirrorModeState(sceneNum); }); -} - void UpdatePatchHand() { if ((CVarGetInteger(CVAR_ENHANCEMENT("EquipmentAlwaysVisible"), 0)) && LINK_IS_CHILD) { ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1", 92, @@ -736,7 +689,6 @@ void InitMods() { RegisterDeleteFileOnDeath(); RegisterHyperBosses(); UpdateHyperEnemiesState(); - RegisterMirrorModeHandler(); RegisterEnemyDefeatCounts(); RegisterBossDefeatTimestamps(); RegisterRandomizedEnemySizes();