Shuffle Grab (#5719)

AKA str0. Named in-game item Power Bracelet

Co-authored-by: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com>
This commit is contained in:
Philip Dubé
2026-01-18 05:32:31 +00:00
committed by GitHub
parent 60205ec0bd
commit 18b00e7bc1
41 changed files with 352 additions and 247 deletions
+7 -1
View File
@@ -1,8 +1,14 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "functions.h"
extern SaveContext gSaveContext;
}
void RegisterSkipAmyPuzzle() {
COND_VB_SHOULD(VB_AMY_SOLVE, CVarGetInteger(CVAR_ENHANCEMENT("SkipAmyPuzzle"), 0), { *should = true; });
COND_VB_SHOULD(VB_AMY_SOLVE, CVarGetInteger(CVAR_ENHANCEMENT("SkipAmyPuzzle"), 0),
{ *should = !IS_RANDO || Flags_GetRandomizerInf(RAND_INF_CAN_GRAB); });
}
static RegisterShipInitFunc initFunc(RegisterSkipAmyPuzzle, { CVAR_ENHANCEMENT("SkipAmyPuzzle") });
@@ -1878,6 +1878,14 @@ typedef enum {
// - None
VB_PREVENT_ADULT_STICK,
// #### `result`
// ```c
// varies
// ```
// #### `args`
// - None
VB_PREVENT_STRENGTH,
// #### `result`
// ```c
// true
@@ -173,7 +173,6 @@ void GenerateItemPool() {
AddItemToPool(RG_GREG_RUPEE, 1, 1, 1, 1);
AddItemToPool(RG_PROGRESSIVE_HOOKSHOT, 2, 2, 2, 2);
AddItemToPool(RG_HYLIAN_SHIELD, 1, 1, 1, 1);
AddItemToPool(RG_PROGRESSIVE_STRENGTH, 4, 3, 3, 3);
AddItemToPool(RG_DOUBLE_DEFENSE, 2, 1, 0, 0);
AddItemToPool(RG_BIGGORON_SWORD, 2, 1, 1, 0);
bool isScrubs = ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_ALL);
@@ -410,6 +409,9 @@ void GenerateItemPool() {
AddItemToPool(RG_OPEN_CHEST, 2, 1, 1, 1);
}
int powerBracelet = ctx->GetOption(RSK_SHUFFLE_GRAB) ? 1 : 0;
AddItemToPool(RG_PROGRESSIVE_STRENGTH, 4 + powerBracelet, 3 + powerBracelet, 3 + powerBracelet, 3 + powerBracelet);
if (ctx->GetOption(RSK_SHUFFLE_BEEHIVES)) {
PlaceItemsForType(RCTYPE_BEEHIVE, true, true);
}
+17
View File
@@ -15,6 +15,7 @@ extern "C" {
#include "objects/object_box/object_box.h"
#include "objects/object_gi_key/object_gi_key.h"
#include "objects/object_gi_bosskey/object_gi_bosskey.h"
#include "objects/object_gi_bracelet/object_gi_bracelet.h"
#include "objects/object_gi_compass/object_gi_compass.h"
#include "objects/object_gi_map/object_gi_map.h"
#include "objects/object_gi_hearts/object_gi_hearts.h"
@@ -1155,6 +1156,22 @@ extern "C" void Randomizer_DrawKneePads(PlayState* play, GetItemEntry* getItemEn
CLOSE_DISPS(play->state.gfxCtx);
}
extern "C" void Randomizer_DrawPowerBracelet(PlayState* play, GetItemEntry* getItemEntry) {
OPEN_DISPS(play->state.gfxCtx);
Gfx_SetupDL_25Opa(play->state.gfxCtx);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_MODELVIEW | G_MTX_LOAD);
gSPGrayscale(POLY_OPA_DISP++, true);
gDPSetGrayscaleColor(POLY_OPA_DISP++, 80, 80, 80, 255);
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gGiGoronBraceletDL);
gSPGrayscale(POLY_OPA_DISP++, false);
CLOSE_DISPS(play->state.gfxCtx);
}
static Gfx* boxLidDL;
static Gfx* boxBodyDL;
extern "C" void EnBox_PostLimbDrawOverride(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
+1
View File
@@ -22,6 +22,7 @@ void Randomizer_DrawTriforcePiece(PlayState* play, GetItemEntry getItemEntry);
void Randomizer_DrawTriforcePieceGI(PlayState* play, GetItemEntry getItemEntry);
void Randomizer_DrawOcarinaButton(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawBronzeScale(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawPowerBracelet(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawKneePads(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawOpenChest(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getItemEntry);
@@ -1063,6 +1063,13 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
*should = false;
break;
}
case VB_PREVENT_STRENGTH: {
if (!Flags_GetRandomizerInf(RAND_INF_CAN_GRAB)) {
GET_PLAYER(gPlayState)->stateFlags2 &= ~PLAYER_STATE2_MOVING_DYNAPOLY;
*should = true;
}
break;
}
case VB_GORONS_CONSIDER_FIRE_TEMPLE_FINISHED: {
*should = Flags_GetEventChkInf(EVENTCHKINF_USED_FIRE_TEMPLE_BLUE_WARP);
break;
+4
View File
@@ -278,6 +278,10 @@ std::shared_ptr<GetItemEntry> Item::GetGIEntry() const { // NOLINT(*-no-recursio
}
break;
case RG_PROGRESSIVE_STRENGTH:
if (!logic->CheckRandoInf(RAND_INF_CAN_GRAB)) {
actual = RG_POWER_BRACELET;
break;
}
switch (logic->CurrentUpgrade(UPG_STRENGTH)) {
case 0:
actual = RG_GORONS_BRACELET;
@@ -366,11 +366,13 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_GERUDO_MASK] = Item(RG_GERUDO_MASK, Text{ "Gerudo Mask", "Masque de Gerudo", TODO_TRANSLATE }, ITEMTYPE_ITEM, RG_GERUDO_MASK, true, LOGIC_NONE, RHT_MASK_GERUDO, RG_GERUDO_MASK, OBJECT_GI_GERUDOMASK, GID_MASK_GERUDO, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
itemTable[RG_MASK_OF_TRUTH] = Item(RG_MASK_OF_TRUTH, Text{ "Mask of Truth", "Masque de Vérité", TODO_TRANSLATE }, ITEMTYPE_ITEM, RG_MASK_OF_TRUTH, true, LOGIC_NONE, RHT_MASK_TRUTH, RG_MASK_OF_TRUTH, OBJECT_GI_TRUTH_MASK, GID_MASK_TRUTH, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
itemTable[RG_BRONZE_SCALE] = Item(RG_BRONZE_SCALE, Text{ "Bronze Scale", "Écaille de Bronze", "Bronzene Schuppe" }, ITEMTYPE_ITEM, GI_SCALE_SILVER, true, LOGIC_PROGRESSIVE_SCALE, RHT_BRONZE_SCALE, RG_BRONZE_SCALE, OBJECT_GI_SCALE, GID_SCALE_SILVER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"the ", "die ", "le "});
itemTable[RG_BRONZE_SCALE] = Item(RG_BRONZE_SCALE, Text{ "Bronze Scale", "Écaille de Bronze", "Bronzene Schuppe" }, ITEMTYPE_ITEM, GI_SCALE_SILVER, true, LOGIC_PROGRESSIVE_SCALE, RHT_NONE, RG_BRONZE_SCALE, OBJECT_GI_SCALE, GID_SCALE_SILVER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"the ", "die ", "le "});
itemTable[RG_BRONZE_SCALE].SetCustomDrawFunc(Randomizer_DrawBronzeScale);
itemTable[RG_CRAWL] = Item(RG_CRAWL, Text{ "Crawl", "Ramper", "Kriechen" }, ITEMTYPE_ITEM, GI_SHIELD_DEKU, true, LOGIC_NONE, RHT_CRAWL, RG_CRAWL, OBJECT_GI_SHIELD_1, GID_SHIELD_DEKU, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
itemTable[RG_CRAWL].SetCustomDrawFunc(Randomizer_DrawKneePads);
itemTable[RG_POWER_BRACELET] = Item(RG_POWER_BRACELET, Text{ "Power Bracelet", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, GI_BRACELET, true, LOGIC_NONE, RHT_NONE, RG_POWER_BRACELET, OBJECT_GI_BRACELET, GID_BRACELET, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
itemTable[RG_POWER_BRACELET].SetCustomDrawFunc(Randomizer_DrawPowerBracelet);
itemTable[RG_OPEN_CHEST] = Item(RG_OPEN_CHEST, Text{ "Open Chests", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, GI_KEY_SMALL, true, LOGIC_NONE, RHT_OPEN_CHEST, RG_OPEN_CHEST, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
itemTable[RG_OPEN_CHEST].SetCustomDrawFunc(Randomizer_DrawOpenChest);
@@ -626,20 +626,20 @@ std::array<Region, RR_MAX> areaTable;
// clang-format off
std::map<RandomizerRegion, SpiritLogicData> Region::spiritLogicData = {
//Vanilla Child uses ExplosiveKeyLogic here because they need to exist for shared adult checks
{RR_SPIRIT_TEMPLE_SUN_ON_FLOOR_1F, {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_2F, {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_ROOM, {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_CHILD, {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;}}},
{RR_SPIRIT_TEMPLE_SUN_ON_FLOOR_1F, {5, 0, 3, 0, []{return true;}, []{return logic->SpiritExplosiveKeyLogic() && logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh() */;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}},
{RR_SPIRIT_TEMPLE_SUN_ON_FLOOR_2F, {5, 0, 3, 0, []{return true/*logic->CanClimbHigh()*/;}, []{return logic->SpiritExplosiveKeyLogic() && logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh() */;}, []{return true/*logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)*/;}}},
{RR_SPIRIT_TEMPLE_2F_MIRROR_ROOM, {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_CHILD, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic()/* && logic->CanClimbHigh()*/;}, []{return logic->SpiritExplosiveKeyLogic() && logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{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->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{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->HasItem(RG_POWER_BRACELET) && logic->SpiritWestToSkull()/* && logic->CanClimbHigh()*/;}, []{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->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{return true;}}},
//Assumes SpiritSunBlockSouthLedge() for all access
{RR_SPIRIT_TEMPLE_SUN_BLOCK_CHEST_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_SUN_BLOCK_CHEST_LEDGE, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic() && logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{return logic->SpiritExplosiveKeyLogic() && logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{return logic->HasItem(RG_POWER_BRACELET)/*((logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)) && logic->HasItem(RG_POWER_BRACELET)) || (logic->CanKillEnemy(RE_BEAMOS) && logic->CanUse(RG_LONGSHOT))*/;}}},
{RR_SPIRIT_TEMPLE_SKULLTULA_STAIRS, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic() && logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{return logic->SpiritExplosiveKeyLogic() && logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{return logic->HasItem(RG_POWER_BRACELET)/*((logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS)) && logic->HasItem(RG_POWER_BRACELET)) || (logic->CanKillEnemy(RE_BEAMOS) && logic->CanUse(RG_LONGSHOT))*/;}}},
{RR_SPIRIT_TEMPLE_OUTER_RIGHT_HAND, {5, 5, 3, 3, []{return logic->OuterWestHandLogic();}, []{return logic->OuterWestHandLogic();}, []{return logic->OuterWestHandLogic();}}},
{RR_SPIRIT_TEMPLE_STATUE_ROOM_ADULT, {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_LEFT_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));}}},
{RR_SPIRIT_TEMPLE_STATUE_ROOM_ADULT, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic() && logic->CanUse(RG_HOOKSHOT)/* && logic->CanClimbHigh()*/;}, []{return logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}},
{RR_SPIRIT_TEMPLE_INNER_LEFT_HAND, {5, 0, 3, 0, []{return logic->SpiritExplosiveKeyLogic() && logic->CanUse(RG_HOOKSHOT)/* && logic->CanClimbHigh()*/;}, []{return logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{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->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{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(SCENE_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(SCENE_SPIRIT_TEMPLE, 6)/* && logic->Climb*/;}, []{return logic->StatueRoomMQKeyLogic()/* && (logic->CanClimb() || logic->CanUse(RG_HOVER_BOOTS))*/;}}},
@@ -648,7 +648,7 @@ std::map<RandomizerRegion, SpiritLogicData> Region::spiritLogicData = {
{RR_SPIRIT_TEMPLE_MQ_INNER_RIGHT_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_RIGHT_HAND, {7, 7, 4, 4, []{return logic->CanHitSwitch() && logic->OuterWestHandMQLogic()/* && logic->CanClimbHigh() && str0*/;}, []{return logic->OuterWestHandMQLogic();}, []{return logic->OuterWestHandMQLogic();}}},
{RR_SPIRIT_TEMPLE_MQ_OUTER_RIGHT_HAND, {7, 7, 4, 4, []{return logic->CanHitSwitch() && logic->OuterWestHandMQLogic() && logic->HasItem(RG_POWER_BRACELET)/* && logic->CanClimbHigh()*/;}, []{return logic->OuterWestHandMQLogic();}, []{return logic->OuterWestHandMQLogic();}}},
{RR_SPIRIT_TEMPLE_MQ_BIG_BLOCKS_DOOR, {7, 0, 0, 0, []{return logic->CanHitSwitch() && /* logic->CanClimbHigh() &&*/
areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCKS_DOOR].AnyAgeTime([]{return logic->MQSpiritStatueSouthDoor();});}, []{return true;}, []{return areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCKS_DOOR].AnyAgeTime([]{return logic->MQSpiritStatueSouthDoor();});}}},
};
@@ -288,7 +288,7 @@ void RegionTable_Init_BottomOfTheWell() {
(logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT))/*&& CanClimb()*/);}),
Entrance(RR_BOTW_MQ_CORNER_CRAWLSPACE, []{return logic->CanUse(RG_CRAWL);}),
Entrance(RR_BOTW_MQ_NEAR_BOSS_LOWER, []{return logic->CanUse(RG_CRAWL) && logic->Get(LOGIC_BOTW_LOWERED_WATER);}),
Entrance(RR_BOTW_MQ_B3, []{return true;}),
Entrance(RR_BOTW_MQ_B3, []{return true;}),
});
areaTable[RR_BOTW_MQ_MIDDLE] = Region("Bottom of the Well MQ Middle", SCENE_BOTTOM_OF_THE_WELL, {}, {
@@ -303,8 +303,8 @@ void RegionTable_Init_BottomOfTheWell() {
Entrance(RR_BOTW_MQ_PERIMETER, []{return logic->Get(LOGIC_BOTW_MQ_OPENED_GATES);}),
Entrance(RR_BOTW_MQ_PIT_CAGE, []{return (bool)ctx->GetTrickOption(RT_BOTW_PITS);}),
Entrance(RR_BOTW_MQ_B3_PLATFORM, []{return logic->Get(LOGIC_BOTW_MQ_OPENED_MIDDLE_HOLE);}),
Entrance(RR_BOTW_MQ_B3, []{return true;}),
Entrance(RR_BOTW_MQ_INVISIBLE_PATH, []{return true/*str0 or CanHitSwitch(ED_BOMB_THROW)*/;}),
Entrance(RR_BOTW_MQ_B3, []{return true;}),
Entrance(RR_BOTW_MQ_INVISIBLE_PATH, []{return AnyAgeTime([]{return logic->HasItem(RG_POWER_BRACELET) || logic->CanHitSwitch(ED_BOMB_THROW);});}),
Entrance(RR_BOTW_MQ_GRAVE_ROOM, []{return logic->Get(LOGIC_BOTW_MQ_OPENED_WEST_ROOM);}),
});
@@ -317,8 +317,8 @@ void RegionTable_Init_BottomOfTheWell() {
LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_3, logic->CanBreakPots()),
}, {
//Exits
Entrance(RR_BOTW_MQ_MIDDLE, []{return true;}),
Entrance(RR_BOTW_MQ_B3, []{return true;}),
Entrance(RR_BOTW_MQ_MIDDLE, []{return true;}),
Entrance(RR_BOTW_MQ_B3, []{return true;}),
});
areaTable[RR_BOTW_MQ_GRAVE_ROOM] = Region("Bottom of the Well Grave Room", SCENE_BOTTOM_OF_THE_WELL, {}, {
@@ -330,7 +330,12 @@ void RegionTable_Init_BottomOfTheWell() {
//Also you get cheap shotted on entry sometimes.
//An MQ lens trick is recommended here, and a review of this room for OHKO logic when that is added is advised.
//In the meantime I assume damage taken or the easy answer (nuts)
LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, (logic->TakeDamage() || logic->CanUse(RG_NUTS)) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)),
//Without power bracelet, the skull can be killed through the Grave with any valid weapon.
//Bow, Sling and Hammer should aim for the left side (from the door's perspective) ot eh grave, hookshot should get close to the grave and aim inside it (no extension needed).
LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, (logic->TakeDamage() || logic->CanUse(RG_NUTS)) &&
(logic->HasItem(RG_POWER_BRACELET) || ctx->GetTrickOption(RT_VISIBLE_COLLISION)) &&
logic->CanKillEnemy(RE_GOLD_SKULLTULA)),
}, {
//Exits
Entrance(RR_BOTW_MQ_MIDDLE, []{return true;}),
@@ -78,8 +78,10 @@ void RegionTable_Init_DekuTree() {
areaTable[RR_DEKU_TREE_BASEMENT_LOWER] = Region("Deku Tree Basement Lower", SCENE_DEKU_TREE, {
//Events
EventAccess(LOGIC_STICK_ACCESS, []{return logic->CanGetDekuBabaSticks();}),
EventAccess(LOGIC_NUT_ACCESS, []{return logic->CanGetDekuBabaNuts();}),
EventAccess(LOGIC_STICK_ACCESS, []{return logic->CanGetDekuBabaSticks();}),
EventAccess(LOGIC_NUT_ACCESS, []{return logic->CanGetDekuBabaNuts();}),
EventAccess(LOGIC_DEKU_TREE_B1_BROKE_WEB, []{return (logic->CanUse(RG_STICKS) && (logic->Get(LOGIC_DEKU_TREE_PUSHED_BASEMENT_BLOCK) || logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS))) ||
(ctx->GetTrickOption(RT_DEKU_B1_BOW_WEBS) && logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}),
}, {
//Locations
LOCATION(RC_DEKU_TREE_BASEMENT_CHEST, logic->HasItem(RG_OPEN_CHEST)),
@@ -164,12 +166,15 @@ void RegionTable_Init_DekuTree() {
//Events
EventAccess(LOGIC_STICK_ACCESS, []{return logic->CanGetDekuBabaSticks();}),
EventAccess(LOGIC_NUT_ACCESS, []{return logic->CanGetDekuBabaNuts();}),
EventAccess(LOGIC_DEKU_TREE_PUSHED_BASEMENT_BLOCK, []{return true;}),
EventAccess(LOGIC_DEKU_TREE_PUSHED_BASEMENT_BLOCK, []{return logic->HasItem(RG_POWER_BRACELET);}),
EventAccess(LOGIC_DEKU_TREE_B1_BROKE_WEB, []{return logic->HasFireSource();}),
}, {}, {
//Exits
Entrance(RR_DEKU_TREE_BASEMENT_LOWER, []{return true;}),
Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->CanUse(RG_CRAWL);}),
Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return AnyAgeTime([]{return logic->HasFireSourceWithTorch() || (ctx->GetTrickOption(RT_DEKU_B1_BOW_WEBS) && logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}),
//It's possible to light a stick on the upper torch with a backflip into a jumpslash, but a trick as it seems to involve landing on the torch platform
//Adult can simply backflip against a nearby wall to the same effect, which is much simpler but still unintuitive enough top be a trick
Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return logic->Get(LOGIC_DEKU_TREE_B1_BROKE_WEB) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}),
});
areaTable[RR_DEKU_TREE_OUTSIDE_BOSS_ROOM] = Region("Deku Tree Outside Boss Room", SCENE_DEKU_TREE, {}, {
@@ -306,8 +311,9 @@ void RegionTable_Init_DekuTree() {
areaTable[RR_DEKU_TREE_MQ_BASEMENT] = Region("Deku Tree MQ Basement", SCENE_DEKU_TREE, {
//Events
EventAccess(LOGIC_STICK_ACCESS, []{return logic->CanGetDekuBabaSticks();}),
EventAccess(LOGIC_NUT_ACCESS, []{return logic->CanGetDekuBabaNuts();}),
EventAccess(LOGIC_STICK_ACCESS, []{return logic->CanGetDekuBabaSticks();}),
EventAccess(LOGIC_NUT_ACCESS, []{return logic->CanGetDekuBabaNuts();}),
EventAccess(LOGIC_DEKU_TREE_B1_BROKE_WEB, []{return logic->CanUse(RG_STICKS) && (logic->Get(LOGIC_DEKU_TREE_PUSHED_BASEMENT_BLOCK) || logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS));}),
}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_BASEMENT_CHEST, (logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)) && logic->HasItem(RG_OPEN_CHEST)),
@@ -416,7 +422,9 @@ void RegionTable_Init_DekuTree() {
areaTable[RR_DEKU_TREE_MQ_BASEMENT_LEDGE] = Region("Deku Tree MQ Basement Ledge", SCENE_DEKU_TREE, {
//Events
EventAccess(LOGIC_DEKU_TREE_PUSHED_BASEMENT_BLOCK, []{return true;}),
EventAccess(LOGIC_DEKU_TREE_PUSHED_BASEMENT_BLOCK, []{return logic->HasItem(RG_POWER_BRACELET);}),
//You can also recoil from RR_DEKU_TREE_MQ_1F with a lit stick to burn the web, but such recoils would be tricks
EventAccess(LOGIC_DEKU_TREE_B1_BROKE_WEB, []{return logic->HasFireSource();}),
}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_DEKU_SCRUB, logic->CanStunDeku() && GetCheckPrice() <= GetWalletCapacity()),
@@ -427,9 +435,8 @@ void RegionTable_Init_DekuTree() {
//Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->CanUse(RG_CRAWL);}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT, []{return true;}),
//If strength 0 is shuffled, add hovers or block push to the stick check
//recoiling to skip swim is possible, but would be a trick
Entrance(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, []{return AnyAgeTime([]{return logic->HasFireSource() || (/*logic->Get(LOGIC_DEKU_TREE_PUSHED_BASEMENT_BLOCK) && */logic->CanUse(RG_STICKS));}) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}),
Entrance(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, []{return logic->Get(LOGIC_DEKU_TREE_B1_BROKE_WEB) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}),
});
areaTable[RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM] = Region("Deku Tree MQ Outside Boss Room", SCENE_DEKU_TREE, {}, {
@@ -55,7 +55,7 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_SE_CORRIDOR] = Region("Dodongos Cavern SE Corridor", SCENE_DODONGOS_CAVERN, {}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_GS_SCARECROW, logic->ReachScarecrow() || (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_DC_SCARECROW_GS) && logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_DODONGOS_CAVERN_GS_SCARECROW, logic->ReachScarecrow() || (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_DC_SCARECROW_GS) && logic->HasItem(RG_POWER_BRACELET) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA))),
LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_1, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_2, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_3, logic->CanBreakPots()),
@@ -66,8 +66,8 @@ void RegionTable_Init_DodongosCavern() {
//Exits
Entrance(RR_DODONGOS_CAVERN_LOBBY, []{return true;}),
//Shield seems to be in logic to drop a pot on their head as they hit you to blow up the wall
Entrance(RR_DODONGOS_CAVERN_SE_ROOM, []{return AnyAgeTime([]{return logic->CanBreakMudWalls() || logic->CanAttack() || (logic->TakeDamage() && logic->CanShield());});}),
Entrance(RR_DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_SE_ROOM, []{return AnyAgeTime([]{return logic->CanBreakMudWalls() || logic->CanAttack() || (logic->TakeDamage() && logic->CanShield() && logic->HasItem(RG_POWER_BRACELET));});}),
Entrance(RR_DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, []{return logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_DODONGOS_CAVERN_SE_ROOM] = Region("Dodongos Cavern SE Room", SCENE_DODONGOS_CAVERN, {}, {
@@ -134,7 +134,7 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_STAIRS_UPPER] = Region("Dodongos Cavern Stairs Upper", SCENE_DODONGOS_CAVERN, {}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, logic->Get(LOGIC_DC_LIFT_PLATFORM) ? ED_BOOMERANG : ED_LONGSHOT)),
LOCATION(RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, logic->IsAdult || logic->CanAttack()),
LOCATION(RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA, logic->IsAdult ? ED_LONG_JUMPSLASH : ED_BOMB_THROW)),
LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_1, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_2, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_3, logic->CanBreakPots()),
@@ -156,13 +156,13 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_ARMOS_ROOM] = Region("Dodongos Cavern Armos Room", SCENE_DODONGOS_CAVERN, {}, {}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_STAIRS_UPPER, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return logic->IsAdult || (logic->HasItem(RG_POWER_BRACELET) || ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS));}),
});
areaTable[RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER] = Region("Dodongos Cavern Bomb Room Lower", SCENE_DODONGOS_CAVERN, {}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_DODONGOS_CAVERN_BLADE_ROOM_HEART, true),
LOCATION(RC_DODONGOS_CAVERN_BLADE_ROOM_HEART, logic->HasItem(RG_POWER_BRACELET)),
LOCATION(RC_DODONGOS_CAVERN_FIRST_BRIDGE_GRASS, logic->CanCutShrubs()),
LOCATION(RC_DODONGOS_CAVERN_BLADE_GRASS, logic->CanCutShrubs()),
}, {
@@ -258,7 +258,7 @@ void RegionTable_Init_DodongosCavern() {
//Exits
Entrance(RR_DODONGOS_CAVERN_LOBBY, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_BACK_ROOM, []{return AnyAgeTime([]{return logic->CanBreakMudWalls();});}),
Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, []{return logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_DODONGOS_CAVERN_BACK_ROOM] = Region("Dodongos Cavern Back Room", SCENE_DODONGOS_CAVERN, {}, {
@@ -412,21 +412,21 @@ void RegionTable_Init_DodongosCavern() {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->TakeDamage();}),
Entrance(RR_DODONGOS_CAVERN_MQ_DODONGO_ROOM, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_MQ_LARVAE_ROOM, []{return logic->HasFireSourceWithTorch();}),//torch checks here need strength 0 with sticks when that is implemented
Entrance(RR_DODONGOS_CAVERN_MQ_LARVAE_ROOM, []{return logic->HasFireSource() || (logic->CanUse(RG_STICKS) && logic->HasItem(RG_POWER_BRACELET));}),
Entrance(RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM, []{return AnyAgeTime([]{return logic->HasFireSourceWithTorch();});}), //Includes an implied CanPass(RE_BIG_SKULLTULA)
//Bunny hood jump can make it as child
Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, []{return (logic->IsAdult && (true /* str0 */ || ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) || logic->CanGroundJump())) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}),
Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, []{return (logic->IsAdult && (logic->HasItem(RG_POWER_BRACELET) || ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) || logic->CanGroundJump())) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}),
Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return logic->CanUse(RG_STICKS) && logic->HasItem(RG_GORONS_BRACELET);}), //Implies access to RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM from here
});
areaTable[RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM] = Region("Dodongos Cavern MQ Torch Puzzle Lower", SCENE_DODONGOS_CAVERN, {}, {
areaTable[RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM] = Region("Dodongos Cavern MQ Big Block Room", SCENE_DODONGOS_CAVERN, {}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_MQ_BIG_BLOCK_POT_1, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_BIG_BLOCK_POT_2, logic->CanBreakPots()),
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}),
Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return (logic->HasFireSource() && logic->HasItem(RG_GORONS_BRACELET)) || logic->CanBreakMudWalls();}), //Requires str0, If you can somehow warp into this room, add logic->CanPassEnemy(RE_BIG_SKULLTULA)
Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return (logic->IsAdult || logic->HasItem(RG_POWER_BRACELET) || logic->CanUse(RG_HOVER_BOOTS)) && ((logic->HasFireSource() && logic->HasItem(RG_GORONS_BRACELET)) || logic->CanBreakMudWalls());}), // If you can somehow warp into this room, add logic->CanPassEnemy(RE_BIG_SKULLTULA)
});
areaTable[RR_DODONGOS_CAVERN_MQ_LARVAE_ROOM] = Region("Dodongos Cavern MQ Larvae Room", SCENE_DODONGOS_CAVERN, {}, {
@@ -468,6 +468,7 @@ void RegionTable_Init_DodongosCavern() {
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return true;}),
//crate platforming skips the puzzle
Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, []{return logic->IsAdult || (AnyAgeTime([]{return logic->BlastOrSmash() || (logic->CanAttack() && logic->HasItem(RG_GORONS_BRACELET));}));}),
});
@@ -490,10 +491,10 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE] = Region("Dodongos Cavern MQ Lower Right Side", SCENE_DODONGOS_CAVERN, {}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_1, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_2, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_3, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_4, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_1, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_2, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_3, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_4, logic->CanBreakPots()),
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return true;}),
@@ -520,18 +521,18 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_MQ_POES_ROOM] = Region("Dodongos Cavern MQ Poes Room", SCENE_DODONGOS_CAVERN, {}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_1, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_2, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_3, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_4, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_1, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_2, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_3, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_4, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_5, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_6, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_7, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_8, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_1, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_2, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_3, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_4, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_1, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_2, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_3, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_4, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_5, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_6, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_7, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_8, logic->HasItem(RG_GORONS_BRACELET) || logic->CanBreakCrates()),
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_OUTSIDE_POES_ROOM, []{return AnyAgeTime([]{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);});}),
@@ -552,7 +553,13 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH] = Region("Dodongos Cavern MQ Behind Mouth", SCENE_DODONGOS_CAVERN, {}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) /* || bunny jumps*/)),
//This can be gotten with only str0 as adult by using 1 pot to kill the skull from the top of a nearby grave,
//then another to hit the switch to turn of the fire then running up the ledge to grab it. This assumes RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE access
//Alternatively, the grave can be pulled and roll jumped off of.
//This may be trickworthy, but it can only come up with doorsanity or decoupled boss door rando, making it too niche to be it's own trick
LOCATION(RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) ||
(logic->IsAdult && logic->HasItem(RG_POWER_BRACELET) &&
(logic->CanPassEnemy(RE_ARMOS) || logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS)/* && Roll*/)/* || bunny jumps*/))),
LOCATION(RC_DODONGOS_CAVERN_MQ_BEFORE_BOSS_SW_POT, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_BEFORE_BOSS_NE_POT, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_ROOM_SE_POT, logic->CanBreakPots()),
@@ -560,9 +567,8 @@ void RegionTable_Init_DodongosCavern() {
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return true;}),
//using pots to get past the fire is in default logic. if str0 gets added, this will need to be:
//str0 || explosives, or projectiles if str0 isn't needed to pull graves (it's a narrow shot though, may be trick worthy)
Entrance(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, []{return logic->HasItem(RG_POWER_BRACELET) || logic->HasExplosives() ||
(logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS)/* && Roll*/)/* || bunny jumps*/));}),
Entrance(RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE, []{return logic->IsAdult;}),
});
@@ -571,28 +577,28 @@ void RegionTable_Init_DodongosCavern() {
EventAccess(LOGIC_DC_MQ_BEHIND_FIRE_SWITCH, []{return logic->CanDetonateBombFlowers();}),
}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)),
LOCATION(RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)),
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, []{return logic->CanAttack();}),
Entrance(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, []{return logic->CanHitSwitch();}),
Entrance(RR_DODONGOS_CAVERN_MQ_BACK_POE_ROOM, []{return true;}),
//There's a trick N64 rolls into the child eyes trick for using armos blow up the bomb flowers when dieing, which would be killing an armos
//RANDOTODO investigate using hovers to go from the door ledge to the block directly
Entrance(RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE, []{return logic->Get(LOGIC_DC_MQ_BEHIND_FIRE_SWITCH);}),
Entrance(RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE, []{return (logic->CanPassEnemy(RE_ARMOS) && (logic->IsAdult || logic->Get(LOGIC_DC_MQ_BEHIND_FIRE_SWITCH))) || logic->CanUse(RG_HOVER_BOOTS);}),
});
areaTable[RR_DODONGOS_CAVERN_MQ_BACK_POE_ROOM] = Region("Dodongos Cavern MQ Back Poe Room", SCENE_DODONGOS_CAVERN, {}, {
LOCATION(RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, logic->HasItem(RG_OPEN_CHEST)), //pulling the grave isn't required, as you can open the chest through it
//the chest is in a grave, but you can open it through it
LOCATION(RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, (ctx->GetTrickOption(RT_VISIBLE_COLLISION) || logic->HasItem(RG_POWER_BRACELET)) && logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_DODONGOS_CAVERN_MQ_BACKROOM_POT_1, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_BACKROOM_POT_2, logic->CanBreakPots()),
LOCATION(RC_DODONGOS_CAVERN_MQ_BACK_POE_GRASS, logic->CanCutShrubs()),
}, {
Entrance(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, []{return logic->CanKillEnemy(RE_POE);}),
Entrance(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, []{return AnyAgeTime([]{return logic->CanKillEnemy(RE_POE);});}),
});
areaTable[RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE] = Region("Dodongos Cavern MQ Back Switch Grave", SCENE_DODONGOS_CAVERN, {
//Events
EventAccess(LOGIC_DC_MQ_BEHIND_FIRE_SWITCH, []{return true/*str0 || logic->CanHitSwitch() || logic->CanDetonateBombFlowers()*/;}),
EventAccess(LOGIC_DC_MQ_BEHIND_FIRE_SWITCH, []{return logic->HasItem(RG_POWER_BRACELET) || logic->CanHitSwitch() || logic->CanDetonateBombFlowers();}),
EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CanBreakPots();}),
}, {
//Locations
@@ -602,8 +608,9 @@ void RegionTable_Init_DodongosCavern() {
LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_GRASS, logic->CanCutShrubs()),
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, []{return true;}), //if strength 0 prevents grave pulls, add it here
Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, []{return logic->HasItem(RG_POWER_BRACELET);}),
});
#pragma endregion
@@ -155,7 +155,7 @@ void RegionTable_Init_FireTemple() {
}, {
//Exits
Entrance(RR_FIRE_TEMPLE_LAVA_GEYSER_1F, []{return logic->TakeDamage();}),
Entrance(RR_FIRE_TEMPLE_LAVA_GEYSER_2F, []{return logic->SmallKeys(SCENE_FIRE_TEMPLE, 4) && logic->FireTimer() >= 48/* && str0*/;}),
Entrance(RR_FIRE_TEMPLE_LAVA_GEYSER_2F, []{return logic->FireTimer() >= 48 && logic->HasItem(RG_POWER_BRACELET);}),
});
//you can get the hearts with an indirect boomerang from here, but it's a trick
@@ -423,7 +423,7 @@ void RegionTable_Init_FireTemple() {
//Exits
Entrance(RR_FIRE_TEMPLE_TOP_OF_COLLAPSING_STAIRS, []{return logic->Get(LOGIC_FIRE_HIT_STAIRS) && logic->IsAdult;}),
// this is here to maintain 1:1 door entrances between regions
Entrance(RR_FIRE_TEMPLE_ABOVE_FIRE_MAZE, []{return logic->Get(LOGIC_FIRE_HIT_STAIRS) && (logic->IsAdult || logic->Get(LOGIC_FIRE_CHILD_AT_TOP_OF_STAIRS))/* && str0*/;}),
Entrance(RR_FIRE_TEMPLE_ABOVE_FIRE_MAZE, []{return logic->Get(LOGIC_FIRE_HIT_STAIRS) && (logic->IsAdult || logic->Get(LOGIC_FIRE_CHILD_AT_TOP_OF_STAIRS)) && logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_FIRE_TEMPLE_ABOVE_FIRE_MAZE] = Region("Fire Temple Above Fire Maze", SCENE_FIRE_TEMPLE, {
@@ -760,7 +760,7 @@ void RegionTable_Init_FireTemple() {
//Exits
Entrance(RR_FIRE_TEMPLE_MQ_UPPER_LIZALFOS_MAZE, []{return true;}),
//Assumes maze access
Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SWITCH_DOOR, []{return logic->HasExplosives()/* && str0*/;}),
Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SWITCH_DOOR, []{return logic->HasExplosives() && logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_FIRE_TEMPLE_MQ_ABOVE_MAZE] = Region("Fire Temple MQ Above Maze", SCENE_FIRE_TEMPLE, {}, {}, {
@@ -807,7 +807,8 @@ void RegionTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_MQ_BURNING_BLOCK] = Region("Fire Temple MQ Burning Block", SCENE_FIRE_TEMPLE, {}, {
//Locations
//There's definitely ways to do this hammerless, but with one points on it's a trick
LOCATION(RC_FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_HOOKSHOT)/* && (str0 || ctx->GetTrickOption(RT_HOOKSHOT_EXTENSION))*/),
//you can just hook through the block while next to it to kill the skull and get the token
LOCATION(RC_FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_HOOKSHOT) && (logic->HasItem(RG_POWER_BRACELET) || ctx->GetTrickOption(RT_VISIBLE_COLLISION))),
}, {
//Exits
Entrance(RR_FIRE_TEMPLE_MQ_TORCH_SLUG_CLIMB, []{return true;}),
@@ -863,7 +864,7 @@ void RegionTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM_ABOVE_CAGE] = Region("Fire Temple MQ High Torch Room Above Cage", SCENE_FIRE_TEMPLE, {
//Events
EventAccess(LOGIC_FIRE_MQ_HIGH_TORCH_LIT, []{return ((logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_HOOKSHOT)/*&& str0*/) && logic->FireTimer() >= 48);}),
EventAccess(LOGIC_FIRE_MQ_HIGH_TORCH_LIT, []{return ((logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_HOOKSHOT) && logic->HasItem(RG_POWER_BRACELET)) && logic->FireTimer() >= 48);}),
}, {
//Locations
//Tunic logic for these checks is handled on entry
@@ -357,7 +357,7 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_GREEN_POE_ROOM] = Region("Forest Temple Green Poe Room", SCENE_FOREST_TEMPLE, {
//Events
EventAccess(LOGIC_FOREST_AMY, []{return logic->CanUse(RG_FAIRY_BOW);}),
EventAccess(LOGIC_FOREST_AMY, []{return logic->CanUse(RG_FAIRY_BOW) && logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_GREEN_POE_POT_1, logic->CanBreakPots()),
@@ -382,11 +382,11 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_BASEMENT] = Region("Forest Temple Basement", SCENE_FOREST_TEMPLE, {
//Events
EventAccess(LOGIC_FOREST_OPEN_BOSS_HALLWAY, []{return true;}),
EventAccess(LOGIC_FOREST_OPEN_BOSS_HALLWAY, []{return logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_BASEMENT_CHEST, logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_FOREST_TEMPLE_GS_BASEMENT, logic->HookshotOrBoomerang()),
LOCATION(RC_FOREST_TEMPLE_BASEMENT_CHEST, logic->HasItem(RG_POWER_BRACELET) && logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_FOREST_TEMPLE_GS_BASEMENT, logic->HasItem(RG_POWER_BRACELET) && logic->HookshotOrBoomerang()),
}, {
//Exits
Entrance(RR_FOREST_TEMPLE_LOBBY, []{return true;}),
@@ -709,7 +709,7 @@ void RegionTable_Init_ForestTemple() {
LOCATION(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3, logic->CanBreakSmallCrates()),
}, {
//Exits
Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE);}),
Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, []{return logic->CanUse(logic->HasItem(RG_POWER_BRACELET) ? RG_FAIRY_BOW : RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE);}),
Entrance(RR_FOREST_TEMPLE_MQ_BETH_ROOM, []{return logic->SmallKeys(SCENE_FOREST_TEMPLE, 6);}),
});
@@ -724,7 +724,7 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_MQ_AMY_ROOM] = Region("Forest Temple MQ Amy Room", SCENE_FOREST_TEMPLE, {
//Events
EventAccess(LOGIC_FOREST_AMY, []{return logic->CanUse(RG_FAIRY_BOW);}),
EventAccess(LOGIC_FOREST_AMY, []{return logic->CanUse(RG_FAIRY_BOW) && logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_MQ_GREEN_POE_POT_1, logic->CanBreakPots()),
@@ -744,14 +744,14 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_MQ_BASEMENT] = Region("Forest Temple MQ Basement", SCENE_FOREST_TEMPLE, {
//Events
//Implies CanHitSwitch()
EventAccess(LOGIC_FOREST_OPEN_BOSS_HALLWAY, []{return logic->CanHitEyeTargets();}),
EventAccess(LOGIC_FOREST_OPEN_BOSS_HALLWAY, []{return logic->HasItem(RG_POWER_BRACELET) && logic->CanHitEyeTargets();}),
}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST, logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST, logic->HasItem(RG_POWER_BRACELET) && logic->HasItem(RG_OPEN_CHEST)),
}, {
//Exits
Entrance(RR_FOREST_TEMPLE_MQ_LOBBY, []{return true;}),
Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT_POT_ROOM, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->TakeDamage();}),
Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT_POT_ROOM, []{return logic->HasItem(RG_POWER_BRACELET) && (logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->TakeDamage());}),
Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, []{return logic->Get(LOGIC_FOREST_OPEN_BOSS_HALLWAY);}),
});
@@ -148,14 +148,16 @@ void RegionTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_WATER_TRIAL_BLOCK_ROOM] = Region("Ganon's Castle Water Trial Block Room", SCENE_INSIDE_GANONS_CASTLE, {
//Events
EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CanBreakPots();}),
EventAccess(LOGIC_WATER_TRIAL_RUSTED_SWITCH, []{return (logic->BlueFire() || ctx->GetTrickOption(RT_RUSTED_SWITCHES)) && logic->CanUse(RG_MEGATON_HAMMER);}),
EventAccess(LOGIC_WATER_TRIAL_RUSTED_SWITCH, []{return logic->IsAdult && (logic->HasItem(RG_POWER_BRACELET) || (logic->CanMiddairGroundJump())) &&
(logic->BlueFire() || ctx->GetTrickOption(RT_RUSTED_SWITCHES)) &&
logic->CanUse(RG_MEGATON_HAMMER);}),
}, {
//Locations
LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_POT_3, logic->CanBreakPots()),
}, {
//Exits
Entrance(RR_GANONS_CASTLE_WATER_TRIAL_BLUE_FIRE_ROOM, []{return true;}),
Entrance(RR_GANONS_CASTLE_WATER_TRIAL_BLOCK_ROOM_END, []{return logic->IsAdult || logic->CanGroundJump();}),
Entrance(RR_GANONS_CASTLE_WATER_TRIAL_BLOCK_ROOM_END, []{return logic->IsAdult || (logic->HasItem(RG_POWER_BRACELET) && logic->CanUse(RG_HOVER_BOOTS)) || logic->CanGroundJump() || ctx->GetTrickOption(RT_SLIDE_JUMP);}),
});
areaTable[RR_GANONS_CASTLE_WATER_TRIAL_BLOCK_ROOM_END] = Region("Ganon's Castle Water Trial Block Room End", SCENE_INSIDE_GANONS_CASTLE, {}, {}, {
@@ -311,8 +313,10 @@ void RegionTable_Init_GanonsCastle() {
});
areaTable[RR_GANONS_CASTLE_LIGHT_TRIAL_BOULDER_ROOM] = Region("Ganon's Castle Light Trial Boulder Room", SCENE_INSIDE_GANONS_CASTLE, {}, {
//Locations
LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_BOULDER_POT_1, logic->CanBreakPots()),
}, {
//Exits
Entrance(RR_GANONS_CASTLE_LIGHT_TRIAL_TRIFORCE_ROOM, []{return logic->SmallKeys(SCENE_INSIDE_GANONS_CASTLE, 2);}),
Entrance(RR_GANONS_CASTLE_LIGHT_TRIAL_FINAL_ROOM, []{return logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanGroundJump());}),
});
@@ -472,12 +476,12 @@ void RegionTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM] = Region("Ganon's Castle MQ Water Trial Block Room", SCENE_INSIDE_GANONS_CASTLE, {
//Events
EventAccess(LOGIC_WATER_TRIAL_MQ_SILVER_RUPEES, []{return logic->IsAdult && logic->BlueFire();}),
EventAccess(LOGIC_WATER_TRIAL_MQ_MELTED_FINAL_DOOR_RED_ICE, []{return logic->IsAdult && logic->BlueFire();}),
EventAccess(LOGIC_WATER_TRIAL_MQ_SILVER_RUPEES, []{return logic->IsAdult && (logic->HasItem(RG_POWER_BRACELET) || logic->CanMiddairGroundJump()) && logic->BlueFire();}),
EventAccess(LOGIC_WATER_TRIAL_MQ_MELTED_FINAL_DOOR_RED_ICE, []{return (ctx->GetOption(RSK_BLUE_FIRE_ARROWS) && logic->CanUse(RG_ICE_ARROWS)) || (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS)) && logic->HasItem(RG_POWER_BRACELET) && logic->CanUse(RG_BOTTLE_WITH_BLUE_FIRE);}),
}, {}, {
//Exits
Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_GEYSER_ROOM, []{return logic->SmallKeys(SCENE_INSIDE_GANONS_CASTLE, 3);}),
Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM_END, []{return logic->Get(LOGIC_WATER_TRIAL_MQ_MELTED_FINAL_DOOR_RED_ICE) && (logic->IsAdult || logic->CanGroundJump());}),
Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM_END, []{return logic->Get(LOGIC_WATER_TRIAL_MQ_MELTED_FINAL_DOOR_RED_ICE) && (logic->IsAdult || (logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_POWER_BRACELET)) || logic->CanGroundJump() || ctx->GetTrickOption(RT_SLIDE_JUMP));}),
});
areaTable[RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM_END] = Region("Ganon's Castle MQ Water Trial Block Room End", SCENE_INSIDE_GANONS_CASTLE, {
@@ -496,7 +500,7 @@ void RegionTable_Init_GanonsCastle() {
LOCATION(RC_GANONS_CASTLE_MQ_WATER_TRIAL_POT_2, logic->CanBreakPots()),
}, {
//Exits
Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM_END, []{return AnyAgeTime([]{return logic->BlueFire();});}),
Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM_END, []{return true;}),
});
areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE] = Region("Ganon's Castle MQ Shadow Trial Starting Ledge", SCENE_INSIDE_GANONS_CASTLE, {
@@ -74,28 +74,40 @@ void RegionTable_Init_IceCavern() {
Entrance(RR_ICE_CAVERN_HUB, []{return true;}),
});
// heavily relies on str0
areaTable[RR_ICE_CAVERN_BLOCK_ROOM] = Region("Ice Cavern Block Room", SCENE_ICE_CAVERN, {
areaTable[RR_ICE_CAVERN_BLOCK_ROOM] = Region("Ice Cavern Block Room", SCENE_ICE_CAVERN, {}, {
//Locations
// trick involves backflip, could be merged into general trick
LOCATION(RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM, logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_ICE_BLOCK_GS) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_SHORT_JUMPSLASH))),
LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_1, logic->CanUse(RG_BOOMERANG)),
LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_2, logic->CanUse(RG_BOOMERANG)),
LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_3, logic->CanUse(RG_BOOMERANG)),
}, {
//Exits
Entrance(RR_ICE_CAVERN_HUB, []{return logic->CanClearStalagmite() || ctx->GetTrickOption(RT_ICE_STALAGMITE_CLIP);}),
Entrance(RR_ICE_CAVERN_BLOCK_ROOM_BLUE_FIRE, []{return logic->HasItem(RG_POWER_BRACELET) || (logic->IsAdult && (logic->CanGroundJump() || ctx->GetTrickOption(RT_SLIDE_JUMP)));}),
Entrance(RR_ICE_CAVERN_BEFORE_FINAL_ROOM, []{return (logic->HasItem(RG_POWER_BRACELET) || (logic->IsAdult && (logic->CanGroundJump() || ctx->GetTrickOption(RT_SLIDE_JUMP)))) && AnyAgeTime([]{return logic->BlueFire();});}),
});
areaTable[RR_ICE_CAVERN_BLOCK_ROOM_BLUE_FIRE] = Region("Ice Cavern Block Room Blue Fire", SCENE_ICE_CAVERN, {
//Events
EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return true;}),
}, {
//Locations
// trick involves backflip, could be merged into general trick
LOCATION(RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM, logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_ICE_BLOCK_GS) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_SHORT_JUMPSLASH))),
LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_1, logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG)),
LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_2, logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG)),
LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_3, logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG)),
LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_1, logic->CanUse(RG_SONG_OF_TIME)),
LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_2, logic->CanUse(RG_SONG_OF_TIME)),
LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_3, logic->CanUse(RG_SONG_OF_TIME)),
}, {
//Exits
Entrance(RR_ICE_CAVERN_HUB, []{return logic->CanClearStalagmite() || ctx->GetTrickOption(RT_ICE_STALAGMITE_CLIP);}),
Entrance(RR_ICE_CAVERN_BEFORE_FINAL_ROOM, []{return AnyAgeTime([]{return logic->BlueFire();});}),
Entrance(RR_ICE_CAVERN_BLOCK_ROOM, []{return true;}),
});
// this represents being past the red ice barricade, not just past the silver rupee door
areaTable[RR_ICE_CAVERN_BEFORE_FINAL_ROOM] = Region("Ice Cavern Before Final Room", SCENE_ICE_CAVERN, {}, {
//Locations
LOCATION(RC_ICE_CAVERN_NEAR_END_POT_1, logic->CanBreakPots() && logic->BlueFire()),
LOCATION(RC_ICE_CAVERN_NEAR_END_POT_2, logic->CanBreakPots() && logic->BlueFire()),
//Assumes RR_ICE_CAVERN_BLOCK_ROOM access
LOCATION(RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM, ctx->GetTrickOption(RT_ICE_BLOCK_GS) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && logic->BlueFire() && logic->HasItem(RG_POWER_BRACELET)),
LOCATION(RC_ICE_CAVERN_NEAR_END_POT_1, logic->CanBreakPots() && logic->BlueFire()),
LOCATION(RC_ICE_CAVERN_NEAR_END_POT_2, logic->CanBreakPots() && logic->BlueFire()),
}, {
//Exits
Entrance(RR_ICE_CAVERN_BLOCK_ROOM, []{return AnyAgeTime([]{return logic->BlueFire();});}),
@@ -134,7 +146,7 @@ void RegionTable_Init_IceCavern() {
//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;}),
Entrance(RR_ICE_CAVERN_MQ_HUB, []{return logic->HasItem(RG_POWER_BRACELET) || logic->CanHitSwitch(ED_BOMB_THROW) || (logic->IsAdult && logic->CanUse(RG_BIGGORON_SWORD));}),
Entrance(RR_ICE_CAVERN_MQ_ABOVE_BEGINNING, []{return false;}),
});
@@ -151,9 +163,6 @@ void RegionTable_Init_IceCavern() {
LOCATION(RC_ICE_CAVERN_MQ_EARLY_WOLFOS_POT_4, logic->CanBreakPots()),
}, {
//Exits
//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
//if you clear the ice, you can hit it with a pot from here.
Entrance(RR_ICE_CAVERN_MQ_BEGINNING, []{return logic->BlueFire();}),
Entrance(RR_ICE_CAVERN_MQ_MAP_ROOM, []{return AnyAgeTime([]{return logic->CanKillEnemy(RE_WHITE_WOLFOS) && logic->CanKillEnemy(RE_FREEZARD);});}),
Entrance(RR_ICE_CAVERN_MQ_COMPASS_ROOM, []{return (logic->IsAdult || (ctx->GetTrickOption(RT_GROUND_JUMP_HARD) && logic->CanGroundJump())) && logic->BlueFire();}),
Entrance(RR_ICE_CAVERN_MQ_SCARECROW_ROOM, []{return logic->BlueFire();}),
@@ -170,15 +179,16 @@ void RegionTable_Init_IceCavern() {
areaTable[RR_ICE_CAVERN_MQ_SCARECROW_ROOM] = Region("Ice Cavern MQ Scarecrow Room", SCENE_ICE_CAVERN, {
//Events
EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return logic->IsAdult && logic->CanGroundJump();}),
EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return logic->CanUse(RG_SONG_OF_TIME) || (logic->IsAdult && (logic->CanGroundJump() || ctx->GetTrickOption(RT_SLIDE_JUMP)));}),
}, {
//Locations
LOCATION(RC_ICE_CAVERN_MQ_GS_ICE_BLOCK, (logic->BlueFire() && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)) || (logic->IsAdult && logic->CanHitSwitch(ED_LONG_JUMPSLASH))),
LOCATION(RC_ICE_CAVERN_MQ_GS_SCARECROW, logic->ReachScarecrow() || (logic->IsAdult && (logic->CanUse(RG_LONGSHOT) || logic->CanGroundJump() || ctx->GetTrickOption(RT_ICE_MQ_SCARECROW)))),
//Implies being able to kill the skull if you hit the switch
LOCATION(RC_ICE_CAVERN_MQ_GS_ICE_BLOCK, (logic->BlueFire() && logic->HasItem(RG_POWER_BRACELET) && logic->CanKillEnemy(RE_GOLD_SKULLTULA)) || logic->CanHitSwitch(logic->IsAdult ? ED_LONG_JUMPSLASH : ED_BOMB_THROW)),
LOCATION(RC_ICE_CAVERN_MQ_GS_SCARECROW, logic->ReachScarecrow() || (logic->IsAdult && (logic->CanUse(RG_LONGSHOT) || logic->CanGroundJump() || ctx->GetTrickOption(RT_SLIDE_JUMP)))),
}, {
//Exits
Entrance(RR_ICE_CAVERN_MQ_HUB, []{return logic->BlueFire();}),
//Assumes RR_ICE_CAVERN_MQ_HUB access for a pot if using blue fire
//The switch defaults into the state where the block exists, and is a temp flag
Entrance(RR_ICE_CAVERN_MQ_WEST_CORRIDOR, []{return logic->IsAdult && logic->BlueFire();}),
});
@@ -32,7 +32,7 @@ void RegionTable_Init_JabuJabusBelly() {
Entrance(RR_JABU_JABUS_BELLY_BEGINNING, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_HOLES_ROOM, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, []{return logic->Get(LOGIC_JABU_LOWERED_PATH) || (ctx->GetTrickOption(RT_JABU_BOSS_HOVER) && logic->CanUse(RG_HOVER_BOOTS));}),
Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, []{return (logic->Get(LOGIC_JABU_LOWERED_PATH) || (ctx->GetTrickOption(RT_JABU_BOSS_HOVER) && logic->CanUse(RG_HOVER_BOOTS))) && logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_JABU_JABUS_BELLY_HOLES_ROOM] = Region("Jabu Jabus Belly Holes Room", SCENE_JABU_JABU, {}, {}, {
@@ -77,10 +77,10 @@ void RegionTable_Init_JabuJabusBelly() {
areaTable[RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_NORTH] = Region("Jabu Jabus Belly Water Switch Room North", SCENE_JABU_JABU, {
//Events
EventAccess(LOGIC_JABU_RUTO_IN_1F, []{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}),
EventAccess(LOGIC_JABU_RUTO_IN_1F, []{return (logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE)) && logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HookshotOrBoomerang()),
LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)),
}, {
//Exits
//there's tricks for getting here with bunny-jumps or just side-hops
@@ -91,12 +91,13 @@ void RegionTable_Init_JabuJabusBelly() {
areaTable[RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH] = Region("Jabu Jabus Belly Water Switch Room South", SCENE_JABU_JABU, {}, {
//Locations
LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HookshotOrBoomerang()),
LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)),
}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_NORTH, []{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}),
Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOVER_BOOTS);}),
Entrance(RR_JABU_JABUS_BELLY_LIFT_ROOM, []{return logic->CanUseProjectile();}),
//Adult can barely reach it with BGS, but it's finnicky enough to be a trick, and too niche to be worth adding yet (only relevant in doorsanity)
Entrance(RR_JABU_JABUS_BELLY_LIFT_ROOM, []{return logic->CanHitSwitch(ED_BOMB_THROW);}),
});
areaTable[RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE] = Region("Jabu Jabus Belly Water Switch Room Ledge", SCENE_JABU_JABU, {
@@ -104,8 +105,10 @@ void RegionTable_Init_JabuJabusBelly() {
EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CanBreakPots();}),
}, {
//Locations
//this is for climbing back and forth to use pots (or ruto) to kill skull... or killing the skull before climbing to grab the token
LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HasItem(RG_BRONZE_SCALE) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW)),
//this is for climbing back and forth to use pots (or ruto) to kill skull...
LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HasItem(RG_POWER_BRACELET) && (logic->HasItem(RG_BRONZE_SCALE) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS))) ||
//or killing the skull before climbing to grab the token
logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW)),
LOCATION(RC_JABU_JABUS_BELLY_BASEMENT_POT_1, logic->CanBreakPots()),
LOCATION(RC_JABU_JABUS_BELLY_BASEMENT_POT_2, logic->CanBreakPots()),
LOCATION(RC_JABU_JABUS_BELLY_BASEMENT_POT_3, logic->CanBreakPots()),
@@ -113,6 +116,8 @@ void RegionTable_Init_JabuJabusBelly() {
//Exits
Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_NORTH, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH, []{return true;}),
//Assumes RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH access
Entrance(RR_JABU_JABUS_BELLY_LIFT_ROOM, []{return logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_JABU_JABUS_BELLY_FORKED_CORRIDOR] = Region("Jabu Jabus Belly Forked Corridor", SCENE_JABU_JABU, {}, {}, {
@@ -225,7 +230,7 @@ void RegionTable_Init_JabuJabusBelly() {
Entrance(RR_JABU_JABUS_BELLY_JIGGLIES_ROOM, []{return true;}),
});
areaTable[RR_JABU_JABUS_BELLY_JIGGLIES_ROOM] = Region("Jabu Jabus Belly Cubes Room", SCENE_JABU_JABU, {}, {}, {
areaTable[RR_JABU_JABUS_BELLY_JIGGLIES_ROOM] = Region("Jabu Jabus Belly Jigglies Room", SCENE_JABU_JABU, {}, {}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_ABOVE_BIGOCTO, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_LIFT_UPPER, []{return logic->CanUse(RG_BOOMERANG) || (logic->IsAdult && logic->CanGroundJump());}),
@@ -324,6 +329,7 @@ void RegionTable_Init_JabuJabusBelly() {
areaTable[RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM_PAST_JIGGLY] = Region("Jabu Jabus Belly MQ Holes Room Past Jiggly", SCENE_JABU_JABU, {}, {}, {
Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return logic->CanUse(RG_BOOMERANG);}),
//It is possible to open the door here without crossing the jiggly using RT_DISTANT_BOULDER and good timing
Entrance(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->Get(LOGIC_JABU_MQ_FORKED_ROOM_DOOR);}),
});
@@ -338,7 +344,7 @@ void RegionTable_Init_JabuJabusBelly() {
//Exits
Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return true /* logic->HasItem(RG_CLIMB) */;}),
Entrance(RR_JABU_JABUS_BELLY_MQ_TO_BIGOCTO, []{return logic->Get(LOGIC_JABU_WEST_TENTACLE);}),
Entrance(RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM, []{return logic->HasItem(RG_POWER_BRACELET);}),
Entrance(RR_JABU_JABUS_BELLY_MQ_INVISIBLE_KEESE_ROOM, []{return logic->Get(LOGIC_JABU_NORTH_TENTACLE);}),
});
@@ -349,7 +355,7 @@ void RegionTable_Init_JabuJabusBelly() {
//Locations
LOCATION(RC_JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, logic->CanKillEnemy(RE_LIZALFOS) && logic->HasItem(RG_OPEN_CHEST)),
LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, (logic->CanUse(RG_SONG_OF_TIME) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)) || (ctx->GetTrickOption(RT_JABU_MQ_SOT_GS) && logic->CanUse(RG_BOOMERANG))),
LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, (logic->CanUse(RG_SONG_OF_TIME) && (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) || logic->HasItem(RG_POWER_BRACELET))) || (ctx->GetTrickOption(RT_JABU_MQ_SOT_GS) && logic->CanUse(RG_BOOMERANG))),
LOCATION(RC_JABU_JABUS_BELLY_MQ_TIME_BLOCK_POT_1, logic->CanBreakPots()),
LOCATION(RC_JABU_JABUS_BELLY_MQ_TIME_BLOCK_POT_2, logic->CanBreakPots()),
LOCATION(RC_JABU_JABUS_BELLY_MQ_BASEMENT_BOOMERANG_GRASS, logic->CanCutShrubs()),
@@ -372,7 +378,7 @@ void RegionTable_Init_JabuJabusBelly() {
//If some mode lets an age use sticks and not sling, and other use sling and not sticks, this needs changing
Entrance(RR_JABU_JABUS_BELLY_MQ_TO_FORK_WEST, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_MQ_TO_FORK_NORTH_WEST, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_MQ_TO_FORK_NORTH, []{return logic->BlastOrSmash();}),
Entrance(RR_JABU_JABUS_BELLY_MQ_TO_FORK_NORTH, []{return logic->BlastOrSmash() && logic->HasItem(RG_POWER_BRACELET);}),
Entrance(RR_JABU_JABUS_BELLY_MQ_FORK_NORTH_EAST, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_MQ_FORK_EAST, []{return AnyAgeTime([]{return logic->CanUse(RG_FAIRY_SLINGSHOT) && logic->CanUse(RG_STICKS);}) || AnyAgeTime([]{return logic->HasFireSource();});}),
});
@@ -410,7 +416,7 @@ void RegionTable_Init_JabuJabusBelly() {
areaTable[RR_JABU_JABUS_BELLY_MQ_TO_FORK_NORTH] = Region("Jabu Jabus Belly MQ To Fork North", SCENE_JABU_JABU, {}, {}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->BlastOrSmash();}),
Entrance(RR_JABU_JABUS_BELLY_MQ_FORK_NORTH, []{return logic->BlastOrSmash() /*&& str0*/;}),
Entrance(RR_JABU_JABUS_BELLY_MQ_FORK_NORTH, []{return logic->BlastOrSmash() && logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_JABU_JABUS_BELLY_MQ_FORK_NORTH] = Region("Jabu Jabus Belly MQ Fork North", SCENE_JABU_JABU, {
@@ -473,8 +479,8 @@ void RegionTable_Init_JabuJabusBelly() {
// Need Ruto here
areaTable[RR_JABU_JABUS_BELLY_MQ_BIGOCTO] = Region("Jabu Jabus Belly MQ Big Octo", SCENE_JABU_JABU, {}, {}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_MQ_TO_BIGOCTO, []{return AnyAgeTime([]{return logic->CanKillEnemy(RE_BIG_OCTO);});}),
Entrance(RR_JABU_JABUS_BELLY_MQ_ABOVE_BIGOCTO, []{return AnyAgeTime([]{return logic->CanKillEnemy(RE_BIG_OCTO);});}),
Entrance(RR_JABU_JABUS_BELLY_MQ_TO_BIGOCTO, []{return AnyAgeTime([]{return logic->HasItem(RG_POWER_BRACELET) && logic->CanKillEnemy(RE_BIG_OCTO);});}),
Entrance(RR_JABU_JABUS_BELLY_MQ_ABOVE_BIGOCTO, []{return AnyAgeTime([]{return logic->HasItem(RG_POWER_BRACELET) && logic->CanKillEnemy(RE_BIG_OCTO);});}),
});
areaTable[RR_JABU_JABUS_BELLY_MQ_ABOVE_BIGOCTO] = Region("Jabu Jabus Belly MQ Above Big Octo", SCENE_JABU_JABU, {}, {
@@ -496,7 +502,7 @@ void RegionTable_Init_JabuJabusBelly() {
}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_MQ_ABOVE_BIGOCTO, []{return true;}),
Entrance(RR_JABU_JABUS_BELLY_MQ_ABOVE_LIFT_ROOM, []{return logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_FAIRY_SLINGSHOT);}),
Entrance(RR_JABU_JABUS_BELLY_MQ_ABOVE_LIFT_ROOM, []{return logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_FAIRY_SLINGSHOT) && logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_JABU_JABUS_BELLY_MQ_ABOVE_LIFT_ROOM] = Region("Jabu Jabus Belly MQ Above Lift Room", SCENE_JABU_JABU, {
@@ -20,7 +20,7 @@ void RegionTable_Init_ShadowTemple() {
//Exits
Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, []{return (ctx->GetTrickOption(RT_LENS_SHADOW) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT));}),
Entrance(RR_SHADOW_TEMPLE_WHISPERING_WALLS_START, []{return ctx->GetTrickOption(RT_LENS_SHADOW) || logic->CanUse(RG_LENS_OF_TRUTH);}),
Entrance(RR_SHADOW_TEMPLE_FIRST_BEAMOS, []{return (ctx->GetTrickOption(RT_LENS_SHADOW) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanUse(RG_HOVER_BOOTS);}),
Entrance(RR_SHADOW_TEMPLE_FIRST_BEAMOS, []{return (ctx->GetTrickOption(RT_LENS_SHADOW) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->HasItem(RG_POWER_BRACELET) && logic->CanUse(RG_HOVER_BOOTS);}),
});
areaTable[RR_SHADOW_TEMPLE_WHISPERING_WALLS_START] = Region("Shadow Temple Whispering Walls Start", SCENE_SHADOW_TEMPLE, {
@@ -83,7 +83,7 @@ void RegionTable_Init_ShadowTemple() {
areaTable[RR_SHADOW_TEMPLE_FIRST_BEAMOS] = Region("Shadow Temple First Beamos", SCENE_SHADOW_TEMPLE, {}, {
//Locations
LOCATION(RC_SHADOW_TEMPLE_BEAMOS_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_SHADOW_TEMPLE_BEAMOS_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)),
}, {
//Exits
Entrance(RR_SHADOW_TEMPLE_BEGINNING, []{return ctx->GetTrickOption(RT_VISIBLE_COLLISION) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT));}),
@@ -371,7 +371,7 @@ void RegionTable_Init_ShadowTemple() {
}, {
//Exits
Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, []{return true;}),
Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, []{return AnyAgeTime([]{return logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}) && (logic->CanUse(RG_HOVER_BOOTS) || AnyAgeTime([]{return logic->CanUse(RG_FIRE_ARROWS);}) || (ctx->GetTrickOption(RT_SHADOW_MQ_GAP) && logic->CanUse(RG_LONGSHOT) && logic->CanJumpslashExceptHammer()));}),
Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, []{return AnyAgeTime([]{return logic->HasItem(RG_POWER_BRACELET) && (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)));}) && (logic->CanUse(RG_HOVER_BOOTS) || AnyAgeTime([]{return logic->CanUse(RG_FIRE_ARROWS);}) || (ctx->GetTrickOption(RT_SHADOW_MQ_GAP) && logic->CanUse(RG_LONGSHOT) && logic->CanJumpslashExceptHammer()));}),
Entrance(RR_SHADOW_TEMPLE_MQ_WHISPERING_WALLS_START, []{return AnyAgeTime([]{return logic->HasExplosives();}) && logic->SmallKeys(SCENE_SHADOW_TEMPLE, 6) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}),
});
@@ -75,8 +75,8 @@ void RegionTable_Init_SpiritTemple() {
LOCATION(RC_SPIRIT_TEMPLE_ANUBIS_POT_4, true),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_SWITCH_BRIDGE_NORTH, []{return AnyAgeTime([]{return logic->CanHitSwitch() || logic->CanKillEnemy(RE_ANUBIS);});}),
Entrance(RR_SPIRIT_TEMPLE_RUPEE_BRIDGE_NORTH, []{return AnyAgeTime([]{return logic->CanHitSwitch() || logic->CanKillEnemy(RE_ANUBIS);});}),
Entrance(RR_SPIRIT_TEMPLE_SWITCH_BRIDGE_NORTH, []{return AnyAgeTime([]{return logic->CanHitSwitch() || logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_ANUBIS);});}),
Entrance(RR_SPIRIT_TEMPLE_RUPEE_BRIDGE_NORTH, []{return AnyAgeTime([]{return logic->CanHitSwitch() || logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_ANUBIS);});}),
});
areaTable[RR_SPIRIT_TEMPLE_RUPEE_BRIDGE_NORTH] = Region("Spirit Temple Rupee Bridge North", SCENE_SPIRIT_TEMPLE, {
@@ -192,12 +192,12 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_2F_MIRROR_ROOM] = Region("Spirit Temple 2F Mirror Room", SCENE_SPIRIT_TEMPLE, {}, {
//Locations
LOCATION(RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, SpiritShared(RR_SPIRIT_TEMPLE_2F_MIRROR_ROOM, []{return logic->HasItem(RG_OPEN_CHEST)/*&& (str0 || SunlightArrows())*/;})),
LOCATION(RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, SpiritShared(RR_SPIRIT_TEMPLE_2F_MIRROR_ROOM, []{return logic->HasItem(RG_OPEN_CHEST)/*&& (str0 || SunlightArrows())*/;})),
LOCATION(RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, SpiritShared(RR_SPIRIT_TEMPLE_2F_MIRROR_ROOM, []{return logic->HasItem(RG_OPEN_CHEST) && (logic->HasItem(RG_POWER_BRACELET) || logic->SunlightArrows());})),
LOCATION(RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, SpiritShared(RR_SPIRIT_TEMPLE_2F_MIRROR_ROOM, []{return logic->HasItem(RG_OPEN_CHEST) && (logic->HasItem(RG_POWER_BRACELET) || logic->SunlightArrows());})),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_1F_MIRROR_ROOM, []{return true;}),
Entrance(RR_SPIRIT_TEMPLE_STATUE_ROOM_ADULT, []{return true/*str0 || SunlightArrows()*/;}),
Entrance(RR_SPIRIT_TEMPLE_STATUE_ROOM_ADULT, []{return logic->HasItem(RG_POWER_BRACELET) || logic->SunlightArrows();}),
});
areaTable[RR_SPIRIT_TEMPLE_STATUE_ROOM_CHILD] = Region("Spirit Temple Statue Rooom Child", SCENE_SPIRIT_TEMPLE, {}, {
@@ -216,13 +216,13 @@ void RegionTable_Init_SpiritTemple() {
// RT_SPIRIT_PLATFORM_HOOKSHOT is currently disabled
Entrance(RR_SPIRIT_TEMPLE_PLATFORM, []{return logic->Get(LOGIC_SPIRIT_PLATFORM_LOWERED) &&
(logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_SPIRIT_PLATFORM_HOOKSHOT) && logic->CanUse(RG_HOOKSHOT)));}),
Entrance(RR_SPIRIT_TEMPLE_EMPTY_STAIRS, []{return true/*str0*/;}),
Entrance(RR_SPIRIT_TEMPLE_EMPTY_STAIRS, []{return logic->HasItem(RG_POWER_BRACELET);}),
//!QUANTUM LOGIC!
//When child enters spirit in reverse, has 4 keys, and dungeon entrance shuffle is off,
//Child cannot lock themselves out of desert colossus access as if they save the west hand lock for last
//they will be able to exit the dungeon through the intended entrance and vice versa
//for needing to open the west hand lock to block the intended child route
Entrance(RR_DESERT_COLOSSUS, []{return ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) && /*str0 &&*/
Entrance(RR_DESERT_COLOSSUS, []{return ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) && logic->HasItem(RG_POWER_BRACELET) &&
logic->CanUse(RG_CRAWL) && logic->SmallKeys(SCENE_SPIRIT_TEMPLE, 4) && logic->CanKillEnemy(RE_IRON_KNUCKLE);}),
});
@@ -274,8 +274,8 @@ void RegionTable_Init_SpiritTemple() {
//If you do not have explosives to kill Beamos, but do have a way to defeat Iron Knuckles, this becomes possible with 4 keys instead.
Entrance(RR_SPIRIT_TEMPLE_ADULT_SIDE_HUB, []{return ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) &&
logic->CanUse(RG_SILVER_GAUNTLETS) && logic->IsAdult &&
((logic->CanKillEnemy(RE_BEAMOS) && logic->SmallKeys(SCENE_SPIRIT_TEMPLE, /*CanClimb() && str0 ?*/ 2 /*: 3*/)) ||
(/*CanClimb() && str0 && */logic->CanKillEnemy(RE_IRON_KNUCKLE) && logic->SmallKeys(SCENE_SPIRIT_TEMPLE, 4)));}),
((logic->CanKillEnemy(RE_BEAMOS) && logic->SmallKeys(SCENE_SPIRIT_TEMPLE, /*CanClimb() &&*/ logic->HasItem(RG_POWER_BRACELET) ? 2 : 3)) ||
(/*CanClimb() &&*/ logic->HasItem(RG_POWER_BRACELET) && logic->CanKillEnemy(RE_IRON_KNUCKLE) && logic->SmallKeys(SCENE_SPIRIT_TEMPLE, 4)));}),
});
areaTable[RR_SPIRIT_TEMPLE_EMPTY_STAIRS] = Region("Spirit Temple Empty Stairs", SCENE_SPIRIT_TEMPLE, {}, {}, {
@@ -286,12 +286,10 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_SUN_BLOCK_ROOM] = Region("Spirit Temple Sun Block Room", SCENE_SPIRIT_TEMPLE, {}, {}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_EMPTY_STAIRS, []{return true/*str0 || SunlightArrows*/;}),
Entrance(RR_SPIRIT_TEMPLE_EMPTY_STAIRS, []{return logic->HasItem(RG_POWER_BRACELET) || logic->SunlightArrows();}),
//The blocks can be used to get onto this ledge itemless
//true/*str0 || IsAdult || CanKillEnemy(RE_BEAMOS) || BunnyHovers() ||
//((HasFireSource() || (SpiritSunBlockTorch && (logic->CanUse(STICKS) || (ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && logic->CanUse(RG_FAIRY_BOW))))) && CanUse(RG_HOOKSHOT))*/
Entrance(RR_SPIRIT_TEMPLE_SUN_BLOCK_CHEST_LEDGE, []{return logic->SpiritSunBlockSouthLedge();}),
Entrance(RR_SPIRIT_TEMPLE_SKULLTULA_STAIRS, []{return true/*str0 || SunlightArrows*/;}),
Entrance(RR_SPIRIT_TEMPLE_SKULLTULA_STAIRS, []{return logic->HasItem(RG_POWER_BRACELET) || logic->SunlightArrows();}),
});
areaTable[RR_SPIRIT_TEMPLE_SUN_BLOCK_CHEST_LEDGE] = Region("Spirit Temple Sun Block Chest ledge", SCENE_SPIRIT_TEMPLE, {
@@ -303,8 +301,8 @@ void RegionTable_Init_SpiritTemple() {
//Spawning the chest to get here is accounted for in movement logic, so we only need to confirm it can be spawned here
LOCATION(RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, SpiritShared(RR_SPIRIT_TEMPLE_SUN_BLOCK_CHEST_LEDGE,
[]{return logic->HasFireSource() ||
(logic->Get(LOGIC_SPIRIT_SUN_BLOCK_TORCH) && //Possible without str0 by timing a shot during a backflip from the ledge, but it's probably a separate trick
(logic->CanUse(RG_STICKS) || (ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && logic->CanUse(RG_FAIRY_BOW)/* && str0*/)));}) && logic->HasItem(RG_OPEN_CHEST)),
(logic->Get(LOGIC_SPIRIT_SUN_BLOCK_TORCH) &&
(logic->CanUse(RG_STICKS) || (ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && logic->CanUse(RG_FAIRY_BOW))));}) && logic->HasItem(RG_OPEN_CHEST)),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_SUN_BLOCK_ROOM, []{return true;}),
@@ -317,7 +315,7 @@ void RegionTable_Init_SpiritTemple() {
LOCATION(RC_SPIRIT_TEMPLE_AFTER_SUN_BLOCK_POT_2, SpiritShared(RR_SPIRIT_TEMPLE_SKULLTULA_STAIRS, []{return logic->CanBreakPots();})),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_SUN_BLOCK_ROOM, []{return true;}),
Entrance(RR_SPIRIT_TEMPLE_SUN_BLOCK_ROOM, []{return true;}),
Entrance(RR_SPIRIT_TEMPLE_CHILD_THRONE, []{return logic->SmallKeys(SCENE_SPIRIT_TEMPLE, 3);}),
});
@@ -504,9 +502,8 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_BIG_MIRROR_CAVE] = Region("Spirit Temple Big Mirror Cave", SCENE_SPIRIT_TEMPLE, {
//Events
EventAccess(LOGIC_SPIRIT_4F_SWITCH, []{return logic->HasExplosives();}),
//WARNING: not currently a permanent flag, needs to be one for doorsanity
EventAccess(LOGIC_SPIRIT_PUSHED_4F_MIRRORS, []{return logic->HasExplosives()/*&& str0*/;}),
EventAccess(LOGIC_SPIRIT_4F_SWITCH, []{return logic->HasExplosives();}),
EventAccess(LOGIC_SPIRIT_PUSHED_4F_MIRRORS, []{return logic->HasExplosives() && logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_SPIRIT_TEMPLE_TOPMOST_CHEST, ((logic->IsAdult && logic->CanUse(RG_MIRROR_SHIELD)) || logic->SunlightArrows()) && logic->HasItem(RG_OPEN_CHEST)),
@@ -590,14 +587,13 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_MQ_GIBDO_GRAVES] = Region("Spirit Temple MQ Gibdo Graves", SCENE_SPIRIT_TEMPLE, {
//Events
EventAccess(LOGIC_SPIRIT_MQ_GIBDOS_CLEARED, []{return /*str0 && */
(logic->CanUse(RG_BOMBCHU_5) && logic->CanHitEyeTargets()) ||
logic->CanUse(RG_HOVER_BOOTS)/* || (IsAdult && CanBunnyJump())*/
&& logic->CanKillEnemy(RE_GIBDO, ED_CLOSE, true, 3) /* && str0*/;}),
EventAccess(LOGIC_SPIRIT_MQ_GIBDOS_CLEARED, []{return logic->HasItem(RG_POWER_BRACELET) &&
((logic->CanUse(RG_BOMBCHU_5) && logic->CanHitEyeTargets()) || logic->CanUse(RG_HOVER_BOOTS)/* || (IsAdult && CanBunnyJump())*/)
&& logic->CanKillEnemy(RE_GIBDO, ED_CLOSE, true, 3);}),
}, {}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_MQ_CHILD_SIDE_HUB, []{return true;}),
Entrance(RR_SPIRIT_TEMPLE_MQ_GIBDO_POTS, []{return /*str0 && */
Entrance(RR_SPIRIT_TEMPLE_MQ_GIBDO_POTS, []{return logic->HasItem(RG_POWER_BRACELET) &&
(logic->CanUse(RG_BOMBCHU_5) && logic->CanHitEyeTargets()) ||
logic->CanUse(RG_HOVER_BOOTS)/* || (IsAdult && CanBunnyJump())*/;}),
});
@@ -636,15 +632,15 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_MQ_ANUBIS_BRIDGE_GRAVE] = Region("Spirit Temple MQ Anubis Bridge Grave", SCENE_SPIRIT_TEMPLE, {
//Events
EventAccess(LOGIC_SPIRIT_MQ_MAP_ROOM_ENEMIES, []{return /*(*/logic->CanKillEnemy(RE_ANUBIS) && logic->CanKillEnemy(RE_KEESE)/*) && (str0 || CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT) || (logic->IsAdult && CanBunnyJump())) ||
logic->CanKillEnemy(RE_ANUBIS, ED_BOOMERANG) && logic->CanKillEnemy(RE_KEESE, ED_FAR)*/;}),
EventAccess(LOGIC_SPIRIT_MQ_MAP_ROOM_ENEMIES, []{return (logic->CanKillEnemy(RE_ANUBIS) && logic->CanKillEnemy(RE_KEESE)) && (logic->HasItem(RG_POWER_BRACELET) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT) /*|| (logic->IsAdult && CanBunnyJump())*/) ||
(logic->CanKillEnemy(RE_ANUBIS, ED_BOOMERANG) && logic->CanKillEnemy(RE_KEESE, ED_FAR));}),
}, {
//Locations
LOCATION(RC_SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, logic->Get(LOGIC_SPIRIT_MQ_MAP_ROOM_ENEMIES) && logic->HasItem(RG_OPEN_CHEST)),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_MQ_TURNTABLE, []{return true;}),
Entrance(RR_SPIRIT_TEMPLE_MQ_ANUBIS_BRIDGE_CHEST, []{return true/*str0 || CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT) || (logic->IsAdult && CanBunnyJump())*/;}),
Entrance(RR_SPIRIT_TEMPLE_MQ_ANUBIS_BRIDGE_CHEST, []{return logic->HasItem(RG_POWER_BRACELET) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT) /*|| (logic->IsAdult && CanBunnyJump())*/;}),
});
areaTable[RR_SPIRIT_TEMPLE_MQ_ANUBIS_BRIDGE_CHEST] = Region("Spirit Temple MQ Anubis Bridge Chest", SCENE_SPIRIT_TEMPLE, {
@@ -712,7 +708,6 @@ void RegionTable_Init_SpiritTemple() {
Entrance(RR_SPIRIT_TEMPLE_MQ_SUN_ON_FLOOR, []{return logic->SmallKeys(SCENE_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_RIGHT_HAND, []{return logic->IsAdult || logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS)/* || CanBunnyJump()*/;}),
//(IsAdult || ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) || CanUse(RG_SONG_OF_TIME) || CanBunnyJump()) && str0
Entrance(RR_SPIRIT_TEMPLE_MQ_FLAMETHROWER_STAIRS, []{return logic->MQSpiritStatueToSunBlock();}),
//explicit adult check here is a precaution against possible child logic leaking, child with a hookshot can do this
Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_ADULT, []{return logic->IsAdult && logic->CanUse(RG_HOOKSHOT);}),
@@ -787,16 +782,16 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM] = Region("Spirit Temple MQ Sun Block Room", SCENE_SPIRIT_TEMPLE, {}, {
//Locations
LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, SpiritShared(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->HasItem(RG_OPEN_CHEST)/*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())*/) ||
LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, SpiritShared(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->HasItem(RG_POWER_BRACELET) && logic->HasItem(RG_OPEN_CHEST);})),
//RT_SPIRIT_MQ_SUN_BLOCK_GS should probably be expanded to cover all ground based methods, 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) && (logic->HasItem(RG_POWER_BRACELET) || logic->SunlightArrows())) ||
(ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_GS) && logic->CanUse(RG_BOOMERANG));})),
LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCKS_POT_1, SpiritShared(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->CanBreakPots();})),
LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCKS_POT_2, SpiritShared(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->CanBreakPots();})),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_MQ_FLAMETHROWER_STAIRS, []{return true/*str0 || SunlightArrows()*/;}),
Entrance(RR_SPIRIT_TEMPLE_MQ_SKULLTULA_STAIRS, []{return true/*str0 || SunlightArrows()*/;}),
Entrance(RR_SPIRIT_TEMPLE_MQ_FLAMETHROWER_STAIRS, []{return logic->HasItem(RG_POWER_BRACELET) || logic->SunlightArrows();}),
Entrance(RR_SPIRIT_TEMPLE_MQ_SKULLTULA_STAIRS, []{return logic->HasItem(RG_POWER_BRACELET) || logic->SunlightArrows();}),
});
areaTable[RR_SPIRIT_TEMPLE_MQ_SKULLTULA_STAIRS] = Region("Spirit Temple MQ Skulltula Stairs", SCENE_SPIRIT_TEMPLE, {}, {}, {
@@ -853,17 +848,7 @@ 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_3_SUNS_ROOM_2F, []{return logic->Get(LOGIC_SPIRIT_MQ_STATUE_ROOM_TORCHES);}),
/* 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)*/
Entrance(RR_DESERT_COLOSSUS, []{return logic->SmallKeys(SCENE_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_RIGHT_HAND, []{return logic->SmallKeys(SCENE_SPIRIT_TEMPLE, 4) && logic->MQSpirit4KeyWestHand();}),
Entrance(RR_SPIRIT_TEMPLE_MQ_FIRE_WALL_STAIRS_LOWER, []{return logic->SmallKeys(SCENE_SPIRIT_TEMPLE, 5);}),
// RT_SPIRIT_PLATFORM_HOOKSHOT is currently disabled
@@ -979,8 +964,8 @@ void RegionTable_Init_SpiritTemple() {
LOCATION(RC_SPIRIT_TEMPLE_MQ_BEAMOS_SMALL_CRATE, logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && logic->CanBreakSmallCrates()),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_MQ_FIRE_WALL_STAIRS_UPPER, []{return logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME)/* && str0*/;}),
Entrance(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, []{return logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME)/* && str0*/;}),
Entrance(RR_SPIRIT_TEMPLE_MQ_FIRE_WALL_STAIRS_UPPER, []{return logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && logic->HasItem(RG_POWER_BRACELET);}),
Entrance(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, []{return logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && logic->HasItem(RG_POWER_BRACELET);}),
Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_WALL_BASE, []{return logic->SmallKeys(SCENE_SPIRIT_TEMPLE, 6);}),
});
@@ -1095,8 +1080,7 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE] = Region("Spirit Temple MQ Big Mirror Cave", SCENE_SPIRIT_TEMPLE, {
//Events
//WARNING: Not currently a permanent flag, needs to be one for doorsanity
EventAccess(LOGIC_SPIRIT_PUSHED_4F_MIRRORS, []{return ((logic->IsAdult && logic->CanUse(RG_MIRROR_SHIELD)) || logic->SunlightArrows())/* && str0*/;}),
EventAccess(LOGIC_SPIRIT_PUSHED_4F_MIRRORS, []{return ((logic->IsAdult && logic->CanUse(RG_MIRROR_SHIELD)) || logic->SunlightArrows()) && logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->HasItem(RG_OPEN_CHEST)),
@@ -347,7 +347,8 @@ void RegionTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_GS_CAGE] = Region("Water Temple GS Cage", SCENE_WATER_TEMPLE, {}, {
//Locations
LOCATION(RC_WATER_TEMPLE_GS_BEHIND_GATE, logic->IsAdult || logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_GROUND_JUMP_HARD) &&logic->CanGroundJump() && logic->CanJumpslash())),
LOCATION(RC_WATER_TEMPLE_GS_BEHIND_GATE, (logic->IsAdult && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))) ||
logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_GROUND_JUMP_HARD) &&logic->CanGroundJump() && logic->CanJumpslash())),
LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_1, logic->CanBreakPots()),
LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_2, logic->CanBreakPots()),
LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_3, logic->CanBreakPots()),
@@ -736,7 +737,7 @@ void RegionTable_Init_WaterTemple() {
//Exits
Entrance(RR_WATER_TEMPLE_MQ_2F_CENTRAL_A, []{return true;}),
Entrance(RR_WATER_TEMPLE_MQ_PILLAR_2F, []{return true;}),
Entrance(RR_WATER_TEMPLE_MQ_HIDDEN_SWITCH_2F, []{return (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_HOOKSHOT);}),
Entrance(RR_WATER_TEMPLE_MQ_HIDDEN_SWITCH_2F, []{return (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_HOOKSHOT) && logic->HasItem(RG_POWER_BRACELET);}),
Entrance(RR_WATER_TEMPLE_MQ_LIZALFOS_LOOP_LM, []{return logic->CanUse(RG_HOVER_BOOTS);}),
});
@@ -954,7 +955,9 @@ void RegionTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_MQ_HIDDEN_SWITCH_3F] = Region("Water Temple MQ Hidden Switch 3F", SCENE_WATER_TEMPLE, {}, {
//Locations
LOCATION(RC_WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)),
//Boxes can kill Gold Skulltulas.
LOCATION(RC_WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, (logic->CanBreakCrates() && logic->HasItem(RG_POWER_BRACELET)) ||
(logic->CanBreakCrates() || ctx->GetTrickOption(RT_VISIBLE_COLLISION)) && logic->CanKillEnemy(RE_GOLD_SKULLTULA)),
LOCATION(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_1, logic->CanBreakCrates()),
LOCATION(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_2, logic->CanBreakCrates()),
LOCATION(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_SMALL_CRATE, logic->CanBreakSmallCrates()),
@@ -1007,6 +1010,7 @@ void RegionTable_Init_WaterTemple() {
//Assumes WL_LOW_OR_MID is checked on entry
areaTable[RR_WATER_TEMPLE_MQ_LIZALFOS_CAGE] = Region("Water Temple MQ Lizalfos Cage", SCENE_WATER_TEMPLE, {}, {
//Locations
//Technically hidden within a crate, but the act of opening the cage kills it and spawns the token on top so it's except from RT_VISUAL_COLLISION
LOCATION(RC_WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, logic->CanKillEnemy(RE_GOLD_SKULLTULA)),
LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_CAGE_SOUTH_POT, logic->CanBreakPots()),
LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_CAGE_NORTH_POT, logic->CanBreakPots()),
@@ -19,7 +19,7 @@ void RegionTable_Init_CastleGrounds() {
areaTable[RR_HYRULE_CASTLE_GROUNDS] = Region("Hyrule Castle Grounds", SCENE_HYRULE_CASTLE, {
//Events
EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairy() || logic->CanUse(RG_STICKS);}),
EventAccess(LOGIC_BUG_ACCESS, []{return true;}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_HC_MALON_EGG, true),
@@ -45,7 +45,7 @@ void RegionTable_Init_CastleGrounds() {
}, {
//Exits
Entrance(RR_CASTLE_GROUNDS, []{return true;}),
Entrance(RR_HC_LEDGE, []{return logic->CanUse(RG_WEIRD_EGG) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}),
Entrance(RR_HC_LEDGE, []{return (logic->CanUse(RG_WEIRD_EGG) && logic->HasItem(RG_POWER_BRACELET)) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}),
Entrance(RR_HC_GREAT_FAIRY_FOUNTAIN, []{return logic->CanUse(RG_CRAWL) && logic->BlastOrSmash();}),
Entrance(RR_HC_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}),
});
@@ -33,7 +33,7 @@ void RegionTable_Init_DeathMountainTrail() {
areaTable[RR_DEATH_MOUNTAIN_SUMMIT] = Region("Death Mountain Summit", SCENE_DEATH_MOUNTAIN_TRAIL, {
//Events
EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairy();}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->IsChild;}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->IsChild && logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_DMT_TRADE_BROKEN_SWORD, logic->IsAdult && logic->CanUse(RG_BROKEN_SWORD)),
@@ -7,7 +7,7 @@ void RegionTable_Init_DesertColossus() {
// clang-format off
areaTable[RR_DESERT_COLOSSUS] = Region("Desert Colossus", SCENE_DESERT_COLOSSUS, {
//Events
EventAccess(LOGIC_BUG_ACCESS, []{return true;}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_COLOSSUS_FREESTANDING_POH, logic->IsAdult && CanPlantBean(RR_DESERT_COLOSSUS, RG_DESERT_COLOSSUS_BEAN_SOUL)),
@@ -7,19 +7,19 @@ void RegionTable_Init_GerudoValley() {
// clang-format off
areaTable[RR_GERUDO_VALLEY] = Region("Gerudo Valley", SCENE_GERUDO_VALLEY, {
//Events
EventAccess(LOGIC_BUG_ACCESS, []{return logic->IsChild;}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->IsChild && logic->HasItem(RG_POWER_BRACELET);}),
}, {
//Locations
LOCATION(RC_GV_GS_SMALL_BRIDGE, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()),
}, {
//Exits
Entrance(RR_HYRULE_FIELD, []{return true;}),
Entrance(RR_GV_UPPER_STREAM, []{return logic->IsChild || logic->HasItem(RG_BRONZE_SCALE) || logic->TakeDamage();}),
Entrance(RR_GV_CRATE_LEDGE, []{return logic->IsChild || logic->CanUse(RG_LONGSHOT);}),
Entrance(RR_GV_UPPER_STREAM, []{return (logic->IsChild && logic->HasItem(RG_POWER_BRACELET)) || logic->HasItem(RG_BRONZE_SCALE) || logic->TakeDamage();}),
Entrance(RR_GV_CRATE_LEDGE, []{return (logic->IsChild && logic->HasItem(RG_POWER_BRACELET)) || logic->CanUse(RG_LONGSHOT);}),
Entrance(RR_GV_GROTTO_LEDGE, []{return true;}),
Entrance(RR_GV_FORTRESS_SIDE, []{return (logic->IsAdult && (logic->SummonEpona() || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || logic->Get(LOGIC_TH_RESCUED_ALL_CARPENTERS))) || (ctx->GetTrickOption(RT_HOVER_BOOST_SIMPLE) && logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_HOVER_BOOTS)) ||
((logic->IsChild || ctx->GetTrickOption(RT_HOOKSHOT_EXTENSION)) && logic->CanUse(RG_HOOKSHOT)) || (logic->IsChild && ctx->GetTrickOption(RT_GV_CHILD_CUCCO_JUMP) && logic->CanJumpslash());}),
Entrance(RR_GV_LOWER_STREAM, []{return logic->IsChild;}), //can use cucco as child
((logic->IsChild || ctx->GetTrickOption(RT_HOOKSHOT_EXTENSION)) && logic->CanUse(RG_HOOKSHOT)) || (logic->IsChild && ctx->GetTrickOption(RT_GV_CHILD_CUCCO_JUMP) && logic->HasItem(RG_POWER_BRACELET) && logic->CanJumpslash());}),
Entrance(RR_GV_LOWER_STREAM, []{return logic->IsChild && logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_GV_UPPER_STREAM] = Region("GV Upper Stream", SCENE_GERUDO_VALLEY, {
@@ -27,7 +27,7 @@ void RegionTable_Init_GerudoValley() {
EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairy() || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_GERUDO_VALLEY_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS));}),
}, {
//Locations
LOCATION(RC_GV_WATERFALL_FREESTANDING_POH, logic->IsChild || logic->HasItem(RG_BRONZE_SCALE) || CanPlantBean(RR_GV_UPPER_STREAM, RG_GERUDO_VALLEY_BEAN_SOUL)),//can use cucco as child
LOCATION(RC_GV_WATERFALL_FREESTANDING_POH, (logic->IsChild && logic->HasItem(RG_POWER_BRACELET)) || logic->HasItem(RG_BRONZE_SCALE) || CanPlantBean(RR_GV_UPPER_STREAM, RG_GERUDO_VALLEY_BEAN_SOUL)),
LOCATION(RC_GV_GS_BEAN_PATCH, logic->CanSpawnSoilSkull(RG_GERUDO_VALLEY_BEAN_SOUL) && logic->CanAttack()),
LOCATION(RC_GV_COW, logic->IsChild && logic->CanUse(RG_EPONAS_SONG)),
LOCATION(RC_GV_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_GERUDO_VALLEY_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
@@ -9,7 +9,7 @@ void RegionTable_Init_GoronCity() {
//Events
EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairyExceptSuns();}),
EventAccess(LOGIC_STICK_ACCESS, []{return logic->IsChild && logic->CanBreakPots();}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS);}),
EventAccess(LOGIC_BUG_ACCESS, []{return (logic->BlastOrSmash() && logic->HasItem(RG_POWER_BRACELET)) || logic->CanUse(RG_SILVER_GAUNTLETS);}),
EventAccess(LOGIC_GORON_CITY_CHILD_FIRE, []{return logic->IsChild && logic->CanUse(RG_DINS_FIRE);}),
EventAccess(LOGIC_GORON_CITY_WOODS_WARP_OPEN, []{return logic->CanDetonateUprightBombFlower() || logic->CanUse(RG_MEGATON_HAMMER) || logic->Get(LOGIC_GORON_CITY_CHILD_FIRE);}),
EventAccess(LOGIC_GORON_CITY_DARUNIAS_DOOR_OPEN_CHILD, []{return logic->IsChild && logic->CanUse(RG_ZELDAS_LULLABY);}),
@@ -82,7 +82,7 @@ void RegionTable_Init_GoronCity() {
}, {
//Exits
Entrance(RR_GORON_CITY, []{return true;}),
Entrance(RR_DMC_LOWER_LOCAL, []{return logic->IsAdult;}),
Entrance(RR_DMC_LOWER_LOCAL, []{return logic->IsAdult && logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_GC_GROTTO_PLATFORM] = Region("GC Grotto Platform", SCENE_GORON_CITY, {}, {}, {
@@ -8,7 +8,7 @@ void RegionTable_Init_Graveyard() {
areaTable[RR_THE_GRAVEYARD] = Region("The Graveyard", SCENE_GRAVEYARD, {
//Events
EventAccess(LOGIC_FAIRY_ACCESS, []{return (logic->AtDay && logic->CanUse(RG_STICKS)) || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS));}),
EventAccess(LOGIC_BUG_ACCESS, []{return true;}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->HasItem(RG_POWER_BRACELET);}),
EventAccess(LOGIC_BORROW_BUNNY_HOOD, []{return logic->IsChild && logic->AtDay && logic->Get(LOGIC_BORROW_SPOOKY_MASK) && logic->HasItem(RG_CHILD_WALLET);}),
}, {
//Locations
@@ -34,10 +34,10 @@ void RegionTable_Init_Graveyard() {
LOCATION(RC_GRAVEYARD_CRATE, ((logic->IsAdult && CanPlantBean(RR_THE_GRAVEYARD, RG_GRAVEYARD_BEAN_SOUL)) || logic->CanUse(RG_LONGSHOT)) && logic->CanBreakCrates()),
}, {
//Exits
Entrance(RR_GRAVEYARD_SHIELD_GRAVE, []{return logic->IsAdult || logic->AtNight;}),
Entrance(RR_GRAVEYARD_SHIELD_GRAVE, []{return (logic->IsAdult || logic->AtNight) && logic->HasItem(RG_POWER_BRACELET);}),
Entrance(RR_GRAVEYARD_COMPOSERS_GRAVE, []{return logic->CanUse(RG_ZELDAS_LULLABY);}),
Entrance(RR_GRAVEYARD_HEART_PIECE_GRAVE, []{return logic->IsAdult || logic->AtNight;}),
Entrance(RR_GRAVEYARD_DAMPES_GRAVE, []{return logic->IsAdult;}),
Entrance(RR_GRAVEYARD_HEART_PIECE_GRAVE, []{return (logic->IsAdult || logic->AtNight) && logic->HasItem(RG_POWER_BRACELET);}),
Entrance(RR_GRAVEYARD_DAMPES_GRAVE, []{return logic->IsAdult && logic->HasItem(RG_POWER_BRACELET);}),
Entrance(RR_GRAVEYARD_DAMPES_HOUSE, []{return logic->IsAdult && logic->CanOpenOverworldDoor(RG_DAMPES_HUT_KEY) /*|| logic->AtDampeTime*/;}), //TODO: This needs to be handled in ToD rework
Entrance(RR_KAKARIKO_VILLAGE, []{return true;}),
Entrance(RR_GRAVEYARD_WARP_PAD_REGION, []{return false;}),
@@ -7,7 +7,7 @@ void RegionTable_Init_Kakariko() {
// clang-format off
areaTable[RR_KAKARIKO_VILLAGE] = Region("Kakariko Village", SCENE_KAKARIKO_VILLAGE, {
//Events
EventAccess(LOGIC_BUG_ACCESS, []{return true;}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->HasItem(RG_POWER_BRACELET);}),
//Open Gate setting is applied in RR_ROOT
EventAccess(LOGIC_KAKARIKO_GATE_OPEN, []{return logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER);}),
//Needs wallet to be able to get another mask after selling Keaton
@@ -15,14 +15,15 @@ void RegionTable_Init_Kakariko() {
}, {
//Locations
LOCATION(RC_SHEIK_IN_KAKARIKO, logic->IsAdult && logic->HasItem(RG_FOREST_MEDALLION) && logic->HasItem(RG_FIRE_MEDALLION) && logic->HasItem(RG_WATER_MEDALLION)),
LOCATION(RC_KAK_ANJU_AS_CHILD, logic->IsChild && logic->AtDay),
// RANDOTODO Readd chickens to rando settings
LOCATION(RC_KAK_ANJU_AS_CHILD, logic->IsChild && logic->AtDay && logic->HasItem(RG_POWER_BRACELET) && logic->CanBreakCrates()),
LOCATION(RC_KAK_ANJU_AS_ADULT, logic->IsAdult && logic->AtDay),
LOCATION(RC_KAK_TRADE_POCKET_CUCCO, logic->IsAdult && logic->AtDay && (logic->CanUse(RG_POCKET_EGG) && logic->Get(LOGIC_WAKE_UP_ADULT_TALON))),
//Can kill lower kak skulls with pots
LOCATION(RC_KAK_GS_HOUSE_UNDER_CONSTRUCTION, logic->IsChild && logic->CanGetNightTimeGS()),
LOCATION(RC_KAK_GS_SKULLTULA_HOUSE, logic->IsChild && logic->CanGetNightTimeGS()),
LOCATION(RC_KAK_GS_GUARDS_HOUSE, logic->IsChild && logic->CanGetNightTimeGS()),
LOCATION(RC_KAK_GS_TREE, logic->IsChild && logic->CanGetNightTimeGS() && logic->CanBonkTrees()),
LOCATION(RC_KAK_GS_HOUSE_UNDER_CONSTRUCTION, logic->IsChild && logic->CanGetNightTimeGS() && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_KAK_GS_SKULLTULA_HOUSE, logic->IsChild && logic->CanGetNightTimeGS() && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_KAK_GS_GUARDS_HOUSE, logic->IsChild && logic->CanGetNightTimeGS() && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_KAK_GS_TREE, logic->IsChild && logic->CanGetNightTimeGS() && logic->CanBonkTrees() && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_KAK_GS_WATCHTOWER, logic->IsChild && (logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_LONGSHOT) || (ctx->GetTrickOption(RT_KAK_TOWER_GS) && logic->CanJumpslashExceptHammer())) && logic->CanGetNightTimeGS()),
LOCATION(RC_KAK_NEAR_POTION_SHOP_POT_1, logic->IsChild && logic->CanBreakPots()),
LOCATION(RC_KAK_NEAR_POTION_SHOP_POT_2, logic->IsChild && logic->CanBreakPots()),
@@ -72,14 +73,14 @@ void RegionTable_Init_Kakariko() {
Entrance(RR_KAK_WELL, []{return logic->IsAdult || logic->Get(LOGIC_DRAIN_WELL) || logic->CanUse(RG_IRON_BOOTS) || (ctx->GetTrickOption(RT_BOTTOM_OF_THE_WELL_NAVI_DIVE) && logic->IsChild && logic->HasItem(RG_BRONZE_SCALE) && logic->CanJumpslash());}),
Entrance(RR_KAK_POTION_SHOP_FRONT, []{return (logic->AtDay || logic->IsChild) && logic->CanOpenOverworldDoor(RG_KAK_POTION_SHOP_KEY);}),
Entrance(RR_KAK_REDEAD_GROTTO, []{return logic->CanOpenBombGrotto();}),
Entrance(RR_KAK_IMPAS_LEDGE, []{return (logic->IsChild && logic->AtDay) || (logic->IsAdult && ctx->GetTrickOption(RT_VISIBLE_COLLISION));}),
Entrance(RR_KAK_IMPAS_LEDGE, []{return (logic->IsChild && logic->AtDay && logic->HasItem(RG_POWER_BRACELET)) || (logic->IsAdult && ctx->GetTrickOption(RT_VISIBLE_COLLISION));}),
Entrance(RR_KAK_WATCHTOWER, []{return logic->IsAdult || logic->AtDay || logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_LONGSHOT) || (ctx->GetTrickOption(RT_KAK_TOWER_GS) && logic->CanJumpslashExceptHammer());}),
Entrance(RR_KAK_ROOFTOP, []{return logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_UNINTUITIVE_JUMPS) && logic->IsAdult);}),
Entrance(RR_KAK_IMPAS_ROOFTOP, []{return logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_KAK_ROOFTOP_GS) && logic->CanUse(RG_HOVER_BOOTS));}),
Entrance(RR_THE_GRAVEYARD, []{return true;}),
Entrance(RR_KAK_BEHIND_GATE, []{return logic->IsAdult || logic->Get(LOGIC_KAKARIKO_GATE_OPEN);}),
//adult can jump from the fence near the windmill to ledgegrab the fence near granny's shop. is in logic on N64
Entrance(RR_KAK_BACKYARD, []{return logic->IsAdult || logic->AtDay;}),
Entrance(RR_KAK_BACKYARD, []{return logic->IsAdult || (logic->AtDay && logic->HasItem(RG_POWER_BRACELET));}),
});
areaTable[RR_KAK_IMPAS_LEDGE] = Region("Kak Impas Ledge", SCENE_KAKARIKO_VILLAGE, {}, {}, {
@@ -87,7 +87,7 @@ void RegionTable_Init_LakeHylia() {
Entrance(RR_LH_FISHING_ISLAND, []{return ((logic->IsChild || logic->Get(LOGIC_WATER_TEMPLE_CLEAR)) && logic->HasItem(RG_BRONZE_SCALE)) || (logic->IsAdult && (logic->ReachScarecrow() || CanPlantBean(RR_LAKE_HYLIA, RG_LAKE_HYLIA_BEAN_SOUL)));}),
Entrance(RR_LH_LAB, []{return logic->CanOpenOverworldDoor(RG_HYLIA_LAB_KEY);}),
Entrance(RR_LH_FROM_WATER_TEMPLE, []{return true;}),
Entrance(RR_LH_GROTTO, []{return true;}),
Entrance(RR_LH_GROTTO, []{return logic->HasItem(RG_POWER_BRACELET);}),
});
areaTable[RR_LH_FROM_SHORTCUT] = Region("LH From Shortcut", SCENE_LAKE_HYLIA, TIME_DOESNT_PASS, {RA_LAKE_HYLIA}, {}, {}, {
@@ -12,8 +12,8 @@ void RegionTable_Init_LonLonRanch() {
}, {
//Locations
LOCATION(RC_SONG_FROM_MALON, logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER) && logic->HasItem(RG_FAIRY_OCARINA) && logic->AtDay),
LOCATION(RC_LLR_GS_TREE, logic->IsChild && logic->CanBonkTrees()),
LOCATION(RC_LLR_GS_RAIN_SHED, logic->IsChild && logic->CanGetNightTimeGS()),
LOCATION(RC_LLR_GS_TREE, logic->IsChild && logic->CanBonkTrees() && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_LLR_GS_RAIN_SHED, logic->IsChild && logic->CanGetNightTimeGS() && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_LLR_GS_HOUSE_WINDOW, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()),
LOCATION(RC_LLR_GS_BACK_WALL, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()),
LOCATION(RC_LLR_FRONT_POT_1, logic->IsChild && logic->CanBreakPots()),
@@ -56,7 +56,7 @@ void RegionTable_Init_LonLonRanch() {
areaTable[RR_LLR_TOWER] = Region("LLR Tower", SCENE_LON_LON_BUILDINGS, {}, {
//Locations
LOCATION(RC_LLR_FREESTANDING_POH, logic->IsChild && logic->HasItem(RG_CRAWL)),
LOCATION(RC_LLR_FREESTANDING_POH, logic->IsChild && logic->HasItem(RG_POWER_BRACELET) && logic->HasItem(RG_CRAWL)),
LOCATION(RC_LLR_TOWER_LEFT_COW, logic->CanUse(RG_EPONAS_SONG)),
LOCATION(RC_LLR_TOWER_RIGHT_COW, logic->CanUse(RG_EPONAS_SONG)),
}, {
@@ -56,7 +56,7 @@ void RegionTable_Init_Market() {
}, {
//Locations
LOCATION(RC_MARKET_10_BIG_POES, logic->IsAdult && (logic->Get(LOGIC_BIG_POE_KILL) || logic->BigPoes >= ctx->GetOption(RSK_BIG_POE_COUNT).Get())),
LOCATION(RC_MARKET_GS_GUARD_HOUSE, logic->IsChild),
LOCATION(RC_MARKET_GS_GUARD_HOUSE, logic->IsChild && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_1, logic->IsChild && logic->CanBreakPots()),
LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_2, logic->IsChild && logic->CanBreakPots()),
LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_3, logic->IsChild && logic->CanBreakPots()),
@@ -8,8 +8,8 @@ void RegionTable_Init_ZorasDomain() {
areaTable[RR_ZORAS_DOMAIN] = Region("Zoras Domain", SCENE_ZORAS_DOMAIN, {
//Events
EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairyExceptSuns();}),
EventAccess(LOGIC_NUT_ACCESS, []{return true;}),
EventAccess(LOGIC_STICK_ACCESS, []{return logic->IsChild;}),
EventAccess(LOGIC_NUT_ACCESS, []{return logic->CanBreakPots();}),
EventAccess(LOGIC_STICK_ACCESS, []{return logic->IsChild && logic->CanBreakPots();}),
EventAccess(LOGIC_FISH_ACCESS, []{return logic->IsChild;}),
EventAccess(LOGIC_KING_ZORA_THAWED, []{return logic->IsAdult && logic->BlueFire();}),
EventAccess(LOGIC_DELIVER_RUTOS_LETTER, []{return logic->CanUse(RG_RUTOS_LETTER) && logic->IsChild && ctx->GetOption(RSK_ZORAS_FOUNTAIN).IsNot(RO_ZF_OPEN);}),
@@ -10,7 +10,7 @@ void RegionTable_Init_ZorasFountain() {
EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairyExceptSuns() || (logic->CanUse(RG_STICKS) && logic->AtDay);}),
}, {
//Locations
LOCATION(RC_ZF_GS_TREE, logic->IsChild && logic->CanBonkTrees()),
LOCATION(RC_ZF_GS_TREE, logic->IsChild && logic->CanBonkTrees() && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_ZF_GS_ABOVE_THE_LOG, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()),
LOCATION(RC_ZF_FAIRY_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()),
LOCATION(RC_ZF_FAIRY_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)),
@@ -41,7 +41,7 @@ void RegionTable_Init_ZoraRiver() {
LOCATION(RC_ZR_FROGS_SUNS_SONG, logic->IsChild && logic->CanUse(RG_SUNS_SONG)),
LOCATION(RC_ZR_FROGS_SONG_OF_TIME, logic->IsChild && logic->CanUse(RG_SONG_OF_TIME)),
LOCATION(RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, logic->CanUse(RG_BOOMERANG)),
LOCATION(RC_ZR_NEAR_DOMAIN_FREESTANDING_POH, (logic->IsChild /*&& str0*/) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_ZR_UPPER))),
LOCATION(RC_ZR_NEAR_DOMAIN_FREESTANDING_POH, (logic->IsChild && logic->HasItem(RG_POWER_BRACELET)) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_ZR_UPPER))),
LOCATION(RC_ZR_GS_LADDER, logic->IsChild && logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_SHORT_JUMPSLASH) && logic->CanGetNightTimeGS()),
LOCATION(RC_ZR_GS_NEAR_RAISED_GROTTOS, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_LONGSHOT) && logic->CanGetNightTimeGS()),
LOCATION(RC_ZR_GS_ABOVE_BRIDGE, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_HOOKSHOT) && logic->CanGetNightTimeGS()),
@@ -59,11 +59,11 @@ void RegionTable_Init_ZoraRiver() {
}, {
//Exits
Entrance(RR_ZR_FRONT, []{return true;}),
Entrance(RR_ZR_ATOP_LADDER, []{return true/*(logic->IsAdult || str0) && (logic->CanUse(RG_CLIMB) || (logic->IsAdult && logic->CanUse(RG_LONGSHOT)))*/;}),
Entrance(RR_ZR_PILLAR, []{return (logic->IsChild/* && str0*/) || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_ZR_LOWER));}),
Entrance(RR_ZR_ATOP_LADDER, []{return (logic->IsAdult || logic->HasItem(RG_POWER_BRACELET)) /*&& (logic->CanUse(RG_CLIMB) || (logic->IsAdult && logic->CanUse(RG_HOOKSHOT)))*/;}),
Entrance(RR_ZR_PILLAR, []{return (logic->IsChild && logic->HasItem(RG_POWER_BRACELET)) || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_ZR_LOWER));}),
Entrance(RR_ZR_FROM_SHORTCUT, []{return logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS);}),
Entrance(RR_ZR_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}),
Entrance(RR_ZR_BEHIND_WATERFALL, []{return ctx->GetOption(RSK_SLEEPING_WATERFALL).Is(RO_WATERFALL_OPEN) || AnyAgeTime([]{return logic->CanUse(RG_ZELDAS_LULLABY);}) || (logic->IsChild && ctx->GetTrickOption(RT_ZR_CUCCO)) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_ZR_HOVERS));}),
Entrance(RR_ZR_BEHIND_WATERFALL, []{return ctx->GetOption(RSK_SLEEPING_WATERFALL).Is(RO_WATERFALL_OPEN) || AnyAgeTime([]{return logic->CanUse(RG_ZELDAS_LULLABY);}) || (logic->IsChild && ctx->GetTrickOption(RT_ZR_CUCCO) && logic->HasItem(RG_POWER_BRACELET)) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_ZR_HOVERS));}),
});
areaTable[RR_ZR_ATOP_LADDER] = Region("ZR Atop Ladder", SCENE_ZORAS_RIVER, {
@@ -78,7 +78,7 @@ void RegionTable_Init_ZoraRiver() {
}, {
//Exits
Entrance(RR_ZORAS_RIVER, []{return true;}),
Entrance(RR_ZR_PILLAR, []{return (logic->IsChild/* && str0*/) || logic->CanUse(RG_HOVER_BOOTS);}),
Entrance(RR_ZR_PILLAR, []{return (logic->IsChild && logic->HasItem(RG_POWER_BRACELET)) || logic->CanUse(RG_HOVER_BOOTS);}),
Entrance(RR_ZR_OPEN_GROTTO, []{return true;}),
Entrance(RR_ZR_FAIRY_GROTTO, []{return AnyAgeTime([]{return logic->BlastOrSmash();});}),
});
+35 -23
View File
@@ -1,7 +1,6 @@
#include "logic.h"
#include "../debugger/performanceTimer.h"
#include <algorithm>
#include <string>
#include <vector>
@@ -80,6 +79,8 @@ bool Logic::HasItem(RandomizerGet itemName) {
return CheckEquipment(RandoGetToEquipFlag.at(itemName)) || Get(LOGIC_MEDIGORON);
case RG_BIGGORON_SWORD:
return CheckEquipment(RandoGetToEquipFlag.at(itemName)) && mSaveContext->bgsFlag;
case RG_POWER_BRACELET:
return CheckRandoInf(RAND_INF_CAN_GRAB);
case RG_GORONS_BRACELET:
return CurrentUpgrade(UPG_STRENGTH);
case RG_SILVER_GAUNTLETS:
@@ -423,10 +424,8 @@ bool Logic::CanUse(RandomizerGet itemName) {
return Get(LOGIC_FAIRY_ACCESS);
default:
SPDLOG_ERROR("CanUse reached `default` for {}. Assuming intention is no extra requirements for use so "
"returning true, but HasItem should be used instead.",
static_cast<uint32_t>(itemName));
assert(false);
SPDLOG_INFO("CanUse reached `default` for {}. using HasItem is a minor Optimisation.",
static_cast<uint32_t>(itemName));
return true;
}
}
@@ -792,7 +791,8 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
(ctx->GetTrickOption(RT_DC_DODONGO_CHU) && IsAdult && CanUse(RG_BOMBCHU_5)));
case RE_BARINADE:
return HasBossSoul(RG_BARINADE_SOUL) && CanUse(RG_BOOMERANG) &&
(CanJumpslashExceptHammer() || ctx->GetTrickOption(RT_JABU_BARINADE_POTS));
(CanJumpslashExceptHammer() ||
(ctx->GetTrickOption(RT_JABU_BARINADE_POTS) && HasItem(RG_POWER_BRACELET)));
case RE_PHANTOM_GANON:
return HasBossSoul(RG_PHANTOM_GANON_SOUL) && CanUseSword() &&
(CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT));
@@ -1018,6 +1018,7 @@ bool Logic::CanGetEnemyDrop(RandomizerEnemy enemy, EnemyDistance distance, bool
if (!CanKillEnemy(enemy, distance)) {
return false;
}
// RANDOTODO assumption broke with RC_WATER_TEMPLE_GS_BEHIND_GATE, redesign GS helpers
if (distance <= ED_MASTER_SWORD_JUMPSLASH) {
return true;
}
@@ -1283,10 +1284,10 @@ bool Logic::CanBreakPots(EnemyDistance distance, bool wallOrFloor, bool inWater)
bool hit = false;
switch (distance) {
case ED_CLOSE:
hit = true; // str0
hit = HasItem(RG_POWER_BRACELET);
[[fallthrough]];
case ED_SHORT_JUMPSLASH:
hit = hit || CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MEGATON_HAMMER);
hit = hit || CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_GIANTS_KNIFE);
[[fallthrough]];
case ED_MASTER_SWORD_JUMPSLASH:
hit = hit || CanUse(RG_MASTER_SWORD);
@@ -1318,7 +1319,7 @@ bool Logic::CanBreakCrates() {
}
bool Logic::CanBreakSmallCrates() {
return true;
return CanJumpslash() || HasExplosives() || HasItem(RG_POWER_BRACELET);
}
bool Logic::CanBonkTrees() {
@@ -1779,8 +1780,14 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
} break;
case RG_PROGRESSIVE_STRENGTH: {
auto currentLevel = CurrentUpgrade(UPG_STRENGTH);
auto newLevel = currentLevel + (!state ? -1 : 1);
SetUpgrade(UPG_STRENGTH, newLevel);
if (!CheckRandoInf(RAND_INF_CAN_GRAB) && state) {
SetRandoInf(RAND_INF_CAN_GRAB, true);
} else if (currentLevel == 0 && !state) {
SetRandoInf(RAND_INF_CAN_GRAB, false);
} else {
auto newLevel = currentLevel + (!state ? -1 : 1);
SetUpgrade(UPG_STRENGTH, newLevel);
}
} break;
case RG_PROGRESSIVE_BOMB_BAG: {
auto realGI = item.GetGIEntry();
@@ -2528,13 +2535,12 @@ bool Logic::SpiritWestToSkull() {
}
bool Logic::SpiritSunBlockSouthLedge() {
// It's also possible to do a backwalk hover + backflip if you equip hovers as you start the backwalk to accelerate
// faster
return true /*str0 || IsAdult || CanKillEnemy(RE_BEAMOS) || BunnyHovers() ||
(CanUse(RG_HOOKSHOT) && (HasFireSource() ||
(SpiritSunBlockTorch && (logic->CanUse(STICKS) ||
(ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && logic->CanUse(RG_FAIRY_BOW))))))*/
;
// also possible to do a backwalk hover + backflip if you equip hovers as you start backwalk to accelerate faster
return HasItem(RG_POWER_BRACELET) || IsAdult || CanKillEnemy(RE_BEAMOS) /*|| BunnyHovers()*/ ||
(CanUse(RG_HOOKSHOT) &&
(HasFireSource() ||
(Get(LOGIC_SPIRIT_SUN_BLOCK_TORCH) &&
(CanUse(RG_STICKS) || (ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && CanUse(RG_FAIRY_BOW))))));
}
bool Logic::SpiritEastToSwitch() {
@@ -2549,7 +2555,8 @@ bool Logic::MQSpiritWestToPots() {
bool Logic::MQSpiritStatueToSunBlock() {
return (IsAdult || ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) ||
CanUse(RG_SONG_OF_TIME) /* || CanBunnyJump()*/) /* && str0*/;
CanUse(RG_SONG_OF_TIME) /* || CanBunnyJump()*/) &&
HasItem(RG_POWER_BRACELET);
}
bool Logic::MQSpiritStatueSouthDoor() {
@@ -2563,8 +2570,8 @@ bool Logic::MQSpirit4KeyColossus() {
// 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) &&*/
return CanAvoidEnemy(RE_BEAMOS, true, 4) && CanUse(RG_SONG_OF_TIME) && CanJumpslash() &&
(HasItem(RG_POWER_BRACELET) || SunlightArrows()) &&
(ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH)) && CanKillEnemy(RE_IRON_KNUCKLE) &&
CanUse(RG_HOOKSHOT);
}
@@ -2579,7 +2586,7 @@ bool Logic::MQSpirit4KeyWestHand() {
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) &&*/
(HasItem(RG_POWER_BRACELET) || SunlightArrows()) &&
(ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH)) && HasItem(RG_LONGSHOT);
}
@@ -2590,7 +2597,7 @@ bool Logic::CouldMQSpirit4KeyWestHand() {
// 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*/ &&
return HasExplosives() /*&& CanClimbHigh()*/ && HasItem(RG_POWER_BRACELET) &&
SmallKeys(SCENE_SPIRIT_TEMPLE, HasItem(RG_LONGSHOT) ? 3 : 5);
}
@@ -2638,6 +2645,11 @@ void Logic::Reset(bool resetSaveContext /*= true*/) {
SetRandoInf(RAND_INF_CAN_CRAWL, true);
}
// If we're not shuffling grab, we start with it
if (ctx->GetOption(RSK_SHUFFLE_GRAB).Is(false)) {
SetRandoInf(RAND_INF_CAN_GRAB, true);
}
// If we're not shuffling open chest, we start with it
if (ctx->GetOption(RSK_SHUFFLE_OPEN_CHEST).Is(false)) {
SetRandoInf(RAND_INF_CAN_OPEN_CHEST, true);
@@ -251,12 +251,14 @@ void Settings::CreateOptionDescriptions() {
"This will require finding the buttons before being able to use them in songs.";
mOptionDescriptions[RSK_SHUFFLE_SWIM] =
"Shuffles the ability to Swim into the item pool.\n"
"The ability to swim has to be found as an item (you can still be underwater if you use iron boots).\n"
"Shuffles the ability to Swim into the item pool as a progressive upgrade before Silver Scale.\n"
"The ability to swim has to be found as an item (you can still be underwater with iron boots).\n"
"\n"
"If you enter a water entrance without swim you will be respawned on land to prevent infinite death loops.\n"
"If you void out in Water Temple you will immediately be kicked out to prevent a softlock.";
mOptionDescriptions[RSK_SHUFFLE_CRAWL] = "Shuffles the ability to use crawlspaces into the item pool.";
mOptionDescriptions[RSK_SHUFFLE_GRAB] =
"Shuffle the ability to grab as a progressive upgrade before Goron Bracelet.";
mOptionDescriptions[RSK_SHUFFLE_OPEN_CHEST] = "Shuffles the ability to open chests into the item pool.";
mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG] = "Shuffles the Weird Egg from Malon in to the item pool. Enabling "
"\"Skip Child Zelda\" disables this feature.\n"
@@ -124,6 +124,7 @@ std::unordered_map<std::string, SceneID> spoilerFileDungeonToScene = {
std::map<RandomizerGet, RandomizerInf> randomizerGetToRandInf = {
{ RG_FISHING_POLE, RAND_INF_FISHING_POLE_FOUND },
{ RG_BRONZE_SCALE, RAND_INF_CAN_SWIM },
{ RG_POWER_BRACELET, RAND_INF_CAN_GRAB },
{ RG_CRAWL, RAND_INF_CAN_CRAWL },
{ RG_OPEN_CHEST, RAND_INF_CAN_OPEN_CHEST },
{ RG_QUIVER_INF, RAND_INF_HAS_INFINITE_QUIVER },
@@ -255,6 +255,7 @@ typedef enum {
LOGIC_GORON_CITY_DARUNIAS_DOOR_OPEN_CHILD,
LOGIC_GORON_CITY_STOP_ROLLING_GORON_AS_ADULT,
LOGIC_DEKU_TREE_1F_BROKE_WEB,
LOGIC_DEKU_TREE_B1_BROKE_WEB,
LOGIC_DEKU_TREE_PUSHED_BASEMENT_BLOCK,
LOGIC_DEKU_TREE_MQ_CLEARED_SE_ROOM,
LOGIC_DEKU_TREE_MQ_WATER_ROOM_TORCHES,
@@ -1411,6 +1412,7 @@ typedef enum {
RR_ICE_CAVERN_MAP_ROOM,
RR_ICE_CAVERN_COMPASS_ROOM,
RR_ICE_CAVERN_BLOCK_ROOM,
RR_ICE_CAVERN_BLOCK_ROOM_BLUE_FIRE,
RR_ICE_CAVERN_BEFORE_FINAL_ROOM,
RR_ICE_CAVERN_FINAL_ROOM,
RR_ICE_CAVERN_FINAL_ROOM_UNDERWATER,
@@ -4118,6 +4120,7 @@ typedef enum {
RT_OPEN_UNDERWATER_CHEST,
RT_DISTANT_BOULDER_COLLISION,
RT_HOOKSHOT_EXTENSION,
RT_SLIDE_JUMP,
RT_KF_ADULT_GS, // -- location tricks
RT_LW_BRIDGE,
RT_LW_MIDO_BACKFLIP,
@@ -4606,6 +4609,7 @@ typedef enum {
RG_TYCOON_WALLET,
RG_BRONZE_SCALE,
RG_CRAWL,
RG_POWER_BRACELET,
RG_OPEN_CHEST,
RG_CHILD_WALLET,
RG_PROGRESSIVE_BOMBCHU_BAG,
@@ -5822,7 +5826,6 @@ typedef enum {
RHT_MASK_ZORA,
RHT_MASK_GERUDO,
RHT_MASK_TRUTH,
RHT_BRONZE_SCALE,
RHT_CRAWL,
RHT_OPEN_CHEST,
RHT_FISHING_POLE,
@@ -6421,6 +6424,7 @@ typedef enum {
RSK_SHUFFLE_OCARINA_BUTTONS,
RSK_SHUFFLE_SWIM,
RSK_SHUFFLE_CRAWL,
RSK_SHUFFLE_GRAB,
RSK_SHUFFLE_OPEN_CHEST,
RSK_STARTING_DEKU_SHIELD,
RSK_STARTING_KOKIRI_SWORD,
@@ -1140,6 +1140,7 @@ DEFINE_RAND_INF(RAND_INF_CAUGHT_LOACH)
DEFINE_RAND_INF(RAND_INF_CAN_SWIM)
DEFINE_RAND_INF(RAND_INF_CAN_CRAWL)
DEFINE_RAND_INF(RAND_INF_CAN_GRAB)
DEFINE_RAND_INF(RAND_INF_CAN_OPEN_CHEST)
DEFINE_RAND_INF(RAND_INF_HAS_WALLET)
@@ -317,6 +317,10 @@ extern "C" void Randomizer_InitSaveFile() {
Flags_SetRandomizerInf(RAND_INF_CAN_CRAWL);
}
if (Randomizer_GetSettingValue(RSK_SHUFFLE_GRAB) == RO_GENERIC_OFF) {
Flags_SetRandomizerInf(RAND_INF_CAN_GRAB);
}
if (Randomizer_GetSettingValue(RSK_SHUFFLE_OPEN_CHEST) == RO_GENERIC_OFF) {
Flags_SetRandomizerInf(RAND_INF_CAN_OPEN_CHEST);
}
+8 -4
View File
@@ -778,6 +778,7 @@ void Settings::CreateOptions() {
});
OPT_BOOL(RSK_SHUFFLE_OCARINA_BUTTONS, "Shuffle Ocarina Buttons", CVAR_RANDOMIZER_SETTING("ShuffleOcarinaButtons"), mOptionDescriptions[RSK_SHUFFLE_OCARINA_BUTTONS]);
OPT_BOOL(RSK_SHUFFLE_SWIM, "Shuffle Swim", CVAR_RANDOMIZER_SETTING("ShuffleSwim"), mOptionDescriptions[RSK_SHUFFLE_SWIM]);
OPT_BOOL(RSK_SHUFFLE_GRAB, "Shuffle Grab", CVAR_RANDOMIZER_SETTING("ShuffleGrab"), mOptionDescriptions[RSK_SHUFFLE_GRAB]);
OPT_BOOL(RSK_SHUFFLE_CRAWL, "Shuffle Crawl", CVAR_RANDOMIZER_SETTING("ShuffleCrawl"), mOptionDescriptions[RSK_SHUFFLE_CRAWL]);
OPT_BOOL(RSK_SHUFFLE_OPEN_CHEST, "Shuffle Open Chest", CVAR_RANDOMIZER_SETTING("ShuffleOpenChest"), mOptionDescriptions[RSK_SHUFFLE_OPEN_CHEST]);
OPT_BOOL(RSK_SHUFFLE_WEIRD_EGG, "Shuffle Weird Egg", CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG]);
@@ -1407,6 +1408,8 @@ void Settings::CreateOptions() {
"Enables ground jumps which require some precision outside of setting up jump:\n- While using Hover "
"Boots in Forest Temple Courtyard to reach upper ledge\n- While using Hover Boots in Shadow Temple "
"invisible spike room to reach door\n- Jumping past second step in Ice Cavern");
OPT_TRICK(RT_SLIDE_JUMP, RCQUEST_BOTH, RA_NONE, { Tricks::Tag::NOVICE }, "Sliding Jumps",
"Running forward while sliding sideways on ice can be used to jump on platforms.");
OPT_TRICK(RT_KF_ADULT_GS, RCQUEST_BOTH, RA_KOKIRI_FOREST, { Tricks::Tag::NOVICE },
"Adult Kokiri Forest GS with Hover Boots",
"Can be obtained without Hookshot by using the Hover Boots off of one of the roots.");
@@ -2060,7 +2063,8 @@ void Settings::CreateOptions() {
OPT_TRICK(RT_SPIRIT_SUN_CHEST, RCQUEST_VANILLA, RA_SPIRIT_TEMPLE, { Tricks::Tag::ADVANCED },
"Spirit Temple Sun Block Room Chest with Bow",
"Using the blocks in the room as platforms you can get lines of sight to all three torches. The timer on "
"the torches is quite short so you must move quickly in order to light all three.");
"the torches is quite short so you must move quickly in order to light all three.\n"
"A backflip can be used instead to light torches without pushing blocks.");
OPT_TRICK(
RT_SPIRIT_WALL, RCQUEST_VANILLA, RA_SPIRIT_TEMPLE, { Tricks::Tag::INTERMEDIATE },
"Spirit Temple Shifting Wall with No Additional Items",
@@ -2093,6 +2097,7 @@ void Settings::CreateOptions() {
OPT_TRICK(RT_ICE_STALAGMITE_HOOKSHOT, RCQUEST_BOTH, RA_ICE_CAVERN, { Tricks::Tag::NOVICE },
"Ice Cavern Stalagmites with Hookshot",
"Shooting stalagmites with hookshot in the right way also breaks them. Also applies to Water Trial.");
// RANDOTO sweep trick descriptions and make sure they match a post-refactor, post shuffles reality
OPT_TRICK(RT_ICE_BLOCK_GS, RCQUEST_VANILLA, RA_ICE_CAVERN, { Tricks::Tag::INTERMEDIATE },
"Ice Cavern Block Room GS with Hover Boots",
"The Hover Boots can be used to get in front of the Skulltula to kill it with a jump slash. Then, the "
@@ -2101,9 +2106,6 @@ void Settings::CreateOptions() {
"Ice Cavern MQ Red Ice GS without Song of Time",
"If you side-hop into the perfect position, you can briefly stand on the platform with the red ice just "
"long enough to dump some blue fire.");
OPT_TRICK(RT_ICE_MQ_SCARECROW, RCQUEST_MQ, RA_ICE_CAVERN, { Tricks::Tag::INTERMEDIATE },
"Ice Cavern MQ Scarecrow GS with No Additional Items",
"As adult a precise jump can be used to reach this alcove.");
OPT_TRICK(RT_LENS_GTG, RCQUEST_VANILLA, RA_GERUDO_TRAINING_GROUND, { Tricks::Tag::NOVICE },
"Gerudo Training Ground without Lens of Truth",
"Removes the requirements for the Lens of Truth in Gerudo Training Ground.");
@@ -2390,6 +2392,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_DEKU_NUT_BAG],
&mOptions[RSK_SHUFFLE_OCARINA_BUTTONS],
&mOptions[RSK_SHUFFLE_SWIM],
&mOptions[RSK_SHUFFLE_GRAB],
&mOptions[RSK_SHUFFLE_CRAWL],
&mOptions[RSK_SHUFFLE_OPEN_CHEST],
&mOptions[RSK_SHUFFLE_BEAN_SOULS],
@@ -2609,6 +2612,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_OCARINA],
&mOptions[RSK_SHUFFLE_OCARINA_BUTTONS],
&mOptions[RSK_SHUFFLE_SWIM],
&mOptions[RSK_SHUFFLE_GRAB],
&mOptions[RSK_SHUFFLE_CRAWL],
&mOptions[RSK_SHUFFLE_OPEN_CHEST],
&mOptions[RSK_SHUFFLE_WEIRD_EGG],
@@ -5578,8 +5578,9 @@ void func_8083A0F4(PlayState* play, Player* this) {
} else if ((interactActorId == ACTOR_EN_ISHI) && ((interactRangeActor->params & 0xF) == 1)) {
Player_SetupAction(play, this, Player_Action_80846260, 0);
anim = &gPlayerAnim_link_silver_carry;
} else if (((interactActorId == ACTOR_EN_BOMBF) || (interactActorId == ACTOR_EN_KUSA)) &&
(Player_GetStrength() <= PLAYER_STR_NONE)) {
} else if (GameInteractor_Should(VB_PREVENT_STRENGTH, ((interactActorId == ACTOR_EN_BOMBF) ||
(interactActorId == ACTOR_EN_KUSA)) &&
(Player_GetStrength() <= PLAYER_STR_NONE))) {
Player_SetupAction(play, this, Player_Action_80846408, 0);
this->actor.world.pos.x =
(Math_SinS(interactRangeActor->yawTowardsPlayer) * 20.0f) + interactRangeActor->world.pos.x;
@@ -13168,7 +13169,7 @@ void Player_Action_8084B78C(Player* this, PlayState* play) {
}
void func_8084B840(PlayState* play, Player* this, f32 arg2) {
if (this->actor.wallBgId != BGCHECK_SCENE) {
if (!GameInteractor_Should(VB_PREVENT_STRENGTH, false) && this->actor.wallBgId != BGCHECK_SCENE) {
DynaPolyActor* dynaPolyActor = DynaPoly_GetActor(&play->colCtx, this->actor.wallBgId);
if (dynaPolyActor != NULL) {