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.

3809 lines
117 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =====//
  2. //
  3. // Purpose: Client-side CBasePlayer.
  4. //
  5. // - Manages the player's flashlight effect.
  6. //
  7. //===========================================================================//
  8. #include "cbase.h"
  9. #include "c_baseplayer.h"
  10. #include "c_user_message_register.h"
  11. #include "flashlighteffect.h"
  12. #include "weapon_selection.h"
  13. #include "history_resource.h"
  14. #include "iinput.h"
  15. #include "input.h"
  16. #include "ammodef.h"
  17. #include "view.h"
  18. #include "iviewrender.h"
  19. #include "iclientmode.h"
  20. #include "in_buttons.h"
  21. #include "engine/IEngineSound.h"
  22. #include "c_soundscape.h"
  23. #include "usercmd.h"
  24. #include "c_playerresource.h"
  25. #include "iclientvehicle.h"
  26. #include "view_shared.h"
  27. #include "movevars_shared.h"
  28. #include "prediction.h"
  29. #include "tier0/vprof.h"
  30. #include "filesystem.h"
  31. #include "bitbuf.h"
  32. #include "keyvalues.h"
  33. #include "particles_simple.h"
  34. #include "fx_water.h"
  35. #include "hltvcamera.h"
  36. #include "hltvreplaysystem.h"
  37. #include "netmessages.h"
  38. #if defined( REPLAY_ENABLED )
  39. #include "replaycamera.h"
  40. #endif
  41. #include "toolframework/itoolframework.h"
  42. #include "toolframework_client.h"
  43. #include "view_scene.h"
  44. #include "c_vguiscreen.h"
  45. #include "datacache/imdlcache.h"
  46. #include "vgui/ISurface.h"
  47. #include "voice_status.h"
  48. #include "fx.h"
  49. #include "cellcoord.h"
  50. #include "vphysics/player_controller.h"
  51. #include "debugoverlay_shared.h"
  52. #include "iclient.h"
  53. #include "steam/steam_api.h"
  54. #include "platforminputdevice.h"
  55. #include "inputsystem/iinputsystem.h"
  56. #if defined( INCLUDE_SCALEFORM ) && defined( CSTRIKE_DLL )
  57. #include "HUD/sfweaponselection.h"
  58. #include "Scaleform/HUD/sfhudfreezepanel.h"
  59. #include "cs_weapon_parse.h"
  60. #endif
  61. #ifdef DEMOPOLISH_ENABLED
  62. #include "demo_polish/demo_polish.h"
  63. #endif
  64. // memdbgon must be the last include file in a .cpp file!!!
  65. #include "tier0/memdbgon.h"
  66. // Don't alias here
  67. #if defined( CBasePlayer )
  68. #undef CBasePlayer
  69. #endif
  70. int g_nKillCamMode = OBS_MODE_NONE;
  71. int g_nKillCamTarget1 = 0;
  72. int g_nKillCamTarget2 = 0;
  73. extern ConVar mp_forcecamera; // in gamevars_shared.h
  74. extern ConVar r_mapextents;
  75. extern ConVar voice_icons_method;
  76. extern ConVar view_recoil_tracking;
  77. #define FLASHLIGHT_DISTANCE 1000
  78. #define MAX_VGUI_INPUT_MODE_SPEED 30
  79. #define MAX_VGUI_INPUT_MODE_SPEED_SQ (MAX_VGUI_INPUT_MODE_SPEED*MAX_VGUI_INPUT_MODE_SPEED)
  80. static Vector WALL_MIN(-WALL_OFFSET,-WALL_OFFSET,-WALL_OFFSET);
  81. static Vector WALL_MAX(WALL_OFFSET,WALL_OFFSET,WALL_OFFSET);
  82. bool CommentaryModeShouldSwallowInput( C_BasePlayer *pPlayer );
  83. extern ConVar default_fov;
  84. extern ConVar sensitivity;
  85. extern ConVar voice_all_icons;
  86. static C_BasePlayer *s_pLocalPlayer[ MAX_SPLITSCREEN_PLAYERS ];
  87. static ConVar cl_customsounds ( "cl_customsounds", "0", 0, "Enable customized player sound playback" );
  88. static ConVar spec_track ( "spec_track", "0", 0, "Tracks an entity in spec mode" );
  89. static ConVar cl_smooth ( "cl_smooth", "1", 0, "Smooth view/eye origin after prediction errors" );
  90. static ConVar cl_smoothtime (
  91. "cl_smoothtime",
  92. "0.1",
  93. 0,
  94. "Smooth client's view after prediction error over this many seconds",
  95. true, 0.01, // min/max is 0.01/2.0
  96. true, 2.0
  97. );
  98. #ifdef CSTRIKE15
  99. ConVar spec_freeze_time( "spec_freeze_time", "3.0", FCVAR_RELEASE | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." );
  100. 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 );
  101. ConVar spec_freeze_traveltime_long( "spec_freeze_traveltime_long", "0.45", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam when they are far away.", true, 0.01, false, 0 );
  102. ConVar spec_freeze_distance_min( "spec_freeze_distance_min", "60", FCVAR_CHEAT, "Minimum random distance from the target to stop when framing them in observer freeze cam." );
  103. ConVar spec_freeze_distance_max( "spec_freeze_distance_max", "80", FCVAR_CHEAT, "Maximum random distance from the target to stop when framing them in observer freeze cam." );
  104. 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." );
  105. 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." );
  106. 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." );
  107. ConVar spec_freeze_target_fov( "spec_freeze_target_fov", "42", FCVAR_CHEAT | FCVAR_REPLICATED, "The target FOV that the deathcam should use." );
  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. ConVar spec_freeze_distance_min( "spec_freeze_distance_min", "96", FCVAR_CHEAT, "Minimum random distance from the target to stop when framing them in observer freeze cam." );
  112. ConVar spec_freeze_distance_max( "spec_freeze_distance_max", "200", FCVAR_CHEAT, "Maximum random distance from the target to stop when framing them in observer freeze cam." );
  113. #endif
  114. ConVar cl_player_fullupdate_predicted_origin_fix( "cl_player_fullupdate_predicted_origin_fix", "1" );
  115. ConVar spec_lock_to_accountid( "spec_lock_to_accountid", "", FCVAR_RELEASE, "As an observer, lock the spectate target to the given accountid." );
  116. bool IsDemoPolishRecording();
  117. // -------------------------------------------------------------------------------- //
  118. // RecvTable for CPlayerState.
  119. // -------------------------------------------------------------------------------- //
  120. BEGIN_RECV_TABLE_NOBASE(CPlayerState, DT_PlayerState)
  121. RecvPropInt (RECVINFO(deadflag)),
  122. END_RECV_TABLE()
  123. BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local )
  124. RecvPropArray3( RECVINFO_ARRAY(m_chAreaBits), RecvPropInt(RECVINFO(m_chAreaBits[0]))),
  125. RecvPropArray3( RECVINFO_ARRAY(m_chAreaPortalBits), RecvPropInt(RECVINFO(m_chAreaPortalBits[0]))),
  126. RecvPropInt(RECVINFO(m_iHideHUD)),
  127. // View
  128. RecvPropFloat(RECVINFO(m_flFOVRate)),
  129. RecvPropInt (RECVINFO(m_bDucked)),
  130. RecvPropInt (RECVINFO(m_bDucking)),
  131. RecvPropFloat (RECVINFO(m_flLastDuckTime)),
  132. RecvPropInt (RECVINFO(m_bInDuckJump)),
  133. RecvPropInt (RECVINFO(m_nDuckTimeMsecs)),
  134. RecvPropInt (RECVINFO(m_nDuckJumpTimeMsecs)),
  135. RecvPropInt (RECVINFO(m_nJumpTimeMsecs)),
  136. RecvPropFloat (RECVINFO(m_flFallVelocity)),
  137. #if PREDICTION_ERROR_CHECK_LEVEL > 1
  138. RecvPropFloat (RECVINFO_NAME( m_viewPunchAngle.m_Value[0], m_viewPunchAngle[0])),
  139. RecvPropFloat (RECVINFO_NAME( m_viewPunchAngle.m_Value[1], m_viewPunchAngle[1])),
  140. RecvPropFloat (RECVINFO_NAME( m_viewPunchAngle.m_Value[2], m_viewPunchAngle[2] )),
  141. RecvPropFloat (RECVINFO_NAME( m_aimPunchAngle.m_Value[0], m_aimPunchAngle[0])),
  142. RecvPropFloat (RECVINFO_NAME( m_aimPunchAngle.m_Value[1], m_aimPunchAngle[1])),
  143. RecvPropFloat (RECVINFO_NAME( m_aimPunchAngle.m_Value[2], m_aimPunchAngle[2] )),
  144. RecvPropFloat (RECVINFO_NAME( m_aimPunchAngleVel.m_Value[0], m_aimPunchAngleVel[0] )),
  145. RecvPropFloat (RECVINFO_NAME( m_aimPunchAngleVel.m_Value[1], m_aimPunchAngleVel[1] )),
  146. RecvPropFloat (RECVINFO_NAME( m_aimPunchAngleVel.m_Value[2], m_aimPunchAngleVel[2] )),
  147. #else
  148. RecvPropVector (RECVINFO(m_viewPunchAngle)),
  149. RecvPropVector (RECVINFO(m_aimPunchAngle)),
  150. RecvPropVector (RECVINFO(m_aimPunchAngleVel)),
  151. #endif
  152. RecvPropInt (RECVINFO(m_bDrawViewmodel)),
  153. RecvPropInt (RECVINFO(m_bWearingSuit)),
  154. RecvPropBool (RECVINFO(m_bPoisoned)),
  155. RecvPropFloat (RECVINFO(m_flStepSize)),
  156. RecvPropInt (RECVINFO(m_bAllowAutoMovement)),
  157. // 3d skybox data
  158. RecvPropInt(RECVINFO(m_skybox3d.scale)),
  159. RecvPropVector(RECVINFO(m_skybox3d.origin)),
  160. RecvPropInt(RECVINFO(m_skybox3d.area)),
  161. // 3d skybox fog data
  162. RecvPropInt( RECVINFO( m_skybox3d.fog.enable ) ),
  163. RecvPropInt( RECVINFO( m_skybox3d.fog.blend ) ),
  164. RecvPropVector( RECVINFO( m_skybox3d.fog.dirPrimary ) ),
  165. RecvPropInt( RECVINFO( m_skybox3d.fog.colorPrimary ), 0, RecvProxy_Int32ToColor32 ),
  166. RecvPropInt( RECVINFO( m_skybox3d.fog.colorSecondary ), 0, RecvProxy_Int32ToColor32 ),
  167. RecvPropFloat( RECVINFO( m_skybox3d.fog.start ) ),
  168. RecvPropFloat( RECVINFO( m_skybox3d.fog.end ) ),
  169. RecvPropFloat( RECVINFO( m_skybox3d.fog.maxdensity ) ),
  170. RecvPropFloat( RECVINFO( m_skybox3d.fog.HDRColorScale ) ),
  171. // audio data
  172. RecvPropVector( RECVINFO( m_audio.localSound[0] ) ),
  173. RecvPropVector( RECVINFO( m_audio.localSound[1] ) ),
  174. RecvPropVector( RECVINFO( m_audio.localSound[2] ) ),
  175. RecvPropVector( RECVINFO( m_audio.localSound[3] ) ),
  176. RecvPropVector( RECVINFO( m_audio.localSound[4] ) ),
  177. RecvPropVector( RECVINFO( m_audio.localSound[5] ) ),
  178. RecvPropVector( RECVINFO( m_audio.localSound[6] ) ),
  179. RecvPropVector( RECVINFO( m_audio.localSound[7] ) ),
  180. RecvPropInt( RECVINFO( m_audio.soundscapeIndex ) ),
  181. RecvPropInt( RECVINFO( m_audio.localBits ) ),
  182. RecvPropInt( RECVINFO( m_audio.entIndex ) ),
  183. END_RECV_TABLE()
  184. // -------------------------------------------------------------------------------- //
  185. // This data only gets sent to clients that ARE this player entity.
  186. // -------------------------------------------------------------------------------- //
  187. BEGIN_RECV_TABLE_NOBASE( C_BasePlayer, DT_LocalPlayerExclusive )
  188. RecvPropDataTable ( RECVINFO_DT(m_Local),0, &REFERENCE_RECV_TABLE(DT_Local) ),
  189. RecvPropFloat ( RECVINFO(m_vecViewOffset[0]) ),
  190. RecvPropFloat ( RECVINFO(m_vecViewOffset[1]) ),
  191. RecvPropFloat ( RECVINFO(m_vecViewOffset[2]) ),
  192. RecvPropFloat ( RECVINFO(m_flFriction) ),
  193. RecvPropInt ( RECVINFO(m_fOnTarget) ),
  194. RecvPropInt ( RECVINFO( m_nTickBase ) ),
  195. RecvPropInt ( RECVINFO( m_nNextThinkTick ) ),
  196. RecvPropEHandle ( RECVINFO( m_hLastWeapon ) ),
  197. RecvPropFloat ( RECVINFO(m_vecVelocity[0]), 0, C_BasePlayer::RecvProxy_LocalVelocityX ),
  198. RecvPropFloat ( RECVINFO(m_vecVelocity[1]), 0, C_BasePlayer::RecvProxy_LocalVelocityY ),
  199. RecvPropFloat ( RECVINFO(m_vecVelocity[2]), 0, C_BasePlayer::RecvProxy_LocalVelocityZ ),
  200. RecvPropVector ( RECVINFO( m_vecBaseVelocity ) ),
  201. RecvPropEHandle ( RECVINFO( m_hConstraintEntity)),
  202. RecvPropVector ( RECVINFO( m_vecConstraintCenter) ),
  203. RecvPropFloat ( RECVINFO( m_flConstraintRadius )),
  204. RecvPropFloat ( RECVINFO( m_flConstraintWidth )),
  205. RecvPropFloat ( RECVINFO( m_flConstraintSpeedFactor )),
  206. RecvPropBool ( RECVINFO( m_bConstraintPastRadius )),
  207. RecvPropFloat ( RECVINFO( m_flDeathTime )),
  208. RecvPropFloat ( RECVINFO( m_flNextDecalTime )),
  209. RecvPropFloat ( RECVINFO( m_fForceTeam )),
  210. RecvPropInt ( RECVINFO( m_nWaterLevel ) ),
  211. RecvPropFloat ( RECVINFO( m_flLaggedMovementValue )),
  212. RecvPropEHandle ( RECVINFO( m_hTonemapController ) ),
  213. END_RECV_TABLE()
  214. // -------------------------------------------------------------------------------- //
  215. // DT_BasePlayer datatable.
  216. // -------------------------------------------------------------------------------- //
  217. IMPLEMENT_CLIENTCLASS_DT(C_BasePlayer, DT_BasePlayer, CBasePlayer)
  218. // We have both the local and nonlocal data in here, but the server proxies
  219. // only send one.
  220. RecvPropDataTable( "localdata", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalPlayerExclusive) ),
  221. RecvPropDataTable(RECVINFO_DT(pl), 0, &REFERENCE_RECV_TABLE(DT_PlayerState), DataTableRecvProxy_StaticDataTable),
  222. RecvPropInt (RECVINFO(m_iFOV)),
  223. RecvPropInt (RECVINFO(m_iFOVStart)),
  224. RecvPropFloat (RECVINFO(m_flFOVTime)),
  225. RecvPropInt (RECVINFO(m_iDefaultFOV)),
  226. RecvPropEHandle (RECVINFO(m_hZoomOwner)),
  227. RecvPropInt( RECVINFO(m_afPhysicsFlags) ),
  228. RecvPropEHandle( RECVINFO(m_hVehicle) ),
  229. RecvPropEHandle( RECVINFO(m_hUseEntity) ),
  230. RecvPropEHandle ( RECVINFO( m_hGroundEntity ) ),
  231. RecvPropInt (RECVINFO(m_iHealth)),
  232. RecvPropInt (RECVINFO(m_lifeState)),
  233. RecvPropArray3 ( RECVINFO_ARRAY(m_iAmmo), RecvPropInt( RECVINFO(m_iAmmo[0])) ),
  234. RecvPropInt (RECVINFO(m_iBonusProgress)),
  235. RecvPropInt (RECVINFO(m_iBonusChallenge)),
  236. RecvPropFloat (RECVINFO(m_flMaxspeed)),
  237. RecvPropInt (RECVINFO(m_fFlags)),
  238. RecvPropInt (RECVINFO(m_iObserverMode), 0, C_BasePlayer::RecvProxy_ObserverMode ),
  239. RecvPropBool (RECVINFO(m_bActiveCameraMan)),
  240. RecvPropBool (RECVINFO(m_bCameraManXRay)),
  241. RecvPropBool (RECVINFO(m_bCameraManOverview)),
  242. RecvPropBool (RECVINFO(m_bCameraManScoreBoard)),
  243. RecvPropInt (RECVINFO(m_uCameraManGraphs)),
  244. RecvPropInt (RECVINFO( m_iDeathPostEffect ) ),
  245. RecvPropEHandle (RECVINFO(m_hObserverTarget), C_BasePlayer::RecvProxy_ObserverTarget ),
  246. RecvPropArray ( RecvPropEHandle( RECVINFO( m_hViewModel[0] ) ), m_hViewModel ),
  247. RecvPropInt (RECVINFO(m_iCoachingTeam)),
  248. RecvPropString( RECVINFO(m_szLastPlaceName) ),
  249. RecvPropVector( RECVINFO(m_vecLadderNormal) ),
  250. RecvPropInt (RECVINFO(m_ladderSurfaceProps) ),
  251. RecvPropInt( RECVINFO( m_ubEFNoInterpParity ) ),
  252. RecvPropEHandle( RECVINFO( m_hPostProcessCtrl ) ), // Send to everybody - for spectating
  253. RecvPropEHandle( RECVINFO( m_hColorCorrectionCtrl ) ), // Send to everybody - for spectating
  254. // fog data
  255. RecvPropEHandle( RECVINFO( m_PlayerFog.m_hCtrl ) ),
  256. RecvPropInt( RECVINFO( m_vphysicsCollisionState ) ),
  257. #if defined( DEBUG_MOTION_CONTROLLERS )
  258. RecvPropVector( RECVINFO( m_Debug_vPhysPosition ) ),
  259. RecvPropVector( RECVINFO( m_Debug_vPhysVelocity ) ),
  260. RecvPropVector( RECVINFO( m_Debug_LinearAccel ) ),
  261. RecvPropVector( RECVINFO( m_vNewVPhysicsPosition ) ),
  262. RecvPropVector( RECVINFO( m_vNewVPhysicsVelocity ) ),
  263. #endif
  264. RecvPropEHandle ( RECVINFO( m_hViewEntity ) ), // L4D: send view entity to everyone for first-person spectating
  265. RecvPropBool ( RECVINFO( m_bShouldDrawPlayerWhileUsingViewEntity ) ),
  266. RecvPropFloat (RECVINFO(m_flDuckAmount)),
  267. RecvPropFloat (RECVINFO(m_flDuckSpeed)),
  268. END_RECV_TABLE()
  269. BEGIN_PREDICTION_DATA_NO_BASE( CPlayerState )
  270. DEFINE_PRED_FIELD( deadflag, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  271. // DEFINE_FIELD( netname, string_t ),
  272. // DEFINE_FIELD( fixangle, FIELD_INTEGER ),
  273. // DEFINE_FIELD( anglechange, FIELD_FLOAT ),
  274. // DEFINE_FIELD( v_angle, FIELD_VECTOR ),
  275. END_PREDICTION_DATA()
  276. BEGIN_PREDICTION_DATA_NO_BASE( CPlayerLocalData )
  277. // DEFINE_PRED_TYPEDESCRIPTION( m_skybox3d, sky3dparams_t ),
  278. // DEFINE_PRED_TYPEDESCRIPTION( m_fog, fogparams_t ),
  279. // DEFINE_PRED_TYPEDESCRIPTION( m_audio, audioparams_t ),
  280. DEFINE_FIELD( m_nStepside, FIELD_INTEGER ),
  281. DEFINE_PRED_FIELD( m_iHideHUD, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  282. #if PREDICTION_ERROR_CHECK_LEVEL > 1
  283. DEFINE_PRED_FIELD( m_viewPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
  284. DEFINE_PRED_FIELD( m_aimPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
  285. DEFINE_PRED_FIELD( m_aimPunchAngleVel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
  286. #else
  287. DEFINE_PRED_FIELD_TOL( m_viewPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ),
  288. DEFINE_PRED_FIELD_TOL( m_aimPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ),
  289. DEFINE_PRED_FIELD_TOL( m_aimPunchAngleVel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ),
  290. #endif
  291. DEFINE_PRED_FIELD( m_bDrawViewmodel, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  292. DEFINE_PRED_FIELD( m_bWearingSuit, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  293. DEFINE_PRED_FIELD( m_bPoisoned, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  294. DEFINE_PRED_FIELD( m_bAllowAutoMovement, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  295. DEFINE_PRED_FIELD( m_bDucked, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  296. DEFINE_PRED_FIELD( m_bDucking, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  297. DEFINE_PRED_FIELD( m_flLastDuckTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  298. DEFINE_PRED_FIELD( m_bInDuckJump, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  299. DEFINE_PRED_FIELD( m_nDuckTimeMsecs, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  300. DEFINE_PRED_FIELD( m_nDuckJumpTimeMsecs, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  301. DEFINE_PRED_FIELD( m_nJumpTimeMsecs, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  302. DEFINE_PRED_FIELD_TOL( m_flFallVelocity, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ),
  303. // DEFINE_PRED_FIELD( m_nOldButtons, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  304. DEFINE_FIELD( m_nOldButtons, FIELD_INTEGER ),
  305. DEFINE_PRED_FIELD( m_flStepSize, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  306. DEFINE_FIELD( m_flFOVRate, FIELD_FLOAT ),
  307. END_PREDICTION_DATA()
  308. BEGIN_PREDICTION_DATA( C_BasePlayer )
  309. DEFINE_PRED_TYPEDESCRIPTION( m_Local, CPlayerLocalData ),
  310. DEFINE_PRED_TYPEDESCRIPTION( pl, CPlayerState ),
  311. DEFINE_PRED_FIELD( m_iFOV, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  312. DEFINE_PRED_FIELD( m_hZoomOwner, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
  313. DEFINE_PRED_FIELD( m_flFOVTime, FIELD_FLOAT, 0 ),
  314. DEFINE_PRED_FIELD( m_iFOVStart, FIELD_INTEGER, 0 ),
  315. DEFINE_FIELD( m_oldOrigin, FIELD_VECTOR ),
  316. DEFINE_FIELD( m_bTouchedPhysObject, FIELD_BOOLEAN ),
  317. DEFINE_FIELD( m_bPhysicsWasFrozen, FIELD_BOOLEAN ),
  318. #if defined( DEBUG_MOTION_CONTROLLERS )
  319. DEFINE_PRED_FIELD( m_vNewVPhysicsPosition, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
  320. DEFINE_PRED_FIELD( m_vNewVPhysicsVelocity, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
  321. #else
  322. DEFINE_FIELD( m_vNewVPhysicsPosition, FIELD_VECTOR ),
  323. DEFINE_FIELD( m_vNewVPhysicsVelocity, FIELD_VECTOR ),
  324. #endif
  325. DEFINE_PRED_FIELD( m_afPhysicsFlags, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ),
  326. DEFINE_PRED_FIELD( m_hVehicle, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
  327. DEFINE_PRED_FIELD_TOL( m_flMaxspeed, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ),
  328. DEFINE_PRED_FIELD( m_iHealth, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  329. DEFINE_PRED_FIELD( m_iBonusProgress, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  330. DEFINE_PRED_FIELD( m_iBonusChallenge, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  331. DEFINE_PRED_FIELD( m_fOnTarget, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  332. DEFINE_PRED_FIELD( m_nNextThinkTick, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  333. DEFINE_PRED_FIELD( m_lifeState, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
  334. DEFINE_PRED_FIELD( m_nWaterLevel, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
  335. DEFINE_PRED_FIELD_TOL( m_vecBaseVelocity, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.05 ),
  336. DEFINE_FIELD( m_nButtons, FIELD_INTEGER ),
  337. DEFINE_FIELD( m_flWaterJumpTime, FIELD_FLOAT ),
  338. DEFINE_FIELD( m_nImpulse, FIELD_INTEGER ),
  339. DEFINE_FIELD( m_flStepSoundTime, FIELD_FLOAT ),
  340. DEFINE_FIELD( m_flSwimSoundTime, FIELD_FLOAT ),
  341. DEFINE_FIELD( m_ignoreLadderJumpTime, FIELD_FLOAT ),
  342. DEFINE_FIELD( m_bHasWalkMovedSinceLastJump, FIELD_BOOLEAN ),
  343. DEFINE_FIELD( m_vecLadderNormal, FIELD_VECTOR ),
  344. DEFINE_FIELD( m_ladderSurfaceProps, FIELD_INTEGER ),
  345. DEFINE_FIELD( m_flPhysics, FIELD_INTEGER ),
  346. DEFINE_AUTO_ARRAY( m_szAnimExtension, FIELD_CHARACTER ),
  347. DEFINE_FIELD( m_afButtonLast, FIELD_INTEGER ),
  348. DEFINE_FIELD( m_afButtonPressed, FIELD_INTEGER ),
  349. DEFINE_FIELD( m_afButtonReleased, FIELD_INTEGER ),
  350. // DEFINE_FIELD( m_vecOldViewAngles, FIELD_VECTOR ),
  351. // DEFINE_ARRAY( m_iOldAmmo, FIELD_INTEGER, MAX_AMMO_TYPES ),
  352. //DEFINE_FIELD( m_hOldVehicle, FIELD_EHANDLE ),
  353. // DEFINE_FIELD( m_pModelLight, dlight_t* ),
  354. // DEFINE_FIELD( m_pEnvironmentLight, dlight_t* ),
  355. // DEFINE_FIELD( m_pBrightLight, dlight_t* ),
  356. DEFINE_PRED_FIELD( m_hLastWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
  357. DEFINE_PRED_FIELD( m_nTickBase, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  358. DEFINE_PRED_FIELD( m_hGroundEntity, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
  359. DEFINE_PRED_ARRAY( m_hViewModel, FIELD_EHANDLE, MAX_VIEWMODELS, FTYPEDESC_INSENDTABLE ),
  360. DEFINE_FIELD( m_surfaceFriction, FIELD_FLOAT ),
  361. DEFINE_FIELD( m_vecPreviouslyPredictedOrigin, FIELD_VECTOR ),
  362. DEFINE_PRED_FIELD( m_vphysicsCollisionState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  363. #if defined( DEBUG_MOTION_CONTROLLERS )
  364. DEFINE_PRED_FIELD( m_Debug_vPhysPosition, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
  365. DEFINE_PRED_FIELD( m_Debug_vPhysVelocity, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
  366. DEFINE_PRED_FIELD( m_Debug_LinearAccel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
  367. #endif
  368. DEFINE_PRED_FIELD( m_flDuckAmount, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  369. DEFINE_PRED_FIELD( m_flDuckSpeed, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  370. END_PREDICTION_DATA()
  371. #if !defined( PORTAL2 )
  372. LINK_ENTITY_TO_CLASS( player, C_BasePlayer );
  373. #endif
  374. // -------------------------------------------------------------------------------- //
  375. // Functions.
  376. // -------------------------------------------------------------------------------- //
  377. C_BasePlayer::C_BasePlayer() : m_iv_vecViewOffset( "C_BasePlayer::m_iv_vecViewOffset" )
  378. {
  379. AddVar( &m_vecViewOffset, &m_iv_vecViewOffset, LATCH_SIMULATION_VAR );
  380. #ifdef _DEBUG
  381. m_vecLadderNormal.Init();
  382. m_ladderSurfaceProps = 0;
  383. m_vecOldViewAngles.Init();
  384. #endif
  385. m_hViewEntity = NULL;
  386. m_bShouldDrawPlayerWhileUsingViewEntity = false;
  387. for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; i++ )
  388. {
  389. m_bFlashlightEnabled[ i ] = false;
  390. }
  391. m_pCurrentVguiScreen = NULL;
  392. m_pCurrentCommand = NULL;
  393. m_flPredictionErrorTime = -100;
  394. m_StuckLast = 0;
  395. m_bWasFrozen = false;
  396. m_bResampleWaterSurface = true;
  397. ResetObserverMode();
  398. m_bActiveCameraMan = false;
  399. m_bCameraManXRay = false;
  400. m_bCameraManOverview = false;
  401. m_bCameraManScoreBoard = false;
  402. m_uCameraManGraphs = 0;
  403. m_bLastActiveCameraManState = false;
  404. m_bLastCameraManXRayState = false;
  405. m_bLastCameraManOverviewState = false;
  406. m_bLastCameraManScoreBoardState = false;
  407. m_uLastCameraManGraphsState = 0;
  408. m_iDeathPostEffect = 0;
  409. m_flTimeLastTouchedGround = 0.0f;
  410. m_vecPredictionError.Init();
  411. m_flPredictionErrorTime = 0;
  412. m_surfaceProps = 0;
  413. m_pSurfaceData = NULL;
  414. m_surfaceFriction = 1.0f;
  415. m_chTextureType = 0;
  416. #if MAX_SPLITSCREEN_PLAYERS > 1
  417. m_nSplitScreenSlot = -1; // This is likely to catch bugs when running in splitscreen config and using local player before initializing the slots
  418. #else
  419. m_nSplitScreenSlot = 0; // When we are building without splitscreen all sorts of SFUI are using local player and might index arrays with negative index otherwise, but we know that only one player exists so just initialize for the correct slot!
  420. #endif
  421. m_bIsLocalPlayer = false;
  422. m_afButtonForced = 0;
  423. m_bDisableSimulationFix = true;
  424. m_flNextAchievementAnnounceTime = 0;
  425. m_flFreezePanelExtendedStartTime = 0;
  426. m_bWasFreezePanelExtended = false;
  427. m_bStartedFreezeFrame = false;
  428. m_bAbortedFreezeFrame = false;
  429. m_bFiredWeapon = false;
  430. m_vecHack_RecvProxy_LocalPlayerOrigin.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  431. m_ignoreLadderJumpTime = 0.0f;
  432. m_bPlayerIsTalkingOverVOIP = false;
  433. m_bCanShowFreezeFrameNow = false;
  434. m_nLastKillerDamageTaken = 0;
  435. m_nLastKillerHitsTaken = 0;
  436. m_nLastKillerDamageGiven = 0;
  437. m_nLastKillerHitsGiven = 0;
  438. // Init eye and angle offsets - used for TrackIR and motion controllers
  439. m_vecEyeOffset.Init();
  440. m_EyeAngleOffset.Init();
  441. m_AimDirection.Init();
  442. m_flDuckAmount = 0.0f;
  443. m_flDuckSpeed = CS_PLAYER_DUCK_SPEED_IDEAL;
  444. m_vecLastPositionAtFullCrouchSpeed = vec2_origin;
  445. m_bHasWalkMovedSinceLastJump = false;
  446. }
  447. //-----------------------------------------------------------------------------
  448. // Purpose:
  449. //-----------------------------------------------------------------------------
  450. C_BasePlayer::~C_BasePlayer()
  451. {
  452. if ( this == s_pLocalPlayer[ 0 ] )
  453. {
  454. extern void UntouchAllTriggerSoundOperator( C_BaseEntity *pEntity );
  455. UntouchAllTriggerSoundOperator( this );
  456. }
  457. DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
  458. for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  459. {
  460. if ( this == s_pLocalPlayer[ i ] )
  461. {
  462. s_pLocalPlayer[ i ] = NULL;
  463. }
  464. else if ( s_pLocalPlayer[ i ] )
  465. {
  466. s_pLocalPlayer[ i ]->RemoveSplitScreenPlayer( this );
  467. }
  468. if ( m_bFlashlightEnabled[ i ] )
  469. {
  470. FlashlightEffectManager( i ).TurnOffFlashlight( true );
  471. m_bFlashlightEnabled[ i ] = false;
  472. }
  473. }
  474. }
  475. bool MsgFunc_SendLastKillerDamageToClient( const CCSUsrMsg_SendLastKillerDamageToClient &msg )
  476. {
  477. int nNumHitsGiven = msg.num_hits_given();
  478. int nDamageGiven = msg.damage_given();
  479. int nNumHitsTaken = msg.num_hits_taken();
  480. int nDamageTaken = msg.damage_taken();
  481. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  482. if ( pPlayer )
  483. {
  484. pPlayer->SetLastKillerDamageAndFreezeframe( nDamageTaken, nNumHitsTaken, nDamageGiven, nNumHitsGiven );
  485. }
  486. return true;
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Purpose:
  490. //-----------------------------------------------------------------------------
  491. void C_BasePlayer::Spawn( void )
  492. {
  493. m_UMCMsg_SendLastKillerDamageToClient.Bind< CS_UM_SendLastKillerDamageToClient, CCSUsrMsg_SendLastKillerDamageToClient >
  494. ( UtlMakeDelegate( MsgFunc_SendLastKillerDamageToClient ));
  495. // Clear all flags except for FL_FULLEDICT
  496. ClearFlags();
  497. AddFlag( FL_CLIENT );
  498. int effects = GetEffects() & EF_NOSHADOW;
  499. SetEffects( effects );
  500. m_iFOV = 0; // init field of view.
  501. SetModel( GetPlayerModelName() );
  502. Precache();
  503. SetThink(NULL);
  504. RANDOM_CEG_TEST_SECRET_LINE_PERIOD( 17, 0, 41, 0 );
  505. SharedSpawn();
  506. m_bWasFreezeFraming = false;
  507. m_bFiredWeapon = false;
  508. }
  509. void C_BasePlayer::UpdateOnRemove( void )
  510. {
  511. if ( m_pPhysicsController )
  512. {
  513. physenv->DestroyPlayerController( m_pPhysicsController );
  514. m_pPhysicsController = NULL;
  515. }
  516. PhysRemoveShadow( this );
  517. VPhysicsSetObject( NULL );
  518. if( m_pShadowStand )
  519. {
  520. physenv->DestroyObject( m_pShadowStand );
  521. m_pShadowStand = NULL;
  522. }
  523. if( m_pShadowCrouch )
  524. {
  525. physenv->DestroyObject( m_pShadowCrouch );
  526. m_pShadowCrouch = NULL;
  527. }
  528. if ( m_speechVOIPParticleEffect.IsValid() )
  529. {
  530. ParticleProp()->StopEmissionAndDestroyImmediately( m_speechVOIPParticleEffect );
  531. m_speechVOIPParticleEffect = NULL;
  532. }
  533. BaseClass::UpdateOnRemove();
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Purpose:
  537. //-----------------------------------------------------------------------------
  538. bool C_BasePlayer::AudioStateIsUnderwater( Vector vecMainViewOrigin )
  539. {
  540. if ( IsObserver() )
  541. {
  542. // Just check the view position
  543. int cont = enginetrace->GetPointContents_WorldOnly( vecMainViewOrigin, MASK_WATER );
  544. return (cont & MASK_WATER) ? true : false;
  545. }
  546. return ( GetWaterLevel() >= WL_Eyes );
  547. }
  548. #if defined( REPLAY_ENABLED )
  549. bool C_BasePlayer::IsReplay() const
  550. {
  551. return ( IsLocalPlayer( const_cast< C_BasePlayer * >( this ) ) && engine->IsReplay() );
  552. }
  553. #endif
  554. bool C_BasePlayer::IsBot( void ) const
  555. {
  556. IGameResources* pGR = GameResources();
  557. return ( pGR && pGR->IsFakePlayer( entindex() ) );
  558. }
  559. CBaseEntity *C_BasePlayer::GetObserverTarget() const // returns players targer or NULL
  560. {
  561. if ( IsHLTV() )
  562. {
  563. return HLTVCamera()->GetPrimaryTarget();
  564. }
  565. #if defined( REPLAY_ENABLED )
  566. if ( IsReplay() )
  567. {
  568. return ReplayCamera()->GetPrimaryTarget();
  569. }
  570. #endif
  571. return m_hObserverTarget;
  572. }
  573. void UpdateWorldmodelVisibility( C_BasePlayer *player )
  574. {
  575. for ( int i = 0; i < player->WeaponCount(); i++ )
  576. {
  577. CBaseCombatWeapon *pWeapon = player->GetWeapon(i);
  578. if ( pWeapon )
  579. {
  580. CBaseWeaponWorldModel *pWeaponWorldModel = pWeapon->GetWeaponWorldModel();
  581. if ( pWeaponWorldModel )
  582. {
  583. pWeaponWorldModel->UpdateVisibility();
  584. }
  585. }
  586. }
  587. }
  588. // Helper method to fix up visiblity across split screen for view models when observer target or mode changes
  589. void UpdateViewmodelVisibility( C_BasePlayer *player )
  590. {
  591. // also update world models
  592. UpdateWorldmodelVisibility( player );
  593. // Update view model visibility
  594. for ( int i = 0; i < MAX_VIEWMODELS; i++ )
  595. {
  596. CBaseViewModel *vm = player->GetViewModel( i );
  597. if ( !vm )
  598. continue;
  599. vm->UpdateVisibility();
  600. }
  601. }
  602. // Called from Recv Proxy, mainly to reset tone map scale
  603. void C_BasePlayer::SetObserverTarget( EHANDLE hObserverTarget )
  604. {
  605. // [msmith] We need to update the view model visibility status of the player we were observing because their view models
  606. // may no longer be rendering in our splitscreen viewport.
  607. C_BasePlayer* pOldObserverTarget = ToBasePlayer( m_hObserverTarget );
  608. C_BasePlayer *pNewObserverTarget = ToBasePlayer( hObserverTarget );
  609. // If the observer target is changing to an entity that the client doesn't know about yet,
  610. // it can resolve to NULL. If the client didn't have an observer target before, then
  611. // comparing EHANDLEs directly will see them as equal, since it uses Get(), and compares
  612. // NULL to NULL. To combat this, we need to check against GetEntryIndex() and
  613. // GetSerialNumber().
  614. if ( hObserverTarget.GetEntryIndex() != m_hObserverTarget.GetEntryIndex() ||
  615. hObserverTarget.GetSerialNumber() != m_hObserverTarget.GetSerialNumber())
  616. {
  617. // Init based on the new handle's entry index and serial number, so that it's Get()
  618. // has a chance to become non-NULL even if it currently resolves to NULL.
  619. m_hObserverTarget.Init( hObserverTarget.GetEntryIndex(), hObserverTarget.GetSerialNumber() );
  620. IGameEvent *event = gameeventmanager->CreateEvent( "spec_target_updated" );
  621. if ( event )
  622. {
  623. event->SetInt("userid", GetUserID() );
  624. gameeventmanager->FireEventClientSide( event );
  625. }
  626. if ( IsLocalPlayer( this ) )
  627. {
  628. ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( this );
  629. ResetToneMapping( -1.0f ); // This forces the tonemapping scalar to the average of min and max
  630. }
  631. UpdateViewmodelVisibility( this );
  632. UpdateVisibility();
  633. if ( pNewObserverTarget )
  634. {
  635. pNewObserverTarget->UpdateVisibility();
  636. UpdateViewmodelVisibility( pNewObserverTarget );
  637. }
  638. }
  639. // [msmith] We need to wait until we've set a new observer target before updating the view model visibility of our
  640. // old observer target.
  641. // NOTE: We need to update this even if the observed target did not change because the observer mode may have changed.
  642. // If the observer mode switched to third person for example, the view model should NOT be drawn.
  643. if ( pOldObserverTarget )
  644. {
  645. pOldObserverTarget->UpdateVisibility();
  646. UpdateViewmodelVisibility( pOldObserverTarget );
  647. }
  648. }
  649. int C_BasePlayer::GetObserverMode() const
  650. {
  651. if ( IsHLTV() )
  652. {
  653. return HLTVCamera()->GetMode();
  654. }
  655. #if defined( REPLAY_ENABLED )
  656. if ( IsReplay() )
  657. {
  658. return ReplayCamera()->GetMode();
  659. }
  660. #endif
  661. return m_iObserverMode;
  662. }
  663. //-----------------------------------------------------------------------------
  664. // Used by prediction, sets the view angles for the player
  665. //-----------------------------------------------------------------------------
  666. void C_BasePlayer::SetLocalViewAngles( const QAngle &viewAngles )
  667. {
  668. pl.v_angle = viewAngles;
  669. }
  670. //-----------------------------------------------------------------------------
  671. // Purpose:
  672. // Input : ang -
  673. //-----------------------------------------------------------------------------
  674. void C_BasePlayer::SetViewAngles( const QAngle& ang )
  675. {
  676. SetLocalAngles( ang );
  677. SetNetworkAngles( ang );
  678. }
  679. surfacedata_t* C_BasePlayer::GetGroundSurface()
  680. {
  681. //
  682. // Find the name of the material that lies beneath the player.
  683. //
  684. Vector start, end;
  685. VectorCopy( GetAbsOrigin(), start );
  686. VectorCopy( start, end );
  687. // Straight down
  688. end.z -= 64;
  689. // Fill in default values, just in case.
  690. Ray_t ray;
  691. ray.Init( start, end, GetPlayerMins(), GetPlayerMaxs() );
  692. trace_t trace;
  693. UTIL_TraceRay( ray, MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  694. if ( trace.fraction == 1.0f )
  695. return NULL; // no ground
  696. return physprops->GetSurfaceData( trace.surface.surfaceProps );
  697. }
  698. //-----------------------------------------------------------------------------
  699. // returns the player name
  700. //-----------------------------------------------------------------------------
  701. const char * C_BasePlayer::GetPlayerName()
  702. {
  703. return g_PR ? g_PR->GetPlayerName( entindex() ) : "";
  704. }
  705. //-----------------------------------------------------------------------------
  706. // Is the player dead?
  707. //-----------------------------------------------------------------------------
  708. bool C_BasePlayer::IsPlayerDead()
  709. {
  710. return pl.deadflag == true;
  711. }
  712. //-----------------------------------------------------------------------------
  713. // Purpose:
  714. //-----------------------------------------------------------------------------
  715. void C_BasePlayer::SetVehicleRole( int nRole )
  716. {
  717. if ( !IsInAVehicle() )
  718. return;
  719. // HL2 has only a player in a vehicle.
  720. if ( nRole > VEHICLE_ROLE_DRIVER )
  721. return;
  722. char szCmd[64];
  723. Q_snprintf( szCmd, sizeof( szCmd ), "vehicleRole %i\n", nRole );
  724. engine->ServerCmd( szCmd );
  725. }
  726. //-----------------------------------------------------------------------------
  727. // Purpose: Store original ammo data to see what has changed
  728. // Input : bnewentity -
  729. //-----------------------------------------------------------------------------
  730. void C_BasePlayer::OnPreDataChanged( DataUpdateType_t updateType )
  731. {
  732. for (int i = 0; i < MAX_AMMO_TYPES; ++i)
  733. {
  734. m_iOldAmmo[i] = GetAmmoCount(i);
  735. }
  736. m_bWasFreezeFraming = (GetObserverMode() == OBS_MODE_FREEZECAM);
  737. m_hOldFogController = m_PlayerFog.m_hCtrl;
  738. m_iOldObserverMode = GetObserverMode();
  739. BaseClass::OnPreDataChanged( updateType );
  740. }
  741. void C_BasePlayer::PreDataUpdate( DataUpdateType_t updateType )
  742. {
  743. BaseClass::PreDataUpdate( updateType );
  744. m_ubOldEFNoInterpParity = m_ubEFNoInterpParity;
  745. }
  746. void C_BasePlayer::CheckForLocalPlayer( int nSplitScreenSlot )
  747. {
  748. // Make sure s_pLocalPlayer is correct
  749. int iLocalPlayerIndex = ( nSplitScreenSlot != -1 ) ? engine->GetLocalPlayer() : 0;
  750. if ( g_nKillCamMode )
  751. iLocalPlayerIndex = g_nKillCamTarget1;
  752. if ( iLocalPlayerIndex == index && !g_HltvReplaySystem.GetHltvReplayDelay() )
  753. {
  754. s_pLocalPlayer[ nSplitScreenSlot ] = this;
  755. m_bIsLocalPlayer = true;
  756. // Tell host player about the parasitic splitscreen user
  757. if ( nSplitScreenSlot != 0 )
  758. {
  759. Assert( s_pLocalPlayer[ 0 ] );
  760. m_nSplitScreenSlot = nSplitScreenSlot;
  761. m_hSplitOwner = s_pLocalPlayer[ 0 ];
  762. if ( s_pLocalPlayer[ 0 ] )
  763. {
  764. s_pLocalPlayer[ 0 ]->AddSplitScreenPlayer( this );
  765. }
  766. }
  767. else
  768. {
  769. // We're the host, not the parasite...
  770. m_nSplitScreenSlot = 0;
  771. m_hSplitOwner = NULL;
  772. }
  773. if ( nSplitScreenSlot == 0 )
  774. {
  775. // Reset our sound mixed in case we were in a freeze cam when we
  776. // changed level, which would cause the snd_soundmixer to be left modified.
  777. ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" );
  778. pVar->Revert();
  779. }
  780. UpdateVisibilityAllEntities();
  781. }
  782. }
  783. void C_BasePlayer::ClientThink()
  784. {
  785. //////////////////////////////////////////////
  786. // spec_lock_to_accountid
  787. //
  788. // Lock observer target to the specified account id
  789. ////////////////////////////////////////////////////////
  790. static float flNextCheck = Plat_FloatTime( ) + 5;
  791. if ( Plat_FloatTime( ) >= flNextCheck &&
  792. spec_lock_to_accountid.GetString( ) &&
  793. spec_lock_to_accountid.GetString( )[0] &&
  794. IsObserver( ) &&
  795. IsLocalPlayer( this ) )
  796. {
  797. bool bSwitchTargets = true;
  798. if ( GetObserverTarget( ) && ( GetObserverMode( ) == OBS_MODE_IN_EYE || GetObserverMode( ) == OBS_MODE_CHASE ) )
  799. {
  800. C_CSPlayer *pPlayer = dynamic_cast< C_CSPlayer* >( GetObserverTarget( ) );
  801. if ( pPlayer )
  802. {
  803. CSteamID SteamID;
  804. pPlayer->GetSteamID( &SteamID );
  805. if ( SteamID.GetAccountID( ) == CSteamID( spec_lock_to_accountid.GetString( ) ).GetAccountID() )
  806. {
  807. bSwitchTargets = false;
  808. }
  809. }
  810. }
  811. if ( bSwitchTargets )
  812. {
  813. DevMsg( "spec_lock_to_accountid: Attempting to switch spec target to %s. Clear out the convar spec_lock_to_accountid to stop.\n", spec_lock_to_accountid.GetString( ) );
  814. if ( g_bEngineIsHLTV )
  815. {
  816. // we can only switch primary spectator targets if PVS isnt locked by auto-director
  817. if ( !HLTVCamera( )->IsPVSLocked( ) )
  818. {
  819. HLTVCamera( )->SpecPlayerByAccountID( spec_lock_to_accountid.GetString( ) );
  820. HLTVCamera( )->SetMode( OBS_MODE_IN_EYE );
  821. //HLTVCamera()->SetAutoDirector( C_HLTVCamera::AUTODIRECTOR_PAUSED );
  822. HLTVCamera( )->SetAutoDirector( C_HLTVCamera::AUTODIRECTOR_OFF );
  823. }
  824. }
  825. else
  826. {
  827. char szCmd[ 64 ];
  828. Q_snprintf( szCmd, sizeof( szCmd ), "spec_player_by_accountid %s\n", spec_lock_to_accountid.GetString() );
  829. engine->ServerCmd( szCmd );
  830. Q_snprintf( szCmd, sizeof( szCmd ), "spec_mode %i\n", OBS_MODE_IN_EYE );
  831. engine->ServerCmd( szCmd );
  832. }
  833. }
  834. flNextCheck = Plat_FloatTime( ) + 5;
  835. }
  836. }
  837. void C_BasePlayer::SetAsLocalPlayer()
  838. {
  839. int nSplitScreenSlot = 0;
  840. Assert( s_pLocalPlayer[ nSplitScreenSlot ] == NULL );
  841. s_pLocalPlayer[ nSplitScreenSlot ] = this;
  842. m_bIsLocalPlayer = true;
  843. // We're the host
  844. m_nSplitScreenSlot = 0;
  845. m_hSplitOwner = NULL;
  846. if ( nSplitScreenSlot == 0 && !g_HltvReplaySystem.GetHltvReplayDelay() )
  847. {
  848. // Reset our sound mixed in case we were in a freeze cam when we
  849. // changed level, which would cause the snd_soundmixer to be left modified.
  850. ConVar *pVar = ( ConVar * )cvar->FindVar( "snd_soundmixer" );
  851. pVar->Revert();
  852. }
  853. UpdateVisibilityAllEntities();
  854. }
  855. //-----------------------------------------------------------------------------
  856. // Purpose:
  857. // Input : updateType -
  858. //-----------------------------------------------------------------------------
  859. void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType )
  860. {
  861. // This has to occur here as opposed to OnDataChanged so that EHandles to the player created
  862. // on this same frame are not stomped because prediction thinks there
  863. // isn't a local player yet!!!
  864. int nSlot = -1;
  865. FOR_EACH_VALID_SPLITSCREEN_PLAYER( i )
  866. {
  867. int nIndex = engine->GetSplitScreenPlayer( i );
  868. if ( nIndex == index )
  869. {
  870. nSlot = i;
  871. break;
  872. }
  873. }
  874. ACTIVE_SPLITSCREEN_PLAYER_GUARD( nSlot );
  875. bool bRecheck = false;
  876. if ( nSlot != -1 && !s_pLocalPlayer[ nSlot ] )
  877. {
  878. bRecheck = true;
  879. }
  880. if ( updateType == DATA_UPDATE_CREATED || bRecheck )
  881. {
  882. CheckForLocalPlayer( nSlot );
  883. }
  884. bool bForceEFNoInterp = ( m_ubOldEFNoInterpParity != m_ubEFNoInterpParity );
  885. if ( IsLocalPlayer( this ) )
  886. {
  887. if ( (updateType == DATA_UPDATE_CREATED) &&
  888. g_pGameRules->IsMultiplayer() &&
  889. cl_player_fullupdate_predicted_origin_fix.GetBool() )
  890. {
  891. if ( (m_vecHack_RecvProxy_LocalPlayerOrigin.x != FLT_MAX) &&
  892. (m_vecHack_RecvProxy_LocalPlayerOrigin.y != FLT_MAX) &&
  893. (m_vecHack_RecvProxy_LocalPlayerOrigin.z != FLT_MAX) )
  894. {
  895. SetNetworkOrigin( m_vecHack_RecvProxy_LocalPlayerOrigin );
  896. }
  897. }
  898. m_vecHack_RecvProxy_LocalPlayerOrigin.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  899. SetSimulatedEveryTick( true );
  900. }
  901. else
  902. {
  903. SetSimulatedEveryTick( false );
  904. // estimate velocity for non local players
  905. float flTimeDelta = m_flSimulationTime - m_flOldSimulationTime;
  906. if (IsParentChanging())
  907. {
  908. bForceEFNoInterp = true;
  909. }
  910. if ( flTimeDelta > 0 && !( IsEffectActive(EF_NOINTERP) || bForceEFNoInterp ) )
  911. {
  912. Vector newVelo = (GetNetworkOrigin() - GetOldOrigin() ) / flTimeDelta;
  913. // This code used to call SetAbsVelocity, which is a no-no since we are in networking and if
  914. // in hieararchy, the parent velocity might not be set up yet.
  915. // On top of that GetNetworkOrigin and GetOldOrigin are local coordinates
  916. // So we'll just set the local vel and avoid an Assert here
  917. SetLocalVelocity( newVelo );
  918. }
  919. }
  920. BaseClass::PostDataUpdate( updateType );
  921. // Only care about this for local player
  922. if ( IsLocalPlayer( this ) )
  923. {
  924. bool bHideFreezePanel = false;
  925. QAngle angles;
  926. engine->GetViewAngles( angles );
  927. if ( updateType == DATA_UPDATE_CREATED )
  928. {
  929. SetLocalViewAngles( angles );
  930. m_flOldPlayerZ = GetLocalOrigin().z;
  931. }
  932. SetLocalAngles( angles );
  933. if ( m_bCanShowFreezeFrameNow && !m_bWasFreezeFraming && GetObserverMode() == OBS_MODE_FREEZECAM )
  934. {
  935. m_vecFreezeFrameStart = MainViewOrigin( GetSplitScreenPlayerSlot() );
  936. m_flFreezeFrameStartTime = gpGlobals->curtime;
  937. m_flFreezeFrameDistance = RandomFloat( spec_freeze_distance_min.GetFloat(), spec_freeze_distance_max.GetFloat() );
  938. m_flFreezeZOffset = RandomFloat( -4, 4 );
  939. m_bSentFreezeFrame = false;
  940. m_bStartedFreezeFrame = false;
  941. m_bAbortedFreezeFrame = false;
  942. IGameEvent *pEvent = gameeventmanager->CreateEvent( "show_freezepanel" );
  943. if ( pEvent )
  944. {
  945. pEvent->SetInt( "killer", GetObserverTarget() ? GetObserverTarget()->entindex() : GetLastKillerIndex() );
  946. pEvent->SetInt( "victim", entindex() );
  947. pEvent->SetInt( "hits_taken", m_nLastKillerHitsTaken );
  948. pEvent->SetInt( "damage_taken", m_nLastKillerDamageTaken );
  949. pEvent->SetInt( "hits_given", m_nLastKillerHitsGiven );
  950. pEvent->SetInt( "damage_given", m_nLastKillerDamageGiven );
  951. gameeventmanager->FireEventClientSide( pEvent );
  952. }
  953. // Force the sound mixer to the freezecam mixer
  954. ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" );
  955. pVar->SetValue( "FreezeCam_Only" );
  956. m_bCanShowFreezeFrameNow = false;
  957. }
  958. else if ( m_bWasFreezeFraming && GetObserverMode() != OBS_MODE_FREEZECAM )
  959. {
  960. if ( spec_freeze_panel_extended_time.GetFloat() > 0 )
  961. {
  962. m_flFreezePanelExtendedStartTime = gpGlobals->curtime;
  963. m_bWasFreezePanelExtended = true;
  964. }
  965. else
  966. {
  967. bHideFreezePanel = true;
  968. }
  969. view->FreezeFrame(0);
  970. ConVar *pVar = ( ConVar * )cvar->FindVar( "snd_soundmixer" );
  971. pVar->Revert();
  972. }
  973. else if ( m_bWasFreezePanelExtended && gpGlobals->curtime >= m_flFreezePanelExtendedStartTime + spec_freeze_panel_extended_time.GetFloat() )
  974. {
  975. bHideFreezePanel = true;
  976. m_bWasFreezePanelExtended = false;
  977. }
  978. else if ( IsAlive() )
  979. {
  980. SFHudFreezePanel *pPanel = GET_HUDELEMENT( SFHudFreezePanel );
  981. if ( pPanel && pPanel->IsVisible() )
  982. {
  983. //pPanel->ShowPanel( false );
  984. bHideFreezePanel = true;
  985. }
  986. }
  987. if ( bHideFreezePanel && !g_HltvReplaySystem.GetHltvReplayDelay() && !g_HltvReplaySystem.IsDelayedReplayRequestPending() )
  988. {
  989. IGameEvent *pEvent = gameeventmanager->CreateEvent( "hide_freezepanel" );
  990. if ( pEvent )
  991. {
  992. gameeventmanager->FireEventClientSide( pEvent );
  993. }
  994. }
  995. }
  996. // If we are updated while paused, allow the player origin to be snapped by the
  997. // server if we receive a packet from the server
  998. if ( engine->IsPaused() || bForceEFNoInterp )
  999. {
  1000. ResetLatched();
  1001. }
  1002. #ifdef DEMOPOLISH_ENABLED
  1003. if ( engine->IsRecordingDemo() &&
  1004. IsDemoPolishRecording() )
  1005. {
  1006. m_bBonePolishSetup = true;
  1007. matrix3x4a_t dummyBones[MAXSTUDIOBONES];
  1008. C_BaseEntity::SetAbsQueriesValid( true );
  1009. ForceSetupBonesAtTime( dummyBones, gpGlobals->curtime );
  1010. C_BaseEntity::SetAbsQueriesValid( false );
  1011. m_bBonePolishSetup = false;
  1012. }
  1013. #endif
  1014. m_fLastUpdateServerTime = engine->GetLastTimeStamp();
  1015. m_nLastUpdateTickBase = m_nTickBase;
  1016. m_nLastUpdateServerTickCount = engine->GetServerTick();
  1017. if ( IsActiveCameraMan() != m_bLastActiveCameraManState )
  1018. {
  1019. m_bLastActiveCameraManState = IsActiveCameraMan();
  1020. if ( IsActiveCameraMan() && HLTVCamera()->AutoDirectorState() != C_HLTVCamera::AUTODIRECTOR_OFF )
  1021. {
  1022. // if a cameraman becomes active and the autodirector is on, just set it on again and it'll switch to the cameraman if enabled
  1023. HLTVCamera()->SetAutoDirector( C_HLTVCamera::AUTODIRECTOR_ON );
  1024. }
  1025. }
  1026. // force voice recording on for casters
  1027. if ( ( GetLocalPlayer() == this ) && HLTVCamera() && ( HLTVCamera()->GetCameraMan() == this ) && !engine->IsVoiceRecording() )
  1028. {
  1029. engine->ForceVoiceRecordOn();
  1030. }
  1031. int eventType = -1;
  1032. int nOptionalParam = 0;
  1033. ConVarRef spec_show_xray( "spec_show_xray" );
  1034. CSteamID steamID;
  1035. // if the state changed for any of the cameraman stuff, send to the local player
  1036. if ( IsActiveCameraMan() && GetSteamID( &steamID ) )
  1037. {
  1038. if ( spec_show_xray.GetBool() != m_bLastCameraManXRayState || m_bCameraManXRay != m_bLastCameraManXRayState )
  1039. {
  1040. m_bLastCameraManXRayState = m_bCameraManXRay;
  1041. eventType = ( m_bCameraManXRay ) ? HLTV_UI_XRAY_ON : HLTV_UI_XRAY_OFF;
  1042. if ( eventType != -1 )
  1043. GetClientMode()->UpdateCameraManUIState( eventType, nOptionalParam, steamID.ConvertToUint64() );
  1044. }
  1045. if ( m_bCameraManOverview != m_bLastCameraManOverviewState )
  1046. {
  1047. m_bLastCameraManOverviewState = m_bCameraManOverview;
  1048. eventType = ( m_bCameraManOverview ) ? HLTV_UI_OVERVIEW_ON : HLTV_UI_OVERVIEW_OFF;
  1049. if ( eventType != -1 )
  1050. GetClientMode()->UpdateCameraManUIState( eventType, nOptionalParam, steamID.ConvertToUint64() );
  1051. }
  1052. if ( m_bCameraManScoreBoard != m_bLastCameraManScoreBoardState )
  1053. {
  1054. m_bLastCameraManScoreBoardState = m_bCameraManScoreBoard;
  1055. eventType = ( m_bCameraManScoreBoard ) ? HLTV_UI_SCOREBOARD_ON : HLTV_UI_SCOREBOARD_OFF;
  1056. if ( eventType != -1 )
  1057. GetClientMode()->UpdateCameraManUIState( eventType, nOptionalParam, steamID.ConvertToUint64() );
  1058. }
  1059. if ( m_uCameraManGraphs != m_uLastCameraManGraphsState )
  1060. {
  1061. m_uLastCameraManGraphsState = m_uCameraManGraphs;
  1062. eventType = ( m_uCameraManGraphs != 0 ) ? HLTV_UI_GRAPHS_ON : HLTV_UI_GRAPHS_OFF;
  1063. if ( eventType == HLTV_UI_GRAPHS_ON )
  1064. {
  1065. nOptionalParam = m_uCameraManGraphs - 1;
  1066. }
  1067. if ( eventType != -1 )
  1068. GetClientMode()->UpdateCameraManUIState( eventType, nOptionalParam, steamID.ConvertToUint64() );
  1069. }
  1070. }
  1071. }
  1072. //-----------------------------------------------------------------------------
  1073. // Purpose:
  1074. //-----------------------------------------------------------------------------
  1075. bool C_BasePlayer::CanSetSoundMixer( void )
  1076. {
  1077. // Can't set sound mixers when we're in freezecam mode, since it has a code-enforced mixer
  1078. return (GetObserverMode() != OBS_MODE_FREEZECAM);
  1079. }
  1080. void C_BasePlayer::ReceiveMessage( int classID, bf_read &msg )
  1081. {
  1082. if ( classID != GetClientClass()->m_ClassID )
  1083. {
  1084. // message is for subclass
  1085. BaseClass::ReceiveMessage( classID, msg );
  1086. return;
  1087. }
  1088. }
  1089. void C_BasePlayer::OnRestore()
  1090. {
  1091. BaseClass::OnRestore();
  1092. if ( IsLocalPlayer( this ) )
  1093. {
  1094. ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( this );
  1095. // debounce the attack key, for if it was used for restore
  1096. input->ClearInputButton( IN_ATTACK | IN_ATTACK2 | IN_ZOOM );
  1097. // GetButtonBits() has to be called for the above to take effect
  1098. input->GetButtonBits( false );
  1099. }
  1100. // For ammo history icons to current value so they don't flash on level transtions
  1101. int ammoTypes = GetAmmoDef()->NumAmmoTypes();
  1102. // ammodef is 1 based, use <=
  1103. for ( int i = 0; i <= ammoTypes; i++ )
  1104. {
  1105. m_iOldAmmo[i] = GetAmmoCount(i);
  1106. }
  1107. }
  1108. //-----------------------------------------------------------------------------
  1109. // Purpose: Process incoming data
  1110. //-----------------------------------------------------------------------------
  1111. void C_BasePlayer::OnDataChanged( DataUpdateType_t updateType )
  1112. {
  1113. bool isLocalPlayer = IsLocalPlayer( this );
  1114. #if !defined( NO_ENTITY_PREDICTION )
  1115. if ( isLocalPlayer )
  1116. {
  1117. SetPredictionEligible( true );
  1118. }
  1119. #endif
  1120. BaseClass::OnDataChanged( updateType );
  1121. bool bIsLocalOrHltvObserverPlayer = g_HltvReplaySystem.GetHltvReplayDelay() ? HLTVCamera()->GetCurrentTargetEntindex() == this->index : isLocalPlayer;
  1122. // Only care about this for local player
  1123. if ( bIsLocalOrHltvObserverPlayer )
  1124. {
  1125. int nSlot = GetSplitScreenPlayerSlot();
  1126. // Reset engine areabits pointer, but only for main local player (not piggybacked split screen users)
  1127. if ( nSlot == 0 )
  1128. {
  1129. render->SetAreaState( m_Local.m_chAreaBits, m_Local.m_chAreaPortalBits );
  1130. }
  1131. #if !defined( INCLUDE_SCALEFORM ) || !defined( CSTRIKE_DLL )
  1132. // Check for Ammo pickups.
  1133. int ammoTypes = GetAmmoDef()->NumAmmoTypes();
  1134. for ( int i = 0; i <= ammoTypes; i++ )
  1135. {
  1136. if ( GetAmmoCount(i) > m_iOldAmmo[i] )
  1137. {
  1138. // Only add this to the correct Hud
  1139. ACTIVE_SPLITSCREEN_PLAYER_GUARD( nSlot );
  1140. // Don't add to ammo pickup if the ammo doesn't do it
  1141. const FileWeaponInfo_t *pWeaponData = gWR.GetWeaponFromAmmo(i);
  1142. if ( !pWeaponData || !( pWeaponData->iFlags & ITEM_FLAG_NOAMMOPICKUPS ) )
  1143. {
  1144. // We got more ammo for this ammo index. Add it to the ammo history
  1145. CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
  1146. if( pHudHR )
  1147. {
  1148. pHudHR->AddToHistory( HISTSLOT_AMMO, i, abs(GetAmmoCount(i) - m_iOldAmmo[i]) );
  1149. }
  1150. }
  1151. }
  1152. }
  1153. #endif
  1154. // Only add this to the correct Hud
  1155. {
  1156. ACTIVE_SPLITSCREEN_PLAYER_GUARD( nSlot );
  1157. Soundscape_Update( m_Local.m_audio );
  1158. }
  1159. }
  1160. if ( isLocalPlayer ) // fog controller is always using local player to update fog; this seems wrong for spectating, because the observer target entity may have different fog parameters, but in practice this has never been a problem. Eventually we may need to address that by changing GetLocalPlayer in viewrender.cpp
  1161. {
  1162. if ( m_hOldFogController != m_PlayerFog.m_hCtrl )
  1163. {
  1164. FogControllerChanged( updateType == DATA_UPDATE_CREATED );
  1165. }
  1166. }
  1167. if( (updateType == DATA_UPDATE_CREATED) && physenv->IsPredicted() )
  1168. {
  1169. if( engine->GetLocalPlayer() == index ) //C_BasePlayer::IsLocalPlayer() doesn't work this early when created. This works just as well
  1170. {
  1171. //create physics objects
  1172. Vector vecAbsOrigin = GetAbsOrigin();
  1173. Vector vecAbsVelocity = GetAbsVelocity();
  1174. solid_t solid;
  1175. Q_strncpy( solid.surfaceprop, "player", sizeof(solid.surfaceprop) );
  1176. solid.params = g_PhysDefaultObjectParams;
  1177. solid.params.mass = 85.0f;
  1178. solid.params.inertia = 1e24f;
  1179. solid.params.enableCollisions = false;
  1180. //disable drag
  1181. solid.params.dragCoefficient = 0;
  1182. // create standing hull
  1183. m_pShadowStand = PhysModelCreateCustom( this, PhysCreateBbox( VEC_HULL_MIN, VEC_HULL_MAX ), GetLocalOrigin(), GetLocalAngles(), "player_stand", false, &solid );
  1184. m_pShadowStand->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION );
  1185. // create crouchig hull
  1186. m_pShadowCrouch = PhysModelCreateCustom( this, PhysCreateBbox( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX ), GetLocalOrigin(), GetLocalAngles(), "player_crouch", false, &solid );
  1187. m_pShadowCrouch->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION );
  1188. // default to stand
  1189. VPhysicsSetObject( m_pShadowStand );
  1190. // tell physics lists I'm a shadow controller object
  1191. PhysAddShadow( this );
  1192. m_pPhysicsController = physenv->CreatePlayerController( m_pShadowStand );
  1193. m_pPhysicsController->SetPushMassLimit( 350.0f );
  1194. m_pPhysicsController->SetPushSpeedLimit( 50.0f );
  1195. // Give the controller a valid position so it doesn't do anything rash.
  1196. UpdatePhysicsShadowToPosition( vecAbsOrigin );
  1197. // init state
  1198. if ( GetFlags() & FL_DUCKING )
  1199. {
  1200. SetVCollisionState( vecAbsOrigin, vecAbsVelocity, VPHYS_CROUCH );
  1201. }
  1202. else
  1203. {
  1204. SetVCollisionState( vecAbsOrigin, vecAbsVelocity, VPHYS_WALK );
  1205. }
  1206. }
  1207. }
  1208. if( IsLocalPlayer() )
  1209. {
  1210. IPhysicsObject *pObject = VPhysicsGetObject();
  1211. if ((pObject != NULL) &&
  1212. (
  1213. ((m_vphysicsCollisionState == VPHYS_CROUCH) && (pObject == m_pShadowStand)) ||
  1214. ((m_vphysicsCollisionState == VPHYS_WALK) && (pObject == m_pShadowCrouch))
  1215. ) )
  1216. {
  1217. //apply networked changes to collision state
  1218. SetVCollisionState( GetAbsOrigin(), GetAbsVelocity(), m_vphysicsCollisionState );
  1219. }
  1220. // [msmith] We want to disable prediction while spectating in first person because the server forcibly sets certain predicted fields on players while
  1221. // they are spectating other players (viewOffset for example). Keeping prediction enabled modifies these values and causes severe jitter.
  1222. // This is most noticable while playing on a dedicated server and the specated player ducks (causing changes to viewOffset).
  1223. int observationMode = GetObserverMode();
  1224. bool isSpectating = GetObserverTarget() != NULL && ( observationMode == OBS_MODE_IN_EYE || observationMode == OBS_MODE_CHASE );
  1225. extern bool g_bSpectatingForceCLPredictOff;
  1226. g_bSpectatingForceCLPredictOff = isSpectating;
  1227. }
  1228. }
  1229. //-----------------------------------------------------------------------------
  1230. // Did we just enter a vehicle this frame?
  1231. //-----------------------------------------------------------------------------
  1232. bool C_BasePlayer::JustEnteredVehicle()
  1233. {
  1234. if ( !IsInAVehicle() )
  1235. return false;
  1236. return ( m_hOldVehicle == m_hVehicle );
  1237. }
  1238. //-----------------------------------------------------------------------------
  1239. // Are we in VGUI input mode?.
  1240. //-----------------------------------------------------------------------------
  1241. bool C_BasePlayer::IsInVGuiInputMode() const
  1242. {
  1243. return (m_pCurrentVguiScreen.Get() != NULL);
  1244. }
  1245. //-----------------------------------------------------------------------------
  1246. // Are we inputing to a view model vgui screen
  1247. //-----------------------------------------------------------------------------
  1248. bool C_BasePlayer::IsInViewModelVGuiInputMode() const
  1249. {
  1250. C_BaseEntity *pScreenEnt = m_pCurrentVguiScreen.Get();
  1251. if ( !pScreenEnt )
  1252. return false;
  1253. Assert( dynamic_cast<C_VGuiScreen*>(pScreenEnt) );
  1254. C_VGuiScreen *pVguiScreen = static_cast<C_VGuiScreen*>(pScreenEnt);
  1255. return ( pVguiScreen->IsAttachedToViewModel() && pVguiScreen->AcceptsInput() );
  1256. }
  1257. //-----------------------------------------------------------------------------
  1258. // Check to see if we're in vgui input mode...
  1259. //-----------------------------------------------------------------------------
  1260. void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd )
  1261. {
  1262. // If we're dead, close down and abort!
  1263. if ( !IsAlive() )
  1264. {
  1265. DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
  1266. m_pCurrentVguiScreen.Set( NULL );
  1267. return;
  1268. }
  1269. // If we're in vgui mode *and* we're holding down mouse buttons,
  1270. // stay in vgui mode even if we're outside the screen bounds
  1271. if ( m_pCurrentVguiScreen.Get() && ( pCmd->buttons & ( IN_ATTACK | IN_ATTACK2 | IN_ZOOM ) ) )
  1272. {
  1273. SetVGuiScreenButtonState( m_pCurrentVguiScreen.Get(), pCmd->buttons );
  1274. // Kill all attack inputs if we're in vgui screen mode
  1275. pCmd->buttons &= ~( IN_ATTACK | IN_ATTACK2 | IN_ZOOM );
  1276. return;
  1277. }
  1278. // We're not in vgui input mode if we're moving, or have hit a key
  1279. // that will make us move...
  1280. // Not in vgui mode if we're moving too quickly
  1281. // ROBIN: Disabled movement preventing VGUI screen usage
  1282. //if (GetVelocity().LengthSqr() > MAX_VGUI_INPUT_MODE_SPEED_SQ)
  1283. if ( 0 )
  1284. {
  1285. DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
  1286. m_pCurrentVguiScreen.Set( NULL );
  1287. return;
  1288. }
  1289. // Don't enter vgui mode if we've got combat buttons held down
  1290. bool bAttacking = false;
  1291. if ( (( pCmd->buttons & IN_ATTACK ) || ( pCmd->buttons & IN_ATTACK2 ) || ( pCmd->buttons & IN_ZOOM ) ) && !m_pCurrentVguiScreen.Get() )
  1292. {
  1293. bAttacking = true;
  1294. }
  1295. // Not in vgui mode if we're pushing any movement key at all
  1296. // Not in vgui mode if we're in a vehicle...
  1297. // ROBIN: Disabled movement preventing VGUI screen usage
  1298. //if ((pCmd->forwardmove > MAX_VGUI_INPUT_MODE_SPEED) ||
  1299. // (pCmd->sidemove > MAX_VGUI_INPUT_MODE_SPEED) ||
  1300. // (pCmd->upmove > MAX_VGUI_INPUT_MODE_SPEED) ||
  1301. // (pCmd->buttons & IN_JUMP) ||
  1302. // (bAttacking) )
  1303. if ( bAttacking || IsInAVehicle() )
  1304. {
  1305. DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
  1306. m_pCurrentVguiScreen.Set( NULL );
  1307. return;
  1308. }
  1309. // Don't interact with world screens when we're in a menu
  1310. if ( vgui::surface()->IsCursorVisible() )
  1311. {
  1312. DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
  1313. m_pCurrentVguiScreen.Set( NULL );
  1314. return;
  1315. }
  1316. // Not in vgui mode if there are no nearby screens
  1317. C_BaseEntity *pOldScreen = m_pCurrentVguiScreen.Get();
  1318. m_pCurrentVguiScreen = FindNearbyVguiScreen( EyePosition(), pCmd->viewangles, GetTeamNumber() );
  1319. if (pOldScreen != m_pCurrentVguiScreen)
  1320. {
  1321. DeactivateVguiScreen( pOldScreen );
  1322. ActivateVguiScreen( m_pCurrentVguiScreen.Get() );
  1323. }
  1324. if (m_pCurrentVguiScreen.Get())
  1325. {
  1326. SetVGuiScreenButtonState( m_pCurrentVguiScreen.Get(), pCmd->buttons );
  1327. // Kill all attack inputs if we're in vgui screen mode
  1328. pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2 | IN_ZOOM);
  1329. }
  1330. }
  1331. //-----------------------------------------------------------------------------
  1332. // Purpose: Input handling
  1333. //-----------------------------------------------------------------------------
  1334. bool C_BasePlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd )
  1335. {
  1336. // Allow the vehicle to clamp the view angles
  1337. if ( IsInAVehicle() )
  1338. {
  1339. IClientVehicle *pVehicle = m_hVehicle.Get()->GetClientVehicle();
  1340. if ( pVehicle )
  1341. {
  1342. pVehicle->UpdateViewAngles( this, pCmd );
  1343. engine->SetViewAngles( pCmd->viewangles );
  1344. }
  1345. }
  1346. else
  1347. {
  1348. #ifndef _GAMECONSOLE
  1349. if ( joy_autosprint.GetBool() )
  1350. #endif
  1351. {
  1352. if ( input->KeyState( &in_joyspeed ) != 0.0f )
  1353. {
  1354. pCmd->buttons |= IN_SPEED;
  1355. }
  1356. }
  1357. CBaseCombatWeapon *pWeapon = GetActiveWeapon();
  1358. if ( pWeapon )
  1359. {
  1360. pWeapon->CreateMove( flInputSampleTime, pCmd, m_vecOldViewAngles );
  1361. }
  1362. }
  1363. // If the frozen flag is set, prevent view movement (server prevents the rest of the movement)
  1364. if ( GetFlags() & FL_FROZEN )
  1365. {
  1366. // Don't stomp the first time we get frozen
  1367. if ( m_bWasFrozen )
  1368. {
  1369. // Stomp the new viewangles with old ones
  1370. pCmd->viewangles = m_vecOldViewAngles;
  1371. engine->SetViewAngles( pCmd->viewangles );
  1372. }
  1373. else
  1374. {
  1375. m_bWasFrozen = true;
  1376. }
  1377. }
  1378. else
  1379. {
  1380. m_bWasFrozen = false;
  1381. }
  1382. m_vecOldViewAngles = pCmd->viewangles;
  1383. // Check to see if we're in vgui input mode...
  1384. DetermineVguiInputMode( pCmd );
  1385. return true;
  1386. }
  1387. //-----------------------------------------------------------------------------
  1388. // Purpose: Player has changed to a new team
  1389. //-----------------------------------------------------------------------------
  1390. void C_BasePlayer::TeamChange( int iNewTeam )
  1391. {
  1392. // Base class does nothing
  1393. }
  1394. //-----------------------------------------------------------------------------
  1395. // Purpose: Creates, destroys, and updates the flashlight effect as needed.
  1396. //-----------------------------------------------------------------------------
  1397. void C_BasePlayer::UpdateFlashlight()
  1398. {
  1399. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  1400. int iSsPlayer = GET_ACTIVE_SPLITSCREEN_SLOT();
  1401. // TERROR: if we're in-eye spectating, use that player's flashlight
  1402. C_BasePlayer *pFlashlightPlayer = this;
  1403. if ( !IsAlive() )
  1404. {
  1405. if ( GetObserverMode() == OBS_MODE_IN_EYE )
  1406. {
  1407. pFlashlightPlayer = ToBasePlayer( GetObserverTarget() );
  1408. }
  1409. }
  1410. if ( pFlashlightPlayer )
  1411. {
  1412. FlashlightEffectManager().SetEntityIndex( pFlashlightPlayer->index );
  1413. }
  1414. // The dim light is the flashlight.
  1415. if ( pFlashlightPlayer && pFlashlightPlayer->IsAlive() && pFlashlightPlayer->IsEffectActive( EF_DIMLIGHT ) && !pFlashlightPlayer->GetViewEntity() )
  1416. {
  1417. // Make sure we're using the proper flashlight texture
  1418. const char *pszTextureName = pFlashlightPlayer->GetFlashlightTextureName();
  1419. if ( !m_bFlashlightEnabled[ iSsPlayer ] )
  1420. {
  1421. // Turned on the headlight; create it.
  1422. if ( pszTextureName )
  1423. {
  1424. FlashlightEffectManager().TurnOnFlashlight( pFlashlightPlayer->index, pszTextureName, pFlashlightPlayer->GetFlashlightFOV(),
  1425. pFlashlightPlayer->GetFlashlightFarZ(), pFlashlightPlayer->GetFlashlightLinearAtten() );
  1426. }
  1427. else
  1428. {
  1429. FlashlightEffectManager().TurnOnFlashlight( pFlashlightPlayer->index );
  1430. }
  1431. m_bFlashlightEnabled[ iSsPlayer ] = true;
  1432. }
  1433. }
  1434. else if ( m_bFlashlightEnabled[ iSsPlayer ] )
  1435. {
  1436. // Turned off the flashlight; delete it.
  1437. FlashlightEffectManager().TurnOffFlashlight();
  1438. m_bFlashlightEnabled[ iSsPlayer ] = false;
  1439. }
  1440. if ( pFlashlightPlayer && m_bFlashlightEnabled[ iSsPlayer ] )
  1441. {
  1442. Vector vecForward, vecRight, vecUp;
  1443. Vector vecPos;
  1444. //Check to see if we have an externally specified flashlight origin, if not, use eye vectors/render origin
  1445. if ( pFlashlightPlayer->m_vecFlashlightOrigin != vec3_origin && pFlashlightPlayer->m_vecFlashlightOrigin.IsValid() )
  1446. {
  1447. vecPos = pFlashlightPlayer->m_vecFlashlightOrigin;
  1448. vecForward = pFlashlightPlayer->m_vecFlashlightForward;
  1449. vecRight = pFlashlightPlayer->m_vecFlashlightRight;
  1450. vecUp = pFlashlightPlayer->m_vecFlashlightUp;
  1451. }
  1452. else
  1453. {
  1454. EyeVectors( &vecForward, &vecRight, &vecUp );
  1455. vecPos = GetRenderOrigin() + m_vecViewOffset;
  1456. }
  1457. // Update the light with the new position and direction.
  1458. FlashlightEffectManager().UpdateFlashlight( vecPos, vecForward, vecRight, vecUp, pFlashlightPlayer->GetFlashlightFOV(),
  1459. pFlashlightPlayer->CastsFlashlightShadows(), pFlashlightPlayer->GetFlashlightFarZ(), pFlashlightPlayer->GetFlashlightLinearAtten(),
  1460. pFlashlightPlayer->GetFlashlightTextureName() );
  1461. }
  1462. }
  1463. //-----------------------------------------------------------------------------
  1464. // Purpose: Creates player flashlight if it's active
  1465. //-----------------------------------------------------------------------------
  1466. void C_BasePlayer::Flashlight( void )
  1467. {
  1468. UpdateFlashlight();
  1469. }
  1470. //-----------------------------------------------------------------------------
  1471. // Purpose: Turns off flashlight if it's active (TERROR)
  1472. //-----------------------------------------------------------------------------
  1473. void C_BasePlayer::TurnOffFlashlight( void )
  1474. {
  1475. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  1476. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1477. if ( m_bFlashlightEnabled[ nSlot ] )
  1478. {
  1479. FlashlightEffectManager().TurnOffFlashlight();
  1480. m_bFlashlightEnabled[ nSlot ] = false;
  1481. }
  1482. }
  1483. //-----------------------------------------------------------------------------
  1484. // Purpose:
  1485. //-----------------------------------------------------------------------------
  1486. void C_BasePlayer::CreateWaterEffects( void )
  1487. {
  1488. // Must be completely submerged to bother
  1489. if ( GetWaterLevel() < WL_Eyes )
  1490. {
  1491. m_bResampleWaterSurface = true;
  1492. return;
  1493. }
  1494. // Do special setup if this is our first time back underwater
  1495. if ( m_bResampleWaterSurface )
  1496. {
  1497. // Reset our particle timer
  1498. m_tWaterParticleTimer.Init( 32 );
  1499. // Find the surface of the water to clip against
  1500. m_flWaterSurfaceZ = UTIL_WaterLevel( WorldSpaceCenter(), WorldSpaceCenter().z, WorldSpaceCenter().z + 256 );
  1501. m_bResampleWaterSurface = false;
  1502. }
  1503. // Make sure the emitter is setup
  1504. if ( m_pWaterEmitter == NULL )
  1505. {
  1506. if ( ( m_pWaterEmitter = WaterDebrisEffect::Create( "splish" ) ) == NULL )
  1507. return;
  1508. }
  1509. Vector vecVelocity;
  1510. GetVectors( &vecVelocity, NULL, NULL );
  1511. Vector offset = WorldSpaceCenter();
  1512. m_pWaterEmitter->SetSortOrigin( offset );
  1513. SimpleParticle *pParticle;
  1514. float curTime = gpGlobals->frametime;
  1515. // Add as many particles as we need
  1516. while ( m_tWaterParticleTimer.NextEvent( curTime ) )
  1517. {
  1518. offset = WorldSpaceCenter() + ( vecVelocity * 128.0f ) + RandomVector( -128, 128 );
  1519. // Make sure we don't start out of the water!
  1520. if ( offset.z > m_flWaterSurfaceZ )
  1521. {
  1522. offset.z = ( m_flWaterSurfaceZ - 8.0f );
  1523. }
  1524. pParticle = (SimpleParticle *) m_pWaterEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_Fleck_Cement[random->RandomInt(0,1)], offset );
  1525. if (pParticle == NULL)
  1526. continue;
  1527. pParticle->m_flLifetime = 0.0f;
  1528. pParticle->m_flDieTime = random->RandomFloat( 2.0f, 4.0f );
  1529. pParticle->m_vecVelocity = RandomVector( -2.0f, 2.0f );
  1530. //FIXME: We should tint these based on the water's fog value!
  1531. float color = random->RandomInt( 32, 128 );
  1532. pParticle->m_uchColor[0] = color;
  1533. pParticle->m_uchColor[1] = color;
  1534. pParticle->m_uchColor[2] = color;
  1535. pParticle->m_uchStartSize = 1;
  1536. pParticle->m_uchEndSize = 1;
  1537. pParticle->m_uchStartAlpha = 255;
  1538. pParticle->m_uchEndAlpha = 0;
  1539. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  1540. pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
  1541. }
  1542. }
  1543. //-----------------------------------------------------------------------------
  1544. // Called when not in tactical mode. Allows view to be overriden for things like driving a tank.
  1545. //-----------------------------------------------------------------------------
  1546. void C_BasePlayer::OverrideView( CViewSetup *pSetup )
  1547. {
  1548. }
  1549. bool C_BasePlayer::IsCameraMan() const
  1550. {
  1551. return IsActiveCameraMan(); //( HLTVCamera() && ( HLTVCamera()->GetCameraMan() == this ) );
  1552. }
  1553. bool C_BasePlayer::ShouldInterpolate()
  1554. {
  1555. // always interpolate myself
  1556. if ( IsLocalPlayer( this ) )
  1557. return true;
  1558. // always interpolate entity if followed by HLTV/Replay
  1559. #if defined( REPLAY_ENABLED )
  1560. if ( HLTVCamera()->GetCameraMan() == this ||
  1561. ReplayCamera()->GetCameraMan() == this )
  1562. return true;
  1563. #else
  1564. if ( HLTVCamera()->GetCameraMan() == this )
  1565. return true;
  1566. #endif
  1567. return BaseClass::ShouldInterpolate();
  1568. }
  1569. bool C_BasePlayer::ShouldDraw()
  1570. {
  1571. // $FIXME(hpe) this was returning false in splitscreen mode making 2nd player invisible
  1572. #if defined (_GAMECONSOLE) && defined ( CSTRIKE15 )
  1573. ConVarRef ss_enable( "ss_enable" );
  1574. if ( ss_enable.GetInt() > 0 )
  1575. {
  1576. return ( IsLocalSplitScreenPlayer() || this != GetSplitScreenViewPlayer() || C_BasePlayer::ShouldDrawLocalPlayer() || (GetObserverMode() == OBS_MODE_DEATHCAM ) ) &&
  1577. BaseClass::ShouldDraw();
  1578. }
  1579. #endif
  1580. return ( this != GetSplitScreenViewPlayer() || C_BasePlayer::ShouldDrawLocalPlayer() || (GetObserverMode() == OBS_MODE_DEATHCAM ) ) &&
  1581. BaseClass::ShouldDraw();
  1582. }
  1583. int C_BasePlayer::DrawModel( int flags, const RenderableInstance_t &instance )
  1584. {
  1585. // if local player is spectating this player in first person mode, don't draw it
  1586. C_BasePlayer * player = C_BasePlayer::GetLocalPlayer();
  1587. if ( player && player->IsObserver() )
  1588. {
  1589. if ( player->GetObserverMode() == OBS_MODE_IN_EYE &&
  1590. player->GetObserverTarget() == this &&
  1591. !input->CAM_IsThirdPerson() &&
  1592. player->GetObserverInterpState() != OBSERVER_INTERP_TRAVELING )
  1593. return 0;
  1594. }
  1595. return BaseClass::DrawModel( flags, instance );
  1596. }
  1597. bool C_BasePlayer::ShouldSuppressForSplitScreenPlayer( int nSlot )
  1598. {
  1599. if ( BaseClass::ShouldSuppressForSplitScreenPlayer( nSlot ) )
  1600. return true;
  1601. PlayerRenderMode_t nMode = GetPlayerRenderMode( nSlot );
  1602. return ( nMode == PLAYER_RENDER_FIRSTPERSON );
  1603. }
  1604. //-----------------------------------------------------------------------------
  1605. // Computes the render mode for this player
  1606. //-----------------------------------------------------------------------------
  1607. PlayerRenderMode_t C_BasePlayer::GetPlayerRenderMode( int nSlot )
  1608. {
  1609. // check if local player chases owner of this weapon in first person
  1610. C_BasePlayer *pSplitscreenPlayer = GetSplitScreenViewPlayer( nSlot );
  1611. if ( !pSplitscreenPlayer )
  1612. return PLAYER_RENDER_THIRDPERSON;
  1613. if ( pSplitscreenPlayer->IsObserver() )
  1614. {
  1615. if ( pSplitscreenPlayer->GetObserverTarget() != this )
  1616. return PLAYER_RENDER_THIRDPERSON;
  1617. if ( pSplitscreenPlayer->GetObserverMode() != OBS_MODE_IN_EYE )
  1618. return PLAYER_RENDER_THIRDPERSON;
  1619. }
  1620. else
  1621. {
  1622. if ( pSplitscreenPlayer != this )
  1623. return PLAYER_RENDER_THIRDPERSON;
  1624. }
  1625. if ( input->CAM_IsThirdPerson( nSlot ) )
  1626. return PLAYER_RENDER_THIRDPERSON;
  1627. if ( (pSplitscreenPlayer->GetViewEntity() != NULL) &&
  1628. (pSplitscreenPlayer->GetViewEntity() != pSplitscreenPlayer) &&
  1629. pSplitscreenPlayer->m_bShouldDrawPlayerWhileUsingViewEntity )
  1630. return PLAYER_RENDER_THIRDPERSON;
  1631. // if ( IsInThirdPersonView() )
  1632. // return PLAYER_RENDER_THIRDPERSON;
  1633. return PLAYER_RENDER_FIRSTPERSON;
  1634. }
  1635. //-----------------------------------------------------------------------------
  1636. // Purpose:
  1637. //-----------------------------------------------------------------------------
  1638. Vector C_BasePlayer::GetChaseCamViewOffset( CBaseEntity *target )
  1639. {
  1640. C_BasePlayer *player = ToBasePlayer( target );
  1641. if ( player && player->IsAlive() )
  1642. {
  1643. if( player->GetFlags() & FL_DUCKING )
  1644. return VEC_DUCK_VIEW;
  1645. return VEC_VIEW;
  1646. }
  1647. #ifdef CSTRIKE_DLL
  1648. CBaseCSGrenadeProjectile *pGrenade = dynamic_cast< CBaseCSGrenadeProjectile* >( target );
  1649. if ( pGrenade )
  1650. return Vector( 0, 0, 8 );
  1651. #endif
  1652. // assume it's the players ragdoll
  1653. return VEC_DEAD_VIEWHEIGHT;
  1654. }
  1655. void C_BasePlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
  1656. {
  1657. C_BaseEntity *target = GetObserverTarget();
  1658. if ( !target )
  1659. {
  1660. // just copy a save in-map position
  1661. VectorCopy( EyePosition(), eyeOrigin );
  1662. VectorCopy( EyeAngles(), eyeAngles );
  1663. return;
  1664. };
  1665. // If our target isn't visible, we're at a camera point of some kind.
  1666. // Instead of letting the player rotate around an invisible point, treat
  1667. // the point as a fixed camera.
  1668. if ( !target->GetBaseAnimating() && !target->GetModel() )
  1669. {
  1670. CalcRoamingView( eyeOrigin, eyeAngles, fov );
  1671. return;
  1672. }
  1673. /*#ifdef CSTRIKE_DLL
  1674. // weapon gun-cam go-pro chase camera
  1675. C_CSPlayer *pPlayer = ToCSPlayer( target );
  1676. if ( pPlayer && pPlayer->ShouldDraw() )
  1677. {
  1678. Vector vecSrc = target->GetObserverCamOrigin();
  1679. VectorAdd( vecSrc, GetChaseCamViewOffset( target ), vecSrc );
  1680. Vector vecObsForward, vecObsRight, vecObsUp;
  1681. AngleVectors( EyeAngles(), &vecObsForward, &vecObsRight, &vecObsUp );
  1682. trace_t playerEyeTrace;
  1683. UTIL_TraceLine( vecSrc, vecSrc - vecObsForward * 75.0f, MASK_SOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &playerEyeTrace );
  1684. float flDistMax = playerEyeTrace.startpos.DistTo( playerEyeTrace.endpos + vecObsForward * 4 );
  1685. m_flObserverChaseApproach = (m_flObserverChaseApproach >= flDistMax) ? flDistMax : Approach( 75.0f, m_flObserverChaseApproach, gpGlobals->frametime * 20 );
  1686. Vector vecIdealCamEyePos = vecSrc - vecObsForward * m_flObserverChaseApproach;
  1687. Vector vecIdealCamTargetPos = vecSrc + vecObsRight * RemapValClamped( m_flObserverChaseApproach, 20, 75, 6, 16 ) * abs(DotProduct(vecObsUp,Vector(0,0,1)));
  1688. VectorAngles( (vecIdealCamTargetPos - vecIdealCamEyePos ).Normalized(), eyeAngles );
  1689. eyeOrigin = vecIdealCamEyePos;
  1690. return;
  1691. }
  1692. #endif*/
  1693. #ifdef CSTRIKE_DLL
  1694. CBaseCSGrenadeProjectile *pGrenade = dynamic_cast< CBaseCSGrenadeProjectile* >( target );
  1695. #endif
  1696. // QAngle tmpangles;
  1697. Vector forward, viewpoint;
  1698. // GetObserverCamOrigin() returns ragdoll pos if player is ragdolled
  1699. Vector origin = target->GetObserverCamOrigin();
  1700. VectorAdd( origin, GetChaseCamViewOffset( target ), origin );
  1701. QAngle viewangles;
  1702. if ( GetObserverMode() == OBS_MODE_IN_EYE )
  1703. {
  1704. viewangles = eyeAngles;
  1705. }
  1706. #ifdef CSTRIKE_DLL
  1707. else if ( pGrenade && pGrenade->m_nBounces <= 0 )
  1708. {
  1709. Vector vecVel = pGrenade->GetLocalVelocity();
  1710. VectorAngles( vecVel, viewangles );
  1711. }
  1712. #endif
  1713. else if ( IsLocalPlayer( this ) )
  1714. {
  1715. engine->GetViewAngles( viewangles );
  1716. }
  1717. else
  1718. {
  1719. viewangles = EyeAngles();
  1720. }
  1721. // [Forrest] Spectating someone who is headshotted by a teammate and then switching to chase cam leaves
  1722. // you with a permanent roll to the camera that doesn't decay and is not reset
  1723. // even when switching to different players or at the start of the next round
  1724. // if you are still a spectator. (If you spawn as a player, the view is reset.
  1725. // if you switch spectator modes, the view is reset.)
  1726. #ifdef CSTRIKE_DLL
  1727. // The chase camera adopts the yaw and pitch of the previous camera, but the camera
  1728. // should not roll.
  1729. viewangles.z = 0;
  1730. #endif
  1731. m_flObserverChaseDistance += gpGlobals->frametime*48.0f;
  1732. float flMaxDistance = CHASE_CAM_DISTANCE;
  1733. if ( target && target->IsBaseTrain() )
  1734. {
  1735. // if this is a train, we want to be back a little further so we can see more of it
  1736. flMaxDistance *= 2.5f;
  1737. }
  1738. else if ( pGrenade )
  1739. {
  1740. flMaxDistance = 64.0f;
  1741. }
  1742. m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, 16, flMaxDistance );
  1743. AngleVectors( viewangles, &forward );
  1744. VectorNormalize( forward );
  1745. VectorMA(origin, -m_flObserverChaseDistance, forward, viewpoint );
  1746. trace_t trace;
  1747. CTraceFilterNoNPCsOrPlayer filter( target, COLLISION_GROUP_NONE );
  1748. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  1749. Vector hullMin = WALL_MIN, hullMax = WALL_MAX;
  1750. #ifdef CSTRIKE_DLL
  1751. if ( target && Q_strcmp( target->GetClassname(), "class C_PlantedC4" ) == 0 )
  1752. {
  1753. hullMin *= 2.f; hullMax *= 2.f;
  1754. }
  1755. #endif
  1756. UTIL_TraceHull( origin, viewpoint, hullMin, hullMax, MASK_SOLID, &filter, &trace );
  1757. C_BaseEntity::PopEnableAbsRecomputations();
  1758. if (trace.fraction < 1.0)
  1759. {
  1760. viewpoint = trace.endpos;
  1761. m_flObserverChaseDistance = VectorLength(origin - eyeOrigin);
  1762. }
  1763. #ifdef CSTRIKE_DLL
  1764. else if ( pGrenade )
  1765. {
  1766. m_flObserverChaseDistance = MAX( 64, m_flObserverChaseDistance );
  1767. }
  1768. #endif
  1769. VectorCopy( viewangles, eyeAngles );
  1770. VectorCopy( viewpoint, eyeOrigin );
  1771. fov = GetFOV();
  1772. }
  1773. void C_BasePlayer::CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
  1774. {
  1775. #ifdef CSTRIKE_DLL
  1776. // in CS, we can have a spec target, but in roaming, we always want to roam FREE!!! despite the target
  1777. C_BaseEntity *target = this;
  1778. #else
  1779. C_BaseEntity *target = GetObserverTarget();
  1780. if ( !target )
  1781. {
  1782. target = this;
  1783. }
  1784. #endif
  1785. m_flObserverChaseDistance = 0.0;
  1786. eyeOrigin = target->EyePosition();
  1787. eyeAngles = target->EyeAngles();
  1788. if ( spec_track.GetInt() > 0 )
  1789. {
  1790. C_BaseEntity *target = ClientEntityList().GetBaseEntity( spec_track.GetInt() );
  1791. if ( target )
  1792. {
  1793. Vector v = target->GetAbsOrigin(); v.z += 54;
  1794. QAngle a; VectorAngles( v - eyeOrigin, a );
  1795. NormalizeAngles( a );
  1796. eyeAngles = a;
  1797. engine->SetViewAngles( a );
  1798. }
  1799. }
  1800. #ifdef CSTRIKE_DLL
  1801. if ( GetObserverMode() == OBS_MODE_FIXED )
  1802. {
  1803. Vector viewpoint;
  1804. // if we are in a fixed position, do a very simple check to make sure we aren't fixed inside the world below us
  1805. trace_t trace;
  1806. CTraceFilterNoNPCsOrPlayer filter( target, COLLISION_GROUP_NONE );
  1807. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  1808. Vector hullMin = Vector( -2, -2, -24 ), hullMax = Vector( 2, 2, 8 );
  1809. UTIL_TraceHull( eyeOrigin + Vector( 0, 0, 42 ), eyeOrigin + Vector( 0, 0, -16 ), hullMin, hullMax, MASK_SOLID, &filter, &trace );
  1810. C_BaseEntity::PopEnableAbsRecomputations();
  1811. if (trace.fraction < 1.0)
  1812. {
  1813. viewpoint = trace.endpos;
  1814. VectorCopy( viewpoint, eyeOrigin );
  1815. }
  1816. }
  1817. #endif
  1818. // Apply a smoothing offset to smooth out prediction errors.
  1819. Vector vSmoothOffset;
  1820. GetPredictionErrorSmoothingVector( vSmoothOffset );
  1821. eyeOrigin += vSmoothOffset;
  1822. fov = GetFOV();
  1823. }
  1824. //-----------------------------------------------------------------------------
  1825. // Purpose: Calculate the view for the player while he's in freeze frame observer mode
  1826. //-----------------------------------------------------------------------------
  1827. void C_BasePlayer::CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
  1828. {
  1829. C_BaseEntity *pTarget = GetObserverTarget();
  1830. if ( !pTarget )
  1831. {
  1832. CalcDeathCamView( eyeOrigin, eyeAngles, fov );
  1833. return;
  1834. }
  1835. if ( !m_bStartedFreezeFrame )
  1836. {
  1837. m_bStartedFreezeFrame = true;
  1838. }
  1839. // Zoom towards our target
  1840. float flCurTime = (gpGlobals->curtime - m_flFreezeFrameStartTime);
  1841. float flBlendPerc = 0.0f;
  1842. if ( !g_HltvReplaySystem.IsDelayedReplayRequestPending() ) // if we auto-start replay, we don't want to layer camera motion on top of fade on top of replay scene cut
  1843. {
  1844. clamp( flCurTime / spec_freeze_traveltime.GetFloat(), 0, 1 );
  1845. //Msg( "Freezecam @%.2f\n", flCurTime / spec_freeze_traveltime.GetFloat() ); // replayfade
  1846. flBlendPerc = SimpleSpline( flBlendPerc );
  1847. }
  1848. Vector vecCamDesired = pTarget->GetObserverCamOrigin(); // Returns ragdoll origin if they're ragdolled
  1849. VectorAdd( vecCamDesired, GetChaseCamViewOffset( pTarget ), vecCamDesired );
  1850. Vector vecCamTarget = vecCamDesired;
  1851. if ( pTarget->IsAlive() )
  1852. {
  1853. // Look at their chest, not their head
  1854. Vector maxs = GameRules()->GetViewVectors()->m_vHullMax;
  1855. vecCamTarget.z -= (maxs.z * 0.5);
  1856. }
  1857. else
  1858. {
  1859. vecCamTarget.z += VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through
  1860. }
  1861. // Figure out a view position in front of the target
  1862. Vector vecEyeOnPlane = eyeOrigin;
  1863. vecEyeOnPlane.z = vecCamTarget.z;
  1864. Vector vecTargetPos = vecCamTarget;
  1865. Vector vecToTarget = vecTargetPos - vecEyeOnPlane;
  1866. VectorNormalize( vecToTarget );
  1867. // Stop a few units away from the target, and shift up to be at the same height
  1868. vecTargetPos = vecCamTarget - (vecToTarget * m_flFreezeFrameDistance);
  1869. float flEyePosZ = pTarget->EyePosition().z;
  1870. vecTargetPos.z = flEyePosZ + m_flFreezeZOffset;
  1871. // Now trace out from the target, so that we're put in front of any walls
  1872. trace_t trace;
  1873. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  1874. UTIL_TraceHull( vecCamTarget, vecTargetPos, WALL_MIN, WALL_MAX, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace );
  1875. C_BaseEntity::PopEnableAbsRecomputations();
  1876. if (trace.fraction < 1.0)
  1877. {
  1878. // The camera's going to be really close to the target. So we don't end up
  1879. // looking at someone's chest, aim close freezecams at the target's eyes.
  1880. vecTargetPos = trace.endpos;
  1881. vecCamTarget = vecCamDesired;
  1882. // To stop all close in views looking up at character's chins, move the view up.
  1883. vecTargetPos.z += fabs(vecCamTarget.z - vecTargetPos.z) * 0.85;
  1884. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  1885. UTIL_TraceHull( vecCamTarget, vecTargetPos, WALL_MIN, WALL_MAX, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace );
  1886. C_BaseEntity::PopEnableAbsRecomputations();
  1887. vecTargetPos = trace.endpos;
  1888. }
  1889. // Look directly at the target
  1890. vecToTarget = vecCamTarget - vecTargetPos;
  1891. VectorNormalize( vecToTarget );
  1892. VectorAngles( vecToTarget, eyeAngles );
  1893. VectorLerp( m_vecFreezeFrameStart, vecTargetPos, flBlendPerc, eyeOrigin );
  1894. if ( flCurTime >= spec_freeze_traveltime.GetFloat() && !m_bSentFreezeFrame )
  1895. {
  1896. IGameEvent *pEvent = gameeventmanager->CreateEvent( "freezecam_started" );
  1897. if ( pEvent )
  1898. {
  1899. gameeventmanager->FireEventClientSide( pEvent );
  1900. }
  1901. m_bSentFreezeFrame = true;
  1902. view->FreezeFrame( spec_freeze_time.GetFloat() );
  1903. }
  1904. }
  1905. void C_BasePlayer::CalcInEyeCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
  1906. {
  1907. C_BaseEntity *target = GetObserverTarget();
  1908. if ( !target )
  1909. {
  1910. // just copy a save in-map position
  1911. VectorCopy( EyePosition(), eyeOrigin );
  1912. VectorCopy( EyeAngles(), eyeAngles );
  1913. return;
  1914. };
  1915. if ( !target->IsAlive() )
  1916. {
  1917. // if dead, show from 3rd person
  1918. CalcChaseCamView( eyeOrigin, eyeAngles, fov );
  1919. return;
  1920. }
  1921. fov = GetFOV(); // TODO use tragets FOV
  1922. m_flObserverChaseDistance = 0.0;
  1923. eyeAngles = target->EyeAngles();
  1924. eyeOrigin = target->GetAbsOrigin();
  1925. CalcViewBob( eyeOrigin );
  1926. CalcViewRoll( eyeAngles );
  1927. CalcAddViewmodelCameraAnimation( eyeOrigin, eyeAngles );
  1928. // Apply punch angle
  1929. VectorAdd( eyeAngles, GetViewPunchAngle(), eyeAngles );
  1930. // Apply aim punch angle
  1931. VectorAdd( eyeAngles, GetAimPunchAngle() * view_recoil_tracking.GetFloat(), eyeAngles );
  1932. #if defined( REPLAY_ENABLED )
  1933. if( g_bEngineIsHLTV || engine->IsReplay() )
  1934. #else
  1935. if( g_bEngineIsHLTV )
  1936. #endif
  1937. {
  1938. if ( target->GetFlags() & FL_DUCKING )
  1939. {
  1940. eyeOrigin += VEC_DUCK_VIEW;
  1941. }
  1942. else
  1943. {
  1944. eyeOrigin += VEC_VIEW;
  1945. }
  1946. }
  1947. else
  1948. {
  1949. Vector offset = m_vecViewOffset;
  1950. eyeOrigin += offset; // hack hack
  1951. }
  1952. engine->SetViewAngles( eyeAngles );
  1953. }
  1954. float C_BasePlayer::GetDeathCamInterpolationTime()
  1955. {
  1956. return DEATH_ANIMATION_TIME;
  1957. }
  1958. void C_BasePlayer::CalcDeathCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
  1959. {
  1960. CBaseEntity * pKiller = NULL;
  1961. if ( mp_forcecamera.GetInt() == OBS_ALLOW_ALL )
  1962. {
  1963. // if mp_forcecamera is off let user see killer or look around
  1964. pKiller = GetObserverTarget();
  1965. eyeAngles = EyeAngles();
  1966. }
  1967. float interpolation = ( gpGlobals->curtime - m_flDeathTime ) / GetDeathCamInterpolationTime();
  1968. interpolation = clamp( interpolation, 0.0f, 1.0f );
  1969. m_flObserverChaseDistance += gpGlobals->frametime*48.0f;
  1970. m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, 16, CHASE_CAM_DISTANCE );
  1971. QAngle aForward = eyeAngles;
  1972. Vector origin = EyePosition();
  1973. IRagdoll *pRagdoll = GetRepresentativeRagdoll();
  1974. if ( pRagdoll )
  1975. {
  1976. origin = pRagdoll->GetRagdollOrigin();
  1977. origin.z += VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through
  1978. }
  1979. if ( pKiller && pKiller->IsPlayer() && (pKiller != this) )
  1980. {
  1981. Vector vKiller = pKiller->EyePosition() - origin;
  1982. QAngle aKiller; VectorAngles( vKiller, aKiller );
  1983. InterpolateAngles( aForward, aKiller, eyeAngles, interpolation );
  1984. };
  1985. Vector vForward; AngleVectors( eyeAngles, &vForward );
  1986. VectorNormalize( vForward );
  1987. VectorMA( origin, -m_flObserverChaseDistance, vForward, eyeOrigin );
  1988. trace_t trace; // clip against world
  1989. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  1990. UTIL_TraceHull( origin, eyeOrigin, WALL_MIN, WALL_MAX, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace );
  1991. C_BaseEntity::PopEnableAbsRecomputations();
  1992. if (trace.fraction < 1.0)
  1993. {
  1994. eyeOrigin = trace.endpos;
  1995. m_flObserverChaseDistance = VectorLength(origin - eyeOrigin);
  1996. }
  1997. fov = GetFOV();
  1998. }
  1999. //-----------------------------------------------------------------------------
  2000. // Purpose: Return the weapon to have open the weapon selection on, based upon our currently active weapon
  2001. // Base class just uses the weapon that's currently active.
  2002. //-----------------------------------------------------------------------------
  2003. C_BaseCombatWeapon *C_BasePlayer::GetActiveWeaponForSelection( void )
  2004. {
  2005. return GetActiveWeapon();
  2006. }
  2007. C_BaseAnimating* C_BasePlayer::GetRenderedWeaponModel()
  2008. {
  2009. // Attach to either their weapon model or their view model.
  2010. if ( ShouldDrawLocalPlayer() || !IsLocalPlayer( this ) )
  2011. {
  2012. return GetActiveWeapon();
  2013. }
  2014. else
  2015. {
  2016. return GetViewModel();
  2017. }
  2018. }
  2019. //-----------------------------------------------------------------------------
  2020. // Purpose: Gets a pointer to the local player, if it exists yet.
  2021. // static method
  2022. //-----------------------------------------------------------------------------
  2023. C_BasePlayer *C_BasePlayer::GetLocalPlayer( int nSlot /*= -1*/ )
  2024. {
  2025. if ( nSlot == -1 )
  2026. {
  2027. // ASSERT_LOCAL_PLAYER_RESOLVABLE();
  2028. return s_pLocalPlayer[ GET_ACTIVE_SPLITSCREEN_SLOT() ];
  2029. }
  2030. return s_pLocalPlayer[ nSlot ];
  2031. }
  2032. void C_BasePlayer::SetRemoteSplitScreenPlayerViewsAreLocalPlayer( bool bSet )
  2033. {
  2034. for( int i = 0; i != MAX_SPLITSCREEN_PLAYERS; ++i )
  2035. {
  2036. if( !IsLocalSplitScreenPlayer( i ) )
  2037. {
  2038. s_pLocalPlayer[i] = bSet ? GetSplitScreenViewPlayer( i ) : NULL;
  2039. }
  2040. }
  2041. }
  2042. bool C_BasePlayer::HasAnyLocalPlayer()
  2043. {
  2044. FOR_EACH_VALID_SPLITSCREEN_PLAYER( i )
  2045. {
  2046. if ( s_pLocalPlayer[ i ] )
  2047. return true;
  2048. }
  2049. return false;
  2050. }
  2051. int C_BasePlayer::GetSplitScreenSlotForPlayer( C_BaseEntity *pl )
  2052. {
  2053. C_BasePlayer *pPlayer = ToBasePlayer( pl );
  2054. if ( !pPlayer )
  2055. {
  2056. Assert( 0 );
  2057. return -1;
  2058. }
  2059. return pPlayer->GetSplitScreenPlayerSlot();
  2060. }
  2061. //-----------------------------------------------------------------------------
  2062. // Purpose:
  2063. // Input : bThirdperson -
  2064. //-----------------------------------------------------------------------------
  2065. void C_BasePlayer::ThirdPersonSwitch( bool bThirdperson )
  2066. {
  2067. // We've switch from first to third, or vice versa.
  2068. UpdateVisibility();
  2069. }
  2070. //-----------------------------------------------------------------------------
  2071. // Purpose: single place to decide whether the local player should draw
  2072. //-----------------------------------------------------------------------------
  2073. bool C_BasePlayer::ShouldDrawLocalPlayer()
  2074. {
  2075. int nSlot = GetSplitScreenPlayerSlot();
  2076. ACTIVE_SPLITSCREEN_PLAYER_GUARD( nSlot );
  2077. #if !defined( SPLIT_SCREEN_STUBS )
  2078. nSlot = GetSplitScreenPlayerSlot();
  2079. #endif
  2080. #ifdef PORTAL2
  2081. if( !IsLocalSplitScreenPlayer( (nSlot == -1) ? GET_ACTIVE_SPLITSCREEN_SLOT() : nSlot ) ) //HACKHACK: shortcut, avoid going into input and getting a bunch of asserts if the splitscreen view is not a local player
  2082. return false;
  2083. #endif
  2084. return ( GetPlayerRenderMode(nSlot) == PLAYER_RENDER_THIRDPERSON ) || input->CAM_IsThirdPerson() || ( ToolsEnabled() && ToolFramework_IsThirdPersonCamera() );
  2085. }
  2086. //----------------------------------------------------------------------------
  2087. // Hooks into the fast path render system
  2088. //----------------------------------------------------------------------------
  2089. IClientModelRenderable *C_BasePlayer::GetClientModelRenderable()
  2090. {
  2091. #if defined ( CSTRIKE15 )// Since cstrike15 does not do glow, we can go ahead and use fast path for teammates.
  2092. // We can enable mostly opaque models to cause players to be rendered in both the opaque and the translucent fast paths
  2093. // allowing both alpha and non alpha materials to show up.
  2094. // However, since the bounding boxes are different for these "sub models" they have sorting issues when the player
  2095. // is inside of a smoke cloud such that the alpha components sort in front of the smoke cloud.
  2096. // Because of this, we no longer use two passes for players and instead cause all players to NOT use the fast path
  2097. // rendering by returning NULL here.
  2098. return NULL;
  2099. #endif
  2100. // Because of alpha sorting issues with smoke when we have mostlyopaque models.
  2101. // Honor base class eligibility
  2102. if ( !BaseClass::GetClientModelRenderable() )
  2103. return NULL;
  2104. // No fast path for firstperson local players
  2105. if ( IsLocalPlayer( this ) )
  2106. {
  2107. bool bThirdPerson = input->CAM_IsThirdPerson() || ( ToolsEnabled() && ToolFramework_IsThirdPersonCamera() );
  2108. if ( !bThirdPerson )
  2109. {
  2110. return NULL;
  2111. }
  2112. }
  2113. // if local player is spectating this player in first person mode, don't use fast path, so we can skip drawing it
  2114. C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
  2115. if ( localPlayer && localPlayer->IsObserver() )
  2116. {
  2117. if ( localPlayer->GetObserverMode() == OBS_MODE_IN_EYE &&
  2118. localPlayer->GetObserverTarget() == this &&
  2119. !input->CAM_IsThirdPerson() )
  2120. return NULL;
  2121. }
  2122. // Probably for the left 4 dead code.
  2123. // don't use fastpath for teammates (causes extra work for glows)
  2124. if ( localPlayer && localPlayer->GetTeamNumber() == GetTeamNumber() )
  2125. {
  2126. return NULL;
  2127. }
  2128. return this;
  2129. }
  2130. //-----------------------------------------------------------------------------
  2131. // Purpose:
  2132. // Output : Returns true on success, false on failure.
  2133. //-----------------------------------------------------------------------------
  2134. bool C_BasePlayer::IsLocalPlayer( const C_BaseEntity *pEntity )
  2135. {
  2136. if ( !pEntity ||
  2137. !pEntity->IsPlayer() )
  2138. return false;
  2139. return static_cast< const C_BasePlayer * >( pEntity )->m_bIsLocalPlayer;
  2140. }
  2141. int C_BasePlayer::GetUserID( void ) const
  2142. {
  2143. player_info_t pi;
  2144. if ( !engine->GetPlayerInfo( entindex(), &pi ) )
  2145. return -1;
  2146. return pi.userID;
  2147. }
  2148. // For weapon prediction
  2149. void C_BasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
  2150. {
  2151. // FIXME
  2152. }
  2153. void C_BasePlayer::UpdateClientData( void )
  2154. {
  2155. // Update all the items
  2156. for ( int i = 0; i < WeaponCount(); i++ )
  2157. {
  2158. if ( GetWeapon(i) ) // each item updates it's successors
  2159. GetWeapon(i)->UpdateClientData( this );
  2160. }
  2161. }
  2162. // Prediction stuff
  2163. void C_BasePlayer::PreThink( void )
  2164. {
  2165. #if !defined( NO_ENTITY_PREDICTION )
  2166. ItemPreFrame();
  2167. UpdateClientData();
  2168. UpdateUnderwaterState();
  2169. // Update the player's fog data if necessary.
  2170. UpdateFogController();
  2171. if (m_lifeState >= LIFE_DYING)
  2172. return;
  2173. //
  2174. // If we're not on the ground, we're falling. Update our falling velocity.
  2175. //
  2176. if ( !( GetFlags() & FL_ONGROUND ) )
  2177. {
  2178. m_Local.m_flFallVelocity = -GetAbsVelocity().z;
  2179. }
  2180. #endif
  2181. if ( GetGroundEntity() )
  2182. {
  2183. m_flTimeLastTouchedGround = gpGlobals->curtime;
  2184. }
  2185. }
  2186. void C_BasePlayer::PostThink( void )
  2187. {
  2188. #if !defined( NO_ENTITY_PREDICTION )
  2189. MDLCACHE_CRITICAL_SECTION();
  2190. if ( IsAlive())
  2191. {
  2192. UpdateCollisionBounds();
  2193. if ( !CommentaryModeShouldSwallowInput( this ) )
  2194. {
  2195. // do weapon stuff
  2196. ItemPostFrame();
  2197. }
  2198. if ( GetFlags() & FL_ONGROUND )
  2199. {
  2200. m_Local.m_flFallVelocity = 0;
  2201. }
  2202. // Don't allow bogus sequence on player
  2203. if ( GetSequence() == -1 )
  2204. {
  2205. SetSequence( 0 );
  2206. }
  2207. StudioFrameAdvance();
  2208. PostThinkVPhysics();
  2209. }
  2210. // Even if dead simulate entities
  2211. SimulatePlayerSimulatedEntities();
  2212. #endif
  2213. }
  2214. //-----------------------------------------------------------------------------
  2215. // Purpose: send various tool messages - viewoffset, and base class messages (flex and bones)
  2216. //-----------------------------------------------------------------------------
  2217. void C_BasePlayer::GetToolRecordingState( KeyValues *msg )
  2218. {
  2219. if ( !ToolsEnabled() )
  2220. return;
  2221. VPROF_BUDGET( "C_BasePlayer::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
  2222. BaseClass::GetToolRecordingState( msg );
  2223. msg->SetBool( "baseplayer", true );
  2224. msg->SetBool( "localplayer", IsLocalPlayer( this ) );
  2225. msg->SetString( "playername", GetPlayerName() );
  2226. static CameraRecordingState_t state;
  2227. state.m_flFOV = GetFOV();
  2228. float flZNear = view->GetZNear();
  2229. float flZFar = view->GetZFar();
  2230. CalcView( state.m_vecEyePosition, state.m_vecEyeAngles, flZNear, flZFar, state.m_flFOV );
  2231. state.m_bThirdPerson = !engine->IsPaused() && ::input->CAM_IsThirdPerson();
  2232. state.m_bPlayerEyeIsPortalled = false;
  2233. // this is a straight copy from ClientModeShared::OverrideView,
  2234. // When that method is removed in favor of rolling it into CalcView,
  2235. // then this code can (should!) be removed
  2236. if ( state.m_bThirdPerson )
  2237. {
  2238. Vector cam_ofs;
  2239. ::input->CAM_GetCameraOffset( cam_ofs );
  2240. QAngle camAngles;
  2241. camAngles[ PITCH ] = cam_ofs[ PITCH ];
  2242. camAngles[ YAW ] = cam_ofs[ YAW ];
  2243. camAngles[ ROLL ] = 0;
  2244. Vector camForward, camRight, camUp;
  2245. AngleVectors( camAngles, &camForward, &camRight, &camUp );
  2246. VectorMA( state.m_vecEyePosition, -cam_ofs[ ROLL ], camForward, state.m_vecEyePosition );
  2247. // Override angles from third person camera
  2248. VectorCopy( camAngles, state.m_vecEyeAngles );
  2249. }
  2250. msg->SetPtr( "camera", &state );
  2251. }
  2252. //-----------------------------------------------------------------------------
  2253. // Purpose: Simulate the player for this frame
  2254. //-----------------------------------------------------------------------------
  2255. bool C_BasePlayer::Simulate()
  2256. {
  2257. //Frame updates
  2258. if ( C_BasePlayer::IsLocalPlayer( this ) )
  2259. {
  2260. ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( this );
  2261. //Update the flashlight
  2262. Flashlight();
  2263. // Update the player's fog data if necessary.
  2264. UpdateFogController();
  2265. }
  2266. else
  2267. {
  2268. // update step sounds for all other players
  2269. Vector vel;
  2270. EstimateAbsVelocity( vel );
  2271. UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel );
  2272. }
  2273. BaseClass::Simulate();
  2274. // Server says don't interpolate this frame, so set previous info to new info.
  2275. if ( IsEffectActive( EF_NOINTERP ) || Teleported() )
  2276. {
  2277. ResetLatched();
  2278. }
  2279. return true;
  2280. }
  2281. //-----------------------------------------------------------------------------
  2282. // Purpose:
  2283. // Output : CBaseViewModel
  2284. //-----------------------------------------------------------------------------
  2285. C_BaseViewModel *C_BasePlayer::GetViewModel( int index /*= 0*/ ) const
  2286. {
  2287. Assert( index >= 0 && index < MAX_VIEWMODELS );
  2288. C_BaseViewModel *vm = m_hViewModel[ index ];
  2289. if ( GetObserverMode() == OBS_MODE_IN_EYE )
  2290. {
  2291. C_BasePlayer *target = ToBasePlayer( GetObserverTarget() );
  2292. // get the targets viewmodel unless the target is an observer itself
  2293. if ( target && target != this && !target->IsObserver() )
  2294. {
  2295. vm = target->GetViewModel( index );
  2296. }
  2297. }
  2298. return vm;
  2299. }
  2300. C_BaseCombatWeapon *C_BasePlayer::GetActiveWeapon( void ) const
  2301. {
  2302. const C_BasePlayer *fromPlayer = this;
  2303. // if localplayer is in InEye spectator mode, return weapon on chased player.
  2304. if ( ( C_BasePlayer::IsLocalPlayer( const_cast< C_BasePlayer * >( fromPlayer) ) ) && ( GetObserverMode() == OBS_MODE_IN_EYE) )
  2305. {
  2306. C_BaseEntity *target = GetObserverTarget();
  2307. if ( target && target->IsPlayer() )
  2308. {
  2309. fromPlayer = ToBasePlayer( target );
  2310. }
  2311. }
  2312. return fromPlayer->C_BaseCombatCharacter::GetActiveWeapon();
  2313. }
  2314. //=========================================================
  2315. // Autoaim
  2316. // set crosshair position to point to enemey
  2317. //=========================================================
  2318. Vector C_BasePlayer::GetAutoaimVector( float flScale )
  2319. {
  2320. // Never autoaim a predicted weapon (for now)
  2321. Vector forward;
  2322. AngleVectors( GetAbsAngles() + m_Local.m_viewPunchAngle, &forward );
  2323. return forward;
  2324. }
  2325. // Stuff for prediction
  2326. void C_BasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeat)
  2327. {
  2328. // FIXME: Do something here?
  2329. }
  2330. //-----------------------------------------------------------------------------
  2331. // Purpose:
  2332. //-----------------------------------------------------------------------------
  2333. void C_BasePlayer::ResetAutoaim( void )
  2334. {
  2335. #if 0
  2336. if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0)
  2337. {
  2338. m_vecAutoAim = QAngle( 0, 0, 0 );
  2339. engine->CrosshairAngle( edict(), 0, 0 );
  2340. }
  2341. #endif
  2342. m_fOnTarget = false;
  2343. }
  2344. bool C_BasePlayer::ShouldPredict( void )
  2345. {
  2346. #if !defined( NO_ENTITY_PREDICTION )
  2347. // Do this before calling into baseclass so prediction data block gets allocated
  2348. if ( IsLocalPlayer( this ) )
  2349. {
  2350. return true;
  2351. }
  2352. #endif
  2353. return false;
  2354. }
  2355. //-----------------------------------------------------------------------------
  2356. // Purpose: Return the player who will predict this entity
  2357. //-----------------------------------------------------------------------------
  2358. C_BasePlayer *C_BasePlayer::GetPredictionOwner( void )
  2359. {
  2360. return this;
  2361. }
  2362. //-----------------------------------------------------------------------------
  2363. // Purpose: Special processing for player simulation
  2364. // NOTE: Don't chain to BaseClass!!!!
  2365. //-----------------------------------------------------------------------------
  2366. void C_BasePlayer::PhysicsSimulate( void )
  2367. {
  2368. #if !defined( NO_ENTITY_PREDICTION )
  2369. VPROF( "C_BasePlayer::PhysicsSimulate" );
  2370. // If we've got a moveparent, we must simulate that first.
  2371. CBaseEntity *pMoveParent = GetMoveParent();
  2372. if (pMoveParent)
  2373. {
  2374. pMoveParent->PhysicsSimulate();
  2375. }
  2376. // Make sure not to simulate this guy twice per frame
  2377. if (m_nSimulationTick == gpGlobals->tickcount)
  2378. return;
  2379. m_nSimulationTick = gpGlobals->tickcount;
  2380. if ( !IsLocalPlayer( this ) )
  2381. return;
  2382. C_CommandContext *ctx = GetCommandContext();
  2383. Assert( ctx );
  2384. Assert( ctx->needsprocessing );
  2385. if ( !ctx->needsprocessing )
  2386. return;
  2387. ctx->needsprocessing = false;
  2388. m_bTouchedPhysObject = false;
  2389. // Handle FL_FROZEN.
  2390. if(GetFlags() & FL_FROZEN)
  2391. {
  2392. ctx->cmd.forwardmove = 0;
  2393. ctx->cmd.sidemove = 0;
  2394. ctx->cmd.upmove = 0;
  2395. ctx->cmd.buttons = 0;
  2396. ctx->cmd.impulse = 0;
  2397. //VectorCopy ( pl.v_angle, ctx->cmd.viewangles );
  2398. }
  2399. // Run the next command
  2400. MoveHelper()->SetHost( this );
  2401. prediction->RunCommand(
  2402. this,
  2403. &ctx->cmd,
  2404. MoveHelper() );
  2405. UpdateVPhysicsPosition( m_vNewVPhysicsPosition, m_vNewVPhysicsVelocity, TICK_INTERVAL );
  2406. MoveHelper()->SetHost( NULL );
  2407. #endif
  2408. }
  2409. void C_BasePlayer::PhysicsTouchTriggers( const Vector *pPrevAbsOrigin )
  2410. {
  2411. C_BaseCombatCharacter::PhysicsTouchTriggers( pPrevAbsOrigin );
  2412. if ( this == GetLocalPlayer() )
  2413. {
  2414. extern void TouchTriggerSoundOperator( C_BaseEntity *pEntity );
  2415. TouchTriggerSoundOperator( this );
  2416. }
  2417. }
  2418. QAngle C_BasePlayer::GetViewPunchAngle()
  2419. {
  2420. return m_Local.m_viewPunchAngle.Get();
  2421. }
  2422. void C_BasePlayer::SetViewPunchAngle( const QAngle &angle )
  2423. {
  2424. m_Local.m_viewPunchAngle = angle;
  2425. }
  2426. QAngle C_BasePlayer::GetAimPunchAngle()
  2427. {
  2428. return m_Local.m_aimPunchAngle.Get();
  2429. }
  2430. void C_BasePlayer::SetAimPunchAngle( const QAngle &angle )
  2431. {
  2432. m_Local.m_aimPunchAngle = angle;
  2433. }
  2434. void C_BasePlayer::SetAimPunchAngleVelocity( const QAngle &angleVelocity )
  2435. {
  2436. m_Local.m_aimPunchAngleVel = angleVelocity;
  2437. }
  2438. QAngle C_BasePlayer::GetFinalAimAngle()
  2439. {
  2440. QAngle eyeAngles = EyeAngles();
  2441. if ( PlatformInputDevice::IsInputDeviceAPointer( g_pInputSystem->GetCurrentInputDevice() ) )
  2442. {
  2443. // If we are using a pointing device, our final aim angle is based on where we're pointing and not where we're looking.
  2444. VectorAngles( GetAimDirection(), eyeAngles );
  2445. }
  2446. return eyeAngles + GetAimPunchAngle();
  2447. }
  2448. float C_BasePlayer::GetWaterJumpTime() const
  2449. {
  2450. return m_flWaterJumpTime;
  2451. }
  2452. void C_BasePlayer::SetWaterJumpTime( float flWaterJumpTime )
  2453. {
  2454. m_flWaterJumpTime = flWaterJumpTime;
  2455. }
  2456. float C_BasePlayer::GetSwimSoundTime() const
  2457. {
  2458. return m_flSwimSoundTime;
  2459. }
  2460. void C_BasePlayer::SetSwimSoundTime( float flSwimSoundTime )
  2461. {
  2462. m_flSwimSoundTime = flSwimSoundTime;
  2463. }
  2464. //-----------------------------------------------------------------------------
  2465. // Purpose: Return true if this object can be +used by the player
  2466. //-----------------------------------------------------------------------------
  2467. bool C_BasePlayer::IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps )
  2468. {
  2469. return false;
  2470. }
  2471. C_BaseEntity* C_BasePlayer::GetUseEntity( void ) const
  2472. {
  2473. return m_hUseEntity;
  2474. }
  2475. C_BaseEntity* C_BasePlayer::GetPotentialUseEntity( void ) const
  2476. {
  2477. return GetUseEntity();
  2478. }
  2479. //-----------------------------------------------------------------------------
  2480. // Purpose:
  2481. // Output : float
  2482. //-----------------------------------------------------------------------------
  2483. float C_BasePlayer::GetFOV( void ) const
  2484. {
  2485. if ( GetObserverMode() == OBS_MODE_IN_EYE )
  2486. {
  2487. C_BasePlayer *pTargetPlayer = ToBasePlayer( GetObserverTarget() );
  2488. // get fov from observer target. Not if target is observer itself
  2489. if ( pTargetPlayer && !pTargetPlayer->IsObserver() )
  2490. {
  2491. return pTargetPlayer->GetFOV();
  2492. }
  2493. }
  2494. // Allow our vehicle to override our FOV if it's currently at the default FOV.
  2495. float flDefaultFOV;
  2496. IClientVehicle *pVehicle = const_cast< C_BasePlayer * >(this)->GetVehicle();
  2497. if ( pVehicle )
  2498. {
  2499. if ( IsX360() == false )
  2500. const_cast< C_BasePlayer * >(this)->CacheVehicleView();
  2501. flDefaultFOV = ( m_flVehicleViewFOV == 0 ) ? GetDefaultFOV() : m_flVehicleViewFOV;
  2502. }
  2503. else
  2504. {
  2505. flDefaultFOV = GetDefaultFOV();
  2506. }
  2507. float fFOV = ( m_iFOV == 0 ) ? flDefaultFOV : m_iFOV;
  2508. // Don't do lerping during prediction. It's only necessary when actually rendering,
  2509. // and it'll cause problems due to prediction timing messiness.
  2510. if ( !prediction->InPrediction() )
  2511. {
  2512. // See if we need to lerp the values for local player
  2513. if ( IsLocalPlayer( this ) && ( fFOV != m_iFOVStart ) && (m_Local.m_flFOVRate > 0.0f ) )
  2514. {
  2515. float deltaTime = (float)( gpGlobals->curtime - m_flFOVTime ) / m_Local.m_flFOVRate;
  2516. #if !defined( NO_ENTITY_PREDICTION )
  2517. if ( GetPredictable() )
  2518. {
  2519. // m_flFOVTime was set to a predicted time in the future, because the FOV change was predicted.
  2520. deltaTime = (float)( GetFinalPredictedTime() - m_flFOVTime );
  2521. deltaTime += ( gpGlobals->interpolation_amount * TICK_INTERVAL );
  2522. deltaTime /= m_Local.m_flFOVRate;
  2523. }
  2524. #endif
  2525. if ( deltaTime >= 1.0f )
  2526. {
  2527. //If we're past the zoom time, just take the new value and stop lerping
  2528. const_cast<C_BasePlayer *>(this)->m_iFOVStart = fFOV;
  2529. }
  2530. else
  2531. {
  2532. fFOV = SimpleSplineRemapValClamped( deltaTime, 0.0f, 1.0f, (float) m_iFOVStart, fFOV );
  2533. }
  2534. }
  2535. }
  2536. return fFOV;
  2537. }
  2538. void C_BasePlayer::RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2539. {
  2540. C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
  2541. Assert( pPlayer );
  2542. float flNewVel_x = pData->m_Value.m_Float;
  2543. Vector vecVelocity = pPlayer->GetLocalVelocity();
  2544. if( vecVelocity.x != flNewVel_x ) // Should this use an epsilon check?
  2545. {
  2546. vecVelocity.x = flNewVel_x;
  2547. pPlayer->SetLocalVelocity( vecVelocity );
  2548. }
  2549. }
  2550. void C_BasePlayer::RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2551. {
  2552. C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
  2553. Assert( pPlayer );
  2554. float flNewVel_y = pData->m_Value.m_Float;
  2555. Vector vecVelocity = pPlayer->GetLocalVelocity();
  2556. if( vecVelocity.y != flNewVel_y )
  2557. {
  2558. vecVelocity.y = flNewVel_y;
  2559. pPlayer->SetLocalVelocity( vecVelocity );
  2560. }
  2561. }
  2562. void C_BasePlayer::RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2563. {
  2564. C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
  2565. Assert( pPlayer );
  2566. float flNewVel_z = pData->m_Value.m_Float;
  2567. Vector vecVelocity = pPlayer->GetLocalVelocity();
  2568. if( vecVelocity.z != flNewVel_z )
  2569. {
  2570. vecVelocity.z = flNewVel_z;
  2571. pPlayer->SetLocalVelocity( vecVelocity );
  2572. }
  2573. }
  2574. void C_BasePlayer::RecvProxy_ObserverMode( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2575. {
  2576. RecvProxy_Int32ToInt32( pData, pStruct, pOut );
  2577. C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
  2578. Assert( pPlayer );
  2579. if ( pPlayer )
  2580. pPlayer->OnObserverModeChange( false );
  2581. }
  2582. void C_BasePlayer::OnObserverModeChange( bool bIsObserverTarget )
  2583. {
  2584. C_BasePlayer *pPlayer = this;
  2585. if ( C_BasePlayer::IsLocalPlayer( pPlayer ) || bIsObserverTarget )
  2586. {
  2587. pPlayer->UpdateVisibility();
  2588. UpdateViewmodelVisibility( pPlayer );
  2589. }
  2590. if ( bIsObserverTarget )
  2591. return;
  2592. // [msmith] When the observer mode changes, we also need to update the visibility of the view models for the
  2593. // target we are observing. This is important when changing between first and third person when in split screen.
  2594. C_BasePlayer* observerTarget = ToBasePlayer( pPlayer->GetObserverTarget() );
  2595. if ( NULL != observerTarget )
  2596. {
  2597. observerTarget->UpdateVisibility();
  2598. UpdateViewmodelVisibility( observerTarget );
  2599. }
  2600. }
  2601. void C_BasePlayer::RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2602. {
  2603. C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
  2604. Assert( pPlayer );
  2605. EHANDLE hTarget;
  2606. RecvProxy_IntToEHandle( pData, pStruct, &hTarget );
  2607. pPlayer->SetObserverTarget( hTarget );
  2608. }
  2609. void C_BasePlayer::RecvProxy_LocalOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2610. {
  2611. C_BasePlayer *player = (C_BasePlayer *) pStruct;
  2612. player->m_vecHack_RecvProxy_LocalPlayerOrigin.x = pData->m_Value.m_Vector[0];
  2613. player->m_vecHack_RecvProxy_LocalPlayerOrigin.y = pData->m_Value.m_Vector[1];
  2614. ((float*)pOut)[0] = pData->m_Value.m_Vector[0];
  2615. ((float*)pOut)[1] = pData->m_Value.m_Vector[1];
  2616. }
  2617. void C_BasePlayer::RecvProxy_LocalOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2618. {
  2619. C_BasePlayer *player = (C_BasePlayer *) pStruct;
  2620. player->m_vecHack_RecvProxy_LocalPlayerOrigin.z = pData->m_Value.m_Float;
  2621. *((float*)pOut) = pData->m_Value.m_Float;
  2622. }
  2623. void C_BasePlayer::RecvProxy_NonLocalOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2624. {
  2625. ((float*)pOut)[0] = pData->m_Value.m_Vector[0];
  2626. ((float*)pOut)[1] = pData->m_Value.m_Vector[1];
  2627. }
  2628. void C_BasePlayer::RecvProxy_NonLocalOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2629. {
  2630. *((float*)pOut) = pData->m_Value.m_Float;
  2631. }
  2632. void C_BasePlayer::RecvProxy_NonLocalCellOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2633. {
  2634. C_BasePlayer *player = (C_BasePlayer *) pStruct;
  2635. player->m_vecCellOrigin.x = pData->m_Value.m_Vector[0];
  2636. player->m_vecCellOrigin.y = pData->m_Value.m_Vector[1];
  2637. register int const cellwidth = player->m_cellwidth; // Load it into a register
  2638. ((float*)pOut)[0] = CoordFromCell( cellwidth, player->m_cellX, pData->m_Value.m_Vector[0] );
  2639. ((float*)pOut)[1] = CoordFromCell( cellwidth, player->m_cellY, pData->m_Value.m_Vector[1] );
  2640. }
  2641. void C_BasePlayer::RecvProxy_NonLocalCellOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2642. {
  2643. C_BasePlayer *player = (C_BasePlayer *) pStruct;
  2644. player->m_vecCellOrigin.z = pData->m_Value.m_Float;
  2645. register int const cellwidth = player->m_cellwidth; // Load it into a register
  2646. *((float*)pOut) = CoordFromCell( cellwidth, player->m_cellZ, pData->m_Value.m_Float );
  2647. }
  2648. //-----------------------------------------------------------------------------
  2649. // Purpose: Remove this player from a vehicle
  2650. //-----------------------------------------------------------------------------
  2651. void C_BasePlayer::LeaveVehicle( void )
  2652. {
  2653. if ( NULL == m_hVehicle.Get() )
  2654. return;
  2655. // Let server do this for now
  2656. #if 0
  2657. IClientVehicle *pVehicle = GetVehicle();
  2658. Assert( pVehicle );
  2659. int nRole = pVehicle->GetPassengerRole( this );
  2660. Assert( nRole != VEHICLE_ROLE_NONE );
  2661. SetParent( NULL );
  2662. // Find the first non-blocked exit point:
  2663. Vector vNewPos = GetAbsOrigin();
  2664. QAngle qAngles = GetAbsAngles();
  2665. pVehicle->GetPassengerExitPoint( nRole, &vNewPos, &qAngles );
  2666. OnVehicleEnd( vNewPos );
  2667. SetAbsOrigin( vNewPos );
  2668. SetAbsAngles( qAngles );
  2669. m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION;
  2670. RemoveEffects( EF_NODRAW );
  2671. SetMoveType( MOVETYPE_WALK );
  2672. SetCollisionGroup( COLLISION_GROUP_PLAYER );
  2673. qAngles[ROLL] = 0;
  2674. SnapEyeAngles( qAngles );
  2675. m_hVehicle = NULL;
  2676. pVehicle->SetPassenger(nRole, NULL);
  2677. Weapon_Switch( m_hLastWeapon );
  2678. #endif
  2679. }
  2680. float C_BasePlayer::GetMinFOV() const
  2681. {
  2682. if ( gpGlobals->maxClients == 1 )
  2683. {
  2684. // Let them do whatever they want, more or less, in single player
  2685. return 5;
  2686. }
  2687. else
  2688. {
  2689. return 75;
  2690. }
  2691. }
  2692. float C_BasePlayer::GetFinalPredictedTime() const
  2693. {
  2694. return ( m_nFinalPredictedTick * TICK_INTERVAL );
  2695. }
  2696. float C_BasePlayer::PredictedServerTime() const
  2697. {
  2698. return m_fLastUpdateServerTime + ((m_nTickBase - m_nLastUpdateTickBase) * TICK_INTERVAL);
  2699. }
  2700. void C_BasePlayer::NotePredictionError( const Vector &vDelta )
  2701. {
  2702. // don't worry about prediction errors when dead
  2703. if ( !IsAlive() )
  2704. return;
  2705. #if !defined( NO_ENTITY_PREDICTION )
  2706. Vector vOldDelta;
  2707. GetPredictionErrorSmoothingVector( vOldDelta );
  2708. // sum all errors within smoothing time
  2709. m_vecPredictionError = vDelta + vOldDelta;
  2710. // remember when last error happened
  2711. m_flPredictionErrorTime = gpGlobals->curtime;
  2712. ResetLatched();
  2713. #endif
  2714. }
  2715. // offset curtime and setup bones at that time using fake interpolation
  2716. // fake interpolation means we don't have reliable interpolation history (the local player doesn't animate locally)
  2717. // so we just modify cycle and origin directly and use that as a fake guess
  2718. void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4a_t *pBonesOut, float curtimeOffset )
  2719. {
  2720. // we don't have any interpolation data, so fake it
  2721. float cycle = m_flCycle;
  2722. Vector origin = GetLocalOrigin();
  2723. // blow the cached prev bones
  2724. InvalidateBoneCache();
  2725. // reset root position to flTime
  2726. Interpolate( gpGlobals->curtime + curtimeOffset );
  2727. // force cycle back by boneDt
  2728. m_flCycle = fmod( 10 + cycle + GetPlaybackRate() * curtimeOffset, 1.0f );
  2729. SetLocalOrigin( origin + curtimeOffset * GetLocalVelocity() );
  2730. // Setup bone state to extrapolate physics velocity
  2731. SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime + curtimeOffset );
  2732. m_flCycle = cycle;
  2733. SetLocalOrigin( origin );
  2734. }
  2735. void C_BasePlayer::GetRagdollInitBoneArrays( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt )
  2736. {
  2737. if ( !C_BasePlayer::IsLocalPlayer( this ) )
  2738. {
  2739. BaseClass::GetRagdollInitBoneArrays(pDeltaBones0, pDeltaBones1, pCurrentBones, boneDt);
  2740. return;
  2741. }
  2742. ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones0, -boneDt );
  2743. ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones1, 0 );
  2744. float ragdollCreateTime = PhysGetSyncCreateTime();
  2745. if ( ragdollCreateTime != gpGlobals->curtime )
  2746. {
  2747. ForceSetupBonesAtTimeFakeInterpolation( pCurrentBones, ragdollCreateTime - gpGlobals->curtime );
  2748. }
  2749. else
  2750. {
  2751. SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  2752. }
  2753. }
  2754. void C_BasePlayer::GetPredictionErrorSmoothingVector( Vector &vOffset )
  2755. {
  2756. #if !defined( NO_ENTITY_PREDICTION )
  2757. if ( engine->IsPlayingDemo() || !cl_smooth.GetInt() || !cl_predict->GetInt() || engine->IsPaused() )
  2758. {
  2759. vOffset.Init();
  2760. return;
  2761. }
  2762. float errorAmount = ( gpGlobals->curtime - m_flPredictionErrorTime ) / cl_smoothtime.GetFloat();
  2763. if ( errorAmount >= 1.0f )
  2764. {
  2765. vOffset.Init();
  2766. return;
  2767. }
  2768. errorAmount = 1.0f - errorAmount;
  2769. vOffset = m_vecPredictionError * errorAmount;
  2770. #else
  2771. vOffset.Init();
  2772. #endif
  2773. }
  2774. IRagdoll* C_BasePlayer::GetRepresentativeRagdoll() const
  2775. {
  2776. return m_pRagdoll;
  2777. }
  2778. IMaterial *C_BasePlayer::GetHeadLabelMaterial( void )
  2779. {
  2780. if ( GetClientVoiceMgr() == NULL )
  2781. return NULL;
  2782. return GetClientVoiceMgr()->GetHeadLabelMaterial();
  2783. }
  2784. void C_BasePlayer::UpdateSpeechVOIP( bool bVoice )
  2785. {
  2786. m_bPlayerIsTalkingOverVOIP = ( bVoice && ShouldShowVOIPIcon() );
  2787. if ( voice_icons_method.GetInt() == 2 )
  2788. return;
  2789. if ( m_bPlayerIsTalkingOverVOIP )
  2790. {
  2791. if ( !m_speechVOIPParticleEffect.IsValid() )
  2792. {
  2793. MDLCACHE_CRITICAL_SECTION();
  2794. m_speechVOIPParticleEffect = GetVOIPParticleEffect();
  2795. }
  2796. }
  2797. else
  2798. {
  2799. if ( m_speechVOIPParticleEffect.IsValid() )
  2800. {
  2801. ParticleProp()->StopEmissionAndDestroyImmediately( m_speechVOIPParticleEffect );
  2802. m_speechVOIPParticleEffect = NULL;
  2803. }
  2804. }
  2805. }
  2806. bool C_BasePlayer::ShouldShowVOIPIcon() const
  2807. {
  2808. return GameRules() && GameRules()->IsMultiplayer() && ( !IsLocalPlayer( this ) || voice_all_icons.GetBool() );
  2809. }
  2810. CNewParticleEffect *C_BasePlayer::GetVOIPParticleEffect( void )
  2811. {
  2812. return ParticleProp()->Create( GetVOIPParticleEffectName(), PATTACH_ABSORIGIN_FOLLOW, -1, ( EyePosition() - GetAbsOrigin() ) + Vector( 0.0f, 0.0f, GetClientVoiceMgr()->GetHeadLabelOffset() ) );
  2813. }
  2814. bool IsInFreezeCam( void )
  2815. {
  2816. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  2817. if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM )
  2818. return true;
  2819. return false;
  2820. }
  2821. void C_BasePlayer::SetLastKillerDamageAndFreezeframe( int nLastKillerDamageTaken, int nLastKillerHitsTaken, int nLastKillerDamageGiven, int nLastKillerHitsGiven )
  2822. {
  2823. m_nLastKillerDamageTaken = nLastKillerDamageTaken;
  2824. m_nLastKillerHitsTaken = nLastKillerHitsTaken;
  2825. m_nLastKillerDamageGiven = nLastKillerDamageGiven;
  2826. m_nLastKillerHitsGiven = nLastKillerHitsGiven;
  2827. m_bCanShowFreezeFrameNow = true;
  2828. //m_bCheckHltvReplayAutoStart = spec_replay_autostart.GetBool();
  2829. }
  2830. //-----------------------------------------------------------------------------
  2831. // Purpose: Set the fog controller data per player.
  2832. // Input : &inputdata -
  2833. //-----------------------------------------------------------------------------
  2834. void C_BasePlayer::FogControllerChanged( bool bSnap )
  2835. {
  2836. if ( m_PlayerFog.m_hCtrl )
  2837. {
  2838. fogparams_t *pFogParams = &(m_PlayerFog.m_hCtrl->m_fog);
  2839. /*
  2840. Msg("FOG %s (%d) Updating Fog Target: (%d,%d,%d) %.0f,%.0f -> (%d,%d,%d) %.0f,%.0f (%.2f seconds)\n",
  2841. GetPlayerName(), entindex(),
  2842. m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(),
  2843. m_CurrentFog.start.Get(), m_CurrentFog.end.Get(),
  2844. pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetB(), pFogParams->colorPrimary.GetG(),
  2845. pFogParams->start.Get(), pFogParams->end.Get(), pFogParams->duration.Get() );*/
  2846. // Setup the fog color transition.
  2847. m_PlayerFog.m_OldColor = m_CurrentFog.colorPrimary;
  2848. m_PlayerFog.m_flOldStart = m_CurrentFog.start;
  2849. m_PlayerFog.m_flOldEnd = m_CurrentFog.end;
  2850. m_PlayerFog.m_flOldMaxDensity = m_CurrentFog.maxdensity;
  2851. m_PlayerFog.m_flOldHDRColorScale = m_CurrentFog.HDRColorScale;
  2852. m_PlayerFog.m_flOldFarZ = m_CurrentFog.farz;
  2853. m_PlayerFog.m_NewColor = pFogParams->colorPrimary;
  2854. m_PlayerFog.m_flNewStart = pFogParams->start;
  2855. m_PlayerFog.m_flNewEnd = pFogParams->end;
  2856. m_PlayerFog.m_flNewMaxDensity = pFogParams->maxdensity;
  2857. m_PlayerFog.m_flNewHDRColorScale = pFogParams->HDRColorScale;
  2858. m_PlayerFog.m_flNewFarZ = pFogParams->farz;
  2859. m_PlayerFog.m_flTransitionTime = bSnap ? -1 : gpGlobals->curtime;
  2860. m_PlayerFog.m_flZoomFogScale = pFogParams->ZoomFogScale;
  2861. m_CurrentFog = *pFogParams;
  2862. // Update the fog player's local fog data with the fog controller's data if need be.
  2863. UpdateFogController();
  2864. }
  2865. }
  2866. //-----------------------------------------------------------------------------
  2867. // Purpose: Check to see that the controllers data is up to date.
  2868. //-----------------------------------------------------------------------------
  2869. void C_BasePlayer::UpdateFogController( void )
  2870. {
  2871. if ( m_PlayerFog.m_hCtrl )
  2872. {
  2873. // Don't bother copying while we're transitioning, since it'll be stomped in UpdateFogBlend();
  2874. if ( m_PlayerFog.m_flTransitionTime == -1 && (m_hOldFogController == m_PlayerFog.m_hCtrl) )
  2875. {
  2876. fogparams_t *pFogParams = &(m_PlayerFog.m_hCtrl->m_fog);
  2877. if ( m_CurrentFog != *pFogParams )
  2878. {
  2879. /*
  2880. Msg("FOG %s (%d) FORCING UPDATE: (%d,%d,%d) %.0f,%.0f -> (%d,%d,%d) %.0f,%.0f (%.2f seconds)\n",
  2881. GetPlayerName(), entindex(),
  2882. m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(),
  2883. m_CurrentFog.start.Get(), m_CurrentFog.end.Get(),
  2884. pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetB(), pFogParams->colorPrimary.GetG(),
  2885. pFogParams->start.Get(), pFogParams->end.Get(), pFogParams->duration.Get() );*/
  2886. m_CurrentFog = *pFogParams;
  2887. }
  2888. }
  2889. }
  2890. else
  2891. {
  2892. if ( m_CurrentFog.farz != -1 || m_CurrentFog.enable != false )
  2893. {
  2894. // No fog controller in this level. Use default fog parameters.
  2895. m_CurrentFog.farz = -1;
  2896. m_CurrentFog.enable = false;
  2897. }
  2898. }
  2899. // Update the fog blending state - of necessary.
  2900. UpdateFogBlend();
  2901. }
  2902. //-----------------------------------------------------------------------------
  2903. //
  2904. //-----------------------------------------------------------------------------
  2905. void C_BasePlayer::UpdateFogBlend( void )
  2906. {
  2907. float flNewStart = m_PlayerFog.m_flNewStart;
  2908. float flNewEnd = m_PlayerFog.m_flNewEnd;
  2909. // Transition.
  2910. if ( m_PlayerFog.m_flTransitionTime != -1 )
  2911. {
  2912. float flTimeDelta = gpGlobals->curtime - m_PlayerFog.m_flTransitionTime;
  2913. if ( flTimeDelta < m_CurrentFog.duration )
  2914. {
  2915. float flScale = flTimeDelta / m_CurrentFog.duration;
  2916. m_CurrentFog.colorPrimary.SetR( ( m_PlayerFog.m_NewColor.r * flScale ) + ( m_PlayerFog.m_OldColor.r * ( 1.0f - flScale ) ) );
  2917. m_CurrentFog.colorPrimary.SetG( ( m_PlayerFog.m_NewColor.g * flScale ) + ( m_PlayerFog.m_OldColor.g * ( 1.0f - flScale ) ) );
  2918. m_CurrentFog.colorPrimary.SetB( ( m_PlayerFog.m_NewColor.b * flScale ) + ( m_PlayerFog.m_OldColor.b * ( 1.0f - flScale ) ) );
  2919. m_CurrentFog.start.Set( ( flNewStart * flScale ) + ( ( m_PlayerFog.m_flOldStart * ( 1.0f - flScale ) ) ) );
  2920. m_CurrentFog.end.Set( ( flNewEnd * flScale ) + ( ( m_PlayerFog.m_flOldEnd * ( 1.0f - flScale ) ) ) );
  2921. m_CurrentFog.maxdensity.Set( ( m_PlayerFog.m_flNewMaxDensity * flScale ) + ( ( m_PlayerFog.m_flOldMaxDensity * ( 1.0f - flScale ) ) ) );
  2922. m_CurrentFog.HDRColorScale.Set( ( m_PlayerFog.m_flNewHDRColorScale * flScale ) + ( ( m_PlayerFog.m_flOldHDRColorScale * ( 1.0f - flScale ) ) ) );
  2923. // Lerp to a sane FarZ (default value comes from CViewRender::GetZFar())
  2924. float newFarZ = m_PlayerFog.m_flNewFarZ;
  2925. if ( newFarZ <= 0 )
  2926. newFarZ = r_mapextents.GetFloat() * 1.73205080757f;
  2927. float oldFarZ = m_PlayerFog.m_flOldFarZ;
  2928. if ( oldFarZ <= 0 )
  2929. oldFarZ = r_mapextents.GetFloat() * 1.73205080757f;
  2930. m_CurrentFog.farz.Set( ( newFarZ * flScale ) + ( ( oldFarZ * ( 1.0f - flScale ) ) ) );
  2931. }
  2932. else
  2933. {
  2934. // Slam the final fog values.
  2935. m_CurrentFog.colorPrimary.SetR( m_PlayerFog.m_NewColor.r );
  2936. m_CurrentFog.colorPrimary.SetG( m_PlayerFog.m_NewColor.g );
  2937. m_CurrentFog.colorPrimary.SetB( m_PlayerFog.m_NewColor.b );
  2938. m_CurrentFog.start.Set( flNewStart );
  2939. m_CurrentFog.end.Set( flNewEnd );
  2940. m_CurrentFog.maxdensity.Set( m_PlayerFog.m_flNewMaxDensity );
  2941. m_CurrentFog.HDRColorScale.Set( m_PlayerFog.m_flNewHDRColorScale );
  2942. m_CurrentFog.farz.Set( m_PlayerFog.m_flNewFarZ );
  2943. m_PlayerFog.m_flTransitionTime = -1;
  2944. /*
  2945. Msg("FOG %s (%d) Finished transition to (%d,%d,%d) %.0f,%.0f\n",
  2946. GetPlayerName(), entindex(),
  2947. m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(),
  2948. m_CurrentFog.start.Get(), m_CurrentFog.end.Get() );*/
  2949. }
  2950. }
  2951. #if defined( CSTRIKE_DLL )
  2952. float flFov = GetFOV();
  2953. float flDefaultFov = GetDefaultFOV( );
  2954. if ( flFov < flDefaultFov )
  2955. {
  2956. float frac = (1.0 - MAX( 0.1, flFov / flDefaultFov )) * m_PlayerFog.m_flZoomFogScale;
  2957. flNewEnd = flNewEnd + (800 * frac);
  2958. flNewStart = flNewStart + (200 * frac);
  2959. m_CurrentFog.start.Set( flNewStart );
  2960. m_CurrentFog.end.Set( flNewEnd );
  2961. }
  2962. #endif
  2963. }
  2964. //-----------------------------------------------------------------------------
  2965. //
  2966. //-----------------------------------------------------------------------------
  2967. C_PostProcessController* C_BasePlayer::GetActivePostProcessController() const
  2968. {
  2969. return m_hPostProcessCtrl.Get();
  2970. }
  2971. //-----------------------------------------------------------------------------
  2972. //
  2973. //-----------------------------------------------------------------------------
  2974. C_ColorCorrection* C_BasePlayer::GetActiveColorCorrection() const
  2975. {
  2976. return m_hColorCorrectionCtrl.Get();
  2977. }
  2978. bool C_BasePlayer::PreRender( int nSplitScreenPlayerSlot )
  2979. {
  2980. if ( !IsVisible() ||
  2981. !GetClientMode()->ShouldDrawLocalPlayer( this ) )
  2982. {
  2983. return true;
  2984. }
  2985. // Add in lighting effects
  2986. return CreateLightEffects();
  2987. }
  2988. bool C_BasePlayer::IsSplitScreenPartner( C_BasePlayer *pPlayer )
  2989. {
  2990. if ( !pPlayer || pPlayer == this )
  2991. return false;
  2992. for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  2993. {
  2994. if ( s_pLocalPlayer[i] == pPlayer )
  2995. return true;
  2996. }
  2997. return false;
  2998. }
  2999. int C_BasePlayer::GetSplitScreenPlayerSlot()
  3000. {
  3001. Assert( ( m_nSplitScreenSlot >= 0 ) && ( m_nSplitScreenSlot < MAX_SPLITSCREEN_PLAYERS ) );
  3002. return m_nSplitScreenSlot;
  3003. }
  3004. bool C_BasePlayer::IsSplitScreenPlayer() const
  3005. {
  3006. return m_nSplitScreenSlot >= 1;
  3007. }
  3008. CrossPlayPlatform_t C_BasePlayer::GetCrossPlayPlatform( void ) const
  3009. {
  3010. return CROSSPLAYPLATFORM_THISPLATFORM;
  3011. }
  3012. bool C_BasePlayer::ShouldRegenerateOriginFromCellBits() const
  3013. {
  3014. // Don't use cell bits for local players
  3015. if (
  3016. #ifdef PORTAL2
  3017. // HACK: In Portal 2, when we start recording a demo, the player is removed and recreated.
  3018. // There's a brief window where there is no local player and the non-local data table
  3019. // is sent across for the newly created player, containing the cell origin. This is
  3020. // incorrectly interpreted and copied to the network origin. The new network origin
  3021. // is copied to the local origin, which, among other things, screws up the player's eye
  3022. // position until she moves enough for a network update to fix her position. During this
  3023. // brief time, if we correctly regenerate the origin from the cell bits we received, it
  3024. // prevents this problem. At this point, changing the portal player's network tables
  3025. // could have a significant impact on perf and require a PS3 fix to maintain crossplay
  3026. // compatibility, so this is less risky.
  3027. // - Ted Rivera (2/25/2011)
  3028. ( C_BasePlayer::HasAnyLocalPlayer() ||
  3029. ( !engine->IsPlayingDemo() &&
  3030. !engine->IsRecordingDemo() &&
  3031. !engine->IsPlayingTimeDemo() ) ) &&
  3032. #endif
  3033. (IsLocalPlayer( this ) ||
  3034. (!g_pGameRules->IsMultiplayer()) ) ) //SP load fails the IsLocalPlayer() test while creating the player. Resulting in a bad origin until you move
  3035. {
  3036. return false;
  3037. }
  3038. /*if ( g_pGameRules->IsMultiplayer() &&
  3039. (GetCreationTick() == gpGlobals->tickcount) &&
  3040. !C_BasePlayer::HasAnyLocalPlayer() &&
  3041. (engine->GetLocalPlayer() == index) )
  3042. {
  3043. return false;
  3044. }*/
  3045. return BaseClass::ShouldRegenerateOriginFromCellBits();
  3046. }
  3047. //-----------------------------------------------------------------------------
  3048. // Purpose:
  3049. //-----------------------------------------------------------------------------
  3050. bool C_BasePlayer::GetSteamID( CSteamID *pID )
  3051. {
  3052. #if !defined( NO_STEAM ) && !defined( NO_STEAM_GAMECOORDINATOR )
  3053. // try to make this a little more efficient
  3054. player_info_t pi;
  3055. if ( engine->GetPlayerInfo( entindex(), &pi ) )
  3056. {
  3057. * pID = CSteamID( pi.xuid );
  3058. if ( pID->GetEAccountType() == k_EAccountTypeIndividual )
  3059. {
  3060. pID->SetAccountInstance( 1 );
  3061. return true;
  3062. }
  3063. if ( pi.friendsID && steamapicontext && steamapicontext->SteamUtils() )
  3064. {
  3065. #if 1 // new
  3066. static EUniverse universe = k_EUniverseInvalid;
  3067. if ( universe == k_EUniverseInvalid )
  3068. universe = steamapicontext->SteamUtils()->GetConnectedUniverse();
  3069. pID->InstancedSet( pi.friendsID, 1, universe, k_EAccountTypeIndividual );
  3070. #else // old
  3071. pID->InstancedSet( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual );
  3072. #endif
  3073. return true;
  3074. }
  3075. }
  3076. #endif //!defined( NO_STEAM ) && !defined( NO_STEAM_GAMECOORDINATOR )
  3077. return false;
  3078. }
  3079. void C_BasePlayer::OnTimeJumpAllPlayers()
  3080. {
  3081. for ( int i = 1; i <= MAX_PLAYERS; i++ )
  3082. {
  3083. C_CSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
  3084. if ( pPlayer )
  3085. {
  3086. pPlayer->OnTimeJump();
  3087. }
  3088. }
  3089. }
  3090. void C_BasePlayer::OnTimeJump()
  3091. {
  3092. }
  3093. void CC_DumpClientSoundscapeData( const CCommand& args )
  3094. {
  3095. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  3096. if ( !pPlayer )
  3097. return;
  3098. Msg("Client Soundscape data dump:\n");
  3099. Msg(" Position: %.2f %.2f %.2f\n", pPlayer->GetAbsOrigin().x, pPlayer->GetAbsOrigin().y, pPlayer->GetAbsOrigin().z );
  3100. Msg(" soundscape index: %d\n", pPlayer->m_Local.m_audio.soundscapeIndex.Get() );
  3101. Msg(" entity index: %d\n", pPlayer->m_Local.m_audio.entIndex.Get() );
  3102. bool bFoundOne = false;
  3103. for ( int i = 0; i < NUM_AUDIO_LOCAL_SOUNDS; i++ )
  3104. {
  3105. if ( pPlayer->m_Local.m_audio.localBits & (1<<i) )
  3106. {
  3107. if ( !bFoundOne )
  3108. {
  3109. Msg(" Sound Positions:\n");
  3110. bFoundOne = true;
  3111. }
  3112. Vector vecPos = pPlayer->m_Local.m_audio.localSound[i];
  3113. Msg(" %d: %.2f %.2f %.2f\n", i, vecPos.x,vecPos.y, vecPos.z );
  3114. }
  3115. }
  3116. Msg("End dump.\n");
  3117. }
  3118. static ConCommand soundscape_dumpclient("soundscape_dumpclient", CC_DumpClientSoundscapeData, "Dumps the client's soundscape data.\n", FCVAR_CHEAT);