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.

3916 lines
116 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Laser Rifle & Shield combo
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "in_buttons.h"
  9. #include "takedamageinfo.h"
  10. #include "weapon_csbase.h"
  11. #include "ammodef.h"
  12. #include "cs_gamerules.h"
  13. #include "basegrenade_shared.h"
  14. #include "weapon_basecsgrenade.h"
  15. #include "platforminputdevice.h"
  16. #include "inputsystem/iinputsystem.h"
  17. // CS-PRO TEST CHANGE: instant movement inaccuracy, curve exponent x^0.25
  18. #define MOVEMENT_ACCURACY_DECAYED 0
  19. #define MOVEMENT_WALK_CURVE01_EXPONENT 0.85
  20. #define MOVEMENT_CURVE01_EXPONENT 0.25
  21. #define SILENCER_VISIBLE 0
  22. #define SILENCER_HIDDEN 1
  23. #ifdef SIXENSE
  24. #include "sixense\in_sixense.h"
  25. #include "view.h"
  26. #endif
  27. #if defined( CLIENT_DLL )
  28. #include "vgui/ISurface.h"
  29. #include "vgui_controls/Controls.h"
  30. #include "c_cs_player.h"
  31. #include "predicted_viewmodel.h"
  32. #include "hud_crosshair.h"
  33. #include "c_te_effect_dispatch.h"
  34. #include "c_te_legacytempents.h"
  35. #include "cs_hud_weaponselection.h"
  36. #include "prediction.h"
  37. #include "materialsystem/icompositetexturegenerator.h"
  38. #include "materialsystem/icustommaterialmanager.h"
  39. #include "cs_custom_material_swap.h"
  40. #include "cs_custom_weapon_visualsdata_processor.h"
  41. //#include "glow_outline_effect.h"
  42. #include "HUD/sfhudreticle.h"
  43. extern IVModelInfoClient* modelinfo;
  44. extern ConVar spec_show_xray;
  45. #else
  46. #include "cs_player.h"
  47. #include "te_effect_dispatch.h"
  48. #include "keyvalues.h"
  49. #include "cs_ammodef.h"
  50. #include "cvisibilitymonitor.h"
  51. extern IVModelInfo* modelinfo;
  52. #endif
  53. // NOTE: This has to be the last file included!
  54. #include "tier0/memdbgon.h"
  55. #if defined( CSTRIKE15 )
  56. extern ConVar crosshair;
  57. extern WeaponRecoilData g_WeaponRecoilData;
  58. #endif
  59. extern ConVar cl_righthand;
  60. extern ConVar mp_weapons_allow_map_placed;
  61. extern ConVar mp_weapons_glow_on_ground;
  62. extern ConVar sv_jump_impulse;
  63. ConVar weapon_land_dip_amt( "weapon_land_dip_amt", "20.0", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT | FCVAR_REPLICATED, "The amount the gun should dip when the player lands after a jump." );
  64. ConVar weapon_recoil_decay1( "weapon_recoil_decay1_exp", "3.5", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Decay factor exponent for weapon recoil" );
  65. ConVar weapon_recoil_decay2_exp( "weapon_recoil_decay2_exp", "8", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Decay factor exponent for weapon recoil" );
  66. ConVar weapon_recoil_decay2_lin( "weapon_recoil_decay2_lin", "18", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Decay factor (linear term) for weapon recoil" );
  67. ConVar weapon_recoil_vel_decay( "weapon_recoil_vel_decay", "4.5", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Decay factor for weapon recoil velocity" );
  68. ConVar weapon_recoil_decay_coefficient( "weapon_recoil_decay_coefficient", "2.0", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "" );
  69. ConVar weapon_accuracy_nospread( "weapon_accuracy_nospread", "0", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Disable weapon inaccuracy spread" );
  70. ConVar weapon_recoil_cooldown( "weapon_recoil_cooldown", "0.55", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "DEPRECATED. Recoil now decays using weapon_recoil_decay_coefficient");
  71. ConVar weapon_recoil_scale( "weapon_recoil_scale", "2.0", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Overall scale factor for recoil. Used to reduce recoil on specific platforms");
  72. ConVar weapon_recoil_scale_motion_controller( "weapon_recoil_scale_motion_controller", "1.0", FCVAR_RELEASE | FCVAR_CHEAT |FCVAR_REPLICATED, "Overall scale factor for recoil. Used to reduce recoil. Only for motion controllers");
  73. ConVar weapon_air_spread_scale( "weapon_air_spread_scale", "1.0", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Scale factor for jumping inaccuracy, set to 0 to make jumping accuracy equal to standing", true, 0.0f, false, 1.0f );
  74. ConVar weapon_legacy_recoiltable( "weapon_legacy_recoiltable", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY );
  75. ConVar weapon_reticle_knife_show( "weapon_reticle_knife_show", "0", FCVAR_RELEASE | FCVAR_REPLICATED, "When enabled will show knife reticle on clients. Used for game modes requiring target id display when holding a knife." );
  76. ConVar weapon_auto_cleanup_time( "weapon_auto_cleanup_time", "0", FCVAR_RELEASE, "If set to non-zero, weapons will delete themselves after the specified time (in seconds) if no players are near." );
  77. ConVar weapon_max_before_cleanup( "weapon_max_before_cleanup", "0", FCVAR_RELEASE, "If set to non-zero, will remove the oldest dropped weapon to maintain the specified number of dropped weapons in the world." );
  78. #if defined( CLIENT_DLL )
  79. ConVar cl_weapon_debug_print_accuracy("cl_weapon_debug_print_accuracy", "0", FCVAR_RELEASE | FCVAR_CHEAT );
  80. ConVar cl_weapon_debug_show_accuracy("cl_weapon_debug_show_accuracy", "0", FCVAR_RELEASE | FCVAR_CHEAT, "Draws a circle representing the effective range with every shot." );
  81. ConVar cl_weapon_debug_show_accuracy_duration( "cl_weapon_debug_show_accuracy_duration", "10", FCVAR_RELEASE | FCVAR_CHEAT );
  82. #endif
  83. #define MP_WEAPON_ACCURACY_SEPARATE_WALK_FUNCTION true
  84. /*
  85. // TODO[pmf] make these work with recoil tables
  86. ConVar weapon_recoil_seed( "weapon_recoil_seed", "0", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT | FCVAR_REPLICATED );
  87. #if defined( GAME_DLL )
  88. CON_COMMAND_F( weapon_recoil_reseed, "Randomly generate a new recoil seed for the current weapon", FCVAR_DEVELOPMENTONLY )
  89. {
  90. int iNewSeed = RandomInt(0, 0xFFFF);
  91. weapon_recoil_seed.SetValue(iNewSeed);
  92. Msg("Recoil seed set to %i\n", iNewSeed);
  93. }
  94. #endif
  95. */
  96. void TE_DynamicLight( IRecipientFilter& filter, float delay,
  97. const Vector* org, int r, int g, int b, int exponent, float radius, float time, float decay, int nLightIndex = LIGHT_INDEX_TE_DYNAMIC );
  98. // ----------------------------------------------------------------------------- //
  99. // Global functions.
  100. // ----------------------------------------------------------------------------- //
  101. struct WeaponAliasTranslationInfoStruct
  102. {
  103. char* alias;
  104. char* translatedAlias;
  105. };
  106. static const WeaponAliasTranslationInfoStruct s_WeaponAliasTranslationInfo[] =
  107. {
  108. { "cv47", "ak47" },
  109. { "defender", "galil" },
  110. { "krieg552", "sg552" },
  111. { "magnum", "awp" },
  112. { "d3au1", "g3sg1" },
  113. { "clarion", "famas" },
  114. { "bullpup", "aug" },
  115. { "krieg550", "sg550" },
  116. { "9x19mm", "glock" },
  117. { "km45", "usp" },
  118. { "228compact", "p228" },
  119. { "nighthawk", "deagle" },
  120. { "elites", "elite" },
  121. { "fn57", "fiveseven" },
  122. { "12gauge", "m3" },
  123. { "autoshotgun", "xm1014" },
  124. { "mp", "tmp" },
  125. { "smg", "mp5navy" },
  126. { "mp5", "mp5navy" },
  127. { "c90", "p90" },
  128. { "vest", "kevlar" },
  129. { "vesthelm", "assaultsuit" },
  130. { "nvgs", "nightvision" },
  131. { "", "" } // this needs to be last
  132. };
  133. struct WeaponAliasInfo
  134. {
  135. CSWeaponID id;
  136. const char* alias;
  137. };
  138. bool IsAmmoType( int iAmmoType, const char *pAmmoName )
  139. {
  140. return GetAmmoDef()->Index( pAmmoName ) == iAmmoType;
  141. }
  142. //--------------------------------------------------------------------------------------------------------
  143. //
  144. // Given an alias, return the translated alias.
  145. //
  146. const char * GetTranslatedWeaponAlias( const char *szAlias )
  147. {
  148. for ( int i = 0; i < ARRAYSIZE( s_WeaponAliasTranslationInfo ); ++i )
  149. {
  150. if ( Q_stricmp( s_WeaponAliasTranslationInfo[i].alias, szAlias ) == 0 )
  151. {
  152. return s_WeaponAliasTranslationInfo[i].translatedAlias;
  153. }
  154. }
  155. return szAlias;
  156. }
  157. //--------------------------------------------------------------------------------------------------------
  158. //
  159. // Given a translated alias, return the alias.
  160. //
  161. const char * GetWeaponAliasFromTranslated( const char *translatedAlias )
  162. {
  163. int i = 0;
  164. const WeaponAliasTranslationInfoStruct *info = &( s_WeaponAliasTranslationInfo[i] );
  165. while ( info->alias[0] != 0 )
  166. {
  167. if ( Q_stricmp( translatedAlias, info->translatedAlias ) == 0 )
  168. {
  169. return info->alias;
  170. }
  171. info = &( s_WeaponAliasTranslationInfo[++i] );
  172. }
  173. return translatedAlias;
  174. }
  175. //--------------------------------------------------------------------------------------------------------
  176. //
  177. // Return true if given weapon ID is a primary weapon
  178. //
  179. bool IsPrimaryWeapon( CSWeaponID id )
  180. {
  181. const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo( id );
  182. if ( pWeaponInfo )
  183. {
  184. return pWeaponInfo->iSlot == WEAPON_SLOT_RIFLE;
  185. }
  186. return false;
  187. }
  188. //--------------------------------------------------------------------------------------------------------
  189. //
  190. // Return true if given weapon ID is a secondary weapon
  191. //
  192. bool IsSecondaryWeapon( CSWeaponID id )
  193. {
  194. const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo( id );
  195. if ( pWeaponInfo )
  196. return pWeaponInfo->iSlot == WEAPON_SLOT_PISTOL;
  197. return false;
  198. }
  199. //--------------------------------------------------------------------------------------------------------
  200. //
  201. // Return true if given weapon ID is a grenade weapon
  202. //
  203. bool IsGrenadeWeapon( CSWeaponID id )
  204. {
  205. const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo( id );
  206. if ( pWeaponInfo )
  207. {
  208. return pWeaponInfo->iSlot == WEAPON_SLOT_GRENADES;
  209. }
  210. return false;
  211. }
  212. //--------------------------------------------------------------------------------------------------------
  213. //
  214. // Return true if given weapon ID is armor
  215. //
  216. bool IsArmor( CSWeaponID id )
  217. {
  218. return id == ITEM_ASSAULTSUIT || id == ITEM_KEVLAR;
  219. }
  220. #ifdef CLIENT_DLL
  221. int GetShellForAmmoType( const char *ammoname )
  222. {
  223. if ( !Q_strcmp( BULLET_PLAYER_762MM, ammoname ) )
  224. return CS_SHELL_762NATO;
  225. if ( !Q_strcmp( BULLET_PLAYER_556MM, ammoname ) )
  226. return CS_SHELL_556;
  227. if ( !Q_strcmp( BULLET_PLAYER_338MAG, ammoname ) )
  228. return CS_SHELL_338MAG;
  229. if ( !Q_strcmp( BULLET_PLAYER_BUCKSHOT, ammoname ) )
  230. return CS_SHELL_12GAUGE;
  231. if ( !Q_strcmp( BULLET_PLAYER_57MM, ammoname ) )
  232. return CS_SHELL_57;
  233. // default 9 mm
  234. return CS_SHELL_9MM;
  235. }
  236. #endif
  237. // ----------------------------------------------------------------------------- //
  238. // CWeaponCSBase tables.
  239. // ----------------------------------------------------------------------------- //
  240. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCSBase, DT_WeaponCSBase )
  241. BEGIN_NETWORK_TABLE( CWeaponCSBase, DT_WeaponCSBase )
  242. #if !defined( CLIENT_DLL )
  243. SendPropInt( SENDINFO( m_weaponMode ), 1, SPROP_UNSIGNED ),
  244. SendPropFloat( SENDINFO( m_fAccuracyPenalty ), 0, SPROP_CHANGES_OFTEN ),
  245. SendPropFloat( SENDINFO( m_fLastShotTime ) ),
  246. //SendPropInt( SENDINFO( m_iRecoilIndex ) ), //DEPRECATED
  247. SendPropFloat( SENDINFO( m_flRecoilIndex ) ),
  248. // world weapon models have no aminations
  249. SendPropExclude( "DT_AnimTimeMustBeFirst", "m_flAnimTime" ),
  250. SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
  251. SendPropEHandle( SENDINFO( m_hPrevOwner ) ),
  252. SendPropBool( SENDINFO( m_bBurstMode ) ),
  253. SendPropTime( SENDINFO( m_flPostponeFireReadyTime ) ),
  254. SendPropBool( SENDINFO( m_bReloadVisuallyComplete ) ),
  255. // SendPropExclude( "DT_LocalActiveWeaponData", "m_flTimeWeaponIdle" ),
  256. SendPropBool( SENDINFO( m_bSilencerOn ) ),
  257. SendPropTime( SENDINFO( m_flDoneSwitchingSilencer ) ),
  258. SendPropInt( SENDINFO( m_iOriginalTeamNumber ) ),
  259. #if defined( WEAPON_FIRE_BULLETS_ACCURACY_FISHTAIL_FEATURE )
  260. SendPropFloat( SENDINFO( m_fAccuracyFishtail ) ),
  261. #endif
  262. #ifdef IRONSIGHT
  263. SendPropInt( SENDINFO( m_iIronSightMode ), 2, SPROP_UNSIGNED ),
  264. #endif //IRONSIGHT
  265. #else
  266. RecvPropInt( RECVINFO( m_weaponMode ) ),
  267. RecvPropFloat( RECVINFO( m_fAccuracyPenalty ) ),
  268. RecvPropFloat( RECVINFO( m_fLastShotTime ) ),
  269. RecvPropInt( RECVINFO( m_iRecoilIndex ) ), // DEPRECATED. Kept for old demo compatibility.
  270. RecvPropFloat( RECVINFO( m_flRecoilIndex ) ),
  271. RecvPropEHandle( RECVINFO( m_hPrevOwner ) ),
  272. RecvPropBool( RECVINFO( m_bBurstMode ) ),
  273. RecvPropTime( RECVINFO( m_flPostponeFireReadyTime ) ),
  274. RecvPropBool( RECVINFO( m_bReloadVisuallyComplete ) ),
  275. RecvPropBool( RECVINFO( m_bSilencerOn ) ),
  276. RecvPropTime( RECVINFO( m_flDoneSwitchingSilencer ) ),
  277. RecvPropInt( RECVINFO( m_iOriginalTeamNumber ) ),
  278. #if defined( WEAPON_FIRE_BULLETS_ACCURACY_FISHTAIL_FEATURE )
  279. RecvPropFloat( RECVINFO( m_fAccuracyFishtail ) ),
  280. #endif
  281. #ifdef IRONSIGHT
  282. RecvPropInt( RECVINFO( m_iIronSightMode ) ),
  283. #endif //IRONSIGHT
  284. #endif
  285. END_NETWORK_TABLE()
  286. #if defined( CLIENT_DLL )
  287. BEGIN_PREDICTION_DATA( CWeaponCSBase )
  288. DEFINE_PRED_FIELD( m_flTimeWeaponIdle, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
  289. DEFINE_PRED_FIELD( m_flNextPrimaryAttack, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
  290. DEFINE_PRED_FIELD( m_flNextSecondaryAttack, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
  291. DEFINE_PRED_FIELD( m_weaponMode, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  292. DEFINE_PRED_FIELD_TOL( m_fAccuracyPenalty, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
  293. #if defined( WEAPON_FIRE_BULLETS_ACCURACY_FISHTAIL_FEATURE )
  294. DEFINE_PRED_FIELD_TOL( m_fAccuracyFishtail, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
  295. #endif
  296. DEFINE_PRED_FIELD( m_fLastShotTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  297. DEFINE_PRED_FIELD( m_iRecoilIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  298. DEFINE_PRED_FIELD( m_flRecoilIndex, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  299. DEFINE_PRED_FIELD( m_bReloadVisuallyComplete, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  300. #ifdef IRONSIGHT
  301. DEFINE_PRED_FIELD( m_iIronSightMode, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  302. #endif
  303. DEFINE_PRED_FIELD( m_flPostponeFireReadyTime, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
  304. END_PREDICTION_DATA()
  305. #endif
  306. LINK_ENTITY_TO_CLASS_ALIASED( weapon_cs_base, WeaponCSBase );
  307. #ifdef GAME_DLL
  308. #define REMOVEUNOWNEDWEAPON_THINK_CONTEXT "WeaponCSBase_RemoveUnownedWeaponThink"
  309. #define REMOVEUNOWNEDWEAPON_THINK_INTERVAL 0.2
  310. #define REMOVEUNOWNEDWEAPON_THINK_REMOVE 3
  311. BEGIN_DATADESC( CWeaponCSBase )
  312. //DEFINE_FUNCTION( DefaultTouch ),
  313. DEFINE_THINKFUNC( FallThink ),
  314. DEFINE_THINKFUNC( RemoveUnownedWeaponThink ),
  315. DEFINE_KEYFIELD( m_bCanBePickedUp, FIELD_BOOLEAN, "CanBePickedUp" )
  316. END_DATADESC()
  317. #endif
  318. #if defined( CLIENT_DLL )
  319. ConVar cl_crosshairstyle( "cl_crosshairstyle", "2", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "0 = DEFAULT, 1 = DEFAULT STATIC, 2 = ACCURATE SPLIT (accurate recoil/spread feedback with a fixed inner part), 3 = ACCURATE DYNAMIC (accurate recoil/spread feedback), 4 = CLASSIC STATIC, 5 = OLD CS STYLE (fake recoil - inaccurate feedback)" );
  320. ConVar cl_crosshaircolor( "cl_crosshaircolor", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS, "Set crosshair color as defined in game_options.consoles.txt" );
  321. //ConVar cl_dynamiccrosshair( "cl_dynamiccrosshair", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  322. ConVar cl_scalecrosshair( "cl_scalecrosshair", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "Enable crosshair scaling (deprecated)" );
  323. ConVar cl_crosshairscale( "cl_crosshairscale", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "Crosshair scaling factor (deprecated)" );
  324. ConVar cl_crosshairalpha( "cl_crosshairalpha", "200", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  325. ConVar cl_crosshairusealpha( "cl_crosshairusealpha", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  326. ConVar cl_crosshairgap( "cl_crosshairgap", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  327. ConVar cl_crosshairgap_useweaponvalue( "cl_crosshairgap_useweaponvalue", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "If set to 1, the gap will update dynamically based on which weapon is currently equipped" );
  328. ConVar cl_crosshairsize( "cl_crosshairsize", "5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  329. ConVar cl_crosshairthickness( "cl_crosshairthickness", "0.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  330. ConVar cl_crosshairdot( "cl_crosshairdot", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  331. ConVar cl_crosshaircolor_r( "cl_crosshaircolor_r", "50", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  332. ConVar cl_crosshaircolor_g( "cl_crosshaircolor_g", "250", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  333. ConVar cl_crosshaircolor_b( "cl_crosshaircolor_b", "50", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS );
  334. ConVar weapon_debug_spread_show( "weapon_debug_spread_show", "0", FCVAR_CLIENTDLL | FCVAR_SS | FCVAR_CHEAT, "Enables display of weapon accuracy; 1: show accuracy box, 3: show accuracy with dynamic crosshair" );
  335. ConVar weapon_debug_spread_gap( "weapon_debug_spread_gap", "0.67", FCVAR_CLIENTDLL | FCVAR_SS | FCVAR_CHEAT );
  336. ConVar cl_crosshair_drawoutline( "cl_crosshair_drawoutline", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "Draws a black outline around the crosshair for better visibility" );
  337. ConVar cl_crosshair_outlinethickness( "cl_crosshair_outlinethickness", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "Set how thick you want your crosshair outline to draw (0.1-3)", true, 0.1, true, 3 );
  338. ConVar cl_crosshair_dynamic_splitdist("cl_crosshair_dynamic_splitdist", "7", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "If using cl_crosshairstyle 2, this is the distance that the crosshair pips will split into 2. (default is 7)"/*, true, 10, true, 3*/);
  339. ConVar cl_crosshair_dynamic_splitalpha_innermod("cl_crosshair_dynamic_splitalpha_innermod", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "If using cl_crosshairstyle 2, this is the alpha modification that will be used for the INNER crosshair pips once they've split. [0 - 1]", true, 0, true, 1);
  340. ConVar cl_crosshair_dynamic_splitalpha_outermod("cl_crosshair_dynamic_splitalpha_outermod", "0.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "If using cl_crosshairstyle 2, this is the alpha modification that will be used for the OUTER crosshair pips once they've split. [0.3 - 1]", true, 0.3, true, 1);
  341. ConVar cl_crosshair_dynamic_maxdist_splitratio("cl_crosshair_dynamic_maxdist_splitratio", "0.35", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS, "If using cl_crosshairstyle 2, this is the ratio used to determine how long the inner and outer xhair pips will be. [inner = cl_crosshairsize*(1-cl_crosshair_dynamic_maxdist_splitratio), outer = cl_crosshairsize*cl_crosshair_dynamic_maxdist_splitratio] [0 - 1]", true, 0, true, 1);
  342. void DrawCrosshairRect( int r, int g, int b, int a, int x0, int y0, int x1, int y1, bool bAdditive )
  343. {
  344. if ( cl_crosshair_drawoutline.GetBool() )
  345. {
  346. float flThick = cl_crosshair_outlinethickness.GetFloat();
  347. vgui::surface()->DrawSetColor( 0, 0, 0, a );
  348. vgui::surface()->DrawFilledRect( x0-flThick, y0-flThick, x1+flThick, y1+flThick );
  349. }
  350. vgui::surface()->DrawSetColor( r, g, b, a );
  351. if ( bAdditive )
  352. {
  353. vgui::surface()->DrawTexturedRect( x0, y0, x1, y1 );
  354. }
  355. else
  356. {
  357. // Alpha-blended crosshair
  358. vgui::surface()->DrawFilledRect( x0, y0, x1, y1 );
  359. }
  360. }
  361. #endif
  362. // must be included after the above macros
  363. #ifndef CLIENT_DLL
  364. #include "cs_bot.h"
  365. #endif
  366. // ----------------------------------------------------------------------------- //
  367. // CWeaponCSBase implementation.
  368. // ----------------------------------------------------------------------------- //
  369. CWeaponCSBase::CWeaponCSBase()
  370. #ifdef CLIENT_DLL
  371. : m_GlowObject( this, Vector( 1.0f, 1.0f, 1.0f ), 0.0f, false, false )
  372. #endif
  373. {
  374. m_nWeaponID = WEAPON_NONE;
  375. SetPredictionEligible( true );
  376. m_nextOwnerTouchTime = 0.0f;
  377. m_nextPrevOwnerTouchTime = 0.0f;
  378. m_hPrevOwner = NULL;
  379. AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches.
  380. m_bCanBePickedUp = true;
  381. m_fAccuracyPenalty = 0.0f;
  382. #if defined( WEAPON_FIRE_BULLETS_ACCURACY_FISHTAIL_FEATURE )
  383. m_fAccuracyFishtail = 0.0f;
  384. #endif
  385. m_fLastShotTime = 0.0f;
  386. m_weaponMode = Primary_Mode;
  387. m_fAccuracySmoothedForZoom = 0.0f;
  388. m_fScopeZoomEndTime = 0.0f;
  389. m_bBurstMode = false;
  390. ResetPostponeFireReadyTime();
  391. m_bWasOwnedByCT = false;
  392. m_bWasOwnedByTerrorist = false;
  393. #ifdef CLIENT_DLL
  394. m_bOldFirstPersonSpectatedState = false;
  395. // This will make it so the weapons get lit with the same ambient cube that the player gets lit with.
  396. SetUseParentLightingOrigin( true );
  397. m_iCrosshairTextureID = 0;
  398. m_flGunAccuracyPosition = 0;
  399. m_bVisualsDataSet = false;
  400. m_flLastClientFireBulletTime = 0;
  401. #else
  402. m_iDefaultExtraAmmo = 0;
  403. m_bFiredOutOfAmmoEvent = false;
  404. m_numRemoveUnownedWeaponThink = 0;
  405. #endif
  406. m_bReloadVisuallyComplete = false;
  407. m_bSilencerOn = false;
  408. m_flDoneSwitchingSilencer = 0.0f;
  409. m_iOriginalTeamNumber = 0;
  410. ResetGunHeat();
  411. #ifdef IRONSIGHT
  412. m_iIronSightMode = IronSight_should_approach_unsighted;
  413. m_IronSightController = NULL;
  414. UpdateIronSightController();
  415. #endif //IRONSIGHT
  416. }
  417. CWeaponCSBase::~CWeaponCSBase()
  418. {
  419. #ifdef IRONSIGHT
  420. delete m_IronSightController;
  421. m_IronSightController = NULL;
  422. #endif //IRONSIGHT
  423. #ifndef CLIENT_DLL
  424. if ( CSGameRules() )
  425. CSGameRules()->RemoveDroppedWeaponFromList( this );
  426. #endif
  427. }
  428. void CWeaponCSBase::ResetGunHeat()
  429. {
  430. #ifdef CLIENT_DLL
  431. m_gunHeat = 0.0f;
  432. m_smokeAttachments = 0x0;
  433. m_lastSmokeTime = 0.0f;
  434. #endif
  435. }
  436. #ifndef CLIENT_DLL
  437. bool CWeaponCSBase::KeyValue( const char *szKeyName, const char *szValue )
  438. {
  439. if ( !BaseClass::KeyValue( szKeyName, szValue ) )
  440. {
  441. if ( FStrEq( szKeyName, "ammo" ) )
  442. {
  443. int bullets = atoi( szValue );
  444. if ( bullets < 0 )
  445. return false;
  446. m_iDefaultExtraAmmo = bullets;
  447. return true;
  448. }
  449. }
  450. return false;
  451. }
  452. #endif
  453. bool CWeaponCSBase::IsPredicted() const
  454. {
  455. return true;
  456. }
  457. bool CWeaponCSBase::IsPistol() const
  458. {
  459. return GetWeaponType() == WEAPONTYPE_PISTOL;
  460. }
  461. bool CWeaponCSBase::PlayEmptySound()
  462. {
  463. //MIKETODO: certain weapons should override this to make it empty:
  464. // C4
  465. // Flashbang
  466. // HE Grenade
  467. // Smoke grenade
  468. CPASAttenuationFilter filter( this );
  469. filter.UsePredictionRules();
  470. if ( IsPistol() )
  471. {
  472. EmitSound( filter, entindex(), "Default.ClipEmpty_Pistol" );
  473. }
  474. else
  475. {
  476. EmitSound( filter, entindex(), "Default.ClipEmpty_Rifle" );
  477. }
  478. return 0;
  479. }
  480. const char *CWeaponCSBase::GetShootSound( int iIndex ) const
  481. {
  482. CEconItemView *pItem = ( (CWeaponCSBase *)this )->GetEconItemView();
  483. if ( pItem && pItem->IsValid() )
  484. {
  485. const char *pszSound = pItem->GetStaticData()->GetWeaponReplacementSound( (WeaponSound_t)iIndex );
  486. if ( pszSound )
  487. {
  488. return pszSound;
  489. }
  490. }
  491. return BaseClass::GetShootSound(iIndex);
  492. }
  493. const char *CWeaponCSBase::GetPlayerAnimationExtension( void ) const
  494. {
  495. CEconItemView *pItem = ( (CWeaponCSBase *)this )->GetEconItemView();
  496. if ( pItem && pItem->IsValid() )
  497. {
  498. return GetCSWpnData().GetPlayerAnimationExtension( pItem );
  499. }
  500. return GetCSWpnData().GetPlayerAnimationExtension();
  501. }
  502. const char *CWeaponCSBase::GetAddonModel( void ) const
  503. {
  504. CEconItemView *pItem = ( (CWeaponCSBase *)this )->GetEconItemView();
  505. if ( pItem && pItem->IsValid() )
  506. {
  507. return GetCSWpnData().GetAddonModel( pItem );
  508. }
  509. return GetCSWpnData().GetAddonModel();
  510. }
  511. CCSPlayer* CWeaponCSBase::GetPlayerOwner() const
  512. {
  513. return dynamic_cast< CCSPlayer* >( GetOwner() );
  514. }
  515. #ifdef CLIENT_DLL
  516. // -----------------------------------------------------------------------------
  517. // Purpose:
  518. // -----------------------------------------------------------------------------
  519. C_BaseEntity *CWeaponCSBase::GetWeaponForEffect()
  520. {
  521. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  522. if ( !pLocalPlayer )
  523. return NULL;
  524. bool bThird = false;
  525. FOR_EACH_VALID_SPLITSCREEN_PLAYER( nSlot )
  526. {
  527. if ( GetPlayerOwner()->GetPlayerRenderMode( nSlot ) == PLAYER_RENDER_THIRDPERSON )
  528. {
  529. bThird = true;
  530. }
  531. }
  532. if ( pLocalPlayer == GetPlayerOwner() && !bThird )
  533. return pLocalPlayer->GetViewModel();
  534. return this;
  535. }
  536. void CWeaponCSBase::UpdateOutlineGlow( void )
  537. {
  538. Vector glowColor;
  539. bool bRender = false;
  540. if ( !GetPlayerOwner() )
  541. {
  542. bool bRenderForSpectator = CanSeeSpectatorOnlyTools() && spec_show_xray.GetInt();
  543. if ( bRenderForSpectator && (GetWeaponType() == WEAPONTYPE_C4) )
  544. {
  545. glowColor.x = (240.0f/255.0f);
  546. glowColor.y = (225.0f/255.0f);
  547. glowColor.z = (90.0f/255.0f);
  548. bRender = true;
  549. }
  550. else if ( (m_iClip1 > 0 || m_iClip2 > 0) && mp_weapons_glow_on_ground.GetBool() )
  551. {
  552. glowColor.x = (224.0f/255.0f);
  553. glowColor.y = (224.0f/255.0f);
  554. glowColor.z = (224.0f/255.0f);
  555. bRender = true;
  556. }
  557. }
  558. // Start glowing
  559. m_GlowObject.SetRenderFlags( bRender, false );
  560. m_GlowObject.SetColor( glowColor );
  561. m_GlowObject.SetAlpha( bRender ? 0.8f : 0.0f );
  562. }
  563. #endif
  564. void CWeaponCSBase::AddToPriorOwnerList( CCSPlayer* pPlayer )
  565. {
  566. if ( !IsAPriorOwner( pPlayer ) )
  567. {
  568. // Add player to prior owner list
  569. m_PriorOwners.AddToTail( pPlayer );
  570. }
  571. }
  572. void CWeaponCSBase::AddPriorOwner( CCSPlayer* pPlayer )
  573. {
  574. if ( pPlayer )
  575. {
  576. if ( !IsAPriorOwner( pPlayer ) )
  577. AddToPriorOwnerList( pPlayer );
  578. // Assign the team that once owned this weapon
  579. if ( pPlayer->GetTeamNumber() == TEAM_CT )
  580. {
  581. m_bWasOwnedByCT = true;
  582. }
  583. else if ( pPlayer->GetTeamNumber() == TEAM_TERRORIST )
  584. {
  585. m_bWasOwnedByTerrorist = true;
  586. }
  587. }
  588. }
  589. bool CWeaponCSBase::WasOwnedByTeam( int teamNumber )
  590. {
  591. // Verify if the incoming team matches the team of a previous owner
  592. switch ( teamNumber )
  593. {
  594. case TEAM_CT:
  595. return m_bWasOwnedByCT;
  596. case TEAM_TERRORIST:
  597. return m_bWasOwnedByTerrorist;
  598. }
  599. return false;
  600. }
  601. bool CWeaponCSBase::IsAPriorOwner( CCSPlayer* pPlayer ) const
  602. {
  603. return ( m_PriorOwners.Find( pPlayer ) != -1 );
  604. }
  605. void CWeaponCSBase::SecondaryAttack( void )
  606. {
  607. #ifndef CLIENT_DLL
  608. CCSPlayer *pPlayer = GetPlayerOwner();
  609. if ( !pPlayer )
  610. return;
  611. if ( pPlayer->HasShield() == false )
  612. BaseClass::SecondaryAttack();
  613. else
  614. {
  615. pPlayer->SetShieldDrawnState( !pPlayer->IsShieldDrawn() );
  616. if ( pPlayer->IsShieldDrawn() )
  617. SendWeaponAnim( ACT_SHIELD_UP );
  618. else
  619. SendWeaponAnim( ACT_SHIELD_DOWN );
  620. m_flNextSecondaryAttack = gpGlobals->curtime + 0.4;
  621. m_flNextPrimaryAttack = gpGlobals->curtime + 0.4;
  622. }
  623. #endif
  624. }
  625. bool CWeaponCSBase::SendWeaponAnim( int iActivity )
  626. {
  627. #ifdef CS_SHIELD_ENABLED
  628. CCSPlayer *pPlayer = GetPlayerOwner();
  629. if ( pPlayer && pPlayer->HasShield() )
  630. {
  631. CBaseViewModel *vm = pPlayer->GetViewModel( 1 );
  632. if ( vm == NULL )
  633. return false;
  634. vm->SetWeaponModel( SHIELD_VIEW_MODEL, this );
  635. int idealSequence = vm->SelectWeightedSequence( ( Activity )iActivity );
  636. if ( idealSequence >= 0 )
  637. {
  638. vm->SendViewModelMatchingSequence( idealSequence );
  639. }
  640. }
  641. #endif
  642. return BaseClass::SendWeaponAnim( iActivity );
  643. }
  644. void CWeaponCSBase::SendViewModelAnim( int nSequence )
  645. {
  646. CCSPlayer *pPlayer = GetPlayerOwner();
  647. if ( !pPlayer || pPlayer->IsTaunting() || pPlayer->IsLookingAtWeapon() )
  648. return;
  649. CBaseViewModel *vm = pPlayer->GetViewModel( m_nViewModelIndex );
  650. if (vm)
  651. {
  652. bool bIsLookingAt = ( vm->GetSequence() != ACT_INVALID && V_stristr( vm->GetSequenceName(vm->GetSequence()), "lookat" ) );
  653. if ( vm->GetCycle() < 0.98f && bIsLookingAt && V_stristr( vm->GetSequenceName( nSequence ), "idle" ) )
  654. {
  655. // Don't switch from taunt to idle
  656. return;
  657. }
  658. #ifdef CLIENT_DLL
  659. if ( !bIsLookingAt )
  660. {
  661. //Fade down stat trak glow if we're doing anything other than inspecting
  662. vm->SetStatTrakGlowMultiplier( 0.0f );
  663. }
  664. #endif
  665. }
  666. BaseClass::SendViewModelAnim( nSequence );
  667. }
  668. // Common code put here to support separate zoom from silencer/burst
  669. void CWeaponCSBase::CallSecondaryAttack()
  670. {
  671. CCSPlayer *pPlayer = GetPlayerOwner();
  672. if ( !pPlayer )
  673. return;
  674. if ( m_iClip2 != -1 && !GetReserveAmmoCount( AMMO_POSITION_SECONDARY ) )
  675. {
  676. m_bFireOnEmpty = TRUE;
  677. }
  678. if ( pPlayer->HasShield() )
  679. CWeaponCSBase::SecondaryAttack();
  680. else
  681. SecondaryAttack();
  682. }
  683. void CWeaponCSBase::UpdateGunHeat( float heat, int iAttachmentIndex )
  684. {
  685. #ifdef CLIENT_DLL
  686. static const float SECONDS_FOR_COOL_DOWN = 2.0f;
  687. static const float MIN_TIME_BETWEEN_SMOKES = 4.0f;
  688. float currentShotTime = gpGlobals->curtime;
  689. float timeSinceLastShot = currentShotTime - m_fLastShotTime;
  690. // Drain off any heat from prior shots.
  691. m_gunHeat -= timeSinceLastShot * ( 1.0f/SECONDS_FOR_COOL_DOWN );
  692. if ( m_gunHeat <= 0.0f )
  693. {
  694. m_gunHeat = 0.0f;
  695. }
  696. // Add the new heat to the gun.
  697. m_gunHeat += heat;
  698. if ( m_gunHeat > 1.0f )
  699. {
  700. // Reset the heat so we have to build up to it again.
  701. m_gunHeat = 0.0f;
  702. m_smokeAttachments |= ( 0x1 << iAttachmentIndex );
  703. }
  704. // Logic for the gun smoke.
  705. if ( m_smokeAttachments != 0x0 )
  706. {
  707. // We don't want to hammer the smoke effect too much, so prevent smoke from spawning too soon after the last smoke.
  708. if ( currentShotTime - m_lastSmokeTime > MIN_TIME_BETWEEN_SMOKES )
  709. {
  710. const char *pszHeatEffect = GetCSWpnData().GetHeatEffectName();
  711. if ( pszHeatEffect && Q_strlen( pszHeatEffect ) > 0 )
  712. {
  713. static const int MAX_SMOKE_ATTACHMENT_INDEX = 16;
  714. for ( int i=0; i<MAX_SMOKE_ATTACHMENT_INDEX && m_smokeAttachments > 0x0; ++i )
  715. {
  716. int attachmentFlag = ( 0x1<<i );
  717. if ( ( attachmentFlag & m_smokeAttachments ) > 0x0 )
  718. {
  719. //Remove the attachment flag from the smoke attachments since we are firing it off.
  720. m_smokeAttachments = ( m_smokeAttachments & ( ~attachmentFlag ) );
  721. CCSPlayer *pPlayer = GetPlayerOwner();
  722. if ( pPlayer )
  723. {
  724. C_BaseViewModel *pViewModel = pPlayer->GetViewModel();
  725. if ( pViewModel )
  726. {
  727. // Dispatch this effect to the split screens that are rendering this first person view model.
  728. int nSlot = GetViewModelSplitScreenSlot( pViewModel );
  729. DispatchParticleEffect( pszHeatEffect, PATTACH_POINT_FOLLOW, pViewModel, i, false, nSlot );
  730. m_lastSmokeTime = currentShotTime;
  731. }
  732. }
  733. }
  734. }
  735. }
  736. //Reset the smoke attachments so that we can start doing a smoke effect for later shots.
  737. m_smokeAttachments = 0x0;
  738. }
  739. }
  740. #endif
  741. }
  742. void CWeaponCSBase::ItemPostFrame()
  743. {
  744. CCSPlayer *pPlayer = GetPlayerOwner();
  745. if ( !pPlayer )
  746. return;
  747. UpdateAccuracyPenalty();
  748. UpdateShieldState();
  749. if ( ( m_bInReload ) && ( pPlayer->m_flNextAttack <= gpGlobals->curtime ))
  750. {
  751. // the AE_WPN_COMPLETE_RELOAD event should handle the stocking the clip, but in case it's missing, we can do it here as well
  752. int j = MIN( GetMaxClip1() - m_iClip1, GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
  753. // Add them to the clip
  754. m_iClip1 += j;
  755. GiveReserveAmmo( AMMO_POSITION_PRIMARY, -j, true );
  756. m_bInReload = false;
  757. }
  758. if ( (pPlayer->m_nButtons & IN_ATTACK ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) )
  759. {
  760. ItemPostFrame_ProcessPrimaryAttack( pPlayer );
  761. }
  762. else if ( ( pPlayer->m_nButtons & IN_ZOOM ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ) )
  763. {
  764. if ( ItemPostFrame_ProcessZoomAction( pPlayer ) )
  765. pPlayer->m_nButtons &= ~IN_ZOOM;
  766. }
  767. else if ( (pPlayer->m_nButtons & IN_ATTACK2 ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ))
  768. {
  769. if ( ItemPostFrame_ProcessSecondaryAttack( pPlayer ) )
  770. pPlayer->m_nButtons &= ~IN_ATTACK2;
  771. }
  772. else if ( pPlayer->m_nButtons & IN_RELOAD && GetMaxClip1() != WEAPON_NOCLIP && !m_bInReload && m_flNextPrimaryAttack < gpGlobals->curtime )
  773. {
  774. ItemPostFrame_ProcessReloadAction( pPlayer );
  775. }
  776. else if ( !( pPlayer->m_nButtons & ( IN_ATTACK|IN_ATTACK2|IN_ZOOM ) ) )
  777. {
  778. ItemPostFrame_ProcessIdleNoAction( pPlayer );
  779. }
  780. }
  781. void CWeaponCSBase::ItemPostFrame_ProcessPrimaryAttack( CCSPlayer *pPlayer )
  782. {
  783. if ( ( m_iClip1 == 0 ) || ( GetMaxClip1() == -1 && !GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) ) )
  784. {
  785. m_bFireOnEmpty = TRUE;
  786. }
  787. if ( CSGameRules()->IsFreezePeriod() ) // Can't shoot during the freeze period
  788. return;
  789. if ( pPlayer->m_bIsDefusing )
  790. return;
  791. if ( pPlayer->State_Get() != STATE_ACTIVE )
  792. return;
  793. if ( pPlayer->IsShieldDrawn() )
  794. return;
  795. // don't repeat fire if this is not a full auto weapon or it's clip is empty
  796. if ( pPlayer->m_iShotsFired > 0 && ( !IsFullAuto() || m_iClip1 == 0 ) )
  797. return;
  798. // ignore attack if we're waiting for the attack button to be released
  799. if ( pPlayer->m_bWaitForNoAttack )
  800. return;
  801. if ( !CanPrimaryAttack() )
  802. return;
  803. if ( IsRevolver() ) // holding primary, will fire when time is elapsed
  804. {
  805. // don't allow a rapid fire shot instantly in the middle of a haul back hold, let the hammer return first
  806. m_flNextSecondaryAttack = gpGlobals->curtime + 0.25f;
  807. if ( GetActivity() != ACT_VM_HAULBACK )
  808. {
  809. ResetPostponeFireReadyTime();
  810. BaseClass::SendWeaponAnim( ACT_VM_HAULBACK );
  811. return;
  812. }
  813. m_weaponMode = Primary_Mode;
  814. if ( !IsPostponFireReadyTimeElapsed() )
  815. return;
  816. if ( m_bFireOnEmpty )
  817. {
  818. ResetPostponeFireReadyTime();
  819. m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;
  820. }
  821. // we're going to fire after this point
  822. }
  823. PrimaryAttack();
  824. m_fLastShotTime = gpGlobals->curtime;
  825. if ( IsRevolver() )
  826. {
  827. // we just fired.
  828. // there's a bit of a cool-off before you can alt-fire at normal alt-fire rate
  829. m_flNextSecondaryAttack = gpGlobals->curtime + ( GetCycleTime( Secondary_Mode ) * 1.7f );
  830. }
  831. }
  832. bool CWeaponCSBase::ItemPostFrame_ProcessZoomAction( CCSPlayer *pPlayer )
  833. {
  834. if ( IsRevolver() ) // Revolver treats zoom as secondary fire
  835. return ItemPostFrame_ProcessSecondaryAttack( pPlayer );
  836. if ( HasZoom() || IsKindOf( WEAPONTYPE_KNIFE ) )
  837. {
  838. CallSecondaryAttack();
  839. }
  840. return true;
  841. }
  842. bool CWeaponCSBase::ItemPostFrame_ProcessSecondaryAttack( CCSPlayer *pPlayer )
  843. {
  844. if ( IsRevolver() )
  845. {
  846. if ( CSGameRules()->IsFreezePeriod() ) // you can't fire the revolver in freezetime
  847. return false;
  848. if ( pPlayer->m_bIsDefusing )
  849. return false;
  850. if ( pPlayer->State_Get() != STATE_ACTIVE )
  851. return false;
  852. if ( ( m_iClip1 == 0 ) || ( GetMaxClip1() == -1 && !GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) ) )
  853. {
  854. m_bFireOnEmpty = TRUE;
  855. }
  856. m_weaponMode = Secondary_Mode;
  857. if ( !m_bFireOnEmpty )
  858. {
  859. ResetPostponeFireReadyTime();
  860. if ( GetActivity() == ACT_VM_HAULBACK )
  861. {
  862. BaseClass::SendWeaponAnim( ACT_VM_IDLE );
  863. return false;
  864. }
  865. }
  866. if ( pPlayer->m_iShotsFired > 0 ) // revolver secondary isn't full-auto even though primary is
  867. return false; // shots fired is zeroed when the buttons release
  868. if ( m_bFireOnEmpty )
  869. {
  870. if ( GetActivity() != ACT_VM_HAULBACK )
  871. {
  872. ResetPostponeFireReadyTime();
  873. BaseClass::SendWeaponAnim( ACT_VM_HAULBACK );
  874. return false;
  875. }
  876. if ( !IsPostponFireReadyTimeElapsed() )
  877. return false;
  878. }
  879. }
  880. CallSecondaryAttack();
  881. return true;
  882. }
  883. void CWeaponCSBase::ItemPostFrame_ProcessReloadAction( CCSPlayer *pPlayer )
  884. {
  885. // reload when reload is pressed, or if no buttons are down and weapon is empty.
  886. //MIKETODO: add code for shields...
  887. //if ( !FBitSet( m_iWeaponState, WPNSTATE_SHIELD_DRAWN ) )
  888. ItemPostFrame_RevolverResetHaulback();
  889. if ( !pPlayer->IsShieldDrawn() )
  890. {
  891. if ( Reload() )
  892. {
  893. #ifndef CLIENT_DLL
  894. // allow the bots to react to the reload
  895. pPlayer->SetHasReloaded();
  896. IGameEvent * event = gameeventmanager->CreateEvent( "weapon_reload" );
  897. if ( event )
  898. {
  899. event->SetInt( "userid", pPlayer->GetUserID() );
  900. gameeventmanager->FireEvent( event );
  901. }
  902. #endif
  903. }
  904. }
  905. }
  906. void CWeaponCSBase::ItemPostFrame_ProcessIdleNoAction( CCSPlayer *pPlayer )
  907. {
  908. ItemPostFrame_RevolverResetHaulback();
  909. // no fire buttons down
  910. m_bFireOnEmpty = FALSE;
  911. // we can fire after this
  912. pPlayer->m_bWaitForNoAttack = false;
  913. // set the shots fired to 0 after the player releases a button
  914. pPlayer->m_iShotsFired = 0;
  915. #ifndef CLIENT_DLL
  916. if ( CSGameRules() && CSGameRules()->IsPlayingTraining() )
  917. {
  918. if ( !m_bFiredOutOfAmmoEvent && m_iClip1 == 0 && !m_bInReload && !pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) )
  919. {
  920. IGameEvent * event = gameeventmanager->CreateEvent( "weapon_outofammo" );
  921. if ( event )
  922. {
  923. m_bFiredOutOfAmmoEvent = true;
  924. event->SetInt( "userid", pPlayer->GetUserID() );
  925. gameeventmanager->FireEvent( event );
  926. }
  927. }
  928. }
  929. #endif
  930. if ( gpGlobals->curtime > m_flNextPrimaryAttack && m_iClip1 == 0 && IsUseable() && !( GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD ) && !m_bInReload )
  931. {
  932. // Reload if current clip is empty and weapon has waited as long as it has to after firing
  933. Reload();
  934. #ifndef CLIENT_DLL
  935. pPlayer->SetHasReloaded();
  936. #endif
  937. return;
  938. }
  939. #ifdef IRONSIGHT
  940. UpdateIronSightController();
  941. if ( m_iIronSightMode == IronSight_viewmodel_is_deploying && GetActivity() != GetDeployActivity() )
  942. {
  943. m_iIronSightMode = IronSight_should_approach_unsighted;
  944. }
  945. #endif
  946. WeaponIdle();
  947. }
  948. void CWeaponCSBase::ItemPostFrame_RevolverResetHaulback()
  949. {
  950. if ( IsRevolver() ) // not holding any weapon buttons
  951. {
  952. m_weaponMode = Secondary_Mode;
  953. ResetPostponeFireReadyTime();
  954. if ( GetActivity() == ACT_VM_HAULBACK )
  955. {
  956. BaseClass::SendWeaponAnim( ACT_VM_IDLE );
  957. }
  958. }
  959. }
  960. void CWeaponCSBase::ItemBusyFrame()
  961. {
  962. UpdateAccuracyPenalty();
  963. CCSPlayer *pPlayer = GetPlayerOwner();
  964. if ( pPlayer && !( pPlayer->m_nButtons & ( IN_ATTACK|IN_ATTACK2|IN_ZOOM ) ) )
  965. {
  966. // we can fire after this
  967. pPlayer->m_bWaitForNoAttack = false;
  968. }
  969. BaseClass::ItemBusyFrame();
  970. }
  971. float CWeaponCSBase::GetInaccuracy() const
  972. {
  973. CCSPlayer *pPlayer = GetPlayerOwner();
  974. if ( !pPlayer )
  975. return 0.0f;
  976. if ( weapon_accuracy_nospread.GetBool() )
  977. return 0.0f;
  978. const CCSWeaponInfo& weaponInfo = GetCSWpnData();
  979. float fMaxSpeed = GetMaxSpeed();
  980. if ( fMaxSpeed == 0.0f )
  981. fMaxSpeed = GetCSWpnData().GetMaxSpeed( GetEconItemView(), 0 );
  982. float fAccuracy = m_fAccuracyPenalty;
  983. // CS-PRO TEST FEATURE
  984. // Adding movement penalty here results in an instaneous penalty that doesn't persist.
  985. #if !MOVEMENT_ACCURACY_DECAYED
  986. float flVerticalSpeed = abs( pPlayer->GetAbsVelocity().z );
  987. float flMovementInaccuracyScale = RemapValClamped(pPlayer->GetAbsVelocity().Length2D(),
  988. fMaxSpeed * CS_PLAYER_SPEED_DUCK_MODIFIER,
  989. fMaxSpeed * 0.95f, // max out at 95% of run speed to avoid jitter near max speed
  990. 0.0f, 1.0f );
  991. if ( flMovementInaccuracyScale > 0.0f )
  992. {
  993. // power curve only applies at speeds greater than walk
  994. if (( MP_WEAPON_ACCURACY_SEPARATE_WALK_FUNCTION ) && ( pPlayer->m_bIsWalking ) )
  995. {
  996. //flMovementInaccuracyScale *= 1.0; // reduce inaccuracy when walking or slower. This is commented out because at 1.0, it's a noop but preserved in case a different value is desired.
  997. //flMovementInaccuracyScale = powf( flMovementInaccuracyScale, float( MOVEMENT_WALK_CURVE01_EXPONENT ) );
  998. }
  999. else
  1000. {
  1001. flMovementInaccuracyScale = powf( flMovementInaccuracyScale, float( MOVEMENT_CURVE01_EXPONENT ));
  1002. }
  1003. fAccuracy += flMovementInaccuracyScale * weaponInfo.GetInaccuracyMove( GetEconItemView(), m_weaponMode );
  1004. }
  1005. // If we are in the air/on ladder, add inaccuracy based on vertical speed (maximum accuracy at apex of jump)
  1006. if ( pPlayer->GetGroundEntity() == nullptr )
  1007. {
  1008. float flInaccuracyJumpInitial = weaponInfo.GetInaccuracyJumpInitial( GetEconItemView() ) * weapon_air_spread_scale.GetFloat();
  1009. static const float kMaxFallingPenalty = 2.0f; // Accuracy is never worse than 2x starting penalty
  1010. // Use sqrt here to make the curve more "sudden" around the accurate point at the apex of the jump
  1011. float fSqrtMaxJumpSpeed = sqrtf( sv_jump_impulse.GetFloat() );
  1012. float fSqrtVerticalSpeed = sqrtf( flVerticalSpeed );
  1013. float flAirSpeedInaccuracy = RemapVal( fSqrtVerticalSpeed,
  1014. fSqrtMaxJumpSpeed * 0.25f, // Anything less than 6.25% of maximum speed has no additional accuracy penalty for z-motion (6.25% = .25 * .25)
  1015. fSqrtMaxJumpSpeed, // Penalty at max jump speed
  1016. 0.0f, // No movement-related penalty when close to stopped
  1017. flInaccuracyJumpInitial ); // Movement-penalty at start of jump
  1018. // Clamp to min/max values. (Don't use RemapValClamped because it makes clamping to > kJumpMovePenalty hard)
  1019. if ( flAirSpeedInaccuracy < 0 )
  1020. flAirSpeedInaccuracy = 0;
  1021. else if ( flAirSpeedInaccuracy > ( kMaxFallingPenalty * flInaccuracyJumpInitial ) )
  1022. flAirSpeedInaccuracy = kMaxFallingPenalty * flInaccuracyJumpInitial;
  1023. // Apply air velocity inaccuracy penalty
  1024. // (There is an additional penalty for being in the air at all applied in UpdateAccuracyPenalty())
  1025. fAccuracy += flAirSpeedInaccuracy;
  1026. }
  1027. #endif // !MOVEMENT_ACCURACY_DECAYED
  1028. if ( fAccuracy > 1.0f )
  1029. fAccuracy = 1.0f;
  1030. return fAccuracy;
  1031. }
  1032. int CWeaponCSBase::GetRecoilSeed( void ) const
  1033. {
  1034. CEconItemView *pItem = ( (CWeaponCSBase *)this )->GetEconItemView();
  1035. if ( pItem->IsValid() )
  1036. {
  1037. return GetCSWpnData().GetRecoilSeed( pItem );
  1038. }
  1039. return GetCSWpnData().GetRecoilSeed();
  1040. }
  1041. const CCSWeaponInfo &CWeaponCSBase::GetCSWpnData() const
  1042. {
  1043. // If we don't have a weapon file the below code will do a bogus cast.
  1044. // There is a ton of code that assumes this function can't fail so if somebody
  1045. // is bored they can do a massive find/replace and allow this function to return null.
  1046. // For now, just crash now instead of creating a time bomb for later.
  1047. if ( GetWeaponFileInfoHandle() == GetInvalidWeaponInfoHandle() )
  1048. {
  1049. CFmtStr outputStr( "Weapon '%s' script file not found, but its data was accessed. This error is fatal.\n", GetName() ? GetName() : "<unknown>" );
  1050. AssertFatalMsg( 0, outputStr.Access() );
  1051. }
  1052. const FileWeaponInfo_t *pWeaponInfo = &GetWpnData();
  1053. const CCSWeaponInfo *pCSInfo = assert_cast< const CCSWeaponInfo* >( pWeaponInfo );
  1054. return *pCSInfo;
  1055. }
  1056. //-----------------------------------------------------------------------------
  1057. // Purpose:
  1058. //-----------------------------------------------------------------------------
  1059. const char *CWeaponCSBase::GetViewModel( int /*viewmodelindex = 0 -- this is ignored in the base class here*/ ) const
  1060. {
  1061. CCSPlayer *pOwner = GetPlayerOwner();
  1062. if ( pOwner == NULL )
  1063. {
  1064. return BaseClass::GetViewModel();
  1065. }
  1066. if ( pOwner->HasShield() && CanBeUsedWithShield() )
  1067. return GetShieldViewModel();
  1068. else
  1069. return BaseClass::GetViewModel();
  1070. }
  1071. // bool CWeaponCSBase::AllowTaunts( void )
  1072. // {
  1073. // //return true; // hack: all weapons can taunt for now
  1074. // return CALL_ATTRIB_HOOK_BOOL( taunt_id );
  1075. // }
  1076. void CWeaponCSBase::Precache( void )
  1077. {
  1078. BaseClass::Precache();
  1079. #ifdef CS_SHIELD_ENABLED
  1080. if ( CanBeUsedWithShield() )
  1081. {
  1082. PrecacheModel( GetShieldViewModel() );
  1083. }
  1084. #endif
  1085. if ( GetSilencerModel()[0] != 0 )
  1086. {
  1087. PrecacheModel( GetSilencerModel() );
  1088. }
  1089. PrecacheScriptSound( "Default.ClipEmpty_Pistol" );
  1090. PrecacheScriptSound( "Default.ClipEmpty_Rifle" );
  1091. if ( GetZoomInSound() && GetZoomInSound()[0] )
  1092. {
  1093. PrecacheScriptSound( GetZoomInSound() );
  1094. }
  1095. if ( GetZoomOutSound() && GetZoomOutSound()[0] )
  1096. {
  1097. PrecacheScriptSound( GetZoomOutSound() );
  1098. }
  1099. const char *pMuzzleFlashEffectName_1stPerson = GetCSWpnData().GetMuzzleFlashEffectName_1stPerson( GetEconItemView() );
  1100. if ( pMuzzleFlashEffectName_1stPerson && pMuzzleFlashEffectName_1stPerson[0] )
  1101. {
  1102. PrecacheEffect( pMuzzleFlashEffectName_1stPerson );
  1103. }
  1104. const char *pMuzzleFlashEffectName_1stPersonAlt = GetCSWpnData().GetMuzzleFlashEffectName_1stPersonAlt( GetEconItemView() );
  1105. if ( pMuzzleFlashEffectName_1stPersonAlt && pMuzzleFlashEffectName_1stPersonAlt[0] )
  1106. {
  1107. PrecacheEffect( pMuzzleFlashEffectName_1stPersonAlt );
  1108. }
  1109. const char *pMuzzleFlashEffectName_3rdPerson = GetCSWpnData().GetMuzzleFlashEffectName_3rdPerson( GetEconItemView() );
  1110. if ( pMuzzleFlashEffectName_3rdPerson && pMuzzleFlashEffectName_3rdPerson[0] )
  1111. {
  1112. PrecacheEffect( pMuzzleFlashEffectName_3rdPerson );
  1113. }
  1114. const char *pMuzzleFlashEffectName_3rdPersonAlt = GetCSWpnData().GetMuzzleFlashEffectName_3rdPersonAlt( GetEconItemView() );
  1115. if ( pMuzzleFlashEffectName_3rdPersonAlt && pMuzzleFlashEffectName_3rdPersonAlt[0] )
  1116. {
  1117. PrecacheEffect( pMuzzleFlashEffectName_3rdPersonAlt );
  1118. }
  1119. const char *pEjectBrassEffectName = GetCSWpnData().GetEjectBrassEffectName( GetEconItemView() );
  1120. if ( pEjectBrassEffectName && pEjectBrassEffectName[0] )
  1121. {
  1122. PrecacheEffect( pEjectBrassEffectName );
  1123. }
  1124. const char *pHeatEffectName = GetCSWpnData().GetHeatEffectName( GetEconItemView() );
  1125. if ( pHeatEffectName && pHeatEffectName[0] )
  1126. {
  1127. PrecacheEffect( pHeatEffectName );
  1128. }
  1129. PrecacheEffect( "gunshotsplash" );
  1130. }
  1131. Activity CWeaponCSBase::GetDeployActivity( void )
  1132. {
  1133. CBaseCombatCharacter *pOwner = GetOwner();
  1134. if (pOwner)
  1135. {
  1136. if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0 && LookupActivity( "ACT_VM_EMPTY_DRAW" ) > 0 )
  1137. {
  1138. return ACT_VM_EMPTY_DRAW;
  1139. }
  1140. }
  1141. return ACT_VM_DRAW;
  1142. }
  1143. bool CWeaponCSBase::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt )
  1144. {
  1145. // Msg( "deploy %s at %f\n", GetClassname(), gpGlobals->curtime );
  1146. CCSPlayer *pOwner = GetPlayerOwner();
  1147. if ( !pOwner )
  1148. {
  1149. return false;
  1150. }
  1151. pOwner->SetAnimationExtension( szAnimExt );
  1152. SetViewModel();
  1153. SendWeaponAnim( GetDeployActivity() );
  1154. pOwner->SetNextAttack( gpGlobals->curtime + SequenceDuration() );
  1155. m_flNextPrimaryAttack = gpGlobals->curtime;
  1156. m_flNextSecondaryAttack = gpGlobals->curtime;
  1157. SetWeaponVisible( true );
  1158. pOwner->SetShieldDrawnState( false );
  1159. if ( pOwner->HasShield() == true )
  1160. SetWeaponModelIndex( SHIELD_WORLD_MODEL );
  1161. else
  1162. SetWeaponModelIndex( szWeaponModel );
  1163. //#ifndef CLIENT_DLL
  1164. // SetWeaponModules();
  1165. //#endif
  1166. #ifdef IRONSIGHT
  1167. m_iIronSightMode = IronSight_viewmodel_is_deploying;
  1168. #endif //IRONSIGHT
  1169. return true;
  1170. }
  1171. void CWeaponCSBase::UpdateShieldState( void )
  1172. {
  1173. //empty by default.
  1174. CCSPlayer *pOwner = GetPlayerOwner();
  1175. if ( pOwner == NULL )
  1176. return;
  1177. //ADRIANTODO
  1178. //Make the hitbox set switches here!!!
  1179. if ( pOwner->HasShield() == false )
  1180. {
  1181. pOwner->SetShieldDrawnState( false );
  1182. //pOwner->SetHitBoxSet( 0 );
  1183. return;
  1184. }
  1185. else
  1186. {
  1187. //pOwner->SetHitBoxSet( 1 );
  1188. }
  1189. }
  1190. void CWeaponCSBase::SetWeaponModelIndex( const char *pName )
  1191. {
  1192. m_iWorldModelIndex = modelinfo->GetModelIndex( pName );
  1193. }
  1194. bool CWeaponCSBase::CanBeSelected( void )
  1195. {
  1196. if ( !VisibleInWeaponSelection() )
  1197. return false;
  1198. return true;
  1199. }
  1200. bool CWeaponCSBase::CanDeploy( void )
  1201. {
  1202. CCSPlayer *pPlayer = GetPlayerOwner();
  1203. if ( !pPlayer )
  1204. return false;
  1205. if ( pPlayer->HasShield() && CanBeUsedWithShield() == false )
  1206. return false;
  1207. return BaseClass::CanDeploy();
  1208. }
  1209. float CWeaponCSBase::CalculateNextAttackTime( float fCycleTime )
  1210. {
  1211. float fCurAttack = m_flNextPrimaryAttack;
  1212. float fDeltaAttack = gpGlobals->curtime - fCurAttack;
  1213. if ( fDeltaAttack < 0 || fDeltaAttack > gpGlobals->interval_per_tick )
  1214. {
  1215. fCurAttack = gpGlobals->curtime;
  1216. }
  1217. m_flNextSecondaryAttack = m_flNextPrimaryAttack = fCurAttack + fCycleTime;
  1218. return fCurAttack;
  1219. }
  1220. bool CWeaponCSBase::Holster( CBaseCombatWeapon *pSwitchingTo )
  1221. {
  1222. CCSPlayer *pPlayer = GetPlayerOwner();
  1223. if ( !pPlayer )
  1224. return false;
  1225. if ( pPlayer )
  1226. pPlayer->SetFOV( pPlayer, 0, 0.0f ); // reset the default FOV.
  1227. if ( pPlayer )
  1228. pPlayer->SetShieldDrawnState( false );
  1229. ResetGunHeat();
  1230. return BaseClass::Holster( pSwitchingTo );
  1231. }
  1232. bool CWeaponCSBase::Deploy()
  1233. {
  1234. #ifdef IRONSIGHT
  1235. if ( GetIronSightController() )
  1236. GetIronSightController()->SetState( IronSight_viewmodel_is_deploying );
  1237. #endif //IRONSIGHT
  1238. #ifdef CLIENT_DLL
  1239. m_iAlpha = 80;
  1240. if ( cl_crosshairstyle.GetInt() == 4 || cl_crosshairstyle.GetInt() == 5 )
  1241. m_flCrosshairDistance = 1;
  1242. // Stop glowing
  1243. //if ( m_nGlowIndex != -1 )
  1244. //{
  1245. // g_GlowObjectManager.UnregisterGlowObject( m_nGlowIndex );
  1246. // m_nGlowIndex = -1;
  1247. //}
  1248. #endif
  1249. CCSPlayer *pPlayer = GetPlayerOwner();
  1250. if ( pPlayer )
  1251. {
  1252. pPlayer->m_iShotsFired = 0;
  1253. pPlayer->m_bResumeZoom = false;
  1254. pPlayer->m_bIsScoped = false;
  1255. pPlayer->SetFOV( pPlayer, 0 );
  1256. pPlayer->m_bWaitForNoAttack = true;
  1257. }
  1258. m_fAccuracyPenalty = 0.0f;
  1259. #if defined( WEAPON_FIRE_BULLETS_ACCURACY_FISHTAIL_FEATURE )
  1260. m_fAccuracyFishtail = 0.0f;
  1261. #endif
  1262. // m_iRecoilIndex = 0; DEPRECATED
  1263. m_flRecoilIndex = 0.0f;
  1264. ResetGunHeat();
  1265. return BaseClass::Deploy();
  1266. }
  1267. #ifndef CLIENT_DLL
  1268. bool CWeaponCSBase::IsRemoveable()
  1269. {
  1270. if ( BaseClass::IsRemoveable() == true )
  1271. {
  1272. if ( m_nextPrevOwnerTouchTime > gpGlobals->curtime || m_nextOwnerTouchTime > gpGlobals->curtime )
  1273. {
  1274. return false;
  1275. }
  1276. }
  1277. // currently held or never had an owner (level designer placed)
  1278. if ( GetOwner() || !m_hPrevOwner.m_Value.IsValid() )
  1279. return false;
  1280. return BaseClass::IsRemoveable();
  1281. }
  1282. void CWeaponCSBase::RemoveUnownedWeaponThink()
  1283. {
  1284. // Keep thinking in case we need to remove ourselves
  1285. SetContextThink( &CWeaponCSBase::RemoveUnownedWeaponThink, gpGlobals->curtime + REMOVEUNOWNEDWEAPON_THINK_INTERVAL, REMOVEUNOWNEDWEAPON_THINK_CONTEXT );
  1286. if ( GetOwner() ) // owned weapons don't get deleted, reset counter
  1287. {
  1288. if ( m_numRemoveUnownedWeaponThink )
  1289. {
  1290. m_numRemoveUnownedWeaponThink = 0;
  1291. }
  1292. return;
  1293. }
  1294. if ( weapon_auto_cleanup_time.GetFloat() > 0 )
  1295. {
  1296. if ( !GetGroundEntity() )
  1297. return; // gun is falling, and might land near a player - don't remove until we're on the ground
  1298. float flSpawnTime = m_nextOwnerTouchTime;
  1299. // if ( m_nextOwnerTouchTime > flSpawnTime )
  1300. // flSpawnTime = m_nextOwnerTouchTime;
  1301. float flTime = weapon_auto_cleanup_time.GetFloat();
  1302. // check if it's out of ammo, if so clean it up super quick
  1303. if ( m_iClip1 == 0 )
  1304. flTime = MIN( 5, flTime ) ;
  1305. if ( flSpawnTime > 0 && (gpGlobals->curtime - flSpawnTime) < flTime )
  1306. return;
  1307. // check to see if any players are close
  1308. for ( int i = 1; i <= MAX_PLAYERS; i++ )
  1309. {
  1310. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  1311. if ( !pPlayer )
  1312. continue;
  1313. if ( (GetAbsOrigin() - pPlayer->GetAbsOrigin()).Length() < 1200 )
  1314. return;
  1315. }
  1316. }
  1317. else if ( m_numRemoveUnownedWeaponThink <= REMOVEUNOWNEDWEAPON_THINK_REMOVE )
  1318. {
  1319. ++ m_numRemoveUnownedWeaponThink;
  1320. return; // let the server think a few frames while the owner might acquire this weapon
  1321. }
  1322. // Schedule this weapon to be removed
  1323. UTIL_Remove( this );
  1324. }
  1325. #endif
  1326. ConVar mp_weapon_prev_owner_touch_time( "mp_weapon_prev_owner_touch_time", "1.5", FCVAR_CHEAT | FCVAR_REPLICATED );
  1327. #if defined ( CLIENT_DLL )
  1328. CEG_NOINLINE void CWeaponCSBase::Drop( const Vector &vecVelocity )
  1329. #else
  1330. void CWeaponCSBase::Drop( const Vector &vecVelocity )
  1331. #endif
  1332. {
  1333. #ifdef CLIENT_DLL
  1334. CEG_PROTECT_VIRTUAL_FUNCTION( CWeaponCSBase_Drop );
  1335. BaseClass::Drop( vecVelocity );
  1336. CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
  1337. if ( pHudSelection )
  1338. {
  1339. pHudSelection->OnWeaponDrop( this );
  1340. }
  1341. UpdateOutlineGlow();
  1342. return;
  1343. #else
  1344. // Once somebody drops a gun, it's fair game for removal when/if
  1345. // a game_weapon_manager does a cleanup on surplus weapons in the
  1346. // world.
  1347. SetRemoveable( true );
  1348. StopAnimation();
  1349. StopFollowingEntity( );
  1350. SetMoveType( MOVETYPE_FLYGRAVITY );
  1351. // clear follow stuff, setup for collision
  1352. SetGravity( 1.0 );
  1353. m_iState = WEAPON_NOT_CARRIED;
  1354. RemoveEffects( EF_NODRAW );
  1355. SetGroundEntity( NULL );
  1356. m_bInReload = false; // stop reloading
  1357. m_bReloadVisuallyComplete = false;
  1358. SetThink( NULL );
  1359. m_nextPrevOwnerTouchTime = gpGlobals->curtime + mp_weapon_prev_owner_touch_time.GetFloat();
  1360. // [msmith] There is an issue where the model index does not get updated on the client if we let a player
  1361. // pick up a weapon in the same frame that it is thrown down by a different player.
  1362. // The m_nextOwnerTouchTime delay fixes that.
  1363. m_nextOwnerTouchTime = gpGlobals->curtime + 0.1f;
  1364. m_hPrevOwner = GetPlayerOwner();
  1365. SetOwnerEntity( NULL );
  1366. SetOwner( NULL );
  1367. VerifyAndSetContextSensitiveWeaponModel();
  1368. FallInit();
  1369. if ( CSGameRules()->IsPlayingGunGameProgressive() || CSGameRules()->IsPlayingGunGameTRBomb() )
  1370. {
  1371. // Don't allow non-c4 weapon pickups in gun game progressive mode
  1372. if ( !IsA( WEAPON_C4 ) )
  1373. {
  1374. SetTouch( NULL );
  1375. }
  1376. else
  1377. {
  1378. SetTouch( &CWeaponCSBase::DefaultTouch );
  1379. }
  1380. }
  1381. else
  1382. {
  1383. SetTouch( &CWeaponCSBase::DefaultTouch );
  1384. }
  1385. IPhysicsObject *pObj = VPhysicsGetObject();
  1386. if ( pObj != NULL )
  1387. {
  1388. AngularImpulse angImp( 100, 100, 100 );
  1389. pObj->AddVelocity( &vecVelocity, &angImp );
  1390. }
  1391. else
  1392. {
  1393. SetAbsVelocity( vecVelocity );
  1394. }
  1395. SetNextThink( gpGlobals->curtime );
  1396. // add it to the list of dropped weapons
  1397. if ( CSGameRules() )
  1398. CSGameRules()->AddDroppedWeaponToList( this );
  1399. #ifdef IRONSIGHT
  1400. if ( GetIronSightController() )
  1401. GetIronSightController()->SetState( IronSight_weapon_is_dropped );
  1402. #endif
  1403. #endif
  1404. }
  1405. // whats going on here is that if the player drops this weapon, they shouldn't take it back themselves
  1406. // for a little while. But if they throw it at someone else, the other player should get it immediately.
  1407. void CWeaponCSBase::DefaultTouch( CBaseEntity *pOther )
  1408. {
  1409. if ( m_bCanBePickedUp == false )
  1410. return;
  1411. if ( pOther->GetFlags() & FL_CONVEYOR )
  1412. {
  1413. pOther->StartTouch( this );
  1414. }
  1415. // Add a small delay in general so the networking has a chance to update the values on the client side before someone
  1416. // picks up the weapon.
  1417. if ( gpGlobals->curtime < m_nextOwnerTouchTime )
  1418. {
  1419. return;
  1420. }
  1421. if ( ( m_hPrevOwner != NULL ) && ( pOther == m_hPrevOwner ) && ( gpGlobals->curtime < m_nextPrevOwnerTouchTime ) )
  1422. {
  1423. return;
  1424. }
  1425. BaseClass::DefaultTouch( pOther );
  1426. }
  1427. #if defined( CLIENT_DLL )
  1428. //-----------------------------------------------------------------------------
  1429. // Purpose: Draw the weapon's crosshair
  1430. //-----------------------------------------------------------------------------
  1431. int CWeaponCSBase::GetReticleWeaponSpread( void )
  1432. {
  1433. int result = 0;
  1434. CCSPlayer* pPlayer = ( CCSPlayer* )C_BasePlayer::GetLocalPlayer();
  1435. if ( pPlayer )
  1436. {
  1437. if ( GetWeaponType() == WEAPONTYPE_GRENADE || GetCSWeaponID() == WEAPON_C4 || GetCSWeaponID() == WEAPON_KNIFE || GetCSWeaponID() == WEAPON_KNIFE_GG )
  1438. {
  1439. return -1; //early out since we don't want a gap and don't want to change the sentinel value with the math later.
  1440. }
  1441. float fHalfFov = DEG2RAD( pPlayer->GetFOV() ) * 0.5f;
  1442. float fSpreadDistance = ( GetInaccuracy() + GetSpread() ) * 320.0f / tanf( fHalfFov );
  1443. result = RoundFloatToInt( YRES( fSpreadDistance ));
  1444. }
  1445. return result;
  1446. }
  1447. int CWeaponCSBase::GetReticleCrosshairGap( void )
  1448. {
  1449. int result = 0;
  1450. CCSPlayer* pPlayer = ( CCSPlayer* )C_BasePlayer::GetLocalPlayer();
  1451. if ( pPlayer )
  1452. {
  1453. int crosshairGap;
  1454. if ( !( pPlayer->GetFlags() & FL_ONGROUND ) )
  1455. crosshairGap = 30;
  1456. else if ( pPlayer->GetFlags() & FL_DUCKING )
  1457. crosshairGap = 3;
  1458. else if ( pPlayer->GetAbsVelocity().Length() > 100 )
  1459. crosshairGap = 20;
  1460. else
  1461. crosshairGap = 10;
  1462. result = ScreenHeight() * crosshairGap / 768;
  1463. }
  1464. return result;
  1465. }
  1466. bool CWeaponCSBase::WantReticleShown( void )
  1467. {
  1468. CCSPlayer* pPlayer = ( CCSPlayer* )C_BasePlayer::GetLocalPlayer();
  1469. if ( !pPlayer )
  1470. return false;
  1471. if ( pPlayer->HasShield() && pPlayer->IsShieldDrawn() == true )
  1472. return false;
  1473. bool isAKnife = ( GetWeaponType() == WEAPONTYPE_KNIFE && !IsA( WEAPON_TASER ) );
  1474. #ifdef CLIENT_DLL
  1475. bool isUsingMotionController = PlatformInputDevice::IsInputDeviceAPointer( g_pInputSystem->GetCurrentInputDevice() );
  1476. #else
  1477. bool isUsingMotionController = PlatformInputDevice::IsInputDeviceAPointer( GetPlayerInputDevice() );
  1478. #endif
  1479. // we hide the sniper Reticle UNLESS we're using a motion controller AND we're not zoomed
  1480. bool hideSniperReticle = GetWeaponType() == WEAPONTYPE_SNIPER_RIFLE &&
  1481. (pPlayer->m_bIsScoped || !isUsingMotionController);
  1482. // no crosshair for sniper rifles
  1483. if ( hideSniperReticle ||
  1484. ( GetWeaponType() == WEAPONTYPE_C4 ) ||
  1485. ( isAKnife && !weapon_reticle_knife_show.GetBool() ) )
  1486. return false;
  1487. return true;
  1488. }
  1489. #ifdef CLIENT_DLL
  1490. ConVar cl_cam_driver_compensation_scale( "cl_cam_driver_compensation_scale", "0.75", FCVAR_RELEASE, "" );
  1491. #endif
  1492. void CWeaponCSBase::DrawCrosshair()
  1493. {
  1494. if ( !crosshair.GetInt() )
  1495. return;
  1496. CHudCrosshair *pCrosshair = GET_HUDELEMENT( CHudCrosshair );
  1497. // clear old hud crosshair
  1498. if ( !pCrosshair )
  1499. return;
  1500. pCrosshair->SetCrosshair( 0, Color( 255, 255, 255, 255 ) );
  1501. CCSPlayer* pPlayer = ( CCSPlayer* )C_BasePlayer::GetLocalPlayer();
  1502. if ( !pPlayer || GetPlayerOwner() == NULL )
  1503. return;
  1504. Assert( (pPlayer == GetPlayerOwner()) || ( pPlayer->GetObserverMode()==OBS_MODE_IN_EYE) );
  1505. if ( pPlayer->IsInVGuiInputMode() )
  1506. return;
  1507. if ( pPlayer->GetObserverInterpState() == C_CSPlayer::OBSERVER_INTERP_TRAVELING )
  1508. return;
  1509. // no crosshair for sniper rifles
  1510. // localplayer must be owner if not in Spec mode
  1511. int r, g, b;
  1512. switch ( cl_crosshaircolor.GetInt() )
  1513. {
  1514. case 0 : r = 250; g = 50; b = 50; break;
  1515. case 1 : r = 50; g = 250; b = 50; break;
  1516. case 2 : r = 250; g = 250; b = 50; break;
  1517. case 3 : r = 50; g = 50; b = 250; break;
  1518. case 4 : r = 50; g = 250; b = 250; break;
  1519. case 5 :
  1520. r = cl_crosshaircolor_r.GetInt();
  1521. g = cl_crosshaircolor_g.GetInt();
  1522. b = cl_crosshaircolor_b.GetInt();
  1523. break;
  1524. default : r = 50; g = 250; b = 50; break;
  1525. }
  1526. // if user is using nightvision, make the crosshair red.
  1527. if ( pPlayer->m_bNightVisionOn )
  1528. {
  1529. r = 250;
  1530. g = 50;
  1531. b = 50;
  1532. }
  1533. int alpha = clamp( cl_crosshairalpha.GetInt(), 0, 255 );
  1534. if ( !m_iCrosshairTextureID )
  1535. {
  1536. CHudTexture *pTexture = HudIcons().GetIcon( "whiteAdditive" );
  1537. if ( pTexture )
  1538. {
  1539. m_iCrosshairTextureID = pTexture->textureId;
  1540. }
  1541. }
  1542. bool bAdditive = !cl_crosshairusealpha.GetBool() && !pPlayer->m_bNightVisionOn;
  1543. if ( bAdditive )
  1544. {
  1545. vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
  1546. alpha = 200;
  1547. }
  1548. #ifdef IRONSIGHT
  1549. if ( GetIronSightController() && !weapon_debug_spread_show.GetBool() && GetIronSightController()->ShouldHideCrossHair() )
  1550. {
  1551. alpha = 0;
  1552. }
  1553. #endif
  1554. if ( pPlayer->HasShield() && pPlayer->IsShieldDrawn() == true )
  1555. return;
  1556. if ( GetWeaponType() == WEAPONTYPE_SNIPER_RIFLE && !weapon_debug_spread_show.GetBool() )
  1557. return;
  1558. float fHalfFov = DEG2RAD( pPlayer->GetFOV() ) * 0.5f;
  1559. float flInaccuracy = GetInaccuracy();
  1560. float flSpread = GetSpread();
  1561. // float flCrossDistanceScale = cl_crosshair_dynamic_distancescale.GetFloat();
  1562. float fSpreadDistance = ((flInaccuracy + flSpread) * 320.0f / tanf(fHalfFov))/* * flCrossDistanceScale*/;
  1563. float flCappedSpreadDistance = fSpreadDistance;
  1564. float flMaxCrossDistance = cl_crosshair_dynamic_splitdist.GetFloat();
  1565. if (fSpreadDistance > flMaxCrossDistance)
  1566. {
  1567. // bHitMax = true;
  1568. // //flLineAlpha = alpha * MAX(0, 1 - ((fSpreadDistance - flMaxCrossDistance) / 20));
  1569. flCappedSpreadDistance = flMaxCrossDistance;
  1570. }
  1571. int iSpreadDistance = cl_crosshairstyle.GetInt() < 4 ? RoundFloatToInt( YRES( fSpreadDistance )) : 2;
  1572. int iCappedSpreadDistance = cl_crosshairstyle.GetInt() < 4 ? RoundFloatToInt(YRES(flCappedSpreadDistance)) : 2;
  1573. float flAccuracyFishtail = GetAccuracyFishtail();
  1574. #ifdef CLIENT_DLL
  1575. if (cl_weapon_debug_print_accuracy.GetInt() == 1)
  1576. {
  1577. float flVel = pPlayer->GetLocalVelocity().Length2D();
  1578. if (flVel > 0)
  1579. Msg("Inaccuracy =\t%f\tSpread =\t%f\tSpreadDistance =\t%f\tPlayer Velocity =\t%f\n", flInaccuracy, flSpread, fSpreadDistance, flVel);
  1580. }
  1581. #endif
  1582. int iDeltaDistance = GetCSWpnData().GetCrosshairDeltaDistance( GetEconItemView() ); // Amount by which the crosshair expands when shooting ( per frame )
  1583. float fCrosshairDistanceGoal = cl_crosshairgap_useweaponvalue.GetBool() ? GetCSWpnData().GetCrosshairMinDistance( GetEconItemView() ) : 4; // The minimum distance the crosshair can achieve...
  1584. //0 = default
  1585. //1 = default static
  1586. //2 = classic standard
  1587. //3 = classic dynamic
  1588. //4 = classic static
  1589. //if ( cl_dynamiccrosshair.GetBool() )
  1590. if ( cl_crosshairstyle.GetInt() != 4 && (cl_crosshairstyle.GetInt() == 2 || cl_crosshairstyle.GetInt() == 3) )
  1591. {
  1592. if ( !( pPlayer->GetFlags() & FL_ONGROUND ) )
  1593. fCrosshairDistanceGoal *= 2.0f;
  1594. else if ( pPlayer->GetFlags() & FL_DUCKING )
  1595. fCrosshairDistanceGoal *= 0.5f;
  1596. else if ( pPlayer->GetAbsVelocity().Length() > 100 )
  1597. fCrosshairDistanceGoal *= 1.5f;
  1598. }
  1599. // [jpaquin] changed to only bump up the crosshair size if the player is still shooting or is spectating someone else
  1600. if ( pPlayer->m_iShotsFired > m_iAmmoLastCheck && ( pPlayer->m_nButtons & ( IN_ATTACK|IN_ATTACK2 )) && m_iClip1 >= 0 )
  1601. {
  1602. if ( cl_crosshairstyle.GetInt() == 5 )
  1603. m_flCrosshairDistance += (GetRecoilMagnitude( m_weaponMode ) / 3.5);
  1604. else if ( cl_crosshairstyle.GetInt() != 4 )
  1605. fCrosshairDistanceGoal += iDeltaDistance;
  1606. }
  1607. m_iAmmoLastCheck = pPlayer->m_iShotsFired;
  1608. if ( m_flCrosshairDistance > fCrosshairDistanceGoal )
  1609. {
  1610. if ( cl_crosshairstyle.GetInt() == 5 )
  1611. {
  1612. //float flPer = ( gpGlobals->frametime / 0.025f );
  1613. //m_flCrosshairDistance -= (0.11 + ( m_flCrosshairDistance * 0.01 )) * gpGlobals->frametime;
  1614. m_flCrosshairDistance -= 42.0 * gpGlobals->frametime;
  1615. }
  1616. else
  1617. m_flCrosshairDistance = Lerp( ( gpGlobals->frametime / 0.025f ), fCrosshairDistanceGoal, m_flCrosshairDistance );
  1618. }
  1619. // clamp max crosshair expansion
  1620. m_flCrosshairDistance = clamp( m_flCrosshairDistance, fCrosshairDistanceGoal, 25.0f );
  1621. int iCrosshairDistance;
  1622. int iCappedCrosshairDistance = 0;
  1623. int iBarSize;
  1624. int iBarThickness;
  1625. iCrosshairDistance = RoundFloatToInt((m_flCrosshairDistance * ScreenHeight() / 1200.0f) + cl_crosshairgap.GetFloat());
  1626. iBarSize = RoundFloatToInt( YRES( cl_crosshairsize.GetFloat() ));
  1627. iBarThickness = MAX( 1, RoundFloatToInt( YRES( cl_crosshairthickness.GetFloat() )) );
  1628. //0 = default
  1629. //1 = default static
  1630. //2 = classic standard
  1631. //3 = classic dynamic
  1632. //4 = classic static
  1633. //if ( weapon_debug_spread_show.GetInt() == 2 )
  1634. if ( weapon_debug_spread_show.GetInt( ) == 2 || (iSpreadDistance > 0 && ( cl_crosshairstyle.GetInt( ) == 2 || cl_crosshairstyle.GetInt( ) == 3 ) ) )
  1635. {
  1636. iCrosshairDistance = iSpreadDistance + cl_crosshairgap.GetFloat();
  1637. if ( cl_crosshairstyle.GetInt( ) == 2 )
  1638. iCappedCrosshairDistance = iCappedSpreadDistance + cl_crosshairgap.GetFloat();
  1639. }
  1640. else if ( cl_crosshairstyle.GetInt( ) == 4 || ( iSpreadDistance == 0 && ( cl_crosshairstyle.GetInt( ) == 2 || cl_crosshairstyle.GetInt( ) == 3 ) ) )
  1641. {
  1642. iCrosshairDistance = fCrosshairDistanceGoal + cl_crosshairgap.GetFloat();
  1643. iCappedCrosshairDistance = 4 + cl_crosshairgap.GetFloat();
  1644. }
  1645. #ifdef SIXENSE
  1646. int iCenterX;
  1647. int iCenterY;
  1648. if( g_pSixenseInput->IsEnabled() )
  1649. {
  1650. // Never autoaim a predicted weapon (for now)
  1651. Vector aimVector;
  1652. AngleVectors( CurrentViewAngles() - g_pSixenseInput->GetViewAngleOffset(), &aimVector );
  1653. // calculate where the bullet would go so we can draw the cross appropriately
  1654. Vector vecStart = pPlayer->Weapon_ShootPosition();
  1655. Vector vecEnd = pPlayer->Weapon_ShootPosition() + aimVector * MAX_TRACE_LENGTH;
  1656. trace_t tr;
  1657. UTIL_TraceLine( vecStart, vecEnd, MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr );
  1658. Vector screen;
  1659. screen.Init();
  1660. ScreenTransform(tr.endpos, screen);
  1661. iCenterX = ScreenWidth() / 2;
  1662. iCenterY = ScreenHeight() / 2;
  1663. iCenterX += 0.5 * screen[0] * ScreenWidth() + 0.5;
  1664. iCenterY += 0.5 * screen[1] * ScreenHeight() + 0.5;
  1665. iCenterY = ScreenHeight() - iCenterY;
  1666. }
  1667. else
  1668. {
  1669. iCenterX = ScreenWidth() / 2;
  1670. iCenterY = ScreenHeight() / 2;
  1671. }
  1672. #else
  1673. int iCenterX = ScreenWidth() / 2;
  1674. int iCenterY = ScreenHeight() / 2;
  1675. #endif
  1676. float flAngleToScreenPixel = 0;
  1677. #ifdef CLIENT_DLL
  1678. // subtract a ratio of cam driver motion from crosshair according to cl_cam_driver_compensation_scale
  1679. if ( cl_cam_driver_compensation_scale.GetFloat() != 0 )
  1680. {
  1681. CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() );
  1682. if ( pOwner )
  1683. {
  1684. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  1685. if ( vm && vm->m_flCamDriverWeight > 0 )
  1686. {
  1687. QAngle angCamDriver = vm->m_flCamDriverWeight * vm->m_angCamDriverLastAng * clamp( cl_cam_driver_compensation_scale.GetFloat(), -10.0f, 10.0f );
  1688. if ( angCamDriver.x != 0 || angCamDriver.y != 0 )
  1689. {
  1690. flAngleToScreenPixel = VIEWPUNCH_COMPENSATE_MAGIC_SCALAR * 2 * ( ScreenHeight() / ( 2.0f * tanf(DEG2RAD( pPlayer->GetFOV() ) / 2.0f) ) );
  1691. iCenterY -= ( flAngleToScreenPixel * sinf( DEG2RAD( angCamDriver.x ) ) ) ;
  1692. iCenterX += ( flAngleToScreenPixel * sinf( DEG2RAD( angCamDriver.y ) ) ) ;
  1693. }
  1694. }
  1695. }
  1696. }
  1697. #endif
  1698. /*
  1699. // Optionally subtract out viewangle since it doesn't affect shooting.
  1700. if ( cl_flinch_compensate_crosshair.GetBool() )
  1701. {
  1702. QAngle viewPunch = pPlayer->GetViewPunchAngle();
  1703. if ( viewPunch.x != 0 || viewPunch.y != 0 )
  1704. {
  1705. if ( flAngleToScreenPixel == 0 )
  1706. flAngleToScreenPixel = VIEWPUNCH_COMPENSATE_MAGIC_SCALAR * 2 * ( ScreenHeight() / ( 2.0f * tanf(DEG2RAD( pPlayer->GetFOV() ) / 2.0f) ) );
  1707. iCenterY -= flAngleToScreenPixel * sinf( DEG2RAD( viewPunch.x ) );
  1708. iCenterX += flAngleToScreenPixel * sinf( DEG2RAD( viewPunch.y ) );
  1709. }
  1710. }
  1711. */
  1712. int nFishTaleShift = ( flAccuracyFishtail * ( ScreenHeight() / 500.0f ) );
  1713. //0 = default
  1714. //1 = default static
  1715. //2 = classic standard
  1716. //3 = classic dynamic
  1717. //4 = classic static
  1718. if ( cl_crosshairstyle.GetInt() == 4 )
  1719. {
  1720. nFishTaleShift = 0;
  1721. }
  1722. float flAlphaSplitInner = cl_crosshair_dynamic_splitalpha_innermod.GetFloat();
  1723. float flAlphaSplitOuter = cl_crosshair_dynamic_splitalpha_outermod.GetFloat();
  1724. float flSplitRatio = cl_crosshair_dynamic_maxdist_splitratio.GetFloat();
  1725. int iInnerCrossDist = iCrosshairDistance;
  1726. float flLineAlphaInner = alpha;
  1727. float flLineAlphaOuter = alpha;
  1728. int iBarSizeInner = iBarSize;
  1729. int iBarSizeOuter = iBarSize;
  1730. // draw the crosshair that splits off from the main xhair
  1731. if (cl_crosshairstyle.GetInt() == 2 && fSpreadDistance > flMaxCrossDistance)
  1732. {
  1733. iInnerCrossDist = iCappedCrosshairDistance;
  1734. flLineAlphaInner = alpha * flAlphaSplitInner;
  1735. flLineAlphaOuter = alpha * flAlphaSplitOuter;
  1736. iBarSizeInner = ceil((float)iBarSize * (1.0f - flSplitRatio));
  1737. iBarSizeOuter = floor((float)iBarSize * flSplitRatio);
  1738. // draw horizontal crosshair lines
  1739. int iInnerLeft = (iCenterX - iCrosshairDistance - iBarThickness / 2 + nFishTaleShift) - iBarSizeInner;
  1740. int iInnerRight = iInnerLeft + 2 * (iCrosshairDistance + iBarSizeInner) + iBarThickness + nFishTaleShift;
  1741. int iOuterLeft = iInnerLeft - iBarSizeOuter;
  1742. int iOuterRight = iInnerRight + iBarSizeOuter;
  1743. int y0 = iCenterY - iBarThickness / 2;
  1744. int y1 = y0 + iBarThickness;
  1745. DrawCrosshairRect(r, g, b, flLineAlphaOuter, iOuterLeft, y0, iInnerLeft, y1, bAdditive);
  1746. DrawCrosshairRect(r, g, b, flLineAlphaOuter, iInnerRight, y0, iOuterRight, y1, bAdditive);
  1747. // draw vertical crosshair lines
  1748. int iInnerTop = (iCenterY - iCrosshairDistance - iBarThickness / 2) - iBarSizeInner;
  1749. int iInnerBottom = iInnerTop + 2 * (iCrosshairDistance + iBarSizeInner) + iBarThickness;
  1750. int iOuterTop = iInnerTop - iBarSizeOuter;
  1751. int iOuterBottom = iInnerBottom + iBarSizeOuter;
  1752. int x0 = iCenterX - iBarThickness / 2;
  1753. int x1 = x0 + iBarThickness;
  1754. DrawCrosshairRect(r, g, b, flLineAlphaOuter, x0, iOuterTop, x1, iInnerTop, bAdditive);
  1755. DrawCrosshairRect(r, g, b, flLineAlphaOuter, x0, iInnerBottom, x1, iOuterBottom, bAdditive);
  1756. }
  1757. // draw horizontal crosshair lines
  1758. int iInnerLeft = iCenterX - iInnerCrossDist - iBarThickness / 2 + nFishTaleShift;
  1759. int iInnerRight = iInnerLeft + 2 * iInnerCrossDist + iBarThickness + nFishTaleShift;
  1760. int iOuterLeft = iInnerLeft - iBarSizeInner;
  1761. int iOuterRight = iInnerRight + iBarSizeInner;
  1762. int y0 = iCenterY - iBarThickness / 2;
  1763. int y1 = y0 + iBarThickness;
  1764. DrawCrosshairRect(r, g, b, flLineAlphaInner, iOuterLeft, y0, iInnerLeft, y1, bAdditive);
  1765. DrawCrosshairRect(r, g, b, flLineAlphaInner, iInnerRight, y0, iOuterRight, y1, bAdditive);
  1766. // draw vertical crosshair lines
  1767. int iInnerTop = iCenterY - iInnerCrossDist - iBarThickness / 2;
  1768. int iInnerBottom = iInnerTop + 2 * iInnerCrossDist + iBarThickness;
  1769. int iOuterTop = iInnerTop - iBarSizeInner;
  1770. int iOuterBottom = iInnerBottom + iBarSizeInner;
  1771. int x0 = iCenterX - iBarThickness / 2;
  1772. int x1 = x0 + iBarThickness;
  1773. DrawCrosshairRect(r, g, b, flLineAlphaInner, x0, iOuterTop, x1, iInnerTop, bAdditive);
  1774. DrawCrosshairRect(r, g, b, flLineAlphaInner, x0, iInnerBottom, x1, iOuterBottom, bAdditive);
  1775. // draw dot
  1776. if ( cl_crosshairdot.GetBool() )
  1777. {
  1778. int x0 = iCenterX - iBarThickness / 2;
  1779. int x1 = x0 + iBarThickness;
  1780. int y0 = iCenterY - iBarThickness / 2;
  1781. int y1 = y0 + iBarThickness;
  1782. DrawCrosshairRect( r, g, b, alpha, x0, y0, x1, y1, bAdditive );
  1783. }
  1784. if ( weapon_debug_spread_show.GetInt() == 1 )
  1785. {
  1786. // colors
  1787. r = 250;
  1788. g = 250;
  1789. b = 50;
  1790. //vgui::surface()->DrawSetColor( r, g, b, alpha );
  1791. int iBarThickness = MAX( 1, RoundFloatToInt( YRES( cl_crosshairthickness.GetFloat() )) );
  1792. // draw vertical spread lines
  1793. int iInnerLeft = iCenterX - iSpreadDistance;
  1794. int iInnerRight = iCenterX + iSpreadDistance;
  1795. int iOuterLeft = iInnerLeft - iBarThickness;
  1796. int iOuterRight = iInnerRight + iBarThickness;
  1797. int iInnerTop = iCenterY - iSpreadDistance;
  1798. int iInnerBottom = iCenterY + iSpreadDistance;
  1799. int iOuterTop = iInnerTop - iBarThickness;
  1800. int iOuterBottom = iInnerBottom + iBarThickness;
  1801. int iGap = RoundFloatToInt( weapon_debug_spread_gap.GetFloat() * iSpreadDistance );
  1802. // draw horizontal lines
  1803. DrawCrosshairRect( r, g, b, alpha, iOuterLeft, iOuterTop, iCenterX - iGap, iInnerTop, bAdditive );
  1804. DrawCrosshairRect( r, g, b, alpha, iCenterX + iGap, iOuterTop, iOuterRight, iInnerTop, bAdditive );
  1805. DrawCrosshairRect( r, g, b, alpha, iOuterLeft, iInnerBottom, iCenterX - iGap, iOuterBottom, bAdditive );
  1806. DrawCrosshairRect( r, g, b, alpha, iCenterX + iGap, iInnerBottom, iOuterRight, iOuterBottom, bAdditive );
  1807. // draw vertical lines
  1808. DrawCrosshairRect( r, g, b, alpha, iOuterLeft, iOuterTop, iInnerLeft, iCenterY - iGap, bAdditive );
  1809. DrawCrosshairRect( r, g, b, alpha, iOuterLeft, iCenterY + iGap, iInnerLeft, iOuterBottom, bAdditive );
  1810. DrawCrosshairRect( r, g, b, alpha, iInnerRight, iOuterTop, iOuterRight, iCenterY - iGap, bAdditive );
  1811. DrawCrosshairRect( r, g, b, alpha, iInnerRight, iCenterY + iGap, iOuterRight, iOuterBottom, bAdditive );
  1812. }
  1813. }
  1814. void CWeaponCSBase::OnDataChanged( DataUpdateType_t type )
  1815. {
  1816. if ( type == DATA_UPDATE_CREATED )
  1817. {
  1818. m_nWeaponID = WeaponIdFromString( GetClassname() );
  1819. }
  1820. bool bChangedCarryState = false;
  1821. if ( ( m_iState != WEAPON_NOT_CARRIED && m_iOldState == WEAPON_NOT_CARRIED ) ||
  1822. ( m_iState == WEAPON_NOT_CARRIED && m_iOldState != WEAPON_NOT_CARRIED ) )
  1823. {
  1824. bChangedCarryState = true;
  1825. }
  1826. C_BaseCombatCharacter *pOwner = GetPreviousOwner();
  1827. if ( GetWeaponType() == WEAPONTYPE_GRENADE )
  1828. {
  1829. pOwner = ( (CBaseGrenade *) this )->GetThrower();
  1830. }
  1831. if ( pOwner )
  1832. {
  1833. C_BasePlayer *pPlayer = ToBasePlayer( pOwner );
  1834. C_CSPlayer *pObservedPlayer = GetHudPlayer();
  1835. // check if weapon was dropped by local player or the player we are observing
  1836. if ( pObservedPlayer == pPlayer )
  1837. {
  1838. ACTIVE_SPLITSCREEN_PLAYER_GUARD( C_BasePlayer::GetSplitScreenSlotForPlayer( pPlayer ) );
  1839. if ( m_iState == WEAPON_NOT_CARRIED && m_iOldState != WEAPON_NOT_CARRIED )
  1840. {
  1841. CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
  1842. if ( pHudSelection )
  1843. {
  1844. pHudSelection->OnWeaponDrop( this );
  1845. }
  1846. }
  1847. }
  1848. }
  1849. BaseClass::OnDataChanged( type );
  1850. #ifdef CLIENT_DLL
  1851. bool bFirstPersonSpectatedState = IsFirstPersonSpectated();
  1852. if ( ( bFirstPersonSpectatedState && !m_bOldFirstPersonSpectatedState ) ||
  1853. ( !bFirstPersonSpectatedState && m_bOldFirstPersonSpectatedState ) )
  1854. {
  1855. bChangedCarryState = true;
  1856. }
  1857. if ( type == DATA_UPDATE_CREATED )
  1858. {
  1859. // this will trigger the custom material to start making itself (if needed) the weapon will render with
  1860. // the original material for a few frames, then switch to the custom material when it's ready
  1861. UpdateCustomMaterial();
  1862. UpdateOutlineGlow();
  1863. }
  1864. else if ( bChangedCarryState )
  1865. {
  1866. CheckCustomMaterial();
  1867. UpdateOutlineGlow();
  1868. }
  1869. #endif
  1870. #ifdef IRONSIGHT
  1871. UpdateIronSightController();
  1872. #endif //IRONSIGHT
  1873. if ( GetPredictable() && !ShouldPredict() )
  1874. ShutdownPredictable();
  1875. }
  1876. bool CWeaponCSBase::ShouldPredict()
  1877. {
  1878. if ( C_BasePlayer::IsLocalPlayer( GetOwner() ) )
  1879. return true;
  1880. return BaseClass::ShouldPredict();
  1881. }
  1882. void CWeaponCSBase::ProcessMuzzleFlashEvent()
  1883. {
  1884. // This is handled from the player's animstate, so it can match up to the beginning of the fire animation
  1885. }
  1886. int CWeaponCSBase::GetViewModelSplitScreenSlot( C_BaseViewModel *pViewModel )
  1887. {
  1888. uint32 visBits = pViewModel->m_VisibilityBits.Get(0, 0xff);
  1889. int nSlot = -1;
  1890. if ( visBits < 3 )
  1891. {
  1892. // If visBits is 3 then it is both slots 1 and 2 meaning all users can see this viewmodel (as indicated via -1).
  1893. // If visBits is 1 or 2 then the view model is only seen in that specific slot either slot (but zero based means slot 0 or 1).
  1894. // If visBits is 0, then split screen is not active so we should not be drawing this view model at all. Currently not handled here but should be handled elsewhere.
  1895. nSlot = visBits-1;
  1896. }
  1897. return nSlot;
  1898. }
  1899. bool CWeaponCSBase::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
  1900. {
  1901. int nSlot = GetViewModelSplitScreenSlot( pViewModel );
  1902. if( event == 5001 )
  1903. {
  1904. C_CSPlayer *pPlayer = ToCSPlayer( GetOwner() );
  1905. if ( !pPlayer )
  1906. return true;
  1907. if( pPlayer && pPlayer->GetFOV() != pPlayer->GetDefaultFOV() && pPlayer->m_bIsScoped && DoesHideViewModelWhenZoomed() )
  1908. return true;
  1909. // hide particle effects when we're interpolating between observer targets
  1910. C_BasePlayer* pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1911. if ( pLocalPlayer && pLocalPlayer->GetObserverTarget() == pPlayer && pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE && pLocalPlayer->GetObserverInterpState() == C_BasePlayer::OBSERVER_INTERP_TRAVELING )
  1912. return true;
  1913. bool bLocalThirdPerson = ( (pPlayer == pLocalPlayer) && pPlayer->ShouldDraw() );
  1914. Vector origin;
  1915. int iAttachmentIndex = GetMuzzleAttachmentIndex_1stPerson( pViewModel );
  1916. const char *pszEffect = GetMuzzleFlashEffectName_1stPerson();
  1917. if ( pszEffect && Q_strlen( pszEffect ) > 0 && iAttachmentIndex >= 0 )
  1918. {
  1919. // The view model fixes up the split screen visibility of any effects spawned off of it.
  1920. if ( !bLocalThirdPerson )
  1921. DispatchParticleEffect( pszEffect, PATTACH_POINT_FOLLOW, pViewModel, iAttachmentIndex, false, nSlot );
  1922. // we can't trust this position
  1923. //pViewModel->GetAttachment( iAttachmentIndex, origin );
  1924. //silencers produce no light at all - even smaller lights would illuminate smoke or cause unwanted visual effects
  1925. if ( !(HasSilencer() && IsSilenced()) )
  1926. {
  1927. CPVSFilter filter( origin );
  1928. origin = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset();
  1929. ACTIVE_SPLITSCREEN_PLAYER_GUARD( pPlayer );
  1930. QAngle vangles;
  1931. Vector vforward, vright, vup;
  1932. engine->GetViewAngles( vangles );
  1933. AngleVectors( vangles, &vforward, &vright, &vup );
  1934. VectorMA( origin, cl_righthand.GetBool() ? 4 : -4, vright, origin );
  1935. VectorMA( origin, 31, vforward, origin );
  1936. origin[2] += 3.0f;
  1937. TE_DynamicLight( filter, 0.0, &origin, 255, 186, 64, 5, 70, 0.05, 768 );
  1938. }
  1939. UpdateGunHeat( GetCSWpnData().GetHeatPerShot(), iAttachmentIndex );
  1940. }
  1941. return true;
  1942. }
  1943. else if ( event == AE_CLIENT_EJECT_BRASS )
  1944. {
  1945. C_CSPlayer *pPlayer = ToCSPlayer( GetOwner() );
  1946. if( pPlayer && pPlayer->GetFOV() != pPlayer->GetDefaultFOV() && pPlayer->m_bIsScoped && DoesHideViewModelWhenZoomed() )
  1947. return true;
  1948. Vector origin;
  1949. const char *pszEffect = GetEjectBrassEffectName();
  1950. int iAttachmentIndex = -1;
  1951. // If options is non-zero in length, treat as an attachment name to use for this particle effect.
  1952. if ( options && Q_strlen( options ) > 0 )
  1953. {
  1954. iAttachmentIndex = pViewModel->LookupAttachment( options );
  1955. }
  1956. else
  1957. {
  1958. iAttachmentIndex = GetEjectBrassAttachmentIndex_1stPerson( pViewModel );
  1959. }
  1960. if ( pszEffect && Q_strlen( pszEffect ) > 0 && iAttachmentIndex >= 0 )
  1961. {
  1962. C_BasePlayer* pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1963. bool bLocalThirdPerson = ( (pPlayer == pLocalPlayer) && pPlayer->ShouldDraw() );
  1964. // The view model fixes up the split screen visibility of any effects spawned off of it.
  1965. if ( !bLocalThirdPerson )
  1966. DispatchParticleEffect( pszEffect, PATTACH_POINT_FOLLOW, pViewModel, iAttachmentIndex, false, nSlot );
  1967. }
  1968. return true;
  1969. }
  1970. else if ( event == AE_CL_SET_STATTRAK_GLOW )
  1971. {
  1972. pViewModel->SetStatTrakGlowMultiplier( atof( options ) );
  1973. return true;
  1974. }
  1975. else if ( event == AE_WPN_NEXTCLIP_TO_POSEPARAM )
  1976. {
  1977. // sets the given pose param to a 0..1 value representing the clip amount after an impending reload
  1978. CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() );
  1979. if ( pOwner )
  1980. {
  1981. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  1982. if ( vm )
  1983. {
  1984. int iNextClip = MIN( GetMaxClip1(), m_iClip1 + GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
  1985. vm->SetPoseParameter( options, 1.0f - (((float)iNextClip) / ((float)GetMaxClip1())) );
  1986. }
  1987. }
  1988. return true;
  1989. }
  1990. else if ( event == AE_WPN_CLIP_TO_POSEPARAM )
  1991. {
  1992. // sets the given pose param to a 0..1 value representing the clip amount
  1993. CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() );
  1994. if ( pOwner )
  1995. {
  1996. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  1997. if ( vm )
  1998. {
  1999. vm->SetPoseParameter( options, 1.0f - (((float)m_iClip1) / ((float)GetMaxClip1())) );
  2000. }
  2001. }
  2002. return true;
  2003. }
  2004. else if ( event == AE_WPN_EMPTYSHOTS_TO_POSEPARAM )
  2005. {
  2006. // sets the given pose param to a 0..1 value representing the number of empty shots
  2007. CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() );
  2008. if ( pOwner )
  2009. {
  2010. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  2011. if ( vm )
  2012. {
  2013. vm->SetPoseParameter( options, fmod( m_iNumEmptyAttacks, (float)GetMaxClip1() ) / (float)GetMaxClip1() );
  2014. }
  2015. }
  2016. return true;
  2017. }
  2018. return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
  2019. }
  2020. const char* CWeaponCSBase::GetMuzzleFlashEffectName_1stPerson( void )
  2021. {
  2022. if ( HasSilencer() && IsSilenced() )
  2023. {
  2024. return GetCSWpnData().GetMuzzleFlashEffectName_1stPersonAlt( GetEconItemView() );
  2025. }
  2026. else
  2027. {
  2028. return GetCSWpnData().GetMuzzleFlashEffectName_1stPerson( GetEconItemView() );
  2029. }
  2030. }
  2031. const char* CWeaponCSBase::GetHeatEffectName( void )
  2032. {
  2033. return GetCSWpnData().GetHeatEffectName( GetEconItemView() );
  2034. }
  2035. const char* CWeaponCSBase::GetMuzzleFlashEffectName_3rdPerson( void )
  2036. {
  2037. if ( HasSilencer() && IsSilenced() )
  2038. {
  2039. return GetCSWpnData().GetMuzzleFlashEffectName_3rdPersonAlt( GetEconItemView() );
  2040. }
  2041. else
  2042. {
  2043. return GetCSWpnData().GetMuzzleFlashEffectName_3rdPerson( GetEconItemView() );
  2044. }
  2045. }
  2046. const char* CWeaponCSBase::GetEjectBrassEffectName( void )
  2047. {
  2048. return GetCSWpnData().GetEjectBrassEffectName( GetEconItemView() );
  2049. }
  2050. int CWeaponCSBase::GetMuzzleAttachmentIndex_1stPerson( C_BaseViewModel *pViewModel )
  2051. {
  2052. if ( pViewModel )
  2053. {
  2054. if ( HasSilencer() && IsSilenced() )
  2055. {
  2056. return pViewModel->LookupAttachment( "muzzle_flash2" );
  2057. }
  2058. return pViewModel->LookupAttachment( "1" );
  2059. }
  2060. return -1;
  2061. }
  2062. int CWeaponCSBase::GetMuzzleAttachmentIndex_3rdPerson( void )
  2063. {
  2064. CBaseWeaponWorldModel *pWeaponWorldModel = GetWeaponWorldModel();
  2065. if ( pWeaponWorldModel )
  2066. {
  2067. if ( HasSilencer() && IsSilenced() )
  2068. {
  2069. return pWeaponWorldModel->LookupAttachment( "muzzle_flash2" );
  2070. }
  2071. return pWeaponWorldModel->LookupAttachment( "muzzle_flash" );
  2072. }
  2073. return -1;
  2074. }
  2075. int CWeaponCSBase::GetEjectBrassAttachmentIndex_1stPerson( C_BaseViewModel *pViewModel )
  2076. {
  2077. if ( pViewModel )
  2078. return pViewModel->LookupAttachment( "2" );
  2079. return -1;
  2080. }
  2081. int CWeaponCSBase::GetEjectBrassAttachmentIndex_3rdPerson( void )
  2082. {
  2083. CBaseWeaponWorldModel *pWeaponWorldModel = GetWeaponWorldModel();
  2084. if ( pWeaponWorldModel )
  2085. return pWeaponWorldModel->LookupAttachment( "shell_eject" );
  2086. return -1;
  2087. }
  2088. #else
  2089. //-----------------------------------------------------------------------------
  2090. // Purpose: Get the accuracy derived from weapon and player, and return it
  2091. //-----------------------------------------------------------------------------
  2092. const Vector& CWeaponCSBase::GetBulletSpread()
  2093. {
  2094. static Vector cone = VECTOR_CONE_8DEGREES;
  2095. return cone;
  2096. }
  2097. //-----------------------------------------------------------------------------
  2098. // Purpose: Match the anim speed to the weapon speed while crouching
  2099. //-----------------------------------------------------------------------------
  2100. float CWeaponCSBase::GetDefaultAnimSpeed()
  2101. {
  2102. return 1.0;
  2103. }
  2104. //-----------------------------------------------------------------------------
  2105. // Purpose: Draw the laser rifle effect
  2106. //-----------------------------------------------------------------------------
  2107. void CWeaponCSBase::BulletWasFired( const Vector &vecStart, const Vector &vecEnd )
  2108. {
  2109. }
  2110. bool CWeaponCSBase::ShouldRemoveOnRoundRestart()
  2111. {
  2112. if ( GetPlayerOwner() )
  2113. return false;
  2114. else
  2115. return true;
  2116. }
  2117. void CWeaponCSBase::OnRoundRestart( void )
  2118. {
  2119. // Clear out the list of prior owners
  2120. // m_PriorOwners.RemoveAll();
  2121. }
  2122. //=========================================================
  2123. // Materialize - make a CWeaponCSBase visible and tangible
  2124. //=========================================================
  2125. void CWeaponCSBase::Materialize()
  2126. {
  2127. if ( IsEffectActive( EF_NODRAW ) )
  2128. {
  2129. // changing from invisible state to visible.
  2130. RemoveEffects( EF_NODRAW );
  2131. DoMuzzleFlash();
  2132. }
  2133. AddSolidFlags( FSOLID_TRIGGER );
  2134. //SetTouch( &CWeaponCSBase::DefaultTouch );
  2135. SetThink( NULL );
  2136. }
  2137. //=========================================================
  2138. // AttemptToMaterialize - the item is trying to rematerialize,
  2139. // should it do so now or wait longer?
  2140. //=========================================================
  2141. void CWeaponCSBase::AttemptToMaterialize()
  2142. {
  2143. float time = g_pGameRules->FlWeaponTryRespawn( this );
  2144. if ( time == 0 )
  2145. {
  2146. Materialize();
  2147. return;
  2148. }
  2149. SetNextThink( gpGlobals->curtime + time );
  2150. }
  2151. //=========================================================
  2152. // CheckRespawn - a player is taking this weapon, should
  2153. // it respawn?
  2154. //=========================================================
  2155. void CWeaponCSBase::CheckRespawn()
  2156. {
  2157. //GOOSEMAN : Do not respawn weapons!
  2158. return;
  2159. }
  2160. //=========================================================
  2161. // Respawn- this item is already in the world, but it is
  2162. // invisible and intangible. Make it visible and tangible.
  2163. //=========================================================
  2164. CBaseEntity* CWeaponCSBase::Respawn()
  2165. {
  2166. // make a copy of this weapon that is invisible and inaccessible to players ( no touch function ). The weapon spawn/respawn code
  2167. // will decide when to make the weapon visible and touchable.
  2168. CBaseEntity *pNewWeapon = CBaseEntity::Create( GetClassname(), g_pGameRules->VecWeaponRespawnSpot( this ), GetAbsAngles(), GetOwner() );
  2169. if ( pNewWeapon )
  2170. {
  2171. pNewWeapon->AddEffects( EF_NODRAW );// invisible for now
  2172. pNewWeapon->SetTouch( NULL );// no touch
  2173. pNewWeapon->SetThink( &CWeaponCSBase::AttemptToMaterialize );
  2174. UTIL_DropToFloor( this, MASK_SOLID );
  2175. // not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement,
  2176. // but when it should respawn is based on conditions belonging to the weapon that was taken.
  2177. pNewWeapon->SetNextThink( gpGlobals->curtime + g_pGameRules->FlWeaponRespawnTime( this ) );
  2178. }
  2179. else
  2180. {
  2181. Msg( "Respawn failed to create %s!\n", GetClassname() );
  2182. }
  2183. return pNewWeapon;
  2184. }
  2185. //-----------------------------------------------------------------------------
  2186. // Purpose:
  2187. //-----------------------------------------------------------------------------
  2188. void CWeaponCSBase::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  2189. {
  2190. CBasePlayer *pPlayer = ToBasePlayer( pActivator );
  2191. if ( pPlayer )
  2192. {
  2193. m_OnPlayerUse.FireOutput( pActivator, pCaller );
  2194. }
  2195. }
  2196. //-----------------------------------------------------------------------------
  2197. // Purpose:
  2198. // Input : *pEvent -
  2199. // *pOperator -
  2200. //-----------------------------------------------------------------------------
  2201. void CWeaponCSBase::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
  2202. {
  2203. int nEvent = pEvent->Event();
  2204. if ( (pEvent->type & AE_TYPE_NEWEVENTSYSTEM) && (pEvent->type & AE_TYPE_SERVER) )
  2205. {
  2206. if ( nEvent == AE_WPN_COMPLETE_RELOAD )
  2207. {
  2208. m_bReloadVisuallyComplete = true;
  2209. CCSPlayer *pPlayer = GetPlayerOwner();
  2210. if ( pPlayer )
  2211. {
  2212. int j = MIN( GetMaxClip1() - m_iClip1, GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
  2213. // Add them to the clip
  2214. m_iClip1 += j;
  2215. GiveReserveAmmo( AMMO_POSITION_PRIMARY, -j, true );
  2216. m_flRecoilIndex = 0;
  2217. }
  2218. }
  2219. else if ( nEvent == AE_BEGIN_TAUNT_LOOP )
  2220. {
  2221. CCSPlayer *pPlayer = GetPlayerOwner();
  2222. if ( pPlayer && pPlayer->IsLookingAtWeapon() && pPlayer->IsHoldingLookAtWeapon() )
  2223. {
  2224. CBaseViewModel *pViewModel = pPlayer->GetViewModel();
  2225. float flPrevCycle = pViewModel->GetCycle();
  2226. float flNewCycle = V_atof( pEvent->options );
  2227. pViewModel->SetCycle( flNewCycle );
  2228. float flSequenceDuration = pViewModel->SequenceDuration( pViewModel->GetSequence() );
  2229. pPlayer->ModifyTauntDuration( ( flNewCycle - flPrevCycle ) * flSequenceDuration );
  2230. }
  2231. //if ( pPlayer && pPlayer->IsTaunting() && pPlayer->IsHoldingTaunt() )
  2232. //{
  2233. // CBaseViewModel *pViewModel = pPlayer->GetViewModel();
  2234. //
  2235. // float flPrevCycle = pViewModel->GetCycle();
  2236. // float flNewCycle = V_atof( pEvent->options );
  2237. // pViewModel->SetCycle( flNewCycle );
  2238. //
  2239. // float flSequenceDuration = pViewModel->SequenceDuration( pViewModel->GetSequence() );
  2240. // pPlayer->ModifyTauntDuration( ( flNewCycle - flPrevCycle ) * flSequenceDuration );
  2241. //}
  2242. return;
  2243. }
  2244. #ifndef CLIENT_DLL
  2245. //update the bullet bodygroup on the client
  2246. else if ( nEvent == AE_CL_BODYGROUP_SET_TO_CLIP )
  2247. {
  2248. CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() );
  2249. if ( pOwner )
  2250. {
  2251. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  2252. if ( vm )
  2253. {
  2254. int iNumBodygroupIndices = vm->GetNumBodyGroups();
  2255. for ( int iGroup=1; iGroup<iNumBodygroupIndices; iGroup++ )
  2256. {
  2257. vm->SetBodygroup( iGroup, (m_iClip1 >= iGroup) ? 0 : 1 );
  2258. }
  2259. }
  2260. }
  2261. }
  2262. else if ( nEvent == AE_CL_BODYGROUP_SET_TO_NEXTCLIP )
  2263. {
  2264. CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() );
  2265. if ( pOwner )
  2266. {
  2267. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  2268. if ( vm )
  2269. {
  2270. int iNextClip = MIN( GetMaxClip1(), m_iClip1 + GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
  2271. int iNumBodygroupIndices = vm->GetNumBodyGroups();
  2272. for ( int iGroup=1; iGroup<iNumBodygroupIndices; iGroup++ )
  2273. {
  2274. vm->SetBodygroup( iGroup, (iNextClip >= iGroup) ? 0 : 1 );
  2275. }
  2276. }
  2277. }
  2278. }
  2279. else if ( nEvent == AE_WPN_NEXTCLIP_TO_POSEPARAM )
  2280. {
  2281. // sets the given pose param to a 0..1 value representing the clip amount after an impending reload
  2282. CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() );
  2283. if ( pOwner )
  2284. {
  2285. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  2286. if ( vm )
  2287. {
  2288. int iNextClip = MIN( GetMaxClip1(), m_iClip1 + GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
  2289. vm->SetPoseParameter( pEvent->options, 1.0f - (((float)iNextClip) / ((float)GetMaxClip1())) );
  2290. }
  2291. }
  2292. }
  2293. else if ( nEvent == AE_WPN_CLIP_TO_POSEPARAM )
  2294. {
  2295. // sets the given pose param to a 0..1 value representing the clip amount
  2296. CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() );
  2297. if ( pOwner )
  2298. {
  2299. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  2300. if ( vm )
  2301. {
  2302. vm->SetPoseParameter( pEvent->options, 1.0f - (((float)m_iClip1) / ((float)GetMaxClip1())) );
  2303. }
  2304. }
  2305. }
  2306. else if ( nEvent == AE_WPN_EMPTYSHOTS_TO_POSEPARAM )
  2307. {
  2308. // sets the given pose param to a 0..1 value representing the number of empty shots
  2309. CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() );
  2310. if ( pOwner )
  2311. {
  2312. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  2313. if ( vm )
  2314. {
  2315. vm->SetPoseParameter( pEvent->options, fmod( m_iNumEmptyAttacks, (float)GetMaxClip1() ) / (float)GetMaxClip1() );
  2316. }
  2317. }
  2318. }
  2319. else if ( nEvent == AE_CL_SHOW_SILENCER )
  2320. {
  2321. if ( CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() ) )
  2322. {
  2323. if ( CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex ) )
  2324. {
  2325. vm->SetBodygroup( vm->FindBodygroupByName( "silencer" ), SILENCER_VISIBLE );
  2326. }
  2327. }
  2328. //world model
  2329. CBaseWeaponWorldModel *pWorldModel = GetWeaponWorldModel();
  2330. if ( pWorldModel )
  2331. {
  2332. pWorldModel->SetBodygroupPreset( "show_silencer" );
  2333. }
  2334. else
  2335. {
  2336. SetBodygroup( FindBodygroupByName( "silencer" ), SILENCER_VISIBLE );
  2337. }
  2338. }
  2339. else if ( nEvent == AE_CL_HIDE_SILENCER )
  2340. {
  2341. if ( CBasePlayer *pOwner = ToBasePlayer( GetPlayerOwner() ) )
  2342. {
  2343. if ( CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex ) )
  2344. {
  2345. vm->SetBodygroup( vm->FindBodygroupByName( "silencer" ), SILENCER_HIDDEN );
  2346. }
  2347. }
  2348. //world model
  2349. CBaseWeaponWorldModel *pWorldModel = GetWeaponWorldModel();
  2350. if ( pWorldModel )
  2351. {
  2352. pWorldModel->SetBodygroupPreset( "hide_silencer" );
  2353. }
  2354. else
  2355. {
  2356. SetBodygroup( FindBodygroupByName( "silencer" ), SILENCER_HIDDEN );
  2357. }
  2358. }
  2359. else if ( nEvent == AE_CL_ATTACH_SILENCER_COMPLETE )
  2360. {
  2361. CBasePlayer *pPlayer = ToBasePlayer( GetPlayerOwner() );
  2362. m_bSilencerOn = true;
  2363. m_weaponMode = Secondary_Mode;
  2364. IGameEvent * event = gameeventmanager->CreateEvent( "silencer_on" );
  2365. if ( event && pPlayer )
  2366. {
  2367. event->SetInt( "userid", pPlayer->GetUserID() );
  2368. gameeventmanager->FireEvent( event );
  2369. }
  2370. }
  2371. else if ( nEvent == AE_CL_DETACH_SILENCER_COMPLETE )
  2372. {
  2373. CBasePlayer *pPlayer = ToBasePlayer( GetPlayerOwner() );
  2374. m_bSilencerOn = false;
  2375. m_weaponMode = Primary_Mode;
  2376. IGameEvent * event = gameeventmanager->CreateEvent( "silencer_off" );
  2377. if ( event && pPlayer )
  2378. {
  2379. event->SetInt( "userid", pPlayer->GetUserID() );
  2380. gameeventmanager->FireEvent( event );
  2381. }
  2382. }
  2383. else if ( nEvent == AE_WPN_CZ_DUMP_CURRENT_MAG )
  2384. {
  2385. CCSPlayer *pCSPlayer = GetPlayerOwner();
  2386. if ( pCSPlayer && pCSPlayer->GetActiveCSWeapon() )
  2387. {
  2388. //m_iClip1 = 0;
  2389. if ( CBaseViewModel *vm = pCSPlayer->GetViewModel( m_nViewModelIndex ) )
  2390. {
  2391. vm->SetBodygroup( vm->FindBodygroupByName( "front_mag" ), 1 );
  2392. //world model
  2393. CBaseWeaponWorldModel *pWorldModel = GetWeaponWorldModel();
  2394. if ( pWorldModel )
  2395. {
  2396. pWorldModel->SetBodygroup( pWorldModel->FindBodygroupByName( "front_mag" ), 1 );
  2397. }
  2398. else
  2399. {
  2400. SetBodygroup( FindBodygroupByName( "front_mag" ), 1 );
  2401. }
  2402. //if the front mag is removed, all subsequent anims use the non-front mag reload
  2403. m_iReloadActivityIndex = ACT_SECONDARY_VM_RELOAD;
  2404. }
  2405. }
  2406. }
  2407. else if ( nEvent == AE_WPN_CZ_UPDATE_BODYGROUP )
  2408. {
  2409. CCSPlayer *pCSPlayer = GetPlayerOwner();
  2410. if ( pCSPlayer && pCSPlayer->GetActiveCSWeapon() )
  2411. {
  2412. int iGroupNum = ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0) ? 1 : 0;
  2413. if ( CBaseViewModel *vm = pCSPlayer->GetViewModel( m_nViewModelIndex ) )
  2414. {
  2415. vm->SetBodygroup( vm->FindBodygroupByName( "front_mag" ), iGroupNum );
  2416. //world model
  2417. CBaseWeaponWorldModel *pWorldModel = GetWeaponWorldModel();
  2418. if ( pWorldModel )
  2419. {
  2420. pWorldModel->SetBodygroup( pWorldModel->FindBodygroupByName( "front_mag" ), iGroupNum );
  2421. }
  2422. else
  2423. {
  2424. SetBodygroup( FindBodygroupByName( "front_mag" ), iGroupNum );
  2425. }
  2426. //if the front mag is removed, all subsequent anims use the non-front mag reload
  2427. m_iReloadActivityIndex = ( iGroupNum == 0 ) ? ACT_VM_RELOAD : ACT_SECONDARY_VM_RELOAD;
  2428. }
  2429. }
  2430. }
  2431. else if ( nEvent == AE_WPN_PRIMARYATTACK )
  2432. {
  2433. // delay time
  2434. const char *p = pEvent->options;
  2435. char token[256];
  2436. p = nexttoken(token, p, ' ');
  2437. if ( token )
  2438. {
  2439. SetPostponeFireReadyTime( gpGlobals->curtime + atof( token ) );
  2440. // play the prepare warning sound to other players
  2441. CCSPlayer *pCSPlayer = GetPlayerOwner();
  2442. if ( pCSPlayer )
  2443. {
  2444. Vector soundPosition = pCSPlayer->GetAbsOrigin() + Vector( 0, 0, 50 );
  2445. CPASAttenuationFilter filter( soundPosition );
  2446. filter.RemoveRecipient( pCSPlayer );
  2447. // remove anyone that is first person spectating this player, since the viewmodel should play this sound for them on their client.
  2448. int i;
  2449. CBasePlayer *pPlayer;
  2450. for( i=1;i<=gpGlobals->maxClients;i++ )
  2451. {
  2452. pPlayer = UTIL_PlayerByIndex( i );
  2453. if ( !pPlayer )
  2454. continue;
  2455. if( pPlayer->GetObserverMode() == OBS_MODE_IN_EYE && pPlayer->GetObserverTarget() == pCSPlayer )
  2456. {
  2457. filter.RemoveRecipient( pPlayer );
  2458. }
  2459. }
  2460. EmitSound( filter, entindex(), "Weapon_Revolver.Prepare" );
  2461. }
  2462. }
  2463. return;
  2464. }
  2465. else if ( nEvent == AE_CL_BODYGROUP_SET_VALUE )
  2466. {
  2467. CCSPlayer *pCSPlayer = GetPlayerOwner();
  2468. if ( pCSPlayer && pCSPlayer->GetActiveCSWeapon() )
  2469. {
  2470. if ( CBaseViewModel *vm = pCSPlayer->GetViewModel( m_nViewModelIndex ) )
  2471. {
  2472. char szBodygroupName[256];
  2473. int value = 0;
  2474. char token[256];
  2475. const char *p = pEvent->options;
  2476. // Bodygroup Name
  2477. p = nexttoken(token, p, ' ');
  2478. if ( token )
  2479. {
  2480. Q_strncpy( szBodygroupName, token, sizeof(szBodygroupName) );
  2481. }
  2482. // Get the desired value
  2483. p = nexttoken(token, p, ' ');
  2484. if ( token )
  2485. {
  2486. value = atoi( token );
  2487. }
  2488. int index = vm->FindBodygroupByName( szBodygroupName );
  2489. if ( index >= 0 )
  2490. {
  2491. vm->SetBodygroup( index, value );
  2492. }
  2493. }
  2494. }
  2495. return;
  2496. }
  2497. #endif
  2498. }
  2499. BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
  2500. }
  2501. bool CWeaponCSBase::Reload()
  2502. {
  2503. m_bFiredOutOfAmmoEvent = false;
  2504. m_bReloadVisuallyComplete = false;
  2505. #ifdef IRONSIGHT
  2506. m_iIronSightMode = IronSight_should_approach_unsighted;
  2507. #endif //IRONSIGHT
  2508. return true;//BaseClass::Reload();
  2509. }
  2510. void CWeaponCSBase::Spawn()
  2511. {
  2512. m_nWeaponID = WeaponIdFromString( GetClassname() );
  2513. BaseClass::Spawn();
  2514. // Override the bloat that our base class sets as it's a little bit bigger than we want.
  2515. // If it's too big, you drop a weapon and its box is so big that you're still touching it
  2516. // when it falls and you pick it up again right away.
  2517. CollisionProp()->UseTriggerBounds( true, 30 );
  2518. // Set this here to allow players to shoot dropped weapons
  2519. SetCollisionGroup( COLLISION_GROUP_WEAPON );
  2520. SetExtraAmmoCount( m_iDefaultExtraAmmo ); //Start with no additional ammo
  2521. ResetGunHeat();
  2522. m_nextOwnerTouchTime = 0.0f;
  2523. m_nextPrevOwnerTouchTime = 0.0f;
  2524. m_hPrevOwner = NULL;
  2525. // [tj] initialize donor of this weapon
  2526. m_donor = NULL;
  2527. m_donated = false;
  2528. m_bSilencerOn = HasSilencer();
  2529. m_weaponMode = HasSilencer() ? Secondary_Mode : Primary_Mode;
  2530. VisibilityMonitor_AddEntity( this, 400.0f, NULL, NULL );
  2531. #ifdef IRONSIGHT
  2532. UpdateIronSightController();
  2533. #endif //IRONSIGHT
  2534. #ifndef CLIENT_DLL
  2535. if ( mp_death_drop_gun.GetInt() == 0 && !IsA( WEAPON_C4 ) )
  2536. {
  2537. SetContextThink( &CWeaponCSBase::RemoveUnownedWeaponThink, gpGlobals->curtime + REMOVEUNOWNEDWEAPON_THINK_INTERVAL, REMOVEUNOWNEDWEAPON_THINK_CONTEXT );
  2538. }
  2539. #endif
  2540. }
  2541. bool CWeaponCSBase::DefaultReload( int iClipSize1, int iClipSize2, int iActivity )
  2542. {
  2543. if ( BaseClass::DefaultReload( iClipSize1, iClipSize2, iActivity ) )
  2544. {
  2545. SendActivityEvents();
  2546. return true;
  2547. }
  2548. else
  2549. {
  2550. return false;
  2551. }
  2552. }
  2553. void CWeaponCSBase::SendActivityEvents( int nActEvents )
  2554. {
  2555. CCSPlayer *pPlayer = dynamic_cast< CCSPlayer* >( GetOwner() );
  2556. if ( !pPlayer )
  2557. return;
  2558. // Send a message to any clients that have this entity to play the reload.
  2559. CPASFilter filter( pPlayer->GetAbsOrigin() );
  2560. filter.RemoveRecipient( pPlayer );
  2561. CCSUsrMsg_ReloadEffect msg;
  2562. msg.set_entidx( pPlayer->entindex() );
  2563. msg.set_actanim( nActEvents );
  2564. const Vector& origin = pPlayer->GetAbsOrigin();
  2565. msg.set_origin_x( origin.x );
  2566. msg.set_origin_y( origin.y );
  2567. msg.set_origin_z( origin.z );
  2568. SendUserMessage( filter, CS_UM_ReloadEffect, msg );
  2569. if ( nActEvents == ACT_VM_RELOAD || nActEvents == ACT_SECONDARY_VM_RELOAD )
  2570. {
  2571. // Make the player play his reload animation.
  2572. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD );
  2573. }
  2574. }
  2575. #endif
  2576. bool CWeaponCSBase::DefaultPistolReload()
  2577. {
  2578. CCSPlayer *pPlayer = GetPlayerOwner();
  2579. if ( !pPlayer )
  2580. return false;
  2581. if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0 )
  2582. return true;
  2583. if ( !DefaultReload( GetCSWpnData().iDefaultClip1, 0, ACT_VM_RELOAD ) )
  2584. return false;
  2585. pPlayer->m_iShotsFired = 0;
  2586. return true;
  2587. }
  2588. bool CWeaponCSBase::IsUseable()
  2589. {
  2590. CCSPlayer *pPlayer = GetPlayerOwner();
  2591. if ( !pPlayer )
  2592. return false;
  2593. if ( Clip1() <= 0 )
  2594. {
  2595. if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0 && GetMaxClip1() != -1 )
  2596. {
  2597. // clip is empty ( or nonexistant ) and the player has no more ammo of this type.
  2598. return false;
  2599. }
  2600. }
  2601. return true;
  2602. }
  2603. #if defined( CLIENT_DLL )
  2604. float g_lateralBob = 0;
  2605. float g_verticalBob = 0;
  2606. static ConVar cl_bob_version( "cl_bob_version","0", FCVAR_CHEAT );
  2607. static ConVar cl_bobcycle( "cl_bobcycle","0.98", FCVAR_ARCHIVE, "the frequency at which the viewmodel bobs.", true, 0.1, true, 2.0 );
  2608. //static ConVar cl_bob( "cl_bob","0.002", FCVAR_ARCHIVE );
  2609. static ConVar cl_bobup( "cl_bobup","0.5", FCVAR_CHEAT );
  2610. ConVar cl_use_new_headbob( "cl_use_new_headbob","1", FCVAR_CHEAT );
  2611. static ConVar cl_bobamt_vert( "cl_bobamt_vert","0.25", FCVAR_ARCHIVE, "The amount the viewmodel moves up and down when running", true, 0.1, true, 2 );
  2612. static ConVar cl_bobamt_lat( "cl_bobamt_lat","0.4", FCVAR_ARCHIVE, "The amount the viewmodel moves side to side when running", true, 0.1, true, 2 );
  2613. static ConVar cl_bob_lower_amt( "cl_bob_lower_amt","21", FCVAR_ARCHIVE, "The amount the viewmodel lowers when running", true, 5, true, 30 );
  2614. static ConVar cl_viewmodel_shift_left_amt( "cl_viewmodel_shift_left_amt","1.5", FCVAR_ARCHIVE, "The amount the viewmodel shifts to the left when shooting accuracy increases.", true, 0.5, true, 2.0 );
  2615. static ConVar cl_viewmodel_shift_right_amt( "cl_viewmodel_shift_right_amt","0.75", FCVAR_ARCHIVE, "The amount the viewmodel shifts to the right when shooting accuracy decreases.", true, 0.25, true, 2.0 );
  2616. //-----------------------------------------------------------------------------
  2617. // Purpose: Helper function to calculate head bob
  2618. //-----------------------------------------------------------------------------
  2619. float CalcViewModelBobHelper( CBasePlayer *player, BobState_t *pBobState, int nVMIndex )
  2620. {
  2621. if ( cl_use_new_headbob.GetBool() == false )
  2622. return 0;
  2623. Assert( pBobState );
  2624. if ( !pBobState )
  2625. return 0;
  2626. float cycle;
  2627. //NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it
  2628. if ( ( !gpGlobals->frametime ) || ( player == NULL ) )
  2629. {
  2630. //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
  2631. return 0.0f;// just use old value
  2632. }
  2633. //Find the speed of the player
  2634. float speed = player->GetLocalVelocity().Length2D();
  2635. // do the dip before speed gets clamped
  2636. float flSpeedFactor;
  2637. float flRunAddAmt = 0.0f;
  2638. float flmaxSpeedDelta = MAX( 0, (gpGlobals->curtime - pBobState->m_flLastBobTime ) * 640.0f );//320
  2639. // Msg( "speed raw = %f\n", speed );
  2640. // don't allow too big speed changes
  2641. speed = clamp( speed, pBobState->m_flLastSpeed-flmaxSpeedDelta, pBobState->m_flLastSpeed+flmaxSpeedDelta );
  2642. speed = clamp( speed, -320.0f, 320.0f );
  2643. pBobState->m_flLastSpeed = speed;
  2644. C_BaseViewModel *pViewModel = player ? player->GetViewModel(nVMIndex) : NULL;
  2645. bool bShouldIgnoreOffsetAndAccuracy = (pViewModel && pViewModel->m_bShouldIgnoreOffsetAndAccuracy);
  2646. // when the player is moving forward, the gun lowers a bit -mtw
  2647. C_CSPlayer *pPlayer = ToCSPlayer( player );
  2648. if ( pPlayer && !pPlayer->IsZoomed() )
  2649. {
  2650. flSpeedFactor = speed * 0.006f;
  2651. clamp( flSpeedFactor, 0.0f, 0.5f );
  2652. float flLowerAmt = cl_bob_lower_amt.GetFloat() * 0.2;
  2653. // HACK until we get 'ACT_VM_IDLE_LOWERED' anims
  2654. //if ( pPlayer->m_Shared.IsSprinting() )
  2655. //flLowerAmt *= 10.0f;
  2656. if ( bShouldIgnoreOffsetAndAccuracy )
  2657. flLowerAmt *= 0.1;
  2658. flRunAddAmt = ( flLowerAmt * flSpeedFactor );
  2659. }
  2660. //FIXME: This maximum speed value must come from the server.
  2661. // MaxSpeed() is not sufficient for dealing with sprinting - jdw
  2662. float bob_offset = RemapVal( speed, 0.0f, 320.0f, 0.0f, 1.0f );
  2663. pBobState->m_flBobTime += ( gpGlobals->curtime - pBobState->m_flLastBobTime ) * bob_offset;
  2664. pBobState->m_flLastBobTime = gpGlobals->curtime;
  2665. //Msg( "speed = %f\n", speed );
  2666. float flBobCycle = 0.5f;
  2667. float flAccuracyDiff = 0;
  2668. float flGunAccPos = 0;
  2669. CWeaponCSBase *pWeapon = ( ( bShouldIgnoreOffsetAndAccuracy || !pPlayer ) ? NULL : pPlayer->GetActiveCSWeapon() );
  2670. if ( pPlayer && pWeapon )
  2671. {
  2672. float flMaxSpeed = pWeapon->GetMaxSpeed();
  2673. flBobCycle = (((1000.0f - flMaxSpeed) / 3.5f) * 0.001f) * cl_bobcycle.GetFloat();
  2674. float flAccuracy = 0.0f;
  2675. bool bIsElites = ( pWeapon->GetCSWeaponID() == WEAPON_ELITE ) ? true : false;
  2676. // don't move the gun around based on accuracy when reloading
  2677. if ( !pWeapon->m_bInReload && !bIsElites )
  2678. {
  2679. // move the gun left or right based on the players current accuracy
  2680. float flCrouchAccuracy = pWeapon->GetInaccuracyCrouch();
  2681. float flBaseAccuracy = pWeapon->GetInaccuracyStand();
  2682. if ( pPlayer->m_Local.m_bDucking || pPlayer->m_Local.m_bDucked )
  2683. flAccuracy = flCrouchAccuracy;
  2684. else
  2685. flAccuracy = pWeapon->GetInaccuracy();
  2686. bool bIsSniper = ( pWeapon->GetWeaponType() == WEAPONTYPE_SNIPER_RIFLE ) ? true : false;
  2687. float flMultiplier = 1;
  2688. if ( flAccuracy < flBaseAccuracy )
  2689. {
  2690. if ( !bIsSniper )
  2691. flMultiplier = 18;
  2692. else
  2693. flMultiplier = 0.15;
  2694. flMultiplier *= cl_viewmodel_shift_left_amt.GetFloat();
  2695. }
  2696. else
  2697. {
  2698. flAccuracy = MIN( flAccuracy, 0.082f );
  2699. flMultiplier *= cl_viewmodel_shift_right_amt.GetFloat();
  2700. }
  2701. // clamp the crouch accuracy
  2702. flAccuracyDiff = MAX( (flAccuracy - flBaseAccuracy) * flMultiplier, -0.1);
  2703. }
  2704. /*
  2705. if ( pWeapon->m_flGunAccuracyPosition > 0.0f )
  2706. Msg( "m_flGunAccuracyPosition1 = %f, flAccuracy = %f\n", pWeapon->m_flGunAccuracyPosition, flAccuracy );
  2707. pWeapon->m_flGunAccuracyPosition = Lerp( ( gpGlobals->frametime / 0.02f ), (flAccuracyDiff*20), pWeapon->m_flGunAccuracyPosition );
  2708. if ( pWeapon->m_flGunAccuracyPosition > 0.0f )
  2709. Msg( "m_flGunAccuracyPosition1 = %f, flAccuracy = %f\n", pWeapon->m_flGunAccuracyPosition, flAccuracy );
  2710. */
  2711. pWeapon->m_flGunAccuracyPosition = Approach( (flAccuracyDiff*80), pWeapon->m_flGunAccuracyPosition, abs( ( (flAccuracyDiff*80)-pWeapon->m_flGunAccuracyPosition )*gpGlobals->frametime ) * 4.0f );
  2712. flGunAccPos = pWeapon->m_flGunAccuracyPosition;
  2713. }
  2714. else
  2715. {
  2716. flBobCycle = (((1000.0f - 150) / 3.5f) * 0.001f) * cl_bobcycle.GetFloat();
  2717. }
  2718. //Msg( "flBobCycle = %f\n", flBobCycle );
  2719. //Calculate the vertical bob
  2720. cycle = pBobState->m_flBobTime - (int)(pBobState->m_flBobTime/flBobCycle)*flBobCycle;
  2721. cycle /= flBobCycle;
  2722. if ( cycle < cl_bobup.GetFloat() )
  2723. {
  2724. cycle = M_PI * cycle / cl_bobup.GetFloat();
  2725. }
  2726. else
  2727. {
  2728. cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat());
  2729. }
  2730. float flBobMultiplier = 0.00625f;
  2731. // if we're in the air, slow our bob down a bit
  2732. if ( player->GetGroundEntity() == NULL )
  2733. flBobMultiplier = 0.00125f;
  2734. float flBobVert = bShouldIgnoreOffsetAndAccuracy ? 0.3 : cl_bobamt_vert.GetFloat();
  2735. pBobState->m_flVerticalBob = speed*( flBobMultiplier * flBobVert );
  2736. pBobState->m_flVerticalBob = ( pBobState->m_flVerticalBob*0.3 + pBobState->m_flVerticalBob*0.7*sin(cycle) );
  2737. pBobState->m_flRawVerticalBob = pBobState->m_flVerticalBob;
  2738. pBobState->m_flVerticalBob = clamp( ( pBobState->m_flVerticalBob - ( flRunAddAmt - (flGunAccPos*0.2) ) ), -7.0f, 4.0f );
  2739. //Msg( "pBobState->m_flVerticalBob = %f, cycle = %f, pBobState->m_flBobTime = %f\n", pBobState->m_flVerticalBob, cycle, pBobState->m_flBobTime );
  2740. //Calculate the lateral bob
  2741. cycle = pBobState->m_flBobTime - (int)(pBobState->m_flBobTime/flBobCycle*2)*flBobCycle*2;
  2742. cycle /= flBobCycle*2;
  2743. if ( cycle < cl_bobup.GetFloat() )
  2744. {
  2745. cycle = M_PI * cycle / cl_bobup.GetFloat();
  2746. }
  2747. else
  2748. {
  2749. cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat());
  2750. }
  2751. float flBobLat = bShouldIgnoreOffsetAndAccuracy ? 0.5 : cl_bobamt_lat.GetFloat();
  2752. if ( pPlayer && pWeapon )
  2753. {
  2754. pBobState->m_flLateralBob = speed*( flBobMultiplier * flBobLat );
  2755. pBobState->m_flLateralBob = pBobState->m_flLateralBob*0.3 + pBobState->m_flLateralBob*0.7*sin(cycle);
  2756. pBobState->m_flRawLateralBob = pBobState->m_flLateralBob;
  2757. pBobState->m_flLateralBob = clamp( (pBobState->m_flLateralBob + flGunAccPos*0.25), -8.0f, 8.0f );
  2758. //Msg( "flAccuracyDiff = %f\n", flAccuracyDiff );
  2759. }
  2760. //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
  2761. return 0.0f;
  2762. }
  2763. //-----------------------------------------------------------------------------
  2764. // Purpose: Helper function to add head bob
  2765. //-----------------------------------------------------------------------------
  2766. void AddViewModelBobHelper( Vector &origin, QAngle &angles, BobState_t *pBobState )
  2767. {
  2768. if ( cl_use_new_headbob.GetBool() == false )
  2769. return;
  2770. Assert( pBobState );
  2771. if ( !pBobState )
  2772. return;
  2773. Vector forward, right;
  2774. AngleVectors( angles, &forward, &right, NULL );
  2775. // Apply bob, but scaled down to 40%
  2776. VectorMA( origin, pBobState->m_flVerticalBob * 0.4f, forward, origin );
  2777. // Z bob a bit more
  2778. origin[2] += pBobState->m_flVerticalBob * 0.1f;
  2779. // bob the angles
  2780. angles[ ROLL ] += pBobState->m_flVerticalBob * 0.5f;
  2781. angles[ PITCH ] -= pBobState->m_flVerticalBob * 0.4f;
  2782. angles[ YAW ] -= pBobState->m_flLateralBob * 0.3f;
  2783. VectorMA( origin, pBobState->m_flLateralBob * 0.2f, right, origin );
  2784. }
  2785. //-----------------------------------------------------------------------------
  2786. // Purpose:
  2787. // Output : float
  2788. //-----------------------------------------------------------------------------
  2789. float CWeaponCSBase::CalcViewmodelBob( void )
  2790. {
  2791. if ( cl_use_new_headbob.GetBool() == true )
  2792. {
  2793. CBasePlayer *player = ToBasePlayer( GetOwner() );
  2794. //Assert( player );
  2795. BobState_t *pBobState = GetBobState();
  2796. if ( pBobState )
  2797. {
  2798. return ::CalcViewModelBobHelper( player, pBobState );
  2799. }
  2800. else
  2801. return 0;
  2802. }
  2803. static float bobtime;
  2804. static float lastbobtime;
  2805. static float lastspeed;
  2806. float cycle;
  2807. CBasePlayer *player = ToBasePlayer( GetOwner() );
  2808. //Assert( player );
  2809. //NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it
  2810. if ( ( !gpGlobals->frametime ) ||
  2811. ( player == NULL ) ||
  2812. ( cl_bobcycle.GetFloat() <= 0.0f ) ||
  2813. ( cl_bobup.GetFloat() <= 0.0f ) ||
  2814. ( cl_bobup.GetFloat() >= 1.0f ) )
  2815. {
  2816. //NOTENOTE: We don't use this return value in our case ( need to restructure the calculation function setup! )
  2817. return 0.0f;// just use old value
  2818. }
  2819. //Find the speed of the player
  2820. float speed = player->GetLocalVelocity().Length2D();
  2821. float flmaxSpeedDelta = MAX( 0, ( gpGlobals->curtime - lastbobtime ) * 320.0f );
  2822. // don't allow too big speed changes
  2823. speed = clamp( speed, lastspeed-flmaxSpeedDelta, lastspeed+flmaxSpeedDelta );
  2824. speed = clamp( speed, -320, 320 );
  2825. lastspeed = speed;
  2826. //FIXME: This maximum speed value must come from the server.
  2827. // MaxSpeed() is not sufficient for dealing with sprinting - jdw
  2828. float bob_offset = RemapVal( speed, 0, 320, 0.0f, 1.0f );
  2829. bobtime += ( gpGlobals->curtime - lastbobtime ) * bob_offset;
  2830. lastbobtime = gpGlobals->curtime;
  2831. //Calculate the vertical bob
  2832. cycle = bobtime - ( int )( bobtime/cl_bobcycle.GetFloat() )*cl_bobcycle.GetFloat();
  2833. cycle /= cl_bobcycle.GetFloat();
  2834. if ( cycle < cl_bobup.GetFloat() )
  2835. {
  2836. cycle = M_PI * cycle / cl_bobup.GetFloat();
  2837. }
  2838. else
  2839. {
  2840. cycle = M_PI + M_PI*( cycle-cl_bobup.GetFloat() )/( 1.0 - cl_bobup.GetFloat() );
  2841. }
  2842. g_verticalBob = speed*0.005f;
  2843. g_verticalBob = g_verticalBob*0.3 + g_verticalBob*0.7*sin( cycle );
  2844. g_verticalBob = clamp( g_verticalBob, -7.0f, 4.0f );
  2845. //Calculate the lateral bob
  2846. cycle = bobtime - ( int )( bobtime/cl_bobcycle.GetFloat()*2 )*cl_bobcycle.GetFloat()*2;
  2847. cycle /= cl_bobcycle.GetFloat()*2;
  2848. if ( cycle < cl_bobup.GetFloat() )
  2849. {
  2850. cycle = M_PI * cycle / cl_bobup.GetFloat();
  2851. }
  2852. else
  2853. {
  2854. cycle = M_PI + M_PI*( cycle-cl_bobup.GetFloat() )/( 1.0 - cl_bobup.GetFloat() );
  2855. }
  2856. g_lateralBob = speed*0.005f;
  2857. g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin( cycle );
  2858. g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f );
  2859. //NOTENOTE: We don't use this return value in our case ( need to restructure the calculation function setup! )
  2860. return 0.0f;
  2861. }
  2862. //-----------------------------------------------------------------------------
  2863. // Purpose:
  2864. // Input : &origin -
  2865. // &angles -
  2866. // viewmodelindex -
  2867. //-----------------------------------------------------------------------------
  2868. void CWeaponCSBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
  2869. {
  2870. if ( cl_use_new_headbob.GetBool() == true )
  2871. {
  2872. // call helper functions to do the calculation
  2873. BobState_t *pBobState = GetBobState();
  2874. if ( pBobState )
  2875. {
  2876. CalcViewmodelBob();
  2877. ::AddViewModelBobHelper( origin, angles, pBobState );
  2878. }
  2879. return;
  2880. }
  2881. Vector forward, right;
  2882. AngleVectors( angles, &forward, &right, NULL );
  2883. CalcViewmodelBob();
  2884. // Apply bob, but scaled down to 40%
  2885. VectorMA( origin, g_verticalBob * 0.4f, forward, origin );
  2886. // Z bob a bit more
  2887. origin[2] += g_verticalBob * 0.1f;
  2888. // bob the angles
  2889. angles[ ROLL ] += g_verticalBob * 0.5f;
  2890. angles[ PITCH ] -= g_verticalBob * 0.4f;
  2891. angles[ YAW ] -= g_lateralBob * 0.3f;
  2892. // VectorMA( origin, g_lateralBob * 0.2f, right, origin );
  2893. }
  2894. //-----------------------------------------------------------------------------
  2895. // Purpose: Returns the head bob state for this weapon, which is stored
  2896. // in the view model. Note that this this function can return
  2897. // NULL if the player is dead or the view model is otherwise not present.
  2898. //-----------------------------------------------------------------------------
  2899. BobState_t *CWeaponCSBase::GetBobState()
  2900. {
  2901. // get the view model for this weapon
  2902. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  2903. if ( pOwner == NULL )
  2904. return NULL;
  2905. CBaseViewModel *baseViewModel = pOwner->GetViewModel( m_nViewModelIndex );
  2906. if ( baseViewModel == NULL )
  2907. return NULL;
  2908. CPredictedViewModel *viewModel = dynamic_cast<CPredictedViewModel *>(baseViewModel);
  2909. if ( viewModel == NULL )
  2910. return NULL;
  2911. //Assert( viewModel );
  2912. // get the bob state out of the view model
  2913. return &( viewModel->GetBobState() );
  2914. }
  2915. #else
  2916. void CWeaponCSBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
  2917. {
  2918. }
  2919. float CWeaponCSBase::CalcViewmodelBob( void )
  2920. {
  2921. return 0.0f;
  2922. }
  2923. #endif
  2924. #ifndef CLIENT_DLL
  2925. bool CWeaponCSBase::PhysicsSplash( const Vector &centerPoint, const Vector &normal, float rawSpeed, float scaledSpeed )
  2926. {
  2927. if ( rawSpeed > 20 )
  2928. {
  2929. float size = 4.0f;
  2930. if ( !IsPistol() )
  2931. size += 2.0f;
  2932. // adjust splash size based on speed
  2933. size += RemapValClamped( rawSpeed, 0, 400, 0, 3 );
  2934. CEffectData data;
  2935. data.m_vOrigin = centerPoint;
  2936. data.m_vNormal = normal;
  2937. data.m_flScale = random->RandomFloat( size, size + 1.0f );
  2938. if ( GetWaterType() & CONTENTS_SLIME )
  2939. {
  2940. data.m_fFlags |= FX_WATER_IN_SLIME;
  2941. }
  2942. DispatchEffect( "gunshotsplash", data );
  2943. return true;
  2944. }
  2945. return false;
  2946. }
  2947. #endif // !CLIENT_DLL
  2948. //-----------------------------------------------------------------------------
  2949. // Purpose:
  2950. // Input : *pPicker -
  2951. //-----------------------------------------------------------------------------
  2952. void CWeaponCSBase::OnPickedUp( CBaseCombatCharacter *pNewOwner )
  2953. {
  2954. #if !defined( CLIENT_DLL )
  2955. RemoveEffects( EF_ITEM_BLINK );
  2956. if( pNewOwner->IsPlayer() && pNewOwner->IsAlive() )
  2957. {
  2958. m_OnPlayerPickup.FireOutput( pNewOwner, this );
  2959. m_bFiredOutOfAmmoEvent = false;
  2960. // Robin: We don't want to delete weapons the player has picked up, so
  2961. // clear the name of the weapon. This prevents wildcards that are meant
  2962. // to find NPCs finding weapons dropped by the NPCs as well.
  2963. SetName( NULL_STRING );
  2964. CEconEntity *pEconEntity = dynamic_cast< CEconEntity* >( this );
  2965. if ( pEconEntity && m_hPrevOwner == NULL )
  2966. {
  2967. CCSPlayer *pPlayer = ToCSPlayer( pNewOwner );
  2968. // set the original owner XUID
  2969. if ( pPlayer && pEconEntity->GetOriginalOwnerXuid() == 0ull && !pPlayer->IsBot() )
  2970. {
  2971. CSteamID steamID;
  2972. pPlayer->GetSteamID( &steamID );
  2973. uint64 verylong = steamID.ConvertToUint64();
  2974. pEconEntity->SetOriginalOwnerXuid( (uint32)verylong, (uint32)(verylong >> 32) );
  2975. }
  2976. m_iOriginalTeamNumber = pPlayer ? pPlayer->GetTeamNumber() : 0;
  2977. }
  2978. if ( CSGameRules() )
  2979. CSGameRules()->RemoveDroppedWeaponFromList( this );
  2980. }
  2981. // Someone picked me up, so make it so that I can't be removed.
  2982. SetRemoveable( false );
  2983. #else
  2984. UpdateOutlineGlow();
  2985. #endif
  2986. #ifdef IRONSIGHT
  2987. UpdateIronSightController();
  2988. #endif //IRONSIGHT
  2989. }
  2990. void CWeaponCSBase::UpdateAccuracyPenalty( )
  2991. {
  2992. CCSPlayer *pPlayer = GetPlayerOwner( );
  2993. if ( !pPlayer )
  2994. return;
  2995. const CCSWeaponInfo& weaponInfo = GetCSWpnData( );
  2996. float fNewPenalty = 0.0f;
  2997. // Adding movement penalty here results in a penalty that persists and requires decay to eliminate.
  2998. #if MOVEMENT_ACCURACY_DECAYED
  2999. // movement penalty
  3000. fNewPenalty += RemapValClamped( pPlayer->GetAbsVelocity().Length2D(),
  3001. weaponInfo.GetMaxSpeed(m_weaponMode, GetEconItemView()) * CS_PLAYER_SPEED_DUCK_MODIFIER,
  3002. weaponInfo.GetMaxSpeed(m_weaponMode, GetEconItemView()) * 0.95f, // max out at 95% of run speed to avoid jitter near max speed
  3003. 0.0f, weaponInfo.GetInaccuracyMove( m_weaponMode, GetEconItemView( ) );
  3004. #endif
  3005. // on ladder?
  3006. if ( pPlayer->GetMoveType( ) == MOVETYPE_LADDER )
  3007. {
  3008. fNewPenalty += weaponInfo.GetInaccuracyLadder( GetEconItemView( ), m_weaponMode ) + weaponInfo.GetInaccuracyLadder( GetEconItemView( ), Primary_Mode );
  3009. }
  3010. // in the air?
  3011. else if ( pPlayer->GetGroundEntity() == nullptr )
  3012. // else if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
  3013. {
  3014. fNewPenalty += weaponInfo.GetInaccuracyStand( GetEconItemView(), m_weaponMode );
  3015. fNewPenalty += weaponInfo.GetInaccuracyJump( GetEconItemView(), m_weaponMode ) * weapon_air_spread_scale.GetFloat();
  3016. }
  3017. else if ( FBitSet( pPlayer->GetFlags( ), FL_DUCKING ) )
  3018. {
  3019. fNewPenalty += weaponInfo.GetInaccuracyCrouch( GetEconItemView( ), m_weaponMode );
  3020. }
  3021. else
  3022. {
  3023. fNewPenalty += weaponInfo.GetInaccuracyStand( GetEconItemView( ), m_weaponMode );
  3024. }
  3025. if ( m_bInReload )
  3026. {
  3027. fNewPenalty += weaponInfo.GetInaccuracyReload( GetEconItemView( ) );
  3028. }
  3029. if ( fNewPenalty > m_fAccuracyPenalty )
  3030. {
  3031. m_fAccuracyPenalty = fNewPenalty;
  3032. }
  3033. else
  3034. {
  3035. float fDecayFactor = logf( 10.0f ) / GetRecoveryTime( );
  3036. m_fAccuracyPenalty = Lerp( expf( TICK_INTERVAL * -fDecayFactor ), fNewPenalty, ( float ) m_fAccuracyPenalty );
  3037. }
  3038. #define WEAPON_RECOIL_DECAY_THRESHOLD 1.10
  3039. // Decay the recoil index if a little more than cycle time has elapsed since the last shot. In other words,
  3040. // don't decay if we're firing full-auto.
  3041. if ( gpGlobals->curtime > m_fLastShotTime + ( GetCycleTime() * WEAPON_RECOIL_DECAY_THRESHOLD ) )
  3042. {
  3043. float fDecayFactor = logf( 10.0f ) * weapon_recoil_decay_coefficient.GetFloat( );
  3044. m_flRecoilIndex = Lerp( expf( TICK_INTERVAL * -fDecayFactor ), 0.0f, ( float ) m_flRecoilIndex );
  3045. }
  3046. }
  3047. float CWeaponCSBase::GetRecoveryTime( void )
  3048. {
  3049. CCSPlayer *pPlayer = GetPlayerOwner( );
  3050. if ( !pPlayer )
  3051. return -1.0f;
  3052. const CCSWeaponInfo& weaponInfo = GetCSWpnData( );
  3053. if ( pPlayer->GetMoveType( ) == MOVETYPE_LADDER )
  3054. {
  3055. return weaponInfo.GetRecoveryTimeStand( GetEconItemView( ) );
  3056. }
  3057. else if ( !FBitSet( pPlayer->GetFlags( ), FL_ONGROUND ) ) // in air
  3058. {
  3059. // enforce a large recovery speed penalty (400%) for players in the air; this helps to provide
  3060. // comparable in-air accuracy to the old weapon model
  3061. return weaponInfo.GetRecoveryTimeCrouch( GetEconItemView( ) ) * 4.0f;
  3062. }
  3063. else if ( FBitSet( pPlayer->GetFlags( ), FL_DUCKING ) )
  3064. {
  3065. float flRecoveryTime = weaponInfo.GetRecoveryTimeCrouch( GetEconItemView( ) );
  3066. float flRecoveryTimeFinal = weaponInfo.GetRecoveryTimeCrouchFinal( GetEconItemView( ) );
  3067. if ( flRecoveryTimeFinal != -1.0f ) // uninitialized final recovery values are set to -1.0 from the weapon_base prefab in schema
  3068. {
  3069. int nRecoilIndex = m_flRecoilIndex;
  3070. flRecoveryTime = RemapValClamped( nRecoilIndex, weaponInfo.GetRecoveryTransitionStartBullet( GetEconItemView( ) ), weaponInfo.GetRecoveryTransitionEndBullet( GetEconItemView( ) ), flRecoveryTime, flRecoveryTimeFinal );
  3071. }
  3072. return flRecoveryTime;
  3073. }
  3074. else
  3075. {
  3076. float flRecoveryTime = weaponInfo.GetRecoveryTimeStand( GetEconItemView( ) );
  3077. float flRecoveryTimeFinal = weaponInfo.GetRecoveryTimeStandFinal( GetEconItemView( ) );
  3078. if ( flRecoveryTimeFinal != -1.0f ) // uninitialized final recovery values are set to -1.0 from the weapon_base prefab in schema
  3079. {
  3080. int nRecoilIndex = m_flRecoilIndex;
  3081. flRecoveryTime = RemapValClamped( nRecoilIndex, weaponInfo.GetRecoveryTransitionStartBullet( GetEconItemView( ) ), weaponInfo.GetRecoveryTransitionEndBullet( GetEconItemView( ) ), flRecoveryTime, flRecoveryTimeFinal );
  3082. }
  3083. return flRecoveryTime;
  3084. }
  3085. }
  3086. void CWeaponCSBase::OnJump( float fImpulse )
  3087. {
  3088. }
  3089. void CWeaponCSBase::OnLand( float fVelocity )
  3090. {
  3091. float fPenalty = GetCSWpnData().GetInaccuracyLand( GetEconItemView(), m_weaponMode ) * fVelocity;
  3092. m_fAccuracyPenalty += fPenalty;
  3093. fPenalty = clamp( fPenalty, -1.0f, 1.0f );
  3094. CCSPlayer *pPlayer = GetPlayerOwner();
  3095. if ( !pPlayer )
  3096. return;
  3097. // NOTE: do NOT call GetAimPunchAngle() here because it may be adjusted by some recoil scalar.
  3098. // We just want to update the raw punch angle.
  3099. QAngle angle = pPlayer->GetRawAimPunchAngle();
  3100. float fVKick = RAD2DEG(asinf(fPenalty)) * 0.2f;
  3101. float fHKick = SharedRandomFloat("LandPunchAngleYaw", -1.0f, +1.0f) * fVKick * 0.1f;
  3102. angle.x += fVKick; // pitch
  3103. angle.y += fHKick; // yaw
  3104. pPlayer->SetAimPunchAngle( angle );
  3105. }
  3106. void CWeaponCSBase::Recoil( CSWeaponMode weaponMode )
  3107. {
  3108. /** Removed for partner depot **/
  3109. }
  3110. #ifdef CLIENT_DLL
  3111. void WeaponSaveCustomTextures( void )
  3112. {
  3113. C_BasePlayer *local = C_BasePlayer::GetLocalPlayer();
  3114. if ( local )
  3115. {
  3116. CWeaponCSBase *pWeapon = ( CWeaponCSBase* )local->GetActiveWeapon();
  3117. pWeapon->SaveCustomMaterialsTextures();
  3118. }
  3119. }
  3120. ConCommand cl_saveweaponcustomtextures( "cl_saveweaponcustomtextures", WeaponSaveCustomTextures, "Save custom textures of current weapon." );
  3121. void CWeaponCSBase::SaveCustomMaterialsTextures( )
  3122. {
  3123. /** Removed for partner depot **/
  3124. }
  3125. void CWeaponCSBase::UpdateCustomMaterial( void )
  3126. {
  3127. /** Removed for partner depot **/
  3128. }
  3129. void CWeaponCSBase::CheckCustomMaterial( void )
  3130. {
  3131. /** Removed for partner depot **/
  3132. }
  3133. #endif // CLIENT_DLL
  3134. #ifdef IRONSIGHT
  3135. CIronSightController *CWeaponCSBase::GetIronSightController( void )
  3136. {
  3137. if ( m_IronSightController && m_IronSightController->IsInitializedAndAvailable() )
  3138. {
  3139. return m_IronSightController;
  3140. }
  3141. return NULL;
  3142. }
  3143. void CWeaponCSBase::UpdateIronSightController()
  3144. {
  3145. if (!m_IronSightController)
  3146. m_IronSightController = new CIronSightController();
  3147. if (m_IronSightController)
  3148. m_IronSightController->Init(this);
  3149. }
  3150. #endif
  3151. int CWeaponCSBase::GetZoomFOV( int nZoomLevel ) const
  3152. {
  3153. switch( nZoomLevel )
  3154. {
  3155. case 0: return 0; // not used -- always default FoV
  3156. case 1: return GetCSWpnData().GetZoomFOV1();
  3157. case 2: return GetCSWpnData().GetZoomFOV2();
  3158. default: Assert(0); return 0;
  3159. }
  3160. }
  3161. float CWeaponCSBase::GetZoomTime( int nZoomLevel ) const
  3162. {
  3163. switch ( nZoomLevel )
  3164. {
  3165. case 0: return GetCSWpnData().GetZoomTime0();
  3166. case 1: return GetCSWpnData().GetZoomTime1();
  3167. case 2: return GetCSWpnData().GetZoomTime2();
  3168. default: Assert( 0 ); return 0;
  3169. }
  3170. }
  3171. CCSPlayer * CWeaponCSBase::GetOriginalOwner()
  3172. {
  3173. if ( m_PriorOwners.Count() )
  3174. return m_PriorOwners.Element( 0 );
  3175. return NULL;
  3176. }