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 <garrettjcox@gmail.com>

* More tweaks, remove processed trap hook

---------

Co-authored-by: Garrett Cox <garrettjcox@gmail.com>
This commit is contained in:
Caladius 2023-08-30 13:34:06 -04:00 committed by GitHub
parent bea24fcde7
commit 0e7c658523
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 200 additions and 20 deletions

View File

@ -173,7 +173,7 @@ namespace GameInteractionEffect {
// MARK: - FreezePlayer // MARK: - FreezePlayer
GameInteractionEffectQueryResult FreezePlayer::CanBeApplied() { GameInteractionEffectQueryResult FreezePlayer::CanBeApplied() {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;

View File

@ -103,7 +103,9 @@ void GameInteractor::RawAction::ForceEquipBoots(int8_t boots) {
} }
void GameInteractor::RawAction::FreezePlayer() { 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() { void GameInteractor::RawAction::BurnPlayer() {

View File

@ -1,6 +1,7 @@
#include "mods.h" #include "mods.h"
#include <libultraship/bridge.h> #include <libultraship/bridge.h>
#include "game-interactor/GameInteractor.h" #include "game-interactor/GameInteractor.h"
#include "soh/Enhancements/randomizer/3drando/random.hpp"
#include "tts/tts.h" #include "tts/tts.h"
#include "soh/Enhancements/boss-rush/BossRushTypes.h" #include "soh/Enhancements/boss-rush/BossRushTypes.h"
#include "soh/Enhancements/enhancementTypes.h" #include "soh/Enhancements/enhancementTypes.h"
@ -16,7 +17,7 @@ extern "C" {
#include "functions.h" #include "functions.h"
extern SaveContext gSaveContext; extern SaveContext gSaveContext;
extern PlayState* gPlayState; extern PlayState* gPlayState;
extern void Overlay_DisplayText(float duration, const char* text);
uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum); uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
} }
bool performDelayedSave = false; 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<AltTrapType> getEnabledAddTraps () {
std::vector<AltTrapType> enabledAddTraps;
for (int i = 0; i < ADD_TRAP_MAX; i++) {
if (CVarGetInteger(altTrapTypeCvars[i], 0)) {
enabledAddTraps.push_back(static_cast<AltTrapType>(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<GameInteractor::OnItemReceive>([](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<GameInteractor::OnPlayerUpdate>([]() {
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() { void InitMods() {
RegisterTTS(); RegisterTTS();
RegisterInfiniteMoney(); RegisterInfiniteMoney();
@ -622,5 +771,6 @@ void InitMods() {
RegisterBonkDamage(); RegisterBonkDamage();
RegisterMenuPathFix(); RegisterMenuPathFix();
RegisterMirrorModeHandler(); RegisterMirrorModeHandler();
RegisterAltTrapTypes();
NameTag_RegisterHooks(); NameTag_RegisterHooks();
} }

View File

@ -22,7 +22,6 @@ void StartingItemGive(GetItemEntry getItemEntry) {
} else if (getItemEntry.modIndex == MOD_RANDOMIZER) { } else if (getItemEntry.modIndex == MOD_RANDOMIZER) {
if (getItemEntry.getItemId == RG_ICE_TRAP) { if (getItemEntry.getItemId == RG_ICE_TRAP) {
gSaveContext.pendingIceTrapCount++; gSaveContext.pendingIceTrapCount++;
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnItemReceive>(getItemEntry);
} else { } else {
Randomizer_Item_Give(NULL, getItemEntry); Randomizer_Item_Give(NULL, getItemEntry);
} }

View File

@ -1101,6 +1101,39 @@ void DrawEnhancementsMenu() {
UIWidgets::PaddedEnhancementCheckbox("Shadow Tag Mode", "gShadowTag", true, false); UIWidgets::PaddedEnhancementCheckbox("Shadow Tag Mode", "gShadowTag", true, false);
UIWidgets::Tooltip("A wallmaster follows Link everywhere, don't get caught!"); 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(); ImGui::EndMenu();
} }

View File

@ -628,8 +628,11 @@ void EnBox_Update(Actor* thisx, PlayState* play) {
if (((!gSaveContext.n64ddFlag && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) || if (((!gSaveContext.n64ddFlag && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) ||
(gSaveContext.n64ddFlag && ABS(sItem.getItemId) == RG_ICE_TRAP)) && (gSaveContext.n64ddFlag && ABS(sItem.getItemId) == RG_ICE_TRAP)) &&
this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100) {
this->iceSmokeTimer < 100) EnBox_SpawnIceSmoke(this, play); if (!CVarGetInteger("gAddTraps.enabled", 0)) {
EnBox_SpawnIceSmoke(this, play);
}
}
} }
void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) { void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) {

View File

@ -988,10 +988,6 @@ void EnGirlA_ItemGive_Randomizer(PlayState* play, EnGirlA* this) {
Randomizer_Item_Give(play, getItemEntry); Randomizer_Item_Give(play, getItemEntry);
} }
if (getItemEntry.itemId == GI_ICE_TRAP || getItemEntry.itemId == RG_ICE_TRAP) {
GameInteractor_ExecuteOnItemReceiveHooks(getItemEntry);
}
Flags_SetRandomizerInf(shopItemIdentity.randomizerInf); Flags_SetRandomizerInf(shopItemIdentity.randomizerInf);
Rupees_ChangeBy(-this->basePrice); Rupees_ChangeBy(-this->basePrice);
} }

View File

@ -6326,6 +6326,8 @@ s32 func_8083E5A8(Player* this, PlayState* play) {
if(gSaveContext.pendingIceTrapCount) { if(gSaveContext.pendingIceTrapCount) {
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->stateFlags1 &= ~(PLAYER_STATE1_GETTING_ITEM | PLAYER_STATE1_ITEM_OVER_HEAD);
this->actor.colChkInfo.damage = 0; this->actor.colChkInfo.damage = 0;
func_80837C0C(play, this, 3, 0.0f, 0.0f, 0, 20); 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); Player_SetPendingFlag(this, play);
Message_StartTextbox(play, 0xF8, NULL); Message_StartTextbox(play, 0xF8, NULL);
Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET);
GameInteractor_ExecuteOnItemReceiveHooks(this->getItemEntry);
gSaveContext.pendingIceTrapCount++; gSaveContext.pendingIceTrapCount++;
return 1; return 1;
} }
@ -12790,7 +12791,6 @@ s32 func_8084DFF4(PlayState* play, Player* this) {
this->unk_862 = 0; this->unk_862 = 0;
gSaveContext.pendingIceTrapCount++; gSaveContext.pendingIceTrapCount++;
Player_SetPendingFlag(this, play); Player_SetPendingFlag(this, play);
GameInteractor_ExecuteOnItemReceiveHooks(giEntry);
} }
this->getItemId = GI_NONE; this->getItemId = GI_NONE;
@ -12949,7 +12949,6 @@ void func_8084E6D4(Player* this, PlayState* play) {
} }
} else { } else {
func_80832DBC(this); func_80832DBC(this);
if ((this->getItemId == GI_ICE_TRAP && !gSaveContext.n64ddFlag) || if ((this->getItemId == GI_ICE_TRAP && !gSaveContext.n64ddFlag) ||
(gSaveContext.n64ddFlag && (this->getItemId == RG_ICE_TRAP || this->getItemEntry.getItemId == RG_ICE_TRAP))) { (gSaveContext.n64ddFlag && (this->getItemId == RG_ICE_TRAP || this->getItemEntry.getItemId == RG_ICE_TRAP))) {
this->stateFlags1 &= ~(PLAYER_STATE1_GETTING_ITEM | PLAYER_STATE1_ITEM_OVER_HEAD); 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, 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); this->actor.world.pos.y + 100.0f, this->actor.world.pos.z, 0, 0, 0, 0, true);
func_8083C0E8(this, play); func_8083C0E8(this, play);
GameInteractor_ExecuteOnItemReceiveHooks(this->getItemEntry); } else if (gSaveContext.n64ddFlag) {
gSaveContext.pendingIceTrapCount++;
Player_SetPendingFlag(this, play);
func_8083C0E8(this, play);
} else { } else {
this->actor.colChkInfo.damage = 0; this->actor.colChkInfo.damage = 0;
func_80837C0C(play, this, 3, 0.0f, 0.0f, 0, 20); 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; return;
} }