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.
 
 
 
 
 
 

312 lines
8.4 KiB

#include "cbase.h"
#include "engine/IEngineSound.h"
#include "asw_shareddefs.h"
#include "basegrenade_shared.h"
#include "Sprite.h"
#include "asw_mortarbug_shell_shared.h"
#ifdef CLIENT_DLL
#include "c_asw_marine.h"
#include "particles_simple.h"
#include "idebugoverlaypanel.h"
#include "engine/IVDebugOverlay.h"
#include "baseparticleentity.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"
#include "world.h"
#include "asw_util_shared.h"
#include "particle_parse.h"
#include "asw_boomer_blob.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 SHELL_MODEL "models/swarm/MortarBugProjectile/MortarBugProjectile.mdl"
#define SHELL_AURA "mortar_shell_aura"
#define SHELL_WARN_DELAY 1.5f
IMPLEMENT_NETWORKCLASS_ALIASED( ASW_Mortarbug_Shell, DT_ASW_Mortarbug_Shell );
BEGIN_NETWORK_TABLE( CASW_Mortarbug_Shell, DT_ASW_Mortarbug_Shell )
END_NETWORK_TABLE()
#ifdef GAME_DLL
LINK_ENTITY_TO_CLASS( asw_mortarbug_shell, CASW_Mortarbug_Shell );
PRECACHE_REGISTER( asw_mortarbug_shell );
BEGIN_DATADESC( CASW_Mortarbug_Shell )
DEFINE_FUNCTION( VShellTouch ),
DEFINE_THINKFUNC( ShellFlyThink ),
DEFINE_THINKFUNC( ShellThink ),
DEFINE_THINKFUNC( Detonate ),
END_DATADESC()
extern int g_sModelIndexFireball;
ConVar asw_mortarbug_shell_gravity("asw_mortarbug_shell_gravity", "0.8f", FCVAR_CHEAT, "Gravity of mortarbug shell");
ConVar asw_mortarbug_shell_fuse("asw_mortarbug_shell_fuse", "3.0f", FCVAR_CHEAT, "Time before mortarbug shell explodes");
CASW_Mortarbug_Shell::CASW_Mortarbug_Shell()
{
m_bDoScreenShake = false;
g_aExplosiveProjectiles.AddToTail( this );
}
CASW_Mortarbug_Shell::~CASW_Mortarbug_Shell()
{
g_aExplosiveProjectiles.FindAndRemove( this );
}
void CASW_Mortarbug_Shell::Precache( void )
{
BaseClass::Precache( );
PrecacheModel( SHELL_MODEL );
PrecacheParticleSystem( SHELL_AURA );
PrecacheScriptSound( "ASW_Boomer_Grenade.Explode" );
PrecacheScriptSound( "ASW_Boomer_Projectile.Spawned" );
PrecacheScriptSound( "ASW_Boomer_Projectile.ImpactHard" );
}
void CASW_Mortarbug_Shell::Spawn( void )
{
Precache( );
SetModel( SHELL_MODEL );
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
SetSequence( LookupSequence( "MortarBugProjectile_Closed" ) );
// TODO:
m_flDamage = 50;
m_DmgRadius = 220.0f;
//Ignite(3.0, false, 0, false);
m_takedamage = DAMAGE_NO;
m_bModelOpening = false;
EmitSound( "ASW_Boomer_Projectile.Spawned" );
SetSize( -Vector(4,4,4), Vector(4,4,4) );
SetSolid( SOLID_BBOX );
SetGravity( asw_mortarbug_shell_gravity.GetFloat() );
SetCollisionGroup( COLLISION_GROUP_DEBRIS ); // TODO: change this to a custom collision group?
SetTouch( &CASW_Mortarbug_Shell::VShellTouch );
// TODO: Have a sound for the shell?
//EmitSound( "ASWGrenade.Alarm" ); // 3 second warning sound
m_vecLastPosition = vec3_origin;
SetThink( &CASW_Mortarbug_Shell::ShellFlyThink );
SetNextThink( gpGlobals->curtime + 0.05f );
}
void CASW_Mortarbug_Shell::ShellFlyThink()
{
// face the direction we're moving
Vector vecForward = GetAbsVelocity();
VectorNormalize(vecForward);
QAngle angles;
VectorAngles( vecForward, angles );
angles[PITCH] -= 90; // TODO: rotate pitch properly?
SetAbsAngles( angles );
SetNextThink( gpGlobals->curtime + 0.05f );
// check for not moving
float flDist = ( GetAbsOrigin() - m_vecLastPosition ).Length();
if ( flDist < 5.0f )
{
SetFuseLength( asw_mortarbug_shell_fuse.GetFloat() + RandomFloat( -0.3f, 0.3f ) );
}
m_vecLastPosition = GetAbsOrigin();
}
void CASW_Mortarbug_Shell::ShellThink( )
{
if ( !m_bModelOpening && gpGlobals->curtime >= (m_fDetonateTime - SHELL_WARN_DELAY) )
{
// we are one second from detonating, commit to detonating and start the opening sequence
// regardless of anyone nearby
m_bModelOpening = true;
ResetSequence( LookupSequence( "MortarBugProjectile_Opening" ) );
CEffectData data;
data.m_vOrigin = GetAbsOrigin();
CPASFilter filter( data.m_vOrigin );
filter.SetIgnorePredictionCull(true);
DispatchParticleEffect( "mortar_grenade_open", PATTACH_ABSORIGIN_FOLLOW, this, -1, false, -1, &filter );
}
// if we exceeded the detonation time, just detonate
if ( gpGlobals->curtime >= m_fDetonateTime )
{
Detonate();
return;
}
// if the model is opening, do the animation advance
if ( m_bModelOpening )
{
StudioFrameAdvance();
SetNextThink( gpGlobals->curtime );
return;
}
if ( m_fDetonateTime <= gpGlobals->curtime + 0.1f )
{
SetThink( &CASW_Mortarbug_Shell::Detonate );
SetNextThink( m_fDetonateTime );
}
else
{
SetThink( &CASW_Mortarbug_Shell::ShellThink );
SetNextThink( gpGlobals->curtime + 0.1f );
}
}
void CASW_Mortarbug_Shell::VShellTouch( CBaseEntity *pOther )
{
if (!pOther || pOther == GetOwnerEntity())
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;
// trace to latch onto the thing we collided with
Vector vecForward = GetAbsVelocity();
VectorNormalize(vecForward);
trace_t tr;
UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + 60 * vecForward, MASK_SOLID,
this, GetCollisionGroup(), &tr);
if ( !tr.DidHit() )
return;
QAngle angles;
VectorAngles( tr.plane.normal, angles );
angles[PITCH] += 90; // TODO: rotate pitch properly?
SetAbsAngles( angles );
SetAbsVelocity( vec3_origin );
UTIL_SetOrigin( this, tr.endpos );
//SetParent( tr.m_pEnt );
EmitSound( "ASW_Boomer_Projectile.ImpactHard" );
SetTouch( NULL );
SetFuseLength( asw_mortarbug_shell_fuse.GetFloat() + RandomFloat( -0.3f, 0.3f ) );
}
void CASW_Mortarbug_Shell::SetFuseLength(float fSeconds)
{
m_fDetonateTime = gpGlobals->curtime + fSeconds;
SetThink( &CASW_Mortarbug_Shell::ShellThink );
SetNextThink( gpGlobals->curtime );
//SetSequence( LookupSequence( "MortarBugProjectile_Opening" ) );
//SetThink( &CASW_Mortarbug_Shell::Detonate );
//SetNextThink( gpGlobals->curtime + fSeconds );
}
CASW_Mortarbug_Shell* CASW_Mortarbug_Shell::CreateShell( const Vector &vecOrigin, const Vector &vecForward, CBaseEntity *pOwner )
{
CASW_Mortarbug_Shell *pShell = (CASW_Mortarbug_Shell *)CreateEntityByName( "asw_mortarbug_shell" );
QAngle angles;
VectorAngles( vecForward, angles );
pShell->SetAbsAngles( angles );
UTIL_SetOrigin( pShell, vecOrigin );
pShell->Spawn();
pShell->SetOwnerEntity( pOwner );
UTIL_SetOrigin( pShell, vecOrigin );
return pShell;
}
void CASW_Mortarbug_Shell::Detonate()
{
m_takedamage = DAMAGE_NO;
// explosion effects
DispatchParticleEffect( "boomer_drop_explosion", GetAbsOrigin(), Vector( m_DmgRadius, 0.0f, 0.0f ), QAngle( 0.0f, 0.0f, 0.0f ) );
EmitSound( "ASW_Boomer_Grenade.Explode" );
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" );
}
ScreenShake_t shake;
shake.direction = Vector( 0, 0, 1 );
shake.amplitude = 40.0f;
shake.duration = 0.3f;
shake.frequency = 1.0f;
shake.command = SHAKE_START;
UTIL_ASW_ScreenPunch( GetAbsOrigin(), 350.0f, shake );
RadiusDamage ( CTakeDamageInfo( this, GetOwnerEntity(), m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL );
UTIL_Remove( this );
}
#endif // GAME_DLL
#ifdef CLIENT_DLL
CASW_Mortarbug_Shell::CASW_Mortarbug_Shell()
{
}
void CASW_Mortarbug_Shell::PostDataUpdate( DataUpdateType_t updateType )
{
BaseClass::PostDataUpdate(updateType);
// If this entity was new, then latch in various values no matter what.
if ( updateType == DATA_UPDATE_CREATED )
{
CNewParticleEffect *pBurningEffect = ParticleProp()->Create( SHELL_AURA, PATTACH_ABSORIGIN_FOLLOW );
if (pBurningEffect)
{
ParticleProp()->AddControlPoint( pBurningEffect, 1, this, PATTACH_ABSORIGIN_FOLLOW );
pBurningEffect->SetControlPoint( 0, GetAbsOrigin() );
pBurningEffect->SetControlPoint( 1, GetAbsOrigin() );
pBurningEffect->SetControlPointEntity( 0, this );
pBurningEffect->SetControlPointEntity( 1, this );
}
}
}
#endif // CLIENT_DLL