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.
465 lines
13 KiB
465 lines
13 KiB
#include "cbase.h" |
|
#include "asw_aoegrenade_projectile.h" |
|
#include "asw_marine.h" |
|
#include "Sprite.h" |
|
#include "SpriteTrail.h" |
|
#include "soundent.h" |
|
#include "te_effect_dispatch.h" |
|
#include "IEffects.h" |
|
#include "decals.h" |
|
#include "asw_shareddefs.h" |
|
#include "particle_parse.h" |
|
#include "triggers.h" |
|
#include "world.h" |
|
#include "asw_game_resource.h" |
|
#include "asw_marine_resource.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
|
|
#define AOEGREN_MODEL "models/items/Mine/mine.mdl" |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: SendProxy that converts the AOEGren list UtlVector to entindices |
|
//----------------------------------------------------------------------------- |
|
void SendProxy_AOEGrenList( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ) |
|
{ |
|
CASW_AOEGrenade_Projectile *pAOEGren = (CASW_AOEGrenade_Projectile*)pStruct; |
|
|
|
// If this assertion fails, then SendProxyArrayLength_AOEGrenArray must have failed. |
|
Assert( iElement < pAOEGren->m_hAOETargets.Count() ); |
|
|
|
CBaseEntity *pEnt = pAOEGren->m_hAOETargets[iElement].Get(); |
|
EHANDLE hOther = pEnt; |
|
|
|
SendProxy_EHandleToInt( pProp, pStruct, &hOther, pOut, iElement, objectID ); |
|
} |
|
|
|
int SendProxyArrayLength_AOEGrenArray( const void *pStruct, int objectID ) |
|
{ |
|
CASW_AOEGrenade_Projectile *pAOEGren = (CASW_AOEGrenade_Projectile*)pStruct; |
|
return pAOEGren->m_hAOETargets.Count(); |
|
} |
|
|
|
|
|
class CASW_AOEGrenade_TouchTrigger : public CBaseTrigger |
|
{ |
|
DECLARE_CLASS( CASW_AOEGrenade_TouchTrigger, CBaseTrigger ); |
|
|
|
public: |
|
CASW_AOEGrenade_TouchTrigger() {} |
|
|
|
void Spawn( void ) |
|
{ |
|
BaseClass::Spawn(); |
|
// SF_TRIGGER_ONLY_PLAYER_ALLY_NPCS means "only marines" in ASW |
|
AddSpawnFlags( SF_TRIGGER_ONLY_PLAYER_ALLY_NPCS ); |
|
InitTrigger(); |
|
} |
|
|
|
virtual void StartTouch( CBaseEntity *pEntity ) |
|
{ |
|
CASW_AOEGrenade_Projectile *pParent = dynamic_cast<CASW_AOEGrenade_Projectile *>(GetOwnerEntity()); |
|
|
|
if ( pParent ) |
|
{ |
|
pParent->StartTouch( pEntity ); |
|
} |
|
} |
|
|
|
virtual void EndTouch( CBaseEntity *pEntity ) |
|
{ |
|
CASW_AOEGrenade_Projectile *pParent = dynamic_cast<CASW_AOEGrenade_Projectile *>(GetOwnerEntity()); |
|
|
|
if ( pParent ) |
|
{ |
|
pParent->EndTouch( pEntity ); |
|
} |
|
} |
|
}; |
|
|
|
|
|
LINK_ENTITY_TO_CLASS( asw_aoegrenade_touch_trigger, CASW_AOEGrenade_TouchTrigger ); |
|
|
|
BEGIN_DATADESC( CASW_AOEGrenade_Projectile ) |
|
DEFINE_FUNCTION( AOEGrenadeTouch ), |
|
DEFINE_FUNCTION( AOEGrenadeThink ), |
|
|
|
// Fields |
|
DEFINE_FIELD( m_pMainGlow, FIELD_EHANDLE ), |
|
DEFINE_FIELD( m_pGlowTrail, FIELD_EHANDLE ), |
|
DEFINE_FIELD( m_flTimeBurnOut, FIELD_TIME ), |
|
DEFINE_FIELD( m_flTimePulse, FIELD_TIME ), |
|
DEFINE_FIELD( m_flLastDoAOE, FIELD_TIME ), |
|
DEFINE_FIELD( m_flScale, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_nBounces, FIELD_INTEGER ), |
|
DEFINE_FIELD( m_flDuration, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_bFading, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_bSettled, FIELD_BOOLEAN ), |
|
END_DATADESC() |
|
|
|
IMPLEMENT_SERVERCLASS_ST( CASW_AOEGrenade_Projectile, DT_ASW_AOEGrenade_Projectile ) |
|
SendPropArray2( |
|
SendProxyArrayLength_AOEGrenArray, |
|
SendPropInt( "aoegren_array_element", 0, SIZEOF_IGNORE, NUM_NETWORKED_EHANDLE_BITS, SPROP_UNSIGNED, SendProxy_AOEGrenList), |
|
MAX_PLAYERS, |
|
0, |
|
"aoetarget_array" |
|
), |
|
|
|
SendPropFloat( SENDINFO( m_flTimeBurnOut ), 0, SPROP_NOSCALE ), |
|
//SendPropFloat( SENDINFO( m_flTimePulse ), 0, SPROP_NOSCALE ), |
|
SendPropFloat( SENDINFO( m_flScale ), 0, SPROP_NOSCALE ), |
|
SendPropBool( SENDINFO( m_bSettled ) ), |
|
SendPropFloat( SENDINFO( m_flRadius ), 0, SPROP_NOSCALE ), |
|
END_SEND_TABLE() |
|
|
|
|
|
// aoegrenades maintain a linked list of themselves, for quick checking for autoaim |
|
CASW_AOEGrenade_Projectile* g_pHeadAOEGrenade = NULL; |
|
|
|
CASW_AOEGrenade_Projectile::CASW_AOEGrenade_Projectile() |
|
{ |
|
m_flScale = 1.0f; |
|
m_flNextDamage = gpGlobals->curtime; |
|
m_lifeState = LIFE_ALIVE; |
|
m_iHealth = 100; |
|
m_flDuration = 20.0f; |
|
m_flRadius = 128.0f; |
|
|
|
SetModelName( MAKE_STRING( AOEGREN_MODEL ) ); |
|
} |
|
|
|
CASW_AOEGrenade_Projectile::~CASW_AOEGrenade_Projectile( void ) |
|
{ |
|
if ( m_hTouchTrigger.Get() ) |
|
{ |
|
UTIL_Remove( m_hTouchTrigger ); |
|
} |
|
|
|
int iSize = m_hAOETargets.Count(); |
|
for ( int i = iSize - 1; i >= 0; i-- ) |
|
{ |
|
EHANDLE hEntity = m_hAOETargets[i]; |
|
StopAOE( hEntity.Get() ); |
|
} |
|
} |
|
|
|
int CASW_AOEGrenade_Projectile::Restore( IRestore &restore ) |
|
{ |
|
int result = BaseClass::Restore( restore ); |
|
return result; |
|
} |
|
|
|
void CASW_AOEGrenade_Projectile::Spawn( void ) |
|
{ |
|
Precache( ); |
|
|
|
SetModel( GetModelName().ToCStr() ); |
|
UTIL_SetSize( this, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ) ); |
|
SetSolid( SOLID_BBOX ); |
|
AddSolidFlags( FSOLID_NOT_SOLID ); |
|
|
|
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); |
|
|
|
//m_iDamage = 0; |
|
m_takedamage = DAMAGE_NO; |
|
|
|
SetFriction( 0.6f ); |
|
SetGravity( UTIL_ScaleForGravity( GetGrenadeGravity() ) ); |
|
m_flTimeBurnOut = gpGlobals->curtime + GetBurnDuration(); |
|
m_flTimePulse = -1; |
|
|
|
AddEffects( EF_NOSHADOW|EF_NORECEIVESHADOW ); |
|
AddFlag( FL_OBJECT ); |
|
SetCollisionGroup( ASW_COLLISION_GROUP_IGNORE_NPCS ); |
|
|
|
// Tumble in air |
|
QAngle vecAngVelocity( 0, random->RandomFloat ( -100, -500 ), 0 ); |
|
SetLocalAngularVelocity( vecAngVelocity ); |
|
|
|
SetTouch( &CASW_AOEGrenade_Projectile::AOEGrenadeTouch ); |
|
|
|
SetThink( &CASW_AOEGrenade_Projectile::AOEGrenadeThink ); |
|
SetNextThink( gpGlobals->curtime + 0.1f ); |
|
} |
|
|
|
void CASW_AOEGrenade_Projectile::Precache( void ) |
|
{ |
|
PrecacheModel( GetModelName().ToCStr() ); |
|
|
|
PrecacheScriptSound( "ASW_BuffGrenade.GrenadeActivate" ); |
|
PrecacheScriptSound( "ASW_BuffGrenade.ActiveLoop" ); |
|
PrecacheScriptSound( "ASW_BuffGrenade.StartBuff" ); |
|
PrecacheScriptSound( "ASW_BuffGrenade.BuffLoop" ); |
|
|
|
PrecacheModel( "swarm/sprites/whiteglow1.vmt" ); |
|
PrecacheModel( "swarm/sprites/greylaser1.vmt" ); |
|
|
|
BaseClass::Precache(); |
|
} |
|
|
|
const Vector& CASW_AOEGrenade_Projectile::GetEffectOrigin() |
|
{ |
|
static Vector s_vecEffectPos; |
|
Vector forward, right, up; |
|
AngleVectors(GetAbsAngles(), &forward, &right, &up); |
|
s_vecEffectPos = GetAbsOrigin() + up * 5; |
|
return s_vecEffectPos; |
|
} |
|
|
|
|
|
unsigned int CASW_AOEGrenade_Projectile::PhysicsSolidMaskForEntity( void ) const |
|
{ |
|
return MASK_NPCSOLID; |
|
} |
|
|
|
void CASW_AOEGrenade_Projectile::AOEGrenadeTouch( CBaseEntity *pOther ) |
|
{ |
|
Assert( pOther ); |
|
if ( !pOther->IsSolid() ) |
|
return; |
|
|
|
// don't touch npcs |
|
if ( pOther->IsNPC() ) |
|
return; |
|
|
|
// Change our flight characteristics |
|
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); |
|
SetGravity( UTIL_ScaleForGravity( 640 ) ); |
|
|
|
m_nBounces++; |
|
|
|
//After the first bounce, smacking into whoever fired the flare is fair game |
|
//SetOwnerEntity( NULL ); |
|
|
|
// Slow down |
|
Vector vecNewVelocity = GetAbsVelocity(); |
|
vecNewVelocity.x *= 0.8f; |
|
vecNewVelocity.y *= 0.8f; |
|
SetAbsVelocity( vecNewVelocity ); |
|
|
|
//Stopped? |
|
if ( GetAbsVelocity().Length() < 128.0f ) |
|
{ |
|
LayFlat(); |
|
SetAbsVelocity( vec3_origin ); |
|
SetMoveType( MOVETYPE_NONE ); |
|
//RemoveSolidFlags( FSOLID_NOT_SOLID ); |
|
//AddSolidFlags( FSOLID_TRIGGER ); |
|
//SetTouch( &CASW_Flare_Projectile::FlareBurnTouch ); |
|
m_hTouchTrigger = CBaseEntity::Create( "asw_aoegrenade_touch_trigger", GetAbsOrigin(), vec3_angle, this ); |
|
int radius = GetEffectRadius(); |
|
UTIL_SetSize( m_hTouchTrigger.Get(), Vector(-radius,-radius,-radius), Vector(radius,radius,radius) ); |
|
m_hTouchTrigger->SetSolid( SOLID_BBOX ); |
|
|
|
// call StartTouch() on all marines in radius |
|
CASW_Game_Resource *pGameResource = ASWGameResource(); |
|
for (int i=0;i<pGameResource->GetMaxMarineResources();i++) |
|
{ |
|
CASW_Marine_Resource *pMR = pGameResource->GetMarineResource(i); |
|
if (!pMR) |
|
continue; |
|
CASW_Marine *pMarine = pMR->GetMarineEntity(); |
|
if (!pMarine) |
|
continue; |
|
|
|
if( GetDistanceToEntity( pMarine ) < m_flRadius ) |
|
{ |
|
CBaseEntity *pEntity = pMarine; |
|
StartTouch( pEntity ); |
|
} |
|
} |
|
|
|
//NDebugOverlay::Box( GetAbsOrigin(), Vector(-radius,-radius,-radius), Vector(radius,radius,radius), 0, 0, 255, 200, 5.5 ); |
|
|
|
Assert( m_hTouchTrigger.Get() ); |
|
|
|
m_bSettled = true; |
|
} |
|
} |
|
|
|
void CASW_AOEGrenade_Projectile::AOEGrenadeThink( void ) |
|
{ |
|
if ( m_flTimeBurnOut != -1.0f ) |
|
{ |
|
//Burned out |
|
if ( m_flTimeBurnOut < gpGlobals->curtime ) |
|
{ |
|
OnBurnout(); |
|
UTIL_Remove( this ); |
|
return; |
|
} |
|
} |
|
|
|
//Act differently underwater |
|
if ( GetWaterLevel() > 1 ) |
|
{ |
|
UTIL_Bubbles( GetEffectOrigin() + Vector( -2, -2, -2 ), GetEffectOrigin() + Vector( 2, 2, 2 ), 1 ); |
|
} |
|
|
|
if ( !m_bSettled && GetAbsVelocity().Length() < 128.0f && GetGroundEntity() ) |
|
{ |
|
AOEGrenadeTouch( GetGroundEntity() ); |
|
} |
|
|
|
GiveEffectToEntitesInRadius(); |
|
|
|
//Next update |
|
SetNextThink( gpGlobals->curtime + 0.1f ); |
|
} |
|
|
|
void CASW_AOEGrenade_Projectile::GiveEffectToEntitesInRadius( void ) |
|
{ |
|
bool bDoAOE = ( gpGlobals->curtime > m_flLastDoAOE + GetDoAOEDelayTime() ); |
|
|
|
// for each player in touching list |
|
int iSize = m_hTouchingEntities.Count(); |
|
for ( int i = iSize-1; i >= 0; i-- ) |
|
{ |
|
EHANDLE hEntity = m_hTouchingEntities[i]; |
|
|
|
CBaseEntity *pEntity = hEntity.Get(); |
|
if ( !pEntity ) |
|
continue; |
|
|
|
if ( !IsAOETarget( pEntity ) ) |
|
{ |
|
// if they're on the list, but we aren't buffing them, do so |
|
StartAOE( pEntity ); |
|
} |
|
|
|
if ( bDoAOE ) |
|
{ |
|
DoAOE( pEntity ); |
|
} |
|
} |
|
|
|
if ( bDoAOE ) |
|
{ |
|
m_flLastDoAOE = gpGlobals->curtime; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_AOEGrenade_Projectile::StartTouch( CBaseEntity *pEntity ) |
|
{ |
|
if ( !ShouldTouchEntity( pEntity ) ) |
|
return; |
|
|
|
// add to touching entities |
|
EHANDLE hEntity = pEntity; |
|
if( m_hTouchingEntities.Find( hEntity ) == -1 ) |
|
{ |
|
m_hTouchingEntities.AddToTail( hEntity ); |
|
|
|
// try to start healing them |
|
StartAOE( pEntity ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_AOEGrenade_Projectile::EndTouch( CBaseEntity *pEntity ) |
|
{ |
|
// remove from touching entities |
|
EHANDLE hEntity = pEntity; |
|
m_hTouchingEntities.FindAndRemove( hEntity ); |
|
|
|
// remove from healing list |
|
StopAOE( pEntity ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Add the buff to this target |
|
//----------------------------------------------------------------------------- |
|
void CASW_AOEGrenade_Projectile::StartAOE( CBaseEntity *pEntity ) |
|
{ |
|
AddAOETarget( pEntity ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Stop healing this target |
|
//----------------------------------------------------------------------------- |
|
bool CASW_AOEGrenade_Projectile::StopAOE( CBaseEntity *pEntity ) |
|
{ |
|
bool bFound = false; |
|
|
|
EHANDLE hEntity = pEntity; |
|
bFound = m_hAOETargets.FindAndRemove( hEntity ); |
|
NetworkStateChanged(); |
|
|
|
return bFound; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_AOEGrenade_Projectile::AddAOETarget( CBaseEntity *pEntity ) |
|
{ |
|
Assert( pEntity ); |
|
// add to tail |
|
EHANDLE hEntity = pEntity; |
|
m_hAOETargets.AddToTail( hEntity ); |
|
NetworkStateChanged(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_AOEGrenade_Projectile::RemoveAOETarget( CBaseEntity *pEntity ) |
|
{ |
|
Assert( pEntity ); |
|
// remove |
|
EHANDLE hEntity = pEntity; |
|
m_hAOETargets.FindAndRemove( hEntity ); |
|
NetworkStateChanged(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Are we buffing this target already |
|
//----------------------------------------------------------------------------- |
|
bool CASW_AOEGrenade_Projectile::IsAOETarget( CBaseEntity *pEntity ) |
|
{ |
|
Assert( pEntity ); |
|
EHANDLE hEntity = pEntity; |
|
return m_hAOETargets.HasElement( hEntity ); |
|
} |
|
|
|
void CASW_AOEGrenade_Projectile::LayFlat() |
|
{ |
|
QAngle angFacing = GetAbsAngles(); |
|
//if (angFacing[PITCH] > 0 && angFacing[PITCH] < 180.0f) |
|
angFacing[PITCH] = 0; //90 |
|
//else |
|
// angFacing[PITCH] = 270; |
|
SetAbsAngles(angFacing); |
|
//Msg("Laying flat to %f, %f, %f\n", angFacing[PITCH], angFacing[YAW], angFacing[ROLL]); |
|
} |
|
|
|
//extern ConVar asw_aoegrenade_autoaim_radius; |
|
void CASW_AOEGrenade_Projectile::DrawDebugGeometryOverlays() |
|
{ |
|
/* |
|
// draw arrows showing the extent of our autoaim |
|
for (int i=0;i<360;i+=45) |
|
{ |
|
float flBaseSize = 10; |
|
float flHeight = asw_aoegrenade_autoaim_radius.GetFloat(); |
|
|
|
Vector vBasePos = GetAbsOrigin() + Vector( 0, 0, 5 ); |
|
QAngle angles( 0, 0, 0 ); |
|
Vector vForward, vRight, vUp; |
|
angles[YAW] = i; |
|
AngleVectors( angles, &vForward, &vRight, &vUp ); |
|
NDebugOverlay::Triangle( vBasePos+vRight*flBaseSize/2, vBasePos-vRight*flBaseSize/2, vBasePos+vForward*flHeight, 0, 255, 0, 255, false, 10 ); |
|
} |
|
*/ |
|
BaseClass::DrawDebugGeometryOverlays(); |
|
} |