From 0e7c6585239c0d7ea2c039b8b8cb7eaedf8928a9 Mon Sep 17 00:00:00 2001 From: Caladius Date: Wed, 30 Aug 2023 13:34:06 -0400 Subject: [PATCH] V1 - Chestapalooza (#2922) * V1- Adds additional trap variants to Chests * Create and use OnTrapProcessed hook * Update naming for Traps, extends to NPC and Token Rewards. New Hook for Rando traps. Restore Vanilla code for ice traps. * Update soh/src/overlays/actors/ovl_player_actor/z_player.c Co-authored-by: Garrett Cox * More tweaks, remove processed trap hook --------- Co-authored-by: Garrett Cox --- .../game-interactor/GameInteractionEffect.cpp | 2 +- .../GameInteractor_RawAction.cpp | 4 +- soh/soh/Enhancements/mods.cpp | 152 +++++++++++++++++- soh/soh/Enhancements/randomizer/savefile.cpp | 1 - soh/soh/SohMenuBar.cpp | 33 ++++ soh/src/overlays/actors/ovl_En_Box/z_en_box.c | 9 +- .../overlays/actors/ovl_En_GirlA/z_en_girla.c | 4 - .../actors/ovl_player_actor/z_player.c | 15 +- 8 files changed, 200 insertions(+), 20 deletions(-) diff --git a/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp b/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp index d0fda0db8..0b8682ca6 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractionEffect.cpp @@ -173,7 +173,7 @@ namespace GameInteractionEffect { // MARK: - FreezePlayer GameInteractionEffectQueryResult FreezePlayer::CanBeApplied() { Player* player = GET_PLAYER(gPlayState); - if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { + if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) { return GameInteractionEffectQueryResult::TemporarilyNotPossible; } else { return GameInteractionEffectQueryResult::Possible; diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp index e7db940cf..0cad9c718 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp @@ -103,7 +103,9 @@ void GameInteractor::RawAction::ForceEquipBoots(int8_t boots) { } void GameInteractor::RawAction::FreezePlayer() { - gSaveContext.pendingIceTrapCount++; + Player* player = GET_PLAYER(gPlayState); + player->actor.colChkInfo.damage = 0; + func_80837C0C(gPlayState, player, 3, 0, 0, 0, 0); } void GameInteractor::RawAction::BurnPlayer() { diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 6fc4a87f5..078fbc2d0 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -1,6 +1,7 @@ #include "mods.h" #include #include "game-interactor/GameInteractor.h" +#include "soh/Enhancements/randomizer/3drando/random.hpp" #include "tts/tts.h" #include "soh/Enhancements/boss-rush/BossRushTypes.h" #include "soh/Enhancements/enhancementTypes.h" @@ -16,7 +17,7 @@ extern "C" { #include "functions.h" extern SaveContext gSaveContext; extern PlayState* gPlayState; - +extern void Overlay_DisplayText(float duration, const char* text); uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum); } bool performDelayedSave = false; @@ -600,6 +601,154 @@ void RegisterMirrorModeHandler() { }); } +typedef enum { + ADD_ICE_TRAP, + ADD_BURN_TRAP, + ADD_SHOCK_TRAP, + ADD_KNOCK_TRAP, + ADD_SPEED_TRAP, + ADD_BOMB_TRAP, + ADD_VOID_TRAP, + ADD_AMMO_TRAP, + ADD_KILL_TRAP, + ADD_TELEPORT_TRAP, + ADD_TRAP_MAX +} AltTrapType; + +const char* altTrapTypeCvars[] = { + "gAddTraps.Ice", + "gAddTraps.Burn", + "gAddTraps.Shock", + "gAddTraps.Knock", + "gAddTraps.Speed", + "gAddTraps.Bomb", + "gAddTraps.Void", + "gAddTraps.Ammo", + "gAddTraps.Kill", + "gAddTraps.Tele" +}; + +std::vector getEnabledAddTraps () { + std::vector enabledAddTraps; + for (int i = 0; i < ADD_TRAP_MAX; i++) { + if (CVarGetInteger(altTrapTypeCvars[i], 0)) { + enabledAddTraps.push_back(static_cast(i)); + } + } + if (enabledAddTraps.size() == 0) { + enabledAddTraps.push_back(ADD_ICE_TRAP); + } + return enabledAddTraps; +}; + +void RegisterAltTrapTypes() { + static AltTrapType roll = ADD_TRAP_MAX; + static int statusTimer = -1; + static int eventTimer = -1; + + GameInteractor::Instance->RegisterGameHook([](GetItemEntry itemEntry) { + if (!CVarGetInteger("gAddTraps.enabled", 0) || itemEntry.modIndex != MOD_RANDOMIZER || itemEntry.getItemId != RG_ICE_TRAP) { + return; + } + roll = RandomElement(getEnabledAddTraps()); + switch (roll) { + case ADD_ICE_TRAP: + GameInteractor::RawAction::FreezePlayer(); + break; + case ADD_BURN_TRAP: + GameInteractor::RawAction::BurnPlayer(); + break; + case ADD_SHOCK_TRAP: + GameInteractor::RawAction::ElectrocutePlayer(); + break; + case ADD_KNOCK_TRAP: + eventTimer = 3; + break; + case ADD_SPEED_TRAP: + Audio_PlaySoundGeneral(NA_SE_VO_KZ_MOVE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + GameInteractor::State::RunSpeedModifier = -2; + statusTimer = 200; + Overlay_DisplayText(10, "Speed Decreased!"); + break; + case ADD_BOMB_TRAP: + eventTimer = 3; + break; + case ADD_VOID_TRAP: + Audio_PlaySoundGeneral(NA_SE_EN_GANON_LAUGH, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + eventTimer = 3; + break; + case ADD_AMMO_TRAP: + eventTimer = 3; + Overlay_DisplayText(5, "Ammo Halved!"); + break; + case ADD_KILL_TRAP: + GameInteractor::RawAction::SetPlayerHealth(0); + break; + case ADD_TELEPORT_TRAP: + eventTimer = 3; + break; + } + }); + GameInteractor::Instance->RegisterGameHook([]() { + Player* player = GET_PLAYER(gPlayState); + if (statusTimer == 0) { + GameInteractor::State::RunSpeedModifier = 0; + } + if (eventTimer == 0) { + switch (roll) { + case ADD_KNOCK_TRAP: + GameInteractor::RawAction::KnockbackPlayer(1); + break; + case ADD_BOMB_TRAP: + GameInteractor::RawAction::SpawnActor(ACTOR_EN_BOM, 1); + break; + case ADD_VOID_TRAP: + Play_TriggerRespawn(gPlayState); + break; + case ADD_AMMO_TRAP: + AMMO(ITEM_STICK) = AMMO(ITEM_STICK) * 0.5; + AMMO(ITEM_NUT) = AMMO(ITEM_NUT) * 0.5; + AMMO(ITEM_SLINGSHOT) = AMMO(ITEM_SLINGSHOT) * 0.5; + AMMO(ITEM_BOW) = AMMO(ITEM_BOW) * 0.5; + AMMO(ITEM_BOMB) = AMMO(ITEM_BOMB) * 0.5; + AMMO(ITEM_BOMBCHU) = AMMO(ITEM_BOMBCHU) * 0.5; + Audio_PlaySoundGeneral(NA_SE_VO_FR_SMILE_0, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + break; + case ADD_TELEPORT_TRAP: + int entrance; + int index = 1 + rand() % 10; + switch (index) { + case 1: + entrance = GI_TP_DEST_SERENADE; + break; + case 2: + entrance = GI_TP_DEST_REQUIEM; + break; + case 3: + entrance = GI_TP_DEST_BOLERO; + break; + case 4: + entrance = GI_TP_DEST_MINUET; + break; + case 5: + entrance = GI_TP_DEST_NOCTURNE; + break; + case 6: + entrance = GI_TP_DEST_PRELUDE; + break; + default: + entrance = GI_TP_DEST_LINKSHOUSE; + break; + } + GameInteractor::RawAction::TeleportPlayer(entrance); + break; + } + } + statusTimer--; + eventTimer--; + }); +} + void InitMods() { RegisterTTS(); RegisterInfiniteMoney(); @@ -622,5 +771,6 @@ void InitMods() { RegisterBonkDamage(); RegisterMenuPathFix(); RegisterMirrorModeHandler(); + RegisterAltTrapTypes(); NameTag_RegisterHooks(); } diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index 4b546e1f0..dfa8632f6 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -22,7 +22,6 @@ void StartingItemGive(GetItemEntry getItemEntry) { } else if (getItemEntry.modIndex == MOD_RANDOMIZER) { if (getItemEntry.getItemId == RG_ICE_TRAP) { gSaveContext.pendingIceTrapCount++; - GameInteractor::Instance->ExecuteHooks(getItemEntry); } else { Randomizer_Item_Give(NULL, getItemEntry); } diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 59dee8444..efd34afb8 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -1101,6 +1101,39 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedEnhancementCheckbox("Shadow Tag Mode", "gShadowTag", true, false); UIWidgets::Tooltip("A wallmaster follows Link everywhere, don't get caught!"); + UIWidgets::Spacer(0); + + UIWidgets::PaddedEnhancementCheckbox("Additional Traps", "gAddTraps.enabled", true, false); + UIWidgets::Tooltip("Enables additional Trap variants."); + + if (CVarGetInteger("gAddTraps.enabled", 0)) { + UIWidgets::PaddedSeparator(); + if (ImGui::BeginMenu("Trap Options")) { + ImGui::Text("Tier 1 Traps:"); + UIWidgets::Spacer(0); + UIWidgets::PaddedEnhancementCheckbox("Freeze Traps", "gAddTraps.Ice", true, false); + UIWidgets::PaddedEnhancementCheckbox("Burn Traps", "gAddTraps.Burn", true, false); + UIWidgets::PaddedEnhancementCheckbox("Shock Traps", "gAddTraps.Shock", true, false); + + UIWidgets::PaddedSeparator(); + ImGui::Text("Tier 2 Traps:"); + UIWidgets::Spacer(0); + UIWidgets::PaddedEnhancementCheckbox("Knockback Traps", "gAddTraps.Knock", true, false); + UIWidgets::PaddedEnhancementCheckbox("Speed Traps", "gAddTraps.Speed", true, false); + UIWidgets::PaddedEnhancementCheckbox("Bomb Traps", "gAddTraps.Bomb", true, false); + + UIWidgets::PaddedSeparator(); + ImGui::Text("Tier 3 Traps:"); + UIWidgets::Spacer(0); + UIWidgets::PaddedEnhancementCheckbox("Void Traps", "gAddTraps.Void", true, false); + UIWidgets::PaddedEnhancementCheckbox("Ammo Traps", "gAddTraps.Ammo", true, false); + UIWidgets::PaddedEnhancementCheckbox("Death Traps", "gAddTraps.Kill", true, false); + UIWidgets::PaddedEnhancementCheckbox("Teleport Traps", "gAddTraps.Tele", true, false); + + ImGui::EndMenu(); + } + } + ImGui::EndMenu(); } diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c index d59c61de4..45b549c77 100644 --- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -627,9 +627,12 @@ void EnBox_Update(Actor* thisx, PlayState* play) { } if (((!gSaveContext.n64ddFlag && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) || - (gSaveContext.n64ddFlag && ABS(sItem.getItemId) == RG_ICE_TRAP)) && - this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && - this->iceSmokeTimer < 100) EnBox_SpawnIceSmoke(this, play); + (gSaveContext.n64ddFlag && ABS(sItem.getItemId) == RG_ICE_TRAP)) && + this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100) { + if (!CVarGetInteger("gAddTraps.enabled", 0)) { + EnBox_SpawnIceSmoke(this, play); + } + } } void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) { diff --git a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c index 96d0c5ec3..f575f60af 100644 --- a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c +++ b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c @@ -988,10 +988,6 @@ void EnGirlA_ItemGive_Randomizer(PlayState* play, EnGirlA* this) { Randomizer_Item_Give(play, getItemEntry); } - if (getItemEntry.itemId == GI_ICE_TRAP || getItemEntry.itemId == RG_ICE_TRAP) { - GameInteractor_ExecuteOnItemReceiveHooks(getItemEntry); - } - Flags_SetRandomizerInf(shopItemIdentity.randomizerInf); Rupees_ChangeBy(-this->basePrice); } 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 b5ddcaa7c..9060f4851 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -6326,6 +6326,8 @@ s32 func_8083E5A8(Player* this, PlayState* play) { if(gSaveContext.pendingIceTrapCount) { gSaveContext.pendingIceTrapCount--; + GameInteractor_ExecuteOnItemReceiveHooks(ItemTable_RetrieveEntry(MOD_RANDOMIZER, RG_ICE_TRAP)); + if (CVarGetInteger("gAddTraps.enabled", 0)) return; this->stateFlags1 &= ~(PLAYER_STATE1_GETTING_ITEM | PLAYER_STATE1_ITEM_OVER_HEAD); this->actor.colChkInfo.damage = 0; func_80837C0C(play, this, 3, 0.0f, 0.0f, 0, 20); @@ -6361,7 +6363,6 @@ s32 func_8083E5A8(Player* this, PlayState* play) { Player_SetPendingFlag(this, play); Message_StartTextbox(play, 0xF8, NULL); Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); - GameInteractor_ExecuteOnItemReceiveHooks(this->getItemEntry); gSaveContext.pendingIceTrapCount++; return 1; } @@ -12790,7 +12791,6 @@ s32 func_8084DFF4(PlayState* play, Player* this) { this->unk_862 = 0; gSaveContext.pendingIceTrapCount++; Player_SetPendingFlag(this, play); - GameInteractor_ExecuteOnItemReceiveHooks(giEntry); } this->getItemId = GI_NONE; @@ -12949,7 +12949,6 @@ void func_8084E6D4(Player* this, PlayState* play) { } } else { func_80832DBC(this); - if ((this->getItemId == GI_ICE_TRAP && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && (this->getItemId == RG_ICE_TRAP || this->getItemEntry.getItemId == RG_ICE_TRAP))) { this->stateFlags1 &= ~(PLAYER_STATE1_GETTING_ITEM | PLAYER_STATE1_ITEM_OVER_HEAD); @@ -12959,15 +12958,13 @@ void func_8084E6D4(Player* this, PlayState* play) { Actor_Spawn(&play->actorCtx, play, ACTOR_EN_CLEAR_TAG, this->actor.world.pos.x, this->actor.world.pos.y + 100.0f, this->actor.world.pos.z, 0, 0, 0, 0, true); func_8083C0E8(this, play); - GameInteractor_ExecuteOnItemReceiveHooks(this->getItemEntry); + } else if (gSaveContext.n64ddFlag) { + gSaveContext.pendingIceTrapCount++; + Player_SetPendingFlag(this, play); + func_8083C0E8(this, play); } else { this->actor.colChkInfo.damage = 0; func_80837C0C(play, this, 3, 0.0f, 0.0f, 0, 20); - GameInteractor_ExecuteOnItemReceiveHooks(this->getItemEntry); - this->getItemId = GI_NONE; - this->getItemEntry = (GetItemEntry)GET_ITEM_NONE; - // Gameplay stats: Increment Ice Trap count - gSaveContext.sohStats.count[COUNT_ICE_TRAPS]++; } return; }