From 684d86a17e023de32d3893610b86893ff1a8e05d Mon Sep 17 00:00:00 2001 From: Michael <44533763+iTNTPiston@users.noreply.github.com> Date: Sat, 16 Jul 2022 18:29:46 -0700 Subject: [PATCH] Item Infra Update and Durability System (#2) * (broken) finished new item system, working on fixing logic in Slots * new item infrastructure, accurate durability transfer * Delete build directory * style issues --- .github/workflows/main_deploy.yml | 2 +- .github/workflows/main_push.yml | 4 +- .gitignore | 2 + Justfile | 14 +- config/webpack.config.js | 9 + package-lock.json | 389 +++++- package.json | 17 +- .../assets/img/Armor/AmberEarrings.png | Bin .../assets/img/Armor/AncientCuirass.png | Bin .../assets/img/Armor/AncientGreaves.png | Bin .../assets/img/Armor/AncientHelm.png | Bin .../assets/img/Armor/BarbarianArmor.png | Bin .../assets/img/Armor/BarbarianHelm.png | Bin .../assets/img/Armor/BarbarianLegWraps.png | Bin .../assets/img/Armor/BokoblinMask.png | Bin .../assets/img/Armor/CapOfTheHero.png | Bin .../assets/img/Armor/CapOfTheSky.png | Bin .../assets/img/Armor/CapOfTheWild.png | Bin .../assets/img/Armor/CapOfTheWind.png | Bin .../assets/img/Armor/CapOfTime.png | Bin .../assets/img/Armor/CapOfTwilight.png | Bin .../assets/img/Armor/ChampionsTunic.png | Bin .../assets/img/Armor/ClimbersBandanna.png | Bin .../assets/img/Armor/ClimbingBoots.png | Bin .../assets/img/Armor/ClimbingGear.png | Bin {src => public}/assets/img/Armor/DarkHood.png | Bin .../assets/img/Armor/DarkTrousers.png | Bin .../assets/img/Armor/DarkTunic.png | Bin .../assets/img/Armor/DesertVoeHeadband.png | Bin .../assets/img/Armor/DesertVoeSpaulder.png | Bin .../assets/img/Armor/DesertVoeTrousers.png | Bin .../assets/img/Armor/DiamondCirclet.png | Bin .../assets/img/Armor/FierceDeityArmor.png | Bin .../assets/img/Armor/FierceDeityBoots.png | Bin .../assets/img/Armor/FierceDeityMask.png | Bin .../assets/img/Armor/FlamebreakerArmor.png | Bin .../assets/img/Armor/FlamebreakerBoots.png | Bin .../assets/img/Armor/FlamebreakerHelm.png | Bin .../assets/img/Armor/GerudoSirwal.png | Bin .../assets/img/Armor/GerudoTop.png | Bin .../assets/img/Armor/GerudoVeil.png | Bin .../assets/img/Armor/HylianHood.png | Bin .../assets/img/Armor/HylianTrousers.png | Bin .../assets/img/Armor/HylianTunic.png | Bin .../assets/img/Armor/IslandLobsterShirt.png | Bin .../assets/img/Armor/KorokMask.png | Bin .../assets/img/Armor/LizalfosMask.png | Bin .../assets/img/Armor/LynelMask.png | Bin .../assets/img/Armor/MajorasMask.png | Bin .../assets/img/Armor/MidnasHelmet.png | Bin .../assets/img/Armor/MoblinMask.png | Bin .../assets/img/Armor/NintendoSwitchShirt.png | Bin {src => public}/assets/img/Armor/OldShirt.png | Bin .../assets/img/Armor/OpalEarrings.png | Bin .../assets/img/Armor/PhantomArmor.png | Bin .../assets/img/Armor/PhantomGanonArmor.png | Bin .../assets/img/Armor/PhantomGanonGreaves.png | Bin .../assets/img/Armor/PhantomGanonSkull.png | Bin .../assets/img/Armor/PhantomGreaves.png | Bin .../assets/img/Armor/PhantomHelmet.png | Bin .../assets/img/Armor/RadiantMask.png | Bin .../assets/img/Armor/RadiantShirt.png | Bin .../assets/img/Armor/RadiantTights.png | Bin .../assets/img/Armor/RaviosHood.png | Bin .../assets/img/Armor/RoyalGuardBoots.png | Bin .../assets/img/Armor/RoyalGuardCap.png | Bin .../assets/img/Armor/RoyalGuardUniform.png | Bin .../assets/img/Armor/RubberArmor.png | Bin .../assets/img/Armor/RubberHelm.png | Bin .../assets/img/Armor/RubberTights.png | Bin .../assets/img/Armor/RubyCirclet.png | Bin .../assets/img/Armor/SalvagerHeadwear.png | Bin .../assets/img/Armor/SalvagerTrousers.png | Bin .../assets/img/Armor/SalvagerVest.png | Bin .../assets/img/Armor/SandBoots.png | Bin .../assets/img/Armor/SapphireCirclet.png | Bin .../assets/img/Armor/SheiksMask.png | Bin .../assets/img/Armor/SnowBoots.png | Bin .../assets/img/Armor/SnowquillHeaddress.png | Bin .../assets/img/Armor/SnowquillTrousers.png | Bin .../assets/img/Armor/SnowquillTunic.png | Bin .../assets/img/Armor/SoldiersArmor.png | Bin .../assets/img/Armor/SoldiersGreaves.png | Bin .../assets/img/Armor/SoldiersHelm.png | Bin .../assets/img/Armor/StealthChestGuard.png | Bin .../assets/img/Armor/StealthMask.png | Bin .../assets/img/Armor/StealthTights.png | Bin .../assets/img/Armor/ThunderHelm.png | Bin .../assets/img/Armor/TinglesHood.png | Bin .../assets/img/Armor/TinglesShirt.png | Bin .../assets/img/Armor/TinglesTights.png | Bin .../assets/img/Armor/TopazEarrings.png | Bin .../assets/img/Armor/TrousersOfTheHero.png | Bin .../assets/img/Armor/TrousersOfTheSky.png | Bin .../assets/img/Armor/TrousersOfTheWild.png | Bin .../assets/img/Armor/TrousersOfTheWind.png | Bin .../assets/img/Armor/TrousersOfTime.png | Bin .../assets/img/Armor/TrousersOfTwilight.png | Bin .../assets/img/Armor/TunicOfTheHero.png | Bin .../assets/img/Armor/TunicOfTheSky.png | Bin .../assets/img/Armor/TunicOfTheWild.png | Bin .../assets/img/Armor/TunicOfTheWind.png | Bin .../assets/img/Armor/TunicOfTime.png | Bin .../assets/img/Armor/TunicOfTwilight.png | Bin .../assets/img/Armor/VahMedohDivineHelm.png | Bin .../assets/img/Armor/VahNaborisDivineHelm.png | Bin .../assets/img/Armor/VahRudaniaDivineHelm.png | Bin .../assets/img/Armor/VahRutaDivineHelm.png | Bin .../assets/img/Armor/WarmDoublet.png | Bin .../assets/img/Armor/WellWornTrousers.png | Bin .../assets/img/Armor/ZantsHelmet.png | Bin .../assets/img/Armor/ZoraArmor.png | Bin .../assets/img/Armor/ZoraGreaves.png | Bin {src => public}/assets/img/Armor/ZoraHelm.png | Bin .../assets/img/Arrow/AncientArrow.png | Bin .../assets/img/Arrow/BombArrow.png | Bin .../assets/img/Arrow/FireArrow.png | Bin {src => public}/assets/img/Arrow/IceArrow.png | Bin .../assets/img/Arrow/NormalArrow.png | Bin .../assets/img/Arrow/ShockArrow.png | Bin {src => public}/assets/img/Bow/AncientBow.png | Bin {src => public}/assets/img/Bow/BokoBow.png | Bin public/assets/img/Bow/Bow.png | Bin 0 -> 21108 bytes {src => public}/assets/img/Bow/BowOfLight.png | Bin .../assets/img/Bow/DragonBoneBokoBow.png | Bin {src => public}/assets/img/Bow/DuplexBow.png | Bin {src => public}/assets/img/Bow/FalconBow.png | Bin .../assets/img/Bow/ForestDwellersBow.png | Bin {src => public}/assets/img/Bow/GoldenBow.png | Bin .../assets/img/Bow/GreatEagleBow.png | Bin {src => public}/assets/img/Bow/KnightsBow.png | Bin {src => public}/assets/img/Bow/LizalBow.png | Bin {src => public}/assets/img/Bow/LynelBow.png | Bin .../assets/img/Bow/MightyLynelBow.png | Bin {src => public}/assets/img/Bow/PhrenicBow.png | Bin {src => public}/assets/img/Bow/RoyalBow.png | Bin .../assets/img/Bow/RoyalGuardsBow.png | Bin .../assets/img/Bow/SavageLynelBow.png | Bin {src => public}/assets/img/Bow/SilverBow.png | Bin .../assets/img/Bow/SoldiersBow.png | Bin .../assets/img/Bow/SpikedBokoBow.png | Bin .../assets/img/Bow/SteelLizalBow.png | Bin .../assets/img/Bow/StrengthenedLizalBow.png | Bin {src => public}/assets/img/Bow/SwallowBow.png | Bin .../assets/img/Bow/TravelersBow.png | Bin .../assets/img/Bow/TwilightBow.png | Bin {src => public}/assets/img/Bow/WoodenBow.png | Bin {src => public}/assets/img/Food/ApplePie.png | Bin .../assets/img/Food/BakedApple.png | Bin .../assets/img/Food/BakedFortifiedPumpkin.png | Bin .../assets/img/Food/BakedPalmFruit.png | Bin .../assets/img/Food/BlackenedCrab.png | Bin .../assets/img/Food/BlueshellEscargot.png | Bin .../assets/img/Food/CampfireEgg.png | Bin .../assets/img/Food/CarrotCake.png | Bin .../assets/img/Food/CarrotStew.png | Bin .../assets/img/Food/CharredPepper.png | Bin .../assets/img/Food/ChillyElixir.png | Bin .../assets/img/Food/ClamChowder.png | Bin .../img/Food/CopiousFriedWildGreens.png | Bin .../assets/img/Food/CopiousMeatSkewers.png | Bin .../img/Food/CopiousMushroomSkewers.png | Bin .../assets/img/Food/CopiousSeafoodSkewers.png | Bin .../assets/img/Food/CopiousSimmeredFruit.png | Bin .../assets/img/Food/CrabOmeletWithRice.png | Bin .../assets/img/Food/CrabRisotto.png | Bin .../assets/img/Food/CrabStirFry.png | Bin .../assets/img/Food/CreamOfMushroomSoup.png | Bin .../assets/img/Food/CreamOfVegetableSoup.png | Bin .../assets/img/Food/CreamyHeartSoup.png | Bin .../assets/img/Food/CreamyMeatSoup.png | Bin .../assets/img/Food/CreamySeafoodSoup.png | Bin .../assets/img/Food/CurryPilaf.png | Bin {src => public}/assets/img/Food/CurryRice.png | Bin .../assets/img/Food/DubiousFood.png | Bin .../assets/img/Food/EggPudding.png | Bin {src => public}/assets/img/Food/EggTart.png | Bin .../assets/img/Food/ElectroElixir.png | Bin {src => public}/assets/img/Food/Elixir.png | Bin .../assets/img/Food/EnduringElixir.png | Bin .../assets/img/Food/EnergizingElixir.png | Bin .../assets/img/Food/FairyTonic.png | Bin .../assets/img/Food/FireproofElixir.png | Bin .../assets/img/Food/FishAndMushroomSkewer.png | Bin {src => public}/assets/img/Food/FishPie.png | Bin .../assets/img/Food/FishSkewer.png | Bin .../assets/img/Food/FragrantMushroomSaute.png | Bin .../assets/img/Food/FriedBananas.png | Bin .../assets/img/Food/FriedEggAndRice.png | Bin .../assets/img/Food/FriedWildGreens.png | Bin .../assets/img/Food/FrozenBass.png | Bin .../assets/img/Food/FrozenBirdDrumstick.png | Bin .../assets/img/Food/FrozenBirdThigh.png | Bin .../assets/img/Food/FrozenCarp.png | Bin .../assets/img/Food/FrozenCrab.png | Bin .../assets/img/Food/FrozenHeartyBass.png | Bin .../assets/img/Food/FrozenHeartySalmon.png | Bin .../assets/img/Food/FrozenPorgy.png | Bin .../assets/img/Food/FrozenRiverSnail.png | Bin .../assets/img/Food/FrozenTrout.png | Bin .../assets/img/Food/FrozenWholeBird.png | Bin .../assets/img/Food/FruitAndMushroomMix.png | Bin {src => public}/assets/img/Food/FruitPie.png | Bin {src => public}/assets/img/Food/Fruitcake.png | Bin .../assets/img/Food/GlazedMeat.png | Bin .../assets/img/Food/GlazedMushrooms.png | Bin .../assets/img/Food/GlazedSeafood.png | Bin .../assets/img/Food/GlazedVeggies.png | Bin .../img/Food/GourmetMeatAndRiceBowl.png | Bin .../img/Food/GourmetMeatAndSeafoodFry.png | Bin .../assets/img/Food/GourmetMeatCurry.png | Bin .../assets/img/Food/GourmetMeatStew.png | Bin .../assets/img/Food/GourmetPoultryCurry.png | Bin .../assets/img/Food/GourmetPoultryPilaf.png | Bin .../img/Food/GourmetSpicedMeatSkewer.png | Bin .../assets/img/Food/HardBoiledEgg.png | Bin .../assets/img/Food/HastyElixir.png | Bin .../assets/img/Food/HeartyElixir.png | Bin {src => public}/assets/img/Food/HerbSaute.png | Bin .../assets/img/Food/HoneyCandy.png | Bin .../assets/img/Food/HoneyCrepe.png | Bin .../assets/img/Food/HoneyedApple.png | Bin .../assets/img/Food/HoneyedFruits.png | Bin .../assets/img/Food/HotButteredApple.png | Bin .../assets/img/Food/IcyGourmetMeat.png | Bin .../img/Food/IcyHeartyBlueshellSnail.png | Bin {src => public}/assets/img/Food/IcyMeat.png | Bin .../assets/img/Food/IcyPrimeMeat.png | Bin .../assets/img/Food/MeatAndMushroomSkewer.png | Bin .../assets/img/Food/MeatAndRiceBowl.png | Bin .../assets/img/Food/MeatAndSeafoodFry.png | Bin {src => public}/assets/img/Food/MeatCurry.png | Bin {src => public}/assets/img/Food/MeatPie.png | Bin .../assets/img/Food/MeatSkewer.png | Bin {src => public}/assets/img/Food/MeatStew.png | Bin .../assets/img/Food/MeatStuffedPumpkin.png | Bin .../assets/img/Food/MeatyRiceBalls.png | Bin .../assets/img/Food/MightyElixir.png | Bin .../assets/img/Food/MonsterCake.png | Bin .../assets/img/Food/MonsterCurry.png | Bin .../assets/img/Food/MonsterRiceBalls.png | Bin .../assets/img/Food/MonsterSoup.png | Bin .../assets/img/Food/MonsterStew.png | Bin .../assets/img/Food/MushroomOmelet.png | Bin .../assets/img/Food/MushroomRiceBalls.png | Bin .../assets/img/Food/MushroomRisotto.png | Bin .../assets/img/Food/MushroomSkewer.png | Bin {src => public}/assets/img/Food/Nutcake.png | Bin {src => public}/assets/img/Food/Omelet.png | Bin .../assets/img/Food/PepperSeafood.png | Bin .../assets/img/Food/PepperSteak.png | Bin .../assets/img/Food/PlainCrepe.png | Bin .../assets/img/Food/PorgyMeuniere.png | Bin .../assets/img/Food/PoultryCurry.png | Bin .../assets/img/Food/PoultryPilaf.png | Bin .../assets/img/Food/PrimeMeatAndRiceBowl.png | Bin .../img/Food/PrimeMeatAndSeafoodFry.png | Bin .../assets/img/Food/PrimeMeatCurry.png | Bin .../assets/img/Food/PrimeMeatStew.png | Bin .../assets/img/Food/PrimePoultryCurry.png | Bin .../assets/img/Food/PrimePoultryPilaf.png | Bin .../assets/img/Food/PrimeSpicedMeatSkewer.png | Bin .../assets/img/Food/PumpkinPie.png | Bin .../assets/img/Food/PumpkinStew.png | Bin .../assets/img/Food/RoastedAcorn.png | Bin .../assets/img/Food/RoastedArmoranth.png | Bin .../assets/img/Food/RoastedBass.png | Bin .../assets/img/Food/RoastedBigRadish.png | Bin .../assets/img/Food/RoastedBirdDrumstick.png | Bin .../assets/img/Food/RoastedBirdThigh.png | Bin .../assets/img/Food/RoastedCarp.png | Bin .../assets/img/Food/RoastedEnduraCarrot.png | Bin .../assets/img/Food/RoastedHeartyBass.png | Bin .../assets/img/Food/RoastedHeartyDurian.png | Bin .../assets/img/Food/RoastedHeartySalmon.png | Bin .../assets/img/Food/RoastedHydromelon.png | Bin .../assets/img/Food/RoastedLotusSeeds.png | Bin .../assets/img/Food/RoastedMightyBananas.png | Bin .../assets/img/Food/RoastedMightyThistle.png | Bin .../assets/img/Food/RoastedPorgy.png | Bin .../assets/img/Food/RoastedRadish.png | Bin .../assets/img/Food/RoastedSwiftCarrot.png | Bin .../assets/img/Food/RoastedTreeNut.png | Bin .../assets/img/Food/RoastedTrout.png | Bin .../assets/img/Food/RoastedVoltfruit.png | Bin .../assets/img/Food/RoastedWholeBird.png | Bin .../assets/img/Food/RoastedWildberry.png | Bin .../assets/img/Food/RockHardFood.png | Bin .../assets/img/Food/SalmonMeuniere.png | Bin .../assets/img/Food/SalmonRisotto.png | Bin .../assets/img/Food/SaltGrilledCrab.png | Bin .../assets/img/Food/SaltGrilledFish.png | Bin .../img/Food/SaltGrilledGourmetMeat.png | Bin .../assets/img/Food/SaltGrilledGreens.png | Bin .../assets/img/Food/SaltGrilledMeat.png | Bin .../assets/img/Food/SaltGrilledMushrooms.png | Bin .../assets/img/Food/SaltGrilledPrimeMeat.png | Bin .../assets/img/Food/SauteedNuts.png | Bin .../assets/img/Food/SauteedPeppers.png | Bin .../assets/img/Food/SeafoodCurry.png | Bin .../assets/img/Food/SeafoodFriedRice.png | Bin .../assets/img/Food/SeafoodMeuniere.png | Bin .../assets/img/Food/SeafoodPaella.png | Bin .../assets/img/Food/SeafoodRiceBalls.png | Bin .../assets/img/Food/SeafoodSkewer.png | Bin .../assets/img/Food/SearedGourmetSteak.png | Bin .../assets/img/Food/SearedPrimeSteak.png | Bin .../assets/img/Food/SearedSteak.png | Bin .../assets/img/Food/SimmeredFruit.png | Bin .../assets/img/Food/SneakyElixir.png | Bin .../assets/img/Food/SneakyRiverEscargot.png | Bin .../assets/img/Food/SpicedMeatSkewer.png | Bin .../assets/img/Food/SpicyElixir.png | Bin .../assets/img/Food/SteamedFish.png | Bin .../assets/img/Food/SteamedFruit.png | Bin .../assets/img/Food/SteamedMeat.png | Bin .../assets/img/Food/SteamedMushrooms.png | Bin .../img/Food/ToastedBigHeartyTruffle.png | Bin .../assets/img/Food/ToastedHeartyTruffle.png | Bin .../assets/img/Food/ToastyChillshroom.png | Bin .../assets/img/Food/ToastyEnduraShroom.png | Bin .../assets/img/Food/ToastyHylianShroom.png | Bin .../assets/img/Food/ToastyIronshroom.png | Bin .../assets/img/Food/ToastyRazorshroom.png | Bin .../assets/img/Food/ToastyRushroom.png | Bin .../assets/img/Food/ToastySilentShroom.png | Bin .../assets/img/Food/ToastyStamellaShroom.png | Bin .../assets/img/Food/ToastySunshroom.png | Bin .../assets/img/Food/ToastyZapshroom.png | Bin .../assets/img/Food/ToughElixir.png | Bin .../assets/img/Food/VegetableCurry.png | Bin .../assets/img/Food/VegetableOmelet.png | Bin .../assets/img/Food/VegetableRisotto.png | Bin .../assets/img/Food/VeggieCreamSoup.png | Bin .../assets/img/Food/VeggieRiceBalls.png | Bin {src => public}/assets/img/Food/WarmMilk.png | Bin .../assets/img/Food/WheatBread.png | Bin .../assets/img/Food/WildberryCrepe.png | Bin .../assets/img/Key/AncientBridle.png | Bin .../assets/img/Key/AncientSaddle.png | Bin .../assets/img/Key/ClassifiedEnvelope.png | Bin .../assets/img/Key/DaruksProtection.png | Bin .../img/Key/DaruksProtectionDisabled.png | Bin .../assets/img/Key/DaruksProtectionPlus.png | Bin .../img/Key/DaruksProtectionPlusDisabled.png | Bin .../assets/img/Key/ExtravagantBridle.png | Bin .../assets/img/Key/ExtravagantSaddle.png | Bin {src => public}/assets/img/Key/HestusGift.png | Bin .../assets/img/Key/HestusMaracas.png | Bin .../assets/img/Key/KnightsBridle.png | Bin .../assets/img/Key/KnightsSaddle.png | Bin {src => public}/assets/img/Key/KorokSeed.png | Bin .../assets/img/Key/MedalOfHonorHinox.png | Bin .../assets/img/Key/MedalOfHonorMolduga.png | Bin .../assets/img/Key/MedalOfHonorTalus.png | Bin .../assets/img/Key/MedohsEmblem.png | Bin .../assets/img/Key/MiphasGrace.png | Bin .../assets/img/Key/MiphasGraceDisabled.png | Bin .../assets/img/Key/MiphasGracePlus.png | Bin .../img/Key/MiphasGracePlusDisabled.png | Bin .../assets/img/Key/MonsterBridle.png | Bin .../assets/img/Key/MonsterSaddle.png | Bin .../assets/img/Key/NaborissEmblem.png | Bin {src => public}/assets/img/Key/Paraglider.png | Bin .../assets/img/Key/PictureOfTheChampions.png | Bin .../assets/img/Key/RevalisGale.png | Bin .../assets/img/Key/RevalisGaleDisabled.png | Bin .../assets/img/Key/RevalisGalePlus.png | Bin .../img/Key/RevalisGalePlusDisabled.png | Bin .../assets/img/Key/RoyalBridle.png | Bin .../assets/img/Key/RoyalSaddle.png | Bin .../assets/img/Key/RudaniasEmblem.png | Bin .../assets/img/Key/RutasEmblem.png | Bin .../assets/img/Key/SheikahSlate.png | Bin {src => public}/assets/img/Key/SpiritOrb.png | Bin .../assets/img/Key/SpiritOrbAnimated.webp | Bin .../assets/img/Key/ThunderHelmKey.png | Bin .../assets/img/Key/TravelMedallion.png | Bin .../img/Key/TravelMedallionAnimated.webp | Bin .../assets/img/Key/TravelersBridle.png | Bin .../assets/img/Key/TravelersSaddle.png | Bin .../assets/img/Key/UrbosasFury.png | Bin .../assets/img/Key/UrbosasFuryDisabled.png | Bin .../assets/img/Key/UrbosasFuryPlus.png | Bin .../img/Key/UrbosasFuryPlusDisabled.png | Bin {src => public}/assets/img/Material/Acorn.png | Bin {src => public}/assets/img/Material/Amber.png | Bin .../assets/img/Material/AncientCore.png | Bin .../assets/img/Material/AncientGear.png | Bin .../assets/img/Material/AncientScrew.png | Bin .../assets/img/Material/AncientShaft.png | Bin .../assets/img/Material/AncientSpring.png | Bin {src => public}/assets/img/Material/Apple.png | Bin .../assets/img/Material/Armoranth.png | Bin .../assets/img/Material/ArmoredCarp.png | Bin .../assets/img/Material/ArmoredPorgy.png | Bin .../assets/img/Material/BigHeartyRadish.png | Bin .../assets/img/Material/BigHeartyTruffle.png | Bin .../assets/img/Material/BirdEgg.png | Bin .../assets/img/Material/BladedRhinoBeetle.png | Bin .../assets/img/Material/BlueNightshade.png | Bin .../assets/img/Material/BokoblinFang.png | Bin .../assets/img/Material/BokoblinGuts.png | Bin .../assets/img/Material/BokoblinHorn.png | Bin .../assets/img/Material/BrightEyedCrab.png | Bin .../assets/img/Material/CaneSugar.png | Bin .../assets/img/Material/ChickalooTreeNut.png | Bin .../assets/img/Material/ChillfinTrout.png | Bin .../assets/img/Material/Chillshroom.png | Bin .../assets/img/Material/ChuchuJelly.png | Bin .../assets/img/Material/ColdDarner.png | Bin .../assets/img/Material/CoolSafflina.png | Bin .../assets/img/Material/CourserBeeHoney.png | Bin .../assets/img/Material/Diamond.png | Bin .../assets/img/Material/DinraalsClaw.png | Bin .../assets/img/Material/DinraalsScale.png | Bin .../assets/img/Material/ElectricDarner.png | Bin .../assets/img/Material/ElectricKeeseWing.png | Bin .../assets/img/Material/ElectricSafflina.png | Bin .../assets/img/Material/EnduraCarrot.png | Bin .../assets/img/Material/EnduraShroom.png | Bin .../img/Material/EnergeticRhinoBeetle.png | Bin {src => public}/assets/img/Material/Fairy.png | Bin .../assets/img/Material/FaroshsClaw.png | Bin .../assets/img/Material/FaroshsScale.png | Bin .../assets/img/Material/FireKeeseWing.png | Bin .../assets/img/Material/FireproofLizard.png | Bin .../assets/img/Material/FleetLotusSeeds.png | Bin {src => public}/assets/img/Material/Flint.png | Bin .../assets/img/Material/FortifiedPumpkin.png | Bin .../assets/img/Material/FreshMilk.png | Bin .../assets/img/Material/GiantAncientCore.png | Bin .../assets/img/Material/GoatButter.png | Bin .../assets/img/Material/GoronSpice.png | Bin .../assets/img/Material/HeartyBass.png | Bin .../img/Material/HeartyBlueshellSnail.png | Bin .../assets/img/Material/HeartyDurian.png | Bin .../assets/img/Material/HeartyLizard.png | Bin .../assets/img/Material/HeartyRadish.png | Bin .../assets/img/Material/HeartySalmon.png | Bin .../assets/img/Material/HeartyTruffle.png | Bin .../assets/img/Material/HightailLizard.png | Bin .../assets/img/Material/HinoxGuts.png | Bin .../assets/img/Material/HinoxToenail.png | Bin .../assets/img/Material/HinoxTooth.png | Bin .../assets/img/Material/HotFootedFrog.png | Bin .../assets/img/Material/Hydromelon.png | Bin .../assets/img/Material/HylianRice.png | Bin .../assets/img/Material/HylianShroom.png | Bin .../assets/img/Material/HyruleBass.png | Bin .../assets/img/Material/HyruleHerb.png | Bin .../assets/img/Material/IceKeeseWing.png | Bin .../assets/img/Material/IcyLizalfosTail.png | Bin .../assets/img/Material/IronshellCrab.png | Bin .../assets/img/Material/Ironshroom.png | Bin .../assets/img/Material/KeeseEyeball.png | Bin .../assets/img/Material/KeeseWing.png | Bin .../assets/img/Material/LizalfosHorn.png | Bin .../assets/img/Material/LizalfosTail.png | Bin .../assets/img/Material/LizalfosTalon.png | Bin .../assets/img/Material/LuminousStone.png | Bin .../assets/img/Material/LynelGuts.png | Bin .../assets/img/Material/LynelHoof.png | Bin .../assets/img/Material/LynelHorn.png | Bin .../assets/img/Material/MightyBananas.png | Bin .../assets/img/Material/MightyCarp.png | Bin .../assets/img/Material/MightyPorgy.png | Bin .../assets/img/Material/MightyThistle.png | Bin .../assets/img/Material/MoblinFang.png | Bin .../assets/img/Material/MoblinGuts.png | Bin .../assets/img/Material/MoblinHorn.png | Bin .../assets/img/Material/MoldugaFin.png | Bin .../assets/img/Material/MoldugaGuts.png | Bin .../assets/img/Material/MonsterExtract.png | Bin .../assets/img/Material/NaydrasClaw.png | Bin .../assets/img/Material/NaydrasScale.png | Bin .../assets/img/Material/OctoBalloon.png | Bin .../assets/img/Material/OctorokEyeball.png | Bin .../assets/img/Material/OctorokTentacle.png | Bin {src => public}/assets/img/Material/Opal.png | Bin .../assets/img/Material/PalmFruit.png | Bin .../assets/img/Material/RawBirdDrumstick.png | Bin .../assets/img/Material/RawBirdThigh.png | Bin .../assets/img/Material/RawGourmetMeat.png | Bin .../assets/img/Material/RawMeat.png | Bin .../assets/img/Material/RawPrimeMeat.png | Bin .../assets/img/Material/RawWholeBird.png | Bin .../assets/img/Material/RazorclawCrab.png | Bin .../assets/img/Material/Razorshroom.png | Bin .../assets/img/Material/RedChuchuJelly.png | Bin .../assets/img/Material/RedLizalfosTail.png | Bin .../assets/img/Material/RestlessCricket.png | Bin .../assets/img/Material/RockSalt.png | Bin {src => public}/assets/img/Material/Ruby.png | Bin .../assets/img/Material/RuggedRhinoBeetle.png | Bin .../assets/img/Material/Rushroom.png | Bin .../assets/img/Material/SankeCarp.png | Bin .../assets/img/Material/Sapphire.png | Bin .../img/Material/ShardOfDinraalsFang.png | Bin .../img/Material/ShardOfDinraalsHorn.png | Bin .../img/Material/ShardOfFaroshsFang.png | Bin .../img/Material/ShardOfFaroshsHorn.png | Bin .../img/Material/ShardOfNaydrasFang.png | Bin .../img/Material/ShardOfNaydrasHorn.png | Bin .../assets/img/Material/SilentPrincess.png | Bin .../assets/img/Material/SilentShroom.png | Bin .../assets/img/Material/SizzlefinTrout.png | Bin .../img/Material/SmotherwingButterfly.png | Bin .../assets/img/Material/SneakyRiverSnail.png | Bin .../assets/img/Material/SpicyPepper.png | Bin .../assets/img/Material/StamellaShroom.png | Bin .../assets/img/Material/StaminokaBass.png | Bin .../assets/img/Material/StarFragment.png | Bin .../assets/img/Material/StealthfinTrout.png | Bin .../img/Material/SummerwingButterfly.png | Bin .../assets/img/Material/SunsetFirefly.png | Bin .../assets/img/Material/Sunshroom.png | Bin .../assets/img/Material/SwiftCarrot.png | Bin .../assets/img/Material/SwiftViolet.png | Bin .../assets/img/Material/TabanthaWheat.png | Bin .../img/Material/ThunderwingButterfly.png | Bin .../assets/img/Material/TirelessFrog.png | Bin {src => public}/assets/img/Material/Topaz.png | Bin .../assets/img/Material/VoltfinTrout.png | Bin .../assets/img/Material/Voltfruit.png | Bin .../assets/img/Material/WarmDarner.png | Bin .../assets/img/Material/WarmSafflina.png | Bin .../assets/img/Material/WhiteChuchuJelly.png | Bin .../assets/img/Material/Wildberry.png | Bin .../img/Material/WinterwingButterfly.png | Bin {src => public}/assets/img/Material/Wood.png | Bin .../assets/img/Material/YellowChuchuJelly.png | Bin .../img/Material/YellowLizalfosTail.png | Bin .../assets/img/Material/Zapshroom.png | Bin .../assets/img/Shield/AncientShield.png | Bin .../assets/img/Shield/BokoShield.png | Bin .../assets/img/Shield/Daybreaker.png | Bin .../img/Shield/DragonboneBokoShield.png | Bin .../assets/img/Shield/EmblazonedShield.png | Bin .../assets/img/Shield/FishermansShield.png | Bin .../img/Shield/ForestDwellersShield.png | Bin .../assets/img/Shield/GerudoShield.png | Bin .../assets/img/Shield/GuardianShield.png | Bin .../assets/img/Shield/GuardianShieldPlus.png | Bin .../img/Shield/GuardianShieldPlusPlus.png | Bin .../assets/img/Shield/HerosShield.png | Bin .../assets/img/Shield/HuntersShield.png | Bin .../assets/img/Shield/HylianShield.png | Bin .../assets/img/Shield/KiteShield.png | Bin .../assets/img/Shield/KnightsShield.png | Bin .../assets/img/Shield/LizalShield.png | Bin .../assets/img/Shield/LynelShield.png | Bin .../assets/img/Shield/MightyLynelShield.png | Bin {src => public}/assets/img/Shield/PotLid.png | Bin .../assets/img/Shield/RadiantShield.png | Bin .../img/Shield/ReinforcedLizalShield.png | Bin .../assets/img/Shield/RoyalGuardsShield.png | Bin .../assets/img/Shield/RoyalShield.png | Bin .../assets/img/Shield/RustyShield.png | Bin .../assets/img/Shield/SavageLynelShield.png | Bin public/assets/img/Shield/Shield.png | Bin 0 -> 21159 bytes .../assets/img/Shield/ShieldOfTheMindsEye.png | Bin .../assets/img/Shield/SilverShield.png | Bin .../assets/img/Shield/SoldiersShield.png | Bin .../assets/img/Shield/SpikedBokoShield.png | Bin .../assets/img/Shield/SteelLizalShield.png | Bin .../assets/img/Shield/TravelersShield.png | Bin .../assets/img/Shield/WoodenShield.png | Bin .../assets/img/Weapon/AncientBattleAxe.png | Bin .../img/Weapon/AncientBattleAxePlus.png | Bin .../img/Weapon/AncientBattleAxePlusPlus.png | Bin .../assets/img/Weapon/AncientBladesaw.png | Bin .../assets/img/Weapon/AncientShortSword.png | Bin .../assets/img/Weapon/AncientSpear.png | Bin .../assets/img/Weapon/BiggoronsSword.png | Bin .../assets/img/Weapon/BlizzardRod.png | Bin {src => public}/assets/img/Weapon/BoatOar.png | Bin {src => public}/assets/img/Weapon/BokoBat.png | Bin .../assets/img/Weapon/BokoClub.png | Bin .../assets/img/Weapon/BokoSpear.png | Bin .../assets/img/Weapon/BokoblinArm.png | Bin .../assets/img/Weapon/Boomerang.png | Bin .../assets/img/Weapon/BoulderBreaker.png | Bin .../assets/img/Weapon/CeremonialTrident.png | Bin .../assets/img/Weapon/CobbleCrusher.png | Bin .../assets/img/Weapon/DemonCarver.png | Bin .../assets/img/Weapon/DoubleAxe.png | Bin .../assets/img/Weapon/DragonboneBokoBat.png | Bin .../assets/img/Weapon/DragonboneBokoClub.png | Bin .../assets/img/Weapon/DragonboneBokoSpear.png | Bin .../img/Weapon/DragonboneMoblinClub.png | Bin .../img/Weapon/DragonboneMoblinSpear.png | Bin .../assets/img/Weapon/Drillshaft.png | Bin .../assets/img/Weapon/EdgeOfDuality.png | Bin .../assets/img/Weapon/EightfoldBlade.png | Bin .../assets/img/Weapon/EightfoldLongblade.png | Bin .../assets/img/Weapon/EnhancedLizalSpear.png | Bin .../assets/img/Weapon/FarmersPitchfork.png | Bin .../assets/img/Weapon/FarmingHoe.png | Bin .../assets/img/Weapon/FeatheredEdge.png | Bin .../assets/img/Weapon/FeatheredSpear.png | Bin .../assets/img/Weapon/FierceDeitySword.png | Bin {src => public}/assets/img/Weapon/FireRod.png | Bin .../assets/img/Weapon/FishingHarpoon.png | Bin .../assets/img/Weapon/Flameblade.png | Bin .../assets/img/Weapon/Flamespear.png | Bin .../assets/img/Weapon/ForestDwellersSpear.png | Bin .../assets/img/Weapon/ForestDwellersSword.png | Bin .../assets/img/Weapon/ForkedLizalSpear.png | Bin .../assets/img/Weapon/Frostblade.png | Bin .../assets/img/Weapon/Frostspear.png | Bin .../assets/img/Weapon/GerudoScimitar.png | Bin .../assets/img/Weapon/GerudoSpear.png | Bin .../assets/img/Weapon/GiantBoomerang.png | Bin .../assets/img/Weapon/GoddessSword.png | Bin .../assets/img/Weapon/GoldenClaymore.png | Bin .../assets/img/Weapon/GreatFlameblade.png | Bin .../assets/img/Weapon/GreatFrostblade.png | Bin .../assets/img/Weapon/GreatThunderblade.png | Bin .../assets/img/Weapon/GuardianSpear.png | Bin .../assets/img/Weapon/GuardianSpearPlus.png | Bin .../img/Weapon/GuardianSpearPlusPlus.png | Bin .../assets/img/Weapon/GuardianSword.png | Bin .../assets/img/Weapon/GuardianSwordPlus.png | Bin .../img/Weapon/GuardianSwordPlusPlus.png | Bin {src => public}/assets/img/Weapon/IceRod.png | Bin .../assets/img/Weapon/IronSledgehammer.png | Bin .../assets/img/Weapon/KnightsBroadsword.png | Bin .../assets/img/Weapon/KnightsClaymore.png | Bin .../assets/img/Weapon/KnightsHalberd.png | Bin .../assets/img/Weapon/KorokLeaf.png | Bin .../assets/img/Weapon/LightningRod.png | Bin .../assets/img/Weapon/LightscaleTrident.png | Bin .../assets/img/Weapon/LizalBoomerang.png | Bin .../img/Weapon/LizalForkedBoomerang.png | Bin .../assets/img/Weapon/LizalSpear.png | Bin .../assets/img/Weapon/LizalTriBoomerang.png | Bin .../assets/img/Weapon/LizalfosArm.png | Bin .../assets/img/Weapon/LynelCrusher.png | Bin .../assets/img/Weapon/LynelSpear.png | Bin .../assets/img/Weapon/LynelSword.png | Bin .../assets/img/Weapon/MasterSword.png | Bin .../assets/img/Weapon/MasterSwordAwakened.png | Bin .../assets/img/Weapon/MeteorRod.png | Bin .../assets/img/Weapon/MightyLynelCrusher.png | Bin .../assets/img/Weapon/MightyLynelSpear.png | Bin .../assets/img/Weapon/MightyLynelSword.png | Bin .../assets/img/Weapon/MoblinArm.png | Bin .../assets/img/Weapon/MoblinClub.png | Bin .../assets/img/Weapon/MoblinSpear.png | Bin .../assets/img/Weapon/MoonlightScimitar.png | Bin .../assets/img/Weapon/OneHitObliterator.png | Bin .../img/Weapon/OneHitObliteratorCharged.png | Bin .../assets/img/Weapon/RoyalBroadsword.png | Bin .../assets/img/Weapon/RoyalClaymore.png | Bin .../assets/img/Weapon/RoyalGuardsClaymore.png | Bin .../assets/img/Weapon/RoyalGuardsSpear.png | Bin .../assets/img/Weapon/RoyalGuardsSword.png | Bin .../assets/img/Weapon/RoyalHalberd.png | Bin .../assets/img/Weapon/RustyBroadsword.png | Bin .../assets/img/Weapon/RustyClaymore.png | Bin .../assets/img/Weapon/RustyHalberd.png | Bin .../assets/img/Weapon/SavageLynelCrusher.png | Bin .../assets/img/Weapon/SavageLynelSpear.png | Bin .../assets/img/Weapon/SavageLynelSword.png | Bin .../assets/img/Weapon/ScimitarOfTheSeven.png | Bin .../assets/img/Weapon/SeaBreezeBoomerang.png | Bin .../assets/img/Weapon/SerpentineSpear.png | Bin .../assets/img/Weapon/SilverLongsword.png | Bin .../assets/img/Weapon/SilverscaleSpear.png | Bin .../assets/img/Weapon/SoldiersBroadsword.png | Bin .../assets/img/Weapon/SoldiersClaymore.png | Bin .../assets/img/Weapon/SoldiersSpear.png | Bin .../assets/img/Weapon/SoupLadle.png | Bin .../assets/img/Weapon/SpikedBokoBat.png | Bin .../assets/img/Weapon/SpikedBokoClub.png | Bin .../assets/img/Weapon/SpikedBokoSpear.png | Bin .../assets/img/Weapon/SpikedMoblinClub.png | Bin .../assets/img/Weapon/SpikedMoblinSpear.png | Bin .../assets/img/Weapon/SpringLoadedHammer.png | Bin .../assets/img/Weapon/StoneSmasher.png | Bin {src => public}/assets/img/Weapon/Sword.png | Bin .../assets/img/Weapon/SwordOfTheSixSages.png | Bin .../assets/img/Weapon/ThrowingSpear.png | Bin .../assets/img/Weapon/Thunderblade.png | Bin .../assets/img/Weapon/Thunderspear.png | Bin .../assets/img/Weapon/ThunderstormRod.png | Bin {src => public}/assets/img/Weapon/Torch.png | Bin .../assets/img/Weapon/TravelersClaymore.png | Bin .../assets/img/Weapon/TravelersSpear.png | Bin .../assets/img/Weapon/TravelersSword.png | Bin .../assets/img/Weapon/TreeBranch.png | Bin .../assets/img/Weapon/ViciousSickle.png | Bin public/assets/img/Weapon/Weapon.png | Bin 0 -> 21128 bytes .../assets/img/Weapon/Windcleaver.png | Bin .../assets/img/Weapon/WoodcuttersAxe.png | Bin .../assets/img/Weapon/WoodenMop.png | Bin .../assets/img/Weapon/ZoraSpear.png | Bin .../assets/img/Weapon/ZoraSword.png | Bin src/App.css | 39 +- src/App.tsx | 186 ++- src/__tests__/README.md | 27 + src/__tests__/empty.e2e.ts | 6 + src/__tests__/empty.in.txt | 0 src/__tests__/empty.out.txt | 0 src/__tests__/goldrush_10reload22drop.e2e.ts | 7 + src/__tests__/goldrush_10reload22drop.in.txt | 81 ++ src/__tests__/goldrush_10reload22drop.out.txt | 5 + src/assets/Crash.png | Bin 9021 -> 0 bytes src/assets/img/index.ts | 25 - src/components/CrashScreen.tsx | 34 + src/components/ItemSlot.tsx | 37 +- src/components/LoadingScreen.tsx | 25 + src/components/Text.tsx | 22 + src/config/i18n/en_US.json | 694 ---------- src/config/items.json | 694 ---------- src/core/DisplayableInventory.ts | 31 +- src/core/GameData.ts | 6 +- src/core/Item.ts | 91 -- src/core/Localization.ts | 23 +- src/core/Parser.ts | 221 --- src/core/SimulationState.ts | 51 +- src/core/Slots.add.test.ts | 507 +++++++ src/core/Slots.ts | 390 ++++-- src/core/SlotsTestHelpers.ts | 32 + src/core/VisibleInventory.ts | 36 +- src/core/command/CommandHint.ts | 49 + src/core/command/CommandWrite.ts | 19 + src/core/{Command.ts => command/Commands.ts} | 205 +-- src/core/command/ItemStackCommandWrapper.ts | 17 + src/core/command/Parser.ts | 345 +++++ src/core/command/helper.ts | 60 + src/core/command/index.ts | 3 + src/core/command/type.ts | 16 + src/data/i18n/LanguageProvider.tsx | 93 ++ src/data/i18n/en.lang.yaml | 694 ++++++++++ src/data/i18n/index.ts | 1 + src/data/item/Item.ts | 64 + src/data/item/ItemProvider.tsx | 284 ++++ src/data/item/ItemStack.ts | 68 + src/data/item/all.items.yaml | 1179 +++++++++++++++++ src/data/item/index.ts | 5 + src/data/item/items.yaml.d.ts | 35 + src/data/item/legacy.ts | 63 + src/data/item/meta.ts | 40 + src/data/item/type.ts | 112 ++ src/data/measurePerformance.ts | 8 + src/data/{mergeSort.ts => stableSort.ts} | 0 src/data/tokenize.ts | 18 + src/index.tsx | 10 +- src/react-app-env.d.ts | 6 + src/setupTests.ts | 97 ++ src/surfaces/DisplayPane.tsx | 239 ++-- src/surfaces/GalleryPage.tsx | 39 + src/surfaces/LimitationPage.tsx | 5 + src/surfaces/ReferencePage.tsx | 132 +- 756 files changed, 5293 insertions(+), 2320 deletions(-) rename {src => public}/assets/img/Armor/AmberEarrings.png (100%) rename {src => public}/assets/img/Armor/AncientCuirass.png (100%) rename {src => public}/assets/img/Armor/AncientGreaves.png (100%) rename {src => public}/assets/img/Armor/AncientHelm.png (100%) rename {src => public}/assets/img/Armor/BarbarianArmor.png (100%) rename {src => public}/assets/img/Armor/BarbarianHelm.png (100%) rename {src => public}/assets/img/Armor/BarbarianLegWraps.png (100%) rename {src => public}/assets/img/Armor/BokoblinMask.png (100%) rename {src => public}/assets/img/Armor/CapOfTheHero.png (100%) rename {src => public}/assets/img/Armor/CapOfTheSky.png (100%) rename {src => public}/assets/img/Armor/CapOfTheWild.png (100%) rename {src => public}/assets/img/Armor/CapOfTheWind.png (100%) rename {src => public}/assets/img/Armor/CapOfTime.png (100%) rename {src => public}/assets/img/Armor/CapOfTwilight.png (100%) rename {src => public}/assets/img/Armor/ChampionsTunic.png (100%) rename {src => public}/assets/img/Armor/ClimbersBandanna.png (100%) rename {src => public}/assets/img/Armor/ClimbingBoots.png (100%) rename {src => public}/assets/img/Armor/ClimbingGear.png (100%) rename {src => public}/assets/img/Armor/DarkHood.png (100%) rename {src => public}/assets/img/Armor/DarkTrousers.png (100%) rename {src => public}/assets/img/Armor/DarkTunic.png (100%) rename {src => public}/assets/img/Armor/DesertVoeHeadband.png (100%) rename {src => public}/assets/img/Armor/DesertVoeSpaulder.png (100%) rename {src => public}/assets/img/Armor/DesertVoeTrousers.png (100%) rename {src => public}/assets/img/Armor/DiamondCirclet.png (100%) rename {src => public}/assets/img/Armor/FierceDeityArmor.png (100%) rename {src => public}/assets/img/Armor/FierceDeityBoots.png (100%) rename {src => public}/assets/img/Armor/FierceDeityMask.png (100%) rename {src => public}/assets/img/Armor/FlamebreakerArmor.png (100%) rename {src => public}/assets/img/Armor/FlamebreakerBoots.png (100%) rename {src => public}/assets/img/Armor/FlamebreakerHelm.png (100%) rename {src => public}/assets/img/Armor/GerudoSirwal.png (100%) rename {src => public}/assets/img/Armor/GerudoTop.png (100%) rename {src => public}/assets/img/Armor/GerudoVeil.png (100%) rename {src => public}/assets/img/Armor/HylianHood.png (100%) rename {src => public}/assets/img/Armor/HylianTrousers.png (100%) rename {src => public}/assets/img/Armor/HylianTunic.png (100%) rename {src => public}/assets/img/Armor/IslandLobsterShirt.png (100%) rename {src => public}/assets/img/Armor/KorokMask.png (100%) rename {src => public}/assets/img/Armor/LizalfosMask.png (100%) rename {src => public}/assets/img/Armor/LynelMask.png (100%) rename {src => public}/assets/img/Armor/MajorasMask.png (100%) rename {src => public}/assets/img/Armor/MidnasHelmet.png (100%) rename {src => public}/assets/img/Armor/MoblinMask.png (100%) rename {src => public}/assets/img/Armor/NintendoSwitchShirt.png (100%) rename {src => public}/assets/img/Armor/OldShirt.png (100%) rename {src => public}/assets/img/Armor/OpalEarrings.png (100%) rename {src => public}/assets/img/Armor/PhantomArmor.png (100%) rename {src => public}/assets/img/Armor/PhantomGanonArmor.png (100%) rename {src => public}/assets/img/Armor/PhantomGanonGreaves.png (100%) rename {src => public}/assets/img/Armor/PhantomGanonSkull.png (100%) rename {src => public}/assets/img/Armor/PhantomGreaves.png (100%) rename {src => public}/assets/img/Armor/PhantomHelmet.png (100%) rename {src => public}/assets/img/Armor/RadiantMask.png (100%) rename {src => public}/assets/img/Armor/RadiantShirt.png (100%) rename {src => public}/assets/img/Armor/RadiantTights.png (100%) rename {src => public}/assets/img/Armor/RaviosHood.png (100%) rename {src => public}/assets/img/Armor/RoyalGuardBoots.png (100%) rename {src => public}/assets/img/Armor/RoyalGuardCap.png (100%) rename {src => public}/assets/img/Armor/RoyalGuardUniform.png (100%) rename {src => public}/assets/img/Armor/RubberArmor.png (100%) rename {src => public}/assets/img/Armor/RubberHelm.png (100%) rename {src => public}/assets/img/Armor/RubberTights.png (100%) rename {src => public}/assets/img/Armor/RubyCirclet.png (100%) rename {src => public}/assets/img/Armor/SalvagerHeadwear.png (100%) rename {src => public}/assets/img/Armor/SalvagerTrousers.png (100%) rename {src => public}/assets/img/Armor/SalvagerVest.png (100%) rename {src => public}/assets/img/Armor/SandBoots.png (100%) rename {src => public}/assets/img/Armor/SapphireCirclet.png (100%) rename {src => public}/assets/img/Armor/SheiksMask.png (100%) rename {src => public}/assets/img/Armor/SnowBoots.png (100%) rename {src => public}/assets/img/Armor/SnowquillHeaddress.png (100%) rename {src => public}/assets/img/Armor/SnowquillTrousers.png (100%) rename {src => public}/assets/img/Armor/SnowquillTunic.png (100%) rename {src => public}/assets/img/Armor/SoldiersArmor.png (100%) rename {src => public}/assets/img/Armor/SoldiersGreaves.png (100%) rename {src => public}/assets/img/Armor/SoldiersHelm.png (100%) rename {src => public}/assets/img/Armor/StealthChestGuard.png (100%) rename {src => public}/assets/img/Armor/StealthMask.png (100%) rename {src => public}/assets/img/Armor/StealthTights.png (100%) rename {src => public}/assets/img/Armor/ThunderHelm.png (100%) rename {src => public}/assets/img/Armor/TinglesHood.png (100%) rename {src => public}/assets/img/Armor/TinglesShirt.png (100%) rename {src => public}/assets/img/Armor/TinglesTights.png (100%) rename {src => public}/assets/img/Armor/TopazEarrings.png (100%) rename {src => public}/assets/img/Armor/TrousersOfTheHero.png (100%) rename {src => public}/assets/img/Armor/TrousersOfTheSky.png (100%) rename {src => public}/assets/img/Armor/TrousersOfTheWild.png (100%) rename {src => public}/assets/img/Armor/TrousersOfTheWind.png (100%) rename {src => public}/assets/img/Armor/TrousersOfTime.png (100%) rename {src => public}/assets/img/Armor/TrousersOfTwilight.png (100%) rename {src => public}/assets/img/Armor/TunicOfTheHero.png (100%) rename {src => public}/assets/img/Armor/TunicOfTheSky.png (100%) rename {src => public}/assets/img/Armor/TunicOfTheWild.png (100%) rename {src => public}/assets/img/Armor/TunicOfTheWind.png (100%) rename {src => public}/assets/img/Armor/TunicOfTime.png (100%) rename {src => public}/assets/img/Armor/TunicOfTwilight.png (100%) rename {src => public}/assets/img/Armor/VahMedohDivineHelm.png (100%) rename {src => public}/assets/img/Armor/VahNaborisDivineHelm.png (100%) rename {src => public}/assets/img/Armor/VahRudaniaDivineHelm.png (100%) rename {src => public}/assets/img/Armor/VahRutaDivineHelm.png (100%) rename {src => public}/assets/img/Armor/WarmDoublet.png (100%) rename {src => public}/assets/img/Armor/WellWornTrousers.png (100%) rename {src => public}/assets/img/Armor/ZantsHelmet.png (100%) rename {src => public}/assets/img/Armor/ZoraArmor.png (100%) rename {src => public}/assets/img/Armor/ZoraGreaves.png (100%) rename {src => public}/assets/img/Armor/ZoraHelm.png (100%) rename {src => public}/assets/img/Arrow/AncientArrow.png (100%) rename {src => public}/assets/img/Arrow/BombArrow.png (100%) rename {src => public}/assets/img/Arrow/FireArrow.png (100%) rename {src => public}/assets/img/Arrow/IceArrow.png (100%) rename src/assets/img/Arrow/Arrow.png => public/assets/img/Arrow/NormalArrow.png (100%) rename {src => public}/assets/img/Arrow/ShockArrow.png (100%) rename {src => public}/assets/img/Bow/AncientBow.png (100%) rename {src => public}/assets/img/Bow/BokoBow.png (100%) create mode 100644 public/assets/img/Bow/Bow.png rename {src => public}/assets/img/Bow/BowOfLight.png (100%) rename {src => public}/assets/img/Bow/DragonBoneBokoBow.png (100%) rename {src => public}/assets/img/Bow/DuplexBow.png (100%) rename {src => public}/assets/img/Bow/FalconBow.png (100%) rename {src => public}/assets/img/Bow/ForestDwellersBow.png (100%) rename {src => public}/assets/img/Bow/GoldenBow.png (100%) rename {src => public}/assets/img/Bow/GreatEagleBow.png (100%) rename {src => public}/assets/img/Bow/KnightsBow.png (100%) rename {src => public}/assets/img/Bow/LizalBow.png (100%) rename {src => public}/assets/img/Bow/LynelBow.png (100%) rename {src => public}/assets/img/Bow/MightyLynelBow.png (100%) rename {src => public}/assets/img/Bow/PhrenicBow.png (100%) rename {src => public}/assets/img/Bow/RoyalBow.png (100%) rename {src => public}/assets/img/Bow/RoyalGuardsBow.png (100%) rename {src => public}/assets/img/Bow/SavageLynelBow.png (100%) rename {src => public}/assets/img/Bow/SilverBow.png (100%) rename {src => public}/assets/img/Bow/SoldiersBow.png (100%) rename {src => public}/assets/img/Bow/SpikedBokoBow.png (100%) rename {src => public}/assets/img/Bow/SteelLizalBow.png (100%) rename {src => public}/assets/img/Bow/StrengthenedLizalBow.png (100%) rename {src => public}/assets/img/Bow/SwallowBow.png (100%) rename {src => public}/assets/img/Bow/TravelersBow.png (100%) rename {src => public}/assets/img/Bow/TwilightBow.png (100%) rename {src => public}/assets/img/Bow/WoodenBow.png (100%) rename {src => public}/assets/img/Food/ApplePie.png (100%) rename {src => public}/assets/img/Food/BakedApple.png (100%) rename {src => public}/assets/img/Food/BakedFortifiedPumpkin.png (100%) rename {src => public}/assets/img/Food/BakedPalmFruit.png (100%) rename {src => public}/assets/img/Food/BlackenedCrab.png (100%) rename {src => public}/assets/img/Food/BlueshellEscargot.png (100%) rename {src => public}/assets/img/Food/CampfireEgg.png (100%) rename {src => public}/assets/img/Food/CarrotCake.png (100%) rename {src => public}/assets/img/Food/CarrotStew.png (100%) rename {src => public}/assets/img/Food/CharredPepper.png (100%) rename {src => public}/assets/img/Food/ChillyElixir.png (100%) rename {src => public}/assets/img/Food/ClamChowder.png (100%) rename {src => public}/assets/img/Food/CopiousFriedWildGreens.png (100%) rename {src => public}/assets/img/Food/CopiousMeatSkewers.png (100%) rename {src => public}/assets/img/Food/CopiousMushroomSkewers.png (100%) rename {src => public}/assets/img/Food/CopiousSeafoodSkewers.png (100%) rename {src => public}/assets/img/Food/CopiousSimmeredFruit.png (100%) rename {src => public}/assets/img/Food/CrabOmeletWithRice.png (100%) rename {src => public}/assets/img/Food/CrabRisotto.png (100%) rename {src => public}/assets/img/Food/CrabStirFry.png (100%) rename {src => public}/assets/img/Food/CreamOfMushroomSoup.png (100%) rename {src => public}/assets/img/Food/CreamOfVegetableSoup.png (100%) rename {src => public}/assets/img/Food/CreamyHeartSoup.png (100%) rename {src => public}/assets/img/Food/CreamyMeatSoup.png (100%) rename {src => public}/assets/img/Food/CreamySeafoodSoup.png (100%) rename {src => public}/assets/img/Food/CurryPilaf.png (100%) rename {src => public}/assets/img/Food/CurryRice.png (100%) rename {src => public}/assets/img/Food/DubiousFood.png (100%) rename {src => public}/assets/img/Food/EggPudding.png (100%) rename {src => public}/assets/img/Food/EggTart.png (100%) rename {src => public}/assets/img/Food/ElectroElixir.png (100%) rename {src => public}/assets/img/Food/Elixir.png (100%) rename {src => public}/assets/img/Food/EnduringElixir.png (100%) rename {src => public}/assets/img/Food/EnergizingElixir.png (100%) rename {src => public}/assets/img/Food/FairyTonic.png (100%) rename {src => public}/assets/img/Food/FireproofElixir.png (100%) rename {src => public}/assets/img/Food/FishAndMushroomSkewer.png (100%) rename {src => public}/assets/img/Food/FishPie.png (100%) rename {src => public}/assets/img/Food/FishSkewer.png (100%) rename {src => public}/assets/img/Food/FragrantMushroomSaute.png (100%) rename {src => public}/assets/img/Food/FriedBananas.png (100%) rename {src => public}/assets/img/Food/FriedEggAndRice.png (100%) rename {src => public}/assets/img/Food/FriedWildGreens.png (100%) rename {src => public}/assets/img/Food/FrozenBass.png (100%) rename {src => public}/assets/img/Food/FrozenBirdDrumstick.png (100%) rename {src => public}/assets/img/Food/FrozenBirdThigh.png (100%) rename {src => public}/assets/img/Food/FrozenCarp.png (100%) rename {src => public}/assets/img/Food/FrozenCrab.png (100%) rename {src => public}/assets/img/Food/FrozenHeartyBass.png (100%) rename {src => public}/assets/img/Food/FrozenHeartySalmon.png (100%) rename {src => public}/assets/img/Food/FrozenPorgy.png (100%) rename {src => public}/assets/img/Food/FrozenRiverSnail.png (100%) rename {src => public}/assets/img/Food/FrozenTrout.png (100%) rename {src => public}/assets/img/Food/FrozenWholeBird.png (100%) rename {src => public}/assets/img/Food/FruitAndMushroomMix.png (100%) rename {src => public}/assets/img/Food/FruitPie.png (100%) rename {src => public}/assets/img/Food/Fruitcake.png (100%) rename {src => public}/assets/img/Food/GlazedMeat.png (100%) rename {src => public}/assets/img/Food/GlazedMushrooms.png (100%) rename {src => public}/assets/img/Food/GlazedSeafood.png (100%) rename {src => public}/assets/img/Food/GlazedVeggies.png (100%) rename {src => public}/assets/img/Food/GourmetMeatAndRiceBowl.png (100%) rename {src => public}/assets/img/Food/GourmetMeatAndSeafoodFry.png (100%) rename {src => public}/assets/img/Food/GourmetMeatCurry.png (100%) rename {src => public}/assets/img/Food/GourmetMeatStew.png (100%) rename {src => public}/assets/img/Food/GourmetPoultryCurry.png (100%) rename {src => public}/assets/img/Food/GourmetPoultryPilaf.png (100%) rename {src => public}/assets/img/Food/GourmetSpicedMeatSkewer.png (100%) rename {src => public}/assets/img/Food/HardBoiledEgg.png (100%) rename {src => public}/assets/img/Food/HastyElixir.png (100%) rename {src => public}/assets/img/Food/HeartyElixir.png (100%) rename {src => public}/assets/img/Food/HerbSaute.png (100%) rename {src => public}/assets/img/Food/HoneyCandy.png (100%) rename {src => public}/assets/img/Food/HoneyCrepe.png (100%) rename {src => public}/assets/img/Food/HoneyedApple.png (100%) rename {src => public}/assets/img/Food/HoneyedFruits.png (100%) rename {src => public}/assets/img/Food/HotButteredApple.png (100%) rename {src => public}/assets/img/Food/IcyGourmetMeat.png (100%) rename {src => public}/assets/img/Food/IcyHeartyBlueshellSnail.png (100%) rename {src => public}/assets/img/Food/IcyMeat.png (100%) rename {src => public}/assets/img/Food/IcyPrimeMeat.png (100%) rename {src => public}/assets/img/Food/MeatAndMushroomSkewer.png (100%) rename {src => public}/assets/img/Food/MeatAndRiceBowl.png (100%) rename {src => public}/assets/img/Food/MeatAndSeafoodFry.png (100%) rename {src => public}/assets/img/Food/MeatCurry.png (100%) rename {src => public}/assets/img/Food/MeatPie.png (100%) rename {src => public}/assets/img/Food/MeatSkewer.png (100%) rename {src => public}/assets/img/Food/MeatStew.png (100%) rename {src => public}/assets/img/Food/MeatStuffedPumpkin.png (100%) rename {src => public}/assets/img/Food/MeatyRiceBalls.png (100%) rename {src => public}/assets/img/Food/MightyElixir.png (100%) rename {src => public}/assets/img/Food/MonsterCake.png (100%) rename {src => public}/assets/img/Food/MonsterCurry.png (100%) rename {src => public}/assets/img/Food/MonsterRiceBalls.png (100%) rename {src => public}/assets/img/Food/MonsterSoup.png (100%) rename {src => public}/assets/img/Food/MonsterStew.png (100%) rename {src => public}/assets/img/Food/MushroomOmelet.png (100%) rename {src => public}/assets/img/Food/MushroomRiceBalls.png (100%) rename {src => public}/assets/img/Food/MushroomRisotto.png (100%) rename {src => public}/assets/img/Food/MushroomSkewer.png (100%) rename {src => public}/assets/img/Food/Nutcake.png (100%) rename {src => public}/assets/img/Food/Omelet.png (100%) rename {src => public}/assets/img/Food/PepperSeafood.png (100%) rename {src => public}/assets/img/Food/PepperSteak.png (100%) rename {src => public}/assets/img/Food/PlainCrepe.png (100%) rename {src => public}/assets/img/Food/PorgyMeuniere.png (100%) rename {src => public}/assets/img/Food/PoultryCurry.png (100%) rename {src => public}/assets/img/Food/PoultryPilaf.png (100%) rename {src => public}/assets/img/Food/PrimeMeatAndRiceBowl.png (100%) rename {src => public}/assets/img/Food/PrimeMeatAndSeafoodFry.png (100%) rename {src => public}/assets/img/Food/PrimeMeatCurry.png (100%) rename {src => public}/assets/img/Food/PrimeMeatStew.png (100%) rename {src => public}/assets/img/Food/PrimePoultryCurry.png (100%) rename {src => public}/assets/img/Food/PrimePoultryPilaf.png (100%) rename {src => public}/assets/img/Food/PrimeSpicedMeatSkewer.png (100%) rename {src => public}/assets/img/Food/PumpkinPie.png (100%) rename {src => public}/assets/img/Food/PumpkinStew.png (100%) rename {src => public}/assets/img/Food/RoastedAcorn.png (100%) rename {src => public}/assets/img/Food/RoastedArmoranth.png (100%) rename {src => public}/assets/img/Food/RoastedBass.png (100%) rename {src => public}/assets/img/Food/RoastedBigRadish.png (100%) rename {src => public}/assets/img/Food/RoastedBirdDrumstick.png (100%) rename {src => public}/assets/img/Food/RoastedBirdThigh.png (100%) rename {src => public}/assets/img/Food/RoastedCarp.png (100%) rename {src => public}/assets/img/Food/RoastedEnduraCarrot.png (100%) rename {src => public}/assets/img/Food/RoastedHeartyBass.png (100%) rename {src => public}/assets/img/Food/RoastedHeartyDurian.png (100%) rename {src => public}/assets/img/Food/RoastedHeartySalmon.png (100%) rename {src => public}/assets/img/Food/RoastedHydromelon.png (100%) rename {src => public}/assets/img/Food/RoastedLotusSeeds.png (100%) rename {src => public}/assets/img/Food/RoastedMightyBananas.png (100%) rename {src => public}/assets/img/Food/RoastedMightyThistle.png (100%) rename {src => public}/assets/img/Food/RoastedPorgy.png (100%) rename {src => public}/assets/img/Food/RoastedRadish.png (100%) rename {src => public}/assets/img/Food/RoastedSwiftCarrot.png (100%) rename {src => public}/assets/img/Food/RoastedTreeNut.png (100%) rename {src => public}/assets/img/Food/RoastedTrout.png (100%) rename {src => public}/assets/img/Food/RoastedVoltfruit.png (100%) rename {src => public}/assets/img/Food/RoastedWholeBird.png (100%) rename {src => public}/assets/img/Food/RoastedWildberry.png (100%) rename {src => public}/assets/img/Food/RockHardFood.png (100%) rename {src => public}/assets/img/Food/SalmonMeuniere.png (100%) rename {src => public}/assets/img/Food/SalmonRisotto.png (100%) rename {src => public}/assets/img/Food/SaltGrilledCrab.png (100%) rename {src => public}/assets/img/Food/SaltGrilledFish.png (100%) rename {src => public}/assets/img/Food/SaltGrilledGourmetMeat.png (100%) rename {src => public}/assets/img/Food/SaltGrilledGreens.png (100%) rename {src => public}/assets/img/Food/SaltGrilledMeat.png (100%) rename {src => public}/assets/img/Food/SaltGrilledMushrooms.png (100%) rename {src => public}/assets/img/Food/SaltGrilledPrimeMeat.png (100%) rename {src => public}/assets/img/Food/SauteedNuts.png (100%) rename {src => public}/assets/img/Food/SauteedPeppers.png (100%) rename {src => public}/assets/img/Food/SeafoodCurry.png (100%) rename {src => public}/assets/img/Food/SeafoodFriedRice.png (100%) rename {src => public}/assets/img/Food/SeafoodMeuniere.png (100%) rename {src => public}/assets/img/Food/SeafoodPaella.png (100%) rename {src => public}/assets/img/Food/SeafoodRiceBalls.png (100%) rename {src => public}/assets/img/Food/SeafoodSkewer.png (100%) rename {src => public}/assets/img/Food/SearedGourmetSteak.png (100%) rename {src => public}/assets/img/Food/SearedPrimeSteak.png (100%) rename {src => public}/assets/img/Food/SearedSteak.png (100%) rename {src => public}/assets/img/Food/SimmeredFruit.png (100%) rename {src => public}/assets/img/Food/SneakyElixir.png (100%) rename {src => public}/assets/img/Food/SneakyRiverEscargot.png (100%) rename {src => public}/assets/img/Food/SpicedMeatSkewer.png (100%) rename {src => public}/assets/img/Food/SpicyElixir.png (100%) rename {src => public}/assets/img/Food/SteamedFish.png (100%) rename {src => public}/assets/img/Food/SteamedFruit.png (100%) rename {src => public}/assets/img/Food/SteamedMeat.png (100%) rename {src => public}/assets/img/Food/SteamedMushrooms.png (100%) rename {src => public}/assets/img/Food/ToastedBigHeartyTruffle.png (100%) rename {src => public}/assets/img/Food/ToastedHeartyTruffle.png (100%) rename {src => public}/assets/img/Food/ToastyChillshroom.png (100%) rename {src => public}/assets/img/Food/ToastyEnduraShroom.png (100%) rename {src => public}/assets/img/Food/ToastyHylianShroom.png (100%) rename {src => public}/assets/img/Food/ToastyIronshroom.png (100%) rename {src => public}/assets/img/Food/ToastyRazorshroom.png (100%) rename {src => public}/assets/img/Food/ToastyRushroom.png (100%) rename {src => public}/assets/img/Food/ToastySilentShroom.png (100%) rename {src => public}/assets/img/Food/ToastyStamellaShroom.png (100%) rename {src => public}/assets/img/Food/ToastySunshroom.png (100%) rename {src => public}/assets/img/Food/ToastyZapshroom.png (100%) rename {src => public}/assets/img/Food/ToughElixir.png (100%) rename {src => public}/assets/img/Food/VegetableCurry.png (100%) rename {src => public}/assets/img/Food/VegetableOmelet.png (100%) rename {src => public}/assets/img/Food/VegetableRisotto.png (100%) rename {src => public}/assets/img/Food/VeggieCreamSoup.png (100%) rename {src => public}/assets/img/Food/VeggieRiceBalls.png (100%) rename {src => public}/assets/img/Food/WarmMilk.png (100%) rename {src => public}/assets/img/Food/WheatBread.png (100%) rename {src => public}/assets/img/Food/WildberryCrepe.png (100%) rename {src => public}/assets/img/Key/AncientBridle.png (100%) rename {src => public}/assets/img/Key/AncientSaddle.png (100%) rename {src => public}/assets/img/Key/ClassifiedEnvelope.png (100%) rename {src => public}/assets/img/Key/DaruksProtection.png (100%) rename {src => public}/assets/img/Key/DaruksProtectionDisabled.png (100%) rename {src => public}/assets/img/Key/DaruksProtectionPlus.png (100%) rename {src => public}/assets/img/Key/DaruksProtectionPlusDisabled.png (100%) rename {src => public}/assets/img/Key/ExtravagantBridle.png (100%) rename {src => public}/assets/img/Key/ExtravagantSaddle.png (100%) rename {src => public}/assets/img/Key/HestusGift.png (100%) rename {src => public}/assets/img/Key/HestusMaracas.png (100%) rename {src => public}/assets/img/Key/KnightsBridle.png (100%) rename {src => public}/assets/img/Key/KnightsSaddle.png (100%) rename {src => public}/assets/img/Key/KorokSeed.png (100%) rename {src => public}/assets/img/Key/MedalOfHonorHinox.png (100%) rename {src => public}/assets/img/Key/MedalOfHonorMolduga.png (100%) rename {src => public}/assets/img/Key/MedalOfHonorTalus.png (100%) rename {src => public}/assets/img/Key/MedohsEmblem.png (100%) rename {src => public}/assets/img/Key/MiphasGrace.png (100%) rename {src => public}/assets/img/Key/MiphasGraceDisabled.png (100%) rename {src => public}/assets/img/Key/MiphasGracePlus.png (100%) rename {src => public}/assets/img/Key/MiphasGracePlusDisabled.png (100%) rename {src => public}/assets/img/Key/MonsterBridle.png (100%) rename {src => public}/assets/img/Key/MonsterSaddle.png (100%) rename {src => public}/assets/img/Key/NaborissEmblem.png (100%) rename {src => public}/assets/img/Key/Paraglider.png (100%) rename {src => public}/assets/img/Key/PictureOfTheChampions.png (100%) rename {src => public}/assets/img/Key/RevalisGale.png (100%) rename {src => public}/assets/img/Key/RevalisGaleDisabled.png (100%) rename {src => public}/assets/img/Key/RevalisGalePlus.png (100%) rename {src => public}/assets/img/Key/RevalisGalePlusDisabled.png (100%) rename {src => public}/assets/img/Key/RoyalBridle.png (100%) rename {src => public}/assets/img/Key/RoyalSaddle.png (100%) rename {src => public}/assets/img/Key/RudaniasEmblem.png (100%) rename {src => public}/assets/img/Key/RutasEmblem.png (100%) rename {src => public}/assets/img/Key/SheikahSlate.png (100%) rename {src => public}/assets/img/Key/SpiritOrb.png (100%) rename {src => public}/assets/img/Key/SpiritOrbAnimated.webp (100%) rename src/assets/img/Key/ThunderHelmKeyItem.png => public/assets/img/Key/ThunderHelmKey.png (100%) rename {src => public}/assets/img/Key/TravelMedallion.png (100%) rename {src => public}/assets/img/Key/TravelMedallionAnimated.webp (100%) rename {src => public}/assets/img/Key/TravelersBridle.png (100%) rename {src => public}/assets/img/Key/TravelersSaddle.png (100%) rename {src => public}/assets/img/Key/UrbosasFury.png (100%) rename {src => public}/assets/img/Key/UrbosasFuryDisabled.png (100%) rename {src => public}/assets/img/Key/UrbosasFuryPlus.png (100%) rename {src => public}/assets/img/Key/UrbosasFuryPlusDisabled.png (100%) rename {src => public}/assets/img/Material/Acorn.png (100%) rename {src => public}/assets/img/Material/Amber.png (100%) rename {src => public}/assets/img/Material/AncientCore.png (100%) rename {src => public}/assets/img/Material/AncientGear.png (100%) rename {src => public}/assets/img/Material/AncientScrew.png (100%) rename {src => public}/assets/img/Material/AncientShaft.png (100%) rename {src => public}/assets/img/Material/AncientSpring.png (100%) rename {src => public}/assets/img/Material/Apple.png (100%) rename {src => public}/assets/img/Material/Armoranth.png (100%) rename {src => public}/assets/img/Material/ArmoredCarp.png (100%) rename {src => public}/assets/img/Material/ArmoredPorgy.png (100%) rename {src => public}/assets/img/Material/BigHeartyRadish.png (100%) rename {src => public}/assets/img/Material/BigHeartyTruffle.png (100%) rename {src => public}/assets/img/Material/BirdEgg.png (100%) rename {src => public}/assets/img/Material/BladedRhinoBeetle.png (100%) rename {src => public}/assets/img/Material/BlueNightshade.png (100%) rename {src => public}/assets/img/Material/BokoblinFang.png (100%) rename {src => public}/assets/img/Material/BokoblinGuts.png (100%) rename {src => public}/assets/img/Material/BokoblinHorn.png (100%) rename {src => public}/assets/img/Material/BrightEyedCrab.png (100%) rename {src => public}/assets/img/Material/CaneSugar.png (100%) rename {src => public}/assets/img/Material/ChickalooTreeNut.png (100%) rename {src => public}/assets/img/Material/ChillfinTrout.png (100%) rename {src => public}/assets/img/Material/Chillshroom.png (100%) rename {src => public}/assets/img/Material/ChuchuJelly.png (100%) rename {src => public}/assets/img/Material/ColdDarner.png (100%) rename {src => public}/assets/img/Material/CoolSafflina.png (100%) rename {src => public}/assets/img/Material/CourserBeeHoney.png (100%) rename {src => public}/assets/img/Material/Diamond.png (100%) rename {src => public}/assets/img/Material/DinraalsClaw.png (100%) rename {src => public}/assets/img/Material/DinraalsScale.png (100%) rename {src => public}/assets/img/Material/ElectricDarner.png (100%) rename {src => public}/assets/img/Material/ElectricKeeseWing.png (100%) rename {src => public}/assets/img/Material/ElectricSafflina.png (100%) rename {src => public}/assets/img/Material/EnduraCarrot.png (100%) rename {src => public}/assets/img/Material/EnduraShroom.png (100%) rename {src => public}/assets/img/Material/EnergeticRhinoBeetle.png (100%) rename {src => public}/assets/img/Material/Fairy.png (100%) rename {src => public}/assets/img/Material/FaroshsClaw.png (100%) rename {src => public}/assets/img/Material/FaroshsScale.png (100%) rename {src => public}/assets/img/Material/FireKeeseWing.png (100%) rename {src => public}/assets/img/Material/FireproofLizard.png (100%) rename {src => public}/assets/img/Material/FleetLotusSeeds.png (100%) rename {src => public}/assets/img/Material/Flint.png (100%) rename {src => public}/assets/img/Material/FortifiedPumpkin.png (100%) rename {src => public}/assets/img/Material/FreshMilk.png (100%) rename {src => public}/assets/img/Material/GiantAncientCore.png (100%) rename {src => public}/assets/img/Material/GoatButter.png (100%) rename {src => public}/assets/img/Material/GoronSpice.png (100%) rename {src => public}/assets/img/Material/HeartyBass.png (100%) rename {src => public}/assets/img/Material/HeartyBlueshellSnail.png (100%) rename {src => public}/assets/img/Material/HeartyDurian.png (100%) rename {src => public}/assets/img/Material/HeartyLizard.png (100%) rename {src => public}/assets/img/Material/HeartyRadish.png (100%) rename {src => public}/assets/img/Material/HeartySalmon.png (100%) rename {src => public}/assets/img/Material/HeartyTruffle.png (100%) rename {src => public}/assets/img/Material/HightailLizard.png (100%) rename {src => public}/assets/img/Material/HinoxGuts.png (100%) rename {src => public}/assets/img/Material/HinoxToenail.png (100%) rename {src => public}/assets/img/Material/HinoxTooth.png (100%) rename {src => public}/assets/img/Material/HotFootedFrog.png (100%) rename {src => public}/assets/img/Material/Hydromelon.png (100%) rename {src => public}/assets/img/Material/HylianRice.png (100%) rename {src => public}/assets/img/Material/HylianShroom.png (100%) rename {src => public}/assets/img/Material/HyruleBass.png (100%) rename {src => public}/assets/img/Material/HyruleHerb.png (100%) rename {src => public}/assets/img/Material/IceKeeseWing.png (100%) rename {src => public}/assets/img/Material/IcyLizalfosTail.png (100%) rename {src => public}/assets/img/Material/IronshellCrab.png (100%) rename {src => public}/assets/img/Material/Ironshroom.png (100%) rename {src => public}/assets/img/Material/KeeseEyeball.png (100%) rename {src => public}/assets/img/Material/KeeseWing.png (100%) rename {src => public}/assets/img/Material/LizalfosHorn.png (100%) rename {src => public}/assets/img/Material/LizalfosTail.png (100%) rename {src => public}/assets/img/Material/LizalfosTalon.png (100%) rename {src => public}/assets/img/Material/LuminousStone.png (100%) rename {src => public}/assets/img/Material/LynelGuts.png (100%) rename {src => public}/assets/img/Material/LynelHoof.png (100%) rename {src => public}/assets/img/Material/LynelHorn.png (100%) rename {src => public}/assets/img/Material/MightyBananas.png (100%) rename {src => public}/assets/img/Material/MightyCarp.png (100%) rename {src => public}/assets/img/Material/MightyPorgy.png (100%) rename {src => public}/assets/img/Material/MightyThistle.png (100%) rename {src => public}/assets/img/Material/MoblinFang.png (100%) rename {src => public}/assets/img/Material/MoblinGuts.png (100%) rename {src => public}/assets/img/Material/MoblinHorn.png (100%) rename {src => public}/assets/img/Material/MoldugaFin.png (100%) rename {src => public}/assets/img/Material/MoldugaGuts.png (100%) rename {src => public}/assets/img/Material/MonsterExtract.png (100%) rename {src => public}/assets/img/Material/NaydrasClaw.png (100%) rename {src => public}/assets/img/Material/NaydrasScale.png (100%) rename {src => public}/assets/img/Material/OctoBalloon.png (100%) rename {src => public}/assets/img/Material/OctorokEyeball.png (100%) rename {src => public}/assets/img/Material/OctorokTentacle.png (100%) rename {src => public}/assets/img/Material/Opal.png (100%) rename {src => public}/assets/img/Material/PalmFruit.png (100%) rename {src => public}/assets/img/Material/RawBirdDrumstick.png (100%) rename {src => public}/assets/img/Material/RawBirdThigh.png (100%) rename {src => public}/assets/img/Material/RawGourmetMeat.png (100%) rename {src => public}/assets/img/Material/RawMeat.png (100%) rename {src => public}/assets/img/Material/RawPrimeMeat.png (100%) rename {src => public}/assets/img/Material/RawWholeBird.png (100%) rename {src => public}/assets/img/Material/RazorclawCrab.png (100%) rename {src => public}/assets/img/Material/Razorshroom.png (100%) rename {src => public}/assets/img/Material/RedChuchuJelly.png (100%) rename {src => public}/assets/img/Material/RedLizalfosTail.png (100%) rename {src => public}/assets/img/Material/RestlessCricket.png (100%) rename {src => public}/assets/img/Material/RockSalt.png (100%) rename {src => public}/assets/img/Material/Ruby.png (100%) rename {src => public}/assets/img/Material/RuggedRhinoBeetle.png (100%) rename {src => public}/assets/img/Material/Rushroom.png (100%) rename {src => public}/assets/img/Material/SankeCarp.png (100%) rename {src => public}/assets/img/Material/Sapphire.png (100%) rename {src => public}/assets/img/Material/ShardOfDinraalsFang.png (100%) rename {src => public}/assets/img/Material/ShardOfDinraalsHorn.png (100%) rename {src => public}/assets/img/Material/ShardOfFaroshsFang.png (100%) rename {src => public}/assets/img/Material/ShardOfFaroshsHorn.png (100%) rename {src => public}/assets/img/Material/ShardOfNaydrasFang.png (100%) rename {src => public}/assets/img/Material/ShardOfNaydrasHorn.png (100%) rename {src => public}/assets/img/Material/SilentPrincess.png (100%) rename {src => public}/assets/img/Material/SilentShroom.png (100%) rename {src => public}/assets/img/Material/SizzlefinTrout.png (100%) rename {src => public}/assets/img/Material/SmotherwingButterfly.png (100%) rename {src => public}/assets/img/Material/SneakyRiverSnail.png (100%) rename {src => public}/assets/img/Material/SpicyPepper.png (100%) rename {src => public}/assets/img/Material/StamellaShroom.png (100%) rename {src => public}/assets/img/Material/StaminokaBass.png (100%) rename {src => public}/assets/img/Material/StarFragment.png (100%) rename {src => public}/assets/img/Material/StealthfinTrout.png (100%) rename {src => public}/assets/img/Material/SummerwingButterfly.png (100%) rename {src => public}/assets/img/Material/SunsetFirefly.png (100%) rename {src => public}/assets/img/Material/Sunshroom.png (100%) rename {src => public}/assets/img/Material/SwiftCarrot.png (100%) rename {src => public}/assets/img/Material/SwiftViolet.png (100%) rename {src => public}/assets/img/Material/TabanthaWheat.png (100%) rename {src => public}/assets/img/Material/ThunderwingButterfly.png (100%) rename {src => public}/assets/img/Material/TirelessFrog.png (100%) rename {src => public}/assets/img/Material/Topaz.png (100%) rename {src => public}/assets/img/Material/VoltfinTrout.png (100%) rename {src => public}/assets/img/Material/Voltfruit.png (100%) rename {src => public}/assets/img/Material/WarmDarner.png (100%) rename {src => public}/assets/img/Material/WarmSafflina.png (100%) rename {src => public}/assets/img/Material/WhiteChuchuJelly.png (100%) rename {src => public}/assets/img/Material/Wildberry.png (100%) rename {src => public}/assets/img/Material/WinterwingButterfly.png (100%) rename {src => public}/assets/img/Material/Wood.png (100%) rename {src => public}/assets/img/Material/YellowChuchuJelly.png (100%) rename {src => public}/assets/img/Material/YellowLizalfosTail.png (100%) rename {src => public}/assets/img/Material/Zapshroom.png (100%) rename {src => public}/assets/img/Shield/AncientShield.png (100%) rename {src => public}/assets/img/Shield/BokoShield.png (100%) rename {src => public}/assets/img/Shield/Daybreaker.png (100%) rename {src => public}/assets/img/Shield/DragonboneBokoShield.png (100%) rename {src => public}/assets/img/Shield/EmblazonedShield.png (100%) rename {src => public}/assets/img/Shield/FishermansShield.png (100%) rename {src => public}/assets/img/Shield/ForestDwellersShield.png (100%) rename {src => public}/assets/img/Shield/GerudoShield.png (100%) rename {src => public}/assets/img/Shield/GuardianShield.png (100%) rename {src => public}/assets/img/Shield/GuardianShieldPlus.png (100%) rename {src => public}/assets/img/Shield/GuardianShieldPlusPlus.png (100%) rename {src => public}/assets/img/Shield/HerosShield.png (100%) rename {src => public}/assets/img/Shield/HuntersShield.png (100%) rename {src => public}/assets/img/Shield/HylianShield.png (100%) rename {src => public}/assets/img/Shield/KiteShield.png (100%) rename {src => public}/assets/img/Shield/KnightsShield.png (100%) rename {src => public}/assets/img/Shield/LizalShield.png (100%) rename {src => public}/assets/img/Shield/LynelShield.png (100%) rename {src => public}/assets/img/Shield/MightyLynelShield.png (100%) rename {src => public}/assets/img/Shield/PotLid.png (100%) rename {src => public}/assets/img/Shield/RadiantShield.png (100%) rename {src => public}/assets/img/Shield/ReinforcedLizalShield.png (100%) rename {src => public}/assets/img/Shield/RoyalGuardsShield.png (100%) rename {src => public}/assets/img/Shield/RoyalShield.png (100%) rename {src => public}/assets/img/Shield/RustyShield.png (100%) rename {src => public}/assets/img/Shield/SavageLynelShield.png (100%) create mode 100644 public/assets/img/Shield/Shield.png rename {src => public}/assets/img/Shield/ShieldOfTheMindsEye.png (100%) rename {src => public}/assets/img/Shield/SilverShield.png (100%) rename {src => public}/assets/img/Shield/SoldiersShield.png (100%) rename {src => public}/assets/img/Shield/SpikedBokoShield.png (100%) rename {src => public}/assets/img/Shield/SteelLizalShield.png (100%) rename {src => public}/assets/img/Shield/TravelersShield.png (100%) rename {src => public}/assets/img/Shield/WoodenShield.png (100%) rename {src => public}/assets/img/Weapon/AncientBattleAxe.png (100%) rename {src => public}/assets/img/Weapon/AncientBattleAxePlus.png (100%) rename {src => public}/assets/img/Weapon/AncientBattleAxePlusPlus.png (100%) rename {src => public}/assets/img/Weapon/AncientBladesaw.png (100%) rename {src => public}/assets/img/Weapon/AncientShortSword.png (100%) rename {src => public}/assets/img/Weapon/AncientSpear.png (100%) rename {src => public}/assets/img/Weapon/BiggoronsSword.png (100%) rename {src => public}/assets/img/Weapon/BlizzardRod.png (100%) rename {src => public}/assets/img/Weapon/BoatOar.png (100%) rename {src => public}/assets/img/Weapon/BokoBat.png (100%) rename {src => public}/assets/img/Weapon/BokoClub.png (100%) rename {src => public}/assets/img/Weapon/BokoSpear.png (100%) rename {src => public}/assets/img/Weapon/BokoblinArm.png (100%) rename {src => public}/assets/img/Weapon/Boomerang.png (100%) rename {src => public}/assets/img/Weapon/BoulderBreaker.png (100%) rename {src => public}/assets/img/Weapon/CeremonialTrident.png (100%) rename {src => public}/assets/img/Weapon/CobbleCrusher.png (100%) rename {src => public}/assets/img/Weapon/DemonCarver.png (100%) rename {src => public}/assets/img/Weapon/DoubleAxe.png (100%) rename {src => public}/assets/img/Weapon/DragonboneBokoBat.png (100%) rename {src => public}/assets/img/Weapon/DragonboneBokoClub.png (100%) rename {src => public}/assets/img/Weapon/DragonboneBokoSpear.png (100%) rename {src => public}/assets/img/Weapon/DragonboneMoblinClub.png (100%) rename {src => public}/assets/img/Weapon/DragonboneMoblinSpear.png (100%) rename {src => public}/assets/img/Weapon/Drillshaft.png (100%) rename {src => public}/assets/img/Weapon/EdgeOfDuality.png (100%) rename {src => public}/assets/img/Weapon/EightfoldBlade.png (100%) rename {src => public}/assets/img/Weapon/EightfoldLongblade.png (100%) rename {src => public}/assets/img/Weapon/EnhancedLizalSpear.png (100%) rename {src => public}/assets/img/Weapon/FarmersPitchfork.png (100%) rename {src => public}/assets/img/Weapon/FarmingHoe.png (100%) rename {src => public}/assets/img/Weapon/FeatheredEdge.png (100%) rename {src => public}/assets/img/Weapon/FeatheredSpear.png (100%) rename {src => public}/assets/img/Weapon/FierceDeitySword.png (100%) rename {src => public}/assets/img/Weapon/FireRod.png (100%) rename {src => public}/assets/img/Weapon/FishingHarpoon.png (100%) rename {src => public}/assets/img/Weapon/Flameblade.png (100%) rename {src => public}/assets/img/Weapon/Flamespear.png (100%) rename {src => public}/assets/img/Weapon/ForestDwellersSpear.png (100%) rename {src => public}/assets/img/Weapon/ForestDwellersSword.png (100%) rename {src => public}/assets/img/Weapon/ForkedLizalSpear.png (100%) rename {src => public}/assets/img/Weapon/Frostblade.png (100%) rename {src => public}/assets/img/Weapon/Frostspear.png (100%) rename {src => public}/assets/img/Weapon/GerudoScimitar.png (100%) rename {src => public}/assets/img/Weapon/GerudoSpear.png (100%) rename {src => public}/assets/img/Weapon/GiantBoomerang.png (100%) rename {src => public}/assets/img/Weapon/GoddessSword.png (100%) rename {src => public}/assets/img/Weapon/GoldenClaymore.png (100%) rename {src => public}/assets/img/Weapon/GreatFlameblade.png (100%) rename {src => public}/assets/img/Weapon/GreatFrostblade.png (100%) rename {src => public}/assets/img/Weapon/GreatThunderblade.png (100%) rename {src => public}/assets/img/Weapon/GuardianSpear.png (100%) rename {src => public}/assets/img/Weapon/GuardianSpearPlus.png (100%) rename {src => public}/assets/img/Weapon/GuardianSpearPlusPlus.png (100%) rename {src => public}/assets/img/Weapon/GuardianSword.png (100%) rename {src => public}/assets/img/Weapon/GuardianSwordPlus.png (100%) rename {src => public}/assets/img/Weapon/GuardianSwordPlusPlus.png (100%) rename {src => public}/assets/img/Weapon/IceRod.png (100%) rename {src => public}/assets/img/Weapon/IronSledgehammer.png (100%) rename {src => public}/assets/img/Weapon/KnightsBroadsword.png (100%) rename {src => public}/assets/img/Weapon/KnightsClaymore.png (100%) rename {src => public}/assets/img/Weapon/KnightsHalberd.png (100%) rename {src => public}/assets/img/Weapon/KorokLeaf.png (100%) rename {src => public}/assets/img/Weapon/LightningRod.png (100%) rename {src => public}/assets/img/Weapon/LightscaleTrident.png (100%) rename {src => public}/assets/img/Weapon/LizalBoomerang.png (100%) rename {src => public}/assets/img/Weapon/LizalForkedBoomerang.png (100%) rename {src => public}/assets/img/Weapon/LizalSpear.png (100%) rename {src => public}/assets/img/Weapon/LizalTriBoomerang.png (100%) rename {src => public}/assets/img/Weapon/LizalfosArm.png (100%) rename {src => public}/assets/img/Weapon/LynelCrusher.png (100%) rename {src => public}/assets/img/Weapon/LynelSpear.png (100%) rename {src => public}/assets/img/Weapon/LynelSword.png (100%) rename {src => public}/assets/img/Weapon/MasterSword.png (100%) rename {src => public}/assets/img/Weapon/MasterSwordAwakened.png (100%) rename {src => public}/assets/img/Weapon/MeteorRod.png (100%) rename {src => public}/assets/img/Weapon/MightyLynelCrusher.png (100%) rename {src => public}/assets/img/Weapon/MightyLynelSpear.png (100%) rename {src => public}/assets/img/Weapon/MightyLynelSword.png (100%) rename {src => public}/assets/img/Weapon/MoblinArm.png (100%) rename {src => public}/assets/img/Weapon/MoblinClub.png (100%) rename {src => public}/assets/img/Weapon/MoblinSpear.png (100%) rename {src => public}/assets/img/Weapon/MoonlightScimitar.png (100%) rename {src => public}/assets/img/Weapon/OneHitObliterator.png (100%) rename {src => public}/assets/img/Weapon/OneHitObliteratorCharged.png (100%) rename {src => public}/assets/img/Weapon/RoyalBroadsword.png (100%) rename {src => public}/assets/img/Weapon/RoyalClaymore.png (100%) rename {src => public}/assets/img/Weapon/RoyalGuardsClaymore.png (100%) rename {src => public}/assets/img/Weapon/RoyalGuardsSpear.png (100%) rename {src => public}/assets/img/Weapon/RoyalGuardsSword.png (100%) rename {src => public}/assets/img/Weapon/RoyalHalberd.png (100%) rename {src => public}/assets/img/Weapon/RustyBroadsword.png (100%) rename {src => public}/assets/img/Weapon/RustyClaymore.png (100%) rename {src => public}/assets/img/Weapon/RustyHalberd.png (100%) rename {src => public}/assets/img/Weapon/SavageLynelCrusher.png (100%) rename {src => public}/assets/img/Weapon/SavageLynelSpear.png (100%) rename {src => public}/assets/img/Weapon/SavageLynelSword.png (100%) rename {src => public}/assets/img/Weapon/ScimitarOfTheSeven.png (100%) rename {src => public}/assets/img/Weapon/SeaBreezeBoomerang.png (100%) rename {src => public}/assets/img/Weapon/SerpentineSpear.png (100%) rename {src => public}/assets/img/Weapon/SilverLongsword.png (100%) rename {src => public}/assets/img/Weapon/SilverscaleSpear.png (100%) rename {src => public}/assets/img/Weapon/SoldiersBroadsword.png (100%) rename {src => public}/assets/img/Weapon/SoldiersClaymore.png (100%) rename {src => public}/assets/img/Weapon/SoldiersSpear.png (100%) rename {src => public}/assets/img/Weapon/SoupLadle.png (100%) rename {src => public}/assets/img/Weapon/SpikedBokoBat.png (100%) rename {src => public}/assets/img/Weapon/SpikedBokoClub.png (100%) rename {src => public}/assets/img/Weapon/SpikedBokoSpear.png (100%) rename {src => public}/assets/img/Weapon/SpikedMoblinClub.png (100%) rename {src => public}/assets/img/Weapon/SpikedMoblinSpear.png (100%) rename {src => public}/assets/img/Weapon/SpringLoadedHammer.png (100%) rename {src => public}/assets/img/Weapon/StoneSmasher.png (100%) rename {src => public}/assets/img/Weapon/Sword.png (100%) rename {src => public}/assets/img/Weapon/SwordOfTheSixSages.png (100%) rename {src => public}/assets/img/Weapon/ThrowingSpear.png (100%) rename {src => public}/assets/img/Weapon/Thunderblade.png (100%) rename {src => public}/assets/img/Weapon/Thunderspear.png (100%) rename {src => public}/assets/img/Weapon/ThunderstormRod.png (100%) rename {src => public}/assets/img/Weapon/Torch.png (100%) rename {src => public}/assets/img/Weapon/TravelersClaymore.png (100%) rename {src => public}/assets/img/Weapon/TravelersSpear.png (100%) rename {src => public}/assets/img/Weapon/TravelersSword.png (100%) rename {src => public}/assets/img/Weapon/TreeBranch.png (100%) rename {src => public}/assets/img/Weapon/ViciousSickle.png (100%) create mode 100644 public/assets/img/Weapon/Weapon.png rename {src => public}/assets/img/Weapon/Windcleaver.png (100%) rename {src => public}/assets/img/Weapon/WoodcuttersAxe.png (100%) rename {src => public}/assets/img/Weapon/WoodenMop.png (100%) rename {src => public}/assets/img/Weapon/ZoraSpear.png (100%) rename {src => public}/assets/img/Weapon/ZoraSword.png (100%) create mode 100644 src/__tests__/README.md create mode 100644 src/__tests__/empty.e2e.ts create mode 100644 src/__tests__/empty.in.txt create mode 100644 src/__tests__/empty.out.txt create mode 100644 src/__tests__/goldrush_10reload22drop.e2e.ts create mode 100644 src/__tests__/goldrush_10reload22drop.in.txt create mode 100644 src/__tests__/goldrush_10reload22drop.out.txt delete mode 100644 src/assets/Crash.png delete mode 100644 src/assets/img/index.ts create mode 100644 src/components/CrashScreen.tsx create mode 100644 src/components/LoadingScreen.tsx create mode 100644 src/components/Text.tsx delete mode 100644 src/config/i18n/en_US.json delete mode 100644 src/config/items.json delete mode 100644 src/core/Item.ts delete mode 100644 src/core/Parser.ts create mode 100644 src/core/Slots.add.test.ts create mode 100644 src/core/SlotsTestHelpers.ts create mode 100644 src/core/command/CommandHint.ts create mode 100644 src/core/command/CommandWrite.ts rename src/core/{Command.ts => command/Commands.ts} (54%) create mode 100644 src/core/command/ItemStackCommandWrapper.ts create mode 100644 src/core/command/Parser.ts create mode 100644 src/core/command/helper.ts create mode 100644 src/core/command/index.ts create mode 100644 src/core/command/type.ts create mode 100644 src/data/i18n/LanguageProvider.tsx create mode 100644 src/data/i18n/en.lang.yaml create mode 100644 src/data/i18n/index.ts create mode 100644 src/data/item/Item.ts create mode 100644 src/data/item/ItemProvider.tsx create mode 100644 src/data/item/ItemStack.ts create mode 100644 src/data/item/all.items.yaml create mode 100644 src/data/item/index.ts create mode 100644 src/data/item/items.yaml.d.ts create mode 100644 src/data/item/legacy.ts create mode 100644 src/data/item/meta.ts create mode 100644 src/data/item/type.ts create mode 100644 src/data/measurePerformance.ts rename src/data/{mergeSort.ts => stableSort.ts} (100%) create mode 100644 src/data/tokenize.ts create mode 100644 src/surfaces/GalleryPage.tsx create mode 100644 src/surfaces/LimitationPage.tsx diff --git a/.github/workflows/main_deploy.yml b/.github/workflows/main_deploy.yml index d275048..87c8ef1 100644 --- a/.github/workflows/main_deploy.yml +++ b/.github/workflows/main_deploy.yml @@ -33,7 +33,7 @@ jobs: - name: Lint run: just lint --verbose - name: Test (WIP) - run: echo "No tests ran" + run: npm run test-all -- --watchAll=false - name: Build run: npm run build - name: Deploy diff --git a/.github/workflows/main_push.yml b/.github/workflows/main_push.yml index d008d28..9f3f729 100644 --- a/.github/workflows/main_push.yml +++ b/.github/workflows/main_push.yml @@ -35,7 +35,7 @@ jobs: run: npm ci - name: Lint run: just lint --verbose - - name: Test (WIP) - run: echo "No tests ran" + - name: Test + run: npm run test-all -- --watchAll=false - name: Build run: npm run build diff --git a/.gitignore b/.gitignore index 6704566..ae4f250 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,5 @@ dist # TernJS port file .tern-port + +build diff --git a/Justfile b/Justfile index 198e503..8eda884 100644 --- a/Justfile +++ b/Justfile @@ -1,12 +1,10 @@ -deploy: - rm -rf docs/ - npm run build - mv -T build docs - git add . - git commit -m "Local Build Deployment" - git push - lint VERBOSE="": pylint scripts python3 scripts/lint.py {{VERBOSE}} npm run lint + +test: + npm run test + +# make sure this passes before you PR +check: lint test diff --git a/config/webpack.config.js b/config/webpack.config.js index 37cf856..eb9395a 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -25,6 +25,9 @@ const ForkTsCheckerWebpackPlugin = ? require('react-dev-utils/ForkTsCheckerWarningWebpackPlugin') : require('react-dev-utils/ForkTsCheckerWebpackPlugin'); const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +const enableBundleAnalyzerPlugin = false; const createEnvironmentHash = require('./webpack/persistentCache/createEnvironmentHash'); @@ -85,6 +88,7 @@ const hasJsxRuntime = (() => { } })(); + // This is the production and development configuration. // It is focused on developer experience, fast rebuilds, and a minimal bundle. module.exports = function (webpackEnv) { @@ -551,6 +555,10 @@ module.exports = function (webpackEnv) { 'sass-loader' ), }, + { + test: /\.ya?ml$/, + use: 'yaml-loader' + }, // "file" loader makes sure those assets get served by WebpackDevServer. // When you `import` an asset, you get its (virtual) filename. // In production, they would get copied to the `build` folder. @@ -755,6 +763,7 @@ module.exports = function (webpackEnv) { }, }, }), + enableBundleAnalyzerPlugin && new BundleAnalyzerPlugin() ].filter(Boolean), // Turn off performance processing because we utilize // our own hints via the FileSizeReporter diff --git a/package-lock.json b/package-lock.json index 68c3f25..f9f4115 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "botw-hundo-dupl", - "version": "0.1.0", + "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "botw-hundo-dupl", - "version": "0.1.0", + "version": "1.0.0", "dependencies": { "@babel/core": "^7.16.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", @@ -67,7 +67,12 @@ "webpack": "^5.64.4", "webpack-dev-server": "^4.6.0", "webpack-manifest-plugin": "^4.0.2", - "workbox-webpack-plugin": "^6.4.1" + "workbox-webpack-plugin": "^6.4.1", + "yaml": "^2.1.1", + "yaml-loader": "^0.8.0" + }, + "devDependencies": { + "webpack-bundle-analyzer": "^4.5.0" } }, "node_modules/@ampproject/remapping": { @@ -3034,6 +3039,12 @@ } } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", + "dev": true + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -5701,6 +5712,14 @@ "node": ">=10" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -6062,6 +6081,14 @@ "postcss": "^8.2.15" } }, + "node_modules/cssnano/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/csso": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", @@ -7878,6 +7905,14 @@ "node": ">=6" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", @@ -9126,6 +9161,11 @@ "node": ">=8" } }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==" + }, "node_modules/jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", @@ -11545,6 +11585,15 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, + "node_modules/mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -11840,6 +11889,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -12632,6 +12690,14 @@ } } }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/postcss-loader": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", @@ -14376,6 +14442,20 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/sirv": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^1.0.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -15057,6 +15137,15 @@ "node": ">=0.6" } }, + "node_modules/totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", @@ -15462,6 +15551,117 @@ } } }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", + "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "dev": true, + "dependencies": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/webpack-dev-middleware": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", @@ -16223,11 +16423,24 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz", + "integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==", "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/yaml-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/yaml-loader/-/yaml-loader-0.8.0.tgz", + "integrity": "sha512-LjeKnTzVBKWiQBeE2L9ssl6WprqaUIxCSNs5tle8PaDydgu3wVFXTbMfsvF2MSErpy9TDVa092n4q6adYwJaWg==", + "dependencies": { + "javascript-stringify": "^2.0.1", + "loader-utils": "^2.0.0", + "yaml": "^2.0.0" + }, + "engines": { + "node": ">= 12.13" } }, "node_modules/yargs": { @@ -18269,6 +18482,12 @@ "source-map": "^0.7.3" } }, + "@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", + "dev": true + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -20225,6 +20444,13 @@ "parse-json": "^5.0.0", "path-type": "^4.0.0", "yaml": "^1.10.0" + }, + "dependencies": { + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + } } }, "cross-spawn": { @@ -20413,6 +20639,13 @@ "cssnano-preset-default": "^5.2.12", "lilconfig": "^2.0.3", "yaml": "^1.10.2" + }, + "dependencies": { + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + } } }, "cssnano-preset-default": { @@ -21784,6 +22017,11 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" } } }, @@ -22648,6 +22886,11 @@ } } }, + "javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==" + }, "jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", @@ -24423,6 +24666,12 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, + "mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -24631,6 +24880,12 @@ "is-wsl": "^2.2.0" } }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -25107,6 +25362,13 @@ "requires": { "lilconfig": "^2.0.5", "yaml": "^1.10.2" + }, + "dependencies": { + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + } } }, "postcss-loader": { @@ -26306,6 +26568,17 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "sirv": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "dev": true, + "requires": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^1.0.0" + } + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -26802,6 +27075,12 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "dev": true + }, "tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", @@ -27122,6 +27401,86 @@ } } }, + "webpack-bundle-analyzer": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", + "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "dev": true, + "requires": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "dependencies": { + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "webpack-dev-middleware": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", @@ -27709,9 +28068,19 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz", + "integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==" + }, + "yaml-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/yaml-loader/-/yaml-loader-0.8.0.tgz", + "integrity": "sha512-LjeKnTzVBKWiQBeE2L9ssl6WprqaUIxCSNs5tle8PaDydgu3wVFXTbMfsvF2MSErpy9TDVa092n4q6adYwJaWg==", + "requires": { + "javascript-stringify": "^2.0.1", + "loader-utils": "^2.0.0", + "yaml": "^2.0.0" + } }, "yargs": { "version": "16.2.0", diff --git a/package.json b/package.json index 3780659..6af1201 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "botw-hundo-dupl", - "version": "1.0.0", + "version": "2.0.0", "homepage": "https://dupl.itntpiston.app/", "private": true, "dependencies": { @@ -63,12 +63,15 @@ "webpack": "^5.64.4", "webpack-dev-server": "^4.6.0", "webpack-manifest-plugin": "^4.0.2", - "workbox-webpack-plugin": "^6.4.1" + "workbox-webpack-plugin": "^6.4.1", + "yaml": "^2.1.1", + "yaml-loader": "^0.8.0" }, "scripts": { "start": "node scripts/start.js", "build": "node scripts/build.js", - "test": "node scripts/test.js", + "test-all": "node scripts/test.js", + "test": "node scripts/test.js test.ts", "lint": "eslint src --ext .ts,.tsx --max-warnings 0" }, "eslintConfig": { @@ -120,7 +123,10 @@ "modulePaths": [], "moduleNameMapper": { "^react-native$": "react-native-web", - "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy" + "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy", + "^data/(.*)$": "/src/data/$1", + "^components/(.*)$": "/src/components/$1", + "^core/(.*)$": "/src/core/$1" }, "moduleFileExtensions": [ "web.js", @@ -144,5 +150,8 @@ "presets": [ "react-app" ] + }, + "devDependencies": { + "webpack-bundle-analyzer": "^4.5.0" } } diff --git a/src/assets/img/Armor/AmberEarrings.png b/public/assets/img/Armor/AmberEarrings.png similarity index 100% rename from src/assets/img/Armor/AmberEarrings.png rename to public/assets/img/Armor/AmberEarrings.png diff --git a/src/assets/img/Armor/AncientCuirass.png b/public/assets/img/Armor/AncientCuirass.png similarity index 100% rename from src/assets/img/Armor/AncientCuirass.png rename to public/assets/img/Armor/AncientCuirass.png diff --git a/src/assets/img/Armor/AncientGreaves.png b/public/assets/img/Armor/AncientGreaves.png similarity index 100% rename from src/assets/img/Armor/AncientGreaves.png rename to public/assets/img/Armor/AncientGreaves.png diff --git a/src/assets/img/Armor/AncientHelm.png b/public/assets/img/Armor/AncientHelm.png similarity index 100% rename from src/assets/img/Armor/AncientHelm.png rename to public/assets/img/Armor/AncientHelm.png diff --git a/src/assets/img/Armor/BarbarianArmor.png b/public/assets/img/Armor/BarbarianArmor.png similarity index 100% rename from src/assets/img/Armor/BarbarianArmor.png rename to public/assets/img/Armor/BarbarianArmor.png diff --git a/src/assets/img/Armor/BarbarianHelm.png b/public/assets/img/Armor/BarbarianHelm.png similarity index 100% rename from src/assets/img/Armor/BarbarianHelm.png rename to public/assets/img/Armor/BarbarianHelm.png diff --git a/src/assets/img/Armor/BarbarianLegWraps.png b/public/assets/img/Armor/BarbarianLegWraps.png similarity index 100% rename from src/assets/img/Armor/BarbarianLegWraps.png rename to public/assets/img/Armor/BarbarianLegWraps.png diff --git a/src/assets/img/Armor/BokoblinMask.png b/public/assets/img/Armor/BokoblinMask.png similarity index 100% rename from src/assets/img/Armor/BokoblinMask.png rename to public/assets/img/Armor/BokoblinMask.png diff --git a/src/assets/img/Armor/CapOfTheHero.png b/public/assets/img/Armor/CapOfTheHero.png similarity index 100% rename from src/assets/img/Armor/CapOfTheHero.png rename to public/assets/img/Armor/CapOfTheHero.png diff --git a/src/assets/img/Armor/CapOfTheSky.png b/public/assets/img/Armor/CapOfTheSky.png similarity index 100% rename from src/assets/img/Armor/CapOfTheSky.png rename to public/assets/img/Armor/CapOfTheSky.png diff --git a/src/assets/img/Armor/CapOfTheWild.png b/public/assets/img/Armor/CapOfTheWild.png similarity index 100% rename from src/assets/img/Armor/CapOfTheWild.png rename to public/assets/img/Armor/CapOfTheWild.png diff --git a/src/assets/img/Armor/CapOfTheWind.png b/public/assets/img/Armor/CapOfTheWind.png similarity index 100% rename from src/assets/img/Armor/CapOfTheWind.png rename to public/assets/img/Armor/CapOfTheWind.png diff --git a/src/assets/img/Armor/CapOfTime.png b/public/assets/img/Armor/CapOfTime.png similarity index 100% rename from src/assets/img/Armor/CapOfTime.png rename to public/assets/img/Armor/CapOfTime.png diff --git a/src/assets/img/Armor/CapOfTwilight.png b/public/assets/img/Armor/CapOfTwilight.png similarity index 100% rename from src/assets/img/Armor/CapOfTwilight.png rename to public/assets/img/Armor/CapOfTwilight.png diff --git a/src/assets/img/Armor/ChampionsTunic.png b/public/assets/img/Armor/ChampionsTunic.png similarity index 100% rename from src/assets/img/Armor/ChampionsTunic.png rename to public/assets/img/Armor/ChampionsTunic.png diff --git a/src/assets/img/Armor/ClimbersBandanna.png b/public/assets/img/Armor/ClimbersBandanna.png similarity index 100% rename from src/assets/img/Armor/ClimbersBandanna.png rename to public/assets/img/Armor/ClimbersBandanna.png diff --git a/src/assets/img/Armor/ClimbingBoots.png b/public/assets/img/Armor/ClimbingBoots.png similarity index 100% rename from src/assets/img/Armor/ClimbingBoots.png rename to public/assets/img/Armor/ClimbingBoots.png diff --git a/src/assets/img/Armor/ClimbingGear.png b/public/assets/img/Armor/ClimbingGear.png similarity index 100% rename from src/assets/img/Armor/ClimbingGear.png rename to public/assets/img/Armor/ClimbingGear.png diff --git a/src/assets/img/Armor/DarkHood.png b/public/assets/img/Armor/DarkHood.png similarity index 100% rename from src/assets/img/Armor/DarkHood.png rename to public/assets/img/Armor/DarkHood.png diff --git a/src/assets/img/Armor/DarkTrousers.png b/public/assets/img/Armor/DarkTrousers.png similarity index 100% rename from src/assets/img/Armor/DarkTrousers.png rename to public/assets/img/Armor/DarkTrousers.png diff --git a/src/assets/img/Armor/DarkTunic.png b/public/assets/img/Armor/DarkTunic.png similarity index 100% rename from src/assets/img/Armor/DarkTunic.png rename to public/assets/img/Armor/DarkTunic.png diff --git a/src/assets/img/Armor/DesertVoeHeadband.png b/public/assets/img/Armor/DesertVoeHeadband.png similarity index 100% rename from src/assets/img/Armor/DesertVoeHeadband.png rename to public/assets/img/Armor/DesertVoeHeadband.png diff --git a/src/assets/img/Armor/DesertVoeSpaulder.png b/public/assets/img/Armor/DesertVoeSpaulder.png similarity index 100% rename from src/assets/img/Armor/DesertVoeSpaulder.png rename to public/assets/img/Armor/DesertVoeSpaulder.png diff --git a/src/assets/img/Armor/DesertVoeTrousers.png b/public/assets/img/Armor/DesertVoeTrousers.png similarity index 100% rename from src/assets/img/Armor/DesertVoeTrousers.png rename to public/assets/img/Armor/DesertVoeTrousers.png diff --git a/src/assets/img/Armor/DiamondCirclet.png b/public/assets/img/Armor/DiamondCirclet.png similarity index 100% rename from src/assets/img/Armor/DiamondCirclet.png rename to public/assets/img/Armor/DiamondCirclet.png diff --git a/src/assets/img/Armor/FierceDeityArmor.png b/public/assets/img/Armor/FierceDeityArmor.png similarity index 100% rename from src/assets/img/Armor/FierceDeityArmor.png rename to public/assets/img/Armor/FierceDeityArmor.png diff --git a/src/assets/img/Armor/FierceDeityBoots.png b/public/assets/img/Armor/FierceDeityBoots.png similarity index 100% rename from src/assets/img/Armor/FierceDeityBoots.png rename to public/assets/img/Armor/FierceDeityBoots.png diff --git a/src/assets/img/Armor/FierceDeityMask.png b/public/assets/img/Armor/FierceDeityMask.png similarity index 100% rename from src/assets/img/Armor/FierceDeityMask.png rename to public/assets/img/Armor/FierceDeityMask.png diff --git a/src/assets/img/Armor/FlamebreakerArmor.png b/public/assets/img/Armor/FlamebreakerArmor.png similarity index 100% rename from src/assets/img/Armor/FlamebreakerArmor.png rename to public/assets/img/Armor/FlamebreakerArmor.png diff --git a/src/assets/img/Armor/FlamebreakerBoots.png b/public/assets/img/Armor/FlamebreakerBoots.png similarity index 100% rename from src/assets/img/Armor/FlamebreakerBoots.png rename to public/assets/img/Armor/FlamebreakerBoots.png diff --git a/src/assets/img/Armor/FlamebreakerHelm.png b/public/assets/img/Armor/FlamebreakerHelm.png similarity index 100% rename from src/assets/img/Armor/FlamebreakerHelm.png rename to public/assets/img/Armor/FlamebreakerHelm.png diff --git a/src/assets/img/Armor/GerudoSirwal.png b/public/assets/img/Armor/GerudoSirwal.png similarity index 100% rename from src/assets/img/Armor/GerudoSirwal.png rename to public/assets/img/Armor/GerudoSirwal.png diff --git a/src/assets/img/Armor/GerudoTop.png b/public/assets/img/Armor/GerudoTop.png similarity index 100% rename from src/assets/img/Armor/GerudoTop.png rename to public/assets/img/Armor/GerudoTop.png diff --git a/src/assets/img/Armor/GerudoVeil.png b/public/assets/img/Armor/GerudoVeil.png similarity index 100% rename from src/assets/img/Armor/GerudoVeil.png rename to public/assets/img/Armor/GerudoVeil.png diff --git a/src/assets/img/Armor/HylianHood.png b/public/assets/img/Armor/HylianHood.png similarity index 100% rename from src/assets/img/Armor/HylianHood.png rename to public/assets/img/Armor/HylianHood.png diff --git a/src/assets/img/Armor/HylianTrousers.png b/public/assets/img/Armor/HylianTrousers.png similarity index 100% rename from src/assets/img/Armor/HylianTrousers.png rename to public/assets/img/Armor/HylianTrousers.png diff --git a/src/assets/img/Armor/HylianTunic.png b/public/assets/img/Armor/HylianTunic.png similarity index 100% rename from src/assets/img/Armor/HylianTunic.png rename to public/assets/img/Armor/HylianTunic.png diff --git a/src/assets/img/Armor/IslandLobsterShirt.png b/public/assets/img/Armor/IslandLobsterShirt.png similarity index 100% rename from src/assets/img/Armor/IslandLobsterShirt.png rename to public/assets/img/Armor/IslandLobsterShirt.png diff --git a/src/assets/img/Armor/KorokMask.png b/public/assets/img/Armor/KorokMask.png similarity index 100% rename from src/assets/img/Armor/KorokMask.png rename to public/assets/img/Armor/KorokMask.png diff --git a/src/assets/img/Armor/LizalfosMask.png b/public/assets/img/Armor/LizalfosMask.png similarity index 100% rename from src/assets/img/Armor/LizalfosMask.png rename to public/assets/img/Armor/LizalfosMask.png diff --git a/src/assets/img/Armor/LynelMask.png b/public/assets/img/Armor/LynelMask.png similarity index 100% rename from src/assets/img/Armor/LynelMask.png rename to public/assets/img/Armor/LynelMask.png diff --git a/src/assets/img/Armor/MajorasMask.png b/public/assets/img/Armor/MajorasMask.png similarity index 100% rename from src/assets/img/Armor/MajorasMask.png rename to public/assets/img/Armor/MajorasMask.png diff --git a/src/assets/img/Armor/MidnasHelmet.png b/public/assets/img/Armor/MidnasHelmet.png similarity index 100% rename from src/assets/img/Armor/MidnasHelmet.png rename to public/assets/img/Armor/MidnasHelmet.png diff --git a/src/assets/img/Armor/MoblinMask.png b/public/assets/img/Armor/MoblinMask.png similarity index 100% rename from src/assets/img/Armor/MoblinMask.png rename to public/assets/img/Armor/MoblinMask.png diff --git a/src/assets/img/Armor/NintendoSwitchShirt.png b/public/assets/img/Armor/NintendoSwitchShirt.png similarity index 100% rename from src/assets/img/Armor/NintendoSwitchShirt.png rename to public/assets/img/Armor/NintendoSwitchShirt.png diff --git a/src/assets/img/Armor/OldShirt.png b/public/assets/img/Armor/OldShirt.png similarity index 100% rename from src/assets/img/Armor/OldShirt.png rename to public/assets/img/Armor/OldShirt.png diff --git a/src/assets/img/Armor/OpalEarrings.png b/public/assets/img/Armor/OpalEarrings.png similarity index 100% rename from src/assets/img/Armor/OpalEarrings.png rename to public/assets/img/Armor/OpalEarrings.png diff --git a/src/assets/img/Armor/PhantomArmor.png b/public/assets/img/Armor/PhantomArmor.png similarity index 100% rename from src/assets/img/Armor/PhantomArmor.png rename to public/assets/img/Armor/PhantomArmor.png diff --git a/src/assets/img/Armor/PhantomGanonArmor.png b/public/assets/img/Armor/PhantomGanonArmor.png similarity index 100% rename from src/assets/img/Armor/PhantomGanonArmor.png rename to public/assets/img/Armor/PhantomGanonArmor.png diff --git a/src/assets/img/Armor/PhantomGanonGreaves.png b/public/assets/img/Armor/PhantomGanonGreaves.png similarity index 100% rename from src/assets/img/Armor/PhantomGanonGreaves.png rename to public/assets/img/Armor/PhantomGanonGreaves.png diff --git a/src/assets/img/Armor/PhantomGanonSkull.png b/public/assets/img/Armor/PhantomGanonSkull.png similarity index 100% rename from src/assets/img/Armor/PhantomGanonSkull.png rename to public/assets/img/Armor/PhantomGanonSkull.png diff --git a/src/assets/img/Armor/PhantomGreaves.png b/public/assets/img/Armor/PhantomGreaves.png similarity index 100% rename from src/assets/img/Armor/PhantomGreaves.png rename to public/assets/img/Armor/PhantomGreaves.png diff --git a/src/assets/img/Armor/PhantomHelmet.png b/public/assets/img/Armor/PhantomHelmet.png similarity index 100% rename from src/assets/img/Armor/PhantomHelmet.png rename to public/assets/img/Armor/PhantomHelmet.png diff --git a/src/assets/img/Armor/RadiantMask.png b/public/assets/img/Armor/RadiantMask.png similarity index 100% rename from src/assets/img/Armor/RadiantMask.png rename to public/assets/img/Armor/RadiantMask.png diff --git a/src/assets/img/Armor/RadiantShirt.png b/public/assets/img/Armor/RadiantShirt.png similarity index 100% rename from src/assets/img/Armor/RadiantShirt.png rename to public/assets/img/Armor/RadiantShirt.png diff --git a/src/assets/img/Armor/RadiantTights.png b/public/assets/img/Armor/RadiantTights.png similarity index 100% rename from src/assets/img/Armor/RadiantTights.png rename to public/assets/img/Armor/RadiantTights.png diff --git a/src/assets/img/Armor/RaviosHood.png b/public/assets/img/Armor/RaviosHood.png similarity index 100% rename from src/assets/img/Armor/RaviosHood.png rename to public/assets/img/Armor/RaviosHood.png diff --git a/src/assets/img/Armor/RoyalGuardBoots.png b/public/assets/img/Armor/RoyalGuardBoots.png similarity index 100% rename from src/assets/img/Armor/RoyalGuardBoots.png rename to public/assets/img/Armor/RoyalGuardBoots.png diff --git a/src/assets/img/Armor/RoyalGuardCap.png b/public/assets/img/Armor/RoyalGuardCap.png similarity index 100% rename from src/assets/img/Armor/RoyalGuardCap.png rename to public/assets/img/Armor/RoyalGuardCap.png diff --git a/src/assets/img/Armor/RoyalGuardUniform.png b/public/assets/img/Armor/RoyalGuardUniform.png similarity index 100% rename from src/assets/img/Armor/RoyalGuardUniform.png rename to public/assets/img/Armor/RoyalGuardUniform.png diff --git a/src/assets/img/Armor/RubberArmor.png b/public/assets/img/Armor/RubberArmor.png similarity index 100% rename from src/assets/img/Armor/RubberArmor.png rename to public/assets/img/Armor/RubberArmor.png diff --git a/src/assets/img/Armor/RubberHelm.png b/public/assets/img/Armor/RubberHelm.png similarity index 100% rename from src/assets/img/Armor/RubberHelm.png rename to public/assets/img/Armor/RubberHelm.png diff --git a/src/assets/img/Armor/RubberTights.png b/public/assets/img/Armor/RubberTights.png similarity index 100% rename from src/assets/img/Armor/RubberTights.png rename to public/assets/img/Armor/RubberTights.png diff --git a/src/assets/img/Armor/RubyCirclet.png b/public/assets/img/Armor/RubyCirclet.png similarity index 100% rename from src/assets/img/Armor/RubyCirclet.png rename to public/assets/img/Armor/RubyCirclet.png diff --git a/src/assets/img/Armor/SalvagerHeadwear.png b/public/assets/img/Armor/SalvagerHeadwear.png similarity index 100% rename from src/assets/img/Armor/SalvagerHeadwear.png rename to public/assets/img/Armor/SalvagerHeadwear.png diff --git a/src/assets/img/Armor/SalvagerTrousers.png b/public/assets/img/Armor/SalvagerTrousers.png similarity index 100% rename from src/assets/img/Armor/SalvagerTrousers.png rename to public/assets/img/Armor/SalvagerTrousers.png diff --git a/src/assets/img/Armor/SalvagerVest.png b/public/assets/img/Armor/SalvagerVest.png similarity index 100% rename from src/assets/img/Armor/SalvagerVest.png rename to public/assets/img/Armor/SalvagerVest.png diff --git a/src/assets/img/Armor/SandBoots.png b/public/assets/img/Armor/SandBoots.png similarity index 100% rename from src/assets/img/Armor/SandBoots.png rename to public/assets/img/Armor/SandBoots.png diff --git a/src/assets/img/Armor/SapphireCirclet.png b/public/assets/img/Armor/SapphireCirclet.png similarity index 100% rename from src/assets/img/Armor/SapphireCirclet.png rename to public/assets/img/Armor/SapphireCirclet.png diff --git a/src/assets/img/Armor/SheiksMask.png b/public/assets/img/Armor/SheiksMask.png similarity index 100% rename from src/assets/img/Armor/SheiksMask.png rename to public/assets/img/Armor/SheiksMask.png diff --git a/src/assets/img/Armor/SnowBoots.png b/public/assets/img/Armor/SnowBoots.png similarity index 100% rename from src/assets/img/Armor/SnowBoots.png rename to public/assets/img/Armor/SnowBoots.png diff --git a/src/assets/img/Armor/SnowquillHeaddress.png b/public/assets/img/Armor/SnowquillHeaddress.png similarity index 100% rename from src/assets/img/Armor/SnowquillHeaddress.png rename to public/assets/img/Armor/SnowquillHeaddress.png diff --git a/src/assets/img/Armor/SnowquillTrousers.png b/public/assets/img/Armor/SnowquillTrousers.png similarity index 100% rename from src/assets/img/Armor/SnowquillTrousers.png rename to public/assets/img/Armor/SnowquillTrousers.png diff --git a/src/assets/img/Armor/SnowquillTunic.png b/public/assets/img/Armor/SnowquillTunic.png similarity index 100% rename from src/assets/img/Armor/SnowquillTunic.png rename to public/assets/img/Armor/SnowquillTunic.png diff --git a/src/assets/img/Armor/SoldiersArmor.png b/public/assets/img/Armor/SoldiersArmor.png similarity index 100% rename from src/assets/img/Armor/SoldiersArmor.png rename to public/assets/img/Armor/SoldiersArmor.png diff --git a/src/assets/img/Armor/SoldiersGreaves.png b/public/assets/img/Armor/SoldiersGreaves.png similarity index 100% rename from src/assets/img/Armor/SoldiersGreaves.png rename to public/assets/img/Armor/SoldiersGreaves.png diff --git a/src/assets/img/Armor/SoldiersHelm.png b/public/assets/img/Armor/SoldiersHelm.png similarity index 100% rename from src/assets/img/Armor/SoldiersHelm.png rename to public/assets/img/Armor/SoldiersHelm.png diff --git a/src/assets/img/Armor/StealthChestGuard.png b/public/assets/img/Armor/StealthChestGuard.png similarity index 100% rename from src/assets/img/Armor/StealthChestGuard.png rename to public/assets/img/Armor/StealthChestGuard.png diff --git a/src/assets/img/Armor/StealthMask.png b/public/assets/img/Armor/StealthMask.png similarity index 100% rename from src/assets/img/Armor/StealthMask.png rename to public/assets/img/Armor/StealthMask.png diff --git a/src/assets/img/Armor/StealthTights.png b/public/assets/img/Armor/StealthTights.png similarity index 100% rename from src/assets/img/Armor/StealthTights.png rename to public/assets/img/Armor/StealthTights.png diff --git a/src/assets/img/Armor/ThunderHelm.png b/public/assets/img/Armor/ThunderHelm.png similarity index 100% rename from src/assets/img/Armor/ThunderHelm.png rename to public/assets/img/Armor/ThunderHelm.png diff --git a/src/assets/img/Armor/TinglesHood.png b/public/assets/img/Armor/TinglesHood.png similarity index 100% rename from src/assets/img/Armor/TinglesHood.png rename to public/assets/img/Armor/TinglesHood.png diff --git a/src/assets/img/Armor/TinglesShirt.png b/public/assets/img/Armor/TinglesShirt.png similarity index 100% rename from src/assets/img/Armor/TinglesShirt.png rename to public/assets/img/Armor/TinglesShirt.png diff --git a/src/assets/img/Armor/TinglesTights.png b/public/assets/img/Armor/TinglesTights.png similarity index 100% rename from src/assets/img/Armor/TinglesTights.png rename to public/assets/img/Armor/TinglesTights.png diff --git a/src/assets/img/Armor/TopazEarrings.png b/public/assets/img/Armor/TopazEarrings.png similarity index 100% rename from src/assets/img/Armor/TopazEarrings.png rename to public/assets/img/Armor/TopazEarrings.png diff --git a/src/assets/img/Armor/TrousersOfTheHero.png b/public/assets/img/Armor/TrousersOfTheHero.png similarity index 100% rename from src/assets/img/Armor/TrousersOfTheHero.png rename to public/assets/img/Armor/TrousersOfTheHero.png diff --git a/src/assets/img/Armor/TrousersOfTheSky.png b/public/assets/img/Armor/TrousersOfTheSky.png similarity index 100% rename from src/assets/img/Armor/TrousersOfTheSky.png rename to public/assets/img/Armor/TrousersOfTheSky.png diff --git a/src/assets/img/Armor/TrousersOfTheWild.png b/public/assets/img/Armor/TrousersOfTheWild.png similarity index 100% rename from src/assets/img/Armor/TrousersOfTheWild.png rename to public/assets/img/Armor/TrousersOfTheWild.png diff --git a/src/assets/img/Armor/TrousersOfTheWind.png b/public/assets/img/Armor/TrousersOfTheWind.png similarity index 100% rename from src/assets/img/Armor/TrousersOfTheWind.png rename to public/assets/img/Armor/TrousersOfTheWind.png diff --git a/src/assets/img/Armor/TrousersOfTime.png b/public/assets/img/Armor/TrousersOfTime.png similarity index 100% rename from src/assets/img/Armor/TrousersOfTime.png rename to public/assets/img/Armor/TrousersOfTime.png diff --git a/src/assets/img/Armor/TrousersOfTwilight.png b/public/assets/img/Armor/TrousersOfTwilight.png similarity index 100% rename from src/assets/img/Armor/TrousersOfTwilight.png rename to public/assets/img/Armor/TrousersOfTwilight.png diff --git a/src/assets/img/Armor/TunicOfTheHero.png b/public/assets/img/Armor/TunicOfTheHero.png similarity index 100% rename from src/assets/img/Armor/TunicOfTheHero.png rename to public/assets/img/Armor/TunicOfTheHero.png diff --git a/src/assets/img/Armor/TunicOfTheSky.png b/public/assets/img/Armor/TunicOfTheSky.png similarity index 100% rename from src/assets/img/Armor/TunicOfTheSky.png rename to public/assets/img/Armor/TunicOfTheSky.png diff --git a/src/assets/img/Armor/TunicOfTheWild.png b/public/assets/img/Armor/TunicOfTheWild.png similarity index 100% rename from src/assets/img/Armor/TunicOfTheWild.png rename to public/assets/img/Armor/TunicOfTheWild.png diff --git a/src/assets/img/Armor/TunicOfTheWind.png b/public/assets/img/Armor/TunicOfTheWind.png similarity index 100% rename from src/assets/img/Armor/TunicOfTheWind.png rename to public/assets/img/Armor/TunicOfTheWind.png diff --git a/src/assets/img/Armor/TunicOfTime.png b/public/assets/img/Armor/TunicOfTime.png similarity index 100% rename from src/assets/img/Armor/TunicOfTime.png rename to public/assets/img/Armor/TunicOfTime.png diff --git a/src/assets/img/Armor/TunicOfTwilight.png b/public/assets/img/Armor/TunicOfTwilight.png similarity index 100% rename from src/assets/img/Armor/TunicOfTwilight.png rename to public/assets/img/Armor/TunicOfTwilight.png diff --git a/src/assets/img/Armor/VahMedohDivineHelm.png b/public/assets/img/Armor/VahMedohDivineHelm.png similarity index 100% rename from src/assets/img/Armor/VahMedohDivineHelm.png rename to public/assets/img/Armor/VahMedohDivineHelm.png diff --git a/src/assets/img/Armor/VahNaborisDivineHelm.png b/public/assets/img/Armor/VahNaborisDivineHelm.png similarity index 100% rename from src/assets/img/Armor/VahNaborisDivineHelm.png rename to public/assets/img/Armor/VahNaborisDivineHelm.png diff --git a/src/assets/img/Armor/VahRudaniaDivineHelm.png b/public/assets/img/Armor/VahRudaniaDivineHelm.png similarity index 100% rename from src/assets/img/Armor/VahRudaniaDivineHelm.png rename to public/assets/img/Armor/VahRudaniaDivineHelm.png diff --git a/src/assets/img/Armor/VahRutaDivineHelm.png b/public/assets/img/Armor/VahRutaDivineHelm.png similarity index 100% rename from src/assets/img/Armor/VahRutaDivineHelm.png rename to public/assets/img/Armor/VahRutaDivineHelm.png diff --git a/src/assets/img/Armor/WarmDoublet.png b/public/assets/img/Armor/WarmDoublet.png similarity index 100% rename from src/assets/img/Armor/WarmDoublet.png rename to public/assets/img/Armor/WarmDoublet.png diff --git a/src/assets/img/Armor/WellWornTrousers.png b/public/assets/img/Armor/WellWornTrousers.png similarity index 100% rename from src/assets/img/Armor/WellWornTrousers.png rename to public/assets/img/Armor/WellWornTrousers.png diff --git a/src/assets/img/Armor/ZantsHelmet.png b/public/assets/img/Armor/ZantsHelmet.png similarity index 100% rename from src/assets/img/Armor/ZantsHelmet.png rename to public/assets/img/Armor/ZantsHelmet.png diff --git a/src/assets/img/Armor/ZoraArmor.png b/public/assets/img/Armor/ZoraArmor.png similarity index 100% rename from src/assets/img/Armor/ZoraArmor.png rename to public/assets/img/Armor/ZoraArmor.png diff --git a/src/assets/img/Armor/ZoraGreaves.png b/public/assets/img/Armor/ZoraGreaves.png similarity index 100% rename from src/assets/img/Armor/ZoraGreaves.png rename to public/assets/img/Armor/ZoraGreaves.png diff --git a/src/assets/img/Armor/ZoraHelm.png b/public/assets/img/Armor/ZoraHelm.png similarity index 100% rename from src/assets/img/Armor/ZoraHelm.png rename to public/assets/img/Armor/ZoraHelm.png diff --git a/src/assets/img/Arrow/AncientArrow.png b/public/assets/img/Arrow/AncientArrow.png similarity index 100% rename from src/assets/img/Arrow/AncientArrow.png rename to public/assets/img/Arrow/AncientArrow.png diff --git a/src/assets/img/Arrow/BombArrow.png b/public/assets/img/Arrow/BombArrow.png similarity index 100% rename from src/assets/img/Arrow/BombArrow.png rename to public/assets/img/Arrow/BombArrow.png diff --git a/src/assets/img/Arrow/FireArrow.png b/public/assets/img/Arrow/FireArrow.png similarity index 100% rename from src/assets/img/Arrow/FireArrow.png rename to public/assets/img/Arrow/FireArrow.png diff --git a/src/assets/img/Arrow/IceArrow.png b/public/assets/img/Arrow/IceArrow.png similarity index 100% rename from src/assets/img/Arrow/IceArrow.png rename to public/assets/img/Arrow/IceArrow.png diff --git a/src/assets/img/Arrow/Arrow.png b/public/assets/img/Arrow/NormalArrow.png similarity index 100% rename from src/assets/img/Arrow/Arrow.png rename to public/assets/img/Arrow/NormalArrow.png diff --git a/src/assets/img/Arrow/ShockArrow.png b/public/assets/img/Arrow/ShockArrow.png similarity index 100% rename from src/assets/img/Arrow/ShockArrow.png rename to public/assets/img/Arrow/ShockArrow.png diff --git a/src/assets/img/Bow/AncientBow.png b/public/assets/img/Bow/AncientBow.png similarity index 100% rename from src/assets/img/Bow/AncientBow.png rename to public/assets/img/Bow/AncientBow.png diff --git a/src/assets/img/Bow/BokoBow.png b/public/assets/img/Bow/BokoBow.png similarity index 100% rename from src/assets/img/Bow/BokoBow.png rename to public/assets/img/Bow/BokoBow.png diff --git a/public/assets/img/Bow/Bow.png b/public/assets/img/Bow/Bow.png new file mode 100644 index 0000000000000000000000000000000000000000..8dcbc1dce3e8d058c9903bed68822b61c4face24 GIT binary patch literal 21108 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�!2+7oko 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 literal 0 HcmV?d00001 diff --git a/src/assets/img/Bow/BowOfLight.png b/public/assets/img/Bow/BowOfLight.png similarity index 100% rename from src/assets/img/Bow/BowOfLight.png rename to public/assets/img/Bow/BowOfLight.png diff --git a/src/assets/img/Bow/DragonBoneBokoBow.png b/public/assets/img/Bow/DragonBoneBokoBow.png similarity index 100% rename from src/assets/img/Bow/DragonBoneBokoBow.png rename to public/assets/img/Bow/DragonBoneBokoBow.png diff --git a/src/assets/img/Bow/DuplexBow.png b/public/assets/img/Bow/DuplexBow.png similarity index 100% rename from src/assets/img/Bow/DuplexBow.png rename to public/assets/img/Bow/DuplexBow.png diff --git a/src/assets/img/Bow/FalconBow.png b/public/assets/img/Bow/FalconBow.png similarity index 100% rename from src/assets/img/Bow/FalconBow.png rename to public/assets/img/Bow/FalconBow.png diff --git a/src/assets/img/Bow/ForestDwellersBow.png b/public/assets/img/Bow/ForestDwellersBow.png similarity index 100% rename from src/assets/img/Bow/ForestDwellersBow.png rename to public/assets/img/Bow/ForestDwellersBow.png diff --git a/src/assets/img/Bow/GoldenBow.png b/public/assets/img/Bow/GoldenBow.png similarity index 100% rename from src/assets/img/Bow/GoldenBow.png rename to public/assets/img/Bow/GoldenBow.png diff --git a/src/assets/img/Bow/GreatEagleBow.png b/public/assets/img/Bow/GreatEagleBow.png similarity index 100% rename from src/assets/img/Bow/GreatEagleBow.png rename to public/assets/img/Bow/GreatEagleBow.png diff --git a/src/assets/img/Bow/KnightsBow.png b/public/assets/img/Bow/KnightsBow.png similarity index 100% rename from src/assets/img/Bow/KnightsBow.png rename to public/assets/img/Bow/KnightsBow.png diff --git a/src/assets/img/Bow/LizalBow.png b/public/assets/img/Bow/LizalBow.png similarity index 100% rename from src/assets/img/Bow/LizalBow.png rename to public/assets/img/Bow/LizalBow.png diff --git a/src/assets/img/Bow/LynelBow.png b/public/assets/img/Bow/LynelBow.png similarity index 100% rename from src/assets/img/Bow/LynelBow.png rename to public/assets/img/Bow/LynelBow.png diff --git a/src/assets/img/Bow/MightyLynelBow.png b/public/assets/img/Bow/MightyLynelBow.png similarity index 100% rename from src/assets/img/Bow/MightyLynelBow.png rename to public/assets/img/Bow/MightyLynelBow.png diff --git a/src/assets/img/Bow/PhrenicBow.png b/public/assets/img/Bow/PhrenicBow.png similarity index 100% rename from src/assets/img/Bow/PhrenicBow.png rename to public/assets/img/Bow/PhrenicBow.png diff --git a/src/assets/img/Bow/RoyalBow.png b/public/assets/img/Bow/RoyalBow.png similarity index 100% rename from src/assets/img/Bow/RoyalBow.png rename to public/assets/img/Bow/RoyalBow.png diff --git a/src/assets/img/Bow/RoyalGuardsBow.png b/public/assets/img/Bow/RoyalGuardsBow.png similarity index 100% rename from src/assets/img/Bow/RoyalGuardsBow.png rename to public/assets/img/Bow/RoyalGuardsBow.png diff --git a/src/assets/img/Bow/SavageLynelBow.png b/public/assets/img/Bow/SavageLynelBow.png similarity index 100% rename from src/assets/img/Bow/SavageLynelBow.png rename to public/assets/img/Bow/SavageLynelBow.png diff --git a/src/assets/img/Bow/SilverBow.png b/public/assets/img/Bow/SilverBow.png similarity index 100% rename from src/assets/img/Bow/SilverBow.png rename to public/assets/img/Bow/SilverBow.png diff --git a/src/assets/img/Bow/SoldiersBow.png b/public/assets/img/Bow/SoldiersBow.png similarity index 100% rename from src/assets/img/Bow/SoldiersBow.png rename to public/assets/img/Bow/SoldiersBow.png diff --git a/src/assets/img/Bow/SpikedBokoBow.png b/public/assets/img/Bow/SpikedBokoBow.png similarity index 100% rename from src/assets/img/Bow/SpikedBokoBow.png rename to public/assets/img/Bow/SpikedBokoBow.png diff --git a/src/assets/img/Bow/SteelLizalBow.png b/public/assets/img/Bow/SteelLizalBow.png similarity index 100% rename from src/assets/img/Bow/SteelLizalBow.png rename to public/assets/img/Bow/SteelLizalBow.png diff --git a/src/assets/img/Bow/StrengthenedLizalBow.png b/public/assets/img/Bow/StrengthenedLizalBow.png similarity index 100% rename from src/assets/img/Bow/StrengthenedLizalBow.png rename to public/assets/img/Bow/StrengthenedLizalBow.png diff --git a/src/assets/img/Bow/SwallowBow.png b/public/assets/img/Bow/SwallowBow.png similarity index 100% rename from src/assets/img/Bow/SwallowBow.png rename to public/assets/img/Bow/SwallowBow.png diff --git a/src/assets/img/Bow/TravelersBow.png b/public/assets/img/Bow/TravelersBow.png similarity index 100% rename from src/assets/img/Bow/TravelersBow.png rename to public/assets/img/Bow/TravelersBow.png diff --git a/src/assets/img/Bow/TwilightBow.png b/public/assets/img/Bow/TwilightBow.png similarity index 100% rename from src/assets/img/Bow/TwilightBow.png rename to public/assets/img/Bow/TwilightBow.png diff --git a/src/assets/img/Bow/WoodenBow.png b/public/assets/img/Bow/WoodenBow.png similarity index 100% rename from src/assets/img/Bow/WoodenBow.png rename to public/assets/img/Bow/WoodenBow.png diff --git a/src/assets/img/Food/ApplePie.png b/public/assets/img/Food/ApplePie.png similarity index 100% rename from src/assets/img/Food/ApplePie.png rename to public/assets/img/Food/ApplePie.png diff --git a/src/assets/img/Food/BakedApple.png b/public/assets/img/Food/BakedApple.png similarity index 100% rename from src/assets/img/Food/BakedApple.png rename to public/assets/img/Food/BakedApple.png diff --git a/src/assets/img/Food/BakedFortifiedPumpkin.png b/public/assets/img/Food/BakedFortifiedPumpkin.png similarity index 100% rename from src/assets/img/Food/BakedFortifiedPumpkin.png rename to public/assets/img/Food/BakedFortifiedPumpkin.png diff --git a/src/assets/img/Food/BakedPalmFruit.png b/public/assets/img/Food/BakedPalmFruit.png similarity index 100% rename from src/assets/img/Food/BakedPalmFruit.png rename to public/assets/img/Food/BakedPalmFruit.png diff --git a/src/assets/img/Food/BlackenedCrab.png b/public/assets/img/Food/BlackenedCrab.png similarity index 100% rename from src/assets/img/Food/BlackenedCrab.png rename to public/assets/img/Food/BlackenedCrab.png diff --git a/src/assets/img/Food/BlueshellEscargot.png b/public/assets/img/Food/BlueshellEscargot.png similarity index 100% rename from src/assets/img/Food/BlueshellEscargot.png rename to public/assets/img/Food/BlueshellEscargot.png diff --git a/src/assets/img/Food/CampfireEgg.png b/public/assets/img/Food/CampfireEgg.png similarity index 100% rename from src/assets/img/Food/CampfireEgg.png rename to public/assets/img/Food/CampfireEgg.png diff --git a/src/assets/img/Food/CarrotCake.png b/public/assets/img/Food/CarrotCake.png similarity index 100% rename from src/assets/img/Food/CarrotCake.png rename to public/assets/img/Food/CarrotCake.png diff --git a/src/assets/img/Food/CarrotStew.png b/public/assets/img/Food/CarrotStew.png similarity index 100% rename from src/assets/img/Food/CarrotStew.png rename to public/assets/img/Food/CarrotStew.png diff --git a/src/assets/img/Food/CharredPepper.png b/public/assets/img/Food/CharredPepper.png similarity index 100% rename from src/assets/img/Food/CharredPepper.png rename to public/assets/img/Food/CharredPepper.png diff --git a/src/assets/img/Food/ChillyElixir.png b/public/assets/img/Food/ChillyElixir.png similarity index 100% rename from src/assets/img/Food/ChillyElixir.png rename to public/assets/img/Food/ChillyElixir.png diff --git a/src/assets/img/Food/ClamChowder.png b/public/assets/img/Food/ClamChowder.png similarity index 100% rename from src/assets/img/Food/ClamChowder.png rename to public/assets/img/Food/ClamChowder.png diff --git a/src/assets/img/Food/CopiousFriedWildGreens.png b/public/assets/img/Food/CopiousFriedWildGreens.png similarity index 100% rename from src/assets/img/Food/CopiousFriedWildGreens.png rename to public/assets/img/Food/CopiousFriedWildGreens.png diff --git a/src/assets/img/Food/CopiousMeatSkewers.png b/public/assets/img/Food/CopiousMeatSkewers.png similarity index 100% rename from src/assets/img/Food/CopiousMeatSkewers.png rename to public/assets/img/Food/CopiousMeatSkewers.png diff --git a/src/assets/img/Food/CopiousMushroomSkewers.png b/public/assets/img/Food/CopiousMushroomSkewers.png similarity index 100% rename from src/assets/img/Food/CopiousMushroomSkewers.png rename to public/assets/img/Food/CopiousMushroomSkewers.png diff --git a/src/assets/img/Food/CopiousSeafoodSkewers.png b/public/assets/img/Food/CopiousSeafoodSkewers.png similarity index 100% rename from src/assets/img/Food/CopiousSeafoodSkewers.png rename to public/assets/img/Food/CopiousSeafoodSkewers.png diff --git a/src/assets/img/Food/CopiousSimmeredFruit.png b/public/assets/img/Food/CopiousSimmeredFruit.png similarity index 100% rename from src/assets/img/Food/CopiousSimmeredFruit.png rename to public/assets/img/Food/CopiousSimmeredFruit.png diff --git a/src/assets/img/Food/CrabOmeletWithRice.png b/public/assets/img/Food/CrabOmeletWithRice.png similarity index 100% rename from src/assets/img/Food/CrabOmeletWithRice.png rename to public/assets/img/Food/CrabOmeletWithRice.png diff --git a/src/assets/img/Food/CrabRisotto.png b/public/assets/img/Food/CrabRisotto.png similarity index 100% rename from src/assets/img/Food/CrabRisotto.png rename to public/assets/img/Food/CrabRisotto.png diff --git a/src/assets/img/Food/CrabStirFry.png b/public/assets/img/Food/CrabStirFry.png similarity index 100% rename from src/assets/img/Food/CrabStirFry.png rename to public/assets/img/Food/CrabStirFry.png diff --git a/src/assets/img/Food/CreamOfMushroomSoup.png b/public/assets/img/Food/CreamOfMushroomSoup.png similarity index 100% rename from src/assets/img/Food/CreamOfMushroomSoup.png rename to public/assets/img/Food/CreamOfMushroomSoup.png diff --git a/src/assets/img/Food/CreamOfVegetableSoup.png b/public/assets/img/Food/CreamOfVegetableSoup.png similarity index 100% rename from src/assets/img/Food/CreamOfVegetableSoup.png rename to public/assets/img/Food/CreamOfVegetableSoup.png diff --git a/src/assets/img/Food/CreamyHeartSoup.png b/public/assets/img/Food/CreamyHeartSoup.png similarity index 100% rename from src/assets/img/Food/CreamyHeartSoup.png rename to public/assets/img/Food/CreamyHeartSoup.png diff --git a/src/assets/img/Food/CreamyMeatSoup.png b/public/assets/img/Food/CreamyMeatSoup.png similarity index 100% rename from src/assets/img/Food/CreamyMeatSoup.png rename to public/assets/img/Food/CreamyMeatSoup.png diff --git a/src/assets/img/Food/CreamySeafoodSoup.png b/public/assets/img/Food/CreamySeafoodSoup.png similarity index 100% rename from src/assets/img/Food/CreamySeafoodSoup.png rename to public/assets/img/Food/CreamySeafoodSoup.png diff --git a/src/assets/img/Food/CurryPilaf.png b/public/assets/img/Food/CurryPilaf.png similarity index 100% rename from src/assets/img/Food/CurryPilaf.png rename to public/assets/img/Food/CurryPilaf.png diff --git a/src/assets/img/Food/CurryRice.png b/public/assets/img/Food/CurryRice.png similarity index 100% rename from src/assets/img/Food/CurryRice.png rename to public/assets/img/Food/CurryRice.png diff --git a/src/assets/img/Food/DubiousFood.png b/public/assets/img/Food/DubiousFood.png similarity index 100% rename from src/assets/img/Food/DubiousFood.png rename to public/assets/img/Food/DubiousFood.png diff --git a/src/assets/img/Food/EggPudding.png b/public/assets/img/Food/EggPudding.png similarity index 100% rename from src/assets/img/Food/EggPudding.png rename to public/assets/img/Food/EggPudding.png diff --git a/src/assets/img/Food/EggTart.png b/public/assets/img/Food/EggTart.png similarity index 100% rename from src/assets/img/Food/EggTart.png rename to public/assets/img/Food/EggTart.png diff --git a/src/assets/img/Food/ElectroElixir.png b/public/assets/img/Food/ElectroElixir.png similarity index 100% rename from src/assets/img/Food/ElectroElixir.png rename to public/assets/img/Food/ElectroElixir.png diff --git a/src/assets/img/Food/Elixir.png b/public/assets/img/Food/Elixir.png similarity index 100% rename from src/assets/img/Food/Elixir.png rename to public/assets/img/Food/Elixir.png diff --git a/src/assets/img/Food/EnduringElixir.png b/public/assets/img/Food/EnduringElixir.png similarity index 100% rename from src/assets/img/Food/EnduringElixir.png rename to public/assets/img/Food/EnduringElixir.png diff --git a/src/assets/img/Food/EnergizingElixir.png b/public/assets/img/Food/EnergizingElixir.png similarity index 100% rename from src/assets/img/Food/EnergizingElixir.png rename to public/assets/img/Food/EnergizingElixir.png diff --git a/src/assets/img/Food/FairyTonic.png b/public/assets/img/Food/FairyTonic.png similarity index 100% rename from src/assets/img/Food/FairyTonic.png rename to public/assets/img/Food/FairyTonic.png diff --git a/src/assets/img/Food/FireproofElixir.png b/public/assets/img/Food/FireproofElixir.png similarity index 100% rename from src/assets/img/Food/FireproofElixir.png rename to public/assets/img/Food/FireproofElixir.png diff --git a/src/assets/img/Food/FishAndMushroomSkewer.png b/public/assets/img/Food/FishAndMushroomSkewer.png similarity index 100% rename from src/assets/img/Food/FishAndMushroomSkewer.png rename to public/assets/img/Food/FishAndMushroomSkewer.png diff --git a/src/assets/img/Food/FishPie.png b/public/assets/img/Food/FishPie.png similarity index 100% rename from src/assets/img/Food/FishPie.png rename to public/assets/img/Food/FishPie.png diff --git a/src/assets/img/Food/FishSkewer.png b/public/assets/img/Food/FishSkewer.png similarity index 100% rename from src/assets/img/Food/FishSkewer.png rename to public/assets/img/Food/FishSkewer.png diff --git a/src/assets/img/Food/FragrantMushroomSaute.png b/public/assets/img/Food/FragrantMushroomSaute.png similarity index 100% rename from src/assets/img/Food/FragrantMushroomSaute.png rename to public/assets/img/Food/FragrantMushroomSaute.png diff --git a/src/assets/img/Food/FriedBananas.png b/public/assets/img/Food/FriedBananas.png similarity index 100% rename from src/assets/img/Food/FriedBananas.png rename to public/assets/img/Food/FriedBananas.png diff --git a/src/assets/img/Food/FriedEggAndRice.png b/public/assets/img/Food/FriedEggAndRice.png similarity index 100% rename from src/assets/img/Food/FriedEggAndRice.png rename to public/assets/img/Food/FriedEggAndRice.png diff --git a/src/assets/img/Food/FriedWildGreens.png b/public/assets/img/Food/FriedWildGreens.png similarity index 100% rename from src/assets/img/Food/FriedWildGreens.png rename to public/assets/img/Food/FriedWildGreens.png diff --git a/src/assets/img/Food/FrozenBass.png b/public/assets/img/Food/FrozenBass.png similarity index 100% rename from src/assets/img/Food/FrozenBass.png rename to public/assets/img/Food/FrozenBass.png diff --git a/src/assets/img/Food/FrozenBirdDrumstick.png b/public/assets/img/Food/FrozenBirdDrumstick.png similarity index 100% rename from src/assets/img/Food/FrozenBirdDrumstick.png rename to public/assets/img/Food/FrozenBirdDrumstick.png diff --git a/src/assets/img/Food/FrozenBirdThigh.png b/public/assets/img/Food/FrozenBirdThigh.png similarity index 100% rename from src/assets/img/Food/FrozenBirdThigh.png rename to public/assets/img/Food/FrozenBirdThigh.png diff --git a/src/assets/img/Food/FrozenCarp.png b/public/assets/img/Food/FrozenCarp.png similarity index 100% rename from src/assets/img/Food/FrozenCarp.png rename to public/assets/img/Food/FrozenCarp.png diff --git a/src/assets/img/Food/FrozenCrab.png b/public/assets/img/Food/FrozenCrab.png similarity index 100% rename from src/assets/img/Food/FrozenCrab.png rename to public/assets/img/Food/FrozenCrab.png diff --git a/src/assets/img/Food/FrozenHeartyBass.png b/public/assets/img/Food/FrozenHeartyBass.png similarity index 100% rename from src/assets/img/Food/FrozenHeartyBass.png rename to public/assets/img/Food/FrozenHeartyBass.png diff --git a/src/assets/img/Food/FrozenHeartySalmon.png b/public/assets/img/Food/FrozenHeartySalmon.png similarity index 100% rename from src/assets/img/Food/FrozenHeartySalmon.png rename to public/assets/img/Food/FrozenHeartySalmon.png diff --git a/src/assets/img/Food/FrozenPorgy.png b/public/assets/img/Food/FrozenPorgy.png similarity index 100% rename from src/assets/img/Food/FrozenPorgy.png rename to public/assets/img/Food/FrozenPorgy.png diff --git a/src/assets/img/Food/FrozenRiverSnail.png b/public/assets/img/Food/FrozenRiverSnail.png similarity index 100% rename from src/assets/img/Food/FrozenRiverSnail.png rename to public/assets/img/Food/FrozenRiverSnail.png diff --git a/src/assets/img/Food/FrozenTrout.png b/public/assets/img/Food/FrozenTrout.png similarity index 100% rename from src/assets/img/Food/FrozenTrout.png rename to public/assets/img/Food/FrozenTrout.png diff --git a/src/assets/img/Food/FrozenWholeBird.png b/public/assets/img/Food/FrozenWholeBird.png similarity index 100% rename from src/assets/img/Food/FrozenWholeBird.png rename to public/assets/img/Food/FrozenWholeBird.png diff --git a/src/assets/img/Food/FruitAndMushroomMix.png b/public/assets/img/Food/FruitAndMushroomMix.png similarity index 100% rename from src/assets/img/Food/FruitAndMushroomMix.png rename to public/assets/img/Food/FruitAndMushroomMix.png diff --git a/src/assets/img/Food/FruitPie.png b/public/assets/img/Food/FruitPie.png similarity index 100% rename from src/assets/img/Food/FruitPie.png rename to public/assets/img/Food/FruitPie.png diff --git a/src/assets/img/Food/Fruitcake.png b/public/assets/img/Food/Fruitcake.png similarity index 100% rename from src/assets/img/Food/Fruitcake.png rename to public/assets/img/Food/Fruitcake.png diff --git a/src/assets/img/Food/GlazedMeat.png b/public/assets/img/Food/GlazedMeat.png similarity index 100% rename from src/assets/img/Food/GlazedMeat.png rename to public/assets/img/Food/GlazedMeat.png diff --git a/src/assets/img/Food/GlazedMushrooms.png b/public/assets/img/Food/GlazedMushrooms.png similarity index 100% rename from src/assets/img/Food/GlazedMushrooms.png rename to public/assets/img/Food/GlazedMushrooms.png diff --git a/src/assets/img/Food/GlazedSeafood.png b/public/assets/img/Food/GlazedSeafood.png similarity index 100% rename from src/assets/img/Food/GlazedSeafood.png rename to public/assets/img/Food/GlazedSeafood.png diff --git a/src/assets/img/Food/GlazedVeggies.png b/public/assets/img/Food/GlazedVeggies.png similarity index 100% rename from src/assets/img/Food/GlazedVeggies.png rename to public/assets/img/Food/GlazedVeggies.png diff --git a/src/assets/img/Food/GourmetMeatAndRiceBowl.png b/public/assets/img/Food/GourmetMeatAndRiceBowl.png similarity index 100% rename from src/assets/img/Food/GourmetMeatAndRiceBowl.png rename to public/assets/img/Food/GourmetMeatAndRiceBowl.png diff --git a/src/assets/img/Food/GourmetMeatAndSeafoodFry.png b/public/assets/img/Food/GourmetMeatAndSeafoodFry.png similarity index 100% rename from src/assets/img/Food/GourmetMeatAndSeafoodFry.png rename to public/assets/img/Food/GourmetMeatAndSeafoodFry.png diff --git a/src/assets/img/Food/GourmetMeatCurry.png b/public/assets/img/Food/GourmetMeatCurry.png similarity index 100% rename from src/assets/img/Food/GourmetMeatCurry.png rename to public/assets/img/Food/GourmetMeatCurry.png diff --git a/src/assets/img/Food/GourmetMeatStew.png b/public/assets/img/Food/GourmetMeatStew.png similarity index 100% rename from src/assets/img/Food/GourmetMeatStew.png rename to public/assets/img/Food/GourmetMeatStew.png diff --git a/src/assets/img/Food/GourmetPoultryCurry.png b/public/assets/img/Food/GourmetPoultryCurry.png similarity index 100% rename from src/assets/img/Food/GourmetPoultryCurry.png rename to public/assets/img/Food/GourmetPoultryCurry.png diff --git a/src/assets/img/Food/GourmetPoultryPilaf.png b/public/assets/img/Food/GourmetPoultryPilaf.png similarity index 100% rename from src/assets/img/Food/GourmetPoultryPilaf.png rename to public/assets/img/Food/GourmetPoultryPilaf.png diff --git a/src/assets/img/Food/GourmetSpicedMeatSkewer.png b/public/assets/img/Food/GourmetSpicedMeatSkewer.png similarity index 100% rename from src/assets/img/Food/GourmetSpicedMeatSkewer.png rename to public/assets/img/Food/GourmetSpicedMeatSkewer.png diff --git a/src/assets/img/Food/HardBoiledEgg.png b/public/assets/img/Food/HardBoiledEgg.png similarity index 100% rename from src/assets/img/Food/HardBoiledEgg.png rename to public/assets/img/Food/HardBoiledEgg.png diff --git a/src/assets/img/Food/HastyElixir.png b/public/assets/img/Food/HastyElixir.png similarity index 100% rename from src/assets/img/Food/HastyElixir.png rename to public/assets/img/Food/HastyElixir.png diff --git a/src/assets/img/Food/HeartyElixir.png b/public/assets/img/Food/HeartyElixir.png similarity index 100% rename from src/assets/img/Food/HeartyElixir.png rename to public/assets/img/Food/HeartyElixir.png diff --git a/src/assets/img/Food/HerbSaute.png b/public/assets/img/Food/HerbSaute.png similarity index 100% rename from src/assets/img/Food/HerbSaute.png rename to public/assets/img/Food/HerbSaute.png diff --git a/src/assets/img/Food/HoneyCandy.png b/public/assets/img/Food/HoneyCandy.png similarity index 100% rename from src/assets/img/Food/HoneyCandy.png rename to public/assets/img/Food/HoneyCandy.png diff --git a/src/assets/img/Food/HoneyCrepe.png b/public/assets/img/Food/HoneyCrepe.png similarity index 100% rename from src/assets/img/Food/HoneyCrepe.png rename to public/assets/img/Food/HoneyCrepe.png diff --git a/src/assets/img/Food/HoneyedApple.png b/public/assets/img/Food/HoneyedApple.png similarity index 100% rename from src/assets/img/Food/HoneyedApple.png rename to public/assets/img/Food/HoneyedApple.png diff --git a/src/assets/img/Food/HoneyedFruits.png b/public/assets/img/Food/HoneyedFruits.png similarity index 100% rename from src/assets/img/Food/HoneyedFruits.png rename to public/assets/img/Food/HoneyedFruits.png diff --git a/src/assets/img/Food/HotButteredApple.png b/public/assets/img/Food/HotButteredApple.png similarity index 100% rename from src/assets/img/Food/HotButteredApple.png rename to public/assets/img/Food/HotButteredApple.png diff --git a/src/assets/img/Food/IcyGourmetMeat.png b/public/assets/img/Food/IcyGourmetMeat.png similarity index 100% rename from src/assets/img/Food/IcyGourmetMeat.png rename to public/assets/img/Food/IcyGourmetMeat.png diff --git a/src/assets/img/Food/IcyHeartyBlueshellSnail.png b/public/assets/img/Food/IcyHeartyBlueshellSnail.png similarity index 100% rename from src/assets/img/Food/IcyHeartyBlueshellSnail.png rename to public/assets/img/Food/IcyHeartyBlueshellSnail.png diff --git a/src/assets/img/Food/IcyMeat.png b/public/assets/img/Food/IcyMeat.png similarity index 100% rename from src/assets/img/Food/IcyMeat.png rename to public/assets/img/Food/IcyMeat.png diff --git a/src/assets/img/Food/IcyPrimeMeat.png b/public/assets/img/Food/IcyPrimeMeat.png similarity index 100% rename from src/assets/img/Food/IcyPrimeMeat.png rename to public/assets/img/Food/IcyPrimeMeat.png diff --git a/src/assets/img/Food/MeatAndMushroomSkewer.png b/public/assets/img/Food/MeatAndMushroomSkewer.png similarity index 100% rename from src/assets/img/Food/MeatAndMushroomSkewer.png rename to public/assets/img/Food/MeatAndMushroomSkewer.png diff --git a/src/assets/img/Food/MeatAndRiceBowl.png b/public/assets/img/Food/MeatAndRiceBowl.png similarity index 100% rename from src/assets/img/Food/MeatAndRiceBowl.png rename to public/assets/img/Food/MeatAndRiceBowl.png diff --git a/src/assets/img/Food/MeatAndSeafoodFry.png b/public/assets/img/Food/MeatAndSeafoodFry.png similarity index 100% rename from src/assets/img/Food/MeatAndSeafoodFry.png rename to public/assets/img/Food/MeatAndSeafoodFry.png diff --git a/src/assets/img/Food/MeatCurry.png b/public/assets/img/Food/MeatCurry.png similarity index 100% rename from src/assets/img/Food/MeatCurry.png rename to public/assets/img/Food/MeatCurry.png diff --git a/src/assets/img/Food/MeatPie.png b/public/assets/img/Food/MeatPie.png similarity index 100% rename from src/assets/img/Food/MeatPie.png rename to public/assets/img/Food/MeatPie.png diff --git a/src/assets/img/Food/MeatSkewer.png b/public/assets/img/Food/MeatSkewer.png similarity index 100% rename from src/assets/img/Food/MeatSkewer.png rename to public/assets/img/Food/MeatSkewer.png diff --git a/src/assets/img/Food/MeatStew.png b/public/assets/img/Food/MeatStew.png similarity index 100% rename from src/assets/img/Food/MeatStew.png rename to public/assets/img/Food/MeatStew.png diff --git a/src/assets/img/Food/MeatStuffedPumpkin.png b/public/assets/img/Food/MeatStuffedPumpkin.png similarity index 100% rename from src/assets/img/Food/MeatStuffedPumpkin.png rename to public/assets/img/Food/MeatStuffedPumpkin.png diff --git a/src/assets/img/Food/MeatyRiceBalls.png b/public/assets/img/Food/MeatyRiceBalls.png similarity index 100% rename from src/assets/img/Food/MeatyRiceBalls.png rename to public/assets/img/Food/MeatyRiceBalls.png diff --git a/src/assets/img/Food/MightyElixir.png b/public/assets/img/Food/MightyElixir.png similarity index 100% rename from src/assets/img/Food/MightyElixir.png rename to public/assets/img/Food/MightyElixir.png diff --git a/src/assets/img/Food/MonsterCake.png b/public/assets/img/Food/MonsterCake.png similarity index 100% rename from src/assets/img/Food/MonsterCake.png rename to public/assets/img/Food/MonsterCake.png diff --git a/src/assets/img/Food/MonsterCurry.png b/public/assets/img/Food/MonsterCurry.png similarity index 100% rename from src/assets/img/Food/MonsterCurry.png rename to public/assets/img/Food/MonsterCurry.png diff --git a/src/assets/img/Food/MonsterRiceBalls.png b/public/assets/img/Food/MonsterRiceBalls.png similarity index 100% rename from src/assets/img/Food/MonsterRiceBalls.png rename to public/assets/img/Food/MonsterRiceBalls.png diff --git a/src/assets/img/Food/MonsterSoup.png b/public/assets/img/Food/MonsterSoup.png similarity index 100% rename from src/assets/img/Food/MonsterSoup.png rename to public/assets/img/Food/MonsterSoup.png diff --git a/src/assets/img/Food/MonsterStew.png b/public/assets/img/Food/MonsterStew.png similarity index 100% rename from src/assets/img/Food/MonsterStew.png rename to public/assets/img/Food/MonsterStew.png diff --git a/src/assets/img/Food/MushroomOmelet.png b/public/assets/img/Food/MushroomOmelet.png similarity index 100% rename from src/assets/img/Food/MushroomOmelet.png rename to public/assets/img/Food/MushroomOmelet.png diff --git a/src/assets/img/Food/MushroomRiceBalls.png b/public/assets/img/Food/MushroomRiceBalls.png similarity index 100% rename from src/assets/img/Food/MushroomRiceBalls.png rename to public/assets/img/Food/MushroomRiceBalls.png diff --git a/src/assets/img/Food/MushroomRisotto.png b/public/assets/img/Food/MushroomRisotto.png similarity index 100% rename from src/assets/img/Food/MushroomRisotto.png rename to public/assets/img/Food/MushroomRisotto.png diff --git a/src/assets/img/Food/MushroomSkewer.png b/public/assets/img/Food/MushroomSkewer.png similarity index 100% rename from src/assets/img/Food/MushroomSkewer.png rename to public/assets/img/Food/MushroomSkewer.png diff --git a/src/assets/img/Food/Nutcake.png b/public/assets/img/Food/Nutcake.png similarity index 100% rename from src/assets/img/Food/Nutcake.png rename to public/assets/img/Food/Nutcake.png diff --git a/src/assets/img/Food/Omelet.png b/public/assets/img/Food/Omelet.png similarity index 100% rename from src/assets/img/Food/Omelet.png rename to public/assets/img/Food/Omelet.png diff --git a/src/assets/img/Food/PepperSeafood.png b/public/assets/img/Food/PepperSeafood.png similarity index 100% rename from src/assets/img/Food/PepperSeafood.png rename to public/assets/img/Food/PepperSeafood.png diff --git a/src/assets/img/Food/PepperSteak.png b/public/assets/img/Food/PepperSteak.png similarity index 100% rename from src/assets/img/Food/PepperSteak.png rename to public/assets/img/Food/PepperSteak.png diff --git a/src/assets/img/Food/PlainCrepe.png b/public/assets/img/Food/PlainCrepe.png similarity index 100% rename from src/assets/img/Food/PlainCrepe.png rename to public/assets/img/Food/PlainCrepe.png diff --git a/src/assets/img/Food/PorgyMeuniere.png b/public/assets/img/Food/PorgyMeuniere.png similarity index 100% rename from src/assets/img/Food/PorgyMeuniere.png rename to public/assets/img/Food/PorgyMeuniere.png diff --git a/src/assets/img/Food/PoultryCurry.png b/public/assets/img/Food/PoultryCurry.png similarity index 100% rename from src/assets/img/Food/PoultryCurry.png rename to public/assets/img/Food/PoultryCurry.png diff --git a/src/assets/img/Food/PoultryPilaf.png b/public/assets/img/Food/PoultryPilaf.png similarity index 100% rename from src/assets/img/Food/PoultryPilaf.png rename to public/assets/img/Food/PoultryPilaf.png diff --git a/src/assets/img/Food/PrimeMeatAndRiceBowl.png b/public/assets/img/Food/PrimeMeatAndRiceBowl.png similarity index 100% rename from src/assets/img/Food/PrimeMeatAndRiceBowl.png rename to public/assets/img/Food/PrimeMeatAndRiceBowl.png diff --git a/src/assets/img/Food/PrimeMeatAndSeafoodFry.png b/public/assets/img/Food/PrimeMeatAndSeafoodFry.png similarity index 100% rename from src/assets/img/Food/PrimeMeatAndSeafoodFry.png rename to public/assets/img/Food/PrimeMeatAndSeafoodFry.png diff --git a/src/assets/img/Food/PrimeMeatCurry.png b/public/assets/img/Food/PrimeMeatCurry.png similarity index 100% rename from src/assets/img/Food/PrimeMeatCurry.png rename to public/assets/img/Food/PrimeMeatCurry.png diff --git a/src/assets/img/Food/PrimeMeatStew.png b/public/assets/img/Food/PrimeMeatStew.png similarity index 100% rename from src/assets/img/Food/PrimeMeatStew.png rename to public/assets/img/Food/PrimeMeatStew.png diff --git a/src/assets/img/Food/PrimePoultryCurry.png b/public/assets/img/Food/PrimePoultryCurry.png similarity index 100% rename from src/assets/img/Food/PrimePoultryCurry.png rename to public/assets/img/Food/PrimePoultryCurry.png diff --git a/src/assets/img/Food/PrimePoultryPilaf.png b/public/assets/img/Food/PrimePoultryPilaf.png similarity index 100% rename from src/assets/img/Food/PrimePoultryPilaf.png rename to public/assets/img/Food/PrimePoultryPilaf.png diff --git a/src/assets/img/Food/PrimeSpicedMeatSkewer.png b/public/assets/img/Food/PrimeSpicedMeatSkewer.png similarity index 100% rename from src/assets/img/Food/PrimeSpicedMeatSkewer.png rename to public/assets/img/Food/PrimeSpicedMeatSkewer.png diff --git a/src/assets/img/Food/PumpkinPie.png b/public/assets/img/Food/PumpkinPie.png similarity index 100% rename from src/assets/img/Food/PumpkinPie.png rename to public/assets/img/Food/PumpkinPie.png diff --git a/src/assets/img/Food/PumpkinStew.png b/public/assets/img/Food/PumpkinStew.png similarity index 100% rename from src/assets/img/Food/PumpkinStew.png rename to public/assets/img/Food/PumpkinStew.png diff --git a/src/assets/img/Food/RoastedAcorn.png b/public/assets/img/Food/RoastedAcorn.png similarity index 100% rename from src/assets/img/Food/RoastedAcorn.png rename to public/assets/img/Food/RoastedAcorn.png diff --git a/src/assets/img/Food/RoastedArmoranth.png b/public/assets/img/Food/RoastedArmoranth.png similarity index 100% rename from src/assets/img/Food/RoastedArmoranth.png rename to public/assets/img/Food/RoastedArmoranth.png diff --git a/src/assets/img/Food/RoastedBass.png b/public/assets/img/Food/RoastedBass.png similarity index 100% rename from src/assets/img/Food/RoastedBass.png rename to public/assets/img/Food/RoastedBass.png diff --git a/src/assets/img/Food/RoastedBigRadish.png b/public/assets/img/Food/RoastedBigRadish.png similarity index 100% rename from src/assets/img/Food/RoastedBigRadish.png rename to public/assets/img/Food/RoastedBigRadish.png diff --git a/src/assets/img/Food/RoastedBirdDrumstick.png b/public/assets/img/Food/RoastedBirdDrumstick.png similarity index 100% rename from src/assets/img/Food/RoastedBirdDrumstick.png rename to public/assets/img/Food/RoastedBirdDrumstick.png diff --git a/src/assets/img/Food/RoastedBirdThigh.png b/public/assets/img/Food/RoastedBirdThigh.png similarity index 100% rename from src/assets/img/Food/RoastedBirdThigh.png rename to public/assets/img/Food/RoastedBirdThigh.png diff --git a/src/assets/img/Food/RoastedCarp.png b/public/assets/img/Food/RoastedCarp.png similarity index 100% rename from src/assets/img/Food/RoastedCarp.png rename to public/assets/img/Food/RoastedCarp.png diff --git a/src/assets/img/Food/RoastedEnduraCarrot.png b/public/assets/img/Food/RoastedEnduraCarrot.png similarity index 100% rename from src/assets/img/Food/RoastedEnduraCarrot.png rename to public/assets/img/Food/RoastedEnduraCarrot.png diff --git a/src/assets/img/Food/RoastedHeartyBass.png b/public/assets/img/Food/RoastedHeartyBass.png similarity index 100% rename from src/assets/img/Food/RoastedHeartyBass.png rename to public/assets/img/Food/RoastedHeartyBass.png diff --git a/src/assets/img/Food/RoastedHeartyDurian.png b/public/assets/img/Food/RoastedHeartyDurian.png similarity index 100% rename from src/assets/img/Food/RoastedHeartyDurian.png rename to public/assets/img/Food/RoastedHeartyDurian.png diff --git a/src/assets/img/Food/RoastedHeartySalmon.png b/public/assets/img/Food/RoastedHeartySalmon.png similarity index 100% rename from src/assets/img/Food/RoastedHeartySalmon.png rename to public/assets/img/Food/RoastedHeartySalmon.png diff --git a/src/assets/img/Food/RoastedHydromelon.png b/public/assets/img/Food/RoastedHydromelon.png similarity index 100% rename from src/assets/img/Food/RoastedHydromelon.png rename to public/assets/img/Food/RoastedHydromelon.png diff --git a/src/assets/img/Food/RoastedLotusSeeds.png b/public/assets/img/Food/RoastedLotusSeeds.png similarity index 100% rename from src/assets/img/Food/RoastedLotusSeeds.png rename to public/assets/img/Food/RoastedLotusSeeds.png diff --git a/src/assets/img/Food/RoastedMightyBananas.png b/public/assets/img/Food/RoastedMightyBananas.png similarity index 100% rename from src/assets/img/Food/RoastedMightyBananas.png rename to public/assets/img/Food/RoastedMightyBananas.png diff --git a/src/assets/img/Food/RoastedMightyThistle.png b/public/assets/img/Food/RoastedMightyThistle.png similarity index 100% rename from src/assets/img/Food/RoastedMightyThistle.png rename to public/assets/img/Food/RoastedMightyThistle.png diff --git a/src/assets/img/Food/RoastedPorgy.png b/public/assets/img/Food/RoastedPorgy.png similarity index 100% rename from src/assets/img/Food/RoastedPorgy.png rename to public/assets/img/Food/RoastedPorgy.png diff --git a/src/assets/img/Food/RoastedRadish.png b/public/assets/img/Food/RoastedRadish.png similarity index 100% rename from src/assets/img/Food/RoastedRadish.png rename to public/assets/img/Food/RoastedRadish.png diff --git a/src/assets/img/Food/RoastedSwiftCarrot.png b/public/assets/img/Food/RoastedSwiftCarrot.png similarity index 100% rename from src/assets/img/Food/RoastedSwiftCarrot.png rename to public/assets/img/Food/RoastedSwiftCarrot.png diff --git a/src/assets/img/Food/RoastedTreeNut.png b/public/assets/img/Food/RoastedTreeNut.png similarity index 100% rename from src/assets/img/Food/RoastedTreeNut.png rename to public/assets/img/Food/RoastedTreeNut.png diff --git a/src/assets/img/Food/RoastedTrout.png b/public/assets/img/Food/RoastedTrout.png similarity index 100% rename from src/assets/img/Food/RoastedTrout.png rename to public/assets/img/Food/RoastedTrout.png diff --git a/src/assets/img/Food/RoastedVoltfruit.png b/public/assets/img/Food/RoastedVoltfruit.png similarity index 100% rename from src/assets/img/Food/RoastedVoltfruit.png rename to public/assets/img/Food/RoastedVoltfruit.png diff --git a/src/assets/img/Food/RoastedWholeBird.png b/public/assets/img/Food/RoastedWholeBird.png similarity index 100% rename from src/assets/img/Food/RoastedWholeBird.png rename to public/assets/img/Food/RoastedWholeBird.png diff --git a/src/assets/img/Food/RoastedWildberry.png b/public/assets/img/Food/RoastedWildberry.png similarity index 100% rename from src/assets/img/Food/RoastedWildberry.png rename to public/assets/img/Food/RoastedWildberry.png diff --git a/src/assets/img/Food/RockHardFood.png b/public/assets/img/Food/RockHardFood.png similarity index 100% rename from src/assets/img/Food/RockHardFood.png rename to public/assets/img/Food/RockHardFood.png diff --git a/src/assets/img/Food/SalmonMeuniere.png b/public/assets/img/Food/SalmonMeuniere.png similarity index 100% rename from src/assets/img/Food/SalmonMeuniere.png rename to public/assets/img/Food/SalmonMeuniere.png diff --git a/src/assets/img/Food/SalmonRisotto.png b/public/assets/img/Food/SalmonRisotto.png similarity index 100% rename from src/assets/img/Food/SalmonRisotto.png rename to public/assets/img/Food/SalmonRisotto.png diff --git a/src/assets/img/Food/SaltGrilledCrab.png b/public/assets/img/Food/SaltGrilledCrab.png similarity index 100% rename from src/assets/img/Food/SaltGrilledCrab.png rename to public/assets/img/Food/SaltGrilledCrab.png diff --git a/src/assets/img/Food/SaltGrilledFish.png b/public/assets/img/Food/SaltGrilledFish.png similarity index 100% rename from src/assets/img/Food/SaltGrilledFish.png rename to public/assets/img/Food/SaltGrilledFish.png diff --git a/src/assets/img/Food/SaltGrilledGourmetMeat.png b/public/assets/img/Food/SaltGrilledGourmetMeat.png similarity index 100% rename from src/assets/img/Food/SaltGrilledGourmetMeat.png rename to public/assets/img/Food/SaltGrilledGourmetMeat.png diff --git a/src/assets/img/Food/SaltGrilledGreens.png b/public/assets/img/Food/SaltGrilledGreens.png similarity index 100% rename from src/assets/img/Food/SaltGrilledGreens.png rename to public/assets/img/Food/SaltGrilledGreens.png diff --git a/src/assets/img/Food/SaltGrilledMeat.png b/public/assets/img/Food/SaltGrilledMeat.png similarity index 100% rename from src/assets/img/Food/SaltGrilledMeat.png rename to public/assets/img/Food/SaltGrilledMeat.png diff --git a/src/assets/img/Food/SaltGrilledMushrooms.png b/public/assets/img/Food/SaltGrilledMushrooms.png similarity index 100% rename from src/assets/img/Food/SaltGrilledMushrooms.png rename to public/assets/img/Food/SaltGrilledMushrooms.png diff --git a/src/assets/img/Food/SaltGrilledPrimeMeat.png b/public/assets/img/Food/SaltGrilledPrimeMeat.png similarity index 100% rename from src/assets/img/Food/SaltGrilledPrimeMeat.png rename to public/assets/img/Food/SaltGrilledPrimeMeat.png diff --git a/src/assets/img/Food/SauteedNuts.png b/public/assets/img/Food/SauteedNuts.png similarity index 100% rename from src/assets/img/Food/SauteedNuts.png rename to public/assets/img/Food/SauteedNuts.png diff --git a/src/assets/img/Food/SauteedPeppers.png b/public/assets/img/Food/SauteedPeppers.png similarity index 100% rename from src/assets/img/Food/SauteedPeppers.png rename to public/assets/img/Food/SauteedPeppers.png diff --git a/src/assets/img/Food/SeafoodCurry.png b/public/assets/img/Food/SeafoodCurry.png similarity index 100% rename from src/assets/img/Food/SeafoodCurry.png rename to public/assets/img/Food/SeafoodCurry.png diff --git a/src/assets/img/Food/SeafoodFriedRice.png b/public/assets/img/Food/SeafoodFriedRice.png similarity index 100% rename from src/assets/img/Food/SeafoodFriedRice.png rename to public/assets/img/Food/SeafoodFriedRice.png diff --git a/src/assets/img/Food/SeafoodMeuniere.png b/public/assets/img/Food/SeafoodMeuniere.png similarity index 100% rename from src/assets/img/Food/SeafoodMeuniere.png rename to public/assets/img/Food/SeafoodMeuniere.png diff --git a/src/assets/img/Food/SeafoodPaella.png b/public/assets/img/Food/SeafoodPaella.png similarity index 100% rename from src/assets/img/Food/SeafoodPaella.png rename to public/assets/img/Food/SeafoodPaella.png diff --git a/src/assets/img/Food/SeafoodRiceBalls.png b/public/assets/img/Food/SeafoodRiceBalls.png similarity index 100% rename from src/assets/img/Food/SeafoodRiceBalls.png rename to public/assets/img/Food/SeafoodRiceBalls.png diff --git a/src/assets/img/Food/SeafoodSkewer.png b/public/assets/img/Food/SeafoodSkewer.png similarity index 100% rename from src/assets/img/Food/SeafoodSkewer.png rename to public/assets/img/Food/SeafoodSkewer.png diff --git a/src/assets/img/Food/SearedGourmetSteak.png b/public/assets/img/Food/SearedGourmetSteak.png similarity index 100% rename from src/assets/img/Food/SearedGourmetSteak.png rename to public/assets/img/Food/SearedGourmetSteak.png diff --git a/src/assets/img/Food/SearedPrimeSteak.png b/public/assets/img/Food/SearedPrimeSteak.png similarity index 100% rename from src/assets/img/Food/SearedPrimeSteak.png rename to public/assets/img/Food/SearedPrimeSteak.png diff --git a/src/assets/img/Food/SearedSteak.png b/public/assets/img/Food/SearedSteak.png similarity index 100% rename from src/assets/img/Food/SearedSteak.png rename to public/assets/img/Food/SearedSteak.png diff --git a/src/assets/img/Food/SimmeredFruit.png b/public/assets/img/Food/SimmeredFruit.png similarity index 100% rename from src/assets/img/Food/SimmeredFruit.png rename to public/assets/img/Food/SimmeredFruit.png diff --git a/src/assets/img/Food/SneakyElixir.png b/public/assets/img/Food/SneakyElixir.png similarity index 100% rename from src/assets/img/Food/SneakyElixir.png rename to public/assets/img/Food/SneakyElixir.png diff --git a/src/assets/img/Food/SneakyRiverEscargot.png b/public/assets/img/Food/SneakyRiverEscargot.png similarity index 100% rename from src/assets/img/Food/SneakyRiverEscargot.png rename to public/assets/img/Food/SneakyRiverEscargot.png diff --git a/src/assets/img/Food/SpicedMeatSkewer.png b/public/assets/img/Food/SpicedMeatSkewer.png similarity index 100% rename from src/assets/img/Food/SpicedMeatSkewer.png rename to public/assets/img/Food/SpicedMeatSkewer.png diff --git a/src/assets/img/Food/SpicyElixir.png b/public/assets/img/Food/SpicyElixir.png similarity index 100% rename from src/assets/img/Food/SpicyElixir.png rename to public/assets/img/Food/SpicyElixir.png diff --git a/src/assets/img/Food/SteamedFish.png b/public/assets/img/Food/SteamedFish.png similarity index 100% rename from src/assets/img/Food/SteamedFish.png rename to public/assets/img/Food/SteamedFish.png diff --git a/src/assets/img/Food/SteamedFruit.png b/public/assets/img/Food/SteamedFruit.png similarity index 100% rename from src/assets/img/Food/SteamedFruit.png rename to public/assets/img/Food/SteamedFruit.png diff --git a/src/assets/img/Food/SteamedMeat.png b/public/assets/img/Food/SteamedMeat.png similarity index 100% rename from src/assets/img/Food/SteamedMeat.png rename to public/assets/img/Food/SteamedMeat.png diff --git a/src/assets/img/Food/SteamedMushrooms.png b/public/assets/img/Food/SteamedMushrooms.png similarity index 100% rename from src/assets/img/Food/SteamedMushrooms.png rename to public/assets/img/Food/SteamedMushrooms.png diff --git a/src/assets/img/Food/ToastedBigHeartyTruffle.png b/public/assets/img/Food/ToastedBigHeartyTruffle.png similarity index 100% rename from src/assets/img/Food/ToastedBigHeartyTruffle.png rename to public/assets/img/Food/ToastedBigHeartyTruffle.png diff --git a/src/assets/img/Food/ToastedHeartyTruffle.png b/public/assets/img/Food/ToastedHeartyTruffle.png similarity index 100% rename from src/assets/img/Food/ToastedHeartyTruffle.png rename to public/assets/img/Food/ToastedHeartyTruffle.png diff --git a/src/assets/img/Food/ToastyChillshroom.png b/public/assets/img/Food/ToastyChillshroom.png similarity index 100% rename from src/assets/img/Food/ToastyChillshroom.png rename to public/assets/img/Food/ToastyChillshroom.png diff --git a/src/assets/img/Food/ToastyEnduraShroom.png b/public/assets/img/Food/ToastyEnduraShroom.png similarity index 100% rename from src/assets/img/Food/ToastyEnduraShroom.png rename to public/assets/img/Food/ToastyEnduraShroom.png diff --git a/src/assets/img/Food/ToastyHylianShroom.png b/public/assets/img/Food/ToastyHylianShroom.png similarity index 100% rename from src/assets/img/Food/ToastyHylianShroom.png rename to public/assets/img/Food/ToastyHylianShroom.png diff --git a/src/assets/img/Food/ToastyIronshroom.png b/public/assets/img/Food/ToastyIronshroom.png similarity index 100% rename from src/assets/img/Food/ToastyIronshroom.png rename to public/assets/img/Food/ToastyIronshroom.png diff --git a/src/assets/img/Food/ToastyRazorshroom.png b/public/assets/img/Food/ToastyRazorshroom.png similarity index 100% rename from src/assets/img/Food/ToastyRazorshroom.png rename to public/assets/img/Food/ToastyRazorshroom.png diff --git a/src/assets/img/Food/ToastyRushroom.png b/public/assets/img/Food/ToastyRushroom.png similarity index 100% rename from src/assets/img/Food/ToastyRushroom.png rename to public/assets/img/Food/ToastyRushroom.png diff --git a/src/assets/img/Food/ToastySilentShroom.png b/public/assets/img/Food/ToastySilentShroom.png similarity index 100% rename from src/assets/img/Food/ToastySilentShroom.png rename to public/assets/img/Food/ToastySilentShroom.png diff --git a/src/assets/img/Food/ToastyStamellaShroom.png b/public/assets/img/Food/ToastyStamellaShroom.png similarity index 100% rename from src/assets/img/Food/ToastyStamellaShroom.png rename to public/assets/img/Food/ToastyStamellaShroom.png diff --git a/src/assets/img/Food/ToastySunshroom.png b/public/assets/img/Food/ToastySunshroom.png similarity index 100% rename from src/assets/img/Food/ToastySunshroom.png rename to public/assets/img/Food/ToastySunshroom.png diff --git a/src/assets/img/Food/ToastyZapshroom.png b/public/assets/img/Food/ToastyZapshroom.png similarity index 100% rename from src/assets/img/Food/ToastyZapshroom.png rename to public/assets/img/Food/ToastyZapshroom.png diff --git a/src/assets/img/Food/ToughElixir.png b/public/assets/img/Food/ToughElixir.png similarity index 100% rename from src/assets/img/Food/ToughElixir.png rename to public/assets/img/Food/ToughElixir.png diff --git a/src/assets/img/Food/VegetableCurry.png b/public/assets/img/Food/VegetableCurry.png similarity index 100% rename from src/assets/img/Food/VegetableCurry.png rename to public/assets/img/Food/VegetableCurry.png diff --git a/src/assets/img/Food/VegetableOmelet.png b/public/assets/img/Food/VegetableOmelet.png similarity index 100% rename from src/assets/img/Food/VegetableOmelet.png rename to public/assets/img/Food/VegetableOmelet.png diff --git a/src/assets/img/Food/VegetableRisotto.png b/public/assets/img/Food/VegetableRisotto.png similarity index 100% rename from src/assets/img/Food/VegetableRisotto.png rename to public/assets/img/Food/VegetableRisotto.png diff --git a/src/assets/img/Food/VeggieCreamSoup.png b/public/assets/img/Food/VeggieCreamSoup.png similarity index 100% rename from src/assets/img/Food/VeggieCreamSoup.png rename to public/assets/img/Food/VeggieCreamSoup.png diff --git a/src/assets/img/Food/VeggieRiceBalls.png b/public/assets/img/Food/VeggieRiceBalls.png similarity index 100% rename from src/assets/img/Food/VeggieRiceBalls.png rename to public/assets/img/Food/VeggieRiceBalls.png diff --git a/src/assets/img/Food/WarmMilk.png b/public/assets/img/Food/WarmMilk.png similarity index 100% rename from src/assets/img/Food/WarmMilk.png rename to public/assets/img/Food/WarmMilk.png diff --git a/src/assets/img/Food/WheatBread.png b/public/assets/img/Food/WheatBread.png similarity index 100% rename from src/assets/img/Food/WheatBread.png rename to public/assets/img/Food/WheatBread.png diff --git a/src/assets/img/Food/WildberryCrepe.png b/public/assets/img/Food/WildberryCrepe.png similarity index 100% rename from src/assets/img/Food/WildberryCrepe.png rename to public/assets/img/Food/WildberryCrepe.png diff --git a/src/assets/img/Key/AncientBridle.png b/public/assets/img/Key/AncientBridle.png similarity index 100% rename from src/assets/img/Key/AncientBridle.png rename to public/assets/img/Key/AncientBridle.png diff --git a/src/assets/img/Key/AncientSaddle.png b/public/assets/img/Key/AncientSaddle.png similarity index 100% rename from src/assets/img/Key/AncientSaddle.png rename to public/assets/img/Key/AncientSaddle.png diff --git a/src/assets/img/Key/ClassifiedEnvelope.png b/public/assets/img/Key/ClassifiedEnvelope.png similarity index 100% rename from src/assets/img/Key/ClassifiedEnvelope.png rename to public/assets/img/Key/ClassifiedEnvelope.png diff --git a/src/assets/img/Key/DaruksProtection.png b/public/assets/img/Key/DaruksProtection.png similarity index 100% rename from src/assets/img/Key/DaruksProtection.png rename to public/assets/img/Key/DaruksProtection.png diff --git a/src/assets/img/Key/DaruksProtectionDisabled.png b/public/assets/img/Key/DaruksProtectionDisabled.png similarity index 100% rename from src/assets/img/Key/DaruksProtectionDisabled.png rename to public/assets/img/Key/DaruksProtectionDisabled.png diff --git a/src/assets/img/Key/DaruksProtectionPlus.png b/public/assets/img/Key/DaruksProtectionPlus.png similarity index 100% rename from src/assets/img/Key/DaruksProtectionPlus.png rename to public/assets/img/Key/DaruksProtectionPlus.png diff --git a/src/assets/img/Key/DaruksProtectionPlusDisabled.png b/public/assets/img/Key/DaruksProtectionPlusDisabled.png similarity index 100% rename from src/assets/img/Key/DaruksProtectionPlusDisabled.png rename to public/assets/img/Key/DaruksProtectionPlusDisabled.png diff --git a/src/assets/img/Key/ExtravagantBridle.png b/public/assets/img/Key/ExtravagantBridle.png similarity index 100% rename from src/assets/img/Key/ExtravagantBridle.png rename to public/assets/img/Key/ExtravagantBridle.png diff --git a/src/assets/img/Key/ExtravagantSaddle.png b/public/assets/img/Key/ExtravagantSaddle.png similarity index 100% rename from src/assets/img/Key/ExtravagantSaddle.png rename to public/assets/img/Key/ExtravagantSaddle.png diff --git a/src/assets/img/Key/HestusGift.png b/public/assets/img/Key/HestusGift.png similarity index 100% rename from src/assets/img/Key/HestusGift.png rename to public/assets/img/Key/HestusGift.png diff --git a/src/assets/img/Key/HestusMaracas.png b/public/assets/img/Key/HestusMaracas.png similarity index 100% rename from src/assets/img/Key/HestusMaracas.png rename to public/assets/img/Key/HestusMaracas.png diff --git a/src/assets/img/Key/KnightsBridle.png b/public/assets/img/Key/KnightsBridle.png similarity index 100% rename from src/assets/img/Key/KnightsBridle.png rename to public/assets/img/Key/KnightsBridle.png diff --git a/src/assets/img/Key/KnightsSaddle.png b/public/assets/img/Key/KnightsSaddle.png similarity index 100% rename from src/assets/img/Key/KnightsSaddle.png rename to public/assets/img/Key/KnightsSaddle.png diff --git a/src/assets/img/Key/KorokSeed.png b/public/assets/img/Key/KorokSeed.png similarity index 100% rename from src/assets/img/Key/KorokSeed.png rename to public/assets/img/Key/KorokSeed.png diff --git a/src/assets/img/Key/MedalOfHonorHinox.png b/public/assets/img/Key/MedalOfHonorHinox.png similarity index 100% rename from src/assets/img/Key/MedalOfHonorHinox.png rename to public/assets/img/Key/MedalOfHonorHinox.png diff --git a/src/assets/img/Key/MedalOfHonorMolduga.png b/public/assets/img/Key/MedalOfHonorMolduga.png similarity index 100% rename from src/assets/img/Key/MedalOfHonorMolduga.png rename to public/assets/img/Key/MedalOfHonorMolduga.png diff --git a/src/assets/img/Key/MedalOfHonorTalus.png b/public/assets/img/Key/MedalOfHonorTalus.png similarity index 100% rename from src/assets/img/Key/MedalOfHonorTalus.png rename to public/assets/img/Key/MedalOfHonorTalus.png diff --git a/src/assets/img/Key/MedohsEmblem.png b/public/assets/img/Key/MedohsEmblem.png similarity index 100% rename from src/assets/img/Key/MedohsEmblem.png rename to public/assets/img/Key/MedohsEmblem.png diff --git a/src/assets/img/Key/MiphasGrace.png b/public/assets/img/Key/MiphasGrace.png similarity index 100% rename from src/assets/img/Key/MiphasGrace.png rename to public/assets/img/Key/MiphasGrace.png diff --git a/src/assets/img/Key/MiphasGraceDisabled.png b/public/assets/img/Key/MiphasGraceDisabled.png similarity index 100% rename from src/assets/img/Key/MiphasGraceDisabled.png rename to public/assets/img/Key/MiphasGraceDisabled.png diff --git a/src/assets/img/Key/MiphasGracePlus.png b/public/assets/img/Key/MiphasGracePlus.png similarity index 100% rename from src/assets/img/Key/MiphasGracePlus.png rename to public/assets/img/Key/MiphasGracePlus.png diff --git a/src/assets/img/Key/MiphasGracePlusDisabled.png b/public/assets/img/Key/MiphasGracePlusDisabled.png similarity index 100% rename from src/assets/img/Key/MiphasGracePlusDisabled.png rename to public/assets/img/Key/MiphasGracePlusDisabled.png diff --git a/src/assets/img/Key/MonsterBridle.png b/public/assets/img/Key/MonsterBridle.png similarity index 100% rename from src/assets/img/Key/MonsterBridle.png rename to public/assets/img/Key/MonsterBridle.png diff --git a/src/assets/img/Key/MonsterSaddle.png b/public/assets/img/Key/MonsterSaddle.png similarity index 100% rename from src/assets/img/Key/MonsterSaddle.png rename to public/assets/img/Key/MonsterSaddle.png diff --git a/src/assets/img/Key/NaborissEmblem.png b/public/assets/img/Key/NaborissEmblem.png similarity index 100% rename from src/assets/img/Key/NaborissEmblem.png rename to public/assets/img/Key/NaborissEmblem.png diff --git a/src/assets/img/Key/Paraglider.png b/public/assets/img/Key/Paraglider.png similarity index 100% rename from src/assets/img/Key/Paraglider.png rename to public/assets/img/Key/Paraglider.png diff --git a/src/assets/img/Key/PictureOfTheChampions.png b/public/assets/img/Key/PictureOfTheChampions.png similarity index 100% rename from src/assets/img/Key/PictureOfTheChampions.png rename to public/assets/img/Key/PictureOfTheChampions.png diff --git a/src/assets/img/Key/RevalisGale.png b/public/assets/img/Key/RevalisGale.png similarity index 100% rename from src/assets/img/Key/RevalisGale.png rename to public/assets/img/Key/RevalisGale.png diff --git a/src/assets/img/Key/RevalisGaleDisabled.png b/public/assets/img/Key/RevalisGaleDisabled.png similarity index 100% rename from src/assets/img/Key/RevalisGaleDisabled.png rename to public/assets/img/Key/RevalisGaleDisabled.png diff --git a/src/assets/img/Key/RevalisGalePlus.png b/public/assets/img/Key/RevalisGalePlus.png similarity index 100% rename from src/assets/img/Key/RevalisGalePlus.png rename to public/assets/img/Key/RevalisGalePlus.png diff --git a/src/assets/img/Key/RevalisGalePlusDisabled.png b/public/assets/img/Key/RevalisGalePlusDisabled.png similarity index 100% rename from src/assets/img/Key/RevalisGalePlusDisabled.png rename to public/assets/img/Key/RevalisGalePlusDisabled.png diff --git a/src/assets/img/Key/RoyalBridle.png b/public/assets/img/Key/RoyalBridle.png similarity index 100% rename from src/assets/img/Key/RoyalBridle.png rename to public/assets/img/Key/RoyalBridle.png diff --git a/src/assets/img/Key/RoyalSaddle.png b/public/assets/img/Key/RoyalSaddle.png similarity index 100% rename from src/assets/img/Key/RoyalSaddle.png rename to public/assets/img/Key/RoyalSaddle.png diff --git a/src/assets/img/Key/RudaniasEmblem.png b/public/assets/img/Key/RudaniasEmblem.png similarity index 100% rename from src/assets/img/Key/RudaniasEmblem.png rename to public/assets/img/Key/RudaniasEmblem.png diff --git a/src/assets/img/Key/RutasEmblem.png b/public/assets/img/Key/RutasEmblem.png similarity index 100% rename from src/assets/img/Key/RutasEmblem.png rename to public/assets/img/Key/RutasEmblem.png diff --git a/src/assets/img/Key/SheikahSlate.png b/public/assets/img/Key/SheikahSlate.png similarity index 100% rename from src/assets/img/Key/SheikahSlate.png rename to public/assets/img/Key/SheikahSlate.png diff --git a/src/assets/img/Key/SpiritOrb.png b/public/assets/img/Key/SpiritOrb.png similarity index 100% rename from src/assets/img/Key/SpiritOrb.png rename to public/assets/img/Key/SpiritOrb.png diff --git a/src/assets/img/Key/SpiritOrbAnimated.webp b/public/assets/img/Key/SpiritOrbAnimated.webp similarity index 100% rename from src/assets/img/Key/SpiritOrbAnimated.webp rename to public/assets/img/Key/SpiritOrbAnimated.webp diff --git a/src/assets/img/Key/ThunderHelmKeyItem.png b/public/assets/img/Key/ThunderHelmKey.png similarity index 100% rename from src/assets/img/Key/ThunderHelmKeyItem.png rename to public/assets/img/Key/ThunderHelmKey.png diff --git a/src/assets/img/Key/TravelMedallion.png b/public/assets/img/Key/TravelMedallion.png similarity index 100% rename from src/assets/img/Key/TravelMedallion.png rename to public/assets/img/Key/TravelMedallion.png diff --git a/src/assets/img/Key/TravelMedallionAnimated.webp b/public/assets/img/Key/TravelMedallionAnimated.webp similarity index 100% rename from src/assets/img/Key/TravelMedallionAnimated.webp rename to public/assets/img/Key/TravelMedallionAnimated.webp diff --git a/src/assets/img/Key/TravelersBridle.png b/public/assets/img/Key/TravelersBridle.png similarity index 100% rename from src/assets/img/Key/TravelersBridle.png rename to public/assets/img/Key/TravelersBridle.png diff --git a/src/assets/img/Key/TravelersSaddle.png b/public/assets/img/Key/TravelersSaddle.png similarity index 100% rename from src/assets/img/Key/TravelersSaddle.png rename to public/assets/img/Key/TravelersSaddle.png diff --git a/src/assets/img/Key/UrbosasFury.png b/public/assets/img/Key/UrbosasFury.png similarity index 100% rename from src/assets/img/Key/UrbosasFury.png rename to public/assets/img/Key/UrbosasFury.png diff --git a/src/assets/img/Key/UrbosasFuryDisabled.png b/public/assets/img/Key/UrbosasFuryDisabled.png similarity index 100% rename from src/assets/img/Key/UrbosasFuryDisabled.png rename to public/assets/img/Key/UrbosasFuryDisabled.png diff --git a/src/assets/img/Key/UrbosasFuryPlus.png b/public/assets/img/Key/UrbosasFuryPlus.png similarity index 100% rename from src/assets/img/Key/UrbosasFuryPlus.png rename to public/assets/img/Key/UrbosasFuryPlus.png diff --git a/src/assets/img/Key/UrbosasFuryPlusDisabled.png b/public/assets/img/Key/UrbosasFuryPlusDisabled.png similarity index 100% rename from src/assets/img/Key/UrbosasFuryPlusDisabled.png rename to public/assets/img/Key/UrbosasFuryPlusDisabled.png diff --git a/src/assets/img/Material/Acorn.png b/public/assets/img/Material/Acorn.png similarity index 100% rename from src/assets/img/Material/Acorn.png rename to public/assets/img/Material/Acorn.png diff --git a/src/assets/img/Material/Amber.png b/public/assets/img/Material/Amber.png similarity index 100% rename from src/assets/img/Material/Amber.png rename to public/assets/img/Material/Amber.png diff --git a/src/assets/img/Material/AncientCore.png b/public/assets/img/Material/AncientCore.png similarity index 100% rename from src/assets/img/Material/AncientCore.png rename to public/assets/img/Material/AncientCore.png diff --git a/src/assets/img/Material/AncientGear.png b/public/assets/img/Material/AncientGear.png similarity index 100% rename from src/assets/img/Material/AncientGear.png rename to public/assets/img/Material/AncientGear.png diff --git a/src/assets/img/Material/AncientScrew.png b/public/assets/img/Material/AncientScrew.png similarity index 100% rename from src/assets/img/Material/AncientScrew.png rename to public/assets/img/Material/AncientScrew.png diff --git a/src/assets/img/Material/AncientShaft.png b/public/assets/img/Material/AncientShaft.png similarity index 100% rename from src/assets/img/Material/AncientShaft.png rename to public/assets/img/Material/AncientShaft.png diff --git a/src/assets/img/Material/AncientSpring.png b/public/assets/img/Material/AncientSpring.png similarity index 100% rename from src/assets/img/Material/AncientSpring.png rename to public/assets/img/Material/AncientSpring.png diff --git a/src/assets/img/Material/Apple.png b/public/assets/img/Material/Apple.png similarity index 100% rename from src/assets/img/Material/Apple.png rename to public/assets/img/Material/Apple.png diff --git a/src/assets/img/Material/Armoranth.png b/public/assets/img/Material/Armoranth.png similarity index 100% rename from src/assets/img/Material/Armoranth.png rename to public/assets/img/Material/Armoranth.png diff --git a/src/assets/img/Material/ArmoredCarp.png b/public/assets/img/Material/ArmoredCarp.png similarity index 100% rename from src/assets/img/Material/ArmoredCarp.png rename to public/assets/img/Material/ArmoredCarp.png diff --git a/src/assets/img/Material/ArmoredPorgy.png b/public/assets/img/Material/ArmoredPorgy.png similarity index 100% rename from src/assets/img/Material/ArmoredPorgy.png rename to public/assets/img/Material/ArmoredPorgy.png diff --git a/src/assets/img/Material/BigHeartyRadish.png b/public/assets/img/Material/BigHeartyRadish.png similarity index 100% rename from src/assets/img/Material/BigHeartyRadish.png rename to public/assets/img/Material/BigHeartyRadish.png diff --git a/src/assets/img/Material/BigHeartyTruffle.png b/public/assets/img/Material/BigHeartyTruffle.png similarity index 100% rename from src/assets/img/Material/BigHeartyTruffle.png rename to public/assets/img/Material/BigHeartyTruffle.png diff --git a/src/assets/img/Material/BirdEgg.png b/public/assets/img/Material/BirdEgg.png similarity index 100% rename from src/assets/img/Material/BirdEgg.png rename to public/assets/img/Material/BirdEgg.png diff --git a/src/assets/img/Material/BladedRhinoBeetle.png b/public/assets/img/Material/BladedRhinoBeetle.png similarity index 100% rename from src/assets/img/Material/BladedRhinoBeetle.png rename to public/assets/img/Material/BladedRhinoBeetle.png diff --git a/src/assets/img/Material/BlueNightshade.png b/public/assets/img/Material/BlueNightshade.png similarity index 100% rename from src/assets/img/Material/BlueNightshade.png rename to public/assets/img/Material/BlueNightshade.png diff --git a/src/assets/img/Material/BokoblinFang.png b/public/assets/img/Material/BokoblinFang.png similarity index 100% rename from src/assets/img/Material/BokoblinFang.png rename to public/assets/img/Material/BokoblinFang.png diff --git a/src/assets/img/Material/BokoblinGuts.png b/public/assets/img/Material/BokoblinGuts.png similarity index 100% rename from src/assets/img/Material/BokoblinGuts.png rename to public/assets/img/Material/BokoblinGuts.png diff --git a/src/assets/img/Material/BokoblinHorn.png b/public/assets/img/Material/BokoblinHorn.png similarity index 100% rename from src/assets/img/Material/BokoblinHorn.png rename to public/assets/img/Material/BokoblinHorn.png diff --git a/src/assets/img/Material/BrightEyedCrab.png b/public/assets/img/Material/BrightEyedCrab.png similarity index 100% rename from src/assets/img/Material/BrightEyedCrab.png rename to public/assets/img/Material/BrightEyedCrab.png diff --git a/src/assets/img/Material/CaneSugar.png b/public/assets/img/Material/CaneSugar.png similarity index 100% rename from src/assets/img/Material/CaneSugar.png rename to public/assets/img/Material/CaneSugar.png diff --git a/src/assets/img/Material/ChickalooTreeNut.png b/public/assets/img/Material/ChickalooTreeNut.png similarity index 100% rename from src/assets/img/Material/ChickalooTreeNut.png rename to public/assets/img/Material/ChickalooTreeNut.png diff --git a/src/assets/img/Material/ChillfinTrout.png b/public/assets/img/Material/ChillfinTrout.png similarity index 100% rename from src/assets/img/Material/ChillfinTrout.png rename to public/assets/img/Material/ChillfinTrout.png diff --git a/src/assets/img/Material/Chillshroom.png b/public/assets/img/Material/Chillshroom.png similarity index 100% rename from src/assets/img/Material/Chillshroom.png rename to public/assets/img/Material/Chillshroom.png diff --git a/src/assets/img/Material/ChuchuJelly.png b/public/assets/img/Material/ChuchuJelly.png similarity index 100% rename from src/assets/img/Material/ChuchuJelly.png rename to public/assets/img/Material/ChuchuJelly.png diff --git a/src/assets/img/Material/ColdDarner.png b/public/assets/img/Material/ColdDarner.png similarity index 100% rename from src/assets/img/Material/ColdDarner.png rename to public/assets/img/Material/ColdDarner.png diff --git a/src/assets/img/Material/CoolSafflina.png b/public/assets/img/Material/CoolSafflina.png similarity index 100% rename from src/assets/img/Material/CoolSafflina.png rename to public/assets/img/Material/CoolSafflina.png diff --git a/src/assets/img/Material/CourserBeeHoney.png b/public/assets/img/Material/CourserBeeHoney.png similarity index 100% rename from src/assets/img/Material/CourserBeeHoney.png rename to public/assets/img/Material/CourserBeeHoney.png diff --git a/src/assets/img/Material/Diamond.png b/public/assets/img/Material/Diamond.png similarity index 100% rename from src/assets/img/Material/Diamond.png rename to public/assets/img/Material/Diamond.png diff --git a/src/assets/img/Material/DinraalsClaw.png b/public/assets/img/Material/DinraalsClaw.png similarity index 100% rename from src/assets/img/Material/DinraalsClaw.png rename to public/assets/img/Material/DinraalsClaw.png diff --git a/src/assets/img/Material/DinraalsScale.png b/public/assets/img/Material/DinraalsScale.png similarity index 100% rename from src/assets/img/Material/DinraalsScale.png rename to public/assets/img/Material/DinraalsScale.png diff --git a/src/assets/img/Material/ElectricDarner.png b/public/assets/img/Material/ElectricDarner.png similarity index 100% rename from src/assets/img/Material/ElectricDarner.png rename to public/assets/img/Material/ElectricDarner.png diff --git a/src/assets/img/Material/ElectricKeeseWing.png b/public/assets/img/Material/ElectricKeeseWing.png similarity index 100% rename from src/assets/img/Material/ElectricKeeseWing.png rename to public/assets/img/Material/ElectricKeeseWing.png diff --git a/src/assets/img/Material/ElectricSafflina.png b/public/assets/img/Material/ElectricSafflina.png similarity index 100% rename from src/assets/img/Material/ElectricSafflina.png rename to public/assets/img/Material/ElectricSafflina.png diff --git a/src/assets/img/Material/EnduraCarrot.png b/public/assets/img/Material/EnduraCarrot.png similarity index 100% rename from src/assets/img/Material/EnduraCarrot.png rename to public/assets/img/Material/EnduraCarrot.png diff --git a/src/assets/img/Material/EnduraShroom.png b/public/assets/img/Material/EnduraShroom.png similarity index 100% rename from src/assets/img/Material/EnduraShroom.png rename to public/assets/img/Material/EnduraShroom.png diff --git a/src/assets/img/Material/EnergeticRhinoBeetle.png b/public/assets/img/Material/EnergeticRhinoBeetle.png similarity index 100% rename from src/assets/img/Material/EnergeticRhinoBeetle.png rename to public/assets/img/Material/EnergeticRhinoBeetle.png diff --git a/src/assets/img/Material/Fairy.png b/public/assets/img/Material/Fairy.png similarity index 100% rename from src/assets/img/Material/Fairy.png rename to public/assets/img/Material/Fairy.png diff --git a/src/assets/img/Material/FaroshsClaw.png b/public/assets/img/Material/FaroshsClaw.png similarity index 100% rename from src/assets/img/Material/FaroshsClaw.png rename to public/assets/img/Material/FaroshsClaw.png diff --git a/src/assets/img/Material/FaroshsScale.png b/public/assets/img/Material/FaroshsScale.png similarity index 100% rename from src/assets/img/Material/FaroshsScale.png rename to public/assets/img/Material/FaroshsScale.png diff --git a/src/assets/img/Material/FireKeeseWing.png b/public/assets/img/Material/FireKeeseWing.png similarity index 100% rename from src/assets/img/Material/FireKeeseWing.png rename to public/assets/img/Material/FireKeeseWing.png diff --git a/src/assets/img/Material/FireproofLizard.png b/public/assets/img/Material/FireproofLizard.png similarity index 100% rename from src/assets/img/Material/FireproofLizard.png rename to public/assets/img/Material/FireproofLizard.png diff --git a/src/assets/img/Material/FleetLotusSeeds.png b/public/assets/img/Material/FleetLotusSeeds.png similarity index 100% rename from src/assets/img/Material/FleetLotusSeeds.png rename to public/assets/img/Material/FleetLotusSeeds.png diff --git a/src/assets/img/Material/Flint.png b/public/assets/img/Material/Flint.png similarity index 100% rename from src/assets/img/Material/Flint.png rename to public/assets/img/Material/Flint.png diff --git a/src/assets/img/Material/FortifiedPumpkin.png b/public/assets/img/Material/FortifiedPumpkin.png similarity index 100% rename from src/assets/img/Material/FortifiedPumpkin.png rename to public/assets/img/Material/FortifiedPumpkin.png diff --git a/src/assets/img/Material/FreshMilk.png b/public/assets/img/Material/FreshMilk.png similarity index 100% rename from src/assets/img/Material/FreshMilk.png rename to public/assets/img/Material/FreshMilk.png diff --git a/src/assets/img/Material/GiantAncientCore.png b/public/assets/img/Material/GiantAncientCore.png similarity index 100% rename from src/assets/img/Material/GiantAncientCore.png rename to public/assets/img/Material/GiantAncientCore.png diff --git a/src/assets/img/Material/GoatButter.png b/public/assets/img/Material/GoatButter.png similarity index 100% rename from src/assets/img/Material/GoatButter.png rename to public/assets/img/Material/GoatButter.png diff --git a/src/assets/img/Material/GoronSpice.png b/public/assets/img/Material/GoronSpice.png similarity index 100% rename from src/assets/img/Material/GoronSpice.png rename to public/assets/img/Material/GoronSpice.png diff --git a/src/assets/img/Material/HeartyBass.png b/public/assets/img/Material/HeartyBass.png similarity index 100% rename from src/assets/img/Material/HeartyBass.png rename to public/assets/img/Material/HeartyBass.png diff --git a/src/assets/img/Material/HeartyBlueshellSnail.png b/public/assets/img/Material/HeartyBlueshellSnail.png similarity index 100% rename from src/assets/img/Material/HeartyBlueshellSnail.png rename to public/assets/img/Material/HeartyBlueshellSnail.png diff --git a/src/assets/img/Material/HeartyDurian.png b/public/assets/img/Material/HeartyDurian.png similarity index 100% rename from src/assets/img/Material/HeartyDurian.png rename to public/assets/img/Material/HeartyDurian.png diff --git a/src/assets/img/Material/HeartyLizard.png b/public/assets/img/Material/HeartyLizard.png similarity index 100% rename from src/assets/img/Material/HeartyLizard.png rename to public/assets/img/Material/HeartyLizard.png diff --git a/src/assets/img/Material/HeartyRadish.png b/public/assets/img/Material/HeartyRadish.png similarity index 100% rename from src/assets/img/Material/HeartyRadish.png rename to public/assets/img/Material/HeartyRadish.png diff --git a/src/assets/img/Material/HeartySalmon.png b/public/assets/img/Material/HeartySalmon.png similarity index 100% rename from src/assets/img/Material/HeartySalmon.png rename to public/assets/img/Material/HeartySalmon.png diff --git a/src/assets/img/Material/HeartyTruffle.png b/public/assets/img/Material/HeartyTruffle.png similarity index 100% rename from src/assets/img/Material/HeartyTruffle.png rename to public/assets/img/Material/HeartyTruffle.png diff --git a/src/assets/img/Material/HightailLizard.png b/public/assets/img/Material/HightailLizard.png similarity index 100% rename from src/assets/img/Material/HightailLizard.png rename to public/assets/img/Material/HightailLizard.png diff --git a/src/assets/img/Material/HinoxGuts.png b/public/assets/img/Material/HinoxGuts.png similarity index 100% rename from src/assets/img/Material/HinoxGuts.png rename to public/assets/img/Material/HinoxGuts.png diff --git a/src/assets/img/Material/HinoxToenail.png b/public/assets/img/Material/HinoxToenail.png similarity index 100% rename from src/assets/img/Material/HinoxToenail.png rename to public/assets/img/Material/HinoxToenail.png diff --git a/src/assets/img/Material/HinoxTooth.png b/public/assets/img/Material/HinoxTooth.png similarity index 100% rename from src/assets/img/Material/HinoxTooth.png rename to public/assets/img/Material/HinoxTooth.png diff --git a/src/assets/img/Material/HotFootedFrog.png b/public/assets/img/Material/HotFootedFrog.png similarity index 100% rename from src/assets/img/Material/HotFootedFrog.png rename to public/assets/img/Material/HotFootedFrog.png diff --git a/src/assets/img/Material/Hydromelon.png b/public/assets/img/Material/Hydromelon.png similarity index 100% rename from src/assets/img/Material/Hydromelon.png rename to public/assets/img/Material/Hydromelon.png diff --git a/src/assets/img/Material/HylianRice.png b/public/assets/img/Material/HylianRice.png similarity index 100% rename from src/assets/img/Material/HylianRice.png rename to public/assets/img/Material/HylianRice.png diff --git a/src/assets/img/Material/HylianShroom.png b/public/assets/img/Material/HylianShroom.png similarity index 100% rename from src/assets/img/Material/HylianShroom.png rename to public/assets/img/Material/HylianShroom.png diff --git a/src/assets/img/Material/HyruleBass.png b/public/assets/img/Material/HyruleBass.png similarity index 100% rename from src/assets/img/Material/HyruleBass.png rename to public/assets/img/Material/HyruleBass.png diff --git a/src/assets/img/Material/HyruleHerb.png b/public/assets/img/Material/HyruleHerb.png similarity index 100% rename from src/assets/img/Material/HyruleHerb.png rename to public/assets/img/Material/HyruleHerb.png diff --git a/src/assets/img/Material/IceKeeseWing.png b/public/assets/img/Material/IceKeeseWing.png similarity index 100% rename from src/assets/img/Material/IceKeeseWing.png rename to public/assets/img/Material/IceKeeseWing.png diff --git a/src/assets/img/Material/IcyLizalfosTail.png b/public/assets/img/Material/IcyLizalfosTail.png similarity index 100% rename from src/assets/img/Material/IcyLizalfosTail.png rename to public/assets/img/Material/IcyLizalfosTail.png diff --git a/src/assets/img/Material/IronshellCrab.png b/public/assets/img/Material/IronshellCrab.png similarity index 100% rename from src/assets/img/Material/IronshellCrab.png rename to public/assets/img/Material/IronshellCrab.png diff --git a/src/assets/img/Material/Ironshroom.png b/public/assets/img/Material/Ironshroom.png similarity index 100% rename from src/assets/img/Material/Ironshroom.png rename to public/assets/img/Material/Ironshroom.png diff --git a/src/assets/img/Material/KeeseEyeball.png b/public/assets/img/Material/KeeseEyeball.png similarity index 100% rename from src/assets/img/Material/KeeseEyeball.png rename to public/assets/img/Material/KeeseEyeball.png diff --git a/src/assets/img/Material/KeeseWing.png b/public/assets/img/Material/KeeseWing.png similarity index 100% rename from src/assets/img/Material/KeeseWing.png rename to public/assets/img/Material/KeeseWing.png diff --git a/src/assets/img/Material/LizalfosHorn.png b/public/assets/img/Material/LizalfosHorn.png similarity index 100% rename from src/assets/img/Material/LizalfosHorn.png rename to public/assets/img/Material/LizalfosHorn.png diff --git a/src/assets/img/Material/LizalfosTail.png b/public/assets/img/Material/LizalfosTail.png similarity index 100% rename from src/assets/img/Material/LizalfosTail.png rename to public/assets/img/Material/LizalfosTail.png diff --git a/src/assets/img/Material/LizalfosTalon.png b/public/assets/img/Material/LizalfosTalon.png similarity index 100% rename from src/assets/img/Material/LizalfosTalon.png rename to public/assets/img/Material/LizalfosTalon.png diff --git a/src/assets/img/Material/LuminousStone.png b/public/assets/img/Material/LuminousStone.png similarity index 100% rename from src/assets/img/Material/LuminousStone.png rename to public/assets/img/Material/LuminousStone.png diff --git a/src/assets/img/Material/LynelGuts.png b/public/assets/img/Material/LynelGuts.png similarity index 100% rename from src/assets/img/Material/LynelGuts.png rename to public/assets/img/Material/LynelGuts.png diff --git a/src/assets/img/Material/LynelHoof.png b/public/assets/img/Material/LynelHoof.png similarity index 100% rename from src/assets/img/Material/LynelHoof.png rename to public/assets/img/Material/LynelHoof.png diff --git a/src/assets/img/Material/LynelHorn.png b/public/assets/img/Material/LynelHorn.png similarity index 100% rename from src/assets/img/Material/LynelHorn.png rename to public/assets/img/Material/LynelHorn.png diff --git a/src/assets/img/Material/MightyBananas.png b/public/assets/img/Material/MightyBananas.png similarity index 100% rename from src/assets/img/Material/MightyBananas.png rename to public/assets/img/Material/MightyBananas.png diff --git a/src/assets/img/Material/MightyCarp.png b/public/assets/img/Material/MightyCarp.png similarity index 100% rename from src/assets/img/Material/MightyCarp.png rename to public/assets/img/Material/MightyCarp.png diff --git a/src/assets/img/Material/MightyPorgy.png b/public/assets/img/Material/MightyPorgy.png similarity index 100% rename from src/assets/img/Material/MightyPorgy.png rename to public/assets/img/Material/MightyPorgy.png diff --git a/src/assets/img/Material/MightyThistle.png b/public/assets/img/Material/MightyThistle.png similarity index 100% rename from src/assets/img/Material/MightyThistle.png rename to public/assets/img/Material/MightyThistle.png diff --git a/src/assets/img/Material/MoblinFang.png b/public/assets/img/Material/MoblinFang.png similarity index 100% rename from src/assets/img/Material/MoblinFang.png rename to public/assets/img/Material/MoblinFang.png diff --git a/src/assets/img/Material/MoblinGuts.png b/public/assets/img/Material/MoblinGuts.png similarity index 100% rename from src/assets/img/Material/MoblinGuts.png rename to public/assets/img/Material/MoblinGuts.png diff --git a/src/assets/img/Material/MoblinHorn.png b/public/assets/img/Material/MoblinHorn.png similarity index 100% rename from src/assets/img/Material/MoblinHorn.png rename to public/assets/img/Material/MoblinHorn.png diff --git a/src/assets/img/Material/MoldugaFin.png b/public/assets/img/Material/MoldugaFin.png similarity index 100% rename from src/assets/img/Material/MoldugaFin.png rename to public/assets/img/Material/MoldugaFin.png diff --git a/src/assets/img/Material/MoldugaGuts.png b/public/assets/img/Material/MoldugaGuts.png similarity index 100% rename from src/assets/img/Material/MoldugaGuts.png rename to public/assets/img/Material/MoldugaGuts.png diff --git a/src/assets/img/Material/MonsterExtract.png b/public/assets/img/Material/MonsterExtract.png similarity index 100% rename from src/assets/img/Material/MonsterExtract.png rename to public/assets/img/Material/MonsterExtract.png diff --git a/src/assets/img/Material/NaydrasClaw.png b/public/assets/img/Material/NaydrasClaw.png similarity index 100% rename from src/assets/img/Material/NaydrasClaw.png rename to public/assets/img/Material/NaydrasClaw.png diff --git a/src/assets/img/Material/NaydrasScale.png b/public/assets/img/Material/NaydrasScale.png similarity index 100% rename from src/assets/img/Material/NaydrasScale.png rename to public/assets/img/Material/NaydrasScale.png diff --git a/src/assets/img/Material/OctoBalloon.png b/public/assets/img/Material/OctoBalloon.png similarity index 100% rename from src/assets/img/Material/OctoBalloon.png rename to public/assets/img/Material/OctoBalloon.png diff --git a/src/assets/img/Material/OctorokEyeball.png b/public/assets/img/Material/OctorokEyeball.png similarity index 100% rename from src/assets/img/Material/OctorokEyeball.png rename to public/assets/img/Material/OctorokEyeball.png diff --git a/src/assets/img/Material/OctorokTentacle.png b/public/assets/img/Material/OctorokTentacle.png similarity index 100% rename from src/assets/img/Material/OctorokTentacle.png rename to public/assets/img/Material/OctorokTentacle.png diff --git a/src/assets/img/Material/Opal.png b/public/assets/img/Material/Opal.png similarity index 100% rename from src/assets/img/Material/Opal.png rename to public/assets/img/Material/Opal.png diff --git a/src/assets/img/Material/PalmFruit.png b/public/assets/img/Material/PalmFruit.png similarity index 100% rename from src/assets/img/Material/PalmFruit.png rename to public/assets/img/Material/PalmFruit.png diff --git a/src/assets/img/Material/RawBirdDrumstick.png b/public/assets/img/Material/RawBirdDrumstick.png similarity index 100% rename from src/assets/img/Material/RawBirdDrumstick.png rename to public/assets/img/Material/RawBirdDrumstick.png diff --git a/src/assets/img/Material/RawBirdThigh.png b/public/assets/img/Material/RawBirdThigh.png similarity index 100% rename from src/assets/img/Material/RawBirdThigh.png rename to public/assets/img/Material/RawBirdThigh.png diff --git a/src/assets/img/Material/RawGourmetMeat.png b/public/assets/img/Material/RawGourmetMeat.png similarity index 100% rename from src/assets/img/Material/RawGourmetMeat.png rename to public/assets/img/Material/RawGourmetMeat.png diff --git a/src/assets/img/Material/RawMeat.png b/public/assets/img/Material/RawMeat.png similarity index 100% rename from src/assets/img/Material/RawMeat.png rename to public/assets/img/Material/RawMeat.png diff --git a/src/assets/img/Material/RawPrimeMeat.png b/public/assets/img/Material/RawPrimeMeat.png similarity index 100% rename from src/assets/img/Material/RawPrimeMeat.png rename to public/assets/img/Material/RawPrimeMeat.png diff --git a/src/assets/img/Material/RawWholeBird.png b/public/assets/img/Material/RawWholeBird.png similarity index 100% rename from src/assets/img/Material/RawWholeBird.png rename to public/assets/img/Material/RawWholeBird.png diff --git a/src/assets/img/Material/RazorclawCrab.png b/public/assets/img/Material/RazorclawCrab.png similarity index 100% rename from src/assets/img/Material/RazorclawCrab.png rename to public/assets/img/Material/RazorclawCrab.png diff --git a/src/assets/img/Material/Razorshroom.png b/public/assets/img/Material/Razorshroom.png similarity index 100% rename from src/assets/img/Material/Razorshroom.png rename to public/assets/img/Material/Razorshroom.png diff --git a/src/assets/img/Material/RedChuchuJelly.png b/public/assets/img/Material/RedChuchuJelly.png similarity index 100% rename from src/assets/img/Material/RedChuchuJelly.png rename to public/assets/img/Material/RedChuchuJelly.png diff --git a/src/assets/img/Material/RedLizalfosTail.png b/public/assets/img/Material/RedLizalfosTail.png similarity index 100% rename from src/assets/img/Material/RedLizalfosTail.png rename to public/assets/img/Material/RedLizalfosTail.png diff --git a/src/assets/img/Material/RestlessCricket.png b/public/assets/img/Material/RestlessCricket.png similarity index 100% rename from src/assets/img/Material/RestlessCricket.png rename to public/assets/img/Material/RestlessCricket.png diff --git a/src/assets/img/Material/RockSalt.png b/public/assets/img/Material/RockSalt.png similarity index 100% rename from src/assets/img/Material/RockSalt.png rename to public/assets/img/Material/RockSalt.png diff --git a/src/assets/img/Material/Ruby.png b/public/assets/img/Material/Ruby.png similarity index 100% rename from src/assets/img/Material/Ruby.png rename to public/assets/img/Material/Ruby.png diff --git a/src/assets/img/Material/RuggedRhinoBeetle.png b/public/assets/img/Material/RuggedRhinoBeetle.png similarity index 100% rename from src/assets/img/Material/RuggedRhinoBeetle.png rename to public/assets/img/Material/RuggedRhinoBeetle.png diff --git a/src/assets/img/Material/Rushroom.png b/public/assets/img/Material/Rushroom.png similarity index 100% rename from src/assets/img/Material/Rushroom.png rename to public/assets/img/Material/Rushroom.png diff --git a/src/assets/img/Material/SankeCarp.png b/public/assets/img/Material/SankeCarp.png similarity index 100% rename from src/assets/img/Material/SankeCarp.png rename to public/assets/img/Material/SankeCarp.png diff --git a/src/assets/img/Material/Sapphire.png b/public/assets/img/Material/Sapphire.png similarity index 100% rename from src/assets/img/Material/Sapphire.png rename to public/assets/img/Material/Sapphire.png diff --git a/src/assets/img/Material/ShardOfDinraalsFang.png b/public/assets/img/Material/ShardOfDinraalsFang.png similarity index 100% rename from src/assets/img/Material/ShardOfDinraalsFang.png rename to public/assets/img/Material/ShardOfDinraalsFang.png diff --git a/src/assets/img/Material/ShardOfDinraalsHorn.png b/public/assets/img/Material/ShardOfDinraalsHorn.png similarity index 100% rename from src/assets/img/Material/ShardOfDinraalsHorn.png rename to public/assets/img/Material/ShardOfDinraalsHorn.png diff --git a/src/assets/img/Material/ShardOfFaroshsFang.png b/public/assets/img/Material/ShardOfFaroshsFang.png similarity index 100% rename from src/assets/img/Material/ShardOfFaroshsFang.png rename to public/assets/img/Material/ShardOfFaroshsFang.png diff --git a/src/assets/img/Material/ShardOfFaroshsHorn.png b/public/assets/img/Material/ShardOfFaroshsHorn.png similarity index 100% rename from src/assets/img/Material/ShardOfFaroshsHorn.png rename to public/assets/img/Material/ShardOfFaroshsHorn.png diff --git a/src/assets/img/Material/ShardOfNaydrasFang.png b/public/assets/img/Material/ShardOfNaydrasFang.png similarity index 100% rename from src/assets/img/Material/ShardOfNaydrasFang.png rename to public/assets/img/Material/ShardOfNaydrasFang.png diff --git a/src/assets/img/Material/ShardOfNaydrasHorn.png b/public/assets/img/Material/ShardOfNaydrasHorn.png similarity index 100% rename from src/assets/img/Material/ShardOfNaydrasHorn.png rename to public/assets/img/Material/ShardOfNaydrasHorn.png diff --git a/src/assets/img/Material/SilentPrincess.png b/public/assets/img/Material/SilentPrincess.png similarity index 100% rename from src/assets/img/Material/SilentPrincess.png rename to public/assets/img/Material/SilentPrincess.png diff --git a/src/assets/img/Material/SilentShroom.png b/public/assets/img/Material/SilentShroom.png similarity index 100% rename from src/assets/img/Material/SilentShroom.png rename to public/assets/img/Material/SilentShroom.png diff --git a/src/assets/img/Material/SizzlefinTrout.png b/public/assets/img/Material/SizzlefinTrout.png similarity index 100% rename from src/assets/img/Material/SizzlefinTrout.png rename to public/assets/img/Material/SizzlefinTrout.png diff --git a/src/assets/img/Material/SmotherwingButterfly.png b/public/assets/img/Material/SmotherwingButterfly.png similarity index 100% rename from src/assets/img/Material/SmotherwingButterfly.png rename to public/assets/img/Material/SmotherwingButterfly.png diff --git a/src/assets/img/Material/SneakyRiverSnail.png b/public/assets/img/Material/SneakyRiverSnail.png similarity index 100% rename from src/assets/img/Material/SneakyRiverSnail.png rename to public/assets/img/Material/SneakyRiverSnail.png diff --git a/src/assets/img/Material/SpicyPepper.png b/public/assets/img/Material/SpicyPepper.png similarity index 100% rename from src/assets/img/Material/SpicyPepper.png rename to public/assets/img/Material/SpicyPepper.png diff --git a/src/assets/img/Material/StamellaShroom.png b/public/assets/img/Material/StamellaShroom.png similarity index 100% rename from src/assets/img/Material/StamellaShroom.png rename to public/assets/img/Material/StamellaShroom.png diff --git a/src/assets/img/Material/StaminokaBass.png b/public/assets/img/Material/StaminokaBass.png similarity index 100% rename from src/assets/img/Material/StaminokaBass.png rename to public/assets/img/Material/StaminokaBass.png diff --git a/src/assets/img/Material/StarFragment.png b/public/assets/img/Material/StarFragment.png similarity index 100% rename from src/assets/img/Material/StarFragment.png rename to public/assets/img/Material/StarFragment.png diff --git a/src/assets/img/Material/StealthfinTrout.png b/public/assets/img/Material/StealthfinTrout.png similarity index 100% rename from src/assets/img/Material/StealthfinTrout.png rename to public/assets/img/Material/StealthfinTrout.png diff --git a/src/assets/img/Material/SummerwingButterfly.png b/public/assets/img/Material/SummerwingButterfly.png similarity index 100% rename from src/assets/img/Material/SummerwingButterfly.png rename to public/assets/img/Material/SummerwingButterfly.png diff --git a/src/assets/img/Material/SunsetFirefly.png b/public/assets/img/Material/SunsetFirefly.png similarity index 100% rename from src/assets/img/Material/SunsetFirefly.png rename to public/assets/img/Material/SunsetFirefly.png diff --git a/src/assets/img/Material/Sunshroom.png b/public/assets/img/Material/Sunshroom.png similarity index 100% rename from src/assets/img/Material/Sunshroom.png rename to public/assets/img/Material/Sunshroom.png diff --git a/src/assets/img/Material/SwiftCarrot.png b/public/assets/img/Material/SwiftCarrot.png similarity index 100% rename from src/assets/img/Material/SwiftCarrot.png rename to public/assets/img/Material/SwiftCarrot.png diff --git a/src/assets/img/Material/SwiftViolet.png b/public/assets/img/Material/SwiftViolet.png similarity index 100% rename from src/assets/img/Material/SwiftViolet.png rename to public/assets/img/Material/SwiftViolet.png diff --git a/src/assets/img/Material/TabanthaWheat.png b/public/assets/img/Material/TabanthaWheat.png similarity index 100% rename from src/assets/img/Material/TabanthaWheat.png rename to public/assets/img/Material/TabanthaWheat.png diff --git a/src/assets/img/Material/ThunderwingButterfly.png b/public/assets/img/Material/ThunderwingButterfly.png similarity index 100% rename from src/assets/img/Material/ThunderwingButterfly.png rename to public/assets/img/Material/ThunderwingButterfly.png diff --git a/src/assets/img/Material/TirelessFrog.png b/public/assets/img/Material/TirelessFrog.png similarity index 100% rename from src/assets/img/Material/TirelessFrog.png rename to public/assets/img/Material/TirelessFrog.png diff --git a/src/assets/img/Material/Topaz.png b/public/assets/img/Material/Topaz.png similarity index 100% rename from src/assets/img/Material/Topaz.png rename to public/assets/img/Material/Topaz.png diff --git a/src/assets/img/Material/VoltfinTrout.png b/public/assets/img/Material/VoltfinTrout.png similarity index 100% rename from src/assets/img/Material/VoltfinTrout.png rename to public/assets/img/Material/VoltfinTrout.png diff --git a/src/assets/img/Material/Voltfruit.png b/public/assets/img/Material/Voltfruit.png similarity index 100% rename from src/assets/img/Material/Voltfruit.png rename to public/assets/img/Material/Voltfruit.png diff --git a/src/assets/img/Material/WarmDarner.png b/public/assets/img/Material/WarmDarner.png similarity index 100% rename from src/assets/img/Material/WarmDarner.png rename to public/assets/img/Material/WarmDarner.png diff --git a/src/assets/img/Material/WarmSafflina.png b/public/assets/img/Material/WarmSafflina.png similarity index 100% rename from src/assets/img/Material/WarmSafflina.png rename to public/assets/img/Material/WarmSafflina.png diff --git a/src/assets/img/Material/WhiteChuchuJelly.png b/public/assets/img/Material/WhiteChuchuJelly.png similarity index 100% rename from src/assets/img/Material/WhiteChuchuJelly.png rename to public/assets/img/Material/WhiteChuchuJelly.png diff --git a/src/assets/img/Material/Wildberry.png b/public/assets/img/Material/Wildberry.png similarity index 100% rename from src/assets/img/Material/Wildberry.png rename to public/assets/img/Material/Wildberry.png diff --git a/src/assets/img/Material/WinterwingButterfly.png b/public/assets/img/Material/WinterwingButterfly.png similarity index 100% rename from src/assets/img/Material/WinterwingButterfly.png rename to public/assets/img/Material/WinterwingButterfly.png diff --git a/src/assets/img/Material/Wood.png b/public/assets/img/Material/Wood.png similarity index 100% rename from src/assets/img/Material/Wood.png rename to public/assets/img/Material/Wood.png diff --git a/src/assets/img/Material/YellowChuchuJelly.png b/public/assets/img/Material/YellowChuchuJelly.png similarity index 100% rename from src/assets/img/Material/YellowChuchuJelly.png rename to public/assets/img/Material/YellowChuchuJelly.png diff --git a/src/assets/img/Material/YellowLizalfosTail.png b/public/assets/img/Material/YellowLizalfosTail.png similarity index 100% rename from src/assets/img/Material/YellowLizalfosTail.png rename to public/assets/img/Material/YellowLizalfosTail.png diff --git a/src/assets/img/Material/Zapshroom.png b/public/assets/img/Material/Zapshroom.png similarity index 100% rename from src/assets/img/Material/Zapshroom.png rename to public/assets/img/Material/Zapshroom.png diff --git a/src/assets/img/Shield/AncientShield.png b/public/assets/img/Shield/AncientShield.png similarity index 100% rename from src/assets/img/Shield/AncientShield.png rename to public/assets/img/Shield/AncientShield.png diff --git a/src/assets/img/Shield/BokoShield.png b/public/assets/img/Shield/BokoShield.png similarity index 100% rename from src/assets/img/Shield/BokoShield.png rename to public/assets/img/Shield/BokoShield.png diff --git a/src/assets/img/Shield/Daybreaker.png b/public/assets/img/Shield/Daybreaker.png similarity index 100% rename from src/assets/img/Shield/Daybreaker.png rename to public/assets/img/Shield/Daybreaker.png diff --git a/src/assets/img/Shield/DragonboneBokoShield.png b/public/assets/img/Shield/DragonboneBokoShield.png similarity index 100% rename from src/assets/img/Shield/DragonboneBokoShield.png rename to public/assets/img/Shield/DragonboneBokoShield.png diff --git a/src/assets/img/Shield/EmblazonedShield.png b/public/assets/img/Shield/EmblazonedShield.png similarity index 100% rename from src/assets/img/Shield/EmblazonedShield.png rename to public/assets/img/Shield/EmblazonedShield.png diff --git a/src/assets/img/Shield/FishermansShield.png b/public/assets/img/Shield/FishermansShield.png similarity index 100% rename from src/assets/img/Shield/FishermansShield.png rename to public/assets/img/Shield/FishermansShield.png diff --git a/src/assets/img/Shield/ForestDwellersShield.png b/public/assets/img/Shield/ForestDwellersShield.png similarity index 100% rename from src/assets/img/Shield/ForestDwellersShield.png rename to public/assets/img/Shield/ForestDwellersShield.png diff --git a/src/assets/img/Shield/GerudoShield.png b/public/assets/img/Shield/GerudoShield.png similarity index 100% rename from src/assets/img/Shield/GerudoShield.png rename to public/assets/img/Shield/GerudoShield.png diff --git a/src/assets/img/Shield/GuardianShield.png b/public/assets/img/Shield/GuardianShield.png similarity index 100% rename from src/assets/img/Shield/GuardianShield.png rename to public/assets/img/Shield/GuardianShield.png diff --git a/src/assets/img/Shield/GuardianShieldPlus.png b/public/assets/img/Shield/GuardianShieldPlus.png similarity index 100% rename from src/assets/img/Shield/GuardianShieldPlus.png rename to public/assets/img/Shield/GuardianShieldPlus.png diff --git a/src/assets/img/Shield/GuardianShieldPlusPlus.png b/public/assets/img/Shield/GuardianShieldPlusPlus.png similarity index 100% rename from src/assets/img/Shield/GuardianShieldPlusPlus.png rename to public/assets/img/Shield/GuardianShieldPlusPlus.png diff --git a/src/assets/img/Shield/HerosShield.png b/public/assets/img/Shield/HerosShield.png similarity index 100% rename from src/assets/img/Shield/HerosShield.png rename to public/assets/img/Shield/HerosShield.png diff --git a/src/assets/img/Shield/HuntersShield.png b/public/assets/img/Shield/HuntersShield.png similarity index 100% rename from src/assets/img/Shield/HuntersShield.png rename to public/assets/img/Shield/HuntersShield.png diff --git a/src/assets/img/Shield/HylianShield.png b/public/assets/img/Shield/HylianShield.png similarity index 100% rename from src/assets/img/Shield/HylianShield.png rename to public/assets/img/Shield/HylianShield.png diff --git a/src/assets/img/Shield/KiteShield.png b/public/assets/img/Shield/KiteShield.png similarity index 100% rename from src/assets/img/Shield/KiteShield.png rename to public/assets/img/Shield/KiteShield.png diff --git a/src/assets/img/Shield/KnightsShield.png b/public/assets/img/Shield/KnightsShield.png similarity index 100% rename from src/assets/img/Shield/KnightsShield.png rename to public/assets/img/Shield/KnightsShield.png diff --git a/src/assets/img/Shield/LizalShield.png b/public/assets/img/Shield/LizalShield.png similarity index 100% rename from src/assets/img/Shield/LizalShield.png rename to public/assets/img/Shield/LizalShield.png diff --git a/src/assets/img/Shield/LynelShield.png b/public/assets/img/Shield/LynelShield.png similarity index 100% rename from src/assets/img/Shield/LynelShield.png rename to public/assets/img/Shield/LynelShield.png diff --git a/src/assets/img/Shield/MightyLynelShield.png b/public/assets/img/Shield/MightyLynelShield.png similarity index 100% rename from src/assets/img/Shield/MightyLynelShield.png rename to public/assets/img/Shield/MightyLynelShield.png diff --git a/src/assets/img/Shield/PotLid.png b/public/assets/img/Shield/PotLid.png similarity index 100% rename from src/assets/img/Shield/PotLid.png rename to public/assets/img/Shield/PotLid.png diff --git a/src/assets/img/Shield/RadiantShield.png b/public/assets/img/Shield/RadiantShield.png similarity index 100% rename from src/assets/img/Shield/RadiantShield.png rename to public/assets/img/Shield/RadiantShield.png diff --git a/src/assets/img/Shield/ReinforcedLizalShield.png b/public/assets/img/Shield/ReinforcedLizalShield.png similarity index 100% rename from src/assets/img/Shield/ReinforcedLizalShield.png rename to public/assets/img/Shield/ReinforcedLizalShield.png diff --git a/src/assets/img/Shield/RoyalGuardsShield.png b/public/assets/img/Shield/RoyalGuardsShield.png similarity index 100% rename from src/assets/img/Shield/RoyalGuardsShield.png rename to public/assets/img/Shield/RoyalGuardsShield.png diff --git a/src/assets/img/Shield/RoyalShield.png b/public/assets/img/Shield/RoyalShield.png similarity index 100% rename from src/assets/img/Shield/RoyalShield.png rename to public/assets/img/Shield/RoyalShield.png diff --git a/src/assets/img/Shield/RustyShield.png b/public/assets/img/Shield/RustyShield.png similarity index 100% rename from src/assets/img/Shield/RustyShield.png rename to public/assets/img/Shield/RustyShield.png diff --git a/src/assets/img/Shield/SavageLynelShield.png b/public/assets/img/Shield/SavageLynelShield.png similarity index 100% rename from src/assets/img/Shield/SavageLynelShield.png rename to public/assets/img/Shield/SavageLynelShield.png diff --git a/public/assets/img/Shield/Shield.png b/public/assets/img/Shield/Shield.png new file mode 100644 index 0000000000000000000000000000000000000000..59bcc7ae4823d53a9e32d35de4566c59e1dcb223 GIT binary patch literal 21159 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 +const getDefaultCommandTexts = (): string[]=>{ const encoded = localStorage.getItem("HDS.CurrentCommandsText"); if(encoded){ const lines = encoded.split("\n"); - return lines.map(parseCommand); + return lines; } return [ - parseCommand("Get 5 Diamond 1 Slate 1 Glider 4 SpiritOrb"), - parseCommand("Save"), - parseCommand("# Magically break 4 slots"), - parseCommand("Break 4 Slots"), - parseCommand("Reload"), - parseCommand("Save"), - parseCommand("Reload"), - ] as Command[]; + "Get 5 Diamond 1 Slate 1 Glider 4 SpiritOrb", + "Save", + "# Magically break 4 slots", + "Break 4 Slots", + "Reload", + "Save", + "Reload", + ]; }; +type Setting = { + interlaceInventory: boolean, + isIconAnimated: boolean, + +} +const getSetting = (): Setting=>{ + const settingString = localStorage.getItem("HDS.Setting"); + const defaultSetting = { + interlaceInventory: false, + isIconAnimated: true, + }; + if(settingString){ + return { + ...defaultSetting, + ...JSON.parse(settingString) + }; + } + return defaultSetting; +}; + +const initialSetting = getSetting(); + export const App: React.FC = () => { + + const searchItem = useSearchItem(); const [page, setPageInState] = useState("#simulation"); // Option States - const [interlaceInventory, setInterlaceInventory] = useState(false); - const [isIconAnimated, setIsIconAnimated] = useState(false); + const [interlaceInventory, setInterlaceInventory] = useState(initialSetting.interlaceInventory); + const [isIconAnimated, setIsIconAnimated] = useState(initialSetting.isIconAnimated); - const [commands, setCommands] = useState(getDefaultCommands()); + // save settings + useEffect(()=>{ + localStorage.setItem("HDS.Setting", JSON.stringify({ + interlaceInventory, + isIconAnimated + })); + },[interlaceInventory, isIconAnimated]); + // Core Logic States + const [commandTexts, setCommandTexts] = useState(getDefaultCommandTexts()); const [selectedSaveName, setSelectedSaveName] = useState(""); const [displayIndex, setDisplayIndex] = useState(0); const [contextMenuX, setContextMenuX] = useState(0); @@ -44,18 +77,24 @@ export const App: React.FC = () => { const contextMenuRef = useRef(null); // compute props + + const parseCommandWithSearch = useCallback((cmd: string)=>{ + return parseCommand(cmd, searchItem); + }, [searchItem]); + + const commands = useMemo(()=>{ + return commandTexts.map(c=>parseCommandWithSearch(c)); + }, [commandTexts, parseCommandWithSearch]); + const simulationStates = useMemo(()=>{ const simulationStates: SimulationState[] = []; const state = createSimulationState(); commands.forEach(c=>{ - c.execute(state); + state.executeCommand(c); simulationStates.push(state.deepClone()); }); return simulationStates; }, [commands]); - const commandText = useMemo(()=>{ - return commands.map(c=>c.getDisplayString()).join("\n"); - }, [commands]); const setPage = useCallback((hash: string)=>{ window.location.hash = hash; @@ -70,39 +109,36 @@ export const App: React.FC = () => { window.onkeydown=(e)=>{ if(e.code==="ArrowDown"){ let nextCommandIndex = displayIndex+1; - while(nextCommandIndex=0 && !commands[nextCommandIndex].isValid()){ + while(nextCommandIndex>=0 && commands[nextCommandIndex].getError() !== undefined){ nextCommandIndex--; } setDisplayIndex(Math.max(0, nextCommandIndex)); } }; - }, [commands, displayIndex]); + }, [commandTexts, displayIndex, commands]); useEffect(()=>{ - // const encoded = serializeCommands(commands); - // localStorage.setItem("HDS.CurrentCommands", encoded); - const lines = commands.map(c=>c.getDisplayString()); - const text = lines.join("\n"); + const text = commandTexts.join("\n"); localStorage.setItem("HDS.CurrentCommandsText", text); - }, [commands]); + }, [commandTexts]); useEffect(()=>{ - if(contextIndex < 0 || contextIndex >= commands.length){ + if(contextIndex < 0 || contextIndex >= commandTexts.length){ setContextIndex(-1); }else if(contextMenuRef.current){ const rect = contextMenuRef.current.getBoundingClientRect(); @@ -110,7 +146,7 @@ export const App: React.FC = () => { setContextMenuY(contextMenuY-rect.height); } } - }, [contextMenuRef, contextIndex, commands]); + }, [contextMenuRef, contextIndex, commandTexts]); return (
@@ -124,10 +160,14 @@ export const App: React.FC = () => { }}>Simulation + }}>Commands + +
{ } { - Object.entries(simulationStates[displayIndex].getNamedSaves()).map(([name, _gamedata])=> + Object.entries(simulationStates[displayIndex].getNamedSaves()).map(([name, _gamedata], i)=> { setSelectedSaveName(name); setPage("#simulation"); @@ -192,7 +233,7 @@ export const App: React.FC = () => {
    { - commands.map((c,i)=> + commandTexts.map((c,i)=> { setDisplayIndex(i); @@ -210,22 +251,22 @@ export const App: React.FC = () => { key={i} isSelected={displayIndex===i} isContextSelected={contextIndex===i} - isComment={c.getDisplayString().startsWith("#")} - useListItem={!c.getDisplayString().startsWith("#")} - isInvalid={!c.isValid()} + isComment={c.startsWith("#")} + useListItem={!c.startsWith("#")} + isInvalid={commands[i].getError() !== undefined} > - {c.getDisplayString()} + {c} ) } { - const arrCopy = [...commands]; - arrCopy.push(new CommandNop("")); - setCommands(arrCopy); + const arrCopy = [...commandTexts]; + arrCopy.push(""); + setCommandTexts(arrCopy); }} onContextMenu={()=>{ - const arrCopy = [...commands]; - arrCopy.push(new CommandNop("")); - setCommands(arrCopy); + const arrCopy = [...commandTexts]; + arrCopy.push(""); + setCommandTexts(arrCopy); }}>(new)
@@ -287,18 +328,19 @@ export const App: React.FC = () => { overflowY: "hidden" }}> {displayIndex >= 0 && displayIndex < commands.length && - { - const arrCopy = [...commands]; - arrCopy[displayIndex] = c; - setCommands(arrCopy); - }} - /> + + { + const arrCopy = [...commandTexts]; + arrCopy[displayIndex] = c; + setCommandTexts(arrCopy); + }} + /> }
@@ -307,6 +349,9 @@ export const App: React.FC = () => { { page === "#reference" && } + { + page === "#items" && + } { page === "#options" && { setInterlaceInventory={setInterlaceInventory} isIconAnimated={isIconAnimated} setIsIconAnimated={setIsIconAnimated} - commandText={commandText} + commandText={commandTexts.join("\n")} setCommandText={(value)=>{ - if(value !== commandText){ - const commands = value.split("\n").map(parseCommand); - setCommands(commands); - } + setCommandTexts(value.split("\n")); }} /> } @@ -353,27 +395,27 @@ export const App: React.FC = () => { }}> { - const arrCopy = [...commands]; - arrCopy.splice(contextIndex, 0, new CommandNop("")); - setCommands(arrCopy); + const arrCopy = [...commandTexts]; + arrCopy.splice(contextIndex, 0, ""); + setCommandTexts(arrCopy); setContextIndex(-1); }}>Insert Above { if(contextIndex > 0){ - const arrCopy = [...commands]; + const arrCopy = [...commandTexts]; const temp = arrCopy[contextIndex]; arrCopy[contextIndex] = arrCopy[contextIndex-1]; arrCopy[contextIndex-1] = temp; - setCommands(arrCopy); + setCommandTexts(arrCopy); setContextIndex(-1); } }}>Move Up { if(confirm("Delete?")){ - setCommands(commands.filter((_,i)=>i!==contextIndex)); - if(displayIndex >= commands.length){ - setDisplayIndex(commands.length-1); + setCommandTexts(commandTexts.filter((_,i)=>i!==contextIndex)); + if(displayIndex >= commandTexts.length){ + setDisplayIndex(commandTexts.length-1); } setContextIndex(-1); } diff --git a/src/__tests__/README.md b/src/__tests__/README.md new file mode 100644 index 0000000..76ef5ad --- /dev/null +++ b/src/__tests__/README.md @@ -0,0 +1,27 @@ +# E2E Tests +## How to add a test +1. Make up a name for the test +2. Write the script in simulator +3. Export the script and put it as `.in.txt` in `src/__tests__` +4. Write another script that uses `initialize`, `save`, `save as` and `break x slots` to achieve the expected result as the first script (look at one of the existing tests as an example) +5. Export the new script and put it as `.out.txt` in `src/__tests__` +6. Create a new file `.e2e.ts` +7. copy paste the following and replace `` with the name of your test. Replace `YOUR_NAME` with your name +```typescript +// Author: YOUR_NAME +const TEST = ""; +it(TEST, ()=>{ + expect(TEST).toPassE2ESimulation(); +}); +export {}; +``` +8. Make a PR on https://github.com/iTNTPiston/botw-hundo-dupl +## How to run E2E tests +`npm run test-all` + +## How to debug E2E tests +1. Open the `e2e.ts` file of the failed test +2. replace `it` with `it.only` +3. replace `toPassE2ESimulation()` with `toPassE2ESimulation(true)` (i.e. type `true` in the parenthese) +4. Run the test again, you should now see `debug.expected.log` and `debug.actual.log` containing the expected and actual content of the simuation states. +5. After fixing the test, revert the changes to `e2e.ts` you made diff --git a/src/__tests__/empty.e2e.ts b/src/__tests__/empty.e2e.ts new file mode 100644 index 0000000..9104ede --- /dev/null +++ b/src/__tests__/empty.e2e.ts @@ -0,0 +1,6 @@ +// Author: iTNTPiston +const TEST = "empty"; +it(TEST, ()=>{ + expect(TEST).toPassE2ESimulation(); +}); +export {}; diff --git a/src/__tests__/empty.in.txt b/src/__tests__/empty.in.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/__tests__/empty.out.txt b/src/__tests__/empty.out.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/__tests__/goldrush_10reload22drop.e2e.ts b/src/__tests__/goldrush_10reload22drop.e2e.ts new file mode 100644 index 0000000..b020d2f --- /dev/null +++ b/src/__tests__/goldrush_10reload22drop.e2e.ts @@ -0,0 +1,7 @@ + +// Author: Swiffy22 +const TEST = "goldrush_10reload22drop"; +it(TEST, ()=>{ + expect(TEST).toPassE2ESimulation(); +}); +export {}; diff --git a/src/__tests__/goldrush_10reload22drop.in.txt b/src/__tests__/goldrush_10reload22drop.in.txt new file mode 100644 index 0000000..1d4b584 --- /dev/null +++ b/src/__tests__/goldrush_10reload22drop.in.txt @@ -0,0 +1,81 @@ +Initialize 1 Weapon 1 Bow 1 BombArrow 1 AncientArrow 1 Shield 1 Tail 1 Beetle 1 Core 2 Opal 2 Wood 2 Apple 2 SpicyPepper 2 Rushroom 2 HylianShroom 2 Acorn 2 SilentPrincess 2 HeartyBass 2 EnduraShroom 1 Screw 2 Spring 1 Shaft 2 Lotus 1 FaroshHorn 2 LizalfosTalon 1 Honey 1 LizalfosHorn 1 Slate 1 Glider 8 SpiritOrb +Equip Weapon +Equip Bow +Equip Shield +Equip BombArrow +Save +# Pick up weapons, drop all materials, 2 drops (8 materials) +Initialize 8 Weapon 1 BombArrow 1 AncientArrow 1 Shield 1 Slate 1 Glider 8 SpiritOrb +Equip BombArrow +# Run to center of town for autosave +Save As Autosave +Break 13 Slots +Reload +Save +Reload Autosave +Drop 2 EnduraShroom +Drop 1 Screw +Drop 2 Spring +Drop 1 Shaft +Drop 2 Lotus +Drop 1 FaroshHorn +Drop 2 LizalfosTalon +Drop 1 Honey +Drop 1 LizalfosHorn +#3 Drops (13 Materials), 5 Total +Reload +Save +Reload Autosave +Drop 2 Spring +Drop 1 Shaft +Drop 2 Lotus +Drop 2 LizalfosTalon +Drop 1 Honey +Drop 1 LizalfosHorn +#2 Drops (9 Materials), 7 Total +Reload +Save +Reload +D&P 1 Honey +D&P 1 LizalfosHorn +#1 Drop (2 Materials), 8 Total +Cook 1 SpeedFood +Remove 1 FaroshHorn From Slot 2 +Remove 4 Lotus +Save +Reload +Sell 112 SpiritOrb +D&P 2 Honey +D&P 2 LizalfosHorn +D&P 2 LizalfosTalon +#2 Drops (6 Materials), 10 Total +Save +Reload +D&P 2 EnduraShroom +D&P 4 LizalfosTalon +D&P 4 Honey +#2 Drops (10 Materials), 12 Total +Save +Reload +Drop 4 LizalfosHorn From Slot 2 +Drop 4 LizalfosHorn From Slot 2 +Pickup 8 LizalfosHorn +Drop 8 Honey From Slot 2 +Pickup 8 Honey +Drop 8 LizalfosTalon From Slot 2 +Pickup 8 LizalfosTalon +Drop 1 Screw From Slot 2 +Drop 1 Screw From Slot 2 +Pickup 2 Screw +Drop 1 Shaft From Slot 2 +Drop 1 Shaft From Slot 2 +Pickup 2 Shaft +#6 Drops (28 Materials), 18 Total +Save +Reload +D&P 8 EnduraShroom +D&P 6 Spring +D&P 4 HeartyBass +D&P 2 SilentPrincess +#4 Drops (20 Materials), 22 Total +Save diff --git a/src/__tests__/goldrush_10reload22drop.out.txt b/src/__tests__/goldrush_10reload22drop.out.txt new file mode 100644 index 0000000..e4e78b2 --- /dev/null +++ b/src/__tests__/goldrush_10reload22drop.out.txt @@ -0,0 +1,5 @@ +Initialize 8 weapon 1 bomb[equip] 1 a*arrow 1 shield 1 slate 1 glider 8 orb +Save As Autosave +Initialize 1 weapon[equip] 1 bow[equip] 1000 bomb arrow[equip] 1000 An*Arr 1 shield[equip] 3 screw 3 a*shaft 10 lizal talon 16 Honey 12 lizal horn 1 far*horn 999 Tail 999 Beetle 999 Core 999 Opal 999 Wood 2 Apple 2 s*pepper 999 rush 2 hy*shr 999 acorn 4 sil*p 6 hear 12 end 8 spring*a 16 SpeedFood 1 slate 1 glider +Save +Break 13 slots diff --git a/src/assets/Crash.png b/src/assets/Crash.png deleted file mode 100644 index ac5657db9903c658486b74bd9b2675553239281b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9021 zcmeHNc~F!`7JtJacLtP8kwpZBKoAd9SUJOR21OFLWI%#=FiL=NL_h{+V2A-lT#z6) zz zzu&vMt4QqSB85R)= z@Mab-%hBtupH9mD1Cj2QG(DZw-}wowE?l&GM>jp>lUm)tm~EV~%=Xfa-ltFN1gX>H zRtJ9*R2&n-)>Zs^gO;bcxx2o_^M=xPlfNqG$xip#pI@A!eiUDDgV}6X@z@j+2;8%JpO z-8&zXSO;m1y~iAM}Zz7Dc)AZ)vZ8)>h8Rc%W=duL=BuLZc;r zZxUL``SQ+99&4p9tZiDE?iO_=?MSxVsB%$F!NNY)kQzE1 zb9vsU^hEz)*;Z!x=VI2xNZH_-q=bc;v0e?N4?dM2TZQQrRR$)dBq1Rnqkv2VvKEl# zkn9L#Hzd0u*$v5Vh`XVHL4lcKfgnJ^L7}XyEEix!nH54opDvsInn~=@RUjH0yRlhv zU4X3v!|k@{iV5JQO%nTR1>lDTe;Kzu;l zakmt$fS-nkyK7MBm<5&}yn8|o@f;>Z;o&^N6V2l}az|QQf8V44+>L}3hE=Lq2Qf7e zoC}i2cO?Za!#^CQK!X;R6)&6Wl@uuGfyf^ZZk56H22N6~Bp=0Bdixr9_C2gW(@z*Z zIh6*GnS(sCO*A<<+0Mz!%ga>*NeVH;tXa2b`ZY$1N1tdx)}OSTq6Gu%v2ZY@c0BC~ zLNWvdM{8?qRRI1V!?sa6#%EuDMeGL4?sVWc`-&7`ZAe`Ztq5Dm-H%@f78c^WZe=BT zDuSI7Aw0e5=+7to{r&GUF*yA=;gsT#rBwkpAKrIGwqtNK*olcw5gp&kY5_8mi5)dH zHAUR%r4{TFinr+eeb>fCt;}zWv!=r+U`VB?L&)Wxo}P_oJQ~VY0b2v_{B4g_x4x1u zwCs2#c!x;{PrlUcuR?)DW31^*6pkDX6owd3LNOjkof|v_yQW(Yq1%| zEyGbSF1@SyH5ClC32mz>;f?lz0L>oQ?&H;ry;mPAp_O7nbwx#mnRxAUEV-JH%vqe9 z99oCWGsJ1)8Odu4G=Bj{%u(IUF;nmy~ zdHrSuSaQLdPktaWc&_E}N>8CdRd5403`K-94kV?(%FYDg^32$SAy5MLCA_(07K=6K zWIs!Z1O74WI*mY6HvXoW`fm0mumN1X|}M2xF+~Fp!90aFM>`PS+eT;wyt4 zlbAr>Oc3fKO;ZGaG>20s>$cDoA)E-aN~BV0y%=Z3PXgnmBdy4nQ!%mksS{;7Isn~goCJY$i&4rB5#*f+vop_HH$5W6lB48tg>luqqOEi$YMMyeSe$ZZs zU1WsYnno;-S1&E#ZAesxd0kup&b5w81!DZ9Ng%Q~Dol!XGDT}0h`mp|co8*fv&gMO z>Eutu@7%)dxIjE19d-r&VIm2;ifm6YQ7tWdeVw6*S<^ixLs|a=QjX)%P*gz)uVyd| zKt#okqIS*R{80Mx$De%{Zq-Mwwg8v#gzdZc^z6QckZEbB<6yRI^s!vCY zlVcCc&UT={2A7=mD2d6#JqZCB1!N-N1L(h~1uK!w8Tf(&N-q!XKjwKv5j~0u(HR9G zWFKnL099t_tN_5!CIsA4wZd;5ih7uYD-bPo7jac0*+@vpC_ynmCJq9DPZkA)!hc>T mpWZJ)S2&6a{$BvHt}xW4*|G`eLfT%8g}1w}TZL=Lhkpa*2VVLB diff --git a/src/assets/img/index.ts b/src/assets/img/index.ts deleted file mode 100644 index ce8c227..0000000 --- a/src/assets/img/index.ts +++ /dev/null @@ -1,25 +0,0 @@ - -// Use webpack require context to import all images under image directory and create a map -const r = require as any; // eslint-disable-line @typescript-eslint/no-explicit-any - -const images = ((requireContext)=>{ - const imgMap: {[name: string]: string} = {}; - requireContext.keys().forEach((k: string)=>{ - if(k.startsWith("./") && (k.endsWith(".png") || k.endsWith("webp"))){ - const module = requireContext(k); - // Clean image path ./name.png => name - - const name = k.substring(2, k.lastIndexOf(".")); - if(typeof module === "string"){ - imgMap[name] = module; - }else if (typeof module === "object" && "default" in module){ - imgMap[name] = module["default"]; - }else{ - console.error("Failed to load image: ", k); - } - } - }); - return imgMap; -})(r.context(".", true, /\.(?:png|webp)$/)); - -export default images as {readonly [name:string]:string}; diff --git a/src/components/CrashScreen.tsx b/src/components/CrashScreen.tsx new file mode 100644 index 0000000..5f7abbc --- /dev/null +++ b/src/components/CrashScreen.tsx @@ -0,0 +1,34 @@ +import { PropsWithChildren } from "react"; + +// an over-engineered crash screen +export const CrashScreen: React.FC = ({children})=>{ + return ( +
+
!
+ + {children} + +
+ ); +}; diff --git a/src/components/ItemSlot.tsx b/src/components/ItemSlot.tsx index a94727c..7c54ba7 100644 --- a/src/components/ItemSlot.tsx +++ b/src/components/ItemSlot.tsx @@ -1,20 +1,45 @@ import clsx from "clsx"; import { DisplayableSlot } from "core/DisplayableInventory"; import Background from "assets/Background.png"; +import { useI18n } from "data/i18n"; type ItemSlotProps = { slot: DisplayableSlot }; -export const ItemSlot: React.FC = ({slot: {image, description, count, isBrokenSlot, isEquipped, displayCount}})=>{ +export const ItemSlot: React.FC = ({slot: { + image, + descKey, + count, + durability, + isBrokenSlot, + isEquipped +}})=>{ + const t = useI18n(); return ( - - + + { - displayCount && - x{count} - + count!==undefined &&
+ { + + x{count} + + } +
} + { + durability!==undefined &&
+ { + + {durability} + + } +
+ } +
); }; diff --git a/src/components/LoadingScreen.tsx b/src/components/LoadingScreen.tsx new file mode 100644 index 0000000..e2a87e9 --- /dev/null +++ b/src/components/LoadingScreen.tsx @@ -0,0 +1,25 @@ +import { PropsWithChildren } from "react"; + +// an over-engineered loading screen +export const LoadingScreen: React.FC = ({children})=>{ + return ( +
+ + {children} + +
+ ); +}; diff --git a/src/components/Text.tsx b/src/components/Text.tsx new file mode 100644 index 0000000..75e49f7 --- /dev/null +++ b/src/components/Text.tsx @@ -0,0 +1,22 @@ +import clsx from "clsx"; +import React, { PropsWithChildren } from "react"; + +export const Header: React.FC = ({children})=>{ + return

{children}

; +}; + +export const SubHeader: React.FC> = ({connected, children})=>{ + return

{children}

; +}; + +export const SubTitle: React.FC = ({children})=>{ + return

{children}

; +}; + +export const BodyText: React.FC> = ({emphasized, children})=>{ + return

{children}

; +}; + +export const Emphasized: React.FC = ({children})=>{ + return {children}; +}; diff --git a/src/config/i18n/en_US.json b/src/config/i18n/en_US.json deleted file mode 100644 index a75e5d7..0000000 --- a/src/config/i18n/en_US.json +++ /dev/null @@ -1,694 +0,0 @@ -{ - "description.Weapon.MasterSword": "Master Sword", - "description.Weapon.TreeBranch": "Tree Branch", - "description.Weapon.Torch": "Torch", - "description.Weapon.SoupLadle": "Soup Ladle", - "description.Weapon.Boomerang": "Boomerang", - "description.Weapon.SpringLoadedHammer": "Spring-Loaded Hammer", - "description.Weapon.TravelersSword": "Traveler's Sword", - "description.Weapon.SoldiersBroadsword": "Soldier's Broadsword", - "description.Weapon.KnightsBroadsword": "Knight's Broadsword", - "description.Weapon.RoyalBroadsword": "Royal Broadsword", - "description.Weapon.ForestDwellersSword": "Forest Dweller's Sword", - "description.Weapon.ZoraSword": "Zora Sword", - "description.Weapon.FeatheredEdge": "Feathered Edge", - "description.Weapon.GerudoScimitar": "Gerudo Scimitar", - "description.Weapon.MoonlightScimitar": "Moonlight Scimitar", - "description.Weapon.ScimitarOfTheSeven": "Scimitar of the Seven", - "description.Weapon.EightfoldBlade": "Eightfold Blade", - "description.Weapon.AncientShortSword": "Ancient Short Sword", - "description.Weapon.RustyBroadsword": "Rusty Broadsword", - "description.Weapon.RoyalGuardsSword": "Royal Guard's Sword", - "description.Weapon.Flameblade": "Flameblade", - "description.Weapon.Frostblade": "Frostblade", - "description.Weapon.Thunderblade": "Thunderblade", - "description.Weapon.GoddessSword": "Goddess Sword", - "description.Weapon.Sword": "Sword", - "description.Weapon.SeaBreezeBoomerang": "Sea-Breeze Boomerang", - "description.Weapon.BokoClub": "Boko Club", - "description.Weapon.SpikedBokoClub": "Spiked Boko Club", - "description.Weapon.DragonboneBokoClub": "Dragonbone Boko Club", - "description.Weapon.LizalBoomerang": "Lizal Boomerang", - "description.Weapon.LizalForkedBoomerang": "Lizal Forked Boomerang", - "description.Weapon.LizalTriBoomerang": "Lizal Tri-Boomerang", - "description.Weapon.GuardianSword": "Guardian Sword", - "description.Weapon.GuardianSwordPlus": "Guardian Sword+", - "description.Weapon.GuardianSwordPlusPlus": "Guardian Sword++", - "description.Weapon.LynelSword": "Lynel Sword", - "description.Weapon.MightyLynelSword": "Mighty Lynel Sword", - "description.Weapon.SavageLynelSword": "Savage Lynel Sword", - "description.Weapon.FireRod": "Fire Rod", - "description.Weapon.MeteorRod": "Meteor Rod", - "description.Weapon.IceRod": "Ice Rod", - "description.Weapon.BlizzardRod": "Blizzard Rod", - "description.Weapon.LightningRod": "Lightning Rod", - "description.Weapon.ThunderstormRod": "Thunderstorm Rod", - "description.Weapon.ViciousSickle": "Vicious Sickle", - "description.Weapon.DemonCarver": "Demon Carver", - "description.Weapon.OneHitObliterator": "One-Hit Obliterator", - "description.Weapon.BokoblinArm": "Bokoblin Arm", - "description.Weapon.LizalfosArm": "Lizalfos Arm", - - "description.Weapon.KorokLeaf": "Korok Leaf", - "description.Weapon.FarmingHoe": "Farming Hoe", - "description.Weapon.BoatOar": "Boat Oar", - "description.Weapon.WoodcuttersAxe": "Woodcutter's Axe", - "description.Weapon.DoubleAxe": "Double Axe", - "description.Weapon.IronSledgehammer": "Iron Sledgehammer", - "description.Weapon.GiantBoomerang": "Giant Boomerang", - "description.Weapon.TravelersClaymore": "Traveler's Claymore", - "description.Weapon.SoldiersClaymore": "Soldier's Claymore", - "description.Weapon.KnightsClaymore": "Knight's Claymore", - "description.Weapon.RoyalClaymore": "Royal Claymore", - "description.Weapon.SilverLongsword": "Silver Longsword", - "description.Weapon.CobbleCrusher": "Cobble Crusher", - "description.Weapon.StoneSmasher": "Stone Smasher", - "description.Weapon.BoulderBreaker": "Boulder Breaker", - "description.Weapon.GoldenClaymore": "Golden Claymore", - "description.Weapon.EightfoldLongblade": "Eightfold Longblade", - "description.Weapon.EdgeOfDuality": "Edge of Duality", - "description.Weapon.AncientBladesaw": "Ancient Bladesaw", - "description.Weapon.RustyClaymore": "Rusty Claymore", - "description.Weapon.RoyalGuardsClaymore": "Royal Guard's Claymore", - "description.Weapon.GreatFlameblade": "Great Flameblade", - "description.Weapon.GreatFrostblade": "Great Frostblade", - "description.Weapon.GreatThunderblade": "Great Thunderblade", - "description.Weapon.SwordOfTheSixSages": "Sword of the Six Sages", - "description.Weapon.BiggoronsSword": "Biggoron's Sword", - "description.Weapon.FierceDeitySword": "Fierce Deity Sword", - "description.Weapon.BokoBat": "Boko Bat", - "description.Weapon.SpikedBokoBat": "Spiked Boko Bat", - "description.Weapon.DragonboneBokoBat": "Dragonbone Boko Bat", - "description.Weapon.MoblinClub": "Moblin Club", - "description.Weapon.SpikedMoblinClub": "Spiked Moblin Club", - "description.Weapon.DragonboneMoblinClub": "Dragonbone Moblin Club", - "description.Weapon.AncientBattleAxe": "Ancient Battle Axe", - "description.Weapon.AncientBattleAxePlus": "Ancient Battle Axe+", - "description.Weapon.AncientBattleAxePlusPlus": "Ancient Battle Axe++", - "description.Weapon.LynelCrusher": "Lynel Crusher", - "description.Weapon.MightyLynelCrusher": "Mighty Lynel Crusher", - "description.Weapon.SavageLynelCrusher": "Savage Lynel Crusher", - "description.Weapon.Windcleaver": "Windcleaver", - "description.Weapon.MoblinArm": "Moblin Arm", - - "description.Weapon.WoodenMop": "Wooden Mop", - "description.Weapon.FarmersPitchfork": "Farmer's Pitchfork", - "description.Weapon.FishingHarpoon": "Fishing Harpoon", - "description.Weapon.ThrowingSpear": "Throwing Spear", - "description.Weapon.TravelersSpear": "Traveler's Spear", - "description.Weapon.SoldiersSpear": "Soldier's Spear", - "description.Weapon.KnightsHalberd": "Knight's Halberd", - "description.Weapon.RoyalHalberd": "Royal Halberd", - "description.Weapon.ForestDwellersSpear": "Forest Dweller's Spear", - "description.Weapon.ZoraSpear": "Zora Spear", - "description.Weapon.SilverscaleSpear": "Silverscale Spear", - "description.Weapon.CeremonialTrident": "Ceremonial Trident", - "description.Weapon.LightscaleTrident": "Lightscale Trident", - "description.Weapon.Drillshaft": "Drillshaft", - "description.Weapon.FeatheredSpear": "Feathered Spear", - "description.Weapon.GerudoSpear": "Gerudo Spear", - "description.Weapon.SerpentineSpear": "Serpentine Spear", - "description.Weapon.AncientSpear": "Ancient Spear", - "description.Weapon.RustyHalberd": "Rusty Halberd", - "description.Weapon.RoyalGuardsSpear": "Royal Guard's Spear", - "description.Weapon.Flamespear": "Flamespear", - "description.Weapon.Frostspear": "Frostspear", - "description.Weapon.Thunderspear": "Thunderspear", - "description.Weapon.BokoSpear": "Boko Spear", - "description.Weapon.SpikedBokoSpear": "Spiked Boko Spear", - "description.Weapon.DragonboneBokoSpear": "Dragonbone Boko Spear", - "description.Weapon.MoblinSpear": "Moblin Spear", - "description.Weapon.SpikedMoblinSpear": "Spiked Moblin Spear", - "description.Weapon.DragonboneMoblinSpear": "Dragonbone Moblin Spear", - "description.Weapon.LizalSpear": "Lizal Spear", - "description.Weapon.EnhancedLizalSpear": "Enhanced Lizal Spear", - "description.Weapon.ForkedLizalSpear": "Forked Lizal Spear", - "description.Weapon.GuardianSpear": "Guardian Spear", - "description.Weapon.GuardianSpearPlus": "Guardian Spear+", - "description.Weapon.GuardianSpearPlusPlus": "Guardian Spear++", - "description.Weapon.LynelSpear": "Lynel Spear", - "description.Weapon.MightyLynelSpear": "Mighty Lynel Spear", - "description.Weapon.SavageLynelSpear": "Savage Lynel Spear", - "description.Weapon.Weapon": "Generic Weapon", - - "description.Bow.BowOfLight": "Bow of Light", - "description.Bow.WoodenBow": "Wooden Bow", - "description.Bow.TravelersBow": "Traveler's Bow", - "description.Bow.SoldiersBow": "Soldier’s Bow", - "description.Bow.KnightsBow": "Knight's Bow", - "description.Bow.RoyalBow": "Royal Bow", - "description.Bow.ForestDwellersBow": "Forest Dweller's Bow", - "description.Bow.SilverBow": "Silver Bow", - "description.Bow.SwallowBow": "Swallow Bow", - "description.Bow.FalconBow": "Falcon Bow", - "description.Bow.GreatEagleBow": "Great Eagle Bow", - "description.Bow.GoldenBow": "Golden Bow", - "description.Bow.PhrenicBow": "Phrenic Bow", - "description.Bow.AncientBow": "Ancient Bow", - "description.Bow.RoyalGuardsBow": "Royal Guard's Bow", - "description.Bow.TwilightBow": "Twilight Bow", - "description.Bow.BokoBow": "Boko Bow", - "description.Bow.SpikedBokoBow": "Spiked Boko Bow", - "description.Bow.DragonBoneBokoBow": "Dragon Bone Boko Bow", - "description.Bow.LizalBow": "Lizal Bow", - "description.Bow.StrengthenedLizalBow": "Strengthened Lizal Bow", - "description.Bow.SteelLizalBow": "Steel Lizal Bow", - "description.Bow.LynelBow": "Lynel Bow", - "description.Bow.MightyLynelBow": "Mighty Lynel Bow", - "description.Bow.SavageLynelBow": "Savage Lynel Bow", - "description.Bow.DuplexBow": "Duplex Bow", - "description.Bow.Bow": "Generic Bow", - - "description.Arrow.NormalArrow": "Arrow", - "description.Arrow.FireArrow": "Fire Arrow", - "description.Arrow.IceArrow": "Ice Arrow", - "description.Arrow.ShockArrow": "Shock Arrow", - "description.Arrow.BombArrow": "Bomb Arrow", - "description.Arrow.AncientArrow": "Ancient Arrow", - - "description.Shield.HylianShield": "Hylian Shield", - "description.Shield.PotLid": "Pot Lid", - "description.Shield.WoodenShield": "Wooden Shield", - "description.Shield.EmblazonedShield": "Emblazoned Shield", - "description.Shield.HuntersShield": "Hunter's Shield", - "description.Shield.FishermansShield": "Fisherman's Shield", - "description.Shield.TravelersShield": "Traveler's Shield", - "description.Shield.SoldiersShield": "Soldier’s Shield", - "description.Shield.KnightsShield": "Knight's Shield", - "description.Shield.RoyalShield": "Royal Shield", - "description.Shield.ForestDwellersShield": "Forest Dweller's Shield", - "description.Shield.SilverShield": "Silver Shield", - "description.Shield.KiteShield": "Kite Shield", - "description.Shield.GerudoShield": "Gerudo Shield", - "description.Shield.RadiantShield": "Radiant Shield", - "description.Shield.Daybreaker": "Daybreaker", - "description.Shield.ShieldOfTheMindsEye": "Shield of the Mind's Eye", - "description.Shield.AncientShield": "Ancient Shield", - "description.Shield.RustyShield": "Rusty Shield", - "description.Shield.RoyalGuardsShield": "Royal Guard's Shield", - "description.Shield.HerosShield": "Hero's Shield", - "description.Shield.BokoShield": "Boko Shield", - "description.Shield.SpikedBokoShield": "Spiked Boko Shield", - "description.Shield.DragonboneBokoShield": "Dragonbone Boko Shield", - "description.Shield.LizalShield": "Lizal Shield", - "description.Shield.ReinforcedLizalShield": "Reinforced Lizal Shield", - "description.Shield.SteelLizalShield": "Steel Lizal Shield", - "description.Shield.GuardianShield": "Guardian Shield", - "description.Shield.GuardianShieldPlus": "Guardian Shield+", - "description.Shield.GuardianShieldPlusPlus": "Guardian Shield++", - "description.Shield.LynelShield": "Lynel Shield", - "description.Shield.MightyLynelShield": "Mighty Lynel Shield", - "description.Shield.SavageLynelShield": "Savage Lynel Shield", - "description.Shield.Shield": "Generic Shield", - - "description.Armor.OldShirt": "Old Shirt", - "description.Armor.WellWornTrousers": "Well-Worn Trousers", - "description.Armor.ChampionsTunic": "Champion's Tunic", - "description.Armor.HylianHood": "Hylian Hood", - "description.Armor.HylianTunic": "Hylian Tunic", - "description.Armor.HylianTrousers": "Hylian Trousers", - "description.Armor.SoldiersHelm": "Soldier's Helm", - "description.Armor.SoldiersArmor": "Soldier's Armor", - "description.Armor.SoldiersGreaves": "Soldier's Greaves", - "description.Armor.AmberEarrings": "Amber Earrings", - "description.Armor.WarmDoublet": "Warm Doublet", - "description.Armor.RubyCirclet": "Ruby Circlet", - "description.Armor.SnowquillHeaddress": "Snowquill Headdress", - "description.Armor.SnowquillTunic": "Snowquill Tunic", - "description.Armor.SnowquillTrousers": "Snowquill Trousers", - "description.Armor.SapphireCirclet": "Sapphire Circlet", - "description.Armor.DesertVoeHeadband": "Desert Voe Headband", - "description.Armor.DesertVoeSpaulder": "Desert Voe Spaulder", - "description.Armor.DesertVoeTrousers": "Desert Voe Trousers", - "description.Armor.GerudoVeil": "Gerudo Veil", - "description.Armor.GerudoTop": "Gerudo Top", - "description.Armor.GerudoSirwal": "Gerudo Sirwal", - "description.Armor.TopazEarrings": "Topaz Earrings", - "description.Armor.RubberHelm": "Rubber Helm", - "description.Armor.RubberArmor": "Rubber Armor", - "description.Armor.RubberTights": "Rubber Tights", - "description.Armor.FlamebreakerHelm": "Flamebreaker Helm", - "description.Armor.FlamebreakerArmor": "Flamebreaker Armor", - "description.Armor.FlamebreakerBoots": "Flamebreaker Boots", - "description.Armor.OpalEarrings": "Opal Earrings", - "description.Armor.ZoraHelm": "Zora Helm", - "description.Armor.ZoraArmor": "Zora Armor", - "description.Armor.ZoraGreaves": "Zora Greaves", - "description.Armor.StealthMask": "Stealth Mask", - "description.Armor.StealthChestGuard": "Stealth Chest Guard", - "description.Armor.StealthTights": "Stealth Tights", - "description.Armor.SheiksMask": "Sheik's Mask", - "description.Armor.ThunderHelm": "Thunder Helm", - "description.Armor.ClimbersBandanna": "Climber's Bandanna", - "description.Armor.ClimbingGear": "Climbing Gear", - "description.Armor.ClimbingBoots": "Climbing Boots", - "description.Armor.BarbarianHelm": "Barbarian Helm", - "description.Armor.BarbarianArmor": "Barbarian Armor", - "description.Armor.BarbarianLegWraps": "Barbarian Leg Wraps", - "description.Armor.FierceDeityMask": "Fierce Deity Mask", - "description.Armor.FierceDeityArmor": "Fierce Deity Armor", - "description.Armor.FierceDeityBoots": "Fierce Deity Boots", - "description.Armor.RadiantMask": "Radiant Mask", - "description.Armor.RadiantShirt": "Radiant Shirt", - "description.Armor.RadiantTights": "Radiant Tights", - "description.Armor.DiamondCirclet": "Diamond Circlet", - "description.Armor.AncientHelm": "Ancient Helm", - "description.Armor.AncientCuirass": "Ancient Cuirass", - "description.Armor.AncientGreaves": "Ancient Greaves", - "description.Armor.SandBoots": "Sand Boots", - "description.Armor.SnowBoots": "Snow Boots", - "description.Armor.BokoblinMask": "Bokoblin Mask", - "description.Armor.MoblinMask": "Moblin Mask", - "description.Armor.LizalfosMask": "Lizalfos Mask", - "description.Armor.LynelMask": "Lynel Mask", - "description.Armor.DarkHood": "Dark Hood", - "description.Armor.DarkTunic": "Dark Tunic", - "description.Armor.DarkTrousers": "Dark Trousers", - "description.Armor.CapOfTime": "Cap of Time", - "description.Armor.TunicOfTime": "Tunic of Time", - "description.Armor.TrousersOfTime": "Trousers of Time", - "description.Armor.CapOfTheWind": "Cap of the Wind", - "description.Armor.TunicOfTheWind": "Tunic of the Wind", - "description.Armor.TrousersOfTheWind": "Trousers of the Wind", - "description.Armor.CapOfTwilight": "Cap of Twilight", - "description.Armor.TunicOfTwilight": "Tunic of Twilight", - "description.Armor.TrousersOfTwilight": "Trousers of Twilight", - "description.Armor.CapOfTheSky": "Cap of the Sky", - "description.Armor.TunicOfTheSky": "Tunic of the Sky", - "description.Armor.TrousersOfTheSky": "Trousers of the Sky", - "description.Armor.CapOfTheHero": "Cap of the Hero", - "description.Armor.TunicOfTheHero": "Tunic of the Hero", - "description.Armor.TrousersOfTheHero": "Trousers of the Hero", - "description.Armor.CapOfTheWild": "Cap of the Wild", - "description.Armor.TunicOfTheWild": "Tunic of the Wild", - "description.Armor.TrousersOfTheWild": "Trousers of the Wild", - "description.Armor.NintendoSwitchShirt": "Nintendo Switch Shirt", - "description.Armor.KorokMask": "Korok Mask", - "description.Armor.MajorasMask": "Majora's Mask", - "description.Armor.TinglesHood": "Tingle's Hood", - "description.Armor.TinglesShirt": "Tingle's Shirt", - "description.Armor.TinglesTights": "Tingle's Tights", - "description.Armor.MidnasHelmet": "Midna's Helmet", - "description.Armor.PhantomHelmet": "Phantom Helmet", - "description.Armor.PhantomArmor": "Phantom Armor", - "description.Armor.PhantomGreaves": "Phantom Greaves", - "description.Armor.IslandLobsterShirt": "Island Lobster Shirt", - "description.Armor.RaviosHood": "Ravio's Hood", - "description.Armor.ZantsHelmet": "Zant's Helmet", - "description.Armor.RoyalGuardCap": "Royal Guard Cap", - "description.Armor.RoyalGuardUniform": "Royal Guard Uniform", - "description.Armor.RoyalGuardBoots": "Royal Guard Boots", - "description.Armor.PhantomGanonSkull": "Phantom Ganon Skull", - "description.Armor.PhantomGanonArmor": "Phantom Ganon Armor", - "description.Armor.PhantomGanonGreaves": "Phantom Ganon Greaves", - "description.Armor.VahRutaDivineHelm": "Vah Ruta Divine Helm", - "description.Armor.VahMedohDivineHelm": "Vah Medoh Divine Helm", - "description.Armor.VahRudaniaDivineHelm": "Vah Rudania Divine Helm", - "description.Armor.VahNaborisDivineHelm": "Vah Naboris Divine Helm", - "description.Armor.SalvagerHeadwear": "Salvager Headwear", - "description.Armor.SalvagerVest": "Salvager Vest", - "description.Armor.SalvagerTrousers": "Salvager Trousers", - "description.Armor.Armor": "Generic Armor", - - "description.Material.HeartyDurian": "Hearty Durian", - "description.Material.PalmFruit": "Palm Fruit", - "description.Material.Apple": "Apple", - "description.Material.Wildberry": "Wildberry", - "description.Material.Hydromelon": "Hydromelon", - "description.Material.SpicyPepper": "Spicy Pepper", - "description.Material.Voltfruit": "Voltfruit", - "description.Material.Lotus": "Fleet-Lotus Seeds", - "description.Material.MightyBananas": "Mighty Bananas", - "description.Material.BigHeartyTruffle": "Big Hearty Truffle", - "description.Material.HeartyTruffle": "Hearty Truffle", - "description.Material.EnduraShroom": "Endura Shroom", - "description.Material.HylianShroom": "Hylian Shroom", - "description.Material.StamellaShroom": "Stamella Shroom", - "description.Material.Chillshroom": "Chillshroom", - "description.Material.Sunshroom": "Sunshroom", - "description.Material.Zapshroom": "Zapshroom", - "description.Material.Rushroom": "Rushroom", - "description.Material.Razorshroom": "Razorshroom", - "description.Material.Ironshroom": "Ironshroom", - "description.Material.SilentShroom": "Silent Shroom", - "description.Material.BigHeartyRadish": "Big Hearty Radish", - "description.Material.HeartyRadish": "Hearty Radish", - "description.Material.EnduraCarrot": "Endura Carrot", - "description.Material.HyruleHerb": "Hyrule Herb", - "description.Material.SwiftCarrot": "Swift Carrot", - "description.Material.FortifiedPumpkin": "Fortified Pumpkin", - "description.Material.CoolSafflina": "Cool Safflina", - "description.Material.WarmSafflina": "Warm Safflina", - "description.Material.ElectricSafflina": "Electric Safflina", - "description.Material.SwiftViolet": "Swift Violet", - "description.Material.MightyThistle": "Mighty Thistle", - "description.Material.Armoranth": "Armoranth", - "description.Material.BlueNightshade": "Blue Nightshade", - "description.Material.SilentPrincess": "Silent Princess", - "description.Material.RawGourmetMeat": "Raw Gourmet Meat", - "description.Material.RawWholeBird": "Raw Whole Bird", - "description.Material.RawPrimeMeat": "Raw Prime Meat", - "description.Material.RawBirdThigh": "Raw Bird Thigh", - "description.Material.RawMeat": "Raw Meat", - "description.Material.RawBirdDrumstick": "Raw Bird Drumstick", - "description.Material.Honey": "Courser Bee Honey", - "description.Material.HylianRice": "Hylian Rice", - "description.Material.BirdEgg": "Bird Egg", - "description.Material.TabanthaWheat": "Tabantha Wheat", - "description.Material.FreshMilk": "Fresh Milk", - "description.Material.Acorn": "Acorn", - "description.Material.ChickalooTreeNut": "Chickaloo Tree Nut", - "description.Material.CaneSugar": "Cane Sugar", - "description.Material.GoatButter": "Goat Butter", - "description.Material.GoronSpice": "Goron Spice", - "description.Material.RockSalt": "Rock Salt", - "description.Material.MonsterExtract": "Monster Extract", - "description.Material.StarFragment": "Star Fragment", - "description.Material.DinraalsScale": "Dinraal's Scale", - "description.Material.DinraalsClaw": "Dinraal's Claw", - "description.Material.ShardOfDinraalsFang": "Shard of Dinraal's Fang", - "description.Material.ShardOfDinraalsHorn": "Shard of Dinraal's Horn", - "description.Material.NaydrasScale": "Naydra's Scale", - "description.Material.NaydrasClaw": "Naydra's Claw", - "description.Material.ShardOfNaydrasFang": "Shard of Naydra's Fang", - "description.Material.ShardOfNaydrasHorn": "Shard of Naydra's Horn", - "description.Material.FaroshScale": "Farosh's Scale", - "description.Material.FaroshClaw": "Farosh's Claw", - "description.Material.ShardOfFaroshsFang": "Shard of Farosh's Fang", - "description.Material.FaroshHorn": "Shard of Farosh's Horn", - "description.Material.HeartySalmon": "Hearty Salmon", - "description.Material.HeartyBlueshellSnail": "Hearty Blueshell Snail", - "description.Material.HeartyBass": "Hearty Bass", - "description.Material.HyruleBass": "Hyrule Bass", - "description.Material.StaminokaBass": "Staminoka Bass", - "description.Material.ChillfinTrout": "Chillfin Trout", - "description.Material.SizzlefinTrout": "Sizzlefin Trout", - "description.Material.VoltfinTrout": "Voltfin Trout", - "description.Material.StealthfinTrout": "Stealthfin Trout", - "description.Material.MightyCarp": "Mighty Carp", - "description.Material.ArmoredCarp": "Armored Carp", - "description.Material.SankeCarp": "Sanke Carp", - "description.Material.MightyPorgy": "Mighty Porgy", - "description.Material.ArmoredPorgy": "Armored Porgy", - "description.Material.SneakyRiverSnail": "Sneaky River Snail", - "description.Material.RazorclawCrab": "Razorclaw Crab", - "description.Material.IronshellCrab": "Ironshell Crab", - "description.Material.BrightEyedCrab": "Bright-Eyed Crab", - "description.Material.Fairy": "Fairy", - "description.Material.WinterwingButterfly": "Winterwing Butterfly", - "description.Material.SummerwingButterfly": "Summerwing Butterfly", - "description.Material.ThunderwingButterfly": "Thunderwing Butterfly", - "description.Material.SmotherwingButterfly": "Smotherwing Butterfly", - "description.Material.ColdDarner": "Cold Darner", - "description.Material.WarmDarner": "Warm Darner", - "description.Material.ElectricDarner": "Electric Darner", - "description.Material.RestlessCricket": "Restless Cricket", - "description.Material.BladedRhinoBeetle": "Bladed Rhino Beetle", - "description.Material.RuggedRhinoBeetle": "Rugged Rhino Beetle", - "description.Material.Beetle": "Energetic Rhino Beetle", - "description.Material.SunsetFirefly": "Sunset Firefly", - "description.Material.HotFootedFrog": "Hot-Footed Frog", - "description.Material.TirelessFrog": "Tireless Frog", - "description.Material.HightailLizard": "Hightail Lizard", - "description.Material.HeartyLizard": "Hearty Lizard", - "description.Material.FireproofLizard": "Fireproof Lizard", - "description.Material.Flint": "Flint", - "description.Material.Amber": "Amber", - "description.Material.Opal": "Opal", - "description.Material.LuminousStone": "Luminous Stone", - "description.Material.Topaz": "Topaz", - "description.Material.Ruby": "Ruby", - "description.Material.Sapphire": "Sapphire", - "description.Material.Diamond": "Diamond", - "description.Material.BokoblinHorn": "Bokoblin Horn", - "description.Material.BokoblinFang": "Bokoblin Fang", - "description.Material.BokoblinGuts": "Bokoblin Guts", - "description.Material.MoblinHorn": "Moblin Horn", - "description.Material.MoblinFang": "Moblin Fang", - "description.Material.MoblinGuts": "Moblin Guts", - "description.Material.LizalfosHorn": "Lizalfos Horn", - "description.Material.LizalfosTalon": "Lizalfos Talon", - "description.Material.Tail": "Lizalfos Tail", - "description.Material.IcyLizalfosTail": "Icy Lizalfos Tail", - "description.Material.RedLizalfosTail": "Red Lizalfos Tail", - "description.Material.YellowLizalfosTail": "Yellow Lizalfos Tail", - "description.Material.LynelHorn": "Lynel Horn", - "description.Material.LynelHoof": "Lynel Hoof", - "description.Material.LynelGuts": "Lynel Guts", - "description.Material.ChuchuJelly": "Chuchu Jelly", - "description.Material.WhiteChuchuJelly": "White Chuchu Jelly", - "description.Material.RedChuchuJelly": "Red Chuchu Jelly", - "description.Material.YellowChuchuJelly": "Yellow Chuchu Jelly", - "description.Material.KeeseWing": "Keese Wing", - "description.Material.IceKeeseWing": "Ice Keese Wing", - "description.Material.FireKeeseWing": "Fire Keese Wing", - "description.Material.ElectricKeeseWing": "Electric Keese Wing", - "description.Material.KeeseEyeball": "Keese Eyeball", - "description.Material.OctorokTentacle": "Octorok Tentacle", - "description.Material.OctorokEyeball": "Octorok Eyeball", - "description.Material.OctoBalloon": "Octo Balloon", - "description.Material.MoldugaFin": "Molduga Fin", - "description.Material.MoldugaGuts": "Molduga Guts", - "description.Material.HinoxToenail": "Hinox Toenail", - "description.Material.HinoxTooth": "Hinox Tooth", - "description.Material.HinoxGuts": "Hinox Guts", - "description.Material.Screw": "Ancient Screw", - "description.Material.Spring": "Ancient Spring", - "description.Material.AncientGear": "Ancient Gear", - "description.Material.Shaft": "Ancient Shaft", - "description.Material.Core": "Ancient Core", - "description.Material.GiantAncientCore": "Giant Ancient Core", - "description.Material.Wood": "Wood", - - "description.Food.SimmeredFruit": "Simmered Fruit", - "description.Food.CopiousSimmeredFruit": "Copious Simmered Fruit", - "description.Food.MushroomSkewer": "Mushroom Skewer", - "description.Food.CopiousMushroomSkewers": "Copious Mushroom Skewers", - "description.Food.FriedWildGreens": "Fried Wild Greens", - "description.Food.CopiousFriedWildGreens": "Copious Fried Wild Greens", - "description.Food.FishSkewer": "Fish Skewer", - "description.Food.SeafoodSkewer": "Seafood Skewer", - "description.Food.CopiousSeafoodSkewers": "Copious Seafood Skewers", - "description.Food.MeatSkewer": "Meat Skewer", - "description.Food.CopiousMeatSkewers": "Copious Meat Skewers", - "description.Food.FruitAndMushroomMix": "Fruit and Mushroom Mix", - "description.Food.FishAndMushroomSkewer": "Fish and Mushroom Skewer", - "description.Food.MeatAndMushroomSkewer": "Meat and Mushroom Skewer", - "description.Food.SteamedFruit": "Steamed Fruit", - "description.Food.SteamedMushrooms": "Steamed Mushrooms", - "description.Food.SteamedFish": "Steamed Fish", - "description.Food.SteamedMeat": "Steamed Meat", - "description.Food.SaltGrilledMushrooms": "Salt-Grilled Mushrooms", - "description.Food.SaltGrilledGreens": "Salt-Grilled Greens", - "description.Food.SaltGrilledFish": "Salt-Grilled Fish", - "description.Food.SaltGrilledCrab": "Salt-Grilled Crab", - "description.Food.SaltGrilledMeat": "Salt-Grilled Meat", - "description.Food.SaltGrilledPrimeMeat": "Salt-Grilled Prime Meat", - "description.Food.SaltGrilledGourmetMeat": "Salt-Grilled Gourmet Meat", - "description.Food.CrabStirFry": "Crab Stir-Fry", - "description.Food.PepperSeafood": "Pepper Seafood", - "description.Food.PepperSteak": "Pepper Steak", - "description.Food.MeatAndSeafoodFry": "Meat and Seafood Fry", - "description.Food.PrimeMeatAndSeafoodFry": "Prime Meat and Seafood Fry", - "description.Food.GourmetMeatAndSeafoodFry": "Gourmet Meat and Seafood Fry", - "description.Food.SpicedMeatSkewer": "Spiced Meat Skewer", - "description.Food.PrimeSpicedMeatSkewer": "Prime Spiced Meat Skewer", - "description.Food.GourmetSpicedMeatSkewer": "Gourmet Spiced Meat Skewer", - "description.Food.FragrantMushroomSaute": "Fragrant Mushroom Sauté", - "description.Food.HerbSaute": "Herb Sauté", - "description.Food.MeatStuffedPumpkin": "Meat-Stuffed Pumpkin", - "description.Food.SauteedNuts": "Sautéed Nuts", - "description.Food.SauteedPeppers": "Sautéed Peppers", - "description.Food.Omelet": "Omelet", - "description.Food.GlazedMushrooms": "Glazed Mushrooms", - "description.Food.GlazedVeggies": "Glazed Veggies", - "description.Food.GlazedSeafood": "Glazed Seafood", - "description.Food.GlazedMeat": "Glazed Meat", - "description.Food.SeafoodMeuniere": "Seafood Meunière", - "description.Food.PorgyMeuniere": "Porgy Meunière", - "description.Food.SalmonMeuniere": "Salmon Meunière", - "description.Food.SeafoodFriedRice": "Seafood Fried Rice", - "description.Food.CrabOmeletWithRice": "Crab Omelet with Rice", - "description.Food.SeafoodPaella": "Seafood Paella", - "description.Food.PoultryPilaf": "Poultry Pilaf", - "description.Food.PrimePoultryPilaf": "Prime Poultry Pilaf", - "description.Food.GourmetPoultryPilaf": "Gourmet Poultry Pilaf", - "description.Food.CurryPilaf": "Curry Pilaf", - "description.Food.FriedEggAndRice": "Fried Egg and Rice", - "description.Food.MushroomRisotto": "Mushroom Risotto", - "description.Food.VegetableRisotto": "Vegetable Risotto", - "description.Food.SalmonRisotto": "Salmon Risotto", - "description.Food.CrabRisotto": "Crab Risotto", - "description.Food.CreamOfVegetableSoup": "Cream of Vegetable Soup", - "description.Food.CreamOfMushroomSoup": "Cream of Mushroom Soup", - "description.Food.VeggieCreamSoup": "Veggie Cream Soup", - "description.Food.CreamyHeartSoup": "Creamy Heart Soup", - "description.Food.CreamySeafoodSoup": "Creamy Seafood Soup", - "description.Food.CreamyMeatSoup": "Creamy Meat Soup", - "description.Food.MonsterSoup": "Monster Soup", - "description.Food.CarrotStew": "Carrot Stew", - "description.Food.PumpkinStew": "Pumpkin Stew", - "description.Food.ClamChowder": "Clam Chowder", - "description.Food.MeatStew": "Meat Stew", - "description.Food.PrimeMeatStew": "Prime Meat Stew", - "description.Food.GourmetMeatStew": "Gourmet Meat Stew", - "description.Food.MonsterStew": "Monster Stew", - "description.Food.CurryRice": "Curry Rice", - "description.Food.VegetableCurry": "Vegetable Curry", - "description.Food.SeafoodCurry": "Seafood Curry", - "description.Food.PoultryCurry": "Poultry Curry", - "description.Food.PrimePoultryCurry": "Prime Poultry Curry", - "description.Food.GourmetPoultryCurry": "Gourmet Poultry Curry", - "description.Food.MeatCurry": "Meat Curry", - "description.Food.PrimeMeatCurry": "Prime Meat Curry", - "description.Food.GourmetMeatCurry": "Gourmet Meat Curry", - "description.Food.MonsterCurry": "Monster Curry", - "description.Food.MushroomOmelet": "Mushroom Omelet", - "description.Food.VegetableOmelet": "Vegetable Omelet", - "description.Food.MushroomRiceBalls": "Mushroom Rice Balls", - "description.Food.VeggieRiceBalls": "Veggie Rice Balls", - "description.Food.SeafoodRiceBalls": "Seafood Rice Balls", - "description.Food.MeatyRiceBalls": "Meaty Rice Balls", - "description.Food.MonsterRiceBalls": "Monster Rice Balls", - "description.Food.MeatAndRiceBowl": "Meat and Rice Bowl", - "description.Food.PrimeMeatAndRiceBowl": "Prime Meat and Rice Bowl", - "description.Food.GourmetMeatAndRiceBowl": "Gourmet Meat and Rice Bowl", - "description.Food.WheatBread": "Wheat Bread", - "description.Food.Nutcake": "Nutcake", - "description.Food.Fruitcake": "Fruitcake", - "description.Food.CarrotCake": "Carrot Cake", - "description.Food.PumpkinPie": "Pumpkin Pie", - "description.Food.MonsterCake": "Monster Cake", - "description.Food.PlainCrepe": "Plain Crepe", - "description.Food.WildberryCrepe": "Wildberry Crepe", - "description.Food.HoneyCrepe": "Honey Crepe", - "description.Food.FruitPie": "Fruit Pie", - "description.Food.ApplePie": "Apple Pie", - "description.Food.FishPie": "Fish Pie", - "description.Food.MeatPie": "Meat Pie", - "description.Food.EggTart": "Egg Tart", - "description.Food.HoneyCandy": "Honey Candy", - "description.Food.HoneyedFruits": "Honeyed Fruits", - "description.Food.HoneyedApple": "Honeyed Apple", - "description.Food.HotButteredApple": "Hot Buttered Apple", - "description.Food.FriedBananas": "Fried Bananas", - "description.Food.EggPudding": "Egg Pudding", - "description.Food.WarmMilk": "Warm Milk", - "description.Food.Elixir": "Elixir", - "description.Food.HeartyElixir": "Hearty Elixir", - "description.Food.EnergizingElixir": "Energizing Elixir", - "description.Food.EnduraFood": "Generic Enduring Food", - "description.Food.EnduringElixir": "Enduring Elixir", - "description.Food.SpeedFood": "Generic Hasty Food", - "description.Food.HastyElixir": "Hasty Elixir", - "description.Food.FireproofElixir": "Fireproof Elixir", - "description.Food.SpicyElixir": "Spicy Elixir", - "description.Food.ChillyElixir": "Chilly Elixir", - "description.Food.ElectroElixir": "Electro Elixir", - "description.Food.MightyElixir": "Mighty Elixir", - "description.Food.ToughElixir": "Tough Elixir", - "description.Food.SneakyElixir": "Sneaky Elixir", - "description.Food.FairyTonic": "Fairy Tonic", - "description.Food.DubiousFood": "Dubious Food", - "description.Food.RockHardFood": "Rock-Hard Food", - "description.Food.BakedApple": "Baked Apple", - "description.Food.BakedPalmFruit": "Baked Palm Fruit", - "description.Food.RoastedWildberry": "Roasted Wildberry", - "description.Food.RoastedAcorn": "Roasted Acorn", - "description.Food.RoastedTreeNut": "Roasted Tree Nut", - "description.Food.RoastedHeartyDurian": "Roasted Hearty Durian", - "description.Food.RoastedHydromelon": "Roasted Hydromelon", - "description.Food.CharredPepper": "Charred Pepper", - "description.Food.RoastedVoltfruit": "Roasted Voltfruit", - "description.Food.RoastedLotusSeeds": "Roasted Lotus Seeds", - "description.Food.RoastedMightyBananas": "Roasted Mighty Bananas", - "description.Food.ToastyHylianShroom": "Toasty Hylian Shroom", - "description.Food.ToastyStamellaShroom": "Toasty Stamella Shroom", - "description.Food.ToastyEnduraShroom": "Toasty Endura Shroom", - "description.Food.ToastedHeartyTruffle": "Toasted Hearty Truffle", - "description.Food.ToastedBigHeartyTruffle": "Toasted Big Hearty Truffle", - "description.Food.ToastyChillshroom": "Toasty Chillshroom", - "description.Food.ToastySunshroom": "Toasty Sunshroom", - "description.Food.ToastyZapshroom": "Toasty Zapshroom", - "description.Food.ToastyRushroom": "Toasty Rushroom", - "description.Food.ToastyRazorshroom": "Toasty Razorshroom", - "description.Food.ToastyIronshroom": "Toasty Ironshroom", - "description.Food.ToastySilentShroom": "Toasty Silent Shroom", - "description.Food.RoastedRadish": "Roasted Radish", - "description.Food.RoastedBigRadish": "Roasted Big Radish", - "description.Food.RoastedSwiftCarrot": "Roasted Swift Carrot", - "description.Food.RoastedEnduraCarrot": "Roasted Endura Carrot", - "description.Food.BakedFortifiedPumpkin": "Baked Fortified Pumpkin", - "description.Food.RoastedMightyThistle": "Roasted Mighty Thistle", - "description.Food.RoastedArmoranth": "Roasted Armoranth", - "description.Food.CampfireEgg": "Campfire Egg", - "description.Food.HardBoiledEgg": "Hard-Boiled Egg", - "description.Food.SearedSteak": "Seared Steak", - "description.Food.SearedPrimeSteak": "Seared Prime Steak", - "description.Food.SearedGourmetSteak": "Seared Gourmet Steak", - "description.Food.RoastedBirdDrumstick": "Roasted Bird Drumstick", - "description.Food.RoastedBirdThigh": "Roasted Bird Thigh", - "description.Food.RoastedWholeBird": "Roasted Whole Bird", - "description.Food.RoastedBass": "Roasted Bass", - "description.Food.RoastedHeartyBass": "Roasted Hearty Bass", - "description.Food.RoastedHeartySalmon": "Roasted Hearty Salmon", - "description.Food.RoastedTrout": "Roasted Trout", - "description.Food.RoastedCarp": "Roasted Carp", - "description.Food.RoastedPorgy": "Roasted Porgy", - "description.Food.SneakyRiverEscargot": "Sneaky River Escargot", - "description.Food.BlueshellEscargot": "Blueshell Escargot", - "description.Food.BlackenedCrab": "Blackened Crab", - "description.Food.IcyMeat": "Icy Meat", - "description.Food.IcyPrimeMeat": "Icy Prime Meat", - "description.Food.IcyGourmetMeat": "Icy Gourmet Meat", - "description.Food.FrozenBirdDrumstick": "Frozen Bird Drumstick", - "description.Food.FrozenBirdThigh": "Frozen Bird Thigh", - "description.Food.FrozenWholeBird": "Frozen Whole Bird", - "description.Food.FrozenBass": "Frozen Bass", - "description.Food.FrozenHeartyBass": "Frozen Hearty Bass", - "description.Food.FrozenHeartySalmon": "Frozen Hearty Salmon", - "description.Food.FrozenTrout": "Frozen Trout", - "description.Food.FrozenCarp": "Frozen Carp", - "description.Food.FrozenPorgy": "Frozen Porgy", - "description.Food.FrozenCrab": "Frozen Crab", - "description.Food.FrozenRiverSnail": "Frozen River Snail", - "description.Food.IcyHeartyBlueshellSnail": "Icy Hearty Blueshell Snail", - - "description.Key.Slate": "Sheikah Slate", - "description.Key.MiphasGrace": "Mipha's Grace", - "description.Key.RevalisGale": "Revali's Gale", - "description.Key.DaruksProtection": "Daruk's Protection", - "description.Key.UrbosasFury": "Urbosa's Fury", - "description.Key.MiphasGracePlus": "Mipha's Grace +", - "description.Key.RevalisGalePlus": "Revali's Gale +", - "description.Key.DaruksProtectionPlus": "Daruk's Protection +", - "description.Key.UrbosasFuryPlus": "Urbosa's Fury +", - "description.Key.Glider": "Paraglider", - "description.Key.RutasEmblem": "Ruta's Emblem", - "description.Key.MedohsEmblem": "Medoh's Emblem", - "description.Key.RudaniasEmblem": "Rudania's Emblem", - "description.Key.NaborissEmblem": "Naboris's Emblem", - "description.Key.SpiritOrb": "Spirit Orb", - "description.Key.KorokSeed": "Korok Seed", - "description.Key.HestusMaracas": "Hestu's Maracas", - "description.Key.ThunderHelmKeyItem": "Thunder Helm", - "description.Key.ClassifiedEnvelope": "Classified Envelope", - "description.Key.HestusGift": "Hestu's Gift", - "description.Key.PictureOfTheChampions": "Picture of the Champions", - "description.Key.MedalOfHonorTalus": "Medal of Honor: Talus", - "description.Key.MedalOfHonorHinox": "Medal of Honor: Hinox", - "description.Key.MedalOfHonorMolduga": "Medal of Honor: Molduga", - "description.Key.TravelersBridle": "Traveler's Bridle", - "description.Key.KnightsBridle": "Knight's Bridle", - "description.Key.RoyalBridle": "Royal Bridle", - "description.Key.ExtravagantBridle": "Extravagant Bridle", - "description.Key.MonsterBridle": "Monster Bridle", - "description.Key.AncientBridle": "Ancient Bridle", - "description.Key.TravelersSaddle": "Traveler's Saddle", - "description.Key.KnightsSaddle": "Knight's Saddle", - "description.Key.RoyalSaddle": "Royal Saddle", - "description.Key.ExtravagantSaddle": "Extravagant Saddle", - "description.Key.MonsterSaddle": "Monster Saddle", - "description.Key.AncientSaddle": "Ancient Saddle", - "description.Key.TravelMedallion": "Travel Medallion" -} diff --git a/src/config/items.json b/src/config/items.json deleted file mode 100644 index 97e5aa8..0000000 --- a/src/config/items.json +++ /dev/null @@ -1,694 +0,0 @@ -{ - "MasterSword": { "type": "Weapon", "options": { "stackable": false } }, - "TreeBranch": { "type": "Weapon", "options": { "stackable": false } }, - "Torch": { "type": "Weapon", "options": { "stackable": false } }, - "SoupLadle": { "type": "Weapon", "options": { "stackable": false } }, - "Boomerang": { "type": "Weapon", "options": { "stackable": false } }, - "SpringLoadedHammer": { "type": "Weapon", "options": { "stackable": false } }, - "TravelersSword": { "type": "Weapon", "options": { "stackable": false } }, - "SoldiersBroadsword": { "type": "Weapon", "options": { "stackable": false } }, - "KnightsBroadsword": { "type": "Weapon", "options": { "stackable": false } }, - "RoyalBroadsword": { "type": "Weapon", "options": { "stackable": false } }, - "ForestDwellersSword": { "type": "Weapon", "options": { "stackable": false } }, - "ZoraSword": { "type": "Weapon", "options": { "stackable": false } }, - "FeatheredEdge": { "type": "Weapon", "options": { "stackable": false } }, - "GerudoScimitar": { "type": "Weapon", "options": { "stackable": false } }, - "MoonlightScimitar": { "type": "Weapon", "options": { "stackable": false } }, - "ScimitarOfTheSeven": { "type": "Weapon", "options": { "stackable": false } }, - "EightfoldBlade": { "type": "Weapon", "options": { "stackable": false } }, - "AncientShortSword": { "type": "Weapon", "options": { "stackable": false } }, - "RustyBroadsword": { "type": "Weapon", "options": { "stackable": false } }, - "RoyalGuardsSword": { "type": "Weapon", "options": { "stackable": false } }, - "Flameblade": { "type": "Weapon", "options": { "stackable": false } }, - "Frostblade": { "type": "Weapon", "options": { "stackable": false } }, - "Thunderblade": { "type": "Weapon", "options": { "stackable": false } }, - "GoddessSword": { "type": "Weapon", "options": { "stackable": false } }, - "Sword": { "type": "Weapon", "options": { "stackable": false } }, - "SeaBreezeBoomerang": { "type": "Weapon", "options": { "stackable": false } }, - "BokoClub": { "type": "Weapon", "options": { "stackable": false } }, - "SpikedBokoClub": { "type": "Weapon", "options": { "stackable": false } }, - "DragonboneBokoClub": { "type": "Weapon", "options": { "stackable": false } }, - "LizalBoomerang": { "type": "Weapon", "options": { "stackable": false } }, - "LizalForkedBoomerang": { "type": "Weapon", "options": { "stackable": false } }, - "LizalTriBoomerang": { "type": "Weapon", "options": { "stackable": false } }, - "GuardianSword": { "type": "Weapon", "options": { "stackable": false } }, - "GuardianSwordPlus": { "type": "Weapon", "options": { "stackable": false } }, - "GuardianSwordPlusPlus": { "type": "Weapon", "options": { "stackable": false } }, - "LynelSword": { "type": "Weapon", "options": { "stackable": false } }, - "MightyLynelSword": { "type": "Weapon", "options": { "stackable": false } }, - "SavageLynelSword": { "type": "Weapon", "options": { "stackable": false } }, - "FireRod": { "type": "Weapon", "options": { "stackable": false } }, - "MeteorRod": { "type": "Weapon", "options": { "stackable": false } }, - "IceRod": { "type": "Weapon", "options": { "stackable": false } }, - "BlizzardRod": { "type": "Weapon", "options": { "stackable": false } }, - "LightningRod": { "type": "Weapon", "options": { "stackable": false } }, - "ThunderstormRod": { "type": "Weapon", "options": { "stackable": false } }, - "ViciousSickle": { "type": "Weapon", "options": { "stackable": false } }, - "DemonCarver": { "type": "Weapon", "options": { "stackable": false } }, - "OneHitObliterator": { "type": "Weapon", "options": { "stackable": false } }, - "BokoblinArm": { "type": "Weapon", "options": { "stackable": false } }, - "LizalfosArm": { "type": "Weapon", "options": { "stackable": false } }, - - "KorokLeaf": { "type": "Weapon", "options": { "stackable": false } }, - "FarmingHoe": { "type": "Weapon", "options": { "stackable": false } }, - "BoatOar": { "type": "Weapon", "options": { "stackable": false } }, - "WoodcuttersAxe": { "type": "Weapon", "options": { "stackable": false } }, - "DoubleAxe": { "type": "Weapon", "options": { "stackable": false } }, - "IronSledgehammer": { "type": "Weapon", "options": { "stackable": false } }, - "GiantBoomerang": { "type": "Weapon", "options": { "stackable": false } }, - "TravelersClaymore": { "type": "Weapon", "options": { "stackable": false } }, - "SoldiersClaymore": { "type": "Weapon", "options": { "stackable": false } }, - "KnightsClaymore": { "type": "Weapon", "options": { "stackable": false } }, - "RoyalClaymore": { "type": "Weapon", "options": { "stackable": false } }, - "SilverLongsword": { "type": "Weapon", "options": { "stackable": false } }, - "CobbleCrusher": { "type": "Weapon", "options": { "stackable": false } }, - "StoneSmasher": { "type": "Weapon", "options": { "stackable": false } }, - "BoulderBreaker": { "type": "Weapon", "options": { "stackable": false } }, - "GoldenClaymore": { "type": "Weapon", "options": { "stackable": false } }, - "EightfoldLongblade": { "type": "Weapon", "options": { "stackable": false } }, - "EdgeOfDuality": { "type": "Weapon", "options": { "stackable": false } }, - "AncientBladesaw": { "type": "Weapon", "options": { "stackable": false } }, - "RustyClaymore": { "type": "Weapon", "options": { "stackable": false } }, - "RoyalGuardsClaymore": { "type": "Weapon", "options": { "stackable": false } }, - "GreatFlameblade": { "type": "Weapon", "options": { "stackable": false } }, - "GreatFrostblade": { "type": "Weapon", "options": { "stackable": false } }, - "GreatThunderblade": { "type": "Weapon", "options": { "stackable": false } }, - "SwordOfTheSixSages": { "type": "Weapon", "options": { "stackable": false } }, - "BiggoronsSword": { "type": "Weapon", "options": { "stackable": false } }, - "FierceDeitySword": { "type": "Weapon", "options": { "stackable": false } }, - "BokoBat": { "type": "Weapon", "options": { "stackable": false } }, - "SpikedBokoBat": { "type": "Weapon", "options": { "stackable": false } }, - "DragonboneBokoBat": { "type": "Weapon", "options": { "stackable": false } }, - "MoblinClub": { "type": "Weapon", "options": { "stackable": false } }, - "SpikedMoblinClub": { "type": "Weapon", "options": { "stackable": false } }, - "DragonboneMoblinClub": { "type": "Weapon", "options": { "stackable": false } }, - "AncientBattleAxe": { "type": "Weapon", "options": { "stackable": false } }, - "AncientBattleAxePlus": { "type": "Weapon", "options": { "stackable": false } }, - "AncientBattleAxePlusPlus": { "type": "Weapon", "options": { "stackable": false } }, - "LynelCrusher": { "type": "Weapon", "options": { "stackable": false } }, - "MightyLynelCrusher": { "type": "Weapon", "options": { "stackable": false } }, - "SavageLynelCrusher": { "type": "Weapon", "options": { "stackable": false } }, - "Windcleaver": { "type": "Weapon", "options": { "stackable": false } }, - "MoblinArm": { "type": "Weapon", "options": { "stackable": false } }, - - "WoodenMop": { "type": "Weapon", "options": { "stackable": false } }, - "FarmersPitchfork": { "type": "Weapon", "options": { "stackable": false } }, - "FishingHarpoon": { "type": "Weapon", "options": { "stackable": false } }, - "ThrowingSpear": { "type": "Weapon", "options": { "stackable": false } }, - "TravelersSpear": { "type": "Weapon", "options": { "stackable": false } }, - "SoldiersSpear": { "type": "Weapon", "options": { "stackable": false } }, - "KnightsHalberd": { "type": "Weapon", "options": { "stackable": false } }, - "RoyalHalberd": { "type": "Weapon", "options": { "stackable": false } }, - "ForestDwellersSpear": { "type": "Weapon", "options": { "stackable": false } }, - "ZoraSpear": { "type": "Weapon", "options": { "stackable": false } }, - "SilverscaleSpear": { "type": "Weapon", "options": { "stackable": false } }, - "CeremonialTrident": { "type": "Weapon", "options": { "stackable": false } }, - "LightscaleTrident": { "type": "Weapon", "options": { "stackable": false } }, - "Drillshaft": { "type": "Weapon", "options": { "stackable": false } }, - "FeatheredSpear": { "type": "Weapon", "options": { "stackable": false } }, - "GerudoSpear": { "type": "Weapon", "options": { "stackable": false } }, - "SerpentineSpear": { "type": "Weapon", "options": { "stackable": false } }, - "AncientSpear": { "type": "Weapon", "options": { "stackable": false } }, - "RustyHalberd": { "type": "Weapon", "options": { "stackable": false } }, - "RoyalGuardsSpear": { "type": "Weapon", "options": { "stackable": false } }, - "Flamespear": { "type": "Weapon", "options": { "stackable": false } }, - "Frostspear": { "type": "Weapon", "options": { "stackable": false } }, - "Thunderspear": { "type": "Weapon", "options": { "stackable": false } }, - "BokoSpear": { "type": "Weapon", "options": { "stackable": false } }, - "SpikedBokoSpear": { "type": "Weapon", "options": { "stackable": false } }, - "DragonboneBokoSpear": { "type": "Weapon", "options": { "stackable": false } }, - "MoblinSpear": { "type": "Weapon", "options": { "stackable": false } }, - "SpikedMoblinSpear": { "type": "Weapon", "options": { "stackable": false } }, - "DragonboneMoblinSpear": { "type": "Weapon", "options": { "stackable": false } }, - "LizalSpear": { "type": "Weapon", "options": { "stackable": false } }, - "EnhancedLizalSpear": { "type": "Weapon", "options": { "stackable": false } }, - "ForkedLizalSpear": { "type": "Weapon", "options": { "stackable": false } }, - "GuardianSpear": { "type": "Weapon", "options": { "stackable": false } }, - "GuardianSpearPlus": { "type": "Weapon", "options": { "stackable": false } }, - "GuardianSpearPlusPlus": { "type": "Weapon", "options": { "stackable": false } }, - "LynelSpear": { "type": "Weapon", "options": { "stackable": false } }, - "MightyLynelSpear": { "type": "Weapon", "options": { "stackable": false } }, - "SavageLynelSpear": { "type": "Weapon", "options": { "stackable": false } }, - "Weapon": { "type": "Weapon", "options": { "image": "WoodcuttersAxe", "stackable": false } }, - - "BowOfLight": { "type": "Bow", "options": { "stackable": false } }, - "WoodenBow": { "type": "Bow", "options": { "stackable": false } }, - "TravelersBow": { "type": "Bow", "options": { "stackable": false } }, - "SoldiersBow": { "type": "Bow", "options": { "stackable": false } }, - "KnightsBow": { "type": "Bow", "options": { "stackable": false } }, - "RoyalBow": { "type": "Bow", "options": { "stackable": false } }, - "ForestDwellersBow": { "type": "Bow", "options": { "stackable": false } }, - "SilverBow": { "type": "Bow", "options": { "stackable": false } }, - "SwallowBow": { "type": "Bow", "options": { "stackable": false } }, - "FalconBow": { "type": "Bow", "options": { "stackable": false } }, - "GreatEagleBow": { "type": "Bow", "options": { "stackable": false } }, - "GoldenBow": { "type": "Bow", "options": { "stackable": false } }, - "PhrenicBow": { "type": "Bow", "options": { "stackable": false } }, - "AncientBow": { "type": "Bow", "options": { "stackable": false } }, - "RoyalGuardsBow": { "type": "Bow", "options": { "stackable": false } }, - "TwilightBow": { "type": "Bow", "options": { "stackable": false } }, - "BokoBow": { "type": "Bow", "options": { "stackable": false } }, - "SpikedBokoBow": { "type": "Bow", "options": { "stackable": false } }, - "DragonBoneBokoBow": { "type": "Bow", "options": { "stackable": false } }, - "LizalBow": { "type": "Bow", "options": { "stackable": false } }, - "StrengthenedLizalBow": { "type": "Bow", "options": { "stackable": false } }, - "SteelLizalBow": { "type": "Bow", "options": { "stackable": false } }, - "LynelBow": { "type": "Bow", "options": { "stackable": false } }, - "MightyLynelBow": { "type": "Bow", "options": { "stackable": false } }, - "SavageLynelBow": { "type": "Bow", "options": { "stackable": false } }, - "DuplexBow": { "type": "Bow", "options": { "stackable": false } }, - "Bow": { "type": "Bow", "options": { "image": "ForestDwellersBow", "stackable": false } }, - - "NormalArrow": { "type": "Arrow", "options": { "image": "Arrow" } }, - "FireArrow": { "type": "Arrow" }, - "IceArrow": { "type": "Arrow" }, - "ShockArrow": { "type": "Arrow" }, - "BombArrow": { "type": "Arrow" }, - "AncientArrow": { "type": "Arrow" }, - - "HylianShield": { "type": "Shield", "options": { "stackable": false } }, - "PotLid": { "type": "Shield", "options": { "stackable": false } }, - "WoodenShield": { "type": "Shield", "options": { "stackable": false } }, - "EmblazonedShield": { "type": "Shield", "options": { "stackable": false } }, - "HuntersShield": { "type": "Shield", "options": { "stackable": false } }, - "FishermansShield": { "type": "Shield", "options": { "stackable": false } }, - "TravelersShield": { "type": "Shield", "options": { "stackable": false } }, - "SoldiersShield": { "type": "Shield", "options": { "stackable": false } }, - "KnightsShield": { "type": "Shield", "options": { "stackable": false } }, - "RoyalShield": { "type": "Shield", "options": { "stackable": false } }, - "ForestDwellersShield": { "type": "Shield", "options": { "stackable": false } }, - "SilverShield": { "type": "Shield", "options": { "stackable": false } }, - "KiteShield": { "type": "Shield", "options": { "stackable": false } }, - "GerudoShield": { "type": "Shield", "options": { "stackable": false } }, - "RadiantShield": { "type": "Shield", "options": { "stackable": false } }, - "Daybreaker": { "type": "Shield", "options": { "stackable": false } }, - "ShieldOfTheMindsEye": { "type": "Shield", "options": { "stackable": false } }, - "AncientShield": { "type": "Shield", "options": { "stackable": false } }, - "RustyShield": { "type": "Shield", "options": { "stackable": false } }, - "RoyalGuardsShield": { "type": "Shield", "options": { "stackable": false } }, - "HerosShield": { "type": "Shield", "options": { "stackable": false } }, - "BokoShield": { "type": "Shield", "options": { "stackable": false } }, - "SpikedBokoShield": { "type": "Shield", "options": { "stackable": false } }, - "DragonboneBokoShield": { "type": "Shield", "options": { "stackable": false } }, - "LizalShield": { "type": "Shield", "options": { "stackable": false } }, - "ReinforcedLizalShield": { "type": "Shield", "options": { "stackable": false } }, - "SteelLizalShield": { "type": "Shield", "options": { "stackable": false } }, - "GuardianShield": { "type": "Shield", "options": { "stackable": false } }, - "GuardianShieldPlus": { "type": "Shield", "options": { "stackable": false } }, - "GuardianShieldPlusPlus": { "type": "Shield", "options": { "stackable": false } }, - "LynelShield": { "type": "Shield", "options": { "stackable": false } }, - "MightyLynelShield": { "type": "Shield", "options": { "stackable": false } }, - "SavageLynelShield": { "type": "Shield", "options": { "stackable": false } }, - "Shield": { "type": "Shield", "options": { "image": "PotLid", "stackable": false } }, - - "OldShirt": { "type": "Armor", "options": { "stackable": false } }, - "WellWornTrousers": { "type": "Armor", "options": { "stackable": false } }, - "ChampionsTunic": { "type": "Armor", "options": { "stackable": false } }, - "HylianHood": { "type": "Armor", "options": { "stackable": false } }, - "HylianTunic": { "type": "Armor", "options": { "stackable": false } }, - "HylianTrousers": { "type": "Armor", "options": { "stackable": false } }, - "SoldiersHelm": { "type": "Armor", "options": { "stackable": false } }, - "SoldiersArmor": { "type": "Armor", "options": { "stackable": false } }, - "SoldiersGreaves": { "type": "Armor", "options": { "stackable": false } }, - "AmberEarrings": { "type": "Armor", "options": { "stackable": false } }, - "WarmDoublet": { "type": "Armor", "options": { "stackable": false } }, - "RubyCirclet": { "type": "Armor", "options": { "stackable": false } }, - "SnowquillHeaddress": { "type": "Armor", "options": { "stackable": false } }, - "SnowquillTunic": { "type": "Armor", "options": { "stackable": false } }, - "SnowquillTrousers": { "type": "Armor", "options": { "stackable": false } }, - "SapphireCirclet": { "type": "Armor", "options": { "stackable": false } }, - "DesertVoeHeadband": { "type": "Armor", "options": { "stackable": false } }, - "DesertVoeSpaulder": { "type": "Armor", "options": { "stackable": false } }, - "DesertVoeTrousers": { "type": "Armor", "options": { "stackable": false } }, - "GerudoVeil": { "type": "Armor", "options": { "stackable": false } }, - "GerudoTop": { "type": "Armor", "options": { "stackable": false } }, - "GerudoSirwal": { "type": "Armor", "options": { "stackable": false } }, - "TopazEarrings": { "type": "Armor", "options": { "stackable": false } }, - "RubberHelm": { "type": "Armor", "options": { "stackable": false } }, - "RubberArmor": { "type": "Armor", "options": { "stackable": false } }, - "RubberTights": { "type": "Armor", "options": { "stackable": false } }, - "FlamebreakerHelm": { "type": "Armor", "options": { "stackable": false } }, - "FlamebreakerArmor": { "type": "Armor", "options": { "stackable": false } }, - "FlamebreakerBoots": { "type": "Armor", "options": { "stackable": false } }, - "OpalEarrings": { "type": "Armor", "options": { "stackable": false } }, - "ZoraHelm": { "type": "Armor", "options": { "stackable": false } }, - "ZoraArmor": { "type": "Armor", "options": { "stackable": false } }, - "ZoraGreaves": { "type": "Armor", "options": { "stackable": false } }, - "StealthMask": { "type": "Armor", "options": { "stackable": false } }, - "StealthChestGuard": { "type": "Armor", "options": { "stackable": false } }, - "StealthTights": { "type": "Armor", "options": { "stackable": false } }, - "SheiksMask": { "type": "Armor", "options": { "stackable": false } }, - "ThunderHelm": { "type": "Armor", "options": { "stackable": false } }, - "ClimbersBandanna": { "type": "Armor", "options": { "stackable": false } }, - "ClimbingGear": { "type": "Armor", "options": { "stackable": false } }, - "ClimbingBoots": { "type": "Armor", "options": { "stackable": false } }, - "BarbarianHelm": { "type": "Armor", "options": { "stackable": false } }, - "BarbarianArmor": { "type": "Armor", "options": { "stackable": false } }, - "BarbarianLegWraps": { "type": "Armor", "options": { "stackable": false } }, - "FierceDeityMask": { "type": "Armor", "options": { "stackable": false } }, - "FierceDeityArmor": { "type": "Armor", "options": { "stackable": false } }, - "FierceDeityBoots": { "type": "Armor", "options": { "stackable": false } }, - "RadiantMask": { "type": "Armor", "options": { "stackable": false } }, - "RadiantShirt": { "type": "Armor", "options": { "stackable": false } }, - "RadiantTights": { "type": "Armor", "options": { "stackable": false } }, - "DiamondCirclet": { "type": "Armor", "options": { "stackable": false } }, - "AncientHelm": { "type": "Armor", "options": { "stackable": false } }, - "AncientCuirass": { "type": "Armor", "options": { "stackable": false } }, - "AncientGreaves": { "type": "Armor", "options": { "stackable": false } }, - "SandBoots": { "type": "Armor", "options": { "stackable": false } }, - "SnowBoots": { "type": "Armor", "options": { "stackable": false } }, - "BokoblinMask": { "type": "Armor", "options": { "stackable": false } }, - "MoblinMask": { "type": "Armor", "options": { "stackable": false } }, - "LizalfosMask": { "type": "Armor", "options": { "stackable": false } }, - "LynelMask": { "type": "Armor", "options": { "stackable": false } }, - "DarkHood": { "type": "Armor", "options": { "stackable": false } }, - "DarkTunic": { "type": "Armor", "options": { "stackable": false } }, - "DarkTrousers": { "type": "Armor", "options": { "stackable": false } }, - "CapOfTime": { "type": "Armor", "options": { "stackable": false } }, - "TunicOfTime": { "type": "Armor", "options": { "stackable": false } }, - "TrousersOfTime": { "type": "Armor", "options": { "stackable": false } }, - "CapOfTheWind": { "type": "Armor", "options": { "stackable": false } }, - "TunicOfTheWind": { "type": "Armor", "options": { "stackable": false } }, - "TrousersOfTheWind": { "type": "Armor", "options": { "stackable": false } }, - "CapOfTwilight": { "type": "Armor", "options": { "stackable": false } }, - "TunicOfTwilight": { "type": "Armor", "options": { "stackable": false } }, - "TrousersOfTwilight": { "type": "Armor", "options": { "stackable": false } }, - "CapOfTheSky": { "type": "Armor", "options": { "stackable": false } }, - "TunicOfTheSky": { "type": "Armor", "options": { "stackable": false } }, - "TrousersOfTheSky": { "type": "Armor", "options": { "stackable": false } }, - "CapOfTheHero": { "type": "Armor", "options": { "stackable": false } }, - "TunicOfTheHero": { "type": "Armor", "options": { "stackable": false } }, - "TrousersOfTheHero": { "type": "Armor", "options": { "stackable": false } }, - "CapOfTheWild": { "type": "Armor", "options": { "stackable": false } }, - "TunicOfTheWild": { "type": "Armor", "options": { "stackable": false } }, - "TrousersOfTheWild": { "type": "Armor", "options": { "stackable": false } }, - "NintendoSwitchShirt": { "type": "Armor", "options": { "stackable": false } }, - "KorokMask": { "type": "Armor", "options": { "stackable": false } }, - "MajorasMask": { "type": "Armor", "options": { "stackable": false } }, - "TinglesHood": { "type": "Armor", "options": { "stackable": false } }, - "TinglesShirt": { "type": "Armor", "options": { "stackable": false } }, - "TinglesTights": { "type": "Armor", "options": { "stackable": false } }, - "MidnasHelmet": { "type": "Armor", "options": { "stackable": false } }, - "PhantomHelmet": { "type": "Armor", "options": { "stackable": false } }, - "PhantomArmor": { "type": "Armor", "options": { "stackable": false } }, - "PhantomGreaves": { "type": "Armor", "options": { "stackable": false } }, - "IslandLobsterShirt": { "type": "Armor", "options": { "stackable": false } }, - "RaviosHood": { "type": "Armor", "options": { "stackable": false } }, - "ZantsHelmet": { "type": "Armor", "options": { "stackable": false } }, - "RoyalGuardCap": { "type": "Armor", "options": { "stackable": false } }, - "RoyalGuardUniform": { "type": "Armor", "options": { "stackable": false } }, - "RoyalGuardBoots": { "type": "Armor", "options": { "stackable": false } }, - "PhantomGanonSkull": { "type": "Armor", "options": { "stackable": false } }, - "PhantomGanonArmor": { "type": "Armor", "options": { "stackable": false } }, - "PhantomGanonGreaves": { "type": "Armor", "options": { "stackable": false } }, - "VahRutaDivineHelm": { "type": "Armor", "options": { "stackable": false } }, - "VahMedohDivineHelm": { "type": "Armor", "options": { "stackable": false } }, - "VahRudaniaDivineHelm": { "type": "Armor", "options": { "stackable": false } }, - "VahNaborisDivineHelm": { "type": "Armor", "options": { "stackable": false } }, - "SalvagerHeadwear": { "type": "Armor", "options": { "stackable": false } }, - "SalvagerVest": { "type": "Armor", "options": { "stackable": false } }, - "SalvagerTrousers": { "type": "Armor", "options": { "stackable": false } }, - "Armor": { "type": "Armor", "options": { "image": "OldShirt", "stackable": false } }, - - "HeartyDurian": { "type": "Material" }, - "PalmFruit": { "type": "Material" }, - "Apple": { "type": "Material" }, - "Wildberry": { "type": "Material" }, - "Hydromelon": { "type": "Material" }, - "SpicyPepper": { "type": "Material" }, - "Voltfruit": { "type": "Material" }, - "Lotus": { "type": "Material", "options": { "image": "FleetLotusSeeds" } }, - "MightyBananas": { "type": "Material" }, - "BigHeartyTruffle": { "type": "Material" }, - "HeartyTruffle": { "type": "Material" }, - "EnduraShroom": { "type": "Material" }, - "HylianShroom": { "type": "Material" }, - "StamellaShroom": { "type": "Material" }, - "Chillshroom": { "type": "Material" }, - "Sunshroom": { "type": "Material" }, - "Zapshroom": { "type": "Material" }, - "Rushroom": { "type": "Material" }, - "Razorshroom": { "type": "Material" }, - "Ironshroom": { "type": "Material" }, - "SilentShroom": { "type": "Material" }, - "BigHeartyRadish": { "type": "Material" }, - "HeartyRadish": { "type": "Material" }, - "EnduraCarrot": { "type": "Material" }, - "HyruleHerb": { "type": "Material" }, - "SwiftCarrot": { "type": "Material" }, - "FortifiedPumpkin": { "type": "Material" }, - "CoolSafflina": { "type": "Material" }, - "WarmSafflina": { "type": "Material" }, - "ElectricSafflina": { "type": "Material" }, - "SwiftViolet": { "type": "Material" }, - "MightyThistle": { "type": "Material" }, - "Armoranth": { "type": "Material" }, - "BlueNightshade": { "type": "Material" }, - "SilentPrincess": { "type": "Material" }, - "RawGourmetMeat": { "type": "Material" }, - "RawWholeBird": { "type": "Material" }, - "RawPrimeMeat": { "type": "Material" }, - "RawBirdThigh": { "type": "Material" }, - "RawMeat": { "type": "Material" }, - "RawBirdDrumstick": { "type": "Material" }, - "Honey": { "type": "Material", "options": { "image": "CourserBeeHoney" } }, - "HylianRice": { "type": "Material" }, - "BirdEgg": { "type": "Material" }, - "TabanthaWheat": { "type": "Material" }, - "FreshMilk": { "type": "Material" }, - "Acorn": { "type": "Material" }, - "ChickalooTreeNut": { "type": "Material" }, - "CaneSugar": { "type": "Material" }, - "GoatButter": { "type": "Material" }, - "GoronSpice": { "type": "Material" }, - "RockSalt": { "type": "Material" }, - "MonsterExtract": { "type": "Material" }, - "StarFragment": { "type": "Material" }, - "DinraalsScale": { "type": "Material" }, - "DinraalsClaw": { "type": "Material" }, - "ShardOfDinraalsFang": { "type": "Material" }, - "ShardOfDinraalsHorn": { "type": "Material" }, - "NaydrasScale": { "type": "Material" }, - "NaydrasClaw": { "type": "Material" }, - "ShardOfNaydrasFang": { "type": "Material" }, - "ShardOfNaydrasHorn": { "type": "Material" }, - "FaroshScale": { "type": "Material", "options": { "image": "FaroshsScale" } }, - "FaroshClaw": { "type": "Material", "options": { "image": "FaroshsClaw" } }, - "ShardOfFaroshsFang": { "type": "Material" }, - "FaroshHorn": { "type": "Material", "options": { "image": "ShardOfFaroshsHorn" } }, - "HeartySalmon": { "type": "Material" }, - "HeartyBlueshellSnail": { "type": "Material" }, - "HeartyBass": { "type": "Material" }, - "HyruleBass": { "type": "Material" }, - "StaminokaBass": { "type": "Material" }, - "ChillfinTrout": { "type": "Material" }, - "SizzlefinTrout": { "type": "Material" }, - "VoltfinTrout": { "type": "Material" }, - "StealthfinTrout": { "type": "Material" }, - "MightyCarp": { "type": "Material" }, - "ArmoredCarp": { "type": "Material" }, - "SankeCarp": { "type": "Material" }, - "MightyPorgy": { "type": "Material" }, - "ArmoredPorgy": { "type": "Material" }, - "SneakyRiverSnail": { "type": "Material" }, - "RazorclawCrab": { "type": "Material" }, - "IronshellCrab": { "type": "Material" }, - "BrightEyedCrab": { "type": "Material" }, - "Fairy": { "type": "Material" }, - "WinterwingButterfly": { "type": "Material" }, - "SummerwingButterfly": { "type": "Material" }, - "ThunderwingButterfly": { "type": "Material" }, - "SmotherwingButterfly": { "type": "Material" }, - "ColdDarner": { "type": "Material" }, - "WarmDarner": { "type": "Material" }, - "ElectricDarner": { "type": "Material" }, - "RestlessCricket": { "type": "Material" }, - "BladedRhinoBeetle": { "type": "Material" }, - "RuggedRhinoBeetle": { "type": "Material" }, - "Beetle": { "type": "Material", "options": { "image": "EnergeticRhinoBeetle" } }, - "SunsetFirefly": { "type": "Material" }, - "HotFootedFrog": { "type": "Material" }, - "TirelessFrog": { "type": "Material" }, - "HightailLizard": { "type": "Material" }, - "HeartyLizard": { "type": "Material" }, - "FireproofLizard": { "type": "Material" }, - "Flint": { "type": "Material" }, - "Amber": { "type": "Material" }, - "Opal": { "type": "Material" }, - "LuminousStone": { "type": "Material" }, - "Topaz": { "type": "Material" }, - "Ruby": { "type": "Material" }, - "Sapphire": { "type": "Material" }, - "Diamond": { "type": "Material" }, - "BokoblinHorn": { "type": "Material" }, - "BokoblinFang": { "type": "Material" }, - "BokoblinGuts": { "type": "Material" }, - "MoblinHorn": { "type": "Material" }, - "MoblinFang": { "type": "Material" }, - "MoblinGuts": { "type": "Material" }, - "LizalfosHorn": { "type": "Material" }, - "LizalfosTalon": { "type": "Material" }, - "Tail": { "type": "Material", "options": { "image": "LizalfosTail" } }, - "IcyLizalfosTail": { "type": "Material" }, - "RedLizalfosTail": { "type": "Material" }, - "YellowLizalfosTail": { "type": "Material" }, - "LynelHorn": { "type": "Material" }, - "LynelHoof": { "type": "Material" }, - "LynelGuts": { "type": "Material" }, - "ChuchuJelly": { "type": "Material" }, - "WhiteChuchuJelly": { "type": "Material" }, - "RedChuchuJelly": { "type": "Material" }, - "YellowChuchuJelly": { "type": "Material" }, - "KeeseWing": { "type": "Material" }, - "IceKeeseWing": { "type": "Material" }, - "FireKeeseWing": { "type": "Material" }, - "ElectricKeeseWing": { "type": "Material" }, - "KeeseEyeball": { "type": "Material" }, - "OctorokTentacle": { "type": "Material" }, - "OctorokEyeball": { "type": "Material" }, - "OctoBalloon": { "type": "Material" }, - "MoldugaFin": { "type": "Material" }, - "MoldugaGuts": { "type": "Material" }, - "HinoxToenail": { "type": "Material" }, - "HinoxTooth": { "type": "Material" }, - "HinoxGuts": { "type": "Material" }, - "Screw": { "type": "Material", "options": { "image": "AncientScrew" } }, - "Spring": { "type": "Material", "options": { "image": "AncientSpring" } }, - "AncientGear": { "type": "Material" }, - "Shaft": { "type": "Material", "options": { "image": "AncientShaft" } }, - "Core": { "type": "Material", "options": { "image": "AncientCore" } }, - "GiantAncientCore": { "type": "Material" }, - "Wood": { "type": "Material" }, - - "SimmeredFruit": { "type": "Food", "options": { "stackable": false } }, - "CopiousSimmeredFruit": { "type": "Food", "options": { "stackable": false } }, - "MushroomSkewer": { "type": "Food", "options": { "stackable": false } }, - "CopiousMushroomSkewers": { "type": "Food", "options": { "stackable": false } }, - "FriedWildGreens": { "type": "Food", "options": { "stackable": false } }, - "CopiousFriedWildGreens": { "type": "Food", "options": { "stackable": false } }, - "FishSkewer": { "type": "Food", "options": { "stackable": false } }, - "SeafoodSkewer": { "type": "Food", "options": { "stackable": false } }, - "CopiousSeafoodSkewers": { "type": "Food", "options": { "stackable": false } }, - "MeatSkewer": { "type": "Food", "options": { "stackable": false } }, - "CopiousMeatSkewers": { "type": "Food", "options": { "stackable": false } }, - "FruitAndMushroomMix": { "type": "Food", "options": { "stackable": false } }, - "FishAndMushroomSkewer": { "type": "Food", "options": { "stackable": false } }, - "MeatAndMushroomSkewer": { "type": "Food", "options": { "stackable": false } }, - "SteamedFruit": { "type": "Food", "options": { "stackable": false } }, - "SteamedMushrooms": { "type": "Food", "options": { "stackable": false } }, - "SteamedFish": { "type": "Food", "options": { "stackable": false } }, - "SteamedMeat": { "type": "Food", "options": { "stackable": false } }, - "SaltGrilledMushrooms": { "type": "Food", "options": { "stackable": false } }, - "SaltGrilledGreens": { "type": "Food", "options": { "stackable": false } }, - "SaltGrilledFish": { "type": "Food", "options": { "stackable": false } }, - "SaltGrilledCrab": { "type": "Food", "options": { "stackable": false } }, - "SaltGrilledMeat": { "type": "Food", "options": { "stackable": false } }, - "SaltGrilledPrimeMeat": { "type": "Food", "options": { "stackable": false } }, - "SaltGrilledGourmetMeat": { "type": "Food", "options": { "stackable": false } }, - "CrabStirFry": { "type": "Food", "options": { "stackable": false } }, - "PepperSeafood": { "type": "Food", "options": { "stackable": false } }, - "PepperSteak": { "type": "Food", "options": { "stackable": false } }, - "MeatAndSeafoodFry": { "type": "Food", "options": { "stackable": false } }, - "PrimeMeatAndSeafoodFry": { "type": "Food", "options": { "stackable": false } }, - "GourmetMeatAndSeafoodFry": { "type": "Food", "options": { "stackable": false } }, - "SpicedMeatSkewer": { "type": "Food", "options": { "stackable": false } }, - "PrimeSpicedMeatSkewer": { "type": "Food", "options": { "stackable": false } }, - "GourmetSpicedMeatSkewer": { "type": "Food", "options": { "stackable": false } }, - "FragrantMushroomSaute": { "type": "Food", "options": { "stackable": false } }, - "HerbSaute": { "type": "Food", "options": { "stackable": false } }, - "MeatStuffedPumpkin": { "type": "Food", "options": { "stackable": false } }, - "SauteedNuts": { "type": "Food", "options": { "stackable": false } }, - "SauteedPeppers": { "type": "Food", "options": { "stackable": false } }, - "Omelet": { "type": "Food", "options": { "stackable": false } }, - "GlazedMushrooms": { "type": "Food", "options": { "stackable": false } }, - "GlazedVeggies": { "type": "Food", "options": { "stackable": false } }, - "GlazedSeafood": { "type": "Food", "options": { "stackable": false } }, - "GlazedMeat": { "type": "Food", "options": { "stackable": false } }, - "SeafoodMeuniere": { "type": "Food", "options": { "stackable": false } }, - "PorgyMeuniere": { "type": "Food", "options": { "stackable": false } }, - "SalmonMeuniere": { "type": "Food", "options": { "stackable": false } }, - "SeafoodFriedRice": { "type": "Food", "options": { "stackable": false } }, - "CrabOmeletWithRice": { "type": "Food", "options": { "stackable": false } }, - "SeafoodPaella": { "type": "Food", "options": { "stackable": false } }, - "PoultryPilaf": { "type": "Food", "options": { "stackable": false } }, - "PrimePoultryPilaf": { "type": "Food", "options": { "stackable": false } }, - "GourmetPoultryPilaf": { "type": "Food", "options": { "stackable": false } }, - "CurryPilaf": { "type": "Food", "options": { "stackable": false } }, - "FriedEggAndRice": { "type": "Food", "options": { "stackable": false } }, - "MushroomRisotto": { "type": "Food", "options": { "stackable": false } }, - "VegetableRisotto": { "type": "Food", "options": { "stackable": false } }, - "SalmonRisotto": { "type": "Food", "options": { "stackable": false } }, - "CrabRisotto": { "type": "Food", "options": { "stackable": false } }, - "CreamOfVegetableSoup": { "type": "Food", "options": { "stackable": false } }, - "CreamOfMushroomSoup": { "type": "Food", "options": { "stackable": false } }, - "VeggieCreamSoup": { "type": "Food", "options": { "stackable": false } }, - "CreamyHeartSoup": { "type": "Food", "options": { "stackable": false } }, - "CreamySeafoodSoup": { "type": "Food", "options": { "stackable": false } }, - "CreamyMeatSoup": { "type": "Food", "options": { "stackable": false } }, - "MonsterSoup": { "type": "Food", "options": { "stackable": false } }, - "CarrotStew": { "type": "Food", "options": { "stackable": false } }, - "PumpkinStew": { "type": "Food", "options": { "stackable": false } }, - "ClamChowder": { "type": "Food", "options": { "stackable": false } }, - "MeatStew": { "type": "Food", "options": { "stackable": false } }, - "PrimeMeatStew": { "type": "Food", "options": { "stackable": false } }, - "GourmetMeatStew": { "type": "Food", "options": { "stackable": false } }, - "MonsterStew": { "type": "Food", "options": { "stackable": false } }, - "CurryRice": { "type": "Food", "options": { "stackable": false } }, - "VegetableCurry": { "type": "Food", "options": { "stackable": false } }, - "SeafoodCurry": { "type": "Food", "options": { "stackable": false } }, - "PoultryCurry": { "type": "Food", "options": { "stackable": false } }, - "PrimePoultryCurry": { "type": "Food", "options": { "stackable": false } }, - "GourmetPoultryCurry": { "type": "Food", "options": { "stackable": false } }, - "MeatCurry": { "type": "Food", "options": { "stackable": false } }, - "PrimeMeatCurry": { "type": "Food", "options": { "stackable": false } }, - "GourmetMeatCurry": { "type": "Food", "options": { "stackable": false } }, - "MonsterCurry": { "type": "Food", "options": { "stackable": false } }, - "MushroomOmelet": { "type": "Food", "options": { "stackable": false } }, - "VegetableOmelet": { "type": "Food", "options": { "stackable": false } }, - "MushroomRiceBalls": { "type": "Food", "options": { "stackable": false } }, - "VeggieRiceBalls": { "type": "Food", "options": { "stackable": false } }, - "SeafoodRiceBalls": { "type": "Food", "options": { "stackable": false } }, - "MeatyRiceBalls": { "type": "Food", "options": { "stackable": false } }, - "MonsterRiceBalls": { "type": "Food", "options": { "stackable": false } }, - "MeatAndRiceBowl": { "type": "Food", "options": { "stackable": false } }, - "PrimeMeatAndRiceBowl": { "type": "Food", "options": { "stackable": false } }, - "GourmetMeatAndRiceBowl": { "type": "Food", "options": { "stackable": false } }, - "WheatBread": { "type": "Food", "options": { "stackable": false } }, - "Nutcake": { "type": "Food", "options": { "stackable": false } }, - "Fruitcake": { "type": "Food", "options": { "stackable": false } }, - "CarrotCake": { "type": "Food", "options": { "stackable": false } }, - "PumpkinPie": { "type": "Food", "options": { "stackable": false } }, - "MonsterCake": { "type": "Food", "options": { "stackable": false } }, - "PlainCrepe": { "type": "Food", "options": { "stackable": false } }, - "WildberryCrepe": { "type": "Food", "options": { "stackable": false } }, - "HoneyCrepe": { "type": "Food", "options": { "stackable": false } }, - "FruitPie": { "type": "Food", "options": { "stackable": false } }, - "ApplePie": { "type": "Food", "options": { "stackable": false } }, - "FishPie": { "type": "Food", "options": { "stackable": false } }, - "MeatPie": { "type": "Food", "options": { "stackable": false } }, - "EggTart": { "type": "Food", "options": { "stackable": false } }, - "HoneyCandy": { "type": "Food", "options": { "stackable": false } }, - "HoneyedFruits": { "type": "Food", "options": { "stackable": false } }, - "HoneyedApple": { "type": "Food", "options": { "stackable": false } }, - "HotButteredApple": { "type": "Food", "options": { "stackable": false } }, - "FriedBananas": { "type": "Food", "options": { "stackable": false } }, - "EggPudding": { "type": "Food", "options": { "stackable": false } }, - "WarmMilk": { "type": "Food", "options": { "stackable": false } }, - "Elixir": { "type": "Food", "options": { "stackable": false } }, - "HeartyElixir": { "type": "Food", "options": { "stackable": false } }, - "EnergizingElixir": { "type": "Food", "options": { "stackable": false } }, - "EnduraFood": { "type": "Food", "options": { "image": "MushroomSkewer", "stackable": false } }, - "EnduringElixir": { "type": "Food", "options": { "stackable": false } }, - "SpeedFood": { "type": "Food", "options": { "image": "SteamedFruit", "stackable": false } }, - "HastyElixir": { "type": "Food", "options": { "stackable": false } }, - "FireproofElixir": { "type": "Food", "options": { "stackable": false } }, - "SpicyElixir": { "type": "Food", "options": { "stackable": false } }, - "ChillyElixir": { "type": "Food", "options": { "stackable": false } }, - "ElectroElixir": { "type": "Food", "options": { "stackable": false } }, - "MightyElixir": { "type": "Food", "options": { "stackable": false } }, - "ToughElixir": { "type": "Food", "options": { "stackable": false } }, - "SneakyElixir": { "type": "Food", "options": { "stackable": false } }, - "FairyTonic": { "type": "Food", "options": { "stackable": false } }, - "DubiousFood": { "type": "Food", "options": { "stackable": false } }, - "RockHardFood": { "type": "Food", "options": { "stackable": false } }, - "BakedApple": { "type": "Food" }, - "BakedPalmFruit": { "type": "Food" }, - "RoastedWildberry": { "type": "Food" }, - "RoastedAcorn": { "type": "Food" }, - "RoastedTreeNut": { "type": "Food" }, - "RoastedHeartyDurian": { "type": "Food" }, - "RoastedHydromelon": { "type": "Food" }, - "CharredPepper": { "type": "Food" }, - "RoastedVoltfruit": { "type": "Food" }, - "RoastedLotusSeeds": { "type": "Food" }, - "RoastedMightyBananas": { "type": "Food" }, - "ToastyHylianShroom": { "type": "Food" }, - "ToastyStamellaShroom": { "type": "Food" }, - "ToastyEnduraShroom": { "type": "Food" }, - "ToastedHeartyTruffle": { "type": "Food" }, - "ToastedBigHeartyTruffle": { "type": "Food" }, - "ToastyChillshroom": { "type": "Food" }, - "ToastySunshroom": { "type": "Food" }, - "ToastyZapshroom": { "type": "Food" }, - "ToastyRushroom": { "type": "Food" }, - "ToastyRazorshroom": { "type": "Food" }, - "ToastyIronshroom": { "type": "Food" }, - "ToastySilentShroom": { "type": "Food" }, - "RoastedRadish": { "type": "Food" }, - "RoastedBigRadish": { "type": "Food" }, - "RoastedSwiftCarrot": { "type": "Food" }, - "RoastedEnduraCarrot": { "type": "Food" }, - "BakedFortifiedPumpkin": { "type": "Food" }, - "RoastedMightyThistle": { "type": "Food" }, - "RoastedArmoranth": { "type": "Food" }, - "CampfireEgg": { "type": "Food" }, - "HardBoiledEgg": { "type": "Food" }, - "SearedSteak": { "type": "Food" }, - "SearedPrimeSteak": { "type": "Food" }, - "SearedGourmetSteak": { "type": "Food" }, - "RoastedBirdDrumstick": { "type": "Food" }, - "RoastedBirdThigh": { "type": "Food" }, - "RoastedWholeBird": { "type": "Food" }, - "RoastedBass": { "type": "Food" }, - "RoastedHeartyBass": { "type": "Food" }, - "RoastedHeartySalmon": { "type": "Food" }, - "RoastedTrout": { "type": "Food" }, - "RoastedCarp": { "type": "Food" }, - "RoastedPorgy": { "type": "Food" }, - "SneakyRiverEscargot": { "type": "Food" }, - "BlueshellEscargot": { "type": "Food" }, - "BlackenedCrab": { "type": "Food" }, - "IcyMeat": { "type": "Food" }, - "IcyPrimeMeat": { "type": "Food" }, - "IcyGourmetMeat": { "type": "Food" }, - "FrozenBirdDrumstick": { "type": "Food" }, - "FrozenBirdThigh": { "type": "Food" }, - "FrozenWholeBird": { "type": "Food" }, - "FrozenBass": { "type": "Food" }, - "FrozenHeartyBass": { "type": "Food" }, - "FrozenHeartySalmon": { "type": "Food" }, - "FrozenTrout": { "type": "Food" }, - "FrozenCarp": { "type": "Food" }, - "FrozenPorgy": { "type": "Food" }, - "FrozenCrab": { "type": "Food" }, - "FrozenRiverSnail": { "type": "Food" }, - "IcyHeartyBlueshellSnail": { "type": "Food" }, - - "Slate": { "type": "Key", "options": { "image": "SheikahSlate", "repeatable": false, "stackable": false } }, - "MiphasGrace": { "type": "Key", "options": { "repeatable": false, "stackable": false, "animated": true } }, - "RevalisGale": { "type": "Key", "options": { "repeatable": false, "stackable": false, "animated": true } }, - "DaruksProtection": { "type": "Key", "options": { "repeatable": false, "stackable": false, "animated": true } }, - "UrbosasFury": { "type": "Key", "options": { "repeatable": false, "stackable": false, "animated": true } }, - "MiphasGracePlus": { "type": "Key", "options": { "repeatable": false, "stackable": false, "animated": true } }, - "RevalisGalePlus": { "type": "Key", "options": { "repeatable": false, "stackable": false, "animated": true } }, - "DaruksProtectionPlus": { "type": "Key", "options": { "repeatable": false, "stackable": false, "animated": true } }, - "UrbosasFuryPlus": { "type": "Key", "options": { "repeatable": false, "stackable": false, "animated": true } }, - "Glider": { "type": "Key", "options": { "image": "Paraglider", "repeatable": false, "stackable": false } }, - "RutasEmblem": { "type": "Key", "options": { "animated": true } }, - "MedohsEmblem": { "type": "Key", "options": { "animated": true } }, - "RudaniasEmblem": { "type": "Key", "options": { "animated": true } }, - "NaborissEmblem": { "type": "Key", "options": { "animated": true } }, - "SpiritOrb": { "type": "Key", "options": { "animated": true } }, - "KorokSeed": { "type": "Key" }, - "HestusMaracas": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "ThunderHelmKeyItem": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "ClassifiedEnvelope": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "HestusGift": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "PictureOfTheChampions": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "MedalOfHonorTalus": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "MedalOfHonorHinox": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "MedalOfHonorMolduga": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "TravelersBridle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "KnightsBridle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "RoyalBridle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "ExtravagantBridle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "MonsterBridle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "AncientBridle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "TravelersSaddle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "KnightsSaddle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "RoyalSaddle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "ExtravagantSaddle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "MonsterSaddle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "AncientSaddle": { "type": "Key", "options": { "repeatable": false, "stackable": false } }, - "TravelMedallion": { "type": "Key", "options": { "repeatable": false, "stackable": false, "animated": true } } -} diff --git a/src/core/DisplayableInventory.ts b/src/core/DisplayableInventory.ts index 2a1add2..1d0e452 100644 --- a/src/core/DisplayableInventory.ts +++ b/src/core/DisplayableInventory.ts @@ -1,12 +1,17 @@ -import { ItemStack, itemToItemData, ItemType } from "./Item"; -import { getDisplayValue } from "./Localization"; +import { ItemStack, ItemType } from "data/item"; export type DisplayableSlot = { + // image to display image: string, - description: string, - count: number, - displayCount: boolean, + // localization key for description + descKey: string, + // count of stack + count?: number, + // durability of stack + durability?: string, + // if the stack is equipped isEquipped: boolean, + // if the slot is broken (i.e in the count offset region) isBrokenSlot: boolean, } @@ -14,14 +19,16 @@ export interface DisplayableInventory { getDisplayedSlots: (isIconAnimated: boolean)=>DisplayableSlot[] } -export const itemStackToDisplayableSlot = ({item, count, equipped}: ItemStack, isBrokenSlot: boolean, isIconAnimated: boolean): DisplayableSlot => { - const data = itemToItemData(item); +export const itemStackToDisplayableSlot = ({item, count, durability, equipped}: ItemStack, isBrokenSlot: boolean, isIconAnimated: boolean): DisplayableSlot => { + // for unstackable items (food/key items) display count if count > 1, even if it's unstackable + const shouldDisplayDurability = item.type === ItemType.Weapon || item.type === ItemType.Bow || item.type === ItemType.Shield; + const displayDurability = Number.isInteger(durability) ? durability + "" : durability.toPrecision(4); + const shouldDisplayCount = !shouldDisplayDurability && (item.stackable ? item.type === ItemType.Arrow || count > 0 : count > 1); return { - image: isIconAnimated ? data.animatedImage ?? data.image : data.image, - description: getDisplayValue(`description.${ItemType[data.type]}.${data.item}`, data.item), - // for unstackable items (food/key items) display count if count > 1, even if it's unstackable - displayCount: data.stackable ? data.type === ItemType.Arrow || count > 0 : count > 1, - count, + image: isIconAnimated ? item.animatedImage : item.image, + descKey: `items.${ItemType[item.type]}.${item.id}`, + count: shouldDisplayCount?count:undefined, + durability: shouldDisplayDurability?displayDurability:undefined, isEquipped: equipped, isBrokenSlot }; diff --git a/src/core/GameData.ts b/src/core/GameData.ts index 32c539f..e4fd05d 100644 --- a/src/core/GameData.ts +++ b/src/core/GameData.ts @@ -20,12 +20,12 @@ export class GameData implements DisplayableInventory { this.slots = pouch.getSlots().deepClone(); } - public updateDurability(durability: number, slot: number){ - this.slots.corrupt(durability, slot); + public updateLife(life: number, slot: number){ + this.slots.updateLife(life, slot); } public addAllToPouchOnReload(pouch: VisibleInventory) { - this.slots.getSlotsRef().forEach(stack=>pouch.addWhenReload(stack.item, stack.count, stack.equipped)); + this.slots.getSlotsRef().forEach(stack=>pouch.addWhenReload(stack)); } public getDisplayedSlots(isIconAnimated: boolean): DisplayableSlot[] { diff --git a/src/core/Item.ts b/src/core/Item.ts deleted file mode 100644 index 47a7a8b..0000000 --- a/src/core/Item.ts +++ /dev/null @@ -1,91 +0,0 @@ -import Images from "assets/img"; - -import itemDataJson from "config/items.json"; -type ItemDataObject = { type: string, options?: Partial }; -const itemMap = itemDataJson as Record; - -export enum ItemType { - Weapon = 0, - Bow = 1, - Arrow = 2, - Shield = 3, - Armor = 4, - Material = 5, - Food = 6, - Key = 7 -} - -export const ItemTypes = [ - ItemType.Weapon, - ItemType.Bow, - ItemType.Arrow, - ItemType.Shield, - ItemType.Armor, - ItemType.Material, - ItemType.Food, - ItemType.Key -]; - -export type ItemStack = { - item: string, - count: number, - equipped: boolean -} - -type ItemData = { - item: string, - image: string, - type: ItemType, - repeatable: boolean, - stackable: boolean, - animated: boolean - animatedImage?: string, - sortOrder: number, -} - -const ItemToData: Record = {}; -const TypeToCount = { - [ItemType.Weapon]: 0, - [ItemType.Bow]: 0, - [ItemType.Arrow]: 0, - [ItemType.Shield]: 0, - [ItemType.Armor]: 0, - [ItemType.Material]: 0, - [ItemType.Key]: 0, - [ItemType.Food]: 0, -}; -const register = (item: string, type: ItemType, options?: Partial) => { - const sortOrder = TypeToCount[type]; - TypeToCount[type]++; - const data: ItemData = { - item, - type, - repeatable: true, - stackable: true, - animated: false, - sortOrder, - ...options||{}, - // If defined, the "image" on the options object is actually an image key. Thus, we must resolve it after - // options are applied to override it with the correct value (falling back on item name if undefined) - animatedImage: options?.animated ? Images[`${ItemType[type]}/${options?.image ?? item}Animated`] : undefined, - image: Images[`${ItemType[type]}/${options?.image ?? item}`], - }; - ItemToData[item] = data; -}; - -for (const item in itemMap) { - const data: ItemDataObject = itemMap[item]; - register(item, ItemType[data.type as keyof typeof ItemType], data.options); -} - -export const itemToItemData = (item: string): ItemData => ItemToData[item] as ItemData; -export const itemExists = (item: string): boolean => !!itemToItemData(item); -export const itemToArrowType = (item: string): string => { - if(itemToItemData(item).type === ItemType.Arrow){ - const str = `${item}`; - return str.substring(0,str.length-5); - } - return ""; -}; - -export const getAllItems = (): string[] => Object.keys(ItemToData); diff --git a/src/core/Localization.ts b/src/core/Localization.ts index 2a57d74..dec026d 100644 --- a/src/core/Localization.ts +++ b/src/core/Localization.ts @@ -1,8 +1,17 @@ -// For now only en_US is supported, but it will be straightforward to add language options later -import display from "config/i18n/en_US.json"; -type LanguageMap = Record; -const displayMap = display as LanguageMap; +export {}; +// // For now only en_US is supported, but it will be straightforward to add language options later +// import display from "config/i18n/en_US.json"; -export const getDisplayValue = (displayKey: string, defaultValue?: string) => { - return displayMap[displayKey] ?? defaultValue ?? displayKey; -}; +// type LanguageMap = Record; +// const displayMap = display as LanguageMap; + +// // import("config/i18n/en_US.lang.yaml").then(langMap=>{ +// // console.log(langMap); +// // }); + +// // const test = "1234"+Math.random(); +// // import(test); + +// export const getDisplayValue = (displayKey: string, defaultValue?: string) => { +// return displayMap[displayKey] ?? defaultValue ?? displayKey; +// }; diff --git a/src/core/Parser.ts b/src/core/Parser.ts deleted file mode 100644 index e0ef663..0000000 --- a/src/core/Parser.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { - Command, - CommandAdd, - CommandAddMultiple, - CommandAddWithoutCount, - CommandBreakSlots, - CommandCloseGame, - CommandDaP, - CommandEquip, - CommandEventide, - CommandInitialize, - CommandNop, - CommandReload, - CommandRemove, - CommandRemoveMultiple, - CommandRemoveWithoutCount, - CommandSave, - CommandSaveAs, - CommandShootArrow, - CommandSortKey, - CommandSortMaterial, - CommandSync, - CommandUnequip, - CommandUse -} from "./Command"; -import { itemExists, ItemStack } from "./Item"; - -export const parseCommand = (cmdString: string): Command => { - - const tokens = cmdString.split(" ").filter(i=>i); - if(tokens.length===0){ - return new CommandNop(""); - } - // intialize - if(tokens.length>1 && tokens[0] === "Initialize"){ - const stacks = parseItemStacks(tokens, 1); - if(stacks){ - return new CommandInitialize(stacks); - } - } - // Save/Reload - if(tokens.length===1 && tokens[0] === "Save"){ - return new CommandSave(); - } - // Multi Save - if (tokens.length === 3 && tokens[0] === "Save" && tokens[1] === "As"){ - const name = tokens[2]; - return new CommandSaveAs(name); - } - if (tokens.length === 2 && tokens[0] === "Use"){ - const name = tokens[1]; - return new CommandUse(name); - } - if(tokens.length===1 && tokens[0] === "Reload"){ - return new CommandReload(); - } - if(tokens.length===2 && tokens[0] === "Reload"){ - return new CommandReload(tokens[1]); - } - // break - if (tokens.length > 2 && tokens[0] === "Break" && tokens[2]=== "Slots" ){ - const slots = parseInt(tokens[1]); - if(Number.isInteger(slots)){ - return new CommandBreakSlots(slots); - } - } - - // add material - if (tokens.length === 3 && isAddVerb(tokens[0])){ - const count = parseInt(tokens[1]); - const item = tokens[2]; - if(Number.isInteger(count) && itemExists(item)){ - return new CommandAdd(tokens[0], count, item); - } - } - if (tokens.length === 2 && isAddVerb(tokens[0])){ - const item = tokens[1]; - if (itemExists(item)){ - return new CommandAddWithoutCount(tokens[0], item); - } - } - if(tokens.length>2 && isAddVerb(tokens[0])){ - const stacks = parseItemStacks(tokens, 1); - if(stacks){ - return new CommandAddMultiple(tokens[0], stacks); - } - } - // remove X item From Slot Y - if (tokens.length === 6 && isRemoveVerb(tokens[0]) && tokens[3] === "From" && tokens[4] ==="Slot" ){ - const count = parseInt(tokens[1]); - const item = tokens[2]; - const slot = parseInt(tokens[5]); - if(Number.isInteger(count) && Number.isInteger(slot) && itemExists(item)){ - return new CommandRemove(tokens[0], count, item, slot-1, false); - } - } - // remove X item - if (tokens.length === 3 && isRemoveVerb(tokens[0]) ){ - const count = parseInt(tokens[1]); - const item = tokens[2]; - if(Number.isInteger(count) && itemExists(item)){ - return new CommandRemove(tokens[0], count, item, 0, true); - } - } - // remove item From Slot Y - if (tokens.length === 5 && isRemoveVerb(tokens[0]) && tokens[2] === "From" && tokens[3] ==="Slot" ){ - const item = tokens[1]; - const slot = parseInt(tokens[4]); - if(Number.isInteger(slot) && itemExists(item)){ - return new CommandRemoveWithoutCount(tokens[0], item, slot-1, false); - } - } - // remove item - if (tokens.length === 2 && isRemoveVerb(tokens[0]) ){ - const item = tokens[1]; - if (itemExists(item)){ - return new CommandRemoveWithoutCount(tokens[0], item, 0, true); - } - } - // remove multiple - if(tokens.length>2 && isRemoveVerb(tokens[0])){ - const stacks = parseItemStacks(tokens, 1); - if(stacks){ - return new CommandRemoveMultiple(tokens[0], stacks); - } - } - //Shortcut for drop and pick up - if (tokens.length >2 && tokens[0] === "D&P" ){ - const stacks = parseItemStacks(tokens, 1); - if(stacks){ - return new CommandDaP(stacks); - } - } - - // Equip item In Slot X - if (tokens.length === 5 && tokens[0] === "Equip" && tokens[2] === "In" && tokens[3] ==="Slot" ){ - const item = tokens[1]; - const slot = parseInt(tokens[4]); - if( Number.isInteger(slot) && itemExists(item)){ - return new CommandEquip(item, slot-1, false); - } - } - // Equip item - if (tokens.length === 2 && tokens[0] === "Equip"){ - const item = tokens[1]; - if (itemExists(item)){ - return new CommandEquip(item, 0, true); - } - } - // Unequip item in slot X - if (tokens.length === 5 && tokens[0] === "Unequip" && tokens[2] === "In" && tokens[3] ==="Slot" ){ - const item = tokens[1]; - const slot = parseInt(tokens[4]); - if( Number.isInteger(slot) && itemExists(item)){ - return new CommandUnequip(item, slot-1, false); - } - } - // Unequip item - if (tokens.length === 2 && tokens[0] === "Unequip"){ - const item = tokens[1]; - if (itemExists(item)){ - return new CommandUnequip(item, -1, true); - } - } - // Shoot X Arrow - if (tokens.length === 3 && tokens[0] === "Shoot" && tokens[2] === "Arrow"){ - const count = parseInt(tokens[1]); - if( Number.isInteger(count) ){ - return new CommandShootArrow(count); - } - } - - if(tokens.length===2 && tokens[0] === "Sort" && tokens[1] === "Key"){ - return new CommandSortKey(); - } - if(tokens.length===2 && tokens[0] === "Sort" && tokens[1] === "Material"){ - return new CommandSortMaterial(); - } - if(tokens.length===2 && tokens[0] === "Close" && tokens[1] === "Game"){ - return new CommandCloseGame(); - } - if(tokens.length===2 && tokens[0] === "Sync" && tokens[1] === "GameData"){ - return new CommandSync("Sync GameData"); - } - if(tokens.length===2 && (tokens[0] === "Enter" || tokens[0] === "Exit") && tokens[1] === "Eventide"){ - return new CommandEventide(tokens[0] === "Enter"); - } - - return new CommandNop(cmdString); -}; - -const isAddVerb = (token: string): boolean => { - return token === "Get" || token === "Cook" || token === "Add" || token === "Pickup" || token === "Buy"; -}; - -const isRemoveVerb = (token: string): boolean => { - return token === "Remove" || token === "Sell" || token === "Eat" || token === "Drop" || token === "With"; -}; - -const parseItemStacks = (tokens: string[], from: number): ItemStack[] | undefined => { - if((tokens.length-from)%2 !== 0){ - return undefined; - } - - const stacks: ItemStack[] = []; - for(let i=from;ithis.pouch.addDirectly(stack)); @@ -96,22 +109,22 @@ export class SimulationState { this.pouch.modifyCount(-n); } - public obtain(item: string, count: number) { - this.pouch.addInGame(item, count); + public obtain(stack: ItemStack) { + this.pouch.addInGame(stack); this.syncGameDataWithPouch(); } - public remove(item: string, count: number, slot: number) { - this.pouch.remove(item, count, slot); + public remove(stack: ItemStack, slot: number) { + this.pouch.remove(stack, slot); this.syncGameDataWithPouch(); } - public equip(item: string, slot: number) { + public equip(item: Item, slot: number) { this.pouch.equip(item, slot); this.syncGameDataWithPouch(); } - public unequip(item: string, slot: number){ + public unequip(item: Item, slot: number){ this.pouch.unequip(item, slot); this.syncGameDataWithPouch(); } @@ -121,6 +134,11 @@ export class SimulationState { // does not sync } + public setMetadata(item: Item, slot: number, meta: MetaOption) { + this.pouch.setMetadata(item, slot, meta); + this.syncGameDataWithPouch(); + } + public closeGame() { this.pouch = new VisibleInventory(new Slots([]), 0); this.gameData = new GameData(new Slots([])); @@ -149,6 +167,10 @@ export class SimulationState { } } + public shouldCrash(): boolean { + return this.pouch.getSlots().length > 420; + } + public get displayableGameData(): DisplayableInventory { return this.gameData; } @@ -161,6 +183,10 @@ export class SimulationState { return this.pouch.getCount(); } + public isCrashed(): boolean{ + return this.crashed; + } + public getManualSave(): GameData | null { return this.manualSave; } @@ -169,15 +195,4 @@ export class SimulationState { return this.namedSaves; } - // public get displayableGameData(): DisplayableInventory { - // return this.gameData; - // } - } - -// Shoot X Arrow, x can be ommited and default to 1 - -// Close Inventory, same as Resync GameData -// Enter Eventide / Leave Eventide -// Sort Key (In Tab X) - need more research on which tab is sorted. (might not be possible to select which tab to sort) -// Sort Material (In Tab X) - need more research on which tab is sorted diff --git a/src/core/Slots.add.test.ts b/src/core/Slots.add.test.ts new file mode 100644 index 0000000..ba81f32 --- /dev/null +++ b/src/core/Slots.add.test.ts @@ -0,0 +1,507 @@ +import { ItemStack, ItemType, createMaterialStack, createEquipmentStack } from "data/item"; +import { Slots } from "./Slots"; +import { createArrowMockItem, createEquipmentMockItem, createFoodMockItem, createKeyMockItem, createMaterialMockItem, equalsExceptEquip } from "./SlotsTestHelpers"; + +describe("Slots.add", ()=>{ + describe("sorted", ()=>{ + describe("reloading = true", ()=>{ + it("should add new stack when empty", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + + const stacks: ItemStack[] = []; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [stackToAdd.modify({})]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add new stack when non empty", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + const mockItem2 = createMaterialMockItem("MaterialB"); + const alreadyHaveStack = createMaterialStack(mockItem2, 1); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack, stackToAdd.modify({})]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add new stack when same type is present", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + const alreadyHaveStack = createMaterialStack(mockItem1, 1); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack, stackToAdd.modify({})]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add new stack when same type is present, =998", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 598); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack, stackToAdd.modify({})]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add new stack when same type is present, =999", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 599); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack, stackToAdd.modify({})]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add multiple new stacks when same type is present, =999", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 599); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + let added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack, stackToAdd]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + added = slots.add(stackToAdd, true, null); + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks([alreadyHaveStack, stackToAdd, stackToAdd]); + + }); + it("should NOT add new stack when same type is present, >999", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 600); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack]; + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add new stack when same type is present but unstackable, >999", ()=>{ + const mockItem1 = createFoodMockItem("FoodA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 600); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack, stackToAdd]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should NOT add new stack when same type is present and not repeatable", ()=>{ + const mockItem1 = createKeyMockItem("KeyA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + const alreadyHaveStack = createMaterialStack(mockItem1, 1); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack]; + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should NOT add new arrow when same arrow is present, >999", ()=>{ + const mockItem1 = createArrowMockItem("ArrowA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 600); + const stacks: ItemStack[] = [alreadyHaveStack]; + + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack]; + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add new >999 arrow when no arrow is present", ()=>{ + const mockItem1 = createArrowMockItem("ArrowA"); + const stackToAdd = createMaterialStack(mockItem1, 99999); + const stacks: ItemStack[] = []; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [stackToAdd]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add new >999 arrow when different arrow is present", ()=>{ + const mockItem1 = createArrowMockItem("ArrowA"); + const stackToAdd = createMaterialStack(mockItem1, 99999); + const mockItem2 = createArrowMockItem("ArrowB"); + const alreadyHaveStack = createMaterialStack(mockItem2, 600); + + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, true, null); + const expected = [alreadyHaveStack,stackToAdd]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should not auto equip weapon/bow/shield", ()=>{ + const mockItem1 = createEquipmentMockItem("WeaponA", ItemType.Weapon); + const mockItem2 = createEquipmentMockItem("BowA", ItemType.Bow); + const mockItem3 = createEquipmentMockItem("ShieldA", ItemType.Shield); + const stackToAdd1 = createEquipmentStack(mockItem1, 1, false); + const stackToAdd2 = createEquipmentStack(mockItem2, 1, false); + const stackToAdd3 = createEquipmentStack(mockItem3, 1, false); + const stacks: ItemStack[] = []; + const slots = new Slots(stacks); + + let added = slots.add(stackToAdd1, true, null); + expect(added).toBe(1); + added = slots.add(stackToAdd2, true, null); + expect(added).toBe(1); + added = slots.add(stackToAdd3, true, null); + expect(added).toBe(1); + const expected = [stackToAdd1,stackToAdd2,stackToAdd3]; + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + }); + describe("reloading = false", ()=>{ + it("should add new stack when empty", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + + const stacks: ItemStack[] = []; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [stackToAdd.modify({})]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add new stack when non empty", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + const mockItem2 = createMaterialMockItem("MaterialB"); + const alreadyHaveStack = createMaterialStack(mockItem2, 1); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [alreadyHaveStack, stackToAdd.modify({})]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should merge with existing when same type is present", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + const alreadyHaveStack = createMaterialStack(mockItem1, 1); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [alreadyHaveStack.modify({count: 2})]; + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should merge with existing same type is present, =998", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 598); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [alreadyHaveStack.modify({count: 998})]; + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should merge with existing same type is present, =999", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 599); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [alreadyHaveStack.modify({count: 999})]; + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should cap at 999 when same type is present, >999", ()=>{ + const mockItem1 = createMaterialMockItem("MaterialA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 600); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [alreadyHaveStack.modify({count: 999})]; + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should add new stack when same type is present but unstackable, >999", ()=>{ + const mockItem1 = createFoodMockItem("FoodA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 600); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [alreadyHaveStack, stackToAdd]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should NOT add new stack when same type is present and not repeatable", ()=>{ + const mockItem1 = createKeyMockItem("KeyA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + const alreadyHaveStack = createMaterialStack(mockItem1, 1); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [alreadyHaveStack]; + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should cap new arrow at 999 when same arrow is present", ()=>{ + const mockItem1 = createArrowMockItem("ArrowA"); + const stackToAdd = createMaterialStack(mockItem1, 400); + const alreadyHaveStack = createMaterialStack(mockItem1, 600); + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [alreadyHaveStack.modify({count: 999})]; + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks(expected, equalsExceptEquip); + }); + it("should add new >999 arrow when no arrow is present", ()=>{ + const mockItem1 = createArrowMockItem("ArrowA"); + const stackToAdd = createMaterialStack(mockItem1, 99999); + const stacks: ItemStack[] = []; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [stackToAdd]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected, equalsExceptEquip); + }); + it("should add new >999 arrow when different arrow is present", ()=>{ + const mockItem1 = createArrowMockItem("ArrowA"); + const stackToAdd = createMaterialStack(mockItem1, 99999); + const mockItem2 = createArrowMockItem("ArrowB"); + const alreadyHaveStack = createMaterialStack(mockItem2, 600); + + const stacks: ItemStack[] = [alreadyHaveStack]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [alreadyHaveStack,stackToAdd]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected, equalsExceptEquip); + }); + it("should auto equip weapon/bow/shield when none is there", ()=>{ + const mockItem1 = createEquipmentMockItem("WeaponA", ItemType.Weapon); + const mockItem2 = createEquipmentMockItem("BowA", ItemType.Bow); + const mockItem3 = createEquipmentMockItem("ShieldA", ItemType.Shield); + const stackToAdd1 = createEquipmentStack(mockItem1, 1, false); + const stackToAdd2 = createEquipmentStack(mockItem2, 1, false); + const stackToAdd3 = createEquipmentStack(mockItem3, 1, false); + const stacks: ItemStack[] = []; + const slots = new Slots(stacks); + + let added = slots.add(stackToAdd1, false, null); + expect(added).toBe(1); + added = slots.add(stackToAdd2, false, null); + expect(added).toBe(1); + added = slots.add(stackToAdd3, false, null); + expect(added).toBe(1); + const expected = [stackToAdd1.modify({equipped:true}),stackToAdd2.modify({equipped:true}),stackToAdd3.modify({equipped:true})]; + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should auto equip weapon/bow/shield when none is equipped", ()=>{ + const mockItem1 = createEquipmentMockItem("WeaponA", ItemType.Weapon); + const mockItem2 = createEquipmentMockItem("BowA", ItemType.Bow); + const mockItem3 = createEquipmentMockItem("ShieldA", ItemType.Shield); + const stackToAdd1 = createEquipmentStack(mockItem1, 1, false); + const stackToAdd2 = createEquipmentStack(mockItem2, 1, false); + const stackToAdd3 = createEquipmentStack(mockItem3, 1, false); + const existing1 = createEquipmentStack(mockItem1, 1, false); + const existing2 = createEquipmentStack(mockItem2, 1, false); + const existing3 = createEquipmentStack(mockItem3, 1, false); + const stacks: ItemStack[] = [existing1,existing2,existing3]; + const slots = new Slots(stacks); + + let added = slots.add(stackToAdd1, false, null); + expect(added).toBe(1); + added = slots.add(stackToAdd2, false, null); + expect(added).toBe(1); + added = slots.add(stackToAdd3, false, null); + expect(added).toBe(1); + const expected = [existing1,stackToAdd1.modify({equipped:true}),existing2,stackToAdd2.modify({equipped:true}),existing3,stackToAdd3.modify({equipped:true})]; + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should auto equip arrow if none is there", ()=>{ + const mockItem1 = createArrowMockItem("ArrowA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + + const stacks: ItemStack[] = []; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [stackToAdd.modify({equipped:true})]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + it("should auto equip arrow if current equipped is 0", ()=>{ + const mockItem1 = createArrowMockItem("ArrowA"); + const stackToAdd = createMaterialStack(mockItem1, 1); + const mockItem2 = createArrowMockItem("ArrowB"); + const existing = createMaterialStack(mockItem2, 0).modify({equipped: true}); + + const stacks: ItemStack[] = [existing]; + const slots = new Slots(stacks); + + const added = slots.add(stackToAdd, false, null); + const expected = [existing.modify({equipped:false}), stackToAdd.modify({equipped:true})]; + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks(expected); + }); + }); + }); + describe("unsorted", ()=>{ + describe("reloading = true", ()=>{ + it("should not sort when mCount is 0 or 1", ()=>{ + const mockItem1 = createKeyMockItem("KeyA"); + const mockItem2 = createMaterialMockItem("ItemA"); + const mockItem3 = createKeyMockItem("KeyB"); + const existing = createMaterialStack(mockItem1, 1); + const stackToAdd1 = createMaterialStack(mockItem2, 1); + const stackToAdd2 = createMaterialStack(mockItem3, 1); + const stacks: ItemStack[] = [existing]; + const slots = new Slots(stacks); + let added = slots.add(stackToAdd1, true, -1); // 0 now + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks([existing, stackToAdd1]); + added = slots.add(stackToAdd2, true, 0); // 1 now + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks([existing, stackToAdd1, stackToAdd2]); + added = slots.add(stackToAdd1, true, 1); // 2 now, sort + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks([stackToAdd1, stackToAdd1, existing, stackToAdd2]); + }); + it("should add unrepeatable if not in first tab", ()=>{ + const mockItem1 = createKeyMockItem("KeyA"); + const mockItem2 = createMaterialMockItem("ItemA"); + const mockItem3 = createKeyMockItem("KeyB"); + const existing1 = createMaterialStack(mockItem1, 1); + const existing2 = createMaterialStack(mockItem2, 1); + const existing3 = createMaterialStack(mockItem3, 1); + const stacks: ItemStack[] = [ + existing1, + existing2, + existing3 + ]; + const slots = new Slots(stacks); + const added = slots.add(existing3, true, null); + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks([existing2, existing1, existing3, existing3]); // sorted + + }); + it("should skip arrow 999 check for [bow, shield, arrow]", ()=>{ + const mockItem1 = createEquipmentMockItem("BowA", ItemType.Bow); + const mockItem2 = createEquipmentMockItem("ShieldA", ItemType.Shield); + const mockItem3 = createArrowMockItem("ArrowA"); + const existing1 = createEquipmentStack(mockItem1, 1, true); + const existing2 = createEquipmentStack(mockItem2, 1, true); + const existing3 = createMaterialStack(mockItem3, 1); + const stacks: ItemStack[] = [ + existing1, + existing2, + existing3 + ]; + const toAdd = createMaterialStack(mockItem3, 999); + const slots = new Slots(stacks); + const added = slots.add(toAdd, true, null); + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks([existing1, existing3, toAdd, existing2]); // sorted + }); + it("should NOT skip arrow 999 check for [bow, weapon, arrow]", ()=>{ + const mockItem1 = createEquipmentMockItem("BowA", ItemType.Bow); + const mockItem2 = createEquipmentMockItem("WeaponA", ItemType.Weapon); + const mockItem3 = createArrowMockItem("ArrowA"); + const existing1 = createEquipmentStack(mockItem1, 1, true); + const existing2 = createEquipmentStack(mockItem2, 1, true); + const existing3 = createMaterialStack(mockItem3, 1); + const stacks: ItemStack[] = [ + existing1, + existing2, + existing3 + ]; + const toAdd = createMaterialStack(mockItem3, 999); + const slots = new Slots(stacks); + const added = slots.add(toAdd, true, null); + expect(added).toBe(0); + expect(slots.getSlotsRef()).toEqualItemStacks([existing1, existing2, existing3]); // not sorted + }); + it("should skip arrow 999 check for [bow, weapon, arrow] if mCount = 0", ()=>{ + const mockItem1 = createEquipmentMockItem("BowA", ItemType.Bow); + const mockItem2 = createEquipmentMockItem("WeaponA", ItemType.Weapon); + const mockItem3 = createArrowMockItem("ArrowA"); + const existing1 = createEquipmentStack(mockItem1, 1, true); + const existing2 = createEquipmentStack(mockItem2, 1, true); + const existing3 = createMaterialStack(mockItem3, 1); + const stacks: ItemStack[] = [ + existing1, + existing2, + existing3 + ]; + const toAdd = createMaterialStack(mockItem3, 999); + const slots = new Slots(stacks); + const added = slots.add(toAdd, true, 0); + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks([existing1, existing2, existing3, toAdd]); // not sorted + }); + it("should skip arrow 999 check for [shield, arrow]", ()=>{ + const mockItem2 = createEquipmentMockItem("ShieldA", ItemType.Shield); + const mockItem3 = createArrowMockItem("ArrowA"); + const existing2 = createEquipmentStack(mockItem2, 1, true); + const existing3 = createMaterialStack(mockItem3, 1); + const stacks: ItemStack[] = [ + existing2, + existing3 + ]; + const toAdd = createMaterialStack(mockItem3, 999); + const slots = new Slots(stacks); + const added = slots.add(toAdd, true, null); + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks([existing3, toAdd, existing2]); // sorted + }); + it("should add unrepeatable if mCount = 0", ()=>{ + const mockItem1 = createKeyMockItem("KeyA"); + const mockItem2 = createMaterialMockItem("ItemA"); + const existing1 = createMaterialStack(mockItem1, 1); + const existing2 = createMaterialStack(mockItem2, 1); + const stacks: ItemStack[] = [ + existing1, + existing2, + ]; + const slots = new Slots(stacks); + const added = slots.add(existing1, true, 0); + expect(added).toBe(1); + expect(slots.getSlotsRef()).toEqualItemStacks([existing1, existing2, existing1]); // not sorted + }); + }); + }); +}); diff --git a/src/core/Slots.ts b/src/core/Slots.ts index 8f0eebd..f8bb96c 100644 --- a/src/core/Slots.ts +++ b/src/core/Slots.ts @@ -1,8 +1,11 @@ -import { stableSort } from "data/mergeSort"; -import { ItemStack, itemToItemData, ItemType } from "./Item"; +import { stableSort } from "data/stableSort"; +import { getTabFromType, Item, ItemStack, ItemTab, ItemType, iterateItemTabs, MetaOption } from "data/item"; /* * This is the data model common to GameData and VisibleInventory + * All branches in public interface should have comment with [confirmed] or [need confirm] indicating whether something is confirmed to be the same in game + * cases tagged with [confirmed] must also have unit tests covering them + * make sure to add unit tests when changing from [needs confirm] to [confirmed] */ export class Slots { private internalSlots: ItemStack[] = []; @@ -13,15 +16,18 @@ export class Slots { return this.internalSlots; } public deepClone(): Slots { - return new Slots(this.internalSlots.map(s=>({...s}))); + // ItemStack is immutable so they do not need to be copied + return new Slots([...this.internalSlots]); } + public get length(): number { return this.internalSlots.length; } // Sort the item types as they appear in game. Arrows are also sorted amongst each other + // Individual tabs are not sorted // input mCount = null will skip the optimization. Otherwise if mCount <= 1, do nothing - public sortItemType(mCount: number | null) { + public sortItemByTab(mCount: number | null) { if(mCount === null){ mCount = this.internalSlots.length; } @@ -29,12 +35,17 @@ export class Slots { return; } stableSort(this.internalSlots, (a,b)=>{ - const aData = itemToItemData(a.item); - const bData = itemToItemData(b.item); - if(aData.type === ItemType.Arrow && bData.type === ItemType.Arrow){ - return aData.sortOrder - bData.sortOrder; + //const aData = itemToItemData(a.item); + //const bData = itemToItemData(b.item); + if(a.item.type === ItemType.Arrow && b.item.type === ItemType.Arrow){ + return a.item.sortOrder - b.item.sortOrder; } - return aData.type - bData.type; + if(a.item.tab === b.item.tab && a.item.tab === ItemTab.Bow){ + // arrows are always after bow + return a.item.type - b.item.type; + } + // otherwise sort by tab + return a.item.tab - b.item.tab; }); } @@ -43,178 +54,216 @@ export class Slots { } public addStackDirectly(stack: ItemStack): number { - const data = itemToItemData(stack.item); - if(data.stackable){ - this.internalSlots.push({...stack}); - return 1; - } - for(let i=0;i 0;i++){ - if(this.internalSlots[i].item === item){ + const stack = this.internalSlots[i]; + if(stack.canStack(toRemove)){ + found = true; if(scount>0); + if(!found){ + for(let i = 0; i 0;i++){ + const stack = this.internalSlots[i]; + if(stack.item === toRemove.item){ + found = true; + if(s{ + return item.type === ItemType.Arrow || count > 0; + }); + } + // Add something to inventory in game // returns number of slots added - public add(item: string, count: number, equippedDuringReload: boolean, reloading: boolean, mCount: number | null): number { + public add(stack: ItemStack, reloading: boolean, mCount: number | null): number { if(mCount === null){ mCount = this.internalSlots.length; } - //let added = false; - const data = itemToItemData(item); - // If item is stackable (arrow, material, spirit orbs) - // Check if there's already a slot, if so, add it to that and cap it at 999 - if(data.stackable){ - for(let i = 0; i 999){ - // do not add new stack during loading save, if it would exceed 999 - return 0; - } - // Otherwise add the stack directly - this.addSlot({item, count, equipped: equippedDuringReload}, mCount+1); - return 1; - } - this.internalSlots[i].count = Math.min(999, this.internalSlots[i].count+count); - return 0; + + // If item is stackable (arrow, material, spirit orbs), do 999 Cap Check + // [confirmed] the 999 cap check always happens, even when mCount = 0 + // https://discord.com/channels/269611402854006785/269616041435332608/997404941754839060 + if(stack.item.stackable){ + let shouldCapAt999 = true; + // [confirmed] kinak: for arrow, if there's "no arrow", 999 check is skipped + if(stack.item.type === ItemType.Arrow){ + // [needs confirm] index will be -1 if mCount is 0, since we won't find any tabs, so arrow check is skipped regardless + const firstArrowIndex = this.findFirstTabIndex(ItemType.Arrow, mCount); + if(firstArrowIndex === -1){ + shouldCapAt999 = false; } } - } - // Need to add new slot - // Key item check: if the key item or master sword already exists in the first tab, do not add - if(mCount != 0){ - if(data.type === ItemType.Key || item === "MasterSword") { - let i=0; - while(i 999){ + // [confirmed] do not add new stack during loading save, if it would exceed 999 + return 0; + } + } + }else{ + // [needs confirm] if not reloading, cap the slot at 999 + const newCount = Math.min(999, this.internalSlots[i].count+stack.count); + if(newCount != this.internalSlots[i].count){ + this.internalSlots[i] = this.internalSlots[i].modify({count: newCount}); + } + + return 0; + } + } - for(;i{ - const sData = itemToItemData(s.item); - return sData.type === data.type && s.equipped && s.count > 0; - }).length === 0; - this.addSlot({item,count,equipped:shouldEquipNew}, mCount+1); - }else{ - this.addSlot({item,count,equipped:false}, mCount+1); + + // Auto equip check + if(!reloading){ + if(stack.item.type===ItemType.Weapon || stack.item.type===ItemType.Bow || stack.item.type===ItemType.Shield || stack.item.type === ItemType.Arrow){ + // [needs confirm] does auto equip check check entire inventory or only first tab? (for now, entire inventory) + // [needs confirm] does this check happen for count = 0 ? (or just equip by force) + // check if none of that type is equipped + const equippedItems = this.internalSlots.filter(s=> + s.item.type === stack.item.type && s.equipped + ); + let shouldEquipNew = equippedItems.length === 0; + if(!shouldEquipNew && stack.item.type === ItemType.Arrow){ + shouldEquipNew = equippedItems.filter(s=> + s.count > 0 + ).length === 0; + } + if(shouldEquipNew){ + stack = stack.modify({equipped: true}); + if(stack.item.type === ItemType.Arrow){ + // unequip other arrows + // [needs confirm] only first tab? + let i = this.findFirstTabIndex(ItemType.Arrow, mCount); + if(i!==-1){ + for(;i{ - const sData = itemToItemData(s.item); - return sData.type === data.type && s.equipped; - }).length === 0; - this.addSlot({item,count:1,equipped: shouldEquipNew}, mCount+1); - for(let i=1;i= this.internalSlots.length){ return; } - const thisData = itemToItemData(this.internalSlots[slot].item); - // Currently only supports corrupting arrows, material, food and key items as durability values are not simulated on equipments - if(thisData.type >= ItemType.Material || thisData.stackable){ - this.internalSlots[slot].count = durability; + if(this.internalSlots[slot].item.stackable && this.internalSlots[slot].item.type !== ItemType.Arrow){ + life = Math.min(999, life); } + //const thisData = itemToItemData(this.internalSlots[slot].item); + // Currently only supports corrupting arrows, material, food and key items as durability values are not simulated on equipments + //if(this.internalSlots[slot].item.type >= ItemType.Material || this.internalSlots[slot].item.stackable){ + //const newLife = Math.min(999, life); + this.modifySlot(slot, {count: life}); + //} } // shoot count arrows. return the slot that was updated, or -1 @@ -238,14 +291,14 @@ export class Slots { // first find equipped arrow, search entire inventory // this is the last equipped arrow before armor let i=0; - let equippedArrow: string | undefined = undefined; + let equippedArrow: Item | undefined = undefined; + // [needs confirm] does this check entire inventory? for(;i ItemType.Shield){ + if(this.internalSlots[i].item.type > ItemType.Shield){ break; } - if(this.internalSlots[i].equipped && data.type === ItemType.Arrow){ - equippedArrow = data.item; + if(this.internalSlots[i].equipped && this.internalSlots[i].item.type === ItemType.Arrow){ + equippedArrow = this.internalSlots[i].item; } } if(i>=this.internalSlots.length){ @@ -255,7 +308,7 @@ export class Slots { // now find the first slot of that arrow and update for(let j=0;jitemToItemData(stack.item).type === ItemType.Key); + const newslots = this.internalSlots.filter(stack=>stack.item.type === ItemType.Key); const removedCount = this.internalSlots.length - newslots.length; this.internalSlots = newslots; return removedCount; } + public findFirstTabIndex(type: ItemType, mCount: number): number { + // figure out the tabs first + const tabArray: [ItemTab, number][] = []; + const tabAdded = new Set(); + if(mCount !== 0){ + // scan inventory array for tabs + let lastTab = ItemTab.None; + for(let i =0;it{ + if(!tabAdded.has(t) && this.isTabDiscovered(t)){ + tabArray.push([t, -1]); + tabAdded.add(t); + } + }); + // add new tab + tabArray.push([currentItemTab, i]); + tabAdded.add(currentItemTab); + lastTab = currentItemTab; + } + } + }else{ + // just add discovered tabs + iterateItemTabs().forEach(t=>{ + if(this.isTabDiscovered(t)){ + tabArray.push([t, -1]); + } + }); + } + + // first first tab of that type + // if type is arrow, find the first arrow in that tab + const tabToFind = getTabFromType(type); + let foundTabItemIndex = -1; + for(let i =0;i ItemType.Arrow){ + // arrow not found + return -1; + } + if(this.internalSlots[foundTabItemIndex].item.type === ItemType.Arrow){ + return foundTabItemIndex; + } + } + } + return foundTabItemIndex; + } + + isTabDiscovered(_tab: ItemTab): boolean { + // [confirmed] kinak: tabs are different when a tab is discovered vs not + // https://discord.com/channels/269611402854006785/269616041435332608/997547358206300231 + // for now we assume tabs are always already discovered + return true; + } + + modifySlot(i: number, option: Partial) { + this.internalSlots[i] = this.internalSlots[i].modify(option); + } + } diff --git a/src/core/SlotsTestHelpers.ts b/src/core/SlotsTestHelpers.ts new file mode 100644 index 0000000..7baec21 --- /dev/null +++ b/src/core/SlotsTestHelpers.ts @@ -0,0 +1,32 @@ +import { createMaterialStack, getTabFromType, Item, ItemStack, ItemTab, ItemType } from "data/item"; + +class MockItem implements Item { + id: string; + type: ItemType; + repeatable: boolean; + stackable: boolean; + sortOrder = -1; + get tab(): ItemTab { + return getTabFromType(this.type); + } + image = ""; + animatedImage= ""; + constructor(id: string, type: ItemType, stackable: boolean, repeatable: boolean){ + this.id = id; + this.type = type; + this.stackable = stackable; + this.repeatable = repeatable; + } + createDefaultStack(): ItemStack { + return createMaterialStack(this, 1); + } + +} + +export const createArrowMockItem = (id: string): Item => new MockItem(id, ItemType.Arrow, true, true); +export const createMaterialMockItem = (id: string): Item => new MockItem(id, ItemType.Material, true, true); +export const createFoodMockItem = (id: string): Item => new MockItem(id, ItemType.Food, false, true); +export const createKeyMockItem = (id: string): Item => new MockItem(id, ItemType.Key, false, false); +export const createEquipmentMockItem = (id: string, type: ItemType): Item => new MockItem(id, type, false, true); + +export const equalsExceptEquip = (a: ItemStack, b: ItemStack): boolean => a.equalsExceptForEquipped(b); diff --git a/src/core/VisibleInventory.ts b/src/core/VisibleInventory.ts index 988ed7a..ab14596 100644 --- a/src/core/VisibleInventory.ts +++ b/src/core/VisibleInventory.ts @@ -1,7 +1,7 @@ import { DisplayableInventory, DisplayableSlot, itemStackToDisplayableSlot } from "./DisplayableInventory"; import { GameData } from "./GameData"; -import { ItemStack, itemToItemData, ItemType } from "./Item"; import { Slots } from "./Slots"; +import { Item, ItemStack, ItemType, MetaOption } from "data/item"; /* * Implementation of Visible Inventory (PauseMenuDataMgr) in botw @@ -31,26 +31,26 @@ export class VisibleInventory implements DisplayableInventory{ this.count+=this.slots.addStackDirectly(stack); } - public addWhenReload(item: string, count: number, equippedDuringReload: boolean) { - const slotsAdded = this.slots.add(item, count, equippedDuringReload, true, this.count); + public addWhenReload(stack: ItemStack) { + const slotsAdded = this.slots.add(stack, true, this.count); this.count+=slotsAdded; } - public addInGame(item: string, count: number) { - const slotsAdded = this.slots.add(item, count, false, false, this.count); + public addInGame(stack: ItemStack) { + const slotsAdded = this.slots.add(stack, false, this.count); this.count+=slotsAdded; } - public remove(item: string, count: number, slot: number) { - const slotsRemoved = this.slots.remove(item, count, slot); + public remove(stack: ItemStack, slot: number) { + const slotsRemoved = this.slots.remove(stack, slot); this.count-=slotsRemoved; } - public equip(item: string, slot: number) { - this.slots.equip(item, slot); + public equip(item: Item, slot: number) { + this.slots.equip(item, slot, this.count); } - public unequip(item: string, slot: number) { + public unequip(item: Item, slot: number) { this.slots.unequip(item, slot); } @@ -67,19 +67,19 @@ export class VisibleInventory implements DisplayableInventory{ let foundWeapon = false; let foundBow = false; let foundShield = false; - this.slots.getSlotsRef().forEach(({item, equipped}, i)=>{ + this.slots.getSlotsRef().forEach(({item, count, equipped}, i)=>{ if(equipped){ - const type = itemToItemData(item).type; + const type = item.type; if(type === ItemType.Weapon && !foundWeapon){ - gameData.updateDurability(999, i); + gameData.updateLife(count, i); foundWeapon = true; } if(type === ItemType.Bow && !foundBow){ - gameData.updateDurability(999, i); + gameData.updateLife(count, i); foundBow = true; } if(type === ItemType.Shield && !foundShield){ - gameData.updateDurability(999, i); + gameData.updateLife(count, i); foundShield = true; } } @@ -90,10 +90,14 @@ export class VisibleInventory implements DisplayableInventory{ const updatedSlot = this.slots.shootArrow(count); if(updatedSlot>=0){ const durability = this.slots.getSlotsRef()[updatedSlot].count; - gameData.updateDurability(durability, updatedSlot); + gameData.updateLife(durability, updatedSlot); } } + public setMetadata(item: Item, slot: number, meta: MetaOption) { + this.slots.setMetadata(item, slot, meta); + } + public getCount(): number { return this.count; } diff --git a/src/core/command/CommandHint.ts b/src/core/command/CommandHint.ts new file mode 100644 index 0000000..3431b15 --- /dev/null +++ b/src/core/command/CommandHint.ts @@ -0,0 +1,49 @@ +import { isAddVerb, isRemoveVerb } from "./helper"; +import { CommandImpl } from "./type"; + +export class CommandHint extends CommandImpl { + private keyword: string; + constructor(keyword: string){ + super(); + this.keyword = keyword; + } + public getError(): string { + switch(this.keyword){ + case "initialize": + return "Initialize X item1[meta] Y item2[meta] Z item3[meta] ..."; + case "save": + return "Save (As )"; + case "reload": + return "Reload ()"; + case "break": + return "Break X Slots"; + case "d&p": + case "dnp": + case "dap": + return "D&P X item1[meta] Y item2[meta] Z item3[meta] ..."; + case "equip": + return "Equip item (In Slot X)"; + case "unequip": + return "Unequip item (In Slot X)"; + case "shoot": + return "Shoot X Arrow"; + case "close": + return "\"Close Game\"?"; + case "exit": + return "Exit Game|TOTS|Eventide"; + case "sync": + return "\"Sync GameData\"?"; + case "enter": + return "Enter TOTS|Eventide"; + case "sort": + return "Sorting is currently not supported"; + } + if(isAddVerb(this.keyword)){ + return "Add item, Add X item1[meta] Y item2[meta] Z item3[meta] ..."; + } + if(isRemoveVerb(this.keyword)){ + return "Remove item (From Slot X), Remove X item (From Slot Y), Remove X item1[meta] Y item2[meta] Z item3[meta] ..."; + } + return "Unknown Command"; + } +} diff --git a/src/core/command/CommandWrite.ts b/src/core/command/CommandWrite.ts new file mode 100644 index 0000000..7f813f8 --- /dev/null +++ b/src/core/command/CommandWrite.ts @@ -0,0 +1,19 @@ +import { SimulationState } from "core/SimulationState"; +import { Item, MetaOption } from "data/item"; +import { CommandImpl } from "./type"; + +export class CommandWrite extends CommandImpl { + private itemTarget: Item; + private slot: number; + private meta: MetaOption; + constructor(item: Item, slot: number, meta: MetaOption) { + super(); + this.itemTarget = item; + this.slot = slot; + this.meta = meta; + } + + execute(state: SimulationState): void { + return state.setMetadata(this.itemTarget, this.slot, this.meta); + } +} diff --git a/src/core/Command.ts b/src/core/command/Commands.ts similarity index 54% rename from src/core/Command.ts rename to src/core/command/Commands.ts index 08cd232..56cffff 100644 --- a/src/core/Command.ts +++ b/src/core/command/Commands.ts @@ -1,34 +1,19 @@ -import { ItemStack } from "./Item"; -import { SimulationState } from "./SimulationState"; - -export interface Command { - isValid(): boolean, - execute(state: SimulationState): void, - getDisplayString(): string, -} - -class CommandImpl implements Command{ - isValid(): boolean { - return true; - } - execute(_state: SimulationState): void { - // nothing - } - getDisplayString(): string { - throw new Error("Method not implemented."); - } -} +import { Item } from "data/item"; +import { SimulationState } from "../SimulationState"; +import { joinItemStackString, processWrappers } from "./helper"; +import { ItemStackCommandWrapper } from "./ItemStackCommandWrapper"; +import { CommandImpl } from "./type"; export class CommandInitialize extends CommandImpl { - private stacks: ItemStack[]; - constructor(stacks: ItemStack[]){ + private stacks: ItemStackCommandWrapper[]; + constructor(stacks: ItemStackCommandWrapper[]){ super(); this.stacks = stacks; } public execute(state: SimulationState): void { - state.initialize(this.stacks); + state.initialize(processWrappers(this.stacks)); } public getDisplayString(): string { return joinItemStackString("Initialize", this.stacks); @@ -86,8 +71,8 @@ export class CommandUse extends CommandImpl{ public getDisplayString(): string { return `Use ${this.name}`; } - public isValid(): boolean { - return false; // this command is deprecated + public getError(): string|undefined { + return `This command is deprecated. Use "Reload ${this.name}" directly`; } } @@ -108,142 +93,53 @@ export class CommandBreakSlots extends CommandImpl { } export class CommandAdd extends CommandImpl { - private verb: string; - private count: number; - private item: string; - constructor(verb: string, count: number, item: string){ + private _verb: string; + private stacks: ItemStackCommandWrapper[]; + constructor(verb: string, stacks: ItemStackCommandWrapper[]){ super(); - this.verb = verb; - this.count = count; - this.item = item; - } - - public execute(state: SimulationState): void { - state.obtain(this.item, this.count); - } - public getDisplayString(): string { - return `${this.verb} ${this.count} ${this.item}`; - } -} - -export class CommandAddWithoutCount extends CommandImpl { - private verb: string; - private item: string; - constructor(verb: string, item: string){ - super(); - this.verb = verb; - this.item = item; - } - - public execute(state: SimulationState): void { - state.obtain(this.item, 1); - } - public getDisplayString(): string { - return `${this.verb} ${this.item}`; - } -} - -export class CommandAddMultiple extends CommandImpl { - private verb: string; - private stacks: ItemStack[]; - constructor(verb: string, stacks: ItemStack[]){ - super(); - this.verb = verb; + this._verb = verb; this.stacks = stacks; } public execute(state: SimulationState): void { - this.stacks.forEach(({item, count})=>state.obtain(item,count)); - } - public getDisplayString(): string { - return joinItemStackString(this.verb, this.stacks); - + processWrappers(this.stacks).forEach(stack=>state.obtain(stack)); } + // public getDisplayString(): string { + // return `${this.verb} ${this.count} ${this.item}`; + // } } export class CommandRemove extends CommandImpl { - private verb: string; - private count: number; - private item: string; + private _verb: string; + private stacks: ItemStackCommandWrapper[]; private slot: number; - private noSlot: boolean; - constructor(verb: string, count: number, item: string, slot: number, noSlot: boolean){ + constructor(verb: string, stacks: ItemStackCommandWrapper[], slot: number){ super(); - this.verb = verb; - this.count = count; - this.item = item; - this.slot = slot; - this.noSlot = noSlot; - } - public execute(state: SimulationState): void { - state.remove(this.item, this.count, this.slot); - } - public getDisplayString(): string { - const slotString = this.noSlot ? "" : ` From Slot ${this.slot+1}`; - return `${this.verb} ${this.count} ${this.item}${slotString}`; - } -} - -export class CommandRemoveWithoutCount extends CommandImpl { - private verb: string; - private item: string; - private slot: number; - private noSlot: boolean; - constructor(verb: string, item: string, slot: number, noSlot: boolean){ - super(); - this.verb = verb; - this.item = item; - this.slot = slot; - this.noSlot = noSlot; - } - public execute(state: SimulationState): void { - state.remove(this.item, 1, this.slot); - } - public getDisplayString(): string { - const slotString = this.noSlot ? "" : ` From Slot ${this.slot+1}`; - return `${this.verb} ${this.item}${slotString}`; - } -} - -export class CommandRemoveMultiple extends CommandImpl { - private verb: string; - private stacks: ItemStack[]; - constructor(verb: string, stacks: ItemStack[]){ - super(); - this.verb = verb; + this._verb = verb; this.stacks = stacks; + this.slot = slot; } - public execute(state: SimulationState): void { - this.stacks.forEach(({item, count})=>state.remove(item,count,0)); - } - public getDisplayString(): string { - return joinItemStackString(this.verb, this.stacks); + processWrappers(this.stacks).forEach(stack=>state.remove(stack, this.slot)); } + // public getDisplayString(): string { + // const slotString = this.noSlot ? "" : ` From Slot ${this.slot+1}`; + // return `${this.verb} ${this.count} ${this.item}${slotString}`; + // } } -const joinItemStackString = (initial: string, stacks: ItemStack[]): string => { - const parts: string[] = [initial]; - stacks.forEach(({item, count})=>{ - parts.push(""+count); - parts.push(item); - }); - return parts.join(" "); -}; - export class CommandDaP extends CommandImpl { - private stacks: ItemStack[]; + private stacks: ItemStackCommandWrapper[]; - constructor(stacks: ItemStack[]){ + constructor(stacks: ItemStackCommandWrapper[]){ super(); this.stacks = stacks; } public execute(state: SimulationState): void { - this.stacks.forEach(({item,count})=>{ - state.remove(item, count, 0); - state.obtain(item, count); - }); - + processWrappers(this.stacks).forEach(stack=>{ + state.remove(stack, 0); + state.obtain(stack); + }); } public getDisplayString(): string { return joinItemStackString("D&P", this.stacks); @@ -251,10 +147,10 @@ export class CommandDaP extends CommandImpl { } export class CommandEquip extends CommandImpl { - private item: string; + private item: Item; private slot: number; private noSlot: boolean; - constructor(item: string, slot: number, noSlot: boolean){ + constructor(item: Item, slot: number, noSlot: boolean){ super(); this.item = item; this.slot = slot; @@ -271,10 +167,10 @@ export class CommandEquip extends CommandImpl { } export class CommandUnequip extends CommandImpl { - private item: string; + private item: Item; private slot: number; private noSlot: boolean; - constructor(item: string, slot: number, noSlot: boolean){ + constructor(item: Item, slot: number, noSlot: boolean){ super(); this.item = item; this.slot = slot; @@ -315,18 +211,11 @@ export class CommandCloseGame extends CommandImpl { } export class CommandSync extends CommandImpl { - private actionString: string; - constructor(actionString: string){ - super(); - this.actionString = actionString; - } public execute(state: SimulationState): void { state.syncGameDataWithPouch(); } - public getDisplayString(): string { - return this.actionString; - } + } export class CommandEventide extends CommandImpl { @@ -346,12 +235,14 @@ export class CommandEventide extends CommandImpl { export class CommandNop extends CommandImpl { private text: string; - constructor(text: string){ + private error: string; + constructor(text: string, error: string){ super(); this.text = text; + this.error = error; } - public isValid(): boolean { - return false; + public getError(): string | undefined { + return this.error; } public execute(_state: SimulationState): void { // nothing @@ -374,8 +265,8 @@ export class CommandSortKey extends CommandImpl { public execute(_state: SimulationState): void { // wip } - public getDisplayString(): string { - return "Sort Key"; + public getError(): string { + return "This command is currently not supported"; } } @@ -392,7 +283,7 @@ export class CommandSortMaterial extends CommandImpl { public execute(_state: SimulationState): void { // wip } - public getDisplayString(): string { - return "Sort Material"; + public getError(): string { + return "This command is currently not supported"; } } diff --git a/src/core/command/ItemStackCommandWrapper.ts b/src/core/command/ItemStackCommandWrapper.ts new file mode 100644 index 0000000..ea4bb6c --- /dev/null +++ b/src/core/command/ItemStackCommandWrapper.ts @@ -0,0 +1,17 @@ +import { ItemStack } from "data/item"; + +export class ItemStackCommandWrapper { + stack: ItemStack; + number: number; + constructor(stack: ItemStack, number: number){ + this.stack = stack; + this.number = number; + } + + public getStackAndSlotCount(): [ItemStack, number] { + if(this.stack.item.stackable){ + return [this.stack.modify({count: this.number}), 1]; + } + return [this.stack, this.number]; + } +} diff --git a/src/core/command/Parser.ts b/src/core/command/Parser.ts new file mode 100644 index 0000000..990a3b2 --- /dev/null +++ b/src/core/command/Parser.ts @@ -0,0 +1,345 @@ +import { ItemStack, parseMetadata } from "data/item"; +import { tokenize } from "data/tokenize"; +import { CommandHint } from "./CommandHint"; +import { + CommandAdd, + CommandBreakSlots, + CommandCloseGame, + CommandDaP, + CommandEquip, + CommandEventide, + CommandInitialize, + CommandNop, + CommandReload, + CommandRemove, + CommandSave, + CommandSaveAs, + CommandShootArrow, + CommandSortKey, + CommandSortMaterial, + CommandSync, + CommandUnequip, + CommandUse +} from "./Commands"; +import { CommandWrite } from "./CommandWrite"; +import { isAddVerb, isRemoveVerb, keywordMatch, keywordMatchAny } from "./helper"; +import { ItemStackCommandWrapper } from "./ItemStackCommandWrapper"; +import { Command } from "./type"; + +export const parseCommand = (cmdString: string, searchFunc: (word: string)=>ItemStack|undefined): Command => { + const tokens = tokenize(cmdString, /[\s.[\]]/).filter(s=>!s.match(/^\s*$/)); + if(tokens.length===0){ + return new CommandNop("", ""); + } + + const simple = parseSimpleCommands(tokens); + if(simple){ + return simple; + } + + const searchFuncWithError = (word: string): ItemStack|string => { + const result = searchFunc(word); + if(!result){ + return `Item not found: ${word}`; + } + return result; + }; + // intialize + if(tokens.length>1 && keywordMatch(tokens[0],"initialize")){ + const stacks = parseItemStacks(tokens, 1, searchFunc); + if(typeof stacks === "string"){ + return new CommandNop(cmdString, stacks); + } + return new CommandInitialize(stacks); + } + if(isAddVerb(tokens[0])){ + // add item + if (tokens.length === 2){ + const item = tokens[1]; + const stack = searchFuncWithError(item); + if(typeof stack === "string"){ + return new CommandNop(cmdString, stack); + } + return new CommandAdd(tokens[0], [new ItemStackCommandWrapper(stack, 1)]); + }else + // add X item1 Y item2 Z item3 + if(tokens.length>2 ){ + const stacks = parseItemStacks(tokens, 1, searchFunc); + if(typeof stacks === "string"){ + return new CommandNop(cmdString, stacks); + } + return new CommandAdd(tokens[0], stacks); + } + } + if(isRemoveVerb(tokens[0])){ + // remove X item From Slot Y + if (tokens.length === 6 && keywordMatch(tokens[3], "from") && keywordMatch(tokens[4], "slot") ){ + const count = parseInteger(tokens[1]); + if(count===undefined){ + return new CommandNop(cmdString, numberError(tokens[1])); + } + const item = tokens[2]; + const slot = parseInt(tokens[5]); + if(!Number.isInteger(slot)){ + return new CommandNop(cmdString, numberError(tokens[5])); + } + const stack = searchFuncWithError(item); + if(typeof stack === "string"){ + return new CommandNop(cmdString, stack); + } + return new CommandRemove(tokens[0], [new ItemStackCommandWrapper(stack, count)], slot-1); + } else + // remove item From Slot Y + if (tokens.length === 5 && keywordMatch(tokens[2], "from") && keywordMatch(tokens[3], "slot")){ + const item = tokens[1]; + const slot = parseInt(tokens[4]); + if(!Number.isInteger(slot)){ + return new CommandNop(cmdString, numberError(tokens[4])); + } + const stack = searchFuncWithError(item); + if(typeof stack === "string"){ + return new CommandNop(cmdString, stack); + } + return new CommandRemove(tokens[0], [new ItemStackCommandWrapper(stack, 1)], slot-1); + } else + // remove item + if (tokens.length === 2){ + const item = tokens[1]; + const stack = searchFuncWithError(item); + if(typeof stack === "string"){ + return new CommandNop(cmdString, stack); + } + return new CommandRemove(tokens[0], [new ItemStackCommandWrapper(stack, 1)], 0); + + } else + // remove multiple + if(tokens.length>2){ + const stacks = parseItemStacks(tokens, 1, searchFunc); + if(typeof stacks === "string"){ + return new CommandNop(cmdString, stacks); + } + return new CommandRemove(tokens[0], stacks, 0); + } + } + + //Shortcut for drop and pick up + if (tokens.length >2 && keywordMatchAny(tokens[0], ["d&p", "dnp", "dap"])){ + const stacks = parseItemStacks(tokens, 1, searchFunc); + if(typeof stacks === "string"){ + return new CommandNop(cmdString, stacks); + } + return new CommandDaP(stacks); + } + + if(keywordMatch(tokens[0], "equip")){ + // Equip item In Slot X + if (tokens.length === 5 && keywordMatch(tokens[2], "in") && keywordMatch(tokens[3], "slot") ){ + const item = tokens[1]; + const slot = parseInt(tokens[4]); + if(!Number.isInteger(slot)){ + return new CommandNop(cmdString, numberError(tokens[4])); + } + const stack = searchFuncWithError(item); + if(typeof stack === "string"){ + return new CommandNop(cmdString, stack); + } + return new CommandEquip(stack.item, slot-1, false); + } + // Equip item + if (tokens.length === 2){ + const item = tokens[1]; + const stack = searchFuncWithError(item); + if(typeof stack === "string"){ + return new CommandNop(cmdString, stack); + } + return new CommandEquip(stack.item, 0, true); + } + } + + if(keywordMatch(tokens[0], "unequip")){ + // Unequip item in slot X + if (tokens.length === 5 && keywordMatch(tokens[2], "in") && keywordMatch(tokens[3], "slot")){ + const item = tokens[1]; + const slot = parseInt(tokens[4]); + if(!Number.isInteger(slot)){ + return new CommandNop(cmdString, numberError(tokens[4])); + } + const stack = searchFuncWithError(item); + if(typeof stack === "string"){ + return new CommandNop(cmdString, stack); + } + return new CommandUnequip(stack.item, slot-1, false); + } + // Unequip item + if (tokens.length === 2){ + const item = tokens[1]; + const stack = searchFuncWithError(item); + if(typeof stack === "string"){ + return new CommandNop(cmdString, stack); + } + return new CommandUnequip(stack.item, -1, true); + } + } + + // Shoot X Arrow + if (tokens.length === 3 && keywordMatch(tokens[0], "shoot") && keywordMatch(tokens[2], "arrow")){ + const count = parseInteger(tokens[1]); + if(count===undefined){ + return new CommandNop(cmdString, numberError(tokens[1])); + } + return new CommandShootArrow(count); + } + + // Write [meta] on item + if(tokens.length > 2 && keywordMatch(tokens[0], "write") && tokens[1]==="["){ + let metaString = ""; + let i = 2; + while(i 0){ + return new CommandHint(tokens[0]); + } + + return new CommandNop(cmdString, "Unknown command"); +}; + +const parseSimpleCommands = (tokens: string[]): Command | undefined => { + // Save/Reload + if(tokens.length===1 && keywordMatch(tokens[0],"save")){ + return new CommandSave(); + } + // Multi Save + if (tokens.length === 3 && keywordMatch(tokens[0],"save") && keywordMatch(tokens[1],"as")){ + const name = tokens[2]; + return new CommandSaveAs(name); + } + if (tokens.length === 2 && keywordMatch(tokens[0],"use")){ + const name = tokens[1]; + return new CommandUse(name); + } + if(tokens.length===1 && keywordMatch(tokens[0],"reload")){ + return new CommandReload(); + } + if(tokens.length===2 && keywordMatch(tokens[0],"reload")){ + return new CommandReload(tokens[1]); + } + // break + if (tokens.length > 2 && keywordMatch(tokens[0],"break") && keywordMatch(tokens[2],"slots") ){ + const slots = parseInt(tokens[1]); + if(Number.isInteger(slots)){ + return new CommandBreakSlots(slots); + } + } + + if(tokens.length===2 && keywordMatch(tokens[0],"sort") && keywordMatch(tokens[1],"key")){ + return new CommandSortKey(); + } + if(tokens.length===2 && keywordMatch(tokens[0],"sort") && keywordMatch(tokens[1],"material")){ + return new CommandSortMaterial(); + } + if(tokens.length===2 && keywordMatchAny(tokens[0],["close", "exit"]) && keywordMatch(tokens[1],"game")){ + return new CommandCloseGame(); + } + if(tokens.length===2 && keywordMatch(tokens[0],"sync") && keywordMatch(tokens[0],"gamedata")){ + return new CommandSync(); + } + if(tokens.length===2 && (keywordMatch(tokens[0],"enter") || keywordMatch(tokens[0],"exit")) && (keywordMatch(tokens[1],"eventide") || keywordMatch(tokens[1],"tots"))){ + return new CommandEventide(keywordMatch(tokens[0],"enter")); + } +}; + +const parseItemStacks = (tokens: string[], from: number, searchFunc: (word: string)=>ItemStack|undefined): ItemStackCommandWrapper[] | string => { + const stacks: ItemStackCommandWrapper[] = []; + let i = from; + while(i [ ], meta not supported atm + const stackSearchNames: string[] = []; + let stackMeta = ""; + let isReadingMeta = false; + while(i { + if(keywordMatch(token, "all")){ + return 9999999; + } + const num = parseInt(token); + if(!Number.isInteger(num)){ + return undefined; + } + return num; +}; + +const numberError = (token: string): string => { + return `Failed to parse number: ${token}`; +}; + +const itemNotFoundError = (token: string): string => { + return `Item not found: ${token}`; +}; diff --git a/src/core/command/helper.ts b/src/core/command/helper.ts new file mode 100644 index 0000000..5675ff3 --- /dev/null +++ b/src/core/command/helper.ts @@ -0,0 +1,60 @@ +import { ItemStack } from "data/item"; +import { ItemStackCommandWrapper } from "./ItemStackCommandWrapper"; + +export const joinItemStackString = (initial: string, stacks: ItemStackCommandWrapper[]): string => { + const parts: string[] = [initial]; + stacks.forEach(({stack, number})=>{ + parts.push(""+number); + parts.push(itemStackToString(stack)); + }); + return parts.join(" "); +}; + +const itemStackToString = (stack: ItemStack): string => { + return stack.item.id; +}; + +// converts stacks from command to stacks to add +export const processWrappers = (stacks: ItemStackCommandWrapper[]): ItemStack[] => { + const returnStacks: ItemStack[] = []; + stacks.forEach(stack=>{ + const [actualStack, count] = stack.getStackAndSlotCount(); + for(let i=0;i { + return keywordMatchAny(token, [ + "get", + "cook", + "add", + "pickup", + "buy" + ]); +}; + +export const isRemoveVerb = (token: string): boolean => { + return keywordMatchAny(token, [ + "remove", + "sell", + "eat", + "drop", + "with" + ]); +}; + +export const keywordMatch = (token: string, keyword: string): boolean => { + return token.toLowerCase() === keyword; +}; + +export const keywordMatchAny = (token: string, keywords: string[]): boolean => { + for(let i=0;istring; +type FlatLangMap = { [flatKey: string]: string}; + +const LanguageContext = React.createContext(x=>x); + +const UnlocalizedSet = new Set(); +export const useI18n = () => useContext(LanguageContext); +export const LanguageProvider: React.FC = ({children}) => { + const [error, setError] = useState(false); + const [flatLangMap, setFlatLangMap] = useState(null); + + useEffect(()=>{ + const loadFuncAync = async () => { + try{ + setFlatLangMap(await loadFlatLangMapAsync()); + }catch(e){ + console.error(e); + setError(true); + setFlatLangMap(null); + } + }; + measurePerformance("Load Language: ", ()=>{ + loadFuncAync(); + }); + + },[]); + + const translationFunction = useCallback((key: string)=>{ + if(!flatLangMap){ + throw new Error("Translation function should not be supplied before lang map is loaded"); + } + if(!(key in flatLangMap)){ + if(!UnlocalizedSet.has(key)){ + // in the future, need to add fallback logic (i.e. on the spot load the default lang file and return new translation later) + console.warn(`Unlocalized: ${key}`); // eslint-disable-line no-console + UnlocalizedSet.add(key); + } + + return key; + } + return flatLangMap[key]; + }, [flatLangMap]); + + if(!flatLangMap){ + if(error){ + return An error has occured while loading language; + }else{ + return Loading language...; + } + } + + return ( + + {children} + + ); + +}; + +type StringTree = typeof import("*.lang.yaml").default; + +const loadFlatLangMapAsync = async ():Promise => { + // In the future, add language detection here + const langMapModule = await import("./en.lang.yaml"); + const langMap = langMapModule["default"]; + // Flatten the lang map + const flatMap: FlatLangMap = {}; + for(const rootKey in langMap){ + flattenInTo(rootKey, langMap[rootKey], flatMap); + } + + return flatMap; +}; + +const flattenInTo = (key: string, obj: StringTree | string, outMap: FlatLangMap) => { + if(typeof obj === "string"){ + outMap[key] = obj; + return; + } + for(const nextKey in obj){ + flattenInTo(key+"."+nextKey, obj[nextKey], outMap); + } +}; diff --git a/src/data/i18n/en.lang.yaml b/src/data/i18n/en.lang.yaml new file mode 100644 index 0000000..881cd78 --- /dev/null +++ b/src/data/i18n/en.lang.yaml @@ -0,0 +1,694 @@ +items: + Weapon: + # single hand + MasterSword: Master Sword + TreeBranch: Tree Branch + Torch: Torch + SoupLadle: Soup Ladle + Boomerang: Boomerang + SpringLoadedHammer: Spring-Loaded Hammer + TravelersSword: Traveler's Sword + SoldiersBroadsword: Soldier's Broadsword + KnightsBroadsword: Knight's Broadsword + RoyalBroadsword: Royal Broadsword + ForestDwellersSword: Forest Dweller's Sword + ZoraSword: Zora Sword + FeatheredEdge: Feathered Edge + GerudoScimitar: Gerudo Scimitar + MoonlightScimitar: Moonlight Scimitar + ScimitarOfTheSeven: Scimitar of the Seven + EightfoldBlade: Eightfold Blade + AncientShortSword: Ancient Short Sword + RustyBroadsword: Rusty Broadsword + RoyalGuardsSword: Royal Guard's Sword + Flameblade: Flameblade + Frostblade: Frostblade + Thunderblade: Thunderblade + GoddessSword: Goddess Sword + Sword: Sword + SeaBreezeBoomerang: Sea-Breeze Boomerang + BokoClub: Boko Club + SpikedBokoClub: Spiked Boko Club + DragonboneBokoClub: Dragonbone Boko Club + LizalBoomerang: Lizal Boomerang + LizalForkedBoomerang: Lizal Forked Boomerang + LizalTriBoomerang: Lizal Tri-Boomerang + GuardianSword: Guardian Sword + GuardianSwordPlus: Guardian Sword+ + GuardianSwordPlusPlus: Guardian Sword++ + LynelSword: Lynel Sword + MightyLynelSword: Mighty Lynel Sword + SavageLynelSword: Savage Lynel Sword + FireRod: Fire Rod + MeteorRod: Meteor Rod + IceRod: Ice Rod + BlizzardRod: Blizzard Rod + LightningRod: Lightning Rod + ThunderstormRod: Thunderstorm Rod + ViciousSickle: Vicious Sickle + DemonCarver: Demon Carver + OneHitObliterator: One-Hit Obliterator + BokoblinArm: Bokoblin Arm + LizalfosArm: Lizalfos Arm + # 2-handed + KorokLeaf: Korok Leaf + FarmingHoe: Farming Hoe + BoatOar: Boat Oar + WoodcuttersAxe: Woodcutter's Axe + DoubleAxe: Double Axe + IronSledgehammer: Iron Sledgehammer + GiantBoomerang: Giant Boomerang + TravelersClaymore: Traveler's Claymore + SoldiersClaymore: Soldier's Claymore + KnightsClaymore: Knight's Claymore + RoyalClaymore: Royal Claymore + SilverLongsword: Silver Longsword + CobbleCrusher: Cobble Crusher + StoneSmasher: Stone Smasher + BoulderBreaker: Boulder Breaker + GoldenClaymore: Golden Claymore + EightfoldLongblade: Eightfold Longblade + EdgeOfDuality: Edge of Duality + AncientBladesaw: Ancient Bladesaw + RustyClaymore: Rusty Claymore + RoyalGuardsClaymore: Royal Guard's Claymore + GreatFlameblade: Great Flameblade + GreatFrostblade: Great Frostblade + GreatThunderblade: Great Thunderblade + SwordOfTheSixSages: Sword of the Six Sages + BiggoronsSword: Biggoron's Sword + FierceDeitySword: Fierce Deity Sword + BokoBat: Boko Bat + SpikedBokoBat: Spiked Boko Bat + DragonboneBokoBat: Dragonbone Boko Bat + MoblinClub: Moblin Club + SpikedMoblinClub: Spiked Moblin Club + DragonboneMoblinClub: Dragonbone Moblin Club + AncientBattleAxe: Ancient Battle Axe + AncientBattleAxePlus: Ancient Battle Axe+ + AncientBattleAxePlusPlus: Ancient Battle Axe++ + LynelCrusher: Lynel Crusher + MightyLynelCrusher: Mighty Lynel Crusher + SavageLynelCrusher: Savage Lynel Crusher + Windcleaver: Windcleaver + MoblinArm: Moblin Arm + # spear + WoodenMop: Wooden Mop + FarmersPitchfork: Farmer's Pitchfork + FishingHarpoon: Fishing Harpoon + ThrowingSpear: Throwing Spear + TravelersSpear: Traveler's Spear + SoldiersSpear: Soldier's Spear + KnightsHalberd: Knight's Halberd + RoyalHalberd: Royal Halberd + ForestDwellersSpear: Forest Dweller's Spear + ZoraSpear: Zora Spear + SilverscaleSpear: Silverscale Spear + CeremonialTrident: Ceremonial Trident + LightscaleTrident: Lightscale Trident + Drillshaft: Drillshaft + FeatheredSpear: Feathered Spear + GerudoSpear: Gerudo Spear + SerpentineSpear: Serpentine Spear + AncientSpear: Ancient Spear + RustyHalberd: Rusty Halberd + RoyalGuardsSpear: Royal Guard's Spear + Flamespear: Flamespear + Frostspear: Frostspear + Thunderspear: Thunderspear + BokoSpear: Boko Spear + SpikedBokoSpear: Spiked Boko Spear + DragonboneBokoSpear: Dragonbone Boko Spear + MoblinSpear: Moblin Spear + SpikedMoblinSpear: Spiked Moblin Spear + DragonboneMoblinSpear: Dragonbone Moblin Spear + LizalSpear: Lizal Spear + EnhancedLizalSpear: Enhanced Lizal Spear + ForkedLizalSpear: Forked Lizal Spear + GuardianSpear: Guardian Spear + GuardianSpearPlus: Guardian Spear+ + GuardianSpearPlusPlus: Guardian Spear++ + LynelSpear: Lynel Spear + MightyLynelSpear: Mighty Lynel Spear + SavageLynelSpear: Savage Lynel Spear + Weapon: Weapon Placeholder + Bow: + BowOfLight: Bow of Light + WoodenBow: Wooden Bow + TravelersBow: Traveler's Bow + SoldiersBow: Soldier's Bow + KnightsBow: Knight's Bow + RoyalBow: Royal Bow + ForestDwellersBow: Forest Dweller's Bow + SilverBow: Silver Bow + SwallowBow: Swallow Bow + FalconBow: Falcon Bow + GreatEagleBow: Great Eagle Bow + GoldenBow: Golden Bow + PhrenicBow: Phrenic Bow + AncientBow: Ancient Bow + RoyalGuardsBow: Royal Guard's Bow + TwilightBow: Twilight Bow + BokoBow: Boko Bow + SpikedBokoBow: Spiked Boko Bow + DragonBoneBokoBow: Dragon Bone Boko Bow + LizalBow: Lizal Bow + StrengthenedLizalBow: Strengthened Lizal Bow + SteelLizalBow: Steel Lizal Bow + LynelBow: Lynel Bow + MightyLynelBow: Mighty Lynel Bow + SavageLynelBow: Savage Lynel Bow + DuplexBow: Duplex Bow + Bow: Bow Placeholder + Arrow: + NormalArrow: Arrow + FireArrow: Fire Arrow + IceArrow: Ice Arrow + ShockArrow: Shock Arrow + BombArrow: Bomb Arrow + AncientArrow: Ancient Arrow + Shield: + HylianShield: Hylian Shield + PotLid: Pot Lid + WoodenShield: Wooden Shield + EmblazonedShield: Emblazoned Shield + HuntersShield: Hunter's Shield + FishermansShield: Fisherman's Shield + TravelersShield: Traveler's Shield + SoldiersShield: Soldier's Shield + KnightsShield: Knight's Shield + RoyalShield: Royal Shield + ForestDwellersShield: Forest Dweller's Shield + SilverShield: Silver Shield + KiteShield: Kite Shield + GerudoShield: Gerudo Shield + RadiantShield: Radiant Shield + Daybreaker: Daybreaker + ShieldOfTheMindsEye: Shield of the Mind's Eye + AncientShield: Ancient Shield + RustyShield: Rusty Shield + RoyalGuardsShield: Royal Guard's Shield + HerosShield: Hero's Shield + BokoShield: Boko Shield + SpikedBokoShield: Spiked Boko Shield + DragonboneBokoShield: Dragonbone Boko Shield + LizalShield: Lizal Shield + ReinforcedLizalShield: Reinforced Lizal Shield + SteelLizalShield: Steel Lizal Shield + GuardianShield: Guardian Shield + GuardianShieldPlus: Guardian Shield+ + GuardianShieldPlusPlus: Guardian Shield++ + LynelShield: Lynel Shield + MightyLynelShield: Mighty Lynel Shield + SavageLynelShield: Savage Lynel Shield + Shield: Shield Placeholder + ArmorUpper: + HylianHood: Hylian Hood + SoldiersHelm: Soldier's Helm + AmberEarrings: Amber Earrings + RubyCirclet: Ruby Circlet + SnowquillHeaddress: Snowquill Headdress + SapphireCirclet: Sapphire Circlet + DesertVoeHeadband: Desert Voe Headband + GerudoVeil: Gerudo Veil + TopazEarrings: Topaz Earrings + RubberHelm: Rubber Helm + FlamebreakerHelm: Flamebreaker Helm + OpalEarrings: Opal Earrings + ZoraHelm: Zora Helm + StealthMask: Stealth Mask + SheiksMask: Sheik's Mask + ThunderHelm: Thunder Helm + ClimbersBandanna: Climber's Bandanna + BarbarianHelm: Barbarian Helm + FierceDeityMask: Fierce Deity Mask + RadiantMask: Radiant Mask + DiamondCirclet: Diamond Circlet + AncientHelm: Ancient Helm + BokoblinMask: Bokoblin Mask + MoblinMask: Moblin Mask + LizalfosMask: Lizalfos Mask + LynelMask: Lynel Mask + DarkHood: Dark Hood + CapOfTime: Cap of Time + CapOfTheWind: Cap of the Wind + CapOfTwilight: Cap of Twilight + CapOfTheWild: Cap of the Wild + CapOfTheSky: Cap of the Sky + CapOfTheHero: Cap of the Hero + KorokMask: Korok Mask + MajorasMask: Majora's Mask + TinglesHood: Tingle's Hood + MidnasHelmet: Midna's Helmet + PhantomHelmet: Phantom Helmet + RaviosHood: Ravio's Hood + ZantsHelmet: Zant's Helmet + RoyalGuardCap: Royal Guard Cap + PhantomGanonSkull: Phantom Ganon Skull + VahRutaDivineHelm: Vah Ruta Divine Helm + VahMedohDivineHelm: Vah Medoh Divine Helm + VahRudaniaDivineHelm: Vah Rudania Divine Helm + VahNaborisDivineHelm: Vah Naboris Divine Helm + SalvagerHeadwear: Salvager Headwear + ArmorMiddle: + OldShirt: Old Shirt + ChampionsTunic: Champion's Tunic + HylianTunic: Hylian Tunic + SoldiersArmor: Soldier's Armor + WarmDoublet: Warm Doublet + SnowquillTunic: Snowquill Tunic + DesertVoeSpaulder: Desert Voe Spaulder + GerudoTop: Gerudo Top + RubberArmor: Rubber Armor + FlamebreakerArmor: Flamebreaker Armor + ZoraArmor: Zora Armor + StealthChestGuard: Stealth Chest Guard + ClimbingGear: Climbing Gear + BarbarianArmor: Barbarian Armor + FierceDeityArmor: Fierce Deity Armor + RadiantShirt: Radiant Shirt + AncientCuirass: Ancient Cuirass + DarkTunic: Dark Tunic + TunicOfTime: Tunic of Time + TunicOfTheWind: Tunic of the Wind + TunicOfTwilight: Tunic of Twilight + TunicOfTheSky: Tunic of the Sky + TunicOfTheHero: Tunic of the Hero + TunicOfTheWild: Tunic of the Wild + NintendoSwitchShirt: Nintendo Switch Shirt + TinglesShirt: Tingle's Shirt + PhantomArmor: Phantom Armor + IslandLobsterShirt: Island Lobster Shirt + RoyalGuardUniform: Royal Guard Uniform + PhantomGanonArmor: Phantom Ganon Armor + SalvagerVest: Salvager Vest + ArmorLower: + WellWornTrousers: Well-Worn Trousers + HylianTrousers: Hylian Trousers + SoldiersGreaves: Soldier's Greaves + SnowquillTrousers: Snowquill Trousers + DesertVoeTrousers: Desert Voe Trousers + GerudoSirwal: Gerudo Sirwal + RubberTights: Rubber Tights + FlamebreakerBoots: Flamebreaker Boots + ZoraGreaves: Zora Greaves + StealthTights: Stealth Tights + ClimbingBoots: Climbing Boots + BarbarianLegWraps: Barbarian Leg Wraps + FierceDeityBoots: Fierce Deity Boots + RadiantTights: Radiant Tights + AncientGreaves: Ancient Greaves + SandBoots: Sand Boots + SnowBoots: Snow Boots + DarkTrousers: Dark Trousers + TrousersOfTime: Trousers of Time + TrousersOfTheWind: Trousers of the Wind + TrousersOfTwilight: Trousers of Twilight + TrousersOfTheSky: Trousers of the Sky + TrousersOfTheHero: Trousers of the Hero + TrousersOfTheWild: Trousers of the Wild + TinglesTights: Tingle's Tights + PhantomGreaves: Phantom Greaves + RoyalGuardBoots: Royal Guard Boots + PhantomGanonGreaves: Phantom Ganon Greaves + SalvagerTrousers: Salvager Trousers + Material: + HeartyDurian: Hearty Durian + PalmFruit: Palm Fruit + Apple: Apple + Wildberry: Wildberry + Hydromelon: Hydromelon + SpicyPepper: Spicy Pepper + Voltfruit: Voltfruit + FleetLotusSeeds: Fleet-Lotus Seeds + MightyBananas: Mighty Bananas + BigHeartyTruffle: Big Hearty Truffle + HeartyTruffle: Hearty Truffle + EnduraShroom: Endura Shroom + HylianShroom: Hylian Shroom + StamellaShroom: Stamella Shroom + Chillshroom: Chillshroom + Sunshroom: Sunshroom + Zapshroom: Zapshroom + Rushroom: Rushroom + Razorshroom: Razorshroom + Ironshroom: Ironshroom + SilentShroom: Silent Shroom + BigHeartyRadish: Big Hearty Radish + HeartyRadish: Hearty Radish + EnduraCarrot: Endura Carrot + HyruleHerb: Hyrule Herb + SwiftCarrot: Swift Carrot + FortifiedPumpkin: Fortified Pumpkin + CoolSafflina: Cool Safflina + WarmSafflina: Warm Safflina + ElectricSafflina: Electric Safflina + SwiftViolet: Swift Violet + MightyThistle: Mighty Thistle + Armoranth: Armoranth + BlueNightshade: Blue Nightshade + SilentPrincess: Silent Princess + RawGourmetMeat: Raw Gourmet Meat + RawWholeBird: Raw Whole Bird + RawPrimeMeat: Raw Prime Meat + RawBirdThigh: Raw Bird Thigh + RawMeat: Raw Meat + RawBirdDrumstick: Raw Bird Drumstick + CourserBeeHoney: Courser Bee Honey + HylianRice: Hylian Rice + BirdEgg: Bird Egg + TabanthaWheat: Tabantha Wheat + FreshMilk: Fresh Milk + Acorn: Acorn + ChickalooTreeNut: Chickaloo Tree Nut + CaneSugar: Cane Sugar + GoatButter: Goat Butter + GoronSpice: Goron Spice + RockSalt: Rock Salt + MonsterExtract: Monster Extract + StarFragment: Star Fragment + DinraalsScale: Dinraal's Scale + DinraalsClaw: Dinraal's Claw + ShardOfDinraalsFang: Shard of Dinraal's Fang + ShardOfDinraalsHorn: Shard of Dinraal's Horn + NaydrasScale: Naydra's Scale + NaydrasClaw: Naydra's Claw + ShardOfNaydrasFang: Shard of Naydra's Fang + ShardOfNaydrasHorn: Shard of Naydra's Horn + FaroshScale: Farosh's Scale + FaroshClaw: Farosh's Claw + ShardOfFaroshsFang: Shard of Farosh's Fang + ShardOfFaroshsHorn: Shard of Farosh's Horn + HeartySalmon: Hearty Salmon + HeartyBlueshellSnail: Hearty Blueshell Snail + HeartyBass: Hearty Bass + HyruleBass: Hyrule Bass + StaminokaBass: Staminoka Bass + ChillfinTrout: Chillfin Trout + SizzlefinTrout: Sizzlefin Trout + VoltfinTrout: Voltfin Trout + StealthfinTrout: Stealthfin Trout + MightyCarp: Mighty Carp + ArmoredCarp: Armored Carp + SankeCarp: Sanke Carp + MightyPorgy: Mighty Porgy + ArmoredPorgy: Armored Porgy + SneakyRiverSnail: Sneaky River Snail + RazorclawCrab: Razorclaw Crab + IronshellCrab: Ironshell Crab + BrightEyedCrab: Bright-Eyed Crab + Fairy: Fairy + WinterwingButterfly: Winterwing Butterfly + SummerwingButterfly: Summerwing Butterfly + ThunderwingButterfly: Thunderwing Butterfly + SmotherwingButterfly: Smotherwing Butterfly + ColdDarner: Cold Darner + WarmDarner: Warm Darner + ElectricDarner: Electric Darner + RestlessCricket: Restless Cricket + BladedRhinoBeetle: Bladed Rhino Beetle + RuggedRhinoBeetle: Rugged Rhino Beetle + EnergeticRhinoBeetle: Energetic Rhino Beetle + SunsetFirefly: Sunset Firefly + HotFootedFrog: Hot-Footed Frog + TirelessFrog: Tireless Frog + HightailLizard: Hightail Lizard + HeartyLizard: Hearty Lizard + FireproofLizard: Fireproof Lizard + Flint: Flint + Amber: Amber + Opal: Opal + LuminousStone: Luminous Stone + Topaz: Topaz + Ruby: Ruby + Sapphire: Sapphire + Diamond: Diamond + BokoblinHorn: Bokoblin Horn + BokoblinFang: Bokoblin Fang + BokoblinGuts: Bokoblin Guts + MoblinHorn: Moblin Horn + MoblinFang: Moblin Fang + MoblinGuts: Moblin Guts + LizalfosHorn: Lizalfos Horn + LizalfosTalon: Lizalfos Talon + LizalfosTail: Lizalfos Tail + IcyLizalfosTail: Icy Lizalfos Tail + RedLizalfosTail: Red Lizalfos Tail + YellowLizalfosTail: Yellow Lizalfos Tail + LynelHorn: Lynel Horn + LynelHoof: Lynel Hoof + LynelGuts: Lynel Guts + ChuchuJelly: Chuchu Jelly + WhiteChuchuJelly: White Chuchu Jelly + RedChuchuJelly: Red Chuchu Jelly + YellowChuchuJelly: Yellow Chuchu Jelly + KeeseWing: Keese Wing + IceKeeseWing: Ice Keese Wing + FireKeeseWing: Fire Keese Wing + ElectricKeeseWing: Electric Keese Wing + KeeseEyeball: Keese Eyeball + OctorokTentacle: Octorok Tentacle + OctorokEyeball: Octorok Eyeball + OctoBalloon: Octo Balloon + MoldugaFin: Molduga Fin + MoldugaGuts: Molduga Guts + HinoxToenail: Hinox Toenail + HinoxTooth: Hinox Tooth + HinoxGuts: Hinox Guts + AncientScrew: Ancient Screw + AncientSpring: Ancient Spring + AncientGear: Ancient Gear + AncientShaft: Ancient Shaft + AncientCore: Ancient Core + GiantAncientCore: Giant Ancient Core + Wood: Wood + Food: + SimmeredFruit: Simmered Fruit + CopiousSimmeredFruit: Copious Simmered Fruit + MushroomSkewer: Mushroom Skewer + CopiousMushroomSkewers: Copious Mushroom Skewers + FriedWildGreens: Fried Wild Greens + CopiousFriedWildGreens: Copious Fried Wild Greens + FishSkewer: Fish Skewer + SeafoodSkewer: Seafood Skewer + CopiousSeafoodSkewers: Copious Seafood Skewers + MeatSkewer: Meat Skewer + CopiousMeatSkewers: Copious Meat Skewers + FruitAndMushroomMix: Fruit and Mushroom Mix + FishAndMushroomSkewer: Fish and Mushroom Skewer + MeatAndMushroomSkewer: Meat and Mushroom Skewer + SteamedFruit: Steamed Fruit + SteamedMushrooms: Steamed Mushrooms + SteamedFish: Steamed Fish + SteamedMeat: Steamed Meat + SaltGrilledMushrooms: Salt-Grilled Mushrooms + SaltGrilledGreens: Salt-Grilled Greens + SaltGrilledFish: Salt-Grilled Fish + SaltGrilledCrab: Salt-Grilled Crab + SaltGrilledMeat: Salt-Grilled Meat + SaltGrilledPrimeMeat: Salt-Grilled Prime Meat + SaltGrilledGourmetMeat: Salt-Grilled Gourmet Meat + CrabStirFry: Crab Stir-Fry + PepperSeafood: Pepper Seafood + PepperSteak: Pepper Steak + MeatAndSeafoodFry: Meat and Seafood Fry + PrimeMeatAndSeafoodFry: Prime Meat and Seafood Fry + GourmetMeatAndSeafoodFry: Gourmet Meat and Seafood Fry + SpicedMeatSkewer: Spiced Meat Skewer + PrimeSpicedMeatSkewer: Prime Spiced Meat Skewer + GourmetSpicedMeatSkewer: Gourmet Spiced Meat Skewer + FragrantMushroomSaute: Fragrant Mushroom Sauté + HerbSaute: Herb Sauté + MeatStuffedPumpkin: Meat-Stuffed Pumpkin + SauteedNuts: Sautéed Nuts + SauteedPeppers: Sautéed Peppers + Omelet: Omelet + GlazedMushrooms: Glazed Mushrooms + GlazedVeggies: Glazed Veggies + GlazedSeafood: Glazed Seafood + GlazedMeat: Glazed Meat + SeafoodMeuniere: Seafood Meunière + PorgyMeuniere: Porgy Meunière + SalmonMeuniere: Salmon Meunière + SeafoodFriedRice: Seafood Fried Rice + CrabOmeletWithRice: Crab Omelet with Rice + SeafoodPaella: Seafood Paella + PoultryPilaf: Poultry Pilaf + PrimePoultryPilaf: Prime Poultry Pilaf + GourmetPoultryPilaf: Gourmet Poultry Pilaf + CurryPilaf: Curry Pilaf + FriedEggAndRice: Fried Egg and Rice + MushroomRisotto: Mushroom Risotto + VegetableRisotto: Vegetable Risotto + SalmonRisotto: Salmon Risotto + CrabRisotto: Crab Risotto + CreamOfVegetableSoup: Cream of Vegetable Soup + CreamOfMushroomSoup: Cream of Mushroom Soup + VeggieCreamSoup: Veggie Cream Soup + CreamyHeartSoup: Creamy Heart Soup + CreamySeafoodSoup: Creamy Seafood Soup + CreamyMeatSoup: Creamy Meat Soup + MonsterSoup: Monster Soup + CarrotStew: Carrot Stew + PumpkinStew: Pumpkin Stew + ClamChowder: Clam Chowder + MeatStew: Meat Stew + PrimeMeatStew: Prime Meat Stew + GourmetMeatStew: Gourmet Meat Stew + MonsterStew: Monster Stew + CurryRice: Curry Rice + VegetableCurry: Vegetable Curry + SeafoodCurry: Seafood Curry + PoultryCurry: Poultry Curry + PrimePoultryCurry: Prime Poultry Curry + GourmetPoultryCurry: Gourmet Poultry Curry + MeatCurry: Meat Curry + PrimeMeatCurry: Prime Meat Curry + GourmetMeatCurry: Gourmet Meat Curry + MonsterCurry: Monster Curry + MushroomOmelet: Mushroom Omelet + VegetableOmelet: Vegetable Omelet + MushroomRiceBalls: Mushroom Rice Balls + VeggieRiceBalls: Veggie Rice Balls + SeafoodRiceBalls: Seafood Rice Balls + MeatyRiceBalls: Meaty Rice Balls + MonsterRiceBalls: Monster Rice Balls + MeatAndRiceBowl: Meat and Rice Bowl + PrimeMeatAndRiceBowl: Prime Meat and Rice Bowl + GourmetMeatAndRiceBowl: Gourmet Meat and Rice Bowl + WheatBread: Wheat Bread + Nutcake: Nutcake + Fruitcake: Fruitcake + CarrotCake: Carrot Cake + PumpkinPie: Pumpkin Pie + MonsterCake: Monster Cake + PlainCrepe: Plain Crepe + WildberryCrepe: Wildberry Crepe + HoneyCrepe: Honey Crepe + FruitPie: Fruit Pie + ApplePie: Apple Pie + FishPie: Fish Pie + MeatPie: Meat Pie + EggTart: Egg Tart + HoneyCandy: Honey Candy + HoneyedFruits: Honeyed Fruits + HoneyedApple: Honeyed Apple + HotButteredApple: Hot Buttered Apple + FriedBananas: Fried Bananas + EggPudding: Egg Pudding + WarmMilk: Warm Milk + Elixir: Elixir + HeartyElixir: Hearty Elixir + EnergizingElixir: Energizing Elixir + EnduringElixir: Enduring Elixir + HastyElixir: Hasty Elixir + FireproofElixir: Fireproof Elixir + SpicyElixir: Spicy Elixir + ChillyElixir: Chilly Elixir + ElectroElixir: Electro Elixir + MightyElixir: Mighty Elixir + ToughElixir: Tough Elixir + SneakyElixir: Sneaky Elixir + FairyTonic: Fairy Tonic + DubiousFood: Dubious Food + RockHardFood: Rock-Hard Food + BakedApple: Baked Apple + BakedPalmFruit: Baked Palm Fruit + RoastedWildberry: Roasted Wildberry + RoastedAcorn: Roasted Acorn + RoastedTreeNut: Roasted Tree Nut + RoastedHeartyDurian: Roasted Hearty Durian + RoastedHydromelon: Roasted Hydromelon + CharredPepper: Charred Pepper + RoastedVoltfruit: Roasted Voltfruit + RoastedLotusSeeds: Roasted Lotus Seeds + RoastedMightyBananas: Roasted Mighty Bananas + ToastyHylianShroom: Toasty Hylian Shroom + ToastyStamellaShroom: Toasty Stamella Shroom + ToastyEnduraShroom: Toasty Endura Shroom + ToastedHeartyTruffle: Toasted Hearty Truffle + ToastedBigHeartyTruffle: Toasted Big Hearty Truffle + ToastyChillshroom: Toasty Chillshroom + ToastySunshroom: Toasty Sunshroom + ToastyZapshroom: Toasty Zapshroom + ToastyRushroom: Toasty Rushroom + ToastyRazorshroom: Toasty Razorshroom + ToastyIronshroom: Toasty Ironshroom + ToastySilentShroom: Toasty Silent Shroom + RoastedRadish: Roasted Radish + RoastedBigRadish: Roasted Big Radish + RoastedSwiftCarrot: Roasted Swift Carrot + RoastedEnduraCarrot: Roasted Endura Carrot + BakedFortifiedPumpkin: Baked Fortified Pumpkin + RoastedMightyThistle: Roasted Mighty Thistle + RoastedArmoranth: Roasted Armoranth + CampfireEgg: Campfire Egg + HardBoiledEgg: Hard-Boiled Egg + SearedSteak: Seared Steak + SearedPrimeSteak: Seared Prime Steak + SearedGourmetSteak: Seared Gourmet Steak + RoastedBirdDrumstick: Roasted Bird Drumstick + RoastedBirdThigh: Roasted Bird Thigh + RoastedWholeBird: Roasted Whole Bird + RoastedBass: Roasted Bass + RoastedHeartyBass: Roasted Hearty Bass + RoastedHeartySalmon: Roasted Hearty Salmon + RoastedTrout: Roasted Trout + RoastedCarp: Roasted Carp + RoastedPorgy: Roasted Porgy + SneakyRiverEscargot: Sneaky River Escargot + BlueshellEscargot: Blueshell Escargot + BlackenedCrab: Blackened Crab + IcyMeat: Icy Meat + IcyPrimeMeat: Icy Prime Meat + IcyGourmetMeat: Icy Gourmet Meat + FrozenBirdDrumstick: Frozen Bird Drumstick + FrozenBirdThigh: Frozen Bird Thigh + FrozenWholeBird: Frozen Whole Bird + FrozenBass: Frozen Bass + FrozenHeartyBass: Frozen Hearty Bass + FrozenHeartySalmon: Frozen Hearty Salmon + FrozenTrout: Frozen Trout + FrozenCarp: Frozen Carp + FrozenPorgy: Frozen Porgy + FrozenCrab: Frozen Crab + FrozenRiverSnail: Frozen River Snail + IcyHeartyBlueshellSnail: Icy Hearty Blueshell Snail + Key: + SheikahSlate: Sheikah Slate + MiphasGrace: Mipha's Grace + RevalisGale: Revali's Gale + DaruksProtection: Daruk's Protection + UrbosasFury: Urbosa's Fury + MiphasGracePlus: Mipha's Grace + + RevalisGalePlus: Revali's Gale + + DaruksProtectionPlus: Daruk's Protection + + UrbosasFuryPlus: Urbosa's Fury + + Paraglider: Paraglider + RutasEmblem: Ruta's Emblem + MedohsEmblem: Medoh's Emblem + RudaniasEmblem: Rudania's Emblem + NaborissEmblem: Naboris's Emblem + SpiritOrb: Spirit Orb + KorokSeed: Korok Seed + HestusMaracas: Hestu's Maracas + ThunderHelmKeyItem: Thunder Helm + ClassifiedEnvelope: Classified Envelope + HestusGift: Hestu's Gift + PictureOfTheChampions: Picture of the Champions + MedalOfHonorTalus: "Medal of Honor: Talus" + MedalOfHonorHinox: "Medal of Honor: Hinox" + MedalOfHonorMolduga: "Medal of Honor: Molduga" + TravelersBridle: Traveler's Bridle + KnightsBridle: Knight's Bridle + RoyalBridle: Royal Bridle + ExtravagantBridle: Extravagant Bridle + MonsterBridle: Monster Bridle + AncientBridle: Ancient Bridle + TravelersSaddle: Traveler's Saddle + KnightsSaddle: Knight's Saddle + RoyalSaddle: Royal Saddle + ExtravagantSaddle: Extravagant Saddle + MonsterSaddle: Monster Saddle + AncientSaddle: Ancient Saddle + TravelMedallion: Travel Medallion diff --git a/src/data/i18n/index.ts b/src/data/i18n/index.ts new file mode 100644 index 0000000..1134fa4 --- /dev/null +++ b/src/data/i18n/index.ts @@ -0,0 +1 @@ +export * from "./LanguageProvider"; diff --git a/src/data/item/Item.ts b/src/data/item/Item.ts new file mode 100644 index 0000000..4c63f7f --- /dev/null +++ b/src/data/item/Item.ts @@ -0,0 +1,64 @@ +import { createMaterialStack } from "./ItemStack"; +import { getTabFromType, Item, ItemStack, ItemTab, ItemType } from "./type"; + +const TypeToCount: Omit<{ + [t in ItemType]: number +}, ItemType.Flag> = { + [ItemType.Weapon]: 0, + [ItemType.Bow]: 0, + [ItemType.Arrow]: 0, + [ItemType.Shield]: 0, + [ItemType.ArmorUpper]: 0, + [ItemType.ArmorMiddle]: 0, + [ItemType.ArmorLower]: 0, + [ItemType.Material]: 0, + [ItemType.Food]: 0, + [ItemType.Key]: 0, +}; + +export class ItemImpl implements Item { + id: string; + type: ItemType; + get tab(): ItemTab { + return getTabFromType(this.type); + } + repeatable: boolean; + stackable: boolean; + sortOrder = -1; + image: string; + configuredAnimatedImage?: string; + defaultStackFactory?: (item: Item)=>ItemStack; + constructor( + id: string, + type: ItemType, + repeatable: boolean, + stackable: boolean, + image: string, + animatedImage: string|undefined, + defaultStackFactory: ((item: Item)=>ItemStack)|undefined + ){ + this.id = id; + this.type = type; + this.repeatable = repeatable; + this.stackable = stackable; + this.image = image; + this.configuredAnimatedImage = animatedImage; + this.defaultStackFactory = defaultStackFactory; + if(type !== ItemType.Flag){ + this.sortOrder = TypeToCount[type]; + TypeToCount[type]++; + } + } + + get animatedImage(): string { + return this.configuredAnimatedImage || this.image; + } + + createDefaultStack(): ItemStack { + if(this.defaultStackFactory){ + return this.defaultStackFactory(this); + } + return createMaterialStack(this, 1); + } + +} diff --git a/src/data/item/ItemProvider.tsx b/src/data/item/ItemProvider.tsx new file mode 100644 index 0000000..6cd411a --- /dev/null +++ b/src/data/item/ItemProvider.tsx @@ -0,0 +1,284 @@ +import { CrashScreen } from "components/CrashScreen"; +import { measurePerformance } from "data/measurePerformance"; +import { LoadingScreen } from "components/LoadingScreen"; +import React, { PropsWithChildren, useContext, useEffect, useMemo, useState } from "react"; +import { ItemImpl } from "./Item"; +import { getTabFromType, Item, ItemIdMap, ItemStack, ItemTab, ItemType } from "./type"; +import { searchLegacyItemNames } from "./legacy"; +import { createEquipmentStack } from "./ItemStack"; + +/* + * Load items from items.yaml files and registers them in memory + */ + +type ItemSearchMap = { [id: string]: string}; // id to search phrase + +type ItemContextFunctions = { + getItem: (id: string) => Item|undefined, + getAllItems: ()=>ItemIdMap, + searchItem: (word: string) => ItemStack|undefined +} + +const ItemContext = React.createContext({} as ItemContextFunctions); +// Memoize search results to accelerate searching, since user typically use the same phrase for the same items +// Note that ItemStack is immutable so it's safe to return the same instance every time +let MemoizedSearchResults: {[phrase: string]: ItemStack|undefined} = {}; + +export const useGetItem = () => useContext(ItemContext).getItem; +export const useAllItems = ()=>useContext(ItemContext).getAllItems(); +export const useSearchItem = () => useContext(ItemContext).searchItem; + +export const ItemProvider: React.FC = ({children}) => { + const [error, setError] = useState(false); + const [itemIdMap, setItemIdMap] = useState(null); + const [itemSearchMap, setItemSearchMap] = useState(null); + + useEffect(()=>{ + const loadFuncAync = async () => { + try{ + const [idMap, searchMap] = await loadItemDataAsync(); + setItemIdMap(idMap); + setItemSearchMap(searchMap); + }catch(e){ + console.error(e); + setError(true); + setItemIdMap(null); + setItemSearchMap(null); + } + }; + measurePerformance("Load Item: ", ()=>{ + loadFuncAync(); + }); + + },[]); + + const [getItem, searchItem, getAllItems] = useMemo(()=>{ + // clear memoized results when recreating search function + MemoizedSearchResults = {}; + if(itemIdMap && itemSearchMap){ + const getItem = (id: string): Item | undefined => itemIdMap[id]; + const searchItem = (word: string): ItemStack | undefined => { + return searchItemMemoized(word, itemIdMap, itemSearchMap, MemoizedSearchResults); + }; + return [getItem, searchItem, ()=>itemIdMap]; + }else{ + return [ + ()=>undefined, + ()=>undefined, + ()=>({}), + ]; + } + + }, [itemIdMap, itemSearchMap]); + + if(!itemIdMap || !itemSearchMap){ + if(error){ + return An error has occured while loading items; + }else{ + return Loading items...; + } + } + + return ( + + {children} + + ); + +}; + +const loadItemDataAsync = async ():Promise<[ItemIdMap, ItemSearchMap]> => { + const itemDataModule = await import("./all.items.yaml"); + const itemData = itemDataModule["default"]; + return loadItemData(itemData); + //const imgModule = await import("assets/img"); + //const { getImage }= imgModule + +}; + +export const loadItemData = (itemData: (typeof import("*.items.yaml"))["default"]): [ItemIdMap, ItemSearchMap] => { + const idMap: ItemIdMap = {}; + const searchMap: ItemSearchMap = {}; + // Register each type + registerItemCategoryByName(itemData, "weapon", ItemType.Weapon, idMap, searchMap); + registerItemCategoryByName(itemData, "bow", ItemType.Bow, idMap, searchMap); + registerItemCategoryByName(itemData, "arrow", ItemType.Arrow, idMap, searchMap); + registerItemCategoryByName(itemData, "shield", ItemType.Shield, idMap, searchMap); + // Pass in undefined for armor type, as it is resolved by option + registerItemCategoryByName(itemData, "armor", undefined as any, idMap, searchMap); // eslint-disable-line @typescript-eslint/no-explicit-any + registerItemCategoryByName(itemData, "material", ItemType.Material, idMap, searchMap); + registerItemCategoryByName(itemData, "food", ItemType.Food, idMap, searchMap); + registerItemCategoryByName(itemData, "key", ItemType.Key, idMap, searchMap); + registerItemCategoryByName(itemData, "flag", ItemType.Flag, idMap, searchMap); + + return [idMap, searchMap]; +}; + +type ItemData = (typeof import("*.items.yaml"))["default"]; +type ItemCategory = Exclude; +type ItemOption = Exclude<(ItemCategory["entries"][number]), string>[string]; + +const DefaultOption: ItemOption = { + stackable: true, + animated: false, + repeatable: true +}; + +const registerItemCategoryByName = (itemData: ItemData, category: keyof ItemData, type: ItemType, outIdMap: ItemIdMap, outSearchMap: ItemSearchMap) => { + const itemCategory = itemData[category]; + if (itemCategory){ + registerItemCategory(itemCategory, type, outIdMap, outSearchMap); + } +}; + +const registerItemCategory = (itemCategory: ItemCategory, type: ItemType, outIdMap: ItemIdMap, outSearchMap: ItemSearchMap) => { + const globalOption = itemCategory.global || {}; + itemCategory.entries.forEach(entry=>{ + let idAndSearch: string; + let option: ItemOption; + if(typeof entry === "string"){ + idAndSearch = entry; + option = {}; + }else{ + [idAndSearch, option] = Object.entries(entry)[0]; + } + // armor special handler + let itemType = type; + if(option.subtype === "upper"){ + itemType = ItemType.ArmorUpper; + } else if(option.subtype === "middle"){ + itemType = ItemType.ArmorMiddle; + } else if(option.subtype === "lower"){ + itemType = ItemType.ArmorLower; + } + + const combinedOption = { + ...DefaultOption, + ...globalOption, + ...option + }; + + registerItem(idAndSearch, combinedOption, itemType, outIdMap, outSearchMap); + }); +}; + +const registerItem = (idAndSearch: string, option: ItemOption, type: ItemType, outIdMap: ItemIdMap, outSearchMap: ItemSearchMap) => { + const [id, search] = splitIdAndSearch(idAndSearch); + const image = getImageUrl(id, type, false); + const animatedImage = option.animated ? getImageUrl(id, type, true) : undefined; + const stackable = option.repeatable && option.stackable; + + // default stack + let defaultStackFactory: ((item: Item) => ItemStack) | undefined = undefined; + if(type === ItemType.Weapon || type === ItemType.Bow || type === ItemType.Shield){ + if(option.durability !== undefined){ + const durability = option.durability; + defaultStackFactory = (item)=>{ + return createEquipmentStack(item, durability, false); + }; + }else{ + defaultStackFactory = (item)=>{ + return createEquipmentStack(item, 10 /* default durability for placeholders */, false); + }; + } + } + + const item = new ItemImpl(id, type, option.repeatable ?? true, stackable ?? true, image, animatedImage, defaultStackFactory); + outIdMap[id] = item; + outSearchMap[id] = search; +}; + +const getImageUrl = (id: string, type: ItemType, animated: boolean): string => { + let typeDir; + if(getTabFromType(type)===ItemTab.Armor){ + typeDir = "Armor"; + }else{ + typeDir = ItemType[type]; + } + return `assets/img/${typeDir}/${id}${animated?"Animated.webp":".png"}`; +}; + +const splitIdAndSearch = (idAndSearch: string): [string, string] => { + const i = idAndSearch.indexOf(":"); + if(i<0){ + return [idAndSearch, idAndSearch.toLowerCase()]; + }else{ + const id = idAndSearch.substring(0, i); + return [id, (id+idAndSearch.substring(i+1)).toLowerCase()]; + } +}; + +export const searchItemMemoized = (name: string, idMap: ItemIdMap, searchMap: ItemSearchMap, memo: {[phrase: string]: ItemStack|undefined}): ItemStack | undefined => { + if(!name){ + return undefined; + } + if (name in memo){ + return memo[name]; + } + + // legacy search must happen first to make sure legacy items are matched exactly + const legacyItem = searchLegacyItemNames(name, idMap); + if(legacyItem){ + memo[name] = legacyItem; + return legacyItem; + } + + const result = searchItemInMap(name, idMap, searchMap); + memo[name] = result; + return result; +}; + +const searchItemInMap = (name: string, idMap: ItemIdMap, searchMap: ItemSearchMap): ItemStack | undefined => { + // if name is an id exactly, return that + const idItem = idMap[name]; + if(idItem){ + return idItem.createDefaultStack(); + } + // break name into dot separated search phrases + const parts = name.split("*"); + // search is O(mn), where m is number of items and n is number of phrases + let filteredResult = Object.keys(searchMap); + // it's faster to filter by each phrase, since the sample sizes decreases every time + // we can return the result when sample size is 1, even if later phrases might exclude that result + // ^ might want to make this togglable in the future + for(let i=0;i{ + const searchPhrase = searchMap[id]; + // searchPhrase must be nonnull because the initial array contains all keys + return searchPhrase.includes(searchKeyLower); + }); + + if(filteredResult.length === 0){ + // nothing found + return undefined; + } + if(filteredResult.length === 1){ + // exactly 1 found, can end + const foundId = filteredResult[0]; + return idMap[foundId].createDefaultStack(); + } + // continue filtering + } + // after all phrases are passed and still have more than 1 result + + // we can either reject the search or return the first result. + // returning the first result here to make the search more generous + const resultStartCountMap: {[id: string]: number} = {}; + filteredResult.forEach((resultId)=>{ + resultStartCountMap[resultId] = parts.filter(p=>resultId.toLowerCase().startsWith(p)).length; + }); + filteredResult.sort((a,b)=>{ + // first see if the result starts with any search key, and prioritize those with more matches + const diffInCount = resultStartCountMap[b] - resultStartCountMap[a]; + if(diffInCount!==0){ + return diffInCount; + } + // if same, prioritize the shorter one + // since the longer ones can always be found by adding more words + return a.length-b.length; + }); + const foundId = filteredResult[0]; + return idMap[foundId].createDefaultStack(); + +}; diff --git a/src/data/item/ItemStack.ts b/src/data/item/ItemStack.ts new file mode 100644 index 0000000..b9db763 --- /dev/null +++ b/src/data/item/ItemStack.ts @@ -0,0 +1,68 @@ +import { Item, ItemStack, MetaOption } from "./type"; + +class ItemStackImpl implements ItemStack { + public item: Item; + life: number; + get count(): number { + return this.life; + } + get durability(): number { + return this.life/100.0; + } + public equipped: boolean; + constructor(item: Item, life: number, equipped: boolean) { + this.item = item; + this.life = life; + this.equipped = equipped; + } + + public modify(option: Partial): ItemStack { + const newItem = "item" in option ? option.item as Item : this.item; + let newLife = this.life; + if("count" in option){ + newLife = option.count as number; + }else if("durability" in option){ + newLife = option.durability as number; + newLife*=100; + } + const newEquipped = "equipped" in option ? !!option.equipped:this.equipped; + return new ItemStackImpl(newItem, newLife, newEquipped); + } + + public modifyMeta(metaOption: MetaOption): ItemStack { + let modifyOption: Partial = {}; + if("life" in metaOption){ + modifyOption = { + ...modifyOption, + count: metaOption.life + }; + } + if("equip" in metaOption){ + modifyOption = { + ...modifyOption, + equipped: metaOption.equip + }; + } + return this.modify(modifyOption); + } + + public equals(other: ItemStack): boolean { + return this.equalsExceptForEquipped(other) && this.equipped === other.equipped; + } + public equalsExceptForEquipped(other: ItemStack): boolean { + return this.canStack(other) && this.life === other.count; + } + public canStack(other: ItemStack): boolean { + // TODO metadata + return this.item === other.item; + } + +} + +export const createMaterialStack = (item: Item, count: number): ItemStack => { + return new ItemStackImpl(item, count, false); +}; + +export const createEquipmentStack = (item: Item, durability: number, equipped: boolean): ItemStack => { + return new ItemStackImpl(item, durability*100, equipped); +}; diff --git a/src/data/item/all.items.yaml b/src/data/item/all.items.yaml new file mode 100644 index 0000000..3d90be0 --- /dev/null +++ b/src/data/item/all.items.yaml @@ -0,0 +1,1179 @@ +# the item name is formatted as name:search. the search phrase is optional (no search phrase means the item name must be matched exactly (case sensitive)) +weapon: + global: + stackable: false + entries: + # single-handed + - MasterSword: + repeatable: false + durability: 40 + - TreeBranch: + durability: 4 + - Torch: + durability: 8 + - SoupLadle: + durability: 5 + - Boomerang: + durability: 18 + - SpringLoadedHammer: + durability: 80 + - TravelersSword: + durability: 20 + - SoldiersBroadsword: + durability: 23 + - KnightsBroadsword: + durability: 27 + - RoyalBroadsword: + durability: 36 + - ForestDwellersSword: + durability: 27 + - ZoraSword: + durability: 27 + - FeatheredEdge: + durability: 27 + - GerudoScimitar: + durability: 23 + - MoonlightScimitar: + durability: 32 + - ScimitarOfTheSeven: + durability: 60 + - EightfoldBlade: + durability: 26 + - AncientShortSword: + durability: 54 + - RustyBroadsword: + durability: 8 + - RoyalGuardsSword: + durability: 14 + - Flameblade: + durability: 36 + - Frostblade: + durability: 30 + - Thunderblade: + durability: 36 + - GoddessSword: + durability: 45 + - Sword: + durability: 27 + - SeaBreezeBoomerang: + durability: 20 + - BokoClub: + durability: 12 + - SpikedBokoClub: + durability: 14 + - DragonboneBokoClub: + durability: 18 + - LizalBoomerang: + durability: 17 + - LizalForkedBoomerang: + durability: 23 + - LizalTriBoomerang: + durability: 27 + - GuardianSword: + durability: 17 + - GuardianSwordPlus: + durability: 26 + - GuardianSwordPlusPlus: + durability: 32 + - LynelSword: + durability: 26 + - MightyLynelSword: + durability: 32 + - SavageLynelSword: + durability: 41 + - FireRod: + durability: 14 + - MeteorRod: + durability: 32 + - IceRod: + durability: 14 + - BlizzardRod: + durability: 32 + - LightningRod: + durability: 14 + - ThunderstormRod: + durability: 32 + - ViciousSickle: + durability: 14 + - DemonCarver: + durability: 25 + - OneHitObliterator:oho: + durability: 40 + - BokoblinArm: + durability: 5 + - LizalfosArm: + durability: 8 + # 2-handed + - KorokLeaf: + durability: 25 + - FarmingHoe: + durability: 6 + - BoatOar: + durability: 8 + - WoodcuttersAxe: + durability: 47 + - DoubleAxe: + durability: 52 + - IronSledgehammer: + durability: 40 + - GiantBoomerang: + durability: 40 + - TravelersClaymore: + durability: 20 + - SoldiersClaymore: + durability: 25 + - KnightsClaymore: + durability: 30 + - RoyalClaymore: + durability: 40 + - SilverLongsword: + durability: 30 + - CobbleCrusher: + durability: 30 + - StoneSmasher: + durability: 40 + - BoulderBreaker: + durability: 60 + - GoldenClaymore: + durability: 30 + - EightfoldLongblade: + durability: 25 + - EdgeOfDuality: + durability: 35 + - AncientBladesaw: + durability: 50 + - RustyClaymore: + durability: 10 + - RoyalGuardsClaymore: + durability: 15 + - GreatFlameblade: + durability: 50 + - GreatFrostblade: + durability: 40 + - GreatThunderblade: + durability: 50 + - SwordOfTheSixSages: + durability: 50 + - BiggoronsSword: + durability: 60 + - FierceDeitySword: + durability: 35 + - BokoBat: + durability: 8 + - SpikedBokoBat: + durability: 12 + - DragonboneBokoBat: + durability: 16 + - MoblinClub: + durability: 12 + - SpikedMoblinClub: + durability: 18 + - DragonboneMoblinClub: + durability: 24 + - AncientBattleAxe: + durability: 15 + - AncientBattleAxePlus: + durability: 20 + - AncientBattleAxePlusPlus: + durability: 25 + - LynelCrusher: + durability: 20 + - MightyLynelCrusher: + durability: 25 + - SavageLynelCrusher: + durability: 35 + - Windcleaver: + durability: 25 + - MoblinArm: + durability: 5 + # spears + - WoodenMop: + durability: 8 + - FarmersPitchfork: + durability: 12 + - FishingHarpoon: + durability: 12 + - ThrowingSpear: + durability: 20 + - TravelersSpear: + durability: 30 + - SoldiersSpear: + durability: 35 + - KnightsHalberd: + durability: 40 + - RoyalHalberd: + durability: 50 + - ForestDwellersSpear: + durability: 35 + - ZoraSpear: + durability: 40 + - SilverscaleSpear: + durability: 40 + - CeremonialTrident: + durability: 40 + - LightscaleTrident: + durability: 70 + - Drillshaft: + durability: 40 + - FeatheredSpear: + durability: 35 + - GerudoSpear: + durability: 35 + - SerpentineSpear: + durability: 35 + - AncientSpear: + durability: 50 + - RustyHalberd: + durability: 15 + - RoyalGuardsSpear: + durability: 15 + - Flamespear: + durability: 50 + - Frostspear: + durability: 40 + - Thunderspear: + durability: 50 + - BokoSpear: + durability: 12 + - SpikedBokoSpear: + durability: 15 + - DragonboneBokoSpear: + durability: 20 + - MoblinSpear: + durability: 15 + - SpikedMoblinSpear: + durability: 20 + - DragonboneMoblinSpear: + durability: 25 + - LizalSpear: + durability: 18 + - EnhancedLizalSpear: + durability: 22 + - ForkedLizalSpear: + durability: 28 + - GuardianSpear: + durability: 20 + - GuardianSpearPlus: + durability: 25 + - GuardianSpearPlusPlus: + durability: 35 + - LynelSpear: + durability: 25 + - MightyLynelSpear: + durability: 35 + - SavageLynelSpear: + durability: 45 + # "ANY" placeholder + - Weapon +bow: + global: + stackable: false + entries: + - BowOfLight + - WoodenBow: + durability: 20 + - TravelersBow: + durability: 22 + - SoldiersBow: + durability: 36 + - KnightsBow: + durability: 48 + - RoyalBow: + durability: 60 + - ForestDwellersBow: + durability: 35 + - SilverBow: + durability: 40 + - SwallowBow: + durability: 30 + - FalconBow: + durability: 50 + - GreatEagleBow: + durability: 60 + - GoldenBow: + durability: 60 + - PhrenicBow: + durability: 45 + - AncientBow: + durability: 120 + - RoyalGuardsBow: + durability: 20 + - TwilightBow: + durability: 100 + - BokoBow: + durability: 16 + - SpikedBokoBow: + durability: 20 + - DragonBoneBokoBow: + durability: 30 + - LizalBow: + durability: 25 + - StrengthenedLizalBow: + durability: 35 + - SteelLizalBow: + durability: 50 + - LynelBow: + durability: 30 + - MightyLynelBow: + durability: 35 + - SavageLynelBow: + durability: 45 + - DuplexBow: + durability: 18 + # "ANY" placeholder + - Bow +arrow: + entries: + - NormalArrow + - FireArrow + - IceArrow + - ShockArrow + - BombArrow + - AncientArrow:aa +shield: + global: + stackable: false + entries: + - HylianShield: + durability: 800 + - PotLid: + durability: 10 + - WoodenShield: + durability: 12 + - EmblazonedShield: + durability: 12 + - HuntersShield: + durability: 10 + - FishermansShield: + durability: 10 + - TravelersShield: + durability: 12 + - SoldiersShield: + durability: 16 + - KnightsShield: + durability: 23 + - RoyalShield: + durability: 29 + - ForestDwellersShield: + durability: 18 + - SilverShield: + durability: 20 + - KiteShield: + durability: 16 + - GerudoShield: + durability: 20 + - RadiantShield: + durability: 26 + - Daybreaker: + durability: 60 + - ShieldOfTheMindsEye: + durability: 16 + - AncientShield: + durability: 32 + - RustyShield: + durability: 16 + - RoyalGuardsShield: + durability: 14 + - HerosShield: + durability: 90 + - BokoShield: + durability: 5 + - SpikedBokoShield: + durability: 7 + - DragonboneBokoShield: + durability: 8 + - LizalShield: + durability: 8 + - ReinforcedLizalShield: + durability: 12 + - SteelLizalShield: + durability: 15 + - GuardianShield: + durability: 10 + - GuardianShieldPlus: + durability: 13 + - GuardianShieldPlusPlus: + durability: 20 + - LynelShield: + durability: 12 + - MightyLynelShield: + durability: 15 + - SavageLynelShield: + durability: 20 + # "ANY" placeholder + - Shield +armor: + global: + stackable: false + entries: + - OldShirt: + subtype: middle + - WellWornTrousers: + subtype: lower + - ChampionsTunic: + subtype: middle + - HylianHood: + subtype: upper + - HylianTunic: + subtype: middle + - HylianTrousers: + subtype: lower + - SoldiersHelm: + subtype: upper + - SoldiersArmor: + subtype: middle + - SoldiersGreaves: + subtype: lower + - AmberEarrings: + subtype: upper + - WarmDoublet: + subtype: middle + - RubyCirclet: + subtype: upper + - SnowquillHeaddress: + subtype: upper + - SnowquillTunic: + subtype: middle + - SnowquillTrousers: + subtype: lower + - SapphireCirclet: + subtype: upper + - DesertVoeHeadband: + subtype: upper + - DesertVoeSpaulder: + subtype: middle + - DesertVoeTrousers: + subtype: lower + - GerudoVeil: + subtype: upper + - GerudoTop: + subtype: middle + - GerudoSirwal: + subtype: lower + - TopazEarrings: + subtype: upper + - RubberHelm: + subtype: upper + - RubberArmor: + subtype: middle + - RubberTights: + subtype: lower + - FlamebreakerHelm: + subtype: upper + - FlamebreakerArmor: + subtype: middle + - FlamebreakerBoots: + subtype: lower + - OpalEarrings: + subtype: upper + - ZoraHelm: + subtype: upper + - ZoraArmor: + subtype: middle + - ZoraGreaves: + subtype: lower + - StealthMask: + subtype: upper + - StealthChestGuard: + subtype: middle + - StealthTights: + subtype: lower + - SheiksMask: + subtype: upper + - ThunderHelm: + subtype: upper + - ClimbersBandanna: + subtype: upper + - ClimbingGear: + subtype: middle + - ClimbingBoots: + subtype: lower + - BarbarianHelm: + subtype: upper + - BarbarianArmor: + subtype: middle + - BarbarianLegWraps: + subtype: lower + - FierceDeityMask: + subtype: upper + - FierceDeityArmor: + subtype: middle + - FierceDeityBoots: + subtype: lower + - RadiantMask: + subtype: upper + - RadiantShirt: + subtype: middle + - RadiantTights: + subtype: lower + - DiamondCirclet: + subtype: upper + - AncientHelm: + subtype: upper + - AncientCuirass: + subtype: middle + - AncientGreaves: + subtype: lower + - SandBoots: + subtype: lower + - SnowBoots: + subtype: lower + - BokoblinMask: + subtype: upper + - MoblinMask: + subtype: upper + - LizalfosMask: + subtype: upper + - LynelMask: + subtype: upper + - DarkHood: + subtype: upper + - DarkTunic: + subtype: middle + - DarkTrousers: + subtype: lower + - CapOfTime: + subtype: upper + - TunicOfTime: + subtype: middle + - TrousersOfTime: + subtype: lower + - CapOfTheWind: + subtype: upper + - TunicOfTheWind: + subtype: middle + - TrousersOfTheWind: + subtype: lower + - CapOfTwilight: + subtype: upper + - TunicOfTwilight: + subtype: middle + - TrousersOfTwilight: + subtype: lower + - CapOfTheSky: + subtype: upper + - TunicOfTheSky: + subtype: middle + - TrousersOfTheSky: + subtype: lower + - CapOfTheHero: + subtype: upper + - TunicOfTheHero: + subtype: middle + - TrousersOfTheHero: + subtype: lower + - CapOfTheWild: + subtype: upper + - TunicOfTheWild: + subtype: middle + - TrousersOfTheWild: + subtype: lower + - NintendoSwitchShirt: + subtype: middle + - KorokMask: + subtype: upper + - MajorasMask: + subtype: upper + - TinglesHood: + subtype: upper + - TinglesShirt: + subtype: middle + - TinglesTights: + subtype: lower + - MidnasHelmet: + subtype: upper + - PhantomHelmet: + subtype: upper + - PhantomArmor: + subtype: middle + - PhantomGreaves: + subtype: lower + - IslandLobsterShirt: + subtype: upper + - RaviosHood: + subtype: upper + - ZantsHelmet: + subtype: upper + - RoyalGuardCap: + subtype: upper + - RoyalGuardUniform: + subtype: middle + - RoyalGuardBoots: + subtype: lower + - PhantomGanonSkull: + subtype: upper + - PhantomGanonArmor: + subtype: middle + - PhantomGanonGreaves: + subtype: lower + - VahRutaDivineHelm: + subtype: upper + - VahMedohDivineHelm: + subtype: upper + - VahRudaniaDivineHelm: + subtype: upper + - VahNaborisDivineHelm: + subtype: upper + - SalvagerHeadwear: + subtype: upper + - SalvagerVest: + subtype: middle + - SalvagerTrousers: + subtype: lower +material: + entries: + - HeartyDurian + - PalmFruit + - Apple + - Wildberry + - Hydromelon + - SpicyPepper + - Voltfruit + - FleetLotusSeeds + - MightyBananas + - BigHeartyTruffle + - HeartyTruffle + - EnduraShroom + - HylianShroom + - StamellaShroom + - Chillshroom + - Sunshroom + - Zapshroom + - Rushroom + - Razorshroom + - Ironshroom + - SilentShroom + - BigHeartyRadish + - HeartyRadish + - EnduraCarrot + - HyruleHerb + - SwiftCarrot + - FortifiedPumpkin + - CoolSafflina + - WarmSafflina + - ElectricSafflina + - SwiftViolet + - MightyThistle + - Armoranth + - BlueNightshade + - SilentPrincess + - RawGourmetMeat + - RawWholeBird + - RawPrimeMeat + - RawBirdThigh + - RawMeat + - RawBirdDrumstick + - CourserBeeHoney + - HylianRice + - BirdEgg + - TabanthaWheat + - FreshMilk + - Acorn + - ChickalooTreeNut + - CaneSugar + - GoatButter + - GoronSpice + - RockSalt + - MonsterExtract + - StarFragment + - DinraalsScale + - DinraalsClaw + - ShardOfDinraalsFang + - ShardOfDinraalsHorn + - NaydrasScale + - NaydrasClaw + - ShardOfNaydrasFang + - ShardOfNaydrasHorn + - FaroshsScale + - FaroshsClaw + - ShardOfFaroshsFang + - ShardOfFaroshsHorn + - HeartySalmon + - HeartyBlueshellSnail + - HeartyBass + - HyruleBass + - StaminokaBass + - ChillfinTrout + - SizzlefinTrout + - VoltfinTrout + - StealthfinTrout + - MightyCarp + - ArmoredCarp + - SankeCarp + - MightyPorgy + - ArmoredPorgy + - SneakyRiverSnail + - RazorclawCrab + - IronshellCrab + - BrightEyedCrab + - Fairy + - WinterwingButterfly + - SummerwingButterfly + - ThunderwingButterfly + - SmotherwingButterfly + - ColdDarner + - WarmDarner + - ElectricDarner + - RestlessCricket + - BladedRhinoBeetle + - RuggedRhinoBeetle + - EnergeticRhinoBeetle + - SunsetFirefly + - HotFootedFrog + - TirelessFrog + - HightailLizard + - HeartyLizard + - FireproofLizard + - Flint + - Amber + - Opal + - LuminousStone + - Topaz + - Ruby + - Sapphire + - Diamond + - BokoblinHorn + - BokoblinFang + - BokoblinGuts + - MoblinHorn + - MoblinFang + - MoblinGuts + - LizalfosHorn + - LizalfosTalon + - LizalfosTail + - IcyLizalfosTail + - RedLizalfosTail + - YellowLizalfosTail + - LynelHorn + - LynelHoof + - LynelGuts + - ChuchuJelly + - WhiteChuchuJelly + - RedChuchuJelly + - YellowChuchuJelly + - KeeseWing + - IceKeeseWing + - FireKeeseWing + - ElectricKeeseWing + - KeeseEyeball + - OctorokTentacle + - OctorokEyeball + - OctoBalloon + - MoldugaFin + - MoldugaGuts + - HinoxToenail + - HinoxTooth + - HinoxGuts + - AncientScrew + - AncientSpring + - AncientGear + - AncientShaft + - AncientCore + - GiantAncientCore + - Wood +food: + entries: + - SimmeredFruit: + stackable: false + - CopiousSimmeredFruit: + stackable: false + - MushroomSkewer: + stackable: false + - CopiousMushroomSkewers: + stackable: false + - FriedWildGreens: + stackable: false + - CopiousFriedWildGreens: + stackable: false + - FishSkewer: + stackable: false + - SeafoodSkewer: + stackable: false + - CopiousSeafoodSkewers: + stackable: false + - MeatSkewer: + stackable: false + - CopiousMeatSkewers: + stackable: false + - FruitAndMushroomMix: + stackable: false + - FishAndMushroomSkewer: + stackable: false + - MeatAndMushroomSkewer: + stackable: false + - SteamedFruit: + stackable: false + - SteamedMushrooms: + stackable: false + - SteamedFish: + stackable: false + - SteamedMeat: + stackable: false + - SaltGrilledMushrooms: + stackable: false + - SaltGrilledGreens: + stackable: false + - SaltGrilledFish: + stackable: false + - SaltGrilledCrab: + stackable: false + - SaltGrilledMeat: + stackable: false + - SaltGrilledPrimeMeat: + stackable: false + - SaltGrilledGourmetMeat: + stackable: false + - CrabStirFry: + stackable: false + - PepperSeafood: + stackable: false + - PepperSteak: + stackable: false + - MeatAndSeafoodFry: + stackable: false + - PrimeMeatAndSeafoodFry: + stackable: false + - GourmetMeatAndSeafoodFry: + stackable: false + - SpicedMeatSkewer: + stackable: false + - PrimeSpicedMeatSkewer: + stackable: false + - GourmetSpicedMeatSkewer: + stackable: false + - FragrantMushroomSaute: + stackable: false + - HerbSaute: + stackable: false + - MeatStuffedPumpkin: + stackable: false + - SauteedNuts: + stackable: false + - SauteedPeppers: + stackable: false + - Omelet: + stackable: false + - GlazedMushrooms: + stackable: false + - GlazedVeggies: + stackable: false + - GlazedSeafood: + stackable: false + - GlazedMeat: + stackable: false + - SeafoodMeuniere: + stackable: false + - PorgyMeuniere: + stackable: false + - SalmonMeuniere: + stackable: false + - SeafoodFriedRice: + stackable: false + - CrabOmeletWithRice: + stackable: false + - SeafoodPaella: + stackable: false + - PoultryPilaf: + stackable: false + - PrimePoultryPilaf: + stackable: false + - GourmetPoultryPilaf: + stackable: false + - CurryPilaf: + stackable: false + - FriedEggAndRice: + stackable: false + - MushroomRisotto: + stackable: false + - VegetableRisotto: + stackable: false + - SalmonRisotto: + stackable: false + - CrabRisotto: + stackable: false + - CreamOfVegetableSoup: + stackable: false + - CreamOfMushroomSoup: + stackable: false + - VeggieCreamSoup: + stackable: false + - CreamyHeartSoup: + stackable: false + - CreamySeafoodSoup: + stackable: false + - CreamyMeatSoup: + stackable: false + - MonsterSoup: + stackable: false + - CarrotStew: + stackable: false + - PumpkinStew: + stackable: false + - ClamChowder: + stackable: false + - MeatStew: + stackable: false + - PrimeMeatStew: + stackable: false + - GourmetMeatStew: + stackable: false + - MonsterStew: + stackable: false + - CurryRice: + stackable: false + - VegetableCurry: + stackable: false + - SeafoodCurry: + stackable: false + - PoultryCurry: + stackable: false + - PrimePoultryCurry: + stackable: false + - GourmetPoultryCurry: + stackable: false + - MeatCurry: + stackable: false + - PrimeMeatCurry: + stackable: false + - GourmetMeatCurry: + stackable: false + - MonsterCurry: + stackable: false + - MushroomOmelet: + stackable: false + - VegetableOmelet: + stackable: false + - MushroomRiceBalls: + stackable: false + - VeggieRiceBalls: + stackable: false + - SeafoodRiceBalls: + stackable: false + - MeatyRiceBalls: + stackable: false + - MonsterRiceBalls: + stackable: false + - MeatAndRiceBowl: + stackable: false + - PrimeMeatAndRiceBowl: + stackable: false + - GourmetMeatAndRiceBowl: + stackable: false + - WheatBread: + stackable: false + - Nutcake: + stackable: false + - Fruitcake: + stackable: false + - CarrotCake: + stackable: false + - PumpkinPie: + stackable: false + - MonsterCake: + stackable: false + - PlainCrepe: + stackable: false + - WildberryCrepe: + stackable: false + - HoneyCrepe: + stackable: false + - FruitPie: + stackable: false + - ApplePie: + stackable: false + - FishPie: + stackable: false + - MeatPie: + stackable: false + - EggTart: + stackable: false + - HoneyCandy: + stackable: false + - HoneyedFruits: + stackable: false + - HoneyedApple: + stackable: false + - HotButteredApple: + stackable: false + - FriedBananas: + stackable: false + - EggPudding: + stackable: false + - WarmMilk: + stackable: false + - Elixir: + stackable: false + - HeartyElixir: + stackable: false + - EnergizingElixir: + stackable: false + - EnduringElixir: + stackable: false + - HastyElixir: + stackable: false + - FireproofElixir: + stackable: false + - SpicyElixir: + stackable: false + - ChillyElixir: + stackable: false + - ElectroElixir: + stackable: false + - MightyElixir: + stackable: false + - ToughElixir: + stackable: false + - SneakyElixir: + stackable: false + - FairyTonic: + stackable: false + - DubiousFood: + stackable: false + - RockHardFood: + stackable: false + - BakedApple + - BakedPalmFruit + - RoastedWildberry + - RoastedAcorn + - RoastedTreeNut + - RoastedHeartyDurian + - RoastedHydromelon + - CharredPepper + - RoastedVoltfruit + - RoastedLotusSeeds + - RoastedMightyBananas + - ToastyHylianShroom + - ToastyStamellaShroom + - ToastyEnduraShroom + - ToastedHeartyTruffle + - ToastedBigHeartyTruffle + - ToastyChillshroom + - ToastySunshroom + - ToastyZapshroom + - ToastyRushroom + - ToastyRazorshroom + - ToastyIronshroom + - ToastySilentShroom + - RoastedRadish + - RoastedBigRadish + - RoastedSwiftCarrot + - RoastedEnduraCarrot + - BakedFortifiedPumpkin + - RoastedMightyThistle + - RoastedArmoranth + - CampfireEgg + - HardBoiledEgg + - SearedSteak + - SearedPrimeSteak + - SearedGourmetSteak + - RoastedBirdDrumstick + - RoastedBirdThigh + - RoastedWholeBird + - RoastedBass + - RoastedHeartyBass + - RoastedHeartySalmon + - RoastedTrout + - RoastedCarp + - RoastedPorgy + - SneakyRiverEscargot + - BlueshellEscargot + - BlackenedCrab + - IcyMeat + - IcyPrimeMeat + - IcyGourmetMeat + - FrozenBirdDrumstick + - FrozenBirdThigh + - FrozenWholeBird + - FrozenBass + - FrozenHeartyBass + - FrozenHeartySalmon + - FrozenTrout + - FrozenCarp + - FrozenPorgy + - FrozenCrab + - FrozenRiverSnail + - IcyHeartyBlueshellSnail +key: + entries: + - SheikahSlate: + repeatable: false + - MiphasGrace: + repeatable: false + animated: false # not supported yet + - RevalisGale: + repeatable: false + animated: false # not supported yet + - DaruksProtection: + repeatable: false + animated: false # not supported yet + - UrbosasFury: + repeatable: false + animated: false # not supported yet + - MiphasGracePlus: + repeatable: false + animated: false # not supported yet + - RevalisGalePlus: + repeatable: false + animated: false # not supported yet + - DaruksProtectionPlus: + repeatable: false + animated: false # not supported yet + - UrbosasFuryPlus: + repeatable: false + animated: false # not supported yet + - Paraglider: + repeatable: false + - RutasEmblem: + animated: false # not supported yet + - MedohsEmblem: + animated: false # not supported yet + - RudaniasEmblem: + animated: false # not supported yet + - NaborissEmblem: + animated: false # not supported yet + - SpiritOrb: + animated: true + - KorokSeed + - HestusMaracas: + repeatable: false + - ThunderHelmKey: + repeatable: false + - ClassifiedEnvelope: + repeatable: false + - HestusGift: + repeatable: false + - PictureOfTheChampions: + repeatable: false + - MedalOfHonorTalus: + repeatable: false + - MedalOfHonorHinox: + repeatable: false + - MedalOfHonorMolduga: + repeatable: false + - TravelersBridle: + repeatable: false + - KnightsBridle: + repeatable: false + - RoyalBridle: + repeatable: false + - ExtravagantBridle: + repeatable: false + - MonsterBridle: + repeatable: false + - AncientBridle: + repeatable: false + - TravelersSaddle: + repeatable: false + - KnightsSaddle: + repeatable: false + - RoyalSaddle: + repeatable: false + - ExtravagantSaddle: + repeatable: false + - MonsterSaddle: + repeatable: false + - AncientSaddle: + repeatable: false + - TravelMedallion: + repeatable: false + animated: true diff --git a/src/data/item/index.ts b/src/data/item/index.ts new file mode 100644 index 0000000..560d323 --- /dev/null +++ b/src/data/item/index.ts @@ -0,0 +1,5 @@ +export * from "./ItemProvider"; +export * from "./type"; +export * from "./legacy"; +export * from "./ItemStack"; +export * from "./meta"; diff --git a/src/data/item/items.yaml.d.ts b/src/data/item/items.yaml.d.ts new file mode 100644 index 0000000..0eb3786 --- /dev/null +++ b/src/data/item/items.yaml.d.ts @@ -0,0 +1,35 @@ +declare module '*.items.yaml' { + type ItemOption = Partial>; + type ItemEntry = { + [id: string]: ItemOption + } | string; + type ItemArray = Array; + type ItemCategory = { + global?: ItemOption, //global option + entries: ItemArray, //actual items + } + type ItemData = Partial>; + const classes: ItemData; + export default classes; +} diff --git a/src/data/item/legacy.ts b/src/data/item/legacy.ts new file mode 100644 index 0000000..2561078 --- /dev/null +++ b/src/data/item/legacy.ts @@ -0,0 +1,63 @@ +import { ItemIdMap, ItemStack } from "./type"; + +// Legacy item names before all items were added + +const LegacyMap = { + "Slate": "SheikahSlate", + "Glider": "Paraglider", + "SpiritOrb": "SpiritOrb", + "Lotus": "FleetLotusSeeds", + "SilentPrincess": "SilentPrincess", + "Honey": "CourserBeeHoney", + "Acorn": "Acorn", + "FaroshScale": "FaroshsScale", + "FaroshClaw": "FaroshsClaw", + "FaroshHorn": "ShardOfFaroshsHorn", + "HeartyBass": "HeartyBass", + "Beetle": "EnergeticRhinoBeetle", + "Opal": "Opal", + "Diamond": "Diamond", + "Tail": "LizalfosTail", + "Spring": "AncientSpring", + "Shaft": "AncientShaft", + "Core": "AncientCore", + "Wood": "Wood", + "Rushroom": "Rushroom", + "Screw": "AncientScrew", + "HyruleBass": "HyruleBass", + "LizalfosHorn": "LizalfosHorn", + "LizalfosTalon": "LizalfosTalon", + "Weapon": "Weapon", + "Bow": "Bow", + "NormalArrow": "NormalArrow", + "FireArrow": "FireArrow", + "IceArrow": "IceArrow", + "ShockArrow": "ShockArrow", + "BombArrow": "BombArrow", + "AncientArrow": "AncientArrow", + "Shield": "Shield", + "Apple": "Apple", + "HylianShroom": "HylianShroom", + "SpicyPepper": "SpicyPepper", + "EnduraShroom": "EnduraShroom", + "HeartyRadish": "HeartyRadish", + "BigHeartyRadish": "BigHeartyRadish", + "Fairy": "Fairy", + "MasterSword": "MasterSword", + "ZoraArmor": "ZoraArmor" +}; + +export const searchLegacyItemNames = (name: string, idMap: ItemIdMap): ItemStack | undefined => { + if (name in LegacyMap){ + return idMap[LegacyMap[name as keyof typeof LegacyMap]].createDefaultStack(); + } + if(name === "SpeedFood"){ + // TODO: effect metadata + return idMap.SteamedFruit.createDefaultStack(); + } + if(name === "EnduraFood"){ + // TODO: effect metadata + return idMap.MushroomSkewer.createDefaultStack(); + } + return undefined; +}; diff --git a/src/data/item/meta.ts b/src/data/item/meta.ts new file mode 100644 index 0000000..f6fafc3 --- /dev/null +++ b/src/data/item/meta.ts @@ -0,0 +1,40 @@ +import { MetaOption } from "./type"; + +export const parseMetadata = (metaString: string): MetaOption | string => { + if(metaString.trim().length === 0){ + return {}; + } + const parts = metaString.toLowerCase().split(","); + const option: MetaOption = {}; + for(let i =0;i [ + ItemTab.Weapon, + ItemTab.Bow, + ItemTab.Shield, + ItemTab.Armor, + ItemTab.Material, + ItemTab.Food, + ItemTab.Key +]; + +export const getTabFromType = (type: ItemType): ItemTab => { + switch(type){ + case ItemType.Weapon: + return ItemTab.Weapon; + case ItemType.Bow: + case ItemType.Arrow: + return ItemTab.Bow; + case ItemType.Shield: + return ItemTab.Shield; + case ItemType.ArmorUpper: + case ItemType.ArmorMiddle: + case ItemType.ArmorLower: + return ItemTab.Armor; + case ItemType.Material: + return ItemTab.Material; + case ItemType.Food: + return ItemTab.Food; + case ItemType.Key: + return ItemTab.Key; + default: + return ItemTab.None; + } +}; +export interface Item { + // The id of Item, which is its name in UpperCamelCase in English as it appears in English, with special characters like ' removed and + turned into Plus + // The only special case is that the key item Thunderhelm is named ThunderHelmKey + readonly id: string, + // The type of the item + readonly type: ItemType + // if this is false, the item will not be added to pouch if one already exists + readonly repeatable: boolean, + // if the item is stackable + readonly stackable: boolean, + // sort order of the item + readonly sortOrder: number, + // which tab the item is in + readonly tab: ItemTab, + // webpack loaded image + readonly image: string, + // animated image. If the item is not animated, this is the same as image + readonly animatedImage: string, + // create item stack with this item and default metadata (durability and default state for weapons, cookdata for meals, etc) + createDefaultStack(): ItemStack, +} + +// ItemStack is an immutable object holding information of a slot +export interface ItemStack { + // type of the item + readonly item: Item, + // how many in slot. for weapon, this is durability*100 + readonly count: number, + // durability of equipment. for material, this is count/100 + readonly durability: number, + // if slot is equipped + readonly equipped: boolean, + // function to create a new stack based on this stack and option + modify(option: Partial): ItemStack, + // function to create a new stack based on this stack and meta option + modifyMeta(metaOption: MetaOption): ItemStack, + // check if 2 stacks are equal: same item, count, equipped nd metadata + equals(other: ItemStack): boolean, + // check if everything equals except for equipped + equalsExceptForEquipped(other: ItemStack): boolean, + // check if item and meta equal, used for stacking + canStack(other: ItemStack): boolean, +} + +export type ItemIdMap = { [id: string]: Item}; + +// the extra data supported when inputing an item +export type MetaOption = { + //life value, count or durability*100 + life?: number, + //equipped. + equip?: boolean, +} diff --git a/src/data/measurePerformance.ts b/src/data/measurePerformance.ts new file mode 100644 index 0000000..a91d56a --- /dev/null +++ b/src/data/measurePerformance.ts @@ -0,0 +1,8 @@ +const PRECISION = 4; // 4 sig-figs +type AnyFunction = (...args: T[])=>void; +export const measurePerformance = performance ? (tag: string, func: AnyFunction) => { + const start = performance.now(); + func(); + const duration = performance.now() - start; + console.log(`${tag}${duration.toPrecision(PRECISION)}ms`); // eslint-disable-line no-console +} : (_tag: string, func: AnyFunction)=>func(); diff --git a/src/data/mergeSort.ts b/src/data/stableSort.ts similarity index 100% rename from src/data/mergeSort.ts rename to src/data/stableSort.ts diff --git a/src/data/tokenize.ts b/src/data/tokenize.ts new file mode 100644 index 0000000..43518a1 --- /dev/null +++ b/src/data/tokenize.ts @@ -0,0 +1,18 @@ +export const tokenize = (str: string, regex: RegExp): string[] => { + const tokens: string[] = []; + let j = str.search(regex); + while(j !== -1){ + if(j!==0){ + //Prevent empty tokens + tokens.push(str.substring(0, j)); + } + + tokens.push(str[j]); + str = str.substring(j+1); + j = str.search(regex); + } + if(str !== ""){ + tokens.push(str); + } + return tokens; +}; diff --git a/src/index.tsx b/src/index.tsx index a8a9285..75a00d7 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,13 +3,21 @@ import ReactDOM from "react-dom/client"; import "./index.css"; import {App} from "./App"; import reportWebVitals from "./reportWebVitals"; +import { LanguageProvider } from "data/i18n"; +import { ItemProvider } from "data/item"; const root = ReactDOM.createRoot( document.getElementById("root") as HTMLElement ); root.render( - + + + + + + + ); diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index 624c875..8f71da8 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -69,3 +69,9 @@ declare module '*.module.sass' { const classes: { readonly [key: string]: string }; export default classes; } + +declare module '*.lang.yaml' { + type StringTree = { readonly [key: string]: StringTree | string }; + const classes: StringTree; + export default classes; +} diff --git a/src/setupTests.ts b/src/setupTests.ts index 1dd407a..13c2fc2 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -3,3 +3,100 @@ // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import "@testing-library/jest-dom"; +import { Command, parseCommand } from "core/command"; +import { createSimulationState, SimulationState } from "core/SimulationState"; +import { ItemStack, loadItemData, searchItemMemoized } from "data/item"; +import fs from "fs"; +import YAML from "yaml"; +const ItemDataString = fs.readFileSync("src/data/item/all.items.yaml", "utf-8"); +const ItemData = YAML.parse(ItemDataString); +expect.extend({ + toEqualItemStacks: (received, expected, equals?)=>{ + if (!Array.isArray(received)) { + return { + message: () => + `expected ${received} to be an ItemStack array`, + pass: false, + }; + } + if (received.length !== expected.length){ + return { + message: () => + `expected ${received} to equal ${expected}, but their length do not equal (${received.length} !== ${expected.length})`, + pass: false, + }; + } + for(let i = 0; i + `Differ at index ${i}, expected ${JSON.stringify(expectStack, null, 2)}, got ${JSON.stringify(receivedStack, null, 2)}`, + pass: false, + }; + } + }else if(!expectStack.equals || !expectStack.equals(receivedStack)){ + return { + message: () => + `Differ at index ${i}, expected ${JSON.stringify(expectStack, null, 2)}, got ${JSON.stringify(receivedStack, null, 2)}`, + pass: false, + }; + } + } + return { + message: () => + "ItemStack arrays are the same", + pass: true, + }; + } +}); + +const [IdMap, SearchMap] = loadItemData(ItemData); +const SearchResultMemo = {}; +const searchFunc = (word: string): ItemStack | undefined => { + return searchItemMemoized(word, IdMap, SearchMap, SearchResultMemo); +}; +const getCommandsFromString = (str: string): Command[] => { + const lines = str.split("\n"); + return lines.map(l=>parseCommand(l, searchFunc)); +}; +const runE2ESimulation = (str: string): SimulationState => { + const state = createSimulationState(); + const commands = getCommandsFromString(str); + commands.forEach(c=>c.execute(state)); + return state; +}; + +const runE2ETest = (name: string, debug: boolean): [string, string]=>{ + const script = fs.readFileSync(`src/__tests__/${name}.in.txt`, "utf-8"); + const result = runE2ESimulation(script); + const resultString = JSON.stringify(result, null, 2); + const expected = fs.readFileSync(`src/__tests__/${name}.out.txt`, "utf-8"); + + const expectedState = runE2ESimulation(expected); + const expectedString = JSON.stringify(expectedState, null, 2); + if(debug){ + fs.writeFileSync("src/__tests__/debug.actual.log", resultString, "utf-8"); + fs.writeFileSync("src/__tests__/debug.expected.log", expectedString, "utf-8"); + } + return [resultString, expectedString]; +}; + +expect.extend({ + toPassE2ESimulation: (receivedName: string, expectDebug?: boolean) => { + const [resultString, expectedString] = runE2ETest(receivedName, !!expectDebug); + if (resultString !== expectedString) { + return { + message: () => + "E2E simulation failed. Pass true to toPassE2ESimulation() to emit debug logs", + pass: false, + }; + } + return { + message: ()=>"E2E simulation passed.", + pass: true + }; + } +}); diff --git a/src/surfaces/DisplayPane.tsx b/src/surfaces/DisplayPane.tsx index 6816f23..e14bdd1 100644 --- a/src/surfaces/DisplayPane.tsx +++ b/src/surfaces/DisplayPane.tsx @@ -1,49 +1,148 @@ import clsx from "clsx"; import { DoubleItemSlot } from "components/ItemSlot"; import { TitledList } from "components/TitledList"; -import { Command } from "core/Command"; -import { parseCommand } from "core/Parser"; + import { SimulationState } from "core/SimulationState"; import Background from "assets/Background.png"; import InGameBackground from "assets/InGame.png"; -import React, { useEffect, useState } from "react"; +import React, { useMemo } from "react"; import { ItemList } from "components/ItemList"; +import { CrashScreen } from "components/CrashScreen"; +import { Emphasized } from "components/Text"; type DisplayPaneProps = { command: string, - displayIndex: number, + commandError: string|undefined, simulationState: SimulationState, overlaySave: boolean, isIconAnimated: boolean, - editCommand: (c: Command)=>void + editCommand: (c: string)=>void } -export const DisplayPane: React.FC = ({command,editCommand,displayIndex,simulationState, overlaySave, isIconAnimated})=>{ - const [commandString, setCommandString] = useState(""); - const [hasError, setHasError] = useState(false); - //const listProps = stacksToItemListProps(slots, numBroken, false); - //const listSaveProps = stacksToItemListProps(savedSlots, 0, true); - useEffect(()=>{ - if(commandString!==command){ - setCommandString(command); - setHasError(false); +export const DisplayPane: React.FC = ({ + command, + commandError, + editCommand, + simulationState, + overlaySave, + isIconAnimated +})=>{ + //const searchItem = useSearchItem(); + // const + const error = useMemo(()=>{ + if(command === ""){ + return ""; + }else if (command.startsWith("#")){ + return ""; } - - }, [command, displayIndex]); + return commandError; + }, [command, commandError]); + + let content: JSX.Element; + if(simulationState.isCrashed()){ + content = +
+ + The game has crashed (This is not a simulator bug) + + +
; + + }else if(overlaySave){ + content = +
+ + + { + (()=>{ + const doubleSlots: JSX.Element[] = []; + const gameDataSlots = simulationState.displayableGameData.getDisplayedSlots(isIconAnimated); + const inventorySlots = simulationState.displayablePouch.getDisplayedSlots(isIconAnimated); + for(let i=0;i); + } + if(gameDataSlots.length>inventorySlots.length){ + for(let i=inventorySlots.length;i); + } + }else if(inventorySlots.length > gameDataSlots.length){ + for(let i=gameDataSlots.length;i); + } + } + return doubleSlots; + })() + } + + +
+ ; + }else{ + content = + <> + +
+ + + + +
+
+ + + + +
+ ; + + } return
- = ({command,editCommand,dis boxSizing: "border-box", fontSize: "16pt", outline: "none", - }}value={commandString} + }}value={command} placeholder="Type command here..." spellCheck={false} onChange={(e)=>{ const cmdString = e.target.value; - setCommandString(cmdString); - const parsedCommand = parseCommand(cmdString); - editCommand(parsedCommand); - setHasError(cmdString!=="" &&!cmdString.startsWith("#") && !parsedCommand.isValid()); + editCommand(cmdString); }}> - + { + error &&
{error}
+ } +
- {overlaySave ? -
- - - { - (()=>{ - const doubleSlots: JSX.Element[] = []; - const gameDataSlots = simulationState.displayableGameData.getDisplayedSlots(isIconAnimated); - const inventorySlots = simulationState.displayablePouch.getDisplayedSlots(isIconAnimated); - for(let i=0;i); - } - if(gameDataSlots.length>inventorySlots.length){ - for(let i=inventorySlots.length;i); - } - }else if(inventorySlots.length > gameDataSlots.length){ - for(let i=gameDataSlots.length;i); - } - } - return doubleSlots; - })() - } - - -
- - :<> - -
- - - - -
-
- - - - -
- } + {content}
; diff --git a/src/surfaces/GalleryPage.tsx b/src/surfaces/GalleryPage.tsx new file mode 100644 index 0000000..31eb5f9 --- /dev/null +++ b/src/surfaces/GalleryPage.tsx @@ -0,0 +1,39 @@ +import { ItemSlot } from "components/ItemSlot"; +import { BodyText} from "components/Text"; +import { TitledList } from "components/TitledList"; +import { itemStackToDisplayableSlot } from "core/DisplayableInventory"; +import { useAllItems } from "data/item"; +import React, { PropsWithChildren } from "react"; + +type Prop = PropsWithChildren<{ + isIconAnimated: boolean +}>; +export const GalleryPage: React.FC = React.memo(({isIconAnimated})=>{ + const allItems = useAllItems(); + return ( +
+ +
+ + You can find every single item here. + + + The value at the bottom left of equipments is the default durability + +
+ { + Object.values(allItems).map((item, i)=>{ + return ; + }) + } +
+
+ +
+
+ ); +}); diff --git a/src/surfaces/LimitationPage.tsx b/src/surfaces/LimitationPage.tsx new file mode 100644 index 0000000..e45cf1c --- /dev/null +++ b/src/surfaces/LimitationPage.tsx @@ -0,0 +1,5 @@ +export {}; +// slot count: in game you have a limit for weapon/shield/bow and you can increase that by spending seeds at Hestu until reaching a full page +// however in sim, it assumes you have no limit whatsoever. you can have 100 weapons if you'd like + +// discover flag: affects result diff --git a/src/surfaces/ReferencePage.tsx b/src/surfaces/ReferencePage.tsx index ab70e4c..c0bb9f8 100644 --- a/src/surfaces/ReferencePage.tsx +++ b/src/surfaces/ReferencePage.tsx @@ -1,36 +1,75 @@ +import { BodyText, Emphasized, Header, SubHeader, SubTitle } from "components/Text"; import { TitledList } from "components/TitledList"; -import { getAllItems } from "core/Item"; import React from "react"; export const ReferencePage: React.FC = React.memo(()=>{ return (
- +
-

Items

- { - getAllItems().map((item, i)=>

{item}

) - } -

Commands

-

- This is a list of available commands. All commands and items are case-sensitive -

-

Initialize X item1 Y item2 Z item3 ...

-

Used for initializing inventory before simulation

-

+

Item Syntax
+ + Item are specified by using search keys and metadata. + + Search Keys + + Search keys are used to find the item. For example, in the command "Add 1 master sword", + 1 specifies the count, and master sword are 2 search keys to locate the item. + Search keys are designed to "just work", but they sometimes find the wrong item. In this case you can add more keys to narrow the search. + For example, shroom will match Rushroom, but shroom hy will match HylianShroom. + Another example, hammer will match IronSledgeHammer, but spr ham will match SpringLoadedHammer + + + In certain commands like Equip, you can only use 1 search key. In this case, you can use "*" to combine search keys into 1. + For example, snow*head is one search key that functions like snow head, which will give you the snowquill headdress + + + The order of the keys doesn't matter and they are case-insensitive. + + Number of Items + + When specifying number of items, you can use an integer or all, which is equivalent to 9999999 and can be used to remove all items without specifying the real count + + + Metadata + + Metadata is used to specify extra information. The syntax is [key1=value1,key2=value2,...]. + Metadata is not available in all commands. If you see item[meta], then it's supported in that particular command. + + + Here is a list of available metadata. More will be added as they are implemented in the future + + life (integer) + Used to specify stack size or durability + + Example: hammer[life=300] makes a hammer with 3 durability + + equip (boolean) + Used to specify if a slot is equipped + + Example: hammer[equip] makes the hammer equipped. [equip] and [equip=true] are the same + + +
Command List
+ + This is a list of available commands. All commands and items are case-insensitive + + Initialize X item1[meta] Y item2[meta] Z item3[meta] ... + Used for initializing inventory before simulation + Fully resets the inventory by clearing all items and set Count to 0, then forcefully write the item list to inventory. This would reset any broken slot you already have, and any in-game checks that happen when adding items are disabled. For example, the items will appear in the order you specify, not in the in-game tab order -

-

+ + If you specify count > 1 for unstackable items like weapon or sheika slate, multiple of that item would be added. Game Data will be synced with Visible Inventory after the reset -

-

+ + Note that this will not clear saves. You can use this command to initialize multiple saves -

-

Example: Initialize 1 Apple 2 Axe 3 Slate 4 SpiritOrb

+
+ Example: Initialize 1 Apple 2 Axe 3 Slate 4 SpiritOrb

Save

Save As NAME

@@ -66,17 +105,6 @@ export const ReferencePage: React.FC = React.memo(()=>{

Example 1: Reload

Example 2: Reload MySave

-

Use NAME

-

(Deprecated) Specify which save to load on the subsequent reload

-

- This command is only for backward compatibility. Use "Reload" instead -

-

- Specify the save named NAME to be reloaded on the next "Reload" command -

- -

Example: Use MySave

-

Break X Slots

Simulate making X broken slots with hold smuggle glitch

@@ -90,8 +118,7 @@ export const ReferencePage: React.FC = React.memo(()=>{

Example: Break 4 Slots

Get/Add/Cook/Pickup/Buy item

-

Get/Add/Cook/Pickup/Buy X item

-

Get/Add/Cook/Pickup/Buy X item1 Y item2 Z item3 ...

+

Get/Add/Cook/Pickup/Buy X item1[meta] Y item2[meta] Z item3[meta] ...

Simulate obtaining items in game

Add the item(s) to visible inventory. Sync with Game Data unless you are on Eventide or inside TOTS @@ -104,18 +131,17 @@ export const ReferencePage: React.FC = React.memo(()=>{ If you specify a count for unstackable items, they are added in different slots as if you pick them up in game, one after another.

- Note that you must not enter plural forms for the item name. + Try to avoid plural forms as they often make search fail

Example 1: Add Apple

Example 2: Get 10 Apple

-

Example 3: Pickup 10 Apple 5 Diamond 1 Slate 5 MasterSword

+

Example 3: Pickup 10 Apple 5 Diamond 1 Slate 5 MasterSword[life=700]

With/Remove/Sell/Eat/Drop item

-

With/Remove/Sell/Eat/Drop X item

With/Remove/Sell/Eat/Drop item From Slot Y

-

With/Remove/Sell/Eat/Drop X item From Slot Y

-

With/Remove/Sell/Eat/Drop X item1 Y item2 Z item3 ...

+

With/Remove/Sell/Eat/Drop X item From Slot Y

+

With/Remove/Sell/Eat/Drop X item1[meta] Y item2[meta] Z item3[meta] ...

Simulate removing items in game

Remove the item(s) to visible inventory. Sync with Game Data unless you are on Eventide or inside TOTS @@ -127,8 +153,11 @@ export const ReferencePage: React.FC = React.memo(()=>{

When slot is specified, it starts removing from slot X (slot 1 is the leftmost slot with that item, slot 2 is the second leftmost slot with that item).

+ + When removing items, the simulator will try to match the stack exactly, including metadata. If no items are found this way, the simulator will then try to match an item while ignoring the metadata +

- Note that you must not enter plural forms for the item name. + Try to avoid plural forms as they often make search fail

Example 1: Remove Apple

@@ -136,7 +165,7 @@ export const ReferencePage: React.FC = React.memo(()=>{

Example 3: Sell 10 Apple 5 Diamond

Example 4: Sell 5 Apple From Slot 3

-

D&P X item1 Y item2 Z item3 ...

+

D&P X item1[meta] Y item2[meta] Z item3[meta] ...

Shortcut for drop and pick up, for sorting inventory

This command drops and pick up each item stack in the specified order. @@ -160,6 +189,9 @@ export const ReferencePage: React.FC = React.memo(()=>{ Note that you can use this command to equip something that is already equipped, which is not possible in game. You can also equip unequippable items like materials, but it is not meaningful

+ + Note that you cannot specify metadata. If you need to equip a specific item among others of the same type, use slot to specify which +

Example 1: Equip Weapon

Example 2: Equip Weapon In Slot 3

@@ -174,6 +206,9 @@ export const ReferencePage: React.FC = React.memo(()=>{ Note that you can use this command to unequip something that is already unequipped, which is useless. You cannot unequip arrows.

+ + Note that you cannot specify metadata. If you need to equip a specific item among others of the same type, use slot to specify which +

Example 1: Unequip Shield

Example 2: Unequip Shield In Slot 5

@@ -191,12 +226,6 @@ export const ReferencePage: React.FC = React.memo(()=>{

Example: Sync GameData

-

Sort Key/Material

-

Simulates press Y to sort tab

-

- This command is currently broken -

-

Shoot X Arrow

Simulates shooting arrow without opening inventory

@@ -211,6 +240,7 @@ export const ReferencePage: React.FC = React.memo(()=>{

Example: Shoot 1 Arrow

Enter/Exit Eventide

+

Enter/Exit TOTS

Simulates entering/exiting Eventide or Trial of the Sword

When entering Eventide or TotS, the entire inventory is cleared except for key items regardless of inventory count. @@ -220,6 +250,18 @@ export const ReferencePage: React.FC = React.memo(()=>{ When exiting the challenge, the game reloads the game data as if reloading a save

Example: Enter Eventide

+ + Write [meta] To item + Write [meta] To item In Slot X + Change the metadata of item + + This can be used to modify durability on weapon or count on items. This will sync inventory to game data. + + + if you write 0 to life, it will not cause the slot to be removed + + Example: Write [life=1000] To pot lid + Example: Write [life=1000] To pot lid In Slot 3