source-engine/game/server/tf2/tf_vehicle_teleport_station.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

415 lines
12 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Teleport Station vehicle
//
//=============================================================================//
#include "cbase.h"
#include "tf_vehicle_teleport_station.h"
#include "engine/IEngineSound.h"
#include "VGuiScreen.h"
#include "ammodef.h"
#include "in_buttons.h"
#include "ndebugoverlay.h"
#include "IEffects.h"
#include "info_act.h"
#include "tf_obj_mcv_selection_panel.h"
#include "info_vehicle_bay.h"
#define TELEPORT_STATION_MINS Vector(-30, -50, -10)
#define TELEPORT_STATION_MAXS Vector( 30, 50, 55)
#define TELEPORT_STATION_MODEL "models/objects/vehicle_teleport_station.mdl"
#define TELEPORT_STATION_ZONE_HEIGHT 200
#define TELEPORT_STATION_THINK_CONTEXT "TeleportThink"
BEGIN_DATADESC( CVehicleTeleportStation )
DEFINE_THINKFUNC( PostTeleportThink ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CVehicleTeleportStation, DT_VehicleTeleportStation )
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( vehicle_teleport_station, CVehicleTeleportStation );
PRECACHE_REGISTER( vehicle_teleport_station );
// CVars
ConVar vehicle_teleport_station_health( "vehicle_teleport_station_health","600", FCVAR_NONE, "Siege tower health" );
CUtlVector<CVehicleTeleportStation*> g_AllTeleportStations;
CUtlVector<CVehicleTeleportStation*> CVehicleTeleportStation::s_DeployedTeleportStations;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CVehicleTeleportStation::CVehicleTeleportStation()
{
g_AllTeleportStations.AddToTail( this );
//FIXME: we should be able to use clientside animation on this vehicle, but prediction is messing it
//up right now.
//UseClientSideAnimation();
}
CVehicleTeleportStation::~CVehicleTeleportStation()
{
g_AllTeleportStations.FindAndRemove( this );
s_DeployedTeleportStations.FindAndRemove( this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::Spawn()
{
SetModel( TELEPORT_STATION_MODEL );
// This size is used for placement only...
UTIL_SetSize( this, TELEPORT_STATION_MINS, TELEPORT_STATION_MAXS );
m_takedamage = DAMAGE_YES;
m_iHealth = vehicle_teleport_station_health.GetInt();
SetType( OBJ_VEHICLE_TELEPORT_STATION );
SetMaxPassengerCount( 4 );
SetBodygroup( 1, true );
BaseClass::Spawn();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::Precache()
{
PrecacheModel( TELEPORT_STATION_MODEL );
PrecacheVGuiScreen( "screen_vehicle_bay" );
PrecacheModel( "sprites/redglow1.vmt" );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::UpdateOnRemove( void )
{
RemoveCornerSprites();
// Chain at end to mimic destructor unwind order
BaseClass::UpdateOnRemove();
}
//-----------------------------------------------------------------------------
// Purpose: Gets info about the control panels
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
{
pPanelName = "screen_vehicle_bay";
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::GetControlPanelClassName( int nPanelIndex, const char *&pPanelName )
{
pPanelName = "vgui_screen_vehicle_bay";
}
//-----------------------------------------------------------------------------
// Purpose: Screens aren't active until deployed
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::FinishedBuilding( void )
{
BaseClass::FinishedBuilding();
SetControlPanelsActive( false );
}
//-----------------------------------------------------------------------------
// Here's where we deal with weapons, ladders, etc.
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::OnItemPostFrame( CBaseTFPlayer *pDriver )
{
// I can't do anything if I'm not active
if ( !ShouldBeActive() )
return;
if ( GetPassengerRole( pDriver ) != VEHICLE_ROLE_DRIVER )
return;
if ( !IsDeployed() && ( pDriver->m_afButtonPressed & IN_ATTACK ) )
{
if ( ValidDeployPosition() )
{
Deploy();
}
}
else if ( IsDeployed() && ( pDriver->m_afButtonPressed & IN_ATTACK ) )
{
UnDeploy();
SetControlPanelsActive( false );
SetBodygroup( 1, true );
RemoveCornerSprites();
SetContextThink( NULL, 0, TELEPORT_STATION_THINK_CONTEXT );
}
}
//-----------------------------------------------------------------------------
// Purpose: Finished our deploy
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::OnFinishedDeploy( void )
{
BaseClass::OnFinishedDeploy();
ValidDeployPosition();
SetBodygroup( 1, false );
// Find the teleport in the mothership
CFuncMassTeleport *pTeleporter = NULL;
while ( (pTeleporter = (CFuncMassTeleport*)gEntList.FindEntityByClassname( pTeleporter, "func_mass_teleport" )) != NULL )
{
if ( pTeleporter->IsMCVTeleport() )
{
m_hTeleportExit = pTeleporter;
m_hTeleportExit->AddMCV( this );
break;
}
}
// Put some flares down to mark the teleport zone
Vector vecOrigin;
QAngle vecAngles;
for ( int i = 0; i < 4; i++ )
{
char buf[64];
Q_snprintf( buf, sizeof( buf ), "teleport_corner%d", i+1 );
if ( GetAttachment( buf, vecOrigin, vecAngles ) )
{
CheckBuildPoint( vecOrigin + Vector(0,0,64), Vector(0,0,128), &vecOrigin );
m_hTeleportCornerSprites[i] = CSprite::SpriteCreate( "sprites/redglow1.vmt", vecOrigin, false );
m_hTeleportCornerSprites[i]->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation );
m_hTeleportCornerSprites[i]->SetScale( 0.1 );
}
}
// Get the ray point
if ( GetAttachment( "muzzle", vecOrigin, vecAngles ) )
{
m_hTeleportCornerSprites[4] = CSprite::SpriteCreate( "sprites/redglow1.vmt", vecOrigin, false );
m_hTeleportCornerSprites[4]->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation );
m_hTeleportCornerSprites[4]->SetScale( 0.1 );
}
SetContextThink( PostTeleportThink, gpGlobals->curtime + 0.1, TELEPORT_STATION_THINK_CONTEXT );
// Add ourselves to the list of deployed MCVs.
s_DeployedTeleportStations.AddToTail( this );
// Set our vehicle bay screen's buildpoint
for ( i = m_hScreens.Count(); --i >= 0; )
{
if (m_hScreens[i].Get())
{
CVGuiScreenVehicleBay *pScreen = dynamic_cast<CVGuiScreenVehicleBay*>( m_hScreens[0].Get() );
if ( pScreen )
{
Vector vecOrigin;
QAngle vecAngles;
if ( GetAttachment( "vehiclebay", vecOrigin, vecAngles ) )
{
pScreen->SetBuildPoint( vecOrigin, vecAngles );
}
}
}
}
SetControlPanelsActive( true );
SignalChangeInMCVSelectionPanels();
}
void CVehicleTeleportStation::OnFinishedUnDeploy( void )
{
BaseClass::OnFinishedUnDeploy();
s_DeployedTeleportStations.FindAndRemove( this );
SignalChangeInMCVSelectionPanels();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::RemoveCornerSprites( void )
{
// Remove all the corner sprites
for ( int i = 0; i < 5; i++ )
{
if ( m_hTeleportCornerSprites[i] )
{
UTIL_Remove( m_hTeleportCornerSprites[i] );
}
}
// Tell the exit we're done
if ( m_hTeleportExit )
{
m_hTeleportExit->RemoveMCV( this );
m_hTeleportExit = NULL;
}
}
int CVehicleTeleportStation::GetNumDeployedTeleportStations()
{
return s_DeployedTeleportStations.Count();
}
CVehicleTeleportStation* CVehicleTeleportStation::GetDeployedTeleportStation( int i )
{
return s_DeployedTeleportStations[i];
}
//-----------------------------------------------------------------------------
// Purpose: Return true if the truck's in a valid position
//-----------------------------------------------------------------------------
bool CVehicleTeleportStation::ValidDeployPosition( void )
{
// Setup for teleporting
QAngle vecAngles;
if ( !GetAttachment( "teleport_corner1", m_vecTeleporterMins, vecAngles ) || !GetAttachment( "teleport_corner4", m_vecTeleporterMaxs, vecAngles ) )
return false;
m_vecTeleporterMaxs.z += TELEPORT_STATION_ZONE_HEIGHT;
// Make sure we've got the right mins & maxs
for ( int i = 0; i < 3; i++ )
{
if ( m_vecTeleporterMaxs[i] < m_vecTeleporterMins[i] )
{
float flVal = m_vecTeleporterMaxs[i];
m_vecTeleporterMaxs[i] = m_vecTeleporterMins[i];
m_vecTeleporterMins[i] = flVal;
}
}
Vector vecDelta = (m_vecTeleporterMaxs - m_vecTeleporterMins) * 0.5;
Vector vecEnd = (m_vecTeleporterMaxs + m_vecTeleporterMins) * 0.5;
Vector vecSrc = vecEnd + Vector(0,0,TELEPORT_STATION_ZONE_HEIGHT * 0.5);
// Make sure it's clear
// Take the hull, start it high, and try and trace down
trace_t tr;
UTIL_TraceHull( vecSrc, vecEnd, -vecDelta, vecDelta, MASK_SOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
//NDebugOverlay::Box( m_vecTeleporterMins, Vector(-2,-2,-2), Vector(2,2,2), 0,255,0,8, 0.1 );
//NDebugOverlay::Box( m_vecTeleporterMaxs, Vector(-2,-2,-2), Vector(2,2,2), 0,255,0,8, 0.1 );
//NDebugOverlay::Box( vecSrc, -vecDelta, vecDelta, 255,0,0,8, 0.1 );
//NDebugOverlay::Box( vecEnd, -vecDelta, vecDelta, 0,0,255,8, 0.1 );
//NDebugOverlay::Line( m_vecTeleporterMins, m_vecTeleporterMaxs, 255,255,255, 1, 0.1 );
// Make sure it's clear
if ( tr.startsolid )
return false;
// Get a list of nearby entities
CBaseEntity *pListOfNearbyEntities[100];
int iNumberOfNearbyEntities = UTIL_EntitiesInBox( pListOfNearbyEntities, 100, m_vecTeleporterMins, m_vecTeleporterMaxs, MASK_ALL );
for ( i = 0; i < iNumberOfNearbyEntities; i++ )
{
CBaseEntity *pEntity = pListOfNearbyEntities[i];
if ( pEntity->IsSolid( ) )
{
if ( pEntity == this )
continue;
if ( pEntity->GetCollisionGroup() == TFCOLLISION_GROUP_SHIELD )
continue;
if ( pEntity->IsPlayer() )
continue;
//NDebugOverlay::EntityBounds( pEntity, 0,255,0,8, 0.1 );
return false;
}
}
m_vecTeleporterCenter = vecEnd;
m_vecTeleporterCenter.z = m_vecTeleporterMins.z;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::DoTeleport( void )
{
ResetDeteriorationTime();
if ( m_hTeleportExit )
{
// Teleport all players attached to me that are within my bbox.
EHANDLE hMCV;
hMCV = this;
Vector vecAbsMins, vecAbsMaxs;
m_hTeleportExit->CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
m_hTeleportExit->DoTeleport( GetTFTeam(), vecAbsMins, vecAbsMaxs, m_vecTeleporterCenter, true, true, hMCV );
}
// Shrink the corner sprites
for ( int i = 0; i < 5; i++ )
{
if ( m_hTeleportCornerSprites[i] )
{
m_hTeleportCornerSprites[i]->SetScale( 0.1 );
}
}
SetContextThink( PostTeleportThink, gpGlobals->curtime + 0.1, TELEPORT_STATION_THINK_CONTEXT );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVehicleTeleportStation::PostTeleportThink( void )
{
float flTime = 10.0;
if ( g_hCurrentAct )
{
flTime = g_hCurrentAct->GetMCVTimer();
}
// Start the corner sprites up
for ( int i = 0; i < 4; i++ )
{
if ( m_hTeleportCornerSprites[i] )
{
m_hTeleportCornerSprites[i]->SetScale( 0.75, flTime );
}
}
m_hTeleportCornerSprites[4]->SetScale( 2, flTime );
}
// Returns INVALID_MCV_ID if there are no deployed MCVs.
CVehicleTeleportStation* CVehicleTeleportStation::GetFirstDeployedMCV( int iTeam )
{
for ( int i=0; i < s_DeployedTeleportStations.Count(); i++ )
{
CVehicleTeleportStation *pStation = s_DeployedTeleportStations[i];
if ( pStation->GetTeamNumber() == iTeam )
return pStation;
}
return NULL;
}