Rewrite MQ GTG and Ice Cavern logic (#4483)

* rewrite GTG logic

* Rewrite MQ Ice Cavern Logic
This commit is contained in:
Pepper0ni 2024-10-27 21:16:51 +00:00 committed by GitHub
parent 169e39ebad
commit 438a8bff79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 313 additions and 77 deletions

View File

@ -277,7 +277,7 @@ void RegionTable_Init_DekuTree() {
LOCATION(RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, logic->CanUse(RG_SONG_OF_TIME) && logic->CanPassEnemy(RE_BIG_SKULLTULA)), LOCATION(RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, logic->CanUse(RG_SONG_OF_TIME) && logic->CanPassEnemy(RE_BIG_SKULLTULA)),
}, { }, {
//Exits //Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, {[]{return logic->MQDekuWaterRoomTorches && logic->CanPassEnemy(RE_BIG_SKULLTULA, logic->CanUse(RG_SONG_OF_TIME) ? ED_CLOSE : ED_HAMMER_JUMPSLASH);}}), Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, {[]{return logic->MQDekuWaterRoomTorches && logic->CanPassEnemy(RE_BIG_SKULLTULA, logic->CanUse(RG_SONG_OF_TIME) ? ED_CLOSE : ED_SHORT_JUMPSLASH);}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield()) || Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield()) ||
logic->CanUse(RG_LONGSHOT) || logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT) || logic->HasItem(RG_BRONZE_SCALE) ||
(logic->CanUse(RG_IRON_BOOTS) && (logic->IsAdult || logic->CanUse(RG_HOOKSHOT)));}}), (logic->CanUse(RG_IRON_BOOTS) && (logic->IsAdult || logic->CanUse(RG_HOOKSHOT)));}}),

View File

@ -280,7 +280,7 @@ void RegionTable_Init_ForestTemple() {
if (ctx->GetDungeon(FOREST_TEMPLE)->IsMQ()) { 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, {}, { areaTable[RR_FOREST_TEMPLE_MQ_LOBBY] = Region("Forest Temple MQ Lobby", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations //Locations
LOCATION(RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA, ED_HAMMER_JUMPSLASH, false) || logic->CanUse(RG_HOVER_BOOTS)), LOCATION(RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA, ED_SHORT_JUMPSLASH, false) || logic->CanUse(RG_HOVER_BOOTS)),
//Implies CanPassEnemy(RE_BIG_SKULLTULA) //Implies CanPassEnemy(RE_BIG_SKULLTULA)
LOCATION(RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, logic->HookshotOrBoomerang()), LOCATION(RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, logic->HookshotOrBoomerang()),
}, { }, {

View File

@ -117,75 +117,218 @@ void RegionTable_Init_GerudoTrainingGrounds() {
//Locations //Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST, true), LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST, true), LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST, true), LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST, true), LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 1)),
}, { }, {
//Exits //Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return true;}}), Entrance(RR_GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return true;}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, []{return logic->HasFireSource();});}}), Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_HIDDEN_ROOM, {[]{return ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, []{return (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)) || (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT));});}}), Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_FIRST_LOCK, {[]{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 1);}}),
//It's possible to use the torch in RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_HIDDEN_ROOM with flame storage to light these
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_SAND_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, []{return logic->HasFireSource();});}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, []{return (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)) || (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT));});}}),
}); });
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE] = Region("Gerudo Training Grounds MQ Right Side", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_HIDDEN_ROOM] = Region("Gerudo Training Grounds MQ Maze Hidden Room", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, true),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, {[]{return true;}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_FIRST_LOCK] = Region("Gerudo Training Grounds MQ Maze First Lock", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST, true),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, {[]{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 1);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_CENTER, {[]{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 3);}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_CENTER] = Region("Gerudo Training Grounds MQ Center", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {
//Events //Events
//EventAccess(&WallFairy, {[]{return WallFairy || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}}), EventAccess(&logic->MQGTGMazeSwitch, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}),
}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_FIRST_LOCK, {[]{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 3);}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_SAND_ROOM] = Region("Gerudo Training Grounds MQ Sand Room", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST, logic->CanKillEnemy(RE_IRON_KNUCKLE)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, {[]{return true;}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_SAND_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE] = Region("Gerudo Training Grounds MQ Left Side", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_SAND_ROOM, {[]{return true;}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, []{return logic->CanUse(RG_LONGSHOT) ||
ctx->GetTrickOption(RT_GTG_MQ_WIHTOUT_HOOKSHOT) ||
(ctx->GetTrickOption(RT_GTG_MQ_WITH_HOOKSHOT) && logic->IsAdult && logic->CanJumpslash() && logic->CanUse(RG_HOOKSHOT));});}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM] = Region("Gerudo Training Grounds MQ Stalfos Room", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->BlueFireAccess, {[]{return true;}}),
}, {
//Locations
//implies logic->CanKillEnemy(RE_BIG_SKULLTULA)
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true)),
}, {
//Exits
//The here check needs to be before the age check here
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_BEHIND_BLOCK, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}) && logic->CanUse(RG_SILVER_GAUNTLETS);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM_LEDGE, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}) && logic->IsAdult &&
(ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->BlueFire() &&
(logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS)));}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_BEHIND_BLOCK] = Region("Gerudo Training Grounds MQ Behind Block", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
//implies logic->CanKillEnemy(RE_SPIKE)
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_FREEZARD)),
}, {});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM_LEDGE] = Region("Gerudo Training Grounds MQ Statue Room Ledge", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, {[]{return true;}}),
//implies dropping down to hit the switch. Using swords, especially master, is a bit awkward, may be trick worthy, but is only relevant with other tricks
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_MAGENTA_FIRE_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM_LEDGE, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG);});}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM, {[]{return true;}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_MAGENTA_FIRE_ROOM] = Region("Gerudo Training Grounds MQ Magenta Fire Room", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_ICE_ARROWS_CHEST, logic->MQGTGMazeSwitch),}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM_LEDGE, {[]{return true;}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM] = Region("Gerudo Training Grounds MQ Statue ROom", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST, logic->CanUse(RG_FAIRY_BOW)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM_LEDGE, {[]{return logic->CanUse(RG_LONGSHOT);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_TORCH_SLUG_ROOM, {[]{return true;}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_TORCH_SLUG_ROOM] = Region("Gerudo Training Grounds MQ Torch Slug Room", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
//implies logic->CanKillEnemy(RE_TORCH_SLUG)
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_SECOND_IRON_KNUCKLE_CHEST, logic->CanKillEnemy(RE_IRON_KNUCKLE)),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_FLAME_CIRCLE_CHEST, logic->CanHitSwitch(ED_RANG_OR_HOOKSHOT)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_TORCH_SLUG_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_SWITCH_LEDGE, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_TORCH_SLUG_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_SWITCH_LEDGE] = Region("Gerudo Training Grounds MQ Switch Ledge", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->MQGTGRightSideSwitch, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}),
EventAccess(&logic->GTGPlatformSilverRupees, {[]{return logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_HOVER_BOOTS);}}),
}, { }, {
//Locations //Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, logic->IsAdult && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))), LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, logic->IsAdult && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))),
}, { }, {
//Exits //Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, {[]{return (logic->CanUse(RG_FAIRY_BOW) || (logic->CanUse(RG_LONGSHOT) && logic->HasFireSource())) && logic->CanUse(RG_HOVER_BOOTS) && logic->IsAdult && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_BIGGORON_SWORD));}}), Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->CanUse(RG_FIRE_ARROWS);}}),
//the fire bubble here is a jerk if you are aiming for the nearest hook platform, you have to aim to the right hand side with hook to dodge it
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_PLATFORMS_UNLIT_TORCH, {[]{return logic->CanUse(RG_LONGSHOT) || (logic->GTGPlatformSilverRupees && logic->CanUse(RG_HOOKSHOT)) ||
((logic->CanUse(RG_FIRE_ARROWS) && logic->GTGPlatformSilverRupees) && logic->CanUse(RG_HOVER_BOOTS));}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT, {[]{return logic->MQGTGRightSideSwitch && logic->CanUse(RG_LONGSHOT);}}),
});
//this region exists to place silver rupee items on later, normally it's all on fire and cannot be stood on without access from another area
//This covers the 2 platforms that can be jumped to directly from RR_GERUDO_TRAINING_GROUNDS_MQ_SWITCH_LEDGE
//the unshuffled rupee collection is handled by the event GTGPlatformSilverRupees
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_LEDGE_SIDE_PLATFORMS] = Region("Gerudo Training Grounds MQ Ledge Side Platforms", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
//This is merely to extend this region's logic if you have hovers
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_FURTHEST_PLATFORM, {[]{return logic->CanUse(RG_HOVER_BOOTS);}}),
});
//this region exists to place silver rupee items on later, normally it's all on fire and cannot be stood on without access from another area
//This covers the platform that needs hover boots or the spawned targets to reach from any starting point other than RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT
//the unshuffled rupee collection is handled by the event GTGPlatformSilverRupees
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_FURTHEST_PLATFORM] = Region("Gerudo Training Grounds MQ Furthest Platform", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
//This is merely to extend this region's logic if you have hovers
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->CanUse(RG_HOVER_BOOTS);}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_PLATFORMS_UNLIT_TORCH] = Region("Gerudo Training Grounds MQ Platforms Unlit Torch", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->GTGPlatformSilverRupees, {[]{return logic->HasFireSource() && logic->CanUse(RG_HOVER_BOOTS);}}),
}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, {[]{return logic->GTGPlatformSilverRupees;}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->HasFireSource() && logic->CanUse(RG_HOVER_BOOTS);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_TORCH_SIDE_PLATFORMS, {[]{return logic->HasFireSource() || logic->CanUse(RG_LONGSHOT);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT, {[]{return logic->MQGTGRightSideSwitch && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->HasFireSource()));}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_TORCH_SIDE_PLATFORMS] = Region("Gerudo Training Grounds Torch Side Platforms", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {
//Events
//this torch shot is possible as child but tight and obtuse enough to be a trick
EventAccess(&logic->GTGPlatformSilverRupees, {[]{return ((logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS)) && logic->CanUse(RG_HOVER_BOOTS);}}),
}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LEDGE_SIDE_PLATFORMS, {[]{return ((logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS)) && logic->CanUse(RG_HOVER_BOOTS);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_PLATFORMS_UNLIT_TORCH, {[]{return (logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS) ||
logic->CanUse(RG_LONGSHOT);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT, {[]{return logic->MQGTGRightSideSwitch && ((logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS) ||
logic->CanUse(RG_LONGSHOT));}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_ROOM, {[]{return true;}}),
}); });
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER] = Region("Gerudo Training Grounds MQ Underwater", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER] = Region("Gerudo Training Grounds MQ Underwater", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations //Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST, logic->HasFireSource() && logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24 && logic->TakeDamage()), //it is possible to snipe the stingers with bow or sling before dropping in, or just get really lucky, and avoid needing to take damage, but that might be trick worthy
}, {}); LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST, logic->HasFireSource() && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24 && logic->TakeDamage()),
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE] = Region("Gerudo Training Grounds MQ Left Side", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST, logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->HasExplosives()),
}, { }, {
//Exits //Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, {[]{return (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || ctx->GetTrickOption(RT_GTG_MQ_WIHTOUT_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_MQ_WITH_HOOKSHOT) && logic->IsAdult && logic->CanUse(RG_HOOKSHOT));}}), Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_PLATFORMS_UNLIT_TORCH, {[]{return true;}}),
//Trick: (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || LogicGtgMQWithoutHookshot || (LogicGtgMQWithHookshot && logic->IsAdult && logic->CanUse(RG_HOOKSHOT))
}); });
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM] = Region("Gerudo Training Grounds MQ Stalfos Room", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT] = Region("Gerudo Training Grounds MQ Maze Right", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {
//Events //Events
EventAccess(&logic->BlueFireAccess, {[]{return logic->BlueFireAccess || logic->HasBottle();}}), EventAccess(&logic->GTGPlatformSilverRupees, {[]{return logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_HOVER_BOOTS);}}),
}, { }, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST, logic->IsAdult && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST, logic->CanUse(RG_SILVER_GAUNTLETS) && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, {[]{return logic->IsAdult && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && (ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->BlueFire() && (logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)));}}),
//Trick: logic->IsAdult && (LogicLensGtgMQ || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->BlueFire && (logic->CanUse(RG_SONG_OF_TIME) || (LogicGtgFakeWall && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS] = Region("Gerudo Training Grounds MQ Back Areas", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST, logic->CanUse(RG_FAIRY_BOW)),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_SECOND_IRON_KNUCKLE_CHEST, logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_FLAME_CIRCLE_CHEST, logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->HasExplosives()),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, {[]{return logic->CanUse(RG_LONGSHOT);}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT] = Region("Gerudo Training Grounds MQ Central Maze Right", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations //Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_CENTRAL_CHEST, true), LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_CENTRAL_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_SIDE_CHEST, true), LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_SIDE_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_ICE_ARROWS_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 3)),
}, { }, {
//Exits //Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, {[]{return logic->IsAdult && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_FAIRY_BOW)));}}), Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, {[]{return true;}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, {[]{return logic->IsAdult && logic->CanUse(RG_HOOKSHOT);}}), Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_PLATFORMS_UNLIT_TORCH, {[]{return logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT) || (logic->GTGPlatformSilverRupees && logic->CanUse(RG_HOVER_BOOTS));}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->CanUse(RG_FIRE_ARROWS);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_FURTHEST_PLATFORM, {[]{return logic->CanUse(RG_FIRE_ARROWS);}}),
}); });
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_ROOM] = Region("Gerudo Training Grounds MQ Dinolfos Room", "Gerudo Training Grounds", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {
//Events
//EventAccess(&WallFairy, {[]{return WallFairy || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}}),
}, {
//Locations
//implies logic->CanKillEnemy(RE_LIZALFOS and logic->CanKillEnemy(RE_DODONGO)
//is logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true) && logic->CanKillEnemy(RE_ARMOS, ED_CLOSE, true, 1, true) broken down to exclude sticks, as it take too many to clear the room
//Proper enemy kill room ammo logic is needed to handle this room
//some combinations may be impossible without taking damage, keep an eye out for issues here
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_FAIRY_BOW) ||
((logic->CanUse(RG_NUTS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)))),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_TORCH_SIDE_PLATFORMS, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_ROOM, []{return logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_FAIRY_BOW) ||
((logic->CanUse(RG_NUTS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)));});}}),
});
} }
} }

View File

@ -45,40 +45,67 @@ void RegionTable_Init_IceCavern() {
| MASTER QUEST DUNGEON | | MASTER QUEST DUNGEON |
---------------------------*/ ---------------------------*/
if (ctx->GetDungeon(ICE_CAVERN)->IsMQ()) { if (ctx->GetDungeon(ICE_CAVERN)->IsMQ()) {
areaTable[RR_ICE_CAVERN_MQ_BEGINNING] = Region("Ice Cavern MQ Beginning", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { areaTable[RR_ICE_CAVERN_MQ_BEGINNING] = Region("Ice Cavern MQ Beginning", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_ICE_CAVERN_ENTRYWAY, {[]{return true;}}),
//It is in logic to use a pot to hit the toggle switch here.
Entrance(RR_ICE_CAVERN_MQ_HUB, {[]{return true;}}),
});
areaTable[RR_ICE_CAVERN_MQ_HUB] = Region("Ice Cavern MQ Hub", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {
//Events //Events
EventAccess(&logic->FairyPot, {[]{return true;}}), EventAccess(&logic->FairyPot, {[]{return true;}}),
}, {}, { }, {}, {
//Exits //Exits
Entrance(RR_ICE_CAVERN_ENTRYWAY, {[]{return true;}}), //the switch for the glass blocking the entrance is linked to the switch that controls the glass around the skulltulla in RR_ICE_CAVERN_MQ_SCARECROW_ROOM
Entrance(RR_ICE_CAVERN_MQ_MAP_ROOM, {[]{return logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_DINS_FIRE) || (logic->HasExplosives() && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW)));}}), //if you clear the ice, you can hit it with a pot from here.
Entrance(RR_ICE_CAVERN_BEGINNING, {[]{return logic->BlueFire();}}),
Entrance(RR_ICE_CAVERN_MQ_MAP_ROOM, {[]{return Here(RR_ICE_CAVERN_MQ_BEGINNING, []{return logic->CanKillEnemy(RE_WHITE_WOLFOS) && logic->CanKillEnemy(RE_FREEZARD);});}}),
Entrance(RR_ICE_CAVERN_MQ_COMPASS_ROOM, {[]{return logic->IsAdult && logic->BlueFire();}}), Entrance(RR_ICE_CAVERN_MQ_COMPASS_ROOM, {[]{return logic->IsAdult && logic->BlueFire();}}),
Entrance(RR_ICE_CAVERN_MQ_IRON_BOOTS_REGION, {[]{return logic->BlueFire();}}), Entrance(RR_ICE_CAVERN_MQ_STALFOS_ROOM, {[]{return logic->BlueFire();}}),
}); });
areaTable[RR_ICE_CAVERN_MQ_MAP_ROOM] = Region("Ice Cavern MQ Map Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { areaTable[RR_ICE_CAVERN_MQ_MAP_ROOM] = Region("Ice Cavern MQ Map Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {
//Events //Events
EventAccess(&logic->BlueFireAccess, {[]{return logic->BlueFireAccess || (logic->HasBottle() && logic->CanJumpslashExceptHammer());}}), //Child can fit between the stalagmites on the left hand side
EventAccess(&logic->BlueFireAccess, {[]{return logic->IsChild || logic->CanJumpslash() || logic->HasExplosives();}}),
}, { }, {
//Locations //Locations
LOCATION(RC_ICE_CAVERN_MQ_MAP_CHEST, logic->BlueFire() && (logic->CanJumpslash() || logic->HasExplosives() || logic->CanUseProjectile())), LOCATION(RC_ICE_CAVERN_MQ_MAP_CHEST, logic->BlueFire() && Here(RR_ICE_CAVERN_MQ_MAP_ROOM, []{return logic->CanHitSwitch();})),
}, {}); }, {});
areaTable[RR_ICE_CAVERN_MQ_IRON_BOOTS_REGION] = Region("Ice Cavern MQ Iron Boots Region", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { areaTable[RR_ICE_CAVERN_MQ_SCARECROW_ROOM] = Region("Ice Cavern MQ Scarecrow Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations //Locations
LOCATION(RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST, logic->IsAdult && (logic->CanJumpslash())), LOCATION(RC_ICE_CAVERN_MQ_GS_ICE_BLOCK, (logic->BlueFire() && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)) || (logic->IsAdult && logic->CanHitSwitch(ED_LONG_JUMPSLASH))),
LOCATION(RC_SHEIK_IN_ICE_CAVERN, logic->IsAdult && (logic->CanJumpslash())), LOCATION(RC_ICE_CAVERN_MQ_GS_SCARECROW, logic->CanUse(RG_SCARECROW) || (logic->IsAdult && (logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_ICE_MQ_SCARECROW)))),
LOCATION(RC_ICE_CAVERN_MQ_GS_ICE_BLOCK, logic->CanAttack()), }, {
LOCATION(RC_ICE_CAVERN_MQ_GS_SCARECROW, logic->CanUse(RG_SCARECROW) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_ICE_MQ_SCARECROW) && logic->IsAdult)), //Exits
//Tricks: (logic->CanUse(RG_SCARECROW) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_LONGSHOT)) || LogicIceMQScarecrow) && logic->IsAdult Entrance(RR_ICE_CAVERN_MQ_HUB, {[]{return logic->BlueFire();}}),
}, {}); //Assumes RR_ICE_CAVERN_MQ_HUB access for a pot if using blue fire
Entrance(RR_ICE_CAVERN_MQ_STALFOS_ROOM, {[]{return logic->IsAdult && logic->BlueFire();}}),
});
areaTable[RR_ICE_CAVERN_MQ_COMPASS_ROOM] = Region("Ice Cavern MQ Compass Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { areaTable[RR_ICE_CAVERN_MQ_STALFOS_ROOM] = Region("Ice Cavern MQ Stalfos Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST, logic->CanKillEnemy(RE_STALFOS)),
LOCATION(RC_SHEIK_IN_ICE_CAVERN, logic->CanKillEnemy(RE_STALFOS)),
}, {
//Exits
Entrance(RR_ICE_CAVERN_MQ_SCARECROW_ROOM, {[]{return logic->BlueFire() && Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}}),
Entrance(RR_ICE_CAVERN_MQ_BEGINNING, {[]{return logic->CanUse(RG_IRON_BOOTS) && Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}}),
});
areaTable[RR_ICE_CAVERN_MQ_COMPASS_ROOM] = Region("Ice Cavern MQ Compass Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->BlueFireAccess, {[]{return true;}}),
}, {
//Locations //Locations
LOCATION(RC_ICE_CAVERN_MQ_COMPASS_CHEST, true), LOCATION(RC_ICE_CAVERN_MQ_COMPASS_CHEST, true),
//It is possible for child with master, BGS or sticks, or adult with BGS, to hit this switch through the ice with a crouchstab, but it's precise and unintuitive for a trick
LOCATION(RC_ICE_CAVERN_MQ_FREESTANDING_POH, logic->HasExplosives()), LOCATION(RC_ICE_CAVERN_MQ_FREESTANDING_POH, logic->HasExplosives()),
LOCATION(RC_ICE_CAVERN_MQ_GS_RED_ICE, logic->CanUse(RG_SONG_OF_TIME) || ctx->GetTrickOption(RT_ICE_MQ_RED_ICE_GS)), //doing RT_ICE_MQ_RED_ICE_GS as child is untested, as I could not perform the trick reliably even as adult
//Trick: logic->CanUse(RG_SONG_OF_TIME) || LogicIceMQRedIceGS LOCATION(RC_ICE_CAVERN_MQ_GS_RED_ICE, (ctx->GetOption(RSK_BLUE_FIRE_ARROWS) && logic->CanUse(RG_ICE_ARROWS)) ||
(logic->CanUse(RG_BOTTLE_WITH_BLUE_FIRE) && (logic->CanUse(RG_SONG_OF_TIME) || (logic->IsAdult && ctx->GetTrickOption(RT_ICE_MQ_RED_ICE_GS))) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA))),
}, {}); }, {});
} }
} }

View File

@ -410,7 +410,7 @@ namespace Rando {
//RANDOTODO quantity is a placeholder for proper ammo use calculation logic. in time will want updating to account for ammo capacity //RANDOTODO quantity is a placeholder for proper ammo use calculation logic. in time will want updating to account for ammo capacity
//Can we kill this enemy //Can we kill this enemy
bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wallOrFloor, uint8_t quantity) { bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wallOrFloor, uint8_t quantity, bool timer) {
bool killed = false; bool killed = false;
switch(enemy) { switch(enemy) {
case RE_GOLD_SKULLTULA: case RE_GOLD_SKULLTULA:
@ -424,9 +424,14 @@ namespace Rando {
//hammer jumpslash cannot damage these, but hammer swing can //hammer jumpslash cannot damage these, but hammer swing can
killed = killed || CanUse(RG_MEGATON_HAMMER); killed = killed || CanUse(RG_MEGATON_HAMMER);
[[fallthrough]]; [[fallthrough]];
case ED_HAMMER_JUMPSLASH: case ED_SHORT_JUMPSLASH:
killed = killed || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_KOKIRI_SWORD);
[[fallthrough]];
case ED_MASTER_SWORD_JUMPSLASH: case ED_MASTER_SWORD_JUMPSLASH:
killed = killed || CanJumpslashExceptHammer(); killed = killed || CanUse(RG_MASTER_SWORD);
[[fallthrough]];
case ED_LONG_JUMPSLASH:
killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
[[fallthrough]]; [[fallthrough]];
case ED_RANG_OR_HOOKSHOT: case ED_RANG_OR_HOOKSHOT:
//RANDOTODO test dins, bomb and chu range in a practical example //RANDOTODO test dins, bomb and chu range in a practical example
@ -461,7 +466,7 @@ namespace Rando {
case RE_STALFOS: 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 //RANDOTODO Add trick to kill stalfos with sticks, and a second one for bombs without stunning. Higher ammo logic for bombs is also plausible
return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_FAIRY_BOW) || CanUse(RG_BOMBCHU_5) || return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_FAIRY_BOW) || CanUse(RG_BOMBCHU_5) ||
(quantity <= 2 && (CanUse(RG_NUTS) || HookshotOrBoomerang()) && CanUse(RG_BOMB_BAG)) || (quantity <= 1 && CanUse(RG_STICKS)); (quantity <= 2 && !timer && (CanUse(RG_NUTS) || HookshotOrBoomerang()) && CanUse(RG_BOMB_BAG)) || (quantity <= 1 && CanUse(RG_STICKS));
//Needs 16 bombs, but is in default logic in N64, probably because getting the hits is quite easy. //Needs 16 bombs, but is in default logic in N64, probably because getting the hits is quite easy.
//bow and sling can wake them and damage after they shed their armour, so could reduce ammo requirements for explosives to 10. //bow and sling can wake them and damage after they shed their armour, so could reduce ammo requirements for explosives to 10.
//requires 8 sticks to kill so would be a trick unless we apply higher stick bag logic //requires 8 sticks to kill so would be a trick unless we apply higher stick bag logic
@ -474,7 +479,8 @@ namespace Rando {
case RE_FLARE_DANCER: 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))); return CanUse(RG_MEGATON_HAMMER) || CanUse(RG_HOOKSHOT) || (HasExplosives() && (CanJumpslashExceptHammer() || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG)));
case RE_WOLFOS: 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_WHITE_WOLFOS:
return CanJumpslash() || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOMBCHU_5) || CanUse(RG_DINS_FIRE) || (CanUse(RG_BOMB_BAG) && (CanUse(RG_NUTS) || CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG)));
case RE_REDEAD: case RE_REDEAD:
return CanJumpslash() || CanUse(RG_DINS_FIRE); return CanJumpslash() || CanUse(RG_DINS_FIRE);
case RE_MEG: case RE_MEG:
@ -487,9 +493,13 @@ namespace Rando {
return CanJumpslash() || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || HasExplosives()/* || (CanUse(RG_DINS_FIRE) && (CanUse(RG_NUTS) || CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG)))*/; return CanJumpslash() || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || HasExplosives()/* || (CanUse(RG_DINS_FIRE) && (CanUse(RG_NUTS) || CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG)))*/;
case RE_DINOLFOS: case RE_DINOLFOS:
//stunning + bombs is possible but painful, as it loves to dodge the bombs and hookshot. it also dodges chus but if you cook it so it detonates under the dodge it usually gets caught on landing //stunning + bombs is possible but painful, as it loves to dodge the bombs and hookshot. it also dodges chus but if you cook it so it detonates under the dodge it usually gets caught on landing
return CanJumpslash() || CanUse(RG_FAIRY_BOW) || CanUse(RG_BOMBCHU_5) || CanUse(RG_FAIRY_SLINGSHOT); return CanJumpslash() || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || (!timer && CanUse(RG_BOMBCHU_5));
case RE_TORCH_SLUG: case RE_TORCH_SLUG:
return CanJumpslash() || HasExplosives() || CanUse(RG_FAIRY_BOW); return CanJumpslash() || HasExplosives() || CanUse(RG_FAIRY_BOW);
case RE_FREEZARD:
return CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_STICKS) || HasExplosives() || CanUse(RG_HOOKSHOT) || CanUse(RG_DINS_FIRE) || CanUse(RG_FIRE_ARROWS);
case RE_SPIKE:
return CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_STICKS) || HasExplosives() || CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_DINS_FIRE);
default: default:
SPDLOG_ERROR("CanKillEnemy reached `default`."); SPDLOG_ERROR("CanKillEnemy reached `default`.");
assert(false); assert(false);
@ -519,9 +529,12 @@ namespace Rando {
case RE_STALFOS: case RE_STALFOS:
case RE_FLARE_DANCER: case RE_FLARE_DANCER:
case RE_WOLFOS: case RE_WOLFOS:
case RE_WHITE_WOLFOS:
case RE_FLOORMASTER: case RE_FLOORMASTER:
case RE_MEG: case RE_MEG:
case RE_ARMOS: case RE_ARMOS:
case RE_FREEZARD:
case RE_SPIKE:
return true; return true;
case RE_BIG_SKULLTULA: case RE_BIG_SKULLTULA:
//hammer jumpslash can pass, but only on flat land where you can kill with hammer swing //hammer jumpslash can pass, but only on flat land where you can kill with hammer swing
@ -561,11 +574,14 @@ namespace Rando {
case RE_IRON_KNUCKLE: case RE_IRON_KNUCKLE:
case RE_FLARE_DANCER: case RE_FLARE_DANCER:
case RE_WOLFOS: case RE_WOLFOS:
case RE_WHITE_WOLFOS:
case RE_FLOORMASTER: case RE_FLOORMASTER:
case RE_REDEAD: case RE_REDEAD:
case RE_MEG: case RE_MEG:
case RE_ARMOS: case RE_ARMOS:
case RE_GREEN_BUBBLE: case RE_GREEN_BUBBLE:
case RE_FREEZARD:
case RE_SPIKE:
return true; return true;
case RE_MAD_SCRUB: case RE_MAD_SCRUB:
case RE_KEESE: case RE_KEESE:
@ -591,7 +607,7 @@ namespace Rando {
switch(enemy) { switch(enemy) {
case RE_GOLD_SKULLTULA: case RE_GOLD_SKULLTULA:
//RANDOTODO double check all jumpslash kills that might be out of jump/backflip range //RANDOTODO double check all jumpslash kills that might be out of jump/backflip range
return distance <= ED_HAMMER_JUMPSLASH || (distance <= ED_RANG_OR_HOOKSHOT && (CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG))) || (distance == ED_LONGSHOT && CanUse(RG_LONGSHOT)); return distance <= ED_SHORT_JUMPSLASH || (distance <= ED_RANG_OR_HOOKSHOT && (CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG))) || (distance == ED_LONGSHOT && CanUse(RG_LONGSHOT));
case RE_KEESE: case RE_KEESE:
case RE_FIRE_KEESE: case RE_FIRE_KEESE:
return true; return true;
@ -660,8 +676,31 @@ namespace Rando {
return CanJumpslashExceptHammer() || CanUse(RG_MEGATON_HAMMER); return CanJumpslashExceptHammer() || CanUse(RG_MEGATON_HAMMER);
} }
bool Logic::CanHitSwitch() { bool Logic::CanHitSwitch(EnemyDistance distance) {
return CanUse(RG_FAIRY_SLINGSHOT) || CanJumpslash() || HasExplosives() || CanUse(RG_FAIRY_BOW) || CanUse(RG_BOOMERANG) || CanUse(RG_HOOKSHOT); bool hit = false;
switch (distance){
case ED_CLOSE:
case ED_SHORT_JUMPSLASH:
hit = hit || CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MEGATON_HAMMER);
[[fallthrough]];
case ED_MASTER_SWORD_JUMPSLASH:
hit = hit || CanUse(RG_MASTER_SWORD);
[[fallthrough]];
case ED_LONG_JUMPSLASH:
hit = hit || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
[[fallthrough]];
case ED_RANG_OR_HOOKSHOT:
//RANDOTODO test bomb and chu range in a practical example
hit = hit || HookshotOrBoomerang() || HasExplosives() ;
[[fallthrough]];
case ED_LONGSHOT:
hit = hit || CanUse(RG_LONGSHOT);
[[fallthrough]];
case ED_FAR:
hit = CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW);
break;
}
return hit;
} }
bool Logic::CanDamage() { bool Logic::CanDamage() {
@ -1905,6 +1944,8 @@ namespace Rando {
ForestClearBelowBowChest = false; ForestClearBelowBowChest = false;
ForestOpenBossCorridor = false; ForestOpenBossCorridor = false;
ShadowTrialFirstChest = false; ShadowTrialFirstChest = false;
MQGTGMazeSwitch = false;
GTGPlatformSilverRupees = false;
StopPerformanceTimer(PT_LOGIC_RESET); StopPerformanceTimer(PT_LOGIC_RESET);
} }

View File

@ -147,6 +147,9 @@ class Logic {
bool ForestClearBelowBowChest = false; //a better name that covers both versions would be nice bool ForestClearBelowBowChest = false; //a better name that covers both versions would be nice
bool ForestOpenBossCorridor = false; bool ForestOpenBossCorridor = false;
bool ShadowTrialFirstChest = false; bool ShadowTrialFirstChest = false;
bool MQGTGMazeSwitch = false;
bool MQGTGRightSideSwitch = false;
bool GTGPlatformSilverRupees = false;
/* --- END OF HELPERS AND LOCATION ACCESS --- */ /* --- END OF HELPERS AND LOCATION ACCESS --- */
@ -160,7 +163,7 @@ class Logic {
bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched); bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched);
bool CanDoGlitch(GlitchType glitch); bool CanDoGlitch(GlitchType glitch);
bool CanEquipSwap(RandomizerGet itemName); bool CanEquipSwap(RandomizerGet itemName);
bool CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool wallOrFloor = true, uint8_t quantity = 1); bool CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool wallOrFloor = true, uint8_t quantity = 1, bool timer = false);
bool CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool wallOrFloor = true); bool CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool wallOrFloor = true);
bool CanAvoidEnemy(RandomizerEnemy enemy); bool CanAvoidEnemy(RandomizerEnemy enemy);
bool CanGetEnemyDrop(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool aboveLink = false); bool CanGetEnemyDrop(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool aboveLink = false);
@ -175,7 +178,7 @@ class Logic {
bool HasBottle(); bool HasBottle();
bool CanJumpslashExceptHammer(); bool CanJumpslashExceptHammer();
bool CanJumpslash(); bool CanJumpslash();
bool CanHitSwitch(); bool CanHitSwitch(EnemyDistance distance = ED_CLOSE);
bool CanDamage(); bool CanDamage();
bool CanAttack(); bool CanAttack();
bool BombchusEnabled(); bool BombchusEnabled();

View File

@ -820,8 +820,10 @@ typedef enum {
RR_ICE_CAVERN_MAIN, RR_ICE_CAVERN_MAIN,
RR_ICE_CAVERN_MQ_BEGINNING, RR_ICE_CAVERN_MQ_BEGINNING,
RR_ICE_CAVERN_MQ_HUB,
RR_ICE_CAVERN_MQ_MAP_ROOM, RR_ICE_CAVERN_MQ_MAP_ROOM,
RR_ICE_CAVERN_MQ_IRON_BOOTS_REGION, RR_ICE_CAVERN_MQ_SCARECROW_ROOM,
RR_ICE_CAVERN_MQ_STALFOS_ROOM,
RR_ICE_CAVERN_MQ_COMPASS_ROOM, RR_ICE_CAVERN_MQ_COMPASS_ROOM,
RR_GERUDO_TRAINING_GROUNDS_LOBBY, RR_GERUDO_TRAINING_GROUNDS_LOBBY,
@ -835,12 +837,25 @@ typedef enum {
RR_GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, RR_GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM,
RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY,
RR_GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_HIDDEN_ROOM,
RR_GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_FIRST_LOCK,
RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_CENTER,
RR_GERUDO_TRAINING_GROUNDS_MQ_SAND_ROOM,
RR_GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, RR_GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE,
RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM,
RR_GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, RR_GERUDO_TRAINING_GROUNDS_MQ_BEHIND_BLOCK,
RR_GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM_LEDGE,
RR_GERUDO_TRAINING_GROUNDS_MQ_MAGENTA_FIRE_ROOM,
RR_GERUDO_TRAINING_GROUNDS_MQ_STATUE_ROOM,
RR_GERUDO_TRAINING_GROUNDS_MQ_TORCH_SLUG_ROOM,
RR_GERUDO_TRAINING_GROUNDS_MQ_SWITCH_LEDGE,
RR_GERUDO_TRAINING_GROUNDS_MQ_LEDGE_SIDE_PLATFORMS,
RR_GERUDO_TRAINING_GROUNDS_MQ_FURTHEST_PLATFORM,
RR_GERUDO_TRAINING_GROUNDS_MQ_TORCH_SIDE_PLATFORMS,
RR_GERUDO_TRAINING_GROUNDS_MQ_PLATFORMS_UNLIT_TORCH,
RR_GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_ROOM,
RR_GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER,
RR_GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT,
RR_GANONS_CASTLE_LOBBY, RR_GANONS_CASTLE_LOBBY,
RR_GANONS_CASTLE_MAIN, RR_GANONS_CASTLE_MAIN,
@ -4482,12 +4497,19 @@ typedef enum {
RE_GREEN_BUBBLE, RE_GREEN_BUBBLE,
RE_DINOLFOS, RE_DINOLFOS,
RE_TORCH_SLUG, RE_TORCH_SLUG,
RE_FREEZARD,
RE_SPIKE,
RE_WHITE_WOLFOS,
} RandomizerEnemy; } RandomizerEnemy;
//RANDOTODO compare child long jumpslash range with adult short
typedef enum { typedef enum {
ED_CLOSE, ED_CLOSE,
ED_HAMMER_JUMPSLASH, //hammer or kokiri sword
ED_SHORT_JUMPSLASH,
ED_MASTER_SWORD_JUMPSLASH, ED_MASTER_SWORD_JUMPSLASH,
//sticks or BGS
ED_LONG_JUMPSLASH,
ED_RANG_OR_HOOKSHOT, ED_RANG_OR_HOOKSHOT,
ED_LONGSHOT, ED_LONGSHOT,
ED_FAR, ED_FAR,