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
This commit is contained in:
@@ -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;}),
|
||||
|
||||
@@ -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, {}, {}, {
|
||||
|
||||
@@ -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),
|
||||
}, {
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user