diff --git a/code/include/game/context.h b/code/include/game/context.h index b065e88..9b33973 100644 --- a/code/include/game/context.h +++ b/code/include/game/context.h @@ -86,7 +86,137 @@ namespace game { WarpingToStoneTower = 0x25, }; - // Incomplete + enum class OcarinaMode : u16 { + OCARINA_MODE_NONE = 0, + OCARINA_MODE_ACTIVE = 1, + OCARINA_MODE_WARP = 2, + OCARINA_MODE_EVENT = 3, + OCARINA_MODE_END = 4, + OCARINA_MODE_PLAYED_TIME = 5, + OCARINA_MODE_PLAYED_HEALING = 6, + OCARINA_MODE_PLAYED_EPONAS = 7, + OCARINA_MODE_PLAYED_SOARING = 8, + OCARINA_MODE_PLAYED_STORMS = 9, + OCARINA_MODE_PLAYED_SUNS = 10, + OCARINA_MODE_PLAYED_INVERTED_TIME = 11, + OCARINA_MODE_PLAYED_DOUBLE_TIME = 12, + OCARINA_MODE_PLAYED_SCARECROW_SPAWN = 13, + OCARINA_MODE_E = 14, + OCARINA_MODE_F = 15, + OCARINA_MODE_10 = 16, + OCARINA_MODE_11 = 17, + OCARINA_MODE_PROCESS_SOT = 18, + OCARINA_MODE_PROCESS_INVERTED_TIME = 19, + OCARINA_MODE_14 = 20, + OCARINA_MODE_PROCESS_DOUBLE_TIME = 21, + OCARINA_MODE_APPLY_SOT = 22, + OCARINA_MODE_17 = 23, + OCARINA_MODE_APPLY_INV_SOT_FAST = 24, + OCARINA_MODE_APPLY_INV_SOT_SLOW = 25, + OCARINA_MODE_APPLY_DOUBLE_SOT = 26, + OCARINA_MODE_1B = 27, + OCARINA_MODE_WARP_TO_GREAT_BAY_COAST = 28, + OCARINA_MODE_WARP_TO_ZORA_CAPE = 29, + OCARINA_MODE_WARP_TO_SNOWHEAD = 30, + OCARINA_MODE_WARP_TO_MOUNTAIN_VILLAGE = 31, + OCARINA_MODE_WARP_TO_SOUTH_CLOCK_TOWN = 32, + OCARINA_MODE_WARP_TO_MILK_ROAD = 33, + OCARINA_MODE_WARP_TO_WOODFALL = 34, + OCARINA_MODE_WARP_TO_SOUTHERN_SWAMP = 35, + OCARINA_MODE_WARP_TO_IKANA_CANYON = 36, + OCARINA_MODE_WARP_TO_STONE_TOWER = 37, + OCARINA_MODE_WARP_TO_ENTRANCE = 38, + OCARINA_MODE_PROCESS_RESTRICTED_SONG = 39, + OCARINA_MODE_28 = 40, + OCARINA_MODE_29 = 41, + OCARINA_MODE_PLAYED_FULL_EVAN_SONG = 42 + }; + + enum class OcarinaSongActionId : u16 { + OCARINA_ACTION_0 = 0, + OCARINA_ACTION_FREE_PLAY = 1, + OCARINA_ACTION_DEMONSTRATE_SONATA = 2, + OCARINA_ACTION_DEMONSTRATE_GORON_LULLABY = 3, + OCARINA_ACTION_DEMONSTRATE_NEW_WAVE = 4, + OCARINA_ACTION_DEMONSTRATE_ELEGY = 5, + OCARINA_ACTION_DEMONSTRATE_OATH = 6, + OCARINA_ACTION_DEMONSTRATE_SARIAS = 7, + OCARINA_ACTION_DEMONSTRATE_TIME = 8, + OCARINA_ACTION_DEMONSTRATE_HEALING = 9, + OCARINA_ACTION_DEMONSTRATE_EPONAS = 10, + OCARINA_ACTION_DEMONSTRATE_SOARING = 11, + OCARINA_ACTION_DEMONSTRATE_STORMS = 12, + OCARINA_ACTION_DEMONSTRATE_SUNS = 13, + OCARINA_ACTION_DEMONSTRATE_INVERTED_TIME = 14, + OCARINA_ACTION_DEMONSTRATE_DOUBLE_TIME = 15, + OCARINA_ACTION_DEMONSTRATE_GORON_LULLABY_INTRO = 16, + OCARINA_ACTION_11 = 17, + OCARINA_ACTION_PROMPT_SONATA = 18, + OCARINA_ACTION_PROMPT_GORON_LULLABY = 19, + OCARINA_ACTION_PROMPT_NEW_WAVE = 20, + OCARINA_ACTION_PROMPT_ELEGY = 21, + OCARINA_ACTION_PROMPT_OATH = 22, + OCARINA_ACTION_PROMPT_SARIAS = 23, + OCARINA_ACTION_PROMPT_TIME = 24, + OCARINA_ACTION_PROMPT_HEALING = 25, + OCARINA_ACTION_PROMPT_EPONAS = 26, + OCARINA_ACTION_PROMPT_SOARING = 27, + OCARINA_ACTION_PROMPT_STORMS = 28, + OCARINA_ACTION_PROMPT_SUNS = 29, + OCARINA_ACTION_PROMPT_INVERTED_TIME = 30, + OCARINA_ACTION_PROMPT_DOUBLE_TIME = 31, + OCARINA_ACTION_PROMPT_GORON_LULLABY_INTRO = 32, + OCARINA_ACTION_21 = 33, + OCARINA_ACTION_CHECK_SONATA = 34, + OCARINA_ACTION_CHECK_GORON_LULLABY = 35, + OCARINA_ACTION_CHECK_NEW_WAVE = 36, + OCARINA_ACTION_CHECK_ELEGY = 37, + OCARINA_ACTION_CHECK_OATH = 38, + OCARINA_ACTION_CHECK_SARIAS = 39, + OCARINA_ACTION_CHECK_TIME = 40, + OCARINA_ACTION_CHECK_HEALING = 41, + OCARINA_ACTION_CHECK_EPONAS = 42, + OCARINA_ACTION_CHECK_SOARING = 43, + OCARINA_ACTION_CHECK_STORMS = 44, + OCARINA_ACTION_CHECK_SUNS = 45, + OCARINA_ACTION_CHECK_INVERTED_TIME = 46, + OCARINA_ACTION_CHECK_DOUBLE_TIME = 47, + OCARINA_ACTION_CHECK_GORON_LULLABY_INTRO = 48, + OCARINA_ACTION_CHECK_SCARECROW_SPAWN = 49, + OCARINA_ACTION_FREE_PLAY_DONE = 50, + OCARINA_ACTION_SCARECROW_LONG_RECORDING = 51, + OCARINA_ACTION_SCARECROW_LONG_DEMONSTRATION = 52, + OCARINA_ACTION_SCARECROW_SPAWN_RECORDING = 53, + OCARINA_ACTION_SCARECROW_SPAWN_DEMONSTRATION = 54, + OCARINA_ACTION_37 = 55, + OCARINA_ACTION_CHECK_NOTIME = 56, + OCARINA_ACTION_CHECK_NOTIME_DONE = 57, + OCARINA_ACTION_3A = 58, + OCARINA_ACTION_3B = 59, + OCARINA_ACTION_3C = 60, + OCARINA_ACTION_DEMONSTRATE_EVAN_PART1_FIRST_HALF = 61, + OCARINA_ACTION_DEMONSTRATE_EVAN_PART2_FIRST_HALF = 62, + OCARINA_ACTION_DEMONSTRATE_EVAN_PART1_SECOND_HALF = 63, + OCARINA_ACTION_DEMONSTRATE_EVAN_PART2_SECOND_HALF = 64, + OCARINA_ACTION_PROMPT_EVAN_PART1_SECOND_HALF = 65, + OCARINA_ACTION_PROMPT_EVAN_PART2_SECOND_HALF = 66, + OCARINA_ACTION_PROMPT_WIND_FISH_HUMAN = 67, + OCARINA_ACTION_PROMPT_WIND_FISH_GORON = 68, + OCARINA_ACTION_PROMPT_WIND_FISH_ZORA = 69, + OCARINA_ACTION_PROMPT_WIND_FISH_DEKU = 70, + OCARINA_ACTION_TIMED_PROMPT_SONATA = 71, + OCARINA_ACTION_TIMED_PROMPT_GORON_LULLABY = 72, + OCARINA_ACTION_TIMED_PROMPT_NEW_WAVE = 73, + OCARINA_ACTION_TIMED_PROMPT_ELEGY = 74, + OCARINA_ACTION_TIMED_PROMPT_OATH = 75, + OCARINA_ACTION_TIMED_PROMPT_SARIAS = 76, + OCARINA_ACTION_TIMED_PROMPT_TIME = 77, + OCARINA_ACTION_TIMED_PROMPT_HEALING = 78, + OCARINA_ACTION_TIMED_PROMPT_EPONAS = 79, + OCARINA_ACTION_TIMED_PROMPT_SOARING = 80, + OCARINA_ACTION_TIMED_PROMPT_STORMS = 81 + }; + enum class OcarinaSong : u16 { SonataOfAwakening = 0, GoronLullaby = 1, @@ -98,14 +228,31 @@ namespace game { EponaSong = 8, SongOfSoaring = 9, SongOfStorms = 10, + SunsSong = 11, InvertedSongOfTime = 12, SongOfDoubleTime = 13, - ScarecrowSong = 21, + GoronLullablyIntro = 14, + WindFishHuman = 15, + WindFishGoron = 16, + WindFishZora = 17, + WindFishDeku = 18, + EvansSongPart1 = 19, + EvansSongPart2 = 20, + ZeldasLullaby = 21, + ScarecrowSong = 22, + TerminaWallSong = 23, + SongMax = 24, InvalidDetecting = 0xfe, Invalid = 0xff, }; + struct OcarinaStaff { + u8 buttonIndex; + u8 song; + u8 pos; + }; + struct HudState { u32 field_0; u8 gap_4[86]; @@ -160,6 +307,59 @@ namespace game { }; static_assert(sizeof(HudState) == 0x280); + struct MessageContext { + void* notebook_stuff; + u8 gap_8024[536]; + OcarinaStaff* ocarinaStaff_maybe; + u16 field_8220; + u8 gap_8222[10]; + int field_822C; + u16 field_8230; + u16 field_8232; + u8 gap_8234[10]; + u8 hide_hud; + u8 field_823F; + u8 gap_8240[160]; + u32 field_82E0; + u8 gap_82E4[28]; + int field_8300; + u8 gap_8304[28]; + int field_8320; + u8 gap_8324[28]; + int state_timer; + u8 gap_8343[2]; + OcarinaMode ocarinaMode; + OcarinaSongActionId ocarinaSongActionId; + OcarinaSong lastPlayedSong; + u8 gap_834A[19]; + u8 some_ocarina_timer; + u16 field_8360; + u16 field_8362; + OcarinaSong ocarina_song2; + OcarinaState ocarina_state; + OcarinaState ocarina_state2; + OcarinaSong ocarina_song; + u16 field_836C; + u8 field_836E; + u8 field_836F; + int field_8370; + int field_8374; + int field_8378; + game::act::Actor* message_actor; + u16 field_8380; + u16 field_8382; + u8 gap_8384[4]; /* ocaEff Spawned here? */ + int item_cost; + int item_cost_two; + u8 gap_8390[61]; + u8 bombers_notebook_event_queue_count; + u8 gap_83CE[58]; + }; + static_assert(offsetof(MessageContext, field_8232) == 0x232); + static_assert(offsetof(MessageContext, ocarinaStaff_maybe) == 0x21c); + static_assert(offsetof(MessageContext, gap_8324) == 0x324); + static_assert(sizeof(MessageContext) == 0x408); + // Likely incomplete. struct GlobalContext : State { bool IsPaused() const { return pause_flags.IsOneSet(PauseFlag::PauseCalc, PauseFlag::PauseDraw); } @@ -259,54 +459,11 @@ namespace game { u8 gap_3DFE[16898]; u32 field_8000; u8 gap_8004[28]; - void* notebook_stuff; - u8 gap_8024[536]; - void* ocarinaData; - u16 field_8220; - u8 gap_8222[10]; - int field_822C; - u8 gap_8230[2]; - u16 field_8232; - u8 gap_8234[10]; - u8 hide_hud; - u8 field_823F; - u8 gap_8240[160]; - u32 field_8300; - u8 gap_8304[28]; - int field_8320; - u8 gap_8324[59]; - u8 some_ocarina_timer; - u16 field_8360; - u16 field_8362; - OcarinaSong ocarina_song2; - OcarinaState ocarina_state; - OcarinaState ocarina_state2; - OcarinaSong ocarina_song; - u16 field_836C; - char field_836E; - char field_836F; - int field_8370; - int field_8374; - int field_8378; - act::Actor* messageActor; - u16 field_8380; - u16 field_8382; - u8 gap_8384[4]; // ocaeffSpawned in here. - int item_cost; - int another_item_cost_maybe; - u8 gap_8390[62]; - u16 field_83CE; // frame counter for notebook? - u8 field_83CD; - u8 gap_83D0[10]; - u32 field_83DE; // Checks during song - u16 field_83E0; - u16 field_83E2; // Stored message ID for after notebook collection. Mainly used for fishing - // pass/PoH/rupee text. - u8 gap_83E0[68]; + MessageContext msg_context; HudState hud_state; u8 gap_86A8[4]; u16 field_86AC; - __attribute__((aligned(4))) u8 gap_86B0[272]; + u8 gap_86B0[272]; u32 field_87C0; u8 gap_87C4[59]; u8 field_87FF; @@ -460,15 +617,9 @@ namespace game { static_assert(offsetof(GlobalContext, pause_flags) == 0xAAC); static_assert(offsetof(GlobalContext, elegy_statues) == 0x2394); static_assert(offsetof(GlobalContext, field_C000) == 0xc000); - static_assert(offsetof(GlobalContext, ocarina_state) == 0x8366); - static_assert(offsetof(GlobalContext, ocarina_song) == 0x836A); - static_assert(offsetof(GlobalContext, hide_hud) == 0x825E); - static_assert(offsetof(GlobalContext, field_836E) == 0x836E); - static_assert(offsetof(GlobalContext, gap_8390) == 0x8390); static_assert(offsetof(GlobalContext, field_C4C8) == 0xC4C8); static_assert(offsetof(GlobalContext, gap_AC6C) == 0xAC6C); - static_assert(offsetof(GlobalContext, field_83CE) == 0x83CE); - static_assert(offsetof(GlobalContext, gap_8384) == 0x8384); + static_assert(offsetof(GlobalContext, msg_context) == 0x8020); static_assert(offsetof(GlobalContext, gap_404) == 0x0404); static_assert(offsetof(GlobalContext, object_context) == 0x9438); static_assert(sizeof(GlobalContext) == 0x11030); diff --git a/code/include/game/items.h b/code/include/game/items.h index d74a5f6..6c1fc4d 100644 --- a/code/include/game/items.h +++ b/code/include/game/items.h @@ -148,7 +148,7 @@ namespace game { InvertedSongOfTime = 0x71, SongOfDoubleTime = 0x72, - X73 = 0x73, + GoronLullabyIntro = 0x73, BossKey = 0x74, Compass = 0x75, diff --git a/code/include/rnd/input.h b/code/include/rnd/input.h index efe79fa..18276b8 100644 --- a/code/include/rnd/input.h +++ b/code/include/rnd/input.h @@ -10,6 +10,7 @@ namespace rnd { btn_t up; btn_t pressed; btn_t old; + cp_t cp_curr; } InputContext; void Input_Update(void); diff --git a/code/include/rnd/item_override.h b/code/include/rnd/item_override.h index eb76d84..67db228 100644 --- a/code/include/rnd/item_override.h +++ b/code/include/rnd/item_override.h @@ -104,7 +104,7 @@ namespace rnd { /* 0x4D */ // GI_ERROR_NOTHING_4D, // ***ERROR TEXT Get Item Nothing in hand - Green Rupee with // Ocarina in Inventory /* 0x4E */ // GI_ERROR_NOTHING_4E, // ***ERROR TEXT Get Item Nothing in hand - Green Rupee with - // Ocarina in Inventory + // Ocarina in Inventory - New Wave Bossa Nova /* 0x4F */ // GI_ERROR_NOTHING_4F, // ***ERROR TEXT Get Item Nothing in hand - Green Rupee with // Ocarina in Inventory /* 0x50 */ GI_BOMBERS_NOTEBOOK = 0x50, @@ -112,7 +112,7 @@ namespace rnd { // subsequently yellow rupee. No rupee increment. /* 0x52 */ GI_GOLD_SKULLTULA_SPIRIT = 0x52, // Pickup model is whacky since we usually don't have one. /* 0x53 */ // GI_ERROR_NOTHING_53, // ***ERROR TEXT Get Item Nothing in hand - Green Rupee with - // Ocarina in Inventory + // Ocarina in Inventory Song of Time /* 0x54 */ // GI_ERROR_NOTHING_54, // ***ERROR TEXT Get Item Nothing in hand - Green Rupee with // Ocarina in Inventory /* 0x55 */ GI_ODOLWAS_REMAINS = 0x55, // Also softlocks! @@ -146,7 +146,7 @@ namespace rnd { /* 0x70 */ GI_BOTTLE_MYSTERY_MILK, // Activates Timer /* 0x71 */ GI_BOTTLE_MOLDY_MILK, // Mystery milk text followed by tatl. /* 0x72 */ // GI_ERROR_NOTHING_72, // ***ERROR TEXT Get Item Nothing in hand - Green Rupee with - // Ocarina in Inventory + // Ocarina in Inventory. Song of Soaring. /* 0x73 */ // GI_ERROR_NOTHING_73, // ***ERROR TEXT Get Item Nothing in hand - Green Rupee with // Ocarina in Inventory /* 0x74 */ // GI_ERROR_NOTHING_74, // ***ERROR TEXT Get Item Nothing in hand - Green Rupee with @@ -448,9 +448,9 @@ namespace rnd { void ItemOverride_GetItemTextAndItemID(game::act::Player*); void ItemOverride_GetItem(game::GlobalContext*, game::act::Actor*, game::act::Player*, s16); void ItemOverride_GetFairyRewardItem(game::GlobalContext*, game::act::GreatFairy*, s16); - void ItemOverride_GetSoHItem(game::GlobalContext*, game::act::Actor*, s16); + void ItemOverride_GetSoHOrSongItem(game::GlobalContext*, game::act::Actor*, s16); int ItemOverride_CheckInventoryItemOverride(game::ItemId); - void ItemOverride_SwapSoHGetItemText(game::GlobalContext*, u16, game::act::Actor*); + void ItemOverride_SwapSoHAndSongGetItemText(game::GlobalContext*, u16, game::act::Actor*); bool ItemOverride_CheckTingleMaps(u16, game::GlobalContext*); u32 ItemOverride_GetGaboraExtData(); u32 ItemOverride_GetOshExtData(); @@ -459,6 +459,8 @@ namespace rnd { u8 ItemOverride_OverrideSkullToken(game::act::Actor*); u8 ItemOverride_CheckBossStatus(); u8 ItemOverride_ReceivedOcarinaFromSkt(); + u8 ItemOverride_ReceivedSongOverride(s16); + u8 ItemOverride_CheckIfSongOfTimeAwarded(u8); } extern "C" u32 rActiveItemGraphicId; extern "C" ItemOverride rItemOverrides[640]; diff --git a/code/include/rnd/savefile.h b/code/include/rnd/savefile.h index 789054c..c15aab4 100644 --- a/code/include/rnd/savefile.h +++ b/code/include/rnd/savefile.h @@ -110,6 +110,23 @@ namespace rnd { BitField<59, 5, u64> unused; }; GivenItemRegister givenItemChecks; + union GivenSongRegister { + u16 raw; + + BitField<0, 1, u16> sonataGiven; + BitField<1, 1, u16> goronLullabyGiven; + BitField<2, 1, u16> goronLullabyIntroGiven; + BitField<3, 1, u16> newWaveBossaNovaGiven; + BitField<4, 1, u16> elegyOfEmptinessGiven; + BitField<5, 1, u16> oathToOrderGiven; + BitField<6, 1, u16> songOfTimeGiven; + BitField<7, 1, u16> songOfHealingGiven; + BitField<8, 1, u16> eponasSongGiven; + BitField<9, 1, u16> songOfSoaringGiven; + BitField<10, 1, u16> songOfStormsGiven; + BitField<11, 5, u16> unused; + }; + GivenSongRegister givenSongChecks; union FairyCollectRegister { u8 raw; diff --git a/code/mm.ld b/code/mm.ld index 5a2cc22..850d460 100644 --- a/code/mm.ld +++ b/code/mm.ld @@ -53,12 +53,16 @@ SECTIONS{ *(.patch_PostActorCalc) } + .patch_ResetCycleFlagOnMoonCrash 0x1851C0 : { + *(.patch_ResetCycleFlagOnMoonCrash) + } + .patch_RemoveCouplesMaskMessage 0x1867C4 : { *(.patch_RemoveCouplesMaskMessage) } - .patch_RemoveSOHCutesceneAfterMessage 0x186810 : { - *(.patch_RemoveSOHCutesceneAfterMessage) + .patch_OverrideSoHAndSongText 0x186810 : { + *(.patch_OverrideSoHAndSongText) } .patch_OverrideBombersNotebook 0x186ACC : { @@ -165,6 +169,10 @@ SECTIONS{ *(.patch_RemoveMysteryMilkSoSCheck) } + .patch_CheckExtForSongOfTime 0x1D7FEC : { + *(.patch_CheckExtForSongOfTime) + } + .patch_DoNotForceMaskChange 0x1DB314 : { *(.patch_DoNotForceMaskChange) } @@ -317,6 +325,10 @@ SECTIONS{ *(.patch_OverrideItemID) } + .patch_SongOfTimeCheckExtData 0x2311A4 : { + *(.patch_SongOfTimeCheckExtData) + } + .patch_ForceSwordUpgradeOnHuman 0x233D88 : { *(.patch_ForceSwordUpgradeOnHuman) } @@ -349,6 +361,18 @@ SECTIONS{ *(.patch_EnteringLocation) } + .patch_LullabyIntroCheckEnJg 0x244378 : { + *(.patch_LullabyIntroCheckEnJg) + } + + .patch_LullabyCheckEnJg 0x244380 : { + *(.patch_LullabyCheckEnJg) + } + + .patch_EnOsnCheckSoHExtData 0x268030 : { + *(.patch_EnOsnCheckSoHExtData) + } + .patch_TwinmoldConsistentDamage 0x28E544 : { *(.patch_TwinmoldConsistentDamage) } @@ -439,6 +463,18 @@ SECTIONS{ *(.patch_RemoveGoronMaskCheckDarmani) } + .patch_EnMa4ExtDataCheckOne 0x2E3784 : { + *(.patch_EnMa4ExtDataCheckOne) + } + + .patch_EnMa4ExtDataCheckThree 0x2E3CD0 : { + *(.patch_EnMa4ExtDataCheckThree) + } + + .patch_EnMa4ExtDataCheckTwo 0x2E3D94 : { + *(.patch_EnMa4ExtDataCheckTwo) + } + /* .patch_RemoveSkulltulaSpawnIfCollectedItem 0x2E8384 : { *(.patch_RemoveSkulltulaSpawnIfCollectedItem) } */ @@ -471,10 +507,18 @@ SECTIONS{ *(.patch_AdjustMapAndCompassChests) } + .patch_EnMnkSongOverride 0x0325D58 : { + *(.patch_EnMnkSongOverride) + } + .patch_RemoveSongCheckKaepora 0x326ED0 : { *(.patch_RemoveSongCheckKaepora) } + .patch_RemoveSoSCheckKaepora 0x326EF8 : { + *(.patch_RemoveSoSCheckKaepora) + } + .patch_RemoveZoraMaskCheckMikau 0x32BBB8 : { *(.patch_RemoveZoraMaskCheckMikau) } @@ -631,6 +675,10 @@ SECTIONS{ *(.patch_OverrideItem00Draw) } + .patch_OverrideSoSGiveItem 0x43FB64 : { + *(.patch_OverrideSoSGiveItem) + } + .patch_FierceDeityArcheryFix 0x4427E8 : { *(.patch_FierceDeityArcheryFix) } @@ -700,6 +748,17 @@ SECTIONS{ *(.patch_SkulltulaOverrideTwo) } + .patch_EnGkCheckLullabyRewardGivenOne 0x546294 : { + *(.patch_EnGkCheckLullabyRewardGivenOne) + } + + .patch_EnGkCheckLullabyRewardGivenTwo 0x546374 : { + *(.patch_EnGkCheckLullabyRewardGivenTwo) + } + .patch_EnMkNWBNOverride 0x58722C : { + *(.patch_EnMkNWBNOverride) + } + .patch_UpdateOcarinaVisibility 0x59AA2C : { *(.patch_UpdateOcarinaVisibility) } @@ -777,6 +836,10 @@ SECTIONS{ *(.patch_HandleOcarinaHooks) } + .patch_OverrideGetSongItem 0x60597C : { + *(.patch_OverrideGetSongItem) + } + .patch_FDOpenDungeonDoors 0x68D9C0 : { *(.patch_FDOpenDungeonDoors) } diff --git a/code/source/asm/hms_hooks.s b/code/source/asm/hms_hooks.s index 13abed5..47a8c15 100644 --- a/code/source/asm/hms_hooks.s +++ b/code/source/asm/hms_hooks.s @@ -11,7 +11,7 @@ hook_OverrideHMSDekuMask: cpy r0,r5 cpy r1,r4 mov r2,#0x78 - bl ItemOverride_GetSoHItem + bl ItemOverride_GetSoHOrSongItem ldr r5,.rActiveItemRow_addr ldr r5,[r5] cmp r5,#0x0 @@ -35,7 +35,7 @@ hook_OverrideHMSBombers: cpy r0,r6 mov r1,#0x0 mov r2,#0x50 - bl ItemOverride_GetSoHItem + bl ItemOverride_GetSoHOrSongItem ldr r5,.rActiveItemRow_addr ldr r5,[r5] cmp r5,#0x0 diff --git a/code/source/asm/item_override_hooks.s b/code/source/asm/item_override_hooks.s index 4eba3bf..c4918f0 100644 --- a/code/source/asm/item_override_hooks.s +++ b/code/source/asm/item_override_hooks.s @@ -192,7 +192,7 @@ hook_GoronMaskGiveItem: cpy r0,r5 cpy r1,r4 mov r2,#0x79 - bl ItemOverride_GetSoHItem + bl ItemOverride_GetSoHOrSongItem ldr r5,.rActiveItemRow_addr ldr r5,[r5] cmp r5,#0x0 @@ -216,7 +216,7 @@ hook_ZoraMaskGiveItem: cpy r0,r5 cpy r1,r4 mov r2,#0x7A - bl ItemOverride_GetSoHItem + bl ItemOverride_GetSoHOrSongItem ldr r5,.rActiveItemRow_addr ldr r5,[r5] cmp r5,#0x0 @@ -240,7 +240,7 @@ hook_GibdoMaskGiveItem: cpy r0,r5 cpy r1,r4 mov r2,#0x87 - bl ItemOverride_GetSoHItem + bl ItemOverride_GetSoHOrSongItem ldr r5,.rActiveItemRow_addr ldr r5,[r5] cmp r5,#0x0 @@ -258,13 +258,40 @@ noOverrideGibdoItemID: bl 0x233BEC b 0x41DC4C +.global hook_OverrideSoSGiveItem +hook_OverrideSoSGiveItem: + cpy r0,r5 + push {r0-r12, lr} + cpy r2,r1 + mov r1,#0xFF + bl ItemOverride_GetSoHOrSongItem + ldr r5,.rActiveItemRow_addr + ldr r5,[r5] + cmp r5,#0x0 + pop {r0-r12, lr} + beq noOverrideSoSGiveItem + push {r0-r12, lr} + ldr r0, [r5,#0xDC] + bl ItemOverride_GetItemTextAndItemID + pop {r0-r12, lr} + cpy r0,r5 + b 0x43FB6C +noOverrideSoSGiveItem: + push {r0-r12, lr} + cpy r0,r1 + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x0 + pop {r0-r12, lr} + beq 0x233BEC + b 0x43FB6C + .global hook_CouplesMaskGiveItem hook_CouplesMaskGiveItem: push {r0-r12, lr} cpy r0,r5 cpy r1,r4 mov r2,#0x85 - bl ItemOverride_GetSoHItem + bl ItemOverride_GetSoHOrSongItem ldr r5,.rActiveItemRow_addr ldr r5,[r5] cmp r5,#0x0 @@ -297,10 +324,10 @@ normalText: mov r1,#0xA2 b 0x1867C8 -.global hook_ChangeSOHToCustomText -hook_ChangeSOHToCustomText: +.global hook_ChangeSoHAndSongToCustomText +hook_ChangeSoHAndSongToCustomText: push {r0-r2, lr} - bl ItemOverride_SwapSoHGetItemText + bl ItemOverride_SwapSoHAndSongGetItemText pop {r0-r2, lr} b 0x186814 @@ -328,4 +355,25 @@ hook_SkulltulaOverrideTwo: bl 0x233BEC b 0x52A048 skulltulaOverriddenTwo: - b 0x52A06C \ No newline at end of file + b 0x52A06C + + +.global hook_OverrideGetSongItem +hook_OverrideGetSongItem: + push {r0-r12, lr} + cpy r2,r1 + mov r1,#0xFF + bl ItemOverride_GetSoHOrSongItem + ldr r5,.rActiveItemRow_addr + ldr r5,[r5] + cmp r5,#0x0 + pop {r0-r12, lr} + beq noOverrideSongItemID + push {r0-r12, lr} + ldr r0, [r0,#0xDC] + bl ItemOverride_GetItemTextAndItemID + pop {r0-r12, lr} + b 0x605980 +noOverrideSongItemID: + bl 0x233BEC + b 0x605980 \ No newline at end of file diff --git a/code/source/asm/item_override_patches.s b/code/source/asm/item_override_patches.s index 71f75c0..3175372 100644 --- a/code/source/asm/item_override_patches.s +++ b/code/source/asm/item_override_patches.s @@ -125,6 +125,11 @@ patch_ZoraMaskGiveItem: patch_GibdoMaskGiveItem: b hook_GibdoMaskGiveItem +.section .patch_OverrideSoSGiveItem +.global patch_OverrideSoSGiveItem +patch_OverrideSoSGiveItem: + b hook_OverrideSoSGiveItem + .section .patch_CouplesMaskGiveItem .global patch_CouplesMaskGiveItem patch_CouplesMaskGiveItem: @@ -138,10 +143,10 @@ patch_RemoveCouplesMaskMessage: @ This should remove the overwriting message for when the @ user receives the Zora Mask. -.section .patch_RemoveSOHCutesceneAfterMessage -.global patch_RemoveSOHCutesceneAfterMessage -patch_RemoveSOHCutesceneAfterMessage: - b hook_ChangeSOHToCustomText +.section .patch_OverrideSoHAndSongText +.global patch_OverrideSoHAndSongText +patch_OverrideSoHAndSongText: + b hook_ChangeSoHAndSongToCustomText .section .patch_SkulltulaOverrideOne .global patch_SkulltulaOverrideOne @@ -151,4 +156,10 @@ patch_SkulltulaOverrideOne: .section .patch_SkulltulaOverrideTwo .global patch_SkulltulaOverrideTwo patch_SkulltulaOverrideTwo: - bl hook_SkulltulaOverrideTwo \ No newline at end of file + bl hook_SkulltulaOverrideTwo + + +.section .patch_OverrideGetSongItem +.global patch_OverrideGetSongItem +patch_OverrideGetSongItem: + b hook_OverrideGetSongItem \ No newline at end of file diff --git a/code/source/asm/ocarina_hooks.s b/code/source/asm/ocarina_hooks.s index 38596d2..ed877f1 100644 --- a/code/source/asm/ocarina_hooks.s +++ b/code/source/asm/ocarina_hooks.s @@ -19,7 +19,7 @@ hook_FixRemovingOcarinaFromInventory: add r0,r0,r1 @ original instruction b 0x201068 ocarinaAlwaysInInventory: - mov r0, #0x0 @ Force the ocarina to always be in inventory + mov r0, #0x00 @ Force the ocarina to always be in inventory b 0x20106C .global hook_DmSktOcarinaAnimationPatchOne diff --git a/code/source/asm/patches.s b/code/source/asm/patches.s index 9389990..c745e64 100644 --- a/code/source/asm/patches.s +++ b/code/source/asm/patches.s @@ -19,6 +19,12 @@ patch_FixSurroundSound: nop nop +@ Change +.section .patch_ResetCycleFlagOnMoonCrash +.global patch_ResetCycleFlagOnMoonCrash +patch_ResetCycleFlagOnMoonCrash: + bl 0x1C92A8 + @ nop gctx->field_22f8 from being potentially nulled. Disables stray fairy respawn and doors locking. .section .patch_DoNotResetPermFlags .global patch_DoNotResetPermFlags diff --git a/code/source/asm/songsanity_hooks.s b/code/source/asm/songsanity_hooks.s new file mode 100644 index 0000000..1a8fd69 --- /dev/null +++ b/code/source/asm/songsanity_hooks.s @@ -0,0 +1,143 @@ +.arm +.text + +.global rActiveItemRow +.rActiveItemRow_addr: + .word rActiveItemRow + +.global hook_CheckExtForSongOfTime +hook_CheckExtForSongOfTime: + push {r0-r12, lr} + mov r0,#0x67 + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x0 + pop {r0-r12,lr} + bx lr + +.global hook_SongOfTimeCheckExtData +hook_SongOfTimeCheckExtData: + push {r0-r12, lr} + bl ItemOverride_CheckIfSongOfTimeAwarded + cmp r0,#0x4C + pop {r0-r12,lr} + bx lr + +.global hook_LullabyIntroCheckEnJg +hook_LullabyIntroCheckEnJg: + push {r0-r12, lr} + mov r0, #0x73 + bl ItemOverride_ReceivedSongOverride + cmp r0, #0x0 + pop {r0-r12, lr} + bx lr + +.global hook_LullabyCheckEnJg +hook_LullabyCheckEnJg: + push {r0-r12, lr} + mov r0, #0x62 + bl ItemOverride_ReceivedSongOverride + cmp r0, #0x0 + pop {r0-r12, lr} + bx lr + + +.global hook_EnOsnCheckSoHExtData +hook_EnOsnCheckSoHExtData: + push {r0-r12, lr} + mov r0,#0x69 + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x0 + pop {r0-r12,lr} + bx lr + +.global hook_EnMa4ExtDataCheckOne +hook_EnMa4ExtDataCheckOne: + push {r0-r12, lr} + mov r0,#0x69 + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x1 @bne check. + pop {r0-r12,lr} + bx lr + +.global hook_EnMa4ExtDataCheckThree +hook_EnMa4ExtDataCheckThree: + push {r0-r12, lr} + mov r0,#0x69 + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x0 @bneq check. + pop {r0-r12,lr} + bx lr + +.global hook_EnMa4ExtDataCheckTwo +hook_EnMa4ExtDataCheckTwo: + push {r0-r12, lr} + mov r0,#0x69 + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x1 @bne check. + pop {r0-r12,lr} + bx lr + +.global hook_EnMnkSongOverride +hook_EnMnkSongOverride: + push {r0-r12,lr} + mov r0,#0x61 + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x0 + pop {r0-r12, lr} + beq noOverrideSonataItemID + b 0x325D5C @Item was already given, so basically noop this call. +noOverrideSonataItemID: + cpy r0,r5 + bl 0x233BEC + b 0x325D5C + +.global hook_RemoveSoSCheckKaepora +hook_RemoveSoSCheckKaepora: + push {r0-r12, lr} + mov r0,#0x6A + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x0 + pop {r0-r12,lr} + bx lr + +.global hook_EnGkCheckLullabyRewardGiven +hook_EnGkCheckLullabyRewardGiven: + push {r0-r12,lr} + mov r0, #0x62 + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x0 + pop {r0-r12,lr} + bx lr + +.global hook_EnGkCheckLullabyRewardGivenTwo +hook_EnGkCheckLullabyRewardGivenTwo: + push {r0-r12,lr} + mov r0, #0x62 + bl ItemOverride_ReceivedSongOverride + cmp r0,#0x1 @We want to check if given, instead of not given at this instruction. + pop {r0-r12,lr} + bx lr + +.global hook_EnMkNWBNOverride +hook_EnMkNWBNOverride: + push {r0-r12,lr} + cpy r2,r1 + mov r1,#0xFF + bl ItemOverride_GetSoHOrSongItem + ldr r5,.rActiveItemRow_addr + ldr r5,[r5] + cmp r5,#0x0 + pop {r0-r12, lr} + beq noOverrideNWBNItemID + push {r0-r12, lr} + ldr r0, [r8,#0xDC] @Load player actor. + bl ItemOverride_GetItemTextAndItemID + pop {r0-r12, lr} + cpy r0,r8 + b 0x587230 +noOverrideNWBNItemID: + cpy r0,r8 + nop + nop + bl 0x233BEC + b 0x587230 \ No newline at end of file diff --git a/code/source/asm/songsanity_patches.s b/code/source/asm/songsanity_patches.s new file mode 100644 index 0000000..b6947aa --- /dev/null +++ b/code/source/asm/songsanity_patches.s @@ -0,0 +1,67 @@ +.arm + +.section .patch_CheckExtForSongOfTime +.global patch_CheckExtForSongOfTime +patch_CheckExtForSongOfTime: + bl hook_CheckExtForSongOfTime + +.section .patch_SongOfTimeCheckExtData +.global patch_SongOfTimeCheckExtData +patch_SongOfTimeCheckExtData: + bl hook_SongOfTimeCheckExtData + +.section .patch_LullabyIntroCheckEnJg +.global patch_LullabyIntroCheckEnJg +patch_LullabyIntroCheckEnJg: + bl hook_LullabyIntroCheckEnJg + +.section .patch_LullabyCheckEnJg +.global patch_LullabyCheckEnJg +patch_LullabyCheckEnJg: + bl hook_LullabyCheckEnJg + +.section .patch_EnOsnCheckSoHExtData +.global patch_EnOsnCheckSoHExtData +patch_EnOsnCheckSoHExtData: + bl hook_EnOsnCheckSoHExtData + +.section .patch_EnMa4ExtDataCheckOne +.global patch_EnMa4ExtDataCheckOne +patch_EnMa4ExtDataCheckOne: + bl hook_EnMa4ExtDataCheckOne + +.section .patch_EnMa4ExtDataCheckThree +.global patch_EnMa4ExtDataCheckThree +patch_EnMa4ExtDataCheckThree: + bl hook_EnMa4ExtDataCheckThree + +.section .patch_EnMa4ExtDataCheckTwo +.global patch_EnMa4ExtDataCheckTwo +patch_EnMa4ExtDataCheckTwo: + bl hook_EnMa4ExtDataCheckTwo + +.section .patch_EnMnkSongOverride +.global patch_EnMnkSongOverride +patch_EnMnkSongOverride: + b hook_EnMnkSongOverride + +.section .patch_RemoveSoSCheckKaepora +.global patch_RemoveSoSCheckKaepora +patch_RemoveSoSCheckKaepora: + bl hook_RemoveSoSCheckKaepora + +.section .patch_EnGkCheckLullabyRewardGivenOne +.global patch_EnGkCheckLullabyRewardGivenOne +patch_EnGkCheckLullabyRewardGivenOne: + bleq hook_EnGkCheckLullabyRewardGiven + +.section .patch_EnGkCheckLullabyRewardGivenTwo +.global patch_EnGkCheckLullabyRewardGivenTwo +patch_EnGkCheckLullabyRewardGivenTwo: + bleq hook_EnGkCheckLullabyRewardGivenTwo + + +.section .patch_EnMkNWBNOverride +.global patch_EnMkNWBNOverride +patch_EnMkNWBNOverride: + b hook_EnMkNWBNOverride \ No newline at end of file diff --git a/code/source/game/player.cpp b/code/source/game/player.cpp index da68aaf..74ded52 100644 --- a/code/source/game/player.cpp +++ b/code/source/game/player.cpp @@ -92,7 +92,7 @@ namespace game::act { !statue || (statue->pos.pos.x == player->pos.pos.x && statue->pos.pos.y == player->pos.pos.y && statue->pos.pos.z == player->pos.pos.z); if (player->timer > 135 || statue_ready) { - gctx->ocarina_state = OcarinaState::StoppedPlaying; + gctx->msg_context.ocarina_state = OcarinaState::StoppedPlaying; PlayerChangeStateToStill(player, gctx); } else if (statue && !statue_ready) { // Speed up the statue fadeout. (0x18 + 8 = 0x20 per game tick) diff --git a/code/source/rnd/gfx.cpp b/code/source/rnd/gfx.cpp index 86d8c63..b3b2155 100644 --- a/code/source/rnd/gfx.cpp +++ b/code/source/rnd/gfx.cpp @@ -15,6 +15,7 @@ namespace rnd { static u64 lastTick = 0; static u64 ticksElapsed = 0; static bool isAsleep = false; + static s64 playingOnCitra = 0; DungeonInfo rDungeonInfoData[10]; u32 pressed; @@ -624,9 +625,8 @@ namespace rnd { static void Gfx_ShowMenu(void) { pressed = 0; Draw_ClearFramebuffer(); - if (gSettingsContext.playOption == PLAY_ON_CONSOLE) { + if (!playingOnCitra) Draw_FlushFramebuffer(); - } do { // End the loop if the system has gone to sleep, so the game can properly respond if (isAsleep) { @@ -717,9 +717,8 @@ namespace rnd { showingLegend = false; Draw_ClearBackbuffer(); Draw_CopyBackBuffer(); - if (gSettingsContext.playOption == PLAY_ON_CONSOLE) { + if (!playingOnCitra) Draw_FlushFramebuffer(); - } break; } else if (pressed & BUTTON_R1) { showingLegend = false; @@ -753,15 +752,15 @@ namespace rnd { Gfx_DrawButtonPrompts(); Gfx_DrawHeader(); Draw_CopyBackBuffer(); - if (gSettingsContext.playOption == PLAY_ON_CONSOLE) { + if (!playingOnCitra) Draw_FlushFramebuffer(); - } pressed = Input_WaitWithTimeout(1000, closingButton); } while (true); } void Gfx_Init(void) { + svcGetSystemInfo(&playingOnCitra, 0x20000, 0); Draw_SetupFramebuffer(); Draw_ClearBackbuffer(); diff --git a/code/source/rnd/input.cpp b/code/source/rnd/input.cpp index c905954..330a050 100644 --- a/code/source/rnd/input.cpp +++ b/code/source/rnd/input.cpp @@ -1,5 +1,6 @@ #include "rnd/input.h" #include "common/debug.h" +#include "game/pad.h" #include "hid.h" #include "utils.h" #include "z3d/z3DVec.h" @@ -21,6 +22,7 @@ namespace rnd { rInputCtx.pressed.val = (rInputCtx.cur.val) & (~rInputCtx.old.val); rInputCtx.up.val = (~rInputCtx.cur.val) & (rInputCtx.old.val); rInputCtx.old.val = rInputCtx.cur.val; + rInputCtx.cp_curr = real_hid->pad.pads[real_hid->pad.index].cp; } u32 buttonCheck(u32 key) { diff --git a/code/source/rnd/item_effect.cpp b/code/source/rnd/item_effect.cpp index e4617eb..3beaede 100644 --- a/code/source/rnd/item_effect.cpp +++ b/code/source/rnd/item_effect.cpp @@ -149,7 +149,6 @@ namespace rnd { comData->save.inventory.collect_register.sonata_of_awakening = 1; break; case 2: - comData->save.inventory.collect_register.lullaby_intro = 1; comData->save.inventory.collect_register.goron_lullaby = 1; break; case 3: diff --git a/code/source/rnd/item_override.cpp b/code/source/rnd/item_override.cpp index 4dfea4f..2e4e5c6 100644 --- a/code/source/rnd/item_override.cpp +++ b/code/source/rnd/item_override.cpp @@ -43,6 +43,8 @@ namespace rnd { 0x2D, 0x33, 0x37, 0x3B, 0x3F, 0x42, 0x46, 0x4A, 0x4F, 0x53, 0x57, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x73, 0x77, 0x7B}; + static bool givenItemOverride = false; + void ItemOverride_Init(void) { #ifdef ENABLE_DEBUG // Manual overide example code @@ -633,6 +635,46 @@ namespace rnd { (itemToBeGiven->itemId > 0x49 && itemToBeGiven->itemId < 0x81) || override.value.getItemId == 0x5A); } + GetItemID ItemOverride_MapSongsToGID(game::ItemId incomingItemId) { + switch (incomingItemId) { + case game::ItemId::SonataOfAwakening: + gExtSaveData.givenSongChecks.sonataGiven = 1; + return GetItemID(0x4B); + case game::ItemId::GoronLullaby: + gExtSaveData.givenSongChecks.goronLullabyGiven = 2; + return GetItemID(0x4D); + case game::ItemId::NewWaveBossaNova: + gExtSaveData.givenSongChecks.newWaveBossaNovaGiven = 1; + return GetItemID(0x4E); + case game::ItemId::ElegyOfEmptiness: + gExtSaveData.givenSongChecks.elegyOfEmptinessGiven = 1; + return GetItemID(0x4F); + case game::ItemId::OathToOrder: + gExtSaveData.givenSongChecks.oathToOrderGiven = 1; + return GetItemID(0x51); + case game::ItemId::SongOfTime: + gExtSaveData.givenSongChecks.songOfTimeGiven = 1; + return GetItemID(0x53); + case game::ItemId::SongOfHealing: + gExtSaveData.givenSongChecks.songOfHealingGiven = 1; + return GetItemID(0x54); + case game::ItemId::EponaSong: + gExtSaveData.givenSongChecks.eponasSongGiven = 1; + return GetItemID(0x6C); + case game::ItemId::SongOfSoaring: + gExtSaveData.givenSongChecks.songOfSoaringGiven = 1; + return GetItemID(0x72); + case game::ItemId::SongOfStorms: + gExtSaveData.givenSongChecks.songOfStormsGiven = 1; + return GetItemID(0x73); + case game::ItemId::GoronLullabyIntro: + gExtSaveData.givenSongChecks.goronLullabyGiven = 1; + return GetItemID(0x74); + default: + return GetItemID::GI_NONE; + } + } + extern "C" { bool ItemOverride_CheckAromaGivenItem() { if (gExtSaveData.givenItemChecks.enAlGivenItem > 0) @@ -829,11 +871,20 @@ namespace rnd { } if (incomingGetItemId != 0x44 && incomingGetItemId != 0x6D && incomingGetItemId != 0x52) player->get_item_id = incomingNegative ? -baseItemId : baseItemId; - // Weird edge case with the way text and masks are handled with Couples' Mask. - // Set the text and apply it later in a different patch. - if (incomingGetItemId == 0x85) { + // Edge case with Song of healing items. Override their show text in their own functions + // to ensure that we have the same 'feel' as the base game. + // This also ensures that if there is no override the default text still works. +#if defined ENABLE_DEBUG || defined DEBUG_PRINT + rnd::util::Print("%s: %#04x\n", __func__, incomingGetItemId); +#endif + if (incomingGetItemId == 0x4B || incomingGetItemId == 0x4D || incomingGetItemId == 0x4E || + incomingGetItemId == 0x51 || incomingGetItemId == 0x53 || incomingGetItemId == 0x6C || + (incomingGetItemId <= 0x72 || incomingGetItemId >= 0x74) || + (incomingGetItemId >= 0x78 && incomingGetItemId <= 0x7A) || incomingGetItemId == 0x85 || + incomingGetItemId == 0x87) { rStoredTextId = rActiveItemRow->textId; } + givenItemOverride = true; return; } @@ -870,10 +921,13 @@ namespace rnd { } } - void ItemOverride_GetSoHItem(game::GlobalContext* gctx, game::act::Actor* fromActor, s16 incomingItemId) { + void ItemOverride_GetSoHOrSongItem(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 & Kafei). +// 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 & Kafei). +#if defined ENABLE_DEBUG || defined DEBUG_PRINT + rnd::util::Print("%s: Link's getitemid %#04x incoming GID is %#04x\n", __func__, link->get_item_id, incomingItemId); +#endif if (link->get_item_id != 0x00) return; if (incomingItemId == 0x7A) { @@ -885,12 +939,16 @@ namespace rnd { } else if (incomingItemId == 0x78) { gExtSaveData.givenItemChecks.enOsnGivenMask = 1; } else if (incomingItemId == 0x50) { - fromActor = gctx->GetPlayerActor(); + fromActor = link; } else if (incomingItemId == 0x85) { gExtSaveData.givenItemChecks.kafeiGivenItem = 1; + } else if ((incomingItemId >= 0x61 || incomingItemId <= 0x6C) || incomingItemId == 0x73) { + // Additional logic to map songs to getItemIds. + incomingItemId = (s16)ItemOverride_MapSongsToGID(game::ItemId(incomingItemId)); + fromActor = link; } - ItemOverride_GetItem(gctx, fromActor, gctx->GetPlayerActor(), incomingItemId); + ItemOverride_GetItem(gctx, fromActor, link, incomingItemId); return; } @@ -998,15 +1056,22 @@ namespace rnd { } // clang-format on - void ItemOverride_SwapSoHGetItemText(game::GlobalContext* gctx, u16 textId, game::act::Actor* fromActor) { - // Check which text ID is coming in. If it's any mask from Song of Healing, replace it with active item text. - if (textId == 0x79 || textId == 0x7a || textId == 0x87 || textId == 0x78) { - return; - } else if (textId == 0x85) { - gctx->ShowMessage(rStoredTextId); - rStoredTextId = 0; - } else + void ItemOverride_SwapSoHAndSongGetItemText(game::GlobalContext* gctx, u16 textId, game::act::Actor* fromActor) { +// Check which text ID is coming in. If it's any mask from Song of Healing, replace it with active item text. +#if defined ENABLE_DEBUG || defined DEBUG_PRINT + rnd::util::Print("%s: txtId = %#08x\n", __func__, textId); +#endif + if (givenItemOverride) { + givenItemOverride = false; + if (rStoredTextId) { + gctx->ShowMessage(rStoredTextId); + rStoredTextId = 0; + } else + gctx->ShowMessage(textId); + } else { gctx->ShowMessage(textId); + } + return; } @@ -1131,5 +1196,49 @@ namespace rnd { u8 ItemOverride_ReceivedOcarinaFromSkt() { return gExtSaveData.givenItemChecks.ocarinaOfTimeGiven == 1 ? 1 : 0; } + + u8 ItemOverride_ReceivedSongOverride(s16 incomingItemId) { +#if defined ENABLE_DEBUG || defined DEBUG_PRINT + rnd::util::Print("%s: Incoming item id is %#04x\n", __func__, incomingItemId); +#endif + game::OcarinaSong lastPlayedSong = GetContext().gctx->msg_context.lastPlayedSong; + switch (incomingItemId) { + case 0x61: + return gExtSaveData.givenSongChecks.sonataGiven == 1 ? 1 : 0; + case 0x62: + if (lastPlayedSong != game::OcarinaSong::GoronLullablyIntro || lastPlayedSong != game::OcarinaSong::GoronLullaby) + return gExtSaveData.givenSongChecks.goronLullabyGiven == 1 ? 1 : 0; + else + return 1; + break; + case 0x63: + return gExtSaveData.givenSongChecks.newWaveBossaNovaGiven == 1 ? 1 : 0; + case 0x64: + return gExtSaveData.givenSongChecks.elegyOfEmptinessGiven == 1 ? 1 : 0; + case 0x65: + return gExtSaveData.givenSongChecks.oathToOrderGiven == 1 ? 1 : 0; + case 0x67: + return gExtSaveData.givenSongChecks.songOfTimeGiven == 1 ? 1 : 0; + case 0x68: + return gExtSaveData.givenSongChecks.songOfHealingGiven == 1 ? 1 : 0; + case 0x69: + return gExtSaveData.givenSongChecks.eponasSongGiven == 1 ? 1 : 0; + case 0x6A: + return gExtSaveData.givenSongChecks.songOfSoaringGiven == 1 ? 1 : 0; + case 0x6B: + return gExtSaveData.givenSongChecks.songOfStormsGiven == 1 ? 1 : 0; + case 0x73: + return gExtSaveData.givenSongChecks.goronLullabyIntroGiven == 1 ? 1 : 0; + default: + return 0; + } + } + + u8 ItemOverride_CheckIfSongOfTimeAwarded(u8 currentItem) { + game::SceneId scene = GetContext().gctx->scene; + if (scene == game::SceneId::ClockTowerRooftop && gExtSaveData.givenSongChecks.songOfTimeGiven == 0) + return 0x4C; + return currentItem; + } } } // namespace rnd diff --git a/code/source/rnd/objects.cpp b/code/source/rnd/objects.cpp index 280b1c4..536baea 100644 --- a/code/source/rnd/objects.cpp +++ b/code/source/rnd/objects.cpp @@ -72,9 +72,9 @@ namespace rnd { extern "C" game::ActorResource::ActorResource* ExtendedObject_GetStatus() { s32 i; -#if defined ENABLE_DEBUG || defined DEBUG_PRINT - rnd::util::Print("%s: rStoredObjId is %#06x\n", __func__, rStoredObjId); -#endif + // #if defined ENABLE_DEBUG || defined DEBUG_PRINT + // rnd::util::Print("%s: rStoredObjId is %#06x\n", __func__, rStoredObjId); + // #endif for (i = 0; i < rExtendedObjectCtx.num; ++i) { s32 id = rExtendedObjectCtx.status[i].object_id; id = (id < 0 ? -id : id); diff --git a/code/source/rnd/ocarina.cpp b/code/source/rnd/ocarina.cpp index 90ebfe0..c6b63b3 100644 --- a/code/source/rnd/ocarina.cpp +++ b/code/source/rnd/ocarina.cpp @@ -24,7 +24,7 @@ namespace rnd { // Disable BGM fadeout util::Write(gctx, 0x8422, 1); - gctx->ocarina_state = game::OcarinaState::StoppedPlaying; + gctx->msg_context.ocarina_state = game::OcarinaState::StoppedPlaying; } static bool IsElegyOfEmptinessAllowed() { @@ -70,8 +70,8 @@ namespace rnd { EndOcarinaSession(self); auto* gctx = GetContext().gctx; game::sound::PlayEffect(game::sound::EffectId::NA_SE_SY_TRE_BOX_APPEAR); - gctx->ocarina_song = song; - gctx->ocarina_state = game::OcarinaState::PlayingAndReplayDone; + gctx->msg_context.ocarina_song = song; + gctx->msg_context.ocarina_state = game::OcarinaState::PlayingAndReplayDone; self->song = u16(song); // This flag must always be false; otherwise the Song of Soaring handler will refuse // to show the map screen. @@ -93,11 +93,11 @@ namespace rnd { auto* gctx = GetContext().gctx; if (IsElegyOfEmptinessAllowed()) { game::sound::PlayEffect(game::sound::EffectId::NA_SE_SY_TRE_BOX_APPEAR); - gctx->ocarina_song = game::OcarinaSong::ElegyOfEmptiness; - gctx->ocarina_state = game::OcarinaState::PlayingAndReplayDone; + gctx->msg_context.ocarina_song = game::OcarinaSong::ElegyOfEmptiness; + gctx->msg_context.ocarina_state = game::OcarinaState::PlayingAndReplayDone; } else { gctx->ShowMessage(0x1B95, 0); // "Your notes echoed far..." - gctx->ocarina_state = game::OcarinaState::StoppedPlaying; + gctx->msg_context.ocarina_state = game::OcarinaState::StoppedPlaying; util::GetPointer(0x1D8C5C)(0); } diff --git a/code/source/rnd/savefile.cpp b/code/source/rnd/savefile.cpp index c4d11ad..23a7746 100644 --- a/code/source/rnd/savefile.cpp +++ b/code/source/rnd/savefile.cpp @@ -33,6 +33,7 @@ namespace rnd { saveData.inventory.inventory_count_register.stick_upgrades = 2; saveData.inventory.inventory_count_register.nut_upgrade = 2; saveData.player.rupee_count = 5000; + rnd::util::GetPointer(0x22b14c)(game::ItemId::Ocarina); rnd::util::GetPointer(0x22b14c)(game::ItemId::Arrow); rnd::util::GetPointer(0x22b14c)(game::ItemId::IceArrow); rnd::util::GetPointer(0x22b14c)(game::ItemId::LightArrow); @@ -108,12 +109,12 @@ namespace rnd { saveData.player.owl_statue_flags.ikana_canyon = 1; saveData.player.owl_statue_flags.stone_tower = 1; - saveData.inventory.collect_register.sonata_of_awakening = 1; + // saveData.inventory.collect_register.sonata_of_awakening = 1; saveData.inventory.collect_register.goron_lullaby = 1; - saveData.inventory.collect_register.new_wave_bossa_nova = 1; + // saveData.inventory.collect_register.new_wave_bossa_nova = 1; saveData.inventory.collect_register.elegy_of_emptiness = 1; saveData.inventory.collect_register.eponas_song = 1; - saveData.inventory.collect_register.song_of_soaring = 1; + // saveData.inventory.collect_register.song_of_soaring = 1; saveData.inventory.collect_register.song_of_time = 1; // saveData.inventory.collect_register.oath_to_order = 1; // saveData.inventory.collect_register.song_of_healing = 1;