mirror of
https://github.com/fortressforever/fortressforever-2013.git
synced 2025-02-15 08:32:15 +00:00
Our very own player class! (CFF_SH_Player, CFF_CL_Player, CFF_SV_Player)
- Note: FFPlayer still derives from CBaseHLPlayer, which has HL-style sprinting code and whatnot, will probably want to end up removing that inheritance - All references to the old HL2MP player have been switched to our FF player (temporarily if we end up replacing those files)
This commit is contained in:
parent
1d6736cb3c
commit
9818913608
34 changed files with 3774 additions and 91 deletions
|
@ -30,6 +30,16 @@ $Project "Client (FF)"
|
|||
// for FF Shared, see game\shared\ff\ff_shared.vpc
|
||||
$Folder "FF"
|
||||
{
|
||||
$Folder "Game"
|
||||
{
|
||||
|
||||
}
|
||||
$Folder "Player"
|
||||
{
|
||||
$File "ff\ff_cl_player.cpp"
|
||||
$File "ff\ff_cl_player.h"
|
||||
}
|
||||
|
||||
$Folder "Libraries"
|
||||
{
|
||||
$Lib lua
|
||||
|
@ -39,11 +49,20 @@ $Project "Client (FF)"
|
|||
|
||||
// IMPORTANT: remove conflicting hl2dm SDK stuff as we implement our own!!
|
||||
// done for us in HL2DM sdk vpc: -$File "$SRCDIR\game\shared\weapon_parse_default.cpp"
|
||||
|
||||
|
||||
$Folder "HL2 DLL"
|
||||
{
|
||||
-$File "$SRCDIR\game\shared\hl2\hl_gamemovement.cpp"
|
||||
-$File "$SRCDIR\game\shared\hl2\hl_gamemovement.h"
|
||||
}
|
||||
|
||||
$Folder "HL2MP"
|
||||
{
|
||||
// Player
|
||||
-$File "hl2mp\c_hl2mp_player.cpp"
|
||||
-$File "hl2mp\c_hl2mp_player.h"
|
||||
-$File "$SRCDIR\game\shared\hl2mp\hl2mp_player_shared.cpp"
|
||||
-$File "$SRCDIR\game\shared\hl2mp\hl2mp_player_shared.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
985
mp/src/game/client/ff/ff_cl_player.cpp
Normal file
985
mp/src/game/client/ff/ff_cl_player.cpp
Normal file
|
@ -0,0 +1,985 @@
|
|||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Player for FF.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "vcollide_parse.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "view.h"
|
||||
#include "takedamageinfo.h"
|
||||
#include "ff_sh_gamerules.h"
|
||||
#include "in_buttons.h"
|
||||
#include "iviewrender_beams.h" // flashlight beam
|
||||
#include "r_efx.h"
|
||||
#include "dlight.h"
|
||||
|
||||
// Don't alias here
|
||||
#if defined( CFF_SH_Player )
|
||||
#undef CFF_SH_Player
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( player, CFF_CL_Player );
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(CFF_CL_Player, DT_FF_Player, CFF_SV_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_fIsWalking ) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CFF_CL_Player )
|
||||
DEFINE_PRED_FIELD( m_fIsWalking, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
#define HL2_WALK_SPEED 150
|
||||
#define HL2_NORM_SPEED 190
|
||||
#define HL2_SPRINT_SPEED 320
|
||||
|
||||
static ConVar cl_playermodel( "cl_playermodel", "none", FCVAR_USERINFO | FCVAR_ARCHIVE | FCVAR_SERVER_CAN_EXECUTE, "Default Player Model");
|
||||
static ConVar cl_defaultweapon( "cl_defaultweapon", "weapon_physcannon", FCVAR_USERINFO | FCVAR_ARCHIVE, "Default Spawn Weapon");
|
||||
|
||||
void SpawnBlood (Vector vecSpot, const Vector &vecDir, int bloodColor, float flDamage);
|
||||
|
||||
CFF_CL_Player::CFF_CL_Player() : m_PlayerAnimState( this ), m_iv_angEyeAngles( "CFF_CL_Player::m_iv_angEyeAngles" )
|
||||
{
|
||||
m_iIDEntIndex = 0;
|
||||
m_iSpawnInterpCounterCache = 0;
|
||||
|
||||
m_angEyeAngles.Init();
|
||||
|
||||
AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
|
||||
|
||||
m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK;
|
||||
m_blinkTimer.Invalidate();
|
||||
|
||||
m_pFlashlightBeam = NULL;
|
||||
}
|
||||
|
||||
CFF_CL_Player::~CFF_CL_Player( void )
|
||||
{
|
||||
ReleaseFlashlight();
|
||||
}
|
||||
|
||||
int CFF_CL_Player::GetIDTarget() const
|
||||
{
|
||||
return m_iIDEntIndex;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update this client's target entity
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFF_CL_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 CFF_CL_Player::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
|
||||
{
|
||||
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();
|
||||
|
||||
CBaseEntity *pAttacker = info.GetAttacker();
|
||||
|
||||
if ( pAttacker )
|
||||
{
|
||||
if ( FFRules()->IsTeamplay() && pAttacker->InSameTeam( this ) == true )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( blood != DONT_BLEED )
|
||||
{
|
||||
SpawnBlood( vecOrigin, vecDir, blood, flDistance );// a little surface blood.
|
||||
TraceBleed( flDistance, vecDir, ptr, info.GetDamageType() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CFF_CL_Player* CFF_CL_Player::GetLocalFFPlayer()
|
||||
{
|
||||
return (CFF_CL_Player*)C_BasePlayer::GetLocalPlayer();
|
||||
}
|
||||
|
||||
void CFF_CL_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 *CFF_CL_Player::OnNewModel( void )
|
||||
{
|
||||
CStudioHdr *hdr = BaseClass::OnNewModel();
|
||||
|
||||
Initialize( );
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* Orient head and eyes towards m_lookAt.
|
||||
*/
|
||||
void CFF_CL_Player::UpdateLookAt( void )
|
||||
{
|
||||
// head yaw
|
||||
if (m_headYawPoseParam < 0 || m_headPitchPoseParam < 0)
|
||||
return;
|
||||
|
||||
// orient eyes
|
||||
m_viewtarget = m_vLookAtTarget;
|
||||
|
||||
// blinking
|
||||
if (m_blinkTimer.IsElapsed())
|
||||
{
|
||||
m_blinktoggle = !m_blinktoggle;
|
||||
m_blinkTimer.Start( RandomFloat( 1.5f, 4.0f ) );
|
||||
}
|
||||
|
||||
// Figure out where we want to look in world space.
|
||||
QAngle desiredAngles;
|
||||
Vector to = m_vLookAtTarget - EyePosition();
|
||||
VectorAngles( to, desiredAngles );
|
||||
|
||||
// Figure out where our body is facing in world space.
|
||||
QAngle bodyAngles( 0, 0, 0 );
|
||||
bodyAngles[YAW] = GetLocalAngles()[YAW];
|
||||
|
||||
|
||||
float flBodyYawDiff = bodyAngles[YAW] - m_flLastBodyYaw;
|
||||
m_flLastBodyYaw = bodyAngles[YAW];
|
||||
|
||||
|
||||
// Set the head's yaw.
|
||||
float desired = AngleNormalize( desiredAngles[YAW] - bodyAngles[YAW] );
|
||||
desired = clamp( desired, m_headYawMin, m_headYawMax );
|
||||
m_flCurrentHeadYaw = ApproachAngle( desired, m_flCurrentHeadYaw, 130 * gpGlobals->frametime );
|
||||
|
||||
// Counterrotate the head from the body rotation so it doesn't rotate past its target.
|
||||
m_flCurrentHeadYaw = AngleNormalize( m_flCurrentHeadYaw - flBodyYawDiff );
|
||||
desired = clamp( desired, m_headYawMin, m_headYawMax );
|
||||
|
||||
SetPoseParameter( m_headYawPoseParam, m_flCurrentHeadYaw );
|
||||
|
||||
|
||||
// Set the head's yaw.
|
||||
desired = AngleNormalize( desiredAngles[PITCH] );
|
||||
desired = clamp( desired, m_headPitchMin, m_headPitchMax );
|
||||
|
||||
m_flCurrentHeadPitch = ApproachAngle( desired, m_flCurrentHeadPitch, 130 * gpGlobals->frametime );
|
||||
m_flCurrentHeadPitch = AngleNormalize( m_flCurrentHeadPitch );
|
||||
SetPoseParameter( m_headPitchPoseParam, m_flCurrentHeadPitch );
|
||||
}
|
||||
|
||||
void CFF_CL_Player::ClientThink( void )
|
||||
{
|
||||
bool bFoundViewTarget = false;
|
||||
|
||||
Vector vForward;
|
||||
AngleVectors( GetLocalAngles(), &vForward );
|
||||
|
||||
for( int iClient = 1; iClient <= gpGlobals->maxClients; ++iClient )
|
||||
{
|
||||
CBaseEntity *pEnt = UTIL_PlayerByIndex( iClient );
|
||||
if(!pEnt || !pEnt->IsPlayer())
|
||||
continue;
|
||||
|
||||
if ( pEnt->entindex() == entindex() )
|
||||
continue;
|
||||
|
||||
Vector vTargetOrigin = pEnt->GetAbsOrigin();
|
||||
Vector vMyOrigin = GetAbsOrigin();
|
||||
|
||||
Vector vDir = vTargetOrigin - vMyOrigin;
|
||||
|
||||
if ( vDir.Length() > 128 )
|
||||
continue;
|
||||
|
||||
VectorNormalize( vDir );
|
||||
|
||||
if ( DotProduct( vForward, vDir ) < 0.0f )
|
||||
continue;
|
||||
|
||||
m_vLookAtTarget = pEnt->EyePosition();
|
||||
bFoundViewTarget = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( bFoundViewTarget == false )
|
||||
{
|
||||
m_vLookAtTarget = GetAbsOrigin() + vForward * 512;
|
||||
}
|
||||
|
||||
UpdateIDTarget();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFF_CL_Player::DrawModel( int flags )
|
||||
{
|
||||
if ( !m_bReadyToDraw )
|
||||
return 0;
|
||||
|
||||
return BaseClass::DrawModel(flags);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Should this object receive shadows?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFF_CL_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 CFF_CL_Player::DoImpactEffect( trace_t &tr, int nDamageType )
|
||||
{
|
||||
if ( GetActiveWeapon() )
|
||||
{
|
||||
GetActiveWeapon()->DoImpactEffect( tr, nDamageType );
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::DoImpactEffect( tr, nDamageType );
|
||||
}
|
||||
|
||||
void CFF_CL_Player::PreThink( void )
|
||||
{
|
||||
QAngle vTempAngles = GetLocalAngles();
|
||||
|
||||
if ( GetLocalPlayer() == this )
|
||||
{
|
||||
vTempAngles[PITCH] = EyeAngles()[PITCH];
|
||||
}
|
||||
else
|
||||
{
|
||||
vTempAngles[PITCH] = m_angEyeAngles[PITCH];
|
||||
}
|
||||
|
||||
if ( vTempAngles[YAW] < 0.0f )
|
||||
{
|
||||
vTempAngles[YAW] += 360.0f;
|
||||
}
|
||||
|
||||
SetLocalAngles( vTempAngles );
|
||||
|
||||
BaseClass::PreThink();
|
||||
|
||||
HandleSpeedChanges();
|
||||
|
||||
if ( m_HL2Local.m_flSuitPower <= 0.0f )
|
||||
{
|
||||
if( IsSprinting() )
|
||||
{
|
||||
StopSprinting();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const QAngle &CFF_CL_Player::EyeAngles()
|
||||
{
|
||||
if( IsLocalPlayer() )
|
||||
{
|
||||
return BaseClass::EyeAngles();
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_angEyeAngles;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFF_CL_Player::AddEntity( void )
|
||||
{
|
||||
BaseClass::AddEntity();
|
||||
|
||||
QAngle vTempAngles = GetLocalAngles();
|
||||
vTempAngles[PITCH] = m_angEyeAngles[PITCH];
|
||||
|
||||
SetLocalAngles( vTempAngles );
|
||||
|
||||
m_PlayerAnimState.Update();
|
||||
|
||||
// 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 );
|
||||
|
||||
if( !m_pFlashlightBeam )
|
||||
{
|
||||
BeamInfo_t beamInfo;
|
||||
beamInfo.m_nType = TE_BEAMPOINTS;
|
||||
beamInfo.m_vecStart = tr.startpos;
|
||||
beamInfo.m_vecEnd = tr.endpos;
|
||||
beamInfo.m_pszModelName = "sprites/glow01.vmt";
|
||||
beamInfo.m_pszHaloName = "sprites/glow01.vmt";
|
||||
beamInfo.m_flHaloScale = 3.0;
|
||||
beamInfo.m_flWidth = 8.0f;
|
||||
beamInfo.m_flEndWidth = 35.0f;
|
||||
beamInfo.m_flFadeLength = 300.0f;
|
||||
beamInfo.m_flAmplitude = 0;
|
||||
beamInfo.m_flBrightness = 60.0;
|
||||
beamInfo.m_flSpeed = 0.0f;
|
||||
beamInfo.m_nStartFrame = 0.0;
|
||||
beamInfo.m_flFrameRate = 0.0;
|
||||
beamInfo.m_flRed = 255.0;
|
||||
beamInfo.m_flGreen = 255.0;
|
||||
beamInfo.m_flBlue = 255.0;
|
||||
beamInfo.m_nSegments = 8;
|
||||
beamInfo.m_bRenderable = true;
|
||||
beamInfo.m_flLife = 0.5;
|
||||
beamInfo.m_nFlags = FBEAM_FOREVER | FBEAM_ONLYNOISEONCE | FBEAM_NOTILE | FBEAM_HALOBEAM;
|
||||
|
||||
m_pFlashlightBeam = beams->CreateBeamPoints( beamInfo );
|
||||
}
|
||||
|
||||
if( m_pFlashlightBeam )
|
||||
{
|
||||
BeamInfo_t beamInfo;
|
||||
beamInfo.m_vecStart = tr.startpos;
|
||||
beamInfo.m_vecEnd = tr.endpos;
|
||||
beamInfo.m_flRed = 255.0;
|
||||
beamInfo.m_flGreen = 255.0;
|
||||
beamInfo.m_flBlue = 255.0;
|
||||
|
||||
beams->UpdateBeamInfo( m_pFlashlightBeam, beamInfo );
|
||||
|
||||
dlight_t *el = effects->CL_AllocDlight( 0 );
|
||||
el->origin = tr.endpos;
|
||||
el->radius = 50;
|
||||
el->color.r = 200;
|
||||
el->color.g = 200;
|
||||
el->color.b = 200;
|
||||
el->die = gpGlobals->curtime + 0.1;
|
||||
}
|
||||
}
|
||||
else if ( m_pFlashlightBeam )
|
||||
{
|
||||
ReleaseFlashlight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShadowType_t CFF_CL_Player::ShadowCastType( void )
|
||||
{
|
||||
if ( !IsVisible() )
|
||||
return SHADOWS_NONE;
|
||||
|
||||
return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
|
||||
}
|
||||
|
||||
|
||||
const QAngle& CFF_CL_Player::GetRenderAngles()
|
||||
{
|
||||
if ( IsRagdoll() )
|
||||
{
|
||||
return vec3_angle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_PlayerAnimState.GetRenderAngles();
|
||||
}
|
||||
}
|
||||
|
||||
bool CFF_CL_Player::ShouldDraw( void )
|
||||
{
|
||||
// If we're dead, our ragdoll will be drawn for us instead.
|
||||
if ( !IsAlive() )
|
||||
return false;
|
||||
|
||||
// if( GetTeamNumber() == TEAM_SPECTATOR )
|
||||
// return false;
|
||||
|
||||
if( IsLocalPlayer() && IsRagdoll() )
|
||||
return true;
|
||||
|
||||
if ( IsRagdoll() )
|
||||
return false;
|
||||
|
||||
return BaseClass::ShouldDraw();
|
||||
}
|
||||
|
||||
void CFF_CL_Player::NotifyShouldTransmit( ShouldTransmitState_t state )
|
||||
{
|
||||
if ( state == SHOULDTRANSMIT_END )
|
||||
{
|
||||
if( m_pFlashlightBeam != NULL )
|
||||
{
|
||||
ReleaseFlashlight();
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::NotifyShouldTransmit( state );
|
||||
}
|
||||
|
||||
void CFF_CL_Player::OnDataChanged( DataUpdateType_t type )
|
||||
{
|
||||
BaseClass::OnDataChanged( type );
|
||||
|
||||
if ( type == DATA_UPDATE_CREATED )
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
}
|
||||
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void CFF_CL_Player::PostDataUpdate( DataUpdateType_t updateType )
|
||||
{
|
||||
if ( m_iSpawnInterpCounter != m_iSpawnInterpCounterCache )
|
||||
{
|
||||
MoveToLastReceivedPosition( true );
|
||||
ResetLatched();
|
||||
m_iSpawnInterpCounterCache = m_iSpawnInterpCounter;
|
||||
}
|
||||
|
||||
BaseClass::PostDataUpdate( updateType );
|
||||
}
|
||||
|
||||
void CFF_CL_Player::ReleaseFlashlight( void )
|
||||
{
|
||||
if( m_pFlashlightBeam )
|
||||
{
|
||||
m_pFlashlightBeam->flags = 0;
|
||||
m_pFlashlightBeam->die = gpGlobals->curtime - 1;
|
||||
|
||||
m_pFlashlightBeam = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
float CFF_CL_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 CFF_CL_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 CFF_CL_Player::CanSprint( void )
|
||||
{
|
||||
return ( (!m_Local.m_bDucked && !m_Local.m_bDucking) && (GetWaterLevel() != 3) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFF_CL_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(), "HL2Player.SprintNoPower" );
|
||||
return;
|
||||
}
|
||||
|
||||
CPASAttenuationFilter filter( this );
|
||||
filter.UsePredictionRules();
|
||||
EmitSound( filter, entindex(), "HL2Player.SprintStart" );
|
||||
|
||||
SetMaxSpeed( HL2_SPRINT_SPEED );
|
||||
m_fIsSprinting = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFF_CL_Player::StopSprinting( void )
|
||||
{
|
||||
SetMaxSpeed( HL2_NORM_SPEED );
|
||||
m_fIsSprinting = false;
|
||||
}
|
||||
|
||||
void CFF_CL_Player::HandleSpeedChanges( void )
|
||||
{
|
||||
int buttonsChanged = m_afButtonPressed | m_afButtonReleased;
|
||||
|
||||
if( buttonsChanged & IN_SPEED )
|
||||
{
|
||||
// The state of the sprint/run button has changed.
|
||||
if ( IsSuitEquipped() )
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( buttonsChanged & IN_WALK )
|
||||
{
|
||||
if ( IsSuitEquipped() )
|
||||
{
|
||||
// The state of the WALK button has changed.
|
||||
if( IsWalking() && !(m_afButtonPressed & IN_WALK) )
|
||||
{
|
||||
StopWalking();
|
||||
}
|
||||
else if( !IsWalking() && !IsSprinting() && (m_afButtonPressed & IN_WALK) && !(m_nButtons & IN_DUCK) )
|
||||
{
|
||||
StartWalking();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( IsSuitEquipped() && m_fIsWalking && !(m_nButtons & IN_WALK) )
|
||||
StopWalking();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFF_CL_Player::StartWalking( void )
|
||||
{
|
||||
SetMaxSpeed( HL2_WALK_SPEED );
|
||||
m_fIsWalking = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFF_CL_Player::StopWalking( void )
|
||||
{
|
||||
SetMaxSpeed( HL2_NORM_SPEED );
|
||||
m_fIsWalking = false;
|
||||
}
|
||||
|
||||
void CFF_CL_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 CFF_CL_Player::ItemPostFrame( void )
|
||||
{
|
||||
if ( GetFlags() & FL_FROZEN )
|
||||
return;
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
}
|
||||
|
||||
C_BaseAnimating *CFF_CL_Player::BecomeRagdollOnClient()
|
||||
{
|
||||
// Let the C_CSRagdoll entity do this.
|
||||
// m_builtRagdoll = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CFF_CL_Player::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov )
|
||||
{
|
||||
if ( m_lifeState != LIFE_ALIVE && !IsObserver() )
|
||||
{
|
||||
Vector origin = EyePosition();
|
||||
|
||||
IRagdoll *pRagdoll = GetRepresentativeRagdoll();
|
||||
|
||||
if ( pRagdoll )
|
||||
{
|
||||
origin = pRagdoll->GetRagdollOrigin();
|
||||
origin.z += VEC_DEAD_VIEWHEIGHT_SCALED( this ).z; // look over ragdoll, not through
|
||||
}
|
||||
|
||||
BaseClass::CalcView( eyeOrigin, eyeAngles, zNear, zFar, fov );
|
||||
|
||||
eyeOrigin = origin;
|
||||
|
||||
Vector vForward;
|
||||
AngleVectors( eyeAngles, &vForward );
|
||||
|
||||
VectorNormalize( vForward );
|
||||
VectorMA( origin, -CHASE_CAM_DISTANCE_MAX, vForward, eyeOrigin );
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::CalcView( eyeOrigin, eyeAngles, zNear, zFar, fov );
|
||||
}
|
||||
|
||||
IRagdoll* CFF_CL_Player::GetRepresentativeRagdoll() const
|
||||
{
|
||||
if ( m_hRagdoll.Get() )
|
||||
{
|
||||
CFF_CL_Ragdoll *pRagdoll = (CFF_CL_Ragdoll*)m_hRagdoll.Get();
|
||||
|
||||
return pRagdoll->GetIRagdoll();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//FFRAGDOLL
|
||||
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT_NOBASE( CFF_CL_Ragdoll, DT_FFRagdoll, CFF_SV_Ragdoll )
|
||||
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()
|
||||
|
||||
|
||||
|
||||
CFF_CL_Ragdoll::CFF_CL_Ragdoll()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CFF_CL_Ragdoll::~CFF_CL_Ragdoll()
|
||||
{
|
||||
PhysCleanupFrictionSounds( this );
|
||||
|
||||
if ( m_hPlayer )
|
||||
{
|
||||
m_hPlayer->CreateModelInstance();
|
||||
}
|
||||
}
|
||||
|
||||
void CFF_CL_Ragdoll::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];
|
||||
const char *pszName = pDestEntry->watcher->GetDebugName();
|
||||
for ( int j=0; j < pSrc->m_Entries.Count(); j++ )
|
||||
{
|
||||
VarMapEntry_t *pSrcEntry = &pSrc->m_Entries[j];
|
||||
if ( !Q_strcmp( pSrcEntry->watcher->GetDebugName(), pszName ) )
|
||||
{
|
||||
pDestEntry->watcher->Copy( pSrcEntry->watcher );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CFF_CL_Ragdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName )
|
||||
{
|
||||
IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
|
||||
|
||||
if( !pPhysicsObject )
|
||||
return;
|
||||
|
||||
Vector dir = pTrace->endpos - pTrace->startpos;
|
||||
|
||||
if ( iDamageType == DMG_BLAST )
|
||||
{
|
||||
dir *= 4000; // adjust impact strenght
|
||||
|
||||
// apply force at object mass center
|
||||
pPhysicsObject->ApplyForceCenter( dir );
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector hitpos;
|
||||
|
||||
VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos );
|
||||
VectorNormalize( dir );
|
||||
|
||||
dir *= 4000; // adjust impact strenght
|
||||
|
||||
// apply force where we hit it
|
||||
pPhysicsObject->ApplyForceOffset( dir, hitpos );
|
||||
|
||||
// Blood spray!
|
||||
// FX_CS_BloodSpray( hitpos, dir, 10 );
|
||||
}
|
||||
|
||||
m_pRagdoll->ResetRagdollSleepAfterTime();
|
||||
}
|
||||
|
||||
|
||||
void CFF_CL_Ragdoll::CreateFFRagdoll( void )
|
||||
{
|
||||
// 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.
|
||||
CFF_CL_Player *pPlayer = dynamic_cast< CFF_CL_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();
|
||||
|
||||
// Copy all the interpolated vars from the player entity.
|
||||
// The entity uses the interpolated history to get bone velocity.
|
||||
bool bRemotePlayer = (pPlayer != C_BasePlayer::GetLocalPlayer());
|
||||
if ( bRemotePlayer )
|
||||
{
|
||||
Interp_Copy( pPlayer );
|
||||
|
||||
SetAbsAngles( pPlayer->GetRenderAngles() );
|
||||
GetRotationInterpolator().Reset();
|
||||
|
||||
m_flAnimTime = pPlayer->m_flAnimTime;
|
||||
SetSequence( pPlayer->GetSequence() );
|
||||
m_flPlaybackRate = pPlayer->GetPlaybackRate();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the local player, so set them in a default
|
||||
// pose and slam their velocity, angles and origin
|
||||
SetAbsOrigin( m_vecRagdollOrigin );
|
||||
|
||||
SetAbsAngles( pPlayer->GetRenderAngles() );
|
||||
|
||||
SetAbsVelocity( m_vecRagdollVelocity );
|
||||
|
||||
int iSeq = pPlayer->GetSequence();
|
||||
if ( iSeq == -1 )
|
||||
{
|
||||
Assert( false ); // missing walk_lower?
|
||||
iSeq = 0;
|
||||
}
|
||||
|
||||
SetSequence( iSeq ); // walk_lower, basic pose
|
||||
SetCycle( 0.0 );
|
||||
|
||||
Interp_Reset( varMap );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// overwrite network origin so later interpolation will
|
||||
// use this position
|
||||
SetNetworkOrigin( m_vecRagdollOrigin );
|
||||
|
||||
SetAbsOrigin( m_vecRagdollOrigin );
|
||||
SetAbsVelocity( m_vecRagdollVelocity );
|
||||
|
||||
Interp_Reset( GetVarMapping() );
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if ( pPlayer && !pPlayer->IsDormant() )
|
||||
{
|
||||
pPlayer->GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
|
||||
}
|
||||
|
||||
InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt );
|
||||
}
|
||||
|
||||
|
||||
void CFF_CL_Ragdoll::OnDataChanged( DataUpdateType_t type )
|
||||
{
|
||||
BaseClass::OnDataChanged( type );
|
||||
|
||||
if ( type == DATA_UPDATE_CREATED )
|
||||
{
|
||||
CreateFFRagdoll();
|
||||
}
|
||||
}
|
||||
|
||||
IRagdoll* CFF_CL_Ragdoll::GetIRagdoll() const
|
||||
{
|
||||
return m_pRagdoll;
|
||||
}
|
||||
|
||||
void CFF_CL_Ragdoll::UpdateOnRemove( void )
|
||||
{
|
||||
VPhysicsSetObject( NULL );
|
||||
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: clear out any face/eye values stored in the material system
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFF_CL_Ragdoll::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
|
||||
{
|
||||
BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
|
||||
|
||||
static float destweight[128];
|
||||
static bool bIsInited = false;
|
||||
|
||||
CStudioHdr *hdr = GetModelPtr();
|
||||
if ( !hdr )
|
||||
return;
|
||||
|
||||
int nFlexDescCount = hdr->numflexdesc();
|
||||
if ( nFlexDescCount )
|
||||
{
|
||||
Assert( !pFlexDelayedWeights );
|
||||
memset( pFlexWeights, 0, nFlexWeightCount * sizeof(float) );
|
||||
}
|
||||
|
||||
if ( m_iEyeAttachment > 0 )
|
||||
{
|
||||
matrix3x4_t attToWorld;
|
||||
if (GetAttachment( m_iEyeAttachment, attToWorld ))
|
||||
{
|
||||
Vector local, tmp;
|
||||
local.Init( 1000.0f, 0.0f, 0.0f );
|
||||
VectorTransform( local, attToWorld, tmp );
|
||||
modelrender->SetViewTarget( GetModelPtr(), GetBody(), tmp );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CFF_CL_Player::PostThink( void )
|
||||
{
|
||||
BaseClass::PostThink();
|
||||
|
||||
// Store the eye angles pitch so the client can compute its animation state correctly.
|
||||
m_angEyeAngles = EyeAngles();
|
||||
}
|
173
mp/src/game/client/ff/ff_cl_player.h
Normal file
173
mp/src/game/client/ff/ff_cl_player.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#ifndef FF_CL_PLAYER_H
|
||||
#define FF_CL_PLAYER_H
|
||||
#pragma once
|
||||
|
||||
class CFF_CL_Player;
|
||||
#include "c_basehlplayer.h"
|
||||
#include "ff_sh_player.h"
|
||||
#include "beamdraw.h"
|
||||
|
||||
//=============================================================================
|
||||
// >> FF_Player
|
||||
//=============================================================================
|
||||
class CFF_CL_Player : public C_BaseHLPlayer
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CFF_CL_Player, C_BaseHLPlayer );
|
||||
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
DECLARE_INTERPOLATION();
|
||||
|
||||
|
||||
CFF_CL_Player();
|
||||
~CFF_CL_Player( void );
|
||||
|
||||
void ClientThink( void );
|
||||
|
||||
static CFF_CL_Player* GetLocalFFPlayer();
|
||||
|
||||
virtual int DrawModel( int flags );
|
||||
virtual void AddEntity( void );
|
||||
|
||||
QAngle GetAnimEyeAngles( void ) { return m_angEyeAngles; }
|
||||
Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL );
|
||||
|
||||
|
||||
// Should this object cast shadows?
|
||||
virtual ShadowType_t ShadowCastType( void );
|
||||
virtual C_BaseAnimating *BecomeRagdollOnClient();
|
||||
virtual const QAngle& GetRenderAngles();
|
||||
virtual bool ShouldDraw( void );
|
||||
virtual void OnDataChanged( DataUpdateType_t type );
|
||||
virtual float GetFOV( void );
|
||||
virtual CStudioHdr *OnNewModel( void );
|
||||
virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
|
||||
virtual void ItemPreFrame( void );
|
||||
virtual void ItemPostFrame( void );
|
||||
virtual float GetMinFOV() const { return 5.0f; }
|
||||
virtual Vector GetAutoaimVector( float flDelta );
|
||||
virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
|
||||
virtual void CreateLightEffects( void ) {}
|
||||
virtual bool ShouldReceiveProjectedTextures( int flags );
|
||||
virtual void PostDataUpdate( DataUpdateType_t updateType );
|
||||
virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force );
|
||||
virtual void PreThink( void );
|
||||
virtual void DoImpactEffect( trace_t &tr, int nDamageType );
|
||||
IRagdoll* GetRepresentativeRagdoll() const;
|
||||
virtual void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov );
|
||||
virtual const QAngle& EyeAngles( void );
|
||||
|
||||
|
||||
bool CanSprint( void );
|
||||
void StartSprinting( void );
|
||||
void StopSprinting( void );
|
||||
void HandleSpeedChanges( void );
|
||||
void UpdateLookAt( void );
|
||||
void Initialize( void );
|
||||
int GetIDTarget() const;
|
||||
void UpdateIDTarget( void );
|
||||
void PrecacheFootStepSounds( void );
|
||||
const char *GetPlayerModelSoundPrefix( void );
|
||||
|
||||
FFPlayerState State_Get() const;
|
||||
|
||||
// Walking
|
||||
void StartWalking( void );
|
||||
void StopWalking( void );
|
||||
bool IsWalking( void ) { return m_fIsWalking; }
|
||||
|
||||
virtual void PostThink( void );
|
||||
|
||||
private:
|
||||
|
||||
CFF_CL_Player( const CFF_CL_Player & );
|
||||
|
||||
CPlayerAnimState m_PlayerAnimState;
|
||||
|
||||
QAngle m_angEyeAngles;
|
||||
|
||||
CInterpolatedVar< QAngle > m_iv_angEyeAngles;
|
||||
|
||||
EHANDLE m_hRagdoll;
|
||||
|
||||
int m_headYawPoseParam;
|
||||
int m_headPitchPoseParam;
|
||||
float m_headYawMin;
|
||||
float m_headYawMax;
|
||||
float m_headPitchMin;
|
||||
float m_headPitchMax;
|
||||
|
||||
bool m_isInit;
|
||||
Vector m_vLookAtTarget;
|
||||
|
||||
float m_flLastBodyYaw;
|
||||
float m_flCurrentHeadYaw;
|
||||
float m_flCurrentHeadPitch;
|
||||
|
||||
int m_iIDEntIndex;
|
||||
|
||||
CountdownTimer m_blinkTimer;
|
||||
|
||||
int m_iSpawnInterpCounter;
|
||||
int m_iSpawnInterpCounterCache;
|
||||
|
||||
int m_iPlayerSoundType;
|
||||
|
||||
void ReleaseFlashlight( void );
|
||||
Beam_t *m_pFlashlightBeam;
|
||||
|
||||
CNetworkVar( FFPlayerState, m_iPlayerState );
|
||||
|
||||
bool m_fIsWalking;
|
||||
};
|
||||
|
||||
inline CFF_CL_Player *ToFFPlayer( CBaseEntity *pEntity )
|
||||
{
|
||||
if ( !pEntity || !pEntity->IsPlayer() )
|
||||
return NULL;
|
||||
|
||||
return dynamic_cast<CFF_CL_Player*>( pEntity );
|
||||
}
|
||||
|
||||
|
||||
class CFF_CL_Ragdoll : public C_BaseAnimatingOverlay
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CFF_CL_Ragdoll, C_BaseAnimatingOverlay );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
CFF_CL_Ragdoll();
|
||||
~CFF_CL_Ragdoll();
|
||||
|
||||
virtual void OnDataChanged( DataUpdateType_t type );
|
||||
|
||||
int GetPlayerEntIndex() const;
|
||||
IRagdoll* GetIRagdoll() const;
|
||||
|
||||
void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName );
|
||||
void UpdateOnRemove( void );
|
||||
virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
|
||||
|
||||
private:
|
||||
|
||||
CFF_CL_Ragdoll( const CFF_CL_Ragdoll & ) {}
|
||||
|
||||
void Interp_Copy( C_BaseAnimatingOverlay *pDestinationEntity );
|
||||
void CreateFFRagdoll( void );
|
||||
|
||||
private:
|
||||
|
||||
EHANDLE m_hPlayer;
|
||||
CNetworkVector( m_vecRagdollVelocity );
|
||||
CNetworkVector( m_vecRagdollOrigin );
|
||||
};
|
||||
|
||||
#endif //FF_CL_PLAYER_H
|
|
@ -12,7 +12,7 @@
|
|||
#include "vgui/ILocalize.h"
|
||||
#include "c_team.h"
|
||||
#include "c_playerresource.h"
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "ff_sh_gamerules.h"
|
||||
#include "ihudlcd.h"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "cbase.h"
|
||||
#include "hud.h"
|
||||
#include "hudelement.h"
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "c_playerresource.h"
|
||||
#include "vgui_entitypanel.h"
|
||||
#include "iclientmode.h"
|
||||
|
@ -106,7 +106,7 @@ void CTargetID::Paint()
|
|||
wchar_t sIDString[ MAX_ID_STRING ];
|
||||
sIDString[0] = 0;
|
||||
|
||||
C_HL2MP_Player *pPlayer = C_HL2MP_Player::GetLocalHL2MPPlayer();
|
||||
CFF_CL_Player *pPlayer = CFF_CL_Player::GetLocalFFPlayer();
|
||||
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "cbase.h"
|
||||
#include "hud.h"
|
||||
#include "hudelement.h"
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "c_playerresource.h"
|
||||
#include "vgui_entitypanel.h"
|
||||
#include "iclientmode.h"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "hl2mpclientscoreboard.h"
|
||||
#include "c_team.h"
|
||||
#include "c_playerresource.h"
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "ff_sh_gamerules.h"
|
||||
|
||||
#include <KeyValues.h>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "cbase.h"
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "ff_sh_gamerules.h"
|
||||
#include "gamerules.h"
|
||||
#include "teamplay_gamerules.h"
|
||||
|
@ -38,7 +38,7 @@ ConVar sv_motd_unload_on_dismissal( "sv_motd_unload_on_dismissal", "0", 0, "If e
|
|||
extern CBaseEntity* FindPickerEntityClass( CBasePlayer *pPlayer, char *classname );
|
||||
extern bool g_fGameOver;
|
||||
|
||||
void FinishClientPutInServer( CHL2MP_Player *pPlayer )
|
||||
void FinishClientPutInServer( CFF_SV_Player *pPlayer )
|
||||
{
|
||||
pPlayer->InitialSpawn();
|
||||
pPlayer->Spawn();
|
||||
|
@ -87,7 +87,7 @@ called each time a player is spawned into the game
|
|||
void ClientPutInServer( edict_t *pEdict, const char *playername )
|
||||
{
|
||||
// Allocate a CBaseTFPlayer for pev, and call spawn
|
||||
CHL2MP_Player *pPlayer = CHL2MP_Player::CreatePlayer( "player", pEdict );
|
||||
CFF_SV_Player *pPlayer = CFF_SV_Player::CreatePlayer( "player", pEdict );
|
||||
pPlayer->SetPlayerName( playername );
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ void ClientActive( edict_t *pEdict, bool bLoadGame )
|
|||
// Can't load games in CS!
|
||||
Assert( !bLoadGame );
|
||||
|
||||
CHL2MP_Player *pPlayer = ToHL2MPPlayer( CBaseEntity::Instance( pEdict ) );
|
||||
CFF_SV_Player *pPlayer = ToFFPlayer( CBaseEntity::Instance( pEdict ) );
|
||||
FinishClientPutInServer( pPlayer );
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ void ClientGamePrecache( void )
|
|||
// called by ClientKill and DeadThink
|
||||
void respawn( CBaseEntity *pEdict, bool fCopyCorpse )
|
||||
{
|
||||
CHL2MP_Player *pPlayer = ToHL2MPPlayer( pEdict );
|
||||
CFF_SV_Player *pPlayer = ToFFPlayer( pEdict );
|
||||
|
||||
if ( pPlayer )
|
||||
{
|
||||
|
|
1634
mp/src/game/server/ff/ff_sv_player.cpp
Normal file
1634
mp/src/game/server/ff/ff_sv_player.cpp
Normal file
File diff suppressed because it is too large
Load diff
176
mp/src/game/server/ff/ff_sv_player.h
Normal file
176
mp/src/game/server/ff/ff_sv_player.h
Normal file
|
@ -0,0 +1,176 @@
|
|||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#ifndef FF_SV_PLAYER_H
|
||||
#define FF_SV_PLAYER_H
|
||||
#pragma once
|
||||
|
||||
class CFF_SV_Player;
|
||||
|
||||
#include "basemultiplayerplayer.h"
|
||||
#include "hl2_playerlocaldata.h"
|
||||
#include "hl2_player.h"
|
||||
#include "simtimer.h"
|
||||
#include "soundenvelope.h"
|
||||
#include "ff_sh_player.h"
|
||||
#include "ff_sh_gamerules.h"
|
||||
#include "utldict.h"
|
||||
|
||||
//=============================================================================
|
||||
// >> FF_Player
|
||||
//=============================================================================
|
||||
class CFFPlayerStateInfo
|
||||
{
|
||||
public:
|
||||
FFPlayerState m_iPlayerState;
|
||||
const char *m_pStateName;
|
||||
|
||||
void (CFF_SV_Player::*pfnEnterState)(); // Init and deinit the state.
|
||||
void (CFF_SV_Player::*pfnLeaveState)();
|
||||
|
||||
void (CFF_SV_Player::*pfnPreThink)(); // Do a PreThink() in this state.
|
||||
};
|
||||
|
||||
class CFF_SV_Player : public CHL2_Player
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CFF_SV_Player, CHL2_Player );
|
||||
|
||||
CFF_SV_Player();
|
||||
~CFF_SV_Player( void );
|
||||
|
||||
static CFF_SV_Player *CreatePlayer( const char *className, edict_t *ed )
|
||||
{
|
||||
CFF_SV_Player::s_PlayerEdict = ed;
|
||||
return (CFF_SV_Player*)CreateEntityByName( className );
|
||||
}
|
||||
|
||||
DECLARE_SERVERCLASS();
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual void Precache( void );
|
||||
virtual void Spawn( void );
|
||||
virtual void PostThink( void );
|
||||
virtual void PreThink( void );
|
||||
virtual void PlayerDeathThink( void );
|
||||
virtual void SetAnimation( PLAYER_ANIM playerAnim );
|
||||
virtual bool HandleCommand_JoinTeam( int team );
|
||||
virtual bool ClientCommand( const CCommand &args );
|
||||
virtual void CreateViewModel( int viewmodelindex = 0 );
|
||||
virtual bool BecomeRagdollOnClient( const Vector &force );
|
||||
virtual void Event_Killed( const CTakeDamageInfo &info );
|
||||
virtual int OnTakeDamage( const CTakeDamageInfo &inputInfo );
|
||||
virtual bool WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits ) const;
|
||||
virtual void FireBullets ( const FireBulletsInfo_t &info );
|
||||
virtual bool Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex = 0);
|
||||
virtual bool BumpWeapon( CBaseCombatWeapon *pWeapon );
|
||||
virtual void ChangeTeam( int iTeam );
|
||||
virtual void PickupObject ( CBaseEntity *pObject, bool bLimitMassAndSize );
|
||||
virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force );
|
||||
virtual void Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL );
|
||||
virtual void UpdateOnRemove( void );
|
||||
virtual void DeathSound( const CTakeDamageInfo &info );
|
||||
virtual CBaseEntity* EntSelectSpawnPoint( void );
|
||||
|
||||
int FlashlightIsOn( void );
|
||||
void FlashlightTurnOn( void );
|
||||
void FlashlightTurnOff( void );
|
||||
void PrecacheFootStepSounds( void );
|
||||
bool ValidatePlayerModel( const char *pModel );
|
||||
|
||||
QAngle GetAnimEyeAngles( void ) { return m_angEyeAngles.Get(); }
|
||||
|
||||
Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL );
|
||||
|
||||
void CheatImpulseCommands( int iImpulse );
|
||||
void CreateRagdollEntity( void );
|
||||
void GiveAllItems( void );
|
||||
void GiveDefaultItems( void );
|
||||
|
||||
void NoteWeaponFired( void );
|
||||
|
||||
void ResetAnimation( void );
|
||||
void SetPlayerModel( void );
|
||||
void SetPlayerTeamModel( void );
|
||||
Activity TranslateTeamActivity( Activity ActToTranslate );
|
||||
|
||||
float GetNextModelChangeTime( void ) { return m_flNextModelChangeTime; }
|
||||
float GetNextTeamChangeTime( void ) { return m_flNextTeamChangeTime; }
|
||||
void PickDefaultSpawnTeam( void );
|
||||
void SetupPlayerSoundsByModel( const char *pModelName );
|
||||
const char *GetPlayerModelSoundPrefix( void );
|
||||
int GetPlayerModelType( void ) { return m_iPlayerSoundType; }
|
||||
|
||||
void DetonateTripmines( void );
|
||||
|
||||
void Reset();
|
||||
|
||||
bool IsReady();
|
||||
void SetReady( bool bReady );
|
||||
|
||||
void CheckChatText( char *p, int bufsize );
|
||||
|
||||
void State_Transition( FFPlayerState newState );
|
||||
void State_Enter( FFPlayerState newState );
|
||||
void State_Leave();
|
||||
void State_PreThink();
|
||||
CFFPlayerStateInfo *State_LookupInfo( FFPlayerState state );
|
||||
|
||||
void State_Enter_ACTIVE();
|
||||
void State_PreThink_ACTIVE();
|
||||
void State_Enter_OBSERVER_MODE();
|
||||
void State_PreThink_OBSERVER_MODE();
|
||||
|
||||
|
||||
virtual bool StartObserverMode( int mode );
|
||||
virtual void StopObserverMode( void );
|
||||
|
||||
|
||||
Vector m_vecTotalBulletForce; //Accumulator for bullet force in a single frame
|
||||
|
||||
// Tracks our ragdoll entity.
|
||||
CNetworkHandle( CBaseEntity, m_hRagdoll ); // networked entity handle
|
||||
|
||||
virtual bool CanHearAndReadChatFrom( CBasePlayer *pPlayer );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CNetworkQAngle( m_angEyeAngles );
|
||||
CPlayerAnimState m_PlayerAnimState;
|
||||
|
||||
int m_iLastWeaponFireUsercmd;
|
||||
int m_iModelType;
|
||||
CNetworkVar( int, m_iSpawnInterpCounter );
|
||||
CNetworkVar( int, m_iPlayerSoundType );
|
||||
|
||||
float m_flNextModelChangeTime;
|
||||
float m_flNextTeamChangeTime;
|
||||
|
||||
float m_flSlamProtectTime;
|
||||
|
||||
FFPlayerState m_iPlayerState;
|
||||
CFFPlayerStateInfo *m_pCurStateInfo;
|
||||
|
||||
bool ShouldRunRateLimitedCommand( const CCommand &args );
|
||||
|
||||
// This lets us rate limit the commands the players can execute so they don't overflow things like reliable buffers.
|
||||
CUtlDict<float,int> m_RateLimitLastCommandTimes;
|
||||
|
||||
bool m_bEnterObserver;
|
||||
bool m_bReady;
|
||||
};
|
||||
|
||||
inline CFF_SV_Player *ToFFPlayer( CBaseEntity *pEntity )
|
||||
{
|
||||
if ( !pEntity || !pEntity->IsPlayer() )
|
||||
return NULL;
|
||||
|
||||
return dynamic_cast<CFF_SV_Player*>( pEntity );
|
||||
}
|
||||
|
||||
#endif //FF_SV_PLAYER_H
|
|
@ -14,12 +14,12 @@
|
|||
|
||||
#include "cbase.h"
|
||||
#include "player.h"
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "in_buttons.h"
|
||||
#include "movehelper_server.h"
|
||||
|
||||
void ClientPutInServer( edict_t *pEdict, const char *playername );
|
||||
void Bot_Think( CHL2MP_Player *pBot );
|
||||
void Bot_Think( CFF_SV_Player *pBot );
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
|
@ -91,7 +91,7 @@ CBasePlayer *BotPutInServer( bool bFrozen, int iTeam )
|
|||
|
||||
// Allocate a CBasePlayer for the bot, and call spawn
|
||||
//ClientPutInServer( pEdict, botname );
|
||||
CHL2MP_Player *pPlayer = ((CHL2MP_Player *)CBaseEntity::Instance( pEdict ));
|
||||
CFF_SV_Player *pPlayer = ((CFF_SV_Player *)CBaseEntity::Instance( pEdict ));
|
||||
pPlayer->ClearFlags();
|
||||
pPlayer->AddFlag( FL_CLIENT | FL_FAKECLIENT );
|
||||
|
||||
|
@ -113,7 +113,7 @@ void Bot_RunAll( void )
|
|||
{
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CHL2MP_Player *pPlayer = ToHL2MPPlayer( UTIL_PlayerByIndex( i ) );
|
||||
CFF_SV_Player *pPlayer = ToFFPlayer( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if ( pPlayer && (pPlayer->GetFlags() & FL_FAKECLIENT) )
|
||||
{
|
||||
|
@ -156,7 +156,7 @@ bool RunMimicCommand( CUserCmd& cmd )
|
|||
// msec -
|
||||
// Output : virtual void
|
||||
//-----------------------------------------------------------------------------
|
||||
static void RunPlayerMove( CHL2MP_Player *fakeclient, const QAngle& viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, float frametime )
|
||||
static void RunPlayerMove( CFF_SV_Player *fakeclient, const QAngle& viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, float frametime )
|
||||
{
|
||||
if ( !fakeclient )
|
||||
return;
|
||||
|
@ -206,7 +206,7 @@ static void RunPlayerMove( CHL2MP_Player *fakeclient, const QAngle& viewangles,
|
|||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Run this Bot's AI for one frame.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Bot_Think( CHL2MP_Player *pBot )
|
||||
void Bot_Think( CFF_SV_Player *pBot )
|
||||
{
|
||||
// Make sure we stay being a bot
|
||||
pBot->AddFlag( FL_FAKECLIENT );
|
||||
|
|
|
@ -34,9 +34,17 @@ $Project "Server (FF)"
|
|||
// for FF Shared, see game\shared\ff\ff_shared.vpc
|
||||
$Folder "FF"
|
||||
{
|
||||
$File "FF\ff_sv_client.cpp"
|
||||
$File "FF\ff_sv_gameinterface.cpp"
|
||||
$File "FF\ff_sv_gameinterface.h"
|
||||
$Folder "Game"
|
||||
{
|
||||
$File "FF\ff_sv_client.cpp"
|
||||
$File "FF\ff_sv_gameinterface.cpp"
|
||||
$File "FF\ff_sv_gameinterface.h"
|
||||
}
|
||||
$Folder "Player"
|
||||
{
|
||||
$File "ff\ff_sv_player.cpp"
|
||||
$File "ff\ff_sv_player.h"
|
||||
}
|
||||
|
||||
$Folder "Libraries"
|
||||
{
|
||||
|
@ -59,6 +67,11 @@ $Project "Server (FF)"
|
|||
-$File "hl2mp\hl2mp_client.cpp"
|
||||
-$File "hl2mp\hl2mp_gameinterface.cpp"
|
||||
-$File "hl2mp\hl2mp_gameinterface.h"
|
||||
// Player
|
||||
-$File "hl2mp\hl2mp_player.cpp"
|
||||
-$File "hl2mp\hl2mp_player.h"
|
||||
-$File "$SRCDIR\game\shared\hl2mp\hl2mp_player_shared.cpp"
|
||||
-$File "$SRCDIR\game\shared\hl2mp\hl2mp_player_shared.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "ammodef.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
|
||||
#include "eventqueue.h"
|
||||
|
@ -26,7 +26,7 @@
|
|||
#include <ctype.h>
|
||||
#include "voice_gamemgr.h"
|
||||
#include "iscorer.h"
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
#include "team.h"
|
||||
#include "voice_gamemgr.h"
|
||||
|
@ -764,9 +764,9 @@ void CFF_SH_Rules::ClientSettingsChanged( CBasePlayer *pPlayer )
|
|||
{
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
CHL2MP_Player *pHL2Player = ToHL2MPPlayer( pPlayer );
|
||||
CFF_SH_Player *pFFPlayer = ToFFPlayer( pPlayer );
|
||||
|
||||
if ( pHL2Player == NULL )
|
||||
if ( pFFPlayer == NULL )
|
||||
return;
|
||||
|
||||
const char *pCurrentModel = modelinfo->GetModelName( pPlayer->GetModel() );
|
||||
|
@ -778,44 +778,44 @@ void CFF_SH_Rules::ClientSettingsChanged( CBasePlayer *pPlayer )
|
|||
//Too soon, set the cvar back to what it was.
|
||||
//Note: this will make this function be called again
|
||||
//but since our models will match it'll just skip this whole dealio.
|
||||
if ( pHL2Player->GetNextModelChangeTime() >= gpGlobals->curtime )
|
||||
if ( pFFPlayer->GetNextModelChangeTime() >= gpGlobals->curtime )
|
||||
{
|
||||
char szReturnString[512];
|
||||
|
||||
Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", pCurrentModel );
|
||||
engine->ClientCommand ( pHL2Player->edict(), szReturnString );
|
||||
engine->ClientCommand ( pFFPlayer->edict(), szReturnString );
|
||||
|
||||
Q_snprintf( szReturnString, sizeof( szReturnString ), "Please wait %d more seconds before trying to switch.\n", (int)(pHL2Player->GetNextModelChangeTime() - gpGlobals->curtime) );
|
||||
ClientPrint( pHL2Player, HUD_PRINTTALK, szReturnString );
|
||||
Q_snprintf( szReturnString, sizeof( szReturnString ), "Please wait %d more seconds before trying to switch.\n", (int)(pFFPlayer->GetNextModelChangeTime() - gpGlobals->curtime) );
|
||||
ClientPrint( pFFPlayer, HUD_PRINTTALK, szReturnString );
|
||||
return;
|
||||
}
|
||||
|
||||
if (FFRules()->IsTeamplay() == false )
|
||||
{
|
||||
pHL2Player->SetPlayerModel();
|
||||
pFFPlayer->SetPlayerModel();
|
||||
|
||||
const char *pszCurrentModelName = modelinfo->GetModelName( pHL2Player->GetModel() );
|
||||
const char *pszCurrentModelName = modelinfo->GetModelName( pFFPlayer->GetModel() );
|
||||
|
||||
char szReturnString[128];
|
||||
Q_snprintf( szReturnString, sizeof( szReturnString ), "Your player model is: %s\n", pszCurrentModelName );
|
||||
|
||||
ClientPrint( pHL2Player, HUD_PRINTTALK, szReturnString );
|
||||
ClientPrint( pFFPlayer, HUD_PRINTTALK, szReturnString );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( Q_stristr( szModelName, "models/human") )
|
||||
{
|
||||
pHL2Player->ChangeTeam( TEAM_REBELS );
|
||||
pFFPlayer->ChangeTeam( TEAM_REBELS );
|
||||
}
|
||||
else
|
||||
{
|
||||
pHL2Player->ChangeTeam( TEAM_COMBINE );
|
||||
pFFPlayer->ChangeTeam( TEAM_COMBINE );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( sv_report_client_settings.GetInt() == 1 )
|
||||
{
|
||||
UTIL_LogPrintf( "\"%s\" cl_cmdrate = \"%s\"\n", pHL2Player->GetPlayerName(), engine->GetClientConVarValue( pHL2Player->entindex(), "cl_cmdrate" ));
|
||||
UTIL_LogPrintf( "\"%s\" cl_cmdrate = \"%s\"\n", pFFPlayer->GetPlayerName(), engine->GetClientConVarValue( pFFPlayer->entindex(), "cl_cmdrate" ));
|
||||
}
|
||||
|
||||
BaseClass::ClientSettingsChanged( pPlayer );
|
||||
|
@ -899,7 +899,7 @@ bool CFF_SH_Rules::ClientCommand( CBaseEntity *pEdict, const CCommand &args )
|
|||
return true;
|
||||
|
||||
|
||||
CHL2MP_Player *pPlayer = (CHL2MP_Player *) pEdict;
|
||||
CFF_SH_Player *pPlayer = (CFF_SH_Player *) pEdict;
|
||||
|
||||
if ( pPlayer->ClientCommand( args ) )
|
||||
return true;
|
||||
|
@ -1018,7 +1018,7 @@ void CFF_SH_Rules::RestartGame()
|
|||
// now respawn all players
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CHL2MP_Player *pPlayer = (CHL2MP_Player*) UTIL_PlayerByIndex( i );
|
||||
CFF_SH_Player *pPlayer = (CFF_SH_Player*) UTIL_PlayerByIndex( i );
|
||||
|
||||
if ( !pPlayer )
|
||||
continue;
|
||||
|
@ -1160,7 +1160,7 @@ void CFF_SH_Rules::CleanUpMap()
|
|||
MapEntity_ParseAllEntities( engine->GetMapEntitiesString(), &filter, true );
|
||||
}
|
||||
|
||||
void CFF_SH_Rules::CheckChatForReadySignal( CHL2MP_Player *pPlayer, const char *chatmsg )
|
||||
void CFF_SH_Rules::CheckChatForReadySignal( CFF_SH_Player *pPlayer, const char *chatmsg )
|
||||
{
|
||||
if( m_bAwaitingReadyRestart && FStrEq( chatmsg, mp_ready_signal.GetString() ) )
|
||||
{
|
||||
|
@ -1223,7 +1223,7 @@ void CFF_SH_Rules::CheckAllPlayersReady( void )
|
|||
{
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CHL2MP_Player *pPlayer = (CHL2MP_Player*) UTIL_PlayerByIndex( i );
|
||||
CFF_SH_Player *pPlayer = (CFF_SH_Player*) UTIL_PlayerByIndex( i );
|
||||
|
||||
if ( !pPlayer )
|
||||
continue;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "gamevars_shared.h"
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#endif
|
||||
|
||||
#define VEC_CROUCH_TRACE_MIN FFRules()->GetFFViewVectors()->m_vCrouchTraceMin
|
||||
|
@ -134,7 +134,7 @@ public:
|
|||
void AddLevelDesignerPlacedObject( CBaseEntity *pEntity );
|
||||
void RemoveLevelDesignerPlacedObject( CBaseEntity *pEntity );
|
||||
void ManageObjectRelocation( void );
|
||||
void CheckChatForReadySignal( CHL2MP_Player *pPlayer, const char *chatmsg );
|
||||
void CheckChatForReadySignal( CFF_SH_Player *pPlayer, const char *chatmsg );
|
||||
const char *GetChatFormat( bool bTeamOnly, CBasePlayer *pPlayer );
|
||||
|
||||
#endif
|
||||
|
|
577
mp/src/game/shared/ff/ff_sh_player.cpp
Normal file
577
mp/src/game/shared/ff/ff_sh_player.cpp
Normal file
|
@ -0,0 +1,577 @@
|
|||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "ff_cl_player.h"
|
||||
#include "prediction.h"
|
||||
#define CRecipientFilter C_RecipientFilter
|
||||
#else
|
||||
#include "ff_sv_player.h"
|
||||
#endif
|
||||
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
||||
|
||||
extern ConVar sv_footsteps;
|
||||
|
||||
const char *g_ppszPlayerSoundPrefixNames[PLAYER_SOUNDS_MAX] =
|
||||
{
|
||||
"NPC_Citizen",
|
||||
"NPC_CombineS",
|
||||
"NPC_MetroPolice",
|
||||
};
|
||||
|
||||
const char *CFF_SH_Player::GetPlayerModelSoundPrefix( void )
|
||||
{
|
||||
return g_ppszPlayerSoundPrefixNames[m_iPlayerSoundType];
|
||||
}
|
||||
|
||||
void CFF_SH_Player::PrecacheFootStepSounds( void )
|
||||
{
|
||||
int iFootstepSounds = ARRAYSIZE( g_ppszPlayerSoundPrefixNames );
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < iFootstepSounds; ++i )
|
||||
{
|
||||
char szFootStepName[128];
|
||||
|
||||
Q_snprintf( szFootStepName, sizeof( szFootStepName ), "%s.RunFootstepLeft", g_ppszPlayerSoundPrefixNames[i] );
|
||||
PrecacheScriptSound( szFootStepName );
|
||||
|
||||
Q_snprintf( szFootStepName, sizeof( szFootStepName ), "%s.RunFootstepRight", g_ppszPlayerSoundPrefixNames[i] );
|
||||
PrecacheScriptSound( szFootStepName );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Consider the weapon's built-in accuracy, this character's proficiency with
|
||||
// the weapon, and the status of the target. Use this information to determine
|
||||
// how accurately to shoot at the target.
|
||||
//-----------------------------------------------------------------------------
|
||||
Vector CFF_SH_Player::GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget )
|
||||
{
|
||||
if ( pWeapon )
|
||||
return pWeapon->GetBulletSpread( WEAPON_PROFICIENCY_PERFECT );
|
||||
|
||||
return VECTOR_CONE_15DEGREES;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : step -
|
||||
// fvol -
|
||||
// force - force sound to play
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFF_SH_Player::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force )
|
||||
{
|
||||
if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
|
||||
return;
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
// during prediction play footstep sounds only once
|
||||
if ( !prediction->IsFirstTimePredicted() )
|
||||
return;
|
||||
#endif
|
||||
|
||||
if ( GetFlags() & FL_DUCKING )
|
||||
return;
|
||||
|
||||
m_Local.m_nStepside = !m_Local.m_nStepside;
|
||||
|
||||
char szStepSound[128];
|
||||
|
||||
if ( m_Local.m_nStepside )
|
||||
{
|
||||
Q_snprintf( szStepSound, sizeof( szStepSound ), "%s.RunFootstepLeft", g_ppszPlayerSoundPrefixNames[m_iPlayerSoundType] );
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_snprintf( szStepSound, sizeof( szStepSound ), "%s.RunFootstepRight", g_ppszPlayerSoundPrefixNames[m_iPlayerSoundType] );
|
||||
}
|
||||
|
||||
CSoundParameters params;
|
||||
if ( GetParametersForSound( szStepSound, params, NULL ) == false )
|
||||
return;
|
||||
|
||||
CRecipientFilter filter;
|
||||
filter.AddRecipientsByPAS( vecOrigin );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// im MP, server removed all players in origins PVS, these players
|
||||
// generate the footsteps clientside
|
||||
if ( gpGlobals->maxClients > 1 )
|
||||
filter.RemoveRecipientsByPVS( vecOrigin );
|
||||
#endif
|
||||
|
||||
EmitSound_t ep;
|
||||
ep.m_nChannel = CHAN_BODY;
|
||||
ep.m_pSoundName = params.soundname;
|
||||
ep.m_flVolume = fvol;
|
||||
ep.m_SoundLevel = params.soundlevel;
|
||||
ep.m_nFlags = 0;
|
||||
ep.m_nPitch = params.pitch;
|
||||
ep.m_pOrigin = &vecOrigin;
|
||||
|
||||
EmitSound( filter, entindex(), ep );
|
||||
}
|
||||
|
||||
|
||||
//==========================
|
||||
// ANIMATION CODE
|
||||
//==========================
|
||||
|
||||
|
||||
// Below this many degrees, slow down turning rate linearly
|
||||
#define FADE_TURN_DEGREES 45.0f
|
||||
// After this, need to start turning feet
|
||||
#define MAX_TORSO_ANGLE 90.0f
|
||||
// Below this amount, don't play a turning animation/perform IK
|
||||
#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f
|
||||
|
||||
static ConVar tf2_feetyawrunscale( "tf2_feetyawrunscale", "2", FCVAR_REPLICATED, "Multiplier on tf2_feetyawrate to allow turning faster when running." );
|
||||
extern ConVar sv_backspeed;
|
||||
extern ConVar mp_feetyawrate;
|
||||
extern ConVar mp_facefronttime;
|
||||
extern ConVar mp_ik;
|
||||
|
||||
CPlayerAnimState::CPlayerAnimState( CFF_SH_Player *outer )
|
||||
: m_pOuter( outer )
|
||||
{
|
||||
m_flGaitYaw = 0.0f;
|
||||
m_flGoalFeetYaw = 0.0f;
|
||||
m_flCurrentFeetYaw = 0.0f;
|
||||
m_flCurrentTorsoYaw = 0.0f;
|
||||
m_flLastYaw = 0.0f;
|
||||
m_flLastTurnTime = 0.0f;
|
||||
m_flTurnCorrectionTime = 0.0f;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::Update()
|
||||
{
|
||||
m_angRender = GetOuter()->GetLocalAngles();
|
||||
m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
|
||||
|
||||
ComputePoseParam_BodyYaw();
|
||||
ComputePoseParam_BodyPitch(GetOuter()->GetModelPtr());
|
||||
ComputePoseParam_BodyLookYaw();
|
||||
|
||||
ComputePlaybackRate();
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
GetOuter()->UpdateLookAt();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::ComputePlaybackRate()
|
||||
{
|
||||
// Determine ideal playback rate
|
||||
Vector vel;
|
||||
GetOuterAbsVelocity( vel );
|
||||
|
||||
float speed = vel.Length2D();
|
||||
|
||||
bool isMoving = ( speed > 0.5f ) ? true : false;
|
||||
|
||||
float maxspeed = GetOuter()->GetSequenceGroundSpeed( GetOuter()->GetSequence() );
|
||||
|
||||
if ( isMoving && ( maxspeed > 0.0f ) )
|
||||
{
|
||||
float flFactor = 1.0f;
|
||||
|
||||
// Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
|
||||
GetOuter()->SetPlaybackRate( ( speed * flFactor ) / maxspeed );
|
||||
|
||||
// BUG BUG:
|
||||
// This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed
|
||||
}
|
||||
else
|
||||
{
|
||||
GetOuter()->SetPlaybackRate( 1.0f );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : CBasePlayer
|
||||
//-----------------------------------------------------------------------------
|
||||
CFF_SH_Player *CPlayerAnimState::GetOuter()
|
||||
{
|
||||
return m_pOuter;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : dt -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::EstimateYaw( void )
|
||||
{
|
||||
float dt = gpGlobals->frametime;
|
||||
|
||||
if ( !dt )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector est_velocity;
|
||||
QAngle angles;
|
||||
|
||||
GetOuterAbsVelocity( est_velocity );
|
||||
|
||||
angles = GetOuter()->GetLocalAngles();
|
||||
|
||||
if ( est_velocity[1] == 0 && est_velocity[0] == 0 )
|
||||
{
|
||||
float flYawDiff = angles[YAW] - m_flGaitYaw;
|
||||
flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
|
||||
if (flYawDiff > 180)
|
||||
flYawDiff -= 360;
|
||||
if (flYawDiff < -180)
|
||||
flYawDiff += 360;
|
||||
|
||||
if (dt < 0.25)
|
||||
flYawDiff *= dt * 4;
|
||||
else
|
||||
flYawDiff *= dt;
|
||||
|
||||
m_flGaitYaw += flYawDiff;
|
||||
m_flGaitYaw = m_flGaitYaw - (int)(m_flGaitYaw / 360) * 360;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flGaitYaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
|
||||
|
||||
if (m_flGaitYaw > 180)
|
||||
m_flGaitYaw = 180;
|
||||
else if (m_flGaitYaw < -180)
|
||||
m_flGaitYaw = -180;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Override for backpeddling
|
||||
// Input : dt -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::ComputePoseParam_BodyYaw( void )
|
||||
{
|
||||
int iYaw = GetOuter()->LookupPoseParameter( "move_yaw" );
|
||||
if ( iYaw < 0 )
|
||||
return;
|
||||
|
||||
// view direction relative to movement
|
||||
float flYaw;
|
||||
|
||||
EstimateYaw();
|
||||
|
||||
QAngle angles = GetOuter()->GetLocalAngles();
|
||||
float ang = angles[ YAW ];
|
||||
if ( ang > 180.0f )
|
||||
{
|
||||
ang -= 360.0f;
|
||||
}
|
||||
else if ( ang < -180.0f )
|
||||
{
|
||||
ang += 360.0f;
|
||||
}
|
||||
|
||||
// calc side to side turning
|
||||
flYaw = ang - m_flGaitYaw;
|
||||
// Invert for mapping into 8way blend
|
||||
flYaw = -flYaw;
|
||||
flYaw = flYaw - (int)(flYaw / 360) * 360;
|
||||
|
||||
if (flYaw < -180)
|
||||
{
|
||||
flYaw = flYaw + 360;
|
||||
}
|
||||
else if (flYaw > 180)
|
||||
{
|
||||
flYaw = flYaw - 360;
|
||||
}
|
||||
|
||||
GetOuter()->SetPoseParameter( iYaw, flYaw );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
//Adrian: Make the model's angle match the legs so the hitboxes match on both sides.
|
||||
GetOuter()->SetLocalAngles( QAngle( GetOuter()->GetAnimEyeAngles().x, m_flCurrentFeetYaw, 0 ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
|
||||
{
|
||||
// Get pitch from v_angle
|
||||
float flPitch = GetOuter()->GetLocalAngles()[ PITCH ];
|
||||
|
||||
if ( flPitch > 180.0f )
|
||||
{
|
||||
flPitch -= 360.0f;
|
||||
}
|
||||
flPitch = clamp( flPitch, -90, 90 );
|
||||
|
||||
QAngle absangles = GetOuter()->GetAbsAngles();
|
||||
absangles.x = 0.0f;
|
||||
m_angRender = absangles;
|
||||
m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
|
||||
|
||||
// See if we have a blender for pitch
|
||||
GetOuter()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : goal -
|
||||
// maxrate -
|
||||
// dt -
|
||||
// current -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current )
|
||||
{
|
||||
int direction = TURN_NONE;
|
||||
|
||||
float anglediff = goal - current;
|
||||
float anglediffabs = fabs( anglediff );
|
||||
|
||||
anglediff = AngleNormalize( anglediff );
|
||||
|
||||
float scale = 1.0f;
|
||||
if ( anglediffabs <= FADE_TURN_DEGREES )
|
||||
{
|
||||
scale = anglediffabs / FADE_TURN_DEGREES;
|
||||
// Always do at least a bit of the turn ( 1% )
|
||||
scale = clamp( scale, 0.01f, 1.0f );
|
||||
}
|
||||
|
||||
float maxmove = maxrate * dt * scale;
|
||||
|
||||
if ( fabs( anglediff ) < maxmove )
|
||||
{
|
||||
current = goal;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( anglediff > 0 )
|
||||
{
|
||||
current += maxmove;
|
||||
direction = TURN_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
current -= maxmove;
|
||||
direction = TURN_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
current = AngleNormalize( current );
|
||||
|
||||
return direction;
|
||||
}
|
||||
|
||||
void CPlayerAnimState::ComputePoseParam_BodyLookYaw( void )
|
||||
{
|
||||
QAngle absangles = GetOuter()->GetAbsAngles();
|
||||
absangles.y = AngleNormalize( absangles.y );
|
||||
m_angRender = absangles;
|
||||
m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
|
||||
|
||||
// See if we even have a blender for pitch
|
||||
int upper_body_yaw = GetOuter()->LookupPoseParameter( "aim_yaw" );
|
||||
if ( upper_body_yaw < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Assume upper and lower bodies are aligned and that we're not turning
|
||||
float flGoalTorsoYaw = 0.0f;
|
||||
int turning = TURN_NONE;
|
||||
float turnrate = 360.0f;
|
||||
|
||||
Vector vel;
|
||||
|
||||
GetOuterAbsVelocity( vel );
|
||||
|
||||
bool isMoving = ( vel.Length() > 1.0f ) ? true : false;
|
||||
|
||||
if ( !isMoving )
|
||||
{
|
||||
// Just stopped moving, try and clamp feet
|
||||
if ( m_flLastTurnTime <= 0.0f )
|
||||
{
|
||||
m_flLastTurnTime = gpGlobals->curtime;
|
||||
m_flLastYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
// Snap feet to be perfectly aligned with torso/eyes
|
||||
m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
m_flCurrentFeetYaw = m_flGoalFeetYaw;
|
||||
m_nTurningInPlace = TURN_NONE;
|
||||
}
|
||||
|
||||
// If rotating in place, update stasis timer
|
||||
if ( m_flLastYaw != GetOuter()->GetAnimEyeAngles().y )
|
||||
{
|
||||
m_flLastTurnTime = gpGlobals->curtime;
|
||||
m_flLastYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
}
|
||||
|
||||
if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
|
||||
{
|
||||
m_flLastTurnTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
|
||||
|
||||
QAngle eyeAngles = GetOuter()->GetAnimEyeAngles();
|
||||
QAngle vAngle = GetOuter()->GetLocalAngles();
|
||||
|
||||
// See how far off current feetyaw is from true yaw
|
||||
float yawdelta = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;
|
||||
yawdelta = AngleNormalize( yawdelta );
|
||||
|
||||
bool rotated_too_far = false;
|
||||
|
||||
float yawmagnitude = fabs( yawdelta );
|
||||
|
||||
// If too far, then need to turn in place
|
||||
if ( yawmagnitude > 45 )
|
||||
{
|
||||
rotated_too_far = true;
|
||||
}
|
||||
|
||||
// Standing still for a while, rotate feet around to face forward
|
||||
// Or rotated too far
|
||||
// FIXME: Play an in place turning animation
|
||||
if ( rotated_too_far ||
|
||||
( gpGlobals->curtime > m_flLastTurnTime + mp_facefronttime.GetFloat() ) )
|
||||
{
|
||||
m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
m_flLastTurnTime = gpGlobals->curtime;
|
||||
|
||||
/* float yd = m_flCurrentFeetYaw - m_flGoalFeetYaw;
|
||||
if ( yd > 0 )
|
||||
{
|
||||
m_nTurningInPlace = TURN_RIGHT;
|
||||
}
|
||||
else if ( yd < 0 )
|
||||
{
|
||||
m_nTurningInPlace = TURN_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nTurningInPlace = TURN_NONE;
|
||||
}
|
||||
|
||||
turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
|
||||
yawdelta = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;*/
|
||||
|
||||
}
|
||||
|
||||
// Snap upper body into position since the delta is already smoothed for the feet
|
||||
flGoalTorsoYaw = yawdelta;
|
||||
m_flCurrentTorsoYaw = flGoalTorsoYaw;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flLastTurnTime = 0.0f;
|
||||
m_nTurningInPlace = TURN_NONE;
|
||||
m_flCurrentFeetYaw = m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
flGoalTorsoYaw = 0.0f;
|
||||
m_flCurrentTorsoYaw = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;
|
||||
}
|
||||
|
||||
|
||||
if ( turning == TURN_NONE )
|
||||
{
|
||||
m_nTurningInPlace = turning;
|
||||
}
|
||||
|
||||
if ( m_nTurningInPlace != TURN_NONE )
|
||||
{
|
||||
// If we're close to finishing the turn, then turn off the turning animation
|
||||
if ( fabs( m_flCurrentFeetYaw - m_flGoalFeetYaw ) < MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION )
|
||||
{
|
||||
m_nTurningInPlace = TURN_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Rotate entire body into position
|
||||
absangles = GetOuter()->GetAbsAngles();
|
||||
absangles.y = m_flCurrentFeetYaw;
|
||||
m_angRender = absangles;
|
||||
m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
|
||||
|
||||
GetOuter()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) );
|
||||
|
||||
/*
|
||||
// FIXME: Adrian, what is this?
|
||||
int body_yaw = GetOuter()->LookupPoseParameter( "body_yaw" );
|
||||
|
||||
if ( body_yaw >= 0 )
|
||||
{
|
||||
GetOuter()->SetPoseParameter( body_yaw, 30 );
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : activity -
|
||||
// Output : Activity
|
||||
//-----------------------------------------------------------------------------
|
||||
Activity CPlayerAnimState::BodyYawTranslateActivity( Activity activity )
|
||||
{
|
||||
// Not even standing still, sigh
|
||||
if ( activity != ACT_IDLE )
|
||||
return activity;
|
||||
|
||||
// Not turning
|
||||
switch ( m_nTurningInPlace )
|
||||
{
|
||||
default:
|
||||
case TURN_NONE:
|
||||
return activity;
|
||||
/*
|
||||
case TURN_RIGHT:
|
||||
return ACT_TURNRIGHT45;
|
||||
case TURN_LEFT:
|
||||
return ACT_TURNLEFT45;
|
||||
*/
|
||||
case TURN_RIGHT:
|
||||
case TURN_LEFT:
|
||||
return mp_ik.GetBool() ? ACT_TURN : activity;
|
||||
}
|
||||
|
||||
Assert( 0 );
|
||||
return activity;
|
||||
}
|
||||
|
||||
const QAngle& CPlayerAnimState::GetRenderAngles()
|
||||
{
|
||||
return m_angRender;
|
||||
}
|
||||
|
||||
|
||||
void CPlayerAnimState::GetOuterAbsVelocity( Vector& vel )
|
||||
{
|
||||
#if defined( CLIENT_DLL )
|
||||
GetOuter()->EstimateAbsVelocity( vel );
|
||||
#else
|
||||
vel = GetOuter()->GetAbsVelocity();
|
||||
#endif
|
||||
}
|
99
mp/src/game/shared/ff/ff_sh_player.h
Normal file
99
mp/src/game/shared/ff/ff_sh_player.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#ifndef FF_SH_PLAYER_H
|
||||
#define FF_SH_PLAYER_H
|
||||
#pragma once
|
||||
|
||||
#define FF_PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f)
|
||||
#include "studio.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PLAYER_SOUNDS_CITIZEN = 0,
|
||||
PLAYER_SOUNDS_COMBINESOLDIER,
|
||||
PLAYER_SOUNDS_METROPOLICE,
|
||||
PLAYER_SOUNDS_MAX,
|
||||
};
|
||||
|
||||
enum FFPlayerState
|
||||
{
|
||||
// Happily running around in the game.
|
||||
STATE_ACTIVE=0,
|
||||
STATE_OBSERVER_MODE, // Noclipping around, watching players, etc.
|
||||
NUM_PLAYER_STATES
|
||||
};
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CFF_SH_Player CFF_CL_Player
|
||||
#else
|
||||
#define CFF_SH_Player CFF_SV_Player
|
||||
#endif
|
||||
|
||||
class CPlayerAnimState
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
TURN_NONE = 0,
|
||||
TURN_LEFT,
|
||||
TURN_RIGHT
|
||||
};
|
||||
|
||||
CPlayerAnimState( CFF_SH_Player *outer );
|
||||
|
||||
Activity BodyYawTranslateActivity( Activity activity );
|
||||
|
||||
void Update();
|
||||
|
||||
const QAngle& GetRenderAngles();
|
||||
|
||||
void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] );
|
||||
|
||||
CFF_SH_Player *GetOuter();
|
||||
|
||||
private:
|
||||
void GetOuterAbsVelocity( Vector& vel );
|
||||
|
||||
int ConvergeAngles( float goal,float maxrate, float dt, float& current );
|
||||
|
||||
void EstimateYaw( void );
|
||||
void ComputePoseParam_BodyYaw( void );
|
||||
void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr );
|
||||
void ComputePoseParam_BodyLookYaw( void );
|
||||
|
||||
void ComputePlaybackRate();
|
||||
|
||||
CFF_SH_Player *m_pOuter;
|
||||
|
||||
float m_flGaitYaw;
|
||||
float m_flStoredCycle;
|
||||
|
||||
// The following variables are used for tweaking the yaw of the upper body when standing still and
|
||||
// making sure that it smoothly blends in and out once the player starts moving
|
||||
// Direction feet were facing when we stopped moving
|
||||
float m_flGoalFeetYaw;
|
||||
float m_flCurrentFeetYaw;
|
||||
|
||||
float m_flCurrentTorsoYaw;
|
||||
|
||||
// To check if they are rotating in place
|
||||
float m_flLastYaw;
|
||||
// Time when we stopped moving
|
||||
float m_flLastTurnTime;
|
||||
|
||||
// One of the above enums
|
||||
int m_nTurningInPlace;
|
||||
|
||||
QAngle m_angRender;
|
||||
|
||||
float m_flTurnCorrectionTime;
|
||||
};
|
||||
|
||||
#endif //FF_SH_PLAYER_H
|
|
@ -17,9 +17,16 @@ $Project
|
|||
$File "$SRCDIR\game\shared\ff\ff_sh_gamemovement.cpp"
|
||||
$File "$SRCDIR\game\shared\ff\ff_sh_gamemovement.h"
|
||||
}
|
||||
|
||||
$File "$SRCDIR\game\shared\ff\ff_sh_gamerules.cpp"
|
||||
$File "$SRCDIR\game\shared\ff\ff_sh_gamerules.h"
|
||||
$Folder "Player"
|
||||
{
|
||||
$File "$SRCDIR\game\shared\ff\ff_sh_player.cpp"
|
||||
$File "$SRCDIR\game\shared\ff\ff_sh_player.h"
|
||||
}
|
||||
$Folder "Game"
|
||||
{
|
||||
$File "$SRCDIR\game\shared\ff\ff_sh_gamerules.cpp"
|
||||
$File "$SRCDIR\game\shared\ff\ff_sh_gamerules.h"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#include "npcevent.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "c_te_effect_dispatch.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "prop_combine_ball.h"
|
||||
#endif
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "c_te_effect_dispatch.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "IEffects.h"
|
||||
#include "Sprite.h"
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
#include "npcevent.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "ai_basenpc.h"
|
||||
#endif
|
||||
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "c_te_effect_dispatch.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "grenade_frag.h"
|
||||
#endif
|
||||
|
@ -405,7 +405,7 @@ void CWeaponFrag::CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye
|
|||
}
|
||||
}
|
||||
|
||||
void DropPrimedFragGrenade( CHL2MP_Player *pPlayer, CBaseCombatWeapon *pGrenade )
|
||||
void DropPrimedFragGrenade( CFF_SH_Player *pPlayer, CBaseCombatWeapon *pGrenade )
|
||||
{
|
||||
CWeaponFrag *pWeaponFrag = dynamic_cast<CWeaponFrag*>( pGrenade );
|
||||
|
||||
|
|
|
@ -23,12 +23,12 @@ extern IVModelInfo* modelinfo;
|
|||
|
||||
#include "vgui/ISurface.h"
|
||||
#include "vgui_controls/Controls.h"
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "hud_crosshair.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "vphysics/constraints.h"
|
||||
|
||||
#endif
|
||||
|
@ -131,9 +131,9 @@ CBasePlayer* CWeaponHL2MPBase::GetPlayerOwner() const
|
|||
return dynamic_cast< CBasePlayer* >( GetOwner() );
|
||||
}
|
||||
|
||||
CHL2MP_Player* CWeaponHL2MPBase::GetHL2MPPlayerOwner() const
|
||||
CFF_SH_Player* CWeaponHL2MPBase::GetFFPlayerOwner() const
|
||||
{
|
||||
return dynamic_cast< CHL2MP_Player* >( GetOwner() );
|
||||
return dynamic_cast< CFF_SH_Player* >( GetOwner() );
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "hl2mp_player_shared.h"
|
||||
#include "ff_sh_player.h"
|
||||
#include "basecombatweapon_shared.h"
|
||||
#include "hl2mp_weapon_parse.h"
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip );
|
||||
#endif
|
||||
|
||||
class CHL2MP_Player;
|
||||
class CFF_SH_Player;
|
||||
|
||||
// These are the names of the ammo types that go in the CAmmoDefs and that the
|
||||
// weapon script files reference.
|
||||
|
@ -51,7 +51,7 @@ public:
|
|||
virtual bool IsPredicted() const;
|
||||
|
||||
CBasePlayer* GetPlayerOwner() const;
|
||||
CHL2MP_Player* GetHL2MPPlayerOwner() const;
|
||||
CFF_SH_Player* GetFFPlayerOwner() const;
|
||||
|
||||
void WeaponSound( WeaponSound_t sound_type, float soundtime = 0.0f );
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
#include "cbase.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbase_machinegun.h"
|
||||
|
@ -91,14 +91,14 @@ void CHL2MPMachineGun::PrimaryAttack( void )
|
|||
m_iClip1 -= iBulletsToFire;
|
||||
}
|
||||
|
||||
CHL2MP_Player *pHL2MPPlayer = ToHL2MPPlayer( pPlayer );
|
||||
CFF_SH_Player *pFFPlayer = ToFFPlayer( pPlayer );
|
||||
|
||||
// Fire the bullets
|
||||
FireBulletsInfo_t info;
|
||||
info.m_iShots = iBulletsToFire;
|
||||
info.m_vecSrc = pHL2MPPlayer->Weapon_ShootPosition( );
|
||||
info.m_vecSrc = pFFPlayer->Weapon_ShootPosition( );
|
||||
info.m_vecDirShooting = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
|
||||
info.m_vecSpread = pHL2MPPlayer->GetAttackSpread( this );
|
||||
info.m_vecSpread = pFFPlayer->GetAttackSpread( this );
|
||||
info.m_flDistance = MAX_TRACE_LENGTH;
|
||||
info.m_iAmmoType = m_iPrimaryAmmoType;
|
||||
info.m_iTracerFreq = 2;
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
#include "animation.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "ndebugoverlay.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "ilagcompensationmanager.h"
|
||||
|
@ -103,7 +103,7 @@ void CBaseHL2MPBludgeonWeapon::PrimaryAttack()
|
|||
{
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
CHL2MP_Player *pPlayer = ToHL2MPPlayer( GetPlayerOwner() );
|
||||
CFF_SH_Player *pPlayer = ToFFPlayer( GetPlayerOwner() );
|
||||
// Move other players back to history positions based on local player's lag
|
||||
lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "cbase.h"
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
||||
#include "hl2mp_player_shared.h"
|
||||
#include "ff_sh_player.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
@ -115,7 +115,7 @@ bool CBaseHL2MPCombatWeapon::Deploy( void )
|
|||
// We have to ask the player if the last time it checked, the weapon was lowered
|
||||
if ( GetOwner() && GetOwner()->IsPlayer() )
|
||||
{
|
||||
CHL2MP_Player *pPlayer = assert_cast<CHL2MP_Player*>( GetOwner() );
|
||||
CFF_SH_Player *pPlayer = assert_cast<CFF_SH_Player*>( GetOwner() );
|
||||
if ( pPlayer->IsWeaponLowered() )
|
||||
{
|
||||
if ( SelectWeightedSequence( ACT_VM_IDLE_LOWERED ) != ACTIVITY_NOT_AVAILABLE )
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbase.h"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "cbase.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "vcollide_parse.h"
|
||||
#include "engine/ivdebugoverlay.h"
|
||||
#include "iviewrender_beams.h"
|
||||
|
@ -17,7 +17,7 @@
|
|||
#include "clienteffectprecachesystem.h"
|
||||
#include "fx_interpvalue.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "soundent.h"
|
||||
#include "ndebugoverlay.h"
|
||||
#include "ai_basenpc.h"
|
||||
|
@ -760,7 +760,7 @@ void CPlayerPickupController::Init( CBasePlayer *pPlayer, CBaseEntity *pObject )
|
|||
}
|
||||
|
||||
|
||||
CHL2MP_Player *pOwner = (CHL2MP_Player *)ToBasePlayer( pPlayer );
|
||||
CFF_SH_Player *pOwner = (CFF_SH_Player *)ToBasePlayer( pPlayer );
|
||||
if ( pOwner )
|
||||
{
|
||||
pOwner->EnableSprint( false );
|
||||
|
@ -813,7 +813,7 @@ void CPlayerPickupController::Shutdown( bool bThrown )
|
|||
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
CHL2MP_Player *pOwner = (CHL2MP_Player *)ToBasePlayer( m_pPlayer );
|
||||
CFF_SH_Player *pOwner = (CFF_SH_Player *)ToBasePlayer( m_pPlayer );
|
||||
if ( pOwner )
|
||||
{
|
||||
pOwner->EnableSprint( true );
|
||||
|
@ -2015,7 +2015,7 @@ bool CWeaponPhysCannon::AttachObject( CBaseEntity *pObject, const Vector &vPosit
|
|||
if ( !pPhysics )
|
||||
return false;
|
||||
|
||||
CHL2MP_Player *pOwner = (CHL2MP_Player *)ToBasePlayer( GetOwner() );
|
||||
CFF_SH_Player *pOwner = (CFF_SH_Player *)ToBasePlayer( GetOwner() );
|
||||
|
||||
m_bActive = true;
|
||||
if( pOwner )
|
||||
|
@ -2375,7 +2375,7 @@ void CWeaponPhysCannon::DetachObject( bool playSound, bool wasLaunched )
|
|||
if ( m_bActive == false )
|
||||
return;
|
||||
|
||||
CHL2MP_Player *pOwner = (CHL2MP_Player *)ToBasePlayer( GetOwner() );
|
||||
CFF_SH_Player *pOwner = (CFF_SH_Player *)ToBasePlayer( GetOwner() );
|
||||
if( pOwner != NULL )
|
||||
{
|
||||
pOwner->EnableSprint( true );
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "weapon_rpg.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#include "model_types.h"
|
||||
#include "beamdraw.h"
|
||||
#include "fx_line.h"
|
||||
|
@ -2226,7 +2226,7 @@ int CLaserDot::DrawModel( int flags )
|
|||
float scale;
|
||||
Vector endPos;
|
||||
|
||||
C_HL2MP_Player *pOwner = ToHL2MPPlayer( GetOwnerEntity() );
|
||||
CFF_CL_Player *pOwner = ToFFPlayer( GetOwnerEntity() );
|
||||
|
||||
if ( pOwner != NULL && pOwner->IsDormant() == false )
|
||||
{
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
#include "engine/IEngineSound.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "grenade_tripmine.h"
|
||||
#include "grenade_satchel.h"
|
||||
#include "entitylist.h"
|
||||
|
@ -339,7 +339,7 @@ void CWeapon_SLAM::StartSatchelDetonate()
|
|||
//-----------------------------------------------------------------------------
|
||||
void CWeapon_SLAM::TripmineAttach( void )
|
||||
{
|
||||
CHL2MP_Player *pOwner = ToHL2MPPlayer( GetOwner() );
|
||||
CFF_SH_Player *pOwner = ToFFPlayer( GetOwner() );
|
||||
if (!pOwner)
|
||||
{
|
||||
return;
|
||||
|
@ -698,7 +698,7 @@ void CWeapon_SLAM::SLAMThink( void )
|
|||
//-----------------------------------------------------------------------------
|
||||
bool CWeapon_SLAM::CanAttachSLAM( void )
|
||||
{
|
||||
CHL2MP_Player *pOwner = ToHL2MPPlayer( GetOwner() );
|
||||
CFF_SH_Player *pOwner = ToFFPlayer( GetOwner() );
|
||||
|
||||
if (!pOwner)
|
||||
{
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "ff_cl_player.h"
|
||||
#else
|
||||
#include "grenade_ar2.h"
|
||||
#include "hl2mp_player.h"
|
||||
#include "ff_sv_player.h"
|
||||
#include "basegrenade_shared.h"
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue