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.

8607 lines
268 KiB

  1. //===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "c_cs_player.h"
  8. #include "c_user_message_register.h"
  9. #include "view.h"
  10. #include "iclientvehicle.h"
  11. #include "ivieweffects.h"
  12. #include "input.h"
  13. #include "IEffects.h"
  14. #include "fx.h"
  15. #include "c_basetempentity.h"
  16. #include "hud_macros.h" //HOOK_COMMAND
  17. #include "engine/ivdebugoverlay.h"
  18. #include "smoke_fog_overlay.h"
  19. #include "bone_setup.h"
  20. #include "in_buttons.h"
  21. #include "r_efx.h"
  22. #include "dlight.h"
  23. #include "shake.h"
  24. #include "cl_animevent.h"
  25. #include "c_physicsprop.h"
  26. #include "props_shared.h"
  27. #include "obstacle_pushaway.h"
  28. #include "death_pose.h"
  29. #include "voice_status.h"
  30. #include "interpolatortypes.h"
  31. #include "smokegrenade_projectile.h"
  32. #include "effect_dispatch_data.h" //for water ripple / splash effect
  33. #include "c_te_effect_dispatch.h" //ditto
  34. #include "c_te_legacytempents.h"
  35. #include "cs_gamerules.h"
  36. #include "fx_cs_blood.h"
  37. #include "c_cs_playerresource.h"
  38. #include "c_team.h"
  39. #include "flashlighteffect.h"
  40. #include "c_cs_hostage.h"
  41. #include "prediction.h"
  42. #include "HUD/sfweaponselection.h"
  43. #include "HUD/sfhudreticle.h"
  44. #include "HUD/sfweaponselection.h"
  45. #include "ragdoll_shared.h"
  46. #include "collisionutils.h"
  47. #include "engineinterface.h"
  48. #include "econ_gcmessages.h"
  49. #include "cstrike15_item_system.h"
  50. #include "hltvcamera.h"
  51. #include "steam/steam_api.h"
  52. #include "vguicenterprint.h"
  53. #include "ixboxsystem.h"
  54. #include "xlast_csgo/csgo.spa.h"
  55. #include "weapon_basecsgrenade.h"
  56. #include <vgui/IInput.h>
  57. #include "vgui_controls/Controls.h"
  58. #include "cs_player_rank_mgr.h"
  59. #include "platforminputdevice.h"
  60. #include "cam_thirdperson.h"
  61. #include "inputsystem/iinputsystem.h"
  62. #include <localize/ilocalize.h>
  63. #include "interfaces/interfaces.h"
  64. #include "gametypes.h"
  65. #include "GameStats.h"
  66. #include "c_cs_team.h"
  67. #include "Scaleform/HUD/sfhudinfopanel.h"
  68. #include <engine/IEngineSound.h>
  69. #include "cs_shareddefs.h"
  70. #include "hltvreplaysystem.h"
  71. #include "cs_custom_material_swap.h"
  72. #include "materialsystem/icustommaterial.h"
  73. // Comment this back in if you want the cl_minmodels convar to operate as normal.
  74. #define CS_ALLOW_CL_MINMODELS 0
  75. #if defined( CCSPlayer )
  76. #undef CCSPlayer
  77. #endif
  78. #include "materialsystem/imesh.h" //for materials->FindMaterial
  79. #include "materialsystem/imaterialvar.h"
  80. #include "iviewrender.h" //for view->
  81. #include "view_shared.h" //for CViewSetup
  82. #include "iviewrender_beams.h" // flashlight beam
  83. #include "materialsystem/icustommaterialmanager.h"
  84. #include "materialsystem/icompositetexturegenerator.h"
  85. #include "cs_custom_clothing_visualsdata_processor.h"
  86. #include "cs_custom_epidermis_visualsdata_processor.h"
  87. #include "model_combiner.h"
  88. #include "physpropclientside.h" // for dropping physics mags
  89. #include "cstrike15_gcmessages.pb.h"
  90. #include "csgo_playeranimstate.h"
  91. #include "c_props.h"
  92. #include "model_types.h"
  93. // NOTE: This has to be the last file included!
  94. #include "tier0/memdbgon.h"
  95. static Vector WALL_MIN(-WALL_OFFSET,-WALL_OFFSET,-WALL_OFFSET );
  96. static Vector WALL_MAX(WALL_OFFSET,WALL_OFFSET,WALL_OFFSET );
  97. extern ConVar econ_use_cosmetics;
  98. extern ConVar spec_freeze_time;
  99. extern ConVar spec_freeze_traveltime;
  100. extern ConVar spec_freeze_traveltime_long;
  101. extern ConVar spec_freeze_distance_min;
  102. extern ConVar spec_freeze_distance_max;
  103. extern ConVar spec_freeze_target_fov;
  104. extern ConVar spec_freeze_target_fov_long;
  105. extern ConVar spec_freeze_deathanim_time;
  106. extern ConVar cl_clanid;
  107. extern ConVar mp_teammates_are_enemies;
  108. extern ConVar mp_use_respawn_waves;
  109. extern ConVar mp_respawn_on_death_ct;
  110. extern ConVar mp_respawn_on_death_t;
  111. extern ConVar sv_disable_immunity_alpha;
  112. extern ConVar cl_spec_use_tournament_content_standards;
  113. extern ConVar sv_spec_use_tournament_content_standards;
  114. ConVar cl_foot_contact_shadows( "cl_foot_contact_shadows", "1", FCVAR_CLIENTDLL | FCVAR_RELEASE, "" );
  115. ConVar spec_freeze_cinematiclight_r( "spec_freeze_cinematiclight_r", "1.5", FCVAR_CHEAT );
  116. ConVar spec_freeze_cinematiclight_g( "spec_freeze_cinematiclight_g", "1.2", FCVAR_CHEAT );
  117. ConVar spec_freeze_cinematiclight_b( "spec_freeze_cinematiclight_b", "1.0", FCVAR_CHEAT );
  118. ConVar spec_freeze_cinematiclight_scale( "spec_freeze_cinematiclight_scale", "2.0", FCVAR_CHEAT );
  119. ConVar spec_glow_silent_factor( "spec_glow_silent_factor", "0.6", FCVAR_CLIENTDLL | FCVAR_RELEASE, "Lurking player xray glow scaling.", true, 0.0f, true, 1.0f );
  120. ConVar spec_glow_spike_factor( "spec_glow_spike_factor", "1.2", FCVAR_CLIENTDLL | FCVAR_RELEASE, "Noisy player xray glow scaling (pop when noise is made). Make >1 to add a 'spike' to noise-making players", true, 1.0f, true, 3.0f );
  121. ConVar spec_glow_full_time( "spec_glow_full_time", "1.0", FCVAR_CLIENTDLL | FCVAR_RELEASE, "Noisy players stay at full brightness for this long.", true, 0.0f, false, 0.0f );
  122. ConVar spec_glow_decay_time( "spec_glow_decay_time", "2.0", FCVAR_CLIENTDLL | FCVAR_RELEASE, "Time to decay glow from 1.0 to spec_glow_silent_factor after spec_glow_full_time.", true, 0.0f, false, 0.0f );
  123. ConVar spec_glow_spike_time( "spec_glow_spike_time", "0.0", FCVAR_CLIENTDLL | FCVAR_RELEASE, "Time for noisy player glow 'spike' to show that they made noise very recently.", true, 0.0f, false, 0.0f );
  124. ConVar cl_crosshair_sniper_width( "cl_crosshair_sniper_width", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "If >1 sniper scope cross lines gain extra width (1 for single-pixel hairline)" );
  125. void BorrowMusicKitChangeCallback( IConVar *var, const char *pOldValue, float flOldValue )
  126. {
  127. }
  128. ConVar cl_borrow_music_from_player_index( "cl_borrow_music_from_player_index", "0", FCVAR_CLIENTDLL,
  129. "", false, false, false, false, BorrowMusicKitChangeCallback );
  130. static void Spec_Show_Xray_Callback( IConVar *pConVar, const char *pOldString, float flOldValue )
  131. {
  132. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  133. if ( pLocalPlayer )
  134. pLocalPlayer->UpdateGlowsForAllPlayers();
  135. }
  136. ConVar spec_show_xray("spec_show_xray", "0", FCVAR_ARCHIVE | FCVAR_RELEASE, "If set to 1, you can see player outlines and name IDs through walls - who you can see depends on your team and mode", Spec_Show_Xray_Callback );
  137. ConVar cl_ragdoll_physics_enable( "cl_ragdoll_physics_enable", "1", 0, "Enable/disable ragdoll physics." );
  138. ConVar cl_minmodels( "cl_minmodels", "0", 0, "Uses one player model for each team. Set this value to -1 to allow unapproved / in progress player models to be used." );
  139. ConVar cl_min_ct( "cl_min_ct", "1", 0, "Controls which CT model is used when cl_minmodels is set to 1." );
  140. ConVar cl_min_t( "cl_min_t", "1", 0, "Controls which Terrorist model is used when cl_minmodels is set to 1." );
  141. // [jason] Adjusts the safe extents of the camera placement for the freeze cam to prevent it from penetrating the killer's geometry
  142. ConVar cl_freeze_cam_penetration_tolerance( "cl_freeze_cam_penetration_tolerance", "0", 0, "If the freeze cam gets closer to target than this distance, we snap to death cam instead (0 = use character bounds instead, -1 = disable this safety check" );
  143. ConVar cl_ragdoll_crumple( "cl_ragdoll_crumple", "1" );
  144. ConVar cl_teamid_overhead( "cl_teamid_overhead", "1", FCVAR_CHEAT | FCVAR_SS, "Shows teamID over player's heads. 0 = off, 1 = on" );
  145. ConVar cl_teamid_overhead_maxdist( "cl_teamid_overhead_maxdist", "3000", FCVAR_CHEAT | FCVAR_SS, "max distance at which the overhead team id icons will show" );
  146. ConVar cl_teamid_overhead_maxdist_spec( "cl_teamid_overhead_maxdist_spec", "2000", FCVAR_CHEAT | FCVAR_SS, "max distance at which the overhead team id icons will show when a spectator" );
  147. ConVar cl_show_equipment_value( "cl_show_equipment_value", "0" );
  148. ConVar cl_show_clan_in_death_notice("cl_show_clan_in_death_notice", "1", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "Is set, the clan name will show next to player names in the death notices.");
  149. //ConVar cl_violent_ragdolls( "cl_violent_ragdolls", "1", FCVAR_RELEASE, "Allows ragdolls to bleed out and react to gun shots.");
  150. #define USE_VIOLENT_RAGDOLLS 0
  151. ConVar cl_dm_buyrandomweapons( "cl_dm_buyrandomweapons", "1", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "Player will automatically receive a random weapon on spawn in deathmatch if this is set to 1 (otherwise, they will receive the last weapon)" );
  152. ConVar cl_teammate_colors_show( "cl_teammate_colors_show", "1", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "In competitive, 1 = show teammates as separate colors in the radar, scoreboard, etc., 2 = show colors and letters" );
  153. ConVar cl_hud_playercount_pos( "cl_hud_playercount_pos", "0", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "0 = default (top), 1 = bottom" );
  154. ConVar cl_hud_playercount_showcount( "cl_hud_playercount_showcount", "0", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "0 = show player avatars (default), 1 = just show count number (no avatars)" );
  155. ConVar cl_hud_color( "cl_hud_color", "0", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "0 = default, 1 = light blue, 2 = orange, 3 = green, 4 = purple, 5 = white." );
  156. static void Hud_Radar_Scale_Callback( IConVar *pConVar, const char *pOldString, float flOldValue )
  157. {
  158. // refresh here
  159. ConVarRef m_hudscaling( "hud_scaling" );
  160. float flScale = m_hudscaling.GetFloat();
  161. m_hudscaling.SetValue( flScale + 1 );
  162. m_hudscaling.SetValue( flScale );
  163. }
  164. ConVar cl_hud_radar_scale( "cl_hud_radar_scale", "1", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "", true, 0.8, true, 1.3, Hud_Radar_Scale_Callback );
  165. ConVar cl_hud_bomb_under_radar( "cl_hud_bomb_under_radar", "1", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "" );
  166. ConVar cl_hud_background_alpha( "cl_hud_background_alpha", "0.5", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "", true, 0.0f, true, 1.0f );
  167. ConVar cl_hud_healthammo_style( "cl_hud_healthammo_style", "0", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "" );
  168. ConVar cl_spec_follow_grenade_key( "cl_spec_follow_grenade_key", "0", FCVAR_CLIENTDLL | FCVAR_RELEASE | FCVAR_ARCHIVE, "0 = LALT, 1 = LSHIFT, 2 = +reload" );
  169. ConVar cl_freezecameffects_showholiday( "cl_freezecameffects_showholiday", "0", FCVAR_CLIENTDLL | FCVAR_RELEASE, "Happy holidays from the CS:GO team and Valve!" );
  170. const float CycleLatchTolerance = 0.15; // amount we can diverge from the server's cycle before we're corrected
  171. extern ConVar mp_playerid_delay;
  172. extern ConVar mp_playerid_hold;
  173. ConVar cl_camera_height_restriction_debug( "cl_camera_height_restriction_debug", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "" );
  174. //ConVar *sv_cheats = NULL;
  175. ConVar fov_cs_debug( "fov_cs_debug", "0", FCVAR_REPLICATED | FCVAR_CHEAT, "Sets the view fov if cheats are on." );
  176. #define FREEZECAM_LONGCAM_DIST 320 // over this amount, the camera will zoom close on target
  177. #define sv_magazine_drop_physics 1
  178. #define sv_magazine_drop_time 15
  179. #define sv_magazine_drop_debug 0
  180. //ConVar sv_magazine_drop_physics( "sv_magazine_drop_physics", "1", FCVAR_REPLICATED | FCVAR_RELEASE, "Players drop physical weapon magazines when reloading." );
  181. //ConVar sv_magazine_drop_time( "sv_magazine_drop_time", "15", FCVAR_REPLICATED | FCVAR_RELEASE, "Duration physical magazines stay in the world.", true, 2.0f, true, 20.0f );
  182. //ConVar sv_magazine_drop_debug( "sv_magazine_drop_debug", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Show a debug marker at mag spawn position." );
  183. class CAddonInfo
  184. {
  185. public:
  186. const char *m_pAttachmentName;
  187. const char *m_pWeaponClassName; // The addon uses the w_ model from this weapon.
  188. const char *m_pModelName; //If this is present, will use this model instead of looking up the weapon
  189. const char *m_pHolsterName;
  190. };
  191. // These must follow the ADDON_ ordering.
  192. CAddonInfo g_AddonInfo[] =
  193. {
  194. { "grenade0", "weapon_flashbang", 0, 0 },
  195. { "grenade1", "weapon_flashbang", 0, 0 },
  196. { "grenade2", "weapon_hegrenade", 0, 0 },
  197. { "grenade3", "weapon_smokegrenade", 0, 0 },
  198. { "c4", "weapon_c4", 0, 0 },
  199. { "defusekit", 0, "models/weapons/w_defuser.mdl", 0 },
  200. { "primary", 0, 0, 0 }, // Primary addon model is looked up based on m_iPrimaryAddon
  201. { "pistol", 0, 0, 0 }, // Pistol addon model is looked up based on m_iSecondaryAddon
  202. { "eholster", 0, "models/weapons/w_eq_eholster_elite.mdl", "models/weapons/w_eq_eholster.mdl" },
  203. { "grenade4", "weapon_decoy", 0, 0 },
  204. { "knife", "weapon_knife", 0, 0 },
  205. { "facemask", 0, "models/player/holiday/facemasks/facemask_skull.mdl", 0 },
  206. { "grenade4", "weapon_tagrenade", 0, 0 },
  207. };
  208. CAddonInfo g_ClientSideAddons[] =
  209. {
  210. { "forward", 0, "models/player/holiday/santahat.mdl", 0 },
  211. { "forward", 0, "models/ghost/ghost.mdl", 0 },
  212. { "facemask", 0, "models/player/holiday/facemasks/facemask_battlemask.mdl", 0 },
  213. };
  214. #define SMOKEGRENADE_LIFETIME 17.5f
  215. CUtlVector<EHANDLE> g_SmokeGrenadeHandles;
  216. CUtlVector<clientSmokeGrenadeRecord_t> g_SmokeGrenades;
  217. void AddSmokeGrenade( Vector location, int iEntityId )
  218. {
  219. int nIndex = g_SmokeGrenades.AddToTail();
  220. g_SmokeGrenades[nIndex].m_flInceptionTime = gpGlobals->curtime;
  221. g_SmokeGrenades[nIndex].m_vecPosition = location;
  222. g_SmokeGrenades[nIndex].m_iEntityId = iEntityId;
  223. }
  224. void AddSmokeGrenadeHandle( EHANDLE hGrenade )
  225. {
  226. for ( int i = 0; i < g_SmokeGrenadeHandles.Count(); i++ )
  227. {
  228. if ( g_SmokeGrenadeHandles[i] && g_SmokeGrenadeHandles[i] == hGrenade )
  229. {
  230. return;
  231. }
  232. }
  233. g_SmokeGrenadeHandles.AddToTail( hGrenade );
  234. }
  235. void RemoveSmokeGrenade( Vector location, int iEntityId )
  236. {
  237. for ( int i = 0; i < g_SmokeGrenades.Count(); i++ )
  238. {
  239. if ( g_SmokeGrenades[i].m_iEntityId == iEntityId && g_SmokeGrenades[i].m_vecPosition.DistToSqr( location ) < 0.1f )
  240. {
  241. g_SmokeGrenades.FastRemove( i );
  242. break;
  243. }
  244. }
  245. }
  246. void RemoveSmokeGrenadeHandle( EHANDLE hGrenade )
  247. {
  248. for ( int i = 0; i < g_SmokeGrenadeHandles.Count(); i++ )
  249. {
  250. if ( g_SmokeGrenadeHandles[i] && g_SmokeGrenadeHandles[i] == hGrenade )
  251. {
  252. g_SmokeGrenadeHandles.FastRemove( i );
  253. break;
  254. }
  255. }
  256. }
  257. bool LineGoesThroughSmoke( Vector from, Vector to, bool grenadeBloat )
  258. {
  259. float totalSmokedLength = 0.0f; // distance along line of sight covered by smoke
  260. // compute unit vector and length of line of sight segment
  261. //Vector sightDir = to - from;
  262. //float sightLength = sightDir.NormalizeInPlace();
  263. const float smokeRadiusSq = SmokeGrenadeRadius * SmokeGrenadeRadius * grenadeBloat * grenadeBloat;
  264. for( int it=0; it < g_SmokeGrenadeHandles.Count(); it++ )
  265. {
  266. float flLengthAdd = 0;
  267. if ( CSGameRules() )
  268. {
  269. C_SmokeGrenadeProjectile *pGrenade = static_cast<C_SmokeGrenadeProjectile*>(g_SmokeGrenadeHandles[it].Get());
  270. if ( pGrenade && pGrenade->m_bDidSmokeEffect == true )
  271. {
  272. flLengthAdd = CSGameRules()->CheckTotalSmokedLength( smokeRadiusSq, pGrenade->GetAbsOrigin(), from, to );
  273. // get the totalSmokedLength and check to see if the line starts or stops in smoke. If it does this will return -1 and we should just bail early
  274. if ( flLengthAdd == -1 )
  275. return true;
  276. totalSmokedLength += flLengthAdd;
  277. }
  278. }
  279. }
  280. // define how much smoke a bot can see thru
  281. const float maxSmokedLength = 0.7f * SmokeGrenadeRadius;
  282. // return true if the total length of smoke-covered line-of-sight is too much
  283. return (totalSmokedLength > maxSmokedLength);
  284. }
  285. void RemoveAllSmokeGrenades( void )
  286. {
  287. g_SmokeGrenadeHandles.RemoveAll();
  288. }
  289. void TruncatePlayerName( wchar_t *pCleanedHTMLName, int destLen, int nTruncateAt, bool bSkipHTML )
  290. {
  291. // this code expects the input string to be clean HTML (call MakeStringSafe on it first)
  292. // This code is smart enough to find HTML style escapements in the strings.
  293. // anything between a & and a ; is treated as one character. &lt; for example.
  294. int charsLeft = nTruncateAt+1;
  295. int bufferPosition = 0;
  296. bool done = false;
  297. bool insideEscapement = false;
  298. while( !done )
  299. {
  300. if ( pCleanedHTMLName[bufferPosition] == 0 || charsLeft == 0 )
  301. {
  302. done = true;
  303. }
  304. else
  305. {
  306. if ( !bSkipHTML )
  307. {
  308. if ( insideEscapement )
  309. {
  310. if ( pCleanedHTMLName[bufferPosition] == L';' )
  311. {
  312. insideEscapement = false;
  313. charsLeft--;
  314. }
  315. }
  316. else if ( pCleanedHTMLName[bufferPosition] == L'&' )
  317. {
  318. insideEscapement = true;
  319. }
  320. else
  321. {
  322. charsLeft--;
  323. }
  324. }
  325. bufferPosition++;
  326. }
  327. }
  328. if ( charsLeft == 0 )
  329. {
  330. if ( ( bufferPosition + 4 ) < destLen )
  331. {
  332. V_wcsncpy( pCleanedHTMLName + bufferPosition, L"...", 4 * sizeof( wchar_t ) );
  333. }
  334. else
  335. {
  336. AssertMsg( false, "Destination buffer of insufficient size." );
  337. }
  338. }
  339. }
  340. #if CS_ALLOW_CL_MINMODELS
  341. // Return the first class id that has a legitimate model based on cl_minmodels.
  342. static int FilterModelUsingCL_MinModels( int iClass )
  343. {
  344. AssertMsg(false, "This needs to be updated to use the PlayerModelInfo class" );
  345. return 0;
  346. /*
  347. int rModel = 0;
  348. int team = GetTeamFromClass( iClass );
  349. if ( cl_minmodels.GetInt() == 1 )
  350. {
  351. if ( team == TEAM_TERRORIST )
  352. {
  353. int index = cl_min_t.GetInt() - 1;
  354. if ( index < 0 || index >= TerroristPlayerModels.Count() )
  355. {
  356. index = 0;
  357. }
  358. rModel = modelinfo->GetModelIndex(TerroristPlayerModels[index] );
  359. }
  360. else
  361. {
  362. int index = cl_min_ct.GetInt() - 1;
  363. if ( index < 0 || index >= CTPlayerModels.Count() )
  364. {
  365. index = 0;
  366. }
  367. rModel = modelinfo->GetModelIndex( CTPlayerModels[index] );
  368. }
  369. }
  370. else if ( cl_minmodels.GetInt() == 0 && !s_approvedModels[iClass] )
  371. {
  372. // Only pull players from the approved list.
  373. if ( team == TEAM_TERRORIST )
  374. {
  375. // Pick the defalut T model.
  376. int bestClass = FindFirstUsableModel( FIRST_T_CLASS, LAST_T_CLASS+1, CS_CLASS_PROFESSIONAL_MALE );
  377. rModel = modelinfo->GetModelIndex( TerroristPlayerModels[ bestClass - FIRST_T_CLASS ] );
  378. }
  379. else
  380. {
  381. // Pick the defalut CT model.
  382. int bestClass = FindFirstUsableModel( FIRST_CT_CLASS, LAST_CT_CLASS+1, CS_CLASS_ST6_MALE );
  383. rModel = modelinfo->GetModelIndex( CTPlayerModels[ bestClass - FIRST_CT_CLASS ] );
  384. }
  385. }
  386. else
  387. {
  388. // Make sure we restore the proper model based on class.
  389. if ( team == TEAM_TERRORIST )
  390. {
  391. rModel = modelinfo->GetModelIndex( TerroristPlayerModels[ iClass - FIRST_T_CLASS ] );
  392. }
  393. else
  394. {
  395. rModel = modelinfo->GetModelIndex( CTPlayerModels[ iClass - FIRST_CT_CLASS ] );
  396. }
  397. }
  398. return rModel;
  399. */
  400. }
  401. #endif // CS_ALLOW_CL_MINMODELS
  402. // -------------------------------------------------------------------------------- //
  403. // Player animation event. Sent to the client when a player fires, jumps, reloads, etc..
  404. // -------------------------------------------------------------------------------- //
  405. class C_TEPlayerAnimEvent : public C_BaseTempEntity
  406. {
  407. public:
  408. DECLARE_CLASS( C_TEPlayerAnimEvent, C_BaseTempEntity );
  409. DECLARE_CLIENTCLASS();
  410. virtual void PostDataUpdate( DataUpdateType_t updateType )
  411. {
  412. // Create the effect.
  413. C_CSPlayer *pPlayer = ToCSPlayer( m_hPlayer.Get() );
  414. if ( pPlayer && !pPlayer->IsDormant() )
  415. {
  416. pPlayer->DoAnimationEvent( (PlayerAnimEvent_t )m_iEvent.Get(), m_nData );
  417. }
  418. }
  419. public:
  420. CNetworkHandle( CBasePlayer, m_hPlayer );
  421. CNetworkVar( int, m_iEvent );
  422. CNetworkVar( int, m_nData );
  423. };
  424. IMPLEMENT_CLIENTCLASS_EVENT( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent, CTEPlayerAnimEvent );
  425. BEGIN_RECV_TABLE_NOBASE( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent )
  426. RecvPropEHandle( RECVINFO( m_hPlayer ) ),
  427. RecvPropInt( RECVINFO( m_iEvent ) ),
  428. RecvPropInt( RECVINFO( m_nData ) )
  429. END_RECV_TABLE()
  430. BEGIN_PREDICTION_DATA( C_CSPlayer )
  431. #ifdef CS_SHIELD_ENABLED
  432. DEFINE_PRED_FIELD( m_bShieldDrawn, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  433. #endif
  434. DEFINE_PRED_FIELD_TOL( m_flStamina, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.1f ),
  435. DEFINE_PRED_FIELD( m_flCycle, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_PRIVATE | FTYPEDESC_NOERRORCHECK ),
  436. DEFINE_PRED_FIELD( m_iShotsFired, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  437. DEFINE_PRED_FIELD( m_iDirection, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  438. DEFINE_PRED_FIELD( m_bIsScoped, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  439. DEFINE_PRED_FIELD( m_bIsWalking, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  440. DEFINE_PRED_FIELD( m_bResumeZoom, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  441. DEFINE_PRED_FIELD( m_nNumFastDucks, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  442. DEFINE_PRED_FIELD( m_bDuckOverride, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  443. END_PREDICTION_DATA()
  444. vgui::IImage* GetDefaultAvatarImage( C_BasePlayer *pPlayer )
  445. {
  446. vgui::IImage* result = NULL;
  447. switch ( pPlayer ? pPlayer->GetTeamNumber() : TEAM_MAXCOUNT )
  448. {
  449. case TEAM_TERRORIST:
  450. result = vgui::scheme()->GetImage( CSTRIKE_DEFAULT_T_AVATAR, true );
  451. break;
  452. case TEAM_CT:
  453. result = vgui::scheme()->GetImage( CSTRIKE_DEFAULT_CT_AVATAR, true );
  454. break;
  455. default:
  456. result = vgui::scheme()->GetImage( CSTRIKE_DEFAULT_AVATAR, true );
  457. break;
  458. }
  459. return result;
  460. }
  461. // ----------------------------------------------------------------------------- //
  462. // Client ragdoll entity.
  463. // ----------------------------------------------------------------------------- //
  464. float g_flDieTranslucentTime = 0.6;
  465. IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_CSRagdoll, DT_CSRagdoll, CCSRagdoll )
  466. RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ),
  467. RecvPropVector( RECVINFO(m_vecRagdollOrigin ) ),
  468. RecvPropEHandle( RECVINFO( m_hPlayer ) ),
  469. RecvPropInt( RECVINFO( m_nModelIndex ) ),
  470. RecvPropInt( RECVINFO(m_nForceBone ) ),
  471. RecvPropVector( RECVINFO(m_vecForce ) ),
  472. RecvPropVector( RECVINFO( m_vecRagdollVelocity ) ),
  473. RecvPropInt( RECVINFO(m_iDeathPose ) ),
  474. RecvPropInt( RECVINFO(m_iDeathFrame ) ),
  475. RecvPropInt(RECVINFO(m_iTeamNum )),
  476. RecvPropInt( RECVINFO(m_bClientSideAnimation )),
  477. RecvPropFloat( RECVINFO(m_flDeathYaw) ),
  478. RecvPropFloat( RECVINFO(m_flAbsYaw) ),
  479. END_RECV_TABLE()
  480. C_CSRagdoll::C_CSRagdoll():
  481. m_nGlowObjectHandle(-1)
  482. {
  483. m_bInitialized = false;
  484. }
  485. C_CSRagdoll::~C_CSRagdoll()
  486. {
  487. DestroyGlowObject();
  488. PhysCleanupFrictionSounds( this );
  489. SetRagdollClientSideAddon( 0 );
  490. DestroyAttachedWearableGibs();
  491. }
  492. void C_CSRagdoll::DestroyGlowObject()
  493. {
  494. if ( m_nGlowObjectHandle >= 0 )
  495. {
  496. GlowObjectManager().UnregisterGlowObject( m_nGlowObjectHandle );
  497. m_nGlowObjectHandle = -1;
  498. }
  499. }
  500. void C_CSRagdoll::AttachWearableGibsFromPlayer( C_CSPlayer *pParentPlayer )
  501. {
  502. /* Removed for partner depot */
  503. }
  504. void C_CSRagdoll::DestroyAttachedWearableGibs( void )
  505. {
  506. /* Removed for partner depot */
  507. }
  508. void C_CSRagdoll::GetRagdollInitBoneArrays( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt )
  509. {
  510. // otherwise use the death pose to set up the ragdoll
  511. ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt );
  512. GetRagdollCurSequenceWithDeathPose( this, pDeltaBones1, gpGlobals->curtime, m_iDeathPose, m_iDeathFrame );
  513. SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  514. }
  515. void C_CSRagdoll::GetRagdollInitBoneArraysYawMode( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt )
  516. {
  517. // turn off interp so we can setup bones in multiple positions
  518. SetEffects( EF_NOINTERP );
  519. // populate bone arrays for current positions and starting velocity positions
  520. InvalidateBoneCache();
  521. SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  522. Plat_FastMemcpy( pDeltaBones0, pCurrentBones, sizeof( matrix3x4a_t ) * MAXSTUDIOBONES );
  523. // set death anim
  524. CBaseAnimatingOverlay *pRagdollOverlay = GetBaseAnimatingOverlay();
  525. int n = pRagdollOverlay->GetNumAnimOverlays();
  526. if ( n > 0 )
  527. {
  528. CAnimationLayer *pLastRagdollLayer = pRagdollOverlay->GetAnimOverlay(n-1);
  529. if ( pLastRagdollLayer )
  530. {
  531. pLastRagdollLayer->SetSequence( m_iDeathPose );
  532. pLastRagdollLayer->SetWeight( 1 );
  533. }
  534. }
  535. SetPoseParameter( LookupPoseParameter( "death_yaw" ), m_flDeathYaw );
  536. SetAbsOrigin( GetAbsOrigin() );
  537. // set up bones in velocity adding positions
  538. InvalidateBoneCache();
  539. SetupBones( pDeltaBones1, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  540. //fallback
  541. Vector vecRagdollVelocityPush = m_vecRagdollVelocity;
  542. C_CSPlayer *pPlayer = dynamic_cast< C_CSPlayer* >( m_hPlayer.Get() );
  543. if ( pPlayer )
  544. {
  545. vecRagdollVelocityPush = pPlayer->m_vecLastAliveLocalVelocity * boneDt;
  546. }
  547. if ( vecRagdollVelocityPush.Length() > CS_PLAYER_SPEED_RUN * 3 )
  548. vecRagdollVelocityPush = vecRagdollVelocityPush.Normalized() * CS_PLAYER_SPEED_RUN * 3;
  549. // apply global extra velocity manually instead of relying on prediction to do it. This means all bones get the same vel...
  550. for ( int i=0; i<MAXSTUDIOBONES; i++ )
  551. {
  552. pDeltaBones1[i].SetOrigin( pDeltaBones0[i].GetOrigin() + vecRagdollVelocityPush );
  553. //debugoverlay->AddBoxOverlay( pCurrentBones[i].GetOrigin(), -Vector(0.1, 0.1, 0.1), Vector(0.1, 0.1, 0.1), QAngle(0,0,0), 255,0,0,255, 5 );
  554. ////debugoverlay->AddBoxOverlay( pDeltaBones1[i].GetOrigin(), -Vector(0.1, 0.1, 0.1), Vector(0.1, 0.1, 0.1), QAngle(0,0,0), 0,255,0,255, 5 );
  555. ////debugoverlay->AddBoxOverlay( pDeltaBones0[i].GetOrigin(), -Vector(0.1, 0.1, 0.1), Vector(0.1, 0.1, 0.1), QAngle(0,0,0), 0,0,255,255, 5 );
  556. //debugoverlay->AddLineOverlay( pDeltaBones0[i].GetOrigin(), pDeltaBones1[i].GetOrigin(), 255,0,0, true, 5 );
  557. }
  558. }
  559. void C_CSRagdoll::Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity )
  560. {
  561. if ( !pSourceEntity )
  562. return;
  563. VarMapping_t *pSrc = pSourceEntity->GetVarMapping();
  564. VarMapping_t *pDest = GetVarMapping();
  565. // Find all the VarMapEntry_t's that represent the same variable.
  566. for ( int i = 0; i < pDest->m_Entries.Count(); i++ )
  567. {
  568. VarMapEntry_t *pDestEntry = &pDest->m_Entries[i];
  569. for ( int j=0; j < pSrc->m_Entries.Count(); j++ )
  570. {
  571. VarMapEntry_t *pSrcEntry = &pSrc->m_Entries[j];
  572. if ( !Q_strcmp( pSrcEntry->watcher->GetDebugName(),
  573. pDestEntry->watcher->GetDebugName() ) )
  574. {
  575. pDestEntry->watcher->Copy( pSrcEntry->watcher );
  576. break;
  577. }
  578. }
  579. }
  580. }
  581. void C_CSRagdoll::ApplySemiRandomDirectionalForce( Vector vecDir, float flStrength )
  582. {
  583. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  584. if( !pPhysicsObject )
  585. return;
  586. IRagdoll *pIRagdoll = GetIRagdoll();
  587. if ( pIRagdoll )
  588. {
  589. for ( int i=0; i<24; i++ )
  590. {
  591. IPhysicsObject *pPhysObj = pIRagdoll->GetElement( i );
  592. if ( pPhysObj != NULL )
  593. {
  594. pPhysObj->ApplyForceCenter( vecDir * flStrength );
  595. }
  596. }
  597. }
  598. m_pRagdoll->ResetRagdollSleepAfterTime();
  599. }
  600. ConVar cl_random_taser_bone_y( "cl_random_taser_bone_y", "-1.0", 0, "The Y position used for the random taser force." );
  601. ConVar cl_random_taser_force_y( "cl_random_taser_force_y", "-1.0", 0, "The Y position used for the random taser force." );
  602. ConVar cl_random_taser_power( "cl_random_taser_power", "4000.0", 0, "Power used when applying the taser effect." );
  603. void C_CSRagdoll::ApplyRandomTaserForce( void )
  604. {
  605. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  606. if( !pPhysicsObject )
  607. return;
  608. int boneID = LookupBone( RandomInt( 0, 1 ) ? "ValveBiped.Bip01_L_Hand" : "ValveBiped.Bip01_R_Hand" );
  609. if( boneID < 0 )
  610. {
  611. // error, couldn't find a bone matching this name, early out
  612. AssertMsg( false, "couldn't find a bone matching this name, early out" );
  613. return;
  614. }
  615. Vector bonePos;
  616. QAngle boneAngle;
  617. GetBonePosition( boneID, bonePos, boneAngle );
  618. bonePos.y += cl_random_taser_bone_y.GetFloat();
  619. Vector dir( random->RandomFloat( -1.0f, 1.0f ), random->RandomFloat( -1.0f, 1.0f ), cl_random_taser_force_y.GetFloat() );
  620. VectorNormalize( dir );
  621. dir *= cl_random_taser_power.GetFloat(); // adjust strength
  622. // apply force where we hit it
  623. pPhysicsObject->ApplyForceOffset( dir, bonePos );
  624. // make sure the ragdoll is "awake" to process our updates, at least for a bit
  625. m_pRagdoll->ResetRagdollSleepAfterTime();
  626. }
  627. void C_CSRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName )
  628. {
  629. #if USE_VIOLENT_RAGDOLLS
  630. static const float RAGDOLL_IMPACT_MAGNITUDE = 8000.0f;
  631. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  632. if( !pPhysicsObject )
  633. return;
  634. Vector dir = pTrace->endpos - pTrace->startpos;
  635. if ( iDamageType == DMG_BLAST )
  636. {
  637. VectorNormalize( dir );
  638. dir *= RAGDOLL_IMPACT_MAGNITUDE; // adjust impact strenght
  639. // apply force at object mass center
  640. pPhysicsObject->ApplyForceCenter( dir );
  641. }
  642. else
  643. {
  644. Vector hitpos;
  645. VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos );
  646. VectorNormalize( dir );
  647. // apply force where we hit it (shock/taser is handled with a special death type )
  648. if ( (iDamageType & DMG_SHOCK ) == 0 )
  649. {
  650. // Blood spray!
  651. float flDamage = 10.0f;
  652. // This does smaller splotches on the guy and splats blood on the world.
  653. TraceBleed( flDamage, dir, pTrace, iDamageType );
  654. FX_CS_BloodSpray( hitpos, dir, flDamage );
  655. dir *= RAGDOLL_IMPACT_MAGNITUDE; // adjust impact strenght
  656. pPhysicsObject->ApplyForceOffset( dir, hitpos );
  657. }
  658. }
  659. m_pRagdoll->ResetRagdollSleepAfterTime();
  660. #endif //USE_VIOLENT_RAGDOLLS
  661. }
  662. void C_CSRagdoll::ValidateModelIndex( void )
  663. {
  664. #if CS_ALLOW_CL_MINMODELS
  665. C_CSPlayer *pPlayer = dynamic_cast< C_CSPlayer* >( m_hPlayer.Get() );
  666. if ( pPlayer )
  667. {
  668. int iClass = pPlayer->PlayerClass();
  669. m_nModelIndex = FilterModelUsingCL_MinModels(iClass );
  670. }
  671. #endif
  672. BaseClass::ValidateModelIndex();
  673. }
  674. void C_CSRagdoll::CreateLowViolenceRagdoll( void )
  675. {
  676. // Just play a death animation.
  677. // Find a death anim to play.
  678. int iMinDeathAnim = 9999, iMaxDeathAnim = -9999;
  679. for ( int iAnim=1; iAnim < 100; iAnim++ )
  680. {
  681. char str[512];
  682. Q_snprintf( str, sizeof( str ), "death%d", iAnim );
  683. if ( LookupSequence( str ) == -1 )
  684. break;
  685. iMinDeathAnim = MIN( iMinDeathAnim, iAnim );
  686. iMaxDeathAnim = MAX( iMaxDeathAnim, iAnim );
  687. }
  688. if ( iMinDeathAnim == 9999 )
  689. {
  690. CreateCSRagdoll();
  691. return;
  692. }
  693. SetNetworkOrigin( m_vecRagdollOrigin );
  694. SetAbsOrigin( m_vecRagdollOrigin );
  695. SetAbsVelocity( m_vecRagdollVelocity );
  696. C_CSPlayer *pPlayer = dynamic_cast< C_CSPlayer* >( m_hPlayer.Get() );
  697. if ( pPlayer )
  698. {
  699. if ( !pPlayer->IsDormant() && !pPlayer->m_bUseNewAnimstate )
  700. {
  701. // move my current model instance to the ragdoll's so decals are preserved.
  702. pPlayer->SnatchModelInstance( this );
  703. // copy bodygroup state
  704. SetBody( pPlayer->GetBody() );
  705. }
  706. SetAbsAngles( pPlayer->GetRenderAngles() );
  707. SetNetworkAngles( pPlayer->GetRenderAngles() );
  708. if ( pPlayer->m_bUseNewAnimstate )
  709. AttachWearableGibsFromPlayer( pPlayer );
  710. //pPlayer->CreateBoneAttachmentsFromWearables( this );
  711. pPlayer->MoveBoneAttachments( this );
  712. }
  713. int iDeathAnim = RandomInt( iMinDeathAnim, iMaxDeathAnim );
  714. char str[512];
  715. Q_snprintf( str, sizeof( str ), "death%d", iDeathAnim );
  716. SetSequence( LookupSequence( str ) );
  717. ForceClientSideAnimationOn();
  718. Interp_Reset( GetVarMapping() );
  719. }
  720. ConVar cl_ragdoll_workaround_threshold( "cl_ragdoll_workaround_threshold", "4", FCVAR_RELEASE, "Mainly cosmetic, client-only effect: when client doesn't know the last position of another player that spawns a ragdoll, the ragdoll creation is simplified and ragdoll is created in the right place. If you increase this significantly, ragdoll positions on your client may be dramatically wrong, but it won't affect other clients" );
  721. ConVar spec_replay_outline( "spec_replay_outline", "1", FCVAR_CLIENTDLL, "Enable outline selecting victim in hltv replay: 0 - none; 1 - ouline YOU; 2 - outline YOU, with red ragdoll outline; 3 - normal spectator outlines" );
  722. void C_CSPlayer::SetSequence( int nSequence )
  723. {
  724. if ( m_bUseNewAnimstate && m_PlayerAnimStateCSGO )
  725. {
  726. AssertMsg( nSequence == 0, "Warning: Player attempted to set non-zero default sequence.\n" );
  727. BaseClass::SetSequence( 0 );
  728. }
  729. else
  730. {
  731. BaseClass::SetSequence( nSequence );
  732. }
  733. }
  734. void C_CSRagdoll::CreateCSRagdoll()
  735. {
  736. // First, initialize all our data. If we have the player's entity on our client,
  737. // then we can make ourselves start out exactly where the player is.
  738. C_CSPlayer *pPlayer = dynamic_cast< C_CSPlayer* >( m_hPlayer.Get() );
  739. // DevMsg( "Ragdoll %d player %d (s:%d) %s\n", entindex(), m_hPlayer.GetEntryIndex(), m_hPlayer.GetSerialNumber(), pPlayer ? " ok" : " unresolved" ); // replay
  740. ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( pPlayer );
  741. // mark this to prevent model changes from overwriting the death sequence with the server sequence
  742. SetReceivedSequence();
  743. // if we're playing a replay, only add a glow to ourselves
  744. DestroyGlowObject();
  745. if ( g_HltvReplaySystem.GetHltvReplayDelay() && pPlayer && engine && spec_replay_outline.GetInt() )
  746. {
  747. if ( pPlayer->entindex() == g_HltvReplaySystem.GetPrimaryVictimEntIndex() )
  748. {
  749. float gb = ( spec_replay_outline.GetInt() == 2 ) ? 0.375f : 1.0f;
  750. m_nGlowObjectHandle = GlowObjectManager().RegisterGlowObject( this, Vector( 1, gb, gb ), 0.8f, true, false, GLOW_FOR_ALL_SPLIT_SCREEN_SLOTS );
  751. SetRenderColor( 255, 0, 0 );
  752. }
  753. }
  754. if ( pPlayer && !pPlayer->IsDormant() )
  755. {
  756. // move my current model instance to the ragdoll's so decals are preserved.
  757. pPlayer->SnatchModelInstance(this);
  758. // copy bodygroup state
  759. SetBody( pPlayer->GetBody() );
  760. VarMapping_t *varMap = GetVarMapping();
  761. // Copy all the interpolated vars from the player entity.
  762. // The entity uses the interpolated history to get bone velocity.
  763. bool bRemotePlayer = (pPlayer != C_BasePlayer::GetLocalPlayer() );
  764. if ( bRemotePlayer )
  765. {
  766. Interp_Copy( pPlayer );
  767. SetAbsAngles( QAngle( 0, m_flAbsYaw, 0 ) );
  768. GetRotationInterpolator().Reset( gpGlobals->curtime );
  769. m_flAnimTime = pPlayer->m_flAnimTime;
  770. SetSequence( pPlayer->GetSequence() );
  771. }
  772. else
  773. {
  774. // This is the local player, so set them in a default
  775. // pose and slam their velocity, angles and origin
  776. SetAbsOrigin( m_vecRagdollOrigin );
  777. SetAbsAngles( QAngle( 0, m_flAbsYaw, 0 ) );
  778. SetAbsVelocity( m_vecRagdollVelocity );
  779. }
  780. // in addition to base cycle, duplicate overlay layers and pose params onto the ragdoll,
  781. // so the starting pose is as accurate as possible.
  782. SetCycle( pPlayer->GetCycle() );
  783. for ( int i=0; i<MAXSTUDIOPOSEPARAM; i++ )
  784. {
  785. //Msg( "Setting pose param %i to %.2f\n", i, pPlayer->GetPoseParameter( i ) );
  786. SetPoseParameter( i, pPlayer->GetPoseParameter( i ) );
  787. }
  788. CBaseAnimatingOverlay *pPlayerOverlay = pPlayer->GetBaseAnimatingOverlay();
  789. CBaseAnimatingOverlay *pRagdollOverlay = GetBaseAnimatingOverlay();
  790. if ( pPlayerOverlay )
  791. {
  792. int layerCount = pPlayerOverlay->GetNumAnimOverlays();
  793. pRagdollOverlay->SetNumAnimOverlays(layerCount);
  794. for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex )
  795. {
  796. CAnimationLayer *playerLayer = pPlayerOverlay->GetAnimOverlay(layerIndex);
  797. CAnimationLayer *ragdollLayer = pRagdollOverlay->GetAnimOverlay(layerIndex);
  798. if( playerLayer && ragdollLayer )
  799. {
  800. ragdollLayer->SetCycle( playerLayer->GetCycle() );
  801. ragdollLayer->SetOrder( playerLayer->GetOrder() );
  802. ragdollLayer->SetSequence( playerLayer->GetSequence() );
  803. ragdollLayer->SetWeight( playerLayer->GetWeight() );
  804. }
  805. }
  806. }
  807. m_flPlaybackRate = pPlayer->GetPlaybackRate();
  808. if ( !bRemotePlayer )
  809. {
  810. Interp_Reset( varMap );
  811. }
  812. CopySequenceTransitions( pPlayer );
  813. if ( pPlayer->m_bUseNewAnimstate )
  814. AttachWearableGibsFromPlayer( pPlayer );
  815. //pPlayer->CreateBoneAttachmentsFromWearables( this );
  816. pPlayer->MoveBoneAttachments( this );
  817. }
  818. else
  819. {
  820. // overwrite network origin so later interpolation will
  821. // use this position
  822. SetNetworkOrigin( m_vecRagdollOrigin );
  823. SetAbsOrigin( m_vecRagdollOrigin );
  824. SetAbsVelocity( m_vecRagdollVelocity );
  825. Interp_Reset( GetVarMapping() );
  826. }
  827. bool bDissolveEntity = true;
  828. // Turn it into a ragdoll.
  829. if ( cl_ragdoll_physics_enable.GetInt() )
  830. {
  831. bool bRemoveCachedBonesAfterUse = g_HltvReplaySystem.GetHltvReplayDelay() == 0; // when we are not replaying, just reuse the bone cache once
  832. CachedRagdollBones_t *pCachedRagdoll = g_HltvReplaySystem.GetCachedRagdollBones( entindex(), bRemoveCachedBonesAfterUse );
  833. if ( pPlayer )
  834. {
  835. bDissolveEntity = false;
  836. // Make us a ragdoll..
  837. m_bClientSideRagdoll = true;
  838. Vector vRagdollOrigin = GetAbsOrigin(), vPlayerOrigin = pPlayer->GetAbsOrigin();
  839. matrix3x4a_t currentBones[ MAXSTUDIOBONES ];
  840. const float boneDt = 0.05f;
  841. bool bleedOut = false;
  842. #if USE_VIOLENT_RAGDOLLS
  843. bleedOut = ( pPlayer ? !pPlayer->m_bKilledByTaser : true );
  844. #endif
  845. if ( pCachedRagdoll && pCachedRagdoll->nBones == GetModelPtr()->numbones() )
  846. {
  847. const matrix3x4a_t *pCachedBones = pCachedRagdoll->GetBones();
  848. //DevMsg( "Reusing bones of ragdoll %d\n", entindex() );
  849. InitAsClientRagdoll( pCachedBones, pCachedBones, pCachedBones, boneDt, bleedOut );
  850. if ( m_pRagdoll )
  851. {
  852. if ( m_pRagdoll->RagdollBoneCount() == pCachedRagdoll->nBodyParts )
  853. {
  854. matrix3x4a_t *pCachedTransforms = pCachedRagdoll->GetBodyParts();
  855. for ( int i = 0; i < pCachedRagdoll->nBodyParts; ++i )
  856. {
  857. IPhysicsObject *pObj = m_pRagdoll->RagdollPhysicsObject( i );
  858. const matrix3x4a_t &cachedMatrix = pCachedTransforms[ i ];
  859. pObj->SetPositionMatrix( cachedMatrix, true );
  860. }
  861. }
  862. if ( pCachedRagdoll->bAllAsleep )
  863. m_pRagdoll->PhysForceRagdollToSleep();
  864. }
  865. }
  866. else if ( ( vRagdollOrigin - vPlayerOrigin ).LengthSqr() > Sqr( cl_ragdoll_workaround_threshold.GetFloat() ) ) // ragdoll origin is set from the player's origin on server. If they aren't the same, it means we haven't seen the player in a while.
  867. {
  868. // The player isn't even visible right now, so we don't need to run the complicated and hacky logic to make ragdoll transition seamless. That logic would teleport the ragdoll to the last known position of the now-dormant player
  869. SetupBones( currentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  870. // Plat_FastMemcpy( boneDelta0, m_CachedBoneData.Base(), sizeof( matrix3x4a_t ) * m_CachedBoneData.Count() );
  871. InitAsClientRagdoll( currentBones, currentBones, currentBones, boneDt, bleedOut );
  872. }
  873. else
  874. {
  875. matrix3x4a_t boneDelta0[ MAXSTUDIOBONES ];
  876. matrix3x4a_t boneDelta1[ MAXSTUDIOBONES ];
  877. // use death pose and death frame differently for new animstate player
  878. if ( pPlayer->m_bUseNewAnimstate )
  879. {
  880. GetRagdollInitBoneArraysYawMode( boneDelta0, boneDelta1, currentBones, boneDt );
  881. }
  882. else
  883. {
  884. // We used to get these values from the local player object when he ragdolled, but he was some bad values when using prediction.
  885. // It ends up that just getting the bone array values for this ragdoll works best for both the local and remote players.
  886. ConVarRef cl_ragdoll_crumple( "cl_ragdoll_crumple" );
  887. if ( cl_ragdoll_crumple.GetBool() )
  888. {
  889. BaseClass::GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
  890. }
  891. else
  892. {
  893. GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
  894. }
  895. }
  896. //Vector vResultOrigin = GetAbsOrigin();
  897. //Msg( "C_CSRagdoll::CreateCSRagdoll at {%.1f,%.1f,%.1f}, player at {%.1f,%.1f,%.1f}, spawning at {%.1f,%.1f,%.1f}\n", vRagdollOrigin.x, vRagdollOrigin.y, vRagdollOrigin.z, vPlayerOrigin.x, vPlayerOrigin.y, vPlayerOrigin.z, vResultOrigin.x, vResultOrigin.y, vResultOrigin.z );
  898. InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt, bleedOut );
  899. }
  900. }
  901. else if ( pCachedRagdoll )
  902. {
  903. // there's no player entity anymore, but we're in replay or just after replay - and we have enough information to recreate this ragdoll, cached off
  904. bDissolveEntity = false;
  905. // Make us a ragdoll..
  906. m_bClientSideRagdoll = true;
  907. const matrix3x4a_t *pCachedBones = pCachedRagdoll->GetBones();
  908. InitAsClientRagdoll( pCachedBones, pCachedBones, pCachedBones, 0.05f, false ); // here, we can recreate the ragdoll... but we lost our wearables :(
  909. if ( m_pRagdoll && pCachedRagdoll->bAllAsleep )
  910. m_pRagdoll->PhysForceRagdollToSleep();
  911. }
  912. if ( bRemoveCachedBonesAfterUse )
  913. g_HltvReplaySystem.FreeCachedRagdollBones( pCachedRagdoll );
  914. }
  915. if ( bDissolveEntity )
  916. {
  917. SetRenderMode( kRenderTransTexture );
  918. SetRenderFX( kRenderFxFadeOut, gpGlobals->curtime, g_flDieTranslucentTime );
  919. }
  920. m_bInitialized = true;
  921. }
  922. void C_CSRagdoll::SetRagdollClientSideAddon( uint32 uiAddonMask )
  923. {
  924. /* Removed for partner depot */
  925. if ( ( uiAddonMask & ADDON_CLIENTSIDE_ASSASSINATION_TARGET ) && !m_hAssassinationTargetAddon.Get() )
  926. {
  927. C_BreakableProp *pEnt = new C_BreakableProp;
  928. pEnt->InitializeAsClientEntity( g_ClientSideAddons[ 2 ].m_pModelName, false );
  929. C_CSPlayer *pPlayer = dynamic_cast< C_CSPlayer* >( m_hPlayer.Get() );
  930. if ( pPlayer )
  931. {
  932. // Create the mask
  933. int nAttachIndex = LookupAttachment( "facemask" );
  934. pEnt->SetParent( this, nAttachIndex );
  935. pEnt->SetLocalOrigin( Vector( 0, 0, 0 ) );
  936. pEnt->SetLocalAngles( QAngle( 0, 0, 0 ) );
  937. pEnt->SetUseParentLightingOrigin( true );
  938. pEnt->SetSolid( SOLID_NONE );
  939. pEnt->RemoveEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
  940. m_hAssassinationTargetAddon.Set( pEnt );
  941. }
  942. }
  943. if ( !( uiAddonMask & ADDON_CLIENTSIDE_ASSASSINATION_TARGET ) && m_hAssassinationTargetAddon.Get() )
  944. {
  945. m_hAssassinationTargetAddon->Release();
  946. m_hAssassinationTargetAddon.Term();
  947. }
  948. }
  949. void C_CSRagdoll::OnDataChanged( DataUpdateType_t type )
  950. {
  951. if ( type == DATA_UPDATE_CREATED )
  952. {
  953. int unused;
  954. AddDataChangeEvent( this, DATA_UPDATE_POST_UPDATE, &unused );
  955. return;
  956. }
  957. DataUpdateType_t typeForBaseClass = ( type == DATA_UPDATE_POST_UPDATE ) ? DATA_UPDATE_CREATED : type;
  958. BaseClass::OnDataChanged( typeForBaseClass );
  959. if ( type == DATA_UPDATE_POST_UPDATE )
  960. {
  961. if ( g_RagdollLVManager.IsLowViolence() )
  962. {
  963. CreateLowViolenceRagdoll();
  964. }
  965. else
  966. {
  967. CreateCSRagdoll();
  968. }
  969. }
  970. else
  971. {
  972. if ( !cl_ragdoll_physics_enable.GetInt() )
  973. {
  974. // Don't let it set us back to a ragdoll with data from the server.
  975. m_bClientSideRagdoll = false;
  976. }
  977. }
  978. }
  979. IRagdoll* C_CSRagdoll::GetIRagdoll() const
  980. {
  981. return m_pRagdoll;
  982. }
  983. //-----------------------------------------------------------------------------
  984. // Purpose: Called when the player toggles nightvision
  985. // Input : *pData - the int value of the nightvision state
  986. // *pStruct - the player
  987. // *pOut -
  988. //-----------------------------------------------------------------------------
  989. void RecvProxy_NightVision( const CRecvProxyData *pData, void *pStruct, void *pOut )
  990. {
  991. C_CSPlayer *pPlayerData = (C_CSPlayer * ) pStruct;
  992. bool bNightVisionOn = ( pData->m_Value.m_Int > 0 );
  993. if ( pPlayerData->m_bNightVisionOn != bNightVisionOn )
  994. {
  995. if ( bNightVisionOn )
  996. pPlayerData->m_flNightVisionAlpha = 1;
  997. }
  998. pPlayerData->m_bNightVisionOn = bNightVisionOn;
  999. }
  1000. void RecvProxy_FlashTime( const CRecvProxyData *pData, void *pStruct, void *pOut )
  1001. {
  1002. C_CSPlayer *pPlayerData = (C_CSPlayer * ) pStruct;
  1003. pPlayerData->m_bFlashBuildUp = false;
  1004. float flNewFlashDuration = pData->m_Value.m_Float;
  1005. if ( flNewFlashDuration == 0.0f )
  1006. {
  1007. // Disable flashbang effect
  1008. pPlayerData->m_flFlashScreenshotAlpha = 0.0f;
  1009. pPlayerData->m_flFlashOverlayAlpha = 0.0f;
  1010. pPlayerData->m_bFlashBuildUp = false;
  1011. pPlayerData->m_bFlashScreenshotHasBeenGrabbed = false;
  1012. pPlayerData->m_flFlashDuration = 0.0f;
  1013. pPlayerData->m_flFlashBangTime = 0.0f;
  1014. pPlayerData->m_bFlashDspHasBeenCleared = false;
  1015. C_CSPlayer *pLocalCSPlayer = C_CSPlayer::GetLocalCSPlayer();
  1016. if (pLocalCSPlayer)
  1017. {
  1018. pLocalCSPlayer->m_bFlashDspHasBeenCleared = false;
  1019. }
  1020. return;
  1021. }
  1022. // If local player is spectating in mode other than first-person, reduce effect duration by half
  1023. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  1024. if ( pLocalPlayer && pLocalPlayer->GetObserverMode() != OBS_MODE_NONE && pLocalPlayer->GetObserverMode() != OBS_MODE_IN_EYE )
  1025. {
  1026. flNewFlashDuration *= 0.5f;
  1027. }
  1028. if ( pLocalPlayer && pLocalPlayer->GetObserverMode() != OBS_MODE_NONE &&
  1029. flNewFlashDuration > 0.0f && pPlayerData->m_flFlashDuration == flNewFlashDuration )
  1030. {
  1031. // Ignore this update. This is a resend from the server triggered by the spectator changing target.
  1032. return;
  1033. }
  1034. if ( !pPlayerData->IsFlashBangActive() && flNewFlashDuration > 0.0f )
  1035. {
  1036. // reset flash alpha to start of effect build-up
  1037. pPlayerData->m_flFlashScreenshotAlpha = 1.0f;
  1038. pPlayerData->m_flFlashOverlayAlpha = 1.0f;
  1039. pPlayerData->m_bFlashBuildUp = true;
  1040. pPlayerData->m_bFlashScreenshotHasBeenGrabbed = false;
  1041. }
  1042. pPlayerData->m_flFlashDuration = flNewFlashDuration;
  1043. pPlayerData->m_flFlashBangTime = gpGlobals->curtime + pPlayerData->m_flFlashDuration;
  1044. pPlayerData->m_bFlashDspHasBeenCleared = false;
  1045. C_CSPlayer *pLocalCSPlayer = C_CSPlayer::GetLocalCSPlayer();
  1046. if (pLocalCSPlayer)
  1047. {
  1048. pLocalCSPlayer->m_bFlashDspHasBeenCleared = false;
  1049. }
  1050. }
  1051. void C_CSPlayer::SetRenderAlpha( byte a )
  1052. {
  1053. /* Removed for partner depot */
  1054. BaseClass::SetRenderAlpha( a );
  1055. }
  1056. void C_CSPlayer::SetRenderMode( RenderMode_t nRenderMode, bool bForceUpdate )
  1057. {
  1058. /* Removed for partner depot */
  1059. BaseClass::SetRenderMode( nRenderMode, bForceUpdate );
  1060. }
  1061. void C_CSPlayer::UpdateFlashBangEffect( void )
  1062. {
  1063. if ( ( m_flFlashBangTime < gpGlobals->curtime ) || ( m_flFlashMaxAlpha <= 0.0f ) )
  1064. {
  1065. // FlashBang is inactive
  1066. m_flFlashScreenshotAlpha = 0.0f;
  1067. m_flFlashOverlayAlpha = 0.0f;
  1068. return;
  1069. }
  1070. static const float FLASH_BUILD_UP_PER_FRAME = 45.0f;
  1071. static const float FLASH_BUILD_UP_DURATION = ( 255.0f / FLASH_BUILD_UP_PER_FRAME ) * ( 1.0f / 60.0f );
  1072. float flFlashTimeElapsed = GetFlashTimeElapsed();
  1073. if ( m_bFlashBuildUp )
  1074. {
  1075. // build up
  1076. m_flFlashScreenshotAlpha = Clamp( ( flFlashTimeElapsed / FLASH_BUILD_UP_DURATION ) * m_flFlashMaxAlpha.Get(), 0.0f, m_flFlashMaxAlpha.Get() );
  1077. m_flFlashOverlayAlpha = m_flFlashScreenshotAlpha;
  1078. if ( flFlashTimeElapsed >= FLASH_BUILD_UP_DURATION )
  1079. {
  1080. m_bFlashBuildUp = false;
  1081. }
  1082. }
  1083. else
  1084. {
  1085. // cool down
  1086. float flFlashTimeLeft = m_flFlashBangTime - gpGlobals->curtime;
  1087. m_flFlashScreenshotAlpha = ( m_flFlashMaxAlpha * flFlashTimeLeft ) / m_flFlashDuration;
  1088. m_flFlashScreenshotAlpha = Clamp( m_flFlashScreenshotAlpha, 0.0f, m_flFlashMaxAlpha.Get() );
  1089. float flAlphaPercentage = 1.0f;
  1090. const float certainBlindnessTimeThresh = 3.0f; // yes this is a magic number, necessary to match CS/CZ flashbang effectiveness cause the rendering system is completely different.
  1091. if (flFlashTimeLeft > certainBlindnessTimeThresh)
  1092. {
  1093. // if we still have enough time of blindness left, make sure the player can't see anything yet.
  1094. flAlphaPercentage = 1.0f;
  1095. }
  1096. else
  1097. {
  1098. // blindness effects shorter than 'certainBlindness`TimeThresh' will start off at less than 255 alpha.
  1099. flAlphaPercentage = flFlashTimeLeft / certainBlindnessTimeThresh;
  1100. // reduce alpha level quicker with dx 8 support and higher to compensate
  1101. // for having the burn-in effect.
  1102. flAlphaPercentage *= flAlphaPercentage;
  1103. }
  1104. m_flFlashOverlayAlpha = flAlphaPercentage *= m_flFlashMaxAlpha; // scale a [0..1) value to a [0..MaxAlpha] value for the alpha.
  1105. // make sure the alpha is in the range of [0..MaxAlpha]
  1106. m_flFlashOverlayAlpha = Max( m_flFlashOverlayAlpha, 0.0f );
  1107. m_flFlashOverlayAlpha = Min( m_flFlashOverlayAlpha, m_flFlashMaxAlpha.Get());
  1108. }
  1109. }
  1110. void RecvProxy_HasDefuser( const CRecvProxyData *pData, void *pStruct, void *pOut )
  1111. {
  1112. C_CSPlayer *pPlayerData = (C_CSPlayer * )pStruct;
  1113. if (pPlayerData == NULL )
  1114. {
  1115. return;
  1116. }
  1117. bool drawIcon = false;
  1118. if (pData->m_Value.m_Int == 0 )
  1119. {
  1120. pPlayerData->RemoveDefuser();
  1121. }
  1122. else
  1123. {
  1124. if (pPlayerData->HasDefuser() == false )
  1125. {
  1126. drawIcon = true;
  1127. }
  1128. pPlayerData->GiveDefuser();
  1129. if ( drawIcon )
  1130. pPlayerData->DisplayInventory( true );
  1131. }
  1132. }
  1133. void C_CSPlayer::RecvProxy_CycleLatch( const CRecvProxyData *pData, void *pStruct, void *pOut )
  1134. {
  1135. // This receive proxy looks to see if the server's value is close enough to what we think it should
  1136. // be. We've been running the same code; this is an error correction for changes we didn't simulate
  1137. // while they were out of PVS.
  1138. C_CSPlayer *pPlayer = (C_CSPlayer * )pStruct;
  1139. if( C_BasePlayer::IsLocalPlayer( pPlayer ) )
  1140. return; // Don't need to fixup ourselves.
  1141. float incomingCycle = (float )(pData->m_Value.m_Int) / 16; // Came in as 4 bit fixed point
  1142. float currentCycle = pPlayer->GetCycle();
  1143. bool closeEnough = fabs(currentCycle - incomingCycle ) < CycleLatchTolerance;
  1144. if( fabs(currentCycle - incomingCycle ) > (1 - CycleLatchTolerance) )
  1145. {
  1146. closeEnough = true;// Handle wrapping around 1->0
  1147. }
  1148. if( !closeEnough )
  1149. {
  1150. // Server disagrees too greatly. Correct our value.
  1151. if ( pPlayer && pPlayer->GetTeam() )
  1152. {
  1153. DevMsg( 2, "%s %s(%d): Cycle latch wants to correct %.2f in to %.2f.\n",
  1154. pPlayer->GetTeam()->Get_Name(), pPlayer->GetPlayerName(), pPlayer->entindex(), currentCycle, incomingCycle );
  1155. }
  1156. pPlayer->SetServerIntendedCycle( incomingCycle );
  1157. }
  1158. }
  1159. bool C_CSPlayer::ShouldRegenerateOriginFromCellBits() const
  1160. {
  1161. return false;
  1162. }
  1163. bool __MsgFunc_ItemDrop( const CCSUsrMsg_ItemDrop &msg )
  1164. {
  1165. return true;
  1166. }
  1167. USER_MESSAGE_REGISTER( ItemDrop );
  1168. bool __MsgFunc_ReloadEffect( const CCSUsrMsg_ReloadEffect &msg )
  1169. {
  1170. int iPlayer = msg.entidx();
  1171. int iActAnimID = msg.has_actanim() ? msg.actanim() : ACT_VM_RELOAD;
  1172. Vector origin;
  1173. Vector *pOrigin = NULL;
  1174. if ( msg.has_origin_x() )
  1175. {
  1176. origin.x = msg.origin_x();
  1177. origin.y = msg.origin_y();
  1178. origin.z = msg.origin_z();
  1179. pOrigin = &origin;
  1180. }
  1181. C_CSPlayer *pPlayer = dynamic_cast< C_CSPlayer* >( C_BaseEntity::Instance( iPlayer ) );
  1182. if ( pPlayer )
  1183. pPlayer->PlayReloadEffect( iActAnimID, pOrigin );
  1184. return true;
  1185. }
  1186. USER_MESSAGE_REGISTER( ReloadEffect );
  1187. BEGIN_RECV_TABLE_NOBASE( C_CSPlayer, DT_CSLocalPlayerExclusive )
  1188. // DEPRECATED; redundant origin positions. Kept for backwards demo compatible.
  1189. RecvPropVectorXY( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ),
  1190. RecvPropFloat( RECVINFO_NAME( m_vecNetworkOrigin[2], m_vecOrigin[2] ) ),
  1191. /////
  1192. RecvPropFloat( RECVINFO(m_flStamina ) ),
  1193. RecvPropInt( RECVINFO( m_iDirection ) ),
  1194. RecvPropInt( RECVINFO( m_iShotsFired ) ),
  1195. RecvPropInt( RECVINFO( m_nNumFastDucks ) ),
  1196. RecvPropBool( RECVINFO( m_bDuckOverride ) ),
  1197. RecvPropFloat( RECVINFO( m_flVelocityModifier ) ),
  1198. RecvPropArray3( RECVINFO_ARRAY( m_bPlayerDominated ), RecvPropBool( RECVINFO( m_bPlayerDominated[0] ) ) ),
  1199. RecvPropArray3( RECVINFO_ARRAY( m_bPlayerDominatingMe ), RecvPropBool( RECVINFO( m_bPlayerDominatingMe[0] ) ) ),
  1200. RecvPropArray3( RECVINFO_ARRAY( m_iWeaponPurchasesThisRound ), RecvPropInt( RECVINFO( m_iWeaponPurchasesThisRound[0] ) ) ),
  1201. RecvPropInt( RECVINFO( m_nQuestProgressReason ) ),
  1202. END_RECV_TABLE()
  1203. BEGIN_RECV_TABLE_NOBASE( C_CSPlayer, DT_CSNonLocalPlayerExclusive )
  1204. // DEPRECATED; redundant origin positions. Kept for backwards demo compatible.
  1205. RecvPropVectorXY( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ),
  1206. RecvPropFloat( RECVINFO_NAME( m_vecNetworkOrigin[2], m_vecOrigin[2] ) ),
  1207. //////
  1208. END_RECV_TABLE()
  1209. IMPLEMENT_CLIENTCLASS_DT( C_CSPlayer, DT_CSPlayer, CCSPlayer )
  1210. // Data that only gets sent to the local player.
  1211. RecvPropDataTable( "cslocaldata", 0, 0, &REFERENCE_RECV_TABLE(DT_CSLocalPlayerExclusive ) ),
  1212. RecvPropDataTable( "csnonlocaldata", 0, 0, &REFERENCE_RECV_TABLE(DT_CSNonLocalPlayerExclusive ) ),
  1213. RecvPropFloat( RECVINFO( m_angEyeAngles[0] ) ),
  1214. RecvPropFloat( RECVINFO( m_angEyeAngles[1] ) ),
  1215. RecvPropInt( RECVINFO( m_iAddonBits ) ),
  1216. RecvPropInt( RECVINFO( m_iPrimaryAddon ) ),
  1217. RecvPropInt( RECVINFO( m_iSecondaryAddon ) ),
  1218. RecvPropInt( RECVINFO( m_iThrowGrenadeCounter ) ),
  1219. RecvPropBool( RECVINFO( m_bWaitForNoAttack ) ),
  1220. RecvPropBool( RECVINFO( m_bIsRespawningForDMBonus ) ),
  1221. RecvPropInt( RECVINFO( m_iPlayerState ) ),
  1222. RecvPropInt( RECVINFO( m_iAccount ) ),
  1223. RecvPropInt( RECVINFO( m_iStartAccount ) ),
  1224. RecvPropInt( RECVINFO( m_totalHitsOnServer ) ),
  1225. RecvPropInt( RECVINFO( m_bInBombZone ) ),
  1226. RecvPropInt( RECVINFO( m_bInBuyZone ) ),
  1227. RecvPropInt( RECVINFO( m_bInNoDefuseArea ) ),
  1228. RecvPropBool( RECVINFO( m_bKilledByTaser ) ),
  1229. RecvPropInt( RECVINFO( m_iMoveState ) ),
  1230. RecvPropInt( RECVINFO( m_iClass ) ),
  1231. RecvPropInt( RECVINFO( m_ArmorValue ) ),
  1232. RecvPropQAngles( RECVINFO( m_angEyeAngles ) ),
  1233. RecvPropInt( RECVINFO( m_bHasDefuser ), 0, RecvProxy_HasDefuser ),
  1234. RecvPropInt( RECVINFO( m_bNightVisionOn ), 0, RecvProxy_NightVision ),
  1235. RecvPropBool( RECVINFO( m_bHasNightVision ) ),
  1236. RecvPropBool( RECVINFO( m_bInHostageRescueZone ) ),
  1237. RecvPropBool( RECVINFO( m_bIsDefusing ) ),
  1238. RecvPropBool( RECVINFO( m_bIsGrabbingHostage ) ),
  1239. RecvPropBool( RECVINFO( m_bIsScoped ) ),
  1240. RecvPropBool( RECVINFO( m_bIsWalking ) ),
  1241. RecvPropBool( RECVINFO( m_bResumeZoom ) ),
  1242. RecvPropFloat( RECVINFO( m_fImmuneToGunGameDamageTime ) ),
  1243. RecvPropBool( RECVINFO( m_bGunGameImmunity ) ),
  1244. RecvPropBool( RECVINFO( m_bHasMovedSinceSpawn ) ),
  1245. RecvPropBool( RECVINFO( m_bMadeFinalGunGameProgressiveKill ) ),
  1246. RecvPropInt( RECVINFO( m_iGunGameProgressiveWeaponIndex ) ),
  1247. RecvPropInt( RECVINFO( m_iNumGunGameTRKillPoints ) ),
  1248. RecvPropInt( RECVINFO( m_iNumGunGameKillsWithCurrentWeapon ) ),
  1249. RecvPropInt( RECVINFO( m_iNumRoundKills ) ),
  1250. RecvPropFloat( RECVINFO( m_fMolotovUseTime ) ),
  1251. RecvPropFloat( RECVINFO( m_fMolotovDamageTime ) ),
  1252. RecvPropString( RECVINFO( m_szArmsModel ) ),
  1253. RecvPropEHandle( RECVINFO(m_hCarriedHostage) ),
  1254. RecvPropEHandle( RECVINFO(m_hCarriedHostageProp) ),
  1255. RecvPropBool( RECVINFO( m_bIsRescuing ) ),
  1256. RecvPropFloat( RECVINFO( m_flGroundAccelLinearFracLastTime ) ),
  1257. RecvPropBool( RECVINFO( m_bCanMoveDuringFreezePeriod ) ),
  1258. RecvPropBool( RECVINFO( m_isCurrentGunGameLeader ) ),
  1259. RecvPropBool( RECVINFO( m_isCurrentGunGameTeamLeader ) ),
  1260. RecvPropFloat( RECVINFO( m_flGuardianTooFarDistFrac ) ),
  1261. RecvPropFloat( RECVINFO( m_flDetectedByEnemySensorTime ) ),
  1262. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_Kills ), RecvPropInt( RECVINFO( m_iMatchStats_Kills[0] ))),
  1263. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_Damage ), RecvPropInt( RECVINFO( m_iMatchStats_Damage[0] ))),
  1264. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_EquipmentValue ), RecvPropInt( RECVINFO( m_iMatchStats_EquipmentValue[0] ))),
  1265. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_MoneySaved ), RecvPropInt( RECVINFO( m_iMatchStats_MoneySaved[0] ))),
  1266. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_KillReward ), RecvPropInt( RECVINFO( m_iMatchStats_KillReward[0] ))),
  1267. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_LiveTime ), RecvPropInt( RECVINFO( m_iMatchStats_LiveTime[0] ))),
  1268. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_Deaths ), RecvPropInt( RECVINFO( m_iMatchStats_Deaths[0] ))),
  1269. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_Assists ), RecvPropInt( RECVINFO( m_iMatchStats_Assists[0] ))),
  1270. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_HeadShotKills ), RecvPropInt( RECVINFO( m_iMatchStats_HeadShotKills[0] ))),
  1271. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_Objective ), RecvPropInt( RECVINFO( m_iMatchStats_Objective[0] ))),
  1272. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_CashEarned ), RecvPropInt( RECVINFO( m_iMatchStats_CashEarned[0] ))),
  1273. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_UtilityDamage ), RecvPropInt( RECVINFO( m_iMatchStats_UtilityDamage[0] ))),
  1274. RecvPropArray3( RECVINFO_ARRAY( m_iMatchStats_EnemiesFlashed ), RecvPropInt( RECVINFO( m_iMatchStats_EnemiesFlashed[0] ))),
  1275. RecvPropArray3( RECVINFO_ARRAY(m_rank), RecvPropInt( RECVINFO(m_rank[0]))),
  1276. RecvPropInt( RECVINFO( m_unMusicID ), 0 ),
  1277. #ifdef CS_SHIELD_ENABLED
  1278. RecvPropBool( RECVINFO( m_bHasShield ) ),
  1279. RecvPropBool( RECVINFO( m_bShieldDrawn ) ),
  1280. #endif
  1281. RecvPropBool( RECVINFO( m_bHasHelmet ) ),
  1282. RecvPropBool( RECVINFO( m_bHasHeavyArmor ) ),
  1283. RecvPropFloat( RECVINFO( m_flFlashDuration ), 0, RecvProxy_FlashTime ),
  1284. RecvPropFloat( RECVINFO( m_flFlashMaxAlpha )),
  1285. RecvPropInt( RECVINFO( m_iProgressBarDuration ) ),
  1286. RecvPropFloat( RECVINFO( m_flProgressBarStartTime ) ),
  1287. RecvPropEHandle( RECVINFO( m_hRagdoll ) ),
  1288. RecvPropInt( RECVINFO( m_cycleLatch ), 0, &C_CSPlayer::RecvProxy_CycleLatch ),
  1289. RecvPropInt( RECVINFO( m_unCurrentEquipmentValue ) ),
  1290. RecvPropInt( RECVINFO( m_unRoundStartEquipmentValue ) ),
  1291. RecvPropInt( RECVINFO( m_unFreezetimeEndEquipmentValue ) ),
  1292. #if CS_CONTROLLABLE_BOTS_ENABLED
  1293. RecvPropBool( RECVINFO( m_bIsControllingBot ) ),
  1294. RecvPropBool( RECVINFO( m_bHasControlledBotThisRound ) ),
  1295. RecvPropBool( RECVINFO( m_bCanControlObservedBot ) ),
  1296. RecvPropInt( RECVINFO( m_iControlledBotEntIndex ) ),
  1297. #endif
  1298. RecvPropBool( RECVINFO( m_bIsAssassinationTarget ) ),
  1299. // data used to show and hide hud via scripts in the training map
  1300. RecvPropBool( RECVINFO( m_bHud_MiniScoreHidden ) ),
  1301. RecvPropBool( RECVINFO( m_bHud_RadarHidden ) ),
  1302. RecvPropInt( RECVINFO( m_nLastKillerIndex ) ),
  1303. // when a player dies, we send to the client the number of unbroken times in a row the player has been killed by their last killer
  1304. RecvPropInt( RECVINFO( m_nLastConcurrentKilled ) ),
  1305. RecvPropInt( RECVINFO( m_nDeathCamMusic ) ),
  1306. RecvPropBool( RECVINFO( m_bIsHoldingLookAtWeapon ) ),
  1307. RecvPropBool( RECVINFO( m_bIsLookingAtWeapon ) ),
  1308. RecvPropInt( RECVINFO( m_iNumRoundKillsHeadshots ) ),
  1309. #if defined( PLAYER_TAUNT_SHIPPING_FEATURE )
  1310. RecvPropBool( RECVINFO( m_bIsTaunting ) ),
  1311. RecvPropBool( RECVINFO( m_bIsThirdPersonTaunt ) ),
  1312. RecvPropBool( RECVINFO( m_bIsHoldingTaunt ) ),
  1313. RecvPropFloat( RECVINFO( m_flTauntYaw ) ),
  1314. #endif
  1315. #if defined( USE_PLAYER_ATTRIBUTE_MANAGER )
  1316. RecvPropDataTable( RECVINFO_DT( m_AttributeManager ), 0, &REFERENCE_RECV_TABLE(DT_AttributeManager) ),
  1317. #endif
  1318. RecvPropFloat( RECVINFO( m_flLowerBodyYawTarget ) ),
  1319. RecvPropBool( RECVINFO( m_bStrafing ) ),
  1320. RecvPropFloat( RECVINFO( m_flThirdpersonRecoil ) ),
  1321. END_RECV_TABLE()
  1322. bool C_CSPlayer::s_bPlayingFreezeCamSound = false;
  1323. C_CSPlayer::C_CSPlayer() :
  1324. m_iv_angEyeAngles( "C_CSPlayer::m_iv_angEyeAngles" ),
  1325. m_GlowObject( this, Vector( 1.0f, 1.0f, 1.0f ), 0.0f, false, false ),
  1326. m_bIsSpecFollowingGrenade( false )
  1327. {
  1328. m_bMaintainSequenceTransitions = false; // disabled for perf - animstate takes care of carefully blending only the layers that need it
  1329. m_PlayerAnimState = CreatePlayerAnimState( this, this, LEGANIM_9WAY, true );
  1330. //the new animstate needs to live side-by-side with the old animstate for a while so it can be hot swappable
  1331. m_PlayerAnimStateCSGO = CreateCSGOPlayerAnimstate( this );
  1332. m_bCanMoveDuringFreezePeriod = false;
  1333. m_flThirdpersonRecoil = 0;
  1334. m_angEyeAngles.Init();
  1335. AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
  1336. // Remove interpolation of variables we have excluded from send table
  1337. // HACK: m_angRotation is private in C_BaseEntity but it's accessible via GetLocalAngles()
  1338. RemoveVar( const_cast<QAngle*>(&GetLocalAngles()) ); // == RemoveVar( &m_angRotation );
  1339. m_bAddonModelsAreOutOfDate = false;
  1340. m_iLastAddonBits = m_iAddonBits = 0;
  1341. m_iLastPrimaryAddon = m_iLastSecondaryAddon = WEAPON_NONE;
  1342. m_iProgressBarDuration = 0;
  1343. m_flProgressBarStartTime = 0.0f;
  1344. m_ArmorValue = 0;
  1345. m_bHasHelmet = false;
  1346. m_bHasHeavyArmor = false;
  1347. m_iIDEntIndex = 0;
  1348. m_delayTargetIDTimer.Reset();
  1349. m_iOldIDEntIndex = 0;
  1350. m_holdTargetIDTimer.Reset();
  1351. m_iDirection = 0;
  1352. m_bIsBuyMenuOpen = false;
  1353. m_flNextGuardianTooFarWarning = 0;
  1354. m_flLastFiredWeaponTime = -1;
  1355. m_nQuestProgressReason = QuestProgress::QUEST_NONINITIALIZED;
  1356. m_unCurrentEquipmentValue = 0;
  1357. m_unRoundStartEquipmentValue = 0;
  1358. m_unFreezetimeEndEquipmentValue = 0;
  1359. m_hC4AddonLED = NULL;
  1360. m_hC4WeaponLED = NULL;
  1361. m_hOldGrenadeObserverTarget = NULL;
  1362. m_Activity = ACT_IDLE;
  1363. m_pFlashlightBeam = NULL;
  1364. m_fNextThinkPushAway = 0.0f;
  1365. m_fNextGlowCheckUpdate = 0.0f;
  1366. m_fNextGlowCheckInterval = GLOWUPDATE_DEFAULT_THINK_INTERVAL;
  1367. m_fGlowAlpha = 1.0f;
  1368. m_fGlowAlphaTarget = 1.0f;
  1369. m_fGlowAlphaUpdateTime = -1.0f;
  1370. m_fGlowAlphaTargetTime = -1.0f;
  1371. m_bFreezeCamFlashlightActive = false;
  1372. m_serverIntendedCycle = -1.0f;
  1373. view->SetScreenOverlayMaterial( NULL );
  1374. m_iTargetedWeaponEntIndex = 0;
  1375. m_vecFreezeFrameEnd = Vector( 0, 0, 0 );
  1376. m_flFreezeFrameTilt = 0;
  1377. m_vecFreezeFrameAnglesStart = QAngle( 0, 0, 0 );
  1378. m_bFreezeFrameCloseOnKiller = false;
  1379. m_nFreezeFrameShiftSideDist = 0;
  1380. m_bOldIsScoped = false;
  1381. m_fImmuneToGunGameDamageTimeLast = 0;
  1382. m_previousPlayerState = STATE_DORMANT;
  1383. m_duckUntilOnGround = false;
  1384. // set all matchstats values to -1 on the client to identify new stats that don't
  1385. // exist in demos
  1386. memset( m_iMatchStats_Kills, -1, sizeof(m_iMatchStats_Kills) );
  1387. memset( m_iMatchStats_Damage, -1, sizeof(m_iMatchStats_Damage) );
  1388. memset( m_iMatchStats_EquipmentValue, -1, sizeof(m_iMatchStats_EquipmentValue) );
  1389. memset( m_iMatchStats_MoneySaved, -1, sizeof(m_iMatchStats_MoneySaved) );
  1390. memset( m_iMatchStats_KillReward, -1, sizeof(m_iMatchStats_KillReward) );
  1391. memset( m_iMatchStats_LiveTime, -1, sizeof(m_iMatchStats_LiveTime) );
  1392. memset( m_iMatchStats_Deaths, -1, sizeof(m_iMatchStats_Deaths) );
  1393. memset( m_iMatchStats_Assists, -1, sizeof(m_iMatchStats_Assists) );
  1394. memset( m_iMatchStats_HeadShotKills, -1, sizeof(m_iMatchStats_HeadShotKills) );
  1395. memset( m_iMatchStats_Objective, -1, sizeof(m_iMatchStats_Objective) );
  1396. memset( m_iMatchStats_CashEarned, -1, sizeof(m_iMatchStats_CashEarned) );
  1397. memset( m_iMatchStats_UtilityDamage, -1, sizeof( m_iMatchStats_UtilityDamage ) );
  1398. memset( m_iMatchStats_EnemiesFlashed, -1, sizeof( m_iMatchStats_EnemiesFlashed ) );
  1399. //=============================================================================
  1400. // HPE_BEGIN:
  1401. // [dwenger] Added for auto-buy functionality
  1402. //=============================================================================
  1403. m_bShouldAutobuyNow = false;
  1404. m_bShouldAutobuyDMWeapons = false;
  1405. ListenForGameEvent( "round_freeze_end" );
  1406. //=============================================================================
  1407. // HPE_END
  1408. //=============================================================================
  1409. ListenForGameEvent( "ggtr_player_levelup" );
  1410. ListenForGameEvent( "ggprogressive_player_levelup" );
  1411. ListenForGameEvent( "gg_player_impending_upgrade" );
  1412. ListenForGameEvent( "gg_killed_enemy" );
  1413. ListenForGameEvent( "gg_final_weapon_achieved" );
  1414. ListenForGameEvent( "gg_bonus_grenade_achieved" );
  1415. ListenForGameEvent( "gg_reset_round_start_sounds" );
  1416. ListenForGameEvent( "gg_leader" );
  1417. ListenForGameEvent( "gg_team_leader" );
  1418. ListenForGameEvent( "round_start" );
  1419. ListenForGameEvent( "round_end" );
  1420. ListenForGameEvent( "round_officially_ended" );
  1421. ListenForGameEvent( "player_death" );
  1422. ListenForGameEvent( "player_spawn" );
  1423. ListenForGameEvent( "item_pickup" );
  1424. ListenForGameEvent( "ammo_pickup" );
  1425. ListenForGameEvent( "defuser_pickup" );
  1426. ListenForGameEvent( "player_given_c4" );
  1427. ListenForGameEvent( "tr_mark_complete" );
  1428. ListenForGameEvent( "tr_mark_best_time" );
  1429. ListenForGameEvent( "cs_pre_restart" );
  1430. ListenForGameEvent( "weapon_fire" );
  1431. ListenForGameEvent( "bot_takeover" );
  1432. ListenForGameEvent( "spec_target_updated" );
  1433. ListenForGameEvent( "add_bullet_hit_marker" );
  1434. ListenForGameEvent( "assassination_target_killed" );
  1435. //m_isCurrentGunGameLeader = false;
  1436. //m_isCurrentGunGameTeamLeader = false;
  1437. m_nextTaserShakeTime = 0.0f;
  1438. m_firstTaserShakeTime= 0.0f;
  1439. m_bKilledByTaser = false;
  1440. m_iMoveState = MOVESTATE_IDLE;
  1441. m_flFlashScreenshotAlpha = 0.0f;
  1442. m_flFlashOverlayAlpha = 0.0f;
  1443. m_bFlashBuildUp = false;
  1444. m_bFlashScreenshotHasBeenGrabbed = false;
  1445. m_bFlashDspHasBeenCleared = true;
  1446. m_bPlayingHostageCarrySound = false;
  1447. m_flLastSmokeOverlayAlpha = 0.0f;
  1448. m_fMolotovUseTime = 0.0f;
  1449. m_fMolotovDamageTime = 0.0f;
  1450. m_vecLastMuzzleFlashPos = Vector(0,0,0);
  1451. m_angLastMuzzleFlashAngle = QAngle(0,0,0);
  1452. m_flHealthFadeValue = 100.0f;
  1453. m_flHealthFadeAlpha = 0.0f;
  1454. SetCurrentMusic( CSMUSIC_NONE );
  1455. m_flMusicRoundStartTime = 0.0;
  1456. m_vecObserverInterpolateOffset = vec3_origin;
  1457. m_bObserverInterpolationNeedsDeferredSetup = false;
  1458. m_flObsInterp_PathLength = 0.0f;
  1459. m_obsInterpState = OBSERVER_INTERP_NONE;
  1460. m_qObsInterp_OrientationStart = m_qObsInterp_OrientationTravelDir = Quaternion( 0, 0, 0, 0 );
  1461. // This code allowed us to measure discrepency between client and server bullet hits.
  1462. // It became obsolete when we started using a separate seed for client and server
  1463. // to eliminate 'rage' hacks.
  1464. //
  1465. m_ui8ClientServerHitDifference = 0;
  1466. m_flNextMagDropTime = 0;
  1467. m_nLastMagDropAttachmentIndex = -1;
  1468. m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].Init( this );
  1469. m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].SetWeightListName( "snapshot_weights_upperbody" );
  1470. m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].Init( this );
  1471. m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].AddSubordinate( &m_boneSnapshots[BONESNAPSHOT_UPPER_BODY] );
  1472. m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].SetWeightListName( "snapshot_weights_all" );
  1473. m_nClipPlaneProximityLimitAttachmentIndex = -1;
  1474. m_flLastSpawnTimeIndex = 0;
  1475. m_vecLastAliveLocalVelocity.Init();
  1476. m_fRenderingClipPlane[0] = 0.0f;
  1477. m_fRenderingClipPlane[1] = 0.0f;
  1478. m_fRenderingClipPlane[2] = 0.0f;
  1479. m_fRenderingClipPlane[3] = 0.0f;
  1480. m_nLastClipPlaneSetupFrame = 0;
  1481. m_vecLastClipCameraPos.Init();
  1482. m_vecLastClipCameraForward.Init();
  1483. m_bClipHitStaticWorld = false;
  1484. m_bCachedPlaneIsValid = false;
  1485. m_pClippingWeaponWorldModel = NULL;
  1486. m_vecLastContactShadowTraceOriginLeft = vec3_origin;
  1487. m_vecLastContactShadowTraceOriginRight = vec3_origin;
  1488. m_flLastContactShadowGroundHeightLeft = 0;
  1489. m_flLastContactShadowGroundHeightRight = 0;
  1490. }
  1491. class C_PlayerFootContactShadow : public C_BreakableProp
  1492. {
  1493. public:
  1494. EHANDLE m_hParentPlayer;
  1495. float * GetRenderClipPlane( void )
  1496. {
  1497. C_CSPlayer *pParentPlayer = ToCSPlayer( m_hParentPlayer.Get() );
  1498. if ( pParentPlayer )
  1499. return pParentPlayer->GetRenderClipPlane();
  1500. return NULL;
  1501. }
  1502. virtual bool ShouldDraw()
  1503. {
  1504. SetAllowFastPath( false );
  1505. if ( !m_hParentPlayer.IsValid() )
  1506. {
  1507. return true;
  1508. }
  1509. if ( GetAbsOrigin().LengthSqr() < 1 )
  1510. return false;
  1511. C_CSPlayer *pParentPlayer = ToCSPlayer( m_hParentPlayer.Get() );
  1512. if ( pParentPlayer )
  1513. {
  1514. if ( pParentPlayer->IsDormant() )
  1515. return false;
  1516. if ( pParentPlayer->m_hContactShadowLeft.Get() == this || pParentPlayer->m_hContactShadowRight.Get() == this )
  1517. {
  1518. return BaseClass::ShouldDraw() && pParentPlayer->ShouldDraw();
  1519. }
  1520. }
  1521. extern bool SetImmediateEntityRemovesAllowed( bool bAllowed );
  1522. bool bTemp = SetImmediateEntityRemovesAllowed( false );
  1523. UTIL_Remove( this );
  1524. SetImmediateEntityRemovesAllowed( bTemp );
  1525. return false;
  1526. }
  1527. };
  1528. void C_CSPlayer::CreateClientEffectModels( void )
  1529. {
  1530. if ( !m_hMuzzleFlashShape.Get() )
  1531. {
  1532. C_BaseAnimating *pMuzzleFlashShape = new C_BaseAnimating;
  1533. if ( pMuzzleFlashShape->InitializeAsClientEntity( "models/weapons/w_muzzlefireshape.mdl", false ) )
  1534. {
  1535. pMuzzleFlashShape->AddEffects( EF_NODRAW );
  1536. m_hMuzzleFlashShape.Set( pMuzzleFlashShape );
  1537. }
  1538. }
  1539. if ( !m_hContactShadowLeft.Get() )
  1540. {
  1541. C_PlayerFootContactShadow *pContactShadowLeft = new C_PlayerFootContactShadow;
  1542. if ( pContactShadowLeft->InitializeAsClientEntity( "models/player/contactshadow/contactshadow_leftfoot.mdl", false ) )
  1543. {
  1544. pContactShadowLeft->m_hParentPlayer = this;
  1545. m_hContactShadowLeft.Set( pContactShadowLeft );
  1546. pContactShadowLeft->AddEffects( EF_NODRAW );
  1547. pContactShadowLeft->AddEffects( EF_NOSHADOW );
  1548. }
  1549. else
  1550. {
  1551. pContactShadowLeft->Release();
  1552. }
  1553. }
  1554. if ( !m_hContactShadowRight.Get() )
  1555. {
  1556. C_PlayerFootContactShadow *pContactShadowRight = new C_PlayerFootContactShadow;
  1557. if ( pContactShadowRight->InitializeAsClientEntity( "models/player/contactshadow/contactshadow_rightfoot.mdl", false ) )
  1558. {
  1559. pContactShadowRight->m_hParentPlayer = this;
  1560. m_hContactShadowRight.Set( pContactShadowRight );
  1561. pContactShadowRight->AddEffects( EF_NODRAW );
  1562. pContactShadowRight->AddEffects( EF_NOSHADOW );
  1563. }
  1564. else
  1565. {
  1566. pContactShadowRight->Release();
  1567. }
  1568. }
  1569. }
  1570. void C_CSPlayer::RemoveClientEffectModels( void )
  1571. {
  1572. if ( m_hMuzzleFlashShape.Get() )
  1573. UTIL_Remove( m_hMuzzleFlashShape.Get() );
  1574. if ( m_hContactShadowLeft.Get() )
  1575. UTIL_Remove( m_hContactShadowLeft.Get() );
  1576. if ( m_hContactShadowRight.Get() )
  1577. UTIL_Remove( m_hContactShadowRight.Get() );
  1578. }
  1579. C_CSPlayer::~C_CSPlayer()
  1580. {
  1581. MDLCACHE_CRITICAL_SECTION();
  1582. RemoveAddonModels();
  1583. for ( int hh = 0 ; hh < MAX_SPLITSCREEN_PLAYERS; ++hh )
  1584. {
  1585. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  1586. ReleaseFlashlight();
  1587. }
  1588. if ( m_PlayerAnimState )
  1589. m_PlayerAnimState->Release();
  1590. if ( m_PlayerAnimStateCSGO )
  1591. m_PlayerAnimStateCSGO->Release();
  1592. m_freezeCamSpotLightTexture.Shutdown();
  1593. RemoveC4Effect( false );
  1594. UpdateRadioHeadIcon( false );
  1595. RemoveClientEffectModels();
  1596. }
  1597. class CTraceFilterOmitPlayers : public CTraceFilterSimple
  1598. {
  1599. public:
  1600. CTraceFilterOmitPlayers( const IHandleEntity *passentity = NULL, int collisionGroup = MASK_SHOT )
  1601. : CTraceFilterSimple( passentity, collisionGroup )
  1602. {
  1603. }
  1604. virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  1605. {
  1606. CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
  1607. if ( !pEntity )
  1608. return NULL;
  1609. if ( pEntity->IsPlayer() )
  1610. return false;
  1611. // Honor BlockLOS - this lets us see through partially-broken doors, etc
  1612. if ( !pEntity->BlocksLOS() )
  1613. return false;
  1614. return CTraceFilterSimple::ShouldHitEntity( pHandleEntity, contentsMask );
  1615. }
  1616. };
  1617. bool UTIL_clipwalls_hitvalid( const trace_t &tr )
  1618. {
  1619. return ( tr.DidHit() && !tr.m_pEnt->IsPlayer() && !(tr.surface.flags & SURF_TRANS) );
  1620. }
  1621. void UTIL_clipwalls_debugline( const trace_t &tr )
  1622. {
  1623. if ( tr.DidHit() )
  1624. {
  1625. debugoverlay->AddLineOverlay( tr.startpos, tr.endpos, 255,0,0, false, 0 );
  1626. }
  1627. else
  1628. {
  1629. debugoverlay->AddLineOverlay( tr.startpos, tr.endpos, 0,255,0, false, 0 );
  1630. }
  1631. }
  1632. ConVar cl_weapon_clip_thinwalls("cl_weapon_clip_thinwalls", "1", FCVAR_CHEAT | FCVAR_REPLICATED );
  1633. ConVar cl_weapon_clip_thinwalls_debug("cl_weapon_clip_thinwalls_debug", "0", FCVAR_CHEAT | FCVAR_REPLICATED );
  1634. ConVar cl_weapon_clip_thinwalls_lock( "cl_weapon_clip_thinwalls_lock", "0", FCVAR_CHEAT | FCVAR_REPLICATED );
  1635. float * C_CSPlayer::GetRenderClipPlane( void )
  1636. {
  1637. // Players that are on the other side of thin surfaces like doors poke through.
  1638. // This experimental solution places a clipping plane at the extent of a player's
  1639. // weapon, to try and keep the renderable part of the player behind thin obstacles
  1640. // in worst-case situations.
  1641. if ( IsAnimLODflagSet(ANIMLODFLAG_OUTSIDEVIEWFRUSTUM|ANIMLODFLAG_INVISIBLELOCALPLAYER) ||
  1642. !m_bUseNewAnimstate || !cl_weapon_clip_thinwalls.GetBool() || IsDormant() || !ShouldDraw() || GetMoveType() == MOVETYPE_LADDER )
  1643. {
  1644. m_bCachedPlaneIsValid = false;
  1645. return NULL;
  1646. }
  1647. if ( cl_weapon_clip_thinwalls_lock.GetBool() )
  1648. return m_fRenderingClipPlane;
  1649. if ( m_nLastClipPlaneSetupFrame == gpGlobals->framecount && m_bCachedPlaneIsValid ) // we already computed a plane this frame, it's still good
  1650. return m_fRenderingClipPlane;
  1651. CWeaponCSBase* pActiveWeapon = GetActiveCSWeapon();
  1652. if ( pActiveWeapon )
  1653. {
  1654. CBaseWeaponWorldModel *pWeaponWorldModel = pActiveWeapon->GetWeaponWorldModel();
  1655. if ( pWeaponWorldModel && !pWeaponWorldModel->HasDormantOwner() )
  1656. {
  1657. if ( !pWeaponWorldModel->IsEffectActive( EF_BONEMERGE ) )
  1658. {
  1659. m_bCachedPlaneIsValid = false;
  1660. return NULL;
  1661. }
  1662. Vector vecEyePosition = EyePosition();
  1663. Vector vecEyeForward;
  1664. Vector vecEyeRight;
  1665. Vector vecEyeUp;
  1666. AngleVectors( EyeAngles(), &vecEyeForward, &vecEyeRight, &vecEyeUp );
  1667. if ( m_bCachedPlaneIsValid )
  1668. {
  1669. // The player is allowed to move a tiny amount relative to the cached plane, so this additional
  1670. // fallback check is to make sure that the cached plane is still never too close to the center of the player
  1671. float flDistFromCachedPlane = DotProduct( vecEyePosition, Vector(m_fRenderingClipPlane[0], m_fRenderingClipPlane[1], m_fRenderingClipPlane[2]) ) - m_fRenderingClipPlane[3];
  1672. // if too close for any reason, invalidate it
  1673. if ( flDistFromCachedPlane < 15 )
  1674. m_bCachedPlaneIsValid = false;
  1675. }
  1676. if ( m_bClipHitStaticWorld && // the clipping plane isn't going to change on us, since we built it when we hit the static world, not a door or some other dynamic object
  1677. m_bCachedPlaneIsValid &&
  1678. m_pClippingWeaponWorldModel &&
  1679. m_pClippingWeaponWorldModel == pWeaponWorldModel &&
  1680. vecEyePosition.DistToSqr( m_vecLastClipCameraPos ) < 2 &&
  1681. vecEyeForward.DistToSqr( m_vecLastClipCameraForward ) < 0.0005f )
  1682. {
  1683. return m_fRenderingClipPlane; // the position, angle, and weapon we used to recently compute the plane are still valid and close enough to re-use.
  1684. }
  1685. m_pClippingWeaponWorldModel = pWeaponWorldModel;
  1686. m_vecLastClipCameraPos = vecEyePosition;
  1687. m_vecLastClipCameraForward = vecEyeForward;
  1688. CSWeaponType wepType = pActiveWeapon->GetWeaponType();
  1689. QAngle angMuzzleAngle;
  1690. Vector vecWeaponMuzzle;
  1691. if ( pWeaponWorldModel->IsVisible() && wepType != WEAPONTYPE_KNIFE && wepType < WEAPONTYPE_C4 )
  1692. {
  1693. int iMuzzleBoneIndex = pWeaponWorldModel->GetMuzzleBoneIndex();
  1694. if ( iMuzzleBoneIndex < 0 )
  1695. {
  1696. m_bCachedPlaneIsValid = false;
  1697. return NULL;
  1698. }
  1699. CStudioHdr *pHdr = pWeaponWorldModel->GetModelPtr();
  1700. if ( pHdr )
  1701. {
  1702. int nRightHandWepBoneIndex = LookupBone( "weapon_hand_R" );
  1703. if ( nRightHandWepBoneIndex > 0 && isBoneAvailableForRead( nRightHandWepBoneIndex ) )
  1704. {
  1705. matrix3x4a_t matHand = GetBone( nRightHandWepBoneIndex );
  1706. vecWeaponMuzzle = VectorTransform( pHdr->pBone(iMuzzleBoneIndex)->pos, matHand );
  1707. VectorAngles( matHand.GetForward(), angMuzzleAngle );
  1708. }
  1709. else
  1710. {
  1711. m_bCachedPlaneIsValid = false;
  1712. return NULL;
  1713. }
  1714. }
  1715. else
  1716. {
  1717. m_bCachedPlaneIsValid = false;
  1718. return NULL;
  1719. }
  1720. }
  1721. else
  1722. {
  1723. vecWeaponMuzzle = vecEyePosition + (vecEyeForward * 32);
  1724. VectorAngles( vecEyeForward, angMuzzleAngle );
  1725. }
  1726. // It's tempting to bail when the muzzle is simply embedded in solid. But this fails in a rather common case:
  1727. // When a player behind a thin door points their weapon through the corner of the door in such a way that the
  1728. // muzzle would poke into the door frame after having poked through the door.
  1729. //int nMuzzlePointContents = enginetrace->GetPointContents(vecWeaponMuzzle);
  1730. //if ( nMuzzlePointContents & CONTENTS_SOLID )
  1731. //{
  1732. // return NULL;
  1733. //}
  1734. Vector vecEyeToWorldMuzzle = vecWeaponMuzzle - vecEyePosition;
  1735. float flEyeToWorldMuzzleLength = vecEyeToWorldMuzzle.Length();
  1736. if ( flEyeToWorldMuzzleLength > 128 )
  1737. {
  1738. m_bCachedPlaneIsValid = false;
  1739. return NULL;
  1740. }
  1741. // the weapon is pointing away from the flat eye direction, don't clip
  1742. Vector vecEyeForwardFlat = Vector( vecEyeForward.x, vecEyeForward.y, 0 ).Normalized();
  1743. float flDotEyeToMuzzleByEyeForward = DotProduct( Vector( vecEyeToWorldMuzzle.x, vecEyeToWorldMuzzle.y, 0 ).Normalized(), vecEyeForwardFlat );
  1744. if ( flDotEyeToMuzzleByEyeForward < 0 )
  1745. {
  1746. m_bCachedPlaneIsValid = false;
  1747. return NULL;
  1748. }
  1749. Vector vecWeaponForward;
  1750. AngleVectors( angMuzzleAngle, &vecWeaponForward );
  1751. Vector vecWeaponRear = vecWeaponMuzzle - vecWeaponForward * flEyeToWorldMuzzleLength;
  1752. vecWeaponMuzzle += vecWeaponForward; // move the muzzle test point forward by 1 unit
  1753. CTraceFilterOmitPlayers traceFilter;
  1754. traceFilter.SetPassEntity( this );
  1755. trace_t tr_StockToMuzzle;
  1756. UTIL_TraceLine( vecWeaponRear, vecWeaponMuzzle, MASK_WEAPONCLIPPING, &traceFilter, &tr_StockToMuzzle );
  1757. if ( UTIL_clipwalls_hitvalid(tr_StockToMuzzle) )
  1758. {
  1759. // Something solid, non-player, and non-translucent is in the way of the gun. At this point we check some
  1760. // edge cases to prevent odd special cases, like preventing the weapon from clipping due to narrow objects
  1761. // like signposts, railing, or ladder rungs.
  1762. if ( tr_StockToMuzzle.m_pEnt )
  1763. m_bClipHitStaticWorld = tr_StockToMuzzle.m_pEnt->IsWorld();
  1764. bool bClipHitPropDoor = false;
  1765. if ( !m_bClipHitStaticWorld )
  1766. {
  1767. C_BasePropDoor *pPropDoor = dynamic_cast<C_BasePropDoor*>(tr_StockToMuzzle.m_pEnt);
  1768. if ( pPropDoor )
  1769. {
  1770. bClipHitPropDoor = true;
  1771. }
  1772. }
  1773. // Can the player see the muzzle position from their eye position?
  1774. trace_t tr_EyeToMuzzle;
  1775. UTIL_TraceLine( vecEyePosition, vecWeaponMuzzle, MASK_WEAPONCLIPPING, &traceFilter, &tr_EyeToMuzzle );
  1776. if ( !UTIL_clipwalls_hitvalid(tr_EyeToMuzzle) )
  1777. {
  1778. // The player CAN see the muzzle position from their eye position. Don't clip the weapon.
  1779. if ( cl_weapon_clip_thinwalls_debug.GetBool() )
  1780. {
  1781. UTIL_clipwalls_debugline( tr_StockToMuzzle );
  1782. UTIL_clipwalls_debugline( tr_EyeToMuzzle );
  1783. }
  1784. m_bCachedPlaneIsValid = false;
  1785. return NULL;
  1786. }
  1787. // if the weapon direction is wildly different from the eye direction, don't clip
  1788. if ( DotProduct( vecEyeForward, vecWeaponForward ) < 0.3 )
  1789. {
  1790. m_bCachedPlaneIsValid = false;
  1791. return NULL;
  1792. }
  1793. // Can the player see the muzzle position from a point to the left of their eye position?
  1794. trace_t tr_LeftOfEyeToMuzzle;
  1795. UTIL_TraceLine( vecEyePosition - (vecEyeRight * 16), vecWeaponMuzzle, MASK_WEAPONCLIPPING, &traceFilter, &tr_LeftOfEyeToMuzzle );
  1796. if ( !UTIL_clipwalls_hitvalid(tr_LeftOfEyeToMuzzle) )
  1797. {
  1798. // Yes, don't clip the weapon.
  1799. if ( cl_weapon_clip_thinwalls_debug.GetBool() )
  1800. {
  1801. UTIL_clipwalls_debugline( tr_StockToMuzzle );
  1802. UTIL_clipwalls_debugline( tr_EyeToMuzzle );
  1803. UTIL_clipwalls_debugline( tr_LeftOfEyeToMuzzle );
  1804. }
  1805. m_bCachedPlaneIsValid = false;
  1806. return NULL;
  1807. }
  1808. // Can a point to the left of the muzzle see the side of the player's head?
  1809. trace_t tr_LeftOfMuzzleToEye;
  1810. UTIL_TraceLine( vecWeaponMuzzle - (vecEyeRight * 16), vecEyePosition - (vecEyeRight * 4), MASK_WEAPONCLIPPING, &traceFilter, &tr_LeftOfMuzzleToEye );
  1811. if ( !UTIL_clipwalls_hitvalid( tr_LeftOfMuzzleToEye ) )
  1812. {
  1813. // Yes, don't clip the weapon.
  1814. if ( cl_weapon_clip_thinwalls_debug.GetBool() )
  1815. {
  1816. UTIL_clipwalls_debugline( tr_StockToMuzzle );
  1817. UTIL_clipwalls_debugline( tr_EyeToMuzzle );
  1818. UTIL_clipwalls_debugline( tr_LeftOfEyeToMuzzle );
  1819. UTIL_clipwalls_debugline( tr_LeftOfMuzzleToEye );
  1820. }
  1821. m_bCachedPlaneIsValid = false;
  1822. return NULL;
  1823. }
  1824. // We also want to avoid the situation where a player can see and fire around a corner, but their weapon doesn't appear.
  1825. // If a point well ahead of the player in-line with where they're looking at can see the muzzle, we shouldn't clip.
  1826. trace_t tr_EyeToTarget;
  1827. UTIL_TraceLine( vecEyePosition, vecEyePosition + vecEyeForward * 80, MASK_WEAPONCLIPPING, &traceFilter, &tr_EyeToTarget );
  1828. trace_t tr_TargetToMuzzle;
  1829. UTIL_TraceLine( tr_EyeToTarget.endpos - vecEyeForward, vecWeaponMuzzle, MASK_WEAPONCLIPPING, &traceFilter, &tr_TargetToMuzzle );
  1830. if ( cl_weapon_clip_thinwalls_debug.GetBool() )
  1831. {
  1832. UTIL_clipwalls_debugline( tr_StockToMuzzle );
  1833. UTIL_clipwalls_debugline( tr_EyeToMuzzle );
  1834. UTIL_clipwalls_debugline( tr_LeftOfEyeToMuzzle );
  1835. UTIL_clipwalls_debugline( tr_LeftOfMuzzleToEye );
  1836. UTIL_clipwalls_debugline( tr_EyeToTarget );
  1837. UTIL_clipwalls_debugline( tr_TargetToMuzzle );
  1838. }
  1839. if ( !UTIL_clipwalls_hitvalid(tr_TargetToMuzzle) )
  1840. {
  1841. // The spot the player is looking at can see the muzzle of the weapon. Don't clip the weapon.
  1842. m_bCachedPlaneIsValid = false;
  1843. return NULL;
  1844. }
  1845. // Should be reasonable to clip the weapon now.
  1846. // can't clip in the fast path?
  1847. pWeaponWorldModel->SetAllowFastPath( false );
  1848. if ( m_nClipPlaneProximityLimitAttachmentIndex == -1 )
  1849. {
  1850. m_nClipPlaneProximityLimitAttachmentIndex = -2;
  1851. m_nClipPlaneProximityLimitAttachmentIndex = LookupAttachment( "clip_limit" );
  1852. }
  1853. Vector vecEyePosFlat = Vector( vecEyePosition.x, vecEyePosition.y, 0 );
  1854. Vector vecClipPosFlat = Vector( tr_TargetToMuzzle.endpos.x, tr_TargetToMuzzle.endpos.y, 0 );
  1855. Vector vecClipLimit = vecClipPosFlat;
  1856. if ( !bClipHitPropDoor && m_nClipPlaneProximityLimitAttachmentIndex >= 0 )
  1857. {
  1858. GetAttachment( m_nClipPlaneProximityLimitAttachmentIndex, vecClipLimit );
  1859. if ( cl_weapon_clip_thinwalls_debug.GetBool() )
  1860. debugoverlay->AddBoxOverlay( vecClipLimit, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 255,0,0, 0, 0 );
  1861. vecClipLimit.z = 0;
  1862. if ( vecClipLimit.DistToSqr( vecEyePosFlat ) > vecClipPosFlat.DistToSqr( vecEyePosFlat ) )
  1863. {
  1864. vecClipPosFlat = vecClipLimit;
  1865. }
  1866. }
  1867. Vector vecSurfNormal = tr_StockToMuzzle.plane.normal;
  1868. Vector vecFallBackNormal = -vecEyeForwardFlat;
  1869. if ( abs(vecSurfNormal.z) >= 1 )
  1870. {
  1871. vecSurfNormal = vecFallBackNormal;
  1872. }
  1873. else
  1874. {
  1875. vecSurfNormal.z = 0;
  1876. vecSurfNormal.NormalizeInPlaceSafe( vecFallBackNormal );
  1877. }
  1878. float flClipPosDistSqr = (vecClipPosFlat - vecEyePosFlat).LengthSqr();
  1879. if ( flClipPosDistSqr < (16*16) )
  1880. {
  1881. vecClipPosFlat = vecEyePosFlat + (vecClipPosFlat - vecEyePosFlat).Normalized() * 16.0f;
  1882. }
  1883. // build a plane around world pos vecClipPosFlat with local normal vecSurfNormal
  1884. matrix3x4_t matTemp;
  1885. VectorMatrix( vecSurfNormal, matTemp );
  1886. matTemp.SetOrigin( vecClipPosFlat );
  1887. cplane_t planeClipLocal;
  1888. planeClipLocal.normal = Vector(1,0,0);
  1889. planeClipLocal.dist = 0;
  1890. cplane_t planeClipWorld;
  1891. MatrixTransformPlane( matTemp, planeClipLocal, planeClipWorld );
  1892. float flDistFromPlane = DotProduct( vecEyePosFlat, planeClipWorld.normal ) - planeClipWorld.dist;
  1893. // Something is catastrophically wrong for the plane to be this far away.
  1894. if ( flDistFromPlane > 128 )
  1895. {
  1896. Assert( false );
  1897. m_bCachedPlaneIsValid = false;
  1898. return NULL;
  1899. }
  1900. if ( flDistFromPlane < 16.0f )
  1901. {
  1902. planeClipWorld.dist -= (16.0f - flDistFromPlane);
  1903. }
  1904. float flDistFromLimit = DotProduct( vecClipLimit, planeClipWorld.normal ) - planeClipWorld.dist;
  1905. if ( flDistFromLimit < 0 )
  1906. {
  1907. planeClipWorld.dist += flDistFromLimit;
  1908. }
  1909. m_fRenderingClipPlane[0] = planeClipWorld.normal.x;
  1910. m_fRenderingClipPlane[1] = planeClipWorld.normal.y;
  1911. m_fRenderingClipPlane[2] = planeClipWorld.normal.z;
  1912. m_fRenderingClipPlane[3] = planeClipWorld.dist;
  1913. if ( cl_weapon_clip_thinwalls_debug.GetBool() )
  1914. {
  1915. Vector vecCenter = VPlane( planeClipWorld.normal, planeClipWorld.dist ).SnapPointToPlane( vecEyePosition );
  1916. // draw a grid of the local clip position, projected onto the final clipping plane
  1917. for ( float nLine=0; nLine<1.05f; nLine += 0.1f )
  1918. {
  1919. Vector vecLineStart = Vector( 0, -30, 60 * nLine - 30 );
  1920. Vector vecLineEnd = Vector( 0, 30, 60 * nLine - 30 );
  1921. Vector vecLineStart2 = Vector( 0, 60 * nLine - 30, -30 );
  1922. Vector vecLineEnd2 = Vector( 0, 60 * nLine - 30, 30 );
  1923. QAngle angAngle;
  1924. VectorAngles( planeClipWorld.normal.Normalized(), angAngle );
  1925. VectorRotate( vecLineStart, angAngle, vecLineStart );
  1926. VectorRotate( vecLineEnd, angAngle, vecLineEnd );
  1927. VectorRotate( vecLineStart2, angAngle, vecLineStart2 );
  1928. VectorRotate( vecLineEnd2, angAngle, vecLineEnd2 );
  1929. vecLineStart += vecCenter;
  1930. vecLineEnd += vecCenter;
  1931. vecLineStart2 += vecCenter;
  1932. vecLineEnd2 += vecCenter;
  1933. debugoverlay->AddLineOverlay( vecLineStart, vecLineEnd, 255, 255, 0, false, 0 );
  1934. debugoverlay->AddLineOverlay( vecLineStart2, vecLineEnd2, 255, 255, 0, false, 0 );
  1935. }
  1936. }
  1937. m_nLastClipPlaneSetupFrame = gpGlobals->framecount;
  1938. m_bCachedPlaneIsValid = true;
  1939. return m_fRenderingClipPlane;
  1940. }
  1941. else
  1942. {
  1943. if ( cl_weapon_clip_thinwalls_debug.GetBool() )
  1944. {
  1945. UTIL_clipwalls_debugline( tr_StockToMuzzle );
  1946. }
  1947. m_bCachedPlaneIsValid = false;
  1948. return NULL;
  1949. }
  1950. }
  1951. }
  1952. m_bCachedPlaneIsValid = false;
  1953. return NULL;
  1954. }
  1955. ConVar thirdperson_lockcamera("thirdperson_lockcamera", "0", FCVAR_CHEAT | FCVAR_REPLICATED );
  1956. Vector C_CSPlayer::GetThirdPersonViewPosition( void )
  1957. {
  1958. if ( !thirdperson_lockcamera.GetBool() )
  1959. {
  1960. m_vecThirdPersonViewPositionOverride = BaseClass::GetThirdPersonViewPosition();
  1961. return m_vecThirdPersonViewPositionOverride;
  1962. }
  1963. return m_vecThirdPersonViewPositionOverride;
  1964. }
  1965. //=============================================================================
  1966. // HPE_BEGIN:
  1967. // [dwenger] Added for auto-buy functionality
  1968. //=============================================================================
  1969. void C_CSPlayer::FireGameEvent( IGameEvent *event )
  1970. {
  1971. const char *name = event->GetName();
  1972. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1973. int EventUserID = event->GetInt( "userid", -1 );
  1974. //int LocalPlayerID = ( pLocalPlayer != NULL ) ? pLocalPlayer->GetUserID() : -2;
  1975. int PlayerUserID = GetUserID();
  1976. if ( Q_strcmp( name, "round_freeze_end" ) == 0 )
  1977. {
  1978. m_bShouldAutobuyNow = false;
  1979. m_bShouldAutobuyDMWeapons = false;
  1980. if ( IsLocalPlayer() )
  1981. {
  1982. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  1983. C_CS_PlayerResource *pCSRes = GetCSResources();
  1984. CEconQuestDefinition *pQuest = CSGameRules()->GetActiveAssassinationQuest();
  1985. if ( pElement && pCSRes && pQuest )
  1986. {
  1987. wchar_t szBuf[ 512 ];
  1988. const char *szAlertToken = NULL;
  1989. if ( IsAssassinationTarget() )
  1990. szAlertToken = "#quest_assassination_you_are_target";
  1991. else if ( GetActiveQuestID() == pQuest->GetID() && (int)pQuest->GetTargetTeam() != GetTeamNumber() )
  1992. szAlertToken = "#quest_assassination_target_on_server_has_quest";
  1993. else
  1994. szAlertToken = "#quest_assassination_target_on_server";
  1995. g_pVGuiLocalize->ConstructString( szBuf, sizeof( szBuf ), g_pVGuiLocalize->Find( szAlertToken ), 1, g_pVGuiLocalize->Find( Helper_GetLocalPlayerAssassinationQuestLocToken( pQuest ) ) );
  1996. ( ( SFHudInfoPanel * ) pElement )->SetPriorityHintText( szBuf );
  1997. }
  1998. }
  1999. }
  2000. else if ( Q_strcmp( name, "cs_pre_restart" ) == 0 )
  2001. {
  2002. // this is a hack because GetHudPlayer seems to return the previously spectated player instead of the newly spawned
  2003. // C_CSPlayer *pHudPlayer = this;
  2004. // if( this->GetTeamNumber() == TEAM_SPECTATOR )
  2005. // {
  2006. // pHudPlayer = GetHudPlayer();
  2007. // }
  2008. CLocalPlayerFilter filter;
  2009. if( CSGameRules()->IsPlayingGunGame() )
  2010. {
  2011. if ( IsLocalPlayer() )
  2012. {
  2013. PlayMusicSelection( filter, CSMUSIC_STARTGG );
  2014. }
  2015. }
  2016. else if( CSGameRules()->IsPlayingCoopMission() )
  2017. {
  2018. }
  2019. else
  2020. {
  2021. if( ( this->GetTeamNumber() == TEAM_SPECTATOR ) || ( this->IsLocalPlayer() ) )
  2022. {
  2023. PlayMusicSelection(filter, CSMUSIC_START);
  2024. }
  2025. SetCurrentMusic( CSMUSIC_START );
  2026. }
  2027. }
  2028. else if ( (Q_strcmp( "bot_takeover", name ) == 0 || Q_strcmp( "spec_target_updated", name ) == 0) && PlayerUserID == EventUserID )
  2029. {
  2030. UpdateGlowsForAllPlayers();
  2031. C_CSPlayer *pLocalCSPlayer = C_CSPlayer::GetLocalCSPlayer();
  2032. if (pLocalCSPlayer)
  2033. {
  2034. // FlashBang effect needs to update it's screenshot
  2035. pLocalCSPlayer->m_bFlashScreenshotHasBeenGrabbed = false;
  2036. //reset smoke alpha
  2037. m_flLastSmokeOverlayAlpha = 0;
  2038. if ( pLocalPlayer->GetObserverMode() != OBS_MODE_NONE && pLocalPlayer->GetUserID() == EventUserID )
  2039. {
  2040. C_CSPlayer *pFlashBangPlayer = GetHudPlayer();
  2041. if ( pFlashBangPlayer )
  2042. {
  2043. pFlashBangPlayer->m_bFlashScreenshotHasBeenGrabbed = false;
  2044. }
  2045. }
  2046. }
  2047. }
  2048. else if ( Q_strcmp( "gg_reset_round_start_sounds", name ) == 0 )
  2049. {
  2050. if ( PlayerUserID == EventUserID )
  2051. {
  2052. // Clear out the queue of round start sound events
  2053. m_StartOfRoundSoundEvents.ClearSounds();
  2054. }
  2055. }
  2056. else if ( Q_strcmp( "ggtr_player_levelup", name ) == 0 )
  2057. {
  2058. // commenting all of this out because the level up sound is associated with killing a player instead of actually leveling up
  2059. // playing the ding when it's not associated with killing someone is causing a bunch of confusion and is percieved as a bug
  2060. // in TR mode, we don't need any sound played when you've leveled up at all
  2061. /*
  2062. // Let the local player know he leveled up
  2063. if ( PlayerUserID == EventUserID )
  2064. {
  2065. // Play level-up gun game sound
  2066. C_RecipientFilter filter;
  2067. filter.AddRecipient( this );
  2068. //C_BaseEntity::EmitSound( filter, entindex(), "GunGameWeapon.LevelUp" );
  2069. m_StartOfRoundSoundEvents.AddSound( this, "GunGameWeapon.LevelUp", 0.10f );
  2070. // Play weapon name voiceover after a delay
  2071. // const char* pWeaponName = event->GetString( "weaponname" );
  2072. // if ( pWeaponName )
  2073. // {
  2074. // char weaponSoundName[64];
  2075. // Q_snprintf( weaponSoundName, 64, "GunGameWeapon.%s", pWeaponName );
  2076. //
  2077. // m_StartOfRoundSoundEvents.AddSound( this, weaponSoundName, 2.0f );
  2078. // }
  2079. }
  2080. */
  2081. }
  2082. else if ( Q_strcmp( "ggprogressive_player_levelup", name ) == 0 )
  2083. {
  2084. // Let the local player know he leveled up
  2085. if ( PlayerUserID == EventUserID )
  2086. {
  2087. // Play level-up gun game sound
  2088. C_RecipientFilter filter;
  2089. filter.AddRecipient( this );
  2090. C_BaseEntity::EmitSound( filter, entindex(), "GunGameWeapon.LevelUp" );
  2091. //C_BaseEntity::EmitSound( filter, entindex(), "UI.DeathMatchBonusKill" );
  2092. // Play weapon name voiceover immediately
  2093. // const char* pWeaponName = event->GetString( "weaponname" );
  2094. // if ( pWeaponName )
  2095. // {
  2096. // char weaponSoundName[64];
  2097. // Q_snprintf( weaponSoundName, 64, "GunGameWeapon.%s", pWeaponName );
  2098. //
  2099. // EmitSound( weaponSoundName );
  2100. // }
  2101. }
  2102. }
  2103. else if ( Q_strcmp( "gg_player_impending_upgrade", name ) == 0 )
  2104. {
  2105. // Let the local player know a level-up is impending
  2106. if ( PlayerUserID == EventUserID )
  2107. {
  2108. // Play level-up gun game sound
  2109. C_RecipientFilter filter;
  2110. filter.AddRecipient( this );
  2111. C_BaseEntity::EmitSound( filter, entindex(), "GunGameWeapon.ImpendingLevelUp" );
  2112. }
  2113. }
  2114. else if ( Q_strcmp( "gg_killed_enemy", name ) == 0 )
  2115. {
  2116. if ( CSGameRules()->IsPlayingGunGame() )
  2117. {
  2118. FirePerfStatsEvent( PERF_STATS_PLAYER );
  2119. if ( pLocalPlayer && pLocalPlayer->GetUserID() == event->GetInt( "attackerid" ) )
  2120. {
  2121. // if ( event->GetInt( "dominated" ) == 1 )
  2122. // {
  2123. // // Play gun game domination sound
  2124. // C_RecipientFilter filter;
  2125. // filter.AddRecipient( this );
  2126. // C_BaseEntity::EmitSound( filter, entindex(), "Music.GG_Dominating" );
  2127. // }
  2128. if ( event->GetInt( "revenge" ) == 1 )
  2129. {
  2130. // Play gun game revenge sound
  2131. C_RecipientFilter filter;
  2132. filter.AddRecipient( this );
  2133. C_BaseEntity::EmitSound( filter, entindex(), "Music.GG_Revenge" );
  2134. STEAMWORKS_TESTSECRETALWAYS_AMORTIZE( 7 );
  2135. }
  2136. if ( event->GetInt( "bonus" ) != 0 )
  2137. {
  2138. C_RecipientFilter filter;
  2139. filter.AddRecipient( this );
  2140. C_BaseEntity::EmitSound( filter, entindex(), "UI.DeathMatchBonusKill" );
  2141. }
  2142. else if ( CSGameRules()->IsPlayingGunGameDeathmatch() || CSGameRules()->IsPlayingGunGameProgressive() )
  2143. {
  2144. // Play level-up gun game sound because it's a better kill sound than the default one.
  2145. C_RecipientFilter filter;
  2146. filter.AddRecipient( this );
  2147. C_BaseEntity::EmitSound( filter, entindex(), "GunGameWeapon.ImpendingLevelUp" );
  2148. }
  2149. }
  2150. // else if ( pLocalPlayer && pLocalPlayer->GetUserID() == event->GetInt( "victimid" ) )
  2151. // {
  2152. // if ( event->GetInt( "dominated" ) == 1 )
  2153. // {
  2154. // // Play gun game nemesis sound
  2155. // C_RecipientFilter filter;
  2156. // filter.AddRecipient( this );
  2157. // C_BaseEntity::EmitSound( filter, entindex(), "GunGameWeapon.Nemesis" );
  2158. // }
  2159. // }
  2160. }
  2161. }
  2162. else if ( Q_strcmp( "gg_final_weapon_achieved", name ) == 0 )
  2163. {
  2164. int nGoldKnifeUserID = event->GetInt( "playerid", -1 );
  2165. if ( CSGameRules()->IsPlayingGunGameProgressive() && nGoldKnifeUserID == pLocalPlayer->GetUserID() )
  2166. {
  2167. // Play an audio cue corresponding to getting the final weapon
  2168. //EmitSound( "GunGameWeapon.AchievedFinalWeapon" );
  2169. GetCenterPrint()->Print( "#SFUI_Notice_Knife_Level_You" );
  2170. STEAMWORKS_TESTSECRETALWAYS_AMORTIZE( 13 );
  2171. }
  2172. else
  2173. {
  2174. C_BasePlayer *pGoldKnifeUser = static_cast<CBasePlayer *>( UTIL_PlayerByUserId( nGoldKnifeUserID ) );
  2175. if ( pGoldKnifeUser )
  2176. {
  2177. wchar_t wszLocalized[100];
  2178. wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
  2179. g_pVGuiLocalize->ConvertANSIToUnicode( pGoldKnifeUser->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) );
  2180. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_Knife_Level" ), 1, wszPlayerName );
  2181. GetCenterPrint()->Print( wszLocalized );
  2182. EmitSound("GunGame.PlayerReachedKnife");
  2183. }
  2184. }
  2185. }
  2186. else if ( Q_strcmp( "gg_bonus_grenade_achieved", name ) == 0 )
  2187. {
  2188. if ( CSGameRules()->IsPlayingGunGameTRBomb() )
  2189. {
  2190. if ( PlayerUserID == EventUserID )
  2191. {
  2192. // Play the bonus grenade voiceover after next round start
  2193. m_StartOfRoundSoundEvents.AddSound( this, "GunGameWeapon.AchievedBonusGrenade", 2.0f );
  2194. STEAMWORKS_TESTSECRETALWAYS_AMORTIZE( 23 );
  2195. }
  2196. }
  2197. }
  2198. else if ( Q_strcmp( "player_given_c4", name ) == 0 )
  2199. {
  2200. FirePerfStatsEvent( PERF_STATS_PLAYER );
  2201. if ( PlayerUserID == EventUserID )
  2202. {
  2203. // Play the voiceover for receiving the c4
  2204. STEAMWORKS_TESTSECRETALWAYS_AMORTIZE( 13 );
  2205. }
  2206. }
  2207. else if ( Q_strcmp( "item_pickup", name ) == 0 )
  2208. {
  2209. FirePerfStatsEvent( PERF_STATS_PLAYER );
  2210. if ( /*Q_strcmp( event->GetString( "item" ), "c4" ) == 0 &&*/
  2211. ( pLocalPlayer && pLocalPlayer->GetUserID() == EventUserID ) )
  2212. {
  2213. // if we aren't playing the sound on the server, play a "silent" version on the client
  2214. if ( event->GetBool( "silent" ) )
  2215. EmitSound( "Player.PickupWeaponSilent" );
  2216. STEAMWORKS_TESTSECRET_AMORTIZE( 67 );
  2217. }
  2218. }
  2219. else if ( Q_strcmp( "ammo_pickup", name ) == 0 )
  2220. {
  2221. FirePerfStatsEvent( PERF_STATS_PLAYER );
  2222. // this is to catch the case where a grenade was just thrown and we picked up another grenade immediately before the one iun our inventory has a chance to remove itself
  2223. // what happens here is that the one we just picked up adds to the "ammo" of the one that we have and we then remove the one that we picked up
  2224. C_CSPlayer *pObservedPlayer = GetHudPlayer();
  2225. // check if weapon was dropped by local player or the player we are observing
  2226. if ( pLocalPlayer && pObservedPlayer->GetUserID() == EventUserID )
  2227. {
  2228. C_WeaponCSBase *pWeapon = dynamic_cast<C_WeaponCSBase*>( ClientEntityList().GetEnt( event->GetInt( "index" ) ) );
  2229. if ( pWeapon && pWeapon->ShouldDrawPickup() )
  2230. {
  2231. CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
  2232. if ( pHudSelection )
  2233. {
  2234. pHudSelection->OnWeaponPickup( pWeapon );
  2235. }
  2236. }
  2237. }
  2238. }
  2239. else if ( Q_strcmp( "gg_leader", name ) == 0 )
  2240. {
  2241. if ( CSGameRules()->IsPlayingGunGameProgressive() || CSGameRules()->IsPlayingGunGameDeathmatch() )
  2242. {
  2243. if ( GetUserID() == event->GetInt("playerid" ) )
  2244. {
  2245. STEAMWORKS_TESTSECRETALWAYS_AMORTIZE( 11 );
  2246. /*
  2247. if ( !m_isCurrentGunGameLeader )
  2248. {
  2249. if ( this == C_BasePlayer::GetLocalPlayer() )
  2250. {
  2251. GetCenterPrint()->Print( "#SFUI_Notice_Gun_Game_Leader" );
  2252. }
  2253. //m_isCurrentGunGameLeader = true;
  2254. //m_isCurrentGunGameTeamLeader = true;
  2255. }
  2256. */
  2257. }
  2258. else
  2259. {
  2260. //m_isCurrentGunGameLeader = false;
  2261. //m_isCurrentGunGameTeamLeader = false;
  2262. }
  2263. // update the glow so it's up-to-date
  2264. m_fNextGlowCheckUpdate = gpGlobals->curtime;
  2265. m_fNextGlowCheckInterval = 0.1f;
  2266. UpdateGlows();
  2267. }
  2268. }
  2269. else if ( Q_strcmp( "gg_team_leader", name ) == 0 )
  2270. {
  2271. if ( CSGameRules()->IsPlayingGunGameProgressive() )
  2272. {
  2273. // update the glow so it's up-to-date
  2274. m_fNextGlowCheckUpdate = gpGlobals->curtime;
  2275. m_fNextGlowCheckInterval = 0.1f;
  2276. UpdateGlows();
  2277. }
  2278. }
  2279. else if ( Q_strcmp( "round_start", name ) == 0 )
  2280. {
  2281. //m_isCurrentGunGameLeader = false;
  2282. //m_isCurrentGunGameTeamLeader = false;
  2283. if( IsLocalPlayer( ) && !IsBot( ) )
  2284. {
  2285. ConVarRef round_start_reset_duck( "round_start_reset_duck" );
  2286. round_start_reset_duck.SetValue( true );
  2287. ConVarRef round_start_reset_speed( "round_start_reset_speed" );
  2288. round_start_reset_speed.SetValue( true );
  2289. }
  2290. UpdateGlowsForAllPlayers();
  2291. // Enable playback of the start of round sound events
  2292. m_StartOfRoundSoundEvents.PlaySounds();
  2293. if ( IsLocalPlayer() && CSGameRules() && CSGameRules()->IsPlayingGunGameDeathmatch() )
  2294. m_bShouldAutobuyDMWeapons = true;
  2295. m_totalHitsOnClient = 0;
  2296. m_isCurrentGunGameTeamLeader = false;
  2297. }
  2298. else if ( Q_strcmp( "round_end", name ) == 0 )
  2299. {
  2300. if ( IsLocalPlayer() )
  2301. {
  2302. // This code allowed us to measure discrepency between client and server bullet hits.
  2303. // It became obsolete when we started using a separate seed for client and server
  2304. // to eliminate 'rage' hacks.
  2305. //
  2306. CompareClientServerBulletHits();
  2307. if ( pLocalPlayer->IsAlive() )
  2308. RecordAmmoForRound();
  2309. }
  2310. }
  2311. else if ( Q_strcmp( "player_death", name ) == 0 )
  2312. {
  2313. FirePerfStatsEvent( PERF_STATS_PLAYER, 1 ); // don't look ahead: after the player is dead, framerate doesn't matter
  2314. C_BasePlayer *pPlayer = UTIL_PlayerByUserId( event->GetInt( "userid" ) );
  2315. C_CSPlayer* csPlayer = ToCSPlayer( pPlayer );
  2316. if ( csPlayer && pPlayer == C_BasePlayer::GetLocalPlayer() )
  2317. {
  2318. ConVarRef round_start_reset_duck( "round_start_reset_duck" );
  2319. round_start_reset_duck.SetValue( true );
  2320. ConVarRef round_start_reset_speed( "round_start_reset_speed" );
  2321. round_start_reset_speed.SetValue( true );
  2322. //reset target ID
  2323. m_iIDEntIndex = 0;
  2324. m_delayTargetIDTimer.Reset();
  2325. m_iOldIDEntIndex = 0;
  2326. m_holdTargetIDTimer.Reset();
  2327. m_iTargetedWeaponEntIndex = 0;
  2328. //// data collection for ammo remaining at death. OGS
  2329. RecordAmmoForRound();
  2330. if ( IsLocalPlayer() )
  2331. {
  2332. if ( CSGameRules() && CSGameRules()->GetActiveAssassinationQuest() && IsAssassinationTarget() )
  2333. {
  2334. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  2335. C_CS_PlayerResource *pCSRes = GetCSResources();
  2336. if ( pElement && pCSRes )
  2337. {
  2338. wchar_t szBuf[ 512 ];
  2339. wchar_t wszName[ MAX_DECORATED_PLAYER_NAME_LENGTH ] = { };
  2340. pCSRes->GetDecoratedPlayerName( entindex(), wszName, sizeof( wszName ), k_EDecoratedPlayerNameFlag_Simple );
  2341. g_pVGuiLocalize->ConstructString( szBuf, sizeof( szBuf ), g_pVGuiLocalize->Find( "#quest_assassination_no_longer_target" ), 1, wszName );
  2342. ( ( SFHudInfoPanel * )pElement )->SetPriorityHintText( szBuf );
  2343. }
  2344. }
  2345. }
  2346. }
  2347. if( CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() && !g_HltvReplaySystem.GetHltvReplayDelay() )
  2348. {
  2349. if (csPlayer && csPlayer->IsLocalPlayer())
  2350. {
  2351. C_RecipientFilter filter;
  2352. filter.AddRecipient( this );
  2353. PlayMusicSelection( filter, CSMUSIC_DEATHCAM );
  2354. }
  2355. }
  2356. UpdateGlowsForAllPlayers();
  2357. }
  2358. else if ( Q_strcmp( "player_spawn", name ) == 0 )
  2359. {
  2360. FirePerfStatsEvent( PERF_STATS_PLAYER, 16, 1 );// look ahead, but not back
  2361. if ( PlayerUserID == EventUserID )
  2362. {
  2363. // we've just spawned, so reset our entity id stuff
  2364. m_iIDEntIndex = 0;
  2365. m_delayTargetIDTimer.Reset();
  2366. m_iOldIDEntIndex = 0;
  2367. m_holdTargetIDTimer.Reset();
  2368. m_iTargetedWeaponEntIndex = 0;
  2369. m_flLastFiredWeaponTime = 0;
  2370. m_nLastKillerDamageTaken = 0;
  2371. m_nLastKillerHitsTaken = 0;
  2372. m_nLastKillerDamageGiven = 0;
  2373. m_nLastKillerHitsGiven = 0;
  2374. m_flHealthFadeValue = 100.0f;
  2375. m_flHealthFadeAlpha = 0.0f;
  2376. RemoveC4Effect( false );
  2377. CancelFreezeCamFlashlightEffect();
  2378. CreateClientEffectModels();
  2379. if ( IsLocalPlayer() && CSGameRules() && CSGameRules()->IsPlayingGunGameDeathmatch() )
  2380. m_bShouldAutobuyDMWeapons = true;
  2381. //
  2382. //if ( IsLocalPlayer() && !IsBot() )
  2383. //{
  2384. // UI_COMPONENT_BROADCAST_EVENT( GameState, PlayerSpawning )
  2385. //}
  2386. ClearAllBulletHitModels();
  2387. // This code allowed us to measure discrepency between client and server bullet hits.
  2388. // It became obsolete when we started using a separate seed for client and server
  2389. // to eliminate 'rage' hacks.
  2390. //
  2391. m_vecBulletVerifyListClient.RemoveAll();
  2392. m_vecBulletVerifyListServer.RemoveAll();
  2393. m_ui8ClientServerHitDifference = 0;
  2394. UpdateAddonModels( true );
  2395. m_flLastSpawnTimeIndex = gpGlobals->curtime;
  2396. m_pViewmodelArmConfig = NULL;
  2397. if ( m_bUseNewAnimstate && m_PlayerAnimStateCSGO )
  2398. {
  2399. m_PlayerAnimStateCSGO->Reset();
  2400. }
  2401. }
  2402. if ( IsLocalPlayer() )
  2403. {
  2404. UpdateGlowsForAllPlayers();
  2405. if ( CSGameRules() && CSGameRules()->IsPlayingGunGameProgressive() )
  2406. {
  2407. m_isCurrentGunGameTeamLeader = entindex() == GetGlobalTeam( GetTeamNumber() )->GetGGLeader( GetTeamNumber() );
  2408. }
  2409. }
  2410. }
  2411. else if ( Q_strcmp( "weapon_fire", name ) == 0 )
  2412. {
  2413. if ( PlayerUserID == EventUserID )
  2414. {
  2415. // we just fired our weapon
  2416. m_flLastFiredWeaponTime = gpGlobals->curtime;
  2417. }
  2418. }
  2419. else if ( Q_strcmp( "assassination_target_killed", name ) == 0 )
  2420. {
  2421. if ( CSGameRules() && CSGameRules()->GetActiveAssassinationQuest() && IsLocalPlayer() )
  2422. {
  2423. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  2424. C_CS_PlayerResource *pCSRes = GetCSResources();
  2425. CEconQuestDefinition *pQuest = CSGameRules()->GetActiveAssassinationQuest();
  2426. wchar_t wszName[ MAX_DECORATED_PLAYER_NAME_LENGTH ] = {};
  2427. if ( pElement && pCSRes && Helper_GetDecoratedAssassinationTargetName( pQuest, wszName, ARRAYSIZE( wszName ) ) )
  2428. {
  2429. wchar_t szBuf[ 512 ];
  2430. g_pVGuiLocalize->ConstructString( szBuf, sizeof( szBuf ), g_pVGuiLocalize->Find( "#quest_assassination_target_killed" ), 1, wszName );
  2431. ( ( SFHudInfoPanel * ) pElement )->SetPriorityHintText( szBuf );
  2432. }
  2433. }
  2434. }
  2435. else if ( Q_strcmp( "add_bullet_hit_marker", name ) == 0 )
  2436. {
  2437. //FirePerfStatsEvent( PERF_STATS_BULLET );
  2438. if ( PlayerUserID == EventUserID )
  2439. {
  2440. int nBoneIndex = event->GetInt( "bone", 0 );
  2441. Vector hitPos = Vector( event->GetFloat("pos_x",0), event->GetFloat("pos_y",0), event->GetFloat("pos_z",0) );
  2442. QAngle hitAng = QAngle( event->GetFloat("ang_x",0), event->GetFloat("ang_y",0), event->GetFloat("ang_z",0) );
  2443. Vector vecStartPos = Vector( event->GetFloat("start_x",0), event->GetFloat("start_y",0), event->GetFloat("start_z",0) );
  2444. if ( nBoneIndex >= 0 && hitPos.IsValid() && hitAng.IsValid() )
  2445. {
  2446. VMatrix matLocalOffset = SetupMatrixOrgAngles( hitPos, hitAng );
  2447. C_BulletHitModel *pBulletHitModel = new C_BulletHitModel();
  2448. pBulletHitModel->AttachToPlayer( this, nBoneIndex, matLocalOffset.As3x4(), event->GetBool( "hit", false ), vecStartPos );
  2449. m_vecBulletHitModels.AddToTail( pBulletHitModel );
  2450. if ( m_vecBulletHitModels.Count() > 25 )
  2451. {
  2452. m_vecBulletHitModels[0]->Release();
  2453. m_vecBulletHitModels.Remove(0);
  2454. }
  2455. }
  2456. }
  2457. }
  2458. }
  2459. // This code allowed us to measure discrepency between client and server bullet hits.
  2460. // It became obsolete when we started using a separate seed for client and server
  2461. // to eliminate 'rage' hacks.
  2462. //
  2463. bool __MsgFunc_ReportHit( const CCSUsrMsg_ReportHit &msg )
  2464. {
  2465. if ( msg.has_pos_x() && msg.has_pos_y() && msg.has_pos_z() && msg.has_timestamp() )
  2466. {
  2467. Vector vecServerHitPos = Vector( msg.pos_x(), msg.pos_y(), msg.pos_z() );
  2468. float flServerHitTime = msg.timestamp();
  2469. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  2470. if ( pPlayer )
  2471. {
  2472. C_CSPlayer* pCSPlayer = ToCSPlayer( pPlayer );
  2473. if ( pCSPlayer)
  2474. {
  2475. pCSPlayer->m_vecBulletVerifyListServer.AddToTail( clientHitVerify_t( vecServerHitPos, flServerHitTime, gpGlobals->curtime + 10 ) );
  2476. }
  2477. }
  2478. }
  2479. return true;
  2480. }
  2481. USER_MESSAGE_REGISTER( ReportHit );
  2482. void C_CSPlayer::CompareClientServerBulletHits( void )
  2483. {
  2484. bool bAllowVisDebug = false;
  2485. AccountID_t uiLocalAccountID = 0;
  2486. if ( steamapicontext && steamapicontext->SteamUser() )
  2487. uiLocalAccountID = steamapicontext->SteamUser()->GetSteamID().GetAccountID();
  2488. switch( uiLocalAccountID )
  2489. {
  2490. case 8186565: // mattw
  2491. case 158213: // ido
  2492. case 24715681: // vitaliy
  2493. case 101804581: // will
  2494. case 11134320: // brianlev
  2495. bAllowVisDebug = true;
  2496. }
  2497. // remove server hits that have matching hits on client
  2498. FOR_EACH_VEC_BACK( m_vecBulletVerifyListServer, s )
  2499. {
  2500. FOR_EACH_VEC_BACK( m_vecBulletVerifyListClient, c )
  2501. {
  2502. if ( CloseEnough( m_vecBulletVerifyListServer[ s ].vecPosition, m_vecBulletVerifyListClient[ c ].vecPosition, 1.0f ) )
  2503. {
  2504. m_vecBulletVerifyListServer.Remove( s );
  2505. break;
  2506. }
  2507. }
  2508. }
  2509. // record the unmatched server hits.
  2510. m_ui8ClientServerHitDifference = MIN( 255, m_vecBulletVerifyListServer.Count() );
  2511. m_vecBulletVerifyListServer.RemoveAll();
  2512. m_vecBulletVerifyListClient.RemoveAll();
  2513. }
  2514. //=============================================================================
  2515. // HPE_END
  2516. //=============================================================================
  2517. static void ClientBuyHelperForwardToServer( char const *szCommand, char const *szParam )
  2518. {
  2519. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  2520. if ( !pPlayer )
  2521. return;
  2522. if ( engine->IsHLTV() )
  2523. return;
  2524. if ( !szParam )
  2525. {
  2526. // just forward the command without parameters
  2527. engine->ServerCmd( szCommand );
  2528. }
  2529. else
  2530. {
  2531. // forward the command with parameter
  2532. char command[ 256 ] = {};
  2533. Q_snprintf( command, sizeof( command ), "%s \"%s\"", szCommand, szParam );
  2534. engine->ServerCmd( command );
  2535. }
  2536. }
  2537. CON_COMMAND_F( autobuy, "Attempt to purchase items with the order listed in cl_autobuy", FCVAR_CLIENTCMD_CAN_EXECUTE )
  2538. {
  2539. extern ConVar cl_autobuy;
  2540. ClientBuyHelperForwardToServer( "autobuy", cl_autobuy.GetString() );
  2541. }
  2542. CON_COMMAND_F( rebuy, "Attempt to repurchase items with the order listed in cl_rebuy", FCVAR_CLIENTCMD_CAN_EXECUTE )
  2543. {
  2544. extern ConVar cl_rebuy;
  2545. ClientBuyHelperForwardToServer( "rebuy", cl_rebuy.GetString() );
  2546. }
  2547. CON_COMMAND_F( dm_togglerandomweapons, "Turns random weapons in deathmatch on/off", FCVAR_CLIENTCMD_CAN_EXECUTE | FCVAR_SERVER_CAN_EXECUTE )
  2548. {
  2549. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  2550. C_CSPlayer* pPlayer = ToCSPlayer(pLocalPlayer);
  2551. if ( pPlayer )
  2552. pPlayer->ToggleRandomWeapons();
  2553. }
  2554. void C_CSPlayer::ToggleRandomWeapons( void )
  2555. {
  2556. ConVarRef cl_dm_buyrandomweapons( "cl_dm_buyrandomweapons" );
  2557. float flTimeLeft = m_fImmuneToGunGameDamageTime - gpGlobals->curtime;
  2558. if ( cl_dm_buyrandomweapons.GetBool() )
  2559. {
  2560. cl_dm_buyrandomweapons.SetValue(false);
  2561. if ( flTimeLeft <= 0 )
  2562. {
  2563. GetCenterPrint()->Print( "#SFUI_Notice_DM_RandomOFF" );
  2564. }
  2565. }
  2566. else
  2567. {
  2568. cl_dm_buyrandomweapons.SetValue(true);
  2569. if ( flTimeLeft <= 0 )
  2570. {
  2571. GetCenterPrint()->Print( "#SFUI_Notice_DM_RandomON" );
  2572. }
  2573. engine->ClientCmd_Unrestricted( "buyrandom" );
  2574. }
  2575. CLocalPlayerFilter filter;
  2576. EmitSound( filter, GetSoundSourceIndex(), "BuyPreset.Updated" );
  2577. }
  2578. bool C_CSPlayer::ShouldShowTeamPlayerColors( int nOtherTeamNum )
  2579. {
  2580. ConVarRef cl_teammate_colors_show( "cl_teammate_colors_show" );
  2581. if ( cl_teammate_colors_show.GetBool( ) == false || engine->IsHLTV( ) )
  2582. return false;
  2583. if ( nOtherTeamNum != TEAM_CT && nOtherTeamNum != TEAM_TERRORIST )
  2584. return false;
  2585. int nMaxPlayers = CCSGameRules::GetMaxPlayers();
  2586. bool bShowColor = (nMaxPlayers <= 10) && CSGameRules() && CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() && (nOtherTeamNum == GetTeamNumber());
  2587. return bShowColor;
  2588. }
  2589. bool C_CSPlayer::ShouldShowTeamPlayerColorLetters( void )
  2590. {
  2591. ConVarRef cl_teammate_colors_show( "cl_teammate_colors_show" );
  2592. if ( cl_teammate_colors_show.GetInt() == 2 && engine->IsHLTV() == false )
  2593. return true;
  2594. return false;
  2595. }
  2596. static void ForwardEndMatchVoteNextMapToServer( const CCommand &args )
  2597. {
  2598. if ( engine->IsPlayingDemo() )
  2599. return;
  2600. if ( args.ArgC() == 1 )
  2601. {
  2602. // just forward the command without parameters
  2603. engine->ServerCmd( args[ 0 ] );
  2604. }
  2605. else if ( args.ArgC() == 2 )
  2606. {
  2607. // forward the command with parameter
  2608. char command[128];
  2609. Q_snprintf( command, sizeof(command), "%s \"%s\"", args[ 0 ], args[ 1 ] );
  2610. engine->ServerCmd( command );
  2611. }
  2612. }
  2613. CON_COMMAND_F( endmatch_votenextmap, "Votes for the next map at the end of the match", FCVAR_CLIENTCMD_CAN_EXECUTE )
  2614. {
  2615. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  2616. if ( !pPlayer || g_bEngineIsHLTV || pPlayer->GetTeamNumber() == TEAM_SPECTATOR )
  2617. return;
  2618. if ( args.ArgC() != 2 )
  2619. return;
  2620. ForwardEndMatchVoteNextMapToServer( args );
  2621. }
  2622. void C_CSPlayer::UpdateGlowsForAllPlayers( void )
  2623. {
  2624. for ( int i = 1; i <= MAX_PLAYERS; i++ )
  2625. {
  2626. C_CSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
  2627. if ( pPlayer )
  2628. {
  2629. pPlayer->UpdateGlows();
  2630. }
  2631. }
  2632. }
  2633. static bool GlowEffectHLTVReplay( C_CSPlayer* thisPlayer, C_CSPlayer* pLocalPlayer, GlowRenderStyle_t& glowStyle, Vector& glowColor, float& alphaStart, float& alpha, float& timeStart, float& timeTarget, bool& animate )
  2634. {
  2635. if ( g_HltvReplaySystem.GetHltvReplayDelay() && spec_replay_outline.GetInt() != 3 )
  2636. {
  2637. if ( spec_replay_outline.GetInt() && ( thisPlayer->entindex() == g_HltvReplaySystem.GetPrimaryVictimEntIndex() ) )
  2638. {
  2639. glowColor.Init( 1, 1, 1 );
  2640. alpha = 0.6f;
  2641. return true;
  2642. }
  2643. }
  2644. else if ( g_HltvReplaySystem.IsDemoPlayback() && g_HltvReplaySystem.IsDemoPlaybackLowLights() && spec_replay_outline.GetInt() )
  2645. {
  2646. if ( g_HltvReplaySystem.GetDemoPlaybackPlayer() == thisPlayer )
  2647. {
  2648. glowColor.Init( 1, 1, 1 );
  2649. alpha = 0.8f;
  2650. return true;
  2651. }
  2652. }
  2653. return false;
  2654. }
  2655. static bool GlowEffectSensorGrenade( C_CSPlayer* thisPlayer, C_CSPlayer* pLocalPlayer, GlowRenderStyle_t& glowStyle, Vector& glowColor, float& alphaStart, float& alpha, float& timeStart, float& timeTarget, bool& animate )
  2656. {
  2657. float detectionTime = thisPlayer->m_flDetectedByEnemySensorTime;
  2658. // If we weren't detected by a sensor grenade, no glow
  2659. if ( detectionTime <= 0.0f )
  2660. return false;
  2661. // If we are on the same team as the detected player, don't show
  2662. if ( !pLocalPlayer )
  2663. return false;
  2664. if( pLocalPlayer->GetTeamNumber() == thisPlayer->GetTeamNumber() )
  2665. return false;
  2666. // If the detection was too long ago, no glow
  2667. static const float kSensorGlowTime = 5.0f;
  2668. if ( gpGlobals->curtime > ( detectionTime + kSensorGlowTime ) )
  2669. return false;
  2670. // glow red
  2671. glowColor.x = ( 255.0f / 255.0f );
  2672. glowColor.y = ( 78.0f / 255.0f );
  2673. glowColor.z = ( 78.0f / 255.0f );
  2674. // Animate from max to 0 over the sensor duration
  2675. alphaStart = 0.6f;
  2676. timeStart = detectionTime;
  2677. alpha = 0.0f;
  2678. timeTarget = detectionTime + kSensorGlowTime;
  2679. animate = true;
  2680. return true;
  2681. }
  2682. static bool GlowEffectGunGameLeader( C_CSPlayer* thisPlayer, C_CSPlayer* pLocalPlayer, GlowRenderStyle_t& glowStyle, Vector& glowColor, float& alphaStart, float& alpha, float& timeStart, float& timeTarget, bool& animate )
  2683. {
  2684. if ( !pLocalPlayer )
  2685. return false;
  2686. if ( !CSGameRules()->IsPlayingGunGameProgressive() )
  2687. return false;
  2688. // Get current player's team
  2689. int nTeam = -1;
  2690. if ( thisPlayer->GetTeamNumber() == TEAM_CT )
  2691. nTeam = TEAM_CT;
  2692. else if ( thisPlayer->GetTeamNumber() == TEAM_TERRORIST )
  2693. nTeam = TEAM_TERRORIST;
  2694. // If current player isn't on a team, they won't glow
  2695. if ( nTeam == -1 )
  2696. return false;
  2697. // if this player isn't winning on their team, they don't glow
  2698. C_Team *team = GetGlobalTeam( nTeam );
  2699. if ( !team )
  2700. return false;
  2701. if ( team->GetGGLeader( nTeam ) != thisPlayer->entindex() )
  2702. return false;
  2703. #if 0
  2704. // if this player hasn't fired for a while, they don't glow
  2705. // (REMOVED)
  2706. if ( thisPlayer->m_flLastFiredWeaponTime > 0 )
  2707. {
  2708. if ( gpGlobals->curTime > ( thisPlayer->m_flLastFiredWeaponTime + 4.0f ) )
  2709. return false;
  2710. }
  2711. #endif
  2712. // if the player is at gold knife level, they don't glow
  2713. int nMaxIndex = CSGameRules()->GetNumProgressiveGunGameWeapons( nTeam ) - 1;
  2714. if ( thisPlayer->m_iGunGameProgressiveWeaponIndex >= nMaxIndex )
  2715. return false;
  2716. // If the local player is leading their team, they don't get to see the glow
  2717. if ( pLocalPlayer->m_isCurrentGunGameTeamLeader
  2718. || pLocalPlayer->entindex() == GetGlobalTeam( pLocalPlayer->GetTeamNumber() )->GetGGLeader( pLocalPlayer->GetTeamNumber() ) )
  2719. return false;
  2720. // Otherwise they glow. Pick a color based on the team. Spectators always see team color glow, but players in-game just see red for the opposing leader.
  2721. if ( pLocalPlayer->GetTeamNumber() != nTeam && ( pLocalPlayer->GetTeamNumber() == TEAM_CT || pLocalPlayer->GetTeamNumber() == TEAM_TERRORIST ) )
  2722. {
  2723. // "enemy", red
  2724. glowColor.x = ( 255.0f / 255.0f );
  2725. glowColor.y = ( 78.0f / 255.0f );
  2726. glowColor.z = ( 78.0f / 255.0f );
  2727. }
  2728. else if ( nTeam == TEAM_CT )
  2729. {
  2730. // CT teammate blue
  2731. glowColor.x = ( 114.0f / 255.0f );
  2732. glowColor.y = ( 155.0f / 255.0f );
  2733. glowColor.z = ( 221.0f / 255.0f );
  2734. }
  2735. else if ( nTeam == TEAM_TERRORIST )
  2736. {
  2737. // T teammate yellow
  2738. glowColor.x = ( 224.0f / 255.0f );
  2739. glowColor.y = ( 175.0f / 255.0f );
  2740. glowColor.z = ( 86.0f / 255.0f );
  2741. }
  2742. // this is arms race glow, so use the edge highlight pulse effect style (doesn't show through walls)
  2743. glowStyle = GLOWRENDERSTYLE_EDGE_HIGHLIGHT;
  2744. // gun game alpha is the default 0.6f
  2745. alpha = 0.6f;
  2746. return true;
  2747. }
  2748. static bool GlowEffectSpectator( C_CSPlayer* thisPlayer, C_CSPlayer* pLocalPlayer, GlowRenderStyle_t& glowStyle, Vector& glowColor, float& alphaStart, float& alpha, float& timeStart, float& timeTarget, bool& animate )
  2749. {
  2750. // Spectator rendering
  2751. if ( !pLocalPlayer )
  2752. return false;
  2753. C_CS_PlayerResource *cs_PR = dynamic_cast< C_CS_PlayerResource * >( g_PR );
  2754. if ( cs_PR )
  2755. {
  2756. if ( cs_PR->GetTeam( thisPlayer->entindex() ) != thisPlayer->GetTeamNumber() )
  2757. {
  2758. //Msg( "Player resource disagrees on player team: %s\n", GetPlayerName() );
  2759. return false;
  2760. }
  2761. }
  2762. bool bRenderForSpectator = ( CanSeeSpectatorOnlyTools() && spec_show_xray.GetInt() );
  2763. if ( !bRenderForSpectator && ( pLocalPlayer->IsAlive() || ( pLocalPlayer->GetObserverMode() <= OBS_MODE_FREEZECAM ) ) )
  2764. return false;
  2765. bool bRender = false;
  2766. if ( mp_teammates_are_enemies.GetBool() && thisPlayer->IsOtherEnemy( pLocalPlayer->entindex() ) ) // if everyone is an enemy
  2767. {
  2768. // red
  2769. glowColor.x = ( 242.0f / 255.0f );
  2770. glowColor.y = ( 117.0f / 255.0f );
  2771. glowColor.z = ( 117.0f / 255.0f );
  2772. bRender = true;
  2773. }
  2774. else if ( ( thisPlayer->GetTeamNumber() == TEAM_CT ) && ( bRenderForSpectator || ( pLocalPlayer->GetAssociatedTeamNumber() == TEAM_CT ) ) )
  2775. {
  2776. // blue
  2777. glowColor.x = ( 114.0f / 255.0f );
  2778. glowColor.y = ( 155.0f / 255.0f );
  2779. glowColor.z = ( 221.0f / 255.0f );
  2780. bRender = true;
  2781. }
  2782. else if ( ( thisPlayer->GetTeamNumber() == TEAM_TERRORIST ) && ( bRenderForSpectator || ( pLocalPlayer->GetAssociatedTeamNumber() == TEAM_TERRORIST ) ) )
  2783. {
  2784. // yellow
  2785. glowColor.x = ( 224.0f / 255.0f );
  2786. glowColor.y = ( 175.0f / 255.0f );
  2787. glowColor.z = ( 86.0f / 255.0f );
  2788. bRender = true;
  2789. }
  2790. // Check for xray highlight of currently selected player
  2791. int nTargetSpec = g_bEngineIsHLTV ? HLTVCamera()->GetCurrentOrLastTarget() : ( pLocalPlayer->GetObserverTarget() ? pLocalPlayer->GetObserverTarget()->entindex() : -1 );
  2792. if ( nTargetSpec == thisPlayer->entindex() )
  2793. {
  2794. bool bShowSelected =
  2795. // we must alraedy be eligible to xray this player to highlight them as selected
  2796. bRender &&
  2797. // $$$REI I think this is a proxy for "is this a competitive mode game"
  2798. ( CCSGameRules::GetMaxPlayers() <= 10 ) &&
  2799. // no selection highlight in dm/armsrace ($$$REI Why?)
  2800. !( CSGameRules()->IsPlayingGunGameDeathmatch() || CSGameRules()->IsPlayingGunGameProgressive() ) &&
  2801. // must be in 'free' observer mode otherwise we are already tethered to the selected player
  2802. ( pLocalPlayer->GetObserverMode() == OBS_MODE_FIXED || pLocalPlayer->GetObserverMode() == OBS_MODE_ROAMING );
  2803. // always highlight the selected player when we are interpolating to them
  2804. if ( pLocalPlayer->IsInObserverInterpolation() )
  2805. bShowSelected = true;
  2806. if ( bShowSelected )
  2807. {
  2808. glowColor.x = ( 255.0f / 255.0f );
  2809. glowColor.y = ( 255.0f / 255.0f );
  2810. glowColor.z = ( 255.0f / 255.0f );
  2811. bRender = true;
  2812. }
  2813. }
  2814. if ( !bRender )
  2815. return false;
  2816. // turn down spectator xray if player is quiet
  2817. float fSpecGlowSilentFactor = spec_glow_silent_factor.GetFloat();
  2818. float fSpecGlowSpikeFactor = spec_glow_spike_factor.GetFloat();
  2819. float fSpecGlowFullTime = spec_glow_full_time.GetFloat();
  2820. float fSpecGlowDecayTime = spec_glow_decay_time.GetFloat();
  2821. float fSpecGlowSpikeTime = spec_glow_spike_time.GetFloat();
  2822. float lastNoiseTime = thisPlayer->m_flLastMadeNoiseTime;
  2823. if ( gpGlobals->curtime >= ( lastNoiseTime + fSpecGlowFullTime + fSpecGlowDecayTime ) )
  2824. {
  2825. // quiet
  2826. alpha = fSpecGlowSilentFactor;
  2827. }
  2828. else if( gpGlobals->curtime >= ( lastNoiseTime + fSpecGlowFullTime ) )
  2829. {
  2830. // animate to 'quiet' alpha over the decay time
  2831. timeStart = lastNoiseTime + fSpecGlowFullTime;
  2832. alphaStart = 1.0f;
  2833. timeTarget = lastNoiseTime + fSpecGlowFullTime + fSpecGlowDecayTime;
  2834. alpha = fSpecGlowSilentFactor;
  2835. animate = true;
  2836. }
  2837. else if( gpGlobals->curtime >= ( lastNoiseTime + fSpecGlowSpikeTime * 2.0f ) )
  2838. {
  2839. // regular "recently noisy" level. still use 'animation' code here so we get a notification when full time expires
  2840. timeStart = lastNoiseTime + fSpecGlowSpikeTime * 2.0f;
  2841. alphaStart = 1.0f;
  2842. timeTarget = lastNoiseTime + fSpecGlowFullTime;
  2843. alpha = 1.0f;
  2844. animate = true;
  2845. }
  2846. else if( gpGlobals->curtime >= ( lastNoiseTime + fSpecGlowSpikeTime ) )
  2847. {
  2848. // animate from spiked value to 1.0f
  2849. timeStart = lastNoiseTime + fSpecGlowSpikeTime;
  2850. alphaStart = fSpecGlowSpikeFactor;
  2851. timeTarget = lastNoiseTime + fSpecGlowSpikeTime * 2.0f;
  2852. alpha = 1.0f;
  2853. animate = true;
  2854. }
  2855. else if ( gpGlobals->curtime >= lastNoiseTime )
  2856. {
  2857. // animate from current alpha to spike
  2858. // note that we use current time here, instead of lastnoisetime. this is because we might not update right away when the noise happens
  2859. // if we are off by too much, we might lose the spike-drop animation, but that's better than losing the spike start animation.
  2860. // if we really care, we could store an extra variable saying we are in the spike animation, but i might cut this feature anyways.
  2861. timeStart = gpGlobals->curtime;
  2862. alphaStart = alphaStart * (1.0f / 0.6f); // we are going to multiply by 0.6f below; we really want to leave it untouched
  2863. timeTarget = gpGlobals->curtime + fSpecGlowSpikeTime;
  2864. alpha = fSpecGlowSpikeFactor;
  2865. animate = true;
  2866. }
  2867. else
  2868. {
  2869. // somehow we made noise in the future? just treat it as normal
  2870. alpha = 1.0f;
  2871. }
  2872. // drop values (remnant of legacy glow code that 1.0 really means 0.6)
  2873. alpha *= 0.6f;
  2874. alphaStart *= 0.6f;
  2875. return true;
  2876. }
  2877. typedef bool( *tGetGlowFunc )( C_CSPlayer* thisPlayer, C_CSPlayer* localPlayer, GlowRenderStyle_t& glowStyle, Vector& glowColor, float& alphaStart, float& alpha, float& timeStart, float& timeTarget, bool& animate );
  2878. void C_CSPlayer::UpdateGlows( void )
  2879. {
  2880. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  2881. //////////////////////////////////////////////////////////////////////////
  2882. // First handle screen effects
  2883. // TODO: Doesn't really belong in UpdateGlow(), but right now they update
  2884. // at the same time as glow effects
  2885. // If we are winning arms race so that we glow to other players, put a glow effect on our screen to warn us
  2886. if ( CSGameRules()->IsPlayingGunGameProgressive()
  2887. && pLocalPlayer == this
  2888. && IsAlive()
  2889. && ( m_isCurrentGunGameTeamLeader || entindex() == GetGlobalTeam( GetTeamNumber() )->GetGGLeader( GetTeamNumber() ) )
  2890. && ( m_iGunGameProgressiveWeaponIndex < ( CSGameRules()->GetNumProgressiveGunGameWeapons( GetTeamNumber() ) - 1 ) )
  2891. )
  2892. {
  2893. float flAlphaScaler = 1.0f; // was some commented out code here to fade it based on time since firing
  2894. if ( !m_ARScreenGlowEffect.IsValid() )
  2895. {
  2896. Vector vecOffset = Vector( 0, 0, 64 );//GetEyeOffset();
  2897. m_ARScreenGlowEffect = ParticleProp()->Create( "ar_screenglow_leader_red", PATTACH_CUSTOMORIGIN );
  2898. if ( m_ARScreenGlowEffect.IsValid() )
  2899. {
  2900. //m_ARScreenGlowEffect->m_pDef->SetDrawThroughLeafSystem( false );
  2901. ParticleProp()->AddControlPoint( m_ARScreenGlowEffect, 1, this, PATTACH_CUSTOMORIGIN );
  2902. m_ARScreenGlowEffect->SetControlPointEntity( 0, this );
  2903. m_ARScreenGlowEffect->SetControlPointEntity( 1, this );
  2904. m_ARScreenGlowEffect->SetControlPoint( 0, GetAbsOrigin() );
  2905. m_ARScreenGlowEffect->SetControlPoint( 1, Vector( flAlphaScaler*0.65, 0, 0 ) );
  2906. m_ARScreenGlowEffect->StartEmission();
  2907. m_ARScreenGlowEffect->SetDrawn( true );
  2908. }
  2909. }
  2910. else // m_ARScreenGlowEffect.IsValid()
  2911. {
  2912. m_ARScreenGlowEffect->SetControlPoint( 1, Vector( flAlphaScaler*0.65, 0, 0 ) );
  2913. if ( flAlphaScaler > 0 )
  2914. m_fNextGlowCheckInterval = 0.05f;
  2915. }
  2916. }
  2917. else if ( m_ARScreenGlowEffect.IsValid() )
  2918. {
  2919. m_ARScreenGlowEffect->StopEmission();
  2920. m_ARScreenGlowEffect->SetRemoveFlag();
  2921. m_ARScreenGlowEffect = NULL;
  2922. }
  2923. // in order of priority
  2924. static const tGetGlowFunc kGlowFuncs[] =
  2925. {
  2926. GlowEffectHLTVReplay,
  2927. GlowEffectSensorGrenade,
  2928. GlowEffectGunGameLeader,
  2929. GlowEffectSpectator,
  2930. nullptr
  2931. };
  2932. m_fNextGlowCheckInterval = GLOWUPDATE_DEFAULT_THINK_INTERVAL;
  2933. bool bRender = false;
  2934. Vector glowColor = vec3_origin;
  2935. GlowRenderStyle_t glowStyle = GLOWRENDERSTYLE_DEFAULT;
  2936. // bool bRenderInside = false;
  2937. float flAlphaStart = m_fGlowAlpha;
  2938. float flAlpha = 1.0f;
  2939. float flAlphaStartTime = gpGlobals->curtime;
  2940. float flAlphaTargetTime = gpGlobals->curtime;
  2941. bool animate = false;
  2942. for ( const tGetGlowFunc* pGlowFunc = kGlowFuncs; *pGlowFunc != nullptr; ++pGlowFunc )
  2943. {
  2944. if ( ( *pGlowFunc )( this, pLocalPlayer, glowStyle, glowColor, flAlphaStart, flAlpha, flAlphaStartTime, flAlphaTargetTime, animate ) )
  2945. {
  2946. bRender = true;
  2947. break;
  2948. }
  2949. }
  2950. m_GlowObject.SetRenderFlags( bRender, false );
  2951. //m_GlowObject.SetRenderFlags( !bRenderInside, bRender, bRenderInside );
  2952. m_GlowObject.SetRenderStyle( glowStyle );
  2953. m_GlowObject.SetColor( glowColor );
  2954. if( bRender && animate )
  2955. {
  2956. // set up animation
  2957. if(flAlphaTargetTime > flAlphaStartTime && flAlphaTargetTime > gpGlobals->curtime )
  2958. {
  2959. m_fGlowAlpha = Lerp( ( gpGlobals->curtime - flAlphaStartTime ) / ( flAlphaTargetTime - flAlphaStartTime ), flAlphaStart, flAlpha );
  2960. m_fGlowAlphaTarget = flAlpha;
  2961. m_fGlowAlphaTargetTime = flAlphaTargetTime;
  2962. }
  2963. else
  2964. {
  2965. m_fGlowAlphaTargetTime = -1.0f;
  2966. m_fGlowAlpha = m_fGlowAlphaTarget = flAlpha;
  2967. }
  2968. }
  2969. else
  2970. {
  2971. m_fGlowAlphaTargetTime = -1.0f;
  2972. m_fGlowAlpha = m_fGlowAlphaTarget = flAlpha;
  2973. }
  2974. m_fGlowAlphaUpdateTime = gpGlobals->curtime;
  2975. m_GlowObject.SetAlpha( bRender ? m_fGlowAlpha : 0.0f );
  2976. }
  2977. void C_CSPlayer::AnimateGlows( void )
  2978. {
  2979. // Lerp towards the target
  2980. float totalTimeRemaining = m_fGlowAlphaTargetTime - m_fGlowAlphaUpdateTime;
  2981. float timeUsed = gpGlobals->curtime - m_fGlowAlphaUpdateTime;
  2982. float percent;
  2983. if ( timeUsed < totalTimeRemaining && totalTimeRemaining > 0 )
  2984. {
  2985. percent = timeUsed / totalTimeRemaining;
  2986. }
  2987. else
  2988. {
  2989. percent = 1.0f;
  2990. }
  2991. if ( percent < 1.0f )
  2992. {
  2993. // animate
  2994. float newAlpha = Lerp( percent, m_fGlowAlpha, m_fGlowAlphaTarget );
  2995. m_fGlowAlpha = newAlpha;
  2996. m_fGlowAlphaUpdateTime = gpGlobals->curtime;
  2997. m_GlowObject.SetAlpha( newAlpha );
  2998. }
  2999. else
  3000. {
  3001. // otherwise we are done with the animation, finish it and check if there is a new state
  3002. m_fGlowAlpha = m_fGlowAlphaTarget;
  3003. m_fGlowAlphaUpdateTime = m_fGlowAlphaTargetTime;
  3004. m_fGlowAlphaTargetTime = -1.0f;
  3005. m_GlowObject.SetAlpha( m_fGlowAlphaTarget );
  3006. UpdateGlows();
  3007. }
  3008. }
  3009. void C_CSPlayer::Spawn( void )
  3010. {
  3011. m_flLastSpawnTimeIndex = gpGlobals->curtime;
  3012. #if defined( USE_PLAYER_ATTRIBUTE_MANAGER )
  3013. m_AttributeManager.SetPlayer( this );
  3014. m_AttributeList.SetManager( &m_AttributeManager );
  3015. #endif
  3016. BaseClass::Spawn();
  3017. if ( m_bUseNewAnimstate && m_PlayerAnimStateCSGO )
  3018. {
  3019. m_PlayerAnimStateCSGO->Reset();
  3020. m_PlayerAnimStateCSGO->Update( EyeAngles()[YAW], EyeAngles()[PITCH] );
  3021. }
  3022. m_roundEndAmmoCount = roundEndAmmoCount_t(); // clear data
  3023. }
  3024. //// data collection for ammo remaining at death. OGS
  3025. void C_CSPlayer::RecordAmmoForRound( void )
  3026. {
  3027. CBaseCombatWeapon *pWeapon;
  3028. if ( !IsControllingBot() && !IsHLTV() && !g_HltvReplaySystem.GetHltvReplayDelay() )
  3029. {
  3030. // PRIMARY WEAPON
  3031. pWeapon = Weapon_GetSlot( WEAPON_SLOT_RIFLE );
  3032. if ( pWeapon )
  3033. {
  3034. m_roundEndAmmoCount.nPrimaryWeaponDefIndex = pWeapon->GetEconItemView()->GetItemDefinition()->GetDefinitionIndex();
  3035. m_roundEndAmmoCount.nPrimaryWeaponAmmoCount = pWeapon->Clip1() + pWeapon->GetReserveAmmoCount( AMMO_POSITION_PRIMARY );
  3036. }
  3037. // SECONDARY WEAPON
  3038. pWeapon = Weapon_GetSlot( WEAPON_SLOT_PISTOL );
  3039. if ( pWeapon )
  3040. {
  3041. m_roundEndAmmoCount.nSecondaryWeaponDefIndex = pWeapon->GetEconItemView()->GetItemDefinition()->GetDefinitionIndex();
  3042. m_roundEndAmmoCount.nSecondaryWeaponAmmoCount = pWeapon->Clip1() + pWeapon->GetReserveAmmoCount( AMMO_POSITION_PRIMARY );
  3043. }
  3044. }
  3045. }
  3046. void C_CSPlayer::UpdateOnRemove( void )
  3047. {
  3048. if ( m_ARScreenGlowEffect.IsValid() && m_ARScreenGlowEffect->IsValid() )
  3049. {
  3050. m_ARScreenGlowEffect->StopEmission();
  3051. m_ARScreenGlowEffect->SetRemoveFlag();
  3052. m_ARScreenGlowEffect = NULL;
  3053. }
  3054. CancelFreezeCamFlashlightEffect();
  3055. BaseClass::UpdateOnRemove();
  3056. }
  3057. //--------------------------------------------------------------------------------------------------------
  3058. void C_CSPlayer::OnSetDormant( bool bDormant )
  3059. {
  3060. if ( bDormant )
  3061. {
  3062. // Turn off effects if we're going dormant
  3063. if ( m_ARScreenGlowEffect.IsValid() )
  3064. {
  3065. m_ARScreenGlowEffect->StopEmission();
  3066. m_ARScreenGlowEffect->SetRemoveFlag();
  3067. m_ARScreenGlowEffect = NULL;
  3068. }
  3069. //if ( m_AdrenalineScreenEffect.IsValid() )
  3070. //{
  3071. // m_AdrenalineScreenEffect->StopEmission();
  3072. // m_AdrenalineScreenEffect->SetRemoveFlag();
  3073. // m_AdrenalineScreenEffect = NULL;
  3074. //}
  3075. if ( !IsAnimLODflagSet( ANIMLODFLAG_DORMANT ) )
  3076. {
  3077. m_nAnimLODflagsOld &= ~ANIMLODFLAG_DORMANT;
  3078. }
  3079. SetAnimLODflag( ANIMLODFLAG_DORMANT );
  3080. }
  3081. else
  3082. {
  3083. if ( IsAnimLODflagSet( ANIMLODFLAG_DORMANT ) )
  3084. {
  3085. m_nAnimLODflagsOld |= ANIMLODFLAG_DORMANT;
  3086. }
  3087. UnSetAnimLODflag( ANIMLODFLAG_DORMANT );
  3088. }
  3089. BaseClass::OnSetDormant( bDormant );
  3090. }
  3091. bool C_CSPlayer::HasDefuser() const
  3092. {
  3093. return m_bHasDefuser;
  3094. }
  3095. void C_CSPlayer::GiveDefuser()
  3096. {
  3097. m_bHasDefuser = true;
  3098. }
  3099. void C_CSPlayer::RemoveDefuser()
  3100. {
  3101. m_bHasDefuser = false;
  3102. }
  3103. bool C_CSPlayer::HasNightVision() const
  3104. {
  3105. return m_bHasNightVision;
  3106. }
  3107. bool C_CSPlayer::IsVIP() const
  3108. {
  3109. C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource* )GameResources();
  3110. if ( !pCSPR )
  3111. return false;
  3112. return pCSPR->IsVIP( entindex() );
  3113. }
  3114. C_CSPlayer* C_CSPlayer::GetLocalCSPlayer()
  3115. {
  3116. return (C_CSPlayer* )C_BasePlayer::GetLocalPlayer();
  3117. }
  3118. CSPlayerState C_CSPlayer::State_Get() const
  3119. {
  3120. return m_iPlayerState;
  3121. }
  3122. float C_CSPlayer::GetMinFOV() const
  3123. {
  3124. // Min FOV for AWP.
  3125. return 10;
  3126. }
  3127. int C_CSPlayer::GetAccount() const
  3128. {
  3129. return m_iAccount;
  3130. }
  3131. int C_CSPlayer::PlayerClass() const
  3132. {
  3133. return m_iClass;
  3134. }
  3135. bool C_CSPlayer::CanShowTeamMenu() const
  3136. {
  3137. return ( CSGameRules() && !CSGameRules()->IsQueuedMatchmaking() && !CSGameRules()->IsPlayingCooperativeGametype() && !IsHLTV() );
  3138. }
  3139. int C_CSPlayer::ArmorValue() const
  3140. {
  3141. return m_ArmorValue;
  3142. }
  3143. bool C_CSPlayer::HasHelmet() const
  3144. {
  3145. return m_bHasHelmet;
  3146. }
  3147. bool C_CSPlayer::HasHeavyArmor() const
  3148. {
  3149. return m_bHasHeavyArmor;
  3150. }
  3151. bool C_CSPlayer::RenderLocalScreenSpaceEffect( CStrikeScreenSpaceEffect effect, IMatRenderContext *pRenderContext, int x, int y, int w, int h )
  3152. {
  3153. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  3154. if ( pLocalPlayer )
  3155. {
  3156. return pLocalPlayer->DrawScreenSpaceVomitParticles( pRenderContext );
  3157. }
  3158. return false;
  3159. }
  3160. int C_CSPlayer::DrawModel( int flags, const RenderableInstance_t &instance )
  3161. {
  3162. if ( IsAnimLODflagSet(ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) || IsDormant() || !IsVisible() )
  3163. {
  3164. if ( !IsVisible() )
  3165. {
  3166. // fixme: players spectators fly towards return false to IsVisible? Special case for now:
  3167. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  3168. if ( pLocalPlayer &&
  3169. pLocalPlayer->GetObserverInterpState() == OBSERVER_INTERP_TRAVELING &&
  3170. pLocalPlayer->GetObserverTarget() == ToBasePlayer(this) )
  3171. {
  3172. return BaseClass::DrawModel( flags, instance );
  3173. }
  3174. }
  3175. return 0;
  3176. }
  3177. return BaseClass::DrawModel( flags, instance );
  3178. }
  3179. // bool C_CSPlayer::RenderScreenSpaceEffect( PortalScreenSpaceEffect effect, IMatRenderContext *pRenderContext, int x, int y, int w, int h )
  3180. // {
  3181. // bool result = false;
  3182. // switch ( effect )
  3183. // {
  3184. // case PAINT_SCREEN_SPACE_EFFECT:
  3185. // result = RenderScreenSpacePaintEffect( pRenderContext );
  3186. // break;
  3187. // }
  3188. //
  3189. // return result;
  3190. // }
  3191. static void SetRenderTargetAndViewPort( ITexture *rt )
  3192. {
  3193. CMatRenderContextPtr pRenderContext( materials );
  3194. pRenderContext->SetRenderTarget( rt );
  3195. if ( rt )
  3196. {
  3197. pRenderContext->Viewport( 0, 0, rt->GetActualWidth(), rt->GetActualHeight() );
  3198. }
  3199. }
  3200. //--------------------------------------------------------------------------------------------------------
  3201. bool C_CSPlayer::AreScreenSpaceVomitParticlesActive( void ) const
  3202. {
  3203. if ( !m_ARScreenGlowEffect.IsValid() )
  3204. {
  3205. return false;
  3206. }
  3207. if ( !m_ARScreenGlowEffect->IsValid() )
  3208. {
  3209. return false;
  3210. }
  3211. return true;
  3212. }
  3213. bool C_CSPlayer::DrawScreenSpaceVomitParticles( IMatRenderContext *pRenderContext )
  3214. {
  3215. if ( AreScreenSpaceVomitParticlesActive() )
  3216. {
  3217. // pRenderContext->PushRenderTargetAndViewport();
  3218. // ITexture* pDestRenderTarget = materials->FindTexture( "_rt_SmallFB1", TEXTURE_GROUP_RENDER_TARGET );
  3219. // SetRenderTargetAndViewPort( pDestRenderTarget );
  3220. // pRenderContext->ClearColor4ub( 128, 128, 0, 0 );
  3221. // pRenderContext->ClearBuffers( true, false, false );
  3222. RenderableInstance_t instance;
  3223. instance.m_nAlpha = 255;
  3224. m_ARScreenGlowEffect->DrawModel( 1, instance );
  3225. // if ( IsGameConsole() )
  3226. // {
  3227. // pRenderContext->CopyRenderTargetToTextureEx( pDestRenderTarget, 0, NULL, NULL );
  3228. // }
  3229. //
  3230. //pRenderContext->PopRenderTargetAndViewport();
  3231. return true;
  3232. }
  3233. return false;
  3234. }
  3235. // --------------------------------------------------------------------------------------------------------
  3236. // void C_CSPlayer::DrawScreenSpaceVomitParticles( void )
  3237. // {
  3238. // if ( !m_ARScreenGlowEffect.IsValid() )
  3239. // {
  3240. // return;
  3241. // }
  3242. // if ( !m_ARScreenGlowEffect->IsValid() )
  3243. // {
  3244. // return;
  3245. // }
  3246. //
  3247. // RenderableInstance_t instance;
  3248. // instance.m_nAlpha = 255;
  3249. // m_ARScreenGlowEffect->DrawModel( 1, instance );
  3250. // }
  3251. void C_CSPlayer::AddDecal( const Vector& rayStart, const Vector& rayEnd, const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal )
  3252. {
  3253. /* Removed for partner depot */
  3254. BaseClass::AddDecal( rayStart, rayEnd, decalCenter, hitbox, decalIndex, doTrace, tr, maxLODToDecal );
  3255. }
  3256. float g_flFattenAmt = 4;
  3257. void C_CSPlayer::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType )
  3258. {
  3259. #if defined( _PS3 ) && defined( CSTRIKE15 )
  3260. // eurogamer PS3 temp fix - prevents the shadow resolution yo-yo (due to render bound changes - comments below) and frees some perf up
  3261. mins = CollisionProp()->OBBMins();
  3262. maxs = CollisionProp()->OBBMaxs();
  3263. // Thus, we give it some padding here.
  3264. mins -= Vector( g_flFattenAmt, g_flFattenAmt, 0 );
  3265. maxs += Vector( g_flFattenAmt, g_flFattenAmt, 0 );
  3266. return;
  3267. #else
  3268. if ( shadowType == SHADOWS_SIMPLE )
  3269. {
  3270. // Don't let the render bounds change when we're using blobby shadows, or else the shadow
  3271. // will pop and stretch.
  3272. mins = CollisionProp()->OBBMins();
  3273. maxs = CollisionProp()->OBBMaxs();
  3274. }
  3275. else
  3276. {
  3277. GetRenderBounds( mins, maxs );
  3278. // We do this because the normal bbox calculations don't take pose params into account, and
  3279. // the rotation of the guy's upper torso can place his gun a ways out of his bbox, and
  3280. // the shadow will get cut off as he rotates.
  3281. //
  3282. // Thus, we give it some padding here.
  3283. mins -= Vector( g_flFattenAmt, g_flFattenAmt, 0 );
  3284. maxs += Vector( g_flFattenAmt, g_flFattenAmt, 0 );
  3285. }
  3286. #endif
  3287. }
  3288. void C_CSPlayer::GetRenderBounds( Vector& theMins, Vector& theMaxs )
  3289. {
  3290. // TODO POSTSHIP - this hack/fix goes hand-in-hand with a fix in CalcSequenceBoundingBoxes in utils/studiomdl/simplify.cpp.
  3291. // When we enable the fix in CalcSequenceBoundingBoxes, we can get rid of this.
  3292. //
  3293. // What we're doing right here is making sure it only uses the bbox for our lower-body sequences since,
  3294. // with the current animations and the bug in CalcSequenceBoundingBoxes, are WAY bigger than they need to be.
  3295. C_BaseAnimating::GetRenderBounds( theMins, theMaxs );
  3296. // If we're ducking, we should reduce the render height by the difference in standing and ducking heights.
  3297. // This prevents shadows from drawing above ducking players etc.
  3298. if ( GetFlags() & FL_DUCKING )
  3299. {
  3300. theMaxs.z -= 18.5f;
  3301. }
  3302. }
  3303. bool C_CSPlayer::GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const
  3304. {
  3305. if ( shadowType == SHADOWS_SIMPLE )
  3306. {
  3307. // Blobby shadows should sit directly underneath us.
  3308. pDirection->Init( 0, 0, -1 );
  3309. return true;
  3310. }
  3311. else
  3312. {
  3313. return BaseClass::GetShadowCastDirection( pDirection, shadowType );
  3314. }
  3315. }
  3316. void C_CSPlayer::VPhysicsUpdate( IPhysicsObject *pPhysics )
  3317. {
  3318. BaseClass::VPhysicsUpdate( pPhysics );
  3319. }
  3320. int C_CSPlayer::GetIDTarget() const
  3321. {
  3322. if ( !m_delayTargetIDTimer.IsElapsed() )
  3323. return 0;
  3324. if ( m_iIDEntIndex )
  3325. {
  3326. return m_iIDEntIndex;
  3327. }
  3328. if ( m_iOldIDEntIndex && !m_holdTargetIDTimer.IsElapsed() )
  3329. {
  3330. return m_iOldIDEntIndex;
  3331. }
  3332. return 0;
  3333. }
  3334. int C_CSPlayer::GetTargetedWeapon( void ) const
  3335. {
  3336. return m_iTargetedWeaponEntIndex;
  3337. }
  3338. void C_CSPlayer::UpdateRadioHeadIcon( bool bRadio )
  3339. {
  3340. bRadio = ( bRadio && ShouldShowRadioHeadIcon() );
  3341. C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
  3342. if ( bRadio )
  3343. {
  3344. if ( !m_radioHeadIconParticleEffect.IsValid() && (pPlayer && pPlayer != this) )
  3345. {
  3346. MDLCACHE_CRITICAL_SECTION();
  3347. m_radioHeadIconParticleEffect = GetRadioHeadParticleEffect();
  3348. }
  3349. }
  3350. else
  3351. {
  3352. if ( m_radioHeadIconParticleEffect.IsValid() )
  3353. {
  3354. m_radioHeadIconParticleEffect->StopEmission();
  3355. m_radioHeadIconParticleEffect->SetRemoveFlag();
  3356. m_radioHeadIconParticleEffect = NULL;
  3357. }
  3358. }
  3359. }
  3360. bool C_CSPlayer::ShouldShowRadioHeadIcon() const
  3361. {
  3362. return GameRules() && GameRules()->IsMultiplayer();
  3363. }
  3364. Vector C_CSPlayer::GetParticleHeadLabelOffset( void )
  3365. {
  3366. Vector vecVoice;
  3367. int iBIndex = LookupBone( "ValveBiped.Bip01_Head" );
  3368. if ( iBIndex >= 0 )
  3369. {
  3370. Vector vecBone;
  3371. QAngle angBone;
  3372. GetBonePosition( iBIndex, vecBone, angBone );
  3373. vecVoice = (vecBone - GetAbsOrigin()) + Vector( 0, 0, 12 );
  3374. }
  3375. else
  3376. {
  3377. vecVoice = (EyePosition() - GetAbsOrigin()) + Vector( 0.0f, 0.0f, GetClientVoiceMgr()->GetHeadLabelOffset() );
  3378. }
  3379. return vecVoice;
  3380. }
  3381. CNewParticleEffect *C_CSPlayer::GetRadioHeadParticleEffect( void )
  3382. {
  3383. Vector vecVoice = GetParticleHeadLabelOffset();
  3384. if ( cl_teamid_overhead.GetInt() > 0 )
  3385. {
  3386. vecVoice += Vector( 0, 0, 18 );
  3387. }
  3388. return ParticleProp()->Create( GetRadioHeadParticleEffectName(), PATTACH_ABSORIGIN_FOLLOW, -1, vecVoice );
  3389. }
  3390. CNewParticleEffect *C_CSPlayer::GetVOIPParticleEffect( void )
  3391. {
  3392. return ParticleProp()->Create( GetVOIPParticleEffectName(), PATTACH_ABSORIGIN_FOLLOW, -1, GetParticleHeadLabelOffset() );
  3393. }
  3394. char *C_CSPlayer::GetHalloweenMaskModelAddon( C_CSPlayer *pPlayer )
  3395. {
  3396. int nMaskIndex = 0;
  3397. bool bShowColor = ( CCSGameRules::GetMaxPlayers() <= 10 ) && CSGameRules() && CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset();
  3398. C_CS_PlayerResource* pCSPR = ( C_CS_PlayerResource* )g_PR;
  3399. int nMainArraySize = ARRAYSIZE( s_HalloweenMaskModels );
  3400. if ( bShowColor && pCSPR )
  3401. {
  3402. int playerIndex = 0;
  3403. for ( int i = 0; i <= MAX_PLAYERS; i++ )
  3404. {
  3405. CBasePlayer* pCheckPlayer = UTIL_PlayerByIndex( i );
  3406. if ( pCheckPlayer && pCheckPlayer == pPlayer )
  3407. {
  3408. playerIndex = i;
  3409. break;
  3410. }
  3411. }
  3412. int nColor = pCSPR->GetCompTeammateColor( playerIndex );
  3413. if ( pPlayer->GetTeamNumber() == TEAM_TERRORIST )
  3414. nColor += 5;
  3415. if ( nColor < 0 )
  3416. nMaskIndex = (pPlayer->entindex() + (CCSGameRules::GetMaxPlayers()-1));
  3417. else
  3418. nMaskIndex = nColor;
  3419. return s_HalloweenMaskModelsCompetitive[nMaskIndex % ARRAYSIZE( s_HalloweenMaskModelsCompetitive )].model;
  3420. }
  3421. else
  3422. {
  3423. int nSeed = CSGameRules()->m_nHalloweenMaskListSeed;
  3424. nMaskIndex = (pPlayer->entindex()+nSeed) % nMainArraySize;
  3425. }
  3426. if ( Q_strcmp( s_HalloweenMaskModels[nMaskIndex].model, "tf2" ) == 0 )
  3427. {
  3428. nMaskIndex += RandomInt( 0, 6 );
  3429. nMaskIndex = nMaskIndex % ARRAYSIZE( s_HalloweenMaskModelsTF2 );
  3430. return s_HalloweenMaskModelsTF2[nMaskIndex].model;
  3431. }
  3432. return s_HalloweenMaskModels[nMaskIndex].model;
  3433. }
  3434. class C_PlayerAddonModel : public C_BreakableProp
  3435. {
  3436. public:
  3437. virtual const Vector& GetAbsOrigin( void ) const
  3438. {
  3439. // if the player carrying this addon is in lod state (meaning outside the camera frustum)
  3440. // we don't need to set up all the player's attachment bones just to find out where exactly
  3441. // the addon model wants to render. Just return the player's origin.
  3442. CBaseEntity *pMoveParent = GetMoveParent();
  3443. if ( pMoveParent && pMoveParent->IsPlayer() )
  3444. {
  3445. C_CSPlayer *pCSPlayer = static_cast<C_CSPlayer *>( pMoveParent );
  3446. if ( pCSPlayer && ( pCSPlayer->IsAnimLODflagSet(ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) || pCSPlayer->IsDormant() || !pCSPlayer->IsVisible() ) )
  3447. return pCSPlayer->GetAbsOrigin();
  3448. }
  3449. return BaseClass::GetAbsOrigin();
  3450. }
  3451. virtual bool ShouldDraw()
  3452. {
  3453. CBaseEntity *pMoveParent = GetMoveParent();
  3454. if ( pMoveParent && pMoveParent->IsPlayer() )
  3455. {
  3456. C_CSPlayer *pCSPlayer = static_cast<C_CSPlayer *>( pMoveParent );
  3457. if ( pCSPlayer && ( pCSPlayer->IsAnimLODflagSet(ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) || pCSPlayer->IsDormant() || !pCSPlayer->IsVisible() ) )
  3458. return false;
  3459. }
  3460. return BaseClass::ShouldDraw();
  3461. }
  3462. virtual bool IsFollowingEntity()
  3463. {
  3464. // addon models are ALWAYS following players
  3465. return true;
  3466. }
  3467. };
  3468. void C_CSPlayer::CreateAddonModel( int i )
  3469. {
  3470. /* Removed for partner depot */
  3471. }
  3472. //-----------------------------------------------------------------------------
  3473. // Purpose:
  3474. // Input : bThirdperson -
  3475. //-----------------------------------------------------------------------------
  3476. void C_CSPlayer::ThirdPersonSwitch( bool bThirdperson )
  3477. {
  3478. BaseClass::ThirdPersonSwitch( bThirdperson );
  3479. if ( m_hCarriedHostageProp != NULL )
  3480. {
  3481. C_HostageCarriableProp *pHostageProp = static_cast< C_HostageCarriableProp* >( m_hCarriedHostageProp.Get() );
  3482. if ( pHostageProp )
  3483. {
  3484. UpdateHostageCarryModels();
  3485. }
  3486. }
  3487. }
  3488. void C_CSPlayer::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov )
  3489. {
  3490. BaseClass::CalcView( eyeOrigin, eyeAngles, zNear, zFar, fov );
  3491. //only modify the eye position for first-person players or observers
  3492. if ( m_bUseNewAnimstate && m_PlayerAnimStateCSGO )
  3493. {
  3494. if ( IsLocalPlayer() && IsAlive() && ( !::input->CAM_IsThirdPerson() || cl_camera_height_restriction_debug.GetBool() ) )
  3495. {
  3496. m_PlayerAnimStateCSGO->ModifyEyePosition( eyeOrigin );
  3497. }
  3498. else if ( GetObserverMode() == OBS_MODE_IN_EYE )
  3499. {
  3500. C_CSPlayer *pTargetPlayer = ToCSPlayer( GetLocalCSPlayer()->GetObserverTarget() );
  3501. if ( pTargetPlayer )
  3502. {
  3503. pTargetPlayer->m_PlayerAnimStateCSGO->ModifyEyePosition( eyeOrigin );
  3504. }
  3505. }
  3506. }
  3507. #ifdef IRONSIGHT
  3508. CWeaponCSBase *pWeapon = GetActiveCSWeapon();
  3509. if (pWeapon)
  3510. {
  3511. CIronSightController* pIronSightController = pWeapon->GetIronSightController();
  3512. if (pIronSightController)
  3513. {
  3514. //bias the local client FOV change so ironsight transitions are nicer
  3515. fov = pIronSightController->GetIronSightFOV(GetDefaultFOV(), true);
  3516. }
  3517. }
  3518. #endif //IRONSIGHT}
  3519. Assert( eyeAngles.IsValid() && eyeOrigin.IsValid() );
  3520. }
  3521. #define MP_TAUNT_PITCH 0
  3522. #define MP_TAUNT_YAW 1
  3523. #define MP_TAUNT_DIST 2
  3524. #define MP_TAUNT_MAXYAW 135
  3525. #define MP_TAUNT_MINYAW -135
  3526. #define MP_TAUNT_MAXPITCH 90
  3527. #define MP_TAUNT_MINPITCH 0
  3528. #define MP_TAUNT_IDEALLAG 4.0f
  3529. static Vector MP_TAUNTCAM_HULL_MIN( -9.0f, -9.0f, -9.0f );
  3530. static Vector MP_TAUNTCAM_HULL_MAX( 9.0f, 9.0f, 9.0f );
  3531. //ConVar sv_slomo_death_cam_speed( "sv_slomo_death_cam_speed", "0.3", FCVAR_CHEAT | FCVAR_REPLICATED );
  3532. //ConVar sv_slomo_death_cam_dist( "sv_slomo_death_cam_dist", "180", FCVAR_CHEAT | FCVAR_REPLICATED );
  3533. void C_CSPlayer::UpdateHostageCarryModels()
  3534. {
  3535. if ( m_hCarriedHostage )
  3536. {
  3537. if ( m_hCarriedHostageProp != NULL )
  3538. {
  3539. C_HostageCarriableProp *pHostageProp = static_cast< C_HostageCarriableProp* >( m_hCarriedHostageProp.Get() );
  3540. if ( pHostageProp )
  3541. {
  3542. pHostageProp->UpdateVisibility();
  3543. }
  3544. }
  3545. C_BaseViewModel *pViewModel = assert_cast<C_BaseViewModel *>( GetViewModel( 1 ) );
  3546. if ( pViewModel )
  3547. {
  3548. pViewModel->UpdateVisibility();
  3549. }
  3550. }
  3551. }
  3552. // ConVar debug_test_hats( "debug_test_hats", "1" );
  3553. void C_CSPlayer::UpdateAddonModels( bool bForce )
  3554. {
  3555. COMPILE_TIME_ASSERT( NUM_ADDON_BITS + NUM_CLIENTSIDE_ADDON_BITS < 32 );
  3556. int iCurAddonBits = m_iAddonBits;
  3557. if ( m_hC4AddonLED && ( IsAnimLODflagSet(ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) || IsDormant() ) )
  3558. {
  3559. RemoveC4Effect( false );
  3560. }
  3561. else if ( !m_hC4AddonLED && !IsAnimLODflagSet(ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) && !IsDormant() && HasC4() )
  3562. {
  3563. int j,jNext;
  3564. for ( j=m_AddonModels.Head(); j != m_AddonModels.InvalidIndex(); j = jNext )
  3565. {
  3566. jNext = m_AddonModels.Next( j );
  3567. CAddonModel *pModel = &m_AddonModels[j];
  3568. // if we haven't removed it
  3569. int addonBit = 1<<pModel->m_iAddon;
  3570. if ( pModel->m_hEnt.Get() && addonBit == ADDON_C4 )
  3571. {
  3572. // make sure the c4 has the light on it
  3573. CreateC4Effect( pModel->m_hEnt.Get(), false );
  3574. }
  3575. }
  3576. }
  3577. // If a CS player has a holiday hat then make all hostages wear a holiday hat too
  3578. C_CHostage::SetClientSideHoldayHatAddonForAllHostagesAndTheirRagdolls( !!( iCurAddonBits & ADDON_CLIENTSIDE_HOLIDAY_HAT ) );
  3579. // If our player has a ragdoll then apply the holiday hat or other addons to the ragdoll
  3580. if ( C_CSRagdoll *pRagdoll = (C_CSRagdoll* )m_hRagdoll.Get() )
  3581. {
  3582. pRagdoll->SetRagdollClientSideAddon( iCurAddonBits );
  3583. if ( iCurAddonBits & ADDON_MASK )
  3584. iCurAddonBits &= ~ADDON_MASK; // halloween
  3585. if ( iCurAddonBits & ADDON_CLIENTSIDE_ASSASSINATION_TARGET)
  3586. iCurAddonBits &= ~ADDON_CLIENTSIDE_ASSASSINATION_TARGET; // clean up assassination target mask if we're dead
  3587. }
  3588. if ( iCurAddonBits & ADDON_CLIENTSIDE_GHOST )
  3589. iCurAddonBits &= ~ADDON_CLIENTSIDE_GHOST; // halloween
  3590. // Don't put addon models on the local player unless in third person.
  3591. if ( IsLocalPlayer( this ) && !C_BasePlayer::ShouldDrawLocalPlayer() )
  3592. iCurAddonBits = 0;
  3593. // If a local player is observing this entity in first-person mode, get rid of its addons.
  3594. FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
  3595. {
  3596. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  3597. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  3598. if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_IN_EYE && pPlayer->GetObserverTarget() == this )
  3599. iCurAddonBits = 0;
  3600. }
  3601. int n,nNext;
  3602. for ( n=m_AddonModels.Head(); n != m_AddonModels.InvalidIndex(); n = nNext )
  3603. {
  3604. nNext = m_AddonModels.Next( n );
  3605. CAddonModel *pModel = &m_AddonModels[n];
  3606. int addonBit = 1<<pModel->m_iAddon;
  3607. if ( !pModel || !pModel->m_hEnt || !pModel->m_hEnt->GetMoveParent() || pModel->m_hEnt->GetMoveParent()->IsDormant() )
  3608. {
  3609. if ( addonBit == ADDON_C4 )
  3610. {
  3611. RemoveC4Effect( false );
  3612. }
  3613. if ( pModel->m_hEnt.Get() )
  3614. {
  3615. pModel->m_hEnt->ClearCustomMaterials();
  3616. pModel->m_hEnt->Release();
  3617. }
  3618. m_AddonModels.Remove( n );
  3619. iCurAddonBits = 0;
  3620. }
  3621. }
  3622. if ( bForce )
  3623. iCurAddonBits = 0;
  3624. // Any changes to the attachments we should have?
  3625. if ( !bForce &&
  3626. m_iLastAddonBits == iCurAddonBits &&
  3627. m_iLastPrimaryAddon == m_iPrimaryAddon &&
  3628. m_iLastSecondaryAddon == m_iSecondaryAddon )
  3629. {
  3630. return;
  3631. }
  3632. bool rebuildPistol2Addon = bForce;
  3633. if ( m_iSecondaryAddon == WEAPON_ELITE && ((m_iLastAddonBits ^ iCurAddonBits ) & ADDON_PISTOL) != 0 )
  3634. {
  3635. rebuildPistol2Addon = true;
  3636. }
  3637. bool rebuildPrimaryAddon = (( m_iLastPrimaryAddon != m_iPrimaryAddon ) || bForce );
  3638. m_iLastAddonBits = iCurAddonBits;
  3639. m_iLastPrimaryAddon = m_iPrimaryAddon;
  3640. m_iLastSecondaryAddon = m_iSecondaryAddon;
  3641. // Get rid of any old models.
  3642. int i,iNext;
  3643. for ( i=m_AddonModels.Head(); i != m_AddonModels.InvalidIndex(); i = iNext )
  3644. {
  3645. iNext = m_AddonModels.Next( i );
  3646. CAddonModel *pModel = &m_AddonModels[i];
  3647. int addonBit = 1<<pModel->m_iAddon;
  3648. if ( !( iCurAddonBits & addonBit ) || (rebuildPistol2Addon && addonBit == ADDON_PISTOL2 ) || ( rebuildPrimaryAddon && addonBit == ADDON_PRIMARY ) )
  3649. {
  3650. if ( addonBit == ADDON_C4 )
  3651. {
  3652. RemoveC4Effect( false );
  3653. }
  3654. if ( pModel->m_hEnt.Get() )
  3655. {
  3656. pModel->m_hEnt->ClearCustomMaterials();
  3657. pModel->m_hEnt->Release();
  3658. }
  3659. m_AddonModels.Remove( i );
  3660. }
  3661. }
  3662. // Figure out which models we have now.
  3663. int curModelBits = 0;
  3664. FOR_EACH_LL( m_AddonModels, j )
  3665. {
  3666. curModelBits |= (1<<m_AddonModels[j].m_iAddon );
  3667. }
  3668. // Add any new models.
  3669. for ( i=0; i < NUM_ADDON_BITS + NUM_CLIENTSIDE_ADDON_BITS; i++ )
  3670. {
  3671. if ( (iCurAddonBits & (1<<i )) && !( curModelBits & (1<<i) ) )
  3672. {
  3673. // Ok, we're supposed to have this one.
  3674. CreateAddonModel( i );
  3675. }
  3676. }
  3677. // go through again and see if they need any effects
  3678. int j,jNext;
  3679. for ( j=m_AddonModels.Head(); j != m_AddonModels.InvalidIndex(); j = jNext )
  3680. {
  3681. jNext = m_AddonModels.Next( j );
  3682. CAddonModel *pModel = &m_AddonModels[j];
  3683. // if we haven't removed it
  3684. int addonBit = 1<<pModel->m_iAddon;
  3685. if ( pModel->m_hEnt.Get() && addonBit == ADDON_C4 )
  3686. {
  3687. // make sure the c4 has the light on it
  3688. CreateC4Effect( pModel->m_hEnt.Get(), false );
  3689. }
  3690. }
  3691. m_bAddonModelsAreOutOfDate = false;
  3692. }
  3693. void C_CSPlayer::RemoveAddonModels()
  3694. {
  3695. m_iAddonBits = 0;
  3696. if ( !m_AddonModels.Count() )
  3697. return;
  3698. //Don't test anything about the addon models, just remove them.
  3699. int n, nNext;
  3700. for ( n=m_AddonModels.Head(); n != m_AddonModels.InvalidIndex(); n = nNext )
  3701. {
  3702. nNext = m_AddonModels.Next( n );
  3703. CAddonModel *pModel = &m_AddonModels[n];
  3704. int addonBit = 1<<pModel->m_iAddon;
  3705. if ( addonBit == ADDON_C4 )
  3706. {
  3707. RemoveC4Effect( false );
  3708. }
  3709. if ( pModel->m_hEnt.Get() )
  3710. {
  3711. pModel->m_hEnt->ClearCustomMaterials();
  3712. pModel->m_hEnt->Release();
  3713. }
  3714. m_AddonModels.Remove( n );
  3715. }
  3716. }
  3717. void C_CSPlayer::CreateC4Effect( CBaseEntity *pEnt, bool bIsWeaponModel )
  3718. {
  3719. if ( !pEnt )
  3720. return;
  3721. if ( bIsWeaponModel )
  3722. {
  3723. if ( !m_hC4WeaponLED )
  3724. {
  3725. //RemoveC4Effect( bIsWeaponModel );
  3726. m_hC4WeaponLED = pEnt->ParticleProp()->Create( "c4_timer_light_held", PATTACH_POINT_FOLLOW, "led" );
  3727. if ( m_hC4WeaponLED )
  3728. {
  3729. ParticleProp()->AddControlPoint( m_hC4WeaponLED, 0, pEnt, PATTACH_POINT_FOLLOW, "led" );
  3730. }
  3731. /*
  3732. int splitScreenRenderFlags = 0x0;
  3733. FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
  3734. {
  3735. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  3736. CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  3737. // We don't want to show third person muzzle flash effects for this player if the splitscreen viewer is looking at this player in first person mode.
  3738. bool viewingInFirstPersonMode = ( pLocalPlayer == this ) ||
  3739. ( pLocalPlayer && pLocalPlayer->GetObserverTarget() == this && pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE );
  3740. if ( !viewingInFirstPersonMode )
  3741. {
  3742. splitScreenRenderFlags |= (0x1 << hh );
  3743. }
  3744. }
  3745. int ledAttachmentIndex = pEnt->LookupAttachment("led" );
  3746. DispatchParticleEffect( "c4_timer_light_held", PATTACH_POINT_FOLLOW, pEnt, ledAttachmentIndex, false, splitScreenRenderFlags );
  3747. */
  3748. }
  3749. }
  3750. else
  3751. {
  3752. if ( m_hC4AddonLED )
  3753. {
  3754. RemoveC4Effect( bIsWeaponModel );
  3755. }
  3756. m_hC4AddonLED = ParticleProp()->Create( "c4_timer_light_held", PATTACH_ABSORIGIN_FOLLOW );
  3757. if ( m_hC4AddonLED )
  3758. {
  3759. ParticleProp()->AddControlPoint( m_hC4AddonLED, 0, pEnt, PATTACH_POINT_FOLLOW, "led" );
  3760. }
  3761. }
  3762. }
  3763. void C_CSPlayer::RemoveC4Effect( bool bIsWeaponModel )
  3764. {
  3765. if ( bIsWeaponModel )
  3766. {
  3767. if ( m_hC4WeaponLED )
  3768. {
  3769. ParticleProp()->StopEmission( m_hC4WeaponLED );
  3770. m_hC4WeaponLED = NULL;
  3771. }
  3772. }
  3773. else
  3774. {
  3775. if ( m_hC4AddonLED )
  3776. {
  3777. ParticleProp()->StopEmission( m_hC4AddonLED );
  3778. m_hC4AddonLED = NULL;
  3779. }
  3780. }
  3781. }
  3782. void C_CSPlayer::NotifyShouldTransmit( ShouldTransmitState_t state )
  3783. {
  3784. // Remove all addon models if we go out of the PVS.
  3785. if ( state == SHOULDTRANSMIT_END )
  3786. {
  3787. RemoveAddonModels();
  3788. if( m_pFlashlightBeam != NULL )
  3789. {
  3790. FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
  3791. {
  3792. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  3793. ReleaseFlashlight();
  3794. }
  3795. }
  3796. }
  3797. BaseClass::NotifyShouldTransmit( state );
  3798. }
  3799. void C_CSPlayer::UpdateSoundEvents()
  3800. {
  3801. int iNext;
  3802. for ( int i=m_SoundEvents.Head(); i != m_SoundEvents.InvalidIndex(); i = iNext )
  3803. {
  3804. iNext = m_SoundEvents.Next( i );
  3805. CCSSoundEvent *pEvent = &m_SoundEvents[i];
  3806. if ( gpGlobals->curtime >= pEvent->m_flEventTime )
  3807. {
  3808. const Vector *pOrigin = NULL;
  3809. if ( pEvent->m_bHasSoundOrigin )
  3810. {
  3811. pOrigin = &pEvent->m_SoundOrigin;
  3812. }
  3813. CLocalPlayerFilter filter;
  3814. EmitSound( filter, GetSoundSourceIndex(), STRING( pEvent->m_SoundName ), pOrigin );
  3815. m_SoundEvents.Remove( i );
  3816. }
  3817. }
  3818. }
  3819. //-----------------------------------------------------------------------------
  3820. void C_CSPlayer::UpdateMinModels( void )
  3821. {
  3822. int modelIndex = m_nModelIndex;
  3823. #if CS_ALLOW_CL_MINMODELS
  3824. modelIndex = FilterModelUsingCL_MinModels( PlayerClass() );
  3825. #endif
  3826. SetModelByIndex( modelIndex );
  3827. }
  3828. extern ConVar sv_showbullethits;
  3829. //-----------------------------------------------------------------------------
  3830. void C_CSPlayer::ClientThink()
  3831. {
  3832. if ( IsLocalPlayer() && cl_show_equipment_value.GetBool() )
  3833. {
  3834. engine->Con_NPrintf( 33, "round start: %d", GetRoundStartEquipmentValue() );
  3835. engine->Con_NPrintf( 34, "current: %d", GetCurrentEquipmentValue() );
  3836. }
  3837. if ( IsAlive() )
  3838. {
  3839. m_vecLastAliveLocalVelocity = (m_vecLastAliveLocalVelocity * 0.8) + (GetLocalVelocity() * 0.2);
  3840. ReevauluateAnimLOD();
  3841. }
  3842. CreateClientEffectModels();
  3843. if ( m_hContactShadowLeft.Get() && m_hContactShadowRight.Get() )
  3844. {
  3845. if ( cl_foot_contact_shadows.GetBool() &&
  3846. IsAlive() &&
  3847. (GetFlags() & FL_ONGROUND) &&
  3848. !IsAnimLODflagSet( ANIMLODFLAG_DISTANT | ANIMLODFLAG_OUTSIDEVIEWFRUSTUM | ANIMLODFLAG_INVISIBLELOCALPLAYER | ANIMLODFLAG_DORMANT ) &&
  3849. ShouldDraw() )
  3850. {
  3851. int nLeftBoneIndex = LookupBone( "ankle_L" );
  3852. matrix3x4_t matBoneLeft;
  3853. GetBoneTransform( nLeftBoneIndex, matBoneLeft );
  3854. Vector vecFootPosLeft = matBoneLeft.GetOrigin();
  3855. int nRightBoneIndex = LookupBone( "ankle_R" );
  3856. matrix3x4_t matBoneRight;
  3857. GetBoneTransform( nRightBoneIndex, matBoneRight );
  3858. Vector vecFootPosRight = matBoneRight.GetOrigin();
  3859. if ( vecFootPosLeft.DistToSqr( m_vecLastContactShadowTraceOriginLeft ) > (8*8) )
  3860. {
  3861. trace_t trLeft;
  3862. UTIL_TraceLine( vecFootPosLeft, vecFootPosLeft + Vector( 0, 0, -12.0f ), MASK_FLOORTRACE, this, COLLISION_GROUP_NONE, &trLeft );
  3863. m_vecLastContactShadowTraceOriginLeft = trLeft.startpos;
  3864. m_flLastContactShadowGroundHeightLeft = trLeft.endpos.z;
  3865. //debugoverlay->AddLineOverlay( trLeft.startpos, trLeft.endpos, 255, 0, 0, true, 1.0f );
  3866. }
  3867. if ( vecFootPosRight.DistToSqr( m_vecLastContactShadowTraceOriginRight ) > (8*8) )
  3868. {
  3869. trace_t trRight;
  3870. UTIL_TraceLine( vecFootPosRight, vecFootPosRight + Vector( 0, 0, -12.0f ), MASK_FLOORTRACE, this, COLLISION_GROUP_NONE, &trRight );
  3871. m_vecLastContactShadowTraceOriginRight = trRight.startpos;
  3872. m_flLastContactShadowGroundHeightRight = trRight.endpos.z;
  3873. //debugoverlay->AddLineOverlay( trRight.startpos, trRight.endpos, 255, 0, 0, true, 1.0f );
  3874. }
  3875. float flTraceLengthLeft = vecFootPosLeft.z - m_flLastContactShadowGroundHeightLeft;
  3876. m_hContactShadowLeft->SetRenderMode( kRenderTransAlpha );
  3877. m_hContactShadowLeft->SetRenderAlpha( MIN( GetRenderAlpha(), RemapValClamped( flTraceLengthLeft, 4.0f, 8.0f, 250.0f, 0.0f ) ) ); // don't be more opaque than the player
  3878. m_hContactShadowLeft->RenderForceOpaquePass( true );
  3879. float flTraceLengthRight = vecFootPosRight.z - m_flLastContactShadowGroundHeightRight;
  3880. m_hContactShadowRight->SetRenderMode( kRenderTransAlpha );
  3881. m_hContactShadowRight->SetRenderAlpha( MIN( GetRenderAlpha(), RemapValClamped( flTraceLengthRight, 4.0f, 8.0f, 250.0f, 0.0f ) ) ); // don't be more opaque than the player
  3882. m_hContactShadowRight->RenderForceOpaquePass( true );
  3883. QAngle angLFoot;
  3884. Vector vecLFootForward = -matBoneLeft.GetForward();
  3885. vecLFootForward.z = 0;
  3886. VectorAngles( vecLFootForward, angLFoot );
  3887. m_hContactShadowLeft->SetAbsAngles( angLFoot );
  3888. m_hContactShadowLeft->SetAbsOrigin( Vector( vecFootPosLeft.x, vecFootPosLeft.y, GetAbsOrigin().z + 0.25f ) );
  3889. m_hContactShadowLeft->RemoveEffects( EF_NODRAW );
  3890. QAngle angRFoot;
  3891. Vector vecRFootForward = matBoneRight.GetForward();
  3892. vecRFootForward.z = 0;
  3893. VectorAngles( vecRFootForward, angRFoot );
  3894. m_hContactShadowRight->SetAbsAngles( angRFoot );
  3895. m_hContactShadowRight->SetAbsOrigin( Vector( vecFootPosRight.x, vecFootPosRight.y, GetAbsOrigin().z + 0.25f ) );
  3896. m_hContactShadowRight->RemoveEffects( EF_NODRAW );
  3897. }
  3898. else
  3899. {
  3900. m_hContactShadowLeft->AddEffects( EF_NODRAW );
  3901. m_hContactShadowRight->AddEffects( EF_NODRAW );
  3902. }
  3903. }
  3904. BaseClass::ClientThink();
  3905. // Cheap cheat detection code to catch cheat-engine users
  3906. /** Removed for partner depot **/
  3907. // velocity music handling
  3908. if( GetCurrentMusic() == CSMUSIC_START && GetMusicStartRoundElapsed() > 0.5 )
  3909. {
  3910. Vector vAbsVelocity = GetAbsVelocity();
  3911. float flAbsVelocity = vAbsVelocity.Length2D();
  3912. if( flAbsVelocity > 10 )
  3913. {
  3914. if( this == GetHudPlayer() )
  3915. {
  3916. CLocalPlayerFilter filter;
  3917. PlayMusicSelection( filter, CSMUSIC_ACTION );
  3918. }
  3919. SetCurrentMusic( CSMUSIC_ACTION );
  3920. }
  3921. }
  3922. //Make sure smoke grenades that have expired are removed.
  3923. for ( int it = 0; it < g_SmokeGrenadeHandles.Count(); it++ )
  3924. {
  3925. CBaseCSGrenadeProjectile *pGrenade = static_cast< CBaseCSGrenadeProjectile* >( g_SmokeGrenadeHandles[it].Get() );
  3926. if ( !pGrenade )
  3927. g_SmokeGrenadeHandles.FastRemove( it-- );
  3928. }
  3929. UpdateSoundEvents();
  3930. UpdateFlashBangEffect();
  3931. UpdateHostageCarryModels();
  3932. // Client controls this addon. Set it if we need it, but respect the below hiding rules (which set all addons to 0)
  3933. C_CSPlayer *pLocalPlayer = GetLocalCSPlayer();
  3934. if ( GetTeamNumber() == TEAM_TERRORIST && IsAssassinationTarget() && !IsControllingBot() && !m_bHasControlledBotThisRound )
  3935. {
  3936. m_iAddonBits |= ADDON_CLIENTSIDE_ASSASSINATION_TARGET;
  3937. }
  3938. UpdateAddonModels( m_bAddonModelsAreOutOfDate );
  3939. // don't show IDs in chase spec mode
  3940. bool inSpecMode = ( GetObserverMode() == OBS_MODE_CHASE || GetObserverMode() == OBS_MODE_DEATHCAM );
  3941. if ( IsLocalPlayer( this ) && !inSpecMode && IsAlive() && ( mp_forcecamera.GetInt() != OBS_ALLOW_NONE ) )
  3942. {
  3943. UpdateIDTarget();
  3944. UpdateTargetedWeapon();
  3945. }
  3946. if ( CSGameRules() && CSGameRules()->IsPlayingCoopGuardian() && IsLocalPlayer( this ) && !inSpecMode && IsAlive() )
  3947. {
  3948. if ( m_flGuardianTooFarDistFrac > 0.2 && m_flNextGuardianTooFarWarning <= gpGlobals->curtime )
  3949. {
  3950. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  3951. if ( pElement )
  3952. {
  3953. if ( CSGameRules()->IsPlayingCoopGuardian() )
  3954. {
  3955. EmitSound( "UI.Guardian.TooFarWarning" );
  3956. ( ( SFHudInfoPanel * )pElement )->SetPriorityHintText( g_pVGuiLocalize->Find( "#SFUI_Notice_GuardianModeTooFarFromBomb" ) );
  3957. }
  3958. }
  3959. m_flNextGuardianTooFarWarning = gpGlobals->curtime + MAX( 0.25, ( 1 - m_flGuardianTooFarDistFrac ) * 2 );
  3960. }
  3961. }
  3962. ////////////////////////////////////
  3963. // show player shot locations
  3964. bool bRenderForSpectator = CanSeeSpectatorOnlyTools() && spec_show_xray.GetInt();
  3965. if ( bRenderForSpectator && GetLocalPlayer() && /*(GetLocalPlayer()->m_nButtons & IN_RELOAD) &&*/ (GetLocalPlayer()->GetObserverMode() == OBS_MODE_FIXED || GetLocalPlayer()->GetObserverMode() == OBS_MODE_ROAMING) )
  3966. {
  3967. Vector aimDir;
  3968. AngleVectors( GetFinalAimAngle(), &aimDir );
  3969. Vector vecShootPos = EyePosition();
  3970. CWeaponCSBase* pActiveWeapon = GetActiveCSWeapon();
  3971. bool bShowLine = true;
  3972. if ( pActiveWeapon )
  3973. {
  3974. QAngle angTemp;
  3975. GetAttachment( LookupAttachment("facemask"), vecShootPos, angTemp );
  3976. vecShootPos += aimDir * 10;
  3977. if ( pActiveWeapon->m_bInReload )
  3978. bShowLine = false;
  3979. }
  3980. if ( bShowLine )
  3981. {
  3982. Vector vecCamPos = g_bEngineIsHLTV ? HLTVCamera()->GetCameraPosition() : (GetLocalPlayer() ? GetLocalPlayer()->EyePosition() : Vector(0,0,0));
  3983. trace_t result;
  3984. UTIL_TraceLine( EyePosition(), EyePosition() + 2000 * aimDir, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, this, COLLISION_GROUP_NONE, &result );
  3985. float flMaxLength = 1024;
  3986. float flLength = VectorLength( vecShootPos - vecCamPos );
  3987. float flLengthEndPoint = VectorLength( result.endpos - vecCamPos );
  3988. float flLengthLine = VectorLength( result.endpos - vecShootPos );
  3989. float flAlpha = (1.0f - (clamp( flLength, 0, flMaxLength ) / flMaxLength)) * 255.0f;
  3990. float flAlphaEndPoint = (1.0f - (clamp( flLengthEndPoint, 0, flMaxLength ) / flMaxLength)) * 180.0f;
  3991. if ( flAlphaEndPoint > flAlpha )
  3992. flAlpha = flAlphaEndPoint;
  3993. // reduce alpha if the line is really short
  3994. float flAlphaMult = clamp( flLengthLine, 0, 256.0f ) / 256.0f;
  3995. flAlpha *= flAlphaMult;
  3996. if ( IsAlive() && GetTeamNumber() == TEAM_CT )
  3997. {
  3998. debugoverlay->AddBoxOverlay( result.endpos, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 0,120,240, (int)flAlpha, 0.01f );
  3999. debugoverlay->AddLineOverlayAlpha( result.endpos, vecShootPos, 0,120,240, flAlpha, true, 0.01f );
  4000. }
  4001. else if ( IsAlive() && GetTeamNumber() == TEAM_TERRORIST )
  4002. {
  4003. debugoverlay->AddBoxOverlay( result.endpos, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 230,128,0, (int)flAlpha, 0.01f );
  4004. debugoverlay->AddLineOverlayAlpha( result.endpos, vecShootPos, 230,128,0, flAlpha, true, 0.01f );
  4005. }
  4006. }
  4007. }
  4008. if ( gpGlobals->curtime >= m_fNextThinkPushAway )
  4009. {
  4010. PerformObstaclePushaway( this );
  4011. m_fNextThinkPushAway = gpGlobals->curtime + PUSHAWAY_THINK_INTERVAL;
  4012. }
  4013. // Do this every frame
  4014. if( m_fGlowAlphaTargetTime != -1.0f )
  4015. AnimateGlows();
  4016. if ( IsLocalPlayer()
  4017. && (m_previousPlayerState != State_Get()
  4018. || gpGlobals->curtime >= m_fNextGlowCheckUpdate
  4019. )
  4020. )
  4021. {
  4022. if ( m_previousPlayerState != State_Get() )
  4023. m_previousPlayerState = State_Get();
  4024. UpdateGlowsForAllPlayers();
  4025. m_fNextGlowCheckUpdate = gpGlobals->curtime + m_fNextGlowCheckInterval;
  4026. }
  4027. if ( IsLocalPlayer() )
  4028. {
  4029. if ( m_iObserverMode == OBS_MODE_FREEZECAM || g_HltvReplaySystem.GetHltvReplayDelay() )
  4030. {
  4031. static ConVarRef sv_disablefreezecam( "sv_disablefreezecam" );
  4032. if ( !s_bPlayingFreezeCamSound && !cl_disablefreezecam.GetBool() && !sv_disablefreezecam.GetBool() && !g_HltvReplaySystem.IsDelayedReplayRequestPending() )
  4033. {
  4034. // Play sound
  4035. s_bPlayingFreezeCamSound = true;
  4036. C_RecipientFilter filter;
  4037. filter.AddRecipient( this );
  4038. // this lets us know at what "level" to play the death cam stinger
  4039. int nConsecutiveKills = GetLastConcurrentKilled();
  4040. // 0 == suicide or no killer
  4041. // 1, 2, 3 == consecutive number of kills from a player
  4042. // 4 + same, but on the 4th kill, domination kicks in
  4043. if ( CSGameRules()->IsPlayingGunGame() )
  4044. {
  4045. if ( nConsecutiveKills > 3 )
  4046. {
  4047. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "Music.GG_Nemesis" );
  4048. }
  4049. else if ( nConsecutiveKills > 2 )
  4050. {
  4051. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "Music.GG_DeathCam_03" );
  4052. }
  4053. else if ( nConsecutiveKills > 1 )
  4054. {
  4055. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "Music.GG_DeathCam_02" );
  4056. }
  4057. else if ( nConsecutiveKills > 0 )
  4058. {
  4059. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "Music.GG_DeathCam_01" );
  4060. }
  4061. }
  4062. // don't play this here with competetive mode, we play it when the player gets the player_death event for that mode instead so it happens immediately
  4063. else if ( !CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() )
  4064. {
  4065. PlayMusicSelection( filter, CSMUSIC_DEATHCAM );
  4066. }
  4067. }
  4068. }
  4069. else
  4070. {
  4071. s_bPlayingFreezeCamSound = false;
  4072. CancelFreezeCamFlashlightEffect();
  4073. }
  4074. }
  4075. if ( sv_disable_immunity_alpha.GetBool() == false )
  4076. {
  4077. ConVarRef mp_respawn_immunitytime( "mp_respawn_immunitytime" );
  4078. float flImmuneTime = mp_respawn_immunitytime.GetFloat();
  4079. if ( flImmuneTime > 0 || CSGameRules()->IsWarmupPeriod() )
  4080. {
  4081. if ( m_bGunGameImmunity )
  4082. {
  4083. SetRenderMode( kRenderTransAlpha );
  4084. SetRenderAlpha( 128 );
  4085. }
  4086. else
  4087. {
  4088. SetRenderMode( kRenderNormal, true );
  4089. SetRenderAlpha( 255 );
  4090. }
  4091. }
  4092. else
  4093. {
  4094. if ( GetRenderAlpha() < 255 )
  4095. {
  4096. SetRenderMode( kRenderNormal, true );
  4097. SetRenderAlpha( 255 );
  4098. }
  4099. }
  4100. }
  4101. if ( CSGameRules()->IsPlayingCoopGuardian() && CSGameRules()->IsWarmupPeriod() == false &&
  4102. mp_use_respawn_waves.GetInt() == 2 && this == GetLocalPlayer() && IsAlive() &&
  4103. GetObserverMode() == OBS_MODE_NONE )
  4104. {
  4105. bool bCanBuy = false;
  4106. if ( !IsBot() && CSGameRules()->m_flGuardianBuyUntilTime - 3.5f > gpGlobals->curtime && m_iAccount > 0 )
  4107. {
  4108. bCanBuy = true;
  4109. }
  4110. //float flTimeLeft = m_fImmuneToGunGameDamageTime - gpGlobals->curtime;
  4111. if ( bCanBuy )
  4112. {
  4113. //wchar_t szNotice[64] = L"";
  4114. // wchar_t wzTime[8] = L"";
  4115. // int nMinLeft = ( int )flTimeLeft / 60;
  4116. // int nSecLeft = ( int )flTimeLeft - ( nMinLeft * 60 );
  4117. // int nMSecLeft = ( flTimeLeft - ( ( float )( nMinLeft * 60 ) + ( float )nSecLeft ) ) * 10;
  4118. // V_swprintf_safe( wzTime, L"%d.%d", nSecLeft, nMSecLeft );
  4119. wchar_t wzBuyBind[32] = L"";
  4120. UTIL_ReplaceKeyBindings( L"%buymenu%", 0, wzBuyBind, sizeof( wzBuyBind ) );
  4121. //wchar_t wzAutoBuyBind[32] = L"";
  4122. //UTIL_ReplaceKeyBindings( L"%autobuy%", 0, wzAutoBuyBind, sizeof( wzAutoBuyBind ) );
  4123. wchar_t wszLocalized[256];
  4124. //if ( flTimeLeft < 1.0f && m_bHasMovedSinceSpawn )
  4125. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_Guardian_BuyMenuAvailable" ), 3, wzBuyBind/*, wzTime, wzAutoBuyBind*/ );
  4126. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  4127. if ( pElement )
  4128. {
  4129. ( ( SFHudInfoPanel * )pElement )->SetPriorityHintText( wszLocalized );
  4130. }
  4131. //GetCenterPrint()->Print( wszLocalized );
  4132. //UTIL_HudHintText( GetOwner(), hint.Access() );
  4133. //UTIL_ClientPrintAll( HUD_PRINTCENTER, "#SFUI_Notice_DM_OpenBuyMenu", wzFinal, wzTime );
  4134. //m_fImmuneToGunGameDamageTimeLast = m_fImmuneToGunGameDamageTime;
  4135. }
  4136. }
  4137. else if ( CSGameRules()->IsPlayingGunGameDeathmatch() && this == GetLocalPlayer() && IsAlive() && GetObserverMode() == OBS_MODE_NONE )
  4138. {
  4139. float flTimeLeft = m_fImmuneToGunGameDamageTime - gpGlobals->curtime;
  4140. if ( m_fImmuneToGunGameDamageTimeLast != 0 || flTimeLeft >= 0 )
  4141. {
  4142. //wchar_t szNotice[64] = L"";
  4143. wchar_t wzTime[8] = L"";
  4144. int nMinLeft = (int)flTimeLeft / 60;
  4145. int nSecLeft = (int)flTimeLeft - ( nMinLeft * 60 );
  4146. int nMSecLeft = (flTimeLeft - ((float)(nMinLeft*60) + (float)nSecLeft)) * 10;
  4147. V_swprintf_safe( wzTime, L"%d.%d", nSecLeft, nMSecLeft );
  4148. wchar_t wzBuyBind[32] = L"";
  4149. UTIL_ReplaceKeyBindings( L"%buymenu%", 0, wzBuyBind, sizeof( wzBuyBind ) );
  4150. wchar_t wzAutoBuyBind[32] = L"";
  4151. UTIL_ReplaceKeyBindings( L"%autobuy%", 0, wzAutoBuyBind, sizeof( wzAutoBuyBind ) );
  4152. wchar_t wszLocalized[256];
  4153. if ( cl_dm_buyrandomweapons.GetBool() )
  4154. {
  4155. if ( flTimeLeft < 1.0f && m_bHasMovedSinceSpawn )
  4156. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_DM_InvulnExpire_RandomON" ), 1, wzAutoBuyBind );
  4157. else if ( flTimeLeft < 0.1 )
  4158. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_DM_BuyMenuExpire_RandomON" ), 1, wzAutoBuyBind );
  4159. else
  4160. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_DM_BuyMenu_RandomON" ), 3, wzBuyBind, wzTime, wzAutoBuyBind );
  4161. }
  4162. else
  4163. {
  4164. if ( flTimeLeft < 1.0f && m_bHasMovedSinceSpawn )
  4165. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_DM_InvulnExpire_RandomOFF" ), 1, wzAutoBuyBind );
  4166. else if ( flTimeLeft < 0.1 )
  4167. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_DM_BuyMenuExpire_RandomOFF" ), 1, wzAutoBuyBind );
  4168. else
  4169. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_DM_BuyMenu_RandomOFF" ), 3, wzBuyBind, wzTime, wzAutoBuyBind );
  4170. }
  4171. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  4172. if ( pElement )
  4173. {
  4174. ((SFHudInfoPanel *)pElement)->SetPriorityHintText( wszLocalized );
  4175. }
  4176. //GetCenterPrint()->Print( wszLocalized );
  4177. //UTIL_HudHintText( GetOwner(), hint.Access() );
  4178. //UTIL_ClientPrintAll( HUD_PRINTCENTER, "#SFUI_Notice_DM_OpenBuyMenu", wzFinal, wzTime );
  4179. m_fImmuneToGunGameDamageTimeLast = m_fImmuneToGunGameDamageTime;
  4180. }
  4181. }
  4182. else if ( IsAlive() && m_hCarriedHostage != NULL && this == GetLocalPlayer() && IsAlive() && GetObserverMode() == OBS_MODE_NONE )
  4183. {
  4184. wchar_t wszLocalized[256];
  4185. //g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_DM_BuyMenu_RandomOFF" ), 3, wzBuyBind, wzTime, wzAutoBuyBind );
  4186. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#Cstrike_TitlesTXT_CarryingHostage" ), 0 );
  4187. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  4188. if ( pElement )
  4189. {
  4190. ((SFHudInfoPanel *)pElement)->SetPriorityHintText( wszLocalized );
  4191. }
  4192. }
  4193. else if ( !IsAlive() && mp_use_respawn_waves.GetBool() && CSGameRules() && IsAbleToInstantRespawn() && this == GetLocalPlayer() && GetObserverMode() > OBS_MODE_FREEZECAM )
  4194. {
  4195. if ( CSGameRules()->IsWarmupPeriod() == false )
  4196. {
  4197. float flTimeLeft = CSGameRules()->GetNextRespawnWave( GetTeamNumber(), NULL ) - gpGlobals->curtime;
  4198. if ( flTimeLeft > CSGameRules()->GetRespawnWaveMaxLength( GetTeamNumber() ) )
  4199. {
  4200. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  4201. if ( pElement )
  4202. {
  4203. ( ( SFHudInfoPanel * )pElement )->SetPriorityHintText( g_pVGuiLocalize->Find( "#SFUI_Notice_WaitToRespawn" ) );
  4204. }
  4205. }
  4206. else if ( flTimeLeft > 1.0f )
  4207. {
  4208. wchar_t wzTime[8] = L"";
  4209. int nMinLeft = (int)flTimeLeft / 60;
  4210. int nSecLeft = (int)flTimeLeft - ( nMinLeft * 60 );
  4211. int nMSecLeft = (flTimeLeft - ((float)(nMinLeft*60) + (float)nSecLeft)) * 10;
  4212. V_swprintf_safe( wzTime, L"%d.%d", nSecLeft, nMSecLeft );
  4213. wchar_t wszLocalized[256];
  4214. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#SFUI_Notice_WaveRespawnIn" ), 1, wzTime );
  4215. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  4216. if ( pElement )
  4217. {
  4218. ((SFHudInfoPanel *)pElement)->SetPriorityHintText( wszLocalized );
  4219. }
  4220. m_fImmuneToGunGameDamageTimeLast = m_fImmuneToGunGameDamageTime;
  4221. }
  4222. else if ( flTimeLeft > 0.75f )
  4223. {
  4224. CHudElement *pElement = GetHud().FindElement( "SFHudInfoPanel" );
  4225. if ( pElement )
  4226. {
  4227. ((SFHudInfoPanel *)pElement)->SetPriorityHintText( g_pVGuiLocalize->Find( "#SFUI_Notice_WaveRespawning" ) );
  4228. }
  4229. m_fImmuneToGunGameDamageTimeLast = m_fImmuneToGunGameDamageTime;
  4230. }
  4231. }
  4232. }
  4233. // Otherwise buy random or get previous round's gear, depending on cl_dm_buyrandomweapons.
  4234. if ( m_bShouldAutobuyDMWeapons )
  4235. {
  4236. if ( this == GetLocalPlayer() && IsAlive() && (GetTeamNumber() == TEAM_CT || GetTeamNumber() == TEAM_TERRORIST) )
  4237. {
  4238. if ( cl_dm_buyrandomweapons.GetBool() )
  4239. {
  4240. engine->ClientCmd_Unrestricted( "buyrandom" );
  4241. }
  4242. else
  4243. {
  4244. engine->ClientCmd_Unrestricted( "rebuy" );
  4245. }
  4246. if ( m_bIsRespawningForDMBonus )
  4247. {
  4248. engine->ClientCmd_Unrestricted( "drop" ); // 'drop' is overloaded for DM to respawn with bonus weapon.
  4249. }
  4250. m_bShouldAutobuyDMWeapons = false;
  4251. }
  4252. }
  4253. //=============================================================================
  4254. // HPE_BEGIN:
  4255. // [dwenger] Added for auto-buy functionality
  4256. //=============================================================================
  4257. if (m_bShouldAutobuyNow )
  4258. {
  4259. if (this == GetLocalPlayer() )
  4260. {
  4261. bool bDoAutoBuy = true;
  4262. // Make sure the player only has the starting equipment (USP for CT, Glock for T )
  4263. if ( Weapon_GetSlot( WEAPON_SLOT_RIFLE ) != NULL )
  4264. {
  4265. // Already has a primary weapon, so don't auto-buy
  4266. bDoAutoBuy = false;
  4267. }
  4268. if (bDoAutoBuy )
  4269. {
  4270. engine->ClientCmd_Unrestricted("autobuy" );
  4271. }
  4272. else
  4273. {
  4274. // Test if armor should be bought
  4275. if ( ArmorValue() < 100 )
  4276. {
  4277. engine->ClientCmd_Unrestricted("buy vesthelm" );
  4278. }
  4279. }
  4280. }
  4281. m_bShouldAutobuyNow = false;
  4282. }
  4283. //=============================================================================
  4284. // HPE_END
  4285. //=============================================================================
  4286. if ( IsAlive() && ShouldDraw() )
  4287. {
  4288. // enable bone snapshots
  4289. m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].Enable();
  4290. m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].Enable();
  4291. }
  4292. else
  4293. {
  4294. m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].Disable();
  4295. m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].Disable();
  4296. }
  4297. UpdateAllBulletHitModels();
  4298. // code for following grenades
  4299. if ( CanSeeSpectatorOnlyTools() && pLocalPlayer )
  4300. {
  4301. bool bHoldingGrenadeKey = IsHoldingSpecGrenadeKey();
  4302. // if we don't have a target, but we have an old grenade target, the grenade exploded
  4303. if ( pLocalPlayer->IsSpecFollowingGrenade() && pLocalPlayer->GetTeamNumber() == TEAM_SPECTATOR && pLocalPlayer->m_hOldGrenadeObserverTarget.Get() &&
  4304. (pLocalPlayer->GetObserverTarget() == NULL || dynamic_cast< CBaseCSGrenadeProjectile* >( pLocalPlayer->GetObserverTarget() ) ) )
  4305. {
  4306. CBaseCSGrenadeProjectile *pGrenade = dynamic_cast< CBaseCSGrenadeProjectile* >( pLocalPlayer->GetObserverTarget() );
  4307. C_BaseEntity *pTarget = m_hOldGrenadeObserverTarget.Get();
  4308. if ( pTarget )
  4309. {
  4310. Vector vecSpecPos = pLocalPlayer->EyePosition();
  4311. QAngle angView;
  4312. engine->GetViewAngles( angView );
  4313. if ( !pGrenade )
  4314. {
  4315. pLocalPlayer->SetSpecWatchingGrenade( NULL, false );
  4316. pLocalPlayer->m_iObserverMode = pLocalPlayer->GetObserverMode();
  4317. }
  4318. //
  4319. // if ( bHoldingGrenadeKey || (pGrenade && pGrenade->GetMoveType() == MOVETYPE_NONE ) )
  4320. // {
  4321. // char commandBuffer[128];
  4322. // char commandB[32] = "spec_lerpto";
  4323. // float flLerpTime = 0.5f;
  4324. //
  4325. // //Vector vecSpecPos = g_bEngineIsHLTV ? HLTVCamera()->GetCameraPosition() : pLocalPlayer->GetAbsOrigin();
  4326. // V_snprintf( commandBuffer, sizeof( commandBuffer ), "%s %f %f %f %f %f %d %f", commandB, vecSpecPos[0], vecSpecPos[1], vecSpecPos[2], angView[0], angView[1], pTarget->entindex(), flLerpTime );
  4327. //
  4328. // engine->ClientCmd( commandBuffer );
  4329. // }
  4330. }
  4331. }
  4332. if ( (!pLocalPlayer->GetObserverTarget() && !IsHLTV()) )
  4333. return;
  4334. int nTargetSpec = -1;
  4335. if ( IsHLTV() )
  4336. {
  4337. if ( HLTVCamera()->GetPrimaryTarget() )
  4338. nTargetSpec = HLTVCamera()->GetPrimaryTarget()->entindex();
  4339. }
  4340. else
  4341. {
  4342. if ( pLocalPlayer->GetObserverTarget() )
  4343. nTargetSpec = pLocalPlayer->GetObserverTarget()->entindex();
  4344. }
  4345. C_BasePlayer *pTarget = UTIL_PlayerByIndex( nTargetSpec );
  4346. bool bIsFollowingGrenade = IsHLTV() ? HLTVCamera()->IsWatchingGrenade() : pLocalPlayer->m_bIsSpecFollowingGrenade;
  4347. CBaseEntity *pGrenade = NULL;
  4348. if ( pTarget && bHoldingGrenadeKey && bIsFollowingGrenade == false )
  4349. {
  4350. CBaseEntity *pEnt = NULL;
  4351. float flNewest = 0;
  4352. float flSpawnTime = 0;
  4353. for ( CEntitySphereQuery sphere( pTarget->GetAbsOrigin(), 1024 ); ( pEnt = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
  4354. {
  4355. CBaseCSGrenadeProjectile* pGrenadeProjectile = dynamic_cast< CBaseCSGrenadeProjectile* >( pEnt );
  4356. // filter out non-tracks
  4357. if ( pGrenadeProjectile && pGrenadeProjectile->GetThrower() && pTarget->entindex() == pGrenadeProjectile->GetThrower()->entindex() )
  4358. {
  4359. flSpawnTime = pGrenadeProjectile->m_flSpawnTime;
  4360. if ( flSpawnTime > flNewest )
  4361. {
  4362. flNewest = flSpawnTime;
  4363. pGrenade = pEnt;
  4364. }
  4365. }
  4366. }
  4367. }
  4368. if ( pGrenade && bHoldingGrenadeKey )
  4369. {
  4370. if ( IsHLTV() )
  4371. {
  4372. HLTVCamera()->SetWatchingGrenade( pGrenade, bHoldingGrenadeKey );
  4373. }
  4374. else
  4375. {
  4376. pLocalPlayer->SetSpecWatchingGrenade( pGrenade, bHoldingGrenadeKey );
  4377. }
  4378. }
  4379. else
  4380. {
  4381. // if we are currently following a grenade, but our "follow greande"
  4382. // key isn't down, stop following
  4383. if ( bHoldingGrenadeKey == false )
  4384. {
  4385. if ( IsHLTV() && bIsFollowingGrenade )
  4386. {
  4387. HLTVCamera()->SetWatchingGrenade( pGrenade, false );
  4388. }
  4389. else if ( bIsFollowingGrenade )
  4390. {
  4391. pLocalPlayer->SetSpecWatchingGrenade( pGrenade, false );
  4392. }
  4393. }
  4394. }
  4395. }
  4396. m_StartOfRoundSoundEvents.Update();
  4397. }
  4398. void C_CSPlayer::OnTimeJump()
  4399. {
  4400. C_BasePlayer::OnTimeJump();
  4401. m_fNextGlowCheckUpdate = 0;
  4402. UpdateGlows();
  4403. ClearAllBulletHitModels();
  4404. }
  4405. bool C_CSPlayer::IsHoldingSpecGrenadeKey( void )
  4406. {
  4407. bool bHoldingGrenadeKey = false;
  4408. int nGrenadeKey = cl_spec_follow_grenade_key.GetInt();
  4409. if ( nGrenadeKey == 0 )
  4410. bHoldingGrenadeKey = vgui::input()->IsKeyDown( KEY_LALT );
  4411. else if ( nGrenadeKey == 1 )
  4412. bHoldingGrenadeKey = vgui::input()->IsKeyDown( KEY_LSHIFT );
  4413. else if ( nGrenadeKey == 2 )
  4414. clientdll->IN_IsKeyDown( "in_reload", bHoldingGrenadeKey );
  4415. int x = 1;
  4416. if ( bHoldingGrenadeKey )
  4417. x++;
  4418. return bHoldingGrenadeKey;
  4419. }
  4420. void C_CSPlayer::OnDataChanged( DataUpdateType_t type )
  4421. {
  4422. BaseClass::OnDataChanged( type );
  4423. if ( type == DATA_UPDATE_CREATED )
  4424. {
  4425. SetNextClientThink( CLIENT_THINK_ALWAYS );
  4426. m_freezeCamSpotLightTexture.Init( "effects/flashlight_freezecam", TEXTURE_GROUP_OTHER, true );
  4427. }
  4428. C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer();
  4429. if ( player == this && player->GetObserverMode() != player->m_iOldObserverMode )
  4430. {
  4431. bool bRespawning = false;
  4432. bool bCompetitive = false;
  4433. if ( CSGameRules() )
  4434. {
  4435. bRespawning = (State_Get() == STATE_GUNGAME_RESPAWN && IsAbleToInstantRespawn());
  4436. if ( bRespawning )
  4437. g_HltvReplaySystem.OnLocalPlayerRespawning();
  4438. bCompetitive = CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset();
  4439. }
  4440. // Commented out because new item acknowledgement will only happen in the main menu.
  4441. // if ( !IsAlive() && ((m_iOldObserverMode < OBS_MODE_FIXED && GetObserverMode() >= OBS_MODE_FIXED) || bRespawning) )
  4442. // {
  4443. // // Show items we've picked up when we exit freezecam, or after deathcam on suicide
  4444. // if ( !bCompetitive )
  4445. // {
  4446. // // Don't do this in competitive modes, instead we'll show those at the end of the match
  4447. // InventoryManager()->ShowItemsPickedUp();
  4448. // }
  4449. // }
  4450. }
  4451. if ( m_bPlayingHostageCarrySound == false && m_hCarriedHostage )
  4452. {
  4453. m_bPlayingHostageCarrySound = true;
  4454. EmitSound( "Hostage.Breath" );
  4455. }
  4456. else if ( m_bPlayingHostageCarrySound == true && !m_hCarriedHostage )
  4457. {
  4458. m_bPlayingHostageCarrySound = false;
  4459. StopSound( "Hostage.Breath" );
  4460. }
  4461. if ( m_bOldIsScoped != m_bIsScoped )
  4462. {
  4463. m_bOldIsScoped = m_bIsScoped;
  4464. FogControllerChanged( true );
  4465. }
  4466. UpdateVisibility();
  4467. }
  4468. void C_CSPlayer::ValidateModelIndex( void )
  4469. {
  4470. UpdateMinModels();
  4471. }
  4472. void C_CSPlayer::SetModelPointer( const model_t *pModel )
  4473. {
  4474. bool bModelPointerIsChanged = ( pModel != GetModel() );
  4475. BaseClass::SetModelPointer( pModel );
  4476. if ( bModelPointerIsChanged )
  4477. {
  4478. m_bUseNewAnimstate = ( Q_stristr( modelinfo->GetModelName(GetModel()), "custom_player" ) != 0 );
  4479. m_bAddonModelsAreOutOfDate = true; // next time we update addon models, do a complete refresh
  4480. // apply BONE_ALWAYS_SETUP flag to certain hardcoded bone names, in case they're missing the flags in content
  4481. CStudioHdr *pHdr = GetModelPtr();
  4482. Assert( pHdr );
  4483. if ( pHdr )
  4484. {
  4485. for ( int i=0; i<pHdr->numbones(); i++ )
  4486. {
  4487. if ( !V_stricmp( pHdr->pBone(i)->pszName(), "lh_ik_driver" ) ||
  4488. !V_stricmp( pHdr->pBone(i)->pszName(), "lean_root" ) ||
  4489. !V_stricmp( pHdr->pBone(i)->pszName(), "lfoot_lock" ) ||
  4490. !V_stricmp( pHdr->pBone(i)->pszName(), "rfoot_lock" ) ||
  4491. !V_stricmp( pHdr->pBone(i)->pszName(), "ball_l" ) ||
  4492. !V_stricmp( pHdr->pBone(i)->pszName(), "ball_r" ) ||
  4493. !V_stricmp( pHdr->pBone(i)->pszName(), "cam_driver" ) )
  4494. {
  4495. pHdr->setBoneFlags( i, BONE_ALWAYS_SETUP );
  4496. }
  4497. }
  4498. }
  4499. }
  4500. }
  4501. void C_CSPlayer::PostDataUpdate( DataUpdateType_t updateType )
  4502. {
  4503. // C_BaseEntity assumes we're networking the entity's angles, so pretend that it
  4504. // networked the same value we already have.
  4505. SetNetworkAngles( GetLocalAngles() );
  4506. BaseClass::PostDataUpdate( updateType );
  4507. if ( updateType == DATA_UPDATE_CREATED )
  4508. {
  4509. if ( m_bUseNewAnimstate && m_PlayerAnimStateCSGO )
  4510. {
  4511. m_PlayerAnimStateCSGO->Reset();
  4512. //m_PlayerAnimStateCSGO->Update( EyeAngles()[YAW], EyeAngles()[PITCH] );
  4513. }
  4514. }
  4515. /*if ( m_nLastObserverMode != GetObserverMode() )
  4516. {
  4517. DevMsg( "Player %d tick %d observer mode %d\n", this->index, gpGlobals->tickcount, GetObserverMode() );
  4518. m_nLastObserverMode = GetObserverMode();
  4519. }*/
  4520. }
  4521. //-----------------------------------------------------------------------------
  4522. // Purpose:
  4523. // Output : Returns true on success, false on failure.
  4524. //-----------------------------------------------------------------------------
  4525. bool C_CSPlayer::Interpolate( float currentTime )
  4526. {
  4527. if ( !BaseClass::Interpolate( currentTime ) )
  4528. return false;
  4529. if ( CSGameRules()->IsFreezePeriod() )
  4530. {
  4531. // don't interpolate players position during freeze periode
  4532. SetAbsOrigin( GetNetworkOrigin() );
  4533. }
  4534. return true;
  4535. }
  4536. void C_CSPlayer::PlayClientJumpSound( void )
  4537. {
  4538. // during prediction play footstep sounds only once
  4539. if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
  4540. return;
  4541. CLocalPlayerFilter filter;
  4542. EmitSound( filter, entindex(), "Default.WalkJump" );
  4543. }
  4544. int C_CSPlayer::GetMaxHealth() const
  4545. {
  4546. return 100;
  4547. }
  4548. bool C_CSPlayer::ShouldInterpolate()
  4549. {
  4550. // [msmith] Do we need to check this for split screen as well?
  4551. // If this is the player, (or being observed by the player ) then we want to interpolate it.
  4552. if ( this == GetLocalOrInEyeCSPlayer() )
  4553. {
  4554. return true;
  4555. }
  4556. return BaseClass::ShouldInterpolate();
  4557. }
  4558. //-----------------------------------------------------------------------------
  4559. // Purpose: Return the local player, or the player being spectated in-eye
  4560. //-----------------------------------------------------------------------------
  4561. C_CSPlayer* GetLocalOrInEyeCSPlayer( void )
  4562. {
  4563. C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer();
  4564. if( player && player->GetObserverMode() == OBS_MODE_IN_EYE )
  4565. {
  4566. C_BaseEntity *target = player->GetObserverTarget();
  4567. if( target && target->IsPlayer() )
  4568. {
  4569. return ToCSPlayer( target );
  4570. }
  4571. }
  4572. return player;
  4573. }
  4574. //-----------------------------------------------------------------------------
  4575. // Purpose: Return the local player, or the player being spectated
  4576. //-----------------------------------------------------------------------------
  4577. C_CSPlayer* GetHudPlayer( void )
  4578. {
  4579. C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer();
  4580. if ( player && ( player->GetObserverMode() == OBS_MODE_IN_EYE || player->GetObserverMode() == OBS_MODE_CHASE ) )
  4581. {
  4582. C_BaseEntity *target = player->GetObserverTarget();
  4583. if( target && target->IsPlayer() )
  4584. {
  4585. return ToCSPlayer( target );
  4586. }
  4587. }
  4588. return player;
  4589. }
  4590. // FIXME(hpe ) sb: some hackery to get split screen up and running
  4591. // CON_COMMAND( joinsplitscreen, "join split screen" )
  4592. // {
  4593. // char splitScreenCommand[1024] = {0};
  4594. //
  4595. // ACTIVE_SPLITSCREEN_PLAYER_GUARD( 1 );
  4596. // Q_snprintf(splitScreenCommand, sizeof( splitScreenCommand ), "jointeam 3\njoinclass\n" );
  4597. // //engine->ClientCmd_Unrestricted(splitScreenCommand ); // ClientCmd_Unrestricted uses in_forceuser so use ClientCmd which uses GET_ACTIVE_SPLITSCREEN_PLAYER
  4598. // engine->ClientCmd(splitScreenCommand );
  4599. // }
  4600. CON_COMMAND_F( rangefinder, "rangefinder", FCVAR_CHEAT )
  4601. {
  4602. CBasePlayer *pPlayer = ToBasePlayer( C_CSPlayer::GetLocalCSPlayer() );
  4603. if ( !pPlayer )
  4604. return;
  4605. // Rangefinder
  4606. trace_t tr;
  4607. Vector vecForward;
  4608. AngleVectors( pPlayer->EyeAngles(), &vecForward );
  4609. UTIL_TraceLine( pPlayer->EyePosition(), pPlayer->EyePosition() + vecForward * MAX_COORD_RANGE, MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr );
  4610. float flDist_aim = ( tr.fraction != 1.0 ) ? ( tr.startpos - tr.endpos ).Length() : 0;
  4611. if ( flDist_aim )
  4612. {
  4613. float flDist_aim = ( tr.startpos - tr.endpos ).Length();
  4614. float flDist_aim2D = ( tr.startpos - tr.endpos ).Length2D();
  4615. Msg( "\nStartPos: %.4f %.4f %.4f --- EndPos: %.4f %.4f %.4f\n", tr.startpos.x, tr.startpos.y, tr.startpos.z, tr.endpos.x, tr.endpos.y, tr.endpos.z );
  4616. Msg( "3D Distance: %.4f units --- 2D Distance: %.4f units\n", flDist_aim, flDist_aim2D );
  4617. }
  4618. }
  4619. #define MAX_FLASHBANG_OPACITY 75.0f
  4620. //-----------------------------------------------------------------------------
  4621. // Purpose: Update this client's targetid entity
  4622. //-----------------------------------------------------------------------------
  4623. ConVar clDrawTargetIDTrace( "clDrawTargetIDTrace", "0", FCVAR_CLIENTDLL | FCVAR_DEVELOPMENTONLY, "visualizing line trace for target ID" );
  4624. void C_CSPlayer::UpdateIDTarget()
  4625. {
  4626. ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( this );
  4627. // Clear old target and find a new one
  4628. m_iIDEntIndex = 0;
  4629. // don't show IDs if mp_playerid == 2
  4630. if ( mp_playerid.GetInt() == 2 )
  4631. return;
  4632. //Check how much of a screen fade we have.
  4633. //if it's more than 75 then we can't see what's going on so we don't display the id.
  4634. byte color[4];
  4635. bool blend;
  4636. GetViewEffects()->GetFadeParams( &color[0], &color[1], &color[2], &color[3], &blend );
  4637. if ( color[3] > MAX_FLASHBANG_OPACITY && ( IsAlive() || GetObserverMode() == OBS_MODE_IN_EYE ) )
  4638. return;
  4639. trace_t tr;
  4640. Vector vecStart, vecEnd;
  4641. Vector forward;
  4642. QAngle viewAngles;
  4643. float fov;
  4644. Vector eyePos;
  4645. CalcPlayerView( eyePos, viewAngles, fov );
  4646. if ( PlatformInputDevice::IsInputDeviceAPointer( g_pInputSystem->GetCurrentInputDevice() ) )
  4647. {
  4648. forward = GetAimDirection();
  4649. }
  4650. else
  4651. {
  4652. AngleVectors( viewAngles, &forward );
  4653. }
  4654. // convert to vector
  4655. VectorMA( eyePos , 2500, forward, vecEnd );
  4656. VectorMA( eyePos , 10, forward, vecStart );
  4657. #define BLUE 0,0,255
  4658. if( clDrawTargetIDTrace.GetBool() )
  4659. {
  4660. DebugDrawLine( vecStart, vecEnd, BLUE, true, 60.0f );
  4661. clDrawTargetIDTrace.SetValue( 0 );
  4662. }
  4663. UTIL_TraceLine( vecStart, vecEnd, MASK_VISIBLE_AND_NPCS | MASK_SOLID, GetLocalOrInEyeCSPlayer(), COLLISION_GROUP_NONE, &tr );
  4664. vecEnd = tr.endpos + (32 * forward);
  4665. if ( !tr.startsolid && !tr.DidHitNonWorldEntity() )
  4666. {
  4667. CTraceFilterSimple filter( GetLocalOrInEyeCSPlayer(), COLLISION_GROUP_NONE );
  4668. // Check for player hitboxes extending outside their collision bounds
  4669. const float rayExtension = 40.0f;
  4670. UTIL_ClipTraceToPlayers(vecStart, vecEnd + forward * rayExtension, MASK_SOLID|CONTENTS_HITBOX, &filter, &tr );
  4671. }
  4672. if ( !tr.startsolid && tr.DidHitNonWorldEntity() )
  4673. {
  4674. C_BaseEntity *pEntity = tr.m_pEnt;
  4675. if ( pEntity && (pEntity != this ) )
  4676. {
  4677. if ( mp_playerid.GetInt() == 1 ) // only show team names
  4678. {
  4679. if ( pEntity->GetTeamNumber() != GetTeamNumber() )
  4680. {
  4681. return;
  4682. }
  4683. }
  4684. if ( LineGoesThroughSmoke( vecStart, pEntity->WorldSpaceCenter(), 1.0f ) )
  4685. {
  4686. return;
  4687. }
  4688. // only test against hit boxes for enemy players
  4689. if ( pEntity->GetTeamNumber() != GetTeamNumber() )
  4690. {
  4691. // trace again here to test hitboxes
  4692. UTIL_TraceLine( vecStart, vecEnd, MASK_VISIBLE_AND_NPCS|CONTENTS_HITBOX, GetLocalOrInEyeCSPlayer(), COLLISION_GROUP_NONE, &tr );
  4693. if ( (tr.surface.flags & SURF_HITBOX) == 0 )
  4694. return;
  4695. }
  4696. if ( !GetIDTarget() && ( !m_iOldIDEntIndex || ( ( m_delayTargetIDTimer.GetRemainingRatio() == 0 ) && ( m_holdTargetIDTimer.GetRemainingRatio() == 0 ) ) ) )
  4697. {
  4698. // track when we first mouse over the target
  4699. float flDelay = mp_playerid_delay.GetFloat();
  4700. C_CSPlayer *pPlayer = ( C_CSPlayer* ) ToCSPlayer( pEntity );
  4701. if ( pPlayer && pPlayer->IsAssassinationTarget() )
  4702. {
  4703. flDelay = 0; // Show assassination target names immediately
  4704. }
  4705. m_delayTargetIDTimer.Start( flDelay );
  4706. }
  4707. m_iIDEntIndex = pEntity->entindex();
  4708. m_iOldIDEntIndex = m_iIDEntIndex;
  4709. m_holdTargetIDTimer.Start( mp_playerid_hold.GetFloat() );
  4710. }
  4711. }
  4712. }
  4713. void C_CSPlayer::UpdateTargetedWeapon( void )
  4714. {
  4715. m_iTargetedWeaponEntIndex = 0;
  4716. Vector aimDir;
  4717. AngleVectors( GetFinalAimAngle(), &aimDir );
  4718. // FIXME: if you drop a weapon at a teammates' feet, you won't get the HUD prompt text because the teammate id
  4719. // trace (which uses the bounding box of the teammate) is prioritized in the hud over the prompt to pick up the weapon.
  4720. // Pressing USE while looking at a weapon a teammate is standing on will still swap to it, since this trace is
  4721. // succeeding - but you don't get the on-screen prompt. This kinda sucks during buytime, ideally the hud should
  4722. // support drawing the teammate name AND the weapon pickup promt at the same time.
  4723. trace_t result;
  4724. CTraceFilterOmitPlayers traceFilter; // don't hit players with this trace
  4725. UTIL_TraceLine( EyePosition(), EyePosition() + MAX_WEAPON_NAME_POPUP_RANGE * aimDir, MASK_SHOT, &traceFilter, &result );
  4726. if ( result.DidHitNonWorldEntity() && result.m_pEnt->IsBaseCombatWeapon() )
  4727. {
  4728. if ( LineGoesThroughSmoke( EyePosition(), result.m_pEnt->WorldSpaceCenter(), 1.0f ) )
  4729. return;
  4730. //now that we have a weapon, we check to see if we are also looking at a bomb
  4731. // setting the weaponEntIndex to the bomb prevents the hint coming up to
  4732. // pick up a weapon if it occupies the same space as a bomb
  4733. if ( GetUsableHighPriorityEntity() )
  4734. return;
  4735. // Set if to point at the weapon
  4736. m_iTargetedWeaponEntIndex = result.m_pEnt->entindex();
  4737. }
  4738. }
  4739. //-----------------------------------------------------------------------------
  4740. // Purpose: Input handling
  4741. //-----------------------------------------------------------------------------
  4742. bool C_CSPlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd )
  4743. {
  4744. // Bleh... we will wind up needing to access bones for attachments in here.
  4745. C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true );
  4746. static QAngle angMoveAngle( 0.0f, 0.0f, 0.0f );
  4747. bool bNoTaunt = true;
  4748. bool bInTaunt = IsTaunting() && IsThirdPersonTaunt();
  4749. if ( bInTaunt )
  4750. {
  4751. pCmd->forwardmove = 0.0f;
  4752. pCmd->sidemove = 0.0f;
  4753. pCmd->upmove = 0.0f;
  4754. pCmd->weaponselect = 0;
  4755. pCmd->buttons = 0;
  4756. VectorCopy( angMoveAngle, pCmd->viewangles );
  4757. bNoTaunt = false;
  4758. }
  4759. else
  4760. {
  4761. VectorCopy( pCmd->viewangles, angMoveAngle );
  4762. }
  4763. BaseClass::CreateMove( flInputSampleTime, pCmd );
  4764. return bNoTaunt;
  4765. }
  4766. //-----------------------------------------------------------------------------
  4767. // Purpose: Flash this entity on the radar
  4768. //-----------------------------------------------------------------------------
  4769. bool C_CSPlayer::IsInHostageRescueZone()
  4770. {
  4771. return m_bInHostageRescueZone;
  4772. }
  4773. void C_CSPlayer::SetBuyMenuOpen( bool bOpen )
  4774. {
  4775. m_bIsBuyMenuOpen = bOpen;
  4776. if ( bOpen == true )
  4777. engine->ClientCmd( "open_buymenu" );
  4778. else
  4779. engine->ClientCmd( "close_buymenu" );
  4780. }
  4781. CWeaponCSBase* C_CSPlayer::GetActiveCSWeapon() const
  4782. {
  4783. return assert_cast< CWeaponCSBase* >( GetActiveWeapon() );
  4784. }
  4785. CWeaponCSBase* C_CSPlayer::GetCSWeapon( CSWeaponID id ) const
  4786. {
  4787. for (int i=0;i<MAX_WEAPONS;i++ )
  4788. {
  4789. CBaseCombatWeapon *weapon = GetWeapon( i );
  4790. if ( weapon )
  4791. {
  4792. CWeaponCSBase *csWeapon = assert_cast< CWeaponCSBase * >( weapon );
  4793. if ( csWeapon )
  4794. {
  4795. if ( id == csWeapon->GetCSWeaponID() )
  4796. {
  4797. return csWeapon;
  4798. }
  4799. }
  4800. }
  4801. }
  4802. return NULL;
  4803. }
  4804. //REMOVEME
  4805. /*
  4806. void C_CSPlayer::SetFireAnimation( PLAYER_ANIM playerAnim )
  4807. {
  4808. Activity idealActivity = ACT_WALK;
  4809. // Figure out stuff about the current state.
  4810. float speed = GetAbsVelocity().Length2D();
  4811. bool isMoving = ( speed != 0.0f ) ? true : false;
  4812. bool isDucked = ( GetFlags() & FL_DUCKING ) ? true : false;
  4813. bool isStillJumping = false; //!( GetFlags() & FL_ONGROUND );
  4814. bool isRunning = false;
  4815. if ( speed > ARBITRARY_RUN_SPEED )
  4816. {
  4817. isRunning = true;
  4818. }
  4819. // Now figure out what to do based on the current state and the new state.
  4820. switch ( playerAnim )
  4821. {
  4822. default:
  4823. case PLAYER_RELOAD:
  4824. case PLAYER_ATTACK1:
  4825. case PLAYER_IDLE:
  4826. case PLAYER_WALK:
  4827. // Are we still jumping?
  4828. // If so, keep playing the jump animation.
  4829. if ( !isStillJumping )
  4830. {
  4831. idealActivity = ACT_WALK;
  4832. if ( isDucked )
  4833. {
  4834. idealActivity = !isMoving ? ACT_CROUCHIDLE : ACT_RUN_CROUCH;
  4835. }
  4836. else
  4837. {
  4838. if ( isRunning )
  4839. {
  4840. idealActivity = ACT_RUN;
  4841. }
  4842. else
  4843. {
  4844. idealActivity = isMoving ? ACT_WALK : ACT_IDLE;
  4845. }
  4846. }
  4847. // Allow body yaw to override for standing and turning in place
  4848. idealActivity = m_PlayerAnimState.BodyYawTranslateActivity( idealActivity );
  4849. }
  4850. break;
  4851. case PLAYER_JUMP:
  4852. idealActivity = ACT_HOP;
  4853. break;
  4854. case PLAYER_DIE:
  4855. // Uses Ragdoll now???
  4856. idealActivity = ACT_DIESIMPLE;
  4857. break;
  4858. // FIXME: Use overlays for reload, start/leave aiming, attacking
  4859. case PLAYER_START_AIMING:
  4860. case PLAYER_LEAVE_AIMING:
  4861. idealActivity = ACT_WALK;
  4862. break;
  4863. }
  4864. CWeaponCSBase *pWeapon = GetActiveCSWeapon();
  4865. if ( pWeapon )
  4866. {
  4867. Activity aWeaponActivity = idealActivity;
  4868. if ( playerAnim == PLAYER_ATTACK1 )
  4869. {
  4870. switch ( idealActivity )
  4871. {
  4872. case ACT_WALK:
  4873. default:
  4874. aWeaponActivity = ACT_PLAYER_WALK_FIRE;
  4875. break;
  4876. case ACT_RUN:
  4877. aWeaponActivity = ACT_PLAYER_RUN_FIRE;
  4878. break;
  4879. case ACT_IDLE:
  4880. aWeaponActivity = ACT_PLAYER_IDLE_FIRE;
  4881. break;
  4882. case ACT_CROUCHIDLE:
  4883. aWeaponActivity = ACT_PLAYER_CROUCH_FIRE;
  4884. break;
  4885. case ACT_RUN_CROUCH:
  4886. aWeaponActivity = ACT_PLAYER_CROUCH_WALK_FIRE;
  4887. break;
  4888. }
  4889. }
  4890. m_PlayerAnimState.SetWeaponLayerSequence( pWeapon->GetPlayerAnimationExtension(), aWeaponActivity );
  4891. }
  4892. }
  4893. */
  4894. ShadowType_t C_CSPlayer::ShadowCastType( void )
  4895. {
  4896. if ( !IsVisible() )
  4897. return SHADOWS_NONE;
  4898. return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
  4899. }
  4900. //-----------------------------------------------------------------------------
  4901. // Purpose: Returns whether or not we can switch to the given weapon.
  4902. // Input : pWeapon -
  4903. //-----------------------------------------------------------------------------
  4904. bool C_CSPlayer::Weapon_CanSwitchTo( CBaseCombatWeapon *pWeapon )
  4905. {
  4906. if ( !pWeapon->CanDeploy() )
  4907. return false;
  4908. if ( GetActiveWeapon() )
  4909. {
  4910. if ( !GetActiveWeapon()->CanHolster() )
  4911. return false;
  4912. }
  4913. return true;
  4914. }
  4915. ConVar clTaserShakeFreqMin( "clTaserShakeFreqMin", "0.2", 0, "how often the shake is applied (min time)" );
  4916. ConVar clTaserShakeFreqMax( "clTaserShakeFreqMax", "0.7", 0, "how often the shake is applied (max time)" );
  4917. ConVar clTaserShakeTimeTotal( "clTaserShakeTimeTotal", "7.0", 0, "time the taser shake is applied." );
  4918. void C_CSPlayer::HandleTaserAnimation()
  4919. {
  4920. if ( m_bClientSideRagdoll && m_bKilledByTaser )
  4921. {
  4922. if ( m_nextTaserShakeTime < gpGlobals->curtime )
  4923. {
  4924. // we're ready to apply a taser force
  4925. C_CSRagdoll *pRagdoll = (C_CSRagdoll* )m_hRagdoll.Get();
  4926. if ( pRagdoll )
  4927. {
  4928. pRagdoll->ApplyRandomTaserForce();
  4929. }
  4930. if ( m_firstTaserShakeTime == 0.0f )
  4931. {
  4932. m_firstTaserShakeTime = gpGlobals->curtime;
  4933. EmitSound("Player.DeathTaser" ); // play death audio here
  4934. }
  4935. if ( m_firstTaserShakeTime + clTaserShakeTimeTotal.GetFloat() < gpGlobals->curtime )
  4936. {
  4937. // we've waited more than clTaserShakeTimeTotal since our first shake so we're done with the taze effect... AKA: "DON'T TAZE ME BRO"
  4938. m_bKilledByTaser = false;
  4939. m_firstTaserShakeTime = 0.0f;
  4940. }
  4941. else
  4942. {
  4943. // set the timer for our next shake
  4944. m_nextTaserShakeTime = gpGlobals->curtime + RandomFloat( clTaserShakeFreqMin.GetFloat(), clTaserShakeFreqMax.GetFloat() );
  4945. }
  4946. }
  4947. }
  4948. }
  4949. void C_CSPlayer::UpdateClientSideAnimation()
  4950. {
  4951. if ( m_bUseNewAnimstate )
  4952. {
  4953. m_PlayerAnimStateCSGO->Update( EyeAngles()[YAW], EyeAngles()[PITCH] );
  4954. }
  4955. else
  4956. {
  4957. // We do this in a different order than the base class.
  4958. // We need our cycle to be valid for when we call the playeranimstate update code,
  4959. // or else it'll synchronize the upper body anims with the wrong cycle.
  4960. if ( GetSequence() != -1 )
  4961. {
  4962. // move frame forward
  4963. FrameAdvance( 0.0f ); // 0 means to use the time we last advanced instead of a constant
  4964. }
  4965. if ( C_BasePlayer::IsLocalPlayer( this ) )
  4966. m_PlayerAnimState->Update( EyeAngles()[YAW], EyeAngles()[PITCH] );
  4967. else
  4968. m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] );
  4969. }
  4970. if ( GetSequence() != -1 )
  4971. {
  4972. // latch old values
  4973. OnLatchInterpolatedVariables( LATCH_ANIMATION_VAR );
  4974. }
  4975. if ( m_bKilledByTaser )
  4976. {
  4977. HandleTaserAnimation();
  4978. }
  4979. // We only update the view model for the local player.
  4980. if ( IsLocalPlayer( this ) )
  4981. {
  4982. CWeaponCSBase *pWeapon = GetActiveCSWeapon();
  4983. if ( pWeapon )
  4984. {
  4985. C_BaseViewModel *pViewModel = assert_cast<C_BaseViewModel *>( GetViewModel( pWeapon->m_nViewModelIndex ) );
  4986. if ( pViewModel )
  4987. {
  4988. pViewModel->UpdateAllViewmodelAddons();
  4989. }
  4990. }
  4991. else
  4992. {
  4993. //We have a null weapon so remove the add ons for all the view models for this player.
  4994. for ( int i=0; i<MAX_VIEWMODELS; ++i )
  4995. {
  4996. C_BaseViewModel *pViewModel = assert_cast<C_BaseViewModel *>( GetViewModel( i ) );
  4997. if ( pViewModel )
  4998. {
  4999. pViewModel->RemoveViewmodelArmModels();
  5000. pViewModel->RemoveViewmodelLabel();
  5001. pViewModel->RemoveViewmodelStatTrak();
  5002. pViewModel->RemoveViewmodelStickers();
  5003. }
  5004. }
  5005. }
  5006. }
  5007. }
  5008. float g_flMuzzleFlashScale=1;
  5009. void C_CSPlayer::ProcessMuzzleFlashEvent()
  5010. {
  5011. CWeaponCSBase *pWeapon = GetActiveCSWeapon();
  5012. if ( !pWeapon )
  5013. return;
  5014. int splitScreenRenderFlags = 0x0;
  5015. FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
  5016. {
  5017. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  5018. CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  5019. // We don't want to show third person muzzle flash effects for this player if the splitscreen viewer is looking at this player in first person mode.
  5020. bool viewingInFirstPersonMode = ( pLocalPlayer == this && !pLocalPlayer->ShouldDraw() ) ||
  5021. ( pLocalPlayer && pLocalPlayer->GetObserverTarget() == this && pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE && !pLocalPlayer->IsInObserverInterpolation() );
  5022. if ( !viewingInFirstPersonMode )
  5023. {
  5024. splitScreenRenderFlags |= (0x1 << hh );
  5025. }
  5026. }
  5027. // Don't draw the effects if this third person weapon is not drawing in any screen.
  5028. if ( 0 == splitScreenRenderFlags )
  5029. {
  5030. return;
  5031. }
  5032. else if ( splitScreenRenderFlags >= 3 )
  5033. {
  5034. // Seen by both split screen players 1 and 2 so use -1 for visible to all split screen players.
  5035. splitScreenRenderFlags = -1;
  5036. }
  5037. else
  5038. {
  5039. splitScreenRenderFlags -= 1;
  5040. }
  5041. // Muzzle Flash Effect.
  5042. int iAttachmentIndex = pWeapon->GetMuzzleAttachmentIndex_3rdPerson();
  5043. const char* pszEffect = pWeapon->GetMuzzleFlashEffectName_3rdPerson();
  5044. CBaseWeaponWorldModel *pWeaponWorldModel = pWeapon->GetWeaponWorldModel();
  5045. if ( !pWeaponWorldModel )
  5046. return;
  5047. if ( pszEffect && Q_strlen(pszEffect ) > 0 && iAttachmentIndex >= 0 && pWeaponWorldModel && pWeaponWorldModel->ShouldDraw() && pWeaponWorldModel->IsVisible() && !pWeaponWorldModel->HasDormantOwner() )
  5048. {
  5049. pWeaponWorldModel->GetAttachment( iAttachmentIndex, m_vecLastMuzzleFlashPos, m_angLastMuzzleFlashAngle );
  5050. DispatchParticleEffect( pszEffect, PATTACH_POINT_FOLLOW, pWeaponWorldModel, iAttachmentIndex, false, splitScreenRenderFlags );
  5051. }
  5052. // Brass Eject Effect.
  5053. iAttachmentIndex = pWeapon->GetEjectBrassAttachmentIndex_3rdPerson();
  5054. pszEffect = pWeapon->GetEjectBrassEffectName();
  5055. if ( pszEffect && Q_strlen(pszEffect ) > 0 && iAttachmentIndex >= 0 && pWeaponWorldModel && pWeaponWorldModel->ShouldDraw() && pWeaponWorldModel->IsVisible() && !pWeaponWorldModel->HasDormantOwner() )
  5056. {
  5057. DispatchParticleEffect( pszEffect, PATTACH_POINT_FOLLOW, pWeaponWorldModel, iAttachmentIndex, false, splitScreenRenderFlags );
  5058. }
  5059. }
  5060. const QAngle& C_CSPlayer::EyeAngles()
  5061. {
  5062. if ( IsLocalPlayer( this ) && !g_nKillCamMode && !g_bEngineIsHLTV )
  5063. {
  5064. return BaseClass::EyeAngles();
  5065. }
  5066. else
  5067. {
  5068. return m_angEyeAngles;
  5069. }
  5070. }
  5071. bool C_CSPlayer::ShouldDraw( void )
  5072. {
  5073. // If we're dead, our ragdoll will be drawn for us instead.
  5074. if ( !IsAlive() )
  5075. return false;
  5076. if( GetTeamNumber() == TEAM_SPECTATOR )
  5077. return false;
  5078. if( IsLocalPlayer( this ) )
  5079. {
  5080. if ( IsRagdoll() )
  5081. return true;
  5082. return ShouldDrawLocalPlayer();
  5083. }
  5084. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  5085. // keep drawing players we're observing with the interpolating spectator camera
  5086. if ( pLocalPlayer && pLocalPlayer->GetObserverInterpState() == OBSERVER_INTERP_TRAVELING )
  5087. {
  5088. return true;
  5089. }
  5090. // don't draw players we're observing in first-person
  5091. if ( pLocalPlayer && pLocalPlayer->GetObserverTarget() == ToBasePlayer(this) && pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
  5092. {
  5093. return false;
  5094. }
  5095. return BaseClass::ShouldDraw();
  5096. }
  5097. #define APPROX_CENTER_PLAYER Vector(0,0,50)
  5098. bool C_CSPlayer::GetAttachment( int number, matrix3x4_t &matrix )
  5099. {
  5100. if ( IsAnimLODflagSet(ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) || IsDormant() )
  5101. {
  5102. MatrixCopy( EntityToWorldTransform(), matrix );
  5103. matrix.SetOrigin( matrix.GetOrigin() + APPROX_CENTER_PLAYER );
  5104. return true;
  5105. }
  5106. return BaseClass::GetAttachment( number, matrix );
  5107. }
  5108. bool C_CSPlayer::GetAttachment( int number, Vector &origin )
  5109. {
  5110. if ( IsAnimLODflagSet(ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) || IsDormant() )
  5111. {
  5112. origin = GetAbsOrigin() + APPROX_CENTER_PLAYER;
  5113. return true;
  5114. }
  5115. return BaseClass::GetAttachment( number, origin );
  5116. }
  5117. bool C_CSPlayer::GetAttachment( int number, Vector &origin, QAngle &angles )
  5118. {
  5119. if ( IsAnimLODflagSet(ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) || IsDormant() )
  5120. {
  5121. origin = GetAbsOrigin() + APPROX_CENTER_PLAYER;
  5122. angles = GetAbsAngles();
  5123. return true;
  5124. }
  5125. return BaseClass::GetAttachment( number, origin, angles );
  5126. }
  5127. //-----------------------------------------------------------------------------
  5128. //
  5129. //-----------------------------------------------------------------------------
  5130. #ifdef DEBUG
  5131. ConVar cl_animlod_dotproduct( "cl_animlod_dotproduct", "0.3" );
  5132. #define animlod_dotproduct cl_animlod_dotproduct.GetFloat()
  5133. #else
  5134. #define animlod_dotproduct 0.3
  5135. #endif
  5136. void C_CSPlayer::ReevauluateAnimLOD( int boneMask )
  5137. {
  5138. if ( !engine->IsHLTV() && gpGlobals->framecount != m_nComputedLODframe )
  5139. {
  5140. m_nCustomBlendingRuleMask = -1;
  5141. bool bFirstSetup = ( m_nComputedLODframe == 0 );
  5142. m_nComputedLODframe = gpGlobals->framecount;
  5143. // save off the old flags before we reset and recompute the new ones, so we have a one-step record of change
  5144. m_nAnimLODflagsOld = m_nAnimLODflags;
  5145. ClearAnimLODflags();
  5146. if ( !bFirstSetup )
  5147. {
  5148. if ( !IsVisible() || IsDormant() || (IsLocalPlayer( this ) && !C_BasePlayer::ShouldDrawLocalPlayer()) || !ShouldDraw() )
  5149. {
  5150. // always do cheap bone setup for an invisible local player
  5151. SetAnimLODflag( ANIMLODFLAG_INVISIBLELOCALPLAYER );
  5152. }
  5153. else
  5154. {
  5155. // is this player being interpolated towards by an observer camera?
  5156. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  5157. bool bTargetOfInterpolatingObsCam = ( pLocalPlayer && pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE &&
  5158. pLocalPlayer->GetObserverTarget() == ToBasePlayer(this) &&
  5159. pLocalPlayer->GetObserverInterpState() != OBSERVER_INTERP_NONE );
  5160. if ( !bTargetOfInterpolatingObsCam )
  5161. {
  5162. // if this player is behind the camera and beyond a certain distance, perform only cheap and simple bone setup.
  5163. Vector vecEyeToPlayer = EyePosition() - MainViewOrigin(GET_ACTIVE_SPLITSCREEN_SLOT());
  5164. m_flDistanceFromCamera = vecEyeToPlayer.Length();
  5165. if ( m_flDistanceFromCamera > 400.0f )
  5166. {
  5167. SetAnimLODflag( ANIMLODFLAG_DISTANT );
  5168. Vector vecEyeDir = MainViewForward(GET_ACTIVE_SPLITSCREEN_SLOT());
  5169. float flEyeDirToPlayerDirDot = DotProduct( vecEyeToPlayer.Normalized(), vecEyeDir.Normalized() );
  5170. if ( flEyeDirToPlayerDirDot < animlod_dotproduct )
  5171. {
  5172. SetAnimLODflag( ANIMLODFLAG_OUTSIDEVIEWFRUSTUM );
  5173. }
  5174. }
  5175. }
  5176. }
  5177. }
  5178. // weapon world model mimics player's anim lod flags
  5179. C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
  5180. if ( pWeapon )
  5181. {
  5182. CBaseWeaponWorldModel *pWeaponWorldModel = pWeapon->m_hWeaponWorldModel.Get();
  5183. if ( pWeaponWorldModel )
  5184. {
  5185. pWeaponWorldModel->m_nAnimLODflags = m_nAnimLODflags;
  5186. pWeaponWorldModel->m_nAnimLODflagsOld = m_nAnimLODflagsOld;
  5187. }
  5188. }
  5189. bool bCrossedDistanceThreshold = ((m_nAnimLODflags & ANIMLODFLAG_DISTANT) != 0) != ((m_nAnimLODflagsOld & ANIMLODFLAG_DISTANT) != 0);
  5190. // unless this is the first setup or the lod state is changing this frame, use a much more conservative bone mask for distant lod
  5191. if ( !bFirstSetup && IsAnimLODflagSet( ANIMLODFLAG_DISTANT ) && !bCrossedDistanceThreshold )
  5192. {
  5193. m_nCustomBlendingRuleMask = (BONE_USED_BY_ATTACHMENT | BONE_USED_BY_HITBOX);
  5194. }
  5195. // if the player has just become awake (no longer dormant) then we should set up all the bones (treat it like a first setup)
  5196. if ( bFirstSetup || (IsDormant() && !(m_nAnimLODflagsOld & ANIMLODFLAG_DORMANT)) )
  5197. {
  5198. m_nCustomBlendingRuleMask = -1;
  5199. }
  5200. //if ( bCrossedDistanceThreshold )
  5201. //{
  5202. // if ( IsAnimLODflagSet( ANIMLODFLAG_DISTANT ) )
  5203. // {
  5204. // debugoverlay->AddTextOverlay( GetAbsOrigin(), 5, "Distant" );
  5205. // }
  5206. // else
  5207. // {
  5208. // debugoverlay->AddTextOverlay( GetAbsOrigin(), 5, "Closer" );
  5209. // }
  5210. //}
  5211. //
  5212. //bool bEnteredFrustum = ((m_nAnimLODflags & ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) != 0) != ((m_nAnimLODflagsOld & ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) != 0);
  5213. //
  5214. //if ( bEnteredFrustum )
  5215. //{
  5216. // if ( !IsAnimLODflagSet( ANIMLODFLAG_OUTSIDEVIEWFRUSTUM ) )
  5217. // {
  5218. // debugoverlay->AddTextOverlay( GetAbsOrigin(), 2, "Enter frustum" );
  5219. // }
  5220. //}
  5221. }
  5222. // // player models don't have explicit levels of vertex lod - yet. This is how vert lod would be masked:
  5223. // studiohwdata_t *pHardwareData = g_pMDLCache->GetHardwareData( modelinfo->GetCacheHandle( GetModel() ) );
  5224. // int nHighLod = MAX( pHardwareData->m_RootLOD, pHardwareData->m_NumLODs - 1 );
  5225. // m_nCustomBlendingRuleMask ... BONE_USED_BY_VERTEX_AT_LOD(nHighLod);
  5226. }
  5227. bool C_CSPlayer::SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
  5228. {
  5229. ReevauluateAnimLOD( boneMask );
  5230. return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
  5231. }
  5232. void C_CSPlayer::AccumulateLayers( IBoneSetup &boneSetup, BoneVector pos[], BoneQuaternion q[], float currentTime )
  5233. {
  5234. if ( !engine->IsHLTV() && IsAnimLODflagSet( ANIMLODFLAG_DORMANT | ANIMLODFLAG_OUTSIDEVIEWFRUSTUM ) )
  5235. return;
  5236. C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
  5237. CBaseWeaponWorldModel *pWeaponWorldModel = NULL;
  5238. if ( pWeapon )
  5239. pWeaponWorldModel = pWeapon->m_hWeaponWorldModel.Get();
  5240. if ( pWeapon && pWeaponWorldModel && m_bUseNewAnimstate && m_PlayerAnimStateCSGO )
  5241. {
  5242. m_PlayerAnimStateCSGO->OnClientWeaponChange( GetActiveCSWeapon() );
  5243. //pre-bone-setup snapshot capture to grab bones before a deleted weapon pops the pose
  5244. int oldReadableBones = m_BoneAccessor.GetReadableBones();
  5245. m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING );
  5246. m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].UpdateReadOnly();
  5247. m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].UpdateReadOnly();
  5248. m_BoneAccessor.SetReadableBones( oldReadableBones );
  5249. AccumulateInterleavedDispatchedLayers( pWeaponWorldModel, boneSetup, pos, q, currentTime, GetLocalOrInEyeCSPlayer() == this );
  5250. return;
  5251. }
  5252. BaseClass::AccumulateLayers( boneSetup, pos, q, currentTime );
  5253. }
  5254. void C_CSPlayer::NotifyOnLayerChangeSequence( const CAnimationLayer* pLayer, const int nNewSequence )
  5255. {
  5256. if ( pLayer && m_bUseNewAnimstate && m_PlayerAnimStateCSGO )
  5257. {
  5258. m_PlayerAnimStateCSGO->NotifyOnLayerChangeSequence( pLayer, nNewSequence );
  5259. }
  5260. }
  5261. void C_CSPlayer::NotifyOnLayerChangeWeight( const CAnimationLayer* pLayer, const float flNewWeight )
  5262. {
  5263. if ( pLayer && m_bUseNewAnimstate && m_PlayerAnimStateCSGO )
  5264. {
  5265. m_PlayerAnimStateCSGO->NotifyOnLayerChangeWeight( pLayer, flNewWeight );
  5266. }
  5267. }
  5268. void C_CSPlayer::NotifyOnLayerChangeCycle( const CAnimationLayer* pLayer, const float flNewCycle )
  5269. {
  5270. if ( pLayer && m_bUseNewAnimstate && m_PlayerAnimStateCSGO )
  5271. {
  5272. m_PlayerAnimStateCSGO->NotifyOnLayerChangeCycle( pLayer, flNewCycle );
  5273. }
  5274. }
  5275. //-----------------------------------------------------------------------------
  5276. //
  5277. //-----------------------------------------------------------------------------
  5278. void C_CSPlayer::DoAnimStateEvent( PlayerAnimEvent_t evt )
  5279. {
  5280. m_PlayerAnimState->DoAnimationEvent( evt );
  5281. }
  5282. void CBoneSnapshot::Update( CBaseAnimating* pEnt, bool bReadOnly )
  5283. {
  5284. if ( m_flWeight > 0 )
  5285. m_flWeight = clamp( smoothstep_bounds( m_flDecayEndTime, m_flDecayStartTime, gpGlobals->curtime ), 0, 1 );
  5286. // if the last known bonesetup occurred too long ago, it doesn't make sense to capture a snapshot of severely outdated or possibly uninitialized bones.
  5287. if ( !IsBoneSetupTimeIndexRecent() || !pEnt )
  5288. return;
  5289. if ( pEnt != m_pEnt )
  5290. {
  5291. Init( pEnt );
  5292. return;
  5293. }
  5294. if ( !m_bEnabled || m_pEnt->Teleported() || m_pEnt->IsEffectActive(EF_NOINTERP) )
  5295. {
  5296. AbandonAnyPending();
  5297. return;
  5298. }
  5299. C_CSPlayer* pPlayer = ToCSPlayer( m_pEnt );
  5300. if ( pPlayer && ( pPlayer->IsAnimLODflagSet(ANIMLODFLAG_INVISIBLELOCALPLAYER|ANIMLODFLAG_DORMANT|ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) || (gpGlobals->curtime - pPlayer->m_flLastSpawnTimeIndex) <= 0.5f ) )
  5301. {
  5302. AbandonAnyPending();
  5303. return;
  5304. }
  5305. if ( !m_bWeightlistInitialized )
  5306. InitWeightList();
  5307. if ( !bReadOnly && m_flWeight > 0 )
  5308. PlaybackSnapshot();
  5309. if ( IsCapturePending() )
  5310. CaptureSnapshot();
  5311. }
  5312. void CBoneSnapshot::CaptureSnapshot( void )
  5313. {
  5314. if ( !m_bCapturePending || !m_pEnt || !m_pEnt->IsVisible() )
  5315. return;
  5316. CStudioHdr *pHdr = m_pEnt->GetModelPtr();
  5317. if ( !pHdr )
  5318. return;
  5319. const studiohdr_t *pRenderHdr = pHdr->GetRenderHdr();
  5320. if ( pRenderHdr )
  5321. {
  5322. if ( m_nStudioRenderHdrId == -1 )
  5323. {
  5324. m_nStudioRenderHdrId = pRenderHdr->id;
  5325. }
  5326. else if ( m_nStudioRenderHdrId != pRenderHdr->id )
  5327. {
  5328. // render hdr id changed underneath us, likely a model swap
  5329. Init( m_pEnt );
  5330. return;
  5331. }
  5332. }
  5333. matrix3x4_t matPlayer;
  5334. AngleMatrix( m_pEnt->GetRenderAngles(), m_pEnt->GetRenderOrigin(), matPlayer );
  5335. matrix3x4_t matPlayerInv = matPlayer.InverseTR();
  5336. for (int i = 0; i < pHdr->numbones(); ++i)
  5337. {
  5338. if ( m_Weightlist[i] <= 0 )
  5339. continue;
  5340. ConcatTransforms( matPlayerInv, m_pEnt->GetBone(i), m_Cache[i] );
  5341. }
  5342. FOR_EACH_VEC( m_vecSubordinateSnapshots, i )
  5343. {
  5344. if ( m_vecSubordinateSnapshots[i] )
  5345. m_vecSubordinateSnapshots[i]->AbandonAnyPending();
  5346. }
  5347. m_vecWorldCapturePos = matPlayer.GetOrigin();
  5348. m_flWeight = 1;
  5349. m_bCapturePending = false;
  5350. }
  5351. void CBoneSnapshot::PlaybackSnapshot( void )
  5352. {
  5353. if ( !m_pEnt )
  5354. return;
  5355. CStudioHdr *pHdr = m_pEnt->GetModelPtr();
  5356. if ( !pHdr || !m_pEnt->IsVisible() || m_flWeight <= 0 )
  5357. return;
  5358. matrix3x4_t matPlayer;
  5359. AngleMatrix( m_pEnt->GetRenderAngles(), m_pEnt->GetRenderOrigin(), matPlayer );
  5360. float flFailsafeDistance = matPlayer.GetOrigin().DistToSqr( m_vecWorldCapturePos );
  5361. m_flWeight = MIN( m_flWeight, RemapValClamped( flFailsafeDistance, 484.0f, 1296.0f, 1.0f, 0.0f ) );
  5362. if ( m_flWeight <= 0 )
  5363. return;
  5364. for (int i = 0; i < pHdr->numbones(); ++i)
  5365. {
  5366. if ( m_Weightlist[i] <= 0 )
  5367. continue;
  5368. float flWeightedElement = m_flWeight * m_Weightlist[i];
  5369. matrix3x4_t matCurrent = m_pEnt->GetBone(i);
  5370. matrix3x4_t matCached = ConcatTransforms( matPlayer, m_Cache[i] );
  5371. Vector posCurrent = matCurrent.GetOrigin();
  5372. Vector posCached = matCached.GetOrigin();
  5373. if ( posCurrent.DistToSqr( posCached ) > 5000 )
  5374. {
  5375. //#ifdef DEBUG
  5376. // AssertMsgOnce( false, "Warning: Bonesnapshot lerp distance is too large.\n" );
  5377. //#endif
  5378. break;
  5379. }
  5380. Quaternion qCurrent;
  5381. MatrixQuaternion( matCurrent, qCurrent );
  5382. Quaternion qCached;
  5383. MatrixQuaternion( matCached, qCached );
  5384. Quaternion qLerpOutput;
  5385. QuaternionSlerp( qCurrent, qCached, flWeightedElement, qLerpOutput );
  5386. Vector posLerpOutput = Lerp( flWeightedElement, posCurrent, posCached );
  5387. AngleMatrix( RadianEuler( qLerpOutput ), posLerpOutput, m_pEnt->GetBoneForWrite(i) );
  5388. }
  5389. }
  5390. void CBoneSnapshot::InitWeightList( void )
  5391. {
  5392. if ( !m_pEnt )
  5393. return;
  5394. const model_t *pModel = m_pEnt->GetModel();
  5395. if ( !pModel )
  5396. return;
  5397. KeyValues *pModelKV = modelinfo->GetModelKeyValues( pModel );
  5398. if ( !pModelKV )
  5399. return;
  5400. pModelKV = pModelKV->FindKey( m_szWeightlistName );
  5401. if ( !pModelKV )
  5402. return;
  5403. for ( int i=0; i<MAXSTUDIOBONES; i++ )
  5404. m_Weightlist[i] = 1;
  5405. FOR_EACH_SUBKEY( pModelKV, pBoneWeightKV )
  5406. {
  5407. int nBoneIdx = m_pEnt->LookupBone( pBoneWeightKV->GetName() );
  5408. if ( nBoneIdx >= 0 && nBoneIdx < MAXSTUDIOBONES )
  5409. {
  5410. m_Weightlist[ nBoneIdx ] = pBoneWeightKV->GetFloat();
  5411. //DevMsg( "Populating weightlist bone: %s (index %i) -> [%f]\n", pBoneWeightKV->GetName(), nBoneIdx, m_Weightlist[ nBoneIdx ] );
  5412. }
  5413. }
  5414. m_bWeightlistInitialized = true;
  5415. }
  5416. bool C_CSPlayer::IsAnyBoneSnapshotPending( void )
  5417. {
  5418. return ( m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].IsCapturePending() || m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].IsCapturePending() );
  5419. }
  5420. #define CS_ARM_HYPEREXTENSION_LIM 22.0f
  5421. #define CS_ARM_HYPEREXTENSION_LIM_SQR 484.0f
  5422. #define cl_player_toe_length 4.5
  5423. void C_CSPlayer::DoExtraBoneProcessing( CStudioHdr *pStudioHdr, BoneVector pos[], BoneQuaternion q[], matrix3x4a_t boneToWorld[], CBoneBitList &boneComputed, CIKContext *pIKContext )
  5424. {
  5425. if ( !m_bUseNewAnimstate || !m_PlayerAnimStateCSGO || IsAnimLODflagSet(ANIMLODFLAG_DORMANT|ANIMLODFLAG_INVISIBLELOCALPLAYER|ANIMLODFLAG_OUTSIDEVIEWFRUSTUM) )
  5426. return;
  5427. if ( !IsVisible() || (IsLocalPlayer( this ) && !C_BasePlayer::ShouldDrawLocalPlayer()) || !ShouldDraw() )
  5428. return;
  5429. mstudioikchain_t *pLeftFootChain = NULL;
  5430. mstudioikchain_t *pRightFootChain = NULL;
  5431. mstudioikchain_t *pLeftArmChain = NULL;
  5432. int nLeftFootBoneIndex = LookupBone( "ankle_L" );
  5433. int nRightFootBoneIndex = LookupBone( "ankle_R" );
  5434. int nLeftHandBoneIndex = LookupBone( "hand_L" );
  5435. Assert( nLeftFootBoneIndex != -1 && nRightFootBoneIndex != -1 && nLeftHandBoneIndex != -1 );
  5436. for( int i = 0; i < pStudioHdr->numikchains(); i++ )
  5437. {
  5438. mstudioikchain_t *pchain = pStudioHdr->pIKChain( i );
  5439. if ( nLeftFootBoneIndex == pchain->pLink( 2 )->bone )
  5440. {
  5441. pLeftFootChain = pchain;
  5442. }
  5443. else if ( nRightFootBoneIndex == pchain->pLink( 2 )->bone )
  5444. {
  5445. pRightFootChain = pchain;
  5446. }
  5447. else if ( nLeftHandBoneIndex == pchain->pLink( 2 )->bone )
  5448. {
  5449. pLeftArmChain = pchain;
  5450. }
  5451. if ( pLeftFootChain && pRightFootChain && pLeftArmChain )
  5452. break;
  5453. }
  5454. Assert( pLeftFootChain && pRightFootChain );
  5455. Vector vecAnimatedLeftFootPos = boneToWorld[nLeftFootBoneIndex].GetOrigin();
  5456. Vector vecAnimatedRightFootPos = boneToWorld[nRightFootBoneIndex].GetOrigin();
  5457. m_PlayerAnimStateCSGO->DoProceduralFootPlant( boneToWorld, pLeftFootChain, pRightFootChain, pos );
  5458. // hack - keep the toes above the ground
  5459. if ( (GetFlags() & FL_ONGROUND) && (GetMoveType() == MOVETYPE_WALK) )
  5460. {
  5461. float flZMaxToe = GetAbsOrigin().z + 0.75f;
  5462. int nLeftToeBoneIndex = LookupBone( "ball_L" );
  5463. int nRightToeBoneIndex = LookupBone( "ball_R" );
  5464. if ( nLeftToeBoneIndex > 0 )
  5465. {
  5466. // need to build an extended toe position
  5467. Vector vecToeLeft = boneToWorld[nLeftFootBoneIndex].TransformVector( pos[nLeftToeBoneIndex] );
  5468. Vector vecForward;
  5469. MatrixGetColumn( boneToWorld[nLeftToeBoneIndex], 0, vecForward );
  5470. vecToeLeft += vecForward * cl_player_toe_length;
  5471. if ( vecToeLeft.z < flZMaxToe )
  5472. {
  5473. boneToWorld[nLeftFootBoneIndex][2][3] += (flZMaxToe - vecToeLeft.z);
  5474. }
  5475. }
  5476. if ( nRightToeBoneIndex > 0 )
  5477. {
  5478. Vector vecToeRight = boneToWorld[nRightFootBoneIndex].TransformVector( pos[nRightToeBoneIndex] );
  5479. Vector vecForward;
  5480. MatrixGetColumn( boneToWorld[nRightToeBoneIndex], 0, vecForward );
  5481. vecToeRight -= vecForward * cl_player_toe_length; // right toe bone is backwards...
  5482. if ( vecToeRight.z < flZMaxToe )
  5483. {
  5484. boneToWorld[nRightFootBoneIndex][2][3] += (flZMaxToe - vecToeRight.z);
  5485. }
  5486. }
  5487. }
  5488. Vector vecLeftFootPos = boneToWorld[nLeftFootBoneIndex].GetOrigin();
  5489. Vector vecRightFootPos = boneToWorld[nRightFootBoneIndex].GetOrigin();
  5490. boneToWorld[nLeftFootBoneIndex].SetOrigin( vecAnimatedLeftFootPos );
  5491. boneToWorld[nRightFootBoneIndex].SetOrigin( vecAnimatedRightFootPos );
  5492. Studio_SolveIK( pLeftFootChain->pLink( 0 )->bone, pLeftFootChain->pLink( 1 )->bone, nLeftFootBoneIndex, vecLeftFootPos, boneToWorld );
  5493. Studio_SolveIK( pRightFootChain->pLink( 0 )->bone, pRightFootChain->pLink( 1 )->bone, nRightFootBoneIndex, vecRightFootPos, boneToWorld );
  5494. int nLeftHandIkBoneDriver = LookupBone( "lh_ik_driver" );
  5495. if ( nLeftHandIkBoneDriver > 0 && pos[nLeftHandIkBoneDriver].x > 0 )
  5496. {
  5497. MDLCACHE_CRITICAL_SECTION();
  5498. int nRightHandWepBoneIndex = LookupBone( "weapon_hand_R" );
  5499. if ( nRightHandWepBoneIndex > 0 )
  5500. {
  5501. // early out if the bone isn't in the ikcontext mask
  5502. CStudioHdr *pPlayerHdr = GetModelPtr();
  5503. if ( !(pPlayerHdr->boneFlags( nRightHandWepBoneIndex ) & pIKContext->GetBoneMask()) )
  5504. return;
  5505. C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
  5506. if ( pWeapon )
  5507. {
  5508. CBaseWeaponWorldModel *pWeaponWorldModel = pWeapon->m_hWeaponWorldModel.Get();
  5509. if ( pWeaponWorldModel && pWeaponWorldModel->IsVisible() && pWeaponWorldModel->GetLeftHandAttachBoneIndex() != -1 )
  5510. {
  5511. int nWepAttach = pWeaponWorldModel->GetLeftHandAttachBoneIndex();
  5512. if ( nWepAttach > -1 )
  5513. {
  5514. // make sure the left hand attach bone is marked for setup
  5515. CStudioHdr *pHdr = pWeaponWorldModel->GetModelPtr();
  5516. if ( !( pHdr->boneFlags(nWepAttach) & BONE_ALWAYS_SETUP ) )
  5517. pHdr->setBoneFlags( nWepAttach, BONE_ALWAYS_SETUP );
  5518. if ( pHdr->boneParent( nWepAttach ) != -1 && pWeaponWorldModel->isBoneAvailableForRead(nWepAttach) )
  5519. {
  5520. pIKContext->BuildBoneChain( pos, q, nRightHandWepBoneIndex, boneToWorld, boneComputed );
  5521. // Turns out the weapon hand attachment bone is sometimes expected to independently animate.
  5522. // hack: derive the local position offset from cached bones, since otherwise the weapon (a child of the
  5523. // player) will try and set up the player before itself, then place itself in the wrong spot relative to
  5524. // the player that's in the position we're setting up NOW
  5525. Vector vecRelTarget;
  5526. int nParent = pHdr->pBone(nWepAttach)->parent;
  5527. if ( nParent != -1 )
  5528. {
  5529. matrix3x4_t matAttach;
  5530. pWeaponWorldModel->GetCachedBoneMatrix( nWepAttach, matAttach );
  5531. matrix3x4_t matAttachParent;
  5532. pWeaponWorldModel->GetCachedBoneMatrix( nParent, matAttachParent );
  5533. matrix3x4_t matRel = ConcatTransforms( matAttachParent.InverseTR(), matAttach );
  5534. vecRelTarget = matRel.GetOrigin();
  5535. }
  5536. else
  5537. {
  5538. vecRelTarget = pHdr->pBone(nWepAttach)->pos;
  5539. }
  5540. Vector vecLHandAttach = boneToWorld[nRightHandWepBoneIndex].TransformVector( vecRelTarget );
  5541. Vector vecTarget = Lerp( pos[nLeftHandIkBoneDriver].x, boneToWorld[nLeftHandBoneIndex].GetOrigin(), vecLHandAttach );
  5542. // let the ik fail gracefully with an elastic-y pull instead of hyper-extension
  5543. float flDist = vecTarget.DistToSqr( boneToWorld[pLeftArmChain->pLink( 0 )->bone].GetOrigin() );
  5544. if ( flDist > CS_ARM_HYPEREXTENSION_LIM_SQR )
  5545. {
  5546. // HACK: force a valid elbow dir (down z)
  5547. boneToWorld[pLeftArmChain->pLink( 1 )->bone][2][3] -= 0.5f;
  5548. Vector vecShoulderToHand = (vecTarget - boneToWorld[pLeftArmChain->pLink( 0 )->bone].GetOrigin()).Normalized() * CS_ARM_HYPEREXTENSION_LIM;
  5549. vecTarget = vecShoulderToHand + boneToWorld[pLeftArmChain->pLink( 0 )->bone].GetOrigin();
  5550. }
  5551. //debugoverlay->AddBoxOverlay( vecTarget, Vector(-0.1,-0.1,-0.1), Vector(0.1,0.1,0.1), QAngle(0,0,0), 0,255,0,255, 0 );
  5552. //debugoverlay->AddLineOverlay( boneToWorld[pLeftArmChain->pLink( 0 )->bone].GetOrigin(), boneToWorld[pLeftArmChain->pLink( 1 )->bone].GetOrigin(), 80,80,80,true,0);
  5553. //debugoverlay->AddLineOverlay( boneToWorld[pLeftArmChain->pLink( 1 )->bone].GetOrigin(), boneToWorld[pLeftArmChain->pLink( 2 )->bone].GetOrigin(), 80,80,80,true,0);
  5554. //debugoverlay->AddLineOverlay( boneToWorld[pLeftArmChain->pLink( 0 )->bone].GetOrigin(), boneToWorld[pLeftArmChain->pLink( 2 )->bone].GetOrigin(), 80,80,80,true,0);
  5555. Studio_SolveIK( pLeftArmChain->pLink( 0 )->bone, pLeftArmChain->pLink( 1 )->bone, pLeftArmChain->pLink( 2 )->bone, vecTarget, boneToWorld );
  5556. //debugoverlay->AddLineOverlay( boneToWorld[pLeftArmChain->pLink( 0 )->bone].GetOrigin(), boneToWorld[pLeftArmChain->pLink( 1 )->bone].GetOrigin(), 255,0,0,true,0);
  5557. //debugoverlay->AddLineOverlay( boneToWorld[pLeftArmChain->pLink( 1 )->bone].GetOrigin(), boneToWorld[pLeftArmChain->pLink( 2 )->bone].GetOrigin(), 255,0,0,true,0);
  5558. //debugoverlay->AddLineOverlay( boneToWorld[pLeftArmChain->pLink( 0 )->bone].GetOrigin(), boneToWorld[pLeftArmChain->pLink( 2 )->bone].GetOrigin(), 0,0,255,true,0);
  5559. }
  5560. }
  5561. }
  5562. }
  5563. }
  5564. }
  5565. }
  5566. //-----------------------------------------------------------------------------
  5567. //
  5568. //-----------------------------------------------------------------------------
  5569. void C_CSPlayer::BuildTransformations( CStudioHdr *pHdr, BoneVector *pos, BoneQuaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
  5570. {
  5571. // First, setup our model's transformations like normal.
  5572. BaseClass::BuildTransformations( pHdr, pos, q, cameraTransform, boneMask, boneComputed );
  5573. if ( !m_bUseNewAnimstate || !m_PlayerAnimStateCSGO )
  5574. return;
  5575. if ( !IsVisible() || IsDormant() || (IsLocalPlayer( this ) && !C_BasePlayer::ShouldDrawLocalPlayer()) || !ShouldDraw() )
  5576. return;
  5577. if ( boneMask == BONE_USED_BY_ATTACHMENT )
  5578. return; // we're only building transformations to get attachment positions. No need to update bone snapshots now.
  5579. // process bone snapshots
  5580. {
  5581. int oldWritableBones = m_BoneAccessor.GetReadableBones();
  5582. m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING );
  5583. int oldReadableBones = m_BoneAccessor.GetReadableBones();
  5584. m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING );
  5585. m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].Update( this );
  5586. m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].Update( this );
  5587. m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].SetLastBoneSetupTimeIndex();
  5588. m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].SetLastBoneSetupTimeIndex();
  5589. m_BoneAccessor.SetWritableBones( oldWritableBones );
  5590. m_BoneAccessor.SetReadableBones( oldReadableBones );
  5591. }
  5592. }
  5593. C_BaseAnimating * C_CSPlayer::BecomeRagdollOnClient()
  5594. {
  5595. return NULL;
  5596. }
  5597. IRagdoll* C_CSPlayer::GetRepresentativeRagdoll() const
  5598. {
  5599. if ( m_hRagdoll.Get() )
  5600. {
  5601. C_CSRagdoll *pRagdoll = (C_CSRagdoll* )m_hRagdoll.Get();
  5602. return pRagdoll->GetIRagdoll();
  5603. }
  5604. else
  5605. {
  5606. return NULL;
  5607. }
  5608. }
  5609. // Update the rich presence for this player when they change teams
  5610. void C_CSPlayer::TeamChange( int iNewTeam )
  5611. {
  5612. C_BasePlayer::TeamChange( iNewTeam );
  5613. // update the spectator glows
  5614. UpdateGlowsForAllPlayers();
  5615. // Apply the new HUD tint for our team
  5616. if ( C_BasePlayer::IsLocalPlayer( this ) && !IsBot() )
  5617. {
  5618. static const int g_CT_Tint = 1;
  5619. static const int g_T_Tint = 2;
  5620. ConVarRef sf_ui_tint( "sf_ui_tint" );
  5621. if ( iNewTeam == TEAM_TERRORIST )
  5622. sf_ui_tint.SetValue( g_T_Tint );
  5623. else
  5624. sf_ui_tint.SetValue( g_CT_Tint );
  5625. if ( CSGameRules() && CSGameRules()->IsPlayingGunGameDeathmatch())
  5626. m_bShouldAutobuyDMWeapons = true;
  5627. }
  5628. #if defined( _X360 )
  5629. if ( C_BasePlayer::IsLocalPlayer( this ) )
  5630. {
  5631. DWORD dwValue = CONTEXT_CSS_TEAM_SPECTATOR;
  5632. if ( iNewTeam == TEAM_TERRORIST )
  5633. dwValue = CONTEXT_CSS_TEAM_T;
  5634. else if ( iNewTeam == TEAM_CT )
  5635. dwValue = CONTEXT_CSS_TEAM_CT;
  5636. DevMsg( "Setting rich presence for team to %d\n", dwValue );
  5637. XUSER_CONTEXT xUserContext = { CONTEXT_CSS_TEAM, dwValue };
  5638. ACTIVE_SPLITSCREEN_PLAYER_GUARD( GET_ACTIVE_SPLITSCREEN_SLOT() );
  5639. xboxsystem->UserSetContext( XBX_GetActiveUserId(), xUserContext, true );
  5640. }
  5641. #endif
  5642. SplitScreenConVarRef varOption( "cl_clanid" );
  5643. const char *pClanID = varOption.GetString( 0 );
  5644. varOption.SetValue( 0, pClanID );
  5645. }
  5646. void C_CSPlayer::PlayReloadEffect( int iActAnimID, const Vector *pOrigin )
  5647. {
  5648. // Only play the effect for other players.
  5649. if ( this == C_CSPlayer::GetLocalCSPlayer() )
  5650. {
  5651. Assert( g_HltvReplaySystem.GetHltvReplayDelay() ); // We shouldn't have been sent this message - except during replay
  5652. return;
  5653. }
  5654. // Get the view model for our current gun.
  5655. CWeaponCSBase *pWeapon = GetActiveCSWeapon();
  5656. if ( !pWeapon )
  5657. return;
  5658. // The weapon needs two models, world and view, but can only cache one. Synthesize the other.
  5659. const model_t *pModel = modelinfo->GetModel( modelinfo->GetModelIndex( pWeapon->GetViewModel() ) );
  5660. if ( !pModel )
  5661. return;
  5662. CStudioHdr studioHdr( modelinfo->GetStudiomodel( pModel ), mdlcache );
  5663. if ( !studioHdr.IsValid() )
  5664. return;
  5665. // Find the reload animation.
  5666. for ( int iSeq=0; iSeq < studioHdr.GetNumSeq(); iSeq++ )
  5667. {
  5668. mstudioseqdesc_t *pSeq = &studioHdr.pSeqdesc( iSeq );
  5669. if ( pSeq->activity == iActAnimID )
  5670. {
  5671. float poseParameters[MAXSTUDIOPOSEPARAM];
  5672. memset( poseParameters, 0, sizeof( poseParameters ) );
  5673. float cyclesPerSecond = Studio_CPS( &studioHdr, *pSeq, iSeq, poseParameters );
  5674. // Now read out all the sound events with their timing
  5675. for ( int iEvent=0; iEvent < pSeq->numevents; iEvent++ )
  5676. {
  5677. mstudioevent_t *pEvent = (mstudioevent_for_client_server_t* )pSeq->pEvent( iEvent );
  5678. if ( pEvent->Event() == CL_EVENT_SOUND )
  5679. {
  5680. CCSSoundEvent event;
  5681. event.m_SoundName = pEvent->options;
  5682. event.m_flEventTime = gpGlobals->curtime + pEvent->cycle / cyclesPerSecond;
  5683. if ( pOrigin != NULL )
  5684. {
  5685. event.m_SoundOrigin = *pOrigin;
  5686. event.m_bHasSoundOrigin = true;
  5687. }
  5688. m_SoundEvents.AddToTail( event );
  5689. }
  5690. }
  5691. break;
  5692. }
  5693. }
  5694. }
  5695. void C_CSPlayer::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
  5696. {
  5697. if ( m_bUseNewAnimstate )
  5698. {
  5699. return;
  5700. }
  5701. if ( event == PLAYERANIMEVENT_THROW_GRENADE )
  5702. {
  5703. // Let the server handle this event. It will update m_iThrowGrenadeCounter and the client will
  5704. // pick up the event in CCSPlayerAnimState.
  5705. }
  5706. else
  5707. {
  5708. m_PlayerAnimState->DoAnimationEvent( event, nData );
  5709. }
  5710. }
  5711. void C_CSPlayer::DropPhysicsMag( const char *options )
  5712. {
  5713. // create a client-side physical magazine model to drop in the world and clatter to the floor. Realism!
  5714. if ( sv_magazine_drop_physics == 0 )
  5715. return;
  5716. CWeaponCSBase *pWeapon = GetActiveCSWeapon();
  5717. if ( !pWeapon )
  5718. return;
  5719. CEconItemView *pItem = pWeapon->GetEconItemView();
  5720. if ( !pItem || !pItem->GetMagazineModel() )
  5721. return;
  5722. Vector attachOrigin = GetAbsOrigin() + Vector(0,0,50);
  5723. QAngle attachAngles = QAngle(0,0,0);
  5724. // find the best attachment position to drop the mag from
  5725. int iMagAttachIndex = -1;
  5726. CBaseWeaponWorldModel *pWeaponWorldModel = pWeapon->m_hWeaponWorldModel.Get();
  5727. if ( options && options[0] != 0 )
  5728. {
  5729. // if a custom attachment is specified, look for it on the weapon, then the player.
  5730. if ( pWeaponWorldModel )
  5731. iMagAttachIndex = pWeaponWorldModel->LookupAttachment( options );
  5732. if ( iMagAttachIndex <= 0 )
  5733. iMagAttachIndex = LookupAttachment( options );
  5734. }
  5735. if ( iMagAttachIndex <= 0 )
  5736. {
  5737. // we either didn't specify a custom attachment, or the one we did wasn't found. Find the default, 'mag_eject' on the weapon, then the player.
  5738. if ( pWeaponWorldModel )
  5739. iMagAttachIndex = pWeaponWorldModel->LookupAttachment( "mag_eject" );
  5740. if ( iMagAttachIndex <= 0 )
  5741. iMagAttachIndex = LookupAttachment( "mag_eject" );
  5742. }
  5743. if ( iMagAttachIndex <= 0 && pWeaponWorldModel )
  5744. {
  5745. // no luck looking for the custom attachment, or "mag_eject". How about "shell_eject"? Wrong, but better than nothing...
  5746. iMagAttachIndex = pWeaponWorldModel->LookupAttachment( "shell_eject" );
  5747. }
  5748. // limit mag drops to one per second, in case animations accidentally overlap or events erroneously get fired too rapidly
  5749. // let new attachment indices through though, for elites
  5750. if ( m_flNextMagDropTime > gpGlobals->curtime && iMagAttachIndex == m_nLastMagDropAttachmentIndex )
  5751. return;
  5752. m_flNextMagDropTime = gpGlobals->curtime + 1;
  5753. m_nLastMagDropAttachmentIndex = iMagAttachIndex;
  5754. if ( iMagAttachIndex <= 0 )
  5755. {
  5756. return;
  5757. }
  5758. if ( !IsDormant() )
  5759. {
  5760. if ( pWeaponWorldModel )
  5761. {
  5762. pWeaponWorldModel->GetAttachment( iMagAttachIndex, attachOrigin, attachAngles );
  5763. }
  5764. else
  5765. {
  5766. GetAttachment( iMagAttachIndex, attachOrigin, attachAngles );
  5767. }
  5768. }
  5769. //// hide the animation-driven w_model magazine
  5770. //if ( pWeaponWorldModel )
  5771. //{
  5772. // pWeaponWorldModel->SetBodygroupPreset( "hide_mag" );
  5773. //}
  5774. // The local first-person player can't drop mags in the correct world-space location, otherwise the mag would appear in mid-air.
  5775. // Instead, first try to drop the mag slightly above the origin of the player.
  5776. // However if the player is looking nearly straight down, they'll still see the mag appear. If this is the case,
  5777. // drop the mags from 10 units behind their eyes. This means the mag ALWAYS drops in from "off-screen"
  5778. if ( ( IsLocalPlayer() && !ShouldDraw() ) || GetSpectatorMode() == OBS_MODE_IN_EYE )
  5779. {
  5780. if ( EyeAngles().x < 42.0f ) //not looking extremely vertically downward
  5781. {
  5782. attachOrigin = GetAbsOrigin() + Vector(0,0,20);
  5783. }
  5784. else
  5785. {
  5786. attachOrigin = EyePosition() - ( Forward() * 10 );
  5787. }
  5788. }
  5789. C_PhysPropClientside *pEntity = C_PhysPropClientside::CreateNew();
  5790. if ( !pEntity )
  5791. return;
  5792. pEntity->SetModelName( pItem->GetMagazineModel() );
  5793. pEntity->SetPhysicsMode( PHYSICS_MULTIPLAYER_CLIENTSIDE );
  5794. pEntity->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
  5795. pEntity->SetDistanceFade( 500.0f, 550.0f );
  5796. pEntity->SetLocalOrigin( attachOrigin );
  5797. pEntity->SetLocalAngles( attachAngles );
  5798. pEntity->m_iHealth = 0;
  5799. pEntity->m_takedamage = DAMAGE_NO;
  5800. if ( !pEntity->Initialize() )
  5801. {
  5802. pEntity->Release();
  5803. return;
  5804. }
  5805. // apply custom material
  5806. pEntity->ClearCustomMaterials();
  5807. for ( int i = 0; i < pWeapon->GetCustomMaterialCount(); i++ )
  5808. pEntity->SetCustomMaterial( pWeapon->GetCustomMaterial( i ), i );
  5809. // fade out after set time
  5810. pEntity->StartFadeOut( sv_magazine_drop_time );
  5811. // apply starting velocity
  5812. IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
  5813. if( pPhysicsObject )
  5814. {
  5815. if ( !IsDormant() ) // don't apply velocity to mags dropped by dormant players
  5816. {
  5817. Vector vecMagVelocity; vecMagVelocity.Init();
  5818. Quaternion quatMagAngular; quatMagAngular.Init();
  5819. if ( pWeaponWorldModel )
  5820. {
  5821. pWeaponWorldModel->GetAttachmentVelocity( iMagAttachIndex, vecMagVelocity, quatMagAngular );
  5822. }
  5823. else
  5824. {
  5825. GetAttachmentVelocity( iMagAttachIndex, vecMagVelocity, quatMagAngular );
  5826. }
  5827. // if the local attachment is returning no motion, pull velocity from the player just to be sure
  5828. if ( vecMagVelocity == vec3_origin )
  5829. vecMagVelocity = GetLocalVelocity();
  5830. if ( sv_magazine_drop_debug && debugoverlay )
  5831. {
  5832. debugoverlay->AddBoxOverlay( attachOrigin, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 200,0,0, 255, 10.0f );
  5833. debugoverlay->AddLineOverlayAlpha( attachOrigin, attachOrigin+vecMagVelocity, 0,200,0, 255, true, 10.0f );
  5834. }
  5835. QAngle angMagAngular; angMagAngular.Init();
  5836. QuaternionAngles( quatMagAngular, angMagAngular );
  5837. AngularImpulse angImpMagAngular; angImpMagAngular.Init();
  5838. QAngleToAngularImpulse( angMagAngular, angImpMagAngular );
  5839. // clamp to 300 max
  5840. if ( vecMagVelocity.Length() > 300.0f )
  5841. vecMagVelocity = vecMagVelocity.Normalized() * 300.0f;
  5842. pPhysicsObject->SetVelocity( &vecMagVelocity, &angImpMagAngular );
  5843. }
  5844. }
  5845. else
  5846. {
  5847. pEntity->Release();
  5848. return;
  5849. }
  5850. }
  5851. void C_CSPlayer::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  5852. {
  5853. if ( event == AE_WPN_HIDE )
  5854. {
  5855. CBaseCombatWeapon *pWeapon = GetActiveWeapon();
  5856. if (pWeapon && options && options[0] != 0)
  5857. pWeapon->m_flWeaponTauntHideTimeout = gpGlobals->curtime + atof(options);
  5858. return;
  5859. }
  5860. else if ( event == AE_CL_EJECT_MAG_UNHIDE )
  5861. {
  5862. // mag is unhidden by the server
  5863. return;
  5864. }
  5865. else if ( event == AE_CL_EJECT_MAG )
  5866. {
  5867. CAnimationLayer *pWeaponLayer = GetAnimOverlay( ANIMATION_LAYER_WEAPON_ACTION );
  5868. if ( pWeaponLayer && pWeaponLayer->m_nDispatchedDst != ACT_INVALID )
  5869. {
  5870. // let the weapon drop the mag
  5871. }
  5872. else
  5873. {
  5874. DropPhysicsMag( options );
  5875. // hack: in first-person, the player isn't playing their third-person gun animations, so the events on the third-person gun model don't fire.
  5876. // This means the event is fired from the player, and the player only fires ONE mag drop event. So while the elite model drops two data-driven mags
  5877. // in third person, we need to help it out a little bit in first-person. So here's some one-off code to drop another physics mag only for the elite,
  5878. // and only in first-person.
  5879. CWeaponCSBase *pWeapon = GetActiveCSWeapon();
  5880. if ( pWeapon && pWeapon->IsA(WEAPON_ELITE) )
  5881. {
  5882. DropPhysicsMag( "mag_eject2" );
  5883. }
  5884. }
  5885. return;
  5886. }
  5887. if (event != 7001 && event != 7002 )
  5888. {
  5889. BaseClass::FireEvent(origin, angles, event, options);
  5890. return;
  5891. }
  5892. bool kneesInWater, feetInWater;
  5893. switch( GetWaterLevel() )
  5894. {
  5895. case WL_NotInWater: default: feetInWater = kneesInWater = false; break;
  5896. case WL_Feet: feetInWater = true; kneesInWater = false; break;
  5897. case WL_Waist: case WL_Eyes: feetInWater = kneesInWater = true; break;
  5898. }
  5899. // If we're not on the ground, don't draw splashes for footsteps
  5900. if ( !(GetFlags() & FL_ONGROUND) )
  5901. {
  5902. kneesInWater = feetInWater = 0;
  5903. }
  5904. if ( !feetInWater && !kneesInWater )
  5905. return;
  5906. if ( event == 7001 )
  5907. {
  5908. //Msg( "run event ( %d )\n", bInWater ? 1 : 0 );
  5909. if( feetInWater )
  5910. {
  5911. //run splash
  5912. CEffectData data;
  5913. //trace up from foot position to the water surface
  5914. trace_t tr;
  5915. Vector vecTrace(0,0,1024 );
  5916. UTIL_TraceLine( origin, origin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
  5917. if ( tr.fractionleftsolid )
  5918. {
  5919. data.m_vOrigin = origin + (vecTrace * tr.fractionleftsolid );
  5920. }
  5921. else
  5922. {
  5923. data.m_vOrigin = origin;
  5924. }
  5925. data.m_vNormal = Vector( 0,0,1 );
  5926. data.m_flScale = random->RandomFloat( 4.0f, 5.0f );
  5927. DispatchEffect( "watersplash", data );
  5928. }
  5929. }
  5930. else if( event == 7002 )
  5931. {
  5932. //Msg( "walk event ( %d )\n", bInWater ? 1 : 0 );
  5933. if( feetInWater )
  5934. {
  5935. //walk ripple
  5936. CEffectData data;
  5937. //trace up from foot position to the water surface
  5938. trace_t tr;
  5939. Vector vecTrace(0,0,1024 );
  5940. UTIL_TraceLine( origin, origin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
  5941. if ( tr.fractionleftsolid )
  5942. {
  5943. data.m_vOrigin = origin + (vecTrace * tr.fractionleftsolid );
  5944. }
  5945. else
  5946. {
  5947. data.m_vOrigin = origin;
  5948. }
  5949. data.m_vNormal = Vector( 0,0,1 );
  5950. data.m_flScale = random->RandomFloat( 4.0f, 7.0f );
  5951. DispatchEffect( "waterripple", data );
  5952. }
  5953. }
  5954. }
  5955. void C_CSPlayer::SetActivity( Activity eActivity )
  5956. {
  5957. m_Activity = eActivity;
  5958. }
  5959. Activity C_CSPlayer::GetActivity() const
  5960. {
  5961. return m_Activity;
  5962. }
  5963. const Vector& C_CSPlayer::GetRenderOrigin( void )
  5964. {
  5965. if ( m_hRagdoll.Get() )
  5966. {
  5967. C_CSRagdoll *pRagdoll = (C_CSRagdoll* )m_hRagdoll.Get();
  5968. if ( pRagdoll->IsInitialized() )
  5969. return pRagdoll->GetRenderOrigin();
  5970. }
  5971. return BaseClass::GetRenderOrigin();
  5972. }
  5973. bool C_CSPlayer::Simulate( void )
  5974. {
  5975. if ( !C_BasePlayer::IsLocalPlayer( this ) )
  5976. {
  5977. if ( IsEffectActive( EF_DIMLIGHT ) )
  5978. {
  5979. QAngle eyeAngles = EyeAngles();
  5980. Vector vForward;
  5981. AngleVectors( eyeAngles, &vForward );
  5982. int iAttachment = LookupAttachment( "muzzle_flash" );
  5983. if ( iAttachment < 0 )
  5984. return false;
  5985. Vector vecOrigin;
  5986. QAngle dummy;
  5987. GetAttachment( iAttachment, vecOrigin, dummy );
  5988. trace_t tr;
  5989. UTIL_TraceLine( vecOrigin, vecOrigin + (vForward * 200 ), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  5990. if( !m_pFlashlightBeam )
  5991. {
  5992. BeamInfo_t beamInfo;
  5993. beamInfo.m_nType = TE_BEAMPOINTS;
  5994. beamInfo.m_vecStart = tr.startpos;
  5995. beamInfo.m_vecEnd = tr.endpos;
  5996. beamInfo.m_pszModelName = "sprites/glow01.vmt";
  5997. beamInfo.m_pszHaloName = "sprites/glow01.vmt";
  5998. beamInfo.m_flHaloScale = 3.0;
  5999. beamInfo.m_flWidth = 8.0f;
  6000. beamInfo.m_flEndWidth = 35.0f;
  6001. beamInfo.m_flFadeLength = 300.0f;
  6002. beamInfo.m_flAmplitude = 0;
  6003. beamInfo.m_flBrightness = 60.0;
  6004. beamInfo.m_flSpeed = 0.0f;
  6005. beamInfo.m_nStartFrame = 0.0;
  6006. beamInfo.m_flFrameRate = 0.0;
  6007. beamInfo.m_flRed = 255.0;
  6008. beamInfo.m_flGreen = 255.0;
  6009. beamInfo.m_flBlue = 255.0;
  6010. beamInfo.m_nSegments = 8;
  6011. beamInfo.m_bRenderable = true;
  6012. beamInfo.m_flLife = 0.5;
  6013. beamInfo.m_nFlags = FBEAM_FOREVER | FBEAM_ONLYNOISEONCE | FBEAM_NOTILE | FBEAM_HALOBEAM;
  6014. m_pFlashlightBeam = beams->CreateBeamPoints( beamInfo );
  6015. }
  6016. if( m_pFlashlightBeam )
  6017. {
  6018. BeamInfo_t beamInfo;
  6019. beamInfo.m_vecStart = tr.startpos;
  6020. beamInfo.m_vecEnd = tr.endpos;
  6021. beamInfo.m_flRed = 255.0;
  6022. beamInfo.m_flGreen = 255.0;
  6023. beamInfo.m_flBlue = 255.0;
  6024. beams->UpdateBeamInfo( m_pFlashlightBeam, beamInfo );
  6025. dlight_t *el = effects->CL_AllocDlight( 0 );
  6026. el->origin = tr.endpos;
  6027. el->radius = 50;
  6028. el->color.r = 200;
  6029. el->color.g = 200;
  6030. el->color.b = 200;
  6031. el->die = gpGlobals->curtime + 0.1;
  6032. }
  6033. }
  6034. else if ( m_pFlashlightBeam )
  6035. {
  6036. ReleaseFlashlight();
  6037. }
  6038. }
  6039. BaseClass::Simulate();
  6040. return true;
  6041. }
  6042. void C_CSPlayer::ReleaseFlashlight( void )
  6043. {
  6044. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  6045. if( m_pFlashlightBeam )
  6046. {
  6047. m_pFlashlightBeam->flags = 0;
  6048. m_pFlashlightBeam->die = gpGlobals->curtime - 1;
  6049. m_pFlashlightBeam = NULL;
  6050. }
  6051. }
  6052. bool C_CSPlayer::HasC4( void )
  6053. {
  6054. if( C_BasePlayer::IsLocalPlayer( this ) )
  6055. {
  6056. return Weapon_OwnsThisType( "weapon_c4" ) != NULL;
  6057. }
  6058. else
  6059. {
  6060. C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource* )GameResources();
  6061. return pCSPR->HasC4( entindex() );
  6062. }
  6063. }
  6064. //-----------------------------------------------------------------------------
  6065. // Purpose:
  6066. // Output : float
  6067. //-----------------------------------------------------------------------------
  6068. float C_CSPlayer::GetFOV( void ) const
  6069. {
  6070. float flCurFOV = BaseClass::GetFOV();
  6071. if ( flCurFOV == GetDefaultFOV() )
  6072. {
  6073. if ( !sv_cheats )
  6074. {
  6075. sv_cheats = cvar->FindVar( "sv_cheats" );
  6076. }
  6077. if ( sv_cheats->GetBool() && fov_cs_debug.GetInt() > 0 )
  6078. {
  6079. return fov_cs_debug.GetInt();
  6080. }
  6081. }
  6082. #ifdef IRONSIGHT
  6083. CWeaponCSBase *pWeapon = GetActiveCSWeapon();
  6084. if ( pWeapon )
  6085. {
  6086. CIronSightController* pIronSightController = pWeapon->GetIronSightController();
  6087. if ( pIronSightController )
  6088. {
  6089. //bias the local client FOV change so ironsight transitions are nicer
  6090. flCurFOV = pIronSightController->GetIronSightFOV( GetDefaultFOV(), true );
  6091. }
  6092. }
  6093. #endif //IRONSIGHT
  6094. if ( GetObserverInterpState() == OBSERVER_INTERP_TRAVELING )
  6095. flCurFOV = GetDefaultFOV();
  6096. return flCurFOV;
  6097. }
  6098. void C_CSPlayer::SetSpecWatchingGrenade( C_BaseEntity *pGrenade, bool bWatching )
  6099. {
  6100. if ( bWatching )
  6101. {
  6102. if ( pGrenade && IsSpecFollowingGrenade() == false )
  6103. {
  6104. m_hOldGrenadeObserverTarget = GetObserverTarget();
  6105. m_bIsSpecFollowingGrenade = true;
  6106. SetObserverTarget( pGrenade );
  6107. }
  6108. }
  6109. else
  6110. {
  6111. // only change state if we get a false
  6112. // if ( pGrenade == GetObserverTarget() )
  6113. {
  6114. if ( IsSpecFollowingGrenade() == true )
  6115. {
  6116. m_bIsSpecFollowingGrenade = false;
  6117. C_BaseEntity *pLastTarget = m_hOldGrenadeObserverTarget.Get();
  6118. if ( !pLastTarget || pLastTarget->IsDormant() || !pLastTarget->IsAlive() )
  6119. {
  6120. // find a player that is alive to go to
  6121. for ( int i = 1; i <= MAX_PLAYERS; i++ )
  6122. {
  6123. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  6124. if ( pPlayer && pPlayer->IsAlive() && ( pPlayer->GetTeamNumber() == TEAM_TERRORIST || pPlayer->GetTeamNumber() == TEAM_CT ) )
  6125. {
  6126. pLastTarget = pPlayer;
  6127. break;
  6128. }
  6129. }
  6130. }
  6131. if ( pLastTarget )
  6132. {
  6133. SetObserverTarget( pLastTarget );
  6134. m_hOldGrenadeObserverTarget = NULL;
  6135. }
  6136. }
  6137. }
  6138. }
  6139. }
  6140. CBaseEntity *C_CSPlayer::GetObserverTarget() const // returns players targer or NULL
  6141. {
  6142. return BaseClass::GetObserverTarget();
  6143. }
  6144. int C_CSPlayer::GetObserverMode() const
  6145. {
  6146. if ( IsHLTV() )
  6147. return BaseClass::GetObserverMode();
  6148. if ( dynamic_cast< C_BaseCSGrenadeProjectile* >( GetObserverTarget() ) )
  6149. {
  6150. //m_bIsSpecFollowingGrenade = true;
  6151. return OBS_MODE_CHASE;
  6152. }
  6153. return BaseClass::GetObserverMode();
  6154. }
  6155. //-----------------------------------------------------------------------------
  6156. void C_CSPlayer::CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
  6157. {
  6158. CancelFreezeCamFlashlightEffect();
  6159. /**
  6160. * TODO: Fix this!
  6161. // CS:S standing eyeheight is above the collision volume, so we need to pull it
  6162. // down when we go into close quarters.
  6163. float maxEyeHeightAboveBounds = VEC_VIEW.z - VEC_HULL_MAX.z;
  6164. if ( GetObserverMode() == OBS_MODE_IN_EYE &&
  6165. maxEyeHeightAboveBounds > 0.0f &&
  6166. GetObserverTarget() &&
  6167. GetObserverTarget()->IsPlayer() )
  6168. {
  6169. const float eyeClearance = 12.0f; // eye pos must be this far below the ceiling
  6170. C_CSPlayer *target = ToCSPlayer( GetObserverTarget() );
  6171. Vector offset = eyeOrigin - GetAbsOrigin();
  6172. Vector vHullMin = VEC_HULL_MIN;
  6173. vHullMin.z = 0.0f;
  6174. Vector vHullMax = VEC_HULL_MAX;
  6175. Vector start = GetAbsOrigin();
  6176. start.z += vHullMax.z;
  6177. Vector end = start;
  6178. end.z += eyeClearance + VEC_VIEW.z - vHullMax.z;
  6179. vHullMax.z = 0.0f;
  6180. Vector fudge( 1, 1, 0 );
  6181. vHullMin += fudge;
  6182. vHullMax -= fudge;
  6183. trace_t trace;
  6184. Ray_t ray;
  6185. ray.Init( start, end, vHullMin, vHullMax );
  6186. UTIL_TraceRay( ray, MASK_PLAYERSOLID, target, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  6187. if ( trace.fraction < 1.0f )
  6188. {
  6189. float est = start.z + trace.fraction * (end.z - start.z ) - GetAbsOrigin().z - eyeClearance;
  6190. if ( ( target->GetFlags() & FL_DUCKING ) == 0 && !target->GetFallVelocity() && !target->IsDucked() )
  6191. {
  6192. offset.z = est;
  6193. }
  6194. else
  6195. {
  6196. offset.z = MIN( est, offset.z );
  6197. }
  6198. eyeOrigin.z = GetAbsOrigin().z + offset.z;
  6199. }
  6200. }
  6201. */
  6202. if ( GetObserverTarget() )
  6203. {
  6204. CBaseCSGrenadeProjectile *pGrenade = dynamic_cast< CBaseCSGrenadeProjectile* >( GetObserverTarget() );
  6205. if ( pGrenade )
  6206. {
  6207. m_bIsSpecFollowingGrenade = true;
  6208. }
  6209. }
  6210. BaseClass::CalcObserverView( eyeOrigin, eyeAngles, fov );
  6211. }
  6212. ConVar cl_obs_interp_enable( "cl_obs_interp_enable", "1", FCVAR_ARCHIVE, "Enables interpolation between observer targets" );
  6213. ConVar cl_obs_interp_pos_rate( "cl_obs_interp_pos_rate", "0.27" );
  6214. ConVar cl_obs_interp_pos_halflife( "cl_obs_interp_pos_halflife", "0.26" );
  6215. ConVar cl_obs_interp_snap_dist( "cl_obs_interp_snap_dist", "1" );
  6216. ConVar cl_obs_interp_settle_dist( "cl_obs_interp_settle_dist", "16" );
  6217. ConVar cl_obs_interp_dist_to_turn_to_face( "cl_obs_interp_dist_to_turn_to_face", "500", 0, "Changing to a target further than this will cause the camera to face the direction of travel" );
  6218. ConVar cl_obs_interp_angle_progress_headstart( "cl_obs_interp_angle_progress_headstart", "0.025" );
  6219. ConVar cl_obs_interp_turn_to_face_start_frac( "cl_obs_interp_turn_to_face_start_frac", "0.1" );
  6220. ConVar cl_obs_interp_turn_to_face_end_frac( "cl_obs_interp_turn_to_face_end_frac", "0.65" );
  6221. ConVar cl_obs_interp_obstruction_behavior( "cl_obs_interp_obstruction_behavior", "2" );
  6222. extern ConVar sv_disable_observer_interpolation;
  6223. void C_CSPlayer::InterpolateObserverView( Vector& vOutOrigin, QAngle& vOutAngles )
  6224. {
  6225. Assert( vOutAngles.IsValid() && vOutOrigin.IsValid() );
  6226. // Interpolate the view between observer target changes
  6227. if ( m_obsInterpState != OBSERVER_INTERP_NONE && ShouldInterpolateObserverChanges() )
  6228. {
  6229. // We flag observer interpolation on as soon as observer targets change in the recvproxy change callback,
  6230. // but we can't get entity position that early in the frame, so some setup is deferred until this point. We
  6231. // have to set observer interpolation earlier, before the view is set up for this frame, otherwise we'll get a flicker
  6232. // as the first frame after an observer target change will draw at the final position.
  6233. if ( m_bObserverInterpolationNeedsDeferredSetup )
  6234. {
  6235. // Initial setup
  6236. m_vecObserverInterpolateOffset = vOutOrigin - m_vecObserverInterpStartPos;
  6237. m_flObsInterp_PathLength = m_vecObserverInterpolateOffset.Length();
  6238. Vector vRight = m_vecObserverInterpolateOffset.Cross( Vector( 0, 0, 1 ) );
  6239. Vector vUp = vRight.Cross( m_vecObserverInterpolateOffset );
  6240. BasisToQuaternion( m_vecObserverInterpolateOffset.Normalized(), vRight.Normalized(), vUp.Normalized(), m_qObsInterp_OrientationTravelDir );
  6241. m_bObserverInterpolationNeedsDeferredSetup = false;
  6242. }
  6243. float flPosProgress = ExponentialDecay( cl_obs_interp_pos_halflife.GetFloat(), cl_obs_interp_pos_rate.GetFloat(), gpGlobals->frametime );
  6244. // Decay the offset vector until we reach the new observer position
  6245. m_vecObserverInterpolateOffset *= flPosProgress;
  6246. vOutOrigin -= m_vecObserverInterpolateOffset;
  6247. // Angle interpolation is a function of position progress so they stay in sync (adding a slight head start for aesthetic reasons)
  6248. float flPathProgress, flObserverInterpolateOffset = m_vecObserverInterpolateOffset.Length();
  6249. if ( m_flObsInterp_PathLength <= 0.0001f * flObserverInterpolateOffset )
  6250. {
  6251. flPathProgress = 1.0f;
  6252. }
  6253. else
  6254. {
  6255. flPathProgress = ( flObserverInterpolateOffset / m_flObsInterp_PathLength ) - cl_obs_interp_angle_progress_headstart.GetFloat();
  6256. flPathProgress = 1.0f - Clamp( flPathProgress, 0.0f, 1.0f );
  6257. }
  6258. // Messy and in flux... still tuning the interpolation code below
  6259. Quaternion q1, q2;
  6260. Quaternion qFinal;
  6261. AngleQuaternion( vOutAngles, qFinal );
  6262. float t = 0;
  6263. if ( m_flObsInterp_PathLength > cl_obs_interp_dist_to_turn_to_face.GetFloat() && GetObserverMode() == OBS_MODE_IN_EYE )
  6264. {
  6265. // at a far enough distance, turn to face direction of motion before ending at final angles
  6266. //QuaternionSlerp( m_qObsInterp_OrientationStart, m_qObsInterp_OrientationTravelDir, flPathProgress, q1 );
  6267. //QuaternionSlerp( m_qObsInterp_OrientationTravelDir, qFinal, flPathProgress, q2 );
  6268. if ( flPathProgress < cl_obs_interp_turn_to_face_start_frac.GetFloat() )
  6269. {
  6270. //QuaternionSlerp( m_qObsInterp_OrientationStart, m_qObsInterp_OrientationTravelDir, flPathProgress, q1 );
  6271. q1 = m_qObsInterp_OrientationStart;
  6272. q2 = m_qObsInterp_OrientationTravelDir;
  6273. t = RemapVal( flPathProgress, 0.0, cl_obs_interp_turn_to_face_start_frac.GetFloat(), 0.0, 1.0 );
  6274. }
  6275. else if ( flPathProgress < cl_obs_interp_turn_to_face_end_frac.GetFloat() )
  6276. {
  6277. q1 = q2 = m_qObsInterp_OrientationTravelDir;
  6278. }
  6279. else
  6280. {
  6281. q1 = m_qObsInterp_OrientationTravelDir;
  6282. q2 = qFinal;
  6283. t = SimpleSplineRemapValClamped( flPathProgress, cl_obs_interp_turn_to_face_end_frac.GetFloat(), 1.0, 0.0, 1.0 );
  6284. }
  6285. }
  6286. else
  6287. {
  6288. // Otherwise, interpolate from start to end orientation
  6289. q1 = m_qObsInterp_OrientationStart;
  6290. q2 = qFinal;
  6291. t = flPathProgress;
  6292. }
  6293. Quaternion qOut;
  6294. //QuaternionSlerp( q1, q2, flPathProgress, qOut );
  6295. QuaternionSlerp( q1, q2, t, qOut );
  6296. QuaternionAngles( qOut, vOutAngles );
  6297. Assert( cl_obs_interp_snap_dist.GetFloat() < cl_obs_interp_settle_dist.GetFloat() );
  6298. // At a close enough dist snap to final and stop interpolating
  6299. if ( m_vecObserverInterpolateOffset.LengthSqr() < cl_obs_interp_snap_dist.GetFloat()*cl_obs_interp_snap_dist.GetFloat() )
  6300. {
  6301. m_obsInterpState = OBSERVER_INTERP_NONE;
  6302. UpdateObserverTargetVisibility();
  6303. }
  6304. else if ( m_vecObserverInterpolateOffset.LengthSqr() < cl_obs_interp_settle_dist.GetFloat() * cl_obs_interp_settle_dist.GetFloat() )
  6305. {
  6306. m_obsInterpState = OBSERVER_INTERP_SETTLING;
  6307. UpdateObserverTargetVisibility();
  6308. }
  6309. }
  6310. Assert( vOutAngles.IsValid() && vOutOrigin.IsValid() );
  6311. }
  6312. void C_CSPlayer::UpdateObserverTargetVisibility( void ) const
  6313. {
  6314. C_CSPlayer *pObservedPlayer = dynamic_cast < C_CSPlayer* >( GetObserverTarget() );
  6315. if ( pObservedPlayer )
  6316. {
  6317. extern void UpdateViewmodelVisibility( C_BasePlayer *player );
  6318. UpdateViewmodelVisibility( pObservedPlayer );
  6319. pObservedPlayer->UpdateVisibility();
  6320. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  6321. if ( pLocalPlayer )
  6322. pLocalPlayer->UpdateGlowsForAllPlayers();
  6323. }
  6324. }
  6325. bool C_CSPlayer::ShouldInterpolateObserverChanges() const
  6326. {
  6327. if ( !cl_obs_interp_enable.GetBool() )
  6328. return false;
  6329. // server doesn't want this
  6330. if ( sv_disable_observer_interpolation.GetBool() )
  6331. return false;
  6332. // Disallow when playing on a team in a competitive match
  6333. bool bIsPlayingOnCompetitiveTeam = CSGameRules() && CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() && ( GetAssociatedTeamNumber() == TEAM_CT || GetAssociatedTeamNumber() == TEAM_TERRORIST );
  6334. if ( bIsPlayingOnCompetitiveTeam )
  6335. return false;
  6336. // supported modes
  6337. if ( GetObserverMode() != OBS_MODE_IN_EYE && GetObserverMode() != OBS_MODE_CHASE && GetObserverMode() != OBS_MODE_ROAMING )
  6338. return false;
  6339. // In hltv, our camera man might be the player we're using for view. Only bother with the dynamic cast if needed.
  6340. CBasePlayer *pCameraMan = NULL;
  6341. if ( engine->IsHLTV() )
  6342. pCameraMan = HLTVCamera()->GetCameraMan();
  6343. // If we are in hltv and have a camera man, only run for that player. Otherwise, only run for the local player.
  6344. CBasePlayer *pInterpPlayer = ( engine->IsHLTV() && pCameraMan ) ? pCameraMan : C_CSPlayer::GetLocalCSPlayer();
  6345. if ( pInterpPlayer != this )
  6346. return false;
  6347. return true;
  6348. }
  6349. // Set up initial state for interpolating between observer positions
  6350. void C_CSPlayer::StartObserverInterpolation( const QAngle& startAngles )
  6351. {
  6352. // Find obstructions in the path, skip past them if needed
  6353. m_vecObserverInterpStartPos = MainViewOrigin( GetSplitScreenPlayerSlot() );
  6354. C_CSPlayer* pObserverTarget = dynamic_cast< C_CSPlayer* > ( GetObserverTarget() );
  6355. if ( cl_obs_interp_obstruction_behavior.GetInt() > 0 && pObserverTarget )
  6356. {
  6357. trace_t tr;
  6358. Ray_t ray;
  6359. // HACK: This is wrong for chase and roam modes, but this is too early in the frame to call
  6360. // CalcObserverView functions without trigger the absqueries valid assert... Revisit if needed,
  6361. // but this will probably be a good enough test to see if we would lerp through solid
  6362. ray.Init( pObserverTarget->GetNetworkOrigin() + VEC_VIEW, m_vecObserverInterpStartPos );
  6363. CTraceFilterWorldAndPropsOnly filter;
  6364. enginetrace->TraceRay( ray, MASK_VISIBLE, &filter, &tr );
  6365. if ( tr.DidHit() )
  6366. {
  6367. if ( cl_obs_interp_obstruction_behavior.GetInt() == 1 )
  6368. {
  6369. m_vecObserverInterpStartPos = tr.endpos;
  6370. }
  6371. else if ( cl_obs_interp_obstruction_behavior.GetInt() == 2 )
  6372. {
  6373. m_obsInterpState = OBSERVER_INTERP_NONE;
  6374. UpdateObserverTargetVisibility();
  6375. return;
  6376. }
  6377. }
  6378. }
  6379. AngleQuaternion( startAngles, m_qObsInterp_OrientationStart );
  6380. m_obsInterpState = OBSERVER_INTERP_TRAVELING;
  6381. m_bObserverInterpolationNeedsDeferredSetup = true;
  6382. UpdateObserverTargetVisibility();
  6383. }
  6384. C_CSPlayer::eObserverInterpState C_CSPlayer::GetObserverInterpState( void ) const
  6385. {
  6386. if ( !ShouldInterpolateObserverChanges() )
  6387. return OBSERVER_INTERP_NONE;
  6388. return m_obsInterpState;
  6389. }
  6390. void C_CSPlayer::SetObserverTarget( EHANDLE hTarget )
  6391. {
  6392. EHANDLE prevTarget = m_hObserverTarget;
  6393. BaseClass::SetObserverTarget( hTarget );
  6394. if ( hTarget && prevTarget != hTarget && ShouldInterpolateObserverChanges() )
  6395. {
  6396. QAngle eyeAngles;
  6397. if ( g_HltvReplaySystem.GetHltvReplayDelay() )
  6398. {
  6399. eyeAngles = view->GetViewSetup()->angles;
  6400. }
  6401. else
  6402. {
  6403. eyeAngles = EyeAngles();
  6404. }
  6405. StartObserverInterpolation( eyeAngles );
  6406. }
  6407. }
  6408. // [tj] checks if this player has another given player on their Steam friends list.
  6409. bool C_CSPlayer::HasPlayerAsFriend( C_CSPlayer* player )
  6410. {
  6411. if ( !steamapicontext || !steamapicontext->SteamFriends() || !steamapicontext->SteamUtils() || !player )
  6412. {
  6413. return false;
  6414. }
  6415. player_info_t pi;
  6416. if ( !engine->GetPlayerInfo( player->entindex(), &pi ) )
  6417. {
  6418. return false;
  6419. }
  6420. if ( !pi.friendsID )
  6421. {
  6422. return false;
  6423. }
  6424. // check and see if they're on the local player's friends list
  6425. CSteamID steamID( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual );
  6426. return steamapicontext->SteamFriends()->HasFriend( steamID, k_EFriendFlagImmediate );
  6427. }
  6428. // [menglish] Returns whether this player is dominating or is being dominated by the specified player
  6429. bool C_CSPlayer::IsPlayerDominated( int iPlayerIndex )
  6430. {
  6431. if ( CSGameRules()->IsPlayingGunGame() )
  6432. return m_bPlayerDominated.Get( iPlayerIndex );
  6433. return false;
  6434. }
  6435. bool C_CSPlayer::IsPlayerDominatingMe( int iPlayerIndex )
  6436. {
  6437. if ( CSGameRules()->IsPlayingGunGame() )
  6438. return m_bPlayerDominatingMe.Get( iPlayerIndex );
  6439. return false;
  6440. }
  6441. //-----------------------------------------------------------------------------
  6442. // Purpose: helper interpolation functions
  6443. //-----------------------------------------------------------------------------
  6444. namespace Interpolators
  6445. {
  6446. inline float Linear( float t ) { return t; }
  6447. inline float SmoothStep( float t )
  6448. {
  6449. t = 3 * t * t - 2.0f * t * t * t;
  6450. return t;
  6451. }
  6452. inline float SmoothStep2( float t )
  6453. {
  6454. return t * t * t * (t * (t * 6.0f - 15.0f ) + 10.0f);
  6455. }
  6456. inline float SmoothStepStart( float t )
  6457. {
  6458. t = 0.5f * t;
  6459. t = 3 * t * t - 2.0f * t * t * t;
  6460. t = t* 2.0f;
  6461. return t;
  6462. }
  6463. inline float SmoothStepEnd( float t )
  6464. {
  6465. t = 0.5f * t + 0.5f;
  6466. t = 3 * t * t - 2.0f * t * t * t;
  6467. t = (t - 0.5f ) * 2.0f;
  6468. return t;
  6469. }
  6470. }
  6471. float C_CSPlayer::GetFreezeFrameInterpolant( void )
  6472. {
  6473. float fCurTime = gpGlobals->curtime - m_flFreezeFrameStartTime;
  6474. float fTravelTime = !m_bFreezeFrameCloseOnKiller ? spec_freeze_traveltime.GetFloat() : spec_freeze_traveltime_long.GetFloat();
  6475. float fInterpolant = clamp( fCurTime / fTravelTime, 0.0f, 1.0f );
  6476. return Interpolators::SmoothStepEnd( fInterpolant );
  6477. }
  6478. //-----------------------------------------------------------------------------
  6479. // Purpose: Calculate the view for the player while he's in freeze frame observer mode
  6480. //-----------------------------------------------------------------------------
  6481. void C_CSPlayer::CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
  6482. {
  6483. //SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate = 0.0f, int iZoomStart = 0 );
  6484. C_BaseEntity *pTarget = GetObserverTarget();
  6485. Vector prevEyeOrigin = eyeOrigin;
  6486. QAngle prevEyeAngles = eyeAngles;
  6487. // if we auto-start replay, we don't want to layer camera motion on top of fade on top of replay scene cut
  6488. float fInterpolant = g_HltvReplaySystem.IsDelayedReplayRequestPending() ? 0.0f : GetFreezeFrameInterpolant();
  6489. static ConVarRef sv_disablefreezecam( "sv_disablefreezecam" );
  6490. if ( m_bAbortedFreezeFrame || !pTarget || pTarget == this || cl_disablefreezecam.GetBool() || sv_disablefreezecam.GetBool() || g_HltvReplaySystem.IsDelayedReplayRequestPending() )
  6491. {
  6492. if ( !pTarget )
  6493. {
  6494. if ( !m_bStartedFreezeFrame )
  6495. {
  6496. // randomly pick left or right
  6497. int nLeftOrRight = RandomInt( 0, 1 );
  6498. // sup dutch
  6499. m_flFreezeFrameTilt = ( nLeftOrRight > 0 ) ? RandomFloat( 4, 10 ) : RandomFloat( -4, -10 );
  6500. m_bStartedFreezeFrame = true;
  6501. }
  6502. eyeAngles.z = Lerp( fInterpolant, 0.0f, m_flFreezeFrameTilt );
  6503. }
  6504. return CalcDeathCamView( eyeOrigin, eyeAngles, fov );
  6505. }
  6506. Vector targetOrig = pTarget->GetRenderOrigin();
  6507. float flDistToTarg = (GetAbsOrigin() - targetOrig ).Length2D();
  6508. Vector vLookAt = pTarget->GetObserverCamOrigin(); // Returns ragdoll origin if they're ragdolled
  6509. vLookAt += GetChaseCamViewOffset( pTarget );
  6510. Vector vecCamTarget = vLookAt;
  6511. if ( pTarget->IsAlive() )
  6512. {
  6513. // Look at their chest, not their head
  6514. Vector maxs = GameRules()->GetViewVectors()->m_vHullMax;
  6515. vecCamTarget.z -= (maxs.z * 0.25 );
  6516. }
  6517. else
  6518. {
  6519. vecCamTarget.z += VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through
  6520. }
  6521. float flScaler = pTarget->IsAlive() ? 0.1 : 0.075;
  6522. float flDistFromCurToTarg2D = vLookAt.AsVector2D().DistTo( eyeOrigin.AsVector2D() );
  6523. vecCamTarget.z -= clamp( (flDistFromCurToTarg2D )*flScaler, 0, 34 );
  6524. // Figure out a view position in front of the target
  6525. Vector vecEyeOnPlane = eyeOrigin;
  6526. vecEyeOnPlane.z = vecCamTarget.z;
  6527. Vector vTargetPos = vecCamTarget;
  6528. Vector vToTarget = vTargetPos - vecEyeOnPlane;
  6529. VectorNormalize( vToTarget );
  6530. // Stop a few units away from the target, and shift up to be at the same height
  6531. vTargetPos = vecCamTarget - (vToTarget * m_flFreezeFrameDistance );
  6532. float flEyePosZ = pTarget->EyePosition().z;
  6533. vTargetPos.z = flEyePosZ + m_flFreezeZOffset;
  6534. if ( vToTarget == Vector( 0, 0, 0 ) )
  6535. {
  6536. // Abort!
  6537. m_bAbortedFreezeFrame = true;
  6538. return;
  6539. }
  6540. // Now trace out from the target, so that we're put in front of any walls
  6541. trace_t trace;
  6542. Vector vecHMinWall(-16,-16,-16 );
  6543. Vector vecHMaxWall(16,16,16 );
  6544. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  6545. UTIL_TraceHull( vecCamTarget, vTargetPos, vecHMinWall, vecHMaxWall, MASK_SHOT, pTarget, COLLISION_GROUP_NONE, &trace );
  6546. C_BaseEntity::PopEnableAbsRecomputations();
  6547. if ( trace.fraction < 1.0 )
  6548. {
  6549. // The camera's going to be really close to the target. So we don't end up
  6550. // looking at someone's chest, aim close freezecams at the target's eyes.
  6551. vTargetPos = trace.endpos;
  6552. vecCamTarget = vLookAt;
  6553. // To stop all close in views looking up at character's chins, move the view up.
  6554. vTargetPos.z += fabs(vecCamTarget.z - vTargetPos.z ) * 0.85;
  6555. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  6556. UTIL_TraceHull( vecCamTarget, vTargetPos, WALL_MIN, WALL_MAX, MASK_SHOT, pTarget, COLLISION_GROUP_NONE, &trace );
  6557. C_BaseEntity::PopEnableAbsRecomputations();
  6558. vTargetPos = trace.endpos;
  6559. }
  6560. // move the eye toward our killer
  6561. if ( !m_bStartedFreezeFrame )
  6562. {
  6563. m_vecFreezeFrameStart = eyeOrigin;
  6564. m_bFreezeFrameCloseOnKiller = false;
  6565. m_vecFreezeFrameAnglesStart = eyeAngles;
  6566. // randomly pick left or right
  6567. int nLeftOrRight = RandomInt( 0, 1 );
  6568. m_nFreezeFrameShiftSideDist = nLeftOrRight == 1 ? RandomInt( 12, 22 ) : RandomInt( -12, -22 );
  6569. // sup dutch
  6570. m_flFreezeFrameTilt = ( m_nFreezeFrameShiftSideDist > 0 ) ? RandomFloat( 6, 14 ) : RandomFloat( -6, -14 );
  6571. if ( flDistToTarg >= FREEZECAM_LONGCAM_DIST )
  6572. {
  6573. m_bFreezeFrameCloseOnKiller = true;
  6574. }
  6575. else
  6576. {
  6577. // do a one time hull trace to the target and see if it's wide enough
  6578. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  6579. Vector vecHMin(-16,-16,-16 );
  6580. Vector vecHMax(16,16,16 );
  6581. trace_t trace3;
  6582. UTIL_TraceHull( m_vecFreezeFrameStart, vTargetPos, vecHMin, vecHMax, MASK_SHOT, this, COLLISION_GROUP_DEBRIS, &trace3 );
  6583. C_BaseEntity::PopEnableAbsRecomputations();
  6584. if ( trace3.fraction < 1.0 )
  6585. {
  6586. //Abort!
  6587. m_bFreezeFrameCloseOnKiller = true;
  6588. }
  6589. }
  6590. m_bStartedFreezeFrame = true;
  6591. }
  6592. //Vector vCamEnd = EyePosition() - ( vToTarget * 90 );
  6593. if ( !m_bFreezeFrameCloseOnKiller && flDistToTarg < FREEZECAM_LONGCAM_DIST )
  6594. {
  6595. Vector vCamEnd = m_vecFreezeFrameStart - ( vToTarget * 8 );
  6596. vCamEnd.z += MAX( (m_vecFreezeFrameStart.z - vecCamTarget.z )*0.75, 8 );
  6597. Vector forward, right, up;
  6598. QAngle angTemp;
  6599. VectorAngles( vToTarget, angTemp );
  6600. AngleVectors (angTemp, &forward, &right, &up );
  6601. Vector vLRStart = m_vecFreezeFrameStart;
  6602. Vector vLREnd = vCamEnd - ( right * m_nFreezeFrameShiftSideDist );
  6603. trace_t traceLR;
  6604. UTIL_TraceHull(m_vecFreezeFrameStart, vLREnd, WALL_MIN, WALL_MAX, MASK_SOLID, this, COLLISION_GROUP_NONE, &traceLR );
  6605. IRagdoll *pRagdoll = GetRepresentativeRagdoll();
  6606. if ( pRagdoll )
  6607. {
  6608. vLRStart = pRagdoll->GetRagdollOrigin();
  6609. vLRStart.z = trace.endpos.z;
  6610. }
  6611. float distToOffset = vLRStart.AsVector2D().DistTo( trace.endpos.AsVector2D() );
  6612. if ( traceLR.fraction < 0.2 || distToOffset < 16 )
  6613. {
  6614. // Abort!
  6615. m_bFreezeFrameCloseOnKiller = true;
  6616. }
  6617. m_vecFreezeFrameEnd = traceLR.endpos;
  6618. //DebugDrawLine( m_vecFreezeFrameStart, m_vecFreezeFrameEnd, 255, 0, 0, false, 25 );
  6619. }
  6620. float flNewFOV = spec_freeze_target_fov.GetFloat();
  6621. // dont frame both player, just zoom on killer
  6622. if ( m_bFreezeFrameCloseOnKiller )
  6623. {
  6624. m_vecFreezeFrameEnd = vTargetPos;
  6625. flNewFOV = spec_freeze_target_fov_long.GetFloat();
  6626. }
  6627. // Look directly at the target
  6628. vToTarget = vecCamTarget - prevEyeOrigin;
  6629. VectorNormalize( vToTarget );
  6630. VectorAngles( vToTarget, eyeAngles );
  6631. // apply the tilt
  6632. eyeAngles.z = Lerp( fInterpolant, 0.0f, m_flFreezeFrameTilt );
  6633. // set the fov to the convar, but have it hit the target slightly before the camera stops
  6634. fov = clamp( Lerp( fInterpolant + 0.05f, (float )GetDefaultFOV(), flNewFOV ), flNewFOV, GetDefaultFOV() );
  6635. Interpolator_CurveInterpolate( INTERPOLATE_SIMPLE_CUBIC, m_vecFreezeFrameStart - Vector( 0, 0, -12 ), m_vecFreezeFrameStart, m_vecFreezeFrameEnd, vTargetPos, fInterpolant, eyeOrigin );
  6636. float fCurTime = gpGlobals->curtime - m_flFreezeFrameStartTime;
  6637. float fTravelTime = !m_bFreezeFrameCloseOnKiller ? spec_freeze_traveltime.GetFloat() : spec_freeze_traveltime_long.GetFloat();
  6638. // cancel the light shortly after the freeze frame was taken
  6639. if ( m_bSentFreezeFrame && fCurTime >= (fTravelTime + 0.25f ) )
  6640. {
  6641. CancelFreezeCamFlashlightEffect();
  6642. }
  6643. else
  6644. {
  6645. UpdateFreezeCamFlashlightEffect( pTarget, fInterpolant );
  6646. }
  6647. // [jason] check that our target position does not fall within the render extents of the target we're looking at;
  6648. // this can happen if our killer is in a tight spot and the camera is trying to avoid clipping geometry
  6649. const int kFreezeCamTolerance = cl_freeze_cam_penetration_tolerance.GetInt();
  6650. if ( !m_bSentFreezeFrame && kFreezeCamTolerance >= 0 )
  6651. {
  6652. // at really long distances the camera moves long distances each frame
  6653. // this means that thecamera could bypass the target spot by a bunch, so
  6654. // let' check to see if the target will surpass the target pos next frame and just go ahead and stop
  6655. bool bStopCamera = false;
  6656. float distFromPrev = eyeOrigin.AsVector2D().DistTo( prevEyeOrigin.AsVector2D() );
  6657. float distToTargetPos = m_vecFreezeFrameEnd.AsVector2D().DistTo( eyeOrigin.AsVector2D() );
  6658. // either use the render extents of the target, or the value we specified in the convar
  6659. float targetRadius = (float )kFreezeCamTolerance;
  6660. if ( m_bFreezeFrameCloseOnKiller && targetRadius <= 0.0f )
  6661. {
  6662. Vector vecMins, vecMaxs;
  6663. pTarget->GetRenderBounds( vecMins, vecMaxs );
  6664. targetRadius = vecMins.AsVector2D().DistTo( vecMaxs.AsVector2D() ) * 0.3f;
  6665. }
  6666. // figure out ho much we moved last frame and keep from clipping too far into the killer's face
  6667. if ( distToTargetPos - (distFromPrev - distToTargetPos) < (targetRadius*0.5f) )
  6668. {
  6669. bStopCamera = true;
  6670. }
  6671. // disregard height, treat the target as an infinite cylinder so we don't end up with extreme up/down view angles
  6672. float distFromTarget = vLookAt.AsVector2D().DistTo( eyeOrigin.AsVector2D() );
  6673. if ( (m_bFreezeFrameCloseOnKiller && distFromTarget < targetRadius ) )
  6674. {
  6675. DevMsg( "CS_PLAYER: Detected overlap: Extents of target = %3.2f, Dist from them = %3.2f \n", targetRadius, distFromTarget );
  6676. bStopCamera = true;
  6677. }
  6678. if ( bStopCamera )
  6679. {
  6680. eyeOrigin = prevEyeOrigin;
  6681. eyeAngles = prevEyeAngles;
  6682. fTravelTime = fCurTime;
  6683. m_flFreezeFrameTilt = eyeAngles.z;
  6684. }
  6685. }
  6686. if ( fCurTime >= fTravelTime && !m_bSentFreezeFrame )
  6687. {
  6688. IGameEvent *pEvent = gameeventmanager->CreateEvent( "freezecam_started" );
  6689. if ( pEvent )
  6690. {
  6691. gameeventmanager->FireEventClientSide( pEvent );
  6692. }
  6693. m_bSentFreezeFrame = true;
  6694. view->FreezeFrame( spec_freeze_time.GetFloat() );
  6695. }
  6696. }
  6697. float C_CSPlayer::GetDeathCamInterpolationTime()
  6698. {
  6699. static ConVarRef sv_disablefreezecam( "sv_disablefreezecam" );
  6700. if ( cl_disablefreezecam.GetBool() || sv_disablefreezecam.GetBool() || !GetObserverTarget() || g_HltvReplaySystem.IsDelayedReplayRequestPending() )
  6701. return spec_freeze_time.GetFloat();
  6702. else
  6703. return spec_freeze_deathanim_time.GetFloat();
  6704. }
  6705. void C_CSPlayer::UpdateFreezeCamFlashlightEffect( C_BaseEntity *pTarget, float flAmount )
  6706. {
  6707. if ( !pTarget )
  6708. {
  6709. CancelFreezeCamFlashlightEffect();
  6710. return;
  6711. }
  6712. Vector brightness( spec_freeze_cinematiclight_r.GetFloat(), spec_freeze_cinematiclight_g.GetFloat(), spec_freeze_cinematiclight_b.GetFloat() );
  6713. Vector dimWhite( 0.3f, 0.3f, 0.3f );
  6714. if ( !m_bFreezeCamFlashlightActive )
  6715. {
  6716. //m_fFlashlightEffectStartTonemapScale = GetCurrentTonemapScale();
  6717. m_bFreezeCamFlashlightActive = true;
  6718. //m_fFlashlightEffectStartTime = gpGlobals->curtime;
  6719. //m_flashLightFadeTimer.Start( 3.0f );
  6720. }
  6721. Vector vecFlashlightOrigin;
  6722. Vector vecFlashlightForward( 0.0f, 0.0f, -1.0f );
  6723. Vector vecFlashlightRight( 1.0f, 0.0f, 0.0f );
  6724. Vector vecFlashlightUp( 0.0f, 1.0f, 0.0f );
  6725. float fFOV = 0.0f;
  6726. float invScale = 1.0f;
  6727. //if ( m_fFlashlightEffectStartTonemapScale != 0.0f )
  6728. //{
  6729. // invScale = 1.0f / m_fFlashlightEffectStartTonemapScale;
  6730. //}
  6731. brightness = (brightness * invScale * spec_freeze_cinematiclight_scale.GetFloat() ) * flAmount;
  6732. //if ( isDying )
  6733. {
  6734. Vector targetOrig = pTarget->GetRenderOrigin();
  6735. targetOrig.z += 32;
  6736. Vector vToTarget = targetOrig - EyePosition();
  6737. VectorNormalize( vToTarget );
  6738. Vector forward, right, up;
  6739. QAngle angTemp;
  6740. VectorAngles( vToTarget, angTemp );
  6741. AngleVectors (angTemp, &forward, &right, &up );
  6742. if ( m_nFreezeFrameShiftSideDist > 0 )
  6743. vecFlashlightOrigin = targetOrig + ( right * 80 );
  6744. else
  6745. vecFlashlightOrigin = targetOrig - ( right * 80 );
  6746. vecFlashlightOrigin -= ( forward * 50 );
  6747. vecFlashlightOrigin.z += 100.f;
  6748. float flFOVExtra = 0;
  6749. trace_t trace;
  6750. UTIL_TraceLine( targetOrig, vecFlashlightOrigin, MASK_OPAQUE, pTarget, COLLISION_GROUP_DEBRIS, &trace );
  6751. if ( trace.fraction >= 0.8 )
  6752. {
  6753. vecFlashlightOrigin = trace.endpos;
  6754. }
  6755. else
  6756. {
  6757. // just go the other way
  6758. if ( m_nFreezeFrameShiftSideDist > 0 )
  6759. vecFlashlightOrigin = targetOrig - ( right * 60 );
  6760. else
  6761. vecFlashlightOrigin = targetOrig + ( right * 60 );
  6762. vecFlashlightOrigin -= ( forward * 40 );
  6763. vecFlashlightOrigin.z += 80.f;
  6764. UTIL_TraceLine( targetOrig, vecFlashlightOrigin, MASK_OPAQUE, pTarget, COLLISION_GROUP_DEBRIS, &trace );
  6765. vecFlashlightOrigin = trace.endpos;
  6766. flFOVExtra = (1 - trace.fraction ) * 20;
  6767. targetOrig.z += flFOVExtra;
  6768. }
  6769. Vector vToTarget2 = targetOrig - vecFlashlightOrigin;
  6770. VectorNormalize( vToTarget2 );
  6771. QAngle angTemp2;
  6772. VectorAngles( vToTarget2, angTemp2 );
  6773. AngleVectors (angTemp2, &vecFlashlightForward, &vecFlashlightRight, &vecFlashlightUp );
  6774. fFOV = 50.f + flFOVExtra;
  6775. }
  6776. MDLCACHE_CRITICAL_SECTION();
  6777. FlashlightEffectManager().EnableFlashlightOverride( true );
  6778. FlashlightEffectManager().UpdateFlashlightOverride( true, vecFlashlightOrigin, vecFlashlightForward, vecFlashlightRight,
  6779. vecFlashlightUp, fFOV, true, m_freezeCamSpotLightTexture, brightness );
  6780. // force tonemapping down
  6781. //if ( m_bOverrideTonemapping )
  6782. //{
  6783. // SetOverrideTonemapScale( true, fTonemapScale );
  6784. //}
  6785. }
  6786. void C_CSPlayer::CancelFreezeCamFlashlightEffect()
  6787. {
  6788. if( m_bFreezeCamFlashlightActive )
  6789. {
  6790. FlashlightEffectManager().EnableFlashlightOverride( false );
  6791. m_bFreezeCamFlashlightActive = false;
  6792. }
  6793. }
  6794. void C_CSPlayer::CalcDeathCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
  6795. {
  6796. CBaseEntity* pKiller = NULL;
  6797. if ( mp_forcecamera.GetInt() == OBS_ALLOW_ALL )
  6798. {
  6799. // if mp_forcecamera is off let user see killer or look around
  6800. pKiller = GetObserverTarget();
  6801. eyeAngles = EyeAngles();
  6802. }
  6803. // NOTE: CS_DEATH_ANIMATION_TIME differs from base class implementation
  6804. float interpolation = ( gpGlobals->curtime - m_flDeathTime ) / CS_DEATH_ANIMATION_TIME;
  6805. interpolation = clamp( interpolation, 0.0f, 1.0f );
  6806. m_flObserverChaseDistance += gpGlobals->frametime*48.0f;
  6807. m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, 16, CHASE_CAM_DISTANCE );
  6808. QAngle aForward = eyeAngles;
  6809. Vector origin = EyePosition();
  6810. IRagdoll *pRagdoll = GetRepresentativeRagdoll();
  6811. if ( pRagdoll )
  6812. {
  6813. origin = pRagdoll->GetRagdollOrigin();
  6814. origin.z += VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through
  6815. }
  6816. if ( pKiller && pKiller->IsPlayer() && pKiller != this )
  6817. {
  6818. //Get the vector from the dead body EyePos to the killers EyePos
  6819. Vector vKiller = pKiller->EyePosition() - origin;
  6820. // Get the angles for that vector
  6821. QAngle aKiller; VectorAngles( vKiller, aKiller );
  6822. // Interpolate from the original eye angles to point at the killers EyePos
  6823. InterpolateAngles( aForward, aKiller, eyeAngles, interpolation );
  6824. }
  6825. // Get the vector for our new view. It should be looking at the killer
  6826. Vector vForward; AngleVectors( eyeAngles, &vForward );
  6827. VectorNormalize( vForward );
  6828. // Add the two vectors with the negative chase distance as a scale
  6829. VectorMA( origin, -m_flObserverChaseDistance, vForward, eyeOrigin );
  6830. trace_t trace; // clip against world
  6831. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  6832. UTIL_TraceHull( origin, eyeOrigin, WALL_MIN, WALL_MAX, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace );
  6833. C_BaseEntity::PopEnableAbsRecomputations();
  6834. if ( trace.fraction < 1.0 )
  6835. {
  6836. eyeOrigin = trace.endpos;
  6837. m_flObserverChaseDistance = VectorLength( origin - eyeOrigin );
  6838. }
  6839. fov = GetFOV();
  6840. }
  6841. bool C_CSPlayer::IsCursorOnAutoAimTarget()
  6842. {
  6843. // don't allow autoaiming on PC at all
  6844. if ( IsPC() )
  6845. return false;
  6846. // disabled 6/29/15 -mtw
  6847. /*
  6848. // [sbodenbender] $TODO: for now, we will still allow autoaim even when blinded
  6849. // code lifted from hintupdate in server side player code
  6850. //if ( IsBlind() || IsObserver() )
  6851. // return false;
  6852. QAngle aimAngles = GetFinalAimAngle();
  6853. Vector forward;
  6854. AngleVectors( aimAngles, &forward );
  6855. trace_t tr;
  6856. // Search for objects in a sphere (tests for entities that are not solid, yet still useable )
  6857. Vector searchStart = EyePosition();
  6858. const float flMaxSearchDistance = 4098.0f; // Make sure this works for long shots like with sniper rifles.
  6859. Vector searchEnd = searchStart + forward * flMaxSearchDistance;
  6860. //int useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_VISIBLE_AND_NPCS;
  6861. int useableContents = MASK_SHOT;
  6862. UTIL_TraceLine( searchStart, searchEnd, useableContents, this, COLLISION_GROUP_NONE, &tr );
  6863. if ( tr.fraction != 1.0f )
  6864. {
  6865. if (tr.DidHitNonWorldEntity() && tr.m_pEnt )
  6866. {
  6867. CBaseEntity *pEntity = tr.m_pEnt;
  6868. // Autoaim at enemy players or at any entity that specifically requests it.
  6869. if ( pEntity && ( ( pEntity->IsPlayer() && !InSameTeam(pEntity ) ) || pEntity->IsAutoaimTarget() ) )
  6870. {
  6871. return true;
  6872. }
  6873. }
  6874. }
  6875. */
  6876. return false;
  6877. }
  6878. bool C_CSPlayer::CanUseGrenade( CSWeaponID nID )
  6879. {
  6880. if ( nID == WEAPON_MOLOTOV || nID == WEAPON_INCGRENADE )
  6881. {
  6882. if ( gpGlobals->curtime < m_fMolotovUseTime )
  6883. {
  6884. // Can't use molotov until timer elapses
  6885. return false;
  6886. }
  6887. }
  6888. return true;
  6889. }
  6890. void C_CSPlayer::DisplayInventory( bool showPistol )
  6891. {
  6892. if ( !C_BasePlayer::GetLocalPlayer() || !engine->IsLocalPlayerResolvable() )
  6893. return;
  6894. SFWeaponSelection *pHudWS = GET_HUDELEMENT( SFWeaponSelection );
  6895. if ( !pHudWS )
  6896. {
  6897. return;
  6898. }
  6899. for ( int i = 0; i < WeaponCount(); ++i )
  6900. {
  6901. CWeaponCSBase *pWeapon = dynamic_cast< CWeaponCSBase* > ( GetWeapon( i ) );
  6902. if ( pWeapon == NULL )
  6903. continue;
  6904. if ( pWeapon->IsKindOf( WEAPONTYPE_GRENADE ) && ( ( CBaseCSGrenade * ) pWeapon )->GetIsThrown() )
  6905. {
  6906. // don't include thrown grenades in inventory
  6907. continue;
  6908. }
  6909. CSWeaponID weaponId = pWeapon->GetCSWeaponID();
  6910. if ( showPistol || !IsSecondaryWeapon( weaponId ) )
  6911. {
  6912. // TODO: weapon selection does this job now
  6913. //pItemHistory->AddToHistory( pWeapon );
  6914. pHudWS->ShowAndUpdateSelection();
  6915. }
  6916. }
  6917. /*
  6918. if ( HasDefuser() )
  6919. {
  6920. pItemHistory->AddToHistory( "defuser", "#Cstrike_BMDefuser" );
  6921. }
  6922. */
  6923. }
  6924. MedalRank_t C_CSPlayer::GetRank( MedalCategory_t category )
  6925. {
  6926. if ( CDemoPlaybackParameters_t const *pParameters = engine->GetDemoPlaybackParameters() )
  6927. {
  6928. if ( pParameters->m_bAnonymousPlayerIdentity )
  6929. return MEDAL_RANK_NONE;
  6930. }
  6931. return m_rank.Get( category );
  6932. }
  6933. uint32 C_CSPlayer::GetMusicID( )
  6934. {
  6935. return m_unMusicID.Get( );
  6936. }
  6937. void C_CSPlayer::UpdateAllBulletHitModels( void )
  6938. {
  6939. if ( sv_showbullethits.GetBool() )
  6940. {
  6941. FOR_EACH_VEC( m_vecBulletHitModels, n )
  6942. {
  6943. m_vecBulletHitModels[n]->UpdatePosition();
  6944. }
  6945. }
  6946. else
  6947. {
  6948. ClearAllBulletHitModels();
  6949. }
  6950. }
  6951. void C_CSPlayer::ClearAllBulletHitModels( void )
  6952. {
  6953. if ( m_vecBulletHitModels.Count() )
  6954. {
  6955. FOR_EACH_VEC( m_vecBulletHitModels, n )
  6956. {
  6957. m_vecBulletHitModels[n]->Release();
  6958. }
  6959. m_vecBulletHitModels.RemoveAll();
  6960. }
  6961. }
  6962. void C_BulletHitModel::AttachToPlayer( C_CSPlayer *pTargetPlayer, int nBoneIndex, matrix3x4_t matLocalOffset, bool bIsHit, Vector vecStartPos )
  6963. {
  6964. InitializeAsClientEntity( "models/tools/bullet_hit_marker.mdl", false );
  6965. m_hPlayerParent = pTargetPlayer;
  6966. MatrixCopy( matLocalOffset, m_matLocal );
  6967. m_iBoneIndex = nBoneIndex;
  6968. m_flTimeCreated = gpGlobals->curtime;
  6969. m_bIsHit = bIsHit;
  6970. m_vecStartPos = vecStartPos;
  6971. UpdatePosition();
  6972. SetAllowFastPath( false );
  6973. }
  6974. C_CSPlayer *C_BulletHitModel::GetPlayerParent() { return m_hPlayerParent.IsValid() ? static_cast< C_CSPlayer* >( m_hPlayerParent.Get() ) : NULL; }
  6975. bool C_BulletHitModel::UpdatePosition( void )
  6976. {
  6977. C_CSPlayer *pPlayer = GetPlayerParent();
  6978. if ( !pPlayer )
  6979. return false;
  6980. float flDuration = gpGlobals->curtime - m_flTimeCreated;
  6981. if ( flDuration > 5 && !m_bIsHit )
  6982. return false;
  6983. matrix3x4_t mat_boneToWorld;
  6984. if ( pPlayer->IsAlive() )
  6985. {
  6986. pPlayer->GetBoneTransform( m_iBoneIndex, mat_boneToWorld );
  6987. }
  6988. else if ( pPlayer->m_hRagdoll.Get() )
  6989. {
  6990. C_CSRagdoll *pRagdoll = (C_CSRagdoll* )pPlayer->m_hRagdoll.Get();
  6991. C_BaseAnimating *pBaseAnimating = pRagdoll->GetBaseAnimating();
  6992. pBaseAnimating->GetBoneTransform( m_iBoneIndex, mat_boneToWorld );
  6993. }
  6994. else
  6995. {
  6996. return false;
  6997. }
  6998. MatrixMultiply( mat_boneToWorld, m_matLocal, mat_boneToWorld );
  6999. Vector vecPos;
  7000. QAngle angAngles;
  7001. MatrixAngles( mat_boneToWorld, angAngles, vecPos );
  7002. SetAbsAngles( angAngles );
  7003. if ( flDuration <= 0.1 )
  7004. vecPos = Lerp( clamp(flDuration*10,0,1), m_vecStartPos, vecPos );
  7005. SetAbsOrigin( vecPos );
  7006. if ( m_bIsHit )
  7007. {
  7008. SetRenderColor( 240, 0, 0 );
  7009. }
  7010. else
  7011. {
  7012. float flDurationToColor = RemapValClamped( flDuration, 0, 0.8, 255, 0 );
  7013. if ( fmod( gpGlobals->curtime, 0.25 ) < 0.125 )
  7014. flDurationToColor = 0;
  7015. flDurationToColor = MAX( flDurationToColor, 100 );
  7016. SetRenderColor( flDurationToColor, flDurationToColor, flDurationToColor );
  7017. }
  7018. return true;
  7019. }
  7020. int C_BulletHitModel::DrawModel( int flags, const RenderableInstance_t &instance )
  7021. {
  7022. if ( m_hPlayerParent.IsValid() && m_hPlayerParent.Get() != GetLocalOrInEyeCSPlayer() && UpdatePosition() )
  7023. {
  7024. SetAllowFastPath( false );
  7025. return BaseClass::DrawModel(flags, instance);
  7026. }
  7027. return 0;
  7028. }
  7029. #if !defined( NO_STEAM ) && !defined( NO_STEAM_GAMECOORDINATOR )
  7030. #if defined ENABLE_CLIENT_INVENTORIES_FOR_OTHER_PLAYERS
  7031. CCSPlayerInventory *C_CSPlayer::Inventory( void )
  7032. {
  7033. static CCSPlayerInventory dummy;
  7034. if ( IsLocalPlayer() )
  7035. return dynamic_cast< CCSPlayerInventory* >( CSInventoryManager()->GetLocalInventory() );
  7036. if ( !g_PR )
  7037. return &dummy;
  7038. static XUID s_myXuid = steamapicontext->SteamUser()->GetSteamID().ConvertToUint64();
  7039. XUID thisXuid = g_PR->GetXuid( entindex() );
  7040. if ( thisXuid == INVALID_XUID )
  7041. return &dummy;
  7042. if ( thisXuid == s_myXuid )
  7043. return dynamic_cast< CCSPlayerInventory* >( CSInventoryManager()->GetLocalInventory() );
  7044. return static_cast< C_CS_PlayerResource * >( g_PR )->GetInventory( entindex() );
  7045. }
  7046. #endif
  7047. #endif //!defined( NO_STEAM ) && !defined( NO_STEAM_GAMECOORDINATOR )
  7048. // Adds a sound event to be played at the next round restart
  7049. void CStartOfRoundAudioPlayback::AddSound( CBaseEntity* pEntityPlayingSound, char* pName, float fPlaybackDuration )
  7050. {
  7051. // Ensure that the sound is not already in the playback list
  7052. for ( int i = 0; i < m_SoundEvents.Count(); ++i )
  7053. {
  7054. if ( Q_strcmp( pName, m_SoundEvents[i].m_SoundName ) == 0 )
  7055. {
  7056. // Found a match, so skip adding this sound
  7057. return;
  7058. }
  7059. }
  7060. if ( pEntityPlayingSound && pName && ( Q_strlen ( pName ) > 0 ) && ( fPlaybackDuration > 0.0f ) )
  7061. {
  7062. RoundStartSoundPlaybackData playbackData;
  7063. playbackData.m_pEntityPlayingSound = pEntityPlayingSound;
  7064. Q_snprintf( playbackData.m_SoundName, sizeof( playbackData.m_SoundName ), "%s", pName );
  7065. playbackData.m_fPlaybackTime = m_NextAvailableTime;
  7066. m_NextAvailableTime += fPlaybackDuration;
  7067. m_SoundEvents.AddToTail( playbackData );
  7068. }
  7069. }
  7070. // Play all the queued sounds
  7071. void CStartOfRoundAudioPlayback::PlaySounds( void )
  7072. {
  7073. m_bPlaybackEnabled = true;
  7074. // Loop through all the queued sound events and set their time to play
  7075. float curtime = gpGlobals->curtime;
  7076. for ( int i = 0; i < m_SoundEvents.Count(); ++i )
  7077. {
  7078. m_SoundEvents[i].m_fPlaybackTime += curtime;
  7079. }
  7080. }
  7081. // Play all the queued sounds
  7082. void CStartOfRoundAudioPlayback::Update( void )
  7083. {
  7084. if ( m_bPlaybackEnabled )
  7085. {
  7086. int nTotalSoundsPlayed = 0;
  7087. // Loop through each sound event to determine if it is time to play it
  7088. for ( int i = 0; i < m_SoundEvents.Count(); ++i )
  7089. {
  7090. if ( !m_SoundEvents[i].m_bHasBeenPlayed )
  7091. {
  7092. if ( ( m_SoundEvents[i].m_fPlaybackTime > 0.0f ) && ( m_SoundEvents[i].m_fPlaybackTime < gpGlobals->curtime ) )
  7093. {
  7094. // Play the bonus grenade voiceover sound
  7095. if ( m_SoundEvents[i].m_pEntityPlayingSound )
  7096. {
  7097. C_CSPlayer* pPlayer = static_cast<C_CSPlayer*>( m_SoundEvents[i].m_pEntityPlayingSound );
  7098. C_RecipientFilter filter;
  7099. filter.AddRecipient( pPlayer );
  7100. C_BaseEntity::EmitSound( filter, pPlayer->entindex(), m_SoundEvents[i].m_SoundName );
  7101. //DevMsg( "Played %s for Entity %d\n", m_SoundEvents[i].m_SoundName, pPlayer->entindex() );
  7102. }
  7103. m_SoundEvents[i].m_bHasBeenPlayed = true;
  7104. }
  7105. }
  7106. else
  7107. {
  7108. nTotalSoundsPlayed++;
  7109. }
  7110. }
  7111. if ( nTotalSoundsPlayed == m_SoundEvents.Count() )
  7112. {
  7113. // All sounds have been played, so clear the list of pending sound events
  7114. ClearSounds();
  7115. }
  7116. }
  7117. }
  7118. // Clear all the queued sounds
  7119. void CStartOfRoundAudioPlayback::ClearSounds( void )
  7120. {
  7121. m_SoundEvents.RemoveAll();
  7122. m_NextAvailableTime = 1.0f;
  7123. m_bPlaybackEnabled = false;
  7124. }
  7125. void CStartOfRoundAudioPlayback::RemoveSoundByName( char* pName )
  7126. {
  7127. FOR_EACH_VEC_BACK( m_SoundEvents, i )
  7128. {
  7129. if ( V_strcmp( m_SoundEvents[i].m_SoundName, pName ) == 0 )
  7130. {
  7131. m_SoundEvents.Remove( i );
  7132. }
  7133. }
  7134. }
  7135. static void CC_PlayerDecalTraceBloodDev( void )
  7136. {
  7137. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  7138. if ( pPlayer )
  7139. {
  7140. Vector vForward; AngleVectors( pPlayer->EyeAngles(), &vForward );
  7141. Vector vecSrc = pPlayer->Weapon_ShootPosition();
  7142. Vector vecEnd = vecSrc + vForward * 512;
  7143. trace_t tr;
  7144. UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
  7145. UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED );
  7146. }
  7147. }
  7148. static ConCommand cl_dev_decaltrace_blood( "cl_dev_decaltrace_blood", CC_PlayerDecalTraceBloodDev, "Shoot out a decal spray that shoots blood.", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );