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.
611 lines
16 KiB
611 lines
16 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "tf_gamerules.h" |
|
#include "teleport_vortex.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
#ifdef CLIENT_DLL |
|
|
|
#include "c_tf_fx.h" |
|
|
|
inline float SCurve( float t ) |
|
{ |
|
t = clamp( t, 0.0f, 1.0f ); |
|
return t * t * (3 - 2*t); |
|
} |
|
|
|
#else |
|
|
|
#include "tf_fx.h" |
|
#include "tf_team.h" |
|
#include "tf_weapon_sniperrifle.h" |
|
|
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
ConVar vortex_float_osc_speed( "vortex_float_osc_speed", "2.0", FCVAR_HIDDEN | FCVAR_CHEAT | FCVAR_REPLICATED ); |
|
ConVar vortex_float_amp( "vortex_float_amp", "5.0", FCVAR_HIDDEN | FCVAR_CHEAT | FCVAR_REPLICATED ); |
|
ConVar vortex_fade_fraction_denom( "vortex_fade_fraction_denom", "10.0", FCVAR_HIDDEN | FCVAR_CHEAT | FCVAR_REPLICATED ); |
|
ConVar vortex_book_offset( "vortex_book_offset", "5.0", FCVAR_HIDDEN | FCVAR_CHEAT | FCVAR_REPLICATED ); |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( TeleportVortex, DT_TeleportVortex ) |
|
|
|
BEGIN_NETWORK_TABLE( CTeleportVortex, DT_TeleportVortex ) |
|
#if defined( CLIENT_DLL ) |
|
RecvPropInt( RECVINFO( m_iState ) ), |
|
#else |
|
SendPropInt( SENDINFO( m_iState ), 4, SPROP_UNSIGNED | SPROP_CHANGES_OFTEN ), |
|
#endif |
|
END_NETWORK_TABLE() |
|
|
|
LINK_ENTITY_TO_CLASS( teleport_vortex, CTeleportVortex ); |
|
|
|
BEGIN_DATADESC( CTeleportVortex ) |
|
END_DATADESC() |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
#define VORTEX_PARTICLE_EFFECT_EYEBALL_MOVED "eyeboss_tp_vortex" |
|
#define VORTEX_PARTICLE_EFFECT_EYEBALL_DIED "eyeboss_aura_angry" |
|
|
|
#define VORTEX_BOOK_MODEL "models/props_halloween/bombonomicon.mdl" |
|
|
|
#define VORTEX_SOUND_EYEBALL_MOVED "Halloween.TeleportVortex.EyeballMovedVortex" |
|
#define VORTEX_SOUND_EYEBALL_DIED "Halloween.TeleportVortex.EyeballDiedVortex" |
|
#define VORTEX_SOUND_BOOK_SPAWN "Halloween.TeleportVortex.BookSpawn" |
|
#define VORTEX_SOUND_BOOK_EXIT "Halloween.TeleportVortex.BookExit" |
|
|
|
#define VORTEX_OPEN_OPEN_ANIM "flip_stimulated" |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
CTeleportVortex::CTeleportVortex() |
|
#ifdef GAME_DLL |
|
: m_iAutoSetupVortex( -1 ) |
|
#endif |
|
{ |
|
} |
|
|
|
CTeleportVortex::~CTeleportVortex() |
|
{ |
|
#ifdef CLIENT_DLL |
|
DestroyParticleEffect(); |
|
#endif |
|
} |
|
|
|
#ifdef CLIENT_DLL |
|
void CTeleportVortex::DestroyParticleEffect() |
|
{ |
|
if ( m_pVortexEffect ) |
|
{ |
|
ParticleProp()->StopEmission( m_pVortexEffect ); |
|
m_pVortexEffect = NULL; |
|
} |
|
} |
|
#else |
|
bool CTeleportVortex::KeyValue( const char *szKeyname, const char *szValue ) |
|
{ |
|
if ( !V_strnicmp( szKeyname, "type", 4 ) ) |
|
{ |
|
m_iAutoSetupVortex = atoi( szValue ); |
|
} |
|
else |
|
{ |
|
return BaseClass::KeyValue( szKeyname, szValue ); |
|
} |
|
|
|
return true; |
|
} |
|
#endif |
|
|
|
void CTeleportVortex::Spawn( void ) |
|
{ |
|
Precache(); |
|
BaseClass::Spawn(); |
|
|
|
AddEffects( EF_NODRAW ); |
|
SetMoveType( MOVETYPE_NONE ); |
|
SetSolid( SOLID_BBOX ); |
|
CollisionProp()->SetCollisionBounds( Vector( -50, -50, -50 ), Vector( 50, 50, 50 ) ); |
|
SetModelName( NULL_STRING ); |
|
SetSolidFlags( FSOLID_TRIGGER ); |
|
SetCollisionGroup( COLLISION_GROUP_WEAPON ); |
|
SetRenderMode( kRenderTransAlpha ); |
|
SetRenderColorA( 255 ); |
|
UseClientSideAnimation(); |
|
|
|
m_lifeTimer.Start( 5.0f ); |
|
|
|
#ifdef CLIENT_DLL |
|
m_flScale = 1.0f; |
|
m_iOldState = VORTEXSTATE_INACTIVE; |
|
m_pVortexEffect = NULL; |
|
|
|
ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS ); |
|
|
|
AddToLeafSystem( RENDER_GROUP_TWOPASS ); |
|
#else |
|
// Default to purgatory |
|
m_pszWhere = "spawn_purgatory"; |
|
|
|
SetThink( &CTeleportVortex::VortexThink ); |
|
SetNextThink( gpGlobals->curtime ); |
|
|
|
m_nSoundCounter = 0; |
|
|
|
m_bSplitTeam = false; |
|
|
|
if ( m_iAutoSetupVortex >= 0 ) |
|
{ |
|
SetupVortex( m_iAutoSetupVortex != 0 ); |
|
} |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CTeleportVortex::Precache( void ) |
|
{ |
|
BaseClass::Precache(); |
|
|
|
PrecacheModel( VORTEX_BOOK_MODEL ); |
|
|
|
// We deliberately allow late precaches here. |
|
bool bAllowPrecache = CBaseAnimating::IsPrecacheAllowed(); |
|
CBaseAnimating::SetAllowPrecache( true ); |
|
|
|
#if GAME_DLL |
|
PrecacheScriptSound( VORTEX_SOUND_EYEBALL_MOVED ); |
|
PrecacheScriptSound( VORTEX_SOUND_EYEBALL_DIED ); |
|
PrecacheScriptSound( VORTEX_SOUND_BOOK_SPAWN ); |
|
PrecacheScriptSound( VORTEX_SOUND_BOOK_EXIT ); |
|
#endif |
|
|
|
PrecacheParticleSystem( VORTEX_PARTICLE_EFFECT_EYEBALL_MOVED ); |
|
PrecacheParticleSystem( VORTEX_PARTICLE_EFFECT_EYEBALL_DIED ); |
|
|
|
CBaseAnimating::SetAllowPrecache( bAllowPrecache ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
#ifdef GAME_DLL |
|
|
|
void CTeleportVortex::Touch( CBaseEntity *pOther ) |
|
{ |
|
BaseClass::Touch( pOther ); |
|
|
|
if ( pOther && pOther->IsPlayer() ) |
|
{ |
|
if ( m_bSplitTeam ) |
|
{ |
|
const char* pszTeam = pOther->GetTeamNumber() == TF_TEAM_RED ? "_red" : "_blue"; |
|
SendPlayerToTheUnderworld( ToTFPlayer( pOther ), CFmtStr( "%s%s", m_pszWhere.Get(), pszTeam ) ); |
|
} |
|
else |
|
{ |
|
SendPlayerToTheUnderworld( ToTFPlayer( pOther ), m_pszWhere ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
int CTeleportVortex::UpdateTransmitState( void ) |
|
{ |
|
return SetTransmitState( FL_EDICT_PVSCHECK ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CTeleportVortex::StartTouch( CBaseEntity *pOther ) |
|
{ |
|
CBaseAnimating::StartTouch( pOther ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CTeleportVortex::SetupVortex( bool bIsDeathVortex, bool bSplitTeam /*= false*/ ) |
|
{ |
|
m_bSplitTeam = bSplitTeam; |
|
if ( bIsDeathVortex ) |
|
{ |
|
m_iState = VORTEXSTATE_ACTIVE_EYEBALL_DIED; |
|
m_pszWhere = "spawn_loot"; |
|
RemoveEffects( EF_NODRAW ); |
|
SetModel( VORTEX_BOOK_MODEL ); |
|
} |
|
else |
|
{ |
|
m_iState = VORTEXSTATE_ACTIVE_EYEBALL_MOVED; |
|
m_pszWhere = "spawn_purgatory"; |
|
AddEffects( EF_NODRAW ); |
|
} |
|
} |
|
|
|
void CTeleportVortex::VortexThink() |
|
{ |
|
if ( m_lifeTimer.IsElapsed() ) |
|
{ |
|
UTIL_Remove( this ); |
|
} |
|
else |
|
{ |
|
StudioFrameAdvance(); |
|
|
|
if ( m_iState == VORTEXSTATE_ACTIVE_EYEBALL_DIED ) |
|
{ |
|
if ( m_nSoundCounter == 0 && ShouldDoBookRampIn() ) |
|
{ |
|
EmitSound( VORTEX_SOUND_BOOK_SPAWN ); |
|
++m_nSoundCounter; |
|
} |
|
else if ( m_nSoundCounter == 1 && ShouldDoBookRampOut() ) |
|
{ |
|
EmitSound( VORTEX_SOUND_BOOK_EXIT ); |
|
++m_nSoundCounter; |
|
} |
|
} |
|
|
|
SetNextThink( gpGlobals->curtime ); |
|
} |
|
|
|
// suck nearby players into the vortex |
|
CUtlVector< CTFPlayer * > playerVector; |
|
CollectPlayers( &playerVector, TF_TEAM_RED, COLLECT_ONLY_LIVING_PLAYERS ); |
|
CollectPlayers( &playerVector, TF_TEAM_BLUE, COLLECT_ONLY_LIVING_PLAYERS, APPEND_PLAYERS ); |
|
|
|
const float suctionRange = 500.0f; |
|
|
|
for( int i=0; i<playerVector.Count(); ++i ) |
|
{ |
|
CTFPlayer *player = playerVector[i]; |
|
|
|
if ( player->GetFlags() & FL_ONGROUND ) |
|
{ |
|
// not airborne |
|
continue; |
|
} |
|
|
|
Vector toVortex = WorldSpaceCenter() - player->WorldSpaceCenter(); |
|
float range = toVortex.NormalizeInPlace(); |
|
|
|
if ( range > suctionRange ) |
|
{ |
|
// too far |
|
continue; |
|
} |
|
|
|
if ( player->IsLookingTowards( WorldSpaceCenter() ) ) |
|
{ |
|
if ( player->IsLineOfSightClear( WorldSpaceCenter(), CBaseCombatCharacter::IGNORE_ACTORS, player ) ) |
|
{ |
|
player->ApplyAbsVelocityImpulse( 30.0f * toVortex ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------------------------------- |
|
void SendPlayerToTheUnderworld( CTFPlayer *teleportingPlayer, const char *where ) |
|
{ |
|
if ( !teleportingPlayer ) |
|
{ |
|
return; |
|
} |
|
|
|
CUtlVector< CBaseEntity * > spawnVector; |
|
|
|
CBaseEntity *spawnPoint = NULL; |
|
while( ( spawnPoint = gEntList.FindEntityByClassname( spawnPoint, "info_target" ) ) != NULL ) |
|
{ |
|
if ( FStrEq( STRING( spawnPoint->GetEntityName() ), where ) ) |
|
{ |
|
spawnVector.AddToTail( spawnPoint ); |
|
} |
|
} |
|
|
|
if ( spawnVector.Count() == 0 ) |
|
{ |
|
Warning( "SendPlayerToTheUnderworld: No info_target entities named '%s' found!\n", where ); |
|
return; |
|
} |
|
|
|
// collect enemies that could block our spawning |
|
CUtlVector< CTFPlayer * > enemyVector; |
|
CollectPlayers( &enemyVector, GetEnemyTeam( teleportingPlayer->GetTeamNumber() ), COLLECT_ONLY_LIVING_PLAYERS ); |
|
|
|
const float nearRange = 25.0f; |
|
|
|
// collect spots without players overlapping them |
|
CUtlVector< CBaseEntity * > openSpawnVector; |
|
for( int i=0; i<spawnVector.Count(); ++i ) |
|
{ |
|
int p; |
|
|
|
for( p=0; p<enemyVector.Count(); ++p ) |
|
{ |
|
if ( ( spawnVector[i]->GetAbsOrigin() - enemyVector[p]->GetAbsOrigin() ).IsLengthLessThan( nearRange ) ) |
|
{ |
|
// a player is occupying this spawn |
|
break; |
|
} |
|
} |
|
|
|
if ( p == enemyVector.Count() ) |
|
{ |
|
// no players are near this spawn point |
|
openSpawnVector.AddToTail( spawnVector[i] ); |
|
} |
|
} |
|
|
|
CBaseEntity *teleportDestination = NULL; |
|
|
|
if ( openSpawnVector.Count() == 0 ) |
|
{ |
|
// there are no free spawns - pick one and telefrag enemies standing there |
|
int which = RandomInt( 0, spawnVector.Count()-1 ); |
|
|
|
teleportDestination = spawnVector[ which ]; |
|
|
|
for( int p=0; p<enemyVector.Count(); ++p ) |
|
{ |
|
if ( ( teleportDestination->GetAbsOrigin() - enemyVector[p]->GetAbsOrigin() ).IsLengthLessThan( nearRange ) ) |
|
{ |
|
// telefrag! |
|
enemyVector[p]->TakeDamage( CTakeDamageInfo( teleportingPlayer, teleportingPlayer, 1000, DMG_CRUSH, TF_DMG_CUSTOM_TELEFRAG ) ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// pick an open destination at random |
|
int which = RandomInt( 0, openSpawnVector.Count()-1 ); |
|
|
|
teleportDestination = openSpawnVector[ which ]; |
|
} |
|
|
|
if ( teleportDestination ) |
|
{ |
|
if ( teleportingPlayer->GetTeam() ) |
|
{ |
|
UTIL_LogPrintf( "HALLOWEEN: \"%s<%i><%s><%s>\" purgatory_teleport \"%s\"\n", |
|
teleportingPlayer->GetPlayerName(), |
|
teleportingPlayer->GetUserID(), |
|
teleportingPlayer->GetNetworkIDString(), |
|
teleportingPlayer->GetTeam()->GetName(), |
|
where ); |
|
} |
|
|
|
teleportingPlayer->Teleport( &teleportDestination->GetAbsOrigin(), &teleportDestination->GetAbsAngles(), &vec3_origin ); |
|
|
|
// When fighting Merasmus, give players full health on teleport |
|
if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_LAKESIDE ) ) |
|
{ |
|
if ( teleportingPlayer->IsAlive() ) |
|
{ |
|
teleportingPlayer->TakeHealth( teleportingPlayer->GetMaxHealth(), DMG_GENERIC ); |
|
teleportingPlayer->m_Shared.HealthKitPickupEffects(); |
|
teleportingPlayer->m_Shared.RemoveCond( TF_COND_HALLOWEEN_BOMB_HEAD ); |
|
} |
|
} |
|
|
|
if ( FStrEq( where, "spawn_loot" ) ) |
|
{ |
|
CReliableBroadcastRecipientFilter filter; |
|
UTIL_SayText2Filter( filter, teleportingPlayer, false, "#TF_Halloween_Loot_Island", teleportingPlayer->GetPlayerName() ); |
|
} |
|
|
|
teleportingPlayer->m_Shared.InstantlySniperUnzoom(); |
|
|
|
color32 fadeColor = { 255, 255, 255, 100 }; |
|
UTIL_ScreenFade( teleportingPlayer, fadeColor, 0.25, 0.4, FFADE_IN ); |
|
} |
|
} |
|
|
|
|
|
#else |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CTeleportVortex::ClientThink() |
|
{ |
|
// Fade in and out for first and last fraction of time |
|
const float flDuration = m_lifeTimer.GetCountdownDuration(); |
|
const float flRampTime = flDuration / vortex_fade_fraction_denom.GetInt(); |
|
const float flElapsed = m_lifeTimer.GetElapsedTime(); |
|
|
|
float t = 1.0f; |
|
if ( ShouldDoBookRampIn() ) |
|
{ |
|
t = SCurve( flElapsed / flRampTime ); |
|
} |
|
else if ( ShouldDoBookRampOut() ) |
|
{ |
|
t = SCurve( 1.0f - ( flElapsed - flDuration + flRampTime ) / flRampTime ); |
|
} |
|
|
|
// SetRenderColorA( t * 255 ); |
|
|
|
m_flScale = t; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CTeleportVortex::BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ) |
|
{ |
|
// Translate root bone towards the player and oscillate a bit - if in the scale in/out period, translate up directly from the underworld, or down towards it. |
|
const Vector vecBob( vortex_book_offset.GetFloat(), 0.0f, vortex_float_amp.GetFloat() * sinf( vortex_float_osc_speed.GetFloat() * gpGlobals->curtime ) ); |
|
pos[0] = vecBob + Vector( 0.0f, 0.0f, Lerp( m_flScale, -500.0f, 0.0f ) ); |
|
|
|
matrix3x4_t mRootBoneRotation; |
|
|
|
// If the local player exists and is alive, render the book so that it's facing him |
|
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( pLocalPlayer && pLocalPlayer->IsAlive() ) |
|
{ |
|
const Vector vecBook = GetAbsOrigin(); |
|
const Vector vecPlayerPos = pLocalPlayer->GetAbsOrigin(); |
|
Vector vecForward = vecPlayerPos - vecBook; |
|
if ( VectorNormalize( vecForward ) > 0.1f ) |
|
{ |
|
// Calculate a matrix based on the forward direction |
|
VectorMatrix( vecForward, mRootBoneRotation ); |
|
} |
|
} |
|
else |
|
{ |
|
// Use whatever rotation is in the root bone already |
|
QuaternionMatrix( q[0], mRootBoneRotation ); |
|
} |
|
|
|
// Convert the matrix to a quaternion and slam the root bone rotation |
|
MatrixQuaternion( mRootBoneRotation, q[0] ); |
|
|
|
// Let the base class actually build the global transforms |
|
BaseClass::BuildTransformations( pStudioHdr, pos, q, cameraTransform, boneMask, boneComputed ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CTeleportVortex::PlayBookAnimation( const char *pAnimName ) |
|
{ |
|
int iAnimSequence = LookupSequence( pAnimName ); |
|
if ( iAnimSequence ) |
|
{ |
|
SetSequence( iAnimSequence ); |
|
SetPlaybackRate( 1.0f ); |
|
SetCycle( 0 ); |
|
ResetSequenceInfo(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CTeleportVortex::OnDataChanged(DataUpdateType_t updateType) |
|
{ |
|
BaseClass::OnDataChanged( updateType ); |
|
|
|
if ( m_iState != m_iOldState ) |
|
{ |
|
if ( m_iState != VORTEXSTATE_INACTIVE ) |
|
{ |
|
// Stop any existing particle effect if necessary |
|
AssertMsg( !m_pVortexEffect, "Particle effect should not be active!" ); |
|
|
|
// Create the particle effect and play a sound |
|
const char *pszEffectName; |
|
const char *pszSound; |
|
if ( m_iState == VORTEXSTATE_ACTIVE_EYEBALL_MOVED ) |
|
{ |
|
pszEffectName = VORTEX_PARTICLE_EFFECT_EYEBALL_MOVED; |
|
pszSound = VORTEX_SOUND_EYEBALL_MOVED; |
|
} |
|
else |
|
{ |
|
pszEffectName = VORTEX_PARTICLE_EFFECT_EYEBALL_DIED; |
|
pszSound = VORTEX_SOUND_EYEBALL_DIED; |
|
|
|
PlayBookAnimation( VORTEX_OPEN_OPEN_ANIM ); |
|
} |
|
m_pVortexEffect = ParticleProp()->Create( pszEffectName, PATTACH_ABSORIGIN ); |
|
EmitSound( pszSound ); |
|
} |
|
|
|
m_iOldState = m_iState; |
|
} |
|
} |
|
|
|
#endif |
|
|
|
float CTeleportVortex::GetRampTime() |
|
{ |
|
const float flDuration = m_lifeTimer.GetCountdownDuration(); |
|
return flDuration / vortex_fade_fraction_denom.GetInt(); |
|
} |
|
|
|
bool CTeleportVortex::ShouldDoBookRampIn() |
|
{ |
|
return m_lifeTimer.GetElapsedTime() <= GetRampTime(); |
|
} |
|
|
|
bool CTeleportVortex::ShouldDoBookRampOut() |
|
{ |
|
const float flDuration = m_lifeTimer.GetCountdownDuration(); |
|
return m_lifeTimer.GetElapsedTime() >= flDuration - GetRampTime(); |
|
} |
|
|
|
#ifdef CLIENT_DLL |
|
#define CHightower_TeleportVortex C_Hightower_TeleportVortex |
|
#endif |
|
class CHightower_TeleportVortex : public CTeleportVortex |
|
{ |
|
DECLARE_DATADESC(); |
|
DECLARE_NETWORKCLASS(); |
|
DECLARE_CLASS( CHightower_TeleportVortex, CTeleportVortex ); |
|
|
|
public: |
|
virtual void Spawn() |
|
{ |
|
BaseClass::Spawn(); |
|
#ifdef GAME_DLL |
|
m_nWinningTeam = TF_TEAM_COUNT; // Invalid |
|
SetupVortex( false, false ); |
|
m_lifeTimer.Start( m_flDuration ); |
|
#endif |
|
} |
|
|
|
virtual void Touch( CBaseEntity *pOther ) |
|
{ |
|
#ifdef GAME_DLL |
|
const char *pszTarget = CFmtStr( "%s_%s", m_pszDestinationBaseName, ( pOther->GetTeamNumber() == m_nWinningTeam ) ? "winner" : "loser" ); |
|
SendPlayerToTheUnderworld( ToTFPlayer( pOther ), pszTarget ); |
|
#endif |
|
} |
|
|
|
#ifdef GAME_DLL |
|
void SetAdvantageTeam( inputdata_t &inputdata ) |
|
{ |
|
m_nWinningTeam = FStrEq( inputdata.value.String(), "red" ) ? TF_TEAM_RED : TF_TEAM_BLUE; |
|
} |
|
#endif |
|
private: |
|
|
|
#ifdef GAME_DLL |
|
int m_nWinningTeam; |
|
const char* m_pszDestinationBaseName; |
|
float m_flDuration; |
|
#endif |
|
}; |
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( Hightower_TeleportVortex, DT_Hightower_TeleportVortex ) |
|
|
|
BEGIN_NETWORK_TABLE( CHightower_TeleportVortex, DT_Hightower_TeleportVortex ) |
|
#if defined( CLIENT_DLL ) |
|
RecvPropInt( RECVINFO( m_iState ) ), |
|
#else |
|
SendPropInt( SENDINFO( m_iState ), 4, SPROP_UNSIGNED | SPROP_CHANGES_OFTEN ), |
|
#endif |
|
END_NETWORK_TABLE() |
|
|
|
LINK_ENTITY_TO_CLASS( hightower_teleport_vortex, CHightower_TeleportVortex ); |
|
|
|
BEGIN_DATADESC( CHightower_TeleportVortex ) |
|
#ifdef GAME_DLL |
|
DEFINE_INPUTFUNC( FIELD_STRING, "SetAdvantageTeam", SetAdvantageTeam ), |
|
DEFINE_KEYFIELD( m_flDuration, FIELD_FLOAT, "lifetime" ), |
|
DEFINE_KEYFIELD( m_pszDestinationBaseName, FIELD_STRING, "target_base_name" ), |
|
#endif |
|
END_DATADESC() |