223 lines
7.5 KiB
C++
223 lines
7.5 KiB
C++
#ifndef _INCLUDED_ASW_ROCKET_H
|
|
#define _INCLUDED_ASW_ROCKET_H
|
|
|
|
#include "basehlcombatweapon.h"
|
|
|
|
class RocketTrail;
|
|
|
|
/// This is a class that can handle cases where you have, say, ten projectiles
|
|
/// and three enemies, and you'd like each enemy to get just the number of projectiles
|
|
/// necessary to kill it. It stores a dictionary of targeted enemies, the total damage
|
|
/// to be done so far upon each of them given the allocated projectiles, and a linked
|
|
/// list of projectiles (or spell effects or what have you) allocated to each one.
|
|
class CASW_DamageAllocationMgr
|
|
{
|
|
public:
|
|
// typedefs
|
|
// relevant data about a given projectile: its handle, and the damage it causes
|
|
struct ProjectileInfo_t
|
|
{
|
|
EHANDLE m_hHandle;
|
|
float m_flDamage;
|
|
|
|
ProjectileInfo_t() : m_flDamage(0) {}
|
|
ProjectileInfo_t( CBaseEntity *pProj, float damage ) : m_hHandle(pProj),
|
|
m_flDamage(damage) {}
|
|
};
|
|
|
|
// we store the chain of projectiles allocated to each target
|
|
// as a linked list. This is actually a MULTILIST, which means
|
|
// that many linked lists actually share the pool of spaces herein
|
|
typedef CUtlLinkedList< ProjectileInfo_t, unsigned short, true, unsigned int > ProjectilePool_t;
|
|
|
|
struct tuple_t
|
|
{
|
|
EHANDLE m_hTargeted;
|
|
float m_flAccumulatedDamage;
|
|
ProjectilePool_t::IndexType_t m_nProjectiles; ///< head of linked list of projectiles targeted at this object
|
|
|
|
tuple_t() : m_flAccumulatedDamage(0), m_nProjectiles( ProjectilePool_t::InvalidIndex() ) {};
|
|
tuple_t( const EHANDLE &handle ) : m_hTargeted(handle),
|
|
m_flAccumulatedDamage(0), m_nProjectiles( ProjectilePool_t::InvalidIndex() ) {};
|
|
};
|
|
|
|
/// an index into the targets contained herein.
|
|
// typedeffed just in case I need to change it from being a pointer.
|
|
typedef tuple_t* IndexType_t;
|
|
|
|
// functions
|
|
// get the element for a given IndexType_t
|
|
inline tuple_t &operator[]( const IndexType_t &I ) { return Elem(I); }
|
|
inline tuple_t &Elem( const IndexType_t &I );
|
|
inline bool IsValid( const IndexType_t &I ) const ;
|
|
static inline IndexType_t InvalidIndex();
|
|
|
|
// if the object hasn't got anything allocated, returns NULL
|
|
IndexType_t Find( const EHANDLE &handle ) ;
|
|
|
|
// add this object to the damage allocator, with nothing allocated
|
|
// to it yet. returns the allocated tuple_t. returns the existing one
|
|
// if the object is already in the manager.
|
|
IndexType_t Insert( CBaseEntity* pTarget );
|
|
|
|
void Remove( const EHANDLE &handle );
|
|
|
|
// allocate a projectile to a target. returns total damage being done to target so far.
|
|
inline float Allocate( CBaseEntity *pTarget, CBaseEntity *pProjectile, float flDamage );
|
|
float Allocate( IndexType_t iTarget, CBaseEntity *pProjectile, float flDamage );
|
|
|
|
// remove a projectile from a target. returns total damage being done to target so far.
|
|
inline float Deallocate( CBaseEntity *pTarget, CBaseEntity *pProjectile );
|
|
float Deallocate( IndexType_t iTarget, CBaseEntity *pProjectile );
|
|
|
|
// is the given projectile allocated to the given target?
|
|
inline bool IsProjectileForTarget( IndexType_t iTarget, CBaseEntity *pProjectile );
|
|
|
|
|
|
// constructor
|
|
CASW_DamageAllocationMgr( int baseSize = 0 ) : m_Targets( 0, baseSize ), m_ProjectileLists( 0, baseSize ) {};
|
|
|
|
protected:
|
|
|
|
// look through the projectile pool for a given target and return the index
|
|
// of the ProjectilePool_t corresponding to the given projectile. Return
|
|
// ProjectilePool_t::InvalidIndex if not found.
|
|
ProjectilePool_t::IndexType_t GetProjectileIndexInTarget( IndexType_t iTarget, CBaseEntity *pProjectile );
|
|
|
|
// rebuild consistency
|
|
void Rebuild( IndexType_t iTarget );
|
|
|
|
CUtlVectorConservative< tuple_t > m_Targets;
|
|
ProjectilePool_t m_ProjectileLists;
|
|
};
|
|
|
|
inline CASW_DamageAllocationMgr::tuple_t & CASW_DamageAllocationMgr::Elem( const IndexType_t &I )
|
|
{
|
|
return *I;
|
|
}
|
|
|
|
|
|
inline bool CASW_DamageAllocationMgr::IsProjectileForTarget( IndexType_t iTarget, CBaseEntity *pProjectile )
|
|
{
|
|
return GetProjectileIndexInTarget( iTarget, pProjectile ) != ProjectilePool_t::InvalidIndex();
|
|
}
|
|
|
|
inline float CASW_DamageAllocationMgr::Allocate( CBaseEntity *pTarget, CBaseEntity *pProjectile, float flDamage )
|
|
{
|
|
IndexType_t i = Find(pTarget);
|
|
if ( !IsValid(i) )
|
|
{
|
|
AssertMsg2( false, "Tried to allocate %s as a damage projectile to %s but it isn't managed\n",
|
|
pProjectile->GetDebugName(), pTarget->GetDebugName() );
|
|
i = Insert( pTarget );
|
|
}
|
|
return Allocate( i, pProjectile, flDamage );
|
|
}
|
|
|
|
inline float CASW_DamageAllocationMgr::Deallocate( CBaseEntity *pTarget, CBaseEntity *pProjectile )
|
|
{
|
|
IndexType_t i = Find(pTarget);
|
|
if ( !IsValid(i) )
|
|
{
|
|
AssertMsg2( false, "Tried to remove %s as a damage projectile to unmanaged %s\n",
|
|
pProjectile->GetDebugName(), pTarget->GetDebugName() );
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return Deallocate( i, pProjectile );
|
|
}
|
|
}
|
|
|
|
inline CASW_DamageAllocationMgr::IndexType_t CASW_DamageAllocationMgr::InvalidIndex()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
inline bool CASW_DamageAllocationMgr::IsValid( const IndexType_t &I ) const
|
|
{
|
|
return I != InvalidIndex();
|
|
}
|
|
|
|
class CASW_Rocket : public CBaseCombatCharacter
|
|
{
|
|
DECLARE_CLASS( CASW_Rocket, CBaseCombatCharacter );
|
|
DECLARE_SERVERCLASS();
|
|
public:
|
|
static const int EXPLOSION_RADIUS = 200;
|
|
|
|
CASW_Rocket();
|
|
virtual ~CASW_Rocket();
|
|
|
|
Class_T Classify( void ) { return CLASS_MISSILE; }
|
|
|
|
virtual void Spawn( void );
|
|
virtual void Activate( void );
|
|
virtual void StopLoopingSounds( void );
|
|
virtual void Precache( void );
|
|
|
|
void MissileTouch( CBaseEntity *pOther );
|
|
void Explode( void );
|
|
void AccelerateThink( void );
|
|
void IgniteThink( void );
|
|
void SeekThink( void );
|
|
void DumbFire( void );
|
|
void SetGracePeriod( float flGracePeriod );
|
|
|
|
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
|
|
void Event_Killed( const CTakeDamageInfo &info );
|
|
|
|
virtual float GetDamage() { return m_flDamage; }
|
|
virtual void SetDamage(float flDamage) { m_flDamage = flDamage; }
|
|
|
|
unsigned int PhysicsSolidMaskForEntity( void ) const;
|
|
|
|
static CASW_Rocket *Create( float fDamage, const Vector &vecOrigin, const QAngle &vecAngles, CBaseCombatCharacter *pentOwner = NULL , CBaseEntity * pCreatorWeapon = NULL, const char *className = "asw_rocket" );
|
|
|
|
void CreateDangerSounds( bool bState ){ m_bCreateDangerSounds = bState; }
|
|
|
|
void FindHomingPosition( Vector *pTarget );
|
|
CBaseEntity *FindPotentialTarget( void ) const ; /// find a good enemy for us to target. The enemy isn't actually targeted until the result is written back to m_hHomingTarget
|
|
void SetTarget( CBaseEntity *pTarget );
|
|
inline CBaseEntity *GetTarget( void ) { return m_hHomingTarget.Get(); }
|
|
|
|
virtual void DrawDebugGeometryOverlays();
|
|
|
|
int m_iAttributeEffects;
|
|
|
|
EHANDLE m_hCreatorWeapon;
|
|
Class_T m_CreatorWeaponClass;
|
|
|
|
protected:
|
|
virtual void DoExplosion(bool bHitwall);
|
|
Vector IntegrateRocketThrust( const Vector &vTargetDir, float flDist ) const ;
|
|
void ComputeWallDodge( const Vector &vCurVel ); /// if we're headed for a wall, adjust the wobble angles so we steer away
|
|
|
|
float GetLifeFraction() const;
|
|
|
|
bool IsWallDodging() const;
|
|
|
|
EHANDLE m_hHomingTarget;
|
|
|
|
float m_flDamage;
|
|
float m_fSpawnTime;
|
|
float m_fDieTime;
|
|
|
|
const char * m_szFlightSound;
|
|
const char * m_szDetonationSound;
|
|
|
|
static CASW_DamageAllocationMgr m_RocketAssigner;
|
|
|
|
private:
|
|
float m_flGracePeriodEndsAt;
|
|
float m_flNextWobbleTime;
|
|
|
|
QAngle m_vWobbleAngles; ///< will approach this direction while wobbling
|
|
|
|
bool m_bCreateDangerSounds;
|
|
bool m_bFlyingWild; // has no target, is wobbling crazily
|
|
|
|
DECLARE_DATADESC();
|
|
};
|
|
|
|
#endif // _INCLUDED_ASW_ROCKET_H
|