diff options
Diffstat (limited to 'game/shared/tf/tf_weapon_grenade_nail.cpp')
| -rw-r--r-- | game/shared/tf/tf_weapon_grenade_nail.cpp | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/game/shared/tf/tf_weapon_grenade_nail.cpp b/game/shared/tf/tf_weapon_grenade_nail.cpp new file mode 100644 index 0000000..5f1c2b2 --- /dev/null +++ b/game/shared/tf/tf_weapon_grenade_nail.cpp @@ -0,0 +1,316 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: TF Nail Grenade. +// +//=============================================================================// +#include "cbase.h" +#include "tf_weaponbase.h" +#include "tf_gamerules.h" +#include "npcevent.h" +#include "engine/IEngineSound.h" +#include "tf_weapon_grenade_nail.h" + +// Server specific. +#ifdef GAME_DLL +#include "tf_player.h" +#include "items.h" +#include "tf_weaponbase_grenadeproj.h" +#include "soundent.h" +#include "KeyValues.h" +#include "tf_projectile_nail.h" +#include "physics_saverestore.h" +#include "phys_controller.h" +#endif + +#define GRENADE_NAIL_TIMER 3.0f //Seconds + +//============================================================================= +// +// TF Nail Grenade tables. +// + +IMPLEMENT_NETWORKCLASS_ALIASED( TFGrenadeNail, DT_TFGrenadeNail ) + +BEGIN_NETWORK_TABLE( CTFGrenadeNail, DT_TFGrenadeNail ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CTFGrenadeNail ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( tf_weapon_grenade_nail, CTFGrenadeNail ); +PRECACHE_WEAPON_REGISTER( tf_weapon_grenade_nail ); + +//============================================================================= +// +// TF Nail Grenade functions. +// + +// Server specific. +#ifdef GAME_DLL + +BEGIN_DATADESC( CTFGrenadeNail ) +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFWeaponBaseGrenadeProj *CTFGrenadeNail::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, + AngularImpulse angImpulse, CBasePlayer *pPlayer, float flTime, int iflags ) +{ + return CTFGrenadeNailProjectile::Create( vecSrc, vecAngles, vecVel, angImpulse, + pPlayer, GetTFWpnData(), flTime ); +} + +#endif + +//============================================================================= +// +// TF Nail Grenade Projectile functions (Server specific). +// +#ifdef GAME_DLL + +BEGIN_DATADESC( CTFGrenadeNailProjectile ) + DEFINE_THINKFUNC( EmitNails ), + DEFINE_EMBEDDED( m_GrenadeController ), + DEFINE_PHYSPTR( m_pMotionController ), +END_DATADESC() + +#define GRENADE_MODEL "models/weapons/w_models/w_grenade_nail.mdl" + +LINK_ENTITY_TO_CLASS( tf_weapon_grenade_nail_projectile, CTFGrenadeNailProjectile ); +PRECACHE_WEAPON_REGISTER( tf_weapon_grenade_nail_projectile ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFGrenadeNailProjectile* CTFGrenadeNailProjectile::Create( const Vector &position, const QAngle &angles, + const Vector &velocity, const AngularImpulse &angVelocity, + CBaseCombatCharacter *pOwner, const CTFWeaponInfo &weaponInfo, float timer, int iFlags ) +{ + // Nail grenades are always thrown like discs + QAngle vecCustomAngles = angles; + vecCustomAngles.x = clamp( vecCustomAngles.x, -10,10 ); + vecCustomAngles.z = clamp( vecCustomAngles.x, -10,10 ); + Vector vecCustomAngVelocity = vec3_origin; + vecCustomAngVelocity.z = RandomFloat( -600, 600 ); + CTFGrenadeNailProjectile *pGrenade = static_cast<CTFGrenadeNailProjectile*>( CTFWeaponBaseGrenadeProj::Create( "tf_weapon_grenade_nail_projectile", position, vecCustomAngles, velocity, vecCustomAngVelocity, pOwner, weaponInfo, timer, iFlags ) ); + return pGrenade; +} + +CTFGrenadeNailProjectile::~CTFGrenadeNailProjectile() +{ + if ( m_pMotionController != NULL ) + { + physenv->DestroyMotionController( m_pMotionController ); + m_pMotionController = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrenadeNailProjectile::Spawn() +{ + SetModel( GRENADE_MODEL ); + + m_pMotionController = NULL; + + UseClientSideAnimation(); + + BaseClass::Spawn(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrenadeNailProjectile::Precache() +{ + PrecacheModel( GRENADE_MODEL ); + + PrecacheScriptSound( "Weapon_Grenade_Nail.Launch" ); + + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrenadeNailProjectile::BounceSound( void ) +{ + EmitSound( "Weapon_Grenade_Nail.Bounce" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrenadeNailProjectile::Detonate() +{ + if ( ShouldNotDetonate() ) + { + RemoveGrenade(); + return; + } + + StartEmittingNails(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFGrenadeNailProjectile::OnTakeDamage( const CTakeDamageInfo &info ) +{ + if ( m_pMotionController != NULL ) + { + // motioncontroller is animating us, dont take hits that will disorient us + return 0; + } + + return BaseClass::OnTakeDamage( info ); +} + +void CTFGrenadeNailProjectile::StartEmittingNails( void ) +{ + // 0.4 seconds later, emit nails + IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); + + if ( pPhysicsObject ) + { + m_pMotionController = physenv->CreateMotionController( &m_GrenadeController ); + m_pMotionController->AttachObject( pPhysicsObject, true ); + + pPhysicsObject->EnableGravity( false ); + + pPhysicsObject->Wake(); + } + + QAngle ang(0,0,0); + Vector pos = GetAbsOrigin(); + pos.z += 32; + m_GrenadeController.SetDesiredPosAndOrientation( pos, ang ); + + m_flNailAngle = 0; + m_iNumNailBurstsLeft = 40; + + int animDesired = SelectWeightedSequence( ACT_RANGE_ATTACK1 ); + ResetSequence( animDesired ); + SetPlaybackRate( 1.0 ); + + Vector soundPosition = GetAbsOrigin() + Vector( 0, 0, 5 ); + CPASAttenuationFilter filter( soundPosition ); + EmitSound( filter, entindex(), "Weapon_Grenade_Nail.Launch" ); + +#ifdef GAME_DLL + SetThink( &CTFGrenadeNailProjectile::EmitNails ); + SetNextThink( gpGlobals->curtime + 0.4 ); +#endif +} + +void CTFGrenadeNailProjectile::EmitNails( void ) +{ + m_iNumNailBurstsLeft--; + + if ( m_iNumNailBurstsLeft < 0 ) + { + BaseClass::Detonate(); + return; + } + + Vector forward, up; + float flAngleToAdd = random->RandomFloat( 30, 40 ); + + // else release some nails + for ( int i=0; i < 4 ;i++ ) + { + m_flNailAngle = UTIL_AngleMod( m_flNailAngle + flAngleToAdd ); + + QAngle angNail( random->RandomFloat( -3, 3 ), m_flNailAngle, 0 ); + + // Emit a nail + CTFProjectile_Nail *pNail = CTFProjectile_Nail::Create( GetAbsOrigin(), angNail, this, GetThrower() ); + if ( pNail ) + { + pNail->SetDamage( 18 ); + } + } + + SetNextThink( gpGlobals->curtime + 0.1 ); +} + +IMotionEvent::simresult_e CNailGrenadeController::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) +{ + // Try to get to m_vecDesiredPosition + + // Try to orient ourselves to m_angDesiredOrientation + + Vector currentPos; + QAngle currentAng; + + pObject->GetPosition( ¤tPos, ¤tAng ); + + Vector vecVel; + AngularImpulse angVel; + pObject->GetVelocity( &vecVel, &angVel ); + + linear.Init(); + angular.Init(); + + if ( m_bReachedPos ) + { + // Lock at this height + if ( vecVel.Length() > 1.0 ) + { + AngularImpulse nil( 0,0,0 ); + pObject->SetVelocityInstantaneous( &vec3_origin, &nil ); + + // For now teleport to the proper orientation + currentAng.x = 0; + currentAng.y = 0; + currentAng.z = 0; + pObject->SetPosition( currentPos, currentAng, true ); + } + } + else + { + // not at the right height yet, keep moving up + linear.z = 50 * ( m_vecDesiredPosition.z - currentPos.z ); + + if ( currentPos.z > m_vecDesiredPosition.z ) + { + // lock into position + m_bReachedPos = true; + } + + // Start rotating in the right direction + // we'll lock angles once we reach proper height to stop the oscillating + matrix3x4_t matrix; + // get the object's local to world transform + pObject->GetPositionMatrix( &matrix ); + + Vector m_worldGoalAxis(0,0,1); + + // Get the alignment axis in object space + Vector currentLocalTargetAxis; + VectorIRotate( m_worldGoalAxis, matrix, currentLocalTargetAxis ); + + float invDeltaTime = (1/deltaTime); + float m_angularLimit = 10; + + angular = ComputeRotSpeedToAlignAxes( m_worldGoalAxis, currentLocalTargetAxis, angVel, 1.0, invDeltaTime * invDeltaTime, m_angularLimit * invDeltaTime ); + } + + return SIM_GLOBAL_ACCELERATION; +} + +void CNailGrenadeController::SetDesiredPosAndOrientation( Vector pos, QAngle orientation ) +{ + m_vecDesiredPosition = pos; + m_angDesiredOrientation = orientation; + + m_bReachedPos = false; + m_bReachedOrientation = false; +} + +BEGIN_SIMPLE_DATADESC( CNailGrenadeController ) +END_DATADESC() + +#endif |