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.
752 lines
22 KiB
752 lines
22 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Special handling for Portal usable ladders |
|
// |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "hl_gamemovement.h" |
|
#include "in_buttons.h" |
|
#include "utlrbtree.h" |
|
#include "movevars_shared.h" |
|
#include "portal_shareddefs.h" |
|
#include "portal_collideable_enumerator.h" |
|
#include "prop_portal_shared.h" |
|
#include "rumble_shared.h" |
|
|
|
#if defined( CLIENT_DLL ) |
|
#include "c_portal_player.h" |
|
#include "c_rumble.h" |
|
#else |
|
#include "portal_player.h" |
|
#include "env_player_surface_trigger.h" |
|
#include "portal_gamestats.h" |
|
#include "physicsshadowclone.h" |
|
#include "recipientfilter.h" |
|
#include "SoundEmitterSystem/isoundemittersystembase.h" |
|
#endif |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
ConVar sv_player_trace_through_portals("sv_player_trace_through_portals", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Causes player movement traces to trace through portals." ); |
|
ConVar sv_player_funnel_into_portals("sv_player_funnel_into_portals", "1", FCVAR_REPLICATED | FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX, "Causes the player to auto correct toward the center of floor portals." ); |
|
|
|
class CReservePlayerSpot; |
|
|
|
#define PORTAL_FUNNEL_AMOUNT 6.0f |
|
|
|
extern bool g_bAllowForcePortalTrace; |
|
extern bool g_bForcePortalTrace; |
|
|
|
static inline CBaseEntity *TranslateGroundEntity( CBaseEntity *pGroundEntity ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
CPhysicsShadowClone *pClone = dynamic_cast<CPhysicsShadowClone *>(pGroundEntity); |
|
|
|
if( pClone && pClone->IsUntransformedClone() ) |
|
{ |
|
CBaseEntity *pSource = pClone->GetClonedEntity(); |
|
|
|
if( pSource ) |
|
return pSource; |
|
} |
|
#endif //#ifndef CLIENT_DLL |
|
|
|
return pGroundEntity; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Portal specific movement code |
|
//----------------------------------------------------------------------------- |
|
class CPortalGameMovement : public CHL2GameMovement |
|
{ |
|
typedef CGameMovement BaseClass; |
|
public: |
|
|
|
CPortalGameMovement(); |
|
|
|
bool m_bInPortalEnv; |
|
// Overrides |
|
virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove ); |
|
virtual bool CheckJumpButton( void ); |
|
|
|
void FunnelIntoPortal( CProp_Portal *pPortal, Vector &wishdir ); |
|
|
|
virtual void AirAccelerate( Vector& wishdir, float wishspeed, float accel ); |
|
virtual void AirMove( void ); |
|
|
|
virtual void PlayerRoughLandingEffects( float fvol ); |
|
|
|
virtual void CategorizePosition( void ); |
|
|
|
// Traces the player bbox as it is swept from start to end |
|
virtual void TracePlayerBBox( const Vector& start, const Vector& end, unsigned int fMask, int collisionGroup, trace_t& pm ); |
|
|
|
// Tests the player position |
|
virtual CBaseHandle TestPlayerPosition( const Vector& pos, int collisionGroup, trace_t& pm ); |
|
|
|
virtual void Duck( void ); // Check for a forced duck |
|
|
|
virtual int CheckStuck( void ); |
|
|
|
virtual void SetGroundEntity( trace_t *pm ); |
|
|
|
private: |
|
|
|
|
|
CPortal_Player *GetPortalPlayer(); |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CPortalGameMovement::CPortalGameMovement() |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
inline CPortal_Player *CPortalGameMovement::GetPortalPlayer() |
|
{ |
|
return static_cast< CPortal_Player * >( player ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pMove - |
|
//----------------------------------------------------------------------------- |
|
void CPortalGameMovement::ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove ) |
|
{ |
|
Assert( pMove && pPlayer ); |
|
|
|
float flStoreFrametime = gpGlobals->frametime; |
|
|
|
//!!HACK HACK: Adrian - slow down all player movement by this factor. |
|
//!!Blame Yahn for this one. |
|
gpGlobals->frametime *= pPlayer->GetLaggedMovementValue(); |
|
|
|
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_iSpeedCropped = SPEED_CROPPED_RESET; |
|
|
|
player = pPlayer; |
|
mv = pMove; |
|
mv->m_flMaxSpeed = sv_maxspeed.GetFloat(); |
|
|
|
m_bInPortalEnv = (((CPortal_Player *)pPlayer)->m_hPortalEnvironment != NULL); |
|
|
|
g_bAllowForcePortalTrace = m_bInPortalEnv; |
|
g_bForcePortalTrace = m_bInPortalEnv; |
|
|
|
// Run the command. |
|
PlayerMove(); |
|
|
|
FinishMove(); |
|
|
|
g_bAllowForcePortalTrace = false; |
|
g_bForcePortalTrace = false; |
|
|
|
#ifndef CLIENT_DLL |
|
pPlayer->UnforceButtons( IN_DUCK ); |
|
pPlayer->UnforceButtons( IN_JUMP ); |
|
#endif |
|
|
|
//This is probably not needed, but just in case. |
|
gpGlobals->frametime = flStoreFrametime; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Base jump behavior, plus an anim event |
|
// Input : - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CPortalGameMovement::CheckJumpButton() |
|
{ |
|
if ( BaseClass::CheckJumpButton() && GetPortalPlayer() ) |
|
{ |
|
GetPortalPlayer()->DoAnimationEvent( PLAYERANIMEVENT_JUMP, 0 ); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void CPortalGameMovement::FunnelIntoPortal( CProp_Portal *pPortal, Vector &wishdir ) |
|
{ |
|
// Make sure there's a portal |
|
if ( !pPortal ) |
|
return; |
|
|
|
// Get portal vectors |
|
Vector vPortalForward, vPortalRight, vPortalUp; |
|
pPortal->GetVectors( &vPortalForward, &vPortalRight, &vPortalUp ); |
|
|
|
// Make sure it's a floor portal |
|
if ( vPortalForward.z < 0.8f ) |
|
return; |
|
|
|
vPortalRight.z = 0.0f; |
|
vPortalUp.z = 0.0f; |
|
VectorNormalize( vPortalRight ); |
|
VectorNormalize( vPortalUp ); |
|
|
|
// Make sure the player is looking downward |
|
CPortal_Player *pPlayer = GetPortalPlayer(); |
|
|
|
Vector vPlayerForward; |
|
pPlayer->EyeVectors( &vPlayerForward ); |
|
|
|
if ( vPlayerForward.z > -0.1f ) |
|
return; |
|
|
|
Vector vPlayerOrigin = pPlayer->GetAbsOrigin(); |
|
Vector vPlayerToPortal = pPortal->GetAbsOrigin() - vPlayerOrigin; |
|
|
|
// Make sure the player is trying to air control, they're falling downward and they are vertically close to the portal |
|
if ( fabsf( wishdir[ 0 ] ) > 64.0f || fabsf( wishdir[ 1 ] ) > 64.0f || mv->m_vecVelocity[ 2 ] > -165.0f || vPlayerToPortal.z < -512.0f ) |
|
return; |
|
|
|
// Make sure we're in the 2D portal rectangle |
|
if ( ( vPlayerToPortal.Dot( vPortalRight ) * vPortalRight ).Length() > PORTAL_HALF_WIDTH * 1.5f ) |
|
return; |
|
if ( ( vPlayerToPortal.Dot( vPortalUp ) * vPortalUp ).Length() > PORTAL_HALF_HEIGHT * 1.5f ) |
|
return; |
|
|
|
if ( vPlayerToPortal.z > -8.0f ) |
|
{ |
|
// We're too close the the portal to continue correcting, but zero the velocity so our fling velocity is nice |
|
mv->m_vecVelocity[ 0 ] = 0.0f; |
|
mv->m_vecVelocity[ 1 ] = 0.0f; |
|
} |
|
else |
|
{ |
|
// Funnel toward the portal |
|
float fFunnelX = vPlayerToPortal.x * PORTAL_FUNNEL_AMOUNT - mv->m_vecVelocity[ 0 ]; |
|
float fFunnelY = vPlayerToPortal.y * PORTAL_FUNNEL_AMOUNT - mv->m_vecVelocity[ 1 ]; |
|
|
|
wishdir[ 0 ] += fFunnelX; |
|
wishdir[ 1 ] += fFunnelY; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : wishdir - |
|
// accel - |
|
//----------------------------------------------------------------------------- |
|
void CPortalGameMovement::AirAccelerate( Vector& wishdir, float wishspeed, float accel ) |
|
{ |
|
int i; |
|
float addspeed, accelspeed, currentspeed; |
|
float wishspd; |
|
|
|
wishspd = wishspeed; |
|
|
|
if (player->pl.deadflag) |
|
return; |
|
|
|
if (player->m_flWaterJumpTime) |
|
return; |
|
|
|
// Cap speed |
|
if (wishspd > 60.0f) |
|
wishspd = 60.0f; |
|
|
|
// 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 * player->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 CPortalGameMovement::AirMove( void ) |
|
{ |
|
int i; |
|
Vector wishvel; |
|
float fmove, smove; |
|
Vector wishdir; |
|
float wishspeed; |
|
Vector forward, right, up; |
|
|
|
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 |
|
|
|
// |
|
// Don't let the player screw their fling because of adjusting into a floor portal |
|
// |
|
if ( mv->m_vecVelocity[ 0 ] * mv->m_vecVelocity[ 0 ] + mv->m_vecVelocity[ 1 ] * mv->m_vecVelocity[ 1 ] > MIN_FLING_SPEED * MIN_FLING_SPEED ) |
|
{ |
|
if ( mv->m_vecVelocity[ 0 ] > MIN_FLING_SPEED * 0.5f && wishdir[ 0 ] < 0.0f ) |
|
wishdir[ 0 ] = 0.0f; |
|
else if ( mv->m_vecVelocity[ 0 ] < -MIN_FLING_SPEED * 0.5f && wishdir[ 0 ] > 0.0f ) |
|
wishdir[ 0 ] = 0.0f; |
|
|
|
if ( mv->m_vecVelocity[ 1 ] > MIN_FLING_SPEED * 0.5f && wishdir[ 1 ] < 0.0f ) |
|
wishdir[ 1 ] = 0.0f; |
|
else if ( mv->m_vecVelocity[ 1 ] < -MIN_FLING_SPEED * 0.5f && wishdir[ 1 ] > 0.0f ) |
|
wishdir[ 1 ] = 0.0f; |
|
} |
|
|
|
// |
|
// Try to autocorrect the player to fall into the middle of the portal |
|
// |
|
else if ( sv_player_funnel_into_portals.GetBool() ) |
|
{ |
|
int iPortalCount = CProp_Portal_Shared::AllPortals.Count(); |
|
if( iPortalCount != 0 ) |
|
{ |
|
CProp_Portal **pPortals = CProp_Portal_Shared::AllPortals.Base(); |
|
for( int i = 0; i != iPortalCount; ++i ) |
|
{ |
|
CProp_Portal *pTempPortal = pPortals[i]; |
|
if( pTempPortal->IsActivedAndLinked() ) |
|
{ |
|
FunnelIntoPortal( pTempPortal, wishdir ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
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; |
|
} |
|
|
|
AirAccelerate( wishdir, wishspeed, 15.0f ); |
|
|
|
// Add in any base velocity to the current velocity. |
|
VectorAdd(mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); |
|
|
|
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, player->GetBaseVelocity(), mv->m_vecVelocity ); |
|
} |
|
|
|
void CPortalGameMovement::PlayerRoughLandingEffects( float fvol ) |
|
{ |
|
BaseClass::PlayerRoughLandingEffects( fvol ); |
|
|
|
#ifndef CLIENT_DLL |
|
if ( fvol >= 1.0 ) |
|
{ |
|
// Play the future shoes sound |
|
CRecipientFilter filter; |
|
filter.AddRecipientsByPAS( player->GetAbsOrigin() ); |
|
|
|
CSoundParameters params; |
|
if ( CBaseEntity::GetParametersForSound( "PortalPlayer.FallRecover", params, NULL ) ) |
|
{ |
|
EmitSound_t ep( params ); |
|
ep.m_nPitch = 125.0f - player->m_Local.m_flFallVelocity * 0.03f; // lower pitch the harder they land |
|
ep.m_flVolume = MIN( player->m_Local.m_flFallVelocity * 0.00075f - 0.38, 1.0f ); // louder the harder they land |
|
|
|
CBaseEntity::EmitSound( filter, player->entindex(), ep ); |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
void TracePlayerBBoxForGround2( const Vector& start, const Vector& end, const Vector& minsSrc, |
|
const Vector& maxsSrc, IHandleEntity *player, unsigned int fMask, |
|
int collisionGroup, trace_t& pm ) |
|
{ |
|
|
|
VPROF( "TracePlayerBBoxForGround" ); |
|
|
|
CPortal_Player *pPortalPlayer = dynamic_cast<CPortal_Player *>(player->GetRefEHandle().Get()); |
|
CProp_Portal *pPlayerPortal = pPortalPlayer->m_hPortalEnvironment; |
|
|
|
#ifndef CLIENT_DLL |
|
if( pPlayerPortal && pPlayerPortal->m_PortalSimulator.IsReadyToSimulate() == false ) |
|
pPlayerPortal = NULL; |
|
#endif |
|
|
|
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 ); |
|
|
|
if( pPlayerPortal ) |
|
UTIL_Portal_TraceRay( pPlayerPortal, ray, fMask, player, collisionGroup, &pm ); |
|
else |
|
UTIL_TraceRay( ray, fMask, player, collisionGroup, &pm ); |
|
|
|
if ( pm.m_pEnt && pm.plane.normal[2] >= 0.7) |
|
{ |
|
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 ); |
|
|
|
if( pPlayerPortal ) |
|
UTIL_Portal_TraceRay( pPlayerPortal, ray, fMask, player, collisionGroup, &pm ); |
|
else |
|
UTIL_TraceRay( ray, fMask, player, collisionGroup, &pm ); |
|
|
|
if ( pm.m_pEnt && pm.plane.normal[2] >= 0.7) |
|
{ |
|
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 ); |
|
|
|
if( pPlayerPortal ) |
|
UTIL_Portal_TraceRay( pPlayerPortal, ray, fMask, player, collisionGroup, &pm ); |
|
else |
|
UTIL_TraceRay( ray, fMask, player, collisionGroup, &pm ); |
|
|
|
if ( pm.m_pEnt && pm.plane.normal[2] >= 0.7) |
|
{ |
|
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 ); |
|
|
|
if( pPlayerPortal ) |
|
UTIL_Portal_TraceRay( pPlayerPortal, ray, fMask, player, collisionGroup, &pm ); |
|
else |
|
UTIL_TraceRay( ray, fMask, player, collisionGroup, &pm ); |
|
|
|
if ( pm.m_pEnt && pm.plane.normal[2] >= 0.7) |
|
{ |
|
pm.fraction = fraction; |
|
pm.endpos = endpos; |
|
return; |
|
} |
|
|
|
pm.fraction = fraction; |
|
pm.endpos = endpos; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &input - |
|
//----------------------------------------------------------------------------- |
|
void CPortalGameMovement::CategorizePosition( void ) |
|
{ |
|
Vector point; |
|
trace_t pm; |
|
|
|
// 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(); |
|
|
|
// observers don't have a ground entity |
|
if ( player->IsObserver() ) |
|
return; |
|
|
|
point[0] = mv->GetAbsOrigin()[0]; |
|
point[1] = mv->GetAbsOrigin()[1]; |
|
point[2] = mv->GetAbsOrigin()[2] - 2; |
|
|
|
Vector bumpOrigin; |
|
bumpOrigin = mv->GetAbsOrigin(); |
|
|
|
// Shooting up really fast. Definitely not on ground. |
|
// On ladder moving up, so not on ground either |
|
// NOTE: 145 is a jump. |
|
if ( mv->m_vecVelocity[2] > 140 || |
|
( mv->m_vecVelocity[2] > 0.0f && player->GetMoveType() == MOVETYPE_LADDER ) ) |
|
{ |
|
SetGroundEntity( NULL ); |
|
} |
|
else |
|
{ |
|
// Try and move down. |
|
TracePlayerBBox( bumpOrigin, point, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
|
|
// If we hit a steep plane, we are not on ground |
|
if ( pm.plane.normal[2] < 0.7) |
|
{ |
|
// Test four sub-boxes, to see if any of them would have found shallower slope we could |
|
// actually stand on |
|
|
|
TracePlayerBBoxForGround2( bumpOrigin, point, GetPlayerMins(), GetPlayerMaxs(), mv->m_nPlayerHandle.Get(), MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); |
|
if ( pm.plane.normal[2] < 0.7) |
|
{ |
|
|
|
SetGroundEntity( NULL ); // too steep |
|
// 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; |
|
} |
|
} |
|
else |
|
{ |
|
SetGroundEntity( &pm ); // Otherwise, point to index of ent under us. |
|
} |
|
} |
|
else |
|
{ |
|
SetGroundEntity( &pm ); // Otherwise, point to index of ent under us. |
|
} |
|
|
|
// If we are on something... |
|
if (player->GetGroundEntity() != NULL) |
|
{ |
|
// Then we are not in water jump sequence |
|
player->m_flWaterJumpTime = 0; |
|
|
|
// If we could make the move, drop us down that 1 pixel |
|
if ( player->GetWaterLevel() < WL_Waist && !pm.startsolid && !pm.allsolid ) |
|
{ |
|
// check distance we would like to move -- this is supposed to just keep up |
|
// "on the ground" surface not stap us back to earth (i.e. on move origin to |
|
// end position when the ground is within .5 units away) (2 units) |
|
if( pm.fraction ) |
|
// if( pm.fraction < 0.5) |
|
{ |
|
mv->SetAbsOrigin( pm.endpos ); |
|
} |
|
} |
|
} |
|
|
|
#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 ( !player->GetGroundEntity() ) |
|
{ |
|
cCurrGameMaterial = 0; |
|
} |
|
|
|
// Changed? |
|
if ( player->m_chPreviousTextureType != cCurrGameMaterial ) |
|
{ |
|
CEnvPlayerSurfaceTrigger::SetPlayerSurface( player, cCurrGameMaterial ); |
|
} |
|
|
|
player->m_chPreviousTextureType = cCurrGameMaterial; |
|
} |
|
#endif |
|
} |
|
} |
|
|
|
void CPortalGameMovement::Duck( void ) |
|
{ |
|
return BaseClass::Duck(); |
|
} |
|
|
|
int CPortalGameMovement::CheckStuck( void ) |
|
{ |
|
if( BaseClass::CheckStuck() ) |
|
{ |
|
CPortal_Player *pPortalPlayer = GetPortalPlayer(); |
|
|
|
#ifndef CLIENT_DLL |
|
if( pPortalPlayer->IsAlive() ) |
|
g_PortalGameStats.Event_PlayerStuck( pPortalPlayer ); |
|
#endif |
|
|
|
//try to fix it, then recheck |
|
Vector vIndecisive; |
|
if( pPortalPlayer->m_hPortalEnvironment ) |
|
{ |
|
pPortalPlayer->m_hPortalEnvironment->GetVectors( &vIndecisive, NULL, NULL ); |
|
} |
|
else |
|
{ |
|
vIndecisive.Init( 0.0f, 0.0f, 1.0f ); |
|
} |
|
Vector ptOldOrigin = pPortalPlayer->GetAbsOrigin(); |
|
|
|
if( pPortalPlayer->m_hPortalEnvironment ) |
|
{ |
|
if( !FindClosestPassableSpace( pPortalPlayer, vIndecisive ) ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
DevMsg( "Hurting the player for FindClosestPassableSpaceFailure!" ); |
|
|
|
CTakeDamageInfo info( pPortalPlayer, pPortalPlayer, vec3_origin, vec3_origin, 1e10, DMG_CRUSH ); |
|
pPortalPlayer->OnTakeDamage( info ); |
|
#endif |
|
} |
|
|
|
//make sure we didn't get put behind the portal >_< |
|
Vector ptCurrentOrigin = pPortalPlayer->GetAbsOrigin(); |
|
if( vIndecisive.Dot( ptCurrentOrigin - ptOldOrigin ) < 0.0f ) |
|
{ |
|
pPortalPlayer->SetAbsOrigin( ptOldOrigin + (vIndecisive * 5.0f) ); //this is an anti-bug hack, since this would have probably popped them out of the world, we're just going to move them forward a few units |
|
} |
|
} |
|
|
|
mv->SetAbsOrigin( pPortalPlayer->GetAbsOrigin() ); |
|
return BaseClass::CheckStuck(); |
|
} |
|
else |
|
{ |
|
return 0; |
|
} |
|
} |
|
|
|
void CPortalGameMovement::SetGroundEntity( trace_t *pm ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
if ( !player->GetGroundEntity() && pm && pm->m_pEnt ) |
|
{ |
|
IGameEvent *event = gameeventmanager->CreateEvent( "portal_player_touchedground" ); |
|
if ( event ) |
|
{ |
|
event->SetInt( "userid", player->GetUserID() ); |
|
gameeventmanager->FireEvent( event ); |
|
} |
|
} |
|
#endif |
|
|
|
BaseClass::SetGroundEntity( pm ); |
|
} |
|
|
|
void CPortalGameMovement::TracePlayerBBox( const Vector& start, const Vector& end, unsigned int fMask, int collisionGroup, trace_t& pm ) |
|
{ |
|
VPROF( "CGameMovement::TracePlayerBBox" ); |
|
|
|
CPortal_Player *pPortalPlayer = (CPortal_Player *)((CBaseEntity *)mv->m_nPlayerHandle.Get()); |
|
|
|
Ray_t ray; |
|
ray.Init( start, end, GetPlayerMins(), GetPlayerMaxs() ); |
|
|
|
#ifdef CLIENT_DLL |
|
CTraceFilterSimple traceFilter( mv->m_nPlayerHandle.Get(), collisionGroup ); |
|
#else |
|
CTraceFilterSimple baseFilter( mv->m_nPlayerHandle.Get(), collisionGroup ); |
|
CTraceFilterTranslateClones traceFilter( &baseFilter ); |
|
#endif |
|
|
|
UTIL_Portal_TraceRay_With( pPortalPlayer->m_hPortalEnvironment, ray, fMask, &traceFilter, &pm ); |
|
|
|
// If we're moving through a portal and failed to hit anything with the above ray trace |
|
// Use UTIL_Portal_TraceEntity to test this movement through a portal and override the trace with the result |
|
if ( pm.fraction == 1.0f && UTIL_DidTraceTouchPortals( ray, pm ) && sv_player_trace_through_portals.GetBool() ) |
|
{ |
|
trace_t tempTrace; |
|
UTIL_Portal_TraceEntity( pPortalPlayer, start, end, fMask, &traceFilter, &tempTrace ); |
|
|
|
if ( tempTrace.DidHit() && tempTrace.fraction < pm.fraction && !tempTrace.startsolid && !tempTrace.allsolid ) |
|
{ |
|
pm = tempTrace; |
|
} |
|
} |
|
} |
|
|
|
CBaseHandle CPortalGameMovement::TestPlayerPosition( const Vector& pos, int collisionGroup, trace_t& pm ) |
|
{ |
|
TracePlayerBBox( pos, pos, MASK_PLAYERSOLID, collisionGroup, pm ); //hook into the existing portal special trace functionality |
|
|
|
//Ray_t ray; |
|
//ray.Init( pos, pos, GetPlayerMins(), GetPlayerMaxs() ); |
|
//UTIL_TraceRay( ray, MASK_PLAYERSOLID, mv->m_nPlayerHandle.Get(), collisionGroup, &pm ); |
|
if( pm.startsolid && pm.m_pEnt && (pm.contents & MASK_PLAYERSOLID) ) |
|
{ |
|
#ifdef _DEBUG |
|
AssertMsgOnce( false, "The player got stuck on something. Break to investigate." ); //happens enough to just leave in a perma-debugger |
|
//this next trace is PURELY for tracking down how the player got stuck. Nothing new is discovered over the same trace about 10 lines up |
|
TracePlayerBBox( pos, pos, MASK_PLAYERSOLID, collisionGroup, pm ); |
|
#endif |
|
return pm.m_pEnt->GetRefEHandle(); |
|
} |
|
#ifndef CLIENT_DLL |
|
else if ( pm.startsolid && pm.m_pEnt && CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pm.m_pEnt ) ) |
|
{ |
|
// Stuck in a portal environment object, so unstick them! |
|
CPortal_Player *pPortalPlayer = (CPortal_Player *)((CBaseEntity *)mv->m_nPlayerHandle.Get()); |
|
pPortalPlayer->SetStuckOnPortalCollisionObject(); |
|
|
|
return INVALID_EHANDLE_INDEX; |
|
} |
|
#endif |
|
else |
|
{ |
|
return INVALID_EHANDLE_INDEX; |
|
} |
|
} |
|
|
|
|
|
// Expose our interface. |
|
static CPortalGameMovement g_GameMovement; |
|
IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement; |
|
|
|
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement ); |
|
|
|
|