Skip to content

Commit 512c3d7

Browse files
committed
game/client: When fire RPG in Half-Life 2 it should show muzzle flash
RPG uses old event system, so fire causes Assert instead of displaying muzzle flash. This commit adds support of muzzle flashes for player and NPC. NPC one already existed, but not used. I derived player one from NPC. See ValveSoftware/source-sdk-2013#170
1 parent e7ba6a2 commit 512c3d7

File tree

7 files changed

+157
-19
lines changed

7 files changed

+157
-19
lines changed

game/client/c_baseanimating.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3748,7 +3748,7 @@ bool C_BaseAnimating::DispatchMuzzleEffect( const char *options, bool isFirstPer
37483748
{
37493749
const char *p = options;
37503750
char token[128];
3751-
int weaponType = 0;
3751+
int weaponType = MUZZLEFLASH_AR2;
37523752

37533753
// Get the first parameter
37543754
p = nexttoken( token, p, ' ' );
@@ -4373,9 +4373,10 @@ void C_BaseAnimating::FireObsoleteEvent( const Vector& origin, const QAngle& ang
43734373
if ( iAttachment != -1 && m_Attachments.Count() > iAttachment )
43744374
{
43754375
GetAttachment( iAttachment+1, attachOrigin, attachAngles );
4376-
int entId = render->GetViewEntity();
4377-
ClientEntityHandle_t hEntity = ClientEntityList().EntIndexToHandle( entId );
4378-
tempents->MuzzleFlash( attachOrigin, attachAngles, atoi( options ), hEntity, bFirstPerson );
4376+
// int entId = render->GetViewEntity();
4377+
// ClientEntityHandle_t hEntity = ClientEntityList().EntIndexToHandle( entId );
4378+
// dimhotepus: Use current entity for muzzle attachment, not view one.
4379+
tempents->MuzzleFlash( attachOrigin, attachAngles, atoi( options ), GetRefEHandle(), /*hEntity,*/ bFirstPerson );
43794380
}
43804381
}
43814382
break;

game/client/c_baseviewmodel.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ void C_BaseViewModel::FireEvent( const Vector& origin, const QAngle& angles, int
140140

141141
bool bResult = pWeapon->OnFireEvent( this, origin, angles, event, options );
142142
if ( !bResult )
143+
{
144+
// dimhotepus: Added special method Ex to allow patch options by weapon class.
145+
bResult = pWeapon->OnFireEventEx( this, origin, angles, event, options );
146+
}
147+
148+
// dimhotepus: Call FireEvent only if OnFireEvent & OnFireEventEx allowed to.
149+
if (!bResult)
143150
{
144151
BaseClass::FireEvent( origin, angles, event, options );
145152
}

game/client/c_te_legacytempents.cpp

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1780,7 +1780,8 @@ void CTempEnts::MuzzleFlash( int type, ClientEntityHandle_t hEntity, int attachm
17801780
case MUZZLEFLASH_RPG:
17811781
if ( firstPerson )
17821782
{
1783-
// MuzzleFlash_RPG_Player( hEntity, attachmentIndex );
1783+
// dimhotepus: Add muzzle flash for RPG.
1784+
MuzzleFlash_RPG_Player( hEntity, attachmentIndex );
17841785
}
17851786
else
17861787
{
@@ -1854,6 +1855,8 @@ void CTempEnts::MuzzleFlash( const Vector& pos1, const QAngle& angles, int type,
18541855
}
18551856
break;
18561857

1858+
// dimhotepus: AR2 and combine are same weapon.
1859+
case MUZZLEFLASH_AR2:
18571860
case MUZZLEFLASH_COMBINE:
18581861
if ( firstPerson )
18591862
{
@@ -1867,6 +1870,18 @@ void CTempEnts::MuzzleFlash( const Vector& pos1, const QAngle& angles, int type,
18671870
}
18681871
break;
18691872

1873+
// dimhotepus: Add muzzle flash support for RPG (Player and NPC).
1874+
case MUZZLEFLASH_RPG:
1875+
if ( firstPerson )
1876+
{
1877+
MuzzleFlash_RPG_Player( hEntity, 1 );
1878+
}
1879+
else
1880+
{
1881+
MuzzleFlash_RPG_NPC( hEntity, 1 );
1882+
}
1883+
break;
1884+
18701885
default:
18711886
// There's no supported muzzle flash for the type specified!
18721887
Assert(0);
@@ -3222,8 +3237,69 @@ void CTempEnts::MuzzleFlash_Pistol_NPC( ClientEntityHandle_t hEntity, int attach
32223237
FX_MuzzleEffectAttached( 0.5f, hEntity, attachmentIndex, NULL, true );
32233238
}
32243239

3240+
//-----------------------------------------------------------------------------
3241+
// Purpose:
3242+
//-----------------------------------------------------------------------------
3243+
// dimhotepus: Derived from MuzzleFlash_RPG_NPC.
3244+
void CTempEnts::MuzzleFlash_RPG_Player( ClientEntityHandle_t hEntity, int attachmentIndex )
3245+
{
3246+
VPROF_BUDGET( "MuzzleFlash_RPG_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
3247+
CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_RPG_Player", hEntity, attachmentIndex, FLE_VIEWMODEL );
3248+
pSimple->SetDrawBeforeViewModel( true );
3249+
3250+
CacheMuzzleFlashes();
3251+
3252+
constexpr float scale = 1.5f;
3253+
3254+
// Lock our bounding box
3255+
pSimple->GetBinding().SetBBox( -( Vector( 16, 16, 16 ) * scale ), ( Vector( 16, 16, 16 ) * scale ) );
3256+
3257+
SimpleParticle *pParticle;
3258+
Vector forward(1,0,0), offset;
3259+
3260+
float flScale = random->RandomFloat( scale-0.25f, scale+0.25f );
3261+
3262+
if ( flScale < 0.5f )
3263+
{
3264+
flScale = 0.5f;
3265+
}
3266+
else if ( flScale > 8.0f )
3267+
{
3268+
flScale = 8.0f;
3269+
}
3270+
3271+
//
3272+
// Flash
3273+
//
3274+
3275+
int i;
3276+
for ( i = 1; i < 9; i++ )
3277+
{
3278+
offset = (forward * (i*2.0f*scale));
3279+
3280+
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_SMG_Muzzleflash[random->RandomInt(0,3)], offset );
3281+
3282+
if ( pParticle == NULL )
3283+
return;
3284+
3285+
pParticle->m_flLifetime = 0.0f;
3286+
pParticle->m_flDieTime = 0.1f;
3287+
3288+
pParticle->m_vecVelocity.Init();
32253289

3290+
pParticle->m_uchColor[0] = 255;
3291+
pParticle->m_uchColor[1] = 255;
3292+
pParticle->m_uchColor[2] = 255;
32263293

3294+
pParticle->m_uchStartAlpha = 255;
3295+
pParticle->m_uchEndAlpha = 128;
3296+
3297+
pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
3298+
pParticle->m_uchEndSize = pParticle->m_uchStartSize;
3299+
pParticle->m_flRoll = random->RandomFloat( 0.0f, 360.0f );
3300+
pParticle->m_flRollDelta = 0.0f;
3301+
}
3302+
}
32273303

32283304
//==================================================
32293305
// Purpose:

game/client/c_te_legacytempents.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ class CTempEnts : public ITempEnts
211211
void MuzzleFlash_357_Player( ClientEntityHandle_t hEntity, int attachmentIndex );
212212

213213
// RPG
214+
// dimhotepus: Add muzzle flash support for Player RPG.
215+
void MuzzleFlash_RPG_Player( ClientEntityHandle_t hEntity, int attachmentIndex );
214216
void MuzzleFlash_RPG_NPC( ClientEntityHandle_t hEntity, int attachmentIndex );
215217
};
216218

game/client/c_weapon__stubs.h

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,29 @@
2020
END_PREDICTION_DATA() \
2121
LINK_ENTITY_TO_CLASS( entityName, className );
2222

23+
// dimhotepus: Split STUB_WEAPON_CLASS on BEGIN .. END to allow method overloads.
24+
#define STUB_WEAPON_CLASS_BEGIN(entityName, className, baseClassName) \
25+
class C_##className : public baseClassName { \
26+
DECLARE_CLASS(C_##className, baseClassName); \
27+
\
28+
public: \
29+
DECLARE_PREDICTABLE(); \
30+
DECLARE_CLIENTCLASS(); \
31+
C_##className(){};
32+
33+
34+
// dimhotepus: Split STUB_WEAPON_CLASS on BEGIN .. END to allow method overloads.
35+
#define STUB_WEAPON_CLASS_END(entityName, className, baseClassName) \
36+
private: \
37+
C_##className(const C_##className&); \
38+
}; \
39+
STUB_WEAPON_CLASS_IMPLEMENT(entityName, C_##className); \
40+
IMPLEMENT_CLIENTCLASS_DT(C_##className, DT_##className, C##className) \
41+
END_RECV_TABLE \
42+
()
2343

2444
#define STUB_WEAPON_CLASS( entityName, className, baseClassName ) \
25-
class C_##className : public baseClassName \
26-
{ \
27-
DECLARE_CLASS( C_##className, baseClassName ); \
28-
public: \
29-
DECLARE_PREDICTABLE(); \
30-
DECLARE_CLIENTCLASS(); \
31-
C_##className() {}; \
32-
private: \
33-
C_##className( const C_##className & ); \
34-
}; \
35-
STUB_WEAPON_CLASS_IMPLEMENT( entityName, C_##className ); \
36-
IMPLEMENT_CLIENTCLASS_DT( C_##className, DT_##className, C##className ) \
37-
END_RECV_TABLE()
45+
STUB_WEAPON_CLASS_BEGIN( entityName, className, baseClassName ) \
46+
STUB_WEAPON_CLASS_END( entityName, className, baseClassName )
3847

3948
#endif // C_WEAPON__STUBS_H

game/client/hl2/c_weapon__stubs_hl2.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include "basehlcombatweapon_shared.h"
1010
#include "c_basehlcombatweapon.h"
1111

12+
// dimhotepus: For animation events.
13+
#include "cl_animevent.h"
14+
1215
// memdbgon must be the last include file in a .cpp file!!!
1316
#include "tier0/memdbgon.h"
1417

@@ -27,7 +30,41 @@ STUB_WEAPON_CLASS( weapon_citizensuitcase, WeaponCitizenSuitcase, C_WeaponCitize
2730
#ifndef HL2MP
2831
STUB_WEAPON_CLASS( weapon_ar2, WeaponAR2, C_HLMachineGun );
2932
STUB_WEAPON_CLASS( weapon_frag, WeaponFrag, C_BaseHLCombatWeapon );
30-
STUB_WEAPON_CLASS( weapon_rpg, WeaponRPG, C_BaseHLCombatWeapon );
33+
34+
STUB_WEAPON_CLASS_BEGIN( weapon_rpg, WeaponRPG, C_BaseHLCombatWeapon )
35+
bool OnFireEventEx( [[maybe_unused]] C_BaseViewModel *pViewModel,
36+
[[maybe_unused]] const Vector& origin,
37+
[[maybe_unused]] const QAngle& angles,
38+
[[maybe_unused]] int event,
39+
const char *&options ) override
40+
{
41+
static const char muzzleFlashRpg[2] = {static_cast<char>('0' + to_underlying(MUZZLEFLASH_RPG)), '\0'};
42+
43+
// dimhotepus: RPG in Half-Life 2 uses obsolete muzzle flash events.
44+
// dimhotepus: and does not set options, but options used later to get weapon type.
45+
// dimhotepus: We ensure options set to weapon type for muzzle flashes to work.
46+
switch (event)
47+
{
48+
// OBSOLETE EVENTS. REPLACED BY NEWER SYSTEMS.
49+
case CL_EVENT_MUZZLEFLASH0:
50+
case CL_EVENT_MUZZLEFLASH1:
51+
case CL_EVENT_MUZZLEFLASH2:
52+
case CL_EVENT_MUZZLEFLASH3:
53+
case CL_EVENT_NPC_MUZZLEFLASH0:
54+
case CL_EVENT_NPC_MUZZLEFLASH1:
55+
case CL_EVENT_NPC_MUZZLEFLASH2:
56+
case CL_EVENT_NPC_MUZZLEFLASH3:
57+
if (Q_isempty(options))
58+
{
59+
options = muzzleFlashRpg;
60+
}
61+
}
62+
63+
// dimhotepus: False to continue processing.
64+
return false;
65+
}
66+
STUB_WEAPON_CLASS_END( weapon_rpg, WeaponRPG, C_BaseHLCombatWeapon );
67+
3168
STUB_WEAPON_CLASS( weapon_pistol, WeaponPistol, C_BaseHLCombatWeapon );
3269
STUB_WEAPON_CLASS( weapon_shotgun, WeaponShotgun, C_BaseHLCombatWeapon );
3370
STUB_WEAPON_CLASS( weapon_smg1, WeaponSMG1, C_HLSelectFireMachineGun );

game/shared/basecombatweapon_shared.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,12 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM
484484
#endif
485485
}
486486

487+
// dimhotepus: Special method to allow change options by weapon class.
488+
virtual bool OnFireEventEx( [[maybe_unused]] C_BaseViewModel *pViewModel, [[maybe_unused]] const Vector& origin, [[maybe_unused]] const QAngle& angles, [[maybe_unused]] int event, [[maybe_unused]] const char *&options )
489+
{
490+
return false;
491+
}
492+
487493
// Should this object cast shadows?
488494
ShadowType_t ShadowCastType() override;
489495
void SetDormant( bool bDormant ) override;

0 commit comments

Comments
 (0)