diff options
Diffstat (limited to 'game/server/hl2/weapon_immolator.cpp')
| -rw-r--r-- | game/server/hl2/weapon_immolator.cpp | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/game/server/hl2/weapon_immolator.cpp b/game/server/hl2/weapon_immolator.cpp new file mode 100644 index 0000000..539d342 --- /dev/null +++ b/game/server/hl2/weapon_immolator.cpp @@ -0,0 +1,373 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "basehlcombatweapon.h" +#include "basecombatcharacter.h" +#include "player.h" +#include "soundent.h" +#include "te_particlesystem.h" +#include "ndebugoverlay.h" +#include "in_buttons.h" +#include "ai_basenpc.h" +#include "ai_memory.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define MAX_BURN_RADIUS 256 +#define RADIUS_GROW_RATE 50.0 // units/sec + +#define IMMOLATOR_TARGET_INVALID Vector( FLT_MAX, FLT_MAX, FLT_MAX ) + +class CWeaponImmolator : public CBaseHLCombatWeapon +{ +public: + DECLARE_CLASS( CWeaponImmolator, CBaseHLCombatWeapon ); + + DECLARE_SERVERCLASS(); + + CWeaponImmolator( void ); + + void Precache( void ); + void PrimaryAttack( void ); + void ItemPostFrame( void ); + + int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; } + + void ImmolationDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore ); + virtual bool WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ); + virtual int WeaponRangeAttack1Condition( float flDot, float flDist ); + + void Update(); + void UpdateThink(); + + void StartImmolating(); + void StopImmolating(); + bool IsImmolating() { return m_flBurnRadius != 0.0; } + + DECLARE_ACTTABLE(); + DECLARE_DATADESC(); + + int m_beamIndex; + + float m_flBurnRadius; + float m_flTimeLastUpdatedRadius; + + Vector m_vecImmolatorTarget; +}; + +IMPLEMENT_SERVERCLASS_ST(CWeaponImmolator, DT_WeaponImmolator) +END_SEND_TABLE() + +LINK_ENTITY_TO_CLASS( info_target_immolator, CPointEntity ); +LINK_ENTITY_TO_CLASS( weapon_immolator, CWeaponImmolator ); +PRECACHE_WEAPON_REGISTER( weapon_immolator ); + +BEGIN_DATADESC( CWeaponImmolator ) + + DEFINE_FIELD( m_beamIndex, FIELD_INTEGER ), + DEFINE_FIELD( m_flBurnRadius, FIELD_FLOAT ), + DEFINE_FIELD( m_flTimeLastUpdatedRadius, FIELD_TIME ), + DEFINE_FIELD( m_vecImmolatorTarget, FIELD_VECTOR ), + + DEFINE_ENTITYFUNC( UpdateThink ), +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Maps base activities to weapons-specific ones so our characters do the right things. +//----------------------------------------------------------------------------- +acttable_t CWeaponImmolator::m_acttable[] = +{ + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SNIPER_RIFLE, true } +}; + +IMPLEMENT_ACTTABLE( CWeaponImmolator ); + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CWeaponImmolator::CWeaponImmolator( void ) +{ + m_fMaxRange1 = 4096; + StopImmolating(); +} + +void CWeaponImmolator::StartImmolating() +{ + // Start the radius really tiny because we use radius == 0.0 to + // determine whether the immolator is operating or not. + m_flBurnRadius = 0.1; + m_flTimeLastUpdatedRadius = gpGlobals->curtime; + SetThink( UpdateThink ); + SetNextThink( gpGlobals->curtime ); + + CSoundEnt::InsertSound( SOUND_DANGER, m_vecImmolatorTarget, 256, 5.0, GetOwner() ); +} + +void CWeaponImmolator::StopImmolating() +{ + m_flBurnRadius = 0.0; + SetThink( NULL ); + m_vecImmolatorTarget= IMMOLATOR_TARGET_INVALID; + m_flNextPrimaryAttack = gpGlobals->curtime + 5.0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponImmolator::Precache( void ) +{ + m_beamIndex = PrecacheModel( "sprites/bluelaser1.vmt" ); + + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponImmolator::PrimaryAttack( void ) +{ + WeaponSound( SINGLE ); + + if( !IsImmolating() ) + { + StartImmolating(); + } +} + +//----------------------------------------------------------------------------- +// This weapon is said to have Line of Sight when it CAN'T see the target, but +// can see a place near the target than can. +//----------------------------------------------------------------------------- +bool CWeaponImmolator::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) +{ + CAI_BaseNPC* npcOwner = GetOwner()->MyNPCPointer(); + + if( !npcOwner ) + { + return false; + } + + if( IsImmolating() ) + { + // Don't update while Immolating. This is a committed attack. + return false; + } + + // Assume we won't find a target. + m_vecImmolatorTarget = targetPos; + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Weapon firing conditions +//----------------------------------------------------------------------------- +int CWeaponImmolator::WeaponRangeAttack1Condition( float flDot, float flDist ) +{ + if( m_flNextPrimaryAttack > gpGlobals->curtime ) + { + // Too soon to attack! + return COND_NONE; + } + + if( IsImmolating() ) + { + // Once is enough! + return COND_NONE; + } + + if( m_vecImmolatorTarget == IMMOLATOR_TARGET_INVALID ) + { + // No target! + return COND_NONE; + } + + if ( flDist > m_fMaxRange1 ) + { + return COND_TOO_FAR_TO_ATTACK; + } + else if ( flDot < 0.5f ) // UNDONE: Why check this here? Isn't the AI checking this already? + { + return COND_NOT_FACING_ATTACK; + } + + return COND_CAN_RANGE_ATTACK1; +} + +void CWeaponImmolator::UpdateThink( void ) +{ + CBaseCombatCharacter *pOwner = GetOwner(); + + if( pOwner && !pOwner->IsAlive() ) + { + StopImmolating(); + return; + } + + Update(); + SetNextThink( gpGlobals->curtime + 0.05 ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CWeaponImmolator::Update() +{ + float flDuration = gpGlobals->curtime - m_flTimeLastUpdatedRadius; + if( flDuration != 0.0 ) + { + m_flBurnRadius += RADIUS_GROW_RATE * flDuration; + } + + // Clamp + m_flBurnRadius = MIN( m_flBurnRadius, MAX_BURN_RADIUS ); + + CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); + + Vector vecSrc; + Vector vecAiming; + + if( pOwner ) + { + vecSrc = pOwner->Weapon_ShootPosition( ); + vecAiming = pOwner->GetAutoaimVector(AUTOAIM_2DEGREES); + } + else + { + CBaseCombatCharacter *pOwner = GetOwner(); + + vecSrc = pOwner->Weapon_ShootPosition( ); + vecAiming = m_vecImmolatorTarget - vecSrc; + VectorNormalize( vecAiming ); + } + + trace_t tr; + UTIL_TraceLine( vecSrc, vecSrc + vecAiming * MAX_TRACE_LENGTH, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); + + int brightness; + brightness = 255 * (m_flBurnRadius/MAX_BURN_RADIUS); + UTIL_Beam( vecSrc, + tr.endpos, + m_beamIndex, + 0, //halo index + 0, //frame start + 2.0f, //framerate + 0.1f, //life + 20, // width + 1, // endwidth + 0, // fadelength, + 1, // noise + + 0, // red + 255, // green + 0, // blue, + + brightness, // bright + 100 // speed + ); + + + if( tr.DidHitWorld() ) + { + int beams; + + for( beams = 0 ; beams < 5 ; beams++ ) + { + Vector vecDest; + + // Random unit vector + vecDest.x = random->RandomFloat( -1, 1 ); + vecDest.y = random->RandomFloat( -1, 1 ); + vecDest.z = random->RandomFloat( 0, 1 ); + + // Push out to radius dist. + vecDest = tr.endpos + vecDest * m_flBurnRadius; + + UTIL_Beam( tr.endpos, + vecDest, + m_beamIndex, + 0, //halo index + 0, //frame start + 2.0f, //framerate + 0.15f, //life + 20, // width + 1.75, // endwidth + 0.75, // fadelength, + 15, // noise + + 0, // red + 255, // green + 0, // blue, + + 128, // bright + 100 // speed + ); + } + + // Immolator starts to hurt a few seconds after the effect is seen + if( m_flBurnRadius > 64.0 ) + { + ImmolationDamage( CTakeDamageInfo( this, this, 1, DMG_BURN ), tr.endpos, m_flBurnRadius, CLASS_NONE ); + } + } + else + { + // The attack beam struck some kind of entity directly. + } + + m_flTimeLastUpdatedRadius = gpGlobals->curtime; + + if( m_flBurnRadius >= MAX_BURN_RADIUS ) + { + StopImmolating(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponImmolator::ItemPostFrame( void ) +{ + BaseClass::ItemPostFrame(); +} + + + +void CWeaponImmolator::ImmolationDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore ) +{ + CBaseEntity *pEntity = NULL; + trace_t tr; + Vector vecSpot; + + Vector vecSrc = vecSrcIn; + + // iterate on all entities in the vicinity. + for ( CEntitySphereQuery sphere( vecSrc, flRadius ); pEntity = sphere.GetCurrentEntity(); sphere.NextEntity() ) + { + CBaseCombatCharacter *pBCC; + + pBCC = pEntity->MyCombatCharacterPointer(); + + if ( pBCC && !pBCC->IsOnFire() ) + { + // UNDONE: this should check a damage mask, not an ignore + if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) + { + continue; + } + + if( pEntity == GetOwner() ) + { + continue; + } + + pBCC->Ignite( random->RandomFloat( 15, 20 ) ); + } + } +} |