#include "logic.hpp"

#include <algorithm>
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>

#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<uint8_t>(difficulty)) {
        return false;
      }
      return true;

    //Super Stab
    case GlitchType::SuperStab:
      setDifficulty = GetDifficultyValueFromString(GlitchSuperStab);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return CanShield && CanUse(STICKS);

    //Infinite Sword Glitch
    case GlitchType::ISG:
      setDifficulty = GetDifficultyValueFromString(GlitchISG);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return CanShield && (IsAdult || KokiriSword || Sticks);

    //Bomb Hover
    case GlitchType::BombHover:
      setDifficulty = GetDifficultyValueFromString(GlitchHover);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && (HasBombchus || (Bombs && setDifficulty >= static_cast<uint8_t>(GlitchDifficulty::ADVANCED)));

    //Bomb Ocarina Items
    case GlitchType::BombOI:
      setDifficulty = GetDifficultyValueFromString(GlitchBombOI);
      if (setDifficulty < static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(difficulty)) {
        return false;
      }
      return Bombs && CanUse(HOVER_BOOTS) && CanSurviveDamage;

    //Super Slide
    case GlitchType::SuperSlide:
      setDifficulty = GetDifficultyValueFromString(GlitchSuperSlide);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return true;

    //Megaflip
    case GlitchType::Megaflip:
      setDifficulty = GetDifficultyValueFromString(GlitchMegaflip);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      //                             Bombchu megaflips should be considered 2 difficulty levels higher
      return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast<uint8_t>(difficulty) + 2));

    //A-Slide
    case GlitchType::ASlide:
      setDifficulty = GetDifficultyValueFromString(GlitchASlide);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      //                                        Same deal as bombchu megaflips
      return IsChild && CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast<uint8_t>(difficulty) + 2));

    //Hammer Slide
    case GlitchType::HammerSlide:
      setDifficulty = GetDifficultyValueFromString(GlitchHammerSlide);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return CanUse(MEGATON_HAMMER) && CanUse(HOVER_BOOTS) && CanShield;

    //Ledge Cancel
    case GlitchType::LedgeCancel:
      setDifficulty = GetDifficultyValueFromString(GlitchLedgeCancel);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      //                             Similar to bombchu megaflips / A-slides but doesn't scale beyond advanced
      return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast<uint8_t>(GlitchDifficulty::ADVANCED)));

    //Action Swap
    case GlitchType::ActionSwap:
      setDifficulty = GetDifficultyValueFromString(GlitchActionSwap);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return true;

    //Quick Put Away
    case GlitchType::QPA:
      setDifficulty = GetDifficultyValueFromString(GlitchQPA);
      if (setDifficulty < static_cast<uint8_t>(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<uint8_t>(GlitchDifficulty::INTERMEDIATE))) || setDifficulty >= static_cast<uint8_t>(GlitchDifficulty::ADVANCED);

    //Hookshot Clip
    case GlitchType::HookshotClip:
      setDifficulty = GetDifficultyValueFromString(GlitchHookshotClip);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return CanUse(HOOKSHOT);

    //Hookshot Jump: Bonk
    case GlitchType::HookshotJump_Bonk:
      setDifficulty = GetDifficultyValueFromString(GlitchHookshotJump_Bonk);
      if (setDifficulty < static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(difficulty)) {
        return false;
      }
      return true;

    //Navi Dives without TSC
    case GlitchType::NaviDive_Stick:
      setDifficulty = GetDifficultyValueFromString(GlitchNaviDive_Stick);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return IsChild && Sticks;

    //Triple Slash Clip
    case GlitchType::TripleSlashClip:
      setDifficulty = GetDifficultyValueFromString(GlitchTripleSlashClip);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return IsAdult || KokiriSword;

    //Ledge Clip
    case GlitchType::LedgeClip:
      setDifficulty = GetDifficultyValueFromString(GlitchLedgeClip);
      if (setDifficulty < static_cast<uint8_t>(difficulty)) {
        return false;
      }
      return IsAdult;

    //Seam Walks
    case GlitchType::SeamWalk:
      setDifficulty = GetDifficultyValueFromString(GlitchSeamWalk);
      if (setDifficulty < static_cast<uint8_t>(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<uint8_t>())                    ||
                           (Bridge.Is(RAINBOWBRIDGE_MEDALLIONS) && MedallionCount >= BridgeMedallionCount.Value<uint8_t>())            ||
                           (Bridge.Is(RAINBOWBRIDGE_REWARDS)    && StoneCount + MedallionCount >= BridgeRewardCount.Value<uint8_t>())  ||
                           (Bridge.Is(RAINBOWBRIDGE_DUNGEONS)   && DungeonCount >= BridgeDungeonCount.Value<uint8_t>())                ||
                           (Bridge.Is(RAINBOWBRIDGE_TOKENS)     && GoldSkulltulaTokens >= BridgeTokenCount.Value<uint8_t>());

    CanTriggerLACS = (LACSCondition == LACSCONDITION_VANILLA    && ShadowMedallion && SpiritMedallion)                          ||
                     (LACSCondition == LACSCONDITION_STONES     && StoneCount >= LACSStoneCount.Value<uint8_t>())                    ||
                     (LACSCondition == LACSCONDITION_MEDALLIONS && MedallionCount >= LACSMedallionCount.Value<uint8_t>())            ||
                     (LACSCondition == LACSCONDITION_REWARDS    && StoneCount + MedallionCount >= LACSRewardCount.Value<uint8_t>())  ||
                     (LACSCondition == LACSCONDITION_DUNGEONS   && DungeonCount >= LACSDungeonCount.Value<uint8_t>())                ||
                     (LACSCondition == LACSCONDITION_TOKENS     && GoldSkulltulaTokens >= LACSTokenCount.Value<uint8_t>());

  }

  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<uint8_t>(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHoverBoost) >= static_cast<uint8_t>(GlitchDifficulty::NOVICE) ||
                          (GetDifficultyValueFromString(GlitchHover) >= static_cast<uint8_t>(GlitchDifficulty::NOVICE) && GetDifficultyValueFromString(GlitchISG) >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE)))) {
          return ForestTempleKeys >= requiredAmountGlitched;
        }
        return ForestTempleKeys >= requiredAmountGlitchless;

      case FIRE_TEMPLE:
        if (IsGlitched && (GetDifficultyValueFromString(GlitchLedgeClip) >= static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHover) >= static_cast<uint8_t>(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<uint8_t>(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<uint8_t>() + 1;
     Hearts          = 0;
     Multiplier      = (DamageMultiplier.Value<uint8_t>() < 6) ? DamageMultiplier.Value<uint8_t>() : 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;
   }
}
