//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: EconItemSchema: Defines a schema for econ items
//
//=============================================================================

#ifndef ECONITEMSCHEMA_H
#define ECONITEMSCHEMA_H
#ifdef _WIN32
#pragma once
#endif

// Valve code doesn't play nicely with standard headers on some platforms sometimes.
#ifdef min
	#undef min
#endif

#ifdef max
	#undef max
#endif

#include <string>

#include "KeyValues.h"
#include "tier1/utldict.h"
#include "tier1/utlhashmaplarge.h"
#include "econ_item_constants.h"

#include "item_selection_criteria.h"
#include "bitvec.h"
#include "language.h"
#include "smartptr.h"
#include "rtime.h"
#include "checksum_sha1.h"

#if defined(CLIENT_DLL) || defined(GAME_DLL)
#include "engine/ivmodelinfo.h"
#include "engine/ivmodelrender.h"
#include "ilocalize.h"
#endif
#include "gamestringpool.h"

class CEconItemSchema;
class CEconItem;
class CEconSharedObjectCache;
class CSOItemRecipe;

union attribute_data_union_t
{
	float asFloat;
	uint32 asUint32;
	byte *asBlobPointer;
};

struct static_attrib_t
{
	static_attrib_t()
	{
		iDefIndex = 0;
		m_value.asBlobPointer = NULL;
#ifdef GC_DLL
		bForceGCToGenerate = false;
		m_pKVCustomData = NULL;
#endif // GC_DLL
	}

	~static_attrib_t()
	{
#ifdef GC_DLL
		if ( m_pKVCustomData )
			m_pKVCustomData->deleteThis();
		m_pKVCustomData = NULL;
#endif
	}

	static_attrib_t( const static_attrib_t& rhs )
	{
		iDefIndex = rhs.iDefIndex;
		m_value = rhs.m_value;
#ifdef GC_DLL
		m_pKVCustomData = rhs.m_pKVCustomData ? rhs.m_pKVCustomData->MakeCopy() : NULL;
		bForceGCToGenerate = rhs.bForceGCToGenerate;
#endif
	}

	attrib_definition_index_t	iDefIndex;
	attribute_data_union_t m_value;
#ifdef GC_DLL
	bool	bForceGCToGenerate;
	KeyValues *m_pKVCustomData;
#endif // GC_DLL

	// Parses a single subsection from a multi-line attribute block that looks like:
	//
	//		"attributes"
	//		{
	//			"cannot trade"
	//			{
	//				"attribute_class"	"cannot_trade"
	//				"value"				"1"
	//			}
	//			"kill eater"
	//			{
	//				"attribute_class"	"kill_eater"
	//				"force_gc_to_generate" "1"
	//				"use_custom_logic"	"gifts_given_out"
	//			}
	//		}
	//
	// The "force_gc_to_generate" and "use_custom_logic" fields will only be parsed on the GC. Will return
	// true/false based on whether the whole attribute and value parsed successfully.
	bool BInitFromKV_MultiLine( const char *pszContext, KeyValues *pKVAttribute, CUtlVector<CUtlString> *pVecErrors );

	// Parses a single subsection from a single-line attribute block that looks like:
	//
	//		CharacterAttributes 
	//		{
	//			"increase buff duration"	9.0
	//			"damage bonus"	2.0 
	//		}
	//
	// It's impossible to specify GC-generated attributes in this format. Will return true/false based on
	// whether the whole attribute and value parsed successfully.
	bool BInitFromKV_SingleLine( const char *pszContext, KeyValues *pKVAttribute, CUtlVector<CUtlString> *pVecErrors, bool bEnableTerribleBackwardsCompatibilitySchemaParsingCode = true );

	// Data access helpers.
	const class CEconItemAttributeDefinition *GetAttributeDefinition() const;
	const class ISchemaAttributeType *GetAttributeType() const;
};

typedef	uint16	equipped_class_t;
typedef uint16	equipped_slot_t;
typedef uint8	equipped_preset_t;

#define INVALID_EQUIPPED_SLOT	((equipped_slot_t)-1)
#define INVALID_STYLE_INDEX		((style_index_t)-1)
#define INVALID_PRESET_INDEX	((equipped_preset_t)-1)

enum EEquipType_t
{
	EQUIP_TYPE_CLASS = 0,
	EQUIP_TYPE_ACCOUNT,

	EQUIP_TYPE_INVALID,
};

// Streamable weapons cause stutters when people enter PVS. Turn it off for now.
// #define WITH_STREAMABLE_WEAPONS

//-----------------------------------------------------------------------------
// IEconItemPropertyGenerator
//-----------------------------------------------------------------------------
class IEconItemPropertyGenerator
{
public:
	virtual ~IEconItemPropertyGenerator() { }

	MUST_CHECK_RETURN virtual bool BGenerateProperties( CEconItem *pItem ) const = 0;
};

//-----------------------------------------------------------------------------
// Item Series
//-----------------------------------------------------------------------------
class CEconItemSeriesDefinition
{
public:
	CEconItemSeriesDefinition( void );
	CEconItemSeriesDefinition( const CEconItemSeriesDefinition &that );
	CEconItemSeriesDefinition &operator=( const CEconItemSeriesDefinition& rhs );

	~CEconItemSeriesDefinition( void ) { }

	bool		BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors = NULL );

	int32		GetDBValue( void ) const			{ return m_nValue; }
	const char	*GetName( void ) const				{ return !m_strName.IsEmpty() ? m_strName.String() : "unknown"; }
	const char	*GetLocKey( void ) const			{ return !m_strLockKey.IsEmpty() ? m_strLockKey.String() : "unknown"; }
	const char	*GetUiFile( void ) const			{ return !m_strUiFile.IsEmpty() ? m_strUiFile.String() : "unknown"; }

private:

	// The value that the game/DB will know this series by
	int32		m_nValue;

	CUtlString	m_strName;			// Key Name
	CUtlString	m_strLockKey;		// Localization key
	CUtlString	m_strUiFile;		// Ui File (.res file)
};
//-----------------------------------------------------------------------------
// CEconItemRarityDefinition
//-----------------------------------------------------------------------------
class CEconItemRarityDefinition
{
public:
	CEconItemRarityDefinition( void );
	
	~CEconItemRarityDefinition( void ) { }

	bool		BInitFromKV( KeyValues *pKVItem, KeyValues *pKVRarityWeights, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors = NULL );

	int32		GetDBValue( void ) const			{ return m_nValue; }
	const char	*GetName( void ) const				{ return !m_strName.IsEmpty() ? m_strName.String() : "unknown"; }
	const char  *GetLocKey( void ) const			{ return m_strLocKey.String(); }
	const char  *GetWepLocKey( void ) const			{ return m_strWepLocKey.String(); }
	const char  *GetDropSound( void ) const			{ return m_strDropSound.String(); }
	attrib_colors_t		GetAttribColor( void ) const		{ return m_iAttribColor; }
	const char	*GetNextRarity( void ) const		{ return m_strNextRarity.String(); }
	int32		GetLootlistWeight( void ) const		{ return m_nLootlistWeight; }

private:

	// The value that the game/DB will know this rarity by
	int32		m_nValue;

	attrib_colors_t		m_iAttribColor;

	// The English name of the rarity
	CUtlString	m_strName;

	// The localization key for this rarity.
	CUtlString  m_strLocKey;
	// The localization key for this rarity, for weapons.
	CUtlString  m_strWepLocKey;

	// The loot list name associated with this rarity.
	CUtlString  m_strDropSound;

	CUtlString  m_strNextRarity;

	int32		m_nLootlistWeight;

};

//-----------------------------------------------------------------------------
// CEconItemQualityDefinition
// Template Definition of a randomly created item
//-----------------------------------------------------------------------------
class CEconItemQualityDefinition
{
public:
	CEconItemQualityDefinition( void );
	CEconItemQualityDefinition( const CEconItemQualityDefinition &that );
	CEconItemQualityDefinition &operator=( const CEconItemQualityDefinition& rhs );

	~CEconItemQualityDefinition( void ) { }

	bool		BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors = NULL );


	int32		GetDBValue( void ) const			{ return m_nValue; }
	const char	*GetName( void ) const				{ return !m_strName.IsEmpty() ? m_strName.Get() : "unknown"; }
	bool		CanSupportSet( void ) const			{ return m_bCanSupportSet; }
	const char	*GetHexColor( void ) const			{ return !m_strHexColor.IsEmpty() ? m_strHexColor.Get() : "B2B2B2"; }

#ifdef DBGFLAG_VALIDATE
	void Validate( CValidator &validator, const char *pchName )
	{
		VALIDATE_SCOPE();
		ValidateObj( m_strName );
	}
#endif // DBGFLAG_VALIDATE

private:

	// The value that the game/DB will know this quality by
	int32			m_nValue;

	// The English name of the quality
	CUtlConstString	m_strName;

	// if this is true the support tool is allowed to set this quality level on any item
	bool			m_bCanSupportSet;

	// A hex string representing the color this quality should display as. Used primarily for display on the Web.
	CUtlConstString	m_strHexColor;
};

//-----------------------------------------------------------------------------
// CEconColorDefinition
//-----------------------------------------------------------------------------
class CEconColorDefinition
{
public:
	bool		BInitFromKV( KeyValues *pKVColor, CUtlVector<CUtlString> *pVecErrors = NULL );

	const char *GetName( void ) const			{ return m_strName.Get(); }
	const char *GetColorName( void ) const		{ return m_strColorName.Get(); }		// meant for passing into VGUI styles, etc.
	const char *GetHexColor( void ) const		{ return m_strHexColor.Get(); }

private:
	// The English name of this color. Only used for lookup.
	CUtlConstString m_strName;

	// The VGUI name of the color in our schema. This will be used to set values
	// for VGUI controls.
	CUtlConstString m_strColorName;

	// The hex string value of this color. This will be used for Web display.
	CUtlConstString m_strHexColor;
};

//-----------------------------------------------------------------------------
// CEconItemSetDefinition
// Definition of an item set
//-----------------------------------------------------------------------------
class CEconItemSetDefinition
{
public:
	CEconItemSetDefinition( void );
	CEconItemSetDefinition( const CEconItemSetDefinition &that );
	CEconItemSetDefinition &operator=( const CEconItemSetDefinition& rhs );

	~CEconItemSetDefinition( void ) {}

	bool	BInitFromKV( KeyValues *pKVItemSet, CUtlVector<CUtlString> *pVecErrors = NULL );

	void	IterateAttributes( class IEconItemAttributeIterator *pIterator ) const;

public:

	const char							   *m_pszName;
	const char							   *m_pszLocalizedName;
	CUtlVector<item_definition_index_t>		m_iItemDefs;
	int										m_iBundleItemDef;	// Item def of the store bundle for this set, if any
	bool									m_bIsHiddenSet;		// If true, this set and any bonuses will only be visible if the whole set is equipped.

	struct itemset_attrib_t
	{
		attrib_definition_index_t		m_iAttribDefIndex;
		float							m_flValue;
	};
	CUtlVector<itemset_attrib_t>	m_iAttributes;
};

//-----------------------------------------------------------------------------
class CEconItemCollectionDefinition
{
public:
	CEconItemCollectionDefinition( void );
	~CEconItemCollectionDefinition( void ) {}

	bool	BInitFromKV( KeyValues *pKVItemCollection, CUtlVector<CUtlString> *pVecErrors = NULL );

	uint8	GetMinRarity() const { return m_iRarityMin; }
	uint8	GetMaxRarity() const { return m_iRarityMax; }

public:

	const char							   *m_pszName;
	const char							   *m_pszLocalizedName;
	const char							   *m_pszLocalizedDesc;
	CUtlVector<item_definition_index_t>		m_iItemDefs;

private:
	bool	m_bIsReferenceCollection;

	uint8	m_iRarityMin;
	uint8	m_iRarityMax;
};

//-----------------------------------------------------------------------------
class CEconItemPaintKitDefinition
{
public:
	CEconItemPaintKitDefinition( void );
	~CEconItemPaintKitDefinition( void );

	bool	BInitFromKV( KeyValues *pKVItemPaintKit, CUtlVector<CUtlString> *pVecErrors = NULL );

	//KeyValues *GetKVP()				{ return m_pKVItem; }

	const char *GetName() const			{ return m_pszName; }
	const char *GetLocalizeName() const	{ return m_pszLocalizedName; }

	KeyValues *GetPaintKitWearKV( int nWear );

private:
	const char							*m_pszName;
	const char							*m_pszLocalizedName;

	CUtlVector< KeyValues * >			m_vecPaintKitWearKVP;
};

//-----------------------------------------------------------------------------
class CEconOperationDefinition
{
public:
	CEconOperationDefinition( void );
	~CEconOperationDefinition( void );

	bool	BInitFromKV( KeyValues *pKVOperation, CUtlVector<CUtlString> *pVecErrors = NULL );

	const char *GetName() const { return m_pszName; }
	operation_definition_index_t GetOperationID() const { return m_unOperationID; }
	item_definition_index_t GetRequiredItemDefIndex() const { return m_unRequiredItemDefIndex; }
	item_definition_index_t GetGatewayItemDefIndex() const { return m_unGatewayItemDefIndex; }

	KeyValues *GetKVP() { return m_pKVItem; }

	// use the date that we stop giving things to players as expiry date
	bool	IsExpired() const { return CRTime::RTime32TimeCur() > GetStopGivingToPlayerDate(); }
	bool	IsActive() const { return CRTime::RTime32TimeCur() >= GetStartDate() && !IsExpired(); }

	const char *GetQuestLogOverrideResFile() const { return m_pszQuestLogResFile; }
	const char *GetQuestListOverrideResFile() const { return m_pszQuestListResFile; }

	RTime32	GetStartDate() const { return m_OperationStartDate; }
	RTime32 GetStopGivingToPlayerDate() const { return m_StopGivingToPlayerDate; }
	RTime32 GetStopAddingToQueueDate() const { return m_StopAddingToQueueDate; }

	const char *GetOperationLootlist() const { return m_pszOperationLootList; }
	bool	IsCampaign() const { return m_bIsCampaign; }
	uint32	GetMaxDropCount() const { return m_unMaxDropCount; }

#ifdef GC_DLL
	enum EContractRewardLootlist_t
	{
		REWARD_CASE,
		REWARD_WEAPON,

		NUM_REWARDS
	};
	const char *GetContractRewardLootlist( EContractRewardLootlist_t eType ) const { return m_pszContractRewardLootlist[ eType ]; }

	RTime32	GetMinQueueFreq() const;
	RTime32	GetMaxQueueFreq() const;
	RTime32	GetMinDropFreq() const;
	RTime32	GetMaxDropFreq() const;

	uint8	GetNumSeededContracts() const { return m_unSeed; }
	uint16	GetNumMaxHeldDrops() const { return m_unMaxHeldDrops; }

	int		GetNumMaxQueueCount() const { return m_nMaxQueueCount; }

	uint8	GetMaxDropPerThink() const { return m_unMaxDropPerThink; }

#endif // GC_DLL

private:
	const char			*m_pszName;
	operation_definition_index_t	m_unOperationID;

	// things operation periodically drops
	const char			*m_pszOperationLootList;
	bool				m_bIsCampaign;
	uint32				m_unMaxDropCount;

	const char			*m_pszQuestLogResFile;
	const char			*m_pszQuestListResFile;

	item_definition_index_t m_unRequiredItemDefIndex;
	item_definition_index_t m_unGatewayItemDefIndex; // Defindex of the item users need to acquire in order to get the required item.  Could be the required item itself.

	RTime32				m_OperationStartDate;		// when the operation starts and gives out rewards
	RTime32				m_StopGivingToPlayerDate;	// when the operation stops giving quests to player
	RTime32				m_StopAddingToQueueDate;	// when the operation stops adding more quests to the bucket

#ifdef GC_DLL
	const char			*m_pszContractRewardLootlist[ NUM_REWARDS ];

	// in seconds
	RTime32				m_rtQueueFreqMin;
	RTime32				m_rtQueueFreqMax;
	RTime32				m_rtDropFreqMin;
	RTime32				m_rtDropFreqMax;

	uint8				m_unSeed;
	uint16				m_unMaxHeldDrops;
	int					m_nMaxQueueCount;

	uint8				m_unMaxDropPerThink;

#endif // GC_DLL

	KeyValues				   *m_pKVItem;
};

//-----------------------------------------------------------------------------
// CEconLootListDefinition
// Definition of a loot list
//-----------------------------------------------------------------------------
class IEconLootList
{
public:
	virtual ~IEconLootList() { }

	MUST_CHECK_RETURN virtual bool BPublicListContents() const = 0;
	MUST_CHECK_RETURN virtual const char *GetLootListHeaderLocalizationKey() const = 0;
	MUST_CHECK_RETURN virtual const char *GetLootListFooterLocalizationKey() const = 0;
	MUST_CHECK_RETURN virtual const char *GetLootListCollectionReference() const = 0;

	class IEconLootListIterator
	{
	public:
		virtual ~IEconLootListIterator() { }
		virtual void OnIterate( item_definition_index_t unItemDefIndex ) = 0;
	};

	virtual void EnumerateUserFacingPotentialDrops( IEconLootListIterator *pIt ) const = 0;

#ifdef GC_DLL
	MUST_CHECK_RETURN virtual bool BGenerateSingleRollRandomItems( const CEconGameAccount *pGameAccount, bool bFreeAccount, CUtlVector<CEconItem *> *out_pvecItems, const CUtlVector< item_definition_index_t > *pVecAvoidItemDefs = NULL ) const = 0;
#endif // GC_DLL
};

#ifdef GC_DLL
struct lootlist_attrib_t
{
	static_attrib_t	m_staticAttrib;
	float	m_flWeight;

	bool BInitFromKV( const char *pszContext, KeyValues *pKVKey, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors );
};

struct random_attrib_t
{
	float				m_flChanceOfRandomAttribute;
	float				m_flTotalAttributeWeight;
	bool				m_bPickAllAttributes;
	CUtlVector<lootlist_attrib_t> m_RandomAttributes;

	bool RollRandomAttributes( CUtlVector< static_attrib_t >& vecAttributes, const CEconGameAccount *pGameAccount ) const;
};
#endif // GC_DLL

class CEconLootListDefinition : public IEconLootList
{
public:
	struct drop_period_t
	{
		bool IsValidForTime( const RTime32& time ) const;

		RTime32		m_DropStartDate;
		RTime32		m_DropEndDate;
	};

	struct drop_item_t
	{
		int m_iItemOrLootlistDef;			// negative values indicate nested loot lists
		float m_flWeight;
		drop_period_t m_dropPeriod;
	};

	struct loot_list_additional_drop_t
	{
		float		m_fChance;
		bool		m_bPremiumOnly;
		const char *m_pszLootListDefName;
		int		    m_iRequiredHolidayIndex;
		drop_period_t m_dropPeriod;
	};

	virtual ~CEconLootListDefinition();
	
	bool BInitFromKV( KeyValues *pKVLootList, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors );

	const char *GetName() const { return m_pszName; }
	virtual const char *GetLootListHeaderLocalizationKey() const OVERRIDE { return m_pszLootListHeader; }
	virtual const char *GetLootListFooterLocalizationKey() const OVERRIDE { return m_pszLootListFooter; }
	virtual const char *GetLootListCollectionReference() const OVERRIDE { return m_pszCollectionReference; }
		
	const CUtlVector<drop_item_t>& GetLootListContents() const { return m_DropList; }
#ifdef GC_DLL
	const CUtlVector<loot_list_additional_drop_t>& GetAdditionalDrops() const { return m_AdditionalDrops; }
#endif
	virtual void EnumerateUserFacingPotentialDrops( IEconLootListIterator *pIt ) const OVERRIDE;

	virtual bool BPublicListContents() const OVERRIDE
	{
		return m_bPublicListContents;
	}

#ifdef GC_DLL

public:
	struct rolled_item_defs_t
	{
		const CEconItemDefinition			*m_pItemDef;
		CCopyableUtlVector< const CEconLootListDefinition * > m_vecAffectingLootLists;
	};

	bool AddRandomAtrributes( KeyValues *pRandomAttributesKV, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors = NULL );
	bool AddRandomAttributesFromTemplates( KeyValues *pRandomAttributesKV, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors = NULL );


	// Generates a single roll for this loot list as well as each "additional drop" loot list specified. This will return
	// true if all items were created successfully or false if anything went wrong in any of the relevant lootlists. All
	// items created will be returned via out_pvecItems.
	MUST_CHECK_RETURN virtual bool BGenerateSingleRollRandomItems( const CEconGameAccount *pGameAccount, bool bFreeAccount, CUtlVector<CEconItem *> *out_pvecItems, const CUtlVector< item_definition_index_t > *pVecAvoidItemDefs = NULL ) const OVERRIDE;

	void	RollRandomAttributes( CUtlVector< static_attrib_t >& vecAttributes, const CEconGameAccount *pGameAccount ) const;
	bool	RollRandomItemsAndAdditionalItems( IUniformRandomStream *pRandomStream, bool bFreeAccount, CUtlVector<rolled_item_defs_t> *out_pVecRolledItems, const CUtlVector< item_definition_index_t > *pVecAvoidItemDefs = NULL ) const;

	uint8	GetRarity() const { return m_unRarity; }
	void	GetRarityLootLists( CUtlVector< const CEconLootListDefinition* > *out_pVecRarityLootList ) const;
	void	GetItemDefs( CUtlVector< item_definition_index_t > *out_pVecItemDefs ) const;

private:
	bool	RollRandomItemDef( IUniformRandomStream *pRandomStream, bool bFreeAccount, CUtlVector<rolled_item_defs_t> *out_pVecRolledItems, const CUtlVector< item_definition_index_t > *pVecAvoidItemDefs = NULL ) const;
	bool	BIsInternalNoDupesLootList() const { return m_iNoDupesIterations >= 0; }

	MUST_CHECK_RETURN bool BInitPropertyGeneratorsFromKV( KeyValues *pKV, CUtlVector<CUtlString> *pVecErrors );
#endif

private:
	const char			*m_pszName;
	const char			*m_pszLootListHeader;
	const char			*m_pszLootListFooter;
	const char			*m_pszCollectionReference;
	CUtlVector<drop_item_t> m_DropList;

	bool				m_bPublicListContents;	// do not show loot list contents to users (ie., when listing crate contents on Steam)

#ifdef GC_DLL

	MUST_CHECK_RETURN bool	BAttachLootListAttributes( const CEconGameAccount *pGameAccount, CEconItem *pItem ) const;

	int					m_iNoDupesIterations;	// if less than zero, "no dupes" functionality disabled; if greater than or equal to zero, the number of iterations we want to run through passing no-dupe sets

	CUtlVector<random_attrib_t*>					m_RandomAttribs;
	CUtlVector<loot_list_additional_drop_t>			m_AdditionalDrops;
	CUtlVector<const IEconItemPropertyGenerator *>	m_PropertyGenerators;

	uint8				m_unRarity;
#endif // GC_DLL
};

//-----------------------------------------------------------------------------
// CEconCraftingRecipeDefinition
// Template Definition of an item recipe
//-----------------------------------------------------------------------------
class CEconCraftingRecipeDefinition
{
public:
	CEconCraftingRecipeDefinition( void );
	virtual ~CEconCraftingRecipeDefinition( void ) { }

	bool		BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors = NULL );

#ifdef GC_DLL
	bool		BIsCraftableByUnverifiedClients() const { return m_bIsCraftableByUnverifiedClient; }
#endif // GC_DLL

	virtual void CopyPolymorphic( const CEconCraftingRecipeDefinition *pSourceDef ) { *this = *pSourceDef; }

	void		SetDefinitionIndex( uint32 iIndex ) { m_nDefIndex = iIndex; }
	int32		GetDefinitionIndex( void ) const	{ return m_nDefIndex; }
	const char	*GetName( void ) const				{ return !m_strName.IsEmpty() ? m_strName.String() : "unknown"; }
	const char	*GetName_A( void ) const				{ return !m_strN_A.IsEmpty() ? m_strN_A.String() : "unknown"; }
	const char	*GetDescInputs( void ) const				{ return !m_strDescInputs.IsEmpty() ? m_strDescInputs.String() : "unknown"; }
	const char	*GetDescOutputs( void ) const				{ return !m_strDescOutputs.IsEmpty() ? m_strDescOutputs.String() : "unknown"; }

	const char	*GetDescI_A( void ) const				{ return !m_strDI_A.IsEmpty() ? m_strDI_A.String() : "unknown"; }
	const char	*GetDescI_B( void ) const				{ return !m_strDI_B.IsEmpty() ? m_strDI_B.String() : "unknown"; }
	const char	*GetDescI_C( void ) const				{ return !m_strDI_C.IsEmpty() ? m_strDI_C.String() : "unknown"; }
	const char	*GetDescO_A( void ) const				{ return !m_strDO_A.IsEmpty() ? m_strDO_A.String() : "unknown"; }
	const char	*GetDescO_B( void ) const				{ return !m_strDO_B.IsEmpty() ? m_strDO_B.String() : "unknown"; }
	const char	*GetDescO_C( void ) const				{ return !m_strDO_C.IsEmpty() ? m_strDO_C.String() : "unknown"; }

	bool		IsDisabled( void ) const { return m_bDisabled; }
	bool		RequiresAllSameClass( void ) { return m_bRequiresAllSameClass; }
	bool		RequiresAllSameSlot( void ) { return m_bRequiresAllSameSlot; }
	bool		IsPremiumAccountOnly( void ) const { return m_bPremiumAccountOnly; }
	recipecategories_t	GetCategory( void ) const { return m_iCategory; }
	int			GetTotalInputItemsRequired( void ) const;
	int			GetTotalOutputItems( void ) const { return m_OutputItemsCriteria.Count(); }

	// Returns true if the vector contains a set of items that matches the inputs for this recipe
	virtual bool ItemListMatchesInputs( CUtlVector<CEconItem*> *vecCraftingItems, KeyValues *out_pCraftParams = NULL, bool bIgnoreSlop = false, CUtlVector<uint64> *vecChosenItems = NULL ) const;

	const CUtlVector<CItemSelectionCriteria> *GetInputItems( void ) const { return &m_InputItemsCriteria; }
	const CUtlVector<uint32>				 &GetInputItemDupeCounts( void ) const { return m_InputItemDupeCounts; }
	const CUtlVector<CItemSelectionCriteria> &GetOutputItems( void ) const { return m_OutputItemsCriteria; }

#ifdef DBGFLAG_VALIDATE
	void Validate( CValidator &validator, const char *pchName )
	{
		VALIDATE_SCOPE();
		ValidateObj( m_InputItemsCriteria );
		ValidateObj( m_InputItemDupeCounts );
		ValidateObj( m_OutputItemsCriteria );
	}
#endif // DBGFLAG_VALIDATE

	// Serializes the criteria to and from messages
	bool		BSerializeToMsg( CSOItemRecipe & msg ) const;
	bool		BDeserializeFromMsg( const CSOItemRecipe & msg );

protected:
	// The number used to refer to this definition in the DB
	int32		m_nDefIndex;

	// Localization key strings
	CUtlString	m_strName; 
	CUtlString	m_strN_A; 
	CUtlString	m_strDescInputs; 
	CUtlString	m_strDescOutputs; 
	CUtlString	m_strDI_A;
	CUtlString	m_strDI_B;
	CUtlString	m_strDI_C;
	CUtlString	m_strDO_A;
	CUtlString	m_strDO_B;
	CUtlString	m_strDO_C;

	bool		m_bDisabled;
#ifdef GC_DLL
	bool		m_bIsCraftableByUnverifiedClient;
#endif // GC_DLL
	bool		m_bRequiresAllSameClass;
	bool		m_bRequiresAllSameSlot;
	int			m_iCacheClassUsageForOutputFromItem;
	int			m_iCacheSlotUsageForOutputFromItem;
	int			m_iCacheSetForOutputFromItem;
	bool		m_bPremiumAccountOnly;
	recipecategories_t	m_iCategory;

	// The list of items that a required to make this recipe
	CUtlVector<CItemSelectionCriteria>	m_InputItemsCriteria;
	CUtlVector<uint32>					m_InputItemDupeCounts;

	// The list of items that are generated by this recipe
	CUtlVector<CItemSelectionCriteria>	m_OutputItemsCriteria;
};

//-----------------------------------------------------------------------------
// Purpose: Attribute definition details
//-----------------------------------------------------------------------------
enum
{
	ATTDESCFORM_VALUE_IS_PERCENTAGE,			// Printed as:	((m_flValue*100)-100.0)
	ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE,	// Printed as:	((m_flValue*100)-100.0) if it's > 1.0, or ((1.0-m_flModifier)*100) if it's < 1.0
	ATTDESCFORM_VALUE_IS_ADDITIVE,				// Printed as:	m_flValue
	ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE,	// Printed as:	(m_flValue*100)
	ATTDESCFORM_VALUE_IS_OR,					// Printed as:  m_flValue, but results are ORd together instead of added
	ATTDESCFORM_VALUE_IS_DATE,					// Printed as a date
	ATTDESCFORM_VALUE_IS_ACCOUNT_ID,			// Printed as steam user name
	ATTDESCFORM_VALUE_IS_PARTICLE_INDEX,		// Printed as a particle description
	ATTDESCFORM_VALUE_IS_KILLSTREAKEFFECT_INDEX,// Printed as killstreak effect description
	ATTDESCFORM_VALUE_IS_KILLSTREAK_IDLEEFFECT_INDEX,  // Printed as idle effect description
	ATTDESCFORM_VALUE_IS_ITEM_DEF,				// Printed as item name
	ATTDESCFORM_VALUE_IS_FROM_LOOKUP_TABLE,		// Printed as a string from a lookup table, specified by the attribute definition name
};

// Coloring for attribute lines
enum attrib_effect_types_t
{
	ATTRIB_EFFECT_UNUSUAL = 0,
	ATTRIB_EFFECT_STRANGE,
	ATTRIB_EFFECT_NEUTRAL,
	ATTRIB_EFFECT_POSITIVE,
	ATTRIB_EFFECT_NEGATIVE,
	
	NUM_EFFECT_TYPES,
};

enum EAssetClassAttrExportRule_t
{
	k_EAssetClassAttrExportRule_Default = 0,
	k_EAssetClassAttrExportRule_Bucketed = ( 1 << 0 ),	// attribute exports bucketed value to Steam Community
	k_EAssetClassAttrExportRule_Skip = ( 1 << 1 ),	// attribute value is not exported to Steam Community
	k_EAssetClassAttrExportRule_GCOnly = ( 1 << 2 ),	// attribute only lives on GC and not exported to any external request
};

//-----------------------------------------------------------------------------
// CEconItemAttributeDefinition
// Template definition of a randomly created attribute
//-----------------------------------------------------------------------------
class CEconItemAttributeDefinition
{
public:
	CEconItemAttributeDefinition( void );
	CEconItemAttributeDefinition( const CEconItemAttributeDefinition &that );
	CEconItemAttributeDefinition &operator=( const CEconItemAttributeDefinition& rhs );

	~CEconItemAttributeDefinition( void );

	bool	BInitFromKV( KeyValues *pKVAttribute, CUtlVector<CUtlString> *pVecErrors = NULL );

	attrib_definition_index_t GetDefinitionIndex( void ) const	{ return m_nDefIndex; }
	// Attribute name referenced in the db.
	const char	*GetDefinitionName( void ) const	{ return m_pszDefinitionName; }
	
	KeyValues	*GetRawDefinition( void ) const		{ return m_pKVAttribute; }

	// Data accessing
	bool		IsHidden( void ) const						{ return m_bHidden; }
	bool		BForceWebSchemaOutput( void ) const			{ return m_bWebSchemaOutputForced; }
	bool		BIsSetBonusAttribute( void ) const			{ return m_bIsSetBonus; }
	bool		CanAffectMarketName( void ) const			{ return m_bCanAffectMarketName; }
	bool		CanAffectRecipeComponentName( void ) const	{ return m_bCanAffectRecipeComponentName; }
	bool		IsStoredAsInteger( void ) const				{ return m_bStoredAsInteger; }
	bool		IsStoredAsFloat( void ) const				{ return !m_bStoredAsInteger; }
	int			GetUserGenerationType( void ) const			{ return m_iUserGenerationType; }
	bool		IsInstanceData() const						{ return m_bInstanceData; }
	EAssetClassAttrExportRule_t GetAssetClassAttrExportRule() const			{ return m_eAssetClassAttrExportRule; }
	uint32		GetAssetClassBucket() const			{ return m_unAssetClassBucket; }
	int			GetDescriptionFormat( void ) const			{ return m_iDescriptionFormat; }
	const char *GetDescriptionString( void ) const			{ return m_pszDescriptionString; }
	const char *GetArmoryDescString( void ) const			{ return m_pszArmoryDesc; }
	const char *GetAttributeClass( void ) const				{ return m_pszAttributeClass; }
	econ_tag_handle_t GetItemDefinitionTag( void ) const	{ return m_ItemDefinitionTag; }
	attrib_effect_types_t GetEffectType( void ) const		{ return m_iEffectType; }

	const class ISchemaAttributeType *GetAttributeType( void ) const { return m_pAttrType; }

#ifndef GC_DLL
	void		ClearStringCache( void ) const		{ m_iszAttributeClass = NULL_STRING; }
	string_t	GetCachedClass( void ) const
	{
		if ( m_iszAttributeClass == NULL_STRING && m_pszAttributeClass )
		{
			m_iszAttributeClass = AllocPooledString( m_pszAttributeClass );
		}
		return m_iszAttributeClass;
	}
#endif

#ifdef DBGFLAG_VALIDATE
	void Validate( CValidator &validator, const char *pchName )
	{
		VALIDATE_SCOPE();
		ValidatePtr( m_pKVAttribute );
	}
#endif // DBGFLAG_VALIDATE

private:
	// The raw keyvalues for this attribute definition.
	KeyValues	*m_pKVAttribute;

	// Required valued from m_pKVAttribute:

	// The number used to refer to this definition in the DB
	attrib_definition_index_t	m_nDefIndex;

	// A pointer to the schema-global type data for this attribute. This maps attribute types to functionality
	// for loading/storing, both to memory and the DB.
	const class ISchemaAttributeType *m_pAttrType;

	// ---------------------------------------------
	// Display related data
	// ---------------------------------------------
	// If true, this attribute isn't shown in the item description
	bool		m_bHidden;

	// If true, this attribute's description is always output in web api calls regardless of the hidden flag.
	bool		m_bWebSchemaOutputForced;

	// Whether or not the value is stored as an integer in the DB.
	bool		m_bStoredAsInteger;

	// If this is true the attribute is counted as "instance" data for purposes of asset class in the Steam Economy. Non-instance
	// properties are considered things that can differentiate items at a fundamental level (ie., definition index, quality); instance
	// properties are more things like additional customizations -- score for strange items, paint color, etc.
	bool		m_bInstanceData;
	EAssetClassAttrExportRule_t	m_eAssetClassAttrExportRule;			// if this is true the attribute will not be exported for asset class
	uint32		m_unAssetClassBucket;									// if this is set then attribute value is bucketed when exported for asset class

	// Set item bonus attributes use a different attribute parser and make assumptions about memory layout. We
	// don't really use these for any new content currently and it isn't worth touching all the old code.
	//
	// At runtime, this flag is used to determine whether or not to rebuild dynamic attributes attached to
	// players on respawn.
	bool		m_bIsSetBonus;

	// Whether or not this attribute is supposed to only come from user actions. These attributes are used for
	// player item upgrades, etc. and cannot be set on items directly in the schema.
	int			m_iUserGenerationType;

	// Overall positive/negative effect. Used to color the attribute.
	attrib_effect_types_t m_iEffectType;

	// Contains the description format & string for this attribute
	int			m_iDescriptionFormat;
	const char	*m_pszDescriptionString;

	// Contains information on how to describe items with this attribute in the Armory
	const char	*m_pszArmoryDesc;

	// Used to allow unique items to specify attributes by name.
	const char	*m_pszDefinitionName;

	// The class name of this attribute. Used in creation, and to hook the attribute into the actual code that uses it.
	const char	*m_pszAttributeClass;

	// Allowed to affect the market bucketization name.  We dont want things like the strange level to affect the name,
	// but we do want things like crate series number and strangifier targets to get their own buckets.
	bool		m_bCanAffectMarketName;

	// Allowed to list itself in the name of an item in the recipe component description.
	bool		m_bCanAffectRecipeComponentName;

	// Do item definitions with this attribute specified automatically get an additional tag applied?
	econ_tag_handle_t	m_ItemDefinitionTag;

#ifndef GC_DLL
	mutable string_t	m_iszAttributeClass;	// Same as the above, but used for fast lookup when applying attributes.
#endif
};


//-----------------------------------------------------------------------------
// Visual data storage in item definitions
//-----------------------------------------------------------------------------
#define TEAM_VISUAL_SECTIONS			5
#define MAX_VISUALS_CUSTOM_SOUNDS		10

struct attachedparticlesystem_t
{
	attachedparticlesystem_t() :
		pszSystemName( NULL )
		, bFollowRootBone( NULL )
		, iCustomType( 0 )
		, nSystemID( 0 )
		, fRefireTime( 0 )			// only works for taunt effects, currently
		, bDrawInViewModel( false )
		, bUseSuffixName( false )
		, bHasViewModelSpecificEffect ( false )
	{
		V_memset( pszControlPoints, 0, sizeof( pszControlPoints ) );
	}

	const char *pszSystemName;
	bool		bFollowRootBone;
	int			iCustomType;
	int			nSystemID;
	float		fRefireTime;				// only works for taunt effects, currently
	bool		bDrawInViewModel;
	bool		bUseSuffixName;
	bool		bHasViewModelSpecificEffect;

	const char *pszControlPoints[7];
};


#if defined(CLIENT_DLL) || defined(GAME_DLL)
enum
{
	kAttachedModelDisplayFlag_WorldModel = 0x01,
	kAttachedModelDisplayFlag_ViewModel	 = 0x02,

	kAttachedModelDisplayFlag_MaskAll	 = kAttachedModelDisplayFlag_WorldModel | kAttachedModelDisplayFlag_ViewModel,
};

struct attachedmodel_t
{
	const char *m_pszModelName;
	int m_iModelDisplayFlags;
};

enum wearableanimplayback_t
{
	WAP_ON_SPAWN,				// Play this animation immediately on spawning the wearable
	WAP_START_BUILDING,			// Game code will start this anim whenever a player wearing this item deploys their builder weapon.
	WAP_STOP_BUILDING,			// Game code will start this anim whenever a player wearing this item holsters their builder weapon.
	WAP_START_TAUNTING,			// Game code will start this anim whenever a player wearing this item taunts
	WAP_STOP_TAUNTING,				// Game code will start this anim whenever a player wearing this item stops taunting

	NUM_WAP_TYPES,
};

struct animation_on_wearable_t
{
	int						iActivity;
	const char				*pszActivity;
	const char				*pszReplacement;
	int						iReplacement; // Replacement activity to play. Might be set to one of kActivityLookup_Unknown/kActivityLookup_Missing.
	const char				*pszSequence;
	const char				*pszRequiredItem;
	const char				*pszScene;
};

struct activity_on_wearable_t
{
	wearableanimplayback_t	iPlayback;
	int						iActivity;
	const char				*pszActivity;
};

struct codecontrolledbodygroupdata_t
{
	const char *pFuncName;
	void *pFunc;
};

// This is a workaround because Source practice is to disable operator=() for CUtlMap.
struct perteamvisuals_maps_t
{
	perteamvisuals_maps_t()
	{
		m_ModifiedBodyGroupNames.SetLessFunc( StringLessThan );
		m_CodeControlledBodyGroupNames.SetLessFunc( StringLessThan );
	}

	void operator=( const perteamvisuals_maps_t& other )
	{
		DeepCopyMap( other.m_ModifiedBodyGroupNames, &m_ModifiedBodyGroupNames );
		DeepCopyMap( other.m_CodeControlledBodyGroupNames, &m_CodeControlledBodyGroupNames );
	}

	CUtlMap<const char*, int> m_ModifiedBodyGroupNames; // Better method: hide multiple body groups by name.
	CUtlMap<const char*, codecontrolledbodygroupdata_t> m_CodeControlledBodyGroupNames;
};

#endif // defined(CLIENT_DLL) || defined(GAME_DLL)

class CEconStyleInfo
{
public:
	CEconStyleInfo()
	{
		for ( int i = 0; i < TEAM_VISUAL_SECTIONS; i++ )
		{
			m_iSkins[i] = 0;
			m_iViewmodelSkins[i] = -1;
		}

		m_pszName = NULL;
		m_pszBasePlayerModel = NULL;
		m_bIsSelectable = true;
		m_pszInventoryImage = NULL;

		m_pszBodygroupName = NULL;
		m_iBodygroupSubmodelIndex = -1;

		m_sIconURLSmall = "";
		m_sIconURLLarge = "";
	}

	virtual ~CEconStyleInfo()
	{
		//
	}

	virtual void BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors );

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	virtual void GeneratePrecacheModelStringsForStyle( CUtlVector<const char *> *out_pVecModelStrings ) const;
#endif

	int GetSkin( int iTeam, bool bViewmodel ) const
	{
		Assert( iTeam >= 0 ); 
		Assert( iTeam < TEAM_VISUAL_SECTIONS );

		if ( bViewmodel && m_iViewmodelSkins[ iTeam ] != -1 )
		{
			return m_iViewmodelSkins[ iTeam ];
		}
		
		return m_iSkins[iTeam];
	}

	const char *GetName() const { return m_pszName; }
	const char *GetBasePlayerDisplayModel() const { return m_pszBasePlayerModel; }
	const CUtlVector<const char *>& GetAdditionalHideBodygroups() const { return m_vecAdditionalHideBodygroups; }
	bool IsSelectable() const { return m_bIsSelectable; }
	const char *GetInventoryImage() const { return m_pszInventoryImage; }

	const char *GetBodygroupName() const { return m_pszBodygroupName; }
	int GetBodygroupSubmodelIndex() const { return m_iBodygroupSubmodelIndex; }

	const char  *GetIconURLSmall() const			{ return m_sIconURLSmall; }
	const char  *GetIconURLLarge() const			{ return m_sIconURLLarge; }
	void	SetIconURLSmall( const char *szURL )	{ m_sIconURLSmall = szURL; }
	void	SetIconURLLarge( const char *szURL )	{ m_sIconURLLarge = szURL; }

protected:
	int m_iSkins[TEAM_VISUAL_SECTIONS];
	int m_iViewmodelSkins[TEAM_VISUAL_SECTIONS];
	const char *m_pszName;
	const char *m_pszBasePlayerModel;
	bool m_bIsSelectable;
	const char *m_pszInventoryImage;

	const char *m_pszBodygroupName;
	int m_iBodygroupSubmodelIndex;

	CUtlVector<const char *> m_vecAdditionalHideBodygroups;

private:

	CUtlString		m_sIconURLSmall;
	CUtlString		m_sIconURLLarge;
};

struct perteamvisuals_t
{
	perteamvisuals_t()
	{
#if defined(CLIENT_DLL) || defined(GAME_DLL)
		iHideParentBodyGroup = -1;

		iSkin = -1;
		bUsePerClassBodygroups = false;
		pszMaterialOverride = NULL;
		pszMuzzleFlash = NULL;
		pszTracerEffect = NULL;
		pszParticleEffect = NULL;
		for ( int i = 0; i < MAX_VISUALS_CUSTOM_SOUNDS; i++ )
		{
			pszCustomSounds[i] = NULL;
		}

		for ( int i = 0; i < NUM_SHOOT_SOUND_TYPES; i++ )
		{
			pszWeaponSoundReplacements[i] = NULL;
		}

		m_iViewModelBodyGroupOverride = -1;
		m_iViewModelBodyGroupStateOverride = -1;
		m_iWorldModelBodyGroupOverride = -1;
		m_iWorldModelBodyGroupStateOverride = -1;

#endif // defined(CLIENT_DLL) || defined(GAME_DLL)
	}

	~perteamvisuals_t()
	{
		m_Styles.PurgeAndDeleteElements();
	}

#if defined(CLIENT_DLL) || defined(GAME_DLL)	
	int iHideParentBodyGroup;

	// Properties necessary for the game client/server but not for the GC.
	perteamvisuals_maps_t m_Maps;
	int			iSkin;
	bool		bUsePerClassBodygroups;
	CUtlVector<attachedmodel_t>	m_AttachedModels;
	CUtlVector<attachedmodel_t>	m_AttachedModelsFestive;	// Attr controlled Festive Attachments
	CUtlVector<attachedparticlesystem_t> m_AttachedParticles;
	CUtlVector<animation_on_wearable_t> m_Animations;
	CUtlVector<activity_on_wearable_t> m_Activities;
	const char *pszCustomSounds[MAX_VISUALS_CUSTOM_SOUNDS];
	const char *pszMaterialOverride;
	const char *pszMuzzleFlash;
	const char *pszTracerEffect;
	const char *pszParticleEffect;
	const char *pszWeaponSoundReplacements[NUM_SHOOT_SOUND_TYPES];
	int m_iViewModelBodyGroupOverride;
	int m_iViewModelBodyGroupStateOverride;
	int m_iWorldModelBodyGroupOverride;
	int m_iWorldModelBodyGroupStateOverride;
#endif // defined(CLIENT_DLL) || defined(GAME_DLL)

	// The GC does care about styles.
	CUtlVector<CEconStyleInfo *> m_Styles;
};

enum item_capabilities_t
{
	ITEM_CAP_NONE					= 0,
	ITEM_CAP_PAINTABLE				= 1 << 0,
	ITEM_CAP_NAMEABLE				= 1 << 1,
	ITEM_CAP_DECODABLE				= 1 << 2,
	ITEM_CAP_CAN_BE_CRAFTED_IF_PURCHASED = 1 << 3,		// was ITEM_CAP_CAN_MOD_SOCKET
	ITEM_CAP_CAN_CUSTOMIZE_TEXTURE	= 1 << 4,
	ITEM_CAP_USABLE					= 1 << 5,
	ITEM_CAP_USABLE_GC				= 1 << 6,
	ITEM_CAP_CAN_GIFT_WRAP			= 1 << 7,
	ITEM_CAP_USABLE_OUT_OF_GAME		= 1 << 8,
	ITEM_CAP_CAN_COLLECT			= 1 << 9,
	ITEM_CAP_CAN_CRAFT_COUNT		= 1 << 10,
	ITEM_CAP_CAN_CRAFT_MARK			= 1 << 11,
	ITEM_CAP_PAINTABLE_TEAM_COLORS	= 1 << 12,
	ITEM_CAP_CAN_BE_RESTORED		= 1 << 13,		// can users remove properties (paint, nametag, etc.) from this item via the in-game UI?
	ITEM_CAP_CAN_USE_STRANGE_PARTS	= 1 << 14,
	ITEM_CAP_CAN_CARD_UPGRADE		= 1 << 15,
	ITEM_CAP_CAN_STRANGIFY			= 1 << 16,
	ITEM_CAP_CAN_KILLSTREAKIFY		= 1 << 17,
	ITEM_CAP_CAN_CONSUME			= 1 << 18,
	ITEM_CAP_CAN_SPELLBOOK_PAGE		= 1 << 19,		// IT'S A VERB OKAY
	ITEM_CAP_HAS_SLOTS				= 1 << 20,
	ITEM_CAP_DUCK_UPGRADABLE		= 1 << 21,
	ITEM_CAP_CAN_UNUSUALIFY			= 1 << 22,
	NUM_ITEM_CAPS					= 23,
};

enum { ITEM_CAP_DEFAULT		 = ITEM_CAP_CAN_CRAFT_MARK | ITEM_CAP_CAN_BE_RESTORED | ITEM_CAP_CAN_USE_STRANGE_PARTS | ITEM_CAP_CAN_CARD_UPGRADE | ITEM_CAP_CAN_STRANGIFY | ITEM_CAP_CAN_KILLSTREAKIFY | ITEM_CAP_CAN_CONSUME | ITEM_CAP_CAN_GIFT_WRAP };	// what are the default capabilities on an item?
enum { ITEM_CAP_TOOL_DEFAULT = ITEM_CAP_NONE };																										// what are the default capabilities of a tool?

struct bundleinfo_t
{
	CUtlVector<CEconItemDefinition *> vecItemDefs;
};

#ifdef GC_DLL
enum EPaymentRuleType
{
	kPaymentRule_SteamWorkshopFileID	= 0x01,
	kPaymentRule_PartnerSteamID			= 0x02,
	kPaymentRule_Bundle					= 0x04,
};

struct econ_item_payment_rule_t
{
	double						m_RevenueShare;
	EPaymentRuleType			m_eRuleType;
	CCopyableUtlVector<uint64>	m_vecValues;
};
#endif // GC_DLL

#ifdef CLIENT_DLL
namespace vgui
{
	class Panel;
}
#endif // CLIENT_DLL

class IEconTool
{
	friend class CEconSharedToolSupport;

public:
	IEconTool( const char *pszTypeName, const char *pszUseString, const char *pszUsageRestriction, item_capabilities_t unCapabilities )
		: m_pszTypeName( pszTypeName )
		, m_pszUseString( pszUseString )
		, m_pszUsageRestriction( pszUsageRestriction )
		, m_unCapabilities( unCapabilities )
	{
		//
	}

	virtual ~IEconTool() { }

	// Shared code.
	const char *GetUsageRestriction() const { return m_pszUsageRestriction; }
	item_capabilities_t GetCapabilities() const { return m_unCapabilities; }

	virtual bool CanApplyTo( const IEconItemInterface *pTool, const IEconItemInterface *pToolSubject ) const { Assert( pTool ); Assert( pToolSubject ); return true; }
	virtual bool ShouldDisplayQuantity( const IEconItemInterface *pTool ) const;
	virtual bool RequiresToolEscrowPeriod() const { return false; }

	// We don't support throwing exceptions from tool construction so this is intended to be checked afterwards
	// whenever a new tool is created. (See CreateEconToolImpl().)
	virtual bool BFinishInitialization() { return true; }
	
	// Used by the GC only for WebAPI responses and for some weird internal code.
	const char *GetTypeName() const { return m_pszTypeName; }		// would like to disable on the client so we aren't tempted to check against it, but used for building a unique tool list
	const char *GetUseString() const { return m_pszUseString; }

#ifdef CLIENT_DLL
	virtual bool CanBeUsedNow( const IEconItemInterface *pItem ) const { return true; }
	virtual bool ShouldShowContainedItemPanel( const IEconItemInterface *pItem ) const { Assert( !"IEconTool::ShouldShowContainedItemPanel(): we don't expect this to be called on anything besides gifts!" ); return false; }
	virtual bool ShouldDisplayAsUseableOnItemsInArmory() const { return true; }
	virtual const char *GetUseCommandLocalizationToken( const IEconItemInterface *pItem, int i = 0 ) const;
	virtual int GetUseCommandCount( const IEconItemInterface *pItem ) const { return 1; }
	virtual const char* GetUseCommand( const IEconItemInterface *pItem, int i = 0 ) const;


	// Client "do something" interface. At least one of these functions must be implemented or your tool
	// won't do anything on the client. Some tools (ie., collections) will implement both because they
	// have one application behavior and one client-UI behavior.

	// When the client attempts to use a consumable item of any kind, this function will be called. This
	// is called from the UI in response to things like using dueling pistols, using a noisemaker, etc.
	// Usually this opens up some UI, sends off a GC message, etc.
	//
	// There is a "default" implementation of this function in ClientConsumableTool_Generic() that can
	// be called if specific behavior isn't needed.
	virtual void OnClientUseConsumable( class C_EconItemView *pItem, vgui::Panel *pParent ) const
	{
		Assert( !"IEconTool::OnClientUseConsumable(): unimplemented call!" );
	}

	// When the client attempts to apply a tool to a specific other item in their inventory, this function
	// will be called. This is called from the UI is response to things like putting paint on an item,
	// using a key to unlock a crate, etc.
	virtual void OnClientApplyTool( class C_EconItemView *pTool, class C_EconItemView *pSubject, vgui::Panel *pParent ) const
	{
		Assert( !"IEconTool::OnClientApplyTool(): unimplemented call!" );
	}
#endif // CLIENT_DLL

#ifdef GC_DLL
	virtual class CGCEconConsumableBehavior *CreateGCConsumableBehavior() const;
	virtual bool BGenerateDynamicAttributes( CEconItem* pItem,  const CEconGameAccount *pGameAccount ) const { return true; }
#endif // GC_DLL

private:
	const char *m_pszTypeName;
	const char *m_pszUseString;
	const char *m_pszUsageRestriction;
	item_capabilities_t m_unCapabilities;
};

//-----------------------------------------------------------------------------
// CQuestObjectiveDefinition
//-----------------------------------------------------------------------------
class CQuestObjectiveDefinition
{
public:

	CQuestObjectiveDefinition( void );
	virtual ~CQuestObjectiveDefinition( void );

	virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors = NULL );

	uint32 GetDefinitionIndex( void ) const { return m_nDefIndex; }
	const char *GetDescriptionToken( void ) const { return m_pszDescriptionToken; }
	bool IsOptional() const { return m_bOptional; }
	bool IsAdvanced() const { return m_bAdvanced; }
	uint32 GetPoints() const { return m_nPoints; } // TODO: change to a float

private:
	const char *m_pszDescriptionToken;
	uint32 m_nDefIndex;
	uint32 m_nPoints;
	bool m_bOptional;
	bool m_bAdvanced;
};

//-----------------------------------------------------------------------------
// CEconItemDefinition
// Template Definition of a randomly created item
//-----------------------------------------------------------------------------
class CEconItemDefinition
{
public:
	CEconItemDefinition( void );
	virtual ~CEconItemDefinition( void );

	// BInitFromKV can be implemented on subclasses to parse additional values.
	virtual bool	BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors = NULL );
#if defined(CLIENT_DLL) || defined(GAME_DLL)
	virtual bool	BInitFromTestItemKVs( int iNewDefIndex, KeyValues *pKVItem, CUtlVector<CUtlString>* pVecErrors = NULL );
	virtual void	GeneratePrecacheModelStrings( bool bDynamicLoad, CUtlVector<const char *> *out_pVecModelStrings ) const;
	virtual void	GeneratePrecacheSoundStrings( bool bDynamicLoad, CUtlVector<const char *> *out_pVecSoundStrings ) const;
	virtual void	CopyPolymorphic( const CEconItemDefinition *pSourceDef ) { *this = *pSourceDef; }
#endif

	bool		BInitItemMappings( CUtlVector<CUtlString> *pVecErrors );

	void		BInitVisualBlockFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors = NULL );
	void		BInitStylesBlockFromKV( KeyValues *pKVStyles, perteamvisuals_t *pVisData, CUtlVector<CUtlString> *pVecErrors );

	item_definition_index_t	GetDefinitionIndex( void ) const	{ return m_nDefIndex; }
	bool		BEnabled( void ) const				{ return m_bEnabled; }
	bool		BLoadOnDemand( void ) const			{ return m_bLoadOnDemand; }
	bool		BHasBeenLoaded( void ) const		{ return m_bHasBeenLoaded; }
	const char	*GetDefinitionName( void ) const	{ return m_pszDefinitionName; }
	const char	*GetItemDefinitionName( void ) const	{ return m_pszDefinitionName; }
	const char	*GetItemClass( void ) const			{ return m_pszItemClassname; }
	const char	*GetItemBaseName( void ) const		{ return m_pszItemBaseName; }
	const char	*GetBrassModelOverride( void ) const{ return m_pszBrassModelOverride; }
	const char	*GetItemTypeName( void ) const		{ return m_pszItemTypeName; }
	uint8		GetMinLevel( void ) const			{ return m_unMinItemLevel; }
	uint8		GetMaxLevel( void ) const			{ return m_unMaxItemLevel; }
	uint8		GetItemSeries( void ) const			{ return m_unItemSeries; }
	uint8		GetQuality( void ) const			{ return m_nItemQuality; }
	void		SetRarity( uint8 nRarity )			{ Assert( m_nItemRarity == k_unItemRarity_Any ); m_nItemRarity = nRarity; } 
	uint8		GetRarity( void ) const				{ return m_nItemRarity; }
	uint8		GetForcedQuality( void ) const		{ return m_nForcedItemQuality; }
	uint16		GetDefaultDropQuantity( void ) const	{ return m_nDefaultDropQuantity; }
	KeyValues	*GetRawDefinition( void ) const		{ return m_pKVItem; }
	const char	*GetDefinitionString( const char *pszKeyName, const char *pszDefaultValue = "" ) const;
	KeyValues	*GetDefinitionKey( const char *pszKeyName ) const;
	const CUtlVector<static_attrib_t> &GetStaticAttributes( void ) const	{ return m_vecStaticAttributes; }
#ifdef TF_CLIENT_DLL
	uint32		GetNumConcreteItems() const			{ return m_unNumConcreteItems; }
#endif // TF_CLIENT_DLL

	// Data accessing
	bool		IsHidden( void ) const				{ return m_bHidden; }
	bool		IsImported( void ) const			{ return m_bImported; }
	bool		IsAllowedInMatch( void ) const		{ return m_bAllowedInThisMatch; }
	bool		IsBaseItem( void ) const			{ return m_bBaseItem; }
	bool		IsBundle( void ) const				{ return m_BundleInfo != NULL; }
	bool		HasProperName( void ) const			{ return m_bProperName; }
	const char	*GetClassToken( void ) const		{ return m_pszClassToken; }
	const char	*GetSlotToken( void ) const			{ return m_pszSlotToken; }
	bool		ShouldAttachToHands( void ) const	{ return m_bAttachToHands; }
	bool		ShouldAttachToHandsVMOnly( void ) const	{ return m_bAttachToHandsVMOnly; }
	bool		ShouldFlipViewmodels( void ) const	{ return m_bFlipViewModel; }
	int			GetInventoryImagePosition( int iIndex ) const	{ Assert( iIndex >= 0 && iIndex < 2); return m_iInventoryImagePosition[iIndex]; }
	int			GetInventoryImageSize( int iIndex ) const	{ Assert( iIndex >= 0 && iIndex < 2); return m_iInventoryImageSize[iIndex]; }
	int			GetDropType( void ) const			{ return m_iDropType; }
	const char	*GetHolidayRestriction( void ) const	{ return m_pszHolidayRestriction; }
	int			GetVisionFilterFlags( void ) const	{ return m_nVisionFilterFlags; }
	int			GetSubType( void ) const	{ return m_iSubType; }
	item_capabilities_t GetCapabilities( void ) const { return m_iCapabilities; }
	int			GetArmoryRemap( void ) const		{ return m_iArmoryRemap; }
	int			GetStoreRemap( void ) const			{ return m_iStoreRemap; }
	item_definition_index_t GetSetItemRemap() const { return m_unSetItemRemapDefIndex; }		// what def index do we consider ourself for purposes of determining "is an item equipped that satisfies this set slot?" (ie., Festive Huntsman -> Huntsman); default is to point to itself
	const char *GetXifierRemapClass() const			{ return m_pszXifierRemapClass; }
	const char	*GetBaseFunctionalItemName() const	{ return m_pszBaseFunctionalItemName; }
	const char *GetParticleSuffix() const			{ return m_pszParticleSuffix; }

	const CEconItemSetDefinition *GetItemSetDefinition( void ) const { return m_pItemSetDef; }
	void		SetItemSetDefinition( const CEconItemSetDefinition *pItemSetDef ) { Assert( !m_pItemSetDef ); m_pItemSetDef = pItemSetDef; }

	const CEconItemCollectionDefinition *GetItemCollectionDefinition( void ) const { return m_pItemCollectionDef; }
	void  SetItemCollectionDefinition( const CEconItemCollectionDefinition *pItemCollectionDef ) { Assert( !m_pItemCollectionDef ); m_pItemCollectionDef = pItemCollectionDef; }

	CEconItemPaintKitDefinition *GetCustomPainkKitDefinition( void ) const { return m_pItemPaintKitDef; }
	void  SetItemPaintKitDefinition( CEconItemPaintKitDefinition *pItemPaintKitDef ) { Assert( !m_pItemPaintKitDef ); m_pItemPaintKitDef = pItemPaintKitDef; }

	perteamvisuals_t	*GetPerTeamVisual( int iTeam ) const	{ return m_PerTeamVisuals[iTeam]; }

	bool IsTool() const									{ return m_bIsTool; }
	const IEconTool	*GetEconTool() const				{ return m_pTool; }
	template < class T >
	const T *GetTypedEconTool() const					{ return dynamic_cast<const T *>( GetEconTool() ); }

	const bundleinfo_t *GetBundleInfo( void ) const { return m_BundleInfo; }
	virtual int GetBundleItemCount( void ) const { return m_BundleInfo ? m_BundleInfo->vecItemDefs.Count() : 0; }
	virtual int GetBundleItem( int iIndex ) const { return m_BundleInfo ? m_BundleInfo->vecItemDefs[iIndex]->GetDefinitionIndex() : -1; }

	// Is this item contained in any bundles? GetContainingBundles() gets the CEconItemDefinitions for those bundles.
	const CUtlVector< const CEconItemDefinition * > &GetContainingBundles() const { return m_vecContainingBundleItemDefs; }
	uint32 GetContainingBundleCount() const { return m_vecContainingBundleItemDefs.Count(); }

	void AddSteamWorkshopContributor( uint32 unAccountID ) { if ( m_vecSteamWorkshopContributors.InvalidIndex() == m_vecSteamWorkshopContributors.Find( unAccountID ) ) { m_vecSteamWorkshopContributors.AddToTail( unAccountID ); } }
	const CUtlVector< uint32 > &GetSteamWorkshopContributors() const { return m_vecSteamWorkshopContributors; }
	bool BIsSteamWorkshopItem() const { return m_vecSteamWorkshopContributors.Count() > 0; }

	const char	*GetIconClassname( void ) const					{ return m_pszItemIconClassname; }
	const char	*GetLogClassname( void ) const					{ return m_pszItemLogClassname; }
	const char	*GetInventoryModel( void ) const				{ return m_pszInventoryModel; }
	const char	*GetInventoryImage( void ) const				{ return m_pszInventoryImage; }
	const char	*GetInventoryOverlayImage( int idx ) const		{ if ( m_pszInventoryOverlayImages.IsValidIndex( idx ) ) return m_pszInventoryOverlayImages[idx]; else return NULL; }
	int			GetInventoryOverlayImageCount( void ) const		{ return m_pszInventoryOverlayImages.Count(); }
	int			GetInspectPanelDistance( void ) const			{ return m_iInspectPanelDistance; }
	const char  *GetIconURLSmall() const						{ return GetIconURL( "s" ); } // Plain small
	const char  *GetIconURLLarge() const						{ return GetIconURL( "l" ); } // Plain large
	void		SetIconURL( const char* pszKey, const char *szURL )	{ m_pDictIcons->Insert( pszKey, CUtlString( szURL ) ); }
	const char  *GetIconURL( const char* pszKey ) const;
	const char	*GetBasePlayerDisplayModel() const				{ return m_pszBaseDisplayModel; }
	int			GetDefaultSkin() const							{ return m_iDefaultSkin; }
	const char  *GetWorldDisplayModel() const					{ return m_pszWorldDisplayModel; }
	const char  *GetCollectionReference() const					{ return m_pszCollectionReference; }

	// Some weapons need a custom model for icon generation. If this value is not present, the world model is used.
	virtual const char  *GetIconDisplayModel()	const;

	const char	*GetExtraWearableModel( void ) const			{ return m_pszWorldExtraWearableModel; }
	const char	*GetExtraWearableViewModel( void ) const		{ return m_pszWorldExtraWearableViewModel; }
	const char  *GetVisionFilteredDisplayModel() const			{ return m_pszVisionFilteredDisplayModel; }
	const char	*GetItemDesc( void ) const						{ return m_pszItemDesc; }
	const char	*GetArmoryDescString( void ) const				{ return m_pszArmoryDesc; }
	RTime32		GetExpirationDate( void ) const					{ return m_rtExpiration; }
	bool		ShouldShowInArmory( void ) const				{ return m_bShouldShowInArmory; }
	bool		IsActingAsAWearable( void ) const				{ return m_bActAsWearable; }
	bool		IsActingAsAWeapon( void ) const					{ return m_bActAsWeapon; }
	bool		GetHideBodyGroupsDeployedOnly( void ) const		{ return m_bHideBodyGroupsDeployedOnly; }
	bool		IsPackBundle( void ) const						{ return m_bIsPackBundle; }
	bool		IsPackItem( void ) const						{ return m_bIsPackItem; }
	CEconItemDefinition	*GetOwningPackBundle()					{ return m_pOwningPackBundle; }
	const CEconItemDefinition	*GetOwningPackBundle() const	{ return m_pOwningPackBundle; }
	const char	*GetDatabaseAuditTableName( void ) const		{ return m_pszDatabaseAuditTable; }

	void SetIsPackItem( bool bIsPackItem ) { m_bIsPackItem = bIsPackItem; }

	equip_region_mask_t GetEquipRegionMask( void ) const { return m_unEquipRegionMask; }
	equip_region_mask_t GetEquipRegionConflictMask( void ) const { return m_unEquipRegionConflictMask; }

	// Dynamic modification during gameplay
	void		SetAllowedInMatch( bool bAllowed )	{ m_bAllowedInThisMatch = bAllowed; }
	void		SetHasBeenLoaded( bool bLoaded )	{ m_bHasBeenLoaded = bLoaded; }

	// Generate and return a random level according to whatever leveling curve this definition uses.
	uint32		RollItemLevel( void ) const;

	const char *GetFirstSaleDate( void ) const;

	void		IterateAttributes( class IEconItemAttributeIterator *pIterator ) const;

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	// Visuals
	// Attached models
	int						GetNumAttachedModels( int iTeam ) const;
	attachedmodel_t			*GetAttachedModelData( int iTeam, int iIdx ) const;

	int						GetNumAttachedModelsFestivized( int iTeam ) const;
	attachedmodel_t			*GetAttachedModelDataFestivized( int iTeam, int iIdx ) const;

	// Attached particle systems
	int						GetNumAttachedParticles( int iTeam ) const;
	attachedparticlesystem_t *GetAttachedParticleData( int iTeam, int iIdx ) const;
	// Activities
	int						GetNumPlaybackActivities( int iTeam ) const;
	activity_on_wearable_t	*GetPlaybackActivityData( int iTeam, int iIdx ) const;
	// Animations
	int						GetNumAnimations( int iTeam ) const;
	animation_on_wearable_t	*GetAnimationData( int iTeam, int iIdx ) const;
	// Animation Overrides
	Activity				GetActivityOverride( int iTeam, Activity baseAct ) const;
	const char				*GetActivityOverride( int iTeam, const char *pszActivity ) const;
	const char				*GetReplacementForActivityOverride( int iTeam, Activity baseAct ) const;
	// Should the content (meshes, etc.) for this be streamed or preloaded?
	virtual bool			IsContentStreamable() const;
#endif // defined(CLIENT_DLL) || defined(GAME_DLL)

	// FX Overrides
	const char				*GetMuzzleFlash( int iTeam ) const;
	const char				*GetTracerEffect( int iTeam ) const;
	const char				*GetParticleEffect( int iTeam ) const;
	// Materials
	const char				*GetMaterialOverride( int iTeam ) const;
	// Sounds
	const char				*GetCustomSound( int iTeam, int iSound ) const;
	const char				*GetWeaponReplacementSound( int iTeam, /*WeaponSound_t*/ int iSound ) const;
	// Bodygroups
	int						GetHiddenParentBodygroup( int iTeam ) const;
	int						GetNumModifiedBodyGroups( int iTeam ) const;
	const char*				GetModifiedBodyGroup( int iTeam, int i, int& body ) const;
	bool					UsesPerClassBodygroups( int iTeam ) const;
	int						GetNumCodeControlledBodyGroups( int iTeam ) const;
	const char*				GetCodeControlledBodyGroup( int iIteam, int i, struct codecontrolledbodygroupdata_t &ccbgd ) const;

	style_index_t			GetNumStyles() const;
	style_index_t			GetNumSelectableStyles() const;
	const CEconStyleInfo   *GetStyleInfo( style_index_t unStyle ) const;

	int						GetViewmodelBodygroupOverride( int iTeam ) const;
	int						GetViewmodelBodygroupStateOverride( int iTeam ) const;
	int						GetWorldmodelBodygroupOverride( int iTeam ) const;
	int						GetWorldmodelBodygroupStateOverride( int iTeam ) const;

	int						GetPopularitySeed() const { return m_nPopularitySeed; }

	bool					HasEconTag( econ_tag_handle_t tag ) const { return m_vecTags.IsValidIndex( m_vecTags.Find( tag ) ); }

	bool					BValidForShuffle( void ) const { return m_bValidForShuffle; }
	bool					BValidForSelfMade( void ) const { return m_bValidForSelfMade; }

#ifdef GC_DLL
private:
	MUST_CHECK_RETURN bool	BInitializeEconItemGenerators( KeyValues *pKV, CUtlVector<CUtlString> *pVecErrors );

public:
	// If this returns true, all relevant property generators were applied to the item instance
	// passed in. If this returns false, some or none of the generators may have been applied,
	// but there are no guarantees about the item state.
	MUST_CHECK_RETURN bool	BApplyPropertyGenerators( CEconItem *pItem ) const;

	const CUtlVector<econ_tag_handle_t>& GetEconTags() const { return m_vecTags; }		// meant for internal/debug use only, not for runtime iteration
	const CUtlVector<econ_item_payment_rule_t>& GetPaymentRules() const { return m_vecPaymentRules; }

private:
	int AddPaymentRule( const econ_item_payment_rule_t& newRule );	// returns which payment rule number was just created
public:
#endif // GC_DLL

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	int						GetStyleSkin( style_index_t unStyle, int iTeam, bool bViewmodel ) const;
	const char*				GetStyleInventoryImage( style_index_t unStyle ) const;
	int						GetBestVisualTeamData( int iTeam ) const;
#endif // defined(CLIENT_DLL) || defined(GAME_DLL)


#ifdef DBGFLAG_VALIDATE
	void Validate( CValidator &validator, const char *pchName )
	{
		VALIDATE_SCOPE();
		ValidateObj( m_vecStaticAttributes );
		ValidatePtr( m_pKVItem );
		ValidatePtr( m_pProxyCriteria );
	}
#endif // DBGFLAG_VALIDATE


private:
	// Pointer to the raw KeyValue definition of the item
	KeyValues *	m_pKVItem;

	// Required values from m_pKVItem:

	// The number used to refer to this definition in the DB
	item_definition_index_t	m_nDefIndex;

	// False if this definition has been turned off and we're not using it to generate items
	bool		m_bEnabled;

	// These values specify the range of item levels that an item based off this definition can be generated within.
	uint8		m_unMinItemLevel;
	uint8		m_unMaxItemLevel;

	// This specifies an item quality that items from this definition must be set to. Used mostly to specify unique item definitions.
	uint8		m_nItemQuality;
	uint8		m_nForcedItemQuality;
	uint8		m_nItemRarity;

	// Default drop quantity
	uint16		m_nDefaultDropQuantity;

	// Item Series
	uint8		m_unItemSeries;

	// Static attributes (ones that are always on these items)
	CUtlVector<static_attrib_t> m_vecStaticAttributes;

	// Seeds the popular item list with this number of the item when the list is reset.
	uint8		m_nPopularitySeed;

	// ---------------------------------------------
	// Display related data
	// ---------------------------------------------
	// The base name of this item. i.e. "The Kritz-Krieg".
	const char		*m_pszItemBaseName;
	bool			m_bProperName;		// If set, the name will have "The" prepended to it, unless it's got a non-unique quality
										// in which case it'll have "A" prepended to the quality. i.e. A Community Kritzkrieg

	// The base type of this item. i.e. "Rocket Launcher" or "Shotgun".
	// This is often the same as the base name, but not always.
	const char		*m_pszItemTypeName;

	// The item's non-attribute description.
	const char		*m_pszItemDesc;

	// expiration time
	RTime32			m_rtExpiration;

	// The .mdl file used for this item when it's displayed in inventory-style boxes.
	const char		*m_pszInventoryModel;
	// Alternatively, the image used for this item when it's displayed in inventory-style boxes. If specified, it's used over the model.
	const char		*m_pszInventoryImage;
	// An optional image that's overlayed over the top of the base inventory image. It'll be RGB colored by the tint color of the item.
	CUtlVector<const char*>	m_pszInventoryOverlayImages;
	int				m_iInventoryImagePosition[2];
	int				m_iInventoryImageSize[2];
	int				m_iInspectPanelDistance;

	const char		*m_pszBaseDisplayModel;
	int				m_iDefaultSkin;
	bool			m_bLoadOnDemand;
	bool			m_bHasBeenLoaded;

	bool			m_bHideBodyGroupsDeployedOnly;

	// The .mdl file used for the world view.
	// This is inferior to using a c_model, but because the geometry of the sticky bomb launcher's
	// world model is significantly different from the view model the demoman pack requires
	// using two separate models for now.
	const char		*m_pszWorldDisplayModel;
	const char		*m_pszWorldExtraWearableModel;		// Some weapons attach an extra wearable item to the player
	const char		*m_pszWorldExtraWearableViewModel;	// Some weapons attach an extra wearable view model item to the player
	const char		*m_pszVisionFilteredDisplayModel;	// Some weapons display differently depending on the viewer's filters

	const char		*m_pszCollectionReference;			// Reference a colletion

	// If set, we use the base hands model for a viewmodel, and bonemerge the above player model
	bool			m_bAttachToHands;
	bool			m_bAttachToHandsVMOnly;

	// If set, we will force the view model to render flipped. Good for models built left handed.
	bool			m_bFlipViewModel;

	// This is a wearable that sits in a non-wearable loadout slot
	bool			m_bActAsWearable;	

	// This is a weapon that sits in a wearable slot (Action)
	bool			m_bActAsWeapon;

	// Is this Item a tool
	bool			m_bIsTool;

	// The set this item is a member of
	const CEconItemSetDefinition *m_pItemSetDef;
	const CEconItemCollectionDefinition *m_pItemCollectionDef;

	CEconItemPaintKitDefinition *m_pItemPaintKitDef;

	// A list of per-team visual data used to modify base model for visual recognition
	perteamvisuals_t	*m_PerTeamVisuals[TEAM_VISUAL_SECTIONS];

	// Optional override for specifying a custom shell ejection model
	const char		*m_pszBrassModelOverride;

	IEconTool		*m_pTool;
	bundleinfo_t	*m_BundleInfo;
	item_capabilities_t m_iCapabilities;

#ifdef TF_CLIENT_DLL
	uint32			m_unNumConcreteItems;		// This is the number of items that will actually end up in a user's inventory - this can be 0 for some items (e.g. map stamps in TF), 1 for a "regular" item, or many for bundles, etc.
#endif // TF_CLIENT_DLL

	CUtlDict< CUtlString >*	m_pDictIcons;

	// ---------------------------------------------
	// Creation related data
	// ---------------------------------------------
	// The entity classname for this item.
	const char		*m_pszItemClassname;

	// The entity name that will be displayed in log files.
	const char		*m_pszItemLogClassname;

	// The name of the icon used in the death notices.
	const char		*m_pszItemIconClassname;

	// This is the script file name of this definition. Used to generate items by script name.
	const char		*m_pszDefinitionName;

	// This is used for auditing purposes
	const char		*m_pszDatabaseAuditTable;

	bool			m_bHidden;
	bool			m_bShouldShowInArmory;
	bool			m_bBaseItem;
	bool			m_bImported;

	// A pack bundle is a bundle that contains items that are not for sale individually
	bool			m_bIsPackBundle;
	
	// A pack item is an item which is not for sale individually and is only for sale as part of a pack bundle. A 'regular' bundle can only include a pack bundle by explicitly including all of the pack bundle's items individually.
	// If this pointer is non-NULL, this item is considered to be a pack item (see CEconItemDefinition::IsPackItem()).
	CEconItemDefinition	*m_pOwningPackBundle;
	bool				m_bIsPackItem;

	// Contains information on how to describe items with this attribute in the Armory
	const char		*m_pszArmoryDesc;

	// Temporary(?) solution to allow xifiers to work on botkiller and festive variants of weapons
	const char		*m_pszXifierRemapClass;

	// Base item name -- used for grouping weapon functionality
	const char		*m_pszBaseFunctionalItemName;

	// For particle effects that have derivatives, what is the suffix for this item
	const char		*m_pszParticleSuffix;

	// ---------------------------------------------
	// Remapping data for armory/store
	// ---------------------------------------------
	int				m_iArmoryRemap;
	int				m_iStoreRemap;
	const char		*m_pszArmoryRemap;
	const char		*m_pszStoreRemap;

	// ---------------------------------------------
	// Crafting related data
	// ---------------------------------------------
	const char		*m_pszClassToken;
	const char		*m_pszSlotToken;

	// ---------------------------------------------
	// Gameplay related data
	// ---------------------------------------------
	// How to behave when the player wearing the item dies.
	int				m_iDropType;

	// Holiday restriction. Item only has an appearance when the holiday is in effect.
	const char		*m_pszHolidayRestriction;

	// Meet the pyro makes some items invisible unless you're wearing Pyro Goggles
	int				m_nVisionFilterFlags;

	// Temporary. Revisit this in the engineer update. Enables an additional buildable.
	int				m_iSubType;

	// Whitelist support for tournament mode
	bool			m_bAllowedInThisMatch;

	equip_region_mask_t	m_unEquipRegionMask;			// which equip regions does this item cover directly
	equip_region_mask_t m_unEquipRegionConflictMask;	// which equip regions does equipping this item prevent from having something in them

	item_definition_index_t m_unSetItemRemapDefIndex;	// reference to the definition index we want to consider this item for set matching purposes; see GetSetItemRemap()

#ifdef GC_DLL
	CUtlVector<const IEconItemPropertyGenerator *> m_vecPropertyGenerators;
	CUtlVector<econ_item_payment_rule_t> m_vecPaymentRules;
#endif // GC_DLL

	// False if this definition is not allowed to be part of a shuffled crate's contents
	bool		m_bValidForShuffle;

	// False if this definition should not grant self-made items
	bool		m_bValidForSelfMade;

protected:
	// Protected to allow subclasses to add/remove game-specific tags.
	CUtlVector<econ_tag_handle_t>	m_vecTags;
	CUtlVector<const CEconItemDefinition *> m_vecContainingBundleItemDefs;	// Item definition indices for any bundles which contain this item
	CUtlVector<uint32> m_vecSteamWorkshopContributors;

	friend class CEconItemSchema;
};

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline style_index_t CEconItemDefinition::GetNumStyles() const
{
	const perteamvisuals_t *pVisData = GetPerTeamVisual( 0 );

	if ( !pVisData )
		return 0;

	// Bad things will happen if we ever get more styles than will fit in our
	// style index type. Not Very Bad things, but bad things. Mostly we'll fail
	// to iterate over all our styles.
	return pVisData->m_Styles.Count();
}


//-----------------------------------------------------------------------------
// Purpose: Similar to GetNumStyles, but only the selectable styles
//-----------------------------------------------------------------------------
inline style_index_t CEconItemDefinition::GetNumSelectableStyles() const
{
	const perteamvisuals_t *pVisData = GetPerTeamVisual(0);

	if (!pVisData)
		return 0;

	style_index_t nCount = 0; 
	FOR_EACH_VEC( pVisData->m_Styles, i )
	{
		if( pVisData->m_Styles[i]->IsSelectable() )
		{
			++nCount;
		}
	}

	return nCount;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const CEconStyleInfo *CEconItemDefinition::GetStyleInfo( style_index_t unStyle ) const
{
	const perteamvisuals_t *pBaseVisuals = GetPerTeamVisual( 0 );
	if ( !pBaseVisuals || !pBaseVisuals->m_Styles.IsValidIndex( unStyle ) )
		return NULL;

	return pBaseVisuals->m_Styles[unStyle];
}

#if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetNumAttachedModels( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return 0;
	return GetPerTeamVisual(iTeam)->m_AttachedModels.Count(); 
#else
	return 0;
#endif
}
//-----------------------------------------------------------------------------
inline attachedmodel_t *CEconItemDefinition::GetAttachedModelData( int iTeam, int iIdx ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	perteamvisuals_t *pVisuals = GetPerTeamVisual(iTeam);
	Assert( pVisuals );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !pVisuals )
		return NULL;

	Assert( iIdx < pVisuals->m_AttachedModels.Count() );
	if ( iIdx >= pVisuals->m_AttachedModels.Count() )
		return NULL;

	return &pVisuals->m_AttachedModels[iIdx];
#else
	return NULL;
#endif
}
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetNumAttachedModelsFestivized( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	perteamvisuals_t *pVisuals = GetPerTeamVisual(iTeam);
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !pVisuals )
		return 0;
	return pVisuals->m_AttachedModelsFestive.Count();
#else
	return 0;
#endif
}
//-----------------------------------------------------------------------------
inline attachedmodel_t *CEconItemDefinition::GetAttachedModelDataFestivized( int iTeam, int iIdx ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	perteamvisuals_t *pVisuals = GetPerTeamVisual(iTeam);
	Assert( pVisuals );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !pVisuals )
		return NULL;

	Assert( iIdx < pVisuals->m_AttachedModelsFestive.Count() );
	if ( iIdx >= pVisuals->m_AttachedModelsFestive.Count() )
		return NULL;

	return &pVisuals->m_AttachedModelsFestive[iIdx];
#else
	return NULL;
#endif
}
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetNumPlaybackActivities( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return 0;
	return GetPerTeamVisual(iTeam)->m_Activities.Count(); 
#else
	return 0;
#endif
}

inline activity_on_wearable_t *CEconItemDefinition::GetPlaybackActivityData( int iTeam, int iIdx ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	Assert( GetPerTeamVisual(iTeam) );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;

	Assert( iIdx < GetPerTeamVisual(iTeam)->m_Activities.Count() );
	if ( iIdx >= GetPerTeamVisual(iTeam)->m_Activities.Count() )
		return NULL;

	return &GetPerTeamVisual(iTeam)->m_Activities[iIdx];
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetNumAnimations( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return 0;
	return GetPerTeamVisual(iTeam)->m_Animations.Count(); 
#else
	return 0;
#endif
}
inline animation_on_wearable_t *CEconItemDefinition::GetAnimationData( int iTeam, int iIdx ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	Assert( GetPerTeamVisual(iTeam) );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;

	Assert( iIdx < GetPerTeamVisual(iTeam)->m_Animations.Count() );
	if ( iIdx >= GetPerTeamVisual(iTeam)->m_Animations.Count() )
		return NULL;

	return &GetPerTeamVisual(iTeam)->m_Animations[iIdx];
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetNumAttachedParticles( int iTeam ) const
{ 
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return 0;
	return GetPerTeamVisual(iTeam)->m_AttachedParticles.Count(); 
#else
	return 0;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline attachedparticlesystem_t *CEconItemDefinition::GetAttachedParticleData( int iTeam, int iIdx ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	Assert( GetPerTeamVisual(iTeam) );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;

	Assert( iIdx < GetPerTeamVisual(iTeam)->m_AttachedParticles.Count() );
	if ( iIdx >= GetPerTeamVisual(iTeam)->m_AttachedParticles.Count() )
		return NULL;

	return &GetPerTeamVisual(iTeam)->m_AttachedParticles[iIdx];
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const char *CEconItemDefinition::GetMaterialOverride( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;
	return GetPerTeamVisual(iTeam)->pszMaterialOverride;
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const char *CEconItemDefinition::GetMuzzleFlash( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;
	return GetPerTeamVisual(iTeam)->pszMuzzleFlash;
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const char *CEconItemDefinition::GetTracerEffect( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;
	return GetPerTeamVisual(iTeam)->pszTracerEffect;
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const char *CEconItemDefinition::GetParticleEffect( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;
	return GetPerTeamVisual(iTeam)->pszParticleEffect;
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetHiddenParentBodygroup( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return -1;
	return GetPerTeamVisual(iTeam)->iHideParentBodyGroup;
#else
	return -1;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetNumModifiedBodyGroups( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return -1;
	return GetPerTeamVisual(iTeam)->m_Maps.m_ModifiedBodyGroupNames.Count();
#else
	return -1;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const char* CEconItemDefinition::GetModifiedBodyGroup( int iTeam, int i, int& body ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;
	body = GetPerTeamVisual(iTeam)->m_Maps.m_ModifiedBodyGroupNames[i];
	return GetPerTeamVisual(iTeam)->m_Maps.m_ModifiedBodyGroupNames.Key(i);
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetNumCodeControlledBodyGroups( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return -1;
	return GetPerTeamVisual(iTeam)->m_Maps.m_CodeControlledBodyGroupNames.Count();
#else
	return -1;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const char* CEconItemDefinition::GetCodeControlledBodyGroup( int iTeam, int i, codecontrolledbodygroupdata_t &ccbgd ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;
	ccbgd = GetPerTeamVisual(iTeam)->m_Maps.m_CodeControlledBodyGroupNames[i];
	return GetPerTeamVisual(iTeam)->m_Maps.m_CodeControlledBodyGroupNames.Key(i);
#else
	return NULL;
#endif
}

#if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetStyleSkin( style_index_t unStyle, int iTeam, bool bViewmodel ) const
{
	const CEconStyleInfo *pStyle = GetStyleInfo( unStyle );

	// Return our skin if we have a style or our default skin of -1 otherwise.
	return pStyle
		 ? pStyle->GetSkin( iTeam, bViewmodel )
		 : GetDefaultSkin();
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const char* CEconItemDefinition::GetStyleInventoryImage( style_index_t unStyle ) const
{
	const CEconStyleInfo *pStyle = GetStyleInfo( unStyle );

	return pStyle ? pStyle->GetInventoryImage() : NULL;
}

#endif // defined(CLIENT_DLL) || defined(GAME_DLL)

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetViewmodelBodygroupOverride( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return 0;
	return GetPerTeamVisual(iTeam)->m_iViewModelBodyGroupOverride;
#else
	return 0;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetViewmodelBodygroupStateOverride( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return 0;
	return GetPerTeamVisual(iTeam)->m_iViewModelBodyGroupStateOverride;
#else
	return 0;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetWorldmodelBodygroupOverride( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return 0;
	return GetPerTeamVisual(iTeam)->m_iWorldModelBodyGroupOverride;
#else
	return 0;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetWorldmodelBodygroupStateOverride( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return 0;
	return GetPerTeamVisual(iTeam)->m_iWorldModelBodyGroupStateOverride;
#else
	return 0;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline bool CEconItemDefinition::UsesPerClassBodygroups( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return false;
	return GetPerTeamVisual(iTeam)->bUsePerClassBodygroups;
#else
	return false;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const char *CEconItemDefinition::GetCustomSound( int iTeam, int iSound ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;
	if ( iSound < 0 || iSound >= MAX_VISUALS_CUSTOM_SOUNDS )
		return NULL;
	return GetPerTeamVisual(iTeam)->pszCustomSounds[iSound];
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline const char *CEconItemDefinition::GetWeaponReplacementSound( int iTeam, /* WeaponSound_t */ int iSound ) const
{
#ifndef CSTRIKE_DLL
	iTeam = GetBestVisualTeamData( iTeam );
	if ( iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS || !GetPerTeamVisual(iTeam) )
		return NULL;
	if ( iSound < 0 || iSound >= NUM_SHOOT_SOUND_TYPES )
		return NULL;
	return GetPerTeamVisual(iTeam)->pszWeaponSoundReplacements[iSound];
#else
	return NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline int CEconItemDefinition::GetBestVisualTeamData( int iTeam ) const
{
#ifndef CSTRIKE_DLL
	Assert( iTeam >= 0 && iTeam < TEAM_VISUAL_SECTIONS );
	// If we don't have data for the specified team, try to fall back to the base
	//	if ( !GetStaticData() )
	//		return 0;
	if ( (iTeam < 0 || iTeam >= TEAM_VISUAL_SECTIONS) || (iTeam > 0 && !GetPerTeamVisual(iTeam)) )
		return 0;
	return iTeam;
#else
	return 0;
#endif
}
#endif // defined(CLIENT_DLL) || defined(GAME_DLL)

//-----------------------------------------------------------------------------
// CTimedItemRewardDefinition
// Describes a periodic item reward
//-----------------------------------------------------------------------------
class CTimedItemRewardDefinition
{
public:
	CTimedItemRewardDefinition( void );
	CTimedItemRewardDefinition( const CTimedItemRewardDefinition &that );
	CTimedItemRewardDefinition &operator=( const CTimedItemRewardDefinition& rhs );

	~CTimedItemRewardDefinition( void ) { }

	bool		BInitFromKV( KeyValues *pKVTimedReward, CUtlVector<CUtlString> *pVecErrors = NULL );

	uint32		GetRandomFrequency( void ) const	{ return RandomFloat( m_unMinFreq, m_unMaxFreq ); }
	uint32		GetMinFrequency( void ) const		{ return m_unMinFreq; }
	uint32		GetMaxFrequency( void ) const		{ return m_unMaxFreq; }
	float		GetChance( void ) const				{ return m_flChance; }
	const CItemSelectionCriteria &GetCriteria( void ) const		{ return m_criteria; }
	const CEconLootListDefinition *GetLootList( void ) const	{ return m_pLootList; }

	bool BHasRequiredItem() const { return m_iRequiredItemDef != INVALID_ITEM_DEF_INDEX; }
	item_definition_index_t GetRequiredItem() const { return m_iRequiredItemDef; }

#ifdef DBGFLAG_VALIDATE
	void Validate( CValidator &validator, const char *pchName )
	{
		VALIDATE_SCOPE();
		ValidateObj( m_criteria );
	}
#endif // DBGFLAG_VALIDATE

private:
	// Frequency of how often the item is awarded
	uint32		m_unMinFreq;
	uint32		m_unMaxFreq;

	// The chance, between 0 and 1, that the item is rewarded
	float		m_flChance;

	// The criteria to use to select the item to reward
	CItemSelectionCriteria m_criteria;
	// Alternatively, the loot_list to use instead
	const CEconLootListDefinition *m_pLootList;

	item_definition_index_t m_iRequiredItemDef;
};

#ifdef GC_DLL
//-----------------------------------------------------------------------------
// CExperimentDefinition
//-----------------------------------------------------------------------------
struct experiment_group_t
{
	const char* m_pName;
	uint32 m_unNumParticipants;
	uint32 m_unMaxParticipants;
	KeyValues *m_pKeyValues;
};

class CExperimentDefinition
{
public:
	CExperimentDefinition( void );
	~CExperimentDefinition( void );

	bool BInitFromKV( KeyValues *pKVExperiment, CUtlVector<CUtlString> *pVecErrors = NULL );

	CUtlVector< experiment_group_t > &GetGroups() { return m_vecGroups; }

	uint32 GetID() const { return m_unExperimentID; }
	const char	*GetName( void ) const { return m_pKeyValues->GetString( "name", "unknown" ); }
	const char	*GetDescription( void ) const { return m_pKeyValues->GetString( "description", "unknown" ); }

	bool IsEnabled() const { return m_bEnabled; }
	bool IsFull() const { return m_unNumParticipants >= m_unMaxParticipants; }

	uint32 GetNumParticipants() const { return m_unNumParticipants; }
	void SetNumParticipants( uint32 unNumParticipants ) { m_unNumParticipants = unNumParticipants; }
	uint32 GetMaxParticipants() const { return m_unMaxParticipants; }

	bool ChooseGroup( uint32 &unGroup );

private:
	bool m_bEnabled;
	uint32 m_unExperimentID;
	uint32 m_unNumParticipants;
	uint32 m_unMaxParticipants;
	KeyValues *m_pKeyValues;
	CUtlVector< experiment_group_t > m_vecGroups;
};
#endif

//-----------------------------------------------------------------------------
// CItemLevelingDefinition
//-----------------------------------------------------------------------------
class CItemLevelingDefinition
{
public:
	CItemLevelingDefinition( void );
	CItemLevelingDefinition( const CItemLevelingDefinition &that );
	CItemLevelingDefinition &operator=( const CItemLevelingDefinition& rhs );

	~CItemLevelingDefinition( void );

	bool		BInitFromKV( KeyValues *pKVItemLevel, const char *pszLevelBlockName, CUtlVector<CUtlString> *pVecErrors = NULL );

	uint32		GetLevel( void ) const { return m_unLevel; }
	uint32		GetRequiredScore( void ) const { return m_unRequiredScore; }
	const char *GetNameLocalizationKey( void ) const { return m_pszLocalizedName_LocalStorage; }

private:
	uint32		m_unLevel;
	uint32		m_unRequiredScore;
	char	   *m_pszLocalizedName_LocalStorage;
};

//-----------------------------------------------------------------------------
// AchievementAward_t
// Holds the item to give away and the Data value to audit it with ( for cross
// game achievements)
//-----------------------------------------------------------------------------
struct AchievementAward_t
{
	AchievementAward_t( const AchievementAward_t & rhs )
		: m_sNativeName( rhs.m_sNativeName ),
		m_unSourceAppId( rhs.m_unSourceAppId ),
		m_unAuditData( rhs.m_unAuditData )
	{
		m_vecDefIndex.CopyArray( rhs.m_vecDefIndex.Base(), rhs.m_vecDefIndex.Count() );
	}
	AchievementAward_t(  ) {}

	CUtlString m_sNativeName;
	AppId_t m_unSourceAppId;
	uint32 m_unAuditData;
	CUtlVector<uint16> m_vecDefIndex;
};

enum eTimedRewardType
{
	kTimedRewards_RegularDrop,
	kTimedRewards_SupplyCrate,
	kTimedRewards_FreeTrialDrop,
	kTimedRewards_RecipeDrop,
	kTimedRewards_EventDrop02,
	kNumTimedRewards
};

struct kill_eater_score_type_t
{
	const char *m_pszTypeString;
	const char *m_pszLevelBlockName;
	bool		m_bAllowBotVictims;			// if true, we don't check for a valid Steam ID on the client before sending or a valid session on the GC before incrementing
#ifdef GC_DLL
	bool		m_bGCUpdateOnly;
	bool		m_AllowIncrementValues;		// if true, clients are allowed to send up the amount to increment by (ie., "did 100 damage") rather than implicitly assuming a value of 1
	bool		m_bIsBaseKillType;			// if true, when clients send up a notification of this type we'll also look for other relevant things on the GC, like whether the victim was a friend, etc.
#endif
};

// Index-to-string table, currently used for attribute value string lookups.
struct schema_string_table_entry_t
{
	int m_iIndex;
	const char *m_pszStr;
};

//-----------------------------------------------------------------------------
// CForeignAppImports
// Defines the way a single foreign app's items are mapped into this app
//-----------------------------------------------------------------------------

class CForeignAppImports
{
public:
	CForeignAppImports() : m_mapDefinitions( DefLessFunc( uint16 ) ) {}

	void AddMapping( uint16 unForeignDefIndex, const CEconItemDefinition *pDefn );
	const CEconItemDefinition *FindMapping( uint16 unForeignDefIndex ) const;

private:
	CUtlMap< uint16, const CEconItemDefinition *> m_mapDefinitions;
};

//-----------------------------------------------------------------------------
// ISchemaAttributeType
//-----------------------------------------------------------------------------
#ifdef GC_DLL
namespace GCSDK
{
	class CColumnSet;
	class CRecordBase;
	class CWebAPIValues;
};
#endif // GC_DLL

// ISchemaAttributeType is the base interface for a "type" of attribute, where "type" is defined as
// "something that describes the memory layout, the DB layout, how to convert between them, etc.".
// Most of the low-level work done with attributes, including DB reading/writing, packing/unpacking
// for wire traffic, and other leaf code works exclusively through this interface.
//
// The class hierarchy looks like:
//
//		ISchemaAttributeTypeBase< TAttribInMemoryType >:
//	
//			This describes a specific in-memory format for an attribute, without any association to
//			a particular DB, wire format, etc. We can't template the base class because it's an
//			interface. This implements about half of ISchemaAttributeType and has its own mini
//			interface consisting of ConvertTypedValueToByteStream()	and ConvertByteStreamToTypedValue(),
//			both of which do work on statically-typed values that don't exist at higher levels.
//
//		CSchemaAttributeTypeBase< TAttribSchType, TAttribInMemoryType >:
//
//			This handles the schema-related functions on ISchemaAttributeType. These exist at a lower
//			inheritance level than ISchemaAttributeTypeBase to allow code that needs to work type-safely
//			on attributes in memory, but that doesn't know or need to know anything about databases,
//			to exist. Examples of this include code that calls CEconItem::SetDynamicAttributeValue<T>().
//
//			Individual implementations of custom attribute type start making sense immediately as
//			subclasses of CSchemaAttributeTypeBase, for example CSchemaAttributeType_Default, which
//			implements all of the old, untyped attribute system logic.
//
//		CSchemaAttributeTypeProtobufBase< TAttribSchType, TProtobufValueType >
//
//			An easy way of automating most of the work for making a new attribute type is to have
//			the in-memory format be a protobuf object, allowing reflection, automatic network support,
//			etc.
//
// Creating a new custom protobuf attribute consists of three steps:
//
//		- create a new DB table that will hold your attribute data. This needs an itemid_t-sized item ID
//		  column named "ItemID", an attrib_definition_index_t-sized definition index column named "AttrDefIndex",
//		  and then whatever data you want to store.
//
//		- create a new protobuf message type that will hold your custom attribute contents. This exists
//		  on the client and the GC in the same format.
//
//		- implement a subclass of CSchemaAttributeTypeProtobufBase<>, for example:
//
//				class CSchemaAttributeType_StrangeScore : public CSchemaAttributeTypeProtobufBase< GC_SCH_REFERENCE( CSchItemAttributeStrangeScore ) CAttribute_StrangeScore >
//				{
//					virtual void ConvertEconAttributeValueToSch( itemid_t unItemId, const CEconItemAttributeDefinition *pAttrDef, const union attribute_data_union_t& value, GCSDK::CRecordBase *out_pSchRecord ) const OVERRIDE;
//					virtual void LoadSchToEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const GCSDK::CRecordBase *pSchRecord ) const OVERRIDE;
//				};
//
//		  Implement these two GC-only functions to convert from the in-memory format to the DB format and
//		  vice versa and you're good to go.
//
//		- register the new type in CEconItemSchema::BInitAttributeTypes().
//
// If the attribute type can't be silently converted to an already-existing attribute value type, a few other
// places will also fail to compile -- things like typed iteration, or compile-time type checking.
//
// Functions that start with "Convert" change the format of an attribute value (in a type-safe way wherever
// possible), copying the value from one of the passed-in parameters to the other. Functions that start with
// "Load" do a format conversion, but also add the post-conversion value to the passed-in CEconItem. This
// comes up most often when generating new items, either from the DB (LoadSch), the network (LoadByteSteam),
// or creation of a new item on the GC (LoadOrGenerate).
class ISchemaAttributeType
{
public:
	virtual ~ISchemaAttributeType() { }

	// Returns a unique integer describing the C++-in-memory-layout type used by this attribute type.
	// For example, something that stores "int" might return 0 and "CSomeFancyWideAttributeType" might
	// return 1. The actual values don't matter and can even differ between different runs of the game/GC.
	// The only important thing is that during a single run the value for a single type is consistent.
	virtual unsigned int GetTypeUniqueIdentifier() const = 0;

#ifdef GC_DLL
	// What's the whole column set (and associated DB table) that this attribute uses? Meant to be
	// implemented by subclasses that have DB type information.
	virtual const GCSDK::CColumnSet& GetFullColumnSet() const = 0;

	// Create an instance of a schema row. Mananging the memory is the responsibility of the caller.
	// Meant to be implemented by subclasses that have DB type information.
	virtual GCSDK::CRecordBase *CreateTypedSchRecord() const = 0;

	// ...
	virtual bool BAssetClassExportedAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value ) const { return true; }

	// Prepare a DB row describing an instance of this attribute for writing.
	virtual void ConvertEconAttributeValueToSch( itemid_t unItemId, const CEconItemAttributeDefinition *pAttrDef, const union attribute_data_union_t& value, GCSDK::CRecordBase *out_pSchRecord ) const = 0;

	// We have a row read from the database and an item to add it as an attribute for. This
	// does the opposite work of ConvertEconAttributeValueToSch() and also adds it to the CEconItem.
	virtual void LoadSchToEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const GCSDK::CRecordBase *pSchRecord ) const = 0;

	// Have this attribute type either copy the data straight out of the value union, or run the logic
	// described by pszCustomLogicDesc to generate a new value. Either way, some correctly-typed data
	// will wind up in an attribute on the target item. This is intended to call through to LoadEconAttributeValue()
	// to do the actual assignment.	This is only accessible on the GC.
	virtual void LoadOrGenerateEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount ) const = 0;

	virtual void GenerateEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount, attribute_data_union_t* out_pValue ) const = 0;
#endif // GC_DLL

	// Have this attribute type copy the data out of the value union and type-copy it onto the item. This
	// is accessible on clients as well as the GC.
	virtual void LoadEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const union attribute_data_union_t& value ) const = 0;

	// ...
	virtual void ConvertEconAttributeValueToByteStream( const union attribute_data_union_t& value, std::string *out_psBytes ) const = 0;

	// ...
	virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue, bool bEnableTerribleBackwardsCompatibilitySchemaParsingCode = false ) const = 0;

	// ...
	virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const = 0;

	// Used to deserialize a byte stream, probably from an on-wire protobuf message, instead an instance
	// of the attribute in memory. See ConvertByteStreamToTypedValue() for example implementation, or
	// ConvertTypedValueToByteStream() for an example of the byte-stream generator code.
	virtual void LoadByteStreamToEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const std::string& sBytes ) const = 0;

	// Give the subclass a chance to default-initialize a new value. For larger types, this may hit the
	// heap. This must be called before otherwise manipulating [out_pValue] through Convert*() functions.
	virtual void InitializeNewEconAttributeValue( attribute_data_union_t *out_pValue ) const = 0;

	// Free any heap-allocated memory from this attribute value. Is not responsible for zeroing out
	// pointers, etc.
	virtual void UnloadEconAttributeValue( union attribute_data_union_t *out_pValue ) const = 0;

	// ...
	virtual bool OnIterateAttributeValue( class IEconItemAttributeIterator *pIterator, const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value ) const = 0;

	// This could also be called "BIsHackyMessyOldAttributeType()". This determines whether the attribute
	// can be set at runtime on a CEconItemView instance, whether the gameserver can replicate the value to
	// game clients, etc. It really only makes sense for value types 32 bits or smaller.
	virtual bool BSupportsGameplayModificationAndNetworking() const { return false; }
};

//-----------------------------------------------------------------------------
// CEconItemSchema
// Defines the way econ items can be used in a game
//-----------------------------------------------------------------------------
typedef CUtlDict<CUtlConstString, int> ArmoryStringDict_t;
typedef CUtlDict< CUtlVector<CItemLevelingDefinition> * > LevelBlockDict_t;
typedef CUtlMap<unsigned int, kill_eater_score_type_t>	KillEaterScoreMap_t;
typedef CUtlDict< CUtlVector< schema_string_table_entry_t > * >	SchemaStringTableDict_t;

struct attr_type_t
{
	CUtlConstString m_sName;
	const ISchemaAttributeType *m_pAttrType;

	attr_type_t( const char *pszName, const ISchemaAttributeType *pAttrType )
		: m_sName( pszName )
		, m_pAttrType( pAttrType )
	{
	}
};

#if defined(CLIENT_DLL) || defined(GAME_DLL)
class IDelayedSchemaData
{
public:
	virtual ~IDelayedSchemaData() {}
	virtual bool InitializeSchema( CEconItemSchema *pItemSchema ) = 0;

protected:
	// Passing '0' as the expected version means "we weren't expecting any version in particular" and will
	// skip the sanity checking.
	bool InitializeSchemaInternal( CEconItemSchema *pItemSchema, CUtlBuffer& bufRawData, bool bInitAsBinary, uint32 nExpectedVersion );
};
#endif // defined(CLIENT_DLL) || defined(GAME_DLL)

class CEconStorePriceSheet;

class CEconItemSchema
{
public:
	CEconItemSchema(  );

private:
	CEconItemSchema( const CEconItemSchema & rhs );
	CEconItemSchema &operator=( CEconItemSchema & rhs );

public:
	virtual ~CEconItemSchema( void ) { Reset(); };

	// Setup & parse in the item data files.
	virtual bool BInit( const char *fileName, const char *pathID, CUtlVector<CUtlString> *pVecErrors = NULL );
	bool		BInitBinaryBuffer( CUtlBuffer &buffer, CUtlVector<CUtlString> *pVecErrors = NULL );
	bool		BInitTextBuffer( CUtlBuffer &buffer, CUtlVector<CUtlString> *pVecErrors = NULL );
#ifdef GC_DLL
	virtual bool DoPostPriceSheetLoadInit( CEconStorePriceSheet *pPriceSheet );	// Called once the price sheet's been loaded
#endif

	uint32		GetVersion() const { return m_unVersion; }
	CSHA		GetSchemaSHA() const { return m_schemaSHA; }
	uint32		GetResetCount() const { return m_unResetCount; }

	// Dump the schema for debug purposes
	bool		DumpItems ( const char *fileName, const char *pathID = NULL );

	// Perform the computation used to calculate the schema version
	static uint32 CalculateKeyValuesVersion( KeyValues *pKV );

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	// This function will immediately reinitialize the schema if it's safe to do so, or store off the data
	// if it isn't safe to update at the moment.
	bool		MaybeInitFromBuffer( IDelayedSchemaData *pDelayedSchemaData );

	// If there is saved schema initialization data, initialize it now. If there is no saved data, this
	// will return success.
	bool		BInitFromDelayedBuffer();
#endif // defined(CLIENT_DLL) || defined(GAME_DLL)

	// Accessors to the base properties
	EEquipType_t		GetEquipTypeFromClassIndex( int iClass ) const;
	equipped_class_t	GetAccountIndex() const								{ return m_unAccoutClassIndex; }
	equipped_class_t	GetFirstValidClass() const							{ return m_unFirstValidClass; }
	equipped_class_t	GetLastValidClass() const							{ return m_unLastValidClass; }
	bool				IsValidClass( equipped_class_t unClass )			{ return ( unClass >= m_unFirstValidClass && unClass <= m_unLastValidClass ) || unClass == GetAccountIndex(); }
	bool				IsValidItemSlot( equipped_slot_t unSlot, equipped_class_t unClass ) const { return IsValidItemSlot( unSlot, unClass == m_unAccoutClassIndex ? EQUIP_TYPE_ACCOUNT : EQUIP_TYPE_CLASS ); }
	bool				IsValidItemSlot( equipped_slot_t unSlot, EEquipType_t eType ) const	
	{
		return eType == EQUIP_TYPE_ACCOUNT ? unSlot >= m_unFirstValidAccountItemSlot && unSlot <= m_unLastValidAccountItemSlot
										   : unSlot >= m_unFirstValidClassItemSlot && unSlot <= m_unLastValidClassItemSlot; 
	}

	enum { kMaxItemPresetCount = 4 };
	uint32				GetNumAllowedItemPresets() const					{ return kMaxItemPresetCount; }
	bool				IsValidPreset( equipped_preset_t unPreset ) const	{ return unPreset <= GetNumAllowedItemPresets(); }

	uint32				GetMinLevel() const									{ return m_unMinLevel; }
	uint32				GetMaxLevel() const									{ return m_unMaxLevel; }

	// Accessors to the underlying sections
	typedef CUtlHashMapLarge<int, CEconItemDefinition*>	ItemDefinitionMap_t;
	const ItemDefinitionMap_t &GetItemDefinitionMap() const { return m_mapItems; }

	typedef CUtlMap<int, CEconItemDefinition*, int>	SortedItemDefinitionMap_t;
	const SortedItemDefinitionMap_t &GetSortedItemDefinitionMap() const { return m_mapItemsSorted; }

	typedef CUtlMap<int, CEconItemDefinition*, int>	ToolsItemDefinitionMap_t;
	const ToolsItemDefinitionMap_t &GetToolsItemDefinitionMap() const { return m_mapToolsItems; }

	typedef CUtlMap<int, CEconItemDefinition*, int>	BaseItemDefinitionMap_t;
	const BaseItemDefinitionMap_t &GetBaseItemDefinitionMap() const { return m_mapBaseItems; }

	typedef CUtlMap<const char*, CEconLootListDefinition *, int>	LootListDefinitionMap_t;
	const LootListDefinitionMap_t &GetLootLists() const { return m_mapLootLists; }

	typedef CUtlMap<int, const char*> RevolvingLootListDefinitionMap_t;
	const RevolvingLootListDefinitionMap_t  &GetRevolvingLootLists() const { return m_mapRevolvingLootLists; }

	typedef CUtlMap<const char*, int> BodygroupStateMap_t;
	const BodygroupStateMap_t  &GetDefaultBodygroupStateMap() const { return m_mapDefaultBodygroupState; }

	typedef CUtlVector<CEconColorDefinition *>	ColorDefinitionsList_t;

	typedef CUtlMap<const char *, KeyValues *, int> PrefabMap_t;

#ifdef GC_DLL
	struct periodic_score_t
	{
		eEconPeriodicScoreEvents	m_eEventType;
		bool						m_bGCUpdateOnly;				// if set, only code that runs on the GC can initiate a change of this stat (ie., counting gifts -> true; bots killed -> false)
		uint32						m_unTimePeriodLengthInSeconds;
		CEconItemDefinition		   *m_pRewardItemDefinition;
	};

	typedef CUtlVector<periodic_score_t> PeriodicScoreTypeList_t;
#endif // GC_DLL

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	CEconItemDefinition *GetDefaultItemDefinition() { return m_pDefaultItemDefinition; }

	bool SetupPreviewItemDefinition( KeyValues *pKV );
#endif

	const CUtlMap<int, CEconItemQualityDefinition, int > &GetQualityDefinitionMap() const { return m_mapQualities; }
	const CUtlMap<int, CEconItemAttributeDefinition, int > &GetAttributeDefinitionMap() const { return m_mapAttributes; }

	typedef CUtlMap<int, CEconCraftingRecipeDefinition*, int > RecipeDefinitionMap_t;
	const RecipeDefinitionMap_t &GetRecipeDefinitionMap() const { return m_mapRecipes; }

	typedef CUtlMap<const char*, CEconItemSetDefinition*, int > ItemSetMap_t;
	const ItemSetMap_t &GetItemSets() const { return m_mapItemSets; }

	typedef CUtlMap<const char*, CEconItemCollectionDefinition*, int > ItemCollectionMap_t;
	const ItemCollectionMap_t &GetItemCollections() const { return m_mapItemCollections; }

	typedef CUtlVector< int > ItemCollectionCrateMap_t;
	const ItemCollectionCrateMap_t &GetItemCollectionCrates() const { return m_vecItemCollectionCrates; }

	typedef CUtlMap<const char*, CEconItemPaintKitDefinition*, int > ItemPaintKitMap_t;
	const ItemPaintKitMap_t &GetItemPaintKits() const { return m_mapItemPaintKits; }

	typedef CUtlMap<const char*, CEconOperationDefinition*, int > OperationDefinitionMap_t;
	const OperationDefinitionMap_t &GetOperationDefinitions() const { return m_mapOperationDefinitions; }
	

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	const ArmoryStringDict_t	&GetArmoryDataItemClasses() const { return m_dictArmoryItemClassesDataStrings; }
	const ArmoryStringDict_t	&GetArmoryDataItemTypes() const { return m_dictArmoryItemTypesDataStrings; }
	const ArmoryStringDict_t	&GetArmoryDataItems() const { return m_dictArmoryItemDataStrings; }
	const ArmoryStringDict_t	&GetArmoryDataAttributes() const { return m_dictArmoryAttributeDataStrings; }
#elif defined(GC_DLL)
	CUtlVector< CExperimentDefinition > &GetExperiments() { return m_vecExperiments; }

	const CUtlVector< AppId_t > & GetForeignApps() const { return m_vecForeignApps; }
	const CEconItemDefinition *GetAppItemImport( AppId_t unAppID, uint16 usDefIndex ) const;
#endif

	const CTimedItemRewardDefinition* GetTimedReward( eTimedRewardType type ) const;

	const CEconLootListDefinition* GetLootListByName( const char* pListName, int *out_piIndex = NULL ) const;
	const CEconLootListDefinition* GetLootListByIndex( int iIdx ) const { return m_mapLootLists.IsValidIndex(iIdx) ? m_mapLootLists[iIdx] : NULL; }

	const CQuestObjectiveDefinition* GetQuestObjectiveByDefIndex( int iIdx ) const;
	const CUtlMap<int, CQuestObjectiveDefinition*, int >& GetQuestObjectives() const { return m_mapQuestObjectives; }

	uint8 GetDefaultQuality() const { return AE_UNIQUE; }

	void AssignDefaultBodygroupState( const char *pszBodygroupName, int iValue );

	equip_region_mask_t GetEquipRegionMaskByName( const char *pRegionName ) const;

	struct EquipRegion
	{
		CUtlConstString		m_sName;
		unsigned int		m_unBitIndex;		// which bit are we claiming ownership over? there might be multiple equip regions with the same bit if we're in a "shared" block
		equip_region_mask_t m_unMask;			// full region conflict mask
	};

	typedef CUtlVector<EquipRegion>		EquipRegionsList_t;
	const EquipRegionsList_t& GetEquipRegionsList() const { return m_vecEquipRegionsList; }

	equip_region_mask_t GetEquipRegionBitMaskByName( const char *pRegionName ) const;

	KeyValues *FindDefinitionPrefabByName( const char *pszPrefabName ) const;
	const PrefabMap_t& GetPrefabMap() const { return m_mapDefinitionPrefabs; }
	
	CUtlVector< CEconItemDefinition * > &GetBundles() { return m_vecBundles; }	// Retrieve a cached list of all bundles

	const char *FindStringTableEntry( const char *pszTableName, int iIndex ) const;

private:
	void SetEquipRegionConflict( int iRegion, unsigned int unBit );
	int GetEquipRegionIndexByName( const char *pRegionName ) const;

public:
	// Common lookup methods
	bool BGetItemQualityFromName( const char *pchName, uint8 *nQuality ) const;
	const CEconItemQualityDefinition *GetQualityDefinition( int nQuality ) const;
	const CEconItemQualityDefinition *GetQualityDefinitionByName( const char *pszDefName ) const;

	bool BGetItemRarityFromName( const char* pchName, uint8 *nRarity ) const;
	const CEconItemRarityDefinition *GetRarityDefinitionByMapIndex( int nRarityIndex ) const;
	const CEconItemRarityDefinition *GetRarityDefinition( int nRarity ) const;
	const CEconItemRarityDefinition *GetRarityDefinitionByName( const char *pszDefName ) const;
	virtual int GetRarityDefinitionCount( void ) const { return m_mapRarities.Count(); }
	virtual const char* GetRarityName( uint8 iRarity );
	virtual const char* GetRarityLocKey( uint8 iRarity );
	virtual const char* GetRarityColor( uint8 iRarity );
	virtual int GetRarityIndex( const char* pszRarity );

	const CEconItemCollectionDefinition *GetCollectionByName( const char* pCollectionName );

	virtual int GetItemSeriesDefinitionCount( void ) const { return m_mapItemSeries.Count(); }
	bool BGetItemSeries( const char* pchName, uint8 *nItemSeries ) const;
	const CEconItemSeriesDefinition *GetItemSeriesDefinition( int nRarity ) const;

	CEconItemDefinition *GetItemDefinition( int iItemIndex );
	const CEconItemDefinition *GetItemDefinition( int iItemIndex ) const;
	CEconItemAttributeDefinition *GetAttributeDefinition( int iAttribIndex );
	const CEconItemAttributeDefinition *GetAttributeDefinition( int iAttribIndex ) const;
	CEconItemAttributeDefinition *GetAttributeDefinitionByName( const char *pszDefName );
	const CEconItemAttributeDefinition *GetAttributeDefinitionByName( const char *pszDefName ) const;
	CEconCraftingRecipeDefinition *GetRecipeDefinition( int iRecipeIndex );
	CEconColorDefinition *GetColorDefinitionByName( const char *pszDefName );
	const CEconColorDefinition *GetColorDefinitionByName( const char *pszDefName ) const;
#ifdef CLIENT_DLL
	const char *GetSteamPackageLocalizationToken( uint32 unPackageId ) const;
#endif // CLIENT_DLL
	
	bool BCanGSCreateItems( uint32 unIP ) const;
#ifdef GC_DLL
	const AchievementAward_t *GetAchievementReward( const char *pchAchievementName, AppId_t unAppID ) const;
	const AchievementAward_t *GetAchievementRewardByData( uint32 unData ) const;
#endif
	const AchievementAward_t *GetAchievementRewardByDefIndex( uint16 usDefIndex ) const;
	bool BHasAchievementRewards( void ) const { return (m_dictAchievementRewards.Count() > 0); }

	static CUtlString ComputeAchievementName( AppId_t unAppID, const char *pchNativeAchievementName );

	// Iterating over the item definitions. Game needs this to precache data.
	CEconItemDefinition *GetItemDefinitionByName( const char *pszDefName );
	const CEconItemDefinition *GetItemDefinitionByName( const char *pszDefName ) const;

#ifdef GC_DLL
	random_attrib_t *GetRandomAttributeTemplateByName( const char *pszAttrTemplateName ) const;
#endif // GC_DLL

	attachedparticlesystem_t* GetAttributeControlledParticleSystem( int id );
	attachedparticlesystem_t* FindAttributeControlledParticleSystem( const char *pchSystemName );
	typedef CUtlMap<int, attachedparticlesystem_t > ParticleDefinitionMap_t;
	const ParticleDefinitionMap_t& GetAttributeControlledParticleSystems() const { return m_mapAttributeControlledParticleSystems; }

	const CUtlVector< int > *GetWeaponUnusualParticleIndexes() const { return &m_vecAttributeControlledParticleSystemsWeapons; }
	const CUtlVector< int > *GetCosmeticUnusualParticleIndexes() const { return &m_vecAttributeControlledParticleSystemsCosmetics; }
	const CUtlVector< int > *GetTauntUnusualParticleIndexes() const { return &m_vecAttributeControlledParticleSystemsTaunts; }

#ifdef CLIENT_DLL
	locchar_t *GetParticleSystemLocalizedName( int index ) const;
#endif // CLIENT_DLL

#ifdef GC_DLL
	const PeriodicScoreTypeList_t& GetPeriodicScoreTypeList() const { return m_vecPeriodicScoreTypes; }

	int						GetPeriodicScoreTypeCount() const { return GetPeriodicScoreTypeList().Count(); }	// how many types of events are we tracking? the range goes from 0 through this return value
	const periodic_score_t& GetPeriodicScoreInfo( int iPeriodicScoreIndex ) const;								// get the full info block for this periodic score -- event type, time period, etc.

	// Only intended to be used for generating data for the WebAPI.
	const KillEaterScoreMap_t& GetKillEaterScoreTypes() const { return m_mapKillEaterScoreTypes; }
	const SchemaStringTableDict_t& GetStringTables() const { return m_dictStringTable; }
#endif // GC_DLL

	item_definition_index_t GetCommunityMarketRemappedDefinitionIndex( item_definition_index_t unSearchItemDef ) const;

	const CUtlVector<attr_type_t>& GetAttributeTypes() const { return m_vecAttributeTypes; }
	const ISchemaAttributeType *GetAttributeType( const char *pszAttrTypeName ) const;

	const LevelBlockDict_t&	GetItemLevelingDataDict() const { return m_vecItemLevelingData; }

	const CUtlVector<CItemLevelingDefinition> *GetItemLevelingData( const char *pszLevelBlockName ) const
	{
		LevelBlockDict_t::IndexType_t i = m_vecItemLevelingData.Find( pszLevelBlockName );
		if ( i == LevelBlockDict_t::InvalidIndex() )
			return NULL;

		return m_vecItemLevelingData[i];
	}

	const CItemLevelingDefinition *GetItemLevelForScore( const char *pszLevelBlockName, uint32 unScore ) const;
	const char *GetKillEaterScoreTypeLocString( uint32 unScoreType ) const;
	const char *GetKillEaterScoreTypeLevelingDataName( uint32 unScoreType ) const;
	bool GetKillEaterScoreTypeAllowsBotVictims( uint32 unScoreType ) const;
#ifdef GC_DLL
	bool GetKillEaterScoreTypeGCOnlyUpdate( uint32 unScoreType ) const;
	bool GetKillEaterScoreTypeAllowsIncrementValues( uint32 unScoreType ) const;
#endif

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	void		ItemTesting_CreateTestDefinition( int iCloneFromItemDef, int iNewDef, KeyValues *pNewKV );
	void		ItemTesting_DiscardTestDefinition( int iDef );
#endif

#ifdef DBGFLAG_VALIDATE
	void Validate( CValidator &validator, const char *pchName );
#endif // DBGFLAG_VALIDATE

	econ_tag_handle_t GetHandleForTag( const char *pszTagName );			// non-const because it may create a new tag handle

	typedef CUtlDict<econ_tag_handle_t> EconTagDict_t;
#ifdef GC_DLL
	const EconTagDict_t& GetEconTagDict() const { return m_dictTags; }		// meant for internal/debug use only, not for runtime iteration
#endif // GC_DLL

	virtual RTime32 GetCustomExpirationDate( const char *pszExpirationDate ) const { return k_RTime32Nil; }

public:
	// Subclass interface.
	virtual CEconItemDefinition				*CreateEconItemDefinition()			{ return new CEconItemDefinition; }
	virtual CEconCraftingRecipeDefinition	*CreateCraftingRecipeDefinition()	{ return new CEconCraftingRecipeDefinition; }
	virtual CEconStyleInfo					*CreateEconStyleInfo()				{ return new CEconStyleInfo; }
	virtual CQuestObjectiveDefinition		*CreateQuestDefinition()			{ return new CQuestObjectiveDefinition; }

	virtual IEconTool						*CreateEconToolImpl( const char *pszToolType, const char *pszUseString, const char *pszUsageRestriction, item_capabilities_t unCapabilities, KeyValues *pUsageKV );

#ifdef GC_DLL
	virtual random_attrib_t					*CreateRandomAttribute( const char *pszContext, KeyValues *pRandomAttributesKV, CUtlVector<CUtlString> *pVecErrors = NULL );
#endif // GC_DLL

	virtual bool							BCanStrangeFilterApplyToStrangeSlotInItem( uint32 /*strange_event_restriction_t*/ unRestrictionType, uint32 unRestrictionValue, const IEconItemInterface *pItem, int iStrangeSlot, uint32 *out_pOptionalScoreType ) const;
	bool									AddQuestObjective( const CQuestObjectiveDefinition **ppQuestObjective, KeyValues *pKVObjective, CUtlVector<CUtlString> *pVecErrors );

	bool BInsertLootlist( const char *pListName, KeyValues *pKVLootList, CUtlVector<CUtlString> *pVecErrors );

#ifdef GC_DLL
	void PerformCaseBehaviorCheck();
#endif
protected:
	virtual void Reset( void );

	virtual bool BInitSchema( KeyValues *pKVRawDefinition, CUtlVector<CUtlString> *pVecErrors = NULL );
#ifdef TF_CLIENT_DLL
	virtual int CalculateNumberOfConcreteItems( const CEconItemDefinition *pItemDef );	// Let derived classes handle custom item types
#endif // TF_CLIENT_DLL

private:
	bool BInitGameInfo( KeyValues *pKVGameInfo, CUtlVector<CUtlString> *pVecErrors );
	bool BInitAttributeTypes( CUtlVector<CUtlString> *pVecErrors );
#ifdef GC_DLL
	bool BInitPeriodicScoring( KeyValues *pKVGameInfo, CUtlVector<CUtlString> *pVecErrors );
#endif // GC_DLL
	bool BInitDefinitionPrefabs( KeyValues *pKVPrefabs, CUtlVector<CUtlString> *pVecErrors );
	bool BInitItemSeries( KeyValues *pKVSeries, CUtlVector<CUtlString> *pVecErrors );
	bool BVerifyBaseItemNames( CUtlVector<CUtlString> *pVecErrors );
	bool BInitRarities( KeyValues *pKVRarities, KeyValues *pKVRarityWeights, CUtlVector<CUtlString> *pVecErrors );
	bool BInitQualities( KeyValues *pKVAttributes, CUtlVector<CUtlString> *pVecErrors );
	bool BInitColors( KeyValues *pKVColors, CUtlVector<CUtlString> *pVecErrors );
	bool BInitAttributes( KeyValues *pKVAttributes, CUtlVector<CUtlString> *pVecErrors );
	bool BInitEquipRegions( KeyValues *pKVEquipRegions, CUtlVector<CUtlString> *pVecErrors );
	bool BInitEquipRegionConflicts( KeyValues *pKVEquipRegions, CUtlVector<CUtlString> *pVecErrors );
	bool BInitItems( KeyValues *pKVAttributes, CUtlVector<CUtlString> *pVecErrors );
	bool BInitItemSets( KeyValues *pKVItemSets, CUtlVector<CUtlString> *pVecErrors );
	bool BInitTimedRewards( KeyValues *pKVTimeRewards, CUtlVector<CUtlString> *pVecErrors );
	bool BInitAchievementRewards( KeyValues *pKVTimeRewards, CUtlVector<CUtlString> *pVecErrors );
#ifdef GC_DLL
	bool BInitRandomAttributeTemplates( KeyValues *pKVRandomAttributeTemplates, CUtlVector<CUtlString> *pVecErrors );
#endif // GC_DLL
	bool BInitRecipes( KeyValues *pKVRecipes, CUtlVector<CUtlString> *pVecErrors );
	bool BInitLootLists( KeyValues *pKVLootLists, CUtlVector<CUtlString> *pVecErrors );
	bool BInitRevolvingLootLists( KeyValues *pKVRevolvingLootLists, CUtlVector<CUtlString> *pVecErrors );
	bool BInitItemCollections( KeyValues *pKVItemSets, CUtlVector<CUtlString> *pVecErrors );
	bool BInitCollectionReferences( CUtlVector<CUtlString> *pVecErrors );
	bool BInitItemPaintKitDefinitions( KeyValues *pKVPaintKits, CUtlVector<CUtlString> *pVecErrors );
	bool BInitOperationDefinitions( KeyValues *pKVGameInfo, KeyValues *pOperations, CUtlVector<CUtlString> *pVecErrors );

#ifdef TF_CLIENT_DLL
	bool BInitConcreteItemCounts( CUtlVector<CUtlString> *pVecErrors );
	bool BInitSteamPackageLocalizationToken( KeyValues *pKVSteamPackages, CUtlVector<CUtlString> *pVecErrors );
#endif // TF_CLIENT_DLL
	bool BInitItemLevels( KeyValues *pKVItemLevels, CUtlVector<CUtlString> *pVecErrors );
	bool BInitKillEaterScoreTypes( KeyValues *pKVItemLevels, CUtlVector<CUtlString> *pVecErrors );
	bool BInitStringTables( KeyValues *pKVStringTables, CUtlVector<CUtlString> *pVecErrors );
	bool BInitCommunityMarketRemaps( KeyValues *pKVCommunityMarketRemaps, CUtlVector<CUtlString> *pVecErrors );

	bool BPostSchemaInit( CUtlVector<CUtlString> *pVecErrors ) const;
	bool BInitAttributeControlledParticleSystems( KeyValues *pKVParticleSystems, CUtlVector<CUtlString> *pVecErrors );

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	bool BInitArmoryData( KeyValues *pKVArmoryData, CUtlVector<CUtlString> *pVecErrors );
#else
	bool BInitExperiements( KeyValues *pKVExperiments, CUtlVector<CUtlString> *pVecErrors );
	bool BInitForeignImports( CUtlVector<CUtlString> *pVecErrors );

	CForeignAppImports *FindOrAddAppImports( AppId_t unAppID );
#endif

	bool BVerifyLootListItemDropDates( const CEconLootListDefinition* pLootList, CUtlVector<CUtlString> *pVecErrors ) const;
	bool BRecurseiveVerifyLootListItemDropDates(  const CEconLootListDefinition* pLootList, const CEconLootListDefinition* pRootLootList, CUtlVector<CUtlString> *pVecErrors ) const;

	// Note: this returns pointers to the inside of a vector and/or NULL. Pointers are not intended to be
	// saved off and used later.
	const kill_eater_score_type_t *FindKillEaterScoreType( uint32 unScoreType ) const;

	uint32			m_unResetCount;

	KeyValues		*m_pKVRawDefinition;
	uint32			m_unVersion;
	CSHA			m_schemaSHA;

	// Class range
	equipped_class_t	m_unFirstValidClass;
	equipped_class_t	m_unLastValidClass;
	equipped_class_t	m_unAccoutClassIndex;

	// Item slot range
	equipped_slot_t		m_unFirstValidClassItemSlot;
	equipped_slot_t		m_unLastValidClassItemSlot;
	equipped_slot_t		m_unFirstValidAccountItemSlot;
	equipped_slot_t		m_unLastValidAccountItemSlot;

	// Number of allowed presets
	uint32			m_unNumItemPresets;

	// Allowable range of item levels for this app
	uint32			m_unMinLevel;
	uint32			m_unMaxLevel;

	// Total value of all the weights of the qualities
	uint32			m_unSumQualityWeights;

	// Name-to-implementation list of all unique attribute types (ie., "wide strange score").
	CUtlVector<attr_type_t>								m_vecAttributeTypes;

	// Contains the list of rarity definitions
	CUtlMap<int, CEconItemSeriesDefinition, int >		m_mapItemSeries;

	// Contains the list of rarity definitions
	CUtlMap<int, CEconItemRarityDefinition, int >		m_mapRarities;

	// Contains the list of item definitions read in from all data files.
	CUtlMap<int, CEconItemQualityDefinition, int >		m_mapQualities;

	// Contains the list of item definitions read in from all data files.
	ItemDefinitionMap_t									m_mapItems;

	CUtlMap<int, CQuestObjectiveDefinition*, int >		m_mapQuestObjectives;

	// A sorted version of the same map, for instances where we really want sorted data
	SortedItemDefinitionMap_t							m_mapItemsSorted;

	// List of all the tool items, is a sublist of mapItems
	ToolsItemDefinitionMap_t							m_mapToolsItems;

	// List of all base items, is a sublist of mapItems
	BaseItemDefinitionMap_t								m_mapBaseItems;

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	// What is the default item definition we'll return in the client code if we can't find the correct one?
	CEconItemDefinition								   *m_pDefaultItemDefinition;
#endif

	// Contains the list of attribute definitions read in from all data files.
	CUtlMap<int, CEconItemAttributeDefinition, int >	m_mapAttributes;

	// Contains the list of item recipes read in from all data files.
	RecipeDefinitionMap_t								m_mapRecipes;

	// Contains the list of item sets.
	ItemSetMap_t										m_mapItemSets;
	ItemCollectionMap_t									m_mapItemCollections;
	ItemCollectionCrateMap_t							m_vecItemCollectionCrates;

	OperationDefinitionMap_t							m_mapOperationDefinitions;

	// Paint Kit defintions
	ItemPaintKitMap_t									m_mapItemPaintKits;

	// Revolving loot lists.
	CUtlMap<int, const char*>							m_mapRevolvingLootLists;

	// Contains the list of loot lists.
	LootListDefinitionMap_t								m_mapLootLists;

	// List of events that award items based on time played
	CUtlVector<CTimedItemRewardDefinition>				m_vecTimedRewards;

	// list of items that will be awarded from achievements
	CUtlDict< AchievementAward_t *, int >				m_dictAchievementRewards;
	CUtlMap< uint32, AchievementAward_t * >				m_mapAchievementRewardsByData;

#ifdef GC_DLL
	// list of random attribute templates
	CUtlDict< random_attrib_t * >						m_dictRandomAttributeTemplates;
#endif // GC_DLL

	// Contains information for attribute attached particle systems
	CUtlMap<int, attachedparticlesystem_t >				m_mapAttributeControlledParticleSystems;
	CUtlVector< int >									m_vecAttributeControlledParticleSystemsCosmetics;
	CUtlVector< int >									m_vecAttributeControlledParticleSystemsWeapons;
	CUtlVector< int >									m_vecAttributeControlledParticleSystemsTaunts;


	// Contains information on which equip regions conflict with each other regions and how to
	// test for overlap.
	EquipRegionsList_t									m_vecEquipRegionsList;

	// Contains information about prefab KeyValues blocks that be can referenced elsewhere
	// in the schema.
	PrefabMap_t											m_mapDefinitionPrefabs;

	// Contains runtime color information, looked-up by name.
	ColorDefinitionsList_t								m_vecColorDefs;

	// Contains information about: a) every bodygroup that appears anywhere in the schema, and
	// b) whether they default to on or off.
	BodygroupStateMap_t									m_mapDefaultBodygroupState;

	// Various definitions can have any number of unique tags associated with them.
	EconTagDict_t										m_dictTags;

#ifdef GC_DLL
	// Information about our periodic score accumulators.
	PeriodicScoreTypeList_t								m_vecPeriodicScoreTypes;
#endif // GC_DLL

	// List of item leveling data.
	KillEaterScoreMap_t									m_mapKillEaterScoreTypes;

	SchemaStringTableDict_t m_dictStringTable;

	typedef CUtlMap< item_definition_index_t, item_definition_index_t, item_definition_index_t > CommunityMarketDefinitionRemapMap_t;
	CommunityMarketDefinitionRemapMap_t					m_mapCommunityMarketDefinitionIndexRemap;

#ifdef CLIENT_DLL
	// Steam-package-ID-to-localization-token map, used for modifying tooltips in the store.
	typedef CUtlMap< uint32, const char * > SteamPackageLocalizationTokenMap_t;
	SteamPackageLocalizationTokenMap_t					m_mapSteamPackageLocalizationTokens;
#endif // CLIENT_DLL

	LevelBlockDict_t m_vecItemLevelingData;

#if defined(CLIENT_DLL) || defined(GAME_DLL)
	// Contains Armory data key->localization string mappings
	ArmoryStringDict_t m_dictArmoryItemTypesDataStrings;
	ArmoryStringDict_t m_dictArmoryItemClassesDataStrings;
	ArmoryStringDict_t m_dictArmoryAttributeDataStrings;
	ArmoryStringDict_t m_dictArmoryItemDataStrings;

	// Used for delaying the parsing of the item schema until its safe to swap out the back end data.
	IDelayedSchemaData *m_pDelayedSchemaData;
#elif defined(GC_DLL)
	// GC only
	CUtlVector< CExperimentDefinition > m_vecExperiments;
	CUtlMap< AppId_t, CForeignAppImports *> m_mapForeignImports;
	CUtlVector< AppId_t > m_vecForeignApps;
#endif

	CUtlVector< CEconItemDefinition * > m_vecBundles;	// A cached list of all bundles
};

#ifdef GC_DLL
	void PerformIncrementKillEaterAttributeScore( CEconUserSession *pLockedOwnerSession, CEconItem *pItem, uint32 unEventType, uint32 unIncrementCount, bool bGCOrigination, GCSDK::CSharedObjectTransactionEx *pTransaction );
#endif // GC_DLL

extern CEconItemSchema & GEconItemSchema();

//-----------------------------------------------------------------------------
// CSchemaFieldHandle
//-----------------------------------------------------------------------------
template < class T >
class CSchemaFieldHandle
{
public:
	explicit CSchemaFieldHandle( const char *szName )
		: m_szName( szName )
	{
		m_pRef = GetTypedRef();
		m_unSchemaGeneration = GEconItemSchema().GetResetCount();
#if _DEBUG
		m_unVersion_Debug = GEconItemSchema().GetVersion();
#endif
	}

	operator const T *( void ) const
	{
		uint32 unSchemaGeneration = GEconItemSchema().GetResetCount();
		if ( m_unSchemaGeneration != unSchemaGeneration )
		{
			m_pRef = GetTypedRef();
			m_unSchemaGeneration = unSchemaGeneration;
#if _DEBUG
			m_unVersion_Debug = GEconItemSchema().GetVersion();
#endif
		}

#if _DEBUG
		Assert( m_unVersion_Debug == GEconItemSchema().GetVersion() );
#endif
		return m_pRef;
	}

	const T *operator->( void ) const
	{
		return static_cast<const T *>( *this );
	}

	const char *GetName( void ) const
	{
		return m_szName;
	}

private:
	const T *GetTypedRef() const;

private:
	const char *m_szName;

	mutable const T *m_pRef;
	mutable uint32 m_unSchemaGeneration;
#if _DEBUG
	mutable uint32 m_unVersion_Debug;
#endif
};

template < >
inline const CEconColorDefinition *CSchemaFieldHandle<CEconColorDefinition>::GetTypedRef( void ) const
{
	return GEconItemSchema().GetColorDefinitionByName( m_szName );
}

template < >
inline const CEconItemAttributeDefinition *CSchemaFieldHandle<CEconItemAttributeDefinition>::GetTypedRef( void ) const
{
	return GEconItemSchema().GetAttributeDefinitionByName( m_szName );
}

template < >
inline const CEconItemDefinition *CSchemaFieldHandle<CEconItemDefinition>::GetTypedRef( void ) const
{
	return GEconItemSchema().GetItemDefinitionByName( m_szName );
}

template < >
inline const CEconLootListDefinition *CSchemaFieldHandle<CEconLootListDefinition>::GetTypedRef( void ) const
{
	return GEconItemSchema().GetLootListByName( m_szName );
}

template < >
inline const attachedparticlesystem_t *CSchemaFieldHandle<attachedparticlesystem_t>::GetTypedRef( void ) const
{
	return GEconItemSchema().FindAttributeControlledParticleSystem( m_szName );
}

typedef CSchemaFieldHandle<CEconColorDefinition>			CSchemaColorDefHandle;
typedef CSchemaFieldHandle<CEconItemAttributeDefinition>	CSchemaAttributeDefHandle;
typedef CSchemaFieldHandle<CEconItemDefinition>				CSchemaItemDefHandle;
typedef CSchemaFieldHandle<CEconLootListDefinition>			CSchemaLootListDefHandle;
typedef CSchemaFieldHandle<attachedparticlesystem_t>		CSchemaParticleHandle;


struct steam_market_gc_identifier_t
{
	item_definition_index_t m_unDefIndex;
	uint8 m_unQuality;

	bool operator<( const struct steam_market_gc_identifier_t& b ) const
	{
		return (m_unDefIndex < b.m_unDefIndex)
			|| ((m_unDefIndex == b.m_unDefIndex) && (m_unQuality < b.m_unQuality));
	}
};

// Implementation reliant on earlier class content.
inline const CEconItemAttributeDefinition *static_attrib_t::GetAttributeDefinition() const
{
	return GEconItemSchema().GetAttributeDefinition( iDefIndex );
}

inline const ISchemaAttributeType *static_attrib_t::GetAttributeType() const
{
	const CEconItemAttributeDefinition *pAttrDef = GetAttributeDefinition();
	if ( !pAttrDef )
		return NULL;

	return pAttrDef->GetAttributeType();
}

// Utility function to convert datafile strings to ints.
int StringFieldToInt( const char *szValue, const char **pValueStrings, int iNumStrings, bool bDontAssert = false );
int StringFieldToInt( const char *szValue, const CUtlVector<const char *>& vecValueStrings, bool bDontAssert = false );

#ifdef GC_DLL
// Global econ-level helper functionality.
EUniverse GetUniverse();

bool BYieldingGetChangedItemDefinitions( int iComparisonColumn, CUtlVector<item_definition_index_t>& out_vecChangedDefIndices );
bool BYieldingUpdateItemDefinitionStateHashValue( GCSDK::CSQLAccess& sqlAccess, item_definition_index_t unItemDef, int iUpdatedColumn );
#endif // GC_DLL

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CAttributeLineItemLootList : public IEconLootList
{
public:
	static CSchemaAttributeDefHandle s_pAttrDef_RandomDropLineItems[4];
#ifdef GC_DLL
	static CSchemaAttributeDefHandle s_pAttrDef_RandomDropLineItemUnusualChance;
	static CSchemaAttributeDefHandle s_pAttrDef_RandomDropLineItemUnusualList;
#endif // GC_DLL
	static CSchemaAttributeDefHandle s_pAttrDef_RandomDropLineItemFooterDesc;

public:
	CAttributeLineItemLootList( const IEconItemInterface *pEconItem )
		: m_pEconItem( pEconItem )
	{
		//
	}

	virtual void EnumerateUserFacingPotentialDrops( IEconLootListIterator *pIt ) const OVERRIDE;
	virtual bool BPublicListContents() const OVERRIDE { return true; }		// any attribute data that clients have is public to them
	virtual const char *GetLootListHeaderLocalizationKey() const OVERRIDE;
	virtual const char *GetLootListFooterLocalizationKey() const OVERRIDE;
	virtual const char *GetLootListCollectionReference() const OVERRIDE;
	
#ifdef GC_DLL
	MUST_CHECK_RETURN virtual bool BGenerateSingleRollRandomItems( const CEconGameAccount *pGameAccount, bool bFreeAccount, CUtlVector<CEconItem *> *out_pvecItems, const CUtlVector< item_definition_index_t > *pVecAvoidItemDefs = NULL ) const OVERRIDE;
#endif // GC_DLL

private:
	const IEconItemInterface *m_pEconItem;
};

void MergeDefinitionPrefab( KeyValues *pKVWriteItem, KeyValues *pKVSourceItem );

#endif //ECONITEMSCHEMA_H