diff --git a/soh/include/functions.h b/soh/include/functions.h index 203d4eea7..99681eb10 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -1063,6 +1063,7 @@ u8 Item_CheckObtainability(u8 item); void Inventory_DeleteItem(u16 item, u16 invSlot); s32 Inventory_ReplaceItem(GlobalContext* globalCtx, u16 oldItem, u16 newItem); s32 Inventory_HasEmptyBottle(void); +bool Inventory_HasEmptyBottleSlot(void); s32 Inventory_HasSpecificBottle(u8 bottleItem); void Inventory_UpdateBottleItem(GlobalContext* globalCtx, u8 item, u8 cButton); s32 Inventory_ConsumeFairy(GlobalContext* globalCtx); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 3f00ed467..b8442e241 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1203,87 +1203,556 @@ bool Randomizer::IsTrialRequired(RandomizerInf trial) { return this->trialsRequired.contains(trial); } -s16 Randomizer::GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) { - s16 itemId = GetItemFromActor(actorId, actorParams, sceneNum, ogId); - return itemId; +RandomizerGet Randomizer::GetRandomizerGetFromActor(s16 actorId, s16 sceneNum, s16 actorParams) { + return this->itemLocations[GetCheckFromActor(actorId, sceneNum, actorParams)]; } -s16 Randomizer::GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId) { - return GetItemFromGet(this->itemLocations[GetCheckFromActor(sceneNum, actorId, actorParams)], ogItemId); +RandomizerGet Randomizer::GetRandomizerGetFromKnownCheck(RandomizerCheck randomizerCheck) { + return this->itemLocations[randomizerCheck]; } -s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { +GetItemID Randomizer::GetItemIdFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogItemId) { + return GetItemIdFromRandomizerGet(GetRandomizerGetFromActor(actorId, sceneNum, actorParams), ogItemId); +} + +ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerCheck(RandomizerCheck randomizerCheck) { + return GetItemObtainabilityFromRandomizerGet(GetRandomizerGetFromKnownCheck(randomizerCheck)); +} + +ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGet randoGet) { + switch (randoGet) { + case RG_NONE: + case RG_TRIFORCE: + case RG_HINT: + case RG_MAX: + case RG_SOLD_OUT: + // TODO: Implement key rings + case RG_FOREST_TEMPLE_KEY_RING: + case RG_FIRE_TEMPLE_KEY_RING: + case RG_WATER_TEMPLE_KEY_RING: + case RG_SPIRIT_TEMPLE_KEY_RING: + case RG_SHADOW_TEMPLE_KEY_RING: + case RG_BOTTOM_OF_THE_WELL_KEY_RING: + case RG_GERUDO_TRAINING_GROUNDS_KEY_RING: + case RG_GERUDO_FORTRESS_KEY_RING: + case RG_GANONS_CASTLE_KEY_RING: + return CANT_OBTAIN_MISC; + + // Equipment + case RG_KOKIRI_SWORD: + return !CHECK_OWNED_EQUIP(EQUIP_SWORD, 0) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BIGGORON_SWORD: + return !gSaveContext.bgsFlag ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DEKU_SHIELD: + case RG_BUY_DEKU_SHIELD: + return !CHECK_OWNED_EQUIP(EQUIP_SHIELD, 0) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_HYLIAN_SHIELD: + case RG_BUY_HYLIAN_SHIELD: + return !CHECK_OWNED_EQUIP(EQUIP_SHIELD, 1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_MIRROR_SHIELD: + return !CHECK_OWNED_EQUIP(EQUIP_SHIELD, 2) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GORON_TUNIC: + case RG_BUY_GORON_TUNIC: + return !CHECK_OWNED_EQUIP(EQUIP_TUNIC, 1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ZORA_TUNIC: + case RG_BUY_ZORA_TUNIC: + return !CHECK_OWNED_EQUIP(EQUIP_TUNIC, 2) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_IRON_BOOTS: + return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_HOVER_BOOTS: + return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 2) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Inventory Items + case RG_PROGRESSIVE_STICK_UPGRADE: + return CUR_UPG_VALUE(UPG_STICKS) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_NUT_UPGRADE: + return CUR_UPG_VALUE(UPG_NUTS) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_BOMB_BAG: + return CUR_UPG_VALUE(UPG_BOMB_BAG) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOMBS_5: + case RG_BOMBS_10: + case RG_BOMBS_20: + case RG_BUY_BOMBS_525: + case RG_BUY_BOMBS_535: + case RG_BUY_BOMBS_10: + case RG_BUY_BOMBS_20: + case RG_BUY_BOMBS_30: + return CUR_UPG_VALUE(UPG_BOMB_BAG) ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + case RG_PROGRESSIVE_BOW: + return CUR_UPG_VALUE(UPG_QUIVER) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ARROWS_5: + case RG_ARROWS_10: + case RG_ARROWS_30: + case RG_BUY_ARROWS_10: + case RG_BUY_ARROWS_30: + case RG_BUY_ARROWS_50: + return CUR_UPG_VALUE(UPG_QUIVER) ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + case RG_PROGRESSIVE_SLINGSHOT: + return CUR_UPG_VALUE(UPG_BULLET_BAG) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DEKU_SEEDS_30: + case RG_BUY_DEKU_SEEDS_30: + return CUR_UPG_VALUE(UPG_BULLET_BAG) ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + case RG_PROGRESSIVE_OCARINA: + switch (INV_CONTENT(ITEM_OCARINA_FAIRY)) { + case ITEM_NONE: + case ITEM_OCARINA_FAIRY: + return CAN_OBTAIN; + case ITEM_OCARINA_TIME: + default: + return CANT_OBTAIN_ALREADY_HAVE; + } + case RG_BOMBCHU_5: + case RG_BOMBCHU_10: + case RG_BOMBCHU_20: + case RG_PROGRESSIVE_BOMBCHUS: + return CAN_OBTAIN; + case RG_BUY_BOMBCHU_10: + case RG_BUY_BOMBCHU_20: + case RG_BUY_BOMBCHU_5: + // If Bombchus aren't in logic, you need a bomb bag to purchase them + // If they are in logic, you need to have already obtained them somewhere else + if (GetRandoSettingValue(RSK_BOMBCHUS_IN_LOGIC)) { + return INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + } else { + return CUR_UPG_VALUE(UPG_BOMB_BAG) ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + } + case RG_BOMBCHU_DROP: + return INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + case RG_PROGRESSIVE_HOOKSHOT: + switch (INV_CONTENT(ITEM_HOOKSHOT)) { + case ITEM_NONE: + case ITEM_HOOKSHOT: + return CAN_OBTAIN; + case ITEM_LONGSHOT: + default: + return CANT_OBTAIN_ALREADY_HAVE; + } + case RG_BOOMERANG: + return INV_CONTENT(ITEM_BOOMERANG) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_LENS_OF_TRUTH: + return INV_CONTENT(ITEM_LENS) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_MAGIC_BEAN: + case RG_MAGIC_BEAN_PACK: + return BEANS_BOUGHT < 10 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_MEGATON_HAMMER: + return INV_CONTENT(ITEM_HAMMER) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_ARROWS: + return INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ICE_ARROWS: + return INV_CONTENT(ITEM_ARROW_ICE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_LIGHT_ARROWS: + return INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DINS_FIRE: + return INV_CONTENT(ITEM_DINS_FIRE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FARORES_WIND: + return INV_CONTENT(ITEM_FARORES_WIND) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_NAYRUS_LOVE: + return INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Bottles + case RG_EMPTY_BOTTLE: + case RG_BOTTLE_WITH_MILK: + case RG_BOTTLE_WITH_RED_POTION: + case RG_BOTTLE_WITH_GREEN_POTION: + case RG_BOTTLE_WITH_BLUE_POTION: + case RG_BOTTLE_WITH_FAIRY: + case RG_BOTTLE_WITH_FISH: + case RG_BOTTLE_WITH_BLUE_FIRE: + case RG_BOTTLE_WITH_BUGS: + case RG_BOTTLE_WITH_POE: + case RG_RUTOS_LETTER: + case RG_BOTTLE_WITH_BIG_POE: + return Inventory_HasEmptyBottleSlot() ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Bottle Refills + case RG_MILK: + case RG_RED_POTION_REFILL: + case RG_GREEN_POTION_REFILL: + case RG_BLUE_POTION_REFILL: + case RG_BUY_FISH: + case RG_BUY_RED_POTION_30: + case RG_BUY_GREEN_POTION: + case RG_BUY_BLUE_POTION: + case RG_BUY_BLUE_FIRE: + case RG_BUY_BOTTLE_BUG: + case RG_BUY_POE: + case RG_BUY_FAIRYS_SPIRIT: + case RG_BUY_RED_POTION_40: + case RG_BUY_RED_POTION_50: + return Inventory_HasEmptyBottle() ? CAN_OBTAIN : CANT_OBTAIN_NEED_EMPTY_BOTTLE; + + // Trade Items + // TODO: Do we want to be strict about any of this? + // case RG_WEIRD_EGG: + // case RG_ZELDAS_LETTER: + // case RG_POCKET_EGG: + // case RG_COJIRO: + // case RG_ODD_MUSHROOM: + // case RG_ODD_POTION: + // case RG_POACHERS_SAW: + // case RG_BROKEN_SWORD: + // case RG_PRESCRIPTION: + // case RG_EYEBALL_FROG: + // case RG_EYEDROPS: + // case RG_CLAIM_CHECK: + // case RG_PROGRESSIVE_GORONSWORD: + // case RG_GIANTS_KNIFE: + + // Misc Items + case RG_STONE_OF_AGONY: + return !CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GERUDO_MEMBERSHIP_CARD: + return !CHECK_QUEST_ITEM(QUEST_GERUDO_CARD) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DOUBLE_DEFENSE: + return !gSaveContext.doubleDefense ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GOLD_SKULLTULA_TOKEN: + return gSaveContext.inventory.gsTokens < 100 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_STRENGTH: + return CUR_UPG_VALUE(UPG_STRENGTH) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_WALLET: + return CUR_UPG_VALUE(UPG_WALLET) < 2 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_SCALE: + return CUR_UPG_VALUE(UPG_SCALE) < 2 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_MAGIC_METER: + case RG_MAGIC_SINGLE: + case RG_MAGIC_DOUBLE: + return gSaveContext.magicLevel < 2 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Songs + case RG_ZELDAS_LULLABY: + return !CHECK_QUEST_ITEM(QUEST_SONG_LULLABY) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_EPONAS_SONG: + return !CHECK_QUEST_ITEM(QUEST_SONG_EPONA) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SARIAS_SONG: + return !CHECK_QUEST_ITEM(QUEST_SONG_SARIA) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SUNS_SONG: + return !CHECK_QUEST_ITEM(QUEST_SONG_SUN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SONG_OF_TIME: + return !CHECK_QUEST_ITEM(QUEST_SONG_TIME) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SONG_OF_STORMS: + return !CHECK_QUEST_ITEM(QUEST_SONG_STORMS) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_MINUET_OF_FOREST: + return !CHECK_QUEST_ITEM(QUEST_SONG_MINUET) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOLERO_OF_FIRE: + return !CHECK_QUEST_ITEM(QUEST_SONG_BOLERO) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SERENADE_OF_WATER: + return !CHECK_QUEST_ITEM(QUEST_SONG_SERENADE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_REQUIEM_OF_SPIRIT: + return !CHECK_QUEST_ITEM(QUEST_SONG_REQUIEM) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_NOCTURNE_OF_SHADOW: + return !CHECK_QUEST_ITEM(QUEST_SONG_NOCTURNE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PRELUDE_OF_LIGHT: + return !CHECK_QUEST_ITEM(QUEST_SONG_PRELUDE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Dungeon Items + case RG_DEKU_TREE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_YDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DODONGOS_CAVERN_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_DDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_JABU_JABUS_BELLY_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_BDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FOREST_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_BMORI1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_HIDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_MIZUSIN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_JYASINZOU) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_HAKADAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOTTOM_OF_THE_WELL_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_HAKADANCH) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ICE_CAVERN_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_ICE_DOUKUTO) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DEKU_TREE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_YDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DODONGOS_CAVERN_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_DDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_JABU_JABUS_BELLY_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_BDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FOREST_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_BMORI1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_HIDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_MIZUSIN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_JYASINZOU) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_HAKADAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOTTOM_OF_THE_WELL_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_HAKADANCH) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ICE_CAVERN_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_ICE_DOUKUTO) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FOREST_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_BMORI1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_HIDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_MIZUSIN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_JYASINZOU) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_HAKADAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GANONS_CASTLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_GANON) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + // TODO: Handle MQ key counts + case RG_FOREST_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_BMORI1] < 5 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_HIDAN] < 8 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_MIZUSIN] < 6 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_JYASINZOU] < 5 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_HAKADAN] < 5 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_HAKADANCH] < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_MEN] < 9 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GERUDO_FORTRESS_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_GERUDOWAY] < 4 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GANONS_CASTLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_GANONTIKA] < 2 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_TREASURE_GAME_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_TAKARAYA] < 6 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Dungeon Rewards + case RG_KOKIRI_EMERALD: + return !CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GORON_RUBY: + return !CHECK_QUEST_ITEM(QUEST_GORON_RUBY) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ZORA_SAPPHIRE: + return !CHECK_QUEST_ITEM(QUEST_ZORA_SAPPHIRE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FOREST_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_FOREST) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_LIGHT_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_LIGHT) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + case RG_RECOVERY_HEART: + case RG_GREEN_RUPEE: + case RG_BLUE_RUPEE: + case RG_RED_RUPEE: + case RG_PURPLE_RUPEE: + case RG_HUGE_RUPEE: + case RG_PIECE_OF_HEART: + case RG_HEART_CONTAINER: + case RG_ICE_TRAP: + case RG_DEKU_NUTS_5: + case RG_DEKU_NUTS_10: + case RG_DEKU_STICK_1: + case RG_TREASURE_GAME_HEART: + case RG_TREASURE_GAME_GREEN_RUPEE: + case RG_BUY_DEKU_NUT_5: + case RG_BUY_DEKU_NUT_10: + case RG_BUY_DEKU_STICK_1: + case RG_BUY_HEART: + default: + return CAN_OBTAIN; + } +} + +GetItemID Randomizer::GetItemIdFromRandomizerGet(RandomizerGet randoGet, GetItemID ogItemId) { switch (randoGet) { case RG_NONE: return ogItemId; + case RG_TRIFORCE: + case RG_HINT: + case RG_MAX: + case RG_SOLD_OUT: + return GI_NONE; + // Equipment case RG_KOKIRI_SWORD: - return !CHECK_OWNED_EQUIP(EQUIP_SWORD, 0) ? GI_SWORD_KOKIRI : GI_RUPEE_BLUE; + return GI_SWORD_KOKIRI; + case RG_PROGRESSIVE_GORONSWORD: //todo progressive? + return GI_SWORD_BGS; case RG_GIANTS_KNIFE: return GI_SWORD_KNIFE; case RG_BIGGORON_SWORD: - return !gSaveContext.bgsFlag ? GI_SWORD_BGS : GI_RUPEE_BLUE; - + return GI_SWORD_BGS; case RG_DEKU_SHIELD: + case RG_BUY_DEKU_SHIELD: return GI_SHIELD_DEKU; case RG_HYLIAN_SHIELD: + case RG_BUY_HYLIAN_SHIELD: return GI_SHIELD_HYLIAN; case RG_MIRROR_SHIELD: - return !CHECK_OWNED_EQUIP(EQUIP_SHIELD, 2) ? GI_SHIELD_MIRROR : GI_RUPEE_BLUE; - + return GI_SHIELD_MIRROR; case RG_GORON_TUNIC: + case RG_BUY_GORON_TUNIC: return GI_TUNIC_GORON; case RG_ZORA_TUNIC: + case RG_BUY_ZORA_TUNIC: return GI_TUNIC_ZORA; - case RG_IRON_BOOTS: - return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 1) ? GI_BOOTS_IRON : GI_RUPEE_BLUE; + return GI_BOOTS_IRON; case RG_HOVER_BOOTS: - return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 2) ? GI_BOOTS_HOVER : GI_RUPEE_BLUE; + return GI_BOOTS_HOVER; + // Inventory Items + case RG_PROGRESSIVE_STICK_UPGRADE: + switch (CUR_UPG_VALUE(UPG_STICKS)) { + case 0: + case 1: + return GI_STICK_UPGRADE_20; + case 2: + return GI_STICK_UPGRADE_30; + } + case RG_PROGRESSIVE_NUT_UPGRADE: + switch (CUR_UPG_VALUE(UPG_NUTS)) { + case 0: + case 1: + return GI_NUT_UPGRADE_30; + case 2: + return GI_NUT_UPGRADE_40; + } + case RG_PROGRESSIVE_BOMB_BAG: + switch (CUR_UPG_VALUE(UPG_BOMB_BAG)) { + case 0: + return GI_BOMB_BAG_20; + case 1: + return GI_BOMB_BAG_30; + case 2: + return GI_BOMB_BAG_40; + } + case RG_BOMBS_5: + case RG_BUY_BOMBS_525: + case RG_BUY_BOMBS_535: + return GI_BOMBS_5; + case RG_BOMBS_10: + case RG_BUY_BOMBS_10: + return GI_BOMBS_10; + case RG_BOMBS_20: + case RG_BUY_BOMBS_20: + return GI_BOMBS_20; + case RG_BUY_BOMBS_30: + return GI_BOMBS_30; + case RG_PROGRESSIVE_BOW: + switch (CUR_UPG_VALUE(UPG_QUIVER)) { + case 0: + return GI_BOW; + case 1: + return GI_QUIVER_40; + case 2: + return GI_QUIVER_50; + } + case RG_ARROWS_5: + case RG_BUY_ARROWS_10: + return GI_ARROWS_SMALL; + case RG_ARROWS_10: + case RG_BUY_ARROWS_30: + return GI_ARROWS_MEDIUM; + case RG_ARROWS_30: + case RG_BUY_ARROWS_50: + return GI_ARROWS_LARGE; + case RG_PROGRESSIVE_SLINGSHOT: + switch (CUR_UPG_VALUE(UPG_BULLET_BAG)) { + case 0: + return GI_SLINGSHOT; + case 1: + return GI_BULLET_BAG_40; + case 2: + return GI_BULLET_BAG_50; + } + case RG_DEKU_SEEDS_30: + case RG_BUY_DEKU_SEEDS_30: + return GI_SEEDS_30; + case RG_PROGRESSIVE_OCARINA: + switch (INV_CONTENT(ITEM_OCARINA_FAIRY)) { + case ITEM_NONE: + return GI_OCARINA_FAIRY; + case ITEM_OCARINA_FAIRY: + return GI_OCARINA_OOT; + } + case RG_PROGRESSIVE_BOMBCHUS: + return GI_BOMBCHUS_20; + case RG_BOMBCHU_5: + case RG_BUY_BOMBCHU_5: + case RG_BOMBCHU_DROP: + return GI_BOMBCHUS_5; + case RG_BOMBCHU_10: + case RG_BUY_BOMBCHU_10: + return GI_BOMBCHUS_10; + case RG_BOMBCHU_20: + case RG_BUY_BOMBCHU_20: + return GI_BOMBCHUS_20; + case RG_PROGRESSIVE_HOOKSHOT: + switch (INV_CONTENT(ITEM_HOOKSHOT)) { + case ITEM_NONE: + return GI_HOOKSHOT; + case ITEM_HOOKSHOT: + return GI_LONGSHOT; + } case RG_BOOMERANG: - return INV_CONTENT(ITEM_BOOMERANG) == ITEM_NONE ? GI_BOOMERANG : GI_RUPEE_BLUE; - + return GI_BOOMERANG; case RG_LENS_OF_TRUTH: - return INV_CONTENT(ITEM_LENS) == ITEM_NONE ? GI_LENS : GI_RUPEE_BLUE; - - case RG_MEGATON_HAMMER: - return INV_CONTENT(ITEM_HAMMER) == ITEM_NONE ? GI_HAMMER : GI_RUPEE_BLUE; - - case RG_STONE_OF_AGONY: - return GI_STONE_OF_AGONY; - - case RG_DINS_FIRE: - return INV_CONTENT(ITEM_DINS_FIRE) == ITEM_NONE ? GI_DINS_FIRE : GI_RUPEE_BLUE; - case RG_FARORES_WIND: - return INV_CONTENT(ITEM_FARORES_WIND) == ITEM_NONE ? GI_FARORES_WIND : GI_RUPEE_BLUE; - case RG_NAYRUS_LOVE: - return INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NONE ? GI_NAYRUS_LOVE : GI_RUPEE_BLUE; - - case RG_FIRE_ARROWS: - return INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_NONE ? GI_ARROW_FIRE : GI_RUPEE_BLUE; - case RG_ICE_ARROWS: - return INV_CONTENT(ITEM_ARROW_ICE) == ITEM_NONE ? GI_ARROW_ICE : GI_RUPEE_BLUE; - case RG_LIGHT_ARROWS: - return INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_NONE ? GI_ARROW_LIGHT : GI_RUPEE_BLUE; - - case RG_DOUBLE_DEFENSE: - return !gSaveContext.doubleDefense ? (GetItemID)RG_DOUBLE_DEFENSE : GI_RUPEE_BLUE; - - case RG_GERUDO_MEMBERSHIP_CARD: - return GI_GERUDO_CARD; - + return GI_LENS; case RG_MAGIC_BEAN: return GI_BEAN; + case RG_MEGATON_HAMMER: + return GI_HAMMER; + case RG_FIRE_ARROWS: + return GI_ARROW_FIRE; + case RG_ICE_ARROWS: + return GI_ARROW_ICE; + case RG_LIGHT_ARROWS: + return GI_ARROW_LIGHT; + case RG_DINS_FIRE: + return GI_DINS_FIRE; + case RG_FARORES_WIND: + return GI_FARORES_WIND; + case RG_NAYRUS_LOVE: + return GI_NAYRUS_LOVE; - case RG_WEIRD_EGG: - return GI_WEIRD_EGG; - - case RG_ZELDAS_LETTER: - return GI_LETTER_ZELDA; + // Bottles + case RG_EMPTY_BOTTLE: + return GI_BOTTLE; + case RG_BOTTLE_WITH_MILK: + return GI_MILK_BOTTLE; case RG_RUTOS_LETTER: return GI_LETTER_RUTO; + // Bottle Refills + case RG_MILK: + return GI_MILK; + case RG_RED_POTION_REFILL: + case RG_BUY_RED_POTION_30: + case RG_BUY_RED_POTION_40: + case RG_BUY_RED_POTION_50: + return GI_POTION_RED; + case RG_GREEN_POTION_REFILL: + case RG_BUY_GREEN_POTION: + return GI_POTION_GREEN; + case RG_BLUE_POTION_REFILL: + case RG_BUY_BLUE_POTION: + return GI_POTION_BLUE; + case RG_BUY_FISH: + return GI_FISH; + case RG_BUY_BLUE_FIRE: + return GI_BLUE_FIRE; + case RG_BUY_BOTTLE_BUG: + return GI_BUGS; + case RG_BUY_POE: + return GI_POE; + case RG_BUY_FAIRYS_SPIRIT: + return GI_FAIRY; + + // Trade Items + case RG_WEIRD_EGG: + return GI_WEIRD_EGG; + case RG_ZELDAS_LETTER: + return GI_LETTER_ZELDA; case RG_POCKET_EGG: return GI_POCKET_EGG; case RG_COJIRO: @@ -1304,19 +1773,14 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { return GI_EYEDROPS; case RG_CLAIM_CHECK: return GI_CLAIM_CHECK; - + + // Misc Items + case RG_STONE_OF_AGONY: + return GI_STONE_OF_AGONY; + case RG_GERUDO_MEMBERSHIP_CARD: + return GI_GERUDO_CARD; case RG_GOLD_SKULLTULA_TOKEN: return GI_SKULL_TOKEN; - - case RG_PROGRESSIVE_HOOKSHOT: - switch (gSaveContext.inventory.items[SLOT_HOOKSHOT]) { - case ITEM_NONE: - return GI_HOOKSHOT; - case ITEM_HOOKSHOT: - return GI_LONGSHOT; - } - return GI_RUPEE_BLUE; - case RG_PROGRESSIVE_STRENGTH: switch (CUR_UPG_VALUE(UPG_STRENGTH)) { case 0: @@ -1326,41 +1790,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case 2: return GI_GAUNTLETS_GOLD; } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_BOMB_BAG: - switch (CUR_UPG_VALUE(UPG_BOMB_BAG)) { - case 0: - return GI_BOMB_BAG_20; - case 1: - return GI_BOMB_BAG_30; - case 2: - return GI_BOMB_BAG_40; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_BOW: - switch (CUR_UPG_VALUE(UPG_QUIVER)) { - case 0: - return GI_BOW; - case 1: - return GI_QUIVER_40; - case 2: - return GI_QUIVER_50; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_SLINGSHOT: - switch (CUR_UPG_VALUE(UPG_BULLET_BAG)) { - case 0: - return GI_SLINGSHOT; - case 1: - return GI_BULLET_BAG_40; - case 2: - return GI_BULLET_BAG_50; - } - return GI_RUPEE_BLUE; - case RG_PROGRESSIVE_WALLET: switch (CUR_UPG_VALUE(UPG_WALLET)) { case 0: @@ -1368,8 +1797,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case 1: return GI_WALLET_GIANT; } - return GI_RUPEE_BLUE; - case RG_PROGRESSIVE_SCALE: switch (CUR_UPG_VALUE(UPG_SCALE)) { case 0: @@ -1377,37 +1804,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case 1: return GI_SCALE_GOLD; } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_NUT_UPGRADE: - switch (CUR_UPG_VALUE(UPG_NUTS)) { - case 0: - case 1: - return GI_NUT_UPGRADE_30; - case 2: - return GI_NUT_UPGRADE_40; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_STICK_UPGRADE: - switch (CUR_UPG_VALUE(UPG_STICKS)) { - case 0: - case 1: - return GI_STICK_UPGRADE_20; - case 2: - return GI_STICK_UPGRADE_30; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_BOMBCHUS: - if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_NONE) { - return GI_BOMBCHUS_20; - } - if (AMMO(ITEM_BOMBCHU) < 5) { - return GI_BOMBCHUS_10; - } - return GI_BOMBCHUS_5; - case RG_PROGRESSIVE_MAGIC_METER: switch (gSaveContext.magicLevel) { case 0: @@ -1415,24 +1811,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case 1: return (GetItemID)RG_MAGIC_DOUBLE; } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_OCARINA: - switch (INV_CONTENT(ITEM_OCARINA_FAIRY) == ITEM_NONE) { - case 1: - return GI_OCARINA_FAIRY; - case 0: - return GI_OCARINA_OOT; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_GORONSWORD: - return GI_SWORD_BGS; //todo progressive? - - case RG_EMPTY_BOTTLE: - return GI_BOTTLE; - case RG_BOTTLE_WITH_MILK: - return GI_MILK_BOTTLE; case RG_DEKU_TREE_MAP: case RG_DODONGOS_CAVERN_MAP: @@ -1447,7 +1825,7 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) { return GI_MAP; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_DEKU_TREE_COMPASS: @@ -1463,7 +1841,7 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) { return GI_COMPASS; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_FOREST_TEMPLE_BOSS_KEY: @@ -1474,13 +1852,13 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { if (GetRandoSettingValue(RSK_BOSS_KEYSANITY) < 3) { return GI_KEY_BOSS; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_GANONS_CASTLE_BOSS_KEY: if (GetRandoSettingValue(RSK_GANONS_BOSS_KEY) < 3) { return GI_KEY_BOSS; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_FOREST_TEMPLE_SMALL_KEY: @@ -1494,34 +1872,18 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { if (GetRandoSettingValue(RSK_KEYSANITY) < 3) { return GI_KEY_SMALL; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_GERUDO_FORTRESS_SMALL_KEY: if (GetRandoSettingValue(RSK_GERUDO_KEYS) == 0) { return GI_KEY_SMALL; } else { - return randoGet; + return (GetItemID)randoGet; } - // todo test this with keys in own dungeon - case RG_TREASURE_GAME_SMALL_KEY: - return GI_DOOR_KEY; - - // todo keyrings - case RG_FOREST_TEMPLE_KEY_RING: - case RG_FIRE_TEMPLE_KEY_RING: - case RG_WATER_TEMPLE_KEY_RING: - case RG_SPIRIT_TEMPLE_KEY_RING: - case RG_SHADOW_TEMPLE_KEY_RING: - case RG_BOTTOM_OF_THE_WELL_KEY_RING: - case RG_GERUDO_TRAINING_GROUNDS_KEY_RING: - case RG_GERUDO_FORTRESS_KEY_RING: - case RG_GANONS_CASTLE_KEY_RING: - return GI_RUPEE_BLUE; - case RG_RECOVERY_HEART: + case RG_BUY_HEART: return GI_HEART; - case RG_GREEN_RUPEE: return GI_RUPEE_GREEN; case RG_BLUE_RUPEE: @@ -1532,73 +1894,33 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { return GI_RUPEE_PURPLE; case RG_HUGE_RUPEE: return GI_RUPEE_GOLD; - case RG_PIECE_OF_HEART: return GI_HEART_PIECE; case RG_HEART_CONTAINER: - // todo figure out what GI_HEART_CONTAINER_2 is return GI_HEART_CONTAINER; - case RG_MILK: - return GI_MILK; //todo logic around needing a bottle? - - case RG_BOMBS_5: - return CUR_UPG_VALUE(UPG_BOMB_BAG) ? GI_BOMBS_5 : GI_RUPEE_BLUE; - case RG_BOMBS_10: - return CUR_UPG_VALUE(UPG_BOMB_BAG) ? GI_BOMBS_10 : GI_RUPEE_BLUE; - case RG_BOMBS_20: - return CUR_UPG_VALUE(UPG_BOMB_BAG) ? GI_BOMBS_20 : GI_RUPEE_BLUE; - - case RG_BOMBCHU_5: - return GI_BOMBCHUS_5; - case RG_BOMBCHU_10: - return GI_BOMBCHUS_10; - case RG_BOMBCHU_20: - return GI_BOMBCHUS_20; - case RG_BOMBCHU_DROP: - return GI_BOMBCHUS_5; //todo figure out what we want to do for chu drops - - case RG_ARROWS_5: - return CUR_UPG_VALUE(UPG_QUIVER) ? GI_ARROWS_SMALL : GI_RUPEE_BLUE; - case RG_ARROWS_10: - return CUR_UPG_VALUE(UPG_QUIVER) ? GI_ARROWS_MEDIUM : GI_RUPEE_BLUE; - case RG_ARROWS_30: - return CUR_UPG_VALUE(UPG_QUIVER) ? GI_ARROWS_LARGE : GI_RUPEE_BLUE; - + case RG_DEKU_NUTS_5: + case RG_BUY_DEKU_NUT_5: return GI_NUTS_5; case RG_DEKU_NUTS_10: + case RG_BUY_DEKU_NUT_10: return GI_NUTS_10; - - case RG_DEKU_SEEDS_30: - return CUR_UPG_VALUE(UPG_BULLET_BAG) ? GI_SEEDS_30 : GI_RUPEE_BLUE; - case RG_DEKU_STICK_1: + case RG_BUY_DEKU_STICK_1: return GI_STICKS_1; - - // RANDOTODO these won't be used until we implement shopsanity/scrub shuffle - case RG_RED_POTION_REFILL: - case RG_GREEN_POTION_REFILL: - case RG_BLUE_POTION_REFILL: - return GI_NONE; - + case RG_TREASURE_GAME_SMALL_KEY: + return GI_DOOR_KEY; case RG_TREASURE_GAME_HEART: return GI_HEART_PIECE_WIN; case RG_TREASURE_GAME_GREEN_RUPEE: - return GI_RUPEE_GREEN_LOSE; //todo figure out how this works outside of the game - - case RG_TRIFORCE: - return GI_RUPEE_BLUE; //todo figure out what this is/does - - case RG_HINT: - return GI_RUPEE_BLUE; //todo - + return GI_RUPEE_GREEN_LOSE; default: if (!IsItemVanilla(randoGet)) { - return randoGet; + return (GetItemID)randoGet; } return ogItemId; - } } +} bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { switch (randoGet) { @@ -2072,11 +2394,11 @@ u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) { return this->randoSettings[randoSettingKey]; } -s16 Randomizer::GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId) { - return GetItemFromGet(this->itemLocations[randomizerCheck], ogId); +GetItemID Randomizer::GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogItemId) { + return GetItemIdFromRandomizerGet(this->itemLocations[randomizerCheck], ogItemId); } -RandomizerCheck Randomizer::GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams) { +RandomizerCheck Randomizer::GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams) { if (!gSaveContext.n64ddFlag) { return RC_UNKNOWN_CHECK; } diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 2c87a5b03..36b5ac4f0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -21,8 +21,6 @@ class Randomizer { std::string ganonText; std::unordered_map randoSettings; std::unordered_map randomizerMerchantPrices; - s16 GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId); - s16 GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId); void ParseRandomizerSettingsFile(const char* spoilerFileName); void ParseHintLocationsFile(const char* spoilerFileName); void ParseRequiredTrialsFile(const char* spoilerFileName); @@ -50,14 +48,19 @@ class Randomizer { void LoadItemLocations(const char* spoilerFileName,bool silent); bool IsTrialRequired(RandomizerInf trial); u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey); - RandomizerCheck GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams); + RandomizerCheck GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams); + RandomizerGet GetRandomizerGetFromActor(s16 actorId, s16 sceneNum, s16 actorParams); + RandomizerGet GetRandomizerGetFromKnownCheck(RandomizerCheck randomizerCheck); std::string GetChildAltarText() const; std::string GetAdultAltarText() const; std::string GetGanonText() const; std::string GetGanonHintText() const; ScrubIdentity IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); - s16 GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); - s16 GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); + GetItemID GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogItemId); + GetItemID GetItemIdFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogItemId); + GetItemID GetItemIdFromRandomizerGet(RandomizerGet randoGet, GetItemID ogItemId); + ItemObtainability GetItemObtainabilityFromRandomizerCheck(RandomizerCheck randomizerCheck); + ItemObtainability GetItemObtainabilityFromRandomizerGet(RandomizerGet randomizerCheck); static void CreateCustomMessages(); static std::string RandomizeRupeeName(std::string message, int language); static CustomMessageEntry GetRupeeMessage(u16 rupeeTextId); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index d30e0cee4..bd7e25a46 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1021,6 +1021,14 @@ typedef enum { RSK_BOMBCHUS_IN_LOGIC } RandomizerSettingKey; +typedef enum { + CAN_OBTAIN, + CANT_OBTAIN_MISC, + CANT_OBTAIN_ALREADY_HAVE, + CANT_OBTAIN_NEED_UPGRADE, + CANT_OBTAIN_NEED_EMPTY_BOTTLE, +} ItemObtainability; + typedef struct ScrubIdentity { RandomizerInf randomizerInf; RandomizerCheck randomizerCheck; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index efb0e4464..d65611725 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1582,8 +1582,8 @@ extern "C" u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey) { return OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(randoSettingKey); } -extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams) { - return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams); +extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams) { + return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(actorId, sceneNum, actorParams); } extern "C" ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData) { @@ -1629,15 +1629,20 @@ extern "C" GetItemEntry ItemTable_RetrieveEntry(s16 tableID, s16 getItemID) { return ItemTableManager::Instance->RetrieveItemEntry(tableID, getItemID); } -extern "C" GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) { +extern "C" GetItemEntry Randomizer_GetItemFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogId) { s16 getItemModIndex; - if (OTRGlobals::Instance->gRandomizer->CheckContainsVanillaItem( - OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams))) { + RandomizerCheck randomizerCheck = OTRGlobals::Instance->gRandomizer->GetCheckFromActor(actorId, sceneNum, actorParams); + if (OTRGlobals::Instance->gRandomizer->CheckContainsVanillaItem(randomizerCheck)) { getItemModIndex = MOD_NONE; } else { getItemModIndex = MOD_RANDOMIZER; } - s16 itemID = OTRGlobals::Instance->gRandomizer->GetRandomizedItemId(ogId, actorId, actorParams, sceneNum); + s16 itemID = OTRGlobals::Instance->gRandomizer->GetItemIdFromActor(actorId, sceneNum, actorParams, ogId); + + if (OTRGlobals::Instance->gRandomizer->GetItemObtainabilityFromRandomizerCheck(randomizerCheck) != CAN_OBTAIN) { + return ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE); + } + return ItemTable_RetrieveEntry(getItemModIndex, itemID); } @@ -1648,7 +1653,12 @@ extern "C" GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomi } else { getItemModIndex = MOD_RANDOMIZER; } - s16 itemID = OTRGlobals::Instance->gRandomizer->GetRandomizedItemIdFromKnownCheck(randomizerCheck, ogId); + s16 itemID = OTRGlobals::Instance->gRandomizer->GetItemIdFromKnownCheck(randomizerCheck, ogId); + + if (OTRGlobals::Instance->gRandomizer->GetItemObtainabilityFromRandomizerCheck(randomizerCheck) != CAN_OBTAIN) { + return ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE); + } + return ItemTable_RetrieveEntry(getItemModIndex, itemID); } @@ -1707,7 +1717,7 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { } RandomizerCheck hintCheck = - Randomizer_GetCheckFromActor(globalCtx->sceneNum, msgCtx->talkActor->id, actorParams); + Randomizer_GetCheckFromActor(msgCtx->talkActor->id, globalCtx->sceneNum, actorParams); messageEntry = Randomizer_GetHintFromCheck(hintCheck); } else if (textId == TEXT_ALTAR_CHILD || textId == TEXT_ALTAR_ADULT) { diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index e1541f0a8..e157db72e 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -97,13 +97,13 @@ void* getN64WeirdFrame(s32 i); Sprite* GetSeedTexture(uint8_t index); void Randomizer_LoadSettings(const char* spoilerFileName); u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); -RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum); +RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams); ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); void Randomizer_LoadHintLocations(const char* spoilerFileName); void Randomizer_LoadRequiredTrials(const char* spoilerFileName); void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent); bool Randomizer_IsTrialRequired(RandomizerInf trial); -GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); +GetItemEntry Randomizer_GetItemFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogId); GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor); bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId); diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 95375ea48..1ceff9f0d 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -520,7 +520,7 @@ void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx) { func_8002F554(&this->actor, globalCtx, getItemId); } } else { - getItem = Randomizer_GetRandomizedItem(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); + getItem = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, getItemId); GiveItemEntryFromActorWithFixedRange(&this->actor, globalCtx, getItem); } } @@ -686,7 +686,7 @@ void func_8001E5C8(EnItem00* this, GlobalContext* globalCtx) { func_8002F434(&this->actor, globalCtx, this->getItemId, 50.0f, 80.0f); } else { GetItemEntry getItemEntry = - Randomizer_GetRandomizedItem(this->getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); + Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, this->getItemId); GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 50.0f, 80.0f); } this->unk_15A++; @@ -911,7 +911,7 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) { if (!gSaveContext.n64ddFlag) { func_8002F554(&this->actor, globalCtx, getItemId); } else { - getItem = Randomizer_GetRandomizedItem(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); + getItem = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, getItemId); getItemId = getItem.getItemId; GiveItemEntryFromActorWithFixedRange(&this->actor, globalCtx, getItem); } @@ -1380,7 +1380,7 @@ void EnItem00_DrawCollectible(EnItem00* this, GlobalContext* globalCtx) { f32 mtxScale = 16.0f; Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); GetItemEntry randoGetItemEntry = - Randomizer_GetRandomizedItem(this->getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); + Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, this->getItemId); EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemEntry); GetItemEntry_Draw(globalCtx, randoGetItemEntry); } else { @@ -1442,7 +1442,7 @@ void EnItem00_DrawHeartPiece(EnItem00* this, GlobalContext* globalCtx) { f32 mtxScale = 16.0f; Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); GetItemEntry randoGetItemEntry = - Randomizer_GetRandomizedItem(GI_HEART_PIECE, this->actor.id, this->ogParams, globalCtx->sceneNum); + Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, GI_HEART_PIECE); EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemEntry); GetItemEntry_Draw(globalCtx, randoGetItemEntry); } else { diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 8d26f3658..ac751cca3 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2556,6 +2556,17 @@ s32 Inventory_HasEmptyBottle(void) { } } +bool Inventory_HasEmptyBottleSlot(void) { + u8* items = gSaveContext.inventory.items; + + return ( + items[SLOT_BOTTLE_1] == ITEM_NONE || + items[SLOT_BOTTLE_2] == ITEM_NONE || + items[SLOT_BOTTLE_3] == ITEM_NONE || + items[SLOT_BOTTLE_4] == ITEM_NONE + ); +} + s32 Inventory_HasSpecificBottle(u8 bottleItem) { u8* items = gSaveContext.inventory.items; diff --git a/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c b/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c index e04755a34..33adac2cf 100644 --- a/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c +++ b/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c @@ -70,7 +70,7 @@ const ActorInit Bg_Dy_Yoseizo_InitVars = { void GivePlayerRandoRewardGreatFairy(BgDyYoseizo* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); - GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_NONE, this->actor.id, this->fountainType + 1, globalCtx->sceneNum); + GetItemEntry getItemEntry = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->fountainType + 1, GI_NONE); if (this->actor.parent == GET_PLAYER(globalCtx) && !Flags_GetTreasure(globalCtx, this->fountainType + 1) && !Player_InBlockingCsMode(globalCtx, GET_PLAYER(globalCtx))) { diff --git a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c index e372d3291..39b754fb8 100644 --- a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c +++ b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c @@ -462,7 +462,7 @@ s32 DoorWarp1_PlayerInRange(DoorWarp1* this, GlobalContext* globalCtx) { } void GivePlayerRandoReward(DoorWarp1* this, Player* player, GlobalContext* globalCtx, u8 ruto, u8 adult) { - GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_NONE, this->actor.id, this->actor.params, globalCtx->sceneNum); + GetItemEntry getItemEntry = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->actor.params, GI_NONE); if (this->actor.parent != NULL && this->actor.parent->id == GET_PLAYER(globalCtx)->actor.id && !Flags_GetTreasure(globalCtx, 0x1F)) { diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c index 3e78982a3..26d29b6d4 100644 --- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -446,7 +446,7 @@ void EnBox_WaitOpen(EnBox* this, GlobalContext* globalCtx) { func_8002DBD0(&this->dyna.actor, &sp4C, &player->actor.world.pos); if (sp4C.z > -50.0f && sp4C.z < 0.0f && fabsf(sp4C.y) < 10.0f && fabsf(sp4C.x) < 20.0f && Player_IsFacingActor(&this->dyna.actor, 0x3000, globalCtx)) { - sItem = Randomizer_GetRandomizedItem(this->dyna.actor.params >> 5 & 0x7F, this->dyna.actor.id, this->dyna.actor.params, globalCtx->sceneNum); + sItem = Randomizer_GetItemFromActor(this->dyna.actor.id, globalCtx->sceneNum, this->dyna.actor.params, this->dyna.actor.params >> 5 & 0x7F); GetItemEntry blueRupee = ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE); // RANDOTODO treasure chest game rando diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c index 39e1195f5..b955eda0e 100644 --- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c +++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c @@ -187,7 +187,7 @@ void EnSi_Draw(Actor* thisx, GlobalContext* globalCtx) { if (!gSaveContext.n64ddFlag) { GetItem_Draw(globalCtx, GID_SKULL_TOKEN_2); } else { - getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum); + getItem = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->actor.params, GI_SKULL_TOKEN); EnItem00_CustomItemsParticles(&this->actor, globalCtx, getItem); if (getItem.itemId != ITEM_SKULL_TOKEN) { f32 mtxScale = 1.5f; @@ -202,7 +202,7 @@ void EnSi_Draw(Actor* thisx, GlobalContext* globalCtx) { void Randomizer_UpdateSkullReward(EnSi* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); - getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum); + getItem = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->actor.params, GI_SKULL_TOKEN); getItemId = getItem.getItemId; if (getItemId == RG_ICE_TRAP) { player->pendingIceTrap = true; diff --git a/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c b/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c index f4181146a..b785d35fa 100644 --- a/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c +++ b/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c @@ -62,7 +62,7 @@ void ItemBHeart_Update(Actor* thisx, GlobalContext* globalCtx) { if (!gSaveContext.n64ddFlag) { func_8002F434(&this->actor, globalCtx, GI_HEART_CONTAINER_2, 30.0f, 40.0f); } else { - GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_HEART_CONTAINER_2, this->actor.id, this->actor.params, globalCtx->sceneNum); + GetItemEntry getItemEntry = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->actor.params, GI_HEART_CONTAINER_2); GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 30.0f, 40.0f); } } @@ -99,8 +99,8 @@ void ItemBHeart_Draw(Actor* thisx, GlobalContext* globalCtx) { } if (gSaveContext.n64ddFlag) { - GetItemEntry_Draw(globalCtx, Randomizer_GetRandomizedItem(GI_HEART_CONTAINER_2, - this->actor.id,this->actor.params, globalCtx->sceneNum)); + GetItemEntry_Draw(globalCtx, Randomizer_GetItemFromActor(this->actor.id, + globalCtx->sceneNum,this->actor.params, GI_HEART_CONTAINER_2)); } else { if (flag) { func_80093D84(globalCtx->state.gfxCtx);