2013-06-26 15:22:04 -07:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Player for HL2.
//
//=============================================================================//
# include "cbase.h"
# include "hl2_player.h"
# include "globalstate.h"
# include "game.h"
# include "gamerules.h"
# include "trains.h"
# include "basehlcombatweapon_shared.h"
# include "vcollide_parse.h"
# include "in_buttons.h"
# include "ai_interactions.h"
# include "ai_squad.h"
# include "igamemovement.h"
# include "ai_hull.h"
# include "hl2_shareddefs.h"
# include "info_camera_link.h"
# include "point_camera.h"
# include "engine/IEngineSound.h"
# include "ndebugoverlay.h"
# include "iservervehicle.h"
# include "IVehicle.h"
# include "globals.h"
# include "collisionutils.h"
# include "coordsize.h"
# include "effect_color_tables.h"
# include "vphysics/player_controller.h"
# include "player_pickup.h"
# include "weapon_physcannon.h"
# include "script_intro.h"
# include "effect_dispatch_data.h"
# include "te_effect_dispatch.h"
# include "ai_basenpc.h"
# include "AI_Criteria.h"
# include "npc_barnacle.h"
# include "entitylist.h"
# include "env_zoom.h"
# include "hl2_gamerules.h"
# include "prop_combine_ball.h"
# include "datacache/imdlcache.h"
# include "eventqueue.h"
# include "gamestats.h"
# include "filters.h"
# include "tier0/icommandline.h"
# ifdef HL2_EPISODIC
# include "npc_alyx_episodic.h"
# endif
# ifdef PORTAL
# include "portal_player.h"
# endif // PORTAL
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
extern ConVar weapon_showproficiency ;
extern ConVar autoaim_max_dist ;
// Do not touch with without seeing me, please! (sjb)
// For consistency's sake, enemy gunfire is traced against a scaled down
// version of the player's hull, not the hitboxes for the player's model
// because the player isn't aware of his model, and can't do anything about
// preventing headshots and other such things. Also, game difficulty will
// not change if the model changes. This is the value by which to scale
// the X/Y of the player's hull to get the volume to trace bullets against.
# define PLAYER_HULL_REDUCTION 0.70
// This switches between the single primary weapon, and multiple weapons with buckets approach (jdw)
# define HL2_SINGLE_PRIMARY_WEAPON_MODE 0
# define TIME_IGNORE_FALL_DAMAGE 10.0
extern int gEvilImpulse101 ;
ConVar sv_autojump ( " sv_autojump " , " 0 " ) ;
ConVar hl2_walkspeed ( " hl2_walkspeed " , " 150 " ) ;
ConVar hl2_normspeed ( " hl2_normspeed " , " 190 " ) ;
ConVar hl2_sprintspeed ( " hl2_sprintspeed " , " 320 " ) ;
ConVar hl2_darkness_flashlight_factor ( " hl2_darkness_flashlight_factor " , " 1 " ) ;
# ifdef HL2MP
# define HL2_WALK_SPEED 150
# define HL2_NORM_SPEED 190
# define HL2_SPRINT_SPEED 320
# else
# define HL2_WALK_SPEED hl2_walkspeed.GetFloat()
# define HL2_NORM_SPEED hl2_normspeed.GetFloat()
# define HL2_SPRINT_SPEED hl2_sprintspeed.GetFloat()
# endif
ConVar player_showpredictedposition ( " player_showpredictedposition " , " 0 " ) ;
ConVar player_showpredictedposition_timestep ( " player_showpredictedposition_timestep " , " 1.0 " ) ;
ConVar player_squad_transient_commands ( " player_squad_transient_commands " , " 1 " , FCVAR_REPLICATED ) ;
ConVar player_squad_double_tap_time ( " player_squad_double_tap_time " , " 0.25 " ) ;
ConVar sv_infinite_aux_power ( " sv_infinite_aux_power " , " 0 " , FCVAR_CHEAT ) ;
ConVar autoaim_unlock_target ( " autoaim_unlock_target " , " 0.8666 " ) ;
ConVar sv_stickysprint ( " sv_stickysprint " , " 0 " , FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX ) ;
# define FLASH_DRAIN_TIME 1.1111 // 100 units / 90 secs
# define FLASH_CHARGE_TIME 50.0f // 100 units / 2 secs
//==============================================================================================
// CAPPED PLAYER PHYSICS DAMAGE TABLE
//==============================================================================================
static impactentry_t cappedPlayerLinearTable [ ] =
{
{ 150 * 150 , 5 } ,
{ 250 * 250 , 10 } ,
{ 450 * 450 , 20 } ,
{ 550 * 550 , 30 } ,
//{ 700*700, 100 },
//{ 1000*1000, 500 },
} ;
static impactentry_t cappedPlayerAngularTable [ ] =
{
{ 100 * 100 , 10 } ,
{ 150 * 150 , 20 } ,
{ 200 * 200 , 30 } ,
//{ 300*300, 500 },
} ;
static impactdamagetable_t gCappedPlayerImpactDamageTable =
{
cappedPlayerLinearTable ,
cappedPlayerAngularTable ,
ARRAYSIZE ( cappedPlayerLinearTable ) ,
ARRAYSIZE ( cappedPlayerAngularTable ) ,
24 * 24.0f , // minimum linear speed
360 * 360.0f , // minimum angular speed
2.0f , // can't take damage from anything under 2kg
5.0f , // anything less than 5kg is "small"
5.0f , // never take more than 5 pts of damage from anything under 5kg
36 * 36.0f , // <5kg objects must go faster than 36 in/s to do damage
0.0f , // large mass in kg (no large mass effects)
1.0f , // large mass scale
2.0f , // large mass falling scale
320.0f , // min velocity for player speed to cause damage
} ;
// Flashlight utility
bool g_bCacheLegacyFlashlightStatus = true ;
bool g_bUseLegacyFlashlight ;
bool Flashlight_UseLegacyVersion ( void )
{
// If this is the first run through, cache off what the answer should be (cannot change during a session)
if ( g_bCacheLegacyFlashlightStatus )
{
char modDir [ MAX_PATH ] ;
if ( UTIL_GetModDir ( modDir , sizeof ( modDir ) ) = = false )
return false ;
g_bUseLegacyFlashlight = ( ! Q_strcmp ( modDir , " hl2 " ) | |
! Q_strcmp ( modDir , " episodic " ) | |
2014-02-28 14:08:09 -05:00
! Q_strcmp ( modDir , " lostcoast " ) | | ! Q_strcmp ( modDir , " hl1 " ) ) ;
2013-06-26 15:22:04 -07:00
g_bCacheLegacyFlashlightStatus = false ;
}
// Return the results
return g_bUseLegacyFlashlight ;
}
//-----------------------------------------------------------------------------
// Purpose: Used to relay outputs/inputs from the player to the world and viceversa
//-----------------------------------------------------------------------------
class CLogicPlayerProxy : public CLogicalEntity
{
DECLARE_CLASS ( CLogicPlayerProxy , CLogicalEntity ) ;
private :
DECLARE_DATADESC ( ) ;
public :
COutputEvent m_OnFlashlightOn ;
COutputEvent m_OnFlashlightOff ;
COutputEvent m_PlayerHasAmmo ;
COutputEvent m_PlayerHasNoAmmo ;
COutputEvent m_PlayerDied ;
COutputEvent m_PlayerMissedAR2AltFire ; // Player fired a combine ball which did not dissolve any enemies.
COutputInt m_RequestedPlayerHealth ;
void InputRequestPlayerHealth ( inputdata_t & inputdata ) ;
void InputSetFlashlightSlowDrain ( inputdata_t & inputdata ) ;
void InputSetFlashlightNormalDrain ( inputdata_t & inputdata ) ;
void InputSetPlayerHealth ( inputdata_t & inputdata ) ;
void InputRequestAmmoState ( inputdata_t & inputdata ) ;
void InputLowerWeapon ( inputdata_t & inputdata ) ;
void InputEnableCappedPhysicsDamage ( inputdata_t & inputdata ) ;
void InputDisableCappedPhysicsDamage ( inputdata_t & inputdata ) ;
void InputSetLocatorTargetEntity ( inputdata_t & inputdata ) ;
# ifdef PORTAL
void InputSuppressCrosshair ( inputdata_t & inputdata ) ;
# endif // PORTAL2
void Activate ( void ) ;
bool PassesDamageFilter ( const CTakeDamageInfo & info ) ;
EHANDLE m_hPlayer ;
} ;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void CC_ToggleZoom ( void )
{
CBasePlayer * pPlayer = UTIL_GetCommandClient ( ) ;
if ( pPlayer )
{
CHL2_Player * pHL2Player = dynamic_cast < CHL2_Player * > ( pPlayer ) ;
if ( pHL2Player & & pHL2Player - > IsSuitEquipped ( ) )
{
pHL2Player - > ToggleZoom ( ) ;
}
}
}
static ConCommand toggle_zoom ( " toggle_zoom " , CC_ToggleZoom , " Toggles zoom display " ) ;
// ConVar cl_forwardspeed( "cl_forwardspeed", "400", FCVAR_CHEAT ); // Links us to the client's version
ConVar xc_crouch_range ( " xc_crouch_range " , " 0.85 " , FCVAR_ARCHIVE , " Percentarge [1..0] of joystick range to allow ducking within " ) ; // Only 1/2 of the range is used
ConVar xc_use_crouch_limiter ( " xc_use_crouch_limiter " , " 0 " , FCVAR_ARCHIVE , " Use the crouch limiting logic on the controller " ) ;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void CC_ToggleDuck ( void )
{
CBasePlayer * pPlayer = UTIL_GetCommandClient ( ) ;
if ( pPlayer = = NULL )
return ;
// Cannot be frozen
if ( pPlayer - > GetFlags ( ) & FL_FROZEN )
return ;
static bool bChecked = false ;
static ConVar * pCVcl_forwardspeed = NULL ;
if ( ! bChecked )
{
bChecked = true ;
pCVcl_forwardspeed = ( ConVar * ) cvar - > FindVar ( " cl_forwardspeed " ) ;
}
// If we're not ducked, do extra checking
if ( xc_use_crouch_limiter . GetBool ( ) )
{
if ( pPlayer - > GetToggledDuckState ( ) = = false )
{
float flForwardSpeed = 400.0f ;
if ( pCVcl_forwardspeed )
{
flForwardSpeed = pCVcl_forwardspeed - > GetFloat ( ) ;
}
flForwardSpeed = MAX ( 1.0f , flForwardSpeed ) ;
// Make sure we're not in the blindspot on the crouch detection
float flStickDistPerc = ( pPlayer - > GetStickDist ( ) / flForwardSpeed ) ; // Speed is the magnitude
if ( flStickDistPerc > xc_crouch_range . GetFloat ( ) )
return ;
}
}
// Toggle the duck
pPlayer - > ToggleDuck ( ) ;
}
static ConCommand toggle_duck ( " toggle_duck " , CC_ToggleDuck , " Toggles duck " ) ;
# ifndef HL2MP
# ifndef PORTAL
LINK_ENTITY_TO_CLASS ( player , CHL2_Player ) ;
# endif
# endif
PRECACHE_REGISTER ( player ) ;
CBaseEntity * FindEntityForward ( CBasePlayer * pMe , bool fHull ) ;
BEGIN_SIMPLE_DATADESC ( LadderMove_t )
DEFINE_FIELD ( m_bForceLadderMove , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_bForceMount , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_flStartTime , FIELD_TIME ) ,
DEFINE_FIELD ( m_flArrivalTime , FIELD_TIME ) ,
DEFINE_FIELD ( m_vecGoalPosition , FIELD_POSITION_VECTOR ) ,
DEFINE_FIELD ( m_vecStartPosition , FIELD_POSITION_VECTOR ) ,
DEFINE_FIELD ( m_hForceLadder , FIELD_EHANDLE ) ,
DEFINE_FIELD ( m_hReservedSpot , FIELD_EHANDLE ) ,
END_DATADESC ( )
// Global Savedata for HL2 player
BEGIN_DATADESC ( CHL2_Player )
DEFINE_FIELD ( m_nControlClass , FIELD_INTEGER ) ,
DEFINE_EMBEDDED ( m_HL2Local ) ,
DEFINE_FIELD ( m_bSprintEnabled , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_flTimeAllSuitDevicesOff , FIELD_TIME ) ,
DEFINE_FIELD ( m_fIsSprinting , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_fIsWalking , FIELD_BOOLEAN ) ,
/*
// These are initialized every time the player calls Activate()
DEFINE_FIELD ( m_bIsAutoSprinting , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_fAutoSprintMinTime , FIELD_TIME ) ,
*/
// Field is used within a single tick, no need to save restore
// DEFINE_FIELD( m_bPlayUseDenySound, FIELD_BOOLEAN ),
// m_pPlayerAISquad reacquired on load
DEFINE_AUTO_ARRAY ( m_vecMissPositions , FIELD_POSITION_VECTOR ) ,
DEFINE_FIELD ( m_nNumMissPositions , FIELD_INTEGER ) ,
// m_pPlayerAISquad
DEFINE_EMBEDDED ( m_CommanderUpdateTimer ) ,
// m_RealTimeLastSquadCommand
DEFINE_FIELD ( m_QueuedCommand , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_flTimeIgnoreFallDamage , FIELD_TIME ) ,
DEFINE_FIELD ( m_bIgnoreFallDamageResetAfterImpact , FIELD_BOOLEAN ) ,
// Suit power fields
DEFINE_FIELD ( m_flSuitPowerLoad , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flIdleTime , FIELD_TIME ) ,
DEFINE_FIELD ( m_flMoveTime , FIELD_TIME ) ,
DEFINE_FIELD ( m_flLastDamageTime , FIELD_TIME ) ,
DEFINE_FIELD ( m_flTargetFindTime , FIELD_TIME ) ,
DEFINE_FIELD ( m_flAdmireGlovesAnimTime , FIELD_TIME ) ,
DEFINE_FIELD ( m_flNextFlashlightCheckTime , FIELD_TIME ) ,
DEFINE_FIELD ( m_flFlashlightPowerDrainScale , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_bFlashlightDisabled , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_bUseCappedPhysicsDamageTable , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_hLockedAutoAimEntity , FIELD_EHANDLE ) ,
DEFINE_EMBEDDED ( m_LowerWeaponTimer ) ,
DEFINE_EMBEDDED ( m_AutoaimTimer ) ,
DEFINE_INPUTFUNC ( FIELD_FLOAT , " IgnoreFallDamage " , InputIgnoreFallDamage ) ,
DEFINE_INPUTFUNC ( FIELD_FLOAT , " IgnoreFallDamageWithoutReset " , InputIgnoreFallDamageWithoutReset ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " OnSquadMemberKilled " , OnSquadMemberKilled ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " DisableFlashlight " , InputDisableFlashlight ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " EnableFlashlight " , InputEnableFlashlight ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " ForceDropPhysObjects " , InputForceDropPhysObjects ) ,
DEFINE_SOUNDPATCH ( m_sndLeeches ) ,
DEFINE_SOUNDPATCH ( m_sndWaterSplashes ) ,
DEFINE_FIELD ( m_flArmorReductionTime , FIELD_TIME ) ,
DEFINE_FIELD ( m_iArmorReductionFrom , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_flTimeUseSuspended , FIELD_TIME ) ,
DEFINE_FIELD ( m_hLocatorTargetEntity , FIELD_EHANDLE ) ,
DEFINE_FIELD ( m_flTimeNextLadderHint , FIELD_TIME ) ,
//DEFINE_FIELD( m_hPlayerProxy, FIELD_EHANDLE ), //Shut up class check!
END_DATADESC ( )
CHL2_Player : : CHL2_Player ( )
{
m_nNumMissPositions = 0 ;
m_pPlayerAISquad = 0 ;
m_bSprintEnabled = true ;
m_flArmorReductionTime = 0.0f ;
m_iArmorReductionFrom = 0 ;
}
//
// SUIT POWER DEVICES
//
# define SUITPOWER_CHARGE_RATE 12.5 // 100 units in 8 seconds
# ifdef HL2MP
CSuitPowerDevice SuitDeviceSprint ( bits_SUIT_DEVICE_SPRINT , 25.0f ) ; // 100 units in 4 seconds
# else
CSuitPowerDevice SuitDeviceSprint ( bits_SUIT_DEVICE_SPRINT , 12.5f ) ; // 100 units in 8 seconds
# endif
# ifdef HL2_EPISODIC
CSuitPowerDevice SuitDeviceFlashlight ( bits_SUIT_DEVICE_FLASHLIGHT , 1.111 ) ; // 100 units in 90 second
# else
CSuitPowerDevice SuitDeviceFlashlight ( bits_SUIT_DEVICE_FLASHLIGHT , 2.222 ) ; // 100 units in 45 second
# endif
CSuitPowerDevice SuitDeviceBreather ( bits_SUIT_DEVICE_BREATHER , 6.7f ) ; // 100 units in 15 seconds (plus three padded seconds)
IMPLEMENT_SERVERCLASS_ST ( CHL2_Player , DT_HL2_Player )
SendPropDataTable ( SENDINFO_DT ( m_HL2Local ) , & REFERENCE_SEND_TABLE ( DT_HL2Local ) , SendProxy_SendLocalDataTable ) ,
SendPropBool ( SENDINFO ( m_fIsSprinting ) ) ,
END_SEND_TABLE ( )
void CHL2_Player : : Precache ( void )
{
BaseClass : : Precache ( ) ;
PrecacheScriptSound ( " HL2Player.SprintNoPower " ) ;
PrecacheScriptSound ( " HL2Player.SprintStart " ) ;
PrecacheScriptSound ( " HL2Player.UseDeny " ) ;
PrecacheScriptSound ( " HL2Player.FlashLightOn " ) ;
PrecacheScriptSound ( " HL2Player.FlashLightOff " ) ;
PrecacheScriptSound ( " HL2Player.PickupWeapon " ) ;
PrecacheScriptSound ( " HL2Player.TrainUse " ) ;
PrecacheScriptSound ( " HL2Player.Use " ) ;
PrecacheScriptSound ( " HL2Player.BurnPain " ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2_Player : : CheckSuitZoom ( void )
{
//#ifndef _XBOX
//Adrian - No zooming without a suit!
if ( IsSuitEquipped ( ) )
{
if ( m_afButtonReleased & IN_ZOOM )
{
StopZooming ( ) ;
}
else if ( m_afButtonPressed & IN_ZOOM )
{
StartZooming ( ) ;
}
}
//#endif//_XBOX
}
void CHL2_Player : : EquipSuit ( bool bPlayEffects )
{
MDLCACHE_CRITICAL_SECTION ( ) ;
BaseClass : : EquipSuit ( ) ;
m_HL2Local . m_bDisplayReticle = true ;
if ( bPlayEffects = = true )
{
StartAdmireGlovesAnimation ( ) ;
}
}
void CHL2_Player : : RemoveSuit ( void )
{
BaseClass : : RemoveSuit ( ) ;
m_HL2Local . m_bDisplayReticle = false ;
}
void CHL2_Player : : HandleSpeedChanges ( void )
{
int buttonsChanged = m_afButtonPressed | m_afButtonReleased ;
bool bCanSprint = CanSprint ( ) ;
bool bIsSprinting = IsSprinting ( ) ;
bool bWantSprint = ( bCanSprint & & IsSuitEquipped ( ) & & ( m_nButtons & IN_SPEED ) ) ;
if ( bIsSprinting ! = bWantSprint & & ( buttonsChanged & IN_SPEED ) )
{
// If someone wants to sprint, make sure they've pressed the button to do so. We want to prevent the
// case where a player can hold down the sprint key and burn tiny bursts of sprint as the suit recharges
// We want a full debounce of the key to resume sprinting after the suit is completely drained
if ( bWantSprint )
{
if ( sv_stickysprint . GetBool ( ) )
{
StartAutoSprint ( ) ;
}
else
{
StartSprinting ( ) ;
}
}
else
{
if ( ! sv_stickysprint . GetBool ( ) )
{
StopSprinting ( ) ;
}
// Reset key, so it will be activated post whatever is suppressing it.
m_nButtons & = ~ IN_SPEED ;
}
}
bool bIsWalking = IsWalking ( ) ;
// have suit, pressing button, not sprinting or ducking
bool bWantWalking ;
if ( IsSuitEquipped ( ) )
{
bWantWalking = ( m_nButtons & IN_WALK ) & & ! IsSprinting ( ) & & ! ( m_nButtons & IN_DUCK ) ;
}
else
{
bWantWalking = true ;
}
if ( bIsWalking ! = bWantWalking )
{
if ( bWantWalking )
{
StartWalking ( ) ;
}
else
{
StopWalking ( ) ;
}
}
}
//-----------------------------------------------------------------------------
// This happens when we powerdown from the mega physcannon to the regular one
//-----------------------------------------------------------------------------
void CHL2_Player : : HandleArmorReduction ( void )
{
if ( m_flArmorReductionTime < gpGlobals - > curtime )
return ;
if ( ArmorValue ( ) < = 0 )
return ;
float flPercent = 1.0f - ( ( m_flArmorReductionTime - gpGlobals - > curtime ) / ARMOR_DECAY_TIME ) ;
int iArmor = Lerp ( flPercent , m_iArmorReductionFrom , 0 ) ;
SetArmorValue ( iArmor ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Allow pre-frame adjustments on the player
//-----------------------------------------------------------------------------
void CHL2_Player : : PreThink ( void )
{
if ( player_showpredictedposition . GetBool ( ) )
{
Vector predPos ;
UTIL_PredictedPosition ( this , player_showpredictedposition_timestep . GetFloat ( ) , & predPos ) ;
NDebugOverlay : : Box ( predPos , NAI_Hull : : Mins ( GetHullType ( ) ) , NAI_Hull : : Maxs ( GetHullType ( ) ) , 0 , 255 , 0 , 0 , 0.01f ) ;
NDebugOverlay : : Line ( GetAbsOrigin ( ) , predPos , 0 , 255 , 0 , 0 , 0.01f ) ;
}
# ifdef HL2_EPISODIC
if ( m_hLocatorTargetEntity ! = NULL )
{
// Keep track of the entity here, the client will pick up the rest of the work
m_HL2Local . m_vecLocatorOrigin = m_hLocatorTargetEntity - > WorldSpaceCenter ( ) ;
}
else
{
m_HL2Local . m_vecLocatorOrigin = vec3_invalid ; // This tells the client we have no locator target.
}
# endif //HL2_EPISODIC
// Riding a vehicle?
if ( IsInAVehicle ( ) )
{
VPROF ( " CHL2_Player::PreThink-Vehicle " ) ;
// make sure we update the client, check for timed damage and update suit even if we are in a vehicle
UpdateClientData ( ) ;
CheckTimeBasedDamage ( ) ;
// Allow the suit to recharge when in the vehicle.
SuitPower_Update ( ) ;
CheckSuitUpdate ( ) ;
CheckSuitZoom ( ) ;
WaterMove ( ) ;
return ;
}
// This is an experiment of mine- autojumping!
// only affects you if sv_autojump is nonzero.
if ( ( GetFlags ( ) & FL_ONGROUND ) & & sv_autojump . GetFloat ( ) ! = 0 )
{
VPROF ( " CHL2_Player::PreThink-Autojump " ) ;
// check autojump
Vector vecCheckDir ;
vecCheckDir = GetAbsVelocity ( ) ;
float flVelocity = VectorNormalize ( vecCheckDir ) ;
if ( flVelocity > 200 )
{
// Going fast enough to autojump
vecCheckDir = WorldSpaceCenter ( ) + vecCheckDir * 34 - Vector ( 0 , 0 , 16 ) ;
trace_t tr ;
UTIL_TraceHull ( WorldSpaceCenter ( ) - Vector ( 0 , 0 , 16 ) , vecCheckDir , NAI_Hull : : Mins ( HULL_TINY_CENTERED ) , NAI_Hull : : Maxs ( HULL_TINY_CENTERED ) , MASK_PLAYERSOLID , this , COLLISION_GROUP_PLAYER , & tr ) ;
//NDebugOverlay::Line( tr.startpos, tr.endpos, 0,255,0, true, 10 );
if ( tr . fraction = = 1.0 & & ! tr . startsolid )
{
// Now trace down!
UTIL_TraceLine ( vecCheckDir , vecCheckDir - Vector ( 0 , 0 , 64 ) , MASK_PLAYERSOLID , this , COLLISION_GROUP_NONE , & tr ) ;
//NDebugOverlay::Line( tr.startpos, tr.endpos, 0,255,0, true, 10 );
if ( tr . fraction = = 1.0 & & ! tr . startsolid )
{
// !!!HACKHACK
// I KNOW, I KNOW, this is definitely not the right way to do this,
// but I'm prototyping! (sjb)
Vector vecNewVelocity = GetAbsVelocity ( ) ;
vecNewVelocity . z + = 250 ;
SetAbsVelocity ( vecNewVelocity ) ;
}
}
}
}
VPROF_SCOPE_BEGIN ( " CHL2_Player::PreThink-Speed " ) ;
HandleSpeedChanges ( ) ;
# ifdef HL2_EPISODIC
HandleArmorReduction ( ) ;
# endif
if ( sv_stickysprint . GetBool ( ) & & m_bIsAutoSprinting )
{
// If we're ducked and not in the air
if ( IsDucked ( ) & & GetGroundEntity ( ) ! = NULL )
{
StopSprinting ( ) ;
}
// Stop sprinting if the player lets off the stick for a moment.
else if ( GetStickDist ( ) = = 0.0f )
{
if ( gpGlobals - > curtime > m_fAutoSprintMinTime )
{
StopSprinting ( ) ;
}
}
else
{
// Stop sprinting one half second after the player stops inputting with the move stick.
m_fAutoSprintMinTime = gpGlobals - > curtime + 0.5f ;
}
}
else if ( IsSprinting ( ) )
{
// Disable sprint while ducked unless we're in the air (jumping)
if ( IsDucked ( ) & & ( GetGroundEntity ( ) ! = NULL ) )
{
StopSprinting ( ) ;
}
}
VPROF_SCOPE_END ( ) ;
if ( g_fGameOver | | IsPlayerLockedInPlace ( ) )
return ; // finale
VPROF_SCOPE_BEGIN ( " CHL2_Player::PreThink-ItemPreFrame " ) ;
ItemPreFrame ( ) ;
VPROF_SCOPE_END ( ) ;
VPROF_SCOPE_BEGIN ( " CHL2_Player::PreThink-WaterMove " ) ;
WaterMove ( ) ;
VPROF_SCOPE_END ( ) ;
if ( g_pGameRules & & g_pGameRules - > FAllowFlashlight ( ) )
m_Local . m_iHideHUD & = ~ HIDEHUD_FLASHLIGHT ;
else
m_Local . m_iHideHUD | = HIDEHUD_FLASHLIGHT ;
VPROF_SCOPE_BEGIN ( " CHL2_Player::PreThink-CommanderUpdate " ) ;
CommanderUpdate ( ) ;
VPROF_SCOPE_END ( ) ;
// Operate suit accessories and manage power consumption/charge
VPROF_SCOPE_BEGIN ( " CHL2_Player::PreThink-SuitPower_Update " ) ;
SuitPower_Update ( ) ;
VPROF_SCOPE_END ( ) ;
// checks if new client data (for HUD and view control) needs to be sent to the client
VPROF_SCOPE_BEGIN ( " CHL2_Player::PreThink-UpdateClientData " ) ;
UpdateClientData ( ) ;
VPROF_SCOPE_END ( ) ;
VPROF_SCOPE_BEGIN ( " CHL2_Player::PreThink-CheckTimeBasedDamage " ) ;
CheckTimeBasedDamage ( ) ;
VPROF_SCOPE_END ( ) ;
VPROF_SCOPE_BEGIN ( " CHL2_Player::PreThink-CheckSuitUpdate " ) ;
CheckSuitUpdate ( ) ;
VPROF_SCOPE_END ( ) ;
VPROF_SCOPE_BEGIN ( " CHL2_Player::PreThink-CheckSuitZoom " ) ;
CheckSuitZoom ( ) ;
VPROF_SCOPE_END ( ) ;
if ( m_lifeState > = LIFE_DYING )
{
PlayerDeathThink ( ) ;
return ;
}
# ifdef HL2_EPISODIC
CheckFlashlight ( ) ;
# endif // HL2_EPISODIC
// So the correct flags get sent to client asap.
//
if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
AddFlag ( FL_ONTRAIN ) ;
else
RemoveFlag ( FL_ONTRAIN ) ;
// Train speed control
if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
{
CBaseEntity * pTrain = GetGroundEntity ( ) ;
float vel ;
if ( pTrain )
{
if ( ! ( pTrain - > ObjectCaps ( ) & FCAP_DIRECTIONAL_USE ) )
pTrain = NULL ;
}
if ( ! pTrain )
{
if ( GetActiveWeapon ( ) & & ( GetActiveWeapon ( ) - > ObjectCaps ( ) & FCAP_DIRECTIONAL_USE ) )
{
m_iTrain = TRAIN_ACTIVE | TRAIN_NEW ;
if ( m_nButtons & IN_FORWARD )
{
m_iTrain | = TRAIN_FAST ;
}
else if ( m_nButtons & IN_BACK )
{
m_iTrain | = TRAIN_BACK ;
}
else
{
m_iTrain | = TRAIN_NEUTRAL ;
}
return ;
}
else
{
trace_t trainTrace ;
// Maybe this is on the other side of a level transition
UTIL_TraceLine ( GetAbsOrigin ( ) , GetAbsOrigin ( ) + Vector ( 0 , 0 , - 38 ) ,
MASK_PLAYERSOLID_BRUSHONLY , this , COLLISION_GROUP_NONE , & trainTrace ) ;
if ( trainTrace . fraction ! = 1.0 & & trainTrace . m_pEnt )
pTrain = trainTrace . m_pEnt ;
if ( ! pTrain | | ! ( pTrain - > ObjectCaps ( ) & FCAP_DIRECTIONAL_USE ) | | ! pTrain - > OnControls ( this ) )
{
// Warning( "In train mode with no train!\n" );
m_afPhysicsFlags & = ~ PFLAG_DIROVERRIDE ;
m_iTrain = TRAIN_NEW | TRAIN_OFF ;
return ;
}
}
}
else if ( ! ( GetFlags ( ) & FL_ONGROUND ) | | pTrain - > HasSpawnFlags ( SF_TRACKTRAIN_NOCONTROL ) | | ( m_nButtons & ( IN_MOVELEFT | IN_MOVERIGHT ) ) )
{
// Turn off the train if you jump, strafe, or the train controls go dead
m_afPhysicsFlags & = ~ PFLAG_DIROVERRIDE ;
m_iTrain = TRAIN_NEW | TRAIN_OFF ;
return ;
}
SetAbsVelocity ( vec3_origin ) ;
vel = 0 ;
if ( m_afButtonPressed & IN_FORWARD )
{
vel = 1 ;
pTrain - > Use ( this , this , USE_SET , ( float ) vel ) ;
}
else if ( m_afButtonPressed & IN_BACK )
{
vel = - 1 ;
pTrain - > Use ( this , this , USE_SET , ( float ) vel ) ;
}
if ( vel )
{
m_iTrain = TrainSpeed ( pTrain - > m_flSpeed , ( ( CFuncTrackTrain * ) pTrain ) - > GetMaxSpeed ( ) ) ;
m_iTrain | = TRAIN_ACTIVE | TRAIN_NEW ;
}
}
else if ( m_iTrain & TRAIN_ACTIVE )
{
m_iTrain = TRAIN_NEW ; // turn off train
}
//
// If we're not on the ground, we're falling. Update our falling velocity.
//
if ( ! ( GetFlags ( ) & FL_ONGROUND ) )
{
m_Local . m_flFallVelocity = - GetAbsVelocity ( ) . z ;
}
if ( m_afPhysicsFlags & PFLAG_ONBARNACLE )
{
bool bOnBarnacle = false ;
CNPC_Barnacle * pBarnacle = NULL ;
do
{
// FIXME: Not a good or fast solution, but maybe it will catch the bug!
pBarnacle = ( CNPC_Barnacle * ) gEntList . FindEntityByClassname ( pBarnacle , " npc_barnacle " ) ;
if ( pBarnacle )
{
if ( pBarnacle - > GetEnemy ( ) = = this )
{
bOnBarnacle = true ;
}
}
} while ( pBarnacle ) ;
if ( ! bOnBarnacle )
{
Warning ( " Attached to barnacle? \n " ) ;
Assert ( 0 ) ;
m_afPhysicsFlags & = ~ PFLAG_ONBARNACLE ;
}
else
{
SetAbsVelocity ( vec3_origin ) ;
}
}
// StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating?
// Update weapon's ready status
UpdateWeaponPosture ( ) ;
// Disallow shooting while zooming
if ( IsX360 ( ) )
{
if ( IsZooming ( ) )
{
if ( GetActiveWeapon ( ) & & ! GetActiveWeapon ( ) - > IsWeaponZoomed ( ) )
{
// If not zoomed because of the weapon itself, do not attack.
m_nButtons & = ~ ( IN_ATTACK | IN_ATTACK2 ) ;
}
}
}
else
{
if ( m_nButtons & IN_ZOOM )
{
//FIXME: Held weapons like the grenade get sad when this happens
# ifdef HL2_EPISODIC
// Episodic allows players to zoom while using a func_tank
CBaseCombatWeapon * pWep = GetActiveWeapon ( ) ;
if ( ! m_hUseEntity | | ( pWep & & pWep - > IsWeaponVisible ( ) ) )
# endif
m_nButtons & = ~ ( IN_ATTACK | IN_ATTACK2 ) ;
}
}
}
void CHL2_Player : : PostThink ( void )
{
BaseClass : : PostThink ( ) ;
if ( ! g_fGameOver & & ! IsPlayerLockedInPlace ( ) & & IsAlive ( ) )
{
HandleAdmireGlovesAnimation ( ) ;
}
}
void CHL2_Player : : StartAdmireGlovesAnimation ( void )
{
MDLCACHE_CRITICAL_SECTION ( ) ;
CBaseViewModel * vm = GetViewModel ( 0 ) ;
if ( vm & & ! GetActiveWeapon ( ) )
{
vm - > SetWeaponModel ( " models/weapons/v_hands.mdl " , NULL ) ;
ShowViewModel ( true ) ;
int idealSequence = vm - > SelectWeightedSequence ( ACT_VM_IDLE ) ;
if ( idealSequence > = 0 )
{
vm - > SendViewModelMatchingSequence ( idealSequence ) ;
m_flAdmireGlovesAnimTime = gpGlobals - > curtime + vm - > SequenceDuration ( idealSequence ) ;
}
}
}
void CHL2_Player : : HandleAdmireGlovesAnimation ( void )
{
CBaseViewModel * pVM = GetViewModel ( ) ;
if ( pVM & & pVM - > GetOwningWeapon ( ) = = NULL )
{
if ( m_flAdmireGlovesAnimTime ! = 0.0 )
{
if ( m_flAdmireGlovesAnimTime > gpGlobals - > curtime )
{
pVM - > m_flPlaybackRate = 1.0f ;
pVM - > StudioFrameAdvance ( ) ;
}
else if ( m_flAdmireGlovesAnimTime < gpGlobals - > curtime )
{
m_flAdmireGlovesAnimTime = 0.0f ;
pVM - > SetWeaponModel ( NULL , NULL ) ;
}
}
}
else
m_flAdmireGlovesAnimTime = 0.0f ;
}
# define HL2PLAYER_RELOADGAME_ATTACK_DELAY 1.0f
void CHL2_Player : : Activate ( void )
{
BaseClass : : Activate ( ) ;
InitSprinting ( ) ;
# ifdef HL2_EPISODIC
// Delay attacks by 1 second after loading a game.
if ( GetActiveWeapon ( ) )
{
float flRemaining = GetActiveWeapon ( ) - > m_flNextPrimaryAttack - gpGlobals - > curtime ;
if ( flRemaining < HL2PLAYER_RELOADGAME_ATTACK_DELAY )
{
GetActiveWeapon ( ) - > m_flNextPrimaryAttack = gpGlobals - > curtime + HL2PLAYER_RELOADGAME_ATTACK_DELAY ;
}
flRemaining = GetActiveWeapon ( ) - > m_flNextSecondaryAttack - gpGlobals - > curtime ;
if ( flRemaining < HL2PLAYER_RELOADGAME_ATTACK_DELAY )
{
GetActiveWeapon ( ) - > m_flNextSecondaryAttack = gpGlobals - > curtime + HL2PLAYER_RELOADGAME_ATTACK_DELAY ;
}
}
# endif
GetPlayerProxy ( ) ;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
Class_T CHL2_Player : : Classify ( void )
{
// If player controlling another entity? If so, return this class
if ( m_nControlClass ! = CLASS_NONE )
{
return m_nControlClass ;
}
else
{
if ( IsInAVehicle ( ) )
{
IServerVehicle * pVehicle = GetVehicle ( ) ;
return pVehicle - > ClassifyPassenger ( this , CLASS_PLAYER ) ;
}
else
{
return CLASS_PLAYER ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: This is a generic function (to be implemented by sub-classes) to
// handle specific interactions between different types of characters
// (For example the barnacle grabbing an NPC)
// Input : Constant for the type of interaction
// Output : true - if sub-class has a response for the interaction
// false - if sub-class has no response
//-----------------------------------------------------------------------------
bool CHL2_Player : : HandleInteraction ( int interactionType , void * data , CBaseCombatCharacter * sourceEnt )
{
if ( interactionType = = g_interactionBarnacleVictimDangle )
return false ;
if ( interactionType = = g_interactionBarnacleVictimReleased )
{
m_afPhysicsFlags & = ~ PFLAG_ONBARNACLE ;
SetMoveType ( MOVETYPE_WALK ) ;
return true ;
}
else if ( interactionType = = g_interactionBarnacleVictimGrab )
{
# ifdef HL2_EPISODIC
CNPC_Alyx * pAlyx = CNPC_Alyx : : GetAlyx ( ) ;
if ( pAlyx )
{
// Make Alyx totally hate this barnacle so that she saves the player.
int priority ;
priority = pAlyx - > IRelationPriority ( sourceEnt ) ;
pAlyx - > AddEntityRelationship ( sourceEnt , D_HT , priority + 5 ) ;
}
# endif //HL2_EPISODIC
m_afPhysicsFlags | = PFLAG_ONBARNACLE ;
ClearUseEntity ( ) ;
return true ;
}
return false ;
}
void CHL2_Player : : PlayerRunCommand ( CUserCmd * ucmd , IMoveHelper * moveHelper )
{
// Handle FL_FROZEN.
if ( m_afPhysicsFlags & PFLAG_ONBARNACLE )
{
ucmd - > forwardmove = 0 ;
ucmd - > sidemove = 0 ;
ucmd - > upmove = 0 ;
ucmd - > buttons & = ~ IN_USE ;
}
// Can't use stuff while dead
if ( IsDead ( ) )
{
ucmd - > buttons & = ~ IN_USE ;
}
//Update our movement information
if ( ( ucmd - > forwardmove ! = 0 ) | | ( ucmd - > sidemove ! = 0 ) | | ( ucmd - > upmove ! = 0 ) )
{
m_flIdleTime - = TICK_INTERVAL * 2.0f ;
if ( m_flIdleTime < 0.0f )
{
m_flIdleTime = 0.0f ;
}
m_flMoveTime + = TICK_INTERVAL ;
if ( m_flMoveTime > 4.0f )
{
m_flMoveTime = 4.0f ;
}
}
else
{
m_flIdleTime + = TICK_INTERVAL ;
if ( m_flIdleTime > 4.0f )
{
m_flIdleTime = 4.0f ;
}
m_flMoveTime - = TICK_INTERVAL * 2.0f ;
if ( m_flMoveTime < 0.0f )
{
m_flMoveTime = 0.0f ;
}
}
//Msg("Player time: [ACTIVE: %f]\t[IDLE: %f]\n", m_flMoveTime, m_flIdleTime );
BaseClass : : PlayerRunCommand ( ucmd , moveHelper ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Sets HL2 specific defaults.
//-----------------------------------------------------------------------------
void CHL2_Player : : Spawn ( void )
{
# ifndef HL2MP
# ifndef PORTAL
SetModel ( " models/player.mdl " ) ;
# endif
# endif
BaseClass : : Spawn ( ) ;
//
// Our player movement speed is set once here. This will override the cl_xxxx
// cvars unless they are set to be lower than this.
//
//m_flMaxspeed = 320;
if ( ! IsSuitEquipped ( ) )
StartWalking ( ) ;
SuitPower_SetCharge ( 100 ) ;
m_Local . m_iHideHUD | = HIDEHUD_CHAT ;
m_pPlayerAISquad = g_AI_SquadManager . FindCreateSquad ( AllocPooledString ( PLAYER_SQUADNAME ) ) ;
InitSprinting ( ) ;
// Setup our flashlight values
# ifdef HL2_EPISODIC
m_HL2Local . m_flFlashBattery = 100.0f ;
# endif
GetPlayerProxy ( ) ;
SetFlashlightPowerDrainScale ( 1.0f ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : UpdateLocatorPosition ( const Vector & vecPosition )
{
# ifdef HL2_EPISODIC
m_HL2Local . m_vecLocatorOrigin = vecPosition ;
# endif //HL2_EPISODIC
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : InitSprinting ( void )
{
StopSprinting ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not we are allowed to sprint now.
//-----------------------------------------------------------------------------
bool CHL2_Player : : CanSprint ( )
{
return ( m_bSprintEnabled & & // Only if sprint is enabled
! IsWalking ( ) & & // Not if we're walking
! ( m_Local . m_bDucked & & ! m_Local . m_bDucking ) & & // Nor if we're ducking
( GetWaterLevel ( ) ! = 3 ) & & // Certainly not underwater
( GlobalEntity_GetState ( " suit_no_sprint " ) ! = GLOBAL_ON ) ) ; // Out of the question without the sprint module
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : StartAutoSprint ( )
{
if ( IsSprinting ( ) )
{
StopSprinting ( ) ;
}
else
{
StartSprinting ( ) ;
m_bIsAutoSprinting = true ;
m_fAutoSprintMinTime = gpGlobals - > curtime + 1.5f ;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : StartSprinting ( void )
{
if ( m_HL2Local . m_flSuitPower < 10 )
{
// Don't sprint unless there's a reasonable
// amount of suit power.
// debounce the button for sound playing
if ( m_afButtonPressed & IN_SPEED )
{
CPASAttenuationFilter filter ( this ) ;
filter . UsePredictionRules ( ) ;
EmitSound ( filter , entindex ( ) , " HL2Player.SprintNoPower " ) ;
}
return ;
}
if ( ! SuitPower_AddDevice ( SuitDeviceSprint ) )
return ;
CPASAttenuationFilter filter ( this ) ;
filter . UsePredictionRules ( ) ;
EmitSound ( filter , entindex ( ) , " HL2Player.SprintStart " ) ;
SetMaxSpeed ( HL2_SPRINT_SPEED ) ;
m_fIsSprinting = true ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : StopSprinting ( void )
{
if ( m_HL2Local . m_bitsActiveDevices & SuitDeviceSprint . GetDeviceID ( ) )
{
SuitPower_RemoveDevice ( SuitDeviceSprint ) ;
}
if ( IsSuitEquipped ( ) )
{
SetMaxSpeed ( HL2_NORM_SPEED ) ;
}
else
{
SetMaxSpeed ( HL2_WALK_SPEED ) ;
}
m_fIsSprinting = false ;
if ( sv_stickysprint . GetBool ( ) )
{
m_bIsAutoSprinting = false ;
m_fAutoSprintMinTime = 0.0f ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Called to disable and enable sprint due to temporary circumstances:
// - Carrying a heavy object with the physcannon
//-----------------------------------------------------------------------------
void CHL2_Player : : EnableSprint ( bool bEnable )
{
if ( ! bEnable & & IsSprinting ( ) )
{
StopSprinting ( ) ;
}
m_bSprintEnabled = bEnable ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : StartWalking ( void )
{
SetMaxSpeed ( HL2_WALK_SPEED ) ;
m_fIsWalking = true ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : StopWalking ( void )
{
SetMaxSpeed ( HL2_NORM_SPEED ) ;
m_fIsWalking = false ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHL2_Player : : CanZoom ( CBaseEntity * pRequester )
{
if ( IsZooming ( ) )
return false ;
//Check our weapon
return true ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : ToggleZoom ( void )
{
if ( IsZooming ( ) )
{
StopZooming ( ) ;
}
else
{
StartZooming ( ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: +zoom suit zoom
//-----------------------------------------------------------------------------
void CHL2_Player : : StartZooming ( void )
{
int iFOV = 25 ;
if ( SetFOV ( this , iFOV , 0.4f ) )
{
m_HL2Local . m_bZooming = true ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2_Player : : StopZooming ( void )
{
int iFOV = GetZoomOwnerDesiredFOV ( m_hZoomOwner ) ;
if ( SetFOV ( this , iFOV , 0.2f ) )
{
m_HL2Local . m_bZooming = false ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHL2_Player : : IsZooming ( void )
{
if ( m_hZoomOwner ! = NULL )
return true ;
return false ;
}
class CPhysicsPlayerCallback : public IPhysicsPlayerControllerEvent
{
public :
int ShouldMoveTo ( IPhysicsObject * pObject , const Vector & position )
{
CHL2_Player * pPlayer = ( CHL2_Player * ) pObject - > GetGameData ( ) ;
if ( pPlayer )
{
if ( pPlayer - > TouchedPhysics ( ) )
{
return 0 ;
}
}
return 1 ;
}
} ;
static CPhysicsPlayerCallback playerCallback ;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2_Player : : InitVCollision ( const Vector & vecAbsOrigin , const Vector & vecAbsVelocity )
{
BaseClass : : InitVCollision ( vecAbsOrigin , vecAbsVelocity ) ;
// Setup the HL2 specific callback.
IPhysicsPlayerController * pPlayerController = GetPhysicsController ( ) ;
if ( pPlayerController )
{
pPlayerController - > SetEventHandler ( & playerCallback ) ;
}
}
CHL2_Player : : ~ CHL2_Player ( void )
{
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CHL2_Player : : CommanderFindGoal ( commandgoal_t * pGoal )
{
CAI_BaseNPC * pAllyNpc ;
trace_t tr ;
Vector vecTarget ;
Vector forward ;
EyeVectors ( & forward ) ;
//---------------------------------
// MASK_SHOT on purpose! So that you don't hit the invisible hulls of the NPCs.
CTraceFilterSkipTwoEntities filter ( this , PhysCannonGetHeldEntity ( GetActiveWeapon ( ) ) , COLLISION_GROUP_INTERACTIVE_DEBRIS ) ;
UTIL_TraceLine ( EyePosition ( ) , EyePosition ( ) + forward * MAX_COORD_RANGE , MASK_SHOT , & filter , & tr ) ;
if ( ! tr . DidHitWorld ( ) )
{
CUtlVector < CAI_BaseNPC * > Allies ;
AISquadIter_t iter ;
for ( pAllyNpc = m_pPlayerAISquad - > GetFirstMember ( & iter ) ; pAllyNpc ; pAllyNpc = m_pPlayerAISquad - > GetNextMember ( & iter ) )
{
if ( pAllyNpc - > IsCommandable ( ) )
Allies . AddToTail ( pAllyNpc ) ;
}
for ( int i = 0 ; i < Allies . Count ( ) ; i + + )
{
if ( Allies [ i ] - > IsValidCommandTarget ( tr . m_pEnt ) )
{
pGoal - > m_pGoalEntity = tr . m_pEnt ;
return true ;
}
}
}
if ( tr . fraction = = 1.0 | | ( tr . surface . flags & SURF_SKY ) )
{
// Move commands invalid against skybox.
pGoal - > m_vecGoalLocation = tr . endpos ;
return false ;
}
if ( tr . m_pEnt - > IsNPC ( ) & & ( ( CAI_BaseNPC * ) ( tr . m_pEnt ) ) - > IsCommandable ( ) )
{
pGoal - > m_vecGoalLocation = tr . m_pEnt - > GetAbsOrigin ( ) ;
}
else
{
vecTarget = tr . endpos ;
Vector mins ( - 16 , - 16 , 0 ) ;
Vector maxs ( 16 , 16 , 0 ) ;
// Back up from whatever we hit so that there's enough space at the
// target location for a bounding box.
// Now trace down.
//UTIL_TraceLine( vecTarget, vecTarget - Vector( 0, 0, 8192 ), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
UTIL_TraceHull ( vecTarget + tr . plane . normal * 24 ,
vecTarget - Vector ( 0 , 0 , 8192 ) ,
mins ,
maxs ,
MASK_SOLID_BRUSHONLY ,
this ,
COLLISION_GROUP_NONE ,
& tr ) ;
if ( ! tr . startsolid )
pGoal - > m_vecGoalLocation = tr . endpos ;
else
pGoal - > m_vecGoalLocation = vecTarget ;
}
pAllyNpc = GetSquadCommandRepresentative ( ) ;
if ( ! pAllyNpc )
return false ;
vecTarget = pGoal - > m_vecGoalLocation ;
if ( ! pAllyNpc - > FindNearestValidGoalPos ( vecTarget , & pGoal - > m_vecGoalLocation ) )
return false ;
return ( ( vecTarget - pGoal - > m_vecGoalLocation ) . LengthSqr ( ) < Square ( 15 * 12 ) ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CAI_BaseNPC * CHL2_Player : : GetSquadCommandRepresentative ( )
{
if ( m_pPlayerAISquad ! = NULL )
{
CAI_BaseNPC * pAllyNpc = m_pPlayerAISquad - > GetFirstMember ( ) ;
if ( pAllyNpc )
{
return pAllyNpc - > GetSquadCommandRepresentative ( ) ;
}
}
return NULL ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CHL2_Player : : GetNumSquadCommandables ( )
{
AISquadIter_t iter ;
int c = 0 ;
for ( CAI_BaseNPC * pAllyNpc = m_pPlayerAISquad - > GetFirstMember ( & iter ) ; pAllyNpc ; pAllyNpc = m_pPlayerAISquad - > GetNextMember ( & iter ) )
{
if ( pAllyNpc - > IsCommandable ( ) )
c + + ;
}
return c ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CHL2_Player : : GetNumSquadCommandableMedics ( )
{
AISquadIter_t iter ;
int c = 0 ;
for ( CAI_BaseNPC * pAllyNpc = m_pPlayerAISquad - > GetFirstMember ( & iter ) ; pAllyNpc ; pAllyNpc = m_pPlayerAISquad - > GetNextMember ( & iter ) )
{
if ( pAllyNpc - > IsCommandable ( ) & & pAllyNpc - > IsMedic ( ) )
c + + ;
}
return c ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : CommanderUpdate ( )
{
CAI_BaseNPC * pCommandRepresentative = GetSquadCommandRepresentative ( ) ;
bool bFollowMode = false ;
if ( pCommandRepresentative )
{
bFollowMode = ( pCommandRepresentative - > GetCommandGoal ( ) = = vec3_invalid ) ;
// set the variables for network transmission (to show on the hud)
m_HL2Local . m_iSquadMemberCount = GetNumSquadCommandables ( ) ;
m_HL2Local . m_iSquadMedicCount = GetNumSquadCommandableMedics ( ) ;
m_HL2Local . m_fSquadInFollowMode = bFollowMode ;
// debugging code for displaying extra squad indicators
/*
char * pszMoving = " " ;
AISquadIter_t iter ;
for ( CAI_BaseNPC * pAllyNpc = m_pPlayerAISquad - > GetFirstMember ( & iter ) ; pAllyNpc ; pAllyNpc = m_pPlayerAISquad - > GetNextMember ( & iter ) )
{
if ( pAllyNpc - > IsCommandMoving ( ) )
{
pszMoving = " <- " ;
break ;
}
}
NDebugOverlay : : ScreenText (
0.932 , 0.919 ,
CFmtStr ( " %d|%c%s " , GetNumSquadCommandables ( ) , ( bFollowMode ) ? ' F ' : ' S ' , pszMoving ) ,
255 , 128 , 0 , 128 ,
0 ) ;
*/
}
else
{
m_HL2Local . m_iSquadMemberCount = 0 ;
m_HL2Local . m_iSquadMedicCount = 0 ;
m_HL2Local . m_fSquadInFollowMode = true ;
}
if ( m_QueuedCommand ! = CC_NONE & & ( m_QueuedCommand = = CC_FOLLOW | | gpGlobals - > realtime - m_RealTimeLastSquadCommand > = player_squad_double_tap_time . GetFloat ( ) ) )
{
CommanderExecute ( m_QueuedCommand ) ;
m_QueuedCommand = CC_NONE ;
}
else if ( ! bFollowMode & & pCommandRepresentative & & m_CommanderUpdateTimer . Expired ( ) & & player_squad_transient_commands . GetBool ( ) )
{
m_CommanderUpdateTimer . Set ( 2.5 ) ;
if ( pCommandRepresentative - > ShouldAutoSummon ( ) )
CommanderExecute ( CC_FOLLOW ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//
// bHandled - indicates whether to continue delivering this order to
// all allies. Allows us to stop delivering certain types of orders once we find
// a suitable candidate. (like picking up a single weapon. We don't wish for
// all allies to respond and try to pick up one weapon).
//-----------------------------------------------------------------------------
bool CHL2_Player : : CommanderExecuteOne ( CAI_BaseNPC * pNpc , const commandgoal_t & goal , CAI_BaseNPC * * Allies , int numAllies )
{
if ( goal . m_pGoalEntity )
{
return pNpc - > TargetOrder ( goal . m_pGoalEntity , Allies , numAllies ) ;
}
else if ( pNpc - > IsInPlayerSquad ( ) )
{
pNpc - > MoveOrder ( goal . m_vecGoalLocation , Allies , numAllies ) ;
}
return true ;
}
//---------------------------------------------------------
//---------------------------------------------------------
void CHL2_Player : : CommanderExecute ( CommanderCommand_t command )
{
CAI_BaseNPC * pPlayerSquadLeader = GetSquadCommandRepresentative ( ) ;
if ( ! pPlayerSquadLeader )
{
EmitSound ( " HL2Player.UseDeny " ) ;
return ;
}
int i ;
CUtlVector < CAI_BaseNPC * > Allies ;
commandgoal_t goal ;
if ( command = = CC_TOGGLE )
{
if ( pPlayerSquadLeader - > GetCommandGoal ( ) ! = vec3_invalid )
command = CC_FOLLOW ;
else
command = CC_SEND ;
}
else
{
if ( command = = CC_FOLLOW & & pPlayerSquadLeader - > GetCommandGoal ( ) = = vec3_invalid )
return ;
}
if ( command = = CC_FOLLOW )
{
goal . m_pGoalEntity = this ;
goal . m_vecGoalLocation = vec3_invalid ;
}
else
{
goal . m_pGoalEntity = NULL ;
goal . m_vecGoalLocation = vec3_invalid ;
// Find a goal for ourselves.
if ( ! CommanderFindGoal ( & goal ) )
{
EmitSound ( " HL2Player.UseDeny " ) ;
return ; // just keep following
}
}
# ifdef _DEBUG
if ( goal . m_pGoalEntity = = NULL & & goal . m_vecGoalLocation = = vec3_invalid )
{
DevMsg ( 1 , " **ERROR: Someone sent an invalid goal to CommanderExecute! \n " ) ;
}
# endif // _DEBUG
AISquadIter_t iter ;
for ( CAI_BaseNPC * pAllyNpc = m_pPlayerAISquad - > GetFirstMember ( & iter ) ; pAllyNpc ; pAllyNpc = m_pPlayerAISquad - > GetNextMember ( & iter ) )
{
if ( pAllyNpc - > IsCommandable ( ) )
Allies . AddToTail ( pAllyNpc ) ;
}
//---------------------------------
// If the trace hits an NPC, send all ally NPCs a "target" order. Always
// goes to targeted one first
# ifdef DBGFLAG_ASSERT
int nAIs = g_AI_Manager . NumAIs ( ) ;
# endif
CAI_BaseNPC * pTargetNpc = ( goal . m_pGoalEntity ) ? goal . m_pGoalEntity - > MyNPCPointer ( ) : NULL ;
bool bHandled = false ;
if ( pTargetNpc )
{
bHandled = ! CommanderExecuteOne ( pTargetNpc , goal , Allies . Base ( ) , Allies . Count ( ) ) ;
}
for ( i = 0 ; ! bHandled & & i < Allies . Count ( ) ; i + + )
{
if ( Allies [ i ] ! = pTargetNpc & & Allies [ i ] - > IsPlayerAlly ( ) )
{
bHandled = ! CommanderExecuteOne ( Allies [ i ] , goal , Allies . Base ( ) , Allies . Count ( ) ) ;
}
Assert ( nAIs = = g_AI_Manager . NumAIs ( ) ) ; // not coded to support mutating set of NPCs
}
}
//-----------------------------------------------------------------------------
// Enter/exit commander mode, manage ally selection.
//-----------------------------------------------------------------------------
void CHL2_Player : : CommanderMode ( )
{
float commandInterval = gpGlobals - > realtime - m_RealTimeLastSquadCommand ;
m_RealTimeLastSquadCommand = gpGlobals - > realtime ;
if ( commandInterval < player_squad_double_tap_time . GetFloat ( ) )
{
m_QueuedCommand = CC_FOLLOW ;
}
else
{
m_QueuedCommand = ( player_squad_transient_commands . GetBool ( ) ) ? CC_SEND : CC_TOGGLE ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : iImpulse -
//-----------------------------------------------------------------------------
void CHL2_Player : : CheatImpulseCommands ( int iImpulse )
{
switch ( iImpulse )
{
case 50 :
{
CommanderMode ( ) ;
break ;
}
case 51 :
{
// Cheat to create a dynamic resupply item
Vector vecForward ;
AngleVectors ( EyeAngles ( ) , & vecForward ) ;
CBaseEntity * pItem = ( CBaseEntity * ) CreateEntityByName ( " item_dynamic_resupply " ) ;
if ( pItem )
{
Vector vecOrigin = GetAbsOrigin ( ) + vecForward * 256 + Vector ( 0 , 0 , 64 ) ;
QAngle vecAngles ( 0 , GetAbsAngles ( ) . y - 90 , 0 ) ;
pItem - > SetAbsOrigin ( vecOrigin ) ;
pItem - > SetAbsAngles ( vecAngles ) ;
pItem - > KeyValue ( " targetname " , " resupply " ) ;
pItem - > Spawn ( ) ;
pItem - > Activate ( ) ;
}
break ;
}
case 52 :
{
// Rangefinder
trace_t tr ;
UTIL_TraceLine ( EyePosition ( ) , EyePosition ( ) + EyeDirection3D ( ) * MAX_COORD_RANGE , MASK_SHOT , this , COLLISION_GROUP_NONE , & tr ) ;
if ( tr . fraction ! = 1.0 )
{
float flDist = ( tr . startpos - tr . endpos ) . Length ( ) ;
float flDist2D = ( tr . startpos - tr . endpos ) . Length2D ( ) ;
DevMsg ( 1 , " \n StartPos: %.4f %.4f %.4f --- EndPos: %.4f %.4f %.4f \n " , tr . startpos . x , tr . startpos . y , tr . startpos . z , tr . endpos . x , tr . endpos . y , tr . endpos . z ) ;
DevMsg ( 1 , " 3D Distance: %.4f units (%.2f feet) --- 2D Distance: %.4f units (%.2f feet) \n " , flDist , flDist / 12.0 , flDist2D , flDist2D / 12.0 ) ;
}
break ;
}
default :
BaseClass : : CheatImpulseCommands ( iImpulse ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2_Player : : SetupVisibility ( CBaseEntity * pViewEntity , unsigned char * pvs , int pvssize )
{
BaseClass : : SetupVisibility ( pViewEntity , pvs , pvssize ) ;
int area = pViewEntity ? pViewEntity - > NetworkProp ( ) - > AreaNum ( ) : NetworkProp ( ) - > AreaNum ( ) ;
PointCameraSetupVisibility ( this , area , pvs , pvssize ) ;
// If the intro script is playing, we want to get it's visibility points
if ( g_hIntroScript )
{
Vector vecOrigin ;
CBaseEntity * pCamera ;
if ( g_hIntroScript - > GetIncludedPVSOrigin ( & vecOrigin , & pCamera ) )
{
// If it's a point camera, turn it on
CPointCamera * pPointCamera = dynamic_cast < CPointCamera * > ( pCamera ) ;
if ( pPointCamera )
{
pPointCamera - > SetActive ( true ) ;
}
engine - > AddOriginToPVS ( vecOrigin ) ;
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : SuitPower_Update ( void )
{
if ( SuitPower_ShouldRecharge ( ) )
{
SuitPower_Charge ( SUITPOWER_CHARGE_RATE * gpGlobals - > frametime ) ;
}
else if ( m_HL2Local . m_bitsActiveDevices )
{
float flPowerLoad = m_flSuitPowerLoad ;
//Since stickysprint quickly shuts off sprint if it isn't being used, this isn't an issue.
if ( ! sv_stickysprint . GetBool ( ) )
{
if ( SuitPower_IsDeviceActive ( SuitDeviceSprint ) )
{
if ( ! fabs ( GetAbsVelocity ( ) . x ) & & ! fabs ( GetAbsVelocity ( ) . y ) )
{
// If player's not moving, don't drain sprint juice.
flPowerLoad - = SuitDeviceSprint . GetDeviceDrainRate ( ) ;
}
}
}
if ( SuitPower_IsDeviceActive ( SuitDeviceFlashlight ) )
{
float factor ;
factor = 1.0f / m_flFlashlightPowerDrainScale ;
flPowerLoad - = ( SuitDeviceFlashlight . GetDeviceDrainRate ( ) * ( 1.0f - factor ) ) ;
}
if ( ! SuitPower_Drain ( flPowerLoad * gpGlobals - > frametime ) )
{
// TURN OFF ALL DEVICES!!
if ( IsSprinting ( ) )
{
StopSprinting ( ) ;
}
if ( Flashlight_UseLegacyVersion ( ) )
{
if ( FlashlightIsOn ( ) )
{
# ifndef HL2MP
FlashlightTurnOff ( ) ;
# endif
}
}
}
if ( Flashlight_UseLegacyVersion ( ) )
{
// turn off flashlight a little bit after it hits below one aux power notch (5%)
if ( m_HL2Local . m_flSuitPower < 4.8f & & FlashlightIsOn ( ) )
{
# ifndef HL2MP
FlashlightTurnOff ( ) ;
# endif
}
}
}
}
//-----------------------------------------------------------------------------
// Charge battery fully, turn off all devices.
//-----------------------------------------------------------------------------
void CHL2_Player : : SuitPower_Initialize ( void )
{
m_HL2Local . m_bitsActiveDevices = 0x00000000 ;
m_HL2Local . m_flSuitPower = 100.0 ;
m_flSuitPowerLoad = 0.0 ;
}
//-----------------------------------------------------------------------------
// Purpose: Interface to drain power from the suit's power supply.
// Input: Amount of charge to remove (expressed as percentage of full charge)
// Output: Returns TRUE if successful, FALSE if not enough power available.
//-----------------------------------------------------------------------------
bool CHL2_Player : : SuitPower_Drain ( float flPower )
{
// Suitpower cheat on?
if ( sv_infinite_aux_power . GetBool ( ) )
return true ;
m_HL2Local . m_flSuitPower - = flPower ;
if ( m_HL2Local . m_flSuitPower < 0.0 )
{
// Power is depleted!
// Clamp and fail
m_HL2Local . m_flSuitPower = 0.0 ;
return false ;
}
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: Interface to add power to the suit's power supply
// Input: Amount of charge to add
//-----------------------------------------------------------------------------
void CHL2_Player : : SuitPower_Charge ( float flPower )
{
m_HL2Local . m_flSuitPower + = flPower ;
if ( m_HL2Local . m_flSuitPower > 100.0 )
{
// Full charge, clamp.
m_HL2Local . m_flSuitPower = 100.0 ;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CHL2_Player : : SuitPower_IsDeviceActive ( const CSuitPowerDevice & device )
{
return ( m_HL2Local . m_bitsActiveDevices & device . GetDeviceID ( ) ) ! = 0 ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CHL2_Player : : SuitPower_AddDevice ( const CSuitPowerDevice & device )
{
// Make sure this device is NOT active!!
if ( m_HL2Local . m_bitsActiveDevices & device . GetDeviceID ( ) )
return false ;
if ( ! IsSuitEquipped ( ) )
return false ;
m_HL2Local . m_bitsActiveDevices | = device . GetDeviceID ( ) ;
m_flSuitPowerLoad + = device . GetDeviceDrainRate ( ) ;
return true ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CHL2_Player : : SuitPower_RemoveDevice ( const CSuitPowerDevice & device )
{
// Make sure this device is active!!
if ( ! ( m_HL2Local . m_bitsActiveDevices & device . GetDeviceID ( ) ) )
return false ;
if ( ! IsSuitEquipped ( ) )
return false ;
// Take a little bit of suit power when you disable a device. If the device is shutting off
// because the battery is drained, no harm done, the battery charge cannot go below 0.
// This code in combination with the delay before the suit can start recharging are a defense
// against exploits where the player could rapidly tap sprint and never run out of power.
SuitPower_Drain ( device . GetDeviceDrainRate ( ) * 0.1f ) ;
m_HL2Local . m_bitsActiveDevices & = ~ device . GetDeviceID ( ) ;
m_flSuitPowerLoad - = device . GetDeviceDrainRate ( ) ;
if ( m_HL2Local . m_bitsActiveDevices = = 0x00000000 )
{
// With this device turned off, we can set this timer which tells us when the
// suit power system entered a no-load state.
m_flTimeAllSuitDevicesOff = gpGlobals - > curtime ;
}
return true ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
# define SUITPOWER_BEGIN_RECHARGE_DELAY 0.5f
bool CHL2_Player : : SuitPower_ShouldRecharge ( void )
{
// Make sure all devices are off.
if ( m_HL2Local . m_bitsActiveDevices ! = 0x00000000 )
return false ;
// Is the system fully charged?
if ( m_HL2Local . m_flSuitPower > = 100.0f )
return false ;
// Has the system been in a no-load state for long enough
// to begin recharging?
if ( gpGlobals - > curtime < m_flTimeAllSuitDevicesOff + SUITPOWER_BEGIN_RECHARGE_DELAY )
return false ;
return true ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
ConVar sk_battery ( " sk_battery " , " 0 " ) ;
bool CHL2_Player : : ApplyBattery ( float powerMultiplier )
{
const float MAX_NORMAL_BATTERY = 100 ;
if ( ( ArmorValue ( ) < MAX_NORMAL_BATTERY ) & & IsSuitEquipped ( ) )
{
int pct ;
char szcharge [ 64 ] ;
IncrementArmorValue ( sk_battery . GetFloat ( ) * powerMultiplier , MAX_NORMAL_BATTERY ) ;
CPASAttenuationFilter filter ( this , " ItemBattery.Touch " ) ;
EmitSound ( filter , entindex ( ) , " ItemBattery.Touch " ) ;
CSingleUserRecipientFilter user ( this ) ;
user . MakeReliable ( ) ;
UserMessageBegin ( user , " ItemPickup " ) ;
WRITE_STRING ( " item_battery " ) ;
MessageEnd ( ) ;
// Suit reports new power level
// For some reason this wasn't working in release build -- round it.
pct = ( int ) ( ( float ) ( ArmorValue ( ) * 100.0 ) * ( 1.0 / MAX_NORMAL_BATTERY ) + 0.5 ) ;
pct = ( pct / 5 ) ;
if ( pct > 0 )
pct - - ;
Q_snprintf ( szcharge , sizeof ( szcharge ) , " !HEV_%1dP " , pct ) ;
//UTIL_EmitSoundSuit(edict(), szcharge);
//SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC);
return true ;
}
return false ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CHL2_Player : : FlashlightIsOn ( void )
{
return IsEffectActive ( EF_DIMLIGHT ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : FlashlightTurnOn ( void )
{
if ( m_bFlashlightDisabled )
return ;
if ( Flashlight_UseLegacyVersion ( ) )
{
if ( ! SuitPower_AddDevice ( SuitDeviceFlashlight ) )
return ;
}
# ifdef HL2_DLL
if ( ! IsSuitEquipped ( ) )
return ;
# endif
AddEffects ( EF_DIMLIGHT ) ;
EmitSound ( " HL2Player.FlashLightOn " ) ;
variant_t flashlighton ;
flashlighton . SetFloat ( m_HL2Local . m_flSuitPower / 100.0f ) ;
FirePlayerProxyOutput ( " OnFlashlightOn " , flashlighton , this , this ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : FlashlightTurnOff ( void )
{
if ( Flashlight_UseLegacyVersion ( ) )
{
if ( ! SuitPower_RemoveDevice ( SuitDeviceFlashlight ) )
return ;
}
RemoveEffects ( EF_DIMLIGHT ) ;
EmitSound ( " HL2Player.FlashLightOff " ) ;
variant_t flashlightoff ;
flashlightoff . SetFloat ( m_HL2Local . m_flSuitPower / 100.0f ) ;
FirePlayerProxyOutput ( " OnFlashlightOff " , flashlightoff , this , this ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
# define FLASHLIGHT_RANGE Square(600)
bool CHL2_Player : : IsIlluminatedByFlashlight ( CBaseEntity * pEntity , float * flReturnDot )
{
if ( ! FlashlightIsOn ( ) )
return false ;
if ( pEntity - > Classify ( ) = = CLASS_BARNACLE & & pEntity - > GetEnemy ( ) = = this )
{
// As long as my flashlight is on, the barnacle that's pulling me in is considered illuminated.
// This is because players often shine their flashlights at Alyx when they are in a barnacle's
// grasp, and wonder why Alyx isn't helping. Alyx isn't helping because the light isn't pointed
// at the barnacle. This will allow Alyx to see the barnacle no matter which way the light is pointed.
return true ;
}
// Within 50 feet?
float flDistSqr = GetAbsOrigin ( ) . DistToSqr ( pEntity - > GetAbsOrigin ( ) ) ;
if ( flDistSqr > FLASHLIGHT_RANGE )
return false ;
// Within 45 degrees?
Vector vecSpot = pEntity - > WorldSpaceCenter ( ) ;
Vector los ;
// If the eyeposition is too close, move it back. Solves problems
// caused by the player being too close the target.
if ( flDistSqr < ( 128 * 128 ) )
{
Vector vecForward ;
EyeVectors ( & vecForward ) ;
Vector vecMovedEyePos = EyePosition ( ) - ( vecForward * 128 ) ;
los = ( vecSpot - vecMovedEyePos ) ;
}
else
{
los = ( vecSpot - EyePosition ( ) ) ;
}
VectorNormalize ( los ) ;
Vector facingDir = EyeDirection3D ( ) ;
float flDot = DotProduct ( los , facingDir ) ;
if ( flReturnDot )
{
* flReturnDot = flDot ;
}
if ( flDot < 0.92387f )
return false ;
if ( ! FVisible ( pEntity ) )
return false ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: Let NPCs know when the flashlight is trained on them
//-----------------------------------------------------------------------------
void CHL2_Player : : CheckFlashlight ( void )
{
if ( ! FlashlightIsOn ( ) )
return ;
if ( m_flNextFlashlightCheckTime > gpGlobals - > curtime )
return ;
m_flNextFlashlightCheckTime = gpGlobals - > curtime + FLASHLIGHT_NPC_CHECK_INTERVAL ;
// Loop through NPCs looking for illuminated ones
for ( int i = 0 ; i < g_AI_Manager . NumAIs ( ) ; i + + )
{
CAI_BaseNPC * pNPC = g_AI_Manager . AccessAIs ( ) [ i ] ;
float flDot ;
if ( IsIlluminatedByFlashlight ( pNPC , & flDot ) )
{
pNPC - > PlayerHasIlluminatedNPC ( this , flDot ) ;
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : SetPlayerUnderwater ( bool state )
{
if ( state )
{
SuitPower_AddDevice ( SuitDeviceBreather ) ;
}
else
{
SuitPower_RemoveDevice ( SuitDeviceBreather ) ;
}
BaseClass : : SetPlayerUnderwater ( state ) ;
}
//-----------------------------------------------------------------------------
bool CHL2_Player : : PassesDamageFilter ( const CTakeDamageInfo & info )
{
CBaseEntity * pAttacker = info . GetAttacker ( ) ;
if ( pAttacker & & pAttacker - > MyNPCPointer ( ) & & pAttacker - > MyNPCPointer ( ) - > IsPlayerAlly ( ) )
{
return false ;
}
if ( m_hPlayerProxy & & ! m_hPlayerProxy - > PassesDamageFilter ( info ) )
{
return false ;
}
return BaseClass : : PassesDamageFilter ( info ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2_Player : : SetFlashlightEnabled ( bool bState )
{
m_bFlashlightDisabled = ! bState ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : InputDisableFlashlight ( inputdata_t & inputdata )
{
if ( FlashlightIsOn ( ) )
FlashlightTurnOff ( ) ;
SetFlashlightEnabled ( false ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : InputEnableFlashlight ( inputdata_t & inputdata )
{
SetFlashlightEnabled ( true ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Prevent the player from taking fall damage for [n] seconds, but
// reset back to taking fall damage after the first impact (so players will be
// hurt if they bounce off what they hit). This is the original behavior.
//-----------------------------------------------------------------------------
void CHL2_Player : : InputIgnoreFallDamage ( inputdata_t & inputdata )
{
float timeToIgnore = inputdata . value . Float ( ) ;
if ( timeToIgnore < = 0.0 )
timeToIgnore = TIME_IGNORE_FALL_DAMAGE ;
m_flTimeIgnoreFallDamage = gpGlobals - > curtime + timeToIgnore ;
m_bIgnoreFallDamageResetAfterImpact = true ;
}
//-----------------------------------------------------------------------------
// Purpose: Absolutely prevent the player from taking fall damage for [n] seconds.
//-----------------------------------------------------------------------------
void CHL2_Player : : InputIgnoreFallDamageWithoutReset ( inputdata_t & inputdata )
{
float timeToIgnore = inputdata . value . Float ( ) ;
if ( timeToIgnore < = 0.0 )
timeToIgnore = TIME_IGNORE_FALL_DAMAGE ;
m_flTimeIgnoreFallDamage = gpGlobals - > curtime + timeToIgnore ;
m_bIgnoreFallDamageResetAfterImpact = false ;
}
//-----------------------------------------------------------------------------
// Purpose: Notification of a player's npc ally in the players squad being killed
//-----------------------------------------------------------------------------
void CHL2_Player : : OnSquadMemberKilled ( inputdata_t & data )
{
// send a message to the client, to notify the hud of the loss
CSingleUserRecipientFilter user ( this ) ;
user . MakeReliable ( ) ;
UserMessageBegin ( user , " SquadMemberDied " ) ;
MessageEnd ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2_Player : : NotifyFriendsOfDamage ( CBaseEntity * pAttackerEntity )
{
CAI_BaseNPC * pAttacker = pAttackerEntity - > MyNPCPointer ( ) ;
if ( pAttacker )
{
const Vector & origin = GetAbsOrigin ( ) ;
for ( int i = 0 ; i < g_AI_Manager . NumAIs ( ) ; i + + )
{
const float NEAR_Z = 12 * 12 ;
const float NEAR_XY_SQ = Square ( 50 * 12 ) ;
CAI_BaseNPC * pNpc = g_AI_Manager . AccessAIs ( ) [ i ] ;
if ( pNpc - > IsPlayerAlly ( ) )
{
const Vector & originNpc = pNpc - > GetAbsOrigin ( ) ;
if ( fabsf ( originNpc . z - origin . z ) < NEAR_Z )
{
if ( ( originNpc . AsVector2D ( ) - origin . AsVector2D ( ) ) . LengthSqr ( ) < NEAR_XY_SQ )
{
pNpc - > OnFriendDamaged ( this , pAttacker ) ;
}
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
ConVar test_massive_dmg ( " test_massive_dmg " , " 30 " ) ;
ConVar test_massive_dmg_clip ( " test_massive_dmg_clip " , " 0.5 " ) ;
int CHL2_Player : : OnTakeDamage ( const CTakeDamageInfo & info )
{
if ( GlobalEntity_GetState ( " gordon_invulnerable " ) = = GLOBAL_ON )
return 0 ;
// ignore fall damage if instructed to do so by input
if ( ( info . GetDamageType ( ) & DMG_FALL ) & & m_flTimeIgnoreFallDamage > gpGlobals - > curtime )
{
// usually, we will reset the input flag after the first impact. However there is another input that
// prevents this behavior.
if ( m_bIgnoreFallDamageResetAfterImpact )
{
m_flTimeIgnoreFallDamage = 0 ;
}
return 0 ;
}
if ( info . GetDamageType ( ) & DMG_BLAST_SURFACE )
{
if ( GetWaterLevel ( ) > 2 )
{
// Don't take blast damage from anything above the surface.
if ( info . GetInflictor ( ) - > GetWaterLevel ( ) = = 0 )
{
return 0 ;
}
}
}
if ( info . GetDamage ( ) > 0.0f )
{
m_flLastDamageTime = gpGlobals - > curtime ;
if ( info . GetAttacker ( ) )
NotifyFriendsOfDamage ( info . GetAttacker ( ) ) ;
}
// Modify the amount of damage the player takes, based on skill.
CTakeDamageInfo playerDamage = info ;
// Should we run this damage through the skill level adjustment?
bool bAdjustForSkillLevel = true ;
if ( info . GetDamageType ( ) = = DMG_GENERIC & & info . GetAttacker ( ) = = this & & info . GetInflictor ( ) = = this )
{
// Only do a skill level adjustment if the player isn't his own attacker AND inflictor.
// This prevents damage from SetHealth() inputs from being adjusted for skill level.
bAdjustForSkillLevel = false ;
}
if ( GetVehicleEntity ( ) ! = NULL & & GlobalEntity_GetState ( " gordon_protect_driver " ) = = GLOBAL_ON )
{
if ( playerDamage . GetDamage ( ) > test_massive_dmg . GetFloat ( ) & & playerDamage . GetInflictor ( ) = = GetVehicleEntity ( ) & & ( playerDamage . GetDamageType ( ) & DMG_CRUSH ) )
{
playerDamage . ScaleDamage ( test_massive_dmg_clip . GetFloat ( ) / playerDamage . GetDamage ( ) ) ;
}
}
if ( bAdjustForSkillLevel )
{
playerDamage . AdjustPlayerDamageTakenForSkillLevel ( ) ;
}
gamestats - > Event_PlayerDamage ( this , info ) ;
return BaseClass : : OnTakeDamage ( playerDamage ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &info -
//-----------------------------------------------------------------------------
int CHL2_Player : : OnTakeDamage_Alive ( const CTakeDamageInfo & info )
{
// Drown
if ( info . GetDamageType ( ) & DMG_DROWN )
{
if ( m_idrowndmg = = m_idrownrestored )
{
EmitSound ( " Player.DrownStart " ) ;
}
else
{
EmitSound ( " Player.DrownContinue " ) ;
}
}
// Burnt
if ( info . GetDamageType ( ) & DMG_BURN )
{
EmitSound ( " HL2Player.BurnPain " ) ;
}
if ( ( info . GetDamageType ( ) & DMG_SLASH ) & & hl2_episodic . GetBool ( ) )
{
if ( m_afPhysicsFlags & PFLAG_USING )
{
// Stop the player using a rotating button for a short time if hit by a creature's melee attack.
// This is for the antlion burrow-corking training in EP1 (sjb).
SuspendUse ( 0.5f ) ;
}
}
// Call the base class implementation
return BaseClass : : OnTakeDamage_Alive ( info ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : OnDamagedByExplosion ( const CTakeDamageInfo & info )
{
if ( info . GetInflictor ( ) & & info . GetInflictor ( ) - > ClassMatches ( " mortarshell " ) )
{
// No ear ringing for mortar
UTIL_ScreenShake ( info . GetInflictor ( ) - > GetAbsOrigin ( ) , 4.0 , 1.0 , 0.5 , 1000 , SHAKE_START , false ) ;
return ;
}
BaseClass : : OnDamagedByExplosion ( info ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CHL2_Player : : ShouldShootMissTarget ( CBaseCombatCharacter * pAttacker )
{
if ( gpGlobals - > curtime > m_flTargetFindTime )
{
// Put this off into the future again.
m_flTargetFindTime = gpGlobals - > curtime + random - > RandomFloat ( 3 , 5 ) ;
return true ;
}
return false ;
}
//-----------------------------------------------------------------------------
// Purpose: Notifies Alyx that player has put a combine ball into a socket so she can comment on it.
// Input : pCombineBall - ball the was socketed
//-----------------------------------------------------------------------------
void CHL2_Player : : CombineBallSocketed ( CPropCombineBall * pCombineBall )
{
# ifdef HL2_EPISODIC
CNPC_Alyx * pAlyx = CNPC_Alyx : : GetAlyx ( ) ;
if ( pAlyx )
{
pAlyx - > CombineBallSocketed ( pCombineBall - > NumBounces ( ) ) ;
}
# endif
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : Event_KilledOther ( CBaseEntity * pVictim , const CTakeDamageInfo & info )
{
BaseClass : : Event_KilledOther ( pVictim , info ) ;
# ifdef HL2_EPISODIC
CAI_BaseNPC * * ppAIs = g_AI_Manager . AccessAIs ( ) ;
for ( int i = 0 ; i < g_AI_Manager . NumAIs ( ) ; i + + )
{
if ( ppAIs [ i ] & & ppAIs [ i ] - > IRelationType ( this ) = = D_LI )
{
ppAIs [ i ] - > OnPlayerKilledOther ( pVictim , info ) ;
}
}
# endif
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : Event_Killed ( const CTakeDamageInfo & info )
{
BaseClass : : Event_Killed ( info ) ;
FirePlayerProxyOutput ( " PlayerDied " , variant_t ( ) , this , this ) ;
NotifyScriptsOfDeath ( ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : NotifyScriptsOfDeath ( void )
{
CBaseEntity * pEnt = gEntList . FindEntityByClassname ( NULL , " scripted_sequence " ) ;
while ( pEnt )
{
variant_t emptyVariant ;
pEnt - > AcceptInput ( " ScriptPlayerDeath " , NULL , NULL , emptyVariant , 0 ) ;
pEnt = gEntList . FindEntityByClassname ( pEnt , " scripted_sequence " ) ;
}
pEnt = gEntList . FindEntityByClassname ( NULL , " logic_choreographed_scene " ) ;
while ( pEnt )
{
variant_t emptyVariant ;
pEnt - > AcceptInput ( " ScriptPlayerDeath " , NULL , NULL , emptyVariant , 0 ) ;
pEnt = gEntList . FindEntityByClassname ( pEnt , " logic_choreographed_scene " ) ;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2_Player : : GetAutoaimVector ( autoaim_params_t & params )
{
BaseClass : : GetAutoaimVector ( params ) ;
if ( IsX360 ( ) )
{
if ( IsInAVehicle ( ) )
{
if ( m_hLockedAutoAimEntity & & m_hLockedAutoAimEntity - > IsAlive ( ) & & ShouldKeepLockedAutoaimTarget ( m_hLockedAutoAimEntity ) )
{
if ( params . m_hAutoAimEntity & & params . m_hAutoAimEntity ! = m_hLockedAutoAimEntity )
{
// Autoaim has picked a new target. Switch.
m_hLockedAutoAimEntity = params . m_hAutoAimEntity ;
}
// Ignore autoaim and just keep aiming at this target.
params . m_hAutoAimEntity = m_hLockedAutoAimEntity ;
Vector vecTarget = m_hLockedAutoAimEntity - > BodyTarget ( EyePosition ( ) , false ) ;
Vector vecDir = vecTarget - EyePosition ( ) ;
VectorNormalize ( vecDir ) ;
params . m_vecAutoAimDir = vecDir ;
params . m_vecAutoAimPoint = vecTarget ;
return ;
}
else
{
m_hLockedAutoAimEntity = NULL ;
}
}
// If the player manually gets his crosshair onto a target, make that target sticky
if ( params . m_fScale ! = AUTOAIM_SCALE_DIRECT_ONLY )
{
// Only affect this for 'real' queries
//if( params.m_hAutoAimEntity && params.m_bOnTargetNatural )
if ( params . m_hAutoAimEntity )
{
// Turn on sticky.
m_HL2Local . m_bStickyAutoAim = true ;
if ( IsInAVehicle ( ) )
{
m_hLockedAutoAimEntity = params . m_hAutoAimEntity ;
}
}
else if ( ! params . m_hAutoAimEntity )
{
// Turn off sticky only if there's no target at all.
m_HL2Local . m_bStickyAutoAim = false ;
m_hLockedAutoAimEntity = NULL ;
}
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CHL2_Player : : ShouldKeepLockedAutoaimTarget ( EHANDLE hLockedTarget )
{
Vector vecLooking ;
Vector vecToTarget ;
vecToTarget = hLockedTarget - > WorldSpaceCenter ( ) - EyePosition ( ) ;
float flDist = vecToTarget . Length2D ( ) ;
VectorNormalize ( vecToTarget ) ;
if ( flDist > autoaim_max_dist . GetFloat ( ) )
return false ;
float flDot ;
vecLooking = EyeDirection3D ( ) ;
flDot = DotProduct ( vecLooking , vecToTarget ) ;
if ( flDot < autoaim_unlock_target . GetFloat ( ) )
return false ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : iCount -
// iAmmoIndex -
// bSuppressSound -
// Output : int
//-----------------------------------------------------------------------------
int CHL2_Player : : GiveAmmo ( int nCount , int nAmmoIndex , bool bSuppressSound )
{
// Don't try to give the player invalid ammo indices.
if ( nAmmoIndex < 0 )
return 0 ;
bool bCheckAutoSwitch = false ;
if ( ! HasAnyAmmoOfType ( nAmmoIndex ) )
{
bCheckAutoSwitch = true ;
}
int nAdd = BaseClass : : GiveAmmo ( nCount , nAmmoIndex , bSuppressSound ) ;
if ( nCount > 0 & & nAdd = = 0 )
{
// we've been denied the pickup, display a hud icon to show that
CSingleUserRecipientFilter user ( this ) ;
user . MakeReliable ( ) ;
UserMessageBegin ( user , " AmmoDenied " ) ;
WRITE_SHORT ( nAmmoIndex ) ;
MessageEnd ( ) ;
}
//
// If I was dry on ammo for my best weapon and justed picked up ammo for it,
// autoswitch to my best weapon now.
//
if ( bCheckAutoSwitch )
{
CBaseCombatWeapon * pWeapon = g_pGameRules - > GetNextBestWeapon ( this , GetActiveWeapon ( ) ) ;
if ( pWeapon & & pWeapon - > GetPrimaryAmmoType ( ) = = nAmmoIndex )
{
SwitchToNextBestWeapon ( GetActiveWeapon ( ) ) ;
}
}
return nAdd ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CHL2_Player : : Weapon_CanUse ( CBaseCombatWeapon * pWeapon )
{
# ifndef HL2MP
if ( pWeapon - > ClassMatches ( " weapon_stunstick " ) )
{
if ( ApplyBattery ( 0.5 ) )
UTIL_Remove ( pWeapon ) ;
return false ;
}
# endif
return BaseClass : : Weapon_CanUse ( pWeapon ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pWeapon -
//-----------------------------------------------------------------------------
void CHL2_Player : : Weapon_Equip ( CBaseCombatWeapon * pWeapon )
{
# if HL2_SINGLE_PRIMARY_WEAPON_MODE
if ( pWeapon - > GetSlot ( ) = = WEAPON_PRIMARY_SLOT )
{
Weapon_DropSlot ( WEAPON_PRIMARY_SLOT ) ;
}
# endif
if ( GetActiveWeapon ( ) = = NULL )
{
m_HL2Local . m_bWeaponLowered = false ;
}
BaseClass : : Weapon_Equip ( pWeapon ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Player reacts to bumping a weapon.
// Input : pWeapon - the weapon that the player bumped into.
// Output : Returns true if player picked up the weapon
//-----------------------------------------------------------------------------
bool CHL2_Player : : BumpWeapon ( CBaseCombatWeapon * pWeapon )
{
# if HL2_SINGLE_PRIMARY_WEAPON_MODE
CBaseCombatCharacter * pOwner = pWeapon - > GetOwner ( ) ;
// Can I have this weapon type?
if ( pOwner | | ! Weapon_CanUse ( pWeapon ) | | ! g_pGameRules - > CanHavePlayerItem ( this , pWeapon ) )
{
if ( gEvilImpulse101 )
{
UTIL_Remove ( pWeapon ) ;
}
return false ;
}
// ----------------------------------------
// If I already have it just take the ammo
// ----------------------------------------
if ( Weapon_OwnsThisType ( pWeapon - > GetClassname ( ) , pWeapon - > GetSubType ( ) ) )
{
//Only remove the weapon if we attained ammo from it
if ( Weapon_EquipAmmoOnly ( pWeapon ) = = false )
return false ;
// Only remove me if I have no ammo left
// Can't just check HasAnyAmmo because if I don't use clips, I want to be removed,
if ( pWeapon - > UsesClipsForAmmo1 ( ) & & pWeapon - > HasPrimaryAmmo ( ) )
return false ;
UTIL_Remove ( pWeapon ) ;
return false ;
}
// -------------------------
// Otherwise take the weapon
// -------------------------
else
{
//Make sure we're not trying to take a new weapon type we already have
if ( Weapon_SlotOccupied ( pWeapon ) )
{
CBaseCombatWeapon * pActiveWeapon = Weapon_GetSlot ( WEAPON_PRIMARY_SLOT ) ;
if ( pActiveWeapon ! = NULL & & pActiveWeapon - > HasAnyAmmo ( ) = = false & & Weapon_CanSwitchTo ( pWeapon ) )
{
Weapon_Equip ( pWeapon ) ;
return true ;
}
//Attempt to take ammo if this is the gun we're holding already
if ( Weapon_OwnsThisType ( pWeapon - > GetClassname ( ) , pWeapon - > GetSubType ( ) ) )
{
Weapon_EquipAmmoOnly ( pWeapon ) ;
}
return false ;
}
pWeapon - > CheckRespawn ( ) ;
pWeapon - > AddSolidFlags ( FSOLID_NOT_SOLID ) ;
pWeapon - > AddEffects ( EF_NODRAW ) ;
Weapon_Equip ( pWeapon ) ;
EmitSound ( " HL2Player.PickupWeapon " ) ;
return true ;
}
# else
return BaseClass : : BumpWeapon ( pWeapon ) ;
# endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *cmd -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHL2_Player : : ClientCommand ( const CCommand & args )
{
# if HL2_SINGLE_PRIMARY_WEAPON_MODE
//Drop primary weapon
if ( ! Q_stricmp ( args [ 0 ] , " DropPrimary " ) )
{
Weapon_DropSlot ( WEAPON_PRIMARY_SLOT ) ;
return true ;
}
# endif
if ( ! Q_stricmp ( args [ 0 ] , " emit " ) )
{
CSingleUserRecipientFilter filter ( this ) ;
if ( args . ArgC ( ) > 1 )
{
EmitSound ( filter , entindex ( ) , args [ 1 ] ) ;
}
else
{
EmitSound ( filter , entindex ( ) , " Test.Sound " ) ;
}
return true ;
}
return BaseClass : : ClientCommand ( args ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : void CBasePlayer::PlayerUse
//-----------------------------------------------------------------------------
void CHL2_Player : : PlayerUse ( void )
{
// Was use pressed or released?
if ( ! ( ( m_nButtons | m_afButtonPressed | m_afButtonReleased ) & IN_USE ) )
return ;
if ( m_afButtonPressed & IN_USE )
{
// Currently using a latched entity?
if ( ClearUseEntity ( ) )
{
return ;
}
else
{
if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
{
m_afPhysicsFlags & = ~ PFLAG_DIROVERRIDE ;
m_iTrain = TRAIN_NEW | TRAIN_OFF ;
return ;
}
else
{ // Start controlling the train!
CBaseEntity * pTrain = GetGroundEntity ( ) ;
if ( pTrain & & ! ( m_nButtons & IN_JUMP ) & & ( GetFlags ( ) & FL_ONGROUND ) & & ( pTrain - > ObjectCaps ( ) & FCAP_DIRECTIONAL_USE ) & & pTrain - > OnControls ( this ) )
{
m_afPhysicsFlags | = PFLAG_DIROVERRIDE ;
m_iTrain = TrainSpeed ( pTrain - > m_flSpeed , ( ( CFuncTrackTrain * ) pTrain ) - > GetMaxSpeed ( ) ) ;
m_iTrain | = TRAIN_NEW ;
EmitSound ( " HL2Player.TrainUse " ) ;
return ;
}
}
}
// Tracker 3926: We can't +USE something if we're climbing a ladder
if ( GetMoveType ( ) = = MOVETYPE_LADDER )
{
return ;
}
}
if ( m_flTimeUseSuspended > gpGlobals - > curtime )
{
// Something has temporarily stopped us being able to USE things.
// Obviously, this should be used very carefully.(sjb)
return ;
}
CBaseEntity * pUseEntity = FindUseEntity ( ) ;
bool usedSomething = false ;
// Found an object
if ( pUseEntity )
{
//!!!UNDONE: traceline here to prevent +USEing buttons through walls
int caps = pUseEntity - > ObjectCaps ( ) ;
variant_t emptyVariant ;
if ( m_afButtonPressed & IN_USE )
{
// Robin: Don't play sounds for NPCs, because NPCs will allow respond with speech.
if ( ! pUseEntity - > MyNPCPointer ( ) )
{
EmitSound ( " HL2Player.Use " ) ;
}
}
if ( ( ( m_nButtons & IN_USE ) & & ( caps & FCAP_CONTINUOUS_USE ) ) | |
( ( m_afButtonPressed & IN_USE ) & & ( caps & ( FCAP_IMPULSE_USE | FCAP_ONOFF_USE ) ) ) )
{
if ( caps & FCAP_CONTINUOUS_USE )
m_afPhysicsFlags | = PFLAG_USING ;
pUseEntity - > AcceptInput ( " Use " , this , this , emptyVariant , USE_TOGGLE ) ;
usedSomething = true ;
}
// UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away
else if ( ( m_afButtonReleased & IN_USE ) & & ( pUseEntity - > ObjectCaps ( ) & FCAP_ONOFF_USE ) ) // BUGBUG This is an "off" use
{
pUseEntity - > AcceptInput ( " Use " , this , this , emptyVariant , USE_TOGGLE ) ;
usedSomething = true ;
}
# if HL2_SINGLE_PRIMARY_WEAPON_MODE
//Check for weapon pick-up
if ( m_afButtonPressed & IN_USE )
{
CBaseCombatWeapon * pWeapon = dynamic_cast < CBaseCombatWeapon * > ( pUseEntity ) ;
if ( ( pWeapon ! = NULL ) & & ( Weapon_CanSwitchTo ( pWeapon ) ) )
{
//Try to take ammo or swap the weapon
if ( Weapon_OwnsThisType ( pWeapon - > GetClassname ( ) , pWeapon - > GetSubType ( ) ) )
{
Weapon_EquipAmmoOnly ( pWeapon ) ;
}
else
{
Weapon_DropSlot ( pWeapon - > GetSlot ( ) ) ;
Weapon_Equip ( pWeapon ) ;
}
usedSomething = true ;
}
}
# endif
}
else if ( m_afButtonPressed & IN_USE )
{
// Signal that we want to play the deny sound, unless the user is +USEing on a ladder!
// The sound is emitted in ItemPostFrame, since that occurs after GameMovement::ProcessMove which
// lets the ladder code unset this flag.
m_bPlayUseDenySound = true ;
}
// Debounce the use key
if ( usedSomething & & pUseEntity )
{
m_Local . m_nOldButtons | = IN_USE ;
m_afButtonPressed & = ~ IN_USE ;
}
}
ConVar sv_show_crosshair_target ( " sv_show_crosshair_target " , " 0 " ) ;
//-----------------------------------------------------------------------------
// Purpose: Updates the posture of the weapon from lowered to ready
//-----------------------------------------------------------------------------
void CHL2_Player : : UpdateWeaponPosture ( void )
{
CBaseCombatWeapon * pWeapon = dynamic_cast < CBaseCombatWeapon * > ( GetActiveWeapon ( ) ) ;
if ( pWeapon & & m_LowerWeaponTimer . Expired ( ) & & pWeapon - > CanLower ( ) )
{
m_LowerWeaponTimer . Set ( .3 ) ;
VPROF ( " CHL2_Player::UpdateWeaponPosture-CheckLower " ) ;
Vector vecAim = BaseClass : : GetAutoaimVector ( AUTOAIM_SCALE_DIRECT_ONLY ) ;
const float CHECK_FRIENDLY_RANGE = 50 * 12 ;
trace_t tr ;
UTIL_TraceLine ( EyePosition ( ) , EyePosition ( ) + vecAim * CHECK_FRIENDLY_RANGE , MASK_SHOT , this , COLLISION_GROUP_NONE , & tr ) ;
CBaseEntity * aimTarget = tr . m_pEnt ;
//If we're over something
if ( aimTarget & & ! tr . DidHitWorld ( ) )
{
if ( ! aimTarget - > IsNPC ( ) | | aimTarget - > MyNPCPointer ( ) - > GetState ( ) ! = NPC_STATE_COMBAT )
{
Disposition_t dis = IRelationType ( aimTarget ) ;
//Debug info for seeing what an object "cons" as
if ( sv_show_crosshair_target . GetBool ( ) )
{
int text_offset = BaseClass : : DrawDebugTextOverlays ( ) ;
char tempstr [ 255 ] ;
switch ( dis )
{
case D_LI :
Q_snprintf ( tempstr , sizeof ( tempstr ) , " Disposition: Like " ) ;
break ;
case D_HT :
Q_snprintf ( tempstr , sizeof ( tempstr ) , " Disposition: Hate " ) ;
break ;
case D_FR :
Q_snprintf ( tempstr , sizeof ( tempstr ) , " Disposition: Fear " ) ;
break ;
case D_NU :
Q_snprintf ( tempstr , sizeof ( tempstr ) , " Disposition: Neutral " ) ;
break ;
default :
case D_ER :
Q_snprintf ( tempstr , sizeof ( tempstr ) , " Disposition: !!!ERROR!!! " ) ;
break ;
}
//Draw the text
NDebugOverlay : : EntityText ( aimTarget - > entindex ( ) , text_offset , tempstr , 0 ) ;
}
//See if we hates it
if ( dis = = D_LI )
{
//We're over a friendly, drop our weapon
if ( Weapon_Lower ( ) = = false )
{
//FIXME: We couldn't lower our weapon!
}
return ;
}
}
}
if ( Weapon_Ready ( ) = = false )
{
//FIXME: We couldn't raise our weapon!
}
}
if ( g_pGameRules - > GetAutoAimMode ( ) ! = AUTOAIM_NONE )
{
if ( ! pWeapon )
{
// This tells the client to draw no crosshair
m_HL2Local . m_bWeaponLowered = true ;
return ;
}
else
{
if ( ! pWeapon - > CanLower ( ) & & m_HL2Local . m_bWeaponLowered )
m_HL2Local . m_bWeaponLowered = false ;
}
if ( ! m_AutoaimTimer . Expired ( ) )
return ;
m_AutoaimTimer . Set ( .1 ) ;
VPROF ( " hl2_x360_aiming " ) ;
// Call the autoaim code to update the local player data, which allows the client to update.
autoaim_params_t params ;
params . m_vecAutoAimPoint . Init ( ) ;
params . m_vecAutoAimDir . Init ( ) ;
params . m_fScale = AUTOAIM_SCALE_DEFAULT ;
params . m_fMaxDist = autoaim_max_dist . GetFloat ( ) ;
GetAutoaimVector ( params ) ;
m_HL2Local . m_hAutoAimTarget . Set ( params . m_hAutoAimEntity ) ;
m_HL2Local . m_vecAutoAimPoint . Set ( params . m_vecAutoAimPoint ) ;
m_HL2Local . m_bAutoAimTarget = ( params . m_bAutoAimAssisting | | params . m_bOnTargetNatural ) ;
return ;
}
else
{
// Make sure there's no residual autoaim target if the user changes the xbox_aiming convar on the fly.
m_HL2Local . m_hAutoAimTarget . Set ( NULL ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Lowers the weapon posture (for hovering over friendlies)
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHL2_Player : : Weapon_Lower ( void )
{
VPROF ( " CHL2_Player::Weapon_Lower " ) ;
// Already lowered?
if ( m_HL2Local . m_bWeaponLowered )
return true ;
m_HL2Local . m_bWeaponLowered = true ;
CBaseCombatWeapon * pWeapon = dynamic_cast < CBaseCombatWeapon * > ( GetActiveWeapon ( ) ) ;
if ( pWeapon = = NULL )
return false ;
return pWeapon - > Lower ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the weapon posture to normal
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHL2_Player : : Weapon_Ready ( void )
{
VPROF ( " CHL2_Player::Weapon_Ready " ) ;
// Already ready?
if ( m_HL2Local . m_bWeaponLowered = = false )
return true ;
m_HL2Local . m_bWeaponLowered = false ;
CBaseCombatWeapon * pWeapon = dynamic_cast < CBaseCombatWeapon * > ( GetActiveWeapon ( ) ) ;
if ( pWeapon = = NULL )
return false ;
return pWeapon - > Ready ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not we can switch to the given weapon.
// Input : pWeapon -
//-----------------------------------------------------------------------------
bool CHL2_Player : : Weapon_CanSwitchTo ( CBaseCombatWeapon * pWeapon )
{
CBasePlayer * pPlayer = ( CBasePlayer * ) this ;
# if !defined( CLIENT_DLL )
IServerVehicle * pVehicle = pPlayer - > GetVehicle ( ) ;
# else
IClientVehicle * pVehicle = pPlayer - > GetVehicle ( ) ;
# endif
if ( pVehicle & & ! pPlayer - > UsingStandardWeaponsInVehicle ( ) )
return false ;
if ( ! pWeapon - > HasAnyAmmo ( ) & & ! GetAmmoCount ( pWeapon - > m_iPrimaryAmmoType ) )
return false ;
if ( ! pWeapon - > CanDeploy ( ) )
return false ;
if ( GetActiveWeapon ( ) )
{
if ( PhysCannonGetHeldEntity ( GetActiveWeapon ( ) ) = = pWeapon & &
Weapon_OwnsThisType ( pWeapon - > GetClassname ( ) , pWeapon - > GetSubType ( ) ) )
{
return true ;
}
if ( ! GetActiveWeapon ( ) - > CanHolster ( ) )
return false ;
}
return true ;
}
void CHL2_Player : : PickupObject ( CBaseEntity * pObject , bool bLimitMassAndSize )
{
// can't pick up what you're standing on
if ( GetGroundEntity ( ) = = pObject )
return ;
if ( bLimitMassAndSize = = true )
{
if ( CBasePlayer : : CanPickupObject ( pObject , 35 , 128 ) = = false )
return ;
}
// Can't be picked up if NPCs are on me
if ( pObject - > HasNPCsOnIt ( ) )
return ;
PlayerPickupObject ( this , pObject ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : CBaseEntity
//-----------------------------------------------------------------------------
bool CHL2_Player : : IsHoldingEntity ( CBaseEntity * pEnt )
{
return PlayerPickupControllerIsHoldingEntity ( m_hUseEntity , pEnt ) ;
}
float CHL2_Player : : GetHeldObjectMass ( IPhysicsObject * pHeldObject )
{
float mass = PlayerPickupGetHeldObjectMass ( m_hUseEntity , pHeldObject ) ;
if ( mass = = 0.0f )
{
mass = PhysCannonGetHeldObjectMass ( GetActiveWeapon ( ) , pHeldObject ) ;
}
return mass ;
}
//-----------------------------------------------------------------------------
// Purpose: Force the player to drop any physics objects he's carrying
//-----------------------------------------------------------------------------
void CHL2_Player : : ForceDropOfCarriedPhysObjects ( CBaseEntity * pOnlyIfHoldingThis )
{
if ( PhysIsInCallback ( ) )
{
variant_t value ;
g_EventQueue . AddEvent ( this , " ForceDropPhysObjects " , value , 0.01f , pOnlyIfHoldingThis , this ) ;
return ;
}
# ifdef HL2_EPISODIC
if ( hl2_episodic . GetBool ( ) )
{
CBaseEntity * pHeldEntity = PhysCannonGetHeldEntity ( GetActiveWeapon ( ) ) ;
if ( pHeldEntity & & pHeldEntity - > ClassMatches ( " grenade_helicopter " ) )
{
return ;
}
}
# endif
// Drop any objects being handheld.
ClearUseEntity ( ) ;
// Then force the physcannon to drop anything it's holding, if it's our active weapon
PhysCannonForceDrop ( GetActiveWeapon ( ) , NULL ) ;
}
void CHL2_Player : : InputForceDropPhysObjects ( inputdata_t & data )
{
ForceDropOfCarriedPhysObjects ( data . pActivator ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2_Player : : UpdateClientData ( void )
{
if ( m_DmgTake | | m_DmgSave | | m_bitsHUDDamage ! = m_bitsDamageType )
{
// Comes from inside me if not set
Vector damageOrigin = GetLocalOrigin ( ) ;
// send "damage" message
// causes screen to flash, and pain compass to show direction of damage
damageOrigin = m_DmgOrigin ;
// only send down damage type that have hud art
int iShowHudDamage = g_pGameRules - > Damage_GetShowOnHud ( ) ;
int visibleDamageBits = m_bitsDamageType & iShowHudDamage ;
m_DmgTake = clamp ( m_DmgTake , 0 , 255 ) ;
m_DmgSave = clamp ( m_DmgSave , 0 , 255 ) ;
// If we're poisoned, but it wasn't this frame, don't send the indicator
// Without this check, any damage that occured to the player while they were
// recovering from a poison bite would register as poisonous as well and flash
// the whole screen! -- jdw
if ( visibleDamageBits & DMG_POISON )
{
float flLastPoisonedDelta = gpGlobals - > curtime - m_tbdPrev ;
if ( flLastPoisonedDelta > 0.1f )
{
visibleDamageBits & = ~ DMG_POISON ;
}
}
CSingleUserRecipientFilter user ( this ) ;
user . MakeReliable ( ) ;
UserMessageBegin ( user , " Damage " ) ;
WRITE_BYTE ( m_DmgSave ) ;
WRITE_BYTE ( m_DmgTake ) ;
WRITE_LONG ( visibleDamageBits ) ;
WRITE_FLOAT ( damageOrigin . x ) ; //BUG: Should be fixed point (to hud) not floats
WRITE_FLOAT ( damageOrigin . y ) ; //BUG: However, the HUD does _not_ implement bitfield messages (yet)
WRITE_FLOAT ( damageOrigin . z ) ; //BUG: We use WRITE_VEC3COORD for everything else
MessageEnd ( ) ;
m_DmgTake = 0 ;
m_DmgSave = 0 ;
m_bitsHUDDamage = m_bitsDamageType ;
// Clear off non-time-based damage indicators
int iTimeBasedDamage = g_pGameRules - > Damage_GetTimeBased ( ) ;
m_bitsDamageType & = iTimeBasedDamage ;
}
// Update Flashlight
# ifdef HL2_EPISODIC
if ( Flashlight_UseLegacyVersion ( ) = = false )
{
if ( FlashlightIsOn ( ) & & sv_infinite_aux_power . GetBool ( ) = = false )
{
m_HL2Local . m_flFlashBattery - = FLASH_DRAIN_TIME * gpGlobals - > frametime ;
if ( m_HL2Local . m_flFlashBattery < 0.0f )
{
FlashlightTurnOff ( ) ;
m_HL2Local . m_flFlashBattery = 0.0f ;
}
}
else
{
m_HL2Local . m_flFlashBattery + = FLASH_CHARGE_TIME * gpGlobals - > frametime ;
if ( m_HL2Local . m_flFlashBattery > 100.0f )
{
m_HL2Local . m_flFlashBattery = 100.0f ;
}
}
}
else
{
m_HL2Local . m_flFlashBattery = - 1.0f ;
}
# endif // HL2_EPISODIC
BaseClass : : UpdateClientData ( ) ;
}
//---------------------------------------------------------
//---------------------------------------------------------
void CHL2_Player : : OnRestore ( )
{
BaseClass : : OnRestore ( ) ;
m_pPlayerAISquad = g_AI_SquadManager . FindCreateSquad ( AllocPooledString ( PLAYER_SQUADNAME ) ) ;
}
//---------------------------------------------------------
//---------------------------------------------------------
Vector CHL2_Player : : EyeDirection2D ( void )
{
Vector vecReturn = EyeDirection3D ( ) ;
vecReturn . z = 0 ;
vecReturn . AsVector2D ( ) . NormalizeInPlace ( ) ;
return vecReturn ;
}
//---------------------------------------------------------
//---------------------------------------------------------
Vector CHL2_Player : : EyeDirection3D ( void )
{
Vector vecForward ;
// Return the vehicle angles if we request them
if ( GetVehicle ( ) ! = NULL )
{
CacheVehicleView ( ) ;
EyeVectors ( & vecForward ) ;
return vecForward ;
}
AngleVectors ( EyeAngles ( ) , & vecForward ) ;
return vecForward ;
}
//---------------------------------------------------------
//---------------------------------------------------------
bool CHL2_Player : : Weapon_Switch ( CBaseCombatWeapon * pWeapon , int viewmodelindex )
{
MDLCACHE_CRITICAL_SECTION ( ) ;
// Recalculate proficiency!
SetCurrentWeaponProficiency ( CalcWeaponProficiency ( pWeapon ) ) ;
// Come out of suit zoom mode
if ( IsZooming ( ) )
{
StopZooming ( ) ;
}
return BaseClass : : Weapon_Switch ( pWeapon , viewmodelindex ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
WeaponProficiency_t CHL2_Player : : CalcWeaponProficiency ( CBaseCombatWeapon * pWeapon )
{
WeaponProficiency_t proficiency ;
proficiency = WEAPON_PROFICIENCY_PERFECT ;
if ( weapon_showproficiency . GetBool ( ) ! = 0 )
{
Msg ( " Player switched to %s, proficiency is %s \n " , pWeapon - > GetClassname ( ) , GetWeaponProficiencyName ( proficiency ) ) ;
}
return proficiency ;
}
//-----------------------------------------------------------------------------
// Purpose: override how single player rays hit the player
//-----------------------------------------------------------------------------
bool LineCircleIntersection (
const Vector2D & center ,
const float radius ,
const Vector2D & vLinePt ,
const Vector2D & vLineDir ,
float * fIntersection1 ,
float * fIntersection2 )
{
// Line = P + Vt
// Sphere = r (assume we've translated to origin)
// (P + Vt)^2 = r^2
// VVt^2 + 2PVt + (PP - r^2)
// Solve as quadratic: (-b +/- sqrt(b^2 - 4ac)) / 2a
// If (b^2 - 4ac) is < 0 there is no solution.
// If (b^2 - 4ac) is = 0 there is one solution (a case this function doesn't support).
// If (b^2 - 4ac) is > 0 there are two solutions.
Vector2D P ;
float a , b , c , sqr , insideSqr ;
// Translate circle to origin.
P [ 0 ] = vLinePt [ 0 ] - center [ 0 ] ;
P [ 1 ] = vLinePt [ 1 ] - center [ 1 ] ;
a = vLineDir . Dot ( vLineDir ) ;
b = 2.0f * P . Dot ( vLineDir ) ;
c = P . Dot ( P ) - ( radius * radius ) ;
insideSqr = b * b - 4 * a * c ;
if ( insideSqr < = 0.000001f )
return false ;
// Ok, two solutions.
sqr = ( float ) FastSqrt ( insideSqr ) ;
float denom = 1.0 / ( 2.0f * a ) ;
* fIntersection1 = ( - b - sqr ) * denom ;
* fIntersection2 = ( - b + sqr ) * denom ;
return true ;
}
static void Collision_ClearTrace ( const Vector & vecRayStart , const Vector & vecRayDelta , CBaseTrace * pTrace )
{
pTrace - > startpos = vecRayStart ;
pTrace - > endpos = vecRayStart ;
pTrace - > endpos + = vecRayDelta ;
pTrace - > startsolid = false ;
pTrace - > allsolid = false ;
pTrace - > fraction = 1.0f ;
pTrace - > contents = 0 ;
}
bool IntersectRayWithAACylinder ( const Ray_t & ray ,
const Vector & center , float radius , float height , CBaseTrace * pTrace )
{
Assert ( ray . m_IsRay ) ;
Collision_ClearTrace ( ray . m_Start , ray . m_Delta , pTrace ) ;
// First intersect the ray with the top + bottom planes
float halfHeight = height * 0.5 ;
// Handle parallel case
Vector vStart = ray . m_Start - center ;
Vector vEnd = vStart + ray . m_Delta ;
float flEnterFrac , flLeaveFrac ;
if ( FloatMakePositive ( ray . m_Delta . z ) < 1e-8 )
{
if ( ( vStart . z < - halfHeight ) | | ( vStart . z > halfHeight ) )
{
return false ; // no hit
}
flEnterFrac = 0.0f ; flLeaveFrac = 1.0f ;
}
else
{
// Clip the ray to the top and bottom of box
flEnterFrac = IntersectRayWithAAPlane ( vStart , vEnd , 2 , 1 , halfHeight ) ;
flLeaveFrac = IntersectRayWithAAPlane ( vStart , vEnd , 2 , 1 , - halfHeight ) ;
if ( flLeaveFrac < flEnterFrac )
{
float temp = flLeaveFrac ;
flLeaveFrac = flEnterFrac ;
flEnterFrac = temp ;
}
if ( flLeaveFrac < 0 | | flEnterFrac > 1 )
{
return false ;
}
}
// Intersect with circle
float flCircleEnterFrac , flCircleLeaveFrac ;
if ( ! LineCircleIntersection ( vec3_origin . AsVector2D ( ) , radius ,
vStart . AsVector2D ( ) , ray . m_Delta . AsVector2D ( ) , & flCircleEnterFrac , & flCircleLeaveFrac ) )
{
return false ; // no hit
}
Assert ( flCircleEnterFrac < = flCircleLeaveFrac ) ;
if ( flCircleLeaveFrac < 0 | | flCircleEnterFrac > 1 )
{
return false ;
}
if ( flEnterFrac < flCircleEnterFrac )
flEnterFrac = flCircleEnterFrac ;
if ( flLeaveFrac > flCircleLeaveFrac )
flLeaveFrac = flCircleLeaveFrac ;
if ( flLeaveFrac < flEnterFrac )
return false ;
VectorMA ( ray . m_Start , flEnterFrac , ray . m_Delta , pTrace - > endpos ) ;
pTrace - > fraction = flEnterFrac ;
pTrace - > contents = CONTENTS_SOLID ;
// Calculate the point on our center line where we're nearest the intersection point
Vector collisionCenter ;
CalcClosestPointOnLineSegment ( pTrace - > endpos , center + Vector ( 0 , 0 , halfHeight ) , center - Vector ( 0 , 0 , halfHeight ) , collisionCenter ) ;
// Our normal is the direction from that center point to the intersection point
pTrace - > plane . normal = pTrace - > endpos - collisionCenter ;
VectorNormalize ( pTrace - > plane . normal ) ;
return true ;
}
bool CHL2_Player : : TestHitboxes ( const Ray_t & ray , unsigned int fContentsMask , trace_t & tr )
{
if ( g_pGameRules - > IsMultiplayer ( ) )
{
return BaseClass : : TestHitboxes ( ray , fContentsMask , tr ) ;
}
else
{
Assert ( ray . m_IsRay ) ;
Vector mins , maxs ;
mins = WorldAlignMins ( ) ;
maxs = WorldAlignMaxs ( ) ;
if ( IntersectRayWithAACylinder ( ray , WorldSpaceCenter ( ) , maxs . x * PLAYER_HULL_REDUCTION , maxs . z - mins . z , & tr ) )
{
tr . hitbox = 0 ;
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
return false ;
mstudiohitboxset_t * set = pStudioHdr - > pHitboxSet ( m_nHitboxSet ) ;
if ( ! set | | ! set - > numhitboxes )
return false ;
mstudiobbox_t * pbox = set - > pHitbox ( tr . hitbox ) ;
mstudiobone_t * pBone = pStudioHdr - > pBone ( pbox - > bone ) ;
tr . surface . name = " **studio** " ;
tr . surface . flags = SURF_HITBOX ;
tr . surface . surfaceProps = physprops - > GetSurfaceIndex ( pBone - > pszSurfaceProp ( ) ) ;
}
return true ;
}
}
//---------------------------------------------------------
// Show the player's scaled down bbox that we use for
// bullet impacts.
//---------------------------------------------------------
void CHL2_Player : : DrawDebugGeometryOverlays ( void )
{
BaseClass : : DrawDebugGeometryOverlays ( ) ;
if ( m_debugOverlays & OVERLAY_BBOX_BIT )
{
Vector mins , maxs ;
mins = WorldAlignMins ( ) ;
maxs = WorldAlignMaxs ( ) ;
mins . x * = PLAYER_HULL_REDUCTION ;
mins . y * = PLAYER_HULL_REDUCTION ;
maxs . x * = PLAYER_HULL_REDUCTION ;
maxs . y * = PLAYER_HULL_REDUCTION ;
NDebugOverlay : : Box ( GetAbsOrigin ( ) , mins , maxs , 255 , 0 , 0 , 100 , 0 ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Helper to remove from ladder
//-----------------------------------------------------------------------------
void CHL2_Player : : ExitLadder ( )
{
if ( MOVETYPE_LADDER ! = GetMoveType ( ) )
return ;
SetMoveType ( MOVETYPE_WALK ) ;
SetMoveCollide ( MOVECOLLIDE_DEFAULT ) ;
// Remove from ladder
m_HL2Local . m_hLadder . Set ( NULL ) ;
}
surfacedata_t * CHL2_Player : : GetLadderSurface ( const Vector & origin )
{
extern const char * FuncLadder_GetSurfaceprops ( CBaseEntity * pLadderEntity ) ;
CBaseEntity * pLadder = m_HL2Local . m_hLadder . Get ( ) ;
if ( pLadder )
{
const char * pSurfaceprops = FuncLadder_GetSurfaceprops ( pLadder ) ;
// get ladder material from func_ladder
return physprops - > GetSurfaceData ( physprops - > GetSurfaceIndex ( pSurfaceprops ) ) ;
}
return BaseClass : : GetLadderSurface ( origin ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Queues up a use deny sound, played in ItemPostFrame.
//-----------------------------------------------------------------------------
void CHL2_Player : : PlayUseDenySound ( )
{
m_bPlayUseDenySound = true ;
}
void CHL2_Player : : ItemPostFrame ( )
{
BaseClass : : ItemPostFrame ( ) ;
if ( m_bPlayUseDenySound )
{
m_bPlayUseDenySound = false ;
EmitSound ( " HL2Player.UseDeny " ) ;
}
}
void CHL2_Player : : StartWaterDeathSounds ( void )
{
CPASAttenuationFilter filter ( this ) ;
if ( m_sndLeeches = = NULL )
{
m_sndLeeches = ( CSoundEnvelopeController : : GetController ( ) ) . SoundCreate ( filter , entindex ( ) , CHAN_STATIC , " coast.leech_bites_loop " , ATTN_NORM ) ;
}
if ( m_sndLeeches )
{
( CSoundEnvelopeController : : GetController ( ) ) . Play ( m_sndLeeches , 1.0f , 100 ) ;
}
if ( m_sndWaterSplashes = = NULL )
{
m_sndWaterSplashes = ( CSoundEnvelopeController : : GetController ( ) ) . SoundCreate ( filter , entindex ( ) , CHAN_STATIC , " coast.leech_water_churn_loop " , ATTN_NORM ) ;
}
if ( m_sndWaterSplashes )
{
( CSoundEnvelopeController : : GetController ( ) ) . Play ( m_sndWaterSplashes , 1.0f , 100 ) ;
}
}
void CHL2_Player : : StopWaterDeathSounds ( void )
{
if ( m_sndLeeches )
{
( CSoundEnvelopeController : : GetController ( ) ) . SoundFadeOut ( m_sndLeeches , 0.5f , true ) ;
m_sndLeeches = NULL ;
}
if ( m_sndWaterSplashes )
{
( CSoundEnvelopeController : : GetController ( ) ) . SoundFadeOut ( m_sndWaterSplashes , 0.5f , true ) ;
m_sndWaterSplashes = NULL ;
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CHL2_Player : : MissedAR2AltFire ( )
{
if ( GetPlayerProxy ( ) ! = NULL )
{
GetPlayerProxy ( ) - > m_PlayerMissedAR2AltFire . FireOutput ( this , this ) ;
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CHL2_Player : : DisplayLadderHudHint ( )
{
# if !defined( CLIENT_DLL )
if ( gpGlobals - > curtime > m_flTimeNextLadderHint )
{
m_flTimeNextLadderHint = gpGlobals - > curtime + 60.0f ;
CFmtStr hint ;
hint . sprintf ( " #Valve_Hint_Ladder " ) ;
UTIL_HudHintText ( this , hint . Access ( ) ) ;
}
# endif //CLIENT_DLL
}
//-----------------------------------------------------------------------------
// Shuts down sounds
//-----------------------------------------------------------------------------
void CHL2_Player : : StopLoopingSounds ( void )
{
if ( m_sndLeeches ! = NULL )
{
( CSoundEnvelopeController : : GetController ( ) ) . SoundDestroy ( m_sndLeeches ) ;
m_sndLeeches = NULL ;
}
if ( m_sndWaterSplashes ! = NULL )
{
( CSoundEnvelopeController : : GetController ( ) ) . SoundDestroy ( m_sndWaterSplashes ) ;
m_sndWaterSplashes = NULL ;
}
BaseClass : : StopLoopingSounds ( ) ;
}
//-----------------------------------------------------------------------------
void CHL2_Player : : ModifyOrAppendPlayerCriteria ( AI_CriteriaSet & set )
{
BaseClass : : ModifyOrAppendPlayerCriteria ( set ) ;
if ( GlobalEntity_GetIndex ( " gordon_precriminal " ) = = - 1 )
{
set . AppendCriteria ( " gordon_precriminal " , " 0 " ) ;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const impactdamagetable_t & CHL2_Player : : GetPhysicsImpactDamageTable ( )
{
if ( m_bUseCappedPhysicsDamageTable )
return gCappedPlayerImpactDamageTable ;
return BaseClass : : GetPhysicsImpactDamageTable ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Makes a splash when the player transitions between water states
//-----------------------------------------------------------------------------
void CHL2_Player : : Splash ( void )
{
CEffectData data ;
data . m_fFlags = 0 ;
data . m_vOrigin = GetAbsOrigin ( ) ;
data . m_vNormal = Vector ( 0 , 0 , 1 ) ;
data . m_vAngles = QAngle ( 0 , 0 , 0 ) ;
if ( GetWaterType ( ) & CONTENTS_SLIME )
{
data . m_fFlags | = FX_WATER_IN_SLIME ;
}
float flSpeed = GetAbsVelocity ( ) . Length ( ) ;
if ( flSpeed < 300 )
{
data . m_flScale = random - > RandomFloat ( 10 , 12 ) ;
DispatchEffect ( " waterripple " , data ) ;
}
else
{
data . m_flScale = random - > RandomFloat ( 6 , 8 ) ;
DispatchEffect ( " watersplash " , data ) ;
}
}
CLogicPlayerProxy * CHL2_Player : : GetPlayerProxy ( void )
{
CLogicPlayerProxy * pProxy = dynamic_cast < CLogicPlayerProxy * > ( m_hPlayerProxy . Get ( ) ) ;
if ( pProxy = = NULL )
{
pProxy = ( CLogicPlayerProxy * ) gEntList . FindEntityByClassname ( NULL , " logic_playerproxy " ) ;
if ( pProxy = = NULL )
return NULL ;
pProxy - > m_hPlayer = this ;
m_hPlayerProxy = pProxy ;
}
return pProxy ;
}
void CHL2_Player : : FirePlayerProxyOutput ( const char * pszOutputName , variant_t variant , CBaseEntity * pActivator , CBaseEntity * pCaller )
{
if ( GetPlayerProxy ( ) = = NULL )
return ;
GetPlayerProxy ( ) - > FireNamedOutput ( pszOutputName , variant , pActivator , pCaller ) ;
}
LINK_ENTITY_TO_CLASS ( logic_playerproxy , CLogicPlayerProxy ) ;
BEGIN_DATADESC ( CLogicPlayerProxy )
DEFINE_OUTPUT ( m_OnFlashlightOn , " OnFlashlightOn " ) ,
DEFINE_OUTPUT ( m_OnFlashlightOff , " OnFlashlightOff " ) ,
DEFINE_OUTPUT ( m_RequestedPlayerHealth , " PlayerHealth " ) ,
DEFINE_OUTPUT ( m_PlayerHasAmmo , " PlayerHasAmmo " ) ,
DEFINE_OUTPUT ( m_PlayerHasNoAmmo , " PlayerHasNoAmmo " ) ,
DEFINE_OUTPUT ( m_PlayerDied , " PlayerDied " ) ,
DEFINE_OUTPUT ( m_PlayerMissedAR2AltFire , " PlayerMissedAR2AltFire " ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " RequestPlayerHealth " , InputRequestPlayerHealth ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " SetFlashlightSlowDrain " , InputSetFlashlightSlowDrain ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " SetFlashlightNormalDrain " , InputSetFlashlightNormalDrain ) ,
DEFINE_INPUTFUNC ( FIELD_INTEGER , " SetPlayerHealth " , InputSetPlayerHealth ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " RequestAmmoState " , InputRequestAmmoState ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " LowerWeapon " , InputLowerWeapon ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " EnableCappedPhysicsDamage " , InputEnableCappedPhysicsDamage ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " DisableCappedPhysicsDamage " , InputDisableCappedPhysicsDamage ) ,
DEFINE_INPUTFUNC ( FIELD_STRING , " SetLocatorTargetEntity " , InputSetLocatorTargetEntity ) ,
# ifdef PORTAL
DEFINE_INPUTFUNC ( FIELD_VOID , " SuppressCrosshair " , InputSuppressCrosshair ) ,
# endif // PORTAL
DEFINE_FIELD ( m_hPlayer , FIELD_EHANDLE ) ,
END_DATADESC ( )
void CLogicPlayerProxy : : Activate ( void )
{
BaseClass : : Activate ( ) ;
if ( m_hPlayer = = NULL )
{
m_hPlayer = AI_GetSinglePlayer ( ) ;
}
}
bool CLogicPlayerProxy : : PassesDamageFilter ( const CTakeDamageInfo & info )
{
if ( m_hDamageFilter )
{
CBaseFilter * pFilter = ( CBaseFilter * ) ( m_hDamageFilter . Get ( ) ) ;
return pFilter - > PassesDamageFilter ( info ) ;
}
return true ;
}
void CLogicPlayerProxy : : InputSetPlayerHealth ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
m_hPlayer - > SetHealth ( inputdata . value . Int ( ) ) ;
}
void CLogicPlayerProxy : : InputRequestPlayerHealth ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
m_RequestedPlayerHealth . Set ( m_hPlayer - > GetHealth ( ) , inputdata . pActivator , inputdata . pCaller ) ;
}
void CLogicPlayerProxy : : InputSetFlashlightSlowDrain ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
CHL2_Player * pPlayer = dynamic_cast < CHL2_Player * > ( m_hPlayer . Get ( ) ) ;
if ( pPlayer )
pPlayer - > SetFlashlightPowerDrainScale ( hl2_darkness_flashlight_factor . GetFloat ( ) ) ;
}
void CLogicPlayerProxy : : InputSetFlashlightNormalDrain ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
CHL2_Player * pPlayer = dynamic_cast < CHL2_Player * > ( m_hPlayer . Get ( ) ) ;
if ( pPlayer )
pPlayer - > SetFlashlightPowerDrainScale ( 1.0f ) ;
}
void CLogicPlayerProxy : : InputRequestAmmoState ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
CHL2_Player * pPlayer = dynamic_cast < CHL2_Player * > ( m_hPlayer . Get ( ) ) ;
for ( int i = 0 ; i < pPlayer - > WeaponCount ( ) ; + + i )
{
CBaseCombatWeapon * pCheck = pPlayer - > GetWeapon ( i ) ;
if ( pCheck )
{
if ( pCheck - > HasAnyAmmo ( ) & & ( pCheck - > UsesPrimaryAmmo ( ) | | pCheck - > UsesSecondaryAmmo ( ) ) )
{
m_PlayerHasAmmo . FireOutput ( this , this , 0 ) ;
return ;
}
}
}
m_PlayerHasNoAmmo . FireOutput ( this , this , 0 ) ;
}
void CLogicPlayerProxy : : InputLowerWeapon ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
CHL2_Player * pPlayer = dynamic_cast < CHL2_Player * > ( m_hPlayer . Get ( ) ) ;
pPlayer - > Weapon_Lower ( ) ;
}
void CLogicPlayerProxy : : InputEnableCappedPhysicsDamage ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
CHL2_Player * pPlayer = dynamic_cast < CHL2_Player * > ( m_hPlayer . Get ( ) ) ;
pPlayer - > EnableCappedPhysicsDamage ( ) ;
}
void CLogicPlayerProxy : : InputDisableCappedPhysicsDamage ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
CHL2_Player * pPlayer = dynamic_cast < CHL2_Player * > ( m_hPlayer . Get ( ) ) ;
pPlayer - > DisableCappedPhysicsDamage ( ) ;
}
void CLogicPlayerProxy : : InputSetLocatorTargetEntity ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
CBaseEntity * pTarget = NULL ; // assume no target
string_t iszTarget = MAKE_STRING ( inputdata . value . String ( ) ) ;
if ( iszTarget ! = NULL_STRING )
{
pTarget = gEntList . FindEntityByName ( NULL , iszTarget ) ;
}
CHL2_Player * pPlayer = dynamic_cast < CHL2_Player * > ( m_hPlayer . Get ( ) ) ;
pPlayer - > SetLocatorTargetEntity ( pTarget ) ;
}
# ifdef PORTAL
void CLogicPlayerProxy : : InputSuppressCrosshair ( inputdata_t & inputdata )
{
if ( m_hPlayer = = NULL )
return ;
CPortal_Player * pPlayer = ToPortalPlayer ( m_hPlayer . Get ( ) ) ;
pPlayer - > SuppressCrosshair ( true ) ;
}
# endif // PORTAL