int CObjectTeleporter::DrawDebugTextOverlays(void) { int text_offset = BaseClass::DrawDebugTextOverlays(); if (m_debugOverlays & OVERLAY_TEXT_BIT) { CObjectTeleporter *pMatch = GetMatchingTeleporter(); char tempstr[512]; // match Q_snprintf( tempstr, sizeof( tempstr ), "Match Found: %s", ( pMatch != NULL ) ? "Yes" : "No" ); EntityText(text_offset,tempstr,0); text_offset++; // state Q_snprintf( tempstr, sizeof( tempstr ), "State: %d", m_iState ); EntityText(text_offset,tempstr,0); text_offset++; // recharge time if ( gpGlobals->curtime < m_flRechargeTime ) { float flPercent = ( m_flRechargeTime - gpGlobals->curtime ) / g_flTeleporterRechargeTimes[ GetUpgradeLevel() - 1 ]; Q_snprintf( tempstr, sizeof( tempstr ), "Recharging: %.1f", flPercent ); EntityText(text_offset,tempstr,0); text_offset++; } } return text_offset; }
bool CObjectTeleporter::CheckUpgradeOnHit( CTFPlayer *pPlayer ) { bool bUpgradeSuccesful = false; if ( BaseClass::CheckUpgradeOnHit( pPlayer ) ) { CObjectTeleporter *pMatch = GetMatchingTeleporter(); if ( pMatch ) { //pMatch->m_iUpgradeMetal = m_iUpgradeMetal; if ( pMatch && pMatch->CanBeUpgraded( pPlayer ) && GetUpgradeLevel() > pMatch->GetUpgradeLevel() ) { // This end just got upgraded so make another end play upgrade anim if possible. pMatch->StartUpgrading(); } // Other end still needs to keep up even while hauled etc. CopyUpgradeStateToMatch( pMatch, false ); } bUpgradeSuccesful = true; } return bUpgradeSuccesful; }
void CObjectTeleporter::ShowDirectionArrow( bool bShow ) { if ( bShow != m_bShowDirectionArrow ) { if ( m_iDirectionBodygroup >= 0 ) { SetBodygroup( m_iDirectionBodygroup, bShow ? 1 : 0 ); } m_bShowDirectionArrow = bShow; if ( bShow ) { CObjectTeleporter *pMatch = GetMatchingTeleporter(); Assert( pMatch ); Vector vecToOwner = pMatch->GetAbsOrigin() - GetAbsOrigin(); QAngle angleToExit; VectorAngles( vecToOwner, Vector(0,0,1), angleToExit ); angleToExit -= GetAbsAngles(); // pose param is flipped and backwards, adjust. //m_flYawToExit = anglemod( -angleToExit.y + 180.0 ); m_flYawToExit = AngleNormalize( -angleToExit.y + 180.0 ); // For whatever reason the original code normalizes angle 0 to 360 while pose param // takes angle from -180 to 180. I have no idea how did this work properly // in official TF2 all this time. (Nicknine) } } }
void CObjectTeleporter::ShowDirectionArrow( bool bShow ) { if ( bShow != m_bShowDirectionArrow ) { if ( m_iDirectionBodygroup >= 0 ) { SetBodygroup( m_iDirectionBodygroup, bShow ? 1 : 0 ); } m_bShowDirectionArrow = bShow; if ( bShow ) { CObjectTeleporter *pMatch = GetMatchingTeleporter(); Assert( pMatch ); Vector vecToOwner = pMatch->GetAbsOrigin() - GetAbsOrigin(); QAngle angleToExit; VectorAngles( vecToOwner, Vector(0,0,1), angleToExit ); angleToExit -= GetAbsAngles(); // pose param is flipped and backwards, adjust. m_flYawToExit = anglemod( -angleToExit.y + 180 ); } } }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CObjectTeleporter::TeleporterTouch( CBaseEntity *pOther ) { if ( IsDisabled() ) { return; } // if it's not a player, ignore if ( !pOther->IsPlayer() ) return; CTFPlayer *pPlayer = ToTFPlayer( pOther ); CTFPlayer *pBuilder = GetBuilder(); Assert( pBuilder ); if ( !pBuilder ) { return; } // if its not a teammate of the builder, notify the builder if ( pBuilder->GetTeamNumber() != pOther->GetTeamNumber() ) { // Don't teleport enemies return; } // is this an entrance and do we have an exit? if ( GetType() == OBJ_TELEPORTER_ENTRANCE ) { if ( ( m_iState == TELEPORTER_STATE_READY ) ) { // are we able to teleport? if ( pPlayer->HasTheFlag() ) { // If they have the flag, print a warning that you can't tele with the flag CSingleUserRecipientFilter filter( pPlayer ); TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_NO_TELE_WITH_FLAG ); return; } // get the velocity of the player touching the teleporter if ( pPlayer->GetAbsVelocity().Length() < 5.0 ) { CObjectTeleporter *pDest = GetMatchingTeleporter(); if ( pDest ) { TeleporterSend( pPlayer ); } } } } }
bool CObjectTeleporter::InputWrenchHit( CTFPlayer *pPlayer, CTFWrench *pWrench, Vector vecHitPos ) { if ( HasSapper() && GetMatchingTeleporter() ) { CObjectTeleporter *pMatch = GetMatchingTeleporter(); // do damage to any attached buildings CTakeDamageInfo info( pPlayer, pPlayer, 65, DMG_CLUB, TF_DMG_WRENCH_FIX ); IHasBuildPoints *pBPInterface = dynamic_cast< IHasBuildPoints * >( pMatch ); int iNumObjects = pBPInterface->GetNumObjectsOnMe(); for ( int iPoint=0; iPoint < iNumObjects; iPoint++ ) { CBaseObject *pObject = pMatch->GetBuildPointObject( iPoint ); if ( pObject && pObject->IsHostileUpgrade() ) pObject->TakeDamage( info ); } } return BaseClass::InputWrenchHit( pPlayer, pWrench, vecHitPos ); }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CObjectTeleporter::TeleporterTouch( CBaseEntity *pOther ) { if ( IsDisabled() ) { return; } // if it's not a player, ignore if ( !pOther->IsPlayer() ) return; CTFPlayer *pPlayer = ToTFPlayer( pOther ); int bTwoWayTeleporter = 0; CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayer, bTwoWayTeleporter, bidirectional_teleport ); // is this an entrance and do we have an exit? if ( GetObjectMode() == TELEPORTER_TYPE_ENTRANCE || bTwoWayTeleporter > 0 ) { if ( ( m_iState == TELEPORTER_STATE_READY ) ) { // are we able to teleport? if ( !PlayerCanBeTeleported( pPlayer ) ) { if ( pPlayer->HasTheFlag() ) { // If they have the flag, print a warning that you can't tele with the flag CSingleUserRecipientFilter filter( pPlayer ); TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_NO_TELE_WITH_FLAG ); } return; } // get the velocity of the player touching the teleporter if ( pPlayer->GetAbsVelocity().Length() < 5.0 ) { CObjectTeleporter *pDest = GetMatchingTeleporter(); if ( pDest ) { TeleporterSend( pPlayer ); } } } } }
//----------------------------------------------------------------------------- // Receive a teleporting player //----------------------------------------------------------------------------- bool CObjectTeleporter::IsMatchingTeleporterReady( void ) { if ( m_hMatchingTeleporter.Get() == NULL ) { m_hMatchingTeleporter = FindMatch(); } CObjectTeleporter *pMatch = GetMatchingTeleporter(); if ( pMatch && pMatch->GetState() != TELEPORTER_STATE_BUILDING && !pMatch->IsDisabled() && !pMatch->IsUpgrading() && !pMatch->IsRedeploying() ) return true; return false; }
bool CObjectTeleporter::Command_Repair( CTFPlayer *pActivator ) { bool bRepaired = false; int iAmountToHeal = 0; int iRepairCost = 0; // There's got to be a better way a shorter way to mirror repairs and such. if ( GetHealth() < GetMaxHealth() ) { iAmountToHeal = min( 100, GetMaxHealth() - GetHealth() ); // repair the building iRepairCost = ceil( (float)( iAmountToHeal ) * 0.2f ); TRACE_OBJECT( UTIL_VarArgs( "%0.2f CObjectDispenser::Command_Repair ( %d / %d ) - cost = %d\n", gpGlobals->curtime, GetHealth(), GetMaxHealth(), iRepairCost ) ); if ( iRepairCost > 0 ) { if ( iRepairCost > pActivator->GetBuildResources() ) { iRepairCost = pActivator->GetBuildResources(); } pActivator->RemoveBuildResources( iRepairCost ); float flNewHealth = min( GetMaxHealth(), GetHealth() + ( iRepairCost * 5 ) ); SetHealth( flNewHealth ); bRepaired = (iRepairCost > 0); CObjectTeleporter *pMatch = GetMatchingTeleporter(); if ( pMatch && pMatch->GetState() != TELEPORTER_STATE_BUILDING && !pMatch->IsUpgrading() ) { float flNewHealth = min( pMatch->GetMaxHealth(), pMatch->GetHealth() + ( iRepairCost * 5 ) ); pMatch->SetHealth( flNewHealth ); } } } else if ( GetMatchingTeleporter() ) // See if the other teleporter needs repairing { CObjectTeleporter *pMatch = GetMatchingTeleporter(); if ( pMatch->GetHealth() < pMatch->GetMaxHealth() && pMatch->GetState() != TELEPORTER_STATE_BUILDING && !pMatch->IsUpgrading() ) { iAmountToHeal = min( 100, pMatch->GetMaxHealth() - pMatch->GetHealth() ); // repair the building iRepairCost = ceil( (float)(iAmountToHeal)* 0.2f ); TRACE_OBJECT( UTIL_VarArgs( "%0.2f CObjectDispenser::Command_Repair ( %d / %d ) - cost = %d\n", gpGlobals->curtime, pMatch->GetHealth(), pMatch->GetMaxHealth(), iRepairCost ) ); if ( iRepairCost > 0 ) { if ( iRepairCost > pActivator->GetBuildResources() ) { iRepairCost = pActivator->GetBuildResources(); } pActivator->RemoveBuildResources( iRepairCost ); float flNewHealth = min( pMatch->GetMaxHealth(), pMatch->GetHealth() + ( iRepairCost * 5 ) ); pMatch->SetHealth( flNewHealth ); bRepaired = (iRepairCost > 0); } } } return bRepaired; }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CObjectTeleporter::TeleporterThink( void ) { SetContextThink( &CObjectTeleporter::TeleporterThink, gpGlobals->curtime + BUILD_TELEPORTER_NEXT_THINK, TELEPORTER_THINK_CONTEXT ); // At any point, if our match is not ready, revert to IDLE if ( IsDisabled() || IsRedeploying() || IsMatchingTeleporterReady() == false ) { ShowDirectionArrow( false ); if ( GetState() != TELEPORTER_STATE_IDLE && !IsUpgrading() ) { SetState( TELEPORTER_STATE_IDLE ); CObjectTeleporter *pMatch = GetMatchingTeleporter(); if ( !pMatch ) { // The other end has been destroyed. Revert back to L1. m_iUpgradeLevel = 1; // We need to adjust for any damage received if we downgraded float flHealthPercentage = GetHealth() / GetMaxHealthForCurrentLevel(); SetMaxHealth( GetMaxHealthForCurrentLevel() ); SetHealth( (int)( GetMaxHealthForCurrentLevel() * flHealthPercentage ) ); m_iUpgradeMetal = 0; } } return; } if ( m_flMyNextThink && m_flMyNextThink > gpGlobals->curtime ) return; // pMatch is not NULL and is not building CObjectTeleporter *pMatch = GetMatchingTeleporter(); Assert( pMatch ); Assert( pMatch->m_iState != TELEPORTER_STATE_BUILDING ); switch ( m_iState ) { // Teleporter is not yet active, do nothing case TELEPORTER_STATE_BUILDING: case TELEPORTER_STATE_UPGRADING: ShowDirectionArrow( false ); break; default: case TELEPORTER_STATE_IDLE: // Do we have a match that is active? // Make sure both ends wait through full recharge time in case they get upgraded while recharging. if ( IsMatchingTeleporterReady() && !IsUpgrading() && gpGlobals->curtime > m_flRechargeTime ) { SetState( TELEPORTER_STATE_READY ); EmitSound( "Building_Teleporter.Ready" ); if ( GetObjectMode() == TELEPORTER_TYPE_ENTRANCE ) { ShowDirectionArrow( true ); } } break; case TELEPORTER_STATE_READY: break; case TELEPORTER_STATE_SENDING: { pMatch->TeleporterReceive( m_hTeleportingPlayer, 1.0 ); m_flRechargeTime = gpGlobals->curtime + ( BUILD_TELEPORTER_FADEOUT_TIME + BUILD_TELEPORTER_FADEIN_TIME + g_flTeleporterRechargeTimes[ GetUpgradeLevel() - 1] ); // change state to recharging... SetState( TELEPORTER_STATE_RECHARGING ); } break; case TELEPORTER_STATE_RECEIVING: { // get the position we'll move the player to Vector newPosition = GetAbsOrigin(); newPosition.z += TELEPORTER_MAXS.z + 1; // Telefrag anyone in the way CBaseEntity *pEnts[256]; Vector mins, maxs; Vector expand( 4, 4, 4 ); mins = newPosition + VEC_HULL_MIN - expand; maxs = newPosition + VEC_HULL_MAX + expand; CTFPlayer *pTeleportingPlayer = m_hTeleportingPlayer.Get(); // move the player if ( pTeleportingPlayer ) { CUtlVector<CBaseEntity*> hPlayersToKill; bool bClear = true; // Telefrag any players in the way int numEnts = UTIL_EntitiesInBox( pEnts, 256, mins, maxs, 0 ); if ( numEnts ) { //Iterate through the list and check the results for ( int i = 0; i < numEnts && bClear; i++ ) { if ( pEnts[i] == NULL ) continue; if ( pEnts[i] == this ) continue; // kill players if ( pEnts[i]->IsPlayer() ) { if ( !pTeleportingPlayer->InSameTeam(pEnts[i]) ) { hPlayersToKill.AddToTail( pEnts[i] ); } continue; } if ( pEnts[i]->IsBaseObject() ) continue; // Solid entities will prevent a teleport if ( pEnts[i]->IsSolid() && pEnts[i]->ShouldCollide( pTeleportingPlayer->GetCollisionGroup(), MASK_ALL ) && g_pGameRules->ShouldCollide( pTeleportingPlayer->GetCollisionGroup(), pEnts[i]->GetCollisionGroup() ) ) { // We're going to teleport into something solid. Abort & destroy this exit. bClear = false; } } } if ( bClear ) { // Telefrag all enemy players we've found for ( int player = 0; player < hPlayersToKill.Count(); player++ ) { CTakeDamageInfo info( this, pTeleportingPlayer, 1000, DMG_CRUSH, TF_DMG_TELEFRAG ); hPlayersToKill[player]->TakeDamage( info ); } pTeleportingPlayer->Teleport( &newPosition, &(GetAbsAngles()), &vec3_origin ); // Unzoom if we are a sniper zoomed! if ( ( pTeleportingPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_SNIPER ) && pTeleportingPlayer->m_Shared.InCond( TF_COND_AIMING ) ) { CTFWeaponBase *pWpn = pTeleportingPlayer->GetActiveTFWeapon(); if ( pWpn && pWpn->GetWeaponID() == TF_WEAPON_SNIPERRIFLE ) { CTFSniperRifle *pRifle = static_cast<CTFSniperRifle*>( pWpn ); pRifle->ToggleZoom(); } } pTeleportingPlayer->SetFOV( pTeleportingPlayer, 0, tf_teleporter_fov_time.GetFloat(), tf_teleporter_fov_start.GetInt() ); color32 fadeColor = {255,255,255,100}; UTIL_ScreenFade( pTeleportingPlayer, fadeColor, 0.25, 0.4, FFADE_IN ); } else { DetonateObject(); } } SetState( TELEPORTER_STATE_RECEIVING_RELEASE ); m_flMyNextThink = gpGlobals->curtime + ( BUILD_TELEPORTER_FADEIN_TIME ); } break; case TELEPORTER_STATE_RECEIVING_RELEASE: { CTFPlayer *pTeleportingPlayer = m_hTeleportingPlayer.Get(); if ( pTeleportingPlayer ) { int iTeam = GetBuilder() ? GetBuilder()->GetTeamNumber() : GetTeamNumber(); pTeleportingPlayer->m_Shared.SetTeleporterEffectColor( iTeam ); pTeleportingPlayer->TeleportEffect(); pTeleportingPlayer->m_Shared.RemoveCond( TF_COND_SELECTED_TO_TELEPORT ); if ( !m_bWasMapPlaced && GetBuilder() ) CTF_GameStats.Event_PlayerUsedTeleport( GetBuilder(), pTeleportingPlayer ); IGameEvent * event = gameeventmanager->CreateEvent( "player_teleported" ); if ( event ) { event->SetInt( "userid", pTeleportingPlayer->GetUserID() ); if ( GetBuilder() ) event->SetInt( "builderid", GetBuilder()->GetUserID() ); Vector vecOrigin = GetAbsOrigin(); Vector vecDestinationOrigin = GetMatchingTeleporter()->GetAbsOrigin(); Vector vecDifference = Vector( vecOrigin.x - vecDestinationOrigin.x, vecOrigin.y - vecDestinationOrigin.y, vecOrigin.z - vecDestinationOrigin.z ); float flDist = sqrtf( pow( vecDifference.x, 2 ) + pow( vecDifference.y, 2 ) + pow( vecDifference.z, 2 ) ); event->SetFloat( "dist", flDist ); gameeventmanager->FireEvent( event, true ); } // Don't thank ourselves. if ( pTeleportingPlayer != GetBuilder() ) pTeleportingPlayer->SpeakConceptIfAllowed( MP_CONCEPT_TELEPORTED ); } // reset the pointers to the player now that we're done teleporting SetTeleportingPlayer( NULL ); pMatch->SetTeleportingPlayer( NULL ); SetState( TELEPORTER_STATE_RECHARGING ); m_flMyNextThink = gpGlobals->curtime + ( g_flTeleporterRechargeTimes[ GetUpgradeLevel() - 1 ] ); } break; case TELEPORTER_STATE_RECHARGING: // If we are finished recharging, go active if ( gpGlobals->curtime > m_flRechargeTime ) { SetState( TELEPORTER_STATE_READY ); EmitSound( "Building_Teleporter.Ready" ); } break; } }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CObjectTeleporter::TeleporterThink( void ) { SetContextThink( &CObjectTeleporter::TeleporterThink, gpGlobals->curtime + BUILD_TELEPORTER_NEXT_THINK, TELEPORTER_THINK_CONTEXT ); // At any point, if our match is not ready, revert to IDLE if ( IsDisabled() || IsMatchingTeleporterReady() == false ) { if ( GetState() != TELEPORTER_STATE_IDLE ) { SetState( TELEPORTER_STATE_IDLE ); ShowDirectionArrow( false ); } return; } if ( m_flMyNextThink && m_flMyNextThink > gpGlobals->curtime ) return; // pMatch is not NULL and is not building CObjectTeleporter *pMatch = GetMatchingTeleporter(); Assert( pMatch ); Assert( pMatch->m_iState != TELEPORTER_STATE_BUILDING ); switch ( m_iState ) { // Teleporter is not yet active, do nothing case TELEPORTER_STATE_BUILDING: break; default: case TELEPORTER_STATE_IDLE: // Do we have a match that is active? if ( IsMatchingTeleporterReady() ) { SetState( TELEPORTER_STATE_READY ); EmitSound( "Building_Teleporter.Ready" ); if ( GetType() == OBJ_TELEPORTER_ENTRANCE ) { ShowDirectionArrow( true ); } } break; case TELEPORTER_STATE_READY: break; case TELEPORTER_STATE_SENDING: { pMatch->TeleporterReceive( m_hTeleportingPlayer, 1.0 ); m_flRechargeTime = gpGlobals->curtime + ( BUILD_TELEPORTER_FADEOUT_TIME + BUILD_TELEPORTER_FADEIN_TIME + TELEPORTER_RECHARGE_TIME ); // change state to recharging... SetState( TELEPORTER_STATE_RECHARGING ); } break; case TELEPORTER_STATE_RECEIVING: { // get the position we'll move the player to Vector newPosition = GetAbsOrigin(); newPosition.z += TELEPORTER_MAXS.z + 1; // Telefrag anyone in the way CBaseEntity *pEnts[256]; Vector mins, maxs; Vector expand( 4, 4, 4 ); mins = newPosition + VEC_HULL_MIN - expand; maxs = newPosition + VEC_HULL_MAX + expand; CTFPlayer *pTeleportingPlayer = m_hTeleportingPlayer.Get(); // move the player if ( pTeleportingPlayer ) { CUtlVector<CBaseEntity*> hPlayersToKill; bool bClear = true; // Telefrag any players in the way int numEnts = UTIL_EntitiesInBox( pEnts, 256, mins, maxs, 0 ); if ( numEnts ) { //Iterate through the list and check the results for ( int i = 0; i < numEnts && bClear; i++ ) { if ( pEnts[i] == NULL ) continue; if ( pEnts[i] == this ) continue; // kill players and NPCs if ( pEnts[i]->IsPlayer() || pEnts[i]->IsNPC() ) { if ( !pTeleportingPlayer->InSameTeam(pEnts[i]) ) { hPlayersToKill.AddToTail( pEnts[i] ); } continue; } if ( pEnts[i]->IsBaseObject() ) continue; // Solid entities will prevent a teleport if ( pEnts[i]->IsSolid() && pEnts[i]->ShouldCollide( pTeleportingPlayer->GetCollisionGroup(), MASK_ALL ) && g_pGameRules->ShouldCollide( pTeleportingPlayer->GetCollisionGroup(), pEnts[i]->GetCollisionGroup() ) ) { // We're going to teleport into something solid. Abort & destroy this exit. bClear = false; } } } if ( bClear ) { // Telefrag all enemy players we've found for ( int player = 0; player < hPlayersToKill.Count(); player++ ) { hPlayersToKill[player]->TakeDamage( CTakeDamageInfo( pTeleportingPlayer, this, 1000, DMG_CRUSH ) ); } pTeleportingPlayer->Teleport( &newPosition, &(GetAbsAngles()), &vec3_origin ); // Unzoom if we are a sniper zoomed! if ( ( pTeleportingPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_SNIPER ) && pTeleportingPlayer->m_Shared.InCond( TF_COND_AIMING ) ) { CTFWeaponBase *pWpn = pTeleportingPlayer->GetActiveTFWeapon(); if ( pWpn && pWpn->GetWeaponID() == TF_WEAPON_SNIPERRIFLE ) { CTFSniperRifle *pRifle = static_cast<CTFSniperRifle*>( pWpn ); pRifle->ToggleZoom(); } } pTeleportingPlayer->SetFOV( pTeleportingPlayer, 0, tf_teleporter_fov_time.GetFloat(), tf_teleporter_fov_start.GetInt() ); color32 fadeColor = {255,255,255,100}; UTIL_ScreenFade( pTeleportingPlayer, fadeColor, 0.25, 0.4, FFADE_IN ); } else { DetonateObject(); } } SetState( TELEPORTER_STATE_RECEIVING_RELEASE ); m_flMyNextThink = gpGlobals->curtime + ( BUILD_TELEPORTER_FADEIN_TIME ); } break; case TELEPORTER_STATE_RECEIVING_RELEASE: { CTFPlayer *pTeleportingPlayer = m_hTeleportingPlayer.Get(); if ( pTeleportingPlayer ) { pTeleportingPlayer->TeleportEffect(); pTeleportingPlayer->m_Shared.RemoveCond( TF_COND_SELECTED_TO_TELEPORT ); CTF_GameStats.Event_PlayerUsedTeleport( GetBuilder(), pTeleportingPlayer ); pTeleportingPlayer->SpeakConceptIfAllowed( MP_CONCEPT_TELEPORTED ); } // reset the pointers to the player now that we're done teleporting SetTeleportingPlayer( NULL ); pMatch->SetTeleportingPlayer( NULL ); SetState( TELEPORTER_STATE_RECHARGING ); m_flMyNextThink = gpGlobals->curtime + ( TELEPORTER_RECHARGE_TIME ); } break; case TELEPORTER_STATE_RECHARGING: // If we are finished recharging, go active if ( gpGlobals->curtime > m_flRechargeTime ) { SetState( TELEPORTER_STATE_READY ); EmitSound( "Building_Teleporter.Ready" ); } break; } }