diff options
Diffstat (limited to 'game/shared/tf/tf_weaponbase_rocket.cpp')
| -rw-r--r-- | game/shared/tf/tf_weaponbase_rocket.cpp | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/game/shared/tf/tf_weaponbase_rocket.cpp b/game/shared/tf/tf_weaponbase_rocket.cpp new file mode 100644 index 0000000..52db211 --- /dev/null +++ b/game/shared/tf/tf_weaponbase_rocket.cpp @@ -0,0 +1,730 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: TF Base Rockets. +// +//=============================================================================// +#include "cbase.h" +#include "tf_weaponbase_rocket.h" + +// Server specific. +#ifdef GAME_DLL +#include "soundent.h" +#include "te_effect_dispatch.h" +#include "tf_fx.h" +#include "iscorer.h" +#include "tf_gamerules.h" +#include "func_nogrenades.h" +#include "tf_obj_sentrygun.h" + +extern void SendProxy_Origin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +extern void SendProxy_Angles( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +#endif + +#ifdef CLIENT_DLL +#include "props_shared.h" +#endif + +//w_rocket_airstrike\w_rocket_airstrike.mdl +#define MINI_ROCKETS_MODEL "models/weapons/w_models/w_rocket_airstrike/w_rocket_airstrike.mdl" + +//============================================================================= +// +// TF Base Rocket tables. +// + +IMPLEMENT_NETWORKCLASS_ALIASED( TFBaseRocket, DT_TFBaseRocket ) + +BEGIN_NETWORK_TABLE( CTFBaseRocket, DT_TFBaseRocket ) +// Client specific. +#ifdef CLIENT_DLL +RecvPropVector( RECVINFO( m_vInitialVelocity ) ), + +RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ), +RecvPropQAngles( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ), +RecvPropInt( RECVINFO( m_iDeflected ) ), +RecvPropEHandle( RECVINFO( m_hLauncher ) ), + +// Server specific. +#else +SendPropVector( SENDINFO( m_vInitialVelocity ), 12 /*nbits*/, 0 /*flags*/, -3000 /*low value*/, 3000 /*high value*/ ), + +SendPropExclude( "DT_BaseEntity", "m_vecOrigin" ), +SendPropExclude( "DT_BaseEntity", "m_angRotation" ), + +SendPropVector (SENDINFO(m_vecOrigin), -1, SPROP_COORD_MP_INTEGRAL|SPROP_CHANGES_OFTEN, 0.0f, HIGH_DEFAULT, SendProxy_Origin ), +SendPropQAngles (SENDINFO(m_angRotation), 6, SPROP_CHANGES_OFTEN, SendProxy_Angles ), +SendPropInt( SENDINFO( m_iDeflected ), 4, SPROP_UNSIGNED ), +SendPropEHandle( SENDINFO( m_hLauncher ) ), + +#endif +END_NETWORK_TABLE() + +// Server specific. +#ifdef GAME_DLL +BEGIN_DATADESC( CTFBaseRocket ) +END_DATADESC() +#endif + +#ifdef _DEBUG +ConVar tf_rocket_show_radius( "tf_rocket_show_radius", "0", FCVAR_REPLICATED | FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Render rocket radius." ); +#endif + +//============================================================================= +// +// Shared (client/server) functions. +// + +//----------------------------------------------------------------------------- +// Purpose: Constructor. +//----------------------------------------------------------------------------- +CTFBaseRocket::CTFBaseRocket() +{ + m_vInitialVelocity.Init(); + m_iDeflected = 0; + +// Client specific. +#ifdef CLIENT_DLL + + m_flSpawnTime = 0.0f; + m_iCachedDeflect = false; + +// Server specific. +#else + + m_flDamage = 0.0f; + m_flDestroyableTime = 0.0f; + m_bStunOnImpact = false; + m_flDamageForceScale = 1.0f; + +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor. +//----------------------------------------------------------------------------- +CTFBaseRocket::~CTFBaseRocket() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFBaseRocket::Precache( void ) +{ + BaseClass::Precache(); + PrecacheParticleSystem( "Explosion_ShockWave_01" ); + PrecacheModel( MINI_ROCKETS_MODEL ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFBaseRocket::Spawn( void ) +{ + BaseClass::Spawn(); + + // Precache. + Precache(); + UseClientSideAnimation(); + + if ( GetLauncher() ) + { + int iMiniRocket = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( GetLauncher(), iMiniRocket, mini_rockets ); + if ( iMiniRocket ) + { + SetModel( MINI_ROCKETS_MODEL ); + } + } + +// Client specific. +#ifdef CLIENT_DLL + + m_flSpawnTime = gpGlobals->curtime; + +// Server specific. +#else + + //Derived classes must have set model. + Assert( GetModel() ); + + SetSolid( SOLID_BBOX ); + SetMoveType( MOVETYPE_FLY, MOVECOLLIDE_FLY_CUSTOM ); + AddEFlags( EFL_NO_WATER_VELOCITY_CHANGE ); + AddEffects( EF_NOSHADOW ); + + SetCollisionGroup( TFCOLLISION_GROUP_ROCKETS ); + + UTIL_SetSize( this, -Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); + ResetSequence( LookupSequence("idle") ); + + // Setup attributes. + m_takedamage = DAMAGE_NO; + SetGravity( 0.0f ); + + // Setup the touch and think functions. + SetTouch( &CTFBaseRocket::RocketTouch ); + SetNextThink( gpGlobals->curtime ); + + AddFlag( FL_GRENADE ); + + m_flDestroyableTime = gpGlobals->curtime + TF_ROCKET_DESTROYABLE_TIMER; + m_bCritical = false; + +#endif +} + +//============================================================================= +// +// Client specific functions. +// +#ifdef CLIENT_DLL + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFBaseRocket::PostDataUpdate( DataUpdateType_t type ) +{ + // Pass through to the base class. + BaseClass::PostDataUpdate( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + // Now stick our initial velocity and angles into the interpolation history. + CInterpolatedVar<Vector> &interpolator = GetOriginInterpolator(); + interpolator.ClearHistory(); + + CInterpolatedVar<QAngle> &rotInterpolator = GetRotationInterpolator(); + rotInterpolator.ClearHistory(); + + float flChangeTime = GetLastChangeTime( LATCH_SIMULATION_VAR ); + + // Add a sample 1 second back. + Vector vCurOrigin = GetLocalOrigin() - m_vInitialVelocity; + interpolator.AddToHead( flChangeTime - 1.0f, &vCurOrigin, false ); + + QAngle vCurAngles = GetLocalAngles(); + rotInterpolator.AddToHead( flChangeTime - 1.0f, &vCurAngles, false ); + + // Add the current sample. + vCurOrigin = GetLocalOrigin(); + interpolator.AddToHead( flChangeTime, &vCurOrigin, false ); + + rotInterpolator.AddToHead( flChangeTime - 1.0, &vCurAngles, false ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFBaseRocket::OnDataChanged(DataUpdateType_t updateType) +{ + BaseClass::OnDataChanged(updateType); + + if ( updateType == DATA_UPDATE_CREATED || m_iCachedDeflect != GetDeflected() ) + { + CreateTrails(); + } + + m_iCachedDeflect = GetDeflected(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFBaseRocket::DrawModel( int flags ) +{ + // During the first 0.2 seconds of our life, don't draw ourselves. + if ( gpGlobals->curtime - m_flSpawnTime < 0.2f ) + return 0; + + return BaseClass::DrawModel( flags ); +} + +//============================================================================= +// +// Server specific functions. +// +#else + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFBaseRocket *CTFBaseRocket::Create( CBaseEntity *pLauncher, const char *pszClassname, const Vector &vecOrigin, + const QAngle &vecAngles, CBaseEntity *pOwner ) +{ + CTFBaseRocket *pRocket = static_cast<CTFBaseRocket*>( CBaseEntity::Create( pszClassname, vecOrigin, vecAngles, pOwner ) ); + if ( !pRocket ) + return NULL; + + pRocket->SetLauncher( pLauncher ); + + // Initialize the owner. + pRocket->SetOwnerEntity( pOwner ); + + // Spawn. + pRocket->Spawn(); + + // Setup the initial velocity. + Vector vecForward, vecRight, vecUp; + AngleVectors( vecAngles, &vecForward, &vecRight, &vecUp ); + + float flLaunchSpeed = 1100.0f; + CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pLauncher, flLaunchSpeed, mult_projectile_speed ); + + // Hack: This attribute represents a bucket of attributes - one of which is projectile speed. + // If the concept works we'll make the "bucket" system directly modify the attributes instead. + if ( pOwner ) + { + // if the owner is a Sentry, Check its owner + int iRocketSpecialist = 0; + CObjectSentrygun *pSentry = dynamic_cast<CObjectSentrygun*>( pOwner ); + if ( pSentry ) + { + CALL_ATTRIB_HOOK_INT_ON_OTHER( pSentry->GetOwner(), iRocketSpecialist, rocket_specialist ); + } + else + { + CALL_ATTRIB_HOOK_INT_ON_OTHER( pOwner, iRocketSpecialist, rocket_specialist ); + } + + if ( iRocketSpecialist ) + { + flLaunchSpeed *= RemapValClamped( iRocketSpecialist, 1.f, 4.f, 1.15f, 1.6f ); + flLaunchSpeed = Min( flLaunchSpeed, 3000.f ); + } + } + + CTFPlayer *pTFOwner = ToTFPlayer( pRocket->GetOwnerPlayer() ); + + if ( pTFOwner ) + { + pRocket->SetTruceValidForEnt( pTFOwner->IsTruceValidForEnt() ); + + if ( pTFOwner->m_Shared.GetCarryingRuneType() == RUNE_PRECISION ) + { + flLaunchSpeed = 3000.f; + } + } + + Vector vecVelocity = vecForward * flLaunchSpeed; + pRocket->SetAbsVelocity( vecVelocity ); + pRocket->SetupInitialTransmittedGrenadeVelocity( vecVelocity ); + + // Setup the initial angles. + QAngle angles; + VectorAngles( vecVelocity, angles ); + pRocket->SetAbsAngles( angles ); + + // Set team. + pRocket->ChangeTeam( pOwner->GetTeamNumber() ); + + return pRocket; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFBaseRocket::RocketTouch( CBaseEntity *pOther ) +{ + // Verify a correct "other." + Assert( pOther ); + bool bShield = pOther->IsCombatItem() && !InSameTeam( pOther ); + if ( pOther->IsSolidFlagSet( FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS ) && !bShield ) + return; + + // Handle hitting skybox (disappear). + const trace_t *pTrace = &CBaseEntity::GetTouchTrace(); + if( pTrace->surface.flags & SURF_SKY ) + { + UTIL_Remove( this ); + return; + } + + trace_t trace; + memcpy( &trace, pTrace, sizeof( trace_t ) ); + Explode( &trace, pOther ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +unsigned int CTFBaseRocket::PhysicsSolidMaskForEntity( void ) const +{ + int teamContents = 0; + + if ( !CanCollideWithTeammates() ) + { + // Only collide with the other team + teamContents = ( GetTeamNumber() == TF_TEAM_RED ) ? CONTENTS_BLUETEAM : CONTENTS_REDTEAM; + } + else + { + // Collide with both teams + teamContents = CONTENTS_REDTEAM | CONTENTS_BLUETEAM; + } + + return BaseClass::PhysicsSolidMaskForEntity() | teamContents; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFBaseRocket::ShouldNotDetonate( void ) +{ + return InNoGrenadeZone( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFBaseRocket::Destroy( bool bBlinkOut, bool bBreakRocket ) +{ + if ( bBreakRocket ) + { + CPVSFilter filter( GetAbsOrigin() ); + UserMessageBegin( filter, "BreakModelRocketDud" ); + WRITE_SHORT( GetModelIndex() ); + WRITE_VEC3COORD( GetAbsOrigin() ); + WRITE_ANGLES( GetAbsAngles() ); + MessageEnd(); + } + + // Kill it + SetThink( &BaseClass::SUB_Remove ); + SetNextThink( gpGlobals->curtime ); + SetTouch( NULL ); + AddEffects( EF_NODRAW ); + + if ( bBlinkOut ) + { + // Sprite flash + CSprite *pGlowSprite = CSprite::SpriteCreate( NOGRENADE_SPRITE, GetAbsOrigin(), false ); + if ( pGlowSprite ) + { + pGlowSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxFadeFast ); + pGlowSprite->SetThink( &CSprite::SUB_Remove ); + pGlowSprite->SetNextThink( gpGlobals->curtime + 1.0 ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFBaseRocket::Explode( trace_t *pTrace, CBaseEntity *pOther ) +{ + if ( ShouldNotDetonate() ) + { + Destroy( true ); + return; + } + + // Save this entity as enemy, they will take 100% damage. + m_hEnemy = pOther; + + // Invisible. + SetModelName( NULL_STRING ); + AddSolidFlags( FSOLID_NOT_SOLID ); + m_takedamage = DAMAGE_NO; + + // Pull out a bit. + if ( pTrace->fraction != 1.0 ) + { + SetAbsOrigin( pTrace->endpos + ( pTrace->plane.normal * 1.0f ) ); + } + + // Play explosion sound and effect. + Vector vecOrigin = GetAbsOrigin(); + CPVSFilter filter( vecOrigin ); + + // Halloween Spell Effect Check + int iHalloweenSpell = 0; + int iCustomParticleIndex = INVALID_STRING_INDEX; + item_definition_index_t ownerWeaponDefIndex = INVALID_ITEM_DEF_INDEX; + // if the owner is a Sentry, Check its owner + CBaseEntity *pPlayerOwner = GetOwnerPlayer(); + + if ( TF_IsHolidayActive( kHoliday_HalloweenOrFullMoon ) ) + { + CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayerOwner, iHalloweenSpell, halloween_pumpkin_explosions ); + if ( iHalloweenSpell > 0 ) + { + iCustomParticleIndex = GetParticleSystemIndex( "halloween_explosion" ); + } + } + + CTFWeaponBase *pWeapon = dynamic_cast< CTFWeaponBase * >( GetOriginalLauncher() ); + if ( pWeapon ) + { + ownerWeaponDefIndex = pWeapon->GetAttributeContainer()->GetItem()->GetItemDefIndex(); + } + + int iLargeExplosion = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayerOwner, iLargeExplosion, use_large_smoke_explosion ); + if ( iLargeExplosion > 0 ) + { + DispatchParticleEffect( "explosionTrail_seeds_mvm", GetAbsOrigin(), GetAbsAngles() ); + DispatchParticleEffect( "fluidSmokeExpl_ring_mvm", GetAbsOrigin(), GetAbsAngles() ); + } + + TE_TFExplosion( filter, 0.0f, vecOrigin, pTrace->plane.normal, GetWeaponID(), pOther->entindex(), ownerWeaponDefIndex, SPECIAL1, iCustomParticleIndex ); + + CSoundEnt::InsertSound ( SOUND_COMBAT, vecOrigin, 1024, 3.0 ); + + // Damage. + CBaseEntity *pAttacker = GetOwnerEntity(); + IScorer *pScorerInterface = dynamic_cast<IScorer*>( pAttacker ); + if ( pScorerInterface ) + { + pAttacker = pScorerInterface->GetScorer(); + } + else if ( pAttacker && pAttacker->GetOwnerEntity() ) + { + pAttacker = pAttacker->GetOwnerEntity(); + } + + float flRadius = GetRadius(); + + if ( pAttacker ) // No attacker, deal no damage. Otherwise we could potentially kill teammates. + { + CTFPlayer *pTarget = ToTFPlayer( GetEnemy() ); + if ( pTarget ) + { + // Rocket Specialist + CheckForStunOnImpact( pTarget ); + + if ( pTarget->GetTeamNumber() != pAttacker->GetTeamNumber() ) + { + IGameEvent *event = gameeventmanager->CreateEvent( "projectile_direct_hit" ); + if ( event ) + { + event->SetInt( "attacker", pAttacker->entindex() ); + event->SetInt( "victim", pTarget->entindex() ); + event->SetInt( "weapon_def_index", ownerWeaponDefIndex ); + + gameeventmanager->FireEvent( event, true ); + } + } + } + + CTakeDamageInfo info( this, pAttacker, GetOriginalLauncher(), vec3_origin, vecOrigin, GetDamage(), GetDamageType(), GetDamageCustom() ); + CTFRadiusDamageInfo radiusinfo( &info, vecOrigin, flRadius, NULL, TF_ROCKET_RADIUS_FOR_RJS, GetDamageForceScale() ); + TFGameRules()->RadiusDamage( radiusinfo ); + } + +#if defined( _DEBUG ) && defined( STAGING_ONLY ) + // Debug! + if ( tf_rocket_show_radius.GetBool() ) + { + DrawRadius( flRadius ); + } +#endif + + // Don't decal players with scorch. + if ( !pOther->IsPlayer() ) + { + UTIL_DecalTrace( pTrace, "Scorch" ); + } + + // Remove the rocket. + UTIL_Remove( this ); + + return; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFBaseRocket::CheckForStunOnImpact( CTFPlayer* pTarget ) +{ + if ( !m_bStunOnImpact ) + return; + + CTFPlayer *pAttacker = ToTFPlayer( GetOwnerPlayer() ); + if ( !pAttacker ) + return; + + int iRocketSpecialist = GetStunLevel(); + if ( !iRocketSpecialist ) + return; + + // Stun + float flStunAmount = pTarget->IsMiniBoss() ? 0.85f : 1.f; + float flStunTime = RemapValClamped( iRocketSpecialist, 1.f, 4.f, 0.5f, 0.75f ); + + pTarget->SetAbsVelocity( vec3_origin ); + pTarget->m_Shared.StunPlayer( flStunTime, flStunAmount, TF_STUN_MOVEMENT | TF_STUN_NO_EFFECTS, pAttacker ); + + if ( TFGameRules()->IsMannVsMachineMode() && pTarget->IsBot() && ( pAttacker->GetTeamNumber() == TF_TEAM_PVE_DEFENDERS ) ) + { + pAttacker->AwardAchievement( ACHIEVEMENT_TF_MVM_ROCKET_SPECIALIST_STUN_GRIND ); + } + + + // Effect + CPVSFilter filter( GetAbsOrigin() ); + TE_TFParticleEffect( filter, 0.0, "mvm_soldier_shockwave", GetAbsOrigin(), QAngle( 0, 0, 0 ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFBaseRocket::GetStunLevel( void ) +{ + CTFPlayer *pAttacker = ToTFPlayer( GetOwnerPlayer() ); + if ( !pAttacker ) + return 0; + + int iRocketSpecialist = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( pAttacker, iRocketSpecialist, rocket_specialist ); + return iRocketSpecialist; +} + +#ifdef STAGING_ONLY +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFBaseRocket::DrawRadius( float flRadius ) +{ + Vector pos = GetAbsOrigin(); + int r = 255; + int g = 0, b = 0; + float flLifetime = 10.0f; + bool bDepthTest = true; + + Vector edge, lastEdge; + NDebugOverlay::Line( pos, pos + Vector( 0, 0, 50 ), r, g, b, !bDepthTest, flLifetime ); + + lastEdge = Vector( flRadius + pos.x, pos.y, pos.z ); + float angle; + for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) + { + edge.x = flRadius * cos( DEG2RAD( angle ) ) + pos.x; + edge.y = pos.y; + edge.z = flRadius * sin( DEG2RAD( angle ) ) + pos.z; + + NDebugOverlay::Line( edge, lastEdge, r, g, b, !bDepthTest, flLifetime ); + + lastEdge = edge; + } + + lastEdge = Vector( pos.x, flRadius + pos.y, pos.z ); + for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) + { + edge.x = pos.x; + edge.y = flRadius * cos( DEG2RAD( angle ) ) + pos.y; + edge.z = flRadius * sin( DEG2RAD( angle ) ) + pos.z; + + NDebugOverlay::Line( edge, lastEdge, r, g, b, !bDepthTest, flLifetime ); + + lastEdge = edge; + } + + lastEdge = Vector( pos.x, flRadius + pos.y, pos.z ); + for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) + { + edge.x = flRadius * cos( DEG2RAD( angle ) ) + pos.x; + edge.y = flRadius * sin( DEG2RAD( angle ) ) + pos.y; + edge.z = pos.z; + + NDebugOverlay::Line( edge, lastEdge, r, g, b, !bDepthTest, flLifetime ); + + lastEdge = edge; + } +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CTFBaseRocket::GetRadius() +{ + float flRadius = TF_ROCKET_RADIUS; + CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( m_hLauncher, flRadius, mult_explosion_radius ); + + CBaseEntity *pAttacker = GetOwnerPlayer(); + if ( pAttacker ) + { + int iRocketSpecialist = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( pAttacker, iRocketSpecialist, rocket_specialist ); + if ( iRocketSpecialist ) + { + bool bDirectHit = ( GetEnemy() && GetEnemy()->GetTeamNumber() != pAttacker->GetTeamNumber() && + ( GetEnemy()->IsPlayer() || GetEnemy()->MyCombatCharacterPointer() ) ); + // If we have the Rocket Specialist attribute and hit an enemy combatant directly... + if ( bDirectHit ) + { + // Increased blast radius + flRadius *= RemapValClamped( iRocketSpecialist, 1.f, 4.f, 1.15f, 1.6f ); + m_bStunOnImpact = true; + } + } + + CTFPlayer *pTFPlayer = ToTFPlayer( pAttacker ); + // Airstrike gets a small blast radius penalty while Rjing + if ( pTFPlayer && pTFPlayer->m_Shared.InCond( TF_COND_BLASTJUMPING ) ) + { + // Using this attr to key in the AirStrike + float flRocketJumpAttackBonus = 1.0f; + CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pAttacker, flRocketJumpAttackBonus, rocketjump_attackrate_bonus ); + if ( flRocketJumpAttackBonus != 1.0f ) + { + flRadius *= 0.80; + } + } + } + + return flRadius; +} + + +//----------------------------------------------------------------------------- +// Checks if the owner is a sentry gun, if so returns the sentry guns owner +//----------------------------------------------------------------------------- +CBaseEntity *CTFBaseRocket::GetOwnerPlayer( void ) const +{ + // if the owner is a Sentry, Check its owner + CBaseEntity *pOwner = GetOwnerEntity(); + CObjectSentrygun *pSentry = dynamic_cast<CObjectSentrygun*>( pOwner ); + + if ( pSentry ) + { + return pSentry->GetOwner(); + } + return pOwner; +} + +#endif + +#if defined( CLIENT_DLL ) + +//----------------------------------------------------------------------------- +// Receive the BreakModelRocketDud user message +//----------------------------------------------------------------------------- +void __MsgFunc_BreakModelRocketDud( bf_read &msg ) +{ + int nModelIndex = (int)msg.ReadShort(); + CUtlVector<breakmodel_t> aGibs; + BuildGibList( aGibs, nModelIndex, 1.0f, COLLISION_GROUP_NONE ); + if ( !aGibs.Count() ) + return; + + // Get the origin & angles + Vector vecOrigin, vecForward; + QAngle vecAngles; + msg.ReadBitVec3Coord( vecOrigin ); + msg.ReadBitAngles( vecAngles ); + + AngleVectors( vecAngles, &vecForward ); + + Vector vecBreakVelocity = Vector(0,0,300) + vecForward*-400; + AngularImpulse angularImpulse( 0, RandomFloat( -500, -3000 ), 0 ); + breakablepropparams_t breakParams( vecOrigin, vecAngles, vecBreakVelocity, angularImpulse ); + breakParams.impactEnergyScale = 1.0f; + + CreateGibsFromList( aGibs, nModelIndex, NULL, breakParams, NULL, -1 , false, true ); +} + +#endif
\ No newline at end of file |