Combine HasBossSoul & CanOpenOverworldDoor into HasItem (#6795)

This commit is contained in:
Philip Dubé
2026-06-22 14:35:57 +00:00
committed by GitHub
parent e894b76182
commit c5896c7efc
9 changed files with 42 additions and 92 deletions
@@ -868,7 +868,7 @@ void RegionTable_Init_GanonsCastle() {
areaTable[RR_GANONS_TOWER_GANONDORF_LAIR] = Region("Ganondorf's Lair", SCENE_GANONDORF_BOSS, {}, {
//Locations
LOCATION(RC_GANONDORF_HINT, logic->HasBossSoul(RG_GANON_SOUL)),
LOCATION(RC_GANONDORF_HINT, logic->HasItem(RG_GANON_SOUL)),
}, {
//Exits
ENTRANCE(RR_GANONS_CASTLE_ESCAPE, logic->CanKillEnemy(RE_GANONDORF)),
@@ -45,7 +45,7 @@ void RegionTable_Init_Graveyard() {
ENTRANCE(RR_GRAVEYARD_COMPOSERS_GRAVE, logic->CanUse(RG_ZELDAS_LULLABY)),
ENTRANCE(RR_GRAVEYARD_HEART_PIECE_GRAVE, (logic->IsAdult || logic->AtNight) && logic->HasItem(RG_POWER_BRACELET)),
ENTRANCE(RR_GRAVEYARD_DAMPES_GRAVE, logic->IsAdult && logic->HasItem(RG_POWER_BRACELET)),
ENTRANCE(RR_GRAVEYARD_DAMPES_HOUSE, logic->IsAdult && logic->CanOpenOverworldDoor(RG_DAMPES_HUT_KEY) /*|| logic->AtDampeTime*/), //TODO: This needs to be handled in ToD rework
ENTRANCE(RR_GRAVEYARD_DAMPES_HOUSE, logic->IsAdult && logic->HasItem(RG_DAMPES_HUT_KEY) /*|| logic->AtDampeTime*/), //TODO: This needs to be handled in ToD rework
ENTRANCE(RR_KAKARIKO_VILLAGE, true),
ENTRANCE(RR_GRAVEYARD_WARP_PAD_REGION, false),
});
@@ -75,14 +75,14 @@ void RegionTable_Init_Kakariko() {
}, {
//Exits
ENTRANCE(RR_HYRULE_FIELD, true),
ENTRANCE(RR_KAK_CARPENTER_BOSS_HOUSE, logic->CanOpenOverworldDoor(RG_BOSS_HOUSE_KEY)),
ENTRANCE(RR_KAK_HOUSE_OF_SKULLTULA, logic->CanOpenOverworldDoor(RG_SKULLTULA_HOUSE_KEY)),
ENTRANCE(RR_KAK_IMPAS_HOUSE, logic->CanOpenOverworldDoor(RG_IMPAS_HOUSE_KEY)),
ENTRANCE(RR_KAK_WINDMILL_LOWER, logic->CanOpenOverworldDoor(RG_WINDMILL_KEY)),
ENTRANCE(RR_KAK_BAZAAR, logic->IsAdult && logic->AtDay && logic->CanOpenOverworldDoor(RG_KAK_BAZAAR_KEY)),
ENTRANCE(RR_KAK_SHOOTING_GALLERY, logic->IsAdult && logic->AtDay && logic->CanOpenOverworldDoor(RG_KAK_SHOOTING_GALLERY_KEY)),
ENTRANCE(RR_KAK_CARPENTER_BOSS_HOUSE, logic->HasItem(RG_BOSS_HOUSE_KEY)),
ENTRANCE(RR_KAK_HOUSE_OF_SKULLTULA, logic->HasItem(RG_SKULLTULA_HOUSE_KEY)),
ENTRANCE(RR_KAK_IMPAS_HOUSE, logic->HasItem(RG_IMPAS_HOUSE_KEY)),
ENTRANCE(RR_KAK_WINDMILL_LOWER, logic->HasItem(RG_WINDMILL_KEY)),
ENTRANCE(RR_KAK_BAZAAR, logic->IsAdult && logic->AtDay && logic->HasItem(RG_KAK_BAZAAR_KEY)),
ENTRANCE(RR_KAK_SHOOTING_GALLERY, logic->IsAdult && logic->AtDay && logic->HasItem(RG_KAK_SHOOTING_GALLERY_KEY)),
ENTRANCE(RR_KAK_WELL, 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, (logic->AtDay || logic->IsChild) && logic->CanOpenOverworldDoor(RG_KAK_POTION_SHOP_KEY)),
ENTRANCE(RR_KAK_POTION_SHOP, (logic->AtDay || logic->IsChild) && logic->HasItem(RG_KAK_POTION_SHOP_KEY)),
ENTRANCE(RR_KAK_REDEAD_GROTTO, logic->CanOpenBombGrotto()),
ENTRANCE(RR_KAK_IMPAS_LEDGE, (logic->IsChild && logic->AtDay && logic->HasItem(RG_POWER_BRACELET)) || (logic->IsAdult && ctx->GetTrickOption(RT_VISIBLE_COLLISION))),
ENTRANCE(RR_KAK_WATCHTOWER, logic->HasItem(RG_CLIMB) && (logic->IsAdult || logic->AtDay || logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_LONGSHOT) || (ctx->GetTrickOption(RT_KAK_TOWER_GS) && logic->CanJumpslashExceptHammer()))),
@@ -139,14 +139,14 @@ void RegionTable_Init_Kakariko() {
//Exits
ENTRANCE(RR_KAKARIKO_VILLAGE, true),
ENTRANCE(RR_KAK_OPEN_GROTTO, true),
ENTRANCE(RR_KAK_ODD_POTION_BUILDING, logic->IsAdult && logic->CanOpenOverworldDoor(RG_GRANNYS_POTION_SHOP_KEY)),
ENTRANCE(RR_KAK_ODD_POTION_BUILDING, logic->IsAdult && logic->HasItem(RG_GRANNYS_POTION_SHOP_KEY)),
ENTRANCE(RR_KAK_BEHIND_POTION_SHOP, logic->HasItem(RG_CLIMB)),
});
areaTable[RR_KAK_BEHIND_POTION_SHOP] = Region("Kak Behind Potion Shop", SCENE_KAKARIKO_VILLAGE, {}, {}, {
//Exits
ENTRANCE(RR_KAK_BACKYARD, true),
ENTRANCE(RR_KAK_POTION_SHOP, logic->IsAdult && logic->AtDay && logic->CanOpenOverworldDoor(RG_KAK_POTION_SHOP_KEY)),
ENTRANCE(RR_KAK_POTION_SHOP, logic->IsAdult && logic->AtDay && logic->HasItem(RG_KAK_POTION_SHOP_KEY)),
//can ledgegrab fence to rooftop with hover boots, but that's more difficult than the unintuitive jump, so not including in default logic
ENTRANCE(RR_KAK_ROOFTOP, ctx->GetTrickOption(RT_HOVER_BOOST_SIMPLE) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_MEGATON_HAMMER) && logic->IsAdult),
});
@@ -89,7 +89,7 @@ void RegionTable_Init_LakeHylia() {
ENTRANCE(RR_LH_FROM_SHORTCUT, true),
ENTRANCE(RR_LH_OWL_FLIGHT, logic->IsChild && (logic->HasItem(RG_SPEAK_DEKU) || logic->HasItem(RG_SPEAK_GERUDO) || logic->HasItem(RG_SPEAK_GORON) || logic->HasItem(RG_SPEAK_KOKIRI) || logic->HasItem(RG_SPEAK_HYLIAN) || logic->HasItem(RG_SPEAK_ZORA))),
ENTRANCE(RR_LH_FISHING_ISLAND, ((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, logic->CanOpenOverworldDoor(RG_HYLIA_LAB_KEY)),
ENTRANCE(RR_LH_LAB, logic->HasItem(RG_HYLIA_LAB_KEY)),
ENTRANCE(RR_LH_FROM_WATER_TEMPLE, true),
ENTRANCE(RR_LH_GROTTO, logic->HasItem(RG_POWER_BRACELET) && (logic->IsAdult || logic->HasItem(RG_SPEAK_DEKU) || logic->HasItem(RG_SPEAK_GERUDO) || logic->HasItem(RG_SPEAK_GORON) || logic->HasItem(RG_SPEAK_KOKIRI) || logic->HasItem(RG_SPEAK_HYLIAN) || logic->HasItem(RG_SPEAK_ZORA))),
});
@@ -113,7 +113,7 @@ void RegionTable_Init_LakeHylia() {
}, {
//Exits
ENTRANCE(RR_LAKE_HYLIA, logic->HasItem(RG_BRONZE_SCALE)),
ENTRANCE(RR_LH_FISHING_POND, logic->CanOpenOverworldDoor(RG_FISHING_HOLE_KEY)),
ENTRANCE(RR_LH_FISHING_POND, logic->HasItem(RG_FISHING_HOLE_KEY)),
});
areaTable[RR_LH_OWL_FLIGHT] = Region("LH Owl Flight", SCENE_LAKE_HYLIA, {}, {}, {
@@ -30,9 +30,9 @@ void RegionTable_Init_LonLonRanch() {
}, {
//Exits
ENTRANCE(RR_HYRULE_FIELD, true),
ENTRANCE(RR_LLR_TALONS_HOUSE, logic->CanOpenOverworldDoor(RG_TALONS_HOUSE_KEY)),
ENTRANCE(RR_LLR_STABLES, logic->CanOpenOverworldDoor(RG_STABLES_KEY)),
ENTRANCE(RR_LLR_TOWER, logic->CanOpenOverworldDoor(RG_BACK_TOWER_KEY)),
ENTRANCE(RR_LLR_TALONS_HOUSE, logic->HasItem(RG_TALONS_HOUSE_KEY)),
ENTRANCE(RR_LLR_STABLES, logic->HasItem(RG_STABLES_KEY)),
ENTRANCE(RR_LLR_TOWER, logic->HasItem(RG_BACK_TOWER_KEY)),
ENTRANCE(RR_LLR_GROTTO, logic->IsChild),
});
@@ -9,7 +9,7 @@ void RegionTable_Init_Market() {
//Exits
ENTRANCE(RR_HYRULE_FIELD, logic->IsAdult || logic->AtDay),
ENTRANCE(RR_THE_MARKET, true),
ENTRANCE(RR_MARKET_GUARD_HOUSE, logic->CanOpenOverworldDoor(RG_GUARD_HOUSE_KEY)),
ENTRANCE(RR_MARKET_GUARD_HOUSE, logic->HasItem(RG_GUARD_HOUSE_KEY)),
});
areaTable[RR_THE_MARKET] = Region("Market", SCENE_MARKET_DAY, {}, {
@@ -43,21 +43,21 @@ void RegionTable_Init_Market() {
ENTRANCE(RR_MARKET_ENTRANCE, true),
ENTRANCE(RR_TOT_ENTRANCE, true),
ENTRANCE(RR_CASTLE_GROUNDS, true),
ENTRANCE(RR_MARKET_BAZAAR, logic->IsChild && logic->AtDay && logic->CanOpenOverworldDoor(RG_MARKET_BAZAAR_KEY)),
ENTRANCE(RR_MARKET_MASK_SHOP, logic->IsChild && logic->AtDay && logic->CanOpenOverworldDoor(RG_MASK_SHOP_KEY)),
ENTRANCE(RR_MARKET_SHOOTING_GALLERY, logic->IsChild && logic->AtDay && logic->CanOpenOverworldDoor(RG_MARKET_SHOOTING_GALLERY_KEY)),
ENTRANCE(RR_MARKET_BOMBCHU_BOWLING, logic->IsChild && logic->CanOpenOverworldDoor(RG_BOMBCHU_BOWLING_KEY)),
ENTRANCE(RR_MARKET_TREASURE_CHEST_GAME, logic->IsChild && logic->AtNight && logic->CanOpenOverworldDoor(RG_TREASURE_CHEST_GAME_BUILDING_KEY)),
ENTRANCE(RR_MARKET_POTION_SHOP, logic->IsChild && logic->AtDay && logic->CanOpenOverworldDoor(RG_MARKET_POTION_SHOP_KEY)),
ENTRANCE(RR_MARKET_BAZAAR, logic->IsChild && logic->AtDay && logic->HasItem(RG_MARKET_BAZAAR_KEY)),
ENTRANCE(RR_MARKET_MASK_SHOP, logic->IsChild && logic->AtDay && logic->HasItem(RG_MASK_SHOP_KEY)),
ENTRANCE(RR_MARKET_SHOOTING_GALLERY, logic->IsChild && logic->AtDay && logic->HasItem(RG_MARKET_SHOOTING_GALLERY_KEY)),
ENTRANCE(RR_MARKET_BOMBCHU_BOWLING, logic->IsChild && logic->HasItem(RG_BOMBCHU_BOWLING_KEY)),
ENTRANCE(RR_MARKET_TREASURE_CHEST_GAME, logic->IsChild && logic->AtNight && logic->HasItem(RG_TREASURE_CHEST_GAME_BUILDING_KEY)),
ENTRANCE(RR_MARKET_POTION_SHOP, logic->IsChild && logic->AtDay && logic->HasItem(RG_MARKET_POTION_SHOP_KEY)),
ENTRANCE(RR_MARKET_BACK_ALLEY, logic->IsChild),
});
areaTable[RR_MARKET_BACK_ALLEY] = Region("Market Back Alley", SCENE_BACK_ALLEY_DAY, {}, {}, {
//Exits
ENTRANCE(RR_THE_MARKET, true),
ENTRANCE(RR_MARKET_BOMBCHU_SHOP, logic->AtNight && logic->CanOpenOverworldDoor(RG_BOMBCHU_SHOP_KEY)),
ENTRANCE(RR_MARKET_DOG_LADY_HOUSE, logic->CanOpenOverworldDoor(RG_RICHARDS_HOUSE_KEY)),
ENTRANCE(RR_MARKET_MAN_IN_GREEN_HOUSE, logic->AtNight && logic->CanOpenOverworldDoor(RG_ALLEY_HOUSE_KEY)),
ENTRANCE(RR_MARKET_BOMBCHU_SHOP, logic->AtNight && logic->HasItem(RG_BOMBCHU_SHOP_KEY)),
ENTRANCE(RR_MARKET_DOG_LADY_HOUSE, logic->HasItem(RG_RICHARDS_HOUSE_KEY)),
ENTRANCE(RR_MARKET_MAN_IN_GREEN_HOUSE, logic->AtNight && logic->HasItem(RG_ALLEY_HOUSE_KEY)),
});
areaTable[RR_MARKET_GUARD_HOUSE] = Region("Market Guard House", SCENE_MARKET_GUARD_HOUSE, {
+15 -63
View File
@@ -1,7 +1,6 @@
#include "logic.h"
#include "../debugger/performanceTimer.h"
#include <string>
#include <vector>
#include "soh/OTRGlobals.h"
@@ -12,10 +11,6 @@
#include "randomizer.h"
#include <spdlog/spdlog.h>
#include <ship/utils/StringHelper.h>
#include "soh/resource/type/Scene.h"
#include "soh/resource/type/scenecommand/SetTransitionActorList.h"
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
#include "src/overlays/actors/ovl_Door_Shutter/z_door_shutter.h"
#include "location_access.h"
namespace Rando {
@@ -190,17 +185,9 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RG_LOST_WOODS_BRIDGE_BEAN_SOUL:
case RG_LOST_WOODS_BEAN_SOUL:
case RG_ZORAS_RIVER_BEAN_SOUL:
// Boss Souls
case RG_GOHMA_SOUL:
case RG_KING_DODONGO_SOUL:
case RG_BARINADE_SOUL:
case RG_PHANTOM_GANON_SOUL:
case RG_VOLVAGIA_SOUL:
case RG_MORPHA_SOUL:
case RG_BONGO_BONGO_SOUL:
case RG_TWINROVA_SOUL:
case RG_GANON_SOUL:
case RG_SKELETON_KEY:
case RG_RUTOS_LETTER:
return CheckRandoInf(StaticData::RandoGetToRandInf.at(itemName));
// Overworld Keys
case RG_GUARD_HOUSE_KEY:
case RG_MARKET_BAZAAR_KEY:
@@ -226,8 +213,8 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RG_BACK_TOWER_KEY:
case RG_HYLIA_LAB_KEY:
case RG_FISHING_HOLE_KEY:
case RG_RUTOS_LETTER:
return CheckRandoInf(StaticData::RandoGetToRandInf.at(itemName));
return !ctx->GetOption(RSK_LOCK_OVERWORLD_DOORS) || HasItem(RG_SKELETON_KEY) ||
CheckRandoInf(StaticData::RandoGetToRandInf.at(itemName));
// Boss Keys
case RG_FOREST_TEMPLE_BOSS_KEY:
case RG_FIRE_TEMPLE_BOSS_KEY:
@@ -657,41 +644,6 @@ bool Logic::HasProjectile(HasProjectileAge age) {
(CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG) || CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW)));
}
bool Logic::HasBossSoul(RandomizerGet itemName) {
if (!ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS)) {
return true;
}
switch (itemName) {
case RG_GOHMA_SOUL:
case RG_KING_DODONGO_SOUL:
case RG_BARINADE_SOUL:
case RG_PHANTOM_GANON_SOUL:
case RG_VOLVAGIA_SOUL:
case RG_MORPHA_SOUL:
case RG_BONGO_BONGO_SOUL:
case RG_TWINROVA_SOUL:
return HasItem(itemName);
case RG_GANON_SOUL:
return ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS).Is(RO_BOSS_SOULS_ON_PLUS_GANON) ? HasItem(RG_GANON_SOUL)
: true;
default:
return false;
}
}
// RANDOMISERTODO intergrate into HasItem
bool Logic::CanOpenOverworldDoor(RandomizerGet key) {
if (!ctx->GetOption(RSK_LOCK_OVERWORLD_DOORS)) {
return true;
}
if (HasItem(RG_SKELETON_KEY)) {
return true;
}
return HasItem(key);
}
bool Logic::CanGroundJump(bool hasBombflower) {
return ctx->GetTrickOption(RT_GROUND_JUMP) && CanStandingShield() &&
(CanUse(RG_BOMB_BAG) || (hasBombflower && HasItem(RG_GORONS_BRACELET)));
@@ -1000,33 +952,33 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
// without shenanigans anyway. Bunny makes it free
return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_STICKS) || CanUse(RG_MASTER_SWORD);
case RE_GOHMA:
return HasBossSoul(RG_GOHMA_SOUL) && CanJumpslash() &&
return HasItem(RG_GOHMA_SOUL) && CanJumpslash() &&
(CanUse(RG_NUTS) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || HookshotOrBoomerang());
case RE_KING_DODONGO:
return HasBossSoul(RG_KING_DODONGO_SOUL) && CanJumpslash() &&
return HasItem(RG_KING_DODONGO_SOUL) && CanJumpslash() &&
(CanUse(RG_BOMB_BAG) || HasItem(RG_GORONS_BRACELET) ||
(ctx->GetTrickOption(RT_DC_DODONGO_CHU) && IsAdult && CanUse(RG_BOMBCHU_5)));
case RE_BARINADE:
return HasBossSoul(RG_BARINADE_SOUL) && CanUse(RG_BOOMERANG) &&
return HasItem(RG_BARINADE_SOUL) && CanUse(RG_BOOMERANG) &&
(CanJumpslashExceptHammer() ||
(ctx->GetTrickOption(RT_JABU_BARINADE_POTS) && HasItem(RG_POWER_BRACELET)));
case RE_PHANTOM_GANON:
return HasBossSoul(RG_PHANTOM_GANON_SOUL) && CanUseSword() &&
return HasItem(RG_PHANTOM_GANON_SOUL) && CanUseSword() &&
(CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT));
case RE_VOLVAGIA:
return HasBossSoul(RG_VOLVAGIA_SOUL) && CanUse(RG_MEGATON_HAMMER);
return HasItem(RG_VOLVAGIA_SOUL) && CanUse(RG_MEGATON_HAMMER);
case RE_MORPHA:
return HasBossSoul(RG_MORPHA_SOUL) &&
return HasItem(RG_MORPHA_SOUL) &&
(CanUse(RG_HOOKSHOT) ||
(ctx->GetTrickOption(RT_WATER_MORPHA_WITHOUT_HOOKSHOT) && HasItem(RG_BRONZE_SCALE))) &&
(CanUseSword() || CanUse(RG_MEGATON_HAMMER));
case RE_BONGO_BONGO:
return HasBossSoul(RG_BONGO_BONGO_SOUL) &&
(CanUse(RG_LENS_OF_TRUTH) || ctx->GetTrickOption(RT_LENS_BONGO)) && CanUseSword() &&
return HasItem(RG_BONGO_BONGO_SOUL) && (CanUse(RG_LENS_OF_TRUTH) || ctx->GetTrickOption(RT_LENS_BONGO)) &&
CanUseSword() &&
(CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) ||
ctx->GetTrickOption(RT_SHADOW_BONGO));
case RE_TWINROVA:
return HasBossSoul(RG_TWINROVA_SOUL) && CanUse(RG_MIRROR_SHIELD) &&
return HasItem(RG_TWINROVA_SOUL) && CanUse(RG_MIRROR_SHIELD) &&
(CanUseSword() || CanUse(RG_MEGATON_HAMMER));
case RE_GANONDORF:
// RANDOTODO: Trick to use hammer (no jumpslash) or stick (only jumpslash) instead of a sword to reflect the
@@ -1036,9 +988,9 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
// for killing ganondorf and all of those can reflect the energy ball
// This will not be the case once ammo logic in taken into account as
// sticks are limited and using a bottle might become a requirement in that case
return HasBossSoul(RG_GANON_SOUL) && CanUse(RG_LIGHT_ARROWS) && CanUseSword();
return HasItem(RG_GANON_SOUL) && CanUse(RG_LIGHT_ARROWS) && CanUseSword();
case RE_GANON:
return HasBossSoul(RG_GANON_SOUL) && CanUse(RG_MASTER_SWORD);
return HasItem(RG_GANON_SOUL) && CanUse(RG_MASTER_SWORD);
case RE_DARK_LINK:
// RANDOTODO make a function to track our ammo vs his HP when ammo capacity is taken into account in logic
// all swords can at least trade blows with dark link, and even with 1 damage a slash it works out
-2
View File
@@ -43,8 +43,6 @@ class Logic {
bool HasItem(RandomizerGet itemName);
bool ItemUseAllowed(RandomizerGet itemName);
bool BAllowed();
bool HasBossSoul(RandomizerGet itemName);
bool CanOpenOverworldDoor(RandomizerGet itemName);
bool SmallKeys(SceneID scene, uint8_t requiredAmount);
bool CanGroundJump(bool hasBombflower = false);
bool CanGroundJumpslash(bool hasBombflower = false);