sqwarmed/sdk_src/game/server/swarm/asw_rifle_grenade.cpp

356 lines
10 KiB
C++

#include "cbase.h"
#include "asw_rifle_grenade.h"
#include "Sprite.h"
#include "SpriteTrail.h"
#include "soundent.h"
#include "te_effect_dispatch.h"
#include "IEffects.h"
#include "asw_gamerules.h"
#include "iasw_spawnable_npc.h"
#include "world.h"
#include "asw_util_shared.h"
#include "asw_marine.h"
#include "asw_marine_resource.h"
#include "asw_fx_shared.h"
#include "particle_parse.h"
#include "asw_achievements.h"
#include "asw_player.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern ConVar sk_plr_dmg_asw_r_g;
ConVar asw_grenade_radius("asw_grenade_radius", "350", FCVAR_CHEAT, "Radius of the rifle's grenade explosion");
const float GRENADE_COEFFICIENT_OF_RESTITUTION = 0.2f;
#define GRENADE_MODEL "models/swarm/grenades/RifleGrenadeProjectile.mdl"
LINK_ENTITY_TO_CLASS( asw_rifle_grenade, CASW_Rifle_Grenade );
PRECACHE_REGISTER(asw_rifle_grenade);
BEGIN_DATADESC( CASW_Rifle_Grenade )
DEFINE_FUNCTION( GrenadeTouch ),
DEFINE_FIELD( m_inSolid, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flDamage, FIELD_FLOAT ),
DEFINE_FIELD( m_DmgRadius, FIELD_FLOAT ),
END_DATADESC()
extern int g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the smoke cloud
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CASW_Rifle_Grenade::~CASW_Rifle_Grenade( void )
{
KillEffects();
}
void CASW_Rifle_Grenade::Spawn( void )
{
Precache( );
SetModel( GRENADE_MODEL );
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
m_flDamage = sk_plr_dmg_asw_r_g.GetFloat();
m_DmgRadius = asw_grenade_radius.GetFloat();
m_takedamage = DAMAGE_NO;
SetSize( -Vector(1,1,1), Vector(1,1,1) );
SetSolid( SOLID_BBOX );
SetGravity( 0.05f );
SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
//CreateVPhysics();
SetTouch( &CASW_Rifle_Grenade::GrenadeTouch );
CreateEffects();
//AddSolidFlags( FSOLID_NOT_STANDABLE );
//BaseClass::Spawn();
// projectile only lasts 1 second
SetThink( &CASW_Rifle_Grenade::SUB_Remove );
SetNextThink( gpGlobals->curtime + 1.0f );
//AddSolidFlags(FSOLID_TRIGGER);
//m_pLastHit = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CASW_Rifle_Grenade::OnRestore( void )
{
CreateEffects();
BaseClass::OnRestore();
}
void CASW_Rifle_Grenade::KillEffects()
{
}
ConVar asw_grentrail_brightness("asw_grentrail_brightness", "128");
ConVar asw_grentrail_width("asw_grentrail_width", "6.0f");
ConVar asw_grentrail_widthend("asw_grentrail_widthend", "1.0f");
ConVar asw_grentrail_lifetime("asw_grentrail_lifetime", "0.2f");
ConVar asw_grentrail_fade("asw_grentrail_fade", "100");
void CASW_Rifle_Grenade::CreateEffects( void )
{
CEffectData data;
data.m_vOrigin = GetAbsOrigin();
CPASFilter filter( data.m_vOrigin );
filter.SetIgnorePredictionCull(true);
DispatchParticleEffect( "rifle_grenade_fx", PATTACH_ABSORIGIN_FOLLOW, this, "fuse", false, -1, &filter );
/*
int nAttachment = LookupAttachment( "fuse" );
m_pGlowTrail = CSpriteTrail::SpriteTrailCreate( "swarm/sprites/greylaser1.vmt", GetLocalOrigin(), false );
if ( m_pGlowTrail != NULL )
{
m_pGlowTrail->FollowEntity( this );
m_pGlowTrail->SetAttachment( this, nAttachment );
m_pGlowTrail->SetTransparency( kRenderTransAdd, 255, 255, 255, asw_grentrail_brightness.GetInt(), kRenderFxNone );
m_pGlowTrail->SetStartWidth( asw_grentrail_width.GetFloat() );
m_pGlowTrail->SetEndWidth( asw_grentrail_widthend.GetFloat() );
m_pGlowTrail->SetLifeTime( asw_grentrail_lifetime.GetFloat() );
m_pGlowTrail->SetMinFadeLength(asw_grentrail_fade.GetFloat());
}
*/
}
bool CASW_Rifle_Grenade::CreateVPhysics()
{
// Create the object in the physics system
VPhysicsInitNormal( SOLID_BBOX, FSOLID_NOT_STANDABLE, false );
return true;
}
unsigned int CASW_Rifle_Grenade::PhysicsSolidMaskForEntity() const
{
return ( BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_HITBOX );
//return ( BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_HITBOX ) | CONTENTS_GRATE;
}
void CASW_Rifle_Grenade::Precache( void )
{
PrecacheModel( GRENADE_MODEL );
BaseClass::Precache();
}
void CASW_Rifle_Grenade::GrenadeTouch( CBaseEntity *pOther )
{
if (!pOther)
return;
if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
return;
// make sure we don't die on things we shouldn't
if (!ASWGameRules() || !ASWGameRules()->ShouldCollide(GetCollisionGroup(), pOther->GetCollisionGroup()))
return;
Detonate();
return;
if ( pOther->m_takedamage != DAMAGE_NO )
{
trace_t tr, tr2;
tr = BaseClass::GetTouchTrace();
Vector vecNormalizedVel = GetAbsVelocity();
ClearMultiDamage();
VectorNormalize( vecNormalizedVel );
if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->IsNPC() )
{
CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_flDamage, DMG_NEVERGIB );
dmgInfo.AdjustPlayerDamageInflictedForSkillLevel();
CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f );
dmgInfo.SetDamagePosition( tr.endpos );
pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
}
else
{
CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_flDamage, DMG_BULLET | DMG_NEVERGIB );
CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f );
dmgInfo.SetDamagePosition( tr.endpos );
pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
}
ApplyMultiDamage();
// play body "thwack" sound
EmitSound( "Weapon_Crossbow.BoltHitBody" );
Vector vForward;
AngleVectors( GetAbsAngles(), &vForward );
VectorNormalize ( vForward );
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vForward * 128, MASK_OPAQUE, pOther, COLLISION_GROUP_NONE, &tr2 );
if ( tr2.fraction != 1.0f )
{
// NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 );
// NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 );
if ( tr2.m_pEnt == NULL || ( tr2.m_pEnt && tr2.m_pEnt->GetMoveType() == MOVETYPE_NONE ) )
{
CEffectData data;
data.m_vOrigin = tr2.endpos;
data.m_vNormal = vForward;
data.m_nEntIndex = tr2.fraction != 1.0f;
//DispatchEffect( "BoltImpact", data );
}
}
SetTouch( NULL );
SetThink( NULL );
KillEffects();
UTIL_Remove( this );
}
else
{
trace_t tr;
tr = BaseClass::GetTouchTrace();
// See if we struck the world
if ( pOther->GetMoveType() == MOVETYPE_NONE && !( tr.surface.flags & SURF_SKY ) )
{
//EmitSound( "Weapon_Crossbow.BoltHitWorld" );
// if what we hit is static architecture, can stay around for a while.
Vector vecDir = GetAbsVelocity();
VectorNormalize( vecDir );
SetMoveType( MOVETYPE_NONE );
Vector vForward;
AngleVectors( GetAbsAngles(), &vForward );
VectorNormalize ( vForward );
CEffectData data;
data.m_vOrigin = tr.endpos;
data.m_vNormal = vForward;
data.m_nEntIndex = 0;
//DispatchEffect( "BoltImpact", data );
UTIL_ImpactTrace( &tr, DMG_BULLET );
AddEffects( EF_NODRAW );
SetTouch( NULL );
KillEffects();
SetThink( &CASW_Rifle_Grenade::SUB_Remove );
SetNextThink( gpGlobals->curtime + 2.0f );
// Shoot some sparks
if ( UTIL_PointContents( GetAbsOrigin(), CONTENTS_WATER ) != CONTENTS_WATER)
{
g_pEffects->Sparks( GetAbsOrigin() );
}
}
else
{
// Put a mark unless we've hit the sky
if ( ( tr.surface.flags & SURF_SKY ) == false )
{
UTIL_ImpactTrace( &tr, DMG_BULLET );
}
KillEffects();
UTIL_Remove( this );
}
}
}
CASW_Rifle_Grenade* CASW_Rifle_Grenade::Rifle_Grenade_Create( float flDamage, float fRadius, const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, CBaseEntity *pOwner, CBaseEntity *pCreator )
{
CASW_Rifle_Grenade *pGrenade = (CASW_Rifle_Grenade *)CreateEntityByName( "asw_rifle_grenade" );
pGrenade->SetAbsAngles( angles );
pGrenade->Spawn();
pGrenade->m_flDamage = flDamage;
pGrenade->m_DmgRadius = fRadius;
pGrenade->SetOwnerEntity( pOwner );
UTIL_SetOrigin( pGrenade, position );
pGrenade->SetAbsVelocity( velocity );
pGrenade->m_hCreatorWeapon.Set( pCreator );
return pGrenade;
}
extern ConVar asw_medal_explosive_kills;
void CASW_Rifle_Grenade::Detonate()
{
m_takedamage = DAMAGE_NO;
Vector vecForward = GetAbsVelocity();
VectorNormalize(vecForward);
trace_t tr;
UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + 60*vecForward, MASK_SHOT,
this, COLLISION_GROUP_NONE, &tr);
if ((tr.m_pEnt != GetWorldEntity()) || (tr.hitbox != 0))
{
// non-world needs smaller decals
if( tr.m_pEnt && !tr.m_pEnt->IsNPC() )
{
UTIL_DecalTrace( &tr, "SmallScorch" );
}
}
else
{
UTIL_DecalTrace( &tr, "Scorch" );
}
UTIL_ASW_ScreenShake( GetAbsOrigin(), 25.0, 150.0, 1.0, 750, SHAKE_START );
UTIL_ASW_GrenadeExplosion( GetAbsOrigin(), m_DmgRadius );
EmitSound( "ASWGrenade.Explode" );
int iPreExplosionKills = 0;
CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>(GetOwnerEntity());
if (pMarine && pMarine->GetMarineResource())
iPreExplosionKills = pMarine->GetMarineResource()->m_iAliensKilled;
CTakeDamageInfo info( this, GetOwnerEntity(), m_flDamage, DMG_BLAST );
info.SetWeapon( m_hCreatorWeapon );
ASWGameRules()->RadiusDamage ( info, GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL );
if (pMarine && pMarine->GetMarineResource())
{
int iKilledByExplosion = pMarine->GetMarineResource()->m_iAliensKilled - iPreExplosionKills;
if (iKilledByExplosion > pMarine->GetMarineResource()->m_iSingleGrenadeKills)
{
pMarine->GetMarineResource()->m_iSingleGrenadeKills = iKilledByExplosion;
if ( iKilledByExplosion > asw_medal_explosive_kills.GetInt() && pMarine->GetCommander() && pMarine->IsInhabited() )
{
pMarine->GetCommander()->AwardAchievement( ACHIEVEMENT_ASW_GRENADE_MULTI_KILL );
}
}
// count as a shot fired
pMarine->GetMarineResource()->UsedWeapon(NULL, 1);
}
UTIL_Remove( this );
}