From 9baa114f6bedc6d66393f0ae2363ab3b5e6409a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= <159546+serprex@users.noreply.github.com> Date: Tue, 18 Aug 2026 14:36:30 +0000 Subject: [PATCH] Hookify fish, refactor fishsanity (#7091) --- soh/include/macros.h | 6 +- .../ExtraModes/EnemyRandomizer.cpp | 1 + soh/soh/Enhancements/Fishing.cpp | 48 +- .../Items/BetterBombchuShopping.cpp | 7 +- .../Enhancements/Items/InjectItemCounts.cpp | 8 +- .../Enhancements/QoL/NoSkulltulaFreeze.cpp | 2 +- .../TimeSavers/QuitFishingAtDoor.cpp | 14 +- .../vanilla-behavior/GIVanillaBehavior.h | 99 ++- .../randomizer/3drando/playthrough.cpp | 5 +- soh/soh/Enhancements/randomizer/BigPoes.cpp | 2 +- soh/soh/Enhancements/randomizer/Bombchus.cpp | 8 +- .../randomizer/ColoredMapsAndCompasses.cpp | 2 +- .../randomizer/MedallionLockedTrials.cpp | 2 +- .../randomizer/Messages/EntranceHints.cpp | 6 +- .../randomizer/Messages/Goron.cpp | 2 +- .../randomizer/Messages/MerchantMessages.cpp | 1 + .../randomizer/Messages/Miscellaneous.cpp | 2 +- .../Enhancements/randomizer/Messages/Navi.cpp | 2 +- .../randomizer/Messages/Rupees.cpp | 2 +- .../Enhancements/randomizer/SeedContext.cpp | 7 +- soh/soh/Enhancements/randomizer/SeedContext.h | 3 - .../randomizer/ShuffleBeehives.cpp | 1 + .../Enhancements/randomizer/ShuffleBeggar.cpp | 1 + .../Enhancements/randomizer/ShuffleCows.cpp | 1 + .../Enhancements/randomizer/ShuffleCrates.cpp | 1 + .../randomizer/ShuffleFairies.cpp | 1 + .../randomizer/ShuffleFreestanding.cpp | 1 + .../Enhancements/randomizer/ShuffleGrass.cpp | 1 + .../randomizer/ShuffleIcicles.cpp | 1 + .../Enhancements/randomizer/ShufflePots.cpp | 1 + .../Enhancements/randomizer/ShuffleRedIce.cpp | 1 + .../Enhancements/randomizer/ShuffleRocks.cpp | 1 + .../Enhancements/randomizer/ShuffleSigns.cpp | 1 + .../Enhancements/randomizer/ShuffleSilver.cpp | 1 + .../Enhancements/randomizer/ShuffleSpeak.cpp | 6 +- .../randomizer/ShuffleTreasureChestGame.cpp | 2 +- .../Enhancements/randomizer/ShuffleTrees.cpp | 1 + .../randomizer/ShuffleWonderItems.cpp | 1 + soh/soh/Enhancements/randomizer/Traps.cpp | 1 + soh/soh/Enhancements/randomizer/entrance.cpp | 1 + .../Enhancements/randomizer/fishsanity.cpp | 677 ++++++++---------- soh/soh/Enhancements/randomizer/fishsanity.h | 209 +----- .../Enhancements/randomizer/hook_handlers.cpp | 3 +- .../Enhancements/randomizer/item_location.cpp | 1 + .../randomizer/randomizer_check_objects.cpp | 3 +- .../randomizer/randomizer_check_tracker.cpp | 4 +- soh/soh/ResourceManagerHelpers.cpp | 1 + soh/soh/SohGui/SohMenuRandomizer.cpp | 8 +- .../overlays/actors/ovl_Fishing/z_fishing.c | 93 +-- .../overlays/actors/ovl_Fishing/z_fishing.h | 1 - 50 files changed, 550 insertions(+), 704 deletions(-) diff --git a/soh/include/macros.h b/soh/include/macros.h index eb377ffa0e..de4de10e8c 100644 --- a/soh/include/macros.h +++ b/soh/include/macros.h @@ -322,9 +322,9 @@ extern GraphicsContext* __gfxCtx; #ifdef __cplusplus #define DUNGEON_ITEMS_CAN_BE_OUTSIDE_DUNGEON(rsk) \ - (OTRGlobals::Instance->gRandoContext->GetOption(rsk).IsNot(RO_DUNGEON_ITEM_LOC_STARTWITH) && \ - OTRGlobals::Instance->gRandoContext->GetOption(rsk).IsNot(RO_DUNGEON_ITEM_LOC_VANILLA) && \ - OTRGlobals::Instance->gRandoContext->GetOption(rsk).IsNot(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON)) + (RAND_GET_OPTION(rsk).IsNot(RO_DUNGEON_ITEM_LOC_STARTWITH) && \ + RAND_GET_OPTION(rsk).IsNot(RO_DUNGEON_ITEM_LOC_VANILLA) && \ + RAND_GET_OPTION(rsk).IsNot(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON)) #endif // #endregion diff --git a/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp b/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp index a90f8f1857..f4a3dd5a34 100644 --- a/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp +++ b/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp @@ -3,6 +3,7 @@ #include "soh/ShipUtils.h" #include "soh/Enhancements/randomizer/SeedContext.h" #include "soh/Enhancements/enhancementTypes.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/ObjectExtension/ObjectExtension.h" #include "variables.h" #include "soh/ResourceManagerHelpers.h" diff --git a/soh/soh/Enhancements/Fishing.cpp b/soh/soh/Enhancements/Fishing.cpp index d35ca1131e..4b1a6eb3b3 100644 --- a/soh/soh/Enhancements/Fishing.cpp +++ b/soh/soh/Enhancements/Fishing.cpp @@ -1,3 +1,5 @@ +#include + #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/ShipInit.hpp" #include "src/overlays/actors/ovl_Fishing/z_fishing.h" @@ -8,7 +10,14 @@ extern "C" { #include extern PlayState* gPlayState; extern SaveContext gSaveContext; -f32 Fishing_GetMinimumRequiredScore(); +} + +// RANDOTODO: update the enhancement sliders to not allow +// values above rando fish weight values when rando'd +static float Fishing_GetMinimumRequiredScore() { + int weight = LINK_IS_CHILD ? CVarGetInteger(CVAR_ENHANCEMENT("MinimumFishWeightChild"), 10) + : CVarGetInteger(CVAR_ENHANCEMENT("MinimumFishWeightAdult"), 13); + return sqrtf((weight - 0.5f) / 0.0036f); } void BuildFishingMessage(uint16_t* textId, bool* loadFromMessageTable) { @@ -29,6 +38,37 @@ void RegisterFishingMessages() { }); } +void RegisterCustomizeFishing() { + bool customized = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0); + + COND_VB_SHOULD(VB_FISHING_USE_DEFAULT_RECORD_LENGTH, customized, { + f32* recordLength = va_arg(args, f32*); + *recordLength = Fishing_GetMinimumRequiredScore(); + *should = false; + }); + + COND_VB_SHOULD(VB_FISHING_SPAWN_LOACHES, (customized && CVarGetInteger(CVAR_ENHANCEMENT("LoachesAlwaysAppear"), 0)), + { *should = true; }); + + COND_VB_SHOULD(VB_FISHING_FISH_IS_LOACH, (customized && CVarGetInteger(CVAR_ENHANCEMENT("AllHyruleLoaches"), 0)), + { *should = true; }); + + COND_VB_SHOULD(VB_FISHING_FISH_BITE, (customized && CVarGetInteger(CVAR_ENHANCEMENT("GuaranteeFishingBite"), 0)), + { *should = true; }); + + COND_VB_SHOULD(VB_FISHING_FISH_ESCAPE, (customized && CVarGetInteger(CVAR_ENHANCEMENT("FishNeverEscape"), 0)), + { *should = false; }); + + COND_VB_SHOULD(VB_FISHING_CATCH_FISH, (customized && CVarGetInteger(CVAR_ENHANCEMENT("InstantFishing"), 0)), + { *should = true; }); + + COND_VB_SHOULD(VB_FISHING_INSTANT_CATCH, (customized && CVarGetInteger(CVAR_ENHANCEMENT("InstantFishing"), 0)), + { *should = true; }); + + COND_VB_SHOULD(VB_FISHING_CONFIRM_KEEPING_SMALLER_FISH, + (customized && CVarGetInteger(CVAR_ENHANCEMENT("SkipKeepConfirmation"), 0)), { *should = false; }); +} + void RegisterHoverFishing() { COND_VB_SHOULD(VB_NOT_CAST_FISHING, (CVarGetInteger(CVAR_ENHANCEMENT("HoverFishing"), false)), { Vec3f* rodCheckPos = va_arg(args, Vec3f*); @@ -68,6 +108,12 @@ void RegisterAllowFishingBlankB() { } static RegisterShipInitFunc initFunc(RegisterFishingMessages, { CVAR_ENHANCEMENT("CustomizeFishing"), "IS_RANDO" }); +static RegisterShipInitFunc + initCustomizeFishing(RegisterCustomizeFishing, + { CVAR_ENHANCEMENT("CustomizeFishing"), CVAR_ENHANCEMENT("LoachesAlwaysAppear"), + CVAR_ENHANCEMENT("AllHyruleLoaches"), CVAR_ENHANCEMENT("GuaranteeFishingBite"), + CVAR_ENHANCEMENT("FishNeverEscape"), CVAR_ENHANCEMENT("InstantFishing"), + CVAR_ENHANCEMENT("SkipKeepConfirmation") }); static RegisterShipInitFunc initHoverFishing(RegisterHoverFishing, { CVAR_ENHANCEMENT("HoverFishing") }); static RegisterShipInitFunc initAllowFishingBlankB(RegisterAllowFishingBlankB, { CVAR_ENHANCEMENT("FishingBlankB"), "IS_RANDO" }); diff --git a/soh/soh/Enhancements/Items/BetterBombchuShopping.cpp b/soh/soh/Enhancements/Items/BetterBombchuShopping.cpp index 4982670d2a..23b4d67c36 100644 --- a/soh/soh/Enhancements/Items/BetterBombchuShopping.cpp +++ b/soh/soh/Enhancements/Items/BetterBombchuShopping.cpp @@ -1,5 +1,8 @@ -#include -#include "soh/Enhancements/randomizer/randomizer.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/custom-message/CustomMessageManager.h" +#include "soh/Enhancements/custom-message/CustomMessageTypes.h" +#include "soh/ShipInit.hpp" +#include "soh/cvar_prefixes.h" extern "C" { #include diff --git a/soh/soh/Enhancements/Items/InjectItemCounts.cpp b/soh/soh/Enhancements/Items/InjectItemCounts.cpp index 5bd7c6ee69..6210649624 100644 --- a/soh/soh/Enhancements/Items/InjectItemCounts.cpp +++ b/soh/soh/Enhancements/Items/InjectItemCounts.cpp @@ -1,5 +1,9 @@ -#include -#include "soh/Enhancements/randomizer/randomizer.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/custom-message/CustomMessageManager.h" +#include "soh/Enhancements/custom-message/CustomMessageTypes.h" +#include "soh/Enhancements/randomizer/SeedContext.h" +#include "soh/ShipInit.hpp" +#include "soh/cvar_prefixes.h" extern "C" { #include "variables.h" diff --git a/soh/soh/Enhancements/QoL/NoSkulltulaFreeze.cpp b/soh/soh/Enhancements/QoL/NoSkulltulaFreeze.cpp index 66e6132a17..772955ecec 100644 --- a/soh/soh/Enhancements/QoL/NoSkulltulaFreeze.cpp +++ b/soh/soh/Enhancements/QoL/NoSkulltulaFreeze.cpp @@ -1,4 +1,4 @@ -#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer.h" extern "C" { diff --git a/soh/soh/Enhancements/TimeSavers/QuitFishingAtDoor.cpp b/soh/soh/Enhancements/TimeSavers/QuitFishingAtDoor.cpp index ea275d593b..097a69bab2 100644 --- a/soh/soh/Enhancements/TimeSavers/QuitFishingAtDoor.cpp +++ b/soh/soh/Enhancements/TimeSavers/QuitFishingAtDoor.cpp @@ -1,9 +1,8 @@ -#include -#include "soh/Enhancements/randomizer/randomizer.h" - -extern "C" { -#include -} +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/custom-message/CustomMessageManager.h" +#include "soh/Enhancements/custom-message/CustomMessageTypes.h" +#include "soh/ShipInit.hpp" +#include "soh/cvar_prefixes.h" // TODO: Port the rest of the behavior for this enhancement here. @@ -23,6 +22,9 @@ void BuildQuitFishingMessage(uint16_t* textId, bool* loadFromMessageTable) { void QuitFishingAtDoor_Register() { COND_ID_HOOK(OnOpenText, TEXT_FISHERMAN_LEAVE, CVarGetInteger(CVAR_ENHANCEMENT("QuitFishingAtDoor"), 0), BuildQuitFishingMessage); + + COND_VB_SHOULD(VB_FISHING_QUIT_AT_DOOR, CVarGetInteger(CVAR_ENHANCEMENT("QuitFishingAtDoor"), 0), + { *should = true; }); } static RegisterShipInitFunc initFunc(QuitFishingAtDoor_Register, { CVAR_ENHANCEMENT("QuitFishingAtDoor") }); \ No newline at end of file diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index f4347d94ac..761033a54f 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -757,6 +757,97 @@ typedef enum { // - `*EnElf` VB_FAIRY_HEAL, + // #### `result` + // ```c + // this->actor.xzDistToPlayer < (KREG(59) + 50.0f) + // ``` + // Whether a hooked fish is reeled in close enough to be caught. + // #### `args` + // - None + VB_FISHING_CATCH_FISH, + + // #### `result` + // ```c + // (this->isLoach == 0) && (sFishOnHandIsLoach == 0) && ((s16)this->fishLength < (s16)sFishOnHandLength) + // ``` + // Whether keeping a fish smaller than the one held asks for confirmation. + // #### `args` + // - None + VB_FISHING_CONFIRM_KEEPING_SMALLER_FISH, + + // #### `result` + // ```c + // ((this->timerArray[0] == 1) || (Rand_ZeroOne() < chance)) && + // ((Rand_ZeroOne() < (this->perception * multiplier)) || ((this->isLoach + 1) == KREG(69))) + // ``` + // Whether a fish bites the lure. + // #### `args` + // - None + VB_FISHING_FISH_BITE, + + // #### `result` + // ```c + // ((sLureTimer & 0x7F) == 0) && (Rand_ZeroOne() < 0.05f) && (sLureEquipped != FS_LURE_SINKING) && (KREG(69) == 0) + // ``` + // Whether a hooked fish randomly escapes the line. + // #### `args` + // - None + VB_FISHING_FISH_ESCAPE, + + // #### `result` + // ```c + // sFishInits[thisx->params - EN_FISH_PARAM].isLoach + // ``` + // Whether this pond fish is a loach. + // #### `args` + // - None + VB_FISHING_FISH_IS_LOACH, + + // #### `result` + // ```c + // false + // ``` + // Whether a caught fish snaps to Link's hand instead of drifting there. + // #### `args` + // - None + VB_FISHING_INSTANT_CATCH, + + // #### `result` + // ```c + // false + // ``` + // Whether the pond owner offers to quit fishing at the door. + // #### `args` + // - None + VB_FISHING_QUIT_AT_DOOR, + + // #### `result` + // ```c + // (KREG(1) == 1) || ((sFishGameNumber & 3) == 3) + // ``` + // Whether loaches spawn in the pond this game. + // #### `args` + // - None + VB_FISHING_SPAWN_LOACHES, + + // #### `result` + // ```c + // true + // ``` + // Whether the starting fishing record uses the vanilla length. + // A hook returning false should write its own length through the arg. + // #### `args` + // - `*f32` (sFishingRecordLength) + VB_FISHING_USE_DEFAULT_RECORD_LENGTH, + + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - None + VB_FISHING_ZERO_XZ, + // #### `result` // True if the next text position must be beyond the current position; false otherwise // #### `args` @@ -2653,14 +2744,6 @@ typedef enum { // - `*Vec3f` VB_NOT_CAST_FISHING, - // #### `result` - // ```c - // true - // ``` - // #### `args` - // - None - VB_FISHING_ZERO_XZ, - // #### `result` // ```c // false diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp index f674efd318..6bc56aa6da 100644 --- a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -1,6 +1,7 @@ -#include "playthrough.hpp" - #include +#include + +#include "playthrough.hpp" #include "fill.hpp" #include "../location_access.h" #include "../rng.h" diff --git a/soh/soh/Enhancements/randomizer/BigPoes.cpp b/soh/soh/Enhancements/randomizer/BigPoes.cpp index fc58f85018..a78fbe830d 100644 --- a/soh/soh/Enhancements/randomizer/BigPoes.cpp +++ b/soh/soh/Enhancements/randomizer/BigPoes.cpp @@ -1,4 +1,4 @@ -#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer.h" extern "C" { diff --git a/soh/soh/Enhancements/randomizer/Bombchus.cpp b/soh/soh/Enhancements/randomizer/Bombchus.cpp index 6977b23185..1491cefc8c 100644 --- a/soh/soh/Enhancements/randomizer/Bombchus.cpp +++ b/soh/soh/Enhancements/randomizer/Bombchus.cpp @@ -1,4 +1,4 @@ -#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/ShipInit.hpp" #include "src/overlays/actors/ovl_En_GirlA/z_en_girla.h" #include "soh/Enhancements/randomizer/SeedContext.h" @@ -21,7 +21,7 @@ void RegisterVBOverrides() { } int8_t capacity = 50; if (bombchuBag.Is(RO_BOMBCHU_BAG_PROGRESSIVE)) { - capacity = OTRGlobals::Instance->gRandoContext->GetBombchuCapacity(); + capacity = Rando::Context::GetInstance()->GetBombchuCapacity(); } if (AMMO(ITEM_BOMBCHU) >= capacity) { *canBuy = CANBUY_RESULT_CANT_GET_NOW; @@ -31,7 +31,7 @@ void RegisterVBOverrides() { COND_VB_SHOULD(VB_CHECK_BOMBCHU_CAPACITY, shouldRegister, { *should = false; - uint8_t capacity = OTRGlobals::Instance->gRandoContext->GetBombchuCapacity(); + uint8_t capacity = Rando::Context::GetInstance()->GetBombchuCapacity(); if (AMMO(ITEM_BOMBCHU) > capacity) { AMMO(ITEM_BOMBCHU) = capacity; } @@ -40,7 +40,7 @@ void RegisterVBOverrides() { COND_VB_SHOULD(VB_COLOR_AMMO_GREEN, shouldRegister, { int16_t i = va_arg(args, int); if (i == ITEM_BOMBCHU) { - uint8_t capacity = OTRGlobals::Instance->gRandoContext->GetBombchuCapacity(); + uint8_t capacity = Rando::Context::GetInstance()->GetBombchuCapacity(); if (AMMO(i) == capacity) { *should = true; } diff --git a/soh/soh/Enhancements/randomizer/ColoredMapsAndCompasses.cpp b/soh/soh/Enhancements/randomizer/ColoredMapsAndCompasses.cpp index 018dc3d2ce..d87a739223 100644 --- a/soh/soh/Enhancements/randomizer/ColoredMapsAndCompasses.cpp +++ b/soh/soh/Enhancements/randomizer/ColoredMapsAndCompasses.cpp @@ -1,9 +1,9 @@ #include "soh/ResourceManagerHelpers.h" +#include #include "soh/ShipInit.hpp" #include "z64save.h" #include "objects/object_gi_compass/object_gi_compass.h" #include "objects/object_gi_map/object_gi_map.h" -#include "soh/OTRGlobals.h" #include "soh/Enhancements/randomizer/SeedContext.h" extern "C" { diff --git a/soh/soh/Enhancements/randomizer/MedallionLockedTrials.cpp b/soh/soh/Enhancements/randomizer/MedallionLockedTrials.cpp index 3cd2585e66..4910233329 100644 --- a/soh/soh/Enhancements/randomizer/MedallionLockedTrials.cpp +++ b/soh/soh/Enhancements/randomizer/MedallionLockedTrials.cpp @@ -1,4 +1,4 @@ -#include "soh/OTRGlobals.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/ShipInit.hpp" #include "soh/Enhancements/randomizer/SeedContext.h" diff --git a/soh/soh/Enhancements/randomizer/Messages/EntranceHints.cpp b/soh/soh/Enhancements/randomizer/Messages/EntranceHints.cpp index 5722668cf0..f67a020b61 100644 --- a/soh/soh/Enhancements/randomizer/Messages/EntranceHints.cpp +++ b/soh/soh/Enhancements/randomizer/Messages/EntranceHints.cpp @@ -1,7 +1,7 @@ #include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer_entrance_tracker.h" #include "soh/Enhancements/randomizer/randomizer.h" -#include extern "C" { #include @@ -12,12 +12,12 @@ extern PlayState* gPlayState; // clang-format attempts to format this strangely for some reason, so temporarily turning it off #define ENTRANCES_SHUFFLED \ IS_RANDO && \ - OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_ENTRANCES).Is(RO_GENERIC_ON) && \ + Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_ENTRANCES).Is(RO_GENERIC_ON) && \ (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("EntrancesOnSigns"), 0) == 1) // clang-format on void BuildEntranceHintMessage(uint16_t* textId, bool* loadFromMessageTable) { - auto ctx = OTRGlobals::Instance->gRandoContext; + auto ctx = Rando::Context::GetInstance(); s16 entrance = -1; switch (*textId) { case TEXT_WATERFALL: diff --git a/soh/soh/Enhancements/randomizer/Messages/Goron.cpp b/soh/soh/Enhancements/randomizer/Messages/Goron.cpp index c683388aea..3e0b2c79eb 100644 --- a/soh/soh/Enhancements/randomizer/Messages/Goron.cpp +++ b/soh/soh/Enhancements/randomizer/Messages/Goron.cpp @@ -2,7 +2,7 @@ * Handles the randomized silly messages that the Fire Temple * trapped Gorons have when you free them. */ -#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer.h" extern "C" { diff --git a/soh/soh/Enhancements/randomizer/Messages/MerchantMessages.cpp b/soh/soh/Enhancements/randomizer/Messages/MerchantMessages.cpp index 51398de1b3..017c24571e 100644 --- a/soh/soh/Enhancements/randomizer/Messages/MerchantMessages.cpp +++ b/soh/soh/Enhancements/randomizer/Messages/MerchantMessages.cpp @@ -7,6 +7,7 @@ * and Carpet Salesman) */ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/ObjectExtension/ObjectExtension.h" #include "soh/Enhancements/randomizer/randomizer.h" diff --git a/soh/soh/Enhancements/randomizer/Messages/Miscellaneous.cpp b/soh/soh/Enhancements/randomizer/Messages/Miscellaneous.cpp index 5a3c846541..1dc3ac80b7 100644 --- a/soh/soh/Enhancements/randomizer/Messages/Miscellaneous.cpp +++ b/soh/soh/Enhancements/randomizer/Messages/Miscellaneous.cpp @@ -5,7 +5,7 @@ * text changes that don't really fit anywhere else. */ -#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer.h" extern "C" { diff --git a/soh/soh/Enhancements/randomizer/Messages/Navi.cpp b/soh/soh/Enhancements/randomizer/Messages/Navi.cpp index 430841ec8c..0d82ce5add 100644 --- a/soh/soh/Enhancements/randomizer/Messages/Navi.cpp +++ b/soh/soh/Enhancements/randomizer/Messages/Navi.cpp @@ -2,7 +2,7 @@ * This file is responsible for the messages * for the Rando-Relevant Navi Hints enhancement. */ -#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer.h" extern "C" { diff --git a/soh/soh/Enhancements/randomizer/Messages/Rupees.cpp b/soh/soh/Enhancements/randomizer/Messages/Rupees.cpp index 3681770c85..c2d7c465fd 100644 --- a/soh/soh/Enhancements/randomizer/Messages/Rupees.cpp +++ b/soh/soh/Enhancements/randomizer/Messages/Rupees.cpp @@ -1,7 +1,7 @@ /** * This file is for handling the Randomize Rupee Names enhancement */ -#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer.h" extern "C" { diff --git a/soh/soh/Enhancements/randomizer/SeedContext.cpp b/soh/soh/Enhancements/randomizer/SeedContext.cpp index 29f00628ed..66fc1b38b2 100644 --- a/soh/soh/Enhancements/randomizer/SeedContext.cpp +++ b/soh/soh/Enhancements/randomizer/SeedContext.cpp @@ -38,7 +38,6 @@ Context::Context() { mDungeons = std::make_shared(); mLogic = std::make_shared(); mTrials = std::make_shared(); - mFishsanity = std::make_shared(); } RandomizerArea Context::GetAreaFromString(std::string str) { @@ -185,7 +184,7 @@ void Context::GenerateLocationPool() { (location.GetRCType() == RCTYPE_COW && mOptions[RSK_SHUFFLE_COWS].Is(RO_GENERIC_OFF)) || (location.GetRandomizerCheck() == RC_LH_HYRULE_LOACH && mOptions[RSK_FISHSANITY].IsNot(RO_FISHSANITY_HYRULE_LOACH)) || - (location.GetRCType() == RCTYPE_FISH && !mFishsanity->GetFishLocationIncluded(&location)) || + (location.GetRCType() == RCTYPE_FISH && !Fishsanity::GetFishLocationIncluded(&location)) || (location.GetRCType() == RCTYPE_POT && mOptions[RSK_SHUFFLE_POTS].Is(RO_SHUFFLE_POTS_OFF)) || (location.GetRCType() == RCTYPE_GRASS && mOptions[RSK_SHUFFLE_GRASS].Is(RO_SHUFFLE_GRASS_OFF)) || (location.GetRCType() == RCTYPE_CRATE && mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_OFF)) || @@ -496,10 +495,6 @@ std::shared_ptr Context::GetDungeons() { return mDungeons; } -std::shared_ptr Context::GetFishsanity() { - return mFishsanity; -} - DungeonInfo* Context::GetDungeon(size_t key) const { return mDungeons->GetDungeon(static_cast(key)); } diff --git a/soh/soh/Enhancements/randomizer/SeedContext.h b/soh/soh/Enhancements/randomizer/SeedContext.h index 8630e600ce..cc5eb5ac12 100644 --- a/soh/soh/Enhancements/randomizer/SeedContext.h +++ b/soh/soh/Enhancements/randomizer/SeedContext.h @@ -3,7 +3,6 @@ #include "randomizerTypes.h" #include "item_override.h" #include "hint.h" -#include "fishsanity.h" #include "trial.h" #include @@ -86,7 +85,6 @@ class Context { const std::set& enabledTricks); std::shared_ptr GetEntranceShuffler(); std::shared_ptr GetDungeons(); - std::shared_ptr GetFishsanity(); DungeonInfo* GetDungeon(size_t key) const; DungeonInfo* GetDungeonFromScene(SceneID key) const; std::shared_ptr GetLogic(); @@ -195,7 +193,6 @@ class Context { std::shared_ptr mDungeons; std::shared_ptr mLogic; std::shared_ptr mTrials; - std::shared_ptr mFishsanity; std::shared_ptr mKaleido; bool mSeedGenerated = false; bool mSpoilerLoaded = false; diff --git a/soh/soh/Enhancements/randomizer/ShuffleBeehives.cpp b/soh/soh/Enhancements/randomizer/ShuffleBeehives.cpp index 285ab5fcd3..b6fda51df2 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleBeehives.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleBeehives.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "static_data.h" #include "soh/ObjectExtension/ObjectExtension.h" #include "soh/Enhancements/randomizer/randomizer.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleBeggar.cpp b/soh/soh/Enhancements/randomizer/ShuffleBeggar.cpp index f16fcded51..6389be71d1 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleBeggar.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleBeggar.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer.h" #include "soh/Enhancements/randomizer/RCToRandInf.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleCows.cpp b/soh/soh/Enhancements/randomizer/ShuffleCows.cpp index ff9937dbae..8df4959d65 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleCows.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleCows.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "static_data.h" #include "soh/Enhancements/randomizer/randomizer.h" #include "soh/Enhancements/randomizer/RCToRandInf.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp b/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp index d3308578c5..bdad9eb69d 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh_assets.h" #include "static_data.h" #include diff --git a/soh/soh/Enhancements/randomizer/ShuffleFairies.cpp b/soh/soh/Enhancements/randomizer/ShuffleFairies.cpp index 1e66e39b10..487b02602a 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleFairies.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleFairies.cpp @@ -1,4 +1,5 @@ #include "soh/OTRGlobals.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "randomizer_grotto.h" #include "draw.h" #include "static_data.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleFreestanding.cpp b/soh/soh/Enhancements/randomizer/ShuffleFreestanding.cpp index 53d81d85bb..ea9c424cad 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleFreestanding.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleFreestanding.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer.h" extern "C" { diff --git a/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp b/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp index 0dd29be179..a065cbdbe5 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh_assets.h" #include "static_data.h" #include "item_category_adj.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleIcicles.cpp b/soh/soh/Enhancements/randomizer/ShuffleIcicles.cpp index 943f6a797f..353d63a9e8 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleIcicles.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleIcicles.cpp @@ -1,4 +1,5 @@ #include "soh/ObjectExtension/ObjectExtension.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "item_category_adj.h" #include "particle_cmc.h" #include "soh/frame_interpolation.h" diff --git a/soh/soh/Enhancements/randomizer/ShufflePots.cpp b/soh/soh/Enhancements/randomizer/ShufflePots.cpp index a803460917..05b616c012 100644 --- a/soh/soh/Enhancements/randomizer/ShufflePots.cpp +++ b/soh/soh/Enhancements/randomizer/ShufflePots.cpp @@ -1,4 +1,5 @@ #include "soh/OTRGlobals.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh_assets.h" #include "static_data.h" #include "item_category_adj.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleRedIce.cpp b/soh/soh/Enhancements/randomizer/ShuffleRedIce.cpp index 1a31811c32..c3d4d00297 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleRedIce.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleRedIce.cpp @@ -1,4 +1,5 @@ #include "soh/OTRGlobals.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/ObjectExtension/ObjectExtension.h" #include "item_category_adj.h" #include "particle_cmc.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleRocks.cpp b/soh/soh/Enhancements/randomizer/ShuffleRocks.cpp index cd9792532d..7cad165192 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleRocks.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleRocks.cpp @@ -1,4 +1,5 @@ #include "ShuffleRocks.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "static_data.h" #include "soh/ObjectExtension/ObjectExtension.h" #include "item_category_adj.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleSigns.cpp b/soh/soh/Enhancements/randomizer/ShuffleSigns.cpp index 09b6c43f52..445fdc8456 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleSigns.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleSigns.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/ObjectExtension/ObjectExtension.h" #include "item_category_adj.h" #include "particle_cmc.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleSilver.cpp b/soh/soh/Enhancements/randomizer/ShuffleSilver.cpp index b71bffdd4d..3ddd38eb3d 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleSilver.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleSilver.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "dungeon.h" #include "SeedContext.h" #include "draw.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleSpeak.cpp b/soh/soh/Enhancements/randomizer/ShuffleSpeak.cpp index 96b150fede..95d285f8ac 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleSpeak.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleSpeak.cpp @@ -1,9 +1,9 @@ -#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/randomizer/SeedContext.h" +extern "C" { #include "z64.h" #include "functions.h" -#include "soh/Enhancements/randomizer/SeedContext.h" #include "overlays/actors/ovl_En_Ossan/z_en_ossan.h" -extern "C" { extern PlayState* gPlayState; } diff --git a/soh/soh/Enhancements/randomizer/ShuffleTreasureChestGame.cpp b/soh/soh/Enhancements/randomizer/ShuffleTreasureChestGame.cpp index 8c145f27ab..cb9fd22d77 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleTreasureChestGame.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleTreasureChestGame.cpp @@ -1,4 +1,4 @@ -#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer.h" extern "C" { diff --git a/soh/soh/Enhancements/randomizer/ShuffleTrees.cpp b/soh/soh/Enhancements/randomizer/ShuffleTrees.cpp index 96ed5cee62..2a8565edfb 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleTrees.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleTrees.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh_assets.h" #include "static_data.h" #include "soh/ObjectExtension/ObjectExtension.h" diff --git a/soh/soh/Enhancements/randomizer/ShuffleWonderItems.cpp b/soh/soh/Enhancements/randomizer/ShuffleWonderItems.cpp index 5926503b6e..855ef0bba4 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleWonderItems.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleWonderItems.cpp @@ -1,4 +1,5 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include #include "soh/ResourceManagerHelpers.h" #include "soh/ObjectExtension/ObjectExtension.h" diff --git a/soh/soh/Enhancements/randomizer/Traps.cpp b/soh/soh/Enhancements/randomizer/Traps.cpp index f69d4a4bec..0cb52ffa40 100644 --- a/soh/soh/Enhancements/randomizer/Traps.cpp +++ b/soh/soh/Enhancements/randomizer/Traps.cpp @@ -1,4 +1,5 @@ #include "Traps.h" +#include #include "soh/Enhancements/randomizer/SeedContext.h" #include "soh/Enhancements/randomizer/static_data.h" #include "soh/ShipUtils.h" diff --git a/soh/soh/Enhancements/randomizer/entrance.cpp b/soh/soh/Enhancements/randomizer/entrance.cpp index cc14f1e8f4..22186bfeee 100644 --- a/soh/soh/Enhancements/randomizer/entrance.cpp +++ b/soh/soh/Enhancements/randomizer/entrance.cpp @@ -1,4 +1,5 @@ #include "entrance.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "3drando/fill.hpp" #include "3drando/pool_functions.hpp" diff --git a/soh/soh/Enhancements/randomizer/fishsanity.cpp b/soh/soh/Enhancements/randomizer/fishsanity.cpp index 7daf3a0ebd..d122a9bbc1 100644 --- a/soh/soh/Enhancements/randomizer/fishsanity.cpp +++ b/soh/soh/Enhancements/randomizer/fishsanity.cpp @@ -1,7 +1,8 @@ -#include "3drando/pool_functions.hpp" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "../../OTRGlobals.h" #include "fishsanity.h" #include "draw.h" +#include "soh/frame_interpolation.h" #include "variables.h" #include "functions.h" #include "macros.h" @@ -50,160 +51,35 @@ std::unordered_map Rando::StaticData::randomizerGrottoF { 0x29, RC_ZR_OPEN_GROTTO_FISH } }; -ActorFunc drawFishing = NULL; -ActorFunc drawEnFish = NULL; -Color_RGB8 fsPulseColor = { 30, 240, 200 }; +typedef struct { + u8 mode; + u8 numFish; + bool ageSplit; +} FishsanityPondOptions; + +typedef enum { + FSC_NONE, + FSC_POND, + FSC_GROTTO, + FSC_ZD, +} FishsanityCheckType; + +static const CheckIdentity defaultIdentity = { RAND_INF_MAX, RC_UNKNOWN_CHECK }; + +static CheckIdentity NextChildPondFish = defaultIdentity; +static CheckIdentity NextAdultPondFish = defaultIdentity; + +static ActorFunc drawFishing = NULL; +static ActorFunc drawEnFish = NULL; +static Color_RGB8 fsPulseColor = { 30, 240, 200 }; static s16 fishGroupCounter = 0; static bool enableAdvance = false; -static CheckIdentity IdentifyFish(s32 sceneNum, s32 actorParams) { - CheckIdentity fishIdentity; - - fishIdentity.randomizerInf = RAND_INF_MAX; - fishIdentity.randomizerCheck = RC_UNKNOWN_CHECK; - - // Fishsanity will determine what the identity of the fish should be - if (sceneNum == SCENE_FISHING_POND) { - return OTRGlobals::Instance->gRandoContext->GetFishsanity()->IdentifyPondFish(actorParams); - } - - Rando::Location* location = - OTRGlobals::Instance->gRandomizer->GetCheckObjectFromActor(ACTOR_EN_FISH, sceneNum, actorParams); - - if (location->GetRandomizerCheck() != RC_UNKNOWN_CHECK) { - fishIdentity.randomizerInf = rcToRandomizerInf[location->GetRandomizerCheck()]; - fishIdentity.randomizerCheck = location->GetRandomizerCheck(); - } - - return fishIdentity; -} - -namespace Rando { -const CheckIdentity Fishsanity::defaultIdentity = { RAND_INF_MAX, RC_UNKNOWN_CHECK }; -bool Fishsanity::fishsanityHelpersInit = false; -std::unordered_map Fishsanity::pondFishAgeMap; -std::vector Fishsanity::childPondFish; -std::vector Fishsanity::adultPondFish; - -Fishsanity::Fishsanity() { - InitializeHelpers(); -} - -Fishsanity::~Fishsanity() { -} - -bool Fishsanity::GetFishLocationIncluded(Rando::Location* loc, FishsanityOptionsSource optionsSource) { - auto [mode, numFish, ageSplit] = GetOptions(optionsSource); - - if (loc->GetRCType() != RCTYPE_FISH || mode == RO_FISHSANITY_OFF || mode == RO_FISHSANITY_HYRULE_LOACH) { - return false; - } - RandomizerCheck rc = loc->GetRandomizerCheck(); - // Are pond fish enabled, and is this a pond fish location? - if (mode != RO_FISHSANITY_OVERWORLD && numFish > 0 && loc->GetScene() == SCENE_FISHING_POND && - loc->GetActorID() == ACTOR_FISHING) { - // Is this a child fish location? If so, is it within the defined number of pond fish checks? - if (rc >= RC_LH_CHILD_FISH_1 && rc <= RC_LH_CHILD_LOACH_2 && numFish > (loc->GetActorParams() - 100)) { - return true; - } - // Are adult fish available, and is this an adult fish location? If so, is it within the defined number of pond - // fish checks? - if (ageSplit && rc >= RC_LH_ADULT_FISH_1 && rc <= RC_LH_ADULT_LOACH && - numFish > (loc->GetActorParams() - 100)) { - return true; - } - } - // Are overworld fish enabled, and is this an overworld fish location? - if (mode != RO_FISHSANITY_POND && (loc->GetScene() == SCENE_GROTTOS || loc->GetScene() == SCENE_ZORAS_DOMAIN) && - loc->GetActorID() == ACTOR_EN_FISH && (loc->GetActorParams() >> 8)) { - return true; - } - // Must not be an included fish location! - return false; -} - -std::pair, std::vector> -Fishsanity::GetFishingPondLocations(FishsanityOptionsSource optionsSource) { - auto [mode, numFish, ageSplit] = GetOptions(optionsSource); - std::vector activeFish; - std::vector remainingFish; - std::vector pondFish = Rando::StaticData::GetPondFishLocations(); - - // Fishsanity_InitializeHelpers(); - remainingFish.insert(remainingFish.end(), pondFish.begin(), pondFish.end()); - - // No pond fish shuffled - if (numFish == 0) { - return std::make_pair(activeFish, remainingFish); - } - // Every pond fish is shuffled, so we can save some time - if (numFish > 16) { - // Child and adult pond fish are both shuffled, set activeFish to remainingFish and return an empty vector for - // inactive fish. - if (ageSplit) { - return std::make_pair(remainingFish, activeFish); - } - // Activate all child fish only - activeFish = FilterAndEraseFromPool( - remainingFish, [](const RandomizerCheck loc) { return pondFishAgeMap[loc] == LINK_AGE_CHILD; }); - return std::make_pair(activeFish, remainingFish); - } - // Only some pond fish are shuffled, so we have to only activate the requested number. - activeFish.insert(activeFish.end(), childPondFish.begin(), childPondFish.begin() + numFish); - // If pond is split, also add the requested number of adult fish. - if (ageSplit) { - activeFish.insert(activeFish.end(), adultPondFish.begin(), - adultPondFish.begin() + std::min(numFish, 16)); - } - // NOTE: This only works because we can assume activeFish is already sorted; changes that break this assumption will - // also break this - std::erase_if(remainingFish, - [&](RandomizerCheck loc) { return std::binary_search(activeFish.begin(), activeFish.end(), loc); }); - - return std::make_pair(activeFish, remainingFish); -} - -std::pair, std::vector> -Fishsanity::GetFishsanityLocations(FishsanityOptionsSource optionsSource) { - auto [mode, numFish, ageSplit] = GetOptions(optionsSource); - std::vector activeFish; - std::vector remainingFish; - - // Add pond fish - if (mode == RO_FISHSANITY_POND || mode == RO_FISHSANITY_BOTH) { - auto pondLocations = GetFishingPondLocations(optionsSource); - activeFish.insert(activeFish.end(), pondLocations.first.begin(), pondLocations.first.end()); - remainingFish.insert(remainingFish.end(), pondLocations.second.begin(), pondLocations.second.end()); - } - - // Add overworld fish - if (mode == RO_FISHSANITY_OVERWORLD || mode == RO_FISHSANITY_BOTH) { - std::vector overworldFish = Rando::StaticData::GetOverworldFishLocations(); - activeFish.insert(activeFish.end(), overworldFish.begin(), overworldFish.end()); - } - - return std::make_pair(activeFish, remainingFish); -} - -CheckIdentity Fishsanity::IdentifyPondFish(u8 fishParams) { - auto [mode, pondCount, ageSplit] = GetOptions(); - CheckIdentity identity = defaultIdentity; - - if (!GetPondFishShuffled()) { - return identity; - } - - if (pondCount > 16) { - identity = GetPondFish(fishParams, IsAdultPond()); - } else { - identity = LINK_IS_ADULT ? mCurrPondFish.second : mCurrPondFish.first; - } - - return identity; -} - -FishsanityPondOptions Fishsanity::GetOptions(FishsanityOptionsSource optionsSource) { +/** + * @brief Get fishsanity fishing pond options from the requested source + */ +static FishsanityPondOptions GetOptions(FishsanityOptionsSource optionsSource = FSO_SOURCE_RANDO) { FishsanityPondOptions options{}; switch (optionsSource) { // Used in check tracker @@ -222,13 +98,101 @@ FishsanityPondOptions Fishsanity::GetOptions(FishsanityOptionsSource optionsSour return options; } -void Fishsanity::UpdateCurrentPondFish() { - auto [mode, pondCount, ageSplit] = GetOptions(); - mCurrPondFish = std::pair(); - mCurrPondFish.first = defaultIdentity; - mCurrPondFish.second = defaultIdentity; +/** + * @brief Returns true if the fishing pond is shuffled + */ +static bool GetPondFishShuffled() { + u8 fsMode = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY); + return OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY_POND_COUNT) > 0 && + (fsMode == RO_FISHSANITY_POND || fsMode == RO_FISHSANITY_BOTH); +} - // Initialize mCurrPondFish if we're shuffling pond fish, but if all fish are shuffled, we don't need to use this. +/** + * @brief Returns true if overworld fish are shuffled + */ +static bool GetOverworldFishShuffled() { + u8 fsMode = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY); + return fsMode == RO_FISHSANITY_OVERWORLD || fsMode == RO_FISHSANITY_BOTH; +} + +/** + * @brief Returns true if the fishing pond is currently adult (i.e., age split is enabled and Link is adult) + */ +static bool IsAdultPond() { + return LINK_IS_ADULT && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY_AGE_SPLIT); +} + +/** + * @brief Gets the type of a fishsanity check + */ +static FishsanityCheckType GetCheckType(RandomizerCheck rc) { + // if it's not RCTYPE_FISH, obviously it's not a fish + if (Rando::StaticData::GetLocation(rc)->GetRCType() != RCTYPE_FISH) { + return FSC_NONE; + } + + auto loc = Rando::StaticData::GetLocation(rc); + switch (loc->GetScene()) { + case SCENE_FISHING_POND: + return FSC_POND; + case SCENE_ZORAS_DOMAIN: + return FSC_ZD; + case SCENE_GROTTOS: + return FSC_GROTTO; + default: + return FSC_NONE; + } +} + +/** + * @brief Returns true if the given CheckIdentity represents an actual fish + */ +static bool IsFish(CheckIdentity* fish) { + if (fish->randomizerCheck == RC_UNKNOWN_CHECK || fish->randomizerInf == RAND_INF_MAX) { + return false; + } + + return GetCheckType(fish->randomizerCheck) != FSC_NONE; +} + +/** + * @brief Resolves a pond fish's CheckIdentity directly from params & pond age + */ +static CheckIdentity GetPondFish(s16 params, bool adultPond) { + auto pair = Rando::StaticData::randomizerFishingPondFish[params - 100]; + RandomizerCheck rc = adultPond ? pair.second : pair.first; + return { OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(rc), rc }; +} + +/** + * @brief Returns the identity for a caught pond fish given its params + */ +static CheckIdentity IdentifyPondFish(u8 fishParams) { + auto [mode, pondCount, ageSplit] = GetOptions(); + CheckIdentity identity = defaultIdentity; + + if (!GetPondFishShuffled()) { + return identity; + } + + if (pondCount > 16) { + identity = GetPondFish(fishParams, IsAdultPond()); + } else { + identity = LINK_IS_ADULT ? NextAdultPondFish : NextChildPondFish; + } + + return identity; +} + +/** + * @brief Updates current pond fish according to save data + */ +static void UpdateCurrentPondFish() { + auto [mode, pondCount, ageSplit] = GetOptions(); + NextChildPondFish = defaultIdentity; + NextAdultPondFish = defaultIdentity; + + // Initialize next pond fish if we're shuffling pond fish, but if all fish are shuffled, we don't need to use this. if ((mode == RO_FISHSANITY_BOTH || mode == RO_FISHSANITY_POND) && pondCount < 17) { // find the first inf that isn't set yet for each age // but don't go past the max number @@ -239,47 +203,31 @@ void Fishsanity::UpdateCurrentPondFish() { OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(tableEntry.first)) || i == pondCount - 1) { // Found first child check - if (!IsFish(&mCurrPondFish.first)) { - mCurrPondFish.first = GetPondFish(params, false); + if (!IsFish(&NextChildPondFish)) { + NextChildPondFish = GetPondFish(params, false); } - if (!ageSplit && !IsFish(&mCurrPondFish.second)) { - mCurrPondFish.second = GetPondFish(params, false); + if (!ageSplit && !IsFish(&NextAdultPondFish)) { + NextAdultPondFish = GetPondFish(params, false); // both ages are resolved! we can quit here break; } } - if (ageSplit && !IsFish(&mCurrPondFish.second) && tableEntry.second != RC_UNKNOWN_CHECK && + if (ageSplit && !IsFish(&NextAdultPondFish) && tableEntry.second != RC_UNKNOWN_CHECK && (!Flags_GetRandomizerInf( OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(tableEntry.second)) || i == pondCount - 1)) { - mCurrPondFish.second = GetPondFish(params, true); + NextAdultPondFish = GetPondFish(params, true); } } } } -void Fishsanity::InitializeFromSave() { - UpdateCurrentPondFish(); -} - -bool Fishsanity::GetPondFishShuffled() { - u8 fsMode = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY); - return OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY_POND_COUNT) > 0 && - (fsMode == RO_FISHSANITY_POND || fsMode == RO_FISHSANITY_BOTH); -} - -bool Fishsanity::GetOverworldFishShuffled() { - u8 fsMode = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY); - return fsMode == RO_FISHSANITY_OVERWORLD || fsMode == RO_FISHSANITY_BOTH; -} - -bool Fishsanity::IsAdultPond() { - return LINK_IS_ADULT && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY_AGE_SPLIT); -} - -bool Fishsanity::GetPondCleared() { +/** + * @brief Returns true if all available pond fish checks have been collected for the current age + */ +static bool GetPondCleared() { auto [mode, pondCount, ageSplit] = GetOptions(); // no fish shuffled, so pond is always cleared :thumbsup: if (pondCount == 0) { @@ -307,187 +255,45 @@ bool Fishsanity::GetPondCleared() { return true; } -bool Fishsanity::GetDomainCleared() { - for (RandomizerInf i = RAND_INF_ZD_FISH_1; i <= RAND_INF_ZD_FISH_5; i = (RandomizerInf)(i + 1)) { - if (!Flags_GetRandomizerInf(i)) { - return false; - } +static CheckIdentity IdentifyFish(s32 sceneNum, s32 actorParams) { + CheckIdentity fishIdentity; + + fishIdentity.randomizerInf = RAND_INF_MAX; + fishIdentity.randomizerCheck = RC_UNKNOWN_CHECK; + + // Fishsanity will determine what the identity of the fish should be + if (sceneNum == SCENE_FISHING_POND) { + return IdentifyPondFish(actorParams); } - return true; + + Rando::Location* location = + OTRGlobals::Instance->gRandomizer->GetCheckObjectFromActor(ACTOR_EN_FISH, sceneNum, actorParams); + + if (location->GetRandomizerCheck() != RC_UNKNOWN_CHECK) { + fishIdentity.randomizerInf = rcToRandomizerInf[location->GetRandomizerCheck()]; + fishIdentity.randomizerCheck = location->GetRandomizerCheck(); + } + + return fishIdentity; } -void Fishsanity::InitializeHelpers() { - if (fishsanityHelpersInit) { - return; - } - - for (auto pair : Rando::StaticData::randomizerFishingPondFish) { - pondFishAgeMap[pair.first] = LINK_AGE_CHILD; - pondFishAgeMap[pair.second] = LINK_AGE_ADULT; - childPondFish.push_back(pair.first); - adultPondFish.push_back(pair.second); - } +static void Fishsanity_OpenGreyscaleColor(PlayState* play, Color_RGB8* color, int16_t frameOffset) { + OPEN_DISPS(play->state.gfxCtx); + gDPSetGrayscaleColor(POLY_OPA_DISP++, color->r, color->g, color->b, + // Make color pulse, offset a bit by the actor params + ABS(255.0f * Math_CosS((play->gameplayFrames + frameOffset) * 1000))); + gSPGrayscale(POLY_OPA_DISP++, true); + CLOSE_DISPS(play->state.gfxCtx); } -CheckIdentity Fishsanity::GetPondFish(s16 params, bool adultPond) { - auto pair = Rando::StaticData::randomizerFishingPondFish[params - 100]; - RandomizerCheck rc = adultPond ? pair.second : pair.first; - return { OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(rc), rc }; +static void Fishsanity_CloseGreyscaleColor(PlayState* play) { + OPEN_DISPS(play->state.gfxCtx); + gSPGrayscale(POLY_OPA_DISP++, false); + CLOSE_DISPS(play->state.gfxCtx); } -CheckIdentity Fishsanity::AdvancePond() { - auto [mode, pondCount, ageSplit] = GetOptions(); - - // No need to update state with full pond shuffle - if (pondCount > 16) { - return defaultIdentity; - } - - UpdateCurrentPondFish(); - - return IsAdultPond() ? mCurrPondFish.second : mCurrPondFish.first; -} - -FishsanityCheckType Fishsanity::GetCheckType(RandomizerCheck rc) { - // if it's not RCTYPE_FISH, obviously it's not a fish - if (Rando::StaticData::GetLocation(rc)->GetRCType() != RCTYPE_FISH) { - return FSC_NONE; - } - - auto loc = Rando::StaticData::GetLocation(rc); - switch (loc->GetScene()) { - case SCENE_FISHING_POND: - return FSC_POND; - case SCENE_ZORAS_DOMAIN: - return FSC_ZD; - case SCENE_GROTTOS: - return FSC_GROTTO; - default: - return FSC_NONE; - } -} - -bool Fishsanity::IsFish(CheckIdentity* fish) { - if (fish->randomizerCheck == RC_UNKNOWN_CHECK || fish->randomizerInf == RAND_INF_MAX) { - return false; - } - - return GetCheckType(fish->randomizerCheck) != FSC_NONE; -} - -void Fishsanity::OnActorInitHandler(void* refActor) { - Actor* actor = static_cast(refActor); - - auto fs = OTRGlobals::Instance->gRandoContext->GetFishsanity(); - CheckIdentity fish; - - if (actor->id == ACTOR_EN_FISH && fs->GetOverworldFishShuffled()) { - // Set fish ID for ZD fish - if (gPlayState->sceneNum == SCENE_ZORAS_DOMAIN && actor->params == -1) { - actor->params ^= fishGroupCounter++; - } else if (gPlayState->sceneNum == SCENE_GROTTOS && actor->params == 1) { - actor->params = 0x100 | gSaveContext.respawn[RESPAWN_MODE_RETURN].data; - } - - fish = IdentifyFish(gPlayState->sceneNum, actor->params); - // Render fish as randomized item - if (Rando::Fishsanity::IsFish(&fish) && !Flags_GetRandomizerInf(fish.randomizerInf)) { - if (!drawEnFish) { - drawEnFish = actor->draw; - } - actor->draw = Fishsanity_DrawEnFish; - } - return; - } - - if (actor->id == ACTOR_FISHING && gPlayState->sceneNum == SCENE_FISHING_POND && actor->params >= 100 && - actor->params <= 117 && fs->GetPondFishShuffled()) { - // Initialize pond fish for fishsanity - // Initialize fishsanity metadata on this actor - Fishing* fishActor = static_cast(refActor); - // fishActor->fishsanityParams = actor->params; - fish = IdentifyFish(gPlayState->sceneNum, actor->params); - - // With every pond fish shuffled, caught fish will not spawn unless all fish have been caught. - if (RAND_GET_OPTION(RSK_FISHSANITY_POND_COUNT).Get() > 16 && !fs->GetPondCleared()) { - // Create effect for uncaught fish - if (!Flags_GetRandomizerInf(fish.randomizerInf)) { - actor->shape.shadowDraw = Fishsanity_DrawEffShadow; - if (!drawFishing) { - drawFishing = actor->draw; - } - actor->draw = Fishsanity_DrawFishing; - } - } - } -} - -void Fishsanity::OnActorUpdateHandler(void* refActor) { - if (gPlayState->sceneNum != SCENE_GROTTOS && gPlayState->sceneNum != SCENE_ZORAS_DOMAIN && - gPlayState->sceneNum != SCENE_FISHING_POND) { - return; - } - - Actor* actor = static_cast(refActor); - auto fs = OTRGlobals::Instance->gRandoContext->GetFishsanity(); - - // Detect fish catch - if (actor->id == ACTOR_FISHING && fs->GetPondFishShuffled()) { - Fishing* fish = static_cast(refActor); - - // State 6 -> Fish caught and hoisted - if (fish->fishState == 6) { - CheckIdentity identity = IdentifyFish(gPlayState->sceneNum, actor->params); - if (identity.randomizerCheck != RC_UNKNOWN_CHECK) { - Flags_SetRandomizerInf(identity.randomizerInf); - enableAdvance = true; - // Remove uncaught effect - if (actor->shape.shadowDraw != NULL) { - actor->shape.shadowDraw = NULL; - actor->draw = drawFishing; - } - } - } - } - - if (actor->id == ACTOR_EN_FISH && fs->GetOverworldFishShuffled()) { - CheckIdentity fish = IdentifyFish(gPlayState->sceneNum, actor->params); - EnFish* fishActor = static_cast(refActor); - if (Rando::Fishsanity::IsFish(&fish) && Flags_GetRandomizerInf(fish.randomizerInf)) { - // Reset draw method - if (actor->draw == Fishsanity_DrawEnFish) { - actor->draw = drawEnFish; - } - } - - if (((actor->params >> 8) > 0) && fishActor->respawnTimer > 0) { - Actor_Kill(actor); - } - } - - // Reset fish group counter when the group gets culled - if (actor->id == ACTOR_OBJ_MURE && gPlayState->sceneNum == SCENE_ZORAS_DOMAIN && fishGroupCounter > 0 && - !(actor->flags & ACTOR_FLAG_UPDATE_CULLING_DISABLED) && fs->GetOverworldFishShuffled()) { - fishGroupCounter = 0; - } -} -} // namespace Rando - -// C interface -extern "C" { -bool Randomizer_GetPondFishShuffled() { - return Rando::Context::GetInstance()->GetFishsanity()->GetPondFishShuffled(); -} - -bool Randomizer_GetOverworldFishShuffled() { - return Rando::Context::GetInstance()->GetFishsanity()->GetOverworldFishShuffled(); -} - -bool Randomizer_IsAdultPond() { - return Rando::Context::GetInstance()->GetFishsanity()->IsAdultPond(); -} - -void Fishsanity_DrawEffShadow(Actor* actor, Lights* lights, PlayState* play) { +/// Custom shadow draw function to add effect to uncollected fish +static void Fishsanity_DrawEffShadow(Actor* actor, Lights* lights, PlayState* play) { Vec3f pos, ripplePos; static Vec3f velocity = { 0.0f, 0.0f, 0.0f }; static Vec3f accel = { 0.0f, 0.0f, 0.0f }; @@ -527,7 +333,8 @@ void Fishsanity_DrawEffShadow(Actor* actor, Lights* lights, PlayState* play) { } } -void Fishsanity_DrawEnFish(struct Actor* actor, struct PlayState* play) { +/// Overridden actor draw function for bottleable fish +static void Fishsanity_DrawEnFish(Actor* actor, PlayState* play) { CheckIdentity fish = IdentifyFish(play->sceneNum, actor->params); GetItemEntry randoItem = Rando::Context::GetInstance()->GetFinalGIEntry(fish.randomizerCheck, true, GI_FISH); if (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0)) { @@ -545,28 +352,149 @@ void Fishsanity_DrawEnFish(struct Actor* actor, struct PlayState* play) { Matrix_Pop(); } -void Fishsanity_DrawFishing(struct Actor* actor, struct PlayState* play) { +/// Overridden actor draw function for the fishing pond +static void Fishsanity_DrawFishing(Actor* actor, PlayState* play) { Fishsanity_OpenGreyscaleColor(play, &fsPulseColor, (actor->params - 100) * 20); drawFishing(actor, play); Fishsanity_CloseGreyscaleColor(play); } -void Fishsanity_OpenGreyscaleColor(PlayState* play, Color_RGB8* color, int16_t frameOffset) { - OPEN_DISPS(play->state.gfxCtx); - gDPSetGrayscaleColor(POLY_OPA_DISP++, color->r, color->g, color->b, - // Make color pulse, offset a bit by the actor params - ABS(255.0f * Math_CosS((play->gameplayFrames + frameOffset) * 1000))); - gSPGrayscale(POLY_OPA_DISP++, true); - CLOSE_DISPS(play->state.gfxCtx); +/** + * @brief ActorInit hook handler for fishsanity + */ +static void OnActorInitHandler(void* refActor) { + Actor* actor = static_cast(refActor); + + CheckIdentity fish; + + if (actor->id == ACTOR_EN_FISH && GetOverworldFishShuffled()) { + // Set fish ID for ZD fish + if (gPlayState->sceneNum == SCENE_ZORAS_DOMAIN && actor->params == -1) { + actor->params ^= fishGroupCounter++; + } else if (gPlayState->sceneNum == SCENE_GROTTOS && actor->params == 1) { + actor->params = 0x100 | gSaveContext.respawn[RESPAWN_MODE_RETURN].data; + } + + fish = IdentifyFish(gPlayState->sceneNum, actor->params); + // Render fish as randomized item + if (IsFish(&fish) && !Flags_GetRandomizerInf(fish.randomizerInf)) { + if (!drawEnFish) { + drawEnFish = actor->draw; + } + actor->draw = Fishsanity_DrawEnFish; + } + return; + } + + if (actor->id == ACTOR_FISHING && gPlayState->sceneNum == SCENE_FISHING_POND && actor->params >= 100 && + actor->params <= 117 && GetPondFishShuffled()) { + // Initialize pond fish for fishsanity + fish = IdentifyFish(gPlayState->sceneNum, actor->params); + + // With every pond fish shuffled, caught fish will not spawn unless all fish have been caught. + if (RAND_GET_OPTION(RSK_FISHSANITY_POND_COUNT).Get() > 16 && !GetPondCleared()) { + // Create effect for uncaught fish + if (!Flags_GetRandomizerInf(fish.randomizerInf)) { + actor->shape.shadowDraw = Fishsanity_DrawEffShadow; + if (!drawFishing) { + drawFishing = actor->draw; + } + actor->draw = Fishsanity_DrawFishing; + } + } + } } -void Fishsanity_CloseGreyscaleColor(PlayState* play) { - OPEN_DISPS(play->state.gfxCtx); - gSPGrayscale(POLY_OPA_DISP++, false); - CLOSE_DISPS(play->state.gfxCtx); +/** + * @brief ActorUpdate hook handler for fishsanity + */ +static void OnActorUpdateHandler(void* refActor) { + if (gPlayState->sceneNum != SCENE_GROTTOS && gPlayState->sceneNum != SCENE_ZORAS_DOMAIN && + gPlayState->sceneNum != SCENE_FISHING_POND) { + return; + } + + Actor* actor = static_cast(refActor); + + // Detect fish catch + if (actor->id == ACTOR_FISHING && GetPondFishShuffled()) { + Fishing* fish = static_cast(refActor); + + // State 6 -> Fish caught and hoisted + if (fish->fishState == 6) { + CheckIdentity identity = IdentifyFish(gPlayState->sceneNum, actor->params); + if (identity.randomizerCheck != RC_UNKNOWN_CHECK) { + Flags_SetRandomizerInf(identity.randomizerInf); + enableAdvance = true; + // Remove uncaught effect + if (actor->shape.shadowDraw != NULL) { + actor->shape.shadowDraw = NULL; + actor->draw = drawFishing; + } + } + } + } + + if (actor->id == ACTOR_EN_FISH && GetOverworldFishShuffled()) { + CheckIdentity fish = IdentifyFish(gPlayState->sceneNum, actor->params); + EnFish* fishActor = static_cast(refActor); + if (IsFish(&fish) && Flags_GetRandomizerInf(fish.randomizerInf)) { + // Reset draw method + if (actor->draw == Fishsanity_DrawEnFish) { + actor->draw = drawEnFish; + } + } + + if (((actor->params >> 8) > 0) && fishActor->respawnTimer > 0) { + Actor_Kill(actor); + } + } + + // Reset fish group counter when the group gets culled + if (actor->id == ACTOR_OBJ_MURE && gPlayState->sceneNum == SCENE_ZORAS_DOMAIN && fishGroupCounter > 0 && + !(actor->flags & ACTOR_FLAG_UPDATE_CULLING_DISABLED) && GetOverworldFishShuffled()) { + fishGroupCounter = 0; + } } + +namespace Rando::Fishsanity { + +bool GetFishLocationIncluded(Rando::Location* loc, FishsanityOptionsSource optionsSource) { + auto [mode, numFish, ageSplit] = GetOptions(optionsSource); + + if (loc->GetRCType() != RCTYPE_FISH || mode == RO_FISHSANITY_OFF || mode == RO_FISHSANITY_HYRULE_LOACH) { + return false; + } + RandomizerCheck rc = loc->GetRandomizerCheck(); + // Are pond fish enabled, and is this a pond fish location? + if (mode != RO_FISHSANITY_OVERWORLD && numFish > 0 && loc->GetScene() == SCENE_FISHING_POND && + loc->GetActorID() == ACTOR_FISHING) { + // Is this a child fish location? If so, is it within the defined number of pond fish checks? + if (rc >= RC_LH_CHILD_FISH_1 && rc <= RC_LH_CHILD_LOACH_2 && numFish > (loc->GetActorParams() - 100)) { + return true; + } + // Are adult fish available, and is this an adult fish location? If so, is it within the defined number of pond + // fish checks? + if (ageSplit && rc >= RC_LH_ADULT_FISH_1 && rc <= RC_LH_ADULT_LOACH && + numFish > (loc->GetActorParams() - 100)) { + return true; + } + } + // Are overworld fish enabled, and is this an overworld fish location? + if (mode != RO_FISHSANITY_POND && (loc->GetScene() == SCENE_GROTTOS || loc->GetScene() == SCENE_ZORAS_DOMAIN) && + loc->GetActorID() == ACTOR_EN_FISH && (loc->GetActorParams() >> 8)) { + return true; + } + // Must not be an included fish location! + return false; } +void InitializeFromSave() { + UpdateCurrentPondFish(); +} + +} // namespace Rando::Fishsanity + void RegisterShuffleFish() { bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_FISHSANITY).IsNot(RO_FISHSANITY_OFF); COND_HOOK(OnSceneInit, shouldRegister, [](int16_t sceneNum) { @@ -575,19 +503,18 @@ void RegisterShuffleFish() { } }); - COND_HOOK(OnActorInit, shouldRegister, Rando::Fishsanity::OnActorInitHandler); - COND_HOOK(OnActorUpdate, shouldRegister, Rando::Fishsanity::OnActorUpdateHandler); + COND_HOOK(OnActorInit, shouldRegister, OnActorInitHandler); + COND_HOOK(OnActorUpdate, shouldRegister, OnActorUpdateHandler); COND_HOOK(OnItemReceive, shouldRegister, [](GetItemEntry itemEntry) { if (enableAdvance) { enableAdvance = false; - OTRGlobals::Instance->gRandoContext->GetFishsanity()->AdvancePond(); + UpdateCurrentPondFish(); } }); COND_VB_SHOULD(VB_BOTTLE_ACTOR, shouldRegister, { Actor* actor = va_arg(args, Actor*); - auto fs = OTRGlobals::Instance->gRandoContext->GetFishsanity(); - if (actor->id == ACTOR_EN_FISH && fs->GetOverworldFishShuffled()) { + if (actor->id == ACTOR_EN_FISH && GetOverworldFishShuffled()) { auto fish = IdentifyFish(gPlayState->sceneNum, actor->params); if (fish.randomizerCheck != RC_UNKNOWN_CHECK && !Flags_GetRandomizerInf(fish.randomizerInf)) { Flags_SetRandomizerInf(fish.randomizerInf); diff --git a/soh/soh/Enhancements/randomizer/fishsanity.h b/soh/soh/Enhancements/randomizer/fishsanity.h index ef3ea6f8f8..2a79453527 100644 --- a/soh/soh/Enhancements/randomizer/fishsanity.h +++ b/soh/soh/Enhancements/randomizer/fishsanity.h @@ -1,209 +1,26 @@ #pragma once -#include -#include "randomizerTypes.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" - -typedef struct { - u8 mode; - u8 numFish; - bool ageSplit; -} FishsanityPondOptions; +#include "soh/Enhancements/randomizer/randomizerTypes.h" +#include "soh/Enhancements/randomizer/location.h" typedef enum { FSO_SOURCE_RANDO, FSO_SOURCE_CVARS, } FishsanityOptionsSource; -typedef enum { - FSC_NONE, - FSC_POND, - FSC_GROTTO, - FSC_ZD, -} FishsanityCheckType; - -#ifdef __cplusplus -#include "soh/Enhancements/randomizer/location.h" - -namespace Rando { +namespace Rando::Fishsanity { /** - * @brief Class to provide an interface for and direct Fishsanity features + * @brief Returns true if the given fish location is active + * + * @param loc The Location to check + * @param optionsSource Optionally declare from which source to pull settings */ -class Fishsanity { - public: - Fishsanity(); - ~Fishsanity(); +bool GetFishLocationIncluded(Rando::Location* loc, FishsanityOptionsSource optionsSource = FSO_SOURCE_RANDO); - static const CheckIdentity defaultIdentity; +/** + * @brief Initializes pond fish state from save + */ +void InitializeFromSave(); - /** - * @brief Gets the type of a fishsanity check - * @param rc The RandomizerCheck to categorize - * @return The check's fishsanity type, or FSC_NONE - */ - static FishsanityCheckType GetCheckType(RandomizerCheck rc); - - /** - * @brief Returns true if the given CheckIdentity represents an actual fish - * @param fish The fish to check - */ - static bool IsFish(CheckIdentity* fish); - - /** - * @brief Returns true if the given fish location is active - * - * @param loc The Location to check - * @param optionsSource Optionally declare from which source to pull settings - */ - bool GetFishLocationIncluded(Rando::Location* loc, FishsanityOptionsSource optionsSource = FSO_SOURCE_RANDO); - - /** - * @brief Get the active and inactive locations in the fishing pond. - * - * @param optionsSource Optionally declare from which source to pull settings - * @return A pair of vectors, where the fist is all active pond fish checks, and the second is all inactive pond - * fish checks. - */ - std::pair, std::vector> - GetFishingPondLocations(FishsanityOptionsSource optionsSource = FSO_SOURCE_RANDO); - - /** - * @brief Get all active fishsanity locations, and all inactive fishing pond locations. - * - * @param optionsSource Optionally declare from which source to pull settings - * @return A pair of vectors, where the first is all active fishsanity checks, and the second is all inactive - * fishsanity checks. - */ - std::pair, std::vector> - GetFishsanityLocations(FishsanityOptionsSource optionsSource = FSO_SOURCE_RANDO); - - /** - * @brief Returns the identity for a caught pond fish given its params. - * Not for use externally from rando - * - * @param fishParams Actor parameters for the fish to identify - */ - CheckIdentity IdentifyPondFish(u8 fishParams); - - /** - * @brief Get fishsanity fishing pond options from the requested source - */ - FishsanityPondOptions GetOptions(FishsanityOptionsSource optionsSource = FSO_SOURCE_RANDO); - - /** - * @brief Updates current pond fish according to save data - */ - void UpdateCurrentPondFish(); - - /** - * @brief Initializes internal state from save - */ - void InitializeFromSave(); - - /** - * @brief Returns true if the fishing pond is shuffled - */ - bool GetPondFishShuffled(); - - /** - * @brief Returns true if overworld fish are shuffled - */ - bool GetOverworldFishShuffled(); - - /** - * @brief Returns true if the fishing pond is currently adult (i.e., age split is enabled and Link is adult) - */ - bool IsAdultPond(); - - /** - * @brief Returns true if all available pond fish checks have been collected for the current age - */ - bool GetPondCleared(); - - /** - * @brief Returns true if all available Zora's Domain fish checks have been collected - */ - bool GetDomainCleared(); - - /** - * @brief Advances current fishing pond check; no effect if every fish is shuffled - * @return The new CheckIdentity for the current pond, or default identity if every fish is shuffled - */ - CheckIdentity AdvancePond(); - - /** - * @brief ActorInit hook handler for fishsanity - */ - static void OnActorInitHandler(void* refActor); - - /** - * @brief ActorUpdate hook handler for fishsanity - */ - static void OnActorUpdateHandler(void* refActor); - - private: - /** - * @brief Initialize helper statics if they have not been initialized yet - */ - void InitializeHelpers(); - - /** - * @brief Resolves a pond fish's CheckIdentity directly from params & pond age - * - * @param params Params for Fishing actor - * @param adultPond Whether to resolve this fish as an adult check - * @return The CheckIdentity for the described fish - */ - static CheckIdentity GetPondFish(s16 params, bool adultPond); - - /** - * @brief Current pond fish when all pond fish are not randomized - */ - std::pair mCurrPondFish; - - /** - * @brief True if fishsanity helpers have been initialized - */ - static bool fishsanityHelpersInit; - - ///////////////////////////////////////////////////////// - //// Helper data structures derived from static data //// - ///////////////////////////////////////////////////////// - - /** - * @brief Mapping from pond fish check to the age where that check can be collected - */ - static std::unordered_map pondFishAgeMap; - - /** - * @brief List of child pond fish checks - */ - static std::vector childPondFish; - - /** - * @brief List of adult pond fish checks - */ - static std::vector adultPondFish; -}; -} // namespace Rando - -extern "C" { -#endif -/// Returns true if pond fish should be shuffled based on fishsanity settings. -bool Randomizer_GetPondFishShuffled(); -/// Returns true if overworld fish should be shuffled based on fishsanity settings. -bool Randomizer_GetOverworldFishShuffled(); -/// Returns true if the adult fishing pond should be used for fishsanity. -bool Randomizer_IsAdultPond(); -/// Custom shadow draw function to add effect to uncollected fish -void Fishsanity_DrawEffShadow(Actor* actor, Lights* lights, PlayState* play); -/// Overridden actor draw function for bottleable fish -void Fishsanity_DrawEnFish(struct Actor* actor, struct PlayState* play); -/// Overridden actor draw function for the fishing pond -void Fishsanity_DrawFishing(struct Actor* actor, struct PlayState* play); -void Fishsanity_OpenGreyscaleColor(PlayState* play, Color_RGB8* color, int16_t frameOffset); -void Fishsanity_CloseGreyscaleColor(PlayState* play); -#ifdef __cplusplus -} -#endif +} // namespace Rando::Fishsanity diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 7530cb0fac..15a799932e 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -5,6 +5,7 @@ #include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/Enhancements/randomizer/bean_patches.h" #include "soh/Enhancements/randomizer/dungeon.h" +#include "soh/Enhancements/randomizer/fishsanity.h" #include "soh/Enhancements/randomizer/static_data.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" @@ -2913,7 +2914,7 @@ static void RandomizerRegisterHooks() { RandomizerOnKaleidoscopeUpdateHandler); if (RAND_GET_OPTION(RSK_FISHSANITY).IsNot(RO_FISHSANITY_OFF)) { - OTRGlobals::Instance->gRandoContext->GetFishsanity()->InitializeFromSave(); + Rando::Fishsanity::InitializeFromSave(); } }); } diff --git a/soh/soh/Enhancements/randomizer/item_location.cpp b/soh/soh/Enhancements/randomizer/item_location.cpp index 5164bdff96..a5efdd7436 100644 --- a/soh/soh/Enhancements/randomizer/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/item_location.cpp @@ -1,4 +1,5 @@ #include "item_location.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "SeedContext.h" #include "logic.h" #include "rng.h" diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp index 313c8fdae6..e41c74c242 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp @@ -1,4 +1,5 @@ #include "randomizer_check_objects.h" +#include #include "static_data.h" #include "SeedContext.h" #include @@ -208,7 +209,7 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() { (location.GetRCType() != RCTYPE_RED_ICE || CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleRedIce"), RO_GENERIC_NO)) && (location.GetRCType() != RCTYPE_FISH || - ctx->GetFishsanity()->GetFishLocationIncluded(&location, FSO_SOURCE_CVARS)) && + Rando::Fishsanity::GetFishLocationIncluded(&location, FSO_SOURCE_CVARS)) && (location.GetRCType() != RCTYPE_ADULT_TRADE || CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), RO_GENERIC_NO)) && (location.GetRandomizerCheck() != RC_KF_KOKIRI_SWORD_CHEST || diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 4e2ac9fb12..e9dd89aaf4 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -12,6 +12,7 @@ #include "soh/SohGui/SohMenu.h" #include "dungeon.h" #include "entrance.h" +#include "fishsanity.h" #include "location_access.h" #include "3drando/fill.hpp" #include "soh/Enhancements/debugger/performanceTimer.h" @@ -1945,8 +1946,7 @@ bool IsCheckShuffled(RandomizerCheck rc) { (showDungeonWonderItems && RandomizerCheckObjects::AreaIsDungeon(loc->GetArea()))) && (loc->GetRCType() != RCTYPE_ICICLE || showIcicles) && (loc->GetRCType() != RCTYPE_RED_ICE || showRedIce) && - (loc->GetRCType() != RCTYPE_FISH || - OTRGlobals::Instance->gRandoContext->GetFishsanity()->GetFishLocationIncluded(loc)) && + (loc->GetRCType() != RCTYPE_FISH || Rando::Fishsanity::GetFishLocationIncluded(loc)) && (loc->GetRCType() != RCTYPE_FREESTANDING || (showOverworldFreestanding && RandomizerCheckObjects::AreaIsOverworld(loc->GetArea())) || (showDungeonFreestanding && RandomizerCheckObjects::AreaIsDungeon(loc->GetArea()))) && diff --git a/soh/soh/ResourceManagerHelpers.cpp b/soh/soh/ResourceManagerHelpers.cpp index d3463a34d0..032b396a97 100644 --- a/soh/soh/ResourceManagerHelpers.cpp +++ b/soh/soh/ResourceManagerHelpers.cpp @@ -1,4 +1,5 @@ #include "ResourceManagerHelpers.h" +#include #include "OTRGlobals.h" #include "variables.h" #include "z64.h" diff --git a/soh/soh/SohGui/SohMenuRandomizer.cpp b/soh/soh/SohGui/SohMenuRandomizer.cpp index 8bf8f5021f..eea57332be 100644 --- a/soh/soh/SohGui/SohMenuRandomizer.cpp +++ b/soh/soh/SohGui/SohMenuRandomizer.cpp @@ -1,11 +1,11 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "SohMenu.h" #include "soh/Enhancements/enhancementTypes.h" #include "soh/Enhancements/randomizer/randomizer_check_objects.h" #include "soh/Enhancements/randomizer/randomizer.h" #include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/Enhancements/randomizer/settings.h" -#include "soh/OTRGlobals.h" #include "soh/ShipUtils.h" #include "soh/SohGui/SohGui.hpp" @@ -67,7 +67,7 @@ void SaveExcludedLocations() { } void DrawLocationsMenu(WidgetInfo& info) { - auto ctx = OTRGlobals::Instance->gRandoContext; + auto ctx = Rando::Context::GetInstance(); int32_t currMQDungeonSetting = CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), 0) | CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeonCount"), 0) << 8; static ImVec2 cellPadding(8.0f, 8.0f); @@ -360,7 +360,7 @@ void UpdateMenuTricks() { } void DrawTricksMenu(WidgetInfo& info) { - auto ctx = OTRGlobals::Instance->gRandoContext; + auto ctx = Rando::Context::GetInstance(); auto randoSettings = Rando::Settings::GetInstance(); static ImVec2 cellPadding(8.0f, 8.0f); bool generating = CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0); @@ -717,7 +717,7 @@ void SohMenu::AddMenuRandomizer() { }); AddWidget(path, "Generate Randomizer", WIDGET_BUTTON) .Callback([](WidgetInfo& info) { - OTRGlobals::Instance->gRandoContext->SetSpoilerLoaded(false); + Rando::Context::GetInstance()->SetSpoilerLoaded(false); GenerateRandomizer(CVarGetInteger(CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), 0) ? seedString : ""); }) .PreFunc([](WidgetInfo& info) { diff --git a/soh/src/overlays/actors/ovl_Fishing/z_fishing.c b/soh/src/overlays/actors/ovl_Fishing/z_fishing.c index ec120805a0..b6829f2356 100644 --- a/soh/src/overlays/actors/ovl_Fishing/z_fishing.c +++ b/soh/src/overlays/actors/ovl_Fishing/z_fishing.c @@ -15,7 +15,6 @@ #define FLAGS ACTOR_FLAG_UPDATE_CULLING_DISABLED #define WATER_SURFACE_Y(play) play->colCtx.colHeader->waterBoxes->ySurface -bool getShouldSpawnLoaches(); void Fishing_Init(Actor* thisx, PlayState* play); void Fishing_Destroy(Actor* thisx, PlayState* play); @@ -432,13 +431,6 @@ static FishingEffect sFishingEffects[FISHING_EFFECT_COUNT]; static Vec3f sStreamSoundProjectedPos; static s16 sFishOnHandParams; -f32 Fishing_GetMinimumRequiredScore(); - -u8 AllHyruleLoaches() { - return CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) && - CVarGetInteger(CVAR_ENHANCEMENT("AllHyruleLoaches"), 0); -} - void Fishing_SetColliderElement(s32 index, ColliderJntSph* collider, Vec3f* pos, f32 scale) { collider->elements[index].dim.worldSphere.center.x = pos->x; collider->elements[index].dim.worldSphere.center.y = pos->y; @@ -906,17 +898,13 @@ void Fishing_Init(Actor* thisx, PlayState* play2) { if (sLinkAge == LINK_AGE_CHILD) { if ((HIGH_SCORE(HS_FISHING) & HS_FISH_LENGTH_CHILD) != 0) { sFishingRecordLength = HIGH_SCORE(HS_FISHING) & HS_FISH_LENGTH_CHILD; - } else if (CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0)) { - sFishingRecordLength = Fishing_GetMinimumRequiredScore(); - } else { + } else if (GameInteractor_Should(VB_FISHING_USE_DEFAULT_RECORD_LENGTH, true, &sFishingRecordLength)) { sFishingRecordLength = 40.0f; // 6 lbs } } else { if ((HIGH_SCORE(HS_FISHING) & HS_FISH_LENGTH_ADULT) != 0) { sFishingRecordLength = (HIGH_SCORE(HS_FISHING) & HS_FISH_LENGTH_ADULT) >> 0x18; - } else if (CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0)) { - sFishingRecordLength = Fishing_GetMinimumRequiredScore(); - } else { + } else if (GameInteractor_Should(VB_FISHING_USE_DEFAULT_RECORD_LENGTH, true, &sFishingRecordLength)) { sFishingRecordLength = 45.0f; // 7 lbs } } @@ -991,8 +979,8 @@ void Fishing_Init(Actor* thisx, PlayState* play2) { ENKANBAN_FISHING); Actor_Spawn(&play->actorCtx, play, ACTOR_FISHING, 0.0f, 0.0f, 0.0f, 0, 0, 0, 200); - // Loach(es) will spawn every fourth game, or if "Loaches Always Appear" is enabled - if (getShouldSpawnLoaches()) { + // Loach(es) will spawn every fourth game + if (GameInteractor_Should(VB_FISHING_SPAWN_LOACHES, (KREG(1) == 1) || ((sFishGameNumber & 3) == 3))) { // Fishes 16 and 17 are loaches. Only 16 is spawned as adult; child also spawns 17. if (sLinkAge != LINK_AGE_CHILD) { fishCount = 16; @@ -1008,7 +996,8 @@ void Fishing_Init(Actor* thisx, PlayState* play2) { sFishInits[i].pos.z, 0, Rand_ZeroFloat(0x10000), 0, 100 + i); } } else { - if ((thisx->params < (EN_FISH_PARAM + 15) && !AllHyruleLoaches()) || (thisx->params == EN_FISH_AQUARIUM)) { + if (!GameInteractor_Should(VB_FISHING_FISH_IS_LOACH, thisx->params >= (EN_FISH_PARAM + 15)) || + (thisx->params == EN_FISH_AQUARIUM)) { SkelAnime_InitFlex(play, &this->skelAnime, &gFishingFishSkel, &gFishingFishAnim, NULL, NULL, 0); Animation_MorphToLoop(&this->skelAnime, &gFishingFishAnim, 0.0f); } else { @@ -1028,7 +1017,8 @@ void Fishing_Init(Actor* thisx, PlayState* play2) { this->fishState = 10; this->fishStateNext = 10; - this->isLoach = sFishInits[thisx->params - EN_FISH_PARAM].isLoach || AllHyruleLoaches(); + this->isLoach = + GameInteractor_Should(VB_FISHING_FISH_IS_LOACH, sFishInits[thisx->params - EN_FISH_PARAM].isLoach); this->perception = sFishInits[thisx->params - EN_FISH_PARAM].perception; this->fishLength = sFishInits[thisx->params - EN_FISH_PARAM].baseLength; @@ -2910,49 +2900,6 @@ void Fishing_HandleAquariumDialog(Fishing* this, PlayState* play) { } } -f32 Fishing_GetMinimumRequiredScore() { - int32_t weight; - // RANDOTODO: update the enhancement sliders to not allow - // values above rando fish weight values when rando'd - if (sLinkAge == 1) { - weight = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) - ? CVarGetInteger(CVAR_ENHANCEMENT("MinimumFishWeightChild"), 10) - : 10; - } else { - weight = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) - ? CVarGetInteger(CVAR_ENHANCEMENT("MinimumFishWeightAdult"), 13) - : 13; - } - - return sqrt(((f32)weight - 0.5f) / 0.0036f); -} - -bool getInstantFish() { - return CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) && - CVarGetInteger(CVAR_ENHANCEMENT("InstantFishing"), 0); -} - -bool getGuaranteeBite() { - return CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) && - CVarGetInteger(CVAR_ENHANCEMENT("GuaranteeFishingBite"), 0); -} - -bool getFishNeverEscape() { - return CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) && - CVarGetInteger(CVAR_ENHANCEMENT("FishNeverEscape"), 0); -} - -bool getShouldSpawnLoaches() { - return (CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) && - CVarGetInteger(CVAR_ENHANCEMENT("LoachesAlwaysAppear"), 0)) || - ((KREG(1) == 1) || ((sFishGameNumber & 3) == 3)); -} - -bool getShouldConfirmKeep() { - return !CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) || - !CVarGetInteger(CVAR_ENHANCEMENT("SkipKeepConfirmation"), 0); -} - void Fishing_UpdateFish(Actor* thisx, PlayState* play2) { s16 i; s16 rotXYScale = 10; @@ -3451,9 +3398,9 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) { if (sLureEquipped == FS_LURE_SINKING) { chance *= 5.0f; } - if (getGuaranteeBite() == 1 || - ((this->timerArray[0] == 1) || (Rand_ZeroOne() < chance)) && - ((Rand_ZeroOne() < (this->perception * multiplier)) || ((this->isLoach + 1) == KREG(69)))) { + if (GameInteractor_Should(VB_FISHING_FISH_BITE, ((this->timerArray[0] == 1) || (Rand_ZeroOne() < chance)) && + ((Rand_ZeroOne() < (this->perception * multiplier)) || + ((this->isLoach + 1) == KREG(69))))) { if (this->isLoach == 0) { this->fishState = 3; this->unk_190 = 1.2f; @@ -3866,8 +3813,9 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) { if ((sRodCastState < 3) || ((sReelLock != 0) && (sFishFightTime > 50)) || (sFishFightTime >= 6000) || ((sLureBitTimer == 0) && (sLineHooked == 0)) || (sRodPullback == 0) || - (((sLureTimer & 0x7F) == 0) && (Rand_ZeroOne() < 0.05f) && (sLureEquipped != FS_LURE_SINKING) && - (KREG(69) == 0) && (getFishNeverEscape() == 0))) { + GameInteractor_Should(VB_FISHING_FISH_ESCAPE, ((sLureTimer & 0x7F) == 0) && (Rand_ZeroOne() < 0.05f) && + (sLureEquipped != FS_LURE_SINKING) && + (KREG(69) == 0))) { sFishingCaughtTextDelay = 20; if ((sLureBitTimer == 0) && (sLineHooked == 0)) { @@ -3897,7 +3845,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) { sFishingMusicDelay = 50; sRodReelingSpeed = 0.5f; this->unk_152 = 0; - } else if (this->actor.xzDistToPlayer < (KREG(59) + 50.0f) || getInstantFish() == 1) { + } else if (GameInteractor_Should(VB_FISHING_CATCH_FISH, this->actor.xzDistToPlayer < (KREG(59) + 50.0f))) { this->fishState = 6; this->timerArray[0] = 100; player->unk_860 = 3; @@ -3976,7 +3924,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) { multiVecSrc.y = -10.0f; multiVecSrc.z = 5.0f; Matrix_MultVec3f(&multiVecSrc, &targetPosOffset); - if (getInstantFish() == 0) { + if (!GameInteractor_Should(VB_FISHING_INSTANT_CATCH, false)) { Math_ApproachF(&this->actor.world.pos.x, player->bodyPartsPos[15].x + targetPosOffset.x, 1.0f, 6.0f); Math_ApproachF(&this->actor.world.pos.y, player->bodyPartsPos[15].y + targetPosOffset.y, 1.0f, 6.0f); Math_ApproachF(&this->actor.world.pos.z, player->bodyPartsPos[15].z + targetPosOffset.z, 1.0f, 6.0f); @@ -4000,9 +3948,10 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) { sFishOnHandIsLoach = this->isLoach; sLureCaughtWith = sLureEquipped; Actor_Kill(&this->actor); - } else if (getShouldConfirmKeep() && (this->isLoach == 0) && - (sFishOnHandIsLoach == 0) && - ((s16)this->fishLength < (s16)sFishOnHandLength)) { + } else if (GameInteractor_Should( + VB_FISHING_CONFIRM_KEEPING_SMALLER_FISH, + (this->isLoach == 0) && (sFishOnHandIsLoach == 0) && + ((s16)this->fishLength < (s16)sFishOnHandLength))) { this->keepState = 1; this->timerArray[0] = 0x3C; Message_StartTextbox(play, 0x4098, NULL); @@ -5548,7 +5497,7 @@ void Fishing_UpdateOwner(Actor* thisx, PlayState* play2) { player->actor.speedXZ = 0.0f; // #region SOH [Enhancement] - if (CVarGetInteger(CVAR_ENHANCEMENT("QuitFishingAtDoor"), 0)) { + if (GameInteractor_Should(VB_FISHING_QUIT_AT_DOOR, false)) { Fishing_QuitAtDoor(this, play); } // #endregion diff --git a/soh/src/overlays/actors/ovl_Fishing/z_fishing.h b/soh/src/overlays/actors/ovl_Fishing/z_fishing.h index 5a937b08c0..5f9606ea31 100644 --- a/soh/src/overlays/actors/ovl_Fishing/z_fishing.h +++ b/soh/src/overlays/actors/ovl_Fishing/z_fishing.h @@ -3,7 +3,6 @@ #include #include "global.h" -#include "soh/Enhancements/randomizer/fishsanity.h" struct Fishing;