Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3930 lines
107 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Player for HL2.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "hl2_player.h"
  8. #include "globalstate.h"
  9. #include "game.h"
  10. #include "gamerules.h"
  11. #include "trains.h"
  12. #include "basehlcombatweapon_shared.h"
  13. #include "vcollide_parse.h"
  14. #include "in_buttons.h"
  15. #include "ai_interactions.h"
  16. #include "ai_squad.h"
  17. #include "igamemovement.h"
  18. #include "ai_hull.h"
  19. #include "hl2_shareddefs.h"
  20. #include "info_camera_link.h"
  21. #include "point_camera.h"
  22. #include "engine/IEngineSound.h"
  23. #include "ndebugoverlay.h"
  24. #include "iservervehicle.h"
  25. #include "IVehicle.h"
  26. #include "globals.h"
  27. #include "collisionutils.h"
  28. #include "coordsize.h"
  29. #include "effect_color_tables.h"
  30. #include "vphysics/player_controller.h"
  31. #include "player_pickup.h"
  32. #include "weapon_physcannon.h"
  33. #include "script_intro.h"
  34. #include "effect_dispatch_data.h"
  35. #include "te_effect_dispatch.h"
  36. #include "ai_basenpc.h"
  37. #include "AI_Criteria.h"
  38. #include "npc_barnacle.h"
  39. #include "entitylist.h"
  40. #include "env_zoom.h"
  41. #include "hl2_gamerules.h"
  42. #include "prop_combine_ball.h"
  43. #include "datacache/imdlcache.h"
  44. #include "eventqueue.h"
  45. #include "gamestats.h"
  46. #include "filters.h"
  47. #include "tier0/icommandline.h"
  48. #ifdef HL2_EPISODIC
  49. #include "npc_alyx_episodic.h"
  50. #endif
  51. #ifdef PORTAL
  52. #include "portal_player.h"
  53. #endif // PORTAL
  54. // memdbgon must be the last include file in a .cpp file!!!
  55. #include "tier0/memdbgon.h"
  56. extern ConVar weapon_showproficiency;
  57. extern ConVar autoaim_max_dist;
  58. // Do not touch with without seeing me, please! (sjb)
  59. // For consistency's sake, enemy gunfire is traced against a scaled down
  60. // version of the player's hull, not the hitboxes for the player's model
  61. // because the player isn't aware of his model, and can't do anything about
  62. // preventing headshots and other such things. Also, game difficulty will
  63. // not change if the model changes. This is the value by which to scale
  64. // the X/Y of the player's hull to get the volume to trace bullets against.
  65. #define PLAYER_HULL_REDUCTION 0.70
  66. // This switches between the single primary weapon, and multiple weapons with buckets approach (jdw)
  67. #define HL2_SINGLE_PRIMARY_WEAPON_MODE 0
  68. #define TIME_IGNORE_FALL_DAMAGE 10.0
  69. extern int gEvilImpulse101;
  70. ConVar sv_autojump( "sv_autojump", "0" );
  71. ConVar hl2_walkspeed( "hl2_walkspeed", "150" );
  72. ConVar hl2_normspeed( "hl2_normspeed", "190" );
  73. ConVar hl2_sprintspeed( "hl2_sprintspeed", "320" );
  74. ConVar hl2_darkness_flashlight_factor ( "hl2_darkness_flashlight_factor", "1" );
  75. #ifdef HL2MP
  76. #define HL2_WALK_SPEED 150
  77. #define HL2_NORM_SPEED 190
  78. #define HL2_SPRINT_SPEED 320
  79. #else
  80. #define HL2_WALK_SPEED hl2_walkspeed.GetFloat()
  81. #define HL2_NORM_SPEED hl2_normspeed.GetFloat()
  82. #define HL2_SPRINT_SPEED hl2_sprintspeed.GetFloat()
  83. #endif
  84. ConVar player_showpredictedposition( "player_showpredictedposition", "0" );
  85. ConVar player_showpredictedposition_timestep( "player_showpredictedposition_timestep", "1.0" );
  86. ConVar player_squad_transient_commands( "player_squad_transient_commands", "1", FCVAR_REPLICATED );
  87. ConVar player_squad_double_tap_time( "player_squad_double_tap_time", "0.25" );
  88. ConVar sv_infinite_aux_power( "sv_infinite_aux_power", "0", FCVAR_CHEAT );
  89. ConVar autoaim_unlock_target( "autoaim_unlock_target", "0.8666" );
  90. ConVar sv_stickysprint("sv_stickysprint", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX);
  91. #define FLASH_DRAIN_TIME 1.1111 // 100 units / 90 secs
  92. #define FLASH_CHARGE_TIME 50.0f // 100 units / 2 secs
  93. //==============================================================================================
  94. // CAPPED PLAYER PHYSICS DAMAGE TABLE
  95. //==============================================================================================
  96. static impactentry_t cappedPlayerLinearTable[] =
  97. {
  98. { 150*150, 5 },
  99. { 250*250, 10 },
  100. { 450*450, 20 },
  101. { 550*550, 30 },
  102. //{ 700*700, 100 },
  103. //{ 1000*1000, 500 },
  104. };
  105. static impactentry_t cappedPlayerAngularTable[] =
  106. {
  107. { 100*100, 10 },
  108. { 150*150, 20 },
  109. { 200*200, 30 },
  110. //{ 300*300, 500 },
  111. };
  112. static impactdamagetable_t gCappedPlayerImpactDamageTable =
  113. {
  114. cappedPlayerLinearTable,
  115. cappedPlayerAngularTable,
  116. ARRAYSIZE(cappedPlayerLinearTable),
  117. ARRAYSIZE(cappedPlayerAngularTable),
  118. 24*24.0f, // minimum linear speed
  119. 360*360.0f, // minimum angular speed
  120. 2.0f, // can't take damage from anything under 2kg
  121. 5.0f, // anything less than 5kg is "small"
  122. 5.0f, // never take more than 5 pts of damage from anything under 5kg
  123. 36*36.0f, // <5kg objects must go faster than 36 in/s to do damage
  124. 0.0f, // large mass in kg (no large mass effects)
  125. 1.0f, // large mass scale
  126. 2.0f, // large mass falling scale
  127. 320.0f, // min velocity for player speed to cause damage
  128. };
  129. // Flashlight utility
  130. bool g_bCacheLegacyFlashlightStatus = true;
  131. bool g_bUseLegacyFlashlight;
  132. bool Flashlight_UseLegacyVersion( void )
  133. {
  134. // If this is the first run through, cache off what the answer should be (cannot change during a session)
  135. if ( g_bCacheLegacyFlashlightStatus )
  136. {
  137. char modDir[MAX_PATH];
  138. if ( UTIL_GetModDir( modDir, sizeof(modDir) ) == false )
  139. return false;
  140. g_bUseLegacyFlashlight = ( !Q_strcmp( modDir, "hl2" ) ||
  141. !Q_strcmp( modDir, "episodic" ) ||
  142. !Q_strcmp( modDir, "lostcoast" ) || !Q_strcmp( modDir, "hl1" ));
  143. g_bCacheLegacyFlashlightStatus = false;
  144. }
  145. // Return the results
  146. return g_bUseLegacyFlashlight;
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Purpose: Used to relay outputs/inputs from the player to the world and viceversa
  150. //-----------------------------------------------------------------------------
  151. class CLogicPlayerProxy : public CLogicalEntity
  152. {
  153. DECLARE_CLASS( CLogicPlayerProxy, CLogicalEntity );
  154. private:
  155. DECLARE_DATADESC();
  156. public:
  157. COutputEvent m_OnFlashlightOn;
  158. COutputEvent m_OnFlashlightOff;
  159. COutputEvent m_PlayerHasAmmo;
  160. COutputEvent m_PlayerHasNoAmmo;
  161. COutputEvent m_PlayerDied;
  162. COutputEvent m_PlayerMissedAR2AltFire; // Player fired a combine ball which did not dissolve any enemies.
  163. COutputInt m_RequestedPlayerHealth;
  164. void InputRequestPlayerHealth( inputdata_t &inputdata );
  165. void InputSetFlashlightSlowDrain( inputdata_t &inputdata );
  166. void InputSetFlashlightNormalDrain( inputdata_t &inputdata );
  167. void InputSetPlayerHealth( inputdata_t &inputdata );
  168. void InputRequestAmmoState( inputdata_t &inputdata );
  169. void InputLowerWeapon( inputdata_t &inputdata );
  170. void InputEnableCappedPhysicsDamage( inputdata_t &inputdata );
  171. void InputDisableCappedPhysicsDamage( inputdata_t &inputdata );
  172. void InputSetLocatorTargetEntity( inputdata_t &inputdata );
  173. #ifdef PORTAL
  174. void InputSuppressCrosshair( inputdata_t &inputdata );
  175. #endif // PORTAL2
  176. void Activate ( void );
  177. bool PassesDamageFilter( const CTakeDamageInfo &info );
  178. EHANDLE m_hPlayer;
  179. };
  180. //------------------------------------------------------------------------------
  181. //------------------------------------------------------------------------------
  182. void CC_ToggleZoom( void )
  183. {
  184. CBasePlayer* pPlayer = UTIL_GetCommandClient();
  185. if( pPlayer )
  186. {
  187. CHL2_Player *pHL2Player = dynamic_cast<CHL2_Player*>(pPlayer);
  188. if( pHL2Player && pHL2Player->IsSuitEquipped() )
  189. {
  190. pHL2Player->ToggleZoom();
  191. }
  192. }
  193. }
  194. static ConCommand toggle_zoom("toggle_zoom", CC_ToggleZoom, "Toggles zoom display" );
  195. // ConVar cl_forwardspeed( "cl_forwardspeed", "400", FCVAR_CHEAT ); // Links us to the client's version
  196. 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
  197. ConVar xc_use_crouch_limiter( "xc_use_crouch_limiter", "0", FCVAR_ARCHIVE, "Use the crouch limiting logic on the controller" );
  198. //------------------------------------------------------------------------------
  199. //------------------------------------------------------------------------------
  200. void CC_ToggleDuck( void )
  201. {
  202. CBasePlayer* pPlayer = UTIL_GetCommandClient();
  203. if ( pPlayer == NULL )
  204. return;
  205. // Cannot be frozen
  206. if ( pPlayer->GetFlags() & FL_FROZEN )
  207. return;
  208. static bool bChecked = false;
  209. static ConVar *pCVcl_forwardspeed = NULL;
  210. if ( !bChecked )
  211. {
  212. bChecked = true;
  213. pCVcl_forwardspeed = ( ConVar * )cvar->FindVar( "cl_forwardspeed" );
  214. }
  215. // If we're not ducked, do extra checking
  216. if ( xc_use_crouch_limiter.GetBool() )
  217. {
  218. if ( pPlayer->GetToggledDuckState() == false )
  219. {
  220. float flForwardSpeed = 400.0f;
  221. if ( pCVcl_forwardspeed )
  222. {
  223. flForwardSpeed = pCVcl_forwardspeed->GetFloat();
  224. }
  225. flForwardSpeed = MAX( 1.0f, flForwardSpeed );
  226. // Make sure we're not in the blindspot on the crouch detection
  227. float flStickDistPerc = ( pPlayer->GetStickDist() / flForwardSpeed ); // Speed is the magnitude
  228. if ( flStickDistPerc > xc_crouch_range.GetFloat() )
  229. return;
  230. }
  231. }
  232. // Toggle the duck
  233. pPlayer->ToggleDuck();
  234. }
  235. static ConCommand toggle_duck("toggle_duck", CC_ToggleDuck, "Toggles duck" );
  236. #ifndef HL2MP
  237. #ifndef PORTAL
  238. LINK_ENTITY_TO_CLASS( player, CHL2_Player );
  239. #endif
  240. #endif
  241. PRECACHE_REGISTER(player);
  242. CBaseEntity *FindEntityForward( CBasePlayer *pMe, bool fHull );
  243. BEGIN_SIMPLE_DATADESC( LadderMove_t )
  244. DEFINE_FIELD( m_bForceLadderMove, FIELD_BOOLEAN ),
  245. DEFINE_FIELD( m_bForceMount, FIELD_BOOLEAN ),
  246. DEFINE_FIELD( m_flStartTime, FIELD_TIME ),
  247. DEFINE_FIELD( m_flArrivalTime, FIELD_TIME ),
  248. DEFINE_FIELD( m_vecGoalPosition, FIELD_POSITION_VECTOR ),
  249. DEFINE_FIELD( m_vecStartPosition, FIELD_POSITION_VECTOR ),
  250. DEFINE_FIELD( m_hForceLadder, FIELD_EHANDLE ),
  251. DEFINE_FIELD( m_hReservedSpot, FIELD_EHANDLE ),
  252. END_DATADESC()
  253. // Global Savedata for HL2 player
  254. BEGIN_DATADESC( CHL2_Player )
  255. DEFINE_FIELD( m_nControlClass, FIELD_INTEGER ),
  256. DEFINE_EMBEDDED( m_HL2Local ),
  257. DEFINE_FIELD( m_bSprintEnabled, FIELD_BOOLEAN ),
  258. DEFINE_FIELD( m_flTimeAllSuitDevicesOff, FIELD_TIME ),
  259. DEFINE_FIELD( m_fIsSprinting, FIELD_BOOLEAN ),
  260. DEFINE_FIELD( m_fIsWalking, FIELD_BOOLEAN ),
  261. /*
  262. // These are initialized every time the player calls Activate()
  263. DEFINE_FIELD( m_bIsAutoSprinting, FIELD_BOOLEAN ),
  264. DEFINE_FIELD( m_fAutoSprintMinTime, FIELD_TIME ),
  265. */
  266. // Field is used within a single tick, no need to save restore
  267. // DEFINE_FIELD( m_bPlayUseDenySound, FIELD_BOOLEAN ),
  268. // m_pPlayerAISquad reacquired on load
  269. DEFINE_AUTO_ARRAY( m_vecMissPositions, FIELD_POSITION_VECTOR ),
  270. DEFINE_FIELD( m_nNumMissPositions, FIELD_INTEGER ),
  271. // m_pPlayerAISquad
  272. DEFINE_EMBEDDED( m_CommanderUpdateTimer ),
  273. // m_RealTimeLastSquadCommand
  274. DEFINE_FIELD( m_QueuedCommand, FIELD_INTEGER ),
  275. DEFINE_FIELD( m_flTimeIgnoreFallDamage, FIELD_TIME ),
  276. DEFINE_FIELD( m_bIgnoreFallDamageResetAfterImpact, FIELD_BOOLEAN ),
  277. // Suit power fields
  278. DEFINE_FIELD( m_flSuitPowerLoad, FIELD_FLOAT ),
  279. DEFINE_FIELD( m_flIdleTime, FIELD_TIME ),
  280. DEFINE_FIELD( m_flMoveTime, FIELD_TIME ),
  281. DEFINE_FIELD( m_flLastDamageTime, FIELD_TIME ),
  282. DEFINE_FIELD( m_flTargetFindTime, FIELD_TIME ),
  283. DEFINE_FIELD( m_flAdmireGlovesAnimTime, FIELD_TIME ),
  284. DEFINE_FIELD( m_flNextFlashlightCheckTime, FIELD_TIME ),
  285. DEFINE_FIELD( m_flFlashlightPowerDrainScale, FIELD_FLOAT ),
  286. DEFINE_FIELD( m_bFlashlightDisabled, FIELD_BOOLEAN ),
  287. DEFINE_FIELD( m_bUseCappedPhysicsDamageTable, FIELD_BOOLEAN ),
  288. DEFINE_FIELD( m_hLockedAutoAimEntity, FIELD_EHANDLE ),
  289. DEFINE_EMBEDDED( m_LowerWeaponTimer ),
  290. DEFINE_EMBEDDED( m_AutoaimTimer ),
  291. DEFINE_INPUTFUNC( FIELD_FLOAT, "IgnoreFallDamage", InputIgnoreFallDamage ),
  292. DEFINE_INPUTFUNC( FIELD_FLOAT, "IgnoreFallDamageWithoutReset", InputIgnoreFallDamageWithoutReset ),
  293. DEFINE_INPUTFUNC( FIELD_VOID, "OnSquadMemberKilled", OnSquadMemberKilled ),
  294. DEFINE_INPUTFUNC( FIELD_VOID, "DisableFlashlight", InputDisableFlashlight ),
  295. DEFINE_INPUTFUNC( FIELD_VOID, "EnableFlashlight", InputEnableFlashlight ),
  296. DEFINE_INPUTFUNC( FIELD_VOID, "ForceDropPhysObjects", InputForceDropPhysObjects ),
  297. DEFINE_SOUNDPATCH( m_sndLeeches ),
  298. DEFINE_SOUNDPATCH( m_sndWaterSplashes ),
  299. DEFINE_FIELD( m_flArmorReductionTime, FIELD_TIME ),
  300. DEFINE_FIELD( m_iArmorReductionFrom, FIELD_INTEGER ),
  301. DEFINE_FIELD( m_flTimeUseSuspended, FIELD_TIME ),
  302. DEFINE_FIELD( m_hLocatorTargetEntity, FIELD_EHANDLE ),
  303. DEFINE_FIELD( m_flTimeNextLadderHint, FIELD_TIME ),
  304. //DEFINE_FIELD( m_hPlayerProxy, FIELD_EHANDLE ), //Shut up class check!
  305. END_DATADESC()
  306. CHL2_Player::CHL2_Player()
  307. {
  308. m_nNumMissPositions = 0;
  309. m_pPlayerAISquad = 0;
  310. m_bSprintEnabled = true;
  311. m_flArmorReductionTime = 0.0f;
  312. m_iArmorReductionFrom = 0;
  313. }
  314. //
  315. // SUIT POWER DEVICES
  316. //
  317. #define SUITPOWER_CHARGE_RATE 12.5 // 100 units in 8 seconds
  318. #ifdef HL2MP
  319. CSuitPowerDevice SuitDeviceSprint( bits_SUIT_DEVICE_SPRINT, 25.0f ); // 100 units in 4 seconds
  320. #else
  321. CSuitPowerDevice SuitDeviceSprint( bits_SUIT_DEVICE_SPRINT, 12.5f ); // 100 units in 8 seconds
  322. #endif
  323. #ifdef HL2_EPISODIC
  324. CSuitPowerDevice SuitDeviceFlashlight( bits_SUIT_DEVICE_FLASHLIGHT, 1.111 ); // 100 units in 90 second
  325. #else
  326. CSuitPowerDevice SuitDeviceFlashlight( bits_SUIT_DEVICE_FLASHLIGHT, 2.222 ); // 100 units in 45 second
  327. #endif
  328. CSuitPowerDevice SuitDeviceBreather( bits_SUIT_DEVICE_BREATHER, 6.7f ); // 100 units in 15 seconds (plus three padded seconds)
  329. IMPLEMENT_SERVERCLASS_ST(CHL2_Player, DT_HL2_Player)
  330. SendPropDataTable(SENDINFO_DT(m_HL2Local), &REFERENCE_SEND_TABLE(DT_HL2Local), SendProxy_SendLocalDataTable),
  331. SendPropBool( SENDINFO(m_fIsSprinting) ),
  332. END_SEND_TABLE()
  333. void CHL2_Player::Precache( void )
  334. {
  335. BaseClass::Precache();
  336. PrecacheScriptSound( "HL2Player.SprintNoPower" );
  337. PrecacheScriptSound( "HL2Player.SprintStart" );
  338. PrecacheScriptSound( "HL2Player.UseDeny" );
  339. PrecacheScriptSound( "HL2Player.FlashLightOn" );
  340. PrecacheScriptSound( "HL2Player.FlashLightOff" );
  341. PrecacheScriptSound( "HL2Player.PickupWeapon" );
  342. PrecacheScriptSound( "HL2Player.TrainUse" );
  343. PrecacheScriptSound( "HL2Player.Use" );
  344. PrecacheScriptSound( "HL2Player.BurnPain" );
  345. }
  346. //-----------------------------------------------------------------------------
  347. // Purpose:
  348. //-----------------------------------------------------------------------------
  349. void CHL2_Player::CheckSuitZoom( void )
  350. {
  351. //#ifndef _XBOX
  352. //Adrian - No zooming without a suit!
  353. if ( IsSuitEquipped() )
  354. {
  355. if ( m_afButtonReleased & IN_ZOOM )
  356. {
  357. StopZooming();
  358. }
  359. else if ( m_afButtonPressed & IN_ZOOM )
  360. {
  361. StartZooming();
  362. }
  363. }
  364. //#endif//_XBOX
  365. }
  366. void CHL2_Player::EquipSuit( bool bPlayEffects )
  367. {
  368. MDLCACHE_CRITICAL_SECTION();
  369. BaseClass::EquipSuit();
  370. m_HL2Local.m_bDisplayReticle = true;
  371. if ( bPlayEffects == true )
  372. {
  373. StartAdmireGlovesAnimation();
  374. }
  375. }
  376. void CHL2_Player::RemoveSuit( void )
  377. {
  378. BaseClass::RemoveSuit();
  379. m_HL2Local.m_bDisplayReticle = false;
  380. }
  381. void CHL2_Player::HandleSpeedChanges( void )
  382. {
  383. int buttonsChanged = m_afButtonPressed | m_afButtonReleased;
  384. bool bCanSprint = CanSprint();
  385. bool bIsSprinting = IsSprinting();
  386. bool bWantSprint = ( bCanSprint && IsSuitEquipped() && (m_nButtons & IN_SPEED) );
  387. if ( bIsSprinting != bWantSprint && (buttonsChanged & IN_SPEED) )
  388. {
  389. // If someone wants to sprint, make sure they've pressed the button to do so. We want to prevent the
  390. // case where a player can hold down the sprint key and burn tiny bursts of sprint as the suit recharges
  391. // We want a full debounce of the key to resume sprinting after the suit is completely drained
  392. if ( bWantSprint )
  393. {
  394. if ( sv_stickysprint.GetBool() )
  395. {
  396. StartAutoSprint();
  397. }
  398. else
  399. {
  400. StartSprinting();
  401. }
  402. }
  403. else
  404. {
  405. if ( !sv_stickysprint.GetBool() )
  406. {
  407. StopSprinting();
  408. }
  409. // Reset key, so it will be activated post whatever is suppressing it.
  410. m_nButtons &= ~IN_SPEED;
  411. }
  412. }
  413. bool bIsWalking = IsWalking();
  414. // have suit, pressing button, not sprinting or ducking
  415. bool bWantWalking;
  416. if( IsSuitEquipped() )
  417. {
  418. bWantWalking = (m_nButtons & IN_WALK) && !IsSprinting() && !(m_nButtons & IN_DUCK);
  419. }
  420. else
  421. {
  422. bWantWalking = true;
  423. }
  424. if( bIsWalking != bWantWalking )
  425. {
  426. if ( bWantWalking )
  427. {
  428. StartWalking();
  429. }
  430. else
  431. {
  432. StopWalking();
  433. }
  434. }
  435. }
  436. //-----------------------------------------------------------------------------
  437. // This happens when we powerdown from the mega physcannon to the regular one
  438. //-----------------------------------------------------------------------------
  439. void CHL2_Player::HandleArmorReduction( void )
  440. {
  441. if ( m_flArmorReductionTime < gpGlobals->curtime )
  442. return;
  443. if ( ArmorValue() <= 0 )
  444. return;
  445. float flPercent = 1.0f - (( m_flArmorReductionTime - gpGlobals->curtime ) / ARMOR_DECAY_TIME );
  446. int iArmor = Lerp( flPercent, m_iArmorReductionFrom, 0 );
  447. SetArmorValue( iArmor );
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Purpose: Allow pre-frame adjustments on the player
  451. //-----------------------------------------------------------------------------
  452. void CHL2_Player::PreThink(void)
  453. {
  454. if ( player_showpredictedposition.GetBool() )
  455. {
  456. Vector predPos;
  457. UTIL_PredictedPosition( this, player_showpredictedposition_timestep.GetFloat(), &predPos );
  458. NDebugOverlay::Box( predPos, NAI_Hull::Mins( GetHullType() ), NAI_Hull::Maxs( GetHullType() ), 0, 255, 0, 0, 0.01f );
  459. NDebugOverlay::Line( GetAbsOrigin(), predPos, 0, 255, 0, 0, 0.01f );
  460. }
  461. #ifdef HL2_EPISODIC
  462. if( m_hLocatorTargetEntity != NULL )
  463. {
  464. // Keep track of the entity here, the client will pick up the rest of the work
  465. m_HL2Local.m_vecLocatorOrigin = m_hLocatorTargetEntity->WorldSpaceCenter();
  466. }
  467. else
  468. {
  469. m_HL2Local.m_vecLocatorOrigin = vec3_invalid; // This tells the client we have no locator target.
  470. }
  471. #endif//HL2_EPISODIC
  472. // Riding a vehicle?
  473. if ( IsInAVehicle() )
  474. {
  475. VPROF( "CHL2_Player::PreThink-Vehicle" );
  476. // make sure we update the client, check for timed damage and update suit even if we are in a vehicle
  477. UpdateClientData();
  478. CheckTimeBasedDamage();
  479. // Allow the suit to recharge when in the vehicle.
  480. SuitPower_Update();
  481. CheckSuitUpdate();
  482. CheckSuitZoom();
  483. WaterMove();
  484. return;
  485. }
  486. // This is an experiment of mine- autojumping!
  487. // only affects you if sv_autojump is nonzero.
  488. if( (GetFlags() & FL_ONGROUND) && sv_autojump.GetFloat() != 0 )
  489. {
  490. VPROF( "CHL2_Player::PreThink-Autojump" );
  491. // check autojump
  492. Vector vecCheckDir;
  493. vecCheckDir = GetAbsVelocity();
  494. float flVelocity = VectorNormalize( vecCheckDir );
  495. if( flVelocity > 200 )
  496. {
  497. // Going fast enough to autojump
  498. vecCheckDir = WorldSpaceCenter() + vecCheckDir * 34 - Vector( 0, 0, 16 );
  499. trace_t tr;
  500. 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 );
  501. //NDebugOverlay::Line( tr.startpos, tr.endpos, 0,255,0, true, 10 );
  502. if( tr.fraction == 1.0 && !tr.startsolid )
  503. {
  504. // Now trace down!
  505. UTIL_TraceLine( vecCheckDir, vecCheckDir - Vector( 0, 0, 64 ), MASK_PLAYERSOLID, this, COLLISION_GROUP_NONE, &tr );
  506. //NDebugOverlay::Line( tr.startpos, tr.endpos, 0,255,0, true, 10 );
  507. if( tr.fraction == 1.0 && !tr.startsolid )
  508. {
  509. // !!!HACKHACK
  510. // I KNOW, I KNOW, this is definitely not the right way to do this,
  511. // but I'm prototyping! (sjb)
  512. Vector vecNewVelocity = GetAbsVelocity();
  513. vecNewVelocity.z += 250;
  514. SetAbsVelocity( vecNewVelocity );
  515. }
  516. }
  517. }
  518. }
  519. VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-Speed" );
  520. HandleSpeedChanges();
  521. #ifdef HL2_EPISODIC
  522. HandleArmorReduction();
  523. #endif
  524. if( sv_stickysprint.GetBool() && m_bIsAutoSprinting )
  525. {
  526. // If we're ducked and not in the air
  527. if( IsDucked() && GetGroundEntity() != NULL )
  528. {
  529. StopSprinting();
  530. }
  531. // Stop sprinting if the player lets off the stick for a moment.
  532. else if( GetStickDist() == 0.0f )
  533. {
  534. if( gpGlobals->curtime > m_fAutoSprintMinTime )
  535. {
  536. StopSprinting();
  537. }
  538. }
  539. else
  540. {
  541. // Stop sprinting one half second after the player stops inputting with the move stick.
  542. m_fAutoSprintMinTime = gpGlobals->curtime + 0.5f;
  543. }
  544. }
  545. else if ( IsSprinting() )
  546. {
  547. // Disable sprint while ducked unless we're in the air (jumping)
  548. if ( IsDucked() && ( GetGroundEntity() != NULL ) )
  549. {
  550. StopSprinting();
  551. }
  552. }
  553. VPROF_SCOPE_END();
  554. if ( g_fGameOver || IsPlayerLockedInPlace() )
  555. return; // finale
  556. VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-ItemPreFrame" );
  557. ItemPreFrame( );
  558. VPROF_SCOPE_END();
  559. VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-WaterMove" );
  560. WaterMove();
  561. VPROF_SCOPE_END();
  562. if ( g_pGameRules && g_pGameRules->FAllowFlashlight() )
  563. m_Local.m_iHideHUD &= ~HIDEHUD_FLASHLIGHT;
  564. else
  565. m_Local.m_iHideHUD |= HIDEHUD_FLASHLIGHT;
  566. VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-CommanderUpdate" );
  567. CommanderUpdate();
  568. VPROF_SCOPE_END();
  569. // Operate suit accessories and manage power consumption/charge
  570. VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-SuitPower_Update" );
  571. SuitPower_Update();
  572. VPROF_SCOPE_END();
  573. // checks if new client data (for HUD and view control) needs to be sent to the client
  574. VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-UpdateClientData" );
  575. UpdateClientData();
  576. VPROF_SCOPE_END();
  577. VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-CheckTimeBasedDamage" );
  578. CheckTimeBasedDamage();
  579. VPROF_SCOPE_END();
  580. VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-CheckSuitUpdate" );
  581. CheckSuitUpdate();
  582. VPROF_SCOPE_END();
  583. VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-CheckSuitZoom" );
  584. CheckSuitZoom();
  585. VPROF_SCOPE_END();
  586. if (m_lifeState >= LIFE_DYING)
  587. {
  588. PlayerDeathThink();
  589. return;
  590. }
  591. #ifdef HL2_EPISODIC
  592. CheckFlashlight();
  593. #endif // HL2_EPISODIC
  594. // So the correct flags get sent to client asap.
  595. //
  596. if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
  597. AddFlag( FL_ONTRAIN );
  598. else
  599. RemoveFlag( FL_ONTRAIN );
  600. // Train speed control
  601. if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
  602. {
  603. CBaseEntity *pTrain = GetGroundEntity();
  604. float vel;
  605. if ( pTrain )
  606. {
  607. if ( !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) )
  608. pTrain = NULL;
  609. }
  610. if ( !pTrain )
  611. {
  612. if ( GetActiveWeapon() && (GetActiveWeapon()->ObjectCaps() & FCAP_DIRECTIONAL_USE) )
  613. {
  614. m_iTrain = TRAIN_ACTIVE | TRAIN_NEW;
  615. if ( m_nButtons & IN_FORWARD )
  616. {
  617. m_iTrain |= TRAIN_FAST;
  618. }
  619. else if ( m_nButtons & IN_BACK )
  620. {
  621. m_iTrain |= TRAIN_BACK;
  622. }
  623. else
  624. {
  625. m_iTrain |= TRAIN_NEUTRAL;
  626. }
  627. return;
  628. }
  629. else
  630. {
  631. trace_t trainTrace;
  632. // Maybe this is on the other side of a level transition
  633. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector(0,0,-38),
  634. MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trainTrace );
  635. if ( trainTrace.fraction != 1.0 && trainTrace.m_pEnt )
  636. pTrain = trainTrace.m_pEnt;
  637. if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(this) )
  638. {
  639. // Warning( "In train mode with no train!\n" );
  640. m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
  641. m_iTrain = TRAIN_NEW|TRAIN_OFF;
  642. return;
  643. }
  644. }
  645. }
  646. else if ( !( GetFlags() & FL_ONGROUND ) || pTrain->HasSpawnFlags( SF_TRACKTRAIN_NOCONTROL ) || (m_nButtons & (IN_MOVELEFT|IN_MOVERIGHT) ) )
  647. {
  648. // Turn off the train if you jump, strafe, or the train controls go dead
  649. m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
  650. m_iTrain = TRAIN_NEW|TRAIN_OFF;
  651. return;
  652. }
  653. SetAbsVelocity( vec3_origin );
  654. vel = 0;
  655. if ( m_afButtonPressed & IN_FORWARD )
  656. {
  657. vel = 1;
  658. pTrain->Use( this, this, USE_SET, (float)vel );
  659. }
  660. else if ( m_afButtonPressed & IN_BACK )
  661. {
  662. vel = -1;
  663. pTrain->Use( this, this, USE_SET, (float)vel );
  664. }
  665. if (vel)
  666. {
  667. m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed());
  668. m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW;
  669. }
  670. }
  671. else if (m_iTrain & TRAIN_ACTIVE)
  672. {
  673. m_iTrain = TRAIN_NEW; // turn off train
  674. }
  675. //
  676. // If we're not on the ground, we're falling. Update our falling velocity.
  677. //
  678. if ( !( GetFlags() & FL_ONGROUND ) )
  679. {
  680. m_Local.m_flFallVelocity = -GetAbsVelocity().z;
  681. }
  682. if ( m_afPhysicsFlags & PFLAG_ONBARNACLE )
  683. {
  684. bool bOnBarnacle = false;
  685. CNPC_Barnacle *pBarnacle = NULL;
  686. do
  687. {
  688. // FIXME: Not a good or fast solution, but maybe it will catch the bug!
  689. pBarnacle = (CNPC_Barnacle*)gEntList.FindEntityByClassname( pBarnacle, "npc_barnacle" );
  690. if ( pBarnacle )
  691. {
  692. if ( pBarnacle->GetEnemy() == this )
  693. {
  694. bOnBarnacle = true;
  695. }
  696. }
  697. } while ( pBarnacle );
  698. if ( !bOnBarnacle )
  699. {
  700. Warning( "Attached to barnacle?\n" );
  701. Assert( 0 );
  702. m_afPhysicsFlags &= ~PFLAG_ONBARNACLE;
  703. }
  704. else
  705. {
  706. SetAbsVelocity( vec3_origin );
  707. }
  708. }
  709. // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating?
  710. // Update weapon's ready status
  711. UpdateWeaponPosture();
  712. // Disallow shooting while zooming
  713. if ( IsX360() )
  714. {
  715. if ( IsZooming() )
  716. {
  717. if( GetActiveWeapon() && !GetActiveWeapon()->IsWeaponZoomed() )
  718. {
  719. // If not zoomed because of the weapon itself, do not attack.
  720. m_nButtons &= ~(IN_ATTACK|IN_ATTACK2);
  721. }
  722. }
  723. }
  724. else
  725. {
  726. if ( m_nButtons & IN_ZOOM )
  727. {
  728. //FIXME: Held weapons like the grenade get sad when this happens
  729. #ifdef HL2_EPISODIC
  730. // Episodic allows players to zoom while using a func_tank
  731. CBaseCombatWeapon* pWep = GetActiveWeapon();
  732. if ( !m_hUseEntity || ( pWep && pWep->IsWeaponVisible() ) )
  733. #endif
  734. m_nButtons &= ~(IN_ATTACK|IN_ATTACK2);
  735. }
  736. }
  737. }
  738. void CHL2_Player::PostThink( void )
  739. {
  740. BaseClass::PostThink();
  741. if ( !g_fGameOver && !IsPlayerLockedInPlace() && IsAlive() )
  742. {
  743. HandleAdmireGlovesAnimation();
  744. }
  745. }
  746. void CHL2_Player::StartAdmireGlovesAnimation( void )
  747. {
  748. MDLCACHE_CRITICAL_SECTION();
  749. CBaseViewModel *vm = GetViewModel( 0 );
  750. if ( vm && !GetActiveWeapon() )
  751. {
  752. vm->SetWeaponModel( "models/weapons/v_hands.mdl", NULL );
  753. ShowViewModel( true );
  754. int idealSequence = vm->SelectWeightedSequence( ACT_VM_IDLE );
  755. if ( idealSequence >= 0 )
  756. {
  757. vm->SendViewModelMatchingSequence( idealSequence );
  758. m_flAdmireGlovesAnimTime = gpGlobals->curtime + vm->SequenceDuration( idealSequence );
  759. }
  760. }
  761. }
  762. void CHL2_Player::HandleAdmireGlovesAnimation( void )
  763. {
  764. CBaseViewModel *pVM = GetViewModel();
  765. if ( pVM && pVM->GetOwningWeapon() == NULL )
  766. {
  767. if ( m_flAdmireGlovesAnimTime != 0.0 )
  768. {
  769. if ( m_flAdmireGlovesAnimTime > gpGlobals->curtime )
  770. {
  771. pVM->m_flPlaybackRate = 1.0f;
  772. pVM->StudioFrameAdvance( );
  773. }
  774. else if ( m_flAdmireGlovesAnimTime < gpGlobals->curtime )
  775. {
  776. m_flAdmireGlovesAnimTime = 0.0f;
  777. pVM->SetWeaponModel( NULL, NULL );
  778. }
  779. }
  780. }
  781. else
  782. m_flAdmireGlovesAnimTime = 0.0f;
  783. }
  784. #define HL2PLAYER_RELOADGAME_ATTACK_DELAY 1.0f
  785. void CHL2_Player::Activate( void )
  786. {
  787. BaseClass::Activate();
  788. InitSprinting();
  789. #ifdef HL2_EPISODIC
  790. // Delay attacks by 1 second after loading a game.
  791. if ( GetActiveWeapon() )
  792. {
  793. float flRemaining = GetActiveWeapon()->m_flNextPrimaryAttack - gpGlobals->curtime;
  794. if ( flRemaining < HL2PLAYER_RELOADGAME_ATTACK_DELAY )
  795. {
  796. GetActiveWeapon()->m_flNextPrimaryAttack = gpGlobals->curtime + HL2PLAYER_RELOADGAME_ATTACK_DELAY;
  797. }
  798. flRemaining = GetActiveWeapon()->m_flNextSecondaryAttack - gpGlobals->curtime;
  799. if ( flRemaining < HL2PLAYER_RELOADGAME_ATTACK_DELAY )
  800. {
  801. GetActiveWeapon()->m_flNextSecondaryAttack = gpGlobals->curtime + HL2PLAYER_RELOADGAME_ATTACK_DELAY;
  802. }
  803. }
  804. #endif
  805. GetPlayerProxy();
  806. }
  807. //------------------------------------------------------------------------------
  808. // Purpose :
  809. // Input :
  810. // Output :
  811. //------------------------------------------------------------------------------
  812. Class_T CHL2_Player::Classify ( void )
  813. {
  814. // If player controlling another entity? If so, return this class
  815. if (m_nControlClass != CLASS_NONE)
  816. {
  817. return m_nControlClass;
  818. }
  819. else
  820. {
  821. if(IsInAVehicle())
  822. {
  823. IServerVehicle *pVehicle = GetVehicle();
  824. return pVehicle->ClassifyPassenger( this, CLASS_PLAYER );
  825. }
  826. else
  827. {
  828. return CLASS_PLAYER;
  829. }
  830. }
  831. }
  832. //-----------------------------------------------------------------------------
  833. // Purpose: This is a generic function (to be implemented by sub-classes) to
  834. // handle specific interactions between different types of characters
  835. // (For example the barnacle grabbing an NPC)
  836. // Input : Constant for the type of interaction
  837. // Output : true - if sub-class has a response for the interaction
  838. // false - if sub-class has no response
  839. //-----------------------------------------------------------------------------
  840. bool CHL2_Player::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt)
  841. {
  842. if ( interactionType == g_interactionBarnacleVictimDangle )
  843. return false;
  844. if (interactionType == g_interactionBarnacleVictimReleased)
  845. {
  846. m_afPhysicsFlags &= ~PFLAG_ONBARNACLE;
  847. SetMoveType( MOVETYPE_WALK );
  848. return true;
  849. }
  850. else if (interactionType == g_interactionBarnacleVictimGrab)
  851. {
  852. #ifdef HL2_EPISODIC
  853. CNPC_Alyx *pAlyx = CNPC_Alyx::GetAlyx();
  854. if ( pAlyx )
  855. {
  856. // Make Alyx totally hate this barnacle so that she saves the player.
  857. int priority;
  858. priority = pAlyx->IRelationPriority(sourceEnt);
  859. pAlyx->AddEntityRelationship( sourceEnt, D_HT, priority + 5 );
  860. }
  861. #endif//HL2_EPISODIC
  862. m_afPhysicsFlags |= PFLAG_ONBARNACLE;
  863. ClearUseEntity();
  864. return true;
  865. }
  866. return false;
  867. }
  868. void CHL2_Player::PlayerRunCommand(CUserCmd *ucmd, IMoveHelper *moveHelper)
  869. {
  870. // Handle FL_FROZEN.
  871. if ( m_afPhysicsFlags & PFLAG_ONBARNACLE )
  872. {
  873. ucmd->forwardmove = 0;
  874. ucmd->sidemove = 0;
  875. ucmd->upmove = 0;
  876. ucmd->buttons &= ~IN_USE;
  877. }
  878. // Can't use stuff while dead
  879. if ( IsDead() )
  880. {
  881. ucmd->buttons &= ~IN_USE;
  882. }
  883. //Update our movement information
  884. if ( ( ucmd->forwardmove != 0 ) || ( ucmd->sidemove != 0 ) || ( ucmd->upmove != 0 ) )
  885. {
  886. m_flIdleTime -= TICK_INTERVAL * 2.0f;
  887. if ( m_flIdleTime < 0.0f )
  888. {
  889. m_flIdleTime = 0.0f;
  890. }
  891. m_flMoveTime += TICK_INTERVAL;
  892. if ( m_flMoveTime > 4.0f )
  893. {
  894. m_flMoveTime = 4.0f;
  895. }
  896. }
  897. else
  898. {
  899. m_flIdleTime += TICK_INTERVAL;
  900. if ( m_flIdleTime > 4.0f )
  901. {
  902. m_flIdleTime = 4.0f;
  903. }
  904. m_flMoveTime -= TICK_INTERVAL * 2.0f;
  905. if ( m_flMoveTime < 0.0f )
  906. {
  907. m_flMoveTime = 0.0f;
  908. }
  909. }
  910. //Msg("Player time: [ACTIVE: %f]\t[IDLE: %f]\n", m_flMoveTime, m_flIdleTime );
  911. BaseClass::PlayerRunCommand( ucmd, moveHelper );
  912. }
  913. //-----------------------------------------------------------------------------
  914. // Purpose: Sets HL2 specific defaults.
  915. //-----------------------------------------------------------------------------
  916. void CHL2_Player::Spawn(void)
  917. {
  918. #ifndef HL2MP
  919. #ifndef PORTAL
  920. SetModel( "models/player.mdl" );
  921. #endif
  922. #endif
  923. BaseClass::Spawn();
  924. //
  925. // Our player movement speed is set once here. This will override the cl_xxxx
  926. // cvars unless they are set to be lower than this.
  927. //
  928. //m_flMaxspeed = 320;
  929. if ( !IsSuitEquipped() )
  930. StartWalking();
  931. SuitPower_SetCharge( 100 );
  932. m_Local.m_iHideHUD |= HIDEHUD_CHAT;
  933. m_pPlayerAISquad = g_AI_SquadManager.FindCreateSquad(AllocPooledString(PLAYER_SQUADNAME));
  934. InitSprinting();
  935. // Setup our flashlight values
  936. #ifdef HL2_EPISODIC
  937. m_HL2Local.m_flFlashBattery = 100.0f;
  938. #endif
  939. GetPlayerProxy();
  940. SetFlashlightPowerDrainScale( 1.0f );
  941. }
  942. //-----------------------------------------------------------------------------
  943. //-----------------------------------------------------------------------------
  944. void CHL2_Player::UpdateLocatorPosition( const Vector &vecPosition )
  945. {
  946. #ifdef HL2_EPISODIC
  947. m_HL2Local.m_vecLocatorOrigin = vecPosition;
  948. #endif//HL2_EPISODIC
  949. }
  950. //-----------------------------------------------------------------------------
  951. //-----------------------------------------------------------------------------
  952. void CHL2_Player::InitSprinting( void )
  953. {
  954. StopSprinting();
  955. }
  956. //-----------------------------------------------------------------------------
  957. // Purpose: Returns whether or not we are allowed to sprint now.
  958. //-----------------------------------------------------------------------------
  959. bool CHL2_Player::CanSprint()
  960. {
  961. return ( m_bSprintEnabled && // Only if sprint is enabled
  962. !IsWalking() && // Not if we're walking
  963. !( m_Local.m_bDucked && !m_Local.m_bDucking ) && // Nor if we're ducking
  964. (GetWaterLevel() != 3) && // Certainly not underwater
  965. (GlobalEntity_GetState("suit_no_sprint") != GLOBAL_ON) ); // Out of the question without the sprint module
  966. }
  967. //-----------------------------------------------------------------------------
  968. //-----------------------------------------------------------------------------
  969. void CHL2_Player::StartAutoSprint()
  970. {
  971. if( IsSprinting() )
  972. {
  973. StopSprinting();
  974. }
  975. else
  976. {
  977. StartSprinting();
  978. m_bIsAutoSprinting = true;
  979. m_fAutoSprintMinTime = gpGlobals->curtime + 1.5f;
  980. }
  981. }
  982. //-----------------------------------------------------------------------------
  983. //-----------------------------------------------------------------------------
  984. void CHL2_Player::StartSprinting( void )
  985. {
  986. if( m_HL2Local.m_flSuitPower < 10 )
  987. {
  988. // Don't sprint unless there's a reasonable
  989. // amount of suit power.
  990. // debounce the button for sound playing
  991. if ( m_afButtonPressed & IN_SPEED )
  992. {
  993. CPASAttenuationFilter filter( this );
  994. filter.UsePredictionRules();
  995. EmitSound( filter, entindex(), "HL2Player.SprintNoPower" );
  996. }
  997. return;
  998. }
  999. if( !SuitPower_AddDevice( SuitDeviceSprint ) )
  1000. return;
  1001. CPASAttenuationFilter filter( this );
  1002. filter.UsePredictionRules();
  1003. EmitSound( filter, entindex(), "HL2Player.SprintStart" );
  1004. SetMaxSpeed( HL2_SPRINT_SPEED );
  1005. m_fIsSprinting = true;
  1006. }
  1007. //-----------------------------------------------------------------------------
  1008. //-----------------------------------------------------------------------------
  1009. void CHL2_Player::StopSprinting( void )
  1010. {
  1011. if ( m_HL2Local.m_bitsActiveDevices & SuitDeviceSprint.GetDeviceID() )
  1012. {
  1013. SuitPower_RemoveDevice( SuitDeviceSprint );
  1014. }
  1015. if( IsSuitEquipped() )
  1016. {
  1017. SetMaxSpeed( HL2_NORM_SPEED );
  1018. }
  1019. else
  1020. {
  1021. SetMaxSpeed( HL2_WALK_SPEED );
  1022. }
  1023. m_fIsSprinting = false;
  1024. if ( sv_stickysprint.GetBool() )
  1025. {
  1026. m_bIsAutoSprinting = false;
  1027. m_fAutoSprintMinTime = 0.0f;
  1028. }
  1029. }
  1030. //-----------------------------------------------------------------------------
  1031. // Purpose: Called to disable and enable sprint due to temporary circumstances:
  1032. // - Carrying a heavy object with the physcannon
  1033. //-----------------------------------------------------------------------------
  1034. void CHL2_Player::EnableSprint( bool bEnable )
  1035. {
  1036. if ( !bEnable && IsSprinting() )
  1037. {
  1038. StopSprinting();
  1039. }
  1040. m_bSprintEnabled = bEnable;
  1041. }
  1042. //-----------------------------------------------------------------------------
  1043. //-----------------------------------------------------------------------------
  1044. void CHL2_Player::StartWalking( void )
  1045. {
  1046. SetMaxSpeed( HL2_WALK_SPEED );
  1047. m_fIsWalking = true;
  1048. }
  1049. //-----------------------------------------------------------------------------
  1050. //-----------------------------------------------------------------------------
  1051. void CHL2_Player::StopWalking( void )
  1052. {
  1053. SetMaxSpeed( HL2_NORM_SPEED );
  1054. m_fIsWalking = false;
  1055. }
  1056. //-----------------------------------------------------------------------------
  1057. // Purpose:
  1058. // Output : Returns true on success, false on failure.
  1059. //-----------------------------------------------------------------------------
  1060. bool CHL2_Player::CanZoom( CBaseEntity *pRequester )
  1061. {
  1062. if ( IsZooming() )
  1063. return false;
  1064. //Check our weapon
  1065. return true;
  1066. }
  1067. //-----------------------------------------------------------------------------
  1068. //-----------------------------------------------------------------------------
  1069. void CHL2_Player::ToggleZoom(void)
  1070. {
  1071. if( IsZooming() )
  1072. {
  1073. StopZooming();
  1074. }
  1075. else
  1076. {
  1077. StartZooming();
  1078. }
  1079. }
  1080. //-----------------------------------------------------------------------------
  1081. // Purpose: +zoom suit zoom
  1082. //-----------------------------------------------------------------------------
  1083. void CHL2_Player::StartZooming( void )
  1084. {
  1085. int iFOV = 25;
  1086. if ( SetFOV( this, iFOV, 0.4f ) )
  1087. {
  1088. m_HL2Local.m_bZooming = true;
  1089. }
  1090. }
  1091. //-----------------------------------------------------------------------------
  1092. // Purpose:
  1093. //-----------------------------------------------------------------------------
  1094. void CHL2_Player::StopZooming( void )
  1095. {
  1096. int iFOV = GetZoomOwnerDesiredFOV( m_hZoomOwner );
  1097. if ( SetFOV( this, iFOV, 0.2f ) )
  1098. {
  1099. m_HL2Local.m_bZooming = false;
  1100. }
  1101. }
  1102. //-----------------------------------------------------------------------------
  1103. // Purpose:
  1104. // Output : Returns true on success, false on failure.
  1105. //-----------------------------------------------------------------------------
  1106. bool CHL2_Player::IsZooming( void )
  1107. {
  1108. if ( m_hZoomOwner != NULL )
  1109. return true;
  1110. return false;
  1111. }
  1112. class CPhysicsPlayerCallback : public IPhysicsPlayerControllerEvent
  1113. {
  1114. public:
  1115. int ShouldMoveTo( IPhysicsObject *pObject, const Vector &position )
  1116. {
  1117. CHL2_Player *pPlayer = (CHL2_Player *)pObject->GetGameData();
  1118. if ( pPlayer )
  1119. {
  1120. if ( pPlayer->TouchedPhysics() )
  1121. {
  1122. return 0;
  1123. }
  1124. }
  1125. return 1;
  1126. }
  1127. };
  1128. static CPhysicsPlayerCallback playerCallback;
  1129. //-----------------------------------------------------------------------------
  1130. // Purpose:
  1131. //-----------------------------------------------------------------------------
  1132. void CHL2_Player::InitVCollision( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity )
  1133. {
  1134. BaseClass::InitVCollision( vecAbsOrigin, vecAbsVelocity );
  1135. // Setup the HL2 specific callback.
  1136. IPhysicsPlayerController *pPlayerController = GetPhysicsController();
  1137. if ( pPlayerController )
  1138. {
  1139. pPlayerController->SetEventHandler( &playerCallback );
  1140. }
  1141. }
  1142. CHL2_Player::~CHL2_Player( void )
  1143. {
  1144. }
  1145. //-----------------------------------------------------------------------------
  1146. //-----------------------------------------------------------------------------
  1147. bool CHL2_Player::CommanderFindGoal( commandgoal_t *pGoal )
  1148. {
  1149. CAI_BaseNPC *pAllyNpc;
  1150. trace_t tr;
  1151. Vector vecTarget;
  1152. Vector forward;
  1153. EyeVectors( &forward );
  1154. //---------------------------------
  1155. // MASK_SHOT on purpose! So that you don't hit the invisible hulls of the NPCs.
  1156. CTraceFilterSkipTwoEntities filter( this, PhysCannonGetHeldEntity( GetActiveWeapon() ), COLLISION_GROUP_INTERACTIVE_DEBRIS );
  1157. UTIL_TraceLine( EyePosition(), EyePosition() + forward * MAX_COORD_RANGE, MASK_SHOT, &filter, &tr );
  1158. if( !tr.DidHitWorld() )
  1159. {
  1160. CUtlVector<CAI_BaseNPC *> Allies;
  1161. AISquadIter_t iter;
  1162. for ( pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) )
  1163. {
  1164. if ( pAllyNpc->IsCommandable() )
  1165. Allies.AddToTail( pAllyNpc );
  1166. }
  1167. for( int i = 0 ; i < Allies.Count() ; i++ )
  1168. {
  1169. if( Allies[ i ]->IsValidCommandTarget( tr.m_pEnt ) )
  1170. {
  1171. pGoal->m_pGoalEntity = tr.m_pEnt;
  1172. return true;
  1173. }
  1174. }
  1175. }
  1176. if( tr.fraction == 1.0 || (tr.surface.flags & SURF_SKY) )
  1177. {
  1178. // Move commands invalid against skybox.
  1179. pGoal->m_vecGoalLocation = tr.endpos;
  1180. return false;
  1181. }
  1182. if ( tr.m_pEnt->IsNPC() && ((CAI_BaseNPC *)(tr.m_pEnt))->IsCommandable() )
  1183. {
  1184. pGoal->m_vecGoalLocation = tr.m_pEnt->GetAbsOrigin();
  1185. }
  1186. else
  1187. {
  1188. vecTarget = tr.endpos;
  1189. Vector mins( -16, -16, 0 );
  1190. Vector maxs( 16, 16, 0 );
  1191. // Back up from whatever we hit so that there's enough space at the
  1192. // target location for a bounding box.
  1193. // Now trace down.
  1194. //UTIL_TraceLine( vecTarget, vecTarget - Vector( 0, 0, 8192 ), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
  1195. UTIL_TraceHull( vecTarget + tr.plane.normal * 24,
  1196. vecTarget - Vector( 0, 0, 8192 ),
  1197. mins,
  1198. maxs,
  1199. MASK_SOLID_BRUSHONLY,
  1200. this,
  1201. COLLISION_GROUP_NONE,
  1202. &tr );
  1203. if ( !tr.startsolid )
  1204. pGoal->m_vecGoalLocation = tr.endpos;
  1205. else
  1206. pGoal->m_vecGoalLocation = vecTarget;
  1207. }
  1208. pAllyNpc = GetSquadCommandRepresentative();
  1209. if ( !pAllyNpc )
  1210. return false;
  1211. vecTarget = pGoal->m_vecGoalLocation;
  1212. if ( !pAllyNpc->FindNearestValidGoalPos( vecTarget, &pGoal->m_vecGoalLocation ) )
  1213. return false;
  1214. return ( ( vecTarget - pGoal->m_vecGoalLocation ).LengthSqr() < Square( 15*12 ) );
  1215. }
  1216. //-----------------------------------------------------------------------------
  1217. //-----------------------------------------------------------------------------
  1218. CAI_BaseNPC *CHL2_Player::GetSquadCommandRepresentative()
  1219. {
  1220. if ( m_pPlayerAISquad != NULL )
  1221. {
  1222. CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember();
  1223. if ( pAllyNpc )
  1224. {
  1225. return pAllyNpc->GetSquadCommandRepresentative();
  1226. }
  1227. }
  1228. return NULL;
  1229. }
  1230. //-----------------------------------------------------------------------------
  1231. //-----------------------------------------------------------------------------
  1232. int CHL2_Player::GetNumSquadCommandables()
  1233. {
  1234. AISquadIter_t iter;
  1235. int c = 0;
  1236. for ( CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) )
  1237. {
  1238. if ( pAllyNpc->IsCommandable() )
  1239. c++;
  1240. }
  1241. return c;
  1242. }
  1243. //-----------------------------------------------------------------------------
  1244. //-----------------------------------------------------------------------------
  1245. int CHL2_Player::GetNumSquadCommandableMedics()
  1246. {
  1247. AISquadIter_t iter;
  1248. int c = 0;
  1249. for ( CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) )
  1250. {
  1251. if ( pAllyNpc->IsCommandable() && pAllyNpc->IsMedic() )
  1252. c++;
  1253. }
  1254. return c;
  1255. }
  1256. //-----------------------------------------------------------------------------
  1257. //-----------------------------------------------------------------------------
  1258. void CHL2_Player::CommanderUpdate()
  1259. {
  1260. CAI_BaseNPC *pCommandRepresentative = GetSquadCommandRepresentative();
  1261. bool bFollowMode = false;
  1262. if ( pCommandRepresentative )
  1263. {
  1264. bFollowMode = ( pCommandRepresentative->GetCommandGoal() == vec3_invalid );
  1265. // set the variables for network transmission (to show on the hud)
  1266. m_HL2Local.m_iSquadMemberCount = GetNumSquadCommandables();
  1267. m_HL2Local.m_iSquadMedicCount = GetNumSquadCommandableMedics();
  1268. m_HL2Local.m_fSquadInFollowMode = bFollowMode;
  1269. // debugging code for displaying extra squad indicators
  1270. /*
  1271. char *pszMoving = "";
  1272. AISquadIter_t iter;
  1273. for ( CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) )
  1274. {
  1275. if ( pAllyNpc->IsCommandMoving() )
  1276. {
  1277. pszMoving = "<-";
  1278. break;
  1279. }
  1280. }
  1281. NDebugOverlay::ScreenText(
  1282. 0.932, 0.919,
  1283. CFmtStr( "%d|%c%s", GetNumSquadCommandables(), ( bFollowMode ) ? 'F' : 'S', pszMoving ),
  1284. 255, 128, 0, 128,
  1285. 0 );
  1286. */
  1287. }
  1288. else
  1289. {
  1290. m_HL2Local.m_iSquadMemberCount = 0;
  1291. m_HL2Local.m_iSquadMedicCount = 0;
  1292. m_HL2Local.m_fSquadInFollowMode = true;
  1293. }
  1294. if ( m_QueuedCommand != CC_NONE && ( m_QueuedCommand == CC_FOLLOW || gpGlobals->realtime - m_RealTimeLastSquadCommand >= player_squad_double_tap_time.GetFloat() ) )
  1295. {
  1296. CommanderExecute( m_QueuedCommand );
  1297. m_QueuedCommand = CC_NONE;
  1298. }
  1299. else if ( !bFollowMode && pCommandRepresentative && m_CommanderUpdateTimer.Expired() && player_squad_transient_commands.GetBool() )
  1300. {
  1301. m_CommanderUpdateTimer.Set(2.5);
  1302. if ( pCommandRepresentative->ShouldAutoSummon() )
  1303. CommanderExecute( CC_FOLLOW );
  1304. }
  1305. }
  1306. //-----------------------------------------------------------------------------
  1307. // Purpose:
  1308. //
  1309. // bHandled - indicates whether to continue delivering this order to
  1310. // all allies. Allows us to stop delivering certain types of orders once we find
  1311. // a suitable candidate. (like picking up a single weapon. We don't wish for
  1312. // all allies to respond and try to pick up one weapon).
  1313. //-----------------------------------------------------------------------------
  1314. bool CHL2_Player::CommanderExecuteOne( CAI_BaseNPC *pNpc, const commandgoal_t &goal, CAI_BaseNPC **Allies, int numAllies )
  1315. {
  1316. if ( goal.m_pGoalEntity )
  1317. {
  1318. return pNpc->TargetOrder( goal.m_pGoalEntity, Allies, numAllies );
  1319. }
  1320. else if ( pNpc->IsInPlayerSquad() )
  1321. {
  1322. pNpc->MoveOrder( goal.m_vecGoalLocation, Allies, numAllies );
  1323. }
  1324. return true;
  1325. }
  1326. //---------------------------------------------------------
  1327. //---------------------------------------------------------
  1328. void CHL2_Player::CommanderExecute( CommanderCommand_t command )
  1329. {
  1330. CAI_BaseNPC *pPlayerSquadLeader = GetSquadCommandRepresentative();
  1331. if ( !pPlayerSquadLeader )
  1332. {
  1333. EmitSound( "HL2Player.UseDeny" );
  1334. return;
  1335. }
  1336. int i;
  1337. CUtlVector<CAI_BaseNPC *> Allies;
  1338. commandgoal_t goal;
  1339. if ( command == CC_TOGGLE )
  1340. {
  1341. if ( pPlayerSquadLeader->GetCommandGoal() != vec3_invalid )
  1342. command = CC_FOLLOW;
  1343. else
  1344. command = CC_SEND;
  1345. }
  1346. else
  1347. {
  1348. if ( command == CC_FOLLOW && pPlayerSquadLeader->GetCommandGoal() == vec3_invalid )
  1349. return;
  1350. }
  1351. if ( command == CC_FOLLOW )
  1352. {
  1353. goal.m_pGoalEntity = this;
  1354. goal.m_vecGoalLocation = vec3_invalid;
  1355. }
  1356. else
  1357. {
  1358. goal.m_pGoalEntity = NULL;
  1359. goal.m_vecGoalLocation = vec3_invalid;
  1360. // Find a goal for ourselves.
  1361. if( !CommanderFindGoal( &goal ) )
  1362. {
  1363. EmitSound( "HL2Player.UseDeny" );
  1364. return; // just keep following
  1365. }
  1366. }
  1367. #ifdef _DEBUG
  1368. if( goal.m_pGoalEntity == NULL && goal.m_vecGoalLocation == vec3_invalid )
  1369. {
  1370. DevMsg( 1, "**ERROR: Someone sent an invalid goal to CommanderExecute!\n" );
  1371. }
  1372. #endif // _DEBUG
  1373. AISquadIter_t iter;
  1374. for ( CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) )
  1375. {
  1376. if ( pAllyNpc->IsCommandable() )
  1377. Allies.AddToTail( pAllyNpc );
  1378. }
  1379. //---------------------------------
  1380. // If the trace hits an NPC, send all ally NPCs a "target" order. Always
  1381. // goes to targeted one first
  1382. #ifdef DBGFLAG_ASSERT
  1383. int nAIs = g_AI_Manager.NumAIs();
  1384. #endif
  1385. CAI_BaseNPC * pTargetNpc = (goal.m_pGoalEntity) ? goal.m_pGoalEntity->MyNPCPointer() : NULL;
  1386. bool bHandled = false;
  1387. if( pTargetNpc )
  1388. {
  1389. bHandled = !CommanderExecuteOne( pTargetNpc, goal, Allies.Base(), Allies.Count() );
  1390. }
  1391. for ( i = 0; !bHandled && i < Allies.Count(); i++ )
  1392. {
  1393. if ( Allies[i] != pTargetNpc && Allies[i]->IsPlayerAlly() )
  1394. {
  1395. bHandled = !CommanderExecuteOne( Allies[i], goal, Allies.Base(), Allies.Count() );
  1396. }
  1397. Assert( nAIs == g_AI_Manager.NumAIs() ); // not coded to support mutating set of NPCs
  1398. }
  1399. }
  1400. //-----------------------------------------------------------------------------
  1401. // Enter/exit commander mode, manage ally selection.
  1402. //-----------------------------------------------------------------------------
  1403. void CHL2_Player::CommanderMode()
  1404. {
  1405. float commandInterval = gpGlobals->realtime - m_RealTimeLastSquadCommand;
  1406. m_RealTimeLastSquadCommand = gpGlobals->realtime;
  1407. if ( commandInterval < player_squad_double_tap_time.GetFloat() )
  1408. {
  1409. m_QueuedCommand = CC_FOLLOW;
  1410. }
  1411. else
  1412. {
  1413. m_QueuedCommand = (player_squad_transient_commands.GetBool()) ? CC_SEND : CC_TOGGLE;
  1414. }
  1415. }
  1416. //-----------------------------------------------------------------------------
  1417. // Purpose:
  1418. // Input : iImpulse -
  1419. //-----------------------------------------------------------------------------
  1420. void CHL2_Player::CheatImpulseCommands( int iImpulse )
  1421. {
  1422. switch( iImpulse )
  1423. {
  1424. case 50:
  1425. {
  1426. CommanderMode();
  1427. break;
  1428. }
  1429. case 51:
  1430. {
  1431. // Cheat to create a dynamic resupply item
  1432. Vector vecForward;
  1433. AngleVectors( EyeAngles(), &vecForward );
  1434. CBaseEntity *pItem = (CBaseEntity *)CreateEntityByName( "item_dynamic_resupply" );
  1435. if ( pItem )
  1436. {
  1437. Vector vecOrigin = GetAbsOrigin() + vecForward * 256 + Vector(0,0,64);
  1438. QAngle vecAngles( 0, GetAbsAngles().y - 90, 0 );
  1439. pItem->SetAbsOrigin( vecOrigin );
  1440. pItem->SetAbsAngles( vecAngles );
  1441. pItem->KeyValue( "targetname", "resupply" );
  1442. pItem->Spawn();
  1443. pItem->Activate();
  1444. }
  1445. break;
  1446. }
  1447. case 52:
  1448. {
  1449. // Rangefinder
  1450. trace_t tr;
  1451. UTIL_TraceLine( EyePosition(), EyePosition() + EyeDirection3D() * MAX_COORD_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  1452. if( tr.fraction != 1.0 )
  1453. {
  1454. float flDist = (tr.startpos - tr.endpos).Length();
  1455. float flDist2D = (tr.startpos - tr.endpos).Length2D();
  1456. DevMsg( 1,"\nStartPos: %.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 );
  1457. DevMsg( 1,"3D Distance: %.4f units (%.2f feet) --- 2D Distance: %.4f units (%.2f feet)\n", flDist, flDist / 12.0, flDist2D, flDist2D / 12.0 );
  1458. }
  1459. break;
  1460. }
  1461. default:
  1462. BaseClass::CheatImpulseCommands( iImpulse );
  1463. }
  1464. }
  1465. //-----------------------------------------------------------------------------
  1466. // Purpose:
  1467. //-----------------------------------------------------------------------------
  1468. void CHL2_Player::SetupVisibility( CBaseEntity *pViewEntity, unsigned char *pvs, int pvssize )
  1469. {
  1470. BaseClass::SetupVisibility( pViewEntity, pvs, pvssize );
  1471. int area = pViewEntity ? pViewEntity->NetworkProp()->AreaNum() : NetworkProp()->AreaNum();
  1472. PointCameraSetupVisibility( this, area, pvs, pvssize );
  1473. // If the intro script is playing, we want to get it's visibility points
  1474. if ( g_hIntroScript )
  1475. {
  1476. Vector vecOrigin;
  1477. CBaseEntity *pCamera;
  1478. if ( g_hIntroScript->GetIncludedPVSOrigin( &vecOrigin, &pCamera ) )
  1479. {
  1480. // If it's a point camera, turn it on
  1481. CPointCamera *pPointCamera = dynamic_cast< CPointCamera* >(pCamera);
  1482. if ( pPointCamera )
  1483. {
  1484. pPointCamera->SetActive( true );
  1485. }
  1486. engine->AddOriginToPVS( vecOrigin );
  1487. }
  1488. }
  1489. }
  1490. //-----------------------------------------------------------------------------
  1491. //-----------------------------------------------------------------------------
  1492. void CHL2_Player::SuitPower_Update( void )
  1493. {
  1494. if( SuitPower_ShouldRecharge() )
  1495. {
  1496. SuitPower_Charge( SUITPOWER_CHARGE_RATE * gpGlobals->frametime );
  1497. }
  1498. else if( m_HL2Local.m_bitsActiveDevices )
  1499. {
  1500. float flPowerLoad = m_flSuitPowerLoad;
  1501. //Since stickysprint quickly shuts off sprint if it isn't being used, this isn't an issue.
  1502. if ( !sv_stickysprint.GetBool() )
  1503. {
  1504. if( SuitPower_IsDeviceActive(SuitDeviceSprint) )
  1505. {
  1506. if( !fabs(GetAbsVelocity().x) && !fabs(GetAbsVelocity().y) )
  1507. {
  1508. // If player's not moving, don't drain sprint juice.
  1509. flPowerLoad -= SuitDeviceSprint.GetDeviceDrainRate();
  1510. }
  1511. }
  1512. }
  1513. if( SuitPower_IsDeviceActive(SuitDeviceFlashlight) )
  1514. {
  1515. float factor;
  1516. factor = 1.0f / m_flFlashlightPowerDrainScale;
  1517. flPowerLoad -= ( SuitDeviceFlashlight.GetDeviceDrainRate() * (1.0f - factor) );
  1518. }
  1519. if( !SuitPower_Drain( flPowerLoad * gpGlobals->frametime ) )
  1520. {
  1521. // TURN OFF ALL DEVICES!!
  1522. if( IsSprinting() )
  1523. {
  1524. StopSprinting();
  1525. }
  1526. if ( Flashlight_UseLegacyVersion() )
  1527. {
  1528. if( FlashlightIsOn() )
  1529. {
  1530. #ifndef HL2MP
  1531. FlashlightTurnOff();
  1532. #endif
  1533. }
  1534. }
  1535. }
  1536. if ( Flashlight_UseLegacyVersion() )
  1537. {
  1538. // turn off flashlight a little bit after it hits below one aux power notch (5%)
  1539. if( m_HL2Local.m_flSuitPower < 4.8f && FlashlightIsOn() )
  1540. {
  1541. #ifndef HL2MP
  1542. FlashlightTurnOff();
  1543. #endif
  1544. }
  1545. }
  1546. }
  1547. }
  1548. //-----------------------------------------------------------------------------
  1549. // Charge battery fully, turn off all devices.
  1550. //-----------------------------------------------------------------------------
  1551. void CHL2_Player::SuitPower_Initialize( void )
  1552. {
  1553. m_HL2Local.m_bitsActiveDevices = 0x00000000;
  1554. m_HL2Local.m_flSuitPower = 100.0;
  1555. m_flSuitPowerLoad = 0.0;
  1556. }
  1557. //-----------------------------------------------------------------------------
  1558. // Purpose: Interface to drain power from the suit's power supply.
  1559. // Input: Amount of charge to remove (expressed as percentage of full charge)
  1560. // Output: Returns TRUE if successful, FALSE if not enough power available.
  1561. //-----------------------------------------------------------------------------
  1562. bool CHL2_Player::SuitPower_Drain( float flPower )
  1563. {
  1564. // Suitpower cheat on?
  1565. if ( sv_infinite_aux_power.GetBool() )
  1566. return true;
  1567. m_HL2Local.m_flSuitPower -= flPower;
  1568. if( m_HL2Local.m_flSuitPower < 0.0 )
  1569. {
  1570. // Power is depleted!
  1571. // Clamp and fail
  1572. m_HL2Local.m_flSuitPower = 0.0;
  1573. return false;
  1574. }
  1575. return true;
  1576. }
  1577. //-----------------------------------------------------------------------------
  1578. // Purpose: Interface to add power to the suit's power supply
  1579. // Input: Amount of charge to add
  1580. //-----------------------------------------------------------------------------
  1581. void CHL2_Player::SuitPower_Charge( float flPower )
  1582. {
  1583. m_HL2Local.m_flSuitPower += flPower;
  1584. if( m_HL2Local.m_flSuitPower > 100.0 )
  1585. {
  1586. // Full charge, clamp.
  1587. m_HL2Local.m_flSuitPower = 100.0;
  1588. }
  1589. }
  1590. //-----------------------------------------------------------------------------
  1591. //-----------------------------------------------------------------------------
  1592. bool CHL2_Player::SuitPower_IsDeviceActive( const CSuitPowerDevice &device )
  1593. {
  1594. return (m_HL2Local.m_bitsActiveDevices & device.GetDeviceID()) != 0;
  1595. }
  1596. //-----------------------------------------------------------------------------
  1597. //-----------------------------------------------------------------------------
  1598. bool CHL2_Player::SuitPower_AddDevice( const CSuitPowerDevice &device )
  1599. {
  1600. // Make sure this device is NOT active!!
  1601. if( m_HL2Local.m_bitsActiveDevices & device.GetDeviceID() )
  1602. return false;
  1603. if( !IsSuitEquipped() )
  1604. return false;
  1605. m_HL2Local.m_bitsActiveDevices |= device.GetDeviceID();
  1606. m_flSuitPowerLoad += device.GetDeviceDrainRate();
  1607. return true;
  1608. }
  1609. //-----------------------------------------------------------------------------
  1610. //-----------------------------------------------------------------------------
  1611. bool CHL2_Player::SuitPower_RemoveDevice( const CSuitPowerDevice &device )
  1612. {
  1613. // Make sure this device is active!!
  1614. if( ! (m_HL2Local.m_bitsActiveDevices & device.GetDeviceID()) )
  1615. return false;
  1616. if( !IsSuitEquipped() )
  1617. return false;
  1618. // Take a little bit of suit power when you disable a device. If the device is shutting off
  1619. // because the battery is drained, no harm done, the battery charge cannot go below 0.
  1620. // This code in combination with the delay before the suit can start recharging are a defense
  1621. // against exploits where the player could rapidly tap sprint and never run out of power.
  1622. SuitPower_Drain( device.GetDeviceDrainRate() * 0.1f );
  1623. m_HL2Local.m_bitsActiveDevices &= ~device.GetDeviceID();
  1624. m_flSuitPowerLoad -= device.GetDeviceDrainRate();
  1625. if( m_HL2Local.m_bitsActiveDevices == 0x00000000 )
  1626. {
  1627. // With this device turned off, we can set this timer which tells us when the
  1628. // suit power system entered a no-load state.
  1629. m_flTimeAllSuitDevicesOff = gpGlobals->curtime;
  1630. }
  1631. return true;
  1632. }
  1633. //-----------------------------------------------------------------------------
  1634. //-----------------------------------------------------------------------------
  1635. #define SUITPOWER_BEGIN_RECHARGE_DELAY 0.5f
  1636. bool CHL2_Player::SuitPower_ShouldRecharge( void )
  1637. {
  1638. // Make sure all devices are off.
  1639. if( m_HL2Local.m_bitsActiveDevices != 0x00000000 )
  1640. return false;
  1641. // Is the system fully charged?
  1642. if( m_HL2Local.m_flSuitPower >= 100.0f )
  1643. return false;
  1644. // Has the system been in a no-load state for long enough
  1645. // to begin recharging?
  1646. if( gpGlobals->curtime < m_flTimeAllSuitDevicesOff + SUITPOWER_BEGIN_RECHARGE_DELAY )
  1647. return false;
  1648. return true;
  1649. }
  1650. //-----------------------------------------------------------------------------
  1651. //-----------------------------------------------------------------------------
  1652. ConVar sk_battery( "sk_battery","0" );
  1653. bool CHL2_Player::ApplyBattery( float powerMultiplier )
  1654. {
  1655. const float MAX_NORMAL_BATTERY = 100;
  1656. if ((ArmorValue() < MAX_NORMAL_BATTERY) && IsSuitEquipped())
  1657. {
  1658. int pct;
  1659. char szcharge[64];
  1660. IncrementArmorValue( sk_battery.GetFloat() * powerMultiplier, MAX_NORMAL_BATTERY );
  1661. CPASAttenuationFilter filter( this, "ItemBattery.Touch" );
  1662. EmitSound( filter, entindex(), "ItemBattery.Touch" );
  1663. CSingleUserRecipientFilter user( this );
  1664. user.MakeReliable();
  1665. UserMessageBegin( user, "ItemPickup" );
  1666. WRITE_STRING( "item_battery" );
  1667. MessageEnd();
  1668. // Suit reports new power level
  1669. // For some reason this wasn't working in release build -- round it.
  1670. pct = (int)( (float)(ArmorValue() * 100.0) * (1.0/MAX_NORMAL_BATTERY) + 0.5);
  1671. pct = (pct / 5);
  1672. if (pct > 0)
  1673. pct--;
  1674. Q_snprintf( szcharge,sizeof(szcharge),"!HEV_%1dP", pct );
  1675. //UTIL_EmitSoundSuit(edict(), szcharge);
  1676. //SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC);
  1677. return true;
  1678. }
  1679. return false;
  1680. }
  1681. //-----------------------------------------------------------------------------
  1682. //-----------------------------------------------------------------------------
  1683. int CHL2_Player::FlashlightIsOn( void )
  1684. {
  1685. return IsEffectActive( EF_DIMLIGHT );
  1686. }
  1687. //-----------------------------------------------------------------------------
  1688. //-----------------------------------------------------------------------------
  1689. void CHL2_Player::FlashlightTurnOn( void )
  1690. {
  1691. if( m_bFlashlightDisabled )
  1692. return;
  1693. if ( Flashlight_UseLegacyVersion() )
  1694. {
  1695. if( !SuitPower_AddDevice( SuitDeviceFlashlight ) )
  1696. return;
  1697. }
  1698. #ifdef HL2_DLL
  1699. if( !IsSuitEquipped() )
  1700. return;
  1701. #endif
  1702. AddEffects( EF_DIMLIGHT );
  1703. EmitSound( "HL2Player.FlashLightOn" );
  1704. variant_t flashlighton;
  1705. flashlighton.SetFloat( m_HL2Local.m_flSuitPower / 100.0f );
  1706. FirePlayerProxyOutput( "OnFlashlightOn", flashlighton, this, this );
  1707. }
  1708. //-----------------------------------------------------------------------------
  1709. //-----------------------------------------------------------------------------
  1710. void CHL2_Player::FlashlightTurnOff( void )
  1711. {
  1712. if ( Flashlight_UseLegacyVersion() )
  1713. {
  1714. if( !SuitPower_RemoveDevice( SuitDeviceFlashlight ) )
  1715. return;
  1716. }
  1717. RemoveEffects( EF_DIMLIGHT );
  1718. EmitSound( "HL2Player.FlashLightOff" );
  1719. variant_t flashlightoff;
  1720. flashlightoff.SetFloat( m_HL2Local.m_flSuitPower / 100.0f );
  1721. FirePlayerProxyOutput( "OnFlashlightOff", flashlightoff, this, this );
  1722. }
  1723. //-----------------------------------------------------------------------------
  1724. //-----------------------------------------------------------------------------
  1725. #define FLASHLIGHT_RANGE Square(600)
  1726. bool CHL2_Player::IsIlluminatedByFlashlight( CBaseEntity *pEntity, float *flReturnDot )
  1727. {
  1728. if( !FlashlightIsOn() )
  1729. return false;
  1730. if( pEntity->Classify() == CLASS_BARNACLE && pEntity->GetEnemy() == this )
  1731. {
  1732. // As long as my flashlight is on, the barnacle that's pulling me in is considered illuminated.
  1733. // This is because players often shine their flashlights at Alyx when they are in a barnacle's
  1734. // grasp, and wonder why Alyx isn't helping. Alyx isn't helping because the light isn't pointed
  1735. // at the barnacle. This will allow Alyx to see the barnacle no matter which way the light is pointed.
  1736. return true;
  1737. }
  1738. // Within 50 feet?
  1739. float flDistSqr = GetAbsOrigin().DistToSqr(pEntity->GetAbsOrigin());
  1740. if( flDistSqr > FLASHLIGHT_RANGE )
  1741. return false;
  1742. // Within 45 degrees?
  1743. Vector vecSpot = pEntity->WorldSpaceCenter();
  1744. Vector los;
  1745. // If the eyeposition is too close, move it back. Solves problems
  1746. // caused by the player being too close the target.
  1747. if ( flDistSqr < (128 * 128) )
  1748. {
  1749. Vector vecForward;
  1750. EyeVectors( &vecForward );
  1751. Vector vecMovedEyePos = EyePosition() - (vecForward * 128);
  1752. los = ( vecSpot - vecMovedEyePos );
  1753. }
  1754. else
  1755. {
  1756. los = ( vecSpot - EyePosition() );
  1757. }
  1758. VectorNormalize( los );
  1759. Vector facingDir = EyeDirection3D( );
  1760. float flDot = DotProduct( los, facingDir );
  1761. if ( flReturnDot )
  1762. {
  1763. *flReturnDot = flDot;
  1764. }
  1765. if ( flDot < 0.92387f )
  1766. return false;
  1767. if( !FVisible(pEntity) )
  1768. return false;
  1769. return true;
  1770. }
  1771. //-----------------------------------------------------------------------------
  1772. // Purpose: Let NPCs know when the flashlight is trained on them
  1773. //-----------------------------------------------------------------------------
  1774. void CHL2_Player::CheckFlashlight( void )
  1775. {
  1776. if ( !FlashlightIsOn() )
  1777. return;
  1778. if ( m_flNextFlashlightCheckTime > gpGlobals->curtime )
  1779. return;
  1780. m_flNextFlashlightCheckTime = gpGlobals->curtime + FLASHLIGHT_NPC_CHECK_INTERVAL;
  1781. // Loop through NPCs looking for illuminated ones
  1782. for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ )
  1783. {
  1784. CAI_BaseNPC *pNPC = g_AI_Manager.AccessAIs()[i];
  1785. float flDot;
  1786. if ( IsIlluminatedByFlashlight( pNPC, &flDot ) )
  1787. {
  1788. pNPC->PlayerHasIlluminatedNPC( this, flDot );
  1789. }
  1790. }
  1791. }
  1792. //-----------------------------------------------------------------------------
  1793. //-----------------------------------------------------------------------------
  1794. void CHL2_Player::SetPlayerUnderwater( bool state )
  1795. {
  1796. if ( state )
  1797. {
  1798. SuitPower_AddDevice( SuitDeviceBreather );
  1799. }
  1800. else
  1801. {
  1802. SuitPower_RemoveDevice( SuitDeviceBreather );
  1803. }
  1804. BaseClass::SetPlayerUnderwater( state );
  1805. }
  1806. //-----------------------------------------------------------------------------
  1807. bool CHL2_Player::PassesDamageFilter( const CTakeDamageInfo &info )
  1808. {
  1809. CBaseEntity *pAttacker = info.GetAttacker();
  1810. if( pAttacker && pAttacker->MyNPCPointer() && pAttacker->MyNPCPointer()->IsPlayerAlly() )
  1811. {
  1812. return false;
  1813. }
  1814. if( m_hPlayerProxy && !m_hPlayerProxy->PassesDamageFilter( info ) )
  1815. {
  1816. return false;
  1817. }
  1818. return BaseClass::PassesDamageFilter( info );
  1819. }
  1820. //-----------------------------------------------------------------------------
  1821. // Purpose:
  1822. //-----------------------------------------------------------------------------
  1823. void CHL2_Player::SetFlashlightEnabled( bool bState )
  1824. {
  1825. m_bFlashlightDisabled = !bState;
  1826. }
  1827. //-----------------------------------------------------------------------------
  1828. //-----------------------------------------------------------------------------
  1829. void CHL2_Player::InputDisableFlashlight( inputdata_t &inputdata )
  1830. {
  1831. if( FlashlightIsOn() )
  1832. FlashlightTurnOff();
  1833. SetFlashlightEnabled( false );
  1834. }
  1835. //-----------------------------------------------------------------------------
  1836. //-----------------------------------------------------------------------------
  1837. void CHL2_Player::InputEnableFlashlight( inputdata_t &inputdata )
  1838. {
  1839. SetFlashlightEnabled( true );
  1840. }
  1841. //-----------------------------------------------------------------------------
  1842. // Purpose: Prevent the player from taking fall damage for [n] seconds, but
  1843. // reset back to taking fall damage after the first impact (so players will be
  1844. // hurt if they bounce off what they hit). This is the original behavior.
  1845. //-----------------------------------------------------------------------------
  1846. void CHL2_Player::InputIgnoreFallDamage( inputdata_t &inputdata )
  1847. {
  1848. float timeToIgnore = inputdata.value.Float();
  1849. if ( timeToIgnore <= 0.0 )
  1850. timeToIgnore = TIME_IGNORE_FALL_DAMAGE;
  1851. m_flTimeIgnoreFallDamage = gpGlobals->curtime + timeToIgnore;
  1852. m_bIgnoreFallDamageResetAfterImpact = true;
  1853. }
  1854. //-----------------------------------------------------------------------------
  1855. // Purpose: Absolutely prevent the player from taking fall damage for [n] seconds.
  1856. //-----------------------------------------------------------------------------
  1857. void CHL2_Player::InputIgnoreFallDamageWithoutReset( inputdata_t &inputdata )
  1858. {
  1859. float timeToIgnore = inputdata.value.Float();
  1860. if ( timeToIgnore <= 0.0 )
  1861. timeToIgnore = TIME_IGNORE_FALL_DAMAGE;
  1862. m_flTimeIgnoreFallDamage = gpGlobals->curtime + timeToIgnore;
  1863. m_bIgnoreFallDamageResetAfterImpact = false;
  1864. }
  1865. //-----------------------------------------------------------------------------
  1866. // Purpose: Notification of a player's npc ally in the players squad being killed
  1867. //-----------------------------------------------------------------------------
  1868. void CHL2_Player::OnSquadMemberKilled( inputdata_t &data )
  1869. {
  1870. // send a message to the client, to notify the hud of the loss
  1871. CSingleUserRecipientFilter user( this );
  1872. user.MakeReliable();
  1873. UserMessageBegin( user, "SquadMemberDied" );
  1874. MessageEnd();
  1875. }
  1876. //-----------------------------------------------------------------------------
  1877. // Purpose:
  1878. //-----------------------------------------------------------------------------
  1879. void CHL2_Player::NotifyFriendsOfDamage( CBaseEntity *pAttackerEntity )
  1880. {
  1881. CAI_BaseNPC *pAttacker = pAttackerEntity->MyNPCPointer();
  1882. if ( pAttacker )
  1883. {
  1884. const Vector &origin = GetAbsOrigin();
  1885. for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ )
  1886. {
  1887. const float NEAR_Z = 12*12;
  1888. const float NEAR_XY_SQ = Square( 50*12 );
  1889. CAI_BaseNPC *pNpc = g_AI_Manager.AccessAIs()[i];
  1890. if ( pNpc->IsPlayerAlly() )
  1891. {
  1892. const Vector &originNpc = pNpc->GetAbsOrigin();
  1893. if ( fabsf( originNpc.z - origin.z ) < NEAR_Z )
  1894. {
  1895. if ( (originNpc.AsVector2D() - origin.AsVector2D()).LengthSqr() < NEAR_XY_SQ )
  1896. {
  1897. pNpc->OnFriendDamaged( this, pAttacker );
  1898. }
  1899. }
  1900. }
  1901. }
  1902. }
  1903. }
  1904. //-----------------------------------------------------------------------------
  1905. // Purpose:
  1906. //-----------------------------------------------------------------------------
  1907. ConVar test_massive_dmg("test_massive_dmg", "30" );
  1908. ConVar test_massive_dmg_clip("test_massive_dmg_clip", "0.5" );
  1909. int CHL2_Player::OnTakeDamage( const CTakeDamageInfo &info )
  1910. {
  1911. if ( GlobalEntity_GetState( "gordon_invulnerable" ) == GLOBAL_ON )
  1912. return 0;
  1913. // ignore fall damage if instructed to do so by input
  1914. if ( ( info.GetDamageType() & DMG_FALL ) && m_flTimeIgnoreFallDamage > gpGlobals->curtime )
  1915. {
  1916. // usually, we will reset the input flag after the first impact. However there is another input that
  1917. // prevents this behavior.
  1918. if ( m_bIgnoreFallDamageResetAfterImpact )
  1919. {
  1920. m_flTimeIgnoreFallDamage = 0;
  1921. }
  1922. return 0;
  1923. }
  1924. if( info.GetDamageType() & DMG_BLAST_SURFACE )
  1925. {
  1926. if( GetWaterLevel() > 2 )
  1927. {
  1928. // Don't take blast damage from anything above the surface.
  1929. if( info.GetInflictor()->GetWaterLevel() == 0 )
  1930. {
  1931. return 0;
  1932. }
  1933. }
  1934. }
  1935. if ( info.GetDamage() > 0.0f )
  1936. {
  1937. m_flLastDamageTime = gpGlobals->curtime;
  1938. if ( info.GetAttacker() )
  1939. NotifyFriendsOfDamage( info.GetAttacker() );
  1940. }
  1941. // Modify the amount of damage the player takes, based on skill.
  1942. CTakeDamageInfo playerDamage = info;
  1943. // Should we run this damage through the skill level adjustment?
  1944. bool bAdjustForSkillLevel = true;
  1945. if( info.GetDamageType() == DMG_GENERIC && info.GetAttacker() == this && info.GetInflictor() == this )
  1946. {
  1947. // Only do a skill level adjustment if the player isn't his own attacker AND inflictor.
  1948. // This prevents damage from SetHealth() inputs from being adjusted for skill level.
  1949. bAdjustForSkillLevel = false;
  1950. }
  1951. if ( GetVehicleEntity() != NULL && GlobalEntity_GetState("gordon_protect_driver") == GLOBAL_ON )
  1952. {
  1953. if( playerDamage.GetDamage() > test_massive_dmg.GetFloat() && playerDamage.GetInflictor() == GetVehicleEntity() && (playerDamage.GetDamageType() & DMG_CRUSH) )
  1954. {
  1955. playerDamage.ScaleDamage( test_massive_dmg_clip.GetFloat() / playerDamage.GetDamage() );
  1956. }
  1957. }
  1958. if( bAdjustForSkillLevel )
  1959. {
  1960. playerDamage.AdjustPlayerDamageTakenForSkillLevel();
  1961. }
  1962. gamestats->Event_PlayerDamage( this, info );
  1963. return BaseClass::OnTakeDamage( playerDamage );
  1964. }
  1965. //-----------------------------------------------------------------------------
  1966. // Purpose:
  1967. // Input : &info -
  1968. //-----------------------------------------------------------------------------
  1969. int CHL2_Player::OnTakeDamage_Alive( const CTakeDamageInfo &info )
  1970. {
  1971. // Drown
  1972. if( info.GetDamageType() & DMG_DROWN )
  1973. {
  1974. if( m_idrowndmg == m_idrownrestored )
  1975. {
  1976. EmitSound( "Player.DrownStart" );
  1977. }
  1978. else
  1979. {
  1980. EmitSound( "Player.DrownContinue" );
  1981. }
  1982. }
  1983. // Burnt
  1984. if ( info.GetDamageType() & DMG_BURN )
  1985. {
  1986. EmitSound( "HL2Player.BurnPain" );
  1987. }
  1988. if( (info.GetDamageType() & DMG_SLASH) && hl2_episodic.GetBool() )
  1989. {
  1990. if( m_afPhysicsFlags & PFLAG_USING )
  1991. {
  1992. // Stop the player using a rotating button for a short time if hit by a creature's melee attack.
  1993. // This is for the antlion burrow-corking training in EP1 (sjb).
  1994. SuspendUse( 0.5f );
  1995. }
  1996. }
  1997. // Call the base class implementation
  1998. return BaseClass::OnTakeDamage_Alive( info );
  1999. }
  2000. //-----------------------------------------------------------------------------
  2001. //-----------------------------------------------------------------------------
  2002. void CHL2_Player::OnDamagedByExplosion( const CTakeDamageInfo &info )
  2003. {
  2004. if ( info.GetInflictor() && info.GetInflictor()->ClassMatches( "mortarshell" ) )
  2005. {
  2006. // No ear ringing for mortar
  2007. UTIL_ScreenShake( info.GetInflictor()->GetAbsOrigin(), 4.0, 1.0, 0.5, 1000, SHAKE_START, false );
  2008. return;
  2009. }
  2010. BaseClass::OnDamagedByExplosion( info );
  2011. }
  2012. //-----------------------------------------------------------------------------
  2013. //-----------------------------------------------------------------------------
  2014. bool CHL2_Player::ShouldShootMissTarget( CBaseCombatCharacter *pAttacker )
  2015. {
  2016. if( gpGlobals->curtime > m_flTargetFindTime )
  2017. {
  2018. // Put this off into the future again.
  2019. m_flTargetFindTime = gpGlobals->curtime + random->RandomFloat( 3, 5 );
  2020. return true;
  2021. }
  2022. return false;
  2023. }
  2024. //-----------------------------------------------------------------------------
  2025. // Purpose: Notifies Alyx that player has put a combine ball into a socket so she can comment on it.
  2026. // Input : pCombineBall - ball the was socketed
  2027. //-----------------------------------------------------------------------------
  2028. void CHL2_Player::CombineBallSocketed( CPropCombineBall *pCombineBall )
  2029. {
  2030. #ifdef HL2_EPISODIC
  2031. CNPC_Alyx *pAlyx = CNPC_Alyx::GetAlyx();
  2032. if ( pAlyx )
  2033. {
  2034. pAlyx->CombineBallSocketed( pCombineBall->NumBounces() );
  2035. }
  2036. #endif
  2037. }
  2038. //-----------------------------------------------------------------------------
  2039. //-----------------------------------------------------------------------------
  2040. void CHL2_Player::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info )
  2041. {
  2042. BaseClass::Event_KilledOther( pVictim, info );
  2043. #ifdef HL2_EPISODIC
  2044. CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs();
  2045. for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ )
  2046. {
  2047. if ( ppAIs[i] && ppAIs[i]->IRelationType(this) == D_LI )
  2048. {
  2049. ppAIs[i]->OnPlayerKilledOther( pVictim, info );
  2050. }
  2051. }
  2052. #endif
  2053. }
  2054. //-----------------------------------------------------------------------------
  2055. //-----------------------------------------------------------------------------
  2056. void CHL2_Player::Event_Killed( const CTakeDamageInfo &info )
  2057. {
  2058. BaseClass::Event_Killed( info );
  2059. FirePlayerProxyOutput( "PlayerDied", variant_t(), this, this );
  2060. NotifyScriptsOfDeath();
  2061. }
  2062. //-----------------------------------------------------------------------------
  2063. //-----------------------------------------------------------------------------
  2064. void CHL2_Player::NotifyScriptsOfDeath( void )
  2065. {
  2066. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "scripted_sequence" );
  2067. while( pEnt )
  2068. {
  2069. variant_t emptyVariant;
  2070. pEnt->AcceptInput( "ScriptPlayerDeath", NULL, NULL, emptyVariant, 0 );
  2071. pEnt = gEntList.FindEntityByClassname( pEnt, "scripted_sequence" );
  2072. }
  2073. pEnt = gEntList.FindEntityByClassname( NULL, "logic_choreographed_scene" );
  2074. while( pEnt )
  2075. {
  2076. variant_t emptyVariant;
  2077. pEnt->AcceptInput( "ScriptPlayerDeath", NULL, NULL, emptyVariant, 0 );
  2078. pEnt = gEntList.FindEntityByClassname( pEnt, "logic_choreographed_scene" );
  2079. }
  2080. }
  2081. //-----------------------------------------------------------------------------
  2082. //-----------------------------------------------------------------------------
  2083. void CHL2_Player::GetAutoaimVector( autoaim_params_t &params )
  2084. {
  2085. BaseClass::GetAutoaimVector( params );
  2086. if ( IsX360() )
  2087. {
  2088. if( IsInAVehicle() )
  2089. {
  2090. if( m_hLockedAutoAimEntity && m_hLockedAutoAimEntity->IsAlive() && ShouldKeepLockedAutoaimTarget(m_hLockedAutoAimEntity) )
  2091. {
  2092. if( params.m_hAutoAimEntity && params.m_hAutoAimEntity != m_hLockedAutoAimEntity )
  2093. {
  2094. // Autoaim has picked a new target. Switch.
  2095. m_hLockedAutoAimEntity = params.m_hAutoAimEntity;
  2096. }
  2097. // Ignore autoaim and just keep aiming at this target.
  2098. params.m_hAutoAimEntity = m_hLockedAutoAimEntity;
  2099. Vector vecTarget = m_hLockedAutoAimEntity->BodyTarget( EyePosition(), false );
  2100. Vector vecDir = vecTarget - EyePosition();
  2101. VectorNormalize( vecDir );
  2102. params.m_vecAutoAimDir = vecDir;
  2103. params.m_vecAutoAimPoint = vecTarget;
  2104. return;
  2105. }
  2106. else
  2107. {
  2108. m_hLockedAutoAimEntity = NULL;
  2109. }
  2110. }
  2111. // If the player manually gets his crosshair onto a target, make that target sticky
  2112. if( params.m_fScale != AUTOAIM_SCALE_DIRECT_ONLY )
  2113. {
  2114. // Only affect this for 'real' queries
  2115. //if( params.m_hAutoAimEntity && params.m_bOnTargetNatural )
  2116. if( params.m_hAutoAimEntity )
  2117. {
  2118. // Turn on sticky.
  2119. m_HL2Local.m_bStickyAutoAim = true;
  2120. if( IsInAVehicle() )
  2121. {
  2122. m_hLockedAutoAimEntity = params.m_hAutoAimEntity;
  2123. }
  2124. }
  2125. else if( !params.m_hAutoAimEntity )
  2126. {
  2127. // Turn off sticky only if there's no target at all.
  2128. m_HL2Local.m_bStickyAutoAim = false;
  2129. m_hLockedAutoAimEntity = NULL;
  2130. }
  2131. }
  2132. }
  2133. }
  2134. //-----------------------------------------------------------------------------
  2135. //-----------------------------------------------------------------------------
  2136. bool CHL2_Player::ShouldKeepLockedAutoaimTarget( EHANDLE hLockedTarget )
  2137. {
  2138. Vector vecLooking;
  2139. Vector vecToTarget;
  2140. vecToTarget = hLockedTarget->WorldSpaceCenter() - EyePosition();
  2141. float flDist = vecToTarget.Length2D();
  2142. VectorNormalize( vecToTarget );
  2143. if( flDist > autoaim_max_dist.GetFloat() )
  2144. return false;
  2145. float flDot;
  2146. vecLooking = EyeDirection3D();
  2147. flDot = DotProduct( vecLooking, vecToTarget );
  2148. if( flDot < autoaim_unlock_target.GetFloat() )
  2149. return false;
  2150. return true;
  2151. }
  2152. //-----------------------------------------------------------------------------
  2153. // Purpose:
  2154. // Input : iCount -
  2155. // iAmmoIndex -
  2156. // bSuppressSound -
  2157. // Output : int
  2158. //-----------------------------------------------------------------------------
  2159. int CHL2_Player::GiveAmmo( int nCount, int nAmmoIndex, bool bSuppressSound)
  2160. {
  2161. // Don't try to give the player invalid ammo indices.
  2162. if (nAmmoIndex < 0)
  2163. return 0;
  2164. bool bCheckAutoSwitch = false;
  2165. if (!HasAnyAmmoOfType(nAmmoIndex))
  2166. {
  2167. bCheckAutoSwitch = true;
  2168. }
  2169. int nAdd = BaseClass::GiveAmmo(nCount, nAmmoIndex, bSuppressSound);
  2170. if ( nCount > 0 && nAdd == 0 )
  2171. {
  2172. // we've been denied the pickup, display a hud icon to show that
  2173. CSingleUserRecipientFilter user( this );
  2174. user.MakeReliable();
  2175. UserMessageBegin( user, "AmmoDenied" );
  2176. WRITE_SHORT( nAmmoIndex );
  2177. MessageEnd();
  2178. }
  2179. //
  2180. // If I was dry on ammo for my best weapon and justed picked up ammo for it,
  2181. // autoswitch to my best weapon now.
  2182. //
  2183. if (bCheckAutoSwitch)
  2184. {
  2185. CBaseCombatWeapon *pWeapon = g_pGameRules->GetNextBestWeapon(this, GetActiveWeapon());
  2186. if ( pWeapon && pWeapon->GetPrimaryAmmoType() == nAmmoIndex )
  2187. {
  2188. SwitchToNextBestWeapon(GetActiveWeapon());
  2189. }
  2190. }
  2191. return nAdd;
  2192. }
  2193. //-----------------------------------------------------------------------------
  2194. //-----------------------------------------------------------------------------
  2195. bool CHL2_Player::Weapon_CanUse( CBaseCombatWeapon *pWeapon )
  2196. {
  2197. #ifndef HL2MP
  2198. if ( pWeapon->ClassMatches( "weapon_stunstick" ) )
  2199. {
  2200. if ( ApplyBattery( 0.5 ) )
  2201. UTIL_Remove( pWeapon );
  2202. return false;
  2203. }
  2204. #endif
  2205. return BaseClass::Weapon_CanUse( pWeapon );
  2206. }
  2207. //-----------------------------------------------------------------------------
  2208. // Purpose:
  2209. // Input : *pWeapon -
  2210. //-----------------------------------------------------------------------------
  2211. void CHL2_Player::Weapon_Equip( CBaseCombatWeapon *pWeapon )
  2212. {
  2213. #if HL2_SINGLE_PRIMARY_WEAPON_MODE
  2214. if ( pWeapon->GetSlot() == WEAPON_PRIMARY_SLOT )
  2215. {
  2216. Weapon_DropSlot( WEAPON_PRIMARY_SLOT );
  2217. }
  2218. #endif
  2219. if( GetActiveWeapon() == NULL )
  2220. {
  2221. m_HL2Local.m_bWeaponLowered = false;
  2222. }
  2223. BaseClass::Weapon_Equip( pWeapon );
  2224. }
  2225. //-----------------------------------------------------------------------------
  2226. // Purpose: Player reacts to bumping a weapon.
  2227. // Input : pWeapon - the weapon that the player bumped into.
  2228. // Output : Returns true if player picked up the weapon
  2229. //-----------------------------------------------------------------------------
  2230. bool CHL2_Player::BumpWeapon( CBaseCombatWeapon *pWeapon )
  2231. {
  2232. #if HL2_SINGLE_PRIMARY_WEAPON_MODE
  2233. CBaseCombatCharacter *pOwner = pWeapon->GetOwner();
  2234. // Can I have this weapon type?
  2235. if ( pOwner || !Weapon_CanUse( pWeapon ) || !g_pGameRules->CanHavePlayerItem( this, pWeapon ) )
  2236. {
  2237. if ( gEvilImpulse101 )
  2238. {
  2239. UTIL_Remove( pWeapon );
  2240. }
  2241. return false;
  2242. }
  2243. // ----------------------------------------
  2244. // If I already have it just take the ammo
  2245. // ----------------------------------------
  2246. if (Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType()))
  2247. {
  2248. //Only remove the weapon if we attained ammo from it
  2249. if ( Weapon_EquipAmmoOnly( pWeapon ) == false )
  2250. return false;
  2251. // Only remove me if I have no ammo left
  2252. // Can't just check HasAnyAmmo because if I don't use clips, I want to be removed,
  2253. if ( pWeapon->UsesClipsForAmmo1() && pWeapon->HasPrimaryAmmo() )
  2254. return false;
  2255. UTIL_Remove( pWeapon );
  2256. return false;
  2257. }
  2258. // -------------------------
  2259. // Otherwise take the weapon
  2260. // -------------------------
  2261. else
  2262. {
  2263. //Make sure we're not trying to take a new weapon type we already have
  2264. if ( Weapon_SlotOccupied( pWeapon ) )
  2265. {
  2266. CBaseCombatWeapon *pActiveWeapon = Weapon_GetSlot( WEAPON_PRIMARY_SLOT );
  2267. if ( pActiveWeapon != NULL && pActiveWeapon->HasAnyAmmo() == false && Weapon_CanSwitchTo( pWeapon ) )
  2268. {
  2269. Weapon_Equip( pWeapon );
  2270. return true;
  2271. }
  2272. //Attempt to take ammo if this is the gun we're holding already
  2273. if ( Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType() ) )
  2274. {
  2275. Weapon_EquipAmmoOnly( pWeapon );
  2276. }
  2277. return false;
  2278. }
  2279. pWeapon->CheckRespawn();
  2280. pWeapon->AddSolidFlags( FSOLID_NOT_SOLID );
  2281. pWeapon->AddEffects( EF_NODRAW );
  2282. Weapon_Equip( pWeapon );
  2283. EmitSound( "HL2Player.PickupWeapon" );
  2284. return true;
  2285. }
  2286. #else
  2287. return BaseClass::BumpWeapon( pWeapon );
  2288. #endif
  2289. }
  2290. //-----------------------------------------------------------------------------
  2291. // Purpose:
  2292. // Input : *cmd -
  2293. // Output : Returns true on success, false on failure.
  2294. //-----------------------------------------------------------------------------
  2295. bool CHL2_Player::ClientCommand( const CCommand &args )
  2296. {
  2297. #if HL2_SINGLE_PRIMARY_WEAPON_MODE
  2298. //Drop primary weapon
  2299. if ( !Q_stricmp( args[0], "DropPrimary" ) )
  2300. {
  2301. Weapon_DropSlot( WEAPON_PRIMARY_SLOT );
  2302. return true;
  2303. }
  2304. #endif
  2305. if ( !Q_stricmp( args[0], "emit" ) )
  2306. {
  2307. CSingleUserRecipientFilter filter( this );
  2308. if ( args.ArgC() > 1 )
  2309. {
  2310. EmitSound( filter, entindex(), args[ 1 ] );
  2311. }
  2312. else
  2313. {
  2314. EmitSound( filter, entindex(), "Test.Sound" );
  2315. }
  2316. return true;
  2317. }
  2318. return BaseClass::ClientCommand( args );
  2319. }
  2320. //-----------------------------------------------------------------------------
  2321. // Purpose:
  2322. // Output : void CBasePlayer::PlayerUse
  2323. //-----------------------------------------------------------------------------
  2324. void CHL2_Player::PlayerUse ( void )
  2325. {
  2326. // Was use pressed or released?
  2327. if ( ! ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) )
  2328. return;
  2329. if ( m_afButtonPressed & IN_USE )
  2330. {
  2331. // Currently using a latched entity?
  2332. if ( ClearUseEntity() )
  2333. {
  2334. return;
  2335. }
  2336. else
  2337. {
  2338. if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
  2339. {
  2340. m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
  2341. m_iTrain = TRAIN_NEW|TRAIN_OFF;
  2342. return;
  2343. }
  2344. else
  2345. { // Start controlling the train!
  2346. CBaseEntity *pTrain = GetGroundEntity();
  2347. if ( pTrain && !(m_nButtons & IN_JUMP) && (GetFlags() & FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(this) )
  2348. {
  2349. m_afPhysicsFlags |= PFLAG_DIROVERRIDE;
  2350. m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed());
  2351. m_iTrain |= TRAIN_NEW;
  2352. EmitSound( "HL2Player.TrainUse" );
  2353. return;
  2354. }
  2355. }
  2356. }
  2357. // Tracker 3926: We can't +USE something if we're climbing a ladder
  2358. if ( GetMoveType() == MOVETYPE_LADDER )
  2359. {
  2360. return;
  2361. }
  2362. }
  2363. if( m_flTimeUseSuspended > gpGlobals->curtime )
  2364. {
  2365. // Something has temporarily stopped us being able to USE things.
  2366. // Obviously, this should be used very carefully.(sjb)
  2367. return;
  2368. }
  2369. CBaseEntity *pUseEntity = FindUseEntity();
  2370. bool usedSomething = false;
  2371. // Found an object
  2372. if ( pUseEntity )
  2373. {
  2374. //!!!UNDONE: traceline here to prevent +USEing buttons through walls
  2375. int caps = pUseEntity->ObjectCaps();
  2376. variant_t emptyVariant;
  2377. if ( m_afButtonPressed & IN_USE )
  2378. {
  2379. // Robin: Don't play sounds for NPCs, because NPCs will allow respond with speech.
  2380. if ( !pUseEntity->MyNPCPointer() )
  2381. {
  2382. EmitSound( "HL2Player.Use" );
  2383. }
  2384. }
  2385. if ( ( (m_nButtons & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) ||
  2386. ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) )
  2387. {
  2388. if ( caps & FCAP_CONTINUOUS_USE )
  2389. m_afPhysicsFlags |= PFLAG_USING;
  2390. pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE );
  2391. usedSomething = true;
  2392. }
  2393. // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away
  2394. else if ( (m_afButtonReleased & IN_USE) && (pUseEntity->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use
  2395. {
  2396. pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE );
  2397. usedSomething = true;
  2398. }
  2399. #if HL2_SINGLE_PRIMARY_WEAPON_MODE
  2400. //Check for weapon pick-up
  2401. if ( m_afButtonPressed & IN_USE )
  2402. {
  2403. CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon *>(pUseEntity);
  2404. if ( ( pWeapon != NULL ) && ( Weapon_CanSwitchTo( pWeapon ) ) )
  2405. {
  2406. //Try to take ammo or swap the weapon
  2407. if ( Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType() ) )
  2408. {
  2409. Weapon_EquipAmmoOnly( pWeapon );
  2410. }
  2411. else
  2412. {
  2413. Weapon_DropSlot( pWeapon->GetSlot() );
  2414. Weapon_Equip( pWeapon );
  2415. }
  2416. usedSomething = true;
  2417. }
  2418. }
  2419. #endif
  2420. }
  2421. else if ( m_afButtonPressed & IN_USE )
  2422. {
  2423. // Signal that we want to play the deny sound, unless the user is +USEing on a ladder!
  2424. // The sound is emitted in ItemPostFrame, since that occurs after GameMovement::ProcessMove which
  2425. // lets the ladder code unset this flag.
  2426. m_bPlayUseDenySound = true;
  2427. }
  2428. // Debounce the use key
  2429. if ( usedSomething && pUseEntity )
  2430. {
  2431. m_Local.m_nOldButtons |= IN_USE;
  2432. m_afButtonPressed &= ~IN_USE;
  2433. }
  2434. }
  2435. ConVar sv_show_crosshair_target( "sv_show_crosshair_target", "0" );
  2436. //-----------------------------------------------------------------------------
  2437. // Purpose: Updates the posture of the weapon from lowered to ready
  2438. //-----------------------------------------------------------------------------
  2439. void CHL2_Player::UpdateWeaponPosture( void )
  2440. {
  2441. CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon *>(GetActiveWeapon());
  2442. if ( pWeapon && m_LowerWeaponTimer.Expired() && pWeapon->CanLower() )
  2443. {
  2444. m_LowerWeaponTimer.Set( .3 );
  2445. VPROF( "CHL2_Player::UpdateWeaponPosture-CheckLower" );
  2446. Vector vecAim = BaseClass::GetAutoaimVector( AUTOAIM_SCALE_DIRECT_ONLY );
  2447. const float CHECK_FRIENDLY_RANGE = 50 * 12;
  2448. trace_t tr;
  2449. UTIL_TraceLine( EyePosition(), EyePosition() + vecAim * CHECK_FRIENDLY_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  2450. CBaseEntity *aimTarget = tr.m_pEnt;
  2451. //If we're over something
  2452. if ( aimTarget && !tr.DidHitWorld() )
  2453. {
  2454. if ( !aimTarget->IsNPC() || aimTarget->MyNPCPointer()->GetState() != NPC_STATE_COMBAT )
  2455. {
  2456. Disposition_t dis = IRelationType( aimTarget );
  2457. //Debug info for seeing what an object "cons" as
  2458. if ( sv_show_crosshair_target.GetBool() )
  2459. {
  2460. int text_offset = BaseClass::DrawDebugTextOverlays();
  2461. char tempstr[255];
  2462. switch ( dis )
  2463. {
  2464. case D_LI:
  2465. Q_snprintf( tempstr, sizeof(tempstr), "Disposition: Like" );
  2466. break;
  2467. case D_HT:
  2468. Q_snprintf( tempstr, sizeof(tempstr), "Disposition: Hate" );
  2469. break;
  2470. case D_FR:
  2471. Q_snprintf( tempstr, sizeof(tempstr), "Disposition: Fear" );
  2472. break;
  2473. case D_NU:
  2474. Q_snprintf( tempstr, sizeof(tempstr), "Disposition: Neutral" );
  2475. break;
  2476. default:
  2477. case D_ER:
  2478. Q_snprintf( tempstr, sizeof(tempstr), "Disposition: !!!ERROR!!!" );
  2479. break;
  2480. }
  2481. //Draw the text
  2482. NDebugOverlay::EntityText( aimTarget->entindex(), text_offset, tempstr, 0 );
  2483. }
  2484. //See if we hates it
  2485. if ( dis == D_LI )
  2486. {
  2487. //We're over a friendly, drop our weapon
  2488. if ( Weapon_Lower() == false )
  2489. {
  2490. //FIXME: We couldn't lower our weapon!
  2491. }
  2492. return;
  2493. }
  2494. }
  2495. }
  2496. if ( Weapon_Ready() == false )
  2497. {
  2498. //FIXME: We couldn't raise our weapon!
  2499. }
  2500. }
  2501. if( g_pGameRules->GetAutoAimMode() != AUTOAIM_NONE )
  2502. {
  2503. if( !pWeapon )
  2504. {
  2505. // This tells the client to draw no crosshair
  2506. m_HL2Local.m_bWeaponLowered = true;
  2507. return;
  2508. }
  2509. else
  2510. {
  2511. if( !pWeapon->CanLower() && m_HL2Local.m_bWeaponLowered )
  2512. m_HL2Local.m_bWeaponLowered = false;
  2513. }
  2514. if( !m_AutoaimTimer.Expired() )
  2515. return;
  2516. m_AutoaimTimer.Set( .1 );
  2517. VPROF( "hl2_x360_aiming" );
  2518. // Call the autoaim code to update the local player data, which allows the client to update.
  2519. autoaim_params_t params;
  2520. params.m_vecAutoAimPoint.Init();
  2521. params.m_vecAutoAimDir.Init();
  2522. params.m_fScale = AUTOAIM_SCALE_DEFAULT;
  2523. params.m_fMaxDist = autoaim_max_dist.GetFloat();
  2524. GetAutoaimVector( params );
  2525. m_HL2Local.m_hAutoAimTarget.Set( params.m_hAutoAimEntity );
  2526. m_HL2Local.m_vecAutoAimPoint.Set( params.m_vecAutoAimPoint );
  2527. m_HL2Local.m_bAutoAimTarget = ( params.m_bAutoAimAssisting || params.m_bOnTargetNatural );
  2528. return;
  2529. }
  2530. else
  2531. {
  2532. // Make sure there's no residual autoaim target if the user changes the xbox_aiming convar on the fly.
  2533. m_HL2Local.m_hAutoAimTarget.Set(NULL);
  2534. }
  2535. }
  2536. //-----------------------------------------------------------------------------
  2537. // Purpose: Lowers the weapon posture (for hovering over friendlies)
  2538. // Output : Returns true on success, false on failure.
  2539. //-----------------------------------------------------------------------------
  2540. bool CHL2_Player::Weapon_Lower( void )
  2541. {
  2542. VPROF( "CHL2_Player::Weapon_Lower" );
  2543. // Already lowered?
  2544. if ( m_HL2Local.m_bWeaponLowered )
  2545. return true;
  2546. m_HL2Local.m_bWeaponLowered = true;
  2547. CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon *>(GetActiveWeapon());
  2548. if ( pWeapon == NULL )
  2549. return false;
  2550. return pWeapon->Lower();
  2551. }
  2552. //-----------------------------------------------------------------------------
  2553. // Purpose: Returns the weapon posture to normal
  2554. // Output : Returns true on success, false on failure.
  2555. //-----------------------------------------------------------------------------
  2556. bool CHL2_Player::Weapon_Ready( void )
  2557. {
  2558. VPROF( "CHL2_Player::Weapon_Ready" );
  2559. // Already ready?
  2560. if ( m_HL2Local.m_bWeaponLowered == false )
  2561. return true;
  2562. m_HL2Local.m_bWeaponLowered = false;
  2563. CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon *>(GetActiveWeapon());
  2564. if ( pWeapon == NULL )
  2565. return false;
  2566. return pWeapon->Ready();
  2567. }
  2568. //-----------------------------------------------------------------------------
  2569. // Purpose: Returns whether or not we can switch to the given weapon.
  2570. // Input : pWeapon -
  2571. //-----------------------------------------------------------------------------
  2572. bool CHL2_Player::Weapon_CanSwitchTo( CBaseCombatWeapon *pWeapon )
  2573. {
  2574. CBasePlayer *pPlayer = (CBasePlayer *)this;
  2575. #if !defined( CLIENT_DLL )
  2576. IServerVehicle *pVehicle = pPlayer->GetVehicle();
  2577. #else
  2578. IClientVehicle *pVehicle = pPlayer->GetVehicle();
  2579. #endif
  2580. if (pVehicle && !pPlayer->UsingStandardWeaponsInVehicle())
  2581. return false;
  2582. if ( !pWeapon->HasAnyAmmo() && !GetAmmoCount( pWeapon->m_iPrimaryAmmoType ) )
  2583. return false;
  2584. if ( !pWeapon->CanDeploy() )
  2585. return false;
  2586. if ( GetActiveWeapon() )
  2587. {
  2588. if ( PhysCannonGetHeldEntity( GetActiveWeapon() ) == pWeapon &&
  2589. Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType()) )
  2590. {
  2591. return true;
  2592. }
  2593. if ( !GetActiveWeapon()->CanHolster() )
  2594. return false;
  2595. }
  2596. return true;
  2597. }
  2598. void CHL2_Player::PickupObject( CBaseEntity *pObject, bool bLimitMassAndSize )
  2599. {
  2600. // can't pick up what you're standing on
  2601. if ( GetGroundEntity() == pObject )
  2602. return;
  2603. if ( bLimitMassAndSize == true )
  2604. {
  2605. if ( CBasePlayer::CanPickupObject( pObject, 35, 128 ) == false )
  2606. return;
  2607. }
  2608. // Can't be picked up if NPCs are on me
  2609. if ( pObject->HasNPCsOnIt() )
  2610. return;
  2611. PlayerPickupObject( this, pObject );
  2612. }
  2613. //-----------------------------------------------------------------------------
  2614. // Purpose:
  2615. // Output : CBaseEntity
  2616. //-----------------------------------------------------------------------------
  2617. bool CHL2_Player::IsHoldingEntity( CBaseEntity *pEnt )
  2618. {
  2619. return PlayerPickupControllerIsHoldingEntity( m_hUseEntity, pEnt );
  2620. }
  2621. float CHL2_Player::GetHeldObjectMass( IPhysicsObject *pHeldObject )
  2622. {
  2623. float mass = PlayerPickupGetHeldObjectMass( m_hUseEntity, pHeldObject );
  2624. if ( mass == 0.0f )
  2625. {
  2626. mass = PhysCannonGetHeldObjectMass( GetActiveWeapon(), pHeldObject );
  2627. }
  2628. return mass;
  2629. }
  2630. //-----------------------------------------------------------------------------
  2631. // Purpose: Force the player to drop any physics objects he's carrying
  2632. //-----------------------------------------------------------------------------
  2633. void CHL2_Player::ForceDropOfCarriedPhysObjects( CBaseEntity *pOnlyIfHoldingThis )
  2634. {
  2635. if ( PhysIsInCallback() )
  2636. {
  2637. variant_t value;
  2638. g_EventQueue.AddEvent( this, "ForceDropPhysObjects", value, 0.01f, pOnlyIfHoldingThis, this );
  2639. return;
  2640. }
  2641. #ifdef HL2_EPISODIC
  2642. if ( hl2_episodic.GetBool() )
  2643. {
  2644. CBaseEntity *pHeldEntity = PhysCannonGetHeldEntity( GetActiveWeapon() );
  2645. if( pHeldEntity && pHeldEntity->ClassMatches( "grenade_helicopter" ) )
  2646. {
  2647. return;
  2648. }
  2649. }
  2650. #endif
  2651. // Drop any objects being handheld.
  2652. ClearUseEntity();
  2653. // Then force the physcannon to drop anything it's holding, if it's our active weapon
  2654. PhysCannonForceDrop( GetActiveWeapon(), NULL );
  2655. }
  2656. void CHL2_Player::InputForceDropPhysObjects( inputdata_t &data )
  2657. {
  2658. ForceDropOfCarriedPhysObjects( data.pActivator );
  2659. }
  2660. //-----------------------------------------------------------------------------
  2661. // Purpose:
  2662. //-----------------------------------------------------------------------------
  2663. void CHL2_Player::UpdateClientData( void )
  2664. {
  2665. if (m_DmgTake || m_DmgSave || m_bitsHUDDamage != m_bitsDamageType)
  2666. {
  2667. // Comes from inside me if not set
  2668. Vector damageOrigin = GetLocalOrigin();
  2669. // send "damage" message
  2670. // causes screen to flash, and pain compass to show direction of damage
  2671. damageOrigin = m_DmgOrigin;
  2672. // only send down damage type that have hud art
  2673. int iShowHudDamage = g_pGameRules->Damage_GetShowOnHud();
  2674. int visibleDamageBits = m_bitsDamageType & iShowHudDamage;
  2675. m_DmgTake = clamp( m_DmgTake, 0, 255 );
  2676. m_DmgSave = clamp( m_DmgSave, 0, 255 );
  2677. // If we're poisoned, but it wasn't this frame, don't send the indicator
  2678. // Without this check, any damage that occured to the player while they were
  2679. // recovering from a poison bite would register as poisonous as well and flash
  2680. // the whole screen! -- jdw
  2681. if ( visibleDamageBits & DMG_POISON )
  2682. {
  2683. float flLastPoisonedDelta = gpGlobals->curtime - m_tbdPrev;
  2684. if ( flLastPoisonedDelta > 0.1f )
  2685. {
  2686. visibleDamageBits &= ~DMG_POISON;
  2687. }
  2688. }
  2689. CSingleUserRecipientFilter user( this );
  2690. user.MakeReliable();
  2691. UserMessageBegin( user, "Damage" );
  2692. WRITE_BYTE( m_DmgSave );
  2693. WRITE_BYTE( m_DmgTake );
  2694. WRITE_LONG( visibleDamageBits );
  2695. WRITE_FLOAT( damageOrigin.x ); //BUG: Should be fixed point (to hud) not floats
  2696. WRITE_FLOAT( damageOrigin.y ); //BUG: However, the HUD does _not_ implement bitfield messages (yet)
  2697. WRITE_FLOAT( damageOrigin.z ); //BUG: We use WRITE_VEC3COORD for everything else
  2698. MessageEnd();
  2699. m_DmgTake = 0;
  2700. m_DmgSave = 0;
  2701. m_bitsHUDDamage = m_bitsDamageType;
  2702. // Clear off non-time-based damage indicators
  2703. int iTimeBasedDamage = g_pGameRules->Damage_GetTimeBased();
  2704. m_bitsDamageType &= iTimeBasedDamage;
  2705. }
  2706. // Update Flashlight
  2707. #ifdef HL2_EPISODIC
  2708. if ( Flashlight_UseLegacyVersion() == false )
  2709. {
  2710. if ( FlashlightIsOn() && sv_infinite_aux_power.GetBool() == false )
  2711. {
  2712. m_HL2Local.m_flFlashBattery -= FLASH_DRAIN_TIME * gpGlobals->frametime;
  2713. if ( m_HL2Local.m_flFlashBattery < 0.0f )
  2714. {
  2715. FlashlightTurnOff();
  2716. m_HL2Local.m_flFlashBattery = 0.0f;
  2717. }
  2718. }
  2719. else
  2720. {
  2721. m_HL2Local.m_flFlashBattery += FLASH_CHARGE_TIME * gpGlobals->frametime;
  2722. if ( m_HL2Local.m_flFlashBattery > 100.0f )
  2723. {
  2724. m_HL2Local.m_flFlashBattery = 100.0f;
  2725. }
  2726. }
  2727. }
  2728. else
  2729. {
  2730. m_HL2Local.m_flFlashBattery = -1.0f;
  2731. }
  2732. #endif // HL2_EPISODIC
  2733. BaseClass::UpdateClientData();
  2734. }
  2735. //---------------------------------------------------------
  2736. //---------------------------------------------------------
  2737. void CHL2_Player::OnRestore()
  2738. {
  2739. BaseClass::OnRestore();
  2740. m_pPlayerAISquad = g_AI_SquadManager.FindCreateSquad(AllocPooledString(PLAYER_SQUADNAME));
  2741. }
  2742. //---------------------------------------------------------
  2743. //---------------------------------------------------------
  2744. Vector CHL2_Player::EyeDirection2D( void )
  2745. {
  2746. Vector vecReturn = EyeDirection3D();
  2747. vecReturn.z = 0;
  2748. vecReturn.AsVector2D().NormalizeInPlace();
  2749. return vecReturn;
  2750. }
  2751. //---------------------------------------------------------
  2752. //---------------------------------------------------------
  2753. Vector CHL2_Player::EyeDirection3D( void )
  2754. {
  2755. Vector vecForward;
  2756. // Return the vehicle angles if we request them
  2757. if ( GetVehicle() != NULL )
  2758. {
  2759. CacheVehicleView();
  2760. EyeVectors( &vecForward );
  2761. return vecForward;
  2762. }
  2763. AngleVectors( EyeAngles(), &vecForward );
  2764. return vecForward;
  2765. }
  2766. //---------------------------------------------------------
  2767. //---------------------------------------------------------
  2768. bool CHL2_Player::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex )
  2769. {
  2770. MDLCACHE_CRITICAL_SECTION();
  2771. // Recalculate proficiency!
  2772. SetCurrentWeaponProficiency( CalcWeaponProficiency( pWeapon ) );
  2773. // Come out of suit zoom mode
  2774. if ( IsZooming() )
  2775. {
  2776. StopZooming();
  2777. }
  2778. return BaseClass::Weapon_Switch( pWeapon, viewmodelindex );
  2779. }
  2780. //-----------------------------------------------------------------------------
  2781. //-----------------------------------------------------------------------------
  2782. WeaponProficiency_t CHL2_Player::CalcWeaponProficiency( CBaseCombatWeapon *pWeapon )
  2783. {
  2784. WeaponProficiency_t proficiency;
  2785. proficiency = WEAPON_PROFICIENCY_PERFECT;
  2786. if( weapon_showproficiency.GetBool() != 0 )
  2787. {
  2788. Msg("Player switched to %s, proficiency is %s\n", pWeapon->GetClassname(), GetWeaponProficiencyName( proficiency ) );
  2789. }
  2790. return proficiency;
  2791. }
  2792. //-----------------------------------------------------------------------------
  2793. // Purpose: override how single player rays hit the player
  2794. //-----------------------------------------------------------------------------
  2795. bool LineCircleIntersection(
  2796. const Vector2D &center,
  2797. const float radius,
  2798. const Vector2D &vLinePt,
  2799. const Vector2D &vLineDir,
  2800. float *fIntersection1,
  2801. float *fIntersection2)
  2802. {
  2803. // Line = P + Vt
  2804. // Sphere = r (assume we've translated to origin)
  2805. // (P + Vt)^2 = r^2
  2806. // VVt^2 + 2PVt + (PP - r^2)
  2807. // Solve as quadratic: (-b +/- sqrt(b^2 - 4ac)) / 2a
  2808. // If (b^2 - 4ac) is < 0 there is no solution.
  2809. // If (b^2 - 4ac) is = 0 there is one solution (a case this function doesn't support).
  2810. // If (b^2 - 4ac) is > 0 there are two solutions.
  2811. Vector2D P;
  2812. float a, b, c, sqr, insideSqr;
  2813. // Translate circle to origin.
  2814. P[0] = vLinePt[0] - center[0];
  2815. P[1] = vLinePt[1] - center[1];
  2816. a = vLineDir.Dot(vLineDir);
  2817. b = 2.0f * P.Dot(vLineDir);
  2818. c = P.Dot(P) - (radius * radius);
  2819. insideSqr = b*b - 4*a*c;
  2820. if(insideSqr <= 0.000001f)
  2821. return false;
  2822. // Ok, two solutions.
  2823. sqr = (float)FastSqrt(insideSqr);
  2824. float denom = 1.0 / (2.0f * a);
  2825. *fIntersection1 = (-b - sqr) * denom;
  2826. *fIntersection2 = (-b + sqr) * denom;
  2827. return true;
  2828. }
  2829. static void Collision_ClearTrace( const Vector &vecRayStart, const Vector &vecRayDelta, CBaseTrace *pTrace )
  2830. {
  2831. pTrace->startpos = vecRayStart;
  2832. pTrace->endpos = vecRayStart;
  2833. pTrace->endpos += vecRayDelta;
  2834. pTrace->startsolid = false;
  2835. pTrace->allsolid = false;
  2836. pTrace->fraction = 1.0f;
  2837. pTrace->contents = 0;
  2838. }
  2839. bool IntersectRayWithAACylinder( const Ray_t &ray,
  2840. const Vector &center, float radius, float height, CBaseTrace *pTrace )
  2841. {
  2842. Assert( ray.m_IsRay );
  2843. Collision_ClearTrace( ray.m_Start, ray.m_Delta, pTrace );
  2844. // First intersect the ray with the top + bottom planes
  2845. float halfHeight = height * 0.5;
  2846. // Handle parallel case
  2847. Vector vStart = ray.m_Start - center;
  2848. Vector vEnd = vStart + ray.m_Delta;
  2849. float flEnterFrac, flLeaveFrac;
  2850. if (FloatMakePositive(ray.m_Delta.z) < 1e-8)
  2851. {
  2852. if ( (vStart.z < -halfHeight) || (vStart.z > halfHeight) )
  2853. {
  2854. return false; // no hit
  2855. }
  2856. flEnterFrac = 0.0f; flLeaveFrac = 1.0f;
  2857. }
  2858. else
  2859. {
  2860. // Clip the ray to the top and bottom of box
  2861. flEnterFrac = IntersectRayWithAAPlane( vStart, vEnd, 2, 1, halfHeight);
  2862. flLeaveFrac = IntersectRayWithAAPlane( vStart, vEnd, 2, 1, -halfHeight);
  2863. if ( flLeaveFrac < flEnterFrac )
  2864. {
  2865. float temp = flLeaveFrac;
  2866. flLeaveFrac = flEnterFrac;
  2867. flEnterFrac = temp;
  2868. }
  2869. if ( flLeaveFrac < 0 || flEnterFrac > 1)
  2870. {
  2871. return false;
  2872. }
  2873. }
  2874. // Intersect with circle
  2875. float flCircleEnterFrac, flCircleLeaveFrac;
  2876. if ( !LineCircleIntersection( vec3_origin.AsVector2D(), radius,
  2877. vStart.AsVector2D(), ray.m_Delta.AsVector2D(), &flCircleEnterFrac, &flCircleLeaveFrac ) )
  2878. {
  2879. return false; // no hit
  2880. }
  2881. Assert( flCircleEnterFrac <= flCircleLeaveFrac );
  2882. if ( flCircleLeaveFrac < 0 || flCircleEnterFrac > 1)
  2883. {
  2884. return false;
  2885. }
  2886. if ( flEnterFrac < flCircleEnterFrac )
  2887. flEnterFrac = flCircleEnterFrac;
  2888. if ( flLeaveFrac > flCircleLeaveFrac )
  2889. flLeaveFrac = flCircleLeaveFrac;
  2890. if ( flLeaveFrac < flEnterFrac )
  2891. return false;
  2892. VectorMA( ray.m_Start, flEnterFrac , ray.m_Delta, pTrace->endpos );
  2893. pTrace->fraction = flEnterFrac;
  2894. pTrace->contents = CONTENTS_SOLID;
  2895. // Calculate the point on our center line where we're nearest the intersection point
  2896. Vector collisionCenter;
  2897. CalcClosestPointOnLineSegment( pTrace->endpos, center + Vector( 0, 0, halfHeight ), center - Vector( 0, 0, halfHeight ), collisionCenter );
  2898. // Our normal is the direction from that center point to the intersection point
  2899. pTrace->plane.normal = pTrace->endpos - collisionCenter;
  2900. VectorNormalize( pTrace->plane.normal );
  2901. return true;
  2902. }
  2903. bool CHL2_Player::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
  2904. {
  2905. if( g_pGameRules->IsMultiplayer() )
  2906. {
  2907. return BaseClass::TestHitboxes( ray, fContentsMask, tr );
  2908. }
  2909. else
  2910. {
  2911. Assert( ray.m_IsRay );
  2912. Vector mins, maxs;
  2913. mins = WorldAlignMins();
  2914. maxs = WorldAlignMaxs();
  2915. if ( IntersectRayWithAACylinder( ray, WorldSpaceCenter(), maxs.x * PLAYER_HULL_REDUCTION, maxs.z - mins.z, &tr ) )
  2916. {
  2917. tr.hitbox = 0;
  2918. CStudioHdr *pStudioHdr = GetModelPtr( );
  2919. if (!pStudioHdr)
  2920. return false;
  2921. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet );
  2922. if ( !set || !set->numhitboxes )
  2923. return false;
  2924. mstudiobbox_t *pbox = set->pHitbox( tr.hitbox );
  2925. mstudiobone_t *pBone = pStudioHdr->pBone(pbox->bone);
  2926. tr.surface.name = "**studio**";
  2927. tr.surface.flags = SURF_HITBOX;
  2928. tr.surface.surfaceProps = physprops->GetSurfaceIndex( pBone->pszSurfaceProp() );
  2929. }
  2930. return true;
  2931. }
  2932. }
  2933. //---------------------------------------------------------
  2934. // Show the player's scaled down bbox that we use for
  2935. // bullet impacts.
  2936. //---------------------------------------------------------
  2937. void CHL2_Player::DrawDebugGeometryOverlays(void)
  2938. {
  2939. BaseClass::DrawDebugGeometryOverlays();
  2940. if (m_debugOverlays & OVERLAY_BBOX_BIT)
  2941. {
  2942. Vector mins, maxs;
  2943. mins = WorldAlignMins();
  2944. maxs = WorldAlignMaxs();
  2945. mins.x *= PLAYER_HULL_REDUCTION;
  2946. mins.y *= PLAYER_HULL_REDUCTION;
  2947. maxs.x *= PLAYER_HULL_REDUCTION;
  2948. maxs.y *= PLAYER_HULL_REDUCTION;
  2949. NDebugOverlay::Box( GetAbsOrigin(), mins, maxs, 255, 0, 0, 100, 0 );
  2950. }
  2951. }
  2952. //-----------------------------------------------------------------------------
  2953. // Purpose: Helper to remove from ladder
  2954. //-----------------------------------------------------------------------------
  2955. void CHL2_Player::ExitLadder()
  2956. {
  2957. if ( MOVETYPE_LADDER != GetMoveType() )
  2958. return;
  2959. SetMoveType( MOVETYPE_WALK );
  2960. SetMoveCollide( MOVECOLLIDE_DEFAULT );
  2961. // Remove from ladder
  2962. m_HL2Local.m_hLadder.Set( NULL );
  2963. }
  2964. surfacedata_t *CHL2_Player::GetLadderSurface( const Vector &origin )
  2965. {
  2966. extern const char *FuncLadder_GetSurfaceprops(CBaseEntity *pLadderEntity);
  2967. CBaseEntity *pLadder = m_HL2Local.m_hLadder.Get();
  2968. if ( pLadder )
  2969. {
  2970. const char *pSurfaceprops = FuncLadder_GetSurfaceprops(pLadder);
  2971. // get ladder material from func_ladder
  2972. return physprops->GetSurfaceData( physprops->GetSurfaceIndex( pSurfaceprops ) );
  2973. }
  2974. return BaseClass::GetLadderSurface(origin);
  2975. }
  2976. //-----------------------------------------------------------------------------
  2977. // Purpose: Queues up a use deny sound, played in ItemPostFrame.
  2978. //-----------------------------------------------------------------------------
  2979. void CHL2_Player::PlayUseDenySound()
  2980. {
  2981. m_bPlayUseDenySound = true;
  2982. }
  2983. void CHL2_Player::ItemPostFrame()
  2984. {
  2985. BaseClass::ItemPostFrame();
  2986. if ( m_bPlayUseDenySound )
  2987. {
  2988. m_bPlayUseDenySound = false;
  2989. EmitSound( "HL2Player.UseDeny" );
  2990. }
  2991. }
  2992. void CHL2_Player::StartWaterDeathSounds( void )
  2993. {
  2994. CPASAttenuationFilter filter( this );
  2995. if ( m_sndLeeches == NULL )
  2996. {
  2997. m_sndLeeches = (CSoundEnvelopeController::GetController()).SoundCreate( filter, entindex(), CHAN_STATIC, "coast.leech_bites_loop" , ATTN_NORM );
  2998. }
  2999. if ( m_sndLeeches )
  3000. {
  3001. (CSoundEnvelopeController::GetController()).Play( m_sndLeeches, 1.0f, 100 );
  3002. }
  3003. if ( m_sndWaterSplashes == NULL )
  3004. {
  3005. m_sndWaterSplashes = (CSoundEnvelopeController::GetController()).SoundCreate( filter, entindex(), CHAN_STATIC, "coast.leech_water_churn_loop" , ATTN_NORM );
  3006. }
  3007. if ( m_sndWaterSplashes )
  3008. {
  3009. (CSoundEnvelopeController::GetController()).Play( m_sndWaterSplashes, 1.0f, 100 );
  3010. }
  3011. }
  3012. void CHL2_Player::StopWaterDeathSounds( void )
  3013. {
  3014. if ( m_sndLeeches )
  3015. {
  3016. (CSoundEnvelopeController::GetController()).SoundFadeOut( m_sndLeeches, 0.5f, true );
  3017. m_sndLeeches = NULL;
  3018. }
  3019. if ( m_sndWaterSplashes )
  3020. {
  3021. (CSoundEnvelopeController::GetController()).SoundFadeOut( m_sndWaterSplashes, 0.5f, true );
  3022. m_sndWaterSplashes = NULL;
  3023. }
  3024. }
  3025. //-----------------------------------------------------------------------------
  3026. //
  3027. //-----------------------------------------------------------------------------
  3028. void CHL2_Player::MissedAR2AltFire()
  3029. {
  3030. if( GetPlayerProxy() != NULL )
  3031. {
  3032. GetPlayerProxy()->m_PlayerMissedAR2AltFire.FireOutput( this, this );
  3033. }
  3034. }
  3035. //-----------------------------------------------------------------------------
  3036. //
  3037. //-----------------------------------------------------------------------------
  3038. void CHL2_Player::DisplayLadderHudHint()
  3039. {
  3040. #if !defined( CLIENT_DLL )
  3041. if( gpGlobals->curtime > m_flTimeNextLadderHint )
  3042. {
  3043. m_flTimeNextLadderHint = gpGlobals->curtime + 60.0f;
  3044. CFmtStr hint;
  3045. hint.sprintf( "#Valve_Hint_Ladder" );
  3046. UTIL_HudHintText( this, hint.Access() );
  3047. }
  3048. #endif//CLIENT_DLL
  3049. }
  3050. //-----------------------------------------------------------------------------
  3051. // Shuts down sounds
  3052. //-----------------------------------------------------------------------------
  3053. void CHL2_Player::StopLoopingSounds( void )
  3054. {
  3055. if ( m_sndLeeches != NULL )
  3056. {
  3057. (CSoundEnvelopeController::GetController()).SoundDestroy( m_sndLeeches );
  3058. m_sndLeeches = NULL;
  3059. }
  3060. if ( m_sndWaterSplashes != NULL )
  3061. {
  3062. (CSoundEnvelopeController::GetController()).SoundDestroy( m_sndWaterSplashes );
  3063. m_sndWaterSplashes = NULL;
  3064. }
  3065. BaseClass::StopLoopingSounds();
  3066. }
  3067. //-----------------------------------------------------------------------------
  3068. void CHL2_Player::ModifyOrAppendPlayerCriteria( AI_CriteriaSet& set )
  3069. {
  3070. BaseClass::ModifyOrAppendPlayerCriteria( set );
  3071. if ( GlobalEntity_GetIndex( "gordon_precriminal" ) == -1 )
  3072. {
  3073. set.AppendCriteria( "gordon_precriminal", "0" );
  3074. }
  3075. }
  3076. //-----------------------------------------------------------------------------
  3077. //-----------------------------------------------------------------------------
  3078. const impactdamagetable_t &CHL2_Player::GetPhysicsImpactDamageTable()
  3079. {
  3080. if ( m_bUseCappedPhysicsDamageTable )
  3081. return gCappedPlayerImpactDamageTable;
  3082. return BaseClass::GetPhysicsImpactDamageTable();
  3083. }
  3084. //-----------------------------------------------------------------------------
  3085. // Purpose: Makes a splash when the player transitions between water states
  3086. //-----------------------------------------------------------------------------
  3087. void CHL2_Player::Splash( void )
  3088. {
  3089. CEffectData data;
  3090. data.m_fFlags = 0;
  3091. data.m_vOrigin = GetAbsOrigin();
  3092. data.m_vNormal = Vector(0,0,1);
  3093. data.m_vAngles = QAngle( 0, 0, 0 );
  3094. if ( GetWaterType() & CONTENTS_SLIME )
  3095. {
  3096. data.m_fFlags |= FX_WATER_IN_SLIME;
  3097. }
  3098. float flSpeed = GetAbsVelocity().Length();
  3099. if ( flSpeed < 300 )
  3100. {
  3101. data.m_flScale = random->RandomFloat( 10, 12 );
  3102. DispatchEffect( "waterripple", data );
  3103. }
  3104. else
  3105. {
  3106. data.m_flScale = random->RandomFloat( 6, 8 );
  3107. DispatchEffect( "watersplash", data );
  3108. }
  3109. }
  3110. CLogicPlayerProxy *CHL2_Player::GetPlayerProxy( void )
  3111. {
  3112. CLogicPlayerProxy *pProxy = dynamic_cast< CLogicPlayerProxy* > ( m_hPlayerProxy.Get() );
  3113. if ( pProxy == NULL )
  3114. {
  3115. pProxy = (CLogicPlayerProxy*)gEntList.FindEntityByClassname(NULL, "logic_playerproxy" );
  3116. if ( pProxy == NULL )
  3117. return NULL;
  3118. pProxy->m_hPlayer = this;
  3119. m_hPlayerProxy = pProxy;
  3120. }
  3121. return pProxy;
  3122. }
  3123. void CHL2_Player::FirePlayerProxyOutput( const char *pszOutputName, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller )
  3124. {
  3125. if ( GetPlayerProxy() == NULL )
  3126. return;
  3127. GetPlayerProxy()->FireNamedOutput( pszOutputName, variant, pActivator, pCaller );
  3128. }
  3129. LINK_ENTITY_TO_CLASS( logic_playerproxy, CLogicPlayerProxy);
  3130. BEGIN_DATADESC( CLogicPlayerProxy )
  3131. DEFINE_OUTPUT( m_OnFlashlightOn, "OnFlashlightOn" ),
  3132. DEFINE_OUTPUT( m_OnFlashlightOff, "OnFlashlightOff" ),
  3133. DEFINE_OUTPUT( m_RequestedPlayerHealth, "PlayerHealth" ),
  3134. DEFINE_OUTPUT( m_PlayerHasAmmo, "PlayerHasAmmo" ),
  3135. DEFINE_OUTPUT( m_PlayerHasNoAmmo, "PlayerHasNoAmmo" ),
  3136. DEFINE_OUTPUT( m_PlayerDied, "PlayerDied" ),
  3137. DEFINE_OUTPUT( m_PlayerMissedAR2AltFire, "PlayerMissedAR2AltFire" ),
  3138. DEFINE_INPUTFUNC( FIELD_VOID, "RequestPlayerHealth", InputRequestPlayerHealth ),
  3139. DEFINE_INPUTFUNC( FIELD_VOID, "SetFlashlightSlowDrain", InputSetFlashlightSlowDrain ),
  3140. DEFINE_INPUTFUNC( FIELD_VOID, "SetFlashlightNormalDrain", InputSetFlashlightNormalDrain ),
  3141. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetPlayerHealth", InputSetPlayerHealth ),
  3142. DEFINE_INPUTFUNC( FIELD_VOID, "RequestAmmoState", InputRequestAmmoState ),
  3143. DEFINE_INPUTFUNC( FIELD_VOID, "LowerWeapon", InputLowerWeapon ),
  3144. DEFINE_INPUTFUNC( FIELD_VOID, "EnableCappedPhysicsDamage", InputEnableCappedPhysicsDamage ),
  3145. DEFINE_INPUTFUNC( FIELD_VOID, "DisableCappedPhysicsDamage", InputDisableCappedPhysicsDamage ),
  3146. DEFINE_INPUTFUNC( FIELD_STRING, "SetLocatorTargetEntity", InputSetLocatorTargetEntity ),
  3147. #ifdef PORTAL
  3148. DEFINE_INPUTFUNC( FIELD_VOID, "SuppressCrosshair", InputSuppressCrosshair ),
  3149. #endif // PORTAL
  3150. DEFINE_FIELD( m_hPlayer, FIELD_EHANDLE ),
  3151. END_DATADESC()
  3152. void CLogicPlayerProxy::Activate( void )
  3153. {
  3154. BaseClass::Activate();
  3155. if ( m_hPlayer == NULL )
  3156. {
  3157. m_hPlayer = AI_GetSinglePlayer();
  3158. }
  3159. }
  3160. bool CLogicPlayerProxy::PassesDamageFilter( const CTakeDamageInfo &info )
  3161. {
  3162. if (m_hDamageFilter)
  3163. {
  3164. CBaseFilter *pFilter = (CBaseFilter *)(m_hDamageFilter.Get());
  3165. return pFilter->PassesDamageFilter(info);
  3166. }
  3167. return true;
  3168. }
  3169. void CLogicPlayerProxy::InputSetPlayerHealth( inputdata_t &inputdata )
  3170. {
  3171. if ( m_hPlayer == NULL )
  3172. return;
  3173. m_hPlayer->SetHealth( inputdata.value.Int() );
  3174. }
  3175. void CLogicPlayerProxy::InputRequestPlayerHealth( inputdata_t &inputdata )
  3176. {
  3177. if ( m_hPlayer == NULL )
  3178. return;
  3179. m_RequestedPlayerHealth.Set( m_hPlayer->GetHealth(), inputdata.pActivator, inputdata.pCaller );
  3180. }
  3181. void CLogicPlayerProxy::InputSetFlashlightSlowDrain( inputdata_t &inputdata )
  3182. {
  3183. if( m_hPlayer == NULL )
  3184. return;
  3185. CHL2_Player *pPlayer = dynamic_cast<CHL2_Player*>(m_hPlayer.Get());
  3186. if( pPlayer )
  3187. pPlayer->SetFlashlightPowerDrainScale( hl2_darkness_flashlight_factor.GetFloat() );
  3188. }
  3189. void CLogicPlayerProxy::InputSetFlashlightNormalDrain( inputdata_t &inputdata )
  3190. {
  3191. if( m_hPlayer == NULL )
  3192. return;
  3193. CHL2_Player *pPlayer = dynamic_cast<CHL2_Player*>(m_hPlayer.Get());
  3194. if( pPlayer )
  3195. pPlayer->SetFlashlightPowerDrainScale( 1.0f );
  3196. }
  3197. void CLogicPlayerProxy::InputRequestAmmoState( inputdata_t &inputdata )
  3198. {
  3199. if( m_hPlayer == NULL )
  3200. return;
  3201. CHL2_Player *pPlayer = dynamic_cast<CHL2_Player*>(m_hPlayer.Get());
  3202. for ( int i = 0 ; i < pPlayer->WeaponCount(); ++i )
  3203. {
  3204. CBaseCombatWeapon* pCheck = pPlayer->GetWeapon( i );
  3205. if ( pCheck )
  3206. {
  3207. if ( pCheck->HasAnyAmmo() && (pCheck->UsesPrimaryAmmo() || pCheck->UsesSecondaryAmmo()))
  3208. {
  3209. m_PlayerHasAmmo.FireOutput( this, this, 0 );
  3210. return;
  3211. }
  3212. }
  3213. }
  3214. m_PlayerHasNoAmmo.FireOutput( this, this, 0 );
  3215. }
  3216. void CLogicPlayerProxy::InputLowerWeapon( inputdata_t &inputdata )
  3217. {
  3218. if( m_hPlayer == NULL )
  3219. return;
  3220. CHL2_Player *pPlayer = dynamic_cast<CHL2_Player*>(m_hPlayer.Get());
  3221. pPlayer->Weapon_Lower();
  3222. }
  3223. void CLogicPlayerProxy::InputEnableCappedPhysicsDamage( inputdata_t &inputdata )
  3224. {
  3225. if( m_hPlayer == NULL )
  3226. return;
  3227. CHL2_Player *pPlayer = dynamic_cast<CHL2_Player*>(m_hPlayer.Get());
  3228. pPlayer->EnableCappedPhysicsDamage();
  3229. }
  3230. void CLogicPlayerProxy::InputDisableCappedPhysicsDamage( inputdata_t &inputdata )
  3231. {
  3232. if( m_hPlayer == NULL )
  3233. return;
  3234. CHL2_Player *pPlayer = dynamic_cast<CHL2_Player*>(m_hPlayer.Get());
  3235. pPlayer->DisableCappedPhysicsDamage();
  3236. }
  3237. void CLogicPlayerProxy::InputSetLocatorTargetEntity( inputdata_t &inputdata )
  3238. {
  3239. if( m_hPlayer == NULL )
  3240. return;
  3241. CBaseEntity *pTarget = NULL; // assume no target
  3242. string_t iszTarget = MAKE_STRING( inputdata.value.String() );
  3243. if( iszTarget != NULL_STRING )
  3244. {
  3245. pTarget = gEntList.FindEntityByName( NULL, iszTarget );
  3246. }
  3247. CHL2_Player *pPlayer = dynamic_cast<CHL2_Player*>(m_hPlayer.Get());
  3248. pPlayer->SetLocatorTargetEntity(pTarget);
  3249. }
  3250. #ifdef PORTAL
  3251. void CLogicPlayerProxy::InputSuppressCrosshair( inputdata_t &inputdata )
  3252. {
  3253. if( m_hPlayer == NULL )
  3254. return;
  3255. CPortal_Player *pPlayer = ToPortalPlayer(m_hPlayer.Get());
  3256. pPlayer->SuppressCrosshair( true );
  3257. }
  3258. #endif // PORTAL