From 076b138a80201647baa7e50125ad3437182e7f76 Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Sun, 29 Jun 2025 14:37:34 +0100 Subject: [PATCH] finish implementation and cleanup --- .../randomizer/location_access.cpp | 156 ++++++++---------- .../Enhancements/randomizer/location_access.h | 2 +- .../dungeons/spirit_temple.cpp | 43 ++--- soh/soh/Enhancements/randomizer/logic.cpp | 75 +++++++-- soh/soh/Enhancements/randomizer/logic.h | 7 +- soh/soh/Enhancements/randomizer/settings.cpp | 8 +- 6 files changed, 153 insertions(+), 138 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp index abf32e49b..f6f87efea 100644 --- a/soh/soh/Enhancements/randomizer/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -573,14 +573,15 @@ bool Here(const RandomizerRegion region, ConditionFn condition) { * Additionally, if it is possible to enter spirit in reverse, there are 2 more universes: * In the third universe, adult enters in reverse, and wastes all the keys so noone can enter through the front * In the forth, child manages to do the same, and lock people out of the front - * All access from the boss door in shared areas is Certain + * However all access from the boss door in Statue Room and adjacent areas is Certain, so this is not usually + relevant * While other universes exist, such as both ages entering in reverse or child using their key, getting stuck, then coming back to do the dungeon as adult, these are all sub-possibilities of these 4 universes * As we do not know which universe we are in until the player chooses one in-game, - we must be able to collect the check in both universes + we must be able to collect the check in all universes * When an Age can no longer be kept out by conflicting universes, that age is said to have Certain Access to a region @@ -592,61 +593,46 @@ bool Here(const RandomizerRegion region, ConditionFn condition) { * We must check for these universes manually as we allow technical access with minimum keys for * technical reasons as otherwise the logic code will never run - * The first and 3rd column list how many keys are needed for each age to have Certain Access - * the second column is child keys in case there's Child reverse access, due to an edge case in MQ spirit logic - * where the broken wall room can be reached with 6 keys if you can hit switches and have reverse Child access + * The 1st and 3rd column list how many keys are needed for each age to have Certain Access from the front + * the 2nd and 4th column list how many keys are needed for each age to have Certain Access from the boss door + * Sometimes, we may check for a higher number of keys in the condition, this happens in cases where the number of + keys + * for Certain Access depends on a certain condition, the listed number is the lowest possible to make sure the + condition is checked. - * The first condition is the combined conditions needed to move from the 1F child lock to the area being checks - * the second condition is the same for adult 1F lock, and the third is the access from the boss door. + * The 1st condition is the combined conditions needed to move from the 1F child lock to the area being checks + * the 2nd condition is the same for adult 1F lock, and the 3rd is the access from the boss door. */ -bool SpiritExplosiveKeyLogic() { - return logic->SmallKeys(RR_SPIRIT_TEMPLE, logic->HasExplosives() ? 1 - : ctx->GetOption(RSK_BOMBCHU_BAG) && logic->BombchuRefill() ? 2 - : 3); -} - -//!QUANTUM LOGIC! -//With 3 keys, you cannot lock adult out of leaving spirit onto the hands and jumping down, as you would have to -//open the west hand door and then adult could climb through sun block room to jump down from there -//This requires that adult can complete both routes -//If we have the longshot, we can also guarantee access to the outer west hand as you can longshot from the east hand to the west -//Implies CanKillEnemy(RE_IRON_KNUCKLE) -bool OuterWestHandLogic(){ - return logic->HasExplosives()/* && logic->CanClimbHigh() && str0*/ && logic->SmallKeys(RR_SPIRIT_TEMPLE, logic->HasItem(RG_LONGSHOT) ? 3 : 5); -} - // clang-format off std::map Region::spiritLogicData = { //Vanilla Child uses ExplosiveKeyLogic here because they need to exist for shared adult checks - {RR_SPIRIT_TEMPLE_WEST_CLIMB_BASE, {5, 0, 3, 0, []{return true;}, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, - {RR_SPIRIT_TEMPLE_SUN_ON_FLOOR, {5, 0, 3, 0, []{return true/*logic->CanClimbHigh()*/;}, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, - {RR_SPIRIT_TEMPLE_2F_MIRROR, {5, 0, 3, 0, []{return logic->CanUse(RG_HOOKSHOT) && logic->SpiritSunOnFloorToStatue();}, []{return true/*logic->CanClimbHigh()*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}}, - {RR_SPIRIT_TEMPLE_STATUE_ROOM_WEST, {5, 0, 3, 0, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh()*/;}, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, - {RR_SPIRIT_TEMPLE_INNER_WEST_HAND, {5, 0, 3, 0, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh()*/;}, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, - {RR_SPIRIT_TEMPLE_GS_LEDGE, {5, 0, 3, 0, []{return SpiritExplosiveKeyLogic() && logic->SpiritWestToSkull()/* && logic->CanClimbHigh()*/;}, []{return SpiritExplosiveKeyLogic() && logic->SpiritWestToSkull()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->SpiritWestToSkull()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}}, - {RR_SPIRIT_TEMPLE_STATUE_ROOM, {5, 0, 3, 0, []{return SpiritExplosiveKeyLogic();}, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true;}}}, + {RR_SPIRIT_TEMPLE_WEST_CLIMB_BASE, {5, 0, 3, 0, []{return true;}, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, + {RR_SPIRIT_TEMPLE_SUN_ON_FLOOR, {5, 0, 3, 0, []{return true/*logic->CanClimbHigh()*/;}, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, + {RR_SPIRIT_TEMPLE_2F_MIRROR, {5, 0, 3, 0, []{return logic->CanUse(RG_HOOKSHOT) && logic->SpiritSunOnFloorToStatue();}, []{return true/*logic->CanClimbHigh()*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}}, + {RR_SPIRIT_TEMPLE_STATUE_ROOM_WEST, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh()*/;}, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, + {RR_SPIRIT_TEMPLE_INNER_WEST_HAND, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh()*/;}, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, + {RR_SPIRIT_TEMPLE_GS_LEDGE, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic() && logic->SpiritWestToSkull()/* && logic->CanClimbHigh()*/;}, []{return logic->SpiritExplosiveKeyLogic() && logic->SpiritWestToSkull()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->SpiritWestToSkull()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}}, + {RR_SPIRIT_TEMPLE_STATUE_ROOM, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic();}, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true;}}}, //Assumes SpiritSunBlockSouthLedge() for all access - {RR_SPIRIT_TEMPLE_SUN_BLOCK_SOUTH_LEDGE, {5, 0, 3, 0, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*((logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)) && str0) || (logic->CanKillEnemy(RE_BEAMOS) && logic->CanUse(RG_LONGSHOT))*/;}}}, - {RR_SPIRIT_TEMPLE_SKULLTULA_STAIRS, {5, 0, 3, 0, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*((logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)) && str0) || (logic->CanKillEnemy(RE_BEAMOS) && logic->CanUse(RG_LONGSHOT))*/;}}}, - {RR_SPIRIT_TEMPLE_OUTER_WEST_HAND, {5, 5, 3, 3, []{return OuterWestHandLogic();}, []{return OuterWestHandLogic();}, []{return OuterWestHandLogic();}}}, - {RR_SPIRIT_TEMPLE_STATUE_ROOM_EAST, {5, 0, 3, 0, []{return SpiritExplosiveKeyLogic() && logic->CanUse(RG_HOOKSHOT)/* && logic->CanClimbHigh()*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}}, - {RR_SPIRIT_TEMPLE_INNER_EAST_HAND, {5, 0, 3, 0, []{return SpiritExplosiveKeyLogic() && logic->CanUse(RG_HOOKSHOT)/* && logic->CanClimbHigh()*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}}, - {RR_SPIRIT_TEMPLE_SHORTCUT_SWITCH, {5, 0, 3, 0, []{return SpiritExplosiveKeyLogic() && logic->CanUse(RG_HOOKSHOT) && logic->SpiritEastToSwitch();}, []{return logic->SpiritEastToSwitch()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->SpiritEastToSwitch() && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}}}, - //MQ /*&& logic->CanClimbHigh()*/ - {RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, {7, 9, 7, 7, []{return true;}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6) && logic->CanHitSwitch()/* && logic->Climb*/;}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6) && logic->CanHitSwitch()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}}, - {RR_SPIRIT_TEMPLE_MQ_SUN_ON_FLOOR, {7, 9, 7, 7, []{return logic->CanHitSwitch()/* && logic->CanClimbHigh()*/;}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6)/* && logic->Climb*/;}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6)/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}}, - {RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_WEST, {7, 0, 0, 0, []{return logic->CanHitSwitch()/* && logic->CanClimbHigh()*/;}, []{return true/*logic->Climb*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, - {RR_SPIRIT_TEMPLE_MQ_POT_LEDGE, {7, 0, 0, 0, []{return logic->CanHitSwitch() && logic->MQSpiritWestToPots()/* && logic->CanClimbHigh()*/;}, []{return logic->MQSpiritWestToPots()/* && logic->Climb*/;}, []{return /*logic->CanUse(RG_HOVER_BOOTS) || (logic->CanClimb() && */logic->MQSpiritWestToPots()/*)*/;}}}, - {RR_SPIRIT_TEMPLE_MQ_INNER_WEST_HAND, {7, 0, 0, 0, []{return logic->CanHitSwitch() && logic->MQSpiritWestToPots()/* && logic->CanClimbHigh()*/;}, []{return logic->MQSpiritWestToPots()/* && logic->Climb*/;}, []{return /*logic->CanUse(RG_HOVER_BOOTS) || (logic->CanClimb() && */logic->MQSpiritWestToPots()/*)*/;}}}, - {RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, {7, 0, 0, 0, []{return logic->CanHitSwitch()/* && logic->CanClimbHigh()*/;}, []{return true;}, []{return true;}}}, - {RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, {7, 0, 0, 0, []{return logic->CanHitSwitch() && logic->MQSpiritStatueToSunBlock()/* && logic->CanClimbHigh()*/;}, []{return logic->MQSpiritStatueToSunBlock()/* && logic->Climb*/;}, []{return logic->MQSpiritStatueToSunBlock()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}}, - //RANDOTODO FIX - {RR_SPIRIT_TEMPLE_MQ_OUTER_WEST_HAND, {7, 7, 4, 4, []{return logic->CanHitSwitch() && logic->MQSpiritStatueToSunBlock() //For the purpose of shared, adult needs to get to west side via BOTH possible routes for it to count //Only using HasItem here for adult items so child can pass this check - /* && logic->CanClimbHigh() && str0*/;}, []{return logic->MQSpirit4KeyWestHand();}, []{return logic->CouldMQSpirit4KeyWestHand();}}}, + {RR_SPIRIT_TEMPLE_SUN_BLOCK_SOUTH_LEDGE, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*((logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)) && str0) || (logic->CanKillEnemy(RE_BEAMOS) && logic->CanUse(RG_LONGSHOT))*/;}}}, + {RR_SPIRIT_TEMPLE_SKULLTULA_STAIRS, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return true/*((logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)) && str0) || (logic->CanKillEnemy(RE_BEAMOS) && logic->CanUse(RG_LONGSHOT))*/;}}}, + {RR_SPIRIT_TEMPLE_OUTER_WEST_HAND, {5, 5, 3, 3, []{return logic->OuterWestHandLogic();}, []{return logic->OuterWestHandLogic();}, []{return logic->OuterWestHandLogic();}}}, + {RR_SPIRIT_TEMPLE_STATUE_ROOM_EAST, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic() && logic->CanUse(RG_HOOKSHOT)/* && logic->CanClimbHigh()*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}}, + {RR_SPIRIT_TEMPLE_INNER_EAST_HAND, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic() && logic->CanUse(RG_HOOKSHOT)/* && logic->CanClimbHigh()*/;}, []{return true/*logic->CanClimbHigh() && str0*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}}, + {RR_SPIRIT_TEMPLE_SHORTCUT_SWITCH, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic() && logic->CanUse(RG_HOOKSHOT) && logic->SpiritEastToSwitch();}, []{return logic->SpiritEastToSwitch()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->SpiritEastToSwitch() && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}}}, + //MQ /*&& logic->CanClimbHigh()*/ + {RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, {7, 6, 7, 7, []{return logic->StatueRoomMQKeyLogic();}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6) && logic->CanHitSwitch()/* && logic->Climb*/;}, []{return logic->StatueRoomMQKeyLogic() && logic->CanHitSwitch()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}}, + {RR_SPIRIT_TEMPLE_MQ_SUN_ON_FLOOR, {7, 6, 7, 7, []{return logic->StatueRoomMQKeyLogic() && logic->CanHitSwitch()/* && logic->CanClimbHigh()*/;}, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6)/* && logic->Climb*/;}, []{return logic->StatueRoomMQKeyLogic()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}}, + {RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_WEST, {7, 0, 0, 0, []{return logic->CanHitSwitch()/* && logic->CanClimbHigh()*/;}, []{return true/*logic->Climb*/;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}}, + {RR_SPIRIT_TEMPLE_MQ_POT_LEDGE, {7, 0, 0, 0, []{return logic->CanHitSwitch() && logic->MQSpiritWestToPots()/* && logic->CanClimbHigh()*/;}, []{return logic->MQSpiritWestToPots()/* && logic->Climb*/;}, []{return /*logic->CanUse(RG_HOVER_BOOTS) || (logic->CanClimb() && */logic->MQSpiritWestToPots()/*)*/;}}}, + {RR_SPIRIT_TEMPLE_MQ_INNER_WEST_HAND, {7, 0, 0, 0, []{return logic->CanHitSwitch() && logic->MQSpiritWestToPots()/* && logic->CanClimbHigh()*/;}, []{return logic->MQSpiritWestToPots()/* && logic->Climb*/;}, []{return /*logic->CanUse(RG_HOVER_BOOTS) || (logic->CanClimb() && */logic->MQSpiritWestToPots()/*)*/;}}}, + {RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, {7, 0, 0, 0, []{return logic->CanHitSwitch()/* && logic->CanClimbHigh()*/;}, []{return true;}, []{return true;}}}, + {RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, {7, 0, 0, 0, []{return logic->CanHitSwitch() && logic->MQSpiritStatueToSunBlock()/* && logic->CanClimbHigh()*/;}, []{return logic->MQSpiritStatueToSunBlock()/* && logic->Climb*/;}, []{return logic->MQSpiritStatueToSunBlock()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}}, + {RR_SPIRIT_TEMPLE_MQ_OUTER_WEST_HAND, {7, 7, 4, 4, []{return logic->CanHitSwitch() && logic->OuterWestHandMQLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->OuterWestHandMQLogic();}, []{return logic->OuterWestHandMQLogic();}}}, {RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH, {7, 0, 0, 0, []{return logic->CanHitSwitch() && areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH].Here([]{return logic->MQSpiritStatueSouthDoor();}) - /* && logic->CanClimbHigh()*/;}, []{return true;}, []{return areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH].Here([]{return logic->MQSpiritStatueSouthDoor();});}}}, + /* && logic->CanClimbHigh()*/;}, []{return true;}, []{return areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH].Here([]{return logic->MQSpiritStatueSouthDoor();});}}}, }; // clang-format on @@ -655,33 +641,25 @@ bool SpiritCertainAccess(RandomizerRegion region) { if (logic->IsChild) { uint8_t keys = curRegionData.childKeys; uint8_t revKeys = curRegionData.childRevKeys; - bool knownFrontAccess = logic->ForwardsSpiritChild || !logic->IsReverseAccessPossible(); - // revKeys set to 9 means it's the sun on floor room in MQ - // If child enters in reverse, then they have access to Certain Access to Broken Wall room in 6 keys, - // the ability to hit switches and the ability to climb because only child can reach the initial child lock - // without opening the Statue room to Broken Wall Room lock first - if (revKeys == 9){ - revKeys = (logic->ReverseSpiritChild && logic->CanHitSwitch() /* && CanClimbHigh()*/) ? 6 : 7; - } - + bool knownFrontAccess = logic->ForwardsSpiritChild || !logic->IsAdultReverseAccessPossible(); // If we have enough keys that an age cannot be kept out, we have Certain Access // otherwise if we have entered in reverse and can reach from the face, we have Certain Access - return ((knownFrontAccess && curRegionData.childAccess()) && logic->SmallKeys(RR_SPIRIT_TEMPLE, keys)) || - ((logic->ReverseSpiritChild && curRegionData.reverseAccess()) && logic->SmallKeys(RR_SPIRIT_TEMPLE, revKeys)) || - (curRegionData.childAccess() && curRegionData.reverseAccess() && logic->SmallKeys(RR_SPIRIT_TEMPLE, keys > revKeys ? keys : revKeys)); + return ((knownFrontAccess && curRegionData.childAccess()) && logic->SmallKeys(RR_SPIRIT_TEMPLE, keys)) || + ((logic->ReverseSpiritChild && curRegionData.reverseAccess()) && + logic->SmallKeys(RR_SPIRIT_TEMPLE, revKeys)) || + (curRegionData.childAccess() && curRegionData.reverseAccess() && + logic->SmallKeys(RR_SPIRIT_TEMPLE, keys > revKeys ? keys : revKeys)); } else { uint8_t keys = curRegionData.adultKeys; uint8_t revKeys = curRegionData.adultRevKeys; - bool knownFrontAccess = logic->ForwardsSpiritAdult || !logic->IsReverseAccessPossible(); - auto test = logic->IsReverseAccessPossible(); - auto test2 = (knownFrontAccess && curRegionData.adultAccess()); - auto test3 = (logic->ReverseSpiritAdult && curRegionData.reverseAccess()); - auto test4 = curRegionData.adultAccess() && curRegionData.reverseAccess(); + bool knownFrontAccess = logic->ForwardsSpiritAdult || !logic->IsAdultReverseAccessPossible(); // If we have enough keys that an age cannot be kept out, we have Certain Access // otherwise if we have entered in reverse and can reach from the face, we have Certain Access - return ((knownFrontAccess && curRegionData.adultAccess()) && logic->SmallKeys(RR_SPIRIT_TEMPLE, keys)) || - ((logic->ReverseSpiritAdult && curRegionData.reverseAccess()) && logic->SmallKeys(RR_SPIRIT_TEMPLE, revKeys)) || - (curRegionData.adultAccess() && curRegionData.reverseAccess() && logic->SmallKeys(RR_SPIRIT_TEMPLE, keys > revKeys ? keys : revKeys)); + return ((knownFrontAccess && curRegionData.adultAccess()) && logic->SmallKeys(RR_SPIRIT_TEMPLE, keys)) || + ((logic->ReverseSpiritAdult && curRegionData.reverseAccess()) && + logic->SmallKeys(RR_SPIRIT_TEMPLE, revKeys)) || + (curRegionData.adultAccess() && curRegionData.reverseAccess() && + logic->SmallKeys(RR_SPIRIT_TEMPLE, keys > revKeys ? keys : revKeys)); } } @@ -738,16 +716,17 @@ bool SpiritShared(RandomizerRegion region, ConditionFn condition, bool anyAge, R // If Adult can get there and get the check, we can get the check in logic // If reverse spirit is also possible, we need to make sure Adult can get it via reverse entry too - result = (curRegionData.adultAccess() && - (!logic->IsReverseAccessPossible() || curRegionData.reverseAccess) && condition()) || - (otherRegion != RR_NONE && - (Region::spiritLogicData[otherRegion].adultAccess() && - (!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) && - otherCondition())) || - (thirdRegion != RR_NONE && - (Region::spiritLogicData[thirdRegion].adultAccess() && - (!logic->IsReverseAccessPossible() || Region::spiritLogicData[thirdRegion].reverseAccess()) && - thirdCondition())); + result = + (curRegionData.adultAccess() && + (!logic->IsAdultReverseAccessPossible() || curRegionData.reverseAccess) && condition()) || + (otherRegion != RR_NONE && + (Region::spiritLogicData[otherRegion].adultAccess() && + (!logic->IsAdultReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) && + otherCondition())) || + (thirdRegion != RR_NONE && + (Region::spiritLogicData[thirdRegion].adultAccess() && + (!logic->IsAdultReverseAccessPossible() || Region::spiritLogicData[thirdRegion].reverseAccess()) && + thirdCondition())); } } else if (areaTable[region].Adult() && pastAdult) { result = condition(); @@ -762,16 +741,17 @@ bool SpiritShared(RandomizerRegion region, ConditionFn condition, bool anyAge, R // If Child can get there and get the check, we can get the check in logic // If reverse spirit is also possible, we need to make sure Child can get it via reverse entry too - result = (curRegionData.childAccess() && - (!logic->IsReverseAccessPossible() || curRegionData.reverseAccess()) && condition()) || - (otherRegion != RR_NONE && - (Region::spiritLogicData[otherRegion].childAccess() && - (!logic->IsReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) && - otherCondition())) || - (thirdRegion != RR_NONE && - (Region::spiritLogicData[thirdRegion].childAccess() && - (!logic->IsReverseAccessPossible() || Region::spiritLogicData[thirdRegion].reverseAccess()) && - thirdCondition())); + result = + (curRegionData.childAccess() && + (!logic->IsAdultReverseAccessPossible() || curRegionData.reverseAccess()) && condition()) || + (otherRegion != RR_NONE && + (Region::spiritLogicData[otherRegion].childAccess() && + (!logic->IsAdultReverseAccessPossible() || Region::spiritLogicData[otherRegion].reverseAccess()) && + otherCondition())) || + (thirdRegion != RR_NONE && + (Region::spiritLogicData[thirdRegion].childAccess() && + (!logic->IsAdultReverseAccessPossible() || Region::spiritLogicData[thirdRegion].reverseAccess()) && + thirdCondition())); } } // set back age variables diff --git a/soh/soh/Enhancements/randomizer/location_access.h b/soh/soh/Enhancements/randomizer/location_access.h index 0e864c228..3fc597b99 100644 --- a/soh/soh/Enhancements/randomizer/location_access.h +++ b/soh/soh/Enhancements/randomizer/location_access.h @@ -123,7 +123,7 @@ struct SpiritLogicData { uint8_t childRevKeys; // the number of keys that guarantees Adult can reach this region // if it is 9, that means the bombchu edge case is to be checked. - uint8_t adultKeys; + uint8_t adultKeys; // the number of keys that guarantees Adult can reach this region with reverse entry uint8_t adultRevKeys; // The area access condition to reach this region as Child, from the first lock, 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 e870e78d6..3909b8cca 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp @@ -153,7 +153,7 @@ void RegionTable_Init_SpiritTemple() { areaTable[RR_SPIRIT_TEMPLE_ABOVE_BOULDERS] = Region("Spirit Temple Above Boulders", SCENE_SPIRIT_TEMPLE, { //Events - //Jump slash is possible as child, but pretty tight. Jumpslash as late as you can + //Jumpslash is possible as child, but pretty tight. Jumpslash as late as you can //A damage boost off the boulder is also possible, but you need to land on the middle of the boulder //to get enough distance to reach the rupee EventAccess(&logic->SpiritBouldersSilvers, []{return logic->CanUse(RG_HOVER_BOOTS) || logic->CanJumpslash() || logic->CanUse(RG_LONGSHOT)/* || CanBunnyHop()*/;}), @@ -394,7 +394,6 @@ void RegionTable_Init_SpiritTemple() { areaTable[RR_SPIRIT_TEMPLE_BEAMOS_PITS] = Region("Spirit Temple Beamos Pits", SCENE_SPIRIT_TEMPLE, {}, {}, { //Exits - //Implies killing the anubis with the fire ring, doing so itemless requires voiding out, which can lock hardcore + OHKO seeds Entrance(RR_SPIRIT_TEMPLE_POT_STAIRS, []{return logic->CanKillEnemy(RE_BEAMOS);}), Entrance(RR_SPIRIT_TEMPLE_FOUR_ARMOS, []{return logic->CanKillEnemy(RE_BEAMOS);}), Entrance(RR_SPIRIT_TEMPLE_BIG_WALL_BASE, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 5);}), @@ -674,7 +673,7 @@ void RegionTable_Init_SpiritTemple() { Entrance(RR_SPIRIT_TEMPLE_MQ_SUN_ON_FLOOR, []{return logic->CanHitSwitch()/* && CanClimbHigh()*/;}), }); - areaTable[RR_SPIRIT_TEMPLE_MQ_SUN_ON_FLOOR] = Region("Spirit Temple MQ Broken Wall Room", SCENE_SPIRIT_TEMPLE, {}, { + areaTable[RR_SPIRIT_TEMPLE_MQ_SUN_ON_FLOOR] = Region("Spirit Temple MQ Sun on Floor Room", SCENE_SPIRIT_TEMPLE, {}, { //Locations //Implies CanKillEnemy(RE_LIKE_LIKE) LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, SpiritShared(RR_SPIRIT_TEMPLE_MQ_SUN_ON_FLOOR, []{return logic->CanKillEnemy(RE_BEAMOS);})), @@ -694,18 +693,13 @@ void RegionTable_Init_SpiritTemple() { //Exits //!QUANTUM LOGIC! //If we entered in reverse and dungeon entrances are off, we only need 6 keys, access to Gauntlets Hand, and the ability to - // crawl through the boulder filled tunnel to reach colossus. + //crawl through the boulder filled tunnel to reach colossus. //This is because with 6 keys it becomes impossible to avoid opening either the west hand lock or the first child side lock //and either direction lets child reach colossus. CanHitSwitch and CanKillEnemy(RE_IRON_KNUCKLE) is implied. //Logic can then allow child back into spirit, putting 1F west in logic with only 6 keys without forwards entry Entrance(RR_DESERT_COLOSSUS, []{return logic->IsChild/*CanUse(RG_CRAWL)*/ && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) && logic->SmallKeys(RR_SPIRIT_TEMPLE, 6) && logic->MQSpiritStatueToSunBlock() && (logic->CanUse(RG_BOMBCHU_5) || (ctx->GetTrickOption(RT_RUSTED_SWITCHES) && Here(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_WEST, []{return logic->CanUse(RG_MEGATON_HAMMER);})));}), - //!QUANTUM LOGIC! - //If we have 6 keys and Child reverse spirit entry, we can guarantee broken wall room access for Child - //as long as we can hit a switch and climb because Adult cannot reach the initial child lock without - //first opening the Statue Room to Broken Wall Room lock. The details of this are handled in SpiritShared. - //if adult can ever cross crawlspaces this becomes more complicated. Entrance(RR_SPIRIT_TEMPLE_MQ_SUN_ON_FLOOR, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6);}), Entrance(RR_SPIRIT_TEMPLE_MQ_POT_LEDGE, []{return logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME);}), Entrance(RR_SPIRIT_TEMPLE_MQ_INNER_WEST_HAND, []{return logic->IsAdult || logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS)/* || CanBunnyJump()*/;}), @@ -784,7 +778,6 @@ void RegionTable_Init_SpiritTemple() { areaTable[RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM] = Region("Spirit Temple MQ Sun Block Room", SCENE_SPIRIT_TEMPLE, {}, { //Locations - //We don't need Shared here because If we are checking as child, universe 2 adult access needs nothing so it always passes, and if we are checking as adult, it is Certain Access LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, SpiritShared(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return true/*str0*/;})), //RT_SPIRIT_MQ_SUN_BLOCK_GS should probably be expanded to cover all ground based methods when str0 is added, as it can be hit with longshot because the skull hitbox is larger than the model LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, SpiritShared(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return (logic->CanUse(RG_HOOKSHOT)/* && (str0 || SunlightArrows())*/) || @@ -851,25 +844,17 @@ void RegionTable_Init_SpiritTemple() { Entrance(RR_SPIRIT_TEMPLE_MQ_CHEST_LEDGE, []{return logic->CanUse(RG_HOVER_BOOTS) || ((ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanUse(RG_LONGSHOT));}), Entrance(RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_2F, []{return logic->MQSpiritStatueRoomTorches;}), - //!QUANTUM LOGIC! - //We only need 4 keys and the ability to reach both hands for adult to logically be able to drop down onto Desert Colossus - //This is because there are only 3 keys that can be wasted without opening up either this lock to East hand, or the West Hand lock through Sun Block Room - //and both directions allow you to drop onto colossus - //logic->CanKillEnemy(RE_FLOORMASTER) is implied - Entrance(RR_DESERT_COLOSSUS, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 4) && - logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && - logic->CanJumpslash() && /*(str0 || SunlightArrows) &&*/ + /* logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && + logic->CanJumpslash() && (str0 || SunlightArrows) && (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanKillEnemy(RE_IRON_KNUCKLE) && - logic->CanUse(RG_HOOKSHOT);}), - //!QUANTUM LOGIC! - //Continuing from above, if we also have a longshot, we can go from the East hand to the West hand, meaning we always have access to East Hand - /* - logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && - logic->CanJumpslash() && (str0 || SunlightArrows) && - (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && - logic->CanKillEnemy(RE_IRON_KNUCKLE) && - logic->CanUse(RG_LONGSHOT) */ + logic->CanUse(RG_HOOKSHOT)*/ + Entrance(RR_DESERT_COLOSSUS, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 4) && logic->MQSpirit4KeyColossus();}), + /* logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && + logic->CanJumpslash() && (str0 || SunlightArrows) && + (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && + logic->CanKillEnemy(RE_IRON_KNUCKLE) && + logic->CanUse(RG_LONGSHOT) */ Entrance(RR_SPIRIT_TEMPLE_MQ_OUTER_WEST_HAND, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 4) && logic->MQSpirit4KeyWestHand();}), Entrance(RR_SPIRIT_TEMPLE_MQ_FIRE_WALL_STAIRS_LOWER, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 5);}), // RT_SPIRIT_PLATFORM_HOOKSHOT is currently disabled @@ -998,7 +983,7 @@ void RegionTable_Init_SpiritTemple() { //Exits Entrance(RR_SPIRIT_TEMPLE_MQ_BEAMOS_PITS, []{return true;}), Entrance(RR_SPIRIT_TEMPLE_MQ_FLOORMASTER_STAIRS, []{return logic->CanJumpslash();}), - Entrance(RR_SPIRIT_TEMPLE_MQ_3F_GIBDO_ROOM, []{return Here(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, []{return (logic->IsAdult || logic->CanUse(RG_SONG_OF_TIME)) && logic->CanUse(RG_MIRROR_SHIELD);});}), + Entrance(RR_SPIRIT_TEMPLE_MQ_3F_GIBDO_ROOM, []{return Here(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, []{return ((logic->IsAdult || logic->CanUse(RG_SONG_OF_TIME)) && logic->CanUse(RG_MIRROR_SHIELD)) || logic->SunlightArrows();});}), }); areaTable[RR_SPIRIT_TEMPLE_MQ_FLOORMASTER_STAIRS] = Region("Spirit Temple MQ Floormaster Stairs", SCENE_SPIRIT_TEMPLE, {}, {}, { @@ -1049,7 +1034,7 @@ void RegionTable_Init_SpiritTemple() { areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_WALL_UPPER] = Region("Spirit Temple MQ Big Wall Upper", SCENE_SPIRIT_TEMPLE, { //Events - //Getting some of these with just climbing downwards is theoretically possible but definitly a trick + //Getting some of these with just climbing downwards is theoretically possible but definitely a trick EventAccess(&logic->MQSpiritBigWallSilvers, []{return /*(*/logic->CanKillEnemy(RE_KEESE)/*|| CanUse(RG_SKULL_MASK)) && CanClimbHigh()*/;}), }, {}, { //Exits diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index e5d398028..0e3ab4cf3 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -2363,20 +2363,25 @@ void Logic::SetInLogic(LogicVal logicVal, bool value) { inLogic[logicVal] = value; } -bool Logic::IsReverseAccessPossible() { - //If we ever allow dungeon entrances to connect to boss rooms directly in dungeon chains, or for 1 boss door to lead to another dungeons boss door, add RSK_MIX_DUNGEON_ENTRANCES to the final condition +bool Logic::IsAdultReverseAccessPossible() { + // If we ever allow dungeon entrances to connect to boss rooms directly in dungeon chains, or for 1 boss door to + // lead to another dungeons boss door, add RSK_MIX_DUNGEON_ENTRANCES to the final condition + // RANDOTODO Check for Age-Locked Boss entrances + Ganon's tower when it is shuffled return !ctx->GetOption(RSK_SHUFFLE_BOSS_ENTRANCES).Is(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF) && - (ctx->GetOption(RSK_DECOUPLED_ENTRANCES) || - (ctx->GetOption(RSK_MIX_BOSS_ENTRANCES) && (ctx->GetOption(RSK_MIX_OVERWORLD_ENTRANCES) || ctx->GetOption(RSK_MIX_INTERIOR_ENTRANCES)))); + ((ctx->GetOption(RSK_DECOUPLED_ENTRANCES) && + ctx->GetOption(RSK_SHUFFLE_BOSS_ENTRANCES).Is(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL)) || + (ctx->GetOption(RSK_MIX_BOSS_ENTRANCES) && + (ctx->GetOption(RSK_MIX_OVERWORLD_ENTRANCES) || ctx->GetOption(RSK_MIX_INTERIOR_ENTRANCES)))); } bool Logic::SpiritSunOnFloorToStatue() { return /*CanClimbHigh() &&*/ (HasExplosives() || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS))); } -bool Logic::SpiritEastToSwitch() { - return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_STATUE_JUMP)) || CanUse(RG_HOVER_BOOTS) || - (CanUse(RG_ZELDAS_LULLABY) && CanUse(RG_HOOKSHOT)); +bool Logic::SpiritExplosiveKeyLogic() { + return SmallKeys(RR_SPIRIT_TEMPLE, HasExplosives() ? 1 + : ctx->GetOption(RSK_BOMBCHU_BAG) && BombchuRefill() ? 2 + : 3); } bool Logic::SpiritWestToSkull() { @@ -2393,6 +2398,12 @@ bool Logic::SpiritSunBlockSouthLedge() { ; } +bool Logic::SpiritEastToSwitch() { + return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_STATUE_JUMP)) || CanUse(RG_HOVER_BOOTS) || + (CanUse(RG_ZELDAS_LULLABY) && CanUse(RG_HOOKSHOT)); +} + + // Combines crossing the ledge directly and the jump from the hand bool Logic::MQSpiritWestToPots() { return (IsAdult && ctx->GetTrickOption(RT_SPIRIT_STATUE_JUMP)) || CanUse(RG_HOVER_BOOTS) || CanUse(RG_SONG_OF_TIME); @@ -2408,20 +2419,52 @@ bool Logic::MQSpiritStatueSouthDoor() { CanUse(RG_SONG_OF_TIME) /* && CanClimb()*/); } -bool Logic::MQSpirit4KeyWestHand() { +bool Logic::MQSpirit4KeyColossus() { + // !QUANTUM LOGIC! + // We only need 4 keys and the ability to reach both hands for adult to logically be able to drop down onto Desert Colossus + // This is because there are only 3 keys that can be wasted without opening up either this lock to East hand, or the West Hand lock through Sun Block Room + // and both directions allow you to drop onto colossus + // logic->CanKillEnemy(RE_FLOORMASTER) is implied return CanAvoidEnemy(RE_BEAMOS, true, 4) && CanUse(RG_SONG_OF_TIME) && CanJumpslash() && /*(str0 || SunlightArrows) &&*/ (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH)) && CanKillEnemy(RE_IRON_KNUCKLE) && - CanUse(RG_LONGSHOT); + CanUse(RG_HOOKSHOT); } -// This version of the function handles reaching there as child, based on what adult could do if they existed + +bool Logic::MQSpirit4KeyWestHand() { + // !QUANTUM LOGIC! + // Continuing from MQSpirit4KeyColossus, if we also have a longshot, we can go from the East hand to the West hand, meaning we always have access to East Hand + return CanUse(RG_LONGSHOT) && MQSpirit4KeyColossus(); +} +// This version of the function handles Shared Access for child, based on what adult could do if they existed bool Logic::CouldMQSpirit4KeyWestHand() { - return CanAvoidEnemy(RE_BEAMOS, true, 4) && CanUse(RG_SONG_OF_TIME) && HasItem(RG_MASTER_SWORD) || - HasItem(RG_BIGGORON_SWORD) || - HasItem(RG_MEGATON_HAMMER) && - /*(str0 || SunlightArrows) &&*/ - (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH)) && CanKillEnemy(RE_IRON_KNUCKLE) && - HasItem(RG_LONGSHOT); + return CanAvoidEnemy(RE_BEAMOS, true, 4) && CanUse(RG_SONG_OF_TIME) && + (HasItem(RG_MASTER_SWORD) || HasItem(RG_BIGGORON_SWORD) || HasItem(RG_MEGATON_HAMMER)) && + /*(str0 || SunlightArrows) &&*/ + (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH)) && HasItem(RG_LONGSHOT); +} + +// !QUANTUM LOGIC! +// With 3 keys, you cannot lock adult out of leaving spirit onto the hands and jumping down, as you would have to +// open the west hand door and then adult could climb through sun block room to jump down from there +// This requires that adult can complete both routes +// If we have the longshot, we can also guarantee access to the outer west hand as you can longshot from the east hand +// to the west Implies CanKillEnemy(RE_IRON_KNUCKLE) +bool Logic::OuterWestHandLogic() { + return HasExplosives() /* && CanClimbHigh() && str0*/ && SmallKeys(RR_SPIRIT_TEMPLE, HasItem(RG_LONGSHOT) ? 3 : 5); +} + +bool Logic::OuterWestHandMQLogic() { + return MQSpiritStatueToSunBlock() && SmallKeys(RR_SPIRIT_TEMPLE, CouldMQSpirit4KeyWestHand() ? 4 : 7); +} + +bool Logic::StatueRoomMQKeyLogic() { + // !QUANTUM LOGIC! + // If child enters in reverse, then they have access to Certain Access to Broken Wall room in 6 keys, + // the ability to hit switches and the ability to climb because only child can reach the initial child lock + // without opening the Statue room to Broken Wall Room lock first + // if adult can ever cross crawlspaces this becomes more complicated. + return SmallKeys(RR_SPIRIT_TEMPLE, IsChild && ReverseSpiritChild && CanHitSwitch() /* && CanClimbHigh()*/ ? 6 : 7); } void Logic::Reset(bool resetSaveContext /*= true*/) { diff --git a/soh/soh/Enhancements/randomizer/logic.h b/soh/soh/Enhancements/randomizer/logic.h index 8b62d8274..3dafa02ee 100644 --- a/soh/soh/Enhancements/randomizer/logic.h +++ b/soh/soh/Enhancements/randomizer/logic.h @@ -302,7 +302,7 @@ class Logic { static std::map RandoGetToDungeonScene; static std::map RandoGetToEquipFlag; static std::map RandoGetToRandInf; - bool IsReverseAccessPossible(); + bool IsAdultReverseAccessPossible(); bool SpiritSunOnFloorToStatue(); bool SpiritEastToSwitch(); bool SpiritWestToSkull(); @@ -310,8 +310,13 @@ class Logic { bool MQSpiritWestToPots(); bool MQSpiritStatueToSunBlock(); bool MQSpiritStatueSouthDoor(); + bool MQSpirit4KeyColossus(); bool MQSpirit4KeyWestHand(); bool CouldMQSpirit4KeyWestHand(); + bool OuterWestHandLogic(); + bool OuterWestHandMQLogic(); + bool SpiritExplosiveKeyLogic(); + bool StatueRoomMQKeyLogic(); private: std::shared_ptr ctx; diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 0f58e27b4..676524506 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -379,12 +379,14 @@ void Settings::CreateOptions() { "Allows the following possible without Tunics:\n- Enter Water Temple. The area below the center pillar " "still requires Zora Tunic. Applies to MQ also.\n- Enter Fire Temple. Volvagia still requires Goron " "Tunic. Applies to MQ also, and includes child access to first floor with dungeon shuffle."); - OPT_TRICK(RT_RUSTED_SWITCHES, RCQUEST_BOTH, RA_NONE, { Tricks::Tag::NOVICE },"Hammer Through Collision", + OPT_TRICK(RT_RUSTED_SWITCHES, RCQUEST_BOTH, RA_NONE, { Tricks::Tag::NOVICE }, "Hammer Through Collision", "Applies to:\n" "- Hitting Fire Temple Highest Goron Chest's Rusted Switch in the SoT Block without Song of Time.\n" "- Hitting MQ Fire Temple Lizalfos Maze's Rusted Switch in the wall.\n" - "- Having Adult hammer the rock in the west side crawlspace of MQ Spirit so child can get through without bombchus." - "- MQ Spirit Trial's Rusted Switch between the thrones without hitting the eye target to drop an Iron Knuckle.\n"); + "- Having Adult hammer the rock in the west side crawlspace of MQ Spirit so child can get through " + "without bombchus." + "- MQ Spirit Trial's Rusted Switch between the thrones without hitting the eye target to drop an Iron " + "Knuckle.\n"); OPT_TRICK(RT_FLAMING_CHESTS, RCQUEST_BOTH, RA_NONE, { Tricks::Tag::INTERMEDIATE }, "Flaming Chests", "The chests encircled in flames in Gerudo Training Ground and in Spirit Temple can be opened by running " "into the flames while Link is invincible after taking damage.");