|
|
//====== Copyright ?, Valve Corporation, All rights reserved. =======
//
// Purpose: EconItemSchema: Defines a schema for econ items
//
//=============================================================================
#include "cbase.h"
#include "econ_item_schema.h"
#include "tier1/fmtstr.h"
#include "tier2/tier2.h"
#include "filesystem.h"
#include "schemainitutils.h"
#include "cstrike15_gcconstants.h"
#include <google/protobuf/text_format.h>
#if defined(CLIENT_DLL) || defined(GAME_DLL)
#include "econ_item_system.h"
#include "econ_item.h"
#include "activitylist.h"
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
#include "tf_gcmessages.h"
#endif
#endif
#if defined(CSTRIKE_CLIENT_DLL) || defined(CSTRIKE_DLL)
#include "cstrike15_gcmessages.pb.h"
#endif
#include "gametypes.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace GCSDK;
#if defined(GAME_DLL)
void PrecacheParticleFileAndSystems( const char *pParticleSystemFile ); #endif
#if defined(CLIENT_DLL)
bool CWebResource::s_Initialized = false; #endif
CEconItemSchema & GEconItemSchema() { #if defined( EXTERNALTESTS_DLL )
static CEconItemSchema g_econItemSchema; return g_econItemSchema; #else
return *ItemSystem()->GetItemSchema(); #endif
}
const char * g_arrQuestVars[ k_EQuestVar_Last ] = { "" }; /** Removed for partner depot **/
static void HelperValidateLocalizationStringToken( char const *pszToken ) { #ifdef CLIENT_DLL
if ( pszToken && *pszToken == '#' ) AssertMsg1( g_pVGuiLocalize->Find( pszToken ), "Schema is referencing a non-existant token: %s", pszToken ); #endif
}
const char *g_szDropTypeStrings[] = { "", // Blank and none mean the same thing: stay attached to the body.
"none", "drop", // The item drops off the body.
"break", // Not implemented, but an example of a type that could be added.
};
#if defined(CLIENT_DLL) || defined(GAME_DLL)
// Used to convert strings to ints for wearable animation types
const char *g_WearableAnimTypeStrings[NUM_WAP_TYPES] = { "on_spawn", // WAP_ON_SPAWN,
"start_building", // WAP_START_BUILDING,
"stop_building", // WAP_STOP_BUILDING,
}; #endif
const char *g_AttributeDescriptionFormats[] = { "value_is_percentage", // ATTDESCFORM_VALUE_IS_PERCENTAGE,
"value_is_inverted_percentage", // ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE
"value_is_additive", // ATTDESCFORM_VALUE_IS_ADDITIVE
"value_is_additive_percentage", // ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE
"value_is_or", // ATTDESCFORM_VALUE_IS_OR
"value_is_date", // ATTDESCFORM_VALUE_IS_DATE
"value_is_account_id", // ATTDESCFORM_VALUE_IS_ACCOUNT_ID
"value_is_particle_index", // ATTDESCFORM_VALUE_IS_PARTICLE_INDEX -> Could change to "string index"
"value_is_item_def", // ATTDESCFORM_VALUE_IS_ITEM_DEF
"value_is_color", // ATTDESCFORM_VALUE_IS_COLOR
"value_is_game_time", // ATTDESCFORM_VALUE_IS_GAME_TIME
"value_is_mins_as_hours", // ATTDESCFORM_VALUE_IS_MINS_AS_HOURS
"value_is_replace", // ATTDESCFORM_VALUE_IS_REPLACE
};
const char *g_EffectTypes[NUM_EFFECT_TYPES] = { "neutral", // ATTRIB_EFFECT_NEUTRAL = 0,
"positive", // ATTRIB_EFFECT_POSITIVE,
"negative", // ATTRIB_EFFECT_NEGATIVE,
};
const char *g_szParticleAttachTypes[] = { "absorigin", // PATTACH_ABSORIGIN = 0, // Create at absorigin, but don't follow
"absorigin_follow", // PATTACH_ABSORIGIN_FOLLOW, // Create at absorigin, and update to follow the entity
"customorigin", // PATTACH_CUSTOMORIGIN, // Create at a custom origin, but don't follow
"customorigin_follow", // PATTACH_CUSTOMORIGIN_FOLLOW, // Create at a custom origin, follow relative position to specified entity
"point", // PATTACH_POINT, // Create on attachment point, but don't follow
"point_follow", // PATTACH_POINT_FOLLOW, // Create on attachment point, and update to follow the entity
"eyes_follow", // PATTACH_EYES_FOLLOW, // Create on eyes of the attached entity, and update to follow the entity
"overhead_follow", // PATTACH_OVERHEAD_FOLLOW, // Create at the top of the entity's bbox
"worldorigin", // PATTACH_WORLDORIGIN, // Used for control points that don't attach to an entity
"rootbone_follow", // PATTACH_ROOTBONE_FOLLOW, // Create at the root bone of the entity, and update to follow
"point_follow_substepped", // PATTACH_POINT_FOLLOW_SUBSTEPPED,// Like point_follow with interpolation
"renderorigin_follow", // PATTACH_RENDERORIGIN_FOLLOW // Create at the renderorigin of the entity, and update to follow
};
const char *g_szParticleAttachToEnt[] = { "self", // ATTPART_TO_SELF,
"parent", // ATTPART_TO_PARENT,
};
//-----------------------------------------------------------------------------
// Purpose: Set the capabilities bitfield based on whether the entry is true/false.
//-----------------------------------------------------------------------------
const char *g_Capabilities[] = { "paintable", // ITEM_CAP_PAINTABLE
"nameable", // ITEM_CAP_NAMEABLE
"decodable", // ITEM_CAP_DECODABLE
"can_delete", // ITEM_CAP_CAN_DELETE
"can_customize_texture", // ITEM_CAP_CAN_CUSTOMIZE_TEXTURE
"usable", // ITEM_CAP_USABLE
"usable_gc", // ITEM_CAP_USABLE_GC
"can_gift_wrap", // ITEM_CAP_CAN_GIFT_WRAP
"usable_out_of_game", // ITEM_CAP_USABLE_OUT_OF_GAME
"can_collect", // ITEM_CAP_CAN_COLLECT
"can_craft_count", // ITEM_CAP_CAN_CRAFT_COUNT
"can_craft_mark", // ITEM_CAP_CAN_CRAFT_MARK
"paintable_team_colors", // ITEM_CAP_PAINTABLE_TEAM_COLORS
"can_be_restored", // ITEM_CAP_CAN_BE_RESTORED
"strange_parts", // ITEM_CAP_CAN_USE_STRANGE_PARTS
"paintable_unusual", // ITEM_CAP_PAINTABLE_UNUSUAL
"can_increment", // ITEM_CAP_CAN_INCREMENT
"uses_essence", // ITEM_CAP_USES_ESSENCE
"autograph", // ITEM_CAP_AUTOGRAPH
"recipe", // ITEM_CAP_RECIPE
"can_sticker", // ITEM_CAP_CAN_STICKER
"can_stattrack_swap", // ITEM_CAP_STATTRACK_SWAP
};
const char* g_AssetModifiers[] = { "activity", "announcer", "announcer_preview", "hud_skin", "ability_name", "sound", "speech", "particle", "particle_snapshot", "particle_control_point", "entity_model", "entity_scale", "icon_replacement", "ability_icon_replacement", "courier", "courier_flying", "hero_model_change" };
#define RETURN_ATTRIBUTE_STRING( attrib_name, default_string ) \
static CSchemaAttributeDefHandle pAttribString( attrib_name ); \ const char *pchResultAttribString = default_string; \ FindAttribute_UnsafeBitwiseCast< CAttribute_String >( this, pAttribString, &pchResultAttribString ); \ return pchResultAttribString;
#define RETURN_ATTRIBUTE_STRING_F( func_name, attrib_name, default_string ) \
const char *func_name( void ) const { RETURN_ATTRIBUTE_STRING( attrib_name, default_string ) }
EAssetModifier GetAssetModifierType( const char* pszType ) { for ( int i=0; i<AM_MAX; ++i ) { if ( Q_strcmp( pszType, g_AssetModifiers[i] ) == 0 ) return (EAssetModifier) i; }
return AM_Invalid; }
CUniformRandomStream CEconItemSchema::m_RandomStream;
static void ParseCapability( item_capabilities_t &capsBitfield, KeyValues* pEntry ) { COMPILE_TIME_ASSERT( ARRAYSIZE(g_Capabilities) == NUM_ITEM_CAPS ); int idx = StringFieldToInt( pEntry->GetName(), g_Capabilities, ARRAYSIZE(g_Capabilities) ); if ( idx < 0 ) { return; } int bit = 1 << idx; if ( pEntry->GetBool() ) { (int&)capsBitfield |= bit; } else { (int&)capsBitfield &= ~bit; } }
//-----------------------------------------------------------------------------
// Purpose: interpret tint colors as integers for the values
//-----------------------------------------------------------------------------
static bool Helper_ExtractIntegerFromValueStringEntry( const char *szValue, int *pnValue ) { if ( V_isdigit( *szValue ) ) { *pnValue = V_atoi( szValue ); return true; } else if ( char const *szTint = StringAfterPrefix( szValue, "tint_") ) { if ( !V_stricmp( szTint, "min" ) ) { *pnValue = 1; return true; } if ( !V_stricmp( szTint, "max" ) ) { *pnValue = GEconItemSchema().GetGraffitiTintMaxValidDefID(); return true; } if ( const CEconGraffitiTintDefinition *pDef = GEconItemSchema().GetGraffitiTintDefinitionByName( szTint ) ) { *pnValue = pDef->GetID(); return true; } return false; } return false; }
//-----------------------------------------------------------------------------
// Purpose: interprets a string such as "1-3,5-20,45,46,47" and adds the
// individual uint32s into the specified vector.
//-----------------------------------------------------------------------------
static bool Helper_ExtractIntegersFromValuesString( const char * pszValues, CCopyableUtlVector< uint32 > &vecValues ) { bool bResult = true; CUtlVector< char* > vecValueStrings; V_SplitString( pszValues, ",", vecValueStrings );
if ( vecValueStrings.Count() < 1 ) bResult = false;
FOR_EACH_VEC( vecValueStrings, i ) { if ( V_strstr( vecValueStrings[ i ], "-" ) ) { CUtlVector< char* > vecRangeStrings; V_SplitString( vecValueStrings[ i ], "-", vecRangeStrings );
if ( vecRangeStrings.Count() == 2 ) { int iRangeMin = 0, iRangeMax = 0; if ( !Helper_ExtractIntegerFromValueStringEntry( vecRangeStrings[ 0 ], &iRangeMin ) || !Helper_ExtractIntegerFromValueStringEntry( vecRangeStrings[ 1 ], &iRangeMax ) || ( iRangeMin >= iRangeMax ) ) { bResult = false; break; }
for ( int j = iRangeMin; j <= iRangeMax; j++ ) { vecValues.AddToTail( j ); } } else { bResult = false; break; }
vecRangeStrings.PurgeAndDeleteElements(); } else { int iValue = 0; if ( !Helper_ExtractIntegerFromValueStringEntry( vecValueStrings[ i ], &iValue ) ) { bResult = false; break; } vecValues.AddToTail( iValue ); }
}
vecValueStrings.PurgeAndDeleteElements();
return bResult;
}
#if defined ( CSTRIKE15 )
const uint32 g_unNumWearBuckets = 3; uint64 Helper_GetAlternateIconKeyForWeaponPaintWearItem( item_definition_index_t nDefIdx, uint32 nPaintId, uint32 nWear ) { return ( nDefIdx << 16 ) + ( nPaintId << 2 ) + nWear;
} uint64 Helper_GetAlternateIconKeyForTintedStickerItem( uint32 nStickerKitID, uint32 unTintID ) { unTintID = CombinedTintIDGetHSVID( unTintID ); return ( uint64( 1 ) << 32 ) | ( ( nStickerKitID & 0xFFFFFF ) << 8 ) | ( unTintID & 0xFF ); } #endif
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CEconItemQualityDefinition::CEconItemQualityDefinition( void ) : m_nValue( INT_MAX ) , m_bCanSupportSet( false ) , m_unWeight( 0 ) , m_bExplicitMatchesOnly( false ) { }
//-----------------------------------------------------------------------------
// Purpose: Copy constructor
//-----------------------------------------------------------------------------
CEconItemQualityDefinition::CEconItemQualityDefinition( const CEconItemQualityDefinition &that ) { (*this) = that; }
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CEconItemQualityDefinition &CEconItemQualityDefinition::operator=( const CEconItemQualityDefinition &rhs ) { m_nValue = rhs.m_nValue; m_strName = rhs.m_strName; m_bCanSupportSet = rhs.m_bCanSupportSet; m_unWeight = rhs.m_unWeight; m_bExplicitMatchesOnly = rhs.m_bExplicitMatchesOnly;
return *this; }
//-----------------------------------------------------------------------------
// Purpose: Initialize the quality definition
// Input: pKVQuality - The KeyValues representation of the quality
// schema - The overall item schema for this attribute
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemQualityDefinition::BInitFromKV( KeyValues *pKVQuality, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) {
m_nValue = pKVQuality->GetInt( "value", -1 ); m_strName = pKVQuality->GetName(); m_bCanSupportSet = pKVQuality->GetBool( "canSupportSet" ); m_strHexColor = pKVQuality->GetString( "hexColor" ); m_unWeight = pKVQuality->GetInt( "weight", 0 );
// Check for required fields
SCHEMA_INIT_CHECK( NULL != pKVQuality->FindKey( "value" ), CFmtStr( "Quality definition %s: Missing required field \"value\"", pKVQuality->GetName() ) );
#if defined(CLIENT_DLL) || defined(GAME_DLL)
return SCHEMA_INIT_SUCCESS(); #endif
// Check for data consistency
SCHEMA_INIT_CHECK( 0 != Q_stricmp( GetName(), "any" ), CFmtStr( "Quality definition any: The quality name \"any\" is a reserved keyword and cannot be used." ) );
SCHEMA_INIT_CHECK( m_nValue != k_unItemQuality_Any, CFmtStr( "Quality definition %s: Invalid value (%d). It is reserved for Any", GetName(), k_unItemQuality_Any ) );
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CEconItemRarityDefinition::CEconItemRarityDefinition( void ) : m_nValue( INT_MAX ) { }
//-----------------------------------------------------------------------------
// Purpose: Copy constructor
//-----------------------------------------------------------------------------
CEconItemRarityDefinition::CEconItemRarityDefinition( const CEconItemRarityDefinition &that ) { (*this) = that; }
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CEconItemRarityDefinition &CEconItemRarityDefinition::operator=( const CEconItemRarityDefinition &rhs ) { m_nValue = rhs.m_nValue; m_strName = rhs.m_strName; m_strLocKey = rhs.m_strLocKey; m_strWepLocKey = rhs.m_strWepLocKey; m_strLootList = rhs.m_strLootList; m_strRecycleLootList = rhs.m_strRecycleLootList; m_strDropSound = rhs.m_strDropSound; m_strNextRarity = rhs.m_strNextRarity; m_iWhiteCount = rhs.m_iWhiteCount; m_iBlackCount = rhs.m_iBlackCount; m_flWeight = rhs.m_flWeight;
return *this; }
//-----------------------------------------------------------------------------
// Purpose: Initialize the rarity definition
//-----------------------------------------------------------------------------
bool CEconItemRarityDefinition::BInitFromKV( KeyValues *pKVRarity, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { m_nValue = pKVRarity->GetInt( "value", -1 ); m_strName = pKVRarity->GetName(); m_strLocKey = pKVRarity->GetString( "loc_key" ); m_strWepLocKey = pKVRarity->GetString( "loc_key_weapon" );
m_iAttribColor = GetAttribColorIndexForName( pKVRarity->GetString( "color" ) ); m_strLootList = pKVRarity->GetString( "loot_list" ); // Not required.
m_strRecycleLootList = pKVRarity->GetString( "recycle_list" ); // Not required.
m_strDropSound = pKVRarity->GetString( "drop_sound" ); m_strNextRarity = pKVRarity->GetString( "next_rarity" ); // Not required.
m_flWeight = pKVRarity->GetFloat( "weight", 0 );
// Check for required fields
SCHEMA_INIT_CHECK( NULL != pKVRarity->FindKey( "value" ), CFmtStr( "Rarity definition %s: Missing required field \"value\"", pKVRarity->GetName() ) );
SCHEMA_INIT_CHECK( NULL != pKVRarity->FindKey( "loc_key" ), CFmtStr( "Rarity definition %s: Missing required field \"loc_key\"", pKVRarity->GetName() ) );
#if defined(CLIENT_DLL) || defined(GAME_DLL)
return SCHEMA_INIT_SUCCESS(); #endif
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconColorDefinition::BInitFromKV( KeyValues *pKVColor, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { m_strName = pKVColor->GetName(); m_strColorName = pKVColor->GetString( "color_name" ); m_strHexColor = pKVColor->GetString( "hex_color" );
SCHEMA_INIT_CHECK( !m_strColorName.IsEmpty(), CFmtStr( "Quality definition %s: missing \"color_name\"", GetName() ) );
SCHEMA_INIT_CHECK( !m_strHexColor.IsEmpty(), CFmtStr( "Quality definition %s: missing \"hex_color\"", GetName() ) );
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconGraffitiTintDefinition::BInitFromKV( KeyValues *pKVColor, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { m_nID = pKVColor->GetInt( "id" ); m_strColorName = pKVColor->GetName(); m_strHexColor = pKVColor->GetString( "hex_color" );
SCHEMA_INIT_CHECK( !m_strColorName.IsEmpty(), CFmtStr( "Graffiti tint definition #%d %s: missing name", GetID(), GetColorName() ) );
SCHEMA_INIT_CHECK( !m_strHexColor.IsEmpty() && ( m_strHexColor.Get()[0] == '#' ), CFmtStr( "Graffiti tint #%d %s: missing or invalid \"hex_color\"", GetID(), GetColorName() ) );
m_unHexColorRGB = ( !m_strHexColor.IsEmpty() ) ? V_atoi( CFmtStr( "0x%s", m_strHexColor.Get() + 1 ) ) : 0;
return !m_strColorName.IsEmpty() && !m_strHexColor.IsEmpty() && ( m_strHexColor.Get()[0] == '#' ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconMusicDefinition::BInitFromKV( KeyValues *pKVMusicDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { nID = Q_atoi( pKVMusicDef->GetName() ); m_strName = pKVMusicDef->GetString( "name" ); m_strNameLocToken = pKVMusicDef->GetString( "loc_name" ); m_strLocDescription = pKVMusicDef->GetString( "loc_description" ); m_strPedestalDisplayModel = pKVMusicDef->GetString( "pedestal_display_model" ); m_strInventoryImage = pKVMusicDef->GetString( "image_inventory" );
SCHEMA_INIT_CHECK( ( nID > 0 ), CFmtStr( "Music definition %s: name must be a positive integer", GetName() ) );
SCHEMA_INIT_CHECK( !m_strName.IsEmpty(), CFmtStr( "Music definition %s: missing \"name\"", GetName() ) );
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconQuestDefinition::BInitFromKV( KeyValues *pKVQuestDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { //TODO - do we care to parse quest definitions on GC at all or only on game server and client?
nID = Q_atoi( pKVQuestDef->GetName() ); SCHEMA_INIT_CHECK( ( nID > 0 ), CFmtStr( "Quest definition %s: name must be a positive integer", GetName() ) );
m_strName = pKVQuestDef->GetString( "name" ); SCHEMA_INIT_CHECK( !m_strName.IsEmpty(), CFmtStr( "Quest definition %s: missing \"name\"", GetName() ) );
m_strGameMode = pKVQuestDef->GetString( "gamemode" ); m_strMapGroup = pKVQuestDef->GetString( "mapgroup" ); m_strMap = pKVQuestDef->GetString( "map" );
#ifndef GC_DLL
static bool bLoadBannedWords = ( !!CommandLine()->FindParm( "-usebanlist" ) ) || ( !!CommandLine()->FindParm( "-perfectworld" ) ); if ( bLoadBannedWords && !V_stricmp( m_strMap.Get(), "ar_monastery" ) ) m_strMap = "ar_shoots"; #endif
m_bIsAnEvent = pKVQuestDef->GetBool( "is_an_event", false );
// Campaign quests require client-exposed points remaining.
// load non-GC only points if it exists.
// Otherwise look for "gc_generation_settings/points"
// quest events are always 1 point.
if ( m_bIsAnEvent ) { m_vecQuestPoints.AddToTail( 1 ); } else { const char* pszPointsRemaining = pKVQuestDef->GetString( "points" );
m_vecQuestPoints.Purge();
if ( pszPointsRemaining && pszPointsRemaining[ 0 ] ) { SCHEMA_INIT_CHECK( Helper_ExtractIntegersFromValuesString( pszPointsRemaining, m_vecQuestPoints ), CFmtStr( "Quest definition %s specifies a malformed values range: %s", GetName(), pszPointsRemaining ) ); } else { // if points aren't specified then default to '1'
m_vecQuestPoints.AddToTail( 1 ); } }
// campaigns use quest-defined rewards rather than attributes rolled later.
m_strRewardLootList = pKVQuestDef->GetString( "quest_reward" );
m_nDifficulty = pKVQuestDef->GetInt( "difficulty", 1 );
m_nOperationalPoints = pKVQuestDef->GetInt( "operational_points", 0 );
if ( !m_bIsAnEvent ) { m_nXPReward = pKVQuestDef->GetInt( "xp_reward", ( m_nDifficulty + 1 ) * 100 ); // campaign quest: 1 = 200, 2 = 300, 3 = 400
} else { m_nXPReward = pKVQuestDef->GetInt( "gc_generation_settings/xp_reward", 1 ); // default quest event xp reward to 1 per action
}
m_nTargetTeam = pKVQuestDef->GetInt( "target_team", 0 );
m_strExpr = pKVQuestDef->GetString( "expression" );
// BONUS
m_strBonusExpr = pKVQuestDef->GetString( "expr_bonus" );
// set bonus percent only if a bonus expression exists
if ( !m_strBonusExpr.IsEmpty() ) { m_nXPBonusPercent = pKVQuestDef->GetInt( "xp_bonus_percent", 100 ); // default bonus is 100%
} else { m_nXPBonusPercent = 0; }
#ifdef CLIENT_DLL // strings
m_strNameLocToken = pKVQuestDef->GetString( "loc_name" ); if ( !m_strNameLocToken.IsEmpty() ) HelperValidateLocalizationStringToken( m_strNameLocToken );
m_strShortNameLocToken = pKVQuestDef->GetString( "loc_shortname" ); if ( !m_strShortNameLocToken.IsEmpty() ) HelperValidateLocalizationStringToken( m_strShortNameLocToken );
m_strDescriptionLocToken = pKVQuestDef->GetString( "loc_description" ); if ( !m_strDescriptionLocToken.IsEmpty() ) HelperValidateLocalizationStringToken( m_strDescriptionLocToken );
m_strHudDescriptionLocToken = pKVQuestDef->GetString( "loc_huddescription" ); if ( !m_strHudDescriptionLocToken.IsEmpty() ) HelperValidateLocalizationStringToken( m_strHudDescriptionLocToken );
// Localizers have request the ability to explicitly write each quest's description because the
// programatic string construction in place is not flexible enough to accommodate various grammars.
//
// Description will defer to this string, if it exists. It should not be used in CSGO_English.
if ( g_pVGuiLocalize->Find( CFmtStr( "Override_Quest_Description_%s", pKVQuestDef->GetName( ) ) ) ) m_strDescriptionLocToken = CFmtStr( "Override_Quest_Description_%s", pKVQuestDef->GetName( ) );
m_strLocBonus = pKVQuestDef->GetString( "loc_bonus" ); if ( !m_strLocBonus.IsEmpty() ) HelperValidateLocalizationStringToken( m_strLocBonus );
m_strIcon = pKVQuestDef->GetString( "quest_icon" );
// Quests used to use explicitly define "string_tokens" in their schema definitions.
// Now the string tokens kv is populated by interpreting the expression
// but we may still want to add tokens manually in the future.
m_kvStringTokens = pKVQuestDef->FindKey( "string_tokens" );
if ( !m_kvStringTokens ) m_kvStringTokens = new KeyValues( "string_tokens" );
KeyValues * pkvExpressionTokens = new KeyValues( "ExpressionTokens" ); KeyValues::AutoDelete autodelete_pKVExpressionTokens( pkvExpressionTokens );
TokenizeQuestExpression( m_strExpr, pkvExpressionTokens );
Assert( pkvExpressionTokens->GetFirstSubKey() != NULL );
PopulateQuestStringTokens( *this, *pkvExpressionTokens, *m_kvStringTokens );
if ( !m_strBonusExpr.IsEmpty() ) { KeyValues * pKVBonusExpressionTokens = new KeyValues( "BonusExpressionTokens" ); KeyValues::AutoDelete autodelete_pKVBonusExpressionTokens( pKVBonusExpressionTokens );
TokenizeQuestExpression( m_strBonusExpr, pKVBonusExpressionTokens );
Assert( pKVBonusExpressionTokens->GetFirstSubKey() != NULL );
PopulateQuestStringTokens( *this, *pKVBonusExpressionTokens, *m_kvStringTokens, true ); }
#endif // ifndef GAME_DLL
// MAPGROUP
//
//
bool bMapGroupValid = false; if ( m_strMapGroup.IsEmpty() ) { bMapGroupValid = true; } // "": empty mapgroups are technically valid
/** Removed for partner depot **/
AssertMsg2( bMapGroupValid, "QUEST %d references a non-existant mapgroup: %s.\n", nID, m_strMapGroup.Get() );
#ifndef GAME_DLL // strings
KeyValues *pGameModestxt = new KeyValues( "GameModes.txt" ); KeyValues::AutoDelete autodelete( pGameModestxt );
if ( !pGameModestxt->LoadFromFile( g_pFullFileSystem, "GameModes.txt" ) ) { pGameModestxt = NULL; }
// MAP
//
//
// get map string from gamemodes.txt and insert it into m_kvStringTokens
//
//
if ( !m_strMap.IsEmpty( ) && StringIsEmpty( m_kvStringTokens->GetString( "map" ) ) ) { KeyValues *pMaps = pGameModestxt->FindKey( "maps" );
if ( pMaps ) { KeyValues *pMapKV = pMaps->FindKey( m_strMap ); Assert( pMapKV );
if ( pMapKV ) { m_kvStringTokens->SetString( "map", pMapKV->GetString( "nameID" ) ); m_kvStringTokens->SetString( "location", pMapKV->GetString( "nameID" ) ); } } }
// get mapgroup string from gamemodes.txt and insert it into m_kvStringTokens
//
//
if ( !m_strMapGroup.IsEmpty() && StringIsEmpty( m_kvStringTokens->GetString( "mapgroup" ) ) ) { KeyValues *pMapGroups = pGameModestxt->FindKey( "mapgroups" );
if ( pMapGroups ) { KeyValues *pMapGroup = pMapGroups->FindKey( m_strMapGroup ); Assert( pMapGroup );
if ( pMapGroup ) { m_kvStringTokens->SetString( "mapgroup", pMapGroup->GetString( "nameID" ) ); }
// if we didn't specify a map then use the mapgroup as the location
if ( !m_kvStringTokens->FindKey("location") ) { m_kvStringTokens->SetString( "location", pMapGroup->GetString( "nameID" ) ); } } }
//GAMEMODE
//
//
#ifdef DBGFLAG_ASSERT
const char * szType; bool bGameModeValid = g_pGameTypes->GetGameTypeFromMode( m_strGameMode, szType ); AssertMsg2( bGameModeValid, "QUEST %d references a non-existant gamemode: %s.\n", nID, m_strGameMode ); #endif
if ( StringIsEmpty( m_kvStringTokens->GetString( "gamemode" ) ) ) {
// get gamemode string from gamemodes.txt and insert it into m_kvStringTokens
//
//
KeyValues *pGameTypes = pGameModestxt->FindKey( "gameTypes" );
FOR_EACH_SUBKEY( pGameTypes, kvGameType ) { KeyValues *pGameModes = kvGameType->FindKey( "GameModes" ); if ( pGameModes ) { KeyValues *pGameMode = pGameModes->FindKey( m_strGameMode ); if ( pGameMode ) { m_kvStringTokens->SetString( "gamemode", pGameModes->FindKey( m_strGameMode )->GetString( "NameID" ) );
break; } } } }
// check all strings in m_kvStringTokens
FOR_EACH_VALUE( m_kvStringTokens, pKVStringToken ) { const char* token = pKVStringToken->GetString(); HelperValidateLocalizationStringToken( token ); }
FOR_EACH_TRUE_SUBKEY( m_kvStringTokens, pKVSubKey ) { FOR_EACH_VALUE( pKVSubKey, pKVStringToken ) { const char* token = pKVStringToken->GetString( ); HelperValidateLocalizationStringToken( token ); } } #endif // not GAME_DLL
return SCHEMA_INIT_SUCCESS(); }
#ifdef CLIENT_DLL
///////////////////////////////////////////////////////////////////////////////////////////
//
// read the expression ( i.e. " %act_kill_human% && %cond_gun_borrowed% && %weapon_smg% )
// and insert appropriate string tokens into the string token keyvalues structure
//
////////////////////////////////////////////////////////////////////////////////////////////
void CEconQuestDefinition::PopulateQuestStringTokens( CEconQuestDefinition &questDef, KeyValues &kvExpressionTokens, KeyValues &kvStringTokens, bool bBonus ) { // 1. Validate that every token ( %TOKEN% ) is accounted for.
// 2. Populate pkvStringTokens with tokens derived from expression keywords e.g. %weapon_ak47%
KeyValues * pkvExpressionTokens = &kvExpressionTokens;
int nItemCount = 0;
FOR_EACH_SUBKEY( pkvExpressionTokens, kvSubKey ) { bool bFound = false;
if ( V_stristr( kvSubKey->GetName(), "act_" ) || V_stristr( kvSubKey->GetName(), "cond_" ) ) { // validate that action or condition is recognized.
for ( int i = 0; i < k_EQuestVar_Last; i++ ) { if ( FStrEq( g_arrQuestVars[ i ], kvSubKey->GetName() ) ) { if ( g_pVGuiLocalize->Find( CFmtStr( "#quest_action_singular_%s", kvSubKey->GetName() ) ) ) { if ( !kvStringTokens.FindKey( "action" ) ) { kvStringTokens.SetString( "action", CFmtStr( "#quest_action_singular_%s", kvSubKey->GetName() ) ); }
if ( !kvStringTokens.FindKey( "actions" ) ) { kvStringTokens.SetString( "actions", CFmtStr( "#quest_action_plural_%s", kvSubKey->GetName() ) ); } } /** Removed for partner depot **/
// note that we have at least one generic weapon if we use any item condition.
if ( V_stristr( kvSubKey->GetName( ), "cond_item" ) ) { if ( nItemCount == 0 ) nItemCount = 1; }
// debug kvStringTokens.SaveToFile( g_pFullFileSystem, "~expressiontokens.txt" );
// debug pkvExpressionTokens->SaveToFile( g_pFullFileSystem, "~expressiontokens.txt" );
bFound = true; break; } } } else if ( V_stristr( kvSubKey->GetName(), "weapon_" ) ) { // find the items subkey or create one if it doesnt exist
KeyValues* pkvItems = kvStringTokens.FindKey( "items" ); if ( !pkvItems ) { pkvItems = new KeyValues( "items" ); kvStringTokens.AddSubKey( pkvItems ); }
CEconItemDefinition * pWeaponItemDef = GetItemSchema( )->GetItemDefinitionByName( kvSubKey->GetName( ) );
if ( pWeaponItemDef ) { // LEGACY PRE-2016
if ( !kvStringTokens.FindKey( "weapon" ) ) { kvStringTokens.SetString( "weapon", pWeaponItemDef->GetItemBaseName() ); } // LEGACY PRE-2016
// insert the weapon into the 'items' true subkey
for ( int i = 1; i < 20; i++ ) { const char * szItemKeyName = CFmtStr( "item%d", i ); if ( !pkvItems->FindKey( szItemKeyName ) ) { pkvItems->SetString( szItemKeyName, pWeaponItemDef->GetItemBaseName( ) );
nItemCount++; break; } }
bFound = true;
// set the quest icon to the weapon if an icon was not explicitly set.
if ( questDef.m_strIcon.IsEmpty( ) && !bBonus ) { questDef.m_strIcon = kvSubKey->GetName() + WEAPON_CLASSNAME_PREFIX_LENGTH; } } else { // look for a weapon category/type
for ( int i = 0; i < LOADOUT_POSITION_COUNT; i++ ) { if ( V_stristr( kvSubKey->GetName(), CFmtStr( "weapon_%s", g_szLoadoutStrings[ i ] ) ) ) { // LEGACY PRE-2016
if ( !kvStringTokens.FindKey( "weapon" ) ) { kvStringTokens.SetString( "weapon", g_szLoadoutStringsForDisplay[ i ] ); } // LEGACY PRE-2016
// insert the weapon into the 'items' true subkey
for ( int j = 1; j < 20; j++ ) { const char * szItemKeyName = CFmtStr( "item%d", j ); if ( !pkvItems->FindKey( szItemKeyName ) ) { const char * szLoadoutStringNoHashMark = g_szLoadoutStringsForDisplay[ i ] + 1; pkvItems->SetString( szItemKeyName, CFmtStr( "#quest_%s", szLoadoutStringNoHashMark ) );
nItemCount++; break; } }
bFound = true; break; } } } } else if ( V_stristr( kvSubKey->GetName(), "set_" ) ) { for ( int i = 0; i < GetItemSchema()->GetItemSetCount(); i++ ) { const CEconItemSetDefinition *pItemSetDef = GetItemSchema()->GetItemSetByIndex( i );
if ( pItemSetDef && FStrEq( kvSubKey->GetName(), pItemSetDef->GetName() ) ) { if ( !kvStringTokens.FindKey( "set" ) ) { kvStringTokens.SetString( "set", CFmtStr( "#CSGO_%s", pItemSetDef->GetName() ) ); }
bFound = true; break; } } } else if ( V_stristr( kvSubKey->GetName(), "map_" ) ) {
/** Removed for partner depot **/
}
// debug save
// kvStringTokens.SaveToFile( g_pFullFileSystem, "~expressiontokens.txt" );
AssertMsg2( bFound, "QUEST %u refs a non-existant var: %s\n", questDef.GetID(), kvSubKey->GetName() ); }
// defaults
if ( !kvStringTokens.FindKey( "commandverb" ) ) { kvStringTokens.SetString( "commandverb", "#quest_commandverb_default" ); }
if ( !kvStringTokens.FindKey( "target" ) ) { kvStringTokens.SetString( "target", "#emptystring" ); }
if ( !kvStringTokens.FindKey( "item_quality" ) ) { kvStringTokens.SetString( "item_quality", "#emptystring" ); }
// no items were specified but due to specified item conditions we know we need one.
if ( !kvStringTokens.FindKey( "items/item1" ) && ( nItemCount > 0 ) ) { kvStringTokens.SetString( "items/item1", "#quest_item_default" ); }
// no description was specified so use one of the default ones.
if ( questDef.m_strDescriptionLocToken.IsEmpty( ) && !bBonus ) { questDef.m_strDescriptionLocToken = CFmtStr( "quest_default_%d_items_desc", nItemCount ); }
// no quest tracker description was specified, so use one of the default ones.
if ( questDef.m_strHudDescriptionLocToken.IsEmpty( ) && !bBonus ) { questDef.m_strHudDescriptionLocToken = CFmtStr( "quest_default_hud_%d_items_desc", nItemCount ); } // kvStringTokens.SaveToFile( g_pFullFileSystem, "~stringtokens.txt" ); // debug only
}
#endif
// NOTE: This does not detect syntax or unrecognized symbols. TODO: Still need to figure out how to detect those.
bool CEconQuestDefinition::IsQuestExpressionValid( const char * pszQuestExpr ) { if ( !pszQuestExpr || !pszQuestExpr[0] ) return false;
CExpressionCalculator expr = CExpressionCalculator( pszQuestExpr );
ZeroOutQuestExpressionVariables( expr );
// This seemed like a good idea but it doesn't work.
//
// for ( int i = 0; i < expr.VariableCount(); i++ )
// {
// if ( !StringIsEmpty( expr.GetVariableName( i ) ) && expr.GetVariableValue( i ) != 1.0 )
// {
// AssertMsg1( 0, "unknown variable %s in quest expression", expr.GetVariableName( i ) );
// return false;
// }
// }
float flResult; bool bSuccess = expr.Evaluate( flResult );
return ( bSuccess && IsFinite(flResult) ); }
void CEconQuestDefinition::SetQuestExpressionVariable( CExpressionCalculator &expQuest, EQuestVar_t questVar, float flValue ) { expQuest.SetVariable( CFmtStr( "%%%s%%", g_arrQuestVars[ questVar ] ), flValue ); }
void CEconQuestDefinition::ZeroOutQuestExpressionVariables( CExpressionCalculator &expr ) { // it's not possible to iterate through expression variables but this would be ideal. VariableCount() returns 1 :/
// expQuest.BuildVariableListFromExpression();
//
// for ( int i = 0; i < expQuest.VariableCount(); i++ )
// {
// expQuest.SetVariable( i, 0 );
// }
// ACTIONS and CONDITIONS
/** Removed for partner depot **/
// WEAPON TYPES
for ( int i = 0; i < LOADOUT_POSITION_COUNT; i++ ) { expr.SetVariable( CFmtStr( "%%weapon_%s%%", g_szLoadoutStrings[ i ] ), 0 ); }
// SETS
for ( int i = 0; i < GetItemSchema()->GetItemSetCount(); i++ ) { const CEconItemSetDefinition *pItemSetDef = GetItemSchema()->GetItemSetByIndex( i );
expr.SetVariable( CFmtStr( "%%%s%%", pItemSetDef->GetName() ), 0 ); }
// WEAPONS
static CUtlVector< const CEconItemDefinition * > s_vecWeaponItemDefs;
// cache these items so we don't do string compares every time we initialize an expression
if ( s_vecWeaponItemDefs.Count() == 0 ) { FOR_EACH_MAP_FAST( GetItemSchema()->GetItemDefinitionMap(), i ) { const CEconItemDefinition * pItemDef = GetItemSchema()->GetItemDefinitionByMapIndex( i );
if ( V_stristr( pItemDef->GetDefinitionName(), "weapon_" ) ) { s_vecWeaponItemDefs.AddToTail( pItemDef ); } } }
FOR_EACH_VEC( s_vecWeaponItemDefs, i ) { expr.SetVariable( CFmtStr( "%%%s%%", s_vecWeaponItemDefs[ i ]->GetDefinitionName() ), 0 ); }
// MAPS
/** Removed for partner depot **/
}
bool CEconCampaignDefinition::BInitFromKV( KeyValues *pKVCampaignDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /*= NULL */ ) { m_nID = Q_atoi( pKVCampaignDef->GetName() ); SCHEMA_INIT_CHECK( ( m_nID > 0 ), CFmtStr( "Campaign definition %d: name must be a positive integer", GetID() ) );
m_strNameLocToken = pKVCampaignDef->GetString( "loc_name" ); HelperValidateLocalizationStringToken( m_strNameLocToken );
m_strLocDescription = pKVCampaignDef->GetString( "loc_description" ); HelperValidateLocalizationStringToken( m_strLocDescription );
m_nSeasonNumber = pKVCampaignDef->GetInt( "season_number" );
SCHEMA_INIT_CHECK( m_nSeasonNumber > 0, CFmtStr( "Campaign %d must specifiy a season number", GetID() ) );
FOR_EACH_TRUE_SUBKEY( pKVCampaignDef, pKVCampaignNode ) { CEconCampaignNodeDefinition *pNewCampaignNodeDef = new CEconCampaignNodeDefinition;
int CampaignNodeIndex = Q_atoi( pKVCampaignNode->GetName() );
uint32 index = m_mapCampaignNodes.Find( CampaignNodeIndex ); if ( !m_mapCampaignNodes.IsValidIndex( index ) ) { m_mapCampaignNodes.Insert( CampaignNodeIndex, pNewCampaignNodeDef ); SCHEMA_INIT_SUBSTEP( pNewCampaignNodeDef->BInitFromKV( GetID(), pKVCampaignNode, pschema ) ); } else { SCHEMA_INIT_CHECK( false, CFmtStr( "Campaign definition %d: campaign node index %d is not unique", GetID(), CampaignNodeIndex ) ); } }
// go back and verify that all nodes point to valid nodes
FOR_EACH_MAP_FAST( m_mapCampaignNodes, i ) { const CUtlVector< uint32 >& pNextNodes = m_mapCampaignNodes.Element( i )->GetNextNodes();
FOR_EACH_VEC( pNextNodes, j ) { int nextnode = pNextNodes[ j ];
int index = m_mapCampaignNodes.Find( nextnode );
SCHEMA_INIT_CHECK( m_mapCampaignNodes.IsValidIndex( index ), CFmtStr( "Campaign definition %d: campaign node index %d leads to an invalid campaign node %d", GetID(), m_mapCampaignNodes.Element( i )->GetID(), nextnode ) ); }
}
// build list of start nodes ( nodes that have no predecessors )
m_mapStartNodes.Purge();
// collect all nodes
FOR_EACH_MAP_FAST( m_mapCampaignNodes, i ) { m_mapStartNodes.Insert( m_mapCampaignNodes.Key( i ), m_mapCampaignNodes.Element( i ) ); }
// subtract nodes referenced as successors
FOR_EACH_MAP_FAST( m_mapCampaignNodes, i ) { const CUtlVector< uint32 >& pCampaignNodes = m_mapCampaignNodes.Element( i )->GetNextNodes();
FOR_EACH_VEC( pCampaignNodes, j ) { int nextnode = pCampaignNodes.Element( j );
m_mapStartNodes.Remove( nextnode ); } }
return SCHEMA_INIT_SUCCESS();
}
void CEconCampaignDefinition::GetAccessibleCampaignNodes( const uint32 unCampaignCompletionBitfield, CUtlVector< CEconCampaignNodeDefinition* > &vecAccessibleNodes ) { vecAccessibleNodes.Purge();
// If no campaign quests have been done yet then the only possible quests are the starting quests.
if ( unCampaignCompletionBitfield == 0 ) { FOR_EACH_MAP_FAST( GetStartNodes(), i ) { vecAccessibleNodes.AddToTail( GetStartNodes().Element( i ) ); } } else { // otherwise recursively look for quests that are successors of completed quests.
FOR_EACH_MAP_FAST( GetStartNodes(), i ) { uint32 nCampaignNodeIndex = GetStartNodes().Key( i );
// is this start quest already complete?
if ( ( 1 << ( nCampaignNodeIndex - 1 ) ) & unCampaignCompletionBitfield ) { // yes. recurse.
Helper_RecursiveGetAccessibleCampaignNodes( unCampaignCompletionBitfield, GetStartNodes().Element( i ), vecAccessibleNodes ); } else { // no. add it to the list and return;
vecAccessibleNodes.AddToTail( GetStartNodes().Element( i ) ); } } } }
void CEconCampaignDefinition::Helper_RecursiveGetAccessibleCampaignNodes( const uint32 unCampaignCompletionBitfield, const CEconCampaignNodeDefinition* pNode, CUtlVector< CEconCampaignNodeDefinition* > &vecAccessibleNodes ) { // recursively look for nodes that don't represent completed quests. Do not recurse incomplete quests.
FOR_EACH_VEC( pNode->GetNextNodes(), i ) { uint32 unNextNodeIndex = pNode->GetNextNodes().Element( i ); int index = GetCampaignNodes().Find( unNextNodeIndex ); if ( GetCampaignNodes().IsValidIndex( index ) ) { CEconCampaignDefinition::CEconCampaignNodeDefinition* pNextNode = GetCampaignNodes().Element( index );
// is this successor quest already complete?
if ( ( 1 << ( unNextNodeIndex - 1 ) ) & unCampaignCompletionBitfield ) { // yes. recurse.
Helper_RecursiveGetAccessibleCampaignNodes( unCampaignCompletionBitfield, pNextNode, vecAccessibleNodes ); } else { // no. add it to the list and return;
vecAccessibleNodes.AddToTail( pNextNode ); } } }
}
bool ResolveQuestIdToCampaignAndIndex( uint16 unQuestID, uint32 &unCampaignID, uint32 &unCamapaignNodeID ) { static bool s_bQuestMappingInitialized = false; static CUtlMap< uint16, uint64, uint16, CDefLess< uint16 > > s_mapping; if ( !s_bQuestMappingInitialized ) { s_bQuestMappingInitialized = true; for ( uint32 unPossibleCampaignID = 1; unPossibleCampaignID <= g_nNumCampaigns; ++unPossibleCampaignID ) { CEconCampaignDefinition const *pCampaignDef = GetItemSchema()->GetCampaignDefinition( unPossibleCampaignID ); if ( !pCampaignDef ) continue;
FOR_EACH_MAP_FAST( pCampaignDef->GetCampaignNodes(), iCN ) { CEconCampaignDefinition::CEconCampaignNodeDefinition const &node = *pCampaignDef->GetCampaignNodes().Element( iCN ); uint16 unMappingKey = node.GetQuestIndex(); if ( unMappingKey ) { uint64 unMappingValue = ( uint64( unPossibleCampaignID ) << 32 ) | uint64( node.GetID() ); Assert( s_mapping.Find( unMappingKey ) == s_mapping.InvalidIndex() ); s_mapping.InsertOrReplace( unMappingKey, unMappingValue ); } } } }
uint16 idxMapping = s_mapping.Find( unQuestID ); if ( idxMapping == s_mapping.InvalidIndex() ) return false;
unCampaignID = uint32( s_mapping.Element( idxMapping ) >> 32 ); unCamapaignNodeID = uint32( s_mapping.Element( idxMapping ) ); return true; }
bool CEconCampaignDefinition::CEconCampaignNodeDefinition::BInitFromKV( int nCampaignIndex, KeyValues *pKVCampaignNodeDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /*= NULL */ ) { m_nID = Q_atoi( pKVCampaignNodeDef->GetName() ); SCHEMA_INIT_CHECK( ( m_nID > 0 ), CFmtStr( "Campaign Node definition %d: name must be a positive integer", GetID() ) );
m_CampaignID = nCampaignIndex;
m_nQuestIndex = Q_atoi( pKVCampaignNodeDef->GetString( "quest_index" ) ); if ( m_nQuestIndex ) // validate only if specified, story-only nodes don't have quest indices
{ SCHEMA_INIT_CHECK( ( GetItemSchema()->GetQuestDefinition( m_nQuestIndex ) != NULL ), CFmtStr( "Campaign definition %d, Node definition %d: Quest Index %d is not a valid quest index", nCampaignIndex, m_nID, m_nQuestIndex ) ); } m_vecNextNodes.Purge();
FOR_EACH_SUBKEY( pKVCampaignNodeDef, pKVCampaignNodeKey ) { if ( !V_strcmp( pKVCampaignNodeKey->GetName(), "->" ) ) { m_vecNextNodes.AddToTail( Q_atoi( pKVCampaignNodeKey->GetString() ) ); } }
#ifdef CLIENT_DLL
FOR_EACH_TRUE_SUBKEY( pKVCampaignNodeDef, pKVCampaignNodeKey ) { if ( FStrEq( pKVCampaignNodeKey->GetName(), "story_block" ) ) { CEconCampaignNodeStoryBlockDefinition *pNewCampaignNodeStoryBlockDef = new CEconCampaignNodeStoryBlockDefinition;
m_vecStoryBlocks.AddToTail( pNewCampaignNodeStoryBlockDef ); SCHEMA_INIT_SUBSTEP( pNewCampaignNodeStoryBlockDef->BInitFromKV( nCampaignIndex, m_nID, pKVCampaignNodeKey, pschema ) ); } } #endif
return SCHEMA_INIT_SUCCESS();
}
#ifdef CLIENT_DLL
// score every story block and return the highest scoring one
CEconCampaignDefinition::CEconCampaignNodeDefinition::CEconCampaignNodeStoryBlockDefinition * CEconCampaignDefinition::CEconCampaignNodeDefinition::GetBestScoringStoryBlock( CEconItemView *pCampaignCoin ) const { CEconCampaignDefinition::CEconCampaignNodeDefinition::CEconCampaignNodeStoryBlockDefinition * pBestStoryBlock = NULL; float flBestStoryBlockScore = 0;
FOR_EACH_VEC( GetStoryBlocks(), iSB ) { float flCurStoryBlockScore = GetStoryBlocks()[ iSB ]->EvaluateStoryBlockExpression( pCampaignCoin );
// only consider story block expressions that have a positive score
if ( flCurStoryBlockScore > 0 ) { if ( !pBestStoryBlock ) { pBestStoryBlock = GetStoryBlocks()[ iSB ]; flBestStoryBlockScore = flCurStoryBlockScore; } else { if ( flCurStoryBlockScore > flBestStoryBlockScore ) { pBestStoryBlock = GetStoryBlocks()[ iSB ]; flBestStoryBlockScore = flCurStoryBlockScore; } } } }
return pBestStoryBlock; }
bool CEconCampaignDefinition::CEconCampaignNodeDefinition::CEconCampaignNodeStoryBlockDefinition::BInitFromKV( int nCampaignIndex, int nNodeID, KeyValues * pKVCampaignNodeStoryBlockDef, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) {
m_strContentFile = pKVCampaignNodeStoryBlockDef->GetString( "content_file" ); m_strCharacterName = pKVCampaignNodeStoryBlockDef->GetString( "character_name" ); m_strDescription = pKVCampaignNodeStoryBlockDef->GetString( "description" ); if ( !m_strDescription.IsEmpty() ) HelperValidateLocalizationStringToken( m_strDescription );
m_strExpr = pKVCampaignNodeStoryBlockDef->GetString( "expression" );
return SCHEMA_INIT_SUCCESS(); }
// Take the expression of an CExpressionCalculator, such as " %weapon_ak47% && %kill% " and extract the % delimited keywords.
//
void CEconQuestDefinition::TokenizeQuestExpression( const char * szExpression, KeyValues * pKVExpressionTokens ) { if ( !szExpression || !szExpression[0] ) return;
if ( !pKVExpressionTokens ) return;
const char * pCur = szExpression;
char szKeyword[ 256 ] = { '\0' }; char *pCurCopy = szKeyword;
bool bReadingKeyword = false;
while ( *pCur != '\0' ) { if ( *pCur == '%' && !bReadingKeyword ) { bReadingKeyword = true;
// reset destination buffer;
V_memset( szKeyword, '\0', sizeof( szKeyword ) ); pCurCopy = szKeyword;
// step past '%'
pCur++; } else if ( *pCur == '%' && bReadingKeyword ) { // end of the keyword
bReadingKeyword = false;
// terminate the string with a null char and then look it up
pCurCopy++; *pCurCopy = '\0';
pKVExpressionTokens->SetBool( szKeyword, true );
// step past '%'
pCur++; }
if ( bReadingKeyword ) { // keep copying the keyword until we reach the terminating '%'
*pCurCopy = *pCur;
pCurCopy++; pCur++; } else { // keep walking until we find the start of a keyword: '%'
pCur++; } }
}
float CEconCampaignDefinition::CEconCampaignNodeDefinition::CEconCampaignNodeStoryBlockDefinition::EvaluateStoryBlockExpression( CEconItemView *pCampaignCoin ) const { // if there's no expression specified then return a minimally true value.
if ( m_strExpr.IsEmpty() ) return 0.99; // default without an expression is trumped by any block with an expression result of 1.0. This means that any true expression block will get picked
// over any block with no expression.
CExpressionCalculator expStoryBlock = CExpressionCalculator( GetStoryBlockExpression() );
KeyValues * pKVExpressionTokens = new KeyValues( "ExpressionTokens" ); KeyValues::AutoDelete autodelete_pKVExpressionTokens( pKVExpressionTokens );
CEconQuestDefinition::TokenizeQuestExpression( GetStoryBlockExpression(), pKVExpressionTokens );
// go through each referenced quest and set the variable %questid% to the value of its completion state ( 0 or 1 )
FOR_EACH_SUBKEY( pKVExpressionTokens, kvSubKey ) { uint16 unQuestID = V_atoi( kvSubKey->GetName() );
uint32 unCampaignID; uint32 unCampaignNodeID;
ResolveQuestIdToCampaignAndIndex( unQuestID, unCampaignID, unCampaignNodeID );
const CSchemaAttributeDefHandle pAttr_CampaignCompletionBitfield = GetCampaignAttributeDefHandle( unCampaignID, k_ECampaignAttribute_CompletionBitfield ); uint32 unCampaignCompletionBitfield; if ( !pCampaignCoin->FindAttribute( pAttr_CampaignCompletionBitfield, &unCampaignCompletionBitfield ) ) return 0;
uint32 unMask = ( 1 << ( unCampaignNodeID - 1 ) );
const char * szKeyWord = CFmtStr( "%%%s%%", kvSubKey->GetName() ); float flCompletionState = ( unCampaignCompletionBitfield & unMask ) ? 1.0 : 0.0; expStoryBlock.SetVariable( szKeyWord, flCompletionState ); }
expStoryBlock.BuildVariableListFromExpression();
float flReturn; expStoryBlock.Evaluate( flReturn );
return flReturn;
} #endif
bool item_list_entry_t::InitFromName( const char *pchName ) { if ( pchName[ 0 ] == '[' ) { // This item has an attached paint type that can affect the name and rarity!
pchName++;
char szPaintName[ 256 ]; int i; for( i = 0; i < ARRAYSIZE( szPaintName ) - 1 && pchName[ i ] != ']'; ++i ) { szPaintName[ i ] = pchName[ i ]; }
szPaintName[ i ] = '\0';
if ( pchName[ i ] != ']' ) return false;
pchName += i + 1;
const CPaintKit *pPaintKit = GetItemSchema()->GetPaintKitDefinitionByName( szPaintName ); if ( pPaintKit ) { m_nPaintKit = pPaintKit->nID; } else { const CStickerKit *pStickerKit = GetItemSchema()->GetStickerKitDefinitionByName( szPaintName ); if ( pStickerKit ) { m_nStickerKit = pStickerKit->nID; } else { const CEconMusicDefinition *pMusicKit = GetItemSchema()->GetMusicKitDefinitionByName( szPaintName ); if ( pMusicKit ) { m_nMusicKit = pMusicKit->GetID(); } else { DevWarning( "Kit \"[%s]\" specified, but doesn't exist!! You're probably missing an entry in items_paintkits.txt or items_stickerkits.txt or need to run with -use_local_item_data\n", szPaintName ); return false; } } } }
CEconItemDefinition *pDef = GetItemSchema()->GetItemDefinitionByName( pchName ); if ( pDef ) { m_nItemDef = pDef->GetDefinitionIndex(); }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CEconItemSetDefinition::CEconItemSetDefinition( void ) : m_pszName( NULL ) , m_pszLocalizedName( NULL ) , m_pszLocalizedDescription( NULL ) , m_pszUnlocalizedName( NULL ) , m_iBundleItemDef( INVALID_ITEM_DEF_INDEX ) , m_bIsCollection( false ) , m_bIsHiddenSet( false ) , m_nCraftReward( 0 ) { }
//-----------------------------------------------------------------------------
// Purpose: Copy constructor
//-----------------------------------------------------------------------------
CEconItemSetDefinition::CEconItemSetDefinition( const CEconItemSetDefinition &that ) { (*this) = that; }
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CEconItemSetDefinition &CEconItemSetDefinition::operator=( const CEconItemSetDefinition &other ) { m_pszName = other.m_pszName; m_pszLocalizedName = other.m_pszLocalizedName; m_pszUnlocalizedName = other.m_pszUnlocalizedName; m_pszLocalizedDescription = other.m_pszLocalizedDescription; m_pszUnlocalizedName = other.m_pszUnlocalizedName; m_ItemEntries = other.m_ItemEntries; m_iAttributes = other.m_iAttributes; m_iBundleItemDef = other.m_iBundleItemDef; m_bIsCollection = other.m_bIsCollection; m_bIsHiddenSet = other.m_bIsHiddenSet; m_nCraftReward = other.m_nCraftReward;
return *this; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CEconItemSetDefinition::BInitFromKV( KeyValues *pKVItemSet, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors ) { m_pszName = pKVItemSet->GetName();
m_iBundleItemDef = INVALID_ITEM_DEF_INDEX; const char *pszBundleName = pKVItemSet->GetString( "store_bundle" ); if ( pszBundleName && pszBundleName[0] ) { const CEconItemDefinition *pDef = pschema.GetItemDefinitionByName( pszBundleName ); if ( pDef ) { m_iBundleItemDef = pDef->GetDefinitionIndex(); }
SCHEMA_INIT_CHECK( pDef != NULL, CFmtStr( "Item Set %s: Bundle definition \"%s\" was not found", m_pszName, pszBundleName ) ); }
FOR_EACH_SUBKEY( pKVItemSet, pKVSetItem ) { const char *pszName = pKVSetItem->GetName();
if ( !Q_strcmp( pszName, "name" ) ) { SCHEMA_INIT_CHECK( m_pszLocalizedName == NULL, CFmtStr( "Item Set %s: Duplicate name specified", m_pszName ) );
m_pszLocalizedName = pKVSetItem->GetString(); } else if ( !Q_strcmp( pszName, "set_description" ) ) { m_pszLocalizedDescription = pKVSetItem->GetString(); } else if ( !Q_strcmp( pszName, "unlocalized_name" ) ) { m_pszUnlocalizedName = pKVSetItem->GetString(); } else if ( !Q_strcmp( pszName, "is_collection" ) ) { m_bIsCollection = pKVSetItem->GetBool(); } else if ( !Q_strcmp( pszName, "is_hidden_set" ) ) { m_bIsHiddenSet = pKVSetItem->GetBool(); } // else if ( !Q_strcmp( pszName, "craft_reward" ) )
// {
// const char *pchCraftReward = pKVSetItem->GetString();
// if ( pchCraftReward && pchCraftReward[ 0 ] != '\0' )
// {
// const CEconItemDefinition *pItemDef = pschema.GetItemDefinitionByName( pKVSetItem->GetString() );
//
// SCHEMA_INIT_CHECK(
// pItemDef && pItemDef->GetDefinitionIndex() > 0,
// CFmtStr( "Item Collection Craft Reward \"%s\" specifies invalid item def", pKVItemSet->GetName() ) );
//
// m_nCraftReward = pItemDef->GetDefinitionIndex();
// }
// }
else if ( !Q_strcmp( pszName, "items" ) ) { FOR_EACH_SUBKEY( pKVSetItem, pKVItem ) { pszName = pKVItem->GetName();
item_list_entry_t entry; bool bEntrySuccess = entry.InitFromName( pszName ); bEntrySuccess;
m_ItemEntries.AddToTail( entry ); } } else if ( !Q_strcmp( pszName, "attributes" ) ) { FOR_EACH_SUBKEY( pKVSetItem, pKVAttribute ) { pszName = pKVAttribute->GetName();
const CEconItemAttributeDefinition *pDef = pschema.GetAttributeDefinitionByName( pszName ); // SCHEMA_INIT_CHECK(
// pDef != NULL,
// CFmtStr( "Item set %s: Attribute definition \"%s\" was not found", m_pszName, pszName ) );
if ( pDef ) { int iIndex = m_iAttributes.AddToTail(); m_iAttributes[iIndex].m_iAttribDefIndex = pDef->GetDefinitionIndex(); if ( pDef->IsStoredAsInteger() ) { m_iAttributes[iIndex].m_valValue = pKVAttribute->GetInt( "value" ); } else { float flValue = pKVAttribute->GetFloat( "value" ); Q_memcpy( &m_iAttributes[iIndex].m_valValue, &flValue, sizeof( float ) ); } } } } }
// Sanity check.
SCHEMA_INIT_CHECK( !(m_bIsCollection && m_bIsHiddenSet), CFmtStr( "Item Set %s: Invalid to set a collection to be hidden", m_pszName ) );
SCHEMA_INIT_CHECK( m_ItemEntries.Count() > 0, CFmtStr( "Item Set %s: Set contains no items", m_pszName ) );
return SCHEMA_INIT_SUCCESS(); }
int CEconItemSetDefinition::GetItemRarity( int iIndex ) const { int nKitRarity = 1; const CStickerKit *pStickerKit = NULL; const CPaintKit *pPaintKit = NULL; const CEconMusicDefinition *pMusicKitDefinition = NULL;
item_list_entry_t const &entry = m_ItemEntries[iIndex];
if ( entry.m_nPaintKit ) { pPaintKit = GetItemSchema()->GetPaintKitDefinition( entry.m_nPaintKit ); if ( pPaintKit ) { nKitRarity = MAX( nKitRarity, pPaintKit->nRarity ); } } if ( entry.m_nStickerKit ) { pStickerKit = GetItemSchema()->GetStickerKitDefinition( entry.m_nStickerKit ); if ( pStickerKit ) { nKitRarity = MAX( nKitRarity, pStickerKit->nRarity ); } } if ( entry.m_nMusicKit ) { pMusicKitDefinition = GetItemSchema()->GetMusicDefinition( entry.m_nMusicKit ); if ( pMusicKitDefinition ) { nKitRarity = Max ( nKitRarity, 1/* pMusicKitDefinition->GetRarity() */); }
}
// Now combine the rarity
const CEconItemDefinition *pDef = GetItemSchema()->GetItemDefinition( entry.m_nItemDef ); return pDef ? EconRarity_CombinedItemAndPaintRarity( pDef->GetRarity(), nKitRarity ) : -1; }
int CEconItemSetDefinition::GetHighestItemRarityValue( void ) const { int nHighestRarityValue = -1; for ( int i = 0; i < GetItemCount(); ++i ) { int nRarity = GetItemRarity( i ); if ( nHighestRarityValue < nRarity ) { nHighestRarityValue = nRarity; } }
return nHighestRarityValue; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CEconLootListDefinition::CEconLootListDefinition( void ) { m_bServerList = false; }
//-----------------------------------------------------------------------------
// Purpose: Copy constructor
//-----------------------------------------------------------------------------
CEconLootListDefinition::CEconLootListDefinition( const CEconLootListDefinition &that ) { (*this) = that; }
//-----------------------------------------------------------------------------
// Dtor
//-----------------------------------------------------------------------------
CEconLootListDefinition::~CEconLootListDefinition( void ) { }
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CEconLootListDefinition &CEconLootListDefinition::operator=( const CEconLootListDefinition &other ) { m_pszName = other.m_pszName; m_ItemEntries = other.m_ItemEntries; m_AdditionalDrops = other.m_AdditionalDrops; m_bServerList = other.m_bServerList;
return *this; }
bool CEconLootListDefinition::AddRandomAtrributes( KeyValues *pRandomAttributesKV, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /*= NULL*/ ) { // We've found the random attribute block. Parse it.
SCHEMA_INIT_CHECK( NULL != pRandomAttributesKV->FindKey( "chance" ), CFmtStr( "Loot List %s: Missing required field \"chance\" in the \"random_attributes\" block.", m_pszName ) );
random_attrib_t *randomAttrib = new random_attrib_t;
randomAttrib->m_flChanceOfRandomAttribute = pRandomAttributesKV->GetFloat( "chance" ); randomAttrib->m_bPickAllAttributes = ( pRandomAttributesKV->GetFloat( "pick_all_attributes" ) != 0 ); randomAttrib->m_flTotalAttributeWeight = 0;
FOR_EACH_TRUE_SUBKEY( pRandomAttributesKV, pKVAttribute ) { const char *pszName = pKVAttribute->GetName();
if ( !Q_strcmp( pszName, "chance" ) ) continue;
const CEconItemAttributeDefinition *pDef = pschema.GetAttributeDefinitionByName( pszName ); SCHEMA_INIT_CHECK( pDef != NULL, CFmtStr( "Loot list %s: Attribute definition \"%s\" was not found", m_pszName, pszName ) );
if ( pDef ) { lootlist_attrib_t lootListAttrib;
SCHEMA_INIT_SUBSTEP( lootListAttrib.BInitFromKV( m_pszName, pKVAttribute, pschema, pVecErrors ) );
randomAttrib->m_flTotalAttributeWeight += lootListAttrib.m_flWeight;
randomAttrib->m_RandomAttributes.AddToTail( lootListAttrib ); } }
m_RandomAttribs.AddToTail( randomAttrib );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CEconLootListDefinition::BInitFromKV( KeyValues *pKVLootList, KeyValues *pKVRandomAttributeTemplates, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors, bool bServerList ) { m_pszName = pKVLootList->GetName();
m_unHeroID = 0;
m_bServerList = bServerList;
FOR_EACH_SUBKEY( pKVLootList, pKVListItem ) { const char *pszName = pKVListItem->GetName();
if ( !Q_strcmp( pszName, "random_attributes" ) ) { AddRandomAtrributes( pKVListItem, pschema, pVecErrors );
continue; } else if ( !Q_strcmp( pszName, "attribute_templates" ) ) { if ( !pKVRandomAttributeTemplates ) { // Clients don't load the attribute template list
// Skip over attribute templates
continue; }
FOR_EACH_SUBKEY( pKVListItem, pKVAttributeTemplate ) { if ( pKVAttributeTemplate->GetDataType() == KeyValues::TYPE_NONE ) { // Support full template specified inplace
AddRandomAtrributes( pKVAttributeTemplate, pschema, pVecErrors ); } else { if ( pKVAttributeTemplate->GetInt() == 0 ) continue;
KeyValues *pKVRandomAttribute = pKVRandomAttributeTemplates->FindKey( pKVAttributeTemplate->GetName() ); SCHEMA_INIT_CHECK( pKVRandomAttribute, CFmtStr( "Loot List %s: Looking for attribute template \"%s\" that couldn't be found in \"random_attribute_templates\" block.\n", m_pszName, pKVAttributeTemplate->GetName() ) );
AddRandomAtrributes( pKVRandomAttribute, pschema, pVecErrors ); } }
continue; } else if ( !Q_strcmp( pszName, "public_list_contents" ) ) { m_bPublicListContents = pKVListItem->GetBool(); continue; } if ( !Q_strcmp( pszName, "additional_drop" ) ) { float fChance = pKVListItem->GetFloat( "chance", 0.0f ); bool bPremiumOnly = pKVListItem->GetBool( "premium_only", false ); const char *pszLootList = pKVListItem->GetString( "loot_list", "" );
SCHEMA_INIT_CHECK( fChance > 0.0f && fChance <= 1.0f, CFmtStr( "Loot list %s: Invalid \"additional_drop\" chance %.2f\n", m_pszName, fChance ) );
SCHEMA_INIT_CHECK( pszLootList && pszLootList[0], CFmtStr( "Loot list %s: Missing \"additional_drop\" loot list name\n", m_pszName ) );
if ( pszLootList ) { const CEconLootListDefinition *pLootListDef = pschema.GetLootListByName( pszLootList ); SCHEMA_INIT_CHECK( pLootListDef, CFmtStr( "Loot list %s: Invalid \"additional_drop\" loot list \"%s\"\n", m_pszName, pszLootList ) );
if ( pLootListDef ) { loot_list_additional_drop_t additionalDrop = { fChance, bPremiumOnly, pszLootList }; m_AdditionalDrops.AddToTail( additionalDrop ); } } continue; }
if ( !Q_strcmp( pszName, "hero" ) ) { const char* pszHeroName = pKVListItem->GetString( "name" ); m_unHeroID = GEconItemSchema().GetHeroID( pszHeroName ); continue; }
item_list_entry_t entry;
// First, see if we've got a loot list name, for embedded loot lists
int iIdx = 0;
if ( V_strstr( pszName, "unusual" ) != NULL ) { entry.m_bIsUnusualList = true; }
if ( pschema.GetLootListByName( pszName, &iIdx ) ) { entry.m_nItemDef = iIdx; entry.m_bIsNestedList = true; } else { bool bEntrySuccess = entry.InitFromName( pszName ); bEntrySuccess; }
// Make sure we never put non-enabled items into loot lists
if ( !entry.m_bIsNestedList && entry.m_nItemDef > 0 ) { const CEconItemDefinition *pItemDef = pschema.GetItemDefinition( entry.m_nItemDef ); SCHEMA_INIT_CHECK( pItemDef, CFmtStr( "Loot list %s: Item definition index \"%s\" (%d) was not found\n", m_pszName, pszName, entry.m_nItemDef ) ); }
m_ItemEntries.AddToTail( entry ); float fItemWeight = pKVListItem->GetFloat(); SCHEMA_INIT_CHECK( fItemWeight > 0.0f, CFmtStr( "Loot list %s: Item definition index \"%s\" (%d) has invalid weight %.2f\n", m_pszName, pszName, entry.m_nItemDef, fItemWeight ) );
m_flWeights.AddToTail( fItemWeight ); m_flTotalWeight += fItemWeight; }
return SCHEMA_INIT_SUCCESS(); }
bool CEconLootListDefinition::HasUnusualLoot() const { FOR_EACH_VEC(GetLootListContents(), i) { const item_list_entry_t& entry = GetLootListContents()[i];
if (entry.m_bIsUnusualList) return true;
if (entry.m_bIsNestedList) { const CEconLootListDefinition *pNestedLootList = GetItemSchema()->GetLootListByIndex(entry.m_nItemDef); if (pNestedLootList) { if (pNestedLootList->HasUnusualLoot()) return true; } } }
return false; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CEconLootListDefinition::GetAdditionalDrop( int iIndex, CUtlString& strLootList, float& flChance ) const { if ( !m_AdditionalDrops.IsValidIndex( iIndex ) ) return false;
strLootList = m_AdditionalDrops[iIndex].m_pszLootListDefName; flChance = m_AdditionalDrops[iIndex].m_fChance; return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CEconLootListDefinition::GetRandomAttributeGroup( int iIndex, float& flChance, float& flTotalWeight ) const { if ( !m_RandomAttribs.IsValidIndex( iIndex ) ) return false;
flChance = m_RandomAttribs[iIndex]->m_flChanceOfRandomAttribute; flTotalWeight = m_RandomAttribs[iIndex]->m_flTotalAttributeWeight;
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int CEconLootListDefinition::GetRandomAttributeCount( int iGroup ) const { if ( !m_RandomAttribs.IsValidIndex( iGroup ) ) return false;
return m_RandomAttribs[iGroup]->m_RandomAttributes.Count(); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CEconLootListDefinition::GetRandomAttribute( int iGroup, int iIndex, float& flWeight, int& iValue, int& iDefIndex ) const { Assert( !"Tell whoever is working on the item editor that loot list random attributes don't support typed attributes!" );
if ( !m_RandomAttribs.IsValidIndex( iGroup ) ) return false;
if ( !m_RandomAttribs[iGroup]->m_RandomAttributes.IsValidIndex( iIndex ) ) return false;
flWeight = m_RandomAttribs[iGroup]->m_RandomAttributes[iIndex].m_flWeight; iValue = (int) m_RandomAttribs[iGroup]->m_RandomAttributes[iIndex].m_staticAttrib.m_value.asFloat; iDefIndex = m_RandomAttribs[iGroup]->m_RandomAttributes[iIndex].m_staticAttrib.iDefIndex;
return true; }
//-----------------------------------------------------------------------------
// Outputs a keyvalues schema representation of this loot list.
//-----------------------------------------------------------------------------
KeyValues* CEconLootListDefinition::GenerateKeyValues() const { KeyValues* pLootListKV = new KeyValues( m_pszName );
// Write out our items and weights.
FOR_EACH_VEC( m_ItemEntries, i ) { const CEconItemDefinition* pItemDef = GetItemSchema()->GetItemDefinition( m_ItemEntries[i].m_nItemDef ); if ( !pItemDef ) continue; pLootListKV->SetFloat( pItemDef->GetRawDefinition()->GetString( "name" ), m_flWeights[i] ); }
// Write out additional drops.
// Write out random attributes.
return pLootListKV; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CEconLootListDefinition::PurgeItems( void ) { m_ItemEntries.Purge(); m_flWeights.Purge(); m_flTotalWeight = 0; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconLootListDefinition::lootlist_attrib_t::BInitFromKV( const char *pszContext, KeyValues *pKVKey, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors ) { SCHEMA_INIT_SUBSTEP( m_staticAttrib.BInitFromKV_MultiLine( pszContext, pKVKey, pVecErrors ) );
SCHEMA_INIT_CHECK( pKVKey->FindKey( "weight" ), CFmtStr( "Loot definition %s: Attribute \"%s\" missing required 'weight' field", pszContext, pKVKey->GetName() ) );
SCHEMA_INIT_CHECK( ( !pKVKey->FindKey( "range_min" ) && !pKVKey->FindKey( "range_max" ) ) || ( !pKVKey->FindKey( "values" ) ), CFmtStr( "Loot definition %s: Attribute \"%s\" specifies both value ranges and explicit values but should only use one method or the other", pszContext, pKVKey->GetName() ) );
m_flWeight = pKVKey->GetFloat( "weight" ); m_flRangeMin = pKVKey->GetFloat( "range_min" ); m_flRangeMax = pKVKey->GetFloat( "range_max" );
const char* pszValues = pKVKey->GetString( "values" );
m_vecValues.Purge();
if ( pszValues && pszValues[ 0 ] ) { SCHEMA_INIT_CHECK( Helper_ExtractIntegersFromValuesString( pszValues, m_vecValues ), CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a malformed values range: %s.", pszContext, pKVKey->GetName(), pszValues ) ); }
// validate that quest id values are valid
// TODO: create a common class for indexed definition classes and have this code validate all of them
if ( !strcmp( pKVKey->GetName(), "quest id" ) ) { if ( m_flRangeMin != 0 || m_flRangeMax != 0 ) { for ( int i = m_flRangeMin; i <= m_flRangeMax; i++ ) { SCHEMA_INIT_CHECK( GetItemSchema()->GetQuestDefinition( i ), CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a quest id that does not exist: %d.\n", pszContext, pKVKey->GetName(), i ) ); } } else if ( m_vecValues.Count() != 0 ) { FOR_EACH_VEC( m_vecValues, i ) { SCHEMA_INIT_CHECK( GetItemSchema()->GetQuestDefinition( m_vecValues[ i ] ), CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a quest id that does not exist: %d.\n", pszContext, pKVKey->GetName(), m_vecValues[ i ] ) ); } } } else if ( !strcmp( pKVKey->GetName(), "quest reward lootlist" ) ) { const CEconItemSchema::RevolvingLootListDefinitionMap_t* pQuestRewardLL= &( GetItemSchema()->GetQuestRewardLootLists() );
if ( m_flRangeMin != 0 || m_flRangeMax != 0 ) { for ( int i = m_flRangeMin; i <= m_flRangeMax; i++ ) { int iLLIndex = pQuestRewardLL->Find( i );
SCHEMA_INIT_CHECK( pQuestRewardLL->IsValidIndex( iLLIndex ), CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a quest reward lootlist that does not exist: %d.\n", pszContext, pKVKey->GetName(), i ) ); } } else if ( m_vecValues.Count() != 0 ) { FOR_EACH_VEC( m_vecValues, i ) { int iLLIndex = pQuestRewardLL->Find( m_vecValues[ i ] );
SCHEMA_INIT_CHECK( pQuestRewardLL->IsValidIndex( iLLIndex ), CFmtStr( "Loot definition %s: Attribute \"%s\" specifies a quest reward lootlist that does not exist: %d.\n", pszContext, pKVKey->GetName(), m_vecValues[ i ] ) ); } }
}
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CEconCraftingRecipeDefinition::CEconCraftingRecipeDefinition( void ) { m_nDefIndex = 0; m_wszName[ 0 ] = L'\0'; m_wszDesc[ 0 ] = L'\0'; }
//-----------------------------------------------------------------------------
// Purpose: Initialize the attribute definition
// Input: pKVAttribute - The KeyValues representation of the attribute
// schema - The overall item schema for this attribute
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconCraftingRecipeDefinition::BInitFromKV( KeyValues *pKVRecipe, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { m_nDefIndex = Q_atoi( pKVRecipe->GetName() ); // Check for required fields
SCHEMA_INIT_CHECK( NULL != pKVRecipe->FindKey( "input_items" ), CFmtStr( "Recipe definition %d: Missing required field \"input_items\"", m_nDefIndex ) );
SCHEMA_INIT_CHECK( NULL != pKVRecipe->FindKey( "output_items" ), CFmtStr( "Recipe definition %d: Missing required field \"output_items\"", m_nDefIndex ) );
m_bDisabled = pKVRecipe->GetBool( "disabled" ); m_strName = pKVRecipe->GetString( "name" ); m_strN_A = pKVRecipe->GetString( "n_A" ); m_strDescInputs = pKVRecipe->GetString( "desc_inputs" ); m_strDescOutputs = pKVRecipe->GetString( "desc_outputs" ); m_strDI_A = pKVRecipe->GetString( "di_A" ); m_strDI_B = pKVRecipe->GetString( "di_B" ); m_strDI_C = pKVRecipe->GetString( "di_C" ); m_strDO_A = pKVRecipe->GetString( "do_A" ); m_strDO_B = pKVRecipe->GetString( "do_B" ); m_strDO_C = pKVRecipe->GetString( "do_C" );
m_bRequiresAllSameClass = pKVRecipe->GetBool( "all_same_class" ); m_bRequiresAllSameSlot = pKVRecipe->GetBool( "all_same_slot" ); m_iCacheClassUsageForOutputFromItem = pKVRecipe->GetInt( "add_class_usage_to_output", -1 ); m_iCacheSlotUsageForOutputFromItem = pKVRecipe->GetInt( "add_slot_usage_to_output", -1 ); m_iCacheSetForOutputFromItem = pKVRecipe->GetInt( "add_set_to_output", -1 ); m_bAlwaysKnown = pKVRecipe->GetBool( "always_known", true ); m_bPremiumAccountOnly = pKVRecipe->GetBool( "premium_only", false ); m_iCategory = (recipecategories_t)StringFieldToInt( pKVRecipe->GetString("category"), g_szRecipeCategoryStrings, ARRAYSIZE(g_szRecipeCategoryStrings) ); m_iFilter = pKVRecipe->GetInt( "filter", -1 );
// Read in all the input items
KeyValues *pKVInputItems = pKVRecipe->FindKey( "input_items" ); if ( NULL != pKVInputItems ) { FOR_EACH_TRUE_SUBKEY( pKVInputItems, pKVInputItem ) { int index = m_InputItemsCriteria.AddToTail(); SCHEMA_INIT_SUBSTEP( m_InputItemsCriteria[index].BInitFromKV( pKVInputItem, pschema ) );
// Recipes ignore the enabled flag when generating items
m_InputItemsCriteria[index].SetIgnoreEnabledFlag( true );
index = m_InputItemDupeCounts.AddToTail(); m_InputItemDupeCounts[index] = atoi( pKVInputItem->GetName() ); } }
// Read in all the output items
KeyValues *pKVOutputItems = pKVRecipe->FindKey( "output_items" ); if ( NULL != pKVOutputItems ) { FOR_EACH_TRUE_SUBKEY( pKVOutputItems, pKVOutputItem ) { int index = m_OutputItemsCriteria.AddToTail(); SCHEMA_INIT_SUBSTEP( m_OutputItemsCriteria[index].BInitFromKV( pKVOutputItem, pschema ) );
// Recipes ignore the enabled flag when generating items
m_OutputItemsCriteria[index].SetIgnoreEnabledFlag( true ); } }
GenerateLocStrings();
return SCHEMA_INIT_SUCCESS(); }
bool CEconCraftingRecipeDefinition::BInitFromSet( const IEconItemSetDefinition *pSet, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { m_bDisabled = false; m_strName = "#RT_T_A"; // "Trade In %s1"
m_strN_A = pSet->GetLocKey(); // "The Office Collection"
m_strDescInputs = "#RDI_AB"; // "Requires: %s1 %s2"
m_strDescOutputs = "RDO_AB"; // "Produces: %s1 %s2"
m_strDI_A = "1"; // "1"
m_strDI_B = pSet->GetLocKey(); // "The Office Collection"
m_strDI_C = NULL; m_strDO_A = "1"; // "1"
const CEconItemDefinition *pItemDef = pschema.GetItemDefinition( pSet->GetCraftReward() );
SCHEMA_INIT_CHECK( pItemDef && pItemDef->GetDefinitionIndex() > 0, CFmtStr( "Item Collection Craft Reward (%d) specifies invalid item def", pSet->GetCraftReward() ) );
m_strDO_B = pItemDef->GetItemBaseName(); m_strDO_C = NULL;
m_bRequiresAllSameClass = false; m_bRequiresAllSameSlot = false; m_iCacheClassUsageForOutputFromItem = -1; m_iCacheSlotUsageForOutputFromItem = -1; m_iCacheSetForOutputFromItem = -1; m_bAlwaysKnown = true; m_bPremiumAccountOnly = false; m_iCategory = (recipecategories_t)StringFieldToInt( "crafting", g_szRecipeCategoryStrings, ARRAYSIZE(g_szRecipeCategoryStrings) ); m_iFilter = -1;
for ( int i = 0; i < pSet->GetItemCount(); ++i ) { int index = m_InputItemsCriteria.AddToTail(); SCHEMA_INIT_SUBSTEP( m_InputItemsCriteria[index].BInitFromItemAndPaint( pSet->GetItemDef( i ), pSet->GetItemPaintKit( i ), pschema ) );
m_InputItemsCriteria[index].SetIgnoreEnabledFlag( true );
index = m_InputItemDupeCounts.AddToTail(); m_InputItemDupeCounts[index] = 1; }
int index = m_OutputItemsCriteria.AddToTail(); SCHEMA_INIT_SUBSTEP( m_OutputItemsCriteria[index].BInitFromItemAndPaint( pSet->GetCraftReward(), 0, pschema ) );
GenerateLocStrings();
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Serializes the criteria to and from messages
//-----------------------------------------------------------------------------
bool CEconCraftingRecipeDefinition::BSerializeToMsg( CSOItemRecipe & msg ) const { msg.set_def_index( m_nDefIndex ); msg.set_name( m_strName ); msg.set_n_a( m_strN_A ); msg.set_desc_inputs( m_strDescInputs ); msg.set_desc_outputs( m_strDescOutputs ); msg.set_di_a( m_strDI_A ); msg.set_di_b( m_strDI_B ); msg.set_di_c( m_strDI_C ); msg.set_do_a( m_strDO_A ); msg.set_do_b( m_strDO_B ); msg.set_do_c( m_strDO_C ); msg.set_requires_all_same_class( m_bRequiresAllSameClass ); msg.set_requires_all_same_slot( m_bRequiresAllSameSlot ); msg.set_class_usage_for_output( m_iCacheClassUsageForOutputFromItem ); msg.set_slot_usage_for_output( m_iCacheSlotUsageForOutputFromItem ); msg.set_set_for_output( m_iCacheSetForOutputFromItem );
FOR_EACH_VEC( m_InputItemsCriteria, i ) { CSOItemCriteria *pCrit = msg.add_input_items_criteria(); if ( !m_InputItemsCriteria[i].BSerializeToMsg( *pCrit ) ) return false; }
FOR_EACH_VEC( m_InputItemDupeCounts, i ) { msg.add_input_item_dupe_counts( m_InputItemDupeCounts[i] ); }
FOR_EACH_VEC( m_OutputItemsCriteria, i ) { CSOItemCriteria *pCrit = msg.add_output_items_criteria(); if ( !m_OutputItemsCriteria[i].BSerializeToMsg( *pCrit ) ) return false; }
return true; }
//-----------------------------------------------------------------------------
// Purpose: Serializes the criteria to and from messages
//-----------------------------------------------------------------------------
bool CEconCraftingRecipeDefinition::BDeserializeFromMsg( const CSOItemRecipe & msg ) { m_nDefIndex = msg.def_index(); m_strName = msg.name().c_str(); m_strN_A = msg.n_a().c_str(); m_strDescInputs = msg.desc_inputs().c_str(); m_strDescOutputs = msg.desc_outputs().c_str(); m_strDI_A = msg.di_a().c_str(); m_strDI_B = msg.di_b().c_str(); m_strDI_C = msg.di_c().c_str(); m_strDO_A = msg.do_a().c_str(); m_strDO_B = msg.do_b().c_str(); m_strDO_C = msg.do_c().c_str();
m_bRequiresAllSameClass = msg.requires_all_same_class(); m_bRequiresAllSameSlot = msg.requires_all_same_slot(); m_iCacheClassUsageForOutputFromItem = msg.class_usage_for_output(); m_iCacheSlotUsageForOutputFromItem = msg.slot_usage_for_output(); m_iCacheSetForOutputFromItem = msg.set_for_output();
// Read how many input items there are
uint32 unCount = msg.input_items_criteria_size(); m_InputItemsCriteria.SetSize( unCount ); for ( uint32 i = 0; i < unCount; i++ ) { if ( !m_InputItemsCriteria[i].BDeserializeFromMsg( msg.input_items_criteria( i ) ) ) return false; }
// Read how many input item dupe counts there are
unCount = msg.input_item_dupe_counts_size(); m_InputItemDupeCounts.SetSize( unCount ); for ( uint32 i = 0; i < unCount; i++ ) { m_InputItemDupeCounts[i] = msg.input_item_dupe_counts( i ); }
// Read how many output items there are
unCount = msg.output_items_criteria_size(); m_OutputItemsCriteria.SetSize( unCount ); for ( uint32 i = 0; i < unCount; i++ ) { if ( !m_OutputItemsCriteria[i].BDeserializeFromMsg( msg.output_items_criteria( i ) ) ) return false; }
GenerateLocStrings();
return true; }
//-----------------------------------------------------------------------------
// Purpose: Returns true if the vector contains a set of items that matches the inputs for this recipe
// Note it will fail if the vector contains extra items that aren't needed.
//
//-----------------------------------------------------------------------------
bool CEconCraftingRecipeDefinition::ItemListMatchesInputs( const CUtlVector< CEconItem* > &vecCraftingItems, bool bAllowPartialMatch /*= false*/ ) const { bool bResult = true;
CUtlVector< uint8 > arrDupesUsed; arrDupesUsed.SetCount( m_InputItemsCriteria.Count() );
uint8 *pDupesUsed = arrDupesUsed.Base(); memset( pDupesUsed, 0, m_InputItemsCriteria.Count() );
int nSet = -1;
if ( ( GetFilter() == CRAFT_FILTER_COLLECT || GetFilter() == CRAFT_FILTER_TRADEUP ) && vecCraftingItems.Count() > 0 ) { nSet = vecCraftingItems[ 0 ]->GetItemSetIndex();
if ( nSet < 0 ) { // This item must be in a set!
return false; } }
FOR_EACH_VEC( vecCraftingItems, nItem ) { CEconItem *pEconItem = vecCraftingItems[ nItem ];
#if 0 // Relaxing set restriction on crafting
if ( nSet >= 0 && pEconItem->GetItemSetIndex() != nSet ) { bResult = false; break; } #endif
// Any items at the top rarity of their set are illegal in crafting
if ( GetFilter() == CRAFT_FILTER_TRADEUP ) { const IEconItemSetDefinition *pSetDef = GetItemSchema()->GetItemSet( vecCraftingItems[ nItem ]->GetItemSetIndex() ); if ( !pSetDef ) { return false; }
bool bHasItemsAtNextRarityTier = false; for ( int i = 0; i < pSetDef->GetItemCount(); ++i ) { if ( pSetDef->GetItemRarity( i ) == pEconItem->GetRarity() + 1 ) { bHasItemsAtNextRarityTier = true; break; } }
if ( !bHasItemsAtNextRarityTier ) return false; }
bool bFoundCriteriaMatch = false;
FOR_EACH_VEC( m_InputItemsCriteria, nCriteria ) { const CItemSelectionCriteria *pCriteria = &( m_InputItemsCriteria[ nCriteria ] ); if ( !pCriteria ) continue;
// Skip if we've used this criteria to the limit
if ( pDupesUsed[ nCriteria ] >= m_InputItemDupeCounts[ nCriteria ] ) continue;
bFoundCriteriaMatch = pCriteria->BEvaluate( pEconItem, *GetItemSchema() ); if ( bFoundCriteriaMatch ) { pDupesUsed[ nCriteria ]++; break; } }
if ( !bFoundCriteriaMatch ) { // Did the item not fit any criteria!
bResult = false; break; } }
if ( !bAllowPartialMatch ) { // Make sure we've matched ALL the criteria
FOR_EACH_VEC( m_InputItemsCriteria, nCriteria ) { if ( pDupesUsed[ nCriteria ] < m_InputItemDupeCounts[ nCriteria ] ) { // Not all criteria dupes were matched
bResult = false; break; } } }
return bResult; }
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
int CEconCraftingRecipeDefinition::GetTotalInputItemsRequired( void ) const { int iCount = 0; FOR_EACH_VEC( m_InputItemsCriteria, i ) { if ( m_InputItemDupeCounts[i] ) { iCount += m_InputItemDupeCounts[i]; } else { iCount++; } } return iCount; }
#if defined( CLIENT_DLL )
wchar_t *LocalizeRecipeStringPiece( const char *pszString, wchar_t *pszConverted, int nConvertedSizeInBytes ) { if ( !pszString ) return L"";
if ( pszString[0] == '#' ) return g_pVGuiLocalize->Find( pszString );
g_pVGuiLocalize->ConvertANSIToUnicode( pszString, pszConverted, nConvertedSizeInBytes ); return pszConverted; } #endif
void CEconCraftingRecipeDefinition::GenerateLocStrings( void ) { #if defined( CLIENT_DLL )
wchar_t *pName_A = g_pVGuiLocalize->Find( GetName_A() ); g_pVGuiLocalize->ConstructString( m_wszName, sizeof( m_wszName ), g_pVGuiLocalize->Find( GetName() ), 1, pName_A );
wchar_t wcTmpA[32]; wchar_t wcTmpB[32]; wchar_t wcTmpC[32]; wchar_t wcTmp[512];
// Build the input string
wchar_t *pInp_A = LocalizeRecipeStringPiece( GetDescI_A(), wcTmpA, sizeof( wcTmpA ) ); wchar_t *pInp_B = LocalizeRecipeStringPiece( GetDescI_B(), wcTmpB, sizeof( wcTmpB ) ); wchar_t *pInp_C = LocalizeRecipeStringPiece( GetDescI_C(), wcTmpC, sizeof( wcTmpC ) ); g_pVGuiLocalize->ConstructString( m_wszDesc, sizeof( m_wszDesc ), g_pVGuiLocalize->Find( GetDescInputs() ), 3, pInp_A, pInp_B, pInp_C );
// Build the output string
wchar_t *pOut_A = LocalizeRecipeStringPiece( GetDescO_A(), wcTmpA, sizeof( wcTmpA ) ); wchar_t *pOut_B = LocalizeRecipeStringPiece( GetDescO_B(), wcTmpB, sizeof( wcTmpB ) ); wchar_t *pOut_C = LocalizeRecipeStringPiece( GetDescO_C(), wcTmpC, sizeof( wcTmpC ) ); g_pVGuiLocalize->ConstructString( wcTmp, sizeof( wcTmp ), g_pVGuiLocalize->Find( GetDescOutputs() ), 3, pOut_A, pOut_B, pOut_C );
// Concatenate, and mark the text changes
V_wcscat_safe( m_wszDesc, L"\n" ); V_wcscat_safe( m_wszDesc, wcTmp ); #endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#define GC_SCH_REFERENCE( TAttribSchType )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
unsigned int Internal_GetAttributeTypeUniqueIdentifierNextValue() { static unsigned int s_unUniqueCounter = 0;
unsigned int unCounter = s_unUniqueCounter; s_unUniqueCounter++; return unCounter; }
template < typename T > unsigned int GetAttributeTypeUniqueIdentifier() { static unsigned int s_unUniqueCounter = Internal_GetAttributeTypeUniqueIdentifierNextValue(); return s_unUniqueCounter; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
template < GC_SCH_REFERENCE( typename TAttribSchType ) typename TAttribInMemoryType > class CSchemaAttributeTypeBase : public ISchemaAttributeTypeBase<TAttribInMemoryType> { public: };
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
template < GC_SCH_REFERENCE( typename TAttribSchType ) typename TProtobufValueType > class CSchemaAttributeTypeProtobufBase : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( TAttribSchType ) TProtobufValueType > { public: virtual void ConvertTypedValueToByteStream( const TProtobufValueType& typedValue, ::std::string *out_psBytes ) const OVERRIDE { DbgVerify( typedValue.SerializeToString( out_psBytes ) ); }
virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, TProtobufValueType *out_pTypedValue ) const OVERRIDE { DbgVerify( out_pTypedValue->ParseFromString( sBytes ) ); }
virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE { Assert( pAttrDef ); Assert( out_pValue ); std::string sValue( pszValue ); TProtobufValueType typedValue; if ( !google::protobuf::TextFormat::ParseFromString( sValue, &typedValue ) ) return false;
this->ConvertTypedValueToEconAttributeValue( typedValue, out_pValue ); return true; }
virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE { Assert( pAttrDef ); Assert( out_ps );
google::protobuf::TextFormat::PrintToString( this->GetTypedValueContentsFromEconAttributeValue( value ), out_ps ); } };
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CSchemaAttributeType_String : public CSchemaAttributeTypeProtobufBase< GC_SCH_REFERENCE( CSchItemAttributeString ) CAttribute_String > { public: // We intentionally override the convert-to-/convert-from-string functions for strings so that string literals can be
// specified in the schema, etc. without worrying about the protobuf text format.
virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE { Assert( pAttrDef ); Assert( out_pValue );
CAttribute_String typedValue; typedValue.set_value( pszValue );
this->ConvertTypedValueToEconAttributeValue( typedValue, out_pValue );
return true; }
virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE { Assert( pAttrDef ); Assert( out_ps );
*out_ps = this->GetTypedValueContentsFromEconAttributeValue( value ).value().c_str(); } };
void CopyStringAttributeValueToCharPointerOutput( const CAttribute_String *pValue, const char **out_pValue ) { Assert( pValue ); Assert( out_pValue );
*out_pValue = pValue->value().c_str(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CSchemaAttributeType_Vector : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( CSchItemAttributeVector ) Vector > { public: // We intentionally override the convert-to-/convert-from-string functions for strings so that string literals can be
// specified in the schema, etc. without worrying about the protobuf text format.
virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE { Assert( pAttrDef ); Assert( out_pValue );
Vector typedValue; if ( sscanf( pszValue, "%f %f %f", &typedValue.x, &typedValue.y, &typedValue.z ) < 3 ) { AssertMsg1( false, "Vector attribute value has invalid string: %s", pszValue ); }
this->ConvertTypedValueToEconAttributeValue( typedValue, out_pValue );
return true; }
virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE { Assert( pAttrDef ); Assert( out_ps );
Vector typedValue; this->ConvertEconAttributeValueToTypedValue( value, &typedValue );
char szTemp[ 256 ]; V_sprintf_safe( szTemp, "%f %f %f", typedValue[ 0 ], typedValue[ 1 ], typedValue[ 2 ] );
*out_ps = szTemp; }
virtual void ConvertTypedValueToByteStream( const Vector& typedValue, ::std::string *out_psBytes ) const OVERRIDE { Assert( out_psBytes ); Assert( out_psBytes->size() == 0 );
out_psBytes->resize( sizeof( Vector ) ); *reinterpret_cast<Vector *>( &((*out_psBytes)[0]) ) = typedValue; }
virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, Vector *out_pTypedValue ) const OVERRIDE { Assert( out_pTypedValue ); Assert( sBytes.size() == sizeof( Vector ) );
*out_pTypedValue = *reinterpret_cast<const Vector *>( &sBytes[0] ); } };
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CSchemaAttributeType_Uint32 : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( CSchItemAttributeUint32 ) uint32 > { public: virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE { Assert( pAttrDef ); Assert( out_pValue );
out_pValue->asUint32 = Q_atoi( pszValue ); return true; }
virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE { Assert( pAttrDef ); Assert( out_ps );
*out_ps = CFmtStr( "%u", value.asUint32 ).Get(); }
virtual void ConvertTypedValueToByteStream( const uint32& typedValue, ::std::string *out_psBytes ) const OVERRIDE { Assert( out_psBytes ); Assert( out_psBytes->size() == 0 );
out_psBytes->resize( sizeof( uint32 ) ); *reinterpret_cast<uint32 *>( &((*out_psBytes)[0]) ) = typedValue; }
virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, uint32 *out_pTypedValue ) const OVERRIDE { Assert( out_pTypedValue ); Assert( sBytes.size() == sizeof( uint32 ) );
*out_pTypedValue = *reinterpret_cast<const uint32 *>( &sBytes[0] ); }
virtual bool BSupportsGameplayModificationAndNetworking() const OVERRIDE { return true; } };
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CSchemaAttributeType_Float : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( CSchItemAttributeFloat ) float > { public: virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE { Assert( pAttrDef ); Assert( out_pValue );
out_pValue->asFloat = Q_atof( pszValue ); return true; }
virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE { Assert( pAttrDef ); Assert( out_ps );
*out_ps = CFmtStr( "%f", value.asFloat ).Get(); }
virtual void ConvertTypedValueToByteStream( const float& typedValue, ::std::string *out_psBytes ) const OVERRIDE { Assert( out_psBytes ); Assert( out_psBytes->size() == 0 );
out_psBytes->resize( sizeof( float ) ); *reinterpret_cast<float *>( &((*out_psBytes)[0]) ) = typedValue; // overwrite string contents (sizeof( float ) bytes)
}
virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, float *out_pTypedValue ) const OVERRIDE { Assert( out_pTypedValue ); Assert( sBytes.size() == sizeof( float ) );
*out_pTypedValue = *reinterpret_cast<const float *>( &sBytes[0] ); }
virtual bool BSupportsGameplayModificationAndNetworking() const OVERRIDE { return true; }
virtual bool OnIterateAttributeValue( IEconItemAttributeIterator *pIterator, const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value ) const OVERRIDE { Assert( pIterator ); Assert( pAttrDef );
// Call the appropriate virtual function on our iterator based on whatever type we represent.
return pIterator->OnIterateAttributeValue( pAttrDef, value.asFloat ); } };
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CSchemaAttributeType_Default : public CSchemaAttributeTypeBase< GC_SCH_REFERENCE( CSchItemAttribute ) attrib_value_t > { public: virtual bool BConvertStringToEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const char *pszValue, union attribute_data_union_t *out_pValue ) const OVERRIDE { Assert( pAttrDef ); Assert( out_pValue );
// This is terrible backwards-compatibility code to support the pulling of values from econ asset classes.
if ( pAttrDef->IsStoredAsInteger() ) { out_pValue->asUint32 = pszValue ? (uint32)V_atoui64( pszValue ) : 0; } else if ( pAttrDef->IsStoredAsFloat() ) { out_pValue->asFloat = pszValue ? V_atof( pszValue ) : 0.0f; } else { Assert( !"Unknown storage type for CSchemaAttributeType_Default::BConvertStringToEconAttributeValue()!" ); return false; }
return true; }
virtual void ConvertEconAttributeValueToString( const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value, std::string *out_ps ) const OVERRIDE { Assert( pAttrDef ); Assert( out_ps );
if( pAttrDef->IsStoredAsFloat() ) { *out_ps = CFmtStr( "%f", value.asFloat ).Get(); } else if( pAttrDef->IsStoredAsInteger() ) { *out_ps = CFmtStr( "%u", value.asUint32 ).Get(); } else { Assert( !"Unknown storage type for CSchemaAttributeType_Default::ConvertEconAttributeValueToString()!" ); } } virtual void ConvertTypedValueToByteStream( const attrib_value_t& typedValue, ::std::string *out_psBytes ) const OVERRIDE { Assert( out_psBytes ); Assert( out_psBytes->size() == 0 );
out_psBytes->resize( sizeof( attrib_value_t ) ); *reinterpret_cast<attrib_value_t *>( &((*out_psBytes)[0]) ) = typedValue; // overwrite string contents (sizeof( attrib_value_t ) bytes)
}
virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, attrib_value_t *out_pTypedValue ) const OVERRIDE { Assert( out_pTypedValue ); // Game clients and servers may have partially out-of-date information, or may have downloaded a new schema
// but not know how to parse an attribute of a certain type, etc. In these cases, because we know we
// aren't on the GC, temporarily failing to load these values until the client shuts down and updates
// is about the best we can hope for.
if ( sBytes.size() < sizeof( attrib_value_t ) ) { *out_pTypedValue = attrib_value_t(); return; }
*out_pTypedValue = *reinterpret_cast<const attrib_value_t *>( &sBytes[0] ); }
virtual bool BSupportsGameplayModificationAndNetworking() const OVERRIDE { return true; }
private: };
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CEconItemAttributeDefinition::CEconItemAttributeDefinition( void ) : m_pKVAttribute( NULL ), m_pAttrType( NULL ), m_bHidden( false ), m_bWebSchemaOutputForced( false ), m_bStoredAsInteger( false ), m_iEffectType( ATTRIB_EFFECT_NEUTRAL ), m_iDescriptionFormat( 0 ), m_pszDescriptionString( NULL ), m_pszDescriptionTag( NULL ), m_pszArmoryDesc( NULL ), m_iScore( 0 ), m_pszDefinitionName( NULL ), m_pszAttributeClass( NULL ) #ifndef GC_DLL
, m_iszAttributeClass( NULL_STRING ) #endif
{ }
//-----------------------------------------------------------------------------
// Purpose: Copy constructor
//-----------------------------------------------------------------------------
CEconItemAttributeDefinition::CEconItemAttributeDefinition( const CEconItemAttributeDefinition &that ) { (*this) = that; }
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CEconItemAttributeDefinition &CEconItemAttributeDefinition::operator=( const CEconItemAttributeDefinition &rhs ) { m_nDefIndex = rhs.m_nDefIndex; m_pAttrType = rhs.m_pAttrType; m_bHidden = rhs.m_bHidden; m_bWebSchemaOutputForced = rhs.m_bWebSchemaOutputForced; m_bStoredAsInteger = rhs.m_bStoredAsInteger; m_bInstanceData = rhs.m_bInstanceData; m_eAssetClassAttrExportRule = rhs.m_eAssetClassAttrExportRule; m_iEffectType = rhs.m_iEffectType; m_iDescriptionFormat = rhs.m_iDescriptionFormat; m_pszDescriptionString = rhs.m_pszDescriptionString; m_pszDescriptionTag = rhs.m_pszDescriptionTag; m_pszArmoryDesc = rhs.m_pszArmoryDesc; m_iScore = rhs.m_iScore; m_pszDefinitionName = rhs.m_pszDefinitionName; m_pszAttributeClass = rhs.m_pszAttributeClass; m_unAssetClassBucket = rhs.m_unAssetClassBucket; #ifndef GC_DLL
m_iszAttributeClass = rhs.m_iszAttributeClass; #endif
m_pKVAttribute = NULL; if ( NULL != rhs.m_pKVAttribute ) { m_pKVAttribute = rhs.m_pKVAttribute->MakeCopy();
// Re-assign string pointers
m_pszDefinitionName = m_pKVAttribute->GetString("name"); m_pszDescriptionString = m_pKVAttribute->GetString( "description_string", NULL ); m_pszDescriptionTag = m_pKVAttribute->GetString( "description_tag", NULL );
m_pszArmoryDesc = m_pKVAttribute->GetString( "armory_desc", NULL ); m_pszAttributeClass = m_pKVAttribute->GetString( "attribute_class", NULL );
Assert( V_strcmp( m_pszDefinitionName, rhs.m_pszDefinitionName ) == 0 ); Assert( V_strcmp( m_pszDescriptionString, rhs.m_pszDescriptionString ) == 0 ); Assert( V_strcmp( m_pszDescriptionTag, rhs.m_pszDescriptionTag ) == 0 ); Assert( V_strcmp( m_pszArmoryDesc, rhs.m_pszArmoryDesc ) == 0 ); Assert( V_strcmp( m_pszAttributeClass, rhs.m_pszAttributeClass ) == 0 ); } else { Assert( m_pszDefinitionName == NULL ); Assert( m_pszDescriptionString == NULL ); Assert( m_pszArmoryDesc == NULL ); Assert( m_pszAttributeClass == NULL ); } return *this; }
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CEconItemAttributeDefinition::~CEconItemAttributeDefinition( void ) { if ( m_pKVAttribute ) m_pKVAttribute->deleteThis(); m_pKVAttribute = NULL; }
//-----------------------------------------------------------------------------
// Purpose: Initialize the attribute definition
// Input: pKVAttribute - The KeyValues representation of the attribute
// schema - The overall item schema for this attribute
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemAttributeDefinition::BInitFromKV( KeyValues *pKVAttribute, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { m_pKVAttribute = pKVAttribute->MakeCopy(); m_nDefIndex = Q_atoi( m_pKVAttribute->GetName() ); m_pszDefinitionName = m_pKVAttribute->GetString("name"); m_bHidden = m_pKVAttribute->GetInt( "hidden", 0 ) != 0; m_bWebSchemaOutputForced = m_pKVAttribute->GetInt( "force_output_description", 0 ) != 0; m_bStoredAsInteger = m_pKVAttribute->GetInt( "stored_as_integer", 0 ) != 0; m_iScore = m_pKVAttribute->GetInt( "score", 0 ); m_iEffectType = (attrib_effect_types_t)StringFieldToInt( m_pKVAttribute->GetString("effect_type"), g_EffectTypes, ARRAYSIZE(g_EffectTypes) ); m_iDescriptionFormat = StringFieldToInt( m_pKVAttribute->GetString("description_format"), g_AttributeDescriptionFormats, ARRAYSIZE(g_AttributeDescriptionFormats) ); m_pszDescriptionString = m_pKVAttribute->GetString( "description_string", NULL ); m_pszDescriptionTag = m_pKVAttribute->GetString( "description_tag", NULL ); m_pszArmoryDesc = m_pKVAttribute->GetString( "armory_desc", NULL ); m_pszAttributeClass = m_pKVAttribute->GetString( "attribute_class", NULL ); m_bInstanceData = pKVAttribute->GetBool( "instance_data", false );
const char *pszAttrType = m_pKVAttribute->GetString( "attribute_type", NULL ); // NULL implies "default type" for backwards compatibility
m_pAttrType = pschema.GetAttributeType( pszAttrType ); SCHEMA_INIT_CHECK( NULL != m_pAttrType, CFmtStr( "Attribute definition %s: Unable to find attribute data type '%s'", m_pszDefinitionName, pszAttrType ? pszAttrType : "(default)" ) );
#if defined(CLIENT_DLL) || defined(GAME_DLL)
m_iszAttributeClass = NULL_STRING; #endif
// Check for required fields
SCHEMA_INIT_CHECK( NULL != m_pKVAttribute->FindKey( "name" ), CFmtStr( "Attribute definition %s: Missing required field \"name\"", m_pKVAttribute->GetName() ) );
m_unAssetClassBucket = pKVAttribute->GetInt( "asset_class_bucket", 0 ); m_eAssetClassAttrExportRule = k_EAssetClassAttrExportRule_Default; if ( char const *szRule = pKVAttribute->GetString( "asset_class_export", NULL ) ) { if ( !V_stricmp( szRule, "skip" ) ) { m_eAssetClassAttrExportRule = k_EAssetClassAttrExportRule_Skip; } else if ( !V_stricmp( szRule, "gconly" ) ) { m_eAssetClassAttrExportRule = EAssetClassAttrExportRule_t( k_EAssetClassAttrExportRule_GCOnly | k_EAssetClassAttrExportRule_Skip ); } else if ( !V_stricmp( szRule, "bucketed" ) ) { SCHEMA_INIT_CHECK( m_unAssetClassBucket, CFmtStr( "Attribute definition %s: Asset class export rule '%s' is incompatible", m_pszDefinitionName, szRule ) ); m_eAssetClassAttrExportRule = k_EAssetClassAttrExportRule_Bucketed; } else if ( !V_stricmp( szRule, "default" ) ) { m_eAssetClassAttrExportRule = k_EAssetClassAttrExportRule_Default; } else { SCHEMA_INIT_CHECK( false, CFmtStr( "Attribute definition %s: Invalid asset class export rule '%s'", m_pszDefinitionName, szRule ) ); } }
// Check for misuse of asset class bucket
SCHEMA_INIT_CHECK( ( !m_unAssetClassBucket || m_bInstanceData ), CFmtStr( "Attribute definition %s: Cannot use \"asset_class_bucket\" on class-level attributes", m_pKVAttribute->GetName() ) );
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CEconSoundMaterialDefinition::CEconSoundMaterialDefinition( void ) : m_nID( INT_MAX ) { }
//-----------------------------------------------------------------------------
// Purpose: Copy constructor
//-----------------------------------------------------------------------------
CEconSoundMaterialDefinition::CEconSoundMaterialDefinition( const CEconSoundMaterialDefinition &that ) { (*this) = that; }
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CEconSoundMaterialDefinition &CEconSoundMaterialDefinition::operator=( const CEconSoundMaterialDefinition &rhs ) { m_nID = rhs.m_nID; m_strName = rhs.m_strName; m_strStartDragSound = rhs.m_strStartDragSound; m_strEndDragSound = rhs.m_strEndDragSound; m_strEquipSound = rhs.m_strEquipSound;
return *this; }
//-----------------------------------------------------------------------------
// Purpose: Initialize the rarity definition
//-----------------------------------------------------------------------------
bool CEconSoundMaterialDefinition::BInitFromKV( KeyValues *pKVSoundMaterial, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { m_nID = pKVSoundMaterial->GetInt( "value", -1 ); m_strName = pKVSoundMaterial->GetName(); m_strStartDragSound = pKVSoundMaterial->GetString( "start_drag_sound" ); m_strEndDragSound = pKVSoundMaterial->GetString( "end_drag_sound" ); m_strEquipSound = pKVSoundMaterial->GetString( "equip_sound" );
// Check for required fields
SCHEMA_INIT_CHECK( NULL != pKVSoundMaterial->FindKey( "value" ), CFmtStr( "Sound material definition %s: Missing required field \"value\"", pKVSoundMaterial->GetName() ) );
#if defined(CLIENT_DLL) || defined(GAME_DLL)
return SCHEMA_INIT_SUCCESS(); #endif // GC_DLL
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CEconItemDefinition::CEconItemDefinition( void ) : m_pKVItem( NULL ), m_bEnabled( false ), m_unMinItemLevel( 0 ), m_unMaxItemLevel( 100 ), m_iArmoryRemap( 0 ), m_iStoreRemap( 0 ), m_nItemRarity( k_unItemRarity_Any ), m_nItemQuality( k_unItemQuality_Any ), m_nForcedItemQuality( k_unItemQuality_Any ), m_nDefaultDropItemQuality( k_unItemQuality_Any ), m_nDefaultDropQuantity( 1 ), m_pProxyCriteria( NULL ), m_bLoadOnDemand( false ), m_pTool( NULL ), m_rtExpiration( 0 ), m_rtDefCreation( 0 ), m_BundleInfo( NULL ), m_unNumConcreteItems( 0 ), m_nSoundMaterialID( 0 ), m_nPopularitySeed( 0 ), m_pszDefinitionName( NULL ), m_pszItemClassname( NULL ), m_pszClassToken( NULL ), m_pszSlotToken( NULL ), m_pszItemBaseName( NULL ), m_pszItemTypeName( NULL ), m_unItemTypeID( 0 ), m_pszItemDesc( NULL ), m_pszArmoryDesc( NULL ), m_pszInventoryModel( NULL ), m_pszInventoryImage( NULL ), m_pszHolidayRestriction( NULL ), m_iSubType( 0 ), m_pszBaseDisplayModel( NULL ), m_pszWorldDisplayModel( NULL ), m_pszWorldDroppedModel( NULL ), m_pszWorldExtraWearableModel( NULL ), m_pszIconDefaultImage( NULL ), m_pszParticleFile( NULL ), m_pszParticleSnapshotFile( NULL ), m_pInventoryImageData( NULL ), m_pszBrassModelOverride( NULL ), m_bHideBodyGroupsDeployedOnly( false ), m_bAttachToHands( false ), m_bAttachToHandsVMOnly( false ), m_bProperName( false ), m_bFlipViewModel( false ), m_bActAsWearable( false ), m_iDropType( 1 ), m_bHidden( false ), m_bShouldShowInArmory( false ), m_bIsPackBundle( false ), m_pOwningPackBundle( NULL ), m_bBaseItem( false ), m_pszItemLogClassname( NULL ), m_pszItemIconClassname( NULL ), #if ECONITEM_DATABASE_AUDIT_TABLES_FEATURE
m_pszDatabaseAuditTable( NULL ), #endif
m_bImported( false ), m_bOnePerAccountCDKEY( false ), m_pszArmoryRemap( NULL ), m_pszStoreRemap( NULL ), m_bPublicItem( false ), m_bIgnoreInCollectionView( false ), m_nAssociatedItemsDefIndexes( NULL ), m_pPortraitsKV( NULL ), m_pAssetInfo( NULL ), m_eItemType( k_EItemTypeNone ), m_bAllowPurchaseStandalone( false ) { m_pMapAlternateIcons = new CUtlMap<uint32, const char*>; m_pMapAlternateIcons->SetLessFunc( DefLessFunc(uint32) ); }
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CEconItemDefinition::~CEconItemDefinition( void ) { if ( m_pKVItem ) m_pKVItem->deleteThis(); m_pKVItem = NULL; delete m_pProxyCriteria; delete m_pTool; delete m_BundleInfo; delete m_pMapAlternateIcons;
if ( m_pInventoryImageData ) { for ( int i = 0; i < MATERIAL_MAX_LIGHT_COUNT; i++ ) { delete m_pInventoryImageData->m_pLightDesc[ i ]; } delete m_pInventoryImageData->m_pCameraOffset; delete m_pInventoryImageData->m_pCameraAngles; delete m_pInventoryImageData; }
PurgeStaticAttributes(); }
void CEconItemDefinition::PurgeStaticAttributes() { FOR_EACH_VEC( m_vecStaticAttributes, i ) { static_attrib_t *pAttrib = &(m_vecStaticAttributes[ i ]);
const CEconItemAttributeDefinition *pAttrDef = pAttrib->GetAttributeDefinition(); Assert( pAttrDef );
const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType(); Assert( pAttrType );
// Free up our temp loading memory.
pAttrType->UnloadEconAttributeValue( &pAttrib->m_value ); }
m_vecStaticAttributes.Purge(); }
#if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose: Stomp our base data with extra testing data specified by the player
//-----------------------------------------------------------------------------
bool CEconItemDefinition::BInitFromTestItemKVs( int iNewDefIndex, KeyValues *pKVItem, CEconItemSchema &pschema ) { // The KeyValues are stored in the player entity, so we can cache our name there
m_nDefIndex = iNewDefIndex;
bool bTestingExistingItem = pKVItem->GetInt( "test_existing_item", 0 ) != 0; if ( !bTestingExistingItem ) { m_pszDefinitionName = pKVItem->GetString( "name", NULL ); m_pszItemBaseName = pKVItem->GetString( "name", NULL );
#ifdef CLIENT_DLL
pKVItem->SetString( "name", VarArgs("Test Item %d", iNewDefIndex) ); #else
pKVItem->SetString( "name", UTIL_VarArgs("Test Item %d", iNewDefIndex) ); #endif
m_pszBaseDisplayModel = pKVItem->GetString( "model_player", NULL ); m_bAttachToHands = pKVItem->GetInt( "attach_to_hands", 0 ) != 0;
BInitVisualBlockFromKV( pKVItem, pschema );
m_pszParticleFile = pKVItem->GetString( "particle_file", NULL ); m_pszParticleSnapshotFile = pKVItem->GetString( "particle_snapshot", NULL ); }
// Handle attributes
PurgeStaticAttributes();
int iPaintCanIndex = pKVItem->GetInt("paintcan_index", 0); if ( iPaintCanIndex ) { static CSchemaAttributeDefHandle pAttrDef_PaintRGB( "set item tint RGB" );
const CEconItemDefinition *pCanDef = pschema.GetItemDefinition(iPaintCanIndex);
float flRGBVal; if ( pCanDef && pAttrDef_PaintRGB && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pCanDef, pAttrDef_PaintRGB, &flRGBVal ) ) { static_attrib_t& StaticAttrib = m_vecStaticAttributes[ m_vecStaticAttributes.AddToTail() ];
StaticAttrib.iDefIndex = pAttrDef_PaintRGB->GetDefinitionIndex(); StaticAttrib.m_value.asFloat = flRGBVal; // this is bad! but we're in crazy hack code for UI customization of item definitions that don't exist so
} }
return true; } #endif
void AssetInfo::AddAssetModifier( AssetModifier* newMod ) { int idx = m_mapAssetModifiers.Find( newMod->m_Type ); if ( !m_mapAssetModifiers.IsValidIndex( idx ) ) { idx = m_mapAssetModifiers.Insert( newMod->m_Type, new CUtlVector<AssetModifier*> ); } m_mapAssetModifiers[idx]->AddToTail( newMod ); }
CUtlVector<AssetModifier*>* AssetInfo::GetAssetModifiers( EAssetModifier type ) { int idx = m_mapAssetModifiers.Find( type ); if ( m_mapAssetModifiers.IsValidIndex( idx ) ) { return m_mapAssetModifiers[idx]; } else { return NULL; } }
const char* AssetInfo::GetModifierByAsset( EAssetModifier type, const char* pszAsset, int iStyle ) { CUtlVector<AssetModifier*>* pAssetModifierList = GetAssetModifiers( type ); if ( pAssetModifierList ) { if ( iStyle > -1 ) { // See if a modifier matches this style.
FOR_EACH_VEC( *pAssetModifierList, i ) { AssetModifier* pMod = pAssetModifierList->Element(i); if ( pMod->m_strAsset == pszAsset && pMod->m_iStyle == iStyle ) return pMod->m_strModifier; } }
// Return the first match.
FOR_EACH_VEC( *pAssetModifierList, i ) { AssetModifier* pMod = pAssetModifierList->Element(i); if ( pMod->m_strAsset == pszAsset ) return pMod->m_strModifier; } }
return NULL; }
const char* AssetInfo::GetAssetByModifier( EAssetModifier type, const char* pszModifier, int iStyle ) { CUtlVector<AssetModifier*>* pAssetModifierList = GetAssetModifiers( type ); if ( pAssetModifierList ) { if ( iStyle > -1 ) { // See if a modifier matches this style.
FOR_EACH_VEC( *pAssetModifierList, i ) { AssetModifier* pMod = pAssetModifierList->Element(i); if ( pMod->m_strModifier == pszModifier && pMod->m_iStyle == iStyle ) return pMod->m_strAsset; } }
// Return the first match.
FOR_EACH_VEC( *pAssetModifierList, i ) { AssetModifier* pMod = pAssetModifierList->Element(i); if ( pMod->m_strModifier == pszModifier ) return pMod->m_strAsset; } }
return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Handle parsing the per-team visual block from the keyvalues
//-----------------------------------------------------------------------------
void CEconItemDefinition::BInitVisualBlockFromKV( KeyValues *pKVItem, IEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors ) { // Visuals
m_pAssetInfo = NULL; KeyValues *pVisualsKV = pKVItem->FindKey( "visuals" ); if ( pVisualsKV ) { AssetInfo *pVisData = new AssetInfo();
#if defined(CLIENT_DLL) || defined(GAME_DLL)
KeyValues *pKVEntry = pVisualsKV->GetFirstSubKey(); while ( pKVEntry ) { const char *pszEntry = pKVEntry->GetName();
if ( !Q_stricmp( pszEntry, "attached_models" ) ) { FOR_EACH_SUBKEY( pKVEntry, pKVAttachedModelData ) { int iAtt = pVisData->m_AttachedModels.AddToTail(); pVisData->m_AttachedModels[iAtt].m_iModelDisplayFlags = pKVAttachedModelData->GetInt( "model_display_flags", kAttachedModelDisplayFlag_MaskAll ); pVisData->m_AttachedModels[iAtt].m_pszModelName = pKVAttachedModelData->GetString( "model", NULL ); } } else if ( StringHasPrefix( pszEntry, "attached_particlesystem" ) ) { // This replaces TF's "attached_particlesystem", "custom_particlesystem", and "custom_particlesystem2"
// It now indexes into the attributecontrolledparticlesystems list (use the "custom_type" field if you want a custom attribute)
int iParticleIndex; if ( pschema.FindAttributeControlledParticleSystem( pKVEntry->GetString( "system", NULL ), &iParticleIndex ) ) { attachedparticle_t attachedParticle; attachedParticle.m_iParticleIndex = iParticleIndex; attachedParticle.m_nStyle = pKVEntry->GetInt( "style", 0 );
pVisData->m_AttachedParticles.AddToTail( attachedParticle ); } } else if ( StringHasPrefix( pszEntry, "asset_modifier" ) ) { AssetModifier* newMod = new AssetModifier(); newMod->m_Type = GetAssetModifierType( pKVEntry->GetString( "type", NULL ) ); newMod->m_strModifier = pKVEntry->GetString( "modifier", NULL ); newMod->m_flModifier = pKVEntry->GetFloat( "modifier", 0.f ); newMod->m_strAsset = pKVEntry->GetString( "asset", NULL ); newMod->m_iStyle = pKVEntry->GetInt( "style", 0 ); pVisData->AddAssetModifier( newMod );
// Items can have any number of asset modifiers.
// The variables can be used in any way, based on type, but the format is all the same to simplify the editor.
const char* pszAssetModifierType = pKVEntry->GetString( "type", NULL );
const char* pszAssetName = pKVEntry->GetString( "asset", NULL ); const char* pszModifierName = pKVEntry->GetString( "modifier", NULL ); float flFrequency = pKVEntry->GetFloat( "frequency", 1.0 );
if ( FStrEq( pszAssetModifierType, "activity" ) ) { int iAtt = pVisData->m_Animations.AddToTail(); pVisData->m_Animations[iAtt].iActivity = -2; pVisData->m_Animations[iAtt].pszActivity = pszAssetName; pVisData->m_Animations[iAtt].iReplacement = kActivityLookup_Unknown; pVisData->m_Animations[iAtt].pszReplacement = pszModifierName; pVisData->m_Animations[iAtt].flFrequency = flFrequency; } else if ( FStrEq( pszAssetModifierType, "announcer" ) ) { pVisData->m_pszAnnouncerName = pszAssetName; pVisData->m_pszAnnouncerResource = pszModifierName; } else if ( FStrEq( pszAssetModifierType, "announcer_preview" ) ) { CUtlString strFilename = pszAssetName;
announcer_preview_t preview;
preview.m_strFileName = pszAssetName; preview.m_strCaption = pszModifierName;
pVisData->m_vecAnnouncerPreview.AddToTail( preview ); } else if ( FStrEq( pszAssetModifierType, "hud_skin" ) ) { pVisData->m_pszHudSkinName = pszAssetName; } else if ( FStrEq( pszAssetModifierType, "ability_name" ) ) { pVisData->m_pszAbilityName = pszAssetName; } else if ( FStrEq( pszAssetModifierType, "sound" ) ) { int iSound = pVisData->m_Sounds.AddToTail(); pVisData->m_Sounds[iSound].pszSound = pszAssetName; pVisData->m_Sounds[iSound].pszReplacement = pszModifierName; } else if ( FStrEq( pszAssetModifierType, "speech" ) ) { pVisData->m_pszSpeechConcept = pszAssetName; pVisData->m_pszChatMessage = pszModifierName; } else if ( FStrEq( pszAssetModifierType, "particle" ) ) { int iParticle = pVisData->m_Particles.AddToTail(); pVisData->m_Particles[iParticle].pszParticle = pszAssetName; pVisData->m_Particles[iParticle].pszReplacement = pszModifierName; } else if ( FStrEq( pszAssetModifierType, "particle_snapshot" ) ) { int iParticle = pVisData->m_ParticleSnapshots.AddToTail(); pVisData->m_ParticleSnapshots[iParticle].pszParticleSnapshot = pszAssetName; pVisData->m_ParticleSnapshots[iParticle].pszReplacement = pszModifierName; } else if ( FStrEq( pszAssetModifierType, "particle_control_point" ) ) { int iParticleCP = pVisData->m_ParticleControlPoints.AddToTail(); pVisData->m_ParticleControlPoints[iParticleCP].pszParticle = pszAssetName; pVisData->m_ParticleControlPoints[iParticleCP].nParticleControlPoint = pKVEntry->GetInt( "control_point_number", 0 ); UTIL_StringToVector( pVisData->m_ParticleControlPoints[iParticleCP].vecCPValue.Base(), pKVEntry->GetString( "cp_position", "0 0 0" ) ); } else if ( FStrEq( pszAssetModifierType, "entity_model" ) ) { pVisData->m_pszEntityClass = pszAssetName; pVisData->m_pszEntityModel = pszModifierName; } else if ( FStrEq( pszAssetModifierType, "view_model" ) ) { pVisData->m_pszEntityClass = pszAssetName; pVisData->m_pszViewModel = pszModifierName; } else if ( FStrEq( pszAssetModifierType, "icon_replacement" ) ) { pVisData->m_pszOriginalIcon = pszAssetName; pVisData->m_pszNewIcon = pszModifierName; } else if ( FStrEq( pszAssetModifierType, "ability_icon_replacement" ) ) { ability_icon_replacement_t iconReplacement;
iconReplacement.m_strAbilityName = pszAssetName; iconReplacement.m_strReplacement = pszModifierName;
pVisData->m_vecAbilityIconReplacements.AddToTail( iconReplacement ); } else if ( FStrEq( pszAssetModifierType, "entity_scale" ) ) { pVisData->m_pszScaleClass = pszAssetName; pVisData->m_flScaleSize = pKVEntry->GetFloat( "modifier", 1.f ); } } else if ( !Q_stricmp( pszEntry, "animation" ) ) { int iAtt = pVisData->m_Animations.AddToTail(); pVisData->m_Animations[iAtt].iActivity = -2; // We can't look it up yet, the activity list hasn't been populated.
pVisData->m_Animations[iAtt].pszActivity = pKVEntry->GetString( "activity", NULL );
const char* playback = pKVEntry->GetString( "playback" ); if ( playback ) { pVisData->m_Animations[iAtt].iPlayback = (wearableanimplayback_t)StringFieldToInt( pKVEntry->GetString("playback"), g_WearableAnimTypeStrings, ARRAYSIZE(g_WearableAnimTypeStrings) ); }
pVisData->m_Animations[iAtt].iReplacement = kActivityLookup_Unknown; pVisData->m_Animations[iAtt].pszReplacement = pKVEntry->GetString( "replacement", NULL );
pVisData->m_Animations[iAtt].pszSequence = pKVEntry->GetString( "sequence", NULL ); pVisData->m_Animations[iAtt].pszScene = pKVEntry->GetString( "scene", NULL ); pVisData->m_Animations[iAtt].pszRequiredItem = pKVEntry->GetString( "required_item", NULL ); pVisData->m_Animations[iAtt].flFrequency = pKVEntry->GetFloat( "frequency", 1.0 ); } else if ( !Q_stricmp( pszEntry, "player_bodygroups" ) ) { FOR_EACH_SUBKEY( pKVEntry, pKVBodygroupKey ) { const char *pszBodygroupName = pKVBodygroupKey->GetName(); int iValue = pKVBodygroupKey->GetInt();
// Track bodygroup information for this item in particular.
pVisData->m_ModifiedBodyGroupNames.Insert( pszBodygroupName, iValue );
// Track global schema state.
CEconItemSchema* pItemSchema = (CEconItemSchema*) &pschema; pItemSchema->AssignDefaultBodygroupState( pszBodygroupName, iValue ); } } else if ( !Q_stricmp( pszEntry, "skin" ) ) { pVisData->iSkin = pKVEntry->GetInt(); } else if ( !Q_stricmp( pszEntry, "use_per_class_bodygroups" ) ) { pVisData->bUsePerClassBodygroups = pKVEntry->GetBool(); } else if ( !Q_stricmp( pszEntry, "muzzle_flash" ) ) { pVisData->m_pszMuzzleFlash = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "tracer_effect" ) ) { pVisData->m_pszTracerEffect = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "particle_effect" ) ) { pVisData->m_pszParticleEffect = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "particle_snapshot" ) ) { pVisData->m_pszParticleSnapshot = pKVEntry->GetString(); } else if ( StringHasPrefix( pszEntry, "custom_sound" ) ) // TF2 style custom sounds.
{ int iIndex = 0; if ( pszEntry[12] ) { iIndex = clamp( atoi( &pszEntry[12] ), 0, MAX_VISUALS_CUSTOM_SOUNDS-1 ); } pVisData->m_pszCustomSounds[iIndex] = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "material_override" ) ) { pVisData->m_pszMaterialOverride = pKVEntry->GetString(); } else if ( StringHasPrefix( pszEntry, "sound_" ) ) // Orange box style weapon sounds.
{ int iIndex = GetWeaponSoundFromString( &pszEntry[6] ); if ( iIndex != -1 ) { pVisData->m_pszWeaponSoundReplacements[iIndex] = pKVEntry->GetString(); } } else if ( !Q_stricmp( pszEntry, "code_controlled_bodygroup" ) ) { const char *pBodyGroupName = pKVEntry->GetString( "bodygroup", NULL ); const char *pFuncName = pKVEntry->GetString( "function", NULL ); if ( pBodyGroupName && pFuncName ) { codecontrolledbodygroupdata_t ccbgd = { pFuncName, NULL }; pVisData->m_CodeControlledBodyGroupNames.Insert( pBodyGroupName, ccbgd ); } } else if ( !Q_stricmp( pszEntry, "vm_bodygroup_override" ) ) { pVisData->m_iViewModelBodyGroupOverride = pKVEntry->GetInt(); } else if ( !Q_stricmp( pszEntry, "vm_bodygroup_state_override" ) ) { pVisData->m_iViewModelBodyGroupStateOverride = pKVEntry->GetInt(); } else if ( !Q_stricmp( pszEntry, "wm_bodygroup_override" ) ) { pVisData->m_iWorldModelBodyGroupOverride = pKVEntry->GetInt(); } else if ( !Q_stricmp( pszEntry, "wm_bodygroup_state_override" ) ) { pVisData->m_iWorldModelBodyGroupStateOverride = pKVEntry->GetInt(); } else if ( !Q_stricmp( pszEntry, "skip_model_combine" ) ) { pVisData->m_bSkipModelCombine = pKVEntry->GetBool(); } else if ( !Q_stricmp( pszEntry, "animation_modifiers" ) ) { FOR_EACH_SUBKEY( pKVEntry, pKVAnimMod ) { pVisData->m_vecAnimationModifiers.AddToTail( pKVAnimMod->GetName() ); } } #ifdef CSTRIKE15
////////////// CS:GO string attributes
else if ( !Q_stricmp( pszEntry, "primary_ammo" ) ) { pVisData->m_pszPrimaryAmmo = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "weapon_type" ) ) { pVisData->m_pszWeaponTypeString = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "addon_location" ) ) { pVisData->m_pszAddonLocation = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "eject_brass_effect" ) ) { pVisData->m_pszEjectBrassEffect = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "tracer_effect" ) ) { pVisData->m_pszTracerEffect = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "muzzle_flash_effect_1st_person" ) ) { pVisData->m_pszMuzzleFlashEffect1stPerson = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "muzzle_flash_effect_1st_person_alt" ) ) { pVisData->m_pszMuzzleFlashEffect1stPersonAlt = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "muzzle_flash_effect_3rd_person" ) ) { pVisData->m_pszMuzzleFlashEffect3rdPerson = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "muzzle_flash_effect_3rd_person_alt" ) ) { pVisData->m_pszMuzzleFlashEffect3rdPersonAlt = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "heat_effect" ) ) { pVisData->m_pszHeatEffect = pKVEntry->GetString(); } else if ( !Q_stricmp( pszEntry, "player_animation_extension" ) ) { pVisData->m_pszPlayerAnimationExtension = pKVEntry->GetString(); }
#endif //#ifdef CSTRIKE15
pKVEntry = pKVEntry->GetNextKey(); } #endif // defined(CLIENT_DLL) || defined(GAME_DLL)
KeyValues *pStylesDataKV = pVisualsKV->FindKey( "styles" ); if ( pStylesDataKV ) { BInitStylesBlockFromKV( pStylesDataKV, *(CEconItemSchema*)( &pschema ), pVisData, pVecErrors ); }
KeyValues * pKVAlternateIcons = pVisualsKV->FindKey( "alternate_icons" ); if ( NULL != pKVAlternateIcons ) { BInitAlternateIconsFromKV( pKVAlternateIcons, *(CEconItemSchema*)( &pschema ), pVisData, pVecErrors ); }
m_pAssetInfo = pVisData; } }
#if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconItemDefinition::GeneratePrecacheModelStrings( bool bDynamicLoad, CUtlVector<const char *> *out_pVecModelStrings ) const { Assert( out_pVecModelStrings );
// Add base model.
out_pVecModelStrings->AddToTail( GetBasePlayerDisplayModel() );
// Add styles.
if ( GetNumStyles() ) { for ( style_index_t i=0; i<GetNumStyles(); ++i ) { const CEconStyleInfo *pStyle = GetStyleInfo( i ); Assert( pStyle );
pStyle->GeneratePrecacheModelStringsForStyle( out_pVecModelStrings ); } }
if ( m_pAssetInfo ) { // Precache all the attached models.
for ( int model = 0; model < m_pAssetInfo->m_AttachedModels.Count(); model++ ) { out_pVecModelStrings->AddToTail( m_pAssetInfo->m_AttachedModels[model].m_pszModelName ); }
// Precache any model overrides.
if ( m_pAssetInfo->m_pszEntityModel ) { out_pVecModelStrings->AddToTail( m_pAssetInfo->m_pszEntityModel ); } if ( m_pAssetInfo->m_pszViewModel ) { out_pVecModelStrings->AddToTail( m_pAssetInfo->m_pszViewModel ); }
// Precache hero model change.
CUtlVector<AssetModifier*>* pHeroModelChanges = m_pAssetInfo->GetAssetModifiers( AM_HeroModelChange ); if ( pHeroModelChanges ) { FOR_EACH_VEC( *pHeroModelChanges, i ) { AssetModifier* pAssetMod = pHeroModelChanges->Element( i ); if ( pAssetMod ) { out_pVecModelStrings->AddToTail( pAssetMod->m_strModifier.Get() ); } } }
// Precache couriers.
pHeroModelChanges = m_pAssetInfo->GetAssetModifiers( AM_Courier ); if ( pHeroModelChanges ) { FOR_EACH_VEC( *pHeroModelChanges, i ) { AssetModifier* pAssetMod = pHeroModelChanges->Element( i ); if ( pAssetMod ) { out_pVecModelStrings->AddToTail( pAssetMod->m_strModifier.Get() ); } } }
// Precache flying couriers.
pHeroModelChanges = m_pAssetInfo->GetAssetModifiers( AM_CourierFlying ); if ( pHeroModelChanges ) { FOR_EACH_VEC( *pHeroModelChanges, i ) { AssetModifier* pAssetMod = pHeroModelChanges->Element( i ); if ( pAssetMod ) { out_pVecModelStrings->AddToTail( pAssetMod->m_strModifier.Get() ); } } } }
#ifdef DOTA_DLL
// We don't need to cache the inventory model, because it's never loaded by the game.
#else
if ( GetIconDisplayModel() ) { out_pVecModelStrings->AddToTail( GetIconDisplayModel() ); } #endif
if ( GetBuyMenuDisplayModel() ) { out_pVecModelStrings->AddToTail( GetBuyMenuDisplayModel() ); }
if ( GetWorldDroppedModel() ) { out_pVecModelStrings->AddToTail( GetWorldDroppedModel() ); }
if ( GetMagazineModel() ) { out_pVecModelStrings->AddToTail( GetMagazineModel() ); }
if ( GetScopeLensMaskModel() ) { out_pVecModelStrings->AddToTail( GetScopeLensMaskModel() ); }
const KillEaterScoreMap_t& mapKillEaterScoreTypes = GetItemSchema()->GetKillEaterScoreTypes(); FOR_EACH_MAP( mapKillEaterScoreTypes, i ) { const char *pchStatTrakModel = GetStatTrakModelByType( mapKillEaterScoreTypes[ i ].m_nValue ); if ( pchStatTrakModel ) { out_pVecModelStrings->AddToTail( pchStatTrakModel ); } }
if ( GetUidModel() ) { out_pVecModelStrings->AddToTail( GetUidModel() ); }
for ( int i=0; i<GetNumSupportedStickerSlots(); ++i ) { if ( GetStickerSlotModelBySlotIndex(i) ) { out_pVecModelStrings->AddToTail( GetStickerSlotModelBySlotIndex(i) ); } }
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconItemDefinition::GeneratePrecacheSoundStrings( CUtlVector<const char*> *out_pVecSoundStrings ) const { Assert( out_pVecSoundStrings );
// Precache all replacement sounds.
if ( m_pAssetInfo ) { for ( int sound=0; sound<m_pAssetInfo->m_Sounds.Count(); sound++ ) { out_pVecSoundStrings->AddToTail( m_pAssetInfo->m_Sounds[sound].pszReplacement ); } for ( int sound = 0; sound < ARRAYSIZE( m_pAssetInfo->m_pszWeaponSoundReplacements ); sound++ ) { if ( !m_pAssetInfo->m_pszWeaponSoundReplacements[ sound ] ) continue;
out_pVecSoundStrings->AddToTail( m_pAssetInfo->m_pszWeaponSoundReplacements[ sound ] ); } } }
void CEconItemDefinition::GeneratePrecacheEffectStrings( CUtlVector<const char*> *out_pVecEffectStrings ) const { Assert( out_pVecEffectStrings );
if ( !m_pAssetInfo ) return;
if ( m_pAssetInfo->m_pszEjectBrassEffect ) { out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszEjectBrassEffect ); } if ( m_pAssetInfo->m_pszTracerEffect ) { out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszTracerEffect ); } if ( m_pAssetInfo->m_pszMuzzleFlashEffect1stPerson ) { out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszMuzzleFlashEffect1stPerson ); } if ( m_pAssetInfo->m_pszMuzzleFlashEffect1stPersonAlt ) { out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszMuzzleFlashEffect1stPersonAlt ); } if ( m_pAssetInfo->m_pszMuzzleFlashEffect3rdPerson ) { out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszMuzzleFlashEffect3rdPerson ); } if ( m_pAssetInfo->m_pszMuzzleFlashEffect3rdPersonAlt ) { out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszMuzzleFlashEffect3rdPersonAlt ); } if ( m_pAssetInfo->m_pszHeatEffect ) { out_pVecEffectStrings->AddToTail( m_pAssetInfo->m_pszHeatEffect ); } }
#endif // #if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose: Parse the alternate icons for this item.
//-----------------------------------------------------------------------------
bool CEconItemDefinition::BInitAlternateIconsFromKV( KeyValues *pKVAlternateIcons, CEconItemSchema &pschema, AssetInfo *pVisData, CUtlVector<CUtlString> *pVecErrors ) { m_pMapAlternateIcons->Purge();
FOR_EACH_TRUE_SUBKEY( pKVAlternateIcons, pKVAlternateIcon ) { int iIconIndex = Q_atoi( pKVAlternateIcon->GetName() );
SCHEMA_INIT_CHECK( !m_pMapAlternateIcons->Find( iIconIndex ) != m_pMapAlternateIcons->InvalidIndex(), CFmtStr( "Duplicate alternate icon definition (%d)", iIconIndex ) );
SCHEMA_INIT_CHECK( iIconIndex >= 0, CFmtStr( "Alternate icon definition index %d must be greater than or equal to zero", iIconIndex ) );
m_pMapAlternateIcons->Insert( iIconIndex, pKVAlternateIcon->GetString( "icon_path" ) ); }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Parse the styles sub-section of the visuals block.
//-----------------------------------------------------------------------------
void CEconItemDefinition::BInitStylesBlockFromKV( KeyValues *pKVStyles, CEconItemSchema &pschema, AssetInfo *pVisData, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_SUBKEY( pKVStyles, pKVStyle ) { CEconStyleInfo *pStyleInfo = pschema.CreateEconStyleInfo(); Assert( pStyleInfo );
pStyleInfo->BInitFromKV( pKVStyle, pschema, pVecErrors );
pVisData->m_Styles.AddToTail( pStyleInfo ); } }
//-----------------------------------------------------------------------------
// Purpose: Parse one style from the styles block.
//-----------------------------------------------------------------------------
void CEconStyleInfo::BInitFromKV( KeyValues *pKVStyle, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors ) { enum { kInvalidSkinKey = -1, };
Assert( pKVStyle );
m_iIndex = atoi( pKVStyle->GetName() );
// A "skin" entry means "use this index for all of our teams, no matter how many we have".
int iCommonSkin = pKVStyle->GetInt( "skin", kInvalidSkinKey ); if ( iCommonSkin != kInvalidSkinKey ) { m_iSkin = iCommonSkin; }
// If we don't have a base entry, we look for a unique entry for each team. This will be
// handled in a subclass if necessary.
// Are we hiding additional bodygroups when this style is active?
KeyValues *pKVHideBodygroups = pKVStyle->FindKey( "additional_hidden_bodygroups" ); if ( pKVHideBodygroups ) { FOR_EACH_SUBKEY( pKVHideBodygroups, pKVBodygroup ) { m_vecAdditionalHideBodygroups.AddToTail( pKVBodygroup->GetName() ); } }
// Remaining common properties.
m_pszName = pKVStyle->GetString( "name", "#TF_UnknownStyle" ); m_pszBasePlayerModel = pKVStyle->GetString( "model_player", NULL );
// An alternate icon to use.
m_iIcon = pKVStyle->GetInt( "alternate_icon", 0 );
// Unlock rules.
KeyValues* pUnlockInfo = pKVStyle->FindKey( "unlock" ); if ( pUnlockInfo ) { m_UnlockInfo.iPrice = pUnlockInfo->GetInt( "price", 0 ); m_UnlockInfo.pszItemName = pUnlockInfo->GetString( "item", NULL ); m_UnlockInfo.iStylePreReq = pUnlockInfo->GetInt( "style", 0 ); m_UnlockInfo.pszAttrib = pUnlockInfo->GetString( "attribute", NULL ); m_UnlockInfo.iAttribValue = pUnlockInfo->GetInt( "attribute_value", 0 ); } }
#if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconStyleInfo::GeneratePrecacheModelStringsForStyle( CUtlVector<const char *> *out_pVecModelStrings ) const { Assert( out_pVecModelStrings );
if ( GetBasePlayerDisplayModel() != NULL ) { out_pVecModelStrings->AddToTail( GetBasePlayerDisplayModel() ); } } #endif
//-----------------------------------------------------------------------------
// Purpose: Item definition initialization helpers.
//-----------------------------------------------------------------------------
static void RecursiveInheritKeyValues( KeyValues *out_pValues, KeyValues *pInstance ) { FOR_EACH_SUBKEY( pInstance, pSubKey ) { KeyValues::types_t eType = pSubKey->GetDataType(); switch ( eType ) { case KeyValues::TYPE_STRING: out_pValues->SetString( pSubKey->GetName(), pSubKey->GetString() ); break; case KeyValues::TYPE_INT: out_pValues->SetInt( pSubKey->GetName(), pSubKey->GetInt() ); break; case KeyValues::TYPE_FLOAT: out_pValues->SetFloat( pSubKey->GetName(), pSubKey->GetFloat() ); break; case KeyValues::TYPE_WSTRING: out_pValues->SetWString( pSubKey->GetName(), pSubKey->GetWString() ); break; case KeyValues::TYPE_COLOR: out_pValues->SetColor( pSubKey->GetName(), pSubKey->GetColor() ) ; break; case KeyValues::TYPE_UINT64: out_pValues->SetUint64( pSubKey->GetName(), pSubKey->GetUint64() ) ; break;
// "NONE" means "KeyValues"
case KeyValues::TYPE_NONE: { // We may already have this part of the tree to stuff data into/overwrite, or we
// may have to make a new block.
KeyValues *pNewChild = out_pValues->FindKey( pSubKey->GetName() ); if ( !pNewChild ) { pNewChild = out_pValues->CreateNewKey(); pNewChild->SetName( pSubKey->GetName() ); }
RecursiveInheritKeyValues( pNewChild, pSubKey ); break; }
case KeyValues::TYPE_PTR: default: Assert( !"Unhandled data type for KeyValues inheritance!" ); break; } } }
#ifdef _DEBUG
#define DEBUG_SCHEMA_WRITE_TMP_FILE 0
#if DEBUG_SCHEMA_WRITE_TMP_FILE
#include <stdio.h>
class CKeyValuesDumpContextAsSchemaFile : public IKeyValuesDumpContextAsText { public: // Overrides developer level to dump in DevMsg, zero to dump as Msg
CKeyValuesDumpContextAsSchemaFile() {}
public: virtual bool KvWriteText( char const *szText ) { FILE *f = NULL; fopen_s( &f, "c:/tmp/econ_item_schema.txt", "a+t" ); if ( f ) { fprintf( f, "%s", szText ); fclose( f ); } return true; } } g_schemadbg; #endif
#endif
// Always returns a newly allocated copy of KeyValues
// Applies prefabs supporting multiple inheritance from Right-to-Left (RTL)
// this way "prefab" "valve tournament p250" will start with "p250" then apply "tournament" prefab on top of that,
// then will apply "valve" prefab on top of that and then the values of the actual instance.
static KeyValues *InheritKeyValuesRTLMulti( KeyValues *pInstance, CEconItemSchema &pschema ) { Assert( pInstance ); KeyValues *pFinalValues = pInstance->MakeCopy();
#if DEBUG_SCHEMA_WRITE_TMP_FILE
static int s_nDebugIndentLevel = 0; #endif
CUtlVector< char * > arrPrefabs; if ( const char *svPrefabName = pFinalValues->GetString( "prefab", NULL ) ) { Q_SplitString( svPrefabName, " ", arrPrefabs );
#if DEBUG_SCHEMA_WRITE_TMP_FILE
if ( arrPrefabs.Count() ) { ++ s_nDebugIndentLevel; g_schemadbg.KvWriteIndent( s_nDebugIndentLevel ); g_schemadbg.KvWriteText( CFmtStr( "Expanding data with %d prefabs:--\n", arrPrefabs.Count() ) ); pFinalValues->Dump( &g_schemadbg, s_nDebugIndentLevel ); g_schemadbg.KvWriteIndent( s_nDebugIndentLevel ); g_schemadbg.KvWriteText( "--\n" ); } #endif
} FOR_EACH_VEC_BACK( arrPrefabs, i ) { KeyValues *pKVPrefab = pschema.FindDefinitionPrefabByName( arrPrefabs[i] ); if ( !pKVPrefab ) continue; #if DEBUG_SCHEMA_WRITE_TMP_FILE
{ g_schemadbg.KvWriteIndent( s_nDebugIndentLevel ); g_schemadbg.KvWriteText( CFmtStr( "Appending prefab '%s':\n", arrPrefabs[i] ) ); pKVPrefab->Dump( &g_schemadbg, s_nDebugIndentLevel ); } #endif
pKVPrefab = InheritKeyValuesRTLMulti( pKVPrefab, pschema ); pKVPrefab->SetName( pFinalValues->GetName() );
RecursiveInheritKeyValues( pKVPrefab, pFinalValues ); pFinalValues->deleteThis(); pFinalValues = pKVPrefab;
#if DEBUG_SCHEMA_WRITE_TMP_FILE
{ g_schemadbg.KvWriteIndent( s_nDebugIndentLevel ); g_schemadbg.KvWriteText( CFmtStr( "After appending prefab '%s':\n", arrPrefabs[ i ] ) ); pFinalValues->Dump( &g_schemadbg, s_nDebugIndentLevel ); } #endif
}
#if DEBUG_SCHEMA_WRITE_TMP_FILE
if ( arrPrefabs.Count() ) { g_schemadbg.KvWriteIndent( s_nDebugIndentLevel ); g_schemadbg.KvWriteText( CFmtStr( "Finished expanding data with %d prefabs:--\n", arrPrefabs.Count() ) ); pFinalValues->Dump( &g_schemadbg, s_nDebugIndentLevel ); g_schemadbg.KvWriteIndent( s_nDebugIndentLevel ); g_schemadbg.KvWriteText( "--\n" );
-- s_nDebugIndentLevel; } #endif
arrPrefabs.PurgeAndDeleteElements();
return pFinalValues; }
KeyValues *CEconItemSchema::FindDefinitionPrefabByName( const char *pszPrefabName ) const { int iIndex = m_mapDefinitionPrefabs.Find( pszPrefabName ); if ( m_mapDefinitionPrefabs.IsValidIndex( iIndex ) ) return m_mapDefinitionPrefabs[iIndex];
return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Initialize the item definition
// Input: pKVItem - The KeyValues representation of the item
// schema - The overall item schema for this item
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemDefinition::BInitFromKV( KeyValues *pKVItem, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { // Set standard members
m_pKVItem = InheritKeyValuesRTLMulti( pKVItem, pschema ); m_bEnabled = m_pKVItem->GetBool( "enabled" ); m_bLoadOnDemand = m_pKVItem->GetBool( "loadondemand" ); m_nDefIndex = Q_atoi( m_pKVItem->GetName() ); m_unMinItemLevel = (uint32)m_pKVItem->GetInt( "min_ilevel", pschema.GetMinLevel() ); m_unMaxItemLevel = (uint32)m_pKVItem->GetInt( "max_ilevel", pschema.GetMaxLevel() ); m_nDefaultDropQuantity = m_pKVItem->GetInt( "default_drop_quantity", 1 );
KeyValues *pKVMultiAssocItems = m_pKVItem->FindKey( "associated_items" ), *pKVSingleAssocItem = m_pKVItem->FindKey( "associated_item" );
// Maybe we have multiple entries?
if ( pKVMultiAssocItems ) { for ( KeyValues *pKVAssocItem = pKVMultiAssocItems->GetFirstSubKey(); pKVAssocItem; pKVAssocItem = pKVAssocItem->GetNextKey() ) { m_nAssociatedItemsDefIndexes.AddToTail( atoi( pKVAssocItem->GetName() ) ); } } // This is our one-and-only-one associated item
else if ( pKVSingleAssocItem ) { const char *pAssocItem = pKVSingleAssocItem->GetString( (const char *)NULL, NULL ); if ( pAssocItem ) { m_nAssociatedItemsDefIndexes.AddToTail( atoi( pAssocItem ) ); } }
m_nSoundMaterialID = m_pKVItem->GetInt( "sound_material" );
m_nPopularitySeed = m_pKVItem->GetInt( "popularity_seed", 0 );
// initializing this one first so that it will be available for all the errors below
m_pszDefinitionName = m_pKVItem->GetString( "name", NULL );
m_bDisableStyleSelection = m_pKVItem->GetBool( "disable_style_selector", false ); #if defined(CLIENT_DLL) || defined(GAME_DLL)
// We read this manually here in the game dlls. The GC reads it below while checking pschema.
pschema.BGetItemQualityFromName( m_pKVItem->GetString( "item_quality" ), &m_nItemQuality ); pschema.BGetItemQualityFromName( m_pKVItem->GetString( "forced_item_quality" ), &m_nForcedItemQuality ); pschema.BGetItemQualityFromName( m_pKVItem->GetString( "default_drop_quality" ), &m_nDefaultDropItemQuality );
pschema.BGetItemRarityFromName( m_pKVItem->GetString( "item_rarity" ), &m_nItemRarity ); #endif
// Check for required fields
SCHEMA_INIT_CHECK( NULL != m_pKVItem->FindKey( "name" ), CFmtStr( "Item definition %s: Missing required field \"name\"", m_pKVItem->GetName() ) );
SCHEMA_INIT_CHECK( NULL != m_pKVItem->FindKey( "item_class" ), CFmtStr( "Item definition %s: Missing required field \"item_class\"", m_pKVItem->GetName() ) );
// Check value ranges
SCHEMA_INIT_CHECK( m_pKVItem->GetInt( "min_ilevel" ) >= 0, CFmtStr( "Item definition %s: \"min_ilevel\" must be greater than or equal to 0", GetDefinitionName() ) );
SCHEMA_INIT_CHECK( m_pKVItem->GetInt( "max_ilevel" ) >= 0, CFmtStr( "Item definition %s: \"max_ilevel\" must be greater than or equal to 0", GetDefinitionName() ) );
// Get the item class
m_pszItemClassname = m_pKVItem->GetString( "item_class", NULL );
m_bAllowPurchaseStandalone = m_pKVItem->GetBool( "allow_purchase_standalone", false );
m_pszClassToken = m_pKVItem->GetString( "class_token_id", NULL ); m_pszSlotToken = m_pKVItem->GetString( "slot_token_id", NULL );
m_bPublicItem = m_pKVItem->GetInt( "developer" ) == 0; m_bIgnoreInCollectionView = m_pKVItem->GetBool( "ignore_in_collection_view", false );
// Display data
m_pszItemBaseName = m_pKVItem->GetString( "item_name", "" ); // non-NULL to ensure we can sort
m_pszItemTypeName = m_pKVItem->GetString( "item_type_name", "" ); // non-NULL to ensure we can sort
m_pszItemDesc = m_pKVItem->GetString( "item_description", NULL ); m_pszArmoryDesc = m_pKVItem->GetString( "armory_desc", NULL ); m_pszInventoryModel = m_pKVItem->GetString( "model_inventory", NULL ); m_pszInventoryImage = m_pKVItem->GetString( "image_inventory", NULL );
m_pPortraitsKV = m_pKVItem->FindKey( "portraits" );
m_unItemTypeID = CRC32_ProcessSingleBuffer( m_pszItemTypeName, V_strlen( m_pszItemTypeName ) ); const char* pOverlay = m_pKVItem->GetString( "image_inventory_overlay", NULL ); if ( pOverlay ) { m_pszInventoryOverlayImages.AddToTail( pOverlay ); } pOverlay = m_pKVItem->GetString( "image_inventory_overlay2", NULL ); if ( pOverlay ) { m_pszInventoryOverlayImages.AddToTail( pOverlay ); }
m_iInventoryImagePosition[0] = m_pKVItem->GetInt( "image_inventory_pos_x", 0 ); m_iInventoryImagePosition[1] = m_pKVItem->GetInt( "image_inventory_pos_y", 0 ); m_iInventoryImageSize[0] = m_pKVItem->GetInt( "image_inventory_size_w", 0 ); m_iInventoryImageSize[1] = m_pKVItem->GetInt( "image_inventory_size_h", 0 ); m_pszHolidayRestriction = m_pKVItem->GetString( "holiday_restriction", NULL ); m_iSubType = m_pKVItem->GetInt( "subtype", 0 ); m_pszBaseDisplayModel = m_pKVItem->GetString( "model_player", NULL ); m_pszWorldDisplayModel = m_pKVItem->GetString( "model_world", NULL ); // Not the ideal method. c_models are better, but this is to solve a retrofit problem with the sticky launcher.
m_pszWorldDroppedModel = m_pKVItem->GetString( "model_dropped", NULL );
//build the world dropped model string by appending "_dropped"
if ( ( m_pszWorldDroppedModel == NULL ) && ( m_pszWorldDisplayModel != NULL ) ) { V_StripExtension( m_pszWorldDisplayModel, m_szWorldDroppedModel, sizeof( m_szWorldDroppedModel ) ); V_strcat_safe( m_szWorldDroppedModel, "_dropped.mdl" ); m_pszWorldDroppedModel = m_szWorldDroppedModel; } // Add new StatTrak modules here.
m_pszIconDefaultImage = m_pKVItem->GetString( "icon_default_image", NULL ); m_pszWorldExtraWearableModel = m_pKVItem->GetString( "extra_wearable", NULL ); m_pszBrassModelOverride = m_pKVItem->GetString( "brass_eject_model", NULL ); m_pszWorldExtraWearableModel = m_pKVItem->GetString( "extra_wearable", NULL ); m_pszBrassModelOverride = m_pKVItem->GetString( "brass_eject_model", NULL ); m_bHideBodyGroupsDeployedOnly = m_pKVItem->GetBool( "hide_bodygroups_deployed_only" ); m_bAttachToHands = m_pKVItem->GetInt( "attach_to_hands", 0 ) != 0; m_bAttachToHandsVMOnly = m_pKVItem->GetInt( "attach_to_hands_vm_only", 0 ) != 0; m_bProperName = m_pKVItem->GetInt( "propername", 0 ) != 0; m_bFlipViewModel = m_pKVItem->GetInt( "flip_viewmodel", 0 ) != 0; m_bActAsWearable = m_pKVItem->GetInt( "act_as_wearable", 0 ) != 0; m_iDropType = StringFieldToInt( m_pKVItem->GetString("drop_type"), g_szDropTypeStrings, ARRAYSIZE(g_szDropTypeStrings) );
// Creation data
m_bHidden = m_pKVItem->GetInt( "hidden", 0 ) != 0; m_bShouldShowInArmory = m_pKVItem->GetInt( "show_in_armory", 0 ) != 0; m_bBaseItem = m_pKVItem->GetInt( "baseitem", 0 ) != 0; m_bDefaultSlotItem = m_pKVItem->GetInt( "default_slot_item", 0 ) != 0; m_pszItemLogClassname = m_pKVItem->GetString( "item_logname", NULL ); m_pszItemIconClassname = m_pKVItem->GetString( "item_iconname", NULL ); #if ECONITEM_DATABASE_AUDIT_TABLES_FEATURE
m_pszDatabaseAuditTable = m_pKVItem->GetString( "database_audit_table", NULL ); #endif
m_bImported = m_pKVItem->FindKey( "import_from" ) != NULL; m_bOnePerAccountCDKEY = m_pKVItem->GetInt( "one_per_account_cdkey", 0 ) != 0;
m_pszParticleFile = m_pKVItem->GetString( "particle_file", NULL ); m_pszParticleSnapshotFile = m_pKVItem->GetString( "particle_snapshot", NULL );
m_pszLootListName = m_pKVItem->GetString( "loot_list_name", NULL );
// Stickers
KeyValues *pStickerDataKV = m_pKVItem->FindKey( "stickers" ); if ( pStickerDataKV ) { FOR_EACH_SUBKEY( pStickerDataKV, pStickerModelEntry ) {
StickerData_t *pStickerData = &m_vStickerModels[ m_vStickerModels.AddToTail() ]; const char *pStickerModelPath = pStickerModelEntry->GetString( "viewmodel_geometry" ); V_strcpy_safe( pStickerData->m_szStickerModelPath, pStickerModelPath );
const char *pStickerMaterialPath = pStickerModelEntry->GetString( "viewmodel_material" ); V_strcpy_safe( pStickerData->m_szStickerMaterialPath, pStickerMaterialPath );
const char *pStickerWorldModelProjectionPosition = pStickerModelEntry->GetString( "worldmodel_decal_pos" ); if ( pStickerWorldModelProjectionPosition[0] != 0 ) { float flX = 0.0f, flY = 0.0f, flZ = 0.0f; sscanf( pStickerWorldModelProjectionPosition, "%f %f %f", &flX, &flY, &flZ ); pStickerData->m_vWorldModelProjectionStart = Vector( flX, flY, flZ ); }
const char *pStickerWorldModelProjectionEnd = pStickerModelEntry->GetString( "worldmodel_decal_end" ); if ( pStickerWorldModelProjectionEnd[0] != 0 ) { float flX = 0.0f, flY = 0.0f, flZ = 0.0f; sscanf( pStickerWorldModelProjectionEnd, "%f %f %f", &flX, &flY, &flZ ); pStickerData->m_vWorldModelProjectionEnd = Vector( flX, flY, flZ ); } else { pStickerData->m_vWorldModelProjectionEnd = Vector(-10,0,0) + pStickerData->m_vWorldModelProjectionStart; }
V_strcpy_safe( pStickerData->m_szStickerBoneParentName, pStickerModelEntry->GetString( "worldmodel_decal_bone", "ValveBiped.weapon_bone" ) );
} }
// Tool data
m_pTool = NULL; KeyValues *pToolDataKV = m_pKVItem->FindKey( "tool" ); if ( pToolDataKV ) { const char *pszType = pToolDataKV->GetString( "type", NULL ); SCHEMA_INIT_CHECK( pszType, CFmtStr( "Tool '%s' missing required type.", m_pKVItem->GetName() ) );
// Common-to-all-tools settings.
const char *pszUseString = pToolDataKV->GetString( "use_string", NULL ); const char *pszUsageRestriction = pToolDataKV->GetString( "restriction", NULL ); KeyValues *pToolUsageKV = pToolDataKV->FindKey( "usage" );
// Common-to-all-tools usage capability flags.
item_capabilities_t usageCapabilities = (item_capabilities_t)ITEM_CAP_TOOL_DEFAULT; KeyValues *pToolUsageCapsKV = pToolDataKV->FindKey( "usage_capabilities" ); if ( pToolUsageCapsKV ) { KeyValues *pEntry = pToolUsageCapsKV->GetFirstSubKey(); while ( pEntry ) { ParseCapability( usageCapabilities, pEntry ); pEntry = pEntry->GetNextKey(); } }
m_pTool = pschema.CreateEconToolImpl( pszType, pszUseString, pszUsageRestriction, usageCapabilities, pToolUsageKV ); SCHEMA_INIT_CHECK( m_pTool, CFmtStr( "Unable to create tool implementation for '%s', of type '%s'.", m_pKVItem->GetName(), pszType ) ); }
// capabilities
m_iCapabilities = (item_capabilities_t)ITEM_CAP_DEFAULT; KeyValues *pCapsKV = m_pKVItem->FindKey( "capabilities" ); if ( pCapsKV ) { KeyValues *pEntry = pCapsKV->GetFirstSubKey(); while ( pEntry ) { ParseCapability( m_iCapabilities, pEntry ); pEntry = pEntry->GetNextKey(); } }
// cache item map names
m_pszArmoryRemap = m_pKVItem->GetString( "armory_remap", NULL ); m_pszStoreRemap = m_pKVItem->GetString( "store_remap", NULL );
// Don't bother parsing visual data on the GC, it's unused.
BInitVisualBlockFromKV( m_pKVItem, pschema, pVecErrors );
// Calculate our equip region mask.
{ m_unEquipRegionMask = 0; m_unEquipRegionConflictMask = 0;
// Our equip region will come from one of two places -- either we have an "equip_regions" (plural) section,
// in which case we have any number of regions specified; or we have an "equip_region" (singular) section
// which will have one and exactly one region. If we have "equip_regions" (plural), we ignore whatever is
// in "equip_region" (singular).
//
// Yes, this is sort of dumb.
CUtlVector<const char *> vecEquipRegionNames;
KeyValues *pKVMultiEquipRegions = m_pKVItem->FindKey( "equip_regions" ), *pKVSingleEquipRegion = m_pKVItem->FindKey( "equip_region" );
// Maybe we have multiple entries?
if ( pKVMultiEquipRegions ) { for ( KeyValues *pKVRegion = pKVMultiEquipRegions->GetFirstSubKey(); pKVRegion; pKVRegion = pKVRegion->GetNextKey() ) { vecEquipRegionNames.AddToTail( pKVRegion->GetName() ); } } // This is our one-and-only-one equip region.
else if ( pKVSingleEquipRegion ) { const char *pEquipRegionName = pKVSingleEquipRegion->GetString( (const char *)NULL, NULL ); if ( pEquipRegionName ) { vecEquipRegionNames.AddToTail( pEquipRegionName ); } }
// For each of our regions, add to our conflict mask both ourself and all the regions
// that we conflict with.
FOR_EACH_VEC( vecEquipRegionNames, i ) { const char *pszEquipRegionName = vecEquipRegionNames[i]; equip_region_mask_t unThisRegionMask = pschema.GetEquipRegionMaskByName( pszEquipRegionName );
SCHEMA_INIT_CHECK( unThisRegionMask != 0, CFmtStr( "Item definition %s: Unable to find equip region mask for region named \"%s\"", GetDefinitionName(), vecEquipRegionNames[i] ) );
m_unEquipRegionMask |= pschema.GetEquipRegionBitMaskByName( pszEquipRegionName ); m_unEquipRegionConflictMask |= unThisRegionMask; } }
// Parse the static attributes for this definition
char const *szStaticAttributesSubkeyNames[] = { "attributes" }; for ( int iStaticAttrGroup = 0; iStaticAttrGroup < Q_ARRAYSIZE( szStaticAttributesSubkeyNames ); ++ iStaticAttrGroup ) { KeyValues *kvStaticAttrGroup = m_pKVItem->FindKey( szStaticAttributesSubkeyNames[iStaticAttrGroup] ); if ( !kvStaticAttrGroup ) continue; FOR_EACH_SUBKEY( kvStaticAttrGroup, pKVKey ) { static_attrib_t staticAttrib;
SCHEMA_INIT_SUBSTEP( staticAttrib.BInitFromKV_SingleLine( GetDefinitionName(), pKVKey, pVecErrors ) );
m_vecStaticAttributes.AddToTail( staticAttrib ); } }
return SCHEMA_INIT_SUCCESS(); }
bool static_attrib_t::BInitFromKV_MultiLine( const char *pszContext, KeyValues *pKVAttribute, CUtlVector<CUtlString> *pVecErrors ) { const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinitionByName( pKVAttribute->GetName() );
SCHEMA_INIT_CHECK( NULL != pAttrDef, CFmtStr( "Context '%s': Attribute \"%s\" in \"attributes\" did not match any attribute definitions", pszContext, pKVAttribute->GetName() ) );
if ( pAttrDef ) { const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType(); Assert( pAttrType );
iDefIndex = pAttrDef->GetDefinitionIndex();
const char *pszValue = pKVAttribute->GetString( "value", NULL ); const bool bSuccessfullyLoadedValue = pAttrType->BConvertStringToEconAttributeValue( pAttrDef, pszValue, &m_value );
SCHEMA_INIT_CHECK( bSuccessfullyLoadedValue, CFmtStr( "Context '%s': Attribute \"%s\" could not parse value \"%s\"!", pszContext, pKVAttribute->GetName(), pszValue ? pszValue : "(null)" ) );
m_bForceGCToGenerate = pKVAttribute->GetBool( "force_gc_to_generate" ); }
return SCHEMA_INIT_SUCCESS(); }
bool static_attrib_t::BInitFromKV_SingleLine( const char *pszContext, KeyValues *pKVAttribute, CUtlVector<CUtlString> *pVecErrors ) { if ( pKVAttribute->GetFirstSubKey() ) { return BInitFromKV_MultiLine( pszContext, pKVAttribute, pVecErrors ); }
const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinitionByName( pKVAttribute->GetName() );
SCHEMA_INIT_CHECK( NULL != pAttrDef, CFmtStr( "Context '%s': Attribute \"%s\" in \"attributes\" did not match any attribute definitions", pszContext, pKVAttribute->GetName() ) );
if ( pAttrDef ) { const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType(); Assert( pAttrType );
iDefIndex = pAttrDef->GetDefinitionIndex();
const char *pszValue = pKVAttribute->GetString(); const bool bSuccessfullyLoadedValue = pAttrType->BConvertStringToEconAttributeValue( pAttrDef, pszValue, &m_value );
SCHEMA_INIT_CHECK( bSuccessfullyLoadedValue, CFmtStr( "Context '%s': Attribute \"%s\" could not parse value \"%s\"!", pszContext, pKVAttribute->GetName(), pszValue ? pszValue : "(null)" ) );
m_bForceGCToGenerate = false; }
return SCHEMA_INIT_SUCCESS(); }
bool CEconItemDefinition::BInitItemMappings( CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors ) { // Armory remapping
if ( m_pszArmoryRemap && m_pszArmoryRemap[0] ) { const CEconItemDefinition *pDef = pschema.GetItemDefinitionByName( m_pszArmoryRemap ); if ( pDef ) { m_iArmoryRemap = pDef->GetDefinitionIndex(); }
SCHEMA_INIT_CHECK( pDef != NULL, CFmtStr( "Item %s: Armory remap definition \"%s\" was not found", m_pszItemBaseName, m_pszArmoryRemap ) ); }
// Store remapping
if ( m_pszStoreRemap && m_pszStoreRemap[0] ) { const CEconItemDefinition *pDef = pschema.GetItemDefinitionByName( m_pszStoreRemap ); if ( pDef ) { m_iStoreRemap = pDef->GetDefinitionIndex(); }
SCHEMA_INIT_CHECK( pDef != NULL, CFmtStr( "Item %s: Store remap definition \"%s\" was not found", m_pszItemBaseName, m_pszStoreRemap ) ); }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
KeyValues* CEconItemDefinition::GetPortraitKVForModel( const char* pszModelName ) const { if ( !m_pPortraitsKV ) return NULL; return m_pPortraitsKV->FindKey( pszModelName ); }
void CEconItemDefinition::AddItemSet( int nIndex ) { if ( m_iItemSets.Find( nIndex ) != m_iItemSets.InvalidIndex() ) return;
m_iItemSets.AddToTail( nIndex ); }
const CUtlVector< int >& CEconItemDefinition::GetItemSets( void ) const { return m_iItemSets; }
#if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
attachedparticlesystem_t *CEconItemDefinition::GetAttachedParticleData( int iIdx ) const { if ( !GetAssetInfo() ) return NULL;
Assert( iIdx < GetAssetInfo()->m_AttachedParticles.Count() ); if ( iIdx >= GetAssetInfo()->m_AttachedParticles.Count() ) return NULL;
int iParticleIndex = GetAssetInfo()->m_AttachedParticles[iIdx].m_iParticleIndex; return ItemSystem()->GetItemSchema()->GetAttributeControlledParticleSystemByIndex( iParticleIndex ); }
bool CEconItemDefinition::IsAttachedParticleDataValidForStyle( int iIdx, int nStyle ) const { Assert( iIdx < GetAssetInfo()->m_AttachedParticles.Count() ); if ( iIdx >= GetAssetInfo()->m_AttachedParticles.Count() ) return false;
return ( GetAssetInfo()->m_AttachedParticles[iIdx].m_nStyle == nStyle ); }
#endif // #if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose: Generate and return a random level according to whatever leveling
// curve this definition uses.
//-----------------------------------------------------------------------------
uint32 CEconItemDefinition::RollItemLevel( void ) const { return RandomInt( GetMinLevel(), GetMaxLevel() ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconItemDefinition::IterateAttributes( IEconItemAttributeIterator *pIterator ) const { FOR_EACH_VEC( GetStaticAttributes(), i ) { const static_attrib_t& staticAttrib = GetStaticAttributes()[i]; // we skip over static attributes that the GC will turn into dynamic attributes because otherwise we'll have
// the appearance of iterating over them twice; for clients these attributes won't even make it into the
// list
if ( staticAttrib.m_bForceGCToGenerate ) continue;
const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( staticAttrib.iDefIndex ); if ( !pAttrDef ) continue;
const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType(); Assert( pAttrType );
if ( !pAttrType->OnIterateAttributeValue( pIterator, pAttrDef, staticAttrib.m_value ) ) return; } }
const char *CEconItemDefinition::GetFirstSaleDate() const { return GetRawDefinition()->GetString( "first_sale_date", "1970/01/01" ); }
#if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
Activity CEconItemDefinition::GetActivityOverride( Activity baseAct ) const { int iAnims = GetNumAnimations(); for ( int i = 0; i < iAnims; i++ ) { animation_on_wearable_t *pData = GetAnimationData( i ); if ( !pData ) continue; if ( pData->iActivity == kActivityLookup_Unknown ) { pData->iActivity = ActivityList_IndexForName( pData->pszActivity ); }
if ( pData->iActivity == baseAct ) { if ( pData->iReplacement == kActivityLookup_Unknown ) { pData->iReplacement = ActivityList_IndexForName( pData->pszReplacement ); }
if ( pData->iReplacement > 0 ) { return (Activity) pData->iReplacement; } } }
return baseAct; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *CEconItemDefinition::GetReplacementForActivityOverride( Activity baseAct ) const { int iAnims = GetNumAnimations(); for ( int i = 0; i < iAnims; i++ ) { animation_on_wearable_t *pData = GetAnimationData( i ); if ( pData->iActivity == kActivityLookup_Unknown ) { pData->iActivity = ActivityList_IndexForName( pData->pszActivity ); } if ( pData && pData->iActivity == baseAct ) { if ( CEconItemSchema::GetRandomStream().RandomFloat() < pData->flFrequency ) return pData->pszReplacement; } }
return NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *CEconItemDefinition::GetReplacementSound( const char* pszSoundName ) const { int iSounds = GetNumSounds(); for ( int i=0; i<iSounds; i++ ) { sound_on_wearable_t *pData = GetSoundData( i ); if ( pData && FStrEq( pData->pszSound, pszSoundName ) ) return pData->pszReplacement; }
return NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *CEconItemDefinition::GetReplacementParticleEffect( const char* pszParticleName ) const { int iParticles = GetNumParticles(); for ( int i=0; i<iParticles; i++ ) { particle_on_wearable_t *pData = GetParticleData( i ); if ( pData && FStrEq( pData->pszParticle, pszParticleName ) ) return pData->pszReplacement; }
return NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *CEconItemDefinition::GetReplacementParticleSnapshot( const char* pszParticleSnapshotName ) const { int iSnapshots = GetNumParticleSnapshots(); for ( int i=0; i<iSnapshots; i++ ) { particlesnapshot_on_wearable_t *pData = GetParticleSnapshotData( i ); if ( pData && FStrEq( pData->pszParticleSnapshot, pszParticleSnapshotName ) ) return pData->pszReplacement; }
return NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconItemDefinition::GetReplacementControlPoint( int nIndex, const char* pszParticleName, int &nOutputCP, Vector &vecCPValue ) const { int iParticles = GetNumParticleControlPoints(); if ( nIndex < iParticles ) { particle_control_point_on_wearable_t *pData = GetParticleControlPointData( nIndex ); if ( pData && FStrEq( pData->pszParticle, pszParticleName ) ) { nOutputCP = pData->nParticleControlPoint; vecCPValue = pData->vecCPValue; return true; } } return false; }
//-----------------------------------------------------------------------------
// Purpose: Returns true if the content for this item view should be streamed. If false,
// it should be preloaded.
//-----------------------------------------------------------------------------
// DO NOT MERGE THIS CONSOLE VARIABLE TO REL WE SHOULD NOT SHIP THIS OH GOD
#define ITEM_ENABLE_DYNAMIC_LOADING true
//ConVar item_enable_dynamic_loading( "item_enable_dynamic_loading", "1", FCVAR_REPLICATED, "Enable/disable dynamic streaming of econ content." );
bool CEconItemDefinition::IsContentStreamable() const { if ( !BLoadOnDemand() ) return false;
return ITEM_ENABLE_DYNAMIC_LOADING; } #endif // defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char* CEconItemDefinition::GetAlternateIcon( int iAlternateIcon ) const { int iIdx = m_pMapAlternateIcons->Find( iAlternateIcon ); if ( !m_pMapAlternateIcons->IsValidIndex( iIdx ) ) return NULL; else return m_pMapAlternateIcons->Element( iIdx ); } //-----------------------------------------------------------------------------
// Purpose:
// Sticker model paths
//-----------------------------------------------------------------------------
const int CEconItemDefinition::GetNumSupportedStickerSlots() const { return m_vStickerModels.Count(); } const char *CEconItemDefinition::GetStickerSlotModelBySlotIndex( uint32 index ) const { return m_vStickerModels[index].m_szStickerModelPath; } const Vector &CEconItemDefinition::GetStickerSlotWorldProjectionStartBySlotIndex( uint32 index ) const { return m_vStickerModels[index].m_vWorldModelProjectionStart; } const Vector &CEconItemDefinition::GetStickerSlotWorldProjectionEndBySlotIndex( uint32 index ) const { return m_vStickerModels[index].m_vWorldModelProjectionEnd; } const char *CEconItemDefinition::GetStickerWorldModelBoneParentNameBySlotIndex( uint32 index ) const { return m_vStickerModels[index].m_szStickerBoneParentName; } const char *CEconItemDefinition::GetStickerSlotMaterialBySlotIndex( uint32 index ) const { return m_vStickerModels[index].m_szStickerMaterialPath; }
RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetIconDisplayModel, "icon display model", m_pszWorldDisplayModel ); RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetBuyMenuDisplayModel, "buymenu display model", m_pszWorldDisplayModel ); RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetPedestalDisplayModel, "pedestal display model", m_pszBaseDisplayModel ); RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetMagazineModel, "magazine model", NULL ); RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetUidModel, "uid model", "models/weapons/uid.mdl" ); RETURN_ATTRIBUTE_STRING_F( CEconItemDefinition::GetScopeLensMaskModel, "aimsight lens mask", NULL );
const char *CEconItemDefinition::GetStatTrakModelByType( uint32 nType ) const { const kill_eater_score_type_t *pScoreType = GetItemSchema()->FindKillEaterScoreType( nType ); if ( !pScoreType ) { pScoreType = GetItemSchema()->FindKillEaterScoreType( 0 ); }
if ( !pScoreType ) return NULL;
CSchemaAttributeDefHandle pAttrib_StatTrakModel( pScoreType->m_pszModelAttributeString ); const char *pchStatTrakModel = NULL; FindAttribute_UnsafeBitwiseCast< CAttribute_String >( this, pAttrib_StatTrakModel, &pchStatTrakModel );
return pchStatTrakModel; }
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CTimedItemRewardDefinition::CTimedItemRewardDefinition( void ) : m_unMinFreq( 0 ), m_unMaxFreq( UINT_MAX ), m_rtForcedBaselineAdjustment( 0 ), m_rtForcedLastDropTimeAdjustment( 0 ), m_unHoursInRewardPeriod( 0 ), m_unHoursBetweenDropsRealtime( 0 ), m_unPointsPerHourOverplayed( 0 ), m_flChance( 0.0f ) { }
//-----------------------------------------------------------------------------
// Purpose: Copy constructor
//-----------------------------------------------------------------------------
CTimedItemRewardDefinition::CTimedItemRewardDefinition( const CTimedItemRewardDefinition &that ) { (*this) = that; }
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CTimedItemRewardDefinition &CTimedItemRewardDefinition::operator=( const CTimedItemRewardDefinition &rhs ) { m_unMinFreq = rhs.m_unMinFreq; m_unMaxFreq = rhs.m_unMaxFreq; m_rtForcedBaselineAdjustment = rhs.m_rtForcedBaselineAdjustment; m_rtForcedLastDropTimeAdjustment = rhs.m_rtForcedLastDropTimeAdjustment; m_unHoursInRewardPeriod = rhs.m_unHoursInRewardPeriod; m_unHoursBetweenDropsRealtime = rhs.m_unHoursBetweenDropsRealtime; m_unPointsPerHourOverplayed = rhs.m_unPointsPerHourOverplayed; m_arrTotalPointsBasedOnHoursPlayed.RemoveAll(); m_arrTotalPointsBasedOnHoursPlayed.EnsureCapacity( rhs.m_arrTotalPointsBasedOnHoursPlayed.Count() ); m_arrTotalPointsBasedOnHoursPlayed.AddMultipleToTail( rhs.m_arrTotalPointsBasedOnHoursPlayed.Count(), rhs.m_arrTotalPointsBasedOnHoursPlayed.Base() ); m_criteria = rhs.m_criteria; m_arrLootLists.CopyArray( rhs.m_arrLootLists.Base(), rhs.m_arrLootLists.Count() ); m_flChance = rhs.m_flChance;
return *this; }
CTimedItemRewardDefinition::~CTimedItemRewardDefinition() { m_arrDynamicLootLists.PurgeAndDeleteElements(); }
//-----------------------------------------------------------------------------
// Purpose: Initialize the attribute definition
// Input: pKVTimedReward - The KeyValues representation of the timed reward
// schema - The overall item schema
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CTimedItemRewardDefinition::BInitFromKV( KeyValues *pKVTimedReward, CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { // Parse the basic values
m_flChance = pKVTimedReward->GetFloat( "pctChance" ); #ifdef DOTA_DLL
m_unMinFreq = pKVTimedReward->GetInt( "value_min", 0 ); m_unMaxFreq = pKVTimedReward->GetInt( "value_max", UINT_MAX );
// Check required fields
SCHEMA_INIT_CHECK( NULL != pKVTimedReward->FindKey( "value_min" ), CFmtStr( "Time reward %s: Missing required field \"value_min\"", pKVTimedReward->GetName() ) ); SCHEMA_INIT_CHECK( NULL != pKVTimedReward->FindKey( "value_max" ), CFmtStr( "Time reward %s: Missing required field \"value_max\"", pKVTimedReward->GetName() ) ); #endif
//
// Parse the basic values
//
SCHEMA_INIT_CHECK( NULL != pKVTimedReward->FindKey( "force_baseline_timestamp" ), CFmtStr( "Time reward %s: Missing required field \"force_baseline_timestamp\"", pKVTimedReward->GetName() ) ); m_rtForcedBaselineAdjustment = pKVTimedReward->GetInt( "force_baseline_timestamp" );
m_rtForcedLastDropTimeAdjustment = 0; if ( pKVTimedReward->FindKey( "force_lastdrop_timestamp" ) ) m_rtForcedLastDropTimeAdjustment = pKVTimedReward->GetInt( "force_lastdrop_timestamp" ); m_unHoursInRewardPeriod = pKVTimedReward->GetInt( "period_hours", 0 ); SCHEMA_INIT_CHECK( NULL != pKVTimedReward->FindKey( "period_hours" ), CFmtStr( "Time reward %s: Missing required field \"period_hours\"", pKVTimedReward->GetName() ) ); SCHEMA_INIT_CHECK( m_unHoursInRewardPeriod > 0, CFmtStr( "Time reward %s: Required field \"period_hours\" has invalid value", pKVTimedReward->GetName() ) );
m_unHoursBetweenDropsRealtime = pKVTimedReward->GetInt( "drop_interval_hours", 0 ); SCHEMA_INIT_CHECK( NULL != pKVTimedReward->FindKey( "drop_interval_hours" ), CFmtStr( "Time reward %s: Missing required field \"drop_interval_hours\"", pKVTimedReward->GetName() ) ); SCHEMA_INIT_CHECK( m_unHoursBetweenDropsRealtime >= 0, CFmtStr( "Time reward %s: Required field \"drop_interval_hours\" has invalid value", pKVTimedReward->GetName() ) );
SCHEMA_INIT_CHECK( NULL != pKVTimedReward->FindKey( "points_progression_hourly" ), CFmtStr( "Time reward %s: Missing required field \"points_progression_hourly\"", pKVTimedReward->GetName() ) ); uint32 numPointsAccumulatedValidation = 0; for ( KeyValues *kvPoints = pKVTimedReward->FindKey( "points_progression_hourly" )->GetFirstSubKey(); kvPoints; kvPoints = kvPoints->GetNextKey() ) { uint32 numPoints = kvPoints->GetInt(); SCHEMA_INIT_CHECK( numPoints > numPointsAccumulatedValidation, CFmtStr( "Time reward %s: Required field \"points_progression_hourly\" defines invalid points after %u hours", pKVTimedReward->GetName(), m_arrTotalPointsBasedOnHoursPlayed.Count() ) ); m_arrTotalPointsBasedOnHoursPlayed.AddToTail( numPoints ); numPointsAccumulatedValidation = numPoints; } SCHEMA_INIT_CHECK( NULL != pKVTimedReward->FindKey( "points_per_additional_hour" ), CFmtStr( "Time reward %s: Missing required field \"points_per_additional_hour\"", pKVTimedReward->GetName() ) ); m_unPointsPerHourOverplayed = pKVTimedReward->GetInt( "points_per_additional_hour", 0 );
SCHEMA_INIT_CHECK( NULL != pKVTimedReward->FindKey( "period_points_rollover" ), CFmtStr( "Time reward %s: Missing required field \"period_points_rollover\"", pKVTimedReward->GetName() ) ); m_unPointsPerPeriodRollover = pKVTimedReward->GetInt( "period_points_rollover", 0 ); SCHEMA_INIT_CHECK( m_unPointsPerPeriodRollover >= numPointsAccumulatedValidation, CFmtStr( "Time reward %s: Required field \"period_points_rollover\" defines invalid points after %u hours", pKVTimedReward->GetName(), m_arrTotalPointsBasedOnHoursPlayed.Count() ) );
SCHEMA_INIT_CHECK( NULL != pKVTimedReward->FindKey( "pctChance" ), CFmtStr( "Time reward %s: Missing required field \"pctChance\"", pKVTimedReward->GetName() ) ); SCHEMA_INIT_CHECK( ( m_flChance >= 0.0f ) && ( m_flChance <= 1.0f ), CFmtStr( "Time reward %s: Required field \"pctChance\" has invalid value", pKVTimedReward->GetName() ) );
// Parse the criteria or loot_list
if ( pKVTimedReward->FindKey( "criteria" ) ) { bool bCriteriaOK = m_criteria.BInitFromKV( pKVTimedReward->FindKey( "criteria", true ), pschema ); SCHEMA_INIT_CHECK( bCriteriaOK, CFmtStr( "Time Reward %s: Invalid criteria", pKVTimedReward->GetName() ) );
// Check to make sure this criteria doesn't filter to an empty set
if ( bCriteriaOK ) { bool bMatch = false; FOR_EACH_MAP_FAST( pschema.GetItemDefinitionMap(), i ) { if ( m_criteria.BEvaluate( pschema.GetItemDefinitionMap()[i], pschema ) ) { bMatch = true; break; } }
SCHEMA_INIT_CHECK( bMatch, CFmtStr( "Time Reward %s: No items match the critera", pKVTimedReward->GetName() ) ); } }
const char *pszLootList = pKVTimedReward->GetString("loot_list", NULL); if ( pszLootList && pszLootList[0] ) { CUtlVector< char * > arrLootListsTokens; V_SplitString( pszLootList, ",", arrLootListsTokens );
SCHEMA_INIT_CHECK( arrLootListsTokens.Count() != 0, CFmtStr( "Time Reward %s: loot_list (%s) has zero elements", pKVTimedReward->GetName(), pszLootList ) );
FOR_EACH_VEC( arrLootListsTokens, iLootListToken ) { const CEconLootListDefinition *pLootList = pschema.GetLootListByName( arrLootListsTokens[iLootListToken] );
// Make sure the item index is correct because we use this index as a reference
SCHEMA_INIT_CHECK( NULL != pLootList, CFmtStr( "Time Reward %s: loot_list (%s) element '%s' does not exist", pKVTimedReward->GetName(), pszLootList, arrLootListsTokens[iLootListToken] ) );
if ( pLootList ) m_arrLootLists.AddToTail( pLootList ); }
arrLootListsTokens.PurgeAndDeleteElements(); }
return SCHEMA_INIT_SUCCESS(); }
float CTimedItemRewardDefinition::GetChance( void ) const { return m_flChance; }
const CSchemaAttributeDefHandle& GetCampaignAttributeDefHandle( int nCampaignID, ECampaignAttributeType type ) { static CSchemaAttributeDefHandle* pAttrCampaignCompletionBitfield[ g_nNumCampaigns + 1 ]; static CSchemaAttributeDefHandle* pAttrCampaignLastCompletedQuest[ g_nNumCampaigns + 1 ];
static bool s_bCampaignAttrInitialized = false; static bool s_bCampaignAttrValid = false;
if ( !s_bCampaignAttrInitialized ) { s_bCampaignAttrInitialized = true; s_bCampaignAttrValid = true; for ( int j = 1; j <= g_nNumCampaigns; ++j ) { pAttrCampaignCompletionBitfield[ j ]= new CSchemaAttributeDefHandle( ( new CFmtStr( "campaign %d completion bitfield", j ) )->Access() ); if ( !( *pAttrCampaignCompletionBitfield[ j ] ) ) s_bCampaignAttrValid = false;
pAttrCampaignLastCompletedQuest[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "campaign %d last completed quest", j ) )->Access() ); if ( !( *pAttrCampaignLastCompletedQuest[ j ] ) ) s_bCampaignAttrValid = false; } }
if ( ( nCampaignID <= 0 ) || ( nCampaignID > g_nNumCampaigns ) ) { Assert( 0 ); Warning( "Attempting to lookup campaign %d, which does not exist. Verify that the code recognizes that campaigns are 1-based.", nCampaignID ); } else if ( s_bCampaignAttrValid ) { switch( type ) { case k_ECampaignAttribute_CompletionBitfield: return *pAttrCampaignCompletionBitfield[ nCampaignID ];
case k_ECampaignAttribute_LastCompletedQuest: return *pAttrCampaignLastCompletedQuest[ nCampaignID ];
default: Assert( 0 ); Warning( "Attempting to lookup campaign %d type %d, which does not exist.", nCampaignID, type ); break; } }
static CSchemaAttributeDefHandle s_DummyAttr( "undefined" ); return s_DummyAttr; }
const CSchemaAttributeDefHandle& GetStickerAttributeDefHandle( int attrNum, EStickerAttributeType type ) { // Attributes of the schema validation
static bool s_bStickerAttrsSetup = false; static bool s_bStickerAttrsValid = false; static CSchemaAttributeDefHandle* pAttrStickerSlotID[ g_nNumStickerAttrs ]; static CSchemaAttributeDefHandle* pAttrStickerSlotWear[ g_nNumStickerAttrs ]; static CSchemaAttributeDefHandle* pAttrStickerSlotScale[ g_nNumStickerAttrs ]; static CSchemaAttributeDefHandle* pAttrStickerSlotRotation[ g_nNumStickerAttrs ];
if ( !s_bStickerAttrsSetup ) { s_bStickerAttrsSetup = true; s_bStickerAttrsValid = true; for ( int j = 0; j < g_nNumStickerAttrs; ++j ) { pAttrStickerSlotID[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "sticker slot %d id", j ) )->Access() ); if ( !( *pAttrStickerSlotID[ j ] ) ) s_bStickerAttrsValid = false; pAttrStickerSlotWear[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "sticker slot %d wear", j ) )->Access() ); if ( !( *pAttrStickerSlotWear[ j ] ) ) s_bStickerAttrsValid = false; pAttrStickerSlotScale[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "sticker slot %d scale", j ) )->Access() ); if ( !( *pAttrStickerSlotScale[ j ] ) ) s_bStickerAttrsValid = false; pAttrStickerSlotRotation[ j ] = new CSchemaAttributeDefHandle( ( new CFmtStr( "sticker slot %d rotation", j ) )->Access() );
if ( !( *pAttrStickerSlotRotation[ j ] ) ) s_bStickerAttrsValid = false; } }
if ( s_bStickerAttrsValid ) { switch ( type ) { case k_EStickerAttribute_ID: return *pAttrStickerSlotID[ attrNum ]; break; case k_EStickerAttribute_Wear: return *pAttrStickerSlotWear[ attrNum ]; break; case k_EStickerAttribute_Scale: return *pAttrStickerSlotScale[ attrNum ]; break; case k_EStickerAttribute_Rotation: return *pAttrStickerSlotRotation[ attrNum ]; break;
default: Assert( 0 ); break; }; }
static CSchemaAttributeDefHandle s_DummyAttr( "undefined" ); return s_DummyAttr; }
bool CStickerKit::InitFromKeyValues( KeyValues *pKVEntry, const CStickerKit *pDefault, CUtlVector<CUtlString> *pVecErrors /*= NULL*/ ) { sName.Set( pKVEntry->GetString( "name", pDefault->sName.String() ) ); sDescriptionString.Set( pKVEntry->GetString( "description_string", pDefault->sDescriptionString.String() ) ); sItemName.Set( pKVEntry->GetString( "item_name", pDefault->sItemName.String() ) );
uint8 ucRarity; GetItemSchema()->BGetItemRarityFromName( pKVEntry->GetString( "item_rarity", "common" ), &ucRarity );
nRarity = ucRarity;
sMaterialPath.Set( pKVEntry->GetString( "sticker_material", pDefault->sMaterialPath.String() ) ); if ( *sMaterialPath.String() ) { sMaterialPathNoDrips.Set( pKVEntry->GetString( "sticker_material_nodrips", CFmtStr( "%s_nodrips", sMaterialPath.String() ) ) ); }
m_strInventoryImage.Set( pKVEntry->GetString( "image_inventory", CFmtStr( "econ/stickers/%s", sMaterialPath.String() ) ) );
SetIconURLSmall( GetInventoryImage() ); SetIconURLLarge( CFmtStr( "%s_large", GetInventoryImage() ) );
//
// gc_generation_settings
//
flRotateStart = pKVEntry->GetFloat( "gc_generation_settings/rotate_start", pDefault->flRotateStart ); flRotateEnd = pKVEntry->GetFloat( "gc_generation_settings/rotate_end", pDefault->flRotateEnd ); SCHEMA_INIT_CHECK( ( flRotateStart >= -360.0f ) && ( flRotateStart <= flRotateEnd ) && ( flRotateEnd <= 360.0f ), CFmtStr( "Sticker kit '%s' rotate range is not valid %f:%f", pKVEntry->GetName(), flRotateStart, flRotateEnd ) );
flScaleMin = pKVEntry->GetFloat( "gc_generation_settings/scale_min", pDefault->flScaleMin ); flScaleMax = pKVEntry->GetFloat( "gc_generation_settings/scale_max", pDefault->flScaleMax ); SCHEMA_INIT_CHECK( // Scale is in UV space so max is a smaller float, min is a larger float
( flScaleMax > 0.0f ) && ( flScaleMax <= flScaleMin ), CFmtStr( "Sticker kit '%s' scale range is not valid %f:%f", pKVEntry->GetName(), flScaleMax, flScaleMin ) );
flWearMin = pKVEntry->GetFloat( "gc_generation_settings/wear_min", pDefault->flWearMin ); flWearMax = pKVEntry->GetFloat( "gc_generation_settings/wear_max", pDefault->flWearMax ); SCHEMA_INIT_CHECK( ( flWearMin >= 0.0f ) && ( flWearMin <= flWearMax ) && ( flWearMax <= 1.0f ), CFmtStr( "Sticker kit '%s' wear range is not valid %f:%f", pKVEntry->GetName(), flWearMin, flWearMax ) );
m_nEventID = pKVEntry->GetInt( "tournament_event_id", pDefault->m_nEventID ); m_nEventTeamID = pKVEntry->GetInt( "tournament_team_id", pDefault->m_nEventTeamID ); m_nPlayerID = pKVEntry->GetInt( "tournament_player_id", pDefault->m_nPlayerID );
m_pKVItem = pKVEntry ? pKVEntry->MakeCopy() : NULL; return true; }
bool CStickerList::InitFromKeyValues( KeyValues *pKVEntry, CUtlVector<CUtlString> *pVecErrors /*= NULL*/ ) { flWearMin = pKVEntry->GetFloat( "gc_generation_settings/wear_min", 0.0f ); flWearMax = pKVEntry->GetFloat( "gc_generation_settings/wear_max", 1.0f ); SCHEMA_INIT_CHECK( ( flWearMin >= 0.0f ) && ( flWearMin <= flWearMax ) && ( flWearMax <= 1.0f ), CFmtStr( "Sticker list '%s' wear range is not valid %f:%f", pKVEntry->GetName(), flWearMin, flWearMax ) );
flTotalWeight = 0.0f;
float flLargestMinWear = 0.0f; float flSmallestMaxWear = 1.0f;
for ( KeyValues *kvChild = pKVEntry->GetFirstValue(); kvChild; kvChild = kvChild->GetNextValue() ) { char const *szName = kvChild->GetName(); const CStickerKit *pStickerKit = GetItemSchema()->GetStickerKitDefinitionByName( szName ); const CStickerList *pStickerList = GetItemSchema()->GetStickerListDefinitionByName( szName ); SCHEMA_INIT_CHECK( ( pStickerKit || pStickerList ) && !( pStickerKit && pStickerList ), CFmtStr( "Sticker list '%s' refers to an unknown stickerkit or stickerlist '%s'", pKVEntry->GetName(), szName ) );
float flWeight = kvChild->GetFloat(); SCHEMA_INIT_CHECK( ( flWeight > 0.0f ), CFmtStr( "Sticker list '%s' has invalid weight %f", pKVEntry->GetName(), flWeight ) );
if ( pStickerKit ) { flLargestMinWear = MAX( flLargestMinWear, pStickerKit->flWearMin ); flSmallestMaxWear = MIN( flSmallestMaxWear, pStickerKit->flWearMax ); } if ( pStickerList ) { flLargestMinWear = MAX( flLargestMinWear, pStickerList->flWearMin ); flSmallestMaxWear = MIN( flSmallestMaxWear, pStickerList->flWearMax ); }
// add the entry
sticker_list_entry_t entry; entry.pKit = pStickerKit; entry.pList = pStickerList; entry.flWeight = flWeight; arrElements.AddToTail( entry ); flTotalWeight += entry.flWeight; }
SCHEMA_INIT_CHECK( ( arrElements.Count() > 0 ), CFmtStr( "Sticker list '%s' has no elements", pKVEntry->GetName() ) );
SCHEMA_INIT_CHECK( ( flTotalWeight > 0.0f ), CFmtStr( "Sticker list '%s' has no elements weight", pKVEntry->GetName() ) );
SCHEMA_INIT_CHECK( ( flSmallestMaxWear >= flWearMin ), CFmtStr( "Sticker list '%s' wear_min %f exceeds elements max range wear %f", pKVEntry->GetName(), flWearMin, flSmallestMaxWear ) ); SCHEMA_INIT_CHECK( ( flLargestMinWear <= flWearMax ), CFmtStr( "Sticker list '%s' wear_max %f below elements min range wear %f", pKVEntry->GetName(), flWearMax, flLargestMinWear ) );
return true; }
bool CStickerKit::GenerateStickerApplicationInfo( CAppliedStickerInfo_t *pInfo ) const { if ( !pInfo ) return false;
pInfo->flWearMin = MAX( pInfo->flWearMin, flWearMin ); pInfo->flWearMax = MIN( pInfo->flWearMax, flWearMax ); if ( pInfo->flWearMin > pInfo->flWearMax ) return false;
pInfo->nID = nID; pInfo->flScale = CEconItemSchema::GetRandomStream().RandomFloat( flScaleMax, flScaleMin ); pInfo->flRotate = CEconItemSchema::GetRandomStream().RandomFloat( flRotateStart, flRotateEnd );
return true; }
bool CStickerList::GenerateStickerApplicationInfo( CAppliedStickerInfo_t *pInfo ) const { if ( !pInfo ) return false;
// Generate a random roll into our list
float flRand = CEconItemSchema::GetRandomStream().RandomFloat(0.f, 1.f) * flTotalWeight;
float flAccum = 0.f; for ( int i=0; i<arrElements.Count(); ++i ) { flAccum += arrElements[i].flWeight; if ( flRand <= flAccum ) { const sticker_list_entry_t &entry = arrElements[i]; pInfo->flWearMin = MAX( pInfo->flWearMin, flWearMin ); pInfo->flWearMax = MIN( pInfo->flWearMax, flWearMax ); if ( pInfo->flWearMin > pInfo->flWearMax ) return false;
if ( entry.pList ) return entry.pList->GenerateStickerApplicationInfo( pInfo ); if ( entry.pKit ) return entry.pKit->GenerateStickerApplicationInfo( pInfo );
return false; } }
return false; }
bool CPaintKit::InitFromKeyValues( KeyValues *pKVEntry, const CPaintKit *pDefault, bool bHandleAbsolutePaths ) { sName.Set( pKVEntry->GetString( "name", pDefault->sName.String() ) ); sDescriptionString.Set( pKVEntry->GetString( "description_string", pDefault->sDescriptionString.String() ) ); sDescriptionTag.Set( pKVEntry->GetString( "description_tag", pDefault->sDescriptionTag.String() ) ); nRarity = 1; // rarities set in the paint_kits_rarity block
// Character paint kit fields
sVmtPath.Set( pKVEntry->GetString( "vmt_path", pDefault->sVmtPath.String() ) );
if ( kvVmtOverrides != nullptr ) { kvVmtOverrides->deleteThis(); kvVmtOverrides = nullptr; }
KeyValues* pVmtOverrides = pKVEntry->FindKey( "vmt_overrides" ); if ( pVmtOverrides != nullptr ) { kvVmtOverrides = new KeyValues( "CustomCharacter" ); kvVmtOverrides->MergeFrom( pVmtOverrides, KeyValues::MERGE_KV_UPDATE ); }
// Regular paint kit fields
if (bHandleAbsolutePaths) { // this solution is less than ideal, it'll only work for windows drive paths (not network paths), and in
// order to make this better we need to change things down inside the material system / texture code.
// it's only used for the workshop preview con command right now.
const char* pPatternPath = pKVEntry->GetString( "pattern", pDefault->sPattern.String() ); #ifdef PLATFORM_WINDOWS
int nLength = V_strlen( pPatternPath ); if ( nLength > 2 && !( pPatternPath[0] == '/' && pPatternPath[1] == '/' && pPatternPath[2] != '/' ) && V_IsAbsolutePath( pPatternPath ) ) { sPattern.Format( "//./%s", pPatternPath ); } else #endif
{ sPattern.Set( pPatternPath ); } } else { sPattern.Set( pKVEntry->GetString( "pattern", pDefault->sPattern.String() ) ); }
sLogoMaterial.Set( pKVEntry->GetString( "logo_material", pDefault->sLogoMaterial.String() ) );
nStyle = pKVEntry->GetInt( "style", pDefault->nStyle ); flWearDefault = pKVEntry->GetFloat( "wear_default", pDefault->flWearDefault ); flWearRemapMin = pKVEntry->GetFloat( "wear_remap_min", pDefault->flWearRemapMin ); flWearRemapMax = pKVEntry->GetFloat( "wear_remap_max", pDefault->flWearRemapMax ); nFixedSeed = pKVEntry->GetInt( "seed", pDefault->nFixedSeed ); uchPhongExponent = pKVEntry->GetInt( "phongexponent", pDefault->uchPhongExponent ); uchPhongAlbedoBoost = pKVEntry->GetInt( "phongalbedoboost", static_cast< int >( pDefault->uchPhongAlbedoBoost ) - 1 ) + 1; uchPhongIntensity = pKVEntry->GetInt( "phongintensity", pDefault->uchPhongIntensity ); flPatternScale = pKVEntry->GetFloat( "pattern_scale", pDefault->flPatternScale ); flPatternOffsetXStart = pKVEntry->GetFloat( "pattern_offset_x_start", pDefault->flPatternOffsetXStart ); flPatternOffsetXEnd = pKVEntry->GetFloat( "pattern_offset_x_end", pDefault->flPatternOffsetXEnd ); flPatternOffsetYStart = pKVEntry->GetFloat( "pattern_offset_y_start", pDefault->flPatternOffsetYStart ); flPatternOffsetYEnd = pKVEntry->GetFloat( "pattern_offset_y_end", pDefault->flPatternOffsetYEnd ); flPatternRotateStart = pKVEntry->GetFloat( "pattern_rotate_start", pDefault->flPatternRotateStart ); flPatternRotateEnd = pKVEntry->GetFloat( "pattern_rotate_end", pDefault->flPatternRotateEnd ); flLogoScale = pKVEntry->GetFloat( "logo_scale", pDefault->flLogoScale ); flLogoOffsetX = pKVEntry->GetFloat( "logo_offset_x", pDefault->flLogoOffsetX ); flLogoOffsetY = pKVEntry->GetFloat( "logo_offset_y", pDefault->flLogoOffsetY ); flLogoRotation = pKVEntry->GetFloat( "logo_rotation", pDefault->flLogoRotation ); bIgnoreWeaponSizeScale = pKVEntry->GetBool( "ignore_weapon_size_scale", pDefault->bIgnoreWeaponSizeScale ); nViewModelExponentOverrideSize = pKVEntry->GetInt( "view_model_exponent_override_size", pDefault->nViewModelExponentOverrideSize ); bOnlyFirstMaterial = pKVEntry->GetBool( "only_first_material", pDefault->bOnlyFirstMaterial );
char szColorName[ 16 ]; for ( int nColor = 0; nColor < CPaintKit::NUM_COLORS; ++nColor ) { // Regular Colors
V_snprintf( szColorName, sizeof( szColorName ), "color%i", nColor );
KeyValues *pKVColor = pKVEntry->FindKey( szColorName ); if ( pKVColor ) { const char *pchColor = pKVColor->GetString(); unsigned int cR, cG, cB; sscanf( pchColor, "%u %u %u", &cR, &cG, &cB ); rgbaColor[ nColor ].SetColor( cR, cG, cB, 255 ); } else { rgbaColor[ nColor ] = pDefault->rgbaColor[ nColor ]; }
// Logo Colors
V_snprintf( szColorName, sizeof( szColorName ), "logocolor%i", nColor );
pKVColor = pKVEntry->FindKey( szColorName ); if ( pKVColor ) { const char *pchColor = pKVColor->GetString(); unsigned int cR, cG, cB; sscanf( pchColor, "%u %u %u", &cR, &cG, &cB ); rgbaLogoColor[ nColor ].SetColor( cR, cG, cB, 255 ); } else { rgbaLogoColor[ nColor ] = pDefault->rgbaLogoColor[ nColor ]; } }
return true; }
void CPaintKit::FillKeyValuesForWorkshop( KeyValues *pKVToFill ) const { pKVToFill->SetInt( "style", nStyle ); pKVToFill->SetString( "pattern", sPattern.String() );
char szColorName[ 16 ]; for ( int nColor = 0; nColor < CPaintKit::NUM_COLORS; ++nColor ) { // Regular Colors
V_snprintf( szColorName, sizeof( szColorName ), "color%i", nColor ); pKVToFill->SetColor( szColorName, rgbaColor[ nColor ] ); }
pKVToFill->SetFloat( "pattern_scale", flPatternScale ); pKVToFill->SetFloat( "pattern_offset_x_start", flPatternOffsetXStart ); pKVToFill->SetFloat( "pattern_offset_x_end", flPatternOffsetXEnd ); pKVToFill->SetFloat( "pattern_offset_y_start", flPatternOffsetYStart ); pKVToFill->SetFloat( "pattern_offset_y_end", flPatternOffsetYEnd ); pKVToFill->SetFloat( "pattern_rotate_start", flPatternRotateStart ); pKVToFill->SetFloat( "pattern_rotate_end", flPatternRotateEnd );
pKVToFill->SetFloat( "wear_remap_min", flWearRemapMin ); pKVToFill->SetFloat( "wear_remap_max", flWearRemapMax ); pKVToFill->SetInt( "phongexponent", uchPhongExponent ); pKVToFill->SetInt( "phongalbedoboost", static_cast< int >( uchPhongAlbedoBoost ) - 1 ); pKVToFill->SetInt( "phongintensity", uchPhongIntensity ); pKVToFill->SetBool( "ignore_weapon_size_scale", bIgnoreWeaponSizeScale ); pKVToFill->SetInt( "view_model_exponent_override_size", nViewModelExponentOverrideSize ); pKVToFill->SetBool( "only_first_material", bOnlyFirstMaterial );
//pKVToFill->SetString( "logo_material", sLogoMaterial.String() );
//pKVToFill->SetFloat( "logo_scale", flLogoScale );
//pKVToFill->SetFloat( "logo_offset_x", flLogoOffsetX );
//pKVToFill->SetFloat( "logo_offset_y", flLogoOffsetY );
//pKVToFill->SetFloat( "logo_rotation", flLogoRotation );
//for ( int nColor = 0; nColor < CPaintKit::NUM_COLORS; ++nColor )
//{
// // Logo Colors
// V_snprintf( szColorName, sizeof( szColorName ), "logocolor%i", nColor );
// pKVToFill->SetColor( szColorName, rgbaLogoColor[ nColor ] );
//}
//pKVToFill->SetInt( "seed", nFixedSeed );
}
//-----------------------------------------------------------------------------
// Purpose: Adds a foreign item definition to local definition mapping for a
// foreign app
//-----------------------------------------------------------------------------
void CForeignAppImports::AddMapping( uint16 unForeignDefIndex, const CEconItemDefinition *pDefn ) { m_mapDefinitions.InsertOrReplace( unForeignDefIndex, pDefn ); }
//-----------------------------------------------------------------------------
// Purpose: Adds a foreign item definition to local definition mapping for a
// foreign app
//-----------------------------------------------------------------------------
const CEconItemDefinition *CForeignAppImports::FindMapping( uint16 unForeignDefIndex ) const { int i = m_mapDefinitions.Find( unForeignDefIndex ); if( m_mapDefinitions.IsValidIndex( i ) ) return m_mapDefinitions[i]; else return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Less function comparator for revolving loot lists map
//-----------------------------------------------------------------------------
static bool LLLessFunc( const int& e1, const int&e2 ) { return e1 < e2; }
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CEconItemSchema::CEconItemSchema( ) : m_unResetCount( 0 ) , m_pKVRawDefinition( NULL ) , m_unVersion( 0 ) , m_pDefaultItemDefinition( NULL ) , m_mapItemSets( DefLessFunc(const char*) ) , m_mapDefinitionPrefabs( DefLessFunc(const char*) ) , m_mapDefaultBodygroupState( DefLessFunc(const char*) ) , m_bSchemaParsingItems(false) #if defined(CLIENT_DLL) || defined(GAME_DLL)
, m_pDelayedSchemaData( NULL ) #endif
, m_mapKillEaterScoreTypes( DefLessFunc( unsigned int ) ) { Reset(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
IEconTool *CEconItemSchema::CreateEconToolImpl( const char *pszToolType, const char *pszUseString, const char *pszUsageRestriction, item_capabilities_t unCapabilities, KeyValues *pUsageKV ) { return nullptr; }
//-----------------------------------------------------------------------------
// Purpose: Resets the schema to before BInit was called
//-----------------------------------------------------------------------------
void CEconItemSchema::Reset( void ) { ++m_unResetCount;
m_unFirstValidClass = 0; m_unLastValidClass = 0; m_unFirstValidItemSlot = 0; m_unLastValidItemSlot = 0; m_unNumItemPresets = 0; m_unMinLevel = 0; m_unMaxLevel = 0; m_nMaxValidGraffitiTintDefID = 0; m_unSumQualityWeights = 0; m_mapRarities.Purge(); m_mapSoundMaterials.Purge(); m_mapQualities.Purge(); m_mapItems.PurgeAndDeleteElements(); m_mapItemsSorted.Purge(); m_mapPaintKits.PurgeAndDeleteElements(); m_mapStickerKits.PurgeAndDeleteElements(); m_mapMusicDefs.PurgeAndDeleteElements(); m_dictStickerKits.Purge(); m_dictStickerLists.Purge(); m_mapAttributesContainer.PurgeAndDeleteElements(); FOR_EACH_VEC( m_vecAttributeTypes, i ) { delete m_vecAttributeTypes[i].m_pAttrType; } m_vecAttributeTypes.Purge(); m_mapRecipes.Purge(); m_vecTimedRewards.Purge(); m_mapAlternateIcons.Purge(); m_mapItemSets.Purge(); m_dictLootLists.Purge(); m_mapAttributeControlledParticleSystems.Purge(); m_unVersion = 0; if ( m_pKVRawDefinition ) { m_pKVRawDefinition->deleteThis(); m_pKVRawDefinition = NULL; }
#if defined(CLIENT_DLL) || defined(GAME_DLL)
delete m_pDefaultItemDefinition; m_pDefaultItemDefinition = NULL; #endif
FOR_EACH_MAP_FAST( m_mapRecipes, i ) { delete m_mapRecipes[i]; }
FOR_EACH_MAP_FAST( m_mapDefinitionPrefabs, i ) { m_mapDefinitionPrefabs[i]->deleteThis(); } m_mapDefinitionPrefabs.Purge();
m_vecEquipRegionsList.Purge(); // m_vecItemLevelingData.PurgeAndDeleteElements();
m_vecItemLevelingData.Purge();
m_RandomStream.SetSeed( 0 ); }
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CEconItemSchema &CEconItemSchema::operator=( CEconItemSchema &rhs ) { Reset(); BInitSchema( rhs.m_pKVRawDefinition ); return *this; }
#if defined( CLIENT_DLL )
#define MERGE_LIVE_PLAYERS_CODE 0
static void Helper_MergeKeyValuesUsingTemplate( KeyValues *kvInto, KeyValues *kvSrc, KeyValues *kvTemplate ) { FOR_EACH_SUBKEY( kvTemplate, kvTemplateSubkey ) { if ( kvTemplateSubkey->GetDataType() == KeyValues::TYPE_NONE ) { // This is a nested subkey
if ( !V_strcmp( kvTemplateSubkey->GetName(), "*" ) ) { // This is a wildcard subkey
FOR_EACH_TRUE_SUBKEY( kvSrc, kvWildcardSrcSubkey ) { KeyValues *pSubInto = kvInto->FindKey( kvWildcardSrcSubkey->GetNameSymbol() ); if ( !pSubInto ) { #if MERGE_LIVE_PLAYERS_CODE
kvInto->AddSubKey( pSubInto = kvWildcardSrcSubkey->MakeCopy() ); #else
kvInto->AddSubKey( pSubInto = new KeyValues( kvWildcardSrcSubkey->GetName() ) ); #endif
} Helper_MergeKeyValuesUsingTemplate( pSubInto, kvWildcardSrcSubkey, kvTemplateSubkey ); } } else { // This is a direct dive into subkey
KeyValues *pSubInto = kvInto->FindKey( kvTemplateSubkey->GetNameSymbol() ); KeyValues *pSubSrc = kvSrc->FindKey( kvTemplateSubkey->GetNameSymbol() ); if ( pSubInto && pSubSrc ) Helper_MergeKeyValuesUsingTemplate( pSubInto, pSubSrc, kvTemplateSubkey ); } } else { // This is a direct value copy
if ( KeyValues *pSubSrc = kvSrc->FindKey( kvTemplateSubkey->GetNameSymbol() ) ) { if ( KeyValues *pSubInto = kvInto->FindKey( kvTemplateSubkey->GetNameSymbol() ) ) { // Cannot override an existing value!
Assert( !"Cannot override existing schema value" ); } else { // Make a copy and append
kvInto->AddSubKey( pSubSrc->MakeCopy() ); } } } } } #endif
//-----------------------------------------------------------------------------
// Initializes the schema, given KV filename
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInit( const char *fileName, const char *pathID, CUtlVector<CUtlString> *pVecErrors /* = NULL */) { Reset(); m_pKVRawDefinition = new KeyValues( "CEconItemSchema" ); m_pKVRawDefinition->UsesEscapeSequences( true ); if ( !m_pKVRawDefinition->LoadFromFile( g_pFullFileSystem, fileName, pathID ) ) { m_pKVRawDefinition->deleteThis(); m_pKVRawDefinition = NULL; }
if ( m_pKVRawDefinition ) { #if defined( CLIENT_DLL )
if ( KeyValues *kvLiveTemplate = m_pKVRawDefinition->FindKey( "items_game_live" ) ) { // for client code we also load the live file to supplement certain portions of schema
char chLiveFilename[MAX_PATH]; V_strcpy_safe( chLiveFilename, fileName ); if ( char *chExt = V_strrchr( chLiveFilename, '.' ) ) { char chSuffix[ 64 ] = {}; V_sprintf_safe( chSuffix, "_live%s", chExt ); *chExt = 0; V_strcat_safe( chLiveFilename, chSuffix );
KeyValues *kvLive = new KeyValues( "CEconItemSchema" ); kvLive->UsesEscapeSequences( true );
if ( kvLive->LoadFromFile( g_pFullFileSystem, chLiveFilename, pathID ) ) { Helper_MergeKeyValuesUsingTemplate( m_pKVRawDefinition, kvLive, kvLiveTemplate ); }
#if MERGE_LIVE_PLAYERS_CODE
if ( KeyValues *kvDump = m_pKVRawDefinition->FindKey( "pro_players" ) ) { kvDump->SaveToFile( g_pFullFileSystem, "pro_players_merged.txt" ); } #endif
kvLive->deleteThis(); kvLive = NULL; } } #endif
return BInitSchema( m_pKVRawDefinition, pVecErrors ); } else { #if !defined(CSTRIKE_DLL)
Warning( "No %s file found. May be unable to create items.\n", fileName ); #endif // CSTRIKE_DLL
return false; } }
//-----------------------------------------------------------------------------
// Initializes the schema, given KV in binary form
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitBinaryBuffer( CUtlBuffer &buffer, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { Reset(); m_pKVRawDefinition = new KeyValues( "CEconItemSchema" ); m_pKVRawDefinition->UsesEscapeSequences( true ); if ( m_pKVRawDefinition->ReadAsBinary( buffer ) ) { return BInitSchema( m_pKVRawDefinition, pVecErrors ); } if ( pVecErrors ) { pVecErrors->AddToTail( "Error parsing keyvalues" ); } return false; }
//-----------------------------------------------------------------------------
// Initializes the schema, given KV in text form
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitTextBuffer( CUtlBuffer &buffer, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { Reset(); m_pKVRawDefinition = new KeyValues( "CEconItemSchema" ); m_pKVRawDefinition->UsesEscapeSequences( true ); if ( m_pKVRawDefinition->LoadFromBuffer( NULL, buffer ) ) { return BInitSchema( m_pKVRawDefinition, pVecErrors ); } if ( pVecErrors ) { pVecErrors->AddToTail( "Error parsing keyvalues" ); } return false; }
#if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Set up the buffer to use to reinitialize our schema next time we can do so safely.
//-----------------------------------------------------------------------------
void CEconItemSchema::MaybeInitFromBuffer( IDelayedSchemaData *pDelayedSchemaData ) { // Use whatever our most current data block is.
if ( m_pDelayedSchemaData ) { delete m_pDelayedSchemaData; }
m_pDelayedSchemaData = pDelayedSchemaData;
#ifdef CLIENT_DLL
// If we aren't in a game we can parse immediately now.
if ( !engine->IsInGame() ) { BInitFromDelayedBuffer(); } #endif // CLIENT_DLL
}
//-----------------------------------------------------------------------------
// We're in a safe place to change the contents of the schema, so do so and clean
// up whatever memory we were using.
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitFromDelayedBuffer() { if ( !m_pDelayedSchemaData ) return true;
bool bSuccess = m_pDelayedSchemaData->InitializeSchema( this ); delete m_pDelayedSchemaData; m_pDelayedSchemaData = NULL;
return bSuccess; } #endif // !GC_DLL
static void CalculateKeyValuesCRCRecursive( KeyValues *pKV, CRC32_t *crc, bool bIgnoreName = false ) { // Hash in the key name in LOWERCASE. Keyvalues files are not deterministic due
// to the case insensitivity of the keys and the dependence on the existing
// state of the name table upon entry.
if ( !bIgnoreName ) { const char *s = pKV->GetName(); for (;;) { unsigned char x = tolower(*s); CRC32_ProcessBuffer( crc, &x, 1 ); // !SPEED! This is slow, but it works.
if (*s == '\0') break; ++s; } }
// Now hash in value, depending on type
// !FIXME! This is not byte-order independent!
switch ( pKV->GetDataType() ) { case KeyValues::TYPE_NONE: { FOR_EACH_SUBKEY( pKV, pChild ) { CalculateKeyValuesCRCRecursive( pChild, crc ); } break; } case KeyValues::TYPE_STRING: { const char *val = pKV->GetString(); CRC32_ProcessBuffer( crc, val, V_strlen(val)+1 ); break; }
case KeyValues::TYPE_INT: { int val = pKV->GetInt(); CRC32_ProcessBuffer( crc, &val, sizeof(val) ); break; }
case KeyValues::TYPE_UINT64: { uint64 val = pKV->GetUint64(); CRC32_ProcessBuffer( crc, &val, sizeof(val) ); break; }
case KeyValues::TYPE_FLOAT: { float val = pKV->GetFloat(); CRC32_ProcessBuffer( crc, &val, sizeof(val) ); break; } case KeyValues::TYPE_COLOR: { int val = pKV->GetColor().GetRawColor(); CRC32_ProcessBuffer( crc, &val, sizeof(val) ); break; }
default: case KeyValues::TYPE_PTR: case KeyValues::TYPE_WSTRING: { Assert( !"Unsupport data type!" ); break; } } }
uint32 CEconItemSchema::CalculateKeyValuesVersion( KeyValues *pKV ) { CRC32_t crc; CRC32_Init( &crc );
// Calc CRC recursively. Ignore the very top-most
// key name, which isn't set consistently
CalculateKeyValuesCRCRecursive( pKV, &crc, true ); CRC32_Final( &crc ); return crc; }
//-----------------------------------------------------------------------------
// Purpose: Initializes the schema
// Input: pKVRawDefinition - The raw KeyValues representation of the schema
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitSchema( KeyValues *pKVRawDefinition, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { #if !defined( GC_DLL )
m_unVersion = CalculateKeyValuesVersion( pKVRawDefinition ); #endif
m_unMinLevel = pKVRawDefinition->GetInt( "item_level_min", 0 ); m_unMaxLevel = pKVRawDefinition->GetInt( "item_level_max", 0 );
// Pre-parsed arrays in order of appearance for schema initialization
CUtlVector< KeyValues * > arrRootPrefabs; CUtlVector< KeyValues * > arrRootClientLootLists; CUtlVector< KeyValues * > arrRootRevolvingLootlists; CUtlVector< KeyValues * > arrRootLootlists; CUtlVector< KeyValues * > arrRootMiscLootlists; CUtlVector< KeyValues * > arrRootStickerKits; CUtlVector< KeyValues * > arrRootStickerLists; CUtlVector< KeyValues * > arrRootPaintKits; CUtlVector< KeyValues * > arrRootPaintKitsRarity; CUtlVector< KeyValues * > arrRootItems; CUtlVector< KeyValues * > arrRootItemSets; CUtlVector< KeyValues * > arrRootMusicDefinitions; FOR_EACH_TRUE_SUBKEY( pKVRawDefinition, kvRootSubKey ) { if ( !V_stricmp( kvRootSubKey->GetName(), "prefabs" ) ) arrRootPrefabs.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "loot_lists" ) ) arrRootLootlists.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "client_loot_lists" ) ) arrRootClientLootLists.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "revolving_loot_lists" ) ) arrRootRevolvingLootlists.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "loot_lists_misc" ) ) arrRootMiscLootlists.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "sticker_kits" ) ) arrRootStickerKits.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "sticker_lists" ) ) arrRootStickerLists.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "paint_kits" ) ) arrRootPaintKits.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "paint_kits_rarity" ) ) arrRootPaintKitsRarity.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "items" ) ) arrRootItems.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "item_sets" ) ) arrRootItemSets.AddToTail( kvRootSubKey ); else if ( !V_stricmp( kvRootSubKey->GetName(), "music_definitions" ) ) arrRootMusicDefinitions.AddToTail( kvRootSubKey ); }
// Parse the prefabs block first so the prefabs will be populated in case anything else wants
// to use them later.
FOR_EACH_VEC( arrRootPrefabs, i ) { SCHEMA_INIT_SUBSTEP( BInitDefinitionPrefabs( arrRootPrefabs[i], pVecErrors ) ); }
// Initialize the game info block
KeyValues *pKVGameInfo = pKVRawDefinition->FindKey( "game_info" ); SCHEMA_INIT_CHECK( NULL != pKVGameInfo, CFmtStr( "Required key \"game_info\" missing.\n" ) );
if ( NULL != pKVGameInfo ) { SCHEMA_INIT_SUBSTEP( BInitGameInfo( pKVGameInfo, pVecErrors ) ); }
// Initialize our attribute types. We don't actually pull this data from the schema right now but it
// still makes sense to initialize it at this point.
SCHEMA_INIT_SUBSTEP( BInitAttributeTypes( pVecErrors ) );
// Initialize the rarity block
KeyValues *pKVRarities = pKVRawDefinition->FindKey( "rarities" ); SCHEMA_INIT_CHECK( NULL != pKVRarities, CFmtStr( "Required key \"rarities\" missing.\n" ) ); if ( NULL != pKVRarities ) { SCHEMA_INIT_SUBSTEP( BInitRarities( pKVRarities, pVecErrors ) ); }
// Initialize the qualities block
KeyValues *pKVQualities = pKVRawDefinition->FindKey( "qualities" ); SCHEMA_INIT_CHECK( NULL != pKVQualities, CFmtStr( "Required key \"qualities\" missing.\n" ) ); if ( NULL != pKVQualities ) { SCHEMA_INIT_SUBSTEP( BInitQualities( pKVQualities, pVecErrors ) ); }
// Initialize the colors block
KeyValues *pKVColors = pKVRawDefinition->FindKey( "colors" ); SCHEMA_INIT_CHECK( NULL != pKVColors, CFmtStr( "Required key \"colors\" missing.\n" ) );
if ( NULL != pKVColors ) { SCHEMA_INIT_SUBSTEP( BInitColors( pKVColors, pVecErrors ) ); }
SCHEMA_INIT_SUBSTEP( BInitGraffitiTints( pKVRawDefinition->FindKey( "graffiti_tints" ), pVecErrors ) );
// Initialize the music block
FOR_EACH_VEC( arrRootMusicDefinitions, i ) { SCHEMA_INIT_SUBSTEP( BInitMusicDefs( arrRootMusicDefinitions[i], pVecErrors ) ); }
// Initialize the attributes block
KeyValues *pKVAttributes = pKVRawDefinition->FindKey( "attributes" ); SCHEMA_INIT_CHECK( NULL != pKVAttributes, CFmtStr( "Required key \"attributes\" missing.\n" ) ); if ( NULL != pKVAttributes ) { SCHEMA_INIT_SUBSTEP( BInitAttributes( pKVAttributes, pVecErrors ) ); }
// Initialize the sound materials block
KeyValues *pKVSoundMaterials = pKVRawDefinition->FindKey( "sound_materials" ); if ( NULL != pKVSoundMaterials ) { SCHEMA_INIT_SUBSTEP( BInitSoundMaterials( pKVSoundMaterials, pVecErrors ) ); }
// Initialize the "equip_regions_list" block -- this is an optional block
KeyValues *pKVEquipRegions = pKVRawDefinition->FindKey( "equip_regions_list" ); if ( NULL != pKVEquipRegions ) { SCHEMA_INIT_SUBSTEP( BInitEquipRegions( pKVEquipRegions, pVecErrors ) ); }
// Initialize the "equip_conflicts" block -- this is an optional block, though it doesn't
// make any sense and will probably fail internally if there is no corresponding "equip_regions"
// block as well
KeyValues *pKVEquipRegionConflicts = pKVRawDefinition->FindKey( "equip_conflicts" ); if ( NULL != pKVEquipRegionConflicts ) { SCHEMA_INIT_SUBSTEP( BInitEquipRegionConflicts( pKVEquipRegionConflicts, pVecErrors ) ); }
// Do before items, so items can refer into it.
KeyValues *pKVParticleSystems = pKVRawDefinition->FindKey( "attribute_controlled_attached_particles" ); SCHEMA_INIT_SUBSTEP( BInitAttributeControlledParticleSystems( pKVParticleSystems, pVecErrors ) );
FOR_EACH_VEC( arrRootStickerKits, i ) { SCHEMA_INIT_SUBSTEP( BInitStickerKits( arrRootStickerKits[i], pVecErrors ) ); }
FOR_EACH_VEC( arrRootPaintKits, i ) { SCHEMA_INIT_SUBSTEP( BInitPaintKits( arrRootPaintKits[i], pVecErrors ) ); }
FOR_EACH_VEC( arrRootPaintKitsRarity, i ) { SCHEMA_INIT_SUBSTEP( BInitPaintKitsRarity( arrRootPaintKitsRarity[i], pVecErrors ) ); }
// Initialize the items block
SCHEMA_INIT_CHECK( arrRootItems.Count(), CFmtStr( "Required key(s) \"items\" missing.\n" ) ); FOR_EACH_VEC( arrRootItems, i ) { m_bSchemaParsingItems = true; SCHEMA_INIT_SUBSTEP( BInitItems( arrRootItems[i], pVecErrors ) ); m_bSchemaParsingItems = false; } SCHEMA_INIT_SUBSTEP( BInitItemMappings( pVecErrors ) );
// Setup bundle links
SCHEMA_INIT_SUBSTEP( BInitBundles( pVecErrors ) );
// Setup payment rules.
SCHEMA_INIT_SUBSTEP( BInitPaymentRules( pVecErrors ) );
// Parse the item_sets block.
FOR_EACH_VEC( arrRootItemSets, i ) { SCHEMA_INIT_SUBSTEP( BInitItemSets( arrRootItemSets[i], pVecErrors ) ); }
// Initialize the quest block
KeyValues *pKVQuestDefs = pKVRawDefinition->FindKey( "quest_definitions" ); SCHEMA_INIT_CHECK( NULL != pKVQuestDefs, CFmtStr( "Required key \"quest_definitions\" missing.\n" ) );
if ( NULL != pKVQuestDefs ) { SCHEMA_INIT_SUBSTEP( BInitQuestDefs( pKVQuestDefs, pVecErrors ) ); }
// Initialize the quest event schedule block
SCHEMA_INIT_SUBSTEP( BInitQuestEvents( pKVRawDefinition->FindKey( "quest_schedule" ), pVecErrors ) );
// Initialize the campaign block
KeyValues *pKVCampaignDefs = pKVRawDefinition->FindKey( "campaign_definitions" ); SCHEMA_INIT_CHECK( NULL != pKVCampaignDefs, CFmtStr( "Required key \"campaign_definitions\" missing.\n" ) );
if ( NULL != pKVCampaignDefs ) { SCHEMA_INIT_SUBSTEP( BInitCampaignDefs( pKVCampaignDefs, pVecErrors ) ); }
// Parse any recipes block
KeyValues *pKVRecipes = pKVRawDefinition->FindKey( "recipes" ); if ( NULL != pKVRecipes ) { SCHEMA_INIT_SUBSTEP( BInitRecipes( pKVRecipes, pVecErrors ) ); }
// Parse alternate icons block.
KeyValues * pKVAlternateIcons = pKVRawDefinition->FindKey( "alternate_icons2" ); if ( NULL != pKVAlternateIcons ) { SCHEMA_INIT_SUBSTEP( BInitAlternateIcons( pKVAlternateIcons, pVecErrors ) ); }
// Reset our loot lists.
m_dictLootLists.Purge();
// Parse the collection loot lists block
KeyValues *pKVQuestRewardLootLists = pKVRawDefinition->FindKey( "quest_reward_loot_lists" ); SCHEMA_INIT_SUBSTEP( BInitQuestRewardLootLists( pKVQuestRewardLootLists, pVecErrors ) );
// Parse the loot lists block (on the GC)
KeyValues *pKVRandomAttributeTemplates = pKVRawDefinition->FindKey( "random_attribute_templates" ); // Parse the client loot lists block (everywhere)
FOR_EACH_VEC( arrRootClientLootLists, i ) { SCHEMA_INIT_SUBSTEP( BInitLootLists( arrRootClientLootLists[i], pKVRandomAttributeTemplates, pVecErrors, false ) ); }
// Parse the revolving loot lists block
FOR_EACH_VEC( arrRootRevolvingLootlists, i ) { SCHEMA_INIT_SUBSTEP( BInitRevolvingLootLists( arrRootRevolvingLootlists[i], pVecErrors ) ); }
#if defined( CLIENT_DLL ) || defined( GAME_DLL )
KeyValues *pKVArmoryData = pKVRawDefinition->FindKey( "armory_data" ); if ( NULL != pKVArmoryData ) { SCHEMA_INIT_SUBSTEP( BInitArmoryData( pKVArmoryData, pVecErrors ) ); } #endif
// Parse any achievement rewards
KeyValues *pKVAchievementRewards = pKVRawDefinition->FindKey( "achievement_rewards" ); if ( NULL != pKVAchievementRewards ) { SCHEMA_INIT_SUBSTEP( BInitAchievementRewards( pKVAchievementRewards, pVecErrors ) ); }
#ifdef TF_CLIENT_DLL
// Compute the number of concrete items, for each item, and cache for quick access
SCHEMA_INIT_SUBSTEP( BInitConcreteItemCounts( pVecErrors ) ); #endif // TF_CLIENT_DLL
// Parse the item levels block
KeyValues *pKVItemLevels = pKVRawDefinition->FindKey( "item_levels" ); SCHEMA_INIT_SUBSTEP( BInitItemLevels( pKVItemLevels, pVecErrors ) );
// Parse the kill eater score types
KeyValues *pKVKillEaterScoreTypes = pKVRawDefinition->FindKey( "kill_eater_score_types" ); SCHEMA_INIT_SUBSTEP( BInitKillEaterScoreTypes( pKVKillEaterScoreTypes, pVecErrors ) );
#ifdef CLIENT_DLL
// Load web resource references.
KeyValues* pKVWebResources = pKVRawDefinition->FindKey( "web_resources" ); SCHEMA_INIT_SUBSTEP( BInitWebResources( pKVWebResources, pVecErrors ) ); #endif
// Load web resource references.
KeyValues* pProPlayers = pKVRawDefinition->FindKey( "pro_players" ); SCHEMA_INIT_SUBSTEP( BInitProPlayers( pProPlayers, pVecErrors ) );
SCHEMA_INIT_SUBSTEP( BPostSchemaInitStartupChecks( pVecErrors ) );
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the "game_info" section of the schema
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitGameInfo( KeyValues *pKVGameInfo, CUtlVector<CUtlString> *pVecErrors ) { m_unFirstValidClass = pKVGameInfo->GetInt( "first_valid_class", 0 ); m_unLastValidClass = pKVGameInfo->GetInt( "last_valid_class", 0 ); SCHEMA_INIT_CHECK( 0 <= m_unFirstValidClass, CFmtStr( "First valid class must be greater or equal to 0." ) ); SCHEMA_INIT_CHECK( m_unFirstValidClass <= m_unLastValidClass, CFmtStr( "First valid class must be less than or equal to last valid class." ) );
m_unFirstValidItemSlot = pKVGameInfo->GetInt( "first_valid_item_slot", INVALID_EQUIPPED_SLOT ); m_unLastValidItemSlot = pKVGameInfo->GetInt( "last_valid_item_slot", INVALID_EQUIPPED_SLOT ); SCHEMA_INIT_CHECK( INVALID_EQUIPPED_SLOT != m_unFirstValidItemSlot, CFmtStr( "first_valid_item_slot not set!" ) ); SCHEMA_INIT_CHECK( INVALID_EQUIPPED_SLOT != m_unLastValidItemSlot, CFmtStr( "last_valid_item_slot not set!" ) ); SCHEMA_INIT_CHECK( m_unFirstValidItemSlot <= m_unLastValidItemSlot, CFmtStr( "First valid item slot must be less than or equal to last valid item slot." ) );
m_unNumItemPresets = pKVGameInfo->GetInt( "num_item_presets", -1 ); SCHEMA_INIT_CHECK( (uint32)-1 != m_unNumItemPresets, CFmtStr( "num_item_presets not set!" ) );
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitAttributeTypes( CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_VEC( m_vecAttributeTypes, i ) { delete m_vecAttributeTypes[i].m_pAttrType; } m_vecAttributeTypes.Purge();
m_vecAttributeTypes.AddToTail( attr_type_t( NULL, new CSchemaAttributeType_Default ) ); m_vecAttributeTypes.AddToTail( attr_type_t( "uint32", new CSchemaAttributeType_Uint32 ) ); m_vecAttributeTypes.AddToTail( attr_type_t( "float", new CSchemaAttributeType_Float ) ); m_vecAttributeTypes.AddToTail( attr_type_t( "string", new CSchemaAttributeType_String ) ); m_vecAttributeTypes.AddToTail( attr_type_t( "vector", new CSchemaAttributeType_Vector ) );
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the "prefabs" section of the schema
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitDefinitionPrefabs( KeyValues *pKVPrefabs, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_TRUE_SUBKEY( pKVPrefabs, pKVPrefab ) { const char *pszPrefabName = pKVPrefab->GetName();
int nMapIndex = m_mapDefinitionPrefabs.Find( pszPrefabName );
// Make sure the item index is correct because we use this index as a reference
SCHEMA_INIT_CHECK( !m_mapDefinitionPrefabs.IsValidIndex( nMapIndex ), CFmtStr( "Duplicate prefab name (%s)", pszPrefabName ) );
m_mapDefinitionPrefabs.Insert( pszPrefabName, pKVPrefab->MakeCopy() ); }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the rarity section of the schema
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitRarities( KeyValues *pKVRarities, CUtlVector<CUtlString> *pVecErrors ) { // initialize the item definitions
if ( NULL != pKVRarities ) { FOR_EACH_TRUE_SUBKEY( pKVRarities, pKVRarity ) { int nRarityIndex = pKVRarity->GetInt( "value" ); int nMapIndex = m_mapRarities.Find( nRarityIndex );
// Make sure the item index is correct because we use this index as a reference
SCHEMA_INIT_CHECK( !m_mapRarities.IsValidIndex( nMapIndex ), CFmtStr( "Duplicate rarity value (%d)", nRarityIndex ) );
nMapIndex = m_mapRarities.Insert( nRarityIndex ); SCHEMA_INIT_SUBSTEP( m_mapRarities[nMapIndex].BInitFromKV( pKVRarity, *this, pVecErrors ) ); } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the qualities section of the schema
// Input: pKVQualities - The qualities section of the KeyValues
// representation of the schema
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitQualities( KeyValues *pKVQualities, CUtlVector<CUtlString> *pVecErrors ) { // initialize the item definitions
if ( NULL != pKVQualities ) { FOR_EACH_TRUE_SUBKEY( pKVQualities, pKVQuality ) { int nQualityIndex = pKVQuality->GetInt( "value" ); int nMapIndex = m_mapQualities.Find( nQualityIndex );
// Make sure the item index is correct because we use this index as a reference
SCHEMA_INIT_CHECK( !m_mapQualities.IsValidIndex( nMapIndex ), CFmtStr( "Duplicate quality value (%d)", nQualityIndex ) );
nMapIndex = m_mapQualities.Insert( nQualityIndex ); SCHEMA_INIT_SUBSTEP( m_mapQualities[nMapIndex].BInitFromKV( pKVQuality, *this, pVecErrors ) ); } }
// Check the integrity of the quality definitions
// Check for duplicate quality names
CUtlRBTree<const char *> rbQualityNames( CaselessStringLessThan ); rbQualityNames.EnsureCapacity( m_mapQualities.Count() ); FOR_EACH_MAP_FAST( m_mapQualities, i ) { int iIndex = rbQualityNames.Find( m_mapQualities[i].GetName() ); SCHEMA_INIT_CHECK( !rbQualityNames.IsValidIndex( iIndex ), CFmtStr( "Quality definition %d: Duplicate quality name %s", m_mapQualities[i].GetDBValue(), m_mapQualities[i].GetName() ) );
if( !rbQualityNames.IsValidIndex( iIndex ) ) rbQualityNames.Insert( m_mapQualities[i].GetName() ); }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitColors( KeyValues *pKVColors, CUtlVector<CUtlString> *pVecErrors ) { // initialize the color definitions
if ( NULL != pKVColors ) { FOR_EACH_TRUE_SUBKEY( pKVColors, pKVColor ) { CEconColorDefinition *pNewColorDef = new CEconColorDefinition;
SCHEMA_INIT_SUBSTEP( pNewColorDef->BInitFromKV( pKVColor, *this, pVecErrors ) ); m_vecColorDefs.AddToTail( pNewColorDef ); } }
return SCHEMA_INIT_SUCCESS(); }
bool CEconItemSchema::BInitGraffitiTints( KeyValues *pKVColors, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_TRUE_SUBKEY( pKVColors, pKVColor ) { CEconGraffitiTintDefinition *pNewDef = new CEconGraffitiTintDefinition;
bool bResult = pNewDef->BInitFromKV( pKVColor, *this, pVecErrors ); const int nMaxIDallowed = 64; if ( bResult ) { SCHEMA_INIT_CHECK( ( pNewDef->GetID() > 0 ) && ( pNewDef->GetID() < nMaxIDallowed ), CFmtStr( "Graffiti tint definition id out of range [1..%d]: #%d %s\n", nMaxIDallowed, pNewDef->GetID(), pNewDef->GetColorName() ) ); SCHEMA_INIT_CHECK( !m_vecGraffitiTintDefs.IsValidIndex( pNewDef->GetID() ) || !m_vecGraffitiTintDefs[pNewDef->GetID()], CFmtStr( "Graffiti tint definition duplicate: #%d %s\n", pNewDef->GetID(), pNewDef->GetColorName() ) ); SCHEMA_INIT_CHECK( pNewDef->GetColorName() && *pNewDef->GetColorName() && !m_mapGraffitiTintByName.Defined( pNewDef->GetColorName() ), CFmtStr( "Graffiti tint name duplicate: #%d %s\n", pNewDef->GetID(), pNewDef->GetColorName() ) ); bResult &= ( pNewDef->GetID() > 0 ) && ( pNewDef->GetID() < nMaxIDallowed ) && ( !m_vecGraffitiTintDefs.IsValidIndex( pNewDef->GetID() ) || !m_vecGraffitiTintDefs[pNewDef->GetID()] ) && pNewDef->GetColorName() && *pNewDef->GetColorName() && !m_mapGraffitiTintByName.Defined( pNewDef->GetColorName() ); } if ( !bResult ) { SCHEMA_INIT_SUBSTEP( bResult ); delete pNewDef; } else { if ( !m_vecGraffitiTintDefs.Count() ) { for ( int j = 0; j < nMaxIDallowed; ++ j ) m_vecGraffitiTintDefs.AddToTail( NULL ); } m_vecGraffitiTintDefs[pNewDef->GetID()] = pNewDef; m_mapGraffitiTintByName[pNewDef->GetColorName()] = pNewDef; m_nMaxValidGraffitiTintDefID = MAX( m_nMaxValidGraffitiTintDefID, pNewDef->GetID() ); } }
SCHEMA_INIT_CHECK( m_vecGraffitiTintDefs.Count() > 0, CFmtStr( "Graffiti tint definitions failed to parse\n" ) );
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
AlternateIconData_t* CEconItemSchema::GetAlternateIcon( uint64 ullAlternateIcon ) { int iIdx = m_mapAlternateIcons.Find( ullAlternateIcon ); if ( !m_mapAlternateIcons.IsValidIndex( iIdx ) ) return NULL; else return &(m_mapAlternateIcons[iIdx]); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the rarity section of the schema
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitSoundMaterials( KeyValues *pKVSoundMaterials, CUtlVector<CUtlString> *pVecErrors ) { // initialize the item definitions
if ( NULL != pKVSoundMaterials ) { FOR_EACH_TRUE_SUBKEY( pKVSoundMaterials, pKVSoundMaterial ) { int nSoundMaterialIndex = pKVSoundMaterial->GetInt( "value" ); int nMapIndex = m_mapSoundMaterials.Find( nSoundMaterialIndex );
// Make sure the item index is correct because we use this index as a reference
SCHEMA_INIT_CHECK( !m_mapSoundMaterials.IsValidIndex( nMapIndex ), CFmtStr( "Duplicate sound material value (%d)", nSoundMaterialIndex ) );
nMapIndex = m_mapSoundMaterials.Insert( nSoundMaterialIndex ); SCHEMA_INIT_SUBSTEP( m_mapSoundMaterials[nMapIndex].BInitFromKV( pKVSoundMaterial, *this, pVecErrors ) ); } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CEconItemSchema::GetEquipRegionIndexByName( const char *pRegionName ) const { FOR_EACH_VEC( m_vecEquipRegionsList, i ) { const char *szEntryRegionName = m_vecEquipRegionsList[i].m_sName; if ( !V_stricmp( szEntryRegionName, pRegionName ) ) return i; }
return -1; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
equip_region_mask_t CEconItemSchema::GetEquipRegionBitMaskByName( const char *pRegionName ) const { int iRegionIndex = GetEquipRegionIndexByName( pRegionName ); if ( !m_vecEquipRegionsList.IsValidIndex( iRegionIndex ) ) return 0;
equip_region_mask_t unRegionMask = 1 << m_vecEquipRegionsList[iRegionIndex].m_unBitIndex; Assert( unRegionMask > 0 );
return unRegionMask; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconItemSchema::SetEquipRegionConflict( int iRegion, unsigned int unBit ) { Assert( m_vecEquipRegionsList.IsValidIndex( iRegion ) );
equip_region_mask_t unRegionMask = 1 << unBit; Assert( unRegionMask > 0 );
m_vecEquipRegionsList[iRegion].m_unMask |= unRegionMask; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
equip_region_mask_t CEconItemSchema::GetEquipRegionMaskByName( const char *pRegionName ) const { int iRegionIdx = GetEquipRegionIndexByName( pRegionName ); if ( iRegionIdx < 0 ) return 0;
return m_vecEquipRegionsList[iRegionIdx].m_unMask; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconItemSchema::AssignDefaultBodygroupState( const char *pszBodygroupName, int iValue ) { // Flip the value passed in -- if we specify in the schema that a region should be off, we assume that it's
// on by default.
int iDefaultValue = iValue == 0 ? 1 : 0;
// Make sure that we're constantly reinitializing our default value to the same default value. This is sort
// of dumb but it works for everything we've got now. In the event that conflicts start cropping up it would
// be easy enough to make a new schema section.
int iIndex = m_mapDefaultBodygroupState.Find( pszBodygroupName ); if ( (m_mapDefaultBodygroupState.IsValidIndex( iIndex ) && m_mapDefaultBodygroupState[iIndex] != iDefaultValue) || (iValue < 0 || iValue > 1) ) { EmitWarning( SPEW_GC, 4, "Unable to get accurate read on whether bodygroup '%s' is enabled or disabled by default. (The schema is fine, but the code is confused and could stand to be made smarter.)\n", pszBodygroupName ); }
if ( !m_mapDefaultBodygroupState.IsValidIndex( iIndex ) ) { m_mapDefaultBodygroupState.Insert( pszBodygroupName, iDefaultValue ); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitEquipRegions( KeyValues *pKVEquipRegions, CUtlVector<CUtlString> *pVecErrors ) { CUtlVector<const char *> vecNames;
FOR_EACH_SUBKEY( pKVEquipRegions, pKVRegion ) { const char *pRegionKeyName = pKVRegion->GetName();
vecNames.Purge();
// The "shared" name is special for equip regions -- it means that all of the sub-regions specified
// will use the same bit to store equipped-or-not data, but that one bit can be accessed by a whole
// bunch of different names. This is useful in TF where different classes have different regions, but
// those regions cannot possibly conflict with each other. For example, "scout_backpack" cannot possibly
// overlap with "pyro_shoulder" because they can't even be equipped on the same character.
if ( pRegionKeyName && !Q_stricmp( pRegionKeyName, "shared" ) ) { FOR_EACH_SUBKEY( pKVRegion, pKVSharedRegionName ) { vecNames.AddToTail( pKVSharedRegionName->GetName() ); } } // We have a standard name -- this one entry is its own equip region.
else { vecNames.AddToTail( pRegionKeyName ); }
// What bit will this equip region use to mask against conflicts? If we don't have any equip regions
// at all, we'll use the base bit, otherwise we just grab one higher than whatever we used last.
unsigned int unNewBitIndex = m_vecEquipRegionsList.Count() <= 0 ? 0 : m_vecEquipRegionsList.Tail().m_unBitIndex + 1; FOR_EACH_VEC( vecNames, i ) { const char *pRegionName = vecNames[i];
// Make sure this name is unique.
if ( GetEquipRegionIndexByName( pRegionName ) >= 0 ) { pVecErrors->AddToTail( CFmtStr( "Duplicate equip region named \"%s\".", pRegionName ).Access() ); continue; }
// Make a new region.
EquipRegion newEquipRegion; newEquipRegion.m_sName = pRegionName; newEquipRegion.m_unMask = 0; // we'll update this mask later
newEquipRegion.m_unBitIndex = unNewBitIndex;
int iIdx = m_vecEquipRegionsList.AddToTail( newEquipRegion );
// Tag this region to conflict with itself so that if nothing else two items in the same
// region can't equip over each other.
SetEquipRegionConflict( iIdx, unNewBitIndex ); } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitEquipRegionConflicts( KeyValues *pKVEquipRegionConflicts, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_TRUE_SUBKEY( pKVEquipRegionConflicts, pKVConflict ) { // What region is the base of this conflict?
const char *pRegionName = pKVConflict->GetName(); int iRegionIdx = GetEquipRegionIndexByName( pRegionName ); if ( iRegionIdx < 0 ) { pVecErrors->AddToTail( CFmtStr( "Unable to find base equip region named \"%s\" for conflicts.", pRegionName ).Access() ); continue; }
FOR_EACH_SUBKEY( pKVConflict, pKVConflictOther ) { const char *pOtherRegionName = pKVConflictOther->GetName(); int iOtherRegionIdx = GetEquipRegionIndexByName( pOtherRegionName ); if ( iOtherRegionIdx < 0 ) { pVecErrors->AddToTail( CFmtStr( "Unable to find other equip region named \"%s\" for conflicts.", pOtherRegionName ).Access() ); continue; }
SetEquipRegionConflict( iRegionIdx, m_vecEquipRegionsList[iOtherRegionIdx].m_unBitIndex ); SetEquipRegionConflict( iOtherRegionIdx, m_vecEquipRegionsList[iRegionIdx].m_unBitIndex ); } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the attributes section of the schema
// Input: pKVAttributes - The attributes section of the KeyValues
// representation of the schema
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitAttributes( KeyValues *pKVAttributes, CUtlVector<CUtlString> *pVecErrors ) { // Initialize the attribute definitions
FOR_EACH_TRUE_SUBKEY( pKVAttributes, pKVAttribute ) { int nAttrIndex = Q_atoi( pKVAttribute->GetName() ); // Make sure the index is positive
SCHEMA_INIT_CHECK( ( nAttrIndex >= 0 ) && ( nAttrIndex < 30*1000 ), CFmtStr( "Attribute definition index %d must be greater than or equal to zero", nAttrIndex ) );
if ( !( ( nAttrIndex >= 0 ) && ( nAttrIndex < 30*1000 ) ) ) continue;
// Build the direct mapping container
while ( nAttrIndex >= m_mapAttributesContainer.Count() ) m_mapAttributesContainer.AddToTail( NULL ); Assert( nAttrIndex < m_mapAttributesContainer.Count() );
// Make sure the attribute index is not repeated
SCHEMA_INIT_CHECK( !m_mapAttributesContainer[nAttrIndex], CFmtStr( "Duplicate attribute definition index (%d)", nAttrIndex ) ); if ( m_mapAttributesContainer[nAttrIndex] ) continue;
m_mapAttributesContainer[nAttrIndex] = new CEconItemAttributeDefinition; SCHEMA_INIT_SUBSTEP( m_mapAttributesContainer[nAttrIndex]->BInitFromKV( pKVAttribute, *this, pVecErrors ) ); }
// Check the integrity of the attribute definitions
// Check for duplicate attribute definition names
CUtlRBTree<const char *> rbAttributeNames( CaselessStringLessThan ); rbAttributeNames.EnsureCapacity( m_mapAttributesContainer.Count() ); FOR_EACH_VEC( m_mapAttributesContainer, i ) { if ( !m_mapAttributesContainer[i] ) continue;
int iIndex = rbAttributeNames.Find( m_mapAttributesContainer[i]->GetDefinitionName() ); SCHEMA_INIT_CHECK( !rbAttributeNames.IsValidIndex( iIndex ), CFmtStr( "Attribute definition %d: Duplicate name \"%s\"", i, m_mapAttributesContainer[i]->GetDefinitionName() ) ); if( !rbAttributeNames.IsValidIndex( iIndex ) ) rbAttributeNames.Insert( m_mapAttributesContainer[i]->GetDefinitionName() ); }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: After bundles are set up, we can do payment rules.
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitPaymentRules( CUtlVector<CUtlString> *pVecErrors ) { return true; }
//-----------------------------------------------------------------------------
// Purpose: After items are initialized, this method links bundles to their contents.
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitBundles( CUtlVector<CUtlString> *pVecErrors ) { // Link each bundle with its contents.
FOR_EACH_MAP_FAST( m_mapItems, i ) { CEconItemDefinition *pItemDef = m_mapItems[ i ]; if ( !pItemDef ) continue;
KeyValues* pItemKV = pItemDef->GetRawDefinition(); if ( !pItemKV ) continue;
KeyValues *pBundleDataKV = pItemKV->FindKey( "bundle" ); if ( pBundleDataKV ) { pItemDef->m_BundleInfo = new bundleinfo_t(); FOR_EACH_SUBKEY( pBundleDataKV, pKVCurItem ) { item_list_entry_t entry; bool bEntrySuccess = entry.InitFromName( pKVCurItem->GetName() );
SCHEMA_INIT_CHECK( bEntrySuccess, CFmtStr( "Bundle %s: Item definition \"%s\" failed to initialize\n", pItemDef->m_pszDefinitionName, pKVCurItem->GetName() ) );
const CEconItemDefinition *pBundleItemDef = GetItemDefinition( entry.m_nItemDef ); SCHEMA_INIT_CHECK( pBundleItemDef, CFmtStr( "Unable to find item definition '%s' for bundle '%s'.", pKVCurItem->GetName(), pItemDef->m_pszDefinitionName ) );
pItemDef->m_BundleInfo->vecItemEntries.AddToTail( entry ); }
// Only check for pack bundle if the item is actually a bundle - note that we could do this programatically by checking that all items in the bundle are flagged as a "pack item" - but for now the bundle needs to be explicitly flagged as a pack bundle.
pItemDef->m_bIsPackBundle = pItemKV->GetInt( "is_pack_bundle", 0 ) != 0; }
// Make a list of all of our bundles.
if ( pItemDef->IsBundle() ) { // Cache off the item def for the bundle, since we'll need both the bundle info and the item def index later.
m_vecBundles.AddToTail( pItemDef );
// If the bundle is a pack bundle, mark all the contained items as pack items / link to the owning pack bundle
if ( pItemDef->IsPackBundle() ) { const bundleinfo_t *pBundleInfo = pItemDef->GetBundleInfo(); FOR_EACH_VEC( pBundleInfo->vecItemEntries, iCurItem ) { CEconItemDefinition *pCurItemDef = GetItemDefinitionMutable( pBundleInfo->vecItemEntries[ iCurItem ].m_nItemDef ); SCHEMA_INIT_CHECK( NULL == pCurItemDef->m_pOwningPackBundle, CFmtStr( "Pack item \"%s\" included in more than one pack bundle - not allowed!", pCurItemDef->GetDefinitionName() ) ); pCurItemDef->m_pOwningPackBundle = pItemDef; } } } }
// Go through all regular (ie non-pack) bundles and ensure that if any pack items are included, *all* pack items in the owning pack bundle are included.
FOR_EACH_VEC( m_vecBundles, iBundle ) { const CEconItemDefinition *pBundleItemDef = m_vecBundles[ iBundle ]; if ( pBundleItemDef->IsPackBundle() ) continue;
// Go through all items in the bundle and look for pack items
const bundleinfo_t *pBundle = pBundleItemDef->GetBundleInfo(); if ( pBundle ) { FOR_EACH_VEC( pBundle->vecItemEntries, iContainedBundleItem ) { // Get the associated pack bundle
const CEconItemDefinition *pContainedBundleItemDef = GetItemDefinition( pBundle->vecItemEntries[ iContainedBundleItem ].m_nItemDef );
// Ignore non-pack items
if ( !pContainedBundleItemDef || !pContainedBundleItemDef->IsPackItem() ) continue;
// Get the pack bundle that contains this particular pack item
const CEconItemDefinition *pOwningPackBundleItemDef = pContainedBundleItemDef->GetOwningPackBundle();
// Make sure all items in the owning pack bundle are in pBundleItemDef's bundle info (pBundle)
const bundleinfo_t *pOwningPackBundle = pOwningPackBundleItemDef->GetBundleInfo(); FOR_EACH_VEC( pOwningPackBundle->vecItemEntries, iCurPackBundleItem ) { bool bFound = false; FOR_EACH_VEC( pBundle->vecItemEntries, i ) { if ( pOwningPackBundle->vecItemEntries[ iCurPackBundleItem ].m_nItemDef == pBundle->vecItemEntries[ i ].m_nItemDef && pOwningPackBundle->vecItemEntries[ iCurPackBundleItem ].m_nPaintKit == pBundle->vecItemEntries[ i ].m_nPaintKit ) { bFound = true; break; } }
if ( !bFound ) { SCHEMA_INIT_CHECK( false, CFmtStr( "The bundle \"%s\" contains some, but not all pack items required specified by pack bundle \"%s.\"", pBundleItemDef->GetDefinitionName(), pOwningPackBundleItemDef->GetDefinitionName() ) ); } } } } }
return true; }
//-----------------------------------------------------------------------------
// Purpose: Initializes the items section of the schema
// Input: pKVItems - The items section of the KeyValues
// representation of the schema
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitItems( KeyValues *pKVItems, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_TRUE_SUBKEY( pKVItems, pKVItem ) { if ( Q_stricmp( pKVItem->GetName(), "default" ) == 0 ) { #if defined(CLIENT_DLL) || defined(GAME_DLL)
SCHEMA_INIT_CHECK( m_pDefaultItemDefinition == NULL, CFmtStr( "Duplicate 'default' item definition." ) );
if ( m_pDefaultItemDefinition == NULL ) { m_pDefaultItemDefinition = CreateEconItemDefinition(); } SCHEMA_INIT_SUBSTEP( m_pDefaultItemDefinition->BInitFromKV( pKVItem, *this, pVecErrors ) ); #endif
} else { int nItemIndex = Q_atoi( pKVItem->GetName() ); int nMapIndex = m_mapItems.Find( nItemIndex );
// Make sure the item index is correct because we use this index as a reference
SCHEMA_INIT_CHECK( !m_mapItems.IsValidIndex( nMapIndex ), CFmtStr( "Duplicate item definition (%d)", nItemIndex ) );
// Check to make sure the index is positive
SCHEMA_INIT_CHECK( nItemIndex >= 0, CFmtStr( "Item definition index %d must be greater than or equal to zero", nItemIndex ) );
CEconItemDefinition *pItemDef = CreateEconItemDefinition(); nMapIndex = m_mapItems.Insert( nItemIndex, pItemDef ); m_mapItemsSorted.Insert( nItemIndex, pItemDef ); SCHEMA_INIT_SUBSTEP( m_mapItems[nMapIndex]->BInitFromKV( pKVItem, *this, pVecErrors ) ); } }
return SCHEMA_INIT_SUCCESS(); }
bool CEconItemSchema::BInitItemMappings( CUtlVector<CUtlString> *pVecErrors ) { // Check the integrity of the item definitions
CUtlRBTree<const char *> rbItemNames( CaselessStringLessThan ); rbItemNames.EnsureCapacity( m_mapItems.Count() ); FOR_EACH_MAP_FAST( m_mapItems, i ) { CEconItemDefinition *pItemDef = m_mapItems[ i ];
// Check for duplicate item definition names
int iIndex = rbItemNames.Find( pItemDef->GetDefinitionName() ); SCHEMA_INIT_CHECK( !rbItemNames.IsValidIndex( iIndex ), CFmtStr( "Item definition %s: Duplicate name on index %d", pItemDef->GetDefinitionName(), m_mapItems.Key( i ) ) ); if( !rbItemNames.IsValidIndex( iIndex ) ) rbItemNames.Insert( m_mapItems[i]->GetDefinitionName() );
// Link up armory and store mappings for the item
SCHEMA_INIT_SUBSTEP( pItemDef->BInitItemMappings( *this, pVecErrors ) ); }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Delete an item definition. Moderately dangerous as cached references will become bad.
// Intended for use by the item editor.
//-----------------------------------------------------------------------------
bool CEconItemSchema::DeleteItemDefinition( int iDefIndex ) { m_mapItemsSorted.Remove( iDefIndex );
int nMapIndex = m_mapItems.Find( iDefIndex ); if ( m_mapItems.IsValidIndex( nMapIndex ) ) { CEconItemDefinition* pItemDef = m_mapItems[nMapIndex]; if ( pItemDef ) { m_mapItems.RemoveAt( nMapIndex ); delete pItemDef; return true; } } return false; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const CEconItemSetDefinition* CEconItemSchema::GetItemSet( const char* pSetName, int *piIndex ) const { for ( unsigned int i=0; i<m_mapItemSets.Count(); ++i ) { if ( !Q_strcmp( m_mapItemSets.Key(i), pSetName ) ) { if ( piIndex ) { *piIndex = i; } return (CEconItemSetDefinition*) &(m_mapItemSets[i]); } }
return NULL; }
const IEconItemSetDefinition* CEconItemSchema::GetItemSet( int iIndex ) const { if ( m_mapItemSets.IsValidIndex( iIndex ) ) return &m_mapItemSets[iIndex]; else return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Parses the Item Sets section.
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitItemSets( KeyValues *pKVItemSets, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_TRUE_SUBKEY( pKVItemSets, pKVItemSet ) { const char* setName = pKVItemSet->GetName();
SCHEMA_INIT_CHECK( setName != NULL, CFmtStr( "All itemsets must have names.") );
if ( m_mapItemSets.Count() > 0 ) { SCHEMA_INIT_CHECK( GetItemSet( setName ) == NULL, CFmtStr( "Duplicate itemset name (%s) found!", setName ) ); }
int idx = m_mapItemSets.Insert( setName ); SCHEMA_INIT_SUBSTEP( m_mapItemSets[idx].BInitFromKV( pKVItemSet, *this, pVecErrors ) );
FOR_EACH_VEC( m_mapItemSets[idx].m_ItemEntries, nEntry ) { item_list_entry_t &itemListEntry = m_mapItemSets[idx].m_ItemEntries[ nEntry ]; CEconItemDefinition *pItemDef = GetItemDefinitionMutable( itemListEntry.m_nItemDef ); if ( pItemDef ) { pItemDef->AddItemSet( idx ); } } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the timed rewards section of the schema
// Input: pKVTimedRewards - The timed_rewards section of the KeyValues
// representation of the schema
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitTimedRewards( KeyValues *pKVTimedRewards, CUtlVector<CUtlString> *pVecErrors ) { m_vecTimedRewards.Purge();
// initialize the rewards sections
if ( NULL != pKVTimedRewards ) { FOR_EACH_TRUE_SUBKEY( pKVTimedRewards, pKVTimedReward ) { int index = m_vecTimedRewards.AddToTail(); SCHEMA_INIT_SUBSTEP( m_vecTimedRewards[index].BInitFromKV( pKVTimedReward, *this, pVecErrors ) ); } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const CTimedItemRewardDefinition* CEconItemSchema::GetTimedReward( eTimedRewardType type ) const { if ( (int)type < m_vecTimedRewards.Count() ) { return &m_vecTimedRewards[type]; } return NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const CEconLootListDefinition* CEconItemSchema::GetLootListByName( const char* pListName, int *out_piIndex ) const { int iIdx = m_dictLootLists.Find( pListName ); if ( out_piIndex ) *out_piIndex = iIdx; if ( m_dictLootLists.IsValidIndex( iIdx ) ) return &m_dictLootLists[iIdx]; else return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Initializes the loot lists section of the schema
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitLootLists( KeyValues *pKVLootLists, KeyValues *pKVRandomAttributeTemplates, CUtlVector<CUtlString> *pVecErrors, bool bServerLists ) { FOR_EACH_TRUE_SUBKEY( pKVLootLists, pKVLootList ) { const char* listName = pKVLootList->GetName();
SCHEMA_INIT_CHECK( listName != NULL, CFmtStr( "All lootlists must have names.") );
if ( m_dictLootLists.Count() > 0 ) { SCHEMA_INIT_CHECK( GetLootListByName( listName ) == NULL, CFmtStr( "Duplicate lootlist name (%s) found!", listName ) ); }
int idx = m_dictLootLists.Insert( listName ); SCHEMA_INIT_SUBSTEP( m_dictLootLists[idx].BInitFromKV( pKVLootList, pKVRandomAttributeTemplates, *this, pVecErrors, bServerLists ) ); }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the revolving loot lists section of the schema
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitRevolvingLootLists( KeyValues *pKVLootLists, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_SUBKEY( pKVLootLists, pKVList ) { int iListIdx = atoi( pKVList->GetName() ); const char* strListName = pKVList->GetString(); m_mapRevolvingLootLists.Insert( iListIdx, strListName ); }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the quest reward loot lists section of the schema
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitQuestRewardLootLists( KeyValues *pKVLootLists, CUtlVector<CUtlString> *pVecErrors ) { m_mapQuestRewardLootLists.Purge();
if ( NULL != pKVLootLists ) { FOR_EACH_SUBKEY( pKVLootLists, pKVList ) { int iListIdx = atoi( pKVList->GetName() ); const char* strListName = pKVList->GetString(); m_mapQuestRewardLootLists.Insert( iListIdx, strListName ); } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Alternate Icons
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitAlternateIcons( KeyValues *pKVAlternateIcons, CUtlVector<CUtlString> *pVecErrors ) { m_mapAlternateIcons.Purge();
FOR_EACH_TRUE_SUBKEY( pKVAlternateIcons, pKVBlock ) { bool bSprayTints = !V_stricmp( pKVBlock->GetName(), "spray_tint_icons" );
FOR_EACH_TRUE_SUBKEY( pKVBlock, pKVAlternateIcon ) { if ( bSprayTints ) { // Custom readable syntax for spray tints:
uint32 unSprayKitID = 0, unTintID1 = 0, unTintID2 = 0; if ( 3 == sscanf( pKVAlternateIcon->GetName(), "%u:%u:%u", &unSprayKitID, &unTintID1, &unTintID2 ) ) { CFmtStr fmtValueLookup( "icon_path_range:%u:%u", unTintID1, unTintID2 ); char const *szIconPath = pKVAlternateIcon->GetString( fmtValueLookup ); if ( szIconPath && *szIconPath ) { for ( uint32 unTintID = unTintID1; unTintID <= unTintID2; ++unTintID ) { uint64 ullAltIconKey = Helper_GetAlternateIconKeyForTintedStickerItem( unSprayKitID, unTintID ); BInitAlternateIcon( ullAltIconKey, CFmtStr( "%s_%u", szIconPath, unTintID ), pKVAlternateIcon, pVecErrors ); } } else { SCHEMA_INIT_CHECK( false, CFmtStr( "Alternate icon '%s' > '%s' must define '%s'", pKVBlock->GetName(), pKVAlternateIcon->GetName(), fmtValueLookup.Get() ) ); } } } else { uint64 ullAltIconKey = V_atoui64( pKVAlternateIcon->GetName() ); char const *szIconPath = pKVAlternateIcon->GetString( "icon_path" ); if ( szIconPath && *szIconPath ) { BInitAlternateIcon( ullAltIconKey, szIconPath, pKVAlternateIcon, pVecErrors ); } else { SCHEMA_INIT_CHECK( false, CFmtStr( "Alternate icon '%s' > '%s' must define '%s'", pKVBlock->GetName(), pKVAlternateIcon->GetName(), "icon_path" ) ); } } } }
return SCHEMA_INIT_SUCCESS(); }
bool CEconItemSchema::BInitAlternateIcon( uint64 ullAltIconKey, char const *szSimpleName, KeyValues *pKVAlternateIcon, CUtlVector<CUtlString> *pVecErrors ) { SCHEMA_INIT_CHECK( !m_mapAlternateIcons.IsValidIndex( m_mapAlternateIcons.Find( ullAltIconKey ) ), CFmtStr( "Duplicate alternate icon definition '%s' (%llu)", pKVAlternateIcon->GetName(), ullAltIconKey ) );
SCHEMA_INIT_CHECK( int64( ullAltIconKey ) > 0, CFmtStr( "Alternate icon definition index '%s' (%llu) must be greater than zero", pKVAlternateIcon->GetName(), ullAltIconKey ) );
int nNew = m_mapAlternateIcons.Insert( ullAltIconKey ); m_mapAlternateIcons[ nNew ].sSimpleName = szSimpleName; m_mapAlternateIcons[ nNew ].sLargeSimpleName.Format( "%s_large", szSimpleName );
return true; }
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Web Resources
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitWebResources( KeyValues *pKVWebResources, CUtlVector<CUtlString> *pVecErrors ) { if ( CWebResource::s_Initialized || !pKVWebResources ) return true;
FOR_EACH_SUBKEY( pKVWebResources, pDef ) { CWebResource* pWebResource = new CWebResource; pWebResource->m_strName = pDef->GetString( "name" ); pWebResource->m_strURL = pDef->GetString( "url" ); pWebResource->m_bOnDemand = pDef->GetBool( "on_demand" ); pWebResource->m_pKeyValues = NULL; pWebResource->m_fnLoadCallback = NULL; m_dictWebResources.Insert( pDef->GetString( "name" ), pWebResource ); }
if ( CommandLine()->CheckParm( "-enabledownloadtest" ) ) { CWebResource* pWebResource = new CWebResource; pWebResource->m_strName = "Test"; pWebResource->m_strURL = "http://media.steampowered.com/apps/570/test/test.txt"; pWebResource->m_bOnDemand = true; pWebResource->m_pKeyValues = NULL; pWebResource->m_fnLoadCallback = NULL; m_dictWebResources.Insert( "Test", pWebResource ); }
// If any of our resources need to be requested immediately, do it now.
FOR_EACH_DICT_FAST( m_dictWebResources, idx ) { CWebResource* pWebResource = m_dictWebResources[idx]; if ( !pWebResource ) continue;
if ( !pWebResource->m_bOnDemand ) { LoadWebResource( pWebResource->m_strName, NULL ); } }
CWebResource::s_Initialized = true;
return SCHEMA_INIT_SUCCESS(); }
EWebResourceStatus CEconItemSchema::LoadWebResource( CUtlString strName, void (*fnCallback)( const char*, KeyValues* ), bool bForceReload ) { return kWebResource_NotLoaded; }
void CEconItemSchema::SetWebResource( CUtlString strName, KeyValues* pResourceKV ) { int idx = m_dictWebResources.Find( strName.Get() ); if ( !m_dictWebResources.IsValidIndex( idx ) ) return;
CWebResource* pResource = m_dictWebResources[idx]; if ( pResource->m_pKeyValues ) { pResource->m_pKeyValues->deleteThis(); pResource->m_pKeyValues = NULL; } pResource->m_pKeyValues = pResourceKV; if ( pResource->m_fnLoadCallback ) pResource->m_fnLoadCallback( strName.Get(), pResourceKV ); }
#endif
bool CEconItemSchema::BInitProPlayers( KeyValues *pKVData, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_SUBKEY( pKVData, pDef ) { // Create the pro player entry
CProPlayerData *pData = new CProPlayerData; if ( !pData->BInitFromKeyValues( pDef, pVecErrors ) ) { delete pData; continue; }
if ( m_mapProPlayersByAccountID.Find( pData->GetAccountID() ) != m_mapProPlayersByAccountID.InvalidIndex() ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Pro-player entry '%s' maps to a duplicate AccountID", pDef->GetName() ) ); Assert( false ); delete pData; continue; }
if ( m_mapProPlayersByCode.Find( pData->GetCode() ) != UTL_INVAL_SYMBOL ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Pro-player entry '%s' has a duplicate code '%s'", pDef->GetName(), pData->GetCode() ) ); Assert( false ); delete pData; continue; }
m_mapProPlayersByAccountID.InsertOrReplace( pData->GetAccountID(), pData ); FOR_EACH_TRUE_SUBKEY( pDef->FindKey( "events" ), kvEvent ) { int nEventID = Q_atoi( kvEvent->GetName() ); int nTeamID = kvEvent->GetInt( "team" ); if ( nEventID && nTeamID ) { uint64 uiKey = ( uint64( uint32( nEventID ) ) << 32 ) | uint32( nTeamID ); MapProPlayersByEventIDTeamID_t::IndexType_t idx = m_mapProPlayersByEventIDTeamID.Find( uiKey ); if ( idx == m_mapProPlayersByEventIDTeamID.InvalidIndex() ) idx = m_mapProPlayersByEventIDTeamID.InsertOrReplace( uiKey, new CUtlVector< const CProPlayerData * > ); m_mapProPlayersByEventIDTeamID.Element( idx )->AddToTail( pData ); } } }
return SCHEMA_INIT_SUCCESS(); }
const CProPlayerData * CEconItemSchema::GetProPlayerDataByAccountID( uint32 unAccountID ) const { MapProPlayersByAccountID_t::IndexType_t idx = m_mapProPlayersByAccountID.Find( unAccountID ); return ( idx == m_mapProPlayersByAccountID.InvalidIndex() ) ? NULL : m_mapProPlayersByAccountID.Element( idx ); }
const CUtlVector< const CProPlayerData * > * CEconItemSchema::GetProPlayersDataForEventIDTeamID( int nEventID, int nTeamID ) const { uint64 uiKey = ( uint64( uint32( nEventID ) ) << 32 ) | uint32( nTeamID ); MapProPlayersByEventIDTeamID_t::IndexType_t idx = m_mapProPlayersByEventIDTeamID.Find( uiKey ); return ( idx != m_mapProPlayersByEventIDTeamID.InvalidIndex() ) ? m_mapProPlayersByEventIDTeamID.Element( idx ) : NULL; }
bool CProPlayerData::BInitFromKeyValues( KeyValues *pDef, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) { uint32 unAccountID = Q_atoi( pDef->GetName() ); SCHEMA_INIT_CHECK( unAccountID != 0, CFmtStr( "Pro-player entry '%s' doesn't have a valid AccountID", pDef->GetName() ) ); if ( !unAccountID ) return false; m_nAccountID = unAccountID;
char const *szName = pDef->GetString( "name" ); if ( !szName || !*szName ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Pro-player entry '%s' has no name", pDef->GetName() ) ); Assert( false ); return false; } m_sName = szName;
char const *szCode = pDef->GetString( "code" ); if ( !szCode || !*szCode ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Pro-player entry '%s' has no code", pDef->GetName() ) ); Assert( false ); return false; } HelperValidateLocalizationStringToken( CFmtStr( "#SFUI_ProPlayer_%s", szCode ) ); m_sCode = szCode;
char const *szGeo = pDef->GetString( "geo" ); SCHEMA_INIT_CHECK( szGeo && *szGeo, CFmtStr( "Pro-player entry '%s' has no geo defined", pDef->GetName() ) ); Assert( szGeo && *szGeo ); HelperValidateLocalizationStringToken( CFmtStr( "#SFUI_Country_%s", szGeo ) ); m_sGeo = szGeo;
m_pKVItem = pDef->MakeCopy();
return true; // typically it should be return SCHEMA_INIT_SUCCESS(); but we don't want spurious "doesn't have a matching pro-player entry" errors
}
//-----------------------------------------------------------------------------
// Purpose: Initializes the recipes section of the schema
// Input: pKVRecipes - The recipes section of the KeyValues
// representation of the schema
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitRecipes( KeyValues *pKVRecipes, CUtlVector<CUtlString> *pVecErrors ) { m_mapRecipes.Purge();
// initialize the rewards sections
if ( NULL != pKVRecipes ) { int nHighestRecipeIndex = 0; FOR_EACH_TRUE_SUBKEY( pKVRecipes, pKVRecipe ) { int nRecipeIndex = Q_atoi( pKVRecipe->GetName() );
// Remember highest recipe index so we can make more past that
if ( nHighestRecipeIndex < nRecipeIndex + 1 ) { nHighestRecipeIndex = nRecipeIndex + 1; }
int nMapIndex = m_mapRecipes.Find( nRecipeIndex );
// Make sure the recipe index is correct because we use this index as a reference
SCHEMA_INIT_CHECK( !m_mapRecipes.IsValidIndex( nMapIndex ), CFmtStr( "Duplicate recipe definition (%d)", nRecipeIndex ) );
// Check to make sure the index is positive
SCHEMA_INIT_CHECK( nRecipeIndex >= 0, CFmtStr( "Recipe definition index %d must be greater than or equal to zero", nRecipeIndex ) );
CEconCraftingRecipeDefinition *recipeDef = CreateCraftingRecipeDefinition(); SCHEMA_INIT_SUBSTEP( recipeDef->BInitFromKV( pKVRecipe, *this, pVecErrors ) );
// On clients, toss out any recipes that aren't always known. (Really, the clients
// shouldn't ever get these, but just in case.)
#if defined(CLIENT_DLL) || defined(GAME_DLL)
if ( recipeDef->IsAlwaysKnown() ) #endif // !GC_DLL
{ #ifdef _DEBUG
// Sanity check in debug builds so that we know we aren't putting the same recipe in
// multiple times.
FOR_EACH_MAP_FAST( m_mapRecipes, i ) { Assert( i != nRecipeIndex ); Assert( m_mapRecipes[i] != recipeDef ); } #endif // _DEBUG
// Store this recipe.
m_mapRecipes.Insert( nRecipeIndex, recipeDef ); } }
#ifdef CSTRIKE15
int nSetCount = GetItemSetCount(); for ( int i = 0; i < nSetCount; ++i ) { const IEconItemSetDefinition *pSet = GetItemSet( i ); if ( !pSet || pSet->GetCraftReward() <= 0 ) continue;
CEconCraftingRecipeDefinition *recipeDef = CreateCraftingRecipeDefinition(); SCHEMA_INIT_SUBSTEP( recipeDef->BInitFromSet( pSet, *this, pVecErrors ) ); recipeDef->SetDefinitionIndex( nHighestRecipeIndex ); recipeDef->SetFilter( CRAFT_FILTER_COLLECT );
// Disabled for now until we ship collection badges!
recipeDef->SetDisabled( true );
m_mapRecipes.Insert( nHighestRecipeIndex, recipeDef );
nHighestRecipeIndex++; } #endif //#ifdef CSTRIKE15
}
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Builds the name of a achievement in the form App<ID>.<AchName>
// Input: unAppID - native app ID
// pchNativeAchievementName - name of the achievement in its native app
// Returns: The combined achievement name
//-----------------------------------------------------------------------------
CUtlString CEconItemSchema::ComputeAchievementName( AppId_t unAppID, const char *pchNativeAchievementName ) { return CFmtStr1024( "App%u.%s", unAppID, pchNativeAchievementName ).Access(); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the achievement rewards section of the schema
// Input: pKVAchievementRewards - The achievement_rewards section of the KeyValues
// representation of the schema
// pVecErrors - An optional vector that will contain error messages if
// the init fails.
// Output: True if initialization succeeded, false otherwise
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitAchievementRewards( KeyValues *pKVAchievementRewards, CUtlVector<CUtlString> *pVecErrors ) { m_dictAchievementRewards.Purge(); m_mapAchievementRewardsByData.PurgeAndDeleteElements();
// initialize the rewards sections
if ( NULL != pKVAchievementRewards ) { FOR_EACH_SUBKEY( pKVAchievementRewards, pKVReward ) { AchievementAward_t award; if( pKVReward->GetDataType() == KeyValues::TYPE_NONE ) { int32 nItemIndex = pKVReward->GetInt( "DefIndex", -1 ); if( nItemIndex != -1 ) { award.m_vecDefIndex.AddToTail( (uint16)nItemIndex ); } else { KeyValues *pkvItems = pKVReward->FindKey( "Items" ); SCHEMA_INIT_CHECK( pkvItems != NULL, CFmtStr( "Complex achievement %s must have an Items key or a DefIndex field", pKVReward->GetName() ) ); if( !pkvItems ) { continue; }
FOR_EACH_VALUE( pkvItems, pkvItem ) { award.m_vecDefIndex.AddToTail( (uint16)Q_atoi( pkvItem->GetName() ) ); } }
} else { award.m_vecDefIndex.AddToTail( (uint16)pKVReward->GetInt("", -1 ) ); } // make sure all the item types are valid
bool bFoundAllItems = true; FOR_EACH_VEC( award.m_vecDefIndex, nItem ) { const CEconItemDefinition *pDefn = GetItemDefinition( award.m_vecDefIndex[nItem] ); SCHEMA_INIT_CHECK( pDefn != NULL, CFmtStr( "Item definition index %d in achievement reward %s was not found", award.m_vecDefIndex[nItem], pKVReward->GetName() ) ); if( !pDefn ) { bFoundAllItems = false; } } if( !bFoundAllItems ) continue;
SCHEMA_INIT_CHECK( award.m_vecDefIndex.Count() > 0, CFmtStr( "Achievement reward %s has no items!", pKVReward->GetName() ) ); if( award.m_vecDefIndex.Count() == 0 ) continue;
award.m_unSourceAppId = k_uAppIdInvalid; if( pKVReward->GetDataType() == KeyValues::TYPE_NONE ) { // cross game achievement
award.m_sNativeName = pKVReward->GetName(); award.m_unAuditData = pKVReward->GetInt( "AuditData", 0 ); award.m_unSourceAppId = pKVReward->GetInt( "SourceAppID", award.m_unSourceAppId ); } else { award.m_sNativeName = pKVReward->GetName(); award.m_unAuditData = 0; }
AchievementAward_t *pAward = new AchievementAward_t; *pAward = award;
m_dictAchievementRewards.Insert( ComputeAchievementName( pAward->m_unSourceAppId, pAward->m_sNativeName ), pAward ); m_mapAchievementRewardsByData.Insert( pAward->m_unAuditData, pAward ); } }
return SCHEMA_INIT_SUCCESS(); }
#ifdef TF_CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Go through all items and cache the number of concrete items in each.
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitConcreteItemCounts( CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_MAP_FAST( m_mapItems, i ) { CEconItemDefinition *pItemDef = m_mapItems[ i ]; pItemDef->m_unNumConcreteItems = CalculateNumberOfConcreteItems( pItemDef ); }
return true; } #endif
//-----------------------------------------------------------------------------
// Purpose: Returns the number of actual "real" items referenced by the item definition
// (i.e. items that would take up space in the inventory)
//-----------------------------------------------------------------------------
int CEconItemSchema::CalculateNumberOfConcreteItems( const CEconItemDefinition *pItemDef ) { AssertMsg( pItemDef, "NULL item definition! This should not happen!" ); if ( !pItemDef ) return 0;
if ( pItemDef->IsBundle() ) { uint32 unNumConcreteItems = 0; const bundleinfo_t *pBundle = pItemDef->GetBundleInfo(); Assert( pBundle );
FOR_EACH_VEC( pBundle->vecItemEntries, i ) { unNumConcreteItems += CalculateNumberOfConcreteItems( GetItemDefinition( pBundle->vecItemEntries[i].m_nItemDef ) ); }
return unNumConcreteItems; }
if ( pItemDef->GetItemClass() && !Q_strcmp( pItemDef->GetItemClass(), "map_token" ) ) return 0;
return 1; }
bool CEconItemSchema::BInitStickerKits( KeyValues *pKVStickerKits, CUtlVector<CUtlString> *pVecErrors ) { CStickerKit *pDefault = NULL; FOR_EACH_TRUE_SUBKEY( pKVStickerKits, pKVEntry ) { const char *pchName = pKVEntry->GetString( "name", "" ); if ( !pchName || pchName[ 0 ] == '\0' ) continue;
CStickerKit *pStickerKit = new CStickerKit(); if ( pStickerKit ) { pStickerKit->nID = atoi( pKVEntry->GetName() );
if ( !pDefault ) { if ( pStickerKit->nID == 0 ) pDefault = pStickerKit; else pDefault = m_mapStickerKits.Element( m_mapStickerKits.Find( 0 ) ); }
if ( !pStickerKit->InitFromKeyValues( pKVEntry, pDefault, pVecErrors ) ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Failed to initialize sticker kit ID %d '%s'", pStickerKit->nID, pStickerKit->sName.Get() ) ); continue; }
if( m_mapStickerKits.Find( pStickerKit->nID ) != m_mapStickerKits.InvalidIndex() ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Duplicate sticker kit ID %d", pStickerKit->nID ) ); continue; }
if( m_dictStickerKits.HasElement( pStickerKit->sName ) ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Duplicate sticker kit name '%s'", pStickerKit->sName.Get() ) ); continue; }
m_mapStickerKits.Insert( pStickerKit->nID, pStickerKit ); m_dictStickerKits.Insert( pStickerKit->sName.Get(), pStickerKit ); } }
return SCHEMA_INIT_SUCCESS(); }
bool CEconItemSchema::BInitStickerLists( KeyValues *pKVStickerLists, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_TRUE_SUBKEY( pKVStickerLists, pKVEntry ) { char const *szName = pKVEntry->GetName(); if ( !szName || !*szName ) continue;
if( m_dictStickerKits.HasElement( szName ) ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Sticker list name duplicating sticker kit name '%s'", szName ) ); continue; }
if( m_dictStickerLists.HasElement( szName ) ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Duplicate sticker list name '%s'", szName ) ); continue; }
CStickerList *pStickerList = new CStickerList(); if ( !pStickerList->InitFromKeyValues( pKVEntry, pVecErrors ) ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Failed to initialize sticker list '%s'", szName ) ); continue; }
m_dictStickerLists.Insert( szName, pStickerList ); }
return SCHEMA_INIT_SUCCESS(); }
bool CEconItemSchema::BInitPaintKits( KeyValues *pKVPaintKits, CUtlVector<CUtlString> *pVecErrors ) { CPaintKit *pDefault = NULL;
FOR_EACH_TRUE_SUBKEY( pKVPaintKits, pKVEntry ) { const char *pchName = pKVEntry->GetString( "name", "" ); if ( !pchName || pchName[ 0 ] == '\0' ) continue;
CPaintKit *pPaintKit = new CPaintKit(); if ( pPaintKit ) { pPaintKit->nID = atoi( pKVEntry->GetName() );
if ( !pDefault ) { if ( pPaintKit->nID == 0 ) pDefault = pPaintKit; else pDefault = m_mapPaintKits.Element( m_mapPaintKits.Find( 0 ) ); }
pPaintKit->InitFromKeyValues( pKVEntry, pDefault ); m_mapPaintKits.Insert( pPaintKit->nID, pPaintKit ); } }
return SCHEMA_INIT_SUCCESS(); }
bool CEconItemSchema::BInitPaintKitsRarity( KeyValues *pKVPaintKitsRarity, CUtlVector<CUtlString> *pVecErrors ) { CPaintKit *pDefault = const_cast< CPaintKit* >( GetPaintKitDefinitionByName( "default" ) ); if ( !pDefault ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Unable to find \"default\" paint kit in \"paint_kits_rarity\"" ) ); return false; }
uint8 nRarity; GetItemSchema()->BGetItemRarityFromName( pKVPaintKitsRarity->GetString( "default", "common" ), &nRarity ); pDefault->nRarity = nRarity;
FOR_EACH_SUBKEY( pKVPaintKitsRarity, pKVEntry ) { CPaintKit *pPaintKit = const_cast< CPaintKit* >( GetPaintKitDefinitionByName( pKVEntry->GetName() ) ); if ( !pPaintKit ) continue;
const char *pchRarity = pKVEntry->GetString(); if ( pchRarity ) { uint8 nRarity; GetItemSchema()->BGetItemRarityFromName( pchRarity, &nRarity ); pPaintKit->nRarity = nRarity; } else { pPaintKit->nRarity = pDefault->nRarity; } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitMusicDefs( KeyValues *pKVMusicDefs, CUtlVector<CUtlString> *pVecErrors ) { FOR_EACH_TRUE_SUBKEY( pKVMusicDefs, pKVMusicDef ) { CEconMusicDefinition *pNewMusicDef = new CEconMusicDefinition;
SCHEMA_INIT_SUBSTEP( pNewMusicDef->BInitFromKV( pKVMusicDef, *this, pVecErrors ) );
if( m_mapMusicDefs.Find( pNewMusicDef->GetID() ) != m_mapMusicDefs.InvalidIndex() ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Duplicate music definition id %d", pNewMusicDef->GetID() ) ); continue; }
m_mapMusicDefs.Insert( pNewMusicDef->GetID(), pNewMusicDef ); }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitQuestDefs( KeyValues *pKVQuestDefs, CUtlVector<CUtlString> *pVecErrors ) { m_mapQuestDefs.PurgeAndDeleteElements();
// initialize the Quest definitions
if ( NULL != pKVQuestDefs ) { FOR_EACH_TRUE_SUBKEY( pKVQuestDefs, pKVQuestDef ) { CEconQuestDefinition *pNewQuestDef = new CEconQuestDefinition;
SCHEMA_INIT_SUBSTEP( pNewQuestDef->BInitFromKV( pKVQuestDef, *this, pVecErrors ) );
if ( m_mapQuestDefs.Find( pNewQuestDef->GetID() ) != m_mapQuestDefs.InvalidIndex() ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Duplicate Quest definition id %d", pNewQuestDef->GetID() ) ); continue; }
m_mapQuestDefs.Insert( pNewQuestDef->GetID(), pNewQuestDef ); } }
return SCHEMA_INIT_SUCCESS(); }
bool CEconItemSchema::BInitQuestEvents( KeyValues *pKVQuestSchedule, CUtlVector<CUtlString> *pVecErrors ) { m_vecQuestEvents.Purge();
// Removed for partner depot
return SCHEMA_INIT_SUCCESS(); }
const QuestEventsSchedule_t& CEconItemSchema::GetAndUpdateQuestEventsSchedule() { return m_mapQuestEventsSchedule; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitCampaignDefs( KeyValues *pKVCampaignDefs, CUtlVector<CUtlString> *pVecErrors ) { m_mapCampaignDefs.PurgeAndDeleteElements();
// initialize the Campaign definitions
if ( NULL != pKVCampaignDefs ) { FOR_EACH_TRUE_SUBKEY( pKVCampaignDefs, pKVCampaignDef ) { CEconCampaignDefinition *pNewCampaignDef = new CEconCampaignDefinition;
SCHEMA_INIT_SUBSTEP( pNewCampaignDef->BInitFromKV( pKVCampaignDef, *this, pVecErrors ) );
if ( m_mapCampaignDefs.Find( pNewCampaignDef->GetID() ) != m_mapCampaignDefs.InvalidIndex() ) { SCHEMA_INIT_CHECK( false, CFmtStr( "Duplicate Campaign definition id %d", pNewCampaignDef->GetID() ) ); continue; }
m_mapCampaignDefs.Insert( pNewCampaignDef->GetID(), pNewCampaignDef ); } }
return SCHEMA_INIT_SUCCESS(); }
attachedparticlesystem_t CEconItemSchema::GetAttachedParticleSystemInfo( KeyValues* pKVEntry, int32 nItemIndex ) const { attachedparticlesystem_t system;
system.pEffectKV = pKVEntry; system.pszResourceName = pKVEntry->GetString( "resource", NULL ); system.pszSystemName = pKVEntry->GetString( "system", NULL ); system.pszAttachmentName = pKVEntry->GetString( "attachment", NULL ); system.bFollowRootBone = pKVEntry->GetInt( "attach_to_rootbone", 0 ) != 0; system.bFlyingCourier = pKVEntry->GetInt( "flying_courier_effect", 0 ) != 0; system.iCustomType = pKVEntry->GetInt( "custom_type", 0 ); system.iCount = 0; system.nSystemID = nItemIndex; system.nRootAttachType = StringFieldToInt( pKVEntry->GetString("attach_type"), g_szParticleAttachTypes, ARRAYSIZE(g_szParticleAttachTypes) ); int iAttachToEnt = StringFieldToInt( pKVEntry->GetString("attach_entity"), g_szParticleAttachToEnt, ARRAYSIZE(g_szParticleAttachToEnt) ); system.nAttachToEntity = ( iAttachToEnt == -1 ) ? ATTPART_TO_SELF : (attachedparticle_toent_t)iAttachToEnt;
// Find any control point settings
KeyValues *pKVControlPoints = pKVEntry->FindKey( "control_points" ); if ( pKVControlPoints ) { FOR_EACH_TRUE_SUBKEY( pKVControlPoints, pKVPoint ) { int iIdx = system.vecControlPoints.AddToTail(); system.vecControlPoints[iIdx].nControlPoint = pKVPoint->GetInt( "control_point_index", -1 ); system.vecControlPoints[iIdx].nAttachType = StringFieldToInt( pKVPoint->GetString("attach_type"), g_szParticleAttachTypes, ARRAYSIZE(g_szParticleAttachTypes) ); system.vecControlPoints[iIdx].pszAttachmentName = pKVPoint->GetString( "attachment", NULL ); float flVec[3]; V_StringToVector( flVec, pKVPoint->GetString( "position", "0 0 0" ) ); system.vecControlPoints[iIdx].vecPosition = Vector( flVec[0], flVec[1], flVec[2] ); } }
return system; }
//-----------------------------------------------------------------------------
// Purpose: Initializes the attribute-controlled-particle-systems section of the schema
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitAttributeControlledParticleSystems( KeyValues *pKVParticleSystems, CUtlVector<CUtlString> *pVecErrors ) { m_mapAttributeControlledParticleSystems.Purge(); if ( NULL != pKVParticleSystems ) { FOR_EACH_TRUE_SUBKEY( pKVParticleSystems, pKVEntry ) { int32 nItemIndex = atoi( pKVEntry->GetName() ); // Check to make sure the index is positive
SCHEMA_INIT_CHECK( nItemIndex > 0, CFmtStr( "Particle system index %d greater than zero", nItemIndex ) ); if ( nItemIndex <= 0 ) continue; int iIndex = m_mapAttributeControlledParticleSystems.Insert( nItemIndex ); attachedparticlesystem_t *system = &m_mapAttributeControlledParticleSystems[iIndex]; *system = GetAttachedParticleSystemInfo( pKVEntry, nItemIndex ); } } return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Inits data for items that can level up through kills, etc.
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitItemLevels( KeyValues *pKVItemLevels, CUtlVector<CUtlString> *pVecErrors ) { m_vecItemLevelingData.RemoveAll();
// initialize the rewards sections
if ( NULL != pKVItemLevels ) { FOR_EACH_TRUE_SUBKEY( pKVItemLevels, pKVItemLevelBlock ) { const char *pszLevelBlockName = pKVItemLevelBlock->GetName(); SCHEMA_INIT_CHECK( GetItemLevelingData( pszLevelBlockName ) == NULL, CFmtStr( "Duplicate leveling data block named \"%s\".", pszLevelBlockName ) );
// Allocate a new structure for this block and assign it. We'll fill in the contents later.
CUtlVector<CItemLevelingDefinition> *pLevelingData = new CUtlVector<CItemLevelingDefinition>; m_vecItemLevelingData.Insert( pszLevelBlockName, pLevelingData );
FOR_EACH_TRUE_SUBKEY( pKVItemLevelBlock, pKVItemLevel ) { int index = pLevelingData->AddToTail(); SCHEMA_INIT_SUBSTEP( (*pLevelingData)[index].BInitFromKV( pKVItemLevel, *this, pszLevelBlockName, pVecErrors ) ); } } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose: Inits data for kill eater types.
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitKillEaterScoreTypes( KeyValues *pKVKillEaterScoreTypes, CUtlVector<CUtlString> *pVecErrors ) { m_mapKillEaterScoreTypes.RemoveAll();
// initialize the rewards sections
if ( NULL != pKVKillEaterScoreTypes ) { FOR_EACH_TRUE_SUBKEY( pKVKillEaterScoreTypes, pKVScoreType ) { unsigned int unIndex = (unsigned int)atoi( pKVScoreType->GetName() ); SCHEMA_INIT_CHECK( m_mapKillEaterScoreTypes.Find( unIndex ) == KillEaterScoreMap_t::InvalidIndex(), CFmtStr( "Duplicate kill eater score type index %u.", unIndex ) ); kill_eater_score_type_t ScoreType; ScoreType.m_nValue = V_atoi( pKVScoreType->GetName() ); ScoreType.m_pszTypeString = pKVScoreType->GetString( "type_name" ); ScoreType.m_pszModelAttributeString = pKVScoreType->GetString( "model_attribute" ); #ifdef CLIENT_DLL
HelperValidateLocalizationStringToken( CFmtStr( "#KillEaterDescriptionNotice_%s", ScoreType.m_pszTypeString ) ); HelperValidateLocalizationStringToken( CFmtStr( "#KillEaterEventType_%s", ScoreType.m_pszTypeString ) ); #endif
// Default to on.
ScoreType.m_bUseLevelBlock = pKVScoreType->GetBool( "use_level_data", 1 );
const char *pszLevelBlockName = pKVScoreType->GetString( "level_data", "KillEaterRank" ); SCHEMA_INIT_CHECK( GetItemLevelingData( pszLevelBlockName ) != NULL, CFmtStr( "Unable to find leveling data block named \"%s\" for kill eater score type %u.", pszLevelBlockName, unIndex ) );
ScoreType.m_pszLevelBlockName = pszLevelBlockName;
m_mapKillEaterScoreTypes.Insert( unIndex, ScoreType ); } }
return SCHEMA_INIT_SUCCESS(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const ISchemaAttributeType *CEconItemSchema::GetAttributeType( const char *pszAttrTypeName ) const { FOR_EACH_VEC( m_vecAttributeTypes, i ) { if ( m_vecAttributeTypes[i].m_sName == pszAttrTypeName ) return m_vecAttributeTypes[i].m_pAttrType; }
return NULL; }
//-----------------------------------------------------------------------------
// CItemLevelingDefinition Accessor
//-----------------------------------------------------------------------------
const CItemLevelingDefinition *CEconItemSchema::GetItemLevelForScore( const char *pszLevelBlockName, uint32 unScore ) const { const CUtlVector<CItemLevelingDefinition> *pLevelingData = GetItemLevelingData( pszLevelBlockName ); if ( !pLevelingData ) return NULL;
if ( pLevelingData->Count() == 0 ) return NULL;
FOR_EACH_VEC( (*pLevelingData), i ) { if ( unScore < (*pLevelingData)[i].GetRequiredScore() ) return &(*pLevelingData)[i]; }
return &(*pLevelingData).Tail(); }
//-----------------------------------------------------------------------------
// Kill eater score type accessor
//-----------------------------------------------------------------------------
const kill_eater_score_type_t *CEconItemSchema::FindKillEaterScoreType( uint32 unScoreType ) const { KillEaterScoreMap_t::IndexType_t i = m_mapKillEaterScoreTypes.Find( unScoreType ); if ( i == KillEaterScoreMap_t::InvalidIndex() ) return NULL;
return &m_mapKillEaterScoreTypes[i]; }
//-----------------------------------------------------------------------------
// Kill eater score type accessor
//-----------------------------------------------------------------------------
const char *CEconItemSchema::GetKillEaterScoreTypeLocString( uint32 unScoreType ) const { const kill_eater_score_type_t *pScoreType = FindKillEaterScoreType( unScoreType );
return pScoreType ? pScoreType->m_pszTypeString : NULL; }
//-----------------------------------------------------------------------------
// Kill eater score type accessor for "use_level_data"
//-----------------------------------------------------------------------------
bool CEconItemSchema::GetKillEaterScoreTypeUseLevelData( uint32 unScoreType ) const { const kill_eater_score_type_t *pScoreType = FindKillEaterScoreType( unScoreType ); return pScoreType ? pScoreType->m_bUseLevelBlock : false; }
//-----------------------------------------------------------------------------
// Kill eater score type accessor
//-----------------------------------------------------------------------------
const char *CEconItemSchema::GetKillEaterScoreTypeLevelingDataName( uint32 unScoreType ) const { const kill_eater_score_type_t *pScoreType = FindKillEaterScoreType( unScoreType );
return pScoreType ? pScoreType->m_pszLevelBlockName : NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
econ_tag_handle_t CEconItemSchema::GetHandleForTag( const char *pszTagName ) { EconTagDict_t::IndexType_t i = m_dictTags.Find( pszTagName ); if ( m_dictTags.IsValidIndex( i ) ) return i;
return m_dictTags.Insert( pszTagName ); }
#if defined(CLIENT_DLL) || defined(GAME_DLL)
//-----------------------------------------------------------------------------
// Purpose: Clones the specified item definition, and returns the new item def.
//-----------------------------------------------------------------------------
void CEconItemSchema::ItemTesting_CreateTestDefinition( int iCloneFromItemDef, int iNewDef, KeyValues *pNewKV ) { int nMapIndex = m_mapItems.Find( iNewDef ); if ( !m_mapItems.IsValidIndex( nMapIndex ) ) { nMapIndex = m_mapItems.Insert( iNewDef, CreateEconItemDefinition() ); m_mapItemsSorted.Insert( iNewDef, m_mapItems[nMapIndex] ); }
// Find & copy the clone item def's data in
const CEconItemDefinition *pCloneDef = GetItemDefinition( iCloneFromItemDef ); if ( !pCloneDef ) return; m_mapItems[nMapIndex]->CopyPolymorphic( pCloneDef );
// Then stomp it with the KV test contents
m_mapItems[nMapIndex]->BInitFromTestItemKVs( iNewDef, pNewKV, *this ); }
//-----------------------------------------------------------------------------
// Purpose: Discards the specified item definition
//-----------------------------------------------------------------------------
void CEconItemSchema::ItemTesting_DiscardTestDefinition( int iDef ) { m_mapItems.Remove( iDef ); m_mapItemsSorted.Remove( iDef ); }
//-----------------------------------------------------------------------------
// Purpose: Initializes the armory data section of the schema
//-----------------------------------------------------------------------------
bool CEconItemSchema::BInitArmoryData( KeyValues *pKVArmoryData, CUtlVector<CUtlString> *pVecErrors ) { m_dictArmoryItemDataStrings.Purge(); m_dictArmoryAttributeDataStrings.Purge(); if ( NULL != pKVArmoryData ) { KeyValues *pKVItemTypes = pKVArmoryData->FindKey( "armory_item_types" ); if ( pKVItemTypes ) { FOR_EACH_SUBKEY( pKVItemTypes, pKVEntry ) { const char *pszDataKey = pKVEntry->GetName(); const char *pszLocString = pKVEntry->GetString(); m_dictArmoryItemTypesDataStrings.Insert( pszDataKey, pszLocString ); } }
pKVItemTypes = pKVArmoryData->FindKey( "armory_item_classes" ); if ( pKVItemTypes ) { FOR_EACH_SUBKEY( pKVItemTypes, pKVEntry ) { const char *pszDataKey = pKVEntry->GetName(); const char *pszLocString = pKVEntry->GetString(); m_dictArmoryItemClassesDataStrings.Insert( pszDataKey, pszLocString ); } }
KeyValues *pKVAttribs = pKVArmoryData->FindKey( "armory_attributes" ); if ( pKVAttribs ) { FOR_EACH_SUBKEY( pKVAttribs, pKVEntry ) { const char *pszDataKey = pKVEntry->GetName(); const char *pszLocString = pKVEntry->GetString(); m_dictArmoryAttributeDataStrings.Insert( pszDataKey, pszLocString ); } }
KeyValues *pKVItems = pKVArmoryData->FindKey( "armory_items" ); if ( pKVItems ) { FOR_EACH_SUBKEY( pKVItems, pKVEntry ) { const char *pszDataKey = pKVEntry->GetName(); const char *pszLocString = pKVEntry->GetString(); m_dictArmoryItemDataStrings.Insert( pszDataKey, pszLocString ); } } } return SCHEMA_INIT_SUCCESS(); } #endif
//-----------------------------------------------------------------------------
// Purpose: Returns the achievement award that matches the provided defindex or NULL
// if there is no such award.
// Input: unData - The data field that would be stored in ItemAudit
//-----------------------------------------------------------------------------
const AchievementAward_t *CEconItemSchema::GetAchievementRewardByDefIndex( uint16 usDefIndex ) const { FOR_EACH_MAP_FAST( m_mapAchievementRewardsByData, nIndex ) { if( m_mapAchievementRewardsByData[nIndex]->m_vecDefIndex.HasElement( usDefIndex ) ) return m_mapAchievementRewardsByData[nIndex]; } return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Gets a rarity value for a name.
//-----------------------------------------------------------------------------
bool CEconItemSchema::BGetItemRarityFromName( const char *pchName, uint8 *nRarity ) const { if ( 0 == Q_stricmp( "any", pchName ) ) { *nRarity = k_unItemRarity_Any; return true; }
FOR_EACH_MAP_FAST( m_mapRarities, i ) { if ( 0 == Q_stricmp( m_mapRarities[i].GetName(), pchName ) ) { *nRarity = m_mapRarities[i].GetDBValue(); return true; } }
return false; }
//-----------------------------------------------------------------------------
// Purpose: Gets a quality value for a name.
// Input: pchName - The name to translate.
// nQuality - (out)The quality number for this name, if found.
// Output: True if the string matched a quality for this schema, false otherwise.
//-----------------------------------------------------------------------------
bool CEconItemSchema::BGetItemQualityFromName( const char *pchName, uint8 *nQuality ) const { if ( 0 == Q_stricmp( "any", pchName ) ) { *nQuality = k_unItemQuality_Any; return true; }
FOR_EACH_MAP_FAST( m_mapQualities, i ) { if ( 0 == Q_stricmp( m_mapQualities[i].GetName(), pchName ) ) { *nQuality = m_mapQualities[i].GetDBValue(); return true; } }
return false; }
//-----------------------------------------------------------------------------
// Purpose: Gets a quality definition for an index
// Input: nQuality - The quality to get.
// Output: A pointer to the desired definition, or NULL if it is not found.
//-----------------------------------------------------------------------------
const CEconItemQualityDefinition *CEconItemSchema::GetQualityDefinition( int nQuality ) const { int iIndex = m_mapQualities.Find( nQuality ); if ( m_mapQualities.IsValidIndex( iIndex ) ) return &m_mapQualities[iIndex]; return NULL; }
const CEconItemQualityDefinition *CEconItemSchema::GetQualityDefinitionByName( const char *pszDefName ) const { FOR_EACH_MAP_FAST( m_mapQualities, i ) { if ( !strcmp( pszDefName, m_mapQualities[i].GetName()) ) return &m_mapQualities[i]; } return NULL; }
const char* CEconItemSchema::GetQualityName( uint8 iQuality ) { const CEconItemQualityDefinition* pItemQuality = GetQualityDefinition( iQuality ); if ( !pItemQuality ) return NULL; else return pItemQuality->GetName(); }
int CEconItemSchema::GetQualityIndex( const char* pszQuality ) { const CEconItemQualityDefinition* pItemQuality = GetQualityDefinitionByName( pszQuality ); if ( pItemQuality ) return pItemQuality->GetDBValue(); else return 0; }
const CEconItemRarityDefinition *CEconItemSchema::GetRarityDefinitionByMapIndex( int nRarityIndex ) const { if ( m_mapRarities.IsValidIndex( nRarityIndex ) ) return &m_mapRarities[nRarityIndex];
return NULL; }
const CEconItemRarityDefinition *CEconItemSchema::GetRarityDefinition( int nRarity ) const { int iIndex = m_mapRarities.Find( nRarity ); if ( m_mapRarities.IsValidIndex( iIndex ) ) return &m_mapRarities[iIndex]; return NULL; }
const CEconItemRarityDefinition *CEconItemSchema::GetRarityDefinitionByName( const char *pszDefName ) const { FOR_EACH_MAP_FAST( m_mapRarities, i ) { if ( !strcmp( pszDefName, m_mapRarities[i].GetName()) ) return &m_mapRarities[i]; } return NULL; }
const char* CEconItemSchema::GetRarityName( uint8 iRarity ) { const CEconItemRarityDefinition* pItemRarity = GetRarityDefinition( iRarity ); if ( !pItemRarity ) return NULL; else return pItemRarity->GetName(); }
const char* CEconItemSchema::GetRarityLocKey( uint8 iRarity ) { const CEconItemRarityDefinition* pItemRarity = GetRarityDefinition( iRarity ); if ( !pItemRarity ) return NULL; else return pItemRarity->GetLocKey(); }
const char* CEconItemSchema::GetRarityColor( uint8 iRarity ) { const CEconItemRarityDefinition* pItemRarity = GetRarityDefinition( iRarity ); if ( !pItemRarity ) return NULL; else return GetHexColorForAttribColor( pItemRarity->GetAttribColor() ); }
const char* CEconItemSchema::GetRarityLootList( uint8 iRarity ) { const CEconItemRarityDefinition* pItemRarity = GetRarityDefinition( iRarity ); if ( !pItemRarity ) return NULL; else return pItemRarity->GetLootList(); }
int CEconItemSchema::GetRarityIndex( const char* pszRarity ) { const CEconItemRarityDefinition* pRarity = GetRarityDefinitionByName( pszRarity ); if ( pRarity ) return pRarity->GetDBValue(); else return 0; }
const CEconSoundMaterialDefinition *CEconItemSchema::GetSoundMaterialDefinitionByID( int nSoundMaterialID ) const { int iIndex = m_mapSoundMaterials.Find( nSoundMaterialID ); if ( m_mapSoundMaterials.IsValidIndex( iIndex ) ) return &m_mapSoundMaterials[iIndex]; return NULL; }
const CEconSoundMaterialDefinition *CEconItemSchema::GetSoundMaterialDefinitionByName( const char *pszSoundMaterialName ) const { FOR_EACH_MAP_FAST( m_mapSoundMaterials, i ) { if ( !strcmp( pszSoundMaterialName, m_mapSoundMaterials[i].GetName()) ) return &m_mapSoundMaterials[i]; } return NULL; }
const char* CEconItemSchema::GetSoundMaterialNameByID( int nSoundMaterialID ) { const CEconSoundMaterialDefinition* pSoundMaterial = GetSoundMaterialDefinitionByID( nSoundMaterialID ); if ( !pSoundMaterial ) return NULL; else return pSoundMaterial->GetName(); }
int CEconItemSchema::GetSoundMaterialID( const char* pszSoundMaterial ) { const CEconSoundMaterialDefinition* pSoundMaterial = GetSoundMaterialDefinitionByName( pszSoundMaterial ); if ( pSoundMaterial ) return pSoundMaterial->GetID(); else return 0; }
int CEconItemSchema::GetSoundMaterialIDByIndex( int nIndex ) { // This makes for a slow iteration pattern. Only used by the item editor currently, should make it a UtlVector/UtlMap pair if it's too slow.
FOR_EACH_MAP( m_mapSoundMaterials, i ) { nIndex--; if ( nIndex < 0 ) { return m_mapSoundMaterials[i].GetID(); } } return -1; }
//-----------------------------------------------------------------------------
// Purpose: Gets an item definition for the specified map index
//-----------------------------------------------------------------------------
const CEconItemDefinition *CEconItemSchema::GetItemDefinitionByMapIndex( int iMapIndex ) const { if ( m_mapItems.IsValidIndex( iMapIndex ) ) return m_mapItems[iMapIndex];
return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Gets an item definition for the specified definition index
// Input: iItemIndex - The index of the desired definition.
// Output: A pointer to the desired definition, or NULL if it is not found.
//-----------------------------------------------------------------------------
CEconItemDefinition *CEconItemSchema::GetItemDefinitionMutable( int iItemIndex, bool bNoDefault ) { #if defined(CLIENT_DLL) || defined(GAME_DLL)
#if !defined(CSTRIKE_DLL)
AssertMsg( m_pDefaultItemDefinition, "No default item definition set up for item schema." ); #endif // CSTRIKE_DLL
#endif // defined(CLIENT_DLL) || defined(GAME_DLL)
int iIndex = m_mapItems.Find( iItemIndex ); if ( m_mapItems.IsValidIndex( iIndex ) ) return m_mapItems[iIndex];
if ( bNoDefault ) return NULL;
if ( m_pDefaultItemDefinition ) return m_pDefaultItemDefinition;
#if !defined(CSTRIKE_DLL)
// We shouldn't ever get down here, but all the same returning a valid pointer is very slightly
// a better plan than returning an invalid pointer to code that won't check to see if it's valid.
static CEconItemDefinition *s_pEmptyDefinition = CreateEconItemDefinition(); return s_pEmptyDefinition; #else
return NULL; #endif // CSTRIKE_DLL
} const CEconItemDefinition *CEconItemSchema::GetItemDefinition( int iItemIndex, bool bNoDefault ) const { return const_cast<CEconItemSchema *>(this)->GetItemDefinitionMutable( iItemIndex, bNoDefault ); }
//-----------------------------------------------------------------------------
// Purpose: Gets an item definition that has a name matching the specified name.
// Input: pszDefName - The name of the desired definition.
// Output: A pointer to the desired definition, or NULL if it is not found.
//-----------------------------------------------------------------------------
CEconItemDefinition *CEconItemSchema::GetItemDefinitionByName( const char *pszDefName ) { SNPROF(__PRETTY_FUNCTION__);
if ( m_bSchemaParsingItems ) { AssertMsg( 0, "GetItemDefinitionByName while parsing item definitions. This is not a valid operation." ); return NULL; }
// This shouldn't happen, but let's not crash if it ever does.
Assert( pszDefName != NULL ); if ( pszDefName == NULL ) return NULL;
FOR_EACH_MAP_FAST( m_mapItems, i ) { if ( !strcmp( pszDefName, m_mapItems[i]->GetDefinitionName()) ) return m_mapItems[i]; } return NULL; }
const CEconItemDefinition *CEconItemSchema::GetItemDefinitionByName( const char *pszDefName ) const { return const_cast<CEconItemSchema *>(this)->GetItemDefinitionByName( pszDefName ); }
//-----------------------------------------------------------------------------
// Purpose: Gets an attribute definition for an index
// Input: iAttribIndex - The index of the desired definition.
// Output: A pointer to the desired definition, or NULL if it is not found.
//-----------------------------------------------------------------------------
const CEconItemAttributeDefinition *CEconItemSchema::GetAttributeDefinition( int iAttribIndex ) const { if ( m_mapAttributesContainer.IsValidIndex( iAttribIndex ) ) return m_mapAttributesContainer[iAttribIndex]; return NULL; }
const CEconItemAttributeDefinition *CEconItemSchema::GetAttributeDefinitionByName( const char *pszDefName ) const { VPROF_BUDGET( "CEconItemSchema::GetAttributeDefinitionByName", VPROF_BUDGETGROUP_STEAM ); SNPROF(__PRETTY_FUNCTION__);
FOR_EACH_VEC( m_mapAttributesContainer, i ) { if ( m_mapAttributesContainer[i] && !strcmp( pszDefName, m_mapAttributesContainer[i]->GetDefinitionName()) ) return m_mapAttributesContainer[i]; } return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Gets a recipe definition for an index
// Input: iRecipeIndex - The index of the desired definition.
// Output: A pointer to the desired definition, or NULL if it is not found.
//-----------------------------------------------------------------------------
const CEconCraftingRecipeDefinition *CEconItemSchema::GetRecipeDefinition( int iRecipeIndex ) const { int iIndex = m_mapRecipes.Find( iRecipeIndex ); if ( m_mapRecipes.IsValidIndex( iIndex ) ) return m_mapRecipes[iIndex]; return NULL; }
//-----------------------------------------------------------------------------
void CEconItemSchema::AddStickerKitDefinition( int iStickerKitID, CStickerKit *pStickerKit ) { int iIndex = m_mapStickerKits.Find( iStickerKitID ); if ( m_mapStickerKits.IsValidIndex( iIndex ) ) { m_mapStickerKits.Remove( iStickerKitID ); }
m_mapStickerKits.Insert( iStickerKitID, pStickerKit ); }
void CEconItemSchema::RemoveStickerKitDefinition( int iStickerKitID ) { m_mapStickerKits.Remove( iStickerKitID ); }
const CStickerKit *CEconItemSchema::GetStickerKitDefinition( int iStickerKitID ) const { int iIndex = m_mapStickerKits.Find( iStickerKitID ); if ( m_mapStickerKits.IsValidIndex( iIndex ) ) return m_mapStickerKits[iIndex]; return NULL; }
const CStickerKit *CEconItemSchema::GetStickerKitDefinitionByMapIndex( int iMapIndex ) { if ( m_mapStickerKits.IsValidIndex( iMapIndex ) ) return m_mapStickerKits[ iMapIndex ];
return NULL; }
const CStickerKit *CEconItemSchema::GetStickerKitDefinitionByName( const char *pchName ) const { int idx = m_dictStickerKits.Find( pchName ); if ( idx != m_dictStickerKits.InvalidIndex() ) return m_dictStickerKits.Element( idx ); else return NULL; }
const CStickerList *CEconItemSchema::GetStickerListDefinitionByName( const char *pchName ) const { int idx = m_dictStickerLists.Find( pchName ); if ( idx != m_dictStickerLists.InvalidIndex() ) return m_dictStickerLists.Element( idx ); else return NULL; }
const CEconMusicDefinition *CEconItemSchema::GetMusicKitDefinitionByName( const char *pchName ) const { FOR_EACH_MAP_FAST( m_mapMusicDefs, i ) { if ( !V_strcmp( m_mapMusicDefs.Element( i )->GetName(), pchName ) ) { return m_mapMusicDefs.Element( i ); } }
return NULL; }
//-----------------------------------------------------------------------------
void CEconItemSchema::AddPaintKitDefinition( int iPaintKitID, CPaintKit *pPaintKit ) { int iIndex = m_mapPaintKits.Find( iPaintKitID ); if ( m_mapPaintKits.IsValidIndex( iIndex ) ) { m_mapPaintKits.Remove( iPaintKitID ); }
m_mapPaintKits.Insert( iPaintKitID, pPaintKit ); }
void CEconItemSchema::RemovePaintKitDefinition( int iPaintKitID ) { m_mapPaintKits.Remove( iPaintKitID ); }
const CPaintKit *CEconItemSchema::GetPaintKitDefinition( int iPaintKitID ) const { int iIndex = m_mapPaintKits.Find( iPaintKitID ); if ( m_mapPaintKits.IsValidIndex( iIndex ) ) return m_mapPaintKits[iIndex]; return NULL; }
const CPaintKit *CEconItemSchema::GetPaintKitDefinitionByMapIndex( int iMapIndex ) { if ( m_mapPaintKits.IsValidIndex( iMapIndex ) ) return m_mapPaintKits[ iMapIndex ];
return NULL; }
const CPaintKit *CEconItemSchema::GetPaintKitDefinitionByName( const char *pchName ) const { FOR_EACH_MAP_FAST( m_mapPaintKits, i ) { CPaintKit *pPaintKit = m_mapPaintKits[ i ]; if ( V_strcmp( pPaintKit->sName.Access(), pchName ) == 0 ) { return pPaintKit; } }
return NULL; }
const unsigned int CEconItemSchema::GetPaintKitCount() const { return m_mapPaintKits.Count(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const CEconColorDefinition *CEconItemSchema::GetColorDefinitionByName( const char *pszDefName ) const { FOR_EACH_VEC( m_vecColorDefs, i ) { if ( !Q_stricmp( m_vecColorDefs[i]->GetName(), pszDefName ) ) return m_vecColorDefs[i]; } return NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const CEconGraffitiTintDefinition * CEconItemSchema::GetGraffitiTintDefinitionByID( int nID ) const { return m_vecGraffitiTintDefs.IsValidIndex( nID ) ? m_vecGraffitiTintDefs[ nID ] : NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const CEconGraffitiTintDefinition * CEconItemSchema::GetGraffitiTintDefinitionByName( const char *pszDefName ) const { UtlSymId_t utlsym = m_mapGraffitiTintByName.Find( pszDefName ); return ( utlsym != UTL_INVAL_SYMBOL ) ? m_mapGraffitiTintByName[ utlsym ] : NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const CEconMusicDefinition *CEconItemSchema::GetMusicDefinition( uint32 unMusicID ) const { int iIndex = m_mapMusicDefs.Find( unMusicID ); if ( m_mapMusicDefs.IsValidIndex( iIndex ) ) return m_mapMusicDefs[iIndex]; return NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEconQuestDefinition *CEconItemSchema::GetQuestDefinition( uint32 unQuestID ) const { int iIndex = m_mapQuestDefs.Find( unQuestID ); if ( m_mapQuestDefs.IsValidIndex( iIndex ) ) return m_mapQuestDefs[ iIndex ]; return NULL; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEconCampaignDefinition *CEconItemSchema::GetCampaignDefinition( uint32 unCampaignID ) const { int iIndex = m_mapCampaignDefs.Find( unCampaignID ); if ( m_mapCampaignDefs.IsValidIndex( iIndex ) ) return m_mapCampaignDefs[ iIndex ]; return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Return the attribute specified attachedparticlesystem_t* associated with the given id.
//-----------------------------------------------------------------------------
attachedparticlesystem_t* CEconItemSchema::GetAttributeControlledParticleSystem( int id ) { int iIndex = m_mapAttributeControlledParticleSystems.Find( id ); if ( m_mapAttributeControlledParticleSystems.IsValidIndex( iIndex ) ) return &m_mapAttributeControlledParticleSystems[iIndex]; return NULL; }
attachedparticlesystem_t* CEconItemSchema::GetAttributeControlledParticleSystemByIndex( int id ) { return &m_mapAttributeControlledParticleSystems[id]; }
attachedparticlesystem_t* CEconItemSchema::FindAttributeControlledParticleSystem( const char *pchSystemName, int *outID ) { FOR_EACH_MAP_FAST( m_mapAttributeControlledParticleSystems, nSystem ) { if( !Q_stricmp( m_mapAttributeControlledParticleSystems[nSystem].pszSystemName, pchSystemName ) ) { if ( outID ) { *outID = nSystem; } return &m_mapAttributeControlledParticleSystems[nSystem]; } } if ( outID ) { *outID = -1; } return NULL; }
bool CEconItemSchema::BPostSchemaInitStartupChecks( CUtlVector<CUtlString> *pVecErrors ) { #if defined( GC_DLL ) || defined( CLIENT_DLL )
// confirm that all stickers that reference players have valid link
FOR_EACH_MAP_FAST( m_mapStickerKits, i ) { CStickerKit * pStickerKit = m_mapStickerKits.Element( i ); if ( !pStickerKit->m_nPlayerID ) continue; SCHEMA_INIT_CHECK( ( m_mapProPlayersByAccountID.Find( pStickerKit->m_nPlayerID ) != m_mapProPlayersByAccountID.InvalidIndex() ), CFmtStr( "Pro-player sticker %d reference player %u which doesn't have a matching pro-player entry", pStickerKit->nID, pStickerKit->m_nPlayerID ) ); }
#endif // #if defined( GC_DLL ) || defined( CLIENT_DLL )
#ifdef CLIENT_DLL
//// Confirm that every story block expression references only existing quest indices.
FOR_EACH_MAP_FAST( m_mapCampaignDefs, iC ) { FOR_EACH_MAP_FAST( m_mapCampaignDefs.Element( iC )->GetCampaignNodes(), iCn ) { CEconCampaignDefinition::CEconCampaignNodeDefinition * pCNodeDef = m_mapCampaignDefs.Element( iC )->GetCampaignNodes().Element( iCn );
FOR_EACH_VEC( pCNodeDef->GetStoryBlocks(), iSB ) {
KeyValues * pKVExpressionTokens = new KeyValues( "ExpressionTokens" ); KeyValues::AutoDelete autodelete( pKVExpressionTokens );
CEconQuestDefinition::TokenizeQuestExpression( pCNodeDef->GetStoryBlocks()[ iSB ]->GetStoryBlockExpression(), pKVExpressionTokens );
FOR_EACH_SUBKEY( pKVExpressionTokens, kvSubKey ) { int iQ = m_mapQuestDefs.Find( V_atoi( kvSubKey->GetName() ) );
SCHEMA_INIT_CHECK( ( m_mapQuestDefs.IsValidIndex( iQ ) ), CFmtStr( "campaign %d, node %d, Story_block %d, references a non-existant quest index %d.", iC, iCn, iSB, iQ ) );
} } } }
// confirm that all quest expressions are valid
FOR_EACH_MAP_FAST( m_mapQuestDefs, i ) { CEconQuestDefinition * pQuestDef = m_mapQuestDefs.Element( i );
SCHEMA_INIT_CHECK( ( CEconQuestDefinition::IsQuestExpressionValid( pQuestDef->GetQuestExpression() ) ), CFmtStr( "Quest definition %s specifies an expression that does not evaluate.", pQuestDef->GetName() ) );
if ( pQuestDef->GetQuestBonusExpression() && pQuestDef->GetQuestBonusExpression()[ 0 ] ) { SCHEMA_INIT_CHECK( ( CEconQuestDefinition::IsQuestExpressionValid( pQuestDef->GetQuestBonusExpression() ) ), CFmtStr( "Quest definition %s specifies a bonus expression that does not evaluate.", pQuestDef->GetName() ) ); } }
#endif // CLIENT_DLL
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CItemLevelingDefinition::CItemLevelingDefinition( void ) { }
//-----------------------------------------------------------------------------
// Purpose: Copy constructor
//-----------------------------------------------------------------------------
CItemLevelingDefinition::CItemLevelingDefinition( const CItemLevelingDefinition &that ) { (*this) = that; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CItemLevelingDefinition::~CItemLevelingDefinition() { // Free up strdup() memory.
free( m_pszLocalizedName_LocalStorage ); CUtlVector< CUtlString > vecErrors; bool bSuccess = GEconItemSchema().BInit( "scripts/items/unencrypted/items_master.txt", "MOD", &vecErrors ); if( !bSuccess ) { FOR_EACH_VEC( vecErrors, nError ) { Msg( "%s", vecErrors[nError].String() ); } } }
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CItemLevelingDefinition &CItemLevelingDefinition::operator=( const CItemLevelingDefinition &other ) { m_unLevel = other.m_unLevel; m_unRequiredScore = other.m_unRequiredScore; m_pszLocalizedName_LocalStorage = strdup( other.m_pszLocalizedName_LocalStorage );
return *this; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CItemLevelingDefinition::BInitFromKV( KeyValues *pKVItemLevel, CEconItemSchema &pschema, const char *pszLevelBlockName, CUtlVector<CUtlString> *pVecErrors ) { m_unLevel = Q_atoi( pKVItemLevel->GetName() ); m_unRequiredScore = pKVItemLevel->GetInt( "score" ); m_pszLocalizedName_LocalStorage = strdup( pKVItemLevel->GetString( "rank_name", CFmtStr( "%s%i", pszLevelBlockName, m_unLevel ).Access() ) );
return SCHEMA_INIT_SUCCESS(); }
#ifdef GAME_DLL
void ReloadMasterItemSchema( void ) { // This command does nothing on the public universe.
if ( steamapicontext->SteamUtils() && steamapicontext->SteamUtils()->GetConnectedUniverse() == k_EUniversePublic ) return;
CUtlVector< CUtlString > vecErrors; bool bSuccess = GEconItemSchema().BInit( "scripts/items/unencrypted/items_master.txt", "MOD", &vecErrors ); if( !bSuccess ) { FOR_EACH_VEC( vecErrors, nError ) { Msg( "%s", vecErrors[nError].String() ); } } }
CON_COMMAND_F( load_master_item_schema, "Reloads the item master schema.", FCVAR_GAMEDLL | FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY | FCVAR_HIDDEN ) { ReloadMasterItemSchema(); }
#endif
|