diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/portal/portal_gamemovement.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/portal/portal_gamemovement.cpp')
| -rw-r--r-- | game/shared/portal/portal_gamemovement.cpp | 752 |
1 files changed, 752 insertions, 0 deletions
diff --git a/game/shared/portal/portal_gamemovement.cpp b/game/shared/portal/portal_gamemovement.cpp new file mode 100644 index 0000000..a966290 --- /dev/null +++ b/game/shared/portal/portal_gamemovement.cpp @@ -0,0 +1,752 @@ +//========= 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 ); + |