Counter Strike : Global Offensive Source Code
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.

9944 lines
264 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Functions dealing with the player.
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "const.h"
  8. #include "baseplayer_shared.h"
  9. #include "trains.h"
  10. #include "soundent.h"
  11. #include "gib.h"
  12. #include "shake.h"
  13. #include "decals.h"
  14. #include "gamerules.h"
  15. #include "game.h"
  16. #include "entityapi.h"
  17. #include "entitylist.h"
  18. #include "eventqueue.h"
  19. #include "worldsize.h"
  20. #include "isaverestore.h"
  21. #include "globalstate.h"
  22. #include "basecombatweapon.h"
  23. #include "ai_basenpc.h"
  24. #include "ai_network.h"
  25. #include "ai_node.h"
  26. #include "ai_networkmanager.h"
  27. #include "ammodef.h"
  28. #include "mathlib/mathlib.h"
  29. #include "ndebugoverlay.h"
  30. #include "baseviewmodel.h"
  31. #include "in_buttons.h"
  32. #include "client.h"
  33. #include "team.h"
  34. #include "particle_smokegrenade.h"
  35. #include "IEffects.h"
  36. #include "vstdlib/random.h"
  37. #include "vstdlib/vstrtools.h"
  38. #include "engine/IEngineSound.h"
  39. #include "movehelper_server.h"
  40. #include "igamemovement.h"
  41. #include "saverestoretypes.h"
  42. #include "iservervehicle.h"
  43. #include "movevars_shared.h"
  44. #include "vcollide_parse.h"
  45. #include "player_command.h"
  46. #include "vehicle_base.h"
  47. #include "ai_criteria.h"
  48. #include "globals.h"
  49. #include "usermessages.h"
  50. #include "gamevars_shared.h"
  51. #include "world.h"
  52. #include "physobj.h"
  53. #include "keyvalues.h"
  54. #include "coordsize.h"
  55. #include "vphysics/player_controller.h"
  56. #include "saverestore_utlvector.h"
  57. #include "hltvdirector.h"
  58. #if defined( REPLAY_ENABLED )
  59. #include "replaydirector.h"
  60. #endif
  61. #include "nav_mesh.h"
  62. #include "env_zoom.h"
  63. #include "rumble_shared.h"
  64. #include "GameStats.h"
  65. #include "env_tonemap_controller.h"
  66. #include "npcevent.h"
  67. #include "datacache/imdlcache.h"
  68. #include "hintsystem.h"
  69. #include "env_debughistory.h"
  70. #include "fogcontroller.h"
  71. #include "gameinterface.h"
  72. #include "toolframework/itoolframework.h"
  73. #include "sendprop_priorities.h"
  74. #include "logic_playerproxy.h"
  75. #include "fogvolume.h"
  76. #include "iclient.h"
  77. #include "vote_controller.h"
  78. #include "platforminputdevice.h"
  79. #ifdef PORTAL2
  80. #include "weapon_portalgun.h"
  81. #endif
  82. #ifdef HL2_DLL
  83. #include "combine_mine.h"
  84. #include "weapon_physcannon.h"
  85. #endif
  86. #ifdef CSTRIKE_DLL
  87. #include "weapon_c4.h"
  88. #include "basecsgrenade_projectile.h"
  89. #include "playerdecals_signature.h"
  90. #endif
  91. #include "CegClientWrapper.h"
  92. // memdbgon must be the last include file in a .cpp file!!!
  93. #include "tier0/memdbgon.h"
  94. ConVar autoaim_max_dist( "autoaim_max_dist", "2160" ); // 2160 = 180 feet
  95. ConVar autoaim_max_deflect( "autoaim_max_deflect", "0.99" );
  96. ConVar spec_replay_cam_delay( "spec_replay_cam_delay", "5", FCVAR_RELEASE, "Hltv Replay delay in seconds" );
  97. ConVar spec_replay_cam_options( "spec_replay_cam_options", "0", FCVAR_RELEASE, "Debug options for replay cam" );
  98. ConVar spec_replay_winddown_time( "spec_replay_winddown_time", "2", FCVAR_RELEASE, "The trailing time, in seconds, of replay past the event, including fade-out" );
  99. #ifdef CSTRIKE_DLL
  100. ConVar spec_freeze_time( "spec_freeze_time", "3.0", FCVAR_RELEASE | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." );
  101. ConVar spec_freeze_time_lock( "spec_freeze_time_lock", "1.0", FCVAR_RELEASE | FCVAR_REPLICATED, "Time players are prevented from skipping the freeze cam" );
  102. ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.3", FCVAR_RELEASE | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0 );
  103. ConVar spec_freeze_panel_extended_time( "spec_freeze_panel_extended_time", "0.0", FCVAR_RELEASE | FCVAR_REPLICATED, "Time spent with the freeze panel still up after observer freeze cam is done." );
  104. ConVar spec_freeze_deathanim_time( "spec_freeze_deathanim_time", "0.8", FCVAR_RELEASE | FCVAR_REPLICATED, "The time that the death cam will spend watching the player's ragdoll before going into the freeze death cam." );
  105. ConVar spec_freeze_target_fov_long( "spec_freeze_target_fov_long", "90", FCVAR_CHEAT | FCVAR_REPLICATED, "The target FOV that the deathcam should use when the cam zoom far away on the target." );
  106. ConVar spec_freeze_target_fov( "spec_freeze_target_fov", "42", FCVAR_CHEAT | FCVAR_REPLICATED, "The target FOV that the deathcam should use." );
  107. ConVar spec_allow_roaming( "spec_allow_roaming", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "If nonzero, allow free-roaming spectator camera." );
  108. #else
  109. ConVar spec_freeze_time( "spec_freeze_time", "4.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." );
  110. ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.4", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0 );
  111. #endif
  112. ConVar sv_bonus_challenge( "sv_bonus_challenge", "0", FCVAR_REPLICATED, "Set to values other than 0 to select a bonus map challenge type." );
  113. ConVar sv_force_transmit_players( "sv_force_transmit_players", "0", FCVAR_RELEASE, "Will transmit players to all clients regardless of PVS checks." );
  114. ConVar sv_regeneration_wait_time ("sv_regeneration_wait_time", "1.0", FCVAR_REPLICATED );
  115. static ConVar sv_maxusrcmdprocessticks( "sv_maxusrcmdprocessticks", "16", FCVAR_RELEASE, "Maximum number of client-issued usrcmd ticks that can be replayed in packet loss conditions, 0 to allow no restrictions" );
  116. static ConVar old_armor( "player_old_armor", "0" );
  117. bool IsInCommentaryMode( void );
  118. bool IsListeningToCommentary( void );
  119. // This is declared in the engine, too
  120. ConVar sv_noclipduringpause( "sv_noclipduringpause", "0", FCVAR_REPLICATED | FCVAR_CHEAT, "If cheats are enabled, then you can noclip with the game paused (for doing screenshots, etc.)." );
  121. extern ConVar sv_maxunlag;
  122. extern ConVar sv_turbophysics;
  123. extern ConVar *sv_maxreplay;
  124. extern ConVar sv_coaching_enabled;
  125. extern CServerGameDLL g_ServerGameDLL;
  126. // TIME BASED DAMAGE AMOUNT
  127. // tweak these values based on gameplay feedback:
  128. #define PARALYZE_DURATION 2 // number of 2 second intervals to take damage
  129. #define PARALYZE_DAMAGE 1.0 // damage to take each 2 second interval
  130. #define NERVEGAS_DURATION 2
  131. #define NERVEGAS_DAMAGE 5.0
  132. #define POISON_DURATION 5
  133. #define POISON_DAMAGE 2.0
  134. #define RADIATION_DURATION 2
  135. #define RADIATION_DAMAGE 1.0
  136. #define ACID_DURATION 2
  137. #define ACID_DAMAGE 5.0
  138. #define SLOWBURN_DURATION 2
  139. #define SLOWBURN_DAMAGE 1.0
  140. #define SLOWFREEZE_DURATION 2
  141. #define SLOWFREEZE_DAMAGE 1.0
  142. //----------------------------------------------------
  143. // Player Physics Shadow
  144. //----------------------------------------------------
  145. extern bool g_fDrawLines;
  146. int gEvilImpulse101;
  147. bool gInitHUD = true;
  148. extern void respawn(CBaseEntity *pEdict, bool fCopyCorpse);
  149. int MapTextureTypeStepType(char chTextureType);
  150. extern void SpawnBlood(Vector vecSpot, const Vector &vecDir, int bloodColor, float flDamage);
  151. extern void AddMultiDamage( const CTakeDamageInfo &info, CBaseEntity *pEntity );
  152. #define CMD_MOSTRECENT 0
  153. //#define FLASH_DRAIN_TIME 1.2 //100 units/3 minutes
  154. //#define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit)
  155. //#define PLAYER_MAX_SAFE_FALL_DIST 20// falling any farther than this many feet will inflict damage
  156. //#define PLAYER_FATAL_FALL_DIST 60// 100% damage inflicted if player falls this many feet
  157. //#define DAMAGE_PER_UNIT_FALLEN (float)( 100 ) / ( ( PLAYER_FATAL_FALL_DIST - PLAYER_MAX_SAFE_FALL_DIST ) * 12 )
  158. //#define MAX_SAFE_FALL_UNITS ( PLAYER_MAX_SAFE_FALL_DIST * 12 )
  159. // player damage adjusters
  160. ConVar sk_player_head( "sk_player_head","2" );
  161. ConVar sk_player_chest( "sk_player_chest","1" );
  162. ConVar sk_player_stomach( "sk_player_stomach","1" );
  163. ConVar sk_player_arm( "sk_player_arm","1" );
  164. ConVar sk_player_leg( "sk_player_leg","1" );
  165. ConVar player_debug_print_damage( "player_debug_print_damage", "0", FCVAR_CHEAT, "When true, print amount and type of all damage received by player to console." );
  166. void CC_GiveCurrentAmmo( void )
  167. {
  168. CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
  169. if( pPlayer )
  170. {
  171. CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
  172. if( pWeapon )
  173. {
  174. if( pWeapon->UsesPrimaryAmmo() )
  175. {
  176. int ammoIndex = pWeapon->GetPrimaryAmmoType();
  177. if( ammoIndex != -1 )
  178. {
  179. int giveAmount;
  180. giveAmount = GetAmmoDef()->MaxCarry(ammoIndex, pPlayer);
  181. pPlayer->GiveAmmo( giveAmount, GetAmmoDef()->GetAmmoOfIndex(ammoIndex)->pName );
  182. }
  183. }
  184. if( pWeapon->UsesSecondaryAmmo() && pWeapon->HasSecondaryAmmo() )
  185. {
  186. // Give secondary ammo out, as long as the player already has some
  187. // from a presumeably natural source. This prevents players on XBox
  188. // having Combine Balls and so forth in areas of the game that
  189. // were not tested with these items.
  190. int ammoIndex = pWeapon->GetSecondaryAmmoType();
  191. if( ammoIndex != -1 )
  192. {
  193. int giveAmount;
  194. giveAmount = GetAmmoDef()->MaxCarry(ammoIndex, pPlayer);
  195. pPlayer->GiveAmmo( giveAmount, GetAmmoDef()->GetAmmoOfIndex(ammoIndex)->pName );
  196. }
  197. }
  198. }
  199. }
  200. }
  201. static ConCommand givecurrentammo("givecurrentammo", CC_GiveCurrentAmmo, "Give a supply of ammo for current weapon..\n", FCVAR_CHEAT );
  202. // pl
  203. BEGIN_SIMPLE_DATADESC( CPlayerState )
  204. // DEFINE_FIELD( netname, FIELD_STRING ), // Don't stomp player name with what's in save/restore
  205. DEFINE_FIELD( v_angle, FIELD_VECTOR ),
  206. DEFINE_FIELD( deadflag, FIELD_BOOLEAN ),
  207. END_DATADESC()
  208. // Global Savedata for player
  209. BEGIN_DATADESC( CBasePlayer )
  210. DEFINE_EMBEDDED( m_Local ),
  211. DEFINE_UTLVECTOR( m_hTriggerSoundscapeList, FIELD_EHANDLE ),
  212. DEFINE_EMBEDDED( pl ),
  213. DEFINE_FIELD( m_StuckLast, FIELD_INTEGER ),
  214. DEFINE_FIELD( m_nButtons, FIELD_INTEGER ),
  215. DEFINE_FIELD( m_afButtonLast, FIELD_INTEGER ),
  216. DEFINE_FIELD( m_afButtonPressed, FIELD_INTEGER ),
  217. DEFINE_FIELD( m_afButtonReleased, FIELD_INTEGER ),
  218. DEFINE_FIELD( m_afButtonDisabled, FIELD_INTEGER ),
  219. DEFINE_FIELD( m_afButtonForced, FIELD_INTEGER ),
  220. DEFINE_FIELD( m_iFOV, FIELD_INTEGER ),
  221. DEFINE_FIELD( m_iFOVStart, FIELD_INTEGER ),
  222. DEFINE_FIELD( m_flFOVTime, FIELD_TIME ),
  223. DEFINE_FIELD( m_iDefaultFOV,FIELD_INTEGER ),
  224. DEFINE_FIELD( m_flVehicleViewFOV, FIELD_FLOAT ),
  225. //DEFINE_FIELD( m_fOnTarget, FIELD_BOOLEAN ), // Don't need to restore
  226. DEFINE_FIELD( m_iObserverMode, FIELD_INTEGER ),
  227. DEFINE_FIELD( m_iObserverLastMode, FIELD_INTEGER ),
  228. DEFINE_FIELD( m_hObserverTarget, FIELD_EHANDLE ),
  229. DEFINE_FIELD( m_bForcedObserverMode, FIELD_BOOLEAN ),
  230. DEFINE_FIELD( m_bActiveCameraMan, FIELD_BOOLEAN ),
  231. DEFINE_FIELD( m_bCameraManXRay, FIELD_BOOLEAN ),
  232. DEFINE_FIELD( m_bCameraManOverview, FIELD_BOOLEAN ),
  233. DEFINE_FIELD( m_bCameraManScoreBoard, FIELD_BOOLEAN ),
  234. DEFINE_FIELD( m_uCameraManGraphs, FIELD_INTEGER ),
  235. DEFINE_FIELD( m_iDeathPostEffect, FIELD_INTEGER ),
  236. DEFINE_AUTO_ARRAY( m_szAnimExtension, FIELD_CHARACTER ),
  237. // DEFINE_CUSTOM_FIELD( m_Activity, ActivityDataOps() ),
  238. DEFINE_FIELD( m_nUpdateRate, FIELD_INTEGER ),
  239. DEFINE_FIELD( m_fLerpTime, FIELD_FLOAT ),
  240. DEFINE_FIELD( m_bLagCompensation, FIELD_BOOLEAN ),
  241. DEFINE_FIELD( m_bPredictWeapons, FIELD_BOOLEAN ),
  242. DEFINE_FIELD( m_vecAdditionalPVSOrigin, FIELD_POSITION_VECTOR ),
  243. DEFINE_FIELD( m_vecCameraPVSOrigin, FIELD_POSITION_VECTOR ),
  244. DEFINE_FIELD( m_bDropEnabled, FIELD_BOOLEAN ),
  245. DEFINE_FIELD( m_bDuckEnabled, FIELD_BOOLEAN ),
  246. DEFINE_FIELD( m_hUseEntity, FIELD_EHANDLE ),
  247. DEFINE_FIELD( m_iTrain, FIELD_INTEGER ),
  248. DEFINE_FIELD( m_iRespawnFrames, FIELD_FLOAT ),
  249. DEFINE_FIELD( m_afPhysicsFlags, FIELD_INTEGER ),
  250. DEFINE_FIELD( m_hVehicle, FIELD_EHANDLE ),
  251. // recreate, don't restore
  252. // DEFINE_FIELD( m_CommandContext, CUtlVector < CCommandContext > ),
  253. //DEFINE_FIELD( m_pPhysicsController, FIELD_POINTER ),
  254. //DEFINE_FIELD( m_pShadowStand, FIELD_POINTER ),
  255. //DEFINE_FIELD( m_pShadowCrouch, FIELD_POINTER ),
  256. //DEFINE_FIELD( m_vphysicsCollisionState, FIELD_INTEGER ),
  257. // DEFINE_FIELD( m_lastNavArea, CNavArea ),
  258. DEFINE_ARRAY( m_szNetworkIDString, FIELD_CHARACTER, MAX_NETWORKID_LENGTH ),
  259. DEFINE_FIELD( m_oldOrigin, FIELD_POSITION_VECTOR ),
  260. DEFINE_FIELD( m_vecSmoothedVelocity, FIELD_VECTOR ),
  261. //DEFINE_FIELD( m_touchedPhysObject, FIELD_BOOLEAN ),
  262. //DEFINE_FIELD( m_bPhysicsWasFrozen, FIELD_BOOLEAN ),
  263. //DEFINE_FIELD( m_iPlayerSound, FIELD_INTEGER ), // Don't restore, set in Precache()
  264. DEFINE_FIELD( m_iTargetVolume, FIELD_INTEGER ),
  265. DEFINE_AUTO_ARRAY( m_rgItems, FIELD_INTEGER ),
  266. //DEFINE_FIELD( m_fNextSuicideTime, FIELD_TIME ),
  267. // DEFINE_FIELD( m_PlayerInfo, CPlayerInfo ),
  268. DEFINE_FIELD( m_flSuitUpdate, FIELD_TIME ),
  269. DEFINE_AUTO_ARRAY( m_rgSuitPlayList, FIELD_INTEGER ),
  270. DEFINE_FIELD( m_iSuitPlayNext, FIELD_INTEGER ),
  271. DEFINE_AUTO_ARRAY( m_rgiSuitNoRepeat, FIELD_INTEGER ),
  272. DEFINE_AUTO_ARRAY( m_rgflSuitNoRepeatTime, FIELD_TIME ),
  273. DEFINE_FIELD( m_bPauseBonusProgress, FIELD_BOOLEAN ),
  274. DEFINE_FIELD( m_iBonusProgress, FIELD_INTEGER ),
  275. DEFINE_FIELD( m_iBonusChallenge, FIELD_INTEGER ),
  276. DEFINE_FIELD( m_lastDamageAmount, FIELD_INTEGER ),
  277. DEFINE_FIELD( m_fTimeLastHurt, FIELD_TIME ),
  278. DEFINE_FIELD( m_tbdPrev, FIELD_TIME ),
  279. DEFINE_FIELD( m_flStepSoundTime, FIELD_FLOAT ),
  280. DEFINE_ARRAY( m_szNetname, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ),
  281. //DEFINE_FIELD( m_flgeigerRange, FIELD_FLOAT ), // Don't restore, reset in Precache()
  282. //DEFINE_FIELD( m_flgeigerDelay, FIELD_FLOAT ), // Don't restore, reset in Precache()
  283. //DEFINE_FIELD( m_igeigerRangePrev, FIELD_FLOAT ), // Don't restore, reset in Precache()
  284. //DEFINE_FIELD( m_iStepLeft, FIELD_INTEGER ), // Don't need to restore
  285. //DEFINE_FIELD( m_chTextureType, FIELD_CHARACTER ), // Don't need to restore
  286. //DEFINE_FIELD( m_surfaceProps, FIELD_INTEGER ), // don't need to restore, reset by gamemovement
  287. // DEFINE_FIELD( m_pSurfaceData, surfacedata_t* ),
  288. //DEFINE_FIELD( m_surfaceFriction, FIELD_FLOAT ),
  289. //DEFINE_FIELD( m_chPreviousTextureType, FIELD_CHARACTER ),
  290. DEFINE_FIELD( m_idrowndmg, FIELD_INTEGER ),
  291. DEFINE_FIELD( m_idrownrestored, FIELD_INTEGER ),
  292. DEFINE_FIELD( m_nPoisonDmg, FIELD_INTEGER ),
  293. DEFINE_FIELD( m_nPoisonRestored, FIELD_INTEGER ),
  294. DEFINE_FIELD( m_bitsHUDDamage, FIELD_INTEGER ),
  295. DEFINE_FIELD( m_fInitHUD, FIELD_BOOLEAN ),
  296. DEFINE_FIELD( m_flDeathTime, FIELD_TIME ),
  297. DEFINE_FIELD( m_flDeathAnimTime, FIELD_TIME ),
  298. DEFINE_FIELD( m_fForceTeam, FIELD_TIME ),
  299. //DEFINE_FIELD( m_fGameHUDInitialized, FIELD_BOOLEAN ), // only used in multiplayer games
  300. //DEFINE_FIELD( m_fWeapon, FIELD_BOOLEAN ), // Don't restore, client needs reset
  301. //DEFINE_FIELD( m_iUpdateTime, FIELD_INTEGER ), // Don't need to restore
  302. //DEFINE_FIELD( m_iClientBattery, FIELD_INTEGER ), // Don't restore, client needs reset
  303. //DEFINE_FIELD( m_iClientHideHUD, FIELD_INTEGER ), // Don't restore, client needs reset
  304. //DEFINE_FIELD( m_vecAutoAim, FIELD_VECTOR ), // Don't save/restore - this is recomputed
  305. //DEFINE_FIELD( m_lastx, FIELD_INTEGER ),
  306. //DEFINE_FIELD( m_lasty, FIELD_INTEGER ),
  307. DEFINE_FIELD( m_iFrags, FIELD_INTEGER ),
  308. DEFINE_FIELD( m_iDeaths, FIELD_INTEGER ),
  309. DEFINE_FIELD( m_bAllowInstantSpawn, FIELD_BOOLEAN ),
  310. DEFINE_FIELD( m_flNextDecalTime, FIELD_TIME ),
  311. //DEFINE_AUTO_ARRAY( m_szTeamName, FIELD_STRING ), // mp
  312. //DEFINE_FIELD( m_iConnected, FIELD_INTEGER ),
  313. // from edict_t
  314. DEFINE_FIELD( m_ArmorValue, FIELD_INTEGER ),
  315. DEFINE_FIELD( m_DmgOrigin, FIELD_VECTOR ),
  316. DEFINE_FIELD( m_DmgTake, FIELD_FLOAT ),
  317. DEFINE_FIELD( m_DmgSave, FIELD_FLOAT ),
  318. DEFINE_FIELD( m_AirFinished, FIELD_TIME ),
  319. DEFINE_FIELD( m_PainFinished, FIELD_TIME ),
  320. DEFINE_FIELD( m_iPlayerLocked, FIELD_INTEGER ),
  321. DEFINE_AUTO_ARRAY( m_hViewModel, FIELD_EHANDLE ),
  322. DEFINE_FIELD( m_flMaxspeed, FIELD_FLOAT ),
  323. DEFINE_FIELD( m_flWaterJumpTime, FIELD_TIME ),
  324. DEFINE_FIELD( m_vecWaterJumpVel, FIELD_VECTOR ),
  325. DEFINE_FIELD( m_nImpulse, FIELD_INTEGER ),
  326. DEFINE_FIELD( m_flSwimSoundTime, FIELD_TIME ),
  327. DEFINE_FIELD( m_ignoreLadderJumpTime, FIELD_TIME ),
  328. DEFINE_FIELD( m_bHasWalkMovedSinceLastJump, FIELD_BOOLEAN ),
  329. DEFINE_FIELD( m_vecLadderNormal, FIELD_VECTOR ),
  330. DEFINE_FIELD( m_flFlashTime, FIELD_TIME ),
  331. DEFINE_FIELD( m_nDrownDmgRate, FIELD_INTEGER ),
  332. DEFINE_FIELD( m_iSuicideCustomKillFlags, FIELD_INTEGER ),
  333. // NOT SAVED
  334. //DEFINE_FIELD( m_vForcedOrigin, FIELD_VECTOR ),
  335. //DEFINE_FIELD( m_bForceOrigin, FIELD_BOOLEAN ),
  336. //DEFINE_FIELD( m_nTickBase, FIELD_INTEGER ),
  337. //DEFINE_FIELD( m_LastCmd, FIELD_ ),
  338. // DEFINE_FIELD( m_pCurrentCommand, CUserCmd ),
  339. //DEFINE_FIELD( m_bGamePaused, FIELD_BOOLEAN ),
  340. // DEFINE_FIELD( m_iVehicleAnalogBias, FIELD_INTEGER ),
  341. // m_flVehicleViewFOV
  342. // m_vecVehicleViewOrigin
  343. // m_vecVehicleViewAngles
  344. // m_nVehicleViewSavedFrame
  345. DEFINE_FIELD( m_bitsDamageType, FIELD_INTEGER ),
  346. DEFINE_AUTO_ARRAY( m_rgbTimeBasedDamage, FIELD_CHARACTER ),
  347. DEFINE_FIELD( m_fLastPlayerTalkTime, FIELD_FLOAT ),
  348. DEFINE_FIELD( m_hLastWeapon, FIELD_EHANDLE ),
  349. #if !defined( NO_ENTITY_PREDICTION )
  350. // DEFINE_FIELD( m_SimulatedByThisPlayer, CUtlVector < CHandle < CBaseEntity > > ),
  351. #endif
  352. DEFINE_FIELD( m_flOldPlayerZ, FIELD_FLOAT ),
  353. DEFINE_FIELD( m_flOldPlayerViewOffsetZ, FIELD_FLOAT ),
  354. DEFINE_FIELD( m_bPlayerUnderwater, FIELD_BOOLEAN ),
  355. DEFINE_FIELD( m_hViewEntity, FIELD_EHANDLE ),
  356. DEFINE_FIELD( m_bShouldDrawPlayerWhileUsingViewEntity, FIELD_BOOLEAN ),
  357. DEFINE_FIELD( m_hConstraintEntity, FIELD_EHANDLE ),
  358. DEFINE_FIELD( m_vecConstraintCenter, FIELD_POSITION_VECTOR ),
  359. DEFINE_FIELD( m_flConstraintRadius, FIELD_FLOAT ),
  360. DEFINE_FIELD( m_flConstraintWidth, FIELD_FLOAT ),
  361. DEFINE_FIELD( m_flConstraintSpeedFactor, FIELD_FLOAT ),
  362. DEFINE_FIELD( m_bConstraintPastRadius, FIELD_BOOLEAN ),
  363. DEFINE_FIELD( m_hZoomOwner, FIELD_EHANDLE ),
  364. DEFINE_FIELD( m_flLaggedMovementValue, FIELD_FLOAT ),
  365. DEFINE_FIELD( m_vNewVPhysicsPosition, FIELD_VECTOR ),
  366. DEFINE_FIELD( m_vNewVPhysicsVelocity, FIELD_VECTOR ),
  367. DEFINE_FIELD( m_bSinglePlayerGameEnding, FIELD_BOOLEAN ),
  368. DEFINE_ARRAY( m_szLastPlaceName, FIELD_CHARACTER, MAX_PLACE_NAME_LENGTH ),
  369. DEFINE_FIELD( m_autoKickDisabled, FIELD_BOOLEAN ),
  370. // Function Pointers
  371. DEFINE_FUNCTION( PlayerDeathThink ),
  372. DEFINE_FUNCTION( PlayerForceTeamThink ),
  373. // Inputs
  374. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetHealth", InputSetHealth ),
  375. DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetHUDVisibility", InputSetHUDVisibility ),
  376. DEFINE_INPUTFUNC( FIELD_STRING, "SetFogController", InputSetFogController ),
  377. DEFINE_FIELD( m_nNumCrouches, FIELD_INTEGER ),
  378. DEFINE_FIELD( m_bDuckToggled, FIELD_BOOLEAN ),
  379. DEFINE_FIELD( m_flForwardMove, FIELD_FLOAT ),
  380. DEFINE_FIELD( m_flSideMove, FIELD_FLOAT ),
  381. DEFINE_FIELD( m_vecPreviouslyPredictedOrigin, FIELD_POSITION_VECTOR ),
  382. DEFINE_FIELD( m_nNumCrateHudHints, FIELD_INTEGER ),
  383. DEFINE_FIELD( m_hPostProcessCtrl, FIELD_EHANDLE ),
  384. DEFINE_FIELD( m_hColorCorrectionCtrl, FIELD_EHANDLE ),
  385. DEFINE_EMBEDDED( m_PlayerFog ),
  386. DEFINE_FIELD( m_flDuckAmount, FIELD_FLOAT ),
  387. DEFINE_FIELD( m_flDuckSpeed, FIELD_FLOAT ),
  388. // DEFINE_FIELD( m_nBodyPitchPoseParam, FIELD_INTEGER ),
  389. // DEFINE_ARRAY( m_StepSoundCache, StepSoundCache_t, 2 ),
  390. // DEFINE_UTLVECTOR( m_vecPlayerCmdInfo ),
  391. // DEFINE_UTLVECTOR( m_vecPlayerSimInfo ),
  392. END_DATADESC()
  393. BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseAnimating, "The player entity." )
  394. DEFINE_SCRIPTFUNC_NAMED( ScriptIsPlayerNoclipping, "IsNoclipping", "Returns true if the player is in noclip mode." )
  395. END_SCRIPTDESC();
  396. int giPrecacheGrunt = 0;
  397. edict_t *CBasePlayer::s_PlayerEdict = NULL;
  398. inline bool ShouldRunCommandsInContext( const CCommandContext *ctx )
  399. {
  400. // TODO: This should be enabled at some point. If usercmds can run while paused, then
  401. // they can create entities which will never die and it will fill up the entity list.
  402. #ifdef NO_USERCMDS_DURING_PAUSE
  403. return !ctx->paused || sv_noclipduringpause.GetInt();
  404. #else
  405. return true;
  406. #endif
  407. }
  408. CBasePlayer* CBasePlayer::GetPlayerBySteamID( const CSteamID &steamID )
  409. {
  410. CSteamID steamIDPlayer;
  411. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  412. {
  413. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  414. if ( !pPlayer )
  415. continue;
  416. pPlayer->GetSteamID( &steamIDPlayer );
  417. if ( steamIDPlayer == steamID )
  418. return pPlayer;
  419. }
  420. return NULL;
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Purpose:
  424. // Output : CBaseViewModel
  425. //-----------------------------------------------------------------------------
  426. CBaseViewModel *CBasePlayer::GetViewModel( int index /*= 0*/ )
  427. {
  428. Assert( index >= 0 && index < MAX_VIEWMODELS );
  429. return m_hViewModel[ index ].Get();
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Purpose:
  433. //-----------------------------------------------------------------------------
  434. void CBasePlayer::CreateViewModel( int index /*=0*/ )
  435. {
  436. Assert( index >= 0 && index < MAX_VIEWMODELS );
  437. if ( GetViewModel( index ) )
  438. return;
  439. CBaseViewModel *vm = ( CBaseViewModel * )CreateEntityByName( "viewmodel" );
  440. if ( vm )
  441. {
  442. vm->SetAbsOrigin( GetAbsOrigin() );
  443. vm->SetOwner( this );
  444. vm->SetIndex( index );
  445. DispatchSpawn( vm );
  446. vm->FollowEntity( this );
  447. m_hViewModel.Set( index, vm );
  448. }
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose:
  452. //-----------------------------------------------------------------------------
  453. void CBasePlayer::DestroyViewModels( void )
  454. {
  455. int i;
  456. for ( i = MAX_VIEWMODELS - 1; i >= 0; i-- )
  457. {
  458. CBaseViewModel *vm = GetViewModel( i );
  459. if ( !vm )
  460. continue;
  461. UTIL_Remove( vm );
  462. m_hViewModel.Set( i, INVALID_EHANDLE );
  463. }
  464. }
  465. //-----------------------------------------------------------------------------
  466. // Purpose: Static member function to create a player of the specified class
  467. // Input : *className -
  468. // *ed -
  469. // Output : CBasePlayer
  470. //-----------------------------------------------------------------------------
  471. CBasePlayer *CBasePlayer::CreatePlayer( const char *className, edict_t *ed )
  472. {
  473. CBasePlayer *player;
  474. CBasePlayer::s_PlayerEdict = ed;
  475. player = ( CBasePlayer * )CreateEntityByName( className );
  476. return player;
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Purpose:
  480. // Input :
  481. // Output :
  482. //-----------------------------------------------------------------------------
  483. CBasePlayer::CBasePlayer( )
  484. {
  485. AddEFlags( EFL_NO_AUTO_EDICT_ATTACH );
  486. #ifdef _DEBUG
  487. m_vecAdditionalPVSOrigin.Init();
  488. m_vecCameraPVSOrigin.Init();
  489. m_DmgOrigin.Init();
  490. m_vecLadderNormal.Init();
  491. m_oldOrigin.Init();
  492. m_vecSmoothedVelocity.Init();
  493. #endif
  494. m_vecAutoAim.Init( 0.0f, 0.0f, 0.0f );
  495. if ( s_PlayerEdict )
  496. {
  497. // take the assigned edict_t and attach it
  498. Assert( s_PlayerEdict != NULL );
  499. NetworkProp()->AttachEdict( s_PlayerEdict );
  500. s_PlayerEdict = NULL;
  501. }
  502. m_flFlashTime = -1;
  503. pl.fixangle = FIXANGLE_ABSOLUTE;
  504. pl.hltv = false;
  505. #if defined( REPLAY_ENABLED )
  506. pl.replay = false;
  507. #endif
  508. pl.frags = 0;
  509. pl.assists = 0;
  510. pl.deaths = 0;
  511. pl.score = 0;
  512. m_szNetname[0] = '\0';
  513. m_iHealth = 0;
  514. Weapon_SetLast( NULL );
  515. m_bitsDamageType = 0;
  516. m_bForceOrigin = false;
  517. m_hVehicle = NULL;
  518. m_pCurrentCommand = NULL;
  519. m_iLockViewanglesTickNumber = 0;
  520. m_qangLockViewangles.Init();
  521. // Setup our default FOV
  522. m_iDefaultFOV = g_pGameRules->DefaultFOV();
  523. m_hZoomOwner = NULL;
  524. m_nUpdateRate = 64; // cl_updaterate default
  525. m_fLerpTime = 0.1f; // cl_interp default
  526. m_bPredictWeapons = true;
  527. m_bLagCompensation = false;
  528. m_flLaggedMovementValue = 1.0f;
  529. m_StuckLast = 0;
  530. m_impactEnergyScale = 1.0f;
  531. m_fLastPlayerTalkTime = 0.0f;
  532. m_PlayerInfo.SetParent( this );
  533. ResetObserverMode();
  534. m_bActiveCameraMan = false;
  535. m_bCameraManXRay = false;
  536. m_bCameraManOverview = false;
  537. m_bCameraManScoreBoard = false;
  538. m_uCameraManGraphs = 0;
  539. m_surfaceProps = 0;
  540. m_pSurfaceData = NULL;
  541. m_surfaceFriction = 1.0f;
  542. m_chTextureType = 0;
  543. m_chPreviousTextureType = 0;
  544. m_iSuicideCustomKillFlags = 0;
  545. m_fDelay = 0.0f;
  546. m_fReplayEnd = -1;
  547. m_iReplayEntity = 0;
  548. m_autoKickDisabled = false;
  549. m_nNumCrouches = 0;
  550. m_bDuckToggled = false;
  551. m_bPhysicsWasFrozen = false;
  552. m_bDropEnabled = true;
  553. m_bDuckEnabled = true;
  554. m_movementCollisionNormal = Vector( 0, 0, 1 );
  555. // Used to mask off buttons
  556. m_afButtonDisabled = 0;
  557. m_afButtonForced = 0;
  558. m_nBodyPitchPoseParam = -1;
  559. m_flForwardMove = 0;
  560. m_flSideMove = 0;
  561. m_bSplitScreenPlayer = false;
  562. m_hSplitOwner = NULL;
  563. m_ClientPlatform = CROSSPLAYPLATFORM_THISPLATFORM;
  564. m_hPostProcessCtrl.Set( NULL );
  565. m_hColorCorrectionCtrl.Set( NULL );
  566. m_vecConstraintCenter = vec3_origin;
  567. m_flTimeLastTouchedGround = 0.0f;
  568. m_ignoreLadderJumpTime = 0.0f;
  569. m_PlayerInputDevice = INPUT_DEVICE_NONE;
  570. m_PlayerPlatform = INPUT_DEVICE_PLATFORM_NONE;
  571. m_lastRequestedClientInfoTime = 0.0f;
  572. // Init eye and angle offsets - used for TrackIR and motion controllers
  573. m_vecEyeOffset.Init();
  574. m_EyeAngleOffset.Init();
  575. m_AimDirection.Init();
  576. m_flMovementTimeForUserCmdProcessingRemaining = 0.0f;
  577. m_flInitialSpawnTime = 0.0f;
  578. m_iCoachingTeam = 0;
  579. m_flDuckAmount = 0.0f;
  580. m_flDuckSpeed = CS_PLAYER_DUCK_SPEED_IDEAL;
  581. m_vecLastPositionAtFullCrouchSpeed = vec2_origin;
  582. m_flNextDecalTime = 0.0f; // initialize to let this player spray
  583. m_bNextDecalTimeExpedited = false;
  584. m_bHasWalkMovedSinceLastJump = false;
  585. }
  586. CBasePlayer::~CBasePlayer( )
  587. {
  588. VPhysicsDestroyObject();
  589. }
  590. //-----------------------------------------------------------------------------
  591. // Purpose:
  592. // Input :
  593. // Output :
  594. //-----------------------------------------------------------------------------
  595. void CBasePlayer::UpdateOnRemove( void )
  596. {
  597. if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM )
  598. {
  599. g_pScriptVM->SetValue( "player", SCRIPT_VARIANT_NULL );
  600. }
  601. VPhysicsDestroyObject();
  602. // Remove him from his current team
  603. if ( GetTeam() )
  604. {
  605. GetTeam()->RemovePlayer( this );
  606. }
  607. if ( m_hSplitOwner )
  608. {
  609. m_hSplitOwner->RemoveSplitScreenPlayer( this );
  610. }
  611. // Chain at end to mimic destructor unwind order
  612. BaseClass::UpdateOnRemove();
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Purpose:
  616. // Input : **pvs -
  617. // **pas -
  618. //-----------------------------------------------------------------------------
  619. ConVar VisForce( "vis_force", "0", FCVAR_CHEAT );
  620. void CBasePlayer::SetupVisibility( CBaseEntity *pViewEntity, unsigned char *pvs, int pvssize )
  621. {
  622. Vector org;
  623. // If we have a view entity, we don't add the player's origin.
  624. if ( !pViewEntity || VisForce.GetBool() )
  625. {
  626. org = EyePosition();
  627. engine->AddOriginToPVS( org );
  628. }
  629. // Merge in PVS from split screen players
  630. CUtlVector< CHandle<CBasePlayer> > &splitPlayers = GetSplitScreenAndPictureInPicturePlayers();
  631. for ( int i = 0; i < splitPlayers.Count(); i++ )
  632. {
  633. CBasePlayer *pl = splitPlayers[i];
  634. if ( !pl )
  635. {
  636. continue;
  637. }
  638. org = pl->EyePosition();
  639. engine->AddOriginToPVS( org );
  640. }
  641. }
  642. int CBasePlayer::UpdateTransmitState()
  643. {
  644. // always call ShouldTransmit() for players
  645. return SetTransmitState( FL_EDICT_FULLCHECK );
  646. }
  647. int CBasePlayer::ShouldTransmit( const CCheckTransmitInfo *pInfo )
  648. {
  649. if ( sv_force_transmit_players.GetBool() )
  650. return FL_EDICT_ALWAYS;
  651. // Allow me to introduce myself to, err, myself.
  652. // I.e., always update the recipient player data even if it's nodraw (first person mode)
  653. if ( pInfo->m_pClientEnt == edict() ||
  654. IsSplitScreenUserOnEdict( pInfo->m_pClientEnt ) ) // If we're using the other guys network connection in split screen, then also force txmit
  655. {
  656. return FL_EDICT_ALWAYS;
  657. }
  658. // when HLTV/Replay is connected and spectators press +USE, they
  659. // signal that they are recording a interesting scene
  660. // so transmit these 'cameramans' to the HLTV or Replay client
  661. #if defined( REPLAY_ENABLED )
  662. if ( HLTVDirector()->GetCameraMan() == entindex() ||
  663. ReplayDirector()->GetCameraMan() == entindex() )
  664. #else
  665. if ( HLTVDirector()->GetCameraMan() == entindex() )
  666. #endif
  667. {
  668. CBaseEntity *pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
  669. Assert( pRecipientEntity->IsPlayer() );
  670. CBasePlayer *pRecipientPlayer = static_cast<CBasePlayer*>( pRecipientEntity );
  671. #if defined( REPLAY_ENABLED )
  672. if ( pRecipientPlayer->IsHLTV() ||
  673. pRecipientPlayer->IsReplay() )
  674. #else
  675. if ( pRecipientPlayer->IsHLTV() )
  676. #endif
  677. {
  678. // HACK force calling RecomputePVSInformation to update PVS data
  679. NetworkProp()->AreaNum();
  680. return FL_EDICT_ALWAYS;
  681. }
  682. }
  683. // In case player is dead: we transmit so ragdolls can access reliable player data, after replay, reconnect and full frame update, as well.
  684. if ( m_lifeState == LIFE_DEAD )
  685. return FL_EDICT_ALWAYS;
  686. int iBaseResult = BaseClass::ShouldTransmit( pInfo );
  687. if ( iBaseResult == FL_EDICT_PVSCHECK )
  688. {
  689. if ( IsAlive() && IsEffectActive( EF_NODRAW ) )
  690. {
  691. return FL_EDICT_DONTSEND;
  692. }
  693. }
  694. return iBaseResult;
  695. }
  696. bool CBasePlayer::WantsLagCompensationOnEntity( const CBaseEntity *entity, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits ) const
  697. {
  698. // Team members shouldn't be adjusted unless friendly fire is on.
  699. if ( !mp_friendlyfire.GetInt() && !mp_teammates_are_enemies.GetBool() && entity->GetTeamNumber() == GetTeamNumber() )
  700. return false;
  701. // If this entity hasn't been transmitted to us and acked, then don't bother lag compensating it.
  702. if ( pEntityTransmitBits && !pEntityTransmitBits->Get( entity->entindex() ) )
  703. return false;
  704. const Vector &vMyOrigin = GetAbsOrigin();
  705. const Vector &vHisOrigin = entity->GetAbsOrigin();
  706. // get max distance player could have moved within max lag compensation time,
  707. // multiply by 1.5 to to avoid "dead zones" (sqrt(2) would be the exact value)
  708. float entityMaxSpeed = ToBasePlayer(entity) ? ToBasePlayer(entity)->MaxSpeed() : 300.0f;
  709. float maxDistance = 1.5 * entityMaxSpeed * sv_maxunlag.GetFloat();
  710. // If the player is within this distance, lag compensate them in case they're running past us.
  711. if ( vHisOrigin.DistTo( vMyOrigin ) < maxDistance )
  712. return true;
  713. // If their origin is not within a 45 degree cone in front of us, no need to lag compensate.
  714. Vector vForward;
  715. AngleVectors( pCmd->viewangles, &vForward );
  716. Vector vDiff = vHisOrigin - vMyOrigin;
  717. VectorNormalize( vDiff );
  718. float flCosAngle = 0.707107f; // 45 degree angle
  719. if ( vForward.Dot( vDiff ) < flCosAngle )
  720. return false;
  721. return true;
  722. }
  723. void CBasePlayer::PauseBonusProgress( bool bPause )
  724. {
  725. m_bPauseBonusProgress = bPause;
  726. }
  727. void CBasePlayer::SetBonusProgress( int iBonusProgress )
  728. {
  729. if ( !m_bPauseBonusProgress )
  730. m_iBonusProgress = iBonusProgress;
  731. }
  732. void CBasePlayer::SetBonusChallenge( int iBonusChallenge )
  733. {
  734. m_iBonusChallenge = iBonusChallenge;
  735. }
  736. //-----------------------------------------------------------------------------
  737. // Sets the view angles
  738. //-----------------------------------------------------------------------------
  739. void CBasePlayer::SnapEyeAngles( const QAngle &viewAngles )
  740. {
  741. pl.v_angle = viewAngles;
  742. pl.fixangle = FIXANGLE_ABSOLUTE;
  743. }
  744. //-----------------------------------------------------------------------------
  745. // Purpose:
  746. // Input : iSpeed -
  747. // iMax -
  748. // Output : int
  749. //-----------------------------------------------------------------------------
  750. int TrainSpeed(int iSpeed, int iMax)
  751. {
  752. float fSpeed, fMax;
  753. int iRet = 0;
  754. fMax = (float)iMax;
  755. fSpeed = iSpeed;
  756. fSpeed = fSpeed/fMax;
  757. if (iSpeed < 0)
  758. iRet = TRAIN_BACK;
  759. else if (iSpeed == 0)
  760. iRet = TRAIN_NEUTRAL;
  761. else if (fSpeed < 0.33)
  762. iRet = TRAIN_SLOW;
  763. else if (fSpeed < 0.66)
  764. iRet = TRAIN_MEDIUM;
  765. else
  766. iRet = TRAIN_FAST;
  767. return iRet;
  768. }
  769. void CBasePlayer::DeathSound( const CTakeDamageInfo &info )
  770. {
  771. // temporarily using pain sounds for death sounds
  772. #if !defined ( PORTAL2 )
  773. // Did we die from falling?
  774. if ( m_bitsDamageType & DMG_FALL )
  775. {
  776. // They died in the fall. Play a splat sound.
  777. EmitSound( "Player.FallGib" );
  778. }
  779. else
  780. {
  781. EmitSound( "Player.Death" );
  782. }
  783. #endif
  784. // play one of the suit death alarms
  785. if ( IsSuitEquipped() )
  786. {
  787. UTIL_EmitGroupnameSuit(edict(), "HEV_DEAD");
  788. }
  789. }
  790. void CBasePlayer::SetFogController( CFogController *pFogController )
  791. {
  792. m_PlayerFog.m_hCtrl.Set( pFogController );
  793. }
  794. // override takehealth
  795. // bitsDamageType indicates type of damage healed.
  796. int CBasePlayer::TakeHealth( float flHealth, int bitsDamageType )
  797. {
  798. // clear out any damage types we healed.
  799. // UNDONE: generic health should not heal any
  800. // UNDONE: time-based damage
  801. if (m_takedamage)
  802. {
  803. int bitsDmgTimeBased = g_pGameRules->Damage_GetTimeBased();
  804. m_bitsDamageType &= ~( bitsDamageType & ~bitsDmgTimeBased );
  805. }
  806. // I disabled reporting history into the dbghist because it was super spammy.
  807. // But, if you need to reenable it, the code is below in the "else" clause.
  808. #if 1 // #ifdef DISABLE_DEBUG_HISTORY
  809. return BaseClass::TakeHealth (flHealth, bitsDamageType);
  810. #else
  811. const int healingTaken = BaseClass::TakeHealth(flHealth,bitsDamageType);
  812. char buf[256];
  813. Q_snprintf(buf, 256, "[%f] Player %s healed for %d with damagetype %X\n", gpGlobals->curtime, GetDebugName(), healingTaken, bitsDamageType);
  814. ADD_DEBUG_HISTORY( HISTORY_PLAYER_DAMAGE, buf );
  815. return healingTaken;
  816. #endif
  817. }
  818. //-----------------------------------------------------------------------------
  819. // Purpose: Draw all overlays (should be implemented in cascade by subclass to add
  820. // any additional non-text overlays)
  821. // Input :
  822. // Output : Current text offset from the top
  823. //-----------------------------------------------------------------------------
  824. void CBasePlayer::DrawDebugGeometryOverlays(void)
  825. {
  826. // --------------------------------------------------------
  827. // If in buddha mode and dead draw lines to indicate death
  828. // --------------------------------------------------------
  829. if ((m_debugOverlays & OVERLAY_BUDDHA_MODE) && m_iHealth == 1)
  830. {
  831. Vector vBodyDir = BodyDirection2D( );
  832. Vector eyePos = EyePosition() + vBodyDir*10.0;
  833. Vector vUp = Vector(0,0,8);
  834. Vector vSide;
  835. CrossProduct( vBodyDir, vUp, vSide);
  836. NDebugOverlay::Line(eyePos+vSide+vUp, eyePos-vSide-vUp, 255,0,0, false, 0);
  837. NDebugOverlay::Line(eyePos+vSide-vUp, eyePos-vSide+vUp, 255,0,0, false, 0);
  838. }
  839. BaseClass::DrawDebugGeometryOverlays();
  840. }
  841. //=========================================================
  842. // TraceAttack
  843. //=========================================================
  844. void CBasePlayer::TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr )
  845. {
  846. if ( m_takedamage )
  847. {
  848. CTakeDamageInfo info = inputInfo;
  849. if ( info.GetAttacker() )
  850. {
  851. // --------------------------------------------------
  852. // If an NPC check if friendly fire is disallowed
  853. // --------------------------------------------------
  854. CAI_BaseNPC *pNPC = info.GetAttacker()->MyNPCPointer();
  855. if ( pNPC && (pNPC->CapabilitiesGet() & bits_CAP_NO_HIT_PLAYER) && pNPC->IRelationType( this ) != D_HT )
  856. return;
  857. // Prevent team damage here so blood doesn't appear
  858. if ( info.GetAttacker()->IsPlayer() )
  859. {
  860. if ( !g_pGameRules->FPlayerCanTakeDamage( this, info.GetAttacker() ) )
  861. return;
  862. }
  863. }
  864. SetLastHitGroup( ptr->hitgroup );
  865. switch ( ptr->hitgroup )
  866. {
  867. case HITGROUP_GENERIC:
  868. break;
  869. case HITGROUP_HEAD:
  870. info.ScaleDamage( sk_player_head.GetFloat() );
  871. break;
  872. case HITGROUP_CHEST:
  873. info.ScaleDamage( sk_player_chest.GetFloat() );
  874. break;
  875. case HITGROUP_STOMACH:
  876. info.ScaleDamage( sk_player_stomach.GetFloat() );
  877. break;
  878. case HITGROUP_LEFTARM:
  879. case HITGROUP_RIGHTARM:
  880. info.ScaleDamage( sk_player_arm.GetFloat() );
  881. break;
  882. case HITGROUP_LEFTLEG:
  883. case HITGROUP_RIGHTLEG:
  884. info.ScaleDamage( sk_player_leg.GetFloat() );
  885. break;
  886. default:
  887. break;
  888. }
  889. #ifdef HL2_EPISODIC
  890. // If this damage type makes us bleed, then do so
  891. bool bShouldBleed = !g_pGameRules->Damage_ShouldNotBleed( info.GetDamageType() );
  892. if ( bShouldBleed )
  893. #endif
  894. {
  895. SpawnBlood(ptr->endpos, vecDir, BloodColor(), info.GetDamage());// a little surface blood.
  896. TraceBleed( info.GetDamage(), vecDir, ptr, info.GetDamageType() );
  897. }
  898. AddMultiDamage( info, this );
  899. }
  900. }
  901. //------------------------------------------------------------------------------
  902. // Purpose : Do some kind of damage effect for the type of damage
  903. // Input :
  904. // Output :
  905. //------------------------------------------------------------------------------
  906. void CBasePlayer::DamageEffect(float flDamage, int fDamageType)
  907. {
  908. if (fDamageType & DMG_CRUSH)
  909. {
  910. //Red damage indicator
  911. color32 red = {128,0,0,128};
  912. UTIL_ScreenFade( this, red, 1.0f, 0.1f, FFADE_IN );
  913. }
  914. else if (fDamageType & DMG_DROWN)
  915. {
  916. //Red damage indicator
  917. color32 blue = {0,0,128,128};
  918. UTIL_ScreenFade( this, blue, 1.0f, 0.1f, FFADE_IN );
  919. }
  920. else if (fDamageType & DMG_SLASH)
  921. {
  922. // If slash damage shoot some blood
  923. SpawnBlood(EyePosition(), g_vecAttackDir, BloodColor(), flDamage);
  924. }
  925. else if (fDamageType & DMG_PLASMA)
  926. {
  927. // Blue screen fade
  928. color32 blue = {0,0,255,100};
  929. UTIL_ScreenFade( this, blue, 0.2, 0.4, FFADE_MODULATE );
  930. // Very small screen shake
  931. ViewPunch(QAngle(random->RandomInt(-0.1,0.1), random->RandomInt(-0.1,0.1), random->RandomInt(-0.1,0.1)));
  932. // Burn sound
  933. EmitSound( "Player.PlasmaDamage" );
  934. }
  935. else if (fDamageType & DMG_SONIC)
  936. {
  937. // Sonic damage sound
  938. EmitSound( "Player.SonicDamage" );
  939. }
  940. else if ( fDamageType & DMG_BULLET )
  941. {
  942. # ifdef PORTAL2
  943. if( GameRules()->IsMultiplayer() )
  944. EmitSound( "CoopBot.CoopBotBulletImpact" );
  945. else
  946. # endif
  947. EmitSound( "Flesh.BulletImpact" );
  948. }
  949. }
  950. /*
  951. Take some damage.
  952. NOTE: each call to OnTakeDamage with bitsDamageType set to a time-based damage
  953. type will cause the damage time countdown to be reset. Thus the ongoing effects of poison, radiation
  954. etc are implemented with subsequent calls to OnTakeDamage using DMG_GENERIC.
  955. */
  956. // Old values
  957. #define OLD_ARMOR_RATIO 0.2 // Armor Takes 80% of the damage
  958. #define OLD_ARMOR_BONUS 0.5 // Each Point of Armor is work 1/x points of health
  959. // New values
  960. #define ARMOR_RATIO 0.2
  961. #define ARMOR_BONUS 1.0
  962. //---------------------------------------------------------
  963. //---------------------------------------------------------
  964. bool CBasePlayer::ShouldTakeDamageInCommentaryMode( const CTakeDamageInfo &inputInfo )
  965. {
  966. // Only ignore damage when we're listening to a commentary node
  967. if ( !IsListeningToCommentary() )
  968. return true;
  969. // Allow SetHealth inputs to kill player.
  970. if ( inputInfo.GetInflictor() == this && inputInfo.GetAttacker() == this )
  971. return true;
  972. #ifdef PORTAL
  973. if ( inputInfo.GetDamageType() & DMG_ACID )
  974. return true;
  975. #endif
  976. // In commentary, ignore all damage except for falling and leeches
  977. if ( !(inputInfo.GetDamageType() & (DMG_BURN | DMG_PLASMA | DMG_FALL | DMG_CRUSH)) && inputInfo.GetDamageType() != DMG_GENERIC )
  978. return false;
  979. // We let DMG_CRUSH pass the check above so that we can check here for stress damage. Deny the CRUSH damage if there is no attacker,
  980. // or if the attacker isn't a BSP model. Therefore, we're allowing any CRUSH damage done by a BSP model.
  981. if ( (inputInfo.GetDamageType() & DMG_CRUSH) && ( inputInfo.GetAttacker() == NULL || !inputInfo.GetAttacker()->IsBSPModel() ) )
  982. return false;
  983. return true;
  984. }
  985. int CBasePlayer::OnTakeDamage( const CTakeDamageInfo &inputInfo )
  986. {
  987. // have suit diagnose the problem - ie: report damage type
  988. int bitsDamage = inputInfo.GetDamageType();
  989. int ffound = true;
  990. int fmajor;
  991. int fcritical;
  992. int fTookDamage;
  993. int ftrivial;
  994. float flRatio;
  995. float flBonus;
  996. float flHealthPrev = m_iHealth;
  997. CTakeDamageInfo info = inputInfo;
  998. IServerVehicle *pVehicle = GetVehicle();
  999. if ( pVehicle )
  1000. {
  1001. // Let the vehicle decide if we should take this damage or not
  1002. if ( pVehicle->PassengerShouldReceiveDamage( info ) == false )
  1003. return 0;
  1004. }
  1005. if ( IsInCommentaryMode() )
  1006. {
  1007. if( !ShouldTakeDamageInCommentaryMode( info ) )
  1008. return 0;
  1009. }
  1010. if ( GetFlags() & FL_GODMODE )
  1011. return 0;
  1012. if ( m_debugOverlays & OVERLAY_BUDDHA_MODE )
  1013. {
  1014. if ((m_iHealth - info.GetDamage()) <= 0)
  1015. {
  1016. m_iHealth = 1;
  1017. return 0;
  1018. }
  1019. }
  1020. // Early out if there's no damage
  1021. if ( !info.GetDamage() )
  1022. return 0;
  1023. if( old_armor.GetBool() )
  1024. {
  1025. flBonus = OLD_ARMOR_BONUS;
  1026. flRatio = OLD_ARMOR_RATIO;
  1027. }
  1028. else
  1029. {
  1030. flBonus = ARMOR_BONUS;
  1031. flRatio = ARMOR_RATIO;
  1032. }
  1033. if ( ( info.GetDamageType() & DMG_BLAST ) && g_pGameRules->IsMultiplayer() )
  1034. {
  1035. // blasts damage armor more.
  1036. flBonus *= 2;
  1037. }
  1038. // Already dead
  1039. if ( !IsAlive() )
  1040. return 0;
  1041. // go take the damage first
  1042. if ( !g_pGameRules->FPlayerCanTakeDamage( this, info.GetAttacker() ) )
  1043. {
  1044. // Refuse the damage
  1045. return 0;
  1046. }
  1047. // print to console if the appropriate cvar is set
  1048. #ifdef DISABLE_DEBUG_HISTORY
  1049. if (player_debug_print_damage.GetBool() && info.GetDamage() > 0)
  1050. #endif
  1051. {
  1052. char dmgtype[64];
  1053. CTakeDamageInfo::DebugGetDamageTypeString( info.GetDamageType(), dmgtype, 512 );
  1054. char outputString[256];
  1055. Q_snprintf( outputString, 256, "%f: Player %s at [%0.2f %0.2f %0.2f] took %f damage from %s, type %s\n", gpGlobals->curtime, GetDebugName(),
  1056. GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z, info.GetDamage(), info.GetInflictor()->GetDebugName(), dmgtype );
  1057. //Msg( "%f: Player %s at [%0.2f %0.2f %0.2f] took %f damage from %s, type %s\n", gpGlobals->curtime, GetDebugName(),
  1058. // GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z, info.GetDamage(), info.GetInflictor()->GetDebugName(), dmgtype );
  1059. ADD_DEBUG_HISTORY( HISTORY_PLAYER_DAMAGE, outputString );
  1060. #ifndef DISABLE_DEBUG_HISTORY
  1061. if ( player_debug_print_damage.GetBool() ) // if we're not in here just for the debug history
  1062. #endif
  1063. {
  1064. Msg( "%s", outputString );
  1065. }
  1066. }
  1067. // keep track of amount of damage last sustained
  1068. m_lastDamageAmount = info.GetDamage();
  1069. // Armor.
  1070. if (m_ArmorValue && !(info.GetDamageType() & (DMG_FALL | DMG_DROWN | DMG_POISON | DMG_RADIATION)) )// armor doesn't protect against fall or drown damage!
  1071. {
  1072. float flNew = info.GetDamage() * flRatio;
  1073. float flArmor;
  1074. flArmor = (info.GetDamage() - flNew) * flBonus;
  1075. if( !old_armor.GetBool() )
  1076. {
  1077. if( flArmor < 1.0 )
  1078. {
  1079. flArmor = 1.0;
  1080. }
  1081. }
  1082. // Does this use more armor than we have?
  1083. if (flArmor > m_ArmorValue)
  1084. {
  1085. flArmor = m_ArmorValue;
  1086. flArmor *= (1/flBonus);
  1087. flNew = info.GetDamage() - flArmor;
  1088. m_DmgSave = m_ArmorValue;
  1089. m_ArmorValue = 0;
  1090. }
  1091. else
  1092. {
  1093. m_DmgSave = flArmor;
  1094. m_ArmorValue -= flArmor;
  1095. }
  1096. info.SetDamage( flNew );
  1097. }
  1098. // this cast to INT is critical!!! If a player ends up with 0.5 health, the engine will get that
  1099. // as an int (zero) and think the player is dead! (this will incite a clientside screentilt, etc)
  1100. // NOTENOTE: jdw - We are now capable of retaining the mantissa of this damage value and deferring its application
  1101. // info.SetDamage( (int)info.GetDamage() );
  1102. // Call up to the base class
  1103. fTookDamage = BaseClass::OnTakeDamage( info );
  1104. // Early out if the base class took no damage
  1105. if ( !fTookDamage )
  1106. return 0;
  1107. // add to the damage total for clients, which will be sent as a single
  1108. // message at the end of the frame
  1109. // todo: remove after combining shotgun blasts?
  1110. if ( info.GetInflictor() && info.GetInflictor()->edict() )
  1111. m_DmgOrigin = info.GetInflictor()->GetAbsOrigin();
  1112. m_DmgTake += (int)info.GetDamage();
  1113. // Reset damage time countdown for each type of time based damage player just sustained
  1114. for (int i = 0; i < CDMG_TIMEBASED; i++)
  1115. {
  1116. // Make sure the damage type is really time-based.
  1117. // This is kind of hacky but necessary until we setup DamageType as an enum.
  1118. int iDamage = ( DMG_PARALYZE << i );
  1119. if ( ( info.GetDamageType() & iDamage ) && g_pGameRules->Damage_IsTimeBased( iDamage ) )
  1120. {
  1121. m_rgbTimeBasedDamage[i] = 0;
  1122. }
  1123. }
  1124. // Display any effect associate with this damage type
  1125. DamageEffect(info.GetDamage(),bitsDamage);
  1126. // how bad is it, doc?
  1127. ftrivial = (m_iHealth > 75 || m_lastDamageAmount < 5);
  1128. fmajor = (m_lastDamageAmount > 25);
  1129. fcritical = (m_iHealth < 30);
  1130. // handle all bits set in this damage message,
  1131. // let the suit give player the diagnosis
  1132. // UNDONE: add sounds for types of damage sustained (ie: burn, shock, slash )
  1133. // UNDONE: still need to record damage and heal messages for the following types
  1134. // DMG_BURN
  1135. // DMG_FREEZE
  1136. // DMG_BLAST
  1137. // DMG_SHOCK
  1138. m_bitsDamageType |= bitsDamage; // Save this so we can report it to the client
  1139. m_bitsHUDDamage = -1; // make sure the damage bits get resent
  1140. while (fTookDamage && (!ftrivial || g_pGameRules->Damage_IsTimeBased( bitsDamage ) ) && ffound && bitsDamage)
  1141. {
  1142. ffound = false;
  1143. if (bitsDamage & DMG_CLUB)
  1144. {
  1145. if (fmajor)
  1146. SetSuitUpdate("!HEV_DMG4", false, SUIT_NEXT_IN_30SEC); // minor fracture
  1147. bitsDamage &= ~DMG_CLUB;
  1148. ffound = true;
  1149. }
  1150. if (bitsDamage & (DMG_FALL | DMG_CRUSH))
  1151. {
  1152. if (fmajor)
  1153. SetSuitUpdate("!HEV_DMG5", false, SUIT_NEXT_IN_30SEC); // major fracture
  1154. else
  1155. SetSuitUpdate("!HEV_DMG4", false, SUIT_NEXT_IN_30SEC); // minor fracture
  1156. bitsDamage &= ~(DMG_FALL | DMG_CRUSH);
  1157. ffound = true;
  1158. }
  1159. if (bitsDamage & DMG_BULLET)
  1160. {
  1161. if (m_lastDamageAmount > 5)
  1162. SetSuitUpdate("!HEV_DMG6", false, SUIT_NEXT_IN_30SEC); // blood loss detected
  1163. //else
  1164. // SetSuitUpdate("!HEV_DMG0", false, SUIT_NEXT_IN_30SEC); // minor laceration
  1165. bitsDamage &= ~DMG_BULLET;
  1166. ffound = true;
  1167. }
  1168. if (bitsDamage & DMG_SLASH)
  1169. {
  1170. if (fmajor)
  1171. SetSuitUpdate("!HEV_DMG1", false, SUIT_NEXT_IN_30SEC); // major laceration
  1172. else
  1173. SetSuitUpdate("!HEV_DMG0", false, SUIT_NEXT_IN_30SEC); // minor laceration
  1174. bitsDamage &= ~DMG_SLASH;
  1175. ffound = true;
  1176. }
  1177. if (bitsDamage & DMG_SONIC)
  1178. {
  1179. if (fmajor)
  1180. SetSuitUpdate("!HEV_DMG2", false, SUIT_NEXT_IN_1MIN); // internal bleeding
  1181. bitsDamage &= ~DMG_SONIC;
  1182. ffound = true;
  1183. }
  1184. if (bitsDamage & (DMG_POISON | DMG_PARALYZE))
  1185. {
  1186. if (bitsDamage & DMG_POISON)
  1187. {
  1188. m_nPoisonDmg += info.GetDamage();
  1189. m_tbdPrev = gpGlobals->curtime;
  1190. m_rgbTimeBasedDamage[itbd_PoisonRecover] = 0;
  1191. }
  1192. SetSuitUpdate("!HEV_DMG3", false, SUIT_NEXT_IN_1MIN); // blood toxins detected
  1193. bitsDamage &= ~( DMG_POISON | DMG_PARALYZE );
  1194. ffound = true;
  1195. }
  1196. if (bitsDamage & DMG_ACID)
  1197. {
  1198. SetSuitUpdate("!HEV_DET1", false, SUIT_NEXT_IN_1MIN); // hazardous chemicals detected
  1199. bitsDamage &= ~DMG_ACID;
  1200. ffound = true;
  1201. }
  1202. if (bitsDamage & DMG_NERVEGAS)
  1203. {
  1204. SetSuitUpdate("!HEV_DET0", false, SUIT_NEXT_IN_1MIN); // biohazard detected
  1205. bitsDamage &= ~DMG_NERVEGAS;
  1206. ffound = true;
  1207. }
  1208. if (bitsDamage & DMG_RADIATION)
  1209. {
  1210. SetSuitUpdate("!HEV_DET2", false, SUIT_NEXT_IN_1MIN); // radiation detected
  1211. bitsDamage &= ~DMG_RADIATION;
  1212. ffound = true;
  1213. }
  1214. if (bitsDamage & DMG_SHOCK)
  1215. {
  1216. bitsDamage &= ~DMG_SHOCK;
  1217. ffound = true;
  1218. }
  1219. }
  1220. float flPunch = RandomFloat( -2, -3.5f );
  1221. if( hl2_episodic.GetBool() && info.GetAttacker() && !FInViewCone( info.GetAttacker() ) )
  1222. {
  1223. if( info.GetDamage() > 10.0f )
  1224. flPunch = -10;
  1225. else
  1226. flPunch = RandomFloat( -5, -7 );
  1227. }
  1228. m_Local.m_viewPunchAngle.SetX( flPunch );
  1229. m_Local.m_viewPunchAngle.SetY( RandomFloat( 1, -1 ) );
  1230. if (fTookDamage && !ftrivial && fmajor && flHealthPrev >= 75)
  1231. {
  1232. // first time we take major damage...
  1233. // turn automedic on if not on
  1234. SetSuitUpdate("!HEV_MED1", false, SUIT_NEXT_IN_30MIN); // automedic on
  1235. // give morphine shot if not given recently
  1236. SetSuitUpdate("!HEV_HEAL7", false, SUIT_NEXT_IN_30MIN); // morphine shot
  1237. }
  1238. if (fTookDamage && !ftrivial && fcritical && flHealthPrev < 75)
  1239. {
  1240. // already took major damage, now it's critical...
  1241. if (m_iHealth < 6)
  1242. SetSuitUpdate("!HEV_HLTH3", false, SUIT_NEXT_IN_10MIN); // near death
  1243. else if (m_iHealth < 20)
  1244. SetSuitUpdate("!HEV_HLTH2", false, SUIT_NEXT_IN_10MIN); // health critical
  1245. // give critical health warnings
  1246. if (!random->RandomInt(0,3) && flHealthPrev < 50)
  1247. SetSuitUpdate("!HEV_DMG7", false, SUIT_NEXT_IN_5MIN); //seek medical attention
  1248. }
  1249. // if we're taking time based damage, warn about its continuing effects
  1250. if (fTookDamage && g_pGameRules->Damage_IsTimeBased( info.GetDamageType() ) && flHealthPrev < 75)
  1251. {
  1252. if (flHealthPrev < 50)
  1253. {
  1254. if (!random->RandomInt(0,3))
  1255. SetSuitUpdate("!HEV_DMG7", false, SUIT_NEXT_IN_5MIN); //seek medical attention
  1256. }
  1257. else
  1258. SetSuitUpdate("!HEV_HLTH1", false, SUIT_NEXT_IN_10MIN); // health dropping
  1259. }
  1260. // Do special explosion damage effect
  1261. if ( bitsDamage & DMG_BLAST )
  1262. {
  1263. OnDamagedByExplosion( info );
  1264. }
  1265. if ( GetHealth() < 100 )
  1266. {
  1267. m_fTimeLastHurt = gpGlobals->curtime;
  1268. }
  1269. return fTookDamage;
  1270. }
  1271. //-----------------------------------------------------------------------------
  1272. // Purpose:
  1273. // Input : &info -
  1274. // damageAmount -
  1275. //-----------------------------------------------------------------------------
  1276. #define MIN_SHOCK_AND_CONFUSION_DAMAGE 30.0f
  1277. #define MIN_EAR_RINGING_DISTANCE 240.0f // 20 feet
  1278. //-----------------------------------------------------------------------------
  1279. // Purpose:
  1280. // Input : &info -
  1281. //-----------------------------------------------------------------------------
  1282. void CBasePlayer::OnDamagedByExplosion( const CTakeDamageInfo &info )
  1283. {
  1284. #ifndef PORTAL2
  1285. float lastDamage = info.GetDamage();
  1286. float distanceFromPlayer = 9999.0f;
  1287. CBaseEntity *inflictor = info.GetInflictor();
  1288. if ( inflictor )
  1289. {
  1290. Vector delta = GetAbsOrigin() - inflictor->GetAbsOrigin();
  1291. distanceFromPlayer = delta.Length();
  1292. }
  1293. bool ear_ringing = distanceFromPlayer < MIN_EAR_RINGING_DISTANCE ? true : false;
  1294. bool shock = lastDamage >= MIN_SHOCK_AND_CONFUSION_DAMAGE;
  1295. if ( !shock && !ear_ringing )
  1296. return;
  1297. int effect = shock ?
  1298. random->RandomInt( 35, 37 ) :
  1299. random->RandomInt( 32, 34 );
  1300. CSingleUserRecipientFilter user( this );
  1301. enginesound->SetPlayerDSP( user, effect, false );
  1302. #endif
  1303. }
  1304. //=========================================================
  1305. // PackDeadPlayerItems - call this when a player dies to
  1306. // pack up the appropriate weapons and ammo items, and to
  1307. // destroy anything that shouldn't be packed.
  1308. //
  1309. // This is pretty brute force :(
  1310. //=========================================================
  1311. void CBasePlayer::PackDeadPlayerItems( void )
  1312. {
  1313. int iWeaponRules;
  1314. int iAmmoRules;
  1315. int i;
  1316. CBaseCombatWeapon *rgpPackWeapons[ 20 ];// 20 hardcoded for now. How to determine exactly how many weapons we have?
  1317. int iPackAmmo[ MAX_AMMO_SLOTS + 1];
  1318. int iPW = 0;// index into packweapons array
  1319. int iPA = 0;// index into packammo array
  1320. memset(rgpPackWeapons, NULL, sizeof(rgpPackWeapons) );
  1321. memset(iPackAmmo, -1, sizeof(iPackAmmo) );
  1322. // get the game rules
  1323. iWeaponRules = g_pGameRules->DeadPlayerWeapons( this );
  1324. iAmmoRules = g_pGameRules->DeadPlayerAmmo( this );
  1325. if ( iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO )
  1326. {
  1327. // nothing to pack. Remove the weapons and return. Don't call create on the box!
  1328. RemoveAllItems( true );
  1329. return;
  1330. }
  1331. // go through all of the weapons and make a list of the ones to pack
  1332. for ( i = 0 ; i < WeaponCount() ; i++ )
  1333. {
  1334. // there's a weapon here. Should I pack it?
  1335. CBaseCombatWeapon *pPlayerItem = GetWeapon( i );
  1336. if ( pPlayerItem )
  1337. {
  1338. switch( iWeaponRules )
  1339. {
  1340. case GR_PLR_DROP_GUN_ACTIVE:
  1341. if ( GetActiveWeapon() && pPlayerItem == GetActiveWeapon() )
  1342. {
  1343. // this is the active item. Pack it.
  1344. rgpPackWeapons[ iPW++ ] = pPlayerItem;
  1345. }
  1346. break;
  1347. case GR_PLR_DROP_GUN_ALL:
  1348. rgpPackWeapons[ iPW++ ] = pPlayerItem;
  1349. break;
  1350. default:
  1351. break;
  1352. }
  1353. }
  1354. }
  1355. // now go through ammo and make a list of which types to pack.
  1356. if ( iAmmoRules != GR_PLR_DROP_AMMO_NO )
  1357. {
  1358. for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ )
  1359. {
  1360. if ( GetAmmoCount( i ) > 0 )
  1361. {
  1362. // player has some ammo of this type.
  1363. switch ( iAmmoRules )
  1364. {
  1365. case GR_PLR_DROP_AMMO_ALL:
  1366. iPackAmmo[ iPA++ ] = i;
  1367. break;
  1368. case GR_PLR_DROP_AMMO_ACTIVE:
  1369. // WEAPONTODO: Make this work
  1370. /*
  1371. if ( GetActiveWeapon() && i == GetActiveWeapon()->m_iPrimaryAmmoType )
  1372. {
  1373. // this is the primary ammo type for the active weapon
  1374. iPackAmmo[ iPA++ ] = i;
  1375. }
  1376. else if ( GetActiveWeapon() && i == GetActiveWeapon()->m_iSecondaryAmmoType )
  1377. {
  1378. // this is the secondary ammo type for the active weapon
  1379. iPackAmmo[ iPA++ ] = i;
  1380. }
  1381. */
  1382. break;
  1383. default:
  1384. break;
  1385. }
  1386. }
  1387. }
  1388. }
  1389. RemoveAllItems( true );// now strip off everything that wasn't handled by the code above.
  1390. }
  1391. void CBasePlayer::RemoveAllItems( bool removeSuit )
  1392. {
  1393. if (GetActiveWeapon())
  1394. {
  1395. ResetAutoaim( );
  1396. GetActiveWeapon()->Holster( );
  1397. }
  1398. Weapon_SetLast( NULL );
  1399. RemoveAllWeapons();
  1400. RemoveAllAmmo();
  1401. if ( removeSuit )
  1402. {
  1403. RemoveSuit();
  1404. }
  1405. UpdateClientData();
  1406. }
  1407. bool CBasePlayer::IsDead() const
  1408. {
  1409. return m_lifeState == LIFE_DEAD;
  1410. }
  1411. static float DamageForce( const Vector &size, float damage )
  1412. {
  1413. float force = damage * ((32 * 32 * 72.0) / (size.x * size.y * size.z)) * 5;
  1414. if ( force > 1000.0)
  1415. {
  1416. force = 1000.0;
  1417. }
  1418. return force;
  1419. }
  1420. const impactdamagetable_t &CBasePlayer::GetPhysicsImpactDamageTable()
  1421. {
  1422. return gDefaultPlayerImpactDamageTable;
  1423. }
  1424. static int g_PlayerHurtEvent = 0;
  1425. int CBasePlayer::OnTakeDamage_Alive( const CTakeDamageInfo &info )
  1426. {
  1427. // set damage type sustained
  1428. m_bitsDamageType |= info.GetDamageType();
  1429. if ( !BaseClass::OnTakeDamage_Alive( info ) )
  1430. return 0;
  1431. CBaseEntity * attacker = info.GetAttacker();
  1432. if ( !attacker )
  1433. return 0;
  1434. Vector vecDir = vec3_origin;
  1435. if ( info.GetInflictor() )
  1436. {
  1437. vecDir = info.GetInflictor()->WorldSpaceCenter() - Vector ( 0, 0, 10 ) - WorldSpaceCenter();
  1438. VectorNormalize( vecDir );
  1439. }
  1440. if ( info.GetInflictor() && (GetMoveType() == MOVETYPE_WALK) &&
  1441. ( !attacker->IsSolidFlagSet(FSOLID_TRIGGER)) )
  1442. {
  1443. Vector force = vecDir * -DamageForce( WorldAlignSize(), info.GetBaseDamage() );
  1444. if ( force.z > 250.0f )
  1445. {
  1446. force.z = 250.0f;
  1447. }
  1448. ApplyAbsVelocityImpulse( force );
  1449. }
  1450. // fire global game event
  1451. IGameEvent * event = gameeventmanager->CreateEvent( "player_hurt", false, &g_PlayerHurtEvent );
  1452. if ( event )
  1453. {
  1454. event->SetInt("userid", GetUserID() );
  1455. event->SetInt("health", Max(0, m_iHealth.Get()) );
  1456. event->SetInt( "priority", 5 ); // player_hurt
  1457. if ( attacker->IsPlayer() )
  1458. {
  1459. CBasePlayer *player = ToBasePlayer( attacker );
  1460. event->SetInt("attacker", player->GetUserID() ); // hurt by other player
  1461. }
  1462. else
  1463. {
  1464. event->SetInt("attacker", 0 ); // hurt by "world"
  1465. }
  1466. gameeventmanager->FireEvent( event );
  1467. }
  1468. // Insert a combat sound so that nearby NPCs hear battle
  1469. if ( attacker->IsNPC() )
  1470. {
  1471. CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 512, 0.5, this );//<<TODO>>//magic number
  1472. }
  1473. return 1;
  1474. }
  1475. void CBasePlayer::Event_Killed( const CTakeDamageInfo &info )
  1476. {
  1477. CSound *pSound;
  1478. if ( Hints() )
  1479. {
  1480. Hints()->ResetHintTimers();
  1481. }
  1482. g_pGameRules->PlayerKilled( this, info );
  1483. #if !defined( _GAMECONSOLE ) || defined ( CSTRIKE15 )
  1484. gamestats->Event_PlayerKilled( this, info );
  1485. #endif
  1486. RumbleEffect( RUMBLE_STOP_ALL, 0, RUMBLE_FLAGS_NONE );
  1487. ForceDropOfCarriedPhysObjects();
  1488. // this client isn't going to be thinking for a while, so reset the sound until they respawn
  1489. pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( edict() ) );
  1490. {
  1491. if ( pSound )
  1492. {
  1493. pSound->Reset();
  1494. }
  1495. }
  1496. // don't let the status bar glitch for players with <0 health.
  1497. if (m_iHealth < -99)
  1498. {
  1499. m_iHealth = 0;
  1500. }
  1501. // holster the current weapon
  1502. if ( GetActiveWeapon() )
  1503. {
  1504. GetActiveWeapon()->Holster();
  1505. }
  1506. SetAnimation( PLAYER_DIE );
  1507. SetViewOffset( VEC_DEAD_VIEWHEIGHT );
  1508. m_lifeState = LIFE_DYING;
  1509. pl.deadflag = true;
  1510. AddSolidFlags( FSOLID_NOT_SOLID );
  1511. // force contact points to get flushed if no longer valid
  1512. // UNDONE: Always do this on RecheckCollisionFilter() ?
  1513. IPhysicsObject *pObject = VPhysicsGetObject();
  1514. if ( pObject )
  1515. {
  1516. pObject->RecheckContactPoints();
  1517. }
  1518. SetMoveType( MOVETYPE_FLYGRAVITY );
  1519. SetGroundEntity( NULL );
  1520. // clear out the suit message cache so we don't keep chattering
  1521. SetSuitUpdate(NULL, false, 0);
  1522. // reset FOV
  1523. SetFOV( this, 0 );
  1524. if ( FlashlightIsOn() )
  1525. {
  1526. FlashlightTurnOff();
  1527. }
  1528. m_flDeathTime = gpGlobals->curtime;
  1529. // only count alive players
  1530. ClearLastKnownArea();
  1531. BaseClass::Event_Killed( info );
  1532. }
  1533. void CBasePlayer::Event_Dying()
  1534. {
  1535. // NOT GIBBED, RUN THIS CODE
  1536. CTakeDamageInfo info;
  1537. DeathSound( info );
  1538. // The dead body rolls out of the vehicle.
  1539. if ( IsInAVehicle() )
  1540. {
  1541. LeaveVehicle();
  1542. }
  1543. QAngle angles = GetLocalAngles();
  1544. angles.x = 0;
  1545. angles.z = 0;
  1546. SetLocalAngles( angles );
  1547. SetThink(&CBasePlayer::PlayerDeathThink);
  1548. SetNextThink( gpGlobals->curtime + 0.1f );
  1549. BaseClass::Event_Dying();
  1550. }
  1551. // Set the activity based on an event or current state
  1552. void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
  1553. {
  1554. int animDesired;
  1555. char szAnim[64];
  1556. float speed;
  1557. speed = GetAbsVelocity().Length2D();
  1558. if (GetFlags() & (FL_FROZEN|FL_ATCONTROLS))
  1559. {
  1560. speed = 0;
  1561. playerAnim = PLAYER_IDLE;
  1562. }
  1563. Activity idealActivity = ACT_WALK;// TEMP!!!!!
  1564. // This could stand to be redone. Why is playerAnim abstracted from activity? (sjb)
  1565. if (playerAnim == PLAYER_JUMP)
  1566. {
  1567. idealActivity = ACT_HOP;
  1568. }
  1569. else if (playerAnim == PLAYER_SUPERJUMP)
  1570. {
  1571. idealActivity = ACT_LEAP;
  1572. }
  1573. else if (playerAnim == PLAYER_DIE)
  1574. {
  1575. if ( m_lifeState == LIFE_ALIVE )
  1576. {
  1577. idealActivity = GetDeathActivity();
  1578. }
  1579. }
  1580. else if (playerAnim == PLAYER_ATTACK1)
  1581. {
  1582. if ( m_Activity == ACT_HOVER ||
  1583. m_Activity == ACT_SWIM ||
  1584. m_Activity == ACT_HOP ||
  1585. m_Activity == ACT_LEAP ||
  1586. m_Activity == ACT_DIESIMPLE )
  1587. {
  1588. idealActivity = m_Activity;
  1589. }
  1590. else
  1591. {
  1592. idealActivity = ACT_RANGE_ATTACK1;
  1593. }
  1594. }
  1595. else if (playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK)
  1596. {
  1597. if ( !( GetFlags() & FL_ONGROUND ) && (m_Activity == ACT_HOP || m_Activity == ACT_LEAP) ) // Still jumping
  1598. {
  1599. idealActivity = m_Activity;
  1600. }
  1601. else if ( GetWaterLevel() > WL_Feet )
  1602. {
  1603. if ( speed == 0 )
  1604. idealActivity = ACT_HOVER;
  1605. else
  1606. idealActivity = ACT_SWIM;
  1607. }
  1608. else
  1609. {
  1610. idealActivity = ACT_WALK;
  1611. }
  1612. }
  1613. if (idealActivity == ACT_RANGE_ATTACK1)
  1614. {
  1615. if ( GetFlags() & FL_DUCKING ) // crouching
  1616. {
  1617. Q_strncpy( szAnim, "crouch_shoot_" ,sizeof(szAnim));
  1618. }
  1619. else
  1620. {
  1621. Q_strncpy( szAnim, "ref_shoot_" ,sizeof(szAnim));
  1622. }
  1623. Q_strncat( szAnim, m_szAnimExtension ,sizeof(szAnim), COPY_ALL_CHARACTERS );
  1624. animDesired = LookupSequence( szAnim );
  1625. if (animDesired == -1)
  1626. animDesired = 0;
  1627. if ( GetSequence() != animDesired || !SequenceLoops() )
  1628. {
  1629. SetCycle( 0 );
  1630. }
  1631. // Tracker 24588: In single player when firing own weapon this causes eye and punchangle to jitter
  1632. //if (!SequenceLoops())
  1633. //{
  1634. // AddEffects( EF_NOINTERP );
  1635. //}
  1636. SetActivity( idealActivity );
  1637. ResetSequence( animDesired );
  1638. }
  1639. else if (idealActivity == ACT_WALK)
  1640. {
  1641. if (GetActivity() != ACT_RANGE_ATTACK1 || IsActivityFinished())
  1642. {
  1643. if ( GetFlags() & FL_DUCKING ) // crouching
  1644. {
  1645. Q_strncpy( szAnim, "crouch_aim_" ,sizeof(szAnim));
  1646. }
  1647. else
  1648. {
  1649. Q_strncpy( szAnim, "ref_aim_" ,sizeof(szAnim));
  1650. }
  1651. Q_strncat( szAnim, m_szAnimExtension,sizeof(szAnim), COPY_ALL_CHARACTERS );
  1652. animDesired = LookupSequence( szAnim );
  1653. if (animDesired == -1)
  1654. animDesired = 0;
  1655. SetActivity( ACT_WALK );
  1656. }
  1657. else
  1658. {
  1659. animDesired = GetSequence();
  1660. }
  1661. }
  1662. else
  1663. {
  1664. if ( GetActivity() == idealActivity)
  1665. return;
  1666. SetActivity( idealActivity );
  1667. animDesired = SelectWeightedSequence( m_Activity );
  1668. // Already using the desired animation?
  1669. if (GetSequence() == animDesired)
  1670. return;
  1671. ResetSequence( animDesired );
  1672. SetCycle( 0 );
  1673. return;
  1674. }
  1675. // Already using the desired animation?
  1676. if (GetSequence() == animDesired)
  1677. return;
  1678. //Msg( "Set animation to %d\n", animDesired );
  1679. // Reset to first frame of desired animation
  1680. ResetSequence( animDesired );
  1681. SetCycle( 0 );
  1682. }
  1683. /*
  1684. ===========
  1685. WaterMove
  1686. ============
  1687. */
  1688. #ifdef HL2_DLL
  1689. // test for HL2 drowning damage increase (aux power used instead)
  1690. #define AIRTIME 7 // lung full of air lasts this many seconds
  1691. #define DROWNING_DAMAGE_INITIAL 10
  1692. #define DROWNING_DAMAGE_MAX 10
  1693. #else
  1694. #define AIRTIME 12 // lung full of air lasts this many seconds
  1695. #define DROWNING_DAMAGE_INITIAL 2
  1696. #define DROWNING_DAMAGE_MAX 5
  1697. #endif
  1698. void CBasePlayer::WaterMove()
  1699. {
  1700. if ( ( GetMoveType() == MOVETYPE_NOCLIP ) && !GetMoveParent() )
  1701. {
  1702. m_AirFinished = gpGlobals->curtime + AIRTIME;
  1703. return;
  1704. }
  1705. if ( m_iHealth < 0 || !IsAlive() )
  1706. {
  1707. UpdateUnderwaterState();
  1708. return;
  1709. }
  1710. // waterlevel 0 - not in water (WL_NotInWater)
  1711. // waterlevel 1 - feet in water (WL_Feet)
  1712. // waterlevel 2 - waist in water (WL_Waist)
  1713. // waterlevel 3 - head in water (WL_Eyes)
  1714. if (GetWaterLevel() != WL_Eyes || CanBreatheUnderwater())
  1715. {
  1716. // not underwater
  1717. // play 'up for air' sound
  1718. if (m_AirFinished < gpGlobals->curtime)
  1719. {
  1720. EmitSound( "Player.DrownStart" );
  1721. }
  1722. m_AirFinished = gpGlobals->curtime + AIRTIME;
  1723. m_nDrownDmgRate = DROWNING_DAMAGE_INITIAL;
  1724. // if we took drowning damage, give it back slowly
  1725. if (m_idrowndmg > m_idrownrestored)
  1726. {
  1727. // set drowning damage bit. hack - dmg_drownrecover actually
  1728. // makes the time based damage code 'give back' health over time.
  1729. // make sure counter is cleared so we start count correctly.
  1730. // NOTE: this actually causes the count to continue restarting
  1731. // until all drowning damage is healed.
  1732. m_bitsDamageType |= DMG_DROWNRECOVER;
  1733. m_bitsDamageType &= ~DMG_DROWN;
  1734. m_rgbTimeBasedDamage[itbd_DrownRecover] = 0;
  1735. }
  1736. }
  1737. else
  1738. { // fully under water
  1739. // stop restoring damage while underwater
  1740. m_bitsDamageType &= ~DMG_DROWNRECOVER;
  1741. m_rgbTimeBasedDamage[itbd_DrownRecover] = 0;
  1742. if (m_AirFinished < gpGlobals->curtime && !(GetFlags() & FL_GODMODE) ) // drown!
  1743. {
  1744. if (m_PainFinished < gpGlobals->curtime)
  1745. {
  1746. // take drowning damage
  1747. m_nDrownDmgRate += 1;
  1748. if (m_nDrownDmgRate > DROWNING_DAMAGE_MAX)
  1749. {
  1750. m_nDrownDmgRate = DROWNING_DAMAGE_MAX;
  1751. }
  1752. OnTakeDamage( CTakeDamageInfo( GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), m_nDrownDmgRate, DMG_DROWN ) );
  1753. m_PainFinished = gpGlobals->curtime + 1;
  1754. // track drowning damage, give it back when
  1755. // player finally takes a breath
  1756. if( CanRecoverCurrentDrowningDamage() )// if we are allowed to recover this damage
  1757. m_idrowndmg += m_nDrownDmgRate;
  1758. }
  1759. }
  1760. else
  1761. {
  1762. m_bitsDamageType &= ~DMG_DROWN;
  1763. }
  1764. }
  1765. UpdateUnderwaterState();
  1766. }
  1767. // true if the player is attached to a ladder
  1768. bool CBasePlayer::IsOnLadder( void )
  1769. {
  1770. return (GetMoveType() == MOVETYPE_LADDER);
  1771. }
  1772. float CBasePlayer::GetWaterJumpTime() const
  1773. {
  1774. return m_flWaterJumpTime;
  1775. }
  1776. void CBasePlayer::SetWaterJumpTime( float flWaterJumpTime )
  1777. {
  1778. m_flWaterJumpTime = flWaterJumpTime;
  1779. }
  1780. float CBasePlayer::GetSwimSoundTime( void ) const
  1781. {
  1782. return m_flSwimSoundTime;
  1783. }
  1784. void CBasePlayer::SetSwimSoundTime( float flSwimSoundTime )
  1785. {
  1786. m_flSwimSoundTime = flSwimSoundTime;
  1787. }
  1788. void CBasePlayer::ShowViewPortPanel( const char * name, bool bShow, KeyValues *data )
  1789. {
  1790. CSingleUserRecipientFilter filter( this );
  1791. filter.MakeReliable();
  1792. int count = 0;
  1793. KeyValues *subkey = NULL;
  1794. if ( data )
  1795. {
  1796. subkey = data->GetFirstSubKey();
  1797. while ( subkey )
  1798. {
  1799. count++; subkey = subkey->GetNextKey();
  1800. }
  1801. subkey = data->GetFirstSubKey(); // reset
  1802. }
  1803. CCSUsrMsg_VGUIMenu msg;
  1804. msg.set_name( name );
  1805. msg.set_show( bShow );
  1806. // write additional data (be careful not more than 192 bytes!)
  1807. while ( subkey )
  1808. {
  1809. CCSUsrMsg_VGUIMenu::Subkey *pMsgSubkey = msg.add_subkeys();
  1810. pMsgSubkey->set_name( subkey->GetName() );
  1811. pMsgSubkey->set_str( subkey-> GetString() );
  1812. subkey = subkey->GetNextKey();
  1813. }
  1814. // int x = 1;
  1815. // if ( bShow )
  1816. // x++;
  1817. SendUserMessage( filter, CS_UM_VGUIMenu, msg );
  1818. }
  1819. void CBasePlayer::PlayerDeathThink(void)
  1820. {
  1821. float flForward;
  1822. SetNextThink( gpGlobals->curtime + 0.1f );
  1823. if (GetFlags() & FL_ONGROUND)
  1824. {
  1825. flForward = GetAbsVelocity().Length() - 20;
  1826. if (flForward <= 0)
  1827. {
  1828. SetAbsVelocity( vec3_origin );
  1829. }
  1830. else
  1831. {
  1832. Vector vecNewVelocity = GetAbsVelocity();
  1833. VectorNormalize( vecNewVelocity );
  1834. vecNewVelocity *= flForward;
  1835. SetAbsVelocity( vecNewVelocity );
  1836. }
  1837. }
  1838. if ( HasWeapons() )
  1839. {
  1840. // we drop the guns here because weapons that have an area effect and can kill their user
  1841. // will sometimes crash coming back from CBasePlayer::Killed() if they kill their owner because the
  1842. // player class sometimes is freed. It's safer to manipulate the weapons once we know
  1843. // we aren't calling into any of their code anymore through the player pointer.
  1844. PackDeadPlayerItems();
  1845. }
  1846. if (GetModelIndex() && (!IsSequenceFinished()) && (m_lifeState == LIFE_DYING))
  1847. {
  1848. StudioFrameAdvance( );
  1849. m_iRespawnFrames++;
  1850. if ( m_iRespawnFrames < 60 ) // animations should be no longer than this
  1851. return;
  1852. }
  1853. if (m_lifeState == LIFE_DYING)
  1854. {
  1855. m_lifeState = LIFE_DEAD;
  1856. m_flDeathAnimTime = gpGlobals->curtime;
  1857. }
  1858. StopAnimation();
  1859. AddEffects( EF_NOINTERP );
  1860. m_flPlaybackRate = 0.0;
  1861. int fAnyButtonDown = (m_nButtons & ~IN_SCORE);
  1862. // Strip out the duck key from this check if it's toggled
  1863. if ( (fAnyButtonDown & IN_DUCK) && GetToggledDuckState())
  1864. {
  1865. fAnyButtonDown &= ~IN_DUCK;
  1866. }
  1867. // wait for all buttons released
  1868. if (m_lifeState == LIFE_DEAD)
  1869. {
  1870. if (fAnyButtonDown)
  1871. return;
  1872. if ( g_pGameRules->FPlayerCanRespawn( this ) )
  1873. {
  1874. m_lifeState = LIFE_RESPAWNABLE;
  1875. }
  1876. return;
  1877. }
  1878. // if the player has been dead for one second longer than allowed by forcerespawn,
  1879. // forcerespawn isn't on. Send the player off to an intermission camera until they
  1880. // choose to respawn.
  1881. if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->curtime > (m_flDeathTime + DEATH_ANIMATION_TIME) ) && !IsObserver() )
  1882. {
  1883. // go to dead camera.
  1884. StartObserverMode( m_iObserverLastMode );
  1885. }
  1886. // wait for any button down, or mp_forcerespawn is set and the respawn time is up
  1887. if (!fAnyButtonDown
  1888. && !( g_pGameRules->IsMultiplayer() && forcerespawn.GetInt() > 0 && (gpGlobals->curtime > (m_flDeathTime + 5))) )
  1889. return;
  1890. m_nButtons = 0;
  1891. m_iRespawnFrames = 0;
  1892. //Msg( "Respawn\n");
  1893. respawn( this, !IsObserver() );// don't copy a corpse if we're in deathcam.
  1894. SetNextThink( TICK_NEVER_THINK );
  1895. }
  1896. void CBasePlayer::PlayerForceTeamThink(void)
  1897. {
  1898. }
  1899. /*
  1900. //=========================================================
  1901. // StartDeathCam - find an intermission spot and send the
  1902. // player off into observer mode
  1903. //=========================================================
  1904. void CBasePlayer::StartDeathCam( void )
  1905. {
  1906. CBaseEntity *pSpot, *pNewSpot;
  1907. int iRand;
  1908. if ( GetViewOffset() == vec3_origin )
  1909. {
  1910. // don't accept subsequent attempts to StartDeathCam()
  1911. return;
  1912. }
  1913. pSpot = gEntList.FindEntityByClassname( NULL, "info_intermission");
  1914. if ( pSpot )
  1915. {
  1916. // at least one intermission spot in the world.
  1917. iRand = random->RandomInt( 0, 3 );
  1918. while ( iRand > 0 )
  1919. {
  1920. pNewSpot = gEntList.FindEntityByClassname( pSpot, "info_intermission");
  1921. if ( pNewSpot )
  1922. {
  1923. pSpot = pNewSpot;
  1924. }
  1925. iRand--;
  1926. }
  1927. CreateCorpse();
  1928. StartObserverMode( pSpot->GetAbsOrigin(), pSpot->GetAbsAngles() );
  1929. }
  1930. else
  1931. {
  1932. // no intermission spot. Push them up in the air, looking down at their corpse
  1933. trace_t tr;
  1934. CreateCorpse();
  1935. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, 128 ),
  1936. MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
  1937. QAngle angles;
  1938. VectorAngles( GetAbsOrigin() - tr.endpos, angles );
  1939. StartObserverMode( tr.endpos, angles );
  1940. return;
  1941. }
  1942. } */
  1943. void CBasePlayer::StopObserverMode()
  1944. {
  1945. m_bForcedObserverMode = false;
  1946. m_afPhysicsFlags &= ~PFLAG_OBSERVER;
  1947. if ( m_iObserverMode == OBS_MODE_NONE )
  1948. return;
  1949. if ( m_iObserverMode > OBS_MODE_DEATHCAM )
  1950. {
  1951. m_iObserverLastMode = m_iObserverMode;
  1952. }
  1953. m_iObserverMode.Set( OBS_MODE_NONE );
  1954. m_hObserverTarget.Set( NULL );
  1955. ShowViewPortPanel( "specmenu", false );
  1956. ShowViewPortPanel( "specgui", false );
  1957. ShowViewPortPanel( "overview", false );
  1958. //Send a specific message to tell the spectator UI that it is no longer needed (whether it is hidden or not).
  1959. CSingleUserRecipientFilter filter( this );
  1960. filter.MakeReliable();
  1961. CCSUsrMsg_StopSpectatorMode msg;
  1962. SendUserMessage( filter, CS_UM_StopSpectatorMode, msg );
  1963. }
  1964. bool CBasePlayer::StartObserverMode(int mode)
  1965. {
  1966. if ( !IsObserver() )
  1967. {
  1968. // set position to last view offset
  1969. SetAbsOrigin( GetAbsOrigin() + GetViewOffset() );
  1970. SetViewOffset( vec3_origin );
  1971. }
  1972. Assert( mode > OBS_MODE_NONE );
  1973. m_afPhysicsFlags |= PFLAG_OBSERVER;
  1974. // Holster weapon immediately, to allow it to cleanup
  1975. if ( GetActiveWeapon() )
  1976. GetActiveWeapon()->Holster();
  1977. // clear out the suit message cache so we don't keep chattering
  1978. SetSuitUpdate(NULL, FALSE, 0);
  1979. SetGroundEntity( (CBaseEntity *)NULL );
  1980. RemoveFlag( FL_DUCKING | FL_ANIMDUCKING );
  1981. m_Local.m_bDucking = m_Local.m_bDucked = false;
  1982. m_flDuckAmount = 0.0f;
  1983. AddSolidFlags( FSOLID_NOT_SOLID );
  1984. SetObserverMode( mode );
  1985. if ( gpGlobals->eLoadType == MapLoad_NewGame )
  1986. {
  1987. ShowViewPortPanel( "specgui" , ModeWantsSpectatorGUI(mode) );
  1988. }
  1989. // Setup flags
  1990. m_takedamage = DAMAGE_NO;
  1991. // Become invisible
  1992. AddEffects( EF_NODRAW );
  1993. m_iHealth = 0;
  1994. m_lifeState = LIFE_DEAD;
  1995. m_flDeathAnimTime = gpGlobals->curtime;
  1996. pl.deadflag = true;
  1997. return true;
  1998. }
  1999. bool CBasePlayer::SetObserverMode(int mode )
  2000. {
  2001. #if defined( CSTRIKE15 )
  2002. // // [mbooth] Adding override cvar. Roaming spec cam is invaluable for debugging bots!
  2003. // if ( !spec_allow_roaming.GetBool() )
  2004. // {
  2005. // // [jbright] Never allow players to enter OBS_MODE_ROAMING
  2006. // if ( mode == OBS_MODE_ROAMING )
  2007. // {
  2008. // mode = OBS_MODE_FIXED;
  2009. // }
  2010. // }
  2011. #endif // CSTRIKE15
  2012. if ( mode < OBS_MODE_NONE || mode >= NUM_OBSERVER_MODES )
  2013. return false;
  2014. // check mp_forcecamera settings for dead players
  2015. if ( ( mode > OBS_MODE_FIXED ) && ( ( GetTeamNumber() > TEAM_SPECTATOR ) || IsCoach() ) )
  2016. {
  2017. switch ( mp_forcecamera.GetInt() )
  2018. {
  2019. case OBS_ALLOW_ALL : break; // no restrictions
  2020. case OBS_ALLOW_TEAM : mode = OBS_MODE_IN_EYE; break;
  2021. case OBS_ALLOW_NONE : mode = OBS_MODE_FIXED; break; // don't allow anything
  2022. }
  2023. }
  2024. #ifdef CSTRIKE_DLL
  2025. // Overridden here instead of in derived class to avoid duplicating the rest of this function:
  2026. // if we're observing the planted bomb, force the camera to be in chase view
  2027. CPlantedC4* pPlantedC4 = dynamic_cast< CPlantedC4* >( m_hObserverTarget.Get() );
  2028. if ( pPlantedC4 )
  2029. {
  2030. mode = OBS_MODE_CHASE;
  2031. }
  2032. else
  2033. {
  2034. CBaseCSGrenadeProjectile* pGrenade = dynamic_cast< CBaseCSGrenadeProjectile* >( m_hObserverTarget.Get() );
  2035. if ( pGrenade )
  2036. mode = OBS_MODE_CHASE;
  2037. }
  2038. #endif
  2039. if ( m_iObserverMode > OBS_MODE_DEATHCAM )
  2040. {
  2041. // remember mode if we were really spectating before
  2042. m_iObserverLastMode = m_iObserverMode;
  2043. }
  2044. if ( ( m_iObserverMode == OBS_MODE_DEATHCAM || m_iObserverMode == OBS_MODE_FREEZECAM ) &&
  2045. ( mode == OBS_MODE_CHASE || mode == OBS_MODE_IN_EYE ) )
  2046. {
  2047. // when we transition from death/freezecam to spectating, reset our spectated target so we
  2048. // properly find a controllable bot (if one is available)
  2049. m_hObserverTarget = NULL;
  2050. }
  2051. m_iObserverMode = mode;
  2052. switch ( mode )
  2053. {
  2054. case OBS_MODE_NONE:
  2055. case OBS_MODE_FIXED :
  2056. case OBS_MODE_DEATHCAM :
  2057. SetFOV( this, 0 ); // Reset FOV
  2058. SetViewOffset( vec3_origin );
  2059. SetObserverTarget( NULL );
  2060. SetMoveType( MOVETYPE_NONE );
  2061. m_bIsSpecLerping = false;
  2062. break;
  2063. case OBS_MODE_CHASE :
  2064. case OBS_MODE_IN_EYE :
  2065. // update FOV and viewmodels
  2066. SetObserverTarget( m_hObserverTarget );
  2067. SetMoveType( MOVETYPE_OBSERVER );
  2068. m_bIsSpecLerping = false;
  2069. break;
  2070. case OBS_MODE_ROAMING :
  2071. SetFOV( this, 0 ); // Reset FOV
  2072. SetObserverTarget( m_hObserverTarget );
  2073. SetViewOffset( vec3_origin );
  2074. SetMoveType( MOVETYPE_OBSERVER );
  2075. break;
  2076. case OBS_MODE_FREEZECAM :
  2077. SetFOV( this, 0 ); // Reset FOV
  2078. SetObserverTarget( m_hObserverTarget );
  2079. SetViewOffset( vec3_origin );
  2080. SetMoveType( MOVETYPE_OBSERVER );
  2081. m_bIsSpecLerping = false;
  2082. break;
  2083. default:
  2084. SetObserverTarget( NULL );
  2085. break;
  2086. }
  2087. CheckObserverSettings();
  2088. IGameEvent *event = gameeventmanager->CreateEvent( "spec_mode_updated" );
  2089. if ( event )
  2090. {
  2091. event->SetInt("userid", GetUserID() );
  2092. gameeventmanager->FireEventClientSide( event );
  2093. }
  2094. return true;
  2095. }
  2096. int CBasePlayer::GetObserverMode()
  2097. {
  2098. return m_iObserverMode;
  2099. }
  2100. void CBasePlayer::ForceObserverMode(int mode)
  2101. {
  2102. int tempMode = OBS_MODE_ROAMING;
  2103. if ( m_iObserverMode == mode )
  2104. return;
  2105. // don't change last mode if already in forced mode
  2106. if ( m_bForcedObserverMode )
  2107. {
  2108. tempMode = m_iObserverLastMode;
  2109. }
  2110. SetObserverMode( mode );
  2111. if ( m_bForcedObserverMode )
  2112. {
  2113. m_iObserverLastMode = tempMode;
  2114. }
  2115. m_bForcedObserverMode = true;
  2116. }
  2117. void CBasePlayer::CheckObserverSettings()
  2118. {
  2119. // check if we are in forced mode and may go back to old mode
  2120. if ( m_bForcedObserverMode )
  2121. {
  2122. CBaseEntity * target = m_hObserverTarget;
  2123. if ( !IsValidObserverTarget(target) )
  2124. {
  2125. // if old target is still invalid, try to find valid one
  2126. target = FindNextObserverTarget( false );
  2127. }
  2128. if ( target )
  2129. {
  2130. // we found a valid target
  2131. m_bForcedObserverMode = false; // disable force mode
  2132. SetObserverMode( m_iObserverLastMode ); // switch to last mode
  2133. SetObserverTarget( target ); // goto target
  2134. // TODO check for HUD icons
  2135. return;
  2136. }
  2137. else
  2138. {
  2139. // else stay in forced mode, no changes
  2140. return;
  2141. }
  2142. }
  2143. // make sure our last mode is valid
  2144. if ( m_iObserverLastMode < OBS_MODE_FIXED )
  2145. {
  2146. m_iObserverLastMode = OBS_MODE_ROAMING;
  2147. }
  2148. // check if our spectating target is still a valid one
  2149. if ( m_iObserverMode == OBS_MODE_IN_EYE || m_iObserverMode == OBS_MODE_CHASE )
  2150. {
  2151. ValidateCurrentObserverTarget();
  2152. CBasePlayer *target = ToBasePlayer( m_hObserverTarget.Get() );
  2153. // for ineye mode we have to copy several data to see exactly the same
  2154. if ( target && m_iObserverMode == OBS_MODE_IN_EYE )
  2155. {
  2156. int flagMask = FL_ONGROUND | FL_DUCKING ;
  2157. int flags = target->GetFlags() & flagMask;
  2158. if ( (GetFlags() & flagMask) != flags )
  2159. {
  2160. flags |= GetFlags() & (~flagMask); // keep other flags
  2161. ClearFlags();
  2162. AddFlag( flags );
  2163. }
  2164. if ( target->GetViewOffset() != GetViewOffset() )
  2165. {
  2166. SetViewOffset( target->GetViewOffset() );
  2167. }
  2168. }
  2169. // Update the fog.
  2170. if ( target )
  2171. {
  2172. if ( target->m_PlayerFog.m_hCtrl.Get() != m_PlayerFog.m_hCtrl.Get() )
  2173. {
  2174. m_PlayerFog.m_hCtrl.Set( target->m_PlayerFog.m_hCtrl.Get() );
  2175. }
  2176. }
  2177. }
  2178. if ( m_bIsSpecLerping )
  2179. {
  2180. if ( (m_vecSpecLerpIdealPos == GetAbsOrigin() && m_angSpecLerpIdealAng == LocalEyeAngles()) || m_flSpecLerpEndTime <= gpGlobals->curtime )
  2181. {
  2182. m_bIsSpecLerping = false;
  2183. JumptoPosition(m_vecSpecLerpIdealPos,m_angSpecLerpIdealAng);
  2184. }
  2185. else
  2186. {
  2187. float flTransTime = m_flSpecLerpTime;
  2188. float flInterp = clamp( ( gpGlobals->curtime - (m_flSpecLerpEndTime - flTransTime) ) / flTransTime, 0.0f, 1.0f );
  2189. float flActualinterp = Gain( flInterp, 0.6 );
  2190. Vector vCamOrigin = m_vecSpecLerpOldPos + ((m_vecSpecLerpIdealPos-m_vecSpecLerpOldPos) * flActualinterp);
  2191. QAngle aCamAngles = Lerp( flActualinterp, m_angSpecLerpOldAng, m_angSpecLerpIdealAng );//m_angSpecLerpOldAng + ((m_angSpecLerpIdealAng-m_angSpecLerpOldAng) * flActualinterp);
  2192. JumptoPosition(vCamOrigin,aCamAngles);
  2193. }
  2194. }
  2195. }
  2196. //-----------------------------------------------------------------------------
  2197. // Purpose:
  2198. //-----------------------------------------------------------------------------
  2199. void CBasePlayer::ValidateCurrentObserverTarget( void )
  2200. {
  2201. if ( !IsValidObserverTarget( m_hObserverTarget.Get( ) ) )
  2202. {
  2203. // our target is not valid, try to find new target
  2204. CBaseEntity * target = FindNextObserverTarget( false );
  2205. if ( target )
  2206. {
  2207. // switch to new valid target
  2208. SetObserverTarget( target );
  2209. }
  2210. else
  2211. {
  2212. #ifdef CSTRIKE_DLL
  2213. // fix player view right where it is
  2214. ForceObserverMode( OBS_MODE_FIXED );
  2215. // default to a terrorist spawn if our camera position is at the world center
  2216. CBaseEntity *spot = NULL;
  2217. if ( EyePosition() == Vector( 0, 0, 0 ) )
  2218. {
  2219. spot = gEntList.FindEntityByClassname( spot, "info_player_terrorist" );
  2220. }
  2221. m_hObserverTarget.Set( spot ? spot : NULL );
  2222. #else
  2223. // couldn't find new target, switch to temporary mode
  2224. if ( mp_forcecamera.GetInt() == OBS_ALLOW_ALL )
  2225. {
  2226. // let player roam around
  2227. ForceObserverMode( OBS_MODE_ROAMING );
  2228. }
  2229. else
  2230. {
  2231. // fix player view right where it is
  2232. ForceObserverMode( OBS_MODE_FIXED );
  2233. m_hObserverTarget.Set( NULL );
  2234. }
  2235. #endif
  2236. }
  2237. }
  2238. }
  2239. //-----------------------------------------------------------------------------
  2240. // Purpose:
  2241. //-----------------------------------------------------------------------------
  2242. void CBasePlayer::AttemptToExitFreezeCam( void )
  2243. {
  2244. StartObserverMode( OBS_MODE_DEATHCAM );
  2245. }
  2246. bool CBasePlayer::StartReplayMode( float fDelay, float fDuration, int iEntity )
  2247. {
  2248. if ( ( sv_maxreplay == NULL ) || ( sv_maxreplay->GetFloat() <= 0 ) )
  2249. return false;
  2250. m_fDelay = fDelay;
  2251. m_fReplayEnd = gpGlobals->curtime + fDuration;
  2252. m_iReplayEntity = iEntity;
  2253. return true;
  2254. }
  2255. void CBasePlayer::StopReplayMode()
  2256. {
  2257. m_fDelay = 0.0f;
  2258. m_fReplayEnd = -1;
  2259. m_iReplayEntity = 0;
  2260. }
  2261. int CBasePlayer::GetDelayTicks()
  2262. {
  2263. if ( m_fReplayEnd > gpGlobals->curtime )
  2264. {
  2265. return TIME_TO_TICKS( m_fDelay );
  2266. }
  2267. else
  2268. {
  2269. if ( m_fDelay > 0.0f )
  2270. StopReplayMode();
  2271. return 0;
  2272. }
  2273. }
  2274. int CBasePlayer::GetReplayEntity()
  2275. {
  2276. return m_iReplayEntity;
  2277. }
  2278. CBaseEntity * CBasePlayer::GetObserverTarget()
  2279. {
  2280. return m_hObserverTarget.Get();
  2281. }
  2282. void CBasePlayer::ObserverUse( bool bIsPressed )
  2283. {
  2284. #if defined( REPLAY_ENABLED )
  2285. if ( !HLTVDirector()->IsActive() && !ReplayDirector()->IsActive() )
  2286. #else
  2287. if ( !HLTVDirector()->IsActive() )
  2288. #endif
  2289. return;
  2290. if ( GetTeamNumber() != TEAM_SPECTATOR || IsCoach() )
  2291. return; // only pure spectators can play cameraman
  2292. if ( !bIsPressed )
  2293. return;
  2294. bool bIsHLTV = HLTVDirector()->IsActive();
  2295. #if defined( REPLAY_ENABLED )
  2296. bool bIsReplay = ReplayDirector()->IsActive();
  2297. #endif
  2298. if ( bIsHLTV )
  2299. {
  2300. #ifdef CAMERAMAN_OLD_WAY
  2301. int iCameraManIndex = HLTVDirector()->GetCameraMan();
  2302. if ( iCameraManIndex == 0 )
  2303. {
  2304. // turn camera on
  2305. HLTVDirector()->SetCameraMan( entindex() );
  2306. }
  2307. else if ( iCameraManIndex == entindex() )
  2308. {
  2309. // turn camera off
  2310. HLTVDirector()->SetCameraMan( 0 );
  2311. }
  2312. else
  2313. {
  2314. ClientPrint( this, HUD_PRINTTALK, "Camera in use by other player." );
  2315. }
  2316. #else
  2317. // toggle the active cameraman flag
  2318. //m_bActiveCameraMan = !m_bActiveCameraMan;
  2319. #endif
  2320. }
  2321. #if defined( REPLAY_ENABLED )
  2322. else if ( bIsReplay )
  2323. {
  2324. int iCameraManIndex = ReplayDirector()->GetCameraMan();
  2325. if ( iCameraManIndex == 0 )
  2326. {
  2327. // turn camera on
  2328. ReplayDirector()->SetCameraMan( entindex() );
  2329. }
  2330. else if ( iCameraManIndex == entindex() )
  2331. {
  2332. // turn camera off
  2333. ReplayDirector()->SetCameraMan( 0 );
  2334. }
  2335. else
  2336. {
  2337. ClientPrint( this, HUD_PRINTTALK, "Camera in use by other player." );
  2338. }
  2339. }
  2340. #endif
  2341. else
  2342. {
  2343. #ifdef CAMERAMAN_OLD_WAY
  2344. IGameEvent *event = gameeventmanager->CreateEvent( "hltv_cameraman" );
  2345. if ( event )
  2346. {
  2347. event->SetInt("index", entindex() );
  2348. gameeventmanager->FireEventClientSide( event );
  2349. }
  2350. #else
  2351. // toggle the active cameraman flag
  2352. //m_bActiveCameraMan = !m_bActiveCameraMan;
  2353. #endif
  2354. }
  2355. /* UTIL_SayText( "Spectator can not USE anything", this );
  2356. Vector dir,end;
  2357. Vector start = GetAbsOrigin();
  2358. AngleVectors( GetAbsAngles(), &dir );
  2359. VectorNormalize( dir );
  2360. VectorMA( start, 32.0f, dir, end );
  2361. trace_t tr;
  2362. UTIL_TraceLine( start, end, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
  2363. if ( tr.fraction == 1.0f )
  2364. return; // no obstacles in spectators way
  2365. VectorMA( start, 128.0f, dir, end );
  2366. Ray_t ray;
  2367. ray.Init( end, start, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
  2368. UTIL_TraceRay( ray, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
  2369. if ( tr.startsolid || tr.allsolid )
  2370. return;
  2371. SetAbsOrigin( tr.endpos ); */
  2372. }
  2373. void CBasePlayer::JumptoPosition(const Vector &origin, const QAngle &angles)
  2374. {
  2375. SetAbsOrigin( origin );
  2376. SetAbsVelocity( vec3_origin ); // stop movement
  2377. SetLocalAngles( angles );
  2378. SnapEyeAngles( angles );
  2379. AddEffects( EF_NOINTERP );
  2380. }
  2381. void CBasePlayer::SpecLerptoPosition( const Vector &origin, const QAngle &angles, float flTime )
  2382. {
  2383. if ( m_iObserverMode != OBS_MODE_ROAMING && m_iObserverMode != OBS_MODE_FIXED )
  2384. return;
  2385. m_bIsSpecLerping = true;
  2386. m_vecSpecLerpOldPos = GetAbsOrigin();
  2387. m_angSpecLerpOldAng = LocalEyeAngles();
  2388. m_vecSpecLerpIdealPos = origin;
  2389. m_angSpecLerpIdealAng = angles;
  2390. m_flSpecLerpTime = flTime;
  2391. m_flSpecLerpEndTime = gpGlobals->curtime + flTime;
  2392. }
  2393. bool CBasePlayer::SetObserverTarget(CBaseEntity *target)
  2394. {
  2395. if ( !IsValidObserverTarget( target ) )
  2396. return false;
  2397. // set new target
  2398. m_hObserverTarget.Set( target );
  2399. // reset fov to default
  2400. SetFOV( this, 0 );
  2401. if ( m_iObserverMode == OBS_MODE_ROAMING )
  2402. {
  2403. Vector dir, end;
  2404. Vector start = target->EyePosition();
  2405. AngleVectors( target->EyeAngles(), &dir );
  2406. VectorNormalize( dir );
  2407. VectorMA( start, -64.0f, dir, end );
  2408. Ray_t ray;
  2409. ray.Init( start, end, VEC_DUCK_HULL_MIN , VEC_DUCK_HULL_MAX );
  2410. trace_t tr;
  2411. MDLCACHE_CRITICAL_SECTION();
  2412. UTIL_TraceRay( ray, MASK_PLAYERSOLID, target, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
  2413. JumptoPosition( tr.endpos, target->EyeAngles() );
  2414. }
  2415. return true;
  2416. }
  2417. ConVar sv_spec_post_death_additional_time( "sv_spec_post_death_additional_time", "0", FCVAR_RELEASE | FCVAR_REPLICATED, "", true, 0.0, true, 60.0 );
  2418. bool CBasePlayer::IsValidObserverTarget(CBaseEntity * target)
  2419. {
  2420. if ( target == NULL )
  2421. return false;
  2422. // MOD AUTHORS: Add checks on target here or in derived method
  2423. if ( !target->IsPlayer() ) // only track players
  2424. return false;
  2425. CBasePlayer * player = ToBasePlayer( target );
  2426. /* Don't spec observers or players who haven't picked a class yet
  2427. if ( player->IsObserver() )
  2428. return false; */
  2429. if( player == this )
  2430. return false; // We can't observe ourselves.
  2431. if ( player->m_lifeState == LIFE_RESPAWNABLE ) // target is dead, waiting for respawn
  2432. return false;
  2433. if ( player->m_lifeState == LIFE_DEAD || player->m_lifeState == LIFE_DYING )
  2434. {
  2435. #define SPEC_TEAMMATE_DEATH_MIN_TIME 0.5
  2436. float flDeathSpecTime = player->m_flDeathTime;
  2437. // allow spectators to add arbitrary delay to post-death target switch
  2438. if ( IsSpectator() )
  2439. {
  2440. flDeathSpecTime += DEATH_ANIMATION_TIME + sv_spec_post_death_additional_time.GetFloat( );
  2441. }
  2442. else
  2443. {
  2444. flDeathSpecTime += MIN( SPEC_TEAMMATE_DEATH_MIN_TIME, DEATH_ANIMATION_TIME );
  2445. }
  2446. if ( flDeathSpecTime < gpGlobals->curtime )
  2447. {
  2448. return false; // allow watching death animation
  2449. }
  2450. }
  2451. else if ( player->IsEffectActive( EF_NODRAW ) ) // don't watch invisible players that are not dead or dying
  2452. return false;
  2453. if ( !IsSpectator( ) )
  2454. {
  2455. // check forcecamera settings for active players
  2456. switch ( mp_forcecamera.GetInt() )
  2457. {
  2458. case OBS_ALLOW_ALL : break;
  2459. case OBS_ALLOW_TEAM : if ( GetAssociatedTeamNumber() != player->GetAssociatedTeamNumber() && !g_fGameOver )
  2460. return false;
  2461. break;
  2462. case OBS_ALLOW_NONE : return false;
  2463. }
  2464. }
  2465. if ( !PassesObserverFilter( player ) )
  2466. {
  2467. return false;
  2468. }
  2469. return true; // passed all test
  2470. }
  2471. int CBasePlayer::GetNextObserverSearchStartPoint( bool bReverse )
  2472. {
  2473. int iDir = bReverse ? -1 : 1;
  2474. int startIndex;
  2475. if ( m_hObserverTarget )
  2476. {
  2477. // start using last followed player
  2478. startIndex = m_hObserverTarget->entindex();
  2479. }
  2480. else
  2481. {
  2482. // start using own player index
  2483. startIndex = this->entindex();
  2484. }
  2485. startIndex += iDir;
  2486. if (startIndex > gpGlobals->maxClients)
  2487. startIndex = 1;
  2488. else if (startIndex < 1)
  2489. startIndex = gpGlobals->maxClients;
  2490. return startIndex;
  2491. }
  2492. bool CBasePlayer::PassesObserverFilter( const CBaseEntity *entity )
  2493. {
  2494. if ( !entity )
  2495. return false;
  2496. if ( !IsNetClient() )
  2497. return true;
  2498. return true;
  2499. }
  2500. CBaseEntity * CBasePlayer::FindNextObserverTarget(bool bReverse)
  2501. {
  2502. // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching
  2503. // only a subset of the players. e.g. Make it check the target's team.
  2504. /* if ( m_flNextFollowTime && m_flNextFollowTime > gpGlobals->time )
  2505. {
  2506. return;
  2507. }
  2508. m_flNextFollowTime = gpGlobals->time + 0.25;
  2509. */ // TODO move outside this function
  2510. int startIndex = GetNextObserverSearchStartPoint( bReverse );
  2511. // [jason] Force this value into the valid client index range, in case we were previously
  2512. // spectating something that isn't a player. This prevents the do..while loop below
  2513. // from getting in an infinite loop because of an invalid boundary condition
  2514. if (startIndex > gpGlobals->maxClients)
  2515. startIndex = 1;
  2516. else if (startIndex < 1)
  2517. startIndex = gpGlobals->maxClients;
  2518. int currentIndex = startIndex;
  2519. int iDir = bReverse ? -1 : 1;
  2520. do
  2521. {
  2522. CBaseEntity * nextTarget = UTIL_PlayerByIndex( currentIndex );
  2523. if ( IsValidObserverTarget( nextTarget ) )
  2524. {
  2525. return nextTarget; // found next valid player
  2526. }
  2527. currentIndex += iDir;
  2528. // Loop through the clients
  2529. if (currentIndex > gpGlobals->maxClients)
  2530. currentIndex = 1;
  2531. else if (currentIndex < 1)
  2532. currentIndex = gpGlobals->maxClients;
  2533. } while ( currentIndex != startIndex );
  2534. return NULL;
  2535. }
  2536. //-----------------------------------------------------------------------------
  2537. // Purpose: Return true if this object can be +used by the player
  2538. //-----------------------------------------------------------------------------
  2539. bool CBasePlayer::IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps )
  2540. {
  2541. if ( pEntity )
  2542. {
  2543. int caps = pEntity->ObjectCaps();
  2544. if ( caps & (FCAP_IMPULSE_USE|FCAP_CONTINUOUS_USE|FCAP_ONOFF_USE|FCAP_DIRECTIONAL_USE) )
  2545. {
  2546. if ( (caps & requiredCaps) == requiredCaps )
  2547. {
  2548. return true;
  2549. }
  2550. }
  2551. }
  2552. return false;
  2553. }
  2554. //-----------------------------------------------------------------------------
  2555. // Purpose: Server side of jumping rules. Most jumping logic is already
  2556. // handled in shared gamemovement code. Put stuff here that should
  2557. // only be done server side.
  2558. //-----------------------------------------------------------------------------
  2559. void CBasePlayer::Jump()
  2560. {
  2561. }
  2562. void CBasePlayer::Duck( )
  2563. {
  2564. if (m_nButtons & IN_DUCK)
  2565. {
  2566. if ( m_Activity != ACT_LEAP )
  2567. {
  2568. SetAnimation( PLAYER_WALK );
  2569. }
  2570. }
  2571. }
  2572. //
  2573. // ID's player as such.
  2574. //
  2575. Class_T CBasePlayer::Classify ( void )
  2576. {
  2577. return CLASS_PLAYER;
  2578. }
  2579. void CBasePlayer::ResetFragCount()
  2580. {
  2581. m_iFrags = 0;
  2582. pl.frags = m_iFrags;
  2583. m_nSuicides = 0;
  2584. }
  2585. void CBasePlayer::IncrementFragCount( int nCount, int nHeadshots )
  2586. {
  2587. m_iFrags += nCount;
  2588. pl.frags = m_iFrags;
  2589. }
  2590. void CBasePlayer::ResetAssistsCount()
  2591. {
  2592. m_iAssists = 0;
  2593. pl.assists = m_iAssists;
  2594. }
  2595. void CBasePlayer::IncrementAssistsCount( int nCount )
  2596. {
  2597. m_iAssists += nCount;
  2598. pl.assists = m_iAssists;
  2599. }
  2600. void CBasePlayer::ResetDeathCount()
  2601. {
  2602. m_iDeaths = 0;
  2603. pl.deaths = m_iDeaths;
  2604. }
  2605. void CBasePlayer::IncrementDeathCount( int nCount )
  2606. {
  2607. m_iDeaths += nCount;
  2608. pl.deaths = m_iDeaths;
  2609. }
  2610. void CBasePlayer::AddPoints( int score, bool bAllowNegativeScore )
  2611. {
  2612. // Positive score always adds
  2613. if ( score < 0 )
  2614. {
  2615. if ( !bAllowNegativeScore )
  2616. {
  2617. if ( m_iFrags < 0 ) // Can't go more negative
  2618. return;
  2619. if ( -score > m_iFrags ) // Will this go negative?
  2620. {
  2621. score = -m_iFrags; // Sum will be 0
  2622. }
  2623. }
  2624. }
  2625. m_iFrags += score;
  2626. pl.frags = m_iFrags;
  2627. }
  2628. void CBasePlayer::AddPointsToTeam( int score, bool bAllowNegativeScore )
  2629. {
  2630. if ( GetTeam() )
  2631. {
  2632. GetTeam()->AddScore( score );
  2633. }
  2634. }
  2635. //-----------------------------------------------------------------------------
  2636. // Purpose:
  2637. // Output : int
  2638. //-----------------------------------------------------------------------------
  2639. int CBasePlayer::GetCommandContextCount( void ) const
  2640. {
  2641. return m_CommandContext.Count();
  2642. }
  2643. //-----------------------------------------------------------------------------
  2644. // Purpose:
  2645. // Input : index -
  2646. // Output : CCommandContext
  2647. //-----------------------------------------------------------------------------
  2648. CCommandContext *CBasePlayer::GetCommandContext( int index )
  2649. {
  2650. if ( index < 0 || index >= m_CommandContext.Count() )
  2651. return NULL;
  2652. return &m_CommandContext[ index ];
  2653. }
  2654. //-----------------------------------------------------------------------------
  2655. // Purpose:
  2656. //-----------------------------------------------------------------------------
  2657. CCommandContext *CBasePlayer::AllocCommandContext( void )
  2658. {
  2659. int idx = m_CommandContext.AddToTail();
  2660. if ( m_CommandContext.Count() > 1000 )
  2661. {
  2662. Assert( 0 );
  2663. }
  2664. return &m_CommandContext[ idx ];
  2665. }
  2666. //-----------------------------------------------------------------------------
  2667. // Purpose:
  2668. // Input : index -
  2669. //-----------------------------------------------------------------------------
  2670. void CBasePlayer::RemoveCommandContext( int index )
  2671. {
  2672. m_CommandContext.Remove( index );
  2673. }
  2674. //-----------------------------------------------------------------------------
  2675. // Purpose:
  2676. //-----------------------------------------------------------------------------
  2677. void CBasePlayer::RemoveAllCommandContexts()
  2678. {
  2679. m_CommandContext.RemoveAll();
  2680. }
  2681. //-----------------------------------------------------------------------------
  2682. // Purpose: Removes all existing contexts, but leaves the last one around ( or creates it if it doesn't exist -- which would be a bug )
  2683. //-----------------------------------------------------------------------------
  2684. CCommandContext *CBasePlayer::RemoveAllCommandContextsExceptNewest( void )
  2685. {
  2686. int count = m_CommandContext.Count();
  2687. int toRemove = count - 1;
  2688. if ( toRemove > 0 )
  2689. {
  2690. m_CommandContext.RemoveMultiple( 0, toRemove );
  2691. }
  2692. if ( !m_CommandContext.Count() )
  2693. {
  2694. Assert( 0 );
  2695. CCommandContext *ctx = AllocCommandContext();
  2696. Q_memset( ctx, 0, sizeof( *ctx ) );
  2697. }
  2698. return &m_CommandContext[ 0 ];
  2699. }
  2700. //-----------------------------------------------------------------------------
  2701. // Purpose: Replaces the first nCommands CUserCmds in the context with the ones passed in -- this is used to help meter out CUserCmds over the number of simulation ticks on the server
  2702. //-----------------------------------------------------------------------------
  2703. void CBasePlayer::ReplaceContextCommands( CCommandContext *ctx, CUserCmd *pCommands, int nCommands )
  2704. {
  2705. // Blow away all of the commands
  2706. ctx->cmds.RemoveAll();
  2707. ctx->numcmds = nCommands;
  2708. ctx->totalcmds = nCommands;
  2709. ctx->dropped_packets = 0; // meaningless in this context
  2710. // Add them in so the most recent is at slot 0
  2711. for ( int i = nCommands - 1; i >= 0; --i )
  2712. {
  2713. ctx->cmds.AddToTail( pCommands[ i ] );
  2714. }
  2715. }
  2716. //-----------------------------------------------------------------------------
  2717. // Purpose: Determine how much time we will be running this frame
  2718. // Output : float
  2719. //-----------------------------------------------------------------------------
  2720. int CBasePlayer::DetermineSimulationTicks( void )
  2721. {
  2722. int command_context_count = GetCommandContextCount();
  2723. int context_number;
  2724. int simulation_ticks = 0;
  2725. // Determine how much time we will be running this frame and fixup player clock as needed
  2726. for ( context_number = 0; context_number < command_context_count; context_number++ )
  2727. {
  2728. CCommandContext const *ctx = GetCommandContext( context_number );
  2729. Assert( ctx );
  2730. Assert( ctx->numcmds > 0 );
  2731. Assert( ctx->dropped_packets >= 0 );
  2732. // Determine how long it will take to run those packets
  2733. simulation_ticks += ctx->numcmds + ctx->dropped_packets;
  2734. }
  2735. return simulation_ticks;
  2736. }
  2737. // 2 ticks ahead or behind current clock means we need to fix clock on client
  2738. static ConVar sv_clockcorrection_msecs( "sv_clockcorrection_msecs", "30", FCVAR_RELEASE, "The server tries to keep each player's m_nTickBase withing this many msecs of the server absolute tickcount" );
  2739. static ConVar sv_playerperfhistorycount( "sv_playerperfhistorycount", "20", 0, "Number of samples to maintain in player perf history", true, 1.0f, true, 128.0 );
  2740. //-----------------------------------------------------------------------------
  2741. // Purpose: Based upon amount of time in simulation time, adjust m_nTickBase so that
  2742. // we just end at the end of the current frame (so the player is basically on clock
  2743. // with the server)
  2744. // Input : simulation_ticks -
  2745. //-----------------------------------------------------------------------------
  2746. void CBasePlayer::AdjustPlayerTimeBase( int simulation_ticks )
  2747. {
  2748. Assert( simulation_ticks >= 0 );
  2749. if ( simulation_ticks < 0 )
  2750. return;
  2751. CPlayerSimInfo *pi = NULL;
  2752. if ( sv_playerperfhistorycount.GetInt() > 0 )
  2753. {
  2754. while ( m_vecPlayerSimInfo.Count() > sv_playerperfhistorycount.GetInt() )
  2755. {
  2756. m_vecPlayerSimInfo.Remove( m_vecPlayerSimInfo.Head() );
  2757. }
  2758. pi = &m_vecPlayerSimInfo[ m_vecPlayerSimInfo.AddToTail() ];
  2759. }
  2760. // Start in the past so that we get to the sv.time that we'll hit at the end of the
  2761. // frame, just as we process the final command
  2762. if ( !m_bPredictionEnabled || (gpGlobals->maxClients == 1) )
  2763. {
  2764. // set TickBase so that player simulation tick matches gpGlobals->tickcount after
  2765. // all commands have been executed
  2766. m_nTickBase = gpGlobals->tickcount - simulation_ticks + gpGlobals->simTicksThisFrame;
  2767. }
  2768. else // multiplayer
  2769. {
  2770. float flCorrectionSeconds = clamp( sv_clockcorrection_msecs.GetFloat() / 1000.0f, 0.0f, 1.0f );
  2771. int nCorrectionTicks = TIME_TO_TICKS( flCorrectionSeconds );
  2772. // Set the target tick flCorrectionSeconds (rounded to ticks) ahead in the future. this way the client can
  2773. // alternate around this target tick without getting smaller than gpGlobals->tickcount.
  2774. // After running the commands simulation time should be equal or after current gpGlobals->tickcount,
  2775. // otherwise the simulation time drops out of the client side interpolated var history window.
  2776. int nIdealFinalTick = gpGlobals->tickcount + nCorrectionTicks;
  2777. int nEstimatedFinalTick = m_nTickBase + simulation_ticks;
  2778. // If client gets ahead of this, we'll need to correct
  2779. int too_fast_limit = nIdealFinalTick + nCorrectionTicks;
  2780. // If client falls behind this, we'll also need to correct
  2781. int too_slow_limit = nIdealFinalTick - nCorrectionTicks;
  2782. // See if we are too fast
  2783. if ( nEstimatedFinalTick > too_fast_limit ||
  2784. nEstimatedFinalTick < too_slow_limit )
  2785. {
  2786. int nCorrectedTick = nIdealFinalTick - simulation_ticks + gpGlobals->simTicksThisFrame;
  2787. if ( pi )
  2788. {
  2789. pi->m_nTicksCorrected = nCorrectionTicks;
  2790. }
  2791. m_nTickBase = nCorrectedTick;
  2792. }
  2793. }
  2794. if ( pi )
  2795. {
  2796. pi->m_flFinalSimulationTime = TICKS_TO_TIME( m_nTickBase + simulation_ticks + gpGlobals->simTicksThisFrame );
  2797. }
  2798. }
  2799. void CBasePlayer::RunNullCommand( void )
  2800. {
  2801. CUserCmd cmd; // NULL command
  2802. // Store off the globals.. they're gonna get whacked
  2803. float flOldFrametime = gpGlobals->frametime;
  2804. float flOldCurtime = gpGlobals->curtime;
  2805. pl.fixangle = FIXANGLE_NONE;
  2806. cmd.viewangles = EyeAngles();
  2807. float flTimeBase = gpGlobals->curtime;
  2808. SetTimeBase( flTimeBase );
  2809. MoveHelperServer()->SetHost( this );
  2810. PlayerRunCommand( &cmd, MoveHelperServer() );
  2811. // save off the last good usercmd
  2812. SetLastUserCommand( cmd );
  2813. // Restore the globals..
  2814. gpGlobals->frametime = flOldFrametime;
  2815. gpGlobals->curtime = flOldCurtime;
  2816. MoveHelperServer()->SetHost( NULL );
  2817. }
  2818. //-----------------------------------------------------------------------------
  2819. // Purpose: Note, don't chain to BaseClass::PhysicsSimulate
  2820. //-----------------------------------------------------------------------------
  2821. void CBasePlayer::PhysicsSimulate( void )
  2822. {
  2823. VPROF_BUDGET( "CBasePlayer::PhysicsSimulate", VPROF_BUDGETGROUP_PLAYER );
  2824. // If we've got a moveparent, we must simulate that first.
  2825. CBaseEntity *pMoveParent = GetMoveParent();
  2826. if (pMoveParent)
  2827. {
  2828. pMoveParent->PhysicsSimulate();
  2829. }
  2830. // Make sure not to simulate this guy twice per frame
  2831. if ( m_nSimulationTick == gpGlobals->tickcount )
  2832. {
  2833. return;
  2834. }
  2835. m_nSimulationTick = gpGlobals->tickcount;
  2836. // See how many CUserCmds are queued up for running
  2837. int simulation_ticks = DetermineSimulationTicks();
  2838. // If some time will elapse, make sure our clock (m_nTickBase) starts at the correct time
  2839. if ( simulation_ticks > 0 )
  2840. {
  2841. AdjustPlayerTimeBase( simulation_ticks );
  2842. }
  2843. #if defined( REPLAY_ENABLED )
  2844. if ( IsHLTV() || IsReplay() )
  2845. #else
  2846. if ( IsHLTV() )
  2847. #endif
  2848. {
  2849. // just run a single, empty command to make sure
  2850. // all PreThink/PostThink functions are called as usual
  2851. Assert ( GetCommandContextCount() == 0 );
  2852. RunNullCommand();
  2853. RemoveAllCommandContexts();
  2854. return;
  2855. }
  2856. // Store off true server timestamps
  2857. float savetime = gpGlobals->curtime;
  2858. float saveframetime = gpGlobals->frametime;
  2859. int command_context_count = GetCommandContextCount();
  2860. // Build a list of all available commands
  2861. CUtlVector< CUserCmd > vecAvailCommands;
  2862. // Contexts go from oldest to newest
  2863. for ( int context_number = 0; context_number < command_context_count; context_number++ )
  2864. {
  2865. // Get oldest ( newer are added to tail )
  2866. CCommandContext *ctx = GetCommandContext( context_number );
  2867. if ( !ShouldRunCommandsInContext( ctx ) )
  2868. continue;
  2869. if ( !ctx->cmds.Count() )
  2870. continue;
  2871. int numbackup = ctx->totalcmds - ctx->numcmds;
  2872. // If we haven't dropped too many packets, then run some commands
  2873. if ( ctx->dropped_packets < 24 )
  2874. {
  2875. int droppedcmds = ctx->dropped_packets;
  2876. // run the last known cmd for each dropped cmd we don't have a backup for
  2877. while ( droppedcmds > numbackup )
  2878. {
  2879. m_LastCmd.tick_count++;
  2880. vecAvailCommands.AddToTail( m_LastCmd );
  2881. droppedcmds--;
  2882. }
  2883. // Now run the "history" commands if we still have dropped packets
  2884. while ( droppedcmds > 0 )
  2885. {
  2886. int cmdnum = ctx->numcmds + droppedcmds - 1;
  2887. vecAvailCommands.AddToTail( ctx->cmds[cmdnum] );
  2888. droppedcmds--;
  2889. }
  2890. }
  2891. // Now run any new command(s). Go backward because the most recent command is at index 0.
  2892. for ( int i = ctx->numcmds - 1; i >= 0; i-- )
  2893. {
  2894. vecAvailCommands.AddToTail( ctx->cmds[i] );
  2895. }
  2896. // Save off the last good command in case we drop > numbackup packets and need to rerun them
  2897. // we'll use this to "guess" at what was in the missing packets
  2898. m_LastCmd = ctx->cmds[ CMD_MOSTRECENT ];
  2899. }
  2900. // gpGlobals->simTicksThisFrame == number of ticks remaining to be run, so we should take the last N CUserCmds and postpone them until the next frame
  2901. // If we're running multiple ticks this frame, don't peel off all of the commands, spread them out over
  2902. // the server ticks. Use blocks of two in alternate ticks
  2903. int commandLimit = CBaseEntity::IsSimulatingOnAlternateTicks() ? 2 : 1;
  2904. int commandsToRun = vecAvailCommands.Count();
  2905. if ( gpGlobals->simTicksThisFrame >= commandLimit && vecAvailCommands.Count() > commandLimit )
  2906. {
  2907. int commandsToRollOver = MIN( vecAvailCommands.Count(), ( gpGlobals->simTicksThisFrame - 1 ) );
  2908. commandsToRun = vecAvailCommands.Count() - commandsToRollOver;
  2909. Assert( commandsToRun >= 0 );
  2910. // Clear all contexts except the last one
  2911. if ( commandsToRollOver > 0 )
  2912. {
  2913. CCommandContext *ctx = RemoveAllCommandContextsExceptNewest();
  2914. ReplaceContextCommands( ctx, &vecAvailCommands[ commandsToRun ], commandsToRollOver );
  2915. }
  2916. else
  2917. {
  2918. // Clear all contexts
  2919. RemoveAllCommandContexts();
  2920. }
  2921. }
  2922. else
  2923. {
  2924. // Clear all contexts
  2925. RemoveAllCommandContexts();
  2926. }
  2927. float vphysicsArrivalTime = TICK_INTERVAL;
  2928. bool bRunNullCmd = false;
  2929. if ( int numUsrCmdProcessTicksMax = sv_maxusrcmdprocessticks.GetInt() )
  2930. {
  2931. // Grant the client some time buffer to execute user commands
  2932. m_flMovementTimeForUserCmdProcessingRemaining += TICK_INTERVAL;
  2933. // but never accumulate more than N ticks
  2934. if ( m_flMovementTimeForUserCmdProcessingRemaining > numUsrCmdProcessTicksMax * TICK_INTERVAL )
  2935. {
  2936. m_flMovementTimeForUserCmdProcessingRemaining = numUsrCmdProcessTicksMax * TICK_INTERVAL;
  2937. bRunNullCmd = true;
  2938. }
  2939. }
  2940. else
  2941. {
  2942. // Otherwise we don't care to track time
  2943. m_flMovementTimeForUserCmdProcessingRemaining = FLT_MAX;
  2944. }
  2945. // Now run the commands
  2946. if ( commandsToRun > 0 )
  2947. {
  2948. MoveHelperServer()->SetHost( this );
  2949. // Suppress predicted events, etc.
  2950. if ( IsPredictingWeapons() )
  2951. {
  2952. IPredictionSystem::SuppressHostEvents( this );
  2953. }
  2954. // Process user commands
  2955. for ( int i = 0; i < commandsToRun; ++i )
  2956. {
  2957. PlayerRunCommand( &vecAvailCommands[ i ], MoveHelperServer() );
  2958. // Update our vphysics object.
  2959. if ( m_pPhysicsController )
  2960. {
  2961. VPROF( "CBasePlayer::PhysicsSimulate-UpdateVPhysicsPosition" );
  2962. // If simulating at 2 * TICK_INTERVAL, add an extra TICK_INTERVAL to position arrival computation
  2963. UpdateVPhysicsPosition( m_vNewVPhysicsPosition, m_vNewVPhysicsVelocity, vphysicsArrivalTime );
  2964. vphysicsArrivalTime += TICK_INTERVAL;
  2965. }
  2966. }
  2967. // Always reset after running commands
  2968. IPredictionSystem::SuppressHostEvents( NULL );
  2969. MoveHelperServer()->SetHost( NULL );
  2970. // Copy in final origin from simulation
  2971. CPlayerSimInfo *pi = NULL;
  2972. if ( m_vecPlayerSimInfo.Count() > 0 )
  2973. {
  2974. pi = &m_vecPlayerSimInfo[ m_vecPlayerSimInfo.Tail() ];
  2975. pi->m_flTime = gpGlobals->realtime;
  2976. pi->m_vecAbsOrigin = GetAbsOrigin();
  2977. pi->m_flGameSimulationTime = gpGlobals->curtime;
  2978. pi->m_nNumCmds = commandsToRun;
  2979. }
  2980. }
  2981. else if ( bRunNullCmd )
  2982. {
  2983. CUserCmd cmd = m_LastCmd;
  2984. float flOldFrametime = gpGlobals->frametime;
  2985. float flOldCurtime = gpGlobals->curtime;
  2986. pl.fixangle = FIXANGLE_NONE;
  2987. cmd.viewangles = EyeAngles();
  2988. float flTimeBase = gpGlobals->curtime;
  2989. SetTimeBase( flTimeBase );
  2990. MoveHelperServer()->SetHost( this );
  2991. PlayerRunCommand( &cmd, MoveHelperServer() );
  2992. SetLastUserCommand( cmd );
  2993. // Restore the globals..
  2994. gpGlobals->frametime = flOldFrametime;
  2995. gpGlobals->curtime = flOldCurtime;
  2996. MoveHelperServer()->SetHost( NULL );
  2997. }
  2998. // Restore the true server clock
  2999. // FIXME: Should this occur after simulation of children so
  3000. // that they are in the timespace of the player?
  3001. gpGlobals->curtime = savetime;
  3002. gpGlobals->frametime = saveframetime;
  3003. }
  3004. unsigned int CBasePlayer::PhysicsSolidMaskForEntity() const
  3005. {
  3006. return MASK_PLAYERSOLID;
  3007. }
  3008. //-----------------------------------------------------------------------------
  3009. // Purpose: Move us a bit to ensure we're spawning somewhere we can actually move around.
  3010. //-----------------------------------------------------------------------------
  3011. void CBasePlayer::EnsureValidSpawnLocation()
  3012. {
  3013. TM_ZONE_DEFAULT( TELEMETRY_LEVEL4 );
  3014. Vector absOrigin = GetAbsOrigin();
  3015. trace_t trace;
  3016. UTIL_TraceEntity( this, absOrigin, absOrigin, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  3017. if ( !trace.startsolid )
  3018. return;
  3019. // See if we can find a place upwards up to 1/2 player height to move to.
  3020. UTIL_TraceEntity( this, absOrigin + Vector( 0, 0, 36 ), absOrigin, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  3021. // Couldn't find a valid location here! Yikes. Ignore the case where the x and y coords are 0, because
  3022. Assert( !trace.allsolid || ( absOrigin.x == 0.0f && absOrigin.y == 0.0f ) );
  3023. if ( trace.allsolid )
  3024. return;
  3025. Teleport( &trace.endpos, NULL, NULL );
  3026. }
  3027. //-----------------------------------------------------------------------------
  3028. // Purpose: This will force usercmd processing to actually consume commands even if the global tick counter isn't incrementing
  3029. //-----------------------------------------------------------------------------
  3030. void CBasePlayer::ForceSimulation()
  3031. {
  3032. m_nSimulationTick = -1;
  3033. }
  3034. //-----------------------------------------------------------------------------
  3035. // Purpose:
  3036. // Input : *buf -
  3037. // totalcmds -
  3038. // dropped_packets -
  3039. // ignore -
  3040. // paused -
  3041. // Output : float -- Time in seconds of last movement command
  3042. //-----------------------------------------------------------------------------
  3043. ConVar sv_usercmd_custom_random_seed( "sv_usercmd_custom_random_seed", "1", FCVAR_RELEASE, "When enabled server will populate an additional random seed independent of the client" );
  3044. void CBasePlayer::ProcessUsercmds( CUserCmd *cmds, int numcmds, int totalcmds,
  3045. int dropped_packets, bool paused )
  3046. {
  3047. CCommandContext *ctx = AllocCommandContext();
  3048. Assert( ctx );
  3049. int i;
  3050. for ( i = totalcmds - 1; i >= 0; i-- )
  3051. {
  3052. int iCmdAdded = ctx->cmds.AddToTail( cmds[ totalcmds - 1 - i ] );
  3053. CUserCmd &cmdFixup = ctx->cmds[ iCmdAdded ];
  3054. if ( sv_usercmd_custom_random_seed.GetBool() )
  3055. {
  3056. float fltTimeNow = float( Plat_FloatTime()*1000.0 );
  3057. cmdFixup.server_random_seed = * reinterpret_cast< int * >( ( char * ) &fltTimeNow );
  3058. }
  3059. else
  3060. {
  3061. cmdFixup.server_random_seed = cmdFixup.random_seed;
  3062. }
  3063. }
  3064. ctx->numcmds = numcmds;
  3065. ctx->totalcmds = totalcmds,
  3066. ctx->dropped_packets = dropped_packets;
  3067. ctx->paused = paused;
  3068. // If the server is paused, zero out motion,buttons,view changes
  3069. if ( ctx->paused )
  3070. {
  3071. bool clear_angles = true;
  3072. // If no clipping and cheats enabled and sv_noclipduringpause enabled, then don't zero out movement part of CUserCmd
  3073. if ( GetMoveType() == MOVETYPE_NOCLIP &&
  3074. sv_cheats->GetBool() &&
  3075. sv_noclipduringpause.GetBool() )
  3076. {
  3077. clear_angles = false;
  3078. }
  3079. for ( i = 0; i < ctx->numcmds; i++ )
  3080. {
  3081. ctx->cmds[ i ].buttons = 0;
  3082. if ( clear_angles )
  3083. {
  3084. ctx->cmds[ i ].forwardmove = 0;
  3085. ctx->cmds[ i ].sidemove = 0;
  3086. ctx->cmds[ i ].upmove = 0;
  3087. VectorCopy ( pl.v_angle, ctx->cmds[ i ].viewangles );
  3088. }
  3089. }
  3090. ctx->dropped_packets = 0;
  3091. }
  3092. // Set global pause state for this player
  3093. m_bGamePaused = paused;
  3094. if ( paused )
  3095. {
  3096. ForceSimulation();
  3097. // Just run the commands right away if paused
  3098. PhysicsSimulate();
  3099. }
  3100. if ( sv_playerperfhistorycount.GetInt() > 0 )
  3101. {
  3102. CPlayerCmdInfo pi;
  3103. pi.m_flTime = gpGlobals->realtime;
  3104. pi.m_nDroppedPackets = dropped_packets;
  3105. pi.m_nNumCmds = numcmds;
  3106. while ( m_vecPlayerCmdInfo.Count() >= sv_playerperfhistorycount.GetInt() )
  3107. {
  3108. m_vecPlayerCmdInfo.Remove( m_vecPlayerCmdInfo.Head() );
  3109. }
  3110. m_vecPlayerCmdInfo.AddToTail( pi );
  3111. }
  3112. }
  3113. void CBasePlayer::DumpPerfToRecipient( CBasePlayer *pRecipient, int nMaxRecords )
  3114. {
  3115. if ( !pRecipient )
  3116. return;
  3117. char buf[ 256 ] = { 0 };
  3118. int curpos = 0;
  3119. int nDumped = 0;
  3120. Vector prevo( 0, 0, 0 );
  3121. float prevt = 0.0f;
  3122. for ( int i = m_vecPlayerSimInfo.Tail(); i != m_vecPlayerSimInfo.InvalidIndex() ; i = m_vecPlayerSimInfo.Previous( i ) )
  3123. {
  3124. const CPlayerSimInfo *pi = &m_vecPlayerSimInfo[ i ];
  3125. float vel = 0.0f;
  3126. // Note we're walking from newest backward
  3127. float dt = prevt - pi->m_flFinalSimulationTime;
  3128. if ( nDumped > 0 && dt > 0.0f )
  3129. {
  3130. Vector d = pi->m_vecAbsOrigin - prevo;
  3131. vel = d.Length() / dt;
  3132. }
  3133. char line[ 128 ];
  3134. int len = Q_snprintf( line, sizeof( line ), "%.3f %d %d %.3f %.3f %.3f [vel %.2f]\n",
  3135. pi->m_flTime,
  3136. pi->m_nNumCmds,
  3137. pi->m_nTicksCorrected,
  3138. pi->m_flFinalSimulationTime,
  3139. pi->m_flGameSimulationTime,
  3140. pi->m_flServerFrameTime,
  3141. vel );
  3142. if ( curpos + len > 200 )
  3143. {
  3144. ClientPrint( pRecipient, HUD_PRINTCONSOLE, (char const *)buf );
  3145. buf[ 0 ] = 0;
  3146. curpos = 0;
  3147. }
  3148. Q_strncpy( &buf[ curpos ], line, sizeof( buf ) - curpos );
  3149. curpos += len;
  3150. ++nDumped;
  3151. if ( nMaxRecords != -1 && nDumped >= nMaxRecords )
  3152. break;
  3153. prevo = pi->m_vecAbsOrigin;
  3154. prevt = pi->m_flFinalSimulationTime;
  3155. }
  3156. if ( curpos > 0 )
  3157. {
  3158. ClientPrint( pRecipient, HUD_PRINTCONSOLE, buf );
  3159. }
  3160. nDumped = 0;
  3161. curpos = 0;
  3162. for ( int i = m_vecPlayerCmdInfo.Tail(); i != m_vecPlayerCmdInfo.InvalidIndex() ; i = m_vecPlayerCmdInfo.Previous( i ) )
  3163. {
  3164. const CPlayerCmdInfo *pi = &m_vecPlayerCmdInfo[ i ];
  3165. char line[ 128 ];
  3166. int len = Q_snprintf( line, sizeof( line ), "%.3f %d %d\n",
  3167. pi->m_flTime,
  3168. pi->m_nNumCmds,
  3169. pi->m_nDroppedPackets );
  3170. if ( curpos + len > 200 )
  3171. {
  3172. ClientPrint( pRecipient, HUD_PRINTCONSOLE, (char const *)buf );
  3173. buf[ 0 ] = 0;
  3174. curpos = 0;
  3175. }
  3176. Q_strncpy( &buf[ curpos ], line, sizeof( buf ) - curpos );
  3177. curpos += len;
  3178. ++nDumped;
  3179. if ( nMaxRecords != -1 && nDumped >= nMaxRecords )
  3180. break;
  3181. }
  3182. if ( curpos > 0 )
  3183. {
  3184. ClientPrint( pRecipient, HUD_PRINTCONSOLE, buf );
  3185. }
  3186. }
  3187. // Duck debouncing code to stop menu changes from disallowing crouch/uncrouch
  3188. ConVar xc_crouch_debounce( "xc_crouch_debounce", "0", FCVAR_NONE );
  3189. //-----------------------------------------------------------------------------
  3190. // Purpose:
  3191. //-----------------------------------------------------------------------------
  3192. bool CBasePlayer::HasQueuedUsercmds( void ) const
  3193. {
  3194. return GetCommandContextCount() > 0;
  3195. }
  3196. //-----------------------------------------------------------------------------
  3197. // Purpose:
  3198. // Input : *ucmd -
  3199. // *moveHelper -
  3200. //-----------------------------------------------------------------------------
  3201. void CBasePlayer::PlayerRunCommand(CUserCmd *ucmd, IMoveHelper *moveHelper)
  3202. {
  3203. m_bTouchedPhysObject = false;
  3204. if ( pl.fixangle == FIXANGLE_NONE)
  3205. {
  3206. VectorCopy ( ucmd->viewangles, pl.v_angle );
  3207. }
  3208. // Handle FL_FROZEN.
  3209. // Prevent player moving for some seconds after New Game, so that they pick up everything
  3210. if( GetFlags() & FL_FROZEN ||
  3211. (developer.GetInt() == 0 && gpGlobals->eLoadType == MapLoad_NewGame && gpGlobals->curtime < 3.0 ) )
  3212. {
  3213. ucmd->forwardmove = 0;
  3214. ucmd->sidemove = 0;
  3215. ucmd->upmove = 0;
  3216. ucmd->buttons = 0;
  3217. ucmd->impulse = 0;
  3218. VectorCopy ( pl.v_angle, ucmd->viewangles );
  3219. }
  3220. else if( !m_bDuckEnabled )
  3221. {
  3222. ucmd->buttons &= ~IN_DUCK;
  3223. m_bDuckToggled = false;
  3224. }
  3225. else
  3226. {
  3227. // Force a duck if we're toggled
  3228. if ( GetToggledDuckState() )
  3229. {
  3230. // If this is set, we've altered our menu options and need to debounce the duck
  3231. if ( xc_crouch_debounce.GetBool() )
  3232. {
  3233. ToggleDuck();
  3234. // Mark it as handled
  3235. xc_crouch_debounce.SetValue( 0 );
  3236. }
  3237. else
  3238. {
  3239. ucmd->buttons |= IN_DUCK;
  3240. }
  3241. }
  3242. }
  3243. PlayerMove()->RunCommand(this, ucmd, moveHelper);
  3244. }
  3245. //-----------------------------------------------------------------------------
  3246. // Purpose: Strips off IN_xxx flags from the player's input
  3247. //-----------------------------------------------------------------------------
  3248. void CBasePlayer::DisableButtons( int nButtons )
  3249. {
  3250. m_afButtonDisabled |= nButtons;
  3251. }
  3252. //-----------------------------------------------------------------------------
  3253. // Purpose: Re-enables stripped IN_xxx flags to the player's input
  3254. //-----------------------------------------------------------------------------
  3255. void CBasePlayer::EnableButtons( int nButtons )
  3256. {
  3257. m_afButtonDisabled &= ~nButtons;
  3258. }
  3259. void CBasePlayer::HandleFuncTrain(void)
  3260. {
  3261. if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
  3262. AddFlag( FL_ONTRAIN );
  3263. else
  3264. RemoveFlag( FL_ONTRAIN );
  3265. // Train speed control
  3266. if (( m_afPhysicsFlags & PFLAG_DIROVERRIDE ) == 0)
  3267. {
  3268. if (m_iTrain & TRAIN_ACTIVE)
  3269. {
  3270. m_iTrain = TRAIN_NEW; // turn off train
  3271. }
  3272. return;
  3273. }
  3274. CBaseEntity *pTrain = GetGroundEntity();
  3275. float vel;
  3276. if ( pTrain )
  3277. {
  3278. if ( !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) )
  3279. pTrain = NULL;
  3280. }
  3281. if ( !pTrain )
  3282. {
  3283. if ( GetActiveWeapon()->ObjectCaps() & FCAP_DIRECTIONAL_USE )
  3284. {
  3285. m_iTrain = TRAIN_ACTIVE | TRAIN_NEW;
  3286. if ( m_nButtons & IN_FORWARD )
  3287. {
  3288. m_iTrain |= TRAIN_FAST;
  3289. }
  3290. else if ( m_nButtons & IN_BACK )
  3291. {
  3292. m_iTrain |= TRAIN_BACK;
  3293. }
  3294. else
  3295. {
  3296. m_iTrain |= TRAIN_NEUTRAL;
  3297. }
  3298. return;
  3299. }
  3300. else
  3301. {
  3302. trace_t trainTrace;
  3303. // Maybe this is on the other side of a level transition
  3304. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector(0,0,-38),
  3305. MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trainTrace );
  3306. if ( trainTrace.fraction != 1.0 && trainTrace.m_pEnt )
  3307. pTrain = trainTrace.m_pEnt;
  3308. if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(this) )
  3309. {
  3310. m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
  3311. m_iTrain = TRAIN_NEW|TRAIN_OFF;
  3312. return;
  3313. }
  3314. }
  3315. }
  3316. else if ( !( GetFlags() & FL_ONGROUND ) || pTrain->HasSpawnFlags( SF_TRACKTRAIN_NOCONTROL ) || (m_nButtons & (IN_MOVELEFT|IN_MOVERIGHT) ) )
  3317. {
  3318. // Turn off the train if you jump, strafe, or the train controls go dead
  3319. m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
  3320. m_iTrain = TRAIN_NEW|TRAIN_OFF;
  3321. return;
  3322. }
  3323. SetAbsVelocity( vec3_origin );
  3324. vel = 0;
  3325. if ( m_afButtonPressed & IN_FORWARD )
  3326. {
  3327. vel = 1;
  3328. pTrain->Use( this, this, USE_SET, (float)vel );
  3329. }
  3330. else if ( m_afButtonPressed & IN_BACK )
  3331. {
  3332. vel = -1;
  3333. pTrain->Use( this, this, USE_SET, (float)vel );
  3334. }
  3335. if (vel)
  3336. {
  3337. m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed());
  3338. m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW;
  3339. }
  3340. }
  3341. void CBasePlayer::PreThink(void)
  3342. {
  3343. EnsureSplitScreenTeam();
  3344. if ( g_fGameOver || m_iPlayerLocked )
  3345. return; // intermission or finale
  3346. if ( Hints() )
  3347. {
  3348. Hints()->Update();
  3349. }
  3350. ItemPreFrame( );
  3351. WaterMove();
  3352. if ( g_pGameRules && g_pGameRules->FAllowFlashlight() )
  3353. m_Local.m_iHideHUD &= ~HIDEHUD_FLASHLIGHT;
  3354. else
  3355. m_Local.m_iHideHUD |= HIDEHUD_FLASHLIGHT;
  3356. // checks if new client data (for HUD and view control) needs to be sent to the client
  3357. UpdateClientData();
  3358. CheckTimeBasedDamage();
  3359. CheckSuitUpdate();
  3360. if ( GetObserverMode() > OBS_MODE_FREEZECAM )
  3361. {
  3362. CheckObserverSettings(); // do this each frame
  3363. }
  3364. if ( m_lifeState >= LIFE_DYING )
  3365. {
  3366. // track where we are in the nav mesh even when dead
  3367. UpdateLastKnownArea();
  3368. return;
  3369. }
  3370. HandleFuncTrain();
  3371. if (m_nButtons & IN_JUMP)
  3372. {
  3373. // If on a ladder, jump off the ladder
  3374. // else Jump
  3375. Jump();
  3376. }
  3377. // If trying to duck, already ducked, or in the process of ducking
  3378. if ((m_nButtons & IN_DUCK) || (GetFlags() & FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING) )
  3379. Duck();
  3380. //
  3381. // If we're not on the ground, we're falling. Update our falling velocity.
  3382. //
  3383. if ( !( GetFlags() & FL_ONGROUND ) )
  3384. {
  3385. m_Local.m_flFallVelocity = -GetAbsVelocity().z;
  3386. }
  3387. if ( GetGroundEntity() )
  3388. {
  3389. m_flTimeLastTouchedGround = gpGlobals->curtime;
  3390. }
  3391. {
  3392. m_flTimeLastTouchedGround = gpGlobals->curtime;
  3393. }
  3394. // track where we are in the nav mesh
  3395. UpdateLastKnownArea();
  3396. // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating?
  3397. }
  3398. /* Time based Damage works as follows:
  3399. 1) There are several types of timebased damage:
  3400. #define DMG_PARALYZE (1 << 14) // slows affected creature down
  3401. #define DMG_NERVEGAS (1 << 15) // nerve toxins, very bad
  3402. #define DMG_POISON (1 << 16) // blood poisioning
  3403. #define DMG_RADIATION (1 << 17) // radiation exposure
  3404. #define DMG_DROWNRECOVER (1 << 18) // drown recovery
  3405. #define DMG_ACID (1 << 19) // toxic chemicals or acid burns
  3406. #define DMG_SLOWBURN (1 << 20) // in an oven
  3407. 2) A new hit inflicting tbd restarts the tbd counter - each NPC has an 8bit counter,
  3408. per damage type. The counter is decremented every second, so the maximum time
  3409. an effect will last is 255/60 = 4.25 minutes. Of course, staying within the radius
  3410. of a damaging effect like fire, nervegas, radiation will continually reset the counter to max.
  3411. 3) Every second that a tbd counter is running, the player takes damage. The damage
  3412. is determined by the type of tdb.
  3413. Paralyze - 1/2 movement rate, 30 second duration.
  3414. Nervegas - 5 points per second, 16 second duration = 80 points max dose.
  3415. Poison - 2 points per second, 25 second duration = 50 points max dose.
  3416. Radiation - 1 point per second, 50 second duration = 50 points max dose.
  3417. Drown - 5 points per second, 2 second duration.
  3418. Acid/Chemical - 5 points per second, 10 second duration = 50 points max.
  3419. Burn - 10 points per second, 2 second duration.
  3420. Freeze - 3 points per second, 10 second duration = 30 points max.
  3421. 4) Certain actions or countermeasures counteract the damaging effects of tbds:
  3422. Armor/Heater/Cooler - Chemical(acid),burn, freeze all do damage to armor power, then to body
  3423. - recharged by suit recharger
  3424. Air In Lungs - drowning damage is done to air in lungs first, then to body
  3425. - recharged by poking head out of water
  3426. - 10 seconds if swiming fast
  3427. Air In SCUBA - drowning damage is done to air in tanks first, then to body
  3428. - 2 minutes in tanks. Need new tank once empty.
  3429. Radiation Syringe - Each syringe full provides protection vs one radiation dosage
  3430. Antitoxin Syringe - Each syringe full provides protection vs one poisoning (nervegas or poison).
  3431. Health kit - Immediate stop to acid/chemical, fire or freeze damage.
  3432. Radiation Shower - Immediate stop to radiation damage, acid/chemical or fire damage.
  3433. */
  3434. // If player is taking time based damage, continue doing damage to player -
  3435. // this simulates the effect of being poisoned, gassed, dosed with radiation etc -
  3436. // anything that continues to do damage even after the initial contact stops.
  3437. // Update all time based damage counters, and shut off any that are done.
  3438. // The m_bitsDamageType bit MUST be set if any damage is to be taken.
  3439. // This routine will detect the initial on value of the m_bitsDamageType
  3440. // and init the appropriate counter. Only processes damage every second.
  3441. //#define PARALYZE_DURATION 30 // number of 2 second intervals to take damage
  3442. //#define PARALYZE_DAMAGE 0.0 // damage to take each 2 second interval
  3443. //#define NERVEGAS_DURATION 16
  3444. //#define NERVEGAS_DAMAGE 5.0
  3445. //#define POISON_DURATION 25
  3446. //#define POISON_DAMAGE 2.0
  3447. //#define RADIATION_DURATION 50
  3448. //#define RADIATION_DAMAGE 1.0
  3449. //#define ACID_DURATION 10
  3450. //#define ACID_DAMAGE 5.0
  3451. //#define SLOWBURN_DURATION 2
  3452. //#define SLOWBURN_DAMAGE 1.0
  3453. //#define SLOWFREEZE_DURATION 1.0
  3454. //#define SLOWFREEZE_DAMAGE 3.0
  3455. /* */
  3456. void CBasePlayer::CheckTimeBasedDamage()
  3457. {
  3458. int i;
  3459. byte bDuration = 0;
  3460. static float gtbdPrev = 0.0;
  3461. // If we don't have any time based damage return.
  3462. if ( !g_pGameRules->Damage_IsTimeBased( m_bitsDamageType ) )
  3463. return;
  3464. // only check for time based damage approx. every 2 seconds
  3465. if ( abs( gpGlobals->curtime - m_tbdPrev ) < 2.0 )
  3466. return;
  3467. m_tbdPrev = gpGlobals->curtime;
  3468. for (i = 0; i < CDMG_TIMEBASED; i++)
  3469. {
  3470. // Make sure the damage type is really time-based.
  3471. // This is kind of hacky but necessary until we setup DamageType as an enum.
  3472. int iDamage = ( DMG_PARALYZE << i );
  3473. if ( !g_pGameRules->Damage_IsTimeBased( iDamage ) )
  3474. continue;
  3475. // make sure bit is set for damage type
  3476. if ( m_bitsDamageType & iDamage )
  3477. {
  3478. switch (i)
  3479. {
  3480. case itbd_Paralyze:
  3481. // UNDONE - flag movement as half-speed
  3482. bDuration = PARALYZE_DURATION;
  3483. break;
  3484. case itbd_NerveGas:
  3485. // OnTakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC);
  3486. bDuration = NERVEGAS_DURATION;
  3487. break;
  3488. // case itbd_Poison:
  3489. // OnTakeDamage( CTakeDamageInfo( this, this, POISON_DAMAGE, DMG_GENERIC ) );
  3490. // bDuration = POISON_DURATION;
  3491. // break;
  3492. case itbd_Radiation:
  3493. // OnTakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC);
  3494. bDuration = RADIATION_DURATION;
  3495. break;
  3496. case itbd_DrownRecover:
  3497. // NOTE: this hack is actually used to RESTORE health
  3498. // after the player has been drowning and finally takes a breath
  3499. if (m_idrowndmg > m_idrownrestored)
  3500. {
  3501. int idif = MIN(m_idrowndmg - m_idrownrestored, 10);
  3502. TakeHealth(idif, DMG_GENERIC);
  3503. m_idrownrestored += idif;
  3504. }
  3505. bDuration = 4; // get up to 5*10 = 50 points back
  3506. break;
  3507. case itbd_PoisonRecover:
  3508. {
  3509. // NOTE: this hack is actually used to RESTORE health
  3510. // after the player has been poisoned.
  3511. if (m_nPoisonDmg > m_nPoisonRestored)
  3512. {
  3513. int nDif = MIN(m_nPoisonDmg - m_nPoisonRestored, 10);
  3514. TakeHealth(nDif, DMG_GENERIC);
  3515. m_nPoisonRestored += nDif;
  3516. }
  3517. bDuration = 9; // get up to 10*10 = 100 points back
  3518. break;
  3519. }
  3520. case itbd_Acid:
  3521. // OnTakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC);
  3522. bDuration = ACID_DURATION;
  3523. break;
  3524. case itbd_SlowBurn:
  3525. // OnTakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC);
  3526. bDuration = SLOWBURN_DURATION;
  3527. break;
  3528. case itbd_SlowFreeze:
  3529. // OnTakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC);
  3530. bDuration = SLOWFREEZE_DURATION;
  3531. break;
  3532. default:
  3533. bDuration = 0;
  3534. }
  3535. if (m_rgbTimeBasedDamage[i])
  3536. {
  3537. // decrement damage duration, detect when done.
  3538. if (!m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0)
  3539. {
  3540. m_rgbTimeBasedDamage[i] = 0;
  3541. // if we're done, clear damage bits
  3542. m_bitsDamageType &= ~(DMG_PARALYZE << i);
  3543. }
  3544. }
  3545. else
  3546. // first time taking this damage type - init damage duration
  3547. m_rgbTimeBasedDamage[i] = bDuration;
  3548. }
  3549. }
  3550. }
  3551. /*
  3552. THE POWER SUIT
  3553. The Suit provides 3 main functions: Protection, Notification and Augmentation.
  3554. Some functions are automatic, some require power.
  3555. The player gets the suit shortly after getting off the train in C1A0 and it stays
  3556. with him for the entire game.
  3557. Protection
  3558. Heat/Cold
  3559. When the player enters a hot/cold area, the heating/cooling indicator on the suit
  3560. will come on and the battery will drain while the player stays in the area.
  3561. After the battery is dead, the player starts to take damage.
  3562. This feature is built into the suit and is automatically engaged.
  3563. Radiation Syringe
  3564. This will cause the player to be immune from the effects of radiation for N seconds. Single use item.
  3565. Anti-Toxin Syringe
  3566. This will cure the player from being poisoned. Single use item.
  3567. Health
  3568. Small (1st aid kits, food, etc.)
  3569. Large (boxes on walls)
  3570. Armor
  3571. The armor works using energy to create a protective field that deflects a
  3572. percentage of damage projectile and explosive attacks. After the armor has been deployed,
  3573. it will attempt to recharge itself to full capacity with the energy reserves from the battery.
  3574. It takes the armor N seconds to fully charge.
  3575. Notification (via the HUD)
  3576. x Health
  3577. x Ammo
  3578. x Automatic Health Care
  3579. Notifies the player when automatic healing has been engaged.
  3580. x Geiger counter
  3581. Classic Geiger counter sound and status bar at top of HUD
  3582. alerts player to dangerous levels of radiation. This is not visible when radiation levels are normal.
  3583. x Poison
  3584. Armor
  3585. Displays the current level of armor.
  3586. Augmentation
  3587. Reanimation (w/adrenaline)
  3588. Causes the player to come back to life after he has been dead for 3 seconds.
  3589. Will not work if player was gibbed. Single use.
  3590. Long Jump
  3591. Used by hitting the ??? key(s). Caused the player to further than normal.
  3592. SCUBA
  3593. Used automatically after picked up and after player enters the water.
  3594. Works for N seconds. Single use.
  3595. Things powered by the battery
  3596. Armor
  3597. Uses N watts for every M units of damage.
  3598. Heat/Cool
  3599. Uses N watts for every second in hot/cold area.
  3600. Long Jump
  3601. Uses N watts for every jump.
  3602. Alien Cloak
  3603. Uses N watts for each use. Each use lasts M seconds.
  3604. Alien Shield
  3605. Augments armor. Reduces Armor drain by one half
  3606. */
  3607. // if in range of radiation source, ping geiger counter
  3608. #define GEIGERDELAY 0.25
  3609. void CBasePlayer::UpdateGeigerCounter( void )
  3610. {
  3611. byte range;
  3612. // delay per update ie: don't flood net with these msgs
  3613. if (gpGlobals->curtime < m_flgeigerDelay)
  3614. return;
  3615. m_flgeigerDelay = gpGlobals->curtime + GEIGERDELAY;
  3616. // send range to radition source to client
  3617. range = (byte) clamp(m_flgeigerRange / 4, 0, 255);
  3618. // This is to make sure you aren't driven crazy by geiger while in the airboat
  3619. if ( IsInAVehicle() )
  3620. {
  3621. range = clamp( (int)range * 4, 0, 255 );
  3622. }
  3623. if (range != m_igeigerRangePrev)
  3624. {
  3625. m_igeigerRangePrev = range;
  3626. CSingleUserRecipientFilter user( this );
  3627. user.MakeReliable();
  3628. CCSUsrMsg_Geiger msg;
  3629. msg.set_range( range );
  3630. SendUserMessage( user, CS_UM_Geiger, msg );
  3631. }
  3632. // reset counter and semaphore
  3633. if (!random->RandomInt(0,3))
  3634. {
  3635. m_flgeigerRange = 1000;
  3636. }
  3637. }
  3638. /*
  3639. ================
  3640. CheckSuitUpdate
  3641. Play suit update if it's time
  3642. ================
  3643. */
  3644. #define SUITUPDATETIME 3.5
  3645. #define SUITFIRSTUPDATETIME 0.1
  3646. void CBasePlayer::CheckSuitUpdate()
  3647. {
  3648. int i;
  3649. int isentence = 0;
  3650. int isearch = m_iSuitPlayNext;
  3651. // Ignore suit updates if no suit
  3652. if ( !IsSuitEquipped() )
  3653. return;
  3654. // if in range of radiation source, ping geiger counter
  3655. UpdateGeigerCounter();
  3656. if ( g_pGameRules->IsMultiplayer() )
  3657. {
  3658. // don't bother updating HEV voice in multiplayer.
  3659. return;
  3660. }
  3661. if ( gpGlobals->curtime >= m_flSuitUpdate && m_flSuitUpdate > 0)
  3662. {
  3663. // play a sentence off of the end of the queue
  3664. for (i = 0; i < CSUITPLAYLIST; i++)
  3665. {
  3666. if ((isentence = m_rgSuitPlayList[isearch]) != 0)
  3667. break;
  3668. if (++isearch == CSUITPLAYLIST)
  3669. isearch = 0;
  3670. }
  3671. if (isentence)
  3672. {
  3673. m_rgSuitPlayList[isearch] = 0;
  3674. if (isentence > 0)
  3675. {
  3676. // play sentence number
  3677. char sentence[512];
  3678. Q_snprintf( sentence, sizeof( sentence ), "!%s", engine->SentenceNameFromIndex( isentence ) );
  3679. UTIL_EmitSoundSuit( edict(), sentence );
  3680. }
  3681. else
  3682. {
  3683. // play sentence group
  3684. UTIL_EmitGroupIDSuit(edict(), -isentence);
  3685. }
  3686. m_flSuitUpdate = gpGlobals->curtime + SUITUPDATETIME;
  3687. }
  3688. else
  3689. // queue is empty, don't check
  3690. m_flSuitUpdate = 0;
  3691. }
  3692. }
  3693. // add sentence to suit playlist queue. if fgroup is true, then
  3694. // name is a sentence group (HEV_AA), otherwise name is a specific
  3695. // sentence name ie: !HEV_AA0. If iNoRepeat is specified in
  3696. // seconds, then we won't repeat playback of this word or sentence
  3697. // for at least that number of seconds.
  3698. void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime)
  3699. {
  3700. int i;
  3701. int isentence;
  3702. int iempty = -1;
  3703. // Ignore suit updates if no suit
  3704. if ( !IsSuitEquipped() )
  3705. return;
  3706. if ( g_pGameRules->IsMultiplayer() )
  3707. {
  3708. // due to static channel design, etc. We don't play HEV sounds in multiplayer right now.
  3709. return;
  3710. }
  3711. // if name == NULL, then clear out the queue
  3712. if (!name)
  3713. {
  3714. for (i = 0; i < CSUITPLAYLIST; i++)
  3715. m_rgSuitPlayList[i] = 0;
  3716. return;
  3717. }
  3718. // get sentence or group number
  3719. if (!fgroup)
  3720. {
  3721. isentence = SENTENCEG_Lookup(name); // Lookup sentence index (not group) by name
  3722. if (isentence < 0)
  3723. return;
  3724. }
  3725. else
  3726. // mark group number as negative
  3727. isentence = -SENTENCEG_GetIndex(name); // Lookup group index by name
  3728. // check norepeat list - this list lets us cancel
  3729. // the playback of words or sentences that have already
  3730. // been played within a certain time.
  3731. for (i = 0; i < CSUITNOREPEAT; i++)
  3732. {
  3733. if (isentence == m_rgiSuitNoRepeat[i])
  3734. {
  3735. // this sentence or group is already in
  3736. // the norepeat list
  3737. if (m_rgflSuitNoRepeatTime[i] < gpGlobals->curtime)
  3738. {
  3739. // norepeat time has expired, clear it out
  3740. m_rgiSuitNoRepeat[i] = 0;
  3741. m_rgflSuitNoRepeatTime[i] = 0.0;
  3742. iempty = i;
  3743. break;
  3744. }
  3745. else
  3746. {
  3747. // don't play, still marked as norepeat
  3748. return;
  3749. }
  3750. }
  3751. // keep track of empty slot
  3752. if (!m_rgiSuitNoRepeat[i])
  3753. iempty = i;
  3754. }
  3755. // sentence is not in norepeat list, save if norepeat time was given
  3756. if (iNoRepeatTime)
  3757. {
  3758. if (iempty < 0)
  3759. iempty = random->RandomInt(0, CSUITNOREPEAT-1); // pick random slot to take over
  3760. m_rgiSuitNoRepeat[iempty] = isentence;
  3761. m_rgflSuitNoRepeatTime[iempty] = iNoRepeatTime + gpGlobals->curtime;
  3762. }
  3763. // find empty spot in queue, or overwrite last spot
  3764. m_rgSuitPlayList[m_iSuitPlayNext++] = isentence;
  3765. if (m_iSuitPlayNext == CSUITPLAYLIST)
  3766. m_iSuitPlayNext = 0;
  3767. if (m_flSuitUpdate <= gpGlobals->curtime)
  3768. {
  3769. if (m_flSuitUpdate == 0)
  3770. // play queue is empty, don't delay too long before playback
  3771. m_flSuitUpdate = gpGlobals->curtime + SUITFIRSTUPDATETIME;
  3772. else
  3773. m_flSuitUpdate = gpGlobals->curtime + SUITUPDATETIME;
  3774. }
  3775. }
  3776. //=========================================================
  3777. // UpdatePlayerSound - updates the position of the player's
  3778. // reserved sound slot in the sound list.
  3779. //=========================================================
  3780. void CBasePlayer::UpdatePlayerSound ( void )
  3781. {
  3782. int iBodyVolume;
  3783. int iVolume;
  3784. CSound *pSound;
  3785. pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( edict() ) );
  3786. if ( !pSound )
  3787. {
  3788. Msg( "Client lost reserved sound!\n" );
  3789. return;
  3790. }
  3791. if (GetFlags() & FL_NOTARGET)
  3792. {
  3793. pSound->m_iVolume = 0;
  3794. return;
  3795. }
  3796. // now figure out how loud the player's movement is.
  3797. if ( GetFlags() & FL_ONGROUND )
  3798. {
  3799. iBodyVolume = GetAbsVelocity().Length();
  3800. // clamp the noise that can be made by the body, in case a push trigger,
  3801. // weapon recoil, or anything shoves the player abnormally fast.
  3802. // NOTE: 512 units is a pretty large radius for a sound made by the player's body.
  3803. // then again, I think some materials are pretty loud.
  3804. if ( iBodyVolume > 512 )
  3805. {
  3806. iBodyVolume = 512;
  3807. }
  3808. }
  3809. else
  3810. {
  3811. iBodyVolume = 0;
  3812. }
  3813. if ( m_nButtons & IN_JUMP )
  3814. {
  3815. // Jumping is a little louder.
  3816. iBodyVolume += 100;
  3817. }
  3818. m_iTargetVolume = iBodyVolume;
  3819. // if target volume is greater than the player sound's current volume, we paste the new volume in
  3820. // immediately. If target is less than the current volume, current volume is not set immediately to the
  3821. // lower volume, rather works itself towards target volume over time. This gives NPCs a much better chance
  3822. // to hear a sound, especially if they don't listen every frame.
  3823. iVolume = pSound->Volume();
  3824. if ( m_iTargetVolume > iVolume )
  3825. {
  3826. iVolume = m_iTargetVolume;
  3827. }
  3828. else if ( iVolume > m_iTargetVolume )
  3829. {
  3830. iVolume -= 250 * gpGlobals->frametime;
  3831. if ( iVolume < m_iTargetVolume )
  3832. {
  3833. iVolume = 0;
  3834. }
  3835. }
  3836. if ( pSound )
  3837. {
  3838. pSound->SetSoundOrigin( GetAbsOrigin() );
  3839. pSound->m_iType = SOUND_PLAYER;
  3840. pSound->m_iVolume = iVolume;
  3841. }
  3842. // Below are a couple of useful little bits that make it easier to visualize just how much noise the
  3843. // player is making.
  3844. //Vector forward = UTIL_YawToVector( pl.v_angle.y );
  3845. //UTIL_Sparks( GetAbsOrigin() + forward * iVolume );
  3846. //Msg( "%d/%d\n", iVolume, m_iTargetVolume );
  3847. }
  3848. // This is a glorious hack to find free space when you've crouched into some solid space
  3849. // Our crouching collisions do not work correctly for some reason and this is easier
  3850. // than fixing the problem :(
  3851. void FixPlayerCrouchStuck( CBasePlayer *pPlayer )
  3852. {
  3853. trace_t trace;
  3854. // Move up as many as 18 pixels if the player is stuck.
  3855. int i;
  3856. Vector org = pPlayer->GetAbsOrigin();;
  3857. for ( i = 0; i < 18; i++ )
  3858. {
  3859. UTIL_TraceHull( pPlayer->GetAbsOrigin(), pPlayer->GetAbsOrigin(),
  3860. VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  3861. if ( trace.startsolid )
  3862. {
  3863. Vector origin = pPlayer->GetAbsOrigin();
  3864. origin.z += 1.0f;
  3865. pPlayer->SetLocalOrigin( origin );
  3866. }
  3867. else
  3868. return;
  3869. }
  3870. pPlayer->SetAbsOrigin( org );
  3871. for ( i = 0; i < 18; i++ )
  3872. {
  3873. UTIL_TraceHull( pPlayer->GetAbsOrigin(), pPlayer->GetAbsOrigin(),
  3874. VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  3875. if ( trace.startsolid )
  3876. {
  3877. Vector origin = pPlayer->GetAbsOrigin();
  3878. origin.z -= 1.0f;
  3879. pPlayer->SetLocalOrigin( origin );
  3880. }
  3881. else
  3882. return;
  3883. }
  3884. }
  3885. #define SMOOTHING_FACTOR 0.9
  3886. extern CMoveData *g_pMoveData;
  3887. //-----------------------------------------------------------------------------
  3888. // For debugging...
  3889. //-----------------------------------------------------------------------------
  3890. void CBasePlayer::ForceOrigin( const Vector &vecOrigin )
  3891. {
  3892. m_bForceOrigin = true;
  3893. m_vForcedOrigin = vecOrigin;
  3894. }
  3895. //--------------------------------------------------------------------------------------------------------
  3896. void CBasePlayer::OnTonemapTriggerStartTouch( CTonemapTrigger *pTonemapTrigger )
  3897. {
  3898. m_hTriggerTonemapList.FindAndRemove( pTonemapTrigger );
  3899. m_hTriggerTonemapList.AddToTail( pTonemapTrigger );
  3900. }
  3901. //--------------------------------------------------------------------------------------------------------
  3902. void CBasePlayer::OnTonemapTriggerEndTouch( CTonemapTrigger *pTonemapTrigger )
  3903. {
  3904. m_hTriggerTonemapList.FindAndRemove( pTonemapTrigger );
  3905. }
  3906. //--------------------------------------------------------------------------------------------------------
  3907. void CBasePlayer::UpdateTonemapController( void )
  3908. {
  3909. m_hTonemapController = TheTonemapSystem()->GetMasterTonemapController();
  3910. }
  3911. //-----------------------------------------------------------------------------
  3912. // Purpose:
  3913. //-----------------------------------------------------------------------------
  3914. void CBasePlayer::PostThink()
  3915. {
  3916. VPROF( "CBasePlayer::PostThink" );
  3917. m_vecSmoothedVelocity = m_vecSmoothedVelocity * SMOOTHING_FACTOR + GetAbsVelocity() * ( 1 - SMOOTHING_FACTOR );
  3918. UpdateTonemapController();
  3919. UpdateFXVolume();
  3920. if ( !g_fGameOver && !m_iPlayerLocked )
  3921. {
  3922. if ( IsAlive() )
  3923. {
  3924. // set correct collision bounds (may have changed in player movement code)
  3925. VPROF_SCOPE_BEGIN( "CBasePlayer::PostThink-Bounds" );
  3926. UpdateCollisionBounds();
  3927. VPROF_SCOPE_END();
  3928. VPROF_SCOPE_BEGIN( "CBasePlayer::PostThink-Use" );
  3929. // Handle controlling an entity
  3930. if ( m_hUseEntity != NULL )
  3931. {
  3932. // if they've moved too far from the gun, or deployed another weapon, unuse the gun
  3933. if ( m_hUseEntity->OnControls( this ) &&
  3934. ( !GetActiveWeapon() || GetActiveWeapon()->IsEffectActive( EF_NODRAW ) ||
  3935. ( GetActiveWeapon()->GetActivity() == ACT_VM_HOLSTER )
  3936. #ifdef PORTAL // Portalgun view model stays up when holding an object -Jeep
  3937. || FClassnameIs( GetActiveWeapon(), "weapon_portalgun" )
  3938. #endif //#ifdef PORTAL
  3939. ) )
  3940. {
  3941. #if defined ( PORTAL2 )
  3942. CPlayerPickupController *pPickup = (CPlayerPickupController*)m_hUseEntity.Get();
  3943. Assert( pPickup );
  3944. if ( pPickup )
  3945. {
  3946. pPickup->UsePickupController( this, this, USE_SET, 2 ); // try fire the gun
  3947. }
  3948. #else
  3949. m_hUseEntity->Use( this, this, USE_SET, 2 ); // try fire the gun
  3950. #endif
  3951. }
  3952. else
  3953. {
  3954. // they've moved off the controls
  3955. ClearUseEntity();
  3956. }
  3957. }
  3958. VPROF_SCOPE_END();
  3959. // do weapon stuff
  3960. VPROF_SCOPE_BEGIN( "CBasePlayer::PostThink-ItemPostFrame" );
  3961. ItemPostFrame();
  3962. VPROF_SCOPE_END();
  3963. if ( GetFlags() & FL_ONGROUND )
  3964. {
  3965. if (m_Local.m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer() && gpGlobals->frametime > 0 )
  3966. {
  3967. CSoundEnt::InsertSound ( SOUND_PLAYER, GetAbsOrigin(), m_Local.m_flFallVelocity, 0.2, this );
  3968. // Msg( "fall %f\n", m_Local.m_flFallVelocity );
  3969. }
  3970. m_Local.m_flFallVelocity = 0;
  3971. }
  3972. // select the proper animation for the player character
  3973. VPROF( "CBasePlayer::PostThink-Animation" );
  3974. // If he's in a vehicle, sit down
  3975. if ( IsInAVehicle() )
  3976. SetAnimation( PLAYER_IN_VEHICLE );
  3977. // why is player animation being overridden here in post think? This should be taken care of in player animstate update?
  3978. //else if (!GetAbsVelocity().x && !GetAbsVelocity().y)
  3979. // SetAnimation( PLAYER_IDLE );
  3980. //else if ((GetAbsVelocity().x || GetAbsVelocity().y) && ( GetFlags() & FL_ONGROUND ))
  3981. // SetAnimation( PLAYER_WALK );
  3982. //else if (GetWaterLevel() > WL_Feet)
  3983. // SetAnimation( PLAYER_WALK );
  3984. }
  3985. else
  3986. {
  3987. ClearImpulse(); // Don't hang onto an old 'spray' etc until the next spawn...
  3988. }
  3989. // Don't allow bogus sequence on player
  3990. if ( GetSequence() == -1 )
  3991. {
  3992. SetSequence( 0 );
  3993. }
  3994. // why is player animation being overridden here in post think? This should be taken care of in player animstate update?
  3995. //VPROF_SCOPE_BEGIN( "CBasePlayer::PostThink-StudioFrameAdvance" );
  3996. //StudioFrameAdvance();
  3997. //VPROF_SCOPE_END();
  3998. VPROF_SCOPE_BEGIN( "CBasePlayer::PostThink-DispatchAnimEvents" );
  3999. DispatchAnimEvents( this );
  4000. VPROF_SCOPE_END();
  4001. SetSimulationTime( gpGlobals->curtime );
  4002. //Let the weapon update as well
  4003. VPROF_SCOPE_BEGIN( "CBasePlayer::PostThink-Weapon_FrameUpdate" );
  4004. Weapon_FrameUpdate();
  4005. VPROF_SCOPE_END();
  4006. VPROF_SCOPE_BEGIN( "CBasePlayer::PostThink-UpdatePlayerSound" );
  4007. UpdatePlayerSound();
  4008. VPROF_SCOPE_END();
  4009. if ( m_bForceOrigin )
  4010. {
  4011. SetLocalOrigin( m_vForcedOrigin );
  4012. SetLocalAngles( m_Local.m_viewPunchAngle );
  4013. m_Local.m_viewPunchAngle = RandomAngle( -25, 25 );
  4014. }
  4015. VPROF_SCOPE_BEGIN( "CBasePlayer::PostThink-PostThinkVPhysics" );
  4016. PostThinkVPhysics();
  4017. VPROF_SCOPE_END();
  4018. }
  4019. else
  4020. {
  4021. // DDK: for g_fGameOver, this fixes a case where the player would never complete an active weapon animation
  4022. // this was because in this case we weren't updating the items and handling animaion completion flags
  4023. VPROF_SCOPE_BEGIN( "CBasePlayer::PostThink-ItemPostFrame" );
  4024. ItemPostFrame();
  4025. VPROF_SCOPE_END();
  4026. }
  4027. #if !defined( NO_ENTITY_PREDICTION )
  4028. // Even if dead simulate entities
  4029. SimulatePlayerSimulatedEntities();
  4030. #endif
  4031. // Regenerate heath
  4032. if ( IsAlive() && GetHealth() < GetMaxHealth() && (GlobalEntity_GetState("player_regenerates_health") != GLOBAL_OFF) )
  4033. {
  4034. // Color to overlay on the screen while the player is taking damage
  4035. color32 hurtScreenOverlay = {64,0,0,64};
  4036. if ( gpGlobals->curtime > m_fTimeLastHurt + sv_regeneration_wait_time.GetFloat() )
  4037. {
  4038. TakeHealth( 1, DMG_GENERIC );
  4039. }
  4040. else
  4041. {
  4042. UTIL_ScreenFade( this, hurtScreenOverlay, 1.0f, 0.1f, FFADE_IN|FFADE_PURGE );
  4043. }
  4044. }
  4045. }
  4046. // handles touching physics objects
  4047. void CBasePlayer::Touch( CBaseEntity *pOther )
  4048. {
  4049. if ( pOther == GetGroundEntity() )
  4050. return;
  4051. if ( pOther->GetMoveType() != MOVETYPE_VPHYSICS || pOther->GetSolid() != SOLID_VPHYSICS || (pOther->GetSolidFlags() & FSOLID_TRIGGER) )
  4052. return;
  4053. IPhysicsObject *pPhys = pOther->VPhysicsGetObject();
  4054. if ( !pPhys || !pPhys->IsMoveable() )
  4055. return;
  4056. SetTouchedPhysics( true );
  4057. }
  4058. Vector CBasePlayer::GetSmoothedVelocity( void )
  4059. {
  4060. if ( IsInAVehicle() )
  4061. {
  4062. return GetVehicle()->GetVehicleEnt()->GetSmoothedVelocity();
  4063. }
  4064. return m_vecSmoothedVelocity;
  4065. }
  4066. CBaseEntity *g_pLastSpawn = NULL;
  4067. //-----------------------------------------------------------------------------
  4068. // Purpose: Finds a player start entity of the given classname. If any entity of
  4069. // of the given classname has the SF_PLAYER_START_MASTER flag set, that
  4070. // is the entity that will be returned. Otherwise, the first entity of
  4071. // the given classname is returned.
  4072. // Input : pszClassName - should be "info_player_start", "info_player_coop", or
  4073. // "info_player_deathmatch"
  4074. //-----------------------------------------------------------------------------
  4075. CBaseEntity *FindPlayerStart(const char *pszClassName)
  4076. {
  4077. #define SF_PLAYER_START_MASTER 1
  4078. CBaseEntity *pStart = gEntList.FindEntityByClassname(NULL, pszClassName);
  4079. CBaseEntity *pStartFirst = pStart;
  4080. while (pStart != NULL)
  4081. {
  4082. if (pStart->HasSpawnFlags(SF_PLAYER_START_MASTER))
  4083. {
  4084. return pStart;
  4085. }
  4086. pStart = gEntList.FindEntityByClassname(pStart, pszClassName);
  4087. }
  4088. return pStartFirst;
  4089. }
  4090. /*
  4091. ============
  4092. EntSelectSpawnPoint
  4093. Returns the entity to spawn at
  4094. USES AND SETS GLOBAL g_pLastSpawn
  4095. ============
  4096. */
  4097. CBaseEntity *CBasePlayer::EntSelectSpawnPoint()
  4098. {
  4099. CBaseEntity *pSpot;
  4100. edict_t *player;
  4101. player = edict();
  4102. // choose a info_player_deathmatch point
  4103. if (g_pGameRules->IsCoOp())
  4104. {
  4105. pSpot = gEntList.FindEntityByClassname( g_pLastSpawn, "info_player_coop");
  4106. if ( pSpot )
  4107. goto ReturnSpot;
  4108. pSpot = gEntList.FindEntityByClassname( g_pLastSpawn, "info_player_start");
  4109. if ( pSpot )
  4110. goto ReturnSpot;
  4111. }
  4112. else if ( g_pGameRules->IsDeathmatch() )
  4113. {
  4114. pSpot = g_pLastSpawn;
  4115. // Randomize the start spot
  4116. for ( int i = random->RandomInt(1,5); i > 0; i-- )
  4117. pSpot = gEntList.FindEntityByClassname( pSpot, "info_player_deathmatch" );
  4118. if ( !pSpot ) // skip over the null point
  4119. pSpot = gEntList.FindEntityByClassname( pSpot, "info_player_deathmatch" );
  4120. CBaseEntity *pFirstSpot = pSpot;
  4121. do
  4122. {
  4123. if ( pSpot )
  4124. {
  4125. // check if pSpot is valid
  4126. if ( g_pGameRules->IsSpawnPointValid( pSpot, this ) )
  4127. {
  4128. if ( pSpot->GetLocalOrigin() == vec3_origin )
  4129. {
  4130. pSpot = gEntList.FindEntityByClassname( pSpot, "info_player_deathmatch" );
  4131. continue;
  4132. }
  4133. // if so, go to pSpot
  4134. goto ReturnSpot;
  4135. }
  4136. }
  4137. // increment pSpot
  4138. pSpot = gEntList.FindEntityByClassname( pSpot, "info_player_deathmatch" );
  4139. } while ( pSpot != pFirstSpot ); // loop if we're not back to the start
  4140. // we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
  4141. if ( pSpot )
  4142. {
  4143. CBaseEntity *ent = NULL;
  4144. for ( CEntitySphereQuery sphere( pSpot->GetAbsOrigin(), 128 ); (ent = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() )
  4145. {
  4146. // if ent is a client, kill em (unless they are ourselves)
  4147. if ( ent->IsPlayer() && !(ent->edict() == player) )
  4148. ent->TakeDamage( CTakeDamageInfo( GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), 300, DMG_GENERIC ) );
  4149. }
  4150. goto ReturnSpot;
  4151. }
  4152. }
  4153. // If startspot is set, (re)spawn there.
  4154. if ( !gpGlobals->startspot || !strlen(STRING(gpGlobals->startspot)))
  4155. {
  4156. pSpot = FindPlayerStart( "info_player_start" );
  4157. if ( pSpot )
  4158. goto ReturnSpot;
  4159. }
  4160. else
  4161. {
  4162. pSpot = gEntList.FindEntityByName( NULL, gpGlobals->startspot );
  4163. if ( pSpot )
  4164. goto ReturnSpot;
  4165. }
  4166. ReturnSpot:
  4167. if ( !pSpot )
  4168. {
  4169. Warning( "PutClientInServer: no info_player_start on level\n");
  4170. return CBaseEntity::Instance( INDEXENT( 0 ) );
  4171. }
  4172. g_pLastSpawn = pSpot;
  4173. return pSpot;
  4174. }
  4175. //-----------------------------------------------------------------------------
  4176. // Purpose: Called the first time the player's created
  4177. //-----------------------------------------------------------------------------
  4178. void CBasePlayer::InitialSpawn( void )
  4179. {
  4180. m_iConnected = PlayerConnected;
  4181. m_flInitialSpawnTime = gpGlobals->curtime;
  4182. #if !defined( _GAMECONSOLE ) || defined ( CSTRIKE15 )
  4183. gamestats->Event_PlayerConnected( this );
  4184. #endif
  4185. }
  4186. //-----------------------------------------------------------------------------
  4187. // Purpose: Called directly after we select a spawn point and teleport to it
  4188. //-----------------------------------------------------------------------------
  4189. void CBasePlayer::PostSpawnPointSelection( )
  4190. {
  4191. // [dkorus] do nothing in base version
  4192. }
  4193. //-----------------------------------------------------------------------------
  4194. // Purpose: Called everytime the player respawns
  4195. //-----------------------------------------------------------------------------
  4196. void CBasePlayer::Spawn( void )
  4197. {
  4198. VPROF( "CBasePlayer::Spawn" );
  4199. // Needs to be done before weapons are given
  4200. if ( Hints() )
  4201. {
  4202. Hints()->ResetHints();
  4203. }
  4204. SetClassname( "player" );
  4205. // Shared spawning code..
  4206. SharedSpawn();
  4207. SetSimulatedEveryTick( true );
  4208. SetAnimatedEveryTick( true );
  4209. m_ArmorValue = SpawnArmorValue();
  4210. SetBlocksLOS( false );
  4211. m_iMaxHealth = m_iHealth;
  4212. // Clear all flags except for FL_FULLEDICT
  4213. if ( GetFlags() & FL_FAKECLIENT )
  4214. {
  4215. ClearFlags();
  4216. AddFlag( FL_CLIENT | FL_FAKECLIENT );
  4217. }
  4218. else
  4219. {
  4220. ClearFlags();
  4221. AddFlag( FL_CLIENT );
  4222. }
  4223. AddFlag( FL_AIMTARGET );
  4224. m_AirFinished = gpGlobals->curtime + AIRTIME;
  4225. m_nDrownDmgRate = DROWNING_DAMAGE_INITIAL;
  4226. // only preserve the shadow flag
  4227. int effects = GetEffects() & EF_NOSHADOW;
  4228. SetEffects( effects | EF_NOINTERP );
  4229. m_bClientSideRagdoll = false;
  4230. // Initialize the fog and postprocess controllers.
  4231. UpdateMapEntityPointers();
  4232. m_DmgTake = 0;
  4233. m_DmgSave = 0;
  4234. m_bitsHUDDamage = -1;
  4235. m_bitsDamageType = 0;
  4236. m_afPhysicsFlags = 0;
  4237. m_idrownrestored = m_idrowndmg;
  4238. SetFOV( this, 0 );
  4239. AllowImmediateDecalPainting(); // sprays are rate-limited regardless of rounds/respawns
  4240. m_flgeigerDelay = gpGlobals->curtime + 2.0; // wait a few seconds until user-defined message registrations
  4241. // are recieved by all clients
  4242. m_flFieldOfView = 0.766;// some NPCs use this to determine whether or not the player is looking at them.
  4243. m_vecAdditionalPVSOrigin = vec3_origin;
  4244. m_vecCameraPVSOrigin = vec3_origin;
  4245. m_bIsSpecLerping = false;
  4246. if ( !m_fGameHUDInitialized )
  4247. g_pGameRules->SetDefaultPlayerTeam( this );
  4248. g_pGameRules->GetPlayerSpawnSpot( this );
  4249. // dkorus: Allow functions to run post-spawn
  4250. // for cstrike characters, this sets the position/rotation on controlled bots
  4251. PostSpawnPointSelection();
  4252. m_bDuckEnabled = true;
  4253. m_bDropEnabled = true;
  4254. m_Local.m_bDucked = false;// This will persist over round restart if you hold duck otherwise.
  4255. m_Local.m_bDucking = false;
  4256. SetViewOffset( VEC_VIEW );
  4257. VPROF_SCOPE_BEGIN( "precache" );
  4258. if ( IsPrecacheAllowed() )
  4259. {
  4260. Precache();
  4261. }
  4262. VPROF_SCOPE_END();
  4263. // Moved Spawn-related code from Precache into Spawn.
  4264. // in the event that the player JUST spawned, and the level node graph
  4265. // was loaded, fix all of the node graph pointers before the game starts.
  4266. m_bitsDamageType = 0;
  4267. m_bitsHUDDamage = -1;
  4268. SetPlayerUnderwater( false );
  4269. m_iTrain = TRAIN_NEW;
  4270. m_HackedGunPos = Vector( 0, 32, 0 );
  4271. m_iBonusChallenge = sv_bonus_challenge.GetInt();
  4272. if ( m_iPlayerSound == SOUNDLIST_EMPTY )
  4273. {
  4274. Msg( "Couldn't alloc player sound slot!\n" );
  4275. }
  4276. SetThink(NULL);
  4277. m_fInitHUD = true;
  4278. m_fWeapon = false;
  4279. m_iClientBattery = -1;
  4280. Q_strncpy( m_szLastPlaceName.GetForModify(), "", MAX_PLACE_NAME_LENGTH );
  4281. m_nTicksSinceLastPlaceUpdate = random->RandomInt( 0, 30 ); // start it off with a random value so players don't update their last place on the same tick every time
  4282. CSingleUserRecipientFilter user( this );
  4283. enginesound->SetPlayerDSP( user, 0, false );
  4284. CreateViewModel();
  4285. SetCollisionGroup( COLLISION_GROUP_PLAYER );
  4286. // if the player is locked, make sure he stays locked
  4287. if ( m_iPlayerLocked )
  4288. {
  4289. m_iPlayerLocked = false;
  4290. LockPlayerInPlace();
  4291. }
  4292. if ( GetTeamNumber() != TEAM_SPECTATOR )
  4293. {
  4294. StopObserverMode();
  4295. }
  4296. else
  4297. {
  4298. StartObserverMode( m_iObserverLastMode );
  4299. }
  4300. StopReplayMode();
  4301. // Clear any screenfade
  4302. color32 nothing = {0,0,0,255};
  4303. UTIL_ScreenFade( this, nothing, 0, 0, FFADE_IN | FFADE_PURGE );
  4304. VPROF_SCOPE_BEGIN( "PlayerSpawn" );
  4305. g_pGameRules->PlayerSpawn( this );
  4306. VPROF_SCOPE_END();
  4307. m_flLaggedMovementValue = 1.0f;
  4308. m_vecSmoothedVelocity = vec3_origin;
  4309. InitVCollision( GetAbsOrigin(), GetAbsVelocity() );
  4310. EnsureValidSpawnLocation();
  4311. IGameEvent *event = gameeventmanager->CreateEvent( "player_spawn" );
  4312. if ( event )
  4313. {
  4314. event->SetInt("userid", GetUserID() );
  4315. event->SetInt("teamnum", GetTeamNumber() );
  4316. gameeventmanager->FireEvent( event );
  4317. }
  4318. RumbleEffect( RUMBLE_STOP_ALL, 0, RUMBLE_FLAGS_NONE );
  4319. // Calculate this immediately
  4320. m_nVehicleViewSavedFrame = 0;
  4321. m_movementCollisionNormal = Vector( 0, 0, 1 );
  4322. // track where we are in the nav mesh
  4323. UpdateLastKnownArea();
  4324. BaseClass::Spawn();
  4325. // track where we are in the nav mesh
  4326. UpdateLastKnownArea();
  4327. if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM )
  4328. {
  4329. g_pScriptVM->SetValue( "player", GetScriptInstance() );
  4330. }
  4331. m_bKilledByHeadshot = false;
  4332. m_iDeathPostEffect = 0;
  4333. m_flDuckAmount = 0;
  4334. m_flDuckSpeed = CS_PLAYER_DUCK_SPEED_IDEAL;
  4335. }
  4336. void CBasePlayer::UpdateMapEntityPointers( void )
  4337. {
  4338. // Initialize the fog and postprocess controllers.
  4339. InitFogController();
  4340. InitPostProcessController();
  4341. InitColorCorrectionController();
  4342. }
  4343. void CBasePlayer::Activate( void )
  4344. {
  4345. BaseClass::Activate();
  4346. AimTarget_ForceRepopulateList();
  4347. RumbleEffect( RUMBLE_STOP_ALL, 0, RUMBLE_FLAGS_NONE );
  4348. // Reset the analog bias. If the player is in a vehicle when the game
  4349. // reloads, it will autosense and apply the correct bias.
  4350. m_iVehicleAnalogBias = VEHICLE_ANALOG_BIAS_NONE;
  4351. }
  4352. void CBasePlayer::Precache( void )
  4353. {
  4354. VPROF( "CBasePlayer::Precache" );
  4355. BaseClass::Precache();
  4356. #ifndef DOTA_DLL
  4357. #if !defined ( PORTAL2 )
  4358. PrecacheScriptSound( "Player.FallGib" );
  4359. PrecacheScriptSound( "Player.Death" );
  4360. #endif
  4361. PrecacheScriptSound( "Player.PlasmaDamage" );
  4362. PrecacheScriptSound( "Player.SonicDamage" );
  4363. PrecacheScriptSound( "Player.DrownStart" );
  4364. PrecacheScriptSound( "Player.DrownContinue" );
  4365. PrecacheScriptSound( "Player.Wade" );
  4366. PrecacheScriptSound( "Player.AmbientUnderWater" );
  4367. enginesound->PrecacheSentenceGroup( "HEV" );
  4368. // These are always needed
  4369. #ifndef TF_DLL
  4370. PrecacheParticleSystem( "slime_splash_01" );
  4371. PrecacheParticleSystem( "slime_splash_02" );
  4372. PrecacheParticleSystem( "slime_splash_03" );
  4373. #endif
  4374. #endif
  4375. // in the event that the player JUST spawned, and the level node graph
  4376. // was loaded, fix all of the node graph pointers before the game starts.
  4377. // !!!BUGBUG - now that we have multiplayer, this needs to be moved!
  4378. /* todo - put in better spot and use new ainetowrk stuff
  4379. if ( WorldGraph.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet )
  4380. {
  4381. if ( !WorldGraph.FSetGraphPointers() )
  4382. {
  4383. Msg( "**Graph pointers were not set!\n");
  4384. }
  4385. else
  4386. {
  4387. Msg( "**Graph Pointers Set!\n" );
  4388. }
  4389. }
  4390. */
  4391. // SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific)
  4392. // because they need to precache before any clients have connected
  4393. // init geiger counter vars during spawn and each time
  4394. // we cross a level transition
  4395. m_flgeigerRange = 1000;
  4396. m_igeigerRangePrev = 1000;
  4397. #if 0
  4398. // @Note (toml 04-19-04): These are saved, used to be slammed here
  4399. m_bitsDamageType = 0;
  4400. m_bitsHUDDamage = -1;
  4401. SetPlayerUnderwter( false );
  4402. m_iTrain = TRAIN_NEW;
  4403. #endif
  4404. m_iClientBattery = -1;
  4405. m_iUpdateTime = 5; // won't update for 1/2 a second
  4406. if ( gInitHUD )
  4407. m_fInitHUD = true;
  4408. }
  4409. //-----------------------------------------------------------------------------
  4410. // Purpose: Force this player to immediately respawn
  4411. //-----------------------------------------------------------------------------
  4412. void CBasePlayer::ForceRespawn( void )
  4413. {
  4414. RemoveAllItems( true );
  4415. // Reset ground state for airwalk animations
  4416. SetGroundEntity( NULL );
  4417. // Stop any firing that was taking place before respawn.
  4418. m_nButtons = 0;
  4419. Spawn();
  4420. }
  4421. int CBasePlayer::Save( ISave &save )
  4422. {
  4423. if ( !BaseClass::Save(save) )
  4424. return 0;
  4425. return 1;
  4426. }
  4427. // Friend class of CBaseEntity to access private member data.
  4428. class CPlayerRestoreHelper
  4429. {
  4430. public:
  4431. const Vector &GetAbsOrigin( CBaseEntity *pent )
  4432. {
  4433. return pent->m_vecAbsOrigin;
  4434. }
  4435. const Vector &GetAbsVelocity( CBaseEntity *pent )
  4436. {
  4437. return pent->m_vecAbsVelocity;
  4438. }
  4439. };
  4440. int CBasePlayer::Restore( IRestore &restore )
  4441. {
  4442. int status = BaseClass::Restore(restore);
  4443. if ( !status )
  4444. return 0;
  4445. CSaveRestoreData *pSaveData = gpGlobals->pSaveData;
  4446. // landmark isn't present.
  4447. if ( !pSaveData->levelInfo.fUseLandmark )
  4448. {
  4449. Msg( "No Landmark:%s\n", pSaveData->levelInfo.szLandmarkName );
  4450. // default to normal spawn
  4451. CBaseEntity *pSpawnSpot = EntSelectSpawnPoint();
  4452. SetLocalOrigin( pSpawnSpot->GetLocalOrigin() + Vector(0,0,1) );
  4453. SetLocalAngles( pSpawnSpot->GetLocalAngles() );
  4454. }
  4455. QAngle newViewAngles = pl.v_angle;
  4456. newViewAngles.z = 0; // Clear out roll
  4457. SetLocalAngles( newViewAngles );
  4458. SnapEyeAngles( newViewAngles );
  4459. // Copied from spawn() for now
  4460. SetBloodColor( BLOOD_COLOR_RED );
  4461. // clear this - it will get reset by touching the trigger again
  4462. m_afPhysicsFlags &= ~PFLAG_VPHYSICS_MOTIONCONTROLLER;
  4463. if ( GetFlags() & FL_DUCKING )
  4464. {
  4465. // Use the crouch HACK
  4466. FixPlayerCrouchStuck( this );
  4467. UTIL_SetSize(this, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX);
  4468. m_Local.m_bDucked = true;
  4469. }
  4470. else
  4471. {
  4472. m_Local.m_bDucked = false;
  4473. UTIL_SetSize(this, VEC_HULL_MIN, VEC_HULL_MAX);
  4474. }
  4475. // We need to get at m_vecAbsOrigin as it was restored but can't let it be
  4476. // recalculated by a call to GetAbsOrigin because hierarchy isn't fully restored yet,
  4477. // so we use this backdoor to get at the private data in CBaseEntity.
  4478. CPlayerRestoreHelper helper;
  4479. InitVCollision( helper.GetAbsOrigin( this ), helper.GetAbsVelocity( this ) );
  4480. // success
  4481. return 1;
  4482. }
  4483. //-----------------------------------------------------------------------------
  4484. // Purpose:
  4485. //-----------------------------------------------------------------------------
  4486. void CBasePlayer::OnRestore( void )
  4487. {
  4488. BaseClass::OnRestore();
  4489. SetViewEntity( m_hViewEntity, m_bShouldDrawPlayerWhileUsingViewEntity );
  4490. SetDefaultFOV(m_iDefaultFOV); // force this to reset if zero
  4491. // Calculate this immediately
  4492. m_nVehicleViewSavedFrame = 0;
  4493. m_nBodyPitchPoseParam = LookupPoseParameter( "body_pitch" );
  4494. if ( gpGlobals->eLoadType == MapLoad_Transition )
  4495. {
  4496. // HACK: (03/25/09) Then the player goes across a transition it doesn't spawn and register
  4497. // it's instance. We're hacking around this for now, but this will go away when we get around to
  4498. // having entities cross transitions and keep their script state.if( !g_pGameRules->IsMultiplayer() && g_pScriptVM )
  4499. {
  4500. g_pScriptVM->SetValue( "player", GetScriptInstance() );
  4501. }
  4502. // Don't persist drop state when we transition to a new level.
  4503. m_bDropEnabled = true;
  4504. m_bDuckEnabled = true;
  4505. }
  4506. }
  4507. /* void CBasePlayer::SetTeamName( const char *pTeamName )
  4508. {
  4509. Q_strncpy( m_szTeamName, pTeamName, TEAM_NAME_LENGTH );
  4510. } */
  4511. void CBasePlayer::SetArmorValue( int value )
  4512. {
  4513. m_ArmorValue = value;
  4514. }
  4515. void CBasePlayer::IncrementArmorValue( int nCount, int nMaxValue )
  4516. {
  4517. m_ArmorValue += nCount;
  4518. if (nMaxValue > 0)
  4519. {
  4520. if (m_ArmorValue > nMaxValue)
  4521. m_ArmorValue = nMaxValue;
  4522. }
  4523. }
  4524. void CBasePlayer::NotifyNearbyRadiationSource( float flRange )
  4525. {
  4526. // if player's current geiger counter range is larger
  4527. // than range to this trigger hurt, reset player's
  4528. // geiger counter range
  4529. if (m_flgeigerRange >= flRange)
  4530. m_flgeigerRange = flRange;
  4531. }
  4532. void CBasePlayer::AllowImmediateDecalPainting()
  4533. {
  4534. // No decal expediting during warmup
  4535. if ( CSGameRules() )
  4536. {
  4537. if ( CSGameRules()->IsWarmupPeriod() )
  4538. return;
  4539. if ( !CSGameRules()->IsPlayingClassic() &&
  4540. !CSGameRules()->IsPlayingGunGameTRBomb() )
  4541. return;
  4542. }
  4543. // CS:GO ensures a minimal ratelimit
  4544. if ( !m_bNextDecalTimeExpedited && ( m_flNextDecalTime > 0 ) )
  4545. {
  4546. m_flNextDecalTime -= ( PLAYERDECALS_COOLDOWN_SECONDS - 3 );
  4547. m_bNextDecalTimeExpedited = true;
  4548. }
  4549. }
  4550. void CBasePlayer::PushAwayDecalPaintingTime( float flTime )
  4551. {
  4552. m_flNextDecalTime = gpGlobals->curtime + flTime;
  4553. m_bNextDecalTimeExpedited = false;
  4554. }
  4555. // Suicide...
  4556. void CBasePlayer::CommitSuicide( bool bExplode /*= false*/, bool bForce /*= false*/ )
  4557. {
  4558. MDLCACHE_CRITICAL_SECTION();
  4559. if( !IsAlive() )
  4560. return;
  4561. // prevent suiciding too often
  4562. if ( m_fNextSuicideTime > gpGlobals->curtime && !bForce )
  4563. return;
  4564. // don't let them suicide for 5 seconds after suiciding
  4565. m_fNextSuicideTime = gpGlobals->curtime + 5;
  4566. int fDamage = DMG_PREVENT_PHYSICS_FORCE | ( bExplode ? ( DMG_BLAST | DMG_ALWAYSGIB ) : DMG_NEVERGIB );
  4567. // have the player kill themself
  4568. m_iHealth = 0;
  4569. Event_Killed( CTakeDamageInfo( this, this, 0, fDamage, m_iSuicideCustomKillFlags ) );
  4570. Event_Dying();
  4571. m_iSuicideCustomKillFlags = 0;
  4572. }
  4573. // Suicide with style...
  4574. void CBasePlayer::CommitSuicide( const Vector &vecForce, bool bExplode /*= false*/, bool bForce /*= false*/ )
  4575. {
  4576. MDLCACHE_CRITICAL_SECTION();
  4577. // Already dead.
  4578. if( !IsAlive() )
  4579. return;
  4580. // Prevent suicides for a time.
  4581. if ( m_fNextSuicideTime > gpGlobals->curtime && !bForce )
  4582. return;
  4583. m_fNextSuicideTime = gpGlobals->curtime + 5;
  4584. // Apply the force.
  4585. int nHealth = GetHealth();
  4586. // Kill the player.
  4587. CTakeDamageInfo info;
  4588. info.SetDamage( nHealth + 10 );
  4589. info.SetAttacker( this );
  4590. info.SetDamageType( bExplode ? DMG_BLAST | DMG_ALWAYSGIB : DMG_GENERIC );
  4591. info.SetDamageForce( vecForce );
  4592. info.SetDamagePosition( WorldSpaceCenter() );
  4593. TakeDamage( info );
  4594. }
  4595. //==============================================
  4596. // HasWeapons - do I have any weapons at all?
  4597. //==============================================
  4598. bool CBasePlayer::HasWeapons( void )
  4599. {
  4600. int i;
  4601. for ( i = 0 ; i < WeaponCount() ; i++ )
  4602. {
  4603. if ( GetWeapon(i) )
  4604. {
  4605. return true;
  4606. }
  4607. }
  4608. return false;
  4609. }
  4610. //-----------------------------------------------------------------------------
  4611. // Purpose:
  4612. // Input : &vecForce -
  4613. //-----------------------------------------------------------------------------
  4614. void CBasePlayer::VelocityPunch( const Vector &vecForce )
  4615. {
  4616. // Clear onground and add velocity.
  4617. SetGroundEntity( NULL );
  4618. ApplyAbsVelocityImpulse(vecForce );
  4619. }
  4620. //--------------------------------------------------------------------------------------------------------------
  4621. // VEHICLES
  4622. //-----------------------------------------------------------------------------
  4623. //-----------------------------------------------------------------------------
  4624. // Purpose: Whether or not the player is currently able to enter the vehicle
  4625. // Output : Returns true on success, false on failure.
  4626. //-----------------------------------------------------------------------------
  4627. bool CBasePlayer::CanEnterVehicle( IServerVehicle *pVehicle, int nRole )
  4628. {
  4629. // Must not have a passenger there already
  4630. if ( pVehicle->GetPassenger( nRole ) )
  4631. return false;
  4632. // Must be able to holster our current weapon (ie. grav gun!)
  4633. if ( pVehicle->IsPassengerUsingStandardWeapons( nRole ) == false )
  4634. {
  4635. //Must be able to stow our weapon
  4636. CBaseCombatWeapon *pWeapon = GetActiveWeapon();
  4637. if ( ( pWeapon != NULL ) && ( pWeapon->CanHolster() == false ) )
  4638. return false;
  4639. }
  4640. // Must be alive
  4641. if ( IsAlive() == false )
  4642. return false;
  4643. // Can't be pulled by a barnacle
  4644. if ( IsEFlagSet( EFL_IS_BEING_LIFTED_BY_BARNACLE ) )
  4645. return false;
  4646. return true;
  4647. }
  4648. //-----------------------------------------------------------------------------
  4649. // Purpose: Put this player in a vehicle
  4650. //-----------------------------------------------------------------------------
  4651. bool CBasePlayer::GetInVehicle( IServerVehicle *pVehicle, int nRole )
  4652. {
  4653. Assert( NULL == m_hVehicle.Get() );
  4654. Assert( nRole >= 0 );
  4655. // Make sure we can enter the vehicle
  4656. if ( CanEnterVehicle( pVehicle, nRole ) == false )
  4657. return false;
  4658. CBaseEntity *pEnt = pVehicle->GetVehicleEnt();
  4659. Assert( pEnt );
  4660. // Try to stow weapons
  4661. if ( pVehicle->IsPassengerUsingStandardWeapons( nRole ) == false )
  4662. {
  4663. CBaseCombatWeapon *pWeapon = GetActiveWeapon();
  4664. if ( pWeapon != NULL )
  4665. {
  4666. pWeapon->Holster( NULL );
  4667. }
  4668. #ifndef HL2_DLL
  4669. m_Local.m_iHideHUD |= HIDEHUD_WEAPONSELECTION;
  4670. #endif
  4671. m_Local.m_iHideHUD |= HIDEHUD_INVEHICLE;
  4672. }
  4673. if ( !pVehicle->IsPassengerVisible( nRole ) )
  4674. {
  4675. AddEffects( EF_NODRAW );
  4676. }
  4677. // Put us in the vehicle
  4678. pVehicle->SetPassenger( nRole, this );
  4679. ViewPunchReset();
  4680. // Setting the velocity to 0 will cause the IDLE animation to play
  4681. SetAbsVelocity( vec3_origin );
  4682. SetMoveType( MOVETYPE_NOCLIP );
  4683. // This is a hack to fixup the player's stats since they really didn't "cheat" and enter noclip from the console
  4684. #if !defined( _GAMECONSOLE ) || defined ( CSTRIKE15 )
  4685. gamestats->Event_DecrementPlayerEnteredNoClip( this );
  4686. #endif
  4687. // Get the seat position we'll be at in this vehicle
  4688. Vector vSeatOrigin;
  4689. QAngle qSeatAngles;
  4690. pVehicle->GetPassengerSeatPoint( nRole, &vSeatOrigin, &qSeatAngles );
  4691. // Set us to that position
  4692. SetAbsOrigin( vSeatOrigin );
  4693. SetAbsAngles( qSeatAngles );
  4694. // Parent to the vehicle
  4695. SetParent( pEnt );
  4696. SetCollisionGroup( COLLISION_GROUP_IN_VEHICLE );
  4697. // We cannot be ducking -- do all this before SetPassenger because it
  4698. // saves our view offset for restoration when we exit the vehicle.
  4699. RemoveFlag( FL_DUCKING | FL_ANIMDUCKING);
  4700. SetViewOffset( VEC_VIEW );
  4701. m_flDuckAmount = 0.0f;
  4702. m_Local.m_bDucked = false;
  4703. m_Local.m_bDucking = false;
  4704. m_Local.m_nDuckTimeMsecs = 0;
  4705. m_Local.m_nDuckJumpTimeMsecs = 0;
  4706. m_Local.m_nJumpTimeMsecs = 0;
  4707. // Turn our toggled duck off
  4708. if ( GetToggledDuckState() )
  4709. {
  4710. ToggleDuck();
  4711. }
  4712. m_hVehicle = pEnt;
  4713. // Throw an event indicating that the player entered the vehicle.
  4714. g_pNotify->ReportNamedEvent( this, "PlayerEnteredVehicle" );
  4715. m_iVehicleAnalogBias = VEHICLE_ANALOG_BIAS_NONE;
  4716. OnVehicleStart();
  4717. return true;
  4718. }
  4719. //-----------------------------------------------------------------------------
  4720. // Purpose: Remove this player from a vehicle
  4721. //-----------------------------------------------------------------------------
  4722. void CBasePlayer::LeaveVehicle( const Vector &vecExitPoint, const QAngle &vecExitAngles )
  4723. {
  4724. if ( NULL == m_hVehicle.Get() )
  4725. return;
  4726. IServerVehicle *pVehicle = GetVehicle();
  4727. Assert( pVehicle );
  4728. int nRole = pVehicle->GetPassengerRole( this );
  4729. Assert( nRole >= 0 );
  4730. SetParent( NULL );
  4731. // Find the first non-blocked exit point:
  4732. Vector vNewPos = GetAbsOrigin();
  4733. QAngle qAngles = GetAbsAngles();
  4734. if ( vecExitPoint == vec3_origin )
  4735. {
  4736. // FIXME: this might fail to find a safe exit point!!
  4737. pVehicle->GetPassengerExitPoint( nRole, &vNewPos, &qAngles );
  4738. }
  4739. else
  4740. {
  4741. vNewPos = vecExitPoint;
  4742. qAngles = vecExitAngles;
  4743. }
  4744. OnVehicleEnd( vNewPos );
  4745. SetAbsOrigin( vNewPos );
  4746. SetAbsAngles( qAngles );
  4747. // Clear out any leftover velocity
  4748. SetAbsVelocity( vec3_origin );
  4749. qAngles[ROLL] = 0;
  4750. SnapEyeAngles( qAngles );
  4751. #ifndef HL2_DLL
  4752. m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION;
  4753. #endif
  4754. m_Local.m_iHideHUD &= ~HIDEHUD_INVEHICLE;
  4755. RemoveEffects( EF_NODRAW );
  4756. SetMoveType( MOVETYPE_WALK );
  4757. SetCollisionGroup( COLLISION_GROUP_PLAYER );
  4758. if ( VPhysicsGetObject() )
  4759. {
  4760. VPhysicsGetObject()->SetPosition( vNewPos, vec3_angle, true );
  4761. }
  4762. m_hVehicle = NULL;
  4763. pVehicle->SetPassenger(nRole, NULL);
  4764. // Re-deploy our weapon
  4765. if ( IsAlive() )
  4766. {
  4767. if ( GetActiveWeapon() && GetActiveWeapon()->IsWeaponVisible() == false )
  4768. {
  4769. GetActiveWeapon()->Deploy();
  4770. ShowCrosshair( true );
  4771. }
  4772. }
  4773. // Just cut all of the rumble effects.
  4774. RumbleEffect( RUMBLE_STOP_ALL, 0, RUMBLE_FLAGS_NONE );
  4775. }
  4776. class CBloodSplat : public CPointEntity
  4777. {
  4778. public:
  4779. DECLARE_CLASS( CBloodSplat, CPointEntity );
  4780. void Spawn ( CBaseEntity *pOwner );
  4781. void Think ( void );
  4782. };
  4783. void CBloodSplat::Spawn ( CBaseEntity *pOwner )
  4784. {
  4785. SetLocalOrigin( pOwner->WorldSpaceCenter() + Vector ( 0 , 0 , 32 ) );
  4786. SetLocalAngles( pOwner->GetLocalAngles() );
  4787. SetOwnerEntity( pOwner );
  4788. SetNextThink( gpGlobals->curtime + 0.1f );
  4789. }
  4790. void CBloodSplat::Think( void )
  4791. {
  4792. trace_t tr;
  4793. if ( g_Language.GetInt() != LANGUAGE_GERMAN )
  4794. {
  4795. CBasePlayer *pPlayer;
  4796. pPlayer = ToBasePlayer( GetOwnerEntity() );
  4797. Vector forward;
  4798. AngleVectors( GetAbsAngles(), &forward );
  4799. UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + forward * 128,
  4800. MASK_SOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, & tr);
  4801. UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED );
  4802. }
  4803. UTIL_Remove( this );
  4804. }
  4805. //==============================================
  4806. //-----------------------------------------------------------------------------
  4807. // Purpose: Create and give the named item to the player. Then return it.
  4808. //-----------------------------------------------------------------------------
  4809. CBaseEntity *CBasePlayer::GiveNamedItem( const char *pchName, int iSubType /*= 0*/, CEconItemView *pScriptItem /*= NULL*/, bool bForce /*= false*/ )
  4810. {
  4811. // If I already own this type don't create one
  4812. if ( Weapon_OwnsThisType( pchName, iSubType ) )
  4813. return NULL;
  4814. // Msg( "giving %s\n", pszName );
  4815. EHANDLE pent;
  4816. pent = CreateEntityByName( pchName );
  4817. if ( pent == NULL )
  4818. {
  4819. Msg( "NULL Ent in GiveNamedItem!\n" );
  4820. return NULL;
  4821. }
  4822. pent->SetLocalOrigin( GetLocalOrigin() );
  4823. pent->AddSpawnFlags( SF_NORESPAWN );
  4824. CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon*>( (CBaseEntity*)pent );
  4825. if ( pWeapon )
  4826. {
  4827. pWeapon->SetSubType( iSubType );
  4828. }
  4829. DispatchSpawn( pent );
  4830. if ( pent != NULL && !(pent->IsMarkedForDeletion()) )
  4831. {
  4832. pent->Touch( this );
  4833. }
  4834. return pent;
  4835. }
  4836. //-----------------------------------------------------------------------------
  4837. // Purpose: Returns the nearest COLLIBALE entity in front of the player
  4838. // that has a clear line of sight with the given classname
  4839. // Input :
  4840. // Output :
  4841. //-----------------------------------------------------------------------------
  4842. CBaseEntity* CBasePlayer::FindEntityClassForward( char *classname )
  4843. {
  4844. trace_t tr;
  4845. Vector forward;
  4846. EyeVectors( &forward );
  4847. UTIL_TraceLine(EyePosition(),
  4848. EyePosition() + forward * MAX_COORD_RANGE,
  4849. MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
  4850. if ( tr.fraction != 1.0 && tr.DidHitNonWorldEntity() )
  4851. {
  4852. CBaseEntity *pHit = tr.m_pEnt;
  4853. if (FClassnameIs( pHit,classname ) )
  4854. {
  4855. return pHit;
  4856. }
  4857. }
  4858. return NULL;
  4859. }
  4860. //-----------------------------------------------------------------------------
  4861. // Purpose: Returns the nearest COLLIBALE entity in front of the player
  4862. // that has a clear line of sight. If HULL is true, the trace will
  4863. // hit the collision hull of entities. Otherwise, the trace will hit
  4864. // hitboxes.
  4865. // Input :
  4866. // Output :
  4867. //-----------------------------------------------------------------------------
  4868. CBaseEntity* CBasePlayer::FindEntityForward( bool fHull )
  4869. {
  4870. trace_t tr;
  4871. Vector forward;
  4872. int mask;
  4873. if( fHull )
  4874. {
  4875. mask = MASK_SOLID;
  4876. }
  4877. else
  4878. {
  4879. mask = MASK_SHOT;
  4880. }
  4881. EyeVectors( &forward );
  4882. UTIL_TraceLine(EyePosition(),
  4883. EyePosition() + forward * MAX_COORD_RANGE,
  4884. mask, this, COLLISION_GROUP_NONE, &tr );
  4885. if ( tr.fraction != 1.0 && tr.DidHitNonWorldEntity() )
  4886. {
  4887. return tr.m_pEnt;
  4888. }
  4889. return NULL;
  4890. }
  4891. //-----------------------------------------------------------------------------
  4892. // Purpose: Finds the nearest entity in front of the player of the given
  4893. // classname, preferring collidable entities, but allows selection of
  4894. // enities that are on the other side of walls or objects
  4895. //
  4896. // Input :
  4897. // Output :
  4898. //-----------------------------------------------------------------------------
  4899. CBaseEntity* CBasePlayer::FindPickerEntityClass( char *classname )
  4900. {
  4901. // First try to trace a hull to an entity
  4902. CBaseEntity *pEntity = FindEntityClassForward( classname );
  4903. // If that fails just look for the nearest facing entity
  4904. if (!pEntity)
  4905. {
  4906. Vector forward;
  4907. Vector origin;
  4908. EyeVectors( &forward );
  4909. origin = WorldSpaceCenter();
  4910. pEntity = gEntList.FindEntityClassNearestFacing( origin, forward,0.95,classname);
  4911. }
  4912. return pEntity;
  4913. }
  4914. //-----------------------------------------------------------------------------
  4915. // Purpose: Finds the nearest entity in front of the player, preferring
  4916. // collidable entities, but allows selection of enities that are
  4917. // on the other side of walls or objects
  4918. // Input :
  4919. // Output :
  4920. //-----------------------------------------------------------------------------
  4921. CBaseEntity* CBasePlayer::FindPickerEntity()
  4922. {
  4923. MDLCACHE_CRITICAL_SECTION();
  4924. // First try to trace a hull to an entity
  4925. CBaseEntity *pEntity = FindEntityForward( true );
  4926. // If that fails just look for the nearest facing entity
  4927. if (!pEntity)
  4928. {
  4929. Vector forward;
  4930. Vector origin;
  4931. EyeVectors( &forward );
  4932. origin = EyePosition();
  4933. pEntity = gEntList.FindEntityNearestFacing( origin, forward, 0.95 );
  4934. }
  4935. return pEntity;
  4936. }
  4937. //-----------------------------------------------------------------------------
  4938. // Purpose: Finds the nearest node in front of the player
  4939. // Input :
  4940. // Output :
  4941. //-----------------------------------------------------------------------------
  4942. CAI_Node* CBasePlayer::FindPickerAINode( int nNodeType )
  4943. {
  4944. Vector forward;
  4945. EyeVectors( &forward );
  4946. return g_pAINetworkManager->GetEditOps()->FindAINodeNearestFacing( EyePosition(), forward,0.90, nNodeType);
  4947. }
  4948. //-----------------------------------------------------------------------------
  4949. // Purpose: Finds the nearest link in front of the player
  4950. // Input :
  4951. // Output :
  4952. //-----------------------------------------------------------------------------
  4953. CAI_Link* CBasePlayer::FindPickerAILink()
  4954. {
  4955. Vector forward;
  4956. EyeVectors( &forward );
  4957. return g_pAINetworkManager->GetEditOps()->FindAILinkNearestFacing( EyePosition(), forward,0.90);
  4958. }
  4959. /*
  4960. ===============
  4961. ForceClientDllUpdate
  4962. When recording a demo, we need to have the server tell us the entire client state
  4963. so that the client side .dll can behave correctly.
  4964. Reset stuff so that the state is transmitted.
  4965. ===============
  4966. */
  4967. void CBasePlayer::ForceClientDllUpdate( void )
  4968. {
  4969. m_iClientBattery = -1;
  4970. m_iTrain |= TRAIN_NEW; // Force new train message.
  4971. m_fWeapon = false; // Force weapon send
  4972. // Force all HUD data to be resent to client
  4973. m_fInitHUD = true;
  4974. // Now force all the necessary messages
  4975. // to be sent.
  4976. UpdateClientData();
  4977. UTIL_RestartAmbientSounds(); // MOTODO that updates the sounds for everybody
  4978. }
  4979. /*
  4980. ============
  4981. ImpulseCommands
  4982. ============
  4983. */
  4984. void CBasePlayer::ImpulseCommands( )
  4985. {
  4986. int iImpulse = (int)m_nImpulse;
  4987. switch (iImpulse)
  4988. {
  4989. case 100:
  4990. // temporary flashlight for level designers
  4991. if ( FlashlightIsOn() )
  4992. {
  4993. FlashlightTurnOff( PLAY_FLASHLIGHT_SOUND );
  4994. }
  4995. else
  4996. {
  4997. FlashlightTurnOn( PLAY_FLASHLIGHT_SOUND );
  4998. }
  4999. break;
  5000. case 200:
  5001. if ( sv_cheats->GetBool() )
  5002. {
  5003. CBaseCombatWeapon *pWeapon;
  5004. pWeapon = GetActiveWeapon();
  5005. if( pWeapon->IsEffectActive( EF_NODRAW ) )
  5006. {
  5007. pWeapon->Deploy();
  5008. }
  5009. else
  5010. {
  5011. pWeapon->Holster();
  5012. }
  5013. }
  5014. break;
  5015. default:
  5016. // check all of the cheat impulse commands now
  5017. CheatImpulseCommands( iImpulse );
  5018. break;
  5019. }
  5020. m_nImpulse = 0;
  5021. }
  5022. #ifdef HL2_EPISODIC
  5023. //-----------------------------------------------------------------------------
  5024. // Purpose:
  5025. //-----------------------------------------------------------------------------
  5026. static void CreateJalopy( CBasePlayer *pPlayer )
  5027. {
  5028. // Cheat to create a jeep in front of the player
  5029. Vector vecForward;
  5030. AngleVectors( pPlayer->EyeAngles(), &vecForward );
  5031. CBaseEntity *pJeep = (CBaseEntity *)CreateEntityByName( "prop_vehicle_jeep" );
  5032. if ( pJeep )
  5033. {
  5034. Vector vecOrigin = pPlayer->GetAbsOrigin() + vecForward * 256 + Vector(0,0,64);
  5035. QAngle vecAngles( 0, pPlayer->GetAbsAngles().y - 90, 0 );
  5036. pJeep->SetAbsOrigin( vecOrigin );
  5037. pJeep->SetAbsAngles( vecAngles );
  5038. pJeep->KeyValue( "model", "models/vehicle.mdl" );
  5039. pJeep->KeyValue( "solid", "6" );
  5040. pJeep->KeyValue( "targetname", "jeep" );
  5041. pJeep->KeyValue( "vehiclescript", "scripts/vehicles/jalopy.txt" );
  5042. DispatchSpawn( pJeep );
  5043. pJeep->Activate();
  5044. pJeep->Teleport( &vecOrigin, &vecAngles, NULL );
  5045. }
  5046. }
  5047. void CC_CH_CreateJalopy( void )
  5048. {
  5049. CBasePlayer *pPlayer = UTIL_GetCommandClient();
  5050. if ( !pPlayer )
  5051. return;
  5052. CreateJalopy( pPlayer );
  5053. }
  5054. static ConCommand ch_createjalopy("ch_createjalopy", CC_CH_CreateJalopy, "Spawn jalopy in front of the player.", FCVAR_CHEAT);
  5055. #endif // HL2_EPISODIC
  5056. //-----------------------------------------------------------------------------
  5057. // Purpose:
  5058. //-----------------------------------------------------------------------------
  5059. static void CreateJeep( CBasePlayer *pPlayer )
  5060. {
  5061. // Cheat to create a jeep in front of the player
  5062. Vector vecForward;
  5063. AngleVectors( pPlayer->EyeAngles(), &vecForward );
  5064. CBaseEntity *pJeep = (CBaseEntity *)CreateEntityByName( "prop_vehicle_jeep" );
  5065. if ( pJeep )
  5066. {
  5067. Vector vecOrigin = pPlayer->GetAbsOrigin() + vecForward * 256 + Vector(0,0,64);
  5068. QAngle vecAngles( 0, pPlayer->GetAbsAngles().y - 90, 0 );
  5069. pJeep->SetAbsOrigin( vecOrigin );
  5070. pJeep->SetAbsAngles( vecAngles );
  5071. pJeep->KeyValue( "model", "models/buggy.mdl" );
  5072. pJeep->KeyValue( "solid", "6" );
  5073. pJeep->KeyValue( "targetname", "jeep" );
  5074. pJeep->KeyValue( "vehiclescript", "scripts/vehicles/jeep_test.txt" );
  5075. DispatchSpawn( pJeep );
  5076. pJeep->Activate();
  5077. pJeep->Teleport( &vecOrigin, &vecAngles, NULL );
  5078. }
  5079. }
  5080. void CC_CH_CreateJeep( void )
  5081. {
  5082. CBasePlayer *pPlayer = UTIL_GetCommandClient();
  5083. if ( !pPlayer )
  5084. return;
  5085. CreateJeep( pPlayer );
  5086. }
  5087. static ConCommand ch_createjeep("ch_createjeep", CC_CH_CreateJeep, "Spawn jeep in front of the player.", FCVAR_CHEAT);
  5088. //-----------------------------------------------------------------------------
  5089. // Create an airboat in front of the specified player
  5090. //-----------------------------------------------------------------------------
  5091. static void CreateAirboat( CBasePlayer *pPlayer )
  5092. {
  5093. // Cheat to create a jeep in front of the player
  5094. Vector vecForward;
  5095. AngleVectors( pPlayer->EyeAngles(), &vecForward );
  5096. CBaseEntity *pJeep = ( CBaseEntity* )CreateEntityByName( "prop_vehicle_airboat" );
  5097. if ( pJeep )
  5098. {
  5099. Vector vecOrigin = pPlayer->GetAbsOrigin() + vecForward * 256 + Vector( 0,0,64 );
  5100. QAngle vecAngles( 0, pPlayer->GetAbsAngles().y - 90, 0 );
  5101. pJeep->SetAbsOrigin( vecOrigin );
  5102. pJeep->SetAbsAngles( vecAngles );
  5103. pJeep->KeyValue( "model", "models/airboat.mdl" );
  5104. pJeep->KeyValue( "solid", "6" );
  5105. pJeep->KeyValue( "targetname", "airboat" );
  5106. pJeep->KeyValue( "vehiclescript", "scripts/vehicles/airboat.txt" );
  5107. DispatchSpawn( pJeep );
  5108. pJeep->Activate();
  5109. }
  5110. }
  5111. //-----------------------------------------------------------------------------
  5112. // Purpose:
  5113. //-----------------------------------------------------------------------------
  5114. void CC_CH_CreateAirboat( void )
  5115. {
  5116. CBasePlayer *pPlayer = UTIL_GetCommandClient();
  5117. if ( !pPlayer )
  5118. return;
  5119. CreateAirboat( pPlayer );
  5120. }
  5121. static ConCommand ch_createairboat( "ch_createairboat", CC_CH_CreateAirboat, "Spawn airboat in front of the player.", FCVAR_CHEAT );
  5122. //=========================================================
  5123. //=========================================================
  5124. void CBasePlayer::CheatImpulseCommands( int iImpulse )
  5125. {
  5126. #if !defined( HLDEMO_BUILD )
  5127. if ( !sv_cheats->GetBool() )
  5128. {
  5129. return;
  5130. }
  5131. CBaseEntity *pEntity;
  5132. trace_t tr;
  5133. switch ( iImpulse )
  5134. {
  5135. case 76:
  5136. {
  5137. if (!giPrecacheGrunt)
  5138. {
  5139. giPrecacheGrunt = 1;
  5140. Msg( "You must now restart to use Grunt-o-matic.\n");
  5141. }
  5142. else
  5143. {
  5144. Vector forward = UTIL_YawToVector( EyeAngles().y );
  5145. Create("NPC_human_grunt", GetLocalOrigin() + forward * 128, GetLocalAngles());
  5146. }
  5147. break;
  5148. }
  5149. case 81:
  5150. GiveNamedItem( "weapon_cubemap" );
  5151. break;
  5152. case 82:
  5153. // Cheat to create a jeep in front of the player
  5154. CreateJeep( this );
  5155. break;
  5156. case 83:
  5157. // Cheat to create a airboat in front of the player
  5158. CreateAirboat( this );
  5159. break;
  5160. case 101:
  5161. gEvilImpulse101 = true;
  5162. EquipSuit();
  5163. #if defined( PORTAL2 )
  5164. // Give the player portal 2 stuff!
  5165. GiveNamedItem( "weapon_camera" );
  5166. GiveNamedItem( "weapon_placement" );
  5167. #else // PORTAL2
  5168. // Give the player everything!
  5169. GiveAmmo( 255, "Pistol");
  5170. GiveAmmo( 255, "AR2");
  5171. GiveAmmo( 5, "AR2AltFire");
  5172. GiveAmmo( 255, "SMG1");
  5173. GiveAmmo( 255, "Buckshot");
  5174. GiveAmmo( 3, "smg1_grenade");
  5175. GiveAmmo( 3, "rpg_round");
  5176. GiveAmmo( 5, "grenade");
  5177. GiveAmmo( 32, "357" );
  5178. GiveAmmo( 16, "XBowBolt" );
  5179. #ifdef HL2_EPISODIC
  5180. GiveAmmo( 5, "Hopwire" );
  5181. #endif
  5182. GiveNamedItem( "weapon_smg1" );
  5183. GiveNamedItem( "weapon_frag" );
  5184. GiveNamedItem( "weapon_crowbar" );
  5185. GiveNamedItem( "weapon_pistol" );
  5186. GiveNamedItem( "weapon_ar2" );
  5187. GiveNamedItem( "weapon_shotgun" );
  5188. GiveNamedItem( "weapon_physcannon" );
  5189. #ifndef HL2_EP3 // No bugbait in EP3
  5190. GiveNamedItem( "weapon_bugbait" );
  5191. #endif
  5192. GiveNamedItem( "weapon_rpg" );
  5193. GiveNamedItem( "weapon_357" );
  5194. GiveNamedItem( "weapon_crossbow" );
  5195. #ifdef HL2_EP3
  5196. GiveNamedItem( "weapon_icegun" );
  5197. GiveNamedItem( "weapon_weaponizer" );
  5198. GiveNamedItem( "weapon_teleport" );
  5199. GiveNamedItem( "weapon_pipebomblauncher" );
  5200. GiveNamedItem( "weapon_flechettegun" );
  5201. GiveNamedItem( "weapon_flamethrower" );
  5202. GiveNamedItem( "weapon_egon" );
  5203. GiveNamedItem( "weapon_gauss" );
  5204. GiveAmmo( 999, "Fuel" );
  5205. GiveAmmo( 100, "Uranium" );
  5206. #endif // HL2_EP3
  5207. #endif // PORTAL2
  5208. if ( GetHealth() < 100 )
  5209. {
  5210. TakeHealth( 25, DMG_GENERIC );
  5211. }
  5212. gEvilImpulse101 = false;
  5213. break;
  5214. case 102:
  5215. // Gibbage!!!
  5216. CGib::SpawnRandomGibs( this, 1, GIB_HUMAN );
  5217. break;
  5218. case 103:
  5219. // What the hell are you doing?
  5220. pEntity = FindEntityForward( true );
  5221. if ( pEntity )
  5222. {
  5223. CAI_BaseNPC *pNPC = pEntity->MyNPCPointer();
  5224. if ( pNPC )
  5225. pNPC->ReportAIState();
  5226. }
  5227. break;
  5228. case 106:
  5229. // Give me the classname and targetname of this entity.
  5230. pEntity = FindEntityForward( true );
  5231. if ( pEntity )
  5232. {
  5233. Msg( "Classname: %s", pEntity->GetClassname() );
  5234. if ( pEntity->GetEntityName() != NULL_STRING )
  5235. {
  5236. Msg( " - Name: %s\n", STRING( pEntity->GetEntityName() ) );
  5237. }
  5238. else
  5239. {
  5240. Msg( " - Name: No Targetname\n" );
  5241. }
  5242. if ( pEntity->m_iParent != NULL_STRING )
  5243. Msg( "Parent: %s\n", STRING(pEntity->m_iParent) );
  5244. Msg( "Model: %s\n", STRING( pEntity->GetModelName() ) );
  5245. if ( pEntity->m_iGlobalname != NULL_STRING )
  5246. Msg( "Globalname: %s\n", STRING(pEntity->m_iGlobalname) );
  5247. }
  5248. break;
  5249. case 107:
  5250. {
  5251. trace_t tr;
  5252. edict_t *pWorld = INDEXENT( 0 );
  5253. Vector start = EyePosition();
  5254. Vector forward;
  5255. EyeVectors( &forward );
  5256. Vector end = start + forward * 1024;
  5257. UTIL_TraceLine( start, end, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
  5258. if ( tr.m_pEnt )
  5259. pWorld = tr.m_pEnt->edict();
  5260. const char *pTextureName = tr.surface.name;
  5261. if ( pTextureName )
  5262. Msg( "Texture: %s\n", pTextureName );
  5263. }
  5264. break;
  5265. //
  5266. // Sets the debug NPC to be the NPC under the crosshair.
  5267. //
  5268. case 108:
  5269. {
  5270. pEntity = FindEntityForward( true );
  5271. if ( pEntity )
  5272. {
  5273. CAI_BaseNPC *pNPC = pEntity->MyNPCPointer();
  5274. if ( pNPC != NULL )
  5275. {
  5276. Msg( "Debugging %s (0x%p)\n", pNPC->GetClassname(), pNPC );
  5277. CAI_BaseNPC::SetDebugNPC( pNPC );
  5278. }
  5279. }
  5280. break;
  5281. }
  5282. case 195:// show shortest paths for entire level to nearest node
  5283. {
  5284. Create("node_viewer_fly", GetLocalOrigin(), GetLocalAngles());
  5285. }
  5286. break;
  5287. case 196:// show shortest paths for entire level to nearest node
  5288. {
  5289. Create("node_viewer_large", GetLocalOrigin(), GetLocalAngles());
  5290. }
  5291. break;
  5292. case 197:// show shortest paths for entire level to nearest node
  5293. {
  5294. Create("node_viewer_human", GetLocalOrigin(), GetLocalAngles());
  5295. }
  5296. break;
  5297. case 202:// Random blood splatter
  5298. {
  5299. Vector forward;
  5300. EyeVectors( &forward );
  5301. UTIL_TraceLine ( EyePosition(),
  5302. EyePosition() + forward * 128,
  5303. MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, & tr);
  5304. if ( tr.fraction != 1.0 )
  5305. {// line hit something, so paint a decal
  5306. CBloodSplat *pBlood = CREATE_UNSAVED_ENTITY( CBloodSplat, "bloodsplat" );
  5307. pBlood->Spawn( this );
  5308. }
  5309. }
  5310. break;
  5311. case 203:// remove creature.
  5312. pEntity = FindEntityForward( true );
  5313. if ( pEntity )
  5314. {
  5315. UTIL_Remove( pEntity );
  5316. // if ( pEntity->m_takedamage )
  5317. // pEntity->SetThink(SUB_Remove);
  5318. }
  5319. break;
  5320. }
  5321. #endif // HLDEMO_BUILD
  5322. }
  5323. bool CBasePlayer::ClientCommand( const CCommand &args )
  5324. {
  5325. const char *cmd = args[0];
  5326. #ifdef _DEBUG
  5327. if( stricmp( cmd, "test_SmokeGrenade" ) == 0 )
  5328. {
  5329. if ( sv_cheats && sv_cheats->GetBool() )
  5330. {
  5331. ParticleSmokeGrenade *pSmoke = dynamic_cast<ParticleSmokeGrenade*>( CreateEntityByName(PARTICLESMOKEGRENADE_ENTITYNAME) );
  5332. if ( pSmoke )
  5333. {
  5334. Vector vForward;
  5335. AngleVectors( GetLocalAngles(), &vForward );
  5336. vForward.z = 0;
  5337. VectorNormalize( vForward );
  5338. pSmoke->SetLocalOrigin( GetLocalOrigin() + vForward * 100 );
  5339. pSmoke->SetFadeTime(25, 30); // Fade out between 25 seconds and 30 seconds.
  5340. pSmoke->Activate();
  5341. pSmoke->SetLifetime(30);
  5342. pSmoke->FillVolume();
  5343. return true;
  5344. }
  5345. }
  5346. }
  5347. else
  5348. #endif // _DEBUG
  5349. if( stricmp( cmd, "vehicleRole" ) == 0 )
  5350. {
  5351. // Get the vehicle role value.
  5352. if ( args.ArgC() == 2 )
  5353. {
  5354. // Check to see if a player is in a vehicle.
  5355. if ( IsInAVehicle() )
  5356. {
  5357. int nRole = atoi( args[1] );
  5358. IServerVehicle *pVehicle = GetVehicle();
  5359. if ( pVehicle )
  5360. {
  5361. // Only switch roles if role is empty!
  5362. if ( !pVehicle->GetPassenger( nRole ) )
  5363. {
  5364. LeaveVehicle();
  5365. GetInVehicle( pVehicle, nRole );
  5366. }
  5367. }
  5368. }
  5369. return true;
  5370. }
  5371. }
  5372. else if ( HandleVoteCommands( args ) )
  5373. {
  5374. return true;
  5375. }
  5376. else if ( stricmp( cmd, "spectate" ) == 0 ) // join spectator team & start observer mode
  5377. {
  5378. if ( GetTeamNumber() == TEAM_SPECTATOR )
  5379. return true;
  5380. ConVarRef mp_allowspectators( "mp_allowspectators" );
  5381. if ( mp_allowspectators.IsValid() )
  5382. {
  5383. #if defined( REPLAY_ENABLED )
  5384. if ( ( mp_allowspectators.GetBool() == false ) && !IsHLTV() && !IsReplay() )
  5385. #else
  5386. if ( ( mp_allowspectators.GetBool() == false ) && !IsHLTV() )
  5387. #endif
  5388. {
  5389. ClientPrint( this, HUD_PRINTCENTER, "#Cannot_Be_Spectator" );
  5390. return true;
  5391. }
  5392. }
  5393. if ( !IsDead() )
  5394. {
  5395. CommitSuicide(); // kill player
  5396. }
  5397. RemoveAllItems( true );
  5398. ChangeTeam( TEAM_SPECTATOR );
  5399. StartObserverMode( OBS_MODE_ROAMING );
  5400. return true;
  5401. }
  5402. else if ( stricmp( cmd, "spec_mode" ) == 0 ) // new observer mode
  5403. {
  5404. int mode;
  5405. int nPlayerEntIndex = entindex();
  5406. if ( engine->GetClientHltvReplayDelay( nPlayerEntIndex - 1 ) )
  5407. {
  5408. engine->StopClientHltvReplay( nPlayerEntIndex - 1 );
  5409. return true;
  5410. }
  5411. if ( GetObserverMode() == OBS_MODE_FREEZECAM )
  5412. {
  5413. AttemptToExitFreezeCam();
  5414. return true;
  5415. }
  5416. // not allowed to change spectator modes when fadetoblack is being used ( mp_forcecamera 2 )
  5417. if ( mp_forcecamera.GetInt() == OBS_ALLOW_NONE )
  5418. {
  5419. if ( GetTeamNumber() > TEAM_SPECTATOR )
  5420. return true;
  5421. }
  5422. // not allowed to change spectator modes when coaching
  5423. if ( IsCoach() )
  5424. {
  5425. return true;
  5426. }
  5427. // check for parameters.
  5428. if ( args.ArgC() >= 2 )
  5429. {
  5430. mode = atoi( args[1] );
  5431. if ( mode < OBS_MODE_IN_EYE || mode > LAST_PLAYER_OBSERVERMODE )
  5432. mode = OBS_MODE_IN_EYE;
  5433. }
  5434. else
  5435. {
  5436. // switch to next spec mode if no parameter given
  5437. mode = GetObserverMode() + 1;
  5438. if ( mode > LAST_PLAYER_OBSERVERMODE )
  5439. {
  5440. mode = OBS_MODE_IN_EYE;
  5441. }
  5442. else if ( mode < OBS_MODE_IN_EYE )
  5443. {
  5444. mode = OBS_MODE_ROAMING;
  5445. }
  5446. }
  5447. // don't allow input while player or death cam animation
  5448. if ( GetObserverMode() > OBS_MODE_DEATHCAM )
  5449. {
  5450. // set new spectator mode, don't allow OBS_MODE_NONE
  5451. if ( !SetObserverMode( mode ) )
  5452. ClientPrint( this, HUD_PRINTCONSOLE, "#Spectator_Mode_Unkown");
  5453. else
  5454. engine->ClientCommand( edict(), "cl_spec_mode %d", mode );
  5455. }
  5456. else
  5457. {
  5458. // remember spectator mode for later use
  5459. m_iObserverLastMode = mode;
  5460. engine->ClientCommand( edict(), "cl_spec_mode %d", mode );
  5461. }
  5462. return true;
  5463. }
  5464. else if ( stricmp( cmd, "spec_next" ) == 0 ) // chase next player
  5465. {
  5466. if ( GetObserverMode() > OBS_MODE_FIXED )
  5467. {
  5468. // set new spectator mode
  5469. CBaseEntity * target = FindNextObserverTarget( false );
  5470. if ( target )
  5471. {
  5472. SetObserverTarget( target );
  5473. }
  5474. }
  5475. else if ( GetObserverMode() == OBS_MODE_FREEZECAM )
  5476. {
  5477. AttemptToExitFreezeCam();
  5478. }
  5479. return true;
  5480. }
  5481. else if ( stricmp( cmd, "spec_prev" ) == 0 ) // chase prevoius player
  5482. {
  5483. if ( GetObserverMode() > OBS_MODE_FIXED )
  5484. {
  5485. // set new spectator mode
  5486. CBaseEntity * target = FindNextObserverTarget( true );
  5487. if ( target )
  5488. {
  5489. SetObserverTarget( target );
  5490. }
  5491. }
  5492. else if ( GetObserverMode() == OBS_MODE_FREEZECAM )
  5493. {
  5494. AttemptToExitFreezeCam();
  5495. }
  5496. return true;
  5497. }
  5498. /*
  5499. else if ( stricmp( cmd, "spec_grenade" ) == 0 ) // chase prevoius player
  5500. {
  5501. // if ( GetObserverMode() > OBS_MODE_FIXED )
  5502. // {
  5503. // // set new spectator mode
  5504. // CBaseEntity * target = FindNextObserverTarget( true );
  5505. // if ( target )
  5506. // {
  5507. // SetObserverTarget( target );
  5508. // }
  5509. // }
  5510. // else if ( GetObserverMode() == OBS_MODE_FREEZECAM )
  5511. // {
  5512. // AttemptToExitFreezeCam();
  5513. // }
  5514. CBaseEntity *pEnt = NULL;
  5515. CBaseEntity *pNearest = NULL;
  5516. float dist, closest;
  5517. closest = 1024;
  5518. for ( CEntitySphereQuery sphere( GetAbsOrigin(), 1024 ); ( pEnt = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
  5519. {
  5520. CBaseCSGrenadeProjectile* pGrenadeProjectile = dynamic_cast<CBaseCSGrenadeProjectile*>( pEnt );
  5521. // filter out non-tracks
  5522. if ( !( pEnt->GetFlags() & ( FL_CLIENT | FL_NPC ) ) && pGrenadeProjectile )
  5523. {
  5524. dist = ( GetAbsOrigin() - pEnt->GetAbsOrigin() ).Length();
  5525. if ( dist < closest )
  5526. {
  5527. closest = dist;
  5528. pNearest = pEnt;
  5529. }
  5530. }
  5531. }
  5532. if ( pNearest )
  5533. SetObserverTarget( pNearest );
  5534. return true;
  5535. }
  5536. */
  5537. else if ( stricmp( cmd, "spec_player" ) == 0 || stricmp( cmd, "spec_player_by_name" ) == 0 ) // chase next player
  5538. {
  5539. if ( GetObserverMode() == OBS_MODE_ROAMING || GetObserverMode() == OBS_MODE_FIXED )
  5540. SetObserverMode( OBS_MODE_IN_EYE );
  5541. if ( GetObserverMode() > OBS_MODE_FIXED && args.ArgC() >= 2 )
  5542. {
  5543. int index = atoi( args[1] );
  5544. CBasePlayer * target = NULL;
  5545. if ( index == 0 )
  5546. {
  5547. target = UTIL_PlayerByName( args.ArgS() );
  5548. }
  5549. else if ( !FStrEq( cmd, "spec_player_by_name" ) )
  5550. {
  5551. target = UTIL_PlayerByIndex( index );
  5552. }
  5553. if ( IsValidObserverTarget( target ) )
  5554. {
  5555. SetObserverTarget( target );
  5556. }
  5557. }
  5558. return true;
  5559. }
  5560. else if ( stricmp( cmd, "spec_player_by_accountid" ) == 0 )
  5561. {
  5562. if ( GetObserverMode( ) == OBS_MODE_ROAMING || GetObserverMode( ) == OBS_MODE_FIXED )
  5563. SetObserverMode( OBS_MODE_IN_EYE );
  5564. if ( GetObserverMode( ) > OBS_MODE_FIXED && args.ArgC( ) >= 2 )
  5565. {
  5566. AccountID_t accountID = CSteamID( args[ 1 ] ).GetAccountID();
  5567. CBasePlayer * target = UTIL_PlayerByAccountID( accountID );
  5568. if ( IsValidObserverTarget( target ) )
  5569. {
  5570. SetObserverTarget( target );
  5571. }
  5572. }
  5573. }
  5574. else if ( stricmp( cmd, "spec_goto" ) == 0 ) // chase next player
  5575. {
  5576. if ( !sv_cheats->GetBool() && IsAlive()/* || (pPlayer->GetObserverMode() != OBS_MODE_ROAMING && pPlayer->GetObserverMode() != OBS_MODE_FIXED)*/ )
  5577. return false;
  5578. if ( args.ArgC() < 6 )
  5579. {
  5580. ClientPrint( this, HUD_PRINTCONSOLE, "Usage: spec_goto x y z pitch yaw\n");
  5581. return false;
  5582. }
  5583. Vector oldorigin = GetAbsOrigin();
  5584. Vector newpos;
  5585. newpos.x = clamp( atof(args[1]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5586. newpos.y = clamp( atof(args[2]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5587. newpos.z = clamp( atof(args[3]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5588. QAngle oldang = GetAbsAngles();
  5589. QAngle newang;
  5590. newang.x = clamp( atof(args[4]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5591. newang.y = clamp( atof(args[5]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5592. newang.z = oldang.z;
  5593. SetAbsOrigin( newpos );
  5594. // have to clear the observer target before we set the mode to roaming, otherwise it pops our position to the target
  5595. m_hObserverTarget.Set( NULL );
  5596. SetObserverMode( OBS_MODE_ROAMING );
  5597. m_iFOV.Set( GetDefaultFOV() );
  5598. SnapEyeAngles( newang );
  5599. int nPlayerIndex = 0;
  5600. if ( args.ArgC() >= 7 )
  5601. nPlayerIndex = atoi(args[6]);
  5602. CBasePlayer *target = UTIL_PlayerByIndex( nPlayerIndex );
  5603. if ( target )
  5604. {
  5605. m_hObserverTarget.Set( target );
  5606. IGameEvent *event = gameeventmanager->CreateEvent( "spec_target_updated" );
  5607. if ( event )
  5608. {
  5609. event->SetInt("userid", GetUserID() );
  5610. gameeventmanager->FireEventClientSide( event );
  5611. }
  5612. }
  5613. return true;
  5614. }
  5615. else if ( stricmp( cmd, "spec_lerpto" ) == 0 )
  5616. {
  5617. if ( !sv_cheats->GetBool() && (IsAlive())/* || (pPlayer->GetObserverMode() != OBS_MODE_ROAMING && pPlayer->GetObserverMode() != OBS_MODE_FIXED)*/ )
  5618. return false;
  5619. if ( args.ArgC() < 7 )
  5620. {
  5621. ClientPrint( this, HUD_PRINTCONSOLE, "Usage: spec_lerpto x y z pitch yaw lerptime\n");
  5622. return false;
  5623. }
  5624. Vector oldorigin = GetAbsOrigin();
  5625. Vector newpos;
  5626. newpos.x = clamp( atof(args[1]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5627. newpos.y = clamp( atof(args[2]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5628. newpos.z = clamp( atof(args[3]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5629. QAngle oldang = GetAbsAngles();
  5630. QAngle newang;
  5631. newang.x = clamp( atof(args[4]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5632. newang.y = clamp( atof(args[5]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  5633. newang.z = oldang.z;
  5634. // have to clear the observer target before we set the mode to roaming, otherwise it pops our position to the target
  5635. m_hObserverTarget.Set( NULL );
  5636. SetObserverMode( OBS_MODE_ROAMING );
  5637. m_iFOV.Set( GetDefaultFOV() );
  5638. SpecLerptoPosition( newpos, newang, clamp( atof(args[7]), MIN_COORD_FLOAT, MAX_COORD_FLOAT ) );
  5639. CBasePlayer *target = UTIL_PlayerByIndex( atoi(args[6]) );
  5640. if ( target )
  5641. {
  5642. m_hObserverTarget.Set( target );
  5643. IGameEvent *event = gameeventmanager->CreateEvent( "spec_target_updated" );
  5644. if ( event )
  5645. {
  5646. event->SetInt("userid", GetUserID() );
  5647. gameeventmanager->FireEventClientSide( event );
  5648. }
  5649. }
  5650. return true;
  5651. }
  5652. else if ( stricmp( cmd, "playerperf" ) == 0 )
  5653. {
  5654. int nRecip = entindex();
  5655. if ( args.ArgC() >= 2 )
  5656. {
  5657. nRecip = clamp( Q_atoi( args.Arg( 1 ) ), 1, gpGlobals->maxClients );
  5658. }
  5659. int nRecords = -1; // all
  5660. if ( args.ArgC() >= 3 )
  5661. {
  5662. nRecords = MAX( Q_atoi( args.Arg( 2 ) ), 1 );
  5663. }
  5664. CBasePlayer *pl = UTIL_PlayerByIndex( nRecip );
  5665. if ( pl )
  5666. {
  5667. pl->DumpPerfToRecipient( this, nRecords );
  5668. }
  5669. return true;
  5670. }
  5671. else if ( stricmp( cmd, "cameraman_request" ) == 0 )
  5672. {
  5673. CSteamID steamID;
  5674. if ( GetSteamID( &steamID ) )
  5675. {
  5676. if ( g_ServerGameDLL.ValidateAndAddActiveCaster( steamID ) )
  5677. {
  5678. // for now, also set this user as an active camera man
  5679. SetActiveCameraMan( true );
  5680. }
  5681. }
  5682. }
  5683. else if ( stricmp( cmd, "cameraman_ui_state" ) == 0 )
  5684. {
  5685. if ( GetTeamNumber() != TEAM_SPECTATOR )
  5686. return false;
  5687. if ( args.ArgC() > 1 )
  5688. {
  5689. int eventType = V_atoi( args[1] );
  5690. int nOptionalParam = 0;
  5691. if ( args.ArgC() > 2 )
  5692. {
  5693. nOptionalParam = V_atoi( args[2] );
  5694. }
  5695. switch ( eventType )
  5696. {
  5697. case HLTV_UI_XRAY_ON:
  5698. case HLTV_UI_XRAY_OFF:
  5699. m_bCameraManXRay = ( eventType == HLTV_UI_XRAY_ON );
  5700. break;
  5701. case HLTV_UI_SCOREBOARD_ON:
  5702. case HLTV_UI_SCOREBOARD_OFF:
  5703. m_bCameraManScoreBoard = ( eventType == HLTV_UI_SCOREBOARD_ON );
  5704. break;
  5705. case HLTV_UI_OVERVIEW_ON:
  5706. case HLTV_UI_OVERVIEW_OFF:
  5707. m_bCameraManOverview = ( eventType == HLTV_UI_OVERVIEW_ON );
  5708. break;
  5709. case HLTV_UI_GRAPHS_ON:
  5710. case HLTV_UI_GRAPHS_OFF:
  5711. m_uCameraManGraphs = ( ( eventType == HLTV_UI_GRAPHS_ON ) ? ( nOptionalParam + 1 ) : 0 );
  5712. break;
  5713. }
  5714. }
  5715. return true;
  5716. }
  5717. return false;
  5718. }
  5719. extern bool UTIL_ItemCanBeTouchedByPlayer( CBaseEntity *pItem, CBasePlayer *pPlayer );
  5720. //-----------------------------------------------------------------------------
  5721. // Purpose: Player reacts to bumping a weapon.
  5722. // Input : pWeapon - the weapon that the player bumped into.
  5723. // Output : Returns true if player picked up the weapon
  5724. //-----------------------------------------------------------------------------
  5725. bool CBasePlayer::BumpWeapon( CBaseCombatWeapon *pWeapon )
  5726. {
  5727. CBaseCombatCharacter *pOwner = pWeapon->GetOwner();
  5728. // Can I have this weapon type?
  5729. if ( !IsAllowedToPickupWeapons() )
  5730. return false;
  5731. if ( pOwner || !Weapon_CanUse( pWeapon ) || !g_pGameRules->CanHavePlayerItem( this, pWeapon ) )
  5732. {
  5733. if ( gEvilImpulse101 )
  5734. {
  5735. UTIL_Remove( pWeapon );
  5736. }
  5737. return false;
  5738. }
  5739. // Act differently in the episodes
  5740. if ( hl2_episodic.GetBool() )
  5741. {
  5742. // Don't let the player touch the item unless unobstructed
  5743. if ( !UTIL_ItemCanBeTouchedByPlayer( pWeapon, this ) && !gEvilImpulse101 )
  5744. return false;
  5745. }
  5746. else
  5747. {
  5748. // Don't let the player fetch weapons through walls (use MASK_SOLID so that you can't pickup through windows)
  5749. if( pWeapon->FVisible( this, MASK_SOLID ) == false && !(GetFlags() & FL_NOTARGET) )
  5750. return false;
  5751. }
  5752. // ----------------------------------------
  5753. // If I already have it just take the ammo
  5754. // ----------------------------------------
  5755. if (Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType()))
  5756. {
  5757. if( Weapon_EquipAmmoOnly( pWeapon ) )
  5758. {
  5759. // Only remove me if I have no ammo left
  5760. if ( pWeapon->HasPrimaryAmmo() )
  5761. return false;
  5762. UTIL_Remove( pWeapon );
  5763. return true;
  5764. }
  5765. else
  5766. {
  5767. return false;
  5768. }
  5769. }
  5770. // -------------------------
  5771. // Otherwise take the weapon
  5772. // -------------------------
  5773. else
  5774. {
  5775. pWeapon->CheckRespawn();
  5776. pWeapon->AddSolidFlags( FSOLID_NOT_SOLID );
  5777. pWeapon->AddEffects( EF_NODRAW );
  5778. Weapon_Equip( pWeapon );
  5779. if ( IsInAVehicle() )
  5780. {
  5781. pWeapon->Holster();
  5782. }
  5783. else
  5784. {
  5785. #ifdef HL2_DLL
  5786. if ( IsGameConsole() )
  5787. {
  5788. CFmtStr hint;
  5789. hint.sprintf( "#valve_hint_select_%s", pWeapon->GetClassname() );
  5790. UTIL_HudHintText( this, hint.Access() );
  5791. }
  5792. // Always switch to a newly-picked up weapon
  5793. if ( !PlayerHasMegaPhysCannon() )
  5794. {
  5795. // If it uses clips, load it full. (this is the first time you've picked up this type of weapon)
  5796. if ( pWeapon->UsesClipsForAmmo1() )
  5797. {
  5798. pWeapon->m_iClip1 = pWeapon->GetMaxClip1();
  5799. }
  5800. Weapon_Switch( pWeapon );
  5801. }
  5802. #endif
  5803. }
  5804. return true;
  5805. }
  5806. }
  5807. bool CBasePlayer::RemovePlayerItem( CBaseCombatWeapon *pItem )
  5808. {
  5809. if (GetActiveWeapon() == pItem)
  5810. {
  5811. ResetAutoaim( );
  5812. pItem->Holster( );
  5813. pItem->SetNextThink( TICK_NEVER_THINK );; // crowbar may be trying to swing again, etc
  5814. pItem->SetThink( NULL );
  5815. }
  5816. if ( m_hLastWeapon.Get() == pItem )
  5817. {
  5818. Weapon_SetLast( NULL );
  5819. }
  5820. return Weapon_Detach( pItem );
  5821. }
  5822. //-----------------------------------------------------------------------------
  5823. // Purpose: Hides or shows the player's view model. The "r_drawviewmodel" cvar
  5824. // can still hide the viewmodel even if this is set to true.
  5825. // Input : bShow - true to show, false to hide the view model.
  5826. //-----------------------------------------------------------------------------
  5827. void CBasePlayer::ShowViewModel(bool bShow)
  5828. {
  5829. m_Local.m_bDrawViewmodel = bShow;
  5830. }
  5831. //-----------------------------------------------------------------------------
  5832. // Purpose:
  5833. // Input : bDraw -
  5834. //-----------------------------------------------------------------------------
  5835. void CBasePlayer::ShowCrosshair( bool bShow )
  5836. {
  5837. if ( bShow )
  5838. {
  5839. m_Local.m_iHideHUD &= ~HIDEHUD_CROSSHAIR;
  5840. }
  5841. else
  5842. {
  5843. m_Local.m_iHideHUD |= HIDEHUD_CROSSHAIR;
  5844. }
  5845. }
  5846. //-----------------------------------------------------------------------------
  5847. // Used by vscript to determine if the player is noclipping
  5848. //-----------------------------------------------------------------------------
  5849. bool CBasePlayer::ScriptIsPlayerNoclipping( void )
  5850. {
  5851. return ( GetMoveType() == MOVETYPE_NOCLIP );
  5852. }
  5853. //-----------------------------------------------------------------------------
  5854. // Purpose:
  5855. //-----------------------------------------------------------------------------
  5856. QAngle CBasePlayer::BodyAngles()
  5857. {
  5858. return EyeAngles();
  5859. }
  5860. //------------------------------------------------------------------------------
  5861. // Purpose : Add noise to BodyTarget() to give enemy a better chance of
  5862. // getting a clear shot when the player is peeking above a hole
  5863. // or behind a ladder (eventually the randomly-picked point
  5864. // along the spine will be one that is exposed above the hole or
  5865. // between rungs of a ladder.)
  5866. // Input :
  5867. // Output :
  5868. //------------------------------------------------------------------------------
  5869. Vector CBasePlayer::BodyTarget( const Vector &posSrc, bool bNoisy )
  5870. {
  5871. if ( IsInAVehicle() )
  5872. {
  5873. return GetVehicle()->GetVehicleEnt()->BodyTarget( posSrc, bNoisy );
  5874. }
  5875. if (bNoisy)
  5876. {
  5877. return GetAbsOrigin() + (GetViewOffset() * random->RandomFloat( 0.7, 1.0 ));
  5878. }
  5879. else
  5880. {
  5881. return EyePosition();
  5882. }
  5883. };
  5884. /*
  5885. =========================================================
  5886. UpdateClientData
  5887. resends any changed player HUD info to the client.
  5888. Called every frame by PlayerPreThink
  5889. Also called at start of demo recording and playback by
  5890. ForceClientDllUpdate to ensure the demo gets messages
  5891. reflecting all of the HUD state info.
  5892. =========================================================
  5893. */
  5894. void CBasePlayer::UpdateClientData( void )
  5895. {
  5896. CSingleUserRecipientFilter user( this );
  5897. user.MakeReliable();
  5898. if (m_fInitHUD)
  5899. {
  5900. m_fInitHUD = false;
  5901. gInitHUD = false;
  5902. CCSUsrMsg_ResetHud msg;
  5903. msg.set_reset( 0 );
  5904. SendUserMessage( user, CS_UM_ResetHud, msg );
  5905. if ( !m_fGameHUDInitialized )
  5906. {
  5907. g_pGameRules->InitHUD( this );
  5908. InitHUD();
  5909. m_fGameHUDInitialized = true;
  5910. if ( g_pGameRules->IsMultiplayer() )
  5911. {
  5912. variant_t value;
  5913. g_EventQueue.AddEvent( "game_player_manager", "OnPlayerJoin", value, 0, this, this );
  5914. }
  5915. }
  5916. variant_t value;
  5917. g_EventQueue.AddEvent( "game_player_manager", "OnPlayerSpawn", value, 0, this, this );
  5918. }
  5919. // HACKHACK -- send the message to display the game title
  5920. CWorld *world = GetWorldEntity();
  5921. if ( world && world->GetDisplayTitle() )
  5922. {
  5923. CCSUsrMsg_GameTitle msg;
  5924. SendUserMessage( user, CS_UM_GameTitle, msg );
  5925. world->SetDisplayTitle( false );
  5926. }
  5927. UpdateBattery();
  5928. #if 0 // BYE BYE!!
  5929. // Update Flashlight
  5930. if ((m_flFlashLightTime) && (m_flFlashLightTime <= gpGlobals->curtime))
  5931. {
  5932. if (FlashlightIsOn())
  5933. {
  5934. if (m_iFlashBattery)
  5935. {
  5936. m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->curtime;
  5937. m_iFlashBattery--;
  5938. if (!m_iFlashBattery)
  5939. FlashlightTurnOff();
  5940. }
  5941. }
  5942. else
  5943. {
  5944. if (m_iFlashBattery < 100)
  5945. {
  5946. m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->curtime;
  5947. m_iFlashBattery++;
  5948. }
  5949. else
  5950. m_flFlashLightTime = 0;
  5951. }
  5952. }
  5953. #endif
  5954. CheckTrainUpdate();
  5955. // Update all the items
  5956. for ( int i = 0; i < WeaponCount(); i++ )
  5957. {
  5958. if ( GetWeapon(i) ) // each item updates it's successors
  5959. GetWeapon(i)->UpdateClientData( this );
  5960. }
  5961. // update the client with our poison state
  5962. m_Local.m_bPoisoned = ( m_bitsDamageType & DMG_POISON )
  5963. && ( m_nPoisonDmg > m_nPoisonRestored )
  5964. && ( m_iHealth < 100 );
  5965. // Check if the bonus progress HUD element should be displayed
  5966. if ( m_iBonusChallenge == 0 && m_iBonusProgress == 0 && !( m_Local.m_iHideHUD & HIDEHUD_BONUS_PROGRESS ) )
  5967. m_Local.m_iHideHUD |= HIDEHUD_BONUS_PROGRESS;
  5968. if ( ( m_iBonusChallenge != 0 )&& ( m_Local.m_iHideHUD & HIDEHUD_BONUS_PROGRESS ) )
  5969. m_Local.m_iHideHUD &= ~HIDEHUD_BONUS_PROGRESS;
  5970. // make sure these hud elements are always in the correct state
  5971. m_Local.m_iHideHUD &= ~HIDEHUD_HEALTH;
  5972. m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION;
  5973. // Let any global rules update the HUD, too
  5974. g_pGameRules->UpdateClientData( this );
  5975. }
  5976. void CBasePlayer::UpdateBattery( void )
  5977. {
  5978. if (m_ArmorValue != m_iClientBattery)
  5979. {
  5980. m_iClientBattery = m_ArmorValue;
  5981. }
  5982. }
  5983. void CBasePlayer::RumbleEffect( unsigned char index, unsigned char rumbleData, unsigned char rumbleFlags )
  5984. {
  5985. if( !IsAlive() )
  5986. return;
  5987. CSingleUserRecipientFilter filter( this );
  5988. filter.MakeReliable();
  5989. CCSUsrMsg_Rumble msg;
  5990. msg.set_index( index );
  5991. msg.set_data( rumbleData );
  5992. msg.set_flags( rumbleFlags );
  5993. SendUserMessage( filter, CS_UM_Rumble, msg );
  5994. }
  5995. void CBasePlayer::EnableControl(bool fControl)
  5996. {
  5997. if (!fControl)
  5998. AddFlag( FL_FROZEN );
  5999. else
  6000. RemoveFlag( FL_FROZEN );
  6001. }
  6002. void CBasePlayer::CheckTrainUpdate( void )
  6003. {
  6004. if ( ( m_iTrain & TRAIN_NEW ) )
  6005. {
  6006. CSingleUserRecipientFilter user( this );
  6007. user.MakeReliable();
  6008. CCSUsrMsg_Train msg;
  6009. msg.set_train( m_iTrain & 0xF );
  6010. SendUserMessage( user, CS_UM_Train, msg );
  6011. m_iTrain &= ~TRAIN_NEW;
  6012. }
  6013. }
  6014. //-----------------------------------------------------------------------------
  6015. // Purpose: Returns whether the player should autoaim or not
  6016. // Output : Returns true on success, false on failure.
  6017. //-----------------------------------------------------------------------------
  6018. bool CBasePlayer::ShouldAutoaim( void )
  6019. {
  6020. if ( IsBot() )
  6021. {
  6022. return false;
  6023. }
  6024. // autoaim if the client isn't using mouse.
  6025. // if ( atoi( engine->GetClientConVarValue( entindex(), "cl_mouselook" ) ) == 0 )
  6026. // return true;
  6027. // cannot be in multiplayer
  6028. if ( gpGlobals->maxClients > 1 )
  6029. return false;
  6030. // autoaiming is only for easy and medium skill
  6031. return ( IsGameConsole() || !g_pGameRules->IsSkillLevel(SKILL_HARD) );
  6032. }
  6033. //-----------------------------------------------------------------------------
  6034. //-----------------------------------------------------------------------------
  6035. Vector CBasePlayer::GetAutoaimVector( float flScale )
  6036. {
  6037. autoaim_params_t params;
  6038. params.m_fScale = flScale;
  6039. params.m_fMaxDist = autoaim_max_dist.GetFloat();
  6040. params.m_fMaxDeflection = -1.0f;//use active weapons default
  6041. GetAutoaimVector( params );
  6042. return params.m_vecAutoAimDir;
  6043. }
  6044. //-----------------------------------------------------------------------------
  6045. //-----------------------------------------------------------------------------
  6046. Vector CBasePlayer::GetAutoaimVector( float flScale, float flMaxDist )
  6047. {
  6048. autoaim_params_t params;
  6049. params.m_fScale = flScale;
  6050. params.m_fMaxDist = flMaxDist;
  6051. params.m_fMaxDeflection = -1.0f;//use active weapons default
  6052. GetAutoaimVector( params );
  6053. return params.m_vecAutoAimDir;
  6054. }
  6055. //-----------------------------------------------------------------------------
  6056. //-----------------------------------------------------------------------------
  6057. Vector CBasePlayer::GetAutoaimVector( float flScale, float flMaxDist, float flMaxDeflection, AimResults *pAimResults )
  6058. {
  6059. autoaim_params_t params;
  6060. params.m_fScale = flScale;
  6061. params.m_fMaxDist = flMaxDist;
  6062. params.m_fMaxDeflection = flMaxDeflection;
  6063. GetAutoaimVector( params );
  6064. *pAimResults = AIMRESULTS_NONE;
  6065. if ( params.m_bOnTargetNatural )
  6066. {
  6067. *pAimResults = AIMRESULTS_ONTARGET;
  6068. }
  6069. else if ( params.m_bAutoAimAssisting )
  6070. {
  6071. *pAimResults = AIMRESULTS_ASSISTED;
  6072. }
  6073. return params.m_vecAutoAimDir;
  6074. }
  6075. //-----------------------------------------------------------------------------
  6076. //-----------------------------------------------------------------------------
  6077. void CBasePlayer::GetAutoaimVector( autoaim_params_t &params )
  6078. {
  6079. // default results
  6080. params.m_bAutoAimAssisting = false;
  6081. params.m_bOnTargetNatural = false;
  6082. params.m_hAutoAimEntity.Set( NULL );
  6083. params.m_vecAutoAimPoint = vec3_invalid;
  6084. if ( ( ShouldAutoaim() == false ) || ( params.m_fScale == AUTOAIM_SCALE_DIRECT_ONLY ) )
  6085. {
  6086. Vector forward;
  6087. AngleVectors( EyeAngles() + m_Local.m_viewPunchAngle, &forward );
  6088. params.m_vecAutoAimDir = forward;
  6089. return;
  6090. }
  6091. Vector vecShootPosition = Weapon_ShootPosition();
  6092. QAngle angles = AutoaimDeflection( vecShootPosition, params );
  6093. // update ontarget if changed
  6094. if ( !g_pGameRules->AllowAutoTargetCrosshair() )
  6095. {
  6096. m_fOnTarget = false;
  6097. }
  6098. if (angles.x > 180)
  6099. angles.x -= 360;
  6100. if (angles.x < -180)
  6101. angles.x += 360;
  6102. if (angles.y > 180)
  6103. angles.y -= 360;
  6104. if (angles.y < -180)
  6105. angles.y += 360;
  6106. if (angles.x > 25)
  6107. angles.x = 25;
  6108. if (angles.x < -25)
  6109. angles.x = -25;
  6110. if (angles.y > 12)
  6111. angles.y = 12;
  6112. if (angles.y < -12)
  6113. angles.y = -12;
  6114. m_vecAutoAim.Init( 0.0f, 0.0f, 0.0f );
  6115. Vector forward;
  6116. if ( ( IsInAVehicle() && g_pGameRules->GetAutoAimMode() == AUTOAIM_ON_CONSOLE ) )
  6117. {
  6118. m_vecAutoAim = angles;
  6119. AngleVectors( EyeAngles() + m_vecAutoAim, &forward );
  6120. }
  6121. else
  6122. {
  6123. // always use non-sticky autoaim
  6124. m_vecAutoAim = angles * 0.9f;
  6125. AngleVectors( EyeAngles() + m_Local.m_viewPunchAngle + m_vecAutoAim, &forward );
  6126. }
  6127. params.m_vecAutoAimDir = forward;
  6128. }
  6129. //-----------------------------------------------------------------------------
  6130. // Targets represent themselves to autoaim as a viewplane-parallel disc with
  6131. // a radius specified by the target. The player then modifies this radius
  6132. // to achieve more or less aggressive aiming assistance.
  6133. // Returns [0..1], 0 is outside of disc, approaching 1 is approaching center of disc.
  6134. //-----------------------------------------------------------------------------
  6135. float CBasePlayer::GetAutoaimScore( const Vector &eyePosition, const Vector &viewDir, const Vector &vecTarget, CBaseEntity *pTarget, float fScale, CBaseCombatWeapon *pActiveWeapon )
  6136. {
  6137. float targetRadius = pTarget->GetAutoAimRadius();
  6138. if ( fScale != 1.0f )
  6139. {
  6140. // use provided radius scale
  6141. targetRadius *= fScale;
  6142. }
  6143. else if ( pActiveWeapon )
  6144. {
  6145. // use default radius scale
  6146. targetRadius *= pActiveWeapon->WeaponAutoAimScale();
  6147. }
  6148. float targetRadiusSqr = Square( targetRadius );
  6149. Vector vecNearestPoint = PointOnLineNearestPoint( eyePosition, eyePosition + viewDir * 8192, vecTarget );
  6150. Vector vecDiff = vecTarget - vecNearestPoint;
  6151. float radiusSqr = vecDiff.LengthSqr();
  6152. float score;
  6153. if ( radiusSqr <= targetRadiusSqr )
  6154. {
  6155. // target radius intersects aim vector
  6156. score = 1.0f - (radiusSqr / targetRadiusSqr);
  6157. Assert( score >= 0.0f && score <= 1.0f );
  6158. }
  6159. else
  6160. {
  6161. // target radius does not intersect aim vector
  6162. // 0 means no score- doesn't qualify for autoaim.
  6163. score = 0.0f;
  6164. }
  6165. return score;
  6166. }
  6167. //-----------------------------------------------------------------------------
  6168. // Purpose:
  6169. // Input : &vecSrc -
  6170. // flDist -
  6171. // flDelta -
  6172. // Output : Vector
  6173. //-----------------------------------------------------------------------------
  6174. class CTraceFilterSkipTwoEntitiesAndTeammates : public CTraceFilterSkipTwoEntities
  6175. {
  6176. public:
  6177. CTraceFilterSkipTwoEntitiesAndTeammates( const IHandleEntity *passentity = NULL, const IHandleEntity *passentity2 = NULL, int collisionGroup = COLLISION_GROUP_NONE ) :
  6178. CTraceFilterSkipTwoEntities( passentity, passentity2, collisionGroup )
  6179. {
  6180. }
  6181. bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  6182. {
  6183. CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
  6184. if ( !pEntity )
  6185. return false;
  6186. const CBaseEntity *pSelf = EntityFromEntityHandle( GetPassEntity() );
  6187. if ( !pSelf )
  6188. return false;
  6189. if ( pSelf->GetTeamNumber() == pEntity->GetTeamNumber() )
  6190. {
  6191. return false;
  6192. }
  6193. return CTraceFilterSkipTwoEntities::ShouldHitEntity( pHandleEntity, contentsMask );
  6194. }
  6195. };
  6196. QAngle CBasePlayer::AutoaimDeflection( Vector &vecSrc, autoaim_params_t &params )
  6197. {
  6198. float bestscore;
  6199. float score;
  6200. QAngle eyeAngles;
  6201. Vector bestdir;
  6202. CBaseEntity *bestent;
  6203. trace_t tr;
  6204. Vector v_forward, v_right, v_up;
  6205. QAngle bestang;
  6206. m_fOnTarget = false;
  6207. eyeAngles = EyeAngles();
  6208. AngleVectors( eyeAngles + m_Local.m_viewPunchAngle + m_vecAutoAim, &v_forward, &v_right, &v_up );
  6209. // try all possible entities
  6210. bestdir = v_forward;
  6211. bestscore = 0.0f;
  6212. bestent = NULL;
  6213. bestang = vec3_angle;
  6214. CBaseEntity *pIgnore = NULL;
  6215. if ( IsInAVehicle() )
  6216. {
  6217. pIgnore = GetVehicleEntity();
  6218. }
  6219. CTraceFilterSkipTwoEntitiesAndTeammates traceFilter( this, pIgnore, COLLISION_GROUP_NONE );
  6220. UTIL_TraceLine( vecSrc, vecSrc + bestdir * MAX_COORD_FLOAT, MASK_SHOT, &traceFilter, &tr );
  6221. // check for on-target
  6222. CBaseEntity *pEntHit = tr.m_pEnt;
  6223. if ( pEntHit && pEntHit->m_takedamage != DAMAGE_NO && pEntHit->IsAlive() )
  6224. {
  6225. // don't look through water
  6226. if ( !((GetWaterLevel() != WL_Eyes && pEntHit->GetWaterLevel() == WL_Eyes) || (GetWaterLevel() == WL_Eyes && pEntHit->GetWaterLevel() == WL_NotInWater)) )
  6227. {
  6228. if ( pEntHit->ShouldAttractAutoAim( this ) )
  6229. {
  6230. bool bAimAtThis = true;
  6231. if ( pEntHit->IsNPC() && g_pGameRules->GetAutoAimMode() > AUTOAIM_NONE )
  6232. {
  6233. int iRelationType = GetDefaultRelationshipDisposition( pEntHit->Classify() );
  6234. if ( iRelationType != D_HT )
  6235. {
  6236. bAimAtThis = false;
  6237. }
  6238. }
  6239. if ( bAimAtThis )
  6240. {
  6241. if ( pEntHit->GetFlags() & FL_AIMTARGET )
  6242. {
  6243. m_fOnTarget = true;
  6244. }
  6245. // Player is already on target naturally, don't autoaim.
  6246. // Fill out the autoaim_params_t struct, though.
  6247. params.m_hAutoAimEntity.Set( pEntHit );
  6248. params.m_vecAutoAimDir = bestdir;
  6249. params.m_vecAutoAimPoint = tr.endpos;
  6250. params.m_bAutoAimAssisting = false;
  6251. params.m_bOnTargetNatural = true;
  6252. }
  6253. }
  6254. // Not on target, fall through and look for an autoaim target
  6255. }
  6256. }
  6257. int count = AimTarget_ListCount();
  6258. if ( count )
  6259. {
  6260. CBaseEntity **pList = (CBaseEntity **)stackalloc( sizeof(CBaseEntity *) * count );
  6261. AimTarget_ListCopy( pList, count );
  6262. for ( int i = 0; i < count; i++ )
  6263. {
  6264. Vector center;
  6265. Vector dir;
  6266. CBaseEntity *pEntity = pList[i];
  6267. // Don't autoaim at anything that doesn't want to be.
  6268. if( !pEntity->ShouldAttractAutoAim(this) )
  6269. continue;
  6270. // Don't shoot yourself
  6271. if ( pEntity == this )
  6272. continue;
  6273. if ( (pEntity->IsNPC() && !pEntity->IsAlive()) || !pEntity->edict() )
  6274. continue;
  6275. if ( !g_pGameRules->ShouldAutoAim( this, pEntity->edict() ) )
  6276. continue;
  6277. // don't look through water
  6278. if ((GetWaterLevel() != WL_Eyes && pEntity->GetWaterLevel() == WL_Eyes) || (GetWaterLevel() == WL_Eyes && pEntity->GetWaterLevel() == WL_NotInWater))
  6279. continue;
  6280. if( pEntity->MyNPCPointer() )
  6281. {
  6282. // If this entity is an NPC, only aim if it is an enemy.
  6283. if ( IRelationType( pEntity ) != D_HT )
  6284. {
  6285. if ( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch())
  6286. // Msg( "friend\n");
  6287. continue;
  6288. }
  6289. }
  6290. // Don't autoaim at the noisy bodytarget, this makes the autoaim crosshair wobble.
  6291. //center = pEntity->BodyTarget( vecSrc, false );
  6292. center = pEntity->WorldSpaceCenter();
  6293. dir = (center - vecSrc);
  6294. float dist = dir.Length2D();
  6295. VectorNormalize( dir );
  6296. // Skip if out of range.
  6297. if( dist > params.m_fMaxDist )
  6298. continue;
  6299. float dot = DotProduct (dir, v_forward );
  6300. // make sure it's in front of the player
  6301. if( dot < 0 )
  6302. continue;
  6303. if( !(pEntity->GetFlags() & FL_FLY) )
  6304. {
  6305. // Refuse to take wild shots at targets far from reticle.
  6306. if( GetActiveWeapon() != NULL && dot < GetActiveWeapon()->GetMaxAutoAimDeflection() )
  6307. {
  6308. // Be lenient if the player is looking down, though. 30 degrees through 90 degrees of pitch.
  6309. // (90 degrees is looking down at player's own 'feet'. Looking straight ahead is 0 degrees pitch.
  6310. // This was done for XBox to make it easier to fight headcrabs around the player's feet.
  6311. if( eyeAngles.x < 30.0f || eyeAngles.x > 90.0f || g_pGameRules->GetAutoAimMode() != AUTOAIM_ON_CONSOLE )
  6312. {
  6313. continue;
  6314. }
  6315. }
  6316. }
  6317. score = GetAutoaimScore(vecSrc, v_forward, pEntity->GetAutoAimCenter(), pEntity, params.m_fScale, GetActiveWeapon() );
  6318. if( score <= bestscore )
  6319. {
  6320. continue;
  6321. }
  6322. UTIL_TraceLine( vecSrc, center, MASK_SHOT, &traceFilter, &tr );
  6323. if (tr.fraction != 1.0 && tr.m_pEnt != pEntity )
  6324. {
  6325. // Msg( "hit %s, can't see %s\n", STRING( tr.u.ent->classname ), STRING( pEdict->classname ) );
  6326. continue;
  6327. }
  6328. // This is the best candidate so far.
  6329. bestscore = score;
  6330. bestent = pEntity;
  6331. bestdir = dir;
  6332. }
  6333. if ( bestent )
  6334. {
  6335. QAngle bestang;
  6336. VectorAngles( bestdir, bestang );
  6337. if( IsInAVehicle() )
  6338. {
  6339. bestang -= EyeAngles();
  6340. }
  6341. else
  6342. {
  6343. bestang -= EyeAngles() - m_Local.m_viewPunchAngle;
  6344. }
  6345. m_fOnTarget = true;
  6346. // Autoaim detected a target for us. Aim automatically at its bodytarget.
  6347. params.m_hAutoAimEntity.Set(bestent);
  6348. params.m_vecAutoAimDir = bestdir;
  6349. params.m_vecAutoAimPoint = bestent->BodyTarget( vecSrc, false );
  6350. params.m_bAutoAimAssisting = true;
  6351. return bestang;
  6352. }
  6353. }
  6354. float maxDeflection = params.m_fMaxDeflection;
  6355. if ( maxDeflection < 0 )
  6356. {
  6357. // use the weapon's specification
  6358. maxDeflection = GetActiveWeapon()->GetMaxAutoAimDeflection();
  6359. }
  6360. return bestang;
  6361. }
  6362. //-----------------------------------------------------------------------------
  6363. // Purpose:
  6364. //-----------------------------------------------------------------------------
  6365. void CBasePlayer::ResetAutoaim( void )
  6366. {
  6367. m_vecAutoAim.Init( 0.0f, 0.0f, 0.0f );
  6368. engine->CrosshairAngle( edict(), 0, 0 );
  6369. m_fOnTarget = false;
  6370. }
  6371. // ==========================================================================
  6372. // > Weapon stuff
  6373. // ==========================================================================
  6374. //-----------------------------------------------------------------------------
  6375. // Purpose:
  6376. // Input : weaponSlot -
  6377. //-----------------------------------------------------------------------------
  6378. void CBasePlayer::Weapon_DropSlot( int weaponSlot )
  6379. {
  6380. CBaseCombatWeapon *pWeapon;
  6381. // Check for that slot being occupied already
  6382. for ( int i=0; i < MAX_WEAPONS; i++ )
  6383. {
  6384. pWeapon = GetWeapon( i );
  6385. if ( pWeapon != NULL )
  6386. {
  6387. // If the slots match, it's already occupied
  6388. if ( pWeapon->GetSlot() == weaponSlot )
  6389. {
  6390. Weapon_Drop( pWeapon, NULL, NULL );
  6391. }
  6392. }
  6393. }
  6394. }
  6395. //-----------------------------------------------------------------------------
  6396. // Purpose: Override to add weapon to the hud
  6397. //-----------------------------------------------------------------------------
  6398. void CBasePlayer::Weapon_Equip( CBaseCombatWeapon *pWeapon )
  6399. {
  6400. BaseClass::Weapon_Equip( pWeapon );
  6401. bool bShouldSwitch = g_pGameRules->FShouldSwitchWeapon( this, pWeapon );
  6402. #ifdef HL2_DLL
  6403. if ( bShouldSwitch == false && PhysCannonGetHeldEntity( GetActiveWeapon() ) == pWeapon &&
  6404. Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType()) )
  6405. {
  6406. bShouldSwitch = true;
  6407. }
  6408. #endif//HL2_DLL
  6409. // should we switch to this item?
  6410. if ( bShouldSwitch )
  6411. {
  6412. Weapon_Switch( pWeapon );
  6413. }
  6414. }
  6415. //=========================================================
  6416. // HasNamedPlayerItem Does the player already have this item?
  6417. //=========================================================
  6418. CBaseEntity *CBasePlayer::HasNamedPlayerItem( const char *pszItemName )
  6419. {
  6420. for ( int i = 0 ; i < WeaponCount() ; i++ )
  6421. {
  6422. if ( !GetWeapon(i) )
  6423. continue;
  6424. if ( FStrEq( pszItemName, GetWeapon(i)->GetClassname() ) )
  6425. {
  6426. return GetWeapon(i);
  6427. }
  6428. }
  6429. return NULL;
  6430. }
  6431. //================================================================================
  6432. // TEAM HANDLING
  6433. //================================================================================
  6434. //-----------------------------------------------------------------------------
  6435. // Purpose: Put the player in the specified team
  6436. //-----------------------------------------------------------------------------
  6437. void CBasePlayer::ChangeTeam( int iTeamNum, bool bAutoTeam, bool bSilent)
  6438. {
  6439. if ( !GetGlobalTeam( iTeamNum ) )
  6440. {
  6441. Warning( "CBasePlayer::ChangeTeam( %d ) - invalid team index.\n", iTeamNum );
  6442. return;
  6443. }
  6444. // if this is our current team, just abort
  6445. if ( iTeamNum == GetTeamNumber() )
  6446. {
  6447. return;
  6448. }
  6449. SetPendingTeamNum( iTeamNum );
  6450. // Immediately tell all clients that he's changing team. This has to be done
  6451. // first, so that all user messages that follow as a result of the team change
  6452. // come after this one, allowing the client to be prepared for them.
  6453. IGameEvent * event = gameeventmanager->CreateEvent( "player_team" );
  6454. if ( event )
  6455. {
  6456. event->SetInt("userid", GetUserID() );
  6457. event->SetInt("team", iTeamNum );
  6458. event->SetInt("oldteam", GetTeamNumber() );
  6459. event->SetInt("disconnect", IsDisconnecting());
  6460. event->SetInt("autoteam", bAutoTeam );
  6461. event->SetInt("silent", bSilent || ( g_pGameRules && g_pGameRules->IsTeamChangeSilent( this, iTeamNum, bAutoTeam, bSilent ) ) );
  6462. if ( GetTeamNumber() == TEAM_UNASSIGNED )
  6463. {
  6464. event->SetString( "name", GetPlayerName() );
  6465. }
  6466. else
  6467. {
  6468. event->SetString( "name", "" ); // don't bother sending the name except on the first connect
  6469. }
  6470. event->SetBool("isbot", !IsNetClient());
  6471. gameeventmanager->FireEvent( event );
  6472. }
  6473. // Remove him from his current team
  6474. if ( GetTeam() )
  6475. {
  6476. GetTeam()->RemovePlayer( this );
  6477. }
  6478. // Are we being added to a team?
  6479. if ( iTeamNum )
  6480. {
  6481. GetGlobalTeam( iTeamNum )->AddPlayer( this );
  6482. }
  6483. BaseClass::ChangeTeam( iTeamNum );
  6484. }
  6485. //-----------------------------------------------------------------------------
  6486. // Purpose: Locks a player to the spot; they can't move, shoot, or be hurt
  6487. //-----------------------------------------------------------------------------
  6488. void CBasePlayer::LockPlayerInPlace( void )
  6489. {
  6490. if ( m_iPlayerLocked )
  6491. return;
  6492. AddFlag( FL_GODMODE | FL_FROZEN );
  6493. SetMoveType( MOVETYPE_NONE );
  6494. m_iPlayerLocked = true;
  6495. // force a client data update, so that anything that has been done to
  6496. // this player previously this frame won't get delayed in being sent
  6497. UpdateClientData();
  6498. }
  6499. //-----------------------------------------------------------------------------
  6500. // Purpose: Unlocks a previously locked player
  6501. //-----------------------------------------------------------------------------
  6502. void CBasePlayer::UnlockPlayer( void )
  6503. {
  6504. if ( !m_iPlayerLocked )
  6505. return;
  6506. RemoveFlag( FL_GODMODE | FL_FROZEN );
  6507. SetMoveType( MOVETYPE_WALK );
  6508. m_iPlayerLocked = false;
  6509. }
  6510. CBaseEntity* CBasePlayer::GetUseEntity( void )
  6511. {
  6512. return m_hUseEntity;
  6513. }
  6514. CBaseEntity* CBasePlayer::GetPotentialUseEntity( void )
  6515. {
  6516. return GetUseEntity();
  6517. }
  6518. //-----------------------------------------------------------------------------
  6519. // Purpose:
  6520. //-----------------------------------------------------------------------------
  6521. void CBasePlayer::HideViewModels( void )
  6522. {
  6523. for ( int i = 0 ; i < MAX_VIEWMODELS; i++ )
  6524. {
  6525. CBaseViewModel *vm = GetViewModel( i );
  6526. if ( !vm )
  6527. continue;
  6528. vm->SetWeaponModel( NULL, NULL );
  6529. }
  6530. }
  6531. class CStripWeapons : public CPointEntity
  6532. {
  6533. DECLARE_CLASS( CStripWeapons, CPointEntity );
  6534. public:
  6535. void InputStripWeapons(inputdata_t &data);
  6536. void InputStripWeaponsAndSuit(inputdata_t &data);
  6537. void StripWeapons(inputdata_t &data, bool stripSuit);
  6538. DECLARE_DATADESC();
  6539. };
  6540. LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons );
  6541. BEGIN_DATADESC( CStripWeapons )
  6542. DEFINE_INPUTFUNC( FIELD_VOID, "Strip", InputStripWeapons ),
  6543. DEFINE_INPUTFUNC( FIELD_VOID, "StripWeaponsAndSuit", InputStripWeaponsAndSuit ),
  6544. END_DATADESC()
  6545. void CStripWeapons::InputStripWeapons(inputdata_t &data)
  6546. {
  6547. StripWeapons(data, false);
  6548. }
  6549. void CStripWeapons::InputStripWeaponsAndSuit(inputdata_t &data)
  6550. {
  6551. StripWeapons(data, true);
  6552. }
  6553. void CStripWeapons::StripWeapons(inputdata_t &data, bool stripSuit)
  6554. {
  6555. CBasePlayer *pPlayer = NULL;
  6556. if ( data.pActivator && data.pActivator->IsPlayer() )
  6557. {
  6558. pPlayer = (CBasePlayer *)data.pActivator;
  6559. }
  6560. else if ( !g_pGameRules->IsDeathmatch() )
  6561. {
  6562. pPlayer = UTIL_GetLocalPlayer();
  6563. }
  6564. if ( pPlayer )
  6565. {
  6566. pPlayer->RemoveAllItems( stripSuit );
  6567. }
  6568. }
  6569. class CRevertSaved : public CPointEntity
  6570. {
  6571. DECLARE_CLASS( CRevertSaved, CPointEntity );
  6572. public:
  6573. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  6574. void LoadThink( void );
  6575. DECLARE_DATADESC();
  6576. inline float Duration( void ) { return m_Duration; }
  6577. inline float HoldTime( void ) { return m_HoldTime; }
  6578. inline float LoadTime( void ) { return m_loadTime; }
  6579. inline void SetDuration( float duration ) { m_Duration = duration; }
  6580. inline void SetHoldTime( float hold ) { m_HoldTime = hold; }
  6581. inline void SetLoadTime( float time ) { m_loadTime = time; }
  6582. //Inputs
  6583. void InputReload(inputdata_t &data);
  6584. private:
  6585. float m_loadTime;
  6586. float m_Duration;
  6587. float m_HoldTime;
  6588. };
  6589. LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved );
  6590. BEGIN_DATADESC( CRevertSaved )
  6591. DEFINE_KEYFIELD( m_loadTime, FIELD_FLOAT, "loadtime" ),
  6592. DEFINE_KEYFIELD( m_Duration, FIELD_FLOAT, "duration" ),
  6593. DEFINE_KEYFIELD( m_HoldTime, FIELD_FLOAT, "holdtime" ),
  6594. DEFINE_INPUTFUNC( FIELD_VOID, "Reload", InputReload ),
  6595. // Function Pointers
  6596. DEFINE_FUNCTION( LoadThink ),
  6597. END_DATADESC()
  6598. CEG_NOINLINE CBaseEntity *CreatePlayerLoadSave( Vector vOrigin, float flDuration, float flHoldTime, float flLoadTime )
  6599. {
  6600. CRevertSaved *pRevertSaved = (CRevertSaved *) CreateEntityByName( "player_loadsaved" );
  6601. if ( pRevertSaved == NULL )
  6602. return NULL;
  6603. UTIL_SetOrigin( pRevertSaved, vOrigin );
  6604. pRevertSaved->Spawn();
  6605. pRevertSaved->SetDuration( flDuration );
  6606. pRevertSaved->SetHoldTime( flHoldTime );
  6607. pRevertSaved->SetLoadTime( flLoadTime );
  6608. return pRevertSaved;
  6609. }
  6610. CEG_PROTECT_FUNCTION( CreatePlayerLoadSave );
  6611. void CRevertSaved::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  6612. {
  6613. UTIL_ScreenFadeAll( m_clrRender, Duration(), HoldTime(), FFADE_OUT );
  6614. SetNextThink( gpGlobals->curtime + LoadTime() );
  6615. SetThink( &CRevertSaved::LoadThink );
  6616. CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
  6617. if ( pPlayer )
  6618. {
  6619. //Adrian: Setting this flag so we can't move or save a game.
  6620. pPlayer->pl.deadflag = true;
  6621. pPlayer->AddFlag( (FL_NOTARGET|FL_FROZEN) );
  6622. // clear any pending autosavedangerous
  6623. g_ServerGameDLL.m_fAutoSaveDangerousTime = 0.0f;
  6624. g_ServerGameDLL.m_fAutoSaveDangerousMinHealthToCommit = 0.0f;
  6625. }
  6626. }
  6627. void CRevertSaved::InputReload( inputdata_t &inputdata )
  6628. {
  6629. UTIL_ScreenFadeAll( m_clrRender, Duration(), HoldTime(), FFADE_OUT );
  6630. SetNextThink( gpGlobals->curtime + LoadTime() );
  6631. SetThink( &CRevertSaved::LoadThink );
  6632. CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
  6633. if ( pPlayer )
  6634. {
  6635. //Adrian: Setting this flag so we can't move or save a game.
  6636. pPlayer->pl.deadflag = true;
  6637. pPlayer->AddFlag( (FL_NOTARGET|FL_FROZEN) );
  6638. // clear any pending autosavedangerous
  6639. g_ServerGameDLL.m_fAutoSaveDangerousTime = 0.0f;
  6640. g_ServerGameDLL.m_fAutoSaveDangerousMinHealthToCommit = 0.0f;
  6641. }
  6642. }
  6643. void CRevertSaved::LoadThink( void )
  6644. {
  6645. if ( !gpGlobals->deathmatch )
  6646. {
  6647. engine->ServerCommand("reload\n");
  6648. }
  6649. }
  6650. #define SF_SPEED_MOD_SUPPRESS_WEAPONS (1<<0) // Take away weapons
  6651. #define SF_SPEED_MOD_SUPPRESS_HUD (1<<1) // Take away the HUD
  6652. #define SF_SPEED_MOD_SUPPRESS_JUMP (1<<2)
  6653. #define SF_SPEED_MOD_SUPPRESS_DUCK (1<<3)
  6654. #define SF_SPEED_MOD_SUPPRESS_USE (1<<4)
  6655. #define SF_SPEED_MOD_SUPPRESS_SPEED (1<<5)
  6656. #define SF_SPEED_MOD_SUPPRESS_ATTACK (1<<6)
  6657. #define SF_SPEED_MOD_SUPPRESS_ZOOM (1<<7)
  6658. class CMovementSpeedMod : public CPointEntity
  6659. {
  6660. DECLARE_CLASS( CMovementSpeedMod, CPointEntity );
  6661. public:
  6662. void InputSpeedMod(inputdata_t &data);
  6663. private:
  6664. int GetDisabledButtonMask( void );
  6665. DECLARE_DATADESC();
  6666. };
  6667. LINK_ENTITY_TO_CLASS( player_speedmod, CMovementSpeedMod );
  6668. BEGIN_DATADESC( CMovementSpeedMod )
  6669. DEFINE_INPUTFUNC( FIELD_FLOAT, "ModifySpeed", InputSpeedMod ),
  6670. END_DATADESC()
  6671. int CMovementSpeedMod::GetDisabledButtonMask( void )
  6672. {
  6673. int nMask = 0;
  6674. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_JUMP ) )
  6675. {
  6676. nMask |= IN_JUMP;
  6677. }
  6678. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_DUCK ) )
  6679. {
  6680. nMask |= IN_DUCK;
  6681. }
  6682. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_USE ) )
  6683. {
  6684. nMask |= IN_USE;
  6685. }
  6686. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_SPEED ) )
  6687. {
  6688. nMask |= IN_SPEED;
  6689. }
  6690. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_ATTACK ) )
  6691. {
  6692. nMask |= (IN_ATTACK|IN_ATTACK2);
  6693. }
  6694. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_ZOOM ) )
  6695. {
  6696. nMask |= IN_ZOOM;
  6697. }
  6698. return nMask;
  6699. }
  6700. void CMovementSpeedMod::InputSpeedMod(inputdata_t &data)
  6701. {
  6702. CBasePlayer *pPlayer = NULL;
  6703. if ( data.pActivator && data.pActivator->IsPlayer() )
  6704. {
  6705. pPlayer = (CBasePlayer *)data.pActivator;
  6706. }
  6707. else if ( !g_pGameRules->IsDeathmatch() )
  6708. {
  6709. pPlayer = UTIL_GetLocalPlayer();
  6710. }
  6711. if ( pPlayer )
  6712. {
  6713. if ( data.value.Float() != 1.0f )
  6714. {
  6715. // Holster weapon immediately, to allow it to cleanup
  6716. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_WEAPONS ) )
  6717. {
  6718. if ( pPlayer->GetActiveWeapon() )
  6719. {
  6720. pPlayer->Weapon_SetLast( pPlayer->GetActiveWeapon() );
  6721. pPlayer->GetActiveWeapon()->Holster();
  6722. pPlayer->ClearActiveWeapon();
  6723. }
  6724. pPlayer->HideViewModels();
  6725. }
  6726. // Turn off the flashlight
  6727. if ( pPlayer->FlashlightIsOn() )
  6728. {
  6729. pPlayer->FlashlightTurnOff();
  6730. }
  6731. // Disable the flashlight's further use
  6732. pPlayer->SetFlashlightEnabled( false );
  6733. pPlayer->DisableButtons( GetDisabledButtonMask() );
  6734. // Hide the HUD
  6735. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_HUD ) )
  6736. {
  6737. pPlayer->m_Local.m_iHideHUD |= HIDEHUD_ALL;
  6738. }
  6739. }
  6740. else
  6741. {
  6742. // Bring the weapon back
  6743. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_WEAPONS ) && pPlayer->GetActiveWeapon() == NULL )
  6744. {
  6745. pPlayer->SetActiveWeapon( pPlayer->Weapon_GetLast() );
  6746. if ( pPlayer->GetActiveWeapon() )
  6747. {
  6748. pPlayer->GetActiveWeapon()->Deploy();
  6749. }
  6750. }
  6751. // Allow the flashlight again
  6752. pPlayer->SetFlashlightEnabled( true );
  6753. pPlayer->EnableButtons( GetDisabledButtonMask() );
  6754. // Restore the HUD
  6755. if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_HUD ) )
  6756. {
  6757. pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_ALL;
  6758. }
  6759. }
  6760. pPlayer->SetLaggedMovementValue( data.value.Float() );
  6761. }
  6762. }
  6763. void SendProxy_CropFlagsToPlayerFlagBitsLength( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID)
  6764. {
  6765. int mask = (1<<PLAYER_FLAG_BITS) - 1;
  6766. int data = *(int *)pVarData;
  6767. pOut->m_Int = ( data & mask );
  6768. }
  6769. void* SendProxy_SendLocalDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  6770. {
  6771. pRecipients->SetOnly( objectID - 1 );
  6772. // include the GOTV client in the recipients for local data
  6773. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  6774. {
  6775. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  6776. if ( pPlayer && pPlayer->IsHLTV() )
  6777. {
  6778. pRecipients->SetRecipient( i - 1 );
  6779. }
  6780. }
  6781. return ( void * )pVarData;
  6782. }
  6783. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendLocalDataTable );
  6784. void* SendProxy_SendNonLocalDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  6785. {
  6786. pRecipients->ExcludeOnly( objectID - 1 );
  6787. return ( void * )pVarData;
  6788. }
  6789. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendNonLocalDataTable );
  6790. // -------------------------------------------------------------------------------- //
  6791. // SendTable for CPlayerState.
  6792. // -------------------------------------------------------------------------------- //
  6793. BEGIN_SEND_TABLE_NOBASE(CPlayerState, DT_PlayerState)
  6794. SendPropInt (SENDINFO(deadflag), 1, SPROP_UNSIGNED ),
  6795. END_SEND_TABLE()
  6796. // -------------------------------------------------------------------------------- //
  6797. // This data only gets sent to clients that ARE this player entity.
  6798. // -------------------------------------------------------------------------------- //
  6799. BEGIN_SEND_TABLE_NOBASE( CBasePlayer, DT_LocalPlayerExclusive )
  6800. SendPropDataTable ( SENDINFO_DT(m_Local), &REFERENCE_SEND_TABLE(DT_Local) ),
  6801. // If HL2_DLL is defined, then baseflex.cpp already sends these.
  6802. #ifndef HL2_DLL
  6803. SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 0), 8, SPROP_ROUNDDOWN, -32.0, 32.0f),
  6804. SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 1), 8, SPROP_ROUNDDOWN, -32.0, 32.0f),
  6805. SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 2), 10, SPROP_CHANGES_OFTEN, 0.0f, 128.0f),
  6806. #endif
  6807. SendPropFloat ( SENDINFO(m_flFriction), 8, SPROP_ROUNDDOWN, 0.0f, 4.0f),
  6808. SendPropInt ( SENDINFO( m_fOnTarget ), 2, SPROP_UNSIGNED ),
  6809. SendPropInt ( SENDINFO( m_nTickBase ), -1, 0, 0, SENDPROP_TICKBASE_PRIORITY ),
  6810. SendPropInt ( SENDINFO( m_nNextThinkTick ) ),
  6811. SendPropEHandle ( SENDINFO( m_hLastWeapon ) ),
  6812. SendPropFloat ( SENDINFO_VECTORELEM(m_vecVelocity, 0), 32, SPROP_NOSCALE, 0, HIGH_DEFAULT, SendProxy_FloatToFloat, SENDPROP_PLAYER_VELOCITY_XY_PRIORITY ),
  6813. SendPropFloat ( SENDINFO_VECTORELEM(m_vecVelocity, 1), 32, SPROP_NOSCALE, 0, HIGH_DEFAULT, SendProxy_FloatToFloat, SENDPROP_PLAYER_VELOCITY_XY_PRIORITY ),
  6814. SendPropFloat ( SENDINFO_VECTORELEM(m_vecVelocity, 2), 32, SPROP_NOSCALE, 0, HIGH_DEFAULT, SendProxy_FloatToFloat, SENDPROP_PLAYER_VELOCITY_Z_PRIORITY ),
  6815. #if PREDICTION_ERROR_CHECK_LEVEL > 1
  6816. SendPropVector ( SENDINFO( m_vecBaseVelocity ), -1, SPROP_COORD ),
  6817. #else
  6818. SendPropVector ( SENDINFO( m_vecBaseVelocity ), 20, 0, -1000, 1000 ),
  6819. #endif
  6820. SendPropEHandle ( SENDINFO( m_hConstraintEntity)),
  6821. SendPropVector ( SENDINFO( m_vecConstraintCenter), 0, SPROP_NOSCALE ),
  6822. SendPropFloat ( SENDINFO( m_flConstraintRadius ), 0, SPROP_NOSCALE ),
  6823. SendPropFloat ( SENDINFO( m_flConstraintWidth ), 0, SPROP_NOSCALE ),
  6824. SendPropFloat ( SENDINFO( m_flConstraintSpeedFactor ), 0, SPROP_NOSCALE ),
  6825. SendPropBool ( SENDINFO( m_bConstraintPastRadius ) ),
  6826. SendPropFloat ( SENDINFO( m_flDeathTime ), 0, SPROP_NOSCALE ),
  6827. SendPropFloat ( SENDINFO( m_flNextDecalTime ), 0, SPROP_NOSCALE ),
  6828. SendPropFloat ( SENDINFO( m_fForceTeam ), 0, SPROP_NOSCALE ),
  6829. SendPropInt ( SENDINFO( m_nWaterLevel ), 2, SPROP_UNSIGNED ),
  6830. SendPropFloat ( SENDINFO( m_flLaggedMovementValue ), 0, SPROP_NOSCALE ),
  6831. SendPropEHandle ( SENDINFO( m_hTonemapController ) ),
  6832. END_SEND_TABLE()
  6833. // -------------------------------------------------------------------------------- //
  6834. // DT_BasePlayer sendtable.
  6835. // -------------------------------------------------------------------------------- //
  6836. IMPLEMENT_SERVERCLASS_ST( CBasePlayer, DT_BasePlayer )
  6837. SendPropDataTable(SENDINFO_DT(pl), &REFERENCE_SEND_TABLE(DT_PlayerState), SendProxy_DataTableToDataTable),
  6838. SendPropInt (SENDINFO(m_afPhysicsFlags), 6, SPROP_UNSIGNED ),
  6839. SendPropEHandle(SENDINFO(m_hVehicle)),
  6840. SendPropEHandle(SENDINFO(m_hUseEntity)),
  6841. SendPropEHandle( SENDINFO( m_hGroundEntity ), SPROP_CHANGES_OFTEN ),
  6842. SendPropInt (SENDINFO(m_iHealth), 16 ),
  6843. SendPropInt (SENDINFO(m_lifeState), 3, SPROP_UNSIGNED ),
  6844. SendPropArray3 ( SENDINFO_ARRAY3(m_iAmmo), SendPropInt( SENDINFO_ARRAY(m_iAmmo), 10, SPROP_UNSIGNED ) ),
  6845. SendPropInt (SENDINFO(m_iBonusProgress), 15 ),
  6846. SendPropInt (SENDINFO(m_iBonusChallenge), 4 ),
  6847. SendPropFloat (SENDINFO(m_flMaxspeed), 12, SPROP_ROUNDDOWN, 0.0f, 2048.0f ), // CL
  6848. SendPropInt (SENDINFO(m_fFlags), PLAYER_FLAG_BITS, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN, SendProxy_CropFlagsToPlayerFlagBitsLength ),
  6849. SendPropInt (SENDINFO(m_iObserverMode), 3, SPROP_UNSIGNED ),
  6850. SendPropBool (SENDINFO(m_bActiveCameraMan)),
  6851. SendPropBool (SENDINFO(m_bCameraManXRay)),
  6852. SendPropBool (SENDINFO(m_bCameraManOverview)),
  6853. SendPropBool (SENDINFO(m_bCameraManScoreBoard)),
  6854. SendPropInt (SENDINFO(m_uCameraManGraphs), 4, SPROP_UNSIGNED ),
  6855. SendPropInt (SENDINFO(m_iCoachingTeam), 3, SPROP_UNSIGNED ),
  6856. SendPropEHandle (SENDINFO(m_hObserverTarget) ),
  6857. SendPropInt (SENDINFO(m_iFOV), 8, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN ),
  6858. SendPropInt (SENDINFO(m_iFOVStart), 8, SPROP_UNSIGNED ),
  6859. SendPropFloat (SENDINFO(m_flFOVTime), 0, SPROP_CHANGES_OFTEN ),
  6860. SendPropInt (SENDINFO(m_iDefaultFOV), 8, SPROP_UNSIGNED ),
  6861. SendPropEHandle (SENDINFO(m_hZoomOwner) ),
  6862. SendPropArray (SendPropEHandle( SENDINFO_ARRAY( m_hViewModel ) ), m_hViewModel ),
  6863. SendPropString (SENDINFO(m_szLastPlaceName) ),
  6864. SendPropVector (SENDINFO(m_vecLadderNormal), 0, SPROP_NORMAL ),
  6865. SendPropInt (SENDINFO(m_ladderSurfaceProps), 0, SPROP_UNSIGNED ),
  6866. SendPropInt (SENDINFO( m_ubEFNoInterpParity ), NOINTERP_PARITY_MAX_BITS, SPROP_UNSIGNED ),
  6867. SendPropInt (SENDINFO( m_iDeathPostEffect ) ),
  6868. // Postprocess data
  6869. SendPropEHandle ( SENDINFO(m_hPostProcessCtrl) ),
  6870. SendPropEHandle ( SENDINFO(m_hColorCorrectionCtrl) ),
  6871. SendPropEHandle( SENDINFO_STRUCTELEM( fogplayerparams_t, m_PlayerFog, m_hCtrl ) ),
  6872. SendPropInt( SENDINFO( m_vphysicsCollisionState ) ),
  6873. #if defined( DEBUG_MOTION_CONTROLLERS )
  6874. SendPropVector( SENDINFO( m_Debug_vPhysPosition ), 0, SPROP_NOSCALE ),
  6875. SendPropVector( SENDINFO( m_Debug_vPhysVelocity ), 0, SPROP_NOSCALE ),
  6876. SendPropVector( SENDINFO( m_Debug_LinearAccel ), 0, SPROP_NOSCALE ),
  6877. SendPropVector( SENDINFO( m_vNewVPhysicsPosition ), 0, SPROP_NOSCALE ),
  6878. SendPropVector( SENDINFO( m_vNewVPhysicsVelocity ), 0, SPROP_NOSCALE ),
  6879. #endif
  6880. SendPropEHandle (SENDINFO( m_hViewEntity)),
  6881. SendPropBool (SENDINFO( m_bShouldDrawPlayerWhileUsingViewEntity )),
  6882. SendPropFloat (SENDINFO(m_flDuckAmount), 0, SPROP_CHANGES_OFTEN ),
  6883. SendPropFloat (SENDINFO(m_flDuckSpeed), 0, SPROP_CHANGES_OFTEN ),
  6884. // Data that only gets sent to the local player.
  6885. SendPropDataTable( "localdata", 0, &REFERENCE_SEND_TABLE(DT_LocalPlayerExclusive), SendProxy_SendLocalDataTable ),
  6886. END_SEND_TABLE()
  6887. //=============================================================================
  6888. //
  6889. // Player Physics Shadow Code
  6890. //
  6891. void CBasePlayer::SetupVPhysicsShadow( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity, CPhysCollide *pStandModel, const char *pStandHullName, CPhysCollide *pCrouchModel, const char *pCrouchHullName )
  6892. {
  6893. solid_t solid;
  6894. Q_strncpy( solid.surfaceprop, "player", sizeof(solid.surfaceprop) );
  6895. solid.params = g_PhysDefaultObjectParams;
  6896. solid.params.mass = 85.0f;
  6897. solid.params.inertia = 1e24f;
  6898. solid.params.enableCollisions = false;
  6899. //disable drag
  6900. solid.params.dragCoefficient = 0;
  6901. // create standing hull
  6902. m_pShadowStand = PhysModelCreateCustom( this, pStandModel, GetLocalOrigin(), GetLocalAngles(), pStandHullName, false, &solid );
  6903. m_pShadowStand->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION );
  6904. // create crouchig hull
  6905. m_pShadowCrouch = PhysModelCreateCustom( this, pCrouchModel, GetLocalOrigin(), GetLocalAngles(), pCrouchHullName, false, &solid );
  6906. m_pShadowCrouch->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION );
  6907. // default to stand
  6908. VPhysicsSetObject( m_pShadowStand );
  6909. // tell physics lists I'm a shadow controller object
  6910. PhysAddShadow( this );
  6911. m_pPhysicsController = physenv->CreatePlayerController( m_pShadowStand );
  6912. m_pPhysicsController->SetPushMassLimit( 350.0f );
  6913. m_pPhysicsController->SetPushSpeedLimit( 50.0f );
  6914. // Give the controller a valid position so it doesn't do anything rash.
  6915. UpdatePhysicsShadowToPosition( vecAbsOrigin );
  6916. // init state
  6917. if ( GetFlags() & FL_DUCKING )
  6918. {
  6919. SetVCollisionState( vecAbsOrigin, vecAbsVelocity, VPHYS_CROUCH );
  6920. }
  6921. else
  6922. {
  6923. SetVCollisionState( vecAbsOrigin, vecAbsVelocity, VPHYS_WALK );
  6924. }
  6925. }
  6926. //-----------------------------------------------------------------------------
  6927. // Purpose: Empty, just want to keep the baseentity version from being called
  6928. // current so we don't kick up dust, etc.
  6929. //-----------------------------------------------------------------------------
  6930. void CBasePlayer::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
  6931. {
  6932. }
  6933. //-----------------------------------------------------------------------------
  6934. // Purpose:
  6935. //-----------------------------------------------------------------------------
  6936. void CBasePlayer::VPhysicsUpdate( IPhysicsObject *pPhysics )
  6937. {
  6938. float savedImpact = m_impactEnergyScale;
  6939. // HACKHACK: Reduce player's stress by 1/8th
  6940. m_impactEnergyScale *= 0.125f;
  6941. ApplyStressDamage( pPhysics, true );
  6942. m_impactEnergyScale = savedImpact;
  6943. }
  6944. // recreate physics on save/load, don't try to save the state!
  6945. bool CBasePlayer::ShouldSavePhysics()
  6946. {
  6947. return false;
  6948. }
  6949. //-----------------------------------------------------------------------------
  6950. // Purpose:
  6951. //-----------------------------------------------------------------------------
  6952. void CBasePlayer::InitVCollision( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity )
  6953. {
  6954. // Cleanup any old vphysics stuff.
  6955. VPhysicsDestroyObject();
  6956. // in turbo physics players dont have a physics shadow
  6957. if ( sv_turbophysics.GetBool() )
  6958. return;
  6959. CPhysCollide *pModel = PhysCreateBbox( VEC_HULL_MIN, VEC_HULL_MAX );
  6960. CPhysCollide *pCrouchModel = PhysCreateBbox( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
  6961. SetupVPhysicsShadow( vecAbsOrigin, vecAbsVelocity, pModel, "player_stand", pCrouchModel, "player_crouch" );
  6962. }
  6963. void CBasePlayer::VPhysicsDestroyObject()
  6964. {
  6965. // Since CBasePlayer aliases its pointer to the physics object, tell CBaseEntity to
  6966. // clear out its physics object pointer so we don't wind up deleting one of
  6967. // the aliased objects twice.
  6968. VPhysicsSetObject( NULL );
  6969. PhysRemoveShadow( this );
  6970. if ( m_pPhysicsController )
  6971. {
  6972. physenv->DestroyPlayerController( m_pPhysicsController );
  6973. m_pPhysicsController = NULL;
  6974. }
  6975. if ( m_pShadowStand )
  6976. {
  6977. m_pShadowStand->EnableCollisions( false );
  6978. PhysDestroyObject( m_pShadowStand );
  6979. m_pShadowStand = NULL;
  6980. }
  6981. if ( m_pShadowCrouch )
  6982. {
  6983. m_pShadowCrouch->EnableCollisions( false );
  6984. PhysDestroyObject( m_pShadowCrouch );
  6985. m_pShadowCrouch = NULL;
  6986. }
  6987. BaseClass::VPhysicsDestroyObject();
  6988. }
  6989. //-----------------------------------------------------------------------------
  6990. // Purpose:
  6991. //-----------------------------------------------------------------------------
  6992. int CBasePlayer::GetFOV( void )
  6993. {
  6994. int nDefaultFOV;
  6995. // The vehicle's FOV wins if we're asking for a default value
  6996. if ( GetVehicle() )
  6997. {
  6998. CacheVehicleView();
  6999. nDefaultFOV = ( m_flVehicleViewFOV == 0 ) ? GetDefaultFOV() : (int) m_flVehicleViewFOV;
  7000. }
  7001. else
  7002. {
  7003. nDefaultFOV = GetDefaultFOV();
  7004. }
  7005. int fFOV = ( m_iFOV == 0 ) ? nDefaultFOV : m_iFOV;
  7006. // If it's immediate, just do it
  7007. if ( m_Local.m_flFOVRate == 0.0f )
  7008. return fFOV;
  7009. float deltaTime = (float)( gpGlobals->curtime - m_flFOVTime ) / m_Local.m_flFOVRate;
  7010. if ( deltaTime >= 1.0f )
  7011. {
  7012. //If we're past the zoom time, just take the new value and stop lerping
  7013. m_iFOVStart = fFOV;
  7014. }
  7015. else
  7016. {
  7017. fFOV = SimpleSplineRemapValClamped( deltaTime, 0.0f, 1.0f, m_iFOVStart, fFOV );
  7018. }
  7019. return fFOV;
  7020. }
  7021. //-----------------------------------------------------------------------------
  7022. // Get the current FOV used for network computations
  7023. // Choose the smallest FOV, as it will open the largest number of portals
  7024. //-----------------------------------------------------------------------------
  7025. int CBasePlayer::GetFOVForNetworking( void )
  7026. {
  7027. int nDefaultFOV;
  7028. // The vehicle's FOV wins if we're asking for a default value
  7029. if ( GetVehicle() )
  7030. {
  7031. CacheVehicleView();
  7032. nDefaultFOV = ( m_flVehicleViewFOV == 0 ) ? GetDefaultFOV() : (int) m_flVehicleViewFOV;
  7033. }
  7034. else
  7035. {
  7036. nDefaultFOV = GetDefaultFOV();
  7037. }
  7038. int fFOV = ( m_iFOV == 0 ) ? nDefaultFOV : m_iFOV;
  7039. // If it's immediate, just do it
  7040. if ( m_Local.m_flFOVRate == 0.0f )
  7041. return fFOV;
  7042. if ( gpGlobals->curtime - m_flFOVTime < m_Local.m_flFOVRate )
  7043. {
  7044. fFOV = Min( fFOV, m_iFOVStart.Get() );
  7045. }
  7046. return fFOV;
  7047. }
  7048. float CBasePlayer::GetFOVDistanceAdjustFactorForNetworking()
  7049. {
  7050. float defaultFOV = (float)GetDefaultFOV();
  7051. float localFOV = (float)GetFOVForNetworking();
  7052. if ( localFOV == defaultFOV || defaultFOV < 0.001f )
  7053. return 1.0f;
  7054. // If FOV is lower, then we're "zoomed" in and this will give a factor < 1 so apparent LOD distances can be
  7055. // shorted accordingly
  7056. return localFOV / defaultFOV;
  7057. }
  7058. //-----------------------------------------------------------------------------
  7059. // Purpose: Sets the default FOV for the player if nothing else is going on
  7060. // Input : FOV - the new base FOV for this player
  7061. //-----------------------------------------------------------------------------
  7062. void CBasePlayer::SetDefaultFOV( int FOV )
  7063. {
  7064. m_iDefaultFOV = ( FOV == 0 ) ? g_pGameRules->DefaultFOV() : FOV;
  7065. }
  7066. //-----------------------------------------------------------------------------
  7067. // Purpose: // static func
  7068. // Input : set -
  7069. //-----------------------------------------------------------------------------
  7070. void CBasePlayer::ModifyOrAppendPlayerCriteria( AI_CriteriaSet& set )
  7071. {
  7072. // Append our health
  7073. set.AppendCriteria( "playerhealth", UTIL_VarArgs( "%i", GetHealth() ) );
  7074. float healthfrac = 0.0f;
  7075. if ( GetMaxHealth() > 0 )
  7076. {
  7077. healthfrac = (float)GetHealth() / (float)GetMaxHealth();
  7078. }
  7079. set.AppendCriteria( "playerhealthfrac", UTIL_VarArgs( "%.3f", healthfrac ) );
  7080. CBaseCombatWeapon *weapon = GetActiveWeapon();
  7081. if ( weapon )
  7082. {
  7083. set.AppendCriteria( "playerweapon", weapon->GetClassname() );
  7084. }
  7085. else
  7086. {
  7087. set.AppendCriteria( "playerweapon", "none" );
  7088. }
  7089. // Append current activity name
  7090. set.AppendCriteria( "playeractivity", CAI_BaseNPC::GetActivityName( GetActivity() ) );
  7091. set.AppendCriteria( "playerspeed", UTIL_VarArgs( "%.3f", GetAbsVelocity().Length() ) );
  7092. #ifdef HL2_EP3
  7093. CBaseEntity *pHeldObject = GetPlayerHeldEntity( this );
  7094. if( !pHeldObject )
  7095. {
  7096. pHeldObject = PhysCannonGetHeldEntity( GetActiveWeapon() );
  7097. }
  7098. if ( pHeldObject )
  7099. {
  7100. if ( pHeldObject->GetEntityName() == NULL_STRING )
  7101. {
  7102. set.AppendCriteria( "playerheldentity", pHeldObject->GetClassname() );
  7103. }
  7104. else
  7105. {
  7106. set.AppendCriteria( "playerheldentity", STRING( pHeldObject->GetEntityName() ) );
  7107. }
  7108. set.AppendCriteria( "playerheldmodel", STRING( pHeldObject->GetModelName() ) );
  7109. }
  7110. #endif
  7111. AppendContextToCriteria( set, "player" );
  7112. }
  7113. QAngle CBasePlayer::GetViewPunchAngle()
  7114. {
  7115. return m_Local.m_viewPunchAngle.Get();
  7116. }
  7117. void CBasePlayer::SetViewPunchAngle( const QAngle &punchAngle )
  7118. {
  7119. m_Local.m_viewPunchAngle = punchAngle;
  7120. PropagatePunchAnglesToObservers();
  7121. }
  7122. void CBasePlayer::SetViewPunchAngle( int axis, float value )
  7123. {
  7124. m_Local.m_viewPunchAngle.Set( axis, value );
  7125. PropagatePunchAnglesToObservers();
  7126. }
  7127. QAngle CBasePlayer::GetAimPunchAngle()
  7128. {
  7129. return m_Local.m_aimPunchAngle.Get();
  7130. }
  7131. void CBasePlayer::SetAimPunchAngle( const QAngle &punchAngle )
  7132. {
  7133. m_Local.m_aimPunchAngle = punchAngle;
  7134. PropagatePunchAnglesToObservers();
  7135. }
  7136. void CBasePlayer::SetAimPunchAngleVelocity( const QAngle &punchAngleVelocity )
  7137. {
  7138. m_Local.m_aimPunchAngleVel = punchAngleVelocity;
  7139. PropagatePunchAnglesToObservers();
  7140. }
  7141. QAngle CBasePlayer::GetFinalAimAngle()
  7142. {
  7143. QAngle eyeAngles = EyeAngles();
  7144. if ( PlatformInputDevice::IsInputDeviceAPointer( GetPlayerInputDevice() ) )
  7145. {
  7146. // If we are using a pointing device, our final aim angle is based on where we're pointing and not where we're looking.
  7147. VectorAngles( GetAimDirection(), eyeAngles );
  7148. }
  7149. return eyeAngles + GetAimPunchAngle();
  7150. }
  7151. //-----------------------------------------------------------------------------
  7152. // Purpose: If someone is observing this player, we set their punch angle
  7153. // as well.
  7154. //-----------------------------------------------------------------------------
  7155. void CBasePlayer::PropagatePunchAnglesToObservers()
  7156. {
  7157. if ( IsAlive() )
  7158. {
  7159. int index = entindex();
  7160. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  7161. {
  7162. if ( i == index )
  7163. continue;
  7164. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  7165. if ( NULL == pPlayer )
  7166. continue;
  7167. if ( pPlayer->GetObserverTarget() == this && pPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
  7168. {
  7169. pPlayer->m_Local.m_viewPunchAngle = m_Local.m_viewPunchAngle.Get();
  7170. pPlayer->m_Local.m_aimPunchAngle = m_Local.m_aimPunchAngle.Get();
  7171. pPlayer->m_Local.m_aimPunchAngleVel = m_Local.m_aimPunchAngleVel.Get();
  7172. }
  7173. }
  7174. }
  7175. }
  7176. //-----------------------------------------------------------------------------
  7177. // Purpose: Apply a movement constraint to the player
  7178. //-----------------------------------------------------------------------------
  7179. void CBasePlayer::ActivateMovementConstraint( CBaseEntity *pEntity, const Vector &vecCenter, float flRadius, float flConstraintWidth, float flSpeedFactor, bool constraintPastRadius )
  7180. {
  7181. m_hConstraintEntity = pEntity;
  7182. m_vecConstraintCenter = vecCenter;
  7183. m_flConstraintRadius = flRadius;
  7184. m_flConstraintWidth = flConstraintWidth;
  7185. m_flConstraintSpeedFactor = flSpeedFactor;
  7186. m_bConstraintPastRadius = constraintPastRadius;
  7187. }
  7188. //-----------------------------------------------------------------------------
  7189. // Purpose:
  7190. //-----------------------------------------------------------------------------
  7191. void CBasePlayer::DeactivateMovementConstraint( )
  7192. {
  7193. m_hConstraintEntity = NULL;
  7194. m_flConstraintRadius = 0.0f;
  7195. m_vecConstraintCenter = vec3_origin;
  7196. }
  7197. //-----------------------------------------------------------------------------
  7198. // Perhaps a poorly-named function. This function traces against the supplied
  7199. // NPC's hitboxes (instead of hull). If the trace hits a different NPC, the
  7200. // new NPC is selected. Otherwise, the supplied NPC is determined to be the
  7201. // one the citizen wants. This function allows the selection of a citizen over
  7202. // another citizen's shoulder, which is impossible without tracing against
  7203. // hitboxes instead of the hull (sjb)
  7204. //-----------------------------------------------------------------------------
  7205. CBaseEntity *CBasePlayer::DoubleCheckUseNPC( CBaseEntity *pNPC, const Vector &vecSrc, const Vector &vecDir )
  7206. {
  7207. trace_t tr;
  7208. UTIL_TraceLine( vecSrc, vecSrc + vecDir * 1024, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  7209. if( tr.m_pEnt != NULL && tr.m_pEnt->MyNPCPointer() && tr.m_pEnt != pNPC )
  7210. {
  7211. // Player is selecting a different NPC through some negative space
  7212. // in the first NPC's hitboxes (between legs, over shoulder, etc).
  7213. return tr.m_pEnt;
  7214. }
  7215. return pNPC;
  7216. }
  7217. bool CBasePlayer::IsBot() const
  7218. {
  7219. return (GetFlags() & FL_FAKECLIENT) != 0;
  7220. }
  7221. bool CBasePlayer::IsFakeClient() const
  7222. {
  7223. return (GetFlags() & FL_FAKECLIENT) != 0;
  7224. }
  7225. void CBasePlayer::EquipSuit( bool bPlayEffects )
  7226. {
  7227. m_Local.m_bWearingSuit = true;
  7228. }
  7229. void CBasePlayer::RemoveSuit( void )
  7230. {
  7231. m_Local.m_bWearingSuit = false;
  7232. }
  7233. //-----------------------------------------------------------------------------
  7234. // Purpose:
  7235. // Input : &tr -
  7236. // nDamageType -
  7237. //-----------------------------------------------------------------------------
  7238. void CBasePlayer::DoImpactEffect( trace_t &tr, int nDamageType )
  7239. {
  7240. if ( GetActiveWeapon() )
  7241. {
  7242. GetActiveWeapon()->DoImpactEffect( tr, nDamageType );
  7243. return;
  7244. }
  7245. BaseClass::DoImpactEffect( tr, nDamageType );
  7246. }
  7247. //-----------------------------------------------------------------------------
  7248. // Purpose:
  7249. //-----------------------------------------------------------------------------
  7250. void CBasePlayer::InputSetHealth( inputdata_t &inputdata )
  7251. {
  7252. int iNewHealth = inputdata.value.Int();
  7253. int iDelta = abs(GetHealth() - iNewHealth);
  7254. if ( iNewHealth > GetHealth() )
  7255. {
  7256. TakeHealth( iDelta, DMG_GENERIC );
  7257. }
  7258. else if ( iNewHealth < GetHealth() )
  7259. {
  7260. // Strip off and restore armor so that it doesn't absorb any of this damage.
  7261. int armor = m_ArmorValue;
  7262. m_ArmorValue = 0;
  7263. TakeDamage( CTakeDamageInfo( this, this, iDelta, DMG_GENERIC ) );
  7264. m_ArmorValue = armor;
  7265. }
  7266. }
  7267. //-----------------------------------------------------------------------------
  7268. // Purpose: Hides or displays the HUD
  7269. // Input : &inputdata -
  7270. //-----------------------------------------------------------------------------
  7271. void CBasePlayer::InputSetHUDVisibility( inputdata_t &inputdata )
  7272. {
  7273. bool bEnable = inputdata.value.Bool();
  7274. if ( bEnable )
  7275. {
  7276. m_Local.m_iHideHUD &= ~HIDEHUD_ALL;
  7277. }
  7278. else
  7279. {
  7280. m_Local.m_iHideHUD |= HIDEHUD_ALL;
  7281. }
  7282. }
  7283. //-----------------------------------------------------------------------------
  7284. // Purpose: Set the fog controller data per player.
  7285. // Input : &inputdata -
  7286. //-----------------------------------------------------------------------------
  7287. void CBasePlayer::InputSetFogController( inputdata_t &inputdata )
  7288. {
  7289. // Find the fog controller with the given name.
  7290. CFogController *pFogController = NULL;
  7291. if ( inputdata.value.FieldType() == FIELD_EHANDLE )
  7292. {
  7293. pFogController = dynamic_cast<CFogController*>( inputdata.value.Entity().Get() );
  7294. }
  7295. else
  7296. {
  7297. pFogController = dynamic_cast<CFogController*>( gEntList.FindEntityByName( NULL, inputdata.value.String() ) );
  7298. }
  7299. if ( pFogController )
  7300. {
  7301. SetFogController( pFogController );
  7302. }
  7303. }
  7304. //-----------------------------------------------------------------------------
  7305. //
  7306. //-----------------------------------------------------------------------------
  7307. void CBasePlayer::InitFogController( void )
  7308. {
  7309. // Setup with the default master controller.
  7310. m_PlayerFog.m_hCtrl = FogSystem()->GetMasterFogController();
  7311. }
  7312. //-----------------------------------------------------------------------------
  7313. //
  7314. //-----------------------------------------------------------------------------
  7315. void CBasePlayer::InitPostProcessController( void )
  7316. {
  7317. // Setup with the default master controller.
  7318. m_hPostProcessCtrl = PostProcessSystem()->GetMasterPostProcessController();
  7319. }
  7320. //-----------------------------------------------------------------------------
  7321. //
  7322. //-----------------------------------------------------------------------------
  7323. void CBasePlayer::InitColorCorrectionController( void )
  7324. {
  7325. m_hColorCorrectionCtrl = ColorCorrectionSystem()->GetMasterColorCorrection();
  7326. }
  7327. //-----------------------------------------------------------------------------
  7328. //
  7329. //-----------------------------------------------------------------------------
  7330. void CBasePlayer::InputSetPostProcessController( inputdata_t &inputdata )
  7331. {
  7332. // Find the fog controller with the given name.
  7333. CPostProcessController *pController = NULL;
  7334. if ( inputdata.value.FieldType() == FIELD_EHANDLE )
  7335. {
  7336. pController = dynamic_cast<CPostProcessController*>( inputdata.value.Entity().Get() );
  7337. }
  7338. else
  7339. {
  7340. pController = dynamic_cast<CPostProcessController*>( gEntList.FindEntityByName( NULL, inputdata.value.String() ) );
  7341. }
  7342. if ( pController )
  7343. {
  7344. m_hPostProcessCtrl.Set( pController );
  7345. }
  7346. }
  7347. //-----------------------------------------------------------------------------
  7348. //
  7349. //-----------------------------------------------------------------------------
  7350. void CBasePlayer::InputSetColorCorrectionController( inputdata_t &inputdata )
  7351. {
  7352. // Find the fog controller with the given name.
  7353. CColorCorrection *pController = NULL;
  7354. if ( inputdata.value.FieldType() == FIELD_EHANDLE )
  7355. {
  7356. pController = dynamic_cast<CColorCorrection*>( inputdata.value.Entity().Get() );
  7357. }
  7358. else
  7359. {
  7360. pController = dynamic_cast<CColorCorrection*>( gEntList.FindEntityByName( NULL, inputdata.value.String() ) );
  7361. }
  7362. if ( pController )
  7363. {
  7364. m_hColorCorrectionCtrl.Set( pController );
  7365. }
  7366. }
  7367. //-----------------------------------------------------------------------------
  7368. // Purpose:
  7369. // Input : *pEntity -
  7370. //-----------------------------------------------------------------------------
  7371. void CBasePlayer::SetViewEntity( CBaseEntity *pEntity, bool bShouldDrawPlayer /*= true*/ )
  7372. {
  7373. m_hViewEntity = pEntity;
  7374. m_bShouldDrawPlayerWhileUsingViewEntity = bShouldDrawPlayer;
  7375. if ( m_hViewEntity )
  7376. {
  7377. engine->SetView( edict(), m_hViewEntity->edict() );
  7378. }
  7379. else
  7380. {
  7381. engine->SetView( edict(), edict() );
  7382. }
  7383. }
  7384. //-----------------------------------------------------------------------------
  7385. // Purpose: Looks at the player's reserve ammo and also all his weapons for any ammo
  7386. // of the specified type
  7387. // Input : nAmmoIndex - ammo to look for
  7388. // Output : Returns true on success, false on failure.
  7389. //-----------------------------------------------------------------------------
  7390. bool CBasePlayer::HasAnyAmmoOfType( int nAmmoIndex )
  7391. {
  7392. // Must be a valid index
  7393. if ( nAmmoIndex < 0 )
  7394. return false;
  7395. // If we have some in reserve, we're already done
  7396. if ( GetAmmoCount( nAmmoIndex ) )
  7397. return true;
  7398. CBaseCombatWeapon *pWeapon;
  7399. // Check all held weapons
  7400. for ( int i=0; i < MAX_WEAPONS; i++ )
  7401. {
  7402. pWeapon = GetWeapon( i );
  7403. if ( !pWeapon )
  7404. continue;
  7405. // We must use clips and use this sort of ammo
  7406. if ( pWeapon->UsesClipsForAmmo1() && pWeapon->GetPrimaryAmmoType() == nAmmoIndex )
  7407. {
  7408. // If we have any ammo, we're done
  7409. if ( pWeapon->HasPrimaryAmmo() )
  7410. return true;
  7411. }
  7412. // We'll check both clips for the same ammo type, just in case
  7413. if ( pWeapon->UsesClipsForAmmo2() && pWeapon->GetSecondaryAmmoType() == nAmmoIndex )
  7414. {
  7415. if ( pWeapon->HasSecondaryAmmo() )
  7416. return true;
  7417. }
  7418. }
  7419. // We're completely without this type of ammo
  7420. return false;
  7421. }
  7422. //-----------------------------------------------------------------------------
  7423. // return a string version of the players network (i.e steam) ID.
  7424. //
  7425. //-----------------------------------------------------------------------------
  7426. const char *CBasePlayer::GetNetworkIDString()
  7427. {
  7428. const char *networkIDString = engine->GetPlayerNetworkIDString( edict() );
  7429. if ( !networkIDString )
  7430. {
  7431. networkIDString = "UNKNOWN";
  7432. }
  7433. V_strncpy( m_szNetworkIDString, networkIDString, sizeof(m_szNetworkIDString) );
  7434. return m_szNetworkIDString;
  7435. }
  7436. //-----------------------------------------------------------------------------
  7437. // Assign the player a name
  7438. //-----------------------------------------------------------------------------
  7439. void CBasePlayer::SetPlayerName( const char *name )
  7440. {
  7441. Assert( name );
  7442. if ( name )
  7443. {
  7444. Assert( strlen(name) > 0 );
  7445. V_UTF8_strncpy( m_szNetname, name, sizeof(m_szNetname) );
  7446. }
  7447. }
  7448. //-----------------------------------------------------------------------------
  7449. //-----------------------------------------------------------------------------
  7450. void CBasePlayer::PrepareForFullUpdate( void )
  7451. {
  7452. }
  7453. //-----------------------------------------------------------------------------
  7454. // sets the "don't autokick me" flag on a player
  7455. //-----------------------------------------------------------------------------
  7456. class DisableAutokick
  7457. {
  7458. public:
  7459. DisableAutokick( int userID )
  7460. {
  7461. m_userID = userID;
  7462. }
  7463. bool operator()( CBasePlayer *player )
  7464. {
  7465. if ( player->GetUserID() == m_userID )
  7466. {
  7467. Msg( "autokick is disabled for %s\n", player->GetPlayerName() );
  7468. player->DisableAutoKick( true );
  7469. return false; // don't need to check other players
  7470. }
  7471. return true; // keep looking at other players
  7472. }
  7473. private:
  7474. int m_userID;
  7475. };
  7476. //-----------------------------------------------------------------------------
  7477. // sets the "don't autokick me" flag on a player
  7478. //-----------------------------------------------------------------------------
  7479. CON_COMMAND( mp_disable_autokick, "Prevents a userid from being auto-kicked" )
  7480. {
  7481. if ( !UTIL_IsCommandIssuedByServerAdmin() )
  7482. return;
  7483. if ( args.ArgC() != 2 )
  7484. {
  7485. Msg( "Usage: mp_disable_autokick <userid>\n" );
  7486. return;
  7487. }
  7488. int userID = atoi( args[1] );
  7489. DisableAutokick disable( userID );
  7490. ForEachPlayer( disable );
  7491. }
  7492. //-----------------------------------------------------------------------------
  7493. // Purpose: Toggle between the duck being on and off
  7494. //-----------------------------------------------------------------------------
  7495. void CBasePlayer::ToggleDuck( void )
  7496. {
  7497. // Toggle the state
  7498. m_bDuckToggled = !m_bDuckToggled;
  7499. }
  7500. //-----------------------------------------------------------------------------
  7501. // Just tells us how far the stick is from the center. No directional info
  7502. //-----------------------------------------------------------------------------
  7503. float CBasePlayer::GetStickDist()
  7504. {
  7505. Vector2D controlStick;
  7506. controlStick.x = m_flForwardMove;
  7507. controlStick.y = m_flSideMove;
  7508. return controlStick.Length();
  7509. }
  7510. //-----------------------------------------------------------------------------
  7511. // Purpose:
  7512. //-----------------------------------------------------------------------------
  7513. void CBasePlayer::HandleAnimEvent( animevent_t *pEvent )
  7514. {
  7515. int nEvent = pEvent->Event();
  7516. if ((pEvent->type & AE_TYPE_NEWEVENTSYSTEM) && (pEvent->type & AE_TYPE_SERVER))
  7517. {
  7518. if ( nEvent == AE_RAGDOLL )
  7519. {
  7520. // Convert to ragdoll immediately
  7521. CreateRagdollEntity();
  7522. BecomeRagdollOnClient( vec3_origin );
  7523. // Force the player to start death thinking
  7524. SetThink(&CBasePlayer::PlayerDeathThink);
  7525. SetNextThink( gpGlobals->curtime + 0.1f );
  7526. return;
  7527. }
  7528. }
  7529. BaseClass::HandleAnimEvent( pEvent );
  7530. }
  7531. //-----------------------------------------------------------------------------
  7532. // CPlayerInfo functions (simple passthroughts to get around the CBasePlayer multiple inheritence limitation)
  7533. //-----------------------------------------------------------------------------
  7534. const char *CPlayerInfo::GetName()
  7535. {
  7536. Assert( m_pParent );
  7537. return m_pParent->GetPlayerName();
  7538. }
  7539. int CPlayerInfo::GetUserID()
  7540. {
  7541. Assert( m_pParent );
  7542. return engine->GetPlayerUserId( m_pParent->edict() );
  7543. }
  7544. const char *CPlayerInfo::GetNetworkIDString()
  7545. {
  7546. Assert( m_pParent );
  7547. return m_pParent->GetNetworkIDString();
  7548. }
  7549. int CPlayerInfo::GetTeamIndex()
  7550. {
  7551. Assert( m_pParent );
  7552. return m_pParent->GetTeamNumber();
  7553. }
  7554. void CPlayerInfo::ChangeTeam( int iTeamNum )
  7555. {
  7556. Assert( m_pParent );
  7557. m_pParent->ChangeTeam(iTeamNum);
  7558. }
  7559. int CPlayerInfo::GetFragCount()
  7560. {
  7561. Assert( m_pParent );
  7562. return m_pParent->FragCount();
  7563. }
  7564. int CPlayerInfo::GetAssistsCount()
  7565. {
  7566. Assert( m_pParent );
  7567. return m_pParent->AssistsCount();
  7568. }
  7569. int CPlayerInfo::GetDeathCount()
  7570. {
  7571. Assert( m_pParent );
  7572. return m_pParent->DeathCount();
  7573. }
  7574. bool CPlayerInfo::IsConnected()
  7575. {
  7576. Assert( m_pParent );
  7577. return m_pParent->IsConnected();
  7578. }
  7579. int CPlayerInfo::GetArmorValue()
  7580. {
  7581. Assert( m_pParent );
  7582. return m_pParent->ArmorValue();
  7583. }
  7584. bool CPlayerInfo::IsHLTV()
  7585. {
  7586. Assert( m_pParent );
  7587. return m_pParent->IsHLTV();
  7588. }
  7589. #if defined( REPLAY_ENABLED )
  7590. bool CPlayerInfo::IsReplay()
  7591. {
  7592. Assert( m_pParent );
  7593. return m_pParent->IsReplay();
  7594. }
  7595. #endif
  7596. bool CPlayerInfo::IsPlayer()
  7597. {
  7598. Assert( m_pParent );
  7599. return m_pParent->IsPlayer();
  7600. }
  7601. bool CPlayerInfo::IsFakeClient()
  7602. {
  7603. Assert( m_pParent );
  7604. return m_pParent->IsFakeClient();
  7605. }
  7606. bool CPlayerInfo::IsDead()
  7607. {
  7608. Assert( m_pParent );
  7609. return m_pParent->IsDead();
  7610. }
  7611. bool CPlayerInfo::IsInAVehicle()
  7612. {
  7613. Assert( m_pParent );
  7614. return m_pParent->IsInAVehicle();
  7615. }
  7616. bool CPlayerInfo::IsObserver()
  7617. {
  7618. Assert( m_pParent );
  7619. return m_pParent->IsObserver();
  7620. }
  7621. const Vector CPlayerInfo::GetAbsOrigin()
  7622. {
  7623. Assert( m_pParent );
  7624. return m_pParent->GetAbsOrigin();
  7625. }
  7626. const QAngle CPlayerInfo::GetAbsAngles()
  7627. {
  7628. Assert( m_pParent );
  7629. return m_pParent->GetAbsAngles();
  7630. }
  7631. const Vector CPlayerInfo::GetPlayerMins()
  7632. {
  7633. Assert( m_pParent );
  7634. return m_pParent->GetPlayerMins();
  7635. }
  7636. const Vector CPlayerInfo::GetPlayerMaxs()
  7637. {
  7638. Assert( m_pParent );
  7639. return m_pParent->GetPlayerMaxs();
  7640. }
  7641. const char *CPlayerInfo::GetWeaponName()
  7642. {
  7643. Assert( m_pParent );
  7644. CBaseCombatWeapon *weap = m_pParent->GetActiveWeapon();
  7645. if ( !weap )
  7646. {
  7647. return NULL;
  7648. }
  7649. return weap->GetName();
  7650. }
  7651. const char *CPlayerInfo::GetModelName()
  7652. {
  7653. Assert( m_pParent );
  7654. return m_pParent->GetModelName().ToCStr();
  7655. }
  7656. const int CPlayerInfo::GetHealth()
  7657. {
  7658. Assert( m_pParent );
  7659. return m_pParent->GetHealth();
  7660. }
  7661. const int CPlayerInfo::GetMaxHealth()
  7662. {
  7663. Assert( m_pParent );
  7664. return m_pParent->GetMaxHealth();
  7665. }
  7666. void CPlayerInfo::SetAbsOrigin( Vector & vec )
  7667. {
  7668. Assert( m_pParent );
  7669. if ( m_pParent->IsBot() )
  7670. {
  7671. m_pParent->SetAbsOrigin(vec);
  7672. }
  7673. }
  7674. void CPlayerInfo::SetAbsAngles( QAngle & ang )
  7675. {
  7676. Assert( m_pParent );
  7677. if ( m_pParent->IsBot() )
  7678. {
  7679. m_pParent->SetAbsAngles(ang);
  7680. }
  7681. }
  7682. void CPlayerInfo::RemoveAllItems( bool removeSuit )
  7683. {
  7684. Assert( m_pParent );
  7685. if ( m_pParent->IsBot() )
  7686. {
  7687. m_pParent->RemoveAllItems(removeSuit);
  7688. }
  7689. }
  7690. void CPlayerInfo::SetActiveWeapon( const char *WeaponName )
  7691. {
  7692. Assert( m_pParent );
  7693. if ( m_pParent->IsBot() )
  7694. {
  7695. CBaseCombatWeapon *weap = m_pParent->Weapon_Create( WeaponName );
  7696. if ( weap )
  7697. {
  7698. m_pParent->Weapon_Equip(weap);
  7699. m_pParent->Weapon_Switch(weap);
  7700. }
  7701. }
  7702. }
  7703. void CPlayerInfo::SetLocalOrigin( const Vector& origin )
  7704. {
  7705. Assert( m_pParent );
  7706. if ( m_pParent->IsBot() )
  7707. {
  7708. m_pParent->SetLocalOrigin(origin);
  7709. }
  7710. }
  7711. const Vector CPlayerInfo::GetLocalOrigin( void )
  7712. {
  7713. Assert( m_pParent );
  7714. if ( m_pParent->IsBot() )
  7715. {
  7716. Vector origin = m_pParent->GetLocalOrigin();
  7717. return origin;
  7718. }
  7719. else
  7720. {
  7721. return Vector( 0, 0, 0 );
  7722. }
  7723. }
  7724. void CPlayerInfo::SetLocalAngles( const QAngle& angles )
  7725. {
  7726. Assert( m_pParent );
  7727. if ( m_pParent->IsBot() )
  7728. {
  7729. m_pParent->SetLocalAngles( angles );
  7730. }
  7731. }
  7732. const QAngle CPlayerInfo::GetLocalAngles( void )
  7733. {
  7734. Assert( m_pParent );
  7735. if ( m_pParent->IsBot() )
  7736. {
  7737. return m_pParent->GetLocalAngles();
  7738. }
  7739. else
  7740. {
  7741. return QAngle();
  7742. }
  7743. }
  7744. void CPlayerInfo::PostClientMessagesSent( void )
  7745. {
  7746. Assert( m_pParent );
  7747. if ( m_pParent->IsBot() )
  7748. {
  7749. m_pParent->PostClientMessagesSent();
  7750. }
  7751. }
  7752. bool CPlayerInfo::IsEFlagSet( int nEFlagMask )
  7753. {
  7754. Assert( m_pParent );
  7755. if ( m_pParent->IsBot() )
  7756. {
  7757. return m_pParent->IsEFlagSet(nEFlagMask);
  7758. }
  7759. return false;
  7760. }
  7761. void CPlayerInfo::RunPlayerMove( CBotCmd *ucmd )
  7762. {
  7763. if ( m_pParent->IsBot() )
  7764. {
  7765. Assert( m_pParent );
  7766. CUserCmd cmd;
  7767. cmd.buttons = ucmd->buttons;
  7768. cmd.command_number = ucmd->command_number;
  7769. cmd.forwardmove = ucmd->forwardmove;
  7770. cmd.hasbeenpredicted = ucmd->hasbeenpredicted;
  7771. cmd.impulse = ucmd->impulse;
  7772. cmd.mousedx = ucmd->mousedx;
  7773. cmd.mousedy = ucmd->mousedy;
  7774. cmd.random_seed = ucmd->random_seed;
  7775. cmd.sidemove = ucmd->sidemove;
  7776. cmd.tick_count = ucmd->tick_count;
  7777. cmd.upmove = ucmd->upmove;
  7778. cmd.viewangles = ucmd->viewangles;
  7779. cmd.weaponselect = ucmd->weaponselect;
  7780. cmd.weaponsubtype = ucmd->weaponsubtype;
  7781. // Store off the globals.. they're gonna get whacked
  7782. float flOldFrametime = gpGlobals->frametime;
  7783. float flOldCurtime = gpGlobals->curtime;
  7784. m_pParent->SetTimeBase( gpGlobals->curtime );
  7785. MoveHelperServer()->SetHost( m_pParent );
  7786. m_pParent->PlayerRunCommand( &cmd, MoveHelperServer() );
  7787. // save off the last good usercmd
  7788. m_pParent->SetLastUserCommand( cmd );
  7789. // Clear out any fixangle that has been set
  7790. m_pParent->pl.fixangle = FIXANGLE_NONE;
  7791. // Restore the globals..
  7792. gpGlobals->frametime = flOldFrametime;
  7793. gpGlobals->curtime = flOldCurtime;
  7794. MoveHelperServer()->SetHost( NULL );
  7795. }
  7796. }
  7797. void CPlayerInfo::SetLastUserCommand( const CBotCmd &ucmd )
  7798. {
  7799. if ( m_pParent->IsBot() )
  7800. {
  7801. Assert( m_pParent );
  7802. CUserCmd cmd;
  7803. cmd.buttons = ucmd.buttons;
  7804. cmd.command_number = ucmd.command_number;
  7805. cmd.forwardmove = ucmd.forwardmove;
  7806. cmd.hasbeenpredicted = ucmd.hasbeenpredicted;
  7807. cmd.impulse = ucmd.impulse;
  7808. cmd.mousedx = ucmd.mousedx;
  7809. cmd.mousedy = ucmd.mousedy;
  7810. cmd.random_seed = ucmd.random_seed;
  7811. cmd.sidemove = ucmd.sidemove;
  7812. cmd.tick_count = ucmd.tick_count;
  7813. cmd.upmove = ucmd.upmove;
  7814. cmd.viewangles = ucmd.viewangles;
  7815. cmd.weaponselect = ucmd.weaponselect;
  7816. cmd.weaponsubtype = ucmd.weaponsubtype;
  7817. m_pParent->SetLastUserCommand(cmd);
  7818. }
  7819. }
  7820. CBotCmd CPlayerInfo::GetLastUserCommand()
  7821. {
  7822. CBotCmd cmd;
  7823. const CUserCmd *ucmd = m_pParent->GetLastUserCommand();
  7824. if ( ucmd )
  7825. {
  7826. cmd.buttons = ucmd->buttons;
  7827. cmd.command_number = ucmd->command_number;
  7828. cmd.forwardmove = ucmd->forwardmove;
  7829. cmd.hasbeenpredicted = ucmd->hasbeenpredicted;
  7830. cmd.impulse = ucmd->impulse;
  7831. cmd.mousedx = ucmd->mousedx;
  7832. cmd.mousedy = ucmd->mousedy;
  7833. cmd.random_seed = ucmd->random_seed;
  7834. cmd.sidemove = ucmd->sidemove;
  7835. cmd.tick_count = ucmd->tick_count;
  7836. cmd.upmove = ucmd->upmove;
  7837. cmd.viewangles = ucmd->viewangles;
  7838. cmd.weaponselect = ucmd->weaponselect;
  7839. cmd.weaponsubtype = ucmd->weaponsubtype;
  7840. }
  7841. return cmd;
  7842. }
  7843. // Notify that I've killed some other entity. (called from Victim's Event_Killed).
  7844. void CBasePlayer::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info )
  7845. {
  7846. BaseClass::Event_KilledOther( pVictim, info );
  7847. if ( pVictim != this )
  7848. {
  7849. #if !defined( _GAMECONSOLE ) || defined ( CSTRIKE15 )
  7850. gamestats->Event_PlayerKilledOther( this, pVictim, info );
  7851. #endif
  7852. }
  7853. }
  7854. void CBasePlayer::SetModel( const char *szModelName )
  7855. {
  7856. BaseClass::SetModel( szModelName );
  7857. MDLCACHE_CRITICAL_SECTION();
  7858. m_nBodyPitchPoseParam = LookupPoseParameter( "body_pitch" );
  7859. }
  7860. void CBasePlayer::SetBodyPitch( float flPitch )
  7861. {
  7862. if ( m_nBodyPitchPoseParam >= 0 )
  7863. {
  7864. SetPoseParameter( m_nBodyPitchPoseParam, flPitch );
  7865. }
  7866. }
  7867. void CBasePlayer::AdjustDrownDmg( int nAmount )
  7868. {
  7869. m_idrowndmg += nAmount;
  7870. if ( m_idrowndmg < m_idrownrestored )
  7871. {
  7872. m_idrowndmg = m_idrownrestored;
  7873. }
  7874. }
  7875. void CBasePlayer::SetSplitScreenPlayer( bool bSplitScreenPlayer, CBasePlayer *pOwner )
  7876. {
  7877. m_bSplitScreenPlayer = bSplitScreenPlayer;
  7878. m_hSplitOwner = pOwner;
  7879. if ( pOwner )
  7880. {
  7881. pOwner->AddSplitScreenPlayer( this );
  7882. }
  7883. }
  7884. bool CBasePlayer::IsSplitScreenPartner( CBasePlayer *pPlayer )
  7885. {
  7886. if ( !pPlayer )
  7887. return false;
  7888. if ( pPlayer->GetSplitScreenPlayerOwner() == this )
  7889. return true;
  7890. if ( GetSplitScreenPlayerOwner() == pPlayer )
  7891. return true;
  7892. return false;
  7893. }
  7894. CBasePlayer *CBasePlayer::GetSplitScreenPlayerOwner()
  7895. {
  7896. return m_hSplitOwner;
  7897. }
  7898. bool CBasePlayer::IsSplitScreenPlayer() const
  7899. {
  7900. return m_bSplitScreenPlayer;
  7901. }
  7902. bool CBasePlayer::IsSplitScreenUserOnEdict( edict_t *edict )
  7903. {
  7904. if ( !IsSplitScreenPlayer() )
  7905. return false;
  7906. CBaseEntity *pCont = GetContainingEntity( edict );
  7907. return ( pCont && ( pCont == GetSplitScreenPlayerOwner() ) );
  7908. }
  7909. int CBasePlayer::GetSplitScreenPlayerSlot()
  7910. {
  7911. if ( !IsSplitScreenPlayer() )
  7912. return 0;
  7913. CBasePlayer *pHost = GetSplitScreenPlayerOwner();
  7914. Assert( pHost );
  7915. Assert( pHost != this );
  7916. for ( int i = 1; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  7917. {
  7918. edict_t *ed = engine->GetSplitScreenPlayerForEdict( pHost->entindex(), i ) ;
  7919. if ( GetContainingEntity( ed ) == this )
  7920. {
  7921. return i;
  7922. }
  7923. }
  7924. Assert( 0 );
  7925. return 0;
  7926. }
  7927. void CBasePlayer::SetCrossPlayPlatform( CrossPlayPlatform_t clientPlatform )
  7928. {
  7929. m_ClientPlatform = clientPlatform;
  7930. }
  7931. CrossPlayPlatform_t CBasePlayer::GetCrossPlayPlatform( void ) const
  7932. {
  7933. return m_ClientPlatform;
  7934. }
  7935. bool CBasePlayer::EnsureSplitScreenTeam()
  7936. {
  7937. // If forcing all split screen users onto same team, and this is a split screen player, and the host player has chosen an actual game team,
  7938. // then force us onto his/her team, too!!!
  7939. if ( GameRules()->ForceSplitScreenPlayersOnToSameTeam() &&
  7940. IsSplitScreenPlayer() &&
  7941. GetSplitScreenPlayerOwner() &&
  7942. GetSplitScreenPlayerOwner()->GetTeamNumber() >= FIRST_GAME_TEAM )
  7943. {
  7944. if ( GetTeamNumber() != GetSplitScreenPlayerOwner()->GetTeamNumber() )
  7945. {
  7946. Msg( "Forcing split screen player onto team %s\n", GetTeamName( GetSplitScreenPlayerOwner()->GetTeamNumber() ) );
  7947. ForceChangeTeam( GetSplitScreenPlayerOwner()->GetTeamNumber() );
  7948. return true;
  7949. }
  7950. }
  7951. return false;
  7952. }
  7953. class CUserMessageThrottleMgr
  7954. {
  7955. public:
  7956. CUserMessageThrottleMgr();
  7957. void Start( char const *pchMessageNames[], int nNumMessageNames );
  7958. void Finish();
  7959. bool ShouldThrottle( CBasePlayer *pPlayer, char const *pchMessageName );
  7960. private:
  7961. // Per messagename bit vector of which player's have seen the message
  7962. CUtlDict< CPlayerBitVec, int > m_SentMessage;
  7963. };
  7964. static CUserMessageThrottleMgr g_ThrottleMgr;
  7965. CUserMessageThrottleMgr::CUserMessageThrottleMgr()
  7966. {
  7967. }
  7968. void CUserMessageThrottleMgr::Start( char const *pchMessageNames[], int nNumMessageNames )
  7969. {
  7970. m_SentMessage.Purge();
  7971. for ( int i = 0; i < nNumMessageNames; ++i )
  7972. {
  7973. int idx = m_SentMessage.Insert( pchMessageNames[ i ] );
  7974. m_SentMessage[ idx ].ClearAll();
  7975. }
  7976. }
  7977. void CUserMessageThrottleMgr::Finish()
  7978. {
  7979. m_SentMessage.RemoveAll();
  7980. }
  7981. bool CUserMessageThrottleMgr::ShouldThrottle( CBasePlayer *pPlayer, char const *pchMessageName )
  7982. {
  7983. int idx = m_SentMessage.Find( pchMessageName );
  7984. if ( idx == m_SentMessage.InvalidIndex() )
  7985. {
  7986. // Not in list.
  7987. return false;
  7988. }
  7989. int nPlayerIndex = pPlayer->entindex();
  7990. nPlayerIndex--;
  7991. CPlayerBitVec &data = m_SentMessage[ idx ];
  7992. if ( data.IsBitSet( nPlayerIndex ) )
  7993. return true;
  7994. data.Set( nPlayerIndex );
  7995. return false;
  7996. }
  7997. void CBasePlayer::StartUserMessageThrottling( char const *pchMessageNames[], int nNumMessageNames )
  7998. {
  7999. g_ThrottleMgr.Start( pchMessageNames, nNumMessageNames );
  8000. }
  8001. void CBasePlayer::FinishUserMessageThrottling()
  8002. {
  8003. g_ThrottleMgr.Finish();
  8004. }
  8005. bool CBasePlayer::ShouldThrottleUserMessage( char const *pchMessageName )
  8006. {
  8007. return g_ThrottleMgr.ShouldThrottle( this, pchMessageName );
  8008. }
  8009. //-----------------------------------------------------------------------------
  8010. // Purpose: Allow bots etc to use slightly different solid masks
  8011. //-----------------------------------------------------------------------------
  8012. unsigned int CBasePlayer::PlayerSolidMask( bool brushOnly ) const
  8013. {
  8014. if ( brushOnly )
  8015. {
  8016. return MASK_PLAYERSOLID_BRUSHONLY;
  8017. }
  8018. return MASK_PLAYERSOLID;
  8019. }
  8020. CLogicPlayerProxy *CBasePlayer::GetPlayerProxy( void )
  8021. {
  8022. CLogicPlayerProxy *pProxy = dynamic_cast< CLogicPlayerProxy* > ( m_hPlayerProxy.Get() );
  8023. if ( pProxy == NULL )
  8024. {
  8025. pProxy = (CLogicPlayerProxy*)gEntList.FindEntityByClassname(NULL, "logic_playerproxy" );
  8026. if ( pProxy == NULL )
  8027. return NULL;
  8028. pProxy->m_hPlayer = this;
  8029. m_hPlayerProxy = pProxy;
  8030. }
  8031. return pProxy;
  8032. }
  8033. void CBasePlayer::FirePlayerProxyOutput( const char *pszOutputName, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller )
  8034. {
  8035. if ( GetPlayerProxy() == NULL )
  8036. return;
  8037. GetPlayerProxy()->FireNamedOutput( pszOutputName, variant, pActivator, pCaller );
  8038. }
  8039. //--------------------------------------------------------------------------------------------------------
  8040. void CBasePlayer::UpdateFXVolume( void )
  8041. {
  8042. CFogController *pFogController = NULL;
  8043. CPostProcessController *pPostProcessController = NULL;
  8044. CColorCorrection* pColorCorrectionEnt = NULL;
  8045. Vector eyePos;
  8046. CBaseEntity *pViewEntity = GetViewEntity();
  8047. if ( pViewEntity )
  8048. {
  8049. eyePos = pViewEntity->GetAbsOrigin();
  8050. }
  8051. else
  8052. {
  8053. eyePos = EyePosition();
  8054. }
  8055. CFogVolume *pFogVolume = CFogVolume::FindFogVolumeForPosition( eyePos );
  8056. if ( pFogVolume )
  8057. {
  8058. pFogController = pFogVolume->GetFogController();
  8059. pPostProcessController = pFogVolume->GetPostProcessController();
  8060. pColorCorrectionEnt = pFogVolume->GetColorCorrectionController();
  8061. if ( !pFogController )
  8062. {
  8063. pFogController = FogSystem()->GetMasterFogController();
  8064. }
  8065. if ( !pPostProcessController )
  8066. {
  8067. pPostProcessController = PostProcessSystem()->GetMasterPostProcessController();
  8068. }
  8069. if ( !pColorCorrectionEnt )
  8070. {
  8071. pColorCorrectionEnt = ColorCorrectionSystem()->GetMasterColorCorrection();
  8072. }
  8073. }
  8074. else if ( TheFogVolumes.Count() > 0 )
  8075. {
  8076. // If we're not in a fog volume, clear our fog volume, if the map has any.
  8077. // This will get us back to using the master fog controller.
  8078. pFogController = FogSystem()->GetMasterFogController();
  8079. pPostProcessController = PostProcessSystem()->GetMasterPostProcessController();
  8080. pColorCorrectionEnt = ColorCorrectionSystem()->GetMasterColorCorrection();
  8081. }
  8082. if ( pFogController && m_PlayerFog.m_hCtrl.Get() != pFogController )
  8083. {
  8084. m_PlayerFog.m_hCtrl.Set( pFogController );
  8085. }
  8086. if ( pPostProcessController )
  8087. {
  8088. m_hPostProcessCtrl.Set( pPostProcessController );
  8089. }
  8090. if ( pColorCorrectionEnt )
  8091. {
  8092. m_hColorCorrectionCtrl.Set( pColorCorrectionEnt );
  8093. }
  8094. }
  8095. CVoteController* CBasePlayer::GetTeamVoteController()
  8096. {
  8097. switch ( GetAssociatedTeamNumber( ) )
  8098. {
  8099. case TEAM_CT:
  8100. return g_voteControllerCT;
  8101. case TEAM_TERRORIST:
  8102. return g_voteControllerT;
  8103. // SPECTATOR or other
  8104. default:
  8105. return g_voteControllerGlobal;
  8106. }
  8107. }
  8108. bool CBasePlayer::HandleVoteCommands( const CCommand &args )
  8109. {
  8110. if( !g_voteControllerGlobal && !GetTeamVoteController() )
  8111. return false;
  8112. if( FStrEq( args[0], "Vote" ) )
  8113. {
  8114. if( args.ArgC() < 2 )
  8115. return true;
  8116. const char *arg2 = args[1];
  8117. char szResultString[MAX_COMMAND_LENGTH];
  8118. CVoteController *pVoteController = NULL;
  8119. // is there a global or team vote to participate in and if so, which?
  8120. if ( g_voteControllerGlobal && g_voteControllerGlobal->IsAVoteInProgress( ) )
  8121. {
  8122. pVoteController = g_voteControllerGlobal;
  8123. }
  8124. else if ( GetTeamVoteController( ) && GetTeamVoteController( )->IsAVoteInProgress( ) )
  8125. {
  8126. pVoteController = GetTeamVoteController( );
  8127. }
  8128. else
  8129. {
  8130. Q_snprintf( szResultString, MAX_COMMAND_LENGTH, "Vote failed: no vote in progress.\n" );
  8131. DevMsg( "%s", szResultString );
  8132. return true;
  8133. }
  8134. if ( !pVoteController )
  8135. return true;
  8136. CVoteController::TryCastVoteResult nTryResult = pVoteController->TryCastVote( entindex( ), arg2 );
  8137. switch( nTryResult )
  8138. {
  8139. case CVoteController::CAST_OK:
  8140. {
  8141. Q_snprintf( szResultString, MAX_COMMAND_LENGTH, "Voting %s.\n", arg2 );
  8142. break;
  8143. }
  8144. case CVoteController::CAST_FAIL_SERVER_DISABLE:
  8145. {
  8146. Q_snprintf( szResultString, MAX_COMMAND_LENGTH, "Vote failed: server disabled.\n" );
  8147. break;
  8148. }
  8149. case CVoteController::CAST_FAIL_NO_ACTIVE_ISSUE:
  8150. {
  8151. Q_snprintf( szResultString, MAX_COMMAND_LENGTH, "Vote failed: no active issue.\n" );
  8152. break;
  8153. }
  8154. case CVoteController::CAST_FAIL_TEAM_RESTRICTED:
  8155. {
  8156. Q_snprintf( szResultString, MAX_COMMAND_LENGTH, "Vote failed: team restricted.\n" );
  8157. break;
  8158. }
  8159. case CVoteController::CAST_FAIL_NO_CHANGES:
  8160. {
  8161. Q_snprintf( szResultString, MAX_COMMAND_LENGTH, "Vote failed: no changing vote.\n" );
  8162. break;
  8163. }
  8164. case CVoteController::CAST_FAIL_DUPLICATE:
  8165. {
  8166. Q_snprintf( szResultString, MAX_COMMAND_LENGTH, "Vote failed: already voting %s.\n", arg2 );
  8167. break;
  8168. }
  8169. case CVoteController::CAST_FAIL_VOTE_CLOSED:
  8170. {
  8171. Q_snprintf( szResultString, MAX_COMMAND_LENGTH, "Vote failed: voting closed.\n" );
  8172. break;
  8173. }
  8174. case CVoteController::CAST_FAIL_SYSTEM_ERROR:
  8175. default:
  8176. {
  8177. Q_snprintf( szResultString, MAX_COMMAND_LENGTH, "Vote failed: system error.\n" );
  8178. break;
  8179. }
  8180. }
  8181. DevMsg( "%s", szResultString );
  8182. return true;
  8183. }
  8184. return false;
  8185. }
  8186. #if !defined(NO_STEAM)
  8187. //-----------------------------------------------------------------------------
  8188. // Purpose:
  8189. //-----------------------------------------------------------------------------
  8190. bool CBasePlayer::GetSteamID( CSteamID *pID, bool bRequireFullyAuthenticated )
  8191. {
  8192. const CSteamID *pClientID = engine->GetClientSteamID( edict(), bRequireFullyAuthenticated );
  8193. if ( pClientID )
  8194. {
  8195. *pID = *pClientID;
  8196. return true;
  8197. }
  8198. return false;
  8199. }
  8200. //-----------------------------------------------------------------------------
  8201. // Purpose:
  8202. //-----------------------------------------------------------------------------
  8203. uint64 CBasePlayer::GetSteamIDAsUInt64( void )
  8204. {
  8205. CSteamID steamIDForPlayer;
  8206. if ( GetSteamID( &steamIDForPlayer ) )
  8207. return steamIDForPlayer.ConvertToUint64();
  8208. return 0;
  8209. }
  8210. #endif // NO_STEAM