diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp index f894d263d..4e44f9674 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp @@ -342,7 +342,7 @@ void RegionTable_Init_FireTemple() { areaTable[RR_FIRE_TEMPLE_MQ_STALFOS_ROOM] = Region("Fire Temple MQ Stalfos Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_IRON_KNUCKLE_ROOM, {[]{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, {[]{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, 2);}});}}), + Entrance(RR_FIRE_TEMPLE_MQ_IRON_KNUCKLE_ROOM, {[]{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, {[]{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);}});}}), }); areaTable[RR_FIRE_TEMPLE_MQ_IRON_KNUCKLE_ROOM] = Region("Fire Temple MQ Iron Knuckle Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp index 0cb217e6f..b9c1d7e8e 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp @@ -280,46 +280,109 @@ void RegionTable_Init_ForestTemple() { if (ctx->GetDungeon(FOREST_TEMPLE)->IsMQ()) { areaTable[RR_FOREST_TEMPLE_MQ_LOBBY] = Region("Forest Temple MQ Lobby", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, logic->CanJumpslashExceptHammer() || logic->CanUse(RG_BOMB_BAG) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_NUTS) || logic->HookshotOrBoomerang() || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOVER_BOOTS)), + LOCATION(RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA, ED_HAMMER_JUMPSLASH, false) || logic->CanUse(RG_HOVER_BOOTS)), + //Implies CanPassEnemy(RE_BIG_SKULLTULA) LOCATION(RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, logic->HookshotOrBoomerang()), }, { //Exits Entrance(RR_FOREST_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 1) && (logic->CanAttack() || logic->CanUse(RG_NUTS));}}), + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 1) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), }); areaTable[RR_FOREST_TEMPLE_MQ_CENTRAL_AREA] = Region("Forest Temple MQ Central Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_WOLFOS_CHEST, (logic->CanUse(RG_SONG_OF_TIME) || logic->IsChild) && (logic->CanJumpslashExceptHammer() || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_KOKIRI_SWORD))), - LOCATION(RC_FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER)), - }, { + EventAccess(&logic->ForestTempleMeg, {[]{return logic->ForestTempleJoelle && logic->ForestTempleBeth && logic->ForestTempleAmy && logic->CanKillEnemy(RE_MEG);}}), + }, {}, { //Exits - Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT);}}), - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT);}}), //This is as far as child can get - Entrance(RR_FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, {[]{return logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || (ctx->GetTrickOption(RT_FOREST_MQ_BLOCK_PUZZLE) && logic->CanUse(RG_BOMBCHU_5) && logic->IsAdult && logic->CanUse(RG_HOOKSHOT)));}}), - //Trick: logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || (LogicForestMQBlockPuzzle && logic->CanUse(RG_BOMBCHU_5) && logic->IsAdult && logic->CanUse(RG_HOOKSHOT))) - Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return (ctx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || (ctx->GetTrickOption(RT_FOREST_MQ_RANG_HALLWAY_SWITCH) && logic->CanUse(RG_BOOMERANG)) || (ctx->GetTrickOption(RT_FOREST_MQ_HOOKSHOT_HALLWAY_SWITCH) && logic->IsAdult && logic->CanUse(RG_HOOKSHOT));}}), - //Trick (logic->Hookshot trick not added to either n64 or oot3d rando as of yet, to enable in SoH needs uncommenting in randomizer_tricks.cpp): (LogicForestMQHallwaySwitchJS && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || (LogicForestMQHallwaySwitchHookshot && logic->IsAdult && logic->CanUse(RG_HOOKSHOT)) - Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, {[]{return logic->ForestTempleJoAndBeth && logic->ForestTempleAmyAndMeg;}}), + Entrance(RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM, {[]{return logic->IsChild || logic->CanUse(RG_SONG_OF_TIME);}}), + Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return logic->CanHitEyeTargets();}}), + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return logic->CanHitEyeTargets();}}), + Entrance(RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE, {[]{return Here(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->CanKillEnemy(RE_STALFOS);}});}}), + //implies the other 3 poes + Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT, {[]{return logic->ForestTempleMeg;}}), }); - areaTable[RR_FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE] = Region("Forest Temple MQ After Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + areaTable[RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM] = Region("Forest Temple MQ Wolfos Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, {[]{return true;}}), + EventAccess(&logic->ForestClearBelowBowChest, {[]{return logic->CanKillEnemy(RE_WOLFOS);}}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_WOLFOS_CHEST, logic->ForestClearBelowBowChest), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->ForestClearBelowBowChest && (logic->IsChild || logic->CanUse(RG_SONG_OF_TIME));}}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE] = Region("Forest Temple MQ Lower Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //longshot is capable of hitting the switch, but some invisible collision makes the shot harder than you would think, so it may be trickworthy + EventAccess(&logic->MQForestBlockRoomTargets, {[]{return (ctx->GetTrickOption(RT_FOREST_MQ_BLOCK_PUZZLE) && logic->CanUse(RG_BOMBCHU_5));}}), + //Trick (RT_FOREST_MQ_HOOKSHOT_HALLWAY_SWITCH not added to either n64 or oot3d rando as of yet, to enable in SoH needs uncommenting in randomizer_tricks.cpp) + //It is barely possible to get this as child with master + hovers, but it's tight without bunny speed + EventAccess(&logic->ForestCanTwistHallway, {[]{return (ctx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && logic->CanUse(RG_HOVER_BOOTS) && + (logic->IsAdult && logic->CanJumpslash()) || + (logic->CanUse(RG_STICKS) || logic->CanUse(RG_BIGGORON_SWORD) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_MASTER_SWORD)))) || + (ctx->GetTrickOption(RT_FOREST_MQ_RANG_HALLWAY_SWITCH) && logic->CanUse(RG_BOOMERANG)) || + (ctx->GetTrickOption(RT_FOREST_MQ_HOOKSHOT_HALLWAY_SWITCH) && logic->CanUse(RG_HOOKSHOT));}}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return Here(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->CanKillEnemy(RE_STALFOS);}});}}), + Entrance(RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE, {[]{return logic->HasItem(RG_GORONS_BRACELET) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_HOOKSHOT));}}), + //Assumes RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE access + Entrance(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, {[]{return (logic->IsAdult && logic->HasItem(RG_GORONS_BRACELET)) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_HOOKSHOT));}}), + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return logic->ForestCanTwistHallway && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE] = Region("Forest Temple MQ Middle Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //longshot is capable of hitting the switch, but some invisible collision makes the shot more annoying than you would think, so it may be trickworthy + EventAccess(&logic->MQForestBlockRoomTargets, {[]{return (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_LONGSHOT));}}), + EventAccess(&logic->ForestCanTwistHallway, {[]{return ctx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && + (logic->IsAdult && logic->CanJumpslash()) || + (logic->CanUse(RG_HOVER_BOOTS) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MASTER_SWORD)));}}), + }, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE, {[]{return true;}}), + Entrance(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, {[]{return (logic->IsAdult && logic->HasItem(RG_GORONS_BRACELET)) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_HOOKSHOT));}}), + //Hammer cannot recoil from here, but can make the jump forwards with a hammer jumpslash as adult + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return logic->ForestCanTwistHallway && logic->CanUse(RG_HOVER_BOOTS) || + (ctx->GetTrickOption(RT_FOREST_OUTSIDE_BACKDOOR) && (logic->CanJumpslashExceptHammer() || (logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER))));}}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE] = Region("Forest Temple MQ After Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { //Locations LOCATION(RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, logic->SmallKeys(RR_FOREST_TEMPLE, 3)), }, { //Exits - Entrance(RR_FOREST_TEMPLE_MQ_BOW_REGION, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 4);}}), - Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 3) || (ctx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && ((logic->IsAdult && logic->CanUse(RG_HOOKSHOT)) || (ctx->GetTrickOption(RT_FOREST_OUTSIDE_BACKDOOR) && (logic->IsAdult || (logic->IsChild && logic->CanUse(RG_STICKS))))));}}), - //Trick (Doing the hallway switch jumpslash as child requires sticks and has been added above): logic->SmallKeys(RR_FOREST_TEMPLE, 3) || (LogicForestMQHallwaySwitchJS && ((logic->IsAdult && logic->CanUse(RG_HOOKSHOT)) || LogicForestOutsideBackdoor)) - Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 2);}}), + Entrance(RR_FOREST_TEMPLE_MQ_STRAIGHT_HALLWAY, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 3);}}), + Entrance(RR_FOREST_TEMPLE_MQ_JOELLE_ROOM, {[]{return logic->ForestCanTwistHallway && logic->SmallKeys(RR_FOREST_TEMPLE, 4);}}), + //!QUANTUM LOGIC! + //As there is no way in default logic to reach the other possible key use without going through RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, this is logically safe for now + //Breaks if there's any other way to RR_FOREST_TEMPLE_MQ_FALLING_ROOM than going through the eye targets in RR_FOREST_TEMPLE_MQ_CENTRAL_AREA + //Requires a bow/sling ammo source once ammo logic is done, to avoid edge cases. + Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 2) && Here(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, {[]{return logic->CanKillEnemy(RE_FLOORMASTER);}});}}), }); - areaTable[RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE] = Region("Forest Temple MQ Outdoor Ledge", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + areaTable[RR_FOREST_TEMPLE_MQ_STRAIGHT_HALLWAY] = Region("Forest Temple MQ Straight Hallway", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_REDEAD_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, logic->SmallKeys(RR_FOREST_TEMPLE, 3)), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM, {[]{return true;}}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM] = Region("Forest Temple MQ Floormaster Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return Here(RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM, {[]{return logic->CanKillEnemy(RE_FLOORMASTER);}});}}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE] = Region("Forest Temple MQ Outdoor Ledge", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + EventAccess(&logic->ForestCanTwistHallway, {[]{return logic->CanHitSwitch();}}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_REDEAD_CHEST, logic->CanKillEnemy(RE_REDEAD)), }, { //Exits Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return true;}}), @@ -327,37 +390,43 @@ void RegionTable_Init_ForestTemple() { areaTable[RR_FOREST_TEMPLE_MQ_NW_OUTDOORS] = Region("Forest Temple MQ NW Outdoors", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, logic->CanAttack()), + LOCATION(RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), }, { //Exits - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return (logic->IsAdult && (logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_FOREST_MQ_WELL_SWIM) && logic->CanUse(RG_HOOKSHOT)))) || logic->HasItem(RG_GOLDEN_SCALE);}}), - //Trick: (logic->IsAdult && (logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_LONGSHOT) || (LogicForestMQWellSwim && logic->CanUse(RG_HOOKSHOT)))) || logic->ProgressiveScale >= 2 - Entrance(RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return logic->IsAdult && logic->CanUse(RG_FIRE_ARROWS);}}), + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return (logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_FOREST_MQ_WELL_SWIM) && logic->CanUse(RG_HOOKSHOT)) || logic->HasItem(RG_GOLDEN_SCALE)) && logic->WaterTimer() > 10;}}), + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return logic->CanUse(RG_FIRE_ARROWS);}}), }); +//The well is included here because the eye target is a temp flag, making it unwieldy to use as an EventAccess to make it it's own room areaTable[RR_FOREST_TEMPLE_MQ_NE_OUTDOORS] = Region("Forest Temple MQ NE Outdoors", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { //Events EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), }, { //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_WELL_CHEST, (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)) || (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT))), - LOCATION(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, logic->HookshotOrBoomerang() || (logic->IsAdult && logic->CanUse(RG_FIRE_ARROWS) && (logic->CanUse(RG_SONG_OF_TIME) || (logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_FOREST_DOORFRAME))))), - LOCATION(RC_FOREST_TEMPLE_MQ_GS_WELL, (logic->IsAdult && ((logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT)) || logic->CanUse(RG_FAIRY_BOW))) || (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT))), + LOCATION(RC_FOREST_TEMPLE_MQ_WELL_CHEST, logic->CanHitEyeTargets()), + LOCATION(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + //implies logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) + LOCATION(RC_FOREST_TEMPLE_MQ_GS_WELL, logic->CanHitEyeTargets() || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT))), }, { //Exits - Entrance(RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return logic->IsAdult && logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME));}}), - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return logic->IsAdult && logic->CanUse(RG_LONGSHOT);}}), + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && ((logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || logic->CanUse(RG_SONG_OF_TIME)));}}), + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return logic->CanUse(RG_LONGSHOT);}}), }); areaTable[RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES] = Region("Forest Temple MQ Outdoors Top Ledges", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { //Locations LOCATION(RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, true), + //Actually killing the skull from the doorframe with melee is annoying. Hammer swing hits low enough unaided, other swords need to crouch stab but the spot is precise based on range. kokiri sword doesn't reach at all for adult. + LOCATION(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, ((logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME)) || (logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_FOREST_DOORFRAME))) && logic->CanJumpslash() && + (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_FAIRY_BOW) || logic->HookshotOrBoomerang() || + (logic->CanStandingShield() && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MASTER_SWORD) || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD)))))), }, { //Exits + Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return logic->HasFireSourceWithTorch();}}), Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return ctx->GetTrickOption(RT_FOREST_OUTDOORS_LEDGE) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS);}}), - //Trick: LogicForestOutdoorsLedge && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) + //N64 logic doesn't check damage but I always take some so I'm adding it + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return ctx->GetTrickOption(RT_FOREST_OUTDOORS_LEDGE) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanJumpslash() && logic->TakeDamage();}}), }); areaTable[RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE] = Region("Forest Temple MQ NE Outdoors Ledge", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { @@ -365,39 +434,94 @@ void RegionTable_Init_ForestTemple() { LOCATION(RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, true), }, { //Exits + //Skipping swim here is non-trival, needs a roll-jump. If a swim lock is added it's probably wise to copy deku baba events here Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return true;}}), Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return logic->CanUse(RG_SONG_OF_TIME);}}), }); - areaTable[RR_FOREST_TEMPLE_MQ_BOW_REGION] = Region("Forest Temple MQ Bow Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + areaTable[RR_FOREST_TEMPLE_MQ_JOELLE_ROOM] = Region("Forest Temple MQ Joelle room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { //Events - EventAccess(&logic->ForestTempleJoAndBeth, {[]{return logic->ForestTempleJoAndBeth || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}}), + EventAccess(&logic->ForestTempleJoelle, {[]{return logic->CanUse(RG_FAIRY_BOW);}}), }, { //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_BOW_CHEST, logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER)), - LOCATION(RC_FOREST_TEMPLE_MQ_MAP_CHEST, logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)), - LOCATION(RC_FOREST_TEMPLE_MQ_COMPASS_CHEST, logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)), + LOCATION(RC_FOREST_TEMPLE_MQ_MAP_CHEST, logic->ForestTempleJoelle), }, { //Exits - Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 5) && ((logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)) || logic->CanUse(RG_DINS_FIRE));}}), + Entrance(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 4);}}), + Entrance(RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM, {[]{return true;}}), }); - areaTable[RR_FOREST_TEMPLE_MQ_FALLING_ROOM] = Region("Forest Temple MQ Falling Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + areaTable[RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM] = Region("Forest Temple MQ 3 Stalfos Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { //Events - EventAccess(&logic->ForestTempleAmyAndMeg, {[]{return logic->ForestTempleAmyAndMeg || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW) && logic->SmallKeys(RR_FOREST_TEMPLE, 6));}}), + //technically happens in RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM, but the way this room blocks the hole means it cannot be logical to do anything else there. + EventAccess(&logic->ForestClearBelowBowChest, {[]{return logic->CanKillEnemy(RE_WOLFOS);}}), }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_BOW_CHEST, logic->ForestClearBelowBowChest && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3)), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_JOELLE_ROOM, {[]{return logic->ForestClearBelowBowChest && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3);}}), + Entrance(RR_FOREST_TEMPLE_MQ_BETH_ROOM, {[]{return logic->ForestClearBelowBowChest && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3);}}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_BETH_ROOM] = Region("Forest Temple MQ Beth Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleBeth, {[]{return logic->CanUse(RG_FAIRY_BOW);}}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_COMPASS_CHEST, logic->ForestTempleBeth), + }, { + //Exits + //!QUANTUM LOGIC! + //This key logic assumes that you can get to falling room either by spending the 5th key here, or by wasting a key in falling room itself. + //While being the 5th key makes this simpler in theory, if a different age can waste the key compared to reaching this room it breaks + Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 5) && + Here(RR_FOREST_TEMPLE_MQ_BETH_ROOM, {[]{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE);}});}}), + Entrance(RR_FOREST_TEMPLE_MQ_TORCH_SHOT_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 6);}}), + Entrance(RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM, {[]{return true;}}), + }); + + //This room exists to show the actual map layout, and for when the crates get added to logic + areaTable[RR_FOREST_TEMPLE_MQ_TORCH_SHOT_ROOM] = Region("Forest Temple MQ Torch Shot Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE);}}), + Entrance(RR_FOREST_TEMPLE_MQ_BETH_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 6);}}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_FALLING_ROOM] = Region("Forest Temple MQ Falling Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { //Locations LOCATION(RC_FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, true), }, { //Exits Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return true;}}), + Entrance(RR_FOREST_TEMPLE_MQ_AMY_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 6);}}), }); - areaTable[RR_FOREST_TEMPLE_MQ_BOSS_REGION] = Region("Forest Temple MQ Boss Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + areaTable[RR_FOREST_TEMPLE_MQ_AMY_ROOM] = Region("Forest Temple MQ Amy Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleAmy, {[]{return logic->CanUse(RG_FAIRY_BOW);}}), + }, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->ForestTempleAmy;}}), + Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return true;}}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_BASEMENT] = Region("Forest Temple MQ Basement", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //Implies CanHitSwitch() + EventAccess(&logic->ForestOpenBossCorridor, {[]{return logic->CanHitEyeTargets();}}), + }, { //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST, true), + LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST, true), }, { //Exits + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->ForestTempleMeg;}}), + Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, {[]{return logic->ForestOpenBossCorridor;}}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_BOSS_REGION] = Region("Forest Temple MQ Boss Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT, {[]{return logic->ForestOpenBossCorridor;}}), Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->HasItem(RG_FOREST_TEMPLE_BOSS_KEY);}}), }); } @@ -409,9 +533,9 @@ void RegionTable_Init_ForestTemple() { Region("Forest Temple Boss Entryway", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { // Exits - Entrance(RR_FOREST_TEMPLE_BOSS_REGION, { [] { return ctx->GetDungeon(FOREST_TEMPLE)->IsVanilla() && false; } }), + Entrance(RR_FOREST_TEMPLE_BOSS_REGION, { [] { return ctx->GetDungeon(FOREST_TEMPLE)->IsVanilla() && false; } }), Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, { [] { return ctx->GetDungeon(FOREST_TEMPLE)->IsMQ() && false; } }), - Entrance(RR_FOREST_TEMPLE_BOSS_ROOM, { [] { return true; } }), + Entrance(RR_FOREST_TEMPLE_BOSS_ROOM, { [] { return true; } }), }); areaTable[RR_FOREST_TEMPLE_BOSS_ROOM] = Region("Forest Temple Boss Room", "Forest Temple", {}, NO_DAY_NIGHT_CYCLE, diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp index 05a32e51b..7330aa77b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp @@ -120,11 +120,11 @@ void RegionTable_Init_HyruleField() { }, { //Locations LOCATION(RC_LH_UNDERWATER_ITEM, logic->IsChild && logic->HasItem(RG_SILVER_SCALE)), - LOCATION(RC_LH_SUN, logic->IsAdult && logic->WaterTempleClear && logic->CanUse(RG_FAIRY_BOW)), + LOCATION(RC_LH_SUN, logic->IsAdult && ((logic->WaterTempleClear && logic->HasItem(RG_BRONZE_SCALE)) || logic->CanUse(RG_DISTANT_SCARECROW)) && logic->CanUse(RG_FAIRY_BOW)), LOCATION(RC_LH_FREESTANDING_POH, logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA))), - LOCATION(RC_LH_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), - LOCATION(RC_LH_GS_LAB_WALL, logic->IsChild && (logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_LH_LAB_WALL_GS) && logic->CanJumpslashExceptHammer())) && logic->AtNight && logic->CanGetNightTimeGS()), - LOCATION(RC_LH_GS_SMALL_ISLAND, logic->IsChild && logic->CanAttack() && logic->AtNight && logic->CanGetNightTimeGS()), + LOCATION(RC_LH_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + LOCATION(RC_LH_GS_LAB_WALL, logic->IsChild && (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_RANG_OR_HOOKSHOT) || (ctx->GetTrickOption(RT_LH_LAB_WALL_GS) && logic->CanJumpslashExceptHammer())) && logic->AtNight && logic->CanGetNightTimeGS()), + LOCATION(RC_LH_GS_SMALL_ISLAND, logic->IsChild && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) && logic->AtNight && logic->CanGetNightTimeGS() && logic->HasItem(RG_BRONZE_SCALE)), LOCATION(RC_LH_GS_TREE, logic->IsAdult && logic->CanUse(RG_LONGSHOT) && logic->AtNight && logic->CanGetNightTimeGS()), LOCATION(RC_LH_LAB_GOSSIP_STONE, true), LOCATION(RC_LH_SOUTHEAST_GOSSIP_STONE, true), @@ -134,7 +134,7 @@ void RegionTable_Init_HyruleField() { Entrance(RR_HYRULE_FIELD, {[]{return true;}}), Entrance(RR_ZORAS_DOMAIN, {[]{return logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS));}}), Entrance(RR_LH_OWL_FLIGHT, {[]{return logic->IsChild;}}), - Entrance(RR_LH_FISHING_ISLAND, {[]{return logic->IsChild || logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA) || logic->WaterTempleClear;}}), + Entrance(RR_LH_FISHING_ISLAND, {[]{return ((logic->IsChild || logic->WaterTempleClear) && logic->HasItem(RG_BRONZE_SCALE)) || (logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA)));}}), Entrance(RR_LH_LAB, {[]{return true;}}), Entrance(RR_WATER_TEMPLE_ENTRYWAY, {[]{return logic->CanUse(RG_HOOKSHOT) && ((logic->CanUse(RG_IRON_BOOTS) || (ctx->GetTrickOption(RT_LH_WATER_HOOKSHOT) && logic->HasItem(RG_GOLDEN_SCALE))) || (logic->IsAdult && logic->CanUse(RG_LONGSHOT) && logic->HasItem(RG_GOLDEN_SCALE)));}}), Entrance(RR_LH_GROTTO, {[]{return true;}}), @@ -142,7 +142,7 @@ void RegionTable_Init_HyruleField() { areaTable[RR_LH_FISHING_ISLAND] = Region("LH Fishing Island", "Lake Hylia", {RA_LAKE_HYLIA}, DAY_NIGHT_CYCLE, {}, {}, { //Exits - Entrance(RR_LAKE_HYLIA, {[]{return true;}}), + Entrance(RR_LAKE_HYLIA, {[]{return logic->HasItem(RG_BRONZE_SCALE);}}), Entrance(RR_LH_FISHING_HOLE, {[]{return true;}}), }); diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index ab5aa360e..33c0f045d 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -409,7 +409,8 @@ namespace Rando { } //RANDOTODO quantity is a placeholder for proper ammo use calculation logic. in time will want updating to account for ammo capacity - bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, uint8_t quantity) { +//Can we kill this enemy + bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wallOrFloor, uint8_t quantity) { bool killed = false; switch(enemy) { case RE_GOLD_SKULLTULA: @@ -428,8 +429,8 @@ namespace Rando { killed = killed || CanJumpslashExceptHammer(); [[fallthrough]]; case ED_RANG_OR_HOOKSHOT: - //RANDOTODO test dins, bomb and chu range in a practical example, might need a wall var to handle chus - killed = killed || CanUse(RG_HOOKSHOT) || HasExplosives() || CanUse(RG_DINS_FIRE); + //RANDOTODO test dins, bomb and chu range in a practical example + killed = killed || CanUse(RG_HOOKSHOT) || CanUse(RG_BOMB_BAG) || (wallOrFloor && CanUse(RG_BOMBCHU_5)) || CanUse(RG_DINS_FIRE); [[fallthrough]]; case ED_LONGSHOT: killed = killed || CanUse(RG_LONGSHOT); @@ -455,6 +456,7 @@ namespace Rando { case RE_WITHERED_DEKU_BABA: return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_BOOMERANG); case RE_LIKE_LIKE: + case RE_FLOORMASTER: return CanDamage(); case RE_STALFOS: //RANDOTODO Add trick to kill stalfos with sticks, and a second one for bombs without stunning. Higher ammo logic for bombs is also plausible @@ -471,6 +473,12 @@ namespace Rando { //Dins killing isn't hard, but is obscure and tight on single magic, so is a trick case RE_FLARE_DANCER: return CanUse(RG_MEGATON_HAMMER) || CanUse(RG_HOOKSHOT) || (HasExplosives() && (CanJumpslashExceptHammer() || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG))); + case RE_WOLFOS: + return CanJumpslash() || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOMBCHU_5) || (CanUse(RG_BOMB_BAG) && (CanUse(RG_NUTS) || CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG))); + case RE_REDEAD: + return CanJumpslash() || CanUse(RG_DINS_FIRE); + case RE_MEG: + return CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || HasExplosives(); default: SPDLOG_ERROR("CanKillEnemy reached `default`."); assert(false); @@ -480,8 +488,9 @@ namespace Rando { //It is rare for Pass Enemy to need distance, this only happens when the enemy blocks a platform and you can't reach it before it blocks you //an example is the Big Skulltula in water room of MQ deku, which is out of sword swing height but blocks off the whole SoT block - bool Logic::CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance) { - if (CanKillEnemy(enemy, distance)){ +//Can we get past this enemy in a tight space? + bool Logic::CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wallOrFloor) { + if (CanKillEnemy(enemy, distance, wallOrFloor)){ return true; } switch(enemy) { @@ -498,12 +507,18 @@ namespace Rando { case RE_WITHERED_DEKU_BABA: case RE_STALFOS: case RE_FLARE_DANCER: + case RE_WOLFOS: + case RE_FLOORMASTER: + case RE_MEG: return true; case RE_BIG_SKULLTULA: //hammer jumpslash can pass, but only on flat land where you can kill with hammer swing return CanUse(RG_NUTS) || CanUse(RG_BOOMERANG); case RE_LIKE_LIKE: return CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG); + case RE_REDEAD: + // we need a way to check if suns won't force a reload + return CanUse(RG_HOOKSHOT) || CanUse(RG_SUNS_SONG); case RE_IRON_KNUCKLE: return false; default: @@ -513,6 +528,7 @@ namespace Rando { } } +//Can we avoid this enemy while climbing up a wall, or doing a difficult platforming challenge? bool Logic::CanAvoidEnemy(RandomizerEnemy enemy) { if (CanKillEnemy(enemy)){ return true; @@ -530,6 +546,10 @@ namespace Rando { case RE_STALFOS: case RE_IRON_KNUCKLE: case RE_FLARE_DANCER: + case RE_WOLFOS: + case RE_FLOORMASTER: + case RE_REDEAD: + case RE_MEG: return true; case RE_MAD_SCRUB: case RE_KEESE: @@ -620,13 +640,16 @@ namespace Rando { return CanUse(RG_STICKS) || CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD); } - bool Logic::CanJumpslash() { return CanJumpslashExceptHammer() || CanUse(RG_MEGATON_HAMMER); } + bool Logic::CanHitSwitch() { + return CanUse(RG_FAIRY_SLINGSHOT) || CanJumpslash() || HasExplosives() || CanUse(RG_FAIRY_BOW) || CanUse(RG_BOOMERANG) || CanUse(RG_HOOKSHOT); + } + bool Logic::CanDamage() { - return CanUse(RG_FAIRY_SLINGSHOT) || CanJumpslashExceptHammer() || BlastOrSmash() || CanUse(RG_DINS_FIRE) || CanUse(RG_FAIRY_BOW); + return CanUse(RG_FAIRY_SLINGSHOT) || CanJumpslash() || HasExplosives() || CanUse(RG_DINS_FIRE) || CanUse(RG_FAIRY_BOW); } bool Logic::CanAttack() { @@ -1844,10 +1867,8 @@ namespace Rando { KingZoraThawed = false; ForestTempleJoelle = false; ForestTempleBeth = false; - ForestTempleJoAndBeth = false; ForestTempleAmy = false; ForestTempleMeg = false; - ForestTempleAmyAndMeg = false; FireLoopSwitch = false; LinksCow = false; DeliverLetter = false; @@ -1863,6 +1884,10 @@ namespace Rando { OpenedUpperFireShortcut = false; HitFireTemplePlatform = false; OpenedFireMQFireMazeDoor = false; + MQForestBlockRoomTargets = false; + ForestCanTwistHallway = false; + ForestClearBelowBowChest = false; + ForestOpenBossCorridor = false; StopPerformanceTimer(PT_LOGIC_RESET); } diff --git a/soh/soh/Enhancements/randomizer/logic.h b/soh/soh/Enhancements/randomizer/logic.h index 2b7ea2bed..b42aac6f8 100644 --- a/soh/soh/Enhancements/randomizer/logic.h +++ b/soh/soh/Enhancements/randomizer/logic.h @@ -125,10 +125,8 @@ class Logic { bool KingZoraThawed = false; bool ForestTempleJoelle = false; bool ForestTempleBeth = false; - bool ForestTempleJoAndBeth = false; bool ForestTempleAmy = false; bool ForestTempleMeg = false; - bool ForestTempleAmyAndMeg = false; bool FireLoopSwitch = false; bool LinksCow = false; bool DeliverLetter = false; @@ -144,6 +142,10 @@ class Logic { bool OpenedUpperFireShortcut = false; bool HitFireTemplePlatform = false; bool OpenedFireMQFireMazeDoor = false; + bool MQForestBlockRoomTargets = false; + bool ForestCanTwistHallway = false; + bool ForestClearBelowBowChest = false; //a better name that covers both versions would be nice + bool ForestOpenBossCorridor = false; /* --- END OF HELPERS AND LOCATION ACCESS --- */ @@ -157,8 +159,8 @@ class Logic { bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched); bool CanDoGlitch(GlitchType glitch); bool CanEquipSwap(RandomizerGet itemName); - bool CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, uint8_t quantity = 1); - bool CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE); + bool CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool wallOrFloor = true, uint8_t quantity = 1); + bool CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool wallOrFloor = true); bool CanAvoidEnemy(RandomizerEnemy enemy); bool CanGetEnemyDrop(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool aboveLink = false); bool CanBreakMudWalls(); @@ -172,6 +174,7 @@ class Logic { bool HasBottle(); bool CanJumpslashExceptHammer(); bool CanJumpslash(); + bool CanHitSwitch(); bool CanDamage(); bool CanAttack(); bool BombchusEnabled(); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index e5c4dee41..d30e8a592 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -623,14 +623,24 @@ typedef enum { RR_FOREST_TEMPLE_MQ_LOBBY, RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, - RR_FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, + RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM, + RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE, + RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE, + RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, + RR_FOREST_TEMPLE_MQ_STRAIGHT_HALLWAY, + RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM, RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, - RR_FOREST_TEMPLE_MQ_BOW_REGION, + RR_FOREST_TEMPLE_MQ_JOELLE_ROOM, + RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM, + RR_FOREST_TEMPLE_MQ_BETH_ROOM, + RR_FOREST_TEMPLE_MQ_TORCH_SHOT_ROOM, RR_FOREST_TEMPLE_MQ_FALLING_ROOM, + RR_FOREST_TEMPLE_MQ_AMY_ROOM, + RR_FOREST_TEMPLE_MQ_BASEMENT, RR_FOREST_TEMPLE_MQ_BOSS_REGION, RR_FOREST_TEMPLE_BOSS_ENTRYWAY, @@ -4447,6 +4457,10 @@ typedef enum { RE_STALFOS, RE_IRON_KNUCKLE, RE_FLARE_DANCER, + RE_WOLFOS, + RE_FLOORMASTER, + RE_REDEAD, + RE_MEG, } RandomizerEnemy; typedef enum { diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 38da8936b..a17f27119 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -420,6 +420,7 @@ void Settings::CreateOptions() { mTrickOptions[RT_FOREST_OUTSIDE_BACKDOOR] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_FOREST_TEMPLE, {Tricks::Tag::ADVANCED}, false, "Forest Temple Outside Backdoor with Jump Slash", "A jump slash recoil can be used to reach the ledge in the block puzzle room that leads to the west courtyard. This skips a potential Hover Boots requirement in vanilla, and it can sometimes apply in MQ as well. This trick can be performed as both ages."); mTrickOptions[RT_FOREST_MQ_WELL_SWIM] = TrickOption::LogicTrick(RCQUEST_MQ, RA_FOREST_TEMPLE, {Tricks::Tag::ADVANCED}, false, "Swim Through Forest Temple MQ Well with Hookshot", "Shoot the vines in the well as low and as far to the right as possible, and then immediately swim under the ceiling to the right. This can only be required if Forest Temple is in its Master Quest form."); mTrickOptions[RT_FOREST_MQ_BLOCK_PUZZLE] = TrickOption::LogicTrick(RCQUEST_MQ, RA_FOREST_TEMPLE, {Tricks::Tag::NOVICE}, false, "Skip Forest Temple MQ Block Puzzle with Bombchu", "Send the Bombchu straight up the center of the wall directly to the left upon entering the room."); + //Child with hovers cannot do this from the lower floor, and most go to the upper floor which needs goron bracelet. Adult can do this with hammer and KSword, But child cannot. mTrickOptions[RT_FOREST_MQ_JS_HALLWAY_SWITCH] = TrickOption::LogicTrick(RCQUEST_MQ, RA_FOREST_TEMPLE, {Tricks::Tag::NOVICE}, false, "Forest Temple MQ Twisted Hallway Switch with Jump Slash", "The switch to twist the hallway can be hit with a jump slash through the glass block. To get in front of the switch, either use the Hover Boots or hit the shortcut switch at the top of the room and jump from the glass blocks that spawn. Sticks can be used as child, but the Kokiri Sword is too short to reach through the glass."); // mTrickOptions[RT_FOREST_MQ_HOOKSHOT_HALLWAY_SWITCH] = TrickOption::LogicTrick(RCQUEST_MQ, RA_FOREST_TEMPLE, {Tricks::Tag::INTERMEDIATE}, false, "Forest Temple MQ Twisted Hallway Switch with Hookshot", "There's a very small gap between the glass block and the wall. Through that gap you can hookshot the target on the ceiling."); mTrickOptions[RT_FOREST_MQ_RANG_HALLWAY_SWITCH] = TrickOption::LogicTrick(RCQUEST_MQ, RA_FOREST_TEMPLE, {Tricks::Tag::INTERMEDIATE}, false, "Forest Temple MQ Twisted Hallway Switch with Boomerang", "The Boomerang can return to Link through walls, allowing child to hit the hallway switch. This can be used to allow adult to pass through later, or in conjuction with \"Forest Temple Outside Backdoor with Jump Slash\".");