Rename GetItemFromGet and move obtainability checks to a separate function

This commit is contained in:
Garrett Cox 2022-08-29 15:26:27 -05:00
parent 6d4288c2a5
commit 5961c33ba9
5 changed files with 552 additions and 207 deletions

View File

@ -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);

View File

@ -1191,81 +1191,541 @@ s16 Randomizer::GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams
}
s16 Randomizer::GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId) {
return GetItemFromGet(this->itemLocations[GetCheckFromActor(sceneNum, actorId, actorParams)], ogItemId);
return GetItemIDFromRandomizerGet(this->itemLocations[GetCheckFromActor(sceneNum, actorId, actorParams)], ogItemId);
}
s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) {
CanObtainResult Randomizer::CanObtainRandomizerGet(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;
// TODO
// case RG_PROGRESSIVE_GORONSWORD:
// case RG_GIANTS_KNIFE:
// case RG_BIGGORON_SWORD:
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_PROGRESSIVE_BOMBCHUS:
return INV_CONTENT(ITEM_BOMBCHU) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE;
case RG_BOMBCHU_5:
case RG_BOMBCHU_10:
case RG_BOMBCHU_20:
case RG_BOMBCHU_DROP:
case RG_BUY_BOMBCHU_10:
case RG_BUY_BOMBCHU_20:
case RG_BUY_BOMBCHU_5:
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:
// 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) {
CanObtainResult canObtain = Randomizer::CanObtainRandomizerGet(randoGet);
if (canObtain !== CAN_OBTAIN) {
return GI_RUPEE_BLUE;
}
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;
case RG_GIANTS_KNIFE:
return GI_SWORD_KNIFE;
case RG_BIGGORON_SWORD:
return !gSaveContext.bgsFlag ? GI_SWORD_BGS : GI_RUPEE_BLUE;
return GI_SWORD_KOKIRI;
// TODO Progressive?
case RG_PROGRESSIVE_GORONSWORD:
return GI_SWORD_BGS;
// case RG_GIANTS_KNIFE:
// case RG_BIGGORON_SWORD:
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:
@ -1286,19 +1746,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:
@ -1308,41 +1763,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:
@ -1350,8 +1770,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:
@ -1359,31 +1777,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:
return GI_BOMBCHUS_20; //todo progressive?
case RG_PROGRESSIVE_MAGIC_METER:
switch (gSaveContext.magicLevel) {
case 0:
@ -1391,44 +1784,10 @@ 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;
// 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:
@ -1439,73 +1798,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) {
@ -1925,7 +2244,7 @@ u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) {
}
s16 Randomizer::GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId) {
return GetItemFromGet(this->itemLocations[randomizerCheck], ogId);
return GetItemIDFromRandomizerGet(this->itemLocations[randomizerCheck], ogId);
}
RandomizerCheck Randomizer::GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams) {

View File

@ -21,7 +21,8 @@ class Randomizer {
std::string ganonText;
std::unordered_map<RandomizerSettingKey, u8> randoSettings;
std::unordered_map<RandomizerCheck, u16> randomizerMerchantPrices;
s16 GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId);
CanObtainResult CanObtainRandomizerGet(RandomizerGet randoGet);
GetItemID GetItemIDFromRandomizerGet(RandomizerGet randoGet, GetItemID ogItemId);
s16 GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId);
void ParseRandomizerSettingsFile(const char* spoilerFileName);
void ParseHintLocationsFile(const char* spoilerFileName);

View File

@ -1020,6 +1020,14 @@ typedef enum {
RSK_SHUFFLE_MAGIC_BEANS
} RandomizerSettingKey;
typedef enum {
CAN_OBTAIN,
CANT_OBTAIN_MISC,
CANT_OBTAIN_ALREADY_HAVE,
CANT_OBTAIN_NEED_UPGRADE,
CANT_OBTAIN_NEED_EMPTY_BOTTLE,
} CanObtainResult;
typedef struct ScrubIdentity {
RandomizerInf randomizerInf;
RandomizerCheck randomizerCheck;

View File

@ -2534,6 +2534,22 @@ s32 Inventory_HasEmptyBottle(void) {
}
}
bool Inventory_HasEmptyBottleSlot(void) {
u8* items = gSaveContext.inventory.items;
if (items[SLOT_BOTTLE_1] == ITEM_NONE) {
return true;
} else if (items[SLOT_BOTTLE_2] == ITEM_NONE) {
return true;
} else if (items[SLOT_BOTTLE_3] == ITEM_NONE) {
return true;
} else if (items[SLOT_BOTTLE_4] == ITEM_NONE) {
return true;
} else {
return false;
}
}
s32 Inventory_HasSpecificBottle(u8 bottleItem) {
u8* items = gSaveContext.inventory.items;