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

326 lines
9.4 KiB
C++

#include "cbase.h"
#include "asw_shotgun_pellet.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 "asw_shareddefs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
const float GRENADE_COEFFICIENT_OF_RESTITUTION = 0.2f;
ConVar asw_shotgun_pellet_fade_length("asw_shotgun_pellet_fade_length", "100.0f", 0, "Length of the trail on the shotgun pellets");
ConVar asw_shotgun_pellets_pass("asw_shotgun_pellets_pass", "0", FCVAR_CHEAT, "Set to make shotgun pellets pass through aliens (as opposed to stopping on contact)");
#define PELLET_MODEL "models/swarm/Shotgun/ShotgunPellet.mdl"
LINK_ENTITY_TO_CLASS( asw_shotgun_pellet, CASW_Shotgun_Pellet );
BEGIN_DATADESC( CASW_Shotgun_Pellet )
DEFINE_FUNCTION( PelletTouch ),
// Fields
DEFINE_FIELD( m_pMainGlow, FIELD_EHANDLE ),
DEFINE_FIELD( m_pGlowTrail, FIELD_EHANDLE ),
DEFINE_FIELD( m_inSolid, FIELD_BOOLEAN ),
DEFINE_FIELD( m_hLastHit, FIELD_EHANDLE ),
DEFINE_FIELD( m_flDamage, FIELD_FLOAT ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CASW_Shotgun_Pellet::~CASW_Shotgun_Pellet( void )
{
KillEffects();
}
void CASW_Shotgun_Pellet::Spawn( void )
{
Precache( );
SetModel( PELLET_MODEL );
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
m_flDamage = 7; // just a default, would get overriden by the skill base damage passed in in the create function
m_takedamage = DAMAGE_NO;
SetSize( -Vector(1,1,1), Vector(1,1,1) );
SetSolid( SOLID_BBOX );
SetGravity( 0.05f );
//SetCollisionGroup( ASW_COLLISION_GROUP_SHOTGUN_PELLET );
SetCollisionGroup( ASW_COLLISION_GROUP_IGNORE_NPCS );
//CreateVPhysics();
SetTouch( &CASW_Shotgun_Pellet::PelletTouch );
CreateEffects();
Msg("Created sg pellet\n");
//AddSolidFlags( FSOLID_NOT_STANDABLE );
//BaseClass::Spawn();
// projectile only lasts 1 second
SetThink( &CASW_Shotgun_Pellet::SUB_Remove );
SetNextThink( gpGlobals->curtime + 1.0f );
//AddSolidFlags(FSOLID_TRIGGER);
m_hLastHit = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CASW_Shotgun_Pellet::OnRestore( void )
{
CreateEffects();
BaseClass::OnRestore();
}
void CASW_Shotgun_Pellet::KillEffects()
{
if (m_pMainGlow)
m_pMainGlow->FadeAndDie(0.05f);
if (m_pGlowTrail)
m_pGlowTrail->FadeAndDie(0.05f);
}
void CASW_Shotgun_Pellet::CreateEffects( void )
{
// Start up the eye glow
m_pMainGlow = CSprite::SpriteCreate( "swarm/sprites/whiteglow1.vmt", GetLocalOrigin(), false );
//int nAttachment = LookupAttachment( "fuse" ); // todo: make an attachment on the new model? is that even needed?
if ( m_pMainGlow != NULL )
{
m_pMainGlow->FollowEntity( this );
//m_pMainGlow->SetAttachment( this, nAttachment );
m_pMainGlow->SetTransparency( kRenderGlow, 255, 255, 255, 200, kRenderFxNoDissipation );
m_pMainGlow->SetScale( 0.2f );
m_pMainGlow->SetGlowProxySize( 4.0f );
}
// Start up the eye trail
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, 128, 128, 128, 255, kRenderFxNone );
m_pGlowTrail->SetStartWidth( 8.0f );
m_pGlowTrail->SetEndWidth( 1.0f );
m_pGlowTrail->SetLifeTime( 0.5f );
m_pGlowTrail->SetMinFadeLength( asw_shotgun_pellet_fade_length.GetFloat() );
}
}
bool CASW_Shotgun_Pellet::CreateVPhysics()
{
// Create the object in the physics system
VPhysicsInitNormal( SOLID_BBOX, FSOLID_NOT_STANDABLE, false );
return true;
}
unsigned int CASW_Shotgun_Pellet::PhysicsSolidMaskForEntity() const
{
return ( BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_HITBOX ) & ~CONTENTS_GRATE;
}
void CASW_Shotgun_Pellet::Precache( void )
{
PrecacheModel( PELLET_MODEL );
PrecacheModel( "swarm/sprites/whiteglow1.vmt" );
PrecacheModel( "swarm/sprites/greylaser1.vmt" );
PrecacheScriptSound("Weapon_Crossbow.BoltHitBody");
BaseClass::Precache();
}
void CASW_Shotgun_Pellet::PelletHit( CBaseEntity *pOther)
{
if (!pOther)
return;
if (pOther == GetLastHit()) // don't damage the same alien twice
return;
if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
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();
//Adrian: keep going through the glass.
if ( pOther->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS )
return;
// pellets should carry on through spawnable enemies?
IASW_Spawnable_NPC* pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>(pOther);
if (pSpawnable && asw_shotgun_pellets_pass.GetBool())
{
m_hLastHit = pOther;
return;
}
SetAbsVelocity( Vector( 0, 0, 0 ) );
// 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_Shotgun_Pellet::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 );
}
}
}
void CASW_Shotgun_Pellet::PelletTouch( CBaseEntity *pOther )
{
if (!pOther)
return;
Msg("sg pellet testing colgroup %d vs %d\n", GetCollisionGroup(), pOther->GetCollisionGroup());
// make sure we don't die on things we shouldn't
if (!ASWGameRules() || !ASWGameRules()->ShouldCollide(GetCollisionGroup(), pOther->GetCollisionGroup()))
return;
Msg(" sg pellet allowed to hit %s\n", pOther->GetClassname());
PelletHit(pOther);
}
CASW_Shotgun_Pellet* CASW_Shotgun_Pellet::Shotgun_Pellet_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, CBaseEntity *pOwner, float damage )
{
Msg("CASW_Shotgun_Pellet::Shotgun_Pellet_Create\n");
CASW_Shotgun_Pellet *pPellet = (CASW_Shotgun_Pellet *)CreateEntityByName( "asw_shotgun_pellet" );
pPellet->SetAbsAngles( angles );
pPellet->Spawn();
pPellet->SetPelletDamage( damage );
pPellet->SetOwnerEntity( pOwner );
//Msg("making pellet with velocity %f,%f,%f\n", velocity.x, velocity.y, velocity.z);
UTIL_SetOrigin( pPellet, position );
pPellet->SetAbsVelocity( velocity );
return pPellet;
}
CBaseEntity* CASW_Shotgun_Pellet::GetLastHit()
{
return m_hLastHit.Get();
}