From 44223c515b0f058324e93321c1ba127dc83e1fdf Mon Sep 17 00:00:00 2001 From: PhlexPlexico Date: Thu, 8 Feb 2024 12:30:21 -0600 Subject: [PATCH] Chests with bottle content no longer show animation upon receiving refill. (#30) Hero Shield items will now give you a silver rupee if you already have the mirror shield. Fix Bottle Logic, as well as chest repeat logic. Progressive items will now properly give you fishing passes if retrieved once from trade items. Better passthrough handling with bottle refills and blue rupee chest cases. --- code/include/rnd/item_upgrade.h | 2 + code/source/rnd/item_override.cpp | 149 +++++++++++++----------------- code/source/rnd/item_table.cpp | 23 ++--- code/source/rnd/item_upgrade.cpp | 51 ++++++++++ 4 files changed, 131 insertions(+), 94 deletions(-) diff --git a/code/include/rnd/item_upgrade.h b/code/include/rnd/item_upgrade.h index 7055caa0..3a49ad2a 100644 --- a/code/include/rnd/item_upgrade.h +++ b/code/include/rnd/item_upgrade.h @@ -14,6 +14,8 @@ namespace rnd { GetItemID ItemUpgrade_Sword(game::SaveData*, GetItemID); GetItemID ItemUpgrade_ArrowsToRupee(game::SaveData*, GetItemID); GetItemID ItemUpgrade_BombsToRupee(game::SaveData*, GetItemID); + GetItemID ItemUpgrade_RefillBottle(game::SaveData*, GetItemID); + GetItemID ItemUpgrade_CheckShield(game::SaveData*, GetItemID); // GetItemID ItemUpgrade_LetterToBottle(game::SaveData*, GetItemID); } // namespace rnd diff --git a/code/source/rnd/item_override.cpp b/code/source/rnd/item_override.cpp index bda3f166..fc85bb5b 100644 --- a/code/source/rnd/item_override.cpp +++ b/code/source/rnd/item_override.cpp @@ -44,9 +44,9 @@ namespace rnd { rItemOverrides[0].value.getItemId = 0x26; rItemOverrides[0].value.looksLikeItemId = 0x26; rItemOverrides[1].key.scene = 0x6F; - rItemOverrides[1].key.type = ItemOverride_Type::OVR_COLLECTABLE; - rItemOverrides[1].value.getItemId = 0x34; - rItemOverrides[1].value.looksLikeItemId = 0x34; + rItemOverrides[1].key.type = ItemOverride_Type::OVR_CHEST; + rItemOverrides[1].value.getItemId = 0x32; + rItemOverrides[1].value.looksLikeItemId = 0x32; rItemOverrides[2].key.scene = 0x12; rItemOverrides[2].key.type = ItemOverride_Type::OVR_COLLECTABLE; rItemOverrides[2].value.getItemId = 0x37; @@ -105,15 +105,15 @@ namespace rnd { } ItemOverride ItemOverride_Lookup(game::act::Actor* actor, u16 scene, s16 getItemId) { - ItemOverride_Key key = ItemOverride_GetSearchKey(actor, scene, getItemId); - if (key.all == 0) { - return (ItemOverride){0}; - } // #if defined ENABLE_DEBUG || defined DEBUG_PRINT // rnd::util::Print( // "%s: Our param values:\nActor Type %#04x\nGet Item ID: %#04x\nActor ID: %#06x\n", // __func__, actor->actor_type, getItemId, actor->id); // #endif + ItemOverride_Key key = ItemOverride_GetSearchKey(actor, scene, getItemId); + if (key.all == 0) { + return (ItemOverride){0}; + } return ItemOverride_LookupByKey(key); } @@ -141,7 +141,6 @@ namespace rnd { u16 resolvedGetItemId = ItemTable_ResolveUpgrades(override.value.getItemId); ItemRow* itemRow = ItemTable_GetItemRow(resolvedGetItemId); - // XXX: Maybe create function for progressive items so that the item drawn is correct? u8 looksLikeItemId = ItemOverride_SetProgressiveItemDraw(override); rActiveItemOverride = override; @@ -492,6 +491,20 @@ namespace rnd { gExtSaveData.givenItemChecks.enMtnDeedGivenItem = 1; } else if (storedGetItemId == rnd::GetItemID::GI_OCEAN_TITLE_DEED) { gExtSaveData.givenItemChecks.enOcnDeedGivenItem = 1; + } else if (storedGetItemId == GetItemID::GI_BOTTLE_MILK) { + gExtSaveData.givenItemChecks.bottleMilkGiven = 1; + } else if (storedGetItemId == GetItemID::GI_BOTTLE_GOLD_DUST || + (s16)storedGetItemId == -(s16)GetItemID::GI_BOTTLE_GOLD_DUST) { + gExtSaveData.givenItemChecks.bottleGoldDustGiven = 1; + } else if (storedGetItemId == GetItemID::GI_BOTTLE_CHATEAU_ROMANI || + (s16)storedGetItemId == -(s16)GetItemID::GI_BOTTLE_CHATEAU_ROMANI) { + gExtSaveData.givenItemChecks.bottleChateuGiven = 1; + } else if (storedGetItemId == GetItemID::GI_BOTTLE_SEAHORSE || + (s16)storedGetItemId == -(s16)GetItemID::GI_BOTTLE_SEAHORSE) { + gExtSaveData.givenItemChecks.bottleSeahorseGiven = 1; + } else if (storedGetItemId == GetItemID::GI_BOTTLE_MYSTERY_MILK || + (s16)storedGetItemId == -(s16)GetItemID::GI_BOTTLE_MYSTERY_MILK) { + gExtSaveData.givenItemChecks.bottleMysteryMilkGiven = 1; } } @@ -550,31 +563,42 @@ namespace rnd { return; } - void ItemOverride_SetBottleRefill(game::act::Player* player, s16 refItemId, bool isChest = false) { + u16 ItemOverride_SetBottleRefill(game::act::Player* player, u16 refItemId) { switch (refItemId) { case 0x60: - player->get_item_id = isChest ? -(s16)GetItemID::GI_BOTTLE_MILK_REFILL : (s16)GetItemID::GI_BOTTLE_MILK_REFILL; + if (gExtSaveData.givenItemChecks.bottleMilkGiven == 1) { + storedGetItemId = GetItemID::GI_BOTTLE_MILK_REFILL; + return 0x92; + } break; case 0x6A: - player->get_item_id = - isChest ? -(s16)GetItemID::GI_BOTTLE_GOLD_DUST_REFILL : (s16)GetItemID::GI_BOTTLE_GOLD_DUST_REFILL; + if (gExtSaveData.givenItemChecks.bottleGoldDustGiven == 1) { + storedGetItemId = GetItemID::GI_BOTTLE_GOLD_DUST_REFILL; + return 0x93; + } break; case 0x6F: - player->get_item_id = - isChest ? -(s16)GetItemID::GI_BOTTLE_CHATEAU_ROMANI_REFILL : (s16)GetItemID::GI_BOTTLE_CHATEAU_ROMANI_REFILL; + if (gExtSaveData.givenItemChecks.bottleChateuGiven == 1) { + storedGetItemId = GetItemID::GI_BOTTLE_CHATEAU_ROMANI_REFILL; + return 0x91; + } break; case 0x6E: - player->get_item_id = - isChest ? -(s16)GetItemID::GI_BOTTLE_SEAHORSE_REFILL : (s16)GetItemID::GI_BOTTLE_SEAHORSE_REFILL; + if (gExtSaveData.givenItemChecks.bottleSeahorseGiven == 1) { + storedGetItemId = GetItemID::GI_BOTTLE_SEAHORSE_REFILL; + return 0x95; + } break; case 0x70: - player->get_item_id = isChest ? -(s16)GetItemID::GI_BOTTLE_MYSTERY_MILK : (s16)GetItemID::GI_BOTTLE_MYSTERY_MILK; + if (gExtSaveData.givenItemChecks.bottleMysteryMilkGiven == 0) { + storedGetItemId = GetItemID::GI_BOTTLE_MYSTERY_MILK_REFILL; + return 0x94; + } break; default: - player->get_item_id = isChest ? -(s16)GetItemID::GI_RUPEE_BLUE : (s16)GetItemID::GI_RUPEE_BLUE; - break; + return (u16)GetItemID::GI_RUPEE_BLUE; } - return; + return (u16)refItemId; } u8 ItemOverride_SetProgressiveItemDraw(ItemOverride override) { @@ -600,7 +624,8 @@ namespace rnd { else return 0x09; } - return override.value.looksLikeItemId; + // No override, use the base item. + return 0x00; } extern "C" { @@ -672,89 +697,47 @@ namespace rnd { return; } else if (override.key.type == ItemOverride_Type::OVR_CHEST && gExtSaveData.chestRewarded[override.key.scene][override.key.flag] == 1) { - // Override was already given, use base game's item code - // If we're a bottled item in our override, we've been received before. Give a refill. - u16 refItemId = override.value.getItemId; -#if defined ENABLE_DEBUG || defined DEBUG_PRINT - rnd::util::Print("%s: Our ref item id is %#04x\n", __func__, refItemId); -#endif - ItemOverride_Clear(); - ItemOverride_SetBottleRefill(player, (s16)refItemId, true); - return; - } else if (override.value.getItemId > 0x45 && override.value.getItemId < 0x4B) { - // This check is mainly to ensure we do not have repeatable progressive items within these base items. - // This is to ensure fairness and allows us to place these items without second guessing in logic. - // Let's be a bit rude and give them fishing passes. + // Override was already given, give a blue rupee instead. + override.value.getItemId = 0x02; + override.value.looksLikeItemId = 0x02; + } + + // This check is mainly to ensure we do not have repeatable progressive items within these base items. + // This is to ensure fairness and allows us to place these items without second guessing in logic. + // Let's be a bit rude and give them fishing passes. + if (override.value.getItemId > 0x45 || override.value.getItemId < 0x4A) { if (incomingGetItemId == (s16)GetItemID::GI_MOONS_TEAR && gExtSaveData.givenItemChecks.enObjMoonStoneGivenItem == 1) { player->get_item_id = (s16)GetItemID::GI_FISHING_HOLE_PASS; + ItemOverride_Clear(); return; } else if (incomingGetItemId == (s16)GetItemID::GI_TOWN_TITLE_DEED && gExtSaveData.givenItemChecks.enTownDeedGivenItem == 1) { player->get_item_id = (s16)GetItemID::GI_FISHING_HOLE_PASS; + ItemOverride_Clear(); return; } else if (incomingGetItemId == (s16)GetItemID::GI_SWAMP_TITLE_DEED && gExtSaveData.givenItemChecks.enSwampDeedGivenItem == 1) { player->get_item_id = (s16)GetItemID::GI_FISHING_HOLE_PASS; + ItemOverride_Clear(); return; } else if (incomingGetItemId == (s16)GetItemID::GI_MOUNTAIN_TITLE_DEED && gExtSaveData.givenItemChecks.enMtnDeedGivenItem == 1) { player->get_item_id = (s16)GetItemID::GI_FISHING_HOLE_PASS; + ItemOverride_Clear(); return; } else if (incomingGetItemId == (s16)GetItemID::GI_OCEAN_TITLE_DEED && gExtSaveData.givenItemChecks.enOcnDeedGivenItem == 1) { player->get_item_id = (s16)GetItemID::GI_FISHING_HOLE_PASS; + ItemOverride_Clear(); return; } - } else if (override.key.type != ItemOverride_Type::OVR_CHEST && - (override.value.getItemId == 0x60 || - (override.value.getItemId > 0x69 && override.value.getItemId < 0x71))) { - switch (override.value.getItemId) { - case 0x60: - if (gExtSaveData.givenItemChecks.bottleMilkGiven == 0) { - gExtSaveData.givenItemChecks.bottleMilkGiven = 1; - } else { - ItemOverride_SetBottleRefill(player, (s16) override.value.getItemId); - return; - } - break; - case 0x6A: - if (gExtSaveData.givenItemChecks.bottleGoldDustGiven == 0) { - gExtSaveData.givenItemChecks.bottleGoldDustGiven = 1; - } else { - ItemOverride_SetBottleRefill(player, (s16) override.value.getItemId); - return; - } - break; - case 0x6F: - if (gExtSaveData.givenItemChecks.bottleGoldDustGiven == 0) { - gExtSaveData.givenItemChecks.bottleGoldDustGiven = 1; - } else { - ItemOverride_SetBottleRefill(player, (s16) override.value.getItemId); - return; - } - break; - case 0x6E: - if (gExtSaveData.givenItemChecks.bottleSeahorseGiven == 0) { - gExtSaveData.givenItemChecks.bottleSeahorseGiven = 1; - } else { - ItemOverride_SetBottleRefill(player, (s16) override.value.getItemId); - return; - } - break; - case 0x70: - if (gExtSaveData.givenItemChecks.bottleMysteryMilkGiven == 0) { - gExtSaveData.givenItemChecks.bottleMysteryMilkGiven = 1; - } else { - ItemOverride_SetBottleRefill(player, (s16) override.value.getItemId); - return; - } - break; - default: - player->get_item_id = -(s16)GetItemID::GI_RUPEE_BLUE; - break; - } - return; + } + + // If we are a bottled item, store the GID to write the ext data. This will ensure through + // ItemUpgrade_BottleRefill that we get a refill on a bottle instead of a new bottle. + if (override.value.getItemId == 0x60 || (override.value.getItemId > 0x69 && override.value.getItemId < 0x71)) { + storedGetItemId = (GetItemID) override.value.getItemId; } ItemOverride_Activate(override); s16 baseItemId = rActiveItemRow->baseItemId; diff --git a/code/source/rnd/item_table.cpp b/code/source/rnd/item_table.cpp index 8827e8c4..3c4a8f0a 100644 --- a/code/source/rnd/item_table.cpp +++ b/code/source/rnd/item_table.cpp @@ -282,7 +282,7 @@ namespace rnd { [0x32] = ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::HeroShield, 0x0032, 0x000B3, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s32)DrawGraphicItemID::DI_HERO_SHIELD, - (rnd::upgradeFunc)ItemUpgrade_None, ItemEffect_None, (s16)-1, (s16)-1), // Hero Sheild + (rnd::upgradeFunc)ItemUpgrade_CheckShield, ItemEffect_None, (s16)-1, (s16)-1), // Hero Sheild [0x33] = ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::MirrorShield, 0x0033, 0x000C3, @@ -504,9 +504,10 @@ namespace rnd { (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s32)DrawGraphicItemID::DI_BOTTLE_DEKU_PRINCESS, (rnd::upgradeFunc)ItemUpgrade_None, ItemEffect_None, (s16)-1, (s16)-1), // Bottle With Deku Princess - [0x60] = ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::Milk, 0x0060, 0x00B6, - (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s32)DrawGraphicItemID::DI_MILK_FULL, - (rnd::upgradeFunc)ItemUpgrade_None, ItemEffect_None, (s16)-1, (s16)-1), // Bottle With Milk + [0x60] = + ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::Milk, 0x0060, 0x00B6, (s8)0xFF, + (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s32)DrawGraphicItemID::DI_MILK_FULL, + (rnd::upgradeFunc)ItemUpgrade_RefillBottle, ItemEffect_None, (s16)-1, (s16)-1), // Bottle With Milk [0x61] = ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::Milk, 0x0061, 0x00B6, (s8)0xFF, @@ -550,10 +551,10 @@ namespace rnd { (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s32)DrawGraphicItemID::DI_BOTTLE_ZORA_EGG, (rnd::upgradeFunc)ItemUpgrade_None, ItemEffect_None, (s16)-1, (s16)-1), // Bottle With Zora Egg - [0x6A] = - ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::GoldDust, 0x006A, 0x01E9, - (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s32)DrawGraphicItemID::DI_GOLD_DUST, - (rnd::upgradeFunc)ItemUpgrade_None, ItemEffect_None, (s16)-1, (s16)-1), // Bottle With Gold Dust + [0x6A] = ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::GoldDust, 0x006A, 0x01E9, + (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s32)DrawGraphicItemID::DI_GOLD_DUST, + (rnd::upgradeFunc)ItemUpgrade_RefillBottle, ItemEffect_None, (s16)-1, + (s16)-1), // Bottle With Gold Dust [0x6B] = ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::MagicalMushroom, 0x006B, 0x021D, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, @@ -572,12 +573,12 @@ namespace rnd { [0x6E] = ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::SeaHorse, 0x006E, 0x01E9, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s32)DrawGraphicItemID::DI_BOTTLE_SEAHORSE, - (rnd::upgradeFunc)ItemUpgrade_None, ItemEffect_None, (s16)-1, + (rnd::upgradeFunc)ItemUpgrade_RefillBottle, ItemEffect_None, (s16)-1, (s16)-1), // Bottle With Sea Horse - Gold Dust Object [0x6F] = ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::ChateauRomani, 0x006F, 0x0227, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, - (s32)DrawGraphicItemID::DI_BOTTLE_CHATEAU_ROMANI, (rnd::upgradeFunc)ItemUpgrade_None, + (s32)DrawGraphicItemID::DI_BOTTLE_CHATEAU_ROMANI, (rnd::upgradeFunc)ItemUpgrade_RefillBottle, ItemEffect_None, (s16)-1, (s16)-1), // Bottle With Chateau Romani // XXX: Trade Item, may have to change values? Seems rather individual and leads to fishing @@ -585,7 +586,7 @@ namespace rnd { [0x70] = ITEM_ROW((u32)GetItemID::GI_NUTS_30, ChestType::WOODEN_BIG, (u8)game::ItemId::MysteryMilk, 0x00CE, 0x00B6, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s8)0xFF, (s32)DrawGraphicItemID::DI_BOTTLE_MYSTERY_MILK, - (rnd::upgradeFunc)ItemUpgrade_None, ItemEffect_None, (s16)-1, + (rnd::upgradeFunc)ItemUpgrade_RefillBottle, ItemEffect_None, (s16)-1, (s16)-1), // Bottle With Mystery Milk [0x71] = diff --git a/code/source/rnd/item_upgrade.cpp b/code/source/rnd/item_upgrade.cpp index 411aa9a0..99d4f2b0 100644 --- a/code/source/rnd/item_upgrade.cpp +++ b/code/source/rnd/item_upgrade.cpp @@ -87,6 +87,57 @@ namespace rnd { getItemId; } + GetItemID ItemUpgrade_RefillBottle(game::SaveData* saveCtx, GetItemID getItemId) { + switch (getItemId) { + case GetItemID::GI_BOTTLE_MILK: + if (gExtSaveData.givenItemChecks.bottleMilkGiven == 1) { + return GetItemID::GI_BOTTLE_MILK_REFILL; + } + break; + case GetItemID::GI_BOTTLE_GOLD_DUST: + if (gExtSaveData.givenItemChecks.bottleGoldDustGiven == 1) { +#if defined ENABLE_DEBUG || defined DEBUG_PRINT + rnd::util::Print("%s: Gold dust given, overriding for refill.\n", __func__); +#endif + return GetItemID::GI_BOTTLE_GOLD_DUST_REFILL; + } + break; + case GetItemID::GI_BOTTLE_SEAHORSE: + if (gExtSaveData.givenItemChecks.bottleSeahorseGiven == 1) { + return GetItemID::GI_BOTTLE_SEAHORSE_REFILL; + } + break; + case GetItemID::GI_BOTTLE_CHATEAU_ROMANI: + if (gExtSaveData.givenItemChecks.bottleChateuGiven == 1) { + return GetItemID::GI_BOTTLE_CHATEAU_ROMANI_REFILL; + } + break; + case GetItemID::GI_BOTTLE_MYSTERY_MILK: + if (gExtSaveData.givenItemChecks.bottleMysteryMilkGiven == 1) { + return GetItemID::GI_BOTTLE_MYSTERY_MILK_REFILL; + } + break; + default: + return getItemId; + } + return getItemId; + } + + GetItemID ItemUpgrade_CheckShield(game::SaveData* saveCtx, GetItemID getItemId) { + switch(saveCtx->equipment.sword_shield.shield) { + case game::ShieldType::NoShield: + return getItemId; + case game::ShieldType::HeroShield: + return getItemId; + case game::ShieldType::MirrorShield: + if (getItemId == GetItemID::GI_SHIELD_HERO) + return GetItemID::GI_RUPEE_SILVER; // Give siler rupee, close enough to same cost. + else return getItemId; + default: + return getItemId; + } + } + // TODO: Trade quest items. /* game::ItemId ItemUpgrade_LetterToBottle(game::SaveData *saveCtx, GetItemId GetItemId) {