Team Fortress 2 Source Code as on 22/4/2020
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.

455 lines
14 KiB

  1. //========= Copyright 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 "icvar.h"
  12. #include "cs_gamerules.h"
  13. #include "cs_blackmarket.h"
  14. //--------------------------------------------------------------------------------------------------------
  15. struct WeaponTypeInfo
  16. {
  17. CSWeaponType type;
  18. const char * name;
  19. };
  20. //--------------------------------------------------------------------------------------------------------
  21. WeaponTypeInfo s_weaponTypeInfo[] =
  22. {
  23. { WEAPONTYPE_KNIFE, "Knife" },
  24. { WEAPONTYPE_PISTOL, "Pistol" },
  25. { WEAPONTYPE_SUBMACHINEGUN, "Submachine Gun" }, // First match is printable
  26. { WEAPONTYPE_SUBMACHINEGUN, "submachinegun" },
  27. { WEAPONTYPE_SUBMACHINEGUN, "smg" },
  28. { WEAPONTYPE_RIFLE, "Rifle" },
  29. { WEAPONTYPE_SHOTGUN, "Shotgun" },
  30. { WEAPONTYPE_SNIPER_RIFLE, "Sniper Rifle" }, // First match is printable
  31. { WEAPONTYPE_SNIPER_RIFLE, "SniperRifle" },
  32. { WEAPONTYPE_MACHINEGUN, "Machine Gun" }, // First match is printable
  33. { WEAPONTYPE_MACHINEGUN, "machinegun" },
  34. { WEAPONTYPE_MACHINEGUN, "mg" },
  35. { WEAPONTYPE_C4, "C4" },
  36. { WEAPONTYPE_GRENADE, "Grenade" },
  37. };
  38. struct WeaponNameInfo
  39. {
  40. CSWeaponID id;
  41. const char *name;
  42. };
  43. WeaponNameInfo s_weaponNameInfo[] =
  44. {
  45. { WEAPON_P228, "weapon_p228" },
  46. { WEAPON_GLOCK, "weapon_glock" },
  47. { WEAPON_SCOUT, "weapon_scout" },
  48. { WEAPON_HEGRENADE, "weapon_hegrenade" },
  49. { WEAPON_XM1014, "weapon_xm1014" },
  50. { WEAPON_C4, "weapon_c4" },
  51. { WEAPON_MAC10, "weapon_mac10" },
  52. { WEAPON_AUG, "weapon_aug" },
  53. { WEAPON_SMOKEGRENADE, "weapon_smokegrenade" },
  54. { WEAPON_ELITE, "weapon_elite" },
  55. { WEAPON_FIVESEVEN, "weapon_fiveseven" },
  56. { WEAPON_UMP45, "weapon_ump45" },
  57. { WEAPON_SG550, "weapon_sg550" },
  58. { WEAPON_GALIL, "weapon_galil" },
  59. { WEAPON_FAMAS, "weapon_famas" },
  60. { WEAPON_USP, "weapon_usp" },
  61. { WEAPON_AWP, "weapon_awp" },
  62. { WEAPON_MP5NAVY, "weapon_mp5navy" },
  63. { WEAPON_M249, "weapon_m249" },
  64. { WEAPON_M3, "weapon_m3" },
  65. { WEAPON_M4A1, "weapon_m4a1" },
  66. { WEAPON_TMP, "weapon_tmp" },
  67. { WEAPON_G3SG1, "weapon_g3sg1" },
  68. { WEAPON_FLASHBANG, "weapon_flashbang" },
  69. { WEAPON_DEAGLE, "weapon_deagle" },
  70. { WEAPON_SG552, "weapon_sg552" },
  71. { WEAPON_AK47, "weapon_ak47" },
  72. { WEAPON_KNIFE, "weapon_knife" },
  73. { WEAPON_P90, "weapon_p90" },
  74. // not sure any of these are needed
  75. { WEAPON_SHIELDGUN, "weapon_shieldgun" },
  76. { WEAPON_KEVLAR, "weapon_kevlar" },
  77. { WEAPON_ASSAULTSUIT, "weapon_assaultsuit" },
  78. { WEAPON_NVG, "weapon_nvg" },
  79. { WEAPON_NONE, "weapon_none" },
  80. };
  81. //--------------------------------------------------------------------------------------------------------------
  82. CCSWeaponInfo g_EquipmentInfo[MAX_EQUIPMENT];
  83. void PrepareEquipmentInfo( void )
  84. {
  85. memset( g_EquipmentInfo, 0, ARRAYSIZE( g_EquipmentInfo ) );
  86. g_EquipmentInfo[2].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_KEVLAR ) );
  87. g_EquipmentInfo[2].SetDefaultPrice( KEVLAR_PRICE );
  88. g_EquipmentInfo[2].SetPreviousPrice( CSGameRules()->GetBlackMarketPreviousPriceForWeapon( WEAPON_KEVLAR ) );
  89. g_EquipmentInfo[2].m_iTeam = TEAM_UNASSIGNED;
  90. Q_strcpy( g_EquipmentInfo[2].szClassName, "weapon_vest" );
  91. #ifdef CLIENT_DLL
  92. g_EquipmentInfo[2].iconActive = new CHudTexture;
  93. g_EquipmentInfo[2].iconActive->cCharacterInFont = 't';
  94. #endif
  95. g_EquipmentInfo[1].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_ASSAULTSUIT ) );
  96. g_EquipmentInfo[1].SetDefaultPrice( ASSAULTSUIT_PRICE );
  97. g_EquipmentInfo[1].SetPreviousPrice( CSGameRules()->GetBlackMarketPreviousPriceForWeapon( WEAPON_ASSAULTSUIT ) );
  98. g_EquipmentInfo[1].m_iTeam = TEAM_UNASSIGNED;
  99. Q_strcpy( g_EquipmentInfo[1].szClassName, "weapon_vesthelm" );
  100. #ifdef CLIENT_DLL
  101. g_EquipmentInfo[1].iconActive = new CHudTexture;
  102. g_EquipmentInfo[1].iconActive->cCharacterInFont = 'u';
  103. #endif
  104. g_EquipmentInfo[0].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_NVG ) );
  105. g_EquipmentInfo[0].SetPreviousPrice( CSGameRules()->GetBlackMarketPreviousPriceForWeapon( WEAPON_NVG ) );
  106. g_EquipmentInfo[0].SetDefaultPrice( NVG_PRICE );
  107. g_EquipmentInfo[0].m_iTeam = TEAM_UNASSIGNED;
  108. Q_strcpy( g_EquipmentInfo[0].szClassName, "weapon_nvgs" );
  109. #ifdef CLIENT_DLL
  110. g_EquipmentInfo[0].iconActive = new CHudTexture;
  111. g_EquipmentInfo[0].iconActive->cCharacterInFont = 's';
  112. #endif
  113. }
  114. //--------------------------------------------------------------------------------------------------------------
  115. CCSWeaponInfo * GetWeaponInfo( CSWeaponID weaponID )
  116. {
  117. if ( weaponID == WEAPON_NONE )
  118. return NULL;
  119. if ( weaponID >= WEAPON_KEVLAR )
  120. {
  121. int iIndex = (WEAPON_MAX - weaponID) - 1;
  122. return &g_EquipmentInfo[iIndex];
  123. }
  124. const char *weaponName = WeaponIdAsString(weaponID);
  125. WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( weaponName );
  126. if ( hWpnInfo == GetInvalidWeaponInfoHandle() )
  127. {
  128. return NULL;
  129. }
  130. CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
  131. return pWeaponInfo;
  132. }
  133. //--------------------------------------------------------------------------------------------------------
  134. const char* WeaponClassAsString( CSWeaponType weaponType )
  135. {
  136. for ( int i = 0; i < ARRAYSIZE(s_weaponTypeInfo); ++i )
  137. {
  138. if ( s_weaponTypeInfo[i].type == weaponType )
  139. {
  140. return s_weaponTypeInfo[i].name;
  141. }
  142. }
  143. return NULL;
  144. }
  145. //--------------------------------------------------------------------------------------------------------
  146. CSWeaponType WeaponClassFromString( const char* weaponType )
  147. {
  148. for ( int i = 0; i < ARRAYSIZE(s_weaponTypeInfo); ++i )
  149. {
  150. if ( !Q_stricmp( s_weaponTypeInfo[i].name, weaponType ) )
  151. {
  152. return s_weaponTypeInfo[i].type;
  153. }
  154. }
  155. return WEAPONTYPE_UNKNOWN;
  156. }
  157. //--------------------------------------------------------------------------------------------------------
  158. CSWeaponType WeaponClassFromWeaponID( CSWeaponID weaponID )
  159. {
  160. const char *weaponStr = WeaponIDToAlias( weaponID );
  161. const char *translatedAlias = GetTranslatedWeaponAlias( weaponStr );
  162. char wpnName[128];
  163. Q_snprintf( wpnName, sizeof( wpnName ), "weapon_%s", translatedAlias );
  164. WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( wpnName );
  165. if ( hWpnInfo != GetInvalidWeaponInfoHandle() )
  166. {
  167. CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
  168. if ( pWeaponInfo )
  169. {
  170. return pWeaponInfo->m_WeaponType;
  171. }
  172. }
  173. return WEAPONTYPE_UNKNOWN;
  174. }
  175. //--------------------------------------------------------------------------------------------------------
  176. const char * WeaponIdAsString( CSWeaponID weaponID )
  177. {
  178. for ( int i = 0; i < ARRAYSIZE(s_weaponNameInfo); ++i )
  179. {
  180. if (s_weaponNameInfo[i].id == weaponID )
  181. return s_weaponNameInfo[i].name;
  182. }
  183. return NULL;
  184. }
  185. //--------------------------------------------------------------------------------------------------------
  186. CSWeaponID WeaponIdFromString( const char *szWeaponName )
  187. {
  188. for ( int i = 0; i < ARRAYSIZE(s_weaponNameInfo); ++i )
  189. {
  190. if ( Q_stricmp(s_weaponNameInfo[i].name, szWeaponName) == 0 )
  191. return s_weaponNameInfo[i].id;
  192. }
  193. return WEAPON_NONE;
  194. }
  195. //--------------------------------------------------------------------------------------------------------
  196. void ParseVector( KeyValues *keyValues, const char *keyName, Vector& vec )
  197. {
  198. vec.x = vec.y = vec.z = 0.0f;
  199. if ( !keyValues || !keyName )
  200. return;
  201. const char *vecString = keyValues->GetString( keyName, "0 0 0" );
  202. if ( vecString && *vecString )
  203. {
  204. float x = 0.0f, y = 0.0f, z = 0.0f;
  205. if ( 3 == sscanf( vecString, "%f %f %f", &x, &y, &z ) )
  206. {
  207. vec.x = x;
  208. vec.y = y;
  209. vec.z = z;
  210. }
  211. }
  212. }
  213. FileWeaponInfo_t* CreateWeaponInfo()
  214. {
  215. return new CCSWeaponInfo;
  216. }
  217. CCSWeaponInfo::CCSWeaponInfo()
  218. {
  219. m_flMaxSpeed = 1; // This should always be set in the script.
  220. m_szAddonModel[0] = 0;
  221. }
  222. int CCSWeaponInfo::GetWeaponPrice( void ) const
  223. {
  224. return m_iWeaponPrice;
  225. }
  226. int CCSWeaponInfo::GetDefaultPrice( void )
  227. {
  228. return m_iDefaultPrice;
  229. }
  230. int CCSWeaponInfo::GetPrevousPrice( void )
  231. {
  232. return m_iPreviousPrice;
  233. }
  234. void CCSWeaponInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
  235. {
  236. BaseClass::Parse( pKeyValuesData, szWeaponName );
  237. m_flMaxSpeed = (float)pKeyValuesData->GetInt( "MaxPlayerSpeed", 1 );
  238. m_iDefaultPrice = m_iWeaponPrice = pKeyValuesData->GetInt( "WeaponPrice", -1 );
  239. if ( m_iWeaponPrice == -1 )
  240. {
  241. // This weapon should have the price in its script.
  242. Assert( false );
  243. }
  244. if ( CSGameRules()->IsBlackMarket() )
  245. {
  246. CSWeaponID iWeaponID = AliasToWeaponID( GetTranslatedWeaponAlias ( szWeaponName ) );
  247. m_iDefaultPrice = m_iWeaponPrice;
  248. m_iPreviousPrice = CSGameRules()->GetBlackMarketPreviousPriceForWeapon( iWeaponID );
  249. m_iWeaponPrice = CSGameRules()->GetBlackMarketPriceForWeapon( iWeaponID );
  250. }
  251. m_flArmorRatio = pKeyValuesData->GetFloat( "WeaponArmorRatio", 1 );
  252. m_iCrosshairMinDistance = pKeyValuesData->GetInt( "CrosshairMinDistance", 4 );
  253. m_iCrosshairDeltaDistance = pKeyValuesData->GetInt( "CrosshairDeltaDistance", 3 );
  254. m_bCanUseWithShield = !!pKeyValuesData->GetInt( "CanEquipWithShield", false );
  255. m_flMuzzleScale = pKeyValuesData->GetFloat( "MuzzleFlashScale", 1 );
  256. const char *pMuzzleFlashStyle = pKeyValuesData->GetString( "MuzzleFlashStyle", "CS_MUZZLEFLASH_NORM" );
  257. if( pMuzzleFlashStyle )
  258. {
  259. if ( Q_stricmp( pMuzzleFlashStyle, "CS_MUZZLEFLASH_X" ) == 0 )
  260. {
  261. m_iMuzzleFlashStyle = CS_MUZZLEFLASH_X;
  262. }
  263. else if ( Q_stricmp( pMuzzleFlashStyle, "CS_MUZZLEFLASH_NONE" ) == 0 )
  264. {
  265. m_iMuzzleFlashStyle = CS_MUZZLEFLASH_NONE;
  266. }
  267. else
  268. {
  269. m_iMuzzleFlashStyle = CS_MUZZLEFLASH_NORM;
  270. }
  271. }
  272. else
  273. {
  274. Assert( false );
  275. }
  276. m_iPenetration = pKeyValuesData->GetInt( "Penetration", 1 );
  277. m_iDamage = pKeyValuesData->GetInt( "Damage", 42 ); // Douglas Adams 1952 - 2001
  278. m_flRange = pKeyValuesData->GetFloat( "Range", 8192.0f );
  279. m_flRangeModifier = pKeyValuesData->GetFloat( "RangeModifier", 0.98f );
  280. m_iBullets = pKeyValuesData->GetInt( "Bullets", 1 );
  281. m_flCycleTime = pKeyValuesData->GetFloat( "CycleTime", 0.15 );
  282. m_bAccuracyQuadratic= pKeyValuesData->GetInt( "AccuracyQuadratic", 0 );
  283. m_flAccuracyDivisor = pKeyValuesData->GetFloat( "AccuracyDivisor", -1 ); // -1 = off
  284. m_flAccuracyOffset = pKeyValuesData->GetFloat( "AccuracyOffset", 0 );
  285. m_flMaxInaccuracy = pKeyValuesData->GetFloat( "MaxInaccuracy", 0 );
  286. // new accuracy model parameters
  287. m_fSpread[0] = pKeyValuesData->GetFloat("Spread", 0.0f);
  288. m_fInaccuracyCrouch[0] = pKeyValuesData->GetFloat("InaccuracyCrouch", 0.0f);
  289. m_fInaccuracyStand[0] = pKeyValuesData->GetFloat("InaccuracyStand", 0.0f);
  290. m_fInaccuracyJump[0] = pKeyValuesData->GetFloat("InaccuracyJump", 0.0f);
  291. m_fInaccuracyLand[0] = pKeyValuesData->GetFloat("InaccuracyLand", 0.0f);
  292. m_fInaccuracyLadder[0] = pKeyValuesData->GetFloat("InaccuracyLadder", 0.0f);
  293. m_fInaccuracyImpulseFire[0] = pKeyValuesData->GetFloat("InaccuracyFire", 0.0f);
  294. m_fInaccuracyMove[0] = pKeyValuesData->GetFloat("InaccuracyMove", 0.0f);
  295. m_fSpread[1] = pKeyValuesData->GetFloat("SpreadAlt", 0.0f);
  296. m_fInaccuracyCrouch[1] = pKeyValuesData->GetFloat("InaccuracyCrouchAlt", 0.0f);
  297. m_fInaccuracyStand[1] = pKeyValuesData->GetFloat("InaccuracyStandAlt", 0.0f);
  298. m_fInaccuracyJump[1] = pKeyValuesData->GetFloat("InaccuracyJumpAlt", 0.0f);
  299. m_fInaccuracyLand[1] = pKeyValuesData->GetFloat("InaccuracyLandAlt", 0.0f);
  300. m_fInaccuracyLadder[1] = pKeyValuesData->GetFloat("InaccuracyLadderAlt", 0.0f);
  301. m_fInaccuracyImpulseFire[1] = pKeyValuesData->GetFloat("InaccuracyFireAlt", 0.0f);
  302. m_fInaccuracyMove[1] = pKeyValuesData->GetFloat("InaccuracyMoveAlt", 0.0f);
  303. m_fInaccuracyReload = pKeyValuesData->GetFloat("InaccuracyReload", 0.0f);
  304. m_fInaccuracyAltSwitch = pKeyValuesData->GetFloat("InaccuracyAltSwitch", 0.0f);
  305. m_fRecoveryTimeCrouch = pKeyValuesData->GetFloat("RecoveryTimeCrouch", 1.0f);
  306. m_fRecoveryTimeStand = pKeyValuesData->GetFloat("RecoveryTimeStand", 1.0f);
  307. m_flTimeToIdleAfterFire = pKeyValuesData->GetFloat( "TimeToIdle", 2 );
  308. m_flIdleInterval = pKeyValuesData->GetFloat( "IdleInterval", 20 );
  309. // Figure out what team can have this weapon.
  310. m_iTeam = TEAM_UNASSIGNED;
  311. const char *pTeam = pKeyValuesData->GetString( "Team", NULL );
  312. if ( pTeam )
  313. {
  314. if ( Q_stricmp( pTeam, "CT" ) == 0 )
  315. {
  316. m_iTeam = TEAM_CT;
  317. }
  318. else if ( Q_stricmp( pTeam, "TERRORIST" ) == 0 )
  319. {
  320. m_iTeam = TEAM_TERRORIST;
  321. }
  322. else if ( Q_stricmp( pTeam, "ANY" ) == 0 )
  323. {
  324. m_iTeam = TEAM_UNASSIGNED;
  325. }
  326. else
  327. {
  328. Assert( false );
  329. }
  330. }
  331. else
  332. {
  333. Assert( false );
  334. }
  335. const char *pWrongTeamMsg = pKeyValuesData->GetString( "WrongTeamMsg", "" );
  336. Q_strncpy( m_WrongTeamMsg, pWrongTeamMsg, sizeof( m_WrongTeamMsg ) );
  337. const char *pShieldViewModel = pKeyValuesData->GetString( "shieldviewmodel", "" );
  338. Q_strncpy( m_szShieldViewModel, pShieldViewModel, sizeof( m_szShieldViewModel ) );
  339. const char *pAnimEx = pKeyValuesData->GetString( "PlayerAnimationExtension", "m4" );
  340. Q_strncpy( m_szAnimExtension, pAnimEx, sizeof( m_szAnimExtension ) );
  341. // Default is 2000.
  342. m_flBotAudibleRange = pKeyValuesData->GetFloat( "BotAudibleRange", 2000.0f );
  343. const char *pTypeString = pKeyValuesData->GetString( "WeaponType", "" );
  344. m_WeaponType = WeaponClassFromString(pTypeString);
  345. m_bFullAuto = pKeyValuesData->GetBool("FullAuto");
  346. // Read the addon model.
  347. Q_strncpy( m_szAddonModel, pKeyValuesData->GetString( "AddonModel" ), sizeof( m_szAddonModel ) );
  348. // Read the dropped model.
  349. Q_strncpy( m_szDroppedModel, pKeyValuesData->GetString( "DroppedModel" ), sizeof( m_szDroppedModel ) );
  350. // Read the silencer model.
  351. Q_strncpy( m_szSilencerModel, pKeyValuesData->GetString( "SilencerModel" ), sizeof( m_szSilencerModel ) );
  352. #ifndef CLIENT_DLL
  353. // Enforce consistency for the weapon here, since that way we don't need to save off the model bounds
  354. // for all time.
  355. // Moved to pure_server_minimal.txt
  356. // engine->ForceExactFile( UTIL_VarArgs("scripts/%s.ctx", szWeaponName ) );
  357. // Model bounds are rounded to the nearest integer, then extended by 1
  358. engine->ForceModelBounds( szWorldModel, Vector( -15, -12, -18 ), Vector( 44, 16, 19 ) );
  359. if ( m_szAddonModel[0] )
  360. {
  361. engine->ForceModelBounds( m_szAddonModel, Vector( -5, -5, -6 ), Vector( 13, 5, 7 ) );
  362. }
  363. if ( m_szSilencerModel[0] )
  364. {
  365. engine->ForceModelBounds( m_szSilencerModel, Vector( -15, -12, -18 ), Vector( 44, 16, 19 ) );
  366. }
  367. #endif // !CLIENT_DLL
  368. }