diff --git a/Client/game_sa/CFxManagerSA.cpp b/Client/game_sa/CFxManagerSA.cpp index 9a0e89dce67..afd5b34c379 100644 --- a/Client/game_sa/CFxManagerSA.cpp +++ b/Client/game_sa/CFxManagerSA.cpp @@ -67,6 +67,18 @@ void CFxManagerSA::OnFxSystemSAInterfaceDestroyed(CFxSystemSAInterface* pFxSyste delete pFxSystemSA; } +CFxSystemBPSAInterface* CFxManagerSA::GetFxSystemBlueprintByName(SString sName) +{ + using func_t = CFxSystemBPSAInterface*(__thiscall*)(CFxManagerSAInterface * pInterface, const char* pChars); + auto func = reinterpret_cast(FUNC_FxManager_c__GetSystemByName); + return func(m_pInterface, sName); +} + +bool CFxManagerSA::IsValidFxSystemBlueprintName(SString sName) +{ + return GetFxSystemBlueprintByName(sName) != nullptr; +} + // // AddToList/RemoveFromList called from CFxSystemSA constructor/destructor // diff --git a/Client/game_sa/CFxManagerSA.h b/Client/game_sa/CFxManagerSA.h index b998372f6d2..c7b5d677951 100644 --- a/Client/game_sa/CFxManagerSA.h +++ b/Client/game_sa/CFxManagerSA.h @@ -14,6 +14,7 @@ #define FUNC_FxManager_c__CreateFxSystem 0x4A9BE0 #define FUNC_FxManager_c__DestroyFxSystem 0x4A9810 +#define FUNC_FxManager_c__GetSystemByName 0x4A9360 class CFxSystemBPSAInterface; class CFxSystemSAInterface; @@ -61,10 +62,12 @@ class CFxManagerSA : public CFxManager public: CFxManagerSA(CFxManagerSAInterface* pInterface) { m_pInterface = pInterface; } // CFxManager interface - CFxSystem* CreateFxSystem(const char* szBlueprint, const CVector& vecPosition, RwMatrix* pRwMatrixTag, unsigned char bSkipCameraFrustumCheck, - bool bSoundEnable); - void DestroyFxSystem(CFxSystem* pFxSystem); - void OnFxSystemSAInterfaceDestroyed(CFxSystemSAInterface* pFxSystemSAInterface); + CFxSystem* CreateFxSystem(const char* szBlueprint, const CVector& vecPosition, RwMatrix* pRwMatrixTag, unsigned char bSkipCameraFrustumCheck, + bool bSoundEnable); + void DestroyFxSystem(CFxSystem* pFxSystem); + void OnFxSystemSAInterfaceDestroyed(CFxSystemSAInterface* pFxSystemSAInterface); + CFxSystemBPSAInterface* GetFxSystemBlueprintByName(SString sName); + bool IsValidFxSystemBlueprintName(SString sName); // CFxManagerSA methods CFxSystemSA* GetFxSystem(CFxSystemSAInterface* pFxSystemSAInterface); diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 5b8c4e833fd..e65437ecda3 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -65,6 +65,12 @@ CGameSA::CGameSA() ModelInfo[i].SetModelID(i); } + // Prepare all object dynamic infos for CObjectGroupPhysicalPropertiesSA instances + for (int i = 0; i < OBJECTDYNAMICINFO_MAX; i++) + { + ObjectGroupsInfo[i].SetGroup(i); + } + DEBUG_TRACE("CGameSA::CGameSA()"); this->m_pAudioEngine = new CAudioEngineSA((CAudioEngineSAInterface*)CLASS_CAudioEngine); this->m_pAEAudioHardware = new CAEAudioHardwareSA((CAEAudioHardwareSAInterface*)CLASS_CAEAudioHardware); @@ -464,6 +470,9 @@ void CGameSA::Reset() // Restore model dummies' positions CModelInfoSA::ResetAllVehicleDummies(); + CModelInfoSA::RestoreAllObjectsPropertiesGroups(); + // restore default properties of all CObjectGroupPhysicalPropertiesSA instances + CObjectGroupPhysicalPropertiesSA::RestoreDefaultValues(); } } @@ -862,3 +871,12 @@ CPed* CGameSA::GetPedContext() m_pPedContext = pGame->GetPools()->GetPedFromRef((DWORD)1); return m_pPedContext; } + +CObjectGroupPhysicalProperties* CGameSA::GetObjectGroupPhysicalProperties(unsigned char ucObjectGroup) +{ + DEBUG_TRACE("CObjectGroupPhysicalProperties * CGameSA::GetObjectGroupPhysicalProperties(unsigned char ucObjectGroup)"); + if (ucObjectGroup < OBJECTDYNAMICINFO_MAX && ObjectGroupsInfo[ucObjectGroup].IsValid()) + return &ObjectGroupsInfo[ucObjectGroup]; + + return nullptr; +} diff --git a/Client/game_sa/CGameSA.h b/Client/game_sa/CGameSA.h index 06e1ce65d86..592c0fa3285 100644 --- a/Client/game_sa/CGameSA.h +++ b/Client/game_sa/CGameSA.h @@ -12,6 +12,7 @@ #pragma once #include "CModelInfoSA.h" +#include "CObjectGroupPhysicalPropertiesSA.h" #include "CFxManagerSA.h" #define MAX_MEMORY_OFFSET_1_0 0xCAF008 @@ -33,6 +34,7 @@ #define NUM_WeaponInfosTotal (NUM_WeaponInfosStdSkill + (3*NUM_WeaponInfosOtherSkill)) // std, (poor, pro, special) #define MODELINFO_MAX 26000 // Actual max is 25755 +#define OBJECTDYNAMICINFO_MAX 160 #define FUNC_GetLevelFromPosition 0x4DD300 @@ -103,6 +105,7 @@ class CGameSA : public CGame private: CWeaponInfo* WeaponInfos[NUM_WeaponInfosTotal]; CModelInfoSA ModelInfo[MODELINFO_MAX]; + CObjectGroupPhysicalPropertiesSA ObjectGroupsInfo[OBJECTDYNAMICINFO_MAX]; public: ZERO_ON_NEW @@ -305,8 +308,9 @@ class CGameSA : public CGame CRenderWareSA* GetRenderWareSA() { return m_pRenderWare; } CFxManagerSA* GetFxManagerSA() { return m_pFxManager; } - CWeaponInfo* GetWeaponInfo(eWeaponType weapon, eWeaponSkill skill = WEAPONSKILL_STD); - CModelInfo* GetModelInfo(DWORD dwModelID); + CWeaponInfo* GetWeaponInfo(eWeaponType weapon, eWeaponSkill skill = WEAPONSKILL_STD); + CModelInfo* GetModelInfo(DWORD dwModelID); + CObjectGroupPhysicalProperties* GetObjectGroupPhysicalProperties(unsigned char ucObjectGroup); DWORD GetSystemTime() { @@ -429,39 +433,40 @@ class CGameSA : public CGame TaskSimpleBeHitHandler* m_pTaskSimpleBeHitHandler; private: - CPools* m_pPools; - CPlayerInfo* m_pPlayerInfo; - CProjectileInfo* m_pProjectileInfo; - CRadar* m_pRadar; - CRestart* m_pRestart; - CClock* m_pClock; - CCoronas* m_pCoronas; - CCheckpoints* m_pCheckpoints; - CEventList* m_pEventList; - CFireManager* m_pFireManager; - CGarages* m_pGarages; - CHud* m_pHud; - CWanted* m_pWanted; - CWeather* m_pWeather; - CWorld* m_pWorld; - CCamera* m_pCamera; - CModelInfo* m_pModelInfo; - CPickups* m_pPickups; - CWeaponInfo* m_pWeaponInfo; - CExplosionManager* m_pExplosionManager; - C3DMarkers* m_p3DMarkers; - CRenderWareSA* m_pRenderWare; - CHandlingManager* m_pHandlingManager; - CAnimManager* m_pAnimManager; - CStreaming* m_pStreaming; - CVisibilityPlugins* m_pVisibilityPlugins; - CKeyGen* m_pKeyGen; - CRopes* m_pRopes; - CFx* m_pFx; - CFxManagerSA* m_pFxManager; - CWaterManager* m_pWaterManager; - CWeaponStatManager* m_pWeaponStatsManager; - CPointLights* m_pPointLights; + CPools* m_pPools; + CPlayerInfo* m_pPlayerInfo; + CProjectileInfo* m_pProjectileInfo; + CRadar* m_pRadar; + CRestart* m_pRestart; + CClock* m_pClock; + CCoronas* m_pCoronas; + CCheckpoints* m_pCheckpoints; + CEventList* m_pEventList; + CFireManager* m_pFireManager; + CGarages* m_pGarages; + CHud* m_pHud; + CWanted* m_pWanted; + CWeather* m_pWeather; + CWorld* m_pWorld; + CCamera* m_pCamera; + CModelInfo* m_pModelInfo; + CPickups* m_pPickups; + CWeaponInfo* m_pWeaponInfo; + CExplosionManager* m_pExplosionManager; + C3DMarkers* m_p3DMarkers; + CRenderWareSA* m_pRenderWare; + CHandlingManager* m_pHandlingManager; + CAnimManager* m_pAnimManager; + CStreaming* m_pStreaming; + CVisibilityPlugins* m_pVisibilityPlugins; + CKeyGen* m_pKeyGen; + CRopes* m_pRopes; + CFx* m_pFx; + CFxManagerSA* m_pFxManager; + CWaterManager* m_pWaterManager; + CWeaponStatManager* m_pWeaponStatsManager; + CPointLights* m_pPointLights; + CObjectGroupPhysicalProperties* m_pObjectGroupPhysicalProperties; CPad* m_pPad; CTheCarGenerators* m_pTheCarGenerators; diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index a6241e1d976..4127ed60b05 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -20,6 +20,7 @@ std::map std::map CModelInfoSA::ms_ModelDefaultLodDistanceMap; std::map CModelInfoSA::ms_ModelDefaultAlphaTransparencyMap; std::unordered_map> CModelInfoSA::ms_ModelDefaultDummiesPosition; +std::unordered_map CModelInfoSA::ms_OriginalObjectPropertiesGroups; CModelInfoSA::CModelInfoSA() { @@ -1373,6 +1374,46 @@ void CModelInfoSA::ResetSupportedUpgrades() m_ModelSupportedUpgrades.Reset(); } +void CModelInfoSA::SetObjectPropertiesGroup(unsigned short usNewGroup) +{ + unsigned short usOrgGroup = GetObjectPropertiesGroup(); + if (usOrgGroup == usNewGroup) + return; + + if (!MapFind(ms_OriginalObjectPropertiesGroups, m_dwModelID)) + MapSet(ms_OriginalObjectPropertiesGroups, m_dwModelID, usOrgGroup); + + GetInterface()->usDynamicIndex = usNewGroup; +} + +unsigned short CModelInfoSA::GetObjectPropertiesGroup() +{ + unsigned short usGroup = GetInterface()->usDynamicIndex; + if (usGroup == 0xFFFF) + usGroup = 0; + + return usGroup; +} + +void CModelInfoSA::RestoreObjectPropertiesGroup() +{ + unsigned short* usGroupInMap = MapFind(ms_OriginalObjectPropertiesGroups, m_dwModelID); + if (usGroupInMap) + { + GetInterface()->usDynamicIndex = *usGroupInMap; + MapRemove(ms_OriginalObjectPropertiesGroups, m_dwModelID); + } +} + +void CModelInfoSA::RestoreAllObjectsPropertiesGroups() +{ + for (const auto& pair : ms_OriginalObjectPropertiesGroups) + { + pGame->GetModelInfo(pair.first)->GetInterface()->usDynamicIndex = pair.second; + } + ms_OriginalObjectPropertiesGroups.clear(); +} + eModelInfoType CModelInfoSA::GetModelType() { return ((eModelInfoType(*)())m_pInterface->VFTBL->GetModelType)(); diff --git a/Client/game_sa/CModelInfoSA.h b/Client/game_sa/CModelInfoSA.h index 41dcd27e855..b7b024d14ed 100644 --- a/Client/game_sa/CModelInfoSA.h +++ b/Client/game_sa/CModelInfoSA.h @@ -139,16 +139,7 @@ class CBaseModelInfoSAInterface unsigned char ucNumOf2DEffects : 8; // +13 unsigned short usUnknown : 16; // +14 Something with 2d effects - unsigned char ucDynamicIndex : 8; // +16 - - unsigned char dwUnknownFlag9 : 1; // +17 - unsigned char dwUnknownFlag10 : 1; - unsigned char dwUnknownFlag11 : 1; - unsigned char dwUnknownFlag12 : 1; - unsigned char dwUnknownFlag13 : 1; - unsigned char dwUnknownFlag14 : 1; - unsigned char dwUnknownFlag15 : 1; - unsigned char dwUnknownFlag16 : 1; + unsigned short usDynamicIndex : 16; // +16 // Flags used by CBaseModelInfo unsigned char bHasBeenPreRendered : 1; // +18 @@ -277,6 +268,7 @@ class CModelInfoSA : public CModelInfo static std::map ms_ModelDefaultLodDistanceMap; static std::map ms_ModelDefaultAlphaTransparencyMap; static std::unordered_map> ms_ModelDefaultDummiesPosition; + static std::unordered_map ms_OriginalObjectPropertiesGroups; bool m_bAddedRefForCollision; SVehicleSupportedUpgrades m_ModelSupportedUpgrades; @@ -375,6 +367,11 @@ class CModelInfoSA : public CModelInfo void InitialiseSupportedUpgrades(RpClump* pClump); void ResetSupportedUpgrades(); + void SetObjectPropertiesGroup(unsigned short usObjectGroup); + unsigned short GetObjectPropertiesGroup(); + void RestoreObjectPropertiesGroup(); + static void RestoreAllObjectsPropertiesGroups(); + private: void RwSetSupportedUpgrades(RwFrame* parent, DWORD dwModel); }; diff --git a/Client/game_sa/CObjectGroupPhysicalPropertiesSA.cpp b/Client/game_sa/CObjectGroupPhysicalPropertiesSA.cpp new file mode 100644 index 00000000000..02b75764c29 --- /dev/null +++ b/Client/game_sa/CObjectGroupPhysicalPropertiesSA.cpp @@ -0,0 +1,368 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CObjectGroupPhysicalPropertiesSA.cpp + * PURPOSE: Objects dynamic physical properties handler class + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#include "CObjectGroupPhysicalPropertiesSA.h" +extern CGameSA* pGame; + +CObjectGroupPhysicalPropertiesSAInterface* pObjectInfo = (CObjectGroupPhysicalPropertiesSAInterface*)ARRAY_ObjectGroupsDynamicInfo; +std::unordered_map> CObjectGroupPhysicalPropertiesSA::ms_OriginalGroupProperties; + +CObjectGroupPhysicalPropertiesSA::CObjectGroupPhysicalPropertiesSA() : m_pInterface(nullptr) +{} + +CObjectGroupPhysicalPropertiesSA::CObjectGroupPhysicalPropertiesSA(unsigned char ucObjectGroup) : m_ucObjectGroup(ucObjectGroup) +{ + m_pInterface = &pObjectInfo[ucObjectGroup]; + m_bModified = MapFind(ms_OriginalGroupProperties, ucObjectGroup); +} + +CObjectGroupPhysicalPropertiesSAInterface* CObjectGroupPhysicalPropertiesSA::GetInterface() const +{ + return m_pInterface; +} + +void CObjectGroupPhysicalPropertiesSA::SetGroup(unsigned char ucObjectGroup) +{ + m_pInterface = &pObjectInfo[ucObjectGroup]; + m_ucObjectGroup = ucObjectGroup; + m_bModified = MapFind(ms_OriginalGroupProperties, ucObjectGroup); +} + +unsigned char CObjectGroupPhysicalPropertiesSA::GetGroup() const +{ + return m_ucObjectGroup; +} + +bool CObjectGroupPhysicalPropertiesSA::IsValid() const +{ + return m_pInterface != nullptr; +} + +void CObjectGroupPhysicalPropertiesSA::ChangeSafeguard() +{ + if (m_bModified) + return; + + m_bModified = true; + // Make copy of original + if (!MapFind(ms_OriginalGroupProperties, m_ucObjectGroup)) + { + auto pOriginalCopy = std::make_unique(); + memcpy(pOriginalCopy.get(), m_pInterface, sizeof(CObjectGroupPhysicalPropertiesSAInterface)); + ms_OriginalGroupProperties[m_ucObjectGroup] = std::move(pOriginalCopy); + } +} + +void CObjectGroupPhysicalPropertiesSA::RestoreDefault() +{ + if (!m_bModified) + return; + + auto ppOriginalCopy = MapFind(ms_OriginalGroupProperties, m_ucObjectGroup); + dassert(ppOriginalCopy); + if (!ppOriginalCopy) + return; + + dassert(ppOriginalCopy->get()); + if (!ppOriginalCopy->get()) + return; + + memcpy(m_pInterface, ppOriginalCopy->get(), sizeof(CObjectGroupPhysicalPropertiesSAInterface)); + m_bModified = false; +} + +void CObjectGroupPhysicalPropertiesSA::RestoreDefaultValues() +{ + for (auto& entry : ms_OriginalGroupProperties) + { + pGame->GetObjectGroupPhysicalProperties(entry.first)->RestoreDefault(); + entry.second.reset(); + MapRemove(ms_OriginalGroupProperties, entry.first); + } +} + +void CObjectGroupPhysicalPropertiesSA::SetMass(float fMass) +{ + if (fabs(m_pInterface->fMass - fMass) < FLOAT_EPSILON) + return; + + ChangeSafeguard(); + m_pInterface->fMass = fMass; +} + +float CObjectGroupPhysicalPropertiesSA::GetMass() const +{ + return m_pInterface->fMass; +} + +void CObjectGroupPhysicalPropertiesSA::SetTurnMass(float fTurnMass) +{ + if (fabs(m_pInterface->fTurnMass - fTurnMass) < FLOAT_EPSILON) + return; + + ChangeSafeguard(); + m_pInterface->fTurnMass = fTurnMass; +} + +float CObjectGroupPhysicalPropertiesSA::GetTurnMass() const +{ + return m_pInterface->fTurnMass; +} + +void CObjectGroupPhysicalPropertiesSA::SetAirResistance(float fAirResistance) +{ + if (fabs(m_pInterface->fAirResistance - fAirResistance) < FLOAT_EPSILON) + return; + + ChangeSafeguard(); + m_pInterface->fAirResistance = fAirResistance; +} + +float CObjectGroupPhysicalPropertiesSA::GetAirResistance() const +{ + return m_pInterface->fAirResistance; +} + +void CObjectGroupPhysicalPropertiesSA::SetElasticity(float fElasticity) +{ + if (fabs(m_pInterface->fElasticity - fElasticity) < FLOAT_EPSILON) + return; + + ChangeSafeguard(); + m_pInterface->fElasticity = fElasticity; +} + +float CObjectGroupPhysicalPropertiesSA::GetElasticity() const +{ + return m_pInterface->fElasticity; +} + +void CObjectGroupPhysicalPropertiesSA::SetBuoyancy(float fBuoyancy) +{ + if (fabs(m_pInterface->fBuoyancy - fBuoyancy) < FLOAT_EPSILON) + return; + + ChangeSafeguard(); + m_pInterface->fBuoyancy = fBuoyancy; +} + +float CObjectGroupPhysicalPropertiesSA::GetBuoyancy() const +{ + return m_pInterface->fBuoyancy; +} + +void CObjectGroupPhysicalPropertiesSA::SetUprootLimit(float fUprootLimit) +{ + if (fabs(m_pInterface->fUprootLimit - fUprootLimit) < FLOAT_EPSILON) + return; + + ChangeSafeguard(); + m_pInterface->fUprootLimit = fUprootLimit; +} + +float CObjectGroupPhysicalPropertiesSA::GetUprootLimit() const +{ + return m_pInterface->fUprootLimit; +} + +void CObjectGroupPhysicalPropertiesSA::SetCollisionDamageMultiplier(float fColMult) +{ + if (fabs(m_pInterface->fColDamageMultiplier - fColMult) < FLOAT_EPSILON) + return; + + ChangeSafeguard(); + m_pInterface->fColDamageMultiplier = fColMult; +} + +float CObjectGroupPhysicalPropertiesSA::GetCollisionDamageMultiplier() const +{ + return m_pInterface->fColDamageMultiplier; +} + +void CObjectGroupPhysicalPropertiesSA::SetCollisionDamageEffect(eObjectGroup::DamageEffect eDamageEffect) +{ + if (static_cast(m_pInterface->eColDamageEffect) == eDamageEffect) + return; + + ChangeSafeguard(); + m_pInterface->eColDamageEffect = eDamageEffect; +} + +eObjectGroup::DamageEffect CObjectGroupPhysicalPropertiesSA::GetCollisionDamageEffect() const +{ + return static_cast(m_pInterface->eColDamageEffect); +} + +void CObjectGroupPhysicalPropertiesSA::SetCollisionSpecialResponseCase(eObjectGroup::CollisionResponse eResponseCase) +{ + if (static_cast(m_pInterface->eSpecialColResponse) == eResponseCase) + return; + + ChangeSafeguard(); + m_pInterface->eSpecialColResponse = eResponseCase; +} + +eObjectGroup::CollisionResponse CObjectGroupPhysicalPropertiesSA::GetCollisionSpecialResponseCase() const +{ + return static_cast(m_pInterface->eSpecialColResponse); +} + +void CObjectGroupPhysicalPropertiesSA::SetCameraAvoidObject(bool bAvoid) +{ + if (m_pInterface->bCameraAvoidObject == bAvoid) + return; + + ChangeSafeguard(); + m_pInterface->bCameraAvoidObject = bAvoid; +} + +bool CObjectGroupPhysicalPropertiesSA::GetCameraAvoidObject() const +{ + return m_pInterface->bCameraAvoidObject; +} + +void CObjectGroupPhysicalPropertiesSA::SetCausesExplosion(bool bExplodes) +{ + if (m_pInterface->bCausesExplosion == bExplodes) + return; + + ChangeSafeguard(); + m_pInterface->bCausesExplosion = bExplodes; +} + +bool CObjectGroupPhysicalPropertiesSA::GetCausesExplosion() const +{ + return m_pInterface->bCausesExplosion; +} + +void CObjectGroupPhysicalPropertiesSA::SetFxType(eObjectGroup::FxType eFxType) +{ + if (static_cast(m_pInterface->eFxType) == eFxType) + return; + + ChangeSafeguard(); + m_pInterface->eFxType = eFxType; +} + +eObjectGroup::FxType CObjectGroupPhysicalPropertiesSA::GetFxType() const +{ + return static_cast(m_pInterface->eFxType); +} + +void CObjectGroupPhysicalPropertiesSA::SetFxOffset(CVector vecOffset) +{ + if (m_pInterface->vecFxOffset == vecOffset) + return; + + ChangeSafeguard(); + m_pInterface->vecFxOffset = vecOffset; +} + +CVector CObjectGroupPhysicalPropertiesSA::GetFxOffset() const +{ + return m_pInterface->vecFxOffset; +} + +bool CObjectGroupPhysicalPropertiesSA::SetFxParticleSystem(CFxSystemBPSAInterface* pBlueprint) +{ + if (!pBlueprint) + return false; + + if (pBlueprint->cPlayMode != 0) + return false; + + if (m_pInterface->pFxSystemBlueprintPtr == pBlueprint) + return true; + + ChangeSafeguard(); + m_pInterface->pFxSystemBlueprintPtr = pBlueprint; + return true; +} + +void CObjectGroupPhysicalPropertiesSA::RemoveFxParticleSystem() +{ + if (!m_pInterface->pFxSystemBlueprintPtr) + return; + + ChangeSafeguard(); + m_pInterface->pFxSystemBlueprintPtr = nullptr; +} + +void CObjectGroupPhysicalPropertiesSA::SetSmashMultiplier(float fMult) +{ + if (fabs(m_pInterface->fSmashMultiplier - fMult) < FLOAT_EPSILON) + return; + + ChangeSafeguard(); + m_pInterface->fSmashMultiplier = fMult; +} + +float CObjectGroupPhysicalPropertiesSA::GetSmashMultiplier() const +{ + return m_pInterface->fSmashMultiplier; +} + +void CObjectGroupPhysicalPropertiesSA::SetBreakVelocity(CVector vecVelocity) +{ + if (m_pInterface->vecBreakVelocity == vecVelocity) + return; + + ChangeSafeguard(); + m_pInterface->vecBreakVelocity = vecVelocity; +} + +CVector CObjectGroupPhysicalPropertiesSA::GetBreakVelocity() const +{ + return m_pInterface->vecBreakVelocity; +} + +void CObjectGroupPhysicalPropertiesSA::SetBreakVelocityRandomness(float fRand) +{ + if (fabs(m_pInterface->fBreakVelocityRand - fRand) < FLOAT_EPSILON) + return; + + ChangeSafeguard(); + m_pInterface->fBreakVelocityRand = fRand; +} + +float CObjectGroupPhysicalPropertiesSA::GetBreakVelocityRandomness() const +{ + return m_pInterface->fBreakVelocityRand; +} + +void CObjectGroupPhysicalPropertiesSA::SetBreakMode(eObjectGroup::BreakMode eBreakMode) +{ + if (static_cast(m_pInterface->eBreakMode) == eBreakMode) + return; + + ChangeSafeguard(); + m_pInterface->eBreakMode = eBreakMode; +} + +eObjectGroup::BreakMode CObjectGroupPhysicalPropertiesSA::GetBreakMode() const +{ + return static_cast(m_pInterface->eBreakMode); +} + +void CObjectGroupPhysicalPropertiesSA::SetSparksOnImpact(bool bSparks) +{ + if (static_cast(m_pInterface->dwSparksOnImpact) == bSparks) + return; + + ChangeSafeguard(); + m_pInterface->dwSparksOnImpact = static_cast(bSparks); +} + +bool CObjectGroupPhysicalPropertiesSA::GetSparksOnImpact() const +{ + return static_cast(m_pInterface->dwSparksOnImpact); +} diff --git a/Client/game_sa/CObjectGroupPhysicalPropertiesSA.h b/Client/game_sa/CObjectGroupPhysicalPropertiesSA.h new file mode 100644 index 00000000000..0cd12b166fa --- /dev/null +++ b/Client/game_sa/CObjectGroupPhysicalPropertiesSA.h @@ -0,0 +1,102 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CObjectGroupPhysicalPropertiesSA.h + * PURPOSE: Header file for objects dynamic physical properties handler class + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +#include +#include + +#define ARRAY_ObjectGroupsDynamicInfo 0xBB4A90 + +class CObjectGroupPhysicalPropertiesSAInterface +{ +public: + float fMass; + float fTurnMass; + float fAirResistance; + float fElasticity; + float fBuoyancy; + float fUprootLimit; + float fColDamageMultiplier; + unsigned char eColDamageEffect; + unsigned char eSpecialColResponse; + bool bCameraAvoidObject; + bool bCausesExplosion; + unsigned char eFxType; + unsigned char pad[3]; + CVector vecFxOffset; + CFxSystemBPSAInterface* pFxSystemBlueprintPtr; + float fSmashMultiplier; + CVector vecBreakVelocity; + float fBreakVelocityRand; + DWORD eBreakMode; + DWORD dwSparksOnImpact; +}; + +class CObjectGroupPhysicalPropertiesSA : public CObjectGroupPhysicalProperties +{ +protected: + CObjectGroupPhysicalPropertiesSAInterface* m_pInterface; + unsigned char m_ucObjectGroup; + bool m_bModified; + static std::unordered_map> ms_OriginalGroupProperties; + +public: + CObjectGroupPhysicalPropertiesSA(); + CObjectGroupPhysicalPropertiesSA(unsigned char ucObjectGroup); + + CObjectGroupPhysicalPropertiesSAInterface* GetInterface() const; + void SetGroup(unsigned char ucObjectGroup); + unsigned char GetGroup() const; + bool IsValid() const; + void ChangeSafeguard(); + void RestoreDefault(); + static void RestoreDefaultValues(); + + void SetMass(float fMass); + float GetMass() const; + void SetTurnMass(float fTurnMass); + float GetTurnMass() const; + void SetAirResistance(float fAirResistance); + float GetAirResistance() const; + void SetElasticity(float fElasticity); + float GetElasticity() const; + void SetBuoyancy(float fBuoyancy); + float GetBuoyancy() const; + void SetUprootLimit(float fUprootLimit); + float GetUprootLimit() const; + void SetCollisionDamageMultiplier(float fColMult); + float GetCollisionDamageMultiplier() const; + void SetCollisionDamageEffect(eObjectGroup::DamageEffect ucDamageEffect); + eObjectGroup::DamageEffect GetCollisionDamageEffect() const; + void SetCollisionSpecialResponseCase(eObjectGroup::CollisionResponse ucResponseCase); + eObjectGroup::CollisionResponse GetCollisionSpecialResponseCase() const; + void SetCameraAvoidObject(bool bAvoid); + bool GetCameraAvoidObject() const; + void SetCausesExplosion(bool bExplodes); + bool GetCausesExplosion() const; + void SetFxType(eObjectGroup::FxType eFxType); + eObjectGroup::FxType GetFxType() const; + void SetFxOffset(CVector vecOffset); + CVector GetFxOffset() const; + bool SetFxParticleSystem(CFxSystemBPSAInterface* pBlueprint); + void RemoveFxParticleSystem(); + void SetSmashMultiplier(float fMult); + float GetSmashMultiplier() const; + void SetBreakVelocity(CVector vecVelocity); + CVector GetBreakVelocity() const; + void SetBreakVelocityRandomness(float fRand); + float GetBreakVelocityRandomness() const; + void SetBreakMode(eObjectGroup::BreakMode eBreakMode); + eObjectGroup::BreakMode GetBreakMode() const; + void SetSparksOnImpact(bool bSparks); + bool GetSparksOnImpact() const; +}; diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index d2f47f7f532..ebea4c893e1 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -380,6 +380,63 @@ ADD_ENUM(OBJECT_PROPERTY_CENTEROFMASS, "center_of_mass") ADD_ENUM(OBJECT_PROPERTY_BUOYANCY, "buoyancy") IMPLEMENT_ENUM_END("object-property") +IMPLEMENT_ENUM_BEGIN(eObjectGroup::Modifiable) +ADD_ENUM(eObjectGroup::Modifiable::MASS, "mass") +ADD_ENUM(eObjectGroup::Modifiable::TURNMASS, "turn_mass") +ADD_ENUM(eObjectGroup::Modifiable::AIRRESISTANCE, "air_resistance") +ADD_ENUM(eObjectGroup::Modifiable::ELASTICITY, "elasticity") +ADD_ENUM(eObjectGroup::Modifiable::BUOYANCY, "buoyancy") +ADD_ENUM(eObjectGroup::Modifiable::UPROOTLIMIT, "uproot_limit") +ADD_ENUM(eObjectGroup::Modifiable::COLDAMAGEMULTIPLIER, "col_damage_multiplier") +ADD_ENUM(eObjectGroup::Modifiable::COLDAMAGEEFFECT, "col_damage_effect") +ADD_ENUM(eObjectGroup::Modifiable::SPECIALCOLRESPONSE, "special_col_response") +ADD_ENUM(eObjectGroup::Modifiable::CAMERAAVOID, "avoid_camera") +ADD_ENUM(eObjectGroup::Modifiable::EXPLOSION, "cause_explosion") +ADD_ENUM(eObjectGroup::Modifiable::FXTYPE, "fx_type") +ADD_ENUM(eObjectGroup::Modifiable::FXOFFSET, "fx_offset") +ADD_ENUM(eObjectGroup::Modifiable::FXSYSTEM, "fx_system") +ADD_ENUM(eObjectGroup::Modifiable::SMASHMULTIPLIER, "smash_multiplier") +ADD_ENUM(eObjectGroup::Modifiable::BREAKVELOCITY, "break_velocity") +ADD_ENUM(eObjectGroup::Modifiable::BREAKVELOCITYRAND, "break_velocity_randomness") +ADD_ENUM(eObjectGroup::Modifiable::BREAKMODE, "break_mode") +ADD_ENUM(eObjectGroup::Modifiable::SPARKSONIMPACT, "sparks_on_impact") +IMPLEMENT_ENUM_END("objectgroup-modifiable") + +IMPLEMENT_ENUM_BEGIN(eObjectGroup::DamageEffect) +ADD_ENUM(eObjectGroup::DamageEffect::NO_EFFECT, "none") +ADD_ENUM(eObjectGroup::DamageEffect::CHANGE_MODEL, "change_model") +ADD_ENUM(eObjectGroup::DamageEffect::SMASH_COMPLETELY, "smash") +ADD_ENUM(eObjectGroup::DamageEffect::CHANGE_THEN_SMASH, "change_smash") +ADD_ENUM(eObjectGroup::DamageEffect::BREAKABLE, "breakable") +ADD_ENUM(eObjectGroup::DamageEffect::BREAKABLE_REMOVED, "breakable_remove") +IMPLEMENT_ENUM_END("objectgroup-damageeffect") + +IMPLEMENT_ENUM_BEGIN(eObjectGroup::CollisionResponse) +ADD_ENUM(eObjectGroup::CollisionResponse::NO_RESPONSE, "none") +ADD_ENUM(eObjectGroup::CollisionResponse::LAMPPOST, "lamppost") +ADD_ENUM(eObjectGroup::CollisionResponse::SMALLBOX, "small_box") +ADD_ENUM(eObjectGroup::CollisionResponse::BIGBOX, "big_box") +ADD_ENUM(eObjectGroup::CollisionResponse::FENCEPART, "fence_part") +ADD_ENUM(eObjectGroup::CollisionResponse::GRENADE, "grenade") +ADD_ENUM(eObjectGroup::CollisionResponse::SWINGDOOR, "swingdoor") +ADD_ENUM(eObjectGroup::CollisionResponse::LOCKDOOR, "lockdoor") +ADD_ENUM(eObjectGroup::CollisionResponse::HANGING, "hanging") +ADD_ENUM(eObjectGroup::CollisionResponse::POOLBALL, "poolball") +IMPLEMENT_ENUM_END("objectgroup-collisionresponse") + +IMPLEMENT_ENUM_BEGIN(eObjectGroup::FxType) +ADD_ENUM(eObjectGroup::FxType::NO_FX, "none") +ADD_ENUM(eObjectGroup::FxType::PLAY_ON_HIT, "play_on_hit") +ADD_ENUM(eObjectGroup::FxType::PLAY_ON_DESTROYED, "play_on_destroyed") +ADD_ENUM(eObjectGroup::FxType::PLAY_ON_HIT_DESTROYED, "play_on_hitdestroyed") +IMPLEMENT_ENUM_END("objectgroup-fxtype") + +IMPLEMENT_ENUM_BEGIN(eObjectGroup::BreakMode) +ADD_ENUM(eObjectGroup::BreakMode::NOT_BY_GUN, "not_by_gun") +ADD_ENUM(eObjectGroup::BreakMode::BY_GUN, "by_gun") +ADD_ENUM(eObjectGroup::BreakMode::SMASHABLE, "smashable") +IMPLEMENT_ENUM_END("objectgroup-breakmode") + IMPLEMENT_ENUM_BEGIN(eFontType) ADD_ENUM(FONT_DEFAULT, "default") ADD_ENUM(FONT_DEFAULT_BOLD, "default-bold") diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index 8a06da885b8..f79db756e3b 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -40,6 +40,11 @@ DECLARE_ENUM(eWeaponState); DECLARE_ENUM(eWeaponFlags); DECLARE_ENUM(eVehicleComponent); DECLARE_ENUM(eObjectProperty); +DECLARE_ENUM(eObjectGroup::Modifiable); +DECLARE_ENUM(eObjectGroup::DamageEffect); +DECLARE_ENUM(eObjectGroup::CollisionResponse); +DECLARE_ENUM(eObjectGroup::FxType); +DECLARE_ENUM(eObjectGroup::BreakMode); DECLARE_ENUM(eFontType); DECLARE_ENUM(eFontQuality); DECLARE_ENUM(eAudioLookupIndex); @@ -421,6 +426,26 @@ inline SString GetClassTypeName(eSurfaceAdhesionGroup*) { return "surface-adhesion-group"; } +inline SString GetClassByTypeName(eObjectGroup::Modifiable*) +{ + return "objectgroup-modifiable"; +} +inline SString GetClassByTypeName(eObjectGroup::DamageEffect*) +{ + return "objectgroup-damageeffect"; +} +inline SString GetClassByTypeName(eObjectGroup::CollisionResponse*) +{ + return "objectgroup-collisionresponse"; +} +inline SString GetClassByTypeName(eObjectGroup::FxType*) +{ + return "objectgroup-fxtype"; +} +inline SString GetClassByTypeName(eObjectGroup::BreakMode*) +{ + return "objectgroup-breakmode"; +} // // CResource from userdata diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 2f9e44e1a03..400f9ae3ab3 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -37,6 +37,12 @@ void CLuaEngineDefs::LoadFunctions() {"engineGetSurfaceProperties", EngineGetSurfaceProperties}, {"engineSetSurfaceProperties", EngineSetSurfaceProperties}, {"engineResetSurfaceProperties", EngineResetSurfaceProperties}, + {"engineGetModelPhysicalPropertiesGroup", EngineGetModelPhysicalPropertiesGroup}, + {"engineSetModelPhysicalPropertiesGroup", EngineSetModelPhysicalPropertiesGroup}, + {"engineRestoreModelPhysicalPropertiesGroup", EngineRestoreModelPhysicalPropertiesGroup}, + {"engineSetObjectGroupPhysicalProperty", EngineSetObjectGroupPhysicalProperty}, + {"engineGetObjectGroupPhysicalProperty", EngineGetObjectGroupPhysicalProperty}, + {"engineRestoreObjectGroupPhysicalProperties", EngineRestoreObjectGroupPhysicalProperties} // CLuaCFunctions::AddFunction ( "engineReplaceMatchingAtomics", EngineReplaceMatchingAtomics ); // CLuaCFunctions::AddFunction ( "engineReplaceWheelAtomics", EngineReplaceWheelAtomics ); @@ -67,6 +73,12 @@ void CLuaEngineDefs::AddClass(lua_State* luaVM) lua_classfunction(luaVM, "getModelTextureNames", "engineGetModelTextureNames"); lua_classfunction(luaVM, "getModelIDFromName", "engineGetModelIDFromName"); lua_classfunction(luaVM, "getModelNameFromID", "engineGetModelNameFromID"); + lua_classfunction(luaVM, "getModelPhysicalPropertiesGroup", "engineGetModelPhysicalPropertiesGroup"); + lua_classfunction(luaVM, "setModelPhysicalPropertiesGroup", "engineSetModelPhysicalPropertiesGroup"); + lua_classfunction(luaVM, "restoreModelPhysicalPropertiesGroup", "engineRestoreModelPhysicalPropertiesGroup"); + lua_classfunction(luaVM, "setObjectGroupPhysicalProperty", "engineSetObjectGroupPhysicalProperty"); + lua_classfunction(luaVM, "getObjectGroupPhysicalProperty", "engineGetObjectGroupPhysicalProperty"); + lua_classfunction(luaVM, "restoreObjectGroupPhysicalProperties", "engineRestoreObjectGroupPhysicalProperties"); // lua_classvariable ( luaVM, "modelLODDistance", "engineSetModelLODDistance", "engineGetModelLODDistance" ); .modelLODDistance[model] = distance // lua_classvariable ( luaVM, "modelNameFromID", NULL, "engineGetModelNameFromID" ); .modelNameFromID[id] = "name" @@ -1328,3 +1340,433 @@ int CLuaEngineDefs::EngineResetSurfaceProperties(lua_State* luaVM) return 1; } + +int CLuaEngineDefs::EngineGetModelPhysicalPropertiesGroup(lua_State* luaVM) +{ + // int engineGetModelPhysicalPropertiesGroup ( int modelID ) + int iModelID; + + CScriptArgReader argStream(luaVM); + argStream.ReadNumber(iModelID); + + if (!argStream.HasErrors()) + { + if (iModelID < 0 || iModelID >= 20000) + { + argStream.SetCustomError("Expected model ID in range [0-19999] at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + auto pModelInfo = g_pGame->GetModelInfo(iModelID); + if (pModelInfo) + { + lua_pushnumber(luaVM, pModelInfo->GetObjectPropertiesGroup()); + return 1; + } + argStream.SetCustomError("Expected valid model ID at argument 1"); + } + + return luaL_error(luaVM, argStream.GetFullErrorMessage()); +} + +int CLuaEngineDefs::EngineSetModelPhysicalPropertiesGroup(lua_State* luaVM) +{ + // bool engineSetModelPhysicalPropertiesGroup ( int modelID, int newGroup ) + int iModelID; + unsigned int iNewGroup; + + CScriptArgReader argStream(luaVM); + argStream.ReadNumber(iModelID); + argStream.ReadNumber(iNewGroup); + + if (!argStream.HasErrors()) + { + if (iModelID < 0 || iModelID > 19999) + { + argStream.SetCustomError("Expected model ID in range [0-19999] at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + if (iNewGroup < 0 || iNewGroup > 159) + { + argStream.SetCustomError("Expected group ID in range [0-159] at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + auto pModelInfo = g_pGame->GetModelInfo(iModelID); + if (pModelInfo) + { + pModelInfo->SetObjectPropertiesGroup(iNewGroup); + lua_pushboolean(luaVM, true); + return 1; + } + argStream.SetCustomError("Expected valid model ID at argument 1"); + } + + return luaL_error(luaVM, argStream.GetFullErrorMessage()); +} + +int CLuaEngineDefs::EngineRestoreModelPhysicalPropertiesGroup(lua_State* luaVM) +{ + // bool engineRestoreModelPhysicalPropertiesGroup ( int modelID ) + int iModelID; + + CScriptArgReader argStream(luaVM); + argStream.ReadNumber(iModelID); + + if (!argStream.HasErrors()) + { + if (iModelID < 0 || iModelID > 19999) + { + argStream.SetCustomError("Expected model ID in range [0-19999] at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + auto pModelInfo = g_pGame->GetModelInfo(iModelID); + if (pModelInfo) + { + pModelInfo->RestoreObjectPropertiesGroup(); + lua_pushboolean(luaVM, true); + return 1; + } + argStream.SetCustomError("Expected valid model ID at argument 1"); + } + + return luaL_error(luaVM, argStream.GetFullErrorMessage()); +} + +std::unordered_map> g_GroupPropertiesSettersFloat{ + {eObjectGroup::Modifiable::MASS, [](CObjectGroupPhysicalProperties* pGroup, float fValue) { pGroup->SetMass(fValue); }}, + {eObjectGroup::Modifiable::TURNMASS, [](CObjectGroupPhysicalProperties* pGroup, float fValue) { pGroup->SetTurnMass(fValue); }}, + {eObjectGroup::Modifiable::AIRRESISTANCE, [](CObjectGroupPhysicalProperties* pGroup, float fValue) { pGroup->SetAirResistance(fValue); }}, + {eObjectGroup::Modifiable::ELASTICITY, [](CObjectGroupPhysicalProperties* pGroup, float fValue) { pGroup->SetElasticity(fValue); }}, + {eObjectGroup::Modifiable::BUOYANCY, [](CObjectGroupPhysicalProperties* pGroup, float fValue) { pGroup->SetBuoyancy(fValue); }}, + {eObjectGroup::Modifiable::UPROOTLIMIT, [](CObjectGroupPhysicalProperties* pGroup, float fValue) { pGroup->SetUprootLimit(fValue); }}, + {eObjectGroup::Modifiable::COLDAMAGEMULTIPLIER, [](CObjectGroupPhysicalProperties* pGroup, float fValue) { pGroup->SetCollisionDamageMultiplier(fValue); }}, + {eObjectGroup::Modifiable::SMASHMULTIPLIER, [](CObjectGroupPhysicalProperties* pGroup, float fValue) { pGroup->SetSmashMultiplier(fValue); }}, + {eObjectGroup::Modifiable::BREAKVELOCITYRAND, [](CObjectGroupPhysicalProperties* pGroup, float fValue) { pGroup->SetBreakVelocityRandomness(fValue); }}, +}; +std::unordered_map> g_GroupPropertiesSettersBool{ + {eObjectGroup::Modifiable::CAMERAAVOID, [](CObjectGroupPhysicalProperties* pGroup, bool bValue) { pGroup->SetCameraAvoidObject(bValue); }}, + {eObjectGroup::Modifiable::EXPLOSION, [](CObjectGroupPhysicalProperties* pGroup, bool bValue) { pGroup->SetCausesExplosion(bValue); }}, + {eObjectGroup::Modifiable::SPARKSONIMPACT, [](CObjectGroupPhysicalProperties* pGroup, bool bValue) { pGroup->SetSparksOnImpact(bValue); }}, +}; +std::unordered_map> g_GroupPropertiesSettersVector{ + {eObjectGroup::Modifiable::FXOFFSET, [](CObjectGroupPhysicalProperties* pGroup, CVector vecValue) { pGroup->SetFxOffset(vecValue); }}, + {eObjectGroup::Modifiable::BREAKVELOCITY, [](CObjectGroupPhysicalProperties* pGroup, CVector vecValue) { pGroup->SetBreakVelocity(vecValue); }}, +}; + +int CLuaEngineDefs::EngineSetObjectGroupPhysicalProperty(lua_State* luaVM) +{ + // bool engineSetObjectGroupPhysicalProperty ( int groupID, string property, ...) + int iGivenGroup; + eObjectGroup::Modifiable eProperty; + + CScriptArgReader argStream(luaVM); + argStream.ReadNumber(iGivenGroup); + argStream.ReadEnumString(eProperty); + + if (argStream.HasErrors()) + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + + if (iGivenGroup < 0 || iGivenGroup > 159) + { + argStream.SetCustomError("Expected group ID in range [0-159] at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + auto pGroup = g_pGame->GetObjectGroupPhysicalProperties(iGivenGroup); + if (!pGroup) + { + argStream.SetCustomError("Expected valid group ID at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + switch (eProperty) + { + case eObjectGroup::Modifiable::MASS: + case eObjectGroup::Modifiable::TURNMASS: + case eObjectGroup::Modifiable::AIRRESISTANCE: + case eObjectGroup::Modifiable::ELASTICITY: + case eObjectGroup::Modifiable::BUOYANCY: + case eObjectGroup::Modifiable::UPROOTLIMIT: + case eObjectGroup::Modifiable::COLDAMAGEMULTIPLIER: + case eObjectGroup::Modifiable::SMASHMULTIPLIER: + case eObjectGroup::Modifiable::BREAKVELOCITYRAND: + { + float fValue; + argStream.ReadNumber(fValue); + if (argStream.HasErrors()) + break; + + g_GroupPropertiesSettersFloat[eProperty](pGroup, fValue); + lua_pushboolean(luaVM, true); + return 1; + } + case eObjectGroup::Modifiable::CAMERAAVOID: + case eObjectGroup::Modifiable::EXPLOSION: + case eObjectGroup::Modifiable::SPARKSONIMPACT: + { + bool bValue; + argStream.ReadBool(bValue); + if (argStream.HasErrors()) + break; + + g_GroupPropertiesSettersBool[eProperty](pGroup, bValue); + lua_pushboolean(luaVM, true); + return 1; + } + case eObjectGroup::Modifiable::FXOFFSET: + case eObjectGroup::Modifiable::BREAKVELOCITY: + { + CVector vecValue; + argStream.ReadVector3D(vecValue); + if (argStream.HasErrors()) + break; + + g_GroupPropertiesSettersVector[eProperty](pGroup, vecValue); + lua_pushboolean(luaVM, true); + return 1; + } + case eObjectGroup::Modifiable::COLDAMAGEEFFECT: + { + eObjectGroup::DamageEffect eDamEffect; + argStream.ReadEnumString(eDamEffect); + if (argStream.HasErrors()) + break; + + pGroup->SetCollisionDamageEffect(eDamEffect); + lua_pushboolean(luaVM, true); + return 1; + } + case eObjectGroup::Modifiable::SPECIALCOLRESPONSE: + { + eObjectGroup::CollisionResponse eColRepsonse; + argStream.ReadEnumString(eColRepsonse); + if (argStream.HasErrors()) + break; + + pGroup->SetCollisionSpecialResponseCase(eColRepsonse); + lua_pushboolean(luaVM, true); + return 1; + } + case eObjectGroup::Modifiable::FXTYPE: + { + eObjectGroup::FxType eFxType; + argStream.ReadEnumString(eFxType); + if (argStream.HasErrors()) + break; + + pGroup->SetFxType(eFxType); + lua_pushboolean(luaVM, true); + return 1; + } + case eObjectGroup::Modifiable::BREAKMODE: + { + eObjectGroup::BreakMode eBreakMode; + argStream.ReadEnumString(eBreakMode); + if (argStream.HasErrors()) + break; + + pGroup->SetBreakMode(eBreakMode); + lua_pushboolean(luaVM, true); + return 1; + } + case eObjectGroup::Modifiable::FXSYSTEM: + { + if (argStream.NextIsBool()) + { + bool bRemove; + argStream.ReadBool(bRemove); + if (!bRemove) + { + pGroup->RemoveFxParticleSystem(); + lua_pushboolean(luaVM, true); + return 1; + } + + argStream.SetCustomError("Expected either false, or valid fx system name at argument 3"); + break; + } + else + { + SString sName; + argStream.ReadString(sName); + if (argStream.HasErrors()) + break; + + if (!g_pGame->GetFxManager()->IsValidFxSystemBlueprintName(sName)) + { + argStream.SetCustomError("Expected valid fx system name at argument 3"); + break; + } + + CFxSystemBPSAInterface* pBlueprint = g_pGame->GetFxManager()->GetFxSystemBlueprintByName(sName); + if (pGroup->SetFxParticleSystem(pBlueprint)) + { + lua_pushboolean(luaVM, true); + return 1; + } + else + { + argStream.SetCustomError("Given fx system isn't supported"); + break; + } + } + } + } + + return luaL_error(luaVM, argStream.GetFullErrorMessage()); +} + +std::unordered_map> g_GroupPropertiesGettersFloat{ + {eObjectGroup::Modifiable::MASS, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetMass(); }}, + {eObjectGroup::Modifiable::TURNMASS, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetTurnMass(); }}, + {eObjectGroup::Modifiable::AIRRESISTANCE, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetAirResistance(); }}, + {eObjectGroup::Modifiable::ELASTICITY, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetElasticity(); }}, + {eObjectGroup::Modifiable::BUOYANCY, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetBuoyancy(); }}, + {eObjectGroup::Modifiable::UPROOTLIMIT, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetUprootLimit(); }}, + {eObjectGroup::Modifiable::COLDAMAGEMULTIPLIER, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetCollisionDamageMultiplier(); }}, + {eObjectGroup::Modifiable::SMASHMULTIPLIER, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetSmashMultiplier(); }}, + {eObjectGroup::Modifiable::BREAKVELOCITYRAND, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetBreakVelocityRandomness(); }}, +}; +std::unordered_map> g_GroupPropertiesGettersBool{ + {eObjectGroup::Modifiable::CAMERAAVOID, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetCameraAvoidObject(); }}, + {eObjectGroup::Modifiable::EXPLOSION, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetCausesExplosion(); }}, + {eObjectGroup::Modifiable::SPARKSONIMPACT, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetSparksOnImpact(); }}, +}; +std::unordered_map> g_GroupPropertiesGettersVector{ + {eObjectGroup::Modifiable::FXOFFSET, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetFxOffset(); }}, + {eObjectGroup::Modifiable::BREAKVELOCITY, [](CObjectGroupPhysicalProperties* pGroup) { return pGroup->GetBreakVelocity(); }}, +}; +int CLuaEngineDefs::EngineGetObjectGroupPhysicalProperty(lua_State* luaVM) +{ + // bool engineGetObjectGroupPhysicalProperty ( int groupID, string property ) + int iGivenGroup; + eObjectGroup::Modifiable eProperty; + + CScriptArgReader argStream(luaVM); + argStream.ReadNumber(iGivenGroup); + argStream.ReadEnumString(eProperty); + + if (argStream.HasErrors()) + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + + if (iGivenGroup < 0 || iGivenGroup > 159) + { + argStream.SetCustomError("Expected group ID in range [0-159] at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + auto pGroup = g_pGame->GetObjectGroupPhysicalProperties(iGivenGroup); + if (!pGroup) + { + argStream.SetCustomError("Expected valid group ID at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + switch (eProperty) + { + case eObjectGroup::Modifiable::MASS: + case eObjectGroup::Modifiable::TURNMASS: + case eObjectGroup::Modifiable::AIRRESISTANCE: + case eObjectGroup::Modifiable::ELASTICITY: + case eObjectGroup::Modifiable::BUOYANCY: + case eObjectGroup::Modifiable::UPROOTLIMIT: + case eObjectGroup::Modifiable::COLDAMAGEMULTIPLIER: + case eObjectGroup::Modifiable::SMASHMULTIPLIER: + case eObjectGroup::Modifiable::BREAKVELOCITYRAND: + { + float fValue = g_GroupPropertiesGettersFloat[eProperty](pGroup); + lua_pushnumber(luaVM, fValue); + return 1; + } + case eObjectGroup::Modifiable::CAMERAAVOID: + case eObjectGroup::Modifiable::EXPLOSION: + case eObjectGroup::Modifiable::SPARKSONIMPACT: + { + bool bValue = g_GroupPropertiesGettersBool[eProperty](pGroup); + lua_pushboolean(luaVM, bValue); + return 1; + } + case eObjectGroup::Modifiable::FXOFFSET: + case eObjectGroup::Modifiable::BREAKVELOCITY: + { + CVector vecValue = g_GroupPropertiesGettersVector[eProperty](pGroup); + lua_pushvector(luaVM, vecValue); + return 1; + } + case eObjectGroup::Modifiable::COLDAMAGEEFFECT: + { + eObjectGroup::DamageEffect eDamEffect = pGroup->GetCollisionDamageEffect(); + if (!EnumValueValid(eDamEffect)) + break; + + lua_pushstring(luaVM, EnumToString(eDamEffect)); + return 1; + } + case eObjectGroup::Modifiable::SPECIALCOLRESPONSE: + { + eObjectGroup::CollisionResponse eColRepsonse = pGroup->GetCollisionSpecialResponseCase(); + if (!EnumValueValid(eColRepsonse)) + break; + + lua_pushstring(luaVM, EnumToString(eColRepsonse)); + return 1; + } + case eObjectGroup::Modifiable::FXTYPE: + { + eObjectGroup::FxType eFxType = pGroup->GetFxType(); + if (!EnumValueValid(eFxType)) + break; + + lua_pushstring(luaVM, EnumToString(eFxType)); + return 1; + } + case eObjectGroup::Modifiable::BREAKMODE: + { + eObjectGroup::BreakMode eBreakMode = pGroup->GetBreakMode(); + if (!EnumValueValid(eBreakMode)) + break; + + lua_pushstring(luaVM, EnumToString(eBreakMode)); + return 1; + } + case eObjectGroup::Modifiable::FXSYSTEM: + { + argStream.SetCustomError("Fx system name isn't possible to be extracted."); + break; + } + } + + return luaL_error(luaVM, argStream.GetFullErrorMessage()); +} + +int CLuaEngineDefs::EngineRestoreObjectGroupPhysicalProperties(lua_State* luaVM) +{ + // bool engineRestoreObjectGroupPhysicalProperties ( int groupID ) + int iGivenGroup; + + CScriptArgReader argStream(luaVM); + argStream.ReadNumber(iGivenGroup); + + if (argStream.HasErrors()) + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + + if (iGivenGroup < 0 || iGivenGroup > 159) + { + argStream.SetCustomError("Expected group ID in range [0-159] at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + auto pGroup = g_pGame->GetObjectGroupPhysicalProperties(iGivenGroup); + if (!pGroup) + { + argStream.SetCustomError("Expected valid group ID at argument 1"); + return luaL_error(luaVM, argStream.GetFullErrorMessage()); + } + + pGroup->RestoreDefault(); + lua_pushboolean(luaVM, true); + return 1; +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h index 9e562873d4b..bb978c28ac8 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h @@ -47,6 +47,12 @@ class CLuaEngineDefs : public CLuaDefs LUA_DECLARE(EngineSetSurfaceProperties); LUA_DECLARE(EngineGetSurfaceProperties); LUA_DECLARE(EngineResetSurfaceProperties); + LUA_DECLARE(EngineGetModelPhysicalPropertiesGroup) + LUA_DECLARE(EngineSetModelPhysicalPropertiesGroup) + LUA_DECLARE(EngineRestoreModelPhysicalPropertiesGroup) + LUA_DECLARE(EngineSetObjectGroupPhysicalProperty) + LUA_DECLARE(EngineGetObjectGroupPhysicalProperty) + LUA_DECLARE(EngineRestoreObjectGroupPhysicalProperties) private: static void AddEngineColClass(lua_State* luaVM); diff --git a/Client/sdk/game/CFxManager.h b/Client/sdk/game/CFxManager.h index 417e65797f3..d50a8dd807a 100644 --- a/Client/sdk/game/CFxManager.h +++ b/Client/sdk/game/CFxManager.h @@ -15,6 +15,7 @@ class CFxSystem; class CFxSystemSAInterface; +class CFxSystemBPSAInterface; class CFxManager { @@ -22,5 +23,7 @@ class CFxManager virtual CFxSystem* CreateFxSystem(const char* szBlueprint, const CVector& vecPosition, RwMatrix* pRwMatrixTag, unsigned char bSkipCameraFrustumCheck, bool bSoundEnable) = 0; virtual void DestroyFxSystem(CFxSystem* pFxSystem) = 0; - virtual void OnFxSystemSAInterfaceDestroyed(CFxSystemSAInterface* pFxSystemSAInterface) = 0; + virtual void OnFxSystemSAInterfaceDestroyed(CFxSystemSAInterface* pFxSystemSAInterface) = 0; + virtual CFxSystemBPSAInterface* GetFxSystemBlueprintByName(SString sName) = 0; + virtual bool IsValidFxSystemBlueprintName(SString sName) = 0; }; diff --git a/Client/sdk/game/CGame.h b/Client/sdk/game/CGame.h index 554f183d48a..b1991a9aed5 100644 --- a/Client/sdk/game/CGame.h +++ b/Client/sdk/game/CGame.h @@ -79,6 +79,7 @@ typedef void(InRenderer)(); #include "CWeaponInfo.h" #include "CWorld.h" #include "TaskCarAccessories.h" +#include "CObjectGroupPhysicalProperties.h" #include @@ -247,4 +248,6 @@ class __declspec(novtable) CGame virtual void SetPreWeaponFireHandler(PreWeaponFireHandler* pPreWeaponFireHandler) = 0; virtual void SetPostWeaponFireHandler(PostWeaponFireHandler* pPostWeaponFireHandler) = 0; virtual void SetTaskSimpleBeHitHandler(TaskSimpleBeHitHandler* pTaskSimpleBeHitHandler) = 0; + + virtual CObjectGroupPhysicalProperties* GetObjectGroupPhysicalProperties(unsigned char ucObjectGroup) = 0; }; diff --git a/Client/sdk/game/CModelInfo.h b/Client/sdk/game/CModelInfo.h index afd09775863..74fd16f7986 100644 --- a/Client/sdk/game/CModelInfo.h +++ b/Client/sdk/game/CModelInfo.h @@ -172,4 +172,8 @@ class CModelInfo virtual SVehicleSupportedUpgrades GetVehicleSupportedUpgrades() = 0; virtual void ResetSupportedUpgrades() = 0; + + virtual void SetObjectPropertiesGroup(unsigned short usObjectGroup) = 0; + virtual unsigned short GetObjectPropertiesGroup() = 0; + virtual void RestoreObjectPropertiesGroup() = 0; }; diff --git a/Client/sdk/game/CObjectGroupPhysicalProperties.h b/Client/sdk/game/CObjectGroupPhysicalProperties.h new file mode 100644 index 00000000000..75b937eac80 --- /dev/null +++ b/Client/sdk/game/CObjectGroupPhysicalProperties.h @@ -0,0 +1,60 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: sdk/game/CObjectGroupPhysicalProperties.h + * PURPOSE: Objects dynamic physical properties handler interface + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ +#pragma once + +#include + +class CObjectGroupPhysicalProperties +{ +public: + virtual class CObjectGroupPhysicalPropertiesSAInterface* GetInterface() const = 0; + virtual unsigned char GetGroup() const = 0; + virtual void RestoreDefault() = 0; + + virtual void SetMass(float fMass) = 0; + virtual float GetMass() const = 0; + virtual void SetTurnMass(float fTurnMass) = 0; + virtual float GetTurnMass() const = 0; + virtual void SetAirResistance(float fAirResistance) = 0; + virtual float GetAirResistance() const = 0; + virtual void SetElasticity(float fElasticity) = 0; + virtual float GetElasticity() const = 0; + virtual void SetBuoyancy(float fBuoyancy) = 0; + virtual float GetBuoyancy() const = 0; + virtual void SetUprootLimit(float fUprootLimit) = 0; + virtual float GetUprootLimit() const = 0; + virtual void SetCollisionDamageMultiplier(float fColMult) = 0; + virtual float GetCollisionDamageMultiplier() const = 0; + virtual void SetCollisionDamageEffect(eObjectGroup::DamageEffect eDamageEffect) = 0; + virtual eObjectGroup::DamageEffect GetCollisionDamageEffect() const = 0; + virtual void SetCollisionSpecialResponseCase(eObjectGroup::CollisionResponse eResponseCase) = 0; + virtual eObjectGroup::CollisionResponse GetCollisionSpecialResponseCase() const = 0; + virtual void SetCameraAvoidObject(bool bAvoid) = 0; + virtual bool GetCameraAvoidObject() const = 0; + virtual void SetCausesExplosion(bool bExplodes) = 0; + virtual bool GetCausesExplosion() const = 0; + virtual void SetFxType(eObjectGroup::FxType eFxType) = 0; + virtual eObjectGroup::FxType GetFxType() const = 0; + virtual void SetFxOffset(CVector vecOffset) = 0; + virtual CVector GetFxOffset() const = 0; + virtual bool SetFxParticleSystem(CFxSystemBPSAInterface* pBlueprint) = 0; + virtual void RemoveFxParticleSystem() = 0; + virtual void SetSmashMultiplier(float fMult) = 0; + virtual float GetSmashMultiplier() const = 0; + virtual void SetBreakVelocity(CVector vecVelocity) = 0; + virtual CVector GetBreakVelocity() const = 0; + virtual void SetBreakVelocityRandomness(float fRand) = 0; + virtual float GetBreakVelocityRandomness() const = 0; + virtual void SetBreakMode(eObjectGroup::BreakMode eBreakMode) = 0; + virtual eObjectGroup::BreakMode GetBreakMode() const = 0; + virtual void SetSparksOnImpact(bool bSparks) = 0; + virtual bool GetSparksOnImpact() const = 0; +}; diff --git a/Client/sdk/game/Common.h b/Client/sdk/game/Common.h index c5484791026..fa599807183 100644 --- a/Client/sdk/game/Common.h +++ b/Client/sdk/game/Common.h @@ -1547,3 +1547,68 @@ enum eObjectProperty OBJECT_PROPERTY_BUOYANCY, OBJECT_PROPERTY_MAX, }; + +namespace eObjectGroup +{ + enum Modifiable + { + MASS, + TURNMASS, + AIRRESISTANCE, + ELASTICITY, + BUOYANCY, + UPROOTLIMIT, + COLDAMAGEMULTIPLIER, + COLDAMAGEEFFECT, + SPECIALCOLRESPONSE, + CAMERAAVOID, + EXPLOSION, + FXTYPE, + FXOFFSET, + FXSYSTEM, + SMASHMULTIPLIER, + BREAKVELOCITY, + BREAKVELOCITYRAND, + BREAKMODE, + SPARKSONIMPACT + }; + + enum DamageEffect + { + NO_EFFECT = 0, + CHANGE_MODEL = 1, + SMASH_COMPLETELY = 20, + CHANGE_THEN_SMASH = 21, + BREAKABLE = 200, + BREAKABLE_REMOVED = 202 + }; + + enum CollisionResponse + { + NO_RESPONSE, + LAMPPOST, + SMALLBOX, + BIGBOX, + FENCEPART, + GRENADE, + SWINGDOOR, + LOCKDOOR, + HANGING, + POOLBALL + }; + + enum FxType + { + NO_FX, + PLAY_ON_HIT, + PLAY_ON_DESTROYED, + PLAY_ON_HIT_DESTROYED + }; + + enum BreakMode + { + NOT_BY_GUN, + BY_GUN, + SMASHABLE, + }; +}