#include "logic.hpp" #include #include #include #include #include #include "settings.hpp" #include "dungeon.hpp" #include "setting_descriptions.hpp" using namespace Settings; namespace Logic { bool noVariable = false; //Child item logic bool KokiriSword = false; bool ZeldasLetter = false; bool WeirdEgg = false; bool HasBottle = false; bool Bombchus = false; bool Bombchus5 = false; bool Bombchus10 = false; bool Bombchus20 = false; bool MagicBean = false; bool MagicBeanPack = false; bool RutosLetter = false; bool Boomerang = false; bool DinsFire = false; bool FaroresWind = false; bool NayrusLove = false; bool LensOfTruth = false; bool ShardOfAgony = false; bool SkullMask = false; bool MaskOfTruth = false; //Adult logic bool Hammer = false; bool IronBoots = false; bool HoverBoots = false; bool MirrorShield = false; bool GoronTunic = false; bool ZoraTunic = false; bool Epona = false; bool BigPoe = false; bool GerudoToken = false; bool FireArrows = false; bool IceArrows = false; bool LightArrows = false; bool MasterSword = false; bool BiggoronSword = false; //Trade Quest bool PocketEgg = false; bool Cojiro = false; bool OddMushroom = false; bool OddPoultice = false; bool PoachersSaw = false; bool BrokenSword = false; bool Prescription = false; bool EyeballFrog = false; bool Eyedrops = false; bool ClaimCheck = false; //Trade Quest Events bool WakeUpAdultTalon = false; bool CojiroAccess = false; bool OddMushroomAccess = false; bool OddPoulticeAccess = false; bool PoachersSawAccess = false; bool BrokenSwordAccess = false; bool PrescriptionAccess = false; bool EyeballFrogAccess = false; bool EyedropsAccess = false; bool DisableTradeRevert = false; //Songs bool ZeldasLullaby = false; bool SariasSong = false; bool SunsSong = false; bool SongOfStorms = false; bool EponasSong = false; bool SongOfTime = false; bool MinuetOfForest = false; bool BoleroOfFire = false; bool SerenadeOfWater = false; bool RequiemOfSpirit = false; bool NocturneOfShadow = false; bool PreludeOfLight = false; //Stones and Meddallions bool ForestMedallion = false; bool FireMedallion = false; bool WaterMedallion = false; bool SpiritMedallion = false; bool ShadowMedallion = false; bool LightMedallion = false; bool KokiriEmerald = false; bool GoronRuby = false; bool ZoraSapphire = false; //Dungeon Clears bool DekuTreeClear = false; bool DodongosCavernClear = false; bool JabuJabusBellyClear = false; bool ForestTempleClear = false; bool FireTempleClear = false; bool WaterTempleClear = false; bool SpiritTempleClear = false; bool ShadowTempleClear = false; //Trial Clears bool ForestTrialClear = false; bool FireTrialClear = false; bool WaterTrialClear = false; bool SpiritTrialClear = false; bool ShadowTrialClear = false; bool LightTrialClear = false; //Progressive Items uint8_t ProgressiveBulletBag = 0; uint8_t ProgressiveBombBag = 0; uint8_t ProgressiveMagic = 0; uint8_t ProgressiveScale = 0; uint8_t ProgressiveHookshot = 0; uint8_t ProgressiveBow = 0; uint8_t ProgressiveWallet = 0; uint8_t ProgressiveStrength = 0; uint8_t ProgressiveOcarina = 0; uint8_t ProgressiveGiantKnife = 0; //Logical keysanity bool IsKeysanity = false; //Keys uint8_t ForestTempleKeys = 0; uint8_t FireTempleKeys = 0; uint8_t WaterTempleKeys = 0; uint8_t SpiritTempleKeys = 0; uint8_t ShadowTempleKeys = 0; uint8_t GanonsCastleKeys = 0; uint8_t GerudoFortressKeys = 0; uint8_t GerudoTrainingGroundsKeys = 0; uint8_t BottomOfTheWellKeys = 0; uint8_t TreasureGameKeys = 0; //Boss Keys bool BossKeyForestTemple = false; bool BossKeyFireTemple = false; bool BossKeyWaterTemple = false; bool BossKeySpiritTemple = false; bool BossKeyShadowTemple = false; bool BossKeyGanonsCastle = false; //Gold Skulltula Count uint8_t GoldSkulltulaTokens = 0; //Bottle Count uint8_t Bottles = 0; uint8_t NumBottles = 0; bool NoBottles = false; //Drops and Bottle Contents Access bool DekuNutDrop = false; bool NutPot = false; bool NutCrate = false; bool DekuBabaNuts = false; bool DekuStickDrop = false; bool StickPot = false; bool DekuBabaSticks = false; bool BugsAccess = false; bool BugShrub = false; bool WanderingBugs = false; bool BugRock = false; bool BlueFireAccess = false; bool FishAccess = false; bool FishGroup = false; bool LoneFish = false; bool FairyAccess = false; bool GossipStoneFairy = false; bool BeanPlantFairy = false; bool ButterflyFairy = false; bool FairyPot = false; bool FreeFairies = false; bool FairyPond = false; bool BombchuDrop = false; bool AmmoCanDrop = false; bool BuyBombchus10 = false; bool BuyBombchus20 = false; bool BuySeed = false; bool BuyArrow = false; bool BuyBomb = false; bool BuyGPotion = false; bool BuyBPotion = false; bool MagicRefill = false; uint8_t PieceOfHeart = 0; uint8_t HeartContainer = 0; bool DoubleDefense = false; /* --- HELPERS, EVENTS, AND LOCATION ACCESS --- */ /* These are used to simplify reading the logic, but need to be updated / every time a base value is updated. */ bool Slingshot = false; bool Ocarina = false; bool OcarinaOfTime = false; bool BombBag = false; bool MagicMeter = false; bool Hookshot = false; bool Longshot = false; bool Bow = false; bool GoronBracelet = false; bool SilverGauntlets = false; bool GoldenGauntlets = false; bool SilverScale = false; bool GoldScale = false; bool AdultsWallet = false; bool ChildScarecrow = false; bool AdultScarecrow = false; bool ScarecrowSong = false; bool Scarecrow = false; bool DistantScarecrow = false; bool Bombs = false; bool DekuShield = false; bool HylianShield = false; bool Nuts = false; bool Sticks = false; bool Bugs = false; bool BlueFire = false; bool Fish = false; bool Fairy = false; bool BottleWithBigPoe = false; bool FoundBombchus = false; bool CanPlayBowling = false; bool HasBombchus = false; bool HasExplosives = false; bool HasBoots = false; bool IsChild = false; bool IsAdult = false; bool IsGlitched = false; bool CanBlastOrSmash = false; bool CanChildAttack = false; bool CanChildDamage = false; bool CanCutShrubs = false; bool CanDive = false; bool CanLeaveForest = false; bool CanPlantBugs = false; bool CanRideEpona = false; bool CanStunDeku = false; bool CanSummonGossipFairy = false; bool CanSummonGossipFairyWithoutSuns = false; bool NeedNayrusLove = false; bool CanSurviveDamage = false; bool CanTakeDamage = false; bool CanTakeDamageTwice = false; //bool CanPlantBean = false; bool CanOpenBombGrotto = false; bool CanOpenStormGrotto = false; bool BigPoeKill = false; bool HookshotOrBoomerang = false; bool CanGetNightTimeGS = false; uint8_t BaseHearts = 0; uint8_t Hearts = 0; uint8_t Multiplier = 0; uint8_t EffectiveHealth = 0; uint8_t FireTimer = 0; uint8_t WaterTimer = 0; bool GuaranteeTradePath = false; bool GuaranteeHint = false; bool HasFireSource = false; bool HasFireSourceWithTorch = false; bool CanFinishGerudoFortress = false; bool HasShield = false; bool CanShield = false; bool CanJumpslash = false; bool CanUseProjectile = false; bool CanUseMagicArrow = false; //Bridge and LACS Requirements uint8_t MedallionCount = 0; uint8_t StoneCount = 0; uint8_t DungeonCount = 0; bool HasAllStones = false; bool HasAllMedallions = false; bool CanBuildRainbowBridge = false; bool CanTriggerLACS = false; //Other bool AtDay = false; bool AtNight = false; uint8_t Age = 0; //Events bool ShowedMidoSwordAndShield = false; bool CarpenterRescue = false; bool GF_GateOpen = false; bool GtG_GateOpen = false; bool DampesWindmillAccess = false; bool DrainWell = false; bool GoronCityChildFire = false; bool GCWoodsWarpOpen = false; bool GCDaruniasDoorOpenChild = false; bool StopGCRollingGoronAsAdult = false; bool WaterTempleLow = false; bool WaterTempleMiddle = false; bool WaterTempleHigh = false; bool KakarikoVillageGateOpen = false; bool KingZoraThawed = false; bool ForestTempleJoelle = false; bool ForestTempleBeth = false; bool ForestTempleJoAndBeth = false; bool ForestTempleAmy = false; bool ForestTempleMeg = false; bool ForestTempleAmyAndMeg = false; bool FireLoopSwitch = false; bool LinksCow = false; bool AtDampeTime = false; bool DeliverLetter = false; bool TimeTravel = false; /* --- END OF HELPERS AND LOCATION ACCESS --- */ //Placement Tracking uint8_t AddedProgressiveBulletBags = 0; uint8_t AddedProgressiveBombBags = 0; uint8_t AddedProgressiveMagics = 0; uint8_t AddedProgressiveScales = 0; uint8_t AddedProgressiveHookshots = 0; uint8_t AddedProgressiveBows = 0; uint8_t AddedProgressiveWallets = 0; uint8_t AddedProgressiveStrengths = 0; uint8_t AddedProgressiveOcarinas = 0; uint8_t TokensInPool = 0; //Event checking past bool DrainWellPast = false; bool DampesWindmillAccessPast = false; bool DekuTreeClearPast = false; bool GoronRubyPast = false; bool ZoraSapphirePast = false; bool ForestTrialClearPast = false; bool FireTrialClearPast = false; bool WaterTrialClearPast = false; bool SpiritTrialClearPast = false; bool ShadowTrialClearPast = false; bool LightTrialClearPast = false; bool BuyDekuShieldPast = false; bool TimeTravelPast = false; bool CanPlay(bool song) { return Ocarina && song; } static bool IsMagicItem(uint32_t item) { return item == DINS_FIRE || item == FARORES_WIND || item == NAYRUS_LOVE || item == LENS_OF_TRUTH; } static bool IsMagicArrow(uint32_t item) { return item == FIRE_ARROWS || item == ICE_ARROWS || item == LIGHT_ARROWS; } bool HasItem(uint32_t itemName) { return (itemName == DINS_FIRE && DinsFire) || (itemName == FARORES_WIND && FaroresWind) || (itemName == NAYRUS_LOVE && NayrusLove) || (itemName == LENS_OF_TRUTH && LensOfTruth) || (itemName == BOW && Bow) || (itemName == MEGATON_HAMMER && Hammer) || (itemName == IRON_BOOTS && IronBoots) || (itemName == HOVER_BOOTS && HoverBoots) || (itemName == HOOKSHOT && Hookshot) || (itemName == LONGSHOT && Longshot) || (itemName == SILVER_GAUNTLETS && SilverGauntlets) || (itemName == GOLDEN_GAUNTLETS && GoldenGauntlets) || (itemName == GORON_TUNIC && GoronTunic) || (itemName == ZORA_TUNIC && ZoraTunic) || (itemName == SCARECROW && Scarecrow) || (itemName == DISTANT_SCARECROW && DistantScarecrow)|| (itemName == HYLIAN_SHIELD && HylianShield) || (itemName == MIRROR_SHIELD && MirrorShield) || (itemName == MASTER_SWORD && MasterSword) || (itemName == BIGGORON_SWORD && BiggoronSword) || (itemName == SLINGSHOT && Slingshot) || (itemName == BOOMERANG && Boomerang) || (itemName == KOKIRI_SWORD && KokiriSword) || (itemName == STICKS && Sticks) || (itemName == DEKU_SHIELD && DekuShield) || (itemName == FIRE_ARROWS && FireArrows) || (itemName == ICE_ARROWS && IceArrows) || (itemName == LIGHT_ARROWS && LightArrows); } //Can the passed in item be used? bool CanUse(uint32_t itemName) { if (!HasItem(itemName)) return false; switch (itemName) { // Adult items case BOW: return IsAdult || BowAsChild; case MEGATON_HAMMER: return IsAdult || HammerAsChild; case IRON_BOOTS: return IsAdult || IronBootsAsChild; case HOVER_BOOTS: return IsAdult || HoverBootsAsChild; case HOOKSHOT: return IsAdult || HookshotAsChild; case LONGSHOT: return IsAdult || HookshotAsChild; case SILVER_GAUNTLETS: return IsAdult; case GOLDEN_GAUNTLETS: return IsAdult; case GORON_TUNIC: return IsAdult || GoronTunicAsChild; case ZORA_TUNIC: return IsAdult || ZoraTunicAsChild; case SCARECROW: return IsAdult || HookshotAsChild; case DISTANT_SCARECROW: return IsAdult || HookshotAsChild; case HYLIAN_SHIELD: return IsAdult; case MIRROR_SHIELD: return IsAdult || MirrorShieldAsChild; case MASTER_SWORD: return IsAdult || MasterSwordAsChild; case BIGGORON_SWORD: return IsAdult || BiggoronSwordAsChild; // Child items case SLINGSHOT: return IsChild || SlingshotAsAdult; case BOOMERANG: return IsChild || BoomerangAsAdult; case KOKIRI_SWORD: return IsChild || KokiriSwordAsAdult; case STICKS: return IsChild || StickAsAdult; case DEKU_SHIELD: return IsChild || DekuShieldAsAdult; // Magic items default: return MagicMeter && (IsMagicItem(itemName) || (IsMagicArrow(itemName) && CanUse(BOW))); } } bool HasProjectile(HasProjectileAge age) { return HasExplosives || (age == HasProjectileAge::Child && (Slingshot || Boomerang)) || (age == HasProjectileAge::Adult && (Hookshot || Bow )) || (age == HasProjectileAge::Both && (Slingshot || Boomerang) && (Hookshot || Bow)) || (age == HasProjectileAge::Either && (Slingshot || Boomerang || Hookshot || Bow)); } uint8_t GetDifficultyValueFromString(Option& glitchOption) { for (size_t i = 0; i < GlitchDifficulties.size(); i++) { if (glitchOption.GetSelectedOptionText() == GlitchDifficulties[i]) { return i + 1; } } return 0; } bool CanDoGlitch(GlitchType glitch, GlitchDifficulty difficulty) { uint8_t setDifficulty; switch (glitch) { //Restricted Items case GlitchType::RestrictedItems: setDifficulty = GetDifficultyValueFromString(GlitchRestrictedItems); if (setDifficulty < static_cast(difficulty)) { return false; } return true; //Super Stab case GlitchType::SuperStab: setDifficulty = GetDifficultyValueFromString(GlitchSuperStab); if (setDifficulty < static_cast(difficulty)) { return false; } return CanShield && CanUse(STICKS); //Infinite Sword Glitch case GlitchType::ISG: setDifficulty = GetDifficultyValueFromString(GlitchISG); if (setDifficulty < static_cast(difficulty)) { return false; } return CanShield && (IsAdult || KokiriSword || Sticks); //Bomb Hover case GlitchType::BombHover: setDifficulty = GetDifficultyValueFromString(GlitchHover); if (setDifficulty < static_cast(difficulty)) { return false; } return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && (HasBombchus || (Bombs && setDifficulty >= static_cast(GlitchDifficulty::ADVANCED))); //Bomb Ocarina Items case GlitchType::BombOI: setDifficulty = GetDifficultyValueFromString(GlitchBombOI); if (setDifficulty < static_cast(difficulty)) { return false; } return Bombs && CanSurviveDamage; case GlitchType::OutdoorBombOI: return ((CanUse(FARORES_WIND) && (DinsFire || NayrusLove || LensOfTruth || HasBottle || HasBombchus || Nuts || StartingConsumables || (IsChild && (Sticks || ProgressiveBulletBag || (MagicBean || MagicBeanPack) || Boomerang || WeirdEgg || (Hammer && HammerAsChild))) || (IsAdult && (ProgressiveBow || Hookshot || HasBoots || Hammer || (Sticks && StickAsAdult) || (Boomerang && BoomerangAsAdult)))) && CanDoGlitch(GlitchType::BombOI, (static_cast(difficulty) >= 3) ? difficulty : GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)) || (((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || (CanUse(FARORES_WIND) && FaroresWindAnywhere)) && CanDoGlitch(GlitchType::BombOI, difficulty))); case GlitchType::WindmillBombOI: return (((CanUse(FARORES_WIND) || (!NeedNayrusLove && (NayrusLove || DinsFire))) && (LensOfTruth || HasBottle || HasBombchus || Nuts || StartingConsumables || (IsChild && (Sticks || ProgressiveBulletBag || (MagicBean || MagicBeanPack) || Boomerang || WeirdEgg || (Hammer && HammerAsChild))) || (IsAdult && (ProgressiveBow || Hookshot || HasBoots || Hammer || (Sticks && StickAsAdult) || (Boomerang && BoomerangAsAdult)))) && CanDoGlitch(GlitchType::BombOI, (static_cast(difficulty) >= 3) ? difficulty : GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)) || (((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (CanUse(FARORES_WIND) && FaroresWindAnywhere)) && CanDoGlitch(GlitchType::BombOI, difficulty))); case GlitchType::IndoorBombOI: return (((IsAdult && ClaimCheck) && (HasBottle || HasBoots || (CanUse(FARORES_WIND) && FaroresWindAnywhere))) || ((Bugs || Fish || Fairy) && (NumBottles >= 2 || (IsAdult && (ClaimCheck || HasBoots)) || (IsChild && WeirdEgg) || (CanUse(FARORES_WIND) && FaroresWindAnywhere))) || ((CanUse(FARORES_WIND) && FaroresWindAnywhere) && (HasBottle || (IsAdult && (ClaimCheck || HasBoots)) || (IsChild && WeirdEgg))) || (((!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || CanUse(FARORES_WIND)) && (NumBottles + ((IsChild) ? ((WeirdEgg) ? 1 : 0) : (((IronBoots) ? 1 : 0) + ((HoverBoots) ? 1 : 0) + ((ClaimCheck) ? 1 : 0))) >= 2))) && CanDoGlitch(GlitchType::BombOI, difficulty) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE); case GlitchType::DungeonBombOI: return ((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || (CanUse(FARORES_WIND))) && CanDoGlitch(GlitchType::BombOI, difficulty); //Hover Boost case GlitchType::HoverBoost: setDifficulty = GetDifficultyValueFromString(GlitchHoverBoost); if (setDifficulty < static_cast(difficulty)) { return false; } return Bombs && CanUse(HOVER_BOOTS) && CanSurviveDamage; //Super Slide case GlitchType::SuperSlide: setDifficulty = GetDifficultyValueFromString(GlitchSuperSlide); if (setDifficulty < static_cast(difficulty)) { return false; } return true; //Megaflip case GlitchType::Megaflip: setDifficulty = GetDifficultyValueFromString(GlitchMegaflip); if (setDifficulty < static_cast(difficulty)) { return false; } // Bombchu megaflips should be considered 2 difficulty levels higher return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast(difficulty) + 2)); //A-Slide case GlitchType::ASlide: setDifficulty = GetDifficultyValueFromString(GlitchASlide); if (setDifficulty < static_cast(difficulty)) { return false; } // Same deal as bombchu megaflips return IsChild && CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast(difficulty) + 2)); //Hammer Slide case GlitchType::HammerSlide: setDifficulty = GetDifficultyValueFromString(GlitchHammerSlide); if (setDifficulty < static_cast(difficulty)) { return false; } return CanUse(MEGATON_HAMMER) && CanUse(HOVER_BOOTS) && CanShield; //Ledge Cancel case GlitchType::LedgeCancel: setDifficulty = GetDifficultyValueFromString(GlitchLedgeCancel); if (setDifficulty < static_cast(difficulty)) { return false; } // Similar to bombchu megaflips / A-slides but doesn't scale beyond advanced return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast(GlitchDifficulty::ADVANCED))); //Action Swap case GlitchType::ActionSwap: setDifficulty = GetDifficultyValueFromString(GlitchActionSwap); if (setDifficulty < static_cast(difficulty)) { return false; } return true; //Quick Put Away case GlitchType::QPA: setDifficulty = GetDifficultyValueFromString(GlitchQPA); if (setDifficulty < static_cast(difficulty)) { return false; } // Boot Put Away Delay Method Frame Perfect Method Ledge Grab Method return (CanTakeDamage && Bombs && ((CanUse(HOVER_BOOTS) || CanUse(IRON_BOOTS)) || setDifficulty >= static_cast(GlitchDifficulty::INTERMEDIATE))) || setDifficulty >= static_cast(GlitchDifficulty::ADVANCED); //Hookshot Clip case GlitchType::HookshotClip: setDifficulty = GetDifficultyValueFromString(GlitchHookshotClip); if (setDifficulty < static_cast(difficulty)) { return false; } return CanUse(HOOKSHOT); //Hookshot Jump: Bonk case GlitchType::HookshotJump_Bonk: setDifficulty = GetDifficultyValueFromString(GlitchHookshotJump_Bonk); if (setDifficulty < static_cast(difficulty)) { return false; } return IsAdult && Hookshot; // Child hookshot jumps are tiny so these stay as adult only until I check //Hookshot Jump: Boots case GlitchType::HookshotJump_Boots: setDifficulty = GetDifficultyValueFromString(GlitchHookshotJump_Boots); if (setDifficulty < static_cast(difficulty)) { return false; } return IsAdult && Hookshot && HasBoots; // Child hookshot jumps are tiny so these stay as adult only until I check //Cutscene Dives case GlitchType::CutsceneDive: setDifficulty = GetDifficultyValueFromString(GlitchCutsceneDive); if (setDifficulty < static_cast(difficulty)) { return false; } return true; //Navi Dives without TSC case GlitchType::NaviDive_Stick: setDifficulty = GetDifficultyValueFromString(GlitchNaviDive_Stick); if (setDifficulty < static_cast(difficulty)) { return false; } return IsChild && Sticks; //Triple Slash Clip case GlitchType::TripleSlashClip: setDifficulty = GetDifficultyValueFromString(GlitchTripleSlashClip); if (setDifficulty < static_cast(difficulty)) { return false; } return IsAdult || KokiriSword; //Ledge Clip case GlitchType::LedgeClip: setDifficulty = GetDifficultyValueFromString(GlitchLedgeClip); if (setDifficulty < static_cast(difficulty)) { return false; } return IsAdult; //Seam Walks case GlitchType::SeamWalk: setDifficulty = GetDifficultyValueFromString(GlitchSeamWalk); if (setDifficulty < static_cast(difficulty)) { return false; } return true; } //Shouldn't be reached return false; } //Updates all logic helpers. Should be called whenever a non-helper is changed void UpdateHelpers() { NumBottles = ((NoBottles) ? 0 : (Bottles + ((DeliverLetter) ? 1 : 0))); HasBottle = NumBottles >= 1; Slingshot = (ProgressiveBulletBag >= 1) && (BuySeed || AmmoCanDrop); Ocarina = ProgressiveOcarina >= 1; OcarinaOfTime = ProgressiveOcarina >= 2; MagicMeter = (ProgressiveMagic >= 1) && (AmmoCanDrop || (HasBottle && (BuyGPotion || BuyBPotion))); BombBag = (ProgressiveBombBag >= 1) && (BuyBomb || AmmoCanDrop); Hookshot = ProgressiveHookshot >= 1; Longshot = ProgressiveHookshot >= 2; Bow = (ProgressiveBow >= 1) && (BuyArrow || AmmoCanDrop); GoronBracelet = ProgressiveStrength >= 1; SilverGauntlets = ProgressiveStrength >= 2; GoldenGauntlets = ProgressiveStrength >= 3; SilverScale = ProgressiveScale >= 1; GoldScale = ProgressiveScale >= 2; AdultsWallet = ProgressiveWallet >= 1; MasterSword = MasterSword || IsAdult; BiggoronSword = BiggoronSword || ProgressiveGiantKnife >= 2; ScarecrowSong = ScarecrowSong || FreeScarecrow || (ChildScarecrow && AdultScarecrow); Scarecrow = Hookshot && CanPlay(ScarecrowSong); DistantScarecrow = Longshot && CanPlay(ScarecrowSong); //Drop Access DekuStickDrop = StickPot || DekuBabaSticks; DekuNutDrop = (NutPot || NutCrate || DekuBabaNuts) && AmmoCanDrop; BugsAccess = BugShrub || WanderingBugs || BugRock; FishAccess = LoneFish || FishGroup; FairyAccess = FairyPot || GossipStoneFairy || BeanPlantFairy || ButterflyFairy || FreeFairies || FairyPond; //refills Bombs = BombBag; Nuts = DekuNutDrop || Nuts; Sticks = DekuStickDrop || Sticks; Bugs = HasBottle && BugsAccess; BlueFire = (HasBottle && BlueFireAccess) || (BlueFireArrows && CanUse(ICE_ARROWS)); Fish = HasBottle && FishAccess; Fairy = HasBottle && FairyAccess; FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20); CanPlayBowling = (BombchusInLogic && FoundBombchus) || (!BombchusInLogic && BombBag); HasBombchus = (BuyBombchus10 || BuyBombchus20 || (AmmoDrops.Is(AMMODROPS_BOMBCHU) && FoundBombchus)); HasExplosives = Bombs || (BombchusInLogic && HasBombchus); HasBoots = IronBoots || HoverBoots; //Unshuffled adult trade quest Eyedrops = Eyedrops || (!ShuffleAdultTradeQuest && ClaimCheck); EyeballFrog = EyeballFrog || (!ShuffleAdultTradeQuest && Eyedrops); Prescription = Prescription || (!ShuffleAdultTradeQuest && EyeballFrog); BrokenSword = BrokenSword || (!ShuffleAdultTradeQuest && Prescription); PoachersSaw = PoachersSaw || (!ShuffleAdultTradeQuest && BrokenSword); OddPoultice = OddPoultice || (!ShuffleAdultTradeQuest && PoachersSaw); OddMushroom = OddMushroom || (!ShuffleAdultTradeQuest && OddPoultice); Cojiro = Cojiro || (!ShuffleAdultTradeQuest && OddMushroom); PocketEgg = PocketEgg || (!ShuffleAdultTradeQuest && Cojiro); // IsChild = Age == AGE_CHILD; // IsAdult = Age == AGE_ADULT; CanBlastOrSmash = HasExplosives || CanUse(MEGATON_HAMMER); CanChildAttack = IsChild && (Slingshot || Boomerang || Sticks || KokiriSword || HasExplosives || CanUse(DINS_FIRE) || CanUse(MASTER_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(BIGGORON_SWORD)); CanChildDamage = IsChild && (Slingshot || Sticks || KokiriSword || HasExplosives || CanUse(DINS_FIRE) || CanUse(MASTER_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(BIGGORON_SWORD)); CanStunDeku = IsAdult || CanChildAttack || Nuts || HasShield; CanCutShrubs = IsAdult /*|| Sticks*/ || KokiriSword || Boomerang || HasExplosives || CanUse(MASTER_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(BIGGORON_SWORD); CanDive = ProgressiveScale >= 1; CanLeaveForest = OpenForest.IsNot(OPENFOREST_CLOSED) || IsAdult || DekuTreeClear || ShuffleInteriorEntrances || ShuffleOverworldEntrances; CanPlantBugs = IsChild && Bugs; CanRideEpona = IsAdult && Epona && CanPlay(EponasSong); CanSummonGossipFairy = Ocarina && (ZeldasLullaby || EponasSong || SongOfTime || SunsSong); CanSummonGossipFairyWithoutSuns = Ocarina && (ZeldasLullaby || EponasSong || SongOfTime); Hearts = BaseHearts + HeartContainer + (PieceOfHeart >> 2); EffectiveHealth = ((Hearts << (2 + DoubleDefense)) >> Multiplier) + ((Hearts << (2 + DoubleDefense)) % (1 << Multiplier) > 0); //Number of half heart hits to die, ranges from 1 to 160 FireTimer = CanUse(GORON_TUNIC) ? 255 : (LogicFewerTunicRequirements) ? (Hearts * 8) : 0; WaterTimer = CanUse( ZORA_TUNIC) ? 255 : (LogicFewerTunicRequirements) ? (Hearts * 8) : 0; NeedNayrusLove = (EffectiveHealth == 1); CanSurviveDamage = !NeedNayrusLove || CanUse(NAYRUS_LOVE); CanTakeDamage = Fairy || CanSurviveDamage; CanTakeDamageTwice = (Fairy && NumBottles >= 2) || ((EffectiveHealth == 2) && (CanUse(NAYRUS_LOVE) || Fairy)) || (EffectiveHealth > 2); //CanPlantBean = IsChild && (MagicBean || MagicBeanPack); CanOpenBombGrotto = CanBlastOrSmash && (ShardOfAgony || LogicGrottosWithoutAgony); CanOpenStormGrotto = CanPlay(SongOfStorms) && (ShardOfAgony || LogicGrottosWithoutAgony); HookshotOrBoomerang = CanUse(HOOKSHOT) || CanUse(BOOMERANG); CanGetNightTimeGS = (CanPlay(SunsSong) || !NightGSExpectSuns); GuaranteeTradePath = ShuffleInteriorEntrances || ShuffleOverworldEntrances || LogicBiggoronBolero || CanBlastOrSmash || StopGCRollingGoronAsAdult; //GuaranteeHint = (hints == "Mask" && MaskofTruth) || (hints == "Agony") || (hints != "Mask" && hints != "Agony"); HasFireSource = CanUse(DINS_FIRE) || CanUse(FIRE_ARROWS); HasFireSourceWithTorch = HasFireSource || CanUse(STICKS); //Gerudo Fortress CanFinishGerudoFortress = (GerudoFortress.Is(GERUDOFORTRESS_NORMAL) && GerudoFortressKeys >= 4 && (IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen)) || (GerudoFortress.Is(GERUDOFORTRESS_FAST) && GerudoFortressKeys >= 1 && (IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))) || (GerudoFortress.IsNot(GERUDOFORTRESS_NORMAL) && GerudoFortress.IsNot(GERUDOFORTRESS_FAST)); HasShield = CanUse(HYLIAN_SHIELD) || CanUse(DEKU_SHIELD); //Mirror shield can't reflect attacks CanShield = CanUse(MIRROR_SHIELD) || HasShield; CanJumpslash = IsAdult || Sticks || KokiriSword; CanUseProjectile = HasExplosives || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(SLINGSHOT) || CanUse(BOOMERANG); CanUseMagicArrow = CanUse(FIRE_ARROWS) || CanUse(ICE_ARROWS) || CanUse(LIGHT_ARROWS); //Bridge and LACS Requirements MedallionCount = (ForestMedallion ? 1:0) + (FireMedallion ? 1:0) + (WaterMedallion ? 1:0) + (SpiritMedallion ? 1:0) + (ShadowMedallion ? 1:0) + (LightMedallion ? 1:0); StoneCount = (KokiriEmerald ? 1:0) + (GoronRuby ? 1:0) + (ZoraSapphire ? 1:0); DungeonCount = (DekuTreeClear ? 1:0) + (DodongosCavernClear ? 1:0) + (JabuJabusBellyClear ? 1:0) + (ForestTempleClear ? 1:0) + (FireTempleClear ? 1:0) + (WaterTempleClear ? 1:0) + (SpiritTempleClear ? 1:0) + (ShadowTempleClear ? 1:0); HasAllStones = StoneCount == 3; HasAllMedallions = MedallionCount == 6; CanBuildRainbowBridge = Bridge.Is(RAINBOWBRIDGE_OPEN) || (Bridge.Is(RAINBOWBRIDGE_VANILLA) && ShadowMedallion && SpiritMedallion && LightArrows) || (Bridge.Is(RAINBOWBRIDGE_STONES) && StoneCount >= BridgeStoneCount.Value()) || (Bridge.Is(RAINBOWBRIDGE_MEDALLIONS) && MedallionCount >= BridgeMedallionCount.Value()) || (Bridge.Is(RAINBOWBRIDGE_REWARDS) && StoneCount + MedallionCount >= BridgeRewardCount.Value()) || (Bridge.Is(RAINBOWBRIDGE_DUNGEONS) && DungeonCount >= BridgeDungeonCount.Value()) || (Bridge.Is(RAINBOWBRIDGE_TOKENS) && GoldSkulltulaTokens >= BridgeTokenCount.Value()); CanTriggerLACS = (LACSCondition == LACSCONDITION_VANILLA && ShadowMedallion && SpiritMedallion) || (LACSCondition == LACSCONDITION_STONES && StoneCount >= LACSStoneCount.Value()) || (LACSCondition == LACSCONDITION_MEDALLIONS && MedallionCount >= LACSMedallionCount.Value()) || (LACSCondition == LACSCONDITION_REWARDS && StoneCount + MedallionCount >= LACSRewardCount.Value()) || (LACSCondition == LACSCONDITION_DUNGEONS && DungeonCount >= LACSDungeonCount.Value()) || (LACSCondition == LACSCONDITION_TOKENS && GoldSkulltulaTokens >= LACSTokenCount.Value()); } bool SmallKeys(Key dungeon, uint8_t requiredAmount) { return SmallKeys(dungeon, requiredAmount, requiredAmount); } bool SmallKeys(Key dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched) { switch (dungeon) { case FOREST_TEMPLE: if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotJump_Boots) >= static_cast(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHoverBoost) >= static_cast(GlitchDifficulty::NOVICE) || (GetDifficultyValueFromString(GlitchHover) >= static_cast(GlitchDifficulty::NOVICE) && GetDifficultyValueFromString(GlitchISG) >= static_cast(GlitchDifficulty::INTERMEDIATE)))) { return ForestTempleKeys >= requiredAmountGlitched; } return ForestTempleKeys >= requiredAmountGlitchless; case FIRE_TEMPLE: if (IsGlitched && (GetDifficultyValueFromString(GlitchLedgeClip) >= static_cast(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHover) >= static_cast(GlitchDifficulty::INTERMEDIATE))) { return FireTempleKeys >= requiredAmountGlitched; } return FireTempleKeys >= requiredAmountGlitchless; case WATER_TEMPLE: if (IsGlitched && (false)) { return WaterTempleKeys >= requiredAmountGlitched; } return WaterTempleKeys >= requiredAmountGlitchless; case SPIRIT_TEMPLE: if (IsGlitched && (false)) { return SpiritTempleKeys >= requiredAmountGlitched; } return SpiritTempleKeys >= requiredAmountGlitchless; case SHADOW_TEMPLE: if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotClip) >= static_cast(GlitchDifficulty::NOVICE))) { return ShadowTempleKeys >= requiredAmountGlitched; } return ShadowTempleKeys >= requiredAmountGlitchless; case BOTTOM_OF_THE_WELL: if (IsGlitched && (false)) { return BottomOfTheWellKeys >= requiredAmountGlitched; } return BottomOfTheWellKeys >= requiredAmountGlitchless; case GERUDO_TRAINING_GROUNDS: if (IsGlitched && (false)) { return GerudoTrainingGroundsKeys >= requiredAmountGlitched; } return GerudoTrainingGroundsKeys >= requiredAmountGlitchless; case GANONS_CASTLE: if (IsGlitched && (false)) { return GanonsCastleKeys >= requiredAmountGlitched; } return GanonsCastleKeys >= requiredAmountGlitchless; case MARKET_TREASURE_CHEST_GAME: if (IsGlitched && (false)) { return TreasureGameKeys >= requiredAmountGlitched; } return TreasureGameKeys >= requiredAmountGlitchless; default: return false; } } bool EventsUpdated() { if (DekuTreeClearPast != DekuTreeClear || GoronRubyPast != GoronRuby || ZoraSapphirePast != ZoraSapphire || ForestTrialClearPast != ForestTrialClear || FireTrialClearPast != FireTrialClear || WaterTrialClearPast != WaterTrialClear || ShadowTrialClearPast != ShadowTrialClear || SpiritTrialClearPast != SpiritTrialClear || LightTrialClearPast != LightTrialClear || DrainWellPast != DrainWell || DampesWindmillAccessPast != DampesWindmillAccess || TimeTravelPast != TimeTravel) { DekuTreeClearPast = DekuTreeClear; GoronRubyPast = GoronRuby; ZoraSapphirePast = ZoraSapphire; ForestTrialClearPast = ForestTrialClear; FireTrialClearPast = FireTrialClear; WaterTrialClearPast = WaterTrialClear; ShadowTrialClearPast = ShadowTrialClear; SpiritTrialClearPast = SpiritTrialClear; LightTrialClearPast = LightTrialClear; DrainWellPast = DrainWell; DampesWindmillAccessPast = DampesWindmillAccess; return true; } return false; } //Reset All Logic to false void LogicReset() { //Settings-dependent variables IsKeysanity = Keysanity.Is(KEYSANITY_ANYWHERE) || Keysanity.Is(KEYSANITY_OVERWORLD) || Keysanity.Is(KEYSANITY_ANY_DUNGEON); AmmoCanDrop = AmmoDrops.IsNot(AMMODROPS_NONE); //Child item logic KokiriSword = false; ZeldasLetter = false; WeirdEgg = false; HasBottle = false; Bombchus = false; Bombchus5 = false; Bombchus10 = false; Bombchus20 = false; MagicBean = false; MagicBeanPack = false; RutosLetter = false; Boomerang = false; DinsFire = false; FaroresWind = false; NayrusLove = false; LensOfTruth = false; ShardOfAgony = false; SkullMask = false; MaskOfTruth = false; //Adult logic Hammer = false; IronBoots = false; HoverBoots = false; MirrorShield = false; GoronTunic = false; ZoraTunic = false; Epona = false; BigPoe = false; GerudoToken = false; FireArrows = false; IceArrows = false; LightArrows = false; MasterSword = false; BiggoronSword = false; //Trade Quest PocketEgg = false; Cojiro = false; OddMushroom = false; OddPoultice = false; PoachersSaw = false; BrokenSword = false; Prescription = false; EyeballFrog = false; Eyedrops = false; ClaimCheck = false; //Trade Quest Events WakeUpAdultTalon = false; CojiroAccess = false; OddMushroomAccess = false; OddPoulticeAccess = false; PoachersSawAccess = false; BrokenSwordAccess = false; PrescriptionAccess = false; EyeballFrogAccess = false; EyedropsAccess = false; DisableTradeRevert = false; //Songs ZeldasLullaby = false; SariasSong = false; SunsSong = false; SongOfStorms = false; EponasSong = false; SongOfTime = false; MinuetOfForest = false; BoleroOfFire = false; SerenadeOfWater = false; RequiemOfSpirit = false; NocturneOfShadow = false; PreludeOfLight = false; //Stones and Meddallions ForestMedallion = false; FireMedallion = false; WaterMedallion = false; SpiritMedallion = false; ShadowMedallion = false; LightMedallion = false; KokiriEmerald = false; GoronRuby = false; ZoraSapphire = false; //Dungeon Clears DekuTreeClear = false; DodongosCavernClear = false; JabuJabusBellyClear = false; ForestTempleClear = false; FireTempleClear = false; WaterTempleClear = false; SpiritTempleClear = false; ShadowTempleClear = false; //Trial Clears ForestTrialClear = false; FireTrialClear = false; WaterTrialClear = false; SpiritTrialClear = false; ShadowTrialClear = false; LightTrialClear = false; //Progressive Items ProgressiveBulletBag = 0; ProgressiveBombBag = 0; ProgressiveMagic = 0; ProgressiveScale = 0; ProgressiveHookshot = 0; ProgressiveBow = 0; ProgressiveWallet = 0; ProgressiveStrength = 0; ProgressiveOcarina = 0; ProgressiveGiantKnife = 0; //Keys ForestTempleKeys = 0; //If not keysanity, start with 1 logical key to account for automatically unlocking the basement door in vanilla FiT FireTempleKeys = IsKeysanity || Dungeon::FireTemple.IsMQ() ? 0 : 1; WaterTempleKeys = 0; SpiritTempleKeys = 0; ShadowTempleKeys = 0; GanonsCastleKeys = 0; GerudoFortressKeys = 0; GerudoTrainingGroundsKeys = 0; BottomOfTheWellKeys = 0; TreasureGameKeys = 0; //Boss Keys BossKeyForestTemple = 0; BossKeyFireTemple = 0; BossKeyWaterTemple = 0; BossKeySpiritTemple = 0; BossKeyShadowTemple = 0; BossKeyGanonsCastle = 0; //Gold Skulltula Count GoldSkulltulaTokens = 0; //Bottle Count Bottles = 0; NumBottles = 0; NoBottles = false; //Drops and Bottle Contents Access DekuNutDrop = false; NutPot = false; NutCrate = false; DekuBabaNuts = false; DekuStickDrop = false; StickPot = false; DekuBabaSticks = false; BugsAccess = false; BugShrub = false; WanderingBugs = false; BugRock = false; BlueFireAccess = false; FishAccess = false; FishGroup = false; LoneFish = false; FairyAccess = false; GossipStoneFairy = false; BeanPlantFairy = false; ButterflyFairy = false; FairyPot = false; FreeFairies = false; FairyPond = false; BombchuDrop = false; BuyBombchus10 = false; BuyBombchus20 = false; BuySeed = false; BuyArrow = false; BuyBomb = false; BuyGPotion = false; BuyBPotion = false; MagicRefill = false; PieceOfHeart = 0; HeartContainer = 0; DoubleDefense = false; /* --- HELPERS, EVENTS, AND LOCATION ACCESS --- */ /* These are used to simplify reading the logic, but need to be updated / every time a base value is updated. */ Slingshot = false; Ocarina = false; OcarinaOfTime = false; BombBag = false; MagicMeter = false; Hookshot = false; Longshot = false; Bow = false; GoronBracelet = false; SilverGauntlets = false; GoldenGauntlets = false; SilverScale = false; GoldScale = false; AdultsWallet = false; ChildScarecrow = false; AdultScarecrow = false; ScarecrowSong = false; Scarecrow = false; DistantScarecrow = false; Bombs = false; DekuShield = false; HylianShield = false; Nuts = false; Sticks = false; Bugs = false; BlueFire = false; Fish = false; Fairy = false; BottleWithBigPoe = false; FoundBombchus = false; CanPlayBowling = false; HasBombchus = false; HasExplosives = false; HasBoots = false; IsChild = false; IsAdult = false; IsGlitched = Settings::Logic.Is(LOGIC_GLITCHED); CanBlastOrSmash = false; CanChildAttack = false; CanChildDamage = false; CanCutShrubs = false; CanDive = false; CanLeaveForest = false; CanPlantBugs = false; CanRideEpona = false; CanStunDeku = false; CanSummonGossipFairy = false; CanSummonGossipFairyWithoutSuns = false; //CanPlantBean = false; CanOpenBombGrotto = false; CanOpenStormGrotto = false; BigPoeKill = false; HookshotOrBoomerang = false; BaseHearts = StartingHearts.Value() + 1; Hearts = 0; Multiplier = (DamageMultiplier.Value() < 6) ? DamageMultiplier.Value() : 10; EffectiveHealth = 0; FireTimer = 0; WaterTimer = 0; GuaranteeTradePath = false; GuaranteeHint = false; HasFireSource = false; HasFireSourceWithTorch = false; CanFinishGerudoFortress = false; HasShield = false; CanShield = false; CanJumpslash = false; CanUseProjectile = false; CanUseMagicArrow = false; //Bridge Requirements HasAllStones = false; HasAllMedallions = false; CanBuildRainbowBridge = false; CanTriggerLACS = false; //Other AtDay = false; AtNight = false; Age = Settings::ResolvedStartingAge; //Events ShowedMidoSwordAndShield = false; CarpenterRescue = false; GF_GateOpen = false; GtG_GateOpen = false; DampesWindmillAccess = false; DrainWell = false; GoronCityChildFire = false; GCWoodsWarpOpen = false; GCDaruniasDoorOpenChild = false; StopGCRollingGoronAsAdult = false; WaterTempleLow = false; WaterTempleMiddle = false; WaterTempleHigh = false; KakarikoVillageGateOpen = false; KingZoraThawed = false; ForestTempleJoelle = false; ForestTempleBeth = false; ForestTempleJoAndBeth = false; ForestTempleAmy = false; ForestTempleMeg = false; ForestTempleAmyAndMeg = false; FireLoopSwitch = false; LinksCow = false; AtDampeTime = false; DeliverLetter = false; TimeTravel = false; DrainWellPast = false; DampesWindmillAccessPast = false; DekuTreeClearPast = false; GoronRubyPast = false; ZoraSapphirePast = false; ForestTrialClearPast = false; FireTrialClearPast = false; WaterTrialClearPast = false; SpiritTrialClearPast = false; ShadowTrialClearPast = false; LightTrialClearPast = false; BuyDekuShieldPast = false; TimeTravelPast = false; } }