diff options
Diffstat (limited to 'game/server/tf2/gasoline_blob.cpp')
| -rw-r--r-- | game/server/tf2/gasoline_blob.cpp | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/game/server/tf2/gasoline_blob.cpp b/game/server/tf2/gasoline_blob.cpp new file mode 100644 index 0000000..e9c4a54 --- /dev/null +++ b/game/server/tf2/gasoline_blob.cpp @@ -0,0 +1,279 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "gasoline_blob.h" +#include "gasoline_shared.h" +#include "utllinkedlist.h" +#include "fire_damage_mgr.h" +#include "tf_gamerules.h" + + +// Flamethrower blobs wait a bit before they cause damage so they don't hurt the guy +// shooting them. +#define BLOB_DAMAGE_WAIT_TIME 1.0 + + +// At what heat level does an unlit blob ignite? +#define IGNITION_HEAT 0.1 + + +#define FIRE_DAMAGE_SEARCH_DISTANCE 200 // It searches within this sphere for entities to damage. +#define FIRE_DAMAGE_DISTANCE 90 // This is how far fire can damage an entity from. + + +ConVar fire_enable( "fire_enable", "1", 0, "Enable or disable fire." ); + + +// ------------------------------------------------------------------------------------------ // +// CGasolineBlob implementation. +// ------------------------------------------------------------------------------------------ // + +IMPLEMENT_SERVERCLASS_ST_NOBASE( CGasolineBlob, DT_GasolineBlob ) + SendPropVector( SENDINFO(m_vecOrigin), -1, SPROP_COORD ), + SendPropEHandle (SENDINFO_NAME(m_hMoveParent, moveparent)), + SendPropFloat( SENDINFO(m_flLitStartTime), -1, SPROP_NOSCALE ), + + SendPropFloat( SENDINFO(m_flCreateTime), -1, SPROP_NOSCALE ), + SendPropFloat( SENDINFO(m_flMaxLifetime), -1, SPROP_NOSCALE ), + + SendPropInt( SENDINFO(m_iTeamNum), TEAMNUM_NUM_BITS, 0 ), + SendPropInt( SENDINFO( m_BlobFlags ), NUM_BLOB_FLAGS, SPROP_UNSIGNED ), + SendPropVector( SENDINFO( m_vSurfaceNormal ), 0, SPROP_NORMAL ), +END_SEND_TABLE() + + +LINK_ENTITY_TO_CLASS( gasoline_blob, CGasolineBlob ); + + +CUtlLinkedList<CGasolineBlob*, int> g_GasolineBlobs; + + +CGasolineBlob* CGasolineBlob::Create( + CBaseEntity *pOwner, + const Vector &vOrigin, + const Vector &vStartVelocity, + bool bUseGravity, + float flAirLifetime, + float flLifetime ) +{ + CGasolineBlob *pBlob = (CGasolineBlob*)CreateEntityByName( "gasoline_blob" ); + if ( !pBlob ) + return NULL; + + // The "constructor". + pBlob->SetLocalOrigin( vOrigin ); + pBlob->SetAbsVelocity( vStartVelocity ); + pBlob->SetThink( &CGasolineBlob::Think ); + pBlob->SetNextThink( gpGlobals->curtime ); + pBlob->SetCollisionBounds( Vector( -GASOLINE_BLOB_RADIUS, -GASOLINE_BLOB_RADIUS, -GASOLINE_BLOB_RADIUS ), Vector( GASOLINE_BLOB_RADIUS, GASOLINE_BLOB_RADIUS, GASOLINE_BLOB_RADIUS ) ); + pBlob->SetMoveType( MOVETYPE_NONE ); + pBlob->SetSolid( SOLID_BBOX ); + pBlob->AddSolidFlags( FSOLID_NOT_SOLID ); + pBlob->AddEFlags( EFL_FORCE_CHECK_TRANSMIT ); + pBlob->m_BlobFlags = 0; + pBlob->m_HeatLevel = 0; + pBlob->m_hOwner = pOwner; + pBlob->m_flCreateTime = gpGlobals->curtime; + pBlob->m_flMaxLifetime = flLifetime; + pBlob->m_takedamage = DAMAGE_YES; + pBlob->m_flLitStartTime = 0; + pBlob->ChangeTeam( pOwner->GetTeamNumber() ); + + if ( bUseGravity ) + pBlob->m_BlobFlags |= BLOBFLAG_USE_GRAVITY; + + pBlob->m_flAirLifetime = flAirLifetime; + pBlob->m_flTimeInAir = 0; + + pBlob->SetNextThink( gpGlobals->curtime ); + g_GasolineBlobs.AddToTail( pBlob ); + + return pBlob; +} + + +CGasolineBlob::~CGasolineBlob() +{ + g_GasolineBlobs.Remove( g_GasolineBlobs.Find( this ) ); +} + + +void CGasolineBlob::AddAutoBurnBlob( CGasolineBlob *pBlob ) +{ + int index = m_AutoBurnBlobs.AddToTail(); + m_AutoBurnBlobs[index] = pBlob; +} + + +int CGasolineBlob::OnTakeDamage( const CTakeDamageInfo &info ) +{ + m_HeatLevel += info.GetDamage(); + if ( m_HeatLevel >= IGNITION_HEAT ) + SetLit( true ); + + return 0; +} + + +void CGasolineBlob::SetLit( bool bLit ) +{ + if ( bLit != IsLit() ) + { + if ( bLit ) + { + m_BlobFlags |= BLOBFLAG_LIT; + m_flLitStartTime = gpGlobals->curtime; + } + else + { + m_BlobFlags &= ~BLOBFLAG_LIT; + } + } +} + + +bool CGasolineBlob::IsLit() const +{ + return (m_BlobFlags & BLOBFLAG_LIT) != 0; +} + + +bool CGasolineBlob::IsStopped() const +{ + return (m_BlobFlags & BLOBFLAG_STOPPED) != 0; +} + + +void CGasolineBlob::AutoBurn_R( CGasolineBlob *pParent ) +{ + SetLit( true ); + + for ( int i=0; i < m_AutoBurnBlobs.Count(); i++ ) + { + CGasolineBlob *pTestBlob = m_AutoBurnBlobs[i]; + + if ( pTestBlob ) + { + if ( pTestBlob != pParent ) + pTestBlob->AutoBurn_R( this ); + } + else + { + m_AutoBurnBlobs.Remove( i ); + --i; + } + } +} + + +void CGasolineBlob::Think() +{ + if ( !fire_enable.GetInt() ) + { + UTIL_Remove( this ); + return; + } + + // Decay quickly while in the air. + if ( !IsStopped() ) + { + m_flTimeInAir += gpGlobals->frametime; + if ( m_flTimeInAir >= m_flAirLifetime ) + { + UTIL_Remove( this ); + return; + } + } + + float flLifetime = gpGlobals->curtime - m_flCreateTime; + if ( flLifetime >= m_flMaxLifetime ) + { + UTIL_Remove( this ); + return; + } + + if ( IsLit() ) + { + // Have we burnt out? + float litPercent = 1 - (flLifetime / m_flMaxLifetime); + if ( litPercent <= 0 ) + { + UTIL_Remove( this ); + return; + } + + // Look for nearby entities to burn. + CBaseEntity *ents[512]; + float dists[512]; + int nEnts = FindBurnableEntsInSphere( ents, dists, ARRAYSIZE( ents ), GetAbsOrigin(), FIRE_DAMAGE_SEARCH_DISTANCE, m_hOwner ); + + for ( int i=0; i < nEnts; i++ ) + { + float flDistFromBorder = MAX( 0, FIRE_DAMAGE_DISTANCE - dists[i] ); + if ( flDistFromBorder <= 0 ) + continue; + + float flDamage = litPercent * flDistFromBorder / FIRE_DAMAGE_DISTANCE * FIRE_DAMAGE_PER_SEC; + GetFireDamageMgr()->AddDamage( ents[i], m_hOwner, flDamage, !IsGasolineBlob( ents[i] ) ); + } + + // Ignite our "auto burn" blobs. + AutoBurn_R( NULL ); + } + + // Figure out where we want to go. + if ( !IsStopped() ) + { + // Apply gravity. + Vector vecNewVelocity = GetAbsVelocity(); + if ( m_BlobFlags & BLOBFLAG_USE_GRAVITY ) + { + vecNewVelocity.z -= 800 * gpGlobals->frametime; + SetAbsVelocity( vecNewVelocity ); + } + + Vector vNewPos = GetAbsOrigin() + vecNewVelocity * gpGlobals->frametime; + + // Can we go there? + trace_t trace; + UTIL_TraceLine( GetAbsOrigin(), vNewPos, CONTENTS_SOLID, NULL, COLLISION_GROUP_NONE, &trace ); + bool bStopped = (trace.fraction != 1); + + if ( !bStopped ) + { + // Trace against shields. + if ( TFGameRules()->IsTraceBlockedByWorldOrShield( GetAbsOrigin(), vNewPos, m_hOwner, DMG_BURN, &trace ) ) + { + // Blobs just fizzle out when they hit a shield. + UTIL_Remove( this ); + } + } + + if( bStopped ) + { + SetLocalOrigin( trace.endpos + trace.plane.normal * 2 ); + + // Ok, we hit something. Stop moving. + m_BlobFlags |= BLOBFLAG_STOPPED; + m_vSurfaceNormal = trace.plane.normal; + } + else + { + SetLocalOrigin( vNewPos ); + } + } + + SetNextThink( gpGlobals->curtime ); +} + + +bool IsGasolineBlob( CBaseEntity *pEnt ) +{ + return FClassnameIs( pEnt, "gasoline_blob" ); +} + |