sqwarmed/sdk_src/game/server/swarm/asw_rocket.h

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