source-engine/game/shared/hl2/env_headcrabcanister_shared.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

394 lines
14 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "env_headcrabcanister_shared.h"
#include "mapdata_shared.h"
#include "sharedInterface.h"
#include "mathlib/vmatrix.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define ROTATION_SPEED 90.0f
BEGIN_SIMPLE_DATADESC( CEnvHeadcrabCanisterShared )
DEFINE_FIELD( m_vecStartPosition, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( m_vecEnterWorldPosition, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( m_vecDirection, FIELD_VECTOR ),
DEFINE_FIELD( m_vecStartAngles, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_flLaunchHeight, FIELD_FLOAT, "StartingHeight" ),
DEFINE_KEYFIELD( m_flFlightSpeed, FIELD_FLOAT, "FlightSpeed" ),
DEFINE_KEYFIELD( m_flFlightTime, FIELD_FLOAT, "FlightTime" ),
DEFINE_FIELD( m_flLaunchTime, FIELD_TIME ),
DEFINE_FIELD( m_flWorldEnterTime, FIELD_FLOAT ),
DEFINE_FIELD( m_flInitialZSpeed, FIELD_FLOAT ),
DEFINE_FIELD( m_flZAcceleration, FIELD_FLOAT ),
DEFINE_FIELD( m_flHorizSpeed, FIELD_FLOAT ),
DEFINE_FIELD( m_bLaunchedFromWithinWorld, FIELD_BOOLEAN ),
DEFINE_FIELD( m_vecSkyboxOrigin, FIELD_VECTOR ),
DEFINE_FIELD( m_vecParabolaDirection, FIELD_VECTOR ),
DEFINE_FIELD( m_flSkyboxScale, FIELD_FLOAT ),
DEFINE_FIELD( m_bInSkybox, FIELD_BOOLEAN ),
END_DATADESC()
BEGIN_NETWORK_TABLE_NOBASE( CEnvHeadcrabCanisterShared, DT_EnvHeadcrabCanisterShared )
#if !defined( CLIENT_DLL )
SendPropFloat ( SENDINFO( m_flFlightSpeed ), 0, SPROP_NOSCALE ),
SendPropTime ( SENDINFO( m_flLaunchTime ) ),
SendPropVector ( SENDINFO( m_vecParabolaDirection ), 0, SPROP_NOSCALE ),
SendPropFloat ( SENDINFO( m_flFlightTime ), 0, SPROP_NOSCALE ),
SendPropFloat ( SENDINFO( m_flWorldEnterTime ), 0, SPROP_NOSCALE ),
SendPropFloat ( SENDINFO( m_flInitialZSpeed ), 0, SPROP_NOSCALE ),
SendPropFloat ( SENDINFO( m_flZAcceleration ), 0, SPROP_NOSCALE ),
SendPropFloat ( SENDINFO( m_flHorizSpeed ), 0, SPROP_NOSCALE ),
SendPropBool ( SENDINFO( m_bLaunchedFromWithinWorld ) ),
SendPropVector ( SENDINFO( m_vecStartPosition ), 0, SPROP_NOSCALE ),
SendPropVector ( SENDINFO( m_vecEnterWorldPosition ), 0, SPROP_NOSCALE ),
SendPropVector ( SENDINFO( m_vecDirection ), 0, SPROP_NOSCALE ),
SendPropVector ( SENDINFO( m_vecStartAngles ), 0, SPROP_NOSCALE ),
SendPropVector ( SENDINFO( m_vecSkyboxOrigin ), 0, SPROP_NOSCALE ),
SendPropFloat ( SENDINFO( m_flSkyboxScale ), 0, SPROP_NOSCALE ),
SendPropBool ( SENDINFO( m_bInSkybox ) ),
#else
RecvPropFloat ( RECVINFO( m_flFlightSpeed ) ),
RecvPropTime ( RECVINFO( m_flLaunchTime ) ),
RecvPropVector ( RECVINFO( m_vecParabolaDirection ) ),
RecvPropFloat ( RECVINFO( m_flFlightTime ) ),
RecvPropFloat ( RECVINFO( m_flWorldEnterTime ) ),
RecvPropFloat ( RECVINFO( m_flInitialZSpeed ) ),
RecvPropFloat ( RECVINFO( m_flZAcceleration ) ),
RecvPropFloat ( RECVINFO( m_flHorizSpeed ) ),
RecvPropBool ( RECVINFO( m_bLaunchedFromWithinWorld ) ),
RecvPropVector ( RECVINFO( m_vecStartPosition ) ),
RecvPropVector ( RECVINFO( m_vecEnterWorldPosition ) ),
RecvPropVector ( RECVINFO( m_vecDirection ) ),
RecvPropVector ( RECVINFO( m_vecStartAngles ) ),
RecvPropVector ( RECVINFO( m_vecSkyboxOrigin ) ),
RecvPropFloat ( RECVINFO( m_flSkyboxScale ) ),
RecvPropBool ( RECVINFO( m_bInSkybox ) ),
#endif
END_NETWORK_TABLE()
//=============================================================================
//
// HeadcrabCanister Functions.
//
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CEnvHeadcrabCanisterShared::CEnvHeadcrabCanisterShared()
{
m_vecStartPosition.Init();
m_vecDirection.Init();
m_flFlightSpeed = 0.0f;
// This tells the client DLL to not draw trails, etc.
m_flLaunchTime = -1.0f;
m_flWorldEnterTime = 0.0f;
m_flFlightTime = 0.0f;
m_bInSkybox = false;
}
//-----------------------------------------------------------------------------
// Creates a headcrab canister in the world
//-----------------------------------------------------------------------------
void CEnvHeadcrabCanisterShared::InitInWorld( float flLaunchTime,
const Vector &vecStartPosition, const QAngle &vecStartAngles,
const Vector &vecDirection, const Vector &vecImpactPosition, bool bLaunchedFromWithinWorld )
{
Vector vecActualStartPosition = vecStartPosition;
if ( !bLaunchedFromWithinWorld )
{
// Move the start position inward if it's too close
Vector vecDelta;
VectorSubtract( vecStartPosition, vecImpactPosition, vecDelta );
VectorNormalize( vecDelta );
VectorMA( vecImpactPosition, m_flFlightTime * m_flFlightSpeed, vecDelta, vecActualStartPosition );
}
// Setup initial parametric state.
m_flLaunchTime = flLaunchTime;
m_vecStartPosition = vecActualStartPosition;
m_vecEnterWorldPosition = vecActualStartPosition;
m_vecDirection = vecDirection;
m_vecStartAngles = vecStartAngles;
m_flWorldEnterTime = 0.0f;
m_bInSkybox = false;
m_bLaunchedFromWithinWorld = bLaunchedFromWithinWorld;
if ( m_bLaunchedFromWithinWorld )
{
m_flSkyboxScale = 1;
m_vecSkyboxOrigin = vec3_origin;
float flLength = m_vecDirection.Get().AsVector2D().Length();
VectorSubtract(vecImpactPosition, vecStartPosition, m_vecParabolaDirection.GetForModify());
m_vecParabolaDirection.GetForModify().z = 0;
float flTotalDistance = VectorNormalize( m_vecParabolaDirection.GetForModify() );
m_vecDirection.GetForModify().x = flLength * m_vecParabolaDirection.Get().x;
m_vecDirection.GetForModify().y = flLength * m_vecParabolaDirection.Get().y;
m_flHorizSpeed = flTotalDistance / m_flFlightTime;
m_flWorldEnterTime = 0;
float flFinalZSpeed = m_vecDirection.Get().z * m_flHorizSpeed;
m_flFlightSpeed = sqrt( m_flHorizSpeed * m_flHorizSpeed + flFinalZSpeed * flFinalZSpeed );
m_flInitialZSpeed = (2.0f * ( vecImpactPosition.z - vecStartPosition.z ) - flFinalZSpeed * m_flFlightTime) / m_flFlightTime;
m_flZAcceleration = (flFinalZSpeed - m_flInitialZSpeed) / m_flFlightTime;
}
}
//-----------------------------------------------------------------------------
// Creates a headcrab canister in the skybox
//-----------------------------------------------------------------------------
void CEnvHeadcrabCanisterShared::InitInSkybox( float flLaunchTime,
const Vector &vecStartPosition, const QAngle &vecStartAngles, const Vector &vecDirection,
const Vector &vecImpactPosition, const Vector &vecSkyboxOrigin, float flSkyboxScale )
{
// Compute a horizontal speed (constant)
m_vecParabolaDirection.Init( vecDirection.x, vecDirection.y, 0.0f );
float flLength = VectorNormalize( m_vecParabolaDirection.GetForModify() );
m_flHorizSpeed = flLength * m_flFlightSpeed;
// compute total distance to travel
float flTotalDistance = m_flFlightTime * m_flHorizSpeed;
flTotalDistance -= vecStartPosition.AsVector2D().DistTo( vecImpactPosition.AsVector2D() );
if ( flTotalDistance <= 0.0f )
{
InitInWorld( flLaunchTime, vecStartPosition, vecStartAngles, vecDirection, vecImpactPosition );
return;
}
// Setup initial parametric state.
m_flLaunchTime = flLaunchTime;
m_flWorldEnterTime = flTotalDistance / m_flHorizSpeed;
m_vecSkyboxOrigin = vecSkyboxOrigin;
m_flSkyboxScale = flSkyboxScale;
m_vecEnterWorldPosition = vecStartPosition;
m_vecDirection = vecDirection;
m_vecStartAngles = vecStartAngles;
m_bInSkybox = true;
m_bLaunchedFromWithinWorld = false;
// Compute parabolic course
// Assume the x velocity remains constant.
// Z moves ballistically, as if under gravity
// zf + lh = zo
// vf = vo + a*t
// zf = zo + vo*t + 0.5 * a * t*t
// a*t = vf - vo
// zf = zo + vo*t + 0.5f * (vf - vo) * t
// zf - zo = 0.5f *vo*t + 0.5f * vf * t
// -lh - 0.5f * vf * t = 0.5f * vo * t
// vo = -2.0f * lh / t - vf
// a = (vf - vo) / t
m_flHorizSpeed /= flSkyboxScale;
VectorMA( vecSkyboxOrigin, 1.0f / m_flSkyboxScale, vecStartPosition, m_vecStartPosition.GetForModify() );
VectorMA( m_vecStartPosition.Get(), -m_flHorizSpeed * m_flWorldEnterTime, m_vecParabolaDirection, m_vecStartPosition.GetForModify() );
float flLaunchHeight = m_flLaunchHeight / flSkyboxScale;
float flFinalZSpeed = m_vecDirection.Get().z * m_flFlightSpeed / flSkyboxScale;
m_vecStartPosition.GetForModify().z += flLaunchHeight;
m_flZAcceleration = 2.0f * ( flLaunchHeight + flFinalZSpeed * m_flWorldEnterTime ) / ( m_flWorldEnterTime * m_flWorldEnterTime );
m_flInitialZSpeed = flFinalZSpeed - m_flZAcceleration * m_flWorldEnterTime;
}
//-----------------------------------------------------------------------------
// Convert from skybox to world
//-----------------------------------------------------------------------------
void CEnvHeadcrabCanisterShared::ConvertFromSkyboxToWorld()
{
Assert( m_bInSkybox );
m_bInSkybox = false;
}
//-----------------------------------------------------------------------------
// Returns the time at which it enters the world
//-----------------------------------------------------------------------------
float CEnvHeadcrabCanisterShared::GetEnterWorldTime() const
{
return m_flWorldEnterTime;
}
//-----------------------------------------------------------------------------
// Did we impact?
//-----------------------------------------------------------------------------
bool CEnvHeadcrabCanisterShared::DidImpact( float flTime ) const
{
return (flTime - m_flLaunchTime) >= m_flFlightTime;
}
//-----------------------------------------------------------------------------
// Computes the position of the canister
//-----------------------------------------------------------------------------
void CEnvHeadcrabCanisterShared::GetPositionAtTime( float flTime, Vector &vecPosition, QAngle &vecAngles )
{
float flDeltaTime = flTime - m_flLaunchTime;
if ( flDeltaTime > m_flFlightTime )
{
flDeltaTime = m_flFlightTime;
}
VMatrix initToWorld;
if ( m_bLaunchedFromWithinWorld || m_bInSkybox )
{
VectorMA( m_vecStartPosition, flDeltaTime * m_flHorizSpeed, m_vecParabolaDirection, vecPosition );
vecPosition.z += m_flInitialZSpeed * flDeltaTime + 0.5f * m_flZAcceleration * flDeltaTime * flDeltaTime;
Vector vecLeft;
CrossProduct( m_vecParabolaDirection, Vector( 0, 0, 1 ), vecLeft );
Vector vecForward;
VectorMultiply( m_vecParabolaDirection, -1.0f, vecForward );
vecForward.z = -(m_flInitialZSpeed + m_flZAcceleration * flDeltaTime) / m_flHorizSpeed; // This is -dz/dx.
VectorNormalize( vecForward );
Vector vecUp;
CrossProduct( vecForward, vecLeft, vecUp );
initToWorld.SetBasisVectors( vecForward, vecLeft, vecUp );
}
else
{
flDeltaTime -= m_flWorldEnterTime;
Vector vecVelocity;
VectorMultiply( m_vecDirection, m_flFlightSpeed, vecVelocity );
VectorMA( m_vecEnterWorldPosition, flDeltaTime, vecVelocity, vecPosition );
MatrixFromAngles( m_vecStartAngles.Get(), initToWorld );
}
VMatrix rotation;
MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), flDeltaTime * ROTATION_SPEED );
VMatrix newAngles;
MatrixMultiply( initToWorld, rotation, newAngles );
MatrixToAngles( newAngles, vecAngles );
}
//-----------------------------------------------------------------------------
// Are we in the skybox?
//-----------------------------------------------------------------------------
bool CEnvHeadcrabCanisterShared::IsInSkybox( )
{
// Check to see if we are always in the world!
return m_bInSkybox;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvHeadcrabCanisterShared::CalcEnterTime( const Vector &vecTriggerMins,
const Vector &vecTriggerMaxs )
{
/*
#define HEADCRABCANISTER_TRIGGER_EPSILON 0.001f
// Initialize the enter/exit fractions.
float flEnterFrac = 0.0f;
float flExitFrac = 1.0f;
// Create an arbitrarily large end position.
Vector vecEndPosition;
VectorMA( m_vecStartPosition, 32000.0f, m_vecDirection, vecEndPosition );
float flFrac, flDistStart, flDistEnd;
for( int iAxis = 0; iAxis < 3; iAxis++ )
{
// Negative Axis
flDistStart = -m_vecStartPosition[iAxis] + vecTriggerMins[iAxis];
flDistEnd = -vecEndPosition[iAxis] + vecTriggerMins[iAxis];
if ( ( flDistStart > 0.0f ) && ( flDistEnd < 0.0f ) )
{
flFrac = ( flDistStart - HEADCRABCANISTER_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
if ( flFrac > flEnterFrac ) { flEnterFrac = flFrac; }
}
if ( ( flDistStart < 0.0f ) && ( flDistEnd > 0.0f ) )
{
flFrac = ( flDistStart + HEADCRABCANISTER_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
if( flFrac < flExitFrac ) { flExitFrac = flFrac; }
}
if ( ( flDistStart > 0.0f ) && ( flDistEnd > 0.0f ) )
return;
// Positive Axis
flDistStart = m_vecStartPosition[iAxis] - vecTriggerMaxs[iAxis];
flDistEnd = vecEndPosition[iAxis] - vecTriggerMaxs[iAxis];
if ( ( flDistStart > 0.0f ) && ( flDistEnd < 0.0f ) )
{
flFrac = ( flDistStart - HEADCRABCANISTER_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
if ( flFrac > flEnterFrac ) { flEnterFrac = flFrac; }
}
if ( ( flDistStart < 0.0f ) && ( flDistEnd > 0.0f ) )
{
flFrac = ( flDistStart + HEADCRABCANISTER_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
if( flFrac < flExitFrac ) { flExitFrac = flFrac; }
}
if ( ( flDistStart > 0.0f ) && ( flDistEnd > 0.0f ) )
return;
}
// Check for intersection.
if ( flExitFrac >= flEnterFrac )
{
// Check to see if we start in the world or the skybox!
if ( flEnterFrac == 0.0f )
{
m_nLocation = HEADCRABCANISTER_LOCATION_WORLD;
}
else
{
m_nLocation = HEADCRABCANISTER_LOCATION_SKYBOX;
}
// Calculate the enter/exit times.
Vector vecEnterPoint, vecExitPoint, vecDeltaPosition;
VectorSubtract( vecEndPosition, m_vecStartPosition, vecDeltaPosition );
VectorScale( vecDeltaPosition, flEnterFrac, vecEnterPoint );
VectorScale( vecDeltaPosition, flExitFrac, vecExitPoint );
m_flWorldEnterTime = vecEnterPoint.Length() / m_flFlightSpeed;
m_flWorldEnterTime += m_flLaunchTime;
}
*/
#undef HEADCRABCANISTER_TRIGGER_EPSILON
}