diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/dod/dod_basegrenade.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/server/dod/dod_basegrenade.cpp')
| -rw-r--r-- | game/server/dod/dod_basegrenade.cpp | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/game/server/dod/dod_basegrenade.cpp b/game/server/dod/dod_basegrenade.cpp new file mode 100644 index 0000000..9420a08 --- /dev/null +++ b/game/server/dod/dod_basegrenade.cpp @@ -0,0 +1,526 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "dod_basegrenade.h" +#include "dod_player.h" +#include "dod_gamerules.h" +#include "func_break.h" +#include "physics_saverestore.h" +#include "grenadetrail.h" +#include "fx_dod_shared.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +float GetCurrentGravity( void ); + +ConVar dod_grenadegravity( "dod_grenadegravity", "-420", FCVAR_CHEAT, "gravity applied to grenades", true, -2000, true, -300 ); +extern ConVar dod_bonusround; + +IMotionEvent::simresult_e CGrenadeController::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) +{ + linear.x = linear.y = 0; + linear.z = dod_grenadegravity.GetFloat(); + + angular.x = angular.y = angular.z = 0; + + return SIM_GLOBAL_ACCELERATION; +} + +BEGIN_SIMPLE_DATADESC( CGrenadeController ) +END_DATADESC() + +BEGIN_DATADESC( CDODBaseGrenade ) + + DEFINE_THINKFUNC( DetonateThink ), + + DEFINE_EMBEDDED( m_GrenadeController ), + DEFINE_PHYSPTR( m_pMotionController ), // probably not necessary + +END_DATADESC() + +IMPLEMENT_SERVERCLASS_ST( CDODBaseGrenade, DT_DODBaseGrenade ) + SendPropVector( SENDINFO( m_vInitialVelocity ), + 20, // nbits + 0, // flags + -3000, // low value + 3000 // high value + ) +END_SEND_TABLE() + +CDODBaseGrenade::CDODBaseGrenade() +{ +} + +CDODBaseGrenade::~CDODBaseGrenade( void ) +{ + if ( m_pMotionController != NULL ) + { + physenv->DestroyMotionController( m_pMotionController ); + m_pMotionController = NULL; + } +} + +void CDODBaseGrenade::Spawn( void ) +{ + m_bUseVPhysics = true; + + BaseClass::Spawn(); + + SetSolid( SOLID_BBOX ); // So it will collide with physics props! + + UTIL_SetSize( this, Vector(-4,-4,-4), Vector(4,4,4) ); + + if( m_bUseVPhysics ) + { + SetCollisionGroup( COLLISION_GROUP_WEAPON ); + IPhysicsObject *pPhysicsObject = VPhysicsInitNormal( SOLID_BBOX, 0, false ); + + if ( pPhysicsObject ) + { + m_pMotionController = physenv->CreateMotionController( &m_GrenadeController ); + m_pMotionController->AttachObject( pPhysicsObject, true ); + + pPhysicsObject->EnableGravity( false ); + } + + m_takedamage = DAMAGE_EVENTS_ONLY; + } + else + { + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM ); + m_takedamage = DAMAGE_NO; + } + + AddSolidFlags( FSOLID_NOT_STANDABLE ); + + m_iHealth = 1; + + SetFriction( GetGrenadeFriction() ); + SetElasticity( GetGrenadeElasticity() ); + + // Remember our owner's team + ChangeTeam( GetThrower()->GetTeamNumber() ); + + m_flDamage = 150; + m_DmgRadius = m_flDamage * 2.5f; + + // Don't collide with players on the owner's team for the first bit of our life + m_flCollideWithTeammatesTime = gpGlobals->curtime + 0.25; + m_bCollideWithTeammates = false; + + SetThink( &CDODBaseGrenade::DetonateThink ); + SetNextThink( gpGlobals->curtime + 0.1 ); +} + +void CDODBaseGrenade::Precache( void ) +{ + BaseClass::Precache(); + + PrecacheParticleSystem( "grenadetrail" ); + PrecacheParticleSystem( "riflegrenadetrail" ); + PrecacheParticleSystem( "explosioncore_midair" ); + PrecacheParticleSystem( "explosioncore_floor" ); +} + +void CDODBaseGrenade::DetonateThink( void ) +{ + if (!IsInWorld()) + { + Remove( ); + return; + } + + if ( gpGlobals->curtime > m_flCollideWithTeammatesTime && m_bCollideWithTeammates == false ) + { + m_bCollideWithTeammates = true; + } + + Vector foo; + AngularImpulse a; + + VPhysicsGetObject()->GetVelocity( &foo, &a ); + + if( gpGlobals->curtime > m_flDetonateTime ) + { + Detonate(); + return; + } + + if (GetWaterLevel() != 0) + { + SetAbsVelocity( GetAbsVelocity() * 0.5 ); + } + + SetNextThink( gpGlobals->curtime + 0.2 ); +} + +//Sets the time at which the grenade will explode +void CDODBaseGrenade::SetDetonateTimerLength( float timer ) +{ + m_flDetonateTime = gpGlobals->curtime + timer; +} + +void CDODBaseGrenade::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity ) +{ + //Assume all surfaces have the same elasticity + float flSurfaceElasticity = 1.0; + + //Don't bounce off of players with perfect elasticity + if( trace.m_pEnt && trace.m_pEnt->IsPlayer() ) + { + flSurfaceElasticity = 0.3; + } + + float flTotalElasticity = GetElasticity() * flSurfaceElasticity; + flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f ); + + // NOTE: A backoff of 2.0f is a reflection + Vector vecAbsVelocity; + PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f ); + vecAbsVelocity *= flTotalElasticity; + + // Get the total velocity (player + conveyors, etc.) + VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity ); + float flSpeedSqr = DotProduct( vecVelocity, vecVelocity ); + + // Stop if on ground. + if ( trace.plane.normal.z > 0.7f ) // Floor + { + // Verify that we have an entity. + CBaseEntity *pEntity = trace.m_pEnt; + Assert( pEntity ); + + // Are we on the ground? + if ( vecVelocity.z < ( GetCurrentGravity() * gpGlobals->frametime ) ) + { + if ( pEntity->IsStandable() ) + { + SetGroundEntity( pEntity ); + } + + vecAbsVelocity.z = 0.0f; + } + SetAbsVelocity( vecAbsVelocity ); + + if ( flSpeedSqr < ( 30 * 30 ) ) + { + if ( pEntity->IsStandable() ) + { + SetGroundEntity( pEntity ); + } + + // Reset velocities. + SetAbsVelocity( vec3_origin ); + SetLocalAngularVelocity( vec3_angle ); + } + else + { + Vector vecDelta = GetBaseVelocity() - vecAbsVelocity; + Vector vecBaseDir = GetBaseVelocity(); + VectorNormalize( vecBaseDir ); + float flScale = vecDelta.Dot( vecBaseDir ); + + VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity ); + VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity ); + PhysicsPushEntity( vecVelocity, &trace ); + } + } + else + { + // If we get *too* slow, we'll stick without ever coming to rest because + // we'll get pushed down by gravity faster than we can escape from the wall. + if ( flSpeedSqr < ( 30 * 30 ) ) + { + // Reset velocities. + SetAbsVelocity( vec3_origin ); + SetLocalAngularVelocity( vec3_angle ); + } + else + { + SetAbsVelocity( vecAbsVelocity ); + } + } + + BounceSound(); +} + +char *CDODBaseGrenade::GetExplodingClassname( void ) +{ + Assert( !"Baseclass must implement this" ); + return NULL; +} + +void CDODBaseGrenade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanBePickedUp() ) + return; + + if ( !pActivator->IsPlayer() ) + return; + + CDODPlayer *pPlayer = ToDODPlayer( pActivator ); + + //Don't pick up grenades while deployed + CBaseCombatWeapon *pWpn = pPlayer->GetActiveWeapon(); + if ( pWpn && !pWpn->CanHolster() ) + { + return; + } + + DODRoundState state = DODGameRules()->State_Get(); + + if ( dod_bonusround.GetBool() ) + { + int team = pPlayer->GetTeamNumber(); + + // if its after the round and bonus round is on, we can only pick it up if we are winners + + if ( team == TEAM_ALLIES && state == STATE_AXIS_WIN ) + return; + + if ( team == TEAM_AXIS && state == STATE_ALLIES_WIN ) + return; + } + else + { + // if its after the round, and bonus round is off, don't allow anyone to pick it up + if ( state != STATE_RND_RUNNING ) + return; + } + + OnPickedUp(); + + char *szClsName = GetExplodingClassname(); + + Assert( szClsName ); + + CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon *>( pPlayer->GiveNamedItem( szClsName ) ); + + Assert( pWeapon && "Wpn pointer has to be valid for us to pick up this grenade" ); + + if( pWeapon ) + { + variant_t flDetTime; + flDetTime.SetFloat( m_flDetonateTime ); + pWeapon->AcceptInput( "DetonateTime", this, this, flDetTime, 0 ); + +#ifdef DBGFLAG_ASSERT + bool bSuccess = +#endif + pPlayer->Weapon_Switch( pWeapon ); + + Assert( bSuccess ); + + //Remove the one we picked up + SetThink( NULL ); + UTIL_Remove( this ); + } +} + +int CDODBaseGrenade::OnTakeDamage( const CTakeDamageInfo &info ) +{ + if( info.GetDamageType() & DMG_BULLET ) + { + // Don't allow players to shoot grenades + return 0; + } + else if( info.GetDamageType() & DMG_BLAST ) + { + // Don't allow explosion force to move grenades + return 0; + } + + VPhysicsTakeDamage( info ); + + return BaseClass::OnTakeDamage( info ); +} + +void CDODBaseGrenade::Detonate() +{ + // Don't explode after the round has ended + if ( dod_bonusround.GetBool() == false && DODGameRules()->State_Get() != STATE_RND_RUNNING ) + { + SetDamage( 0 ); + } + + // stun players in a radius + const float flStunDamage = 100; + + CTakeDamageInfo info( this, GetThrower(), GetBlastForce(), GetAbsOrigin(), flStunDamage, DMG_STUN ); + DODGameRules()->RadiusStun( info, GetAbsOrigin(), m_DmgRadius ); + + BaseClass::Detonate(); +} + +bool CDODBaseGrenade::CreateVPhysics() +{ + // Create the object in the physics system + VPhysicsInitNormal( SOLID_BBOX, 0, false ); + return true; +} + +void CDODBaseGrenade::Explode( trace_t *pTrace, int bitsDamageType ) +{ + SetModelName( NULL_STRING );//invisible + AddSolidFlags( FSOLID_NOT_SOLID ); + + m_takedamage = DAMAGE_NO; + + // Pull out of the wall a bit + if ( pTrace->fraction != 1.0 ) + { + SetAbsOrigin( pTrace->endpos + (pTrace->plane.normal * 0.6) ); + } + + // Explosion effect on client + Vector vecOrigin = GetAbsOrigin(); + CPVSFilter filter( vecOrigin ); + TE_DODExplosion( filter, 0.0f, vecOrigin, pTrace->plane.normal ); + + // Use the thrower's position as the reported position + Vector vecReported = GetThrower() ? GetThrower()->GetAbsOrigin() : vec3_origin; + + CTakeDamageInfo info( this, GetThrower(), GetBlastForce(), GetAbsOrigin(), m_flDamage, bitsDamageType, 0, &vecReported ); + + RadiusDamage( info, vecOrigin, GetDamageRadius(), CLASS_NONE, NULL ); + + // Don't decal players with scorch. + if ( pTrace->m_pEnt && !pTrace->m_pEnt->IsPlayer() ) + { + UTIL_DecalTrace( pTrace, "Scorch" ); + } + + SetThink( &CBaseGrenade::SUB_Remove ); + SetTouch( NULL ); + + AddEffects( EF_NODRAW ); + SetAbsVelocity( vec3_origin ); + SetNextThink( gpGlobals->curtime ); +} + +// this will hit only things that are in newCollisionGroup, but NOT in collisionGroupAlreadyChecked +class CTraceFilterCollisionGroupDelta : public CTraceFilterEntitiesOnly +{ +public: + // It does have a base, but we'll never network anything below here.. + DECLARE_CLASS_NOBASE( CTraceFilterCollisionGroupDelta ); + + CTraceFilterCollisionGroupDelta( const IHandleEntity *passentity, int collisionGroupAlreadyChecked, int newCollisionGroup ) + : m_pPassEnt(passentity), m_collisionGroupAlreadyChecked( collisionGroupAlreadyChecked ), m_newCollisionGroup( newCollisionGroup ) + { + } + + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ) + { + if ( !PassServerEntityFilter( pHandleEntity, m_pPassEnt ) ) + return false; + CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity ); + + if ( pEntity ) + { + if ( g_pGameRules->ShouldCollide( m_collisionGroupAlreadyChecked, pEntity->GetCollisionGroup() ) ) + return false; + if ( g_pGameRules->ShouldCollide( m_newCollisionGroup, pEntity->GetCollisionGroup() ) ) + return true; + } + + return false; + } + +protected: + const IHandleEntity *m_pPassEnt; + int m_collisionGroupAlreadyChecked; + int m_newCollisionGroup; +}; + + +const float GRENADE_COEFFICIENT_OF_RESTITUTION = 0.2f; + +void CDODBaseGrenade::VPhysicsUpdate( IPhysicsObject *pPhysics ) +{ + BaseClass::VPhysicsUpdate( pPhysics ); + Vector vel; + AngularImpulse angVel; + pPhysics->GetVelocity( &vel, &angVel ); + + Vector start = GetAbsOrigin(); + // find all entities that my collision group wouldn't hit, but COLLISION_GROUP_NONE would and bounce off of them as a ray cast + CTraceFilterCollisionGroupDelta filter( this, GetCollisionGroup(), COLLISION_GROUP_NONE ); + trace_t tr; + + UTIL_TraceLine( start, start + vel * gpGlobals->frametime, CONTENTS_HITBOX|CONTENTS_MONSTER|CONTENTS_SOLID, &filter, &tr ); + + bool bHitTeammate = false; + + if ( m_bCollideWithTeammates == false && tr.m_pEnt && tr.m_pEnt->IsPlayer() && tr.m_pEnt->GetTeamNumber() == GetTeamNumber() ) + { + bHitTeammate = true; + } + + if ( tr.startsolid ) + { + if ( m_bInSolid == false && bHitTeammate == false ) + { + // UNDONE: Do a better contact solution that uses relative velocity? + vel *= -GRENADE_COEFFICIENT_OF_RESTITUTION; // bounce backwards + pPhysics->SetVelocity( &vel, NULL ); + } + m_bInSolid = true; + return; + } + m_bInSolid = false; + if ( tr.DidHit() && bHitTeammate == false ) + { + Vector dir = vel; + VectorNormalize(dir); + + float flPercent = vel.Length() / 2000; + float flDmg = 5 * flPercent; + + // send a tiny amount of damage so the character will react to getting bonked + CTakeDamageInfo info( this, GetThrower(), pPhysics->GetMass() * vel, GetAbsOrigin(), flDmg, DMG_CRUSH ); + tr.m_pEnt->DispatchTraceAttack( info, dir, &tr ); + ApplyMultiDamage(); + + if ( vel.Length() > 1000 ) + { + CTakeDamageInfo stunInfo( this, GetThrower(), vec3_origin, GetAbsOrigin(), flDmg, DMG_STUN ); + tr.m_pEnt->TakeDamage( stunInfo ); + } + + // reflect velocity around normal + vel = -2.0f * tr.plane.normal * DotProduct(vel,tr.plane.normal) + vel; + + // absorb 80% in impact + vel *= GetElasticity(); + angVel *= -0.5f; + pPhysics->SetVelocity( &vel, &angVel ); + } +} + +float CDODBaseGrenade::GetElasticity( void ) +{ + return GRENADE_COEFFICIENT_OF_RESTITUTION; +} + +const float DOD_GRENADE_WINDOW_BREAK_DAMPING_AMOUNT = 0.5f; + +// If we hit a window, let it break and continue on our way +// with a damped speed +void CDODBaseGrenade::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) +{ + CBreakable *pBreakable = dynamic_cast<CBreakable*>( pEvent->pEntities[!index] ); + if ( pBreakable && pBreakable->GetMaterialType() == matGlass && VPhysicsGetObject() ) + { + // don't stop, go through this entity after breaking it + Vector dampedVelocity = DOD_GRENADE_WINDOW_BREAK_DAMPING_AMOUNT * pEvent->preVelocity[index]; + VPhysicsGetObject()->SetVelocity( &dampedVelocity, &pEvent->preAngularVelocity[index] ); + } + else + BaseClass::VPhysicsCollision( index, pEvent ); +} |