mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-14 10:37:17 -07:00
reduce logical implications of closed forest (#5626)
* reduce logical implications of closed forest closed forest should only be about kokiri blocking the way, no need to try plug alternate forest escapes out * revert adult deku being unlocked in forest without showing mido sword/shield
This commit is contained in:
parent
96d3b480b1
commit
928bb7767b
9 changed files with 13 additions and 64 deletions
|
@ -1211,15 +1211,6 @@ int EntranceShuffler::ShuffleAllEntrances() {
|
|||
if (ctx->GetOption(RSK_SHUFFLE_BOSS_ENTRANCES).Is(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL)) {
|
||||
entrancePools[EntranceType::Boss] = GetShuffleableEntrances(EntranceType::ChildBoss);
|
||||
AddElementsToPool(entrancePools[EntranceType::Boss], GetShuffleableEntrances(EntranceType::AdultBoss));
|
||||
// If forest is closed, ensure Ghoma is inside the Deku tree
|
||||
// Deku tree being in its vanilla location is handled below
|
||||
if (ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_ON) &&
|
||||
!(ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES))) {
|
||||
FilterAndEraseFromPool(entrancePools[EntranceType::Boss], [](const Entrance* entrance) {
|
||||
return entrance->GetParentRegionKey() == RR_DEKU_TREE_BOSS_ENTRYWAY &&
|
||||
entrance->GetConnectedRegionKey() == RR_DEKU_TREE_BOSS_ROOM;
|
||||
});
|
||||
}
|
||||
if (ctx->GetOption(RSK_DECOUPLED_ENTRANCES)) {
|
||||
for (Entrance* entrance : entrancePools[EntranceType::Boss]) {
|
||||
entrancePools[EntranceType::BossReverse].push_back(entrance->GetReverse());
|
||||
|
@ -1228,14 +1219,6 @@ int EntranceShuffler::ShuffleAllEntrances() {
|
|||
} else {
|
||||
entrancePools[EntranceType::ChildBoss] = GetShuffleableEntrances(EntranceType::ChildBoss);
|
||||
entrancePools[EntranceType::AdultBoss] = GetShuffleableEntrances(EntranceType::AdultBoss);
|
||||
// If forest is closed, ensure Ghoma is inside the Deku tree
|
||||
if (ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_ON) &&
|
||||
!(ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES))) {
|
||||
FilterAndEraseFromPool(entrancePools[EntranceType::ChildBoss], [](const Entrance* entrance) {
|
||||
return entrance->GetParentRegionKey() == RR_DEKU_TREE_BOSS_ENTRYWAY &&
|
||||
entrance->GetConnectedRegionKey() == RR_DEKU_TREE_BOSS_ROOM;
|
||||
});
|
||||
}
|
||||
if (ctx->GetOption(RSK_DECOUPLED_ENTRANCES)) {
|
||||
for (Entrance* entrance : entrancePools[EntranceType::ChildBoss]) {
|
||||
entrancePools[EntranceType::ChildBossReverse].push_back(entrance->GetReverse());
|
||||
|
@ -1255,14 +1238,6 @@ int EntranceShuffler::ShuffleAllEntrances() {
|
|||
AddElementsToPool(entrancePools[EntranceType::Dungeon],
|
||||
GetShuffleableEntrances(EntranceType::GanonDungeon));
|
||||
}
|
||||
// If forest is closed don't allow a forest escape via spirit temple hands
|
||||
if (ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_ON) &&
|
||||
!(ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES))) {
|
||||
FilterAndEraseFromPool(entrancePools[EntranceType::Dungeon], [](const Entrance* entrance) {
|
||||
return entrance->GetParentRegionKey() == RR_KF_OUTSIDE_DEKU_TREE &&
|
||||
entrance->GetConnectedRegionKey() == RR_DEKU_TREE_ENTRYWAY;
|
||||
});
|
||||
}
|
||||
if (ctx->GetOption(RSK_DECOUPLED_ENTRANCES)) {
|
||||
for (Entrance* entrance : entrancePools[EntranceType::Dungeon]) {
|
||||
entrancePools[EntranceType::DungeonReverse].push_back(entrance->GetReverse());
|
||||
|
|
|
@ -808,11 +808,11 @@ void RegionTable_Init() {
|
|||
Entrance(RR_CHILD_SPAWN, []{return logic->IsChild;}),
|
||||
Entrance(RR_ADULT_SPAWN, []{return logic->IsAdult;}),
|
||||
Entrance(RR_MINUET_OF_FOREST_WARP, []{return logic->CanUse(RG_MINUET_OF_FOREST);}),
|
||||
Entrance(RR_BOLERO_OF_FIRE_WARP, []{return logic->CanUse(RG_BOLERO_OF_FIRE) && logic->CanLeaveForest();}),
|
||||
Entrance(RR_SERENADE_OF_WATER_WARP, []{return logic->CanUse(RG_SERENADE_OF_WATER) && logic->CanLeaveForest();}),
|
||||
Entrance(RR_NOCTURNE_OF_SHADOW_WARP, []{return logic->CanUse(RG_NOCTURNE_OF_SHADOW) && logic->CanLeaveForest();}),
|
||||
Entrance(RR_REQUIEM_OF_SPIRIT_WARP, []{return logic->CanUse(RG_REQUIEM_OF_SPIRIT) && logic->CanLeaveForest();}),
|
||||
Entrance(RR_PRELUDE_OF_LIGHT_WARP, []{return logic->CanUse(RG_PRELUDE_OF_LIGHT) && logic->CanLeaveForest();}),
|
||||
Entrance(RR_BOLERO_OF_FIRE_WARP, []{return logic->CanUse(RG_BOLERO_OF_FIRE);}),
|
||||
Entrance(RR_SERENADE_OF_WATER_WARP, []{return logic->CanUse(RG_SERENADE_OF_WATER);}),
|
||||
Entrance(RR_NOCTURNE_OF_SHADOW_WARP, []{return logic->CanUse(RG_NOCTURNE_OF_SHADOW);}),
|
||||
Entrance(RR_REQUIEM_OF_SPIRIT_WARP, []{return logic->CanUse(RG_REQUIEM_OF_SPIRIT);}),
|
||||
Entrance(RR_PRELUDE_OF_LIGHT_WARP, []{return logic->CanUse(RG_PRELUDE_OF_LIGHT);}),
|
||||
});
|
||||
|
||||
areaTable[RR_CHILD_SPAWN] = Region("Child Spawn", SCENE_ID_MAX, TIME_DOESNT_PASS, {RA_LINKS_POCKET}, {}, {}, {
|
||||
|
|
|
@ -63,7 +63,7 @@ void RegionTable_Init_GoronCity() {
|
|||
EventAccess(&logic->GCWoodsWarpOpen, []{return logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE);}),
|
||||
}, {}, {
|
||||
//Exits
|
||||
Entrance(RR_GORON_CITY, []{return logic->CanLeaveForest() && logic->GCWoodsWarpOpen;}),
|
||||
Entrance(RR_GORON_CITY, []{return logic->GCWoodsWarpOpen;}),
|
||||
Entrance(RR_THE_LOST_WOODS, []{return true;}),
|
||||
});
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ void RegionTable_Init_KokiriForest() {
|
|||
}, {
|
||||
//Locations
|
||||
LOCATION(RC_KF_KOKIRI_SWORD_CHEST, logic->IsChild),
|
||||
LOCATION(RC_KF_GS_KNOW_IT_ALL_HOUSE, logic->IsChild && logic->CanAttack() && (/*TODO: HasNightStart ||*/ logic->CanLeaveForest() || logic->CanUse(RG_SUNS_SONG)) && logic->CanGetNightTimeGS()),
|
||||
LOCATION(RC_KF_GS_KNOW_IT_ALL_HOUSE, logic->IsChild && logic->CanAttack() && logic->CanGetNightTimeGS()),
|
||||
LOCATION(RC_KF_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()),
|
||||
LOCATION(RC_KF_GS_HOUSE_OF_TWINS, logic->IsAdult && (logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_KF_ADULT_GS) && logic->CanUse(RG_HOVER_BOOTS))) && logic->CanGetNightTimeGS()),
|
||||
LOCATION(RC_KF_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
|
||||
|
|
|
@ -57,8 +57,8 @@ void RegionTable_Init_LostWoods() {
|
|||
//Exits
|
||||
Entrance(RR_LW_FOREST_EXIT, []{return true;}),
|
||||
Entrance(RR_GC_WOODS_WARP, []{return true;}),
|
||||
Entrance(RR_LW_BRIDGE, []{return logic->CanLeaveForest() && ((logic->IsAdult && (CanPlantBean(RR_THE_LOST_WOODS) || ctx->GetTrickOption(RT_LW_BRIDGE))) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT));}),
|
||||
Entrance(RR_ZR_FROM_SHORTCUT, []{return logic->CanLeaveForest() && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS) || (ctx->GetTrickOption(RT_LOST_WOOD_NAVI_DIVE) && logic->IsChild && logic->HasItem(RG_BRONZE_SCALE) && logic->CanJumpslash()));}),
|
||||
Entrance(RR_LW_BRIDGE, []{return (logic->IsAdult && (CanPlantBean(RR_THE_LOST_WOODS) || ctx->GetTrickOption(RT_LW_BRIDGE))) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT);}),
|
||||
Entrance(RR_ZR_FROM_SHORTCUT, []{return logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS) || (ctx->GetTrickOption(RT_LOST_WOOD_NAVI_DIVE) && logic->IsChild && logic->HasItem(RG_BRONZE_SCALE) && logic->CanJumpslash());}),
|
||||
Entrance(RR_LW_BEYOND_MIDO, []{return logic->IsChild || logic->CanUse(RG_SARIAS_SONG) || ctx->GetTrickOption(RT_LW_MIDO_BACKFLIP);}),
|
||||
Entrance(RR_LW_NEAR_SHORTCUTS_GROTTO, []{return Here(RR_THE_LOST_WOODS, []{return logic->BlastOrSmash();});}),
|
||||
});
|
||||
|
|
|
@ -1177,11 +1177,6 @@ bool Logic::CanStunDeku() {
|
|||
return CanAttack() || CanUse(RG_NUTS) || CanReflectNuts();
|
||||
}
|
||||
|
||||
bool Logic::CanLeaveForest() {
|
||||
return ctx->GetOption(RSK_FOREST).IsNot(RO_CLOSED_FOREST_ON) || IsAdult || DekuTreeClear ||
|
||||
ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES);
|
||||
}
|
||||
|
||||
bool Logic::CallGossipFairyExceptSuns() {
|
||||
return CanUse(RG_ZELDAS_LULLABY) || CanUse(RG_EPONAS_SONG) || CanUse(RG_SONG_OF_TIME);
|
||||
}
|
||||
|
|
|
@ -231,7 +231,6 @@ class Logic {
|
|||
bool CanReflectNuts();
|
||||
bool CanCutShrubs();
|
||||
bool CanStunDeku();
|
||||
bool CanLeaveForest();
|
||||
bool CallGossipFairy();
|
||||
bool CallGossipFairyExceptSuns();
|
||||
uint8_t EffectiveHealth();
|
||||
|
|
|
@ -358,17 +358,6 @@ extern "C" void Randomizer_InitSaveFile() {
|
|||
gSaveContext.sceneFlags[SCENE_WATER_TEMPLE].swch |= (1 << 0x15);
|
||||
}
|
||||
|
||||
// Now handled on the fly.
|
||||
// int openForest = Randomizer_GetSettingValue(RSK_FOREST);
|
||||
// switch (openForest) {
|
||||
// case RO_CLOSED_FOREST_OFF:
|
||||
// Flags_SetEventChkInf(EVENTCHKINF_SHOWED_MIDO_SWORD_SHIELD);
|
||||
// // Fallthrough
|
||||
// case RO_CLOSED_FOREST_DEKU_ONLY:
|
||||
// Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_KOKIRI_EMERALD_DEKU_TREE_DEAD);
|
||||
// break;
|
||||
// }
|
||||
|
||||
int doorOfTime = Randomizer_GetSettingValue(RSK_DOOR_OF_TIME);
|
||||
switch (doorOfTime) {
|
||||
case RO_DOOROFTIME_OPEN:
|
||||
|
|
|
@ -1832,10 +1832,9 @@ void Settings::UpdateOptionProperties() {
|
|||
} else {
|
||||
mOptionGroups[RSG_AREA_ACCESS_IMGUI].Enable();
|
||||
// Starting Age - Disabled when Forest is set to Closed or under very specific conditions
|
||||
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ClosedForest"), RO_CLOSED_FOREST_ON) == RO_CLOSED_FOREST_ON ||
|
||||
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("DoorOfTime"), RO_DOOROFTIME_CLOSED) == RO_DOOROFTIME_CLOSED &&
|
||||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), RO_GENERIC_OFF) ==
|
||||
RO_GENERIC_OFF)) /* closed door of time with ocarina shuffle off */ {
|
||||
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("DoorOfTime"), RO_DOOROFTIME_CLOSED) == RO_DOOROFTIME_CLOSED &&
|
||||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), RO_GENERIC_OFF) ==
|
||||
RO_GENERIC_OFF) /* closed door of time with ocarina shuffle off */ {
|
||||
mOptions[RSK_STARTING_AGE].Disable(
|
||||
"This option is disabled due to other options making the game unbeatable.");
|
||||
} else {
|
||||
|
@ -2532,8 +2531,7 @@ void Context::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocation
|
|||
}
|
||||
|
||||
// With certain access settings, the seed is only beatable if Starting Age is set to Child.
|
||||
if (mOptions[RSK_FOREST].Is(RO_CLOSED_FOREST_ON) ||
|
||||
(mOptions[RSK_DOOR_OF_TIME].Is(RO_DOOROFTIME_CLOSED) && !mOptions[RSK_SHUFFLE_OCARINA])) {
|
||||
if (mOptions[RSK_DOOR_OF_TIME].Is(RO_DOOROFTIME_CLOSED) && !mOptions[RSK_SHUFFLE_OCARINA]) {
|
||||
mOptions[RSK_STARTING_AGE].Set(RO_AGE_CHILD);
|
||||
}
|
||||
|
||||
|
@ -2847,13 +2845,6 @@ void Context::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocation
|
|||
mOptions[RSK_MIX_GROTTO_ENTRANCES].Set(RO_GENERIC_OFF);
|
||||
}
|
||||
|
||||
if (mOptions[RSK_FOREST].Is(RO_CLOSED_FOREST_ON) &&
|
||||
(mOptions[RSK_SHUFFLE_INTERIOR_ENTRANCES].Is(RO_INTERIOR_ENTRANCE_SHUFFLE_ALL) ||
|
||||
mOptions[RSK_SHUFFLE_OVERWORLD_ENTRANCES] || mOptions[RSK_SHUFFLE_OVERWORLD_SPAWNS] ||
|
||||
mOptions[RSK_DECOUPLED_ENTRANCES] || mOptions[RSK_MIXED_ENTRANCE_POOLS])) {
|
||||
mOptions[RSK_FOREST].Set(RO_CLOSED_FOREST_DEKU_ONLY);
|
||||
}
|
||||
|
||||
if (mOptions[RSK_STARTING_AGE].Is(RO_AGE_RANDOM)) {
|
||||
if (const uint32_t choice = Random(0, 2); choice == 0) {
|
||||
mOptions[RSK_SELECTED_STARTING_AGE].Set(RO_AGE_CHILD);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue