diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/tf/tf_triggers.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/server/tf/tf_triggers.cpp')
| -rw-r--r-- | game/server/tf/tf_triggers.cpp | 1021 |
1 files changed, 1021 insertions, 0 deletions
diff --git a/game/server/tf/tf_triggers.cpp b/game/server/tf/tf_triggers.cpp new file mode 100644 index 0000000..2001d09 --- /dev/null +++ b/game/server/tf/tf_triggers.cpp @@ -0,0 +1,1021 @@ +//========= 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 ); +} |