From 806398a65b04c994d6472eb482e0de400d48cc72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= <159546+serprex@users.noreply.github.com> Date: Thu, 23 Apr 2026 12:34:26 +0000 Subject: [PATCH] Fix OGC great fairy reward in vanilla with skip misc interactions when fish is not obtainable (#6556) Item_CheckObtainability should only be called with MOD_NONE GI For RG_DOUBLE_DEFENSE that became ITEM_FISH. Nonsense ensued To reproduce issue, create debug save & go straight to OGC great fairy with only magic/ocarina/lullaby --- soh/soh/Enhancements/randomizer/item.h | 1 - .../Enhancements/timesaver_hook_handlers.cpp | 62 +++++++++---------- soh/src/code/z_actor.c | 15 +++-- soh/src/code/z_player_lib.c | 1 - .../actors/ovl_player_actor/z_player.c | 9 +-- 5 files changed, 43 insertions(+), 45 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/item.h b/soh/soh/Enhancements/randomizer/item.h index ab4b3c1194..f484159102 100644 --- a/soh/soh/Enhancements/randomizer/item.h +++ b/soh/soh/Enhancements/randomizer/item.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include "3drando/text.hpp" diff --git a/soh/soh/Enhancements/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/timesaver_hook_handlers.cpp index b609224349..204de040fa 100644 --- a/soh/soh/Enhancements/timesaver_hook_handlers.cpp +++ b/soh/soh/Enhancements/timesaver_hook_handlers.cpp @@ -24,7 +24,6 @@ extern "C" { #include "src/overlays/actors/ovl_En_Jj/z_en_jj.h" #include "src/overlays/actors/ovl_En_Daiku/z_en_daiku.h" #include "src/overlays/actors/ovl_Bg_Spot02_Objects/z_bg_spot02_objects.h" -#include "src/overlays/actors/ovl_Bg_Spot06_Objects/z_bg_spot06_objects.h" #include "src/overlays/actors/ovl_Bg_Spot03_Taki/z_bg_spot03_taki.h" #include "src/overlays/actors/ovl_Bg_Hidan_Kousi/z_bg_hidan_kousi.h" #include "src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.h" @@ -1241,41 +1240,41 @@ void TimeSaverOnFlagSetHandler(int16_t flagType, int16_t flag) { case FLAG_EVENT_CHECK_INF: switch (flag) { case EVENTCHKINF_SPOKE_TO_SARIA_ON_BRIDGE: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_FAIRY_OCARINA).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_FAIRY_OCARINA); break; case EVENTCHKINF_OBTAINED_KOKIRI_EMERALD_DEKU_TREE_DEAD: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_KOKIRI_EMERALD).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_KOKIRI_EMERALD); break; case EVENTCHKINF_USED_DODONGOS_CAVERN_BLUE_WARP: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_GORON_RUBY).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_GORON_RUBY); break; case EVENTCHKINF_USED_JABU_JABUS_BELLY_BLUE_WARP: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_ZORA_SAPPHIRE).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_ZORA_SAPPHIRE); break; case EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_FOREST_MEDALLION).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_FOREST_MEDALLION); break; case EVENTCHKINF_USED_FIRE_TEMPLE_BLUE_WARP: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_FIRE_MEDALLION).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_FIRE_MEDALLION); break; case EVENTCHKINF_USED_WATER_TEMPLE_BLUE_WARP: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_WATER_MEDALLION).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_WATER_MEDALLION); break; case EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_LIGHT_ARROWS).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_LIGHT_ARROWS); break; case EVENTCHKINF_TIME_TRAVELED_TO_ADULT: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_LIGHT_MEDALLION).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_LIGHT_MEDALLION); break; } break; case FLAG_RANDOMIZER_INF: switch (flag) { case RAND_INF_DUNGEONS_DONE_SHADOW_TEMPLE: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_SHADOW_MEDALLION).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_SHADOW_MEDALLION); break; case RAND_INF_DUNGEONS_DONE_SPIRIT_TEMPLE: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_SPIRIT_MEDALLION).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_SPIRIT_MEDALLION); break; } break; @@ -1287,22 +1286,22 @@ void TimeSaverOnFlagSetHandler(int16_t flagType, int16_t flag) { case FLAG_RANDOMIZER_INF: switch (flag) { case RAND_INF_ZF_GREAT_FAIRY_REWARD: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_FARORES_WIND).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_FARORES_WIND); break; case RAND_INF_HC_GREAT_FAIRY_REWARD: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_DINS_FIRE).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_DINS_FIRE); break; case RAND_INF_COLOSSUS_GREAT_FAIRY_REWARD: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_NAYRUS_LOVE).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_NAYRUS_LOVE); break; case RAND_INF_DMT_GREAT_FAIRY_REWARD: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_MAGIC_SINGLE).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_MAGIC_SINGLE); break; case RAND_INF_DMC_GREAT_FAIRY_REWARD: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_MAGIC_DOUBLE).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_MAGIC_DOUBLE); break; case RAND_INF_OGC_GREAT_FAIRY_REWARD: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_DOUBLE_DEFENSE).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_DOUBLE_DEFENSE); break; } break; @@ -1328,47 +1327,44 @@ void TimeSaverOnFlagSetHandler(int16_t flagType, int16_t flag) { case FLAG_EVENT_CHECK_INF: switch (flag) { case EVENTCHKINF_LEARNED_ZELDAS_LULLABY: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_ZELDAS_LULLABY).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_ZELDAS_LULLABY); break; case EVENTCHKINF_LEARNED_MINUET_OF_FOREST: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_MINUET_OF_FOREST).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_MINUET_OF_FOREST); break; case EVENTCHKINF_LEARNED_BOLERO_OF_FIRE: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_BOLERO_OF_FIRE).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_BOLERO_OF_FIRE); break; case EVENTCHKINF_LEARNED_SERENADE_OF_WATER: - vanillaQueuedItemEntry = - Rando::StaticData::RetrieveItem(RG_SERENADE_OF_WATER).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_SERENADE_OF_WATER); break; case EVENTCHKINF_LEARNED_REQUIEM_OF_SPIRIT: - vanillaQueuedItemEntry = - Rando::StaticData::RetrieveItem(RG_REQUIEM_OF_SPIRIT).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_REQUIEM_OF_SPIRIT); break; case EVENTCHKINF_BONGO_BONGO_ESCAPED_FROM_WELL: - vanillaQueuedItemEntry = - Rando::StaticData::RetrieveItem(RG_NOCTURNE_OF_SHADOW).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_NOCTURNE_OF_SHADOW); break; case EVENTCHKINF_LEARNED_PRELUDE_OF_LIGHT: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_PRELUDE_OF_LIGHT).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_PRELUDE_OF_LIGHT); break; case EVENTCHKINF_LEARNED_SARIAS_SONG: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_SARIAS_SONG).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_SARIAS_SONG); break; case EVENTCHKINF_LEARNED_SONG_OF_TIME: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_SONG_OF_TIME).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_SONG_OF_TIME); break; case EVENTCHKINF_LEARNED_SONG_OF_STORMS: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_SONG_OF_STORMS).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_SONG_OF_STORMS); break; case EVENTCHKINF_LEARNED_SUNS_SONG: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_SUNS_SONG).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_SUNS_SONG); break; } break; case FLAG_RANDOMIZER_INF: switch (flag) { case RAND_INF_LEARNED_EPONA_SONG: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_EPONAS_SONG).GetGIEntry_Copy(); + TimeSaverQueueItem(RG_EPONAS_SONG); break; } break; diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 54c33e2cfa..f69a7ea8cc 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -2032,8 +2032,10 @@ s32 GiveItemEntryWithoutActor(PlayState* play, GetItemEntry getItemEntry) { PLAYER_STATE1_CLIMBING_LEDGE | PLAYER_STATE1_JUMPING | PLAYER_STATE1_FREEFALL | PLAYER_STATE1_FIRST_PERSON | PLAYER_STATE1_CLIMBING_LADDER)) && Player_GetExplosiveHeld(player) < 0) { - if (((player->heldActor != NULL) && ((getItemEntry.getItemId > GI_NONE) && (getItemEntry.getItemId < GI_MAX)) || - (IS_RANDO && (getItemEntry.getItemId > RG_NONE) && (getItemEntry.getItemId < RG_MAX))) || + if (((player->heldActor != NULL && (getItemEntry.modIndex == MOD_NONE && getItemEntry.getItemId > GI_NONE && + getItemEntry.getItemId < GI_MAX)) || + (getItemEntry.modIndex == MOD_RANDOMIZER && getItemEntry.getItemId > RG_NONE && + getItemEntry.getItemId < RG_MAX)) || (!(player->stateFlags1 & (PLAYER_STATE1_CARRYING_ACTOR | PLAYER_STATE1_IN_CUTSCENE)))) { if ((getItemEntry.getItemId != GI_NONE)) { player->getItemEntry = getItemEntry; @@ -2073,8 +2075,10 @@ s32 GiveItemEntryFromActor(Actor* actor, PlayState* play, GetItemEntry getItemEn PLAYER_STATE1_CLIMBING_LADDER)) && Player_GetExplosiveHeld(player) < 0) { if ((((player->heldActor != NULL) || (actor == player->talkActor)) && - ((!IS_RANDO && ((getItemEntry.getItemId > GI_NONE) && (getItemEntry.getItemId < GI_MAX))) || - (IS_RANDO && ((getItemEntry.getItemId > RG_NONE) && (getItemEntry.getItemId < RG_MAX))))) || + ((getItemEntry.getItemId == MOD_NONE && + ((getItemEntry.getItemId > GI_NONE) && (getItemEntry.getItemId < GI_MAX))) || + (getItemEntry.getItemId == MOD_RANDOMIZER && + ((getItemEntry.getItemId > RG_NONE) && (getItemEntry.getItemId < RG_MAX))))) || (!(player->stateFlags1 & (PLAYER_STATE1_CARRYING_ACTOR | PLAYER_STATE1_IN_CUTSCENE)))) { if ((actor->xzDistToPlayer < xzRange) && (fabsf(actor->yDistToPlayer) < yRange)) { s16 yawDiff = actor->yawTowardsPlayer - player->actor.shape.rot.y; @@ -2118,8 +2122,7 @@ s32 Actor_OfferGetItem(Actor* actor, PlayState* play, s32 getItemId, f32 xzRange PLAYER_STATE1_CLIMBING_LADDER)) && Player_GetExplosiveHeld(player) < 0) { if ((((player->heldActor != NULL) || (actor == player->talkActor)) && - ((!IS_RANDO && ((getItemId > GI_NONE) && (getItemId < GI_MAX))) || - (IS_RANDO && ((getItemId > RG_NONE) && (getItemId < RG_MAX))))) || + ((getItemId > GI_NONE) && (getItemId < GI_MAX))) || (!(player->stateFlags1 & (PLAYER_STATE1_CARRYING_ACTOR | PLAYER_STATE1_IN_CUTSCENE)))) { if ((actor->xzDistToPlayer < xzRange) && (fabsf(actor->yDistToPlayer) < yRange)) { s16 yawDiff = actor->yawTowardsPlayer - player->actor.shape.rot.y; diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index 83dfd7608c..79bf0bfb6b 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -3,7 +3,6 @@ #include "objects/gameplay_field_keep/gameplay_field_keep.h" #include "objects/object_link_boy/object_link_boy.h" #include "objects/object_link_child/object_link_child.h" -#include "objects/object_triforce_spot/object_triforce_spot.h" #include "overlays/actors/ovl_Demo_Effect/z_demo_effect.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 5aa9d94704..804292a786 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -7339,8 +7339,9 @@ s32 Player_ActionHandler_2(Player* this, PlayState* play) { // getting bombchus need to show the cutscene) and whenever the player doesn't have the item yet. In // rando, we're overruling this because we need to keep showing the cutscene because those items can be // randomized and thus it's important to keep showing the cutscene. - uint8_t showItemCutscene = play->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY || - Item_CheckObtainability(giEntry.itemId) == ITEM_NONE || IS_RANDO; + uint8_t showItemCutscene = play->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY || IS_RANDO || + giEntry.modIndex == MOD_RANDOMIZER || + Item_CheckObtainability(giEntry.itemId) == ITEM_NONE; // Only skip cutscenes for drops when they're items/consumables from bushes/rocks/enemies. uint8_t isDropToSkip = @@ -7359,8 +7360,8 @@ s32 Player_ActionHandler_2(Player* this, PlayState* play) { // the player already has because those items could be a randomized item coming from scrubs, // freestanding PoH's and keys. So we need to once again overrule this specifically for items coming // from bushes/rocks/enemies when the player has already picked that item up. - uint8_t skipItemCutsceneRando = - IS_RANDO && Item_CheckObtainability(giEntry.itemId) != ITEM_NONE && isDropToSkip; + uint8_t skipItemCutsceneRando = IS_RANDO && giEntry.modIndex == MOD_NONE && + Item_CheckObtainability(giEntry.itemId) != ITEM_NONE && isDropToSkip; // Show cutscene when picking up a item. if (showItemCutscene && !skipItemCutscene && !skipItemCutsceneRando) {