diff options
Diffstat (limited to 'game/server/hl2/weapon_flaregun.cpp')
| -rw-r--r-- | game/server/hl2/weapon_flaregun.cpp | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/game/server/hl2/weapon_flaregun.cpp b/game/server/hl2/weapon_flaregun.cpp new file mode 100644 index 0000000..d3fd6b1 --- /dev/null +++ b/game/server/hl2/weapon_flaregun.cpp @@ -0,0 +1,755 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Flare gun (fffsssssssssss!!) +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "player.h" +#include "gamerules.h" +#include "basehlcombatweapon.h" +#include "decals.h" +#include "soundenvelope.h" +#include "IEffects.h" +#include "engine/IEngineSound.h" +#include "weapon_flaregun.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +/******************************************************************** + NOTE: if you are looking at this file becase you would like flares + to be considered as fires (and thereby trigger gas traps), be aware + that the env_flare class is actually found in weapon_flaregun.cpp + and is really a repurposed piece of ammunition. (env_flare isn't the + rod-like safety flare prop, but rather the bit of flame on the end.) + + You will have some difficulty making it work here, because CFlare + does not inherit from CFire and will thus not be enumerated by + CFireSphere::EnumElement(). In order to have flares be detected and + used by this system, you will need to promote certain member functions + of CFire into an interface class from which both CFire and CFlare + inherit. You will also need to modify CFireSphere::EnumElement so that + it properly disambiguates between fires and flares. + + For some partial work towards this end, see changelist 192474. + + ********************************************************************/ + + +#define FLARE_LAUNCH_SPEED 1500 + +LINK_ENTITY_TO_CLASS( env_flare, CFlare ); + +BEGIN_DATADESC( CFlare ) + + DEFINE_FIELD( m_pOwner, FIELD_CLASSPTR ), + DEFINE_FIELD( m_nBounces, FIELD_INTEGER ), + DEFINE_FIELD( m_flTimeBurnOut, FIELD_TIME ), + DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "scale" ), + DEFINE_KEYFIELD( m_flDuration, FIELD_FLOAT, "duration" ), + DEFINE_FIELD( m_flNextDamage, FIELD_TIME ), + DEFINE_SOUNDPATCH( m_pBurnSound ), + DEFINE_FIELD( m_bFading, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bLight, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bSmoke, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bPropFlare, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bInActiveList, FIELD_BOOLEAN ), + DEFINE_FIELD( m_pNextFlare, FIELD_CLASSPTR ), + + //Input functions + DEFINE_INPUTFUNC( FIELD_FLOAT, "Start", InputStart ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "Die", InputDie ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "Launch", InputLaunch), + + // Function Pointers + DEFINE_FUNCTION( FlareTouch ), + DEFINE_FUNCTION( FlareBurnTouch ), + DEFINE_FUNCTION( FlareThink ), + +END_DATADESC() + +//Data-tables +IMPLEMENT_SERVERCLASS_ST( CFlare, DT_Flare ) + SendPropFloat( SENDINFO( m_flTimeBurnOut ), 0, SPROP_NOSCALE ), + SendPropFloat( SENDINFO( m_flScale ), 0, SPROP_NOSCALE ), + SendPropInt( SENDINFO( m_bLight ), 1, SPROP_UNSIGNED ), + SendPropInt( SENDINFO( m_bSmoke ), 1, SPROP_UNSIGNED ), + SendPropInt( SENDINFO( m_bPropFlare ), 1, SPROP_UNSIGNED ), +END_SEND_TABLE() + +CFlare *CFlare::activeFlares = NULL; + +CFlare *CFlare::GetActiveFlares( void ) +{ + return CFlare::activeFlares; +} + +Class_T CFlare::Classify( void ) +{ + return CLASS_FLARE; +} + +CBaseEntity *CreateFlare( Vector vOrigin, QAngle Angles, CBaseEntity *pOwner, float flDuration ) +{ + CFlare *pFlare = CFlare::Create( vOrigin, Angles, pOwner, flDuration ); + + if ( pFlare ) + { + pFlare->m_bPropFlare = true; + } + + return pFlare; +} + +void KillFlare( CBaseEntity *pOwnerEntity, CBaseEntity *pEntity, float flKillTime ) +{ + CFlare *pFlare = dynamic_cast< CFlare *>( pEntity ); + + if ( pFlare ) + { + float flDieTime = (pFlare->m_flTimeBurnOut - gpGlobals->curtime) - flKillTime; + + if ( flDieTime > 1.0f ) + { + pFlare->Die( flDieTime ); + pOwnerEntity->SetNextThink( gpGlobals->curtime + flDieTime + 3.0f ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CFlare::CFlare( void ) +{ + m_flScale = 1.0f; + m_nBounces = 0; + m_bFading = false; + m_bLight = true; + m_bSmoke = true; + m_flNextDamage = gpGlobals->curtime; + m_lifeState = LIFE_ALIVE; + m_iHealth = 100; + m_bPropFlare = false; + m_bInActiveList = false; + m_pNextFlare = NULL; +} + +CFlare::~CFlare() +{ + CSoundEnvelopeController::GetController().SoundDestroy( m_pBurnSound ); + m_pBurnSound = NULL; + + RemoveFromActiveFlares(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFlare::Precache( void ) +{ + PrecacheModel("models/weapons/flare.mdl" ); + + PrecacheScriptSound( "Weapon_FlareGun.Burn" ); + + // FIXME: needed to precache the fire model. Shouldn't have to do this. + UTIL_PrecacheOther( "_firesmoke" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &restore - +// Output : int +//----------------------------------------------------------------------------- +int CFlare::Restore( IRestore &restore ) +{ + int result = BaseClass::Restore( restore ); + + if ( m_spawnflags & SF_FLARE_NO_DLIGHT ) + { + m_bLight = false; + } + + if ( m_spawnflags & SF_FLARE_NO_SMOKE ) + { + m_bSmoke = false; + } + + return result; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFlare::Spawn( void ) +{ + Precache(); + + SetModel( "models/weapons/flare.mdl" ); + + UTIL_SetSize( this, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ) ); + + SetSolid( SOLID_BBOX ); + AddSolidFlags( FSOLID_NOT_SOLID ); + + SetMoveType( MOVETYPE_NONE ); + SetFriction( 0.6f ); + SetGravity( UTIL_ScaleForGravity( 400 ) ); + m_flTimeBurnOut = gpGlobals->curtime + 30; + + AddEffects( EF_NOSHADOW|EF_NORECEIVESHADOW ); + + if ( m_spawnflags & SF_FLARE_NO_DLIGHT ) + { + m_bLight = false; + } + + if ( m_spawnflags & SF_FLARE_NO_SMOKE ) + { + m_bSmoke = false; + } + + if ( m_spawnflags & SF_FLARE_INFINITE ) + { + m_flTimeBurnOut = -1.0f; + } + + if ( m_spawnflags & SF_FLARE_START_OFF ) + { + AddEffects( EF_NODRAW ); + } + + AddFlag( FL_OBJECT ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFlare::Activate( void ) +{ + BaseClass::Activate(); + + // Start the burning sound if we're already on + if ( ( m_spawnflags & SF_FLARE_START_OFF ) == false ) + { + StartBurnSound(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFlare::StartBurnSound( void ) +{ + if ( m_pBurnSound == NULL ) + { + CPASAttenuationFilter filter( this ); + m_pBurnSound = CSoundEnvelopeController::GetController().SoundCreate( + filter, entindex(), CHAN_WEAPON, "Weapon_FlareGun.Burn", 3.0f ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : vecOrigin - +// vecAngles - +// *pOwner - +// Output : CFlare +//----------------------------------------------------------------------------- +CFlare *CFlare::Create( Vector vecOrigin, QAngle vecAngles, CBaseEntity *pOwner, float lifetime ) +{ + CFlare *pFlare = (CFlare *) CreateEntityByName( "env_flare" ); + + if ( pFlare == NULL ) + return NULL; + + UTIL_SetOrigin( pFlare, vecOrigin ); + + pFlare->SetLocalAngles( vecAngles ); + pFlare->Spawn(); + pFlare->SetTouch( &CFlare::FlareTouch ); + pFlare->SetThink( &CFlare::FlareThink ); + + //Start up the flare + pFlare->Start( lifetime ); + + //Don't start sparking immediately + pFlare->SetNextThink( gpGlobals->curtime + 0.5f ); + + //Burn out time + pFlare->m_flTimeBurnOut = gpGlobals->curtime + lifetime; + + pFlare->RemoveSolidFlags( FSOLID_NOT_SOLID ); + pFlare->AddSolidFlags( FSOLID_NOT_STANDABLE ); + + pFlare->SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); + + pFlare->SetOwnerEntity( pOwner ); + pFlare->m_pOwner = pOwner; + + return pFlare; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +unsigned int CFlare::PhysicsSolidMaskForEntity( void ) const +{ + return MASK_NPCSOLID; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFlare::FlareThink( void ) +{ + float deltaTime = ( m_flTimeBurnOut - gpGlobals->curtime ); + + if ( !m_bInActiveList && ( ( deltaTime > FLARE_BLIND_TIME ) || ( m_flTimeBurnOut == -1.0f ) ) ) + { + AddToActiveFlares(); + } + + if ( m_flTimeBurnOut != -1.0f ) + { + //Fading away + if ( ( deltaTime <= FLARE_DECAY_TIME ) && ( m_bFading == false ) ) + { + m_bFading = true; + CSoundEnvelopeController::GetController().SoundChangePitch( m_pBurnSound, 60, deltaTime ); + CSoundEnvelopeController::GetController().SoundFadeOut( m_pBurnSound, deltaTime ); + } + + // if flare is no longer bright, remove it from active flare list + if ( m_bInActiveList && ( deltaTime <= FLARE_BLIND_TIME ) ) + { + RemoveFromActiveFlares(); + } + + //Burned out + if ( m_flTimeBurnOut < gpGlobals->curtime ) + { + UTIL_Remove( this ); + return; + } + } + + //Act differently underwater + if ( GetWaterLevel() > 1 ) + { + UTIL_Bubbles( GetAbsOrigin() + Vector( -2, -2, -2 ), GetAbsOrigin() + Vector( 2, 2, 2 ), 1 ); + m_bSmoke = false; + } + else + { + //Shoot sparks + if ( random->RandomInt( 0, 8 ) == 1 ) + { + g_pEffects->Sparks( GetAbsOrigin() ); + } + } + + //Next update + SetNextThink( gpGlobals->curtime + 0.1f ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pOther - +//----------------------------------------------------------------------------- +void CFlare::FlareBurnTouch( CBaseEntity *pOther ) +{ + if ( pOther && pOther->m_takedamage && ( m_flNextDamage < gpGlobals->curtime ) ) + { + pOther->TakeDamage( CTakeDamageInfo( this, m_pOwner, 1, (DMG_BULLET|DMG_BURN) ) ); + m_flNextDamage = gpGlobals->curtime + 1.0f; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pOther - +//----------------------------------------------------------------------------- +void CFlare::FlareTouch( CBaseEntity *pOther ) +{ + Assert( pOther ); + if ( !pOther->IsSolid() ) + return; + + if ( ( m_nBounces < 10 ) && ( GetWaterLevel() < 1 ) ) + { + // Throw some real chunks here + g_pEffects->Sparks( GetAbsOrigin() ); + } + + //If the flare hit a person or NPC, do damage here. + if ( pOther && pOther->m_takedamage ) + { + /* + The Flare is the iRifle round right now. No damage, just ignite. (sjb) + + //Damage is a function of how fast the flare is flying. + int iDamage = GetAbsVelocity().Length() / 50.0f; + + if ( iDamage < 5 ) + { + //Clamp minimum damage + iDamage = 5; + } + + //Use m_pOwner, not GetOwnerEntity() + pOther->TakeDamage( CTakeDamageInfo( this, m_pOwner, iDamage, (DMG_BULLET|DMG_BURN) ) ); + m_flNextDamage = gpGlobals->curtime + 1.0f; + */ + + CBaseAnimating *pAnim; + + pAnim = dynamic_cast<CBaseAnimating*>(pOther); + if( pAnim ) + { + pAnim->Ignite( 30.0f ); + } + + Vector vecNewVelocity = GetAbsVelocity(); + vecNewVelocity *= 0.1f; + SetAbsVelocity( vecNewVelocity ); + + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); + SetGravity(1.0f); + + + Die( 0.5 ); + + return; + } + else + { + // hit the world, check the material type here, see if the flare should stick. + trace_t tr; + tr = CBaseEntity::GetTouchTrace(); + + //Only do this on the first bounce + if ( m_nBounces == 0 ) + { + const surfacedata_t *pdata = physprops->GetSurfaceData( tr.surface.surfaceProps ); + + if ( pdata != NULL ) + { + //Only embed into concrete and wood (jdw: too obscure for players?) + //if ( ( pdata->gameMaterial == 'C' ) || ( pdata->gameMaterial == 'W' ) ) + { + Vector impactDir = ( tr.endpos - tr.startpos ); + VectorNormalize( impactDir ); + + float surfDot = tr.plane.normal.Dot( impactDir ); + + //Do not stick to ceilings or on shallow impacts + if ( ( tr.plane.normal.z > -0.5f ) && ( surfDot < -0.9f ) ) + { + RemoveSolidFlags( FSOLID_NOT_SOLID ); + AddSolidFlags( FSOLID_TRIGGER ); + UTIL_SetOrigin( this, tr.endpos + ( tr.plane.normal * 2.0f ) ); + SetAbsVelocity( vec3_origin ); + SetMoveType( MOVETYPE_NONE ); + + SetTouch( &CFlare::FlareBurnTouch ); + + int index = decalsystem->GetDecalIndexForName( "SmallScorch" ); + if ( index >= 0 ) + { + CBroadcastRecipientFilter filter; + te->Decal( filter, 0.0, &tr.endpos, &tr.startpos, ENTINDEX( tr.m_pEnt ), tr.hitbox, index ); + } + + CPASAttenuationFilter filter2( this, "Flare.Touch" ); + EmitSound( filter2, entindex(), "Flare.Touch" ); + + return; + } + } + } + } + + //Scorch decal + if ( GetAbsVelocity().LengthSqr() > (250*250) ) + { + int index = decalsystem->GetDecalIndexForName( "FadingScorch" ); + if ( index >= 0 ) + { + CBroadcastRecipientFilter filter; + te->Decal( filter, 0.0, &tr.endpos, &tr.startpos, ENTINDEX( tr.m_pEnt ), tr.hitbox, index ); + } + } + + // 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( this ); + + // Slow down + Vector vecNewVelocity = GetAbsVelocity(); + vecNewVelocity.x *= 0.8f; + vecNewVelocity.y *= 0.8f; + SetAbsVelocity( vecNewVelocity ); + + //Stopped? + if ( GetAbsVelocity().Length() < 64.0f ) + { + SetAbsVelocity( vec3_origin ); + SetMoveType( MOVETYPE_NONE ); + RemoveSolidFlags( FSOLID_NOT_SOLID ); + AddSolidFlags( FSOLID_TRIGGER ); + SetTouch( &CFlare::FlareBurnTouch ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFlare::Start( float lifeTime ) +{ + StartBurnSound(); + + if ( m_pBurnSound != NULL ) + { + CSoundEnvelopeController::GetController().Play( m_pBurnSound, 0.0f, 60 ); + CSoundEnvelopeController::GetController().SoundChangeVolume( m_pBurnSound, 0.8f, 2.0f ); + CSoundEnvelopeController::GetController().SoundChangePitch( m_pBurnSound, 100, 2.0f ); + } + + if ( lifeTime > 0 ) + { + m_flTimeBurnOut = gpGlobals->curtime + lifeTime; + } + else + { + m_flTimeBurnOut = -1.0f; + } + + RemoveEffects( EF_NODRAW ); + + SetThink( &CFlare::FlareThink ); + SetNextThink( gpGlobals->curtime + 0.1f ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFlare::Die( float fadeTime ) +{ + m_flTimeBurnOut = gpGlobals->curtime + fadeTime; + + SetThink( &CFlare::FlareThink ); + SetNextThink( gpGlobals->curtime + 0.1f ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFlare::Launch( const Vector &direction, float speed ) +{ + // Make sure we're visible + if ( m_spawnflags & SF_FLARE_INFINITE ) + { + Start( -1 ); + } + else + { + Start( 8.0f ); + } + + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); + + // Punch our velocity towards our facing + SetAbsVelocity( direction * speed ); + + SetGravity( 1.0f ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CFlare::InputStart( inputdata_t &inputdata ) +{ + Start( inputdata.value.Float() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CFlare::InputDie( inputdata_t &inputdata ) +{ + Die( inputdata.value.Float() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CFlare::InputLaunch( inputdata_t &inputdata ) +{ + Vector direction; + AngleVectors( GetAbsAngles(), &direction ); + + float speed = inputdata.value.Float(); + + if ( speed == 0 ) + { + speed = FLARE_LAUNCH_SPEED; + } + + Launch( direction, speed ); +} + +//----------------------------------------------------------------------------- +// Purpose: Removes flare from active flare list +//----------------------------------------------------------------------------- +void CFlare::RemoveFromActiveFlares( void ) +{ + CFlare *pFlare; + CFlare *pPrevFlare; + + if ( !m_bInActiveList ) + return; + + pPrevFlare = NULL; + for( pFlare = CFlare::activeFlares; pFlare != NULL; pFlare = pFlare->m_pNextFlare ) + { + if ( pFlare == this ) + { + if ( pPrevFlare ) + { + pPrevFlare->m_pNextFlare = m_pNextFlare; + } + else + { + activeFlares = m_pNextFlare; + } + break; + } + pPrevFlare = pFlare; + } + + m_pNextFlare = NULL; + m_bInActiveList = false; +} + +//----------------------------------------------------------------------------- +// Purpose: Adds flare to active flare list +//----------------------------------------------------------------------------- +void CFlare::AddToActiveFlares( void ) +{ + if ( !m_bInActiveList ) + { + m_pNextFlare = CFlare::activeFlares; + CFlare::activeFlares = this; + m_bInActiveList = true; + } +} + +#if 0 + +IMPLEMENT_SERVERCLASS_ST(CFlaregun, DT_Flaregun) +END_SEND_TABLE() + +LINK_ENTITY_TO_CLASS( weapon_flaregun, CFlaregun ); +PRECACHE_WEAPON_REGISTER( weapon_flaregun ); + +//----------------------------------------------------------------------------- +// Purpose: Precache +//----------------------------------------------------------------------------- +void CFlaregun::Precache( void ) +{ + BaseClass::Precache(); + + PrecacheScriptSound( "Flare.Touch" ); + + PrecacheScriptSound( "Weapon_FlareGun.Burn" ); + + UTIL_PrecacheOther( "env_flare" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Main attack +//----------------------------------------------------------------------------- +void CFlaregun::PrimaryAttack( void ) +{ + CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); + + if ( pOwner == NULL ) + return; + + if ( m_iClip1 <= 0 ) + { + SendWeaponAnim( ACT_VM_DRYFIRE ); + pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration(); + return; + } + + m_iClip1 = m_iClip1 - 1; + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + pOwner->m_flNextAttack = gpGlobals->curtime + 1; + + CFlare *pFlare = CFlare::Create( pOwner->Weapon_ShootPosition(), pOwner->EyeAngles(), pOwner, FLARE_DURATION ); + + if ( pFlare == NULL ) + return; + + Vector forward; + pOwner->EyeVectors( &forward ); + + pFlare->SetAbsVelocity( forward * 1500 ); + + WeaponSound( SINGLE ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFlaregun::SecondaryAttack( void ) +{ + CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); + + if ( pOwner == NULL ) + return; + + if ( m_iClip1 <= 0 ) + { + SendWeaponAnim( ACT_VM_DRYFIRE ); + pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration(); + return; + } + + m_iClip1 = m_iClip1 - 1; + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + pOwner->m_flNextAttack = gpGlobals->curtime + 1; + + CFlare *pFlare = CFlare::Create( pOwner->Weapon_ShootPosition(), pOwner->EyeAngles(), pOwner, FLARE_DURATION ); + + if ( pFlare == NULL ) + return; + + Vector forward; + pOwner->EyeVectors( &forward ); + + pFlare->SetAbsVelocity( forward * 500 ); + pFlare->SetGravity(1.0f); + pFlare->SetFriction( 0.85f ); + pFlare->SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); + + WeaponSound( SINGLE ); +} + +#endif |