2178 lines
49 KiB
C++
2178 lines
49 KiB
C++
//
|
|
// $Logfile:: /Code/DLLs/game/actor_locomotion.cpp $
|
|
// $Revision:: 47 $
|
|
// $Author:: Sketcher $
|
|
// $Date:: 4/26/03 4:24p $
|
|
//
|
|
// Copyright (C) 2001 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
//
|
|
|
|
#include "_pch_cpp.h"
|
|
#include "actor_locomotion.h"
|
|
#include "player.h"
|
|
#include "object.h"
|
|
|
|
//======================================
|
|
// LocomotionController Implementation
|
|
//=====================================
|
|
|
|
|
|
//
|
|
// Name: LocomotionController()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Default Constructor
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
LocomotionController::LocomotionController()
|
|
{
|
|
// Should always use other constructor
|
|
gi.Error( ERR_FATAL, "LocomotionController::LocomotionController -- Default Constructor Called" );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: LocomotionController()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Default Constructor
|
|
//
|
|
// Parameters: Actor *actor
|
|
//
|
|
// Returns: None
|
|
//
|
|
LocomotionController::LocomotionController( Actor *actor )
|
|
{
|
|
//Initialize our Actor
|
|
if ( actor )
|
|
act = actor;
|
|
else
|
|
gi.Error( ERR_DROP, "LocomotionController::LocomotionController -- actor is NULL" );
|
|
|
|
_init();
|
|
}
|
|
|
|
|
|
//
|
|
// Name: ~LocomotionController()
|
|
// Class: LocomotionController()
|
|
//
|
|
// Description: Destructor
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
LocomotionController::~LocomotionController()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Name: Begin()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Begins a session of locomotion
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
void LocomotionController::Begin()
|
|
{
|
|
_chase.Begin( *act );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: Evaluate()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Evaluation Iteration for the locomotion session
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
void LocomotionController::Evaluate()
|
|
{
|
|
_chase.Evaluate( *act );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: End()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Ends a locomotion session
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
void LocomotionController::End()
|
|
{
|
|
_chase.End( *act );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: SetMovementStyle()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Sets the _movementStyle
|
|
//
|
|
// Parameters: MovementStyle Style -- The style to set
|
|
//
|
|
// Returns: None
|
|
//
|
|
void LocomotionController::SetMovementStyle( MovementStyle style )
|
|
{
|
|
_movementStyle = style;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: GetMovementStyle()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Gets the _movementStyle
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: _movementStyle
|
|
//
|
|
MovementStyle LocomotionController::GetMovementStyle()
|
|
{
|
|
return _movementStyle;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: DoArchive()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Sets the Actor pointer and calls Archive()
|
|
//
|
|
// Parameters: Archiver &arc -- The archiver object
|
|
// Actor *actor -- The actor
|
|
//
|
|
// Returns: None
|
|
//
|
|
void LocomotionController::DoArchive( Archiver &arc , Actor *actor )
|
|
{
|
|
Archive( arc );
|
|
if ( actor )
|
|
act = actor;
|
|
else
|
|
gi.Error( ERR_FATAL, "LocomotionController::DoArchive -- actor is NULL" );
|
|
}
|
|
|
|
//
|
|
// Name: Archive()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Archives the class
|
|
//
|
|
// Parameters: Archiver &arc -- The archiver object
|
|
//
|
|
// Returns: None
|
|
//
|
|
void LocomotionController::Archive( Archiver &arc )
|
|
{
|
|
ArchiveEnum( _movementStyle, MovementStyle );
|
|
arc.ArchiveObject( &_chase );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _init()
|
|
// Class: LocomotionController
|
|
//
|
|
// Description: Initializes the class
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
void LocomotionController::_init()
|
|
{
|
|
_movementStyle = MOVEMENT_STYLE_NONE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//======================================
|
|
// MovementSubsystem Implementation
|
|
//=====================================
|
|
|
|
// Init Static Vars
|
|
Vector MovementSubsystem::_step = Vector( 0.0f, 0.0f, STEPSIZE );
|
|
|
|
|
|
//
|
|
// Name: MovementSubsystem()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Default Constructor
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
MovementSubsystem::MovementSubsystem()
|
|
{
|
|
// Should always use other constructor
|
|
gi.Error( ERR_FATAL, "MovementSubsystem::MovementSubsystem -- Default Constructor Called" );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: MovementSubsystem()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Constructor
|
|
//
|
|
// Parameters: Actor *actor
|
|
//
|
|
// Returns: None
|
|
//
|
|
MovementSubsystem::MovementSubsystem( Actor *actor )
|
|
{
|
|
//Initialize our Actor
|
|
if ( actor )
|
|
act = actor;
|
|
else
|
|
gi.Error( ERR_DROP, "MovementSubsystem::MovementSubsystem -- actor is NULL" );
|
|
|
|
_init();
|
|
}
|
|
|
|
|
|
//
|
|
// Name: ~MovementSubsystem()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Destructor
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
MovementSubsystem::~MovementSubsystem()
|
|
{
|
|
if ( _path )
|
|
{
|
|
delete _path;
|
|
_path = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Name: CanMoveTo()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Pass through to _canMoveSimplePath()
|
|
//
|
|
// Parameters: Vector &pos -- The location to check
|
|
//
|
|
// Returns: True or False
|
|
//
|
|
qboolean MovementSubsystem::CanMoveTo ( const Vector &pos )
|
|
{
|
|
return _canMoveSimplePath( act->mins, act->maxs , pos );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: CanWalkTowardsPoint()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Tests to see if Actor can move in the desired direction a small amount
|
|
//
|
|
// Parameters: Vector direction -- Desired direction of movement
|
|
//
|
|
// Returns: whether the direction is clear and has a floor
|
|
//
|
|
|
|
bool MovementSubsystem::CanWalkTowardsPoint( const Vector &goalPoint, const int mask )
|
|
{
|
|
Vector step( goalPoint - act->origin );
|
|
const float distance = Vector::Distance( goalPoint, act->origin );
|
|
step.normalize();
|
|
step *= min( distance, max ( 64.0f, Vector::Distance( act->origin, act->last_origin ) ) );
|
|
return CanWalkTo( act->origin + step, 0, ENTITYNUM_NONE, mask ) == 1;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: CanWalkTo()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Pass through to CanWalkToFrom()
|
|
//
|
|
// Parameters: Vector &pos -- The location to check
|
|
// float bounding_box_extra -- Additional volume to the bounding box
|
|
// int entnum -- entity number
|
|
//
|
|
// Returns:
|
|
//
|
|
qboolean MovementSubsystem::CanWalkTo( const Vector &pos, float bounding_box_extra, int entnum, const int mask )
|
|
{
|
|
return CanWalkToFrom( act->origin, pos, bounding_box_extra, entnum, mask );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: CanWalkToFrom()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Checks if a location is reachable
|
|
//
|
|
// Parameters: const Vector &origin -- Starting position
|
|
// const Vector &pos -- Ending position
|
|
// float bounding_box_extra -- Extra volume added to the bounding box
|
|
// int entnum -- Entity number
|
|
//
|
|
// Returns: True or False
|
|
//
|
|
qboolean MovementSubsystem::CanWalkToFrom ( const Vector &origin, const Vector &pos, float bounding_box_extra, int entnum, const int mask )
|
|
{
|
|
Vector real_pos;
|
|
Vector test_mins;
|
|
Vector test_maxs;
|
|
|
|
|
|
// Setup bounding box
|
|
test_mins = act->mins;
|
|
test_maxs = act->maxs;
|
|
|
|
test_mins.x -= bounding_box_extra;
|
|
test_mins.y -= bounding_box_extra;
|
|
|
|
test_maxs.x += bounding_box_extra;
|
|
test_maxs.y += bounding_box_extra;
|
|
|
|
|
|
// Calculate the real position we have to get to
|
|
if ( entnum != ENTITYNUM_NONE )
|
|
real_pos = _getRealDestinationPosition( pos );
|
|
else
|
|
real_pos = pos;
|
|
|
|
Vector startPos;
|
|
startPos = act->origin;
|
|
startPos.z += 15;
|
|
|
|
// Do simple CanWalkTo if specified
|
|
|
|
if ( act->GetActorFlag( ACTOR_FLAG_SIMPLE_PATHFINDING ) )
|
|
return _canMoveSimplePath( test_mins, test_maxs, real_pos );
|
|
|
|
// Check to make sure the ground is good each step of the move
|
|
return _checkHaveGroundEachStep( origin, real_pos, test_mins, test_maxs, mask );
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Name: Acclerate()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Applies steering force to the actor's movement
|
|
//
|
|
// Parameters: const Vector &original_steering -- steering force from the steering classes
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::Accelerate( const Vector &original_steering )
|
|
{
|
|
Vector steering = original_steering;
|
|
Vector newDir = _movedir.toAngles();
|
|
|
|
|
|
// If we didn't move last frame ( stopped ) then we can just set our moveDir to where we
|
|
// want to go, however, if we are moving, we want to adjust our turning based on our turnspeed
|
|
// so that we can't just turn 90 degrees at a snap
|
|
|
|
if ( !act->GetActorFlag(ACTOR_FLAG_HAVE_MOVED) )
|
|
{
|
|
/* if ( steering.y > _turnspeed )
|
|
steering.y = _turnspeed;
|
|
else if ( steering.y < -_turnspeed )
|
|
steering.y = -_turnspeed;
|
|
*/
|
|
}
|
|
|
|
if( steering.x )
|
|
steering.x = steering.x;
|
|
|
|
if( steering.y )
|
|
newDir.y += steering.y;
|
|
|
|
newDir.EulerNormalize();
|
|
|
|
|
|
if ( act->animate->frame_delta.x > 4.0f )
|
|
{
|
|
// make him lean into the turn a bit
|
|
newDir.z = _movespeed * ( 0.4f / 320.0f ) * steering.y;
|
|
|
|
if ( ( act->flags & FL_FLY ) || ( ( act->flags & FL_SWIM ) && act->waterlevel > 0 ) )
|
|
newDir.z = bound( act->angles.z, -2.0f, 2.0f );
|
|
else
|
|
newDir.z = bound( act->angles.z, -5.0f, 5.0f );
|
|
}
|
|
else
|
|
newDir.z = 0.0f;
|
|
|
|
/*
|
|
if ( _movingBackwards )
|
|
newDir[YAW] = AngleNormalize180( newDir[YAW] - 180.0f );
|
|
*/
|
|
|
|
newDir.AngleVectors( &_movedir );
|
|
|
|
//Set my turn angles;
|
|
Vector newAng = _animdir.toAngles();
|
|
|
|
float newDirYaw;
|
|
if ( act->bind_info && act->bind_info->bindmaster )
|
|
{
|
|
float orientation[3][3];
|
|
float parentOrientation[3][3];
|
|
float mat[3][3];
|
|
AnglesToAxis( newDir, mat );
|
|
Vector parentAngles;
|
|
|
|
MatrixToEulerAngles( act->bind_info->bindmaster->orientation, parentAngles );
|
|
parentAngles[ YAW ] = AngleNormalize180( -parentAngles[ YAW ] );
|
|
AnglesToAxis( parentAngles, parentOrientation );
|
|
|
|
R_ConcatRotations( mat, parentOrientation, orientation );
|
|
MatrixToEulerAngles( orientation, newDir );
|
|
|
|
|
|
AnglesToAxis( newAng, mat );
|
|
R_ConcatRotations( mat, parentOrientation, orientation );
|
|
MatrixToEulerAngles( orientation, newAng );
|
|
}
|
|
|
|
newDirYaw = AngleNormalize180(newDir.yaw() );
|
|
float newAngYaw = AngleNormalize180(newAng.yaw() );
|
|
|
|
|
|
if ( _movingBackwards )
|
|
newDirYaw = AngleNormalize180( newDirYaw - 180.0f );
|
|
|
|
|
|
float AngleDiff = newDirYaw - newAngYaw;
|
|
AngleDiff = AngleNormalize180(AngleDiff);
|
|
|
|
//First check if we're close enough just to set our angles
|
|
if ( ( ( AngleDiff >= 0.0f ) && ( AngleDiff < _turnspeed ) ) || ( ( AngleDiff <= 0.0f ) && ( AngleDiff > -_turnspeed ) ) )
|
|
{
|
|
newAng[YAW] = AngleNormalize360(newDirYaw);
|
|
|
|
if ( _faceEnemy )
|
|
{
|
|
Entity *currentEnemy;
|
|
currentEnemy = act->enemyManager->GetCurrentEnemy();
|
|
|
|
if ( !currentEnemy )
|
|
{
|
|
act->enemyManager->FindHighestHateEnemy();
|
|
currentEnemy = act->enemyManager->GetCurrentEnemy();
|
|
}
|
|
|
|
if ( currentEnemy )
|
|
{
|
|
Vector selfToEnemy;
|
|
selfToEnemy = currentEnemy->origin - act->origin;
|
|
selfToEnemy = selfToEnemy.toAngles();
|
|
selfToEnemy[PITCH] = 0.0f;
|
|
|
|
newAng = selfToEnemy;
|
|
}
|
|
}
|
|
|
|
if ( _adjustAnimDir )
|
|
act->setAngles( newAng );
|
|
return;
|
|
}
|
|
|
|
//Update our angles
|
|
if ( AngleDiff > 0.0f )
|
|
newAng[YAW] = AngleNormalize360( newAng[YAW] += _turnspeed );
|
|
else
|
|
newAng[YAW] = AngleNormalize360( newAng[YAW] -= _turnspeed );
|
|
|
|
|
|
|
|
/*
|
|
if ( _fliplegs )
|
|
newAng[YAW] += 180;
|
|
*/
|
|
|
|
|
|
|
|
if ( _movingBackwards )
|
|
newAng[YAW] = AngleNormalize180( newDir[YAW] - 180.0f );
|
|
|
|
|
|
if ( _faceEnemy )
|
|
{
|
|
Entity *currentEnemy;
|
|
currentEnemy = act->enemyManager->GetCurrentEnemy();
|
|
|
|
if ( !currentEnemy )
|
|
{
|
|
act->enemyManager->FindHighestHateEnemy();
|
|
currentEnemy = act->enemyManager->GetCurrentEnemy();
|
|
}
|
|
|
|
if ( currentEnemy )
|
|
{
|
|
Vector selfToEnemy;
|
|
selfToEnemy = currentEnemy->origin - act->origin;
|
|
selfToEnemy = selfToEnemy.toAngles();
|
|
selfToEnemy[PITCH] = 0.0f;
|
|
|
|
newAng = selfToEnemy;
|
|
}
|
|
}
|
|
|
|
if ( _adjustAnimDir )
|
|
act->setAngles( newAng );
|
|
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// Name: CalcMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Calculates the _move Vector
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//--------------------------------------------------------------
|
|
void MovementSubsystem::CalcMove ( void )
|
|
{
|
|
|
|
// Use total_delta from the animation if we can, but
|
|
// over-ride it if we set a forward speed ( When the
|
|
// new animation stuff is availiable )
|
|
_totallen = 0;
|
|
|
|
if ( act->total_delta != vec_zero )
|
|
_totallen = act->total_delta.length();
|
|
|
|
if ( _forwardspeed )
|
|
{
|
|
_totallen = _forwardspeed;
|
|
}
|
|
|
|
if ( _movementType == MOVEMENT_TYPE_ANIM )
|
|
{
|
|
MatrixTransformVector( act->total_delta, act->orientation, _move );
|
|
}
|
|
else
|
|
{
|
|
_movedir.normalize();
|
|
_move = _movedir;
|
|
_move *= _totallen;
|
|
}
|
|
|
|
// If we are not allowed to move, make sure we set the length of our
|
|
// movement vector to 0.0
|
|
if ( act->movetype == MOVETYPE_NONE )
|
|
_move *= 0.0f;
|
|
|
|
act->total_delta = vec_zero;
|
|
_animdir = act->orientation[0];
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Name: WaterMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Attempts to move based on being in water
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: stepmoveresult_t
|
|
//
|
|
stepmoveresult_t MovementSubsystem::WaterMove ( void )
|
|
{
|
|
Vector oldorg;
|
|
Vector neworg;
|
|
trace_t trace;
|
|
int oldwater;
|
|
|
|
if ( ( _totallen <= 0.01f ) || ( _move == vec_zero ) )
|
|
{
|
|
return STEPMOVE_OK;
|
|
}
|
|
|
|
// try the move
|
|
oldorg = act->origin;
|
|
neworg = act->origin + _move;
|
|
|
|
trace = G_Trace( oldorg, act->mins, act->maxs, neworg, act, act->edict->clipmask, false, "Actor::WaterMove 1" );
|
|
if ( trace.fraction == 0.0f )
|
|
return STEPMOVE_STUCK;
|
|
|
|
oldwater = act->waterlevel;
|
|
|
|
act->setOrigin( trace.endpos );
|
|
|
|
CheckWater();
|
|
|
|
// swim monsters don't exit water voluntarily
|
|
if ( ( oldwater > 1 ) && ( act->waterlevel < 2 ) )
|
|
{
|
|
act->waterlevel = oldwater;
|
|
act->setOrigin( oldorg );
|
|
return STEPMOVE_STUCK;
|
|
}
|
|
|
|
return STEPMOVE_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: AirMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Attempts to move based on being in the air
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: stepmoveresult_t
|
|
//
|
|
stepmoveresult_t MovementSubsystem::AirMove ( void )
|
|
{
|
|
Vector oldorg;
|
|
Vector neworg;
|
|
trace_t trace;
|
|
int oldwater;
|
|
|
|
if ( ( _totallen <= 0.01f ) || ( _move == vec_zero ) )
|
|
{
|
|
return STEPMOVE_OK;
|
|
}
|
|
|
|
// try the move
|
|
oldorg = act->origin;
|
|
neworg = act->origin + _move;
|
|
|
|
trace = G_Trace( oldorg, act->mins, act->maxs, neworg, act, act->edict->clipmask, false, "Actor::AirMove 1" );
|
|
if ( trace.fraction < 0.0001f )
|
|
{
|
|
return STEPMOVE_BLOCKED_BY_WATER;
|
|
}
|
|
|
|
oldwater = act->waterlevel;
|
|
|
|
act->setOrigin( trace.endpos );
|
|
|
|
if ( !act->GetActorFlag( ACTOR_FLAG_IGNORE_WATER ) )
|
|
{
|
|
CheckWater();
|
|
|
|
// fly monsters don't enter water voluntarily
|
|
if ( !oldwater && act->waterlevel )
|
|
{
|
|
act->waterlevel = oldwater;
|
|
act->setOrigin( oldorg );
|
|
return STEPMOVE_STUCK;
|
|
}
|
|
}
|
|
|
|
return STEPMOVE_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: TryMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Tries to move based on being on the ground
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: stepmoveresult_t
|
|
//
|
|
stepmoveresult_t MovementSubsystem::IsMoveValid( trace_t &horizontalTrace, trace_t &verticalTrace, const Vector &moveBegin, const Vector &moveEnd )
|
|
{
|
|
horizontalTrace = act->Trace( moveBegin, moveEnd, "MovementSubsystem::IsMoveValid" );
|
|
|
|
if ( horizontalTrace.startsolid )
|
|
{
|
|
horizontalTrace = G_Trace( moveBegin, act->mins, act->maxs, moveBegin + _move, act, act->edict->clipmask, false, "MovementSubsystem::IsMoveValid2" );
|
|
}
|
|
|
|
if ( horizontalTrace.startsolid || ( horizontalTrace.fraction < 0.0001f ) )
|
|
return STEPMOVE_STUCK;
|
|
|
|
// See if we are blocked by a door
|
|
if ( _isBlockedByDoor(horizontalTrace) )
|
|
return STEPMOVE_BLOCKED_BY_DOOR;
|
|
|
|
// Don't step down an extra step if gravity is turned off for this actor right now or the actor is dead
|
|
if ( !act->GetActorFlag( ACTOR_FLAG_USE_GRAVITY ) || (act->gravity == 0) || act->deadflag )
|
|
{
|
|
return _noGravityTryMove( horizontalTrace.endpos, verticalTrace );
|
|
}
|
|
|
|
stepmoveresult_t result = STEPMOVE_OK;
|
|
if ( horizontalTrace.fraction < 1.0f )
|
|
{
|
|
if ( horizontalTrace.entityNum == ENTITYNUM_WORLD )
|
|
{
|
|
result = STEPMOVE_BLOCKED_BY_WORLD;
|
|
}
|
|
else
|
|
{
|
|
result = STEPMOVE_BLOCKED_BY_ENTITY;
|
|
_blockingEntity = horizontalTrace.ent->entity;
|
|
//if ( _blockingEntity->isSubclassOf( Player ) )
|
|
// act->InContext( "blockedbyplayer" );
|
|
|
|
act->AddStateFlag(STATE_FLAG_BLOCKED_BY_ENTITY);
|
|
}
|
|
}
|
|
|
|
// Phase 2: Send a trace down from the end of the first trace to try and found ground -- and thus
|
|
// what should be our new origin
|
|
Vector traceBegin( horizontalTrace.endpos );
|
|
Vector traceEnd( traceBegin - ( _step * 2.0f ) );
|
|
|
|
verticalTrace = G_Trace( traceBegin, act->mins, act->maxs, traceEnd, act, act->edict->clipmask, false, "MovementSubsystem::IsMoveValid3" );
|
|
// Check if we are blocked by a fall
|
|
if ( _isBlockedByFall( verticalTrace ) )
|
|
return STEPMOVE_BLOCKED_BY_FALL;
|
|
|
|
|
|
// If the feet width is set make sure the actor's feet are really on the ground
|
|
if ( act->feet_width )
|
|
{
|
|
verticalTrace = _feetWidthTrace( verticalTrace.endpos , verticalTrace.endpos - ( _step * 3.0f ) , verticalTrace.endpos, act->edict->clipmask );
|
|
|
|
// Check if we are blocked by a fall
|
|
if ( _isBlockedByFall( verticalTrace ) )
|
|
return STEPMOVE_BLOCKED_BY_FALL;
|
|
|
|
}
|
|
|
|
/* Experiment to deal with uneven floor geometry
|
|
if ( result == STEPMOVE_OK )
|
|
{
|
|
if ( !_checkHaveGroundEachStep ( moveBegin , moveEnd , act->mins , act->maxs ))
|
|
return STEPMOVE_BLOCKED_BY_FALL;
|
|
}
|
|
*/
|
|
|
|
return result;
|
|
}
|
|
//
|
|
// Name: TryMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Tries to move based on being on the ground
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: stepmoveresult_t
|
|
//
|
|
stepmoveresult_t MovementSubsystem::TryMove ( void )
|
|
{
|
|
|
|
// See if we should bother doing any movement
|
|
if ( !_shouldTryMove() )
|
|
return STEPMOVE_OK;
|
|
|
|
|
|
// Phase 1: Send a trace out from our origin ( plus stepsize ) along our move Vector.
|
|
Vector moveBegin = act->origin;
|
|
|
|
trace_t horizontalTrace;
|
|
trace_t verticalTrace;
|
|
verticalTrace.ent = 0 ;
|
|
stepmoveresult_t returnValue = IsMoveValid( horizontalTrace, verticalTrace, moveBegin, moveBegin + _move );
|
|
if ( returnValue == STEPMOVE_OK )
|
|
{
|
|
// The move is ok
|
|
act->setOrigin( verticalTrace.endpos );
|
|
|
|
// Save the ground information now so we don't have to do it later
|
|
if ( verticalTrace.fraction < 1.0f )
|
|
_saveGroundInformation( verticalTrace );
|
|
|
|
|
|
act->flags &= ~FL_PARTIALGROUND; // set in ActorThink
|
|
CheckWater();
|
|
|
|
}
|
|
else if ( returnValue == STEPMOVE_BLOCKED_BY_FALL )
|
|
{
|
|
act->AddStateFlag( STATE_FLAG_STUCK );
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: SimpleMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Move with no collision and no ground following
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: stepmoveresult_t
|
|
//
|
|
stepmoveresult_t MovementSubsystem::SimpleMove( const bool stickToGround )
|
|
{
|
|
Vector newPosition ( act->origin + _move );
|
|
if ( stickToGround )
|
|
{
|
|
Vector traceBegin( newPosition + _step );
|
|
Vector traceEnd( traceBegin - ( _step * 2.0f ) );
|
|
|
|
trace_t trace = G_Trace( traceBegin, act->mins, act->maxs, traceEnd, act, MASK_PATHSOLID, false, "MovementSubsystem::SimpleMove" );
|
|
newPosition = trace.endpos;
|
|
}
|
|
act->setOrigin( newPosition );
|
|
return STEPMOVE_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: Push()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Moves the actor based on the push direction
|
|
//
|
|
// Parameters: const Vector &dir -- The direction of the push
|
|
//
|
|
// Returns: True or False
|
|
//
|
|
qboolean MovementSubsystem::Push ( const Vector &dir )
|
|
{
|
|
Vector oldorg;
|
|
Vector neworg;
|
|
trace_t trace;
|
|
int i;
|
|
|
|
|
|
if ( !act->GetActorFlag( ACTOR_FLAG_PUSHABLE ) )
|
|
return false;
|
|
|
|
for( i = 0 ; i < 5 ; i++ )
|
|
{
|
|
oldorg = act->origin + _step;
|
|
neworg = oldorg + dir;
|
|
|
|
trace = G_Trace( oldorg, act->mins, act->maxs, neworg, act, act->edict->clipmask, false, "Actor::Push 1" );
|
|
|
|
if ( trace.startsolid )
|
|
{
|
|
oldorg = act->origin;
|
|
neworg = oldorg + dir;
|
|
|
|
trace = G_Trace( oldorg, act->mins, act->maxs, neworg, act, act->edict->clipmask, false, "Actor::Push 2" );
|
|
|
|
if ( trace.startsolid )
|
|
return false;
|
|
}
|
|
|
|
if ( trace.ent && trace.ent->entity->isSubclassOf( Actor ) )
|
|
{
|
|
Actor *actor = (Actor *) trace.ent->entity;
|
|
actor->Push( dir );
|
|
continue;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if ( trace.endpos == oldorg )
|
|
return false;
|
|
|
|
// Step down to a step height below our original height to account for gravity
|
|
|
|
oldorg = trace.endpos;
|
|
|
|
if ( act->flags & FL_FLY )
|
|
neworg = oldorg - _step;
|
|
else
|
|
neworg = oldorg - _step * 2.0f;
|
|
|
|
trace = G_Trace( oldorg, act->mins, act->maxs, neworg, act, act->edict->clipmask, false, "Actor::Push 3" );
|
|
|
|
act->setOrigin( trace.endpos );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: CheckWater()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets the waterlevel
|
|
// Waterlevel 1 means actor's feet are in the water
|
|
// Waterlevel 2 means actor's waist is in the water
|
|
// Waterlevel 3 means actor's eyes are in the water -- Important
|
|
// because at level 3, we start to choke.
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::CheckWater( void )
|
|
{
|
|
Vector sample[3];
|
|
int cont;
|
|
|
|
//
|
|
// get waterlevel and type
|
|
//
|
|
act->waterlevel = 0;
|
|
act->watertype = 0;
|
|
|
|
sample[ 0 ] = act->origin;
|
|
sample[ 2 ] = act->EyePosition();
|
|
sample[ 1 ] = ( sample[ 0 ] + sample[ 2 ] ) * 0.5f;
|
|
|
|
cont = gi.pointcontents( sample[ 0 ], 0 );
|
|
|
|
if ( ( cont != -1 ) && ( cont & MASK_WATER ) )
|
|
{
|
|
act->watertype = cont;
|
|
act->waterlevel = 1;
|
|
cont = gi.pointcontents( sample[ 2 ], 0 );
|
|
if (cont & MASK_WATER)
|
|
{
|
|
act->waterlevel = 3;
|
|
}
|
|
else
|
|
{
|
|
cont = gi.pointcontents( sample[ 1 ], 0 );
|
|
if (cont & MASK_WATER)
|
|
{
|
|
act->waterlevel = 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Name: JumpTo()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Jumps the actor to the specified target
|
|
//
|
|
// Parameters: const Vector &targ -- The target
|
|
// float speed -- Jump speed
|
|
// float vertical_speed -- Vertical speed
|
|
//
|
|
// Returns: float traveltime
|
|
//
|
|
float MovementSubsystem::JumpTo( const Vector &targetPosition, const Angle angle )
|
|
{
|
|
Trajectory trajectory( act->origin, targetPosition, angle, act->gravity * -sv_currentGravity->value );
|
|
act->velocity = trajectory.GetInitialVelocity();
|
|
|
|
Vector directionXY( targetPosition - act->origin );
|
|
directionXY.z = 0.0f;
|
|
act->setAngles( directionXY.toAngles() );
|
|
_movedir = directionXY;
|
|
|
|
act->groundentity = NULL;
|
|
return trajectory.GetTravelTime();
|
|
}
|
|
|
|
|
|
//
|
|
// Name: JumpTo()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Wrapper for JumpTo
|
|
//
|
|
// Parameters: PathNode *goal -- Jump target
|
|
// float speed -- Jump speed
|
|
// float vertical_speed -- Vertical jump speed
|
|
//
|
|
// Returns: float JumpTo result
|
|
//
|
|
float MovementSubsystem::JumpTo ( PathNode *goal, const Angle angle )
|
|
{
|
|
if ( goal )
|
|
return JumpTo( goal->origin, angle );
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Name: JumpTo()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Wrapper for JumpTo
|
|
//
|
|
// Parameters: Entity *goal -- Jump target
|
|
// float speed -- Jump speed
|
|
// float vertical_speed -- Vertical jump speed
|
|
//
|
|
// Returns: float JumpTo result
|
|
//
|
|
float MovementSubsystem::JumpTo ( Entity *goal, const Angle angle )
|
|
{
|
|
if ( goal )
|
|
return JumpTo( goal->origin, angle );
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Name: SteerTowardsPoint()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Basic Seek/Intercept Steering
|
|
//
|
|
// Parameters: const Vector &targetPosition - Point to steer towards
|
|
// const Vector &targetVelocity - current velocity used to predict future position of target point
|
|
// const Vector &moveDirection - the actors current direction of movement
|
|
// const float maxSpeed - maximum speed of actor
|
|
//
|
|
// Returns: Euler angles containing rotation that will point actor in a direction to intercept the target
|
|
//
|
|
// x - predictedPosition
|
|
// A - myPosition( moveDirection is towards the point of the "A")
|
|
// + - centerOfTurn
|
|
//
|
|
//
|
|
// _x
|
|
// /
|
|
// |
|
|
// A +
|
|
//
|
|
//
|
|
//
|
|
const Vector MovementSubsystem::SteerTowardsPoint( const Vector &targetPosition, const Vector &targetVelocity, const Vector &moveDirection, const float maxSpeed, const bool adjustSpeed)
|
|
{
|
|
assert(act != NULL);
|
|
Vector myPosition (act->origin);
|
|
Vector predictedPosition = targetPosition + targetVelocity * ( Vector::Distance(targetPosition, myPosition) / maxSpeed );
|
|
Vector desiredDirection = predictedPosition - myPosition;
|
|
|
|
Vector newSteeringForce = Vector::AnglesBetween(desiredDirection, moveDirection);
|
|
newSteeringForce[ROLL]=0.0f;
|
|
newSteeringForce.EulerNormalize();
|
|
|
|
if ( adjustSpeed )
|
|
{
|
|
const float currentSpeed = _forwardspeed;
|
|
const float turnRate = _turnspeed;
|
|
const float turnRadius = currentSpeed / turnRate;
|
|
|
|
Vector right;
|
|
right.CrossProduct( moveDirection, Vector( 0, 0, 1 ) );
|
|
const Vector centerOfTurn( myPosition + ( right * DotProduct( right, desiredDirection ) ) );
|
|
|
|
const float forwardComponent = DotProduct( desiredDirection, moveDirection );
|
|
const float rightComponent = DotProduct( desiredDirection, right );
|
|
|
|
if ( Vector::DistanceXY( centerOfTurn, predictedPosition ) < turnRadius )
|
|
{
|
|
const float newTurnRadius = ( ( rightComponent * rightComponent ) + ( forwardComponent * forwardComponent ) ) / ( 2.0f * rightComponent );
|
|
_forwardspeed = 2.0f * turnRate * newTurnRadius;
|
|
}
|
|
}
|
|
return newSteeringForce;
|
|
}
|
|
|
|
//
|
|
// Name: _canMoveSimplePath()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Checks if an Actor can do a simple move to the specified destination
|
|
//
|
|
// Parameters: const Vector &mins -- mins of the actor
|
|
// const Vector &maxs -- maxs of the actor
|
|
// const Vector &pos -- target destination
|
|
//
|
|
// Returns: True or False
|
|
//
|
|
qboolean MovementSubsystem::_canMoveSimplePath( const Vector &mins, const Vector &maxs , const Vector &pos ) const
|
|
{
|
|
trace_t trace = act->Trace( act->origin + _step, pos + _step, "Actor::_canMoveSimplePath" );
|
|
if ( trace.fraction == 1.0f )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _getRealDestinationPosition()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: uses the mins and maxs to calculate the actual final position
|
|
//
|
|
// Parameters: const Vector &pos
|
|
//
|
|
// Returns: Vector target destination
|
|
//
|
|
Vector MovementSubsystem::_getRealDestinationPosition( const Vector &pos ) const
|
|
{
|
|
Vector temp_dir = pos - act->origin;
|
|
float temp_length = temp_dir.length();
|
|
|
|
temp_length -= sqrt( act->maxs.x * act->maxs.x * 2.0f ) + 5.0f;
|
|
|
|
if ( temp_length < 0.0f )
|
|
temp_length = 0.0f;
|
|
|
|
temp_dir.normalize();
|
|
temp_dir *= temp_length;
|
|
|
|
return act->origin + temp_dir;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _feetWidthTrace()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Does a trace based off of the actor's feet -- to help prevent corner
|
|
// of the boundingbox Wile E Coyote problems.
|
|
//
|
|
// Parameters: const Vector ¤tLoc -- Starting position
|
|
// const Vector &bottom -- The end point of the trace
|
|
// const Vector &endPos -- The end position being copied over
|
|
//
|
|
// Returns: trace_t trace
|
|
//
|
|
trace_t MovementSubsystem::_feetWidthTrace( const Vector ¤tLoc, const Vector &bottom, const Vector &endPos, const int mask ) const
|
|
{
|
|
trace_t trace;
|
|
Vector temp_mins;
|
|
Vector temp_maxs;
|
|
Vector saved_endpos;
|
|
|
|
temp_mins[0] = -act->feet_width;
|
|
temp_mins[1] = -act->feet_width;
|
|
temp_mins[2] = act->mins[2];
|
|
|
|
temp_maxs[0] = act->feet_width;
|
|
temp_maxs[1] = act->feet_width;
|
|
temp_maxs[2] = act->maxs[2];
|
|
|
|
trace = G_Trace( currentLoc, temp_mins, temp_maxs, bottom, act, mask, false, "Actor::CanWalkTo2" );
|
|
|
|
saved_endpos = endPos;
|
|
saved_endpos.copyTo( trace.endpos );
|
|
|
|
return trace;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _getTraceStep()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Calculates the trace step size
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: float trace_step
|
|
//
|
|
float MovementSubsystem::_getTraceStep() const
|
|
{
|
|
// Find the step amount
|
|
float trace_step = act->maxs[0] * 2.0f; //was 2.0
|
|
|
|
// Make sure trace_step is divisible by 8
|
|
trace_step = ( (int)(trace_step / 8.0f ) ) * 8.0f;
|
|
|
|
if ( trace_step < 8.0f )
|
|
trace_step = 8.0f;
|
|
|
|
return trace_step;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _checkHaveGroundEachStep()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Checks each step required to traverse the vector, and checks if there is ground to step on
|
|
//
|
|
// Parameters: const Vector &start -- starting position
|
|
// const Vector &end -- target destination
|
|
// const Vector &test_mins -- mins used in the check
|
|
// const Vector &test_maxs -- maxs used in the check
|
|
//
|
|
//
|
|
// Returns: True or False
|
|
//
|
|
qboolean MovementSubsystem::_checkHaveGroundEachStep( const Vector &start, const Vector &end, const Vector &test_mins, const Vector &test_maxs, const int mask ) const
|
|
{
|
|
int clipMask = act->edict->clipmask;
|
|
if ( mask >= 0 )
|
|
{
|
|
clipMask = mask;
|
|
}
|
|
|
|
// Find the vector to walk
|
|
Vector dir = end - start;
|
|
float length = dir.length();
|
|
dir.normalize();
|
|
|
|
// Get Trace Steps;
|
|
float trace_step = _getTraceStep();
|
|
float small_trace_step = 8;
|
|
|
|
// Test each step to see if the ground is not too far below
|
|
float last_height = end[2];
|
|
|
|
Vector last_loc = Vector::Identity();
|
|
// Vector last_loc = start;
|
|
for( float i = 0 ; i < length ; i += trace_step )
|
|
{
|
|
Vector current_loc = start + ( dir * i );
|
|
current_loc[2] = last_height + STEPSIZE;
|
|
|
|
Vector bottom = current_loc;
|
|
|
|
if ( !act->GetActorFlag( ACTOR_FLAG_ALLOW_FALL ) )
|
|
bottom[2] = last_height - STEPSIZE;
|
|
else
|
|
bottom[2] = last_height - 1000.0f;
|
|
|
|
trace_t trace = G_Trace( current_loc, test_mins, test_maxs, bottom, act, clipMask, false, "Actor::CanWalkTo1" );
|
|
|
|
if ( !( ( trace.fraction == 1.0f ) || trace.startsolid || trace.allsolid ) && act->feet_width )
|
|
trace = _feetWidthTrace( current_loc , bottom , trace.endpos, clipMask );
|
|
|
|
if ( ( trace.fraction == 1.0f ) || trace.startsolid || trace.allsolid )
|
|
{
|
|
// The wide one failed, do the small traces for this segment
|
|
if ( ( i == 0 ) || ( trace_step == small_trace_step ) )
|
|
return false;
|
|
|
|
for( float j = small_trace_step ; j <= trace_step ; j += small_trace_step )
|
|
{
|
|
current_loc = last_loc + ( dir * j );
|
|
current_loc[2] = last_height + STEPSIZE;
|
|
|
|
bottom = current_loc;
|
|
bottom[2] = last_height - STEPSIZE;
|
|
|
|
trace = G_Trace( current_loc, test_mins, test_maxs, bottom, act, clipMask, false, "Actor::CanWalkTo3" );
|
|
|
|
if ( ( trace.fraction == 1.0f ) || trace.startsolid || trace.allsolid ||
|
|
( trace.ent && trace.ent->entity->isSubclassOf( Sentient ) && !act->GetActorFlag( ACTOR_FLAG_CAN_WALK_ON_OTHERS ) ) )
|
|
return false;
|
|
|
|
if ( act->feet_width )
|
|
trace = _feetWidthTrace( current_loc , bottom , trace.endpos, clipMask );
|
|
|
|
last_height = trace.endpos[2];
|
|
}
|
|
}
|
|
|
|
last_height = trace.endpos[2];
|
|
last_loc = current_loc;
|
|
}
|
|
|
|
if ( ( last_height > ( end.z + ( STEPSIZE * 2.0f ) ) ) || ( last_height < ( end.z - ( STEPSIZE * 2.0f ) ) ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _isBlockedByDoor()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Checks if the actor is blocked by a door
|
|
//
|
|
// Parameters: trace_t &trace -- the trace
|
|
//
|
|
// Returns: True or False
|
|
//
|
|
qboolean MovementSubsystem::_isBlockedByDoor( trace_t &trace ) const
|
|
{
|
|
Door *door;
|
|
|
|
if ( !act->deadflag && trace.ent )
|
|
{
|
|
// Check if we hit a door
|
|
|
|
if ( trace.ent->entity->isSubclassOf( Door ) )
|
|
{
|
|
door = ( Door * )trace.ent->entity;
|
|
if ( !door->locked && !door->isOpen() )
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _noGravityTryMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Traces to see if actor can be positioned in space, without worrying if
|
|
// ground is underneath -- Should be used by flying creatures
|
|
//
|
|
// Parameters: const Vector &oldorg -- The origin before trying the move
|
|
//
|
|
// Returns: stepmoveresult_t
|
|
//
|
|
stepmoveresult_t MovementSubsystem::_noGravityTryMove( const Vector &oldorg, trace_t &verticalTrace ) const
|
|
{
|
|
Vector neworg = oldorg - _step;
|
|
//trace_t newTrace;
|
|
|
|
// try stepping down
|
|
verticalTrace = G_Trace( oldorg, act->mins, act->maxs, neworg, act, act->edict->clipmask, false, "Actor::TryMove 2" );
|
|
|
|
if ( verticalTrace.startsolid )
|
|
return STEPMOVE_STUCK;
|
|
|
|
|
|
//act->setOrigin( verticalTrace.endpos );
|
|
|
|
return STEPMOVE_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _isBlockedByFall()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Checks if the Actor is blocked by fall
|
|
//
|
|
// Parameters: trace_t &trace
|
|
//
|
|
// Returns: True or False
|
|
//
|
|
qboolean MovementSubsystem::_isBlockedByFall( trace_t &trace ) const
|
|
{
|
|
// Determine if we should allow the actor to fall
|
|
qboolean allow_fall = _allowFall();
|
|
|
|
// We never want to step on a flying creature, even if we are allowed to
|
|
// step on sentients in general. This is because, if we were to step on a flying
|
|
// creature, and the flying creature moved, then we might fall, where had we not
|
|
// stepped on the flying creature we would still be safe and sound
|
|
if ( trace.ent && ( trace.ent->entity->flags & FL_FLY ) && !allow_fall )
|
|
return true;
|
|
|
|
// Don't voluntarilty step on sentients
|
|
if ( trace.ent && trace.ent->entity->isSubclassOf( Sentient ) &&
|
|
!allow_fall && !act->GetActorFlag( ACTOR_FLAG_CAN_WALK_ON_OTHERS ) )
|
|
return true;
|
|
|
|
// Check if the move places us on solid ground
|
|
if ( trace.fraction == 1.0f )
|
|
{
|
|
if ( allow_fall )
|
|
{
|
|
// don't let guys get stuck standing on other guys
|
|
// if monster had the ground pulled out, go ahead and fall
|
|
act->groundentity = NULL;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// walked off an edge
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Make sure ground is not too slopped or we will just slide off
|
|
|
|
if ( ( trace.plane.normal[ 2 ] <= 0.7f ) && !allow_fall )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Name: _allowFall()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Checks if the actor is allowed to fall
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: True or False
|
|
//
|
|
qboolean MovementSubsystem::_allowFall() const
|
|
{
|
|
if ( ( act->flags & FL_PARTIALGROUND ) ||
|
|
( act->groundentity && act->groundentity->entity && ( act->groundentity->entity->isSubclassOf( Sentient ) ) ) ||
|
|
( act->GetActorFlag( ACTOR_FLAG_ALLOW_FALL ) ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _shouldTryMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Checks if the Actor should even try to move
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: True or False
|
|
//
|
|
qboolean MovementSubsystem::_shouldTryMove() const
|
|
{
|
|
// We have a velocity so movement of the actor is done in physics
|
|
if ( ( act->velocity != vec_zero ) && !act->deadflag )
|
|
return false;
|
|
|
|
if ( ( _totallen <= 0.01f ) || ( _move == vec_zero ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _saveGroundInformation()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Saves trace information on the actor
|
|
//
|
|
// Parameters: trace_t &trace
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::_saveGroundInformation(trace_t &trace)
|
|
{
|
|
act->groundentity = trace.ent;
|
|
act->groundplane = trace.plane;
|
|
act->groundcontents = trace.contents;
|
|
act->last_origin = act->origin;
|
|
act->SetActorFlag( ACTOR_FLAG_HAVE_MOVED, true );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: _init()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Initializes the class
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::_init()
|
|
{
|
|
_lastmove = STEPMOVE_OK;
|
|
_path = NULL;
|
|
_turnspeed = TURN_SPEED;
|
|
_startpos = act->origin;
|
|
_forwardspeed = 0;
|
|
_divedir = vec_zero;
|
|
act->angles.AngleVectors( &_movedir );
|
|
|
|
//Set our internal step var
|
|
_step = Vector( 0.0f, 0.0f, STEPSIZE );
|
|
_movespeed = 1.0f;
|
|
|
|
_fliplegs = false;
|
|
_movingBackwards = false;
|
|
_faceEnemy = false;
|
|
_adjustAnimDir = true;
|
|
_useCodeDrivenSpeed = false;
|
|
|
|
_movementType = MOVEMENT_TYPE_NORMAL;
|
|
_stickToGround = true;
|
|
CheckWater();
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Name: setMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets the _move
|
|
//
|
|
// Parameters: const Vector &move -- The move to set
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setMove( const Vector &move )
|
|
{
|
|
_move = move;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _move
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: Vector _move
|
|
//
|
|
Vector MovementSubsystem::getMove()
|
|
{
|
|
return _move;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Name: setMoveDir()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _moveDir
|
|
//
|
|
// Parameters: const Vector &moveDir -- The move dir to set
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setMoveDir( const Vector &moveDir )
|
|
{
|
|
_movedir = moveDir;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getMoveDir()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _movedir
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: Vector _movedir
|
|
//
|
|
Vector MovementSubsystem::getMoveDir()
|
|
{
|
|
return _movedir;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Name: setMoveVelocity()
|
|
// Class: const Vector &moveVelocity
|
|
//
|
|
// Description: Sets _movevelocity
|
|
//
|
|
// Parameters: const Vector &moveVelocity -- the move velocity to set
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setMoveVelocity( const Vector &moveVelocity )
|
|
{
|
|
_movevelocity = moveVelocity;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getMoveVelocity()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _movevelocity
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
Vector MovementSubsystem::getMoveVelocity()
|
|
{
|
|
return _movevelocity;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: setAnimDir()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _animdir
|
|
//
|
|
// Parameters: const Vector &animDir
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setAnimDir( const Vector &animDir )
|
|
{
|
|
_animdir = animDir;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getAnimDir()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _animdir
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: Vector _animdir
|
|
//
|
|
Vector MovementSubsystem::getAnimDir()
|
|
{
|
|
return _animdir;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: setDiveDir()
|
|
// Class: const Vector &diveDir
|
|
//
|
|
// Description: Sets _divedir
|
|
//
|
|
// Parameters: const Vector &diveDir -- the dive dir to set
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setDiveDir( const Vector &diveDir )
|
|
{
|
|
_divedir = diveDir;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getDiveDir()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: returns _divedir
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: Vector _divedir
|
|
//
|
|
Vector MovementSubsystem::getDiveDir()
|
|
{
|
|
return _divedir;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: setStartPos()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _startpos
|
|
//
|
|
// Parameters: const Vector &startPos -- the start pos to set
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setStartPos( const Vector &startPos )
|
|
{
|
|
_startpos = startPos;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getStartPos
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _startpos
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: Vector _startpos
|
|
//
|
|
Vector MovementSubsystem::getStartPos()
|
|
{
|
|
return _startpos;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Name: setTotalLen()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: sets _totallen
|
|
//
|
|
// Parameters: float totallen -- the total len to set
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setTotalLen( float totalLen )
|
|
{
|
|
_totallen = totalLen;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getTotalLen()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _totallen
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: float _totallen
|
|
//
|
|
float MovementSubsystem::getTotalLen()
|
|
{
|
|
return _totallen;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: setTurnSpeed()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _turnspeed
|
|
//
|
|
// Parameters: float turnSpeed -- the turn speed to set
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setTurnSpeed( float turnSpeed )
|
|
{
|
|
_turnspeed = turnSpeed;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getTurnSpeed()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _turnspeed
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: float _turnspeed
|
|
//
|
|
float MovementSubsystem::getTurnSpeed()
|
|
{
|
|
return _turnspeed;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: setForwardSpeed()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _forwardspeed
|
|
//
|
|
// Parameters: float forwardSpeed
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setForwardSpeed( float forwardSpeed )
|
|
{
|
|
_forwardspeed = forwardSpeed;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getForwardSpeed()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _forwardspeed
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: float _forwardspeed
|
|
//
|
|
float MovementSubsystem::getForwardSpeed()
|
|
{
|
|
return _forwardspeed;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Name: setMoveSpeed()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _movespeed
|
|
//
|
|
// Parameters: float moveSpeed
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setMoveSpeed( float moveSpeed )
|
|
{
|
|
_movespeed = moveSpeed;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getMoveSpeed()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _movespeed
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: float _movespeed
|
|
//
|
|
float MovementSubsystem::getMoveSpeed()
|
|
{
|
|
return _movespeed;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: setFlipLegs()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _fliplegs
|
|
//
|
|
// Parameters: qboolean flip
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setFlipLegs( qboolean flip )
|
|
{
|
|
_fliplegs = flip;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getFlipLegs()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _fliplegs
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: qboolean _fliplegs
|
|
//
|
|
qboolean MovementSubsystem::getFlipLegs()
|
|
{
|
|
return _fliplegs;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: flipLegs()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Turns the actor around, and allows for backward movement
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::flipLegs()
|
|
{
|
|
Vector Angles;
|
|
|
|
_fliplegs = !_fliplegs;
|
|
|
|
|
|
if ( _fliplegs )
|
|
_movingBackwards = true;
|
|
else
|
|
_movingBackwards = false;
|
|
|
|
|
|
Angles = _animdir;
|
|
Angles = Angles.toAngles();
|
|
|
|
Angles[PITCH] = AngleNormalize180( Angles[PITCH] );
|
|
Angles[ROLL] = AngleNormalize180( Angles[ROLL] );
|
|
|
|
Angles[YAW] = AngleNormalize180( Angles[YAW] + 180.0f );
|
|
|
|
Angles.AngleVectors( &_animdir );
|
|
|
|
//act->setAngles( Angles );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Name: setMovingBackwards()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _movingBackwards
|
|
//
|
|
// Parameters: qboolean backwards
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setMovingBackwards( qboolean backwards )
|
|
{
|
|
_movingBackwards = backwards;
|
|
}
|
|
|
|
|
|
void MovementSubsystem::setFaceEnemy( bool faceEnemy )
|
|
{
|
|
_faceEnemy = faceEnemy;
|
|
}
|
|
|
|
void MovementSubsystem::setAdjustAnimDir( bool adjustAnimDir )
|
|
{
|
|
_adjustAnimDir = adjustAnimDir;
|
|
}
|
|
|
|
bool MovementSubsystem::getAdjustAnimDir()
|
|
{
|
|
return _adjustAnimDir;
|
|
}
|
|
|
|
//
|
|
// Name: getMovingBackwards
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _movingBackwards
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
qboolean MovementSubsystem::getMovingBackwards()
|
|
{
|
|
return _movingBackwards;
|
|
}
|
|
|
|
bool MovementSubsystem::getFaceEnemy()
|
|
{
|
|
return _faceEnemy;
|
|
}
|
|
|
|
//
|
|
// Name: setPath()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _path
|
|
//
|
|
// Parameters: Path *path
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setPath( Path *path )
|
|
{
|
|
if ( _path && ( _path != path ) )
|
|
delete _path;
|
|
|
|
_path = path;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getPath()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _path
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: Path *_path
|
|
//
|
|
Path* MovementSubsystem::getPath()
|
|
{
|
|
return _path;
|
|
}
|
|
|
|
//
|
|
// Name: setStep()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _step
|
|
//
|
|
// Parameters: const Vector & lastMove
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setStep( const Vector &step )
|
|
{
|
|
_step = step;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getLastMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _step
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: stepmoveresult_t _lastmove
|
|
//
|
|
const Vector & MovementSubsystem::getStep() const
|
|
{
|
|
return _step;
|
|
}
|
|
|
|
//
|
|
// Name: setLastMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets _lastmove
|
|
//
|
|
// Parameters: stepmoveresult_t lastMove
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setLastMove( stepmoveresult_t lastMove )
|
|
{
|
|
_lastmove = lastMove;
|
|
}
|
|
|
|
|
|
//
|
|
// Name: getLastMove()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns _lastmove
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: stepmoveresult_t _lastmove
|
|
//
|
|
stepmoveresult_t MovementSubsystem::getLastMove()
|
|
{
|
|
return _lastmove;
|
|
}
|
|
|
|
//
|
|
// Name: setMovementType()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets the _movementType
|
|
//
|
|
// Parameters: MovementType_t mType -- the type to set
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::setMovementType( MovementType_t mType )
|
|
{
|
|
_movementType = mType;
|
|
}
|
|
|
|
//
|
|
// Name: getMovementType()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Returns the _movementType
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: MovementType_t _movementType;
|
|
//
|
|
MovementType_t MovementSubsystem::getMovementType()
|
|
{
|
|
return _movementType;
|
|
}
|
|
|
|
void MovementSubsystem::SetStickToGround( const bool stick )
|
|
{
|
|
_stickToGround = stick;
|
|
}
|
|
|
|
const bool MovementSubsystem::GetStickToGround( void ) const
|
|
{
|
|
return _stickToGround;
|
|
}
|
|
|
|
Entity* MovementSubsystem::getBlockingEntity()
|
|
{
|
|
return _blockingEntity;
|
|
}
|
|
|
|
void MovementSubsystem::clearBlockingEntity()
|
|
{
|
|
_blockingEntity = NULL;
|
|
}
|
|
|
|
//
|
|
// Name: DoArchive()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Sets up the class for archiving
|
|
//
|
|
// Parameters: Archiver &arc -- the archiving object
|
|
// Actor *actor -- the class' actor pointer
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::DoArchive( Archiver &arc , Actor *actor )
|
|
{
|
|
Archive( arc );
|
|
if ( actor )
|
|
act = actor;
|
|
else
|
|
gi.Error( ERR_FATAL, "MovementSubsystem::DoArchive -- actor is NULL" );
|
|
}
|
|
|
|
|
|
//
|
|
// Name: Archive()
|
|
// Class: MovementSubsystem
|
|
//
|
|
// Description: Archives the class
|
|
//
|
|
// Parameters: Archiver &arc -- the archiving object
|
|
//
|
|
// Returns: None
|
|
//
|
|
void MovementSubsystem::Archive( Archiver &arc )
|
|
{
|
|
// Don't archive
|
|
//static Vector _step;
|
|
|
|
ArchiveEnum( _lastmove, stepmoveresult_t );
|
|
arc.ArchiveFloat( &_forwardspeed );
|
|
arc.ArchiveSafePointer( &_path );
|
|
arc.ArchiveVector( &_move );
|
|
arc.ArchiveVector( &_movedir );
|
|
arc.ArchiveFloat( &_movespeed );
|
|
arc.ArchiveVector( &_movevelocity );
|
|
arc.ArchiveFloat( &_totallen );
|
|
arc.ArchiveFloat( &_turnspeed );
|
|
arc.ArchiveVector( &_animdir );
|
|
arc.ArchiveVector( &_divedir );
|
|
arc.ArchiveVector( &_startpos );
|
|
arc.ArchiveBoolean( &_fliplegs );
|
|
arc.ArchiveBoolean( &_movingBackwards );
|
|
arc.ArchiveBool ( &_faceEnemy );
|
|
arc.ArchiveBool ( &_adjustAnimDir );
|
|
ArchiveEnum( _movementType, MovementType_t );
|
|
arc.ArchiveBool( &_stickToGround );
|
|
arc.ArchiveBool( &_useCodeDrivenSpeed );
|
|
arc.ArchiveSafePointer( &_blockingEntity );
|
|
}
|