Modularize Mirrored World mode hook (#5930)

* Modularize Mirrored World mode hook

* Remove IS_RANDO from registration conditions

Co-authored-by: Philip Dubé <serprex@users.noreply.github.com>

---------

Co-authored-by: Philip Dubé <serprex@users.noreply.github.com>
This commit is contained in:
Jordan Longstaff
2025-11-09 20:27:45 -05:00
committed by GitHub
parent 5249cd89df
commit a3e540ebfe
2 changed files with 80 additions and 48 deletions

View File

@@ -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();
}

View File

@@ -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 <soh/Enhancements/item-tables/ItemTableManager.h>
#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<GameInteractor::OnSceneInit>(
[](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();