You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
302 lines
6.7 KiB
302 lines
6.7 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "tf_walker_base.h" |
|
|
|
|
|
#include "in_buttons.h" |
|
#include "shake.h" |
|
|
|
|
|
static float MAX_WALKER_VEL = 100; |
|
|
|
|
|
IMPLEMENT_SERVERCLASS_ST( CWalkerBase, DT_WalkerBase ) |
|
END_SEND_TABLE() |
|
|
|
|
|
CWalkerBase::CWalkerBase() |
|
{ |
|
m_vSteerVelocity.Init(); |
|
m_iMovePoseParamX = -1; |
|
m_iMovePoseParamY = -1; |
|
m_bWalkMode = false; |
|
m_flDontMakeSoundsUntil = 0; |
|
m_flPlaybackSpeedBoost = 1; |
|
m_flVelocityDecayRate = 80; |
|
m_LastButtons = 0; |
|
m_vLastCmdViewAngles.Init(); |
|
} |
|
|
|
|
|
void CWalkerBase::SpawnWalker( |
|
const char *pModelName, |
|
int objectType, |
|
const Vector &vPlacementMins, |
|
const Vector &vPlacementMaxs, |
|
int iHealth, |
|
int nMaxPassengers, |
|
float flPlaybackSpeedBoost |
|
) |
|
{ |
|
SetModel( pModelName ); |
|
SetType( objectType ); |
|
|
|
UTIL_SetSize( this, vPlacementMins, vPlacementMaxs ); |
|
m_iHealth = iHealth; |
|
m_flPlaybackSpeedBoost = flPlaybackSpeedBoost; |
|
|
|
m_takedamage = DAMAGE_YES; |
|
SetMaxPassengerCount( nMaxPassengers ); |
|
|
|
|
|
|
|
// The model should be set before the derived class calls our Spawn(). |
|
Assert( GetModel() ); |
|
|
|
// By default, all walkers use the walk_box animation as they move. |
|
m_iMovePoseParamX = LookupPoseParameter( "move_x" ); |
|
m_iMovePoseParamY = LookupPoseParameter( "move_y" ); |
|
EnableWalkMode( true ); |
|
|
|
// The base class spawn sets a default collision group, so this needs to |
|
// be called post. |
|
SetCollisionGroup( COLLISION_GROUP_VEHICLE ); |
|
|
|
BaseClass::Spawn(); |
|
|
|
|
|
// HACKHACK: this is just so CBaseObject doesn't call StudioFrameAdvance for us. We should probably have |
|
// a specific flag for this behavior. |
|
m_fObjectFlags |= OF_DOESNT_HAVE_A_MODEL; |
|
m_fObjectFlags &= ~OF_MUST_BE_BUILT_ON_ATTACHMENT; |
|
|
|
|
|
// We animate, so let's not use manual mode for now. |
|
SetMoveType( MOVETYPE_STEP ); |
|
AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST ); |
|
|
|
EnableServerIK(); |
|
|
|
SetContextThink( WalkerThink, gpGlobals->curtime, "WalkerThink" ); |
|
} |
|
|
|
void CWalkerBase::EnableWalkMode( bool bEnable ) |
|
{ |
|
m_bWalkMode = bEnable; |
|
|
|
// Stop any movement.. |
|
m_vSteerVelocity.Init(); |
|
|
|
if ( bEnable ) |
|
{ |
|
ResetSequence( LookupSequence( "walk_box" ) ); |
|
|
|
// HACK: there should be a better way to this.. like CBaseAnimating::ResetAnimation, |
|
// or ResetSequence should do it. |
|
SetCycle( 0 ); |
|
} |
|
} |
|
|
|
|
|
void CWalkerBase::AdjustInitialBuildAngles() |
|
{ |
|
QAngle vNewAngles = GetAbsAngles(); |
|
vNewAngles[YAW] += 90; |
|
SetAbsAngles( vNewAngles ); |
|
} |
|
|
|
|
|
void CWalkerBase::WalkerThink() |
|
{ |
|
float dt = GetTimeDelta(); |
|
|
|
// Decay our velocity. |
|
if ( m_bWalkMode ) |
|
{ |
|
m_flPlaybackRate = m_flPlaybackSpeedBoost; |
|
|
|
|
|
float flDecayRate = m_flVelocityDecayRate; |
|
|
|
float flLen = m_vSteerVelocity.Length(); |
|
Vector2DNormalize( m_vSteerVelocity ); |
|
|
|
float flDecayAmt = flDecayRate * dt; |
|
flLen = MAX( 0, flLen - flDecayAmt ); |
|
m_vSteerVelocity *= flLen; |
|
|
|
|
|
// Setup our pose parameters. |
|
SetPoseParameter( m_iMovePoseParamX, RemapVal( m_vSteerVelocity.x, -MAX_WALKER_VEL, MAX_WALKER_VEL, -1, 1 ) ); |
|
SetPoseParameter( m_iMovePoseParamY, RemapVal( m_vSteerVelocity.y, -MAX_WALKER_VEL, MAX_WALKER_VEL, -1, 1 ) ); |
|
|
|
// Use an idle animation if they're not moving. |
|
int iWantedSequence = LookupSequence( "walk_box" ); |
|
if ( m_vSteerVelocity.x == 0 && m_vSteerVelocity.y == 0 ) |
|
{ |
|
iWantedSequence = LookupSequence( "idle" ); |
|
|
|
// HACK: HL2 Strider has no idle |
|
if ( iWantedSequence == -1 ) |
|
iWantedSequence = LookupSequence( "ragdoll" ); |
|
} |
|
|
|
if ( iWantedSequence != -1 && GetSequence() != iWantedSequence ) |
|
ResetSequence( iWantedSequence ); |
|
} |
|
|
|
|
|
// Now ask the model how far it thought it moved based on the animation. |
|
// Turns out the animation thinks it's moving just a tiny bit, even when we're centered on the idle animation, |
|
// so we just force it not to move here if we know we're not supposed to move. |
|
if ( m_vSteerVelocity.Length() > 0 ) |
|
{ |
|
Vector vNewPos = GetWalkerLocalMovement(); |
|
|
|
SetLocalOrigin( vNewPos ); |
|
} |
|
|
|
|
|
// Hard-coded for now. These should come from the vehicle's script eventually. |
|
// Now slowly rotate towards the player's eye angles. |
|
CBasePlayer *pPlayer = GetPassenger( VEHICLE_ROLE_DRIVER ); |
|
if ( pPlayer ) |
|
{ |
|
static float flAccelRate = 180; |
|
static float flRotateRate = 60; |
|
|
|
|
|
// Figure out a force to apply to our current velocity. |
|
Vector2D vAccel( 0, 0 ); |
|
|
|
if ( m_LastButtons & IN_FORWARD ) |
|
vAccel.x += flAccelRate; |
|
|
|
if ( m_LastButtons & IN_BACK ) |
|
vAccel.x -= flAccelRate; |
|
|
|
if ( m_LastButtons & IN_MOVELEFT ) |
|
vAccel.y -= flAccelRate; |
|
|
|
if ( m_LastButtons & IN_MOVERIGHT ) |
|
vAccel.y += flAccelRate; |
|
|
|
m_vSteerVelocity += vAccel * dt; |
|
|
|
|
|
m_vSteerVelocity.x = clamp( m_vSteerVelocity.x, -MAX_WALKER_VEL, MAX_WALKER_VEL ); |
|
m_vSteerVelocity.y = clamp( m_vSteerVelocity.y, -MAX_WALKER_VEL, MAX_WALKER_VEL ); |
|
|
|
|
|
float wantedYaw = m_vLastCmdViewAngles[YAW]; |
|
QAngle curAngles = GetAbsAngles(); |
|
curAngles[YAW] = ApproachAngle( wantedYaw, curAngles[YAW], flRotateRate * dt ); |
|
SetAbsAngles( curAngles ); |
|
} |
|
|
|
|
|
DispatchAnimEvents( this ); |
|
|
|
|
|
// Get another think. |
|
SetContextThink( WalkerThink, gpGlobals->curtime + dt, "WalkerThink" ); |
|
} |
|
|
|
|
|
Vector CWalkerBase::GetWalkerLocalMovement() |
|
{ |
|
bool bIgnored; |
|
Vector vNewPos; |
|
QAngle vNewAngles; |
|
GetIntervalMovement( GetAnimTimeInterval(), bIgnored, vNewPos, vNewAngles ); |
|
return vNewPos; |
|
} |
|
|
|
|
|
const Vector2D& CWalkerBase::GetSteerVelocity() const |
|
{ |
|
return m_vSteerVelocity; |
|
} |
|
|
|
|
|
|
|
void CWalkerBase::Spawn() |
|
{ |
|
// Derived classes should call SpawnWalker instead of chaining down to CWalkerBase::Spawn(). |
|
Assert( false ); |
|
} |
|
|
|
|
|
void CWalkerBase::Activate() |
|
{ |
|
WalkerActivate(); |
|
BaseClass::Activate(); |
|
} |
|
|
|
void CWalkerBase::WalkerActivate( void ) |
|
{ |
|
// Until we're finished building, turn off vphysics-based motion |
|
SetSolid( SOLID_VPHYSICS ); |
|
VPhysicsInitStatic(); |
|
|
|
SetPoseParameter( m_iMovePoseParamX, 0 ); |
|
SetPoseParameter( m_iMovePoseParamY, 0 ); |
|
} |
|
|
|
|
|
void CWalkerBase::SetVelocityDecayRate( float flDecayRate ) |
|
{ |
|
m_flVelocityDecayRate = flDecayRate; |
|
} |
|
|
|
|
|
float CWalkerBase::GetTimeDelta() const |
|
{ |
|
return 0.1; |
|
} |
|
|
|
|
|
void CWalkerBase::SetupMove( CBasePlayer *pPlayer, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) |
|
{ |
|
// This calls StudioFrameAdvance for us. |
|
//BaseClass::SetupMove( pPlayer, ucmd, pHelper, move ); |
|
|
|
// Lose control when the player dies |
|
if ( pPlayer->IsAlive() == false ) |
|
{ |
|
m_LastButtons = 0; |
|
return; |
|
} |
|
|
|
// Only the driver gets to drive. |
|
int nRole = GetPassengerRole( pPlayer ); |
|
if ( nRole != VEHICLE_ROLE_DRIVER ) |
|
return; |
|
|
|
m_LastButtons = ucmd->buttons; |
|
m_vLastCmdViewAngles = ucmd->viewangles; |
|
} |
|
|
|
|
|
bool CWalkerBase::IsPassengerVisible( int nRole ) |
|
{ |
|
return true; |
|
} |
|
|
|
|
|
bool CWalkerBase::StartBuilding( CBaseEntity *pBuilder ) |
|
{ |
|
if ( !BaseClass::StartBuilding( pBuilder ) ) |
|
return false; |
|
|
|
WalkerActivate(); |
|
return true; |
|
} |
|
|
|
|
|
|
|
|