diff --git a/Client/game_sa/CAEWeaponAudioEntitySA.h b/Client/game_sa/CAEWeaponAudioEntitySA.h new file mode 100644 index 00000000000..0f35260de07 --- /dev/null +++ b/Client/game_sa/CAEWeaponAudioEntitySA.h @@ -0,0 +1,52 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CAEWeaponAudioEntitySA.h + * PURPOSE: Weapon audio entity header + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once +#include "CAudioEngineSA.h" + +enum class eMiniGunState : std::uint8_t +{ + SPINNING, + FIRING, + STOPPING, + STOPPED, +}; + +enum class eChainsawState : std::uint8_t +{ + IDLE, + ACTIVE, + CUTTING, + STOPPING, + STOPPED, +}; + +class CAEWeaponAudioEntitySAInterface : public CAEAudioEntity +{ +public: + bool m_isMiniGunSpinActive; + bool m_isMiniGunFireActive; + + std::uint8_t m_lastWeaponPlaneFrequencyIndex; + + eMiniGunState m_miniGunState; + eChainsawState m_chainsawState; + + std::uint32_t m_lastFlamethrowerFireTimeInMS; + std::uint32_t m_lastSpraycanFireTimeInMS; + std::uint32_t m_lastFireExtinguisherFireTimeInMS; + std::uint32_t m_lastMinigunFireTimeInMS; + std::uint32_t m_lastChainsawFireTimeInMS; + std::uint32_t m_lastGunFireTimeInMS; + + CAESound* m_flameThrowerIdleGasLoopSound{}; +}; +static_assert(sizeof(CAEWeaponAudioEntitySAInterface) == 0xA0, "Invalid size for CAEWeaponAudioEntitySAInterface"); diff --git a/Client/game_sa/CPedSA.cpp b/Client/game_sa/CPedSA.cpp index b6541d7e71d..0601cabcf71 100644 --- a/Client/game_sa/CPedSA.cpp +++ b/Client/game_sa/CPedSA.cpp @@ -1,556 +1,315 @@ /***************************************************************************** * - * PROJECT: Multi Theft Auto v1.0 + * PROJECT: Multi Theft Auto * LICENSE: See LICENSE in the top level directory * FILE: game_sa/CPedSA.cpp * PURPOSE: Ped entity * - * Multi Theft Auto is available from http://www.multitheftauto.com/ + * Multi Theft Auto is available from https://www.multitheftauto.com/ * *****************************************************************************/ #include "StdInc.h" -#include -#include "CFireManagerSA.h" #include "CGameSA.h" -#include "CPedModelInfoSA.h" #include "CPedSA.h" +#include "CPedModelInfoSA.h" #include "CPlayerInfoSA.h" -#include "CProjectileInfoSA.h" #include "CStatsSA.h" #include "CTaskManagerSA.h" #include "CTasksSA.h" -#include "CWeaponInfoSA.h" +#include "CProjectileInfoSA.h" #include "CWeaponStatManagerSA.h" +#include "CFireManagerSA.h" extern CGameSA* pGame; -int g_bOnlyUpdateRotations = false; - -CPedSA::CPedSA(CPedSAInterface* pPedInterface) noexcept - : m_pPedInterface(pPedInterface) -{ - MemSetFast(m_pWeapons, 0, sizeof(CWeaponSA*) * WEAPONSLOT_MAX); -} - -void CPedSA::SetInterface(CEntitySAInterface* intInterface) -{ - m_pInterface = intInterface; -} +static bool g_onlyUpdateRotations = false; CPedSA::~CPedSA() { - if (m_pPedIntelligence) - delete m_pPedIntelligence; - if (m_pPedSound) - delete m_pPedSound; - - for (int i = 0; i < WEAPONSLOT_MAX; i++) - { - if (m_pWeapons[i]) - delete m_pWeapons[i]; - } - // Make sure this ped is not refed in the flame shot info array - CFlameShotInfo* pInfo = (CFlameShotInfo*)ARRAY_CFlameShotInfo; - for (uint i = 0; i < MAX_FLAME_SHOT_INFOS; i++) + auto* info = reinterpret_cast(ARRAY_CFlameShotInfo); + for (std::size_t i = 0; i < MAX_FLAME_SHOT_INFOS; i++, info++) { - if (pInfo->pInstigator == m_pInterface) - { - pInfo->pInstigator = NULL; - pInfo->ucFlag1 = 0; - } - pInfo++; + if (info->pInstigator != m_pInterface) + continue; + + info->pInstigator = nullptr; + info->ucFlag1 = 0; } } // used to init weapons at the moment, called by CPlayerPedSA when its been constructed // can't use constructor as thats called before the interface pointer has been set the the aforementioned constructor -/** - * \todo Reimplement weapons and PedIK for SA - */ +// TODO Reimplement weapons and PedIK for SA void CPedSA::Init() { CPedSAInterface* pedInterface = GetPedInterface(); - DWORD dwPedIntelligence = 0; - DWORD dwFunc = 0x411DE0; - DWORD dwInterface = (DWORD)pedInterface; - _asm - { - mov ecx, dwInterface - call dwFunc - mov dwPedIntelligence, eax - } - CPedIntelligenceSAInterface* m_pPedIntelligenceInterface = (CPedIntelligenceSAInterface*)(dwPedIntelligence); - m_pPedIntelligence = new CPedIntelligenceSA(m_pPedIntelligenceInterface, this); - m_pPedSound = new CPedSoundSA(&pedInterface->pedSound); + m_pedIntelligence = std::make_unique(pedInterface->pPedIntelligence, this); - m_sDefaultVoiceType = m_pPedSound->GetVoiceTypeID(); - m_sDefaultVoiceID = m_pPedSound->GetVoiceID(); + m_pedSound = std::make_unique(&pedInterface->pedSound); + m_defaultVoiceType = m_pedSound->GetVoiceTypeID(); + m_defaultVoiceID = m_pedSound->GetVoiceID(); - for (int i = 0; i < WEAPONSLOT_MAX; i++) - m_pWeapons[i] = new CWeaponSA(&(pedInterface->Weapons[i]), this, (eWeaponSlot)i); + for (std::size_t i = 0; i < WEAPONSLOT_MAX; i++) + m_weapons[i] = std::make_unique(&(pedInterface->Weapons[i]), this, static_cast(i)); - // this->m_pPedIK = new Cm_pPedIKSA(&(pedInterface->m_pPedIK)); + #ifdef PedIK_SA + this->m_pPedIK = new Cm_pPedIKSA(&(pedInterface->m_pPedIK)); + #endif } -void CPedSA::SetModelIndex(DWORD dwModelIndex) +void CPedSA::SetModelIndex(std::uint32_t modelIndex) { - // Delete any existing RwObject first - GetPedInterface()->DeleteRwObject(); - - // Set new model - DWORD dwThis = (DWORD)GetInterface(); - DWORD dwFunction = FUNC_SetModelIndex; - _asm - { - mov ecx, dwThis - push dwModelIndex - call dwFunction - } + // char __thiscall CPed::SetModelIndex(void *this, int a2) + ((char(__thiscall*)(CEntitySAInterface*, int))FUNC_SetModelIndex)(m_pInterface, modelIndex); // Also set the voice gender - CPedModelInfoSAInterface* pModelInfo = (CPedModelInfoSAInterface*)pGame->GetModelInfo(dwModelIndex)->GetInterface(); - if (pModelInfo) - { - DWORD dwType = pModelInfo->pedType; - GetPedInterface()->pedSound.m_bIsFemale = (dwType == 5 || dwType == 22); - } -} + CModelInfo* mi = pGame->GetModelInfo(modelIndex); + if (!mi) + return; -bool CPedSA::IsInWater() -{ - CTask* pTask = m_pPedIntelligence->GetTaskManager()->GetTask(TASK_PRIORITY_EVENT_RESPONSE_NONTEMP); - return (pTask && (pTask->GetTaskType() == TASK_COMPLEX_IN_WATER)); -} + CPedModelInfoSAInterface* modelInfo = static_cast(mi->GetInterface()); + if (!modelInfo) + return; -bool CPedSA::AddProjectile(eWeaponType eWeapon, CVector vecOrigin, float fForce, CVector* target, CEntity* targetEntity) -{ - return ((CProjectileInfoSA*)pGame->GetProjectileInfo())->AddProjectile((CEntitySA*)this, eWeapon, vecOrigin, fForce, target, targetEntity); + std::uint32_t type = modelInfo->pedType; + GetPedInterface()->pedSound.m_bIsFemale = type == 5 || type == 22; } -void CPedSA::DetachPedFromEntity() +bool CPedSA::AddProjectile(eWeaponType weaponType, CVector origin, float force, CVector* target, CEntity* targetEntity) { - DWORD dwFunc = FUNC_DetachPedFromEntity; - DWORD dwThis = (DWORD)GetInterface(); - _asm - { - mov ecx, dwThis - call dwFunc - } + CProjectileInfo* projectileInfo = pGame->GetProjectileInfo(); + if (!projectileInfo) + return false; + + return projectileInfo->AddProjectile(static_cast(this), weaponType, origin, force, const_cast(target), const_cast(targetEntity)); } -bool CPedSA::InternalAttachEntityToEntity(DWORD dwEntityInterface, const CVector* vecPosition, const CVector* vecRotation) +void CPedSA::DetachPedFromEntity() { - AttachPedToEntity(dwEntityInterface, const_cast(vecPosition), 0, 0.0f, WEAPONTYPE_UNARMED, FALSE); - return true; + // void __thiscall CPed::DettachPedFromEntity(CPed *this) + ((void(__thiscall*)(CEntitySAInterface*))FUNC_DetachPedFromEntity)(m_pInterface); } -void CPedSA::AttachPedToEntity(DWORD dwEntityInterface, CVector* vector, unsigned short sDirection, float fRotationLimit, eWeaponType weaponType, - bool bChangeCamera) +bool CPedSA::InternalAttachEntityToEntity(DWORD entityInteface, const CVector* position, const CVector* rotation) { // sDirection and fRotationLimit only apply to first-person shooting (bChangeCamera) - DWORD dwFunc = FUNC_AttachPedToEntity; - DWORD dwThis = (DWORD)GetInterface(); - float fX = vector->fX; - float fY = vector->fY; - float fZ = vector->fZ; - BYTE bPedType = ((CPedSAInterface*)GetInterface())->bPedType; + CPedSAInterface* pedInterface = GetPedInterface(); + std::uint8_t pedType = pedInterface->bPedType; // Hack the CPed type(?) to non-player so the camera doesn't get changed - if (!bChangeCamera) - ((CPedSAInterface*)GetInterface())->bPedType = 2; + pedInterface->bPedType = 2; - _asm - { - push weaponType - push fRotationLimit - movzx ecx, sDirection - push ecx - push fZ - push fY - push fX - push dwEntityInterface - mov ecx, dwThis - call dwFunc - } + // CEntity *__thiscall CPed::AttachPedToEntity(CPed *this, CEntity *a2, float arg4, float a4, float a5, __int16 a6, int a7, eWeaponType a3) + ((CEntitySAInterface*(__thiscall*)(CEntitySAInterface*, CEntitySAInterface*, float, float, float, std::uint16_t, int, eWeaponType))FUNC_AttachPedToEntity)(m_pInterface, reinterpret_cast(entityInteface), position->fX, position->fY, position->fZ, 0, 0, WEAPONTYPE_UNARMED); // Hack the CPed type(?) to whatever it was set to - if (!bChangeCamera)((CPedSAInterface*)GetInterface())->bPedType = bPedType; -} - -CVehicle* CPedSA::GetVehicle() -{ - if (((CPedSAInterface*)GetInterface())->pedFlags.bInVehicle) - { - CVehicleSAInterface* vehicle = (CVehicleSAInterface*)(((CPedSAInterface*)GetInterface())->pVehicle); - if (vehicle) - { - SClientEntity* pVehicleClientEntity = pGame->GetPools()->GetVehicle((DWORD*)vehicle); - return pVehicleClientEntity ? pVehicleClientEntity->pEntity : nullptr; - } - } - return NULL; -} - -void CPedSA::Respawn(CVector* position, bool bCameraCut) -{ - CPed* pLocalPlayer = pGame->GetPools()->GetPedFromRef((DWORD)1); - - if (!bCameraCut) - { - // DISABLE call to CCamera__RestoreWithJumpCut when respawning - MemSet((void*)0x4422EA, 0x90, 20); - } - - float fX = position->fX; - float fY = position->fY; - float fZ = position->fZ; - float fUnk = 1.0f; - DWORD dwFunc = FUNC_RestorePlayerStuffDuringResurrection; - DWORD dwThis = (DWORD)GetInterface(); - _asm - { - push fUnk - push fZ - push fY - push fX - push dwThis - call dwFunc - add esp, 20 - } -#if 0 // Removed to see if it reduces crashes - dwFunc = 0x441440; // CGameLogic::SortOutStreamingAndMemory - fUnk = 10.0f; - _asm - { - push fUnk - push position - call dwFunc - add esp, 8 - } -#endif - dwFunc = FUNC_RemoveGogglesModel; - _asm - { - mov ecx, dwThis - call dwFunc - } + pedInterface->bPedType = pedType; - if (!bCameraCut) - { - // B9 28 F0 B6 00 E8 4C 9A 0C 00 B9 28 F0 B6 00 E8 B2 97 0C 00 - unsigned char szCode[] = {0xB9, 0x28, 0xF0, 0xB6, 0x00, 0xE8, 0x4C, 0x9A, 0x0C, 0x00, 0xB9, 0x28, 0xF0, 0xB6, 0x00, 0xE8, 0xB2, 0x97, 0x0C, 0x00}; - // RE-ENABLE call to CCamera__RestoreWithJumpCut when respawning - MemCpy((void*)0x4422EA, szCode, 20); - } - // OutputDebugString ( "Respawn!!!!" ); -} - -float CPedSA::GetHealth() -{ - return GetPedInterface()->fHealth; -} - -void CPedSA::SetHealth(float fHealth) -{ - GetPedInterface()->fHealth = fHealth; + return true; } -float CPedSA::GetArmor() noexcept +CVehicle* CPedSA::GetVehicle() const { - return GetPedInterface()->fArmor; -} + CPedSAInterface* pedInterface = GetPedInterface(); + if (!pedInterface || !pedInterface->pedFlags.bInVehicle) + return nullptr; -void CPedSA::SetArmor(float armor) noexcept -{ - GetPedInterface()->fArmor = armor; -} + CVehicleSAInterface* vehicleInterface = pedInterface->pVehicle; + if (!vehicleInterface) + return nullptr; -float CPedSA::GetOxygenLevel() -{ - return GetPedInterface()->pPlayerData->m_fBreath; + auto* vehicleClientEntity = pGame->GetPools()->GetVehicle(reinterpret_cast(vehicleInterface)); + return vehicleClientEntity ? vehicleClientEntity->pEntity : nullptr; } -void CPedSA::SetOxygenLevel(float fOxygen) +void CPedSA::Respawn(CVector* position, bool cameraCut) { - GetPedInterface()->pPlayerData->m_fBreath = fOxygen; -} + if (!cameraCut) + // CGameLogic::RestorePlayerStuffDuringResurrection + // Disable calls to CCamera::SetCameraDirectlyBehindForFollowPed_CamOnAString & CCamera::RestoreWithJumpCut + MemSet((void*)0x4422EA, 0x90, 20); -void CPedSA::SetIsStanding(bool bStanding) -{ - DWORD dwFunc = FUNC_SetIsStanding; - DWORD dwThis = (DWORD)GetInterface(); - _asm - { - mov ecx, dwThis - push bStanding - call dwFunc - } -} + // void __cdecl CGameLogic::RestorePlayerStuffDuringResurrection(CPlayerPed *player, __int128 a2) + ((void(__cdecl*)(CEntitySAInterface*, float, float, float, float))FUNC_RestorePlayerStuffDuringResurrection)(m_pInterface, position->fX, position->fY, position->fZ, 1.0f); -DWORD CPedSA::GetType() -{ - return m_dwType; -} + #ifdef SortOutStreamingAndMemory // Disabled to see if it reduces crashes + float angle = 10.0f; // angle for CRenderer::RequestObjectsInDirection -void CPedSA::SetType(DWORD dwType) -{ - m_dwType = dwType; -} + // void __cdecl CGameLogic::SortOutStreamingAndMemory(CVector *translation, float angle) + ((void(__cdecl*)(CVector*, float))FUNC_SortOutStreamingAndMemory)(position, angle); + #endif -void CPedSA::RemoveWeaponModel(int iModel) -{ - DWORD dwFunc = FUNC_RemoveWeaponModel; - DWORD dwThis = (DWORD)GetInterface(); - _asm - { - mov ecx, dwThis - push iModel - call dwFunc - } -} + // BYTE *__thiscall CPed::RemoveGogglesModel(CPed *this) + ((std::uint8_t*(__thiscall*)(CEntitySAInterface*))FUNC_RemoveGogglesModel)(m_pInterface); -void CPedSA::ClearWeapon(eWeaponType weaponType) -{ - DWORD dwFunc = FUNC_ClearWeapon; - DWORD dwThis = (DWORD)GetInterface(); - _asm - { - mov ecx, dwThis - push weaponType - call dwFunc - } + if (!cameraCut) + // Re-enable calls to CCamera::SetCameraDirectlyBehindForFollowPed_CamOnAString & CCamera::RestoreWithJumpCut + // Restore original bytes + MemCpy((void*)0x4422EA, "\xB9\x28\xF0\xB6\x00\xE8\x4C\x9A\x0C\x00\xB9\x28\xF0\xB6\x00\xE8\xB2\x97\x0C\x00", 20); } -CWeapon* CPedSA::GiveWeapon(eWeaponType weaponType, unsigned int uiAmmo, eWeaponSkill skill) +CWeapon* CPedSA::GiveWeapon(eWeaponType weaponType, std::uint32_t ammo, eWeaponSkill skill) { + // Load weapon model if (weaponType != WEAPONTYPE_UNARMED) { - CWeaponInfo* pInfo = pGame->GetWeaponInfo(weaponType, skill); - if (pInfo) + CWeaponInfo* weaponInfo = pGame->GetWeaponInfo(weaponType, skill); + if (weaponInfo) { - int iModel = pInfo->GetModel(); - - if (iModel) + CModelInfo* modelInfo = pGame->GetModelInfo(static_cast(weaponInfo->GetModel())); + if (modelInfo) { - CModelInfo* pWeaponModel = pGame->GetModelInfo(iModel); - if (pWeaponModel) - { - pWeaponModel->Request(BLOCKING, "CPedSA::GiveWeapon"); - pWeaponModel->MakeCustomModel(); - } + modelInfo->Request(BLOCKING, "CPedSA::GiveWeapon"); + modelInfo->MakeCustomModel(); } + // If the weapon is satchels, load the detonator too if (weaponType == WEAPONTYPE_REMOTE_SATCHEL_CHARGE) - { - /*int iModel = pGame->GetWeaponInfo ( WEAPONTYPE_DETONATOR )->GetModel(); - if ( iModel ) - { - CModelInfo * pWeaponModel = pGame->GetModelInfo ( iModel ); - if ( pWeaponModel ) - { - pWeaponModel->Request ( true, true ); - } - }*/ - // Load the weapon and give it properly so getPedWeapon shows the weapon is there. GiveWeapon(WEAPONTYPE_DETONATOR, 1, WEAPONSKILL_STD); - } } } - DWORD dwReturn = 0; - DWORD dwFunc = FUNC_GiveWeapon; - DWORD dwThis = (DWORD)GetInterface(); - _asm - { - mov ecx, dwThis - push 1 - push uiAmmo - push weaponType - call dwFunc - mov dwReturn, eax - } - - CWeapon* pWeapon = GetWeapon((eWeaponSlot)dwReturn); + // eWeaponType __thiscall CPed::GiveWeapon(CPed *this, eWeaponType weaponID, signed int ammo, int a4) + // Last argument is unused + eWeaponSlot weaponSlot = ((eWeaponSlot(__thiscall*)(CEntitySAInterface*, eWeaponType, std::uint32_t, int))FUNC_GiveWeapon)(m_pInterface, weaponType, ammo, 1); - return pWeapon; + return GetWeapon(weaponSlot); } -CWeapon* CPedSA::GetWeapon(eWeaponType weaponType) +CWeapon* CPedSA::GetWeapon(eWeaponType weaponType) const { - if (weaponType < WEAPONTYPE_LAST_WEAPONTYPE) - { - CWeapon* pWeapon = GetWeapon(pGame->GetWeaponInfo(weaponType)->GetSlot()); - if (pWeapon->GetType() == weaponType) - return pWeapon; - } - return NULL; + if (weaponType >= WEAPONTYPE_LAST_WEAPONTYPE) + return nullptr; + + CWeapon* weapon = GetWeapon(pGame->GetWeaponInfo(weaponType)->GetSlot()); + return (weapon && weapon->GetType() == weaponType) ? weapon : nullptr; } -CWeapon* CPedSA::GetWeapon(eWeaponSlot weaponSlot) +CWeapon* CPedSA::GetWeapon(eWeaponSlot weaponSlot) const noexcept { - if (weaponSlot < WEAPONSLOT_MAX) - { - return m_pWeapons[weaponSlot]; - } - else - return NULL; + return (weaponSlot >= 0 && weaponSlot < WEAPONSLOT_MAX) ? m_weapons[weaponSlot].get() : nullptr; } void CPedSA::ClearWeapons() { // Remove all the weapons - for (unsigned int i = 0; i < WEAPONSLOT_MAX; i++) + for (auto& weapon : m_weapons) { - if (m_pWeapons[i]) - { - m_pWeapons[i]->SetAmmoInClip(0); - m_pWeapons[i]->SetAmmoTotal(0); - m_pWeapons[i]->Remove(); - } + weapon->SetAmmoInClip(0); + weapon->SetAmmoTotal(0); + weapon->Remove(); } } -void CPedSA::RestoreLastGoodPhysicsState() +void CPedSA::RemoveWeaponModel(std::uint32_t model) { - CPhysicalSA::RestoreLastGoodPhysicsState(); - SetCurrentRotation(0); - SetTargetRotation(0); + // void __thiscall CPed::RemoveWeaponModel(CPed *this, int modelID) + ((void(__thiscall*)(CEntitySAInterface*, std::uint32_t))FUNC_RemoveWeaponModel)(m_pInterface, model); } -float CPedSA::GetCurrentRotation() +void CPedSA::ClearWeapon(eWeaponType weaponType) { - return GetPedInterface()->fCurrentRotation; + // BYTE *__thiscall CPed::ClearWeapon(CPed *this, eWeaponType a2) + ((std::uint8_t * (__thiscall*)(CEntitySAInterface*, eWeaponType)) FUNC_ClearWeapon)(m_pInterface, weaponType); } -float CPedSA::GetTargetRotation() +void CPedSA::SetIsStanding(bool standing) { - return GetPedInterface()->fTargetRotation; + // int __thiscall CPed::SetIsStanding(CPed *this, unsigned __int8 a2) + ((void(__thiscall*)(CEntitySAInterface*, bool))FUNC_SetIsStanding)(m_pInterface, standing); } -void CPedSA::SetCurrentRotation(float fRotation) +void CPedSA::RestoreLastGoodPhysicsState() { - GetPedInterface()->fCurrentRotation = fRotation; - - // char szDebug[255] = {'\0'}; - // sprintf(szDebug,"CurrentRotate Offset: %d", ((DWORD)&((CPedSAInterface *)GetInterface())->CurrentRotate) - (DWORD)GetInterface()); - // OutputDebugString(szDebug); + CPhysicalSA::RestoreLastGoodPhysicsState(); + SetCurrentRotation(0); + SetTargetRotation(0); } -void CPedSA::SetTargetRotation(float fRotation) +void CPedSA::SetCurrentWeaponSlot(eWeaponSlot weaponSlot) { - GetPedInterface()->fTargetRotation = fRotation; -} + if (weaponSlot >= WEAPONSLOT_MAX) + return; -eWeaponSlot CPedSA::GetCurrentWeaponSlot() -{ - return (eWeaponSlot)GetPedInterface()->bCurrentWeaponSlot; -} + eWeaponSlot currentSlot = GetCurrentWeaponSlot(); + if (weaponSlot == currentSlot) + return; -void CPedSA::SetCurrentWeaponSlot(eWeaponSlot weaponSlot) -{ - if (weaponSlot < WEAPONSLOT_MAX) + CWeapon* weapon = GetWeapon(currentSlot); + if (weapon) { - eWeaponSlot currentSlot = GetCurrentWeaponSlot(); - if (weaponSlot != GetCurrentWeaponSlot()) - { - CWeapon* weapon = GetWeapon(currentSlot); - if (weapon) - { - CWeaponInfo* weaponInfo = weapon->GetInfo(WEAPONSKILL_STD); + CWeaponInfo* weaponInfo = weapon->GetInfo(WEAPONSKILL_STD); + if (weaponInfo) + RemoveWeaponModel(weaponInfo->GetModel()); + } - if (weaponInfo) - RemoveWeaponModel(weaponInfo->GetModel()); - } + // set the new weapon slot + GetPedInterface()->bCurrentWeaponSlot = weaponSlot; - CPedSAInterface* thisPed = (CPedSAInterface*)GetInterface(); + // is the player the local player? + CPed* localPlayer = pGame->GetPedContext(); - // set the new weapon slot - thisPed->bCurrentWeaponSlot = weaponSlot; + std::uintptr_t changeWeaponFunc; - // is the player the local player? - CPed* pPed = pGame->GetPools()->GetPedFromRef((DWORD)1); - // if ( pPed == this && thisPed->pPlayerInfo ) - //{ + if (localPlayer == this) + { + auto* playerInfo = static_cast(pGame->GetPlayerInfo()); + if (!playerInfo) + return; - DWORD dwThis = (DWORD)GetInterface(); - if (pPed == this) - { - ((CPlayerInfoSA*)pGame->GetPlayerInfo())->GetInterface()->PlayerPedData.m_nChosenWeapon = weaponSlot; - - DWORD dwFunc = FUNC_MakeChangesForNewWeapon_Slot; - _asm - { - mov ecx, dwThis - push weaponSlot - call dwFunc - } - } - else - { - DWORD dwFunc = FUNC_SetCurrentWeapon; - _asm - { - mov ecx, dwThis - push weaponSlot - call dwFunc - } - } - } + if (auto* infoInterface = playerInfo->GetInterface()) + infoInterface->PlayerPedData.m_nChosenWeapon = weaponSlot; + + // void __thiscall CPlayerPed::MakeChangesForNewWeapon(CPlayerPed *this, int a3) + changeWeaponFunc = FUNC_MakeChangesForNewWeapon_Slot; } + else + // void __thiscall CPed::SetCurrentWeapon(CPed *this, int slot) + changeWeaponFunc = FUNC_SetCurrentWeapon; + + ((void(__thiscall*)(CEntitySAInterface*, eWeaponSlot))changeWeaponFunc)(m_pInterface, weaponSlot); } -CVector* CPedSA::GetBonePosition(eBone bone, CVector* vecPosition) +CVector* CPedSA::GetBonePosition(eBone bone, CVector* position) { ApplySwimAndSlopeRotations(); CEntitySAInterface* entity = GetInterface(); // NOTE(botder): A crash used to occur at 0x749B7B in RpClumpForAllAtomics, because the clump pointer might have been null // for a broken model. - if (entity->m_pRwObject != nullptr) - { - // void __thiscall CPed::GetBonePosition(struct RwV3d &, unsigned int, bool) - using Signature = void(__thiscall*)(CEntitySAInterface*, CVector*, unsigned int, bool); - const auto GameFunction = reinterpret_cast(FUNC_GetBonePosition); - GameFunction(entity, vecPosition, bone, true); - } + if (entity->m_pRwObject) + // int __thiscall CPed::GetBonePosition(CPed *this, CVector *pPoint, int bone_id, bool bDynamic) + ((void(__thiscall*)(CEntitySAInterface*, CVector*, eBone, bool))FUNC_GetBonePosition)(entity, position, bone, true); // Clamp to a sane range as this function can occasionally return massive values, // which causes ProcessLineOfSight to effectively freeze - if (!IsValidPosition(*vecPosition)) - { - *vecPosition = *GetPosition(); - } + if (!IsValidPosition(*position)) + *position = *GetPosition(); - return vecPosition; + return position; } -CVector* CPedSA::GetTransformedBonePosition(eBone bone, CVector* vecPosition) +CVector* CPedSA::GetTransformedBonePosition(eBone bone, CVector* position) { ApplySwimAndSlopeRotations(); CEntitySAInterface* entity = GetInterface(); // NOTE(botder): A crash used to occur at 0x7C51A8 in RpHAnimIDGetIndex, because the clump pointer might have been null // for a broken model. - if (entity->m_pRwObject != nullptr) - { - // void __thiscall CPed::GetTransformedBonePosition(struct RwV3d &, unsigned int, bool) - using Signature = void(__thiscall*)(CEntitySAInterface*, CVector*, unsigned int, bool); - const auto GameFunction = reinterpret_cast(FUNC_GetTransformedBonePosition); - GameFunction(entity, vecPosition, bone, true); - } + if (entity->m_pRwObject) + // RwV3D *__thiscall CPed::GetTransformedBonePosition(CPed *this, RwV3D *pointsIn, int boneId, char bUpdateBones) + ((RwV3d*(__thiscall*)(CEntitySAInterface*, CVector*, eBone, bool))FUNC_GetTransformedBonePosition)(entity, position, bone, true); // Clamp to a sane range as this function can occasionally return massive values, // which causes ProcessLineOfSight to effectively freeze - if (!IsValidPosition(*vecPosition)) - { - *vecPosition = *GetPosition(); - } + if (!IsValidPosition(*position)) + *position = *GetPosition(); - return vecPosition; + return position; } // @@ -559,296 +318,104 @@ CVector* CPedSA::GetTransformedBonePosition(eBone bone, CVector* vecPosition) // void CPedSA::ApplySwimAndSlopeRotations() { - CPedSAInterface* pPedInterface = GetPedInterface(); - if (pPedInterface->pedFlags.bCalledPreRender) + CPedSAInterface* pedInterface = GetPedInterface(); + if (pedInterface->pedFlags.bCalledPreRender) return; - g_bOnlyUpdateRotations = true; - - DWORD dwFunc = FUNC_PreRenderAfterTest; - _asm - { - mov ecx, pPedInterface - call dwFunc - } - - g_bOnlyUpdateRotations = false; -} - -bool CPedSA::IsDucking() -{ - return ((CPedSAInterface*)GetInterface())->pedFlags.bIsDucking; -} - -void CPedSA::SetDucking(bool bDuck) -{ - ((CPedSAInterface*)GetInterface())->pedFlags.bIsDucking = bDuck; + // void __thiscall CPed::PreRenderAfterTest(CPed *this) + g_onlyUpdateRotations = true; + ((void(__thiscall*)(CEntitySAInterface*))FUNC_PreRenderAfterTest)(pedInterface); + g_onlyUpdateRotations = false; } -int CPedSA::GetCantBeKnockedOffBike() +bool CPedSA::IsInWater() const { - return ((CPedSAInterface*)GetInterface())->pedFlags.CantBeKnockedOffBike; + CTask* task = GetPedIntelligence()->GetTaskManager()->GetTask(TASK_PRIORITY_EVENT_RESPONSE_NONTEMP); + return (task && task->GetTaskType() == TASK_COMPLEX_IN_WATER); } -void CPedSA::SetCantBeKnockedOffBike(int iCantBeKnockedOffBike) +void CPedSA::SetGogglesState(bool isWearingThem) { - ((CPedSAInterface*)GetInterface())->pedFlags.CantBeKnockedOffBike = iCantBeKnockedOffBike; + // void __thiscall CPed::PutOnGoggles(CPed *this) + // void __thiscall CPed::TakeOffGoggles(CPed *this) + std::uintptr_t enableGoggleFunc = isWearingThem ? FUNC_PutOnGoggles : FUNC_TakeOffGoggles; + ((void(__thiscall*)(CEntitySAInterface*))enableGoggleFunc)(m_pInterface); } -void CPedSA::QuitEnteringCar(CVehicle* vehicle, int iSeat, bool bUnknown) +void CPedSA::SetClothesTextureAndModel(const char* texture, const char* model, int textureType) { - CVehicleSA* pVehicleSA = dynamic_cast(vehicle); - if (!pVehicleSA) + CPedClothesDesc* clothes = GetPedInterface()->pPlayerData->m_pClothes; + if (!clothes) return; - DWORD dwFunc = FUNC_QuitEnteringCar; - DWORD dwThis = (DWORD)GetInterface(); - DWORD dwVehicle = (DWORD)pVehicleSA->GetInterface(); - _asm - { - push bUnknown - push iSeat - push dwVehicle - push dwThis - call dwFunc - add esp, 16 - } -} - -bool CPedSA::IsWearingGoggles() -{ - DWORD dwFunc = FUNC_IsWearingGoggles; - DWORD dwThis = (DWORD)GetInterface(); - bool bReturn = false; - _asm - { - mov ecx, dwThis - call dwFunc - mov bReturn, al - } - return bReturn; -} - -void CPedSA::SetGogglesState(bool bIsWearingThem) -{ - DWORD dwFunc = FUNC_TakeOffGoggles; - if (bIsWearingThem) - dwFunc = FUNC_PutOnGoggles; - - DWORD dwThis = (DWORD)GetInterface(); - _asm - { - mov ecx, dwThis - call dwFunc - } -} - -void CPedSA::SetClothesTextureAndModel(const char* szTexture, const char* szModel, int textureType) -{ - DWORD dwFunc = FUNC_CPedClothesDesc__SetTextureAndModel; - // DWORD dwThis = (DWORD)this->GetInterface()->PlayerPedData.m_pClothes; - DWORD dwThis = (DWORD)((CPedSAInterface*)GetInterface())->pPlayerData->m_pClothes; - _asm - { - mov ecx, dwThis - push textureType - push szModel - push szTexture - call dwFunc - } + // int __fastcall CPedClothesDesc::SetTextureAndModel(DWORD* this, int unknown, char* textureName, char* modelName, eClothesTexturePart texturePart) + // Second argument is unused in CKeyGen::GetUppercaseKey + ((void(__fastcall*)(CPedClothesDesc*, int, const char*, const char*, std::uint8_t))FUNC_CPedClothesDesc__SetTextureAndModel)(clothes, 0, texture, model, textureType); } void CPedSA::RebuildPlayer() { - DWORD dwFunc = FUNC_CClothes__RebuildPlayer; - DWORD dwThis = (DWORD)GetInterface(); - _asm - { - push 0 - push dwThis - call dwFunc - add esp, 8 - } -} - -eFightingStyle CPedSA::GetFightingStyle() -{ - return (eFightingStyle)((CPedSAInterface*)GetInterface())->bFightingStyle; -} - -void CPedSA::SetFightingStyle(eFightingStyle style, BYTE bStyleExtra) -{ - BYTE bStyle = (BYTE)style; - BYTE* pFightingStyle = &((CPedSAInterface*)GetInterface())->bFightingStyle; - BYTE* pFightingStyleExtra = &((CPedSAInterface*)GetInterface())->bFightingStyleExtra; - if (bStyle != *pFightingStyle) - { - *pFightingStyle = bStyle; - if (bStyleExtra > 0 && bStyleExtra <= 6) - { - bStyleExtra--; - BYTE bTemp = *pFightingStyleExtra; - switch (bStyleExtra) - { - case 0: - break; - case 1: - bTemp |= 1; - break; - case 2: - bTemp |= 2; - break; - case 3: - bTemp |= 4; - break; - case 4: - bTemp |= 8; - break; - case 5: - bTemp |= 16; - break; - } - *pFightingStyleExtra = bTemp; - } - } + // void __cdecl CClothes::RebuildPlayer(CPed *ped, char bIgnoreFatAndMuscle) + ((void(__cdecl*)(CEntitySAInterface*, bool))FUNC_CClothes__RebuildPlayer)(m_pInterface, false); } -CEntity* CPedSA::GetContactEntity() +void CPedSA::SetFightingStyle(eFightingStyle style, std::uint8_t styleExtra) { - CEntitySAInterface* pInterface = ((CPedSAInterface*)GetInterface())->pContactEntity; - if (pInterface) - { - CPools* pPools = pGame->GetPools(); - switch (pInterface->nType) - { - case ENTITY_TYPE_VEHICLE: - { - SClientEntity* pVehicleClientEntity = pPools->GetVehicle((DWORD*)pInterface); - if (pVehicleClientEntity) - { - return pVehicleClientEntity->pEntity; - } - break; - } - case ENTITY_TYPE_OBJECT: - { - SClientEntity* pObjectClientEntity = pPools->GetObject((DWORD*)pInterface); - if (pObjectClientEntity) - { - return pObjectClientEntity->pEntity; - } - break; - } - default: - { - break; - } - } - } - return nullptr; -} + CPedSAInterface* pedInterface = GetPedInterface(); + if (style == pedInterface->bFightingStyle) + return; -unsigned char CPedSA::GetRunState() -{ - return *(unsigned char*)(((DWORD)(GetInterface()) + 1332)); -} + pedInterface->bFightingStyle = style; -CEntity* CPedSA::GetTargetedEntity() -{ - CEntitySAInterface* pInterface = ((CPedSAInterface*)GetInterface())->pTargetedEntity; - if (pInterface) - { - CPools* pPools = pGame->GetPools(); - return pPools->GetEntity((DWORD*)pInterface); - } - return nullptr; + if (styleExtra > 0 && styleExtra <= 6) + pedInterface->bFightingStyleExtra |= (1 << (styleExtra - 1)); } -void CPedSA::SetTargetedEntity(CEntity* pEntity) +CEntity* CPedSA::GetContactEntity() const { - CEntitySAInterface* pInterface = NULL; - if (pEntity) - { - CEntitySA* pEntitySA = dynamic_cast(pEntity); - if (pEntitySA) - pInterface = pEntitySA->GetInterface(); - } + CEntitySAInterface* contactInterface = GetPedInterface()->pContactEntity; + if (!contactInterface) + return nullptr; - ((CPedSAInterface*)GetInterface())->pTargetedEntity = pInterface; + return pGame->GetPools()->GetEntity(reinterpret_cast(contactInterface)); } -bool CPedSA::GetCanBeShotInVehicle() +CEntity* CPedSA::GetTargetedEntity() const { - return GetPedInterface()->pedFlags.bCanBeShotInVehicle; -} + CEntitySAInterface* targetInterface = GetPedInterface()->pTargetedEntity; + if (!targetInterface) + return nullptr; -bool CPedSA::GetTestForShotInVehicle() -{ - return GetPedInterface()->pedFlags.bTestForShotInVehicle; + return pGame->GetPools()->GetEntity(reinterpret_cast(targetInterface)); } -void CPedSA::SetCanBeShotInVehicle(bool bShot) +void CPedSA::SetTargetedEntity(CEntity* targetEntity) { - GetPedInterface()->pedFlags.bCanBeShotInVehicle = bShot; + GetPedInterface()->pTargetedEntity = targetEntity ? targetEntity->GetInterface() : nullptr; } -void CPedSA::SetTestForShotInVehicle(bool bTest) +void CPedSA::RemoveBodyPart(std::uint8_t boneID, std::uint8_t direction) { - GetPedInterface()->pedFlags.bTestForShotInVehicle = bTest; + // char __thiscall CPed::RemoveBodyPart(CPed *this, int boneID, int localDir) + // second argument is unused (direction) + ((char(__thiscall*)(CEntitySAInterface*, std::uint8_t, std::uint8_t))FUNC_CPed_RemoveBodyPart)(m_pInterface, boneID, 0); } -void CPedSA::RemoveBodyPart(int i, char c) +void CPedSA::SetFootBlood(std::uint32_t footBlood) { - DWORD dwThis = (DWORD)GetInterface(); - DWORD dwFunc = FUNC_CPed_RemoveBodyPart; - _asm - { - mov ecx, dwThis - push c - push i - call dwFunc - } -} + CPedSAInterface* pedInterface = GetPedInterface(); + pedInterface->pedFlags.bDoBloodyFootprints = footBlood > 0; -void CPedSA::SetFootBlood(unsigned int uiFootBlood) -{ - DWORD dwThis = (DWORD)GetInterface(); - // Check if the ped is to have foot blood - if (uiFootBlood > 0) - { - // Make sure the foot blood flag is activated - MemOrFast(dwThis + 0x46F, 16); - } - else if (*(unsigned short*)(dwThis + 0x46F) & 16) - { - // If the foot blood flag is activated, deactivate it - MemSubFast(dwThis + 0x46F, 16); - } // Set the amount of foot blood - MemPutFast(dwThis + 0x750, uiFootBlood); + pedInterface->timeWhenDead = footBlood; } -unsigned int CPedSA::GetFootBlood() +std::uint32_t CPedSA::GetFootBlood() const { - DWORD dwThis = (DWORD)GetInterface(); - // Check if the ped has the foot blood flag - if (*(unsigned short*)(dwThis + 0x46F) & 16) - { - // If the foot blood flag is activated, return the amount of foot blood - return *(unsigned int*)(dwThis + 0x750); - } - // Otherwise, return zero as there is no foot blood - return 0; -} - -bool CPedSA::IsBleeding() -{ - return GetPedInterface()->pedFlags.bPedIsBleeding; -} - -void CPedSA::SetBleeding(bool bBleeding) -{ - GetPedInterface()->pedFlags.bPedIsBleeding = bBleeding; + CPedSAInterface* pedInterface = GetPedInterface(); + + // If the foot blood flag is activated, return the amount of foot blood + return pedInterface->pedFlags.bDoBloodyFootprints ? pedInterface->timeWhenDead : 0; } bool CPedSA::SetOnFire(bool onFire) @@ -858,6 +425,8 @@ bool CPedSA::SetOnFire(bool onFire) return false; auto* fireManager = static_cast(pGame->GetFireManager()); + if (!fireManager) + return false; if (onFire) { @@ -886,108 +455,139 @@ bool CPedSA::SetOnFire(bool onFire) return true; } -void CPedSA::SetStayInSamePlace(bool bStay) +void CPedSA::GetVoice(std::int16_t* voiceType, std::int16_t* voiceID) const { - GetPedInterface()->pedFlags.bStayInSamePlace = bStay; -} + if (!m_pedSound) + return; -void CPedSA::GetVoice(short* psVoiceType, short* psVoiceID) -{ - if (psVoiceType) - *psVoiceType = m_pPedSound->GetVoiceTypeID(); - if (psVoiceID) - *psVoiceID = m_pPedSound->GetVoiceID(); + if (voiceType) + *voiceType = m_pedSound->GetVoiceTypeID(); + + if (voiceID) + *voiceID = m_pedSound->GetVoiceID(); } -void CPedSA::GetVoice(const char** pszVoiceType, const char** pszVoice) +void CPedSA::GetVoice(const char** voiceType, const char** voice) const { - short sVoiceType, sVoiceID; + std::int16_t sVoiceType, sVoiceID; GetVoice(&sVoiceType, &sVoiceID); - if (pszVoiceType) - *pszVoiceType = CPedSoundSA::GetVoiceTypeNameFromID(sVoiceType); - if (pszVoice) - *pszVoice = CPedSoundSA::GetVoiceNameFromID(sVoiceType, sVoiceID); + + if (voiceType) + *voiceType = CPedSoundSA::GetVoiceTypeNameFromID(sVoiceType); + if (voice) + *voice = CPedSoundSA::GetVoiceNameFromID(sVoiceType, sVoiceID); } -void CPedSA::SetVoice(short sVoiceType, short sVoiceID) +void CPedSA::SetVoice(std::int16_t voiceType, std::int16_t voiceID) { - m_pPedSound->SetVoiceTypeID(sVoiceType); - m_pPedSound->SetVoiceID(sVoiceID); + if (!m_pedSound) + return; + + m_pedSound->SetVoiceTypeID(voiceType); + m_pedSound->SetVoiceID(voiceID); } -void CPedSA::SetVoice(const char* szVoiceType, const char* szVoice) +void CPedSA::SetVoice(const char* voiceType, const char* voice) { - short sVoiceType = CPedSoundSA::GetVoiceTypeIDFromName(szVoiceType); + std::int16_t sVoiceType = CPedSoundSA::GetVoiceTypeIDFromName(voiceType); if (sVoiceType < 0) return; - short sVoiceID = CPedSoundSA::GetVoiceIDFromName(sVoiceType, szVoice); + + std::int16_t sVoiceID = CPedSoundSA::GetVoiceIDFromName(sVoiceType, voice); if (sVoiceID < 0) return; - SetVoice(sVoiceType, sVoiceID); -} -void CPedSA::ResetVoice() -{ - SetVoice(m_sDefaultVoiceType, m_sDefaultVoiceID); + SetVoice(sVoiceType, sVoiceID); } // GetCurrentWeaponStat will only work if the game ped context is currently set to this ped -CWeaponStat* CPedSA::GetCurrentWeaponStat() +CWeaponStat* CPedSA::GetCurrentWeaponStat() const { if (pGame->GetPedContext() != this) { OutputDebugLine("WARNING: GetCurrentWeaponStat ped context mismatch"); - return NULL; + return nullptr; } - CWeapon* pWeapon = GetWeapon(GetCurrentWeaponSlot()); + CWeapon* weapon = GetWeapon(GetCurrentWeaponSlot()); + if (!weapon) + return nullptr; - if (!pWeapon) - return NULL; + eWeaponType weaponType = weapon->GetType(); + std::uint16_t weaponSkillStat = pGame->GetStats()->GetSkillStatIndex(weaponType); + float skill = pGame->GetStats()->GetStatValue(weaponSkillStat); - eWeaponType eWeapon = pWeapon->GetType(); - ushort usStat = pGame->GetStats()->GetSkillStatIndex(eWeapon); - float fSkill = pGame->GetStats()->GetStatValue(usStat); - CWeaponStat* pWeaponStat = pGame->GetWeaponStatManager()->GetWeaponStatsFromSkillLevel(eWeapon, fSkill); - return pWeaponStat; + return pGame->GetWeaponStatManager()->GetWeaponStatsFromSkillLevel(weaponType, skill); } -float CPedSA::GetCurrentWeaponRange() +float CPedSA::GetCurrentWeaponRange() const { - CWeaponStat* pWeaponStat = GetCurrentWeaponStat(); - if (!pWeaponStat) - return 1; - - return pWeaponStat->GetWeaponRange(); + CWeaponStat* weaponStat = GetCurrentWeaponStat(); + return weaponStat ? weaponStat->GetWeaponRange() : 1.0f; } void CPedSA::AddWeaponAudioEvent(EPedWeaponAudioEventType audioEventType) { - DWORD dwFunc = FUNC_CAEPedWeaponAudioEntity__AddAudioEvent; - CPedWeaponAudioEntitySAInterface* pThis = &GetPedInterface()->weaponAudioEntity; - _asm - { - mov ecx, pThis - push audioEventType - call dwFunc - } + // void __thiscall CAEPedWeaponAudioEntity::AddAudioEvent(CAEPedWeaponAudioEntity *this, int audioEventId) + ((void(__thiscall*)(CPedWeaponAudioEntitySAInterface*, std::uint16_t))FUNC_CAEPedWeaponAudioEntity__AddAudioEvent)(&GetPedInterface()->weaponAudioEntity, static_cast(audioEventType)); +} + +bool CPedSA::IsDoingGangDriveby() const +{ + if (!m_pedIntelligence) + return false; + + CTask* task = GetPedIntelligence()->GetTaskManager()->GetTask(TASK_PRIORITY_PRIMARY); + return (task && task->GetTaskType() == TASK_SIMPLE_GANG_DRIVEBY); } -int CPedSA::GetCustomMoveAnim() +float CPedSA::GetOxygenLevel() const { - return m_iCustomMoveAnim; + return GetPedInterface()->pPlayerData->m_fBreath; +} + +void CPedSA::SetOxygenLevel(float oxygen) +{ + GetPedInterface()->pPlayerData->m_fBreath = oxygen; } -bool CPedSA::IsDoingGangDriveby() +void CPedSA::Say(const ePedSpeechContext& speechId, float probability) +{ + // Call CPed::Say + ((void(__thiscall*)(CPedSAInterface*, ePedSpeechContext, int, float, bool, bool, bool))FUNC_CPed_Say)(GetPedInterface(), speechId, 0, probability, false, false, false); +} + +void CPedSA::GetAttachedSatchels(std::vector& satchelsList) const { - auto pTaskManager = m_pPedIntelligence->GetTaskManager(); - CTask* pTask = pTaskManager->GetTask(TASK_PRIORITY_PRIMARY); - if (pTask && pTask->GetTaskType() == TASK_SIMPLE_GANG_DRIVEBY) + // Array of projectiles objects + auto** projectilesArray = reinterpret_cast(ARRAY_CProjectile); + CProjectileSAInterface* projectileInterface = nullptr; + + // Array of projectiles infos + auto* projectilesInfoArray = reinterpret_cast(ARRAY_CProjectileInfo); + CProjectileInfoSAInterface* projectileInfoInterface = nullptr; + + satchelsList.reserve(PROJECTILE_COUNT); + + // Loop through all projectiles + for (std::size_t i = 0; i < PROJECTILE_COUNT; i++) { - return true; - } + projectileInterface = projectilesArray[i]; + + // is attached to our ped? + if (!projectileInterface || projectileInterface->m_pAttachedEntity != m_pInterface) + continue; - return false; + // index is always the same for both arrays + projectileInfoInterface = &projectilesInfoArray[i]; + + // We are only interested in satchels + if (!projectileInfoInterface || projectileInfoInterface->dwProjectileType != eWeaponType::WEAPONTYPE_REMOTE_SATCHEL_CHARGE) + continue; + + // Push satchel into the array. There is no need to check the counter because for satchels it restarts until the player detonates the charges + satchelsList.emplace_back(projectileInterface, &projectileInterface->m_vecAttachedOffset, &projectileInterface->m_vecAttachedRotation); + } } //////////////////////////////////////////////////////////////// @@ -998,50 +598,34 @@ bool CPedSA::IsDoingGangDriveby() // Check if they have already been applied. // //////////////////////////////////////////////////////////////// -__declspec(noinline) int _cdecl OnCPed_PreRenderAfterTest(CPedSAInterface* pPedInterface) -{ - if (pPedInterface->pedFlags.bCalledPreRender) - return 1; // Skip slope and swim rotations - return 0; -} - -// Hook info -#define HOOKPOS_CPed_PreRenderAfterTest 0x05E65A0 -#define HOOKSIZE_CPed_PreRenderAfterTest 15 -DWORD RETURN_CPed_PreRenderAfterTest = 0x05E65AF; -DWORD RETURN_CPed_PreRenderAfterTestSkip = 0x05E6658; -void _declspec(naked) HOOK_CPed_PreRenderAfterTest() +#define HOOKPOS_CPed_PreRenderAfterTest 0x5E65A0 +#define HOOKSIZE_CPed_PreRenderAfterTest 15 +static constexpr std::uintptr_t RETURN_CPed_PreRenderAfterTest = 0x5E65AF; +static constexpr std::uintptr_t RETURN_CPed_PreRenderAfterTestSkip = 0x5E6658; +static void _declspec(naked) HOOK_CPed_PreRenderAfterTest() { _asm { - pushad - push ecx // this - call OnCPed_PreRenderAfterTest - mov [esp+0],eax // Put result temp - add esp, 4*1 - popad - - mov eax,[esp-32-4*1] // Get result temp - // Replaced code - sub esp,70h - push ebx - push ebp - push esi - mov ebp,ecx - mov ecx,dword ptr [ebp+47Ch] - push edi + sub esp,70h + push ebx + push ebp + push esi + mov ebp, ecx + mov ecx, dword ptr [ebp+47Ch] + push edi // Check what to do - cmp eax,0 - jnz skip_rotation_update + mov eax, [ebp+474h] // Load m_nThirdPedFlags + test eax, 400h // check bCalledPreRender flag + jnz skip_rotation_update // Run code at start of CPed::PreRenderAfterTest - jmp RETURN_CPed_PreRenderAfterTest + jmp RETURN_CPed_PreRenderAfterTest skip_rotation_update: // Skip code at start of CPed::PreRenderAfterTest - jmp RETURN_CPed_PreRenderAfterTestSkip + jmp RETURN_CPed_PreRenderAfterTestSkip } } @@ -1053,76 +637,37 @@ void _declspec(naked) HOOK_CPed_PreRenderAfterTest() // Check if it should not be called because we only wanted to do the extra rotations // //////////////////////////////////////////////////////////////// - -// Hook info -#define HOOKPOS_CPed_PreRenderAfterTest_Mid 0x05E6669 -#define HOOKSIZE_CPed_PreRenderAfterTest_Mid 5 -DWORD RETURN_CPed_PreRenderAfterTest_Mid = 0x05E666E; -DWORD RETURN_CPed_PreRenderAfterTest_MidSkip = 0x05E766F; -void _declspec(naked) HOOK_CPed_PreRenderAfterTest_Mid() +#define HOOKPOS_CPed_PreRenderAfterTest_Mid 0x5E6669 +#define HOOKSIZE_CPed_PreRenderAfterTest_Mid 5 +static constexpr std::uintptr_t RETURN_CPed_PreRenderAfterTest_Mid = 0x5E666E; +static constexpr std::uintptr_t RETURN_CPed_PreRenderAfterTest_MidSkip = 0x5E766F; +static void _declspec(naked) HOOK_CPed_PreRenderAfterTest_Mid() { _asm { // Check what to do - mov eax, g_bOnlyUpdateRotations - cmp eax,0 - jnz skip_tail + movzx eax, byte ptr g_onlyUpdateRotations + test eax, eax + jnz skip_tail // Replaced code - mov al,byte ptr ds:[00B7CB89h] + mov al, byte ptr ds:[00B7CB89h] // Run code at mid of CPed::PreRenderAfterTest - jmp RETURN_CPed_PreRenderAfterTest_Mid + jmp RETURN_CPed_PreRenderAfterTest_Mid skip_tail: // Skip code at mid of CPed::PreRenderAfterTest - jmp RETURN_CPed_PreRenderAfterTest_MidSkip + jmp RETURN_CPed_PreRenderAfterTest_MidSkip } } -////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// // // Setup hooks // -////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// void CPedSA::StaticSetHooks() { EZHookInstall(CPed_PreRenderAfterTest); EZHookInstall(CPed_PreRenderAfterTest_Mid); } - -void CPedSA::GetAttachedSatchels(std::vector& satchelsList) const -{ - // Array of projectiles objects - CProjectileSAInterface** projectilesArray = (CProjectileSAInterface**)ARRAY_CProjectile; - CProjectileSAInterface* pProjectileInterface; - - // Array of projectiles infos - CProjectileInfoSAInterface* projectilesInfoArray = (CProjectileInfoSAInterface*)ARRAY_CProjectileInfo; - CProjectileInfoSAInterface* pProjectileInfoInterface; - - // Loop through all projectiles - for (size_t i = 0; i < PROJECTILE_COUNT; i++) - { - pProjectileInterface = projectilesArray[i]; - - // is attached to our ped? - if (!pProjectileInterface || pProjectileInterface->m_pAttachedEntity != m_pInterface) - continue; - - // index is always the same for both arrays - pProjectileInfoInterface = &projectilesInfoArray[i]; - - // We are only interested in satchels - if (!pProjectileInfoInterface || pProjectileInfoInterface->dwProjectileType != eWeaponType::WEAPONTYPE_REMOTE_SATCHEL_CHARGE) - continue; - - // Push satchel into the array. There is no need to check the counter because for satchels it restarts until the player detonates the charges - satchelsList.push_back({pProjectileInterface, &pProjectileInterface->m_vecAttachedOffset, &pProjectileInterface->m_vecAttachedRotation}); - } -} - -void CPedSA::Say(const ePedSpeechContext& speechId, float probability) -{ - // Call CPed::Say - ((void(__thiscall*)(CPedSAInterface*, ePedSpeechContext, int, float, bool, bool, bool))FUNC_CPed_Say)(GetPedInterface(), speechId, 0, probability, false, false, false); -} diff --git a/Client/game_sa/CPedSA.h b/Client/game_sa/CPedSA.h index 201cb494ac5..df9abc476de 100644 --- a/Client/game_sa/CPedSA.h +++ b/Client/game_sa/CPedSA.h @@ -1,16 +1,14 @@ /***************************************************************************** * - * PROJECT: Multi Theft Auto v1.0 + * PROJECT: Multi Theft Auto * LICENSE: See LICENSE in the top level directory * FILE: game_sa/CPedSA.h * PURPOSE: Header file for ped entity base class * - * Multi Theft Auto is available from http://www.multitheftauto.com/ + * Multi Theft Auto is available from https://www.multitheftauto.com/ * *****************************************************************************/ -class CPedSA; - #pragma once #include @@ -20,54 +18,50 @@ class CPedSA; #include "CFireSA.h" #include "CPedIKSA.h" #include "CPhysicalSA.h" - #include "CPedSoundSA.h" #include "CPoolsSA.h" -#include "CVehicleSA.h" #include "CWeaponSA.h" +#include "CPedIntelligenceSA.h" -class CPedIntelligenceSA; class CPlayerPedDataSAInterface; -class CPedIntelligenceSAInterface; - -#include "CPedIntelligenceSA.h" +class CVehicleSAInterface; -#define SIZEOF_CPLAYERPED 1956 - -#define FUNC_SetModelIndex 0x5E4880 -#define FUNC_AttachPedToEntity 0x5E7CB0 -#define FUNC_RestorePlayerStuffDuringResurrection 0x442060 -#define FUNC_SetIsStanding 0x4ABBE0 -#define FUNC_MakeChangesForNewWeapon_Slot 0x60D000 - -#define FUNC_CPedClothesDesc__SetTextureAndModel 0x5A8080 -#define FUNC_CClothes__RebuildPlayer 0x5A82C0 -#define FUNC_CAEPedWeaponAudioEntity__AddAudioEvent 0x4E69F0 - -#define FUNC_QuitEnteringCar 0x650130 // really belongs in CCarEnterExit - -#define FUNC_SetCurrentWeapon 0x5E61F0 -#define FUNC_GiveWeapon 0x5E6080 -#define FUNC_GetBonePosition 0x5E4280 -#define FUNC_GetTransformedBonePosition 0x5E01C0 -#define FUNC_IsWearingGoggles 0x479D10 -#define FUNC_TakeOffGoggles 0x5E6010 -#define FUNC_PutOnGoggles 0x5E3AE0 -#define FUNC_RemoveWeaponModel 0x5E3990 -#define FUNC_RemoveGogglesModel 0x5DF170 -#define FUNC_ClearWeapon 0x5E62B0 -#define FUNC_DetachPedFromEntity 0x5E7EC0 -#define FUNC_CPed_RemoveBodyPart 0x5f0140 -#define FUNC_PreRenderAfterTest 0x5E65A0 +// CPed +#define FUNC_AttachPedToEntity 0x5E7CB0 // CPed::AttachPedToEntity +#define FUNC_DetachPedFromEntity 0x5E7EC0 // CPed::DettachPedFromEntity +#define FUNC_SetModelIndex 0x5E4880 // CPed::SetModelIndex +#define FUNC_SetIsStanding 0x4ABBE0 // CPed::SetIsStanding +#define FUNC_SetCurrentWeapon 0x5E61F0 // CPed::SetCurrentWeapon +#define FUNC_GiveWeapon 0x5E6080 // CPed::GiveWeapon +#define FUNC_ClearWeapon 0x5E62B0 // CPed::ClearWeapon +#define FUNC_RemoveWeaponModel 0x5E3990 // CPed::RemoveWeaponModel +#define FUNC_GetBonePosition 0x5E4280 // CPed::GetBonePosition +#define FUNC_GetTransformedBonePosition 0x5E01C0 // CPed::GetTransformedBonePosition +#define FUNC_TakeOffGoggles 0x5E6010 // CPed::TakeOffGoggles +#define FUNC_PutOnGoggles 0x5E3AE0 // CPed::PutOnGoggles +#define FUNC_RemoveGogglesModel 0x5DF170 // CPed::RemoveGogglesModel +#define FUNC_CPed_RemoveBodyPart 0x5F0140 // CPed::RemoveBodyPart +#define FUNC_PreRenderAfterTest 0x5E65A0 // CPed::PreRenderAfterTest #define FUNC_CPed_Say 0x5EFFE0 -#define VAR_LocalPlayer 0x94AD28 +// CPlayerPed +#define FUNC_MakeChangesForNewWeapon_Slot 0x60D000 // CPlayerPed::MakeChangesForNewWeapon + +// CPedClothesDesc && CClothes +#define FUNC_CPedClothesDesc__SetTextureAndModel 0x5A8080 // CPedClothesDesc::SetTextureAndModel +#define FUNC_CClothes__RebuildPlayer 0x5A82C0 // CClothes::RebuildPlayer + +// CAEPedWeaponAudioEntity +#define FUNC_CAEPedWeaponAudioEntity__AddAudioEvent 0x4E69F0 // CAEPedWeaponAudioEntity::AddAudioEvent + +// CGameLogic +#define FUNC_RestorePlayerStuffDuringResurrection 0x442060 // CGameLogic::RestorePlayerStuffDuringResurrection +#define FUNC_SortOutStreamingAndMemory 0x441440 // CGameLogic::SortOutStreamingAndMemory -//+1328 = Ped state -//+1344 = ped health class CPedFlags { public: + // m_nPedFlags unsigned int bIsStanding : 1; // is ped standing on something unsigned int bWasStanding : 1; // was ped standing on something unsigned int bIsLooking : 1; // is ped looking at something or in a direction @@ -92,8 +86,7 @@ class CPedFlags unsigned int bStopAndShoot : 1; // Ped cannot reach target to attack with fist, need to use gun unsigned int bIsPedDieAnimPlaying : 1; // is ped die animation finished so can dead now unsigned int bStayInSamePlace : 1; // when set, ped stays put - unsigned int - bKindaStayInSamePlace : 1; // when set, ped doesn't seek out opponent or cover large distances. Will still shuffle and look for cover + unsigned int bKindaStayInSamePlace : 1; // when set, ped doesn't seek out opponent or cover large distances. Will still shuffle and look for cover unsigned int bBeingChasedByPolice : 1; // use nodes for routefind unsigned int bNotAllowedToDuck : 1; // Is this ped allowed to duck at all? @@ -105,6 +98,7 @@ class CPedFlags unsigned int bStillOnValidPoly : 1; // set if the polygon the ped is on is still valid for collision unsigned int bAllowMedicsToReviveMe : 1; + // m_nSecondPedFlags unsigned int bResetWalkAnims : 1; unsigned int bOnBoat : 1; // flee but only using nodes unsigned int bBusJacked : 1; // flee but only using nodes @@ -141,6 +135,7 @@ class CPedFlags unsigned int bCrouchWhenScared : 1; unsigned int bKnockedOffBike : 1; + // m_nThirdPedFlags unsigned int bDonePositionOutOfCollision : 1; unsigned int bDontRender : 1; unsigned int bHasBeenAddedToPopulation : 1; @@ -176,8 +171,9 @@ class CPedFlags unsigned int bIsCached : 1; unsigned int bPushOtherPeds : 1; // GETS RESET EVERY FRAME - SET IN TASK: want to push other peds around (eg. leader of a group or ped trying to // get in a car) - unsigned int bHasBulletProofVest : 1; + // m_nFourthPedFlags + unsigned int bHasBulletProofVest : 1; unsigned int bUsingMobilePhone : 1; unsigned int bUpperBodyDamageAnimsOnly : 1; unsigned int bStuckUnderCar : 1; @@ -200,226 +196,304 @@ class CPedFlags unsigned int bJustGotOffTrain : 1; unsigned int bDeathPickupsPersist : 1; unsigned int bTestForShotInVehicle : 1; - // #ifdef GTA_REPLAY unsigned int bUsedForReplay : 1; // This ped is controlled by replay and should be removed when replay is done. - // #endif }; -class CPedWeaponAudioEntitySAInterface +class CPedAcquaintanceSAInterface { -public: + int respect; + int like; + int ignore; + int dislike; + int hate; }; +static_assert(sizeof(CPedAcquaintanceSAInterface) == 0x14, "Invalid size for CPedAcquaintanceSAInterface"); -class CVehicleSAInterface; +class CPedStatSAInterface +{ + std::uint32_t id; + char name[24]; + float fleedDistance; + float headingChangeRate; + std::uint8_t fear; + std::uint8_t temper; + std::uint8_t lawFullness; + std::uint8_t sexiness; + float attackStrength; + float defendWeakness; + std::uint16_t shootingRate; + std::uint8_t defaultDecisionMaker; +}; +static_assert(sizeof(CPedStatSAInterface) == 0x34, "Invalid size for CPedStatSAInterface"); -class CPedSAInterface : public CPhysicalSAInterface // +1420 = current vehicle 312 first byte +class CPedSAInterface : public CPhysicalSAInterface { public: - // current weapon slot 1184 ( and +1816?) - // CPedIKSAInterface pedIK; // 528 - // CWeaponSAInterface Weapons[9]; // 1032 - BYTE bPad[348]; - CPedSoundSAInterface pedSound; - BYTE bPad11[256 - sizeof(CPedSoundSAInterface)]; - CPedWeaponAudioEntitySAInterface weaponAudioEntity; - BYTE bPad12[216 - sizeof(CPedWeaponAudioEntitySAInterface)]; - CPedFlags pedFlags; // 1132 (16 bytes long including alignment probably) + CPedSoundEntitySAInterface pedAudio; // CAEPedAudioEntity + CPedSoundSAInterface pedSound; // CAEPedSpeechAudioEntity + CPedWeaponAudioEntitySAInterface weaponAudioEntity; // CAEPedWeaponAudioEntity + + std::uint8_t unk_43C[36]; + CPedSAInterface* roadRageWith; + std::uint8_t unk_464[8]; + + CPedFlags pedFlags; CPedIntelligenceSAInterface* pPedIntelligence; - CPlayerPedDataSAInterface* pPlayerData; // 1152 - BYTE bPad4a[4]; - void* pedNodes[19]; - int iMoveAnimGroup; // 1236 - BYTE bPad4b[52]; - CPedIKSAInterface pedIK; // 1292 (length 32 bytes) - - std::uint32_t field_52C; - ePedState pedState; - eMoveState moveState; - eMoveState swimmingMoveState; - std::uint32_t field_53C; - - float fHealth; - int iUnknown121; - float fArmor; - - int iUnknown313[3]; // +1356 - // +1368 = rotation - float fCurrentRotation; - float fTargetRotation; - float fRotationSpeed; - float fMoveAnim; - CEntitySAInterface* pContactEntity; - CVector unk_56C; - CVector unk_578; - - CEntitySAInterface* pLastContactEntity; - CVehicleSAInterface* pLastVehicle; - CVehicleSAInterface* pVehicle; - - int unk_590; - int unk_594; - BYTE bPedType; // ped type? 0 = player, >1 = ped? // 1432 - BYTE bPad9[7]; - CWeaponSAInterface Weapons[WEAPONSLOT_MAX]; - // weapons at +1440 ends at +1804 - BYTE bPad4[12]; - BYTE bCurrentWeaponSlot; // is actually here - BYTE bPad6[3]; - CEntitySAInterface* pTargetedObject; - BYTE tempPad[13]; - BYTE bFightingStyle; // 1837 - BYTE bFightingStyleExtra; - BYTE bPad7[1]; - CFireSAInterface* pFireOnPed; - BYTE bPad10[104]; - CEntitySAInterface* pTargetedEntity; // 1948 + CPlayerPedDataSAInterface* pPlayerData; + + std::uint8_t createdBy; + void* pedNodes[19]; // AnimBlendFrameData* + int iMoveAnimGroup; + CVector2D vecAnimMovingShiftLocal; + CPedAcquaintanceSAInterface pedAcquaintance; + + RpClump* pWeaponObject; + RwFrame* pGunflashObject; + RpClump* pGogglesObject; + bool* pGogglesState; + + std::int16_t weaponGunflashStateRightHand; + std::int16_t weaponGunFlashAlphaProgMP1; + std::int16_t weaponGunflashStateLeftHand; + std::int16_t weaponGunFlashAlphaProgMP2; + + CPedIKSAInterface pedIK; + int unk_52C; + + int pedState; + int moveState; + int swimmingMoveState; + + int unk_53C; + float fHealth; + float fMaxHealth; + float fArmor; + + std::uint32_t timeTillWeNeedThisPed; + CVector2D vecAnimMovingShift; + float fCurrentRotation; + float fTargetRotation; + float fRotationSpeed; + float fMoveAnim; + + CEntitySAInterface* pContactEntity; + CVector unk_56C; + CVector unk_578; + CEntitySAInterface* pLastContactEntity; + + CVehicleSAInterface* pLastVehicle; + CVehicleSAInterface* pVehicle; + CVehicleSAInterface* vehicleDeadInFrontOf; + + int unk_594; + int bPedType; // ped type? 0 = player, >1 = ped? + CPedStatSAInterface* pPedStats; + CWeaponSAInterface Weapons[WEAPONSLOT_MAX]; + eWeaponType savedWeapon; + eWeaponType delayedWeapon; + std::uint32_t delayedWeaponAmmo; + std::uint8_t bCurrentWeaponSlot; + std::uint8_t weaponShootingRate; + std::uint8_t weaponAccuracy; + + CEntitySAInterface* pTargetedObject; + int unk_720; + int unk_724; + int unk_728; + + eWeaponSkill weaponSkill; + eFightingStyle bFightingStyle; + std::uint8_t bFightingStyleExtra; + std::uint8_t bPad7; + + CFireSAInterface* pFireOnPed; + float fireDamageMult; + + CEntitySAInterface* pLookAtEntity; + float fLookHeading; + + std::uint32_t weaponModelID; + int unk_744; + std::uint32_t lookTime; + int unk_74C; + std::uint32_t timeWhenDead; // death time in MS + std::uint8_t bodyPartToRemove; + std::int16_t unk_755; + std::int16_t moneyCount; + std::int16_t unk_758; + int unk_75C; + std::uint8_t lastWeaponDamage; + std::uint8_t unk_761[3]; + CEntitySAInterface* pTargetedEntity; + std::int16_t unk_768; + + CVector vecTurretOffset; + float fTurretAngleA; + float fTurretAngleB; + std::uint32_t turretPosnMode; + std::uint32_t turretAmmo; + + void* pCoverPoint; // CCoverPoint* + void* pEnex; // CEntryExit* + float fRemovalDistMultiplier; + std::int16_t specialModelIndex; // StreamedScriptBrainToLoad + + std::int16_t unk_796; + int unk_798; }; +static_assert(sizeof(CPedSAInterface) == 0x79C, "Invalid size for CPedSAInterface"); class CPedSA : public virtual CPed, public virtual CPhysicalSA { friend class CPoolsSA; -private: - CWeaponSA* m_pWeapons[WEAPONSLOT_MAX]{}; - CPedIKSA* m_pPedIK{}; - CPedIntelligenceSA* m_pPedIntelligence{}; - CPedSAInterface* m_pPedInterface{}; - CPedSoundSA* m_pPedSound{}; - - short m_sDefaultVoiceType; - short m_sDefaultVoiceID; +public: + ~CPedSA(); - DWORD m_dwType; - unsigned char m_ucOccupiedSeat; + void SetInterface(CEntitySAInterface* intInterface) noexcept { m_pInterface = intInterface; } + CPedSAInterface* GetPedInterface() noexcept override { return static_cast(m_pInterface); } + CPedSAInterface* GetPedInterface() const noexcept { return static_cast(m_pInterface); } -protected: - int m_iCustomMoveAnim{ 0 }; + void Init(); + + void SetModelIndex(std::uint32_t modelIndex) override; -public: - CPedSA(CPedSAInterface* pedInterface = nullptr) noexcept; - ~CPedSA(); + bool InternalAttachEntityToEntity(DWORD entityInterface, const CVector* position, const CVector* rotation) override; + void DetachPedFromEntity() override; - void SetInterface(CEntitySAInterface* intInterface); - CPedSAInterface* GetPedInterface() { return (CPedSAInterface*)GetInterface(); } - void Init(); - void SetModelIndex(DWORD dwModelIndex); - void AttachPedToEntity(DWORD dwEntityInterface, CVector* vector, unsigned short sDirection, float fRotationLimit, eWeaponType weaponType, - bool bChangeCamera); - void DetachPedFromEntity(); + CVehicle* GetVehicle() const override; - CVehicle* GetVehicle(); - void Respawn(CVector* position, bool bCameraCut); - bool AddProjectile(eWeaponType eWeapon, CVector vecOrigin, float fForce, CVector* target, CEntity* targetEntity); + void Respawn(CVector* position, bool cameraCut) override; - float GetHealth(); - void SetHealth(float fHealth); + float GetHealth() const override { return GetPedInterface()->fHealth; } + void SetHealth(float health) override { GetPedInterface()->fHealth = health; } - float GetArmor() noexcept; - void SetArmor(float armor) noexcept; + float GetArmor() const override { return GetPedInterface()->fArmor; } + void SetArmor(float armor) override { GetPedInterface()->fArmor = armor; } - float GetOxygenLevel(); - void SetOxygenLevel(float fOxygen); + float GetOxygenLevel() const override; + void SetOxygenLevel(float oxygen) override; - CWeapon* GiveWeapon(eWeaponType weaponType, unsigned int uiAmmo, eWeaponSkill skill); - CWeapon* GetWeapon(eWeaponSlot weaponSlot); - CWeapon* GetWeapon(eWeaponType weaponType); + bool AddProjectile(eWeaponType weaponType, CVector origin, float force, CVector* target, CEntity* targetEntity) override; + CWeapon* GiveWeapon(eWeaponType weaponType, std::uint32_t ammo, eWeaponSkill skill) override; + CWeapon* GetWeapon(eWeaponSlot weaponSlot) const noexcept override; + CWeapon* GetWeapon(eWeaponType weaponType) const override; void ClearWeapons(); - void RemoveWeaponModel(int iModel); - void ClearWeapon(eWeaponType weaponType); + void RemoveWeaponModel(std::uint32_t model) override; + void ClearWeapon(eWeaponType weaponType) override; + + void SetIsStanding(bool standing) override; - void SetIsStanding(bool bStanding); - CPedIntelligence* GetPedIntelligence() { return m_pPedIntelligence; } - CPedSound* GetPedSound() { return m_pPedSound; } - DWORD GetType(); - void SetType(DWORD dwType); + std::uint32_t GetType() const noexcept override { return m_type; } + void SetType(std::uint32_t type) noexcept { m_type = type; } + + CPedIntelligence* GetPedIntelligence() const noexcept override { return m_pedIntelligence.get(); } + CPedSound* GetPedSound() const noexcept override { return m_pedSound.get(); } virtual void RestoreLastGoodPhysicsState(); - float GetCurrentRotation(); - float GetTargetRotation(); - void SetCurrentRotation(float fRotation); - void SetTargetRotation(float fRotation); - eWeaponSlot GetCurrentWeaponSlot(); - void SetCurrentWeaponSlot(eWeaponSlot weaponSlot); + float GetCurrentRotation() const override { return GetPedInterface()->fCurrentRotation; } + float GetTargetRotation() const override { return GetPedInterface()->fTargetRotation; } + void SetCurrentRotation(float rotation) override { GetPedInterface()->fCurrentRotation = rotation; } + void SetTargetRotation(float rotation) override { GetPedInterface()->fTargetRotation = rotation; } - CVector* GetBonePosition(eBone bone, CVector* vecPosition); - CVector* GetTransformedBonePosition(eBone bone, CVector* vecPosition); - void ApplySwimAndSlopeRotations(); + eWeaponSlot GetCurrentWeaponSlot() const override { return static_cast(GetPedInterface()->bCurrentWeaponSlot); } + void SetCurrentWeaponSlot(eWeaponSlot weaponSlot) override; - bool IsDucking(); - void SetDucking(bool bDuck); + CVector* GetBonePosition(eBone bone, CVector* position) override; + CVector* GetTransformedBonePosition(eBone bone, CVector* position) override; - bool IsInWater(); + bool IsDucking() const override { return GetPedInterface()->pedFlags.bIsDucking; } + void SetDucking(bool duck) override { GetPedInterface()->pedFlags.bIsDucking = duck; } - int GetCantBeKnockedOffBike(); - void SetCantBeKnockedOffBike(int iCantBeKnockedOffBike); - void QuitEnteringCar(CVehicle* vehicle, int iSeat, bool bUnknown); + bool IsInWater() const override; - bool IsWearingGoggles(); - void SetGogglesState(bool bIsWearingThem); + std::uint32_t GetCantBeKnockedOffBike() const override { return GetPedInterface()->pedFlags.CantBeKnockedOffBike; } + void SetCantBeKnockedOffBike(std::uint32_t cantBeKnockedOffBike) override { GetPedInterface()->pedFlags.CantBeKnockedOffBike = cantBeKnockedOffBike; } - void SetClothesTextureAndModel(const char* szTexture, const char* szModel, int textureType); - void RebuildPlayer(); + bool IsWearingGoggles() const override { return GetPedInterface()->pGogglesObject != nullptr; } + void SetGogglesState(bool isWearingThem) override; - eFightingStyle GetFightingStyle(); - void SetFightingStyle(eFightingStyle style, BYTE bStyleExtra = 6); + void SetClothesTextureAndModel(const char* texture, const char* model, int textureType) override; + void RebuildPlayer() override; - CEntity* GetContactEntity(); + eFightingStyle GetFightingStyle() const override { return static_cast(GetPedInterface()->bFightingStyle); } + void SetFightingStyle(eFightingStyle style, std::uint8_t styleExtra = 6) override; - unsigned char GetRunState(); + CEntity* GetContactEntity() const override; - CEntity* GetTargetedEntity(); - void SetTargetedEntity(CEntity* pEntity); + int GetRunState() const override { return GetPedInterface()->moveState; } - bool GetCanBeShotInVehicle(); - bool GetTestForShotInVehicle(); + CEntity* GetTargetedEntity() const override; + void SetTargetedEntity(CEntity* targetEntity) override; - void SetCanBeShotInVehicle(bool bShot); - void SetTestForShotInVehicle(bool bTest); + bool GetCanBeShotInVehicle() const override{ return GetPedInterface()->pedFlags.bCanBeShotInVehicle; } + bool GetTestForShotInVehicle() const override { return GetPedInterface()->pedFlags.bTestForShotInVehicle; } - bool InternalAttachEntityToEntity(DWORD dwEntityInterface, const CVector* vecPosition, const CVector* vecRotation); + void SetCanBeShotInVehicle(bool shot) override { GetPedInterface()->pedFlags.bCanBeShotInVehicle = shot; } + void SetTestForShotInVehicle(bool test) override { GetPedInterface()->pedFlags.bTestForShotInVehicle = test; } - BYTE GetOccupiedSeat() { return m_ucOccupiedSeat; } - void SetOccupiedSeat(BYTE seat) { m_ucOccupiedSeat = seat; } + std::uint8_t GetOccupiedSeat() const noexcept override { return m_occupiedSeat; } + void SetOccupiedSeat(std::uint8_t seat) noexcept override { m_occupiedSeat = seat; } - void RemoveBodyPart(int i, char c); + void RemoveBodyPart(std::uint8_t boneID, std::uint8_t direction) override; - void SetFootBlood(unsigned int uiFootBlood); - unsigned int GetFootBlood(); + void SetFootBlood(std::uint32_t footBlood) override; + std::uint32_t GetFootBlood() const override; - bool IsBleeding(); - void SetBleeding(bool bBleeding); + bool IsBleeding() const override { return GetPedInterface()->pedFlags.bPedIsBleeding; } + void SetBleeding(bool bleeding) override { GetPedInterface()->pedFlags.bPedIsBleeding = bleeding; } - bool IsOnFire() override { return GetPedInterface()->pFireOnPed != nullptr; } + bool IsOnFire() const override { return GetPedInterface()->pFireOnPed != nullptr; } bool SetOnFire(bool onFire) override; - bool GetStayInSamePlace() { return GetPedInterface()->pedFlags.bStayInSamePlace; } - void SetStayInSamePlace(bool bStay); + bool GetStayInSamePlace() const override { return GetPedInterface()->pedFlags.bStayInSamePlace; } + void SetStayInSamePlace(bool stay) override { GetPedInterface()->pedFlags.bStayInSamePlace = stay; } + + void GetVoice(std::int16_t* voiceType, std::int16_t* voiceID) const override; + void GetVoice(const char** voiceType, const char** voice) const override; + void SetVoice(std::int16_t voiceType, std::int16_t voiceID) override; + void SetVoice(const char* voiceType, const char* voice) override; + void ResetVoice() override { SetVoice(m_defaultVoiceType, m_defaultVoiceID); } + void Say(const ePedSpeechContext& speechId, float probability) override; - void GetVoice(short* psVoiceType, short* psVoiceID); - void GetVoice(const char** pszVoiceType, const char** pszVoice); - void SetVoice(short sVoiceType, short sVoiceID); - void SetVoice(const char* szVoiceType, const char* szVoice); - void ResetVoice(); - void SetLanding(bool bIsLanding) { GetPedInterface()->pedFlags.bIsLanding = bIsLanding; } - void SetUpdateMetricsRequired(bool required) { GetPedInterface()->pedFlags.bUpdateMatricesRequired = required; } + void SetLanding(bool isLanding) override { GetPedInterface()->pedFlags.bIsLanding = isLanding; } + void SetUpdateMetricsRequired(bool required) override { GetPedInterface()->pedFlags.bUpdateMatricesRequired = required; } - CWeaponStat* GetCurrentWeaponStat(); - float GetCurrentWeaponRange(); - void AddWeaponAudioEvent(EPedWeaponAudioEventType audioEventType); + CWeaponStat* GetCurrentWeaponStat() const override; + float GetCurrentWeaponRange() const override; + void AddWeaponAudioEvent(EPedWeaponAudioEventType audioEventType) override; - virtual int GetCustomMoveAnim(); - bool IsDoingGangDriveby(); + int GetCustomMoveAnim() const noexcept override { return m_iCustomMoveAnim; } - CPedIKSAInterface* GetPedIKInterface() { return &reinterpret_cast(m_pInterface)->pedIK; } - void* GetPedNodeInterface(std::int32_t nodeId) { return reinterpret_cast(m_pInterface)->pedNodes[nodeId]; } - std::unique_ptr GetPedIK() { return std::make_unique(GetPedIKInterface()); } - static void StaticSetHooks(); + bool IsDoingGangDriveby() const override; - CEntitySAInterface* GetTargetedObject() { return GetPedInterface()->pTargetedObject; } - ePedState GetPedState() { return GetPedInterface()->pedState; } + CPedIKSAInterface* GetPedIKInterface() override { return &GetPedInterface()->pedIK; } + void* GetPedNodeInterface(std::int32_t nodeId) override { return GetPedInterface()->pedNodes[nodeId]; } + std::unique_ptr GetPedIK() override { return std::make_unique(GetPedIKInterface()); } + + CEntitySAInterface* GetTargetedObject() const override { return GetPedInterface()->pTargetedObject; } + ePedState GetPedState() const override { return static_cast(GetPedInterface()->pedState); } void GetAttachedSatchels(std::vector &satchelsList) const override; - void Say(const ePedSpeechContext& speechId, float probability) override; + static void StaticSetHooks(); + +private: + void ApplySwimAndSlopeRotations(); + +protected: + int m_iCustomMoveAnim{0}; + +private: + std::array, WEAPONSLOT_MAX> m_weapons{}; + + std::unique_ptr m_pedIntelligence{}; + std::unique_ptr m_pedSound{}; + + std::int16_t m_defaultVoiceType; + std::int16_t m_defaultVoiceID; + + std::uint32_t m_type{PLAYER_PED}; + std::uint8_t m_occupiedSeat; }; diff --git a/Client/game_sa/CPedSoundSA.cpp b/Client/game_sa/CPedSoundSA.cpp index 4fd4ef1b16e..2bce3857180 100644 --- a/Client/game_sa/CPedSoundSA.cpp +++ b/Client/game_sa/CPedSoundSA.cpp @@ -30,7 +30,7 @@ short CPedSoundSA::GetVoiceID() void CPedSoundSA::SetVoiceTypeID(short sVoiceType) { - m_pInterface->m_sVoiceType = sVoiceType; + m_pInterface->m_sVoiceType = static_cast(sVoiceType); } void CPedSoundSA::SetVoiceID(short sVoiceID) diff --git a/Client/game_sa/CPedSoundSA.h b/Client/game_sa/CPedSoundSA.h index 140706b85c6..9ed6ae13e00 100644 --- a/Client/game_sa/CPedSoundSA.h +++ b/Client/game_sa/CPedSoundSA.h @@ -12,6 +12,11 @@ #pragma once #include +#include "CAudioEngineSA.h" +#include "CAEVehicleAudioEntitySA.h" +#include "CAEWeaponAudioEntitySA.h" + +class CPedSAInterface; #define FUNC_CAEPedSound__GetVoice 0x4E3CD0 // 4E3CD0 ; public: static short __cdecl CAEPedSound::GetVoice(char *,short) #define FUNC_CAEPedSound__GetAudioPedType 0x4E3C60 // 4E3C60 ; public: static short __cdecl CAEPedSound::GetAudioPedType(char *) @@ -30,13 +35,14 @@ #define NUM_PED_VOICE_TYPES 5 -enum +enum ePedVoiceType : std::uint16_t { PED_TYPE_GEN, PED_TYPE_EMG, PED_TYPE_PLAYER, PED_TYPE_GANG, - PED_TYPE_GFD + PED_TYPE_GFD, + PED_TYPE_SPC }; #define NUM_GEN_VOICES 209 @@ -50,16 +56,68 @@ typedef struct char szName[20]; } SPedVoiceName; -class CPedSoundSAInterface +// CAEPedSpeechAudioEntity +class CPedSoundSAInterface : public CAEAudioEntity +{ +public: + CAESound* sounds[5]; + bool isInitialised; + ePedVoiceType m_sVoiceType; + std::uint16_t m_sVoiceID; + std::uint16_t m_bIsFemale; + bool m_bTalking; + bool m_bDisabled; + bool m_bDisabledSpeechForScripts; + bool m_bIsFrontend; + bool m_bIsForcedAudible; + CAESound* m_sound; + std::int16_t m_soundId; + std::int16_t m_bankId; + std::int16_t m_pedSpeechSlotIndex; + float m_fVoiceVolume; + std::int16_t m_sPhraseId; + std::uint32_t m_nextTimeCanSay[19]; +}; +static_assert(sizeof(CPedSoundSAInterface) == 0x100, "Invalid size for CPedSoundSAInterface"); + +// CAEPedAudioEntity +class CPedSoundEntitySAInterface : public CAEAudioEntity +{ +public: + bool canAddEvent; + + std::uint8_t field_7D; + std::int16_t sfxId; + std::uint32_t timeInMS; + + float volume1; + float volume2; + float volume3; + float jetpackSoundSpeedMult; + + CPedSAInterface* ped; + + bool jetpackSoundPlaying; + CAESound* jetpackSound1; + CAESound* jetpackSound2; + CAESound* jetpackSound3; + + CAETwinLoopSoundEntity twinLoopSoundEntity; + CAESound* field_150; + + std::uint8_t field_154[4]; + std::uint8_t field_158[4]; +}; +static_assert(sizeof(CPedSoundEntitySAInterface) == 0x15C, "Invalid size for CPedSoundEntitySAInterface"); + +// CAEPedWeaponAudioEntity +class CPedWeaponAudioEntitySAInterface : public CAEWeaponAudioEntitySAInterface { public: - BYTE ucPad1[0x92]; - short m_sVoiceType; - short m_sVoiceID; - short m_bIsFemale; - BYTE ucPad2[1]; - bool m_bDisabled; + bool m_bIsInitialised; + CPedSAInterface* m_ped; }; +static_assert(sizeof(CPedWeaponAudioEntitySAInterface) == 0xA8, "Invalid size for CPedWeaponAudioEntitySAInterface"); class CPedSoundSA : public CPedSound { diff --git a/Client/game_sa/CWeaponSA.cpp b/Client/game_sa/CWeaponSA.cpp index e36697170f3..d0fcc3785f1 100644 --- a/Client/game_sa/CWeaponSA.cpp +++ b/Client/game_sa/CWeaponSA.cpp @@ -134,7 +134,7 @@ bool CWeaponSA::FireBullet(CEntity* firingEntity, const CVector& vecOrigin, cons // Fire sound if (firingPlayerPed) - firingPlayerPed->AddWeaponAudioEvent(EPedWeaponAudioEvent::FIRE); + firingPlayerPed->AddWeaponAudioEvent(EPedWeaponAudioEventType::FIRE); // Do post shot lag compensation reset & script events if (pGame->m_pPostWeaponFireHandler && firingPlayerPed) diff --git a/Client/sdk/game/CPed.h b/Client/sdk/game/CPed.h index 03c81d64c71..3c3c8459660 100644 --- a/Client/sdk/game/CPed.h +++ b/Client/sdk/game/CPed.h @@ -1,23 +1,23 @@ /***************************************************************************** * - * PROJECT: Multi Theft Auto v1.0 + * PROJECT: Multi Theft Auto * LICENSE: See LICENSE in the top level directory * FILE: sdk/game/CPed.h * PURPOSE: Ped entity interface * - * Multi Theft Auto is available from http://www.multitheftauto.com/ + * Multi Theft Auto is available from https://www.multitheftauto.com/ * *****************************************************************************/ #pragma once - -#include -#include "Common.h" #include "CPhysical.h" #include "CWeaponInfo.h" #include "CPedSound.h" -class CObject; +// To avoid VS intellisense highlight errors +#include +#include + class CPedIK; class CPedIKSAInterface; class CPedIntelligence; @@ -92,7 +92,7 @@ enum ATTACH_DIRECTION_RIGHT }; -enum eFightingStyle +enum eFightingStyle : std::uint8_t { STYLE_STANDARD = 4, STYLE_BOXING, @@ -152,139 +152,157 @@ enum eLandedPedFoot LANDED_PED_LEFT_FOOT = 1, }; -inline bool IsValidMoveAnim(uint iMoveAnim) -{ - return (iMoveAnim == MOVE_DEFAULT) || (iMoveAnim >= MOVE_PLAYER && iMoveAnim <= MOVE_JETPACK) || (iMoveAnim >= MOVE_MAN && iMoveAnim <= MOVE_SKATE); -} - -enum +enum ePedEntityType { PLAYER_PED, CIVILIAN_PED }; -namespace EPedWeaponAudioEvent +enum class EPedWeaponAudioEventType { - enum EPedWeaponAudioEventType - { - FIRE = 0x91, - }; -} -using EPedWeaponAudioEvent::EPedWeaponAudioEventType; + FIRE = 0x91, + RELOAD_A = 0x92, + RELOAD_B = 0x93, + FIRE_MINIGUN_AMMO = 0x96, + FIRE_MINIGUN_NO_AMMO = 0x97, + CHAINSAW_IDLE = 0x99, + CHAINSAW_ACTIVE = 0x9A, + CHAINSAW_CUTTING = 0x9B, + STEALTH_KILL = 0x9C, +}; struct SSatchelsData { CProjectileSAInterface* pProjectileInterface; CVector* vecAttachedOffsets; CVector* vecAttachedRotation; + + SSatchelsData(CProjectileSAInterface* proj, CVector* offset, CVector* rotation) : pProjectileInterface(proj), vecAttachedOffsets(offset), vecAttachedRotation(rotation) {} }; +inline bool IsValidMoveAnim(std::uint32_t iMoveAnim) noexcept +{ + return (iMoveAnim == MOVE_DEFAULT) || (iMoveAnim >= MOVE_PLAYER && iMoveAnim <= MOVE_JETPACK) || (iMoveAnim >= MOVE_MAN && iMoveAnim <= MOVE_SKATE); +} + class CPed : public virtual CPhysical { public: virtual ~CPed(){}; - virtual class CPedSAInterface* GetPedInterface() = 0; + virtual class CPedSAInterface* GetPedInterface() noexcept = 0; + + virtual void SetModelIndex(std::uint32_t modelIndex) = 0; virtual void DetachPedFromEntity() = 0; - virtual CVehicle* GetVehicle() = 0; - virtual void Respawn(CVector* position, bool bCameraCut) = 0; - - virtual void SetModelIndex(unsigned long ulModel) = 0; - - virtual float GetHealth() = 0; - virtual void SetHealth(float fHealth) = 0; - virtual float GetArmor() = 0; - virtual void SetArmor(float armor) = 0; - virtual float GetOxygenLevel() = 0; - virtual void SetOxygenLevel(float fOxygen) = 0; - virtual bool AddProjectile(eWeaponType eWeapon, CVector vecOrigin, float fForce, CVector* target, CEntity* targetEntity) = 0; - virtual CWeapon* GiveWeapon(eWeaponType weaponType, unsigned int uiAmmo, eWeaponSkill weaponSkill) = 0; - virtual CWeapon* GetWeapon(eWeaponSlot weaponSlot) = 0; - virtual CWeapon* GetWeapon(eWeaponType weaponType) = 0; + virtual CVehicle* GetVehicle() const = 0; + + virtual void Respawn(CVector* position, bool cameraCut) = 0; + + virtual float GetHealth() const = 0; + virtual void SetHealth(float health) = 0; + + virtual float GetArmor() const = 0; + virtual void SetArmor(float armor) = 0; + + virtual float GetOxygenLevel() const = 0; + virtual void SetOxygenLevel(float oxygen) = 0; + + virtual bool AddProjectile(eWeaponType weaponType, CVector origin, float force, CVector* target, CEntity* targetEntity) = 0; + virtual CWeapon* GiveWeapon(eWeaponType weaponType, std::uint32_t ammo, eWeaponSkill weaponSkill) = 0; + virtual CWeapon* GetWeapon(eWeaponSlot weaponSlot) const noexcept = 0; + virtual CWeapon* GetWeapon(eWeaponType weaponType) const = 0; virtual void ClearWeapons() = 0; - virtual void RemoveWeaponModel(int iModel) = 0; + virtual void RemoveWeaponModel(std::uint32_t model) = 0; virtual void ClearWeapon(eWeaponType weaponType) = 0; - virtual void SetIsStanding(bool bStanding) = 0; - virtual DWORD GetType() = 0; - virtual CPedIntelligence* GetPedIntelligence() = 0; - virtual CPedSound* GetPedSound() = 0; + virtual void SetIsStanding(bool standing) = 0; + + virtual std::uint32_t GetType() const noexcept = 0; + virtual CPedIntelligence* GetPedIntelligence() const noexcept = 0; + virtual CPedSound* GetPedSound() const noexcept = 0; - virtual float GetCurrentRotation() = 0; - virtual float GetTargetRotation() = 0; - virtual void SetCurrentRotation(float fRotation) = 0; - virtual void SetTargetRotation(float fRotation) = 0; - virtual eWeaponSlot GetCurrentWeaponSlot() = 0; + virtual float GetCurrentRotation() const = 0; + virtual float GetTargetRotation() const = 0; + virtual void SetCurrentRotation(float rotation) = 0; + virtual void SetTargetRotation(float rotation) = 0; + + virtual eWeaponSlot GetCurrentWeaponSlot() const = 0; virtual void SetCurrentWeaponSlot(eWeaponSlot weaponSlot) = 0; - virtual CVector* GetBonePosition(eBone bone, CVector* vecPosition) = 0; - virtual CVector* GetTransformedBonePosition(eBone bone, CVector* vecPosition) = 0; + virtual CVector* GetBonePosition(eBone bone, CVector* position) = 0; + virtual CVector* GetTransformedBonePosition(eBone bone, CVector* position) = 0; + + virtual bool IsDucking() const = 0; + virtual void SetDucking(bool duck) = 0; - virtual bool IsDucking() = 0; - virtual void SetDucking(bool bDuck) = 0; - virtual bool IsInWater() = 0; - virtual int GetCantBeKnockedOffBike() = 0; - virtual void SetCantBeKnockedOffBike(int iCantBeKnockedOffBike) = 0; - virtual void QuitEnteringCar(CVehicle* vehicle, int iSeat, bool bUnknown) = 0; + virtual bool IsInWater() const = 0; - virtual void SetBleeding(bool bBleeding) = 0; + virtual std::uint32_t GetCantBeKnockedOffBike() const = 0; + virtual void SetCantBeKnockedOffBike(std::uint32_t cantBeKnockedOffBike) = 0; - virtual bool IsWearingGoggles() = 0; - virtual void SetGogglesState(bool bIsWearingThem) = 0; + virtual bool IsWearingGoggles() const = 0; + virtual void SetGogglesState(bool isWearingThem) = 0; - virtual void SetClothesTextureAndModel(const char* szModel, const char* szModelLocationName, int iTexture) = 0; + virtual void SetClothesTextureAndModel(const char* texture, const char* model, int textureType) = 0; virtual void RebuildPlayer() = 0; - virtual eFightingStyle GetFightingStyle() = 0; - virtual void SetFightingStyle(eFightingStyle style, BYTE bStyleExtra) = 0; + virtual eFightingStyle GetFightingStyle() const = 0; + virtual void SetFightingStyle(eFightingStyle style, std::uint8_t styleExtra) = 0; - virtual CEntity* GetContactEntity() = 0; + virtual CEntity* GetContactEntity() const = 0; - virtual unsigned char GetRunState() = 0; + virtual int GetRunState() const = 0; - virtual CEntity* GetTargetedEntity() = 0; - virtual void SetTargetedEntity(CEntity* pEntity) = 0; + virtual CEntity* GetTargetedEntity() const = 0; + virtual void SetTargetedEntity(CEntity* targetEntity) = 0; - virtual bool GetCanBeShotInVehicle() = 0; - virtual bool GetTestForShotInVehicle() = 0; + virtual bool GetCanBeShotInVehicle() const = 0; + virtual bool GetTestForShotInVehicle() const = 0; - virtual void SetCanBeShotInVehicle(bool bShot) = 0; - virtual void SetTestForShotInVehicle(bool bTest) = 0; + virtual void SetCanBeShotInVehicle(bool shot) = 0; + virtual void SetTestForShotInVehicle(bool test) = 0; - virtual BYTE GetOccupiedSeat() = 0; - virtual void SetOccupiedSeat(BYTE seat) = 0; + virtual std::uint8_t GetOccupiedSeat() const noexcept = 0; + virtual void SetOccupiedSeat(std::uint8_t seat) noexcept = 0; - virtual void RemoveBodyPart(int i, char c) = 0; + virtual void RemoveBodyPart(std::uint8_t boneID, std::uint8_t direction) = 0; - virtual void SetFootBlood(unsigned int uiFootBlood) = 0; - virtual unsigned int GetFootBlood() = 0; + virtual void SetFootBlood(std::uint32_t footBlood) = 0; + virtual std::uint32_t GetFootBlood() const = 0; - virtual bool GetStayInSamePlace() = 0; - virtual void SetStayInSamePlace(bool bStay) = 0; + virtual bool IsBleeding() const = 0; + virtual void SetBleeding(bool bleeding) = 0; - virtual void GetVoice(short* psVoiceType, short* psVoiceID) = 0; - virtual void GetVoice(const char** pszVoiceType, const char** pszVoice) = 0; - virtual void SetVoice(short sVoiceType, short sVoiceID) = 0; - virtual void SetVoice(const char* szVoiceType, const char* szVoice) = 0; + virtual bool IsOnFire() const = 0; + virtual bool SetOnFire(bool onFire) = 0; + + virtual bool GetStayInSamePlace() const = 0; + virtual void SetStayInSamePlace(bool stay) = 0; + + virtual void GetVoice(std::int16_t* voiceType, std::int16_t* voiceID) const = 0; + virtual void GetVoice(const char** voiceType, const char** voice) const = 0; + virtual void SetVoice(std::int16_t voiceType, std::int16_t voiceID) = 0; + virtual void SetVoice(const char* voiceType, const char* voice) = 0; virtual void ResetVoice() = 0; - virtual void SetLanding(bool bIsLanding) = 0; + + virtual void SetLanding(bool isLanding) = 0; virtual void SetUpdateMetricsRequired(bool required) = 0; - virtual CWeaponStat* GetCurrentWeaponStat() = 0; - virtual float GetCurrentWeaponRange() = 0; + virtual CWeaponStat* GetCurrentWeaponStat() const = 0; + virtual float GetCurrentWeaponRange() const = 0; virtual void AddWeaponAudioEvent(EPedWeaponAudioEventType audioEventType) = 0; - virtual int GetCustomMoveAnim() = 0; - virtual bool IsDoingGangDriveby() = 0; + virtual int GetCustomMoveAnim() const noexcept = 0; + virtual bool IsDoingGangDriveby() const = 0; virtual CPedIKSAInterface* GetPedIKInterface() = 0; virtual void* GetPedNodeInterface(std::int32_t nodeId) = 0; virtual std::unique_ptr GetPedIK() = 0; - virtual CEntitySAInterface* GetTargetedObject() = 0; - virtual ePedState GetPedState() = 0; + virtual CEntitySAInterface* GetTargetedObject() const = 0; + virtual ePedState GetPedState() const = 0; virtual void GetAttachedSatchels(std::vector &satchelsList) const = 0; diff --git a/Client/sdk/game/CWeaponInfo.h b/Client/sdk/game/CWeaponInfo.h index edd308663b7..16567a0b64a 100644 --- a/Client/sdk/game/CWeaponInfo.h +++ b/Client/sdk/game/CWeaponInfo.h @@ -15,7 +15,7 @@ class CVector; -enum eWeaponSkill +enum eWeaponSkill : std::uint8_t { WEAPONSKILL_POOR = 0, WEAPONSKILL_STD,