quake4-sdk/source/game/vehicle/Vehicle_Walker.cpp
2007-06-15 00:00:00 +00:00

593 lines
16 KiB
C++

#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
#include "VehicleAnimated.h"
class rvVehicleWalker : public rvVehicleAnimated {
public:
CLASS_PROTOTYPE( rvVehicleWalker );
rvVehicleWalker ( void );
void Think ( void );
void Spawn ( void );
void Save ( idSaveGame *savefile ) const;
void Restore ( idRestoreGame *savefile );
virtual void UpdateState ( void );
virtual void SetInput ( int position, const usercmd_t& cmd, const idAngles& newAngles );
const char* stopAnimName;
virtual bool FindClearExitPoint ( int pos, idVec3& origin, idMat3& axis ) const;
private:
void HandleStrafing ( void );
stateResult_t Frame_ForwardRight ( int );
stateResult_t Frame_ForwardLeft ( int );
stateResult_t Frame_BackwardRight ( int );
stateResult_t Frame_BackwardLeft ( int );
stateResult_t State_Wait_OnlineAnim ( const stateParms_t& parms );
stateResult_t State_Idle ( const stateParms_t& parms );
stateResult_t State_IdleThink ( const stateParms_t& parms );
stateResult_t State_IdleOffline ( const stateParms_t& parms );
stateResult_t State_Offline ( const stateParms_t& parms );
stateResult_t State_Online ( const stateParms_t& parms );
stateResult_t State_ForwardStart ( const stateParms_t& parms );
stateResult_t State_Forward ( const stateParms_t& parms );
stateResult_t State_BackwardStart ( const stateParms_t& parms );
stateResult_t State_Backward ( const stateParms_t& parms );
stateResult_t State_Stop ( const stateParms_t& parms );
stateResult_t State_Turn ( const stateParms_t& parms );
stateResult_t State_TurnThink ( const stateParms_t& parms );
stateResult_t State_ScriptedAnim ( const stateParms_t& parms );
void Event_ScriptedAnim ( const char* animname, int blendFrames, bool loop, bool endWithIdle );
void Event_ScriptedDone ( void );
void Event_ScriptedStop ( void );
CLASS_STATES_PROTOTYPE ( rvVehicleWalker );
};
CLASS_DECLARATION( rvVehicleAnimated, rvVehicleWalker )
EVENT( AI_ScriptedAnim, rvVehicleWalker::Event_ScriptedAnim )
EVENT( AI_ScriptedDone, rvVehicleWalker::Event_ScriptedDone )
EVENT( AI_ScriptedStop, rvVehicleWalker::Event_ScriptedStop )
END_CLASS
/*
================
rvVehicleWalker::rvVehicleWalker
================
*/
rvVehicleWalker::rvVehicleWalker ( void ) {
stopAnimName = "";
}
/*
================
rvVehicleWalker::Think
================
*/
void rvVehicleWalker::Think ( void ) {
rvVehicleAnimated::Think();
if ( !HasDrivers() || IsStalled() ) {
return;
}
idVec3 delta;
animator.GetDelta( gameLocal.time - gameLocal.GetMSec(), gameLocal.time, delta );
if ( delta.LengthSqr() > 0.1f ) {
gameLocal.RadiusDamage( GetOrigin(), this, this, this, this, spawnArgs.GetString( "def_stompDamage", "damage_Smallexplosion" ) );
}
}
/*
================
rvVehicleWalker::Spawn
================
*/
void rvVehicleWalker::Spawn ( void ) {
SetAnimState ( ANIMCHANNEL_LEGS, "State_IdleOffline", 0 );
}
/*
================
rvVehicleWalker::Save
================
*/
void rvVehicleWalker::Save ( idSaveGame *savefile ) const {
savefile->WriteString( stopAnimName );
}
/*
================
rvVehicleWalker::Restore
================
*/
void rvVehicleWalker::Restore ( idRestoreGame *savefile ) {
//twhitaker: I just happened to see this, while going through this code which I originally wrote (at 3am or so).
//TODO: fix this. Make stopAnimName an idStr?
idStr str;
savefile->ReadString( str );
stopAnimName = str;
}
/*
================
rvVehicleWalker::UpdateState
================
*/
void rvVehicleWalker::UpdateState ( void ) {
rvVehiclePosition& pos = positions[0];
usercmd_t& cmd = pos.mInputCmd;
vfl.driver = pos.IsOccupied();
vfl.forward = (vfl.driver && cmd.forwardmove > 0);
vfl.backward = (vfl.driver && cmd.forwardmove < 0);
vfl.right = (vfl.driver && cmd.rightmove < 0);
vfl.left = (vfl.driver && cmd.rightmove > 0);
vfl.strafe = (vfl.driver && cmd.buttons & BUTTON_STRAFE );
if ( g_vehicleMode.GetInteger() != 0 ) {
vfl.strafe = !vfl.strafe;
}
}
/*
================
rvVehicleWalker::SetInput
================
*/
void rvVehicleWalker::SetInput ( int position, const usercmd_t& cmd, const idAngles& newAngles ) {
usercmd_t* pcmd = const_cast<usercmd_t*>( &cmd );
pcmd->rightmove *= -1;
GetPosition(position)->SetInput ( cmd, newAngles );
}
/*
================
rvVehicleWalker::HandleStrafing
================
*/
void rvVehicleWalker::HandleStrafing ( void ) {
if ( vfl.right ) {
additionalDelta -= spawnArgs.GetVector( "strafe_delta", "0 0 1.2" );
}
if ( vfl.left ) {
additionalDelta += spawnArgs.GetVector( "strafe_delta", "0 0 1.2" );
}
}
// mekberg: overloaded this because physics bounds code is significantly different
/*
=====================
rvVehicleWalker::FindClearExitPoint
=====================
*/
// FIXME: this whole function could be cleaned up
bool rvVehicleWalker::FindClearExitPoint( int pos, idVec3& origin, idMat3& axis ) const {
trace_t trace;
const rvVehiclePosition* position = GetPosition( pos );
idActor* driver = position->GetDriver();
idVec3 end;
idVec3 traceOffsetPoints[4];
const float error = 1.1f;
origin.Zero();
axis.Identity();
idMat3 driverAxis = driver->viewAxis;
idVec3 driverOrigin = driver->GetPhysics()->GetOrigin();
idMat3 vehicleAxis = position->GetEyeAxis();
idVec3 vehicleOrigin = GetPhysics()->GetOrigin();
idBounds driverBounds( driver->GetPhysics()->GetBounds() );
idBounds vehicleBounds( GetPhysics()->GetBounds() );
idBounds driverAbsBounds;
idBounds vehicleAbsBounds;
vehicleAbsBounds.FromTransformedBounds( vehicleBounds, vehicleOrigin, GetPhysics()->GetAxis() );
if( position->fl.driverVisible ) {
// May want to do this even if the driver isn't visible
if( position->mExitPosOffset.LengthSqr() > VECTOR_EPSILON ) {
axis = GetPhysics()->GetAxis() * position->mExitAxisOffset;
origin = vehicleOrigin + position->mExitPosOffset * axis;
} else {
origin = driverOrigin;
axis = (driver->IsBoundTo(this)) ? vehicleAxis : driverAxis;
}
return true;
}
// Build list
// FIXME: try and find a cleaner way to do this
traceOffsetPoints[ 0 ] = vehicleBounds.FindVectorToEdge( vehicleAxis[ 1 ] ) - driverBounds.FindVectorToEdge( -vehicleAxis[ 1 ] );
traceOffsetPoints[ 1 ] = vehicleBounds.FindVectorToEdge( -vehicleAxis[ 1 ] ) - driverBounds.FindVectorToEdge( vehicleAxis[ 1 ] );
traceOffsetPoints[ 2 ] = vehicleBounds.FindVectorToEdge( vehicleAxis[ 0 ] ) - driverBounds.FindVectorToEdge( -vehicleAxis[ 0 ] );
traceOffsetPoints[ 3 ] = vehicleBounds.FindVectorToEdge( -vehicleAxis[ 0 ] ) - driverBounds.FindVectorToEdge( vehicleAxis[ 0 ] );
for( int ix = 0; ix < 4; ++ix ) {
//Try all four sides and on top if need be
end = vehicleOrigin + traceOffsetPoints[ ix ] * error;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.Translation( this, trace, vehicleOrigin, end, driver->GetPhysics()->GetClipModel(), driverAxis, driver->GetPhysics()->GetClipMask(), this, driver );
// RAVEN END
driverAbsBounds.FromTransformedBounds( driverBounds, trace.endpos, driverAxis );
if( trace.fraction > 0.0f && !driverAbsBounds.IntersectsBounds(vehicleAbsBounds) ) {
origin = trace.endpos;
axis = vehicleAxis;
return true;
}
}
return false;
}
/*
===============================================================================
States
===============================================================================
*/
CLASS_STATES_DECLARATION ( rvVehicleWalker )
STATE ( "ForwardLeft", rvVehicleWalker::Frame_ForwardLeft )
STATE ( "ForwardRight", rvVehicleWalker::Frame_ForwardRight )
STATE ( "BackwardLeft", rvVehicleWalker::Frame_BackwardLeft )
STATE ( "BackwardRight", rvVehicleWalker::Frame_BackwardRight )
STATE ( "Wait_OnlineAnim", rvVehicleWalker::State_Wait_OnlineAnim )
STATE ( "State_Idle", rvVehicleWalker::State_Idle )
STATE ( "State_IdleThink", rvVehicleWalker::State_IdleThink )
STATE ( "State_IdleOffline", rvVehicleWalker::State_IdleOffline )
STATE ( "State_Offline", rvVehicleWalker::State_Offline )
STATE ( "State_Online", rvVehicleWalker::State_Online )
STATE ( "State_ForwardStart", rvVehicleWalker::State_ForwardStart )
STATE ( "State_Forward", rvVehicleWalker::State_Forward )
STATE ( "State_BackwardStart", rvVehicleWalker::State_BackwardStart )
STATE ( "State_Backward", rvVehicleWalker::State_Backward )
STATE ( "State_Stop", rvVehicleWalker::State_Stop )
STATE ( "State_Turn", rvVehicleWalker::State_Turn )
STATE ( "State_TurnThink", rvVehicleWalker::State_TurnThink )
STATE ( "State_ScriptedAnim", rvVehicleWalker::State_ScriptedAnim )
END_CLASS_STATES
/*
================
rvVehicleWalker::State_IdleOffline
================
*/
stateResult_t rvVehicleWalker::State_IdleOffline ( const stateParms_t& parms ) {
vfl.frozen = true;
PlayCycle ( ANIMCHANNEL_LEGS, "idle_offline", parms.blendFrames );
PostAnimState ( ANIMCHANNEL_LEGS, "Wait_Driver", 2 );
PostAnimState ( ANIMCHANNEL_LEGS, "State_Online", 2 );
return SRESULT_DONE;
}
/*
================
rvVehicleWalker::State_Online
================
*/
stateResult_t rvVehicleWalker::State_Online ( const stateParms_t& parms ) {
vfl.frozen = false;
PlayAnim ( ANIMCHANNEL_LEGS, "start", parms.blendFrames );
PostAnimState ( ANIMCHANNEL_LEGS, "Wait_OnlineAnim", 4 );
PostAnimState ( ANIMCHANNEL_LEGS, "State_Idle", 4 );
return SRESULT_DONE;
}
/*
================
rvVehicleWalker::State_Offline
================
*/
stateResult_t rvVehicleWalker::State_Offline ( const stateParms_t& parms ) {
PlayAnim ( ANIMCHANNEL_LEGS, "stop", parms.blendFrames );
PostAnimState ( ANIMCHANNEL_LEGS, "Wait_TorsoAnim", 4 );
PostAnimState ( ANIMCHANNEL_LEGS, "State_IdleOffline", 4 );
return SRESULT_DONE;
}
/*
================
rvVehicleWalker::State_Idle
================
*/
stateResult_t rvVehicleWalker::State_Idle ( const stateParms_t& parms ) {
if ( SRESULT_WAIT != State_IdleThink ( parms ) ) {
return SRESULT_DONE;
}
PlayCycle( ANIMCHANNEL_LEGS, "idle", parms.blendFrames );
PostAnimState ( ANIMCHANNEL_LEGS, "State_IdleThink", 2 );
return SRESULT_DONE;
}
/*
================
rvVehicleWalker::State_Idle
================
*/
stateResult_t rvVehicleWalker::State_IdleThink ( const stateParms_t& parms ) {
if ( !vfl.driver || vfl.stalled ) {
PostAnimState ( ANIMCHANNEL_LEGS, "State_Offline", parms.blendFrames );
return SRESULT_DONE;
}
if ( IsMovementEnabled ( ) ) {
if ( vfl.forward ) {
PostAnimState ( ANIMCHANNEL_LEGS, "State_ForwardStart", 2 );
return SRESULT_DONE;
}
if ( vfl.backward ) {
PostAnimState ( ANIMCHANNEL_LEGS, "State_BackwardStart", 2 );
return SRESULT_DONE;
}
if ( vfl.right || vfl.left ) {
PostAnimState ( ANIMCHANNEL_LEGS, "State_Turn", 2 );
return SRESULT_DONE;
}
}
return SRESULT_WAIT;
}
/*
================
rvVehicleWalker::State_ForwardStart
================
*/
stateResult_t rvVehicleWalker::State_ForwardStart ( const stateParms_t& parms ) {
PlayAnim ( ANIMCHANNEL_LEGS, "forward_start", 2 );
PostAnimState ( ANIMCHANNEL_LEGS, "Wait_TorsoAnim", 2 );
PostAnimState ( ANIMCHANNEL_LEGS, "State_Forward", 2 );
return SRESULT_DONE;
}
stateResult_t rvVehicleWalker::State_Forward ( const stateParms_t& parms ) {
// If not moving anymore by the time we get here just play the stop anim
if ( !vfl.forward ) {
stopAnimName = "forward_stop_leftmid";
SetAnimState ( ANIMCHANNEL_LEGS, "State_Stop", 4 );
return SRESULT_DONE;
}
if ( !parms.stage ) {
PlayCycle( ANIMCHANNEL_LEGS, "forward", 2 );
return SRESULT_STAGE(parms.stage + 1);
}
if ( AnimDone( ANIMCHANNEL_LEGS, 2 ) ) {
return SRESULT_DONE;
}
HandleStrafing();
return SRESULT_WAIT;
}
/*
================
rvVehicleWalker::State_BackwardStart
================
*/
stateResult_t rvVehicleWalker::State_BackwardStart ( const stateParms_t& parms ) {
PlayAnim ( ANIMCHANNEL_LEGS, "backward_start", parms.blendFrames );
PostAnimState ( ANIMCHANNEL_LEGS, "Wait_TorsoAnim", 2 );
PostAnimState ( ANIMCHANNEL_LEGS, "State_Backward", 2 );
return SRESULT_DONE;
}
stateResult_t rvVehicleWalker::State_Backward ( const stateParms_t& parms ) {
// If not moving anymore by the time we get here just play the stop anim
if ( !vfl.backward ) {
stopAnimName = "backward_stop_leftmid";
SetAnimState ( ANIMCHANNEL_LEGS, "State_Stop", 2 );
return SRESULT_DONE;
}
if ( !parms.stage ) {
PlayCycle( ANIMCHANNEL_LEGS, "backward", 2 );
return SRESULT_STAGE(parms.stage + 1);
}
if ( AnimDone( ANIMCHANNEL_LEGS, 2 ) ) {
return SRESULT_DONE;
}
HandleStrafing();
return SRESULT_WAIT;
}
/*
================
rvVehicleWalker::State_Stop
================
*/
stateResult_t rvVehicleWalker::State_Stop ( const stateParms_t& parms ) {
PlayAnim ( ANIMCHANNEL_LEGS, stopAnimName, parms.blendFrames );
PostAnimState ( ANIMCHANNEL_LEGS, "Wait_TorsoAnim", 2 );
PostAnimState ( ANIMCHANNEL_LEGS, "State_Idle", 2 );
return SRESULT_DONE;
}
/*
================
rvVehicleWalker::State_Turn
================
*/
stateResult_t rvVehicleWalker::State_Turn ( const stateParms_t& parms ) {
if ( vfl.left ) {
PlayAnim ( ANIMCHANNEL_LEGS, "turn_left", parms.blendFrames );
} else if ( vfl.right ) {
PlayAnim ( ANIMCHANNEL_LEGS, "turn_right", parms.blendFrames );
} else {
PostAnimState ( ANIMCHANNEL_LEGS, "State_Idle", parms.blendFrames );
return SRESULT_DONE;
}
PostAnimState ( ANIMCHANNEL_LEGS, "State_TurnThink", 16 );
return SRESULT_DONE;
}
/*
================
rvVehicleWalker::State_TurnThink
================
*/
stateResult_t rvVehicleWalker::State_TurnThink ( const stateParms_t& parms ) {
// If moving again bail on the turn, reguardless of whether its in mid animation
if ( vfl.forward || vfl.backward ) {
PostAnimState ( ANIMCHANNEL_LEGS, "State_Idle", parms.blendFrames );
return SRESULT_DONE;
}
// If the animation is done then repeat
if ( AnimDone ( ANIMCHANNEL_LEGS, 8 ) ){
PostAnimState ( ANIMCHANNEL_LEGS, "State_Turn", 8 );
return SRESULT_DONE;
}
HandleStrafing();
return SRESULT_WAIT;
}
/*
================
rvVehicleWalker::Frame_ForwardLeft
================
*/
stateResult_t rvVehicleWalker::Frame_ForwardLeft ( int ) {
if ( !vfl.forward ) {
stopAnimName = "forward_stop_left";
SetAnimState ( ANIMCHANNEL_LEGS, "State_Stop", 2 );
}
return SRESULT_OK;
}
/*
================
rvVehicleWalker::Frame_ForwardRight
================
*/
stateResult_t rvVehicleWalker::Frame_ForwardRight ( int ) {
if ( !vfl.forward ) {
stopAnimName = "forward_stop_right";
SetAnimState ( ANIMCHANNEL_LEGS, "State_Stop", 2 );
}
return SRESULT_OK;
}
/*
================
rvVehicleWalker::Frame_BackwardLeft
================
*/
stateResult_t rvVehicleWalker::Frame_BackwardLeft ( int ) {
if ( !vfl.backward ) {
stopAnimName = "backward_stop_left";
SetAnimState ( ANIMCHANNEL_LEGS, "State_Stop", 2 );
}
return SRESULT_OK;
}
/*
================
rvVehicleWalker::Frame_BackwardRight
================
*/
stateResult_t rvVehicleWalker::Frame_BackwardRight ( int ) {
if ( !vfl.backward ) {
stopAnimName = "backward_stop_right";
SetAnimState ( ANIMCHANNEL_LEGS, "State_Stop", 2 );
}
return SRESULT_OK;
}
/*
================
rvVehicleWalker::State_Wait_OnlineAnim
================
*/
stateResult_t rvVehicleWalker::State_Wait_OnlineAnim ( const stateParms_t& parms ) {
if ( !AnimDone ( ANIMCHANNEL_LEGS, parms.blendFrames ) && vfl.driver ) {
return SRESULT_WAIT;
}
return SRESULT_DONE;
}
/*
================
rvVehicleWalker::State_ScriptedAnim
================
*/
stateResult_t rvVehicleWalker::State_ScriptedAnim ( const stateParms_t& parms ) {
if ( !AnimDone ( ANIMCHANNEL_LEGS, parms.blendFrames ) ) {
return SRESULT_WAIT;
}
Event_ScriptedStop();
return SRESULT_DONE;
}
/*
================
rvVehicleWalker::Event_ScriptedAnim
================
*/
void rvVehicleWalker::Event_ScriptedAnim( const char* animname, int blendFrames, bool loop, bool endWithIdle ) {
vfl.endWithIdle = endWithIdle;
if ( loop ) {
PlayCycle ( ANIMCHANNEL_LEGS, animname, blendFrames );
} else {
PlayAnim ( ANIMCHANNEL_LEGS, animname, blendFrames );
}
SetAnimState ( ANIMCHANNEL_LEGS, "State_ScriptedAnim", blendFrames );
vfl.scripted = true;
}
/*
================
rvVehicleWalker::Event_ScriptedDone
================
*/
void rvVehicleWalker::Event_ScriptedDone( void ) {
idThread::ReturnInt( !vfl.scripted );
}
/*
================
rvVehicleWalker::Event_ScriptedStop
================
*/
void rvVehicleWalker::Event_ScriptedStop( void ) {
vfl.scripted = false;
if ( vfl.endWithIdle ) {
SetAnimState ( ANIMCHANNEL_LEGS, "State_Idle", 2 );
}
}