From 5822c33268bc4aef5ef94d3e5d24ed2fe83d5417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Tue, 30 Dec 2025 20:11:27 +0000 Subject: [PATCH] RT_ICE_STALAGMITE_CLIP, RT_ICE_STALAGMITE_HOOKSHOT (#5909) Coming back from block room to hub, the clip is different, instead it's by wall that both ages can get past with pretty specific sidehop. This is pretty niche since generally logic isn't doing reverse ice cavern --- .../location_access/dungeons/ganons_castle.cpp | 2 +- .../randomizer/location_access/dungeons/ice_cavern.cpp | 10 +++++----- soh/soh/Enhancements/randomizer/logic.cpp | 3 ++- soh/soh/Enhancements/randomizer/randomizerTypes.h | 2 ++ soh/soh/Enhancements/randomizer/settings.cpp | 7 +++++++ 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp index 5519fe37f..052def606 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp @@ -134,7 +134,7 @@ void RegionTable_Init_GanonsCastle() { areaTable[RR_GANONS_CASTLE_WATER_TRIAL_BLUE_FIRE_ROOM] = Region("Ganon's Castle Water Trial Blue Fire Room", SCENE_INSIDE_GANONS_CASTLE, { //Events - EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return true;}), + EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return logic->CanClearStalagmite() || ctx->GetTrickOption(RT_ICE_STALAGMITE_CLIP);}), }, { //Locations LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, true), diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp index d4e99d185..753fab8b0 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp @@ -40,7 +40,7 @@ void RegionTable_Init_IceCavern() { Entrance(RR_ICE_CAVERN_BEGINNING, []{return true;}), Entrance(RR_ICE_CAVERN_MAP_ROOM, []{return (logic->IsAdult || (ctx->GetTrickOption(RT_GROUND_JUMP_HARD) && logic->CanGroundJump())) && logic->CanClearStalagmite();}), Entrance(RR_ICE_CAVERN_COMPASS_ROOM, []{return Here(RR_ICE_CAVERN_HUB, []{return logic->BlueFire();});}), - Entrance(RR_ICE_CAVERN_BLOCK_ROOM, []{return Here(RR_ICE_CAVERN_HUB, []{return logic->BlueFire();}) && logic->CanClearStalagmite();}), + Entrance(RR_ICE_CAVERN_BLOCK_ROOM, []{return Here(RR_ICE_CAVERN_HUB, []{return logic->BlueFire();}) && (logic->CanClearStalagmite() || ctx->GetTrickOption(RT_ICE_STALAGMITE_CLIP));}), }); areaTable[RR_ICE_CAVERN_MAP_ROOM] = Region("Ice Cavern Map Room", SCENE_ICE_CAVERN, { @@ -66,8 +66,8 @@ void RegionTable_Init_IceCavern() { EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return true;}), }, { //Locations - LOCATION(RC_ICE_CAVERN_COMPASS_CHEST, logic->CanClearStalagmite() && logic->BlueFire()), - LOCATION(RC_ICE_CAVERN_FREESTANDING_POH, logic->CanClearStalagmite() && logic->BlueFire()), // can skip blue fire with rang trick + LOCATION(RC_ICE_CAVERN_COMPASS_CHEST, (logic->IsChild || logic->CanClearStalagmite() || ctx->GetTrickOption(RT_ICE_STALAGMITE_CLIP)) && logic->BlueFire()), + LOCATION(RC_ICE_CAVERN_FREESTANDING_POH, (logic->CanClearStalagmite() || ctx->GetTrickOption(RT_ICE_STALAGMITE_CLIP)) && logic->BlueFire()), // can skip blue fire with rang trick LOCATION(RC_ICE_CAVERN_GS_HEART_PIECE_ROOM, logic->HookshotOrBoomerang()), }, { //Exits @@ -87,7 +87,7 @@ void RegionTable_Init_IceCavern() { LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_3, logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG)), }, { //Exits - Entrance(RR_ICE_CAVERN_HUB, []{return logic->CanClearStalagmite();}), + Entrance(RR_ICE_CAVERN_HUB, []{return logic->CanClearStalagmite() || ctx->GetTrickOption(RT_ICE_STALAGMITE_CLIP);}), Entrance(RR_ICE_CAVERN_BEFORE_FINAL_ROOM, []{return Here(RR_ICE_CAVERN_BLOCK_ROOM, []{return logic->BlueFire();});}), }); @@ -162,7 +162,7 @@ void RegionTable_Init_IceCavern() { areaTable[RR_ICE_CAVERN_MQ_MAP_ROOM] = Region("Ice Cavern MQ Map Room", SCENE_ICE_CAVERN, { //Events //Child can fit between the stalagmites on the left hand side - EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return logic->IsChild || logic->CanClearStalagmite();}), + EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return logic->IsChild || logic->CanClearStalagmite() || ctx->GetTrickOption(RT_ICE_STALAGMITE_CLIP);}), }, { //Locations LOCATION(RC_ICE_CAVERN_MQ_MAP_CHEST, logic->BlueFire() && Here(RR_ICE_CAVERN_MQ_MAP_ROOM, []{return logic->CanHitSwitch();})), diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 445851cbd..bb835c440 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -1079,7 +1079,8 @@ bool Logic::CanJumpslash() { } bool Logic::CanClearStalagmite() { - return CanJumpslash() || HasExplosives(); + return CanJumpslash() || HasExplosives() || + (ctx->GetTrickOption(RT_ICE_STALAGMITE_HOOKSHOT) && CanUse(RG_HOOKSHOT)); } bool Logic::CanHitSwitch(EnemyDistance distance, bool inWater) { diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 6d5036945..2d4355015 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -3998,6 +3998,8 @@ typedef enum { RT_SPIRIT_MQ_SUN_BLOCK_GS, RT_SPIRIT_MQ_LOWER_ADULT, RT_SPIRIT_MQ_FROZEN_EYE, + RT_ICE_STALAGMITE_CLIP, + RT_ICE_STALAGMITE_HOOKSHOT, RT_ICE_BLOCK_GS, RT_ICE_MQ_RED_ICE_GS, RT_ICE_MQ_SCARECROW, diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 8715b154b..ba272c0e6 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -1121,6 +1121,13 @@ void Settings::CreateOptions() { "Spirit Temple MQ Frozen Eye Switch without Fire", "You can melt the ice by shooting an arrow through a torch. The only way to find a line of sight for " "this shot is to first spawn a Song of Time block, and then stand on the very edge of it."); + OPT_TRICK(RT_ICE_STALAGMITE_CLIP, RCQUEST_BOTH, RA_ICE_CAVERN, { Tricks::Tag::NOVICE }, + "Ice Cavern Stalagmite Clips", + "Most stalagmites blocking path in Ice Cavern can be clipped past with basic movement. Also applies to " + "Water Trial."); + OPT_TRICK(RT_ICE_STALAGMITE_HOOKSHOT, RCQUEST_BOTH, RA_ICE_CAVERN, { Tricks::Tag::NOVICE }, + "Ice Cavern Stalagmites with Hookshot", + "Shooting stalagmites with hookshot in the right way also breaks them. Also applies to Water Trial."); OPT_TRICK(RT_ICE_BLOCK_GS, RCQUEST_VANILLA, RA_ICE_CAVERN, { Tricks::Tag::INTERMEDIATE }, "Ice Cavern Block Room GS with Hover Boots", "The Hover Boots can be used to get in front of the Skulltula to kill it with a jump slash. Then, the "