Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

276 lines
7.3 KiB

#include "cbase.h"
#include "engine/IEngineSound.h"
#include "asw_shareddefs.h"
#include "basegrenade_shared.h"
#include "Sprite.h"
#include "asw_bouncing_pellet_shared.h"
#ifdef CLIENT_DLL
#include "c_asw_marine.h"
#include "particles_simple.h"
#include "c_asw_trail_beam.h"
#include "idebugoverlaypanel.h"
#include "engine/IVDebugOverlay.h"
#define CASW_Marine C_ASW_Marine
#else
#include "asw_marine.h"
#include "iasw_spawnable_npc.h"
#include "IEffects.h"
#include "te_effect_dispatch.h"
#endif
#include "asw_gamerules.h"
#include "util_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define PELLET_MODEL "models/swarm/Shotgun/ShotgunPellet.mdl"
IMPLEMENT_NETWORKCLASS_ALIASED( ASW_Bouncing_Pellet, DT_ASW_Bouncing_Pellet );
BEGIN_NETWORK_TABLE( CASW_Bouncing_Pellet, DT_ASW_Bouncing_Pellet )
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS( asw_bouncing_pellet, CASW_Bouncing_Pellet );
PRECACHE_REGISTER(asw_bouncing_pellet);
CASW_Bouncing_Pellet::CASW_Bouncing_Pellet()
{
m_hLastHit = NULL;
m_iBounces = 2;
#ifdef CLIENT_DLL
m_pTrail = NULL;
m_bClientPellet = false;
#endif
}
void CASW_Bouncing_Pellet::Precache( void )
{
BaseClass::Precache( );
PrecacheModel( PELLET_MODEL );
PrecacheModel( "swarm/sprites/whiteglow1.vmt" );
PrecacheModel( "swarm/sprites/greylaser1.vmt" );
}
void CASW_Bouncing_Pellet::Spawn( void )
{
Precache();
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
SetSolid( SOLID_BBOX );
//m_flGravity = 1.0;
SetFriction( 0.75 );
SetModel( PELLET_MODEL );
SetSize( -Vector(1,1,1), Vector(1,1,1) );
SetSolid( SOLID_BBOX );
SetGravity( 0.05f );
SetCollisionGroup( ASW_COLLISION_GROUP_SHOTGUN_PELLET );
SetTouch( &CASW_Bouncing_Pellet::PelletTouch );
SetThink( &CASW_Bouncing_Pellet::SUB_Remove );
SetNextThink( gpGlobals->curtime + 1.0f );
m_flDamage = 10;
m_takedamage = DAMAGE_NO;
}
void CASW_Bouncing_Pellet::UpdateOnRemove( void )
{
BaseClass::UpdateOnRemove();
#ifdef CLIENT_DLL
ReleaseBeamTrail();
#endif
}
CASW_Bouncing_Pellet *CASW_Bouncing_Pellet::CreatePellet( const Vector &vecOrigin, const Vector &vecForward, CBaseEntity *pMarine, float flDamage )
{
CASW_Bouncing_Pellet *pProjectile = dynamic_cast<CASW_Bouncing_Pellet*>(CreateEntityByName("asw_bouncing_pellet"));
//(CASW_Bouncing_Pellet*)CREATE_PREDICTED_ENTITY( "asw_shotgun_pellet_predicted" );
#ifdef CLIENT_DLL
if (!pProjectile->InitializeAsClientEntity( PELLET_MODEL, false ))
{
Msg("CASW_Bouncing_Pellet Error, couldn't InitializeAsClientEntity\n");
pProjectile->Release();
return NULL;
}
if (pProjectile)
pProjectile->m_bClientPellet = true;
#endif
if ( pProjectile )
{
UTIL_SetOrigin( pProjectile, vecOrigin );
pProjectile->SetOwnerEntity( pMarine );
pProjectile->Spawn();
pProjectile->SetAbsVelocity( vecForward );
pProjectile->m_flDamage = flDamage;
QAngle angles;
VectorAngles( vecForward, angles );
pProjectile->SetLocalAngles( angles );
}
return pProjectile;
}
#ifdef CLIENT_DLL
void CASW_Bouncing_Pellet::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED)
{
CreateBeamTrail();
SetNextClientThink(CLIENT_THINK_ALWAYS);
}
}
ConVar asw_pellet_trail_width("asw_pellet_trail_width", "1.5f", FCVAR_CHEAT);
ConVar asw_pellet_trail_fade("asw_pellet_trail_fade", "0.0f", FCVAR_CHEAT);
ConVar asw_pellet_trail_life("asw_pellet_trail_life", "1.0f", FCVAR_CHEAT);
ConVar asw_pellet_trail_r("asw_pellet_trail_r", "255", FCVAR_CHEAT);
ConVar asw_pellet_trail_g("asw_pellet_trail_g", "255", FCVAR_CHEAT);
ConVar asw_pellet_trail_b("asw_pellet_trail_b", "255", FCVAR_CHEAT);
ConVar asw_pellet_trail_a("asw_pellet_trail_a", "40", FCVAR_CHEAT);
ConVar asw_pellet_trail_material("asw_pellet_trail_material", "sprites/laserbeam.vmt", FCVAR_CHEAT);
void CASW_Bouncing_Pellet::CreateBeamTrail()
{
BeamInfo_t beamInfo;
beamInfo.m_pStartEnt = this;
beamInfo.m_nStartAttachment = 0;
beamInfo.m_nModelIndex = modelinfo->GetModelIndex( asw_pellet_trail_material.GetString() );
beamInfo.m_nHaloIndex = 0;
beamInfo.m_flHaloScale = 0;
beamInfo.m_flLife = asw_pellet_trail_life.GetFloat();
beamInfo.m_flWidth = asw_pellet_trail_width.GetFloat();
beamInfo.m_flEndWidth = asw_pellet_trail_width.GetFloat();
beamInfo.m_flFadeLength = asw_pellet_trail_fade.GetFloat();
beamInfo.m_flBrightness = asw_pellet_trail_a.GetFloat();
beamInfo.m_flRed = asw_pellet_trail_r.GetFloat();
beamInfo.m_flGreen = asw_pellet_trail_g.GetFloat();
beamInfo.m_flBlue = asw_pellet_trail_b.GetFloat();
if (!IsClientCreated())
{
beamInfo.m_flBlue = 0;
}
beamInfo.m_flAmplitude = asw_pellet_trail_life.GetFloat();
m_pTrail = beams->CreateBeamFollow( beamInfo );
}
void CASW_Bouncing_Pellet::ReleaseBeamTrail()
{
if (m_pTrail)
{
m_pTrail->flags = 0;
m_pTrail->die = gpGlobals->curtime - 1;
m_pTrail = NULL;
}
}
void CASW_Bouncing_Pellet::ClientThink()
{
if (!m_bClientPellet)
return;
// move us forward
Vector vecForward;
AngleVectors(GetAbsAngles(), &vecForward);
Vector vecEndPosition = GetAbsOrigin() + vecForward * 2500 * gpGlobals->frametime; // todo: FIX HARDCODED speed
trace_t trace;
CTraceFilterWorldOnly traceFilter;
UTIL_TraceHull( GetAbsOrigin(), vecEndPosition, -Vector(1,1,1), Vector(1,1,1),
MASK_SOLID_BRUSHONLY, &traceFilter, &trace );
if ( trace.fraction < 1.0f )
{
PelletTouch(trace.m_pEnt);
}
else
{
debugoverlay->AddLineOverlay(GetAbsOrigin(), vecEndPosition,
0, 0, 255, true, 1.0f);
SetAbsOrigin(vecEndPosition);
}
SetNextClientThink(CLIENT_THINK_ALWAYS);
}
#endif
#ifdef GAME_DLL
void CASW_Bouncing_Pellet::PelletHurt( CBaseEntity *pOther, trace_t &tr )
{
if (pOther == m_hLastHit.Get()) // don't damage the same alien twice
return;
ClearMultiDamage();
CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_flDamage, DMG_BUCKSHOT );
Vector vecNormalizedVel = GetAbsVelocity();
VectorNormalize( vecNormalizedVel );
CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f );
dmgInfo.SetDamagePosition( tr.endpos );
pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
ApplyMultiDamage();
}
#endif
void CASW_Bouncing_Pellet::PelletTouch( CBaseEntity *pOther )
{
if (!pOther)
return;
// make sure we don't die on things we shouldn't
if (!ASWGameRules() || !ASWGameRules()->ShouldCollide(GetCollisionGroup(), pOther->GetCollisionGroup()))
return;
if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
return;
trace_t tr;
tr = BaseClass::GetTouchTrace();
if ( pOther->m_takedamage != DAMAGE_NO )
{
#ifdef GAME_DLL
PelletHurt(pOther, tr);
#endif
}
// keep going through glass
if ( pOther->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS )
return;
// keep going through aliens
if ( pOther->IsNPC() )
return;
// todo: impact effects?
if (m_iBounces > 0)
{
// bounce
Vector vecNewDir = GetAbsVelocity();
float speed = vecNewDir.NormalizeInPlace();
float proj = (vecNewDir).Dot( tr.plane.normal );
VectorMA( vecNewDir, -proj*2, tr.plane.normal, vecNewDir );
vecNewDir *= speed;
SetAbsVelocity(Vector(vecNewDir.x, vecNewDir.y, GetAbsVelocity().z)); // don't alter z
m_iBounces--;
}
// hit something with no bounces left, time to die
SetAbsVelocity( Vector( 0, 0, 0 ) );
SetTouch( NULL );
SetThink( &CASW_Bouncing_Pellet::SUB_Remove );
SetNextThink( gpGlobals->curtime );
}