From 0538c5a6446df4e3e3f06d5510446d38bc07eee6 Mon Sep 17 00:00:00 2001 From: PhlexPlexico Date: Mon, 19 Feb 2024 13:46:31 -0600 Subject: [PATCH] More decomp actor work (#36) * More decomp actor work. * Formatting fixes. Fix refill bottle logic to ensure we give a refill when requested. * Finalize bottle logic to not give the refill if user does not have an empty bottle. * Update to get Ingo bros to not give rewards after the first time. Same with medigoron and powder kegs. --- code/include/game/actor.h | 26 +++++--- code/include/rnd/savefile.h | 3 +- code/mm.ld | 100 +++++++++++++++--------------- code/source/rnd/item_override.cpp | 90 +++++++++++++++++++++------ code/source/rnd/item_upgrade.cpp | 3 - code/source/rnd/link.cpp | 3 +- code/source/rnd/savefile.cpp | 1 + 7 files changed, 142 insertions(+), 84 deletions(-) diff --git a/code/include/game/actor.h b/code/include/game/actor.h index b5db33a2..2f03e58f 100644 --- a/code/include/game/actor.h +++ b/code/include/game/actor.h @@ -194,6 +194,21 @@ namespace game::act { }; static_assert(sizeof(PosRot) == 0x14); + using ActorShadowFunc = void(Actor* self, void* lightMapper, GlobalContext* gctx); + struct ActorShape { + z3dVec3s rot; + s16 face; + float y_offset; + ActorShadowFunc* shadow_draw; + float shadow_scale; + u8 shadow_alpha; + u8 feet_floor_flags; + u8 field_16; + u8 field_17; + z3dVec3f feet_pos[2]; + }; + static_assert(sizeof(ActorShape) == 0x30); + struct Actor { enum class Flag : u32 { Targetable = 0x1, @@ -259,16 +274,7 @@ namespace game::act { DamageType damage_type; u8 field_BE; u8 field_BF; - // u16 field_C0; - // u16 angle; - z3dVec3s angle; - // u16 field_C4; - u8 gap_C6[2]; - float field_C8; - u32 field_CC; - float field_D0; - u8 field_D4; - u8 gap_D5[27]; + ActorShape actor_shape; z3dVec3f field_F0; u32 field_FC; z3dVec3f field_100; diff --git a/code/include/rnd/savefile.h b/code/include/rnd/savefile.h index 5b353818..a550eedb 100644 --- a/code/include/rnd/savefile.h +++ b/code/include/rnd/savefile.h @@ -90,7 +90,8 @@ namespace rnd { BitField<43, 1, u64> bottleChateuGiven; BitField<44, 1, u64> bottleRedPotionGiven; BitField<45, 2, u64> progressiveSwordUpgrade; - BitField<46, 18, u64> unused; + BitField<46, 1, u64> enInMysteryMilkGiven; + BitField<45, 17, u64> unused; }; GivenItemRegister givenItemChecks; union FairyCollectRegister { diff --git a/code/mm.ld b/code/mm.ld index fdb664ea..f8a6c4e0 100644 --- a/code/mm.ld +++ b/code/mm.ld @@ -37,6 +37,14 @@ SECTIONS{ *(.patch_Gfx_Update) } + .patch_FixSurroundSound 0x1404E8 : { + *(.patch_FixSurroundSound) + } + + .patch_RemoveCouplesMaskMessage 0x1867C4 : { + *(.patch_RemoveCouplesMaskMessage) + } + .patch_RemoveSOHCutesceneAfterMessage 0x186810 : { *(.patch_RemoveSOHCutesceneAfterMessage) } @@ -67,9 +75,17 @@ SECTIONS{ *(.patch_RemoveMysteryMilkTimer) } + .patch_GetCustomText 0x1BDE78 : { + *(.patch_GetCustomText) + } + .patch_DoNotResetTempleFlags 0x1C936C : { *(.patch_DoNotResetTempleFlags) - } + } + + .patch_DoNotResetPermFlags 0x1C9348 : { + *(.patch_DoNotResetPermFlags) + } .patch_DoNotRemoveTradeItems 0x1c9aa8 : { *(.patch_DoNotRemoveTradeItems) @@ -95,10 +111,22 @@ SECTIONS{ *(.patch_RemoveSwordFlagsOnReset) } + .patch_OverrideBomberTextID 0x1D2764 : { + *(.patch_OverrideBomberTextID) + } + + .patch_ISGCrouchStabOne 0x1D32E0 : { + *(.patch_ISGCrouchStabOne) + } + .patch_RemoveDekuMaskCheckSoT 0x1D8008 : { *(.patch_RemoveDekuMaskCheckSoT) } + .patch_RemoveMysteryMilkSoSCheck 0x1D79F8 : { + *(.patch_RemoveMysteryMilkSoSCheck) + } + .patch_DoNotForceMaskChange 0x1DB314 : { *(.patch_DoNotForceMaskChange) } @@ -107,10 +135,18 @@ SECTIONS{ *(.patch_HandleFastMaskTransforms) } + .patch_ISGCrouchStabTwo 0x1DBEA4 : { + *(.patch_ISGCrouchStabTwo) + } + .patch_RemoveMysteryMilkUsabilityCheck 0x1E04D8 : { *(.patch_RemoveMysteryMilkUsabilityCheck) } + .patch_OcarinaDive 0x1E1F0C : { + *(.patch_OcarinaDive) + } + .patch_ByPassMaskEquipmentChecks 0x1E770C : { *(.patch_ByPassMaskEquipmentChecks) } @@ -167,6 +203,18 @@ SECTIONS{ *(.patch_ZoraBarrierCheckMagicAcquired) } + .patch_RemoveRSHealthOne 0x20826C : { + *(.patch_RemoveRazordSwordHealth) + } + + .patch_RemoveRSHealthTwo 0x20843C : { + *(.patch_RemoveRazordSwordHealthTwo) + } + + .patch_OverrideItemIdIndex 0x21D124 : { + *(.patch_OverrideItemIdIndex) + } + .patch_ChangeTriggerAandRToA 0x220EFC : { *(.patch_ChangeTriggerAandRToA) } @@ -199,54 +247,10 @@ SECTIONS{ *(.patch_DisableMilkTimer) } - .patch_FixSurroundSound 0x1404E8 : { - *(.patch_FixSurroundSound) - } - - .patch_DoNotResetPermFlags 0x1C9348 : { - *(.patch_DoNotResetPermFlags) - } - - .patch_OcarinaDive 0x1E1F0C : { - *(.patch_OcarinaDive) - } - - .patch_GetCustomText 0x1BDE78 : { - *(.patch_GetCustomText) - } - - .patch_OverrideBomberTextID 0x1D2764 : { - *(.patch_OverrideBomberTextID) - } - - .patch_ISGCrouchStabOne 0x1D32E0 : { - *(.patch_ISGCrouchStabOne) - } - - .patch_RemoveMysteryMilkSoSCheck 0x1D79F8 : { - *(.patch_RemoveMysteryMilkSoSCheck) - } - - .patch_ISGCrouchStabTwo 0x1DBEA4 : { - *(.patch_ISGCrouchStabTwo) - } - - .patch_RemoveRSHealthOne 0x20826C : { - *(.patch_RemoveRazordSwordHealth) - } - - .patch_RemoveRSHealthTwo 0x20843C : { - *(.patch_RemoveRazordSwordHealthTwo) - } - .patch_RemoveRSHealthThree 0x235800 : { *(.patch_RemoveRazordSwordHealthThree) } - .patch_OverrideItemIdIndex 0x21d124 : { - *(.patch_OverrideItemIdIndex) - } - .patch_RemoveRemainsStateCheck 0x22B7BC : { *(.patch_RemoveRemainsStateCheck) } @@ -267,7 +271,7 @@ SECTIONS{ *(.patch_OverrideItemID) } - .patch_EnteringLocation 0x23aa54 : { + .patch_EnteringLocation 0x23AA54 : { *(.patch_EnteringLocation) } @@ -398,10 +402,6 @@ SECTIONS{ .patch_GibdoMaskGiveItem 0x41DC48 : { *(.patch_GibdoMaskGiveItem) } - /*0x46E228*/ - .patch_RemoveCouplesMaskMessage 0x1867C4 : { - *(.patch_RemoveCouplesMaskMessage) - } .patch_OverrideBankerWalletReward 0x459044 : { *(.patch_OverrideProgessiveWalletTwo) diff --git a/code/source/rnd/item_override.cpp b/code/source/rnd/item_override.cpp index 90d8aae5..4cab8f22 100644 --- a/code/source/rnd/item_override.cpp +++ b/code/source/rnd/item_override.cpp @@ -45,8 +45,8 @@ namespace rnd { rItemOverrides[0].value.looksLikeItemId = 0x26; rItemOverrides[1].key.scene = 0x6F; rItemOverrides[1].key.type = ItemOverride_Type::OVR_COLLECTABLE; - rItemOverrides[1].value.getItemId = 0x01; - rItemOverrides[1].value.looksLikeItemId = 0x01; + rItemOverrides[1].value.getItemId = 0x0C; + rItemOverrides[1].value.looksLikeItemId = 0x0C; rItemOverrides[2].key.scene = 0x12; rItemOverrides[2].key.type = ItemOverride_Type::OVR_COLLECTABLE; rItemOverrides[2].value.getItemId = 0x37; @@ -452,6 +452,8 @@ namespace rnd { gExtSaveData.givenItemChecks.bgDyYoseizoGivenItem = 1; } else if (storedActorId == game::act::Id::EnIn && storedGetItemId == GetItemID::GI_MASK_GARO) { gExtSaveData.givenItemChecks.enInGivenItem = 1; + } else if (storedActorId == game::act::Id::EnIn && storedGetItemId == GetItemID::GI_BOTTLE_MYSTERY_MILK) { + gExtSaveData.givenItemChecks.enInMysteryMilkGiven = 1; } else if (storedActorId == game::act::Id::EnHs) { gExtSaveData.givenItemChecks.enHsGivenItem = 1; } else if (storedActorId == game::act::Id::EnHgo) { @@ -500,6 +502,8 @@ namespace rnd { gExtSaveData.givenItemChecks.bottleChateuGiven = 1; } else if (storedGetItemId == GetItemID::GI_BOTTLE_SEAHORSE) { gExtSaveData.givenItemChecks.bottleSeahorseGiven = 1; + } else if (storedGetItemId == GetItemID::GI_BOTTLE_POTION_RED) { + gExtSaveData.givenItemChecks.bottleRedPotionGiven = 1; } } @@ -585,6 +589,12 @@ namespace rnd { return 0x00; } + bool ItemOverride_IsItemObtained(ItemOverride override) { + ItemRow* itemToBeGiven = ItemTable_GetItemRow(override.value.getItemId); + return (game::HasMask((game::ItemId)itemToBeGiven->itemId) || game::HasItem((game::ItemId)itemToBeGiven->itemId) || + (itemToBeGiven->itemId > 0x49 && itemToBeGiven->itemId < 0x9E)); + } + extern "C" { bool ItemOverride_CheckAromaGivenItem() { if (gExtSaveData.givenItemChecks.enAlGivenItem > 0) @@ -612,8 +622,8 @@ namespace rnd { rnd::util::Print("%s: Active item row item ID is %#04x and key flag is %#04x\n", __func__, rActiveItemRow->itemId, rActiveItemOverride.key.flag); #endif - // Only set if we're not a trade item or bottled item. - if ((rActiveItemRow->itemId < 0x12 || rActiveItemRow->itemId > 0x30) && (rActiveItemRow->itemId < 0x9F)) { + // Only set if we're not a trade item. + if ((rActiveItemRow->itemId < 0x28 || rActiveItemRow->itemId > 0x30) && (rActiveItemRow->itemId < 0x9F)) { gExtSaveData.chestRewarded[rActiveItemOverride.key.scene][rActiveItemOverride.key.flag] = 1; } } @@ -651,7 +661,7 @@ namespace rnd { if (override.key.all != 0) { // Override the stored get item if we are a bottled item. if (override.value.getItemId == 0x59 || override.value.getItemId == 0x60 || override.value.getItemId == 0x6A || - override.value.getItemId == 0x6E || override.value.getItemId == 0x6F || override.value.getItemId == 0x70) { + override.value.getItemId == 0x6E || override.value.getItemId == 0x6F) { storedGetItemId = (GetItemID) override.value.getItemId; } } @@ -666,19 +676,55 @@ namespace rnd { // Override was already given, check to see if the item exists in inventory, if it does // then we give a blue rupee. Only check for inventory items. If an item is a heart piece // do not give multiples. - // Only do this for items that are not bottle refills. - // Bottle logic is taken care of in the ItemUpgrade function for each bottle. - ItemRow* itemToBeGiven = ItemTable_GetItemRow(override.value.getItemId); - if (game::HasMask((game::ItemId)itemToBeGiven->itemId) || game::HasItem((game::ItemId)itemToBeGiven->itemId) || - itemToBeGiven->itemId > 0x49) { + if (ItemOverride_IsItemObtained(override)) { + // Do a secondary check as well for bottled items, and check to see if we have an empty bottle in our inventory. + // If we don't, then do not give the item as we don't want to override items in users inventories. override.value.getItemId = 0x02; override.value.looksLikeItemId = 0x02; + } else if (override.value.getItemId == 0x59 || override.value.getItemId == 0x60 || + override.value.getItemId == 0x6A || override.value.getItemId == 0x6E || + override.value.getItemId == 0x6F) { + switch (override.value.getItemId) { + case 0x59: + if (gExtSaveData.givenItemChecks.bottleRedPotionGiven == 1 && !game::HasBottle(game::ItemId::Bottle)) { + override.value.getItemId = 0x02; + override.value.looksLikeItemId = 0x02; + } + break; + case 0x60: + if (gExtSaveData.givenItemChecks.bottleMilkGiven == 1 && !game::HasBottle(game::ItemId::Bottle)) { + override.value.getItemId = 0x02; + override.value.looksLikeItemId = 0x02; + } + break; + case 0x6A: + if (gExtSaveData.givenItemChecks.bottleGoldDustGiven == 1 && !game::HasBottle(game::ItemId::Bottle)) { + override.value.getItemId = 0x02; + override.value.looksLikeItemId = 0x02; + } + break; + case 0x6E: + if (gExtSaveData.givenItemChecks.bottleSeahorseGiven == 1 && !game::HasBottle(game::ItemId::Bottle)) { + override.value.getItemId = 0x02; + override.value.looksLikeItemId = 0x02; + } + break; + case 0x6F: + if (gExtSaveData.givenItemChecks.bottleChateuGiven == 1 && !game::HasBottle(game::ItemId::Bottle)) { + override.value.getItemId = 0x02; + override.value.looksLikeItemId = 0x02; + } + break; + default: + break; + } } } // 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. + // XXX: This may be simplified with the IsItemObtained checks as well. if (override.value.getItemId > 0x45 || override.value.getItemId < 0x4A) { if (incomingGetItemId == (s16)GetItemID::GI_MOONS_TEAR && gExtSaveData.givenItemChecks.enObjMoonStoneGivenItem == 1) { @@ -707,7 +753,20 @@ namespace rnd { return; } } - + if (incomingGetItemId == 0x70 || incomingGetItemId == 0x94) { + // If we've completed the milk quest, make sure we're not a heart piece + // or any way to cheese the game. + if (gExtSaveData.givenItemChecks.enInMysteryMilkGiven == 1 && ItemOverride_IsItemObtained(override)) { + override.value.getItemId = 0x02; + override.value.looksLikeItemId = 0x02; + } + } else if (incomingGetItemId == (s16)GetItemID::GI_POWDER_KEG && + (gctx->scene == game::SceneId::GoronVillageWinter || gctx->scene == game::SceneId::GoronVillageSpring) && + gExtSaveData.givenItemChecks.enGoGivenItem == 1) { + // Also check if we are not the powder keg area as to avoid getting multiple items. + override.value.getItemId = 0x02; + override.value.looksLikeItemId = 0x02; + } ItemOverride_Activate(override); s16 baseItemId = rActiveItemRow->baseItemId; @@ -762,7 +821,7 @@ namespace rnd { void ItemOverride_GetSoHItem(game::GlobalContext* gctx, game::act::Actor* fromActor, s16 incomingItemId) { game::act::Player* link = gctx->GetPlayerActor(); // Run only once. Once the get item is assigned, we shouldn't have to worry about running it again. - // This is mainly prevalent when the item override is in a calc function (Anju). + // This is mainly prevalent when the item override is in a calc function (Anju & Kafei). if (link->get_item_id != 0x00) return; if (incomingItemId == 0x7A) { @@ -855,7 +914,6 @@ namespace rnd { if (gctx->scene == game::SceneId::GoronVillageWinter || gctx->scene == game::SceneId::GoronVillageSpring) { return givenItems.enGoGivenItem ? (int) currentItem : (int)0xFF; - } return game::HasItem((game::ItemId)currentItem) ? (int) currentItem @@ -936,11 +994,5 @@ namespace rnd { u32 ItemOverride_GetOshExtData() { return (u32)gExtSaveData.givenItemChecks.enOshGivenItem; } - - void DebugStatement(game::ItemId curItemSlot) { -#if defined ENABLE_DEBUG || defined DEBUG_PRINT - rnd::util::Print("%s: Current item slot is %#04x\n", __func__, curItemSlot); -#endif - } } } // namespace rnd diff --git a/code/source/rnd/item_upgrade.cpp b/code/source/rnd/item_upgrade.cpp index d1c3fa94..4c14761f 100644 --- a/code/source/rnd/item_upgrade.cpp +++ b/code/source/rnd/item_upgrade.cpp @@ -105,9 +105,6 @@ namespace rnd { 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; diff --git a/code/source/rnd/link.cpp b/code/source/rnd/link.cpp index 699a2828..f7b69443 100644 --- a/code/source/rnd/link.cpp +++ b/code/source/rnd/link.cpp @@ -112,7 +112,8 @@ namespace rnd::link { util::Print("%s: spawning %s (param=%u)\n", __func__, s_arrow_types[type].name, param); #endif - auto* arrow = gctx->SpawnActor(player, game::act::Id::Arrow, 0, player->angle.y, 0, param, player->pos.pos); + auto* arrow = + gctx->SpawnActor(player, game::act::Id::Arrow, 0, player->actor_shape.rot.y, 0, param, player->pos.pos); player->projectile_actor = arrow; cdata.magic_cost = 0; // For some reason, updating the magic cost immediately doesn't work, diff --git a/code/source/rnd/savefile.cpp b/code/source/rnd/savefile.cpp index 4ef58609..a048563e 100644 --- a/code/source/rnd/savefile.cpp +++ b/code/source/rnd/savefile.cpp @@ -29,6 +29,7 @@ namespace rnd { rnd::util::GetPointer(0x22b14c)(game::ItemId::PictographBox); rnd::util::GetPointer(0x22b14c)(game::ItemId::BlastMask); rnd::util::GetPointer(0x22b14c)(game::ItemId::KafeiMask); + rnd::util::GetPointer(0x22b14c)(game::ItemId::CircusLeaderMask); // rnd::util::GetPointer(0x22b14c)(game::ItemId::PowderKeg); // saveData.inventory.inventory_count_register.quiver_upgrade = game::Quiver::Quiver50; saveData.inventory.inventory_count_register.bomb_bag_upgrade = game::BombBag::BombBag40;