Skip to content

Commit 700b229

Browse files
committed
Fix #491: Trigger onClientExplosion for local entities and breakable models
1 parent 0c67100 commit 700b229

File tree

1 file changed

+88
-69
lines changed

1 file changed

+88
-69
lines changed

Client/mods/deathmatch/logic/CClientExplosionManager.cpp

Lines changed: 88 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -41,93 +41,112 @@ bool CClientExplosionManager::Hook_StaticExplosionCreation(CEntity* pGameExplodi
4141
bool 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

Comments
 (0)