diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h index 3ac408e78ef..78fe45df8c0 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h @@ -47,6 +47,11 @@ DEFINE_HOOK(OnVanillaBehavior, (GIVanillaBehavior flag, bool* result, va_list or DEFINE_HOOK(OnSaveFile, (int32_t fileNum)); DEFINE_HOOK(OnLoadFile, (int32_t fileNum)); DEFINE_HOOK(OnDeleteFile, (int32_t fileNum)); +DEFINE_HOOK(OnLinkAnimEnd, (SkelAnime * skelAnime)); +DEFINE_HOOK(OnQPADamage, (uint32_t * dmgFlags)); +DEFINE_HOOK(OnESS, ()); +DEFINE_HOOK(OnWaitForPutaway, ()); +DEFINE_HOOK(OnAnimationSetLoadFrame, (LinkAnimationHeader * animation, int32_t* frame)); DEFINE_HOOK(OnDialogMessage, ()); DEFINE_HOOK(OnPresentTitleCard, ()); @@ -74,3 +79,4 @@ DEFINE_HOOK(OnSetGameLanguage, ()); DEFINE_HOOK(OnFileDropped, (std::string filePath)); DEFINE_HOOK(OnAssetAltChange, ()); DEFINE_HOOK(OnKaleidoUpdate, ()); +DEFINE_HOOK(OnKaleidoMoveCursorFromSpecialPos, (PauseContext * pauseCtx, uint16_t* cursorItem)); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp index f69cc29af53..18872ee7d11 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -97,6 +97,26 @@ void GameInteractor_ExecuteOnCuccoOrChickenHatch() { GameInteractor::Instance->ExecuteHooks(); } +void GameInteractor_ExecuteOnLinkAnimEnd(SkelAnime* skelAnime) { + GameInteractor::Instance->ExecuteHooks(skelAnime); +} + +void GameInteractor_ExecuteOnQPADamage(uint32_t* dmgFlags) { + GameInteractor::Instance->ExecuteHooks(dmgFlags); +} + +void GameInteractor_ExecuteOnESS() { + GameInteractor::Instance->ExecuteHooks(); +} + +void GameInteractor_ExecuteOnWaitForPutaway() { + GameInteractor::Instance->ExecuteHooks(); +} + +void GameInteractor_ExecuteOnAnimationSetLoadFrame(LinkAnimationHeader* animation, int32_t* frame) { + GameInteractor::Instance->ExecuteHooks(animation, frame); +} + void GameInteractor_ExecuteOnShopSlotChangeHooks(uint8_t cursorIndex, int16_t price) { GameInteractor::Instance->ExecuteHooks(cursorIndex, price); } @@ -323,3 +343,7 @@ void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void)) { void GameInteractor_ExecuteOnKaleidoUpdate() { GameInteractor::Instance->ExecuteHooks(); } + +void GameInteractor_ExecuteOnKaleidoMoveCursorFromSpecialPos(PauseContext* pauseCtx, uint16_t* cursorItem) { + GameInteractor::Instance->ExecuteHooks(pauseCtx, cursorItem); +} diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h index a6f1563f23e..d64d0a7fc9c 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -28,6 +28,11 @@ void GameInteractor_ExecuteOnPlayerUpdate(); void GameInteractor_ExecuteOnSetDoAction(uint16_t action); void GameInteractor_ExecuteOnOcarinaSongAction(); void GameInteractor_ExecuteOnCuccoOrChickenHatch(); +void GameInteractor_ExecuteOnLinkAnimEnd(SkelAnime* skelAnime); +void GameInteractor_ExecuteOnQPADamage(uint32_t* dmgFlags); +void GameInteractor_ExecuteOnESS(); +void GameInteractor_ExecuteOnWaitForPutaway(); +void GameInteractor_ExecuteOnAnimationSetLoadFrame(LinkAnimationHeader* animation, int32_t* frame); void GameInteractor_ExecuteOnActorInit(void* actor); void GameInteractor_ExecuteOnActorSpawn(void* actor); void GameInteractor_ExecuteOnActorUpdate(void* actor); @@ -84,6 +89,7 @@ void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void)); // Mark: - Pause Menu void GameInteractor_ExecuteOnKaleidoUpdate(); +void GameInteractor_ExecuteOnKaleidoMoveCursorFromSpecialPos(PauseContext* pauseCtx, uint16_t* cursorItem); #ifdef __cplusplus } diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 7e517155b07..4a965cd6e9b 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -2253,6 +2253,22 @@ typedef enum { // #### `args` // - `*DoorShutter` VB_BE_NEAR_DOOR_SHUTTER, + + // #### `result` + // ```c + // false + // ``` + // #### `args` + // - None + VB_SKIP_FORCE_PLAY_OCARINA, + + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - None + VB_HOVER_WITH_ISG, } GIVanillaBehavior; #endif diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp index c74c0ff23b9..11bfcb99c8b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp @@ -2132,6 +2132,80 @@ void StaticData::HintTable_Init_Item() { CustomMessage("a four legged friend", /*german*/"ein vierbeiniger Freund", /*french*/"un puissant animal")}); // /*spanish*/una amiga cuadrúpeda + hintTextTable[RHT_ABILITY_ISG] = HintText(CustomMessage("ISG", /*german*/"ISG", /*french*/"ISG"), + // /*spanish*/ISG + { + CustomMessage("a flashy weapon", /*german*/"ISG", /*french*/"ISG") + // /*spanish*/ISG + }, { + CustomMessage("a permanent hitbox", /*german*/"ISG", /*french*/"ISG")}); + // /*spanish*/ISG + + hintTextTable[RHT_ABILITY_OI] = HintText(CustomMessage("OI", /*german*/"OI", /*french*/"OI"), + // /*spanish*/OI + { + CustomMessage("a musical bottle", /*german*/"OI", /*french*/"OI") + // /*spanish*/OI + }, { + CustomMessage("a potato of any color", /*german*/"OI", /*french*/"OI")}); + // /*spanish*/OI + hintTextTable[RHT_ABILITY_QPA] = HintText(CustomMessage("QPA", /*german*/"QPA", /*french*/"QPA"), + // /*spanish*/QPA + { + CustomMessage("some funky damage", /*german*/"QPA", /*french*/"QPA") + // /*spanish*/QPA + }, { + CustomMessage("some fast hands", /*german*/"QPA", /*french*/"QPA")}); + // /*spanish*/QPA + hintTextTable[RHT_ABILITY_HESS] = HintText(CustomMessage("Extended Superslide", /*german*/"Extended Superslide", /*french*/"Extended Superslide"), + // /*spanish*/Extended Superslide + { + CustomMessage("some explosive speed", /*german*/"Extended Superslide", /*french*/"Extended Superslide") + // /*spanish*/Extended Superslide + }, { + CustomMessage("some slick feet", /*german*/"Extended Superslide", /*french*/"Extended Superslide")}); + // /*spanish*/Extended Superslide + hintTextTable[RHT_ABILITY_SUPERSLIDE] = HintText(CustomMessage("Superslide", /*german*/"Superslide", /*french*/"Superslide"), + // /*spanish*/Superslide + { + CustomMessage("some straight line speed", /*german*/"Superslide", /*french*/"Superslide") + // /*spanish*/Superslide + }, { + CustomMessage("some shield power", /*german*/"Superslide", /*french*/"Superslide")}); + // /*spanish*/Superslide + hintTextTable[RHT_ABILITY_HOVER] = HintText(CustomMessage("Hovering", /*german*/"Hovering", /*french*/"Hovering"), + // /*spanish*/Hovering + { + CustomMessage("a weightless trick", /*german*/"Hovering", /*french*/"Hovering") + // /*spanish*/Hovering + }, { + CustomMessage("gravityn't", /*german*/"Hovering", /*french*/"Hovering")}); + // /*spanish*/Hovering + hintTextTable[RHT_ABILITY_EQUIP_SWAP] = HintText(CustomMessage("Equip Swap", /*german*/"Equip Swap", /*french*/"Equip Swap"), + // /*spanish*/Equip Swap + { + CustomMessage("an unbufferable ability", /*german*/"Equip Swap", /*french*/"Equip Swap") + // /*spanish*/Equip Swap + }, { + CustomMessage("a timeless talent", /*german*/"Equip Swap", /*french*/"Equip Swap")}); + // /*spanish*/Equip Swap + hintTextTable[RHT_ABILITY_GROUND_JUMP] = HintText(CustomMessage("Ground Jump", /*german*/"Ground Jump", /*french*/"Ground Jump"), + // /*spanish*/Ground Jump + { + CustomMessage("a little leap", /*german*/"Ground Jump", /*french*/"Ground Jump") + // /*spanish*/Ground Jump + }, { + CustomMessage("a beginner's trick", /*german*/"Ground Jump", /*french*/"Ground Jump")}); + // /*spanish*/Ground Jump + hintTextTable[RHT_ABILITY_WEIRDSHOT] = HintText(CustomMessage("Weirdshot", /*german*/"Weirdshot", /*french*/"Weirdshot"), + // /*spanish*/Weirdshot + { + CustomMessage("a weird shot", /*german*/"Weirdshot", /*french*/"Weirdshot") + // /*spanish*/Weirdshot + }, { + CustomMessage("a mangled animation", /*german*/"Weirdshot", /*french*/"Weirdshot")}); + // /*spanish*/Weirdshot + //What is this used for? hintTextTable[RHT_HINT_MYSTERIOUS] = HintText(CustomMessage("something mysterious", /*german*/"etwas Mysteriöses", /*french*/"un sacré mystère")); // /*spanish*/algo misterioso diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index 28f05010eac..8011f0d34fa 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -591,6 +591,34 @@ void GenerateItemPool() { AddItemToMainPool(RG_PROGRESSIVE_SCALE); } + if (ctx->GetOption(RSK_SHUFFLE_ISG)) { + AddItemToMainPool(RG_ABILITY_ISG); + } + if (ctx->GetOption(RSK_SHUFFLE_OI)) { + AddItemToMainPool(RG_ABILITY_OI); + } + if (ctx->GetOption(RSK_SHUFFLE_QPA)) { + AddItemToMainPool(RG_ABILITY_QPA); + } + if (ctx->GetOption(RSK_SHUFFLE_HESS)) { + AddItemToMainPool(RG_ABILITY_HESS); + } + if (ctx->GetOption(RSK_SHUFFLE_SUPERSLIDE)) { + AddItemToMainPool(RG_ABILITY_SUPERSLIDE); + } + if (ctx->GetOption(RSK_SHUFFLE_HOVER)) { + AddItemToMainPool(RG_ABILITY_HOVER); + } + if (ctx->GetOption(RSK_SHUFFLE_EQUIP_SWAP)) { + AddItemToMainPool(RG_ABILITY_EQUIP_SWAP); + } + if (ctx->GetOption(RSK_SHUFFLE_GROUND_JUMP)) { + AddItemToMainPool(RG_ABILITY_GROUND_JUMP); + } + if (ctx->GetOption(RSK_SHUFFLE_WEIRDSHOT)) { + AddItemToMainPool(RG_ABILITY_WEIRDSHOT); + } + if (ctx->GetOption(RSK_SHUFFLE_BEEHIVES)) { // 32 total beehive locations AddItemToPool(PendingJunkPool, RG_RED_RUPEE, 23); diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index fa3aa4019cb..c5f442f9408 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -69,6 +69,12 @@ extern void EnGe1_Wait_Archery(EnGe1* enGe1, PlayState* play); extern void EnGe1_SetAnimationIdle(EnGe1* enGe1); extern void EnGe1_SetAnimationIdle(EnGe1* enGe1); extern void EnGe2_SetupCapturePlayer(EnGe2* enGe2, PlayState* play); +extern void func_80832318(Player* player); +extern void Player_SetupActionPreserveItemAction(PlayState* play, Player* player, PlayerActionFunc actionFunc, + s32 flags); +extern void Player_Action_Idle(Player* player, PlayState* play); +extern s32 Player_DecelerateToZero(Player* player); +extern s32 func_80834BD4(Player* player, PlayState* play); } bool LocMatchesQuest(Rando::Location loc) { @@ -2323,6 +2329,15 @@ void RandomizerOnPlayerUpdateHandler() { GameInteractor::State::TriforceHuntPieceGiven = 0; } } + + if (!Flags_GetRandomizerInf(RAND_INF_CAN_GROUND_JUMP)) { + if (GET_PLAYER(gPlayState)->stateFlags1 & PLAYER_STATE1_CARRYING_ACTOR && + GET_PLAYER(gPlayState)->stateFlags1 & PLAYER_STATE1_SHIELDING) { + if (GET_PLAYER(gPlayState)->upperActionFunc == func_80834BD4 && GET_PLAYER(gPlayState)->heldActor == NULL) { + GET_PLAYER(gPlayState)->stateFlags1 &= ~PLAYER_STATE1_CARRYING_ACTOR; + } + } + } } void RandomizerOnSceneSpawnActorsHandler() { @@ -2384,6 +2399,83 @@ void RandomizerOnCuccoOrChickenHatch() { } } +void RandomizerOnLinkAnimEnd(SkelAnime* skelAnime) { + if (!Flags_GetRandomizerInf(RAND_INF_CAN_ISG)) { + Player* player = GET_PLAYER(gPlayState); + + // Make sure we are only checking for the end of link's animation + // TODO: Use gPlayerAnim_link_normal_defense_kiru? + if (skelAnime == &player->skelAnime && player->meleeWeaponAnimation == PLAYER_MWA_STAB_1H) { + func_80832318(player); + } + } +} + +void RandomizerShouldSkipForcePlayOcarina(bool* should) { + + if (!Flags_GetRandomizerInf(RAND_INF_CAN_OI)) { + Player* player = GET_PLAYER(gPlayState); + + if (player->itemAction != PLAYER_IA_OCARINA_FAIRY && player->itemAction != PLAYER_IA_OCARINA_OF_TIME) { + player->unk_6AD = 0; + Sfx_PlaySfxCentered(NA_SE_SY_ERROR); + Player_SetupActionPreserveItemAction(gPlayState, player, Player_Action_Idle, 0); + player->stateFlags1 &= ~PLAYER_STATE1_IN_CUTSCENE; + *should = true; + } + } +} + +void RandomizerOnQPADamage(uint32_t* dmgFlags) { + if (!Flags_GetRandomizerInf(RAND_INF_CAN_QPA)) { + *dmgFlags = 0; + } +} + +void RandomizerOnESS() { + if (!Flags_GetRandomizerInf(RAND_INF_CAN_HESS)) { + Player_DecelerateToZero(GET_PLAYER(gPlayState)); + } +} + +void RandomizerOnWaitForPutaway() { + if (!Flags_GetRandomizerInf(RAND_INF_CAN_SUPERSLIDE)) { + Player_DecelerateToZero(GET_PLAYER(gPlayState)); + } +} + +void RandomizerShouldHover(bool* should) { + if (!Flags_GetRandomizerInf(RAND_INF_CAN_HOVER)) { + *should = false; + } +} + +void RandomizerOnKaleidoMoveCursorFromSpecialPos(PauseContext* pauseCtx, uint16_t* cursorItem) { + if (!Flags_GetRandomizerInf(RAND_INF_CAN_EQUIP_SWAP)) { + *cursorItem = PAUSE_ITEM_NONE; + // PAUSE_ITEM_NONE feels more accurate to intended behaviour, but alternative here also works + // *cursorItem = gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]]; + } +} + +void RandomizerOnAnimationSetLoadFrame(LinkAnimationHeader* animation, int32_t* frame) { + if (!Flags_GetRandomizerInf(RAND_INF_CAN_WEIRDSHOT)) { + std::optional animationName; + + if (ResourceMgr_OTRSigCheck(reinterpret_cast(animation)) != 0) { + animationName = reinterpret_cast(animation); + animation = reinterpret_cast(ResourceMgr_LoadAnimByName(*animationName)); + } + + const auto playerAnimHeader = + static_cast(SEGMENTED_TO_VIRTUAL(static_cast(animation))); + + if (*frame < 0 || *frame >= playerAnimHeader->common.frameCount) { + *frame = 0; + } + } +} + void RandomizerRegisterHooks() { static uint32_t onFlagSetHook = 0; static uint32_t onSceneFlagSetHook = 0; @@ -2403,6 +2495,12 @@ void RandomizerRegisterHooks() { static uint32_t onExitGameHook = 0; static uint32_t onKaleidoUpdateHook = 0; static uint32_t onCuccoOrChickenHatchHook = 0; + static uint32_t onLinkAnimEndHook = 0; + static uint32_t onQPADamageHook = 0; + static uint32_t onESSHook = 0; + static uint32_t onWaitForPutawayHook = 0; + static uint32_t onKaleidoMoveCursorFromSpecialPosHook = 0; + static uint32_t onAnimationSetLoadFrameHook = 0; static uint32_t fishsanityOnActorInitHook = 0; static uint32_t fishsanityOnActorUpdateHook = 0; @@ -2435,6 +2533,14 @@ void RandomizerRegisterHooks() { GameInteractor::Instance->UnregisterGameHook(onExitGameHook); GameInteractor::Instance->UnregisterGameHook(onKaleidoUpdateHook); GameInteractor::Instance->UnregisterGameHook(onCuccoOrChickenHatchHook); + GameInteractor::Instance->UnregisterGameHook(onLinkAnimEndHook); + GameInteractor::Instance->UnregisterGameHook(onQPADamageHook); + GameInteractor::Instance->UnregisterGameHook(onESSHook); + GameInteractor::Instance->UnregisterGameHook(onWaitForPutawayHook); + GameInteractor::Instance->UnregisterGameHook( + onKaleidoMoveCursorFromSpecialPosHook); + GameInteractor::Instance->UnregisterGameHook( + onAnimationSetLoadFrameHook); GameInteractor::Instance->UnregisterGameHook(fishsanityOnActorInitHook); GameInteractor::Instance->UnregisterGameHook(fishsanityOnActorUpdateHook); @@ -2461,6 +2567,7 @@ void RandomizerRegisterHooks() { onExitGameHook = 0; onKaleidoUpdateHook = 0; onCuccoOrChickenHatchHook = 0; + onLinkAnimEndHook = 0; fishsanityOnActorInitHook = 0; fishsanityOnActorUpdateHook = 0; @@ -2516,6 +2623,27 @@ void RandomizerRegisterHooks() { RandomizerOnKaleidoscopeUpdateHandler); onCuccoOrChickenHatchHook = GameInteractor::Instance->RegisterGameHook( RandomizerOnCuccoOrChickenHatch); + onLinkAnimEndHook = GameInteractor::Instance->RegisterGameHook( + [](SkelAnime* skelAnime) { RandomizerOnLinkAnimEnd(skelAnime); }); + onQPADamageHook = GameInteractor::Instance->RegisterGameHook( + [](uint32_t* dmgFlags) { RandomizerOnQPADamage(dmgFlags); }); + onESSHook = GameInteractor::Instance->RegisterGameHook(RandomizerOnESS); + onWaitForPutawayHook = + GameInteractor::Instance->RegisterGameHook(RandomizerOnWaitForPutaway); + onKaleidoMoveCursorFromSpecialPosHook = + GameInteractor::Instance->RegisterGameHook( + [](PauseContext* pauseCtx, uint16_t* cursorItem) { + RandomizerOnKaleidoMoveCursorFromSpecialPos(pauseCtx, cursorItem); + }); + onAnimationSetLoadFrameHook = + GameInteractor::Instance->RegisterGameHook( + [](LinkAnimationHeader* animation, int32_t* frame) { + RandomizerOnAnimationSetLoadFrame(animation, frame); + }); + + COND_VB_SHOULD(VB_SKIP_FORCE_PLAY_OCARINA, true, { RandomizerShouldSkipForcePlayOcarina(should); }); + + COND_VB_SHOULD(VB_HOVER_WITH_ISG, true, { RandomizerShouldHover(should); }); if (RAND_GET_OPTION(RSK_FISHSANITY) != RO_FISHSANITY_OFF) { OTRGlobals::Instance->gRandoContext->GetFishsanity()->InitializeFromSave(); diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp index 3f6535c8326..a16479d3e4b 100644 --- a/soh/soh/Enhancements/randomizer/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/item_list.cpp @@ -352,6 +352,25 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_BRONZE_SCALE] = Item(RG_BRONZE_SCALE, Text{ "Bronze Scale", "Écaille de Bronze", "Bronzene Schuppe" }, ITEMTYPE_ITEM, GI_SCALE_SILVER, true, LOGIC_PROGRESSIVE_WALLET, RHT_BRONZE_SCALE, RG_BRONZE_SCALE, OBJECT_GI_SCALE, GID_SCALE_SILVER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_BRONZE_SCALE].SetCustomDrawFunc(Randomizer_DrawBronzeScale); + itemTable[RG_ABILITY_ISG] = Item(RG_ABILITY_ISG, Text{ "ISG", "ISG", "ISG" }, ITEMTYPE_ITEM, GI_NONE, true, LOGIC_NONE, RHT_ABILITY_ISG, RG_ABILITY_ISG, OBJECT_GI_COIN, GID_NCOIN_YELLOW, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ABILITY_ISG].SetCustomDrawFunc(Randomizer_DrawMysteryItem); + itemTable[RG_ABILITY_OI] = Item(RG_ABILITY_OI, Text{ "OI", "OI", "OI" }, ITEMTYPE_ITEM, GI_NONE, true, LOGIC_NONE, RHT_ABILITY_OI, RG_ABILITY_OI, OBJECT_GI_COIN, GID_NCOIN_YELLOW, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ABILITY_OI].SetCustomDrawFunc(Randomizer_DrawMysteryItem); + itemTable[RG_ABILITY_QPA] = Item(RG_ABILITY_QPA, Text{ "QPA", "QPA", "QPA" }, ITEMTYPE_ITEM, GI_NONE, true, LOGIC_NONE, RHT_ABILITY_QPA, RG_ABILITY_QPA, OBJECT_GI_COIN, GID_NCOIN_YELLOW, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ABILITY_QPA].SetCustomDrawFunc(Randomizer_DrawMysteryItem); + itemTable[RG_ABILITY_HESS] = Item(RG_ABILITY_HESS, Text{ "Extended Superslide", "Extended Superslide", "Extended Superslide" }, ITEMTYPE_ITEM, GI_NONE, true, LOGIC_NONE, RHT_ABILITY_HESS, RG_ABILITY_HESS, OBJECT_GI_COIN, GID_NCOIN_YELLOW, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ABILITY_HESS].SetCustomDrawFunc(Randomizer_DrawMysteryItem); + itemTable[RG_ABILITY_SUPERSLIDE] = Item(RG_ABILITY_SUPERSLIDE, Text{ "Superslide", "Superslide", "Superslide" }, ITEMTYPE_ITEM, GI_NONE, true, LOGIC_NONE, RHT_ABILITY_SUPERSLIDE, RG_ABILITY_SUPERSLIDE, OBJECT_GI_COIN, GID_NCOIN_YELLOW, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ABILITY_SUPERSLIDE].SetCustomDrawFunc(Randomizer_DrawMysteryItem); + itemTable[RG_ABILITY_HOVER] = Item(RG_ABILITY_HOVER, Text{ "Hovering", "Hovering", "Hovering" }, ITEMTYPE_ITEM, GI_NONE, true, LOGIC_NONE, RHT_ABILITY_HOVER, RG_ABILITY_HOVER, OBJECT_GI_COIN, GID_NCOIN_YELLOW, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ABILITY_HOVER].SetCustomDrawFunc(Randomizer_DrawMysteryItem); + itemTable[RG_ABILITY_EQUIP_SWAP] = Item(RG_ABILITY_EQUIP_SWAP, Text{ "Equip Swap", "Equip Swap", "Equip Swap" }, ITEMTYPE_ITEM, GI_NONE, true, LOGIC_NONE, RHT_ABILITY_EQUIP_SWAP, RG_ABILITY_EQUIP_SWAP, OBJECT_GI_COIN, GID_NCOIN_YELLOW, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ABILITY_EQUIP_SWAP].SetCustomDrawFunc(Randomizer_DrawMysteryItem); + itemTable[RG_ABILITY_GROUND_JUMP] = Item(RG_ABILITY_GROUND_JUMP, Text{ "Ground Jump", "Ground Jump", "Ground Jump" }, ITEMTYPE_ITEM, GI_NONE, true, LOGIC_NONE, RHT_ABILITY_GROUND_JUMP, RG_ABILITY_GROUND_JUMP, OBJECT_GI_COIN, GID_NCOIN_YELLOW, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ABILITY_GROUND_JUMP].SetCustomDrawFunc(Randomizer_DrawMysteryItem); + itemTable[RG_ABILITY_WEIRDSHOT] = Item(RG_ABILITY_WEIRDSHOT, Text{ "Weirdshot", "Weirdshot", "Weirdshot" }, ITEMTYPE_ITEM, GI_NONE, true, LOGIC_NONE, RHT_ABILITY_WEIRDSHOT, RG_ABILITY_WEIRDSHOT, OBJECT_GI_COIN, GID_NCOIN_YELLOW, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ABILITY_WEIRDSHOT].SetCustomDrawFunc(Randomizer_DrawMysteryItem); + itemTable[RG_BOMBCHU_BAG] = Item(RG_BOMBCHU_BAG, Text{ "Bombchu Bag", "Sac de Missiles Teigneux", "Krabbelminentasche" }, ITEMTYPE_ITEM, RG_BOMBCHU_BAG, true, LOGIC_BOMBCHUS, RHT_BOMBCHU_BAG, RG_BOMBCHU_BAG, OBJECT_GI_BOMB_2, GID_BOMBCHU, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_BOMBCHU_BAG].SetCustomDrawFunc(Randomizer_DrawBombchuBag); diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 0779a5aec4d..8e37033e5ed 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -1803,6 +1803,33 @@ void Logic::ApplyItemEffect(Item& item, bool state) { case RG_BOMBCHU_20: SetInventory(ITEM_BOMBCHU, (!state ? ITEM_NONE : ITEM_BOMBCHU)); break; + case RG_ABILITY_ISG: + SetRandoInf(RAND_INF_CAN_ISG, state); + break; + case RG_ABILITY_OI: + SetRandoInf(RAND_INF_CAN_OI, state); + break; + case RG_ABILITY_QPA: + SetRandoInf(RAND_INF_CAN_QPA, state); + break; + case RG_ABILITY_HESS: + SetRandoInf(RAND_INF_CAN_HESS, state); + break; + case RG_ABILITY_SUPERSLIDE: + SetRandoInf(RAND_INF_CAN_SUPERSLIDE, state); + break; + case RG_ABILITY_HOVER: + SetRandoInf(RAND_INF_CAN_HOVER, state); + break; + case RG_ABILITY_EQUIP_SWAP: + SetRandoInf(RAND_INF_CAN_EQUIP_SWAP, state); + break; + case RG_ABILITY_GROUND_JUMP: + SetRandoInf(RAND_INF_CAN_GROUND_JUMP, state); + break; + case RG_ABILITY_WEIRDSHOT: + SetRandoInf(RAND_INF_CAN_WEIRDSHOT, state); + break; default: break; } @@ -2326,6 +2353,35 @@ void Logic::Reset(bool resetSaveContext /*= true*/) { SetRandoInf(RAND_INF_CAN_SWIM, true); } + // If we're not shuffling glitch abilites, we start with them + if (ctx->GetOption(RSK_SHUFFLE_ISG).Is(false)) { + SetRandoInf(RAND_INF_CAN_ISG, true); + } + if (ctx->GetOption(RSK_SHUFFLE_OI).Is(false)) { + SetRandoInf(RAND_INF_CAN_OI, true); + } + if (ctx->GetOption(RSK_SHUFFLE_QPA).Is(false)) { + SetRandoInf(RAND_INF_CAN_QPA, true); + } + if (ctx->GetOption(RSK_SHUFFLE_HESS).Is(false)) { + SetRandoInf(RAND_INF_CAN_HESS, true); + } + if (ctx->GetOption(RSK_SHUFFLE_SUPERSLIDE).Is(false)) { + SetRandoInf(RAND_INF_CAN_SUPERSLIDE, true); + } + if (ctx->GetOption(RSK_SHUFFLE_HOVER).Is(false)) { + SetRandoInf(RAND_INF_CAN_HOVER, true); + } + if (ctx->GetOption(RSK_SHUFFLE_EQUIP_SWAP).Is(false)) { + SetRandoInf(RAND_INF_CAN_EQUIP_SWAP, true); + } + if (ctx->GetOption(RSK_SHUFFLE_GROUND_JUMP).Is(false)) { + SetRandoInf(RAND_INF_CAN_GROUND_JUMP, true); + } + if (ctx->GetOption(RSK_SHUFFLE_WEIRDSHOT).Is(false)) { + SetRandoInf(RAND_INF_CAN_WEIRDSHOT, true); + } + // If we're not shuffling child's wallet, we start with it if (ctx->GetOption(RSK_SHUFFLE_CHILD_WALLET).Is(false)) { SetRandoInf(RAND_INF_HAS_WALLET, true); diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index 50d11d9b2ab..5fe157a9a60 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -760,5 +760,18 @@ void Settings::CreateOptionDescriptions() { "Shuffles 8 boss souls (one for each blue warp dungeon). A boss will not appear until you collect its " "respective soul." "\n\"On + Ganon\" will also hide Ganon and Ganondorf behind a boss soul."; + + mOptionDescriptions[RSK_SHUFFLE_ISG] = + "Shuffles the ability to use the Infinite Sword Glitch (ISG) into the item pool."; + mOptionDescriptions[RSK_SHUFFLE_OI] = "Shuffles the ability to use the glitch Ocarina Items into the item pool."; + mOptionDescriptions[RSK_SHUFFLE_QPA] = + "Shuffles the ability to use Quick Putaway Glitched Damage into the item pool."; + mOptionDescriptions[RSK_SHUFFLE_HESS] = + "Shuffles the ability to perform an Extended Superslide into the item pool."; + mOptionDescriptions[RSK_SHUFFLE_SUPERSLIDE] = "Shuffles the ability to Superslide into the item pool."; + mOptionDescriptions[RSK_SHUFFLE_HOVER] = "Shuffles the ability to Hover into the item pool."; + mOptionDescriptions[RSK_SHUFFLE_EQUIP_SWAP] = "Shuffles the ability to Equip Swap into the item pool."; + mOptionDescriptions[RSK_SHUFFLE_GROUND_JUMP] = "Shuffles the ability to Ground Jump into the item pool."; + mOptionDescriptions[RSK_SHUFFLE_WEIRDSHOT] = "Shuffles the ability to Weirdshot into the item pool."; } } // namespace Rando diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 49f5fa45a65..db553b40178 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -5394,7 +5394,7 @@ CustomMessage Randomizer::GetGoronMessage(u16 index) { void Randomizer::CreateCustomMessages() { // RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED // with GIMESSAGE(getItemID, itemID, english, german, french). - const std::array getItemMessages = { { + const std::array getItemMessages = { { GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, "You found %gGreg%w!", "%gGreg%w! Du hast ihn&wirklich gefunden!", "Félicitation! Vous avez trouvé %gGreg%w!"), GIMESSAGE(RG_MASTER_SWORD, ITEM_SWORD_MASTER, "You found the %gMaster Sword%w!", @@ -5718,6 +5718,26 @@ void Randomizer::CreateCustomMessages() { GIMESSAGE(RG_BRONZE_SCALE, ITEM_SCALE_SILVER, "You got the %rBronze Scale%w!&The power of buoyancy is yours!", "Du hast die %rBronzene Schuppe%w&erhalten! Die Fähigkeit zu&Schwimmen ist nun dein!", "Vous obtenez l'%rÉcaille de Bronze%w!&Le pouvoir de la flottabilité est&à vous!"), + + GIMESSAGE(RG_ABILITY_ISG, ITEM_SWORD_MASTER, "You got %rISG%w!", "Du hast %rISG%w&erhalten!", + "Vous obtenez %rISG%w!"), + GIMESSAGE(RG_ABILITY_OI, ITEM_OCARINA_TIME, "You got %rOI%w!", "Du hast %rOI%w&erhalten!", + "Vous obtenez %rOI%w!"), + GIMESSAGE(RG_ABILITY_QPA, ITEM_BLUE_FIRE, "You got %rQPA%w!", "Du hast %rQPA%w&erhalten!", + "Vous obtenez %rQPA%w!"), + GIMESSAGE(RG_ABILITY_HESS, ITEM_BOOTS_HOVER, "You got %rHESS%w!", "Du hast %rHESS%w&erhalten!", + "Vous obtenez %rHESS%w!"), + GIMESSAGE(RG_ABILITY_SUPERSLIDE, ITEM_BOOTS_HOVER, "You got %rSuperslide%w!", + "Du hast %rSuperslide%w&erhalten!", "Vous obtenez %rSuperslide%w!"), + GIMESSAGE(RG_ABILITY_HOVER, ITEM_BOOTS_HOVER, "You got %rHover%w!", "Du hast %rHover%w&erhalten!", + "Vous obtenez %rHover%w!"), + GIMESSAGE(RG_ABILITY_EQUIP_SWAP, ITEM_DINS_FIRE, "You got %rEquip Swap%w!", "Du hast %rEquip Swap%w&erhalten!", + "Vous obtenez %rEquip Swap%w!"), + GIMESSAGE(RG_ABILITY_GROUND_JUMP, ITEM_SHIELD_HYLIAN, "You got %rGround Jump%w!", + "Du hast %rGround Jump%w&erhalten!", "Vous obtenez %rGround Jump%w!"), + GIMESSAGE(RG_ABILITY_WEIRDSHOT, ITEM_HOOKSHOT, "You got %rWeirdshot%w!", "Du hast %rWeirdshot%w&erhalten!", + "Vous obtenez %rWeirdshot%w!"), + GIMESSAGE(RG_FISHING_POLE, ITEM_FISHING_POLE, "You found a lost %rFishing Pole%w!&Time to hit the pond!", "Du hast eine verlorene %rAngelrute%w&gefunden!&Zeit, im Teich&zu angeln!", "Vous obtenez une %rCanne à pêche%w&perdue!&Il est temps d'aller à %gl'étang%w!"), @@ -5911,6 +5931,15 @@ std::map randomizerGetToRandInf = { { RG_BONGO_BONGO_SOUL, RAND_INF_BONGO_BONGO_SOUL }, { RG_TWINROVA_SOUL, RAND_INF_TWINROVA_SOUL }, { RG_GANON_SOUL, RAND_INF_GANON_SOUL }, + { RG_ABILITY_ISG, RAND_INF_CAN_ISG }, + { RG_ABILITY_OI, RAND_INF_CAN_OI }, + { RG_ABILITY_QPA, RAND_INF_CAN_QPA }, + { RG_ABILITY_HESS, RAND_INF_CAN_HESS }, + { RG_ABILITY_SUPERSLIDE, RAND_INF_CAN_SUPERSLIDE }, + { RG_ABILITY_HOVER, RAND_INF_CAN_HOVER }, + { RG_ABILITY_EQUIP_SWAP, RAND_INF_CAN_EQUIP_SWAP }, + { RG_ABILITY_GROUND_JUMP, RAND_INF_CAN_GROUND_JUMP }, + { RG_ABILITY_WEIRDSHOT, RAND_INF_CAN_WEIRDSHOT }, }; extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index ab9b6edbcbb..de04e51b1f1 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -4053,6 +4053,18 @@ typedef enum { RG_BACK_TOWER_KEY, RG_HYLIA_LAB_KEY, RG_FISHING_HOLE_KEY, + + // Glitch abilities + RG_ABILITY_ISG, + RG_ABILITY_OI, + RG_ABILITY_QPA, + RG_ABILITY_HESS, + RG_ABILITY_SUPERSLIDE, + RG_ABILITY_HOVER, + RG_ABILITY_EQUIP_SWAP, + RG_ABILITY_GROUND_JUMP, + RG_ABILITY_WEIRDSHOT, + // Logic Only RG_DISTANT_SCARECROW, RG_STICKS, @@ -5647,6 +5659,16 @@ typedef enum { RHT_DODONGOS_CAVERN_GRASS, RHT_BOTTOM_OF_THE_WELL_GRASS, RHT_JABU_JABUS_BELLY_GRASS, + // Glitch Abilities + RHT_ABILITY_ISG, + RHT_ABILITY_OI, + RHT_ABILITY_QPA, + RHT_ABILITY_HESS, + RHT_ABILITY_SUPERSLIDE, + RHT_ABILITY_HOVER, + RHT_ABILITY_EQUIP_SWAP, + RHT_ABILITY_GROUND_JUMP, + RHT_ABILITY_WEIRDSHOT, // MAX RHT_MAX, } RandomizerHintTextKey; @@ -5940,6 +5962,16 @@ typedef enum { RSK_SHUFFLE_FAIRIES, RSK_LOCK_OVERWORLD_DOORS, RSK_SHUFFLE_GRASS, + // Glitch shuffles + RSK_SHUFFLE_ISG, + RSK_SHUFFLE_OI, + RSK_SHUFFLE_QPA, + RSK_SHUFFLE_HESS, + RSK_SHUFFLE_SUPERSLIDE, + RSK_SHUFFLE_HOVER, + RSK_SHUFFLE_EQUIP_SWAP, + RSK_SHUFFLE_GROUND_JUMP, + RSK_SHUFFLE_WEIRDSHOT, RSK_MAX } RandomizerSettingKey; diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h index d42e14cb101..be967faab0b 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_inf.h +++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h @@ -1004,6 +1004,16 @@ DEFINE_RAND_INF(RAND_INF_CAN_SWIM) DEFINE_RAND_INF(RAND_INF_HAS_WALLET) +DEFINE_RAND_INF(RAND_INF_CAN_ISG) +DEFINE_RAND_INF(RAND_INF_CAN_OI) +DEFINE_RAND_INF(RAND_INF_CAN_QPA) +DEFINE_RAND_INF(RAND_INF_CAN_HESS) +DEFINE_RAND_INF(RAND_INF_CAN_SUPERSLIDE) +DEFINE_RAND_INF(RAND_INF_CAN_HOVER) +DEFINE_RAND_INF(RAND_INF_CAN_EQUIP_SWAP) +DEFINE_RAND_INF(RAND_INF_CAN_GROUND_JUMP) +DEFINE_RAND_INF(RAND_INF_CAN_WEIRDSHOT) + DEFINE_RAND_INF(RAND_INF_BEEHIVE_KF_STORMS_GROTTO_LEFT) DEFINE_RAND_INF(RAND_INF_BEEHIVE_KF_STORMS_GROTTO_RIGHT) DEFINE_RAND_INF(RAND_INF_BEEHIVE_LW_NEAR_SHORTCUTS_GROTTO_LEFT) diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index 51101f6fa59..a1928dc144d 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -258,6 +258,34 @@ extern "C" void Randomizer_InitSaveFile() { Flags_SetRandomizerInf(RAND_INF_CAN_SWIM); } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_ISG) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_ISG); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_OI) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_OI); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_QPA) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_QPA); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_HESS) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_HESS); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_SUPERSLIDE) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_SUPERSLIDE); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_HOVER) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_HOVER); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_EQUIP_SWAP) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_EQUIP_SWAP); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_GROUND_JUMP) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_GROUND_JUMP); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_WEIRDSHOT) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_WEIRDSHOT); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_CHILD_WALLET) == RO_GENERIC_OFF) { Flags_SetRandomizerInf(RAND_INF_HAS_WALLET); } diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index e46cc4eeeda..0aac05d2656 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -214,6 +214,15 @@ void Settings::CreateOptions() { OPT_BOOL(RSK_SHUFFLE_SWIM, "Shuffle Swim", CVAR_RANDOMIZER_SETTING("ShuffleSwim"), mOptionDescriptions[RSK_SHUFFLE_SWIM]); OPT_BOOL(RSK_SHUFFLE_WEIRD_EGG, "Shuffle Weird Egg", CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG]); OPT_BOOL(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD, "Shuffle Gerudo Membership Card", CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), mOptionDescriptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD]); + OPT_BOOL(RSK_SHUFFLE_ISG, "Shuffle ISG", CVAR_RANDOMIZER_SETTING("ShuffleISG"), mOptionDescriptions[RSK_SHUFFLE_ISG]); + OPT_BOOL(RSK_SHUFFLE_OI, "Shuffle OI", CVAR_RANDOMIZER_SETTING("ShuffleOI"), mOptionDescriptions[RSK_SHUFFLE_OI]); + OPT_BOOL(RSK_SHUFFLE_QPA, "Shuffle QPA", CVAR_RANDOMIZER_SETTING("ShuffleQPA"), mOptionDescriptions[RSK_SHUFFLE_QPA]); + OPT_BOOL(RSK_SHUFFLE_HESS, "Shuffle HESS", CVAR_RANDOMIZER_SETTING("ShuffleHESS"), mOptionDescriptions[RSK_SHUFFLE_HESS]); + OPT_BOOL(RSK_SHUFFLE_SUPERSLIDE, "Shuffle Superslide", CVAR_RANDOMIZER_SETTING("ShuffleSuperslide"), mOptionDescriptions[RSK_SHUFFLE_SUPERSLIDE]); + OPT_BOOL(RSK_SHUFFLE_HOVER, "Shuffle Hovering", CVAR_RANDOMIZER_SETTING("ShuffleHover"), mOptionDescriptions[RSK_SHUFFLE_HOVER]); + OPT_BOOL(RSK_SHUFFLE_EQUIP_SWAP, "Shuffle Equip Swap", CVAR_RANDOMIZER_SETTING("ShuffleEquipSwap"), mOptionDescriptions[RSK_SHUFFLE_EQUIP_SWAP]); + OPT_BOOL(RSK_SHUFFLE_GROUND_JUMP, "Shuffle Ground Jump", CVAR_RANDOMIZER_SETTING("ShuffleGroundJump"), mOptionDescriptions[RSK_SHUFFLE_GROUND_JUMP]); + OPT_BOOL(RSK_SHUFFLE_WEIRDSHOT, "Shuffle Weirdshot", CVAR_RANDOMIZER_SETTING("ShuffleWeirdshot"), mOptionDescriptions[RSK_SHUFFLE_WEIRDSHOT]); OPT_U8(RSK_SHUFFLE_POTS, "Shuffle Pots", {"Off", "Dungeons", "Overworld", "All Pots"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShufflePots"), mOptionDescriptions[RSK_SHUFFLE_POTS], WidgetType::Combobox, RO_SHUFFLE_POTS_OFF); OPT_U8(RSK_SHUFFLE_GRASS, "Shuffle Grass", {"Off", "Dungeons", "Overworld", "All Grass/Bushes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleGrass"), mOptionDescriptions[RSK_SHUFFLE_GRASS], WidgetType::Combobox, RO_SHUFFLE_GRASS_OFF); OPT_U8(RSK_SHUFFLE_CRATES, "Shuffle Crates", {"Off", "Dungeons", "Overworld", "All Crates"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleCrates"), mOptionDescriptions[RSK_SHUFFLE_CRATES], WidgetType::Combobox, RO_SHUFFLE_CRATES_OFF); @@ -1247,6 +1256,15 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_DEKU_STICK_BAG], &mOptions[RSK_SHUFFLE_DEKU_NUT_BAG], &mOptions[RSK_SHUFFLE_FREESTANDING], + &mOptions[RSK_SHUFFLE_ISG], + &mOptions[RSK_SHUFFLE_OI], + &mOptions[RSK_SHUFFLE_QPA], + &mOptions[RSK_SHUFFLE_HESS], + &mOptions[RSK_SHUFFLE_SUPERSLIDE], + &mOptions[RSK_SHUFFLE_HOVER], + &mOptions[RSK_SHUFFLE_EQUIP_SWAP], + &mOptions[RSK_SHUFFLE_GROUND_JUMP], + &mOptions[RSK_SHUFFLE_WEIRDSHOT], }, WidgetContainerType::COLUMN); mOptionGroups[RSG_SHUFFLE_NPCS_IMGUI] = @@ -1541,6 +1559,15 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_DEKU_NUT_BAG], &mOptions[RSK_SHUFFLE_FREESTANDING], &mOptions[RSK_SHUFFLE_FAIRIES], + &mOptions[RSK_SHUFFLE_ISG], + &mOptions[RSK_SHUFFLE_OI], + &mOptions[RSK_SHUFFLE_QPA], + &mOptions[RSK_SHUFFLE_HESS], + &mOptions[RSK_SHUFFLE_SUPERSLIDE], + &mOptions[RSK_SHUFFLE_HOVER], + &mOptions[RSK_SHUFFLE_EQUIP_SWAP], + &mOptions[RSK_SHUFFLE_GROUND_JUMP], + &mOptions[RSK_SHUFFLE_WEIRDSHOT], }); mOptionGroups[RSG_SHUFFLE_DUNGEON_ITEMS] = OptionGroup("Shuffle Dungeon Items", { diff --git a/soh/src/code/z_skelanime.c b/soh/src/code/z_skelanime.c index a7e93e8c356..74ba737de44 100644 --- a/soh/src/code/z_skelanime.c +++ b/soh/src/code/z_skelanime.c @@ -889,6 +889,8 @@ void AnimationContext_SetLoadFrame(PlayState* play, LinkAnimationHeader* animati Vec3s* frameTable) { AnimationEntry* entry = AnimationContext_AddEntry(&play->animationCtx, ANIMENTRY_LOADFRAME); + GameInteractor_ExecuteOnAnimationSetLoadFrame(animation, &frame); + if (GameInteractor_Should(VB_LOAD_PLAYER_ANIMATION_FRAME, entry != NULL, entry, animation, frame, limbCount, frameTable)) { if (ResourceMgr_OTRSigCheck(animation) != 0) @@ -1225,6 +1227,7 @@ s32 LinkAnimation_Once(PlayState* play, SkelAnime* skelAnime) { if (skelAnime->curFrame == skelAnime->endFrame) { LinkAnimation_AnimateFrame(play, skelAnime); + GameInteractor_ExecuteOnLinkAnimEnd(skelAnime); return 1; } skelAnime->curFrame += skelAnime->playSpeed * updateRate; 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 3571ca1352e..8bf20178658 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -4450,6 +4450,7 @@ void func_80837948(PlayState* play, Player* this, s32 arg2) { if ((arg2 >= PLAYER_MWA_FLIPSLASH_START) && (arg2 <= PLAYER_MWA_JUMPSLASH_FINISH)) { if (CVarGetInteger(CVAR_GENERAL("RestoreQPA"), 1) && temp == -1) { dmgFlags = 0x16171617; + GameInteractor_ExecuteOnQPADamage(&dmgFlags); } else { dmgFlags = D_80854488[temp][1]; } @@ -5788,7 +5789,8 @@ void func_8083AA10(Player* this, PlayState* play) { if (!(this->stateFlags3 & PLAYER_STATE3_MIDAIR) && !(this->skelAnime.movementFlags & 0x80) && (Player_Action_8084411C != this->actionFunc) && (Player_Action_80844A44 != this->actionFunc)) { - if ((sPrevFloorProperty == 7) || (this->meleeWeaponState != 0)) { + if ((sPrevFloorProperty == 7) || + (GameInteractor_Should(VB_HOVER_WITH_ISG, true) && (this->meleeWeaponState != 0))) { Math_Vec3f_Copy(&this->actor.world.pos, &this->actor.prevPos); Player_ZeroSpeedXZ(this); return; @@ -6100,6 +6102,9 @@ s32 Player_ActionHandler_13(Player* this, PlayState* play) { func_80835EA4(play, 2); } } else { + if (GameInteractor_Should(VB_SKIP_FORCE_PLAY_OCARINA, false)) { + return 0; + } Player_SetupActionPreserveItemAction(play, this, Player_Action_8084E3C4, 0); Player_AnimPlayOnceAdjusted(play, this, &gPlayerAnim_link_normal_okarina_start); this->stateFlags2 |= PLAYER_STATE2_OCARINA_PLAYING; @@ -8729,6 +8734,8 @@ void Player_Action_TurnInPlace(Player* this, PlayState* play) { this->skelAnime.morphTable, sUpperBodyLimbCopyMap); } + GameInteractor_ExecuteOnESS(); + Player_GetMovementSpeedAndYaw(this, &speedTarget, &yawTarget, SPEED_MODE_CURVED, play); //! @bug This action does not handle xzSpeed in any capacity. @@ -10222,6 +10229,8 @@ void Player_Action_WaitForPutAway(Player* this, PlayState* play) { this->stateFlags2 |= PLAYER_STATE2_DISABLE_ROTATION_Z_TARGET | PLAYER_STATE2_DISABLE_ROTATION_ALWAYS; LinkAnimation_Update(play, &this->skelAnime); + GameInteractor_ExecuteOnWaitForPutaway(); + // Wait for the held item put away process to complete. // Determining if the put away process is complete is a bit complicated: // `Player_UpdateUpperBody` will only return false if the current UpperAction returns false. diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index 7f0cfcc7a1a..05fe233b92e 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -554,6 +554,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { pauseCtx->cursorX[PAUSE_ITEM] = cursorX; pauseCtx->cursorY[PAUSE_ITEM] = cursorY; moveCursorResult = 1; + GameInteractor_ExecuteOnKaleidoMoveCursorFromSpecialPos(pauseCtx, &cursorItem); break; } @@ -590,6 +591,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { pauseCtx->cursorX[PAUSE_ITEM] = cursorX; pauseCtx->cursorY[PAUSE_ITEM] = cursorY; moveCursorResult = 1; + GameInteractor_ExecuteOnKaleidoMoveCursorFromSpecialPos(pauseCtx, &cursorItem); break; }