📄 movemgr.cpp
字号:
#include "client_de.h"
#include "physics_lt.h"
#include "MoveMgr.h"
#include "BloodClientShell.h"
#include "SharedMovement.h"
#include "Commands.h"
#include "ClientServerShared.h"
#include "SharedDefs.h"
#include "ClientUtilities.h"
#define MIN_SWIM_ON_SURFACE_TIME 0.5f
#define SPECTATOR_ACCELERATION 100000.0f
#define LADDER_STOP_TIME 0.2f
#define SWIM_STOP_TIME 1.0f
#define DEFAULT_JUMPVEL 600.0f
// Values to use for acceleration & velocity
//DFLOAT gMoveAccel[6] = { 3300.0f, 3750.0f, 4200.0f, 4650.0f, 4950.0f, 5250.0f };
static DFLOAT fDragCoeff = 15.0f;
// Max velocity is gMoveAccel/fDragCoeff
class Pusher
{
public:
Pusher()
{
m_Link.m_pData = this;
}
DVector m_Pos;
float m_Radius;
float m_Delay; // How long before it starts actually pushing.
float m_TimeLeft; // Time left for this sphere.
float m_Strength;
DLink m_Link;
};
CMoveMgr::CMoveMgr(CBloodClientShell *pShell)
{
VEC_SET(m_WantedDims, 1, 1, 1);
m_nStillAnims = 0;
m_bSwimmingJump = DFALSE;
m_eLastContainerCode= CC_NOTHING;
m_nContainers = 0;
m_hObject = DNULL;
m_pClientDE = DNULL;
m_pClientShell = pShell;
dl_TieOff(&m_Pushers);
m_dwControlFlags = 0;
m_dwLastControlFlags= 0;
m_bMovementBlocked = DFALSE;
m_bForcedCrouch = DFALSE;
m_wLastChangeFlags = 0;
m_eLastSurface = SURFTYPE_UNKNOWN;
}
CMoveMgr::~CMoveMgr()
{
DLink *pCur, *pNext;
for(pCur=m_Pushers.m_pNext; pCur != &m_Pushers; pCur=pNext)
{
pNext = pCur->m_pNext;
delete (Pusher*)pCur->m_pData;
}
dl_TieOff(&m_Pushers);
}
DBOOL CMoveMgr::Init(ClientDE *pClientDE)
{
m_pClientDE = pClientDE;
m_pPhysicsLT = pClientDE->Physics();
// Init some defaults. These should NEVER get used because we don't
// have our object until the server sends the physics update.
m_fMoveVel = 0.0f;
m_fJumpVel = DEFAULT_JUMPVEL;
m_fSwimVel = DEFAULT_SWIM_VEL;
m_fLadderVel = DEFAULT_LADDER_VEL;
m_fFrictionCoeff = 0.0f;
m_fMoveMultiplier = 1.0f;
m_bBodyInLiquid = DFALSE;
m_bBodyOnLadder = DFALSE;
m_bBodyOnConveyor = DFALSE;
m_bOnGround = DTRUE;
m_nMouseStrafeFlags = 0;
m_bSwimmingOnSurface = DFALSE;
m_bCanSwimJump = DFALSE;
m_fLeashLen = 100.0f;
m_fBaseMoveAccel = 0.0f;
m_fMoveAccelMultiplier = 1.0f;
m_fJumpMultiplier = 1.0f;
VEC_INIT( m_vServerVelocity );
return DTRUE;
}
void CMoveMgr::UpdateAxisMovement(DBOOL bUseAxisForwardBackward, float fForwardBackward, float fForwardBackwardDeadZone,
DBOOL bUseAxisLeftRight, float fLeftRight, float fLeftRightDeadZone )
{
m_bUseAxisForwardBackward = bUseAxisForwardBackward;
m_fAxisForwardBackwardVel = fForwardBackward;
m_fAxisForwardBackwardDeadZone = fForwardBackwardDeadZone;
m_bUseAxisLeftRight = bUseAxisLeftRight;
m_fAxisLeftRightVel = fLeftRight;
m_fAxisLeftRightDeadZone = fLeftRightDeadZone;
}
void CMoveMgr::UpdateControlFlags()
{
// Clear control flags...
m_dwLastControlFlags = m_dwControlFlags;
m_dwControlFlags = 0;
// Make sure it's ok for us to move...
if (g_pBloodClientShell->IsDead()) return;
if (!(m_pClientShell->GetCDataFlags() & CDATA_CANMOVE)) return;
if (g_pBloodClientShell->IsWonkyNoMove()) return; // [blg] 01/13/99
// Determine what commands are currently on...
if (m_pClientDE->IsCommandOn(COMMAND_RUN) || m_pClientShell->GetCDataFlags() & CDATA_RUNLOCK)
{
m_dwControlFlags |= CTRLFLAG_RUN;
}
if (m_pClientDE->IsCommandOn(COMMAND_JUMP))
{
m_dwControlFlags |= CTRLFLAG_JUMP;
}
if (m_pClientDE->IsCommandOn(COMMAND_DUCK))
{
m_dwControlFlags |= CTRLFLAG_CROUCH;
}
if (m_pClientDE->IsCommandOn(COMMAND_FORWARD))
{
m_dwControlFlags |= CTRLFLAG_FORWARD;
}
if (m_pClientDE->IsCommandOn(COMMAND_BACKWARD))
{
m_dwControlFlags |= CTRLFLAG_BACKWARD;
}
if (m_pClientDE->IsCommandOn(COMMAND_LEFT))
{
m_dwControlFlags |= CTRLFLAG_LEFT;
}
if (m_pClientDE->IsCommandOn(COMMAND_RIGHT))
{
m_dwControlFlags |= CTRLFLAG_RIGHT;
}
if (m_pClientDE->IsCommandOn(COMMAND_STRAFE))
{
m_dwControlFlags |= CTRLFLAG_STRAFE;
}
if (m_pClientDE->IsCommandOn(COMMAND_STRAFERIGHT))
{
m_dwControlFlags |= CTRLFLAG_STRAFERIGHT;
}
if (m_pClientDE->IsCommandOn(COMMAND_STRAFELEFT))
{
m_dwControlFlags |= CTRLFLAG_STRAFELEFT;
}
if (m_pClientDE->IsCommandOn(COMMAND_FIRE))
{
m_dwControlFlags |= CTRLFLAG_FIRE;
}
if (m_pClientDE->IsCommandOn(COMMAND_ALTFIRE))
{
m_dwControlFlags |= CTRLFLAG_ALTFIRE;
}
if (m_pClientDE->IsCommandOn(COMMAND_GRAB))
{
m_dwControlFlags |= CTRLFLAG_GRAB;
}
if (m_pClientDE->IsCommandOn(COMMAND_TAUNT))
{
m_dwControlFlags |= CTRLFLAG_TAUNT;
}
}
void CMoveMgr::UpdateInLiquid(CContainerInfo *pInfo)
{
if(pInfo->m_bHidden)
return;
// If head is above water and standing on something, then don't inhibit movement.
DBOOL bHeadInLiquid = IsLiquid(m_pClientShell->GetCurContainerCode());
// Don't limit velocity if on the ground
if( !bHeadInLiquid && m_bOnGround )
return;
m_bBodyInLiquid = DTRUE;
// Do REAL friction dampening (i.e., actually change our velocity)...
DVector vVel;
m_pPhysicsLT->GetVelocity(m_hObject, &vVel);
DFLOAT fTimeDelta = m_FrameTime;
DVector vCurVel;
VEC_COPY(vCurVel, vVel);
if (VEC_MAG(vCurVel) > 1.0f)
{
DVector vDir;
VEC_COPY(vDir, vCurVel);
VEC_NORM(vDir);
DFLOAT fAdjust = m_FrameTime*(m_fSwimVel/SWIM_STOP_TIME);
VEC_MULSCALAR(vVel, vDir, fAdjust);
if (VEC_MAG(vVel) < VEC_MAG(vCurVel))
{
VEC_SUB(vVel, vCurVel, vVel);
}
else
{
VEC_INIT(vVel);
}
}
DVector curAccel;
m_pPhysicsLT->GetAcceleration(m_hObject, &curAccel);
// Handle floating around on the surface...
if (m_bSwimmingOnSurface)
{
DBOOL bMoving = ((VEC_MAG(curAccel) > 0.01f) || (VEC_MAG(vVel) > 0.01f));
// Disable gravity.
m_pClientDE->SetObjectFlags(m_hObject,
m_pClientDE->GetObjectFlags(m_hObject) & ~FLAG_GRAVITY);
if (bMoving) // Turn off y acceleration and velocity
{
if (vVel.y > 0.0f || curAccel.y > 0.0f)
{
vVel.y = 0.0f;
curAccel.y = 0.0f;
}
}
else // Pull us down if we're not moving (fast enough)
{
curAccel.y += pInfo->m_fGravity;
}
}
else if (IsLiquid(pInfo->m_ContainerCode))
{
m_pClientDE->SetObjectFlags(m_hObject,
m_pClientDE->GetObjectFlags(m_hObject) & ~FLAG_GRAVITY);
curAccel.y += pInfo->m_fGravity;
}
m_pPhysicsLT->SetVelocity(m_hObject, &vVel);
m_pPhysicsLT->SetAcceleration(m_hObject, &curAccel);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBaseCharacter::UpdateOnLadder
//
// PURPOSE: Update movement when on a ladder
//
// ----------------------------------------------------------------------- //
void CMoveMgr::UpdateOnLadder(CContainerInfo *pInfo)
{
if(pInfo->m_bHidden)
return;
m_bBodyOnLadder = DTRUE;
// Do REAL friction dampening (i.e., actually change our velocity)...
DVector vVel;
m_pPhysicsLT->GetVelocity(m_hObject, &vVel);
DVector vCurVel;
VEC_COPY(vCurVel, vVel);
if (VEC_MAG(vCurVel) > 1.0f)
{
DVector vDir;
VEC_COPY(vDir, vCurVel);
VEC_NORM(vDir);
DFLOAT fAdjust = m_FrameTime*(m_fLadderVel/LADDER_STOP_TIME);
VEC_MULSCALAR(vVel, vDir, fAdjust);
if (VEC_MAG(vVel) < VEC_MAG(vCurVel))
{
VEC_SUB(vVel, vCurVel, vVel);
}
else
{
VEC_INIT(vVel);
}
m_pPhysicsLT->SetVelocity(m_hObject, &vVel);
}
m_pClientDE->SetObjectFlags(m_hObject,
m_pClientDE->GetObjectFlags(m_hObject) & ~FLAG_GRAVITY);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBaseCharacter::UpdateOnConveyor
//
// PURPOSE: Update movement when on a conveyor. Just use ladder
// restrictions.
//
// ----------------------------------------------------------------------- //
void CMoveMgr::UpdateOnConveyor(CContainerInfo *pInfo)
{
if(pInfo->m_bHidden)
return;
m_bBodyOnConveyor = DTRUE;
// Do REAL friction dampening (i.e., actually change our velocity)...
DVector vVel;
m_pPhysicsLT->GetVelocity(m_hObject, &vVel);
DVector vCurVel;
VEC_COPY(vCurVel, vVel);
if (VEC_MAG(vCurVel) > 1.0f)
{
DVector vDir;
VEC_COPY(vDir, vCurVel);
VEC_NORM(vDir);
DFLOAT fAdjust = m_FrameTime*(m_fLadderVel/LADDER_STOP_TIME);
VEC_MULSCALAR(vVel, vDir, fAdjust);
if (VEC_MAG(vVel) < VEC_MAG(vCurVel))
{
VEC_SUB(vVel, vCurVel, vVel);
}
else
{
VEC_INIT(vVel);
}
m_pPhysicsLT->SetVelocity(m_hObject, &vVel);
}
}
void CMoveMgr::UpdateOnGround(CollisionInfo *pInfo)
{
DVector vAccel, vCross1, vCross2;
DVector vVel;
// Lets see if we are in the ground or in the air.
m_pPhysicsLT->GetStandingOn(m_hObject, pInfo);
if (pInfo->m_hObject)
{
m_bOnGround = DTRUE;
// Get the last surface type (for footsteps, etc)
m_eLastSurface = ::GetSurfaceType(pInfo->m_hObject, pInfo->m_hPoly);
// Don't allow climbing slopes greater than 60 degrees.
if( pInfo->m_Plane.m_Normal.y < 0.5 )
{
m_pPhysicsLT->GetAcceleration( m_hObject, &vAccel );
DVector vCross1, vCross2;
VEC_SET(vCross1, 0.0, 1.0, 0.0);
VEC_CROSS(vCross2, pInfo->m_Plane.m_Normal, vCross1);
VEC_NORM(vCross2);
VEC_CROSS(vCross1, vCross2, pInfo->m_Plane.m_Normal);
VEC_MULSCALAR(vCross1, vCross1, -2000.0f);
VEC_ADD(vAccel, vAccel, vCross1);
m_pPhysicsLT->SetAcceleration( m_hObject, &vAccel );
m_bOnGround = DFALSE;
// Force us down...
m_pPhysicsLT->GetVelocity(m_hObject, &vVel);
vVel.y = - VEC_MAG(vVel);
vVel.x = vVel.z = 0.0f;
m_pPhysicsLT->SetVelocity(m_hObject, &vVel);
}
}
else
{
m_bOnGround = DFALSE;
}
}
DBOOL CMoveMgr::IsBodyInLiquid()
{
DDWORD i;
for(i=0; i < m_nContainers; i++)
{
if(IsLiquid(m_Containers[i].m_ContainerCode))
return DTRUE;
}
return DFALSE;
}
DBOOL CMoveMgr::IsDead()
{
return m_pClientShell->IsDead();
}
void CMoveMgr::UpdateMotion()
{
DVector vMyVel;
DVector vAccel;
DVector vUp;
DVector vRight;
DVector vForward;
DVector vMyPos;
DFLOAT fMaxMoveAccel;
DFLOAT fMaxMoveVel;
DFLOAT fMoveAccel = 0.0;
DFLOAT fStrafeAccel = 0;
DFLOAT fMoveVel;
DFLOAT fOrigMaxMoveVel;
// Normally we have gravity on, but the containers might turn it off.
DDWORD dwFlags = m_pClientDE->GetObjectFlags(m_hObject);
if(!m_pClientShell->IsSpectatorMode())
{
dwFlags |= FLAG_GRAVITY | FLAG_SOLID;
dwFlags &= ~(FLAG_GOTHRUWORLD);
}
else
{
dwFlags &= ~(FLAG_SOLID | FLAG_GRAVITY);
dwFlags |= FLAG_GOTHRUWORLD;
}
m_pClientDE->SetObjectFlags(m_hObject, dwFlags);
// Zero acceleration to start with
VEC_INIT(vAccel);
m_pPhysicsLT->SetAcceleration(m_hObject, &vAccel);
// Get the axis offset
DFLOAT offsets[3];
g_pClientDE->GetAxisOffsets(offsets);
DFLOAT fMouseAxis0 = offsets[0];
DFLOAT fMouseAxis1 = offsets[1];
// Update containers
DBOOL bDidLiquid = DFALSE;
DBOOL bDidLadder = DFALSE;
DBOOL bDidConveyor = DFALSE;
for(unsigned i=0; i < m_nContainers; i++)
{
if(IsLiquid(m_Containers[i].m_ContainerCode) && !bDidLiquid)
{
UpdateInLiquid(&m_Containers[i]);
bDidLiquid = DTRUE;
}
else if(m_Containers[i].m_ContainerCode == CC_LADDER && !bDidLadder)
{
UpdateOnLadder(&m_Containers[i]);
bDidLadder = DTRUE;
}
else if( m_Containers[i].m_ContainerCode == CC_CONVEYOR && !bDidConveyor )
{
UpdateOnConveyor(&m_Containers[i]);
bDidConveyor = DTRUE;
}
if(!m_Containers[i].m_bHidden)
{
m_pPhysicsLT->GetVelocity(m_hObject, &vMyVel);
vMyVel += m_Containers[i].m_Current * m_FrameTime;
m_pPhysicsLT->SetVelocity(m_hObject, &vMyVel);
}
}
DBOOL bHeadInLiquid = IsLiquid(m_pClientShell->GetCurContainerCode());
DBOOL bInLiquid = bHeadInLiquid || m_bBodyInLiquid;
DBOOL bFreeMovement = bHeadInLiquid || m_bBodyOnLadder || m_pClientShell->IsSpectatorMode();
DBOOL bLateralMovement = DFALSE;
// Get my position
m_pClientDE->GetObjectPos(m_hObject, &vMyPos);
CollisionInfo collisionInfo;
UpdateOnGround(&collisionInfo);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -