summaryrefslogtreecommitdiff
path: root/game/client/portal/c_portal_player.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/portal/c_portal_player.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/portal/c_portal_player.cpp')
-rw-r--r--game/client/portal/c_portal_player.cpp1653
1 files changed, 1653 insertions, 0 deletions
diff --git a/game/client/portal/c_portal_player.cpp b/game/client/portal/c_portal_player.cpp
new file mode 100644
index 0000000..59ce85b
--- /dev/null
+++ b/game/client/portal/c_portal_player.cpp
@@ -0,0 +1,1653 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Player for .
+//
+//===========================================================================//
+
+#include "cbase.h"
+#include "vcollide_parse.h"
+#include "c_portal_player.h"
+#include "view.h"
+#include "c_basetempentity.h"
+#include "takedamageinfo.h"
+#include "in_buttons.h"
+#include "iviewrender_beams.h"
+#include "r_efx.h"
+#include "dlight.h"
+#include "PortalRender.h"
+#include "toolframework/itoolframework.h"
+#include "toolframework_client.h"
+#include "tier1/KeyValues.h"
+#include "ScreenSpaceEffects.h"
+#include "portal_shareddefs.h"
+#include "ivieweffects.h" // for screenshake
+#include "prop_portal_shared.h"
+
+// NVNT for fov updates
+#include "haptics/ihaptics.h"
+
+
+// Don't alias here
+#if defined( CPortal_Player )
+#undef CPortal_Player
+#endif
+
+
+#define REORIENTATION_RATE 120.0f
+#define REORIENTATION_ACCELERATION_RATE 400.0f
+
+#define ENABLE_PORTAL_EYE_INTERPOLATION_CODE
+
+
+#define DEATH_CC_LOOKUP_FILENAME "materials/correction/cc_death.raw"
+#define DEATH_CC_FADE_SPEED 0.05f
+
+
+ConVar cl_reorient_in_air("cl_reorient_in_air", "1", FCVAR_ARCHIVE, "Allows the player to only reorient from being upside down while in the air." );
+
+
+// -------------------------------------------------------------------------------- //
+// Player animation event. Sent to the client when a player fires, jumps, reloads, etc..
+// -------------------------------------------------------------------------------- //
+
+class C_TEPlayerAnimEvent : public C_BaseTempEntity
+{
+public:
+ DECLARE_CLASS( C_TEPlayerAnimEvent, C_BaseTempEntity );
+ DECLARE_CLIENTCLASS();
+
+ virtual void PostDataUpdate( DataUpdateType_t updateType )
+ {
+ // Create the effect.
+ C_Portal_Player *pPlayer = dynamic_cast< C_Portal_Player* >( m_hPlayer.Get() );
+ if ( pPlayer && !pPlayer->IsDormant() )
+ {
+ pPlayer->DoAnimationEvent( (PlayerAnimEvent_t)m_iEvent.Get(), m_nData );
+ }
+ }
+
+public:
+ CNetworkHandle( CBasePlayer, m_hPlayer );
+ CNetworkVar( int, m_iEvent );
+ CNetworkVar( int, m_nData );
+};
+
+IMPLEMENT_CLIENTCLASS_EVENT( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent, CTEPlayerAnimEvent );
+
+BEGIN_RECV_TABLE_NOBASE( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent )
+RecvPropEHandle( RECVINFO( m_hPlayer ) ),
+RecvPropInt( RECVINFO( m_iEvent ) ),
+RecvPropInt( RECVINFO( m_nData ) )
+END_RECV_TABLE()
+
+
+//=================================================================================
+//
+// Ragdoll Entity
+//
+class C_PortalRagdoll : public C_BaseFlex
+{
+public:
+
+ DECLARE_CLASS( C_PortalRagdoll, C_BaseFlex );
+ DECLARE_CLIENTCLASS();
+
+ C_PortalRagdoll();
+ ~C_PortalRagdoll();
+
+ virtual void OnDataChanged( DataUpdateType_t type );
+
+ int GetPlayerEntIndex() const;
+ IRagdoll* GetIRagdoll() const;
+
+ virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
+
+private:
+
+ C_PortalRagdoll( const C_PortalRagdoll & ) {}
+
+ void Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity );
+ void CreatePortalRagdoll();
+
+private:
+
+ EHANDLE m_hPlayer;
+ CNetworkVector( m_vecRagdollVelocity );
+ CNetworkVector( m_vecRagdollOrigin );
+
+};
+
+IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_PortalRagdoll, DT_PortalRagdoll, CPortalRagdoll )
+RecvPropVector( RECVINFO(m_vecRagdollOrigin) ),
+RecvPropEHandle( RECVINFO( m_hPlayer ) ),
+RecvPropInt( RECVINFO( m_nModelIndex ) ),
+RecvPropInt( RECVINFO(m_nForceBone) ),
+RecvPropVector( RECVINFO(m_vecForce) ),
+RecvPropVector( RECVINFO( m_vecRagdollVelocity ) ),
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+C_PortalRagdoll::C_PortalRagdoll()
+{
+ m_hPlayer = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+C_PortalRagdoll::~C_PortalRagdoll()
+{
+ ( this );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pSourceEntity -
+//-----------------------------------------------------------------------------
+void C_PortalRagdoll::Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity )
+{
+ if ( !pSourceEntity )
+ return;
+
+ VarMapping_t *pSrc = pSourceEntity->GetVarMapping();
+ VarMapping_t *pDest = GetVarMapping();
+
+ // Find all the VarMapEntry_t's that represent the same variable.
+ for ( int i = 0; i < pDest->m_Entries.Count(); i++ )
+ {
+ VarMapEntry_t *pDestEntry = &pDest->m_Entries[i];
+ for ( int j=0; j < pSrc->m_Entries.Count(); j++ )
+ {
+ VarMapEntry_t *pSrcEntry = &pSrc->m_Entries[j];
+ if ( !Q_strcmp( pSrcEntry->watcher->GetDebugName(), pDestEntry->watcher->GetDebugName() ) )
+ {
+ pDestEntry->watcher->Copy( pSrcEntry->watcher );
+ break;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Setup vertex weights for drawing
+//-----------------------------------------------------------------------------
+void C_PortalRagdoll::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
+{
+ // While we're dying, we want to mimic the facial animation of the player. Once they're dead, we just stay as we are.
+ if ( (m_hPlayer && m_hPlayer->IsAlive()) || !m_hPlayer )
+ {
+ BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
+ }
+ else if ( m_hPlayer )
+ {
+ m_hPlayer->SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void C_PortalRagdoll::CreatePortalRagdoll()
+{
+ // First, initialize all our data. If we have the player's entity on our client,
+ // then we can make ourselves start out exactly where the player is.
+ C_Portal_Player *pPlayer = dynamic_cast<C_Portal_Player*>( m_hPlayer.Get() );
+
+ if ( pPlayer && !pPlayer->IsDormant() )
+ {
+ // Move my current model instance to the ragdoll's so decals are preserved.
+ pPlayer->SnatchModelInstance( this );
+
+ VarMapping_t *varMap = GetVarMapping();
+
+ // This is the local player, so set them in a default
+ // pose and slam their velocity, angles and origin
+ SetAbsOrigin( /* m_vecRagdollOrigin : */ pPlayer->GetRenderOrigin() );
+ SetAbsAngles( pPlayer->GetRenderAngles() );
+ SetAbsVelocity( m_vecRagdollVelocity );
+
+ // Hack! Find a neutral standing pose or use the idle.
+ int iSeq = LookupSequence( "ragdoll" );
+ if ( iSeq == -1 )
+ {
+ Assert( false );
+ iSeq = 0;
+ }
+ SetSequence( iSeq );
+ SetCycle( 0.0 );
+
+ Interp_Reset( varMap );
+
+ m_nBody = pPlayer->GetBody();
+ SetModelIndex( m_nModelIndex );
+ // Make us a ragdoll..
+ m_nRenderFX = kRenderFxRagdoll;
+
+ matrix3x4_t boneDelta0[MAXSTUDIOBONES];
+ matrix3x4_t boneDelta1[MAXSTUDIOBONES];
+ matrix3x4_t currentBones[MAXSTUDIOBONES];
+ const float boneDt = 0.05f;
+
+ pPlayer->GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
+
+ InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : IRagdoll*
+//-----------------------------------------------------------------------------
+IRagdoll* C_PortalRagdoll::GetIRagdoll() const
+{
+ return m_pRagdoll;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : type -
+//-----------------------------------------------------------------------------
+void C_PortalRagdoll::OnDataChanged( DataUpdateType_t type )
+{
+ BaseClass::OnDataChanged( type );
+
+ if ( type == DATA_UPDATE_CREATED )
+ {
+ CreatePortalRagdoll();
+ }
+}
+
+
+LINK_ENTITY_TO_CLASS( player, C_Portal_Player );
+
+IMPLEMENT_CLIENTCLASS_DT(C_Portal_Player, DT_Portal_Player, CPortal_Player)
+RecvPropFloat( RECVINFO( m_angEyeAngles[0] ) ),
+RecvPropFloat( RECVINFO( m_angEyeAngles[1] ) ),
+RecvPropEHandle( RECVINFO( m_hRagdoll ) ),
+RecvPropInt( RECVINFO( m_iSpawnInterpCounter ) ),
+RecvPropInt( RECVINFO( m_iPlayerSoundType ) ),
+RecvPropBool( RECVINFO( m_bHeldObjectOnOppositeSideOfPortal ) ),
+RecvPropEHandle( RECVINFO( m_pHeldObjectPortal ) ),
+RecvPropBool( RECVINFO( m_bPitchReorientation ) ),
+RecvPropEHandle( RECVINFO( m_hPortalEnvironment ) ),
+RecvPropEHandle( RECVINFO( m_hSurroundingLiquidPortal ) ),
+RecvPropBool( RECVINFO( m_bSuppressingCrosshair ) ),
+END_RECV_TABLE()
+
+
+BEGIN_PREDICTION_DATA( C_Portal_Player )
+END_PREDICTION_DATA()
+
+#define _WALK_SPEED 150
+#define _NORM_SPEED 190
+#define _SPRINT_SPEED 320
+
+static ConVar cl_playermodel( "cl_playermodel", "none", FCVAR_USERINFO | FCVAR_ARCHIVE | FCVAR_SERVER_CAN_EXECUTE, "Default Player Model");
+
+extern bool g_bUpsideDown;
+
+//EHANDLE g_eKillTarget1;
+//EHANDLE g_eKillTarget2;
+
+void SpawnBlood (Vector vecSpot, const Vector &vecDir, int bloodColor, float flDamage);
+
+C_Portal_Player::C_Portal_Player()
+: m_iv_angEyeAngles( "C_Portal_Player::m_iv_angEyeAngles" )
+{
+ m_PlayerAnimState = CreatePortalPlayerAnimState( this );
+
+ m_iIDEntIndex = 0;
+ m_iSpawnInterpCounterCache = 0;
+ m_flDeathCCWeight = 0.0f;
+
+ m_hRagdoll.Set( NULL );
+ m_flStartLookTime = 0.0f;
+
+ m_bHeldObjectOnOppositeSideOfPortal = false;
+ m_pHeldObjectPortal = 0;
+
+ m_bPitchReorientation = false;
+ m_fReorientationRate = 0.0f;
+
+ m_angEyeAngles.Init();
+
+ AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
+
+ m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK;
+ m_blinkTimer.Invalidate();
+
+ m_CCDeathHandle = INVALID_CLIENT_CCHANDLE;
+}
+
+C_Portal_Player::~C_Portal_Player( void )
+{
+ if ( m_PlayerAnimState )
+ {
+ m_PlayerAnimState->Release();
+ }
+
+ g_pColorCorrectionMgr->RemoveColorCorrection( m_CCDeathHandle );
+}
+
+int C_Portal_Player::GetIDTarget() const
+{
+ return m_iIDEntIndex;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update this client's target entity
+//-----------------------------------------------------------------------------
+void C_Portal_Player::UpdateIDTarget()
+{
+ if ( !IsLocalPlayer() )
+ return;
+
+ // Clear old target and find a new one
+ m_iIDEntIndex = 0;
+
+ // don't show IDs in chase spec mode
+ if ( GetObserverMode() == OBS_MODE_CHASE ||
+ GetObserverMode() == OBS_MODE_DEATHCAM )
+ return;
+
+ trace_t tr;
+ Vector vecStart, vecEnd;
+ VectorMA( MainViewOrigin(), 1500, MainViewForward(), vecEnd );
+ VectorMA( MainViewOrigin(), 10, MainViewForward(), vecStart );
+ UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
+
+ if ( !tr.startsolid && tr.DidHitNonWorldEntity() )
+ {
+ C_BaseEntity *pEntity = tr.m_pEnt;
+
+ if ( pEntity && (pEntity != this) )
+ {
+ m_iIDEntIndex = pEntity->entindex();
+ }
+ }
+}
+
+void C_Portal_Player::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
+{
+ Vector vecOrigin = ptr->endpos - vecDir * 4;
+
+ float flDistance = 0.0f;
+
+ if ( info.GetAttacker() )
+ {
+ flDistance = (ptr->endpos - info.GetAttacker()->GetAbsOrigin()).Length();
+ }
+
+ if ( m_takedamage )
+ {
+ AddMultiDamage( info, this );
+
+ int blood = BloodColor();
+
+ if ( blood != DONT_BLEED )
+ {
+ SpawnBlood( vecOrigin, vecDir, blood, flDistance );// a little surface blood.
+ TraceBleed( flDistance, vecDir, ptr, info.GetDamageType() );
+ }
+ }
+}
+
+void C_Portal_Player::Initialize( void )
+{
+ m_headYawPoseParam = LookupPoseParameter( "head_yaw" );
+ GetPoseParameterRange( m_headYawPoseParam, m_headYawMin, m_headYawMax );
+
+ m_headPitchPoseParam = LookupPoseParameter( "head_pitch" );
+ GetPoseParameterRange( m_headPitchPoseParam, m_headPitchMin, m_headPitchMax );
+
+ CStudioHdr *hdr = GetModelPtr();
+ for ( int i = 0; i < hdr->GetNumPoseParameters() ; i++ )
+ {
+ SetPoseParameter( hdr, i, 0.0 );
+ }
+}
+
+CStudioHdr *C_Portal_Player::OnNewModel( void )
+{
+ CStudioHdr *hdr = BaseClass::OnNewModel();
+
+ Initialize( );
+
+ return hdr;
+}
+
+//-----------------------------------------------------------------------------
+/**
+* Orient head and eyes towards m_lookAt.
+*/
+void C_Portal_Player::UpdateLookAt( void )
+{
+ // head yaw
+ if (m_headYawPoseParam < 0 || m_headPitchPoseParam < 0)
+ return;
+
+ // This is buggy with dt 0, just skip since there is no work to do.
+ if ( gpGlobals->frametime <= 0.0f )
+ return;
+
+ // Player looks at themselves through portals. Pick the portal we're turned towards.
+ const int iPortalCount = CProp_Portal_Shared::AllPortals.Count();
+ CProp_Portal **pPortals = CProp_Portal_Shared::AllPortals.Base();
+ float *fPortalDot = (float *)stackalloc( sizeof( float ) * iPortalCount );
+ float flLowDot = 1.0f;
+ int iUsePortal = -1;
+
+ // defaults if no portals are around
+ Vector vPlayerForward;
+ GetVectors( &vPlayerForward, NULL, NULL );
+ Vector vCurLookTarget = EyePosition();
+
+ if ( !IsAlive() )
+ {
+ m_viewtarget = EyePosition() + vPlayerForward*10.0f;
+ return;
+ }
+
+ bool bNewTarget = false;
+ if ( UTIL_IntersectEntityExtentsWithPortal( this ) != NULL )
+ {
+ // player is in a portal
+ vCurLookTarget = EyePosition() + vPlayerForward*10.0f;
+ }
+ else if ( pPortals && pPortals[0] )
+ {
+ // Test through any active portals: This may be a shorter distance to the target
+ for( int i = 0; i != iPortalCount; ++i )
+ {
+ CProp_Portal *pTempPortal = pPortals[i];
+
+ if( pTempPortal && pTempPortal->m_bActivated && pTempPortal->m_hLinkedPortal.Get() )
+ {
+ Vector vEyeForward, vPortalForward;
+ EyeVectors( &vEyeForward );
+ pTempPortal->GetVectors( &vPortalForward, NULL, NULL );
+ fPortalDot[i] = vEyeForward.Dot( vPortalForward );
+ if ( fPortalDot[i] < flLowDot )
+ {
+ flLowDot = fPortalDot[i];
+ iUsePortal = i;
+ }
+ }
+ }
+
+ if ( iUsePortal >= 0 )
+ {
+ C_Prop_Portal* pPortal = pPortals[iUsePortal];
+ if ( pPortal )
+ {
+ vCurLookTarget = pPortal->MatrixThisToLinked()*vCurLookTarget;
+ if ( vCurLookTarget != m_vLookAtTarget )
+ {
+ bNewTarget = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ // No other look targets, look straight ahead
+ vCurLookTarget += vPlayerForward*10.0f;
+ }
+
+ // Figure out where we want to look in world space.
+ QAngle desiredAngles;
+ Vector to = vCurLookTarget - EyePosition();
+ VectorAngles( to, desiredAngles );
+ QAngle aheadAngles;
+ VectorAngles( vCurLookTarget, aheadAngles );
+
+ // Figure out where our body is facing in world space.
+ QAngle bodyAngles( 0, 0, 0 );
+ bodyAngles[YAW] = GetLocalAngles()[YAW];
+
+ m_flLastBodyYaw = bodyAngles[YAW];
+
+ // Set the head's yaw.
+ float desiredYaw = AngleNormalize( desiredAngles[YAW] - bodyAngles[YAW] );
+ desiredYaw = clamp( desiredYaw, m_headYawMin, m_headYawMax );
+
+ float desiredPitch = AngleNormalize( desiredAngles[PITCH] );
+ desiredPitch = clamp( desiredPitch, m_headPitchMin, m_headPitchMax );
+
+ if ( bNewTarget )
+ {
+ m_flStartLookTime = gpGlobals->curtime;
+ }
+
+ float dt = (gpGlobals->frametime);
+ float flSpeed = 1.0f - ExponentialDecay( 0.7f, 0.033f, dt );
+
+ m_flCurrentHeadYaw = m_flCurrentHeadYaw + flSpeed * ( desiredYaw - m_flCurrentHeadYaw );
+ m_flCurrentHeadYaw = AngleNormalize( m_flCurrentHeadYaw );
+ SetPoseParameter( m_headYawPoseParam, m_flCurrentHeadYaw );
+
+ m_flCurrentHeadPitch = m_flCurrentHeadPitch + flSpeed * ( desiredPitch - m_flCurrentHeadPitch );
+ m_flCurrentHeadPitch = AngleNormalize( m_flCurrentHeadPitch );
+ SetPoseParameter( m_headPitchPoseParam, m_flCurrentHeadPitch );
+
+ // This orients the eyes
+ m_viewtarget = m_vLookAtTarget = vCurLookTarget;
+}
+
+void C_Portal_Player::ClientThink( void )
+{
+ //PortalEyeInterpolation.m_bNeedToUpdateEyePosition = true;
+
+ Vector vForward;
+ AngleVectors( GetLocalAngles(), &vForward );
+
+ // Allow sprinting
+ HandleSpeedChanges();
+
+ FixTeleportationRoll();
+
+ //QAngle vAbsAngles = EyeAngles();
+
+ // Look at the thing that killed you
+ //if ( !IsAlive() )
+ //{
+ // C_BaseEntity *pEntity1 = g_eKillTarget1.Get();
+ // C_BaseEntity *pEntity2 = g_eKillTarget2.Get();
+
+ // if ( pEntity2 && pEntity1 )
+ // {
+ // //engine->GetViewAngles( vAbsAngles );
+
+ // Vector vLook = pEntity1->GetAbsOrigin() - pEntity2->GetAbsOrigin();
+ // VectorNormalize( vLook );
+
+ // QAngle qLook;
+ // VectorAngles( vLook, qLook );
+
+ // if ( qLook[PITCH] > 180.0f )
+ // {
+ // qLook[PITCH] -= 360.0f;
+ // }
+
+ // if ( vAbsAngles[YAW] < 0.0f )
+ // {
+ // vAbsAngles[YAW] += 360.0f;
+ // }
+
+ // if ( vAbsAngles[PITCH] < qLook[PITCH] )
+ // {
+ // vAbsAngles[PITCH] += gpGlobals->frametime * 120.0f;
+ // if ( vAbsAngles[PITCH] > qLook[PITCH] )
+ // vAbsAngles[PITCH] = qLook[PITCH];
+ // }
+ // else if ( vAbsAngles[PITCH] > qLook[PITCH] )
+ // {
+ // vAbsAngles[PITCH] -= gpGlobals->frametime * 120.0f;
+ // if ( vAbsAngles[PITCH] < qLook[PITCH] )
+ // vAbsAngles[PITCH] = qLook[PITCH];
+ // }
+
+ // if ( vAbsAngles[YAW] < qLook[YAW] )
+ // {
+ // vAbsAngles[YAW] += gpGlobals->frametime * 240.0f;
+ // if ( vAbsAngles[YAW] > qLook[YAW] )
+ // vAbsAngles[YAW] = qLook[YAW];
+ // }
+ // else if ( vAbsAngles[YAW] > qLook[YAW] )
+ // {
+ // vAbsAngles[YAW] -= gpGlobals->frametime * 240.0f;
+ // if ( vAbsAngles[YAW] < qLook[YAW] )
+ // vAbsAngles[YAW] = qLook[YAW];
+ // }
+
+ // if ( vAbsAngles[YAW] > 180.0f )
+ // {
+ // vAbsAngles[YAW] -= 360.0f;
+ // }
+
+ // engine->SetViewAngles( vAbsAngles );
+ // }
+ //}
+
+ // If dead, fade in death CC lookup
+ if ( m_CCDeathHandle != INVALID_CLIENT_CCHANDLE )
+ {
+ if ( m_lifeState != LIFE_ALIVE )
+ {
+ if ( m_flDeathCCWeight < 1.0f )
+ {
+ m_flDeathCCWeight += DEATH_CC_FADE_SPEED;
+ clamp( m_flDeathCCWeight, 0.0f, 1.0f );
+ }
+ }
+ else
+ {
+ m_flDeathCCWeight = 0.0f;
+ }
+ g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCDeathHandle, m_flDeathCCWeight );
+ }
+
+ UpdateIDTarget();
+}
+
+void C_Portal_Player::FixTeleportationRoll( void )
+{
+ if( IsInAVehicle() ) //HL2 compatibility fix. do absolutely nothing to the view in vehicles
+ return;
+
+ if( !IsLocalPlayer() )
+ return;
+
+ // Normalize roll from odd portal transitions
+ QAngle vAbsAngles = EyeAngles();
+
+
+ Vector vCurrentForward, vCurrentRight, vCurrentUp;
+ AngleVectors( vAbsAngles, &vCurrentForward, &vCurrentRight, &vCurrentUp );
+
+ if ( vAbsAngles[ROLL] == 0.0f )
+ {
+ m_fReorientationRate = 0.0f;
+ g_bUpsideDown = ( vCurrentUp.z < 0.0f );
+ return;
+ }
+
+ bool bForcePitchReorient = ( vAbsAngles[ROLL] > 175.0f && vCurrentForward.z > 0.99f );
+ bool bOnGround = ( GetGroundEntity() != NULL );
+
+ if ( bForcePitchReorient )
+ {
+ m_fReorientationRate = REORIENTATION_RATE * ( ( bOnGround ) ? ( 2.0f ) : ( 1.0f ) );
+ }
+ else
+ {
+ // Don't reorient in air if they don't want to
+ if ( !cl_reorient_in_air.GetBool() && !bOnGround )
+ {
+ g_bUpsideDown = ( vCurrentUp.z < 0.0f );
+ return;
+ }
+ }
+
+ if ( vCurrentUp.z < 0.75f )
+ {
+ m_fReorientationRate += gpGlobals->frametime * REORIENTATION_ACCELERATION_RATE;
+
+ // Upright faster if on the ground
+ float fMaxReorientationRate = REORIENTATION_RATE * ( ( bOnGround ) ? ( 2.0f ) : ( 1.0f ) );
+ if ( m_fReorientationRate > fMaxReorientationRate )
+ m_fReorientationRate = fMaxReorientationRate;
+ }
+ else
+ {
+ if ( m_fReorientationRate > REORIENTATION_RATE * 0.5f )
+ {
+ m_fReorientationRate -= gpGlobals->frametime * REORIENTATION_ACCELERATION_RATE;
+ if ( m_fReorientationRate < REORIENTATION_RATE * 0.5f )
+ m_fReorientationRate = REORIENTATION_RATE * 0.5f;
+ }
+ else if ( m_fReorientationRate < REORIENTATION_RATE * 0.5f )
+ {
+ m_fReorientationRate += gpGlobals->frametime * REORIENTATION_ACCELERATION_RATE;
+ if ( m_fReorientationRate > REORIENTATION_RATE * 0.5f )
+ m_fReorientationRate = REORIENTATION_RATE * 0.5f;
+ }
+ }
+
+ if ( !m_bPitchReorientation && !bForcePitchReorient )
+ {
+ // Randomize which way we roll if we're completely upside down
+ if ( vAbsAngles[ROLL] == 180.0f && RandomInt( 0, 1 ) == 1 )
+ {
+ vAbsAngles[ROLL] = -180.0f;
+ }
+
+ if ( vAbsAngles[ROLL] < 0.0f )
+ {
+ vAbsAngles[ROLL] += gpGlobals->frametime * m_fReorientationRate;
+ if ( vAbsAngles[ROLL] > 0.0f )
+ vAbsAngles[ROLL] = 0.0f;
+ engine->SetViewAngles( vAbsAngles );
+ }
+ else if ( vAbsAngles[ROLL] > 0.0f )
+ {
+ vAbsAngles[ROLL] -= gpGlobals->frametime * m_fReorientationRate;
+ if ( vAbsAngles[ROLL] < 0.0f )
+ vAbsAngles[ROLL] = 0.0f;
+ engine->SetViewAngles( vAbsAngles );
+ m_angEyeAngles = vAbsAngles;
+ m_iv_angEyeAngles.Reset();
+ }
+ }
+ else
+ {
+ if ( vAbsAngles[ROLL] != 0.0f )
+ {
+ if ( vCurrentUp.z < 0.2f )
+ {
+ float fDegrees = gpGlobals->frametime * m_fReorientationRate;
+ if ( vCurrentForward.z > 0.0f )
+ {
+ fDegrees = -fDegrees;
+ }
+
+ // Rotate around the right axis
+ VMatrix mAxisAngleRot = SetupMatrixAxisRot( vCurrentRight, fDegrees );
+
+ vCurrentUp = mAxisAngleRot.VMul3x3( vCurrentUp );
+ vCurrentForward = mAxisAngleRot.VMul3x3( vCurrentForward );
+
+ VectorAngles( vCurrentForward, vCurrentUp, vAbsAngles );
+
+ engine->SetViewAngles( vAbsAngles );
+ m_angEyeAngles = vAbsAngles;
+ m_iv_angEyeAngles.Reset();
+ }
+ else
+ {
+ if ( vAbsAngles[ROLL] < 0.0f )
+ {
+ vAbsAngles[ROLL] += gpGlobals->frametime * m_fReorientationRate;
+ if ( vAbsAngles[ROLL] > 0.0f )
+ vAbsAngles[ROLL] = 0.0f;
+ engine->SetViewAngles( vAbsAngles );
+ m_angEyeAngles = vAbsAngles;
+ m_iv_angEyeAngles.Reset();
+ }
+ else if ( vAbsAngles[ROLL] > 0.0f )
+ {
+ vAbsAngles[ROLL] -= gpGlobals->frametime * m_fReorientationRate;
+ if ( vAbsAngles[ROLL] < 0.0f )
+ vAbsAngles[ROLL] = 0.0f;
+ engine->SetViewAngles( vAbsAngles );
+ m_angEyeAngles = vAbsAngles;
+ m_iv_angEyeAngles.Reset();
+ }
+ }
+ }
+ }
+
+ // Keep track of if we're upside down for look control
+ vAbsAngles = EyeAngles();
+ AngleVectors( vAbsAngles, NULL, NULL, &vCurrentUp );
+
+ if ( bForcePitchReorient )
+ g_bUpsideDown = ( vCurrentUp.z < 0.0f );
+ else
+ g_bUpsideDown = false;
+}
+
+const QAngle& C_Portal_Player::GetRenderAngles()
+{
+ if ( IsRagdoll() )
+ {
+ return vec3_angle;
+ }
+ else
+ {
+ return m_PlayerAnimState->GetRenderAngles();
+ }
+}
+
+void C_Portal_Player::UpdateClientSideAnimation( void )
+{
+ UpdateLookAt();
+
+ // Update the animation data. It does the local check here so this works when using
+ // a third-person camera (and we don't have valid player angles).
+ if ( this == C_Portal_Player::GetLocalPortalPlayer() )
+ m_PlayerAnimState->Update( EyeAngles()[YAW], m_angEyeAngles[PITCH] );
+ else
+ m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] );
+
+ BaseClass::UpdateClientSideAnimation();
+}
+
+void C_Portal_Player::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
+{
+ m_PlayerAnimState->DoAnimationEvent( event, nData );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_Portal_Player::DrawModel( int flags )
+{
+ if ( !m_bReadyToDraw )
+ return 0;
+
+ if( IsLocalPlayer() )
+ {
+ if ( !C_BasePlayer::ShouldDrawThisPlayer() )
+ {
+ if ( !g_pPortalRender->IsRenderingPortal() )
+ return 0;
+
+ if( (g_pPortalRender->GetViewRecursionLevel() == 1) && (m_iForceNoDrawInPortalSurface != -1) ) //CPortalRender::s_iRenderingPortalView )
+ return 0;
+ }
+ }
+
+ return BaseClass::DrawModel(flags);
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Should this object receive shadows?
+//-----------------------------------------------------------------------------
+bool C_Portal_Player::ShouldReceiveProjectedTextures( int flags )
+{
+ Assert( flags & SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK );
+
+ if ( IsEffectActive( EF_NODRAW ) )
+ return false;
+
+ if( flags & SHADOW_FLAGS_FLASHLIGHT )
+ {
+ return true;
+ }
+
+ return BaseClass::ShouldReceiveProjectedTextures( flags );
+}
+
+void C_Portal_Player::DoImpactEffect( trace_t &tr, int nDamageType )
+{
+ if ( GetActiveWeapon() )
+ {
+ GetActiveWeapon()->DoImpactEffect( tr, nDamageType );
+ return;
+ }
+
+ BaseClass::DoImpactEffect( tr, nDamageType );
+}
+
+void C_Portal_Player::PreThink( void )
+{
+ QAngle vTempAngles = GetLocalAngles();
+
+ if ( IsLocalPlayer() )
+ {
+ vTempAngles[PITCH] = EyeAngles()[PITCH];
+ }
+ else
+ {
+ vTempAngles[PITCH] = m_angEyeAngles[PITCH];
+ }
+
+ if ( vTempAngles[YAW] < 0.0f )
+ {
+ vTempAngles[YAW] += 360.0f;
+ }
+
+ SetLocalAngles( vTempAngles );
+
+ BaseClass::PreThink();
+
+ HandleSpeedChanges();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_Portal_Player::AddEntity( void )
+{
+ BaseClass::AddEntity();
+
+ QAngle vTempAngles = GetLocalAngles();
+ vTempAngles[PITCH] = m_angEyeAngles[PITCH];
+
+ SetLocalAngles( vTempAngles );
+
+ // Zero out model pitch, blending takes care of all of it.
+ SetLocalAnglesDim( X_INDEX, 0 );
+
+ if( this != C_BasePlayer::GetLocalPlayer() )
+ {
+ if ( IsEffectActive( EF_DIMLIGHT ) )
+ {
+ int iAttachment = LookupAttachment( "anim_attachment_RH" );
+
+ if ( iAttachment < 0 )
+ return;
+
+ Vector vecOrigin;
+ QAngle eyeAngles = m_angEyeAngles;
+
+ GetAttachment( iAttachment, vecOrigin, eyeAngles );
+
+ Vector vForward;
+ AngleVectors( eyeAngles, &vForward );
+
+ trace_t tr;
+ UTIL_TraceLine( vecOrigin, vecOrigin + (vForward * 200), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+ }
+ }
+}
+
+ShadowType_t C_Portal_Player::ShadowCastType( void )
+{
+ // Drawing player shadows looks bad in first person when they get close to walls
+ // It doesn't make sense to have shadows in the portal view, but not in the main view
+ // So no shadows for the player
+ return SHADOWS_NONE;
+}
+
+bool C_Portal_Player::ShouldDraw( void )
+{
+ if ( !IsAlive() )
+ return false;
+
+ //return true;
+
+ // if( GetTeamNumber() == TEAM_SPECTATOR )
+ // return false;
+
+ if( IsLocalPlayer() && IsRagdoll() )
+ return true;
+
+ if ( IsRagdoll() )
+ return false;
+
+ return true;
+
+ return BaseClass::ShouldDraw();
+}
+
+const QAngle& C_Portal_Player::EyeAngles()
+{
+ if ( IsLocalPlayer() && g_nKillCamMode == OBS_MODE_NONE )
+ {
+ return BaseClass::EyeAngles();
+ }
+ else
+ {
+ //C_BaseEntity *pEntity1 = g_eKillTarget1.Get();
+ //C_BaseEntity *pEntity2 = g_eKillTarget2.Get();
+
+ //Vector vLook = Vector( 0.0f, 0.0f, 0.0f );
+
+ //if ( pEntity2 )
+ //{
+ // vLook = pEntity1->GetAbsOrigin() - pEntity2->GetAbsOrigin();
+ // VectorNormalize( vLook );
+ //}
+ //else if ( pEntity1 )
+ //{
+ // return BaseClass::EyeAngles();
+ // //vLook = - pEntity1->GetAbsOrigin();
+ //}
+
+ //if ( vLook != Vector( 0.0f, 0.0f, 0.0f ) )
+ //{
+ // VectorAngles( vLook, m_angEyeAngles );
+ //}
+
+ return m_angEyeAngles;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : IRagdoll*
+//-----------------------------------------------------------------------------
+IRagdoll* C_Portal_Player::GetRepresentativeRagdoll() const
+{
+ if ( m_hRagdoll.Get() )
+ {
+ C_PortalRagdoll *pRagdoll = static_cast<C_PortalRagdoll*>( m_hRagdoll.Get() );
+ if ( !pRagdoll )
+ return NULL;
+
+ return pRagdoll->GetIRagdoll();
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+void C_Portal_Player::PlayerPortalled( C_Prop_Portal *pEnteredPortal )
+{
+ if( pEnteredPortal )
+ {
+ m_bPortalledMessagePending = true;
+ m_PendingPortalMatrix = pEnteredPortal->MatrixThisToLinked();
+
+ if( IsLocalPlayer() )
+ g_pPortalRender->EnteredPortal( pEnteredPortal );
+ }
+}
+
+void C_Portal_Player::OnPreDataChanged( DataUpdateType_t type )
+{
+ Assert( m_pPortalEnvironment_LastCalcView == m_hPortalEnvironment.Get() );
+ PreDataChanged_Backup.m_hPortalEnvironment = m_hPortalEnvironment;
+ PreDataChanged_Backup.m_hSurroundingLiquidPortal = m_hSurroundingLiquidPortal;
+ PreDataChanged_Backup.m_qEyeAngles = m_iv_angEyeAngles.GetCurrent();
+
+ BaseClass::OnPreDataChanged( type );
+}
+
+void C_Portal_Player::OnDataChanged( DataUpdateType_t type )
+{
+ BaseClass::OnDataChanged( type );
+
+ if( m_hSurroundingLiquidPortal != PreDataChanged_Backup.m_hSurroundingLiquidPortal )
+ {
+ CLiquidPortal_InnerLiquidEffect *pLiquidEffect = (CLiquidPortal_InnerLiquidEffect *)g_pScreenSpaceEffects->GetScreenSpaceEffect( "LiquidPortal_InnerLiquid" );
+ if( pLiquidEffect )
+ {
+ C_Func_LiquidPortal *pSurroundingPortal = m_hSurroundingLiquidPortal.Get();
+ if( pSurroundingPortal != NULL )
+ {
+ C_Func_LiquidPortal *pOldSurroundingPortal = PreDataChanged_Backup.m_hSurroundingLiquidPortal.Get();
+ if( pOldSurroundingPortal != pSurroundingPortal->m_hLinkedPortal.Get() )
+ {
+ pLiquidEffect->m_pImmersionPortal = pSurroundingPortal;
+ pLiquidEffect->m_bFadeBackToReality = false;
+ }
+ else
+ {
+ pLiquidEffect->m_bFadeBackToReality = true;
+ pLiquidEffect->m_fFadeBackTimeLeft = pLiquidEffect->s_fFadeBackEffectTime;
+ }
+ }
+ else
+ {
+ pLiquidEffect->m_pImmersionPortal = NULL;
+ pLiquidEffect->m_bFadeBackToReality = false;
+ }
+ }
+ }
+
+ DetectAndHandlePortalTeleportation();
+
+ if ( type == DATA_UPDATE_CREATED )
+ {
+ // Load color correction lookup for the death effect
+ m_CCDeathHandle = g_pColorCorrectionMgr->AddColorCorrection( DEATH_CC_LOOKUP_FILENAME );
+ if ( m_CCDeathHandle != INVALID_CLIENT_CCHANDLE )
+ {
+ g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCDeathHandle, 0.0f );
+ }
+
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+
+ UpdateVisibility();
+}
+
+//CalcView() gets called between OnPreDataChanged() and OnDataChanged(), and these changes need to be known about in both before CalcView() gets called, and if CalcView() doesn't get called
+bool C_Portal_Player::DetectAndHandlePortalTeleportation( void )
+{
+ if( m_bPortalledMessagePending )
+ {
+ m_bPortalledMessagePending = false;
+
+ //C_Prop_Portal *pOldPortal = PreDataChanged_Backup.m_hPortalEnvironment.Get();
+ //Assert( pOldPortal );
+ //if( pOldPortal )
+ {
+ Vector ptNewPosition = GetNetworkOrigin();
+
+ UTIL_Portal_PointTransform( m_PendingPortalMatrix, PortalEyeInterpolation.m_vEyePosition_Interpolated, PortalEyeInterpolation.m_vEyePosition_Interpolated );
+ UTIL_Portal_PointTransform( m_PendingPortalMatrix, PortalEyeInterpolation.m_vEyePosition_Uninterpolated, PortalEyeInterpolation.m_vEyePosition_Uninterpolated );
+
+ PortalEyeInterpolation.m_bEyePositionIsInterpolating = true;
+
+ UTIL_Portal_AngleTransform( m_PendingPortalMatrix, m_qEyeAngles_LastCalcView, m_angEyeAngles );
+ m_angEyeAngles.x = AngleNormalize( m_angEyeAngles.x );
+ m_angEyeAngles.y = AngleNormalize( m_angEyeAngles.y );
+ m_angEyeAngles.z = AngleNormalize( m_angEyeAngles.z );
+ m_iv_angEyeAngles.Reset(); //copies from m_angEyeAngles
+
+ if( engine->IsPlayingDemo() )
+ {
+ pl.v_angle = m_angEyeAngles;
+ engine->SetViewAngles( pl.v_angle );
+ }
+
+ engine->ResetDemoInterpolation();
+ if( IsLocalPlayer() )
+ {
+ //DevMsg( "FPT: %.2f %.2f %.2f\n", m_angEyeAngles.x, m_angEyeAngles.y, m_angEyeAngles.z );
+ SetLocalAngles( m_angEyeAngles );
+ }
+
+ m_PlayerAnimState->Teleport ( &ptNewPosition, &GetNetworkAngles(), this );
+
+ // Reorient last facing direction to fix pops in view model lag
+ for ( int i = 0; i < MAX_VIEWMODELS; i++ )
+ {
+ CBaseViewModel *vm = GetViewModel( i );
+ if ( !vm )
+ continue;
+
+ UTIL_Portal_VectorTransform( m_PendingPortalMatrix, vm->m_vecLastFacing, vm->m_vecLastFacing );
+ }
+ }
+ m_bPortalledMessagePending = false;
+ }
+
+ return false;
+}
+
+/*bool C_Portal_Player::ShouldInterpolate( void )
+{
+if( !IsInterpolationEnabled() )
+return false;
+
+return BaseClass::ShouldInterpolate();
+}*/
+
+
+void C_Portal_Player::PostDataUpdate( DataUpdateType_t updateType )
+{
+ // C_BaseEntity assumes we're networking the entity's angles, so pretend that it
+ // networked the same value we already have.
+ SetNetworkAngles( GetLocalAngles() );
+
+ if ( m_iSpawnInterpCounter != m_iSpawnInterpCounterCache )
+ {
+ MoveToLastReceivedPosition( true );
+ ResetLatched();
+ m_iSpawnInterpCounterCache = m_iSpawnInterpCounter;
+ }
+
+ BaseClass::PostDataUpdate( updateType );
+}
+
+float C_Portal_Player::GetFOV( void )
+{
+ //Find our FOV with offset zoom value
+ float flFOVOffset = C_BasePlayer::GetFOV() + GetZoom();
+
+ // Clamp FOV in MP
+ int min_fov = GetMinFOV();
+
+ // Don't let it go too low
+ flFOVOffset = MAX( min_fov, flFOVOffset );
+
+ return flFOVOffset;
+}
+
+//=========================================================
+// Autoaim
+// set crosshair position to point to enemey
+//=========================================================
+Vector C_Portal_Player::GetAutoaimVector( float flDelta )
+{
+ // Never autoaim a predicted weapon (for now)
+ Vector forward;
+ AngleVectors( EyeAngles() + m_Local.m_vecPunchAngle, &forward );
+ return forward;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns whether or not we are allowed to sprint now.
+//-----------------------------------------------------------------------------
+bool C_Portal_Player::CanSprint( void )
+{
+ return ( (!m_Local.m_bDucked && !m_Local.m_bDucking) && (GetWaterLevel() != 3) );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_Portal_Player::StartSprinting( void )
+{
+ //if( m_HL2Local.m_flSuitPower < 10 )
+ //{
+ // // Don't sprint unless there's a reasonable
+ // // amount of suit power.
+ // CPASAttenuationFilter filter( this );
+ // filter.UsePredictionRules();
+ // EmitSound( filter, entindex(), "Player.SprintNoPower" );
+ // return;
+ //}
+
+ CPASAttenuationFilter filter( this );
+ filter.UsePredictionRules();
+ EmitSound( filter, entindex(), "Player.SprintStart" );
+
+ SetMaxSpeed( _SPRINT_SPEED );
+ m_fIsSprinting = true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_Portal_Player::StopSprinting( void )
+{
+ SetMaxSpeed( _NORM_SPEED );
+ m_fIsSprinting = false;
+}
+
+void C_Portal_Player::HandleSpeedChanges( void )
+{
+ int buttonsChanged = m_afButtonPressed | m_afButtonReleased;
+
+ if( buttonsChanged & IN_SPEED )
+ {
+ if ( !(m_afButtonPressed & IN_SPEED) && IsSprinting() )
+ {
+ StopSprinting();
+ }
+ else if ( (m_afButtonPressed & IN_SPEED) && !IsSprinting() )
+ {
+ if ( CanSprint() )
+ {
+ StartSprinting();
+ }
+ else
+ {
+ // Reset key, so it will be activated post whatever is suppressing it.
+ m_nButtons &= ~IN_SPEED;
+ }
+ }
+ }
+}
+
+void C_Portal_Player::ItemPreFrame( void )
+{
+ if ( GetFlags() & FL_FROZEN )
+ return;
+
+ // Disallow shooting while zooming
+ if ( m_nButtons & IN_ZOOM )
+ {
+ //FIXME: Held weapons like the grenade get sad when this happens
+ m_nButtons &= ~(IN_ATTACK|IN_ATTACK2);
+ }
+
+ BaseClass::ItemPreFrame();
+
+}
+
+void C_Portal_Player::ItemPostFrame( void )
+{
+ if ( GetFlags() & FL_FROZEN )
+ return;
+
+ BaseClass::ItemPostFrame();
+}
+
+C_BaseAnimating *C_Portal_Player::BecomeRagdollOnClient()
+{
+ // Let the C_CSRagdoll entity do this.
+ // m_builtRagdoll = true;
+ return NULL;
+}
+
+void C_Portal_Player::UpdatePortalEyeInterpolation( void )
+{
+#ifdef ENABLE_PORTAL_EYE_INTERPOLATION_CODE
+ //PortalEyeInterpolation.m_bEyePositionIsInterpolating = false;
+ if( PortalEyeInterpolation.m_bUpdatePosition_FreeMove )
+ {
+ PortalEyeInterpolation.m_bUpdatePosition_FreeMove = false;
+
+ C_Prop_Portal *pOldPortal = PreDataChanged_Backup.m_hPortalEnvironment.Get();
+ if( pOldPortal )
+ {
+ UTIL_Portal_PointTransform( pOldPortal->MatrixThisToLinked(), PortalEyeInterpolation.m_vEyePosition_Interpolated, PortalEyeInterpolation.m_vEyePosition_Interpolated );
+ //PortalEyeInterpolation.m_vEyePosition_Interpolated = pOldPortal->m_matrixThisToLinked * PortalEyeInterpolation.m_vEyePosition_Interpolated;
+
+ //Vector vForward;
+ //m_hPortalEnvironment.Get()->GetVectors( &vForward, NULL, NULL );
+
+ PortalEyeInterpolation.m_vEyePosition_Interpolated = EyeFootPosition();
+
+ PortalEyeInterpolation.m_bEyePositionIsInterpolating = true;
+ }
+ }
+
+ if( IsInAVehicle() )
+ PortalEyeInterpolation.m_bEyePositionIsInterpolating = false;
+
+ if( !PortalEyeInterpolation.m_bEyePositionIsInterpolating )
+ {
+ PortalEyeInterpolation.m_vEyePosition_Uninterpolated = EyeFootPosition();
+ PortalEyeInterpolation.m_vEyePosition_Interpolated = PortalEyeInterpolation.m_vEyePosition_Uninterpolated;
+ return;
+ }
+
+ Vector vThisFrameUninterpolatedPosition = EyeFootPosition();
+
+ //find offset between this and last frame's uninterpolated movement, and apply this as freebie movement to the interpolated position
+ PortalEyeInterpolation.m_vEyePosition_Interpolated += (vThisFrameUninterpolatedPosition - PortalEyeInterpolation.m_vEyePosition_Uninterpolated);
+ PortalEyeInterpolation.m_vEyePosition_Uninterpolated = vThisFrameUninterpolatedPosition;
+
+ Vector vDiff = vThisFrameUninterpolatedPosition - PortalEyeInterpolation.m_vEyePosition_Interpolated;
+ float fLength = vDiff.Length();
+ float fFollowSpeed = gpGlobals->frametime * 100.0f;
+ const float fMaxDiff = 150.0f;
+ if( fLength > fMaxDiff )
+ {
+ //camera lagging too far behind, give it a speed boost to bring it within maximum range
+ fFollowSpeed = fLength - fMaxDiff;
+ }
+ else if( fLength < fFollowSpeed )
+ {
+ //final move
+ PortalEyeInterpolation.m_bEyePositionIsInterpolating = false;
+ PortalEyeInterpolation.m_vEyePosition_Interpolated = vThisFrameUninterpolatedPosition;
+ return;
+ }
+
+ if ( fLength > 0.001f )
+ {
+ vDiff *= (fFollowSpeed/fLength);
+ PortalEyeInterpolation.m_vEyePosition_Interpolated += vDiff;
+ }
+ else
+ {
+ PortalEyeInterpolation.m_vEyePosition_Interpolated = vThisFrameUninterpolatedPosition;
+ }
+
+
+
+#else
+ PortalEyeInterpolation.m_vEyePosition_Interpolated = BaseClass::EyePosition();
+#endif
+}
+
+Vector C_Portal_Player::EyePosition()
+{
+ return PortalEyeInterpolation.m_vEyePosition_Interpolated;
+}
+
+Vector C_Portal_Player::EyeFootPosition( const QAngle &qEyeAngles )
+{
+#if 0
+ static int iPrintCounter = 0;
+ ++iPrintCounter;
+ if( iPrintCounter == 50 )
+ {
+ QAngle vAbsAngles = qEyeAngles;
+ DevMsg( "Eye Angles: %f %f %f\n", vAbsAngles.x, vAbsAngles.y, vAbsAngles.z );
+ iPrintCounter = 0;
+ }
+#endif
+
+ //interpolate between feet and normal eye position based on view roll (gets us wall/ceiling & ceiling/ceiling teleportations without an eye position pop)
+ float fFootInterp = fabs(qEyeAngles[ROLL]) * ((1.0f/180.0f) * 0.75f); //0 when facing straight up, 0.75 when facing straight down
+ return (BaseClass::EyePosition() - (fFootInterp * m_vecViewOffset)); //TODO: Find a good Up vector for this rolled player and interpolate along actual eye/foot axis
+}
+
+void C_Portal_Player::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov )
+{
+ DetectAndHandlePortalTeleportation();
+ //if( DetectAndHandlePortalTeleportation() )
+ // DevMsg( "Teleported within OnDataChanged\n" );
+
+ m_iForceNoDrawInPortalSurface = -1;
+ bool bEyeTransform_Backup = m_bEyePositionIsTransformedByPortal;
+ m_bEyePositionIsTransformedByPortal = false; //assume it's not transformed until it provably is
+ UpdatePortalEyeInterpolation();
+
+ QAngle qEyeAngleBackup = EyeAngles();
+ Vector ptEyePositionBackup = EyePosition();
+ C_Prop_Portal *pPortalBackup = m_hPortalEnvironment.Get();
+
+ if ( m_lifeState != LIFE_ALIVE )
+ {
+ if ( g_nKillCamMode != 0 )
+ {
+ return;
+ }
+
+ Vector origin = EyePosition();
+
+ C_BaseEntity* pRagdoll = m_hRagdoll.Get();
+
+ if ( pRagdoll )
+ {
+ origin = pRagdoll->GetAbsOrigin();
+#if !PORTAL_HIDE_PLAYER_RAGDOLL
+ origin.z += VEC_DEAD_VIEWHEIGHT_SCALED( this ).z; // look over ragdoll, not through
+#endif //PORTAL_HIDE_PLAYER_RAGDOLL
+ }
+
+ BaseClass::CalcView( eyeOrigin, eyeAngles, zNear, zFar, fov );
+
+ eyeOrigin = origin;
+
+ Vector vForward;
+ AngleVectors( eyeAngles, &vForward );
+
+ VectorNormalize( vForward );
+#if !PORTAL_HIDE_PLAYER_RAGDOLL
+ VectorMA( origin, -CHASE_CAM_DISTANCE_MAX, vForward, eyeOrigin );
+#endif //PORTAL_HIDE_PLAYER_RAGDOLL
+
+ Vector WALL_MIN( -WALL_OFFSET, -WALL_OFFSET, -WALL_OFFSET );
+ Vector WALL_MAX( WALL_OFFSET, WALL_OFFSET, WALL_OFFSET );
+
+ trace_t trace; // clip against world
+ C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
+ UTIL_TraceHull( origin, eyeOrigin, WALL_MIN, WALL_MAX, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trace );
+ C_BaseEntity::PopEnableAbsRecomputations();
+
+ if (trace.fraction < 1.0)
+ {
+ eyeOrigin = trace.endpos;
+ }
+ }
+ else
+ {
+ IClientVehicle *pVehicle;
+ pVehicle = GetVehicle();
+
+ if ( !pVehicle )
+ {
+ if ( IsObserver() )
+ {
+ CalcObserverView( eyeOrigin, eyeAngles, fov );
+ }
+ else
+ {
+ CalcPlayerView( eyeOrigin, eyeAngles, fov );
+ if( m_hPortalEnvironment.Get() != NULL )
+ {
+ //time for hax
+ m_bEyePositionIsTransformedByPortal = bEyeTransform_Backup;
+ CalcPortalView( eyeOrigin, eyeAngles );
+ }
+ }
+ }
+ else
+ {
+ CalcVehicleView( pVehicle, eyeOrigin, eyeAngles, zNear, zFar, fov );
+ }
+ }
+
+ m_qEyeAngles_LastCalcView = qEyeAngleBackup;
+ m_ptEyePosition_LastCalcView = ptEyePositionBackup;
+ m_pPortalEnvironment_LastCalcView = pPortalBackup;
+
+#ifdef WIN32
+ // NVNT Inform haptics module of fov
+ if(IsLocalPlayer())
+ haptics->UpdatePlayerFOV(fov);
+#endif
+}
+
+void C_Portal_Player::SetLocalViewAngles( const QAngle &viewAngles )
+{
+ // Nothing
+ if ( engine->IsPlayingDemo() )
+ return;
+ BaseClass::SetLocalViewAngles( viewAngles );
+}
+
+void C_Portal_Player::SetViewAngles( const QAngle& ang )
+{
+ BaseClass::SetViewAngles( ang );
+
+ if ( engine->IsPlayingDemo() )
+ {
+ pl.v_angle = ang;
+ }
+}
+
+void C_Portal_Player::CalcPortalView( Vector &eyeOrigin, QAngle &eyeAngles )
+{
+ //although we already ran CalcPlayerView which already did these copies, they also fudge these numbers in ways we don't like, so recopy
+ VectorCopy( EyePosition(), eyeOrigin );
+ VectorCopy( EyeAngles(), eyeAngles );
+
+ //Re-apply the screenshake (we just stomped it)
+ vieweffects->ApplyShake( eyeOrigin, eyeAngles, 1.0 );
+
+ C_Prop_Portal *pPortal = m_hPortalEnvironment.Get();
+ assert( pPortal );
+
+ C_Prop_Portal *pRemotePortal = pPortal->m_hLinkedPortal;
+ if( !pRemotePortal )
+ {
+ return; //no hacks possible/necessary
+ }
+
+ Vector ptPortalCenter;
+ Vector vPortalForward;
+
+ ptPortalCenter = pPortal->GetNetworkOrigin();
+ pPortal->GetVectors( &vPortalForward, NULL, NULL );
+ float fPortalPlaneDist = vPortalForward.Dot( ptPortalCenter );
+
+ bool bOverrideSpecialEffects = false; //sometimes to get the best effect we need to kill other effects that are simply for cleanliness
+
+ float fEyeDist = vPortalForward.Dot( eyeOrigin ) - fPortalPlaneDist;
+ bool bTransformEye = false;
+ if( fEyeDist < 0.0f ) //eye behind portal
+ {
+ if( pPortal->m_PortalSimulator.EntityIsInPortalHole( this ) ) //player standing in portal
+ {
+ bTransformEye = true;
+ }
+ else if( vPortalForward.z < -0.01f ) //there's a weird case where the player is ducking below a ceiling portal. As they unduck their eye moves beyond the portal before the code detects that they're in the portal hole.
+ {
+ Vector ptPlayerOrigin = GetAbsOrigin();
+ float fOriginDist = vPortalForward.Dot( ptPlayerOrigin ) - fPortalPlaneDist;
+
+ if( fOriginDist > 0.0f )
+ {
+ float fInvTotalDist = 1.0f / (fOriginDist - fEyeDist); //fEyeDist is negative
+ Vector ptPlaneIntersection = (eyeOrigin * fOriginDist * fInvTotalDist) - (ptPlayerOrigin * fEyeDist * fInvTotalDist);
+ Assert( fabs( vPortalForward.Dot( ptPlaneIntersection ) - fPortalPlaneDist ) < 0.01f );
+
+ Vector vIntersectionTest = ptPlaneIntersection - ptPortalCenter;
+
+ Vector vPortalRight, vPortalUp;
+ pPortal->GetVectors( NULL, &vPortalRight, &vPortalUp );
+
+ if( (vIntersectionTest.Dot( vPortalRight ) <= PORTAL_HALF_WIDTH) &&
+ (vIntersectionTest.Dot( vPortalUp ) <= PORTAL_HALF_HEIGHT) )
+ {
+ bTransformEye = true;
+ }
+ }
+ }
+ }
+
+ if( bTransformEye )
+ {
+ m_bEyePositionIsTransformedByPortal = true;
+
+ //DevMsg( 2, "transforming portal view from <%f %f %f> <%f %f %f>\n", eyeOrigin.x, eyeOrigin.y, eyeOrigin.z, eyeAngles.x, eyeAngles.y, eyeAngles.z );
+
+ VMatrix matThisToLinked = pPortal->MatrixThisToLinked();
+ UTIL_Portal_PointTransform( matThisToLinked, eyeOrigin, eyeOrigin );
+ UTIL_Portal_AngleTransform( matThisToLinked, eyeAngles, eyeAngles );
+
+ //DevMsg( 2, "transforming portal view to <%f %f %f> <%f %f %f>\n", eyeOrigin.x, eyeOrigin.y, eyeOrigin.z, eyeAngles.x, eyeAngles.y, eyeAngles.z );
+
+ if ( IsToolRecording() )
+ {
+ static EntityTeleportedRecordingState_t state;
+
+ KeyValues *msg = new KeyValues( "entity_teleported" );
+ msg->SetPtr( "state", &state );
+ state.m_bTeleported = false;
+ state.m_bViewOverride = true;
+ state.m_vecTo = eyeOrigin;
+ state.m_qaTo = eyeAngles;
+ MatrixInvert( matThisToLinked.As3x4(), state.m_teleportMatrix );
+
+ // Post a message back to all IToolSystems
+ Assert( (int)GetToolHandle() != 0 );
+ ToolFramework_PostToolMessage( GetToolHandle(), msg );
+
+ msg->deleteThis();
+ }
+
+ bOverrideSpecialEffects = true;
+ }
+ else
+ {
+ m_bEyePositionIsTransformedByPortal = false;
+ }
+
+ if( bOverrideSpecialEffects )
+ {
+ m_iForceNoDrawInPortalSurface = ((pRemotePortal->m_bIsPortal2)?(2):(1));
+ pRemotePortal->m_fStaticAmount = 0.0f;
+ }
+}
+
+extern float g_fMaxViewModelLag;
+void C_Portal_Player::CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles)
+{
+ // HACK: Manually adjusting the eye position that view model looking up and down are similar
+ // (solves view model "pop" on floor to floor transitions)
+ Vector vInterpEyeOrigin = eyeOrigin;
+
+ Vector vForward;
+ Vector vRight;
+ Vector vUp;
+ AngleVectors( eyeAngles, &vForward, &vRight, &vUp );
+
+ if ( vForward.z < 0.0f )
+ {
+ float fT = vForward.z * vForward.z;
+ vInterpEyeOrigin += vRight * ( fT * 4.7f ) + vForward * ( fT * 5.0f ) + vUp * ( fT * 4.0f );
+ }
+
+ if ( UTIL_IntersectEntityExtentsWithPortal( this ) )
+ g_fMaxViewModelLag = 0.0f;
+ else
+ g_fMaxViewModelLag = 1.5f;
+
+ for ( int i = 0; i < MAX_VIEWMODELS; i++ )
+ {
+ CBaseViewModel *vm = GetViewModel( i );
+ if ( !vm )
+ continue;
+
+ vm->CalcViewModelView( this, vInterpEyeOrigin, eyeAngles );
+ }
+}
+
+bool LocalPlayerIsCloseToPortal( void )
+{
+ return C_Portal_Player::GetLocalPlayer()->IsCloseToPortal();
+}
+