rewrite MQ deku tree logic (#4418)

This commit is contained in:
Pepper0ni 2024-10-16 22:16:58 +01:00 committed by GitHub
parent da79e5e015
commit 43b04a32cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 222 additions and 58 deletions

View File

@ -102,7 +102,7 @@ void StaticData::HintTable_Init_Exclude_Dungeon() {
/*french*/ "Selon moi, une #Skulltula dans une boîte dans l'Arbre Mojo# a #[[1]]#.", {QM_RED, QM_GREEN}));
// /*spanish*/ Según dicen, una #Skulltula bajo una caja# del Árbol Deku otorga #[[1]]#.
hintTextTable[RHT_DEKU_TREE_MQ_GS_COMPASS_ROOM] = HintText(CustomMessage("They say that a #wall of rock protects a spider# within the Deku Tree holding #[[1]]#.",
hintTextTable[RHT_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES] = HintText(CustomMessage("They say that a #wall of rock protects a spider# within the Deku Tree holding #[[1]]#.",
/*german*/ "Man erzählt sich, daß eine #von einer Steinwand geschützte Spinne# innerhalb des Deku-Baums #[[1]]# hielte.",
/*french*/ "Selon moi, une #Skulltula derrière des rochers dans l'Arbre Mojo# a #[[1]]#.", {QM_RED, QM_GREEN}));
// /*spanish*/ Según dicen, una #Skulltula protegida por una pared rocosa# del Árbol Deku otorga #[[1]]#.

View File

@ -11,7 +11,7 @@ void RegionTable_Init_DekuTree() {
areaTable[RR_DEKU_TREE_ENTRYWAY] = Region("Deku Tree Entryway", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DEKU_TREE_LOBBY, {[]{return ctx->GetDungeon(DEKU_TREE)->IsVanilla();}}),
Entrance(RR_DEKU_TREE_MQ_LOBBY, {[]{return ctx->GetDungeon(DEKU_TREE)->IsMQ();}}),
Entrance(RR_DEKU_TREE_MQ_1F, {[]{return ctx->GetDungeon(DEKU_TREE)->IsMQ();}}),
Entrance(RR_KF_OUTSIDE_DEKU_TREE, {[]{return true;}}),
});
@ -155,88 +155,186 @@ void RegionTable_Init_DekuTree() {
| MASTER QUEST DUNGEON |
---------------------------*/
if (ctx->GetDungeon(DEKU_TREE)->IsMQ()) {
areaTable[RR_DEKU_TREE_MQ_LOBBY] = Region("Deku Tree MQ Lobby", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {
areaTable[RR_DEKU_TREE_MQ_1F] = Region("Deku Tree MQ 1F", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanKillEnemy(RE_WITHERED_DEKU_BABA);}}),
EventAccess(&logic->BrokeDeku1FWeb, {[]{return logic->HasFireSource();}}),
}, {}, {
//Exits
Entrance(RR_DEKU_TREE_ENTRYWAY, {[]{return true;}}),
//may need canAvoid logic with enemy shuffle
Entrance(RR_DEKU_TREE_MQ_2F, {[]{return true;}}),
//Swim is not required because you can jump with enough momentum to hit land.
//You even avoid fall damage if you hit the shallow water, though it's obscure knowledge so may be a trick
//if it is, then we need a landing room with (IsAdult || CanUse(RG_BRONZE_SCALE) || TakeDamage() || that trick) to reach basement
Entrance(RR_DEKU_TREE_MQ_BASEMENT, {[]{return logic->BrokeDeku1FWeb;}}),
//is it possible to recoil from here to the ledge with a trick?
});
areaTable[RR_DEKU_TREE_MQ_2F] = Region("Deku Tree MQ 2F", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_MAP_CHEST, true),
LOCATION(RC_DEKU_TREE_MQ_GS_LOBBY, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_1F, {[]{return true;}}),
//Will need canAvoid logic with enemy shuffle
Entrance(RR_DEKU_TREE_MQ_3F, {[]{return true;}}),
Entrance(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_2F, []{return logic->HasFireSource();});}}),
});
areaTable[RR_DEKU_TREE_MQ_3F] = Region("Deku Tree MQ 3F", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}),
EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}),
EventAccess(&logic->BrokeDeku1FWeb, {[]{return true;}}),
}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_MAP_CHEST, true),
LOCATION(RC_DEKU_TREE_MQ_SLINGSHOT_CHEST, logic->CanAttack()),
//Implies CanKillEnemy(RE_GOHMA_LARVA)
LOCATION(RC_DEKU_TREE_MQ_SLINGSHOT_CHEST, logic->CanKillEnemy(RE_DEKU_BABA)),
LOCATION(RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, logic->HasFireSourceWithTorch() || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW))),
LOCATION(RC_DEKU_TREE_MQ_BASEMENT_CHEST, logic->HasFireSourceWithTorch() || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW))),
LOCATION(RC_DEKU_TREE_MQ_GS_LOBBY, logic->CanAttack()),
}, {
//Exits
Entrance(RR_DEKU_TREE_ENTRYWAY, {[]{return true;}}),
Entrance(RR_DEKU_TREE_MQ_COMPASS_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_LOBBY, []{return (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT)) || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}) &&
Here(RR_DEKU_TREE_MQ_LOBBY, []{return logic->HasFireSourceWithTorch() || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return Here(RR_DEKU_TREE_MQ_LOBBY, []{return (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT)) || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}) &&
Here(RR_DEKU_TREE_MQ_LOBBY, []{return logic->HasFireSourceWithTorch();});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return ctx->GetTrickOption(RT_DEKU_B1_SKIP) || Here(RR_DEKU_TREE_MQ_LOBBY, []{return logic->IsAdult;});}}),
Entrance(RR_DEKU_TREE_MQ_2F, {[]{return true;}}),
//Assumes RR_DEKU_TREE_MQ_2F access
Entrance(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_3F, []{return logic->CanUse(RG_STICKS) || logic->CanUse(RG_FAIRY_BOW);});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT, {[]{return true;}}),
});
areaTable[RR_DEKU_TREE_MQ_EYE_TARGET_ROOM] = Region("Deku Tree MQ Eye Target Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_COMPASS_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, []{return logic->CanHitEyeTargets();});}}),
Entrance(RR_DEKU_TREE_MQ_2F, {[]{return true;}}),
});
areaTable[RR_DEKU_TREE_MQ_COMPASS_ROOM] = Region("Deku Tree MQ Compass Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_COMPASS_CHEST, true),
LOCATION(RC_DEKU_TREE_MQ_GS_COMPASS_ROOM, logic->HookshotOrBoomerang() &&
Here(RR_DEKU_TREE_MQ_COMPASS_ROOM, []{return logic->CanUse(RG_BOMBCHU_5) ||
(logic->CanUse(RG_BOMB_BAG) && (logic->CanUse(RG_SONG_OF_TIME) || logic->IsAdult)) ||
(logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER) && (logic->CanUse(RG_SONG_OF_TIME) || ctx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS)));})),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_LOBBY, {[]{return true;}}),
Entrance(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, {[]{return true;}}),
Entrance(RR_DEKU_TREE_MQ_PAST_BOULDER_VINES, {[]{return Here(RR_DEKU_TREE_MQ_COMPASS_ROOM, []{return logic->CanUse(RG_BOMBCHU_5) ||
(logic->CanUse(RG_BOMB_BAG) && (logic->CanUse(RG_SONG_OF_TIME) || logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS))) ||
(logic->CanUse(RG_MEGATON_HAMMER) && (logic->CanUse(RG_SONG_OF_TIME) || ctx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS)));});}}),
});
areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT] = Region("Deku Tree MQ Basement Water Room Front", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[RR_DEKU_TREE_MQ_PAST_BOULDER_VINES] = Region("Deku Tree MQ Past Boulder Vines", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_RANG_OR_HOOKSHOT)),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_COMPASS_ROOM, {[]{return logic->BlastOrSmash();}}),
});
areaTable[RR_DEKU_TREE_MQ_BASEMENT] = Region("Deku Tree MQ Basement", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}),
EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}),
}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_BASEMENT_CHEST, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_1F, {[]{return true;}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->CanHitEyeTargets();});}}),
//includes RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM Access, other fire sources clear directly from there
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->CanHitEyeTargets();}) && logic->ClearedMQDekuSERoom &&
Here(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->CanUse(RG_STICKS);});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return ctx->GetTrickOption(RT_DEKU_B1_SKIP) || logic->PushedDekuBasementBlock || logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS);}}),
});
areaTable[RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM] = Region("Deku Tree MQ Southeast Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {
//Events
//Implies CanKillEnemy(RE_GOHMA_LARVA)
EventAccess(&logic->ClearedMQDekuSERoom, {[]{return logic->CanKillEnemy(RE_MAD_SCRUB);}}),
}, {}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return logic->HasFireSource();}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT, {[]{return logic->ClearedMQDekuSERoom;}}),
});
areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT] = Region("Deku Tree MQ Basement Water Room Front", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {
//Events
//It's possible to get this with bow if you have move while in first person and one-point skips on, noticeably harder and jankier as child, but that's a trick
EventAccess(&logic->MQDekuWaterRoomTorches, {[]{return logic->CanUse(RG_FIRE_ARROWS) || (logic->IsChild && logic->CanUse(RG_STICKS) && logic->CanShield());}}),
}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, true),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && (logic->CanUse(RG_DEKU_SHIELD) || logic->HasItem(RG_HYLIAN_SHIELD))) ||
(logic->IsAdult && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS))));}}),
Entrance(RR_DEKU_TREE_MQ_LOBBY, {[]{return true;}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield()) ||
logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS));}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM, {[]{return true;}}),
});
areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK] = Region("Deku Tree MQ Basement Water Room Back", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK] = Region("Deku Tree MQ Basement Water Room Back", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanKillEnemy(RE_WITHERED_DEKU_BABA);}}),
EventAccess(&logic->MQDekuWaterRoomTorches, {[]{return logic->HasFireSource();}}),
}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, logic->CanUse(RG_SONG_OF_TIME)),
//it blocks the chest while stunned unless you stun it from afar while it's slightly off the ground
LOCATION(RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, logic->CanUse(RG_SONG_OF_TIME) && logic->CanPassEnemy(RE_BIG_SKULLTULA)),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, []{return (logic->IsChild && logic->CanUse(RG_STICKS)) || logic->CanUse(RG_DINS_FIRE) ||
Here(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, []{return logic->IsAdult && logic->CanUse(RG_FIRE_ARROWS);});}) &&
Here(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, []{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) ||
logic->CanUseProjectile() || (logic->CanUse(RG_NUTS) && logic->CanUse(RG_STICKS));});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return true;}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, {[]{return logic->MQDekuWaterRoomTorches && logic->CanPassEnemy(RE_BIG_SKULLTULA, logic->CanUse(RG_SONG_OF_TIME) ? ED_CLOSE : ED_HAMMER_JUMPSLASH);}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield()) ||
logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_BRONZE_SCALE) ||
(logic->CanUse(RG_IRON_BOOTS) && (logic->IsAdult || logic->CanUse(RG_HOOKSHOT)));}}),
});
areaTable[RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM] = Region("Deku Tree MQ Basement Southwest Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
//both imply CanKillEnemy(RE_GOHMA_LARVA)
Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return logic->CanKillEnemy(RE_MAD_SCRUB) && logic->CanKillEnemy(RE_KEESE);});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return logic->CanKillEnemy(RE_MAD_SCRUB) && logic->CanKillEnemy(RE_KEESE);});}}),
});
areaTable[RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM] = Region("Deku Tree MQ Basement Grave Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}),
EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}})
}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_SONG_OF_TIME) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_RANG_OR_HOOKSHOT))),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return logic->IsChild && Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, {[]{return true;}}),
//Using a bow to get past here as adult is a bit precise on standing position but simple, doing as as child requires a side-hop with the bow out to shoot through the torch and may be trick worthy
Entrance(RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}}),
});
areaTable[RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM] = Region("Deku Tree MQ Basement Back Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (logic->CanUse(RG_SONG_OF_TIME) && logic->HookshotOrBoomerang())),
LOCATION(RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, logic->HasFireSourceWithTorch() && logic->HookshotOrBoomerang()),
LOCATION(RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_RANG_OR_HOOKSHOT)),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return logic->IsChild;}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUseProjectile() || (logic->CanUse(RG_NUTS) && (logic->IsChild && logic->CanUse(RG_STICKS)));}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, {[]{return true;}}),
});
areaTable[RR_DEKU_TREE_MQ_BASEMENT_LEDGE] = Region("Deku Tree MQ Basement Ledge", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[RR_DEKU_TREE_MQ_BASEMENT_LEDGE] = Region("Deku Tree MQ Basement Ledge", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->PushedDekuBasementBlock, {[]{return true;}}),
}, {
//Locations
LOCATION(RC_DEKU_TREE_MQ_DEKU_SCRUB, logic->CanStunDeku()),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return logic->IsChild;}}),
Entrance(RR_DEKU_TREE_MQ_LOBBY, {[]{return true;}}),
Entrance(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM,
{ [] { return Here(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, [] { return logic->HasFireSourceWithTorch(); }); } }),
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 Here(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return logic->HasFireSource() || (/*logic->PushedDekuBasementBlock && */logic->CanUse(RG_STICKS));})
&& (logic->CanUse(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}}),
});
areaTable[RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM] =
Region("Deku Tree MQ Outside Boss Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {},
{
// Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{ return true; }}),
Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, {[]{return (logic->HasItem(RG_BRONZE_SCALE) || Here(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return logic->CanUse(RG_IRON_BOOTS);})) && Here(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, [] { return logic->CanReflectNuts(); }); } }),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return logic->CanUse(RG_BRONZE_SCALE);}}),
Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, {[]{return Here(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, []{return logic->CanReflectNuts();});}}),
});
}

View File

@ -187,7 +187,7 @@ Dungeons::Dungeons() {
RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST,
RC_DEKU_TREE_MQ_DEKU_SCRUB,
RC_DEKU_TREE_MQ_GS_LOBBY,
RC_DEKU_TREE_MQ_GS_COMPASS_ROOM,
RC_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES,
RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM,
RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM,
},

View File

@ -649,7 +649,7 @@ void Rando::StaticData::InitLocationTable() { //
locationTable[RC_DEKU_TREE_GS_BASEMENT_VINES] = Location::GSToken(RC_DEKU_TREE_GS_BASEMENT_VINES, RCQUEST_VANILLA, SCENE_DEKU_TREE, 8196, 0x04, "GS Basement Vines", RHT_DEKU_TREE_GS_BASEMENT_VINES);
locationTable[RC_DEKU_TREE_GS_COMPASS_ROOM] = Location::GSToken(RC_DEKU_TREE_GS_COMPASS_ROOM, RCQUEST_VANILLA, SCENE_DEKU_TREE, 8200, 0x08, "GS Compass Room", RHT_DEKU_TREE_GS_COMPASS_ROOM);
locationTable[RC_DEKU_TREE_MQ_GS_LOBBY] = Location::GSToken(RC_DEKU_TREE_MQ_GS_LOBBY, RCQUEST_MQ, SCENE_DEKU_TREE, 8194, 0x02, "MQ GS Lobby", RHT_DEKU_TREE_MQ_GS_LOBBY);
locationTable[RC_DEKU_TREE_MQ_GS_COMPASS_ROOM] = Location::GSToken(RC_DEKU_TREE_MQ_GS_COMPASS_ROOM, RCQUEST_MQ, SCENE_DEKU_TREE, 8200, 0x08, "MQ GS Compass Room", RHT_DEKU_TREE_MQ_GS_COMPASS_ROOM);
locationTable[RC_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES] = Location::GSToken(RC_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES, RCQUEST_MQ, SCENE_DEKU_TREE, 8200, 0x08, "MQ GS Past Boulder Vines", RHT_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES);
locationTable[RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM] = Location::GSToken(RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, RCQUEST_MQ, SCENE_DEKU_TREE, 8196, 0x04, "MQ GS Basement Graves Room", RHT_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM);
locationTable[RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM] = Location::GSToken(RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, RCQUEST_MQ, SCENE_DEKU_TREE, 8193, 0x01, "MQ GS Basement Back Room", RHT_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM);
// Dodongo's Cavern

View File

@ -421,13 +421,35 @@ namespace Rando {
}
bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance) {
bool killed = false;
switch(enemy) {
case RE_GOLD_SKULLTULA:
case RE_GOHMA_LARVA:
case RE_MAD_SCRUB:
case RE_DEKU_BABA:
return CanAttack();
case RE_BIG_SKULLTULA:
return CanDamage() || CanUse(RG_HOOKSHOT);
switch (distance){
case ED_CLOSE:
//hammer jumpslash cannot damage these, but hammer swing can
killed = killed || CanUse(RG_MEGATON_HAMMER);
[[fallthrough]];
case ED_HAMMER_JUMPSLASH:
case ED_MASTER_SWORD_JUMPSLASH:
killed = killed || CanJumpslashExceptHammer();
[[fallthrough]];
case ED_RANG_OR_HOOKSHOT:
//RANDOTODO test dins, bomb and chu range in a practical example, might need a wall var to handle chus
killed = killed || CanUse(RG_HOOKSHOT) || HasExplosives() || CanUse(RG_DINS_FIRE);
[[fallthrough]];
case ED_LONGSHOT:
killed = killed || CanUse(RG_LONGSHOT);
[[fallthrough]];
case ED_FAR:
killed = CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW);
break;
}
return killed;
case RE_DODONGO:
case RE_LIZALFOS:
return CanJumpslash() || HasExplosives() || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW);
@ -435,12 +457,14 @@ namespace Rando {
case RE_FIRE_KEESE:
return CanJumpslash() || HasExplosives() || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG);
case RE_BLUE_BUBBLE:
//RANDOTODO Trick to use shield hylian shield to stun these guys
//RANDOTODO Trick to use shield hylian shield as child to stun these guys
//RANDOTODO check hammer damage
return BlastOrSmash() || CanUse(RG_FAIRY_BOW) || ((CanJumpslashExceptHammer() || CanUse(RG_FAIRY_SLINGSHOT)) && (CanUse(RG_NUTS) || HookshotOrBoomerang() || CanStandingShield()));
case RE_DEAD_HAND:
//RANDOTODO change Dead Hand trick to be sticks Dead Hand
return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || (CanUse(RG_STICKS) && ctx->GetTrickOption(RT_BOTW_CHILD_DEADHAND));
case RE_WITHERED_DEKU_BABA:
return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_BOOMERANG);
default:
SPDLOG_ERROR("CanKillEnemy reached `default`.");
assert(false);
@ -448,8 +472,10 @@ namespace Rando {
}
}
bool Logic::CanPassEnemy(RandomizerEnemy enemy) {
if (CanKillEnemy(enemy)){
//It is rare for Pass Enemy to need distance, this only happens when the enemy blocks a platform and you can't reach it before it blocks you
//an example is the Big Skulltula in water room of MQ deku, which is out of sword swing height but blocks off the whole SoT block
bool Logic::CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance) {
if (CanKillEnemy(enemy, distance)){
return true;
}
switch(enemy) {
@ -462,8 +488,11 @@ namespace Rando {
case RE_FIRE_KEESE:
case RE_BLUE_BUBBLE:
case RE_DEAD_HAND:
case RE_DEKU_BABA:
case RE_WITHERED_DEKU_BABA:
return true;
case RE_BIG_SKULLTULA:
//hammer jumpslash can pass, but only on flat land where you can kill with hammer swing
return CanUse(RG_NUTS) || CanUse(RG_BOOMERANG);
default:
SPDLOG_ERROR("CanPassEnemy reached `default`.");
@ -483,13 +512,15 @@ namespace Rando {
case RE_DODONGO: //RANDOTODO do dodongos block the way in tight corridors?
case RE_BIG_SKULLTULA:
case RE_DEAD_HAND:
case RE_DEKU_BABA:
case RE_WITHERED_DEKU_BABA:
return true;
case RE_MAD_SCRUB:
case RE_KEESE:
case RE_FIRE_KEESE:
return CanUse(RG_NUTS);
case RE_BLUE_BUBBLE:
//RANDOTODO Trick to use shield hylian shield to stun these guys
//RANDOTODO Trick to use shield hylian shield as child to stun these guys
return CanUse(RG_NUTS) || HookshotOrBoomerang() || CanStandingShield();
default:
SPDLOG_ERROR("CanPassEnemy reached `default`.");
@ -644,9 +675,26 @@ namespace Rando {
return CallGossipFairyExceptSuns() || CanUse(RG_SUNS_SONG);
}
//the number returned by this is in half heart hits taken.
//RANDOTODO work in OoT side health instead for greater applicability (16 per heart)
uint8_t Logic::EffectiveHealth(){
/* Multiplier will be:
0 for half daamge
1 for normal damage
2 for double damage
3 for quad damage
4 for 8* damage
5 for 16* damage
10 for OHKO.
This is the number of shifts to apply, not a real multiplier
*/
uint8_t Multiplier = (ctx->GetOption(RSK_DAMAGE_MULTIPLIER).Value<uint8_t>() < 6) ? ctx->GetOption(RSK_DAMAGE_MULTIPLIER).Value<uint8_t>() : 10;
return ((Hearts() << (2 + HasItem(RG_DOUBLE_DEFENSE))) >> Multiplier) + ((Hearts() << (2 + HasItem(RG_DOUBLE_DEFENSE))) % (1 << Multiplier) > 0);
//(Hearts() << (2 + HasItem(RG_DOUBLE_DEFENSE))) is quarter hearts after DD
//>> Multiplier halves on normal and does nothing on half, meaning we're working with half hearts on normal damage
return ((Hearts() << (2 + HasItem(RG_DOUBLE_DEFENSE))) >> Multiplier) +
//As 1 is a quarter heart, (1 << Multiplier) is effectivly half-hearts of unmodified damage
//Adds an extra hit if the damage is not exact lethal
((Hearts() << (2 + HasItem(RG_DOUBLE_DEFENSE))) % (1 << Multiplier) > 0);
}
uint8_t Logic::Hearts(){
@ -1791,6 +1839,10 @@ namespace Rando {
LoweredWaterInsideBotw = false;
OpenedWestRoomMQBotw = false;
OpenedMiddleHoleMQBotw = false;
BrokeDeku1FWeb = false;
ClearedMQDekuSERoom = false;
MQDekuWaterRoomTorches = false;
PushedDekuBasementBlock = false;
StopPerformanceTimer(PT_LOGIC_RESET);
}

View File

@ -136,6 +136,10 @@ class Logic {
bool LoweredWaterInsideBotw = false;
bool OpenedWestRoomMQBotw = false;
bool OpenedMiddleHoleMQBotw = false;
bool BrokeDeku1FWeb = false;
bool ClearedMQDekuSERoom = false;
bool MQDekuWaterRoomTorches = false;
bool PushedDekuBasementBlock = false;
/* --- END OF HELPERS AND LOCATION ACCESS --- */
@ -150,7 +154,7 @@ class Logic {
bool CanDoGlitch(GlitchType glitch);
bool CanEquipSwap(RandomizerGet itemName);
bool CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE);
bool CanPassEnemy(RandomizerEnemy enemy);
bool CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE);
bool CanAvoidEnemy(RandomizerEnemy enemy);
bool CanGetEnemyDrop(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool aboveLink = false);
bool CanBreakMudWalls();

View File

@ -501,10 +501,18 @@ typedef enum {
RR_DEKU_TREE_BASEMENT_UPPER,
RR_DEKU_TREE_OUTSIDE_BOSS_ROOM,
RR_DEKU_TREE_MQ_LOBBY,
RR_DEKU_TREE_MQ_1F,
RR_DEKU_TREE_MQ_2F,
RR_DEKU_TREE_MQ_3F,
RR_DEKU_TREE_MQ_EYE_TARGET_ROOM,
RR_DEKU_TREE_MQ_COMPASS_ROOM,
RR_DEKU_TREE_MQ_PAST_BOULDER_VINES,
RR_DEKU_TREE_MQ_BASEMENT,
RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM,
RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT,
RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK,
RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM,
RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM,
RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM,
RR_DEKU_TREE_MQ_BASEMENT_LEDGE,
RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM,
@ -1207,7 +1215,7 @@ typedef enum {
RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST,
RC_DEKU_TREE_MQ_DEKU_SCRUB,
RC_DEKU_TREE_MQ_GS_LOBBY,
RC_DEKU_TREE_MQ_GS_COMPASS_ROOM,
RC_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES,
RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM,
RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM,
RC_DEKU_TREE_QUEEN_GOHMA_HEART,
@ -2806,7 +2814,7 @@ typedef enum {
RHT_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST,
RHT_DEKU_TREE_MQ_DEKU_SCRUB,
RHT_DEKU_TREE_MQ_GS_LOBBY,
RHT_DEKU_TREE_MQ_GS_COMPASS_ROOM,
RHT_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES,
RHT_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM,
RHT_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM,
RHT_DEKU_TREE_QUEEN_GOHMA_HEART,
@ -4409,6 +4417,8 @@ typedef enum {
RE_MAD_SCRUB,
RE_BLUE_BUBBLE,
RE_DEAD_HAND,
RE_DEKU_BABA,
RE_WITHERED_DEKU_BABA,
} RandomizerEnemy;
typedef enum {