diff options
Diffstat (limited to 'game/shared/hl1/hl1mp_weapon_handgrenade.cpp')
| -rw-r--r-- | game/shared/hl1/hl1mp_weapon_handgrenade.cpp | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/game/shared/hl1/hl1mp_weapon_handgrenade.cpp b/game/shared/hl1/hl1mp_weapon_handgrenade.cpp new file mode 100644 index 0000000..5676138 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_handgrenade.cpp @@ -0,0 +1,456 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hand grenade +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1mp_basecombatweapon_shared.h" +//#include "basecombatcharacter.h" +//#include "AI_BaseNPC.h" +#ifdef CLIENT_DLL +#include "hl1/hl1_c_player.h" +#else +#include "hl1_player.h" +#endif +#include "gamerules.h" +#include "in_buttons.h" +#ifdef CLIENT_DLL +#else +#include "soundent.h" +#include "game.h" +#endif +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#ifdef CLIENT_DLL +#else +#include "hl1_basegrenade.h" +#endif + + +#define HANDGRENADE_MODEL "models/w_grenade.mdl" + + +#ifndef CLIENT_DLL + +extern ConVar sk_plr_dmg_grenade; + +//----------------------------------------------------------------------------- +// CHandGrenade +//----------------------------------------------------------------------------- +LINK_ENTITY_TO_CLASS( grenade_hand, CHandGrenade ); + +BEGIN_DATADESC( CHandGrenade ) + DEFINE_ENTITYFUNC( BounceTouch ), +END_DATADESC() + + +void CHandGrenade::Spawn( void ) +{ + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); + SetSolid( SOLID_BBOX ); + AddSolidFlags( FSOLID_NOT_STANDABLE ); + + SetModel( HANDGRENADE_MODEL ); + + UTIL_SetSize( this, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); + + m_bHasWarnedAI = false; +} + + +void CHandGrenade::Precache( void ) +{ + BaseClass::Precache( ); + + PrecacheScriptSound( "Weapon_HandGrenade.GrenadeBounce" ); + + PrecacheModel( HANDGRENADE_MODEL ); +} + + +void CHandGrenade::ShootTimed( CBaseCombatCharacter *pOwner, Vector vecVelocity, float flTime ) +{ + SetAbsVelocity( vecVelocity ); + + SetThrower( pOwner ); + SetOwnerEntity( pOwner ); + + SetTouch( &CHandGrenade::BounceTouch ); // Bounce if touched + + m_flDetonateTime = gpGlobals->curtime + flTime; + SetThink( &CBaseGrenade::TumbleThink ); + SetNextThink( gpGlobals->curtime + 0.1 ); + if ( flTime < 0.1 ) + { + SetNextThink( gpGlobals->curtime ); + SetAbsVelocity( vec3_origin ); + } + +// SetSequence( SelectWeightedSequence( ACT_GRENADE_TOSS ) ); + SetSequence( 0 ); + m_flPlaybackRate = 1.0; + + SetAbsAngles( QAngle( 0,0,60) ); + + AngularImpulse angImpulse; + angImpulse[0] = random->RandomInt( -200, 200 ); + angImpulse[1] = random->RandomInt( 400, 500 ); + angImpulse[2] = random->RandomInt( -100, 100 ); + ApplyLocalAngularVelocityImpulse( angImpulse ); + + SetGravity( UTIL_ScaleForGravity( 400 ) ); // use a lower gravity for grenades to make them easier to see + SetFriction( 0.8 ); + + SetDamage( sk_plr_dmg_grenade.GetFloat() ); + SetDamageRadius( GetDamage() * 2.5 ); +} + + +void CHandGrenade ::BounceSound( void ) +{ + EmitSound( "Weapon_HandGrenade.GrenadeBounce" ); +} + + +void CHandGrenade::BounceTouch( CBaseEntity *pOther ) +{ + if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS) ) + return; + + // don't hit the guy that launched this grenade + if ( pOther == GetThrower() ) + return; + + // Do a special test for players + if ( pOther->IsPlayer() ) + { + // Never hit a player again (we'll explode and fixup anyway) + SetCollisionGroup( COLLISION_GROUP_DEBRIS ); + } + // only do damage if we're moving fairly fast + if ( (pOther->m_takedamage != DAMAGE_NO) && (m_flNextAttack < gpGlobals->curtime && GetAbsVelocity().Length() > 100)) + { + if ( GetThrower() ) + { + trace_t tr; + tr = CBaseEntity::GetTouchTrace( ); + ClearMultiDamage( ); + Vector forward; + AngleVectors( GetAbsAngles(), &forward ); + + CTakeDamageInfo info( this, GetThrower(), 1, DMG_CLUB ); + CalculateMeleeDamageForce( &info, forward, tr.endpos ); + pOther->DispatchTraceAttack( info, forward, &tr ); + ApplyMultiDamage(); + } + m_flNextAttack = gpGlobals->curtime + 1.0; // debounce + } + + Vector vecTestVelocity; + // m_vecAngVelocity = Vector (300, 300, 300); + + // this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical + // or thrown very far tend to slow down too quickly for me to always catch just by testing velocity. + // trimming the Z velocity a bit seems to help quite a bit. + vecTestVelocity = GetAbsVelocity(); + vecTestVelocity.z *= 0.45; + + if ( !m_bHasWarnedAI && vecTestVelocity.Length() <= 60 ) + { + // grenade is moving really slow. It's probably very close to where it will ultimately stop moving. + // emit the danger sound. + + // register a radius louder than the explosion, so we make sure everyone gets out of the way + CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), m_flDamage / 0.4, 0.3 ); + m_bHasWarnedAI = TRUE; + } + + // HACKHACK - On ground isn't always set, so look for ground underneath + trace_t tr; + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,10), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction < 1.0 ) + { + // add a bit of static friction +// SetAbsVelocity( GetAbsVelocity() * 0.8 ); + SetSequence( SelectWeightedSequence( ACT_IDLE ) ); + SetAbsAngles( vec3_angle ); + } + + // play bounce sound + BounceSound(); + + m_flPlaybackRate = GetAbsVelocity().Length() / 200.0; + if (m_flPlaybackRate > 1.0) + m_flPlaybackRate = 1; + else if (m_flPlaybackRate < 0.5) + m_flPlaybackRate = 0; +} + +#endif + +#ifdef CLIENT_DLL +#define CWeaponHandGrenade C_WeaponHandGrenade +#endif + +//----------------------------------------------------------------------------- +// CWeaponHandGrenade +//----------------------------------------------------------------------------- + +class CWeaponHandGrenade : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponHandGrenade, CBaseHL1MPCombatWeapon ); +public: + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponHandGrenade( void ); + + void Precache( void ); + void PrimaryAttack( void ); + void WeaponIdle( void ); + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + +// DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +private: +// float m_flStartThrow; +// float m_flReleaseThrow; + CNetworkVar( float, m_flStartThrow ); + CNetworkVar( float, m_flReleaseThrow ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponHandGrenade, DT_WeaponHandGrenade ); + +BEGIN_NETWORK_TABLE( CWeaponHandGrenade, DT_WeaponHandGrenade ) +#ifdef CLIENT_DLL + RecvPropFloat( RECVINFO( m_flStartThrow ) ), + RecvPropFloat( RECVINFO( m_flReleaseThrow ) ), +#else + SendPropFloat( SENDINFO( m_flStartThrow ) ), + SendPropFloat( SENDINFO( m_flReleaseThrow ) ), +#endif +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponHandGrenade ) +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_flStartThrow, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flReleaseThrow, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), +#endif +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_handgrenade, CWeaponHandGrenade ); + +PRECACHE_WEAPON_REGISTER( weapon_handgrenade ); + +//IMPLEMENT_SERVERCLASS_ST( CWeaponHandGrenade, DT_WeaponHandGrenade ) +//END_SEND_TABLE() + +BEGIN_DATADESC( CWeaponHandGrenade ) +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponHandGrenade::CWeaponHandGrenade( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponHandGrenade::Precache( void ) +{ +#ifndef CLIENT_DLL + UTIL_PrecacheOther( "grenade_hand" ); +#endif + + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponHandGrenade::PrimaryAttack( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( ( m_flStartThrow <= 0 ) && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + m_flStartThrow = gpGlobals->curtime; + m_flReleaseThrow = 0; + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + SetWeaponIdleTime( gpGlobals->curtime + 0.5 ); + } +} + + +void CWeaponHandGrenade::WeaponIdle( void ) +{ + if ( m_flReleaseThrow == 0 && m_flStartThrow ) + m_flReleaseThrow = gpGlobals->curtime; + + if ( !HasWeaponIdleTimeElapsed() ) + return; + + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( m_flStartThrow ) + { + Vector vecAiming = pPlayer->GetAutoaimVector( 0 ); + + QAngle angThrow; + VectorAngles( vecAiming, angThrow ); + + Vector vecUp; + Vector vecRight; + AngleVectors( angThrow, NULL, &vecRight, &vecUp ); + + if ( angThrow.x > 180 ) // player is pitching up + angThrow.x = -15 - ( 360 - angThrow.x ) * ( ( 90 - 10 ) / 90.0 ); + else // player is pitching down + angThrow.x = -15 + angThrow.x * ( ( 90 + 10 ) / 90.0 ); + + float flVel = ( 90 - angThrow.x ) * 4; + if ( flVel > 500 ) + flVel = 500; + + Vector vecFwd; + AngleVectors( angThrow, &vecFwd ); + + Vector vecSrc = pPlayer->EyePosition() + vecFwd * 16; + Vector vecThrow = vecFwd * flVel + pPlayer->GetAbsVelocity(); + + QAngle angles; + VectorAngles( vecThrow, angles ); +#ifndef CLIENT_DLL + CHandGrenade *pGrenade = (CHandGrenade*)Create( "grenade_hand", vecSrc, angles ); + if ( pGrenade ) + { + // always explode 3 seconds after the pin was pulled + float flTime = m_flStartThrow - gpGlobals->curtime + 3.0; + if ( flTime < 0 ) + { + flTime = 0; + } + + pGrenade->ShootTimed( pPlayer, vecThrow, flTime ); + } +#endif + + if ( flVel < 500 ) + { + SendWeaponAnim( ACT_HANDGRENADE_THROW1 ); + } + else if ( flVel < 1000 ) + { + SendWeaponAnim( ACT_HANDGRENADE_THROW2 ); + } + else + { + SendWeaponAnim( ACT_HANDGRENADE_THROW3 ); + } + + // player "shoot" animation + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_flReleaseThrow = 0; + m_flStartThrow = 0; + + SetWeaponIdleTime( gpGlobals->curtime + 0.5 ); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; + + pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); + + return; + } + else if ( m_flReleaseThrow > 0 ) + { + // we've finished the throw, restart. + m_flStartThrow = 0; + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + SendWeaponAnim( ACT_VM_DRAW ); + } + else + { +// RetireWeapon(); + return; + } + + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) ); + m_flReleaseThrow = -1; + return; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + float flRand = random->RandomFloat( 0, 1 ); + if ( flRand <= 0.75 ) + { + SendWeaponAnim( ACT_VM_IDLE ); + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) );// how long till we do this again. + } + else + { + SendWeaponAnim( ACT_VM_FIDGET ); + } + } +} + +bool CWeaponHandGrenade::Deploy( void ) +{ + m_flReleaseThrow = -1; + + return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() ); +} + +bool CWeaponHandGrenade::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return false; + } + + if ( m_flStartThrow > 0 ) + { + return false; + } + + if ( !BaseClass::Holster( pSwitchingTo ) ) + { + return false; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { +#ifndef CLIENT_DLL + SetThink( &CWeaponHandGrenade::DestroyItem ); + SetNextThink( gpGlobals->curtime + 0.1 ); +#endif + } + + pPlayer->SetNextAttack( gpGlobals->curtime + 0.5 ); + + return true; +} |