📄 tf_shield_mobile_shared.cpp
字号:
//-----------------------------------------------------------------------------
// Set the shield angles
//-----------------------------------------------------------------------------
void CShieldMobile::SetCenterAngles( const QAngle& angles )
{
// The tmp ang locked angles is simply there to prevent unnecessary network traffic
m_tmpAngLockedAngles = angles;
if ( ( m_ShieldState.Get() & SHIELD_ORIENT_TO_OWNER ) == 0 )
{
m_angLockedAngles.Set( angles );
}
}
bool CShieldMobile::IsAlwaysOrienting( )
{
return ( m_ShieldState.Get() & SHIELD_ORIENT_TO_OWNER ) != 0;
}
void CShieldMobile::SetAngularSpringConstant( float flConstant )
{
m_flSpringConstant = flConstant;
m_ShieldEffect.SetAngularSpringConstant( flConstant );
}
void CShieldMobile::SetFrontDistance( float flDistance )
{
m_flFrontDistance = flDistance;
}
void CShieldMobile::SetThetaPhi( float flTheta, float flPhi )
{
// This sets the bounds of the shield; how tall + wide is it?
m_flShieldTheta = flTheta;
m_flShieldPhi = flPhi;
m_ShieldEffect.SetThetaPhi(flTheta, flPhi);
}
//-----------------------------------------------------------------------------
// Computes the shield bounding box
//-----------------------------------------------------------------------------
void CShieldMobile::ComputeBoundingBox( void )
{
Vector mins, maxs;
m_ShieldEffect.ComputeBounds(mins, maxs);
#ifdef CLIENT_DLL
SetCollisionBounds( mins, maxs );
Relink();
#else
UTIL_SetSize( this, mins, maxs );
#endif
}
//-----------------------------------------------------------------------------
// Computes a surrounding box the the entity
//-----------------------------------------------------------------------------
void CShieldMobile::SetObjectCollisionBox( void )
{
SetAbsMins( WorldAlignMins() + GetAbsOrigin() );
SetAbsMaxs( WorldAlignMaxs() + GetAbsOrigin() );
}
//-----------------------------------------------------------------------------
// Determines shield obstructions
//-----------------------------------------------------------------------------
void CShieldMobile::DetermineObstructions( )
{
m_ShieldEffect.ComputeVertexActivity();
}
//-----------------------------------------------------------------------------
// Called by the enumerator call in ShieldThink
//-----------------------------------------------------------------------------
bool CShieldMobile::EnumEntity( IHandleEntity *pHandleEntity )
{
#ifdef CLIENT_DLL
CBaseEntity *pOther = cl_entitylist->GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() );
#else
CBaseEntity *pOther = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() );
#endif
if (!pOther)
return true;
// Blow off non-solid things
if ( !::IsSolid(pOther->GetSolid(), pOther->GetSolidFlags()) )
return true;
// No model, blow it off
if ( !pOther->GetModelIndex() )
return true;
// Blow off point-sized things....
if ( pOther->IsPointSized() )
return true;
// Don't bother if we shouldn't be colliding with this guy...
if (!m_pEnumCtx->m_Filter.ShouldHitEntity( pOther, MASK_SOLID ))
return true;
// The shield is in its final position, so we're gonna have to determine the
// point of collision by working in the space of the final position....
// We do this by moving the obstruction by the relative movement amount...
Vector vecStart, vecEnd;
VectorAdd( pOther->GetAbsOrigin(), m_pEnumCtx->m_vecStartDelta, vecStart );
VectorAdd( vecStart, m_pEnumCtx->m_vecEndDelta, vecEnd );
Ray_t ray;
ray.Init( vecStart, vecEnd, pOther->WorldAlignMins(), pOther->WorldAlignMaxs() );
trace_t tr;
if (TestCollision( ray, pOther->PhysicsSolidMaskForEntity(), tr ))
{
// Ok, we got a collision. Let's indicate it happened...
// At the moment, we'll report the collision point as being on the
// surface of the shield in its final position, which is kind of bogus...
pOther->PhysicsImpact( this, tr );
}
return true;
}
//-----------------------------------------------------------------------------
// Update the shield position:
//-----------------------------------------------------------------------------
void CShieldMobile::SimulateShield( void )
{
CBaseEntity *owner = GetOwnerEntity();
Vector origin;
if ( owner )
{
if ( m_ShieldState & SHIELD_ORIENT_TO_OWNER )
{
if ( owner->IsPlayer() )
{
m_ShieldEffect.SetDesiredAngles( owner->EyeAngles() );
}
else
{
m_ShieldEffect.SetDesiredAngles( owner->GetAbsAngles() );
}
}
else
{
m_ShieldEffect.SetDesiredAngles( m_angLockedAngles );
}
if ( m_nAttachmentIndex == 0 )
{
origin = owner->EyePosition();
}
else
{
QAngle angles;
CBaseAnimating *pAnim = dynamic_cast<CBaseAnimating*>( owner );
if (pAnim)
{
pAnim->GetAttachment( m_nAttachmentIndex, origin, angles );
}
else
{
origin = owner->EyePosition();
}
}
if ( m_flFrontDistance )
{
Vector vForward;
AngleVectors( m_ShieldEffect.GetDesiredAngles(), &vForward );
origin += vForward * m_flFrontDistance;
}
}
else
{
Assert( 0 );
origin = vec3_origin;
}
Vector vecOldOrigin = m_ShieldEffect.GetCurrentPosition();
Vector vecDelta;
VectorSubtract( origin, vecOldOrigin, vecDelta );
float flMaxDist = 100 + m_flFrontDistance;
if (vecDelta.LengthSqr() > flMaxDist * flMaxDist )
{
OnTeleported();
return;
}
m_ShieldEffect.SetDesiredOrigin( origin );
m_ShieldEffect.Simulate(gpGlobals->frametime);
DetermineObstructions();
SetAbsOrigin( m_ShieldEffect.GetCurrentPosition() );
SetAbsAngles( m_ShieldEffect.GetCurrentAngles() );
#ifdef CLIENT_DLL
// Necessary because we exclude the network origin
SetNetworkOrigin( m_ShieldEffect.GetCurrentPosition() );
SetNetworkAngles( m_ShieldEffect.GetCurrentAngles() );
#endif
// Compute a composite bounding box surrounding the initial + new positions..
Vector vecCompositeMins = WorldAlignMins() + vecOldOrigin;
Vector vecCompositeMaxs = WorldAlignMaxs() + vecOldOrigin;
ComputeBoundingBox();
// Sweep the shield through the world + touch things it hits...
SweepContext_t ctx( this, GetCollisionGroup() );
VectorSubtract( GetAbsOrigin(), vecOldOrigin, ctx.m_vecStartDelta );
if (ctx.m_vecStartDelta != vec3_origin)
{
// FIXME: Brutal hack; needed because IntersectRayWithTriangle misses stuff
// especially with short rays; I'm not sure what to do about this.
// This basically simulates a shield thickness of 15 units
ctx.m_vecEndDelta = ctx.m_vecStartDelta;
VectorNormalize( ctx.m_vecEndDelta );
ctx.m_vecEndDelta *= -15.0f;
Vector vecNewMins = WorldAlignMins() + GetAbsOrigin();
Vector vecNewMaxs = WorldAlignMaxs() + GetAbsOrigin();
VectorMin( vecCompositeMins, vecNewMins, vecCompositeMins );
VectorMax( vecCompositeMaxs, vecNewMaxs, vecCompositeMaxs );
m_pEnumCtx = &ctx;
enginetrace->EnumerateEntities( vecCompositeMins, vecCompositeMaxs, this );
}
}
//-----------------------------------------------------------------------------
// Update the shield position:
//-----------------------------------------------------------------------------
void CShieldMobile::ShieldThink( void )
{
SimulateShield();
#ifdef CLIENT_DLL
m_ShieldEffect.ComputeControlPoints();
m_ShieldEffect.ComputePanelActivity();
#endif
SetNextThink( gpGlobals->curtime + 0.01f );
}
void CShieldMobile::ClientThink()
{
#ifdef CLIENT_DLL
if ( GetPredictable() )
return;
SimulateShield();
m_ShieldEffect.ComputeControlPoints();
m_ShieldEffect.ComputePanelActivity();
#endif
}
//-----------------------------------------------------------------------------
// Teleport!
//-----------------------------------------------------------------------------
void CShieldMobile::OnTeleported( )
{
CBaseEntity *owner = GetOwnerEntity();
if (!owner)
return;
m_ShieldEffect.SetCurrentAngles( owner->GetAbsAngles() );
Vector origin;
origin = owner->EyePosition();
if ( m_flFrontDistance )
{
Vector vForward;
AngleVectors( m_ShieldEffect.GetCurrentAngles(), &vForward );
origin += vForward * m_flFrontDistance;
}
m_ShieldEffect.SetCurrentPosition( origin );
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Get this after the data changes
//-----------------------------------------------------------------------------
void CShieldMobile::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
m_ShieldEffect.SetThetaPhi( m_flShieldTheta, m_flShieldPhi );
m_ShieldEffect.SetAngularSpringConstant( m_flSpringConstant );
}
//-----------------------------------------------------------------------------
// A little pre-render processing
//-----------------------------------------------------------------------------
void C_ShieldMobile::PreRender( )
{
if (m_ShieldState & SHIELD_MOBILE_EMP)
{
// Decay fade if we've been EMPed or if we're inactive
if (m_FadeValue > 0.0f)
{
m_FadeValue -= gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
if (m_FadeValue < 0.0f)
{
m_FadeValue = 0.0f;
// Reset the shield to un-wobbled state
m_ShieldEffect.ComputeControlPoints();
}
else
{
Vector dir;
AngleVectors( m_ShieldEffect.GetCurrentAngles(), & dir, 0, 0 );
// Futz with the control points if we've been EMPed
for (int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i)
{
// Get the direction for the point
float factor = -EMP_WAVE_AMPLITUDE * sin( i * M_PI * 0.5f + gpGlobals->curtime * M_PI / SHIELD_EMP_WOBBLE_TIME );
m_ShieldEffect.GetPoint(i) += dir * factor;
}
}
}
}
else
{
// Fade back in, no longer EMPed
if (m_FadeValue < 1.0f)
{
m_FadeValue += gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
if (m_FadeValue >= 1.0f)
{
m_FadeValue = 1.0f;
}
}
}
}
void CShieldMobile::AddEntity( )
{
BaseClass::AddEntity( );
PreRender();
}
//-----------------------------------------------------------------------------
// Bounds computation
//-----------------------------------------------------------------------------
void CShieldMobile::GetBounds( Vector& mins, Vector& maxs )
{
m_ShieldEffect.ComputeBounds( mins, maxs );
}
//-----------------------------------------------------------------------------
// Gets at the control point data; who knows how it was made?
//-----------------------------------------------------------------------------
void CShieldMobile::GetShieldData( const Vector** ppVerts, float* pOpacity, float* pBlend )
{
for ( int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i )
{
ppVerts[i] = &m_ShieldEffect.GetControlPoint(i);
if ( m_pVertsActive[i >> 3] & (1 << (i & 0x7)) )
{
pOpacity[i] = m_ShieldEffect.ComputeOpacity( *ppVerts[i], GetAbsOrigin() );
pBlend[i] = 1.0f;
}
else
{
pOpacity[i] = 192.0f;
pBlend[i] = 0.0f;
}
}
}
#endif // CLIENT_DLL
#ifndef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Create a mobile version of the shield
//-----------------------------------------------------------------------------
CShield *CreateMobileShield( CBaseEntity *owner, float flFrontDistance )
{
CShieldMobile *pShield = (CShieldMobile*)CreateEntityByName("shield_mobile");
pShield->SetOwnerEntity( owner );
pShield->SetLocalAngles( owner->GetAbsAngles() );
pShield->SetFrontDistance( flFrontDistance );
// Start it in the right place
Vector vForward;
AngleVectors( owner->GetAbsAngles(), &vForward );
Vector vecOrigin = owner->EyePosition() + (vForward * flFrontDistance);
UTIL_SetOrigin( pShield, vecOrigin );
pShield->ChangeTeam( owner->GetTeamNumber() );
pShield->SetupRecharge( shield_mobile_power.GetFloat(), shield_mobile_recharge_delay.GetFloat(), shield_mobile_recharge_amount.GetFloat(), shield_mobile_recharge_time.GetFloat() );
pShield->Spawn();
return pShield;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -