diff --git a/UnleashedRecomp/api/SWA.h b/UnleashedRecomp/api/SWA.h index e2a846e1..48b0730b 100644 --- a/UnleashedRecomp/api/SWA.h +++ b/UnleashedRecomp/api/SWA.h @@ -59,6 +59,7 @@ #include "SWA/CSD/CsdTexListMirage.h" #include "SWA/CSD/GameObjectCSD.h" #include "SWA/Camera/Camera.h" +#include "SWA/Camera/CameraController.h" #include "SWA/HUD/GeneralWindow/GeneralWindow.h" #include "SWA/HUD/Loading/Loading.h" #include "SWA/HUD/Pause/HudPause.h" @@ -73,6 +74,7 @@ #include "SWA/Inspire/InspireTextureAnimationInfo.h" #include "SWA/Inspire/InspireTextureOverlay.h" #include "SWA/Inspire/InspireTextureOverlayInfo.h" +#include "SWA/Menu/MenuWindowBase.h" #include "SWA/Movie/MovieDisplayer.h" #include "SWA/Movie/MovieManager.h" #include "SWA/Player/Character/EvilSonic/EvilSonic.h" @@ -97,6 +99,9 @@ #include "SWA/System/GameMode/Title/TitleMenu.h" #include "SWA/System/GameMode/Title/TitleStateBase.h" #include "SWA/System/GameMode/Title/TitleStateIntro.h" +#include "SWA/System/GameMode/Title/TitleStateWorldMap.h" +#include "SWA/System/GameMode/WorldMap/WorldMapCamera.h" +#include "SWA/System/GameMode/WorldMap/WorldMapCursor.h" #include "SWA/System/GameObject.h" #include "SWA/System/GameParameter.h" #include "SWA/System/GammaController.h" diff --git a/UnleashedRecomp/api/SWA/Camera/CameraController.h b/UnleashedRecomp/api/SWA/Camera/CameraController.h new file mode 100644 index 00000000..9262ed05 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Camera/CameraController.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace SWA +{ + class CCameraController : public Hedgehog::Universe::CStateMachineBase::CStateBase + { + public: + SWA_INSERT_PADDING(0x04); + be m_FieldOfView; + SWA_INSERT_PADDING(0x68); + }; + + SWA_ASSERT_OFFSETOF(CCameraController, m_FieldOfView, 0x64); + SWA_ASSERT_SIZEOF(CCameraController, 0xD0); +} diff --git a/UnleashedRecomp/api/SWA/Menu/MenuWindowBase.h b/UnleashedRecomp/api/SWA/Menu/MenuWindowBase.h new file mode 100644 index 00000000..ccab2f68 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Menu/MenuWindowBase.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace SWA +{ + class CMenuWindowBase + { + public: + SWA_INSERT_PADDING(0x10); + }; +} diff --git a/UnleashedRecomp/api/SWA/System/GameMode/Title/TitleStateWorldMap.h b/UnleashedRecomp/api/SWA/System/GameMode/Title/TitleStateWorldMap.h new file mode 100644 index 00000000..4934d740 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameMode/Title/TitleStateWorldMap.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +namespace SWA +{ + class CTitleStateWorldMap : public CTitleStateBase + { + public: + SWA_INSERT_PADDING(0x08); + xpointer m_pWorldMapCursor; + }; +} diff --git a/UnleashedRecomp/api/SWA/System/GameMode/WorldMap/WorldMapCamera.h b/UnleashedRecomp/api/SWA/System/GameMode/WorldMap/WorldMapCamera.h new file mode 100644 index 00000000..77c1ab3b --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameMode/WorldMap/WorldMapCamera.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace SWA +{ + class CWorldMapCamera : public CCameraController + { + public: + be m_Pitch; + be m_Yaw; + be m_Distance; + be m_RotationSpeed; + SWA_INSERT_PADDING(0x08); + bool m_CanMove; + SWA_INSERT_PADDING(0x34); + be m_TiltToEarthTransitionSpeed; + }; + + SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_Pitch, 0xD0); + SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_Yaw, 0xD4); + SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_Distance, 0xD8); + SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_RotationSpeed, 0xDC); + SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_CanMove, 0xE8); + SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_TiltToEarthTransitionSpeed, 0x120); +} diff --git a/UnleashedRecomp/api/SWA/System/GameMode/WorldMap/WorldMapCursor.h b/UnleashedRecomp/api/SWA/System/GameMode/WorldMap/WorldMapCursor.h new file mode 100644 index 00000000..03ceb730 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameMode/WorldMap/WorldMapCursor.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace SWA +{ + class CWorldMapCursor : public CMenuWindowBase + { + public: + SWA_INSERT_PADDING(0x24); + be m_LeftStickVertical; + be m_LeftStickHorizontal; + bool m_IsCursorMoving; + SWA_INSERT_PADDING(0x07); + be m_CursorY; + be m_CursorX; + }; + + SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_LeftStickVertical, 0x34); + SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_LeftStickHorizontal, 0x38); + SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_IsCursorMoving, 0x3C); + SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_CursorY, 0x44); + SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_CursorX, 0x48); +} diff --git a/UnleashedRecomp/patches/input_patches.cpp b/UnleashedRecomp/patches/input_patches.cpp index fdddd619..10ef7cc3 100644 --- a/UnleashedRecomp/patches/input_patches.cpp +++ b/UnleashedRecomp/patches/input_patches.cpp @@ -1,28 +1,161 @@ #include +#include +#include +#include -static void SetDPadAnalogDirectionX(PPCRegister& pPadState, PPCRegister& x, bool negate) +constexpr float WORLD_MAP_TOUCH_CANCEL_DEADZONE = 0.31f; +constexpr float WORLD_MAP_TOUCH_DAMPING_FACTOR = 0.99f; +constexpr float WORLD_MAP_TOUCH_FLICK_ACCELERATION_X = 0.4f; +constexpr float WORLD_MAP_TOUCH_FLICK_ACCELERATION_Y = 0.2f; +constexpr float WORLD_MAP_TOUCH_FLICK_TERMINAL_VELOCITY = 40.0f; +constexpr float WORLD_MAP_TOUCH_FLICK_THRESHOLD = 2.25f; +constexpr float WORLD_MAP_TOUCH_SENSITIVITY_MULTIPLIER = 1.35f; +constexpr float WORLD_MAP_TOUCH_SMOOTHING_FACTOR = 0.8f; + +static bool g_isTouchActive; + +static float g_worldMapTouchVelocityX; +static float g_worldMapTouchVelocityY; + +class SDLEventListenerForInputPatches : public SDLEventListener +{ + static inline int ms_touchpadFingerCount; + + static inline float ms_touchpadX; + static inline float ms_touchpadY; + static inline float ms_touchpadDeltaX; + static inline float ms_touchpadDeltaY; + static inline float ms_touchpadPrevX; + static inline float ms_touchpadPrevY; + +public: + static void Update(float deltaTime) + { + /* NOTE (Hyper): this code was written at 144Hz and was + discovered later to be faulty at any other frame rate, + so this is here to account for that without changing + all the constants that I had tuned. */ + constexpr auto referenceDeltaTime = 1.0f / 144.0f; + + if (g_isTouchActive) + { + constexpr auto sensitivity = WORLD_MAP_TOUCH_SENSITIVITY_MULTIPLIER; + + auto dxNorm = ms_touchpadDeltaX / referenceDeltaTime; + auto dyNorm = ms_touchpadDeltaY / referenceDeltaTime; + auto dxSens = dxNorm * sensitivity; + auto dySens = dyNorm * sensitivity; + + auto smoothing = powf(WORLD_MAP_TOUCH_SMOOTHING_FACTOR, deltaTime / referenceDeltaTime); + + g_worldMapTouchVelocityX = smoothing * g_worldMapTouchVelocityX + (1.0f - smoothing) * dxSens; + g_worldMapTouchVelocityY = smoothing * g_worldMapTouchVelocityY + (1.0f - smoothing) * dySens; + + constexpr auto flickThreshold = WORLD_MAP_TOUCH_FLICK_THRESHOLD; + + if (fabs(dxSens) > flickThreshold || fabs(dySens) > flickThreshold) + { + constexpr auto flickAccelX = WORLD_MAP_TOUCH_FLICK_ACCELERATION_X; + constexpr auto flickAccelY = WORLD_MAP_TOUCH_FLICK_ACCELERATION_Y; + + g_worldMapTouchVelocityX += dxNorm * flickAccelX * (deltaTime / referenceDeltaTime); + g_worldMapTouchVelocityY += dyNorm * flickAccelY * (deltaTime / referenceDeltaTime); + } + + constexpr auto terminalVelocity = WORLD_MAP_TOUCH_FLICK_TERMINAL_VELOCITY; + + g_worldMapTouchVelocityX = std::clamp(g_worldMapTouchVelocityX, -terminalVelocity, terminalVelocity); + g_worldMapTouchVelocityY = std::clamp(g_worldMapTouchVelocityY, -terminalVelocity, terminalVelocity); + } + else + { + auto dampingFactor = powf(WORLD_MAP_TOUCH_DAMPING_FACTOR, deltaTime / referenceDeltaTime); + + g_worldMapTouchVelocityX *= dampingFactor; + g_worldMapTouchVelocityY *= dampingFactor; + } + } + + void OnSDLEvent(SDL_Event* event) override + { + switch (event->type) + { + case SDL_CONTROLLERTOUCHPADMOTION: + { + g_isTouchActive = true; + + if (ms_touchpadFingerCount > 1) + { + g_isTouchActive = false; + break; + } + + ms_touchpadX = event->ctouchpad.x; + ms_touchpadY = event->ctouchpad.y; + ms_touchpadDeltaX = ms_touchpadX - ms_touchpadPrevX; + ms_touchpadDeltaY = ms_touchpadY - ms_touchpadPrevY; + ms_touchpadPrevX = ms_touchpadX; + ms_touchpadPrevY = ms_touchpadY; + + break; + } + + case SDL_CONTROLLERTOUCHPADDOWN: + ms_touchpadFingerCount++; + ms_touchpadPrevX = event->ctouchpad.x; + ms_touchpadPrevY = event->ctouchpad.y; + break; + + case SDL_CONTROLLERTOUCHPADUP: + g_isTouchActive = false; + ms_touchpadFingerCount--; + break; + } + } +} +g_sdlEventListenerForInputPatches; + +// -------------- COMMON --------------- // + +static bool IsDPadActive(SWA::SPadState* pPadState) +{ + return pPadState->IsDown(SWA::eKeyState_DpadUp) || + pPadState->IsDown(SWA::eKeyState_DpadDown) || + pPadState->IsDown(SWA::eKeyState_DpadLeft) || + pPadState->IsDown(SWA::eKeyState_DpadRight); +} + +static void SetDPadAnalogDirectionX(PPCRegister& pPadState, PPCRegister& x, bool invert, float max = 1.0f) { auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32); if (pGuestPadState->IsDown(SWA::eKeyState_DpadLeft)) - x.f64 = negate ? 1.0f : -1.0f; + x.f64 = invert ? max : -max; if (pGuestPadState->IsDown(SWA::eKeyState_DpadRight)) - x.f64 = negate ? -1.0f : 1.0f; + x.f64 = invert ? -max : max; } -static void SetDPadAnalogDirectionY(PPCRegister& pPadState, PPCRegister& y, bool negate) +static void SetDPadAnalogDirectionY(PPCRegister& pPadState, PPCRegister& y, bool invert, float max = 1.0f) { auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32); if (pGuestPadState->IsDown(SWA::eKeyState_DpadUp)) - y.f64 = negate ? -1.0f : 1.0f; + y.f64 = invert ? -max : max; if (pGuestPadState->IsDown(SWA::eKeyState_DpadDown)) - y.f64 = negate ? 1.0f : -1.0f; + y.f64 = invert ? max : -max; } +// -------------- PLAYER --------------- // + void PostureDPadSupportMidAsmHook(PPCRegister& pPadState, PPCRegister& x, PPCRegister& y) +{ + SetDPadAnalogDirectionX(pPadState, x, false); + SetDPadAnalogDirectionY(pPadState, y, false); +} + +void PostureDPadSupportInvertYMidAsmHook(PPCRegister& pPadState, PPCRegister& x, PPCRegister& y) { SetDPadAnalogDirectionX(pPadState, x, false); SetDPadAnalogDirectionY(pPadState, y, true); @@ -38,8 +171,148 @@ void PostureDPadSupportYMidAsmHook(PPCRegister& pPadState, PPCRegister& y) SetDPadAnalogDirectionY(pPadState, y, false); } -void PostureDPadSupportPathLocalMidAsmHook(PPCRegister& pPadState, PPCRegister& x, PPCRegister& y) +void PostureSpaceHurrierDPadSupportXMidAsmHook(PPCRegister& pPadState, PPCVRegister& vector) { - SetDPadAnalogDirectionX(pPadState, x, false); - SetDPadAnalogDirectionY(pPadState, y, false); + auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32); + + if (pGuestPadState->IsDown(SWA::eKeyState_DpadLeft)) + vector.f32[3] = -1.0f; + + if (pGuestPadState->IsDown(SWA::eKeyState_DpadRight)) + vector.f32[3] = 1.0f; +} + +void PostureSpaceHurrierDPadSupportYMidAsmHook(PPCRegister& pPadState, PPCVRegister& vector) +{ + auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32); + + if (pGuestPadState->IsDown(SWA::eKeyState_DpadUp)) + vector.f32[3] = 1.0f; + + if (pGuestPadState->IsDown(SWA::eKeyState_DpadDown)) + vector.f32[3] = -1.0f; +} + +// ------------- WORLD MAP ------------- // + +bool WorldMapTouchSupportMidAsmHook() +{ + SDLEventListenerForInputPatches::Update(App::s_deltaTime); + + return fabs(g_worldMapTouchVelocityX) > 0 || fabs(g_worldMapTouchVelocityY) > 0; +} + +bool WorldMapTouchMagnetismSupportMidAsmHook(PPCRegister& f0) +{ + return fabs(g_worldMapTouchVelocityX) > f0.f64 || fabs(g_worldMapTouchVelocityY) > f0.f64; +} + +void TouchAndDPadSupportWorldMapXMidAsmHook(PPCRegister& pPadState, PPCRegister& x) +{ + auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32); + + if (fabs(pGuestPadState->LeftStickHorizontal) > WORLD_MAP_TOUCH_CANCEL_DEADZONE || + fabs(pGuestPadState->LeftStickVertical) > WORLD_MAP_TOUCH_CANCEL_DEADZONE) + { + g_worldMapTouchVelocityX = 0; + } + + if (IsDPadActive(pGuestPadState)) + { + g_worldMapTouchVelocityX = 0; + + SetDPadAnalogDirectionX(pPadState, x, false); + } + else + { + if (fabs(g_worldMapTouchVelocityX) > 0) + x.f64 = -g_worldMapTouchVelocityX; + } +} + +void TouchAndDPadSupportWorldMapYMidAsmHook(PPCRegister& pPadState, PPCRegister& y) +{ + auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32); + + if (fabs(pGuestPadState->LeftStickHorizontal) > WORLD_MAP_TOUCH_CANCEL_DEADZONE || + fabs(pGuestPadState->LeftStickVertical) > WORLD_MAP_TOUCH_CANCEL_DEADZONE) + { + g_worldMapTouchVelocityY = 0; + } + + if (IsDPadActive(pGuestPadState)) + { + g_worldMapTouchVelocityY = 0; + + SetDPadAnalogDirectionY(pPadState, y, false); + } + else + { + if (fabs(g_worldMapTouchVelocityY) > 0) + y.f64 = g_worldMapTouchVelocityY; + } +} + +/* This hook is unique as it is created after a label that is branched to + if input should be prohibited, resulting in the pad state being a nullptr. + We check the condition that enables that branch here for safety. */ +void TouchAndDPadSupportWorldMapMagnetismXMidAsmHook(PPCRegister& pPadState, PPCRegister& x, PPCRegister& isInputProhibited) +{ + if (isInputProhibited.u8 || !pPadState.u32) + return; + + TouchAndDPadSupportWorldMapXMidAsmHook(pPadState, x); +} + +// SWA::CWorldMapCamera::Update +PPC_FUNC_IMPL(__imp__sub_82486968); +PPC_FUNC(sub_82486968) +{ + auto pWorldMapCamera = (SWA::CWorldMapCamera*)g_memory.Translate(ctx.r3.u32); + + // Reset vertical velocity if maximum pitch reached. + if (fabs(pWorldMapCamera->m_Pitch) >= 80.0f) + g_worldMapTouchVelocityY = 0; + + __imp__sub_82486968(ctx, base); +} + +// World Map cursor move hook. +PPC_FUNC_IMPL(__imp__sub_8256C938); +PPC_FUNC(sub_8256C938) +{ + auto pWorldMapCursor = (SWA::CWorldMapCursor*)g_memory.Translate(ctx.r3.u32); + + pWorldMapCursor->m_IsCursorMoving = g_isTouchActive; + + if (ctx.r4.u8) + { + pWorldMapCursor->m_LeftStickVertical = 0; + pWorldMapCursor->m_LeftStickHorizontal = 0; + } + else if (auto pInputState = SWA::CInputState::GetInstance()) + { + auto& rPadState = pInputState->GetPadState(); + + pWorldMapCursor->m_LeftStickVertical = rPadState.LeftStickVertical; + pWorldMapCursor->m_LeftStickHorizontal = rPadState.LeftStickHorizontal; + + if (rPadState.IsDown(SWA::eKeyState_DpadUp)) + pWorldMapCursor->m_LeftStickVertical = 1.0f; + + if (rPadState.IsDown(SWA::eKeyState_DpadDown)) + pWorldMapCursor->m_LeftStickVertical = -1.0f; + + if (rPadState.IsDown(SWA::eKeyState_DpadLeft)) + pWorldMapCursor->m_LeftStickHorizontal = -1.0f; + + if (rPadState.IsDown(SWA::eKeyState_DpadRight)) + pWorldMapCursor->m_LeftStickHorizontal = 1.0f; + + if (sqrtf((pWorldMapCursor->m_LeftStickHorizontal * pWorldMapCursor->m_LeftStickHorizontal) + + (pWorldMapCursor->m_LeftStickVertical * pWorldMapCursor->m_LeftStickVertical)) > 0.7f) + { + pWorldMapCursor->m_IsCursorMoving = true; + } + } } diff --git a/UnleashedRecompLib/config/SWA.toml b/UnleashedRecompLib/config/SWA.toml index cbb89710..64207ccc 100644 --- a/UnleashedRecompLib/config/SWA.toml +++ b/UnleashedRecompLib/config/SWA.toml @@ -550,25 +550,25 @@ address = 0x824DC9D4 # CPlayerSpeedPostureInputOnPath [[midasm_hook]] -name = "PostureDPadSupportMidAsmHook" +name = "PostureDPadSupportInvertYMidAsmHook" address = 0x8234F194 registers = ["r31", "f13", "f0"] # CPlayerSpeedPostureInputOnPathLocal [[midasm_hook]] -name = "PostureDPadSupportPathLocalMidAsmHook" +name = "PostureDPadSupportMidAsmHook" address = 0x8234F610 registers = ["r30", "f0", "f13"] # CPlayerSpeedPostureInput3DStandard [[midasm_hook]] -name = "PostureDPadSupportMidAsmHook" +name = "PostureDPadSupportInvertYMidAsmHook" address = 0x8234EEE8 registers = ["r31", "f12", "f13"] # CEvilPostureInputStandard [[midasm_hook]] -name = "PostureDPadSupportMidAsmHook" +name = "PostureDPadSupportInvertYMidAsmHook" address = 0x823CDA60 registers = ["r3", "f11", "f12"] @@ -580,9 +580,94 @@ registers = ["r3", "f0"] # CEvilPostureInputStandard [[midasm_hook]] -name = "PostureDPadSupportYMidAsmHook" -address = 0x823CDA88 -registers = ["r3", "f12"] +name = "PostureDPadSupportXMidAsmHook" +address = 0x823CDA74 +registers = ["r3", "f0"] + +# SWA::CObjBobsleigh::CStateMode3D +[[midasm_hook]] +name = "PostureDPadSupportXMidAsmHook" +address = 0x8266B5F0 +registers = ["r29", "f13"] + +# SWA::CObjBobsleigh::CStateMode3D +[[midasm_hook]] +name = "PostureDPadSupportXMidAsmHook" +address = 0x8266B8B4 +registers = ["r29", "f0"] + +# SWA::CObjBobsleigh::CStateMode3D +[[midasm_hook]] +name = "PostureDPadSupportXMidAsmHook" +address = 0x8266B618 +registers = ["r29", "f0"] + +# SWA::CObjBobsleigh::CStateMode3D +[[midasm_hook]] +name = "PostureDPadSupportXMidAsmHook" +address = 0x8266B6AC +registers = ["r29", "f0"] + +# CSuperSonicPostureInputSpaceHurrier +[[midasm_hook]] +name = "PostureSpaceHurrierDPadSupportXMidAsmHook" +address = 0x82455DD8 +registers = ["r30", "v61"] + +# CSuperSonicPostureInputSpaceHurrier +[[midasm_hook]] +name = "PostureSpaceHurrierDPadSupportYMidAsmHook" +address = 0x82455DC8 +registers = ["r30", "v63"] + +# CWorldMapCamera - disable rotation deadzone for touch +[[midasm_hook]] +name = "WorldMapTouchSupportMidAsmHook" +address = 0x824862EC +jump_address_on_true = 0x824862F0 + +# CWorldMapCamera - disable flag magnetism for touch +[[midasm_hook]] +name = "WorldMapTouchMagnetismSupportMidAsmHook" +address = 0x824866D4 +registers = ["f0"] +jump_address_on_true = 0x82486838 + +# CWorldMapCamera - touch and D-Pad support for camera adjustment threshold on the X axis +[[midasm_hook]] +name = "TouchAndDPadSupportWorldMapXMidAsmHook" +address = 0x824862D8 +registers = ["r30", "f12"] + +# CWorldMapCamera - touch and D-Pad support for adjusing camera yaw +[[midasm_hook]] +name = "TouchAndDPadSupportWorldMapXMidAsmHook" +address = 0x82486318 +registers = ["r30", "f12"] + +# CWorldMapCamera - touch and D-Pad support for camera adjustment threshold on the Y axis +[[midasm_hook]] +name = "TouchAndDPadSupportWorldMapYMidAsmHook" +address = 0x824862CC +registers = ["r30", "f0"] + +# CWorldMapCamera - touch and D-Pad support for adjusing camera pitch +[[midasm_hook]] +name = "TouchAndDPadSupportWorldMapYMidAsmHook" +address = 0x824862F4 +registers = ["r30", "f0"] + +# CWorldMapCamera - touch and D-Pad support for flag magnetism on the X axis +[[midasm_hook]] +name = "TouchAndDPadSupportWorldMapMagnetismXMidAsmHook" +address = 0x82486660 +registers = ["r27", "f29", "r28"] + +# CWorldMapCamera - touch and D-Pad support for flag magnetism on the Y axis +[[midasm_hook]] +name = "TouchAndDPadSupportWorldMapYMidAsmHook" +address = 0x8248665C +registers = ["r27", "f28"] [[midasm_hook]] name = "LoadingUpdateMidAsmHook"