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.
5046 lines
146 KiB
5046 lines
146 KiB
#include "cbase.h" |
|
#ifdef CLIENT_DLL |
|
#include "c_asw_player.h" |
|
#include "c_asw_marine.h" |
|
#include "c_asw_weapon.h" |
|
#include "prediction.h" |
|
#define CASW_Player C_ASW_Player |
|
#define CASW_Marine C_ASW_Marine |
|
#define CASW_Weapon C_ASW_Weapon |
|
#else |
|
#include "asw_marine.h" |
|
#include "asw_player.h" |
|
#include "asw_weapon.h" |
|
#include "asw_alien.h" |
|
#include "takedamageinfo.h" |
|
#include "ndebugoverlay.h" |
|
#include "world.h" |
|
#endif |
|
#include "asw_util_shared.h" |
|
#include "asw_marine_profile.h" |
|
#include "asw_marine_gamemovement.h" |
|
#include "in_buttons.h" |
|
#include <stdarg.h> |
|
#include "movevars_shared.h" |
|
#include "engine/IEngineTrace.h" |
|
#include "SoundEmitterSystem/isoundemittersystembase.h" |
|
#include "decals.h" |
|
#include "asw_shareddefs.h" |
|
#include "coordsize.h" |
|
#include "asw_melee_system.h" |
|
#include "asw_movedata.h" |
|
#include "asw_marine_skills.h" |
|
#include "asw_gamerules.h" |
|
#include "particle_parse.h" |
|
#include "asw_movedata.h" |
|
#ifdef GAME_DLL |
|
#include "te_effect_dispatch.h" |
|
#else |
|
#include "c_te_effect_dispatch.h" |
|
#endif |
|
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
// this code is based on gamemovement.cpp/.h, but is altered to drive a marine AI |
|
|
|
#define STOP_EPSILON 0.1 |
|
#define MAX_CLIP_PLANES 5 |
|
|
|
#define ASW_JUMP_LATERAL_SCALE 0.85f |
|
#define ASW_MIN_ACCELERATION_SPEED 210.0f |
|
|
|
#define ASW_NO_WATER_JUMP 1 // stop us bouncing out of the waist high water in sewers all the time |
|
|
|
#include "filesystem.h" |
|
#include <stdarg.h> |
|
|
|
extern IFileSystem *filesystem; |
|
|
|
#ifndef CLIENT_DLL |
|
#include "env_player_surface_trigger.h" |
|
static ConVar marine_dispcoll_drawplane( "marine_dispcoll_drawplane", "0" ); |
|
#endif |
|
|
|
static ConVar asw_marine_gravity( "asw_marine_gravity","800", FCVAR_NOTIFY | FCVAR_REPLICATED, "Marine gravity." ); |
|
static ConVar asw_marine_friction( "asw_marine_friction","10", FCVAR_NOTIFY | FCVAR_REPLICATED, "Marine movement friction." ); |
|
static ConVar asw_sv_maxspeed( "asw_sv_maxspeed", "500", FCVAR_NOTIFY | FCVAR_REPLICATED); |
|
static ConVar asw_debug_steps("asw_debug_steps", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "Gives debug info on moving up/down steps"); |
|
static ConVar asw_debug_air_move("asw_debug_air_move", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "Gives debug info on air moving"); |
|
extern ConVar asw_controls; |
|
|
|
// tickcount currently isn't set during prediction, although gpGlobals->curtime and |
|
// gpGlobals->frametime are. We should probably set tickcount (to player->m_nTickBase), |
|
// but we're REALLY close to shipping, so we can change that later and people can use |
|
// player->CurrentCommandNumber() in the meantime. |
|
#define tickcount USE_PLAYER_CURRENT_COMMAND_NUMBER__INSTEAD_OF_TICKCOUNT |
|
|
|
extern void DiffPrint( bool bServer, int nCommandNumber, char const *fmt, ... ); |
|
|
|
// [MD] I'll remove this eventually. For now, I want the ability to A/B the optimizations. |
|
extern bool g_bMovementOptimizations; |
|
|
|
// Roughly how often we want to update the info about the ground surface we're on. |
|
// We don't need to do this very often. |
|
#define CATEGORIZE_GROUND_SURFACE_INTERVAL 0.3f |
|
#define CATEGORIZE_GROUND_SURFACE_TICK_INTERVAL ( (int)( CATEGORIZE_GROUND_SURFACE_INTERVAL / TICK_INTERVAL ) ) |
|
|
|
#define CHECK_STUCK_INTERVAL 0.4f |
|
#define CHECK_STUCK_TICK_INTERVAL ( (int)( CHECK_STUCK_INTERVAL / TICK_INTERVAL ) ) |
|
|
|
#define CHECK_LADDER_INTERVAL 0.2f |
|
#define CHECK_LADDER_TICK_INTERVAL ( (int)( CHECK_LADDER_INTERVAL / TICK_INTERVAL ) ) |
|
|
|
extern void COM_Log( char *pszFile, char *fmt, ...); |
|
|
|
CASW_MarineGameMovement* g_pASWGameMovement = NULL; |
|
|
|
CASW_MarineGameMovement* ASWGameMovement() { return g_pASWGameMovement; } |
|
|
|
#ifndef CLIENT_DLL |
|
extern ConVar asw_debug_marine_damage; |
|
extern ConVar asw_marine_fall_damage; |
|
//----------------------------------------------------------------------------- |
|
// Purpose: Debug - draw the displacement collision plane. |
|
//----------------------------------------------------------------------------- |
|
extern void DrawDispCollPlane( CBaseTrace *pTrace ); |
|
|
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Traces marine movement + position |
|
//----------------------------------------------------------------------------- |
|
inline void CASW_MarineGameMovement::TraceMarineBBox( const Vector& start, const Vector& end, unsigned int fMask, int collisionGroup, trace_t& pm ) |
|
{ |
|
++m_nTraceCount; |
|
VPROF( "CASW_MarineGameMovement::TraceMarineBBox" ); |
|
|
|
Ray_t ray; |
|
ray.Init( start, end, GetPlayerMins(), GetPlayerMaxs() ); |
|
ITraceFilter *pFilter = LockTraceFilter( collisionGroup ); |
|
if ( m_pTraceListData && m_pTraceListData->CanTraceRay(ray) ) |
|
{ |
|
enginetrace->TraceRayAgainstLeafAndEntityList( ray, m_pTraceListData, fMask, pFilter, &pm ); |
|
} |
|
else |
|
{ |
|
enginetrace->TraceRay( ray, fMask, pFilter, &pm ); |
|
} |
|
UnlockTraceFilter( pFilter ); |
|
} |
|
|
|
static inline void DoMarineTrace( ITraceListData *pTraceListData, const Ray_t &ray, uint32 fMask, ITraceFilter *filter, trace_t *ptr, int *counter ) |
|
{ |
|
++*counter; |
|
|
|
if ( pTraceListData && pTraceListData->CanTraceRay(ray) ) |
|
{ |
|
enginetrace->TraceRayAgainstLeafAndEntityList( ray, pTraceListData, fMask, filter, ptr ); |
|
} |
|
else |
|
{ |
|
enginetrace->TraceRay( ray, fMask, filter, ptr ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Traces the player's collision bounds in quadrants, looking for a plane that |
|
// can be stood upon (normal's z >= flStandableZ). Regardless of success or failure, |
|
// replace the fraction and endpos with the original ones, so we don't try to |
|
// move the player down to the new floor and get stuck on a leaning wall that |
|
// the original trace hit first. |
|
//----------------------------------------------------------------------------- |
|
void TraceMarineBBoxForGround( ITraceListData *pTraceListData, const Vector& start, const Vector& end, const Vector& minsSrc, |
|
const Vector& maxsSrc, unsigned int fMask, |
|
ITraceFilter *filter, trace_t& pm, float minGroundNormalZ, bool overwriteEndpos, int *pCounter ) |
|
{ |
|
VPROF( "TraceMarineBBoxForGround" ); |
|
|
|
Ray_t ray; |
|
Vector mins, maxs; |
|
|
|
float fraction = pm.fraction; |
|
Vector endpos = pm.endpos; |
|
|
|
// Check the -x, -y quadrant |
|
mins = minsSrc; |
|
maxs.Init( MIN( 0, maxsSrc.x ), MIN( 0, maxsSrc.y ), maxsSrc.z ); |
|
ray.Init( start, end, mins, maxs ); |
|
DoMarineTrace( pTraceListData, ray, fMask, filter, &pm, pCounter ); |
|
if ( pm.m_pEnt && pm.plane.normal[2] >= minGroundNormalZ) |
|
{ |
|
if ( overwriteEndpos ) |
|
{ |
|
pm.fraction = fraction; |
|
pm.endpos = endpos; |
|
} |
|
return; |
|
} |
|
|
|
// Check the +x, +y quadrant |
|
mins.Init( MAX( 0, minsSrc.x ), MAX( 0, minsSrc.y ), minsSrc.z ); |
|
maxs = maxsSrc; |
|
ray.Init( start, end, mins, maxs ); |
|
DoMarineTrace( pTraceListData, ray, fMask, filter, &pm, pCounter ); |
|
if ( pm.m_pEnt && pm.plane.normal[2] >= minGroundNormalZ) |
|
{ |
|
if ( overwriteEndpos ) |
|
{ |
|
pm.fraction = fraction; |
|
pm.endpos = endpos; |
|
} |
|
return; |
|
} |
|
|
|
// Check the -x, +y quadrant |
|
mins.Init( minsSrc.x, MAX( 0, minsSrc.y ), minsSrc.z ); |
|
maxs.Init( MIN( 0, maxsSrc.x ), maxsSrc.y, maxsSrc.z ); |
|
ray.Init( start, end, mins, maxs ); |
|
DoMarineTrace( pTraceListData, ray, fMask, filter, &pm, pCounter ); |
|
if ( pm.m_pEnt && pm.plane.normal[2] >= 0.7) |
|
{ |
|
if ( overwriteEndpos ) |
|
{ |
|
pm.fraction = fraction; |
|
pm.endpos = endpos; |
|
} |
|
return; |
|
} |
|
|
|
// Check the +x, -y quadrant |
|
mins.Init( MAX( 0, minsSrc.x ), minsSrc.y, minsSrc.z ); |
|
maxs.Init( maxsSrc.x, MIN( 0, maxsSrc.y ), maxsSrc.z ); |
|
ray.Init( start, end, mins, maxs ); |
|
DoMarineTrace( pTraceListData, ray, fMask, filter, &pm, pCounter ); |
|
if ( pm.m_pEnt && pm.plane.normal[2] >= minGroundNormalZ) |
|
{ |
|
if ( overwriteEndpos ) |
|
{ |
|
pm.fraction = fraction; |
|
pm.endpos = endpos; |
|
} |
|
return; |
|
} |
|
|
|
if ( overwriteEndpos ) |
|
{ |
|
pm.fraction = fraction; |
|
pm.endpos = endpos; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructs GameMovement interface |
|
//----------------------------------------------------------------------------- |
|
CASW_MarineGameMovement::CASW_MarineGameMovement( void ) |
|
{ |
|
m_nOldWaterLevel = WL_NotInWater; |
|
m_nOnLadder = 0; |
|
|
|
mv = NULL; |
|
|
|
g_pASWGameMovement = this; |
|
m_pTraceListData = NULL; |
|
|
|
memset( m_flStuckCheckTime, 0, sizeof(m_flStuckCheckTime) ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Destructor |
|
//----------------------------------------------------------------------------- |
|
CASW_MarineGameMovement::~CASW_MarineGameMovement( void ) |
|
{ |
|
g_pASWGameMovement = NULL; |
|
if ( enginetrace ) |
|
{ |
|
enginetrace->FreeTraceListData(m_pTraceListData); |
|
} |
|
} |
|
|
|
//-------------------------------------------------------------------------------------------------------- |
|
enum |
|
{ |
|
MAX_NESTING = 8 |
|
}; |
|
|
|
static CTraceFilterSkipTwoEntities s_TraceFilter[MAX_NESTING]; |
|
static int s_nTraceFilterCount = 0; |
|
|
|
ITraceFilter *CASW_MarineGameMovement::LockTraceFilter( int collisionGroup ) |
|
{ |
|
// If this assertion triggers, you forgot to call UnlockTraceFilter |
|
Assert( s_nTraceFilterCount < MAX_NESTING ); |
|
if ( s_nTraceFilterCount >= MAX_NESTING ) |
|
return NULL; |
|
|
|
CTraceFilterSkipTwoEntities *pFilter = &s_TraceFilter[s_nTraceFilterCount++]; |
|
pFilter->SetPassEntity( marine ); |
|
pFilter->SetCollisionGroup( collisionGroup ); |
|
|
|
return pFilter; |
|
} |
|
|
|
void CASW_MarineGameMovement::UnlockTraceFilter( ITraceFilter *&pFilter ) |
|
{ |
|
Assert( s_nTraceFilterCount > 0 ); |
|
--s_nTraceFilterCount; |
|
Assert( &s_TraceFilter[s_nTraceFilterCount] == pFilter ); |
|
pFilter = NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : type - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CASW_MarineGameMovement::GetCheckInterval( IntervalType_t type ) |
|
{ |
|
int tickInterval = 1; |
|
switch ( type ) |
|
{ |
|
default: |
|
tickInterval = 1; |
|
break; |
|
case GROUND: |
|
tickInterval = CATEGORIZE_GROUND_SURFACE_TICK_INTERVAL; |
|
break; |
|
case STUCK: |
|
tickInterval = CHECK_STUCK_TICK_INTERVAL; |
|
break; |
|
case LADDER: |
|
tickInterval = CHECK_LADDER_TICK_INTERVAL; |
|
break; |
|
} |
|
return tickInterval; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : type - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CASW_MarineGameMovement::CheckInterval( IntervalType_t type ) |
|
{ |
|
int tickInterval = GetCheckInterval( type ); |
|
|
|
if ( g_bMovementOptimizations ) |
|
{ |
|
return (player->CurrentCommandNumber() + player->entindex()) % tickInterval == 0; |
|
} |
|
else |
|
{ |
|
return true; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : ducked - |
|
// Output : const Vector |
|
//----------------------------------------------------------------------------- |
|
const Vector& CASW_MarineGameMovement::GetPlayerMins( bool ducked ) const |
|
{ |
|
return marine->CollisionProp()->OBBMins(); |
|
//return ducked ? VEC_DUCK_HULL_MIN : VEC_HULL_MIN; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : ducked - |
|
// Output : const Vector |
|
//----------------------------------------------------------------------------- |
|
const Vector& CASW_MarineGameMovement::GetPlayerMaxs( bool ducked ) const |
|
{ |
|
return marine->CollisionProp()->OBBMaxs(); |
|
//return ducked ? VEC_DUCK_HULL_MAX : VEC_HULL_MAX; |
|
// TODO: Remove all uses of VEC_HULL_MAX and other defines |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : const Vector |
|
//----------------------------------------------------------------------------- |
|
const Vector& CASW_MarineGameMovement::GetPlayerMins( void ) const |
|
{ |
|
return marine->CollisionProp()->OBBMins(); |
|
//return VEC_HULL_MIN; |
|
|
|
//if ( player->IsObserver() ) |
|
//{ |
|
//return VEC_OBS_HULL_MIN; |
|
//} |
|
//else |
|
//{ |
|
//return player->m_Local.m_bDucked ? VEC_DUCK_HULL_MIN : VEC_HULL_MIN; |
|
//} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : const Vector |
|
//----------------------------------------------------------------------------- |
|
const Vector& CASW_MarineGameMovement::GetPlayerMaxs( void ) const |
|
{ |
|
return marine->CollisionProp()->OBBMaxs(); |
|
//return VEC_HULL_MAX; |
|
//if ( player->IsObserver() ) |
|
//{ |
|
//return VEC_OBS_HULL_MAX; |
|
//} |
|
//else |
|
//{ |
|
//return player->m_Local.m_bDucked ? VEC_DUCK_HULL_MAX : VEC_HULL_MAX; |
|
//} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : ducked - |
|
// Output : const Vector |
|
//----------------------------------------------------------------------------- |
|
const Vector& CASW_MarineGameMovement::GetPlayerViewOffset( bool ducked ) const |
|
{ |
|
return ducked ? VEC_DUCK_VIEW : VEC_VIEW; |
|
} |
|
|
|
#if 0 |
|
//----------------------------------------------------------------------------- |
|
// Traces player movement + position |
|
//----------------------------------------------------------------------------- |
|
inline void CASW_MarineGameMovement::TraceMarineBBox( const Vector& start, const Vector& end, unsigned int fMask, int collisionGroup, trace_t& pm ) |
|
{ |
|
VPROF( "CASW_MarineGameMovement::TraceMarineBBox" ); |
|
|
|
Ray_t ray; |
|
ray.Init( start, end, GetPlayerMins(), GetPlayerMaxs() ); |
|
UTIL_TraceRay( ray, fMask, marine, collisionGroup, &pm ); |
|
} |
|
#endif |
|
|
|
inline CBaseHandle CASW_MarineGameMovement::TestPlayerPosition( const Vector& pos, int collisionGroup, trace_t& pm ) |
|
{ |
|
Ray_t ray; |
|
ray.Init( pos, pos, GetPlayerMins(), GetPlayerMaxs() ); |
|
UTIL_TraceRay( ray, MASK_PLAYERSOLID, marine, collisionGroup, &pm ); |
|
#ifdef GAME_DLL |
|
|
|
if ( asw_debug_steps.GetInt() == 2 ) |
|
{ |
|
NDebugOverlay::Box( pos, GetPlayerMins(), GetPlayerMaxs(), 100, 255, 100, 255, 0.1f ); |
|
engine->Con_NPrintf( 10, "%s TestPlayerPosition hit %i/%s", |
|
IsServerDll() ? "server" : "client", |
|
pm.m_pEnt ? pm.m_pEnt->entindex() : 0, pm.m_pEnt ? pm.m_pEnt->GetDebugName() : "NULL" ); |
|
engine->Con_NPrintf( 11, "testpos %f %f %f", |
|
VectorExpand( pos ) ); |
|
} |
|
|
|
#endif |
|
if ( (pm.contents & MASK_PLAYERSOLID) && pm.m_pEnt ) |
|
{ |
|
return pm.m_pEnt->GetRefEHandle(); |
|
} |
|
else |
|
{ |
|
return INVALID_EHANDLE_INDEX; |
|
} |
|
} |
|
|
|
/* |
|
// FIXME FIXME: Does this need to be hooked up? |
|
bool CASW_MarineGameMovement::IsWet() const |
|
{ |
|
return ((pev->flags & FL_INRAIN) != 0) || (m_WetTime >= gpGlobals->time); |
|
} |
|
*/ |
|
//----------------------------------------------------------------------------- |
|
// Plants player footprint decals |
|
//----------------------------------------------------------------------------- |
|
/* |
|
#define PLAYER_HALFWIDTH 12 |
|
void CASW_MarineGameMovement::PlantFootprint( surfacedata_t *psurface ) |
|
{ |
|
int footprintDecal = -1; |
|
|
|
// Figure out which footprint type to plant... |
|
// Use the wet footprint if we're wet... |
|
//if (IsWet()) |
|
//{ |
|
footprintDecal = 1; //DECAL_FOOTPRINT_WET; |
|
//} |
|
//else |
|
//{ |
|
// FIXME: Activate this once we decide to pull the trigger on it. |
|
// NOTE: We could add in snow, mud, others here |
|
// switch(psurface->gameMaterial) |
|
// { |
|
// case 'D': |
|
// footprintDecal = DECAL_FOOTPRINT_DIRT; |
|
// break; |
|
// } |
|
//} |
|
|
|
if (footprintDecal != -1) |
|
{ |
|
Vector right; |
|
AngleVectors( marine->GetAbsAngles(), 0, &right, 0 ); |
|
|
|
// Figure out where the top of the stepping leg is |
|
trace_t tr; |
|
Vector hipOrigin; |
|
VectorMA( marine->GetAbsOrigin(), |
|
m_bIsFootprintOnLeft ? -PLAYER_HALFWIDTH : PLAYER_HALFWIDTH, |
|
right, hipOrigin ); |
|
|
|
// Find where that leg hits the ground |
|
UTIL_TraceLine( hipOrigin, hipOrigin + Vector(0, 0, -COORD_EXTENT * 1.74), |
|
MASK_SOLID_BRUSHONLY, marine, COLLISION_GROUP_NONE, &tr); |
|
|
|
//unsigned char mType = TEXTURETYPE_Find( &tr ); |
|
|
|
//"swarm/decals/arrowupdecal" |
|
// Splat a decal |
|
CPVSFilter filter( tr.endpos ); |
|
te->FootprintDecal( filter, 0.0f, &tr.endpos, &right, tr.GetEntityIndex(), |
|
10, marine->m_chTextureType ); //gDecals[footprintDecal].index |
|
} |
|
|
|
// Switch feet for next time |
|
m_bIsFootprintOnLeft = !m_bIsFootprintOnLeft; |
|
} |
|
|
|
#define WET_TIME 5.f // how many seconds till we're completely wet/dry |
|
#define DRY_TIME 20.f // how many seconds till we're completely wet/dry |
|
|
|
void CBasePlayer::UpdateWetness() |
|
{ |
|
// BRJ 1/7/01 |
|
// Check for whether we're in a rainy area.... |
|
// Do this by tracing a line straight down with a size guaranteed to |
|
// be larger than the map |
|
// Update wetness based on whether we're in rain or not... |
|
|
|
trace_t tr; |
|
UTIL_TraceLine( pev->origin, pev->origin + Vector(0, 0, -COORD_EXTENT * 1.74), |
|
MASK_SOLID_BRUSHONLY, edict(), COLLISION_GROUP_NONE, &tr); |
|
if (tr.surface.flags & SURF_WET) |
|
{ |
|
if (! (pev->flags & FL_INRAIN) ) |
|
{ |
|
// Transition... |
|
// Figure out how wet we are now (we were drying off...) |
|
float wetness = (m_WetTime - gpGlobals->time) / DRY_TIME; |
|
if (wetness < 0.0f) |
|
wetness = 0.0f; |
|
|
|
// Here, wet time represents the time at which we get totally wet |
|
m_WetTime = gpGlobals->time + (1.0 - wetness) * WET_TIME; |
|
|
|
pev->flags |= FL_INRAIN; |
|
} |
|
} |
|
else |
|
{ |
|
if ((pev->flags & FL_INRAIN) != 0) |
|
{ |
|
// Transition... |
|
// Figure out how wet we are now (we were getting more wet...) |
|
float wetness = 1.0f + (gpGlobals->time - m_WetTime) / WET_TIME; |
|
if (wetness > 1.0f) |
|
wetness = 1.0f; |
|
|
|
// Here, wet time represents the time at which we get totally dry |
|
m_WetTime = gpGlobals->time + wetness * DRY_TIME; |
|
|
|
pev->flags &= ~FL_INRAIN; |
|
} |
|
} |
|
} |
|
*/ |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::CategorizeGroundSurface( trace_t &pm ) |
|
{ |
|
IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps(); |
|
marine->m_surfaceProps = pm.surface.surfaceProps; |
|
marine->m_pSurfaceData = physprops->GetSurfaceData( marine->m_surfaceProps ); |
|
physprops->GetPhysicsProperties( marine->m_surfaceProps, NULL, NULL, &marine->m_surfaceFriction, NULL ); |
|
|
|
// HACKHACK: Scale this to fudge the relationship between vphysics friction values and player friction values. |
|
// A value of 0.8f feels pretty normal for vphysics, whereas 1.0f is normal for players. |
|
// This scaling trivially makes them equivalent. REVISIT if this affects low friction surfaces too much. |
|
marine->m_surfaceFriction *= 1.25f; |
|
if ( marine->m_surfaceFriction > 1.0f ) |
|
marine->m_surfaceFriction = 1.0f; |
|
|
|
if ( marine->m_pSurfaceData ) |
|
{ |
|
marine->m_chTextureType = marine->m_pSurfaceData->game.material; |
|
} |
|
/* |
|
// |
|
// Find the name of the material that lies beneath the player. |
|
// |
|
Vector start, end; |
|
VectorCopy( mv->GetAbsOrigin() + Vector(0,0,1), start ); |
|
VectorCopy( mv->GetAbsOrigin(), end ); |
|
|
|
// Straight down |
|
end[2] -= 37; |
|
|
|
// Fill in default values, just in case. |
|
trace_t trace; |
|
TraceMarineBBox( start, end, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace ); |
|
IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps(); |
|
marine->m_surfaceProps = trace.surface.surfaceProps; |
|
marine->m_pSurfaceData = physprops->GetSurfaceData( marine->m_surfaceProps ); |
|
physprops->GetPhysicsProperties( marine->m_surfaceProps, NULL, NULL, &marine->m_surfaceFriction, NULL ); |
|
|
|
// HACKHACK: Scale this to fudge the relationship between vphysics friction values and player friction values. |
|
// A value of 0.8f feels pretty normal for vphysics, whereas 1.0f is normal for players. |
|
// This scaling trivially makes them equivalent. REVISIT if this affects low friction surfaces too much. |
|
marine->m_surfaceFriction *= 1.25f; |
|
if ( marine->m_surfaceFriction > 1.0f ) |
|
marine->m_surfaceFriction = 1.0f; |
|
|
|
marine->m_chTextureType = marine->m_pSurfaceData->game.material; |
|
*/ |
|
} |
|
|
|
bool CASW_MarineGameMovement::IsDead( void ) const |
|
{ |
|
return ( marine->m_iHealth <= 0 ) ? true : false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Figures out how the constraint should slow us down |
|
//----------------------------------------------------------------------------- |
|
float CASW_MarineGameMovement::ComputeConstraintSpeedFactor( void ) |
|
{ |
|
// If we have a constraint, slow down because of that too. |
|
if ( !mv || mv->m_flConstraintRadius == 0.0f ) |
|
return 1.0f; |
|
|
|
float flDistSq = mv->GetAbsOrigin().DistToSqr( mv->m_vecConstraintCenter ); |
|
|
|
float flOuterRadiusSq = mv->m_flConstraintRadius * mv->m_flConstraintRadius; |
|
float flInnerRadiusSq = mv->m_flConstraintRadius - mv->m_flConstraintWidth; |
|
flInnerRadiusSq *= flInnerRadiusSq; |
|
|
|
// Only slow us down if we're inside the constraint ring |
|
if ((flDistSq <= flInnerRadiusSq) || (flDistSq >= flOuterRadiusSq)) |
|
return 1.0f; |
|
|
|
// Only slow us down if we're running away from the center |
|
Vector vecDesired; |
|
VectorMultiply( m_vecForward, mv->m_flForwardMove, vecDesired ); |
|
VectorMA( vecDesired, mv->m_flSideMove, m_vecRight, vecDesired ); |
|
VectorMA( vecDesired, mv->m_flUpMove, m_vecUp, vecDesired ); |
|
|
|
Vector vecDelta; |
|
VectorSubtract( mv->GetAbsOrigin(), mv->m_vecConstraintCenter, vecDelta ); |
|
VectorNormalize( vecDelta ); |
|
VectorNormalize( vecDesired ); |
|
if (DotProduct( vecDelta, vecDesired ) < 0.0f) |
|
return 1.0f; |
|
|
|
float flFrac = (sqrt(flDistSq) - (mv->m_flConstraintRadius - mv->m_flConstraintWidth)) / mv->m_flConstraintWidth; |
|
|
|
float flSpeedFactor = Lerp( flFrac, 1.0f, mv->m_flConstraintSpeedFactor ); |
|
return flSpeedFactor; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::CheckParameters( void ) |
|
{ |
|
QAngle v_angle; |
|
|
|
if ( marine->GetMoveType() != MOVETYPE_ISOMETRIC && |
|
marine->GetMoveType() != MOVETYPE_NOCLIP && |
|
marine->GetMoveType() != MOVETYPE_OBSERVER ) |
|
{ |
|
float spd; |
|
float maxspeed; |
|
|
|
spd = ( mv->m_flForwardMove * mv->m_flForwardMove ) + |
|
( mv->m_flSideMove * mv->m_flSideMove ) + |
|
( mv->m_flUpMove * mv->m_flUpMove ); |
|
|
|
maxspeed = mv->m_flClientMaxSpeed; |
|
if ( maxspeed != 0.0 ) |
|
{ |
|
mv->m_flMaxSpeed = MIN( maxspeed, mv->m_flMaxSpeed ); |
|
} |
|
|
|
// Slow down by the speed factor |
|
float flSpeedFactor = 1.0f; |
|
if (marine->m_pSurfaceData) |
|
{ |
|
flSpeedFactor = marine->m_pSurfaceData->game.maxSpeedFactor; |
|
} |
|
|
|
// If we have a constraint, slow down because of that too. |
|
float flConstraintSpeedFactor = ComputeConstraintSpeedFactor(); |
|
if (flConstraintSpeedFactor < flSpeedFactor) |
|
flSpeedFactor = flConstraintSpeedFactor; |
|
|
|
mv->m_flMaxSpeed *= flSpeedFactor; |
|
|
|
if ( g_bMovementOptimizations ) |
|
{ |
|
// Same thing but only do the sqrt if we have to. |
|
if ( ( spd != 0.0 ) && ( spd > mv->m_flMaxSpeed*mv->m_flMaxSpeed ) ) |
|
{ |
|
float fRatio = mv->m_flMaxSpeed / sqrt( spd ); |
|
mv->m_flForwardMove *= fRatio; |
|
mv->m_flSideMove *= fRatio; |
|
mv->m_flUpMove *= fRatio; |
|
} |
|
} |
|
else |
|
{ |
|
spd = sqrt( spd ); |
|
if ( ( spd != 0.0 ) && ( spd > mv->m_flMaxSpeed ) ) |
|
{ |
|
float fRatio = mv->m_flMaxSpeed / spd; |
|
mv->m_flForwardMove *= fRatio; |
|
mv->m_flSideMove *= fRatio; |
|
mv->m_flUpMove *= fRatio; |
|
} |
|
} |
|
} |
|
|
|
//if ( !m_bSpeedCropped && ( mv->m_nButtons & IN_SPEED ) && !( player->m_Local.m_bDucked && !player->m_Local.m_bDucking )) |
|
if ( !m_bSpeedCropped && ( mv->m_nButtons & IN_SPEED )) |
|
{ |
|
float frac = 1.0f; // TODO can we remove this ? |
|
mv->m_flForwardMove *= frac; |
|
mv->m_flSideMove *= frac; |
|
mv->m_flUpMove *= frac; |
|
m_bSpeedCropped = true; |
|
} |
|
|
|
// slow marine down if walk key is held down |
|
if ( mv->m_nButtons & IN_WALK ) |
|
{ |
|
//Msg("Walking, forward=%f side=%f\n", mv->m_flForwardMove, mv->m_flSideMove); |
|
|
|
float fSpeed = ( mv->m_flForwardMove * mv->m_flForwardMove ) + |
|
( mv->m_flSideMove * mv->m_flSideMove ); |
|
|
|
if (fSpeed > 0) |
|
{ |
|
float frac = 180.0f / sqrt( fSpeed ); |
|
|
|
mv->m_flForwardMove *= frac; |
|
mv->m_flSideMove *= frac; |
|
mv->m_flUpMove *= frac; |
|
} |
|
} |
|
|
|
marine->m_bWalking = ( mv->m_nButtons & IN_WALK ) != 0; |
|
|
|
if ( marine->GetFlags() & FL_FROZEN || |
|
marine->GetFlags() & FL_ONTRAIN || |
|
IsDead() ) |
|
{ |
|
mv->m_flForwardMove = 0; |
|
mv->m_flSideMove = 0; |
|
mv->m_flUpMove = 0; |
|
} |
|
|
|
DecayPunchAngle(); |
|
|
|
// Take angles from command. |
|
if ( !IsDead() ) |
|
{ |
|
v_angle = mv->m_vecAngles; |
|
//v_angle = v_angle + player->m_Local.m_vecPunchAngle; |
|
|
|
// Now adjust roll angle |
|
if ( marine->GetMoveType() != MOVETYPE_ISOMETRIC && |
|
marine->GetMoveType() != MOVETYPE_NOCLIP ) |
|
{ |
|
mv->m_vecAngles[ROLL] = CalcRoll( v_angle, mv->m_vecVelocity, sv_rollangle.GetFloat(), sv_rollspeed.GetFloat() ); |
|
} |
|
else |
|
{ |
|
mv->m_vecAngles[ROLL] = 0.0; // v_angle[ ROLL ]; |
|
} |
|
mv->m_vecAngles[PITCH] = v_angle[PITCH]; |
|
mv->m_vecAngles[YAW] = v_angle[YAW]; |
|
} |
|
else |
|
{ |
|
mv->m_vecAngles = mv->m_vecOldAngles; |
|
} |
|
|
|
// Set dead player view_offset |
|
if ( IsDead() ) |
|
{ |
|
player->SetViewOffset( VEC_DEAD_VIEWHEIGHT ); |
|
} |
|
|
|
// Adjust client view angles to match values used on server. |
|
if ( mv->m_vecAngles[YAW] > 180.0f ) |
|
{ |
|
mv->m_vecAngles[YAW] -= 360.0f; |
|
} |
|
} |
|
|
|
void CASW_MarineGameMovement::ReduceTimers( void ) |
|
{ |
|
float frame_msec = 1000.0f * gpGlobals->frametime; |
|
int nFrameMsec = (int)frame_msec; |
|
|
|
if ( player->m_Local.m_nDuckTimeMsecs > 0 ) |
|
{ |
|
player->m_Local.m_nDuckTimeMsecs -= nFrameMsec; |
|
if ( player->m_Local.m_nDuckTimeMsecs < 0 ) |
|
{ |
|
player->m_Local.m_nDuckTimeMsecs = 0; |
|
} |
|
} |
|
if ( player->m_Local.m_nDuckJumpTimeMsecs > 0 ) |
|
{ |
|
player->m_Local.m_nDuckJumpTimeMsecs -= nFrameMsec; |
|
if ( player->m_Local.m_nDuckJumpTimeMsecs < 0 ) |
|
{ |
|
player->m_Local.m_nDuckJumpTimeMsecs = 0; |
|
} |
|
} |
|
if ( player->m_Local.m_nJumpTimeMsecs > 0 ) |
|
{ |
|
player->m_Local.m_nJumpTimeMsecs -= nFrameMsec; |
|
if ( player->m_Local.m_nJumpTimeMsecs < 0 ) |
|
{ |
|
player->m_Local.m_nJumpTimeMsecs = 0; |
|
} |
|
} |
|
|
|
if ( player->GetSwimSoundTime() > 0 ) |
|
{ |
|
player->SetSwimSoundTime(MAX(player->GetSwimSoundTime() - frame_msec, 0)); |
|
} |
|
} |
|
|
|
// get a conservative bounds for this player's movement traces |
|
// This allows gamemovement to optimize those traces |
|
void CASW_MarineGameMovement::SetupMovementBounds( CMoveData *move ) |
|
{ |
|
if ( m_pTraceListData ) |
|
{ |
|
m_pTraceListData->Reset(); |
|
} |
|
else |
|
{ |
|
m_pTraceListData = enginetrace->AllocTraceListData(); |
|
} |
|
if ( !marine || !player ) |
|
{ |
|
return; |
|
} |
|
|
|
Vector moveMins, moveMaxs; |
|
ClearBounds( moveMins, moveMaxs ); |
|
Vector start = move->GetAbsOrigin(); |
|
float radius = ((move->m_vecVelocity.Length() + move->m_flMaxSpeed) * gpGlobals->frametime) + 1.0f; |
|
// NOTE: assumes the unducked bbox encloses the ducked bbox |
|
Vector boxMins = GetPlayerMins(false); |
|
Vector boxMaxs = GetPlayerMaxs(false); |
|
|
|
// bloat by traveling the max velocity in all directions, plus the stepsize up/down |
|
Vector bloat; |
|
bloat.Init(radius, radius, radius); |
|
bloat.z += player->m_Local.m_flStepSize; |
|
AddPointToBounds( start + boxMaxs + bloat, moveMins, moveMaxs ); |
|
AddPointToBounds( start + boxMins - bloat, moveMins, moveMaxs ); |
|
// now build an optimized trace within these bounds |
|
enginetrace->SetupLeafAndEntityListBox( moveMins, moveMaxs, m_pTraceListData ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pMove - |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::ProcessMovement( CBasePlayer *pPlayer, CBaseEntity *pMarine, CMoveData *pMove ) |
|
{ |
|
Assert( pMove && pPlayer && pMarine ); |
|
|
|
CASW_Marine *pMarineEntity = CASW_Marine::AsMarine( pMarine ); |
|
|
|
static float old_z_pos = 0; |
|
|
|
#ifdef CLIENT_DLL |
|
//Msg(" [C] Process move jump=%d oldjump=%d\n", pMove->m_nButtons & IN_JUMP, pMove->m_nOldButtons & IN_JUMP); |
|
//Msg("c zpos = %f\tzchange = %f\n", pMarine->GetAbsOrigin().z, pMarine->GetAbsOrigin().z - old_z_pos); |
|
#else/ |
|
//Msg("[S] Process move jump=%d oldjump=%d\n", pMove->m_nButtons & IN_JUMP, pMove->m_nOldButtons & IN_JUMP); |
|
//Msg("s zpos = %f\tzchange = %f\n", pMarine->GetAbsOrigin().z, pMarine->GetAbsOrigin().z - old_z_pos); |
|
#endif |
|
old_z_pos = pMarine->GetAbsOrigin().z; |
|
#ifdef GAME_DLL // hurt the marine if he's trying to walk on top of an alien and it's not friendly |
|
if ( pMarineEntity && pMarine->GetGroundEntity() && pMarine->GetGroundEntity()->IsNPC() ) |
|
{ |
|
CASW_Alien *pAlien = dynamic_cast<CASW_Alien*>(pMarine->GetGroundEntity()); |
|
if (pAlien && gpGlobals->curtime > pMarineEntity->m_fNextAlienWalkDamage) |
|
{ |
|
CTakeDamageInfo info( pAlien, pAlien, 15, DMG_SLASH ); |
|
Vector diff = pMarine->GetAbsOrigin() - pAlien->GetAbsOrigin(); |
|
diff.NormalizeInPlace(); |
|
CalculateMeleeDamageForce( &info, diff, pMarine->GetAbsOrigin() - diff * 30 ); |
|
pMarine->TakeDamage( info ); |
|
pMarineEntity->m_fNextAlienWalkDamage = gpGlobals->curtime + 0.4f; |
|
} |
|
} |
|
#endif |
|
|
|
float flStoreFrametime = gpGlobals->frametime; |
|
|
|
//!!HACK HACK: Adrian - slow down all player movement by this factor. |
|
//!!Blame Yahn for this one. |
|
gpGlobals->frametime *= pPlayer->GetLaggedMovementValue(); |
|
|
|
//if (pMove->m_vecVelocity.x > 150) |
|
//{ |
|
//Msg("going fast right"); |
|
//} |
|
|
|
ResetGetPointContentsCache(); |
|
|
|
// Cropping movement speed scales mv->m_fForwardSpeed etc. globally |
|
// Once we crop, we don't want to recursively crop again, so we set the crop |
|
// flag globally here once per usercmd cycle. |
|
m_bSpeedCropped = false; |
|
|
|
player = pPlayer; |
|
marine = pMarineEntity; |
|
mv = pMove; |
|
mv->m_flMaxSpeed = asw_sv_maxspeed.GetFloat(); |
|
|
|
// check for melee attacks |
|
ASWMeleeSystem()->ProcessMovement( pMarineEntity, mv ); |
|
|
|
// Run the command. |
|
PlayerMove(); |
|
|
|
FinishMove(); |
|
|
|
//This is probably not needed, but just in case. |
|
gpGlobals->frametime = flStoreFrametime; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets ground entity |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FinishMove( void ) |
|
{ |
|
mv->m_nOldButtons = mv->m_nButtons; |
|
} |
|
|
|
#define PUNCH_DAMPING 9.0f // bigger number makes the response more damped, smaller is less damped |
|
// currently the system will overshoot, with larger damping values it won't |
|
#define PUNCH_SPRING_CONSTANT 65.0f // bigger number increases the speed at which the view corrects |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Decays the punchangle toward 0,0,0. |
|
// Modelled as a damped spring |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::DecayPunchAngle( void ) |
|
{ |
|
if ( player->m_Local.m_vecPunchAngle->LengthSqr() > 0.001 || player->m_Local.m_vecPunchAngleVel->LengthSqr() > 0.001 ) |
|
{ |
|
player->m_Local.m_vecPunchAngle += player->m_Local.m_vecPunchAngleVel * gpGlobals->frametime; |
|
float damping = 1 - (PUNCH_DAMPING * gpGlobals->frametime); |
|
|
|
if ( damping < 0 ) |
|
{ |
|
damping = 0; |
|
} |
|
player->m_Local.m_vecPunchAngleVel *= damping; |
|
|
|
// torsional spring |
|
// UNDONE: Per-axis spring constant? |
|
float springForceMagnitude = PUNCH_SPRING_CONSTANT * gpGlobals->frametime; |
|
springForceMagnitude = clamp(springForceMagnitude, 0, 2 ); |
|
player->m_Local.m_vecPunchAngleVel -= player->m_Local.m_vecPunchAngle * springForceMagnitude; |
|
|
|
// don't wrap around |
|
player->m_Local.m_vecPunchAngle.Init( |
|
clamp(player->m_Local.m_vecPunchAngle->x, -89, 89 ), |
|
clamp(player->m_Local.m_vecPunchAngle->y, -179, 179 ), |
|
clamp(player->m_Local.m_vecPunchAngle->z, -89, 89 ) ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::StartGravity( void ) |
|
{ |
|
float ent_gravity; |
|
|
|
if (marine->GetGravity()) |
|
ent_gravity = marine->GetGravity(); |
|
else |
|
ent_gravity = 1.0; |
|
|
|
// Add gravity so they'll be in the correct position during movement |
|
// yes, this 0.5 looks wrong, but it's not. |
|
mv->m_vecVelocity[2] -= (ent_gravity * asw_marine_gravity.GetFloat() * 0.5 * gpGlobals->frametime ); |
|
mv->m_vecVelocity[2] += marine->GetBaseVelocity()[2] * gpGlobals->frametime; |
|
|
|
Vector temp = marine->GetBaseVelocity(); |
|
temp[ 2 ] = 0; |
|
marine->SetBaseVelocity( temp ); |
|
|
|
CheckVelocity(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::CheckWaterJump( void ) |
|
{ |
|
Vector flatforward; |
|
Vector forward; |
|
Vector flatvelocity; |
|
float curspeed; |
|
|
|
#ifdef ASW_NO_WATER_JUMP |
|
return; |
|
#endif |
|
|
|
if ( asw_controls.GetInt() == 1 ) |
|
AngleVectors( ASWGameRules()->GetTopDownMovementAxis(), &forward ); |
|
else |
|
AngleVectors( mv->m_vecViewAngles, &forward ); // Determine movement angles |
|
|
|
// Already water jumping. |
|
if (player->GetWaterJumpTime()) |
|
return; |
|
|
|
// Don't hop out if we just jumped in |
|
if (mv->m_vecVelocity[2] < -180) |
|
return; // only hop out if we are moving up |
|
|
|
// See if we are backing up |
|
flatvelocity[0] = mv->m_vecVelocity[0]; |
|
flatvelocity[1] = mv->m_vecVelocity[1]; |
|
flatvelocity[2] = 0; |
|
|
|
// Must be moving |
|
curspeed = VectorNormalize( flatvelocity ); |
|
|
|
// see if near an edge |
|
flatforward[0] = forward[0]; |
|
flatforward[1] = forward[1]; |
|
flatforward[2] = 0; |
|
VectorNormalize (flatforward); |
|
|
|
// Are we backing into water from steps or something? If so, don't pop forward |
|
if ( curspeed != 0.0 && ( DotProduct( flatvelocity, flatforward ) < 0.0 ) ) |
|
return; |
|
|
|
Vector vecStart; |
|
// Start line trace at waist height (using the center of the player for this here) |
|
vecStart= mv->GetAbsOrigin() + (GetPlayerMins() + GetPlayerMaxs() ) * 0.5; |
|
|
|
Vector vecEnd; |
|
VectorMA( vecStart, 24.0f, flatforward, vecEnd ); |
|
|
|
trace_t tr; |
|
TraceMarineBBox( vecStart, vecEnd, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, tr ); |
|
if ( tr.fraction < 1.0 ) // solid at waist |
|
{ |
|
vecStart.z = mv->GetAbsOrigin().z + player->GetViewOffset().z + WATERJUMP_HEIGHT; |
|
VectorMA( vecStart, 24.0f, flatforward, vecEnd ); |
|
VectorMA( vec3_origin, -50.0f, tr.plane.normal, player->m_vecWaterJumpVel ); |
|
|
|
TraceMarineBBox( vecStart, vecEnd, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, tr ); |
|
if ( tr.fraction == 1.0 ) // open at eye level |
|
{ |
|
// Now trace down to see if we would actually land on a standable surface. |
|
VectorCopy( vecEnd, vecStart ); |
|
vecEnd.z -= 1024.0f; |
|
TraceMarineBBox( vecStart, vecEnd, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, tr ); |
|
if ( ( tr.fraction < 1.0f ) && ( tr.plane.normal.z >= 0.7 ) ) |
|
{ |
|
mv->m_vecVelocity[2] = 250.0f; // Push up |
|
mv->m_nOldButtons |= IN_JUMP; // Don't jump again until released |
|
marine->AddFlag( FL_WATERJUMP ); |
|
player->SetWaterJumpTime(2000.0f); // Do this for 2 seconds |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::WaterJump( void ) |
|
{ |
|
if (player->GetWaterJumpTime() > 10000) |
|
player->SetWaterJumpTime(10000); |
|
|
|
if (!player->GetWaterJumpTime()) |
|
return; |
|
|
|
player->SetWaterJumpTime( player->GetWaterJumpTime() - 1000.0f * gpGlobals->frametime ); |
|
|
|
if (player->GetWaterJumpTime() <= 0 || !marine->GetWaterLevel()) |
|
{ |
|
player->SetWaterJumpTime(0); |
|
marine->RemoveFlag( FL_WATERJUMP ); |
|
} |
|
|
|
mv->m_vecVelocity[0] = player->m_vecWaterJumpVel[0]; |
|
mv->m_vecVelocity[1] = player->m_vecWaterJumpVel[1]; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::WaterMove( void ) |
|
{ |
|
int i; |
|
Vector wishvel; |
|
float wishspeed; |
|
Vector wishdir; |
|
Vector start, dest; |
|
Vector temp; |
|
trace_t pm; |
|
float speed, newspeed, addspeed, accelspeed; |
|
Vector forward, right, up; |
|
|
|
if ( asw_controls.GetInt() == 1 ) |
|
AngleVectors( ASWGameRules()->GetTopDownMovementAxis(), &forward, &right, &up ); |
|
else |
|
AngleVectors (mv->m_vecViewAngles, &forward, &right, &up); // Determine movement angles |
|
|
|
// |
|
// user intentions |
|
// |
|
for (i=0 ; i<3 ; i++) |
|
{ |
|
wishvel[i] = forward[i]*mv->m_flForwardMove + right[i]*mv->m_flSideMove; |
|
} |
|
|
|
// if we have the jump key down, move us up as well |
|
if (mv->m_nButtons & IN_JUMP) |
|
{ |
|
wishvel[2] += mv->m_flClientMaxSpeed; |
|
} |
|
// Sinking after no other movement occurs |
|
else if (!mv->m_flForwardMove && !mv->m_flSideMove && !mv->m_flUpMove) |
|
{ |
|
wishvel[2] -= 60; // drift towards bottom |
|
} |
|
else // Go straight up by upmove amount. |
|
{ |
|
wishvel[2] += mv->m_flUpMove; |
|
} |
|
|
|
// Copy it over and determine speed |
|
VectorCopy (wishvel, wishdir); |
|
wishspeed = VectorNormalize(wishdir); |
|
|
|
// Cap speed. |
|
if (wishspeed > mv->m_flMaxSpeed) |
|
{ |
|
VectorScale (wishvel, mv->m_flMaxSpeed/wishspeed, wishvel); |
|
wishspeed = mv->m_flMaxSpeed; |
|
} |
|
|
|
// Slow us down a bit. |
|
wishspeed *= 0.8; |
|
|
|
// Water friction |
|
VectorCopy(mv->m_vecVelocity, temp); |
|
speed = VectorNormalize(temp); |
|
if (speed) |
|
{ |
|
newspeed = speed - gpGlobals->frametime * speed * asw_marine_friction.GetFloat() * marine->m_surfaceFriction; |
|
if (newspeed < 0.1f) |
|
{ |
|
newspeed = 0; |
|
} |
|
|
|
VectorScale (mv->m_vecVelocity, newspeed/speed, mv->m_vecVelocity); |
|
} |
|
else |
|
{ |
|
newspeed = 0; |
|
} |
|
|
|
// water acceleration |
|
if (wishspeed >= 0.1f) // old ! |
|
{ |
|
addspeed = wishspeed - newspeed; |
|
if (addspeed > 0) |
|
{ |
|
VectorNormalize(wishvel); |
|
accelspeed = sv_accelerate.GetFloat() * wishspeed * gpGlobals->frametime * marine->m_surfaceFriction; |
|
if (accelspeed > addspeed) |
|
{ |
|
accelspeed = addspeed; |
|
} |
|
|
|
for (i = 0; i < 3; i++) |
|
{ |
|
float deltaSpeed = accelspeed * wishvel[i]; |
|
mv->m_vecVelocity[i] += deltaSpeed; |
|
mv->m_outWishVel[i] += deltaSpeed; |
|
} |
|
} |
|
} |
|
|
|
VectorAdd (mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity); |
|
|
|
// Now move |
|
// assume it is a stair or a slope, so press down from stepheight above |
|
VectorMA (mv->GetAbsOrigin(), gpGlobals->frametime, mv->m_vecVelocity, dest); |
|
|
|
TraceMarineBBox( mv->GetAbsOrigin(), dest, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
if ( pm.fraction == 1.0f ) |
|
{ |
|
VectorCopy( dest, start ); |
|
if ( player->m_Local.m_bAllowAutoMovement ) |
|
{ |
|
start[2] += player->m_Local.m_flStepSize + 1; |
|
} |
|
|
|
TraceMarineBBox( start, dest, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
|
|
if (!pm.startsolid && !pm.allsolid) |
|
{ |
|
float stepDist = pm.endpos.z - mv->GetAbsOrigin().z; |
|
mv->m_outStepHeight += stepDist; |
|
// walked up the step, so just keep result and exit |
|
mv->SetAbsOrigin( pm.endpos ); |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
return; |
|
} |
|
|
|
// Try moving straight along out normal path. |
|
TryPlayerMove(); |
|
} |
|
else |
|
{ |
|
if ( !marine->GetGroundEntity() ) |
|
{ |
|
TryPlayerMove(); |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
return; |
|
} |
|
|
|
StepMove( dest, pm ); |
|
} |
|
|
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Does the basic move attempting to climb up step heights. It uses |
|
// the mv->m_vecAbsOrigin and mv->m_vecVelocity. It returns a new |
|
// new mv->m_vecAbsOrigin, mv->m_vecVelocity, and mv->m_outStepHeight. |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::StepMove( Vector &vecDestination, trace_t &trace ) |
|
{ |
|
Vector vecEndPos; |
|
VectorCopy( vecDestination, vecEndPos ); |
|
|
|
// Try sliding forward both on ground and up 16 pixels |
|
// take the move that goes farthest |
|
Vector vecStartPos, vecStartVel; |
|
VectorCopy( mv->GetAbsOrigin(), vecStartPos ); // store start position and velocity |
|
VectorCopy( mv->m_vecVelocity, vecStartVel ); |
|
|
|
// Slide move down. |
|
TryPlayerMove( &vecEndPos, &trace ); |
|
|
|
// Down results. |
|
Vector vecDownPos, vecDownVel; |
|
Vector vecNormalMovePos, vecNormalMoveVel; |
|
VectorCopy( mv->GetAbsOrigin(), vecNormalMovePos ); |
|
VectorCopy( mv->m_vecVelocity, vecNormalMoveVel ); |
|
|
|
// Reset original values. |
|
mv->SetAbsOrigin( vecStartPos ); |
|
VectorCopy( vecStartVel, mv->m_vecVelocity ); |
|
|
|
// Takes the marine from his start position and tries to slide him up by the stepsize |
|
VectorCopy( mv->GetAbsOrigin(), vecEndPos ); |
|
if ( player->m_Local.m_bAllowAutoMovement ) |
|
{ |
|
vecEndPos.z += player->m_Local.m_flStepSize; |
|
} |
|
|
|
TraceMarineBBox( mv->GetAbsOrigin(), vecEndPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace ); |
|
if ( !trace.startsolid && !trace.allsolid ) |
|
{ |
|
mv->SetAbsOrigin( trace.endpos ); |
|
} |
|
|
|
// with the marine moved up by stepsize units, then try to do his move |
|
// this moves him forward by his velocity * time, sliding along the collision planes |
|
TryPlayerMove(); |
|
|
|
// with the marine moved forward, now try to drop him straight back down to the floor again |
|
VectorCopy( mv->GetAbsOrigin(), vecEndPos ); |
|
if ( player->m_Local.m_bAllowAutoMovement ) |
|
{ |
|
vecEndPos.z -= player->m_Local.m_flStepSize; |
|
} |
|
|
|
TraceMarineBBox( mv->GetAbsOrigin(), vecEndPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace ); |
|
#ifndef CLIENT_DLL |
|
if (asw_debug_steps.GetBool()) |
|
{ |
|
NDebugOverlay::Box(mv->GetAbsOrigin(), GetPlayerMins(), GetPlayerMaxs(), 255, 0, 0, 0 ,0); |
|
NDebugOverlay::Box(vecEndPos, GetPlayerMins(), GetPlayerMaxs(), 0, 255, 0, 0 ,0); |
|
} |
|
#endif |
|
|
|
// If we are not on the ground any more then use the original movement attempt. |
|
if ( trace.plane.normal[2] < 0.7 ) |
|
{ |
|
mv->SetAbsOrigin( vecNormalMovePos ); |
|
VectorCopy( vecNormalMoveVel, mv->m_vecVelocity ); |
|
float flStepDist = mv->GetAbsOrigin().z - vecStartPos.z; |
|
if ( flStepDist > 0.0f ) |
|
{ |
|
mv->m_outStepHeight += flStepDist; |
|
} |
|
return; |
|
} |
|
|
|
// If the trace ended up in empty space, copy the end over to the origin. |
|
if ( !trace.startsolid && !trace.allsolid ) |
|
{ |
|
mv->SetAbsOrigin( trace.endpos ); |
|
} |
|
|
|
// Copy this origin to up. |
|
Vector vecUpPos; |
|
VectorCopy( mv->GetAbsOrigin(), vecUpPos ); |
|
|
|
// decide which one went farther |
|
float flDownDist = ( vecNormalMovePos.x - vecStartPos.x ) * ( vecNormalMovePos.x - vecStartPos.x ) + ( vecNormalMovePos.y - vecStartPos.y ) * ( vecNormalMovePos.y - vecStartPos.y ); |
|
float flUpDist = ( vecUpPos.x - vecStartPos.x ) * ( vecUpPos.x - vecStartPos.x ) + ( vecUpPos.y - vecStartPos.y ) * ( vecUpPos.y - vecStartPos.y ); |
|
if ( flDownDist > flUpDist ) |
|
{ |
|
mv->SetAbsOrigin( vecNormalMovePos ); |
|
VectorCopy( vecNormalMoveVel, mv->m_vecVelocity ); |
|
} |
|
else |
|
{ |
|
// copy z value from slide move |
|
mv->m_vecVelocity.z = vecNormalMoveVel.z; |
|
} |
|
|
|
float flStepDist = mv->GetAbsOrigin().z - vecStartPos.z; |
|
if ( flStepDist > 0 ) |
|
{ |
|
if (asw_debug_steps.GetBool()) |
|
Msg("Marine stepdist %f\n", flStepDist); |
|
mv->m_outStepHeight += flStepDist; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::Friction( void ) |
|
{ |
|
float speed, newspeed, control; |
|
float friction; |
|
float drop; |
|
Vector newvel; |
|
|
|
|
|
// If we are in water jump cycle, don't apply friction |
|
if (player->GetWaterJumpTime()) |
|
return; |
|
|
|
// Calculate speed |
|
speed = VectorLength( mv->m_vecVelocity ); |
|
|
|
// If too slow, return |
|
if (speed < 0.1f) |
|
{ |
|
return; |
|
} |
|
|
|
drop = 0; |
|
|
|
// apply ground friction |
|
if (marine->GetGroundEntity() != NULL) // On an entity that is the ground |
|
{ |
|
Vector start, stop; |
|
trace_t pm; |
|
|
|
// |
|
// NOTE: added a "1.0f" to the player minimum (bbox) value so that the |
|
// trace starts just inside of the bounding box, this make sure |
|
// that we don't get any collision epsilon (on surface) errors. |
|
// The significance of the 16 below is this is how many units out front we are checking |
|
// to see if the player box would fall. The 49 is the number of units down that is required |
|
// to be considered a fall. 49 is derived from 1 (added 1 from above) + 48 the max fall |
|
// distance a player can fall and still jump back up. |
|
// |
|
// UNDONE: In some cases there are still problems here. Specifically, no collision check is |
|
// done so 16 units in front of the player could be inside a volume or past a collision point. |
|
start[0] = stop[0] = mv->GetAbsOrigin()[0] + (mv->m_vecVelocity[0]/speed)*16; |
|
start[1] = stop[1] = mv->GetAbsOrigin()[1] + (mv->m_vecVelocity[1]/speed)*16; |
|
start[2] = mv->GetAbsOrigin()[2] + ( GetPlayerMins()[2] + 1.0f ); |
|
stop[2] = start[2] - 49; |
|
|
|
if ( g_bMovementOptimizations ) |
|
{ |
|
// We don't actually need this trace. |
|
} |
|
else |
|
{ |
|
TraceMarineBBox( start, stop, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
} |
|
|
|
friction = asw_marine_friction.GetFloat(); |
|
|
|
// Grab friction value. |
|
friction *= marine->m_surfaceFriction; // player friction? |
|
|
|
// Bleed off some speed, but if we have less than the bleed |
|
// threshhold, bleed the theshold amount. |
|
control = (speed < sv_stopspeed.GetFloat()) ? |
|
sv_stopspeed.GetFloat() : speed; |
|
|
|
// Add the amount to the drop amount. |
|
drop += control*friction*gpGlobals->frametime; |
|
} |
|
|
|
// scale the velocity |
|
newspeed = speed - drop; |
|
if (newspeed < 0) |
|
newspeed = 0; |
|
|
|
// Determine proportion of old speed we are using. |
|
newspeed /= speed; |
|
|
|
// Adjust velocity according to proportion. |
|
newvel[0] = mv->m_vecVelocity[0] * newspeed; |
|
newvel[1] = mv->m_vecVelocity[1] * newspeed; |
|
newvel[2] = mv->m_vecVelocity[2] * newspeed; |
|
|
|
VectorCopy( newvel, mv->m_vecVelocity ); |
|
mv->m_outWishVel -= (1.f-newspeed) * mv->m_vecVelocity; |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FinishGravity( void ) |
|
{ |
|
float ent_gravity; |
|
|
|
if ( player->GetWaterJumpTime() ) |
|
return; |
|
|
|
if ( marine->GetGravity() ) |
|
ent_gravity = marine->GetGravity(); |
|
else |
|
ent_gravity = 1.0; |
|
|
|
// Get the correct velocity for the end of the dt |
|
mv->m_vecVelocity[2] -= (ent_gravity * asw_marine_gravity.GetFloat() * gpGlobals->frametime * 0.5); |
|
|
|
CheckVelocity(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : wishdir - |
|
// accel - |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::AirAccelerate( Vector& wishdir, float wishspeed, float accel ) |
|
{ |
|
int i; |
|
float addspeed, accelspeed, currentspeed; |
|
float wishspd; |
|
|
|
wishspd = wishspeed; |
|
|
|
if (player->pl.deadflag) |
|
return; |
|
|
|
if (player->GetWaterJumpTime()) |
|
return; |
|
|
|
// Cap speed |
|
if (wishspd > 30) |
|
wishspd = 30; |
|
|
|
// Determine veer amount |
|
currentspeed = mv->m_vecVelocity.Dot(wishdir); |
|
|
|
// See how much to add |
|
addspeed = wishspd - currentspeed; |
|
|
|
// If not adding any, done. |
|
if (addspeed <= 0) |
|
return; |
|
|
|
// Determine acceleration speed after acceleration |
|
accelspeed = accel * wishspeed * gpGlobals->frametime * marine->m_surfaceFriction; |
|
|
|
// Cap it |
|
if (accelspeed > addspeed) |
|
accelspeed = addspeed; |
|
|
|
// Adjust pmove vel. |
|
for (i=0 ; i<3 ; i++) |
|
{ |
|
mv->m_vecVelocity[i] += accelspeed * wishdir[i]; |
|
mv->m_outWishVel[i] += accelspeed * wishdir[i]; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::AirMove( void ) |
|
{ |
|
int i; |
|
Vector wishvel; |
|
float fmove, smove; |
|
Vector wishdir; |
|
float wishspeed; |
|
Vector forward, right, up; |
|
|
|
if ( asw_controls.GetInt() == 1 ) |
|
AngleVectors( ASWGameRules()->GetTopDownMovementAxis(), &forward, &right, &up ); |
|
else |
|
AngleVectors (mv->m_vecViewAngles, &forward, &right, &up); // Determine movement angles |
|
|
|
// Copy movement amounts |
|
fmove = mv->m_flForwardMove; |
|
smove = mv->m_flSideMove; |
|
|
|
// Zero out z components of movement vectors |
|
forward[2] = 0; |
|
right[2] = 0; |
|
VectorNormalize(forward); // Normalize remainder of vectors |
|
VectorNormalize(right); // |
|
|
|
for (i=0 ; i<2 ; i++) // Determine x and y parts of velocity |
|
wishvel[i] = forward[i]*fmove + right[i]*smove; |
|
wishvel[2] = 0; // Zero out z part of velocity |
|
|
|
VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move |
|
wishspeed = VectorNormalize(wishdir); |
|
|
|
// |
|
// clamp to server defined max speed |
|
// |
|
if ( wishspeed != 0 && (wishspeed > mv->m_flMaxSpeed)) |
|
{ |
|
VectorScale (wishvel, mv->m_flMaxSpeed/wishspeed, wishvel); |
|
wishspeed = mv->m_flMaxSpeed; |
|
} |
|
|
|
if ( mv->m_bNoAirControl == false ) |
|
{ |
|
AirAccelerate( wishdir, wishspeed, sv_airaccelerate.GetFloat() ); |
|
} |
|
|
|
// Add in any base velocity to the current velocity. |
|
VectorAdd(mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
|
|
if (asw_debug_air_move.GetBool()) |
|
Msg(" #2: Vel=%f,%f,%f\n", mv->m_vecVelocity[0], mv->m_vecVelocity[1], mv->m_vecVelocity[2]); |
|
|
|
TryPlayerMove(); |
|
|
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
} |
|
|
|
|
|
bool CASW_MarineGameMovement::CanAccelerate() |
|
{ |
|
// Dead players don't accelerate. |
|
if (player->pl.deadflag) |
|
return false; |
|
|
|
// If waterjumping, don't accelerate |
|
if (player->GetWaterJumpTime()) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : wishdir - |
|
// wishspeed - |
|
// accel - |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::Accelerate( Vector& wishdir, float wishspeed, float accel ) |
|
{ |
|
int i; |
|
float addspeed, accelspeed, currentspeed; |
|
|
|
// This gets overridden because some games (CSPort) want to allow dead (observer) players |
|
// to be able to move around. |
|
if ( !CanAccelerate() ) |
|
return; |
|
|
|
// See if we are changing direction a bit |
|
currentspeed = mv->m_vecVelocity.Dot(wishdir); |
|
|
|
// Reduce wishspeed by the amount of veer. |
|
addspeed = wishspeed - currentspeed; |
|
|
|
// If not going to add any speed, done. |
|
if (addspeed <= 0) |
|
return; |
|
|
|
// Determine amount of accleration. |
|
accelspeed = accel * gpGlobals->frametime * MAX( wishspeed, ASW_MIN_ACCELERATION_SPEED ) * marine->m_surfaceFriction; |
|
|
|
// Cap at addspeed |
|
if (accelspeed > addspeed) |
|
accelspeed = addspeed; |
|
|
|
// Adjust velocity. |
|
for (i=0 ; i<3 ; i++) |
|
{ |
|
mv->m_vecVelocity[i] += accelspeed * wishdir[i]; |
|
} |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Try to keep a walking player on the ground when running down slopes etc |
|
// ASW NOTE: We're not using this as we adjusted the movement code to do this ourselves before getting this code |
|
//----------------------------------------------------------------------------- |
|
#if 0 |
|
void CASW_MarineGameMovement::StayOnGround( void ) |
|
{ |
|
trace_t trace; |
|
Vector start( mv->m_vecAbsOrigin ); |
|
Vector end( mv->m_vecAbsOrigin ); |
|
start.z += 2; |
|
end.z -= player->GetStepSize(); |
|
|
|
// See how far up we can go without getting stuck |
|
TracePlayerBBox( mv->m_vecAbsOrigin, start, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace ); |
|
start = trace.endpos; |
|
|
|
// using trace.startsolid is unreliable here, it doesn't get set when |
|
// tracing bounding box vs. terrain |
|
|
|
// Now trace down from a known safe position |
|
TracePlayerBBox( start, end, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace ); |
|
if ( trace.fraction > 0.0f && // must go somewhere |
|
trace.fraction < 1.0f && // must hit something |
|
!trace.startsolid && // can't be embedded in a solid |
|
trace.plane.normal[2] >= 0.7 ) // can't hit a steep slope that we can't stand on anyway |
|
{ |
|
float flDelta = fabs(mv->m_vecAbsOrigin.z - trace.endpos.z); |
|
|
|
//This is incredibly hacky. The real problem is that trace returning that strange value we can't network over. |
|
if ( flDelta > 0.5f * COORD_RESOLUTION) |
|
{ |
|
mv->m_vecAbsOrigin = trace.endpos; |
|
} |
|
} |
|
} |
|
#endif |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::WalkMove( void ) |
|
{ |
|
int i; |
|
|
|
Vector wishvel; |
|
float spd; |
|
float fmove, smove; |
|
Vector wishdir; |
|
float wishspeed; |
|
|
|
Vector dest; |
|
trace_t pm; |
|
Vector forward, right, up; |
|
|
|
if ( asw_controls.GetInt() == 1 ) |
|
AngleVectors( ASWGameRules()->GetTopDownMovementAxis(), &forward, &right, &up ); |
|
else |
|
AngleVectors (mv->m_vecViewAngles, &forward, &right, &up); // Determine movement angles |
|
|
|
CHandle< CBaseEntity > oldground; |
|
oldground = marine->GetGroundEntity(); |
|
|
|
// Copy movement amounts |
|
fmove = mv->m_flForwardMove; |
|
smove = mv->m_flSideMove; |
|
|
|
// Zero out z components of movement vectors |
|
if ( g_bMovementOptimizations ) |
|
{ |
|
if ( forward[2] != 0 ) |
|
{ |
|
forward[2] = 0; |
|
VectorNormalize( forward ); |
|
} |
|
|
|
if ( right[2] != 0 ) |
|
{ |
|
right[2] = 0; |
|
VectorNormalize( right ); |
|
} |
|
} |
|
else |
|
{ |
|
forward[2] = 0; |
|
right[2] = 0; |
|
|
|
VectorNormalize (forward); // Normalize remainder of vectors. |
|
VectorNormalize (right); // |
|
} |
|
|
|
for (i=0 ; i<2 ; i++) // Determine x and y parts of velocity |
|
wishvel[i] = forward[i]*fmove + right[i]*smove; |
|
|
|
wishvel[2] = 0; // Zero out z part of velocity |
|
|
|
VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move |
|
wishspeed = VectorNormalize(wishdir); |
|
|
|
// |
|
// Clamp to server defined max speed |
|
// |
|
if ((wishspeed != 0.0f) && (wishspeed > mv->m_flMaxSpeed)) |
|
{ |
|
VectorScale (wishvel, mv->m_flMaxSpeed/wishspeed, wishvel); |
|
wishspeed = mv->m_flMaxSpeed; |
|
} |
|
|
|
// Set pmove velocity |
|
mv->m_vecVelocity[2] = 0; |
|
Accelerate ( wishdir, wishspeed, sv_accelerate.GetFloat() ); |
|
mv->m_vecVelocity[2] = 0; |
|
|
|
// Add in any base velocity to the current velocity. |
|
VectorAdd (mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
|
|
spd = VectorLength( mv->m_vecVelocity ); |
|
|
|
if ( spd < 1.0f ) |
|
{ |
|
mv->m_vecVelocity.Init(); |
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
return; |
|
} |
|
|
|
// first try just moving to the destination |
|
dest[0] = mv->GetAbsOrigin()[0] + mv->m_vecVelocity[0]*gpGlobals->frametime; |
|
dest[1] = mv->GetAbsOrigin()[1] + mv->m_vecVelocity[1]*gpGlobals->frametime; |
|
dest[2] = mv->GetAbsOrigin()[2]; |
|
|
|
// first try moving directly to the next spot |
|
TraceMarineBBox( mv->GetAbsOrigin(), dest, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
|
|
// If we made it all the way, then copy trace end as new player position. |
|
mv->m_outWishVel += wishdir * wishspeed; |
|
|
|
if ( pm.fraction == 1) |
|
{ |
|
// asw check for stepping down stairs |
|
if (oldground != NULL) |
|
{ |
|
Vector vecEndPos; |
|
VectorCopy( pm.endpos, vecEndPos ); |
|
if ( player->m_Local.m_bAllowAutoMovement ) |
|
{ |
|
vecEndPos.z -= player->m_Local.m_flStepSize; |
|
} |
|
|
|
trace_t trace; |
|
TraceMarineBBox( pm.endpos, vecEndPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace ); |
|
|
|
// If we hit the ground, then use this move |
|
if ( trace.plane.normal[2] > 0.7 && !trace.startsolid && !trace.allsolid ) |
|
{ |
|
float flStepDist = trace.endpos.z - mv->GetAbsOrigin().z; |
|
if ( flStepDist != 0.0f ) |
|
{ |
|
mv->m_outStepHeight += flStepDist; |
|
mv->SetAbsOrigin( trace.endpos ); |
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
if (asw_debug_steps.GetBool()) |
|
Msg("moved down a stair %f\n", flStepDist); |
|
return; |
|
} |
|
} |
|
} |
|
mv->SetAbsOrigin( pm.endpos ); |
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
return; |
|
} |
|
|
|
// Don't walk up stairs if not on ground. |
|
if ( oldground == NULL && marine->GetWaterLevel() == 0 ) |
|
{ |
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
return; |
|
} |
|
|
|
// If we are jumping out of water, don't do anything more. |
|
if ( player->GetWaterJumpTime() ) |
|
{ |
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
return; |
|
} |
|
|
|
StepMove( dest, pm ); |
|
|
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
} |
|
|
|
ConVar asw_jump_jet_height( "asw_jump_jet_height", "160", FCVAR_REPLICATED ); |
|
ConVar asw_jump_jet_pounce_height( "asw_jump_jet_pounce_height", "60", FCVAR_REPLICATED ); |
|
ConVar asw_blink_height( "asw_blink_height", "50", FCVAR_REPLICATED ); |
|
ConVar asw_charge_height( "asw_charge_height", "5", FCVAR_REPLICATED ); |
|
ConVar asw_blink_visible_time( "asw_blink_visible_time", "0.15", FCVAR_REPLICATED ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FullJumpJetMove() |
|
{ |
|
CASW_MoveData *pASWMove = static_cast<CASW_MoveData*>( mv ); |
|
if ( marine->m_iJumpJetting == JJ_JUMP_JETS ) |
|
{ |
|
// update jump jet end over time with location sent up from the client |
|
if ( pASWMove->m_vecSkillDest != vec3_origin ) |
|
{ |
|
marine->m_vecJumpJetEnd = pASWMove->m_vecSkillDest; |
|
} |
|
} |
|
|
|
float flJumpJetTime = marine->m_flJumpJetEndTime - marine->m_flJumpJetStartTime; |
|
float flJumpJetProgress = ( gpGlobals->curtime - marine->m_flJumpJetStartTime ) / flJumpJetTime; |
|
flJumpJetProgress = clamp( flJumpJetProgress, 0.0f, 1.0f ); |
|
|
|
// x/y linearly between start and end |
|
float xy_progress = flJumpJetProgress; //0.5f + 0.5f * sin( -0.5f * M_PI + flJumpJetProgress * M_PI ); |
|
|
|
Vector vecJump = marine->m_vecJumpJetEnd - marine->m_vecJumpJetStart; |
|
Vector vecDest = marine->m_vecJumpJetStart + vecJump * xy_progress; |
|
|
|
if ( marine->m_iJumpJetting == JJ_JUMP_JETS ) |
|
{ |
|
// on the Z, blend between start and end dests, with a jump curve applied |
|
float flJumpHeight = asw_jump_jet_height.GetFloat(); |
|
vecDest.z = marine->m_vecJumpJetStart.z + vecJump.z * flJumpJetProgress + sin( flJumpJetProgress * M_PI ) * flJumpHeight; |
|
} |
|
else if ( marine->m_iJumpJetting == JJ_CHARGE ) |
|
{ |
|
// slide to the destination Z |
|
float flJumpHeight = asw_charge_height.GetFloat(); |
|
vecDest.z = marine->m_vecJumpJetStart.z + vecJump.z * flJumpJetProgress + sin( flJumpJetProgress * M_PI ) * flJumpHeight; |
|
} |
|
|
|
// check for hiding marine while he blinks |
|
if ( marine->m_iJumpJetting == JJ_BLINK ) |
|
{ |
|
bool bHide = ( flJumpJetProgress > asw_blink_visible_time.GetFloat() && flJumpJetProgress < ( 1.0f - asw_blink_visible_time.GetFloat() ) ); |
|
if ( marine->IsEffectActive( EF_NODRAW ) != bHide ) |
|
{ |
|
if ( bHide ) |
|
{ |
|
#ifdef CLIENT_DLL |
|
if ( prediction->InPrediction() && prediction->IsFirstTimePredicted() ) |
|
{ |
|
#endif |
|
marine->EmitSound( "ASW_Blink.Blink" ); |
|
DispatchParticleEffect( "Blink", marine->GetAbsOrigin(), vec3_angle ); |
|
DispatchParticleEffect( "electrified_armor_burst", marine->GetAbsOrigin(), vec3_angle ); |
|
#ifdef CLIENT_DLL |
|
} |
|
#else |
|
CASW_Weapon *pWeapon = marine->GetASWWeapon( ASW_INVENTORY_SLOT_EXTRA ); |
|
ASWGameRules()->ShockNearbyAliens( marine, pWeapon ); |
|
#endif |
|
marine->AddEffects( EF_NODRAW ); |
|
} |
|
else |
|
{ |
|
#ifdef CLIENT_DLL |
|
if ( prediction->InPrediction() && prediction->IsFirstTimePredicted() ) |
|
{ |
|
#endif |
|
marine->EmitSound( "ASW_Blink.Teleport" ); |
|
DispatchParticleEffect( "Blink", marine->GetAbsOrigin(), vec3_angle ); |
|
DispatchParticleEffect( "electrified_armor_burst", marine->GetAbsOrigin(), vec3_angle ); |
|
#ifdef CLIENT_DLL |
|
} |
|
#else |
|
CASW_Weapon *pWeapon = marine->GetASWWeapon( ASW_INVENTORY_SLOT_EXTRA ); |
|
ASWGameRules()->ShockNearbyAliens( marine, pWeapon ); |
|
#endif |
|
marine->RemoveEffects( EF_NODRAW ); |
|
} |
|
} |
|
|
|
float flJumpHeight = asw_blink_height.GetFloat(); |
|
if ( flJumpJetProgress < asw_blink_visible_time.GetFloat() ) // jump straight up |
|
{ |
|
float flUpProgress = flJumpJetProgress / asw_blink_visible_time.GetFloat(); |
|
vecDest = marine->m_vecJumpJetStart; |
|
vecDest.z = marine->m_vecJumpJetStart.z + sin( flUpProgress * M_PI * 0.5f ) * flJumpHeight; |
|
} |
|
else if ( flJumpJetProgress < ( 1.0f - asw_blink_visible_time.GetFloat() ) ) // slide quickly to end X/Y |
|
{ |
|
// lerp between start and end |
|
Vector vecStartTop = marine->m_vecJumpJetStart + Vector( 0, 0, flJumpHeight ); |
|
Vector vecEndTop = marine->m_vecJumpJetEnd + Vector( 0, 0, flJumpHeight ); |
|
|
|
float flSlideProgress = ( flJumpJetProgress - asw_blink_visible_time.GetFloat() ) / ( 1.0f - asw_blink_visible_time.GetFloat() * 2 ); |
|
flSlideProgress = sin( flSlideProgress * M_PI * 0.5f ); |
|
vecDest = vecStartTop + ( vecEndTop - vecStartTop ) * flSlideProgress; |
|
} |
|
else // fall to ground |
|
{ |
|
float flDownProgress = 1.0f - ( ( 1.0f - flJumpJetProgress ) / asw_blink_visible_time.GetFloat() ); |
|
|
|
vecDest = marine->m_vecJumpJetEnd; |
|
vecDest.z = marine->m_vecJumpJetEnd.z + sin( flDownProgress * M_PI * 0.5f ) * flJumpHeight; |
|
} |
|
} |
|
|
|
mv->SetAbsOrigin( vecDest ); |
|
|
|
if ( flJumpJetProgress >= 1.0f ) |
|
{ |
|
// TODO: Set these based on BLINK/HOVER |
|
float flRadius = 200.0f; |
|
#ifdef GAME_DLL |
|
int iBaseDamage = 150; |
|
#endif |
|
CASW_Marine_Profile *pProfile = marine->GetMarineProfile(); |
|
if ( pProfile ) |
|
{ |
|
if ( marine->m_iJumpJetting == JJ_BLINK ) |
|
{ |
|
// TODO: Stun aliens at the point of exit? |
|
/* |
|
#ifdef GAME_DLL |
|
// any effects on blink landing |
|
CASW_Weapon_EffectVolume *pEffect = (CASW_Weapon_EffectVolume*) CreateEntityByName("asw_weapon_effect_volume"); |
|
if ( pEffect ) |
|
{ |
|
pEffect->SetAbsOrigin( marine->GetAbsOrigin() ); |
|
pEffect->SetOwnerEntity( marine ); |
|
pEffect->SetOwnerWeapon( NULL ); |
|
pEffect->SetEffectFlag( ASW_WEV_ELECTRIC_BIG ); |
|
pEffect->SetDuration( pSkill->GetValue( CASW_Skill_Details::Duration, pProfile->GetMarineSkill( pSkill->m_iSkillIndex ) ) ); |
|
pEffect->Spawn(); |
|
} |
|
#endif |
|
*/ |
|
} |
|
} |
|
|
|
if ( marine->m_iJumpJetting == JJ_CHARGE || marine->m_iJumpJetting == JJ_JUMP_JETS ) // charge/jump jets |
|
{ |
|
CEffectData data; |
|
|
|
data.m_nHitBox = GetParticleSystemIndex( "jj_ground_pound" ); |
|
data.m_vOrigin = marine->GetAbsOrigin(); |
|
data.m_vStart = Vector( flRadius, 0, 0 ); |
|
data.m_vAngles = marine->GetAbsAngles(); |
|
#ifdef CLIENT_DLL |
|
data.m_hEntity = NULL; |
|
#else |
|
data.m_nEntIndex = 0; |
|
#endif |
|
|
|
#ifdef CLIENT_DLL |
|
if ( prediction->InPrediction() && prediction->IsFirstTimePredicted() ) |
|
{ |
|
#endif |
|
CBroadcastRecipientFilter filter; |
|
DispatchEffect( filter, 0.0f, "ParticleEffect", data ); |
|
marine->EmitSound( filter, marine->entindex(), "ASW_JumpJet.Impact" ); |
|
#ifdef CLIENT_DLL |
|
//ASW_TransmitShakeEvent( player, 25.0f, 1.0f, 0.4f, SHAKE_START, Vector( 0, 0, 1 ) ); |
|
ScreenShake_t shake; |
|
shake.direction = Vector( 0, 0, 1 ); |
|
shake.amplitude = 40.0f; |
|
shake.duration = 0.3f; |
|
shake.frequency = 1.0f; |
|
shake.command = SHAKE_START; |
|
ASW_TransmitShakeEvent( player, shake ); |
|
} |
|
#endif |
|
|
|
#ifdef GAME_DLL |
|
|
|
if ( gpGlobals->maxClients == 1 ) // client isn't running prediction, so need to send down the screen shake |
|
{ |
|
ScreenShake_t shake; |
|
shake.direction = Vector( 0, 0, 1 ); |
|
shake.amplitude = 40.0f; |
|
shake.duration = 0.3f; |
|
shake.frequency = 1.0f; |
|
shake.command = SHAKE_START; |
|
ASW_TransmitShakeEvent( player, shake ); |
|
} |
|
/* |
|
// scorch the ground |
|
trace_t tr; |
|
UTIL_TraceLine ( marine->GetAbsOrigin(), marine->GetAbsOrigin() + Vector( 0, 0, -80 ), MASK_SHOT, |
|
marine, COLLISION_GROUP_NONE, &tr); |
|
if ((tr.m_pEnt != GetWorldEntity()) || (tr.hitbox != 0)) |
|
{ |
|
// non-world needs smaller decals |
|
if( tr.m_pEnt && !tr.m_pEnt->IsNPC() ) |
|
{ |
|
UTIL_DecalTrace( &tr, "Rollermine.Crater" ); |
|
} |
|
} |
|
else |
|
{ |
|
UTIL_DecalTrace( &tr, "Rollermine.Crater" ); |
|
} |
|
*/ |
|
|
|
CASW_Weapon *pWeapon = marine->GetASWWeapon( ASW_INVENTORY_SLOT_EXTRA ); |
|
CBaseEntity *pInflictor = pWeapon; |
|
if ( !pInflictor ) |
|
{ |
|
pInflictor = marine; |
|
} |
|
CTakeDamageInfo dmgInfo( pInflictor, marine, iBaseDamage, DMG_CLUB ); |
|
dmgInfo.SetWeapon( pInflictor ); |
|
ASWGameRules()->RadiusDamage( dmgInfo, marine->GetAbsOrigin(), flRadius * 0.5f, CLASS_NONE, NULL ); |
|
ASWGameRules()->StumbleAliensInRadius( marine, marine->GetAbsOrigin(), flRadius ); |
|
|
|
if ( pWeapon ) |
|
{ |
|
pWeapon->DestroyIfEmpty( true, false ); |
|
} |
|
#endif |
|
} |
|
|
|
marine->m_iJumpJetting = JJ_NONE; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FullMeleeMove( void ) |
|
{ |
|
if ( !CheckWater() ) |
|
{ |
|
StartGravity(); |
|
} |
|
|
|
// If we are leaping out of the water, just update the counters. |
|
if (player->GetWaterJumpTime()) |
|
{ |
|
WaterJump(); |
|
TryPlayerMove(); |
|
// See if we are still in water? |
|
CheckWater(); |
|
return; |
|
} |
|
|
|
if (marine->GetGroundEntity() != NULL) |
|
{ |
|
mv->m_vecVelocity[2] = 0.0; |
|
//Friction(); |
|
} |
|
|
|
// Make sure velocity is valid. |
|
CheckVelocity(); |
|
MeleeMove(); |
|
|
|
// Set final flags. |
|
CategorizePosition(); |
|
|
|
// Make sure velocity is valid. |
|
CheckVelocity(); |
|
|
|
// Add any remaining gravitational component. |
|
if ( !CheckWater() ) |
|
{ |
|
FinishGravity(); |
|
} |
|
|
|
// If we are on ground, no downward velocity. |
|
if ( marine->GetGroundEntity() != NULL ) |
|
{ |
|
mv->m_vecVelocity[2] = 0; |
|
} |
|
CheckFalling(); |
|
|
|
if ( ( m_nOldWaterLevel == WL_NotInWater && marine->GetWaterLevel() != WL_NotInWater ) || |
|
( m_nOldWaterLevel != WL_NotInWater && marine->GetWaterLevel() == WL_NotInWater ) ) |
|
{ |
|
PlaySwimSound(); |
|
} |
|
} |
|
void CASW_MarineGameMovement::MeleeMove( void ) |
|
{ |
|
#ifdef GAME_DLL |
|
// do lag comp on melee movements |
|
//CASW_Player *pPlayer = marine->GetCommander(); |
|
bool bLagComp = false; |
|
/*if ( pPlayer && marine->IsInhabited() && !CASW_Lag_Compensation::IsInLagCompensation() ) |
|
{ |
|
bLagComp = true; |
|
CASW_Lag_Compensation::AllowLagCompensation( pPlayer ); |
|
CASW_Lag_Compensation::RequestLagCompensation( pPlayer, pPlayer->GetCurrentUserCommand() ); |
|
}*/ |
|
#endif |
|
|
|
Vector dest; |
|
trace_t pm; |
|
|
|
CHandle< CBaseEntity > oldground = marine->GetGroundEntity(); |
|
|
|
// first try just moving to the destination |
|
dest[0] = mv->GetAbsOrigin()[0] + mv->m_vecVelocity[0]*gpGlobals->frametime; |
|
dest[1] = mv->GetAbsOrigin()[1] + mv->m_vecVelocity[1]*gpGlobals->frametime; |
|
dest[2] = mv->GetAbsOrigin()[2]; |
|
|
|
if ( !oldground ) |
|
{ |
|
dest[2] += mv->m_vecVelocity[2]*gpGlobals->frametime; |
|
} |
|
|
|
// first try moving directly to the next spot |
|
TraceMarineBBox( mv->GetAbsOrigin(), dest, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
if ( pm.DidHitNonWorldEntity() && marine->GetCurrentMeleeAttack() ) |
|
{ |
|
//marine->GetCurrentMeleeAttack()->MovementCollision( marine, mv, &pm ); |
|
} |
|
|
|
// If we made it all the way, then copy trace end as new player position. |
|
mv->m_outWishVel = mv->m_vecVelocity; |
|
|
|
if ( pm.fraction == 1) |
|
{ |
|
// asw check for stepping down stairs |
|
if (oldground != NULL) |
|
{ |
|
Vector vecEndPos; |
|
VectorCopy( pm.endpos, vecEndPos ); |
|
if ( player->m_Local.m_bAllowAutoMovement ) |
|
{ |
|
vecEndPos.z -= player->m_Local.m_flStepSize; |
|
} |
|
|
|
trace_t trace; |
|
TraceMarineBBox( pm.endpos, vecEndPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace ); |
|
|
|
// If we hit the ground, then use this move |
|
if ( trace.plane.normal[2] > 0.7 && !trace.startsolid && !trace.allsolid ) |
|
{ |
|
float flStepDist = trace.endpos.z - mv->GetAbsOrigin().z; |
|
if ( flStepDist != 0.0f ) |
|
{ |
|
mv->m_outStepHeight += flStepDist; |
|
mv->SetAbsOrigin( trace.endpos ); |
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
if (asw_debug_steps.GetBool()) |
|
Msg("moved down a stair %f\n", flStepDist); |
|
#ifdef GAME_DLL |
|
if ( bLagComp ) |
|
{ |
|
CASW_Lag_Compensation::FinishLagCompensation(); // undo lag compensation if we need to |
|
} |
|
#endif |
|
return; |
|
} |
|
} |
|
} |
|
mv->SetAbsOrigin( pm.endpos ); |
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
#ifdef GAME_DLL |
|
if ( bLagComp ) |
|
{ |
|
CASW_Lag_Compensation::FinishLagCompensation(); // undo lag compensation if we need to |
|
} |
|
#endif |
|
return; |
|
} |
|
|
|
// Don't walk up stairs if not on ground. |
|
if ( oldground == NULL && marine->GetWaterLevel() == 0 ) |
|
{ |
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
#ifdef GAME_DLL |
|
if ( bLagComp ) |
|
{ |
|
CASW_Lag_Compensation::FinishLagCompensation(); // undo lag compensation if we need to |
|
} |
|
#endif |
|
return; |
|
} |
|
|
|
// If we are jumping out of water, don't do anything more. |
|
if ( player->GetWaterJumpTime() ) |
|
{ |
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
#ifdef GAME_DLL |
|
if ( bLagComp ) |
|
{ |
|
CASW_Lag_Compensation::FinishLagCompensation(); // undo lag compensation if we need to |
|
} |
|
#endif |
|
return; |
|
} |
|
|
|
StepMove( dest, pm ); |
|
|
|
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?) |
|
VectorSubtract( mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity ); |
|
#ifdef GAME_DLL |
|
if ( bLagComp ) |
|
{ |
|
CASW_Lag_Compensation::FinishLagCompensation(); // undo lag compensation if we need to |
|
} |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FullWalkMove( ) |
|
{ |
|
if ( marine->GetCurrentMeleeAttack() && marine->m_iMeleeAllowMovement == MELEE_MOVEMENT_FALLING_ONLY ) |
|
{ |
|
mv->m_flForwardMove = 0.0f; |
|
mv->m_flSideMove = 0.0f; |
|
mv->m_flUpMove = 0.0f; |
|
mv->m_bNoAirControl = true; |
|
mv->m_nButtons &= ~IN_JUMP; |
|
} |
|
|
|
if ( !CheckWater() ) |
|
{ |
|
StartGravity(); |
|
} |
|
|
|
// If we are leaping out of the water, just update the counters. |
|
if (player->GetWaterJumpTime()) |
|
{ |
|
WaterJump(); |
|
TryPlayerMove(); |
|
// See if we are still in water? |
|
CheckWater(); |
|
return; |
|
} |
|
|
|
// If we are swimming in the water, see if we are nudging against a place we can jump up out |
|
// of, and, if so, start out jump. Otherwise, if we are not moving up, then reset jump timer to 0 |
|
if ( marine->GetWaterLevel() >= WL_Waist ) |
|
{ |
|
if ( marine->GetWaterLevel() == WL_Waist ) |
|
{ |
|
CheckWaterJump(); |
|
} |
|
|
|
// If we are falling again, then we must not trying to jump out of water any more. |
|
if ( mv->m_vecVelocity[2] < 0 && |
|
player->GetWaterJumpTime() ) |
|
{ |
|
player->SetWaterJumpTime(0); |
|
} |
|
|
|
// Was jump button pressed? |
|
if (mv->m_nButtons & IN_JUMP) |
|
{ |
|
CheckJumpButton(); |
|
} |
|
else |
|
{ |
|
mv->m_nOldButtons &= ~IN_JUMP; |
|
} |
|
|
|
// Perform regular water movement |
|
WaterMove(); |
|
|
|
// Redetermine position vars |
|
CategorizePosition(); |
|
|
|
// If we are on ground, no downward velocity. |
|
if ( marine->GetGroundEntity() != NULL ) |
|
{ |
|
mv->m_vecVelocity[2] = 0; |
|
} |
|
} |
|
else |
|
// Not fully underwater |
|
{ |
|
// Was jump button pressed? |
|
if (mv->m_nButtons & IN_JUMP) |
|
{ |
|
CheckJumpButton(); |
|
} |
|
else |
|
{ |
|
mv->m_nOldButtons &= ~IN_JUMP; |
|
} |
|
|
|
// Fricion is handled before we add in any base velocity. That way, if we are on a conveyor, |
|
// we don't slow when standing still, relative to the conveyor. |
|
if (marine->GetGroundEntity() != NULL) |
|
{ |
|
mv->m_vecVelocity[2] = 0.0; |
|
Friction(); |
|
} |
|
|
|
// Make sure velocity is valid. |
|
CheckVelocity(); |
|
|
|
if (marine->GetGroundEntity() != NULL) |
|
{ |
|
WalkMove(); |
|
} |
|
else |
|
{ |
|
if (asw_debug_air_move.GetBool()) |
|
Msg("AirMove: Vel=%f,%f,%f\n", mv->m_vecVelocity[0], mv->m_vecVelocity[1], mv->m_vecVelocity[2]); |
|
AirMove(); // Take into account movement when in air. |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #3 Vel=%f,%f,%f\n", mv->m_vecVelocity[0], mv->m_vecVelocity[1], mv->m_vecVelocity[2]); |
|
} |
|
|
|
// Set final flags. |
|
CategorizePosition(); |
|
|
|
// Make sure velocity is valid. |
|
CheckVelocity(); |
|
|
|
// Add any remaining gravitational component. |
|
if ( !CheckWater() ) |
|
{ |
|
FinishGravity(); |
|
} |
|
|
|
// If we are on ground, no downward velocity. |
|
if ( marine->GetGroundEntity() != NULL ) |
|
{ |
|
mv->m_vecVelocity[2] = 0; |
|
} |
|
CheckFalling(); |
|
|
|
} |
|
|
|
if ( ( m_nOldWaterLevel == WL_NotInWater && marine->GetWaterLevel() != WL_NotInWater ) || |
|
( m_nOldWaterLevel != WL_NotInWater && marine->GetWaterLevel() == WL_NotInWater ) ) |
|
{ |
|
PlaySwimSound(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FullObserverMove( void ) |
|
{ |
|
int mode = player->GetObserverMode(); |
|
|
|
if ( mode == OBS_MODE_IN_EYE || mode == OBS_MODE_CHASE ) |
|
{ |
|
CBaseEntity * target = player->GetObserverTarget(); |
|
|
|
if ( target != NULL ) |
|
{ |
|
mv->SetAbsOrigin( target->EyePosition() ); |
|
mv->m_vecViewAngles = target->EyeAngles(); |
|
mv->m_vecVelocity = target->GetAbsVelocity(); |
|
} |
|
|
|
return; |
|
} |
|
|
|
if ( mode != OBS_MODE_ROAMING ) |
|
{ |
|
// don't move in fixed or death cam mode |
|
return; |
|
} |
|
|
|
if ( sv_specnoclip.GetBool() ) |
|
{ |
|
// roam in noclip mode |
|
FullNoClipMove( sv_specspeed.GetFloat(), sv_specaccelerate.GetFloat() ); |
|
return; |
|
} |
|
|
|
// do a full clipped free roam move: |
|
|
|
Vector wishvel; |
|
Vector forward, right, up; |
|
Vector wishdir, wishend; |
|
float wishspeed; |
|
|
|
if ( asw_controls.GetInt() == 1 ) |
|
AngleVectors( ASWGameRules()->GetTopDownMovementAxis(), &forward, &right, &up ); |
|
else |
|
AngleVectors (mv->m_vecViewAngles, &forward, &right, &up); // Determine movement angles |
|
|
|
// Copy movement amounts |
|
|
|
float factor = sv_specspeed.GetFloat(); |
|
|
|
if ( mv->m_nButtons & IN_SPEED ) |
|
{ |
|
factor /= 2.0f; |
|
} |
|
|
|
float fmove = mv->m_flForwardMove * factor; |
|
float smove = mv->m_flSideMove * factor; |
|
|
|
VectorNormalize (forward); // Normalize remainder of vectors |
|
VectorNormalize (right); // |
|
|
|
for (int i=0 ; i<3 ; i++) // Determine x and y parts of velocity |
|
wishvel[i] = forward[i]*fmove + right[i]*smove; |
|
wishvel[2] += mv->m_flUpMove; |
|
|
|
VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move |
|
wishspeed = VectorNormalize(wishdir); |
|
|
|
// |
|
// Clamp to server defined max speed |
|
// |
|
|
|
float maxspeed = sv_maxvelocity.GetFloat(); |
|
|
|
|
|
if (wishspeed > maxspeed ) |
|
{ |
|
VectorScale (wishvel, mv->m_flMaxSpeed/wishspeed, wishvel); |
|
wishspeed = maxspeed; |
|
} |
|
|
|
// Set pmove velocity, give observer 50% acceration bonus |
|
Accelerate ( wishdir, wishspeed, sv_specaccelerate.GetFloat() ); |
|
|
|
float spd = VectorLength( mv->m_vecVelocity ); |
|
if (spd < 1.0f) |
|
{ |
|
mv->m_vecVelocity.Init(); |
|
return; |
|
} |
|
|
|
float friction = asw_marine_friction.GetFloat(); |
|
|
|
// Add the amount to the drop amount. |
|
float drop = spd * friction * gpGlobals->frametime; |
|
|
|
// scale the velocity |
|
float newspeed = spd - drop; |
|
|
|
if (newspeed < 0) |
|
newspeed = 0; |
|
|
|
// Determine proportion of old speed we are using. |
|
newspeed /= spd; |
|
|
|
VectorScale( mv->m_vecVelocity, newspeed, mv->m_vecVelocity ); |
|
|
|
CheckVelocity(); |
|
|
|
TryPlayerMove(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FullNoClipMove( float factor, float maxacceleration ) |
|
{ |
|
Vector wishvel; |
|
Vector forward, right, up; |
|
Vector wishdir; |
|
float wishspeed; |
|
float maxspeed = asw_sv_maxspeed.GetFloat() * factor; |
|
|
|
if ( asw_controls.GetInt() == 1 ) |
|
AngleVectors( ASWGameRules()->GetTopDownMovementAxis(), &forward, &right, &up ); |
|
else |
|
AngleVectors (mv->m_vecViewAngles, &forward, &right, &up); // Determine movement angles |
|
|
|
if ( mv->m_nButtons & IN_SPEED ) |
|
{ |
|
factor /= 2.0f; |
|
} |
|
|
|
// Copy movement amounts |
|
float fmove = mv->m_flForwardMove * factor; |
|
float smove = mv->m_flSideMove * factor; |
|
|
|
VectorNormalize (forward); // Normalize remainder of vectors |
|
VectorNormalize (right); // |
|
|
|
for (int i=0 ; i<3 ; i++) // Determine x and y parts of velocity |
|
wishvel[i] = forward[i]*fmove + right[i]*smove; |
|
wishvel[2] += mv->m_flUpMove * factor; |
|
|
|
VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move |
|
wishspeed = VectorNormalize(wishdir); |
|
|
|
// |
|
// Clamp to server defined max speed |
|
// |
|
if (wishspeed > maxspeed ) |
|
{ |
|
VectorScale (wishvel, maxspeed/wishspeed, wishvel); |
|
wishspeed = maxspeed; |
|
} |
|
|
|
if ( maxacceleration > 0.0 ) |
|
{ |
|
// Set pmove velocity |
|
Accelerate ( wishdir, wishspeed, maxacceleration ); |
|
|
|
float spd = VectorLength( mv->m_vecVelocity ); |
|
if (spd < 1.0f) |
|
{ |
|
mv->m_vecVelocity.Init(); |
|
return; |
|
} |
|
|
|
// Bleed off some speed, but if we have less than the bleed |
|
// threshhold, bleed the theshold amount. |
|
float control = (spd < maxspeed/4.0) ? maxspeed/4.0 : spd; |
|
|
|
float friction = asw_marine_friction.GetFloat() * marine->m_surfaceFriction; |
|
|
|
// Add the amount to the drop amount. |
|
float drop = control * friction * gpGlobals->frametime; |
|
|
|
// scale the velocity |
|
float newspeed = spd - drop; |
|
if (newspeed < 0) |
|
newspeed = 0; |
|
|
|
// Determine proportion of old speed we are using. |
|
newspeed /= spd; |
|
VectorScale( mv->m_vecVelocity, newspeed, mv->m_vecVelocity ); |
|
} |
|
else |
|
{ |
|
VectorCopy( wishvel, mv->m_vecVelocity ); |
|
} |
|
|
|
// Just move ( don't clip or anything ) |
|
Vector dest; |
|
VectorMA( mv->GetAbsOrigin(), gpGlobals->frametime, mv->m_vecVelocity, dest ); |
|
mv->SetAbsOrigin( dest ); |
|
|
|
// Zero out velocity if in noaccel mode |
|
if ( maxacceleration < 0.0f ) |
|
{ |
|
mv->m_vecVelocity.Init(); |
|
} |
|
} |
|
|
|
|
|
void CASW_MarineGameMovement::PlaySwimSound() |
|
{ |
|
MoveHelper()->StartSound( mv->GetAbsOrigin(), "Player.Swim" ); |
|
} |
|
|
|
ConVar jump_jet_height( "jump_jet_height", "150", FCVAR_CHEAT | FCVAR_REPLICATED ); |
|
ConVar jump_jet_forward( "jump_jet_forward", "320", FCVAR_CHEAT | FCVAR_REPLICATED ); |
|
|
|
void CASW_MarineGameMovement::DoJumpJet() |
|
{ |
|
// In the air now. |
|
SetGroundEntity( NULL ); |
|
|
|
// fixme: should play from the marine, not the player |
|
Vector vecSrc = mv->GetAbsOrigin(); |
|
player->PlayStepSound( vecSrc, marine->m_pSurfaceData, 1.0, true ); |
|
|
|
// fixme: set the animation on the marine |
|
//MoveHelper()->PlayerSetAnimation( PLAYER_JUMP ); |
|
CASW_Player* pASWPlayer = dynamic_cast<CASW_Player*>(player); |
|
if (pASWPlayer && pASWPlayer->GetMarine()) |
|
{ |
|
pASWPlayer->GetMarine()->DoAnimationEvent( PLAYERANIMEVENT_JUMP ); |
|
} |
|
|
|
float flMul = sqrt(2 * asw_marine_gravity.GetFloat() * jump_jet_height.GetFloat() ); |
|
|
|
// Acclerate upward |
|
// If we are ducking... |
|
float startz = mv->m_vecVelocity[2]; |
|
|
|
// d = 0.5 * g * t^2 - distance traveled with linear accel |
|
// t = sqrt(2.0 * 45 / g) - how long to fall 45 units |
|
// v = g * t - velocity at the end (just invert it to jump up that high) |
|
// v = g * sqrt(2.0 * 45 / g ) |
|
// v^2 = g * g * 2.0 * 45 / g |
|
// v = sqrt( g * 2.0 * 45 ) |
|
mv->m_vecVelocity[2] = flMul; // 2 * gravity * height |
|
|
|
Vector vecForward; |
|
AngleVectors( mv->m_vecViewAngles, &vecForward ); |
|
|
|
vecForward.z = 0; |
|
VectorNormalize( vecForward ); |
|
for ( int iAxis = 0; iAxis < 2 ; ++iAxis ) |
|
{ |
|
mv->m_vecVelocity[ iAxis ] = vecForward[ iAxis ] * jump_jet_forward.GetFloat(); |
|
} |
|
|
|
FinishGravity(); |
|
|
|
mv->m_outJumpVel.z += mv->m_vecVelocity[2] - startz; |
|
mv->m_outStepHeight += 0.15f; |
|
|
|
CASW_Melee_Attack *pAttack = ASWMeleeSystem()->GetMeleeAttackByName( "JumpJetImpact" ); |
|
if ( pAttack ) |
|
{ |
|
marine->m_iOnLandMeleeAttackID = pAttack->m_nAttackID; |
|
} |
|
} |
|
|
|
extern ConVar asw_marine_rolls; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Checks to see if we should actually jump |
|
//----------------------------------------------------------------------------- |
|
bool CASW_MarineGameMovement::CheckJumpButton( void ) |
|
{ |
|
// fixme: don't jump if marine is dead |
|
//if (player->pl.deadflag) |
|
//{ |
|
//mv->m_nOldButtons |= IN_JUMP ; // don't jump again until released |
|
//return false; |
|
//} |
|
|
|
// See if we are waterjumping. If so, decrement count and return. |
|
// fixme: put water jumptime, etc into the marine |
|
//if (player->m_flWaterJumpTime) |
|
//{ |
|
//player->m_flWaterJumpTime -= gpGlobals->frametime; |
|
//if (player->m_flWaterJumpTime < 0) |
|
//player->m_flWaterJumpTime = 0; |
|
|
|
//return false; |
|
//} |
|
|
|
// No jumping while hacking |
|
if ( marine->IsHacking() ) |
|
return false; |
|
|
|
if ( asw_marine_rolls.GetBool() ) |
|
return false; |
|
|
|
// If we are in the water most of the way... |
|
if ( marine->GetWaterLevel() >= 2 ) |
|
{ |
|
// swimming, not jumping |
|
SetGroundEntity( NULL ); |
|
|
|
if(marine->GetWaterType() == CONTENTS_WATER) // We move up a certain amount |
|
mv->m_vecVelocity[2] = 100; |
|
else if (marine->GetWaterType() == CONTENTS_SLIME) |
|
mv->m_vecVelocity[2] = 80; |
|
|
|
// play swiming sound |
|
if ( player->GetSwimSoundTime() <= 0 ) |
|
{ |
|
// Don't play sound again for 1 second |
|
player->SetSwimSoundTime(1000); |
|
PlaySwimSound(); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
// No more effect |
|
if (marine->GetGroundEntity() == NULL || marine->GetAbsVelocity().z > 0) |
|
{ |
|
mv->m_nOldButtons |= IN_JUMP; |
|
return false; // in air, so no effect |
|
} |
|
|
|
// Don't allow jumping when the player is in a stasis field. |
|
// asw: irrelevant for marines |
|
//if ( player->m_Local.m_bSlowMovement ) |
|
//return false; |
|
|
|
if ( mv->m_nOldButtons & IN_JUMP ) |
|
return false; // don't pogo stick |
|
|
|
if (marine->GetFlags() & FL_FROZEN) // no jumping when frozen |
|
return false; |
|
|
|
// Cannot jump will in the unduck transition. |
|
// asw: irrelevant for marines (since they don't duck atm) |
|
//if ( player->m_Local.m_bDucking && ( player->GetFlags() & FL_DUCKING ) ) |
|
//return false; |
|
|
|
// Still updating the eye position. |
|
// asw: irrelevant for marines (since they don't duck atm) |
|
//if ( player->m_Local.m_nDuckJumpTimeMsecs > 0.0f ) |
|
//return false; |
|
|
|
|
|
// In the air now. |
|
SetGroundEntity( NULL ); |
|
|
|
// fixme: should play from the marine, not the player |
|
Vector vecSrc = mv->GetAbsOrigin(); |
|
player->PlayStepSound( vecSrc, marine->m_pSurfaceData, 1.0, true ); |
|
|
|
// fixme: set the animation on the marine |
|
//MoveHelper()->PlayerSetAnimation( PLAYER_JUMP ); |
|
CASW_Player* pASWPlayer = dynamic_cast<CASW_Player*>(player); |
|
if (pASWPlayer && pASWPlayer->GetMarine()) |
|
{ |
|
pASWPlayer->GetMarine()->DoAnimationEvent( PLAYERANIMEVENT_JUMP ); |
|
} |
|
|
|
float flGroundFactor = 1.0f; |
|
if (marine->m_pSurfaceData) |
|
{ |
|
flGroundFactor = marine->m_pSurfaceData->game.jumpFactor; |
|
} |
|
|
|
float flMul; |
|
// asw comment |
|
/* |
|
if ( g_bMovementOptimizations ) |
|
{ |
|
#if defined(HL2_DLL) || defined(HL2_CLIENT_DLL) |
|
Assert( sv_gravity.GetFloat() == 600.0f ); |
|
flMul = 160.0f; // approx. 21 units. |
|
#else |
|
Assert( sv_gravity.GetFloat() == 800.0f ); |
|
flMul = 268.3281572999747f; |
|
#endif |
|
|
|
} |
|
else*/ |
|
{ |
|
flMul = sqrt(2 * asw_marine_gravity.GetFloat() * GAMEMOVEMENT_ASW_JUMP_HEIGHT); |
|
} |
|
|
|
// Acclerate upward |
|
// If we are ducking... |
|
float startz = mv->m_vecVelocity[2]; |
|
|
|
if ( ( player->m_Local.m_bDucking ) || ( marine->GetFlags() & FL_DUCKING ) ) |
|
{ |
|
// d = 0.5 * g * t^2 - distance traveled with linear accel |
|
// t = sqrt(2.0 * 45 / g) - how long to fall 45 units |
|
// v = g * t - velocity at the end (just invert it to jump up that high) |
|
// v = g * sqrt(2.0 * 45 / g ) |
|
// v^2 = g * g * 2.0 * 45 / g |
|
// v = sqrt( g * 2.0 * 45 ) |
|
mv->m_vecVelocity[2] = flGroundFactor * flMul; // 2 * gravity * height |
|
} |
|
else |
|
{ |
|
mv->m_vecVelocity[2] += flGroundFactor * flMul; // 2 * gravity * height |
|
} |
|
|
|
// reduce the marine's x/y velocity some |
|
mv->m_vecVelocity[0] *= ASW_JUMP_LATERAL_SCALE; |
|
mv->m_vecVelocity[1] *= ASW_JUMP_LATERAL_SCALE; |
|
|
|
// Add a little forward velocity based on your current forward velocity - if you are not sprinting. |
|
// asw: no forward boost |
|
/* |
|
#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) |
|
CHLMoveData *pMoveData = ( CHLMoveData* )mv; |
|
Vector vecForward; |
|
AngleVectors( mv->m_vecViewAngles, &vecForward ); |
|
vecForward.z = 0; |
|
VectorNormalize( vecForward ); |
|
if ( !pMoveData->m_bIsSprinting && !player->m_Local.m_bDucked ) |
|
{ |
|
for ( int iAxis = 0; iAxis < 2 ; ++iAxis ) |
|
{ |
|
vecForward[iAxis] *= ( mv->m_flForwardMove * 0.5f ); |
|
// vecForward[iAxis] *= ( mv->m_flForwardMove * jumpforwardscale.GetFloat() ); |
|
} |
|
} |
|
else |
|
{ |
|
for ( int iAxis = 0; iAxis < 2 ; ++iAxis ) |
|
{ |
|
vecForward[iAxis] *= ( mv->m_flForwardMove * 0.1f ); |
|
// vecForward[iAxis] *= ( mv->m_flForwardMove * jumpforwardsprintscale.GetFloat() ); |
|
} |
|
} |
|
VectorAdd( vecForward, mv->m_vecVelocity, mv->m_vecVelocity ); |
|
#endif |
|
*/ |
|
|
|
FinishGravity(); |
|
#ifdef CLIENT_DLL |
|
//Msg(" [C] %f Jumping! v.z=%f\n", gpGlobals->curtime, marine->GetAbsVelocity().z); |
|
#else |
|
//Msg("[S] %f Jumping! v.z=%f\n", gpGlobals->curtime, marine->GetAbsVelocity().z); |
|
#endif |
|
|
|
mv->m_outJumpVel.z += mv->m_vecVelocity[2] - startz; |
|
mv->m_outStepHeight += 0.15f; |
|
|
|
// Set jump time. |
|
player->m_Local.m_nJumpTimeMsecs = GAMEMOVEMENT_JUMP_TIME; |
|
player->m_Local.m_bInDuckJump = true; |
|
|
|
// Flag that we jumped. |
|
mv->m_nOldButtons |= IN_JUMP; // don't jump again until released |
|
|
|
//Msg("jumping. m_outJumpVel.z = %f m_outStepHeight = %f vecvel.z = %f\n", |
|
//mv->m_outJumpVel.z, mv->m_outStepHeight, mv->m_vecVelocity[2]); |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FullLadderMove() |
|
{ |
|
CheckWater(); |
|
|
|
// Was jump button pressed? If so, set velocity to 270 away from ladder. |
|
if ( mv->m_nButtons & IN_JUMP ) |
|
{ |
|
CheckJumpButton(); |
|
} |
|
else |
|
{ |
|
mv->m_nOldButtons &= ~IN_JUMP; |
|
} |
|
|
|
// Perform the move accounting for any base velocity. |
|
VectorAdd (mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity); |
|
TryPlayerMove(); |
|
VectorSubtract (mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CASW_MarineGameMovement::TryPlayerMove( Vector *pFirstDest, trace_t *pFirstTrace ) |
|
{ |
|
int bumpcount, numbumps; |
|
Vector dir; |
|
float d; |
|
int numplanes; |
|
Vector planes[MAX_CLIP_PLANES]; |
|
Vector primal_velocity, original_velocity; |
|
Vector new_velocity; |
|
int i, j; |
|
trace_t pm; |
|
Vector end; |
|
float time_left, allFraction; |
|
int blocked; |
|
|
|
numbumps = 4; // Bump up to four times |
|
|
|
blocked = 0; // Assume not blocked |
|
numplanes = 0; // and not sliding along any planes |
|
|
|
VectorCopy (mv->m_vecVelocity, original_velocity); // Store original velocity |
|
VectorCopy (mv->m_vecVelocity, primal_velocity); |
|
|
|
allFraction = 0; |
|
time_left = gpGlobals->frametime; // Total time for this movement operation. |
|
|
|
new_velocity.Init(); |
|
|
|
for (bumpcount=0 ; bumpcount < numbumps; bumpcount++) |
|
{ |
|
if ( mv->m_vecVelocity.Length() == 0.0 ) |
|
break; |
|
|
|
// Assume we can move all the way from the current origin to the |
|
// end point. |
|
VectorMA( mv->GetAbsOrigin(), time_left, mv->m_vecVelocity, end ); |
|
|
|
// See if we can make it from origin to end point. |
|
if ( g_bMovementOptimizations ) |
|
{ |
|
// If their velocity Z is 0, then we can avoid an extra trace here during WalkMove. |
|
if ( pFirstDest && end == *pFirstDest ) |
|
pm = *pFirstTrace; |
|
else |
|
TraceMarineBBox( mv->GetAbsOrigin(), end, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
} |
|
else |
|
{ |
|
TraceMarineBBox( mv->GetAbsOrigin(), end, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
} |
|
|
|
allFraction += pm.fraction; |
|
|
|
// If we started in a solid object, or we were in solid space |
|
// the whole way, zero out our velocity and return that we |
|
// are blocked by floor and wall. |
|
if (pm.allsolid) |
|
{ |
|
// entity is trapped in another solid |
|
VectorCopy (vec3_origin, mv->m_vecVelocity); |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #T1 Stuck in a solid\n"); |
|
return 4; |
|
} |
|
|
|
// If we moved some portion of the total distance, then |
|
// copy the end position into the pmove.origin and |
|
// zero the plane counter. |
|
if( pm.fraction > 0 ) |
|
{ |
|
// actually covered some distance |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #T1.5 Moving marine absorigin. vel = %f,%f,%f\n", mv->m_vecVelocity[0], mv->m_vecVelocity[1], mv->m_vecVelocity[2]); |
|
mv->SetAbsOrigin( pm.endpos ); |
|
VectorCopy (mv->m_vecVelocity, original_velocity); |
|
numplanes = 0; |
|
} |
|
|
|
// If we covered the entire distance, we are done |
|
// and can return. |
|
if (pm.fraction == 1) |
|
{ |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #T2 Moved the entire distance\n"); |
|
break; // moved the entire distance |
|
} |
|
|
|
// Save entity that blocked us (since fraction was < 1.0) |
|
// for contact |
|
// Add it if it's not already in the list!!! |
|
MoveHelper( )->AddToTouched( pm, mv->m_vecVelocity ); |
|
|
|
// If the plane we hit has a high z component in the normal, then |
|
// it's probably a floor |
|
if (pm.plane.normal[2] > 0.7) |
|
{ |
|
blocked |= 1; // floor |
|
} |
|
// If the plane has a zero z component in the normal, then it's a |
|
// step or wall |
|
if (!pm.plane.normal[2]) |
|
{ |
|
blocked |= 2; // step / wall |
|
} |
|
|
|
// Reduce amount of m_flFrameTime left by total time left * fraction |
|
// that we covered. |
|
time_left -= time_left * pm.fraction; |
|
|
|
// Did we run out of planes to clip against? |
|
if (numplanes >= MAX_CLIP_PLANES) |
|
{ |
|
// this shouldn't really happen |
|
// Stop our movement if so. |
|
VectorCopy (vec3_origin, mv->m_vecVelocity); |
|
//Con_DPrintf("Too many planes 4\n"); |
|
|
|
break; |
|
} |
|
|
|
// Set up next clipping plane |
|
VectorCopy (pm.plane.normal, planes[numplanes]); |
|
numplanes++; |
|
|
|
// modify original_velocity so it parallels all of the clip planes |
|
// |
|
|
|
// relfect player velocity |
|
// Only give this a try for first impact plane because you can get yourself stuck in an acute corner by jumping in place |
|
// and pressing forward and nobody was really using this bounce/reflection feature anyway... |
|
if ( numplanes == 1 && |
|
marine->GetMoveType() == MOVETYPE_WALK && |
|
marine->GetGroundEntity() == NULL ) |
|
{ |
|
for ( i = 0; i < numplanes; i++ ) |
|
{ |
|
if ( planes[i][2] > 0.7 ) |
|
{ |
|
// floor or slope |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #T3 On a floor or slope, clipping velocity to the 1 plane\n"); |
|
ClipVelocity( original_velocity, planes[i], new_velocity, 1 ); |
|
VectorCopy( new_velocity, original_velocity ); |
|
} |
|
else |
|
{ |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #T4 Not on a floor or slope, clipping velocity to the some sv_bounce reflected amount around 1 plane\n"); |
|
ClipVelocity( original_velocity, planes[i], new_velocity, 1.0 + sv_bounce.GetFloat() * (1 - marine->m_surfaceFriction) ); |
|
} |
|
} |
|
|
|
VectorCopy( new_velocity, mv->m_vecVelocity ); |
|
VectorCopy( new_velocity, original_velocity ); |
|
} |
|
else |
|
{ |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #T5 Clipping velocity to the %d planes\n", numplanes); |
|
for (i=0 ; i < numplanes ; i++) |
|
{ |
|
ClipVelocity ( |
|
original_velocity, |
|
planes[i], |
|
mv->m_vecVelocity, |
|
1); |
|
|
|
for (j=0 ; j<numplanes ; j++) |
|
if (j != i) |
|
{ |
|
// Are we now moving against this plane? |
|
if (mv->m_vecVelocity.Dot(planes[j]) < 0) |
|
break; // not ok |
|
} |
|
if (j == numplanes) // Didn't have to clip, so we're ok |
|
break; |
|
} |
|
|
|
// Did we go all the way through plane set |
|
if (i != numplanes) |
|
{ // go along this plane |
|
// pmove.velocity is set in clipping call, no need to set again. |
|
; |
|
} |
|
else |
|
{ // go along the crease |
|
if (numplanes != 2) |
|
{ |
|
VectorCopy (vec3_origin, mv->m_vecVelocity); |
|
break; |
|
} |
|
CrossProduct (planes[0], planes[1], dir); |
|
dir.NormalizeInPlace(); // asw - added sept 2nd 06 |
|
d = dir.Dot(mv->m_vecVelocity); |
|
VectorScale (dir, d, mv->m_vecVelocity ); |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #T6 Going along the crease\n", numplanes); |
|
} |
|
|
|
// |
|
// if original velocity is against the original velocity, stop dead |
|
// to avoid tiny occilations in sloping corners |
|
// |
|
d = mv->m_vecVelocity.Dot(primal_velocity); |
|
if (d <= 0) |
|
{ |
|
//Con_DPrintf("Back\n"); |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #T7 Going opposite, so stopping\n", numplanes); |
|
VectorCopy (vec3_origin, mv->m_vecVelocity); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if ( allFraction == 0 ) |
|
{ |
|
if (asw_debug_air_move.GetBool() && marine->GetGroundEntity() == NULL) |
|
Msg(" #T8 Going nowhere, so stopping\n", numplanes); |
|
VectorCopy (vec3_origin, mv->m_vecVelocity); |
|
} |
|
|
|
return blocked; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Determine whether or not the player is on a ladder (physprop or world). |
|
//----------------------------------------------------------------------------- |
|
inline bool CASW_MarineGameMovement::OnLadder( trace_t &trace ) |
|
{ |
|
if ( trace.contents & CONTENTS_LADDER ) |
|
return true; |
|
|
|
IPhysicsSurfaceProps *pPhysProps = MoveHelper( )->GetSurfaceProps(); |
|
if ( pPhysProps ) |
|
{ |
|
surfacedata_t *pSurfaceData = pPhysProps->GetSurfaceData( trace.surface.surfaceProps ); |
|
if ( pSurfaceData ) |
|
{ |
|
if ( pSurfaceData->game.climbable != 0 ) |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CASW_MarineGameMovement::LadderMove( void ) |
|
{ |
|
trace_t pm; |
|
bool onFloor; |
|
Vector floor; |
|
Vector wishdir; |
|
Vector end; |
|
|
|
if ( marine->GetMoveType() == MOVETYPE_NOCLIP ) |
|
return false; |
|
|
|
// If I'm already moving on a ladder, use the previous ladder direction |
|
if ( marine->GetMoveType() == MOVETYPE_LADDER ) |
|
{ |
|
wishdir = -player->m_vecLadderNormal.Get(); |
|
} |
|
else |
|
{ |
|
// otherwise, use the direction player is attempting to move |
|
if ( mv->m_flForwardMove || mv->m_flSideMove ) |
|
{ |
|
for (int i=0 ; i<3 ; i++) // Determine x and y parts of velocity |
|
wishdir[i] = m_vecForward[i]*mv->m_flForwardMove + m_vecRight[i]*mv->m_flSideMove; |
|
|
|
VectorNormalize(wishdir); |
|
} |
|
else |
|
{ |
|
// Player is not attempting to move, no ladder behavior |
|
return false; |
|
} |
|
} |
|
|
|
// wishdir points toward the ladder if any exists |
|
VectorMA( mv->GetAbsOrigin(), 2, wishdir, end ); |
|
TraceMarineBBox( mv->GetAbsOrigin(), end, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
|
|
// no ladder in that direction, return |
|
if ( pm.fraction == 1.0f || !OnLadder( pm ) ) |
|
return false; |
|
|
|
marine->SetMoveType( MOVETYPE_LADDER ); |
|
marine->SetMoveCollide( MOVECOLLIDE_DEFAULT ); |
|
|
|
player->m_vecLadderNormal = pm.plane.normal; |
|
|
|
// On ladder, convert movement to be relative to the ladder |
|
|
|
VectorCopy( mv->GetAbsOrigin(), floor ); |
|
floor[2] += GetPlayerMins()[2] - 1; |
|
|
|
if( enginetrace->GetPointContents( floor ) == CONTENTS_SOLID ) |
|
{ |
|
onFloor = true; |
|
} |
|
else |
|
{ |
|
onFloor = false; |
|
} |
|
|
|
marine->SetGravity( 0 ); |
|
|
|
float forwardSpeed = 0, rightSpeed = 0; |
|
if ( mv->m_nButtons & IN_BACK ) |
|
forwardSpeed -= MAX_CLIMB_SPEED; |
|
|
|
if ( mv->m_nButtons & IN_FORWARD ) |
|
forwardSpeed += MAX_CLIMB_SPEED; |
|
|
|
if ( mv->m_nButtons & IN_MOVELEFT ) |
|
rightSpeed -= MAX_CLIMB_SPEED; |
|
|
|
if ( mv->m_nButtons & IN_MOVERIGHT ) |
|
rightSpeed += MAX_CLIMB_SPEED; |
|
|
|
if ( mv->m_nButtons & IN_JUMP ) |
|
{ |
|
marine->SetMoveType( MOVETYPE_WALK ); |
|
marine->SetMoveCollide( MOVECOLLIDE_DEFAULT ); |
|
|
|
VectorScale( pm.plane.normal, 270, mv->m_vecVelocity ); |
|
} |
|
else |
|
{ |
|
if ( forwardSpeed != 0 || rightSpeed != 0 ) |
|
{ |
|
Vector velocity, perp, cross, lateral, tmp; |
|
|
|
//ALERT(at_console, "pev %.2f %.2f %.2f - ", |
|
// pev->velocity.x, pev->velocity.y, pev->velocity.z); |
|
// Calculate player's intended velocity |
|
//Vector velocity = (forward * gpGlobals->v_forward) + (right * gpGlobals->v_right); |
|
VectorScale( m_vecForward, forwardSpeed, velocity ); |
|
VectorMA( velocity, rightSpeed, m_vecRight, velocity ); |
|
|
|
// Perpendicular in the ladder plane |
|
VectorCopy( vec3_origin, tmp ); |
|
tmp[2] = 1; |
|
CrossProduct( tmp, pm.plane.normal, perp ); |
|
VectorNormalize( perp ); |
|
|
|
// decompose velocity into ladder plane |
|
float normal = DotProduct( velocity, pm.plane.normal ); |
|
|
|
// This is the velocity into the face of the ladder |
|
VectorScale( pm.plane.normal, normal, cross ); |
|
|
|
// This is the player's additional velocity |
|
VectorSubtract( velocity, cross, lateral ); |
|
|
|
// This turns the velocity into the face of the ladder into velocity that |
|
// is roughly vertically perpendicular to the face of the ladder. |
|
// NOTE: It IS possible to face up and move down or face down and move up |
|
// because the velocity is a sum of the directional velocity and the converted |
|
// velocity through the face of the ladder -- by design. |
|
CrossProduct( pm.plane.normal, perp, tmp ); |
|
VectorMA( lateral, -normal, tmp, mv->m_vecVelocity ); |
|
|
|
if ( onFloor && normal > 0 ) // On ground moving away from the ladder |
|
{ |
|
VectorMA( mv->m_vecVelocity, MAX_CLIMB_SPEED, pm.plane.normal, mv->m_vecVelocity ); |
|
} |
|
//pev->velocity = lateral - (CrossProduct( trace.vecPlaneNormal, perp ) * normal); |
|
} |
|
else |
|
{ |
|
mv->m_vecVelocity.Init(); |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : axis - |
|
// Output : const char |
|
//----------------------------------------------------------------------------- |
|
extern const char *DescribeAxis( int axis ); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::CheckVelocity( void ) |
|
{ |
|
int i; |
|
|
|
// |
|
// bound velocity |
|
// |
|
Vector origin = mv->GetAbsOrigin(); |
|
bool bFixedOrigin = false; |
|
for (i=0; i < 3; i++) |
|
{ |
|
// See if it's bogus. |
|
if (IS_NAN(mv->m_vecVelocity[i])) |
|
{ |
|
DevMsg( 1, "PM Got a NaN velocity %s\n", DescribeAxis( i ) ); |
|
mv->m_vecVelocity[i] = 0; |
|
} |
|
if (IS_NAN(origin[i])) |
|
{ |
|
DevMsg( 1, "PM Got a NaN origin on %s\n", DescribeAxis( i ) ); |
|
origin[i] = 0; |
|
bFixedOrigin = true; |
|
} |
|
|
|
// Bound it. |
|
if (mv->m_vecVelocity[i] > sv_maxvelocity.GetFloat()) |
|
{ |
|
DevMsg( 1, "PM Got a velocity too high on %s %f\n", DescribeAxis( i ), mv->m_vecVelocity[i] ); |
|
mv->m_vecVelocity[i] = sv_maxvelocity.GetFloat(); |
|
} |
|
else if (mv->m_vecVelocity[i] < -sv_maxvelocity.GetFloat()) |
|
{ |
|
DevMsg( 1, "PM Got a velocity too low on %s %f\n", DescribeAxis( i ), mv->m_vecVelocity[i] ); |
|
mv->m_vecVelocity[i] = -sv_maxvelocity.GetFloat(); |
|
} |
|
} |
|
if ( bFixedOrigin ) |
|
mv->SetAbsOrigin( origin ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::AddGravity( void ) |
|
{ |
|
float ent_gravity; |
|
|
|
if ( player->GetWaterJumpTime() ) |
|
return; |
|
|
|
if (marine->GetGravity()) |
|
ent_gravity = marine->GetGravity(); |
|
else |
|
ent_gravity = 1.0; |
|
|
|
// Add gravity incorrectly |
|
mv->m_vecVelocity[2] -= (ent_gravity * asw_marine_gravity.GetFloat() * gpGlobals->frametime); |
|
mv->m_vecVelocity[2] += marine->GetBaseVelocity()[2] * gpGlobals->frametime; |
|
Vector temp = marine->GetBaseVelocity(); |
|
temp[2] = 0; |
|
marine->SetBaseVelocity( temp ); |
|
|
|
CheckVelocity(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : push - |
|
// Output : trace_t |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::PushEntity( Vector& push, trace_t *pTrace ) |
|
{ |
|
Vector end; |
|
|
|
VectorAdd (mv->GetAbsOrigin(), push, end); |
|
TraceMarineBBox( mv->GetAbsOrigin(), end, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, *pTrace ); |
|
mv->SetAbsOrigin( pTrace->endpos ); |
|
|
|
// So we can run impact function afterwards. |
|
// If |
|
if ( pTrace->fraction < 1.0 && !pTrace->allsolid ) |
|
{ |
|
MoveHelper( )->AddToTouched( *pTrace, mv->m_vecVelocity ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : in - |
|
// normal - |
|
// out - |
|
// overbounce - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CASW_MarineGameMovement::ClipVelocity( Vector& in, Vector& normal, Vector& out, float overbounce ) |
|
{ |
|
float backoff; |
|
float change; |
|
float angle; |
|
int i, blocked; |
|
|
|
angle = normal[ 2 ]; |
|
|
|
blocked = 0x00; // Assume unblocked. |
|
if (angle > 0) // If the plane that is blocking us has a positive z component, then assume it's a floor. |
|
blocked |= 0x01; // |
|
if (!angle) // If the plane has no Z, it is vertical (wall/step) |
|
blocked |= 0x02; // |
|
|
|
|
|
// Determine how far along plane to slide based on incoming direction. |
|
backoff = DotProduct (in, normal) * overbounce; |
|
|
|
for (i=0 ; i<3 ; i++) |
|
{ |
|
change = normal[i]*backoff; |
|
out[i] = in[i] - change; |
|
// If out velocity is too small, zero it out. |
|
if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) |
|
out[i] = 0; |
|
} |
|
|
|
#if 0 |
|
// slight adjustment - hopefully to adjust for displacement surfaces |
|
float adjust = DotProduct( out, normal ); |
|
if( adjust < 0.0f ) |
|
{ |
|
out += ( normal * -adjust ); |
|
// Msg( "Adjustment = %lf\n", adjust ); |
|
} |
|
#endif |
|
// asw: added sept 2nd 06 |
|
// iterate once to make sure we aren't still moving through the plane |
|
float adjust = DotProduct( out, normal ); |
|
if( adjust < 0.0f ) |
|
{ |
|
out -= ( normal * adjust ); |
|
// Msg( "Adjustment = %lf\n", adjust ); |
|
} |
|
|
|
|
|
|
|
// Return blocking flags. |
|
return blocked; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Computes roll angle for a certain movement direction and velocity |
|
// Input : angles - |
|
// velocity - |
|
// rollangle - |
|
// rollspeed - |
|
// Output : float |
|
//----------------------------------------------------------------------------- |
|
float CASW_MarineGameMovement::CalcRoll ( const QAngle &angles, const Vector &velocity, float rollangle, float rollspeed ) |
|
{ |
|
float sign; |
|
float side; |
|
float value; |
|
Vector forward, right, up; |
|
|
|
AngleVectors (angles, &forward, &right, &up); |
|
|
|
side = DotProduct (velocity, right); |
|
sign = side < 0 ? -1 : 1; |
|
side = fabs(side); |
|
value = rollangle; |
|
if (side < rollspeed) |
|
{ |
|
side = side * value / rollspeed; |
|
} |
|
else |
|
{ |
|
side = value; |
|
} |
|
return side*sign; |
|
} |
|
|
|
#define CHECKSTUCK_MINTIME 0.05 // Don't check again too quickly. |
|
|
|
static Vector rgv3tMarineStuckTable[54]; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CreateMarineStuckTable( void ) |
|
{ |
|
float x, y, z; |
|
int idx; |
|
int i; |
|
float zi[3]; |
|
static int firsttime = 1; |
|
|
|
if ( !firsttime ) |
|
return; |
|
|
|
firsttime = 0; |
|
|
|
memset(rgv3tMarineStuckTable, 0, sizeof(rgv3tMarineStuckTable)); |
|
|
|
idx = 0; |
|
// Little Moves. |
|
x = y = 0; |
|
// Z moves |
|
for (z = -0.125 ; z <= 0.125 ; z += 0.125) |
|
{ |
|
rgv3tMarineStuckTable[idx][0] = x; |
|
rgv3tMarineStuckTable[idx][1] = y; |
|
rgv3tMarineStuckTable[idx][2] = z; |
|
idx++; |
|
} |
|
x = z = 0; |
|
// Y moves |
|
for (y = -0.125 ; y <= 0.125 ; y += 0.125) |
|
{ |
|
rgv3tMarineStuckTable[idx][0] = x; |
|
rgv3tMarineStuckTable[idx][1] = y; |
|
rgv3tMarineStuckTable[idx][2] = z; |
|
idx++; |
|
} |
|
y = z = 0; |
|
// X moves |
|
for (x = -0.125 ; x <= 0.125 ; x += 0.125) |
|
{ |
|
rgv3tMarineStuckTable[idx][0] = x; |
|
rgv3tMarineStuckTable[idx][1] = y; |
|
rgv3tMarineStuckTable[idx][2] = z; |
|
idx++; |
|
} |
|
|
|
// Remaining multi axis nudges. |
|
for ( x = - 0.125; x <= 0.125; x += 0.250 ) |
|
{ |
|
for ( y = - 0.125; y <= 0.125; y += 0.250 ) |
|
{ |
|
for ( z = - 0.125; z <= 0.125; z += 0.250 ) |
|
{ |
|
rgv3tMarineStuckTable[idx][0] = x; |
|
rgv3tMarineStuckTable[idx][1] = y; |
|
rgv3tMarineStuckTable[idx][2] = z; |
|
idx++; |
|
} |
|
}} |
|
|
|
// Big Moves. |
|
x = y = 0; |
|
zi[0] = 0.0f; |
|
zi[1] = 1.0f; |
|
zi[2] = 6.0f; |
|
|
|
for (i = 0; i < 3; i++) |
|
{ |
|
// Z moves |
|
z = zi[i]; |
|
rgv3tMarineStuckTable[idx][0] = x; |
|
rgv3tMarineStuckTable[idx][1] = y; |
|
rgv3tMarineStuckTable[idx][2] = z; |
|
idx++; |
|
} |
|
|
|
x = z = 0; |
|
|
|
// Y moves |
|
for (y = -2.0f ; y <= 2.0f ; y += 2.0) |
|
{ |
|
rgv3tMarineStuckTable[idx][0] = x; |
|
rgv3tMarineStuckTable[idx][1] = y; |
|
rgv3tMarineStuckTable[idx][2] = z; |
|
idx++; |
|
} |
|
y = z = 0; |
|
// X moves |
|
for (x = -2.0f ; x <= 2.0f ; x += 2.0f) |
|
{ |
|
rgv3tMarineStuckTable[idx][0] = x; |
|
rgv3tMarineStuckTable[idx][1] = y; |
|
rgv3tMarineStuckTable[idx][2] = z; |
|
idx++; |
|
} |
|
|
|
// Remaining multi axis nudges. |
|
for (i = 0 ; i < 3; i++) |
|
{ |
|
z = zi[i]; |
|
|
|
for (x = -2.0f ; x <= 2.0f ; x += 2.0f) |
|
{ |
|
for (y = -2.0f ; y <= 2.0f ; y += 2.0) |
|
{ |
|
rgv3tMarineStuckTable[idx][0] = x; |
|
rgv3tMarineStuckTable[idx][1] = y; |
|
rgv3tMarineStuckTable[idx][2] = z; |
|
idx++; |
|
} |
|
} |
|
} |
|
Assert( idx < sizeof(rgv3tMarineStuckTable)/sizeof(rgv3tMarineStuckTable[0])); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : nIndex - |
|
// server - |
|
// offset - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int MarineGetRandomStuckOffsets( CBasePlayer *pPlayer, Vector& offset) |
|
{ |
|
// Last time we did a full |
|
int idx; |
|
idx = pPlayer->m_StuckLast; |
|
|
|
VectorCopy(rgv3tMarineStuckTable[idx % 54], offset); |
|
|
|
return (idx % 54); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : nIndex - |
|
// server - |
|
//----------------------------------------------------------------------------- |
|
void MarineResetStuckOffsets( CBasePlayer *pPlayer ) |
|
{ |
|
pPlayer->m_StuckLast = 0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &input - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CASW_MarineGameMovement::CheckStuck( void ) |
|
{ |
|
Vector base; |
|
Vector offset; |
|
Vector test; |
|
EntityHandle_t hitent; |
|
int idx; |
|
float fTime; |
|
//int i; |
|
trace_t traceresult; |
|
|
|
CreateMarineStuckTable(); |
|
|
|
hitent = TestPlayerPosition( mv->GetAbsOrigin(), COLLISION_GROUP_PLAYER_MOVEMENT, traceresult ); |
|
/* |
|
#ifdef CLIENT_DLL |
|
Msg("[C] CS pos=%f,%f,%f mins=%f,%f,%f maxs=%f,%f,%f he=%i/%s\n", |
|
mv->m_vecAbsOrigin.x, mv->m_vecAbsOrigin.y, mv->m_vecAbsOrigin.z, |
|
GetPlayerMins().x, GetPlayerMins().y, GetPlayerMins().z, |
|
GetPlayerMaxs().x, GetPlayerMaxs().y, GetPlayerMaxs().z, |
|
hitent , MoveHelper()->GetName(hitent)); |
|
#else |
|
Msg("[S] CS pos=%f,%f,%f mins=%f,%f,%f maxs=%f,%f,%f he=%i/%s\n", |
|
mv->m_vecAbsOrigin.x, mv->m_vecAbsOrigin.y, mv->m_vecAbsOrigin.z, |
|
GetPlayerMins().x, GetPlayerMins().y, GetPlayerMins().z, |
|
GetPlayerMaxs().x, GetPlayerMaxs().y, GetPlayerMaxs().z, |
|
hitent , MoveHelper()->GetName(hitent)); |
|
#endif |
|
*/ |
|
if ( hitent == INVALID_ENTITY_HANDLE ) |
|
{ |
|
MarineResetStuckOffsets( player ); |
|
return 0; |
|
} |
|
|
|
// Deal with stuckness... |
|
#ifndef DEDICATED |
|
if ( developer.GetBool() ) |
|
{ |
|
bool isServer = player->IsServer(); |
|
engine->Con_NPrintf( isServer, "%s stuck on object %i/%s", |
|
isServer ? "server" : "client", |
|
hitent , MoveHelper()->GetName(hitent) ); |
|
} |
|
#endif |
|
|
|
#ifndef CLIENT_DLL |
|
if ( marine ) |
|
{ |
|
marine->m_fLastStuckTime = gpGlobals->curtime; // let the marine know he's stuck, so he can enable his vphysics shadow (to push away any offending phys objects which might be making us stuck) |
|
if ( marine->m_flFirstStuckTime == 0.0f ) |
|
{ |
|
marine->m_flFirstStuckTime = gpGlobals->curtime; |
|
} |
|
if ( gpGlobals->curtime - marine->m_flFirstStuckTime > 1.0f ) |
|
{ |
|
bool bTeleportMarine = true; |
|
edict_t* pEdict = gEntList.GetEdict( hitent ); |
|
if ( pEdict ) |
|
{ |
|
CBaseEntity *pEntity = CBaseEntity::Instance( pEdict ); |
|
if ( pEntity && pEntity->m_takedamage == DAMAGE_YES && pEntity->Classify() == CLASS_ASW_PHYSICS_PROP ) |
|
{ |
|
const char *szModelName = STRING( pEntity->GetModelName() ); |
|
if ( szModelName && !CanMarineGetStuckOnProp( szModelName ) ) |
|
{ |
|
bTeleportMarine = false; // marine is stuck in a breakable crate, don't teleport him |
|
} |
|
} |
|
} |
|
if ( bTeleportMarine ) |
|
{ |
|
marine->TeleportStuckMarine(); |
|
marine->m_flFirstStuckTime = 0.0f; |
|
mv->SetAbsOrigin( marine->GetAbsOrigin() ); |
|
return 0; |
|
} |
|
else |
|
{ |
|
marine->m_flFirstStuckTime = gpGlobals->curtime; |
|
} |
|
} |
|
} |
|
#endif |
|
|
|
VectorCopy( mv->GetAbsOrigin(), base ); |
|
|
|
// |
|
// Deal with precision error in network. |
|
// |
|
// World or BSP model |
|
if ( !player->IsServer() ) |
|
{ |
|
if ( MoveHelper()->IsWorldEntity( hitent ) ) |
|
{ |
|
//Msg("StuckWorld: y = %f :", mv->m_vecAbsOrigin.y); |
|
int nReps = 0; |
|
MarineResetStuckOffsets( player ); |
|
do |
|
{ |
|
player->m_StuckLast = MarineGetRandomStuckOffsets( player, offset) + 1; |
|
|
|
VectorAdd(base, offset, test); |
|
//Msg("Off:%f,%f,%f ", VectorExpand(offset)); |
|
if (TestPlayerPosition( test, COLLISION_GROUP_PLAYER_MOVEMENT, traceresult ) == INVALID_ENTITY_HANDLE) |
|
{ |
|
//Msg(" FREE!\n"); |
|
MarineResetStuckOffsets( player ); |
|
mv->SetAbsOrigin( test ); |
|
return 0; |
|
} |
|
nReps++; |
|
} while (nReps < 54); |
|
//Msg(" Failed\n"); |
|
} |
|
} |
|
|
|
// Only an issue on the client. |
|
idx = player->IsServer() ? 0 : 1; |
|
|
|
fTime = Plat_FloatTime(); |
|
// Too soon? |
|
if ( m_flStuckCheckTime[player->entindex()][idx] >= fTime - CHECKSTUCK_MINTIME ) |
|
{ |
|
return 1; |
|
} |
|
m_flStuckCheckTime[player->entindex()][idx] = fTime; |
|
|
|
MoveHelper( )->AddToTouched( traceresult, mv->m_vecVelocity ); |
|
|
|
player->m_StuckLast = MarineGetRandomStuckOffsets( player, offset) + 1; |
|
|
|
VectorAdd(base, offset, test); |
|
|
|
if (TestPlayerPosition( test, COLLISION_GROUP_PLAYER_MOVEMENT, traceresult ) == INVALID_ENTITY_HANDLE) |
|
{ |
|
MarineResetStuckOffsets( player ); |
|
|
|
if ( player->m_StuckLast - 1 >= 27 ) |
|
{ |
|
mv->SetAbsOrigin( test ); |
|
} |
|
return 0; |
|
} |
|
|
|
/* |
|
// If player is flailing while stuck in another player ( should never happen ), then see |
|
// if we can't "unstick" them forceably. |
|
if ( mv->m_nButtons & ( IN_JUMP | IN_DUCK | IN_ATTACK ) && ( pmv->physents[ hitent ].player != 0 ) ) |
|
{ |
|
float x, y, z; |
|
float xystep = 8.0; |
|
float zstep = 18.0; |
|
float xyminmax = xystep; |
|
float zminmax = 4 * zstep; |
|
|
|
for ( z = 0; z <= zminmax; z += zstep ) |
|
{ |
|
for ( x = -xyminmax; x <= xyminmax; x += xystep ) |
|
{ |
|
for ( y = -xyminmax; y <= xyminmax; y += xystep ) |
|
{ |
|
VectorCopy( base, test ); |
|
test[0] += x; |
|
test[1] += y; |
|
test[2] += z; |
|
|
|
if ( pmv->TestPosition ( test, NULL ) == -1 ) |
|
{ |
|
VectorCopy( test, mv->m_vecAbsOrigin ); |
|
return 0; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
*/ |
|
return 1; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : bool |
|
//----------------------------------------------------------------------------- |
|
bool CASW_MarineGameMovement::InWater( void ) |
|
{ |
|
return ( marine->GetWaterLevel() > WL_Feet ); |
|
} |
|
|
|
|
|
void CASW_MarineGameMovement::ResetGetPointContentsCache() |
|
{ |
|
m_CachedGetPointContents = -9999; |
|
} |
|
|
|
|
|
int CASW_MarineGameMovement::GetPointContentsCached( const Vector &point ) |
|
{ |
|
if ( g_bMovementOptimizations ) |
|
{ |
|
if ( m_CachedGetPointContents == -9999 || point.DistToSqr( m_CachedGetPointContentsPoint ) > 1 ) |
|
{ |
|
m_CachedGetPointContents = enginetrace->GetPointContents ( point ); |
|
m_CachedGetPointContentsPoint = point; |
|
} |
|
|
|
return m_CachedGetPointContents; |
|
} |
|
else |
|
{ |
|
return enginetrace->GetPointContents ( point ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &input - |
|
// Output : bool |
|
//----------------------------------------------------------------------------- |
|
bool CASW_MarineGameMovement::CheckWater( void ) |
|
{ |
|
Vector point; |
|
int cont; |
|
|
|
// Pick a spot just above the players feet. |
|
point[0] = mv->GetAbsOrigin()[0] + (GetPlayerMins()[0] + GetPlayerMaxs()[0]) * 0.5; |
|
point[1] = mv->GetAbsOrigin()[1] + (GetPlayerMins()[1] + GetPlayerMaxs()[1]) * 0.5; |
|
point[2] = mv->GetAbsOrigin()[2] + GetPlayerMins()[2] + 1; |
|
|
|
// Assume that we are not in water at all. |
|
marine->SetWaterLevel( WL_NotInWater ); |
|
marine->SetWaterType( CONTENTS_EMPTY ); |
|
|
|
// Grab point contents. |
|
cont = GetPointContentsCached( point ); |
|
|
|
// Are we under water? (not solid and not empty?) |
|
if ( cont & MASK_WATER ) |
|
{ |
|
// Set water type |
|
marine->SetWaterType( cont ); |
|
|
|
// We are at least at level one |
|
marine->SetWaterLevel( WL_Feet ); |
|
|
|
// Now check a point that is at the player hull midpoint. |
|
point[2] = mv->GetAbsOrigin()[2] + (GetPlayerMins()[2] + GetPlayerMaxs()[2])*0.5; |
|
cont = enginetrace->GetPointContents( point ); |
|
// If that point is also under water... |
|
if ( cont & MASK_WATER ) |
|
{ |
|
// Set a higher water level. |
|
marine->SetWaterLevel( WL_Waist ); |
|
|
|
// Now check the eye position. (view_ofs is relative to the origin) |
|
point[2] = mv->GetAbsOrigin()[2] + player->GetViewOffset()[2]; |
|
cont = enginetrace->GetPointContents( point ); |
|
if ( cont & MASK_WATER ) |
|
marine->SetWaterLevel( WL_Eyes ); // In over our eyes |
|
} |
|
|
|
// Adjust velocity based on water current, if any. |
|
if ( cont & MASK_CURRENT ) |
|
{ |
|
Vector v; |
|
VectorClear(v); |
|
if ( cont & CONTENTS_CURRENT_0 ) |
|
v[0] += 1; |
|
if ( cont & CONTENTS_CURRENT_90 ) |
|
v[1] += 1; |
|
if ( cont & CONTENTS_CURRENT_180 ) |
|
v[0] -= 1; |
|
if ( cont & CONTENTS_CURRENT_270 ) |
|
v[1] -= 1; |
|
if ( cont & CONTENTS_CURRENT_UP ) |
|
v[2] += 1; |
|
if ( cont & CONTENTS_CURRENT_DOWN ) |
|
v[2] -= 1; |
|
|
|
// BUGBUG -- this depends on the value of an unspecified enumerated type |
|
// The deeper we are, the stronger the current. |
|
Vector temp; |
|
VectorMA( marine->GetBaseVelocity(), 50.0*marine->GetWaterLevel(), v, temp ); |
|
marine->SetBaseVelocity( temp ); |
|
} |
|
} |
|
|
|
return ( marine->GetWaterLevel() > WL_Feet ); |
|
} |
|
|
|
void CASW_MarineGameMovement::SetGroundEntity( trace_t *pm ) |
|
{ |
|
CBaseEntity *newGround = pm ? pm->m_pEnt : NULL; |
|
|
|
CBaseEntity *oldGround = marine->GetGroundEntity(); |
|
Vector vecBaseVelocity = marine->GetBaseVelocity(); |
|
|
|
if ( !oldGround && newGround ) |
|
{ |
|
// Subtract ground velocity at instant we hit ground jumping |
|
vecBaseVelocity -= newGround->GetAbsVelocity(); |
|
vecBaseVelocity.z = newGround->GetAbsVelocity().z; |
|
// paranoid to get rid of a crazy sliding physics bug: clear base velocity if we just left the world |
|
if (newGround->entindex() == 0) |
|
vecBaseVelocity = vec3_origin; |
|
} |
|
else if ( oldGround && !newGround ) |
|
{ |
|
// Add in ground velocity at instant we started jumping |
|
vecBaseVelocity += oldGround->GetAbsVelocity(); |
|
vecBaseVelocity.z = oldGround->GetAbsVelocity().z; |
|
// paranoid to get rid of a crazy sliding physics bug: clear base velocity if we just left the world |
|
if (oldGround->entindex() == 0) |
|
vecBaseVelocity = vec3_origin; |
|
} |
|
|
|
marine->SetBaseVelocity( vecBaseVelocity ); |
|
marine->SetGroundEntity( newGround ); |
|
|
|
// If we are on something... |
|
|
|
if ( newGround ) |
|
{ |
|
CategorizeGroundSurface( *pm ); |
|
|
|
// Then we are not in water jump sequence |
|
player->m_flWaterJumpTime = 0; |
|
|
|
// Standing on an entity other than the world, so signal that we are touching something. |
|
if ( !pm->DidHitWorld() ) |
|
{ |
|
MoveHelper()->AddToTouched( *pm, mv->m_vecVelocity ); |
|
} |
|
|
|
if( marine->GetMoveType() != MOVETYPE_NOCLIP ) |
|
mv->m_vecVelocity.z = 0.0f; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &input - |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::CategorizePosition( void ) |
|
{ |
|
Vector point; |
|
trace_t pm; |
|
|
|
// Reset this each time we-recategorize, otherwise we have bogus friction when we jump into water and plunge downward really quickly |
|
player->m_surfaceFriction = 1.0f; |
|
|
|
// if the player hull point one unit down is solid, the player |
|
// is on ground |
|
|
|
// see if standing on something solid |
|
|
|
// Doing this before we move may introduce a potential latency in water detection, but |
|
// doing it after can get us stuck on the bottom in water if the amount we move up |
|
// is less than the 1 pixel 'threshold' we're about to snap to. Also, we'll call |
|
// this several times per frame, so we really need to avoid sticking to the bottom of |
|
// water on each call, and the converse case will correct itself if called twice. |
|
CheckWater(); |
|
|
|
point[0] = mv->GetAbsOrigin()[0]; |
|
point[1] = mv->GetAbsOrigin()[1]; |
|
point[2] = mv->GetAbsOrigin()[2] - 2; // move a total of 4 units to try and avoid some |
|
// epsilon error |
|
|
|
Vector bumpOrigin; |
|
bumpOrigin = mv->GetAbsOrigin(); |
|
//bumpOrigin.z += 2; |
|
|
|
// Shooting up really fast. Definitely not on ground. |
|
// On ladder moving up, so not on ground either |
|
// NOTE: 145 is a jump. |
|
#define NON_JUMP_VELOCITY 140.0f |
|
|
|
float zvel = mv->m_vecVelocity[2]; |
|
bool bMovingUp = zvel > 0.0f; |
|
bool bMovingUpRapidly = zvel > NON_JUMP_VELOCITY; |
|
float flGroundEntityVelZ = 0.0f; |
|
if ( bMovingUpRapidly ) |
|
{ |
|
// Tracker 73219, 75878: ywb 8/2/07 |
|
// After save/restore (and maybe at other times), we can get a case where we were saved on a lift and |
|
// after restore we'll have a high local velocity due to the lift making our abs velocity appear high. |
|
// We need to account for standing on a moving ground object in that case in order to determine if we really |
|
// are moving away from the object we are standing on at too rapid a speed. Note that CheckJump already sets |
|
// ground entity to NULL, so this wouldn't have any effect unless we are moving up rapidly not from the jump button. |
|
CBaseEntity *ground = marine->GetGroundEntity(); |
|
if ( ground ) |
|
{ |
|
flGroundEntityVelZ = ground->GetAbsVelocity().z; |
|
bMovingUpRapidly = ( zvel - flGroundEntityVelZ ) > NON_JUMP_VELOCITY; |
|
} |
|
} |
|
|
|
// NOTE YWB 7/5/07: Since we're already doing a traceline here, we'll subsume the StayOnGround (stair debouncing) check into the main traceline we do here to see what we're standing on |
|
bool bUnderwater = ( player->GetWaterLevel() >= WL_Eyes ); |
|
bool bMoveToEndPos = false; |
|
if ( marine->GetMoveType() == MOVETYPE_WALK && |
|
marine->GetGroundEntity() != NULL && !bUnderwater ) |
|
{ |
|
// if walking and still think we're on ground, we'll extend trace down by stepsize so we don't bounce down slopes |
|
bMoveToEndPos = true; |
|
point.z -= player->m_Local.m_flStepSize; |
|
} |
|
|
|
// Was on ground, but now suddenly am not |
|
if ( bMovingUpRapidly || |
|
( bMovingUp && marine->GetMoveType() == MOVETYPE_LADDER ) ) |
|
{ |
|
SetGroundEntity( NULL ); |
|
bMoveToEndPos = false; |
|
} |
|
else |
|
{ |
|
// Try and move down. |
|
TraceMarineBBox( bumpOrigin, point, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
|
|
// Was on ground, but now suddenly am not. If we hit a steep plane, we are not on ground |
|
float flStandableZ = 0.7; |
|
|
|
if ( !pm.m_pEnt || ( pm.plane.normal[2] < flStandableZ ) ) |
|
{ |
|
// Test four sub-boxes, to see if any of them would have found shallower slope we could actually stand on |
|
ITraceFilter *pFilter = LockTraceFilter( COLLISION_GROUP_PLAYER_MOVEMENT ); |
|
TraceMarineBBoxForGround( m_pTraceListData, bumpOrigin, point, GetPlayerMins(), |
|
GetPlayerMaxs(), MASK_PLAYERSOLID, pFilter, pm, flStandableZ, true, &m_nTraceCount ); |
|
UnlockTraceFilter( pFilter ); |
|
if ( !pm.m_pEnt || ( pm.plane.normal[2] < flStandableZ ) ) |
|
{ |
|
SetGroundEntity( NULL ); |
|
// probably want to add a check for a +z velocity too! |
|
if ( ( mv->m_vecVelocity.z > 0.0f ) && |
|
( player->GetMoveType() != MOVETYPE_NOCLIP ) ) |
|
{ |
|
player->m_surfaceFriction = 0.25f; |
|
} |
|
bMoveToEndPos = false; |
|
} |
|
else |
|
{ |
|
SetGroundEntity( &pm ); |
|
} |
|
} |
|
else |
|
{ |
|
SetGroundEntity( &pm ); // Otherwise, point to index of ent under us. |
|
} |
|
|
|
#ifndef CLIENT_DLL |
|
|
|
//Adrian: vehicle code handles for us. |
|
if ( player->IsInAVehicle() == false ) |
|
{ |
|
// If our gamematerial has changed, tell any player surface triggers that are watching |
|
IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps(); |
|
surfacedata_t *pSurfaceProp = physprops->GetSurfaceData( pm.surface.surfaceProps ); |
|
char cCurrGameMaterial = pSurfaceProp->game.material; |
|
if ( !marine->GetGroundEntity() ) |
|
{ |
|
cCurrGameMaterial = 0; |
|
} |
|
|
|
// Changed? |
|
if ( marine->m_chPreviousTextureType != cCurrGameMaterial ) |
|
{ |
|
CEnvPlayerSurfaceTrigger::SetPlayerSurface( player, cCurrGameMaterial ); |
|
} |
|
|
|
marine->m_chPreviousTextureType = cCurrGameMaterial; |
|
} |
|
#endif |
|
} |
|
|
|
// YWB: This logic block essentially lifted from StayOnGround implementation |
|
if ( bMoveToEndPos && |
|
!pm.startsolid && // not sure we need this check as fraction would == 0.0f? |
|
pm.fraction > 0.0f && // must go somewhere |
|
pm.fraction < 1.0f ) // must hit something |
|
{ |
|
mv->SetAbsOrigin( pm.endpos ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Determine if the player has hit the ground while falling, apply |
|
// damage, and play the appropriate impact sound. |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::CheckFalling( void ) |
|
{ |
|
float fFallVel = player->m_Local.m_flFallVelocity; |
|
//Msg("Checking falling, fall vel = %f\n", fFallVel); |
|
if ( marine->GetGroundEntity() != NULL && |
|
!IsDead() && |
|
fFallVel >= PLAYER_FALL_PUNCH_THRESHOLD ) |
|
{ |
|
bool bAlive = true; |
|
float fvol = 0.5; |
|
|
|
if ( marine->GetWaterLevel() > 0 ) |
|
{ |
|
// They landed in water. |
|
} |
|
else |
|
{ |
|
// Scale it down if we landed on something that's floating... |
|
if ( marine->GetGroundEntity()->IsFloating() ) |
|
{ |
|
fFallVel -= PLAYER_LAND_ON_FLOATING_OBJECT; |
|
} |
|
|
|
// |
|
// They hit the ground. |
|
// |
|
|
|
// asw added this if block: sept 2nd 06 |
|
if( marine->GetGroundEntity()->GetAbsVelocity().z < 0.0f ) |
|
{ |
|
// Player landed on a descending object. Subtract the velocity of the ground entity. |
|
player->m_Local.m_flFallVelocity += marine->GetGroundEntity()->GetAbsVelocity().z; |
|
player->m_Local.m_flFallVelocity = MAX( 0.1f, player->m_Local.m_flFallVelocity ); |
|
} |
|
|
|
if ( fFallVel > PLAYER_MAX_SAFE_FALL_SPEED ) |
|
{ |
|
// |
|
// If they hit the ground going this fast they may take damage (and die). |
|
// |
|
//bAlive = MoveHelper( )->PlayerFallingDamage(); |
|
#ifndef CLIENT_DLL |
|
float fFallVelMod = fFallVel; |
|
fFallVelMod -= PLAYER_MAX_SAFE_FALL_SPEED; |
|
float flFallDamage = fFallVelMod * DAMAGE_FOR_FALL_SPEED; |
|
if ( asw_debug_marine_damage.GetBool() ) |
|
{ |
|
Msg("Marine fell with speed %f modded to %f damage is %f\n", fFallVel, fFallVelMod, flFallDamage); |
|
} |
|
if ( flFallDamage > 0 ) |
|
{ |
|
if ( asw_marine_fall_damage.GetBool() ) |
|
{ |
|
marine->TakeDamage( CTakeDamageInfo( GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), flFallDamage, DMG_FALL ) ); |
|
} |
|
CRecipientFilter filter; |
|
filter.AddRecipientsByPAS( marine->GetAbsOrigin() ); |
|
|
|
CBaseEntity::EmitSound( filter, marine->entindex(), "Player.FallDamage" ); |
|
} |
|
bAlive = marine->GetHealth() > 0; |
|
#endif |
|
fvol = 1.0; |
|
} |
|
else if ( fFallVel > PLAYER_MAX_SAFE_FALL_SPEED / 2 ) |
|
{ |
|
fvol = 0.85; |
|
} |
|
else if ( fFallVel < PLAYER_MIN_BOUNCE_SPEED ) |
|
{ |
|
fvol = 0; |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if ( fvol > 0.0 ) |
|
{ |
|
// |
|
// Play landing sound right away. |
|
player->m_flStepSoundTime = 400; |
|
|
|
// Play step sound for current texture. |
|
Vector vecSrc = mv->GetAbsOrigin(); |
|
player->PlayStepSound( vecSrc, marine->m_pSurfaceData, fvol, true ); |
|
|
|
// |
|
// Knock the screen around a little bit, temporary effect. |
|
// |
|
// (either of) these lines present on the server fixes the flickering gun |
|
player->m_Local.m_vecPunchAngle.Set( ROLL, fFallVel * 0.013 ); |
|
|
|
if ( player->m_Local.m_vecPunchAngle[PITCH] > 8 ) |
|
{ |
|
// (either of) these lines present on the server fixes the flickering gun |
|
player->m_Local.m_vecPunchAngle.Set( PITCH, 8 ); |
|
} |
|
} |
|
|
|
|
|
if (bAlive) |
|
{ |
|
MoveHelper( )->PlayerSetAnimation( PLAYER_WALK ); |
|
} |
|
} |
|
|
|
// |
|
// Clear the fall velocity so the impact doesn't happen again. |
|
// |
|
if ( marine->GetGroundEntity() != NULL ) |
|
{ |
|
player->m_Local.m_flFallVelocity = 0; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Use for ease-in, ease-out style interpolation (accel/decel) Used by ducking code. |
|
// Input : value - |
|
// scale - |
|
// Output : float |
|
//----------------------------------------------------------------------------- |
|
float CASW_MarineGameMovement::SplineFraction( float value, float scale ) |
|
{ |
|
float valueSquared; |
|
|
|
value = scale * value; |
|
valueSquared = value * value; |
|
|
|
// Nice little ease-in, ease-out spline-like curve |
|
return 3 * valueSquared - 2 * valueSquared * value; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Determine if crouch/uncrouch caused player to get stuck in world |
|
// Input : direction - |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FixPlayerCrouchStuck( bool upward ) |
|
{ |
|
EntityHandle_t hitent; |
|
int i; |
|
Vector test; |
|
trace_t dummy; |
|
|
|
int direction = upward ? 1 : 0; |
|
|
|
hitent = TestPlayerPosition( mv->GetAbsOrigin(), COLLISION_GROUP_PLAYER_MOVEMENT, dummy ); |
|
if (hitent == INVALID_ENTITY_HANDLE ) |
|
return; |
|
|
|
VectorCopy( mv->GetAbsOrigin(), test ); |
|
for ( i = 0; i < 36; i++ ) |
|
{ |
|
Vector dest = mv->GetAbsOrigin(); |
|
dest[2] += direction; |
|
mv->SetAbsOrigin( dest ); |
|
hitent = TestPlayerPosition( mv->GetAbsOrigin(), COLLISION_GROUP_PLAYER_MOVEMENT, dummy ); |
|
if (hitent == INVALID_ENTITY_HANDLE ) |
|
return; |
|
} |
|
|
|
mv->SetAbsOrigin( test ); // Failed |
|
} |
|
|
|
bool CASW_MarineGameMovement::CanUnduck() |
|
{ |
|
int i; |
|
trace_t trace; |
|
Vector newOrigin; |
|
|
|
VectorCopy( mv->GetAbsOrigin(), newOrigin ); |
|
|
|
if ( marine->GetGroundEntity() != NULL ) |
|
{ |
|
for ( i = 0; i < 3; i++ ) |
|
{ |
|
newOrigin[i] += ( VEC_DUCK_HULL_MIN[i] - VEC_HULL_MIN[i] ); |
|
} |
|
} |
|
else |
|
{ |
|
// If in air an letting go of croush, make sure we can offset origin to make |
|
// up for uncrouching |
|
Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN; |
|
Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN; |
|
Vector viewDelta = ( hullSizeNormal - hullSizeCrouch ); |
|
viewDelta.Negate(); |
|
VectorAdd( newOrigin, viewDelta, newOrigin ); |
|
} |
|
|
|
bool saveducked = player->m_Local.m_bDucked; |
|
player->m_Local.m_bDucked = false; |
|
TraceMarineBBox( mv->GetAbsOrigin(), newOrigin, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace ); |
|
player->m_Local.m_bDucked = saveducked; |
|
if ( trace.startsolid || ( trace.fraction != 1.0f ) ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Stop ducking |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FinishUnDuck( void ) |
|
{ |
|
int i; |
|
trace_t trace; |
|
Vector newOrigin; |
|
|
|
VectorCopy( mv->GetAbsOrigin(), newOrigin ); |
|
|
|
if ( marine->GetGroundEntity() != NULL ) |
|
{ |
|
for ( i = 0; i < 3; i++ ) |
|
{ |
|
newOrigin[i] += ( VEC_DUCK_HULL_MIN[i] - VEC_HULL_MIN[i] ); |
|
} |
|
} |
|
else |
|
{ |
|
// If in air an letting go of croush, make sure we can offset origin to make |
|
// up for uncrouching |
|
Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN; |
|
Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN; |
|
Vector viewDelta = ( hullSizeNormal - hullSizeCrouch ); |
|
viewDelta.Negate(); |
|
VectorAdd( newOrigin, viewDelta, newOrigin ); |
|
} |
|
|
|
player->m_Local.m_bDucked = false; |
|
marine->RemoveFlag( FL_DUCKING ); |
|
player->m_Local.m_bDucking = false; |
|
player->SetViewOffset( GetPlayerViewOffset( false ) ); |
|
player->m_Local.m_nDuckTimeMsecs = 0; |
|
|
|
mv->SetAbsOrigin( newOrigin ); |
|
|
|
// Recategorize position since ducking can change origin |
|
CategorizePosition(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::UpdateDuckJumpEyeOffset( void ) |
|
{ |
|
if ( player->m_Local.m_nDuckJumpTimeMsecs != 0 ) |
|
{ |
|
int nDuckMilliseconds = MAX( 0, GAMEMOVEMENT_DUCK_TIME - player->m_Local.m_nDuckJumpTimeMsecs ); |
|
if ( nDuckMilliseconds > TIME_TO_UNDUCK_MSECS ) |
|
{ |
|
player->m_Local.m_nDuckJumpTimeMsecs = 0.0f; |
|
return; |
|
} |
|
|
|
float flDuckFraction = SimpleSpline( 1.0f - FractionUnDucked( nDuckMilliseconds ) ); |
|
|
|
Vector vDuckHullMin = GetPlayerMins( true ); |
|
Vector vStandHullMin = GetPlayerMins( false ); |
|
|
|
float fMore = ( vDuckHullMin.z - vStandHullMin.z ); |
|
|
|
Vector vecDuckViewOffset = GetPlayerViewOffset( true ); |
|
Vector vecStandViewOffset = GetPlayerViewOffset( false ); |
|
Vector vecTemp = player->GetViewOffset(); |
|
vecTemp.z = ( ( vecDuckViewOffset.z - fMore ) * flDuckFraction ) + ( vecStandViewOffset.z * ( 1 - flDuckFraction ) ); |
|
player->SetViewOffset( vecTemp ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FinishUnDuckJump( trace_t &trace ) |
|
{ |
|
Vector vecNewOrigin; |
|
VectorCopy( mv->GetAbsOrigin(), vecNewOrigin ); |
|
|
|
// Up for uncrouching. |
|
Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN; |
|
Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN; |
|
Vector viewDelta = ( hullSizeNormal - hullSizeCrouch ); |
|
|
|
float flDeltaZ = viewDelta.z; |
|
viewDelta.z *= trace.fraction; |
|
flDeltaZ -= viewDelta.z; |
|
|
|
marine->RemoveFlag( FL_DUCKING ); |
|
player->m_Local.m_bDucked = false; |
|
player->m_Local.m_bDucking = false; |
|
player->m_Local.m_bInDuckJump = false; |
|
player->m_Local.m_nDuckTimeMsecs = 0; |
|
player->m_Local.m_nDuckJumpTimeMsecs = 0; |
|
player->m_Local.m_nJumpTimeMsecs = 0; |
|
|
|
Vector vecViewOffset = GetPlayerViewOffset( false ); |
|
vecViewOffset.z -= flDeltaZ; |
|
player->SetViewOffset( vecViewOffset ); |
|
|
|
VectorSubtract( vecNewOrigin, viewDelta, vecNewOrigin ); |
|
mv->SetAbsOrigin( vecNewOrigin ); |
|
|
|
// Recategorize position since ducking can change origin |
|
CategorizePosition(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Finish ducking |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FinishDuck( void ) |
|
{ |
|
int i; |
|
|
|
marine->AddFlag( FL_DUCKING ); |
|
player->m_Local.m_bDucked = true; |
|
player->m_Local.m_bDucking = false; |
|
|
|
player->SetViewOffset( GetPlayerViewOffset( true ) ); |
|
|
|
// HACKHACK - Fudge for collision bug - no time to fix this properly |
|
if ( marine->GetGroundEntity() != NULL ) |
|
{ |
|
Vector origin = mv->GetAbsOrigin(); |
|
for ( i = 0; i < 3; i++ ) |
|
{ |
|
origin[i] -= ( VEC_DUCK_HULL_MIN[i] - VEC_HULL_MIN[i] ); |
|
} |
|
mv->SetAbsOrigin( origin ); |
|
} |
|
else |
|
{ |
|
Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN; |
|
Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN; |
|
Vector viewDelta = ( hullSizeNormal - hullSizeCrouch ); |
|
Vector dest; |
|
VectorAdd( mv->GetAbsOrigin(), viewDelta, dest ); |
|
mv->SetAbsOrigin( dest ); |
|
} |
|
|
|
// See if we are stuck? |
|
FixPlayerCrouchStuck( true ); |
|
|
|
// Recategorize position since ducking can change origin |
|
CategorizePosition(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::StartUnDuckJump( void ) |
|
{ |
|
marine->AddFlag( FL_DUCKING ); |
|
player->m_Local.m_bDucked = true; |
|
player->m_Local.m_bDucking = false; |
|
|
|
player->SetViewOffset( GetPlayerViewOffset( true ) ); |
|
|
|
Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN; |
|
Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN; |
|
Vector viewDelta = ( hullSizeNormal - hullSizeCrouch ); |
|
Vector dest; |
|
VectorAdd( mv->GetAbsOrigin(), viewDelta, dest ); |
|
mv->SetAbsOrigin( dest ); |
|
|
|
// See if we are stuck? |
|
FixPlayerCrouchStuck( true ); |
|
|
|
// Recategorize position since ducking can change origin |
|
CategorizePosition(); |
|
} |
|
|
|
// |
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : duckFraction - |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::SetDuckedEyeOffset( float duckFraction ) |
|
{ |
|
Vector vDuckHullMin = GetPlayerMins( true ); |
|
Vector vStandHullMin = GetPlayerMins( false ); |
|
|
|
float fMore = ( vDuckHullMin.z - vStandHullMin.z ); |
|
|
|
Vector vecDuckViewOffset = GetPlayerViewOffset( true ); |
|
Vector vecStandViewOffset = GetPlayerViewOffset( false ); |
|
Vector temp = player->GetViewOffset(); |
|
temp.z = ( ( vecDuckViewOffset.z - fMore ) * duckFraction ) + |
|
( vecStandViewOffset.z * ( 1 - duckFraction ) ); |
|
player->SetViewOffset( temp ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Crop the speed of the player when ducking and on the ground. |
|
// Input: bInDuck - is the player already ducking |
|
// bInAir - is the player in air |
|
// NOTE: Only crop player speed once. |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::HandleDuckingSpeedCrop( void ) |
|
{ |
|
if ( !m_bSpeedCropped && ( marine->GetFlags() & FL_DUCKING ) && ( marine->GetGroundEntity() != NULL ) ) |
|
{ |
|
float frac = 0.33333333f; |
|
mv->m_flForwardMove *= frac; |
|
mv->m_flSideMove *= frac; |
|
mv->m_flUpMove *= frac; |
|
m_bSpeedCropped = true; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Check to see if we are in a situation where we can unduck jump. |
|
//----------------------------------------------------------------------------- |
|
bool CASW_MarineGameMovement::CanUnDuckJump( trace_t &trace ) |
|
{ |
|
// Trace down to the stand position and see if we can stand. |
|
Vector vecEnd( mv->GetAbsOrigin() ); |
|
vecEnd.z -= 36.0f; // This will have to change if bounding hull change! |
|
TraceMarineBBox( mv->GetAbsOrigin(), vecEnd, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace ); |
|
if ( trace.fraction < 1.0f ) |
|
{ |
|
// Find the endpoint. |
|
vecEnd.z = mv->GetAbsOrigin().z + ( -36.0f * trace.fraction ); |
|
|
|
// Test a normal hull. |
|
trace_t traceUp; |
|
bool bWasDucked = player->m_Local.m_bDucked; |
|
player->m_Local.m_bDucked = false; |
|
TraceMarineBBox( vecEnd, vecEnd, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, traceUp ); |
|
player->m_Local.m_bDucked = bWasDucked; |
|
if ( !traceUp.startsolid ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: See if duck button is pressed and do the appropriate things |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::Duck( void ) |
|
{ |
|
int buttonsChanged = ( mv->m_nOldButtons ^ mv->m_nButtons ); // These buttons have changed this frame |
|
int buttonsPressed = buttonsChanged & mv->m_nButtons; // The changed ones still down are "pressed" |
|
int buttonsReleased = buttonsChanged & mv->m_nOldButtons; // The changed ones which were previously down are "released" |
|
|
|
// Check to see if we are in the air. |
|
bool bInAir = ( marine->GetGroundEntity() == NULL ); |
|
bool bInDuck = ( marine->GetFlags() & FL_DUCKING ) ? true : false; |
|
bool bDuckJump = ( player->m_Local.m_nJumpTimeMsecs > 0 ); |
|
bool bDuckJumpTime = ( player->m_Local.m_nDuckJumpTimeMsecs > 0 ); |
|
|
|
if ( mv->m_nButtons & IN_DUCK ) |
|
{ |
|
mv->m_nOldButtons |= IN_DUCK; |
|
} |
|
else |
|
{ |
|
mv->m_nOldButtons &= ~IN_DUCK; |
|
} |
|
|
|
// Handle death. |
|
if ( IsDead() ) |
|
return; |
|
|
|
// Slow down ducked players. |
|
HandleDuckingSpeedCrop(); |
|
|
|
// If the player is holding down the duck button, the player is in duck transition, ducking, or duck-jumping. |
|
if ( ( mv->m_nButtons & IN_DUCK ) || player->m_Local.m_bDucking || bInDuck || bDuckJump ) |
|
{ |
|
// DUCK |
|
if ( ( mv->m_nButtons & IN_DUCK ) || bDuckJump ) |
|
{ |
|
// Have the duck button pressed, but the player currently isn't in the duck position. |
|
if ( ( buttonsPressed & IN_DUCK ) && !bInDuck && !bDuckJump && !bDuckJumpTime ) |
|
{ |
|
player->m_Local.m_nDuckTimeMsecs = GAMEMOVEMENT_DUCK_TIME; |
|
player->m_Local.m_bDucking = true; |
|
} |
|
|
|
// The player is in duck transition and not duck-jumping. |
|
if ( player->m_Local.m_bDucking && !bDuckJump && !bDuckJumpTime ) |
|
{ |
|
int nDuckMilliseconds = MAX( 0, GAMEMOVEMENT_DUCK_TIME - player->m_Local.m_nDuckTimeMsecs ); |
|
|
|
// Finish in duck transition when transition time is over, in "duck", in air. |
|
if ( ( nDuckMilliseconds > TIME_TO_DUCK_MSECS ) || bInDuck || bInAir ) |
|
{ |
|
FinishDuck(); |
|
} |
|
else |
|
{ |
|
// Calc parametric time |
|
float flDuckFraction = SimpleSpline( FractionDucked( nDuckMilliseconds ) ); |
|
SetDuckedEyeOffset( flDuckFraction ); |
|
} |
|
} |
|
|
|
if ( bDuckJump ) |
|
{ |
|
// Make the bounding box small immediately. |
|
if ( !bInDuck ) |
|
{ |
|
StartUnDuckJump(); |
|
} |
|
else |
|
{ |
|
// Check for a crouch override. |
|
if ( !( mv->m_nButtons & IN_DUCK ) ) |
|
{ |
|
trace_t trace; |
|
if ( CanUnDuckJump( trace ) ) |
|
{ |
|
FinishUnDuckJump( trace ); |
|
player->m_Local.m_nDuckJumpTimeMsecs = (int)( ( (float)GAMEMOVEMENT_TIME_TO_UNDUCK_MSECS * ( 1.0f - trace.fraction ) ) + (float)GAMEMOVEMENT_TIME_TO_UNDUCK_MSECS_INV ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
// UNDUCK (or attempt to...) |
|
else |
|
{ |
|
if ( player->m_Local.m_bInDuckJump ) |
|
{ |
|
// Check for a crouch override. |
|
if ( !( mv->m_nButtons & IN_DUCK ) ) |
|
{ |
|
trace_t trace; |
|
if ( CanUnDuckJump( trace ) ) |
|
{ |
|
FinishUnDuckJump( trace ); |
|
|
|
if ( trace.fraction < 1.0f ) |
|
{ |
|
player->m_Local.m_nDuckJumpTimeMsecs = (int)( ( (float)GAMEMOVEMENT_TIME_TO_UNDUCK_MSECS * ( 1.0f - trace.fraction ) ) + (float)GAMEMOVEMENT_TIME_TO_UNDUCK_MSECS_INV ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
player->m_Local.m_bInDuckJump = false; |
|
} |
|
} |
|
|
|
if ( bDuckJumpTime ) |
|
return; |
|
|
|
// Try to unduck unless automovement is not allowed |
|
// NOTE: When not onground, you can always unduck |
|
if ( player->m_Local.m_bAllowAutoMovement || bInAir ) |
|
{ |
|
// We released the duck button, we aren't in "duck" and we are not in the air - start unduck transition. |
|
if ( ( buttonsReleased & IN_DUCK ) && bInDuck && !bDuckJump ) |
|
{ |
|
player->m_Local.m_nDuckTimeMsecs = GAMEMOVEMENT_DUCK_TIME; |
|
} |
|
|
|
// Check to see if we are capable of unducking. |
|
if ( CanUnduck() ) |
|
{ |
|
// or unducking |
|
if ( ( player->m_Local.m_bDucking || player->m_Local.m_bDucked ) ) |
|
{ |
|
int nDuckMilliseconds = MAX( 0, GAMEMOVEMENT_DUCK_TIME - player->m_Local.m_nDuckTimeMsecs ); |
|
|
|
// Finish ducking immediately if duck time is over or not on ground |
|
if ( nDuckMilliseconds > TIME_TO_UNDUCK_MSECS || ( bInAir && !bDuckJump ) ) |
|
{ |
|
FinishUnDuck(); |
|
} |
|
else |
|
{ |
|
// Calc parametric time |
|
float flDuckFraction = SimpleSpline( 1.0f - FractionUnDucked( nDuckMilliseconds ) ); |
|
SetDuckedEyeOffset( flDuckFraction ); |
|
player->m_Local.m_bDucking = true; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// Still under something where we can't unduck, so make sure we reset this timer so |
|
// that we'll unduck once we exit the tunnel, etc. |
|
player->m_Local.m_nDuckTimeMsecs = GAMEMOVEMENT_DUCK_TIME; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::PlayerMove( void ) |
|
{ |
|
VPROF( "CASW_MarineGameMovement::PlayerMove" ); |
|
|
|
CheckParameters(); |
|
|
|
// clear output applied velocity |
|
mv->m_outWishVel.Init(); |
|
mv->m_outJumpVel.Init(); |
|
|
|
MoveHelper( )->ResetTouchList(); // Assume we don't touch anything |
|
|
|
ReduceTimers(); |
|
|
|
if ( marine->m_iJumpJetting != JJ_NONE ) |
|
{ |
|
FullJumpJetMove(); |
|
return; |
|
} |
|
|
|
// use fixed axis? |
|
if ( asw_controls.GetInt() == 1 ) |
|
AngleVectors( ASWGameRules()->GetTopDownMovementAxis(), &m_vecForward, &m_vecRight, &m_vecUp ); |
|
else |
|
AngleVectors (mv->m_vecViewAngles, &m_vecForward, &m_vecRight, &m_vecUp ); // Determine movement angles |
|
|
|
// Always try and unstick us unless we are a couple of the movement modes |
|
//if ( CheckInterval( STUCK ) ) |
|
{ |
|
if ( marine->GetMoveType() != MOVETYPE_NOCLIP && |
|
marine->GetMoveType() != MOVETYPE_NONE && |
|
marine->GetMoveType() != MOVETYPE_ISOMETRIC && |
|
marine->GetMoveType() != MOVETYPE_OBSERVER ) |
|
{ |
|
//Msg("Befor move: "); |
|
if ( CheckStuck() ) |
|
{ |
|
//Msg("*** Can't move, we're stuck\n"); |
|
// Can't move, we're stuck |
|
return; |
|
} |
|
} |
|
} |
|
|
|
// Now that we are "unstuck", see where we are (marine->GetWaterLevel() and type, marine->GetGroundEntity()). |
|
CategorizePosition(); |
|
|
|
// Store off the starting water level |
|
m_nOldWaterLevel = marine->GetWaterLevel(); |
|
|
|
// If we are not on ground, store off how fast we are moving down |
|
if ( marine->GetGroundEntity() == NULL ) |
|
{ |
|
player->m_Local.m_flFallVelocity = -mv->m_vecVelocity[ 2 ]; |
|
} |
|
|
|
m_nOnLadder = 0; |
|
|
|
// if ( CheckInterval( GROUND ) ) |
|
// { |
|
// CategorizeGroundSurface(); |
|
// } |
|
|
|
//marine->UpdateStepSound( marine->m_pSurfaceData, mv->m_vecAbsOrigin, mv->m_vecVelocity ); |
|
|
|
UpdateDuckJumpEyeOffset(); |
|
//Duck(); // asw, remove duck for now (causes strange z change when you jump) |
|
|
|
// Don't run ladder code if dead on on a train |
|
if ( !player->pl.deadflag && !(marine->GetFlags() & FL_ONTRAIN) ) |
|
{ |
|
// If was not on a ladder now, but was on one before, |
|
// get off of the ladder |
|
|
|
// TODO: this causes lots of weirdness. |
|
//bool bCheckLadder = CheckInterval( LADDER ); |
|
//if ( bCheckLadder || marine->GetMoveType() == MOVETYPE_LADDER ) |
|
{ |
|
if ( !LadderMove() && |
|
( marine->GetMoveType() == MOVETYPE_LADDER ) ) |
|
{ |
|
// Clear ladder stuff unless player is dead or riding a train |
|
// It will be reset immediately again next frame if necessary |
|
marine->SetMoveType( MOVETYPE_WALK ); |
|
marine->SetMoveCollide( MOVECOLLIDE_DEFAULT ); |
|
} |
|
} |
|
} |
|
|
|
// Handle movement modes. |
|
switch (marine->GetMoveType()) |
|
{ |
|
case MOVETYPE_NONE: |
|
break; |
|
|
|
case MOVETYPE_NOCLIP: |
|
FullNoClipMove( sv_noclipspeed.GetFloat(), sv_noclipaccelerate.GetFloat() ); |
|
break; |
|
|
|
case MOVETYPE_FLY: |
|
case MOVETYPE_FLYGRAVITY: |
|
FullTossMove(); |
|
break; |
|
|
|
case MOVETYPE_LADDER: |
|
FullLadderMove(); |
|
break; |
|
|
|
case MOVETYPE_WALK: |
|
if ( marine->GetCurrentMeleeAttack() && marine->m_iMeleeAllowMovement == MELEE_MOVEMENT_ANIMATION_ONLY ) |
|
{ |
|
FullMeleeMove(); |
|
} |
|
else |
|
{ |
|
FullWalkMove(); |
|
} |
|
break; |
|
|
|
case MOVETYPE_ISOMETRIC: |
|
//IsometricMove(); |
|
// Could also try: FullTossMove(); |
|
FullWalkMove(); |
|
break; |
|
|
|
case MOVETYPE_OBSERVER: |
|
FullObserverMove(); // clips against world&players |
|
break; |
|
|
|
default: |
|
DevMsg( 1, "Bogus pmove marine movetype %i on (%i) 0=cl 1=sv\n", marine->GetMoveType(), player->IsServer()); |
|
break; |
|
} |
|
//Msg("After move: "); CheckStuck(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Performs the collision resolution for fliers. |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::PerformFlyCollisionResolution( trace_t &pm, Vector &move ) |
|
{ |
|
Vector base; |
|
float vel; |
|
float backoff; |
|
|
|
switch (marine->GetMoveCollide()) |
|
{ |
|
case MOVECOLLIDE_FLY_CUSTOM: |
|
// Do nothing; the velocity should have been modified by touch |
|
// FIXME: It seems wrong for touch to modify velocity |
|
// given that it can be called in a number of places |
|
// where collision resolution do *not* in fact occur |
|
|
|
// Should this ever occur for players!? |
|
Assert(0); |
|
break; |
|
|
|
case MOVECOLLIDE_FLY_BOUNCE: |
|
case MOVECOLLIDE_DEFAULT: |
|
{ |
|
if (marine->GetMoveCollide() == MOVECOLLIDE_FLY_BOUNCE) |
|
backoff = 2.0 - marine->m_surfaceFriction; |
|
else |
|
backoff = 1; |
|
|
|
ClipVelocity (mv->m_vecVelocity, pm.plane.normal, mv->m_vecVelocity, backoff); |
|
} |
|
break; |
|
|
|
default: |
|
// Invalid collide type! |
|
Assert(0); |
|
break; |
|
} |
|
|
|
// stop if on ground |
|
if (pm.plane.normal[2] > 0.7) |
|
{ |
|
base.Init(); |
|
if (mv->m_vecVelocity[2] < asw_marine_gravity.GetFloat() * gpGlobals->frametime) |
|
{ |
|
// we're rolling on the ground, add static friction. |
|
SetGroundEntity( &pm ); |
|
mv->m_vecVelocity[2] = 0; |
|
} |
|
|
|
vel = DotProduct( mv->m_vecVelocity, mv->m_vecVelocity ); |
|
|
|
// Con_DPrintf("%f %f: %.0f %.0f %.0f\n", vel, trace.fraction, ent->velocity[0], ent->velocity[1], ent->velocity[2] ); |
|
|
|
if (vel < (30 * 30) || (marine->GetMoveCollide() != MOVECOLLIDE_FLY_BOUNCE)) |
|
{ |
|
SetGroundEntity( &pm ); |
|
mv->m_vecVelocity.Init(); |
|
} |
|
else |
|
{ |
|
VectorScale (mv->m_vecVelocity, (1.0 - pm.fraction) * gpGlobals->frametime * 0.9, move); |
|
PushEntity( move, &pm ); |
|
} |
|
VectorSubtract( mv->m_vecVelocity, base, mv->m_vecVelocity ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_MarineGameMovement::FullTossMove( void ) |
|
{ |
|
trace_t pm; |
|
Vector move; |
|
|
|
CheckWater(); |
|
|
|
// add velocity if player is moving |
|
if ( (mv->m_flForwardMove != 0.0f) || (mv->m_flSideMove != 0.0f) || (mv->m_flUpMove != 0.0f)) |
|
{ |
|
Vector forward, right, up; |
|
float fmove, smove; |
|
Vector wishdir, wishvel; |
|
float wishspeed; |
|
int i; |
|
|
|
if ( asw_controls.GetInt() == 1 ) |
|
AngleVectors( ASWGameRules()->GetTopDownMovementAxis(), &forward, &right, &up ); |
|
else |
|
AngleVectors (mv->m_vecViewAngles, &forward, &right, &up); // Determine movement angles |
|
|
|
// Copy movement amounts |
|
fmove = mv->m_flForwardMove; |
|
smove = mv->m_flSideMove; |
|
|
|
VectorNormalize (forward); // Normalize remainder of vectors. |
|
VectorNormalize (right); // |
|
|
|
for (i=0 ; i<3 ; i++) // Determine x and y parts of velocity |
|
wishvel[i] = forward[i]*fmove + right[i]*smove; |
|
|
|
wishvel[2] += mv->m_flUpMove; |
|
|
|
VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move |
|
wishspeed = VectorNormalize(wishdir); |
|
|
|
// |
|
// Clamp to server defined max speed |
|
// |
|
if (wishspeed > mv->m_flMaxSpeed) |
|
{ |
|
VectorScale (wishvel, mv->m_flMaxSpeed/wishspeed, wishvel); |
|
wishspeed = mv->m_flMaxSpeed; |
|
} |
|
|
|
// Set pmove velocity |
|
Accelerate( wishdir, wishspeed, sv_accelerate.GetFloat() ); |
|
} |
|
|
|
if ( mv->m_vecVelocity[2] > 0 ) |
|
{ |
|
SetGroundEntity( NULL ); |
|
} |
|
|
|
// If on ground and not moving, return. |
|
if ( marine->GetGroundEntity() != NULL ) |
|
{ |
|
if (VectorCompare(marine->GetBaseVelocity(), vec3_origin) && |
|
VectorCompare(mv->m_vecVelocity, vec3_origin)) |
|
return; |
|
} |
|
|
|
CheckVelocity(); |
|
|
|
// add gravity |
|
if ( marine->GetMoveType() == MOVETYPE_FLYGRAVITY ) |
|
{ |
|
AddGravity(); |
|
} |
|
|
|
// move origin |
|
// Base velocity is not properly accounted for since this entity will move again after the bounce without |
|
// taking it into account |
|
VectorAdd (mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity); |
|
|
|
CheckVelocity(); |
|
|
|
VectorScale (mv->m_vecVelocity, gpGlobals->frametime, move); |
|
VectorSubtract (mv->m_vecVelocity, marine->GetBaseVelocity(), mv->m_vecVelocity); |
|
|
|
PushEntity( move, &pm ); // Should this clear basevelocity |
|
|
|
CheckVelocity(); |
|
|
|
if (pm.allsolid) |
|
{ |
|
// entity is trapped in another solid |
|
SetGroundEntity( &pm ); |
|
mv->m_vecVelocity.Init(); |
|
return; |
|
} |
|
|
|
if (pm.fraction != 1) |
|
{ |
|
PerformFlyCollisionResolution( pm, move ); |
|
} |
|
|
|
// check for in water |
|
CheckWater(); |
|
} |
|
|
|
surfacedata_t* CASW_MarineGameMovement::GetSurfaceData() |
|
{ |
|
return marine->m_pSurfaceData; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: TF2 commander mode movement logic |
|
//----------------------------------------------------------------------------- |
|
|
|
#pragma warning (disable : 4701) |
|
|
|
void CASW_MarineGameMovement::IsometricMove( void ) |
|
{ |
|
int i; |
|
Vector wishvel; |
|
float fmove, smove; |
|
Vector forward, right, up; |
|
|
|
if ( asw_controls.GetInt() == 1 ) |
|
AngleVectors( ASWGameRules()->GetTopDownMovementAxis(), &forward, &right, &up ); |
|
else |
|
AngleVectors (mv->m_vecViewAngles, &forward, &right, &up); // Determine movement angles |
|
|
|
// Copy movement amounts |
|
fmove = mv->m_flForwardMove; |
|
smove = mv->m_flSideMove; |
|
|
|
// No up / down movement |
|
forward[2] = 0; |
|
right[2] = 0; |
|
|
|
VectorNormalize (forward); // Normalize remainder of vectors |
|
VectorNormalize (right); // |
|
|
|
for (i=0 ; i<3 ; i++) // Determine x and y parts of velocity |
|
wishvel[i] = forward[i]*fmove + right[i]*smove; |
|
//wishvel[2] += mv->m_flUpMove; |
|
|
|
Vector dest; |
|
VectorMA (mv->GetAbsOrigin(), gpGlobals->frametime, wishvel, dest); |
|
mv->SetAbsOrigin( dest ); |
|
|
|
// Zero out the velocity so that we don't accumulate a huge downward velocity from |
|
// gravity, etc. |
|
mv->m_vecVelocity.Init(); |
|
} |
|
|
|
#pragma warning (default : 4701) |
|
|
|
// Expose our interface. |
|
static CASW_MarineGameMovement g_MarineGameMovement; |
|
IMarineGameMovement *g_pMarineGameMovement = ( IMarineGameMovement * )&g_MarineGameMovement; |
|
|
|
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CASW_MarineGameMovement, IMarineGameMovement,INTERFACENAME_MARINEGAMEMOVEMENT, g_MarineGameMovement );
|
|
|