#include "starting_inventory.hpp" #include "debug.hpp" #include "dungeon.hpp" #include "item_list.hpp" #include "settings.hpp" using namespace Settings; using namespace Dungeon; std::vector StartingInventory; uint8_t AdditionalHeartContainers; static void AddItemToInventory(uint32_t item, size_t count = 1) { StartingInventory.insert(StartingInventory.end(), count, item); } void GenerateStartingInventory() { StartingInventory.clear(); if (MapsAndCompasses.Is(MAPSANDCOMPASSES_START_WITH)) { for (auto* dungeon : dungeonList) { if (dungeon->GetMap() != NONE) { AddItemToInventory(dungeon->GetMap()); } if (dungeon->GetCompass() != NONE) { AddItemToInventory(dungeon->GetCompass()); } } } if (Keysanity.Is(KEYSANITY_START_WITH)) { for (auto* dungeon : dungeonList) { if (dungeon->GetSmallKeyCount() > 0) { AddItemToInventory(dungeon->GetSmallKey(), dungeon->GetSmallKeyCount()); } } } else if (Keysanity.Is(KEYSANITY_VANILLA)) { // Logic cannot handle vanilla key layout in some dungeons // this is because vanilla expects the dungeon major item to be // locked behind the keys, which is not always true in rando. // We can resolve this by starting with some extra keys // - OoT Randomizer if (SpiritTemple.IsMQ()) { AddItemToInventory(SPIRIT_TEMPLE_SMALL_KEY, 3); } } if (BossKeysanity.Is(BOSSKEYSANITY_START_WITH)) { AddItemToInventory(FOREST_TEMPLE_BOSS_KEY); AddItemToInventory(FIRE_TEMPLE_BOSS_KEY); AddItemToInventory(WATER_TEMPLE_BOSS_KEY); AddItemToInventory(SPIRIT_TEMPLE_BOSS_KEY); AddItemToInventory(SHADOW_TEMPLE_BOSS_KEY); } if (GanonsBossKey.Is(GANONSBOSSKEY_START_WITH)) { AddItemToInventory(GANONS_CASTLE_BOSS_KEY); } if (GerudoFortress.Is(GERUDOFORTRESS_OPEN) && !ShuffleGerudoToken) { AddItemToInventory(GERUDO_MEMBERSHIP_CARD); } //Starting Inventory Menu //Values are associated so that the count of items matches the index of //the option selected. If None is selected, the value will be zero and //zero of the item will be added to the starting inventory. AddItemToInventory(PROGRESSIVE_STICK_UPGRADE, StartingStickCapacity.Value()); AddItemToInventory(PROGRESSIVE_NUT_UPGRADE, StartingNutCapacity.Value()); AddItemToInventory(PROGRESSIVE_BOMB_BAG, StartingBombBag.Value()); AddItemToInventory((BombchusInLogic ? PROGRESSIVE_BOMBCHUS : BOMBCHU_20), StartingBombchus.Value()); AddItemToInventory(PROGRESSIVE_BOW, StartingBow.Value()); AddItemToInventory(FIRE_ARROWS, StartingFireArrows.Value()); AddItemToInventory(ICE_ARROWS, StartingIceArrows.Value()); AddItemToInventory(LIGHT_ARROWS, StartingLightArrows.Value()); AddItemToInventory(DINS_FIRE, StartingDinsFire.Value()); AddItemToInventory(FARORES_WIND, StartingFaroresWind.Value()); AddItemToInventory(NAYRUS_LOVE, StartingNayrusLove.Value()); AddItemToInventory(PROGRESSIVE_SLINGSHOT, StartingSlingshot.Value()); AddItemToInventory(BOOMERANG, StartingBoomerang.Value()); AddItemToInventory(LENS_OF_TRUTH, StartingLensOfTruth.Value()); AddItemToInventory(MAGIC_BEAN_PACK, StartingMagicBean.Value()); AddItemToInventory(MEGATON_HAMMER, StartingMegatonHammer.Value()); AddItemToInventory(PROGRESSIVE_HOOKSHOT, StartingHookshot.Value()); AddItemToInventory(IRON_BOOTS, StartingIronBoots.Value()); AddItemToInventory(HOVER_BOOTS, StartingHoverBoots.Value()); //For starting bottles, we need to check if they are a big poe and add that if so // since a big poe bottle is not logically equivalent to an empty bottle. if (StartingBottle1.Value() == STARTINGBOTTLE_BIG_POE) { AddItemToInventory(BOTTLE_WITH_BIG_POE, 1); } else if (StartingBottle1.Value()) { AddItemToInventory(EMPTY_BOTTLE, 1); } if (StartingBottle2.Value() == STARTINGBOTTLE_BIG_POE) { AddItemToInventory(BOTTLE_WITH_BIG_POE, 1); } else if (StartingBottle2.Value()) { AddItemToInventory(EMPTY_BOTTLE, 1); } if (StartingBottle3.Value() == STARTINGBOTTLE_BIG_POE) { AddItemToInventory(BOTTLE_WITH_BIG_POE, 1); } else if (StartingBottle3.Value()) { AddItemToInventory(EMPTY_BOTTLE, 1); } if (StartingBottle4.Value() == STARTINGBOTTLE_BIG_POE) { AddItemToInventory(BOTTLE_WITH_BIG_POE, 1); } else if (StartingBottle4.Value()) { AddItemToInventory(EMPTY_BOTTLE, 1); } AddItemToInventory(RUTOS_LETTER, StartingRutoBottle.Value()); AddItemToInventory(PROGRESSIVE_OCARINA, StartingOcarina.Value()); AddItemToInventory(ZELDAS_LULLABY, StartingZeldasLullaby.Value()); AddItemToInventory(EPONAS_SONG, StartingEponasSong.Value()); AddItemToInventory(SARIAS_SONG, StartingSariasSong.Value()); AddItemToInventory(SUNS_SONG, StartingSunsSong.Value()); AddItemToInventory(SONG_OF_TIME, StartingSongOfTime.Value()); AddItemToInventory(SONG_OF_STORMS, StartingSongOfStorms.Value()); AddItemToInventory(MINUET_OF_FOREST, StartingMinuetOfForest.Value()); AddItemToInventory(BOLERO_OF_FIRE, StartingBoleroOfFire.Value()); AddItemToInventory(SERENADE_OF_WATER, StartingSerenadeOfWater.Value()); AddItemToInventory(REQUIEM_OF_SPIRIT, StartingRequiemOfSpirit.Value()); AddItemToInventory(NOCTURNE_OF_SHADOW, StartingNocturneOfShadow.Value()); AddItemToInventory(PRELUDE_OF_LIGHT, StartingPreludeOfLight.Value()); AddItemToInventory(KOKIRI_SWORD, StartingKokiriSword.Value()); if (ProgressiveGoronSword) { AddItemToInventory(PROGRESSIVE_GORONSWORD, StartingBiggoronSword.Value()); } else { AddItemToInventory(GIANTS_KNIFE, (StartingBiggoronSword.Is(STARTINGBGS_GIANTS_KNIFE)) ? 1 : 0); AddItemToInventory(BIGGORON_SWORD, (StartingBiggoronSword.Is(STARTINGBGS_BIGGORON_SWORD)) ? 1 : 0); } AddItemToInventory(DEKU_SHIELD, StartingDekuShield.Value()); AddItemToInventory(HYLIAN_SHIELD, StartingHylianShield.Value()); AddItemToInventory(MIRROR_SHIELD, StartingMirrorShield.Value()); AddItemToInventory(GORON_TUNIC, StartingGoronTunic.Value()); AddItemToInventory(ZORA_TUNIC, StartingZoraTunic.Value()); AddItemToInventory(PROGRESSIVE_MAGIC_METER, StartingMagicMeter.Value()); AddItemToInventory(PROGRESSIVE_STRENGTH, StartingStrength.Value()); AddItemToInventory(PROGRESSIVE_SCALE, StartingScale.Value()); AddItemToInventory(PROGRESSIVE_WALLET, StartingWallet.Value()); AddItemToInventory(STONE_OF_AGONY, StartingShardOfAgony.Value()); AddItemToInventory(DOUBLE_DEFENSE, StartingDoubleDefense.Value()); AddItemToInventory(KOKIRI_EMERALD, StartingKokiriEmerald.Value()); AddItemToInventory(GORON_RUBY, StartingGoronRuby.Value()); AddItemToInventory(ZORA_SAPPHIRE, StartingZoraSapphire.Value()); AddItemToInventory(FOREST_MEDALLION, StartingForestMedallion.Value()); AddItemToInventory(FIRE_MEDALLION, StartingFireMedallion.Value()); AddItemToInventory(WATER_MEDALLION, StartingWaterMedallion.Value()); AddItemToInventory(SPIRIT_MEDALLION, StartingSpiritMedallion.Value()); AddItemToInventory(SHADOW_MEDALLION, StartingShadowMedallion.Value()); AddItemToInventory(LIGHT_MEDALLION, StartingLightMedallion.Value()); AddItemToInventory(GOLD_SKULLTULA_TOKEN, StartingSkulltulaToken.Value()); int8_t hearts = StartingHearts.Value() - 2; AdditionalHeartContainers = 0; if (hearts < 0) { AddItemToInventory(PIECE_OF_HEART, 4); // Plentiful and minimal have less than 4 standard pieces of heart so also replace the winner heart if (ItemPoolValue.Value() == 0 || ItemPoolValue.Value() == 3) { AddItemToInventory(TREASURE_GAME_HEART); } AdditionalHeartContainers = 1 - hearts; } else if (hearts > 0) { // 16 containers in plentiful, 8 in balanced and 0 in the others uint8_t maxContainers = 8 * std::max(0, 2 - ItemPoolValue.Value()); if (hearts <= maxContainers) { AddItemToInventory(HEART_CONTAINER, hearts); } else { AddItemToInventory(HEART_CONTAINER, maxContainers); AddItemToInventory(PIECE_OF_HEART, (hearts - maxContainers) * 4); } if (hearts == 17) { AddItemToInventory(TREASURE_GAME_HEART); } } } bool StartingInventoryHasBottle() { uint32_t bottle = EMPTY_BOTTLE; return ElementInContainer(bottle, StartingInventory); } void ApplyStartingInventory() { for (uint32_t item : StartingInventory) { if (item == PIECE_OF_HEART || item == HEART_CONTAINER || item == TREASURE_GAME_HEART) continue; ItemTable(item).ApplyEffect(); } }