mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-12-11 08:08:32 +00:00
418 lines
10 KiB
C++
418 lines
10 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
//
|
|
//=============================================================================
|
|
#include "cbase.h"
|
|
#include "tf_point_manager.h"
|
|
|
|
#ifdef CLIENT_DLL
|
|
#include "prediction.h"
|
|
#endif // CLIENT_DLL
|
|
|
|
#ifdef GAME_DLL
|
|
#include "tf_pumpkin_bomb.h"
|
|
#include "tf_generic_bomb.h"
|
|
#include "halloween/merasmus/merasmus_trick_or_treat_prop.h"
|
|
#endif
|
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( TFPointManager, DT_TFPointManager );
|
|
|
|
|
|
BEGIN_NETWORK_TABLE( CTFPointManager, DT_TFPointManager )
|
|
#ifdef GAME_DLL
|
|
SendPropInt( SENDINFO( m_nRandomSeed ) ),
|
|
SendPropInt( SENDINFO( m_unNextPointIndex ), -1, SPROP_UNSIGNED | SPROP_VARINT ),
|
|
SendPropArray3( SENDINFO_ARRAY3( m_nSpawnTime ), SendPropInt( SENDINFO_ARRAY( m_nSpawnTime ), -1, SPROP_VARINT ) ),
|
|
#else
|
|
RecvPropInt( RECVINFO( m_nRandomSeed ) ),
|
|
RecvPropInt( RECVINFO( m_unNextPointIndex ) ),
|
|
RecvPropArray3( RECVINFO_ARRAY( m_nSpawnTime ), RecvPropInt( RECVINFO( m_nSpawnTime[0] ) ) ),
|
|
#endif
|
|
END_NETWORK_TABLE()
|
|
|
|
BEGIN_DATADESC( CTFPointManager )
|
|
END_DATADESC()
|
|
|
|
CTFPointManager::CTFPointManager()
|
|
{
|
|
m_unNextPointIndex = 0;
|
|
m_flLastUpdateTime = gpGlobals->curtime;
|
|
}
|
|
|
|
void CTFPointManager::Spawn( void )
|
|
{
|
|
BaseClass::Spawn();
|
|
|
|
#ifdef GAME_DLL
|
|
m_takedamage = DAMAGE_NO;
|
|
|
|
SetSolid( SOLID_BBOX );
|
|
SetMoveType( MOVETYPE_FLY );
|
|
SetSolidFlags( FSOLID_TRIGGER | FSOLID_NOT_SOLID );
|
|
SetCollisionGroup( TFCOLLISION_GROUP_ROCKETS );
|
|
|
|
m_nRandomSeed = RandomInt( 0, 9999 );
|
|
|
|
SetThink( &CTFPointManager::PointThink );
|
|
SetNextThink( gpGlobals->curtime );
|
|
#endif // GAME_DLL
|
|
}
|
|
|
|
|
|
void CTFPointManager::UpdateOnRemove( void )
|
|
{
|
|
// make sure we clean this up before parent gets deleted
|
|
ClearPoints();
|
|
|
|
BaseClass::UpdateOnRemove();
|
|
}
|
|
|
|
void CTFPointManager::InitializePoint( tf_point_t *pPoint, int nPointIndex )
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
Assert( !prediction->InPrediction() );
|
|
#endif// CLIENT_DLL
|
|
|
|
int nSeed = m_nSpawnTime[ nPointIndex ] + m_nRandomSeed + nPointIndex;
|
|
m_randomStream.SetSeed( nSeed );
|
|
|
|
pPoint->m_vecPosition = GetInitialPosition();
|
|
pPoint->m_vecPrevPosition = pPoint->m_vecPosition;
|
|
pPoint->m_vecVelocity = GetInitialVelocity();
|
|
pPoint->m_flSpawnTime = gpGlobals->curtime;
|
|
pPoint->m_flLifeTime = GetLifeTime();
|
|
pPoint->m_nPointIndex = nPointIndex;
|
|
|
|
}
|
|
|
|
|
|
tf_point_t* CTFPointManager::AddPointInternal( int nPointIndex )
|
|
{
|
|
tf_point_t *pNewPoint = AllocatePoint();
|
|
if ( pNewPoint )
|
|
{
|
|
InitializePoint( pNewPoint, nPointIndex );
|
|
m_vecPoints.AddToTail( pNewPoint );
|
|
|
|
return pNewPoint;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
#ifdef GAME_DLL
|
|
void CTFPointManager::Touch( CBaseEntity *pOther )
|
|
{
|
|
if ( !ShouldCollide( pOther ) )
|
|
return;
|
|
|
|
// find the first point that collide with this ent
|
|
FOR_EACH_VEC( m_vecPoints, iPoint )
|
|
{
|
|
tf_point_t *pPoint = m_vecPoints[iPoint];
|
|
|
|
float flRadius = GetRadius( pPoint );
|
|
Vector vMins = flRadius * Vector( -1, -1, -1 );
|
|
Vector vMaxs = flRadius * Vector( 1, 1, 1 );
|
|
|
|
Ray_t ray;
|
|
ray.Init( pPoint->m_vecPrevPosition, pPoint->m_vecPosition, vMins, vMaxs );
|
|
|
|
trace_t trEnt;
|
|
enginetrace->ClipRayToEntity( ray, MASK_SOLID | CONTENTS_HITBOX, pOther, &trEnt );
|
|
if ( trEnt.DidHit() )
|
|
{
|
|
OnCollide( pOther, iPoint );
|
|
|
|
// found the first ray that hit this entity, stop checking against other rays
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int CTFPointManager::UpdateTransmitState()
|
|
{
|
|
return SetTransmitState( FL_EDICT_PVSCHECK );
|
|
}
|
|
|
|
unsigned int CTFPointManager::PhysicsSolidMaskForEntity( void ) const
|
|
{
|
|
return BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_REDTEAM | CONTENTS_BLUETEAM;
|
|
}
|
|
|
|
bool CTFPointManager::AddPoint( int iCurrentTick )
|
|
{
|
|
if ( !CanAddPoint() )
|
|
return false;
|
|
|
|
if ( AddPointInternal( m_unNextPointIndex ) != NULL )
|
|
{
|
|
// network tickcount to make sure client spawns on the same frame
|
|
m_nSpawnTime.Set( m_unNextPointIndex, iCurrentTick );
|
|
|
|
m_unNextPointIndex = ( m_unNextPointIndex + 1 ) % MAX_POINT_MANAGER_POINTS;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CTFPointManager::PointThink()
|
|
{
|
|
Update();
|
|
|
|
SetNextThink( gpGlobals->curtime );
|
|
}
|
|
|
|
#else // GAME_DLL
|
|
|
|
void CTFPointManager::OnDataChanged( DataUpdateType_t updateType )
|
|
{
|
|
BaseClass::OnDataChanged(updateType);
|
|
|
|
// Simulate every frame.
|
|
if ( updateType == DATA_UPDATE_CREATED )
|
|
{
|
|
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
|
}
|
|
}
|
|
|
|
void CTFPointManager::PostDataUpdate( DataUpdateType_t updateType )
|
|
{
|
|
BaseClass::PostDataUpdate( updateType );
|
|
|
|
int nSpawnTime = TIME_TO_TICKS( gpGlobals->curtime );
|
|
// try to catch up with the server's last spawn point
|
|
while ( m_unClientNextPointIndex != m_unNextPointIndex )
|
|
{
|
|
int nServerSpawnTime = m_nSpawnTime.Get( m_unClientNextPointIndex );
|
|
|
|
// skip invalid
|
|
if ( nServerSpawnTime == 0 )
|
|
{
|
|
m_unClientNextPointIndex = ( m_unClientNextPointIndex + 1 ) % MAX_POINT_MANAGER_POINTS;
|
|
continue;
|
|
}
|
|
|
|
// wait until we can spawn
|
|
if ( nSpawnTime < nServerSpawnTime )
|
|
break;
|
|
|
|
tf_point_t *pNewestPoint = AddPointInternal( m_unClientNextPointIndex );
|
|
if ( pNewestPoint )
|
|
{
|
|
if ( nSpawnTime > nServerSpawnTime )
|
|
{
|
|
// need to update new point to catch up to current time
|
|
float flDT = m_flLastUpdateTime - TICKS_TO_TIME( nServerSpawnTime );
|
|
UpdatePoint( pNewestPoint, m_vecPoints.Count() - 1, flDT );
|
|
}
|
|
OnClientPointAdded( pNewestPoint );
|
|
}
|
|
else
|
|
{
|
|
// we failed to create for some reason, just stop and try again next update
|
|
Assert( !"Failed to add new point" );
|
|
}
|
|
|
|
m_unClientNextPointIndex = ( m_unClientNextPointIndex + 1 ) % MAX_POINT_MANAGER_POINTS;
|
|
}
|
|
}
|
|
|
|
void CTFPointManager::ClientThink()
|
|
{
|
|
if ( !prediction->InPrediction() )
|
|
{
|
|
Update();
|
|
}
|
|
}
|
|
|
|
#endif // CLIENT_DLL
|
|
|
|
void CTFPointManager::Update()
|
|
{
|
|
TM_ZONE_DEFAULT( TELEMETRY_LEVEL0 )
|
|
|
|
float flDT = gpGlobals->curtime - m_flLastUpdateTime;
|
|
if ( flDT <= 0.f )
|
|
return;
|
|
|
|
m_flLastUpdateTime = gpGlobals->curtime;
|
|
|
|
#ifdef GAME_DLL
|
|
bool bUpdatePoints = m_vecPoints.Count() > 0;
|
|
Vector vHullMin( MAX_COORD_FLOAT, MAX_COORD_FLOAT, MAX_COORD_FLOAT );
|
|
Vector vHullMax( MIN_COORD_FLOAT, MIN_COORD_FLOAT, MIN_COORD_FLOAT );
|
|
#endif // GAME_DLL
|
|
|
|
// update point pos
|
|
FOR_EACH_VEC_BACK( m_vecPoints, i )
|
|
{
|
|
tf_point_t *pPoint = m_vecPoints[i];
|
|
|
|
// reset random seed
|
|
m_randomStream.SetSeed( m_nSpawnTime[ pPoint->m_nPointIndex ] + entindex() );
|
|
|
|
bool bShouldRemove = false;
|
|
// expired
|
|
if ( gpGlobals->curtime > pPoint->m_flSpawnTime + pPoint->m_flLifeTime )
|
|
{
|
|
bShouldRemove = true;
|
|
}
|
|
|
|
// in water?
|
|
int nContents = UTIL_PointContents( pPoint->m_vecPosition );
|
|
if ( (nContents & MASK_WATER) )
|
|
{
|
|
bShouldRemove = true;
|
|
}
|
|
|
|
if ( bShouldRemove )
|
|
{
|
|
RemovePoint( i );
|
|
continue;
|
|
}
|
|
|
|
Vector vecNewPos, vecMins, vecMaxs;
|
|
if ( !UpdatePoint( pPoint, i, flDT, &vecNewPos, &vecMins, &vecMaxs ) )
|
|
{
|
|
RemovePoint( i );
|
|
continue;
|
|
}
|
|
|
|
#ifdef GAME_DLL
|
|
VectorMin( vecNewPos + vecMins, vHullMin, vHullMin );
|
|
VectorMax( vecNewPos + vecMaxs, vHullMax, vHullMax );
|
|
#endif // GAME_DLL
|
|
}
|
|
|
|
#ifdef GAME_DLL
|
|
if ( bUpdatePoints )
|
|
{
|
|
if ( m_vecPoints.Count() == 0 )
|
|
{
|
|
UTIL_Remove( this );
|
|
}
|
|
else
|
|
{
|
|
Vector vExtent = 0.5f * ( vHullMax - vHullMin );
|
|
Vector vOrigin = vHullMin + vExtent;
|
|
SetAbsOrigin( vOrigin );
|
|
UTIL_SetSize( this, -vExtent, vExtent );
|
|
}
|
|
}
|
|
#endif // GAME_DLL
|
|
}
|
|
|
|
// return false if this point should be removed
|
|
bool CTFPointManager::UpdatePoint( tf_point_t *pPoint, int nIndex, float flDT, Vector *pVecNewPos /*= NULL*/, Vector *pVecMins /*= NULL*/, Vector *pVecMaxs /*= NULL*/ )
|
|
{
|
|
if ( flDT <= 0.f )
|
|
return true;
|
|
|
|
float flRadius = GetRadius( pPoint );
|
|
Vector vecMins = flRadius * Vector( -1, -1, -1 );
|
|
Vector vecMaxs = flRadius * Vector( 1, 1, 1 );
|
|
|
|
Vector vecGravity = Vector( 0, 0, GetGravity() ) * flDT;
|
|
Vector vecNewVelocity = pPoint->m_vecVelocity + vecGravity + GetAdditionalVelocity( pPoint );
|
|
Vector vecNewPos = pPoint->m_vecPosition + flDT * vecNewVelocity;
|
|
|
|
if ( pVecMins )
|
|
{
|
|
*pVecMins = vecMins;
|
|
}
|
|
if ( pVecMaxs )
|
|
{
|
|
*pVecMaxs = vecMaxs;
|
|
}
|
|
if ( pVecNewPos )
|
|
{
|
|
*pVecNewPos = vecNewPos;
|
|
}
|
|
|
|
// Create a ray for point to trace
|
|
Ray_t rayWorld;
|
|
rayWorld.Init( pPoint->m_vecPosition, vecNewPos, vecMins, vecMaxs );
|
|
|
|
// check against world first for point movement
|
|
trace_t trWorld;
|
|
UTIL_TraceRay( rayWorld, MASK_SOLID, this, COLLISION_GROUP_DEBRIS, &trWorld );
|
|
|
|
// start in a wall, just remove this
|
|
if ( !ShouldIgnoreStartSolid() && trWorld.startsolid )
|
|
{
|
|
return false;
|
|
}
|
|
// hit world? change direction to move along wall
|
|
else if ( trWorld.fraction < 1.f )
|
|
{
|
|
// increment number of time this point has touched world
|
|
pPoint->m_nHitWall++;
|
|
|
|
#ifdef GAME_DLL
|
|
// Some things we collide with but don't touch. Here we're going to make sure we collide.
|
|
if ( trWorld.m_pEnt && ShouldCollide( trWorld.m_pEnt ) )
|
|
{
|
|
// Sigh...
|
|
bool bSpecialMagicCollide = dynamic_cast<CTFPumpkinBomb*>( trWorld.m_pEnt ) ||
|
|
dynamic_cast<CTFGenericBomb*>( trWorld.m_pEnt ) ||
|
|
dynamic_cast<CTFMerasmusTrickOrTreatProp*>( trWorld.m_pEnt );
|
|
|
|
if ( bSpecialMagicCollide )
|
|
{
|
|
OnCollide( trWorld.m_pEnt, nIndex );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( OnPointHitWall( pPoint, vecNewPos, vecNewVelocity, trWorld, flDT ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// vecNewVelocity only used to compute vecNewPos
|
|
// if we hit nothing, set back to original velocity so we can apply drag
|
|
vecNewVelocity = pPoint->m_vecVelocity;
|
|
}
|
|
|
|
// apply drag
|
|
float flDrag = GetDrag();
|
|
float flSpeed = vecNewVelocity.NormalizeInPlace();
|
|
flSpeed = Clamp( flSpeed - flDT * flDrag * flSpeed, 0.f, flSpeed );
|
|
pPoint->m_vecVelocity = flSpeed * vecNewVelocity + vecGravity;
|
|
|
|
ModifyAdditionalMovementInfo( pPoint, flDT );
|
|
|
|
pPoint->m_vecPrevPosition = pPoint->m_vecPosition;
|
|
|
|
pPoint->m_vecPosition = vecNewPos;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CTFPointManager::OnPointHitWall( tf_point_t *pPoint, Vector &vecNewPos, Vector &vecNewVelocity, const trace_t& tr, float flDT )
|
|
{
|
|
// default behavior is to stop point on collision
|
|
vecNewPos = tr.endpos + GetRadius( pPoint ) * tr.plane.normal;
|
|
vecNewVelocity = vec3_origin;
|
|
|
|
return false;
|
|
}
|
|
|
|
void CTFPointManager::RemovePoint( int nPointIndex )
|
|
{
|
|
// free up spawn time for this slot
|
|
m_nSpawnTime.Set( m_vecPoints[ nPointIndex ]->m_nPointIndex, 0 );
|
|
|
|
delete m_vecPoints[ nPointIndex ];
|
|
m_vecPoints.Remove( nPointIndex );
|
|
}
|
|
|
|
void CTFPointManager::ClearPoints( void )
|
|
{
|
|
m_vecPoints.PurgeAndDeleteElements();
|
|
} |