You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1021 lines
22 KiB
1021 lines
22 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Team Fortress specific special triggers |
|
// |
|
//===========================================================================// |
|
|
|
#include "cbase.h" |
|
#include "player.h" |
|
#include "gamerules.h" |
|
#include "entityapi.h" |
|
#include "entitylist.h" |
|
#include "saverestore_utlvector.h" |
|
#include "tf_player.h" |
|
#include "triggers.h" |
|
#include "tf_triggers.h" |
|
#include "tf_weapon_compound_bow.h" |
|
#include "doors.h" |
|
#include "bot/tf_bot.h" |
|
#include "trigger_area_capture.h" |
|
#include "particle_parse.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
BEGIN_DATADESC( CTriggerStun ) |
|
|
|
// Function Pointers |
|
DEFINE_FUNCTION( StunThink ), |
|
|
|
// Fields |
|
|
|
DEFINE_KEYFIELD( m_flTriggerDelay, FIELD_FLOAT, "trigger_delay" ), |
|
DEFINE_KEYFIELD( m_flStunDuration, FIELD_FLOAT, "stun_duration" ), |
|
DEFINE_KEYFIELD( m_flMoveSpeedReduction, FIELD_FLOAT, "move_speed_reduction" ), |
|
DEFINE_KEYFIELD( m_iStunType, FIELD_INTEGER, "stun_type" ), |
|
DEFINE_KEYFIELD( m_bStunEffects, FIELD_INTEGER, "stun_effects" ), |
|
|
|
DEFINE_UTLVECTOR( m_stunEntities, FIELD_EHANDLE ), |
|
|
|
// Outputs |
|
DEFINE_OUTPUT( m_OnStunPlayer, "OnStunPlayer" ), |
|
|
|
END_DATADESC() |
|
|
|
|
|
LINK_ENTITY_TO_CLASS( trigger_stun, CTriggerStun ); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when spawning, after keyvalues have been handled. |
|
//----------------------------------------------------------------------------- |
|
void CTriggerStun::Spawn( void ) |
|
{ |
|
BaseClass::Spawn(); |
|
|
|
InitTrigger(); |
|
|
|
SetNextThink( TICK_NEVER_THINK ); |
|
SetThink( NULL ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: When touched, a stun trigger applies its stunflags to the other for a duration. |
|
// Input : pOther - The entity that is touching us. |
|
//----------------------------------------------------------------------------- |
|
bool CTriggerStun::StunEntity( CBaseEntity *pOther ) |
|
{ |
|
if ( !pOther->m_takedamage || !PassesTriggerFilters(pOther) ) |
|
return false; |
|
|
|
CTFPlayer* pTFPlayer = ToTFPlayer( pOther ); |
|
if ( !pTFPlayer ) |
|
return false; |
|
|
|
int iStunFlags = TF_STUN_MOVEMENT; |
|
switch ( m_iStunType ) |
|
{ |
|
case 0: |
|
// Movement Only |
|
break; |
|
case 1: |
|
// Controls |
|
iStunFlags |= TF_STUN_CONTROLS; |
|
break; |
|
case 2: |
|
// Loser State |
|
iStunFlags |= TF_STUN_LOSER_STATE; |
|
break; |
|
} |
|
|
|
if ( !m_bStunEffects ) |
|
{ |
|
iStunFlags |= TF_STUN_NO_EFFECTS; |
|
} |
|
|
|
iStunFlags |= TF_STUN_BY_TRIGGER; |
|
|
|
pTFPlayer->m_Shared.StunPlayer( m_flStunDuration, m_flMoveSpeedReduction, iStunFlags, NULL ); |
|
|
|
m_OnStunPlayer.FireOutput( pOther, this ); |
|
m_stunEntities.AddToTail( EHANDLE(pOther) ); |
|
|
|
return true; |
|
} |
|
|
|
void CTriggerStun::StunThink() |
|
{ |
|
// If I stun anyone, think again. |
|
if ( StunAllTouchers( 0.5 ) <= 0 ) |
|
{ |
|
SetThink(NULL); |
|
} |
|
else |
|
{ |
|
SetNextThink( gpGlobals->curtime + 0.5f ); |
|
} |
|
} |
|
|
|
void CTriggerStun::EndTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( PassesTriggerFilters(pOther) ) |
|
{ |
|
EHANDLE hOther; |
|
hOther = pOther; |
|
|
|
// If this guy has never been stunned... |
|
if ( !m_stunEntities.HasElement( hOther ) ) |
|
{ |
|
StunEntity( pOther ); |
|
} |
|
} |
|
BaseClass::EndTouch( pOther ); |
|
} |
|
|
|
int CTriggerStun::StunAllTouchers( float dt ) |
|
{ |
|
m_flLastStunTime = gpGlobals->curtime; |
|
m_stunEntities.RemoveAll(); |
|
|
|
int stunCount = 0; |
|
touchlink_t *root = ( touchlink_t * )GetDataObject( TOUCHLINK ); |
|
if ( root ) |
|
{ |
|
for ( touchlink_t *link = root->nextLink; link != root; link = link->nextLink ) |
|
{ |
|
CBaseEntity *pTouch = link->entityTouched; |
|
if ( pTouch ) |
|
{ |
|
if ( StunEntity( pTouch ) ) |
|
{ |
|
stunCount++; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return stunCount; |
|
} |
|
|
|
void CTriggerStun::Touch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_pfnThink == NULL ) |
|
{ |
|
SetThink( &CTriggerStun::StunThink ); |
|
SetNextThink( gpGlobals->curtime + m_flTriggerDelay ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Ignites the arrows of any bow carried by a player who touches this trigger |
|
//----------------------------------------------------------------------------- |
|
class CTriggerIgniteArrows : public CBaseTrigger |
|
{ |
|
public: |
|
DECLARE_CLASS( CTriggerIgniteArrows, CBaseTrigger ); |
|
|
|
void Spawn( void ); |
|
void Touch( CBaseEntity *pOther ); |
|
|
|
DECLARE_DATADESC(); |
|
}; |
|
|
|
BEGIN_DATADESC( CTriggerIgniteArrows ) |
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( trigger_ignite_arrows, CTriggerIgniteArrows ); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTriggerIgniteArrows::Spawn( void ) |
|
{ |
|
BaseClass::Spawn(); |
|
InitTrigger(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Ignites the arrows of any bow carried by a player who touches this trigger |
|
//----------------------------------------------------------------------------- |
|
void CTriggerIgniteArrows::Touch( CBaseEntity *pOther ) |
|
{ |
|
if (!PassesTriggerFilters(pOther)) |
|
return; |
|
|
|
if ( !pOther->IsPlayer() ) |
|
return; |
|
|
|
CTFPlayer *pPlayer = ToTFPlayer( pOther ); |
|
|
|
// Ignore non-snipers |
|
if ( !pPlayer || !pPlayer->IsPlayerClass(TF_CLASS_SNIPER) ) |
|
return; |
|
|
|
// Make sure they're looking at the origin |
|
Vector vecPos, vecForward, vecUp, vecRight; |
|
pPlayer->EyePositionAndVectors( &vecPos, &vecForward, &vecUp, &vecRight ); |
|
Vector vTargetDir = GetAbsOrigin() - vecPos; |
|
VectorNormalize(vTargetDir); |
|
float fDotPr = DotProduct(vecForward,vTargetDir); |
|
if (fDotPr < 0.95) |
|
return; |
|
|
|
// Does he have the bow? |
|
CTFWeaponBase *pWpn = pPlayer->GetActiveTFWeapon(); |
|
if ( pWpn && pWpn->GetWeaponID() == TF_WEAPON_COMPOUND_BOW ) |
|
{ |
|
CTFCompoundBow *pBow = static_cast<CTFCompoundBow*>( pWpn ); |
|
pBow->SetArrowAlight( true ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Trigger that controls door speed by specified time |
|
//----------------------------------------------------------------------------- |
|
class CTriggerTimerDoor : public CTriggerAreaCapture |
|
{ |
|
public: |
|
DECLARE_CLASS( CTriggerTimerDoor, CTriggerAreaCapture ); |
|
DECLARE_DATADESC(); |
|
|
|
virtual void Spawn( void ) OVERRIDE; |
|
virtual void StartTouch( CBaseEntity *pOther ) OVERRIDE; |
|
|
|
virtual void OnStartCapture( int iTeam ) OVERRIDE; |
|
virtual void OnEndCapture( int iTeam ) OVERRIDE; |
|
|
|
protected: |
|
virtual bool CaptureModeScalesWithPlayers() const OVERRIDE { return false; } |
|
|
|
private: |
|
CHandle<CBaseDoor> m_hDoor; //the door that we are linked to! |
|
|
|
string_t m_iszDoorName; |
|
}; |
|
|
|
BEGIN_DATADESC( CTriggerTimerDoor ) |
|
DEFINE_KEYFIELD( m_iszDoorName, FIELD_STRING, "door_name" ), |
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( trigger_timer_door, CTriggerTimerDoor ); |
|
|
|
#define GATE_THINK_TIME 0.1f |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTriggerTimerDoor::Spawn( void ) |
|
{ |
|
BaseClass::Spawn(); |
|
InitTrigger(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Bot enters the trigger, open the door |
|
//----------------------------------------------------------------------------- |
|
void CTriggerTimerDoor::StartTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_bDisabled ) |
|
return; |
|
|
|
if (!PassesTriggerFilters(pOther)) |
|
return; |
|
|
|
if ( !m_hDoor ) |
|
{ |
|
m_hDoor = dynamic_cast< CBaseDoor* >( gEntList.FindEntityByName(NULL, m_iszDoorName ) ); |
|
if ( !m_hDoor ) |
|
{ |
|
Warning( "trigger_bot_gate failed to find \"%s\" door entity", STRING( m_iszDoorName ) ); |
|
return; |
|
} |
|
else |
|
{ |
|
float flDoorTravelDistance = ( m_hDoor->m_vecPosition2 - m_hDoor->m_vecPosition1 ).Length(); |
|
m_hDoor->m_flSpeed = flDoorTravelDistance / GetCapTime(); |
|
} |
|
} |
|
|
|
BaseClass::StartTouch( pOther ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Bot starts opening the door |
|
//----------------------------------------------------------------------------- |
|
void CTriggerTimerDoor::OnStartCapture( int iTeam ) |
|
{ |
|
BaseClass::OnStartCapture( iTeam ); |
|
|
|
if ( FStrEq( gpGlobals->mapname.ToCStr(), "mvm_mannhattan" ) ) |
|
{ |
|
TFGameRules()->RandomPlayersSpeakConceptIfAllowed( MP_CONCEPT_MANNHATTAN_GATE_ATK, 1, TF_TEAM_RED ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Bot finishes opening the door |
|
//----------------------------------------------------------------------------- |
|
void CTriggerTimerDoor::OnEndCapture( int iTeam ) |
|
{ |
|
BaseClass::OnEndCapture( iTeam ); |
|
|
|
if ( FStrEq( gpGlobals->mapname.ToCStr(), "mvm_mannhattan" ) ) |
|
{ |
|
TFGameRules()->RandomPlayersSpeakConceptIfAllowed( MP_CONCEPT_MANNHATTAN_GATE_TAKE, 1, TF_TEAM_RED ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Trigger that adds tag to bots |
|
//----------------------------------------------------------------------------- |
|
class CTriggerBotTag : public CBaseTrigger |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CTriggerBotTag, CBaseTrigger ); |
|
|
|
virtual void Spawn( void ); |
|
|
|
virtual void Touch( CBaseEntity *pOther ); |
|
|
|
private: |
|
string_t m_iszTags; |
|
|
|
bool m_bAdd; |
|
CUtlStringList m_tags; |
|
}; |
|
|
|
BEGIN_DATADESC( CTriggerBotTag ) |
|
DEFINE_KEYFIELD( m_iszTags, FIELD_STRING, "tags" ), |
|
DEFINE_KEYFIELD( m_bAdd, FIELD_BOOLEAN, "add" ), |
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( trigger_bot_tag, CTriggerBotTag ); |
|
|
|
void CTriggerBotTag::Spawn() |
|
{ |
|
BaseClass::Spawn(); |
|
InitTrigger(); |
|
|
|
m_tags.RemoveAll(); |
|
// chop space-delimited string into individual tokens |
|
const char *tags = STRING( m_iszTags ); |
|
if ( tags ) |
|
{ |
|
CSplitString splitStrings( tags, " " ); |
|
for( int i=0; i<splitStrings.Count(); ++i ) |
|
{ |
|
m_tags.CopyAndAddToTail( splitStrings.Element( i ) ); |
|
} |
|
} |
|
} |
|
|
|
|
|
void CTriggerBotTag::Touch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_bDisabled ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !pOther->IsPlayer() ) |
|
{ |
|
return; |
|
} |
|
|
|
CTFBot *pBot = ToTFBot( pOther ); |
|
if ( !pBot ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( m_bAdd ) |
|
{ |
|
for ( int i=0; i<m_tags.Count(); ++i ) |
|
{ |
|
pBot->AddTag( m_tags[i] ); |
|
} |
|
} |
|
else |
|
{ |
|
for ( int i=0; i<m_tags.Count(); ++i ) |
|
{ |
|
pBot->RemoveTag( m_tags[i] ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Trigger that adds a condition to players |
|
//----------------------------------------------------------------------------- |
|
class CTriggerAddTFPlayerCondition : public CBaseTrigger |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CTriggerAddTFPlayerCondition, CBaseTrigger ); |
|
|
|
virtual void Spawn( void ); |
|
|
|
virtual void StartTouch( CBaseEntity *pOther ); |
|
virtual void EndTouch( CBaseEntity *pOther ); |
|
|
|
private: |
|
ETFCond m_nCondition; |
|
|
|
float m_flDuration; |
|
}; |
|
|
|
BEGIN_DATADESC( CTriggerAddTFPlayerCondition ) |
|
DEFINE_KEYFIELD( m_nCondition, FIELD_INTEGER, "condition" ), |
|
DEFINE_KEYFIELD( m_flDuration, FIELD_FLOAT, "duration" ), |
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( trigger_add_tf_player_condition, CTriggerAddTFPlayerCondition ); |
|
|
|
void CTriggerAddTFPlayerCondition::Spawn() |
|
{ |
|
BaseClass::Spawn(); |
|
InitTrigger(); |
|
} |
|
|
|
|
|
void CTriggerAddTFPlayerCondition::StartTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_bDisabled ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !PassesTriggerFilters(pOther) ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !pOther->IsPlayer() ) |
|
{ |
|
return; |
|
} |
|
|
|
CTFPlayer *pPlayer = ToTFPlayer( pOther ); |
|
if ( !pPlayer ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( m_nCondition != TF_COND_INVALID ) |
|
{ |
|
pPlayer->m_Shared.AddCond( m_nCondition, m_flDuration ); |
|
BaseClass::StartTouch( pOther ); |
|
} |
|
else |
|
{ |
|
Warning( "Invalid Condition ID [%d] in trigger %s\n", m_nCondition, GetEntityName().ToCStr() ); |
|
} |
|
} |
|
|
|
void CTriggerAddTFPlayerCondition::EndTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_flDuration != PERMANENT_CONDITION ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( m_bDisabled ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !PassesTriggerFilters(pOther) ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !pOther->IsPlayer() ) |
|
{ |
|
return; |
|
} |
|
|
|
CTFPlayer *pPlayer = ToTFPlayer( pOther ); |
|
if ( !pPlayer ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( m_nCondition != TF_COND_INVALID ) |
|
{ |
|
pPlayer->m_Shared.RemoveCond( m_nCondition ); |
|
BaseClass::EndTouch( pOther ); |
|
} |
|
else |
|
{ |
|
Warning( "Invalid Condition ID [%d] in trigger %s\n", m_nCondition, GetEntityName().ToCStr() ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: CTriggerPlayerRespawnOverride |
|
//----------------------------------------------------------------------------- |
|
BEGIN_DATADESC( CTriggerPlayerRespawnOverride ) |
|
DEFINE_KEYFIELD( m_flRespawnTime, FIELD_FLOAT, "RespawnTime" ), |
|
DEFINE_KEYFIELD( m_strRespawnEnt, FIELD_STRING, "RespawnName" ), |
|
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetRespawnTime", InputSetRespawnTime ), |
|
DEFINE_INPUTFUNC( FIELD_STRING, "SetRespawnName", InputSetRespawnName ), |
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( trigger_player_respawn_override, CTriggerPlayerRespawnOverride ); |
|
|
|
IMPLEMENT_AUTO_LIST( ITriggerPlayerRespawnOverride ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Trigger that ignites players |
|
//----------------------------------------------------------------------------- |
|
class CTriggerIgnite : public CBaseTrigger |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CTriggerIgnite, CBaseTrigger ); |
|
|
|
CTriggerIgnite(); |
|
|
|
virtual void Spawn( void ); |
|
virtual void Precache( void ); |
|
|
|
virtual void StartTouch( CBaseEntity *pOther ); |
|
|
|
void BurnThink(); |
|
|
|
private: |
|
void IgniteEntity( CBaseEntity *pOther ); |
|
int BurnEntities(); |
|
|
|
float m_flBurnDuration; |
|
float m_flDamagePercentPerSecond; |
|
string_t m_iszIgniteParticleName; |
|
string_t m_iszIgniteSoundName; |
|
|
|
float m_flLastBurnTime; |
|
}; |
|
|
|
BEGIN_DATADESC( CTriggerIgnite ) |
|
DEFINE_KEYFIELD( m_flBurnDuration, FIELD_FLOAT, "burn_duration" ), |
|
DEFINE_KEYFIELD( m_flDamagePercentPerSecond, FIELD_FLOAT, "damage_percent_per_second" ), |
|
DEFINE_KEYFIELD( m_iszIgniteParticleName, FIELD_STRING, "ignite_particle_name" ), |
|
DEFINE_KEYFIELD( m_iszIgniteSoundName, FIELD_STRING, "ignite_sound_name" ), |
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( trigger_ignite, CTriggerIgnite ); |
|
|
|
#define BURN_INTERVAL 0.1f |
|
|
|
|
|
CTriggerIgnite::CTriggerIgnite() |
|
{ |
|
m_flBurnDuration = 1.f; |
|
m_flDamagePercentPerSecond = 10.f; |
|
m_flLastBurnTime = 0.f; |
|
} |
|
|
|
|
|
void CTriggerIgnite::Spawn() |
|
{ |
|
BaseClass::Spawn(); |
|
InitTrigger(); |
|
|
|
SetNextThink( TICK_NEVER_THINK ); |
|
SetThink( NULL ); |
|
} |
|
|
|
|
|
void CTriggerIgnite::Precache( void ) |
|
{ |
|
BaseClass::Precache(); |
|
|
|
const char *pszParticleName = STRING( m_iszIgniteParticleName ); |
|
if ( pszParticleName && *pszParticleName ) |
|
{ |
|
PrecacheParticleSystem( pszParticleName ); |
|
} |
|
|
|
const char *pszSoundName = STRING( m_iszIgniteSoundName ); |
|
if ( pszSoundName && *pszSoundName ) |
|
{ |
|
PrecacheScriptSound( pszSoundName ); |
|
} |
|
} |
|
|
|
|
|
void CTriggerIgnite::BurnThink() |
|
{ |
|
if ( BurnEntities() > 0 ) |
|
{ |
|
SetNextThink( gpGlobals->curtime + BURN_INTERVAL ); |
|
} |
|
else |
|
{ |
|
SetThink( NULL ); |
|
} |
|
} |
|
|
|
|
|
void CTriggerIgnite::StartTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_bDisabled ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !PassesTriggerFilters(pOther) ) |
|
{ |
|
return; |
|
} |
|
|
|
IgniteEntity( pOther ); |
|
|
|
BaseClass::StartTouch( pOther ); |
|
|
|
if ( m_pfnThink == NULL ) |
|
{ |
|
m_flLastBurnTime = gpGlobals->curtime; |
|
SetThink( &CTriggerIgnite::BurnThink ); |
|
SetNextThink( gpGlobals->curtime + BURN_INTERVAL ); |
|
} |
|
} |
|
|
|
|
|
void CTriggerIgnite::IgniteEntity( CBaseEntity *pOther ) |
|
{ |
|
Vector vecEffectPos = pOther->GetAbsOrigin(); |
|
const char *pszParticleName = STRING( m_iszIgniteParticleName ); |
|
if ( pszParticleName && *pszParticleName ) |
|
{ |
|
DispatchParticleEffect( pszParticleName, vecEffectPos, vec3_angle ); |
|
} |
|
|
|
const char *pszSoundName = STRING( m_iszIgniteSoundName ); |
|
if ( pszSoundName && *pszSoundName ) |
|
{ |
|
CSoundParameters params; |
|
if ( CBaseEntity::GetParametersForSound( pszSoundName, params, NULL ) ) |
|
{ |
|
CPASAttenuationFilter soundFilter( vecEffectPos, params.soundlevel ); |
|
EmitSound_t ep( params ); |
|
ep.m_pOrigin = &vecEffectPos; |
|
EmitSound( soundFilter, entindex(), ep ); |
|
} |
|
} |
|
|
|
if ( pOther->IsPlayer() ) |
|
{ |
|
CTFPlayer *pTFPlayer = ToTFPlayer( pOther ); |
|
if ( pTFPlayer && !pTFPlayer->m_Shared.IsInvulnerable() && !pTFPlayer->m_Shared.InCond( TF_COND_BURNING ) ) |
|
{ |
|
pTFPlayer->m_Shared.SelfBurn( m_flBurnDuration ); |
|
} |
|
} |
|
else |
|
{ |
|
UTIL_Remove( pOther ); |
|
} |
|
} |
|
|
|
|
|
int CTriggerIgnite::BurnEntities() |
|
{ |
|
if ( m_hTouchingEntities.IsEmpty() ) |
|
return 0; |
|
|
|
float flDT = gpGlobals->curtime - m_flLastBurnTime; |
|
m_flLastBurnTime = gpGlobals->curtime; |
|
int nBurn = 0; |
|
FOR_EACH_VEC( m_hTouchingEntities, i ) |
|
{ |
|
CBaseEntity *pEnt = m_hTouchingEntities[i]; |
|
if ( pEnt && pEnt->IsPlayer() ) |
|
{ |
|
CTFPlayer *pTFPlayer = ToTFPlayer( pEnt ); |
|
if ( pTFPlayer ) |
|
{ |
|
float flDamageScale = m_flDamagePercentPerSecond * 0.01f; |
|
float flDamage = flDT * flDamageScale * pTFPlayer->GetMaxHealth(); |
|
CTakeDamageInfo info( this, this, flDamage, DMG_BURN ); |
|
if ( !pTFPlayer->m_Shared.IsInvulnerable() && !pTFPlayer->m_Shared.InCond( TF_COND_BURNING ) ) // if player enters trigger invuln, we need to ignite them when it wears off. We also don't want to ignite an already burning player |
|
{ |
|
IgniteEntity( pTFPlayer ); |
|
} |
|
|
|
pTFPlayer->TakeDamage( info ); |
|
nBurn++; |
|
} |
|
} |
|
} |
|
|
|
return nBurn; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Trigger that spawn particles on entities |
|
//----------------------------------------------------------------------------- |
|
class CTriggerParticle : public CBaseTrigger |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CTriggerParticle, CBaseTrigger ); |
|
|
|
CTriggerParticle(); |
|
|
|
virtual void Spawn( void ); |
|
virtual void Precache( void ); |
|
|
|
virtual void StartTouch( CBaseEntity *pOther ); |
|
|
|
private: |
|
string_t m_iszParticleName; |
|
string_t m_iszAttachmentName; |
|
ParticleAttachment_t m_nAttachType; |
|
}; |
|
|
|
BEGIN_DATADESC( CTriggerParticle ) |
|
DEFINE_KEYFIELD( m_iszParticleName, FIELD_STRING, "particle_name" ), |
|
DEFINE_KEYFIELD( m_iszAttachmentName, FIELD_STRING, "attachment_name" ), |
|
DEFINE_KEYFIELD( m_nAttachType, FIELD_INTEGER, "attachment_type" ), |
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( trigger_particle, CTriggerParticle ); |
|
|
|
|
|
CTriggerParticle::CTriggerParticle() |
|
{ |
|
m_nAttachType = PATTACH_ABSORIGIN; |
|
} |
|
|
|
|
|
void CTriggerParticle::Spawn() |
|
{ |
|
BaseClass::Spawn(); |
|
InitTrigger(); |
|
|
|
SetNextThink( TICK_NEVER_THINK ); |
|
SetThink( NULL ); |
|
} |
|
|
|
|
|
void CTriggerParticle::Precache( void ) |
|
{ |
|
BaseClass::Precache(); |
|
|
|
const char *pszParticleName = STRING( m_iszParticleName ); |
|
if ( pszParticleName && *pszParticleName ) |
|
{ |
|
PrecacheParticleSystem( pszParticleName ); |
|
} |
|
} |
|
|
|
|
|
void CTriggerParticle::StartTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_bDisabled ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !PassesTriggerFilters(pOther) ) |
|
{ |
|
return; |
|
} |
|
|
|
BaseClass::StartTouch( pOther ); |
|
|
|
const char *pszParticleName = STRING( m_iszParticleName ); |
|
const char *pszAttachmentName = STRING( m_iszAttachmentName ); |
|
int iAttachment = -1; |
|
if ( pszAttachmentName && *pszAttachmentName ) |
|
{ |
|
iAttachment = pOther->GetBaseAnimating()->LookupAttachment( pszAttachmentName ); |
|
} |
|
|
|
DispatchParticleEffect( pszParticleName, m_nAttachType, pOther, iAttachment ); |
|
} |
|
|
|
|
|
class CTriggerRemoveTFPlayerCondition : public CBaseTrigger |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CTriggerRemoveTFPlayerCondition, CBaseTrigger ); |
|
|
|
virtual void Spawn( void ); |
|
|
|
virtual void StartTouch( CBaseEntity *pOther ); |
|
|
|
private: |
|
ETFCond m_nCondition; |
|
}; |
|
|
|
|
|
BEGIN_DATADESC( CTriggerRemoveTFPlayerCondition ) |
|
DEFINE_KEYFIELD( m_nCondition, FIELD_INTEGER, "condition" ), |
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( trigger_remove_tf_player_condition, CTriggerRemoveTFPlayerCondition ); |
|
|
|
|
|
void CTriggerRemoveTFPlayerCondition::Spawn() |
|
{ |
|
BaseClass::Spawn(); |
|
InitTrigger(); |
|
} |
|
|
|
|
|
void CTriggerRemoveTFPlayerCondition::StartTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_bDisabled ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !PassesTriggerFilters(pOther) ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !pOther->IsPlayer() ) |
|
{ |
|
return; |
|
} |
|
|
|
CTFPlayer *pPlayer = ToTFPlayer( pOther ); |
|
if ( !pPlayer ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( m_nCondition != TF_COND_INVALID ) |
|
{ |
|
pPlayer->m_Shared.RemoveCond( m_nCondition ); |
|
|
|
// Hack for Bank until we re-address this for parachuting MvM bots |
|
CTFBot *pTFBot = dynamic_cast< CTFBot* >( pPlayer ); |
|
if ( pTFBot ) |
|
{ |
|
pTFBot->ClearLastKnownArea(); |
|
} |
|
} |
|
else |
|
{ |
|
pPlayer->m_Shared.RemoveAllCond(); |
|
} |
|
|
|
BaseClass::StartTouch( pOther ); |
|
} |
|
|
|
|
|
class CTriggerAddOrRemoveTFPlayerAttributes : public CBaseTrigger |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CTriggerAddOrRemoveTFPlayerAttributes, CBaseTrigger ); |
|
|
|
virtual void Spawn( void ); |
|
|
|
virtual void StartTouch( CBaseEntity *pOther ); |
|
virtual void EndTouch( CBaseEntity *pOther ); |
|
|
|
private: |
|
bool m_bRemove; |
|
string_t m_iszAttributeName; |
|
float m_flAttributeValue; |
|
float m_flDuration; |
|
bool m_bValidAttribute; |
|
}; |
|
|
|
|
|
BEGIN_DATADESC( CTriggerAddOrRemoveTFPlayerAttributes ) |
|
DEFINE_KEYFIELD( m_bRemove, FIELD_BOOLEAN, "add_or_remove" ), |
|
DEFINE_KEYFIELD( m_iszAttributeName, FIELD_STRING, "attribute_name" ), |
|
DEFINE_KEYFIELD( m_flAttributeValue, FIELD_FLOAT, "value" ), |
|
DEFINE_KEYFIELD( m_flDuration, FIELD_FLOAT, "duration" ), |
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( trigger_add_or_remove_tf_player_attributes, CTriggerAddOrRemoveTFPlayerAttributes ); |
|
|
|
|
|
void CTriggerAddOrRemoveTFPlayerAttributes::Spawn() |
|
{ |
|
BaseClass::Spawn(); |
|
InitTrigger(); |
|
|
|
m_bValidAttribute = false; |
|
const char *pszAttrName = STRING( m_iszAttributeName ); |
|
if ( pszAttrName && *pszAttrName ) |
|
{ |
|
CSchemaAttributeDefHandle pAttrTest( pszAttrName ); |
|
if ( pAttrTest ) |
|
{ |
|
m_bValidAttribute = true; |
|
} |
|
else |
|
{ |
|
Warning( "Invalid attribute name '%s' from trigger trigger_add_or_remove_tf_player_attributes name '%s'\n", pszAttrName, STRING( GetEntityName() ) ); |
|
} |
|
} |
|
} |
|
|
|
|
|
void CTriggerAddOrRemoveTFPlayerAttributes::StartTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_bDisabled ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !m_bValidAttribute ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !PassesTriggerFilters(pOther) ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !pOther->IsPlayer() ) |
|
{ |
|
return; |
|
} |
|
|
|
CTFPlayer *pPlayer = ToTFPlayer( pOther ); |
|
if ( !pPlayer ) |
|
{ |
|
return; |
|
} |
|
|
|
const char *pszAttrName = STRING( m_iszAttributeName ); |
|
if ( m_bRemove ) |
|
{ |
|
pPlayer->RemoveCustomAttribute( pszAttrName ); |
|
} |
|
else |
|
{ |
|
pPlayer->AddCustomAttribute( pszAttrName, m_flAttributeValue, m_flDuration ); |
|
} |
|
|
|
BaseClass::StartTouch( pOther ); |
|
} |
|
|
|
|
|
void CTriggerAddOrRemoveTFPlayerAttributes::EndTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( m_bDisabled ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !m_bValidAttribute ) |
|
{ |
|
return; |
|
} |
|
|
|
// only run auto remove on added attribute |
|
if ( m_bRemove ) |
|
{ |
|
return; |
|
} |
|
|
|
// ignore timer attribute. it'll remove itself |
|
if ( m_flDuration > 0.f ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !PassesTriggerFilters(pOther) ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !pOther->IsPlayer() ) |
|
{ |
|
return; |
|
} |
|
|
|
CTFPlayer *pPlayer = ToTFPlayer( pOther ); |
|
if ( !pPlayer ) |
|
{ |
|
return; |
|
} |
|
|
|
// remove permanent attribute on exist trigger |
|
const char *pszAttrName = STRING( m_iszAttributeName ); |
|
pPlayer->RemoveCustomAttribute( pszAttrName ); |
|
|
|
BaseClass::EndTouch( pOther ); |
|
}
|
|
|