From 486b730168126ddcb5e45a3df9ea6df829be12a0 Mon Sep 17 00:00:00 2001 From: ricardoofnl Date: Sat, 5 Sep 2026 08:00:47 +0700 Subject: [PATCH] [saco] Implement/match `FUNC_10014FF0`; it slerps the ped 75% onto the synced quaternion and reheads it --- saco/game/playerped.h | 1 + saco/game/util.h | 3 +++ saco/net/remoteplayer.cpp | 23 +++++++++++++++++++++++ saco/net/remoteplayer.h | 7 +++++-- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/saco/game/playerped.h b/saco/game/playerped.h index 2632253..edc52e3 100644 --- a/saco/game/playerped.h +++ b/saco/game/playerped.h @@ -132,6 +132,7 @@ public: void FUNC_100AC410(DWORD dwGtaId, int a2); // .text:100AC410 void FUNC_100ADFB0(int iLevel); // .text:100ADFB0 int FUNC_100ADC90(); // .text:100ADC90 + void FUNC_100ABF10(float fAngle); // .text:100ABF10 void ProcessVehicleHorn(); diff --git a/saco/game/util.h b/saco/game/util.h index 405d2f4..cf833c0 100644 --- a/saco/game/util.h +++ b/saco/game/util.h @@ -109,6 +109,9 @@ int __stdcall FUNC_100B4240(DWORD *pdwIn, DWORD dwParam); // .text:100B4240 void __stdcall FUNC_100B42B0(DWORD *pdwEntity); // .text:100B42B0 DWORD __stdcall FUNC_100B4430(int a1, int a2); // .text:100B4430 void FUNC_100B5D20(); // .text:100B5D20 +void FUNC_100B52B0(MATRIX4X4 *pMatrix, float *pQuatOut); // .text:100B52B0 +void FUNC_100B5480(float *pQuatOut, float *pQuatFrom, float *pQuatTo, float fT); // .text:100B5480 +void FUNC_100B6A80(float *pQuat, MATRIX4X4 *pMatrix); // .text:100B6A80 void FUNC_100B5210(int a1, void *a2); // .text:100B5210, __cdecl: the caller's // stack cleanup is folded into the next call's argument setup diff --git a/saco/net/remoteplayer.cpp b/saco/net/remoteplayer.cpp index 764bd8a..8a44306 100644 --- a/saco/net/remoteplayer.cpp +++ b/saco/net/remoteplayer.cpp @@ -13,6 +13,7 @@ extern CChatWindow *pChatWindow; typedef char CRemotePlayer_offsets[( offsetof(CRemotePlayer, field_C5) == 0xC5 && + offsetof(CRemotePlayer, field_C5.quat) == 0xD7 && offsetof(CRemotePlayer, field_C5.vecOffset) == 0xF7 && offsetof(CRemotePlayer, field_C5.wVehicleID) == 0x103 && sizeof(((CRemotePlayer *)0)->field_C5) == 68 && @@ -358,6 +359,28 @@ void CRemotePlayer::FUNC_10014800() //---------------------------------------------------- +void CRemotePlayer::FUNC_10014FF0() +{ + if(!m_pPlayerPed) return; + + MATRIX4X4 mat; + float quatBlend[4]; + float quatCur[4]; + + m_pPlayerPed->GetMatrix(&mat); + FUNC_100B52B0(&mat, quatCur); + FUNC_100B5480(quatBlend, field_C5.quat, quatCur, 0.75f); + FUNC_100B6A80(quatBlend, &mat); + m_pPlayerPed->SetMatrix(mat); + + float fAngle = atan2(-mat.up.X, mat.up.Y) * 57.2957764f; + if(fAngle < 0.0f) fAngle += 360.0f; + else if(fAngle >= 360.0f) fAngle -= 360.0f; + m_pPlayerPed->FUNC_100ABF10(fAngle); +} + +//---------------------------------------------------- + void CRemotePlayer::FUNC_100148F0() { if(m_pPlayerPed && m_pPlayerPed->IsInVehicle()) { diff --git a/saco/net/remoteplayer.h b/saco/net/remoteplayer.h index a5318ba..50a32ee 100644 --- a/saco/net/remoteplayer.h +++ b/saco/net/remoteplayer.h @@ -23,10 +23,12 @@ public: char field_AD[24]; // one 68-byte block: ResetAllSyncAttributes memsets it whole struct { - char _pad0[50]; + char _pad0[18]; + float quat[4]; // 0xD7 + char _padE7[16]; VECTOR vecOffset; // 0xF7 WORD wVehicleID; // 0x103 - char _pad1[4]; + char _pad105[4]; } field_C5; char field_109; BYTE field_10A; @@ -82,6 +84,7 @@ public: void FUNC_10014540(short a1, short a2, short a3); // .text:10014540 void FUNC_10014650(); // .text:10014650 void FUNC_100148F0(); // .text:100148F0 + void FUNC_10014FF0(); // .text:10014FF0 void FUNC_10014800(); // .text:10014800 void FUNC_10017610(char *szText); // .text:10017610 void FUNC_100150D0(VECTOR *pPos, VECTOR *pMoveSpeed); // .text:100150D0