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.

1441 lines
54 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include <keyvalues.h>
  8. #include "cs_weapon_parse.h"
  9. #include "cs_shareddefs.h"
  10. #include "weapon_csbase.h"
  11. #include "weapon_csbasegun.h"
  12. #include "icvar.h"
  13. #include "cs_gamerules.h"
  14. #include "ihasattributes.h"
  15. // NOTE: This has to be the last file included!
  16. #include "tier0/memdbgon.h"
  17. //--------------------------------------------------------------------------------------------------------
  18. struct WeaponTypeInfo
  19. {
  20. CSWeaponType type;
  21. const char * name;
  22. };
  23. //--------------------------------------------------------------------------------------------------------
  24. WeaponTypeInfo s_weaponTypeInfo[] =
  25. {
  26. { WEAPONTYPE_KNIFE, "Knife" },
  27. { WEAPONTYPE_PISTOL, "Pistol" },
  28. { WEAPONTYPE_SUBMACHINEGUN, "Submachine Gun" }, // First match is printable
  29. { WEAPONTYPE_SUBMACHINEGUN, "submachinegun" },
  30. { WEAPONTYPE_SUBMACHINEGUN, "smg" },
  31. { WEAPONTYPE_RIFLE, "Rifle" },
  32. { WEAPONTYPE_SHOTGUN, "Shotgun" },
  33. { WEAPONTYPE_SNIPER_RIFLE, "SniperRifle" },
  34. { WEAPONTYPE_MACHINEGUN, "Machine Gun" }, // First match is printable
  35. { WEAPONTYPE_MACHINEGUN, "machinegun" },
  36. { WEAPONTYPE_MACHINEGUN, "mg" },
  37. { WEAPONTYPE_C4, "C4" },
  38. { WEAPONTYPE_GRENADE, "Grenade" },
  39. { WEAPONTYPE_STACKABLEITEM, "StackableItem" },
  40. };
  41. struct WeaponNameInfo
  42. {
  43. CSWeaponID id;
  44. const char *name;
  45. };
  46. // note you have to add an item here if it is a new base item that derives from another base item (like the silenced m4)
  47. WeaponNameInfo s_weaponNameInfo[] =
  48. {
  49. { WEAPON_DEAGLE, "weapon_deagle" },
  50. { WEAPON_DEAGLE, "weapon_revolver" },
  51. { WEAPON_ELITE, "weapon_elite" },
  52. { WEAPON_FIVESEVEN, "weapon_fiveseven" },
  53. { WEAPON_FIVESEVEN, "weapon_cz75a" },
  54. { WEAPON_GLOCK, "weapon_glock" },
  55. { WEAPON_P228, "weapon_p228" },
  56. { WEAPON_USP, "weapon_usp" },
  57. { WEAPON_AK47, "weapon_ak47" },
  58. { WEAPON_AUG, "weapon_aug" },
  59. { WEAPON_AWP, "weapon_awp" },
  60. { WEAPON_FAMAS, "weapon_famas" },
  61. { WEAPON_G3SG1, "weapon_g3sg1" },
  62. { WEAPON_GALIL, "weapon_galil" },
  63. { WEAPON_GALILAR, "weapon_galilar" },
  64. { WEAPON_M249, "weapon_m249" },
  65. { WEAPON_M3, "weapon_m3" },
  66. { WEAPON_M4A1, "weapon_m4a1" },
  67. { WEAPON_M4A1, "weapon_m4a1_silencer" },
  68. { WEAPON_MAC10, "weapon_mac10" },
  69. { WEAPON_MP5NAVY, "weapon_mp5navy" },
  70. { WEAPON_P90, "weapon_p90" },
  71. { WEAPON_SCOUT, "weapon_scout" },
  72. { WEAPON_SG550, "weapon_sg550" },
  73. { WEAPON_SG552, "weapon_sg552" },
  74. { WEAPON_TMP, "weapon_tmp" },
  75. { WEAPON_UMP45, "weapon_ump45" },
  76. { WEAPON_XM1014, "weapon_xm1014" },
  77. { WEAPON_BIZON, "weapon_bizon" },
  78. { WEAPON_MAG7, "weapon_mag7" },
  79. { WEAPON_NEGEV, "weapon_negev" },
  80. { WEAPON_SAWEDOFF, "weapon_sawedoff" },
  81. { WEAPON_TEC9, "weapon_tec9" },
  82. { WEAPON_TEC9, "weapon_cz75a" },
  83. { WEAPON_TASER, "weapon_taser" },
  84. { WEAPON_HKP2000, "weapon_hkp2000" },
  85. { WEAPON_MP7, "weapon_mp7" },
  86. { WEAPON_MP9, "weapon_mp9" },
  87. { WEAPON_NOVA, "weapon_nova" },
  88. { WEAPON_P250, "weapon_p250" },
  89. { WEAPON_SCAR17, "weapon_scar17" },
  90. { WEAPON_SCAR20, "weapon_scar20" },
  91. { WEAPON_SG556, "weapon_sg556" },
  92. { WEAPON_SSG08, "weapon_ssg08" },
  93. { WEAPON_KNIFE_GG, "weapon_knifegg" },
  94. { WEAPON_KNIFE, "weapon_knife" },
  95. { WEAPON_HEGRENADE, "weapon_hegrenade" },
  96. { WEAPON_SMOKEGRENADE, "weapon_smokegrenade" },
  97. { WEAPON_FLASHBANG, "weapon_flashbang" },
  98. { WEAPON_MOLOTOV, "weapon_molotov" },
  99. { WEAPON_INCGRENADE, "weapon_incgrenade" },
  100. { WEAPON_DECOY, "weapon_decoy" },
  101. { WEAPON_TAGRENADE, "weapon_tagrenade" },
  102. { WEAPON_C4, "weapon_c4" },
  103. { WEAPON_HEALTHSHOT, "weapon_healthshot" },
  104. { ITEM_KEVLAR, "item_kevlar" },
  105. { ITEM_ASSAULTSUIT, "item_assaultsuit" },
  106. { ITEM_HEAVYASSAULTSUIT, "item_heavyassaultsuit" },
  107. { ITEM_NVG, "item_nvg" },
  108. { ITEM_DEFUSER, "item_defuser" },
  109. { ITEM_CUTTERS, "item_cutters" },
  110. { WEAPON_NONE, "weapon_none" },
  111. };
  112. //--------------------------------------------------------------------------------------------------------------
  113. struct EquipmentInfo
  114. {
  115. const char* szClassName;
  116. const char* szPrintName;
  117. int iTeam;
  118. int iPrice;
  119. };
  120. EquipmentInfo g_EquipmentInfo[] =
  121. {
  122. { "item_assaultsuit", "#SFUI_WPNHUD_ASSAULTSUIT", TEAM_UNASSIGNED, ITEM_PRICE_ASSAULTSUIT },
  123. { "item_kevlar", "#SFUI_WPNHUD_KEVLAR", TEAM_UNASSIGNED, ITEM_PRICE_KEVLAR },
  124. { "item_heavyassaultsuit", "#SFUI_WPNHUD_HEAVYASSAULTSUIT", TEAM_UNASSIGNED, ITEM_PRICE_HEAVYASSAULTSUIT },
  125. { "item_defuser", "#SFUI_WPNHUD_DEFUSER", TEAM_CT, ITEM_PRICE_DEFUSEKIT },
  126. { "item_cutters", "#SFUI_WPNHUD_CUTTERS", TEAM_CT, ITEM_PRICE_DEFUSEKIT },
  127. };
  128. void LoadEquipmentData()
  129. {
  130. for ( int i = 0; i < ARRAYSIZE( g_EquipmentInfo ); ++i )
  131. {
  132. WEAPON_FILE_INFO_HANDLE handle = g_WeaponDatabase.FindOrCreateWeaponInfo(g_EquipmentInfo[i].szClassName);
  133. CCSWeaponInfo* pInfo = dynamic_cast<CCSWeaponInfo*>( g_WeaponDatabase.GetFileWeaponInfoFromHandle( handle ) );
  134. if ( pInfo )
  135. {
  136. pInfo->m_weaponId = WeaponIdFromString( pInfo->szClassName );
  137. Q_strncpy( pInfo->szClassName, g_EquipmentInfo[i].szClassName, MAX_WEAPON_STRING );
  138. Q_strncpy( pInfo->szPrintName, g_EquipmentInfo[i].szPrintName, MAX_WEAPON_STRING );
  139. pInfo->SetUsedByTeam( g_EquipmentInfo[i].iTeam );
  140. pInfo->SetWeaponPrice( g_EquipmentInfo[i].iPrice );
  141. pInfo->SetWeaponType( WEAPONTYPE_EQUIPMENT );
  142. }
  143. }
  144. }
  145. //--------------------------------------------------------------------------------------------------------------
  146. const CCSWeaponInfo* GetWeaponInfo( CSWeaponID weaponID )
  147. {
  148. if ( weaponID == WEAPON_NONE )
  149. return NULL;
  150. const char *weaponName = WeaponIdAsString( weaponID );
  151. WEAPON_FILE_INFO_HANDLE hWpnInfo = g_WeaponDatabase.FindWeaponInfo( weaponName );
  152. if ( hWpnInfo == GetInvalidWeaponInfoHandle() )
  153. {
  154. return NULL;
  155. }
  156. CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( g_WeaponDatabase.GetFileWeaponInfoFromHandle( hWpnInfo ) );
  157. return pWeaponInfo;
  158. }
  159. //--------------------------------------------------------------------------------------------------------
  160. const char* WeaponClassAsString( CSWeaponType weaponType )
  161. {
  162. for ( int i = 0; i < ARRAYSIZE( s_weaponTypeInfo ); ++i )
  163. {
  164. if ( s_weaponTypeInfo[i].type == weaponType )
  165. {
  166. return s_weaponTypeInfo[i].name;
  167. }
  168. }
  169. return NULL;
  170. }
  171. //--------------------------------------------------------------------------------------------------------
  172. CSWeaponType WeaponClassFromString( const char* weaponType )
  173. {
  174. for ( int i = 0; i < ARRAYSIZE( s_weaponTypeInfo ); ++i )
  175. {
  176. if ( !V_stricmp( s_weaponTypeInfo[i].name, weaponType ) )
  177. {
  178. return s_weaponTypeInfo[i].type;
  179. }
  180. }
  181. return WEAPONTYPE_UNKNOWN;
  182. }
  183. //--------------------------------------------------------------------------------------------------------
  184. CSWeaponType WeaponClassFromWeaponID( CSWeaponID weaponID )
  185. {
  186. const char *weaponStr = WeaponIdAsString( weaponID );
  187. WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot(weaponStr );
  188. if ( hWpnInfo != GetInvalidWeaponInfoHandle() )
  189. {
  190. CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
  191. if ( pWeaponInfo )
  192. {
  193. return pWeaponInfo->GetWeaponType();
  194. }
  195. }
  196. return WEAPONTYPE_UNKNOWN;
  197. }
  198. //--------------------------------------------------------------------------------------------------------
  199. const char * WeaponIdAsString( CSWeaponID weaponID )
  200. {
  201. for ( int i = 0; i < ARRAYSIZE( s_weaponNameInfo ); ++i )
  202. {
  203. if ( s_weaponNameInfo[i].id == weaponID )
  204. return s_weaponNameInfo[i].name;
  205. }
  206. return NULL;
  207. }
  208. //--------------------------------------------------------------------------------------------------------
  209. CSWeaponID WeaponIdFromString( const char *szWeaponName )
  210. {
  211. for ( int i = 0; i < ARRAYSIZE( s_weaponNameInfo ); ++i )
  212. {
  213. if ( V_stricmp( s_weaponNameInfo[i].name, szWeaponName ) == 0 )
  214. return s_weaponNameInfo[i].id;
  215. }
  216. return WEAPON_NONE;
  217. }
  218. //--------------------------------------------------------------------------------------------------------
  219. //
  220. // Given a weapon ID, return its alias
  221. //
  222. const char *WeaponIDToAlias( int id )
  223. {
  224. for ( int i = 0; i < ARRAYSIZE( s_weaponNameInfo ); ++i )
  225. {
  226. if ( s_weaponNameInfo[i].id == id )
  227. return ( strchr( s_weaponNameInfo[i].name, '_' ) + 1 );
  228. }
  229. return NULL;
  230. }
  231. //--------------------------------------------------------------------------------------------------------
  232. //
  233. // Given an alias, return the associated weapon ID
  234. //
  235. CSWeaponID AliasToWeaponID( const char *szAlias )
  236. {
  237. if ( !szAlias )
  238. return WEAPON_NONE;
  239. for ( int i = 0; i < ARRAYSIZE( s_weaponNameInfo ); ++i )
  240. {
  241. Assert( strchr( s_weaponNameInfo[i].name, '_' ) );
  242. if ( Q_stricmp( ( strchr( s_weaponNameInfo[i].name, '_' ) + 1 ), szAlias ) == 0 )
  243. return s_weaponNameInfo[i].id;
  244. }
  245. return WEAPON_NONE;
  246. }
  247. bool IsGunWeapon( CSWeaponType weaponType )
  248. {
  249. switch ( weaponType )
  250. {
  251. case WEAPONTYPE_PISTOL:
  252. case WEAPONTYPE_SUBMACHINEGUN:
  253. case WEAPONTYPE_RIFLE:
  254. case WEAPONTYPE_SHOTGUN:
  255. case WEAPONTYPE_SNIPER_RIFLE:
  256. case WEAPONTYPE_MACHINEGUN:
  257. return true;
  258. default:
  259. return false;
  260. }
  261. }
  262. //--------------------------------------------------------------------------------------------------------
  263. void ParseVector( KeyValues *keyValues, const char *keyName, Vector& vec )
  264. {
  265. vec.x = vec.y = vec.z = 0.0f;
  266. if ( !keyValues || !keyName )
  267. return;
  268. const char *vecString = keyValues->GetString( keyName, "0 0 0" );
  269. if ( vecString && *vecString )
  270. {
  271. float x, y, z;
  272. if ( 3 == sscanf( vecString, "%f %f %f", &x, &y, &z ) )
  273. {
  274. vec.x = x;
  275. vec.y = y;
  276. vec.z = z;
  277. }
  278. }
  279. }
  280. struct EnumerationStringValue
  281. {
  282. const char* szString;
  283. int iValue;
  284. };
  285. int ParseEnumeration( KeyValues* pKeyValuesData, const char* szKeyName, const EnumerationStringValue enumStringTable[], int iCount, int iDefaultValue )
  286. {
  287. const char *pTeam = pKeyValuesData->GetString( "Team", NULL );
  288. if ( !pTeam )
  289. return iDefaultValue;
  290. for ( int i = 0; i < iCount; ++i )
  291. {
  292. if ( V_stricmp( pTeam, enumStringTable[i].szString ) == 0 )
  293. return enumStringTable[i].iValue;
  294. }
  295. Assert( false );
  296. return iDefaultValue;
  297. }
  298. FileWeaponInfo_t* CreateWeaponInfo()
  299. {
  300. return new CCSWeaponInfo;
  301. }
  302. template <typename T>
  303. void ZeroObject( T* p )
  304. {
  305. memset( p, 0x0, sizeof(T) );
  306. }
  307. CCSWeaponInfo::CCSWeaponInfo()
  308. {
  309. m_weaponId = WEAPON_NONE;
  310. m_flMaxSpeed[0] = m_flMaxSpeed[1] = 1; // This should always be set in the script.
  311. m_iZoomLevels = 0;
  312. ZeroObject(m_iZoomFov);
  313. ZeroObject(m_fZoomTime);
  314. m_bHideViewModelZoomed = false;
  315. m_szZoomINSound[0] = '\0';
  316. m_szZoomOUTSound[0] = '\0';
  317. m_WeaponType = WEAPONTYPE_UNKNOWN;
  318. m_bFullAuto = false;
  319. m_iTeam = TEAM_UNASSIGNED;
  320. m_flBotAudibleRange = 0.f;
  321. m_flArmorRatio = 0.f;
  322. m_iCrosshairMinDistance = 0;
  323. m_iCrosshairDeltaDistance = 0;
  324. m_bCanUseWithShield = false;
  325. m_WrongTeamMsg[0] = '\0';
  326. m_szAnimExtension[0] = '\0';
  327. m_szShieldViewModel[0] = '\0';
  328. m_szAddonModel[0] = '\0';
  329. m_szAddonLocation[0] = '\0';
  330. m_szSilencerModel[0] = '\0';
  331. m_flAddonScale = 1.f;
  332. m_fFlinchVelocityModifierLarge = 1.f;
  333. m_fFlinchVelocityModifierSmall = 1.f;
  334. m_flPenetration = 0;
  335. m_iDamage = 0;
  336. m_flRange = 0.f;
  337. m_flRangeModifier = 0.f;
  338. m_iBullets = 0;
  339. m_flCycleTime = 0.f;
  340. m_flCycleTimeAlt = 0.f;
  341. ZeroObject(m_fSpread);
  342. ZeroObject(m_fInaccuracyCrouch);
  343. ZeroObject(m_fInaccuracyStand);
  344. ZeroObject(m_fInaccuracyJump);
  345. ZeroObject(m_fInaccuracyLand);
  346. ZeroObject(m_fInaccuracyLadder);
  347. ZeroObject(m_fInaccuracyImpulseFire);
  348. ZeroObject(m_fInaccuracyMove);
  349. m_fRecoveryTimeStand = 0.f;
  350. m_fRecoveryTimeCrouch = 0.f;
  351. m_fInaccuracyReload = 0.f;
  352. m_fInaccuracyAltSwitch = 0.f;
  353. m_fInaccuracyPitchShift = 0.f;
  354. m_fInaccuracyAltSoundThreshold = 0.f;
  355. ZeroObject(m_fRecoilAngle);
  356. ZeroObject(m_fRecoilAngleVariance);
  357. ZeroObject(m_fRecoilMagnitude);
  358. ZeroObject(m_fRecoilMagnitudeVariance);
  359. m_iRecoilSeed = 0;
  360. m_flTimeToIdleAfterFire = 0.f;
  361. m_flIdleInterval = 0.f;
  362. m_fThrowVelocity = 0.0f;
  363. m_iKillAward = 0;
  364. m_iWeaponPrice = 0;
  365. m_flHeatPerShot = 0.f;
  366. m_szHeatEffectName[0] = '\0';
  367. m_vSmokeColor.Zero();
  368. m_szMuzzleFlashEffectName_1stPerson[0] = '\0';
  369. m_szMuzzleFlashEffectName_3rdPerson[0] = '\0';
  370. m_szEjectBrassEffectName[0] = '\0';
  371. m_szTracerEffectName[0] = '\0';
  372. m_iTracerFequency = 0;
  373. // recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result.
  374. ZeroObject(m_recoilTable);
  375. if ( !m_bCSWeaponInfoLookupInitialized )
  376. {
  377. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_bFullAuto ), FIELD_BOOLEAN, "is full auto" ) );
  378. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flHeatPerShot ), FIELD_FLOAT, "heat per shot" ) );
  379. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flAddonScale ), FIELD_FLOAT, "addon scale" ) );
  380. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iTracerFequency ), FIELD_INTEGER, "tracer frequency" ) );
  381. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flMaxSpeed[0] ), FIELD_FLOAT, "max player speed" ) );
  382. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flMaxSpeed[1] ), FIELD_FLOAT, "max player speed alt" ) );
  383. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iWeaponPrice ), FIELD_INTEGER, "in game price" ) );
  384. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flArmorRatio ), FIELD_FLOAT, "armor ratio" ) );
  385. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iKillAward ), FIELD_INTEGER, "kill award" ) );
  386. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iCrosshairMinDistance ), FIELD_INTEGER, "crosshair min distance" ) );
  387. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iCrosshairDeltaDistance ), FIELD_INTEGER, "crosshair delta distance" ) );
  388. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flPenetration ), FIELD_FLOAT, "penetration" ) );
  389. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iDamage ), FIELD_INTEGER, "damage" ) );
  390. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flRange ), FIELD_FLOAT, "range" ) );
  391. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flRangeModifier ), FIELD_FLOAT, "range modifier" ) );
  392. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iBullets ), FIELD_INTEGER, "bullets" ) );
  393. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flCycleTime ), FIELD_FLOAT, "cycletime" ) );
  394. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flCycleTimeAlt ), FIELD_FLOAT, "cycletime alt" ) );
  395. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flTimeToIdleAfterFire ), FIELD_FLOAT, "time to idle" ) );
  396. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_flIdleInterval ), FIELD_FLOAT, "idle interval" ) );
  397. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fFlinchVelocityModifierLarge ), FIELD_FLOAT, "flinch velocity modifier large" ) );
  398. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fFlinchVelocityModifierSmall ), FIELD_FLOAT, "flinch velocity modifier small" ) );
  399. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fZoomTime[ 0 ] ), FIELD_FLOAT, "zoom time 0" ) );
  400. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fZoomTime[ 1 ] ), FIELD_FLOAT, "zoom time 1" ) );
  401. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fZoomTime[ 2 ] ), FIELD_FLOAT, "zoom time 2" ) );
  402. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iZoomFov[1] ), FIELD_INTEGER, "zoom fov 1" ) );
  403. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iZoomFov[2] ), FIELD_INTEGER, "zoom fov 2" ) );
  404. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_bHideViewModelZoomed ), FIELD_BOOLEAN, "hide view model zoomed" ) );
  405. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iZoomLevels ), FIELD_INTEGER, "zoom levels" ) );
  406. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fSpread[0] ), FIELD_FLOAT, "spread" ) );
  407. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyCrouch[0] ), FIELD_FLOAT, "inaccuracy crouch" ) );
  408. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyStand[0] ), FIELD_FLOAT, "inaccuracy stand" ) );
  409. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyJump[0] ), FIELD_FLOAT, "inaccuracy jump" ) );
  410. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyLand[0] ), FIELD_FLOAT, "inaccuracy land" ) );
  411. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyLadder[0] ), FIELD_FLOAT, "inaccuracy ladder" ) );
  412. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyImpulseFire[0] ), FIELD_FLOAT, "inaccuracy fire" ) );
  413. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyMove[0] ), FIELD_FLOAT, "inaccuracy move" ) );
  414. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyReload ), FIELD_FLOAT, "inaccuracy reload" ) );
  415. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fSpread[1] ), FIELD_FLOAT, "spread alt" ) );
  416. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyCrouch[1] ), FIELD_FLOAT, "inaccuracy crouch alt" ) );
  417. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyStand[1] ), FIELD_FLOAT, "inaccuracy stand alt" ) );
  418. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyJump[1] ), FIELD_FLOAT, "inaccuracy jump alt" ) );
  419. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyLand[1] ), FIELD_FLOAT, "inaccuracy land alt" ) );
  420. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyLadder[1] ), FIELD_FLOAT, "inaccuracy ladder alt" ) );
  421. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyImpulseFire[1] ), FIELD_FLOAT, "inaccuracy fire alt" ) );
  422. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fInaccuracyMove[1] ), FIELD_FLOAT, "inaccuracy move alt" ) );
  423. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoveryTimeCrouch ), FIELD_FLOAT, "recovery time crouch" ) );
  424. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoveryTimeStand ), FIELD_FLOAT, "recovery time stand" ) );
  425. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoveryTimeCrouchFinal ), FIELD_FLOAT, "recovery time crouch final" ) );
  426. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoveryTimeStandFinal ), FIELD_FLOAT, "recovery time stand final" ) );
  427. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_iRecoilSeed ), FIELD_INTEGER, "recoil seed" ) );
  428. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoilAngle[0] ), FIELD_FLOAT, "recoil angle" ) );
  429. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoilAngleVariance[0] ), FIELD_FLOAT, "recoil angle variance" ) );
  430. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoilMagnitude[0] ), FIELD_FLOAT, "recoil magnitude" ) );
  431. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoilMagnitudeVariance[0] ), FIELD_FLOAT, "recoil magnitude variance" ) );
  432. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoilAngle[1] ), FIELD_FLOAT, "recoil angle alt" ) );
  433. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoilAngleVariance[1] ), FIELD_FLOAT, "recoil angle variance alt" ) );
  434. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoilMagnitude[1] ), FIELD_FLOAT, "recoil magnitude alt" ) );
  435. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( CCSWeaponInfo, m_fRecoilMagnitudeVariance[1] ), FIELD_FLOAT, "recoil magnitude variance alt" ) );
  436. m_bCSWeaponInfoLookupInitialized = true;
  437. }
  438. }
  439. bool CCSWeaponInfo::m_bCSWeaponInfoLookupInitialized;
  440. CSWeaponType CCSWeaponInfo::GetWeaponType( const CEconItemView* pWepView ) const
  441. {
  442. if ( pWepView && pWepView->IsValid() )
  443. {
  444. const char *pszString = pWepView->GetStaticData()->GetWeaponTypeString();
  445. if ( pszString )
  446. {
  447. return WeaponClassFromString( pszString );
  448. }
  449. else
  450. {
  451. // DevWarning( "Weapon %s is missing a weapontype in the item schema.\n", WeaponIdAsString( m_weaponId ) );
  452. return m_WeaponType;
  453. }
  454. }
  455. return m_WeaponType;
  456. }
  457. const char* CCSWeaponInfo::GetAddonLocation( const CEconItemView* pWepView ) const
  458. {
  459. if ( pWepView && pWepView->IsValid() )
  460. {
  461. // TODO: replace visual data with attributes when attributes support strings.
  462. const char *pszString = pWepView->GetStaticData()->GetAddonLocation();
  463. if ( pszString )
  464. {
  465. return pszString;
  466. }
  467. }
  468. return m_szAddonLocation;
  469. }
  470. const char* CCSWeaponInfo::GetEjectBrassEffectName( const CEconItemView* pWepView ) const
  471. {
  472. if ( pWepView && pWepView->IsValid() )
  473. {
  474. // TODO: replace visual data with attributes when attributes support strings.
  475. const char *pszString = pWepView->GetStaticData()->GetEjectBrassEffect();
  476. if ( pszString )
  477. {
  478. return pszString;
  479. }
  480. }
  481. return m_szEjectBrassEffectName;
  482. }
  483. const char* CCSWeaponInfo::GetTracerEffectName( const CEconItemView* pWepView ) const
  484. {
  485. if ( pWepView && pWepView->IsValid() )
  486. {
  487. // TODO: replace visual data with attributes when attributes support strings.
  488. const char *pszString = pWepView->GetStaticData()->GetTracerEffect();
  489. if ( pszString )
  490. {
  491. return pszString;
  492. }
  493. }
  494. return m_szTracerEffectName;
  495. }
  496. const char* CCSWeaponInfo::GetMuzzleFlashEffectName_1stPerson( const CEconItemView* pWepView ) const
  497. {
  498. if ( pWepView && pWepView->IsValid() )
  499. {
  500. // TODO: replace visual data with attributes when attributes support strings.
  501. const char *pszString = pWepView->GetStaticData()->GetMuzzleFlashEffect1stPerson();
  502. if ( pszString )
  503. {
  504. return pszString;
  505. }
  506. }
  507. return m_szMuzzleFlashEffectName_1stPerson;
  508. }
  509. const char* CCSWeaponInfo::GetMuzzleFlashEffectName_1stPersonAlt( const CEconItemView* pWepView ) const
  510. {
  511. if ( pWepView && pWepView->IsValid() )
  512. {
  513. // TODO: replace visual data with attributes when attributes support strings.
  514. const char *pszString = pWepView->GetStaticData()->GetMuzzleFlashEffect1stPersonAlt();
  515. if ( pszString )
  516. {
  517. return pszString;
  518. }
  519. }
  520. return m_szMuzzleFlashEffectName_1stPerson;
  521. }
  522. const char* CCSWeaponInfo::GetMuzzleFlashEffectName_3rdPerson( const CEconItemView* pWepView ) const
  523. {
  524. if ( pWepView && pWepView->IsValid() )
  525. {
  526. // TODO: replace visual data with attributes when attributes support strings.
  527. const char *pszString = pWepView->GetStaticData()->GetMuzzleFlashEffect3rdPerson();
  528. if ( pszString )
  529. {
  530. return pszString;
  531. }
  532. }
  533. return m_szMuzzleFlashEffectName_3rdPerson;
  534. }
  535. const char* CCSWeaponInfo::GetMuzzleFlashEffectName_3rdPersonAlt( const CEconItemView* pWepView ) const
  536. {
  537. if ( pWepView && pWepView->IsValid() )
  538. {
  539. // TODO: replace visual data with attributes when attributes support strings.
  540. const char *pszString = pWepView->GetStaticData()->GetMuzzleFlashEffect3rdPersonAlt();
  541. if ( pszString )
  542. {
  543. return pszString;
  544. }
  545. }
  546. return m_szMuzzleFlashEffectName_3rdPerson;
  547. }
  548. const char* CCSWeaponInfo::GetHeatEffectName( const CEconItemView* pWepView ) const
  549. {
  550. if ( pWepView && pWepView->IsValid() )
  551. {
  552. // TODO: replace visual data with attributes when attributes support strings.
  553. const char *pszString = pWepView->GetStaticData()->GetHeatEffect();
  554. if ( pszString )
  555. {
  556. return pszString;
  557. }
  558. }
  559. return m_szHeatEffectName;
  560. }
  561. const char* CCSWeaponInfo::GetPlayerAnimationExtension( const CEconItemView* pWepView ) const
  562. {
  563. if ( pWepView && pWepView->IsValid() )
  564. {
  565. // TODO: replace visual data with attributes when attributes support strings.
  566. const char *pszString = pWepView->GetStaticData()->GetPlayerAnimationExtension();
  567. if ( pszString )
  568. {
  569. return pszString;
  570. }
  571. }
  572. return m_szAnimExtension;
  573. }
  574. int CCSWeaponInfo::GetUsedByTeam( const CEconItemView* pWepView ) const
  575. {
  576. if ( pWepView && pWepView->IsValid() )
  577. {
  578. return pWepView->GetStaticData()->GetUsedByTeam();
  579. }
  580. return m_iTeam;
  581. }
  582. const char* CCSWeaponInfo::GetAddonModel( const CEconItemView* pWepView ) const
  583. {
  584. if ( pWepView && pWepView->IsValid() )
  585. {
  586. const char *pchAddon = pWepView->GetStaticData()->GetEntityOverrideModel();
  587. return pchAddon ? pchAddon : m_szAddonModel;
  588. }
  589. else
  590. {
  591. return m_szAddonModel;
  592. }
  593. }
  594. const CUtlVector< WeaponPaintableMaterial_t >* CCSWeaponInfo::GetPaintData( const CEconItemView* pWepView ) const
  595. {
  596. if ( !pWepView || !pWepView->IsValid() )
  597. return NULL;
  598. return pWepView->GetStaticData()->GetPaintData();
  599. }
  600. void CCSWeaponInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
  601. {
  602. BaseClass::Parse( pKeyValuesData, szWeaponName );
  603. m_weaponId = WeaponIdFromString( szWeaponName );
  604. m_flMaxSpeed[0] = ( float )pKeyValuesData->GetInt( "MaxPlayerSpeed", 1 );
  605. m_flMaxSpeed[1] = ( float )pKeyValuesData->GetInt( "MaxPlayerSpeedAlt", m_flMaxSpeed[0] );
  606. m_iZoomLevels = pKeyValuesData->GetInt( "ZoomLevels", 0 );
  607. // sanity check
  608. Assert( m_iZoomLevels < ARRAYSIZE( m_fZoomTime ) && m_iZoomLevels < ARRAYSIZE( m_iZoomFov ) );
  609. m_iZoomLevels = MIN( m_iZoomLevels, ARRAYSIZE( m_iZoomFov ) );
  610. m_iZoomFov[0] = 0; // not used -- always default FoV
  611. m_fZoomTime[0] = pKeyValuesData->GetFloat( "ZoomTime0", 0.0f );
  612. m_iZoomFov[1] = pKeyValuesData->GetInt( "ZoomFov1", 90 );
  613. m_fZoomTime[1] = pKeyValuesData->GetFloat( "ZoomTime1", 0.0f );
  614. m_iZoomFov[2] = pKeyValuesData->GetInt( "ZoomFov2", 90 );
  615. m_fZoomTime[2] = pKeyValuesData->GetFloat( "ZoomTime2", 0.0f );
  616. m_bHideViewModelZoomed = pKeyValuesData->GetBool( "HideViewModelZoomed", false );
  617. V_strncpy( m_szZoomINSound, pKeyValuesData->GetString( "ZoomINSound" ), sizeof( m_szZoomINSound ) );
  618. V_strncpy( m_szZoomOUTSound, pKeyValuesData->GetString( "ZoomOUTSound" ), sizeof( m_szZoomOUTSound ) );
  619. m_iKillAward = pKeyValuesData->GetInt( "KillAward", 300 );
  620. m_iWeaponPrice = pKeyValuesData->GetInt( "WeaponPrice", -1 );
  621. if ( m_iWeaponPrice == -1 )
  622. {
  623. // This weapon should have the price in its script.
  624. Assert( false );
  625. }
  626. m_flArmorRatio = pKeyValuesData->GetFloat( "WeaponArmorRatio", 1 );
  627. m_iCrosshairMinDistance = pKeyValuesData->GetInt( "CrosshairMinDistance", 4 );
  628. m_iCrosshairDeltaDistance = pKeyValuesData->GetInt( "CrosshairDeltaDistance", 3 );
  629. m_bCanUseWithShield = !!pKeyValuesData->GetInt( "CanEquipWithShield", false );
  630. m_flAddonScale = pKeyValuesData->GetFloat( "AddonScale", 1.0f );
  631. m_fFlinchVelocityModifierLarge = pKeyValuesData->GetFloat( "FlinchVelocityModifierLarge", 1.0f );
  632. m_fFlinchVelocityModifierSmall = pKeyValuesData->GetFloat( "FlinchVelocityModifierSmall", 1.0f );
  633. m_flPenetration = pKeyValuesData->GetFloat( "Penetration", 1.0 );
  634. m_iDamage = pKeyValuesData->GetInt( "Damage", 42 ); // Douglas Adams 1952 - 2001
  635. m_flRange = pKeyValuesData->GetFloat( "Range", 8192.0f );
  636. m_flRangeModifier = pKeyValuesData->GetFloat( "RangeModifier", 0.98f );
  637. m_iBullets = pKeyValuesData->GetInt( "Bullets", 1 );
  638. m_flCycleTime = pKeyValuesData->GetFloat( "CycleTime", 0.15 );
  639. m_flCycleTimeAlt = pKeyValuesData->GetFloat( "CycleTimeAlt", 0.3 );
  640. // new accuracy model parameters
  641. m_fSpread[0] = pKeyValuesData->GetFloat( "Spread", 0.0f );
  642. m_fInaccuracyCrouch[0] = pKeyValuesData->GetFloat( "InaccuracyCrouch", 0.0f );
  643. m_fInaccuracyStand[0] = pKeyValuesData->GetFloat( "InaccuracyStand", 0.0f );
  644. m_fInaccuracyJump[0] = pKeyValuesData->GetFloat( "InaccuracyJump", 0.0f );
  645. m_fInaccuracyLand[0] = pKeyValuesData->GetFloat( "InaccuracyLand", 0.0f );
  646. m_fInaccuracyLadder[0] = pKeyValuesData->GetFloat( "InaccuracyLadder", 0.0f );
  647. m_fInaccuracyImpulseFire[0] = pKeyValuesData->GetFloat( "InaccuracyFire", 0.0f );
  648. m_fInaccuracyMove[0] = pKeyValuesData->GetFloat( "InaccuracyMove", 0.0f );
  649. m_fSpread[1] = pKeyValuesData->GetFloat( "SpreadAlt", m_fSpread[0] );
  650. m_fInaccuracyCrouch[1] = pKeyValuesData->GetFloat( "InaccuracyCrouchAlt", m_fInaccuracyCrouch[0] );
  651. m_fInaccuracyStand[1] = pKeyValuesData->GetFloat( "InaccuracyStandAlt", m_fInaccuracyStand[0] );
  652. m_fInaccuracyJump[1] = pKeyValuesData->GetFloat( "InaccuracyJumpAlt", m_fInaccuracyJump[0] );
  653. m_fInaccuracyLand[1] = pKeyValuesData->GetFloat( "InaccuracyLandAlt", m_fInaccuracyLand[0] );
  654. m_fInaccuracyLadder[1] = pKeyValuesData->GetFloat( "InaccuracyLadderAlt", m_fInaccuracyLadder[0] );
  655. m_fInaccuracyImpulseFire[1] = pKeyValuesData->GetFloat( "InaccuracyFireAlt", m_fInaccuracyImpulseFire[0] );
  656. m_fInaccuracyMove[1] = pKeyValuesData->GetFloat( "InaccuracyMoveAlt", m_fInaccuracyMove[0] );
  657. m_fRecoilAngle[0] = pKeyValuesData->GetFloat( "RecoilAngle", 0.0f );
  658. m_fRecoilAngleVariance[0] = pKeyValuesData->GetFloat( "RecoilAngleVariance", 0.0f );
  659. m_fRecoilMagnitude[0] = pKeyValuesData->GetFloat( "RecoilMagnitude", 0.0f );
  660. m_fRecoilMagnitudeVariance[0] = pKeyValuesData->GetFloat( "RecoilMagnitudeVariance", 0.0f );
  661. m_fRecoilAngle[1] = pKeyValuesData->GetFloat( "RecoilAngleAlt", m_fRecoilAngle[0] );
  662. m_fRecoilAngleVariance[1] = pKeyValuesData->GetFloat( "RecoilAngleVarianceAlt", m_fRecoilAngleVariance[0] );
  663. m_fRecoilMagnitude[1] = pKeyValuesData->GetFloat( "RecoilMagnitudeAlt", m_fRecoilMagnitude[0] );
  664. m_fRecoilMagnitudeVariance[1] = pKeyValuesData->GetFloat( "RecoilMagnitudeVarianceAlt", m_fRecoilMagnitudeVariance[0] );
  665. m_iRecoilSeed = pKeyValuesData->GetInt( "RecoilSeed", 0 );
  666. // FIXME[pmf]: temp code - remove when weapon scripts have seed values
  667. if ( m_iRecoilSeed == 0 && IsGunWeapon(GetWeaponType()) )
  668. {
  669. // create a temporary seed value based on a hash of the weapon name
  670. const char *weaponName = szClassName;
  671. CRC32_t crc;
  672. CRC32_Init( &crc );
  673. CRC32_ProcessBuffer( &crc, (void *)weaponName, Q_strlen( weaponName ) );
  674. CRC32_Final( &crc );
  675. m_iRecoilSeed = (int)crc & 0xFFFF;
  676. #ifdef GAME_DLL
  677. Msg( "RECOIL: No seed found for weapon %s, generated placeholder seed %i\n", weaponName, m_iRecoilSeed );
  678. #endif
  679. }
  680. m_fInaccuracyReload = pKeyValuesData->GetFloat( "InaccuracyReload", 0.0f );
  681. m_fInaccuracyAltSwitch = pKeyValuesData->GetFloat( "InaccuracyAltSwitch", 0.0f );
  682. m_fInaccuracyPitchShift = pKeyValuesData->GetFloat( "InaccuracyPitchShift", 0.0f );
  683. m_fInaccuracyAltSoundThreshold = pKeyValuesData->GetFloat( "InaccuracyAltSoundThreshold", 0.0f );
  684. m_fRecoveryTimeCrouch = pKeyValuesData->GetFloat( "RecoveryTimeCrouch", 1.0f );
  685. m_fRecoveryTimeStand = pKeyValuesData->GetFloat( "RecoveryTimeStand", 1.0f );
  686. m_fRecoveryTimeCrouchFinal = pKeyValuesData->GetFloat( "RecoveryTimeCrouchFinal", m_fRecoveryTimeCrouch );
  687. m_fRecoveryTimeStandFinal = pKeyValuesData->GetFloat( "RecoveryTimeStandFinal", m_fRecoveryTimeStand );
  688. m_flTimeToIdleAfterFire = pKeyValuesData->GetFloat( "TimeToIdle", 2 );
  689. m_flIdleInterval = pKeyValuesData->GetFloat( "IdleInterval", 20 );
  690. // grenade parameters
  691. m_fThrowVelocity = pKeyValuesData->GetFloat( "ThrowVelocity", 0.0f );
  692. m_flHeatPerShot = pKeyValuesData->GetFloat( "HeatPerShot", 0.25f );
  693. UTIL_StringToVector( m_vSmokeColor.Base(), pKeyValuesData->GetString( "SmokeColor", "1.0 1.0 1.0" ) );
  694. V_strncpy( m_szHeatEffectName, pKeyValuesData->GetString( "HeatEffect" ), sizeof( m_szHeatEffectName ) );
  695. // Figure out what team can have this weapon.
  696. EnumerationStringValue teamEnums[] =
  697. {
  698. { "CT", TEAM_CT },
  699. { "TERRORIST", TEAM_TERRORIST },
  700. { "ANY", TEAM_UNASSIGNED },
  701. };
  702. m_iTeam = ParseEnumeration(pKeyValuesData, "Team", teamEnums, ARRAYSIZE(teamEnums), TEAM_UNASSIGNED );
  703. const char *pWrongTeamMsg = pKeyValuesData->GetString( "WrongTeamMsg", "" );
  704. V_strncpy( m_WrongTeamMsg, pWrongTeamMsg, sizeof( m_WrongTeamMsg ) );
  705. const char *pShieldViewModel = pKeyValuesData->GetString( "shieldviewmodel", "" );
  706. V_strncpy( m_szShieldViewModel, pShieldViewModel, sizeof( m_szShieldViewModel ) );
  707. const char *pAnimEx = pKeyValuesData->GetString( "PlayerAnimationExtension", "m4" );
  708. V_strncpy( m_szAnimExtension, pAnimEx, sizeof( m_szAnimExtension ) );
  709. // Default is 2000.
  710. m_flBotAudibleRange = pKeyValuesData->GetFloat( "BotAudibleRange", 2000.0f );
  711. const char *pTypeString = pKeyValuesData->GetString( "WeaponType", "" );
  712. m_WeaponType = WeaponClassFromString( pTypeString );
  713. m_bFullAuto = pKeyValuesData->GetBool( "FullAuto", false );
  714. // Read the addon model.
  715. V_strncpy( m_szAddonModel, pKeyValuesData->GetString( "AddonModel" ), sizeof( m_szAddonModel ) );
  716. // Read a special addon attachment location if not the default location
  717. V_strncpy( m_szAddonLocation, pKeyValuesData->GetString( "AddonLocation" ), sizeof( m_szAddonLocation ) );
  718. // Read the silencer model.
  719. V_strncpy( m_szSilencerModel, pKeyValuesData->GetString( "SilencerModel" ), sizeof( m_szSilencerModel ) );
  720. #ifndef CLIENT_DLL
  721. // Enforce consistency for the weapon here, since that way we don't need to save off the model bounds
  722. // for all time.
  723. engine->ForceExactFile( UTIL_VarArgs( "scripts/%s.ctx", szWeaponName ) );
  724. // Model bounds are rounded to the nearest integer, then extended by 1
  725. engine->ForceModelBounds( szWorldModel, Vector( -15, -12, -18 ), Vector( 44, 16, 19 ) );
  726. if ( m_szAddonModel[0] )
  727. {
  728. engine->ForceModelBounds( m_szAddonModel, Vector( -5, -5, -6 ), Vector( 13, 5, 7 ) );
  729. }
  730. if ( m_szSilencerModel[0] )
  731. {
  732. engine->ForceModelBounds( m_szSilencerModel, Vector( -15, -12, -18 ), Vector( 44, 16, 19 ) );
  733. }
  734. #endif // !CLIENT_DLL
  735. // particle muzzle flash effect to play when fired
  736. V_strncpy( m_szMuzzleFlashEffectName_1stPerson, pKeyValuesData->GetString( "MuzzleFlashEffect_1stPerson" ), sizeof( m_szMuzzleFlashEffectName_1stPerson ) );
  737. V_strncpy( m_szMuzzleFlashEffectName_3rdPerson, pKeyValuesData->GetString( "MuzzleFlashEffect_3rdPerson" ), sizeof( m_szMuzzleFlashEffectName_3rdPerson ) );
  738. // particle effect for the shell casing to eject when we fire bullets
  739. V_strncpy( m_szEjectBrassEffectName, pKeyValuesData->GetString( "EjectBrassEffect" ), sizeof( m_szEjectBrassEffectName ) );
  740. // gun tracer effect and frequency
  741. V_strncpy( m_szTracerEffectName, pKeyValuesData->GetString( "TracerEffect" ), sizeof( m_szTracerEffectName ) );
  742. m_iTracerFequency = pKeyValuesData->GetInt( "TracerFrequency", 0 );
  743. // recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result.
  744. // generate the recoil table after everything else has been loaded (since it depends on other script parameters)
  745. GenerateRecoilTable();
  746. }
  747. ConVar weapon_recoil_suppression_shots( "weapon_recoil_suppression_shots", "4", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Number of shots before weapon uses full recoil" );
  748. ConVar weapon_recoil_suppression_factor( "weapon_recoil_suppression_factor", "0.75", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Initial recoil suppression factor (first suppressed shot will use this factor * standard recoil, lerping to 1 for later shots" );
  749. ConVar weapon_recoil_variance("weapon_recoil_variance", "0.55", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Amount of variance per recoil impulse", true, 0.0f, true, 1.0f );
  750. // recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result.
  751. void CCSWeaponInfo::GenerateRecoilTable()
  752. {
  753. const int iSuppressionShots = weapon_recoil_suppression_shots.GetInt();
  754. const float fBaseSuppressionFactor = weapon_recoil_suppression_factor.GetFloat();
  755. const float fRecoilVariance = weapon_recoil_variance.GetFloat();
  756. CUniformRandomStream recoilRandom;
  757. for ( int iMode = 0; iMode < 2; ++iMode )
  758. {
  759. recoilRandom.SetSeed( m_iRecoilSeed );
  760. float fAngle = 0.0f;
  761. float fMagnitude = 0.0f;
  762. for ( int j = 0; j < ARRAYSIZE( m_recoilTable[iMode] ); ++j )
  763. {
  764. float fAngleNew = m_fRecoilAngle[iMode] + recoilRandom.RandomFloat(-m_fRecoilAngleVariance[iMode], +m_fRecoilAngleVariance[iMode]);
  765. float fMagnitudeNew = m_fRecoilMagnitude[iMode] + recoilRandom.RandomFloat(-m_fRecoilMagnitudeVariance[iMode], +m_fRecoilMagnitudeVariance[iMode]);
  766. if ( m_bFullAuto && j > 0 )
  767. {
  768. fAngle = Lerp( fRecoilVariance, fAngle, fAngleNew );
  769. fMagnitude = Lerp( fRecoilVariance, fMagnitude, fMagnitudeNew );
  770. }
  771. else
  772. {
  773. fAngle = fAngleNew;
  774. fMagnitude = fMagnitudeNew;
  775. }
  776. if ( m_bFullAuto && j < iSuppressionShots )
  777. {
  778. float fSuppressionFactor = Lerp( (float)j / (float)iSuppressionShots, fBaseSuppressionFactor, 1.0f );
  779. fMagnitude *= fSuppressionFactor;
  780. }
  781. m_recoilTable[iMode][j].fAngle = fAngle;
  782. m_recoilTable[iMode][j].fMagnitude = fMagnitude;
  783. }
  784. }
  785. }
  786. // recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result.
  787. void CCSWeaponInfo::GetRecoilOffsets( int iMode, int iIndex, float& fAngle, float &fMagnitude ) const
  788. {
  789. iIndex = iIndex % ARRAYSIZE( m_recoilTable[iMode] );
  790. fAngle = m_recoilTable[iMode][iIndex].fAngle;
  791. fMagnitude = m_recoilTable[iMode][iIndex].fMagnitude;
  792. }
  793. //////////////////////////////////////////////////////////////////////////////////////////////////////
  794. // PURPOSE: Get an attribute associated with the weapon. It might seem a bit odd that in order to get
  795. // a weapon's damage you need to ask its deprecated weaponinfo object to extract it from its own econitemview
  796. // but we do this because In CS, there are a bunch of cases where there is no weapon instantiated yet and we need the data. All of this
  797. // legacy code uses weaponinfo objects.
  798. //
  799. // POSSIBLE RETURNS:
  800. // -2: total failure. We did not find the attribute in the econ item or in the weaponinfo instance.
  801. // -1: the attribute was found in the econitemview that was passed in.
  802. // >=0: the returned int is the index into g_WeaponInfoTable that contains the desired data.
  803. //////////////////////////////////////////////////////////////////////////////////////////////////////
  804. static bool GetAttribute_bool( const CCSWeaponInfo* pWeaponInfo, const char * iszAttrib, CSchemaAttributeDefHandle hAttrib, const CEconItemView *pWepView, float flScale = 1.0f )
  805. {
  806. uint32 unLocalValue = 0;
  807. int index = -2;
  808. if ( pWepView && pWepView->IsValid() )
  809. {
  810. if ( pWepView->FindAttribute( hAttrib, &unLocalValue ) )
  811. {
  812. return ( unLocalValue != 0 );
  813. }
  814. }
  815. // otherwise use legacy weapon script value
  816. index = pWeaponInfo->GetIndexofAttribute( AllocPooledString( iszAttrib ) );
  817. if ( index == -1 ) // we found the attribute in the item.
  818. {
  819. return false;
  820. }
  821. else if ( index > -1 )
  822. {
  823. Assert( pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_fieldType == FIELD_BOOLEAN );
  824. if ( pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_fieldType != FIELD_BOOLEAN )
  825. return false;
  826. const bool* pBool;
  827. pBool = reinterpret_cast< const bool* >( reinterpret_cast< const char* >( pWeaponInfo ) + pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_nWeaponParseDataOffset );
  828. return *pBool;
  829. }
  830. return false;
  831. }
  832. static int GetAttribute_int( const CCSWeaponInfo* pWeaponInfo, const char * iszAttrib, CSchemaAttributeDefHandle hAttrib, const CEconItemView *pWepView, float flScale = 1.0f )
  833. {
  834. uint32 unLocalValue = 0;
  835. int index = -2;
  836. if ( pWepView && pWepView->IsValid() )
  837. {
  838. if ( pWepView->FindAttribute( hAttrib, &unLocalValue ) )
  839. {
  840. return unLocalValue;
  841. }
  842. }
  843. // otherwise use legacy weapon script value
  844. index = pWeaponInfo->GetIndexofAttribute( AllocPooledString( iszAttrib ) );
  845. if ( index == -1 )
  846. {
  847. return 0;
  848. }
  849. else if ( index > -1 )
  850. {
  851. Assert( pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_fieldType == FIELD_INTEGER );
  852. if ( pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_fieldType != FIELD_INTEGER )
  853. return false;
  854. const int* pInt;
  855. pInt = reinterpret_cast< const int* >( reinterpret_cast< const char* >( pWeaponInfo ) + pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_nWeaponParseDataOffset );
  856. return *pInt;
  857. }
  858. return 0;
  859. }
  860. static float GetAttribute_float( const CCSWeaponInfo* pWeaponInfo, const char * iszAttrib, CSchemaAttributeDefHandle hAttrib, const CEconItemView *pWepView, float flScale = 1.0f )
  861. {
  862. float flLocalValue = 0.0f;
  863. int index = -2;
  864. if ( pWepView && pWepView->IsValid() )
  865. {
  866. if ( pWepView->FindAttribute( hAttrib, &flLocalValue ) )
  867. {
  868. return flScale * flLocalValue;
  869. }
  870. }
  871. // otherwise use legacy weapon script value
  872. index = pWeaponInfo->GetIndexofAttribute( AllocPooledString( iszAttrib ) );
  873. if ( index == -1 )
  874. {
  875. return flLocalValue;
  876. }
  877. else if ( index > -1 )
  878. {
  879. Assert( pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_fieldType == FIELD_FLOAT );
  880. if ( pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_fieldType != FIELD_FLOAT )
  881. return false;
  882. const float* pFloat;
  883. pFloat = reinterpret_cast< const float* >( reinterpret_cast< const char* >( pWeaponInfo ) + pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_nWeaponParseDataOffset );
  884. return flScale * *pFloat;
  885. }
  886. return 0;
  887. }
  888. // template < class T >
  889. // T GetAttributeFromSchemaOrScript( const CCSWeaponInfo* pWeaponInfo, const char * iszAttrib, CSchemaAttributeDefHandle hAttrib, const CEconItemView *pWepView )
  890. // {
  891. // uint32 unLocalValue = 0;
  892. // int index = -2;
  893. //
  894. // if ( pWepView && pWepView->IsValid() )
  895. // {
  896. // if ( pWepView->FindAttribute( hAttrib, &unLocalValue ) )
  897. // {
  898. // return unLocalValue;
  899. // }
  900. // }
  901. //
  902. // // otherwise use legacy weapon script value
  903. // index = pWeaponInfo->GetIndexofAttribute( AllocPooledString( iszAttrib ) );
  904. //
  905. // if ( index == -1 )
  906. // {
  907. // return false;
  908. // }
  909. // else if ( index > -1 )
  910. // {
  911. // const T* pValue;
  912. // pValue = reinterpret_cast< const T* >( reinterpret_cast< const char* >( pWeaponInfo ) + pWeaponInfo->ms_vecWeaponInfoLookup[ index ]->m_nWeaponParseDataOffset );
  913. //
  914. // return *pValue;
  915. // }
  916. //
  917. // return false;
  918. // }
  919. // Weapon attribute accessor is macroized and templatized so that we can use static attribute def handles
  920. // because generating them at every access is costly.
  921. //
  922. #define GET_WEAPON_ATTR_FUNC( type, functionname, attrname ) \
  923. type CCSWeaponInfo::functionname( const CEconItemView* pWepView, int nAlt, float flScale ) const \
  924. { \
  925. const char* pszAttrib; \
  926. static CSchemaAttributeDefHandle hAttrib( attrname ); \
  927. static CSchemaAttributeDefHandle hAttribAlt( attrname " alt" ); \
  928. CSchemaAttributeDefHandle * pAttrib; \
  929. if ( nAlt ) \
  930. { \
  931. pszAttrib = attrname " alt"; \
  932. pAttrib = &hAttribAlt; \
  933. } \
  934. else \
  935. { \
  936. pszAttrib = attrname; \
  937. pAttrib = &hAttrib; \
  938. } \
  939. return GetAttribute_##type( this, pszAttrib, *pAttrib, pWepView, flScale ); \
  940. }
  941. GET_WEAPON_ATTR_FUNC( int, GetWeaponPrice, "in game price" )
  942. GET_WEAPON_ATTR_FUNC( bool, IsFullAuto, "is full auto" )
  943. GET_WEAPON_ATTR_FUNC( bool, HasSilencer, "has silencer" )
  944. GET_WEAPON_ATTR_FUNC( int, GetBullets, "bullets" )
  945. GET_WEAPON_ATTR_FUNC( float, GetCycleTime, "cycletime" )
  946. GET_WEAPON_ATTR_FUNC( float, GetHeatPerShot, "heat per shot" )
  947. GET_WEAPON_ATTR_FUNC( float, GetRecoveryTimeCrouch, "recovery time crouch" )
  948. GET_WEAPON_ATTR_FUNC( float, GetRecoveryTimeStand, "recovery time stand" )
  949. GET_WEAPON_ATTR_FUNC( float, GetRecoveryTimeCrouchFinal, "recovery time crouch final" )
  950. GET_WEAPON_ATTR_FUNC( float, GetRecoveryTimeStandFinal, "recovery time stand final" )
  951. GET_WEAPON_ATTR_FUNC( int, GetRecoveryTransitionStartBullet, "recovery transition start bullet" )
  952. GET_WEAPON_ATTR_FUNC( int, GetRecoveryTransitionEndBullet, "recovery transition end bullet" )
  953. GET_WEAPON_ATTR_FUNC( int, GetRecoilSeed, "recoil seed" )
  954. GET_WEAPON_ATTR_FUNC( float, GetFlinchVelocityModifierLarge, "flinch velocity modifier large" )
  955. GET_WEAPON_ATTR_FUNC( float, GetFlinchVelocityModifierSmall, "flinch velocity modifier small" )
  956. GET_WEAPON_ATTR_FUNC( float, GetTimeToIdleAfterFire, "time to idle" )
  957. GET_WEAPON_ATTR_FUNC( float, GetIdleInterval, "idle interval" )
  958. GET_WEAPON_ATTR_FUNC( float, GetRange, "range" )
  959. GET_WEAPON_ATTR_FUNC( float, GetRangeModifier, "range modifier" )
  960. GET_WEAPON_ATTR_FUNC( int, GetDamage, "damage" )
  961. GET_WEAPON_ATTR_FUNC( float, GetPenetration, "penetration" )
  962. GET_WEAPON_ATTR_FUNC( int, GetCrosshairDeltaDistance, "crosshair delta distance" )
  963. GET_WEAPON_ATTR_FUNC( int, GetCrosshairMinDistance, "crosshair min distance" )
  964. GET_WEAPON_ATTR_FUNC( float, GetMaxSpeed, "max player speed" )
  965. GET_WEAPON_ATTR_FUNC( float, GetSpread, "spread" )
  966. GET_WEAPON_ATTR_FUNC( float, GetInaccuracyCrouch, "inaccuracy crouch" )
  967. GET_WEAPON_ATTR_FUNC( float, GetInaccuracyStand, "inaccuracy stand" )
  968. GET_WEAPON_ATTR_FUNC( float, GetInaccuracyJumpInitial, "inaccuracy jump initial" )
  969. GET_WEAPON_ATTR_FUNC( float, GetInaccuracyJump, "inaccuracy jump" )
  970. GET_WEAPON_ATTR_FUNC( float, GetInaccuracyLand, "inaccuracy land" )
  971. GET_WEAPON_ATTR_FUNC( float, GetInaccuracyLadder, "inaccuracy ladder" )
  972. GET_WEAPON_ATTR_FUNC( float, GetInaccuracyFire, "inaccuracy fire" )
  973. GET_WEAPON_ATTR_FUNC( float, GetInaccuracyMove, "inaccuracy move" )
  974. GET_WEAPON_ATTR_FUNC( float, GetInaccuracyReload, "inaccuracy reload" )
  975. GET_WEAPON_ATTR_FUNC( float, GetRecoilAngle, "recoil angle" )
  976. GET_WEAPON_ATTR_FUNC( float, GetRecoilAngleVariance, "recoil angle variance" )
  977. GET_WEAPON_ATTR_FUNC( float, GetRecoilMagnitude, "recoil magnitude" )
  978. GET_WEAPON_ATTR_FUNC( float, GetRecoilMagnitudeVariance, "recoil magnitude variance" )
  979. GET_WEAPON_ATTR_FUNC( int, GetTracerFrequency, "tracer frequency" )
  980. GET_WEAPON_ATTR_FUNC( int, GetPrimaryClipSize, "primary clip size" )
  981. GET_WEAPON_ATTR_FUNC( int, GetSecondaryClipSize, "secondary clip size" )
  982. GET_WEAPON_ATTR_FUNC( int, GetDefaultPrimaryClipSize, "primary default clip size" )
  983. GET_WEAPON_ATTR_FUNC( int, GetDefaultSecondaryClipSize, "secondary default clip size" )
  984. GET_WEAPON_ATTR_FUNC( int, GetKillAward, "kill award" )
  985. GET_WEAPON_ATTR_FUNC( bool, HasBurstMode, "has burst mode" )
  986. GET_WEAPON_ATTR_FUNC( bool, IsRevolver, "is revolver" )
  987. GET_WEAPON_ATTR_FUNC( bool, HasAlternateFastSlowReload, "alternate fastslow reload" )
  988. GET_WEAPON_ATTR_FUNC( float, GetArmorRatio, "armor ratio" )
  989. GET_WEAPON_ATTR_FUNC( bool, HasTraditionalScope, "traditional scope" )
  990. GET_WEAPON_ATTR_FUNC( bool, CannotShootUnderwater, "cannot shoot underwater" )
  991. GET_WEAPON_ATTR_FUNC( bool, DoesUnzoomAfterShot, "unzoom after shot" )
  992. GET_WEAPON_ATTR_FUNC( bool, DoesHideViewModelWhenZoomed, "hide view model zoomed" )
  993. GET_WEAPON_ATTR_FUNC( int, GetBucketSlot, "bucket slot" )
  994. GET_WEAPON_ATTR_FUNC( int, GetZoomLevels, "zoom levels" )
  995. GET_WEAPON_ATTR_FUNC( int, GetZoomFOV1, "zoom fov 1" )
  996. GET_WEAPON_ATTR_FUNC( int, GetZoomFOV2, "zoom fov 2" )
  997. GET_WEAPON_ATTR_FUNC( float, GetZoomTime0, "zoom time 0" )
  998. GET_WEAPON_ATTR_FUNC( float, GetZoomTime1, "zoom time 1" )
  999. GET_WEAPON_ATTR_FUNC( float, GetZoomTime2, "zoom time 2" )
  1000. GET_WEAPON_ATTR_FUNC( int, GetPrimaryReserveAmmoMax, "primary reserve ammo max" )
  1001. GET_WEAPON_ATTR_FUNC( int, GetSecondaryReserveAmmoMax, "secondary reserve ammo max" )
  1002. WeaponRecoilData::WeaponRecoilData()
  1003. {
  1004. m_mapRecoilTables.SetLessFunc( DefLessFunc( item_definition_index_t ) );
  1005. }
  1006. WeaponRecoilData::~WeaponRecoilData()
  1007. {
  1008. m_mapRecoilTables.PurgeAndDeleteElements();
  1009. }
  1010. static inline float AttrValueAsFloat( attrib_value_t val )
  1011. {
  1012. float flValue;
  1013. Q_memcpy( &flValue, &val, sizeof( float ) );
  1014. return flValue;
  1015. }
  1016. void WeaponRecoilData::GenerateRecoilTable( RecoilData *data )
  1017. {
  1018. const int iSuppressionShots = weapon_recoil_suppression_shots.GetInt();
  1019. const float fBaseSuppressionFactor = weapon_recoil_suppression_factor.GetFloat();
  1020. const float fRecoilVariance = weapon_recoil_variance.GetFloat();
  1021. CUniformRandomStream recoilRandom;
  1022. if ( !data )
  1023. return;
  1024. const CEconItemDefinition *pEconItemDefinition = GetItemSchema()->GetItemDefinition( data->iItemDefIndex );
  1025. Assert( pEconItemDefinition );
  1026. // Walk the attributes to determine all things that we need
  1027. int iSeed = 0;
  1028. bool bHasAttrSeed = false;
  1029. bool bFullAuto = false;
  1030. bool bHasAttrFullAuto = false;
  1031. float flRecoilAngle[2] = {};
  1032. bool bHasAttrRecoilAngle[2] = {};
  1033. float flRecoilAngleVariance[2] = {};
  1034. bool bHasAttrRecoilAngleVariance[2] = {};
  1035. float flRecoilMagnitude[2] = {};
  1036. bool bHasAttrRecoilMagnitude[2] = {};
  1037. float flRecoilMagnitudeVariance[2] = {};
  1038. bool bHasAttrRecoilMagnitudeVariance[2] = {};
  1039. CCSWeaponInfo const *pWeaponInfo = NULL;
  1040. if ( ( data->iItemDefIndex >= WEAPON_FIRST ) && ( data->iItemDefIndex <= WEAPON_LAST ) )
  1041. {
  1042. pWeaponInfo = GetWeaponInfo( CSWeaponID( data->iItemDefIndex ) );
  1043. }
  1044. if ( !pWeaponInfo && pEconItemDefinition->GetItemClass() )
  1045. {
  1046. char const *szItemClass = pEconItemDefinition->GetItemClass();
  1047. CSWeaponID wpnId = WeaponIdFromString( szItemClass );
  1048. if ( wpnId != WEAPON_NONE )
  1049. {
  1050. pWeaponInfo = GetWeaponInfo( wpnId );
  1051. }
  1052. }
  1053. if ( pWeaponInfo )
  1054. {
  1055. iSeed = pWeaponInfo->GetRecoilSeed();
  1056. bFullAuto = pWeaponInfo->IsFullAuto();
  1057. for ( int iMode = 0; iMode < 2; ++ iMode )
  1058. {
  1059. flRecoilAngle[iMode] = pWeaponInfo->GetRecoilAngle( NULL, iMode );
  1060. flRecoilAngleVariance[iMode] = pWeaponInfo->GetRecoilAngleVariance( NULL, iMode );
  1061. flRecoilMagnitude[iMode] = pWeaponInfo->GetRecoilMagnitude( NULL, iMode );
  1062. flRecoilMagnitudeVariance[iMode] = pWeaponInfo->GetRecoilMagnitudeVariance( NULL, iMode );
  1063. }
  1064. }
  1065. const CUtlVector< static_attrib_t > &arrAttributes = pEconItemDefinition->GetStaticAttributes();
  1066. Assert( pWeaponInfo || arrAttributes.Count() );
  1067. for ( int j = 0; j < arrAttributes.Count(); ++ j )
  1068. {
  1069. switch ( arrAttributes[j].iDefIndex )
  1070. {
  1071. case 59: // recoil seed
  1072. Assert( !bHasAttrSeed );
  1073. bHasAttrSeed = true;
  1074. iSeed = arrAttributes[j].m_value.asFloat;
  1075. break;
  1076. case 60: // recoil angle
  1077. Assert( !bHasAttrRecoilAngle[0] );
  1078. bHasAttrRecoilAngle[0] = true;
  1079. flRecoilAngle[0] = arrAttributes[j].m_value.asFloat;
  1080. break;
  1081. case 64: // recoil angle alt
  1082. Assert( !bHasAttrRecoilAngle[1] );
  1083. bHasAttrRecoilAngle[1] = true;
  1084. flRecoilAngle[1] = arrAttributes[j].m_value.asFloat;
  1085. break;
  1086. case 61: // recoil angle variance
  1087. Assert( !bHasAttrRecoilAngleVariance[0] );
  1088. bHasAttrRecoilAngleVariance[0] = true;
  1089. flRecoilAngleVariance[0] = arrAttributes[j].m_value.asFloat;
  1090. break;
  1091. case 65: // recoil angle variance alt
  1092. Assert( !bHasAttrRecoilAngleVariance[1] );
  1093. bHasAttrRecoilAngleVariance[1] = true;
  1094. flRecoilAngleVariance[1] = arrAttributes[j].m_value.asFloat;
  1095. break;
  1096. case 62: // recoil magnitude
  1097. Assert( !bHasAttrRecoilMagnitude[0] );
  1098. bHasAttrRecoilMagnitude[0] = true;
  1099. flRecoilMagnitude[0] = arrAttributes[j].m_value.asFloat;
  1100. break;
  1101. case 66: // recoil magnitude alt
  1102. Assert( !bHasAttrRecoilMagnitude[1] );
  1103. bHasAttrRecoilMagnitude[1] = true;
  1104. flRecoilMagnitude[1] = arrAttributes[j].m_value.asFloat;
  1105. break;
  1106. case 63: // recoil magnitude variance
  1107. Assert( !bHasAttrRecoilMagnitudeVariance[0] );
  1108. bHasAttrRecoilMagnitudeVariance[0] = true;
  1109. flRecoilMagnitudeVariance[0] = arrAttributes[j].m_value.asFloat;
  1110. break;
  1111. case 67: // recoil magnitude variance alt
  1112. Assert( !bHasAttrRecoilMagnitudeVariance[1] );
  1113. bHasAttrRecoilMagnitudeVariance[1] = true;
  1114. flRecoilMagnitudeVariance[1] = arrAttributes[j].m_value.asFloat;
  1115. break;
  1116. case 22: // full auto
  1117. Assert( !bHasAttrFullAuto );
  1118. bHasAttrFullAuto = true;
  1119. bFullAuto = ( arrAttributes[j].m_value.asUint32 != 0.0f );
  1120. break;
  1121. }
  1122. }
  1123. for ( int iMode = 0; iMode < 2; ++iMode )
  1124. {
  1125. Assert( pWeaponInfo || ( bHasAttrSeed && bHasAttrFullAuto &&
  1126. bHasAttrRecoilAngle[iMode] && bHasAttrRecoilAngleVariance[iMode] &&
  1127. bHasAttrRecoilMagnitude[iMode] && bHasAttrRecoilMagnitudeVariance[iMode] ) );
  1128. recoilRandom.SetSeed( iSeed );
  1129. float fAngle = 0.0f;
  1130. float fMagnitude = 0.0f;
  1131. for ( int j = 0; j < ARRAYSIZE( data->recoilTable[iMode] ); ++j )
  1132. {
  1133. float fAngleNew = flRecoilAngle[iMode] + recoilRandom.RandomFloat(- flRecoilAngleVariance[iMode], + flRecoilAngleVariance[iMode] );
  1134. float fMagnitudeNew = flRecoilMagnitude[iMode] + recoilRandom.RandomFloat(- flRecoilMagnitudeVariance[iMode], + flRecoilMagnitudeVariance[iMode] );
  1135. if ( bFullAuto && ( j > 0 ) )
  1136. {
  1137. fAngle = Lerp( fRecoilVariance, fAngle, fAngleNew );
  1138. fMagnitude = Lerp( fRecoilVariance, fMagnitude, fMagnitudeNew );
  1139. }
  1140. else
  1141. {
  1142. fAngle = fAngleNew;
  1143. fMagnitude = fMagnitudeNew;
  1144. }
  1145. if ( bFullAuto && ( j < iSuppressionShots ) )
  1146. {
  1147. float fSuppressionFactor = Lerp( (float)j / (float)iSuppressionShots, fBaseSuppressionFactor, 1.0f );
  1148. fMagnitude *= fSuppressionFactor;
  1149. }
  1150. data->recoilTable[iMode][j].fAngle = fAngle;
  1151. data->recoilTable[iMode][j].fMagnitude = fMagnitude;
  1152. }
  1153. }
  1154. }
  1155. void WeaponRecoilData::GetRecoilOffsets( CWeaponCSBase *pWeapon, int iMode, int iIndex, float& fAngle, float &fMagnitude )
  1156. {
  1157. // Recoil offset tables are indexed by a weapon's definition index.
  1158. // Look for the existing table, otherwise generate it.
  1159. item_definition_index_t iDefIndex = pWeapon->GetEconItemView()->GetItemDefinition()->GetDefinitionIndex();
  1160. RecoilData *wepData = NULL;
  1161. CUtlMap< item_definition_index_t, RecoilData* >::IndexType_t iMapLocation = m_mapRecoilTables.Find( iDefIndex );
  1162. if ( iMapLocation == m_mapRecoilTables.InvalidIndex() )
  1163. {
  1164. Assert( !"Generating recoil table too late" ); // failed to find recoil table, need to re-generate!
  1165. wepData = new RecoilData;
  1166. wepData->iItemDefIndex = iDefIndex;
  1167. iMapLocation = m_mapRecoilTables.InsertOrReplace( iDefIndex, wepData );
  1168. GenerateRecoilTable( wepData );
  1169. }
  1170. else
  1171. {
  1172. wepData = m_mapRecoilTables.Element( iMapLocation );
  1173. Assert( wepData );
  1174. Assert( wepData->iItemDefIndex == iDefIndex );
  1175. }
  1176. iIndex = iIndex % ARRAYSIZE( wepData->recoilTable[iMode] );
  1177. fAngle = wepData->recoilTable[iMode][iIndex].fAngle;
  1178. fMagnitude = wepData->recoilTable[iMode][iIndex].fMagnitude;
  1179. }
  1180. void WeaponRecoilData::GenerateRecoilPatternForItemDefinition( item_definition_index_t idx )
  1181. {
  1182. CUtlMap< item_definition_index_t, RecoilData* >::IndexType_t iMapLocation = m_mapRecoilTables.Find( idx );
  1183. if ( iMapLocation == m_mapRecoilTables.InvalidIndex() )
  1184. {
  1185. RecoilData *wepData = new RecoilData;
  1186. wepData->iItemDefIndex = idx;
  1187. iMapLocation = m_mapRecoilTables.InsertOrReplace( idx, wepData );
  1188. GenerateRecoilTable( wepData );
  1189. }
  1190. }
  1191. WeaponRecoilData g_WeaponRecoilData;
  1192. void GenerateWeaponRecoilPatternForItemDefinition( item_definition_index_t idx )
  1193. {
  1194. g_WeaponRecoilData.GenerateRecoilPatternForItemDefinition( idx );
  1195. }