Shipwright/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp

1180 lines
35 KiB
C++

#include "item_pool.hpp"
#include "dungeon.hpp"
#include "fill.hpp"
#include "item_list.hpp"
#include "item_location.hpp"
#include "pool_functions.hpp"
#include "random.hpp"
#include "settings.hpp"
#include "spoiler_log.hpp"
#include "z64item.h"
#include <Lib/spdlog/include/spdlog/spdlog.h>
using namespace Settings;
using namespace Dungeon;
std::vector<uint32_t> ItemPool = {};
std::vector<uint32_t> PendingJunkPool = {};
std::vector<uint8_t> IceTrapModels = {};
const std::array<uint32_t, 9> dungeonRewards = {
KOKIRI_EMERALD,
GORON_RUBY,
ZORA_SAPPHIRE,
FOREST_MEDALLION,
FIRE_MEDALLION,
WATER_MEDALLION,
SPIRIT_MEDALLION,
SHADOW_MEDALLION,
LIGHT_MEDALLION,
};
const std::array<uint32_t, 16> JunkPoolItems = {
BOMBS_5,
BOMBS_10,
BOMBS_20,
DEKU_NUTS_5,
DEKU_STICK_1,
DEKU_SEEDS_30,
RECOVERY_HEART,
ARROWS_5,
ARROWS_10,
ARROWS_30,
BLUE_RUPEE,
RED_RUPEE,
PURPLE_RUPEE,
HUGE_RUPEE,
DEKU_NUTS_10,
ICE_TRAP,
};
const std::array<uint32_t, 59> alwaysItems = {
BIGGORON_SWORD,
BOOMERANG,
LENS_OF_TRUTH,
MEGATON_HAMMER,
IRON_BOOTS,
GORON_TUNIC,
ZORA_TUNIC,
HOVER_BOOTS,
MIRROR_SHIELD,
STONE_OF_AGONY,
FIRE_ARROWS,
ICE_ARROWS,
LIGHT_ARROWS,
DINS_FIRE,
FARORES_WIND,
NAYRUS_LOVE,
GREEN_RUPEE,
PROGRESSIVE_HOOKSHOT, //2 progressive hookshots
PROGRESSIVE_HOOKSHOT,
DEKU_SHIELD,
HYLIAN_SHIELD,
PROGRESSIVE_STRENGTH, //3 progressive strength upgrades
PROGRESSIVE_STRENGTH,
PROGRESSIVE_STRENGTH,
PROGRESSIVE_SCALE, //2 progressive scales
PROGRESSIVE_SCALE,
PROGRESSIVE_BOW, //3 progressive Bows
PROGRESSIVE_BOW,
PROGRESSIVE_BOW,
PROGRESSIVE_SLINGSHOT, //3 progressive bullet bags
PROGRESSIVE_SLINGSHOT,
PROGRESSIVE_SLINGSHOT,
PROGRESSIVE_BOMB_BAG, //3 progressive bomb bags
PROGRESSIVE_BOMB_BAG,
PROGRESSIVE_BOMB_BAG,
PROGRESSIVE_WALLET, //2 progressive wallets
PROGRESSIVE_WALLET,
PROGRESSIVE_MAGIC_METER, //2 progressive magic meters
PROGRESSIVE_MAGIC_METER,
DOUBLE_DEFENSE,
PROGRESSIVE_STICK_UPGRADE, //2 stick upgrades
PROGRESSIVE_STICK_UPGRADE,
PROGRESSIVE_NUT_UPGRADE, //2 nut upgrades
PROGRESSIVE_NUT_UPGRADE,
RECOVERY_HEART, //6 recovery hearts
RECOVERY_HEART,
RECOVERY_HEART,
RECOVERY_HEART,
RECOVERY_HEART,
RECOVERY_HEART,
BOMBS_5, //2
BOMBS_5,
BOMBS_10,
BOMBS_20,
ARROWS_5,
ARROWS_10, //5
ARROWS_10,
ARROWS_10,
TREASURE_GAME_HEART,
};
const std::array<uint32_t, 43> easyItems = {
BIGGORON_SWORD,
KOKIRI_SWORD,
BOOMERANG,
LENS_OF_TRUTH,
MEGATON_HAMMER,
IRON_BOOTS,
GORON_TUNIC,
ZORA_TUNIC,
HOVER_BOOTS,
MIRROR_SHIELD,
FIRE_ARROWS,
LIGHT_ARROWS,
DINS_FIRE,
PROGRESSIVE_HOOKSHOT,
PROGRESSIVE_STRENGTH,
PROGRESSIVE_SCALE,
PROGRESSIVE_WALLET,
PROGRESSIVE_MAGIC_METER,
PROGRESSIVE_STICK_UPGRADE,
PROGRESSIVE_NUT_UPGRADE,
PROGRESSIVE_BOW,
PROGRESSIVE_SLINGSHOT,
PROGRESSIVE_BOMB_BAG,
DOUBLE_DEFENSE,
HEART_CONTAINER, //16 Heart Containers
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
PIECE_OF_HEART, //3 heart pieces
PIECE_OF_HEART,
PIECE_OF_HEART,
};
const std::array<uint32_t, 43> normalItems = {
PIECE_OF_HEART, //35 pieces of heart
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
PIECE_OF_HEART,
HEART_CONTAINER, //8 heart containers
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
HEART_CONTAINER,
};
const std::array<uint32_t, 2> DT_Vanilla = {
RECOVERY_HEART,
RECOVERY_HEART,
};
const std::array<uint32_t, 3> DT_MQ = {
DEKU_SHIELD,
DEKU_SHIELD,
PURPLE_RUPEE,
};
const std::array<uint32_t, 1> DC_Vanilla = {
RED_RUPEE,
};
const std::array<uint32_t, 2> DC_MQ = {
HYLIAN_SHIELD,
BLUE_RUPEE,
};
const std::array<uint32_t, 7> JB_MQ = {
DEKU_NUTS_5,
DEKU_NUTS_5,
DEKU_NUTS_5,
DEKU_NUTS_5,
RECOVERY_HEART,
DEKU_SHIELD,
DEKU_STICK_1,
};
const std::array<uint32_t, 3> FoT_Vanilla = {
RECOVERY_HEART,
ARROWS_10,
ARROWS_30,
};
const std::array<uint32_t, 1> FoT_MQ = {
ARROWS_5,
};
const std::array<uint32_t, 1> FiT_Vanilla = {
HUGE_RUPEE,
};
const std::array<uint32_t, 2> FiT_MQ = {
BOMBS_20,
HYLIAN_SHIELD,
};
const std::array<uint32_t, 4> SpT_Vanilla = {
DEKU_SHIELD,
DEKU_SHIELD,
RECOVERY_HEART,
BOMBS_20,
};
const std::array<uint32_t, 3> SpT_MQ = {
PURPLE_RUPEE,
PURPLE_RUPEE,
ARROWS_30,
};
const std::array<uint32_t, 1> ShT_Vanilla = {
ARROWS_30,
};
const std::array<uint32_t, 3> ShT_MQ = {
ARROWS_5,
ARROWS_5,
RED_RUPEE,
};
const std::array<uint32_t, 7> BW_Vanilla = {
RECOVERY_HEART,
BOMBS_10,
HUGE_RUPEE,
DEKU_NUTS_5,
DEKU_NUTS_10,
DEKU_SHIELD,
HYLIAN_SHIELD,
};
const std::array<uint32_t, 4> GTG_Vanilla = {
ARROWS_30,
ARROWS_30,
ARROWS_30,
HUGE_RUPEE,
};
const std::array<uint32_t, 5> GTG_MQ = {
TREASURE_GAME_GREEN_RUPEE,
TREASURE_GAME_GREEN_RUPEE,
ARROWS_10,
GREEN_RUPEE,
PURPLE_RUPEE,
};
const std::array<uint32_t, 4> GC_Vanilla = {
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
ARROWS_30,
};
const std::array<uint32_t, 5> GC_MQ = {
ARROWS_10,
ARROWS_10,
BOMBS_5,
RED_RUPEE,
RECOVERY_HEART,
};
const std::array<uint32_t, 11> normalBottles = {
EMPTY_BOTTLE,
BOTTLE_WITH_MILK,
BOTTLE_WITH_RED_POTION,
BOTTLE_WITH_GREEN_POTION,
BOTTLE_WITH_BLUE_POTION,
BOTTLE_WITH_FAIRY,
BOTTLE_WITH_FISH,
BOTTLE_WITH_BUGS,
BOTTLE_WITH_POE,
BOTTLE_WITH_BIG_POE,
BOTTLE_WITH_BLUE_FIRE,
};
const std::array<uint32_t, 28> normalRupees = {
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
HUGE_RUPEE,
HUGE_RUPEE,
HUGE_RUPEE,
};
const std::array<uint32_t, 28> shopsanityRupees = {
BLUE_RUPEE,
BLUE_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
RED_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
PURPLE_RUPEE,
HUGE_RUPEE,
HUGE_RUPEE,
HUGE_RUPEE,
HUGE_RUPEE,
HUGE_RUPEE,
PROGRESSIVE_WALLET,
};
const std::array<uint32_t, 19> dekuScrubItems = {
DEKU_NUTS_5,
DEKU_NUTS_5,
DEKU_NUTS_5,
DEKU_NUTS_5,
DEKU_NUTS_5,
DEKU_STICK_1,
BOMBS_5,
BOMBS_5,
BOMBS_5,
BOMBS_5,
BOMBS_5,
RECOVERY_HEART,
RECOVERY_HEART,
RECOVERY_HEART,
RECOVERY_HEART,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
BLUE_RUPEE,
};
const std::array<uint32_t, 12> songList = {
ZELDAS_LULLABY,
EPONAS_SONG,
SUNS_SONG,
SARIAS_SONG,
SONG_OF_TIME,
SONG_OF_STORMS,
MINUET_OF_FOREST,
PRELUDE_OF_LIGHT,
BOLERO_OF_FIRE,
SERENADE_OF_WATER,
NOCTURNE_OF_SHADOW,
REQUIEM_OF_SPIRIT,
};
const std::array<uint32_t, 10> tradeItems = {
POCKET_EGG,
//POCKET_CUCCO,
COJIRO,
ODD_MUSHROOM,
POACHERS_SAW,
BROKEN_SWORD,
PRESCRIPTION,
EYEBALL_FROG,
EYEDROPS,
CLAIM_CHECK,
};
void AddItemToPool(std::vector<uint32_t>& pool, uint32_t item, size_t count /*= 1*/) {
pool.insert(pool.end(), count, item);
}
template <typename FromPool>
static void AddItemsToPool(std::vector<uint32_t>& toPool, const FromPool& fromPool) {
AddElementsToPool(toPool, fromPool);
}
static void AddItemToMainPool(const uint32_t item, size_t count = 1) {
ItemPool.insert(ItemPool.end(), count, item);
}
static void AddRandomBottle(std::vector<uint32_t>& bottlePool) {
AddItemToMainPool(RandomElement(bottlePool, true));
}
uint32_t GetJunkItem() {
if (IceTrapValue.Is(ICETRAPS_MAYHEM) || IceTrapValue.Is(ICETRAPS_ONSLAUGHT)) {
return ICE_TRAP;
} else if (IceTrapValue.Is(ICETRAPS_EXTRA)) {
return RandomElement(JunkPoolItems);
}
//Ice Trap is the last item in JunkPoolItems, so subtract 1 to never hit that index
uint8_t idx = Random(0, JunkPoolItems.size() - 1);
return JunkPoolItems[idx];
}
static uint32_t GetPendingJunkItem() {
if (PendingJunkPool.empty()) {
return GetJunkItem();
}
return RandomElement(PendingJunkPool, true);
}
//Replace junk items in the pool with pending junk
static void ReplaceMaxItem(const uint32_t itemToReplace, int max) {
int itemCount = 0;
for (size_t i = 0; i < ItemPool.size(); i++) {
if (ItemPool[i] == itemToReplace) {
if (itemCount >= max) {
ItemPool[i] = GetJunkItem();
}
itemCount++;
}
}
}
void PlaceJunkInExcludedLocation(const uint32_t il) {
//place a non-advancement item in this location
for (size_t i = 0; i < ItemPool.size(); i++) {
if (!ItemTable(ItemPool[i]).IsAdvancement()) {
PlaceItemInLocation(il, ItemPool[i]);
ItemPool.erase(ItemPool.begin() + i);
return;
}
}
printf("ERROR: No Junk to Place!!!\n");
}
static void PlaceVanillaDekuScrubItems() {
PlaceItemInLocation(ZR_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true);
PlaceItemInLocation(ZR_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true);
PlaceItemInLocation(SFM_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true);
PlaceItemInLocation(SFM_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true);
PlaceItemInLocation(LH_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true);
PlaceItemInLocation(LH_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true);
PlaceItemInLocation(LH_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true);
PlaceItemInLocation(GV_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true);
PlaceItemInLocation(GV_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true);
PlaceItemInLocation(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, DEKU_NUTS_5, false, true);
PlaceItemInLocation(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, DEKU_STICK_1, false, true);
PlaceItemInLocation(LW_DEKU_SCRUB_GROTTO_REAR, DEKU_SEEDS_30, false, true);
PlaceItemInLocation(COLOSSUS_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true);
PlaceItemInLocation(COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true);
PlaceItemInLocation(DMC_DEKU_SCRUB, BOMBS_5, false, true);
PlaceItemInLocation(DMC_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true);
PlaceItemInLocation(DMC_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true);
PlaceItemInLocation(DMC_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true);
PlaceItemInLocation(GC_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true);
PlaceItemInLocation(GC_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true);
PlaceItemInLocation(GC_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true);
PlaceItemInLocation(LLR_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true);
PlaceItemInLocation(LLR_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true);
PlaceItemInLocation(LLR_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true);
//Dungeon Scrubs
if (DekuTree.IsMQ()) {
PlaceItemInLocation(DEKU_TREE_MQ_DEKU_SCRUB, DEKU_SHIELD, false, true);
}
if (DodongosCavern.IsMQ()) {
PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, DEKU_STICK_1, false, true);
PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, DEKU_SEEDS_30, false, true);
PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, DEKU_SHIELD, false, true);
PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, RED_POTION_REFILL, false, true);
} else {
PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, DEKU_NUTS_5, false, true);
PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, DEKU_STICK_1, false, true);
PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, DEKU_SEEDS_30, false, true);
PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, DEKU_SHIELD, false, true);
}
if (JabuJabusBelly.IsVanilla()) {
PlaceItemInLocation(JABU_JABUS_BELLY_DEKU_SCRUB, DEKU_NUTS_5);
}
if (GanonsCastle.IsMQ()) {
PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, GREEN_POTION_REFILL, false, true);
PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, BOMBS_5, false, true);
PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, ARROWS_30, false, true);
PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, RED_POTION_REFILL, false, true);
PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, DEKU_NUTS_5, false, true);
} else {
PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, BOMBS_5, false, true);
PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, DEKU_SEEDS_30, false, true);
PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_RIGHT, RED_POTION_REFILL, false, true);
PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_LEFT, GREEN_POTION_REFILL, false, true);
}
}
static void PlaceVanillaMapsAndCompasses() {
for (auto dungeon : dungeonList) {
dungeon->PlaceVanillaMap();
dungeon->PlaceVanillaCompass();
}
}
static void PlaceVanillaSmallKeys() {
for (auto dungeon : dungeonList) {
dungeon->PlaceVanillaSmallKeys();
}
}
static void PlaceVanillaBossKeys() {
for (auto dungeon : dungeonList) {
dungeon->PlaceVanillaBossKey();
}
}
static void PlaceVanillaCowMilk() {
PlaceItemInLocation(KF_LINKS_HOUSE_COW, MILK, false, true);
PlaceItemInLocation(HF_COW_GROTTO_COW, MILK, false, true);
PlaceItemInLocation(GV_COW, MILK, false, true);
PlaceItemInLocation(KAK_IMPAS_HOUSE_COW, MILK, false, true);
PlaceItemInLocation(DMT_COW_GROTTO_COW, MILK, false, true);
PlaceItemInLocation(LLR_STABLES_LEFT_COW, MILK, false, true);
PlaceItemInLocation(LLR_STABLES_RIGHT_COW, MILK, false, true);
PlaceItemInLocation(LLR_TOWER_LEFT_COW, MILK, false, true);
PlaceItemInLocation(LLR_TOWER_RIGHT_COW, MILK, false, true);
if (JabuJabusBelly.IsMQ()) {
PlaceItemInLocation(JABU_JABUS_BELLY_MQ_COW, MILK, false, true);
}
}
static void SetScarceItemPool() {
ReplaceMaxItem(PROGRESSIVE_BOMBCHUS, 3);
ReplaceMaxItem(BOMBCHU_5, 1);
ReplaceMaxItem(BOMBCHU_10, 2);
ReplaceMaxItem(BOMBCHU_20, 0);
ReplaceMaxItem(PROGRESSIVE_MAGIC_METER, 1);
ReplaceMaxItem(DOUBLE_DEFENSE, 0);
ReplaceMaxItem(PROGRESSIVE_STICK_UPGRADE, 1);
ReplaceMaxItem(PROGRESSIVE_NUT_UPGRADE, 1);
ReplaceMaxItem(PROGRESSIVE_BOW, 2);
ReplaceMaxItem(PROGRESSIVE_SLINGSHOT, 2);
ReplaceMaxItem(PROGRESSIVE_BOMB_BAG, 2);
ReplaceMaxItem(HEART_CONTAINER, 0);
}
static void SetMinimalItemPool() {
ReplaceMaxItem(PROGRESSIVE_BOMBCHUS, 1);
ReplaceMaxItem(BOMBCHU_5, 1);
ReplaceMaxItem(BOMBCHU_10, 0);
ReplaceMaxItem(BOMBCHU_20, 0);
ReplaceMaxItem(NAYRUS_LOVE, 0);
ReplaceMaxItem(PROGRESSIVE_MAGIC_METER, 1);
ReplaceMaxItem(DOUBLE_DEFENSE, 0);
ReplaceMaxItem(PROGRESSIVE_STICK_UPGRADE, 0);
ReplaceMaxItem(PROGRESSIVE_NUT_UPGRADE, 0);
ReplaceMaxItem(PROGRESSIVE_BOW, 1);
ReplaceMaxItem(PROGRESSIVE_SLINGSHOT, 1);
ReplaceMaxItem(PROGRESSIVE_BOMB_BAG, 1);
ReplaceMaxItem(PIECE_OF_HEART, 0);
// Need an extra heart container when starting with 1 heart to be able to reach 3 hearts
ReplaceMaxItem(HEART_CONTAINER, (StartingHearts.Value<uint8_t>() == 18)? 1 : 0);
}
void GenerateItemPool() {
ItemPool.clear();
PendingJunkPool.clear();
//Initialize ice trap models to always major items
IceTrapModels = {
GI_SHIELD_MIRROR,
GI_BOOMERANG,
GI_LENS,
GI_HAMMER,
GI_BOOTS_IRON,
GI_BOOTS_HOVER,
GI_STONE_OF_AGONY,
GI_DINS_FIRE,
GI_FARORES_WIND,
GI_NAYRUS_LOVE,
GI_ARROW_FIRE,
GI_ARROW_ICE,
GI_ARROW_LIGHT,
0xB8, //Double defense
GI_CLAIM_CHECK,
0x80, //Progressive hookshot
0x81, //Progressive strength
0x82, //Progressive bomb bag
0x83, //Progressive bow
0x84, //Progressive slingshot
0x85, //Progressive wallet
0x86, //Progressive scale
0x8A, //Progressive magic
};
//Check song shuffle and dungeon reward shuffle just for ice traps
if (ShuffleSongs.Is(SONGSHUFFLE_ANYWHERE)) {
//Push item ids for songs
IceTrapModels.push_back(0xC1);
IceTrapModels.push_back(0xC2);
IceTrapModels.push_back(0xC3);
IceTrapModels.push_back(0xC4);
IceTrapModels.push_back(0xC5);
IceTrapModels.push_back(0xC6);
IceTrapModels.push_back(0xBB);
IceTrapModels.push_back(0xBC);
IceTrapModels.push_back(0xBD);
IceTrapModels.push_back(0xBE);
IceTrapModels.push_back(0xBF);
IceTrapModels.push_back(0xC0);
}
if (ShuffleRewards.Is(REWARDSHUFFLE_ANYWHERE)) {
//Push item ids for dungeon rewards
IceTrapModels.push_back(0xCB);
IceTrapModels.push_back(0xCC);
IceTrapModels.push_back(0xCD);
IceTrapModels.push_back(0xCE);
IceTrapModels.push_back(0xCF);
IceTrapModels.push_back(0xD0);
IceTrapModels.push_back(0xD1);
IceTrapModels.push_back(0xD2);
IceTrapModels.push_back(0xD3);
}
//Fixed item locations
PlaceItemInLocation(HC_ZELDAS_LETTER, ZELDAS_LETTER);
PlaceItemInLocation(GANON, TRIFORCE); //The Triforce is only used to make sure Ganon is accessible
PlaceItemInLocation(MARKET_BOMBCHU_BOWLING_BOMBCHUS, BOMBCHU_DROP);
if (ShuffleKokiriSword) {
AddItemToMainPool(KOKIRI_SWORD);
IceTrapModels.push_back(GI_SWORD_KOKIRI);
} else {
PlaceItemInLocation(KF_KOKIRI_SWORD_CHEST, KOKIRI_SWORD, false, true);
}
if (ShuffleWeirdEgg) {
AddItemToMainPool(WEIRD_EGG);
IceTrapModels.push_back(GI_WEIRD_EGG);
} else {
PlaceItemInLocation(HC_MALON_EGG, WEIRD_EGG, false, true);
}
if (ShuffleOcarinas) {
AddItemToMainPool(PROGRESSIVE_OCARINA, 2);
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
AddItemToPool(PendingJunkPool, PROGRESSIVE_OCARINA);
}
IceTrapModels.push_back(0x8B); //Progressive ocarina
} else {
PlaceItemInLocation(LW_GIFT_FROM_SARIA, PROGRESSIVE_OCARINA, false, true);
PlaceItemInLocation(HF_OCARINA_OF_TIME_ITEM, PROGRESSIVE_OCARINA, false, true);
}
if (ShuffleCows) {
//9 total cow locations
for (uint8_t i = 0; i < 9; i++) {
AddItemToMainPool(GetJunkItem());
}
//extra location for Jabu MQ
if (JabuJabusBelly.IsMQ()) {
AddItemToMainPool(GetJunkItem());
}
} else {
PlaceVanillaCowMilk();
}
if (ShuffleMagicBeans) {
AddItemToMainPool(MAGIC_BEAN_PACK);
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
AddItemToPool(PendingJunkPool, MAGIC_BEAN_PACK);
}
IceTrapModels.push_back(0xC9); //Magic bean pack
} else {
PlaceItemInLocation(ZR_MAGIC_BEAN_SALESMAN, MAGIC_BEAN, false, true);
}
if (ShuffleMerchants.IsNot(SHUFFLEMERCHANTS_OFF)) {
if (!ProgressiveGoronSword) {
AddItemToMainPool(GIANTS_KNIFE);
}
if (BombchusInLogic) {
AddItemToMainPool(PROGRESSIVE_BOMBCHUS);
} else {
AddItemToMainPool(BOMBCHU_10);
}
} else {
PlaceItemInLocation(GC_MEDIGORON, GIANTS_KNIFE, false, true);
PlaceItemInLocation(WASTELAND_BOMBCHU_SALESMAN, BOMBCHU_10, false, true);
}
if (ShuffleAdultTradeQuest) {
AddItemToMainPool(POCKET_EGG);
AddItemToMainPool(COJIRO);
AddItemToMainPool(ODD_MUSHROOM);
AddItemToMainPool(ODD_POTION);
AddItemToMainPool(POACHERS_SAW);
AddItemToMainPool(BROKEN_SWORD);
AddItemToMainPool(PRESCRIPTION);
AddItemToMainPool(EYEBALL_FROG);
AddItemToMainPool(EYEDROPS);
} else {
PlaceItemInLocation(KAK_TRADE_POCKET_CUCCO, COJIRO, false, true);
PlaceItemInLocation(LW_TRADE_COJIRO, ODD_MUSHROOM, false, true);
PlaceItemInLocation(KAK_TRADE_ODD_MUSHROOM, ODD_POTION, false, true);
PlaceItemInLocation(LW_TRADE_ODD_POTION, POACHERS_SAW, false, true);
PlaceItemInLocation(GV_TRADE_SAW, BROKEN_SWORD, false, true);
PlaceItemInLocation(DMT_TRADE_BROKEN_SWORD, PRESCRIPTION, false, true);
PlaceItemInLocation(ZD_TRADE_PRESCRIPTION, EYEBALL_FROG, false, true);
PlaceItemInLocation(LH_TRADE_FROG, EYEDROPS, false, true);
PlaceItemInLocation(DMT_TRADE_EYEDROPS, CLAIM_CHECK, false, true);
}
AddItemToMainPool(CLAIM_CHECK);
if (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS)) {
AddItemToMainPool(TREASURE_GAME_SMALL_KEY, 6); // 6 individual keys
} else if (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK)) {
AddItemToMainPool(TREASURE_GAME_SMALL_KEY); // 1 key which will behave as a pack of 6
} else {
PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_1, TREASURE_GAME_SMALL_KEY, false, true);
PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_2, TREASURE_GAME_SMALL_KEY, false, true);
PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_3, TREASURE_GAME_SMALL_KEY, false, true);
PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_4, TREASURE_GAME_SMALL_KEY, false, true);
PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_5, TREASURE_GAME_SMALL_KEY, false, true);
};
if (Tokensanity.Is(TOKENSANITY_OFF)) {
for (uint32_t loc : GetLocations(allLocations, Category::cSkulltula)) {
PlaceItemInLocation(loc, GOLD_SKULLTULA_TOKEN, false, true);
}
} else if (Tokensanity.Is(TOKENSANITY_DUNGEONS)) {
for (uint32_t loc : GetLocations(allLocations, Category::cSkulltula)) {
if (Location(loc)->IsOverworld()) {
PlaceItemInLocation(loc, GOLD_SKULLTULA_TOKEN, false, true);
} else {
AddItemToMainPool(GOLD_SKULLTULA_TOKEN);
}
}
} else if (Tokensanity.Is(TOKENSANITY_OVERWORLD)) {
for (uint32_t loc : GetLocations(allLocations, Category::cSkulltula)) {
if (Location(loc)->IsDungeon()) {
PlaceItemInLocation(loc, GOLD_SKULLTULA_TOKEN, false, true);
} else {
AddItemToMainPool(GOLD_SKULLTULA_TOKEN);
}
}
} else {
AddItemToMainPool(GOLD_SKULLTULA_TOKEN, 100);
}
if (BombchusInLogic) {
AddItemToMainPool(PROGRESSIVE_BOMBCHUS, 5);
} else {
AddItemToMainPool(BOMBCHU_5);
AddItemToMainPool(BOMBCHU_10, 3);
AddItemToMainPool(BOMBCHU_20);
}
//Ice Traps
AddItemToMainPool(ICE_TRAP);
if (GerudoTrainingGrounds.IsVanilla()) {
AddItemToMainPool(ICE_TRAP);
}
if (GanonsCastle.IsVanilla()) {
AddItemToMainPool(ICE_TRAP, 4);
}
//Gerudo Fortress
if (GerudoFortress.Is(GERUDOFORTRESS_OPEN)) {
PlaceItemInLocation(GF_NORTH_F1_CARPENTER, RECOVERY_HEART, false, true);
PlaceItemInLocation(GF_NORTH_F2_CARPENTER, RECOVERY_HEART, false, true);
PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, RECOVERY_HEART, false, true);
PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, RECOVERY_HEART, false, true);
} else if (GerudoKeys.IsNot(GERUDOKEYS_VANILLA)) {
if (GerudoFortress.Is(GERUDOFORTRESS_FAST)) {
AddItemToMainPool(GERUDO_FORTRESS_SMALL_KEY);
PlaceItemInLocation(GF_NORTH_F2_CARPENTER, RECOVERY_HEART, false, true);
PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, RECOVERY_HEART, false, true);
PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, RECOVERY_HEART, false, true);
} else {
//Only add key ring if 4 Fortress keys necessary
if (RingFortress) {
AddItemToMainPool(GERUDO_FORTRESS_KEY_RING);
//Add junk to make up for missing keys
for (uint8_t i = 0; i < 3; i++) {
AddItemToMainPool(GetJunkItem());
}
} else {
AddItemToMainPool(GERUDO_FORTRESS_SMALL_KEY, 4);
}
}
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
if (RingFortress && GerudoFortress.Is(GERUDOFORTRESS_NORMAL)) {
AddItemToPool(PendingJunkPool, GERUDO_FORTRESS_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, GERUDO_FORTRESS_SMALL_KEY);
}
}
} else {
if (GerudoFortress.Is(GERUDOFORTRESS_FAST)) {
PlaceItemInLocation(GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true);
PlaceItemInLocation(GF_NORTH_F2_CARPENTER, RECOVERY_HEART, false, true);
PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, RECOVERY_HEART, false, true);
PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, RECOVERY_HEART, false, true);
} else {
PlaceItemInLocation(GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true);
PlaceItemInLocation(GF_NORTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true);
PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true);
PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true);
}
}
//Gerudo Membership Card
if (ShuffleGerudoToken && GerudoFortress.IsNot(GERUDOFORTRESS_OPEN)) {
AddItemToMainPool(GERUDO_MEMBERSHIP_CARD);
IceTrapModels.push_back(GI_GERUDO_CARD);
} else if (ShuffleGerudoToken) {
AddItemToPool(PendingJunkPool, GERUDO_MEMBERSHIP_CARD);
PlaceItemInLocation(GF_GERUDO_MEMBERSHIP_CARD, ICE_TRAP, false, true);
} else {
PlaceItemInLocation(GF_GERUDO_MEMBERSHIP_CARD, GERUDO_MEMBERSHIP_CARD, false, true);
}
//Keys
//For key rings, need to add as many junk items as "missing" keys
if (KeyRings) {
uint8_t ringJunkAmt = 0;
for (auto dungeon : dungeonList) {
if (dungeon->HasKeyRing()) {
ringJunkAmt += dungeon->GetSmallKeyCount() - 1;
}
}
for (uint8_t i = 0; i < ringJunkAmt; i++) {
AddItemToMainPool(GetJunkItem());
}
}
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
if (ShuffleGerudoToken) {
AddItemToPool(PendingJunkPool, GERUDO_MEMBERSHIP_CARD);
}
//Plentiful small keys
if (Keysanity.Is(KEYSANITY_ANYWHERE) || Keysanity.Is(KEYSANITY_ANY_DUNGEON) || Keysanity.Is(KEYSANITY_OVERWORLD)) {
if (BottomOfTheWell.HasKeyRing()) {
AddItemToPool(PendingJunkPool, BOTTOM_OF_THE_WELL_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, BOTTOM_OF_THE_WELL_SMALL_KEY);
}
if (ForestTemple.HasKeyRing()) {
AddItemToPool(PendingJunkPool, FOREST_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, FOREST_TEMPLE_SMALL_KEY);
}
if (FireTemple.HasKeyRing()) {
AddItemToPool(PendingJunkPool, FIRE_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, FIRE_TEMPLE_SMALL_KEY);
}
if (WaterTemple.HasKeyRing()) {
AddItemToPool(PendingJunkPool, WATER_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, WATER_TEMPLE_SMALL_KEY);
}
if (SpiritTemple.HasKeyRing()) {
AddItemToPool(PendingJunkPool, SPIRIT_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, SPIRIT_TEMPLE_SMALL_KEY);
}
if (ShadowTemple.HasKeyRing()) {
AddItemToPool(PendingJunkPool, SHADOW_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, SHADOW_TEMPLE_SMALL_KEY);
}
if (GerudoTrainingGrounds.HasKeyRing()) {
AddItemToPool(PendingJunkPool, GERUDO_TRAINING_GROUNDS_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, GERUDO_TRAINING_GROUNDS_SMALL_KEY);
}
if (GanonsCastle.HasKeyRing()) {
AddItemToPool(PendingJunkPool, GANONS_CASTLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, GANONS_CASTLE_SMALL_KEY);
}
}
if (BossKeysanity.Is(BOSSKEYSANITY_ANYWHERE) || BossKeysanity.Is(BOSSKEYSANITY_ANY_DUNGEON) || BossKeysanity.Is(BOSSKEYSANITY_OVERWORLD)) {
AddItemToPool(PendingJunkPool, FOREST_TEMPLE_BOSS_KEY);
AddItemToPool(PendingJunkPool, FIRE_TEMPLE_BOSS_KEY);
AddItemToPool(PendingJunkPool, WATER_TEMPLE_BOSS_KEY);
AddItemToPool(PendingJunkPool, SPIRIT_TEMPLE_BOSS_KEY);
AddItemToPool(PendingJunkPool, SHADOW_TEMPLE_BOSS_KEY);
}
if (GanonsBossKey.Is(GANONSBOSSKEY_ANYWHERE) || GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON) || GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) {
AddItemToPool(PendingJunkPool, GANONS_CASTLE_BOSS_KEY);
}
}
//Shopsanity
if (Settings::Shopsanity.Is(SHOPSANITY_OFF) || Settings::Shopsanity.Is(SHOPSANITY_ZERO)) {
AddItemsToPool(ItemPool, normalRupees);
} else { //Shopsanity 1-4, random
AddItemsToPool(ItemPool, shopsanityRupees); //Shopsanity gets extra large rupees
}
//Scrubsanity
if (Settings::Scrubsanity.IsNot(SCRUBSANITY_OFF)) {
//Deku Tree
if (DekuTree.IsMQ()) {
AddItemToMainPool(DEKU_SHIELD);
}
//Dodongos Cavern
AddItemToMainPool(DEKU_STICK_1);
AddItemToMainPool(DEKU_SHIELD);
if (DodongosCavern.IsMQ()) {
AddItemToMainPool(RECOVERY_HEART);
} else {
AddItemToMainPool(DEKU_NUTS_5);
}
//Jabu Jabus Belly
if (JabuJabusBelly.IsVanilla()) {
AddItemToMainPool(DEKU_NUTS_5);
}
//Ganons Castle
AddItemToMainPool(BOMBS_5);
AddItemToMainPool(RECOVERY_HEART);
AddItemToMainPool(BLUE_RUPEE);
if (GanonsCastle.IsMQ()) {
AddItemToMainPool(DEKU_NUTS_5);
}
//Overworld Scrubs
AddItemsToPool(ItemPool, dekuScrubItems);
//I'm not sure what this is for, but it was in ootr so I copied it
for (uint8_t i = 0; i < 7; i++) {
if (Random(0, 3)) {
AddItemToMainPool(ARROWS_30);
} else {
AddItemToMainPool(DEKU_SEEDS_30);
}
}
} else {
PlaceVanillaDekuScrubItems();
}
AddItemsToPool(ItemPool, alwaysItems);
AddItemsToPool(ItemPool, dungeonRewards);
//Dungeon pools
if (DekuTree.IsMQ()) {
AddItemsToPool(ItemPool, DT_MQ);
} else {
AddItemsToPool(ItemPool, DT_Vanilla);
}
if (DodongosCavern.IsMQ()) {
AddItemsToPool(ItemPool, DC_MQ);
} else {
AddItemsToPool(ItemPool, DC_Vanilla);
}
if (JabuJabusBelly.IsMQ()) {
AddItemsToPool(ItemPool, JB_MQ);
}
if (ForestTemple.IsMQ()) {
AddItemsToPool(ItemPool, FoT_MQ);
} else {
AddItemsToPool(ItemPool, FoT_Vanilla);
}
if (FireTemple.IsMQ()) {
AddItemsToPool(ItemPool, FiT_MQ);
} else {
AddItemsToPool(ItemPool, FiT_Vanilla);
}
if (SpiritTemple.IsMQ()) {
AddItemsToPool(ItemPool, SpT_MQ);
} else {
AddItemsToPool(ItemPool, SpT_Vanilla);
}
if (ShadowTemple.IsMQ()) {
AddItemsToPool(ItemPool, ShT_MQ);
} else {
AddItemsToPool(ItemPool, ShT_Vanilla);
}
if (BottomOfTheWell.IsVanilla()) {
AddItemsToPool(ItemPool, BW_Vanilla);
}
if (GerudoTrainingGrounds.IsMQ()) {
AddItemsToPool(ItemPool, GTG_MQ);
} else {
AddItemsToPool(ItemPool, GTG_Vanilla);
}
if (GanonsCastle.IsMQ()) {
AddItemsToPool(ItemPool, GC_MQ);
} else {
AddItemsToPool(ItemPool, GC_Vanilla);
}
uint8_t rutoBottles = 1;
if (ZorasFountain.Is(ZORASFOUNTAIN_OPEN)) {
rutoBottles = 0;
}
//Add 4 total bottles
uint8_t bottleCount = 4;
std::vector<uint32_t> bottles;
bottles.assign(normalBottles.begin(), normalBottles.end());
IceTrapModels.push_back(ItemTable(RandomElement(bottles)).GetItemID()); //Get one random bottle type for ice traps
for (uint8_t i = 0; i < bottleCount; i++) {
if (i >= rutoBottles) {
AddRandomBottle(bottles);
} else {
AddItemToMainPool(RUTOS_LETTER);
}
}
//add extra songs only if song shuffle is anywhere
AddItemsToPool(ItemPool, songList);
if (ShuffleSongs.Is(SONGSHUFFLE_ANYWHERE) && ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
AddItemsToPool(PendingJunkPool, songList);
}
/*For item pool generation, dungeon items are either placed in their vanilla
| location, or added to the pool now and filtered out later depending on when
| they need to get placed or removed in fill.cpp. These items are kept in the
| pool until removal because the filling algorithm needs to know all of the
| advancement items that haven't been placed yet for placing higher priority
| items like stones/medallions.*/
if (MapsAndCompasses.Is(MAPSANDCOMPASSES_VANILLA)) {
PlaceVanillaMapsAndCompasses();
} else {
for (auto dungeon : dungeonList) {
if (dungeon->GetMap() != NONE) {
AddItemToMainPool(dungeon->GetMap());
}
if (dungeon->GetCompass() != NONE) {
AddItemToMainPool(dungeon->GetCompass());
}
}
}
if (Keysanity.Is(KEYSANITY_VANILLA)) {
PlaceVanillaSmallKeys();
} else {
for (auto dungeon : dungeonList) {
if (dungeon->HasKeyRing() && Keysanity.IsNot(KEYSANITY_START_WITH)) {
AddItemToMainPool(dungeon->GetKeyRing());
} else {
if (dungeon->GetSmallKeyCount() > 0) {
AddItemToMainPool(dungeon->GetSmallKey(), dungeon->GetSmallKeyCount());
}
}
}
}
if (BossKeysanity.Is(BOSSKEYSANITY_VANILLA)) {
PlaceVanillaBossKeys();
} else {
AddItemToMainPool(FOREST_TEMPLE_BOSS_KEY);
AddItemToMainPool(FIRE_TEMPLE_BOSS_KEY);
AddItemToMainPool(WATER_TEMPLE_BOSS_KEY);
AddItemToMainPool(SPIRIT_TEMPLE_BOSS_KEY);
AddItemToMainPool(SHADOW_TEMPLE_BOSS_KEY);
}
if (GanonsBossKey.Value<uint8_t>() >= GANONSBOSSKEY_LACS_VANILLA) {
PlaceItemInLocation(TOT_LIGHT_ARROWS_CUTSCENE, GANONS_CASTLE_BOSS_KEY);
} else if (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA)) {
PlaceItemInLocation(GANONS_TOWER_BOSS_KEY_CHEST, GANONS_CASTLE_BOSS_KEY);
} else {
AddItemToMainPool(GANONS_CASTLE_BOSS_KEY);
}
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
AddItemsToPool(ItemPool, easyItems);
} else {
AddItemsToPool(ItemPool, normalItems);
}
if (!ShuffleKokiriSword) {
ReplaceMaxItem(KOKIRI_SWORD, 0);
}
if (ProgressiveGoronSword) {
ReplaceMaxItem(BIGGORON_SWORD, 0);
AddItemToMainPool(PROGRESSIVE_GORONSWORD, 2);
IceTrapModels.push_back(0xD4); // Progressive Goron Sword
} else {
IceTrapModels.push_back(GI_SWORD_BGS);
}
//Replace ice traps with junk from the pending junk pool if necessary
if (IceTrapValue.Is(ICETRAPS_OFF)) {
ReplaceMaxItem(ICE_TRAP, 0);
}
//Replace all junk items with ice traps for onslaught mode
else if (IceTrapValue.Is(ICETRAPS_ONSLAUGHT)) {
for (uint8_t i = 0; i < JunkPoolItems.size() - 3; i++) { // -3 Omits Huge Rupees and Deku Nuts 10
ReplaceMaxItem(JunkPoolItems[i], 0);
}
}
if (ItemPoolValue.Is(ITEMPOOL_SCARCE)) {
SetScarceItemPool();
} else if (ItemPoolValue.Is(ITEMPOOL_MINIMAL)) {
SetMinimalItemPool();
} else if (RemoveDoubleDefense) {
ReplaceMaxItem(DOUBLE_DEFENSE, 0);
}
//this feels ugly and there's probably a better way, but
//it replaces random junk with pending junk.
bool junkSet;
for (uint32_t pendingJunk : PendingJunkPool) {
junkSet = false;
for (uint32_t& item : ItemPool) {
for (uint32_t junk : JunkPoolItems) {
if (item == junk && item != HUGE_RUPEE && item != DEKU_NUTS_10) {
item = pendingJunk;
junkSet = true;
break;
}
}
if (junkSet) break;
}
}
PendingJunkPool.clear();
}
void AddJunk() {
SPDLOG_INFO("HAD TO PLACE EXTRA JUNK ");
AddItemToMainPool(GetPendingJunkItem());
}