@@ -41,93 +41,112 @@ bool CClientExplosionManager::Hook_StaticExplosionCreation(CEntity* pGameExplodi
4141bool CClientExplosionManager::Hook_ExplosionCreation (CEntity* pGameExplodingEntity, CEntity* pGameCreator, const CVector& vecPosition,
4242 eExplosionType explosionType)
4343{
44- CClientPlayer* pLocalPlayer = m_pManager->GetPlayerManager ()->GetLocalPlayer ();
45-
46- CPools* pPools = g_pGame->GetPools ();
44+ CPools* const pPools = g_pGame->GetPools ();
4745
4846 // Grab the entity responsible
49- CClientEntity* pResponsible = NULL ;
50- CEntity* pResponsibleGameEntity = (pGameExplodingEntity) ? pGameExplodingEntity : pGameCreator;
47+ CEntity* const pResponsibleGameEntity = pGameExplodingEntity ? pGameExplodingEntity : pGameCreator;
48+
49+ if (!pResponsibleGameEntity)
50+ return false ;
51+
52+ CClientEntity* pResponsible = nullptr ;
53+
5154 if (pResponsibleGameEntity)
52- pResponsible = pPools->GetClientEntity (( DWORD*) pResponsibleGameEntity->GetInterface ());
55+ pResponsible = pPools->GetClientEntity (reinterpret_cast < DWORD*>( pResponsibleGameEntity->GetInterface () ));
5356
54- unsigned short usModel;
55- if (pResponsible && (pResponsible->IsLocalEntity () ||
56- (CStaticFunctionDefinitions::GetElementModel (*pResponsible, usModel) && CClientObjectManager::IsBreakableModel (usModel))))
57- return true ; // Handle this explosion client side only if entity is local or breakable (i.e. barrel)
57+ if (!pResponsible)
58+ return false ;
59+
60+ // Determine the used weapon
61+ eWeaponType explosionWeaponType = WEAPONTYPE_EXPLOSION;
5862
59- eWeaponType explosionWeaponType;
6063 switch (explosionType)
6164 {
62- case EXP_TYPE_GRENADE:
63- {
64- // Grenade type explosions from vehicles should only be freefall bombs
65- // TODO: need a way to check if its a freefall bomb if creator is a ped
66- if (pGameCreator && pGameCreator->GetEntityType () == ENTITY_TYPE_VEHICLE)
67- explosionWeaponType = WEAPONTYPE_FREEFALL_BOMB;
68- else
69- explosionWeaponType = WEAPONTYPE_GRENADE;
70- break ;
71- }
72- case EXP_TYPE_MOLOTOV:
73- explosionWeaponType = WEAPONTYPE_MOLOTOV;
74- break ;
75- case EXP_TYPE_ROCKET:
76- case EXP_TYPE_ROCKET_WEAK:
77- explosionWeaponType = WEAPONTYPE_ROCKET;
78- break ;
79- case EXP_TYPE_TANK_GRENADE:
80- explosionWeaponType = WEAPONTYPE_TANK_GRENADE;
81- break ;
82- default :
83- explosionWeaponType = WEAPONTYPE_EXPLOSION;
84- break ;
65+ case EXP_TYPE_GRENADE:
66+ {
67+ // Grenade type explosions from vehicles should only be freefall bombs
68+ // TODO: need a way to check if its a freefall bomb if creator is a ped
69+ if (pGameCreator && pGameCreator->GetEntityType () == ENTITY_TYPE_VEHICLE)
70+ explosionWeaponType = WEAPONTYPE_FREEFALL_BOMB;
71+ else
72+ explosionWeaponType = WEAPONTYPE_GRENADE;
73+ break ;
74+ }
75+ case EXP_TYPE_MOLOTOV:
76+ explosionWeaponType = WEAPONTYPE_MOLOTOV;
77+ break ;
78+ case EXP_TYPE_ROCKET:
79+ case EXP_TYPE_ROCKET_WEAK:
80+ explosionWeaponType = WEAPONTYPE_ROCKET;
81+ break ;
82+ case EXP_TYPE_TANK_GRENADE:
83+ explosionWeaponType = WEAPONTYPE_TANK_GRENADE;
84+ break ;
85+ default :
86+ break ;
8587 }
8688
87- // Got a responsible entity?
88- if (pResponsible)
89+ // Handle this explosion client side only if entity is local or breakable (i.e. barrel)
90+ unsigned short usModel;
91+ const bool bHasModel = CStaticFunctionDefinitions::GetElementModel (*pResponsible, usModel);
92+
93+ if (pResponsible->IsLocalEntity () || (bHasModel && CClientObjectManager::IsBreakableModel (usModel)))
8994 {
90- // Is the local player responsible for this?
91- bool bLocal = ((pResponsible == pLocalPlayer) || (pResponsible == pLocalPlayer->GetOccupiedVehicle ()) ||
92- (g_pClientGame->GetUnoccupiedVehicleSync ()->Exists (static_cast <CDeathmatchVehicle*>(pResponsible))));
95+ CLuaArguments Arguments;
96+ Arguments.PushNumber (vecPosition.fX );
97+ Arguments.PushNumber (vecPosition.fY );
98+ Arguments.PushNumber (vecPosition.fZ );
99+ Arguments.PushNumber (explosionWeaponType);
100+ const bool bAllowExplosion = pResponsible->CallEvent (" onClientExplosion" , Arguments, true );
101+ return bAllowExplosion;
102+ }
93103
94- if (bLocal)
95- {
96- CClientEntity* pOriginSource = NULL ;
104+ // All explosions are handled server side (ATTENTION: always 'return false;' below)
105+ CClientPlayer* pLocalPlayer = m_pManager->GetPlayerManager ()->GetLocalPlayer ();
97106
98- // Is this an exploding vehicle?
99- if (pGameExplodingEntity && pGameExplodingEntity->GetEntityType () == ENTITY_TYPE_VEHICLE)
100- {
101- // Set our origin-source to the vehicle
102- SClientEntity<CVehicleSA>* pVehicleClientEntity = pPools->GetVehicle ((DWORD*)pGameExplodingEntity->GetInterface ());
103- if (pVehicleClientEntity)
104- {
105- pOriginSource = pVehicleClientEntity->pClientEntity ;
106- }
107- }
108- // If theres other players, sync it relative to the closest (lag compensation)
109- else if (m_pManager->GetPlayerManager ()->Count () > 1 )
107+ // Is the local player responsible for this?
108+ const bool bIsLocalPlayer = pResponsible == pLocalPlayer;
109+ const bool bIsLocalPlayerVehicle = pResponsible == pLocalPlayer->GetOccupiedVehicle ();
110+ const bool bIsUnoccupiedVehicleSynced = g_pClientGame->GetUnoccupiedVehicleSync ()->Exists (static_cast <CDeathmatchVehicle*>(pResponsible));
111+
112+ if (!bIsLocalPlayer && !bIsLocalPlayerVehicle && !bIsUnoccupiedVehicleSynced)
113+ return false ;
114+
115+ CClientEntity* pOriginSource = nullptr ;
116+
117+ // Is this an exploding vehicle?
118+ if (pGameExplodingEntity && pGameExplodingEntity->GetEntityType () == ENTITY_TYPE_VEHICLE)
119+ {
120+ // Set our origin-source to the vehicle
121+ SClientEntity<CVehicleSA>* pVehicleClientEntity = pPools->GetVehicle (reinterpret_cast <DWORD*>(pGameExplodingEntity->GetInterface ()));
122+
123+ if (pVehicleClientEntity)
124+ {
125+ pOriginSource = pVehicleClientEntity->pClientEntity ;
126+ }
127+ }
128+ // If theres other players, sync it relative to the closest (lag compensation)
129+ else if (m_pManager->GetPlayerManager ()->Count () > 1 )
130+ {
131+ switch (explosionWeaponType)
132+ {
133+ case WEAPONTYPE_ROCKET:
134+ case WEAPONTYPE_ROCKET_HS:
110135 {
111- switch (explosionWeaponType)
136+ CClientPlayer* pPlayer = g_pClientGame->GetClosestRemotePlayer (vecPosition, 200 .0f );
137+
138+ if (pPlayer)
112139 {
113- case WEAPONTYPE_ROCKET:
114- case WEAPONTYPE_ROCKET_HS:
115- {
116- CClientPlayer* pPlayer = g_pClientGame->GetClosestRemotePlayer (vecPosition, 200 .0f );
117- if (pPlayer)
118- {
119- pOriginSource = pPlayer;
120- }
121- break ;
122- }
140+ pOriginSource = pPlayer;
123141 }
142+
143+ break ;
124144 }
125- // Request a new explosion
126- g_pClientGame->SendExplosionSync (vecPosition, explosionType, pOriginSource);
127145 }
128146 }
129147
130- // All explosions are handled server side
148+ // Request a new explosion
149+ g_pClientGame->SendExplosionSync (vecPosition, explosionType, pOriginSource);
131150 return false ;
132151}
133152
@@ -167,4 +186,4 @@ CExplosion* CClientExplosionManager::Create(eExplosionType explosionType, CVecto
167186
168187 CExplosion* pExplosion = g_pGame->GetExplosionManager ()->AddExplosion (NULL , pGameCreator, explosionType, vecPosition, 0 , bMakeSound, fCamShake , bNoDamage);
169188 return pExplosion;
170- }
189+ }
0 commit comments