summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Dubé <serprex@users.noreply.github.com>2025-12-31 02:54:41 +0000
committerGitHub <noreply@github.com>2025-12-31 02:54:41 +0000
commit8cc02fd23565ceebce03f8bed7f9b8084efd85b5 (patch)
tree6e32e3f915441f78bafad49f32fa5a0d16716343
parent8ee637880dfe41778324cee3646bdb2c6a286d27 (diff)
Add missing extension trick to Shadow MQ, fix 2 logic mixups in GTG (#5983)
Also allow Giant's Knife to logically hit these switches Ganon's Castle diamond switch can be hit with bomb by setting bomb down instead of shield dropping
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp2
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp2
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp6
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp2
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/goron_city.cpp7
-rw-r--r--soh/soh/Enhancements/randomizer/logic.cpp34
-rw-r--r--soh/soh/Enhancements/randomizer/randomizerTypes.h1
-rw-r--r--soh/soh/Enhancements/randomizer/settings.cpp3
8 files changed, 34 insertions, 23 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 859172230..aa64b85de 100644
--- a/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp
@@ -214,7 +214,7 @@ void RegionTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_SPIRIT_TRIAL_BEFORE_SWITCH] = Region("Ganon's Castle Spirit Trial Before Switch", SCENE_INSIDE_GANONS_CASTLE, {}, {
//Locations
- LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, logic->CanJumpslashExceptHammer() || logic->HasExplosives()),
+ LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, logic->CanJumpslash() || logic->HasExplosives() || logic->CanUse(RG_GIANTS_KNIFE)),
}, {
//Exits
Entrance(RR_GANONS_CASTLE_SPIRIT_TRIAL_BEAMOS_ROOM, []{return true;}),
diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp
index d8d7cb64e..d70844bea 100644
--- a/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp
@@ -272,7 +272,7 @@ void RegionTable_Init_GerudoTrainingGround() {
//implies logic->CanKillEnemy(RE_SPIKE)
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_FREEZARD)),
}, {
- Entrance(RR_GERUDO_TRAINING_GROUND_MQ_ROOM_BEHIND_BLOCK, []{return true;}),
+ Entrance(RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE] = Region("Gerudo Training Ground MQ Statue Room Ledge", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp
index ae24f1a78..02a79384e 100644
--- a/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp
@@ -514,7 +514,7 @@ void RegionTable_Init_ShadowTemple() {
Entrance(RR_SHADOW_TEMPLE_MQ_B2_TO_B3_CORRIDOR_B3, []{return logic->CanUse(RG_LONGSHOT);}),
Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, []{return logic->Get(LOGIC_SHADOW_MQ_PIT_STAIRS);}),
Entrance(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT_DOOR_LEDGE, []{return logic->CanUse(RG_HOVER_BOOTS) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ_PLATFORM) || logic->CanUse(RG_LENS_OF_TRUTH));}),
- Entrance(RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM, []{return Here(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, []{return logic->CanJumpslash() || logic->HasExplosives();});}),
+ Entrance(RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM, []{return Here(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, []{return logic->CanJumpslash() || logic->HasExplosives() || logic->CanUse(RG_GIANTS_KNIFE) || (ctx->GetTrickOption(RT_HOOKSHOT_EXTENSION) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)));});}),
});
areaTable[RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT_DOOR_LEDGE] = Region("Shadow Temple MQ Upper Huge Pit Door Ledge", SCENE_SHADOW_TEMPLE, {}, {}, {
@@ -669,8 +669,8 @@ void RegionTable_Init_ShadowTemple() {
//Locations
LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_CHASM_WEST_POT, logic->CanBreakPots()),
LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_CHASM_EAST_POT, logic->CanBreakPots()),
- LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_UPPER_LEFT_HEART, logic->CanUse(RG_SONG_OF_TIME) && logic->CanHitEyeTargets() && logic->CanUse(RG_LONGSHOT)),
- LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_UPPER_RIGHT_HEART, logic->CanUse(RG_SONG_OF_TIME) && logic->CanHitEyeTargets() && logic->CanUse(RG_LONGSHOT)),
+ LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_UPPER_LEFT_HEART, logic->Get(LOGIC_SHADOW_MQ_EYE_SWITCH_ACROSS_CHASM) && logic->CanUse(RG_LONGSHOT)),
+ LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_UPPER_RIGHT_HEART, logic->Get(LOGIC_SHADOW_MQ_EYE_SWITCH_ACROSS_CHASM) && logic->CanUse(RG_LONGSHOT)),
//There's invisible floor collision that makes aiming for the heart with rang harder than it should be, so it's a trick.
LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_LOWER_HEART, logic->IsAdult),
}, {
diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp
index 2127ab254..6d2c9f4d0 100644
--- a/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp
@@ -133,7 +133,7 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Region("Spirit Temple Beyond Final Locked Door", SCENE_SPIRIT_TEMPLE, {}, {
//Locations
LOCATION(RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST, logic->CanUse(RG_ZELDAS_LULLABY) && ((logic->TakeDamage() && ctx->GetTrickOption(RT_FLAMING_CHESTS)) || (logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_HOOKSHOT)))),
- LOCATION(RC_SPIRIT_TEMPLE_TOPMOST_CHEST, (logic->CanUse(RG_MIRROR_SHIELD) && (logic->CanJumpslash() || logic->HasExplosives() || (ctx->GetTrickOption(RT_HOOKSHOT_EXTENSION) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_HOOKSHOT))))) ||
+ LOCATION(RC_SPIRIT_TEMPLE_TOPMOST_CHEST, (logic->CanUse(RG_MIRROR_SHIELD) && (logic->CanJumpslash() || logic->HasExplosives() || logic->CanUse(RG_GIANTS_KNIFE) || (ctx->GetTrickOption(RT_HOOKSHOT_EXTENSION) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_HOOKSHOT))))) ||
(ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))),
LOCATION(RC_SPIRIT_TEMPLE_ADULT_CLIMB_LEFT_HEART, logic->CanUse(RG_HOOKSHOT)),
LOCATION(RC_SPIRIT_TEMPLE_ADULT_CLIMB_RIGHT_HEART, logic->CanUse(RG_HOOKSHOT)),
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/goron_city.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/goron_city.cpp
index 7edb4392a..9641da2fa 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/goron_city.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/goron_city.cpp
@@ -26,7 +26,6 @@ void RegionTable_Init_GoronCity() {
LOCATION(RC_GC_ROLLING_GORON_AS_ADULT, logic->Get(LOGIC_GORON_CITY_STOP_ROLLING_GORON_AS_ADULT)),
LOCATION(RC_GC_GS_BOULDER_MAZE, logic->IsChild && logic->BlastOrSmash()),
LOCATION(RC_GC_GS_CENTER_PLATFORM, logic->IsAdult && logic->CanAttack()),
- LOCATION(RC_GC_MEDIGORON, logic->IsAdult && (logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET)) && GetCheckPrice() <= GetWalletCapacity()),
LOCATION(RC_GC_MAZE_GOSSIP_STONE_FAIRY, (logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)) && logic->CallGossipFairyExceptSuns()),
LOCATION(RC_GC_MAZE_GOSSIP_STONE_FAIRY_BIG, (logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)) && logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_GC_MAZE_GOSSIP_STONE, logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)),
@@ -47,8 +46,12 @@ void RegionTable_Init_GoronCity() {
Entrance(RR_GC_GROTTO_PLATFORM, []{return logic->IsAdult && ((logic->CanUse(RG_SONG_OF_TIME) && ((logic->EffectiveHealth() > 2) || logic->CanUse(RG_GORON_TUNIC) || logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_NAYRUS_LOVE))) || (logic->EffectiveHealth() > 1 && logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_HOOKSHOT)) || (logic->CanUse(RG_NAYRUS_LOVE) && logic->CanUse(RG_HOOKSHOT)) || (logic->EffectiveHealth() > 2 && logic->CanUse(RG_HOOKSHOT) && ctx->GetTrickOption(RT_GC_GROTTO)));}),
});
- areaTable[RR_GC_MEDIGORON] = Region("GC Medigoron", SCENE_GORON_CITY, {}, {
+ areaTable[RR_GC_MEDIGORON] = Region("GC Medigoron", SCENE_GORON_CITY, {
+ //Events
+ EventAccess(LOGIC_MEDIGORON, []{return logic->HasItem(RG_ADULT_WALLET) && GetCheckPrice(RC_GC_MEDIGORON) <= GetWalletCapacity();}),
+ }, {
//Locations
+ LOCATION(RC_GC_MEDIGORON, logic->IsAdult && GetCheckPrice() <= GetWalletCapacity()),
LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()),
LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE, true),
diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp
index 06f1e16ec..136acb3dc 100644
--- a/soh/soh/Enhancements/randomizer/logic.cpp
+++ b/soh/soh/Enhancements/randomizer/logic.cpp
@@ -78,10 +78,13 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RG_HYLIAN_SHIELD:
case RG_MIRROR_SHIELD:
case RG_MASTER_SWORD:
- case RG_BIGGORON_SWORD:
case RG_IRON_BOOTS:
case RG_HOVER_BOOTS:
return CheckEquipment(RandoGetToEquipFlag.at(itemName));
+ case RG_GIANTS_KNIFE:
+ return CheckEquipment(RandoGetToEquipFlag.at(itemName)) || Get(LOGIC_MEDIGORON);
+ case RG_BIGGORON_SWORD:
+ return CheckEquipment(RandoGetToEquipFlag.at(itemName)) && mSaveContext->bgsFlag;
case RG_GORONS_BRACELET:
return CurrentUpgrade(UPG_STRENGTH);
case RG_SILVER_GAUNTLETS:
@@ -307,6 +310,7 @@ bool Logic::CanUse(RandomizerGet itemName) {
return IsAdult; // || MirrorShieldAsChild;
case RG_MASTER_SWORD:
return IsAdult; // || MasterSwordAsChild;
+ case RG_GIANTS_KNIFE:
case RG_BIGGORON_SWORD:
return IsAdult; // || BiggoronSwordAsChild;
case RG_SILVER_GAUNTLETS:
@@ -1093,7 +1097,7 @@ bool Logic::CanJumpslash() {
}
bool Logic::CanClearStalagmite() {
- return CanJumpslash() || HasExplosives() ||
+ return CanJumpslash() || HasExplosives() || CanUse(RG_GIANTS_KNIFE) ||
(ctx->GetTrickOption(RT_ICE_STALAGMITE_HOOKSHOT) && CanUse(RG_HOOKSHOT));
}
@@ -1102,7 +1106,7 @@ bool Logic::CanHitSwitch(EnemyDistance distance, bool inWater) {
switch (distance) {
case ED_CLOSE:
case ED_SHORT_JUMPSLASH:
- hit = CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MEGATON_HAMMER);
+ hit = CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_GIANTS_KNIFE);
[[fallthrough]];
case ED_MASTER_SWORD_JUMPSLASH:
hit = hit || CanUse(RG_MASTER_SWORD);
@@ -1197,7 +1201,8 @@ bool Logic::CanReflectNuts() {
bool Logic::CanCutShrubs() {
return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BOOMERANG) || HasExplosives() || CanUse(RG_MASTER_SWORD) ||
- CanUse(RG_MEGATON_HAMMER) || CanUse(RG_BIGGORON_SWORD) || HasItem(RG_GORONS_BRACELET);
+ CanUse(RG_MEGATON_HAMMER) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_GIANTS_KNIFE) ||
+ HasItem(RG_GORONS_BRACELET);
}
bool Logic::CanStunDeku() {
@@ -1403,13 +1408,14 @@ bool Logic::SmallKeys(s16 scene, uint8_t requiredAmount) {
}
std::map<RandomizerGet, uint32_t> Logic::RandoGetToEquipFlag = {
- { RG_KOKIRI_SWORD, EQUIP_FLAG_SWORD_KOKIRI }, { RG_MASTER_SWORD, EQUIP_FLAG_SWORD_MASTER },
- { RG_BIGGORON_SWORD, EQUIP_FLAG_SWORD_BGS }, { RG_DEKU_SHIELD, EQUIP_FLAG_SHIELD_DEKU },
- { RG_HYLIAN_SHIELD, EQUIP_FLAG_SHIELD_HYLIAN }, { RG_MIRROR_SHIELD, EQUIP_FLAG_SHIELD_MIRROR },
- { RG_GORON_TUNIC, EQUIP_FLAG_TUNIC_GORON }, { RG_ZORA_TUNIC, EQUIP_FLAG_TUNIC_ZORA },
- { RG_BUY_DEKU_SHIELD, EQUIP_FLAG_SHIELD_DEKU }, { RG_BUY_HYLIAN_SHIELD, EQUIP_FLAG_SHIELD_HYLIAN },
- { RG_BUY_GORON_TUNIC, EQUIP_FLAG_TUNIC_GORON }, { RG_BUY_ZORA_TUNIC, EQUIP_FLAG_TUNIC_ZORA },
- { RG_IRON_BOOTS, EQUIP_FLAG_BOOTS_IRON }, { RG_HOVER_BOOTS, EQUIP_FLAG_BOOTS_HOVER }
+ { RG_KOKIRI_SWORD, EQUIP_FLAG_SWORD_KOKIRI }, { RG_MASTER_SWORD, EQUIP_FLAG_SWORD_MASTER },
+ { RG_GIANTS_KNIFE, EQUIP_FLAG_SWORD_BGS }, { RG_BIGGORON_SWORD, EQUIP_FLAG_SWORD_BGS },
+ { RG_DEKU_SHIELD, EQUIP_FLAG_SHIELD_DEKU }, { RG_HYLIAN_SHIELD, EQUIP_FLAG_SHIELD_HYLIAN },
+ { RG_MIRROR_SHIELD, EQUIP_FLAG_SHIELD_MIRROR }, { RG_GORON_TUNIC, EQUIP_FLAG_TUNIC_GORON },
+ { RG_ZORA_TUNIC, EQUIP_FLAG_TUNIC_ZORA }, { RG_BUY_DEKU_SHIELD, EQUIP_FLAG_SHIELD_DEKU },
+ { RG_BUY_HYLIAN_SHIELD, EQUIP_FLAG_SHIELD_HYLIAN }, { RG_BUY_GORON_TUNIC, EQUIP_FLAG_TUNIC_GORON },
+ { RG_BUY_ZORA_TUNIC, EQUIP_FLAG_TUNIC_ZORA }, { RG_IRON_BOOTS, EQUIP_FLAG_BOOTS_IRON },
+ { RG_HOVER_BOOTS, EQUIP_FLAG_BOOTS_HOVER }
};
std::map<RandomizerGet, uint32_t> Logic::RandoGetToRandInf = {
@@ -1858,18 +1864,18 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
} break;
case ITEMTYPE_EQUIP: {
RandomizerGet itemRG = item.GetRandomizerGet();
- if (itemRG == RG_GIANTS_KNIFE || itemRG == RG_DEKU_SHIELD || itemRG == RG_HYLIAN_SHIELD) {
+ if (itemRG == RG_DEKU_SHIELD || itemRG == RG_HYLIAN_SHIELD) {
return;
}
uint32_t equipId = RandoGetToEquipFlag.find(itemRG)->second;
if (!state) {
mSaveContext->inventory.equipment &= ~equipId;
- if (equipId == EQUIP_FLAG_SWORD_BGS) {
+ if (equipId == EQUIP_FLAG_SWORD_BGS && itemRG != RG_GIANTS_KNIFE) {
mSaveContext->bgsFlag = false;
}
} else {
mSaveContext->inventory.equipment |= equipId;
- if (equipId == EQUIP_FLAG_SWORD_BGS) {
+ if (equipId == EQUIP_FLAG_SWORD_BGS && itemRG != RG_GIANTS_KNIFE) {
mSaveContext->bgsFlag = true;
}
}
diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h
index 1880a64ba..d01ab357c 100644
--- a/soh/soh/Enhancements/randomizer/randomizerTypes.h
+++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h
@@ -234,6 +234,7 @@ typedef enum {
LOGIC_CHILD_SCARECROW,
LOGIC_ADULT_SCARECROW,
LOGIC_CARPET_MERCHANT,
+ LOGIC_MEDIGORON,
LOGIC_COULD_PLAY_BOWLING,
LOGIC_BIG_POE_KILL,
LOGIC_BUILD_RAINBOW_BRIDGE,
diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp
index ce365146e..0a8fda379 100644
--- a/soh/soh/Enhancements/randomizer/settings.cpp
+++ b/soh/soh/Enhancements/randomizer/settings.cpp
@@ -424,7 +424,8 @@ void Settings::CreateOptions() {
"- Crossing Gerudo Valley with Hookshot\n"
"- Retrieving DMT Gold Skulltula beside bomb flower\n"
"- Hitting switch through wall in Spirit Temple's big mirror room with Bow, Slingshot, or Hookshot\n"
- "- Hitting switch through wall in Spirit Trial with Bow or Slingshot");
+ "- Hitting switch through wall in Spirit Trial with Bow or Slingshot\n"
+ "- Hitting switch through gate in Shadow Temple MQ with Bow or Slingshot");
OPT_TRICK(RT_BIG_SKULLTULA_PAUSE_LIFT, RCQUEST_BOTH, RA_NONE, { Tricks::Tag::NOVICE, Tricks::Tag::GLITCH },
"Lift Big Skulltulas with Pausing",
"Pausing while a big skulltula is bobbing upwards slightly lifts it,\n"