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.

8972 lines
304 KiB

  1. //====== Copyright ?, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: EconItemSchema: Defines a schema for econ items
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "econ_item_schema.h"
  8. #include "tier1/fmtstr.h"
  9. #include "tier2/tier2.h"
  10. #include "filesystem.h"
  11. #include "schemainitutils.h"
  12. #include "cstrike15_gcconstants.h"
  13. #include <google/protobuf/text_format.h>
  14. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  15. #include "econ_item_system.h"
  16. #include "econ_item.h"
  17. #include "activitylist.h"
  18. #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
  19. #include "tf_gcmessages.h"
  20. #endif
  21. #endif
  22. #if defined(CSTRIKE_CLIENT_DLL) || defined(CSTRIKE_DLL)
  23. #include "cstrike15_gcmessages.pb.h"
  24. #endif
  25. #include "gametypes.h"
  26. // memdbgon must be the last include file in a .cpp file!!!
  27. #include "tier0/memdbgon.h"
  28. using namespace GCSDK;
  29. #if defined(GAME_DLL)
  30. void PrecacheParticleFileAndSystems( const char *pParticleSystemFile );
  31. #endif
  32. #if defined(CLIENT_DLL)
  33. bool CWebResource::s_Initialized = false;
  34. #endif
  35. CEconItemSchema & GEconItemSchema()
  36. {
  37. #if defined( EXTERNALTESTS_DLL )
  38. static CEconItemSchema g_econItemSchema;
  39. return g_econItemSchema;
  40. #else
  41. return *ItemSystem()->GetItemSchema();
  42. #endif
  43. }
  44. const char * g_arrQuestVars[ k_EQuestVar_Last ] = { "" };
  45. /** Removed for partner depot **/
  46. static void HelperValidateLocalizationStringToken( char const *pszToken )
  47. {
  48. #ifdef CLIENT_DLL
  49. if ( pszToken && *pszToken == '#' )
  50. AssertMsg1( g_pVGuiLocalize->Find( pszToken ), "Schema is referencing a non-existant token: %s", pszToken );
  51. #endif
  52. }
  53. const char *g_szDropTypeStrings[] =
  54. {
  55. "", // Blank and none mean the same thing: stay attached to the body.
  56. "none",
  57. "drop", // The item drops off the body.
  58. "break", // Not implemented, but an example of a type that could be added.
  59. };
  60. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  61. // Used to convert strings to ints for wearable animation types
  62. const char *g_WearableAnimTypeStrings[NUM_WAP_TYPES] =
  63. {
  64. "on_spawn", // WAP_ON_SPAWN,
  65. "start_building", // WAP_START_BUILDING,
  66. "stop_building", // WAP_STOP_BUILDING,
  67. };
  68. #endif
  69. const char *g_AttributeDescriptionFormats[] =
  70. {
  71. "value_is_percentage", // ATTDESCFORM_VALUE_IS_PERCENTAGE,
  72. "value_is_inverted_percentage", // ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE
  73. "value_is_additive", // ATTDESCFORM_VALUE_IS_ADDITIVE
  74. "value_is_additive_percentage", // ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE
  75. "value_is_or", // ATTDESCFORM_VALUE_IS_OR
  76. "value_is_date", // ATTDESCFORM_VALUE_IS_DATE
  77. "value_is_account_id", // ATTDESCFORM_VALUE_IS_ACCOUNT_ID
  78. "value_is_particle_index", // ATTDESCFORM_VALUE_IS_PARTICLE_INDEX -> Could change to "string index"
  79. "value_is_item_def", // ATTDESCFORM_VALUE_IS_ITEM_DEF
  80. "value_is_color", // ATTDESCFORM_VALUE_IS_COLOR
  81. "value_is_game_time", // ATTDESCFORM_VALUE_IS_GAME_TIME
  82. "value_is_mins_as_hours", // ATTDESCFORM_VALUE_IS_MINS_AS_HOURS
  83. "value_is_replace", // ATTDESCFORM_VALUE_IS_REPLACE
  84. };
  85. const char *g_EffectTypes[NUM_EFFECT_TYPES] =
  86. {
  87. "neutral", // ATTRIB_EFFECT_NEUTRAL = 0,
  88. "positive", // ATTRIB_EFFECT_POSITIVE,
  89. "negative", // ATTRIB_EFFECT_NEGATIVE,
  90. };
  91. const char *g_szParticleAttachTypes[] =
  92. {
  93. "absorigin", // PATTACH_ABSORIGIN = 0, // Create at absorigin, but don't follow
  94. "absorigin_follow", // PATTACH_ABSORIGIN_FOLLOW, // Create at absorigin, and update to follow the entity
  95. "customorigin", // PATTACH_CUSTOMORIGIN, // Create at a custom origin, but don't follow
  96. "customorigin_follow", // PATTACH_CUSTOMORIGIN_FOLLOW, // Create at a custom origin, follow relative position to specified entity
  97. "point", // PATTACH_POINT, // Create on attachment point, but don't follow
  98. "point_follow", // PATTACH_POINT_FOLLOW, // Create on attachment point, and update to follow the entity
  99. "eyes_follow", // PATTACH_EYES_FOLLOW, // Create on eyes of the attached entity, and update to follow the entity
  100. "overhead_follow", // PATTACH_OVERHEAD_FOLLOW, // Create at the top of the entity's bbox
  101. "worldorigin", // PATTACH_WORLDORIGIN, // Used for control points that don't attach to an entity
  102. "rootbone_follow", // PATTACH_ROOTBONE_FOLLOW, // Create at the root bone of the entity, and update to follow
  103. "point_follow_substepped", // PATTACH_POINT_FOLLOW_SUBSTEPPED,// Like point_follow with interpolation
  104. "renderorigin_follow", // PATTACH_RENDERORIGIN_FOLLOW // Create at the renderorigin of the entity, and update to follow
  105. };
  106. const char *g_szParticleAttachToEnt[] =
  107. {
  108. "self", // ATTPART_TO_SELF,
  109. "parent", // ATTPART_TO_PARENT,
  110. };
  111. //-----------------------------------------------------------------------------
  112. // Purpose: Set the capabilities bitfield based on whether the entry is true/false.
  113. //-----------------------------------------------------------------------------
  114. const char *g_Capabilities[] =
  115. {
  116. "paintable", // ITEM_CAP_PAINTABLE
  117. "nameable", // ITEM_CAP_NAMEABLE
  118. "decodable", // ITEM_CAP_DECODABLE
  119. "can_delete", // ITEM_CAP_CAN_DELETE
  120. "can_customize_texture", // ITEM_CAP_CAN_CUSTOMIZE_TEXTURE
  121. "usable", // ITEM_CAP_USABLE
  122. "usable_gc", // ITEM_CAP_USABLE_GC
  123. "can_gift_wrap", // ITEM_CAP_CAN_GIFT_WRAP
  124. "usable_out_of_game", // ITEM_CAP_USABLE_OUT_OF_GAME
  125. "can_collect", // ITEM_CAP_CAN_COLLECT
  126. "can_craft_count", // ITEM_CAP_CAN_CRAFT_COUNT
  127. "can_craft_mark", // ITEM_CAP_CAN_CRAFT_MARK
  128. "paintable_team_colors", // ITEM_CAP_PAINTABLE_TEAM_COLORS
  129. "can_be_restored", // ITEM_CAP_CAN_BE_RESTORED
  130. "strange_parts", // ITEM_CAP_CAN_USE_STRANGE_PARTS
  131. "paintable_unusual", // ITEM_CAP_PAINTABLE_UNUSUAL
  132. "can_increment", // ITEM_CAP_CAN_INCREMENT
  133. "uses_essence", // ITEM_CAP_USES_ESSENCE
  134. "autograph", // ITEM_CAP_AUTOGRAPH
  135. "recipe", // ITEM_CAP_RECIPE
  136. "can_sticker", // ITEM_CAP_CAN_STICKER
  137. "can_stattrack_swap", // ITEM_CAP_STATTRACK_SWAP
  138. };
  139. const char* g_AssetModifiers[] =
  140. {
  141. "activity",
  142. "announcer",
  143. "announcer_preview",
  144. "hud_skin",
  145. "ability_name",
  146. "sound",
  147. "speech",
  148. "particle",
  149. "particle_snapshot",
  150. "particle_control_point",
  151. "entity_model",
  152. "entity_scale",
  153. "icon_replacement",
  154. "ability_icon_replacement",
  155. "courier",
  156. "courier_flying",
  157. "hero_model_change"
  158. };
  159. #define RETURN_ATTRIBUTE_STRING( attrib_name, default_string ) \
  160. static CSchemaAttributeDefHandle pAttribString( attrib_name ); \
  161. const char *pchResultAttribString = default_string; \
  162. FindAttribute_UnsafeBitwiseCast< CAttribute_String >( this, pAttribString, &pchResultAttribString ); \
  163. return pchResultAttribString;
  164. #define RETURN_ATTRIBUTE_STRING_F( func_name, attrib_name, default_string ) \
  165. const char *func_name( void ) const { RETURN_ATTRIBUTE_STRING( attrib_name, default_string ) }
  166. EAssetModifier GetAssetModifierType( const char* pszType )
  167. {
  168. for ( int i=0; i<AM_MAX; ++i )
  169. {
  170. if ( Q_strcmp( pszType, g_AssetModifiers[i] ) == 0 )
  171. return (EAssetModifier) i;
  172. }
  173. return AM_Invalid;
  174. }
  175. CUniformRandomStream CEconItemSchema::m_RandomStream;
  176. static void ParseCapability( item_capabilities_t &capsBitfield, KeyValues* pEntry )
  177. {
  178. COMPILE_TIME_ASSERT( ARRAYSIZE(g_Capabilities) == NUM_ITEM_CAPS );
  179. int idx = StringFieldToInt( pEntry->GetName(), g_Capabilities, ARRAYSIZE(g_Capabilities) );
  180. if ( idx < 0 )
  181. {
  182. return;
  183. }
  184. int bit = 1 << idx;
  185. if ( pEntry->GetBool() )
  186. {
  187. (int&)capsBitfield |= bit;
  188. }
  189. else
  190. {
  191. (int&)capsBitfield &= ~bit;
  192. }
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: interpret tint colors as integers for the values
  196. //-----------------------------------------------------------------------------
  197. static bool Helper_ExtractIntegerFromValueStringEntry( const char *szValue, int *pnValue )
  198. {
  199. if ( V_isdigit( *szValue ) )
  200. {
  201. *pnValue = V_atoi( szValue );
  202. return true;
  203. }
  204. else if ( char const *szTint = StringAfterPrefix( szValue, "tint_") )
  205. {
  206. if ( !V_stricmp( szTint, "min" ) )
  207. {
  208. *pnValue = 1;
  209. return true;
  210. }
  211. if ( !V_stricmp( szTint, "max" ) )
  212. {
  213. *pnValue = GEconItemSchema().GetGraffitiTintMaxValidDefID();
  214. return true;
  215. }
  216. if ( const CEconGraffitiTintDefinition *pDef = GEconItemSchema().GetGraffitiTintDefinitionByName( szTint ) )
  217. {
  218. *pnValue = pDef->GetID();
  219. return true;
  220. }
  221. return false;
  222. }
  223. return false;
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Purpose: interprets a string such as "1-3,5-20,45,46,47" and adds the
  227. // individual uint32s into the specified vector.
  228. //-----------------------------------------------------------------------------
  229. static bool Helper_ExtractIntegersFromValuesString( const char * pszValues, CCopyableUtlVector< uint32 > &vecValues )
  230. {
  231. bool bResult = true;
  232. CUtlVector< char* > vecValueStrings;
  233. V_SplitString( pszValues, ",", vecValueStrings );
  234. if ( vecValueStrings.Count() < 1 )
  235. bResult = false;
  236. FOR_EACH_VEC( vecValueStrings, i )
  237. {
  238. if ( V_strstr( vecValueStrings[ i ], "-" ) )
  239. {
  240. CUtlVector< char* > vecRangeStrings;
  241. V_SplitString( vecValueStrings[ i ], "-", vecRangeStrings );
  242. if ( vecRangeStrings.Count() == 2 )
  243. {
  244. int iRangeMin = 0, iRangeMax = 0;
  245. if ( !Helper_ExtractIntegerFromValueStringEntry( vecRangeStrings[ 0 ], &iRangeMin ) ||
  246. !Helper_ExtractIntegerFromValueStringEntry( vecRangeStrings[ 1 ], &iRangeMax ) ||
  247. ( iRangeMin >= iRangeMax ) )
  248. {
  249. bResult = false;
  250. break;
  251. }
  252. for ( int j = iRangeMin; j <= iRangeMax; j++ )
  253. {
  254. vecValues.AddToTail( j );
  255. }
  256. }
  257. else
  258. {
  259. bResult = false;
  260. break;
  261. }
  262. vecRangeStrings.PurgeAndDeleteElements();
  263. }
  264. else
  265. {
  266. int iValue = 0;
  267. if ( !Helper_ExtractIntegerFromValueStringEntry( vecValueStrings[ i ], &iValue ) )
  268. {
  269. bResult = false;
  270. break;
  271. }
  272. vecValues.AddToTail( iValue );
  273. }
  274. }
  275. vecValueStrings.PurgeAndDeleteElements();
  276. return bResult;
  277. }
  278. #if defined ( CSTRIKE15 )
  279. const uint32 g_unNumWearBuckets = 3;
  280. uint64 Helper_GetAlternateIconKeyForWeaponPaintWearItem( item_definition_index_t nDefIdx, uint32 nPaintId, uint32 nWear )
  281. {
  282. return ( nDefIdx << 16 ) + ( nPaintId << 2 ) + nWear;
  283. }
  284. uint64 Helper_GetAlternateIconKeyForTintedStickerItem( uint32 nStickerKitID, uint32 unTintID )
  285. {
  286. unTintID = CombinedTintIDGetHSVID( unTintID );
  287. return ( uint64( 1 ) << 32 ) | ( ( nStickerKitID & 0xFFFFFF ) << 8 ) | ( unTintID & 0xFF );
  288. }
  289. #endif
  290. //-----------------------------------------------------------------------------
  291. // Purpose: Constructor
  292. //-----------------------------------------------------------------------------
  293. CEconItemQualityDefinition::CEconItemQualityDefinition( void )
  294. : m_nValue( INT_MAX )
  295. , m_bCanSupportSet( false )
  296. , m_unWeight( 0 )
  297. , m_bExplicitMatchesOnly( false )
  298. {
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Purpose: Copy constructor
  302. //-----------------------------------------------------------------------------
  303. CEconItemQualityDefinition::CEconItemQualityDefinition( const CEconItemQualityDefinition &that )
  304. {
  305. (*this) = that;
  306. }
  307. //-----------------------------------------------------------------------------
  308. // Purpose: Operator=
  309. //-----------------------------------------------------------------------------
  310. CEconItemQualityDefinition &CEconItemQualityDefinition::operator=( const CEconItemQualityDefinition &rhs )
  311. {
  312. m_nValue = rhs.m_nValue;
  313. m_strName = rhs.m_strName;
  314. m_bCanSupportSet = rhs.m_bCanSupportSet;
  315. m_unWeight = rhs.m_unWeight;
  316. m_bExplicitMatchesOnly = rhs.m_bExplicitMatchesOnly;
  317. return *this;
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Purpose: Initialize the quality definition
  321. // Input: pKVQuality - The KeyValues representation of the quality
  322. // schema - The overall item schema for this attribute
  323. // pVecErrors - An optional vector that will contain error messages if
  324. // the init fails.
  325. // Output: True if initialization succeeded, false otherwise
  326. //-----------------------------------------------------------------------------
  327. bool CEconItemQualityDefinition::BInitFromKV( KeyValues *pKVQuality, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  328. {
  329. m_nValue = pKVQuality->GetInt( "value", -1 );
  330. m_strName = pKVQuality->GetName();
  331. m_bCanSupportSet = pKVQuality->GetBool( "canSupportSet" );
  332. m_strHexColor = pKVQuality->GetString( "hexColor" );
  333. m_unWeight = pKVQuality->GetInt( "weight", 0 );
  334. // Check for required fields
  335. SCHEMA_INIT_CHECK(
  336. NULL != pKVQuality->FindKey( "value" ),
  337. CFmtStr( "Quality definition %s: Missing required field \"value\"", pKVQuality->GetName() ) );
  338. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  339. return SCHEMA_INIT_SUCCESS();
  340. #endif
  341. // Check for data consistency
  342. SCHEMA_INIT_CHECK(
  343. 0 != Q_stricmp( GetName(), "any" ),
  344. CFmtStr( "Quality definition any: The quality name \"any\" is a reserved keyword and cannot be used." ) );
  345. SCHEMA_INIT_CHECK(
  346. m_nValue != k_unItemQuality_Any,
  347. CFmtStr( "Quality definition %s: Invalid value (%d). It is reserved for Any", GetName(), k_unItemQuality_Any ) );
  348. return SCHEMA_INIT_SUCCESS();
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Purpose: Constructor
  352. //-----------------------------------------------------------------------------
  353. CEconItemRarityDefinition::CEconItemRarityDefinition( void )
  354. : m_nValue( INT_MAX )
  355. {
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Purpose: Copy constructor
  359. //-----------------------------------------------------------------------------
  360. CEconItemRarityDefinition::CEconItemRarityDefinition( const CEconItemRarityDefinition &that )
  361. {
  362. (*this) = that;
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Purpose: Operator=
  366. //-----------------------------------------------------------------------------
  367. CEconItemRarityDefinition &CEconItemRarityDefinition::operator=( const CEconItemRarityDefinition &rhs )
  368. {
  369. m_nValue = rhs.m_nValue;
  370. m_strName = rhs.m_strName;
  371. m_strLocKey = rhs.m_strLocKey;
  372. m_strWepLocKey = rhs.m_strWepLocKey;
  373. m_strLootList = rhs.m_strLootList;
  374. m_strRecycleLootList = rhs.m_strRecycleLootList;
  375. m_strDropSound = rhs.m_strDropSound;
  376. m_strNextRarity = rhs.m_strNextRarity;
  377. m_iWhiteCount = rhs.m_iWhiteCount;
  378. m_iBlackCount = rhs.m_iBlackCount;
  379. m_flWeight = rhs.m_flWeight;
  380. return *this;
  381. }
  382. //-----------------------------------------------------------------------------
  383. // Purpose: Initialize the rarity definition
  384. //-----------------------------------------------------------------------------
  385. bool CEconItemRarityDefinition::BInitFromKV( KeyValues *pKVRarity, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  386. {
  387. m_nValue = pKVRarity->GetInt( "value", -1 );
  388. m_strName = pKVRarity->GetName();
  389. m_strLocKey = pKVRarity->GetString( "loc_key" );
  390. m_strWepLocKey = pKVRarity->GetString( "loc_key_weapon" );
  391. m_iAttribColor = GetAttribColorIndexForName( pKVRarity->GetString( "color" ) );
  392. m_strLootList = pKVRarity->GetString( "loot_list" ); // Not required.
  393. m_strRecycleLootList = pKVRarity->GetString( "recycle_list" ); // Not required.
  394. m_strDropSound = pKVRarity->GetString( "drop_sound" );
  395. m_strNextRarity = pKVRarity->GetString( "next_rarity" ); // Not required.
  396. m_flWeight = pKVRarity->GetFloat( "weight", 0 );
  397. // Check for required fields
  398. SCHEMA_INIT_CHECK(
  399. NULL != pKVRarity->FindKey( "value" ),
  400. CFmtStr( "Rarity definition %s: Missing required field \"value\"", pKVRarity->GetName() ) );
  401. SCHEMA_INIT_CHECK(
  402. NULL != pKVRarity->FindKey( "loc_key" ),
  403. CFmtStr( "Rarity definition %s: Missing required field \"loc_key\"", pKVRarity->GetName() ) );
  404. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  405. return SCHEMA_INIT_SUCCESS();
  406. #endif
  407. return SCHEMA_INIT_SUCCESS();
  408. }
  409. //-----------------------------------------------------------------------------
  410. // Purpose:
  411. //-----------------------------------------------------------------------------
  412. bool CEconColorDefinition::BInitFromKV( KeyValues *pKVColor, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  413. {
  414. m_strName = pKVColor->GetName();
  415. m_strColorName = pKVColor->GetString( "color_name" );
  416. m_strHexColor = pKVColor->GetString( "hex_color" );
  417. SCHEMA_INIT_CHECK(
  418. !m_strColorName.IsEmpty(),
  419. CFmtStr( "Quality definition %s: missing \"color_name\"", GetName() ) );
  420. SCHEMA_INIT_CHECK(
  421. !m_strHexColor.IsEmpty(),
  422. CFmtStr( "Quality definition %s: missing \"hex_color\"", GetName() ) );
  423. return SCHEMA_INIT_SUCCESS();
  424. }
  425. //-----------------------------------------------------------------------------
  426. // Purpose:
  427. //-----------------------------------------------------------------------------
  428. bool CEconGraffitiTintDefinition::BInitFromKV( KeyValues *pKVColor, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  429. {
  430. m_nID = pKVColor->GetInt( "id" );
  431. m_strColorName = pKVColor->GetName();
  432. m_strHexColor = pKVColor->GetString( "hex_color" );
  433. SCHEMA_INIT_CHECK(
  434. !m_strColorName.IsEmpty(),
  435. CFmtStr( "Graffiti tint definition #%d %s: missing name", GetID(), GetColorName() ) );
  436. SCHEMA_INIT_CHECK(
  437. !m_strHexColor.IsEmpty() && ( m_strHexColor.Get()[0] == '#' ),
  438. CFmtStr( "Graffiti tint #%d %s: missing or invalid \"hex_color\"", GetID(), GetColorName() ) );
  439. m_unHexColorRGB = ( !m_strHexColor.IsEmpty() ) ? V_atoi( CFmtStr( "0x%s", m_strHexColor.Get() + 1 ) ) : 0;
  440. return !m_strColorName.IsEmpty() && !m_strHexColor.IsEmpty() && ( m_strHexColor.Get()[0] == '#' );
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose:
  444. //-----------------------------------------------------------------------------
  445. bool CEconMusicDefinition::BInitFromKV( KeyValues *pKVMusicDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  446. {
  447. nID = Q_atoi( pKVMusicDef->GetName() );
  448. m_strName = pKVMusicDef->GetString( "name" );
  449. m_strNameLocToken = pKVMusicDef->GetString( "loc_name" );
  450. m_strLocDescription = pKVMusicDef->GetString( "loc_description" );
  451. m_strPedestalDisplayModel = pKVMusicDef->GetString( "pedestal_display_model" );
  452. m_strInventoryImage = pKVMusicDef->GetString( "image_inventory" );
  453. SCHEMA_INIT_CHECK(
  454. ( nID > 0 ),
  455. CFmtStr( "Music definition %s: name must be a positive integer", GetName() ) );
  456. SCHEMA_INIT_CHECK(
  457. !m_strName.IsEmpty(),
  458. CFmtStr( "Music definition %s: missing \"name\"", GetName() ) );
  459. return SCHEMA_INIT_SUCCESS();
  460. }
  461. //-----------------------------------------------------------------------------
  462. // Purpose:
  463. //-----------------------------------------------------------------------------
  464. bool CEconQuestDefinition::BInitFromKV( KeyValues *pKVQuestDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  465. {
  466. //TODO - do we care to parse quest definitions on GC at all or only on game server and client?
  467. nID = Q_atoi( pKVQuestDef->GetName() );
  468. SCHEMA_INIT_CHECK(
  469. ( nID > 0 ),
  470. CFmtStr( "Quest definition %s: name must be a positive integer", GetName() ) );
  471. m_strName = pKVQuestDef->GetString( "name" );
  472. SCHEMA_INIT_CHECK(
  473. !m_strName.IsEmpty(),
  474. CFmtStr( "Quest definition %s: missing \"name\"", GetName() ) );
  475. m_strGameMode = pKVQuestDef->GetString( "gamemode" );
  476. m_strMapGroup = pKVQuestDef->GetString( "mapgroup" );
  477. m_strMap = pKVQuestDef->GetString( "map" );
  478. #ifndef GC_DLL
  479. static bool bLoadBannedWords = ( !!CommandLine()->FindParm( "-usebanlist" ) ) || (
  480. !!CommandLine()->FindParm( "-perfectworld" )
  481. );
  482. if ( bLoadBannedWords && !V_stricmp( m_strMap.Get(), "ar_monastery" ) )
  483. m_strMap = "ar_shoots";
  484. #endif
  485. m_bIsAnEvent = pKVQuestDef->GetBool( "is_an_event", false );
  486. // Campaign quests require client-exposed points remaining.
  487. // load non-GC only points if it exists.
  488. // Otherwise look for "gc_generation_settings/points"
  489. // quest events are always 1 point.
  490. if ( m_bIsAnEvent )
  491. {
  492. m_vecQuestPoints.AddToTail( 1 );
  493. }
  494. else
  495. {
  496. const char* pszPointsRemaining = pKVQuestDef->GetString( "points" );
  497. m_vecQuestPoints.Purge();
  498. if ( pszPointsRemaining && pszPointsRemaining[ 0 ] )
  499. {
  500. SCHEMA_INIT_CHECK(
  501. Helper_ExtractIntegersFromValuesString( pszPointsRemaining, m_vecQuestPoints ),
  502. CFmtStr( "Quest definition %s specifies a malformed values range: %s", GetName(), pszPointsRemaining ) );
  503. }
  504. else
  505. {
  506. // if points aren't specified then default to '1'
  507. m_vecQuestPoints.AddToTail( 1 );
  508. }
  509. }
  510. // campaigns use quest-defined rewards rather than attributes rolled later.
  511. m_strRewardLootList = pKVQuestDef->GetString( "quest_reward" );
  512. m_nDifficulty = pKVQuestDef->GetInt( "difficulty", 1 );
  513. m_nOperationalPoints = pKVQuestDef->GetInt( "operational_points", 0 );
  514. if ( !m_bIsAnEvent )
  515. {
  516. m_nXPReward = pKVQuestDef->GetInt( "xp_reward", ( m_nDifficulty + 1 ) * 100 ); // campaign quest: 1 = 200, 2 = 300, 3 = 400
  517. }
  518. else
  519. {
  520. m_nXPReward = pKVQuestDef->GetInt( "gc_generation_settings/xp_reward", 1 ); // default quest event xp reward to 1 per action
  521. }
  522. m_nTargetTeam = pKVQuestDef->GetInt( "target_team", 0 );
  523. m_strExpr = pKVQuestDef->GetString( "expression" );
  524. // BONUS
  525. m_strBonusExpr = pKVQuestDef->GetString( "expr_bonus" );
  526. // set bonus percent only if a bonus expression exists
  527. if ( !m_strBonusExpr.IsEmpty() )
  528. {
  529. m_nXPBonusPercent = pKVQuestDef->GetInt( "xp_bonus_percent", 100 ); // default bonus is 100%
  530. }
  531. else
  532. {
  533. m_nXPBonusPercent = 0;
  534. }
  535. #ifdef CLIENT_DLL // strings
  536. m_strNameLocToken = pKVQuestDef->GetString( "loc_name" );
  537. if ( !m_strNameLocToken.IsEmpty() )
  538. HelperValidateLocalizationStringToken( m_strNameLocToken );
  539. m_strShortNameLocToken = pKVQuestDef->GetString( "loc_shortname" );
  540. if ( !m_strShortNameLocToken.IsEmpty() )
  541. HelperValidateLocalizationStringToken( m_strShortNameLocToken );
  542. m_strDescriptionLocToken = pKVQuestDef->GetString( "loc_description" );
  543. if ( !m_strDescriptionLocToken.IsEmpty() )
  544. HelperValidateLocalizationStringToken( m_strDescriptionLocToken );
  545. m_strHudDescriptionLocToken = pKVQuestDef->GetString( "loc_huddescription" );
  546. if ( !m_strHudDescriptionLocToken.IsEmpty() )
  547. HelperValidateLocalizationStringToken( m_strHudDescriptionLocToken );
  548. // Localizers have request the ability to explicitly write each quest's description because the
  549. // programatic string construction in place is not flexible enough to accommodate various grammars.
  550. //
  551. // Description will defer to this string, if it exists. It should not be used in CSGO_English.
  552. if ( g_pVGuiLocalize->Find( CFmtStr( "Override_Quest_Description_%s", pKVQuestDef->GetName( ) ) ) )
  553. m_strDescriptionLocToken = CFmtStr( "Override_Quest_Description_%s", pKVQuestDef->GetName( ) );
  554. m_strLocBonus = pKVQuestDef->GetString( "loc_bonus" );
  555. if ( !m_strLocBonus.IsEmpty() )
  556. HelperValidateLocalizationStringToken( m_strLocBonus );
  557. m_strIcon = pKVQuestDef->GetString( "quest_icon" );
  558. // Quests used to use explicitly define "string_tokens" in their schema definitions.
  559. // Now the string tokens kv is populated by interpreting the expression
  560. // but we may still want to add tokens manually in the future.
  561. m_kvStringTokens = pKVQuestDef->FindKey( "string_tokens" );
  562. if ( !m_kvStringTokens )
  563. m_kvStringTokens = new KeyValues( "string_tokens" );
  564. KeyValues * pkvExpressionTokens = new KeyValues( "ExpressionTokens" );
  565. KeyValues::AutoDelete autodelete_pKVExpressionTokens( pkvExpressionTokens );
  566. TokenizeQuestExpression( m_strExpr, pkvExpressionTokens );
  567. Assert( pkvExpressionTokens->GetFirstSubKey() != NULL );
  568. PopulateQuestStringTokens( *this, *pkvExpressionTokens, *m_kvStringTokens );
  569. if ( !m_strBonusExpr.IsEmpty() )
  570. {
  571. KeyValues * pKVBonusExpressionTokens = new KeyValues( "BonusExpressionTokens" );
  572. KeyValues::AutoDelete autodelete_pKVBonusExpressionTokens( pKVBonusExpressionTokens );
  573. TokenizeQuestExpression( m_strBonusExpr, pKVBonusExpressionTokens );
  574. Assert( pKVBonusExpressionTokens->GetFirstSubKey() != NULL );
  575. PopulateQuestStringTokens( *this, *pKVBonusExpressionTokens, *m_kvStringTokens, true );
  576. }
  577. #endif // ifndef GAME_DLL
  578. // MAPGROUP
  579. //
  580. //
  581. bool bMapGroupValid = false;
  582. if ( m_strMapGroup.IsEmpty() ) { bMapGroupValid = true; } // "": empty mapgroups are technically valid
  583. /** Removed for partner depot **/
  584. AssertMsg2( bMapGroupValid, "QUEST %d references a non-existant mapgroup: %s.\n", nID, m_strMapGroup.Get() );
  585. #ifndef GAME_DLL // strings
  586. KeyValues *pGameModestxt = new KeyValues( "GameModes.txt" );
  587. KeyValues::AutoDelete autodelete( pGameModestxt );
  588. if ( !pGameModestxt->LoadFromFile( g_pFullFileSystem, "GameModes.txt" ) )
  589. {
  590. pGameModestxt = NULL;
  591. }
  592. // MAP
  593. //
  594. //
  595. // get map string from gamemodes.txt and insert it into m_kvStringTokens
  596. //
  597. //
  598. if ( !m_strMap.IsEmpty( ) && StringIsEmpty( m_kvStringTokens->GetString( "map" ) ) )
  599. {
  600. KeyValues *pMaps = pGameModestxt->FindKey( "maps" );
  601. if ( pMaps )
  602. {
  603. KeyValues *pMapKV = pMaps->FindKey( m_strMap );
  604. Assert( pMapKV );
  605. if ( pMapKV )
  606. {
  607. m_kvStringTokens->SetString( "map", pMapKV->GetString( "nameID" ) );
  608. m_kvStringTokens->SetString( "location", pMapKV->GetString( "nameID" ) );
  609. }
  610. }
  611. }
  612. // get mapgroup string from gamemodes.txt and insert it into m_kvStringTokens
  613. //
  614. //
  615. if ( !m_strMapGroup.IsEmpty() && StringIsEmpty( m_kvStringTokens->GetString( "mapgroup" ) ) )
  616. {
  617. KeyValues *pMapGroups = pGameModestxt->FindKey( "mapgroups" );
  618. if ( pMapGroups )
  619. {
  620. KeyValues *pMapGroup = pMapGroups->FindKey( m_strMapGroup );
  621. Assert( pMapGroup );
  622. if ( pMapGroup )
  623. {
  624. m_kvStringTokens->SetString( "mapgroup", pMapGroup->GetString( "nameID" ) );
  625. }
  626. // if we didn't specify a map then use the mapgroup as the location
  627. if ( !m_kvStringTokens->FindKey("location") )
  628. {
  629. m_kvStringTokens->SetString( "location", pMapGroup->GetString( "nameID" ) );
  630. }
  631. }
  632. }
  633. //GAMEMODE
  634. //
  635. //
  636. #ifdef DBGFLAG_ASSERT
  637. const char * szType;
  638. bool bGameModeValid = g_pGameTypes->GetGameTypeFromMode( m_strGameMode, szType );
  639. AssertMsg2( bGameModeValid, "QUEST %d references a non-existant gamemode: %s.\n", nID, m_strGameMode );
  640. #endif
  641. if ( StringIsEmpty( m_kvStringTokens->GetString( "gamemode" ) ) )
  642. {
  643. // get gamemode string from gamemodes.txt and insert it into m_kvStringTokens
  644. //
  645. //
  646. KeyValues *pGameTypes = pGameModestxt->FindKey( "gameTypes" );
  647. FOR_EACH_SUBKEY( pGameTypes, kvGameType )
  648. {
  649. KeyValues *pGameModes = kvGameType->FindKey( "GameModes" );
  650. if ( pGameModes )
  651. {
  652. KeyValues *pGameMode = pGameModes->FindKey( m_strGameMode );
  653. if ( pGameMode )
  654. {
  655. m_kvStringTokens->SetString( "gamemode", pGameModes->FindKey( m_strGameMode )->GetString( "NameID" ) );
  656. break;
  657. }
  658. }
  659. }
  660. }
  661. // check all strings in m_kvStringTokens
  662. FOR_EACH_VALUE( m_kvStringTokens, pKVStringToken )
  663. {
  664. const char* token = pKVStringToken->GetString();
  665. HelperValidateLocalizationStringToken( token );
  666. }
  667. FOR_EACH_TRUE_SUBKEY( m_kvStringTokens, pKVSubKey )
  668. {
  669. FOR_EACH_VALUE( pKVSubKey, pKVStringToken )
  670. {
  671. const char* token = pKVStringToken->GetString( );
  672. HelperValidateLocalizationStringToken( token );
  673. }
  674. }
  675. #endif // not GAME_DLL
  676. return SCHEMA_INIT_SUCCESS();
  677. }
  678. #ifdef CLIENT_DLL
  679. ///////////////////////////////////////////////////////////////////////////////////////////
  680. //
  681. // read the expression ( i.e. " %act_kill_human% && %cond_gun_borrowed% && %weapon_smg% )
  682. // and insert appropriate string tokens into the string token keyvalues structure
  683. //
  684. ////////////////////////////////////////////////////////////////////////////////////////////
  685. void CEconQuestDefinition::PopulateQuestStringTokens( CEconQuestDefinition &questDef, KeyValues &kvExpressionTokens, KeyValues &kvStringTokens, bool bBonus )
  686. {
  687. // 1. Validate that every token ( %TOKEN% ) is accounted for.
  688. // 2. Populate pkvStringTokens with tokens derived from expression keywords e.g. %weapon_ak47%
  689. KeyValues * pkvExpressionTokens = &kvExpressionTokens;
  690. int nItemCount = 0;
  691. FOR_EACH_SUBKEY( pkvExpressionTokens, kvSubKey )
  692. {
  693. bool bFound = false;
  694. if ( V_stristr( kvSubKey->GetName(), "act_" ) || V_stristr( kvSubKey->GetName(), "cond_" ) )
  695. {
  696. // validate that action or condition is recognized.
  697. for ( int i = 0; i < k_EQuestVar_Last; i++ )
  698. {
  699. if ( FStrEq( g_arrQuestVars[ i ], kvSubKey->GetName() ) )
  700. {
  701. if ( g_pVGuiLocalize->Find( CFmtStr( "#quest_action_singular_%s", kvSubKey->GetName() ) ) )
  702. {
  703. if ( !kvStringTokens.FindKey( "action" ) )
  704. {
  705. kvStringTokens.SetString( "action", CFmtStr( "#quest_action_singular_%s", kvSubKey->GetName() ) );
  706. }
  707. if ( !kvStringTokens.FindKey( "actions" ) )
  708. {
  709. kvStringTokens.SetString( "actions", CFmtStr( "#quest_action_plural_%s", kvSubKey->GetName() ) );
  710. }
  711. }
  712. /** Removed for partner depot **/
  713. // note that we have at least one generic weapon if we use any item condition.
  714. if ( V_stristr( kvSubKey->GetName( ), "cond_item" ) )
  715. {
  716. if ( nItemCount == 0 ) nItemCount = 1;
  717. }
  718. // debug kvStringTokens.SaveToFile( g_pFullFileSystem, "~expressiontokens.txt" );
  719. // debug pkvExpressionTokens->SaveToFile( g_pFullFileSystem, "~expressiontokens.txt" );
  720. bFound = true;
  721. break;
  722. }
  723. }
  724. }
  725. else if ( V_stristr( kvSubKey->GetName(), "weapon_" ) )
  726. {
  727. // find the items subkey or create one if it doesnt exist
  728. KeyValues* pkvItems = kvStringTokens.FindKey( "items" );
  729. if ( !pkvItems )
  730. {
  731. pkvItems = new KeyValues( "items" );
  732. kvStringTokens.AddSubKey( pkvItems );
  733. }
  734. CEconItemDefinition * pWeaponItemDef = GetItemSchema( )->GetItemDefinitionByName( kvSubKey->GetName( ) );
  735. if ( pWeaponItemDef )
  736. {
  737. // LEGACY PRE-2016
  738. if ( !kvStringTokens.FindKey( "weapon" ) )
  739. {
  740. kvStringTokens.SetString( "weapon", pWeaponItemDef->GetItemBaseName() );
  741. }
  742. // LEGACY PRE-2016
  743. // insert the weapon into the 'items' true subkey
  744. for ( int i = 1; i < 20; i++ )
  745. {
  746. const char * szItemKeyName = CFmtStr( "item%d", i );
  747. if ( !pkvItems->FindKey( szItemKeyName ) )
  748. {
  749. pkvItems->SetString( szItemKeyName, pWeaponItemDef->GetItemBaseName( ) );
  750. nItemCount++;
  751. break;
  752. }
  753. }
  754. bFound = true;
  755. // set the quest icon to the weapon if an icon was not explicitly set.
  756. if ( questDef.m_strIcon.IsEmpty( ) && !bBonus )
  757. {
  758. questDef.m_strIcon = kvSubKey->GetName() + WEAPON_CLASSNAME_PREFIX_LENGTH;
  759. }
  760. }
  761. else
  762. {
  763. // look for a weapon category/type
  764. for ( int i = 0; i < LOADOUT_POSITION_COUNT; i++ )
  765. {
  766. if ( V_stristr( kvSubKey->GetName(), CFmtStr( "weapon_%s", g_szLoadoutStrings[ i ] ) ) )
  767. {
  768. // LEGACY PRE-2016
  769. if ( !kvStringTokens.FindKey( "weapon" ) )
  770. {
  771. kvStringTokens.SetString( "weapon", g_szLoadoutStringsForDisplay[ i ] );
  772. }
  773. // LEGACY PRE-2016
  774. // insert the weapon into the 'items' true subkey
  775. for ( int j = 1; j < 20; j++ )
  776. {
  777. const char * szItemKeyName = CFmtStr( "item%d", j );
  778. if ( !pkvItems->FindKey( szItemKeyName ) )
  779. {
  780. const char * szLoadoutStringNoHashMark = g_szLoadoutStringsForDisplay[ i ] + 1;
  781. pkvItems->SetString( szItemKeyName, CFmtStr( "#quest_%s", szLoadoutStringNoHashMark ) );
  782. nItemCount++;
  783. break;
  784. }
  785. }
  786. bFound = true;
  787. break;
  788. }
  789. }
  790. }
  791. }
  792. else if ( V_stristr( kvSubKey->GetName(), "set_" ) )
  793. {
  794. for ( int i = 0; i < GetItemSchema()->GetItemSetCount(); i++ )
  795. {
  796. const CEconItemSetDefinition *pItemSetDef = GetItemSchema()->GetItemSetByIndex( i );
  797. if ( pItemSetDef && FStrEq( kvSubKey->GetName(), pItemSetDef->GetName() ) )
  798. {
  799. if ( !kvStringTokens.FindKey( "set" ) )
  800. {
  801. kvStringTokens.SetString( "set", CFmtStr( "#CSGO_%s", pItemSetDef->GetName() ) );
  802. }
  803. bFound = true;
  804. break;
  805. }
  806. }
  807. }
  808. else if ( V_stristr( kvSubKey->GetName(), "map_" ) )
  809. {
  810. /** Removed for partner depot **/
  811. }
  812. // debug save
  813. // kvStringTokens.SaveToFile( g_pFullFileSystem, "~expressiontokens.txt" );
  814. AssertMsg2( bFound, "QUEST %u refs a non-existant var: %s\n", questDef.GetID(), kvSubKey->GetName() );
  815. }
  816. // defaults
  817. if ( !kvStringTokens.FindKey( "commandverb" ) )
  818. {
  819. kvStringTokens.SetString( "commandverb", "#quest_commandverb_default" );
  820. }
  821. if ( !kvStringTokens.FindKey( "target" ) )
  822. {
  823. kvStringTokens.SetString( "target", "#emptystring" );
  824. }
  825. if ( !kvStringTokens.FindKey( "item_quality" ) )
  826. {
  827. kvStringTokens.SetString( "item_quality", "#emptystring" );
  828. }
  829. // no items were specified but due to specified item conditions we know we need one.
  830. if ( !kvStringTokens.FindKey( "items/item1" ) && ( nItemCount > 0 ) )
  831. {
  832. kvStringTokens.SetString( "items/item1", "#quest_item_default" );
  833. }
  834. // no description was specified so use one of the default ones.
  835. if ( questDef.m_strDescriptionLocToken.IsEmpty( ) && !bBonus )
  836. {
  837. questDef.m_strDescriptionLocToken = CFmtStr( "quest_default_%d_items_desc", nItemCount );
  838. }
  839. // no quest tracker description was specified, so use one of the default ones.
  840. if ( questDef.m_strHudDescriptionLocToken.IsEmpty( ) && !bBonus )
  841. {
  842. questDef.m_strHudDescriptionLocToken = CFmtStr( "quest_default_hud_%d_items_desc", nItemCount );
  843. }
  844. // kvStringTokens.SaveToFile( g_pFullFileSystem, "~stringtokens.txt" ); // debug only
  845. }
  846. #endif
  847. // NOTE: This does not detect syntax or unrecognized symbols. TODO: Still need to figure out how to detect those.
  848. bool CEconQuestDefinition::IsQuestExpressionValid( const char * pszQuestExpr )
  849. {
  850. if ( !pszQuestExpr || !pszQuestExpr[0] )
  851. return false;
  852. CExpressionCalculator expr = CExpressionCalculator( pszQuestExpr );
  853. ZeroOutQuestExpressionVariables( expr );
  854. // This seemed like a good idea but it doesn't work.
  855. //
  856. // for ( int i = 0; i < expr.VariableCount(); i++ )
  857. // {
  858. // if ( !StringIsEmpty( expr.GetVariableName( i ) ) && expr.GetVariableValue( i ) != 1.0 )
  859. // {
  860. // AssertMsg1( 0, "unknown variable %s in quest expression", expr.GetVariableName( i ) );
  861. // return false;
  862. // }
  863. // }
  864. float flResult;
  865. bool bSuccess = expr.Evaluate( flResult );
  866. return ( bSuccess && IsFinite(flResult) );
  867. }
  868. void CEconQuestDefinition::SetQuestExpressionVariable( CExpressionCalculator &expQuest, EQuestVar_t questVar, float flValue )
  869. {
  870. expQuest.SetVariable( CFmtStr( "%%%s%%", g_arrQuestVars[ questVar ] ), flValue );
  871. }
  872. void CEconQuestDefinition::ZeroOutQuestExpressionVariables( CExpressionCalculator &expr )
  873. {
  874. // it's not possible to iterate through expression variables but this would be ideal. VariableCount() returns 1 :/
  875. // expQuest.BuildVariableListFromExpression();
  876. //
  877. // for ( int i = 0; i < expQuest.VariableCount(); i++ )
  878. // {
  879. // expQuest.SetVariable( i, 0 );
  880. // }
  881. // ACTIONS and CONDITIONS
  882. /** Removed for partner depot **/
  883. // WEAPON TYPES
  884. for ( int i = 0; i < LOADOUT_POSITION_COUNT; i++ )
  885. {
  886. expr.SetVariable( CFmtStr( "%%weapon_%s%%", g_szLoadoutStrings[ i ] ), 0 );
  887. }
  888. // SETS
  889. for ( int i = 0; i < GetItemSchema()->GetItemSetCount(); i++ )
  890. {
  891. const CEconItemSetDefinition *pItemSetDef = GetItemSchema()->GetItemSetByIndex( i );
  892. expr.SetVariable( CFmtStr( "%%%s%%", pItemSetDef->GetName() ), 0 );
  893. }
  894. // WEAPONS
  895. static CUtlVector< const CEconItemDefinition * > s_vecWeaponItemDefs;
  896. // cache these items so we don't do string compares every time we initialize an expression
  897. if ( s_vecWeaponItemDefs.Count() == 0 )
  898. {
  899. FOR_EACH_MAP_FAST( GetItemSchema()->GetItemDefinitionMap(), i )
  900. {
  901. const CEconItemDefinition * pItemDef = GetItemSchema()->GetItemDefinitionByMapIndex( i );
  902. if ( V_stristr( pItemDef->GetDefinitionName(), "weapon_" ) )
  903. {
  904. s_vecWeaponItemDefs.AddToTail( pItemDef );
  905. }
  906. }
  907. }
  908. FOR_EACH_VEC( s_vecWeaponItemDefs, i )
  909. {
  910. expr.SetVariable( CFmtStr( "%%%s%%", s_vecWeaponItemDefs[ i ]->GetDefinitionName() ), 0 );
  911. }
  912. // MAPS
  913. /** Removed for partner depot **/
  914. }
  915. bool CEconCampaignDefinition::BInitFromKV( KeyValues *pKVCampaignDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /*= NULL */ )
  916. {
  917. m_nID = Q_atoi( pKVCampaignDef->GetName() );
  918. SCHEMA_INIT_CHECK(
  919. ( m_nID > 0 ),
  920. CFmtStr( "Campaign definition %d: name must be a positive integer", GetID() ) );
  921. m_strNameLocToken = pKVCampaignDef->GetString( "loc_name" );
  922. HelperValidateLocalizationStringToken( m_strNameLocToken );
  923. m_strLocDescription = pKVCampaignDef->GetString( "loc_description" );
  924. HelperValidateLocalizationStringToken( m_strLocDescription );
  925. m_nSeasonNumber = pKVCampaignDef->GetInt( "season_number" );
  926. SCHEMA_INIT_CHECK( m_nSeasonNumber > 0, CFmtStr( "Campaign %d must specifiy a season number", GetID() ) );
  927. FOR_EACH_TRUE_SUBKEY( pKVCampaignDef, pKVCampaignNode )
  928. {
  929. CEconCampaignNodeDefinition *pNewCampaignNodeDef = new CEconCampaignNodeDefinition;
  930. int CampaignNodeIndex = Q_atoi( pKVCampaignNode->GetName() );
  931. uint32 index = m_mapCampaignNodes.Find( CampaignNodeIndex );
  932. if ( !m_mapCampaignNodes.IsValidIndex( index ) )
  933. {
  934. m_mapCampaignNodes.Insert( CampaignNodeIndex, pNewCampaignNodeDef );
  935. SCHEMA_INIT_SUBSTEP( pNewCampaignNodeDef->BInitFromKV( GetID(), pKVCampaignNode, pschema ) );
  936. }
  937. else
  938. {
  939. SCHEMA_INIT_CHECK(
  940. false,
  941. CFmtStr( "Campaign definition %d: campaign node index %d is not unique", GetID(), CampaignNodeIndex ) );
  942. }
  943. }
  944. // go back and verify that all nodes point to valid nodes
  945. FOR_EACH_MAP_FAST( m_mapCampaignNodes, i )
  946. {
  947. const CUtlVector< uint32 >& pNextNodes = m_mapCampaignNodes.Element( i )->GetNextNodes();
  948. FOR_EACH_VEC( pNextNodes, j )
  949. {
  950. int nextnode = pNextNodes[ j ];
  951. int index = m_mapCampaignNodes.Find( nextnode );
  952. SCHEMA_INIT_CHECK(
  953. m_mapCampaignNodes.IsValidIndex( index ),
  954. CFmtStr( "Campaign definition %d: campaign node index %d leads to an invalid campaign node %d", GetID(), m_mapCampaignNodes.Element( i )->GetID(), nextnode ) );
  955. }
  956. }
  957. // build list of start nodes ( nodes that have no predecessors )
  958. m_mapStartNodes.Purge();
  959. // collect all nodes
  960. FOR_EACH_MAP_FAST( m_mapCampaignNodes, i )
  961. {
  962. m_mapStartNodes.Insert( m_mapCampaignNodes.Key( i ), m_mapCampaignNodes.Element( i ) );
  963. }
  964. // subtract nodes referenced as successors
  965. FOR_EACH_MAP_FAST( m_mapCampaignNodes, i )
  966. {
  967. const CUtlVector< uint32 >& pCampaignNodes = m_mapCampaignNodes.Element( i )->GetNextNodes();
  968. FOR_EACH_VEC( pCampaignNodes, j )
  969. {
  970. int nextnode = pCampaignNodes.Element( j );
  971. m_mapStartNodes.Remove( nextnode );
  972. }
  973. }
  974. return SCHEMA_INIT_SUCCESS();
  975. }
  976. void CEconCampaignDefinition::GetAccessibleCampaignNodes( const uint32 unCampaignCompletionBitfield, CUtlVector< CEconCampaignNodeDefinition* > &vecAccessibleNodes )
  977. {
  978. vecAccessibleNodes.Purge();
  979. // If no campaign quests have been done yet then the only possible quests are the starting quests.
  980. if ( unCampaignCompletionBitfield == 0 )
  981. {
  982. FOR_EACH_MAP_FAST( GetStartNodes(), i )
  983. {
  984. vecAccessibleNodes.AddToTail( GetStartNodes().Element( i ) );
  985. }
  986. }
  987. else
  988. {
  989. // otherwise recursively look for quests that are successors of completed quests.
  990. FOR_EACH_MAP_FAST( GetStartNodes(), i )
  991. {
  992. uint32 nCampaignNodeIndex = GetStartNodes().Key( i );
  993. // is this start quest already complete?
  994. if ( ( 1 << ( nCampaignNodeIndex - 1 ) ) & unCampaignCompletionBitfield )
  995. {
  996. // yes. recurse.
  997. Helper_RecursiveGetAccessibleCampaignNodes( unCampaignCompletionBitfield, GetStartNodes().Element( i ), vecAccessibleNodes );
  998. }
  999. else
  1000. {
  1001. // no. add it to the list and return;
  1002. vecAccessibleNodes.AddToTail( GetStartNodes().Element( i ) );
  1003. }
  1004. }
  1005. }
  1006. }
  1007. void CEconCampaignDefinition::Helper_RecursiveGetAccessibleCampaignNodes( const uint32 unCampaignCompletionBitfield, const CEconCampaignNodeDefinition* pNode, CUtlVector< CEconCampaignNodeDefinition* > &vecAccessibleNodes )
  1008. {
  1009. // recursively look for nodes that don't represent completed quests. Do not recurse incomplete quests.
  1010. FOR_EACH_VEC( pNode->GetNextNodes(), i )
  1011. {
  1012. uint32 unNextNodeIndex = pNode->GetNextNodes().Element( i );
  1013. int index = GetCampaignNodes().Find( unNextNodeIndex );
  1014. if ( GetCampaignNodes().IsValidIndex( index ) )
  1015. {
  1016. CEconCampaignDefinition::CEconCampaignNodeDefinition* pNextNode = GetCampaignNodes().Element( index );
  1017. // is this successor quest already complete?
  1018. if ( ( 1 << ( unNextNodeIndex - 1 ) ) & unCampaignCompletionBitfield )
  1019. {
  1020. // yes. recurse.
  1021. Helper_RecursiveGetAccessibleCampaignNodes( unCampaignCompletionBitfield, pNextNode, vecAccessibleNodes );
  1022. }
  1023. else
  1024. {
  1025. // no. add it to the list and return;
  1026. vecAccessibleNodes.AddToTail( pNextNode );
  1027. }
  1028. }
  1029. }
  1030. }
  1031. bool ResolveQuestIdToCampaignAndIndex( uint16 unQuestID, uint32 &unCampaignID, uint32 &unCamapaignNodeID )
  1032. {
  1033. static bool s_bQuestMappingInitialized = false;
  1034. static CUtlMap< uint16, uint64, uint16, CDefLess< uint16 > > s_mapping;
  1035. if ( !s_bQuestMappingInitialized )
  1036. {
  1037. s_bQuestMappingInitialized = true;
  1038. for ( uint32 unPossibleCampaignID = 1; unPossibleCampaignID <= g_nNumCampaigns; ++unPossibleCampaignID )
  1039. {
  1040. CEconCampaignDefinition const *pCampaignDef = GetItemSchema()->GetCampaignDefinition( unPossibleCampaignID );
  1041. if ( !pCampaignDef )
  1042. continue;
  1043. FOR_EACH_MAP_FAST( pCampaignDef->GetCampaignNodes(), iCN )
  1044. {
  1045. CEconCampaignDefinition::CEconCampaignNodeDefinition const &node = *pCampaignDef->GetCampaignNodes().Element( iCN );
  1046. uint16 unMappingKey = node.GetQuestIndex();
  1047. if ( unMappingKey )
  1048. {
  1049. uint64 unMappingValue = ( uint64( unPossibleCampaignID ) << 32 ) | uint64( node.GetID() );
  1050. Assert( s_mapping.Find( unMappingKey ) == s_mapping.InvalidIndex() );
  1051. s_mapping.InsertOrReplace( unMappingKey, unMappingValue );
  1052. }
  1053. }
  1054. }
  1055. }
  1056. uint16 idxMapping = s_mapping.Find( unQuestID );
  1057. if ( idxMapping == s_mapping.InvalidIndex() )
  1058. return false;
  1059. unCampaignID = uint32( s_mapping.Element( idxMapping ) >> 32 );
  1060. unCamapaignNodeID = uint32( s_mapping.Element( idxMapping ) );
  1061. return true;
  1062. }
  1063. bool CEconCampaignDefinition::CEconCampaignNodeDefinition::BInitFromKV( int nCampaignIndex, KeyValues *pKVCampaignNodeDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /*= NULL */ )
  1064. {
  1065. m_nID = Q_atoi( pKVCampaignNodeDef->GetName() );
  1066. SCHEMA_INIT_CHECK(
  1067. ( m_nID > 0 ),
  1068. CFmtStr( "Campaign Node definition %d: name must be a positive integer", GetID() ) );
  1069. m_CampaignID = nCampaignIndex;
  1070. m_nQuestIndex = Q_atoi( pKVCampaignNodeDef->GetString( "quest_index" ) );
  1071. if ( m_nQuestIndex ) // validate only if specified, story-only nodes don't have quest indices
  1072. {
  1073. SCHEMA_INIT_CHECK(
  1074. ( GetItemSchema()->GetQuestDefinition( m_nQuestIndex ) != NULL ),
  1075. CFmtStr( "Campaign definition %d, Node definition %d: Quest Index %d is not a valid quest index", nCampaignIndex, m_nID, m_nQuestIndex ) );
  1076. }
  1077. m_vecNextNodes.Purge();
  1078. FOR_EACH_SUBKEY( pKVCampaignNodeDef, pKVCampaignNodeKey )
  1079. {
  1080. if ( !V_strcmp( pKVCampaignNodeKey->GetName(), "->" ) )
  1081. {
  1082. m_vecNextNodes.AddToTail( Q_atoi( pKVCampaignNodeKey->GetString() ) );
  1083. }
  1084. }
  1085. #ifdef CLIENT_DLL
  1086. FOR_EACH_TRUE_SUBKEY( pKVCampaignNodeDef, pKVCampaignNodeKey )
  1087. {
  1088. if ( FStrEq( pKVCampaignNodeKey->GetName(), "story_block" ) )
  1089. {
  1090. CEconCampaignNodeStoryBlockDefinition *pNewCampaignNodeStoryBlockDef = new CEconCampaignNodeStoryBlockDefinition;
  1091. m_vecStoryBlocks.AddToTail( pNewCampaignNodeStoryBlockDef );
  1092. SCHEMA_INIT_SUBSTEP( pNewCampaignNodeStoryBlockDef->BInitFromKV( nCampaignIndex, m_nID, pKVCampaignNodeKey, pschema ) );
  1093. }
  1094. }
  1095. #endif
  1096. return SCHEMA_INIT_SUCCESS();
  1097. }
  1098. #ifdef CLIENT_DLL
  1099. // score every story block and return the highest scoring one
  1100. CEconCampaignDefinition::CEconCampaignNodeDefinition::CEconCampaignNodeStoryBlockDefinition * CEconCampaignDefinition::CEconCampaignNodeDefinition::GetBestScoringStoryBlock( CEconItemView *pCampaignCoin ) const
  1101. {
  1102. CEconCampaignDefinition::CEconCampaignNodeDefinition::CEconCampaignNodeStoryBlockDefinition * pBestStoryBlock = NULL;
  1103. float flBestStoryBlockScore = 0;
  1104. FOR_EACH_VEC( GetStoryBlocks(), iSB )
  1105. {
  1106. float flCurStoryBlockScore = GetStoryBlocks()[ iSB ]->EvaluateStoryBlockExpression( pCampaignCoin );
  1107. // only consider story block expressions that have a positive score
  1108. if ( flCurStoryBlockScore > 0 )
  1109. {
  1110. if ( !pBestStoryBlock )
  1111. {
  1112. pBestStoryBlock = GetStoryBlocks()[ iSB ];
  1113. flBestStoryBlockScore = flCurStoryBlockScore;
  1114. }
  1115. else
  1116. {
  1117. if ( flCurStoryBlockScore > flBestStoryBlockScore )
  1118. {
  1119. pBestStoryBlock = GetStoryBlocks()[ iSB ];
  1120. flBestStoryBlockScore = flCurStoryBlockScore;
  1121. }
  1122. }
  1123. }
  1124. }
  1125. return pBestStoryBlock;
  1126. }
  1127. bool CEconCampaignDefinition::CEconCampaignNodeDefinition::CEconCampaignNodeStoryBlockDefinition::BInitFromKV( int nCampaignIndex, int nNodeID, KeyValues * pKVCampaignNodeStoryBlockDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  1128. {
  1129. m_strContentFile = pKVCampaignNodeStoryBlockDef->GetString( "content_file" );
  1130. m_strCharacterName = pKVCampaignNodeStoryBlockDef->GetString( "character_name" );
  1131. m_strDescription = pKVCampaignNodeStoryBlockDef->GetString( "description" );
  1132. if ( !m_strDescription.IsEmpty() )
  1133. HelperValidateLocalizationStringToken( m_strDescription );
  1134. m_strExpr = pKVCampaignNodeStoryBlockDef->GetString( "expression" );
  1135. return SCHEMA_INIT_SUCCESS();
  1136. }
  1137. // Take the expression of an CExpressionCalculator, such as " %weapon_ak47% && %kill% " and extract the % delimited keywords.
  1138. //
  1139. void CEconQuestDefinition::TokenizeQuestExpression( const char * szExpression, KeyValues * pKVExpressionTokens )
  1140. {
  1141. if ( !szExpression || !szExpression[0] )
  1142. return;
  1143. if ( !pKVExpressionTokens )
  1144. return;
  1145. const char * pCur = szExpression;
  1146. char szKeyword[ 256 ] = { '\0' };
  1147. char *pCurCopy = szKeyword;
  1148. bool bReadingKeyword = false;
  1149. while ( *pCur != '\0' )
  1150. {
  1151. if ( *pCur == '%' && !bReadingKeyword )
  1152. {
  1153. bReadingKeyword = true;
  1154. // reset destination buffer;
  1155. V_memset( szKeyword, '\0', sizeof( szKeyword ) );
  1156. pCurCopy = szKeyword;
  1157. // step past '%'
  1158. pCur++;
  1159. }
  1160. else if ( *pCur == '%' && bReadingKeyword )
  1161. {
  1162. // end of the keyword
  1163. bReadingKeyword = false;
  1164. // terminate the string with a null char and then look it up
  1165. pCurCopy++;
  1166. *pCurCopy = '\0';
  1167. pKVExpressionTokens->SetBool( szKeyword, true );
  1168. // step past '%'
  1169. pCur++;
  1170. }
  1171. if ( bReadingKeyword )
  1172. {
  1173. // keep copying the keyword until we reach the terminating '%'
  1174. *pCurCopy = *pCur;
  1175. pCurCopy++;
  1176. pCur++;
  1177. }
  1178. else
  1179. {
  1180. // keep walking until we find the start of a keyword: '%'
  1181. pCur++;
  1182. }
  1183. }
  1184. }
  1185. float CEconCampaignDefinition::CEconCampaignNodeDefinition::CEconCampaignNodeStoryBlockDefinition::EvaluateStoryBlockExpression( CEconItemView *pCampaignCoin ) const
  1186. {
  1187. // if there's no expression specified then return a minimally true value.
  1188. if ( m_strExpr.IsEmpty() )
  1189. return 0.99; // default without an expression is trumped by any block with an expression result of 1.0. This means that any true expression block will get picked
  1190. // over any block with no expression.
  1191. CExpressionCalculator expStoryBlock = CExpressionCalculator( GetStoryBlockExpression() );
  1192. KeyValues * pKVExpressionTokens = new KeyValues( "ExpressionTokens" );
  1193. KeyValues::AutoDelete autodelete_pKVExpressionTokens( pKVExpressionTokens );
  1194. CEconQuestDefinition::TokenizeQuestExpression( GetStoryBlockExpression(), pKVExpressionTokens );
  1195. // go through each referenced quest and set the variable %questid% to the value of its completion state ( 0 or 1 )
  1196. FOR_EACH_SUBKEY( pKVExpressionTokens, kvSubKey )
  1197. {
  1198. uint16 unQuestID = V_atoi( kvSubKey->GetName() );
  1199. uint32 unCampaignID;
  1200. uint32 unCampaignNodeID;
  1201. ResolveQuestIdToCampaignAndIndex( unQuestID, unCampaignID, unCampaignNodeID );
  1202. const CSchemaAttributeDefHandle pAttr_CampaignCompletionBitfield = GetCampaignAttributeDefHandle( unCampaignID, k_ECampaignAttribute_CompletionBitfield );
  1203. uint32 unCampaignCompletionBitfield;
  1204. if ( !pCampaignCoin->FindAttribute( pAttr_CampaignCompletionBitfield, &unCampaignCompletionBitfield ) )
  1205. return 0;
  1206. uint32 unMask = ( 1 << ( unCampaignNodeID - 1 ) );
  1207. const char * szKeyWord = CFmtStr( "%%%s%%", kvSubKey->GetName() );
  1208. float flCompletionState = ( unCampaignCompletionBitfield & unMask ) ? 1.0 : 0.0;
  1209. expStoryBlock.SetVariable( szKeyWord, flCompletionState );
  1210. }
  1211. expStoryBlock.BuildVariableListFromExpression();
  1212. float flReturn;
  1213. expStoryBlock.Evaluate( flReturn );
  1214. return flReturn;
  1215. }
  1216. #endif
  1217. bool item_list_entry_t::InitFromName( const char *pchName )
  1218. {
  1219. if ( pchName[ 0 ] == '[' )
  1220. {
  1221. // This item has an attached paint type that can affect the name and rarity!
  1222. pchName++;
  1223. char szPaintName[ 256 ];
  1224. int i;
  1225. for( i = 0; i < ARRAYSIZE( szPaintName ) - 1 && pchName[ i ] != ']'; ++i )
  1226. {
  1227. szPaintName[ i ] = pchName[ i ];
  1228. }
  1229. szPaintName[ i ] = '\0';
  1230. if ( pchName[ i ] != ']' )
  1231. return false;
  1232. pchName += i + 1;
  1233. const CPaintKit *pPaintKit = GetItemSchema()->GetPaintKitDefinitionByName( szPaintName );
  1234. if ( pPaintKit )
  1235. {
  1236. m_nPaintKit = pPaintKit->nID;
  1237. }
  1238. else
  1239. {
  1240. const CStickerKit *pStickerKit = GetItemSchema()->GetStickerKitDefinitionByName( szPaintName );
  1241. if ( pStickerKit )
  1242. {
  1243. m_nStickerKit = pStickerKit->nID;
  1244. }
  1245. else
  1246. {
  1247. const CEconMusicDefinition *pMusicKit = GetItemSchema()->GetMusicKitDefinitionByName( szPaintName );
  1248. if ( pMusicKit )
  1249. {
  1250. m_nMusicKit = pMusicKit->GetID();
  1251. }
  1252. else
  1253. {
  1254. DevWarning( "Kit \"[%s]\" specified, but doesn't exist!! You're probably missing an entry in items_paintkits.txt or items_stickerkits.txt or need to run with -use_local_item_data\n", szPaintName );
  1255. return false;
  1256. }
  1257. }
  1258. }
  1259. }
  1260. CEconItemDefinition *pDef = GetItemSchema()->GetItemDefinitionByName( pchName );
  1261. if ( pDef )
  1262. {
  1263. m_nItemDef = pDef->GetDefinitionIndex();
  1264. }
  1265. return true;
  1266. }
  1267. //-----------------------------------------------------------------------------
  1268. //
  1269. //-----------------------------------------------------------------------------
  1270. CEconItemSetDefinition::CEconItemSetDefinition( void )
  1271. : m_pszName( NULL )
  1272. , m_pszLocalizedName( NULL )
  1273. , m_pszLocalizedDescription( NULL )
  1274. , m_pszUnlocalizedName( NULL )
  1275. , m_iBundleItemDef( INVALID_ITEM_DEF_INDEX )
  1276. , m_bIsCollection( false )
  1277. , m_bIsHiddenSet( false )
  1278. , m_nCraftReward( 0 )
  1279. {
  1280. }
  1281. //-----------------------------------------------------------------------------
  1282. // Purpose: Copy constructor
  1283. //-----------------------------------------------------------------------------
  1284. CEconItemSetDefinition::CEconItemSetDefinition( const CEconItemSetDefinition &that )
  1285. {
  1286. (*this) = that;
  1287. }
  1288. //-----------------------------------------------------------------------------
  1289. // Purpose: Operator=
  1290. //-----------------------------------------------------------------------------
  1291. CEconItemSetDefinition &CEconItemSetDefinition::operator=( const CEconItemSetDefinition &other )
  1292. {
  1293. m_pszName = other.m_pszName;
  1294. m_pszLocalizedName = other.m_pszLocalizedName;
  1295. m_pszUnlocalizedName = other.m_pszUnlocalizedName;
  1296. m_pszLocalizedDescription = other.m_pszLocalizedDescription;
  1297. m_pszUnlocalizedName = other.m_pszUnlocalizedName;
  1298. m_ItemEntries = other.m_ItemEntries;
  1299. m_iAttributes = other.m_iAttributes;
  1300. m_iBundleItemDef = other.m_iBundleItemDef;
  1301. m_bIsCollection = other.m_bIsCollection;
  1302. m_bIsHiddenSet = other.m_bIsHiddenSet;
  1303. m_nCraftReward = other.m_nCraftReward;
  1304. return *this;
  1305. }
  1306. //-----------------------------------------------------------------------------
  1307. //
  1308. //-----------------------------------------------------------------------------
  1309. bool CEconItemSetDefinition::BInitFromKV( KeyValues *pKVItemSet, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors )
  1310. {
  1311. m_pszName = pKVItemSet->GetName();
  1312. m_iBundleItemDef = INVALID_ITEM_DEF_INDEX;
  1313. const char *pszBundleName = pKVItemSet->GetString( "store_bundle" );
  1314. if ( pszBundleName && pszBundleName[0] )
  1315. {
  1316. const CEconItemDefinition *pDef = pschema.GetItemDefinitionByName( pszBundleName );
  1317. if ( pDef )
  1318. {
  1319. m_iBundleItemDef = pDef->GetDefinitionIndex();
  1320. }
  1321. SCHEMA_INIT_CHECK(
  1322. pDef != NULL,
  1323. CFmtStr( "Item Set %s: Bundle definition \"%s\" was not found", m_pszName, pszBundleName ) );
  1324. }
  1325. FOR_EACH_SUBKEY( pKVItemSet, pKVSetItem )
  1326. {
  1327. const char *pszName = pKVSetItem->GetName();
  1328. if ( !Q_strcmp( pszName, "name" ) )
  1329. {
  1330. SCHEMA_INIT_CHECK(
  1331. m_pszLocalizedName == NULL,
  1332. CFmtStr( "Item Set %s: Duplicate name specified", m_pszName ) );
  1333. m_pszLocalizedName = pKVSetItem->GetString();
  1334. }
  1335. else if ( !Q_strcmp( pszName, "set_description" ) )
  1336. {
  1337. m_pszLocalizedDescription = pKVSetItem->GetString();
  1338. }
  1339. else if ( !Q_strcmp( pszName, "unlocalized_name" ) )
  1340. {
  1341. m_pszUnlocalizedName = pKVSetItem->GetString();
  1342. }
  1343. else if ( !Q_strcmp( pszName, "is_collection" ) )
  1344. {
  1345. m_bIsCollection = pKVSetItem->GetBool();
  1346. }
  1347. else if ( !Q_strcmp( pszName, "is_hidden_set" ) )
  1348. {
  1349. m_bIsHiddenSet = pKVSetItem->GetBool();
  1350. }
  1351. // else if ( !Q_strcmp( pszName, "craft_reward" ) )
  1352. // {
  1353. // const char *pchCraftReward = pKVSetItem->GetString();
  1354. // if ( pchCraftReward && pchCraftReward[ 0 ] != '\0' )
  1355. // {
  1356. // const CEconItemDefinition *pItemDef = pschema.GetItemDefinitionByName( pKVSetItem->GetString() );
  1357. //
  1358. // SCHEMA_INIT_CHECK(
  1359. // pItemDef && pItemDef->GetDefinitionIndex() > 0,
  1360. // CFmtStr( "Item Collection Craft Reward \"%s\" specifies invalid item def", pKVItemSet->GetName() ) );
  1361. //
  1362. // m_nCraftReward = pItemDef->GetDefinitionIndex();
  1363. // }
  1364. // }
  1365. else if ( !Q_strcmp( pszName, "items" ) )
  1366. {
  1367. FOR_EACH_SUBKEY( pKVSetItem, pKVItem )
  1368. {
  1369. pszName = pKVItem->GetName();
  1370. item_list_entry_t entry;
  1371. bool bEntrySuccess = entry.InitFromName( pszName );
  1372. bEntrySuccess;
  1373. m_ItemEntries.AddToTail( entry );
  1374. }
  1375. }
  1376. else if ( !Q_strcmp( pszName, "attributes" ) )
  1377. {
  1378. FOR_EACH_SUBKEY( pKVSetItem, pKVAttribute )
  1379. {
  1380. pszName = pKVAttribute->GetName();
  1381. const CEconItemAttributeDefinition *pDef = pschema.GetAttributeDefinitionByName( pszName );
  1382. // SCHEMA_INIT_CHECK(
  1383. // pDef != NULL,
  1384. // CFmtStr( "Item set %s: Attribute definition \"%s\" was not found", m_pszName, pszName ) );
  1385. if ( pDef )
  1386. {
  1387. int iIndex = m_iAttributes.AddToTail();
  1388. m_iAttributes[iIndex].m_iAttribDefIndex = pDef->GetDefinitionIndex();
  1389. if ( pDef->IsStoredAsInteger() )
  1390. {
  1391. m_iAttributes[iIndex].m_valValue = pKVAttribute->GetInt( "value" );
  1392. }
  1393. else
  1394. {
  1395. float flValue = pKVAttribute->GetFloat( "value" );
  1396. Q_memcpy( &m_iAttributes[iIndex].m_valValue, &flValue, sizeof( float ) );
  1397. }
  1398. }
  1399. }
  1400. }
  1401. }
  1402. // Sanity check.
  1403. SCHEMA_INIT_CHECK( !(m_bIsCollection && m_bIsHiddenSet),
  1404. CFmtStr( "Item Set %s: Invalid to set a collection to be hidden", m_pszName ) );
  1405. SCHEMA_INIT_CHECK( m_ItemEntries.Count() > 0,
  1406. CFmtStr( "Item Set %s: Set contains no items", m_pszName ) );
  1407. return SCHEMA_INIT_SUCCESS();
  1408. }
  1409. int CEconItemSetDefinition::GetItemRarity( int iIndex ) const
  1410. {
  1411. int nKitRarity = 1;
  1412. const CStickerKit *pStickerKit = NULL;
  1413. const CPaintKit *pPaintKit = NULL;
  1414. const CEconMusicDefinition *pMusicKitDefinition = NULL;
  1415. item_list_entry_t const &entry = m_ItemEntries[iIndex];
  1416. if ( entry.m_nPaintKit )
  1417. {
  1418. pPaintKit = GetItemSchema()->GetPaintKitDefinition( entry.m_nPaintKit );
  1419. if ( pPaintKit )
  1420. {
  1421. nKitRarity = MAX( nKitRarity, pPaintKit->nRarity );
  1422. }
  1423. }
  1424. if ( entry.m_nStickerKit )
  1425. {
  1426. pStickerKit = GetItemSchema()->GetStickerKitDefinition( entry.m_nStickerKit );
  1427. if ( pStickerKit )
  1428. {
  1429. nKitRarity = MAX( nKitRarity, pStickerKit->nRarity );
  1430. }
  1431. }
  1432. if ( entry.m_nMusicKit )
  1433. {
  1434. pMusicKitDefinition = GetItemSchema()->GetMusicDefinition( entry.m_nMusicKit );
  1435. if ( pMusicKitDefinition )
  1436. {
  1437. nKitRarity = Max ( nKitRarity, 1/* pMusicKitDefinition->GetRarity() */);
  1438. }
  1439. }
  1440. // Now combine the rarity
  1441. const CEconItemDefinition *pDef = GetItemSchema()->GetItemDefinition( entry.m_nItemDef );
  1442. return pDef ? EconRarity_CombinedItemAndPaintRarity( pDef->GetRarity(), nKitRarity ) : -1;
  1443. }
  1444. int CEconItemSetDefinition::GetHighestItemRarityValue( void ) const
  1445. {
  1446. int nHighestRarityValue = -1;
  1447. for ( int i = 0; i < GetItemCount(); ++i )
  1448. {
  1449. int nRarity = GetItemRarity( i );
  1450. if ( nHighestRarityValue < nRarity )
  1451. {
  1452. nHighestRarityValue = nRarity;
  1453. }
  1454. }
  1455. return nHighestRarityValue;
  1456. }
  1457. //-----------------------------------------------------------------------------
  1458. //
  1459. //-----------------------------------------------------------------------------
  1460. CEconLootListDefinition::CEconLootListDefinition( void )
  1461. {
  1462. m_bServerList = false;
  1463. }
  1464. //-----------------------------------------------------------------------------
  1465. // Purpose: Copy constructor
  1466. //-----------------------------------------------------------------------------
  1467. CEconLootListDefinition::CEconLootListDefinition( const CEconLootListDefinition &that )
  1468. {
  1469. (*this) = that;
  1470. }
  1471. //-----------------------------------------------------------------------------
  1472. // Dtor
  1473. //-----------------------------------------------------------------------------
  1474. CEconLootListDefinition::~CEconLootListDefinition( void )
  1475. {
  1476. }
  1477. //-----------------------------------------------------------------------------
  1478. // Purpose: Operator=
  1479. //-----------------------------------------------------------------------------
  1480. CEconLootListDefinition &CEconLootListDefinition::operator=( const CEconLootListDefinition &other )
  1481. {
  1482. m_pszName = other.m_pszName;
  1483. m_ItemEntries = other.m_ItemEntries;
  1484. m_AdditionalDrops = other.m_AdditionalDrops;
  1485. m_bServerList = other.m_bServerList;
  1486. return *this;
  1487. }
  1488. bool CEconLootListDefinition::AddRandomAtrributes( KeyValues *pRandomAttributesKV, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /*= NULL*/ )
  1489. {
  1490. // We've found the random attribute block. Parse it.
  1491. SCHEMA_INIT_CHECK(
  1492. NULL != pRandomAttributesKV->FindKey( "chance" ),
  1493. CFmtStr( "Loot List %s: Missing required field \"chance\" in the \"random_attributes\" block.", m_pszName ) );
  1494. random_attrib_t *randomAttrib = new random_attrib_t;
  1495. randomAttrib->m_flChanceOfRandomAttribute = pRandomAttributesKV->GetFloat( "chance" );
  1496. randomAttrib->m_bPickAllAttributes = ( pRandomAttributesKV->GetFloat( "pick_all_attributes" ) != 0 );
  1497. randomAttrib->m_flTotalAttributeWeight = 0;
  1498. FOR_EACH_TRUE_SUBKEY( pRandomAttributesKV, pKVAttribute )
  1499. {
  1500. const char *pszName = pKVAttribute->GetName();
  1501. if ( !Q_strcmp( pszName, "chance" ) )
  1502. continue;
  1503. const CEconItemAttributeDefinition *pDef = pschema.GetAttributeDefinitionByName( pszName );
  1504. SCHEMA_INIT_CHECK(
  1505. pDef != NULL,
  1506. CFmtStr( "Loot list %s: Attribute definition \"%s\" was not found", m_pszName, pszName ) );
  1507. if ( pDef )
  1508. {
  1509. lootlist_attrib_t lootListAttrib;
  1510. SCHEMA_INIT_SUBSTEP( lootListAttrib.BInitFromKV( m_pszName, pKVAttribute, pschema, pVecErrors ) );
  1511. randomAttrib->m_flTotalAttributeWeight += lootListAttrib.m_flWeight;
  1512. randomAttrib->m_RandomAttributes.AddToTail( lootListAttrib );
  1513. }
  1514. }
  1515. m_RandomAttribs.AddToTail( randomAttrib );
  1516. return true;
  1517. }
  1518. //-----------------------------------------------------------------------------
  1519. //
  1520. //-----------------------------------------------------------------------------
  1521. bool CEconLootListDefinition::BInitFromKV( KeyValues *pKVLootList, KeyValues *pKVRandomAttributeTemplates, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors, bool bServerList )
  1522. {
  1523. m_pszName = pKVLootList->GetName();
  1524. m_unHeroID = 0;
  1525. m_bServerList = bServerList;
  1526. FOR_EACH_SUBKEY( pKVLootList, pKVListItem )
  1527. {
  1528. const char *pszName = pKVListItem->GetName();
  1529. if ( !Q_strcmp( pszName, "random_attributes" ) )
  1530. {
  1531. AddRandomAtrributes( pKVListItem, pschema, pVecErrors );
  1532. continue;
  1533. }
  1534. else if ( !Q_strcmp( pszName, "attribute_templates" ) )
  1535. {
  1536. if ( !pKVRandomAttributeTemplates )
  1537. {
  1538. // Clients don't load the attribute template list
  1539. // Skip over attribute templates
  1540. continue;
  1541. }
  1542. FOR_EACH_SUBKEY( pKVListItem, pKVAttributeTemplate )
  1543. {
  1544. if ( pKVAttributeTemplate->GetDataType() == KeyValues::TYPE_NONE )
  1545. { // Support full template specified inplace
  1546. AddRandomAtrributes( pKVAttributeTemplate, pschema, pVecErrors );
  1547. }
  1548. else
  1549. {
  1550. if ( pKVAttributeTemplate->GetInt() == 0 )
  1551. continue;
  1552. KeyValues *pKVRandomAttribute = pKVRandomAttributeTemplates->FindKey( pKVAttributeTemplate->GetName() );
  1553. SCHEMA_INIT_CHECK(
  1554. pKVRandomAttribute,
  1555. CFmtStr( "Loot List %s: Looking for attribute template \"%s\" that couldn't be found in \"random_attribute_templates\" block.\n", m_pszName, pKVAttributeTemplate->GetName() ) );
  1556. AddRandomAtrributes( pKVRandomAttribute, pschema, pVecErrors );
  1557. }
  1558. }
  1559. continue;
  1560. }
  1561. else if ( !Q_strcmp( pszName, "public_list_contents" ) )
  1562. {
  1563. m_bPublicListContents = pKVListItem->GetBool();
  1564. continue;
  1565. }
  1566. if ( !Q_strcmp( pszName, "additional_drop" ) )
  1567. {
  1568. float fChance = pKVListItem->GetFloat( "chance", 0.0f );
  1569. bool bPremiumOnly = pKVListItem->GetBool( "premium_only", false );
  1570. const char *pszLootList = pKVListItem->GetString( "loot_list", "" );
  1571. SCHEMA_INIT_CHECK(
  1572. fChance > 0.0f && fChance <= 1.0f,
  1573. CFmtStr( "Loot list %s: Invalid \"additional_drop\" chance %.2f\n", m_pszName, fChance ) );
  1574. SCHEMA_INIT_CHECK(
  1575. pszLootList && pszLootList[0],
  1576. CFmtStr( "Loot list %s: Missing \"additional_drop\" loot list name\n", m_pszName ) );
  1577. if ( pszLootList )
  1578. {
  1579. const CEconLootListDefinition *pLootListDef = pschema.GetLootListByName( pszLootList );
  1580. SCHEMA_INIT_CHECK(
  1581. pLootListDef,
  1582. CFmtStr( "Loot list %s: Invalid \"additional_drop\" loot list \"%s\"\n", m_pszName, pszLootList ) );
  1583. if ( pLootListDef )
  1584. {
  1585. loot_list_additional_drop_t additionalDrop = { fChance, bPremiumOnly, pszLootList };
  1586. m_AdditionalDrops.AddToTail( additionalDrop );
  1587. }
  1588. }
  1589. continue;
  1590. }
  1591. if ( !Q_strcmp( pszName, "hero" ) )
  1592. {
  1593. const char* pszHeroName = pKVListItem->GetString( "name" );
  1594. m_unHeroID = GEconItemSchema().GetHeroID( pszHeroName );
  1595. continue;
  1596. }
  1597. item_list_entry_t entry;
  1598. // First, see if we've got a loot list name, for embedded loot lists
  1599. int iIdx = 0;
  1600. if ( V_strstr( pszName, "unusual" ) != NULL )
  1601. {
  1602. entry.m_bIsUnusualList = true;
  1603. }
  1604. if ( pschema.GetLootListByName( pszName, &iIdx ) )
  1605. {
  1606. entry.m_nItemDef = iIdx;
  1607. entry.m_bIsNestedList = true;
  1608. }
  1609. else
  1610. {
  1611. bool bEntrySuccess = entry.InitFromName( pszName );
  1612. bEntrySuccess;
  1613. }
  1614. // Make sure we never put non-enabled items into loot lists
  1615. if ( !entry.m_bIsNestedList && entry.m_nItemDef > 0 )
  1616. {
  1617. const CEconItemDefinition *pItemDef = pschema.GetItemDefinition( entry.m_nItemDef );
  1618. SCHEMA_INIT_CHECK(
  1619. pItemDef,
  1620. CFmtStr( "Loot list %s: Item definition index \"%s\" (%d) was not found\n", m_pszName, pszName, entry.m_nItemDef ) );
  1621. }
  1622. m_ItemEntries.AddToTail( entry );
  1623. float fItemWeight = pKVListItem->GetFloat();
  1624. SCHEMA_INIT_CHECK(
  1625. fItemWeight > 0.0f,
  1626. CFmtStr( "Loot list %s: Item definition index \"%s\" (%d) has invalid weight %.2f\n", m_pszName, pszName, entry.m_nItemDef, fItemWeight ) );
  1627. m_flWeights.AddToTail( fItemWeight );
  1628. m_flTotalWeight += fItemWeight;
  1629. }
  1630. return SCHEMA_INIT_SUCCESS();
  1631. }
  1632. bool CEconLootListDefinition::HasUnusualLoot() const
  1633. {
  1634. FOR_EACH_VEC(GetLootListContents(), i)
  1635. {
  1636. const item_list_entry_t& entry = GetLootListContents()[i];
  1637. if (entry.m_bIsUnusualList)
  1638. return true;
  1639. if (entry.m_bIsNestedList)
  1640. {
  1641. const CEconLootListDefinition *pNestedLootList = GetItemSchema()->GetLootListByIndex(entry.m_nItemDef);
  1642. if (pNestedLootList)
  1643. {
  1644. if (pNestedLootList->HasUnusualLoot())
  1645. return true;
  1646. }
  1647. }
  1648. }
  1649. return false;
  1650. }
  1651. //-----------------------------------------------------------------------------
  1652. //
  1653. //-----------------------------------------------------------------------------
  1654. bool CEconLootListDefinition::GetAdditionalDrop( int iIndex, CUtlString& strLootList, float& flChance ) const
  1655. {
  1656. if ( !m_AdditionalDrops.IsValidIndex( iIndex ) )
  1657. return false;
  1658. strLootList = m_AdditionalDrops[iIndex].m_pszLootListDefName;
  1659. flChance = m_AdditionalDrops[iIndex].m_fChance;
  1660. return true;
  1661. }
  1662. //-----------------------------------------------------------------------------
  1663. //
  1664. //-----------------------------------------------------------------------------
  1665. bool CEconLootListDefinition::GetRandomAttributeGroup( int iIndex, float& flChance, float& flTotalWeight ) const
  1666. {
  1667. if ( !m_RandomAttribs.IsValidIndex( iIndex ) )
  1668. return false;
  1669. flChance = m_RandomAttribs[iIndex]->m_flChanceOfRandomAttribute;
  1670. flTotalWeight = m_RandomAttribs[iIndex]->m_flTotalAttributeWeight;
  1671. return true;
  1672. }
  1673. //-----------------------------------------------------------------------------
  1674. //
  1675. //-----------------------------------------------------------------------------
  1676. int CEconLootListDefinition::GetRandomAttributeCount( int iGroup ) const
  1677. {
  1678. if ( !m_RandomAttribs.IsValidIndex( iGroup ) )
  1679. return false;
  1680. return m_RandomAttribs[iGroup]->m_RandomAttributes.Count();
  1681. }
  1682. //-----------------------------------------------------------------------------
  1683. //
  1684. //-----------------------------------------------------------------------------
  1685. bool CEconLootListDefinition::GetRandomAttribute( int iGroup, int iIndex, float& flWeight, int& iValue, int& iDefIndex ) const
  1686. {
  1687. Assert( !"Tell whoever is working on the item editor that loot list random attributes don't support typed attributes!" );
  1688. if ( !m_RandomAttribs.IsValidIndex( iGroup ) )
  1689. return false;
  1690. if ( !m_RandomAttribs[iGroup]->m_RandomAttributes.IsValidIndex( iIndex ) )
  1691. return false;
  1692. flWeight = m_RandomAttribs[iGroup]->m_RandomAttributes[iIndex].m_flWeight;
  1693. iValue = (int) m_RandomAttribs[iGroup]->m_RandomAttributes[iIndex].m_staticAttrib.m_value.asFloat;
  1694. iDefIndex = m_RandomAttribs[iGroup]->m_RandomAttributes[iIndex].m_staticAttrib.iDefIndex;
  1695. return true;
  1696. }
  1697. //-----------------------------------------------------------------------------
  1698. // Outputs a keyvalues schema representation of this loot list.
  1699. //-----------------------------------------------------------------------------
  1700. KeyValues* CEconLootListDefinition::GenerateKeyValues() const
  1701. {
  1702. KeyValues* pLootListKV = new KeyValues( m_pszName );
  1703. // Write out our items and weights.
  1704. FOR_EACH_VEC( m_ItemEntries, i )
  1705. {
  1706. const CEconItemDefinition* pItemDef = GetItemSchema()->GetItemDefinition( m_ItemEntries[i].m_nItemDef );
  1707. if ( !pItemDef )
  1708. continue;
  1709. pLootListKV->SetFloat( pItemDef->GetRawDefinition()->GetString( "name" ), m_flWeights[i] );
  1710. }
  1711. // Write out additional drops.
  1712. // Write out random attributes.
  1713. return pLootListKV;
  1714. }
  1715. //-----------------------------------------------------------------------------
  1716. //
  1717. //-----------------------------------------------------------------------------
  1718. void CEconLootListDefinition::PurgeItems( void )
  1719. {
  1720. m_ItemEntries.Purge();
  1721. m_flWeights.Purge();
  1722. m_flTotalWeight = 0;
  1723. }
  1724. //-----------------------------------------------------------------------------
  1725. // Purpose:
  1726. //-----------------------------------------------------------------------------
  1727. bool CEconLootListDefinition::lootlist_attrib_t::BInitFromKV( const char *pszContext, KeyValues *pKVKey, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors )
  1728. {
  1729. SCHEMA_INIT_SUBSTEP( m_staticAttrib.BInitFromKV_MultiLine( pszContext, pKVKey, pVecErrors ) );
  1730. SCHEMA_INIT_CHECK(
  1731. pKVKey->FindKey( "weight" ),
  1732. CFmtStr( "Loot definition %s: Attribute \"%s\" missing required 'weight' field", pszContext, pKVKey->GetName() ) );
  1733. SCHEMA_INIT_CHECK(
  1734. ( !pKVKey->FindKey( "range_min" ) && !pKVKey->FindKey( "range_max" ) ) ||
  1735. ( !pKVKey->FindKey( "values" ) ),
  1736. CFmtStr( "Loot definition %s: Attribute \"%s\" specifies both value ranges and explicit values but should only use one method or the other", pszContext, pKVKey->GetName() ) );
  1737. m_flWeight = pKVKey->GetFloat( "weight" );
  1738. m_flRangeMin = pKVKey->GetFloat( "range_min" );
  1739. m_flRangeMax = pKVKey->GetFloat( "range_max" );
  1740. const char* pszValues = pKVKey->GetString( "values" );
  1741. m_vecValues.Purge();
  1742. if ( pszValues && pszValues[ 0 ] )
  1743. {
  1744. SCHEMA_INIT_CHECK(
  1745. Helper_ExtractIntegersFromValuesString( pszValues, m_vecValues ),
  1746. CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a malformed values range: %s.", pszContext, pKVKey->GetName(), pszValues ) );
  1747. }
  1748. // validate that quest id values are valid
  1749. // TODO: create a common class for indexed definition classes and have this code validate all of them
  1750. if ( !strcmp( pKVKey->GetName(), "quest id" ) )
  1751. {
  1752. if ( m_flRangeMin != 0 || m_flRangeMax != 0 )
  1753. {
  1754. for ( int i = m_flRangeMin; i <= m_flRangeMax; i++ )
  1755. {
  1756. SCHEMA_INIT_CHECK(
  1757. GetItemSchema()->GetQuestDefinition( i ),
  1758. CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a quest id that does not exist: %d.\n", pszContext, pKVKey->GetName(), i ) );
  1759. }
  1760. }
  1761. else if ( m_vecValues.Count() != 0 )
  1762. {
  1763. FOR_EACH_VEC( m_vecValues, i )
  1764. {
  1765. SCHEMA_INIT_CHECK(
  1766. GetItemSchema()->GetQuestDefinition( m_vecValues[ i ] ),
  1767. CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a quest id that does not exist: %d.\n", pszContext, pKVKey->GetName(), m_vecValues[ i ] ) );
  1768. }
  1769. }
  1770. }
  1771. else if ( !strcmp( pKVKey->GetName(), "quest reward lootlist" ) )
  1772. {
  1773. const CEconItemSchema::RevolvingLootListDefinitionMap_t* pQuestRewardLL= &( GetItemSchema()->GetQuestRewardLootLists() );
  1774. if ( m_flRangeMin != 0 || m_flRangeMax != 0 )
  1775. {
  1776. for ( int i = m_flRangeMin; i <= m_flRangeMax; i++ )
  1777. {
  1778. int iLLIndex = pQuestRewardLL->Find( i );
  1779. SCHEMA_INIT_CHECK(
  1780. pQuestRewardLL->IsValidIndex( iLLIndex ),
  1781. CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a quest reward lootlist that does not exist: %d.\n", pszContext, pKVKey->GetName(), i ) );
  1782. }
  1783. }
  1784. else if ( m_vecValues.Count() != 0 )
  1785. {
  1786. FOR_EACH_VEC( m_vecValues, i )
  1787. {
  1788. int iLLIndex = pQuestRewardLL->Find( m_vecValues[ i ] );
  1789. SCHEMA_INIT_CHECK(
  1790. pQuestRewardLL->IsValidIndex( iLLIndex ),
  1791. CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a quest reward lootlist that does not exist: %d.\n", pszContext, pKVKey->GetName(), m_vecValues[ i ] ) );
  1792. }
  1793. }
  1794. }
  1795. return SCHEMA_INIT_SUCCESS();
  1796. }
  1797. //-----------------------------------------------------------------------------
  1798. // Purpose: Constructor
  1799. //-----------------------------------------------------------------------------
  1800. CEconCraftingRecipeDefinition::CEconCraftingRecipeDefinition( void )
  1801. {
  1802. m_nDefIndex = 0;
  1803. m_wszName[ 0 ] = L'\0';
  1804. m_wszDesc[ 0 ] = L'\0';
  1805. }
  1806. //-----------------------------------------------------------------------------
  1807. // Purpose: Initialize the attribute definition
  1808. // Input: pKVAttribute - The KeyValues representation of the attribute
  1809. // schema - The overall item schema for this attribute
  1810. // pVecErrors - An optional vector that will contain error messages if
  1811. // the init fails.
  1812. // Output: True if initialization succeeded, false otherwise
  1813. //-----------------------------------------------------------------------------
  1814. bool CEconCraftingRecipeDefinition::BInitFromKV( KeyValues *pKVRecipe, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  1815. {
  1816. m_nDefIndex = Q_atoi( pKVRecipe->GetName() );
  1817. // Check for required fields
  1818. SCHEMA_INIT_CHECK(
  1819. NULL != pKVRecipe->FindKey( "input_items" ),
  1820. CFmtStr( "Recipe definition %d: Missing required field \"input_items\"", m_nDefIndex ) );
  1821. SCHEMA_INIT_CHECK(
  1822. NULL != pKVRecipe->FindKey( "output_items" ),
  1823. CFmtStr( "Recipe definition %d: Missing required field \"output_items\"", m_nDefIndex ) );
  1824. m_bDisabled = pKVRecipe->GetBool( "disabled" );
  1825. m_strName = pKVRecipe->GetString( "name" );
  1826. m_strN_A = pKVRecipe->GetString( "n_A" );
  1827. m_strDescInputs = pKVRecipe->GetString( "desc_inputs" );
  1828. m_strDescOutputs = pKVRecipe->GetString( "desc_outputs" );
  1829. m_strDI_A = pKVRecipe->GetString( "di_A" );
  1830. m_strDI_B = pKVRecipe->GetString( "di_B" );
  1831. m_strDI_C = pKVRecipe->GetString( "di_C" );
  1832. m_strDO_A = pKVRecipe->GetString( "do_A" );
  1833. m_strDO_B = pKVRecipe->GetString( "do_B" );
  1834. m_strDO_C = pKVRecipe->GetString( "do_C" );
  1835. m_bRequiresAllSameClass = pKVRecipe->GetBool( "all_same_class" );
  1836. m_bRequiresAllSameSlot = pKVRecipe->GetBool( "all_same_slot" );
  1837. m_iCacheClassUsageForOutputFromItem = pKVRecipe->GetInt( "add_class_usage_to_output", -1 );
  1838. m_iCacheSlotUsageForOutputFromItem = pKVRecipe->GetInt( "add_slot_usage_to_output", -1 );
  1839. m_iCacheSetForOutputFromItem = pKVRecipe->GetInt( "add_set_to_output", -1 );
  1840. m_bAlwaysKnown = pKVRecipe->GetBool( "always_known", true );
  1841. m_bPremiumAccountOnly = pKVRecipe->GetBool( "premium_only", false );
  1842. m_iCategory = (recipecategories_t)StringFieldToInt( pKVRecipe->GetString("category"), g_szRecipeCategoryStrings, ARRAYSIZE(g_szRecipeCategoryStrings) );
  1843. m_iFilter = pKVRecipe->GetInt( "filter", -1 );
  1844. // Read in all the input items
  1845. KeyValues *pKVInputItems = pKVRecipe->FindKey( "input_items" );
  1846. if ( NULL != pKVInputItems )
  1847. {
  1848. FOR_EACH_TRUE_SUBKEY( pKVInputItems, pKVInputItem )
  1849. {
  1850. int index = m_InputItemsCriteria.AddToTail();
  1851. SCHEMA_INIT_SUBSTEP( m_InputItemsCriteria[index].BInitFromKV( pKVInputItem, pschema ) );
  1852. // Recipes ignore the enabled flag when generating items
  1853. m_InputItemsCriteria[index].SetIgnoreEnabledFlag( true );
  1854. index = m_InputItemDupeCounts.AddToTail();
  1855. m_InputItemDupeCounts[index] = atoi( pKVInputItem->GetName() );
  1856. }
  1857. }
  1858. // Read in all the output items
  1859. KeyValues *pKVOutputItems = pKVRecipe->FindKey( "output_items" );
  1860. if ( NULL != pKVOutputItems )
  1861. {
  1862. FOR_EACH_TRUE_SUBKEY( pKVOutputItems, pKVOutputItem )
  1863. {
  1864. int index = m_OutputItemsCriteria.AddToTail();
  1865. SCHEMA_INIT_SUBSTEP( m_OutputItemsCriteria[index].BInitFromKV( pKVOutputItem, pschema ) );
  1866. // Recipes ignore the enabled flag when generating items
  1867. m_OutputItemsCriteria[index].SetIgnoreEnabledFlag( true );
  1868. }
  1869. }
  1870. GenerateLocStrings();
  1871. return SCHEMA_INIT_SUCCESS();
  1872. }
  1873. bool CEconCraftingRecipeDefinition::BInitFromSet( const IEconItemSetDefinition *pSet, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  1874. {
  1875. m_bDisabled = false;
  1876. m_strName = "#RT_T_A"; // "Trade In %s1"
  1877. m_strN_A = pSet->GetLocKey(); // "The Office Collection"
  1878. m_strDescInputs = "#RDI_AB"; // "Requires: %s1 %s2"
  1879. m_strDescOutputs = "RDO_AB"; // "Produces: %s1 %s2"
  1880. m_strDI_A = "1"; // "1"
  1881. m_strDI_B = pSet->GetLocKey(); // "The Office Collection"
  1882. m_strDI_C = NULL;
  1883. m_strDO_A = "1"; // "1"
  1884. const CEconItemDefinition *pItemDef = pschema.GetItemDefinition( pSet->GetCraftReward() );
  1885. SCHEMA_INIT_CHECK(
  1886. pItemDef && pItemDef->GetDefinitionIndex() > 0,
  1887. CFmtStr( "Item Collection Craft Reward (%d) specifies invalid item def", pSet->GetCraftReward() ) );
  1888. m_strDO_B = pItemDef->GetItemBaseName();
  1889. m_strDO_C = NULL;
  1890. m_bRequiresAllSameClass = false;
  1891. m_bRequiresAllSameSlot = false;
  1892. m_iCacheClassUsageForOutputFromItem = -1;
  1893. m_iCacheSlotUsageForOutputFromItem = -1;
  1894. m_iCacheSetForOutputFromItem = -1;
  1895. m_bAlwaysKnown = true;
  1896. m_bPremiumAccountOnly = false;
  1897. m_iCategory = (recipecategories_t)StringFieldToInt( "crafting", g_szRecipeCategoryStrings, ARRAYSIZE(g_szRecipeCategoryStrings) );
  1898. m_iFilter = -1;
  1899. for ( int i = 0; i < pSet->GetItemCount(); ++i )
  1900. {
  1901. int index = m_InputItemsCriteria.AddToTail();
  1902. SCHEMA_INIT_SUBSTEP( m_InputItemsCriteria[index].BInitFromItemAndPaint( pSet->GetItemDef( i ), pSet->GetItemPaintKit( i ), pschema ) );
  1903. m_InputItemsCriteria[index].SetIgnoreEnabledFlag( true );
  1904. index = m_InputItemDupeCounts.AddToTail();
  1905. m_InputItemDupeCounts[index] = 1;
  1906. }
  1907. int index = m_OutputItemsCriteria.AddToTail();
  1908. SCHEMA_INIT_SUBSTEP( m_OutputItemsCriteria[index].BInitFromItemAndPaint( pSet->GetCraftReward(), 0, pschema ) );
  1909. GenerateLocStrings();
  1910. return SCHEMA_INIT_SUCCESS();
  1911. }
  1912. //-----------------------------------------------------------------------------
  1913. // Purpose: Serializes the criteria to and from messages
  1914. //-----------------------------------------------------------------------------
  1915. bool CEconCraftingRecipeDefinition::BSerializeToMsg( CSOItemRecipe & msg ) const
  1916. {
  1917. msg.set_def_index( m_nDefIndex );
  1918. msg.set_name( m_strName );
  1919. msg.set_n_a( m_strN_A );
  1920. msg.set_desc_inputs( m_strDescInputs );
  1921. msg.set_desc_outputs( m_strDescOutputs );
  1922. msg.set_di_a( m_strDI_A );
  1923. msg.set_di_b( m_strDI_B );
  1924. msg.set_di_c( m_strDI_C );
  1925. msg.set_do_a( m_strDO_A );
  1926. msg.set_do_b( m_strDO_B );
  1927. msg.set_do_c( m_strDO_C );
  1928. msg.set_requires_all_same_class( m_bRequiresAllSameClass );
  1929. msg.set_requires_all_same_slot( m_bRequiresAllSameSlot );
  1930. msg.set_class_usage_for_output( m_iCacheClassUsageForOutputFromItem );
  1931. msg.set_slot_usage_for_output( m_iCacheSlotUsageForOutputFromItem );
  1932. msg.set_set_for_output( m_iCacheSetForOutputFromItem );
  1933. FOR_EACH_VEC( m_InputItemsCriteria, i )
  1934. {
  1935. CSOItemCriteria *pCrit = msg.add_input_items_criteria();
  1936. if ( !m_InputItemsCriteria[i].BSerializeToMsg( *pCrit ) )
  1937. return false;
  1938. }
  1939. FOR_EACH_VEC( m_InputItemDupeCounts, i )
  1940. {
  1941. msg.add_input_item_dupe_counts( m_InputItemDupeCounts[i] );
  1942. }
  1943. FOR_EACH_VEC( m_OutputItemsCriteria, i )
  1944. {
  1945. CSOItemCriteria *pCrit = msg.add_output_items_criteria();
  1946. if ( !m_OutputItemsCriteria[i].BSerializeToMsg( *pCrit ) )
  1947. return false;
  1948. }
  1949. return true;
  1950. }
  1951. //-----------------------------------------------------------------------------
  1952. // Purpose: Serializes the criteria to and from messages
  1953. //-----------------------------------------------------------------------------
  1954. bool CEconCraftingRecipeDefinition::BDeserializeFromMsg( const CSOItemRecipe & msg )
  1955. {
  1956. m_nDefIndex = msg.def_index();
  1957. m_strName = msg.name().c_str();
  1958. m_strN_A = msg.n_a().c_str();
  1959. m_strDescInputs = msg.desc_inputs().c_str();
  1960. m_strDescOutputs = msg.desc_outputs().c_str();
  1961. m_strDI_A = msg.di_a().c_str();
  1962. m_strDI_B = msg.di_b().c_str();
  1963. m_strDI_C = msg.di_c().c_str();
  1964. m_strDO_A = msg.do_a().c_str();
  1965. m_strDO_B = msg.do_b().c_str();
  1966. m_strDO_C = msg.do_c().c_str();
  1967. m_bRequiresAllSameClass = msg.requires_all_same_class();
  1968. m_bRequiresAllSameSlot = msg.requires_all_same_slot();
  1969. m_iCacheClassUsageForOutputFromItem = msg.class_usage_for_output();
  1970. m_iCacheSlotUsageForOutputFromItem = msg.slot_usage_for_output();
  1971. m_iCacheSetForOutputFromItem = msg.set_for_output();
  1972. // Read how many input items there are
  1973. uint32 unCount = msg.input_items_criteria_size();
  1974. m_InputItemsCriteria.SetSize( unCount );
  1975. for ( uint32 i = 0; i < unCount; i++ )
  1976. {
  1977. if ( !m_InputItemsCriteria[i].BDeserializeFromMsg( msg.input_items_criteria( i ) ) )
  1978. return false;
  1979. }
  1980. // Read how many input item dupe counts there are
  1981. unCount = msg.input_item_dupe_counts_size();
  1982. m_InputItemDupeCounts.SetSize( unCount );
  1983. for ( uint32 i = 0; i < unCount; i++ )
  1984. {
  1985. m_InputItemDupeCounts[i] = msg.input_item_dupe_counts( i );
  1986. }
  1987. // Read how many output items there are
  1988. unCount = msg.output_items_criteria_size();
  1989. m_OutputItemsCriteria.SetSize( unCount );
  1990. for ( uint32 i = 0; i < unCount; i++ )
  1991. {
  1992. if ( !m_OutputItemsCriteria[i].BDeserializeFromMsg( msg.output_items_criteria( i ) ) )
  1993. return false;
  1994. }
  1995. GenerateLocStrings();
  1996. return true;
  1997. }
  1998. //-----------------------------------------------------------------------------
  1999. // Purpose: Returns true if the vector contains a set of items that matches the inputs for this recipe
  2000. // Note it will fail if the vector contains extra items that aren't needed.
  2001. //
  2002. //-----------------------------------------------------------------------------
  2003. bool CEconCraftingRecipeDefinition::ItemListMatchesInputs( const CUtlVector< CEconItem* > &vecCraftingItems, bool bAllowPartialMatch /*= false*/ ) const
  2004. {
  2005. bool bResult = true;
  2006. CUtlVector< uint8 > arrDupesUsed;
  2007. arrDupesUsed.SetCount( m_InputItemsCriteria.Count() );
  2008. uint8 *pDupesUsed = arrDupesUsed.Base();
  2009. memset( pDupesUsed, 0, m_InputItemsCriteria.Count() );
  2010. int nSet = -1;
  2011. if ( ( GetFilter() == CRAFT_FILTER_COLLECT || GetFilter() == CRAFT_FILTER_TRADEUP ) &&
  2012. vecCraftingItems.Count() > 0 )
  2013. {
  2014. nSet = vecCraftingItems[ 0 ]->GetItemSetIndex();
  2015. if ( nSet < 0 )
  2016. {
  2017. // This item must be in a set!
  2018. return false;
  2019. }
  2020. }
  2021. FOR_EACH_VEC( vecCraftingItems, nItem )
  2022. {
  2023. CEconItem *pEconItem = vecCraftingItems[ nItem ];
  2024. #if 0 // Relaxing set restriction on crafting
  2025. if ( nSet >= 0 && pEconItem->GetItemSetIndex() != nSet )
  2026. {
  2027. bResult = false;
  2028. break;
  2029. }
  2030. #endif
  2031. // Any items at the top rarity of their set are illegal in crafting
  2032. if ( GetFilter() == CRAFT_FILTER_TRADEUP )
  2033. {
  2034. const IEconItemSetDefinition *pSetDef = GetItemSchema()->GetItemSet( vecCraftingItems[ nItem ]->GetItemSetIndex() );
  2035. if ( !pSetDef )
  2036. {
  2037. return false;
  2038. }
  2039. bool bHasItemsAtNextRarityTier = false;
  2040. for ( int i = 0; i < pSetDef->GetItemCount(); ++i )
  2041. {
  2042. if ( pSetDef->GetItemRarity( i ) == pEconItem->GetRarity() + 1 )
  2043. {
  2044. bHasItemsAtNextRarityTier = true;
  2045. break;
  2046. }
  2047. }
  2048. if ( !bHasItemsAtNextRarityTier )
  2049. return false;
  2050. }
  2051. bool bFoundCriteriaMatch = false;
  2052. FOR_EACH_VEC( m_InputItemsCriteria, nCriteria )
  2053. {
  2054. const CItemSelectionCriteria *pCriteria = &( m_InputItemsCriteria[ nCriteria ] );
  2055. if ( !pCriteria )
  2056. continue;
  2057. // Skip if we've used this criteria to the limit
  2058. if ( pDupesUsed[ nCriteria ] >= m_InputItemDupeCounts[ nCriteria ] )
  2059. continue;
  2060. bFoundCriteriaMatch = pCriteria->BEvaluate( pEconItem, *GetItemSchema() );
  2061. if ( bFoundCriteriaMatch )
  2062. {
  2063. pDupesUsed[ nCriteria ]++;
  2064. break;
  2065. }
  2066. }
  2067. if ( !bFoundCriteriaMatch )
  2068. {
  2069. // Did the item not fit any criteria!
  2070. bResult = false;
  2071. break;
  2072. }
  2073. }
  2074. if ( !bAllowPartialMatch )
  2075. {
  2076. // Make sure we've matched ALL the criteria
  2077. FOR_EACH_VEC( m_InputItemsCriteria, nCriteria )
  2078. {
  2079. if ( pDupesUsed[ nCriteria ] < m_InputItemDupeCounts[ nCriteria ] )
  2080. {
  2081. // Not all criteria dupes were matched
  2082. bResult = false;
  2083. break;
  2084. }
  2085. }
  2086. }
  2087. return bResult;
  2088. }
  2089. //-----------------------------------------------------------------------------
  2090. // Purpose: Constructor
  2091. //-----------------------------------------------------------------------------
  2092. int CEconCraftingRecipeDefinition::GetTotalInputItemsRequired( void ) const
  2093. {
  2094. int iCount = 0;
  2095. FOR_EACH_VEC( m_InputItemsCriteria, i )
  2096. {
  2097. if ( m_InputItemDupeCounts[i] )
  2098. {
  2099. iCount += m_InputItemDupeCounts[i];
  2100. }
  2101. else
  2102. {
  2103. iCount++;
  2104. }
  2105. }
  2106. return iCount;
  2107. }
  2108. #if defined( CLIENT_DLL )
  2109. wchar_t *LocalizeRecipeStringPiece( const char *pszString, wchar_t *pszConverted, int nConvertedSizeInBytes )
  2110. {
  2111. if ( !pszString )
  2112. return L"";
  2113. if ( pszString[0] == '#' )
  2114. return g_pVGuiLocalize->Find( pszString );
  2115. g_pVGuiLocalize->ConvertANSIToUnicode( pszString, pszConverted, nConvertedSizeInBytes );
  2116. return pszConverted;
  2117. }
  2118. #endif
  2119. void CEconCraftingRecipeDefinition::GenerateLocStrings( void )
  2120. {
  2121. #if defined( CLIENT_DLL )
  2122. wchar_t *pName_A = g_pVGuiLocalize->Find( GetName_A() );
  2123. g_pVGuiLocalize->ConstructString( m_wszName, sizeof( m_wszName ), g_pVGuiLocalize->Find( GetName() ), 1, pName_A );
  2124. wchar_t wcTmpA[32];
  2125. wchar_t wcTmpB[32];
  2126. wchar_t wcTmpC[32];
  2127. wchar_t wcTmp[512];
  2128. // Build the input string
  2129. wchar_t *pInp_A = LocalizeRecipeStringPiece( GetDescI_A(), wcTmpA, sizeof( wcTmpA ) );
  2130. wchar_t *pInp_B = LocalizeRecipeStringPiece( GetDescI_B(), wcTmpB, sizeof( wcTmpB ) );
  2131. wchar_t *pInp_C = LocalizeRecipeStringPiece( GetDescI_C(), wcTmpC, sizeof( wcTmpC ) );
  2132. g_pVGuiLocalize->ConstructString( m_wszDesc, sizeof( m_wszDesc ), g_pVGuiLocalize->Find( GetDescInputs() ), 3, pInp_A, pInp_B, pInp_C );
  2133. // Build the output string
  2134. wchar_t *pOut_A = LocalizeRecipeStringPiece( GetDescO_A(), wcTmpA, sizeof( wcTmpA ) );
  2135. wchar_t *pOut_B = LocalizeRecipeStringPiece( GetDescO_B(), wcTmpB, sizeof( wcTmpB ) );
  2136. wchar_t *pOut_C = LocalizeRecipeStringPiece( GetDescO_C(), wcTmpC, sizeof( wcTmpC ) );
  2137. g_pVGuiLocalize->ConstructString( wcTmp, sizeof( wcTmp ), g_pVGuiLocalize->Find( GetDescOutputs() ), 3, pOut_A, pOut_B, pOut_C );
  2138. // Concatenate, and mark the text changes
  2139. V_wcscat_safe( m_wszDesc, L"\n" );
  2140. V_wcscat_safe( m_wszDesc, wcTmp );
  2141. #endif
  2142. }
  2143. //-----------------------------------------------------------------------------
  2144. // Purpose:
  2145. //-----------------------------------------------------------------------------
  2146. #define GC_SCH_REFERENCE( TAttribSchType )
  2147. //-----------------------------------------------------------------------------
  2148. // Purpose:
  2149. //-----------------------------------------------------------------------------
  2150. unsigned int Internal_GetAttributeTypeUniqueIdentifierNextValue()
  2151. {
  2152. static unsigned int s_unUniqueCounter = 0;
  2153. unsigned int unCounter = s_unUniqueCounter;
  2154. s_unUniqueCounter++;
  2155. return unCounter;
  2156. }
  2157. template < typename T >
  2158. unsigned int GetAttributeTypeUniqueIdentifier()
  2159. {
  2160. static unsigned int s_unUniqueCounter = Internal_GetAttributeTypeUniqueIdentifierNextValue();
  2161. return s_unUniqueCounter;
  2162. }
  2163. //-----------------------------------------------------------------------------
  2164. // Purpose:
  2165. //-----------------------------------------------------------------------------
  2166. template < GC_SCH_REFERENCE( typename TAttribSchType ) typename TAttribInMemoryType >
  2167. class CSchemaAttributeTypeBase : public ISchemaAttributeTypeBase<TAttribInMemoryType>
  2168. {
  2169. public:
  2170. };
  2171. //-----------------------------------------------------------------------------
  2172. // Purpose:
  2173. //-----------------------------------------------------------------------------
  2174. template < GC_SCH_REFERENCE( typename TAttribSchType ) typename TProtobufValueType >
  2175. class CSchemaAttributeTypeProtobufBase : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( TAttribSchType ) TProtobufValueType >
  2176. {
  2177. public:
  2178. virtual void ConvertTypedValueToByteStream( const TProtobufValueType& typedValue, ::std::string *out_psBytes ) const OVERRIDE
  2179. {
  2180. DbgVerify( typedValue.SerializeToString( out_psBytes ) );
  2181. }
  2182. virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, TProtobufValueType *out_pTypedValue ) const OVERRIDE
  2183. {
  2184. DbgVerify( out_pTypedValue->ParseFromString( sBytes ) );
  2185. }
  2186. virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE
  2187. {
  2188. Assert( pAttrDef );
  2189. Assert( out_pValue );
  2190. std::string sValue( pszValue );
  2191. TProtobufValueType typedValue;
  2192. if ( !google::protobuf::TextFormat::ParseFromString( sValue, &typedValue ) )
  2193. return false;
  2194. this->ConvertTypedValueToEconAttributeValue( typedValue, out_pValue );
  2195. return true;
  2196. }
  2197. virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE
  2198. {
  2199. Assert( pAttrDef );
  2200. Assert( out_ps );
  2201. google::protobuf::TextFormat::PrintToString( this->GetTypedValueContentsFromEconAttributeValue( value ), out_ps );
  2202. }
  2203. };
  2204. //-----------------------------------------------------------------------------
  2205. // Purpose:
  2206. //-----------------------------------------------------------------------------
  2207. class CSchemaAttributeType_String : public CSchemaAttributeTypeProtobufBase< GC_SCH_REFERENCE( CSchItemAttributeString ) CAttribute_String >
  2208. {
  2209. public:
  2210. // We intentionally override the convert-to-/convert-from-string functions for strings so that string literals can be
  2211. // specified in the schema, etc. without worrying about the protobuf text format.
  2212. virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE
  2213. {
  2214. Assert( pAttrDef );
  2215. Assert( out_pValue );
  2216. CAttribute_String typedValue;
  2217. typedValue.set_value( pszValue );
  2218. this->ConvertTypedValueToEconAttributeValue( typedValue, out_pValue );
  2219. return true;
  2220. }
  2221. virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE
  2222. {
  2223. Assert( pAttrDef );
  2224. Assert( out_ps );
  2225. *out_ps = this->GetTypedValueContentsFromEconAttributeValue( value ).value().c_str();
  2226. }
  2227. };
  2228. void CopyStringAttributeValueToCharPointerOutput( const CAttribute_String *pValue, const char **out_pValue )
  2229. {
  2230. Assert( pValue );
  2231. Assert( out_pValue );
  2232. *out_pValue = pValue->value().c_str();
  2233. }
  2234. //-----------------------------------------------------------------------------
  2235. // Purpose:
  2236. //-----------------------------------------------------------------------------
  2237. class CSchemaAttributeType_Vector : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( CSchItemAttributeVector ) Vector >
  2238. {
  2239. public:
  2240. // We intentionally override the convert-to-/convert-from-string functions for strings so that string literals can be
  2241. // specified in the schema, etc. without worrying about the protobuf text format.
  2242. virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE
  2243. {
  2244. Assert( pAttrDef );
  2245. Assert( out_pValue );
  2246. Vector typedValue;
  2247. if ( sscanf( pszValue, "%f %f %f", &typedValue.x, &typedValue.y, &typedValue.z ) < 3 )
  2248. {
  2249. AssertMsg1( false, "Vector attribute value has invalid string: %s", pszValue );
  2250. }
  2251. this->ConvertTypedValueToEconAttributeValue( typedValue, out_pValue );
  2252. return true;
  2253. }
  2254. virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE
  2255. {
  2256. Assert( pAttrDef );
  2257. Assert( out_ps );
  2258. Vector typedValue;
  2259. this->ConvertEconAttributeValueToTypedValue( value, &typedValue );
  2260. char szTemp[ 256 ];
  2261. V_sprintf_safe( szTemp, "%f %f %f", typedValue[ 0 ], typedValue[ 1 ], typedValue[ 2 ] );
  2262. *out_ps = szTemp;
  2263. }
  2264. virtual void ConvertTypedValueToByteStream( const Vector& typedValue, ::std::string *out_psBytes ) const OVERRIDE
  2265. {
  2266. Assert( out_psBytes );
  2267. Assert( out_psBytes->size() == 0 );
  2268. out_psBytes->resize( sizeof( Vector ) );
  2269. *reinterpret_cast<Vector *>( &((*out_psBytes)[0]) ) = typedValue;
  2270. }
  2271. virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, Vector *out_pTypedValue ) const OVERRIDE
  2272. {
  2273. Assert( out_pTypedValue );
  2274. Assert( sBytes.size() == sizeof( Vector ) );
  2275. *out_pTypedValue = *reinterpret_cast<const Vector *>( &sBytes[0] );
  2276. }
  2277. };
  2278. //-----------------------------------------------------------------------------
  2279. // Purpose:
  2280. //-----------------------------------------------------------------------------
  2281. class CSchemaAttributeType_Uint32 : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( CSchItemAttributeUint32 ) uint32 >
  2282. {
  2283. public:
  2284. virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE
  2285. {
  2286. Assert( pAttrDef );
  2287. Assert( out_pValue );
  2288. out_pValue->asUint32 = Q_atoi( pszValue );
  2289. return true;
  2290. }
  2291. virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE
  2292. {
  2293. Assert( pAttrDef );
  2294. Assert( out_ps );
  2295. *out_ps = CFmtStr( "%u", value.asUint32 ).Get();
  2296. }
  2297. virtual void ConvertTypedValueToByteStream( const uint32& typedValue, ::std::string *out_psBytes ) const OVERRIDE
  2298. {
  2299. Assert( out_psBytes );
  2300. Assert( out_psBytes->size() == 0 );
  2301. out_psBytes->resize( sizeof( uint32 ) );
  2302. *reinterpret_cast<uint32 *>( &((*out_psBytes)[0]) ) = typedValue;
  2303. }
  2304. virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, uint32 *out_pTypedValue ) const OVERRIDE
  2305. {
  2306. Assert( out_pTypedValue );
  2307. Assert( sBytes.size() == sizeof( uint32 ) );
  2308. *out_pTypedValue = *reinterpret_cast<const uint32 *>( &sBytes[0] );
  2309. }
  2310. virtual bool BSupportsGameplayModificationAndNetworking() const OVERRIDE
  2311. {
  2312. return true;
  2313. }
  2314. };
  2315. //-----------------------------------------------------------------------------
  2316. // Purpose:
  2317. //-----------------------------------------------------------------------------
  2318. class CSchemaAttributeType_Float : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( CSchItemAttributeFloat ) float >
  2319. {
  2320. public:
  2321. virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE
  2322. {
  2323. Assert( pAttrDef );
  2324. Assert( out_pValue );
  2325. out_pValue->asFloat = Q_atof( pszValue );
  2326. return true;
  2327. }
  2328. virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE
  2329. {
  2330. Assert( pAttrDef );
  2331. Assert( out_ps );
  2332. *out_ps = CFmtStr( "%f", value.asFloat ).Get();
  2333. }
  2334. virtual void ConvertTypedValueToByteStream( const float& typedValue, ::std::string *out_psBytes ) const OVERRIDE
  2335. {
  2336. Assert( out_psBytes );
  2337. Assert( out_psBytes->size() == 0 );
  2338. out_psBytes->resize( sizeof( float ) );
  2339. *reinterpret_cast<float *>( &((*out_psBytes)[0]) ) = typedValue; // overwrite string contents (sizeof( float ) bytes)
  2340. }
  2341. virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, float *out_pTypedValue ) const OVERRIDE
  2342. {
  2343. Assert( out_pTypedValue );
  2344. Assert( sBytes.size() == sizeof( float ) );
  2345. *out_pTypedValue = *reinterpret_cast<const float *>( &sBytes[0] );
  2346. }
  2347. virtual bool BSupportsGameplayModificationAndNetworking() const OVERRIDE
  2348. {
  2349. return true;
  2350. }
  2351. virtual bool OnIterateAttributeValue( IEconItemAttributeIterator *pIterator, const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value ) const OVERRIDE
  2352. {
  2353. Assert( pIterator );
  2354. Assert( pAttrDef );
  2355. // Call the appropriate virtual function on our iterator based on whatever type we represent.
  2356. return pIterator->OnIterateAttributeValue( pAttrDef, value.asFloat );
  2357. }
  2358. };
  2359. //-----------------------------------------------------------------------------
  2360. // Purpose:
  2361. //-----------------------------------------------------------------------------
  2362. class CSchemaAttributeType_Default : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( CSchItemAttribute ) attrib_value_t >
  2363. {
  2364. public:
  2365. virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE
  2366. {
  2367. Assert( pAttrDef );
  2368. Assert( out_pValue );
  2369. // This is terrible backwards-compatibility code to support the pulling of values from econ asset classes.
  2370. if ( pAttrDef->IsStoredAsInteger() )
  2371. {
  2372. out_pValue->asUint32 = pszValue ? (uint32)V_atoui64( pszValue ) : 0;
  2373. }
  2374. else if ( pAttrDef->IsStoredAsFloat() )
  2375. {
  2376. out_pValue->asFloat = pszValue ? V_atof( pszValue ) : 0.0f;
  2377. }
  2378. else
  2379. {
  2380. Assert( !"Unknown storage type for CSchemaAttributeType_Default::BConvertStringToEconAttributeValue()!" );
  2381. return false;
  2382. }
  2383. return true;
  2384. }
  2385. virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE
  2386. {
  2387. Assert( pAttrDef );
  2388. Assert( out_ps );
  2389. if( pAttrDef->IsStoredAsFloat() )
  2390. {
  2391. *out_ps = CFmtStr( "%f", value.asFloat ).Get();
  2392. }
  2393. else if( pAttrDef->IsStoredAsInteger() )
  2394. {
  2395. *out_ps = CFmtStr( "%u", value.asUint32 ).Get();
  2396. }
  2397. else
  2398. {
  2399. Assert( !"Unknown storage type for CSchemaAttributeType_Default::ConvertEconAttributeValueToString()!" );
  2400. }
  2401. }
  2402. virtual void ConvertTypedValueToByteStream( const attrib_value_t& typedValue, ::std::string *out_psBytes ) const OVERRIDE
  2403. {
  2404. Assert( out_psBytes );
  2405. Assert( out_psBytes->size() == 0 );
  2406. out_psBytes->resize( sizeof( attrib_value_t ) );
  2407. *reinterpret_cast<attrib_value_t *>( &((*out_psBytes)[0]) ) = typedValue; // overwrite string contents (sizeof( attrib_value_t ) bytes)
  2408. }
  2409. virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, attrib_value_t *out_pTypedValue ) const OVERRIDE
  2410. {
  2411. Assert( out_pTypedValue );
  2412. // Game clients and servers may have partially out-of-date information, or may have downloaded a new schema
  2413. // but not know how to parse an attribute of a certain type, etc. In these cases, because we know we
  2414. // aren't on the GC, temporarily failing to load these values until the client shuts down and updates
  2415. // is about the best we can hope for.
  2416. if ( sBytes.size() < sizeof( attrib_value_t ) )
  2417. {
  2418. *out_pTypedValue = attrib_value_t();
  2419. return;
  2420. }
  2421. *out_pTypedValue = *reinterpret_cast<const attrib_value_t *>( &sBytes[0] );
  2422. }
  2423. virtual bool BSupportsGameplayModificationAndNetworking() const OVERRIDE
  2424. {
  2425. return true;
  2426. }
  2427. private:
  2428. };
  2429. //-----------------------------------------------------------------------------
  2430. // Purpose: Constructor
  2431. //-----------------------------------------------------------------------------
  2432. CEconItemAttributeDefinition::CEconItemAttributeDefinition( void )
  2433. : m_pKVAttribute( NULL ),
  2434. m_pAttrType( NULL ),
  2435. m_bHidden( false ),
  2436. m_bWebSchemaOutputForced( false ),
  2437. m_bStoredAsInteger( false ),
  2438. m_iEffectType( ATTRIB_EFFECT_NEUTRAL ),
  2439. m_iDescriptionFormat( 0 ),
  2440. m_pszDescriptionString( NULL ),
  2441. m_pszDescriptionTag( NULL ),
  2442. m_pszArmoryDesc( NULL ),
  2443. m_iScore( 0 ),
  2444. m_pszDefinitionName( NULL ),
  2445. m_pszAttributeClass( NULL )
  2446. #ifndef GC_DLL
  2447. , m_iszAttributeClass( NULL_STRING )
  2448. #endif
  2449. {
  2450. }
  2451. //-----------------------------------------------------------------------------
  2452. // Purpose: Copy constructor
  2453. //-----------------------------------------------------------------------------
  2454. CEconItemAttributeDefinition::CEconItemAttributeDefinition( const CEconItemAttributeDefinition &that )
  2455. {
  2456. (*this) = that;
  2457. }
  2458. //-----------------------------------------------------------------------------
  2459. // Purpose: Operator=
  2460. //-----------------------------------------------------------------------------
  2461. CEconItemAttributeDefinition &CEconItemAttributeDefinition::operator=( const CEconItemAttributeDefinition &rhs )
  2462. {
  2463. m_nDefIndex = rhs.m_nDefIndex;
  2464. m_pAttrType = rhs.m_pAttrType;
  2465. m_bHidden = rhs.m_bHidden;
  2466. m_bWebSchemaOutputForced = rhs.m_bWebSchemaOutputForced;
  2467. m_bStoredAsInteger = rhs.m_bStoredAsInteger;
  2468. m_bInstanceData = rhs.m_bInstanceData;
  2469. m_eAssetClassAttrExportRule = rhs.m_eAssetClassAttrExportRule;
  2470. m_iEffectType = rhs.m_iEffectType;
  2471. m_iDescriptionFormat = rhs.m_iDescriptionFormat;
  2472. m_pszDescriptionString = rhs.m_pszDescriptionString;
  2473. m_pszDescriptionTag = rhs.m_pszDescriptionTag;
  2474. m_pszArmoryDesc = rhs.m_pszArmoryDesc;
  2475. m_iScore = rhs.m_iScore;
  2476. m_pszDefinitionName = rhs.m_pszDefinitionName;
  2477. m_pszAttributeClass = rhs.m_pszAttributeClass;
  2478. m_unAssetClassBucket = rhs.m_unAssetClassBucket;
  2479. #ifndef GC_DLL
  2480. m_iszAttributeClass = rhs.m_iszAttributeClass;
  2481. #endif
  2482. m_pKVAttribute = NULL;
  2483. if ( NULL != rhs.m_pKVAttribute )
  2484. {
  2485. m_pKVAttribute = rhs.m_pKVAttribute->MakeCopy();
  2486. // Re-assign string pointers
  2487. m_pszDefinitionName = m_pKVAttribute->GetString("name");
  2488. m_pszDescriptionString = m_pKVAttribute->GetString( "description_string", NULL );
  2489. m_pszDescriptionTag = m_pKVAttribute->GetString( "description_tag", NULL );
  2490. m_pszArmoryDesc = m_pKVAttribute->GetString( "armory_desc", NULL );
  2491. m_pszAttributeClass = m_pKVAttribute->GetString( "attribute_class", NULL );
  2492. Assert( V_strcmp( m_pszDefinitionName, rhs.m_pszDefinitionName ) == 0 );
  2493. Assert( V_strcmp( m_pszDescriptionString, rhs.m_pszDescriptionString ) == 0 );
  2494. Assert( V_strcmp( m_pszDescriptionTag, rhs.m_pszDescriptionTag ) == 0 );
  2495. Assert( V_strcmp( m_pszArmoryDesc, rhs.m_pszArmoryDesc ) == 0 );
  2496. Assert( V_strcmp( m_pszAttributeClass, rhs.m_pszAttributeClass ) == 0 );
  2497. }
  2498. else
  2499. {
  2500. Assert( m_pszDefinitionName == NULL );
  2501. Assert( m_pszDescriptionString == NULL );
  2502. Assert( m_pszArmoryDesc == NULL );
  2503. Assert( m_pszAttributeClass == NULL );
  2504. }
  2505. return *this;
  2506. }
  2507. //-----------------------------------------------------------------------------
  2508. // Purpose: Destructor
  2509. //-----------------------------------------------------------------------------
  2510. CEconItemAttributeDefinition::~CEconItemAttributeDefinition( void )
  2511. {
  2512. if ( m_pKVAttribute )
  2513. m_pKVAttribute->deleteThis();
  2514. m_pKVAttribute = NULL;
  2515. }
  2516. //-----------------------------------------------------------------------------
  2517. // Purpose: Initialize the attribute definition
  2518. // Input: pKVAttribute - The KeyValues representation of the attribute
  2519. // schema - The overall item schema for this attribute
  2520. // pVecErrors - An optional vector that will contain error messages if
  2521. // the init fails.
  2522. // Output: True if initialization succeeded, false otherwise
  2523. //-----------------------------------------------------------------------------
  2524. bool CEconItemAttributeDefinition::BInitFromKV( KeyValues *pKVAttribute, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  2525. {
  2526. m_pKVAttribute = pKVAttribute->MakeCopy();
  2527. m_nDefIndex = Q_atoi( m_pKVAttribute->GetName() );
  2528. m_pszDefinitionName = m_pKVAttribute->GetString("name");
  2529. m_bHidden = m_pKVAttribute->GetInt( "hidden", 0 ) != 0;
  2530. m_bWebSchemaOutputForced = m_pKVAttribute->GetInt( "force_output_description", 0 ) != 0;
  2531. m_bStoredAsInteger = m_pKVAttribute->GetInt( "stored_as_integer", 0 ) != 0;
  2532. m_iScore = m_pKVAttribute->GetInt( "score", 0 );
  2533. m_iEffectType = (attrib_effect_types_t)StringFieldToInt( m_pKVAttribute->GetString("effect_type"), g_EffectTypes, ARRAYSIZE(g_EffectTypes) );
  2534. m_iDescriptionFormat = StringFieldToInt( m_pKVAttribute->GetString("description_format"), g_AttributeDescriptionFormats, ARRAYSIZE(g_AttributeDescriptionFormats) );
  2535. m_pszDescriptionString = m_pKVAttribute->GetString( "description_string", NULL );
  2536. m_pszDescriptionTag = m_pKVAttribute->GetString( "description_tag", NULL );
  2537. m_pszArmoryDesc = m_pKVAttribute->GetString( "armory_desc", NULL );
  2538. m_pszAttributeClass = m_pKVAttribute->GetString( "attribute_class", NULL );
  2539. m_bInstanceData = pKVAttribute->GetBool( "instance_data", false );
  2540. const char *pszAttrType = m_pKVAttribute->GetString( "attribute_type", NULL ); // NULL implies "default type" for backwards compatibility
  2541. m_pAttrType = pschema.GetAttributeType( pszAttrType );
  2542. SCHEMA_INIT_CHECK(
  2543. NULL != m_pAttrType,
  2544. CFmtStr( "Attribute definition %s: Unable to find attribute data type '%s'", m_pszDefinitionName, pszAttrType ? pszAttrType : "(default)" ) );
  2545. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  2546. m_iszAttributeClass = NULL_STRING;
  2547. #endif
  2548. // Check for required fields
  2549. SCHEMA_INIT_CHECK(
  2550. NULL != m_pKVAttribute->FindKey( "name" ),
  2551. CFmtStr( "Attribute definition %s: Missing required field \"name\"", m_pKVAttribute->GetName() ) );
  2552. m_unAssetClassBucket = pKVAttribute->GetInt( "asset_class_bucket", 0 );
  2553. m_eAssetClassAttrExportRule = k_EAssetClassAttrExportRule_Default;
  2554. if ( char const *szRule = pKVAttribute->GetString( "asset_class_export", NULL ) )
  2555. {
  2556. if ( !V_stricmp( szRule, "skip" ) )
  2557. {
  2558. m_eAssetClassAttrExportRule = k_EAssetClassAttrExportRule_Skip;
  2559. }
  2560. else if ( !V_stricmp( szRule, "gconly" ) )
  2561. {
  2562. m_eAssetClassAttrExportRule = EAssetClassAttrExportRule_t( k_EAssetClassAttrExportRule_GCOnly | k_EAssetClassAttrExportRule_Skip );
  2563. }
  2564. else if ( !V_stricmp( szRule, "bucketed" ) )
  2565. {
  2566. SCHEMA_INIT_CHECK(
  2567. m_unAssetClassBucket,
  2568. CFmtStr( "Attribute definition %s: Asset class export rule '%s' is incompatible", m_pszDefinitionName, szRule ) );
  2569. m_eAssetClassAttrExportRule = k_EAssetClassAttrExportRule_Bucketed;
  2570. }
  2571. else if ( !V_stricmp( szRule, "default" ) )
  2572. {
  2573. m_eAssetClassAttrExportRule = k_EAssetClassAttrExportRule_Default;
  2574. }
  2575. else
  2576. {
  2577. SCHEMA_INIT_CHECK(
  2578. false,
  2579. CFmtStr( "Attribute definition %s: Invalid asset class export rule '%s'", m_pszDefinitionName, szRule ) );
  2580. }
  2581. }
  2582. // Check for misuse of asset class bucket
  2583. SCHEMA_INIT_CHECK(
  2584. ( !m_unAssetClassBucket || m_bInstanceData ),
  2585. CFmtStr( "Attribute definition %s: Cannot use \"asset_class_bucket\" on class-level attributes", m_pKVAttribute->GetName() )
  2586. );
  2587. return SCHEMA_INIT_SUCCESS();
  2588. }
  2589. //-----------------------------------------------------------------------------
  2590. // Purpose: Constructor
  2591. //-----------------------------------------------------------------------------
  2592. CEconSoundMaterialDefinition::CEconSoundMaterialDefinition( void )
  2593. : m_nID( INT_MAX )
  2594. {
  2595. }
  2596. //-----------------------------------------------------------------------------
  2597. // Purpose: Copy constructor
  2598. //-----------------------------------------------------------------------------
  2599. CEconSoundMaterialDefinition::CEconSoundMaterialDefinition( const CEconSoundMaterialDefinition &that )
  2600. {
  2601. (*this) = that;
  2602. }
  2603. //-----------------------------------------------------------------------------
  2604. // Purpose: Operator=
  2605. //-----------------------------------------------------------------------------
  2606. CEconSoundMaterialDefinition &CEconSoundMaterialDefinition::operator=( const CEconSoundMaterialDefinition &rhs )
  2607. {
  2608. m_nID = rhs.m_nID;
  2609. m_strName = rhs.m_strName;
  2610. m_strStartDragSound = rhs.m_strStartDragSound;
  2611. m_strEndDragSound = rhs.m_strEndDragSound;
  2612. m_strEquipSound = rhs.m_strEquipSound;
  2613. return *this;
  2614. }
  2615. //-----------------------------------------------------------------------------
  2616. // Purpose: Initialize the rarity definition
  2617. //-----------------------------------------------------------------------------
  2618. bool CEconSoundMaterialDefinition::BInitFromKV( KeyValues *pKVSoundMaterial, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  2619. {
  2620. m_nID = pKVSoundMaterial->GetInt( "value", -1 );
  2621. m_strName = pKVSoundMaterial->GetName();
  2622. m_strStartDragSound = pKVSoundMaterial->GetString( "start_drag_sound" );
  2623. m_strEndDragSound = pKVSoundMaterial->GetString( "end_drag_sound" );
  2624. m_strEquipSound = pKVSoundMaterial->GetString( "equip_sound" );
  2625. // Check for required fields
  2626. SCHEMA_INIT_CHECK(
  2627. NULL != pKVSoundMaterial->FindKey( "value" ),
  2628. CFmtStr( "Sound material definition %s: Missing required field \"value\"", pKVSoundMaterial->GetName() ) );
  2629. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  2630. return SCHEMA_INIT_SUCCESS();
  2631. #endif // GC_DLL
  2632. return SCHEMA_INIT_SUCCESS();
  2633. }
  2634. //-----------------------------------------------------------------------------
  2635. // Purpose: Constructor
  2636. //-----------------------------------------------------------------------------
  2637. CEconItemDefinition::CEconItemDefinition( void )
  2638. : m_pKVItem( NULL ),
  2639. m_bEnabled( false ),
  2640. m_unMinItemLevel( 0 ),
  2641. m_unMaxItemLevel( 100 ),
  2642. m_iArmoryRemap( 0 ),
  2643. m_iStoreRemap( 0 ),
  2644. m_nItemRarity( k_unItemRarity_Any ),
  2645. m_nItemQuality( k_unItemQuality_Any ),
  2646. m_nForcedItemQuality( k_unItemQuality_Any ),
  2647. m_nDefaultDropItemQuality( k_unItemQuality_Any ),
  2648. m_nDefaultDropQuantity( 1 ),
  2649. m_pProxyCriteria( NULL ),
  2650. m_bLoadOnDemand( false ),
  2651. m_pTool( NULL ),
  2652. m_rtExpiration( 0 ),
  2653. m_rtDefCreation( 0 ),
  2654. m_BundleInfo( NULL ),
  2655. m_unNumConcreteItems( 0 ),
  2656. m_nSoundMaterialID( 0 ),
  2657. m_nPopularitySeed( 0 ),
  2658. m_pszDefinitionName( NULL ),
  2659. m_pszItemClassname( NULL ),
  2660. m_pszClassToken( NULL ),
  2661. m_pszSlotToken( NULL ),
  2662. m_pszItemBaseName( NULL ),
  2663. m_pszItemTypeName( NULL ),
  2664. m_unItemTypeID( 0 ),
  2665. m_pszItemDesc( NULL ),
  2666. m_pszArmoryDesc( NULL ),
  2667. m_pszInventoryModel( NULL ),
  2668. m_pszInventoryImage( NULL ),
  2669. m_pszHolidayRestriction( NULL ),
  2670. m_iSubType( 0 ),
  2671. m_pszBaseDisplayModel( NULL ),
  2672. m_pszWorldDisplayModel( NULL ),
  2673. m_pszWorldDroppedModel( NULL ),
  2674. m_pszWorldExtraWearableModel( NULL ),
  2675. m_pszIconDefaultImage( NULL ),
  2676. m_pszParticleFile( NULL ),
  2677. m_pszParticleSnapshotFile( NULL ),
  2678. m_pInventoryImageData( NULL ),
  2679. m_pszBrassModelOverride( NULL ),
  2680. m_bHideBodyGroupsDeployedOnly( false ),
  2681. m_bAttachToHands( false ),
  2682. m_bAttachToHandsVMOnly( false ),
  2683. m_bProperName( false ),
  2684. m_bFlipViewModel( false ),
  2685. m_bActAsWearable( false ),
  2686. m_iDropType( 1 ),
  2687. m_bHidden( false ),
  2688. m_bShouldShowInArmory( false ),
  2689. m_bIsPackBundle( false ),
  2690. m_pOwningPackBundle( NULL ),
  2691. m_bBaseItem( false ),
  2692. m_pszItemLogClassname( NULL ),
  2693. m_pszItemIconClassname( NULL ),
  2694. #if ECONITEM_DATABASE_AUDIT_TABLES_FEATURE
  2695. m_pszDatabaseAuditTable( NULL ),
  2696. #endif
  2697. m_bImported( false ),
  2698. m_bOnePerAccountCDKEY( false ),
  2699. m_pszArmoryRemap( NULL ),
  2700. m_pszStoreRemap( NULL ),
  2701. m_bPublicItem( false ),
  2702. m_bIgnoreInCollectionView( false ),
  2703. m_nAssociatedItemsDefIndexes( NULL ),
  2704. m_pPortraitsKV( NULL ),
  2705. m_pAssetInfo( NULL ),
  2706. m_eItemType( k_EItemTypeNone ),
  2707. m_bAllowPurchaseStandalone( false )
  2708. {
  2709. m_pMapAlternateIcons = new CUtlMap<uint32, const char*>;
  2710. m_pMapAlternateIcons->SetLessFunc( DefLessFunc(uint32) );
  2711. }
  2712. //-----------------------------------------------------------------------------
  2713. // Purpose: Destructor
  2714. //-----------------------------------------------------------------------------
  2715. CEconItemDefinition::~CEconItemDefinition( void )
  2716. {
  2717. if ( m_pKVItem )
  2718. m_pKVItem->deleteThis();
  2719. m_pKVItem = NULL;
  2720. delete m_pProxyCriteria;
  2721. delete m_pTool;
  2722. delete m_BundleInfo;
  2723. delete m_pMapAlternateIcons;
  2724. if ( m_pInventoryImageData )
  2725. {
  2726. for ( int i = 0; i < MATERIAL_MAX_LIGHT_COUNT; i++ )
  2727. {
  2728. delete m_pInventoryImageData->m_pLightDesc[ i ];
  2729. }
  2730. delete m_pInventoryImageData->m_pCameraOffset;
  2731. delete m_pInventoryImageData->m_pCameraAngles;
  2732. delete m_pInventoryImageData;
  2733. }
  2734. PurgeStaticAttributes();
  2735. }
  2736. void CEconItemDefinition::PurgeStaticAttributes()
  2737. {
  2738. FOR_EACH_VEC( m_vecStaticAttributes, i )
  2739. {
  2740. static_attrib_t *pAttrib = &(m_vecStaticAttributes[ i ]);
  2741. const CEconItemAttributeDefinition *pAttrDef = pAttrib->GetAttributeDefinition();
  2742. Assert( pAttrDef );
  2743. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  2744. Assert( pAttrType );
  2745. // Free up our temp loading memory.
  2746. pAttrType->UnloadEconAttributeValue( &pAttrib->m_value );
  2747. }
  2748. m_vecStaticAttributes.Purge();
  2749. }
  2750. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  2751. //-----------------------------------------------------------------------------
  2752. // Purpose: Stomp our base data with extra testing data specified by the player
  2753. //-----------------------------------------------------------------------------
  2754. bool CEconItemDefinition::BInitFromTestItemKVs( int iNewDefIndex, KeyValues *pKVItem, CEconItemSchema &pschema )
  2755. {
  2756. // The KeyValues are stored in the player entity, so we can cache our name there
  2757. m_nDefIndex = iNewDefIndex;
  2758. bool bTestingExistingItem = pKVItem->GetInt( "test_existing_item", 0 ) != 0;
  2759. if ( !bTestingExistingItem )
  2760. {
  2761. m_pszDefinitionName = pKVItem->GetString( "name", NULL );
  2762. m_pszItemBaseName = pKVItem->GetString( "name", NULL );
  2763. #ifdef CLIENT_DLL
  2764. pKVItem->SetString( "name", VarArgs("Test Item %d", iNewDefIndex) );
  2765. #else
  2766. pKVItem->SetString( "name", UTIL_VarArgs("Test Item %d", iNewDefIndex) );
  2767. #endif
  2768. m_pszBaseDisplayModel = pKVItem->GetString( "model_player", NULL );
  2769. m_bAttachToHands = pKVItem->GetInt( "attach_to_hands", 0 ) != 0;
  2770. BInitVisualBlockFromKV( pKVItem, pschema );
  2771. m_pszParticleFile = pKVItem->GetString( "particle_file", NULL );
  2772. m_pszParticleSnapshotFile = pKVItem->GetString( "particle_snapshot", NULL );
  2773. }
  2774. // Handle attributes
  2775. PurgeStaticAttributes();
  2776. int iPaintCanIndex = pKVItem->GetInt("paintcan_index", 0);
  2777. if ( iPaintCanIndex )
  2778. {
  2779. static CSchemaAttributeDefHandle pAttrDef_PaintRGB( "set item tint RGB" );
  2780. const CEconItemDefinition *pCanDef = pschema.GetItemDefinition(iPaintCanIndex);
  2781. float flRGBVal;
  2782. if ( pCanDef && pAttrDef_PaintRGB && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pCanDef, pAttrDef_PaintRGB, &flRGBVal ) )
  2783. {
  2784. static_attrib_t& StaticAttrib = m_vecStaticAttributes[ m_vecStaticAttributes.AddToTail() ];
  2785. StaticAttrib.iDefIndex = pAttrDef_PaintRGB->GetDefinitionIndex();
  2786. StaticAttrib.m_value.asFloat = flRGBVal; // this is bad! but we're in crazy hack code for UI customization of item definitions that don't exist so
  2787. }
  2788. }
  2789. return true;
  2790. }
  2791. #endif
  2792. void AssetInfo::AddAssetModifier( AssetModifier* newMod )
  2793. {
  2794. int idx = m_mapAssetModifiers.Find( newMod->m_Type );
  2795. if ( !m_mapAssetModifiers.IsValidIndex( idx ) )
  2796. {
  2797. idx = m_mapAssetModifiers.Insert( newMod->m_Type, new CUtlVector<AssetModifier*> );
  2798. }
  2799. m_mapAssetModifiers[idx]->AddToTail( newMod );
  2800. }
  2801. CUtlVector<AssetModifier*>* AssetInfo::GetAssetModifiers( EAssetModifier type )
  2802. {
  2803. int idx = m_mapAssetModifiers.Find( type );
  2804. if ( m_mapAssetModifiers.IsValidIndex( idx ) )
  2805. {
  2806. return m_mapAssetModifiers[idx];
  2807. }
  2808. else
  2809. {
  2810. return NULL;
  2811. }
  2812. }
  2813. const char* AssetInfo::GetModifierByAsset( EAssetModifier type, const char* pszAsset, int iStyle )
  2814. {
  2815. CUtlVector<AssetModifier*>* pAssetModifierList = GetAssetModifiers( type );
  2816. if ( pAssetModifierList )
  2817. {
  2818. if ( iStyle > -1 )
  2819. {
  2820. // See if a modifier matches this style.
  2821. FOR_EACH_VEC( *pAssetModifierList, i )
  2822. {
  2823. AssetModifier* pMod = pAssetModifierList->Element(i);
  2824. if ( pMod->m_strAsset == pszAsset && pMod->m_iStyle == iStyle )
  2825. return pMod->m_strModifier;
  2826. }
  2827. }
  2828. // Return the first match.
  2829. FOR_EACH_VEC( *pAssetModifierList, i )
  2830. {
  2831. AssetModifier* pMod = pAssetModifierList->Element(i);
  2832. if ( pMod->m_strAsset == pszAsset )
  2833. return pMod->m_strModifier;
  2834. }
  2835. }
  2836. return NULL;
  2837. }
  2838. const char* AssetInfo::GetAssetByModifier( EAssetModifier type, const char* pszModifier, int iStyle )
  2839. {
  2840. CUtlVector<AssetModifier*>* pAssetModifierList = GetAssetModifiers( type );
  2841. if ( pAssetModifierList )
  2842. {
  2843. if ( iStyle > -1 )
  2844. {
  2845. // See if a modifier matches this style.
  2846. FOR_EACH_VEC( *pAssetModifierList, i )
  2847. {
  2848. AssetModifier* pMod = pAssetModifierList->Element(i);
  2849. if ( pMod->m_strModifier == pszModifier && pMod->m_iStyle == iStyle )
  2850. return pMod->m_strAsset;
  2851. }
  2852. }
  2853. // Return the first match.
  2854. FOR_EACH_VEC( *pAssetModifierList, i )
  2855. {
  2856. AssetModifier* pMod = pAssetModifierList->Element(i);
  2857. if ( pMod->m_strModifier == pszModifier )
  2858. return pMod->m_strAsset;
  2859. }
  2860. }
  2861. return NULL;
  2862. }
  2863. //-----------------------------------------------------------------------------
  2864. // Purpose: Handle parsing the per-team visual block from the keyvalues
  2865. //-----------------------------------------------------------------------------
  2866. void CEconItemDefinition::BInitVisualBlockFromKV( KeyValues *pKVItem, IEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors )
  2867. {
  2868. // Visuals
  2869. m_pAssetInfo = NULL;
  2870. KeyValues *pVisualsKV = pKVItem->FindKey( "visuals" );
  2871. if ( pVisualsKV )
  2872. {
  2873. AssetInfo *pVisData = new AssetInfo();
  2874. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  2875. KeyValues *pKVEntry = pVisualsKV->GetFirstSubKey();
  2876. while ( pKVEntry )
  2877. {
  2878. const char *pszEntry = pKVEntry->GetName();
  2879. if ( !Q_stricmp( pszEntry, "attached_models" ) )
  2880. {
  2881. FOR_EACH_SUBKEY( pKVEntry, pKVAttachedModelData )
  2882. {
  2883. int iAtt = pVisData->m_AttachedModels.AddToTail();
  2884. pVisData->m_AttachedModels[iAtt].m_iModelDisplayFlags = pKVAttachedModelData->GetInt( "model_display_flags", kAttachedModelDisplayFlag_MaskAll );
  2885. pVisData->m_AttachedModels[iAtt].m_pszModelName = pKVAttachedModelData->GetString( "model", NULL );
  2886. }
  2887. }
  2888. else if ( StringHasPrefix( pszEntry, "attached_particlesystem" ) )
  2889. {
  2890. // This replaces TF's "attached_particlesystem", "custom_particlesystem", and "custom_particlesystem2"
  2891. // It now indexes into the attributecontrolledparticlesystems list (use the "custom_type" field if you want a custom attribute)
  2892. int iParticleIndex;
  2893. if ( pschema.FindAttributeControlledParticleSystem( pKVEntry->GetString( "system", NULL ), &iParticleIndex ) )
  2894. {
  2895. attachedparticle_t attachedParticle;
  2896. attachedParticle.m_iParticleIndex = iParticleIndex;
  2897. attachedParticle.m_nStyle = pKVEntry->GetInt( "style", 0 );
  2898. pVisData->m_AttachedParticles.AddToTail( attachedParticle );
  2899. }
  2900. }
  2901. else if ( StringHasPrefix( pszEntry, "asset_modifier" ) )
  2902. {
  2903. AssetModifier* newMod = new AssetModifier();
  2904. newMod->m_Type = GetAssetModifierType( pKVEntry->GetString( "type", NULL ) );
  2905. newMod->m_strModifier = pKVEntry->GetString( "modifier", NULL );
  2906. newMod->m_flModifier = pKVEntry->GetFloat( "modifier", 0.f );
  2907. newMod->m_strAsset = pKVEntry->GetString( "asset", NULL );
  2908. newMod->m_iStyle = pKVEntry->GetInt( "style", 0 );
  2909. pVisData->AddAssetModifier( newMod );
  2910. // Items can have any number of asset modifiers.
  2911. // The variables can be used in any way, based on type, but the format is all the same to simplify the editor.
  2912. const char* pszAssetModifierType = pKVEntry->GetString( "type", NULL );
  2913. const char* pszAssetName = pKVEntry->GetString( "asset", NULL );
  2914. const char* pszModifierName = pKVEntry->GetString( "modifier", NULL );
  2915. float flFrequency = pKVEntry->GetFloat( "frequency", 1.0 );
  2916. if ( FStrEq( pszAssetModifierType, "activity" ) )
  2917. {
  2918. int iAtt = pVisData->m_Animations.AddToTail();
  2919. pVisData->m_Animations[iAtt].iActivity = -2;
  2920. pVisData->m_Animations[iAtt].pszActivity = pszAssetName;
  2921. pVisData->m_Animations[iAtt].iReplacement = kActivityLookup_Unknown;
  2922. pVisData->m_Animations[iAtt].pszReplacement = pszModifierName;
  2923. pVisData->m_Animations[iAtt].flFrequency = flFrequency;
  2924. }
  2925. else if ( FStrEq( pszAssetModifierType, "announcer" ) )
  2926. {
  2927. pVisData->m_pszAnnouncerName = pszAssetName;
  2928. pVisData->m_pszAnnouncerResource = pszModifierName;
  2929. }
  2930. else if ( FStrEq( pszAssetModifierType, "announcer_preview" ) )
  2931. {
  2932. CUtlString strFilename = pszAssetName;
  2933. announcer_preview_t preview;
  2934. preview.m_strFileName = pszAssetName;
  2935. preview.m_strCaption = pszModifierName;
  2936. pVisData->m_vecAnnouncerPreview.AddToTail( preview );
  2937. }
  2938. else if ( FStrEq( pszAssetModifierType, "hud_skin" ) )
  2939. {
  2940. pVisData->m_pszHudSkinName = pszAssetName;
  2941. }
  2942. else if ( FStrEq( pszAssetModifierType, "ability_name" ) )
  2943. {
  2944. pVisData->m_pszAbilityName = pszAssetName;
  2945. }
  2946. else if ( FStrEq( pszAssetModifierType, "sound" ) )
  2947. {
  2948. int iSound = pVisData->m_Sounds.AddToTail();
  2949. pVisData->m_Sounds[iSound].pszSound = pszAssetName;
  2950. pVisData->m_Sounds[iSound].pszReplacement = pszModifierName;
  2951. }
  2952. else if ( FStrEq( pszAssetModifierType, "speech" ) )
  2953. {
  2954. pVisData->m_pszSpeechConcept = pszAssetName;
  2955. pVisData->m_pszChatMessage = pszModifierName;
  2956. }
  2957. else if ( FStrEq( pszAssetModifierType, "particle" ) )
  2958. {
  2959. int iParticle = pVisData->m_Particles.AddToTail();
  2960. pVisData->m_Particles[iParticle].pszParticle = pszAssetName;
  2961. pVisData->m_Particles[iParticle].pszReplacement = pszModifierName;
  2962. }
  2963. else if ( FStrEq( pszAssetModifierType, "particle_snapshot" ) )
  2964. {
  2965. int iParticle = pVisData->m_ParticleSnapshots.AddToTail();
  2966. pVisData->m_ParticleSnapshots[iParticle].pszParticleSnapshot = pszAssetName;
  2967. pVisData->m_ParticleSnapshots[iParticle].pszReplacement = pszModifierName;
  2968. }
  2969. else if ( FStrEq( pszAssetModifierType, "particle_control_point" ) )
  2970. {
  2971. int iParticleCP = pVisData->m_ParticleControlPoints.AddToTail();
  2972. pVisData->m_ParticleControlPoints[iParticleCP].pszParticle = pszAssetName;
  2973. pVisData->m_ParticleControlPoints[iParticleCP].nParticleControlPoint = pKVEntry->GetInt( "control_point_number", 0 );
  2974. UTIL_StringToVector( pVisData->m_ParticleControlPoints[iParticleCP].vecCPValue.Base(), pKVEntry->GetString( "cp_position", "0 0 0" ) );
  2975. }
  2976. else if ( FStrEq( pszAssetModifierType, "entity_model" ) )
  2977. {
  2978. pVisData->m_pszEntityClass = pszAssetName;
  2979. pVisData->m_pszEntityModel = pszModifierName;
  2980. }
  2981. else if ( FStrEq( pszAssetModifierType, "view_model" ) )
  2982. {
  2983. pVisData->m_pszEntityClass = pszAssetName;
  2984. pVisData->m_pszViewModel = pszModifierName;
  2985. }
  2986. else if ( FStrEq( pszAssetModifierType, "icon_replacement" ) )
  2987. {
  2988. pVisData->m_pszOriginalIcon = pszAssetName;
  2989. pVisData->m_pszNewIcon = pszModifierName;
  2990. }
  2991. else if ( FStrEq( pszAssetModifierType, "ability_icon_replacement" ) )
  2992. {
  2993. ability_icon_replacement_t iconReplacement;
  2994. iconReplacement.m_strAbilityName = pszAssetName;
  2995. iconReplacement.m_strReplacement = pszModifierName;
  2996. pVisData->m_vecAbilityIconReplacements.AddToTail( iconReplacement );
  2997. }
  2998. else if ( FStrEq( pszAssetModifierType, "entity_scale" ) )
  2999. {
  3000. pVisData->m_pszScaleClass = pszAssetName;
  3001. pVisData->m_flScaleSize = pKVEntry->GetFloat( "modifier", 1.f );
  3002. }
  3003. }
  3004. else if ( !Q_stricmp( pszEntry, "animation" ) )
  3005. {
  3006. int iAtt = pVisData->m_Animations.AddToTail();
  3007. pVisData->m_Animations[iAtt].iActivity = -2; // We can't look it up yet, the activity list hasn't been populated.
  3008. pVisData->m_Animations[iAtt].pszActivity = pKVEntry->GetString( "activity", NULL );
  3009. const char* playback = pKVEntry->GetString( "playback" );
  3010. if ( playback )
  3011. {
  3012. pVisData->m_Animations[iAtt].iPlayback = (wearableanimplayback_t)StringFieldToInt( pKVEntry->GetString("playback"), g_WearableAnimTypeStrings, ARRAYSIZE(g_WearableAnimTypeStrings) );
  3013. }
  3014. pVisData->m_Animations[iAtt].iReplacement = kActivityLookup_Unknown;
  3015. pVisData->m_Animations[iAtt].pszReplacement = pKVEntry->GetString( "replacement", NULL );
  3016. pVisData->m_Animations[iAtt].pszSequence = pKVEntry->GetString( "sequence", NULL );
  3017. pVisData->m_Animations[iAtt].pszScene = pKVEntry->GetString( "scene", NULL );
  3018. pVisData->m_Animations[iAtt].pszRequiredItem = pKVEntry->GetString( "required_item", NULL );
  3019. pVisData->m_Animations[iAtt].flFrequency = pKVEntry->GetFloat( "frequency", 1.0 );
  3020. }
  3021. else if ( !Q_stricmp( pszEntry, "player_bodygroups" ) )
  3022. {
  3023. FOR_EACH_SUBKEY( pKVEntry, pKVBodygroupKey )
  3024. {
  3025. const char *pszBodygroupName = pKVBodygroupKey->GetName();
  3026. int iValue = pKVBodygroupKey->GetInt();
  3027. // Track bodygroup information for this item in particular.
  3028. pVisData->m_ModifiedBodyGroupNames.Insert( pszBodygroupName, iValue );
  3029. // Track global schema state.
  3030. CEconItemSchema* pItemSchema = (CEconItemSchema*) &pschema;
  3031. pItemSchema->AssignDefaultBodygroupState( pszBodygroupName, iValue );
  3032. }
  3033. }
  3034. else if ( !Q_stricmp( pszEntry, "skin" ) )
  3035. {
  3036. pVisData->iSkin = pKVEntry->GetInt();
  3037. }
  3038. else if ( !Q_stricmp( pszEntry, "use_per_class_bodygroups" ) )
  3039. {
  3040. pVisData->bUsePerClassBodygroups = pKVEntry->GetBool();
  3041. }
  3042. else if ( !Q_stricmp( pszEntry, "muzzle_flash" ) )
  3043. {
  3044. pVisData->m_pszMuzzleFlash = pKVEntry->GetString();
  3045. }
  3046. else if ( !Q_stricmp( pszEntry, "tracer_effect" ) )
  3047. {
  3048. pVisData->m_pszTracerEffect = pKVEntry->GetString();
  3049. }
  3050. else if ( !Q_stricmp( pszEntry, "particle_effect" ) )
  3051. {
  3052. pVisData->m_pszParticleEffect = pKVEntry->GetString();
  3053. }
  3054. else if ( !Q_stricmp( pszEntry, "particle_snapshot" ) )
  3055. {
  3056. pVisData->m_pszParticleSnapshot = pKVEntry->GetString();
  3057. }
  3058. else if ( StringHasPrefix( pszEntry, "custom_sound" ) ) // TF2 style custom sounds.
  3059. {
  3060. int iIndex = 0;
  3061. if ( pszEntry[12] )
  3062. {
  3063. iIndex = clamp( atoi( &pszEntry[12] ), 0, MAX_VISUALS_CUSTOM_SOUNDS-1 );
  3064. }
  3065. pVisData->m_pszCustomSounds[iIndex] = pKVEntry->GetString();
  3066. }
  3067. else if ( !Q_stricmp( pszEntry, "material_override" ) )
  3068. {
  3069. pVisData->m_pszMaterialOverride = pKVEntry->GetString();
  3070. }
  3071. else if ( StringHasPrefix( pszEntry, "sound_" ) ) // Orange box style weapon sounds.
  3072. {
  3073. int iIndex = GetWeaponSoundFromString( &pszEntry[6] );
  3074. if ( iIndex != -1 )
  3075. {
  3076. pVisData->m_pszWeaponSoundReplacements[iIndex] = pKVEntry->GetString();
  3077. }
  3078. }
  3079. else if ( !Q_stricmp( pszEntry, "code_controlled_bodygroup" ) )
  3080. {
  3081. const char *pBodyGroupName = pKVEntry->GetString( "bodygroup", NULL );
  3082. const char *pFuncName = pKVEntry->GetString( "function", NULL );
  3083. if ( pBodyGroupName && pFuncName )
  3084. {
  3085. codecontrolledbodygroupdata_t ccbgd = { pFuncName, NULL };
  3086. pVisData->m_CodeControlledBodyGroupNames.Insert( pBodyGroupName, ccbgd );
  3087. }
  3088. }
  3089. else if ( !Q_stricmp( pszEntry, "vm_bodygroup_override" ) )
  3090. {
  3091. pVisData->m_iViewModelBodyGroupOverride = pKVEntry->GetInt();
  3092. }
  3093. else if ( !Q_stricmp( pszEntry, "vm_bodygroup_state_override" ) )
  3094. {
  3095. pVisData->m_iViewModelBodyGroupStateOverride = pKVEntry->GetInt();
  3096. }
  3097. else if ( !Q_stricmp( pszEntry, "wm_bodygroup_override" ) )
  3098. {
  3099. pVisData->m_iWorldModelBodyGroupOverride = pKVEntry->GetInt();
  3100. }
  3101. else if ( !Q_stricmp( pszEntry, "wm_bodygroup_state_override" ) )
  3102. {
  3103. pVisData->m_iWorldModelBodyGroupStateOverride = pKVEntry->GetInt();
  3104. }
  3105. else if ( !Q_stricmp( pszEntry, "skip_model_combine" ) )
  3106. {
  3107. pVisData->m_bSkipModelCombine = pKVEntry->GetBool();
  3108. }
  3109. else if ( !Q_stricmp( pszEntry, "animation_modifiers" ) )
  3110. {
  3111. FOR_EACH_SUBKEY( pKVEntry, pKVAnimMod )
  3112. {
  3113. pVisData->m_vecAnimationModifiers.AddToTail( pKVAnimMod->GetName() );
  3114. }
  3115. }
  3116. #ifdef CSTRIKE15
  3117. ////////////// CS:GO string attributes
  3118. else if ( !Q_stricmp( pszEntry, "primary_ammo" ) )
  3119. {
  3120. pVisData->m_pszPrimaryAmmo = pKVEntry->GetString();
  3121. }
  3122. else if ( !Q_stricmp( pszEntry, "weapon_type" ) )
  3123. {
  3124. pVisData->m_pszWeaponTypeString = pKVEntry->GetString();
  3125. }
  3126. else if ( !Q_stricmp( pszEntry, "addon_location" ) )
  3127. {
  3128. pVisData->m_pszAddonLocation = pKVEntry->GetString();
  3129. }
  3130. else if ( !Q_stricmp( pszEntry, "eject_brass_effect" ) )
  3131. {
  3132. pVisData->m_pszEjectBrassEffect = pKVEntry->GetString();
  3133. }
  3134. else if ( !Q_stricmp( pszEntry, "tracer_effect" ) )
  3135. {
  3136. pVisData->m_pszTracerEffect = pKVEntry->GetString();
  3137. }
  3138. else if ( !Q_stricmp( pszEntry, "muzzle_flash_effect_1st_person" ) )
  3139. {
  3140. pVisData->m_pszMuzzleFlashEffect1stPerson = pKVEntry->GetString();
  3141. }
  3142. else if ( !Q_stricmp( pszEntry, "muzzle_flash_effect_1st_person_alt" ) )
  3143. {
  3144. pVisData->m_pszMuzzleFlashEffect1stPersonAlt = pKVEntry->GetString();
  3145. }
  3146. else if ( !Q_stricmp( pszEntry, "muzzle_flash_effect_3rd_person" ) )
  3147. {
  3148. pVisData->m_pszMuzzleFlashEffect3rdPerson = pKVEntry->GetString();
  3149. }
  3150. else if ( !Q_stricmp( pszEntry, "muzzle_flash_effect_3rd_person_alt" ) )
  3151. {
  3152. pVisData->m_pszMuzzleFlashEffect3rdPersonAlt = pKVEntry->GetString();
  3153. }
  3154. else if ( !Q_stricmp( pszEntry, "heat_effect" ) )
  3155. {
  3156. pVisData->m_pszHeatEffect = pKVEntry->GetString();
  3157. }
  3158. else if ( !Q_stricmp( pszEntry, "player_animation_extension" ) )
  3159. {
  3160. pVisData->m_pszPlayerAnimationExtension = pKVEntry->GetString();
  3161. }
  3162. #endif //#ifdef CSTRIKE15
  3163. pKVEntry = pKVEntry->GetNextKey();
  3164. }
  3165. #endif // defined(CLIENT_DLL) || defined(GAME_DLL)
  3166. KeyValues *pStylesDataKV = pVisualsKV->FindKey( "styles" );
  3167. if ( pStylesDataKV )
  3168. {
  3169. BInitStylesBlockFromKV( pStylesDataKV, *(CEconItemSchema*)( &pschema ), pVisData, pVecErrors );
  3170. }
  3171. KeyValues * pKVAlternateIcons = pVisualsKV->FindKey( "alternate_icons" );
  3172. if ( NULL != pKVAlternateIcons )
  3173. {
  3174. BInitAlternateIconsFromKV( pKVAlternateIcons, *(CEconItemSchema*)( &pschema ), pVisData, pVecErrors );
  3175. }
  3176. m_pAssetInfo = pVisData;
  3177. }
  3178. }
  3179. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  3180. //-----------------------------------------------------------------------------
  3181. // Purpose:
  3182. //-----------------------------------------------------------------------------
  3183. void CEconItemDefinition::GeneratePrecacheModelStrings( bool bDynamicLoad, CUtlVector<const char *> *out_pVecModelStrings ) const
  3184. {
  3185. Assert( out_pVecModelStrings );
  3186. // Add base model.
  3187. out_pVecModelStrings->AddToTail( GetBasePlayerDisplayModel() );
  3188. // Add styles.
  3189. if ( GetNumStyles() )
  3190. {
  3191. for ( style_index_t i=0; i<GetNumStyles(); ++i )
  3192. {
  3193. const CEconStyleInfo *pStyle = GetStyleInfo( i );
  3194. Assert( pStyle );
  3195. pStyle->GeneratePrecacheModelStringsForStyle( out_pVecModelStrings );
  3196. }
  3197. }
  3198. if ( m_pAssetInfo )
  3199. {
  3200. // Precache all the attached models.
  3201. for ( int model = 0; model < m_pAssetInfo->m_AttachedModels.Count(); model++ )
  3202. {
  3203. out_pVecModelStrings->AddToTail( m_pAssetInfo->m_AttachedModels[model].m_pszModelName );
  3204. }
  3205. // Precache any model overrides.
  3206. if ( m_pAssetInfo->m_pszEntityModel )
  3207. {
  3208. out_pVecModelStrings->AddToTail( m_pAssetInfo->m_pszEntityModel );
  3209. }
  3210. if ( m_pAssetInfo->m_pszViewModel )
  3211. {
  3212. out_pVecModelStrings->AddToTail( m_pAssetInfo->m_pszViewModel );
  3213. }
  3214. // Precache hero model change.
  3215. CUtlVector<AssetModifier*>* pHeroModelChanges = m_pAssetInfo->GetAssetModifiers( AM_HeroModelChange );
  3216. if ( pHeroModelChanges )
  3217. {
  3218. FOR_EACH_VEC( *pHeroModelChanges, i )
  3219. {
  3220. AssetModifier* pAssetMod = pHeroModelChanges->Element( i );
  3221. if ( pAssetMod )
  3222. {
  3223. out_pVecModelStrings->AddToTail( pAssetMod->m_strModifier.Get() );
  3224. }
  3225. }
  3226. }
  3227. // Precache couriers.
  3228. pHeroModelChanges = m_pAssetInfo->GetAssetModifiers( AM_Courier );
  3229. if ( pHeroModelChanges )
  3230. {
  3231. FOR_EACH_VEC( *pHeroModelChanges, i )
  3232. {
  3233. AssetModifier* pAssetMod = pHeroModelChanges->Element( i );
  3234. if ( pAssetMod )
  3235. {
  3236. out_pVecModelStrings->AddToTail( pAssetMod->m_strModifier.Get() );
  3237. }
  3238. }
  3239. }
  3240. // Precache flying couriers.
  3241. pHeroModelChanges = m_pAssetInfo->GetAssetModifiers( AM_CourierFlying );
  3242. if ( pHeroModelChanges )
  3243. {
  3244. FOR_EACH_VEC( *pHeroModelChanges, i )
  3245. {
  3246. AssetModifier* pAssetMod = pHeroModelChanges->Element( i );
  3247. if ( pAssetMod )
  3248. {
  3249. out_pVecModelStrings->AddToTail( pAssetMod->m_strModifier.Get() );
  3250. }
  3251. }
  3252. }
  3253. }
  3254. #ifdef DOTA_DLL
  3255. // We don't need to cache the inventory model, because it's never loaded by the game.
  3256. #else
  3257. if ( GetIconDisplayModel() )
  3258. {
  3259. out_pVecModelStrings->AddToTail( GetIconDisplayModel() );
  3260. }
  3261. #endif
  3262. if ( GetBuyMenuDisplayModel() )
  3263. {
  3264. out_pVecModelStrings->AddToTail( GetBuyMenuDisplayModel() );
  3265. }
  3266. if ( GetWorldDroppedModel() )
  3267. {
  3268. out_pVecModelStrings->AddToTail( GetWorldDroppedModel() );
  3269. }
  3270. if ( GetMagazineModel() )
  3271. {
  3272. out_pVecModelStrings->AddToTail( GetMagazineModel() );
  3273. }
  3274. if ( GetScopeLensMaskModel() )
  3275. {
  3276. out_pVecModelStrings->AddToTail( GetScopeLensMaskModel() );
  3277. }
  3278. const KillEaterScoreMap_t& mapKillEaterScoreTypes = GetItemSchema()->GetKillEaterScoreTypes();
  3279. FOR_EACH_MAP( mapKillEaterScoreTypes, i )
  3280. {
  3281. const char *pchStatTrakModel = GetStatTrakModelByType( mapKillEaterScoreTypes[ i ].m_nValue );
  3282. if ( pchStatTrakModel )
  3283. {
  3284. out_pVecModelStrings->AddToTail( pchStatTrakModel );
  3285. }
  3286. }
  3287. if ( GetUidModel() )
  3288. {
  3289. out_pVecModelStrings->AddToTail( GetUidModel() );
  3290. }
  3291. for ( int i=0; i<GetNumSupportedStickerSlots(); ++i )
  3292. {
  3293. if ( GetStickerSlotModelBySlotIndex(i) )
  3294. {
  3295. out_pVecModelStrings->AddToTail( GetStickerSlotModelBySlotIndex(i) );
  3296. }
  3297. }
  3298. }
  3299. //-----------------------------------------------------------------------------
  3300. // Purpose:
  3301. //-----------------------------------------------------------------------------
  3302. void CEconItemDefinition::GeneratePrecacheSoundStrings( CUtlVector<const char*> *out_pVecSoundStrings ) const
  3303. {
  3304. Assert( out_pVecSoundStrings );
  3305. // Precache all replacement sounds.
  3306. if ( m_pAssetInfo )
  3307. {
  3308. for ( int sound=0; sound<m_pAssetInfo->m_Sounds.Count(); sound++ )
  3309. {
  3310. out_pVecSoundStrings->AddToTail( m_pAssetInfo->m_Sounds[sound].pszReplacement );
  3311. }
  3312. for ( int sound = 0; sound < ARRAYSIZE( m_pAssetInfo->m_pszWeaponSoundReplacements ); sound++ )
  3313. {
  3314. if ( !m_pAssetInfo->m_pszWeaponSoundReplacements[ sound ] )
  3315. continue;
  3316. out_pVecSoundStrings->AddToTail( m_pAssetInfo->m_pszWeaponSoundReplacements[ sound ] );
  3317. }
  3318. }
  3319. }
  3320. void CEconItemDefinition::GeneratePrecacheEffectStrings( CUtlVector<const char*> *out_pVecEffectStrings ) const
  3321. {
  3322. Assert( out_pVecEffectStrings );
  3323. if ( !m_pAssetInfo )
  3324. return;
  3325. if ( m_pAssetInfo->m_pszEjectBrassEffect )
  3326. {
  3327. out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszEjectBrassEffect );
  3328. }
  3329. if ( m_pAssetInfo->m_pszTracerEffect )
  3330. {
  3331. out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszTracerEffect );
  3332. }
  3333. if ( m_pAssetInfo->m_pszMuzzleFlashEffect1stPerson )
  3334. {
  3335. out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszMuzzleFlashEffect1stPerson );
  3336. }
  3337. if ( m_pAssetInfo->m_pszMuzzleFlashEffect1stPersonAlt )
  3338. {
  3339. out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszMuzzleFlashEffect1stPersonAlt );
  3340. }
  3341. if ( m_pAssetInfo->m_pszMuzzleFlashEffect3rdPerson )
  3342. {
  3343. out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszMuzzleFlashEffect3rdPerson );
  3344. }
  3345. if ( m_pAssetInfo->m_pszMuzzleFlashEffect3rdPersonAlt )
  3346. {
  3347. out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszMuzzleFlashEffect3rdPersonAlt );
  3348. }
  3349. if ( m_pAssetInfo->m_pszHeatEffect )
  3350. {
  3351. out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszHeatEffect );
  3352. }
  3353. }
  3354. #endif // #if defined(CLIENT_DLL) || defined(GAME_DLL)
  3355. //-----------------------------------------------------------------------------
  3356. // Purpose: Parse the alternate icons for this item.
  3357. //-----------------------------------------------------------------------------
  3358. bool CEconItemDefinition::BInitAlternateIconsFromKV( KeyValues *pKVAlternateIcons, CEconItemSchema &pschema, AssetInfo *pVisData, CUtlVector<CUtlString> *pVecErrors )
  3359. {
  3360. m_pMapAlternateIcons->Purge();
  3361. FOR_EACH_TRUE_SUBKEY( pKVAlternateIcons, pKVAlternateIcon )
  3362. {
  3363. int iIconIndex = Q_atoi( pKVAlternateIcon->GetName() );
  3364. SCHEMA_INIT_CHECK(
  3365. !m_pMapAlternateIcons->Find( iIconIndex ) != m_pMapAlternateIcons->InvalidIndex(),
  3366. CFmtStr( "Duplicate alternate icon definition (%d)", iIconIndex ) );
  3367. SCHEMA_INIT_CHECK(
  3368. iIconIndex >= 0,
  3369. CFmtStr( "Alternate icon definition index %d must be greater than or equal to zero", iIconIndex ) );
  3370. m_pMapAlternateIcons->Insert( iIconIndex, pKVAlternateIcon->GetString( "icon_path" ) );
  3371. }
  3372. return SCHEMA_INIT_SUCCESS();
  3373. }
  3374. //-----------------------------------------------------------------------------
  3375. // Purpose: Parse the styles sub-section of the visuals block.
  3376. //-----------------------------------------------------------------------------
  3377. void CEconItemDefinition::BInitStylesBlockFromKV( KeyValues *pKVStyles, CEconItemSchema &pschema, AssetInfo *pVisData, CUtlVector<CUtlString> *pVecErrors )
  3378. {
  3379. FOR_EACH_SUBKEY( pKVStyles, pKVStyle )
  3380. {
  3381. CEconStyleInfo *pStyleInfo = pschema.CreateEconStyleInfo();
  3382. Assert( pStyleInfo );
  3383. pStyleInfo->BInitFromKV( pKVStyle, pschema, pVecErrors );
  3384. pVisData->m_Styles.AddToTail( pStyleInfo );
  3385. }
  3386. }
  3387. //-----------------------------------------------------------------------------
  3388. // Purpose: Parse one style from the styles block.
  3389. //-----------------------------------------------------------------------------
  3390. void CEconStyleInfo::BInitFromKV( KeyValues *pKVStyle, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors )
  3391. {
  3392. enum { kInvalidSkinKey = -1, };
  3393. Assert( pKVStyle );
  3394. m_iIndex = atoi( pKVStyle->GetName() );
  3395. // A "skin" entry means "use this index for all of our teams, no matter how many we have".
  3396. int iCommonSkin = pKVStyle->GetInt( "skin", kInvalidSkinKey );
  3397. if ( iCommonSkin != kInvalidSkinKey )
  3398. {
  3399. m_iSkin = iCommonSkin;
  3400. }
  3401. // If we don't have a base entry, we look for a unique entry for each team. This will be
  3402. // handled in a subclass if necessary.
  3403. // Are we hiding additional bodygroups when this style is active?
  3404. KeyValues *pKVHideBodygroups = pKVStyle->FindKey( "additional_hidden_bodygroups" );
  3405. if ( pKVHideBodygroups )
  3406. {
  3407. FOR_EACH_SUBKEY( pKVHideBodygroups, pKVBodygroup )
  3408. {
  3409. m_vecAdditionalHideBodygroups.AddToTail( pKVBodygroup->GetName() );
  3410. }
  3411. }
  3412. // Remaining common properties.
  3413. m_pszName = pKVStyle->GetString( "name", "#TF_UnknownStyle" );
  3414. m_pszBasePlayerModel = pKVStyle->GetString( "model_player", NULL );
  3415. // An alternate icon to use.
  3416. m_iIcon = pKVStyle->GetInt( "alternate_icon", 0 );
  3417. // Unlock rules.
  3418. KeyValues* pUnlockInfo = pKVStyle->FindKey( "unlock" );
  3419. if ( pUnlockInfo )
  3420. {
  3421. m_UnlockInfo.iPrice = pUnlockInfo->GetInt( "price", 0 );
  3422. m_UnlockInfo.pszItemName = pUnlockInfo->GetString( "item", NULL );
  3423. m_UnlockInfo.iStylePreReq = pUnlockInfo->GetInt( "style", 0 );
  3424. m_UnlockInfo.pszAttrib = pUnlockInfo->GetString( "attribute", NULL );
  3425. m_UnlockInfo.iAttribValue = pUnlockInfo->GetInt( "attribute_value", 0 );
  3426. }
  3427. }
  3428. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  3429. //-----------------------------------------------------------------------------
  3430. // Purpose:
  3431. //-----------------------------------------------------------------------------
  3432. void CEconStyleInfo::GeneratePrecacheModelStringsForStyle( CUtlVector<const char *> *out_pVecModelStrings ) const
  3433. {
  3434. Assert( out_pVecModelStrings );
  3435. if ( GetBasePlayerDisplayModel() != NULL )
  3436. {
  3437. out_pVecModelStrings->AddToTail( GetBasePlayerDisplayModel() );
  3438. }
  3439. }
  3440. #endif
  3441. //-----------------------------------------------------------------------------
  3442. // Purpose: Item definition initialization helpers.
  3443. //-----------------------------------------------------------------------------
  3444. static void RecursiveInheritKeyValues( KeyValues *out_pValues, KeyValues *pInstance )
  3445. {
  3446. FOR_EACH_SUBKEY( pInstance, pSubKey )
  3447. {
  3448. KeyValues::types_t eType = pSubKey->GetDataType();
  3449. switch ( eType )
  3450. {
  3451. case KeyValues::TYPE_STRING: out_pValues->SetString( pSubKey->GetName(), pSubKey->GetString() ); break;
  3452. case KeyValues::TYPE_INT: out_pValues->SetInt( pSubKey->GetName(), pSubKey->GetInt() ); break;
  3453. case KeyValues::TYPE_FLOAT: out_pValues->SetFloat( pSubKey->GetName(), pSubKey->GetFloat() ); break;
  3454. case KeyValues::TYPE_WSTRING: out_pValues->SetWString( pSubKey->GetName(), pSubKey->GetWString() ); break;
  3455. case KeyValues::TYPE_COLOR: out_pValues->SetColor( pSubKey->GetName(), pSubKey->GetColor() ) ; break;
  3456. case KeyValues::TYPE_UINT64: out_pValues->SetUint64( pSubKey->GetName(), pSubKey->GetUint64() ) ; break;
  3457. // "NONE" means "KeyValues"
  3458. case KeyValues::TYPE_NONE:
  3459. {
  3460. // We may already have this part of the tree to stuff data into/overwrite, or we
  3461. // may have to make a new block.
  3462. KeyValues *pNewChild = out_pValues->FindKey( pSubKey->GetName() );
  3463. if ( !pNewChild )
  3464. {
  3465. pNewChild = out_pValues->CreateNewKey();
  3466. pNewChild->SetName( pSubKey->GetName() );
  3467. }
  3468. RecursiveInheritKeyValues( pNewChild, pSubKey );
  3469. break;
  3470. }
  3471. case KeyValues::TYPE_PTR:
  3472. default:
  3473. Assert( !"Unhandled data type for KeyValues inheritance!" );
  3474. break;
  3475. }
  3476. }
  3477. }
  3478. #ifdef _DEBUG
  3479. #define DEBUG_SCHEMA_WRITE_TMP_FILE 0
  3480. #if DEBUG_SCHEMA_WRITE_TMP_FILE
  3481. #include <stdio.h>
  3482. class CKeyValuesDumpContextAsSchemaFile : public IKeyValuesDumpContextAsText
  3483. {
  3484. public:
  3485. // Overrides developer level to dump in DevMsg, zero to dump as Msg
  3486. CKeyValuesDumpContextAsSchemaFile() {}
  3487. public:
  3488. virtual bool KvWriteText( char const *szText )
  3489. {
  3490. FILE *f = NULL;
  3491. fopen_s( &f, "c:/tmp/econ_item_schema.txt", "a+t" );
  3492. if ( f )
  3493. {
  3494. fprintf( f, "%s", szText );
  3495. fclose( f );
  3496. }
  3497. return true;
  3498. }
  3499. }
  3500. g_schemadbg;
  3501. #endif
  3502. #endif
  3503. // Always returns a newly allocated copy of KeyValues
  3504. // Applies prefabs supporting multiple inheritance from Right-to-Left (RTL)
  3505. // this way "prefab" "valve tournament p250" will start with "p250" then apply "tournament" prefab on top of that,
  3506. // then will apply "valve" prefab on top of that and then the values of the actual instance.
  3507. static KeyValues *InheritKeyValuesRTLMulti( KeyValues *pInstance, CEconItemSchema &pschema )
  3508. {
  3509. Assert( pInstance );
  3510. KeyValues *pFinalValues = pInstance->MakeCopy();
  3511. #if DEBUG_SCHEMA_WRITE_TMP_FILE
  3512. static int s_nDebugIndentLevel = 0;
  3513. #endif
  3514. CUtlVector< char * > arrPrefabs;
  3515. if ( const char *svPrefabName = pFinalValues->GetString( "prefab", NULL ) )
  3516. {
  3517. Q_SplitString( svPrefabName, " ", arrPrefabs );
  3518. #if DEBUG_SCHEMA_WRITE_TMP_FILE
  3519. if ( arrPrefabs.Count() )
  3520. {
  3521. ++ s_nDebugIndentLevel;
  3522. g_schemadbg.KvWriteIndent( s_nDebugIndentLevel );
  3523. g_schemadbg.KvWriteText( CFmtStr( "Expanding data with %d prefabs:--\n", arrPrefabs.Count() ) );
  3524. pFinalValues->Dump( &g_schemadbg, s_nDebugIndentLevel );
  3525. g_schemadbg.KvWriteIndent( s_nDebugIndentLevel );
  3526. g_schemadbg.KvWriteText( "--\n" );
  3527. }
  3528. #endif
  3529. }
  3530. FOR_EACH_VEC_BACK( arrPrefabs, i )
  3531. {
  3532. KeyValues *pKVPrefab = pschema.FindDefinitionPrefabByName( arrPrefabs[i] );
  3533. if ( !pKVPrefab ) continue;
  3534. #if DEBUG_SCHEMA_WRITE_TMP_FILE
  3535. {
  3536. g_schemadbg.KvWriteIndent( s_nDebugIndentLevel );
  3537. g_schemadbg.KvWriteText( CFmtStr( "Appending prefab '%s':\n", arrPrefabs[i] ) );
  3538. pKVPrefab->Dump( &g_schemadbg, s_nDebugIndentLevel );
  3539. }
  3540. #endif
  3541. pKVPrefab = InheritKeyValuesRTLMulti( pKVPrefab, pschema );
  3542. pKVPrefab->SetName( pFinalValues->GetName() );
  3543. RecursiveInheritKeyValues( pKVPrefab, pFinalValues );
  3544. pFinalValues->deleteThis();
  3545. pFinalValues = pKVPrefab;
  3546. #if DEBUG_SCHEMA_WRITE_TMP_FILE
  3547. {
  3548. g_schemadbg.KvWriteIndent( s_nDebugIndentLevel );
  3549. g_schemadbg.KvWriteText( CFmtStr( "After appending prefab '%s':\n", arrPrefabs[ i ] ) );
  3550. pFinalValues->Dump( &g_schemadbg, s_nDebugIndentLevel );
  3551. }
  3552. #endif
  3553. }
  3554. #if DEBUG_SCHEMA_WRITE_TMP_FILE
  3555. if ( arrPrefabs.Count() )
  3556. {
  3557. g_schemadbg.KvWriteIndent( s_nDebugIndentLevel );
  3558. g_schemadbg.KvWriteText( CFmtStr( "Finished expanding data with %d prefabs:--\n", arrPrefabs.Count() ) );
  3559. pFinalValues->Dump( &g_schemadbg, s_nDebugIndentLevel );
  3560. g_schemadbg.KvWriteIndent( s_nDebugIndentLevel );
  3561. g_schemadbg.KvWriteText( "--\n" );
  3562. -- s_nDebugIndentLevel;
  3563. }
  3564. #endif
  3565. arrPrefabs.PurgeAndDeleteElements();
  3566. return pFinalValues;
  3567. }
  3568. KeyValues *CEconItemSchema::FindDefinitionPrefabByName( const char *pszPrefabName ) const
  3569. {
  3570. int iIndex = m_mapDefinitionPrefabs.Find( pszPrefabName );
  3571. if ( m_mapDefinitionPrefabs.IsValidIndex( iIndex ) )
  3572. return m_mapDefinitionPrefabs[iIndex];
  3573. return NULL;
  3574. }
  3575. //-----------------------------------------------------------------------------
  3576. // Purpose: Initialize the item definition
  3577. // Input: pKVItem - The KeyValues representation of the item
  3578. // schema - The overall item schema for this item
  3579. // pVecErrors - An optional vector that will contain error messages if
  3580. // the init fails.
  3581. // Output: True if initialization succeeded, false otherwise
  3582. //-----------------------------------------------------------------------------
  3583. bool CEconItemDefinition::BInitFromKV( KeyValues *pKVItem, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  3584. {
  3585. // Set standard members
  3586. m_pKVItem = InheritKeyValuesRTLMulti( pKVItem, pschema );
  3587. m_bEnabled = m_pKVItem->GetBool( "enabled" );
  3588. m_bLoadOnDemand = m_pKVItem->GetBool( "loadondemand" );
  3589. m_nDefIndex = Q_atoi( m_pKVItem->GetName() );
  3590. m_unMinItemLevel = (uint32)m_pKVItem->GetInt( "min_ilevel", pschema.GetMinLevel() );
  3591. m_unMaxItemLevel = (uint32)m_pKVItem->GetInt( "max_ilevel", pschema.GetMaxLevel() );
  3592. m_nDefaultDropQuantity = m_pKVItem->GetInt( "default_drop_quantity", 1 );
  3593. KeyValues *pKVMultiAssocItems = m_pKVItem->FindKey( "associated_items" ),
  3594. *pKVSingleAssocItem = m_pKVItem->FindKey( "associated_item" );
  3595. // Maybe we have multiple entries?
  3596. if ( pKVMultiAssocItems )
  3597. {
  3598. for ( KeyValues *pKVAssocItem = pKVMultiAssocItems->GetFirstSubKey(); pKVAssocItem; pKVAssocItem = pKVAssocItem->GetNextKey() )
  3599. {
  3600. m_nAssociatedItemsDefIndexes.AddToTail( atoi( pKVAssocItem->GetName() ) );
  3601. }
  3602. }
  3603. // This is our one-and-only-one associated item
  3604. else if ( pKVSingleAssocItem )
  3605. {
  3606. const char *pAssocItem = pKVSingleAssocItem->GetString( (const char *)NULL, NULL );
  3607. if ( pAssocItem )
  3608. {
  3609. m_nAssociatedItemsDefIndexes.AddToTail( atoi( pAssocItem ) );
  3610. }
  3611. }
  3612. m_nSoundMaterialID = m_pKVItem->GetInt( "sound_material" );
  3613. m_nPopularitySeed = m_pKVItem->GetInt( "popularity_seed", 0 );
  3614. // initializing this one first so that it will be available for all the errors below
  3615. m_pszDefinitionName = m_pKVItem->GetString( "name", NULL );
  3616. m_bDisableStyleSelection = m_pKVItem->GetBool( "disable_style_selector", false );
  3617. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  3618. // We read this manually here in the game dlls. The GC reads it below while checking pschema.
  3619. pschema.BGetItemQualityFromName( m_pKVItem->GetString( "item_quality" ), &m_nItemQuality );
  3620. pschema.BGetItemQualityFromName( m_pKVItem->GetString( "forced_item_quality" ), &m_nForcedItemQuality );
  3621. pschema.BGetItemQualityFromName( m_pKVItem->GetString( "default_drop_quality" ), &m_nDefaultDropItemQuality );
  3622. pschema.BGetItemRarityFromName( m_pKVItem->GetString( "item_rarity" ), &m_nItemRarity );
  3623. #endif
  3624. // Check for required fields
  3625. SCHEMA_INIT_CHECK(
  3626. NULL != m_pKVItem->FindKey( "name" ),
  3627. CFmtStr( "Item definition %s: Missing required field \"name\"", m_pKVItem->GetName() ) );
  3628. SCHEMA_INIT_CHECK(
  3629. NULL != m_pKVItem->FindKey( "item_class" ),
  3630. CFmtStr( "Item definition %s: Missing required field \"item_class\"", m_pKVItem->GetName() ) );
  3631. // Check value ranges
  3632. SCHEMA_INIT_CHECK(
  3633. m_pKVItem->GetInt( "min_ilevel" ) >= 0,
  3634. CFmtStr( "Item definition %s: \"min_ilevel\" must be greater than or equal to 0", GetDefinitionName() ) );
  3635. SCHEMA_INIT_CHECK(
  3636. m_pKVItem->GetInt( "max_ilevel" ) >= 0,
  3637. CFmtStr( "Item definition %s: \"max_ilevel\" must be greater than or equal to 0", GetDefinitionName() ) );
  3638. // Get the item class
  3639. m_pszItemClassname = m_pKVItem->GetString( "item_class", NULL );
  3640. m_bAllowPurchaseStandalone = m_pKVItem->GetBool( "allow_purchase_standalone", false );
  3641. m_pszClassToken = m_pKVItem->GetString( "class_token_id", NULL );
  3642. m_pszSlotToken = m_pKVItem->GetString( "slot_token_id", NULL );
  3643. m_bPublicItem = m_pKVItem->GetInt( "developer" ) == 0;
  3644. m_bIgnoreInCollectionView = m_pKVItem->GetBool( "ignore_in_collection_view", false );
  3645. // Display data
  3646. m_pszItemBaseName = m_pKVItem->GetString( "item_name", "" ); // non-NULL to ensure we can sort
  3647. m_pszItemTypeName = m_pKVItem->GetString( "item_type_name", "" ); // non-NULL to ensure we can sort
  3648. m_pszItemDesc = m_pKVItem->GetString( "item_description", NULL );
  3649. m_pszArmoryDesc = m_pKVItem->GetString( "armory_desc", NULL );
  3650. m_pszInventoryModel = m_pKVItem->GetString( "model_inventory", NULL );
  3651. m_pszInventoryImage = m_pKVItem->GetString( "image_inventory", NULL );
  3652. m_pPortraitsKV = m_pKVItem->FindKey( "portraits" );
  3653. m_unItemTypeID = CRC32_ProcessSingleBuffer( m_pszItemTypeName, V_strlen( m_pszItemTypeName ) );
  3654. const char* pOverlay = m_pKVItem->GetString( "image_inventory_overlay", NULL );
  3655. if ( pOverlay )
  3656. {
  3657. m_pszInventoryOverlayImages.AddToTail( pOverlay );
  3658. }
  3659. pOverlay = m_pKVItem->GetString( "image_inventory_overlay2", NULL );
  3660. if ( pOverlay )
  3661. {
  3662. m_pszInventoryOverlayImages.AddToTail( pOverlay );
  3663. }
  3664. m_iInventoryImagePosition[0] = m_pKVItem->GetInt( "image_inventory_pos_x", 0 );
  3665. m_iInventoryImagePosition[1] = m_pKVItem->GetInt( "image_inventory_pos_y", 0 );
  3666. m_iInventoryImageSize[0] = m_pKVItem->GetInt( "image_inventory_size_w", 0 );
  3667. m_iInventoryImageSize[1] = m_pKVItem->GetInt( "image_inventory_size_h", 0 );
  3668. m_pszHolidayRestriction = m_pKVItem->GetString( "holiday_restriction", NULL );
  3669. m_iSubType = m_pKVItem->GetInt( "subtype", 0 );
  3670. m_pszBaseDisplayModel = m_pKVItem->GetString( "model_player", NULL );
  3671. m_pszWorldDisplayModel = m_pKVItem->GetString( "model_world", NULL ); // Not the ideal method. c_models are better, but this is to solve a retrofit problem with the sticky launcher.
  3672. m_pszWorldDroppedModel = m_pKVItem->GetString( "model_dropped", NULL );
  3673. //build the world dropped model string by appending "_dropped"
  3674. if ( ( m_pszWorldDroppedModel == NULL ) && ( m_pszWorldDisplayModel != NULL ) )
  3675. {
  3676. V_StripExtension( m_pszWorldDisplayModel, m_szWorldDroppedModel, sizeof( m_szWorldDroppedModel ) );
  3677. V_strcat_safe( m_szWorldDroppedModel, "_dropped.mdl" );
  3678. m_pszWorldDroppedModel = m_szWorldDroppedModel;
  3679. }
  3680. // Add new StatTrak modules here.
  3681. m_pszIconDefaultImage = m_pKVItem->GetString( "icon_default_image", NULL );
  3682. m_pszWorldExtraWearableModel = m_pKVItem->GetString( "extra_wearable", NULL );
  3683. m_pszBrassModelOverride = m_pKVItem->GetString( "brass_eject_model", NULL );
  3684. m_pszWorldExtraWearableModel = m_pKVItem->GetString( "extra_wearable", NULL );
  3685. m_pszBrassModelOverride = m_pKVItem->GetString( "brass_eject_model", NULL );
  3686. m_bHideBodyGroupsDeployedOnly = m_pKVItem->GetBool( "hide_bodygroups_deployed_only" );
  3687. m_bAttachToHands = m_pKVItem->GetInt( "attach_to_hands", 0 ) != 0;
  3688. m_bAttachToHandsVMOnly = m_pKVItem->GetInt( "attach_to_hands_vm_only", 0 ) != 0;
  3689. m_bProperName = m_pKVItem->GetInt( "propername", 0 ) != 0;
  3690. m_bFlipViewModel = m_pKVItem->GetInt( "flip_viewmodel", 0 ) != 0;
  3691. m_bActAsWearable = m_pKVItem->GetInt( "act_as_wearable", 0 ) != 0;
  3692. m_iDropType = StringFieldToInt( m_pKVItem->GetString("drop_type"), g_szDropTypeStrings, ARRAYSIZE(g_szDropTypeStrings) );
  3693. // Creation data
  3694. m_bHidden = m_pKVItem->GetInt( "hidden", 0 ) != 0;
  3695. m_bShouldShowInArmory = m_pKVItem->GetInt( "show_in_armory", 0 ) != 0;
  3696. m_bBaseItem = m_pKVItem->GetInt( "baseitem", 0 ) != 0;
  3697. m_bDefaultSlotItem = m_pKVItem->GetInt( "default_slot_item", 0 ) != 0;
  3698. m_pszItemLogClassname = m_pKVItem->GetString( "item_logname", NULL );
  3699. m_pszItemIconClassname = m_pKVItem->GetString( "item_iconname", NULL );
  3700. #if ECONITEM_DATABASE_AUDIT_TABLES_FEATURE
  3701. m_pszDatabaseAuditTable = m_pKVItem->GetString( "database_audit_table", NULL );
  3702. #endif
  3703. m_bImported = m_pKVItem->FindKey( "import_from" ) != NULL;
  3704. m_bOnePerAccountCDKEY = m_pKVItem->GetInt( "one_per_account_cdkey", 0 ) != 0;
  3705. m_pszParticleFile = m_pKVItem->GetString( "particle_file", NULL );
  3706. m_pszParticleSnapshotFile = m_pKVItem->GetString( "particle_snapshot", NULL );
  3707. m_pszLootListName = m_pKVItem->GetString( "loot_list_name", NULL );
  3708. // Stickers
  3709. KeyValues *pStickerDataKV = m_pKVItem->FindKey( "stickers" );
  3710. if ( pStickerDataKV )
  3711. {
  3712. FOR_EACH_SUBKEY( pStickerDataKV, pStickerModelEntry )
  3713. {
  3714. StickerData_t *pStickerData = &m_vStickerModels[ m_vStickerModels.AddToTail() ];
  3715. const char *pStickerModelPath = pStickerModelEntry->GetString( "viewmodel_geometry" );
  3716. V_strcpy_safe( pStickerData->m_szStickerModelPath, pStickerModelPath );
  3717. const char *pStickerMaterialPath = pStickerModelEntry->GetString( "viewmodel_material" );
  3718. V_strcpy_safe( pStickerData->m_szStickerMaterialPath, pStickerMaterialPath );
  3719. const char *pStickerWorldModelProjectionPosition = pStickerModelEntry->GetString( "worldmodel_decal_pos" );
  3720. if ( pStickerWorldModelProjectionPosition[0] != 0 )
  3721. {
  3722. float flX = 0.0f, flY = 0.0f, flZ = 0.0f;
  3723. sscanf( pStickerWorldModelProjectionPosition, "%f %f %f", &flX, &flY, &flZ );
  3724. pStickerData->m_vWorldModelProjectionStart = Vector( flX, flY, flZ );
  3725. }
  3726. const char *pStickerWorldModelProjectionEnd = pStickerModelEntry->GetString( "worldmodel_decal_end" );
  3727. if ( pStickerWorldModelProjectionEnd[0] != 0 )
  3728. {
  3729. float flX = 0.0f, flY = 0.0f, flZ = 0.0f;
  3730. sscanf( pStickerWorldModelProjectionEnd, "%f %f %f", &flX, &flY, &flZ );
  3731. pStickerData->m_vWorldModelProjectionEnd = Vector( flX, flY, flZ );
  3732. }
  3733. else
  3734. {
  3735. pStickerData->m_vWorldModelProjectionEnd = Vector(-10,0,0) + pStickerData->m_vWorldModelProjectionStart;
  3736. }
  3737. V_strcpy_safe( pStickerData->m_szStickerBoneParentName, pStickerModelEntry->GetString( "worldmodel_decal_bone", "ValveBiped.weapon_bone" ) );
  3738. }
  3739. }
  3740. // Tool data
  3741. m_pTool = NULL;
  3742. KeyValues *pToolDataKV = m_pKVItem->FindKey( "tool" );
  3743. if ( pToolDataKV )
  3744. {
  3745. const char *pszType = pToolDataKV->GetString( "type", NULL );
  3746. SCHEMA_INIT_CHECK( pszType, CFmtStr( "Tool '%s' missing required type.", m_pKVItem->GetName() ) );
  3747. // Common-to-all-tools settings.
  3748. const char *pszUseString = pToolDataKV->GetString( "use_string", NULL );
  3749. const char *pszUsageRestriction = pToolDataKV->GetString( "restriction", NULL );
  3750. KeyValues *pToolUsageKV = pToolDataKV->FindKey( "usage" );
  3751. // Common-to-all-tools usage capability flags.
  3752. item_capabilities_t usageCapabilities = (item_capabilities_t)ITEM_CAP_TOOL_DEFAULT;
  3753. KeyValues *pToolUsageCapsKV = pToolDataKV->FindKey( "usage_capabilities" );
  3754. if ( pToolUsageCapsKV )
  3755. {
  3756. KeyValues *pEntry = pToolUsageCapsKV->GetFirstSubKey();
  3757. while ( pEntry )
  3758. {
  3759. ParseCapability( usageCapabilities, pEntry );
  3760. pEntry = pEntry->GetNextKey();
  3761. }
  3762. }
  3763. m_pTool = pschema.CreateEconToolImpl( pszType, pszUseString, pszUsageRestriction, usageCapabilities, pToolUsageKV );
  3764. SCHEMA_INIT_CHECK( m_pTool, CFmtStr( "Unable to create tool implementation for '%s', of type '%s'.", m_pKVItem->GetName(), pszType ) );
  3765. }
  3766. // capabilities
  3767. m_iCapabilities = (item_capabilities_t)ITEM_CAP_DEFAULT;
  3768. KeyValues *pCapsKV = m_pKVItem->FindKey( "capabilities" );
  3769. if ( pCapsKV )
  3770. {
  3771. KeyValues *pEntry = pCapsKV->GetFirstSubKey();
  3772. while ( pEntry )
  3773. {
  3774. ParseCapability( m_iCapabilities, pEntry );
  3775. pEntry = pEntry->GetNextKey();
  3776. }
  3777. }
  3778. // cache item map names
  3779. m_pszArmoryRemap = m_pKVItem->GetString( "armory_remap", NULL );
  3780. m_pszStoreRemap = m_pKVItem->GetString( "store_remap", NULL );
  3781. // Don't bother parsing visual data on the GC, it's unused.
  3782. BInitVisualBlockFromKV( m_pKVItem, pschema, pVecErrors );
  3783. // Calculate our equip region mask.
  3784. {
  3785. m_unEquipRegionMask = 0;
  3786. m_unEquipRegionConflictMask = 0;
  3787. // Our equip region will come from one of two places -- either we have an "equip_regions" (plural) section,
  3788. // in which case we have any number of regions specified; or we have an "equip_region" (singular) section
  3789. // which will have one and exactly one region. If we have "equip_regions" (plural), we ignore whatever is
  3790. // in "equip_region" (singular).
  3791. //
  3792. // Yes, this is sort of dumb.
  3793. CUtlVector<const char *> vecEquipRegionNames;
  3794. KeyValues *pKVMultiEquipRegions = m_pKVItem->FindKey( "equip_regions" ),
  3795. *pKVSingleEquipRegion = m_pKVItem->FindKey( "equip_region" );
  3796. // Maybe we have multiple entries?
  3797. if ( pKVMultiEquipRegions )
  3798. {
  3799. for ( KeyValues *pKVRegion = pKVMultiEquipRegions->GetFirstSubKey(); pKVRegion; pKVRegion = pKVRegion->GetNextKey() )
  3800. {
  3801. vecEquipRegionNames.AddToTail( pKVRegion->GetName() );
  3802. }
  3803. }
  3804. // This is our one-and-only-one equip region.
  3805. else if ( pKVSingleEquipRegion )
  3806. {
  3807. const char *pEquipRegionName = pKVSingleEquipRegion->GetString( (const char *)NULL, NULL );
  3808. if ( pEquipRegionName )
  3809. {
  3810. vecEquipRegionNames.AddToTail( pEquipRegionName );
  3811. }
  3812. }
  3813. // For each of our regions, add to our conflict mask both ourself and all the regions
  3814. // that we conflict with.
  3815. FOR_EACH_VEC( vecEquipRegionNames, i )
  3816. {
  3817. const char *pszEquipRegionName = vecEquipRegionNames[i];
  3818. equip_region_mask_t unThisRegionMask = pschema.GetEquipRegionMaskByName( pszEquipRegionName );
  3819. SCHEMA_INIT_CHECK(
  3820. unThisRegionMask != 0,
  3821. CFmtStr( "Item definition %s: Unable to find equip region mask for region named \"%s\"", GetDefinitionName(), vecEquipRegionNames[i] ) );
  3822. m_unEquipRegionMask |= pschema.GetEquipRegionBitMaskByName( pszEquipRegionName );
  3823. m_unEquipRegionConflictMask |= unThisRegionMask;
  3824. }
  3825. }
  3826. // Parse the static attributes for this definition
  3827. char const *szStaticAttributesSubkeyNames[] = { "attributes"
  3828. };
  3829. for ( int iStaticAttrGroup = 0; iStaticAttrGroup < Q_ARRAYSIZE( szStaticAttributesSubkeyNames ); ++ iStaticAttrGroup )
  3830. {
  3831. KeyValues *kvStaticAttrGroup = m_pKVItem->FindKey( szStaticAttributesSubkeyNames[iStaticAttrGroup] );
  3832. if ( !kvStaticAttrGroup ) continue;
  3833. FOR_EACH_SUBKEY( kvStaticAttrGroup, pKVKey )
  3834. {
  3835. static_attrib_t staticAttrib;
  3836. SCHEMA_INIT_SUBSTEP( staticAttrib.BInitFromKV_SingleLine( GetDefinitionName(), pKVKey, pVecErrors ) );
  3837. m_vecStaticAttributes.AddToTail( staticAttrib );
  3838. }
  3839. }
  3840. return SCHEMA_INIT_SUCCESS();
  3841. }
  3842. bool static_attrib_t::BInitFromKV_MultiLine( const char *pszContext, KeyValues *pKVAttribute, CUtlVector<CUtlString> *pVecErrors )
  3843. {
  3844. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinitionByName( pKVAttribute->GetName() );
  3845. SCHEMA_INIT_CHECK(
  3846. NULL != pAttrDef,
  3847. CFmtStr( "Context '%s': Attribute \"%s\" in \"attributes\" did not match any attribute definitions", pszContext, pKVAttribute->GetName() ) );
  3848. if ( pAttrDef )
  3849. {
  3850. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  3851. Assert( pAttrType );
  3852. iDefIndex = pAttrDef->GetDefinitionIndex();
  3853. const char *pszValue = pKVAttribute->GetString( "value", NULL );
  3854. const bool bSuccessfullyLoadedValue = pAttrType->BConvertStringToEconAttributeValue( pAttrDef, pszValue, &m_value );
  3855. SCHEMA_INIT_CHECK(
  3856. bSuccessfullyLoadedValue,
  3857. CFmtStr( "Context '%s': Attribute \"%s\" could not parse value \"%s\"!", pszContext, pKVAttribute->GetName(), pszValue ? pszValue : "(null)" ) );
  3858. m_bForceGCToGenerate = pKVAttribute->GetBool( "force_gc_to_generate" );
  3859. }
  3860. return SCHEMA_INIT_SUCCESS();
  3861. }
  3862. bool static_attrib_t::BInitFromKV_SingleLine( const char *pszContext, KeyValues *pKVAttribute, CUtlVector<CUtlString> *pVecErrors )
  3863. {
  3864. if ( pKVAttribute->GetFirstSubKey() )
  3865. {
  3866. return BInitFromKV_MultiLine( pszContext, pKVAttribute, pVecErrors );
  3867. }
  3868. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinitionByName( pKVAttribute->GetName() );
  3869. SCHEMA_INIT_CHECK(
  3870. NULL != pAttrDef,
  3871. CFmtStr( "Context '%s': Attribute \"%s\" in \"attributes\" did not match any attribute definitions", pszContext, pKVAttribute->GetName() ) );
  3872. if ( pAttrDef )
  3873. {
  3874. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  3875. Assert( pAttrType );
  3876. iDefIndex = pAttrDef->GetDefinitionIndex();
  3877. const char *pszValue = pKVAttribute->GetString();
  3878. const bool bSuccessfullyLoadedValue = pAttrType->BConvertStringToEconAttributeValue( pAttrDef, pszValue, &m_value );
  3879. SCHEMA_INIT_CHECK(
  3880. bSuccessfullyLoadedValue,
  3881. CFmtStr( "Context '%s': Attribute \"%s\" could not parse value \"%s\"!", pszContext, pKVAttribute->GetName(), pszValue ? pszValue : "(null)" ) );
  3882. m_bForceGCToGenerate = false;
  3883. }
  3884. return SCHEMA_INIT_SUCCESS();
  3885. }
  3886. bool CEconItemDefinition::BInitItemMappings( CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors )
  3887. {
  3888. // Armory remapping
  3889. if ( m_pszArmoryRemap && m_pszArmoryRemap[0] )
  3890. {
  3891. const CEconItemDefinition *pDef = pschema.GetItemDefinitionByName( m_pszArmoryRemap );
  3892. if ( pDef )
  3893. {
  3894. m_iArmoryRemap = pDef->GetDefinitionIndex();
  3895. }
  3896. SCHEMA_INIT_CHECK(
  3897. pDef != NULL,
  3898. CFmtStr( "Item %s: Armory remap definition \"%s\" was not found", m_pszItemBaseName, m_pszArmoryRemap ) );
  3899. }
  3900. // Store remapping
  3901. if ( m_pszStoreRemap && m_pszStoreRemap[0] )
  3902. {
  3903. const CEconItemDefinition *pDef = pschema.GetItemDefinitionByName( m_pszStoreRemap );
  3904. if ( pDef )
  3905. {
  3906. m_iStoreRemap = pDef->GetDefinitionIndex();
  3907. }
  3908. SCHEMA_INIT_CHECK(
  3909. pDef != NULL,
  3910. CFmtStr( "Item %s: Store remap definition \"%s\" was not found", m_pszItemBaseName, m_pszStoreRemap ) );
  3911. }
  3912. return SCHEMA_INIT_SUCCESS();
  3913. }
  3914. //-----------------------------------------------------------------------------
  3915. KeyValues* CEconItemDefinition::GetPortraitKVForModel( const char* pszModelName ) const
  3916. {
  3917. if ( !m_pPortraitsKV )
  3918. return NULL;
  3919. return m_pPortraitsKV->FindKey( pszModelName );
  3920. }
  3921. void CEconItemDefinition::AddItemSet( int nIndex )
  3922. {
  3923. if ( m_iItemSets.Find( nIndex ) != m_iItemSets.InvalidIndex() )
  3924. return;
  3925. m_iItemSets.AddToTail( nIndex );
  3926. }
  3927. const CUtlVector< int >& CEconItemDefinition::GetItemSets( void ) const
  3928. {
  3929. return m_iItemSets;
  3930. }
  3931. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  3932. //-----------------------------------------------------------------------------
  3933. // Purpose:
  3934. //-----------------------------------------------------------------------------
  3935. attachedparticlesystem_t *CEconItemDefinition::GetAttachedParticleData( int iIdx ) const
  3936. {
  3937. if ( !GetAssetInfo() )
  3938. return NULL;
  3939. Assert( iIdx < GetAssetInfo()->m_AttachedParticles.Count() );
  3940. if ( iIdx >= GetAssetInfo()->m_AttachedParticles.Count() )
  3941. return NULL;
  3942. int iParticleIndex = GetAssetInfo()->m_AttachedParticles[iIdx].m_iParticleIndex;
  3943. return ItemSystem()->GetItemSchema()->GetAttributeControlledParticleSystemByIndex( iParticleIndex );
  3944. }
  3945. bool CEconItemDefinition::IsAttachedParticleDataValidForStyle( int iIdx, int nStyle ) const
  3946. {
  3947. Assert( iIdx < GetAssetInfo()->m_AttachedParticles.Count() );
  3948. if ( iIdx >= GetAssetInfo()->m_AttachedParticles.Count() )
  3949. return false;
  3950. return ( GetAssetInfo()->m_AttachedParticles[iIdx].m_nStyle == nStyle );
  3951. }
  3952. #endif // #if defined(CLIENT_DLL) || defined(GAME_DLL)
  3953. //-----------------------------------------------------------------------------
  3954. // Purpose: Generate and return a random level according to whatever leveling
  3955. // curve this definition uses.
  3956. //-----------------------------------------------------------------------------
  3957. uint32 CEconItemDefinition::RollItemLevel( void ) const
  3958. {
  3959. return RandomInt( GetMinLevel(), GetMaxLevel() );
  3960. }
  3961. //-----------------------------------------------------------------------------
  3962. // Purpose:
  3963. //-----------------------------------------------------------------------------
  3964. void CEconItemDefinition::IterateAttributes( IEconItemAttributeIterator *pIterator ) const
  3965. {
  3966. FOR_EACH_VEC( GetStaticAttributes(), i )
  3967. {
  3968. const static_attrib_t& staticAttrib = GetStaticAttributes()[i];
  3969. // we skip over static attributes that the GC will turn into dynamic attributes because otherwise we'll have
  3970. // the appearance of iterating over them twice; for clients these attributes won't even make it into the
  3971. // list
  3972. if ( staticAttrib.m_bForceGCToGenerate )
  3973. continue;
  3974. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( staticAttrib.iDefIndex );
  3975. if ( !pAttrDef )
  3976. continue;
  3977. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  3978. Assert( pAttrType );
  3979. if ( !pAttrType->OnIterateAttributeValue( pIterator, pAttrDef, staticAttrib.m_value ) )
  3980. return;
  3981. }
  3982. }
  3983. const char *CEconItemDefinition::GetFirstSaleDate() const
  3984. {
  3985. return GetRawDefinition()->GetString( "first_sale_date", "1970/01/01" );
  3986. }
  3987. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  3988. //-----------------------------------------------------------------------------
  3989. // Purpose:
  3990. //-----------------------------------------------------------------------------
  3991. Activity CEconItemDefinition::GetActivityOverride( Activity baseAct ) const
  3992. {
  3993. int iAnims = GetNumAnimations();
  3994. for ( int i = 0; i < iAnims; i++ )
  3995. {
  3996. animation_on_wearable_t *pData = GetAnimationData( i );
  3997. if ( !pData )
  3998. continue;
  3999. if ( pData->iActivity == kActivityLookup_Unknown )
  4000. {
  4001. pData->iActivity = ActivityList_IndexForName( pData->pszActivity );
  4002. }
  4003. if ( pData->iActivity == baseAct )
  4004. {
  4005. if ( pData->iReplacement == kActivityLookup_Unknown )
  4006. {
  4007. pData->iReplacement = ActivityList_IndexForName( pData->pszReplacement );
  4008. }
  4009. if ( pData->iReplacement > 0 )
  4010. {
  4011. return (Activity) pData->iReplacement;
  4012. }
  4013. }
  4014. }
  4015. return baseAct;
  4016. }
  4017. //-----------------------------------------------------------------------------
  4018. // Purpose:
  4019. //-----------------------------------------------------------------------------
  4020. const char *CEconItemDefinition::GetReplacementForActivityOverride( Activity baseAct ) const
  4021. {
  4022. int iAnims = GetNumAnimations();
  4023. for ( int i = 0; i < iAnims; i++ )
  4024. {
  4025. animation_on_wearable_t *pData = GetAnimationData( i );
  4026. if ( pData->iActivity == kActivityLookup_Unknown )
  4027. {
  4028. pData->iActivity = ActivityList_IndexForName( pData->pszActivity );
  4029. }
  4030. if ( pData && pData->iActivity == baseAct )
  4031. {
  4032. if ( CEconItemSchema::GetRandomStream().RandomFloat() < pData->flFrequency )
  4033. return pData->pszReplacement;
  4034. }
  4035. }
  4036. return NULL;
  4037. }
  4038. //-----------------------------------------------------------------------------
  4039. // Purpose:
  4040. //-----------------------------------------------------------------------------
  4041. const char *CEconItemDefinition::GetReplacementSound( const char* pszSoundName ) const
  4042. {
  4043. int iSounds = GetNumSounds();
  4044. for ( int i=0; i<iSounds; i++ )
  4045. {
  4046. sound_on_wearable_t *pData = GetSoundData( i );
  4047. if ( pData && FStrEq( pData->pszSound, pszSoundName ) )
  4048. return pData->pszReplacement;
  4049. }
  4050. return NULL;
  4051. }
  4052. //-----------------------------------------------------------------------------
  4053. // Purpose:
  4054. //-----------------------------------------------------------------------------
  4055. const char *CEconItemDefinition::GetReplacementParticleEffect( const char* pszParticleName ) const
  4056. {
  4057. int iParticles = GetNumParticles();
  4058. for ( int i=0; i<iParticles; i++ )
  4059. {
  4060. particle_on_wearable_t *pData = GetParticleData( i );
  4061. if ( pData && FStrEq( pData->pszParticle, pszParticleName ) )
  4062. return pData->pszReplacement;
  4063. }
  4064. return NULL;
  4065. }
  4066. //-----------------------------------------------------------------------------
  4067. // Purpose:
  4068. //-----------------------------------------------------------------------------
  4069. const char *CEconItemDefinition::GetReplacementParticleSnapshot( const char* pszParticleSnapshotName ) const
  4070. {
  4071. int iSnapshots = GetNumParticleSnapshots();
  4072. for ( int i=0; i<iSnapshots; i++ )
  4073. {
  4074. particlesnapshot_on_wearable_t *pData = GetParticleSnapshotData( i );
  4075. if ( pData && FStrEq( pData->pszParticleSnapshot, pszParticleSnapshotName ) )
  4076. return pData->pszReplacement;
  4077. }
  4078. return NULL;
  4079. }
  4080. //-----------------------------------------------------------------------------
  4081. // Purpose:
  4082. //-----------------------------------------------------------------------------
  4083. bool CEconItemDefinition::GetReplacementControlPoint( int nIndex, const char* pszParticleName, int &nOutputCP, Vector &vecCPValue ) const
  4084. {
  4085. int iParticles = GetNumParticleControlPoints();
  4086. if ( nIndex < iParticles )
  4087. {
  4088. particle_control_point_on_wearable_t *pData = GetParticleControlPointData( nIndex );
  4089. if ( pData && FStrEq( pData->pszParticle, pszParticleName ) )
  4090. {
  4091. nOutputCP = pData->nParticleControlPoint;
  4092. vecCPValue = pData->vecCPValue;
  4093. return true;
  4094. }
  4095. }
  4096. return false;
  4097. }
  4098. //-----------------------------------------------------------------------------
  4099. // Purpose: Returns true if the content for this item view should be streamed. If false,
  4100. // it should be preloaded.
  4101. //-----------------------------------------------------------------------------
  4102. // DO NOT MERGE THIS CONSOLE VARIABLE TO REL WE SHOULD NOT SHIP THIS OH GOD
  4103. #define ITEM_ENABLE_DYNAMIC_LOADING true
  4104. //ConVar item_enable_dynamic_loading( "item_enable_dynamic_loading", "1", FCVAR_REPLICATED, "Enable/disable dynamic streaming of econ content." );
  4105. bool CEconItemDefinition::IsContentStreamable() const
  4106. {
  4107. if ( !BLoadOnDemand() )
  4108. return false;
  4109. return ITEM_ENABLE_DYNAMIC_LOADING;
  4110. }
  4111. #endif // defined(CLIENT_DLL) || defined(GAME_DLL)
  4112. //-----------------------------------------------------------------------------
  4113. // Purpose:
  4114. //-----------------------------------------------------------------------------
  4115. const char* CEconItemDefinition::GetAlternateIcon( int iAlternateIcon ) const
  4116. {
  4117. int iIdx = m_pMapAlternateIcons->Find( iAlternateIcon );
  4118. if ( !m_pMapAlternateIcons->IsValidIndex( iIdx ) )
  4119. return NULL;
  4120. else
  4121. return m_pMapAlternateIcons->Element( iIdx );
  4122. }
  4123. //-----------------------------------------------------------------------------
  4124. // Purpose:
  4125. // Sticker model paths
  4126. //-----------------------------------------------------------------------------
  4127. const int CEconItemDefinition::GetNumSupportedStickerSlots() const
  4128. {
  4129. return m_vStickerModels.Count();
  4130. }
  4131. const char *CEconItemDefinition::GetStickerSlotModelBySlotIndex( uint32 index ) const
  4132. {
  4133. return m_vStickerModels[index].m_szStickerModelPath;
  4134. }
  4135. const Vector &CEconItemDefinition::GetStickerSlotWorldProjectionStartBySlotIndex( uint32 index ) const
  4136. {
  4137. return m_vStickerModels[index].m_vWorldModelProjectionStart;
  4138. }
  4139. const Vector &CEconItemDefinition::GetStickerSlotWorldProjectionEndBySlotIndex( uint32 index ) const
  4140. {
  4141. return m_vStickerModels[index].m_vWorldModelProjectionEnd;
  4142. }
  4143. const char *CEconItemDefinition::GetStickerWorldModelBoneParentNameBySlotIndex( uint32 index ) const
  4144. {
  4145. return m_vStickerModels[index].m_szStickerBoneParentName;
  4146. }
  4147. const char *CEconItemDefinition::GetStickerSlotMaterialBySlotIndex( uint32 index ) const
  4148. {
  4149. return m_vStickerModels[index].m_szStickerMaterialPath;
  4150. }
  4151. RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetIconDisplayModel, "icon display model", m_pszWorldDisplayModel );
  4152. RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetBuyMenuDisplayModel, "buymenu display model", m_pszWorldDisplayModel );
  4153. RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetPedestalDisplayModel, "pedestal display model", m_pszBaseDisplayModel );
  4154. RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetMagazineModel, "magazine model", NULL );
  4155. RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetUidModel, "uid model", "models/weapons/uid.mdl" );
  4156. RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetScopeLensMaskModel, "aimsight lens mask", NULL );
  4157. const char *CEconItemDefinition::GetStatTrakModelByType( uint32 nType ) const
  4158. {
  4159. const kill_eater_score_type_t *pScoreType = GetItemSchema()->FindKillEaterScoreType( nType );
  4160. if ( !pScoreType )
  4161. {
  4162. pScoreType = GetItemSchema()->FindKillEaterScoreType( 0 );
  4163. }
  4164. if ( !pScoreType )
  4165. return NULL;
  4166. CSchemaAttributeDefHandle pAttrib_StatTrakModel( pScoreType->m_pszModelAttributeString );
  4167. const char *pchStatTrakModel = NULL;
  4168. FindAttribute_UnsafeBitwiseCast< CAttribute_String >( this, pAttrib_StatTrakModel, &pchStatTrakModel );
  4169. return pchStatTrakModel;
  4170. }
  4171. //-----------------------------------------------------------------------------
  4172. // Purpose: Constructor
  4173. //-----------------------------------------------------------------------------
  4174. CTimedItemRewardDefinition::CTimedItemRewardDefinition( void )
  4175. : m_unMinFreq( 0 ),
  4176. m_unMaxFreq( UINT_MAX ),
  4177. m_rtForcedBaselineAdjustment( 0 ),
  4178. m_rtForcedLastDropTimeAdjustment( 0 ),
  4179. m_unHoursInRewardPeriod( 0 ),
  4180. m_unHoursBetweenDropsRealtime( 0 ),
  4181. m_unPointsPerHourOverplayed( 0 ),
  4182. m_flChance( 0.0f )
  4183. {
  4184. }
  4185. //-----------------------------------------------------------------------------
  4186. // Purpose: Copy constructor
  4187. //-----------------------------------------------------------------------------
  4188. CTimedItemRewardDefinition::CTimedItemRewardDefinition( const CTimedItemRewardDefinition &that )
  4189. {
  4190. (*this) = that;
  4191. }
  4192. //-----------------------------------------------------------------------------
  4193. // Purpose: Operator=
  4194. //-----------------------------------------------------------------------------
  4195. CTimedItemRewardDefinition &CTimedItemRewardDefinition::operator=( const CTimedItemRewardDefinition &rhs )
  4196. {
  4197. m_unMinFreq = rhs.m_unMinFreq;
  4198. m_unMaxFreq = rhs.m_unMaxFreq;
  4199. m_rtForcedBaselineAdjustment = rhs.m_rtForcedBaselineAdjustment;
  4200. m_rtForcedLastDropTimeAdjustment = rhs.m_rtForcedLastDropTimeAdjustment;
  4201. m_unHoursInRewardPeriod = rhs.m_unHoursInRewardPeriod;
  4202. m_unHoursBetweenDropsRealtime = rhs.m_unHoursBetweenDropsRealtime;
  4203. m_unPointsPerHourOverplayed = rhs.m_unPointsPerHourOverplayed;
  4204. m_arrTotalPointsBasedOnHoursPlayed.RemoveAll();
  4205. m_arrTotalPointsBasedOnHoursPlayed.EnsureCapacity( rhs.m_arrTotalPointsBasedOnHoursPlayed.Count() );
  4206. m_arrTotalPointsBasedOnHoursPlayed.AddMultipleToTail( rhs.m_arrTotalPointsBasedOnHoursPlayed.Count(), rhs.m_arrTotalPointsBasedOnHoursPlayed.Base() );
  4207. m_criteria = rhs.m_criteria;
  4208. m_arrLootLists.CopyArray( rhs.m_arrLootLists.Base(), rhs.m_arrLootLists.Count() );
  4209. m_flChance = rhs.m_flChance;
  4210. return *this;
  4211. }
  4212. CTimedItemRewardDefinition::~CTimedItemRewardDefinition()
  4213. {
  4214. m_arrDynamicLootLists.PurgeAndDeleteElements();
  4215. }
  4216. //-----------------------------------------------------------------------------
  4217. // Purpose: Initialize the attribute definition
  4218. // Input: pKVTimedReward - The KeyValues representation of the timed reward
  4219. // schema - The overall item schema
  4220. // pVecErrors - An optional vector that will contain error messages if
  4221. // the init fails.
  4222. // Output: True if initialization succeeded, false otherwise
  4223. //-----------------------------------------------------------------------------
  4224. bool CTimedItemRewardDefinition::BInitFromKV( KeyValues *pKVTimedReward, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  4225. {
  4226. // Parse the basic values
  4227. m_flChance = pKVTimedReward->GetFloat( "pctChance" );
  4228. #ifdef DOTA_DLL
  4229. m_unMinFreq = pKVTimedReward->GetInt( "value_min", 0 );
  4230. m_unMaxFreq = pKVTimedReward->GetInt( "value_max", UINT_MAX );
  4231. // Check required fields
  4232. SCHEMA_INIT_CHECK(
  4233. NULL != pKVTimedReward->FindKey( "value_min" ),
  4234. CFmtStr( "Time reward %s: Missing required field \"value_min\"", pKVTimedReward->GetName() ) );
  4235. SCHEMA_INIT_CHECK(
  4236. NULL != pKVTimedReward->FindKey( "value_max" ),
  4237. CFmtStr( "Time reward %s: Missing required field \"value_max\"", pKVTimedReward->GetName() ) );
  4238. #endif
  4239. //
  4240. // Parse the basic values
  4241. //
  4242. SCHEMA_INIT_CHECK(
  4243. NULL != pKVTimedReward->FindKey( "force_baseline_timestamp" ),
  4244. CFmtStr( "Time reward %s: Missing required field \"force_baseline_timestamp\"", pKVTimedReward->GetName() ) );
  4245. m_rtForcedBaselineAdjustment = pKVTimedReward->GetInt( "force_baseline_timestamp" );
  4246. m_rtForcedLastDropTimeAdjustment = 0;
  4247. if ( pKVTimedReward->FindKey( "force_lastdrop_timestamp" ) )
  4248. m_rtForcedLastDropTimeAdjustment = pKVTimedReward->GetInt( "force_lastdrop_timestamp" );
  4249. m_unHoursInRewardPeriod = pKVTimedReward->GetInt( "period_hours", 0 );
  4250. SCHEMA_INIT_CHECK(
  4251. NULL != pKVTimedReward->FindKey( "period_hours" ),
  4252. CFmtStr( "Time reward %s: Missing required field \"period_hours\"", pKVTimedReward->GetName() ) );
  4253. SCHEMA_INIT_CHECK(
  4254. m_unHoursInRewardPeriod > 0,
  4255. CFmtStr( "Time reward %s: Required field \"period_hours\" has invalid value", pKVTimedReward->GetName() ) );
  4256. m_unHoursBetweenDropsRealtime = pKVTimedReward->GetInt( "drop_interval_hours", 0 );
  4257. SCHEMA_INIT_CHECK(
  4258. NULL != pKVTimedReward->FindKey( "drop_interval_hours" ),
  4259. CFmtStr( "Time reward %s: Missing required field \"drop_interval_hours\"", pKVTimedReward->GetName() ) );
  4260. SCHEMA_INIT_CHECK(
  4261. m_unHoursBetweenDropsRealtime >= 0,
  4262. CFmtStr( "Time reward %s: Required field \"drop_interval_hours\" has invalid value", pKVTimedReward->GetName() ) );
  4263. SCHEMA_INIT_CHECK(
  4264. NULL != pKVTimedReward->FindKey( "points_progression_hourly" ),
  4265. CFmtStr( "Time reward %s: Missing required field \"points_progression_hourly\"", pKVTimedReward->GetName() ) );
  4266. uint32 numPointsAccumulatedValidation = 0;
  4267. for ( KeyValues *kvPoints = pKVTimedReward->FindKey( "points_progression_hourly" )->GetFirstSubKey(); kvPoints; kvPoints = kvPoints->GetNextKey() )
  4268. {
  4269. uint32 numPoints = kvPoints->GetInt();
  4270. SCHEMA_INIT_CHECK(
  4271. numPoints > numPointsAccumulatedValidation,
  4272. CFmtStr( "Time reward %s: Required field \"points_progression_hourly\" defines invalid points after %u hours", pKVTimedReward->GetName(), m_arrTotalPointsBasedOnHoursPlayed.Count() ) );
  4273. m_arrTotalPointsBasedOnHoursPlayed.AddToTail( numPoints );
  4274. numPointsAccumulatedValidation = numPoints;
  4275. }
  4276. SCHEMA_INIT_CHECK(
  4277. NULL != pKVTimedReward->FindKey( "points_per_additional_hour" ),
  4278. CFmtStr( "Time reward %s: Missing required field \"points_per_additional_hour\"", pKVTimedReward->GetName() ) );
  4279. m_unPointsPerHourOverplayed = pKVTimedReward->GetInt( "points_per_additional_hour", 0 );
  4280. SCHEMA_INIT_CHECK(
  4281. NULL != pKVTimedReward->FindKey( "period_points_rollover" ),
  4282. CFmtStr( "Time reward %s: Missing required field \"period_points_rollover\"", pKVTimedReward->GetName() ) );
  4283. m_unPointsPerPeriodRollover = pKVTimedReward->GetInt( "period_points_rollover", 0 );
  4284. SCHEMA_INIT_CHECK(
  4285. m_unPointsPerPeriodRollover >= numPointsAccumulatedValidation,
  4286. CFmtStr( "Time reward %s: Required field \"period_points_rollover\" defines invalid points after %u hours", pKVTimedReward->GetName(), m_arrTotalPointsBasedOnHoursPlayed.Count() ) );
  4287. SCHEMA_INIT_CHECK(
  4288. NULL != pKVTimedReward->FindKey( "pctChance" ),
  4289. CFmtStr( "Time reward %s: Missing required field \"pctChance\"", pKVTimedReward->GetName() ) );
  4290. SCHEMA_INIT_CHECK(
  4291. ( m_flChance >= 0.0f ) && ( m_flChance <= 1.0f ),
  4292. CFmtStr( "Time reward %s: Required field \"pctChance\" has invalid value", pKVTimedReward->GetName() ) );
  4293. // Parse the criteria or loot_list
  4294. if ( pKVTimedReward->FindKey( "criteria" ) )
  4295. {
  4296. bool bCriteriaOK = m_criteria.BInitFromKV( pKVTimedReward->FindKey( "criteria", true ), pschema );
  4297. SCHEMA_INIT_CHECK( bCriteriaOK, CFmtStr( "Time Reward %s: Invalid criteria", pKVTimedReward->GetName() ) );
  4298. // Check to make sure this criteria doesn't filter to an empty set
  4299. if ( bCriteriaOK )
  4300. {
  4301. bool bMatch = false;
  4302. FOR_EACH_MAP_FAST( pschema.GetItemDefinitionMap(), i )
  4303. {
  4304. if ( m_criteria.BEvaluate( pschema.GetItemDefinitionMap()[i], pschema ) )
  4305. {
  4306. bMatch = true;
  4307. break;
  4308. }
  4309. }
  4310. SCHEMA_INIT_CHECK(
  4311. bMatch,
  4312. CFmtStr( "Time Reward %s: No items match the critera", pKVTimedReward->GetName() ) );
  4313. }
  4314. }
  4315. const char *pszLootList = pKVTimedReward->GetString("loot_list", NULL);
  4316. if ( pszLootList && pszLootList[0] )
  4317. {
  4318. CUtlVector< char * > arrLootListsTokens;
  4319. V_SplitString( pszLootList, ",", arrLootListsTokens );
  4320. SCHEMA_INIT_CHECK(
  4321. arrLootListsTokens.Count() != 0,
  4322. CFmtStr( "Time Reward %s: loot_list (%s) has zero elements", pKVTimedReward->GetName(), pszLootList ) );
  4323. FOR_EACH_VEC( arrLootListsTokens, iLootListToken )
  4324. {
  4325. const CEconLootListDefinition *pLootList = pschema.GetLootListByName( arrLootListsTokens[iLootListToken] );
  4326. // Make sure the item index is correct because we use this index as a reference
  4327. SCHEMA_INIT_CHECK(
  4328. NULL != pLootList,
  4329. CFmtStr( "Time Reward %s: loot_list (%s) element '%s' does not exist", pKVTimedReward->GetName(), pszLootList, arrLootListsTokens[iLootListToken] ) );
  4330. if ( pLootList )
  4331. m_arrLootLists.AddToTail( pLootList );
  4332. }
  4333. arrLootListsTokens.PurgeAndDeleteElements();
  4334. }
  4335. return SCHEMA_INIT_SUCCESS();
  4336. }
  4337. float CTimedItemRewardDefinition::GetChance( void ) const
  4338. {
  4339. return m_flChance;
  4340. }
  4341. const CSchemaAttributeDefHandle& GetCampaignAttributeDefHandle( int nCampaignID, ECampaignAttributeType type )
  4342. {
  4343. static CSchemaAttributeDefHandle* pAttrCampaignCompletionBitfield[ g_nNumCampaigns + 1 ];
  4344. static CSchemaAttributeDefHandle* pAttrCampaignLastCompletedQuest[ g_nNumCampaigns + 1 ];
  4345. static bool s_bCampaignAttrInitialized = false;
  4346. static bool s_bCampaignAttrValid = false;
  4347. if ( !s_bCampaignAttrInitialized )
  4348. {
  4349. s_bCampaignAttrInitialized = true;
  4350. s_bCampaignAttrValid = true;
  4351. for ( int j = 1; j <= g_nNumCampaigns; ++j )
  4352. {
  4353. pAttrCampaignCompletionBitfield[ j ]= new CSchemaAttributeDefHandle( ( new CFmtStr( "campaign %d completion bitfield", j ) )->Access() );
  4354. if ( !( *pAttrCampaignCompletionBitfield[ j ] ) )
  4355. s_bCampaignAttrValid = false;
  4356. pAttrCampaignLastCompletedQuest[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "campaign %d last completed quest", j ) )->Access() );
  4357. if ( !( *pAttrCampaignLastCompletedQuest[ j ] ) )
  4358. s_bCampaignAttrValid = false;
  4359. }
  4360. }
  4361. if ( ( nCampaignID <= 0 ) || ( nCampaignID > g_nNumCampaigns ) )
  4362. {
  4363. Assert( 0 );
  4364. Warning( "Attempting to lookup campaign %d, which does not exist. Verify that the code recognizes that campaigns are 1-based.", nCampaignID );
  4365. }
  4366. else if ( s_bCampaignAttrValid )
  4367. {
  4368. switch( type )
  4369. {
  4370. case k_ECampaignAttribute_CompletionBitfield:
  4371. return *pAttrCampaignCompletionBitfield[ nCampaignID ];
  4372. case k_ECampaignAttribute_LastCompletedQuest:
  4373. return *pAttrCampaignLastCompletedQuest[ nCampaignID ];
  4374. default:
  4375. Assert( 0 );
  4376. Warning( "Attempting to lookup campaign %d type %d, which does not exist.", nCampaignID, type );
  4377. break;
  4378. }
  4379. }
  4380. static CSchemaAttributeDefHandle s_DummyAttr( "undefined" );
  4381. return s_DummyAttr;
  4382. }
  4383. const CSchemaAttributeDefHandle& GetStickerAttributeDefHandle( int attrNum, EStickerAttributeType type )
  4384. {
  4385. // Attributes of the schema validation
  4386. static bool s_bStickerAttrsSetup = false;
  4387. static bool s_bStickerAttrsValid = false;
  4388. static CSchemaAttributeDefHandle* pAttrStickerSlotID[ g_nNumStickerAttrs ];
  4389. static CSchemaAttributeDefHandle* pAttrStickerSlotWear[ g_nNumStickerAttrs ];
  4390. static CSchemaAttributeDefHandle* pAttrStickerSlotScale[ g_nNumStickerAttrs ];
  4391. static CSchemaAttributeDefHandle* pAttrStickerSlotRotation[ g_nNumStickerAttrs ];
  4392. if ( !s_bStickerAttrsSetup )
  4393. {
  4394. s_bStickerAttrsSetup = true;
  4395. s_bStickerAttrsValid = true;
  4396. for ( int j = 0; j < g_nNumStickerAttrs; ++j )
  4397. {
  4398. pAttrStickerSlotID[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "sticker slot %d id", j ) )->Access() );
  4399. if ( !( *pAttrStickerSlotID[ j ] ) ) s_bStickerAttrsValid = false;
  4400. pAttrStickerSlotWear[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "sticker slot %d wear", j ) )->Access() );
  4401. if ( !( *pAttrStickerSlotWear[ j ] ) ) s_bStickerAttrsValid = false;
  4402. pAttrStickerSlotScale[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "sticker slot %d scale", j ) )->Access() );
  4403. if ( !( *pAttrStickerSlotScale[ j ] ) ) s_bStickerAttrsValid = false;
  4404. pAttrStickerSlotRotation[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "sticker slot %d rotation", j ) )->Access() );
  4405. if ( !( *pAttrStickerSlotRotation[ j ] ) ) s_bStickerAttrsValid = false;
  4406. }
  4407. }
  4408. if ( s_bStickerAttrsValid )
  4409. {
  4410. switch ( type )
  4411. {
  4412. case k_EStickerAttribute_ID:
  4413. return *pAttrStickerSlotID[ attrNum ];
  4414. break;
  4415. case k_EStickerAttribute_Wear:
  4416. return *pAttrStickerSlotWear[ attrNum ];
  4417. break;
  4418. case k_EStickerAttribute_Scale:
  4419. return *pAttrStickerSlotScale[ attrNum ];
  4420. break;
  4421. case k_EStickerAttribute_Rotation:
  4422. return *pAttrStickerSlotRotation[ attrNum ];
  4423. break;
  4424. default:
  4425. Assert( 0 );
  4426. break;
  4427. };
  4428. }
  4429. static CSchemaAttributeDefHandle s_DummyAttr( "undefined" );
  4430. return s_DummyAttr;
  4431. }
  4432. bool CStickerKit::InitFromKeyValues( KeyValues *pKVEntry, const CStickerKit *pDefault, CUtlVector<CUtlString> *pVecErrors /*= NULL*/ )
  4433. {
  4434. sName.Set( pKVEntry->GetString( "name", pDefault->sName.String() ) );
  4435. sDescriptionString.Set( pKVEntry->GetString( "description_string", pDefault->sDescriptionString.String() ) );
  4436. sItemName.Set( pKVEntry->GetString( "item_name", pDefault->sItemName.String() ) );
  4437. uint8 ucRarity;
  4438. GetItemSchema()->BGetItemRarityFromName( pKVEntry->GetString( "item_rarity", "common" ), &ucRarity );
  4439. nRarity = ucRarity;
  4440. sMaterialPath.Set( pKVEntry->GetString( "sticker_material", pDefault->sMaterialPath.String() ) );
  4441. if ( *sMaterialPath.String() )
  4442. {
  4443. sMaterialPathNoDrips.Set( pKVEntry->GetString( "sticker_material_nodrips", CFmtStr( "%s_nodrips", sMaterialPath.String() ) ) );
  4444. }
  4445. m_strInventoryImage.Set( pKVEntry->GetString( "image_inventory", CFmtStr( "econ/stickers/%s", sMaterialPath.String() ) ) );
  4446. SetIconURLSmall( GetInventoryImage() );
  4447. SetIconURLLarge( CFmtStr( "%s_large", GetInventoryImage() ) );
  4448. //
  4449. // gc_generation_settings
  4450. //
  4451. flRotateStart = pKVEntry->GetFloat( "gc_generation_settings/rotate_start", pDefault->flRotateStart );
  4452. flRotateEnd = pKVEntry->GetFloat( "gc_generation_settings/rotate_end", pDefault->flRotateEnd );
  4453. SCHEMA_INIT_CHECK(
  4454. ( flRotateStart >= -360.0f ) && ( flRotateStart <= flRotateEnd ) && ( flRotateEnd <= 360.0f ),
  4455. CFmtStr( "Sticker kit '%s' rotate range is not valid %f:%f", pKVEntry->GetName(), flRotateStart, flRotateEnd ) );
  4456. flScaleMin = pKVEntry->GetFloat( "gc_generation_settings/scale_min", pDefault->flScaleMin );
  4457. flScaleMax = pKVEntry->GetFloat( "gc_generation_settings/scale_max", pDefault->flScaleMax );
  4458. SCHEMA_INIT_CHECK( // Scale is in UV space so max is a smaller float, min is a larger float
  4459. ( flScaleMax > 0.0f ) && ( flScaleMax <= flScaleMin ),
  4460. CFmtStr( "Sticker kit '%s' scale range is not valid %f:%f", pKVEntry->GetName(), flScaleMax, flScaleMin ) );
  4461. flWearMin = pKVEntry->GetFloat( "gc_generation_settings/wear_min", pDefault->flWearMin );
  4462. flWearMax = pKVEntry->GetFloat( "gc_generation_settings/wear_max", pDefault->flWearMax );
  4463. SCHEMA_INIT_CHECK(
  4464. ( flWearMin >= 0.0f ) && ( flWearMin <= flWearMax ) && ( flWearMax <= 1.0f ),
  4465. CFmtStr( "Sticker kit '%s' wear range is not valid %f:%f", pKVEntry->GetName(), flWearMin, flWearMax ) );
  4466. m_nEventID = pKVEntry->GetInt( "tournament_event_id", pDefault->m_nEventID );
  4467. m_nEventTeamID = pKVEntry->GetInt( "tournament_team_id", pDefault->m_nEventTeamID );
  4468. m_nPlayerID = pKVEntry->GetInt( "tournament_player_id", pDefault->m_nPlayerID );
  4469. m_pKVItem = pKVEntry ? pKVEntry->MakeCopy() : NULL;
  4470. return true;
  4471. }
  4472. bool CStickerList::InitFromKeyValues( KeyValues *pKVEntry, CUtlVector<CUtlString> *pVecErrors /*= NULL*/ )
  4473. {
  4474. flWearMin = pKVEntry->GetFloat( "gc_generation_settings/wear_min", 0.0f );
  4475. flWearMax = pKVEntry->GetFloat( "gc_generation_settings/wear_max", 1.0f );
  4476. SCHEMA_INIT_CHECK(
  4477. ( flWearMin >= 0.0f ) && ( flWearMin <= flWearMax ) && ( flWearMax <= 1.0f ),
  4478. CFmtStr( "Sticker list '%s' wear range is not valid %f:%f", pKVEntry->GetName(), flWearMin, flWearMax ) );
  4479. flTotalWeight = 0.0f;
  4480. float flLargestMinWear = 0.0f;
  4481. float flSmallestMaxWear = 1.0f;
  4482. for ( KeyValues *kvChild = pKVEntry->GetFirstValue(); kvChild; kvChild = kvChild->GetNextValue() )
  4483. {
  4484. char const *szName = kvChild->GetName();
  4485. const CStickerKit *pStickerKit = GetItemSchema()->GetStickerKitDefinitionByName( szName );
  4486. const CStickerList *pStickerList = GetItemSchema()->GetStickerListDefinitionByName( szName );
  4487. SCHEMA_INIT_CHECK(
  4488. ( pStickerKit || pStickerList ) && !( pStickerKit && pStickerList ),
  4489. CFmtStr( "Sticker list '%s' refers to an unknown stickerkit or stickerlist '%s'", pKVEntry->GetName(), szName ) );
  4490. float flWeight = kvChild->GetFloat();
  4491. SCHEMA_INIT_CHECK(
  4492. ( flWeight > 0.0f ),
  4493. CFmtStr( "Sticker list '%s' has invalid weight %f", pKVEntry->GetName(), flWeight ) );
  4494. if ( pStickerKit )
  4495. {
  4496. flLargestMinWear = MAX( flLargestMinWear, pStickerKit->flWearMin );
  4497. flSmallestMaxWear = MIN( flSmallestMaxWear, pStickerKit->flWearMax );
  4498. }
  4499. if ( pStickerList )
  4500. {
  4501. flLargestMinWear = MAX( flLargestMinWear, pStickerList->flWearMin );
  4502. flSmallestMaxWear = MIN( flSmallestMaxWear, pStickerList->flWearMax );
  4503. }
  4504. // add the entry
  4505. sticker_list_entry_t entry;
  4506. entry.pKit = pStickerKit;
  4507. entry.pList = pStickerList;
  4508. entry.flWeight = flWeight;
  4509. arrElements.AddToTail( entry );
  4510. flTotalWeight += entry.flWeight;
  4511. }
  4512. SCHEMA_INIT_CHECK(
  4513. ( arrElements.Count() > 0 ),
  4514. CFmtStr( "Sticker list '%s' has no elements", pKVEntry->GetName() ) );
  4515. SCHEMA_INIT_CHECK(
  4516. ( flTotalWeight > 0.0f ),
  4517. CFmtStr( "Sticker list '%s' has no elements weight", pKVEntry->GetName() ) );
  4518. SCHEMA_INIT_CHECK(
  4519. ( flSmallestMaxWear >= flWearMin ),
  4520. CFmtStr( "Sticker list '%s' wear_min %f exceeds elements max range wear %f", pKVEntry->GetName(), flWearMin, flSmallestMaxWear ) );
  4521. SCHEMA_INIT_CHECK(
  4522. ( flLargestMinWear <= flWearMax ),
  4523. CFmtStr( "Sticker list '%s' wear_max %f below elements min range wear %f", pKVEntry->GetName(), flWearMax, flLargestMinWear ) );
  4524. return true;
  4525. }
  4526. bool CStickerKit::GenerateStickerApplicationInfo( CAppliedStickerInfo_t *pInfo ) const
  4527. {
  4528. if ( !pInfo )
  4529. return false;
  4530. pInfo->flWearMin = MAX( pInfo->flWearMin, flWearMin );
  4531. pInfo->flWearMax = MIN( pInfo->flWearMax, flWearMax );
  4532. if ( pInfo->flWearMin > pInfo->flWearMax )
  4533. return false;
  4534. pInfo->nID = nID;
  4535. pInfo->flScale = CEconItemSchema::GetRandomStream().RandomFloat( flScaleMax, flScaleMin );
  4536. pInfo->flRotate = CEconItemSchema::GetRandomStream().RandomFloat( flRotateStart, flRotateEnd );
  4537. return true;
  4538. }
  4539. bool CStickerList::GenerateStickerApplicationInfo( CAppliedStickerInfo_t *pInfo ) const
  4540. {
  4541. if ( !pInfo )
  4542. return false;
  4543. // Generate a random roll into our list
  4544. float flRand = CEconItemSchema::GetRandomStream().RandomFloat(0.f, 1.f) * flTotalWeight;
  4545. float flAccum = 0.f;
  4546. for ( int i=0; i<arrElements.Count(); ++i )
  4547. {
  4548. flAccum += arrElements[i].flWeight;
  4549. if ( flRand <= flAccum )
  4550. {
  4551. const sticker_list_entry_t &entry = arrElements[i];
  4552. pInfo->flWearMin = MAX( pInfo->flWearMin, flWearMin );
  4553. pInfo->flWearMax = MIN( pInfo->flWearMax, flWearMax );
  4554. if ( pInfo->flWearMin > pInfo->flWearMax )
  4555. return false;
  4556. if ( entry.pList )
  4557. return entry.pList->GenerateStickerApplicationInfo( pInfo );
  4558. if ( entry.pKit )
  4559. return entry.pKit->GenerateStickerApplicationInfo( pInfo );
  4560. return false;
  4561. }
  4562. }
  4563. return false;
  4564. }
  4565. bool CPaintKit::InitFromKeyValues( KeyValues *pKVEntry, const CPaintKit *pDefault, bool bHandleAbsolutePaths )
  4566. {
  4567. sName.Set( pKVEntry->GetString( "name", pDefault->sName.String() ) );
  4568. sDescriptionString.Set( pKVEntry->GetString( "description_string", pDefault->sDescriptionString.String() ) );
  4569. sDescriptionTag.Set( pKVEntry->GetString( "description_tag", pDefault->sDescriptionTag.String() ) );
  4570. nRarity = 1; // rarities set in the paint_kits_rarity block
  4571. // Character paint kit fields
  4572. sVmtPath.Set( pKVEntry->GetString( "vmt_path", pDefault->sVmtPath.String() ) );
  4573. if ( kvVmtOverrides != nullptr )
  4574. {
  4575. kvVmtOverrides->deleteThis();
  4576. kvVmtOverrides = nullptr;
  4577. }
  4578. KeyValues* pVmtOverrides = pKVEntry->FindKey( "vmt_overrides" );
  4579. if ( pVmtOverrides != nullptr )
  4580. {
  4581. kvVmtOverrides = new KeyValues( "CustomCharacter" );
  4582. kvVmtOverrides->MergeFrom( pVmtOverrides, KeyValues::MERGE_KV_UPDATE );
  4583. }
  4584. // Regular paint kit fields
  4585. if (bHandleAbsolutePaths)
  4586. {
  4587. // this solution is less than ideal, it'll only work for windows drive paths (not network paths), and in
  4588. // order to make this better we need to change things down inside the material system / texture code.
  4589. // it's only used for the workshop preview con command right now.
  4590. const char* pPatternPath = pKVEntry->GetString( "pattern", pDefault->sPattern.String() );
  4591. #ifdef PLATFORM_WINDOWS
  4592. int nLength = V_strlen( pPatternPath );
  4593. if ( nLength > 2 && !( pPatternPath[0] == '/' && pPatternPath[1] == '/' && pPatternPath[2] != '/' ) && V_IsAbsolutePath( pPatternPath ) )
  4594. {
  4595. sPattern.Format( "//./%s", pPatternPath );
  4596. }
  4597. else
  4598. #endif
  4599. {
  4600. sPattern.Set( pPatternPath );
  4601. }
  4602. }
  4603. else
  4604. {
  4605. sPattern.Set( pKVEntry->GetString( "pattern", pDefault->sPattern.String() ) );
  4606. }
  4607. sLogoMaterial.Set( pKVEntry->GetString( "logo_material", pDefault->sLogoMaterial.String() ) );
  4608. nStyle = pKVEntry->GetInt( "style", pDefault->nStyle );
  4609. flWearDefault = pKVEntry->GetFloat( "wear_default", pDefault->flWearDefault );
  4610. flWearRemapMin = pKVEntry->GetFloat( "wear_remap_min", pDefault->flWearRemapMin );
  4611. flWearRemapMax = pKVEntry->GetFloat( "wear_remap_max", pDefault->flWearRemapMax );
  4612. nFixedSeed = pKVEntry->GetInt( "seed", pDefault->nFixedSeed );
  4613. uchPhongExponent = pKVEntry->GetInt( "phongexponent", pDefault->uchPhongExponent );
  4614. uchPhongAlbedoBoost = pKVEntry->GetInt( "phongalbedoboost", static_cast< int >( pDefault->uchPhongAlbedoBoost ) - 1 ) + 1;
  4615. uchPhongIntensity = pKVEntry->GetInt( "phongintensity", pDefault->uchPhongIntensity );
  4616. flPatternScale = pKVEntry->GetFloat( "pattern_scale", pDefault->flPatternScale );
  4617. flPatternOffsetXStart = pKVEntry->GetFloat( "pattern_offset_x_start", pDefault->flPatternOffsetXStart );
  4618. flPatternOffsetXEnd = pKVEntry->GetFloat( "pattern_offset_x_end", pDefault->flPatternOffsetXEnd );
  4619. flPatternOffsetYStart = pKVEntry->GetFloat( "pattern_offset_y_start", pDefault->flPatternOffsetYStart );
  4620. flPatternOffsetYEnd = pKVEntry->GetFloat( "pattern_offset_y_end", pDefault->flPatternOffsetYEnd );
  4621. flPatternRotateStart = pKVEntry->GetFloat( "pattern_rotate_start", pDefault->flPatternRotateStart );
  4622. flPatternRotateEnd = pKVEntry->GetFloat( "pattern_rotate_end", pDefault->flPatternRotateEnd );
  4623. flLogoScale = pKVEntry->GetFloat( "logo_scale", pDefault->flLogoScale );
  4624. flLogoOffsetX = pKVEntry->GetFloat( "logo_offset_x", pDefault->flLogoOffsetX );
  4625. flLogoOffsetY = pKVEntry->GetFloat( "logo_offset_y", pDefault->flLogoOffsetY );
  4626. flLogoRotation = pKVEntry->GetFloat( "logo_rotation", pDefault->flLogoRotation );
  4627. bIgnoreWeaponSizeScale = pKVEntry->GetBool( "ignore_weapon_size_scale", pDefault->bIgnoreWeaponSizeScale );
  4628. nViewModelExponentOverrideSize = pKVEntry->GetInt( "view_model_exponent_override_size", pDefault->nViewModelExponentOverrideSize );
  4629. bOnlyFirstMaterial = pKVEntry->GetBool( "only_first_material", pDefault->bOnlyFirstMaterial );
  4630. char szColorName[ 16 ];
  4631. for ( int nColor = 0; nColor < CPaintKit::NUM_COLORS; ++nColor )
  4632. {
  4633. // Regular Colors
  4634. V_snprintf( szColorName, sizeof( szColorName ), "color%i", nColor );
  4635. KeyValues *pKVColor = pKVEntry->FindKey( szColorName );
  4636. if ( pKVColor )
  4637. {
  4638. const char *pchColor = pKVColor->GetString();
  4639. unsigned int cR, cG, cB;
  4640. sscanf( pchColor, "%u %u %u", &cR, &cG, &cB );
  4641. rgbaColor[ nColor ].SetColor( cR, cG, cB, 255 );
  4642. }
  4643. else
  4644. {
  4645. rgbaColor[ nColor ] = pDefault->rgbaColor[ nColor ];
  4646. }
  4647. // Logo Colors
  4648. V_snprintf( szColorName, sizeof( szColorName ), "logocolor%i", nColor );
  4649. pKVColor = pKVEntry->FindKey( szColorName );
  4650. if ( pKVColor )
  4651. {
  4652. const char *pchColor = pKVColor->GetString();
  4653. unsigned int cR, cG, cB;
  4654. sscanf( pchColor, "%u %u %u", &cR, &cG, &cB );
  4655. rgbaLogoColor[ nColor ].SetColor( cR, cG, cB, 255 );
  4656. }
  4657. else
  4658. {
  4659. rgbaLogoColor[ nColor ] = pDefault->rgbaLogoColor[ nColor ];
  4660. }
  4661. }
  4662. return true;
  4663. }
  4664. void CPaintKit::FillKeyValuesForWorkshop( KeyValues *pKVToFill ) const
  4665. {
  4666. pKVToFill->SetInt( "style", nStyle );
  4667. pKVToFill->SetString( "pattern", sPattern.String() );
  4668. char szColorName[ 16 ];
  4669. for ( int nColor = 0; nColor < CPaintKit::NUM_COLORS; ++nColor )
  4670. {
  4671. // Regular Colors
  4672. V_snprintf( szColorName, sizeof( szColorName ), "color%i", nColor );
  4673. pKVToFill->SetColor( szColorName, rgbaColor[ nColor ] );
  4674. }
  4675. pKVToFill->SetFloat( "pattern_scale", flPatternScale );
  4676. pKVToFill->SetFloat( "pattern_offset_x_start", flPatternOffsetXStart );
  4677. pKVToFill->SetFloat( "pattern_offset_x_end", flPatternOffsetXEnd );
  4678. pKVToFill->SetFloat( "pattern_offset_y_start", flPatternOffsetYStart );
  4679. pKVToFill->SetFloat( "pattern_offset_y_end", flPatternOffsetYEnd );
  4680. pKVToFill->SetFloat( "pattern_rotate_start", flPatternRotateStart );
  4681. pKVToFill->SetFloat( "pattern_rotate_end", flPatternRotateEnd );
  4682. pKVToFill->SetFloat( "wear_remap_min", flWearRemapMin );
  4683. pKVToFill->SetFloat( "wear_remap_max", flWearRemapMax );
  4684. pKVToFill->SetInt( "phongexponent", uchPhongExponent );
  4685. pKVToFill->SetInt( "phongalbedoboost", static_cast< int >( uchPhongAlbedoBoost ) - 1 );
  4686. pKVToFill->SetInt( "phongintensity", uchPhongIntensity );
  4687. pKVToFill->SetBool( "ignore_weapon_size_scale", bIgnoreWeaponSizeScale );
  4688. pKVToFill->SetInt( "view_model_exponent_override_size", nViewModelExponentOverrideSize );
  4689. pKVToFill->SetBool( "only_first_material", bOnlyFirstMaterial );
  4690. //pKVToFill->SetString( "logo_material", sLogoMaterial.String() );
  4691. //pKVToFill->SetFloat( "logo_scale", flLogoScale );
  4692. //pKVToFill->SetFloat( "logo_offset_x", flLogoOffsetX );
  4693. //pKVToFill->SetFloat( "logo_offset_y", flLogoOffsetY );
  4694. //pKVToFill->SetFloat( "logo_rotation", flLogoRotation );
  4695. //for ( int nColor = 0; nColor < CPaintKit::NUM_COLORS; ++nColor )
  4696. //{
  4697. // // Logo Colors
  4698. // V_snprintf( szColorName, sizeof( szColorName ), "logocolor%i", nColor );
  4699. // pKVToFill->SetColor( szColorName, rgbaLogoColor[ nColor ] );
  4700. //}
  4701. //pKVToFill->SetInt( "seed", nFixedSeed );
  4702. }
  4703. //-----------------------------------------------------------------------------
  4704. // Purpose: Adds a foreign item definition to local definition mapping for a
  4705. // foreign app
  4706. //-----------------------------------------------------------------------------
  4707. void CForeignAppImports::AddMapping( uint16 unForeignDefIndex, const CEconItemDefinition *pDefn )
  4708. {
  4709. m_mapDefinitions.InsertOrReplace( unForeignDefIndex, pDefn );
  4710. }
  4711. //-----------------------------------------------------------------------------
  4712. // Purpose: Adds a foreign item definition to local definition mapping for a
  4713. // foreign app
  4714. //-----------------------------------------------------------------------------
  4715. const CEconItemDefinition *CForeignAppImports::FindMapping( uint16 unForeignDefIndex ) const
  4716. {
  4717. int i = m_mapDefinitions.Find( unForeignDefIndex );
  4718. if( m_mapDefinitions.IsValidIndex( i ) )
  4719. return m_mapDefinitions[i];
  4720. else
  4721. return NULL;
  4722. }
  4723. //-----------------------------------------------------------------------------
  4724. // Purpose: Less function comparator for revolving loot lists map
  4725. //-----------------------------------------------------------------------------
  4726. static bool LLLessFunc( const int& e1, const int&e2 )
  4727. {
  4728. return e1 < e2;
  4729. }
  4730. //-----------------------------------------------------------------------------
  4731. // Purpose: Constructor
  4732. //-----------------------------------------------------------------------------
  4733. CEconItemSchema::CEconItemSchema( )
  4734. : m_unResetCount( 0 )
  4735. , m_pKVRawDefinition( NULL )
  4736. , m_unVersion( 0 )
  4737. , m_pDefaultItemDefinition( NULL )
  4738. , m_mapItemSets( DefLessFunc(const char*) )
  4739. , m_mapDefinitionPrefabs( DefLessFunc(const char*) )
  4740. , m_mapDefaultBodygroupState( DefLessFunc(const char*) )
  4741. , m_bSchemaParsingItems(false)
  4742. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  4743. , m_pDelayedSchemaData( NULL )
  4744. #endif
  4745. , m_mapKillEaterScoreTypes( DefLessFunc( unsigned int ) )
  4746. {
  4747. Reset();
  4748. }
  4749. //-----------------------------------------------------------------------------
  4750. // Purpose:
  4751. //-----------------------------------------------------------------------------
  4752. IEconTool *CEconItemSchema::CreateEconToolImpl( const char *pszToolType, const char *pszUseString, const char *pszUsageRestriction, item_capabilities_t unCapabilities, KeyValues *pUsageKV )
  4753. {
  4754. return nullptr;
  4755. }
  4756. //-----------------------------------------------------------------------------
  4757. // Purpose: Resets the schema to before BInit was called
  4758. //-----------------------------------------------------------------------------
  4759. void CEconItemSchema::Reset( void )
  4760. {
  4761. ++m_unResetCount;
  4762. m_unFirstValidClass = 0;
  4763. m_unLastValidClass = 0;
  4764. m_unFirstValidItemSlot = 0;
  4765. m_unLastValidItemSlot = 0;
  4766. m_unNumItemPresets = 0;
  4767. m_unMinLevel = 0;
  4768. m_unMaxLevel = 0;
  4769. m_nMaxValidGraffitiTintDefID = 0;
  4770. m_unSumQualityWeights = 0;
  4771. m_mapRarities.Purge();
  4772. m_mapSoundMaterials.Purge();
  4773. m_mapQualities.Purge();
  4774. m_mapItems.PurgeAndDeleteElements();
  4775. m_mapItemsSorted.Purge();
  4776. m_mapPaintKits.PurgeAndDeleteElements();
  4777. m_mapStickerKits.PurgeAndDeleteElements();
  4778. m_mapMusicDefs.PurgeAndDeleteElements();
  4779. m_dictStickerKits.Purge();
  4780. m_dictStickerLists.Purge();
  4781. m_mapAttributesContainer.PurgeAndDeleteElements();
  4782. FOR_EACH_VEC( m_vecAttributeTypes, i )
  4783. {
  4784. delete m_vecAttributeTypes[i].m_pAttrType;
  4785. }
  4786. m_vecAttributeTypes.Purge();
  4787. m_mapRecipes.Purge();
  4788. m_vecTimedRewards.Purge();
  4789. m_mapAlternateIcons.Purge();
  4790. m_mapItemSets.Purge();
  4791. m_dictLootLists.Purge();
  4792. m_mapAttributeControlledParticleSystems.Purge();
  4793. m_unVersion = 0;
  4794. if ( m_pKVRawDefinition )
  4795. {
  4796. m_pKVRawDefinition->deleteThis();
  4797. m_pKVRawDefinition = NULL;
  4798. }
  4799. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  4800. delete m_pDefaultItemDefinition;
  4801. m_pDefaultItemDefinition = NULL;
  4802. #endif
  4803. FOR_EACH_MAP_FAST( m_mapRecipes, i )
  4804. {
  4805. delete m_mapRecipes[i];
  4806. }
  4807. FOR_EACH_MAP_FAST( m_mapDefinitionPrefabs, i )
  4808. {
  4809. m_mapDefinitionPrefabs[i]->deleteThis();
  4810. }
  4811. m_mapDefinitionPrefabs.Purge();
  4812. m_vecEquipRegionsList.Purge();
  4813. // m_vecItemLevelingData.PurgeAndDeleteElements();
  4814. m_vecItemLevelingData.Purge();
  4815. m_RandomStream.SetSeed( 0 );
  4816. }
  4817. //-----------------------------------------------------------------------------
  4818. // Purpose: Operator=
  4819. //-----------------------------------------------------------------------------
  4820. CEconItemSchema &CEconItemSchema::operator=( CEconItemSchema &rhs )
  4821. {
  4822. Reset();
  4823. BInitSchema( rhs.m_pKVRawDefinition );
  4824. return *this;
  4825. }
  4826. #if defined( CLIENT_DLL )
  4827. #define MERGE_LIVE_PLAYERS_CODE 0
  4828. static void Helper_MergeKeyValuesUsingTemplate( KeyValues *kvInto, KeyValues *kvSrc, KeyValues *kvTemplate )
  4829. {
  4830. FOR_EACH_SUBKEY( kvTemplate, kvTemplateSubkey )
  4831. {
  4832. if ( kvTemplateSubkey->GetDataType() == KeyValues::TYPE_NONE )
  4833. {
  4834. // This is a nested subkey
  4835. if ( !V_strcmp( kvTemplateSubkey->GetName(), "*" ) )
  4836. {
  4837. // This is a wildcard subkey
  4838. FOR_EACH_TRUE_SUBKEY( kvSrc, kvWildcardSrcSubkey )
  4839. {
  4840. KeyValues *pSubInto = kvInto->FindKey( kvWildcardSrcSubkey->GetNameSymbol() );
  4841. if ( !pSubInto )
  4842. {
  4843. #if MERGE_LIVE_PLAYERS_CODE
  4844. kvInto->AddSubKey( pSubInto = kvWildcardSrcSubkey->MakeCopy() );
  4845. #else
  4846. kvInto->AddSubKey( pSubInto = new KeyValues( kvWildcardSrcSubkey->GetName() ) );
  4847. #endif
  4848. }
  4849. Helper_MergeKeyValuesUsingTemplate( pSubInto, kvWildcardSrcSubkey, kvTemplateSubkey );
  4850. }
  4851. }
  4852. else
  4853. {
  4854. // This is a direct dive into subkey
  4855. KeyValues *pSubInto = kvInto->FindKey( kvTemplateSubkey->GetNameSymbol() );
  4856. KeyValues *pSubSrc = kvSrc->FindKey( kvTemplateSubkey->GetNameSymbol() );
  4857. if ( pSubInto && pSubSrc )
  4858. Helper_MergeKeyValuesUsingTemplate( pSubInto, pSubSrc, kvTemplateSubkey );
  4859. }
  4860. }
  4861. else
  4862. {
  4863. // This is a direct value copy
  4864. if ( KeyValues *pSubSrc = kvSrc->FindKey( kvTemplateSubkey->GetNameSymbol() ) )
  4865. {
  4866. if ( KeyValues *pSubInto = kvInto->FindKey( kvTemplateSubkey->GetNameSymbol() ) )
  4867. {
  4868. // Cannot override an existing value!
  4869. Assert( !"Cannot override existing schema value" );
  4870. }
  4871. else
  4872. {
  4873. // Make a copy and append
  4874. kvInto->AddSubKey( pSubSrc->MakeCopy() );
  4875. }
  4876. }
  4877. }
  4878. }
  4879. }
  4880. #endif
  4881. //-----------------------------------------------------------------------------
  4882. // Initializes the schema, given KV filename
  4883. //-----------------------------------------------------------------------------
  4884. bool CEconItemSchema::BInit( const char *fileName, const char *pathID, CUtlVector<CUtlString> *pVecErrors /* = NULL */)
  4885. {
  4886. Reset();
  4887. m_pKVRawDefinition = new KeyValues( "CEconItemSchema" );
  4888. m_pKVRawDefinition->UsesEscapeSequences( true );
  4889. if ( !m_pKVRawDefinition->LoadFromFile( g_pFullFileSystem, fileName, pathID ) )
  4890. {
  4891. m_pKVRawDefinition->deleteThis();
  4892. m_pKVRawDefinition = NULL;
  4893. }
  4894. if ( m_pKVRawDefinition )
  4895. {
  4896. #if defined( CLIENT_DLL )
  4897. if ( KeyValues *kvLiveTemplate = m_pKVRawDefinition->FindKey( "items_game_live" ) )
  4898. {
  4899. // for client code we also load the live file to supplement certain portions of schema
  4900. char chLiveFilename[MAX_PATH];
  4901. V_strcpy_safe( chLiveFilename, fileName );
  4902. if ( char *chExt = V_strrchr( chLiveFilename, '.' ) )
  4903. {
  4904. char chSuffix[ 64 ] = {};
  4905. V_sprintf_safe( chSuffix, "_live%s", chExt );
  4906. *chExt = 0;
  4907. V_strcat_safe( chLiveFilename, chSuffix );
  4908. KeyValues *kvLive = new KeyValues( "CEconItemSchema" );
  4909. kvLive->UsesEscapeSequences( true );
  4910. if ( kvLive->LoadFromFile( g_pFullFileSystem, chLiveFilename, pathID ) )
  4911. {
  4912. Helper_MergeKeyValuesUsingTemplate( m_pKVRawDefinition, kvLive, kvLiveTemplate );
  4913. }
  4914. #if MERGE_LIVE_PLAYERS_CODE
  4915. if ( KeyValues *kvDump = m_pKVRawDefinition->FindKey( "pro_players" ) )
  4916. {
  4917. kvDump->SaveToFile( g_pFullFileSystem, "pro_players_merged.txt" );
  4918. }
  4919. #endif
  4920. kvLive->deleteThis();
  4921. kvLive = NULL;
  4922. }
  4923. }
  4924. #endif
  4925. return BInitSchema( m_pKVRawDefinition, pVecErrors );
  4926. }
  4927. else
  4928. {
  4929. #if !defined(CSTRIKE_DLL)
  4930. Warning( "No %s file found. May be unable to create items.\n", fileName );
  4931. #endif // CSTRIKE_DLL
  4932. return false;
  4933. }
  4934. }
  4935. //-----------------------------------------------------------------------------
  4936. // Initializes the schema, given KV in binary form
  4937. //-----------------------------------------------------------------------------
  4938. bool CEconItemSchema::BInitBinaryBuffer( CUtlBuffer &buffer, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  4939. {
  4940. Reset();
  4941. m_pKVRawDefinition = new KeyValues( "CEconItemSchema" );
  4942. m_pKVRawDefinition->UsesEscapeSequences( true );
  4943. if ( m_pKVRawDefinition->ReadAsBinary( buffer ) )
  4944. {
  4945. return BInitSchema( m_pKVRawDefinition, pVecErrors );
  4946. }
  4947. if ( pVecErrors )
  4948. {
  4949. pVecErrors->AddToTail( "Error parsing keyvalues" );
  4950. }
  4951. return false;
  4952. }
  4953. //-----------------------------------------------------------------------------
  4954. // Initializes the schema, given KV in text form
  4955. //-----------------------------------------------------------------------------
  4956. bool CEconItemSchema::BInitTextBuffer( CUtlBuffer &buffer, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  4957. {
  4958. Reset();
  4959. m_pKVRawDefinition = new KeyValues( "CEconItemSchema" );
  4960. m_pKVRawDefinition->UsesEscapeSequences( true );
  4961. if ( m_pKVRawDefinition->LoadFromBuffer( NULL, buffer ) )
  4962. {
  4963. return BInitSchema( m_pKVRawDefinition, pVecErrors );
  4964. }
  4965. if ( pVecErrors )
  4966. {
  4967. pVecErrors->AddToTail( "Error parsing keyvalues" );
  4968. }
  4969. return false;
  4970. }
  4971. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  4972. //-----------------------------------------------------------------------------
  4973. // Set up the buffer to use to reinitialize our schema next time we can do so safely.
  4974. //-----------------------------------------------------------------------------
  4975. void CEconItemSchema::MaybeInitFromBuffer( IDelayedSchemaData *pDelayedSchemaData )
  4976. {
  4977. // Use whatever our most current data block is.
  4978. if ( m_pDelayedSchemaData )
  4979. {
  4980. delete m_pDelayedSchemaData;
  4981. }
  4982. m_pDelayedSchemaData = pDelayedSchemaData;
  4983. #ifdef CLIENT_DLL
  4984. // If we aren't in a game we can parse immediately now.
  4985. if ( !engine->IsInGame() )
  4986. {
  4987. BInitFromDelayedBuffer();
  4988. }
  4989. #endif // CLIENT_DLL
  4990. }
  4991. //-----------------------------------------------------------------------------
  4992. // We're in a safe place to change the contents of the schema, so do so and clean
  4993. // up whatever memory we were using.
  4994. //-----------------------------------------------------------------------------
  4995. bool CEconItemSchema::BInitFromDelayedBuffer()
  4996. {
  4997. if ( !m_pDelayedSchemaData )
  4998. return true;
  4999. bool bSuccess = m_pDelayedSchemaData->InitializeSchema( this );
  5000. delete m_pDelayedSchemaData;
  5001. m_pDelayedSchemaData = NULL;
  5002. return bSuccess;
  5003. }
  5004. #endif // !GC_DLL
  5005. static void CalculateKeyValuesCRCRecursive( KeyValues *pKV, CRC32_t *crc, bool bIgnoreName = false )
  5006. {
  5007. // Hash in the key name in LOWERCASE. Keyvalues files are not deterministic due
  5008. // to the case insensitivity of the keys and the dependence on the existing
  5009. // state of the name table upon entry.
  5010. if ( !bIgnoreName )
  5011. {
  5012. const char *s = pKV->GetName();
  5013. for (;;)
  5014. {
  5015. unsigned char x = tolower(*s);
  5016. CRC32_ProcessBuffer( crc, &x, 1 ); // !SPEED! This is slow, but it works.
  5017. if (*s == '\0') break;
  5018. ++s;
  5019. }
  5020. }
  5021. // Now hash in value, depending on type
  5022. // !FIXME! This is not byte-order independent!
  5023. switch ( pKV->GetDataType() )
  5024. {
  5025. case KeyValues::TYPE_NONE:
  5026. {
  5027. FOR_EACH_SUBKEY( pKV, pChild )
  5028. {
  5029. CalculateKeyValuesCRCRecursive( pChild, crc );
  5030. }
  5031. break;
  5032. }
  5033. case KeyValues::TYPE_STRING:
  5034. {
  5035. const char *val = pKV->GetString();
  5036. CRC32_ProcessBuffer( crc, val, V_strlen(val)+1 );
  5037. break;
  5038. }
  5039. case KeyValues::TYPE_INT:
  5040. {
  5041. int val = pKV->GetInt();
  5042. CRC32_ProcessBuffer( crc, &val, sizeof(val) );
  5043. break;
  5044. }
  5045. case KeyValues::TYPE_UINT64:
  5046. {
  5047. uint64 val = pKV->GetUint64();
  5048. CRC32_ProcessBuffer( crc, &val, sizeof(val) );
  5049. break;
  5050. }
  5051. case KeyValues::TYPE_FLOAT:
  5052. {
  5053. float val = pKV->GetFloat();
  5054. CRC32_ProcessBuffer( crc, &val, sizeof(val) );
  5055. break;
  5056. }
  5057. case KeyValues::TYPE_COLOR:
  5058. {
  5059. int val = pKV->GetColor().GetRawColor();
  5060. CRC32_ProcessBuffer( crc, &val, sizeof(val) );
  5061. break;
  5062. }
  5063. default:
  5064. case KeyValues::TYPE_PTR:
  5065. case KeyValues::TYPE_WSTRING:
  5066. {
  5067. Assert( !"Unsupport data type!" );
  5068. break;
  5069. }
  5070. }
  5071. }
  5072. uint32 CEconItemSchema::CalculateKeyValuesVersion( KeyValues *pKV )
  5073. {
  5074. CRC32_t crc;
  5075. CRC32_Init( &crc );
  5076. // Calc CRC recursively. Ignore the very top-most
  5077. // key name, which isn't set consistently
  5078. CalculateKeyValuesCRCRecursive( pKV, &crc, true );
  5079. CRC32_Final( &crc );
  5080. return crc;
  5081. }
  5082. //-----------------------------------------------------------------------------
  5083. // Purpose: Initializes the schema
  5084. // Input: pKVRawDefinition - The raw KeyValues representation of the schema
  5085. // pVecErrors - An optional vector that will contain error messages if
  5086. // the init fails.
  5087. // Output: True if initialization succeeded, false otherwise
  5088. //-----------------------------------------------------------------------------
  5089. bool CEconItemSchema::BInitSchema( KeyValues *pKVRawDefinition, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  5090. {
  5091. #if !defined( GC_DLL )
  5092. m_unVersion = CalculateKeyValuesVersion( pKVRawDefinition );
  5093. #endif
  5094. m_unMinLevel = pKVRawDefinition->GetInt( "item_level_min", 0 );
  5095. m_unMaxLevel = pKVRawDefinition->GetInt( "item_level_max", 0 );
  5096. // Pre-parsed arrays in order of appearance for schema initialization
  5097. CUtlVector< KeyValues * > arrRootPrefabs;
  5098. CUtlVector< KeyValues * > arrRootClientLootLists;
  5099. CUtlVector< KeyValues * > arrRootRevolvingLootlists;
  5100. CUtlVector< KeyValues * > arrRootLootlists;
  5101. CUtlVector< KeyValues * > arrRootMiscLootlists;
  5102. CUtlVector< KeyValues * > arrRootStickerKits;
  5103. CUtlVector< KeyValues * > arrRootStickerLists;
  5104. CUtlVector< KeyValues * > arrRootPaintKits;
  5105. CUtlVector< KeyValues * > arrRootPaintKitsRarity;
  5106. CUtlVector< KeyValues * > arrRootItems;
  5107. CUtlVector< KeyValues * > arrRootItemSets;
  5108. CUtlVector< KeyValues * > arrRootMusicDefinitions;
  5109. FOR_EACH_TRUE_SUBKEY( pKVRawDefinition, kvRootSubKey )
  5110. {
  5111. if ( !V_stricmp( kvRootSubKey->GetName(), "prefabs" ) )
  5112. arrRootPrefabs.AddToTail( kvRootSubKey );
  5113. else if ( !V_stricmp( kvRootSubKey->GetName(), "loot_lists" ) )
  5114. arrRootLootlists.AddToTail( kvRootSubKey );
  5115. else if ( !V_stricmp( kvRootSubKey->GetName(), "client_loot_lists" ) )
  5116. arrRootClientLootLists.AddToTail( kvRootSubKey );
  5117. else if ( !V_stricmp( kvRootSubKey->GetName(), "revolving_loot_lists" ) )
  5118. arrRootRevolvingLootlists.AddToTail( kvRootSubKey );
  5119. else if ( !V_stricmp( kvRootSubKey->GetName(), "loot_lists_misc" ) )
  5120. arrRootMiscLootlists.AddToTail( kvRootSubKey );
  5121. else if ( !V_stricmp( kvRootSubKey->GetName(), "sticker_kits" ) )
  5122. arrRootStickerKits.AddToTail( kvRootSubKey );
  5123. else if ( !V_stricmp( kvRootSubKey->GetName(), "sticker_lists" ) )
  5124. arrRootStickerLists.AddToTail( kvRootSubKey );
  5125. else if ( !V_stricmp( kvRootSubKey->GetName(), "paint_kits" ) )
  5126. arrRootPaintKits.AddToTail( kvRootSubKey );
  5127. else if ( !V_stricmp( kvRootSubKey->GetName(), "paint_kits_rarity" ) )
  5128. arrRootPaintKitsRarity.AddToTail( kvRootSubKey );
  5129. else if ( !V_stricmp( kvRootSubKey->GetName(), "items" ) )
  5130. arrRootItems.AddToTail( kvRootSubKey );
  5131. else if ( !V_stricmp( kvRootSubKey->GetName(), "item_sets" ) )
  5132. arrRootItemSets.AddToTail( kvRootSubKey );
  5133. else if ( !V_stricmp( kvRootSubKey->GetName(), "music_definitions" ) )
  5134. arrRootMusicDefinitions.AddToTail( kvRootSubKey );
  5135. }
  5136. // Parse the prefabs block first so the prefabs will be populated in case anything else wants
  5137. // to use them later.
  5138. FOR_EACH_VEC( arrRootPrefabs, i )
  5139. {
  5140. SCHEMA_INIT_SUBSTEP( BInitDefinitionPrefabs( arrRootPrefabs[i], pVecErrors ) );
  5141. }
  5142. // Initialize the game info block
  5143. KeyValues *pKVGameInfo = pKVRawDefinition->FindKey( "game_info" );
  5144. SCHEMA_INIT_CHECK( NULL != pKVGameInfo, CFmtStr( "Required key \"game_info\" missing.\n" ) );
  5145. if ( NULL != pKVGameInfo )
  5146. {
  5147. SCHEMA_INIT_SUBSTEP( BInitGameInfo( pKVGameInfo, pVecErrors ) );
  5148. }
  5149. // Initialize our attribute types. We don't actually pull this data from the schema right now but it
  5150. // still makes sense to initialize it at this point.
  5151. SCHEMA_INIT_SUBSTEP( BInitAttributeTypes( pVecErrors ) );
  5152. // Initialize the rarity block
  5153. KeyValues *pKVRarities = pKVRawDefinition->FindKey( "rarities" );
  5154. SCHEMA_INIT_CHECK( NULL != pKVRarities, CFmtStr( "Required key \"rarities\" missing.\n" ) );
  5155. if ( NULL != pKVRarities )
  5156. {
  5157. SCHEMA_INIT_SUBSTEP( BInitRarities( pKVRarities, pVecErrors ) );
  5158. }
  5159. // Initialize the qualities block
  5160. KeyValues *pKVQualities = pKVRawDefinition->FindKey( "qualities" );
  5161. SCHEMA_INIT_CHECK( NULL != pKVQualities, CFmtStr( "Required key \"qualities\" missing.\n" ) );
  5162. if ( NULL != pKVQualities )
  5163. {
  5164. SCHEMA_INIT_SUBSTEP( BInitQualities( pKVQualities, pVecErrors ) );
  5165. }
  5166. // Initialize the colors block
  5167. KeyValues *pKVColors = pKVRawDefinition->FindKey( "colors" );
  5168. SCHEMA_INIT_CHECK( NULL != pKVColors, CFmtStr( "Required key \"colors\" missing.\n" ) );
  5169. if ( NULL != pKVColors )
  5170. {
  5171. SCHEMA_INIT_SUBSTEP( BInitColors( pKVColors, pVecErrors ) );
  5172. }
  5173. SCHEMA_INIT_SUBSTEP( BInitGraffitiTints( pKVRawDefinition->FindKey( "graffiti_tints" ), pVecErrors ) );
  5174. // Initialize the music block
  5175. FOR_EACH_VEC( arrRootMusicDefinitions, i )
  5176. {
  5177. SCHEMA_INIT_SUBSTEP( BInitMusicDefs( arrRootMusicDefinitions[i], pVecErrors ) );
  5178. }
  5179. // Initialize the attributes block
  5180. KeyValues *pKVAttributes = pKVRawDefinition->FindKey( "attributes" );
  5181. SCHEMA_INIT_CHECK( NULL != pKVAttributes, CFmtStr( "Required key \"attributes\" missing.\n" ) );
  5182. if ( NULL != pKVAttributes )
  5183. {
  5184. SCHEMA_INIT_SUBSTEP( BInitAttributes( pKVAttributes, pVecErrors ) );
  5185. }
  5186. // Initialize the sound materials block
  5187. KeyValues *pKVSoundMaterials = pKVRawDefinition->FindKey( "sound_materials" );
  5188. if ( NULL != pKVSoundMaterials )
  5189. {
  5190. SCHEMA_INIT_SUBSTEP( BInitSoundMaterials( pKVSoundMaterials, pVecErrors ) );
  5191. }
  5192. // Initialize the "equip_regions_list" block -- this is an optional block
  5193. KeyValues *pKVEquipRegions = pKVRawDefinition->FindKey( "equip_regions_list" );
  5194. if ( NULL != pKVEquipRegions )
  5195. {
  5196. SCHEMA_INIT_SUBSTEP( BInitEquipRegions( pKVEquipRegions, pVecErrors ) );
  5197. }
  5198. // Initialize the "equip_conflicts" block -- this is an optional block, though it doesn't
  5199. // make any sense and will probably fail internally if there is no corresponding "equip_regions"
  5200. // block as well
  5201. KeyValues *pKVEquipRegionConflicts = pKVRawDefinition->FindKey( "equip_conflicts" );
  5202. if ( NULL != pKVEquipRegionConflicts )
  5203. {
  5204. SCHEMA_INIT_SUBSTEP( BInitEquipRegionConflicts( pKVEquipRegionConflicts, pVecErrors ) );
  5205. }
  5206. // Do before items, so items can refer into it.
  5207. KeyValues *pKVParticleSystems = pKVRawDefinition->FindKey( "attribute_controlled_attached_particles" );
  5208. SCHEMA_INIT_SUBSTEP( BInitAttributeControlledParticleSystems( pKVParticleSystems, pVecErrors ) );
  5209. FOR_EACH_VEC( arrRootStickerKits, i )
  5210. {
  5211. SCHEMA_INIT_SUBSTEP( BInitStickerKits( arrRootStickerKits[i], pVecErrors ) );
  5212. }
  5213. FOR_EACH_VEC( arrRootPaintKits, i )
  5214. {
  5215. SCHEMA_INIT_SUBSTEP( BInitPaintKits( arrRootPaintKits[i], pVecErrors ) );
  5216. }
  5217. FOR_EACH_VEC( arrRootPaintKitsRarity, i )
  5218. {
  5219. SCHEMA_INIT_SUBSTEP( BInitPaintKitsRarity( arrRootPaintKitsRarity[i], pVecErrors ) );
  5220. }
  5221. // Initialize the items block
  5222. SCHEMA_INIT_CHECK( arrRootItems.Count(), CFmtStr( "Required key(s) \"items\" missing.\n" ) );
  5223. FOR_EACH_VEC( arrRootItems, i )
  5224. {
  5225. m_bSchemaParsingItems = true;
  5226. SCHEMA_INIT_SUBSTEP( BInitItems( arrRootItems[i], pVecErrors ) );
  5227. m_bSchemaParsingItems = false;
  5228. }
  5229. SCHEMA_INIT_SUBSTEP( BInitItemMappings( pVecErrors ) );
  5230. // Setup bundle links
  5231. SCHEMA_INIT_SUBSTEP( BInitBundles( pVecErrors ) );
  5232. // Setup payment rules.
  5233. SCHEMA_INIT_SUBSTEP( BInitPaymentRules( pVecErrors ) );
  5234. // Parse the item_sets block.
  5235. FOR_EACH_VEC( arrRootItemSets, i )
  5236. {
  5237. SCHEMA_INIT_SUBSTEP( BInitItemSets( arrRootItemSets[i], pVecErrors ) );
  5238. }
  5239. // Initialize the quest block
  5240. KeyValues *pKVQuestDefs = pKVRawDefinition->FindKey( "quest_definitions" );
  5241. SCHEMA_INIT_CHECK( NULL != pKVQuestDefs, CFmtStr( "Required key \"quest_definitions\" missing.\n" ) );
  5242. if ( NULL != pKVQuestDefs )
  5243. {
  5244. SCHEMA_INIT_SUBSTEP( BInitQuestDefs( pKVQuestDefs, pVecErrors ) );
  5245. }
  5246. // Initialize the quest event schedule block
  5247. SCHEMA_INIT_SUBSTEP( BInitQuestEvents( pKVRawDefinition->FindKey( "quest_schedule" ), pVecErrors ) );
  5248. // Initialize the campaign block
  5249. KeyValues *pKVCampaignDefs = pKVRawDefinition->FindKey( "campaign_definitions" );
  5250. SCHEMA_INIT_CHECK( NULL != pKVCampaignDefs, CFmtStr( "Required key \"campaign_definitions\" missing.\n" ) );
  5251. if ( NULL != pKVCampaignDefs )
  5252. {
  5253. SCHEMA_INIT_SUBSTEP( BInitCampaignDefs( pKVCampaignDefs, pVecErrors ) );
  5254. }
  5255. // Parse any recipes block
  5256. KeyValues *pKVRecipes = pKVRawDefinition->FindKey( "recipes" );
  5257. if ( NULL != pKVRecipes )
  5258. {
  5259. SCHEMA_INIT_SUBSTEP( BInitRecipes( pKVRecipes, pVecErrors ) );
  5260. }
  5261. // Parse alternate icons block.
  5262. KeyValues * pKVAlternateIcons = pKVRawDefinition->FindKey( "alternate_icons2" );
  5263. if ( NULL != pKVAlternateIcons )
  5264. {
  5265. SCHEMA_INIT_SUBSTEP( BInitAlternateIcons( pKVAlternateIcons, pVecErrors ) );
  5266. }
  5267. // Reset our loot lists.
  5268. m_dictLootLists.Purge();
  5269. // Parse the collection loot lists block
  5270. KeyValues *pKVQuestRewardLootLists = pKVRawDefinition->FindKey( "quest_reward_loot_lists" );
  5271. SCHEMA_INIT_SUBSTEP( BInitQuestRewardLootLists( pKVQuestRewardLootLists, pVecErrors ) );
  5272. // Parse the loot lists block (on the GC)
  5273. KeyValues *pKVRandomAttributeTemplates = pKVRawDefinition->FindKey( "random_attribute_templates" );
  5274. // Parse the client loot lists block (everywhere)
  5275. FOR_EACH_VEC( arrRootClientLootLists, i )
  5276. {
  5277. SCHEMA_INIT_SUBSTEP( BInitLootLists( arrRootClientLootLists[i], pKVRandomAttributeTemplates, pVecErrors, false ) );
  5278. }
  5279. // Parse the revolving loot lists block
  5280. FOR_EACH_VEC( arrRootRevolvingLootlists, i )
  5281. {
  5282. SCHEMA_INIT_SUBSTEP( BInitRevolvingLootLists( arrRootRevolvingLootlists[i], pVecErrors ) );
  5283. }
  5284. #if defined( CLIENT_DLL ) || defined( GAME_DLL )
  5285. KeyValues *pKVArmoryData = pKVRawDefinition->FindKey( "armory_data" );
  5286. if ( NULL != pKVArmoryData )
  5287. {
  5288. SCHEMA_INIT_SUBSTEP( BInitArmoryData( pKVArmoryData, pVecErrors ) );
  5289. }
  5290. #endif
  5291. // Parse any achievement rewards
  5292. KeyValues *pKVAchievementRewards = pKVRawDefinition->FindKey( "achievement_rewards" );
  5293. if ( NULL != pKVAchievementRewards )
  5294. {
  5295. SCHEMA_INIT_SUBSTEP( BInitAchievementRewards( pKVAchievementRewards, pVecErrors ) );
  5296. }
  5297. #ifdef TF_CLIENT_DLL
  5298. // Compute the number of concrete items, for each item, and cache for quick access
  5299. SCHEMA_INIT_SUBSTEP( BInitConcreteItemCounts( pVecErrors ) );
  5300. #endif // TF_CLIENT_DLL
  5301. // Parse the item levels block
  5302. KeyValues *pKVItemLevels = pKVRawDefinition->FindKey( "item_levels" );
  5303. SCHEMA_INIT_SUBSTEP( BInitItemLevels( pKVItemLevels, pVecErrors ) );
  5304. // Parse the kill eater score types
  5305. KeyValues *pKVKillEaterScoreTypes = pKVRawDefinition->FindKey( "kill_eater_score_types" );
  5306. SCHEMA_INIT_SUBSTEP( BInitKillEaterScoreTypes( pKVKillEaterScoreTypes, pVecErrors ) );
  5307. #ifdef CLIENT_DLL
  5308. // Load web resource references.
  5309. KeyValues* pKVWebResources = pKVRawDefinition->FindKey( "web_resources" );
  5310. SCHEMA_INIT_SUBSTEP( BInitWebResources( pKVWebResources, pVecErrors ) );
  5311. #endif
  5312. // Load web resource references.
  5313. KeyValues* pProPlayers = pKVRawDefinition->FindKey( "pro_players" );
  5314. SCHEMA_INIT_SUBSTEP( BInitProPlayers( pProPlayers, pVecErrors ) );
  5315. SCHEMA_INIT_SUBSTEP( BPostSchemaInitStartupChecks( pVecErrors ) );
  5316. return SCHEMA_INIT_SUCCESS();
  5317. }
  5318. //-----------------------------------------------------------------------------
  5319. // Purpose: Initializes the "game_info" section of the schema
  5320. //-----------------------------------------------------------------------------
  5321. bool CEconItemSchema::BInitGameInfo( KeyValues *pKVGameInfo, CUtlVector<CUtlString> *pVecErrors )
  5322. {
  5323. m_unFirstValidClass = pKVGameInfo->GetInt( "first_valid_class", 0 );
  5324. m_unLastValidClass = pKVGameInfo->GetInt( "last_valid_class", 0 );
  5325. SCHEMA_INIT_CHECK( 0 <= m_unFirstValidClass, CFmtStr( "First valid class must be greater or equal to 0." ) );
  5326. SCHEMA_INIT_CHECK( m_unFirstValidClass <= m_unLastValidClass, CFmtStr( "First valid class must be less than or equal to last valid class." ) );
  5327. m_unFirstValidItemSlot = pKVGameInfo->GetInt( "first_valid_item_slot", INVALID_EQUIPPED_SLOT );
  5328. m_unLastValidItemSlot = pKVGameInfo->GetInt( "last_valid_item_slot", INVALID_EQUIPPED_SLOT );
  5329. SCHEMA_INIT_CHECK( INVALID_EQUIPPED_SLOT != m_unFirstValidItemSlot, CFmtStr( "first_valid_item_slot not set!" ) );
  5330. SCHEMA_INIT_CHECK( INVALID_EQUIPPED_SLOT != m_unLastValidItemSlot, CFmtStr( "last_valid_item_slot not set!" ) );
  5331. SCHEMA_INIT_CHECK( m_unFirstValidItemSlot <= m_unLastValidItemSlot, CFmtStr( "First valid item slot must be less than or equal to last valid item slot." ) );
  5332. m_unNumItemPresets = pKVGameInfo->GetInt( "num_item_presets", -1 );
  5333. SCHEMA_INIT_CHECK( (uint32)-1 != m_unNumItemPresets, CFmtStr( "num_item_presets not set!" ) );
  5334. return SCHEMA_INIT_SUCCESS();
  5335. }
  5336. //-----------------------------------------------------------------------------
  5337. // Purpose:
  5338. //-----------------------------------------------------------------------------
  5339. bool CEconItemSchema::BInitAttributeTypes( CUtlVector<CUtlString> *pVecErrors )
  5340. {
  5341. FOR_EACH_VEC( m_vecAttributeTypes, i )
  5342. {
  5343. delete m_vecAttributeTypes[i].m_pAttrType;
  5344. }
  5345. m_vecAttributeTypes.Purge();
  5346. m_vecAttributeTypes.AddToTail( attr_type_t( NULL, new CSchemaAttributeType_Default ) );
  5347. m_vecAttributeTypes.AddToTail( attr_type_t( "uint32", new CSchemaAttributeType_Uint32 ) );
  5348. m_vecAttributeTypes.AddToTail( attr_type_t( "float", new CSchemaAttributeType_Float ) );
  5349. m_vecAttributeTypes.AddToTail( attr_type_t( "string", new CSchemaAttributeType_String ) );
  5350. m_vecAttributeTypes.AddToTail( attr_type_t( "vector", new CSchemaAttributeType_Vector ) );
  5351. return SCHEMA_INIT_SUCCESS();
  5352. }
  5353. //-----------------------------------------------------------------------------
  5354. // Purpose: Initializes the "prefabs" section of the schema
  5355. //-----------------------------------------------------------------------------
  5356. bool CEconItemSchema::BInitDefinitionPrefabs( KeyValues *pKVPrefabs, CUtlVector<CUtlString> *pVecErrors )
  5357. {
  5358. FOR_EACH_TRUE_SUBKEY( pKVPrefabs, pKVPrefab )
  5359. {
  5360. const char *pszPrefabName = pKVPrefab->GetName();
  5361. int nMapIndex = m_mapDefinitionPrefabs.Find( pszPrefabName );
  5362. // Make sure the item index is correct because we use this index as a reference
  5363. SCHEMA_INIT_CHECK(
  5364. !m_mapDefinitionPrefabs.IsValidIndex( nMapIndex ),
  5365. CFmtStr( "Duplicate prefab name (%s)", pszPrefabName ) );
  5366. m_mapDefinitionPrefabs.Insert( pszPrefabName, pKVPrefab->MakeCopy() );
  5367. }
  5368. return SCHEMA_INIT_SUCCESS();
  5369. }
  5370. //-----------------------------------------------------------------------------
  5371. // Purpose: Initializes the rarity section of the schema
  5372. //-----------------------------------------------------------------------------
  5373. bool CEconItemSchema::BInitRarities( KeyValues *pKVRarities, CUtlVector<CUtlString> *pVecErrors )
  5374. {
  5375. // initialize the item definitions
  5376. if ( NULL != pKVRarities )
  5377. {
  5378. FOR_EACH_TRUE_SUBKEY( pKVRarities, pKVRarity )
  5379. {
  5380. int nRarityIndex = pKVRarity->GetInt( "value" );
  5381. int nMapIndex = m_mapRarities.Find( nRarityIndex );
  5382. // Make sure the item index is correct because we use this index as a reference
  5383. SCHEMA_INIT_CHECK(
  5384. !m_mapRarities.IsValidIndex( nMapIndex ),
  5385. CFmtStr( "Duplicate rarity value (%d)", nRarityIndex ) );
  5386. nMapIndex = m_mapRarities.Insert( nRarityIndex );
  5387. SCHEMA_INIT_SUBSTEP( m_mapRarities[nMapIndex].BInitFromKV( pKVRarity, *this, pVecErrors ) );
  5388. }
  5389. }
  5390. return SCHEMA_INIT_SUCCESS();
  5391. }
  5392. //-----------------------------------------------------------------------------
  5393. // Purpose: Initializes the qualities section of the schema
  5394. // Input: pKVQualities - The qualities section of the KeyValues
  5395. // representation of the schema
  5396. // pVecErrors - An optional vector that will contain error messages if
  5397. // the init fails.
  5398. // Output: True if initialization succeeded, false otherwise
  5399. //-----------------------------------------------------------------------------
  5400. bool CEconItemSchema::BInitQualities( KeyValues *pKVQualities, CUtlVector<CUtlString> *pVecErrors )
  5401. {
  5402. // initialize the item definitions
  5403. if ( NULL != pKVQualities )
  5404. {
  5405. FOR_EACH_TRUE_SUBKEY( pKVQualities, pKVQuality )
  5406. {
  5407. int nQualityIndex = pKVQuality->GetInt( "value" );
  5408. int nMapIndex = m_mapQualities.Find( nQualityIndex );
  5409. // Make sure the item index is correct because we use this index as a reference
  5410. SCHEMA_INIT_CHECK(
  5411. !m_mapQualities.IsValidIndex( nMapIndex ),
  5412. CFmtStr( "Duplicate quality value (%d)", nQualityIndex ) );
  5413. nMapIndex = m_mapQualities.Insert( nQualityIndex );
  5414. SCHEMA_INIT_SUBSTEP( m_mapQualities[nMapIndex].BInitFromKV( pKVQuality, *this, pVecErrors ) );
  5415. }
  5416. }
  5417. // Check the integrity of the quality definitions
  5418. // Check for duplicate quality names
  5419. CUtlRBTree<const char *> rbQualityNames( CaselessStringLessThan );
  5420. rbQualityNames.EnsureCapacity( m_mapQualities.Count() );
  5421. FOR_EACH_MAP_FAST( m_mapQualities, i )
  5422. {
  5423. int iIndex = rbQualityNames.Find( m_mapQualities[i].GetName() );
  5424. SCHEMA_INIT_CHECK(
  5425. !rbQualityNames.IsValidIndex( iIndex ),
  5426. CFmtStr( "Quality definition %d: Duplicate quality name %s", m_mapQualities[i].GetDBValue(), m_mapQualities[i].GetName() ) );
  5427. if( !rbQualityNames.IsValidIndex( iIndex ) )
  5428. rbQualityNames.Insert( m_mapQualities[i].GetName() );
  5429. }
  5430. return SCHEMA_INIT_SUCCESS();
  5431. }
  5432. //-----------------------------------------------------------------------------
  5433. // Purpose:
  5434. //-----------------------------------------------------------------------------
  5435. bool CEconItemSchema::BInitColors( KeyValues *pKVColors, CUtlVector<CUtlString> *pVecErrors )
  5436. {
  5437. // initialize the color definitions
  5438. if ( NULL != pKVColors )
  5439. {
  5440. FOR_EACH_TRUE_SUBKEY( pKVColors, pKVColor )
  5441. {
  5442. CEconColorDefinition *pNewColorDef = new CEconColorDefinition;
  5443. SCHEMA_INIT_SUBSTEP( pNewColorDef->BInitFromKV( pKVColor, *this, pVecErrors ) );
  5444. m_vecColorDefs.AddToTail( pNewColorDef );
  5445. }
  5446. }
  5447. return SCHEMA_INIT_SUCCESS();
  5448. }
  5449. bool CEconItemSchema::BInitGraffitiTints( KeyValues *pKVColors, CUtlVector<CUtlString> *pVecErrors )
  5450. {
  5451. FOR_EACH_TRUE_SUBKEY( pKVColors, pKVColor )
  5452. {
  5453. CEconGraffitiTintDefinition *pNewDef = new CEconGraffitiTintDefinition;
  5454. bool bResult = pNewDef->BInitFromKV( pKVColor, *this, pVecErrors );
  5455. const int nMaxIDallowed = 64;
  5456. if ( bResult )
  5457. {
  5458. SCHEMA_INIT_CHECK( ( pNewDef->GetID() > 0 ) && ( pNewDef->GetID() < nMaxIDallowed ),
  5459. CFmtStr( "Graffiti tint definition id out of range [1..%d]: #%d %s\n", nMaxIDallowed, pNewDef->GetID(), pNewDef->GetColorName() ) );
  5460. SCHEMA_INIT_CHECK( !m_vecGraffitiTintDefs.IsValidIndex( pNewDef->GetID() ) || !m_vecGraffitiTintDefs[pNewDef->GetID()],
  5461. CFmtStr( "Graffiti tint definition duplicate: #%d %s\n", pNewDef->GetID(), pNewDef->GetColorName() ) );
  5462. SCHEMA_INIT_CHECK( pNewDef->GetColorName() && *pNewDef->GetColorName() && !m_mapGraffitiTintByName.Defined( pNewDef->GetColorName() ),
  5463. CFmtStr( "Graffiti tint name duplicate: #%d %s\n", pNewDef->GetID(), pNewDef->GetColorName() ) );
  5464. bResult &= ( pNewDef->GetID() > 0 ) && ( pNewDef->GetID() < nMaxIDallowed ) &&
  5465. ( !m_vecGraffitiTintDefs.IsValidIndex( pNewDef->GetID() ) || !m_vecGraffitiTintDefs[pNewDef->GetID()] ) &&
  5466. pNewDef->GetColorName() && *pNewDef->GetColorName() && !m_mapGraffitiTintByName.Defined( pNewDef->GetColorName() );
  5467. }
  5468. if ( !bResult )
  5469. {
  5470. SCHEMA_INIT_SUBSTEP( bResult );
  5471. delete pNewDef;
  5472. }
  5473. else
  5474. {
  5475. if ( !m_vecGraffitiTintDefs.Count() )
  5476. {
  5477. for ( int j = 0; j < nMaxIDallowed; ++ j )
  5478. m_vecGraffitiTintDefs.AddToTail( NULL );
  5479. }
  5480. m_vecGraffitiTintDefs[pNewDef->GetID()] = pNewDef;
  5481. m_mapGraffitiTintByName[pNewDef->GetColorName()] = pNewDef;
  5482. m_nMaxValidGraffitiTintDefID = MAX( m_nMaxValidGraffitiTintDefID, pNewDef->GetID() );
  5483. }
  5484. }
  5485. SCHEMA_INIT_CHECK( m_vecGraffitiTintDefs.Count() > 0, CFmtStr( "Graffiti tint definitions failed to parse\n" ) );
  5486. return SCHEMA_INIT_SUCCESS();
  5487. }
  5488. //-----------------------------------------------------------------------------
  5489. // Purpose:
  5490. //-----------------------------------------------------------------------------
  5491. AlternateIconData_t* CEconItemSchema::GetAlternateIcon( uint64 ullAlternateIcon )
  5492. {
  5493. int iIdx = m_mapAlternateIcons.Find( ullAlternateIcon );
  5494. if ( !m_mapAlternateIcons.IsValidIndex( iIdx ) )
  5495. return NULL;
  5496. else
  5497. return &(m_mapAlternateIcons[iIdx]);
  5498. }
  5499. //-----------------------------------------------------------------------------
  5500. // Purpose: Initializes the rarity section of the schema
  5501. //-----------------------------------------------------------------------------
  5502. bool CEconItemSchema::BInitSoundMaterials( KeyValues *pKVSoundMaterials, CUtlVector<CUtlString> *pVecErrors )
  5503. {
  5504. // initialize the item definitions
  5505. if ( NULL != pKVSoundMaterials )
  5506. {
  5507. FOR_EACH_TRUE_SUBKEY( pKVSoundMaterials, pKVSoundMaterial )
  5508. {
  5509. int nSoundMaterialIndex = pKVSoundMaterial->GetInt( "value" );
  5510. int nMapIndex = m_mapSoundMaterials.Find( nSoundMaterialIndex );
  5511. // Make sure the item index is correct because we use this index as a reference
  5512. SCHEMA_INIT_CHECK(
  5513. !m_mapSoundMaterials.IsValidIndex( nMapIndex ),
  5514. CFmtStr( "Duplicate sound material value (%d)", nSoundMaterialIndex ) );
  5515. nMapIndex = m_mapSoundMaterials.Insert( nSoundMaterialIndex );
  5516. SCHEMA_INIT_SUBSTEP( m_mapSoundMaterials[nMapIndex].BInitFromKV( pKVSoundMaterial, *this, pVecErrors ) );
  5517. }
  5518. }
  5519. return SCHEMA_INIT_SUCCESS();
  5520. }
  5521. //-----------------------------------------------------------------------------
  5522. // Purpose:
  5523. //-----------------------------------------------------------------------------
  5524. int CEconItemSchema::GetEquipRegionIndexByName( const char *pRegionName ) const
  5525. {
  5526. FOR_EACH_VEC( m_vecEquipRegionsList, i )
  5527. {
  5528. const char *szEntryRegionName = m_vecEquipRegionsList[i].m_sName;
  5529. if ( !V_stricmp( szEntryRegionName, pRegionName ) )
  5530. return i;
  5531. }
  5532. return -1;
  5533. }
  5534. //-----------------------------------------------------------------------------
  5535. // Purpose:
  5536. //-----------------------------------------------------------------------------
  5537. equip_region_mask_t CEconItemSchema::GetEquipRegionBitMaskByName( const char *pRegionName ) const
  5538. {
  5539. int iRegionIndex = GetEquipRegionIndexByName( pRegionName );
  5540. if ( !m_vecEquipRegionsList.IsValidIndex( iRegionIndex ) )
  5541. return 0;
  5542. equip_region_mask_t unRegionMask = 1 << m_vecEquipRegionsList[iRegionIndex].m_unBitIndex;
  5543. Assert( unRegionMask > 0 );
  5544. return unRegionMask;
  5545. }
  5546. //-----------------------------------------------------------------------------
  5547. // Purpose:
  5548. //-----------------------------------------------------------------------------
  5549. void CEconItemSchema::SetEquipRegionConflict( int iRegion, unsigned int unBit )
  5550. {
  5551. Assert( m_vecEquipRegionsList.IsValidIndex( iRegion ) );
  5552. equip_region_mask_t unRegionMask = 1 << unBit;
  5553. Assert( unRegionMask > 0 );
  5554. m_vecEquipRegionsList[iRegion].m_unMask |= unRegionMask;
  5555. }
  5556. //-----------------------------------------------------------------------------
  5557. // Purpose:
  5558. //-----------------------------------------------------------------------------
  5559. equip_region_mask_t CEconItemSchema::GetEquipRegionMaskByName( const char *pRegionName ) const
  5560. {
  5561. int iRegionIdx = GetEquipRegionIndexByName( pRegionName );
  5562. if ( iRegionIdx < 0 )
  5563. return 0;
  5564. return m_vecEquipRegionsList[iRegionIdx].m_unMask;
  5565. }
  5566. //-----------------------------------------------------------------------------
  5567. // Purpose:
  5568. //-----------------------------------------------------------------------------
  5569. void CEconItemSchema::AssignDefaultBodygroupState( const char *pszBodygroupName, int iValue )
  5570. {
  5571. // Flip the value passed in -- if we specify in the schema that a region should be off, we assume that it's
  5572. // on by default.
  5573. int iDefaultValue = iValue == 0 ? 1 : 0;
  5574. // Make sure that we're constantly reinitializing our default value to the same default value. This is sort
  5575. // of dumb but it works for everything we've got now. In the event that conflicts start cropping up it would
  5576. // be easy enough to make a new schema section.
  5577. int iIndex = m_mapDefaultBodygroupState.Find( pszBodygroupName );
  5578. if ( (m_mapDefaultBodygroupState.IsValidIndex( iIndex ) && m_mapDefaultBodygroupState[iIndex] != iDefaultValue) ||
  5579. (iValue < 0 || iValue > 1) )
  5580. {
  5581. EmitWarning( SPEW_GC, 4, "Unable to get accurate read on whether bodygroup '%s' is enabled or disabled by default. (The schema is fine, but the code is confused and could stand to be made smarter.)\n", pszBodygroupName );
  5582. }
  5583. if ( !m_mapDefaultBodygroupState.IsValidIndex( iIndex ) )
  5584. {
  5585. m_mapDefaultBodygroupState.Insert( pszBodygroupName, iDefaultValue );
  5586. }
  5587. }
  5588. //-----------------------------------------------------------------------------
  5589. // Purpose:
  5590. //-----------------------------------------------------------------------------
  5591. bool CEconItemSchema::BInitEquipRegions( KeyValues *pKVEquipRegions, CUtlVector<CUtlString> *pVecErrors )
  5592. {
  5593. CUtlVector<const char *> vecNames;
  5594. FOR_EACH_SUBKEY( pKVEquipRegions, pKVRegion )
  5595. {
  5596. const char *pRegionKeyName = pKVRegion->GetName();
  5597. vecNames.Purge();
  5598. // The "shared" name is special for equip regions -- it means that all of the sub-regions specified
  5599. // will use the same bit to store equipped-or-not data, but that one bit can be accessed by a whole
  5600. // bunch of different names. This is useful in TF where different classes have different regions, but
  5601. // those regions cannot possibly conflict with each other. For example, "scout_backpack" cannot possibly
  5602. // overlap with "pyro_shoulder" because they can't even be equipped on the same character.
  5603. if ( pRegionKeyName && !Q_stricmp( pRegionKeyName, "shared" ) )
  5604. {
  5605. FOR_EACH_SUBKEY( pKVRegion, pKVSharedRegionName )
  5606. {
  5607. vecNames.AddToTail( pKVSharedRegionName->GetName() );
  5608. }
  5609. }
  5610. // We have a standard name -- this one entry is its own equip region.
  5611. else
  5612. {
  5613. vecNames.AddToTail( pRegionKeyName );
  5614. }
  5615. // What bit will this equip region use to mask against conflicts? If we don't have any equip regions
  5616. // at all, we'll use the base bit, otherwise we just grab one higher than whatever we used last.
  5617. unsigned int unNewBitIndex = m_vecEquipRegionsList.Count() <= 0 ? 0 : m_vecEquipRegionsList.Tail().m_unBitIndex + 1;
  5618. FOR_EACH_VEC( vecNames, i )
  5619. {
  5620. const char *pRegionName = vecNames[i];
  5621. // Make sure this name is unique.
  5622. if ( GetEquipRegionIndexByName( pRegionName ) >= 0 )
  5623. {
  5624. pVecErrors->AddToTail( CFmtStr( "Duplicate equip region named \"%s\".", pRegionName ).Access() );
  5625. continue;
  5626. }
  5627. // Make a new region.
  5628. EquipRegion newEquipRegion;
  5629. newEquipRegion.m_sName = pRegionName;
  5630. newEquipRegion.m_unMask = 0; // we'll update this mask later
  5631. newEquipRegion.m_unBitIndex = unNewBitIndex;
  5632. int iIdx = m_vecEquipRegionsList.AddToTail( newEquipRegion );
  5633. // Tag this region to conflict with itself so that if nothing else two items in the same
  5634. // region can't equip over each other.
  5635. SetEquipRegionConflict( iIdx, unNewBitIndex );
  5636. }
  5637. }
  5638. return SCHEMA_INIT_SUCCESS();
  5639. }
  5640. //-----------------------------------------------------------------------------
  5641. // Purpose:
  5642. //-----------------------------------------------------------------------------
  5643. bool CEconItemSchema::BInitEquipRegionConflicts( KeyValues *pKVEquipRegionConflicts, CUtlVector<CUtlString> *pVecErrors )
  5644. {
  5645. FOR_EACH_TRUE_SUBKEY( pKVEquipRegionConflicts, pKVConflict )
  5646. {
  5647. // What region is the base of this conflict?
  5648. const char *pRegionName = pKVConflict->GetName();
  5649. int iRegionIdx = GetEquipRegionIndexByName( pRegionName );
  5650. if ( iRegionIdx < 0 )
  5651. {
  5652. pVecErrors->AddToTail( CFmtStr( "Unable to find base equip region named \"%s\" for conflicts.", pRegionName ).Access() );
  5653. continue;
  5654. }
  5655. FOR_EACH_SUBKEY( pKVConflict, pKVConflictOther )
  5656. {
  5657. const char *pOtherRegionName = pKVConflictOther->GetName();
  5658. int iOtherRegionIdx = GetEquipRegionIndexByName( pOtherRegionName );
  5659. if ( iOtherRegionIdx < 0 )
  5660. {
  5661. pVecErrors->AddToTail( CFmtStr( "Unable to find other equip region named \"%s\" for conflicts.", pOtherRegionName ).Access() );
  5662. continue;
  5663. }
  5664. SetEquipRegionConflict( iRegionIdx, m_vecEquipRegionsList[iOtherRegionIdx].m_unBitIndex );
  5665. SetEquipRegionConflict( iOtherRegionIdx, m_vecEquipRegionsList[iRegionIdx].m_unBitIndex );
  5666. }
  5667. }
  5668. return SCHEMA_INIT_SUCCESS();
  5669. }
  5670. //-----------------------------------------------------------------------------
  5671. // Purpose: Initializes the attributes section of the schema
  5672. // Input: pKVAttributes - The attributes section of the KeyValues
  5673. // representation of the schema
  5674. // pVecErrors - An optional vector that will contain error messages if
  5675. // the init fails.
  5676. // Output: True if initialization succeeded, false otherwise
  5677. //-----------------------------------------------------------------------------
  5678. bool CEconItemSchema::BInitAttributes( KeyValues *pKVAttributes, CUtlVector<CUtlString> *pVecErrors )
  5679. {
  5680. // Initialize the attribute definitions
  5681. FOR_EACH_TRUE_SUBKEY( pKVAttributes, pKVAttribute )
  5682. {
  5683. int nAttrIndex = Q_atoi( pKVAttribute->GetName() );
  5684. // Make sure the index is positive
  5685. SCHEMA_INIT_CHECK(
  5686. ( nAttrIndex >= 0 ) && ( nAttrIndex < 30*1000 ),
  5687. CFmtStr( "Attribute definition index %d must be greater than or equal to zero", nAttrIndex ) );
  5688. if ( !( ( nAttrIndex >= 0 ) && ( nAttrIndex < 30*1000 ) ) )
  5689. continue;
  5690. // Build the direct mapping container
  5691. while ( nAttrIndex >= m_mapAttributesContainer.Count() )
  5692. m_mapAttributesContainer.AddToTail( NULL );
  5693. Assert( nAttrIndex < m_mapAttributesContainer.Count() );
  5694. // Make sure the attribute index is not repeated
  5695. SCHEMA_INIT_CHECK(
  5696. !m_mapAttributesContainer[nAttrIndex],
  5697. CFmtStr( "Duplicate attribute definition index (%d)", nAttrIndex ) );
  5698. if ( m_mapAttributesContainer[nAttrIndex] )
  5699. continue;
  5700. m_mapAttributesContainer[nAttrIndex] = new CEconItemAttributeDefinition;
  5701. SCHEMA_INIT_SUBSTEP( m_mapAttributesContainer[nAttrIndex]->BInitFromKV( pKVAttribute, *this, pVecErrors ) );
  5702. }
  5703. // Check the integrity of the attribute definitions
  5704. // Check for duplicate attribute definition names
  5705. CUtlRBTree<const char *> rbAttributeNames( CaselessStringLessThan );
  5706. rbAttributeNames.EnsureCapacity( m_mapAttributesContainer.Count() );
  5707. FOR_EACH_VEC( m_mapAttributesContainer, i )
  5708. {
  5709. if ( !m_mapAttributesContainer[i] )
  5710. continue;
  5711. int iIndex = rbAttributeNames.Find( m_mapAttributesContainer[i]->GetDefinitionName() );
  5712. SCHEMA_INIT_CHECK(
  5713. !rbAttributeNames.IsValidIndex( iIndex ),
  5714. CFmtStr( "Attribute definition %d: Duplicate name \"%s\"", i, m_mapAttributesContainer[i]->GetDefinitionName() ) );
  5715. if( !rbAttributeNames.IsValidIndex( iIndex ) )
  5716. rbAttributeNames.Insert( m_mapAttributesContainer[i]->GetDefinitionName() );
  5717. }
  5718. return SCHEMA_INIT_SUCCESS();
  5719. }
  5720. //-----------------------------------------------------------------------------
  5721. // Purpose: After bundles are set up, we can do payment rules.
  5722. //-----------------------------------------------------------------------------
  5723. bool CEconItemSchema::BInitPaymentRules( CUtlVector<CUtlString> *pVecErrors )
  5724. {
  5725. return true;
  5726. }
  5727. //-----------------------------------------------------------------------------
  5728. // Purpose: After items are initialized, this method links bundles to their contents.
  5729. //-----------------------------------------------------------------------------
  5730. bool CEconItemSchema::BInitBundles( CUtlVector<CUtlString> *pVecErrors )
  5731. {
  5732. // Link each bundle with its contents.
  5733. FOR_EACH_MAP_FAST( m_mapItems, i )
  5734. {
  5735. CEconItemDefinition *pItemDef = m_mapItems[ i ];
  5736. if ( !pItemDef )
  5737. continue;
  5738. KeyValues* pItemKV = pItemDef->GetRawDefinition();
  5739. if ( !pItemKV )
  5740. continue;
  5741. KeyValues *pBundleDataKV = pItemKV->FindKey( "bundle" );
  5742. if ( pBundleDataKV )
  5743. {
  5744. pItemDef->m_BundleInfo = new bundleinfo_t();
  5745. FOR_EACH_SUBKEY( pBundleDataKV, pKVCurItem )
  5746. {
  5747. item_list_entry_t entry;
  5748. bool bEntrySuccess = entry.InitFromName( pKVCurItem->GetName() );
  5749. SCHEMA_INIT_CHECK(
  5750. bEntrySuccess,
  5751. CFmtStr( "Bundle %s: Item definition \"%s\" failed to initialize\n", pItemDef->m_pszDefinitionName, pKVCurItem->GetName() ) );
  5752. const CEconItemDefinition *pBundleItemDef = GetItemDefinition( entry.m_nItemDef );
  5753. SCHEMA_INIT_CHECK( pBundleItemDef, CFmtStr( "Unable to find item definition '%s' for bundle '%s'.", pKVCurItem->GetName(), pItemDef->m_pszDefinitionName ) );
  5754. pItemDef->m_BundleInfo->vecItemEntries.AddToTail( entry );
  5755. }
  5756. // Only check for pack bundle if the item is actually a bundle - note that we could do this programatically by checking that all items in the bundle are flagged as a "pack item" - but for now the bundle needs to be explicitly flagged as a pack bundle.
  5757. pItemDef->m_bIsPackBundle = pItemKV->GetInt( "is_pack_bundle", 0 ) != 0;
  5758. }
  5759. // Make a list of all of our bundles.
  5760. if ( pItemDef->IsBundle() )
  5761. {
  5762. // Cache off the item def for the bundle, since we'll need both the bundle info and the item def index later.
  5763. m_vecBundles.AddToTail( pItemDef );
  5764. // If the bundle is a pack bundle, mark all the contained items as pack items / link to the owning pack bundle
  5765. if ( pItemDef->IsPackBundle() )
  5766. {
  5767. const bundleinfo_t *pBundleInfo = pItemDef->GetBundleInfo();
  5768. FOR_EACH_VEC( pBundleInfo->vecItemEntries, iCurItem )
  5769. {
  5770. CEconItemDefinition *pCurItemDef = GetItemDefinitionMutable( pBundleInfo->vecItemEntries[ iCurItem ].m_nItemDef );
  5771. SCHEMA_INIT_CHECK( NULL == pCurItemDef->m_pOwningPackBundle, CFmtStr( "Pack item \"%s\" included in more than one pack bundle - not allowed!", pCurItemDef->GetDefinitionName() ) );
  5772. pCurItemDef->m_pOwningPackBundle = pItemDef;
  5773. }
  5774. }
  5775. }
  5776. }
  5777. // Go through all regular (ie non-pack) bundles and ensure that if any pack items are included, *all* pack items in the owning pack bundle are included.
  5778. FOR_EACH_VEC( m_vecBundles, iBundle )
  5779. {
  5780. const CEconItemDefinition *pBundleItemDef = m_vecBundles[ iBundle ];
  5781. if ( pBundleItemDef->IsPackBundle() )
  5782. continue;
  5783. // Go through all items in the bundle and look for pack items
  5784. const bundleinfo_t *pBundle = pBundleItemDef->GetBundleInfo();
  5785. if ( pBundle )
  5786. {
  5787. FOR_EACH_VEC( pBundle->vecItemEntries, iContainedBundleItem )
  5788. {
  5789. // Get the associated pack bundle
  5790. const CEconItemDefinition *pContainedBundleItemDef = GetItemDefinition( pBundle->vecItemEntries[ iContainedBundleItem ].m_nItemDef );
  5791. // Ignore non-pack items
  5792. if ( !pContainedBundleItemDef || !pContainedBundleItemDef->IsPackItem() )
  5793. continue;
  5794. // Get the pack bundle that contains this particular pack item
  5795. const CEconItemDefinition *pOwningPackBundleItemDef = pContainedBundleItemDef->GetOwningPackBundle();
  5796. // Make sure all items in the owning pack bundle are in pBundleItemDef's bundle info (pBundle)
  5797. const bundleinfo_t *pOwningPackBundle = pOwningPackBundleItemDef->GetBundleInfo();
  5798. FOR_EACH_VEC( pOwningPackBundle->vecItemEntries, iCurPackBundleItem )
  5799. {
  5800. bool bFound = false;
  5801. FOR_EACH_VEC( pBundle->vecItemEntries, i )
  5802. {
  5803. if ( pOwningPackBundle->vecItemEntries[ iCurPackBundleItem ].m_nItemDef == pBundle->vecItemEntries[ i ].m_nItemDef &&
  5804. pOwningPackBundle->vecItemEntries[ iCurPackBundleItem ].m_nPaintKit == pBundle->vecItemEntries[ i ].m_nPaintKit )
  5805. {
  5806. bFound = true;
  5807. break;
  5808. }
  5809. }
  5810. if ( !bFound )
  5811. {
  5812. SCHEMA_INIT_CHECK(
  5813. false,
  5814. CFmtStr( "The bundle \"%s\" contains some, but not all pack items required specified by pack bundle \"%s.\"",
  5815. pBundleItemDef->GetDefinitionName(),
  5816. pOwningPackBundleItemDef->GetDefinitionName()
  5817. )
  5818. );
  5819. }
  5820. }
  5821. }
  5822. }
  5823. }
  5824. return true;
  5825. }
  5826. //-----------------------------------------------------------------------------
  5827. // Purpose: Initializes the items section of the schema
  5828. // Input: pKVItems - The items section of the KeyValues
  5829. // representation of the schema
  5830. // pVecErrors - An optional vector that will contain error messages if
  5831. // the init fails.
  5832. // Output: True if initialization succeeded, false otherwise
  5833. //-----------------------------------------------------------------------------
  5834. bool CEconItemSchema::BInitItems( KeyValues *pKVItems, CUtlVector<CUtlString> *pVecErrors )
  5835. {
  5836. FOR_EACH_TRUE_SUBKEY( pKVItems, pKVItem )
  5837. {
  5838. if ( Q_stricmp( pKVItem->GetName(), "default" ) == 0 )
  5839. {
  5840. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  5841. SCHEMA_INIT_CHECK(
  5842. m_pDefaultItemDefinition == NULL,
  5843. CFmtStr( "Duplicate 'default' item definition." ) );
  5844. if ( m_pDefaultItemDefinition == NULL )
  5845. {
  5846. m_pDefaultItemDefinition = CreateEconItemDefinition();
  5847. }
  5848. SCHEMA_INIT_SUBSTEP( m_pDefaultItemDefinition->BInitFromKV( pKVItem, *this, pVecErrors ) );
  5849. #endif
  5850. }
  5851. else
  5852. {
  5853. int nItemIndex = Q_atoi( pKVItem->GetName() );
  5854. int nMapIndex = m_mapItems.Find( nItemIndex );
  5855. // Make sure the item index is correct because we use this index as a reference
  5856. SCHEMA_INIT_CHECK(
  5857. !m_mapItems.IsValidIndex( nMapIndex ),
  5858. CFmtStr( "Duplicate item definition (%d)", nItemIndex ) );
  5859. // Check to make sure the index is positive
  5860. SCHEMA_INIT_CHECK(
  5861. nItemIndex >= 0,
  5862. CFmtStr( "Item definition index %d must be greater than or equal to zero", nItemIndex ) );
  5863. CEconItemDefinition *pItemDef = CreateEconItemDefinition();
  5864. nMapIndex = m_mapItems.Insert( nItemIndex, pItemDef );
  5865. m_mapItemsSorted.Insert( nItemIndex, pItemDef );
  5866. SCHEMA_INIT_SUBSTEP( m_mapItems[nMapIndex]->BInitFromKV( pKVItem, *this, pVecErrors ) );
  5867. }
  5868. }
  5869. return SCHEMA_INIT_SUCCESS();
  5870. }
  5871. bool CEconItemSchema::BInitItemMappings( CUtlVector<CUtlString> *pVecErrors )
  5872. {
  5873. // Check the integrity of the item definitions
  5874. CUtlRBTree<const char *> rbItemNames( CaselessStringLessThan );
  5875. rbItemNames.EnsureCapacity( m_mapItems.Count() );
  5876. FOR_EACH_MAP_FAST( m_mapItems, i )
  5877. {
  5878. CEconItemDefinition *pItemDef = m_mapItems[ i ];
  5879. // Check for duplicate item definition names
  5880. int iIndex = rbItemNames.Find( pItemDef->GetDefinitionName() );
  5881. SCHEMA_INIT_CHECK(
  5882. !rbItemNames.IsValidIndex( iIndex ),
  5883. CFmtStr( "Item definition %s: Duplicate name on index %d", pItemDef->GetDefinitionName(), m_mapItems.Key( i ) ) );
  5884. if( !rbItemNames.IsValidIndex( iIndex ) )
  5885. rbItemNames.Insert( m_mapItems[i]->GetDefinitionName() );
  5886. // Link up armory and store mappings for the item
  5887. SCHEMA_INIT_SUBSTEP( pItemDef->BInitItemMappings( *this, pVecErrors ) );
  5888. }
  5889. return SCHEMA_INIT_SUCCESS();
  5890. }
  5891. //-----------------------------------------------------------------------------
  5892. // Purpose: Delete an item definition. Moderately dangerous as cached references will become bad.
  5893. // Intended for use by the item editor.
  5894. //-----------------------------------------------------------------------------
  5895. bool CEconItemSchema::DeleteItemDefinition( int iDefIndex )
  5896. {
  5897. m_mapItemsSorted.Remove( iDefIndex );
  5898. int nMapIndex = m_mapItems.Find( iDefIndex );
  5899. if ( m_mapItems.IsValidIndex( nMapIndex ) )
  5900. {
  5901. CEconItemDefinition* pItemDef = m_mapItems[nMapIndex];
  5902. if ( pItemDef )
  5903. {
  5904. m_mapItems.RemoveAt( nMapIndex );
  5905. delete pItemDef;
  5906. return true;
  5907. }
  5908. }
  5909. return false;
  5910. }
  5911. //-----------------------------------------------------------------------------
  5912. // Purpose:
  5913. //-----------------------------------------------------------------------------
  5914. const CEconItemSetDefinition* CEconItemSchema::GetItemSet( const char* pSetName, int *piIndex ) const
  5915. {
  5916. for ( unsigned int i=0; i<m_mapItemSets.Count(); ++i )
  5917. {
  5918. if ( !Q_strcmp( m_mapItemSets.Key(i), pSetName ) )
  5919. {
  5920. if ( piIndex )
  5921. {
  5922. *piIndex = i;
  5923. }
  5924. return (CEconItemSetDefinition*) &(m_mapItemSets[i]);
  5925. }
  5926. }
  5927. return NULL;
  5928. }
  5929. const IEconItemSetDefinition* CEconItemSchema::GetItemSet( int iIndex ) const
  5930. {
  5931. if ( m_mapItemSets.IsValidIndex( iIndex ) )
  5932. return &m_mapItemSets[iIndex];
  5933. else
  5934. return NULL;
  5935. }
  5936. //-----------------------------------------------------------------------------
  5937. // Purpose: Parses the Item Sets section.
  5938. //-----------------------------------------------------------------------------
  5939. bool CEconItemSchema::BInitItemSets( KeyValues *pKVItemSets, CUtlVector<CUtlString> *pVecErrors )
  5940. {
  5941. FOR_EACH_TRUE_SUBKEY( pKVItemSets, pKVItemSet )
  5942. {
  5943. const char* setName = pKVItemSet->GetName();
  5944. SCHEMA_INIT_CHECK( setName != NULL, CFmtStr( "All itemsets must have names.") );
  5945. if ( m_mapItemSets.Count() > 0 )
  5946. {
  5947. SCHEMA_INIT_CHECK( GetItemSet( setName ) == NULL, CFmtStr( "Duplicate itemset name (%s) found!", setName ) );
  5948. }
  5949. int idx = m_mapItemSets.Insert( setName );
  5950. SCHEMA_INIT_SUBSTEP( m_mapItemSets[idx].BInitFromKV( pKVItemSet, *this, pVecErrors ) );
  5951. FOR_EACH_VEC( m_mapItemSets[idx].m_ItemEntries, nEntry )
  5952. {
  5953. item_list_entry_t &itemListEntry = m_mapItemSets[idx].m_ItemEntries[ nEntry ];
  5954. CEconItemDefinition *pItemDef = GetItemDefinitionMutable( itemListEntry.m_nItemDef );
  5955. if ( pItemDef )
  5956. {
  5957. pItemDef->AddItemSet( idx );
  5958. }
  5959. }
  5960. }
  5961. return SCHEMA_INIT_SUCCESS();
  5962. }
  5963. //-----------------------------------------------------------------------------
  5964. // Purpose: Initializes the timed rewards section of the schema
  5965. // Input: pKVTimedRewards - The timed_rewards section of the KeyValues
  5966. // representation of the schema
  5967. // pVecErrors - An optional vector that will contain error messages if
  5968. // the init fails.
  5969. // Output: True if initialization succeeded, false otherwise
  5970. //-----------------------------------------------------------------------------
  5971. bool CEconItemSchema::BInitTimedRewards( KeyValues *pKVTimedRewards, CUtlVector<CUtlString> *pVecErrors )
  5972. {
  5973. m_vecTimedRewards.Purge();
  5974. // initialize the rewards sections
  5975. if ( NULL != pKVTimedRewards )
  5976. {
  5977. FOR_EACH_TRUE_SUBKEY( pKVTimedRewards, pKVTimedReward )
  5978. {
  5979. int index = m_vecTimedRewards.AddToTail();
  5980. SCHEMA_INIT_SUBSTEP( m_vecTimedRewards[index].BInitFromKV( pKVTimedReward, *this, pVecErrors ) );
  5981. }
  5982. }
  5983. return SCHEMA_INIT_SUCCESS();
  5984. }
  5985. //-----------------------------------------------------------------------------
  5986. // Purpose:
  5987. //-----------------------------------------------------------------------------
  5988. const CTimedItemRewardDefinition* CEconItemSchema::GetTimedReward( eTimedRewardType type ) const
  5989. {
  5990. if ( (int)type < m_vecTimedRewards.Count() )
  5991. {
  5992. return &m_vecTimedRewards[type];
  5993. }
  5994. return NULL;
  5995. }
  5996. //-----------------------------------------------------------------------------
  5997. // Purpose:
  5998. //-----------------------------------------------------------------------------
  5999. const CEconLootListDefinition* CEconItemSchema::GetLootListByName( const char* pListName, int *out_piIndex ) const
  6000. {
  6001. int iIdx = m_dictLootLists.Find( pListName );
  6002. if ( out_piIndex )
  6003. *out_piIndex = iIdx;
  6004. if ( m_dictLootLists.IsValidIndex( iIdx ) )
  6005. return &m_dictLootLists[iIdx];
  6006. else
  6007. return NULL;
  6008. }
  6009. //-----------------------------------------------------------------------------
  6010. // Purpose: Initializes the loot lists section of the schema
  6011. //-----------------------------------------------------------------------------
  6012. bool CEconItemSchema::BInitLootLists( KeyValues *pKVLootLists, KeyValues *pKVRandomAttributeTemplates, CUtlVector<CUtlString> *pVecErrors, bool bServerLists )
  6013. {
  6014. FOR_EACH_TRUE_SUBKEY( pKVLootLists, pKVLootList )
  6015. {
  6016. const char* listName = pKVLootList->GetName();
  6017. SCHEMA_INIT_CHECK( listName != NULL, CFmtStr( "All lootlists must have names.") );
  6018. if ( m_dictLootLists.Count() > 0 )
  6019. {
  6020. SCHEMA_INIT_CHECK( GetLootListByName( listName ) == NULL, CFmtStr( "Duplicate lootlist name (%s) found!", listName ) );
  6021. }
  6022. int idx = m_dictLootLists.Insert( listName );
  6023. SCHEMA_INIT_SUBSTEP( m_dictLootLists[idx].BInitFromKV( pKVLootList, pKVRandomAttributeTemplates, *this, pVecErrors, bServerLists ) );
  6024. }
  6025. return SCHEMA_INIT_SUCCESS();
  6026. }
  6027. //-----------------------------------------------------------------------------
  6028. // Purpose: Initializes the revolving loot lists section of the schema
  6029. //-----------------------------------------------------------------------------
  6030. bool CEconItemSchema::BInitRevolvingLootLists( KeyValues *pKVLootLists, CUtlVector<CUtlString> *pVecErrors )
  6031. {
  6032. FOR_EACH_SUBKEY( pKVLootLists, pKVList )
  6033. {
  6034. int iListIdx = atoi( pKVList->GetName() );
  6035. const char* strListName = pKVList->GetString();
  6036. m_mapRevolvingLootLists.Insert( iListIdx, strListName );
  6037. }
  6038. return SCHEMA_INIT_SUCCESS();
  6039. }
  6040. //-----------------------------------------------------------------------------
  6041. // Purpose: Initializes the quest reward loot lists section of the schema
  6042. //-----------------------------------------------------------------------------
  6043. bool CEconItemSchema::BInitQuestRewardLootLists( KeyValues *pKVLootLists, CUtlVector<CUtlString> *pVecErrors )
  6044. {
  6045. m_mapQuestRewardLootLists.Purge();
  6046. if ( NULL != pKVLootLists )
  6047. {
  6048. FOR_EACH_SUBKEY( pKVLootLists, pKVList )
  6049. {
  6050. int iListIdx = atoi( pKVList->GetName() );
  6051. const char* strListName = pKVList->GetString();
  6052. m_mapQuestRewardLootLists.Insert( iListIdx, strListName );
  6053. }
  6054. }
  6055. return SCHEMA_INIT_SUCCESS();
  6056. }
  6057. //-----------------------------------------------------------------------------
  6058. // Alternate Icons
  6059. //-----------------------------------------------------------------------------
  6060. bool CEconItemSchema::BInitAlternateIcons( KeyValues *pKVAlternateIcons, CUtlVector<CUtlString> *pVecErrors )
  6061. {
  6062. m_mapAlternateIcons.Purge();
  6063. FOR_EACH_TRUE_SUBKEY( pKVAlternateIcons, pKVBlock )
  6064. {
  6065. bool bSprayTints = !V_stricmp( pKVBlock->GetName(), "spray_tint_icons" );
  6066. FOR_EACH_TRUE_SUBKEY( pKVBlock, pKVAlternateIcon )
  6067. {
  6068. if ( bSprayTints )
  6069. {
  6070. // Custom readable syntax for spray tints:
  6071. uint32 unSprayKitID = 0, unTintID1 = 0, unTintID2 = 0;
  6072. if ( 3 == sscanf( pKVAlternateIcon->GetName(), "%u:%u:%u", &unSprayKitID, &unTintID1, &unTintID2 ) )
  6073. {
  6074. CFmtStr fmtValueLookup( "icon_path_range:%u:%u", unTintID1, unTintID2 );
  6075. char const *szIconPath = pKVAlternateIcon->GetString( fmtValueLookup );
  6076. if ( szIconPath && *szIconPath )
  6077. {
  6078. for ( uint32 unTintID = unTintID1; unTintID <= unTintID2; ++unTintID )
  6079. {
  6080. uint64 ullAltIconKey = Helper_GetAlternateIconKeyForTintedStickerItem( unSprayKitID, unTintID );
  6081. BInitAlternateIcon( ullAltIconKey, CFmtStr( "%s_%u", szIconPath, unTintID ), pKVAlternateIcon, pVecErrors );
  6082. }
  6083. }
  6084. else
  6085. {
  6086. SCHEMA_INIT_CHECK( false,
  6087. CFmtStr( "Alternate icon '%s' > '%s' must define '%s'", pKVBlock->GetName(), pKVAlternateIcon->GetName(), fmtValueLookup.Get() ) );
  6088. }
  6089. }
  6090. }
  6091. else
  6092. {
  6093. uint64 ullAltIconKey = V_atoui64( pKVAlternateIcon->GetName() );
  6094. char const *szIconPath = pKVAlternateIcon->GetString( "icon_path" );
  6095. if ( szIconPath && *szIconPath )
  6096. {
  6097. BInitAlternateIcon( ullAltIconKey, szIconPath, pKVAlternateIcon, pVecErrors );
  6098. }
  6099. else
  6100. {
  6101. SCHEMA_INIT_CHECK( false,
  6102. CFmtStr( "Alternate icon '%s' > '%s' must define '%s'", pKVBlock->GetName(), pKVAlternateIcon->GetName(), "icon_path" ) );
  6103. }
  6104. }
  6105. }
  6106. }
  6107. return SCHEMA_INIT_SUCCESS();
  6108. }
  6109. bool CEconItemSchema::BInitAlternateIcon( uint64 ullAltIconKey, char const *szSimpleName, KeyValues *pKVAlternateIcon, CUtlVector<CUtlString> *pVecErrors )
  6110. {
  6111. SCHEMA_INIT_CHECK(
  6112. !m_mapAlternateIcons.IsValidIndex( m_mapAlternateIcons.Find( ullAltIconKey ) ),
  6113. CFmtStr( "Duplicate alternate icon definition '%s' (%llu)", pKVAlternateIcon->GetName(), ullAltIconKey ) );
  6114. SCHEMA_INIT_CHECK(
  6115. int64( ullAltIconKey ) > 0,
  6116. CFmtStr( "Alternate icon definition index '%s' (%llu) must be greater than zero", pKVAlternateIcon->GetName(), ullAltIconKey ) );
  6117. int nNew = m_mapAlternateIcons.Insert( ullAltIconKey );
  6118. m_mapAlternateIcons[ nNew ].sSimpleName = szSimpleName;
  6119. m_mapAlternateIcons[ nNew ].sLargeSimpleName.Format( "%s_large", szSimpleName );
  6120. return true;
  6121. }
  6122. #ifdef CLIENT_DLL
  6123. //-----------------------------------------------------------------------------
  6124. // Web Resources
  6125. //-----------------------------------------------------------------------------
  6126. bool CEconItemSchema::BInitWebResources( KeyValues *pKVWebResources, CUtlVector<CUtlString> *pVecErrors )
  6127. {
  6128. if ( CWebResource::s_Initialized || !pKVWebResources )
  6129. return true;
  6130. FOR_EACH_SUBKEY( pKVWebResources, pDef )
  6131. {
  6132. CWebResource* pWebResource = new CWebResource;
  6133. pWebResource->m_strName = pDef->GetString( "name" );
  6134. pWebResource->m_strURL = pDef->GetString( "url" );
  6135. pWebResource->m_bOnDemand = pDef->GetBool( "on_demand" );
  6136. pWebResource->m_pKeyValues = NULL;
  6137. pWebResource->m_fnLoadCallback = NULL;
  6138. m_dictWebResources.Insert( pDef->GetString( "name" ), pWebResource );
  6139. }
  6140. if ( CommandLine()->CheckParm( "-enabledownloadtest" ) )
  6141. {
  6142. CWebResource* pWebResource = new CWebResource;
  6143. pWebResource->m_strName = "Test";
  6144. pWebResource->m_strURL = "http://media.steampowered.com/apps/570/test/test.txt";
  6145. pWebResource->m_bOnDemand = true;
  6146. pWebResource->m_pKeyValues = NULL;
  6147. pWebResource->m_fnLoadCallback = NULL;
  6148. m_dictWebResources.Insert( "Test", pWebResource );
  6149. }
  6150. // If any of our resources need to be requested immediately, do it now.
  6151. FOR_EACH_DICT_FAST( m_dictWebResources, idx )
  6152. {
  6153. CWebResource* pWebResource = m_dictWebResources[idx];
  6154. if ( !pWebResource )
  6155. continue;
  6156. if ( !pWebResource->m_bOnDemand )
  6157. {
  6158. LoadWebResource( pWebResource->m_strName, NULL );
  6159. }
  6160. }
  6161. CWebResource::s_Initialized = true;
  6162. return SCHEMA_INIT_SUCCESS();
  6163. }
  6164. EWebResourceStatus CEconItemSchema::LoadWebResource( CUtlString strName, void (*fnCallback)( const char*, KeyValues* ), bool bForceReload )
  6165. {
  6166. return kWebResource_NotLoaded;
  6167. }
  6168. void CEconItemSchema::SetWebResource( CUtlString strName, KeyValues* pResourceKV )
  6169. {
  6170. int idx = m_dictWebResources.Find( strName.Get() );
  6171. if ( !m_dictWebResources.IsValidIndex( idx ) )
  6172. return;
  6173. CWebResource* pResource = m_dictWebResources[idx];
  6174. if ( pResource->m_pKeyValues )
  6175. {
  6176. pResource->m_pKeyValues->deleteThis();
  6177. pResource->m_pKeyValues = NULL;
  6178. }
  6179. pResource->m_pKeyValues = pResourceKV;
  6180. if ( pResource->m_fnLoadCallback )
  6181. pResource->m_fnLoadCallback( strName.Get(), pResourceKV );
  6182. }
  6183. #endif
  6184. bool CEconItemSchema::BInitProPlayers( KeyValues *pKVData, CUtlVector<CUtlString> *pVecErrors )
  6185. {
  6186. FOR_EACH_SUBKEY( pKVData, pDef )
  6187. {
  6188. // Create the pro player entry
  6189. CProPlayerData *pData = new CProPlayerData;
  6190. if ( !pData->BInitFromKeyValues( pDef, pVecErrors ) )
  6191. {
  6192. delete pData;
  6193. continue;
  6194. }
  6195. if ( m_mapProPlayersByAccountID.Find( pData->GetAccountID() ) != m_mapProPlayersByAccountID.InvalidIndex() )
  6196. {
  6197. SCHEMA_INIT_CHECK( false,
  6198. CFmtStr( "Pro-player entry '%s' maps to a duplicate AccountID", pDef->GetName() ) );
  6199. Assert( false );
  6200. delete pData;
  6201. continue;
  6202. }
  6203. if ( m_mapProPlayersByCode.Find( pData->GetCode() ) != UTL_INVAL_SYMBOL )
  6204. {
  6205. SCHEMA_INIT_CHECK( false,
  6206. CFmtStr( "Pro-player entry '%s' has a duplicate code '%s'", pDef->GetName(), pData->GetCode() ) );
  6207. Assert( false );
  6208. delete pData;
  6209. continue;
  6210. }
  6211. m_mapProPlayersByAccountID.InsertOrReplace( pData->GetAccountID(), pData );
  6212. FOR_EACH_TRUE_SUBKEY( pDef->FindKey( "events" ), kvEvent )
  6213. {
  6214. int nEventID = Q_atoi( kvEvent->GetName() );
  6215. int nTeamID = kvEvent->GetInt( "team" );
  6216. if ( nEventID && nTeamID )
  6217. {
  6218. uint64 uiKey = ( uint64( uint32( nEventID ) ) << 32 ) | uint32( nTeamID );
  6219. MapProPlayersByEventIDTeamID_t::IndexType_t idx = m_mapProPlayersByEventIDTeamID.Find( uiKey );
  6220. if ( idx == m_mapProPlayersByEventIDTeamID.InvalidIndex() )
  6221. idx = m_mapProPlayersByEventIDTeamID.InsertOrReplace( uiKey, new CUtlVector< const CProPlayerData * > );
  6222. m_mapProPlayersByEventIDTeamID.Element( idx )->AddToTail( pData );
  6223. }
  6224. }
  6225. }
  6226. return SCHEMA_INIT_SUCCESS();
  6227. }
  6228. const CProPlayerData * CEconItemSchema::GetProPlayerDataByAccountID( uint32 unAccountID ) const
  6229. {
  6230. MapProPlayersByAccountID_t::IndexType_t idx = m_mapProPlayersByAccountID.Find( unAccountID );
  6231. return ( idx == m_mapProPlayersByAccountID.InvalidIndex() ) ? NULL : m_mapProPlayersByAccountID.Element( idx );
  6232. }
  6233. const CUtlVector< const CProPlayerData * > * CEconItemSchema::GetProPlayersDataForEventIDTeamID( int nEventID, int nTeamID ) const
  6234. {
  6235. uint64 uiKey = ( uint64( uint32( nEventID ) ) << 32 ) | uint32( nTeamID );
  6236. MapProPlayersByEventIDTeamID_t::IndexType_t idx = m_mapProPlayersByEventIDTeamID.Find( uiKey );
  6237. return ( idx != m_mapProPlayersByEventIDTeamID.InvalidIndex() )
  6238. ? m_mapProPlayersByEventIDTeamID.Element( idx ) : NULL;
  6239. }
  6240. bool CProPlayerData::BInitFromKeyValues( KeyValues *pDef, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  6241. {
  6242. uint32 unAccountID = Q_atoi( pDef->GetName() );
  6243. SCHEMA_INIT_CHECK(
  6244. unAccountID != 0,
  6245. CFmtStr( "Pro-player entry '%s' doesn't have a valid AccountID", pDef->GetName() ) );
  6246. if ( !unAccountID )
  6247. return false;
  6248. m_nAccountID = unAccountID;
  6249. char const *szName = pDef->GetString( "name" );
  6250. if ( !szName || !*szName )
  6251. {
  6252. SCHEMA_INIT_CHECK( false,
  6253. CFmtStr( "Pro-player entry '%s' has no name", pDef->GetName() ) );
  6254. Assert( false );
  6255. return false;
  6256. }
  6257. m_sName = szName;
  6258. char const *szCode = pDef->GetString( "code" );
  6259. if ( !szCode || !*szCode )
  6260. {
  6261. SCHEMA_INIT_CHECK( false,
  6262. CFmtStr( "Pro-player entry '%s' has no code", pDef->GetName() ) );
  6263. Assert( false );
  6264. return false;
  6265. }
  6266. HelperValidateLocalizationStringToken( CFmtStr( "#SFUI_ProPlayer_%s", szCode ) );
  6267. m_sCode = szCode;
  6268. char const *szGeo = pDef->GetString( "geo" );
  6269. SCHEMA_INIT_CHECK( szGeo && *szGeo,
  6270. CFmtStr( "Pro-player entry '%s' has no geo defined", pDef->GetName() ) );
  6271. Assert( szGeo && *szGeo );
  6272. HelperValidateLocalizationStringToken( CFmtStr( "#SFUI_Country_%s", szGeo ) );
  6273. m_sGeo = szGeo;
  6274. m_pKVItem = pDef->MakeCopy();
  6275. return true; // typically it should be return SCHEMA_INIT_SUCCESS(); but we don't want spurious "doesn't have a matching pro-player entry" errors
  6276. }
  6277. //-----------------------------------------------------------------------------
  6278. // Purpose: Initializes the recipes section of the schema
  6279. // Input: pKVRecipes - The recipes section of the KeyValues
  6280. // representation of the schema
  6281. // pVecErrors - An optional vector that will contain error messages if
  6282. // the init fails.
  6283. // Output: True if initialization succeeded, false otherwise
  6284. //-----------------------------------------------------------------------------
  6285. bool CEconItemSchema::BInitRecipes( KeyValues *pKVRecipes, CUtlVector<CUtlString> *pVecErrors )
  6286. {
  6287. m_mapRecipes.Purge();
  6288. // initialize the rewards sections
  6289. if ( NULL != pKVRecipes )
  6290. {
  6291. int nHighestRecipeIndex = 0;
  6292. FOR_EACH_TRUE_SUBKEY( pKVRecipes, pKVRecipe )
  6293. {
  6294. int nRecipeIndex = Q_atoi( pKVRecipe->GetName() );
  6295. // Remember highest recipe index so we can make more past that
  6296. if ( nHighestRecipeIndex < nRecipeIndex + 1 )
  6297. {
  6298. nHighestRecipeIndex = nRecipeIndex + 1;
  6299. }
  6300. int nMapIndex = m_mapRecipes.Find( nRecipeIndex );
  6301. // Make sure the recipe index is correct because we use this index as a reference
  6302. SCHEMA_INIT_CHECK(
  6303. !m_mapRecipes.IsValidIndex( nMapIndex ),
  6304. CFmtStr( "Duplicate recipe definition (%d)", nRecipeIndex ) );
  6305. // Check to make sure the index is positive
  6306. SCHEMA_INIT_CHECK(
  6307. nRecipeIndex >= 0,
  6308. CFmtStr( "Recipe definition index %d must be greater than or equal to zero", nRecipeIndex ) );
  6309. CEconCraftingRecipeDefinition *recipeDef = CreateCraftingRecipeDefinition();
  6310. SCHEMA_INIT_SUBSTEP( recipeDef->BInitFromKV( pKVRecipe, *this, pVecErrors ) );
  6311. // On clients, toss out any recipes that aren't always known. (Really, the clients
  6312. // shouldn't ever get these, but just in case.)
  6313. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  6314. if ( recipeDef->IsAlwaysKnown() )
  6315. #endif // !GC_DLL
  6316. {
  6317. #ifdef _DEBUG
  6318. // Sanity check in debug builds so that we know we aren't putting the same recipe in
  6319. // multiple times.
  6320. FOR_EACH_MAP_FAST( m_mapRecipes, i )
  6321. {
  6322. Assert( i != nRecipeIndex );
  6323. Assert( m_mapRecipes[i] != recipeDef );
  6324. }
  6325. #endif // _DEBUG
  6326. // Store this recipe.
  6327. m_mapRecipes.Insert( nRecipeIndex, recipeDef );
  6328. }
  6329. }
  6330. #ifdef CSTRIKE15
  6331. int nSetCount = GetItemSetCount();
  6332. for ( int i = 0; i < nSetCount; ++i )
  6333. {
  6334. const IEconItemSetDefinition *pSet = GetItemSet( i );
  6335. if ( !pSet || pSet->GetCraftReward() <= 0 )
  6336. continue;
  6337. CEconCraftingRecipeDefinition *recipeDef = CreateCraftingRecipeDefinition();
  6338. SCHEMA_INIT_SUBSTEP( recipeDef->BInitFromSet( pSet, *this, pVecErrors ) );
  6339. recipeDef->SetDefinitionIndex( nHighestRecipeIndex );
  6340. recipeDef->SetFilter( CRAFT_FILTER_COLLECT );
  6341. // Disabled for now until we ship collection badges!
  6342. recipeDef->SetDisabled( true );
  6343. m_mapRecipes.Insert( nHighestRecipeIndex, recipeDef );
  6344. nHighestRecipeIndex++;
  6345. }
  6346. #endif //#ifdef CSTRIKE15
  6347. }
  6348. return SCHEMA_INIT_SUCCESS();
  6349. }
  6350. //-----------------------------------------------------------------------------
  6351. // Purpose: Builds the name of a achievement in the form App<ID>.<AchName>
  6352. // Input: unAppID - native app ID
  6353. // pchNativeAchievementName - name of the achievement in its native app
  6354. // Returns: The combined achievement name
  6355. //-----------------------------------------------------------------------------
  6356. CUtlString CEconItemSchema::ComputeAchievementName( AppId_t unAppID, const char *pchNativeAchievementName )
  6357. {
  6358. return CFmtStr1024( "App%u.%s", unAppID, pchNativeAchievementName ).Access();
  6359. }
  6360. //-----------------------------------------------------------------------------
  6361. // Purpose: Initializes the achievement rewards section of the schema
  6362. // Input: pKVAchievementRewards - The achievement_rewards section of the KeyValues
  6363. // representation of the schema
  6364. // pVecErrors - An optional vector that will contain error messages if
  6365. // the init fails.
  6366. // Output: True if initialization succeeded, false otherwise
  6367. //-----------------------------------------------------------------------------
  6368. bool CEconItemSchema::BInitAchievementRewards( KeyValues *pKVAchievementRewards, CUtlVector<CUtlString> *pVecErrors )
  6369. {
  6370. m_dictAchievementRewards.Purge();
  6371. m_mapAchievementRewardsByData.PurgeAndDeleteElements();
  6372. // initialize the rewards sections
  6373. if ( NULL != pKVAchievementRewards )
  6374. {
  6375. FOR_EACH_SUBKEY( pKVAchievementRewards, pKVReward )
  6376. {
  6377. AchievementAward_t award;
  6378. if( pKVReward->GetDataType() == KeyValues::TYPE_NONE )
  6379. {
  6380. int32 nItemIndex = pKVReward->GetInt( "DefIndex", -1 );
  6381. if( nItemIndex != -1 )
  6382. {
  6383. award.m_vecDefIndex.AddToTail( (uint16)nItemIndex );
  6384. }
  6385. else
  6386. {
  6387. KeyValues *pkvItems = pKVReward->FindKey( "Items" );
  6388. SCHEMA_INIT_CHECK(
  6389. pkvItems != NULL,
  6390. CFmtStr( "Complex achievement %s must have an Items key or a DefIndex field", pKVReward->GetName() ) );
  6391. if( !pkvItems )
  6392. {
  6393. continue;
  6394. }
  6395. FOR_EACH_VALUE( pkvItems, pkvItem )
  6396. {
  6397. award.m_vecDefIndex.AddToTail( (uint16)Q_atoi( pkvItem->GetName() ) );
  6398. }
  6399. }
  6400. }
  6401. else
  6402. {
  6403. award.m_vecDefIndex.AddToTail( (uint16)pKVReward->GetInt("", -1 ) );
  6404. }
  6405. // make sure all the item types are valid
  6406. bool bFoundAllItems = true;
  6407. FOR_EACH_VEC( award.m_vecDefIndex, nItem )
  6408. {
  6409. const CEconItemDefinition *pDefn = GetItemDefinition( award.m_vecDefIndex[nItem] );
  6410. SCHEMA_INIT_CHECK(
  6411. pDefn != NULL,
  6412. CFmtStr( "Item definition index %d in achievement reward %s was not found", award.m_vecDefIndex[nItem], pKVReward->GetName() ) );
  6413. if( !pDefn )
  6414. {
  6415. bFoundAllItems = false;
  6416. }
  6417. }
  6418. if( !bFoundAllItems )
  6419. continue;
  6420. SCHEMA_INIT_CHECK(
  6421. award.m_vecDefIndex.Count() > 0,
  6422. CFmtStr( "Achievement reward %s has no items!", pKVReward->GetName() ) );
  6423. if( award.m_vecDefIndex.Count() == 0 )
  6424. continue;
  6425. award.m_unSourceAppId = k_uAppIdInvalid;
  6426. if( pKVReward->GetDataType() == KeyValues::TYPE_NONE )
  6427. {
  6428. // cross game achievement
  6429. award.m_sNativeName = pKVReward->GetName();
  6430. award.m_unAuditData = pKVReward->GetInt( "AuditData", 0 );
  6431. award.m_unSourceAppId = pKVReward->GetInt( "SourceAppID", award.m_unSourceAppId );
  6432. }
  6433. else
  6434. {
  6435. award.m_sNativeName = pKVReward->GetName();
  6436. award.m_unAuditData = 0;
  6437. }
  6438. AchievementAward_t *pAward = new AchievementAward_t;
  6439. *pAward = award;
  6440. m_dictAchievementRewards.Insert( ComputeAchievementName( pAward->m_unSourceAppId, pAward->m_sNativeName ), pAward );
  6441. m_mapAchievementRewardsByData.Insert( pAward->m_unAuditData, pAward );
  6442. }
  6443. }
  6444. return SCHEMA_INIT_SUCCESS();
  6445. }
  6446. #ifdef TF_CLIENT_DLL
  6447. //-----------------------------------------------------------------------------
  6448. // Purpose: Go through all items and cache the number of concrete items in each.
  6449. //-----------------------------------------------------------------------------
  6450. bool CEconItemSchema::BInitConcreteItemCounts( CUtlVector<CUtlString> *pVecErrors )
  6451. {
  6452. FOR_EACH_MAP_FAST( m_mapItems, i )
  6453. {
  6454. CEconItemDefinition *pItemDef = m_mapItems[ i ];
  6455. pItemDef->m_unNumConcreteItems = CalculateNumberOfConcreteItems( pItemDef );
  6456. }
  6457. return true;
  6458. }
  6459. #endif
  6460. //-----------------------------------------------------------------------------
  6461. // Purpose: Returns the number of actual "real" items referenced by the item definition
  6462. // (i.e. items that would take up space in the inventory)
  6463. //-----------------------------------------------------------------------------
  6464. int CEconItemSchema::CalculateNumberOfConcreteItems( const CEconItemDefinition *pItemDef )
  6465. {
  6466. AssertMsg( pItemDef, "NULL item definition! This should not happen!" );
  6467. if ( !pItemDef )
  6468. return 0;
  6469. if ( pItemDef->IsBundle() )
  6470. {
  6471. uint32 unNumConcreteItems = 0;
  6472. const bundleinfo_t *pBundle = pItemDef->GetBundleInfo();
  6473. Assert( pBundle );
  6474. FOR_EACH_VEC( pBundle->vecItemEntries, i )
  6475. {
  6476. unNumConcreteItems += CalculateNumberOfConcreteItems( GetItemDefinition( pBundle->vecItemEntries[i].m_nItemDef ) );
  6477. }
  6478. return unNumConcreteItems;
  6479. }
  6480. if ( pItemDef->GetItemClass() && !Q_strcmp( pItemDef->GetItemClass(), "map_token" ) )
  6481. return 0;
  6482. return 1;
  6483. }
  6484. bool CEconItemSchema::BInitStickerKits( KeyValues *pKVStickerKits, CUtlVector<CUtlString> *pVecErrors )
  6485. {
  6486. CStickerKit *pDefault = NULL;
  6487. FOR_EACH_TRUE_SUBKEY( pKVStickerKits, pKVEntry )
  6488. {
  6489. const char *pchName = pKVEntry->GetString( "name", "" );
  6490. if ( !pchName || pchName[ 0 ] == '\0' )
  6491. continue;
  6492. CStickerKit *pStickerKit = new CStickerKit();
  6493. if ( pStickerKit )
  6494. {
  6495. pStickerKit->nID = atoi( pKVEntry->GetName() );
  6496. if ( !pDefault )
  6497. {
  6498. if ( pStickerKit->nID == 0 )
  6499. pDefault = pStickerKit;
  6500. else
  6501. pDefault = m_mapStickerKits.Element( m_mapStickerKits.Find( 0 ) );
  6502. }
  6503. if ( !pStickerKit->InitFromKeyValues( pKVEntry, pDefault, pVecErrors ) )
  6504. {
  6505. SCHEMA_INIT_CHECK(
  6506. false,
  6507. CFmtStr( "Failed to initialize sticker kit ID %d '%s'", pStickerKit->nID, pStickerKit->sName.Get() ) );
  6508. continue;
  6509. }
  6510. if( m_mapStickerKits.Find( pStickerKit->nID ) != m_mapStickerKits.InvalidIndex() )
  6511. {
  6512. SCHEMA_INIT_CHECK(
  6513. false,
  6514. CFmtStr( "Duplicate sticker kit ID %d", pStickerKit->nID ) );
  6515. continue;
  6516. }
  6517. if( m_dictStickerKits.HasElement( pStickerKit->sName ) )
  6518. {
  6519. SCHEMA_INIT_CHECK(
  6520. false,
  6521. CFmtStr( "Duplicate sticker kit name '%s'", pStickerKit->sName.Get() ) );
  6522. continue;
  6523. }
  6524. m_mapStickerKits.Insert( pStickerKit->nID, pStickerKit );
  6525. m_dictStickerKits.Insert( pStickerKit->sName.Get(), pStickerKit );
  6526. }
  6527. }
  6528. return SCHEMA_INIT_SUCCESS();
  6529. }
  6530. bool CEconItemSchema::BInitStickerLists( KeyValues *pKVStickerLists, CUtlVector<CUtlString> *pVecErrors )
  6531. {
  6532. FOR_EACH_TRUE_SUBKEY( pKVStickerLists, pKVEntry )
  6533. {
  6534. char const *szName = pKVEntry->GetName();
  6535. if ( !szName || !*szName )
  6536. continue;
  6537. if( m_dictStickerKits.HasElement( szName ) )
  6538. {
  6539. SCHEMA_INIT_CHECK(
  6540. false,
  6541. CFmtStr( "Sticker list name duplicating sticker kit name '%s'", szName ) );
  6542. continue;
  6543. }
  6544. if( m_dictStickerLists.HasElement( szName ) )
  6545. {
  6546. SCHEMA_INIT_CHECK(
  6547. false,
  6548. CFmtStr( "Duplicate sticker list name '%s'", szName ) );
  6549. continue;
  6550. }
  6551. CStickerList *pStickerList = new CStickerList();
  6552. if ( !pStickerList->InitFromKeyValues( pKVEntry, pVecErrors ) )
  6553. {
  6554. SCHEMA_INIT_CHECK(
  6555. false,
  6556. CFmtStr( "Failed to initialize sticker list '%s'", szName ) );
  6557. continue;
  6558. }
  6559. m_dictStickerLists.Insert( szName, pStickerList );
  6560. }
  6561. return SCHEMA_INIT_SUCCESS();
  6562. }
  6563. bool CEconItemSchema::BInitPaintKits( KeyValues *pKVPaintKits, CUtlVector<CUtlString> *pVecErrors )
  6564. {
  6565. CPaintKit *pDefault = NULL;
  6566. FOR_EACH_TRUE_SUBKEY( pKVPaintKits, pKVEntry )
  6567. {
  6568. const char *pchName = pKVEntry->GetString( "name", "" );
  6569. if ( !pchName || pchName[ 0 ] == '\0' )
  6570. continue;
  6571. CPaintKit *pPaintKit = new CPaintKit();
  6572. if ( pPaintKit )
  6573. {
  6574. pPaintKit->nID = atoi( pKVEntry->GetName() );
  6575. if ( !pDefault )
  6576. {
  6577. if ( pPaintKit->nID == 0 )
  6578. pDefault = pPaintKit;
  6579. else
  6580. pDefault = m_mapPaintKits.Element( m_mapPaintKits.Find( 0 ) );
  6581. }
  6582. pPaintKit->InitFromKeyValues( pKVEntry, pDefault );
  6583. m_mapPaintKits.Insert( pPaintKit->nID, pPaintKit );
  6584. }
  6585. }
  6586. return SCHEMA_INIT_SUCCESS();
  6587. }
  6588. bool CEconItemSchema::BInitPaintKitsRarity( KeyValues *pKVPaintKitsRarity, CUtlVector<CUtlString> *pVecErrors )
  6589. {
  6590. CPaintKit *pDefault = const_cast< CPaintKit* >( GetPaintKitDefinitionByName( "default" ) );
  6591. if ( !pDefault )
  6592. {
  6593. SCHEMA_INIT_CHECK(
  6594. false,
  6595. CFmtStr( "Unable to find \"default\" paint kit in \"paint_kits_rarity\"" ) );
  6596. return false;
  6597. }
  6598. uint8 nRarity;
  6599. GetItemSchema()->BGetItemRarityFromName( pKVPaintKitsRarity->GetString( "default", "common" ), &nRarity );
  6600. pDefault->nRarity = nRarity;
  6601. FOR_EACH_SUBKEY( pKVPaintKitsRarity, pKVEntry )
  6602. {
  6603. CPaintKit *pPaintKit = const_cast< CPaintKit* >( GetPaintKitDefinitionByName( pKVEntry->GetName() ) );
  6604. if ( !pPaintKit )
  6605. continue;
  6606. const char *pchRarity = pKVEntry->GetString();
  6607. if ( pchRarity )
  6608. {
  6609. uint8 nRarity;
  6610. GetItemSchema()->BGetItemRarityFromName( pchRarity, &nRarity );
  6611. pPaintKit->nRarity = nRarity;
  6612. }
  6613. else
  6614. {
  6615. pPaintKit->nRarity = pDefault->nRarity;
  6616. }
  6617. }
  6618. return SCHEMA_INIT_SUCCESS();
  6619. }
  6620. //-----------------------------------------------------------------------------
  6621. // Purpose:
  6622. //-----------------------------------------------------------------------------
  6623. bool CEconItemSchema::BInitMusicDefs( KeyValues *pKVMusicDefs, CUtlVector<CUtlString> *pVecErrors )
  6624. {
  6625. FOR_EACH_TRUE_SUBKEY( pKVMusicDefs, pKVMusicDef )
  6626. {
  6627. CEconMusicDefinition *pNewMusicDef = new CEconMusicDefinition;
  6628. SCHEMA_INIT_SUBSTEP( pNewMusicDef->BInitFromKV( pKVMusicDef, *this, pVecErrors ) );
  6629. if( m_mapMusicDefs.Find( pNewMusicDef->GetID() ) != m_mapMusicDefs.InvalidIndex() )
  6630. {
  6631. SCHEMA_INIT_CHECK(
  6632. false,
  6633. CFmtStr( "Duplicate music definition id %d", pNewMusicDef->GetID() ) );
  6634. continue;
  6635. }
  6636. m_mapMusicDefs.Insert( pNewMusicDef->GetID(), pNewMusicDef );
  6637. }
  6638. return SCHEMA_INIT_SUCCESS();
  6639. }
  6640. //-----------------------------------------------------------------------------
  6641. // Purpose:
  6642. //-----------------------------------------------------------------------------
  6643. bool CEconItemSchema::BInitQuestDefs( KeyValues *pKVQuestDefs, CUtlVector<CUtlString> *pVecErrors )
  6644. {
  6645. m_mapQuestDefs.PurgeAndDeleteElements();
  6646. // initialize the Quest definitions
  6647. if ( NULL != pKVQuestDefs )
  6648. {
  6649. FOR_EACH_TRUE_SUBKEY( pKVQuestDefs, pKVQuestDef )
  6650. {
  6651. CEconQuestDefinition *pNewQuestDef = new CEconQuestDefinition;
  6652. SCHEMA_INIT_SUBSTEP( pNewQuestDef->BInitFromKV( pKVQuestDef, *this, pVecErrors ) );
  6653. if ( m_mapQuestDefs.Find( pNewQuestDef->GetID() ) != m_mapQuestDefs.InvalidIndex() )
  6654. {
  6655. SCHEMA_INIT_CHECK(
  6656. false,
  6657. CFmtStr( "Duplicate Quest definition id %d", pNewQuestDef->GetID() ) );
  6658. continue;
  6659. }
  6660. m_mapQuestDefs.Insert( pNewQuestDef->GetID(), pNewQuestDef );
  6661. }
  6662. }
  6663. return SCHEMA_INIT_SUCCESS();
  6664. }
  6665. bool CEconItemSchema::BInitQuestEvents( KeyValues *pKVQuestSchedule, CUtlVector<CUtlString> *pVecErrors )
  6666. {
  6667. m_vecQuestEvents.Purge();
  6668. // Removed for partner depot
  6669. return SCHEMA_INIT_SUCCESS();
  6670. }
  6671. const QuestEventsSchedule_t& CEconItemSchema::GetAndUpdateQuestEventsSchedule()
  6672. {
  6673. return m_mapQuestEventsSchedule;
  6674. }
  6675. //-----------------------------------------------------------------------------
  6676. // Purpose:
  6677. //-----------------------------------------------------------------------------
  6678. bool CEconItemSchema::BInitCampaignDefs( KeyValues *pKVCampaignDefs, CUtlVector<CUtlString> *pVecErrors )
  6679. {
  6680. m_mapCampaignDefs.PurgeAndDeleteElements();
  6681. // initialize the Campaign definitions
  6682. if ( NULL != pKVCampaignDefs )
  6683. {
  6684. FOR_EACH_TRUE_SUBKEY( pKVCampaignDefs, pKVCampaignDef )
  6685. {
  6686. CEconCampaignDefinition *pNewCampaignDef = new CEconCampaignDefinition;
  6687. SCHEMA_INIT_SUBSTEP( pNewCampaignDef->BInitFromKV( pKVCampaignDef, *this, pVecErrors ) );
  6688. if ( m_mapCampaignDefs.Find( pNewCampaignDef->GetID() ) != m_mapCampaignDefs.InvalidIndex() )
  6689. {
  6690. SCHEMA_INIT_CHECK(
  6691. false,
  6692. CFmtStr( "Duplicate Campaign definition id %d", pNewCampaignDef->GetID() ) );
  6693. continue;
  6694. }
  6695. m_mapCampaignDefs.Insert( pNewCampaignDef->GetID(), pNewCampaignDef );
  6696. }
  6697. }
  6698. return SCHEMA_INIT_SUCCESS();
  6699. }
  6700. attachedparticlesystem_t CEconItemSchema::GetAttachedParticleSystemInfo( KeyValues* pKVEntry, int32 nItemIndex ) const
  6701. {
  6702. attachedparticlesystem_t system;
  6703. system.pEffectKV = pKVEntry;
  6704. system.pszResourceName = pKVEntry->GetString( "resource", NULL );
  6705. system.pszSystemName = pKVEntry->GetString( "system", NULL );
  6706. system.pszAttachmentName = pKVEntry->GetString( "attachment", NULL );
  6707. system.bFollowRootBone = pKVEntry->GetInt( "attach_to_rootbone", 0 ) != 0;
  6708. system.bFlyingCourier = pKVEntry->GetInt( "flying_courier_effect", 0 ) != 0;
  6709. system.iCustomType = pKVEntry->GetInt( "custom_type", 0 );
  6710. system.iCount = 0;
  6711. system.nSystemID = nItemIndex;
  6712. system.nRootAttachType = StringFieldToInt( pKVEntry->GetString("attach_type"), g_szParticleAttachTypes, ARRAYSIZE(g_szParticleAttachTypes) );
  6713. int iAttachToEnt = StringFieldToInt( pKVEntry->GetString("attach_entity"), g_szParticleAttachToEnt, ARRAYSIZE(g_szParticleAttachToEnt) );
  6714. system.nAttachToEntity = ( iAttachToEnt == -1 ) ? ATTPART_TO_SELF : (attachedparticle_toent_t)iAttachToEnt;
  6715. // Find any control point settings
  6716. KeyValues *pKVControlPoints = pKVEntry->FindKey( "control_points" );
  6717. if ( pKVControlPoints )
  6718. {
  6719. FOR_EACH_TRUE_SUBKEY( pKVControlPoints, pKVPoint )
  6720. {
  6721. int iIdx = system.vecControlPoints.AddToTail();
  6722. system.vecControlPoints[iIdx].nControlPoint = pKVPoint->GetInt( "control_point_index", -1 );
  6723. system.vecControlPoints[iIdx].nAttachType = StringFieldToInt( pKVPoint->GetString("attach_type"), g_szParticleAttachTypes, ARRAYSIZE(g_szParticleAttachTypes) );
  6724. system.vecControlPoints[iIdx].pszAttachmentName = pKVPoint->GetString( "attachment", NULL );
  6725. float flVec[3];
  6726. V_StringToVector( flVec, pKVPoint->GetString( "position", "0 0 0" ) );
  6727. system.vecControlPoints[iIdx].vecPosition = Vector( flVec[0], flVec[1], flVec[2] );
  6728. }
  6729. }
  6730. return system;
  6731. }
  6732. //-----------------------------------------------------------------------------
  6733. // Purpose: Initializes the attribute-controlled-particle-systems section of the schema
  6734. //-----------------------------------------------------------------------------
  6735. bool CEconItemSchema::BInitAttributeControlledParticleSystems( KeyValues *pKVParticleSystems, CUtlVector<CUtlString> *pVecErrors )
  6736. {
  6737. m_mapAttributeControlledParticleSystems.Purge();
  6738. if ( NULL != pKVParticleSystems )
  6739. {
  6740. FOR_EACH_TRUE_SUBKEY( pKVParticleSystems, pKVEntry )
  6741. {
  6742. int32 nItemIndex = atoi( pKVEntry->GetName() );
  6743. // Check to make sure the index is positive
  6744. SCHEMA_INIT_CHECK(
  6745. nItemIndex > 0,
  6746. CFmtStr( "Particle system index %d greater than zero", nItemIndex ) );
  6747. if ( nItemIndex <= 0 )
  6748. continue;
  6749. int iIndex = m_mapAttributeControlledParticleSystems.Insert( nItemIndex );
  6750. attachedparticlesystem_t *system = &m_mapAttributeControlledParticleSystems[iIndex];
  6751. *system = GetAttachedParticleSystemInfo( pKVEntry, nItemIndex );
  6752. }
  6753. }
  6754. return SCHEMA_INIT_SUCCESS();
  6755. }
  6756. //-----------------------------------------------------------------------------
  6757. // Purpose: Inits data for items that can level up through kills, etc.
  6758. //-----------------------------------------------------------------------------
  6759. bool CEconItemSchema::BInitItemLevels( KeyValues *pKVItemLevels, CUtlVector<CUtlString> *pVecErrors )
  6760. {
  6761. m_vecItemLevelingData.RemoveAll();
  6762. // initialize the rewards sections
  6763. if ( NULL != pKVItemLevels )
  6764. {
  6765. FOR_EACH_TRUE_SUBKEY( pKVItemLevels, pKVItemLevelBlock )
  6766. {
  6767. const char *pszLevelBlockName = pKVItemLevelBlock->GetName();
  6768. SCHEMA_INIT_CHECK( GetItemLevelingData( pszLevelBlockName ) == NULL,
  6769. CFmtStr( "Duplicate leveling data block named \"%s\".", pszLevelBlockName ) );
  6770. // Allocate a new structure for this block and assign it. We'll fill in the contents later.
  6771. CUtlVector<CItemLevelingDefinition> *pLevelingData = new CUtlVector<CItemLevelingDefinition>;
  6772. m_vecItemLevelingData.Insert( pszLevelBlockName, pLevelingData );
  6773. FOR_EACH_TRUE_SUBKEY( pKVItemLevelBlock, pKVItemLevel )
  6774. {
  6775. int index = pLevelingData->AddToTail();
  6776. SCHEMA_INIT_SUBSTEP( (*pLevelingData)[index].BInitFromKV( pKVItemLevel, *this, pszLevelBlockName, pVecErrors ) );
  6777. }
  6778. }
  6779. }
  6780. return SCHEMA_INIT_SUCCESS();
  6781. }
  6782. //-----------------------------------------------------------------------------
  6783. // Purpose: Inits data for kill eater types.
  6784. //-----------------------------------------------------------------------------
  6785. bool CEconItemSchema::BInitKillEaterScoreTypes( KeyValues *pKVKillEaterScoreTypes, CUtlVector<CUtlString> *pVecErrors )
  6786. {
  6787. m_mapKillEaterScoreTypes.RemoveAll();
  6788. // initialize the rewards sections
  6789. if ( NULL != pKVKillEaterScoreTypes )
  6790. {
  6791. FOR_EACH_TRUE_SUBKEY( pKVKillEaterScoreTypes, pKVScoreType )
  6792. {
  6793. unsigned int unIndex = (unsigned int)atoi( pKVScoreType->GetName() );
  6794. SCHEMA_INIT_CHECK( m_mapKillEaterScoreTypes.Find( unIndex ) == KillEaterScoreMap_t::InvalidIndex(),
  6795. CFmtStr( "Duplicate kill eater score type index %u.", unIndex ) );
  6796. kill_eater_score_type_t ScoreType;
  6797. ScoreType.m_nValue = V_atoi( pKVScoreType->GetName() );
  6798. ScoreType.m_pszTypeString = pKVScoreType->GetString( "type_name" );
  6799. ScoreType.m_pszModelAttributeString = pKVScoreType->GetString( "model_attribute" );
  6800. #ifdef CLIENT_DLL
  6801. HelperValidateLocalizationStringToken( CFmtStr( "#KillEaterDescriptionNotice_%s", ScoreType.m_pszTypeString ) );
  6802. HelperValidateLocalizationStringToken( CFmtStr( "#KillEaterEventType_%s", ScoreType.m_pszTypeString ) );
  6803. #endif
  6804. // Default to on.
  6805. ScoreType.m_bUseLevelBlock = pKVScoreType->GetBool( "use_level_data", 1 );
  6806. const char *pszLevelBlockName = pKVScoreType->GetString( "level_data", "KillEaterRank" );
  6807. SCHEMA_INIT_CHECK( GetItemLevelingData( pszLevelBlockName ) != NULL,
  6808. CFmtStr( "Unable to find leveling data block named \"%s\" for kill eater score type %u.", pszLevelBlockName, unIndex ) );
  6809. ScoreType.m_pszLevelBlockName = pszLevelBlockName;
  6810. m_mapKillEaterScoreTypes.Insert( unIndex, ScoreType );
  6811. }
  6812. }
  6813. return SCHEMA_INIT_SUCCESS();
  6814. }
  6815. //-----------------------------------------------------------------------------
  6816. // Purpose:
  6817. //-----------------------------------------------------------------------------
  6818. const ISchemaAttributeType *CEconItemSchema::GetAttributeType( const char *pszAttrTypeName ) const
  6819. {
  6820. FOR_EACH_VEC( m_vecAttributeTypes, i )
  6821. {
  6822. if ( m_vecAttributeTypes[i].m_sName == pszAttrTypeName )
  6823. return m_vecAttributeTypes[i].m_pAttrType;
  6824. }
  6825. return NULL;
  6826. }
  6827. //-----------------------------------------------------------------------------
  6828. // CItemLevelingDefinition Accessor
  6829. //-----------------------------------------------------------------------------
  6830. const CItemLevelingDefinition *CEconItemSchema::GetItemLevelForScore( const char *pszLevelBlockName, uint32 unScore ) const
  6831. {
  6832. const CUtlVector<CItemLevelingDefinition> *pLevelingData = GetItemLevelingData( pszLevelBlockName );
  6833. if ( !pLevelingData )
  6834. return NULL;
  6835. if ( pLevelingData->Count() == 0 )
  6836. return NULL;
  6837. FOR_EACH_VEC( (*pLevelingData), i )
  6838. {
  6839. if ( unScore < (*pLevelingData)[i].GetRequiredScore() )
  6840. return &(*pLevelingData)[i];
  6841. }
  6842. return &(*pLevelingData).Tail();
  6843. }
  6844. //-----------------------------------------------------------------------------
  6845. // Kill eater score type accessor
  6846. //-----------------------------------------------------------------------------
  6847. const kill_eater_score_type_t *CEconItemSchema::FindKillEaterScoreType( uint32 unScoreType ) const
  6848. {
  6849. KillEaterScoreMap_t::IndexType_t i = m_mapKillEaterScoreTypes.Find( unScoreType );
  6850. if ( i == KillEaterScoreMap_t::InvalidIndex() )
  6851. return NULL;
  6852. return &m_mapKillEaterScoreTypes[i];
  6853. }
  6854. //-----------------------------------------------------------------------------
  6855. // Kill eater score type accessor
  6856. //-----------------------------------------------------------------------------
  6857. const char *CEconItemSchema::GetKillEaterScoreTypeLocString( uint32 unScoreType ) const
  6858. {
  6859. const kill_eater_score_type_t *pScoreType = FindKillEaterScoreType( unScoreType );
  6860. return pScoreType
  6861. ? pScoreType->m_pszTypeString
  6862. : NULL;
  6863. }
  6864. //-----------------------------------------------------------------------------
  6865. // Kill eater score type accessor for "use_level_data"
  6866. //-----------------------------------------------------------------------------
  6867. bool CEconItemSchema::GetKillEaterScoreTypeUseLevelData( uint32 unScoreType ) const
  6868. {
  6869. const kill_eater_score_type_t *pScoreType = FindKillEaterScoreType( unScoreType );
  6870. return pScoreType ? pScoreType->m_bUseLevelBlock : false;
  6871. }
  6872. //-----------------------------------------------------------------------------
  6873. // Kill eater score type accessor
  6874. //-----------------------------------------------------------------------------
  6875. const char *CEconItemSchema::GetKillEaterScoreTypeLevelingDataName( uint32 unScoreType ) const
  6876. {
  6877. const kill_eater_score_type_t *pScoreType = FindKillEaterScoreType( unScoreType );
  6878. return pScoreType
  6879. ? pScoreType->m_pszLevelBlockName
  6880. : NULL;
  6881. }
  6882. //-----------------------------------------------------------------------------
  6883. // Purpose:
  6884. //-----------------------------------------------------------------------------
  6885. econ_tag_handle_t CEconItemSchema::GetHandleForTag( const char *pszTagName )
  6886. {
  6887. EconTagDict_t::IndexType_t i = m_dictTags.Find( pszTagName );
  6888. if ( m_dictTags.IsValidIndex( i ) )
  6889. return i;
  6890. return m_dictTags.Insert( pszTagName );
  6891. }
  6892. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  6893. //-----------------------------------------------------------------------------
  6894. // Purpose: Clones the specified item definition, and returns the new item def.
  6895. //-----------------------------------------------------------------------------
  6896. void CEconItemSchema::ItemTesting_CreateTestDefinition( int iCloneFromItemDef, int iNewDef, KeyValues *pNewKV )
  6897. {
  6898. int nMapIndex = m_mapItems.Find( iNewDef );
  6899. if ( !m_mapItems.IsValidIndex( nMapIndex ) )
  6900. {
  6901. nMapIndex = m_mapItems.Insert( iNewDef, CreateEconItemDefinition() );
  6902. m_mapItemsSorted.Insert( iNewDef, m_mapItems[nMapIndex] );
  6903. }
  6904. // Find & copy the clone item def's data in
  6905. const CEconItemDefinition *pCloneDef = GetItemDefinition( iCloneFromItemDef );
  6906. if ( !pCloneDef )
  6907. return;
  6908. m_mapItems[nMapIndex]->CopyPolymorphic( pCloneDef );
  6909. // Then stomp it with the KV test contents
  6910. m_mapItems[nMapIndex]->BInitFromTestItemKVs( iNewDef, pNewKV, *this );
  6911. }
  6912. //-----------------------------------------------------------------------------
  6913. // Purpose: Discards the specified item definition
  6914. //-----------------------------------------------------------------------------
  6915. void CEconItemSchema::ItemTesting_DiscardTestDefinition( int iDef )
  6916. {
  6917. m_mapItems.Remove( iDef );
  6918. m_mapItemsSorted.Remove( iDef );
  6919. }
  6920. //-----------------------------------------------------------------------------
  6921. // Purpose: Initializes the armory data section of the schema
  6922. //-----------------------------------------------------------------------------
  6923. bool CEconItemSchema::BInitArmoryData( KeyValues *pKVArmoryData, CUtlVector<CUtlString> *pVecErrors )
  6924. {
  6925. m_dictArmoryItemDataStrings.Purge();
  6926. m_dictArmoryAttributeDataStrings.Purge();
  6927. if ( NULL != pKVArmoryData )
  6928. {
  6929. KeyValues *pKVItemTypes = pKVArmoryData->FindKey( "armory_item_types" );
  6930. if ( pKVItemTypes )
  6931. {
  6932. FOR_EACH_SUBKEY( pKVItemTypes, pKVEntry )
  6933. {
  6934. const char *pszDataKey = pKVEntry->GetName();
  6935. const char *pszLocString = pKVEntry->GetString();
  6936. m_dictArmoryItemTypesDataStrings.Insert( pszDataKey, pszLocString );
  6937. }
  6938. }
  6939. pKVItemTypes = pKVArmoryData->FindKey( "armory_item_classes" );
  6940. if ( pKVItemTypes )
  6941. {
  6942. FOR_EACH_SUBKEY( pKVItemTypes, pKVEntry )
  6943. {
  6944. const char *pszDataKey = pKVEntry->GetName();
  6945. const char *pszLocString = pKVEntry->GetString();
  6946. m_dictArmoryItemClassesDataStrings.Insert( pszDataKey, pszLocString );
  6947. }
  6948. }
  6949. KeyValues *pKVAttribs = pKVArmoryData->FindKey( "armory_attributes" );
  6950. if ( pKVAttribs )
  6951. {
  6952. FOR_EACH_SUBKEY( pKVAttribs, pKVEntry )
  6953. {
  6954. const char *pszDataKey = pKVEntry->GetName();
  6955. const char *pszLocString = pKVEntry->GetString();
  6956. m_dictArmoryAttributeDataStrings.Insert( pszDataKey, pszLocString );
  6957. }
  6958. }
  6959. KeyValues *pKVItems = pKVArmoryData->FindKey( "armory_items" );
  6960. if ( pKVItems )
  6961. {
  6962. FOR_EACH_SUBKEY( pKVItems, pKVEntry )
  6963. {
  6964. const char *pszDataKey = pKVEntry->GetName();
  6965. const char *pszLocString = pKVEntry->GetString();
  6966. m_dictArmoryItemDataStrings.Insert( pszDataKey, pszLocString );
  6967. }
  6968. }
  6969. }
  6970. return SCHEMA_INIT_SUCCESS();
  6971. }
  6972. #endif
  6973. //-----------------------------------------------------------------------------
  6974. // Purpose: Returns the achievement award that matches the provided defindex or NULL
  6975. // if there is no such award.
  6976. // Input: unData - The data field that would be stored in ItemAudit
  6977. //-----------------------------------------------------------------------------
  6978. const AchievementAward_t *CEconItemSchema::GetAchievementRewardByDefIndex( uint16 usDefIndex ) const
  6979. {
  6980. FOR_EACH_MAP_FAST( m_mapAchievementRewardsByData, nIndex )
  6981. {
  6982. if( m_mapAchievementRewardsByData[nIndex]->m_vecDefIndex.HasElement( usDefIndex ) )
  6983. return m_mapAchievementRewardsByData[nIndex];
  6984. }
  6985. return NULL;
  6986. }
  6987. //-----------------------------------------------------------------------------
  6988. // Purpose: Gets a rarity value for a name.
  6989. //-----------------------------------------------------------------------------
  6990. bool CEconItemSchema::BGetItemRarityFromName( const char *pchName, uint8 *nRarity ) const
  6991. {
  6992. if ( 0 == Q_stricmp( "any", pchName ) )
  6993. {
  6994. *nRarity = k_unItemRarity_Any;
  6995. return true;
  6996. }
  6997. FOR_EACH_MAP_FAST( m_mapRarities, i )
  6998. {
  6999. if ( 0 == Q_stricmp( m_mapRarities[i].GetName(), pchName ) )
  7000. {
  7001. *nRarity = m_mapRarities[i].GetDBValue();
  7002. return true;
  7003. }
  7004. }
  7005. return false;
  7006. }
  7007. //-----------------------------------------------------------------------------
  7008. // Purpose: Gets a quality value for a name.
  7009. // Input: pchName - The name to translate.
  7010. // nQuality - (out)The quality number for this name, if found.
  7011. // Output: True if the string matched a quality for this schema, false otherwise.
  7012. //-----------------------------------------------------------------------------
  7013. bool CEconItemSchema::BGetItemQualityFromName( const char *pchName, uint8 *nQuality ) const
  7014. {
  7015. if ( 0 == Q_stricmp( "any", pchName ) )
  7016. {
  7017. *nQuality = k_unItemQuality_Any;
  7018. return true;
  7019. }
  7020. FOR_EACH_MAP_FAST( m_mapQualities, i )
  7021. {
  7022. if ( 0 == Q_stricmp( m_mapQualities[i].GetName(), pchName ) )
  7023. {
  7024. *nQuality = m_mapQualities[i].GetDBValue();
  7025. return true;
  7026. }
  7027. }
  7028. return false;
  7029. }
  7030. //-----------------------------------------------------------------------------
  7031. // Purpose: Gets a quality definition for an index
  7032. // Input: nQuality - The quality to get.
  7033. // Output: A pointer to the desired definition, or NULL if it is not found.
  7034. //-----------------------------------------------------------------------------
  7035. const CEconItemQualityDefinition *CEconItemSchema::GetQualityDefinition( int nQuality ) const
  7036. {
  7037. int iIndex = m_mapQualities.Find( nQuality );
  7038. if ( m_mapQualities.IsValidIndex( iIndex ) )
  7039. return &m_mapQualities[iIndex];
  7040. return NULL;
  7041. }
  7042. const CEconItemQualityDefinition *CEconItemSchema::GetQualityDefinitionByName( const char *pszDefName ) const
  7043. {
  7044. FOR_EACH_MAP_FAST( m_mapQualities, i )
  7045. {
  7046. if ( !strcmp( pszDefName, m_mapQualities[i].GetName()) )
  7047. return &m_mapQualities[i];
  7048. }
  7049. return NULL;
  7050. }
  7051. const char* CEconItemSchema::GetQualityName( uint8 iQuality )
  7052. {
  7053. const CEconItemQualityDefinition* pItemQuality = GetQualityDefinition( iQuality );
  7054. if ( !pItemQuality )
  7055. return NULL;
  7056. else
  7057. return pItemQuality->GetName();
  7058. }
  7059. int CEconItemSchema::GetQualityIndex( const char* pszQuality )
  7060. {
  7061. const CEconItemQualityDefinition* pItemQuality = GetQualityDefinitionByName( pszQuality );
  7062. if ( pItemQuality )
  7063. return pItemQuality->GetDBValue();
  7064. else
  7065. return 0;
  7066. }
  7067. const CEconItemRarityDefinition *CEconItemSchema::GetRarityDefinitionByMapIndex( int nRarityIndex ) const
  7068. {
  7069. if ( m_mapRarities.IsValidIndex( nRarityIndex ) )
  7070. return &m_mapRarities[nRarityIndex];
  7071. return NULL;
  7072. }
  7073. const CEconItemRarityDefinition *CEconItemSchema::GetRarityDefinition( int nRarity ) const
  7074. {
  7075. int iIndex = m_mapRarities.Find( nRarity );
  7076. if ( m_mapRarities.IsValidIndex( iIndex ) )
  7077. return &m_mapRarities[iIndex];
  7078. return NULL;
  7079. }
  7080. const CEconItemRarityDefinition *CEconItemSchema::GetRarityDefinitionByName( const char *pszDefName ) const
  7081. {
  7082. FOR_EACH_MAP_FAST( m_mapRarities, i )
  7083. {
  7084. if ( !strcmp( pszDefName, m_mapRarities[i].GetName()) )
  7085. return &m_mapRarities[i];
  7086. }
  7087. return NULL;
  7088. }
  7089. const char* CEconItemSchema::GetRarityName( uint8 iRarity )
  7090. {
  7091. const CEconItemRarityDefinition* pItemRarity = GetRarityDefinition( iRarity );
  7092. if ( !pItemRarity )
  7093. return NULL;
  7094. else
  7095. return pItemRarity->GetName();
  7096. }
  7097. const char* CEconItemSchema::GetRarityLocKey( uint8 iRarity )
  7098. {
  7099. const CEconItemRarityDefinition* pItemRarity = GetRarityDefinition( iRarity );
  7100. if ( !pItemRarity )
  7101. return NULL;
  7102. else
  7103. return pItemRarity->GetLocKey();
  7104. }
  7105. const char* CEconItemSchema::GetRarityColor( uint8 iRarity )
  7106. {
  7107. const CEconItemRarityDefinition* pItemRarity = GetRarityDefinition( iRarity );
  7108. if ( !pItemRarity )
  7109. return NULL;
  7110. else
  7111. return GetHexColorForAttribColor( pItemRarity->GetAttribColor() );
  7112. }
  7113. const char* CEconItemSchema::GetRarityLootList( uint8 iRarity )
  7114. {
  7115. const CEconItemRarityDefinition* pItemRarity = GetRarityDefinition( iRarity );
  7116. if ( !pItemRarity )
  7117. return NULL;
  7118. else
  7119. return pItemRarity->GetLootList();
  7120. }
  7121. int CEconItemSchema::GetRarityIndex( const char* pszRarity )
  7122. {
  7123. const CEconItemRarityDefinition* pRarity = GetRarityDefinitionByName( pszRarity );
  7124. if ( pRarity )
  7125. return pRarity->GetDBValue();
  7126. else
  7127. return 0;
  7128. }
  7129. const CEconSoundMaterialDefinition *CEconItemSchema::GetSoundMaterialDefinitionByID( int nSoundMaterialID ) const
  7130. {
  7131. int iIndex = m_mapSoundMaterials.Find( nSoundMaterialID );
  7132. if ( m_mapSoundMaterials.IsValidIndex( iIndex ) )
  7133. return &m_mapSoundMaterials[iIndex];
  7134. return NULL;
  7135. }
  7136. const CEconSoundMaterialDefinition *CEconItemSchema::GetSoundMaterialDefinitionByName( const char *pszSoundMaterialName ) const
  7137. {
  7138. FOR_EACH_MAP_FAST( m_mapSoundMaterials, i )
  7139. {
  7140. if ( !strcmp( pszSoundMaterialName, m_mapSoundMaterials[i].GetName()) )
  7141. return &m_mapSoundMaterials[i];
  7142. }
  7143. return NULL;
  7144. }
  7145. const char* CEconItemSchema::GetSoundMaterialNameByID( int nSoundMaterialID )
  7146. {
  7147. const CEconSoundMaterialDefinition* pSoundMaterial = GetSoundMaterialDefinitionByID( nSoundMaterialID );
  7148. if ( !pSoundMaterial )
  7149. return NULL;
  7150. else
  7151. return pSoundMaterial->GetName();
  7152. }
  7153. int CEconItemSchema::GetSoundMaterialID( const char* pszSoundMaterial )
  7154. {
  7155. const CEconSoundMaterialDefinition* pSoundMaterial = GetSoundMaterialDefinitionByName( pszSoundMaterial );
  7156. if ( pSoundMaterial )
  7157. return pSoundMaterial->GetID();
  7158. else
  7159. return 0;
  7160. }
  7161. int CEconItemSchema::GetSoundMaterialIDByIndex( int nIndex )
  7162. {
  7163. // This makes for a slow iteration pattern. Only used by the item editor currently, should make it a UtlVector/UtlMap pair if it's too slow.
  7164. FOR_EACH_MAP( m_mapSoundMaterials, i )
  7165. {
  7166. nIndex--;
  7167. if ( nIndex < 0 )
  7168. {
  7169. return m_mapSoundMaterials[i].GetID();
  7170. }
  7171. }
  7172. return -1;
  7173. }
  7174. //-----------------------------------------------------------------------------
  7175. // Purpose: Gets an item definition for the specified map index
  7176. //-----------------------------------------------------------------------------
  7177. const CEconItemDefinition *CEconItemSchema::GetItemDefinitionByMapIndex( int iMapIndex ) const
  7178. {
  7179. if ( m_mapItems.IsValidIndex( iMapIndex ) )
  7180. return m_mapItems[iMapIndex];
  7181. return NULL;
  7182. }
  7183. //-----------------------------------------------------------------------------
  7184. // Purpose: Gets an item definition for the specified definition index
  7185. // Input: iItemIndex - The index of the desired definition.
  7186. // Output: A pointer to the desired definition, or NULL if it is not found.
  7187. //-----------------------------------------------------------------------------
  7188. CEconItemDefinition *CEconItemSchema::GetItemDefinitionMutable( int iItemIndex, bool bNoDefault )
  7189. {
  7190. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  7191. #if !defined(CSTRIKE_DLL)
  7192. AssertMsg( m_pDefaultItemDefinition, "No default item definition set up for item schema." );
  7193. #endif // CSTRIKE_DLL
  7194. #endif // defined(CLIENT_DLL) || defined(GAME_DLL)
  7195. int iIndex = m_mapItems.Find( iItemIndex );
  7196. if ( m_mapItems.IsValidIndex( iIndex ) )
  7197. return m_mapItems[iIndex];
  7198. if ( bNoDefault )
  7199. return NULL;
  7200. if ( m_pDefaultItemDefinition )
  7201. return m_pDefaultItemDefinition;
  7202. #if !defined(CSTRIKE_DLL)
  7203. // We shouldn't ever get down here, but all the same returning a valid pointer is very slightly
  7204. // a better plan than returning an invalid pointer to code that won't check to see if it's valid.
  7205. static CEconItemDefinition *s_pEmptyDefinition = CreateEconItemDefinition();
  7206. return s_pEmptyDefinition;
  7207. #else
  7208. return NULL;
  7209. #endif // CSTRIKE_DLL
  7210. }
  7211. const CEconItemDefinition *CEconItemSchema::GetItemDefinition( int iItemIndex, bool bNoDefault ) const
  7212. {
  7213. return const_cast<CEconItemSchema *>(this)->GetItemDefinitionMutable( iItemIndex, bNoDefault );
  7214. }
  7215. //-----------------------------------------------------------------------------
  7216. // Purpose: Gets an item definition that has a name matching the specified name.
  7217. // Input: pszDefName - The name of the desired definition.
  7218. // Output: A pointer to the desired definition, or NULL if it is not found.
  7219. //-----------------------------------------------------------------------------
  7220. CEconItemDefinition *CEconItemSchema::GetItemDefinitionByName( const char *pszDefName )
  7221. {
  7222. SNPROF(__PRETTY_FUNCTION__);
  7223. if ( m_bSchemaParsingItems )
  7224. {
  7225. AssertMsg( 0, "GetItemDefinitionByName while parsing item definitions. This is not a valid operation." );
  7226. return NULL;
  7227. }
  7228. // This shouldn't happen, but let's not crash if it ever does.
  7229. Assert( pszDefName != NULL );
  7230. if ( pszDefName == NULL )
  7231. return NULL;
  7232. FOR_EACH_MAP_FAST( m_mapItems, i )
  7233. {
  7234. if ( !strcmp( pszDefName, m_mapItems[i]->GetDefinitionName()) )
  7235. return m_mapItems[i];
  7236. }
  7237. return NULL;
  7238. }
  7239. const CEconItemDefinition *CEconItemSchema::GetItemDefinitionByName( const char *pszDefName ) const
  7240. {
  7241. return const_cast<CEconItemSchema *>(this)->GetItemDefinitionByName( pszDefName );
  7242. }
  7243. //-----------------------------------------------------------------------------
  7244. // Purpose: Gets an attribute definition for an index
  7245. // Input: iAttribIndex - The index of the desired definition.
  7246. // Output: A pointer to the desired definition, or NULL if it is not found.
  7247. //-----------------------------------------------------------------------------
  7248. const CEconItemAttributeDefinition *CEconItemSchema::GetAttributeDefinition( int iAttribIndex ) const
  7249. {
  7250. if ( m_mapAttributesContainer.IsValidIndex( iAttribIndex ) )
  7251. return m_mapAttributesContainer[iAttribIndex];
  7252. return NULL;
  7253. }
  7254. const CEconItemAttributeDefinition *CEconItemSchema::GetAttributeDefinitionByName( const char *pszDefName ) const
  7255. {
  7256. VPROF_BUDGET( "CEconItemSchema::GetAttributeDefinitionByName", VPROF_BUDGETGROUP_STEAM );
  7257. SNPROF(__PRETTY_FUNCTION__);
  7258. FOR_EACH_VEC( m_mapAttributesContainer, i )
  7259. {
  7260. if ( m_mapAttributesContainer[i] && !strcmp( pszDefName, m_mapAttributesContainer[i]->GetDefinitionName()) )
  7261. return m_mapAttributesContainer[i];
  7262. }
  7263. return NULL;
  7264. }
  7265. //-----------------------------------------------------------------------------
  7266. // Purpose: Gets a recipe definition for an index
  7267. // Input: iRecipeIndex - The index of the desired definition.
  7268. // Output: A pointer to the desired definition, or NULL if it is not found.
  7269. //-----------------------------------------------------------------------------
  7270. const CEconCraftingRecipeDefinition *CEconItemSchema::GetRecipeDefinition( int iRecipeIndex ) const
  7271. {
  7272. int iIndex = m_mapRecipes.Find( iRecipeIndex );
  7273. if ( m_mapRecipes.IsValidIndex( iIndex ) )
  7274. return m_mapRecipes[iIndex];
  7275. return NULL;
  7276. }
  7277. //-----------------------------------------------------------------------------
  7278. void CEconItemSchema::AddStickerKitDefinition( int iStickerKitID, CStickerKit *pStickerKit )
  7279. {
  7280. int iIndex = m_mapStickerKits.Find( iStickerKitID );
  7281. if ( m_mapStickerKits.IsValidIndex( iIndex ) )
  7282. {
  7283. m_mapStickerKits.Remove( iStickerKitID );
  7284. }
  7285. m_mapStickerKits.Insert( iStickerKitID, pStickerKit );
  7286. }
  7287. void CEconItemSchema::RemoveStickerKitDefinition( int iStickerKitID )
  7288. {
  7289. m_mapStickerKits.Remove( iStickerKitID );
  7290. }
  7291. const CStickerKit *CEconItemSchema::GetStickerKitDefinition( int iStickerKitID ) const
  7292. {
  7293. int iIndex = m_mapStickerKits.Find( iStickerKitID );
  7294. if ( m_mapStickerKits.IsValidIndex( iIndex ) )
  7295. return m_mapStickerKits[iIndex];
  7296. return NULL;
  7297. }
  7298. const CStickerKit *CEconItemSchema::GetStickerKitDefinitionByMapIndex( int iMapIndex )
  7299. {
  7300. if ( m_mapStickerKits.IsValidIndex( iMapIndex ) )
  7301. return m_mapStickerKits[ iMapIndex ];
  7302. return NULL;
  7303. }
  7304. const CStickerKit *CEconItemSchema::GetStickerKitDefinitionByName( const char *pchName ) const
  7305. {
  7306. int idx = m_dictStickerKits.Find( pchName );
  7307. if ( idx != m_dictStickerKits.InvalidIndex() )
  7308. return m_dictStickerKits.Element( idx );
  7309. else
  7310. return NULL;
  7311. }
  7312. const CStickerList *CEconItemSchema::GetStickerListDefinitionByName( const char *pchName ) const
  7313. {
  7314. int idx = m_dictStickerLists.Find( pchName );
  7315. if ( idx != m_dictStickerLists.InvalidIndex() )
  7316. return m_dictStickerLists.Element( idx );
  7317. else
  7318. return NULL;
  7319. }
  7320. const CEconMusicDefinition *CEconItemSchema::GetMusicKitDefinitionByName( const char *pchName ) const
  7321. {
  7322. FOR_EACH_MAP_FAST( m_mapMusicDefs, i )
  7323. {
  7324. if ( !V_strcmp( m_mapMusicDefs.Element( i )->GetName(), pchName ) )
  7325. {
  7326. return m_mapMusicDefs.Element( i );
  7327. }
  7328. }
  7329. return NULL;
  7330. }
  7331. //-----------------------------------------------------------------------------
  7332. void CEconItemSchema::AddPaintKitDefinition( int iPaintKitID, CPaintKit *pPaintKit )
  7333. {
  7334. int iIndex = m_mapPaintKits.Find( iPaintKitID );
  7335. if ( m_mapPaintKits.IsValidIndex( iIndex ) )
  7336. {
  7337. m_mapPaintKits.Remove( iPaintKitID );
  7338. }
  7339. m_mapPaintKits.Insert( iPaintKitID, pPaintKit );
  7340. }
  7341. void CEconItemSchema::RemovePaintKitDefinition( int iPaintKitID )
  7342. {
  7343. m_mapPaintKits.Remove( iPaintKitID );
  7344. }
  7345. const CPaintKit *CEconItemSchema::GetPaintKitDefinition( int iPaintKitID ) const
  7346. {
  7347. int iIndex = m_mapPaintKits.Find( iPaintKitID );
  7348. if ( m_mapPaintKits.IsValidIndex( iIndex ) )
  7349. return m_mapPaintKits[iIndex];
  7350. return NULL;
  7351. }
  7352. const CPaintKit *CEconItemSchema::GetPaintKitDefinitionByMapIndex( int iMapIndex )
  7353. {
  7354. if ( m_mapPaintKits.IsValidIndex( iMapIndex ) )
  7355. return m_mapPaintKits[ iMapIndex ];
  7356. return NULL;
  7357. }
  7358. const CPaintKit *CEconItemSchema::GetPaintKitDefinitionByName( const char *pchName ) const
  7359. {
  7360. FOR_EACH_MAP_FAST( m_mapPaintKits, i )
  7361. {
  7362. CPaintKit *pPaintKit = m_mapPaintKits[ i ];
  7363. if ( V_strcmp( pPaintKit->sName.Access(), pchName ) == 0 )
  7364. {
  7365. return pPaintKit;
  7366. }
  7367. }
  7368. return NULL;
  7369. }
  7370. const unsigned int CEconItemSchema::GetPaintKitCount() const
  7371. {
  7372. return m_mapPaintKits.Count();
  7373. }
  7374. //-----------------------------------------------------------------------------
  7375. // Purpose:
  7376. //-----------------------------------------------------------------------------
  7377. const CEconColorDefinition *CEconItemSchema::GetColorDefinitionByName( const char *pszDefName ) const
  7378. {
  7379. FOR_EACH_VEC( m_vecColorDefs, i )
  7380. {
  7381. if ( !Q_stricmp( m_vecColorDefs[i]->GetName(), pszDefName ) )
  7382. return m_vecColorDefs[i];
  7383. }
  7384. return NULL;
  7385. }
  7386. //-----------------------------------------------------------------------------
  7387. // Purpose:
  7388. //-----------------------------------------------------------------------------
  7389. const CEconGraffitiTintDefinition * CEconItemSchema::GetGraffitiTintDefinitionByID( int nID ) const
  7390. {
  7391. return m_vecGraffitiTintDefs.IsValidIndex( nID ) ? m_vecGraffitiTintDefs[ nID ] : NULL;
  7392. }
  7393. //-----------------------------------------------------------------------------
  7394. // Purpose:
  7395. //-----------------------------------------------------------------------------
  7396. const CEconGraffitiTintDefinition * CEconItemSchema::GetGraffitiTintDefinitionByName( const char *pszDefName ) const
  7397. {
  7398. UtlSymId_t utlsym = m_mapGraffitiTintByName.Find( pszDefName );
  7399. return ( utlsym != UTL_INVAL_SYMBOL ) ? m_mapGraffitiTintByName[ utlsym ] : NULL;
  7400. }
  7401. //-----------------------------------------------------------------------------
  7402. // Purpose:
  7403. //-----------------------------------------------------------------------------
  7404. const CEconMusicDefinition *CEconItemSchema::GetMusicDefinition( uint32 unMusicID ) const
  7405. {
  7406. int iIndex = m_mapMusicDefs.Find( unMusicID );
  7407. if ( m_mapMusicDefs.IsValidIndex( iIndex ) )
  7408. return m_mapMusicDefs[iIndex];
  7409. return NULL;
  7410. }
  7411. //-----------------------------------------------------------------------------
  7412. // Purpose:
  7413. //-----------------------------------------------------------------------------
  7414. CEconQuestDefinition *CEconItemSchema::GetQuestDefinition( uint32 unQuestID ) const
  7415. {
  7416. int iIndex = m_mapQuestDefs.Find( unQuestID );
  7417. if ( m_mapQuestDefs.IsValidIndex( iIndex ) )
  7418. return m_mapQuestDefs[ iIndex ];
  7419. return NULL;
  7420. }
  7421. //-----------------------------------------------------------------------------
  7422. // Purpose:
  7423. //-----------------------------------------------------------------------------
  7424. CEconCampaignDefinition *CEconItemSchema::GetCampaignDefinition( uint32 unCampaignID ) const
  7425. {
  7426. int iIndex = m_mapCampaignDefs.Find( unCampaignID );
  7427. if ( m_mapCampaignDefs.IsValidIndex( iIndex ) )
  7428. return m_mapCampaignDefs[ iIndex ];
  7429. return NULL;
  7430. }
  7431. //-----------------------------------------------------------------------------
  7432. // Purpose: Return the attribute specified attachedparticlesystem_t* associated with the given id.
  7433. //-----------------------------------------------------------------------------
  7434. attachedparticlesystem_t* CEconItemSchema::GetAttributeControlledParticleSystem( int id )
  7435. {
  7436. int iIndex = m_mapAttributeControlledParticleSystems.Find( id );
  7437. if ( m_mapAttributeControlledParticleSystems.IsValidIndex( iIndex ) )
  7438. return &m_mapAttributeControlledParticleSystems[iIndex];
  7439. return NULL;
  7440. }
  7441. attachedparticlesystem_t* CEconItemSchema::GetAttributeControlledParticleSystemByIndex( int id )
  7442. {
  7443. return &m_mapAttributeControlledParticleSystems[id];
  7444. }
  7445. attachedparticlesystem_t* CEconItemSchema::FindAttributeControlledParticleSystem( const char *pchSystemName, int *outID )
  7446. {
  7447. FOR_EACH_MAP_FAST( m_mapAttributeControlledParticleSystems, nSystem )
  7448. {
  7449. if( !Q_stricmp( m_mapAttributeControlledParticleSystems[nSystem].pszSystemName, pchSystemName ) )
  7450. {
  7451. if ( outID )
  7452. {
  7453. *outID = nSystem;
  7454. }
  7455. return &m_mapAttributeControlledParticleSystems[nSystem];
  7456. }
  7457. }
  7458. if ( outID )
  7459. {
  7460. *outID = -1;
  7461. }
  7462. return NULL;
  7463. }
  7464. bool CEconItemSchema::BPostSchemaInitStartupChecks( CUtlVector<CUtlString> *pVecErrors )
  7465. {
  7466. #if defined( GC_DLL ) || defined( CLIENT_DLL )
  7467. // confirm that all stickers that reference players have valid link
  7468. FOR_EACH_MAP_FAST( m_mapStickerKits, i )
  7469. {
  7470. CStickerKit * pStickerKit = m_mapStickerKits.Element( i );
  7471. if ( !pStickerKit->m_nPlayerID ) continue;
  7472. SCHEMA_INIT_CHECK(
  7473. ( m_mapProPlayersByAccountID.Find( pStickerKit->m_nPlayerID ) != m_mapProPlayersByAccountID.InvalidIndex() ),
  7474. CFmtStr( "Pro-player sticker %d reference player %u which doesn't have a matching pro-player entry", pStickerKit->nID, pStickerKit->m_nPlayerID ) );
  7475. }
  7476. #endif // #if defined( GC_DLL ) || defined( CLIENT_DLL )
  7477. #ifdef CLIENT_DLL
  7478. //// Confirm that every story block expression references only existing quest indices.
  7479. FOR_EACH_MAP_FAST( m_mapCampaignDefs, iC )
  7480. {
  7481. FOR_EACH_MAP_FAST( m_mapCampaignDefs.Element( iC )->GetCampaignNodes(), iCn )
  7482. {
  7483. CEconCampaignDefinition::CEconCampaignNodeDefinition * pCNodeDef = m_mapCampaignDefs.Element( iC )->GetCampaignNodes().Element( iCn );
  7484. FOR_EACH_VEC( pCNodeDef->GetStoryBlocks(), iSB )
  7485. {
  7486. KeyValues * pKVExpressionTokens = new KeyValues( "ExpressionTokens" );
  7487. KeyValues::AutoDelete autodelete( pKVExpressionTokens );
  7488. CEconQuestDefinition::TokenizeQuestExpression( pCNodeDef->GetStoryBlocks()[ iSB ]->GetStoryBlockExpression(), pKVExpressionTokens );
  7489. FOR_EACH_SUBKEY( pKVExpressionTokens, kvSubKey )
  7490. {
  7491. int iQ = m_mapQuestDefs.Find( V_atoi( kvSubKey->GetName() ) );
  7492. SCHEMA_INIT_CHECK(
  7493. ( m_mapQuestDefs.IsValidIndex( iQ ) ),
  7494. CFmtStr( "campaign %d, node %d, Story_block %d, references a non-existant quest index %d.", iC, iCn, iSB, iQ ) );
  7495. }
  7496. }
  7497. }
  7498. }
  7499. // confirm that all quest expressions are valid
  7500. FOR_EACH_MAP_FAST( m_mapQuestDefs, i )
  7501. {
  7502. CEconQuestDefinition * pQuestDef = m_mapQuestDefs.Element( i );
  7503. SCHEMA_INIT_CHECK(
  7504. ( CEconQuestDefinition::IsQuestExpressionValid( pQuestDef->GetQuestExpression() ) ),
  7505. CFmtStr( "Quest definition %s specifies an expression that does not evaluate.", pQuestDef->GetName() ) );
  7506. if ( pQuestDef->GetQuestBonusExpression() && pQuestDef->GetQuestBonusExpression()[ 0 ] )
  7507. {
  7508. SCHEMA_INIT_CHECK(
  7509. ( CEconQuestDefinition::IsQuestExpressionValid( pQuestDef->GetQuestBonusExpression() ) ),
  7510. CFmtStr( "Quest definition %s specifies a bonus expression that does not evaluate.", pQuestDef->GetName() ) );
  7511. }
  7512. }
  7513. #endif // CLIENT_DLL
  7514. return true;
  7515. }
  7516. //-----------------------------------------------------------------------------
  7517. //
  7518. //-----------------------------------------------------------------------------
  7519. CItemLevelingDefinition::CItemLevelingDefinition( void )
  7520. {
  7521. }
  7522. //-----------------------------------------------------------------------------
  7523. // Purpose: Copy constructor
  7524. //-----------------------------------------------------------------------------
  7525. CItemLevelingDefinition::CItemLevelingDefinition( const CItemLevelingDefinition &that )
  7526. {
  7527. (*this) = that;
  7528. }
  7529. //-----------------------------------------------------------------------------
  7530. //
  7531. //-----------------------------------------------------------------------------
  7532. CItemLevelingDefinition::~CItemLevelingDefinition()
  7533. {
  7534. // Free up strdup() memory.
  7535. free( m_pszLocalizedName_LocalStorage );
  7536. CUtlVector< CUtlString > vecErrors;
  7537. bool bSuccess = GEconItemSchema().BInit( "scripts/items/unencrypted/items_master.txt", "MOD", &vecErrors );
  7538. if( !bSuccess )
  7539. {
  7540. FOR_EACH_VEC( vecErrors, nError )
  7541. {
  7542. Msg( "%s", vecErrors[nError].String() );
  7543. }
  7544. }
  7545. }
  7546. //-----------------------------------------------------------------------------
  7547. // Purpose: Operator=
  7548. //-----------------------------------------------------------------------------
  7549. CItemLevelingDefinition &CItemLevelingDefinition::operator=( const CItemLevelingDefinition &other )
  7550. {
  7551. m_unLevel = other.m_unLevel;
  7552. m_unRequiredScore = other.m_unRequiredScore;
  7553. m_pszLocalizedName_LocalStorage = strdup( other.m_pszLocalizedName_LocalStorage );
  7554. return *this;
  7555. }
  7556. //-----------------------------------------------------------------------------
  7557. //
  7558. //-----------------------------------------------------------------------------
  7559. bool CItemLevelingDefinition::BInitFromKV( KeyValues *pKVItemLevel, CEconItemSchema &pschema, const char *pszLevelBlockName, CUtlVector<CUtlString> *pVecErrors )
  7560. {
  7561. m_unLevel = Q_atoi( pKVItemLevel->GetName() );
  7562. m_unRequiredScore = pKVItemLevel->GetInt( "score" );
  7563. m_pszLocalizedName_LocalStorage = strdup( pKVItemLevel->GetString( "rank_name", CFmtStr( "%s%i", pszLevelBlockName, m_unLevel ).Access() ) );
  7564. return SCHEMA_INIT_SUCCESS();
  7565. }
  7566. #ifdef GAME_DLL
  7567. void ReloadMasterItemSchema( void )
  7568. {
  7569. // This command does nothing on the public universe.
  7570. if ( steamapicontext->SteamUtils() && steamapicontext->SteamUtils()->GetConnectedUniverse() == k_EUniversePublic )
  7571. return;
  7572. CUtlVector< CUtlString > vecErrors;
  7573. bool bSuccess = GEconItemSchema().BInit( "scripts/items/unencrypted/items_master.txt", "MOD", &vecErrors );
  7574. if( !bSuccess )
  7575. {
  7576. FOR_EACH_VEC( vecErrors, nError )
  7577. {
  7578. Msg( "%s", vecErrors[nError].String() );
  7579. }
  7580. }
  7581. }
  7582. CON_COMMAND_F( load_master_item_schema, "Reloads the item master schema.", FCVAR_GAMEDLL | FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY | FCVAR_HIDDEN )
  7583. {
  7584. ReloadMasterItemSchema();
  7585. }
  7586. #endif