ValveSoftware / source-sdk-2013

The 2013 edition of the Source SDK
https://developer.valvesoftware.com/wiki/SDK2013_GettingStarted
Other
3.84k stars 2.02k forks source link

Fix two grenade bugs (EDIT) #437

Closed Adrianilloo closed 5 years ago

Adrianilloo commented 7 years ago

These changes are applied to MP and SP. Shortly,

YouTube: HL2MP grenade fixes (SSDK2013)

EDIT

Kefta commented 7 years ago

It would be better to trace through to the desired grenade position to keep the behaviour of the grenade coming out a bit in front of the person, but back it out if need be to prevent it from passing through surfaces. If I recall correctly, CS:S or some other Source game's grenades did something like this.

Adrianilloo commented 4 years ago

Update: Finally I discovered an almost perfect fix from game code.

But now I'll be brief and just paste the patches here with explanatory comments for SP and MP branches separately, since there's an slight difference between them (different grenade model's origin). Fix for HL2MP:

--- a/mp/src/game/shared/hl2mp/weapon_frag.cpp
+++ b/mp/src/game/shared/hl2mp/weapon_frag.cpp
@@ -74,7 +74,8 @@ private:
        void    RollGrenade( CBasePlayer *pPlayer );
        void    LobGrenade( CBasePlayer *pPlayer );
        // check a throw from vecSrc.  If not valid, move the position back along the line to vecEye
-       void    CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc );
+       void    CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc,
+               const QAngle& angles = vec3_angle );

        CNetworkVar( bool,      m_bRedraw );    //Draw the weapon again after throwing a grenade

@@ -392,12 +393,20 @@ void CWeaponFrag::ItemPostFrame( void )
 }

        // check a throw from vecSrc.  If not valid, move the position back along the line to vecEye
-void CWeaponFrag::CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc )
+void CWeaponFrag::CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc, const QAngle& angles )
 {
+       // Compute an extended AABB that takes into account the requested grenade rotation.
+       // This will prevent grenade from going through nearby solids when model initially intersects with any.
+       matrix3x4_t rotation;
+       AngleMatrix(angles, rotation);
+       Vector mins, maxs;
+       RotateAABB(rotation, -Vector(GRENADE_RADIUS + 2, GRENADE_RADIUS + 2, 2),
+               Vector(GRENADE_RADIUS + 2, GRENADE_RADIUS + 2, GRENADE_RADIUS * 2 + 2), mins, maxs);
+
        trace_t tr;

-       UTIL_TraceHull( vecEye, vecSrc, -Vector(GRENADE_RADIUS+2,GRENADE_RADIUS+2,GRENADE_RADIUS+2), Vector(GRENADE_RADIUS+2,GRENADE_RADIUS+2,GRENADE_RADIUS+2),
-               pPlayer->PhysicsSolidMaskForEntity(), pPlayer, pPlayer->GetCollisionGroup(), &tr );
+       UTIL_TraceHull( vecEye, vecSrc, mins, maxs, pPlayer->PhysicsSolidMaskForEntity(),
+               pPlayer, pPlayer->GetCollisionGroup(), &tr );

        if ( tr.DidHit() )
        {
@@ -523,7 +532,6 @@ void CWeaponFrag::RollGrenade( CBasePlayer *pPlayer )
                CrossProduct( tr.plane.normal, tangent, vecFacing );
        }
        vecSrc += (vecFacing * 18.0);
-       CheckThrowPosition( pPlayer, pPlayer->WorldSpaceCenter(), vecSrc );

        Vector vecThrow;
        pPlayer->GetVelocity( &vecThrow, NULL );
@@ -532,6 +540,7 @@ void CWeaponFrag::RollGrenade( CBasePlayer *pPlayer )
        QAngle orientation(0,pPlayer->GetLocalAngles().y,-90);
        // roll it
        AngularImpulse rotSpeed(0,0,720);
+       CheckThrowPosition( pPlayer, pPlayer->WorldSpaceCenter(), vecSrc, orientation );
        CBaseGrenade *pGrenade = Fraggrenade_Create( vecSrc, orientation, vecThrow, rotSpeed, pPlayer, GRENADE_TIMER, false );

        if ( pGrenade )

For HL2SP:

--- a/sp/src/game/server/hl2/weapon_frag.cpp
+++ b/sp/src/game/server/hl2/weapon_frag.cpp
@@ -60,7 +60,8 @@ private:
        void    RollGrenade( CBasePlayer *pPlayer );
        void    LobGrenade( CBasePlayer *pPlayer );
        // check a throw from vecSrc.  If not valid, move the position back along the line to vecEye
-       void    CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc );
+       void    CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc,
+               const QAngle& angles = vec3_angle );

        bool    m_bRedraw;      //Draw the weapon again after throwing a grenade

@@ -367,12 +368,20 @@ void CWeaponFrag::ItemPostFrame( void )
 }

        // check a throw from vecSrc.  If not valid, move the position back along the line to vecEye
-void CWeaponFrag::CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc )
+void CWeaponFrag::CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc, const QAngle& angles )
 {
+       // Compute an extended AABB that takes into account the requested grenade rotation.
+       // This will prevent grenade from going through nearby solids when model initially intersects with any.
+       matrix3x4_t rotation;
+       AngleMatrix(angles, rotation);
+       Vector mins, maxs;
+       RotateAABB(rotation, -Vector(GRENADE_RADIUS + 2, GRENADE_RADIUS + 2, GRENADE_RADIUS + 2),
+               Vector(GRENADE_RADIUS + 2, GRENADE_RADIUS + 2, GRENADE_RADIUS + 2), mins, maxs);
+
        trace_t tr;

-       UTIL_TraceHull( vecEye, vecSrc, -Vector(GRENADE_RADIUS+2,GRENADE_RADIUS+2,GRENADE_RADIUS+2), Vector(GRENADE_RADIUS+2,GRENADE_RADIUS+2,GRENADE_RADIUS+2),
-               pPlayer->PhysicsSolidMaskForEntity(), pPlayer, pPlayer->GetCollisionGroup(), &tr );
+       UTIL_TraceHull( vecEye, vecSrc, mins, maxs, pPlayer->PhysicsSolidMaskForEntity(),
+               pPlayer, pPlayer->GetCollisionGroup(), &tr );

        if ( tr.DidHit() )
        {
@@ -459,7 +468,6 @@ void CWeaponFrag::RollGrenade( CBasePlayer *pPlayer )
                CrossProduct( tr.plane.normal, tangent, vecFacing );
        }
        vecSrc += (vecFacing * 18.0);
-       CheckThrowPosition( pPlayer, pPlayer->WorldSpaceCenter(), vecSrc );

        Vector vecThrow;
        pPlayer->GetVelocity( &vecThrow, NULL );
@@ -468,6 +476,7 @@ void CWeaponFrag::RollGrenade( CBasePlayer *pPlayer )
        QAngle orientation(0,pPlayer->GetLocalAngles().y,-90);
        // roll it
        AngularImpulse rotSpeed(0,0,720);
+       CheckThrowPosition( pPlayer, pPlayer->WorldSpaceCenter(), vecSrc, orientation );
        Fraggrenade_Create( vecSrc, orientation, vecThrow, rotSpeed, pPlayer, GRENADE_TIMER, false );

        WeaponSound( SPECIAL1 );