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.

689 lines
19 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Weapon data file parsing, shared by game & client dlls.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include <keyvalues.h>
  9. #include <tier0/mem.h>
  10. #include "filesystem.h"
  11. #include "utldict.h"
  12. #include "ammodef.h"
  13. #include "util_shared.h"
  14. #include "weapon_parse.h"
  15. #include "econ_item_view.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. CWeaponDatabase g_WeaponDatabase;
  19. extern void LoadEquipmentData();
  20. // The sound categories found in the weapon classname.txt files
  21. // This needs to match the WeaponSound_t enum in weapon_parse.h
  22. #if !defined(_STATIC_LINKED) || defined(CLIENT_DLL)
  23. const char *pWeaponSoundCategories[ NUM_SHOOT_SOUND_TYPES ] =
  24. {
  25. "empty",
  26. "single_shot",
  27. "single_shot_accurate",
  28. "single_shot_npc",
  29. "double_shot",
  30. "double_shot_npc",
  31. "burst",
  32. "reload",
  33. "reload_npc",
  34. "melee_miss",
  35. "melee_hit",
  36. "melee_hit_world",
  37. "special1",
  38. "special2",
  39. "special3",
  40. "taunt",
  41. "nearlyempty",
  42. "fastreload"
  43. };
  44. #else
  45. extern const char *pWeaponSoundCategories[ NUM_SHOOT_SOUND_TYPES ];
  46. #endif
  47. int GetWeaponSoundFromString( const char *pszString )
  48. {
  49. for ( int i = EMPTY; i < NUM_SHOOT_SOUND_TYPES; i++ )
  50. {
  51. if ( !Q_stricmp(pszString,pWeaponSoundCategories[i]) )
  52. return (WeaponSound_t)i;
  53. }
  54. return -1;
  55. }
  56. // Item flags that we parse out of the file.
  57. typedef struct
  58. {
  59. const char *m_pFlagName;
  60. int m_iFlagValue;
  61. } itemFlags_t;
  62. #if !defined(_STATIC_LINKED) || defined(CLIENT_DLL)
  63. itemFlags_t g_ItemFlags[8] =
  64. {
  65. { "ITEM_FLAG_SELECTONEMPTY", ITEM_FLAG_SELECTONEMPTY },
  66. { "ITEM_FLAG_NOAUTORELOAD", ITEM_FLAG_NOAUTORELOAD },
  67. { "ITEM_FLAG_NOAUTOSWITCHEMPTY", ITEM_FLAG_NOAUTOSWITCHEMPTY },
  68. { "ITEM_FLAG_LIMITINWORLD", ITEM_FLAG_LIMITINWORLD },
  69. { "ITEM_FLAG_EXHAUSTIBLE", ITEM_FLAG_EXHAUSTIBLE },
  70. { "ITEM_FLAG_DOHITLOCATIONDMG", ITEM_FLAG_DOHITLOCATIONDMG },
  71. { "ITEM_FLAG_NOAMMOPICKUPS", ITEM_FLAG_NOAMMOPICKUPS },
  72. { "ITEM_FLAG_NOITEMPICKUP", ITEM_FLAG_NOITEMPICKUP }
  73. };
  74. #else
  75. extern itemFlags_t g_ItemFlags[7];
  76. #endif
  77. #ifdef _DEBUG
  78. // used to track whether or not two weapons have been mistakenly assigned the wrong slot
  79. bool g_bUsedWeaponSlots[MAX_WEAPON_SLOTS][MAX_WEAPON_POSITIONS] = { 0 };
  80. #endif
  81. // Find a weapon slot, assuming the weapon's data has already been loaded.
  82. WEAPON_FILE_INFO_HANDLE LookupWeaponInfoSlot( const char *name )
  83. {
  84. return g_WeaponDatabase.FindWeaponInfo( name );
  85. }
  86. FileWeaponInfo_t *GetFileWeaponInfoFromHandle( WEAPON_FILE_INFO_HANDLE handle )
  87. {
  88. return g_WeaponDatabase.GetFileWeaponInfoFromHandle( handle );
  89. }
  90. void PrecacheFileWeaponInfoDatabase()
  91. {
  92. g_WeaponDatabase.PrecacheAllWeapons();
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose:
  96. // Output : WEAPON_FILE_INFO_HANDLE
  97. //-----------------------------------------------------------------------------
  98. WEAPON_FILE_INFO_HANDLE GetInvalidWeaponInfoHandle( void )
  99. {
  100. return (WEAPON_FILE_INFO_HANDLE)-1;
  101. }
  102. KeyValues* ReadEncryptedKVFile( IFileSystem *filesystem, const char *szFilenameWithoutExtension, const unsigned char *pICEKey, bool bForceReadEncryptedFile )
  103. {
  104. Assert( strchr( szFilenameWithoutExtension, '.' ) == NULL );
  105. char szFullName[512];
  106. const char *pSearchPath = "GAME";
  107. // Open the weapon data file, and abort if we can't
  108. KeyValues *pKV = new KeyValues( "WeaponDatafile" );
  109. pKV->UsesEscapeSequences( true );
  110. Q_snprintf(szFullName,sizeof(szFullName), "%s.txt", szFilenameWithoutExtension);
  111. if ( bForceReadEncryptedFile || !pKV->LoadFromFile( filesystem, szFullName, pSearchPath ) ) // try to load the normal .txt file first
  112. {
  113. if ( pICEKey )
  114. {
  115. Q_snprintf(szFullName,sizeof(szFullName), "%s.ctx", szFilenameWithoutExtension); // fall back to the .ctx file
  116. FileHandle_t f = filesystem->Open( szFullName, "rb", pSearchPath );
  117. if (!f)
  118. {
  119. pKV->deleteThis();
  120. return NULL;
  121. }
  122. // load file into a null-terminated buffer
  123. int fileSize = filesystem->Size(f);
  124. char *buffer = (char*)MemAllocScratch(fileSize + 1);
  125. Assert(buffer);
  126. filesystem->Read(buffer, fileSize, f); // read into local buffer
  127. buffer[fileSize] = 0; // null terminate file as EOF
  128. filesystem->Close( f ); // close file after reading
  129. UTIL_DecodeICE( (unsigned char*)buffer, fileSize, pICEKey );
  130. bool retOK = pKV->LoadFromBuffer( szFullName, buffer, filesystem );
  131. MemFreeScratch();
  132. if ( !retOK )
  133. {
  134. pKV->deleteThis();
  135. return NULL;
  136. }
  137. }
  138. else
  139. {
  140. pKV->deleteThis();
  141. return NULL;
  142. }
  143. }
  144. return pKV;
  145. }
  146. CUtlSortVector< WeaponInfoLookup*, CWeaponInfoLookupListLess > FileWeaponInfo_t::ms_vecWeaponInfoLookup;
  147. bool FileWeaponInfo_t::ms_bWeaponInfoLookupInitialized;
  148. WeaponInfoLookup::WeaponInfoLookup( size_t offset, _fieldtypes p_fieldType, const char *szAttribClassName )
  149. {
  150. m_nWeaponParseDataOffset = offset;
  151. m_fieldType = p_fieldType;
  152. m_iszAttribClassName.Set( szAttribClassName );
  153. }
  154. WeaponInfoLookup::WeaponInfoLookup( const WeaponInfoLookup &WepInfoLookup )
  155. {
  156. m_nWeaponParseDataOffset = WepInfoLookup.m_nWeaponParseDataOffset;
  157. m_fieldType = WepInfoLookup.m_fieldType;
  158. m_iszAttribClassName.Set( STRING( WepInfoLookup.m_iszAttribClassName.Get() ) );
  159. }
  160. //-----------------------------------------------------------------------------
  161. // FileWeaponInfo_t implementation.
  162. //-----------------------------------------------------------------------------
  163. FileWeaponInfo_t::FileWeaponInfo_t()
  164. {
  165. bParsedScript = false;
  166. bLoadedHudElements = false;
  167. szClassName[0] = 0;
  168. szPrintName[0] = 0;
  169. szViewModel[0] = 0;
  170. szWorldModel[0] = 0;
  171. szAnimationPrefix[0] = 0;
  172. iSlot = 0;
  173. iPosition = 0;
  174. iMaxClip1 = 0;
  175. iMaxClip2 = 0;
  176. iDefaultClip1 = 0;
  177. iDefaultClip2 = 0;
  178. iWeight = 0;
  179. iRumbleEffect = -1;
  180. bAutoSwitchTo = false;
  181. bAutoSwitchFrom = false;
  182. iFlags = 0;
  183. szAmmo1[0] = 0;
  184. szAmmo2[0] = 0;
  185. szAIAddOn[0] = 0;
  186. memset( aShootSounds, 0, sizeof( aShootSounds ) );
  187. iAmmoType = 0;
  188. iAmmo2Type = 0;
  189. m_bMeleeWeapon = false;
  190. iSpriteCount = 0;
  191. iconActive = 0;
  192. iconInactive = 0;
  193. iconAmmo = 0;
  194. iconAmmo2 = 0;
  195. iconCrosshair = 0;
  196. iconAutoaim = 0;
  197. iconZoomedCrosshair = 0;
  198. iconZoomedAutoaim = 0;
  199. bShowUsageHint = false;
  200. m_bAllowFlipping = true;
  201. m_bBuiltRightHanded = true;
  202. if ( !ms_bWeaponInfoLookupInitialized )
  203. {
  204. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( FileWeaponInfo_t, iMaxClip1 ), FIELD_INTEGER, "primary clip size" ) );
  205. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( FileWeaponInfo_t, iMaxClip2 ), FIELD_INTEGER, "secondary clip size" ) );
  206. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( FileWeaponInfo_t, iDefaultClip1 ), FIELD_INTEGER, "primary default clip size" ) );
  207. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( FileWeaponInfo_t, iDefaultClip2 ), FIELD_INTEGER, "secondary default clip size" ) );
  208. ms_vecWeaponInfoLookup.Insert( new WeaponInfoLookup( offsetof( FileWeaponInfo_t, iSlot ), FIELD_INTEGER, "bucket slot" ) );
  209. ms_bWeaponInfoLookupInitialized = true;
  210. }
  211. }
  212. #ifdef CLIENT_DLL
  213. extern ConVar hud_fastswitch;
  214. #endif
  215. void FileWeaponInfo_t::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
  216. {
  217. // Okay, we tried at least once to look this up...
  218. bParsedScript = true;
  219. // Classname
  220. Q_strncpy( szClassName, szWeaponName, MAX_WEAPON_STRING );
  221. // Printable name
  222. Q_strncpy( szPrintName, pKeyValuesData->GetString( "printname", WEAPON_PRINTNAME_MISSING ), MAX_WEAPON_STRING );
  223. // View model & world model
  224. Q_strncpy( szViewModel, pKeyValuesData->GetString( "viewmodel" ), MAX_WEAPON_STRING );
  225. Q_strncpy( szWorldModel, pKeyValuesData->GetString( "playermodel" ), MAX_WEAPON_STRING );
  226. V_StripExtension( szWorldModel, szWorldDroppedModel, sizeof( szWorldDroppedModel ) );
  227. V_strcat_safe( szWorldDroppedModel, "_dropped.mdl" );
  228. Q_strncpy( szAnimationPrefix, pKeyValuesData->GetString( "anim_prefix" ), MAX_WEAPON_PREFIX );
  229. iSlot = pKeyValuesData->GetInt( "bucket", 0 );
  230. iPosition = pKeyValuesData->GetInt( "bucket_position", 0 );
  231. // Use the console (X360) buckets if hud_fastswitch is set to 2.
  232. #ifdef CLIENT_DLL
  233. if ( hud_fastswitch.GetInt() == 2 )
  234. #else
  235. if ( IsGameConsole() )
  236. #endif
  237. {
  238. iSlot = pKeyValuesData->GetInt( "bucket_360", iSlot );
  239. iPosition = pKeyValuesData->GetInt( "bucket_position_360", iPosition );
  240. }
  241. iMaxClip1 = pKeyValuesData->GetInt( "clip_size", WEAPON_NOCLIP ); // Max primary clips gun can hold (assume they don't use clips by default)
  242. iMaxClip2 = pKeyValuesData->GetInt( "clip2_size", WEAPON_NOCLIP ); // Max secondary clips gun can hold (assume they don't use clips by default)
  243. iDefaultClip1 = pKeyValuesData->GetInt( "default_clip", iMaxClip1 ); // amount of primary ammo placed in the primary clip when it's picked up
  244. iDefaultClip2 = pKeyValuesData->GetInt( "default_clip2", iMaxClip2 ); // amount of secondary ammo placed in the secondary clip when it's picked up
  245. iWeight = pKeyValuesData->GetInt( "weight", 0 );
  246. iRumbleEffect = pKeyValuesData->GetInt( "rumble", -1 );
  247. // LAME old way to specify item flags.
  248. // Weapon scripts should use the flag names.
  249. iFlags = pKeyValuesData->GetInt( "item_flags", ITEM_FLAG_LIMITINWORLD );
  250. for ( int i=0; i < ARRAYSIZE( g_ItemFlags ); i++ )
  251. {
  252. int iVal = pKeyValuesData->GetInt( g_ItemFlags[i].m_pFlagName, -1 );
  253. if ( iVal == 0 )
  254. {
  255. iFlags &= ~g_ItemFlags[i].m_iFlagValue;
  256. }
  257. else if ( iVal == 1 )
  258. {
  259. iFlags |= g_ItemFlags[i].m_iFlagValue;
  260. }
  261. }
  262. bShowUsageHint = pKeyValuesData->GetBool( "showusagehint", false );
  263. bAutoSwitchTo = pKeyValuesData->GetBool( "autoswitchto", true );
  264. bAutoSwitchFrom = pKeyValuesData->GetBool( "autoswitchfrom", true );
  265. m_bBuiltRightHanded = pKeyValuesData->GetBool( "BuiltRightHanded", true );
  266. m_bAllowFlipping = pKeyValuesData->GetBool( "AllowFlipping", true );
  267. m_bMeleeWeapon = pKeyValuesData->GetBool( "MeleeWeapon", false );
  268. #if defined(_DEBUG) && defined(HL2_CLIENT_DLL)
  269. // make sure two weapons aren't in the same slot & position
  270. if ( iSlot >= MAX_WEAPON_SLOTS ||
  271. iPosition >= MAX_WEAPON_POSITIONS )
  272. {
  273. Warning( "Invalid weapon slot or position [slot %d/%d max], pos[%d/%d max]\n",
  274. iSlot, MAX_WEAPON_SLOTS - 1, iPosition, MAX_WEAPON_POSITIONS - 1 );
  275. }
  276. else
  277. {
  278. if (g_bUsedWeaponSlots[iSlot][iPosition])
  279. {
  280. Warning( "Duplicately assigned weapon slots in selection hud: %s (%d, %d)\n", szPrintName, iSlot, iPosition );
  281. }
  282. g_bUsedWeaponSlots[iSlot][iPosition] = true;
  283. }
  284. #endif
  285. // Primary ammo used
  286. const char *pAmmo = pKeyValuesData->GetString( "primary_ammo", "None" );
  287. if ( strcmp("None", pAmmo) == 0 )
  288. Q_strncpy( szAmmo1, "", sizeof( szAmmo1 ) );
  289. else
  290. Q_strncpy( szAmmo1, pAmmo, sizeof( szAmmo1 ) );
  291. iAmmoType = GetAmmoDef()->Index( szAmmo1 );
  292. // Secondary ammo used
  293. pAmmo = pKeyValuesData->GetString( "secondary_ammo", "None" );
  294. if ( strcmp("None", pAmmo) == 0)
  295. Q_strncpy( szAmmo2, "", sizeof( szAmmo2 ) );
  296. else
  297. Q_strncpy( szAmmo2, pAmmo, sizeof( szAmmo2 ) );
  298. iAmmo2Type = GetAmmoDef()->Index( szAmmo2 );
  299. // AI AddOn
  300. const char *pAIAddOn = pKeyValuesData->GetString( "ai_addon", "ai_addon_basecombatweapon" );
  301. if ( strcmp("None", pAIAddOn) == 0)
  302. Q_strncpy( szAIAddOn, "", sizeof( szAIAddOn ) );
  303. else
  304. Q_strncpy( szAIAddOn, pAIAddOn, sizeof( szAIAddOn ) );
  305. // Now read the weapon sounds
  306. memset( aShootSounds, 0, sizeof( aShootSounds ) );
  307. KeyValues *pSoundData = pKeyValuesData->FindKey( "SoundData" );
  308. if ( pSoundData )
  309. {
  310. for ( int i = EMPTY; i < NUM_SHOOT_SOUND_TYPES; i++ )
  311. {
  312. const char *soundname = pSoundData->GetString( pWeaponSoundCategories[i] );
  313. if ( soundname && soundname[0] )
  314. {
  315. Q_strncpy( aShootSounds[i], soundname, MAX_WEAPON_STRING );
  316. }
  317. else
  318. {
  319. // FIXME: find a better way to populate defaults
  320. if ( i == NEARLYEMPTY ) // explicit check because it looks like most weapon sound categories don't fall back by default
  321. {
  322. V_sprintf_safe( aShootSounds[i], "Default.%s", pWeaponSoundCategories[i] );
  323. }
  324. }
  325. }
  326. }
  327. }
  328. const char* FileWeaponInfo_t::GetWorldModel( const CEconItemView* pWepView, int iTeam ) const
  329. {
  330. if ( pWepView && pWepView->IsValid() )
  331. {
  332. const char *pchWorldOverride = pWepView->GetStaticData()->GetEntityOverrideModel();
  333. if ( pchWorldOverride )
  334. {
  335. return pchWorldOverride;
  336. }
  337. return pWepView->GetItemDefinition()->GetWorldDisplayModel();
  338. }
  339. else
  340. {
  341. return szWorldModel;
  342. }
  343. }
  344. const char* FileWeaponInfo_t::GetViewModel( const CEconItemView* pWepView, int iTeam ) const
  345. {
  346. if ( pWepView && pWepView->IsValid() )
  347. {
  348. const char *pchViewOverride = pWepView->GetStaticData()->GetViewOverrideModel();
  349. if ( pchViewOverride )
  350. {
  351. return pchViewOverride;
  352. }
  353. return pWepView->GetItemDefinition()->GetBasePlayerDisplayModel();
  354. }
  355. else
  356. {
  357. return szViewModel;
  358. }
  359. }
  360. const char* FileWeaponInfo_t::GetWorldDroppedModel( const CEconItemView* pWepView, int iTeam ) const
  361. {
  362. if ( pWepView && pWepView->IsValid() )
  363. {
  364. const char *pchWorldDroppedModel = pWepView->GetItemDefinition()->GetWorldDroppedModel();
  365. if ( pchWorldDroppedModel )
  366. {
  367. return pchWorldDroppedModel;
  368. }
  369. }
  370. return szWorldDroppedModel;
  371. }
  372. const char* FileWeaponInfo_t::GetPrimaryAmmo( const CEconItemView* pWepView ) const
  373. {
  374. if ( pWepView && pWepView->IsValid() )
  375. {
  376. // TODO: replace visual data with attributes when attributes support strings.
  377. const char *pszString = pWepView->GetStaticData()->GetPrimaryAmmo();
  378. if ( pszString )
  379. {
  380. return pszString;
  381. }
  382. }
  383. return szAmmo1;
  384. }
  385. int FileWeaponInfo_t::GetPrimaryAmmoType( const CEconItemView* pWepView ) const
  386. {
  387. if ( pWepView && pWepView->IsValid() )
  388. {
  389. // TODO: replace visual data with attributes when attributes support strings.
  390. const char *pszString = GetPrimaryAmmo( pWepView );
  391. if ( pszString )
  392. {
  393. return GetAmmoDef()->Index( pszString );
  394. }
  395. }
  396. return iAmmoType;
  397. }
  398. static int WeaponInfoLookupCompare( WeaponInfoLookup * const * src1, WeaponInfoLookup * const * src2 )
  399. {
  400. if ( ( *src1 )->m_iszAttribClassName.Get() == ( *src2 )->m_iszAttribClassName.Get() )
  401. return 0;
  402. if ( ( *src1 )->m_iszAttribClassName.Get() < ( *src2 )->m_iszAttribClassName.Get() )
  403. return -1;
  404. return 1;
  405. }
  406. // Convert a schema attribute classname into an index of g_WeaponInfoTable
  407. int FileWeaponInfo_t::GetIndexofAttribute( string_t iszAttribClassName ) const
  408. {
  409. if ( ms_vecWeaponInfoLookup.Count() == 0 )
  410. return -1;
  411. if ( ms_vecWeaponInfoLookup[ 0 ]->m_iszAttribClassName.IsSerialNumberOutOfDate() )
  412. {
  413. // If the strings are out of date, rebuild and resort them
  414. FOR_EACH_VEC( ms_vecWeaponInfoLookup, i )
  415. {
  416. ms_vecWeaponInfoLookup[ i ]->m_iszAttribClassName.Get();
  417. }
  418. ms_vecWeaponInfoLookup.Sort( &WeaponInfoLookupCompare );
  419. }
  420. WeaponInfoLookup searchKey;
  421. searchKey.m_iszAttribClassName.SetFastNoCopy( iszAttribClassName );
  422. return ms_vecWeaponInfoLookup.Find( &searchKey );
  423. }
  424. #if defined( GAME_DLL )
  425. CON_COMMAND_F ( weapon_reload_database, "Reload the weapon database", FCVAR_CHEAT | FCVAR_GAMEDLL| FCVAR_SERVER_CAN_EXECUTE )
  426. {
  427. g_WeaponDatabase.LoadManifest();
  428. IGameEvent *event = gameeventmanager->CreateEvent( "weapon_reload_database" );
  429. if ( event )
  430. {
  431. gameeventmanager->FireEventClientSide( event );
  432. }
  433. }
  434. #endif
  435. CWeaponDatabase::CWeaponDatabase() : m_bPreCached( false )
  436. {
  437. }
  438. bool CWeaponDatabase::Init()
  439. {
  440. ListenForGameEvent( "weapon_reload_database" );
  441. return LoadManifest();
  442. }
  443. bool CWeaponDatabase::LoadManifest()
  444. {
  445. // FIXME[pmf]: this is defined as a virtual in g_pGameRules, but it isn't construction yet...
  446. const unsigned char szEncryptionKey[] = "d7NSuLq2";
  447. // KeyValues::AutoDelete manifest = ReadEncryptedKVFile( filesystem, "scripts/weapon_manifest.txt", szEncryptionKey );
  448. KeyValues::AutoDelete manifest( "weaponscripts" );
  449. manifest->UsesEscapeSequences( true );
  450. if ( manifest->LoadFromFile( filesystem, "scripts/weapon_manifest.txt", "GAME" ) )
  451. {
  452. for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL ; sub = sub->GetNextKey() )
  453. {
  454. if ( !Q_stricmp( sub->GetName(), "file" ) )
  455. {
  456. char fileBase[512];
  457. Q_FileBase( sub->GetString(), fileBase, sizeof(fileBase) );
  458. LoadWeaponDataFromFile( filesystem, fileBase, szEncryptionKey );
  459. }
  460. else
  461. {
  462. Error( "Expecting 'file', got %s\n", sub->GetName() );
  463. }
  464. }
  465. }
  466. LoadEquipmentData();
  467. return true;
  468. }
  469. void CWeaponDatabase::PrecacheAllWeapons()
  470. {
  471. // NOTE[pmf]: removed this precache check for now, since it seems that the caches are getting evicted on map change
  472. // if ( m_bPreCached )
  473. // return;
  474. FOR_EACH_DICT( m_WeaponInfoDatabase, it )
  475. {
  476. const char* szClassName = m_WeaponInfoDatabase.GetElementName( it );
  477. #if defined( CLIENT_DLL )
  478. // don't try to precache items that don't have entities (e.g. the items don't exist as entities on the client)
  479. if ( GetClassMap().GetClassSize(szClassName) <= 0 )
  480. // if ( V_strncasecmp(szClassName, "item_", 5) == 0)
  481. continue;
  482. #endif
  483. UTIL_PrecacheOther( szClassName );
  484. }
  485. m_bPreCached = true;
  486. }
  487. void CWeaponDatabase::RefreshAllWeapons()
  488. {
  489. FOR_EACH_DICT( m_WeaponInfoDatabase, it )
  490. {
  491. FileWeaponInfo_t* pWeaponInfo = m_WeaponInfoDatabase[it];
  492. if ( pWeaponInfo )
  493. {
  494. pWeaponInfo->RefreshDynamicParameters();
  495. }
  496. }
  497. }
  498. WEAPON_FILE_INFO_HANDLE CWeaponDatabase::FindWeaponInfo( const char *name )
  499. {
  500. return m_WeaponInfoDatabase.Find( name );
  501. }
  502. WEAPON_FILE_INFO_HANDLE CWeaponDatabase::FindOrCreateWeaponInfo( const char *name )
  503. {
  504. // Complain about duplicately defined metaclass names...
  505. unsigned short lookup = m_WeaponInfoDatabase.Find( name );
  506. if ( lookup != m_WeaponInfoDatabase.InvalidIndex() )
  507. {
  508. return lookup;
  509. }
  510. FileWeaponInfo_t *insert = CreateWeaponInfo();
  511. lookup = m_WeaponInfoDatabase.Insert( name, insert );
  512. Assert( lookup != m_WeaponInfoDatabase.InvalidIndex() );
  513. return lookup;
  514. }
  515. static FileWeaponInfo_t * Helper_GetNullWeaponInfo()
  516. {
  517. static FileWeaponInfo_t gNullWeaponInfo;
  518. return &gNullWeaponInfo;
  519. }
  520. FileWeaponInfo_t * CWeaponDatabase::GetFileWeaponInfoFromHandle( WEAPON_FILE_INFO_HANDLE handle )
  521. {
  522. if ( handle >= m_WeaponInfoDatabase.Count() )
  523. {
  524. return Helper_GetNullWeaponInfo();
  525. }
  526. if ( handle == m_WeaponInfoDatabase.InvalidIndex() )
  527. {
  528. return Helper_GetNullWeaponInfo();
  529. }
  530. return m_WeaponInfoDatabase[ handle ];
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Purpose: Read data on weapon from script file
  534. // Output: true - if data2 successfully read
  535. // false - if data load fails
  536. //-----------------------------------------------------------------------------
  537. bool CWeaponDatabase::LoadWeaponDataFromFile( IFileSystem* filesystem, const char *szWeaponName, const unsigned char *pICEKey )
  538. {
  539. char sz[128];
  540. Q_snprintf( sz, sizeof( sz ), "scripts/%s", szWeaponName );
  541. KeyValues *pKV = ReadEncryptedKVFile( filesystem, sz, pICEKey );
  542. if ( !pKV )
  543. return false;
  544. WEAPON_FILE_INFO_HANDLE handle = FindOrCreateWeaponInfo( szWeaponName );
  545. FileWeaponInfo_t *pFileInfo = GetFileWeaponInfoFromHandle( handle );
  546. Assert( pFileInfo );
  547. pFileInfo->Parse( pKV, szWeaponName );
  548. pKV->deleteThis();
  549. return true;
  550. }
  551. void CWeaponDatabase::Reset()
  552. {
  553. int c = m_WeaponInfoDatabase.Count();
  554. for ( int i = 0; i < c; ++i )
  555. {
  556. delete m_WeaponInfoDatabase[ i ];
  557. }
  558. m_WeaponInfoDatabase.RemoveAll();
  559. #ifdef _DEBUG
  560. memset(g_bUsedWeaponSlots, 0, sizeof(g_bUsedWeaponSlots));
  561. #endif
  562. m_bPreCached = false;
  563. }
  564. void CWeaponDatabase::FireGameEvent( IGameEvent *pEvent )
  565. {
  566. #if defined( CLIENT_DLL )
  567. const char *pEventName = pEvent->GetName();
  568. if ( 0 == Q_strcmp( pEventName, "weapon_reload_database" ) )
  569. {
  570. LoadManifest();
  571. }
  572. #endif
  573. }