mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-10 18:59:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,881 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "attribute_manager.h"
|
||||
#include "gamestringpool.h"
|
||||
#include "saverestore.h"
|
||||
#include "saverestore_utlvector.h"
|
||||
#include "fmtstr.h"
|
||||
#include "KeyValues.h"
|
||||
#include "econ_item_system.h"
|
||||
|
||||
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
|
||||
#include "tf_gamerules.h" // attribute cache flushing; can be generalized if/when Dota needs similar functionality
|
||||
#endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL )
|
||||
|
||||
#define PROVIDER_PARITY_BITS 6
|
||||
#define PROVIDER_PARITY_MASK ((1<<PROVIDER_PARITY_BITS)-1)
|
||||
|
||||
//==================================================================================================================
|
||||
// ATTRIBUTE MANAGER SAVE/LOAD & NETWORKING
|
||||
//===================================================================================================================
|
||||
BEGIN_DATADESC_NO_BASE( CAttributeManager )
|
||||
DEFINE_UTLVECTOR( m_Providers, FIELD_EHANDLE ),
|
||||
DEFINE_UTLVECTOR( m_Receivers, FIELD_EHANDLE ),
|
||||
DEFINE_FIELD( m_iReapplyProvisionParity, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_hOuter, FIELD_EHANDLE ),
|
||||
// DEFINE_FIELD( m_bPreventLoopback, FIELD_BOOLEAN ), // Don't need to save
|
||||
DEFINE_FIELD( m_ProviderType, FIELD_INTEGER ),
|
||||
END_DATADESC()
|
||||
|
||||
BEGIN_DATADESC( CAttributeContainer )
|
||||
DEFINE_EMBEDDED( m_Item ),
|
||||
END_DATADESC()
|
||||
|
||||
#ifndef DOTA_DLL
|
||||
BEGIN_DATADESC( CAttributeContainerPlayer )
|
||||
END_DATADESC()
|
||||
#endif
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
EXTERN_SEND_TABLE( DT_ScriptCreatedItem );
|
||||
#else
|
||||
EXTERN_RECV_TABLE( DT_ScriptCreatedItem );
|
||||
#endif
|
||||
|
||||
BEGIN_NETWORK_TABLE_NOBASE( CAttributeManager, DT_AttributeManager )
|
||||
#ifndef CLIENT_DLL
|
||||
SendPropEHandle( SENDINFO(m_hOuter) ),
|
||||
SendPropInt( SENDINFO(m_ProviderType), 4, SPROP_UNSIGNED ),
|
||||
SendPropInt( SENDINFO(m_iReapplyProvisionParity), PROVIDER_PARITY_BITS, SPROP_UNSIGNED ),
|
||||
#else
|
||||
RecvPropEHandle( RECVINFO(m_hOuter) ),
|
||||
RecvPropInt( RECVINFO(m_ProviderType) ),
|
||||
RecvPropInt( RECVINFO(m_iReapplyProvisionParity) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_NETWORK_TABLE_NOBASE( CAttributeContainer, DT_AttributeContainer )
|
||||
#ifndef CLIENT_DLL
|
||||
SendPropEHandle( SENDINFO(m_hOuter) ),
|
||||
SendPropInt( SENDINFO(m_ProviderType), 4, SPROP_UNSIGNED ),
|
||||
SendPropInt( SENDINFO(m_iReapplyProvisionParity), PROVIDER_PARITY_BITS, SPROP_UNSIGNED ),
|
||||
SendPropDataTable(SENDINFO_DT(m_Item), &REFERENCE_SEND_TABLE(DT_ScriptCreatedItem)),
|
||||
#else
|
||||
RecvPropEHandle( RECVINFO(m_hOuter) ),
|
||||
RecvPropInt( RECVINFO(m_ProviderType) ),
|
||||
RecvPropInt( RECVINFO(m_iReapplyProvisionParity) ),
|
||||
RecvPropDataTable(RECVINFO_DT(m_Item), 0, &REFERENCE_RECV_TABLE(DT_ScriptCreatedItem)),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#ifndef DOTA_DLL
|
||||
BEGIN_NETWORK_TABLE_NOBASE( CAttributeContainerPlayer, DT_AttributeContainerPlayer )
|
||||
#ifndef CLIENT_DLL
|
||||
SendPropEHandle( SENDINFO(m_hOuter) ),
|
||||
SendPropInt( SENDINFO(m_ProviderType), 4, SPROP_UNSIGNED ),
|
||||
SendPropInt( SENDINFO(m_iReapplyProvisionParity), PROVIDER_PARITY_BITS, SPROP_UNSIGNED ),
|
||||
SendPropEHandle( SENDINFO(m_hPlayer) ),
|
||||
#else
|
||||
RecvPropEHandle( RECVINFO(m_hOuter) ),
|
||||
RecvPropInt( RECVINFO(m_ProviderType) ),
|
||||
RecvPropInt( RECVINFO(m_iReapplyProvisionParity) ),
|
||||
RecvPropEHandle( RECVINFO( m_hPlayer ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
#endif
|
||||
|
||||
template< class T > T AttributeConvertFromFloat( float flValue )
|
||||
{
|
||||
return static_cast<T>( flValue );
|
||||
}
|
||||
|
||||
template<> float AttributeConvertFromFloat<float>( float flValue )
|
||||
{
|
||||
return flValue;
|
||||
}
|
||||
|
||||
template<> int AttributeConvertFromFloat<int>( float flValue )
|
||||
{
|
||||
return RoundFloatToInt( flValue );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// All fields in the object are all initialized to 0.
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CAttributeManager::operator new( size_t stAllocateBlock )
|
||||
{
|
||||
// call into engine to get memory
|
||||
Assert( stAllocateBlock != 0 );
|
||||
void *pMem = malloc( stAllocateBlock );
|
||||
memset( pMem, 0, stAllocateBlock );
|
||||
return pMem;
|
||||
};
|
||||
|
||||
void *CAttributeManager::operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine )
|
||||
{
|
||||
// call into engine to get memory
|
||||
Assert( stAllocateBlock != 0 );
|
||||
void *pMem = malloc( stAllocateBlock );
|
||||
memset( pMem, 0, stAllocateBlock );
|
||||
return pMem;
|
||||
}
|
||||
|
||||
CAttributeManager::CAttributeManager()
|
||||
{
|
||||
m_nCalls = 0;
|
||||
m_nCurrentTick = 0;
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAttributeManager::OnPreDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
m_iOldReapplyProvisionParity = m_iReapplyProvisionParity;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAttributeManager::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
if ( m_iReapplyProvisionParity != m_iOldReapplyProvisionParity )
|
||||
{
|
||||
// We've changed who we're providing to in some way. Reapply it.
|
||||
IHasAttributes *pAttribInterface = GetAttribInterface( GetOuter() );
|
||||
if ( pAttribInterface )
|
||||
{
|
||||
pAttribInterface->ReapplyProvision();
|
||||
}
|
||||
|
||||
ClearCache();
|
||||
|
||||
m_iOldReapplyProvisionParity = m_iReapplyProvisionParity.Get();
|
||||
}
|
||||
}
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Call this inside your entity's Spawn()
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAttributeManager::InitializeAttributes( CBaseEntity *pEntity )
|
||||
{
|
||||
Assert( GetAttribInterface( pEntity ) );
|
||||
m_hOuter = pEntity;
|
||||
m_bPreventLoopback = false;
|
||||
}
|
||||
|
||||
//=====================================================================================================
|
||||
// ATTRIBUTE PROVIDERS
|
||||
//=====================================================================================================
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAttributeManager::ProvideTo( CBaseEntity *pProvider )
|
||||
{
|
||||
IHasAttributes *pOwnerAttribInterface = GetAttribInterface( pProvider );
|
||||
if ( pOwnerAttribInterface )
|
||||
{
|
||||
pOwnerAttribInterface->GetAttributeManager()->AddProvider( m_hOuter.Get() );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
m_iReapplyProvisionParity = (m_iReapplyProvisionParity + 1) & PROVIDER_PARITY_MASK;
|
||||
NetworkStateChanged();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAttributeManager::StopProvidingTo( CBaseEntity *pProvider )
|
||||
{
|
||||
IHasAttributes *pOwnerAttribInterface = GetAttribInterface( pProvider );
|
||||
if ( pOwnerAttribInterface )
|
||||
{
|
||||
pOwnerAttribInterface->GetAttributeManager()->RemoveProvider( m_hOuter.Get() );
|
||||
#ifndef CLIENT_DLL
|
||||
m_iReapplyProvisionParity = (m_iReapplyProvisionParity + 1) & PROVIDER_PARITY_MASK;
|
||||
NetworkStateChanged();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAttributeManager::AddProvider( CBaseEntity *pProvider )
|
||||
{
|
||||
// Make sure he's not already in our list, and prevent circular provision
|
||||
Assert( !IsBeingProvidedToBy(pProvider) );
|
||||
Assert( !IsProvidingTo(pProvider) );
|
||||
|
||||
// Ensure he's allowed to provide
|
||||
IHasAttributes *pProviderAttrInterface = GetAttribInterface( pProvider );
|
||||
Assert( pProviderAttrInterface );
|
||||
|
||||
m_Providers.AddToTail( pProvider );
|
||||
pProviderAttrInterface->GetAttributeManager()->m_Receivers.AddToTail( GetOuter() );
|
||||
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAttributeManager::RemoveProvider( CBaseEntity *pProvider )
|
||||
{
|
||||
Assert( pProvider );
|
||||
|
||||
IHasAttributes *pProviderAttrInterface = GetAttribInterface( pProvider );
|
||||
Assert( pProviderAttrInterface );
|
||||
|
||||
if ( !IsBeingProvidedToBy( pProvider ) )
|
||||
return;
|
||||
|
||||
Assert( pProviderAttrInterface->GetAttributeManager()->IsProvidingTo( GetOuter() ) );
|
||||
Assert( pProviderAttrInterface->GetAttributeManager()->m_Receivers.Find( GetOuter() ) != pProviderAttrInterface->GetAttributeManager()->m_Receivers.InvalidIndex() );
|
||||
|
||||
m_Providers.FindAndFastRemove( pProvider );
|
||||
pProviderAttrInterface->GetAttributeManager()->m_Receivers.FindAndFastRemove( GetOuter() );
|
||||
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAttributeManager::ClearCache( void )
|
||||
{
|
||||
if ( m_bPreventLoopback )
|
||||
return;
|
||||
|
||||
m_CachedResults.Purge();
|
||||
|
||||
m_bPreventLoopback = true;
|
||||
|
||||
// Tell all providers relying on me that they need to wipe their cache too
|
||||
FOR_EACH_VEC( m_Receivers, i )
|
||||
{
|
||||
IHasAttributes *pAttribInterface = GetAttribInterface( m_Receivers[i].Get() );
|
||||
if ( pAttribInterface )
|
||||
{
|
||||
pAttribInterface->GetAttributeManager()->ClearCache();
|
||||
}
|
||||
}
|
||||
|
||||
// Tell our owner that he needs to clear his too, in case he has attributes affecting him
|
||||
IHasAttributes *pMyAttribInterface = GetAttribInterface( m_hOuter.Get().Get() );
|
||||
if ( pMyAttribInterface )
|
||||
{
|
||||
pMyAttribInterface->GetAttributeManager()->ClearCache();
|
||||
}
|
||||
|
||||
m_bPreventLoopback = false;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// Force out client to clear their cache as well
|
||||
m_iReapplyProvisionParity = (m_iReapplyProvisionParity + 1) & PROVIDER_PARITY_MASK;
|
||||
NetworkStateChanged();
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAttributeManager::GetGlobalCacheVersion() const
|
||||
{
|
||||
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
|
||||
return TFGameRules() ? TFGameRules()->GetGlobalAttributeCacheVersion() : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this entity is providing attributes to the specified entity
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CAttributeManager::IsProvidingTo( CBaseEntity *pEntity ) const
|
||||
{
|
||||
IHasAttributes *pAttribInterface = GetAttribInterface( pEntity );
|
||||
if ( pAttribInterface )
|
||||
{
|
||||
if ( pAttribInterface->GetAttributeManager()->IsBeingProvidedToBy( GetOuter() ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this entity is being provided attributes by the specified entity
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CAttributeManager::IsBeingProvidedToBy( CBaseEntity *pEntity ) const
|
||||
{
|
||||
return ( m_Providers.Find( pEntity ) != m_Providers.InvalidIndex() );
|
||||
}
|
||||
|
||||
//=====================================================================================================
|
||||
// ATTRIBUTE HOOKS
|
||||
//=====================================================================================================
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Wrapper that checks to see if we've already got the result in our cache
|
||||
//-----------------------------------------------------------------------------
|
||||
float CAttributeManager::ApplyAttributeFloatWrapper( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
|
||||
{
|
||||
VPROF_BUDGET( "CAttributeManager::ApplyAttributeFloatWrapper", VPROF_BUDGETGROUP_ATTRIBUTES );
|
||||
|
||||
#ifdef DEBUG
|
||||
AssertMsg1( m_nCalls != 5000, "%d calls for attributes in a single tick. This is slow and bad.", m_nCalls );
|
||||
|
||||
if( m_nCurrentTick != gpGlobals->tickcount )
|
||||
{
|
||||
m_nCalls = 0;
|
||||
m_nCurrentTick = gpGlobals->tickcount;
|
||||
}
|
||||
|
||||
++m_nCalls;
|
||||
#endif
|
||||
|
||||
// Have we requested a global attribute cache flush?
|
||||
const int iGlobalCacheVersion = GetGlobalCacheVersion();
|
||||
if ( m_iCacheVersion != iGlobalCacheVersion )
|
||||
{
|
||||
ClearCache();
|
||||
m_iCacheVersion = iGlobalCacheVersion;
|
||||
}
|
||||
|
||||
// We can't cache off item references so if we asked for them we need to execute the whole slow path.
|
||||
if ( !pItemList )
|
||||
{
|
||||
int iCount = m_CachedResults.Count();
|
||||
for ( int i = iCount-1; i >= 0; i-- )
|
||||
{
|
||||
if ( m_CachedResults[i].iAttribHook == iszAttribHook )
|
||||
{
|
||||
if ( m_CachedResults[i].in.fl == flValue )
|
||||
return m_CachedResults[i].out.fl;
|
||||
|
||||
// We've got a cached result for a different flIn value. Remove the cached result to
|
||||
// prevent stacking up entries for different requests (i.e. crit chance)
|
||||
m_CachedResults.Remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wasn't in cache, or we need item references. Do the work.
|
||||
float flResult = ApplyAttributeFloat( flValue, pInitiator, iszAttribHook, pItemList );
|
||||
|
||||
// Add it to our cache if we didn't ask for item references. We could add the result value here
|
||||
// even if we did but we'd need to walk the cache to search for an old entry to overwrite first.
|
||||
if ( !pItemList )
|
||||
{
|
||||
int iIndex = m_CachedResults.AddToTail();
|
||||
m_CachedResults[iIndex].in.fl = flValue;
|
||||
m_CachedResults[iIndex].out.fl = flResult;
|
||||
m_CachedResults[iIndex].iAttribHook = iszAttribHook;
|
||||
}
|
||||
|
||||
return flResult;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Wrapper that checks to see if we've already got the result in our cache
|
||||
//-----------------------------------------------------------------------------
|
||||
string_t CAttributeManager::ApplyAttributeStringWrapper( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList /*= NULL*/ )
|
||||
{
|
||||
// Have we requested a global attribute cache flush?
|
||||
const int iGlobalCacheVersion = GetGlobalCacheVersion();
|
||||
if ( m_iCacheVersion != iGlobalCacheVersion )
|
||||
{
|
||||
ClearCache();
|
||||
m_iCacheVersion = iGlobalCacheVersion;
|
||||
}
|
||||
|
||||
// We can't cache off item references so if we asked for them we need to execute the whole slow path.
|
||||
if ( !pItemList )
|
||||
{
|
||||
int iCount = m_CachedResults.Count();
|
||||
for ( int i = iCount-1; i >= 0; i-- )
|
||||
{
|
||||
if ( m_CachedResults[i].iAttribHook == iszAttribHook )
|
||||
{
|
||||
if ( m_CachedResults[i].in.isz == iszValue )
|
||||
{
|
||||
return m_CachedResults[i].out.isz;
|
||||
}
|
||||
|
||||
// We've got a cached result for a different flIn value. Remove the cached result to
|
||||
// prevent stacking up entries for different requests (i.e. crit chance)
|
||||
m_CachedResults.Remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wasn't in cache, or we need item references. Do the work.
|
||||
string_t iszOut = ApplyAttributeString( iszValue, pInitiator, iszAttribHook, pItemList );
|
||||
|
||||
// Add it to our cache if we didn't ask for item references. We could add the result value here
|
||||
// even if we did but we'd need to walk the cache to search for an old entry to overwrite first.
|
||||
if ( !pItemList )
|
||||
{
|
||||
int iIndex = m_CachedResults.AddToTail();
|
||||
m_CachedResults[iIndex].in.isz = iszValue;
|
||||
m_CachedResults[iIndex].out.isz = iszOut;
|
||||
m_CachedResults[iIndex].iAttribHook = iszAttribHook;
|
||||
}
|
||||
|
||||
return iszOut;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
float CAttributeManager::ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
|
||||
{
|
||||
VPROF_BUDGET( "CAttributeManager::ApplyAttributeFloat", VPROF_BUDGETGROUP_ATTRIBUTES );
|
||||
|
||||
if ( m_bPreventLoopback || !GetOuter() )
|
||||
return flValue;
|
||||
|
||||
// We need to prevent loopback between two items both providing to the same entity.
|
||||
m_bPreventLoopback = true;
|
||||
|
||||
IHasAttributes *pInitiatorAttribInterface = GetAttribInterface( pInitiator );
|
||||
|
||||
// See if we have any providers. If we do, tell them to apply.
|
||||
FOR_EACH_VEC( m_Providers, iHook )
|
||||
{
|
||||
CBaseEntity *pProvider = m_Providers[iHook].Get();
|
||||
|
||||
if ( !pProvider )
|
||||
continue;
|
||||
|
||||
if ( pProvider == pInitiator )
|
||||
continue;
|
||||
|
||||
IHasAttributes *pAttribInterface = GetAttribInterface( pProvider );
|
||||
Assert( pAttribInterface );
|
||||
|
||||
// Don't allow weapons to provide to other weapons being carried by the same person
|
||||
if ( pInitiatorAttribInterface &&
|
||||
pAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON &&
|
||||
pInitiatorAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
flValue = pAttribInterface->GetAttributeManager()->ApplyAttributeFloat( flValue, pInitiator, iszAttribHook, pItemList );
|
||||
}
|
||||
|
||||
// Then see if our owner has any attributes he wants to apply as well.
|
||||
// i.e. An aura is providing attributes to this weapon's carrier.
|
||||
IHasAttributes *pMyAttribInterface = GetAttribInterface( m_hOuter.Get().Get() );
|
||||
Assert( pMyAttribInterface );
|
||||
|
||||
if ( pMyAttribInterface && pMyAttribInterface->GetAttributeOwner() )
|
||||
{
|
||||
IHasAttributes *pOwnerAttribInterface = GetAttribInterface( pMyAttribInterface->GetAttributeOwner() );
|
||||
if ( pOwnerAttribInterface )
|
||||
{
|
||||
flValue = pOwnerAttribInterface->GetAttributeManager()->ApplyAttributeFloat( flValue, pInitiator, iszAttribHook, pItemList );
|
||||
}
|
||||
}
|
||||
|
||||
m_bPreventLoopback = false;
|
||||
|
||||
return flValue;
|
||||
}
|
||||
|
||||
string_t CAttributeManager::ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook /*= NULL_STRING*/, CUtlVector<CBaseEntity*> *pItemList /*= NULL*/ )
|
||||
{
|
||||
VPROF_BUDGET( "CAttributeManager::ApplyAttributeString", VPROF_BUDGETGROUP_ATTRIBUTES );
|
||||
|
||||
if ( m_bPreventLoopback || !GetOuter() )
|
||||
return iszValue;
|
||||
|
||||
// We need to prevent loopback between two items both providing to the same entity.
|
||||
m_bPreventLoopback = true;
|
||||
|
||||
IHasAttributes *pInitiatorAttribInterface = GetAttribInterface( pInitiator );
|
||||
|
||||
// See if we have any providers. If we do, tell them to apply.
|
||||
FOR_EACH_VEC( m_Providers, iHook )
|
||||
{
|
||||
CBaseEntity *pProvider = m_Providers[iHook].Get();
|
||||
|
||||
if ( !pProvider )
|
||||
continue;
|
||||
|
||||
if ( pProvider == pInitiator )
|
||||
continue;
|
||||
|
||||
IHasAttributes *pAttribInterface = GetAttribInterface( pProvider );
|
||||
Assert( pAttribInterface );
|
||||
|
||||
// Don't allow weapons to provide to other weapons being carried by the same person
|
||||
if ( pInitiatorAttribInterface &&
|
||||
pAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON &&
|
||||
pInitiatorAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
iszValue = pAttribInterface->GetAttributeManager()->ApplyAttributeString( iszValue, pInitiator, iszAttribHook, pItemList );
|
||||
}
|
||||
|
||||
// Then see if our owner has any attributes he wants to apply as well.
|
||||
// i.e. An aura is providing attributes to this weapon's carrier.
|
||||
IHasAttributes *pMyAttribInterface = GetAttribInterface( m_hOuter.Get().Get() );
|
||||
Assert( pMyAttribInterface );
|
||||
|
||||
if ( pMyAttribInterface->GetAttributeOwner() )
|
||||
{
|
||||
IHasAttributes *pOwnerAttribInterface = GetAttribInterface( pMyAttribInterface->GetAttributeOwner() );
|
||||
if ( pOwnerAttribInterface )
|
||||
{
|
||||
iszValue = pOwnerAttribInterface->GetAttributeManager()->ApplyAttributeString( iszValue, pInitiator, iszAttribHook, pItemList );
|
||||
}
|
||||
}
|
||||
|
||||
m_bPreventLoopback = false;
|
||||
|
||||
return iszValue;
|
||||
}
|
||||
|
||||
//=====================================================================================================
|
||||
// ATTRIBUTE CONTAINER
|
||||
//=====================================================================================================
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Call this inside your entity's Spawn()
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAttributeContainer::InitializeAttributes( CBaseEntity *pEntity )
|
||||
{
|
||||
BaseClass::InitializeAttributes( pEntity );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
/*
|
||||
if ( !m_Item.IsValid() )
|
||||
{
|
||||
Warning("Item '%s' not setup correctly. Attempting to create attributes on an unitialized item.\n", m_hOuter.Get()->GetDebugName() );
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
m_Item.GetAttributeList()->SetManager( this );
|
||||
|
||||
OnAttributeValuesChanged();
|
||||
}
|
||||
|
||||
static void ApplyAttribute( const CEconItemAttributeDefinition *pAttributeDef, float& flValue, const float flValueModifier )
|
||||
{
|
||||
Assert( pAttributeDef );
|
||||
Assert( pAttributeDef->GetAttributeType() );
|
||||
AssertMsg1( pAttributeDef->GetAttributeType()->BSupportsGameplayModificationAndNetworking(), "Attempt to hook the value of attribute '%s' which doesn't support hooking! Pull the value of the attribute directly using FindAttribute()!", pAttributeDef->GetDefinitionName() );
|
||||
|
||||
const int iAttrDescFormat = pAttributeDef->GetDescriptionFormat();
|
||||
|
||||
switch ( iAttrDescFormat )
|
||||
{
|
||||
case ATTDESCFORM_VALUE_IS_PERCENTAGE:
|
||||
case ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE:
|
||||
{
|
||||
flValue *= flValueModifier;
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTDESCFORM_VALUE_IS_ADDITIVE:
|
||||
case ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE:
|
||||
case ATTDESCFORM_VALUE_IS_PARTICLE_INDEX:
|
||||
{
|
||||
flValue += flValueModifier;
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTDESCFORM_VALUE_IS_KILLSTREAK_IDLEEFFECT_INDEX:
|
||||
case ATTDESCFORM_VALUE_IS_KILLSTREAKEFFECT_INDEX:
|
||||
case ATTDESCFORM_VALUE_IS_FROM_LOOKUP_TABLE:
|
||||
{
|
||||
flValue = flValueModifier;
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTDESCFORM_VALUE_IS_OR:
|
||||
{
|
||||
int iTmp = flValue;
|
||||
iTmp |= (int)flValueModifier;
|
||||
flValue = iTmp;
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTDESCFORM_VALUE_IS_DATE:
|
||||
Assert( !"Attempt to apply date attribute in ApplyAttribute()." ); // No-one should be hooking date descriptions
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown value format.
|
||||
AssertMsg1( false, "Unknown attribute value type %i in ApplyAttribute().", iAttrDescFormat );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Given two attributes, return a collated value.
|
||||
//-----------------------------------------------------------------------------
|
||||
float CollateAttributeValues( const CEconItemAttributeDefinition *pAttrDef1, const float flAttribValue1, const CEconItemAttributeDefinition *pAttrDef2, const float flAttribValue2 )
|
||||
{
|
||||
Assert( pAttrDef1 );
|
||||
Assert( pAttrDef2 );
|
||||
AssertMsg2( !Q_stricmp( pAttrDef1->GetAttributeClass(), pAttrDef2->GetAttributeClass() ), "We can only collate attributes of matching definitions: mismatch between '%s' / '%s'!", pAttrDef1->GetAttributeClass(), pAttrDef2->GetAttributeClass() );
|
||||
AssertMsg2( pAttrDef1->GetDescriptionFormat() == pAttrDef2->GetDescriptionFormat(), "We can only collate attributes of matching description format: mismatch between '%u' / '%u'!", pAttrDef1->GetDescriptionFormat(), pAttrDef2->GetDescriptionFormat() );
|
||||
|
||||
const int iAttrDescFormat = pAttrDef1->GetDescriptionFormat();
|
||||
|
||||
float flValue = 0;
|
||||
switch ( iAttrDescFormat )
|
||||
{
|
||||
case ATTDESCFORM_VALUE_IS_PERCENTAGE:
|
||||
case ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE:
|
||||
{
|
||||
flValue = 1.0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTDESCFORM_VALUE_IS_ADDITIVE:
|
||||
case ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE:
|
||||
case ATTDESCFORM_VALUE_IS_FROM_LOOKUP_TABLE:
|
||||
case ATTDESCFORM_VALUE_IS_OR:
|
||||
{
|
||||
flValue = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTDESCFORM_VALUE_IS_DATE:
|
||||
Assert( !"Attempt to apply date attribute in CollateAttributeValues()." ); // No-one should be hooking date descriptions
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown value format.
|
||||
AssertMsg1( false, "Unknown attribute value type %i in ApplyAttribute().", iAttrDescFormat );
|
||||
break;
|
||||
}
|
||||
|
||||
ApplyAttribute( pAttrDef1, flValue, flAttribValue1 );
|
||||
ApplyAttribute( pAttrDef2, flValue, flAttribValue2 );
|
||||
|
||||
return flValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemAttributeIterator_ApplyAttributeFloat : public CEconItemSpecificAttributeIterator
|
||||
{
|
||||
public:
|
||||
CEconItemAttributeIterator_ApplyAttributeFloat( CBaseEntity *pOuter, float flInitialValue, string_t iszAttribHook, CUtlVector<CBaseEntity *> *pItemList )
|
||||
: m_pOuter( pOuter )
|
||||
, m_flValue( flInitialValue )
|
||||
, m_iszAttribHook( iszAttribHook )
|
||||
, m_pItemList( pItemList )
|
||||
{
|
||||
Assert( pOuter );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value )
|
||||
{
|
||||
COMPILE_TIME_ASSERT( sizeof( value ) == sizeof( float ) );
|
||||
|
||||
Assert( pAttrDef );
|
||||
|
||||
if ( pAttrDef->GetCachedClass() != m_iszAttribHook )
|
||||
return true;
|
||||
|
||||
if ( m_pItemList && !m_pItemList->HasElement( m_pOuter ) )
|
||||
{
|
||||
m_pItemList->AddToTail( m_pOuter );
|
||||
}
|
||||
|
||||
ApplyAttribute( pAttrDef, m_flValue, *reinterpret_cast<float *>( &value ) );
|
||||
|
||||
// We assume that each attribute can only be in the attribute list for a single item once, but we're
|
||||
// iterating over attribute *classes* here, not unique attribute types, so we carry on looking.
|
||||
return true;
|
||||
}
|
||||
|
||||
float GetResultValue() const
|
||||
{
|
||||
return m_flValue;
|
||||
}
|
||||
|
||||
private:
|
||||
CBaseEntity *m_pOuter;
|
||||
float m_flValue;
|
||||
string_t m_iszAttribHook;
|
||||
CUtlVector<CBaseEntity *> *m_pItemList;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
float CAttributeContainer::ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
|
||||
{
|
||||
if ( m_bPreventLoopback || !GetOuter() )
|
||||
return flValue;
|
||||
|
||||
// We need to prevent loopback between two items both providing to the same entity.
|
||||
m_bPreventLoopback = true;
|
||||
|
||||
// ...
|
||||
CEconItemAttributeIterator_ApplyAttributeFloat it( GetOuter(), flValue, iszAttribHook, pItemList );
|
||||
m_Item.IterateAttributes( &it );
|
||||
|
||||
m_bPreventLoopback = false;
|
||||
|
||||
return BaseClass::ApplyAttributeFloat( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
|
||||
}
|
||||
|
||||
#ifndef DOTA_DLL
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
float CAttributeContainerPlayer::ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
|
||||
{
|
||||
if ( m_bPreventLoopback || !GetOuter() )
|
||||
return flValue;
|
||||
|
||||
m_bPreventLoopback = true;
|
||||
|
||||
CEconItemAttributeIterator_ApplyAttributeFloat it( GetOuter(), flValue, iszAttribHook, pItemList );
|
||||
|
||||
CBasePlayer *pPlayer = GetPlayer();
|
||||
if ( pPlayer )
|
||||
{
|
||||
pPlayer->m_AttributeList.IterateAttributes( &it );
|
||||
}
|
||||
|
||||
m_bPreventLoopback = false;
|
||||
|
||||
return BaseClass::ApplyAttributeFloat( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemAttributeIterator_ApplyAttributeString : public CEconItemSpecificAttributeIterator
|
||||
{
|
||||
public:
|
||||
CEconItemAttributeIterator_ApplyAttributeString( CBaseEntity *pOuter, string_t iszInitialValue, string_t iszAttribHook, CUtlVector<CBaseEntity *> *pItemList )
|
||||
: m_pOuter( pOuter )
|
||||
, m_iszValue( iszInitialValue )
|
||||
, m_iszAttribHook( iszAttribHook )
|
||||
, m_pItemList( pItemList )
|
||||
, m_bFoundString( false )
|
||||
{
|
||||
Assert( pOuter );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value )
|
||||
{
|
||||
COMPILE_TIME_ASSERT( sizeof( value ) == sizeof( float ) );
|
||||
|
||||
// Do we want to process attribute of this type?
|
||||
Assert( pAttrDef );
|
||||
Assert( pAttrDef->GetCachedClass() != m_iszAttribHook );
|
||||
//AssertMsg( 0, "OnIterateAttributeValue of type CAttribute_String, we shouldn't get here." );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value )
|
||||
{
|
||||
Assert( pAttrDef );
|
||||
|
||||
if ( pAttrDef->GetCachedClass() != m_iszAttribHook )
|
||||
return true;
|
||||
|
||||
if ( FoundString() )
|
||||
return true;
|
||||
|
||||
m_iszValue = AllocPooledString( value.value().c_str() );
|
||||
|
||||
m_bFoundString = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string_t GetResultValue()
|
||||
{
|
||||
return m_iszValue;
|
||||
}
|
||||
|
||||
private:
|
||||
bool FoundString()
|
||||
{
|
||||
// Implement something for the case where there's more than one of the same attribute
|
||||
AssertMsg( !m_bFoundString, "Already found a string attribute with %s class, return the first attribute found.", STRING( m_iszAttribHook ) );
|
||||
|
||||
return m_bFoundString;
|
||||
}
|
||||
|
||||
CBaseEntity *m_pOuter;
|
||||
string_t m_iszValue;
|
||||
string_t m_iszAttribHook;
|
||||
CUtlVector<CBaseEntity *> *m_pItemList;
|
||||
bool m_bFoundString;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
string_t CAttributeContainer::ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook /*= NULL_STRING*/, CUtlVector<CBaseEntity*> *pItemList /*= NULL*/ )
|
||||
{
|
||||
if ( m_bPreventLoopback || !GetOuter() )
|
||||
return iszValue;
|
||||
|
||||
// We need to prevent loopback between two items both providing to the same entity.
|
||||
m_bPreventLoopback = true;
|
||||
|
||||
// ...
|
||||
CEconItemAttributeIterator_ApplyAttributeString it( GetOuter(), iszValue, iszAttribHook, pItemList );
|
||||
m_Item.IterateAttributes( &it );
|
||||
|
||||
m_bPreventLoopback = false;
|
||||
|
||||
return BaseClass::ApplyAttributeString( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
|
||||
}
|
||||
|
||||
|
||||
string_t CAttributeContainerPlayer::ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook /*= NULL_STRING*/, CUtlVector<CBaseEntity*> *pItemList /*= NULL*/ )
|
||||
{
|
||||
if ( m_bPreventLoopback || !GetOuter() )
|
||||
return iszValue;
|
||||
|
||||
m_bPreventLoopback = true;
|
||||
|
||||
CEconItemAttributeIterator_ApplyAttributeString it( GetOuter(), iszValue, iszAttribHook, pItemList );
|
||||
|
||||
CBasePlayer *pPlayer = GetPlayer();
|
||||
if ( pPlayer )
|
||||
{
|
||||
pPlayer->m_AttributeList.IterateAttributes( &it );
|
||||
}
|
||||
|
||||
m_bPreventLoopback = false;
|
||||
|
||||
return BaseClass::ApplyAttributeString( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Attributable entities contain one of these, which handles game specific handling:
|
||||
// - Save / Restore
|
||||
// - Networking
|
||||
// - Attribute providers
|
||||
// - Application of attribute effects
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ATTRIBUTE_MANAGER_H
|
||||
#define ATTRIBUTE_MANAGER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "econ_item_view.h"
|
||||
#include "ihasattributes.h"
|
||||
#include "tf_gcmessages.h"
|
||||
|
||||
// Provider types
|
||||
enum attributeprovidertypes_t
|
||||
{
|
||||
PROVIDER_GENERIC,
|
||||
PROVIDER_WEAPON,
|
||||
};
|
||||
|
||||
float CollateAttributeValues( const CEconItemAttributeDefinition *pAttrDef1, const float flAttribValue1, const CEconItemAttributeDefinition *pAttrDef2, const float flAttribValue2 );
|
||||
|
||||
// Retrieve the IHasAttributes pointer from a Base Entity. This function checks for NULL entities
|
||||
// and asserts the return value is == to dynamic_cast< IHasAttributes * >( pEntity ).
|
||||
inline IHasAttributes *GetAttribInterface( CBaseEntity *pEntity )
|
||||
{
|
||||
IHasAttributes *pAttribInterface = pEntity ? pEntity->GetHasAttributesInterfacePtr() : NULL;
|
||||
// If this assert hits it most likely means that m_pAttribInterface has not been set
|
||||
// in the leaf class constructor for this object. See CTFPlayer::CTFPlayer() for an
|
||||
// example.
|
||||
Assert( pAttribInterface == dynamic_cast< IHasAttributes *>( pEntity ) );
|
||||
return pAttribInterface;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Macros for hooking the application of attributes
|
||||
#define CALL_ATTRIB_HOOK( vartype, retval, hookName, who, itemlist ) \
|
||||
retval = CAttributeManager::AttribHookValue<vartype>( retval, #hookName, static_cast<const CBaseEntity*>( who ), itemlist, true );
|
||||
|
||||
#define CALL_ATTRIB_HOOK_INT( retval, hookName ) CALL_ATTRIB_HOOK( int, retval, hookName, this, NULL )
|
||||
#define CALL_ATTRIB_HOOK_FLOAT( retval, hookName ) CALL_ATTRIB_HOOK( float, retval, hookName, this, NULL )
|
||||
#define CALL_ATTRIB_HOOK_STRING( retval, hookName ) CALL_ATTRIB_HOOK( CAttribute_String, retval, hookName, this, NULL )
|
||||
#define CALL_ATTRIB_HOOK_INT_ON_OTHER( other, retval, hookName ) CALL_ATTRIB_HOOK( int, retval, hookName, other, NULL )
|
||||
#define CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( other, retval, hookName ) CALL_ATTRIB_HOOK( float, retval, hookName, other, NULL )
|
||||
#define CALL_ATTRIB_HOOK_STRING_ON_OTHER( other, retval, hookName ) CALL_ATTRIB_HOOK( CAttribute_String, retval, hookName, other, NULL )
|
||||
#define CALL_ATTRIB_HOOK_INT_ON_OTHER_WITH_ITEMS( other, retval, items_array, hookName ) CALL_ATTRIB_HOOK( int, retval, hookName, other, items_array )
|
||||
#define CALL_ATTRIB_HOOK_FLOAT_ON_OTHER_WITH_ITEMS( other, retval, items_array, hookName ) CALL_ATTRIB_HOOK( float, retval, hookName, other, items_array )
|
||||
#define CALL_ATTRIB_HOOK_STRING_ON_OTHER_WITH_ITEMS( other, retval, items_array, hookName ) CALL_ATTRIB_HOOK( CAttribute_String, retval, hookName, other, items_array )
|
||||
|
||||
template< class T > T AttributeConvertFromFloat( float flValue );
|
||||
template<> float AttributeConvertFromFloat<float>( float flValue );
|
||||
template<> int AttributeConvertFromFloat<int>( float flValue );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Base Attribute manager.
|
||||
// This class knows how to apply attribute effects that have been
|
||||
// provided to its owner by other entities, but doesn't contain attributes itself.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAttributeManager
|
||||
{
|
||||
DECLARE_CLASS_NOBASE( CAttributeManager );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_EMBEDDED_NETWORKVAR();
|
||||
|
||||
CAttributeManager();
|
||||
virtual ~CAttributeManager() {}
|
||||
|
||||
// Call this inside your entity's Spawn()
|
||||
virtual void InitializeAttributes( CBaseEntity *pEntity );
|
||||
|
||||
CBaseEntity *GetOuter( void ) const { return m_hOuter.Get(); }
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Attribute providers.
|
||||
// Other entities that are providing attributes to this entity (i.e. weapons being carried by a player)
|
||||
void ProvideTo( CBaseEntity *pProvider );
|
||||
void StopProvidingTo( CBaseEntity *pProvider );
|
||||
|
||||
protected:
|
||||
// Not to be called directly. Use ProvideTo() or StopProvidingTo() above.
|
||||
void AddProvider( CBaseEntity *pProvider );
|
||||
void RemoveProvider( CBaseEntity *pProvider );
|
||||
|
||||
public:
|
||||
// Return true if this entity is providing attributes to the specified entity
|
||||
bool IsProvidingTo( CBaseEntity *pEntity ) const;
|
||||
|
||||
// Return true if this entity is being provided attributes by the specified entity
|
||||
bool IsBeingProvidedToBy( CBaseEntity *pEntity ) const;
|
||||
|
||||
// Provider types are used to prevent specified providers supplying to certain initiators
|
||||
void SetProviderType( attributeprovidertypes_t tType ) { m_ProviderType = tType; }
|
||||
attributeprovidertypes_t GetProviderType( void ) const { return m_ProviderType; }
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Attribute hook. Use the CALL_ATTRIB_HOOK macros above.
|
||||
template <class T> static T AttribHookValue( T TValue, const char *pszAttribHook, const CBaseEntity *pEntity, CUtlVector<CBaseEntity*> *pItemList = NULL, bool bIsGlobalConstString = false )
|
||||
{
|
||||
VPROF_BUDGET( "CAttributeManager::AttribHookValue", VPROF_BUDGETGROUP_ATTRIBUTES );
|
||||
|
||||
// Do we have a hook?
|
||||
if ( pszAttribHook == NULL || pszAttribHook[0] == '\0' )
|
||||
return TValue;
|
||||
|
||||
// Verify that we have an entity, at least as "this"
|
||||
if ( pEntity == NULL )
|
||||
return TValue;
|
||||
|
||||
IHasAttributes *pAttribInterface = GetAttribInterface( (CBaseEntity*) pEntity );
|
||||
AssertMsg( pAttribInterface, "If you hit this, you've probably got a hook incorrectly setup, because the entity it's hooking on doesn't know about attributes." );
|
||||
if ( pAttribInterface == NULL )
|
||||
return TValue;
|
||||
|
||||
// Hook base attribute.
|
||||
T Scratch;
|
||||
AttribHookValueInternal( Scratch, TValue, pszAttribHook, pEntity, pAttribInterface, pItemList, bIsGlobalConstString );
|
||||
|
||||
return Scratch;
|
||||
}
|
||||
|
||||
private:
|
||||
template <class T> static void TypedAttribHookValueInternal( T& out, T TValue, string_t iszAttribHook, const CBaseEntity *pEntity, IHasAttributes *pAttribInterface, CUtlVector<CBaseEntity*> *pItemList )
|
||||
{
|
||||
float flValue = pAttribInterface->GetAttributeManager()->ApplyAttributeFloatWrapper( static_cast<float>( TValue ), const_cast<CBaseEntity *>( pEntity ), iszAttribHook, pItemList );
|
||||
|
||||
out = AttributeConvertFromFloat<T>( flValue );
|
||||
}
|
||||
|
||||
static void TypedAttribHookValueInternal( CAttribute_String& out, const CAttribute_String& TValue, string_t iszAttribHook, const CBaseEntity *pEntity, IHasAttributes *pAttribInterface, CUtlVector<CBaseEntity*> *pItemList )
|
||||
{
|
||||
string_t iszIn = AllocPooledString( TValue.value().c_str() );
|
||||
string_t iszOut = pAttribInterface->GetAttributeManager()->ApplyAttributeStringWrapper( iszIn, const_cast<CBaseEntity *>( pEntity ), iszAttribHook, pItemList );
|
||||
const char* pszOut = STRING( iszOut );
|
||||
// STRING() returns different value for server and client
|
||||
// server will return "" for NULL_STRING
|
||||
// client will return NULL for NULL_STRING
|
||||
if ( pszOut )
|
||||
{
|
||||
out.set_value( pszOut );
|
||||
}
|
||||
else
|
||||
{
|
||||
out.set_value( "" );
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> static void AttribHookValueInternal( T& out, T TValue, const char *pszAttribHook, const CBaseEntity *pEntity, IHasAttributes *pAttribInterface, CUtlVector<CBaseEntity*> *pItemList, bool bIsGlobalConstString )
|
||||
{
|
||||
Assert( pszAttribHook );
|
||||
Assert( pszAttribHook[0] );
|
||||
Assert( pEntity );
|
||||
Assert( pAttribInterface );
|
||||
Assert( GetAttribInterface( (CBaseEntity*) pEntity ) == pAttribInterface );
|
||||
Assert( pAttribInterface->GetAttributeManager() );
|
||||
|
||||
string_t iszAttribHook = bIsGlobalConstString ? AllocPooledString_StaticConstantStringPointer( pszAttribHook ) : AllocPooledString( pszAttribHook );
|
||||
return TypedAttribHookValueInternal( out, TValue, iszAttribHook, pEntity, pAttribInterface, pItemList );
|
||||
}
|
||||
int m_nCurrentTick;
|
||||
int m_nCalls;
|
||||
|
||||
public:
|
||||
virtual float ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL );
|
||||
virtual string_t ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL );
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Networking
|
||||
#ifdef CLIENT_DLL
|
||||
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------
|
||||
// memory handling
|
||||
void *operator new( size_t stAllocateBlock );
|
||||
void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine );
|
||||
|
||||
protected:
|
||||
CUtlVector<EHANDLE> m_Providers; // entities that we receive attribute data *from*
|
||||
CUtlVector<EHANDLE> m_Receivers; // entities that we provide attribute data *to*
|
||||
CNetworkVarForDerived( int, m_iReapplyProvisionParity );
|
||||
CNetworkVarForDerived( EHANDLE, m_hOuter );
|
||||
bool m_bPreventLoopback;
|
||||
CNetworkVarForDerived( attributeprovidertypes_t, m_ProviderType );
|
||||
int m_iCacheVersion; // maps to gamerules counter for global cache flushing
|
||||
|
||||
public:
|
||||
virtual void OnAttributeValuesChanged()
|
||||
{
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
private:
|
||||
void ClearCache();
|
||||
int GetGlobalCacheVersion() const;
|
||||
|
||||
virtual float ApplyAttributeFloatWrapper( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList = NULL );
|
||||
virtual string_t ApplyAttributeStringWrapper( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList = NULL );
|
||||
|
||||
// Cached attribute results
|
||||
// We cache off requests for data, and wipe the cache whenever our providers change.
|
||||
union cached_attribute_types
|
||||
{
|
||||
float fl;
|
||||
string_t isz;
|
||||
};
|
||||
|
||||
struct cached_attribute_t
|
||||
{
|
||||
string_t iAttribHook;
|
||||
cached_attribute_types in;
|
||||
cached_attribute_types out;
|
||||
};
|
||||
CUtlVector<cached_attribute_t> m_CachedResults;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
public:
|
||||
// Data received from the server
|
||||
int m_iOldReapplyProvisionParity;
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This is an attribute manager that also knows how to contain attributes.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAttributeContainer : public CAttributeManager
|
||||
{
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_CLASS( CAttributeContainer, CAttributeManager );
|
||||
DECLARE_EMBEDDED_NETWORKVAR();
|
||||
|
||||
virtual void InitializeAttributes( CBaseEntity *pEntity );
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Attribute hook. Use the CALL_ATTRIB_HOOK macros above.
|
||||
virtual float ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ) OVERRIDE;
|
||||
virtual string_t ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ) OVERRIDE;
|
||||
|
||||
CEconItemView *GetItem( void ) { return &m_Item; }
|
||||
const CEconItemView *GetItem( void ) const { return &m_Item; }
|
||||
void SetItem( const CEconItemView *pItem ) { m_Item.CopyFrom( *pItem ); }
|
||||
|
||||
virtual void OnAttributeValuesChanged()
|
||||
{
|
||||
BaseClass::OnAttributeValuesChanged();
|
||||
|
||||
m_Item.OnAttributeValuesChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
CNetworkVarEmbedded( CEconItemView, m_Item );
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: An attribute manager that uses a player's shared attributes.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef DOTA_DLL
|
||||
class CAttributeContainerPlayer : public CAttributeManager
|
||||
{
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_CLASS( CAttributeContainerPlayer, CAttributeManager );
|
||||
DECLARE_EMBEDDED_NETWORKVAR();
|
||||
|
||||
virtual float ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ) OVERRIDE;
|
||||
virtual string_t ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ) OVERRIDE;
|
||||
|
||||
CBasePlayer* GetPlayer( void ) { return m_hPlayer; }
|
||||
void SetPlayer( CBasePlayer *pPlayer ) { m_hPlayer = pPlayer; }
|
||||
|
||||
virtual void OnAttributeValuesChanged()
|
||||
{
|
||||
BaseClass::OnAttributeValuesChanged();
|
||||
|
||||
m_hPlayer->NetworkStateChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
CNetworkHandle( CBasePlayer, m_hPlayer );
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
EXTERN_RECV_TABLE( DT_AttributeManager );
|
||||
EXTERN_RECV_TABLE( DT_AttributeContainer );
|
||||
#else
|
||||
EXTERN_SEND_TABLE( DT_AttributeManager );
|
||||
EXTERN_SEND_TABLE( DT_AttributeContainer );
|
||||
#endif
|
||||
|
||||
#endif // ATTRIBUTE_MANAGER_H
|
||||
@@ -0,0 +1,126 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Code for the CEconClaimCode object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "econ_item_tools.h"
|
||||
#include "econ_claimcode.h"
|
||||
|
||||
using namespace GCSDK;
|
||||
|
||||
#ifdef GC
|
||||
IMPLEMENT_CLASS_MEMPOOL( CEconClaimCode, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
bool CEconClaimCode::BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess )
|
||||
{
|
||||
CSchAssignedClaimCode schCode;
|
||||
WriteToRecord( &schCode );
|
||||
return CSchemaSharedObjectHelper::BYieldingAddInsertToTransaction( sqlAccess, &schCode );
|
||||
}
|
||||
|
||||
void CEconClaimCode::WriteToRecord( CSchAssignedClaimCode *pClaimCode )
|
||||
{
|
||||
pClaimCode->m_unAccountID = Obj().account_id();
|
||||
pClaimCode->m_unCodeType = Obj().code_type();
|
||||
pClaimCode->m_rtime32TimeAcquired = Obj().time_acquired();
|
||||
WRITE_VAR_CHAR_FIELD( *pClaimCode, VarCharCode, Obj().code().c_str() );
|
||||
}
|
||||
|
||||
void CEconClaimCode::ReadFromRecord( const CSchAssignedClaimCode & code )
|
||||
{
|
||||
const char *pchCode = READ_VAR_CHAR_FIELD( code, m_VarCharCode );
|
||||
Obj().set_code_type( code.m_unCodeType );
|
||||
Obj().set_time_acquired( code.m_rtime32TimeAcquired );
|
||||
Obj().set_code( pchCode );
|
||||
}
|
||||
|
||||
|
||||
bool BBuildRedemptionURL( CEconClaimCode *pClaimCode, CUtlString &redemptionURL )
|
||||
{
|
||||
const CEconItemDefinition *pItemDef = GEconManager()->GetItemSchema()->GetItemDefinition( pClaimCode->Obj().code_type() );
|
||||
if ( pItemDef )
|
||||
{
|
||||
const char *pOriginalURL = pItemDef->GetDefinitionString( "redeem_url" );
|
||||
const char *code = pClaimCode->Obj().code().c_str();
|
||||
char url[1024];
|
||||
if ( Q_StrSubst( pOriginalURL, "CLAIMCODE", code, url, sizeof( url ) ) )
|
||||
{
|
||||
redemptionURL = url;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Purpose: Gets a summary of what's going on with the GC
|
||||
// -----------------------------------------------------------------------------
|
||||
class CJobWG_GetPromoCodes : public CGCGameBaseWGJob
|
||||
{
|
||||
public:
|
||||
CJobWG_GetPromoCodes( CGCGameBase *pGC ) : CGCGameBaseWGJob( pGC ) {}
|
||||
|
||||
virtual bool BYieldingRunJobFromRequest( KeyValues *pkvRequest, KeyValues *pkvResponse );
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
bool CJobWG_GetPromoCodes::BYieldingRunJobFromRequest( KeyValues *pkvRequest, KeyValues *pkvResponse )
|
||||
{
|
||||
CSteamID actorID( pkvRequest->GetUint64( "token/steamid" ) );
|
||||
|
||||
KeyValues *pkvPromoCodes = pkvResponse->FindKey( "promo_codes", true );
|
||||
|
||||
CSharedObjectCache *pSOCache = m_pGCGameBase->YieldingFindOrLoadSOCache( actorID );
|
||||
if ( pSOCache == NULL )
|
||||
return true;
|
||||
|
||||
CSharedObjectTypeCache *pTypeCache = pSOCache->FindBaseTypeCache( k_EEconTypeClaimCode );
|
||||
if ( pTypeCache == NULL )
|
||||
return true;
|
||||
|
||||
for ( uint32 i = 0; i < pTypeCache->GetCount(); ++i )
|
||||
{
|
||||
CEconClaimCode *pClaimCode = (CEconClaimCode*)pTypeCache->GetObject( i );
|
||||
const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( pClaimCode->Obj().code_type() );
|
||||
if ( pItemDef == NULL )
|
||||
continue;
|
||||
|
||||
const CEconTool_ClaimCode *pEconClaimCodeTool = pItemDef->GetTypedEconTool<CEconTool_ClaimCode>();
|
||||
if ( pEconClaimCodeTool == NULL )
|
||||
continue;
|
||||
|
||||
const char *pClaimCodeName = pEconClaimCodeTool->GetClaimType();
|
||||
if ( pClaimCodeName == NULL )
|
||||
continue;
|
||||
|
||||
CUtlString claimURL;
|
||||
if ( BBuildRedemptionURL( pClaimCode, claimURL ) == false )
|
||||
{
|
||||
SetErrorMessage( pkvResponse, CFmtStr( "Unable to construct redemption url for: %s", pClaimCodeName ), k_EResultFail );
|
||||
continue;
|
||||
}
|
||||
const char *code = pClaimCode->Obj().code().c_str();
|
||||
// finally populate the key values
|
||||
KeyValues *pkvPromoCode = pkvPromoCodes->CreateNewKey();
|
||||
pkvPromoCode->SetString( "code_name", pClaimCodeName );
|
||||
pkvPromoCode->SetInt( "timestamp", pClaimCode->Obj().time_acquired() );
|
||||
pkvPromoCode->SetString( "code", code );
|
||||
pkvPromoCode->SetString( "redeem_url", claimURL.Get() );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DECLARE_GCWG_JOB( CGCEcon, CJobWG_GetPromoCodes, "GetPromoCodes", k_EGCWebApiPriv_Session )
|
||||
END_DECLARE_GCWG_JOB( CJobWG_GetPromoCodes);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds the CEconClaimCode object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ECON_CLAIMCODE_H
|
||||
#define ECON_CLAIMCODE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "gcsdk/protobufsharedobject.h"
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: All the account-level information that the GC tracks for TF
|
||||
//---------------------------------------------------------------------------------
|
||||
class CEconClaimCode : public GCSDK::CProtoBufSharedObject< CSOEconClaimCode, k_EEconTypeClaimCode >
|
||||
{
|
||||
#ifdef GC
|
||||
DECLARE_CLASS_MEMPOOL( CEconClaimCode );
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
#ifdef GC
|
||||
virtual bool BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess );
|
||||
|
||||
void WriteToRecord( CSchAssignedClaimCode *pClaimCode );
|
||||
void ReadFromRecord( const CSchAssignedClaimCode & mapContribution );
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef GC
|
||||
bool BBuildRedemptionURL( CEconClaimCode *pClaimCode, CUtlString &redemptionURL );
|
||||
#endif
|
||||
|
||||
#endif // ECON_CLAIMCODE_H
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Code for the CTFMapContribution object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "econ_contribution.h"
|
||||
|
||||
using namespace GCSDK;
|
||||
|
||||
#ifdef GC
|
||||
IMPLEMENT_CLASS_MEMPOOL( CTFMapContribution, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
bool CTFMapContribution::BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess )
|
||||
{
|
||||
CSchMapContribution schMapContribution;
|
||||
WriteToRecord( &schMapContribution );
|
||||
return CSchemaSharedObjectHelper::BYieldingAddInsertToTransaction( sqlAccess, &schMapContribution );
|
||||
}
|
||||
|
||||
bool CTFMapContribution::BYieldingAddWriteToTransaction( GCSDK::CSQLAccess & sqlAccess, const CUtlVector< int > &fields )
|
||||
{
|
||||
CSchMapContribution schMapContribution;
|
||||
WriteToRecord( &schMapContribution );
|
||||
CColumnSet csDatabaseDirty( schMapContribution.GetPSchema()->GetRecordInfo() );
|
||||
csDatabaseDirty.MakeEmpty();
|
||||
if ( fields.HasElement( CSOTFMapContribution::kContributionLevelFieldNumber ) )
|
||||
{
|
||||
csDatabaseDirty.BAddColumn( CSchMapContribution::k_iField_unContributionLevel );
|
||||
}
|
||||
return CSchemaSharedObjectHelper::BYieldingAddWriteToTransaction( sqlAccess, &schMapContribution, csDatabaseDirty );
|
||||
}
|
||||
|
||||
bool CTFMapContribution::BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess & sqlAccess )
|
||||
{
|
||||
CSchMapContribution schMapContribution;
|
||||
WriteToRecord( &schMapContribution );
|
||||
return CSchemaSharedObjectHelper::BYieldingAddRemoveToTransaction( sqlAccess, &schMapContribution );
|
||||
}
|
||||
|
||||
void CTFMapContribution::WriteToRecord( CSchMapContribution *pMapContribution ) const
|
||||
{
|
||||
pMapContribution->m_unAccountID = Obj().account_id();
|
||||
pMapContribution->m_unDefIndex = Obj().def_index();
|
||||
pMapContribution->m_unContributionLevel = Obj().contribution_level();
|
||||
}
|
||||
|
||||
|
||||
void CTFMapContribution::ReadFromRecord( const CSchMapContribution & mapContribution )
|
||||
{
|
||||
Obj().set_account_id( mapContribution.m_unAccountID );
|
||||
Obj().set_def_index( mapContribution.m_unDefIndex );
|
||||
Obj().set_contribution_level( mapContribution.m_unContributionLevel );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds the CTFMapContribution object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TFMAPCONTRIBUTION_H
|
||||
#define TFMAPCONTRIBUTION_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "gcsdk/protobufsharedobject.h"
|
||||
#include "tf_gcmessages.h"
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
class CSQLAccess;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: All the account-level information that the GC tracks for TF
|
||||
//---------------------------------------------------------------------------------
|
||||
class CTFMapContribution : public GCSDK::CProtoBufSharedObject< CSOTFMapContribution, k_EEconTypeMapContribution >
|
||||
{
|
||||
#ifdef GC
|
||||
DECLARE_CLASS_MEMPOOL( CTFMapContribution );
|
||||
#endif
|
||||
|
||||
public:
|
||||
CTFMapContribution() {}
|
||||
|
||||
#ifdef GC
|
||||
virtual bool BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess );
|
||||
virtual bool BYieldingAddWriteToTransaction( GCSDK::CSQLAccess & sqlAccess, const CUtlVector< int > &fields );
|
||||
virtual bool BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess & sqlAccess );
|
||||
|
||||
void WriteToRecord( CSchMapContribution *pMapContribution ) const;
|
||||
void ReadFromRecord( const CSchMapContribution & mapContribution );
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // TFMAPCONTRIBUTION_H
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Functions related to dynamic recipes
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#include "cbase.h"
|
||||
#include "econ_dynamic_recipe.h"
|
||||
#ifndef GC_DLL
|
||||
#include "quest_objective_manager.h"
|
||||
#endif
|
||||
|
||||
// This pattern was chosen to not be:
|
||||
// - a valid string acceptable for user-input (ie., custom name)
|
||||
// - a sensical float bit pattern
|
||||
// - a common int bit pattern
|
||||
// - meaningful Unicode data
|
||||
const char *g_pszAttrEncodeSeparator = "|\x01\x02\x01\x03|\x01\x02\x01\x03|";
|
||||
|
||||
CRecipeComponentMatchingIterator::CRecipeComponentMatchingIterator( const IEconItemInterface *pSourceItem,
|
||||
const IEconItemInterface *pTargetItem )
|
||||
: m_pSourceItem( pSourceItem )
|
||||
, m_pTargetItem( pTargetItem )
|
||||
, m_bIgnoreCompleted( true )
|
||||
, m_nInputsTotal( 0 )
|
||||
, m_nInputsFulfilled( 0 )
|
||||
, m_nOutputsTotal( 0 )
|
||||
{}
|
||||
|
||||
bool CRecipeComponentMatchingIterator::OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& value )
|
||||
{
|
||||
// Don't count ourselves as a match!
|
||||
if ( m_pSourceItem && m_pTargetItem && m_pSourceItem->GetID() == m_pTargetItem->GetID() )
|
||||
return true;
|
||||
|
||||
// If this isn't a match and the item isn't NULL, we skip. We consider NULL to mean
|
||||
// that we want to tally ALL attributes of this type
|
||||
if ( !DefinedItemAttribMatch( value, m_pTargetItem ) && m_pTargetItem != NULL )
|
||||
return true;
|
||||
|
||||
// Dont let non-craftable items through
|
||||
if ( m_pTargetItem && !m_pTargetItem->IsUsableInCrafting() )
|
||||
return true;
|
||||
|
||||
// Is this an output?
|
||||
if ( value.component_flags() & DYNAMIC_RECIPE_FLAG_IS_OUTPUT )
|
||||
{
|
||||
m_vecMatchingOutputs.AddToTail( pAttrDef );
|
||||
m_nOutputsTotal += value.num_required();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vecMatchingInputs.AddToTail( pAttrDef );
|
||||
m_nInputsTotal += value.num_required();
|
||||
m_nInputsFulfilled += value.num_fulfilled();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool DefinedItemAttribMatch( const CAttribute_DynamicRecipeComponent& attribValue, const IEconItemInterface* pItem )
|
||||
{
|
||||
if ( !pItem )
|
||||
return false;
|
||||
|
||||
// If our fulfilled count is what our item count is, then we're done. We dont want any more matches.
|
||||
if ( attribValue.num_fulfilled() == attribValue.num_required() )
|
||||
return false;
|
||||
|
||||
// If the item_def flag is set, and the item's item_def doesnt match then not a match
|
||||
if ( ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ITEM_DEF_SET ) &&
|
||||
( attribValue.def_index() != (uint32)pItem->GetItemDefIndex() ) )
|
||||
return false;
|
||||
|
||||
// If the quality flag is set, and the item's quality doesn't match, then not a match
|
||||
if ( ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_QUALITY_SET ) &&
|
||||
( attribValue.item_quality() != (uint32)pItem->GetQuality() ) )
|
||||
return false;
|
||||
|
||||
// check if we have ALL required attributes
|
||||
if ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ATTRIBUTE_SET_ALL )
|
||||
{
|
||||
CUtlVector<CEconItem::attribute_t> vecAttribs;
|
||||
if( !DecodeAttributeStringIntoAttributes( attribValue, vecAttribs ) )
|
||||
{
|
||||
AssertMsg2( 0, "%s: Unable to decode dynamic recipe attributes on item %llu", __FUNCTION__, pItem->GetID() );
|
||||
return false;
|
||||
}
|
||||
|
||||
FOR_EACH_VEC( vecAttribs, i )
|
||||
{
|
||||
const CEconItemAttributeDefinition *pAttr = GetItemSchema()->GetAttributeDefinition( vecAttribs[i].m_unDefinitionIndex );
|
||||
Assert( pAttr );
|
||||
uint32 itemAttributeValue;
|
||||
if ( !pAttr || !pItem->FindAttribute( pAttr, &itemAttributeValue ) || itemAttributeValue != vecAttribs[i].m_value.asUint32 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if we have ANY required attributes
|
||||
else if ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ATTRIBUTE_SET_ANY )
|
||||
{
|
||||
CUtlVector<CEconItem::attribute_t> vecAttribs;
|
||||
if( !DecodeAttributeStringIntoAttributes( attribValue, vecAttribs ) )
|
||||
{
|
||||
AssertMsg2( 0, "%s: Unable to decode dynamic recipe attributes on item %llu", __FUNCTION__, pItem->GetID() );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bHasAnyMatchingAttributes = false;
|
||||
FOR_EACH_VEC( vecAttribs, i )
|
||||
{
|
||||
const CEconItemAttributeDefinition *pAttr = GetItemSchema()->GetAttributeDefinition( vecAttribs[i].m_unDefinitionIndex );
|
||||
Assert( pAttr );
|
||||
uint32 itemAttributeValue;
|
||||
if ( pAttr && pItem->FindAttribute( pAttr, &itemAttributeValue ) && itemAttributeValue == vecAttribs[i].m_value.asUint32 )
|
||||
{
|
||||
bHasAnyMatchingAttributes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !bHasAnyMatchingAttributes )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeAttributeStringIntoAttributes( const CAttribute_DynamicRecipeComponent& attribValue, CUtlVector<CEconItem::attribute_t>& vecAttribs )
|
||||
{
|
||||
CUtlStringList vecAttributeStrings; // Automatically free'd
|
||||
V_SplitString( attribValue.attributes_string().c_str(), g_pszAttrEncodeSeparator, vecAttributeStrings );
|
||||
|
||||
if( vecAttributeStrings.Count() % 2 != 0 )
|
||||
{
|
||||
AssertMsg1( 0, "%s: Uneven count of encoded attribute strings!", __FUNCTION__ );
|
||||
return false;
|
||||
}
|
||||
|
||||
for( int j = 0; j< vecAttributeStrings.Count(); j+=2 )
|
||||
{
|
||||
// Get the attribute definition that's stored in the string, and its type
|
||||
attrib_definition_index_t index = Q_atoi( vecAttributeStrings[j] );
|
||||
const CEconItemAttributeDefinition *pAttrDef = GEconItemSchema().GetAttributeDefinition( index );
|
||||
if ( !pAttrDef )
|
||||
{
|
||||
#ifdef GC
|
||||
EmitError( SPEW_GC, __FUNCTION__ ": Unable to find attribute definition '%s' (index %d)!\n", vecAttributeStrings[j], j );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
CEconItem::attribute_t& attrib = vecAttribs[vecAttribs.AddToTail()];
|
||||
attrib.m_unDefinitionIndex = pAttrDef->GetDefinitionIndex();
|
||||
|
||||
// Now have the attribute read in the value stored in the string
|
||||
const ISchemaAttributeType* pAttrType = pAttrDef->GetAttributeType();
|
||||
pAttrType->InitializeNewEconAttributeValue( &attrib.m_value );
|
||||
|
||||
// Don't fail us now!
|
||||
const char* pszAttribValue = vecAttributeStrings[j+1];
|
||||
if ( !pAttrType->BConvertStringToEconAttributeValue( pAttrDef, pszAttribValue, &attrib.m_value ) )
|
||||
{
|
||||
#ifdef GC
|
||||
EmitError( SPEW_GC, __FUNCTION__ ": Unable to parse attribute value '%s' for attribute '%s'!\n", pszAttribValue, pAttrDef->GetDefinitionName() );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeItemFromEncodedAttributeString( const CAttribute_DynamicRecipeComponent& attribValue, CEconItem* pItem )
|
||||
{
|
||||
// If the item_def flag is set, set that item def
|
||||
if ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ITEM_DEF_SET )
|
||||
{
|
||||
pItem->SetDefinitionIndex( attribValue.def_index() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the flag is not set, then we want the item name to be generic. In english, we want to just call it "item".
|
||||
CAttribute_String attrStr;
|
||||
attrStr.set_value( "#TF_ItemName_Item" );
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_ItemNameTextOverride( "item name text override" );
|
||||
pItem->SetDynamicAttributeValue( pAttrDef_ItemNameTextOverride, attrStr );
|
||||
}
|
||||
|
||||
// If the quality flag is set, take the quality
|
||||
if ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_QUALITY_SET )
|
||||
{
|
||||
pItem->SetQuality( attribValue.item_quality() );
|
||||
|
||||
// If there's no item def set and the quality specified is "unique", we want to be explicit
|
||||
// and have the item description actually say "unique item" so there's no confusion as to what
|
||||
// item quality we want as an input.
|
||||
if ( !( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ITEM_DEF_SET )
|
||||
&& pItem->GetQuality() == AE_UNIQUE )
|
||||
{
|
||||
CAttribute_String attrStr;
|
||||
attrStr.set_value( "#unique" );
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_QualityTextOverride( "quality text override" );
|
||||
pItem->SetDynamicAttributeValue( pAttrDef_QualityTextOverride, attrStr );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no quality was specified, we want to explicity say that we'll accept ANY quality.
|
||||
pItem->SetQuality( AE_UNIQUE );
|
||||
CAttribute_String attrStr;
|
||||
attrStr.set_value( "#TF_QualityText_Any" );
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_QualityTextOverride( "quality text override" );
|
||||
pItem->SetDynamicAttributeValue( pAttrDef_QualityTextOverride, attrStr );
|
||||
}
|
||||
pItem->SetFlags( 0 );
|
||||
|
||||
// Get all the attributes encoded into the attribute
|
||||
CUtlVector<CEconItem::attribute_t> vecAttribs;
|
||||
if( !DecodeAttributeStringIntoAttributes( attribValue, vecAttribs ) )
|
||||
{
|
||||
AssertMsg1( 0, " %s : Unable to decode dynamic recipe attributes", __FUNCTION__ );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apply the attributes to the item
|
||||
FOR_EACH_VEC( vecAttribs, j )
|
||||
{
|
||||
// We don't expect to get here with any missing attributes.
|
||||
const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( vecAttribs[j].m_unDefinitionIndex );
|
||||
Assert( pAttrDef );
|
||||
|
||||
const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
|
||||
pAttrType->LoadEconAttributeValue( pItem, pAttrDef, vecAttribs[j].m_value );
|
||||
|
||||
// Free up our attribute memory now that we're done with it.
|
||||
pAttrType->UnloadEconAttributeValue( &vecAttribs[j].m_value );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Functions related to dynamic recipes
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECON_DYNAMIC_RECIPE
|
||||
#define ECON_DYNAMIC_RECIPE
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tf_gcmessages.h"
|
||||
#include "game_item_schema.h"
|
||||
#include "econ_item.h"
|
||||
|
||||
extern const char *g_pszAttrEncodeSeparator;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Stores off all CAttribute_DynamicRecipeComponent attributes
|
||||
// that consider m_pTargetItem to be a match. If NULL is passed in for pTargetItem
|
||||
// then we consider all attributes to be a match
|
||||
//-----------------------------------------------------------------------------
|
||||
class CRecipeComponentMatchingIterator : public CEconItemSpecificAttributeIterator
|
||||
{
|
||||
public:
|
||||
CRecipeComponentMatchingIterator( const IEconItemInterface *pSourceItem,
|
||||
const IEconItemInterface *pTargetItem );
|
||||
|
||||
void SetSourceItem( const IEconItemInterface *m_pSourceItem );
|
||||
void SetTargetItem( const IEconItemInterface *pTargetItem );
|
||||
void SetIgnoreCompleted( bool bIgnoreCompleted ) { m_bIgnoreCompleted = bIgnoreCompleted; }
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef,
|
||||
const CAttribute_DynamicRecipeComponent& value ) OVERRIDE;
|
||||
|
||||
const CUtlVector< const CEconItemAttributeDefinition* >& GetMatchingComponentInputs() const { return m_vecMatchingInputs; }
|
||||
const CUtlVector< const CEconItemAttributeDefinition* >& GetMatchingComponentOutputs() const { return m_vecMatchingOutputs; }
|
||||
|
||||
int GetTotalInputs() const { return m_nInputsTotal; }
|
||||
int GetInputsFulfilled() const { return m_nInputsFulfilled; }
|
||||
int GetTotalOutputs() const { return m_nOutputsTotal; }
|
||||
private:
|
||||
|
||||
const IEconItemInterface *m_pSourceItem;
|
||||
const IEconItemInterface *m_pTargetItem;
|
||||
bool m_bIgnoreCompleted;
|
||||
|
||||
CUtlVector< const CEconItemAttributeDefinition* > m_vecMatchingInputs;
|
||||
CUtlVector< const CEconItemAttributeDefinition* > m_vecMatchingOutputs;
|
||||
|
||||
int m_nInputsTotal;
|
||||
int m_nInputsFulfilled;
|
||||
int m_nOutputsTotal;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Given a CAttribute_DynamicRecipeComponent and a IEconItemInterface,
|
||||
// returns whether the item pass the criteria of the attribute
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DefinedItemAttribMatch( const CAttribute_DynamicRecipeComponent& attribValue, const IEconItemInterface* pItem );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Decodes the encoded attributes in attribValue and applies those attributes to pItem
|
||||
// Returns true on success, false if anything fails
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DecodeAttributeStringIntoAttributes( const CAttribute_DynamicRecipeComponent& attribValue, CUtlVector<CEconItem::attribute_t>& vecAttribs);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Decodes the encoded attributes in attribValue forms pItem into the
|
||||
// item that it describes
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DecodeItemFromEncodedAttributeString( const CAttribute_DynamicRecipeComponent& attribValue, CEconItem* pItem );
|
||||
|
||||
#endif //ECON_DYNAMIC_RECIPE
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,229 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECON_ENTITY_H
|
||||
#define ECON_ENTITY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ihasattributes.h"
|
||||
#include "ihasowner.h"
|
||||
#include "attribute_manager.h"
|
||||
#include "econ_item_view.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CEconEntity C_EconEntity
|
||||
#define CBaseAttributableItem C_BaseAttributableItem
|
||||
|
||||
// Additional attachments.
|
||||
struct AttachedModelData_t
|
||||
{
|
||||
const model_t *m_pModel;
|
||||
int m_iModelDisplayFlags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconEntity : public CBaseAnimating, public IHasAttributes
|
||||
{
|
||||
DECLARE_CLASS( CEconEntity, CBaseAnimating );
|
||||
public:
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_DATADESC();
|
||||
CEconEntity();
|
||||
~CEconEntity();
|
||||
|
||||
void InitializeAttributes( void );
|
||||
void DebugDescribe( void );
|
||||
Activity TranslateViewmodelHandActivity( Activity actBase );
|
||||
virtual void UpdateOnRemove( void );
|
||||
|
||||
virtual CStudioHdr * OnNewModel();
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
virtual void GiveTo( CBaseEntity *pOther ) {}
|
||||
void OnOwnerClassChange( void );
|
||||
void UpdateModelToClass( void );
|
||||
void PlayAnimForPlaybackEvent( wearableanimplayback_t iPlayback );
|
||||
virtual int CalculateVisibleClassFor( CBaseCombatCharacter *pPlayer );
|
||||
|
||||
#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
|
||||
void MarkAttachedEntityAsValidated() { m_bValidatedAttachedEntity = true; }
|
||||
#endif // TF_DLL || TF_CLIENT_DLL
|
||||
|
||||
#else
|
||||
enum ParticleSystemState_t
|
||||
{
|
||||
PARTICLE_SYSTEM_STATE_NOT_VISIBLE,
|
||||
PARTICLE_SYSTEM_STATE_VISIBLE,
|
||||
PARTICLE_SYSTEM_STATE_VISIBLE_VM
|
||||
};
|
||||
|
||||
virtual void Release();
|
||||
virtual void SetDormant( bool bDormant );
|
||||
virtual void OnPreDataChanged( DataUpdateType_t type );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual bool ShouldShowToolTip( void ) { return true; }
|
||||
virtual bool InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup );
|
||||
virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo );
|
||||
virtual IMaterial *GetEconWeaponMaterialOverride( int iTeam ) OVERRIDE;
|
||||
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
bool InternalFireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
|
||||
// Custom flex controllers
|
||||
virtual bool UsesFlexDelayedWeights( void );
|
||||
virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
|
||||
float m_flFlexDelayTime;
|
||||
float * m_flFlexDelayedWeight;
|
||||
int m_cFlexDelayedWeight;
|
||||
|
||||
// Custom particle attachments
|
||||
bool HasCustomParticleSystems( void ) const;
|
||||
void UpdateParticleSystems( void );
|
||||
virtual bool ShouldDrawParticleSystems( void );
|
||||
void SetParticleSystemsVisible( ParticleSystemState_t bVisible );
|
||||
void UpdateSingleParticleSystem( bool bVisible, const attachedparticlesystem_t *pSystem );
|
||||
virtual void UpdateAttachmentModels( void );
|
||||
virtual bool AttachmentModelsShouldBeVisible( void ) { return true; }
|
||||
void GetEconParticleSystems( CUtlVector<const attachedparticlesystem_t *> *out_pvecParticleSystems ) const;
|
||||
|
||||
// Model swaping
|
||||
bool ShouldDraw( void );
|
||||
bool ShouldHideForVisionFilterFlags( void );
|
||||
|
||||
virtual bool IsTransparent( void ) OVERRIDE;
|
||||
|
||||
// Viewmodel overriding
|
||||
virtual bool ViewModel_IsTransparent( void );
|
||||
virtual bool ViewModel_IsUsingFBTexture( void );
|
||||
virtual bool IsOverridingViewmodel( void );
|
||||
virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags );
|
||||
|
||||
// Attachments
|
||||
bool WantsToOverrideViewmodelAttachments( void ) { return (m_hViewmodelAttachment != NULL); }
|
||||
virtual int LookupAttachment( const char *pAttachmentName );
|
||||
virtual bool GetAttachment( const char *szName, Vector &absOrigin ) { return BaseClass::GetAttachment(szName,absOrigin); }
|
||||
virtual bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles ) { return BaseClass::GetAttachment(szName,absOrigin,absAngles); }
|
||||
virtual bool GetAttachment( int number, matrix3x4_t &matrix );
|
||||
virtual bool GetAttachment( int number, Vector &origin );
|
||||
virtual bool GetAttachment( int number, Vector &origin, QAngle &angles );
|
||||
virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel );
|
||||
|
||||
C_BaseAnimating *GetViewmodelAttachment( void ) { return m_hViewmodelAttachment.Get(); }
|
||||
virtual void ViewModelAttachmentBlending( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ) {}
|
||||
|
||||
void SetWaitingToLoad( bool bWaiting );
|
||||
|
||||
virtual bool ValidateEntityAttachedToPlayer( bool &bShouldRetry );
|
||||
|
||||
virtual void SetMaterialOverride( int team, const char *pszMaterial );
|
||||
virtual void SetMaterialOverride( int team, CMaterialReference &ref );
|
||||
|
||||
// Deal with recording
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
// IHasAttributes
|
||||
CAttributeManager *GetAttributeManager( void ) { return &m_AttributeManager; }
|
||||
CAttributeContainer *GetAttributeContainer( void ) { return &m_AttributeManager; }
|
||||
const CAttributeContainer *GetAttributeContainer( void ) const { return &m_AttributeManager; }
|
||||
CBaseEntity *GetAttributeOwner( void ) { return GetOwnerEntity(); }
|
||||
CAttributeList *GetAttributeList( void ) { return m_AttributeManager.GetItem()->GetAttributeList(); }
|
||||
virtual void ReapplyProvision( void );
|
||||
|
||||
virtual bool UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState );
|
||||
|
||||
protected:
|
||||
virtual Activity TranslateViewmodelHandActivityInternal( Activity actBase ) { return actBase; }
|
||||
|
||||
protected:
|
||||
CNetworkVarEmbedded( CAttributeContainer, m_AttributeManager );
|
||||
|
||||
#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
|
||||
CNetworkVar( bool, m_bValidatedAttachedEntity );
|
||||
#endif // TF_DLL || TF_CLIENT_DLL
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
bool m_bClientside;
|
||||
ParticleSystemState_t m_nParticleSystemsCreated;
|
||||
CMaterialReference m_MaterialOverrides[TEAM_VISUAL_SECTIONS];
|
||||
CHandle<C_BaseAnimating> m_hViewmodelAttachment;
|
||||
int m_iOldTeam;
|
||||
bool m_bAttachmentDirty;
|
||||
int m_nUnloadedModelIndex;
|
||||
int m_iNumOwnerValidationRetries;
|
||||
#endif
|
||||
|
||||
bool m_bHasParticleSystems;
|
||||
EHANDLE m_hOldProvidee;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
int m_iOldOwnerClass; // Used to detect class changes on items that have per-class models
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
public:
|
||||
|
||||
CUtlVector<AttachedModelData_t> m_vecAttachedModels;
|
||||
|
||||
#endif // CLIENT_DLL
|
||||
};
|
||||
|
||||
#define ITEM_PICKUP_BOX_BLOAT 24
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CBaseAttributableItem : public CEconEntity
|
||||
{
|
||||
DECLARE_CLASS( CBaseAttributableItem, CEconEntity );
|
||||
public:
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CBaseAttributableItem();
|
||||
};
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#ifndef DOTA_DLL
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_ViewmodelAttachmentModel : public C_BaseAnimating, public IHasOwner
|
||||
{
|
||||
DECLARE_CLASS( C_ViewmodelAttachmentModel, C_BaseAnimating );
|
||||
public:
|
||||
void SetOuter( CEconEntity *pOuter );
|
||||
CHandle<CEconEntity> GetOuter( void ) { return m_hOuter; }
|
||||
bool InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup );
|
||||
int InternalDrawModel( int flags );
|
||||
bool OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo );
|
||||
virtual void StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask );
|
||||
|
||||
virtual CBaseEntity *GetOwnerViaInterface( void ) { return GetOuter()->GetAttributeOwner(); }
|
||||
|
||||
virtual void FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld );
|
||||
|
||||
virtual int GetSkin( void );
|
||||
|
||||
private:
|
||||
CHandle<CEconEntity> m_hOuter;
|
||||
bool m_bAlwaysFlip;
|
||||
};
|
||||
#endif // !defined( DOTA_DLL )
|
||||
#endif // defined( CLIENT_DLL )
|
||||
|
||||
#endif // ECON_ENTITY_H
|
||||
@@ -0,0 +1,180 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "econ_entity_creation.h"
|
||||
#include "utldict.h"
|
||||
#include "filesystem.h"
|
||||
#include "gamestringpool.h"
|
||||
#include "KeyValues.h"
|
||||
#include "attribute_manager.h"
|
||||
#include "vgui/ILocalize.h"
|
||||
#include "tier3/tier3.h"
|
||||
#include "util_shared.h"
|
||||
|
||||
#ifdef TF_CLIENT_DLL
|
||||
#include "c_tf_player.h"
|
||||
#endif // TF_CLIENT_DLL
|
||||
|
||||
//==================================================================================
|
||||
// GENERATION SYSTEM
|
||||
//==================================================================================
|
||||
CItemGeneration g_ItemGenerationSystem;
|
||||
CItemGeneration *ItemGeneration( void )
|
||||
{
|
||||
return &g_ItemGenerationSystem;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CItemGeneration::CItemGeneration( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generate a random item matching the specified criteria
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CItemGeneration::GenerateRandomItem( CItemSelectionCriteria *pCriteria, const Vector &vecOrigin, const QAngle &vecAngles )
|
||||
{
|
||||
entityquality_t iQuality;
|
||||
int iChosenItem = ItemSystem()->GenerateRandomItem( pCriteria, &iQuality );
|
||||
if ( iChosenItem == INVALID_ITEM_DEF_INDEX )
|
||||
return NULL;
|
||||
|
||||
return SpawnItem( iChosenItem, vecOrigin, vecAngles, pCriteria->GetItemLevel(), iQuality, NULL );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generate a random item matching the specified definition index
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CItemGeneration::GenerateItemFromDefIndex( int iDefIndex, const Vector &vecOrigin, const QAngle &vecAngles )
|
||||
{
|
||||
return SpawnItem( iDefIndex, vecOrigin, vecAngles, 1, AE_UNIQUE, NULL );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generate an item from the specified item data
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CItemGeneration::GenerateItemFromScriptData( const CEconItemView *pData, const Vector &vecOrigin, const QAngle &vecAngles, const char *pszOverrideClassName )
|
||||
{
|
||||
return SpawnItem( pData, vecOrigin, vecAngles, pszOverrideClassName );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generate the base item for a class's loadout slot
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CItemGeneration::GenerateBaseItem( struct baseitemcriteria_t *pCriteria )
|
||||
{
|
||||
int iChosenItem = ItemSystem()->GenerateBaseItem( pCriteria );
|
||||
if ( iChosenItem == INVALID_ITEM_DEF_INDEX )
|
||||
return NULL;
|
||||
|
||||
return SpawnItem( iChosenItem, vec3_origin, vec3_angle, 1, AE_NORMAL, NULL );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create a new instance of the chosen item
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CItemGeneration::SpawnItem( int iChosenItem, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles, int iItemLevel, entityquality_t entityQuality, const char *pszOverrideClassName )
|
||||
{
|
||||
CEconItemDefinition *pData = ItemSystem()->GetStaticDataForItemByDefIndex( iChosenItem );
|
||||
if ( !pData )
|
||||
return NULL;
|
||||
|
||||
if ( !pszOverrideClassName )
|
||||
{
|
||||
pszOverrideClassName = pData->GetItemClass();
|
||||
}
|
||||
|
||||
if ( !pszOverrideClassName )
|
||||
return NULL;
|
||||
|
||||
CBaseEntity *pItem = CreateEntityByName( pszOverrideClassName );
|
||||
if ( !pItem )
|
||||
return NULL;
|
||||
|
||||
// Set the item level & quality
|
||||
IHasAttributes *pItemInterface = GetAttribInterface( pItem );
|
||||
Assert( pItemInterface );
|
||||
if ( pItemInterface )
|
||||
{
|
||||
// Setup the script item. Don't generate attributes here, because it'll be done during entity spawn.
|
||||
CEconItemView *pScriptItem = pItemInterface->GetAttributeContainer()->GetItem();
|
||||
pScriptItem->Init( iChosenItem, entityQuality, iItemLevel, false );
|
||||
}
|
||||
|
||||
return PostSpawnItem( pItem, pItemInterface, vecAbsOrigin, vecAbsAngles );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create a base entity for the specified item data
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CItemGeneration::SpawnItem( const CEconItemView *pData, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles, const char *pszOverrideClassName )
|
||||
{
|
||||
if ( !pData->GetStaticData() )
|
||||
return NULL;
|
||||
|
||||
if ( !pszOverrideClassName )
|
||||
{
|
||||
pszOverrideClassName = pData->GetStaticData()->GetItemClass();
|
||||
}
|
||||
|
||||
if ( !pszOverrideClassName )
|
||||
return NULL;
|
||||
|
||||
CBaseEntity *pItem = CreateEntityByName( pszOverrideClassName );
|
||||
if ( !pItem )
|
||||
return NULL;
|
||||
|
||||
// Set the item level & quality
|
||||
IHasAttributes *pItemInterface = GetAttribInterface( pItem );
|
||||
Assert( pItemInterface );
|
||||
if ( pItemInterface )
|
||||
{
|
||||
pItemInterface->GetAttributeContainer()->SetItem( pData );
|
||||
}
|
||||
|
||||
return PostSpawnItem( pItem, pItemInterface, vecAbsOrigin, vecAbsAngles );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CItemGeneration::PostSpawnItem( CBaseEntity *pItem, IHasAttributes *pItemInterface, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
const char *pszPlayerModel = NULL;
|
||||
if ( pItemInterface )
|
||||
{
|
||||
CEconItemView *pScriptItem = pItemInterface->GetAttributeContainer()->GetItem();
|
||||
|
||||
int iClass = 0;
|
||||
int iTeam = 0;
|
||||
#ifdef TF_CLIENT_DLL
|
||||
C_TFPlayer *pTFPlayer = ToTFPlayer( GetPlayerByAccountID( pScriptItem->GetAccountID() ) );
|
||||
if ( pTFPlayer )
|
||||
{
|
||||
iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
|
||||
iTeam = pTFPlayer->GetTeamNumber();
|
||||
}
|
||||
#endif // TF_CLIENT_DLL
|
||||
pszPlayerModel = pScriptItem->GetPlayerDisplayModel( iClass, iTeam );
|
||||
}
|
||||
|
||||
// If we create a clientside item, we need to force it to initialize attributes
|
||||
if ( pItem->InitializeAsClientEntity( pszPlayerModel, RENDER_GROUP_OPAQUE_ENTITY ) == false )
|
||||
return NULL;
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
pItem->SetAbsOrigin( vecAbsOrigin );
|
||||
pItem->SetAbsAngles( vecAbsAngles );
|
||||
|
||||
pItem->Spawn();
|
||||
pItem->Activate();
|
||||
return pItem;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ITEM_CREATION_H
|
||||
#define ITEM_CREATION_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "igamesystem.h"
|
||||
#include "econ_item_system.h"
|
||||
#include "econ_entity.h"
|
||||
|
||||
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
|
||||
#include "tf_shareddefs.h"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Game system that handles initializing the item system, and generating items as full game entities
|
||||
//-----------------------------------------------------------------------------
|
||||
class CItemGeneration : public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
CItemGeneration( void );
|
||||
|
||||
// Generate a random item matching the specified criteria
|
||||
CBaseEntity *GenerateRandomItem( CItemSelectionCriteria *pCriteria, const Vector &vecOrigin, const QAngle &vecAngles );
|
||||
|
||||
// Generate a random item matching the specified definition index
|
||||
CBaseEntity *GenerateItemFromDefIndex( int iDefIndex, const Vector &vecOrigin, const QAngle &vecAngles );
|
||||
|
||||
// Generate an item from the specified item data
|
||||
CBaseEntity *GenerateItemFromScriptData( const CEconItemView *pData, const Vector &vecOrigin, const QAngle &vecAngles, const char *pszOverrideClassName );
|
||||
|
||||
// Generate the base item for a class's loadout slot
|
||||
CBaseEntity *GenerateBaseItem( struct baseitemcriteria_t *pCriteria );
|
||||
|
||||
private:
|
||||
// Create a new instance of the chosen item
|
||||
CBaseEntity *SpawnItem( int iChosenItem, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles, int iItemLevel, entityquality_t entityQuality, const char *pszOverrideClassName );
|
||||
CBaseEntity *SpawnItem( const CEconItemView *pData, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles, const char *pszOverrideClassName );
|
||||
CBaseEntity *PostSpawnItem( CBaseEntity *pItem, IHasAttributes *pItemInterface, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles );
|
||||
};
|
||||
|
||||
extern CItemGeneration *ItemGeneration( void );
|
||||
|
||||
#endif // ITEM_CREATION_H
|
||||
@@ -0,0 +1,19 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "econ_experiment.h"
|
||||
|
||||
using namespace GCSDK;
|
||||
|
||||
#ifdef GC_DLL
|
||||
IMPLEMENT_CLASS_MEMPOOL( CEconExperiment, 10 * 10000, UTLMEMORYPOOL_GROW_SLOW );
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
@@ -0,0 +1,27 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds the CEconExperiment
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TFEXPERIMENT_H
|
||||
#define TFEXPERIMENT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "gcsdk/schemasharedobject.h"
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//---------------------------------------------------------------------------------
|
||||
class CEconExperiment : public GCSDK::CSchemaSharedObject< CSchExperiment, k_EEconTypeExperiment >
|
||||
{
|
||||
#ifdef GC_DLL
|
||||
DECLARE_CLASS_MEMPOOL( CEconExperiment );
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // TFEXPERIMENT_H
|
||||
@@ -0,0 +1,17 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Code for the CEconGameAccount object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
using namespace GCSDK;
|
||||
|
||||
#ifdef GC_DLL
|
||||
IMPLEMENT_CLASS_MEMPOOL( CEconGameAccount, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
|
||||
#endif
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds the CEconGameAccount object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ECON_GAME_ACCOUNT_H
|
||||
#define ECON_GAME_ACCOUNT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "gcsdk/schemasharedobject.h"
|
||||
#include "rtime.h"
|
||||
|
||||
enum
|
||||
{
|
||||
kGameAccountFlags_ConvertedUniques = 1 << 0,
|
||||
kGameAccountFlags_MadeFirstPurchase = 1 << 1,
|
||||
kGameAccountFlags_ConvertItemFlagsToOrigin = 1 << 2,
|
||||
kGameAccountFlags_ConvertPackageItemGrants = 1 << 3,
|
||||
kGameAccountFlags_RemoveCafeOrSchoolItems = 1 << 4,
|
||||
kGameAccountFlags_CleanupItemNames = 1 << 5,
|
||||
kGameAccountFlags_NeedToChooseMostHelpfulFriend = 1 << 6,
|
||||
kGameAccountFlags_DONT_USE_THIS_BUI_LIES = 1 << 7, // some accounts might have this set! it used to be the "needs to thank a friend" bit
|
||||
kGameAccountFlags_OwnedGameServersDisabled = 1 << 8,
|
||||
kGameAccountFlags_UpdatedEquippedSlots = 1 << 9,
|
||||
kGameAccountFlags_MadeFirstWebPurchase = 1 << 10,
|
||||
kGameAccountFlags_UpdatedPresetOriginalItemIDs = 1 << 11,
|
||||
kGameAccountFlags_GC_UpgradedToPremium = 1 << 12, // we did something (used an item, whatever) on the GC that means the GC has decided we're premium regardless of what Steam says
|
||||
// Deprecated
|
||||
// kGameAccountFlags_InitializedSkillRating = 1 << 13,
|
||||
// kGameAccountFlags_InitializedSkillRating6v6 = 1 << 14,
|
||||
// kGameAccountFlags_InitializedSkillRating9v9 = 1 << 15,
|
||||
kGameAccountFlags_InitializedKickBucket = 1 << 16,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: All the account-level information that the GC tracks
|
||||
//---------------------------------------------------------------------------------
|
||||
class CEconGameAccount : public GCSDK::CSchemaSharedObject< CSchGameAccount, k_EEconTypeGameAccount >
|
||||
{
|
||||
#ifdef GC_DLL
|
||||
DECLARE_CLASS_MEMPOOL( CEconGameAccount );
|
||||
#endif
|
||||
|
||||
public:
|
||||
CEconGameAccount() {}
|
||||
CEconGameAccount( uint32 unAccountID )
|
||||
{
|
||||
Obj().m_unAccountID = unAccountID;
|
||||
Obj().m_rtime32FirstPlayed = CRTime::RTime32TimeCur();
|
||||
}
|
||||
};
|
||||
|
||||
#endif //ECON_GAME_ACCOUNT_H
|
||||
@@ -0,0 +1,18 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Code for the CEconGameAccountClient object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
using namespace GCSDK;
|
||||
|
||||
#ifdef GC
|
||||
IMPLEMENT_CLASS_MEMPOOL( CEconGameAccountClient, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds the CEconGameAccountClient object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ECON_GAME_ACCOUNT_CLIENT_H
|
||||
#define ECON_GAME_ACCOUNT_CLIENT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "gcsdk/protobufsharedobject.h"
|
||||
#include "base_gcmessages.pb.h"
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: All the account-level information that the GC tracks
|
||||
//---------------------------------------------------------------------------------
|
||||
class CEconGameAccountClient : public GCSDK::CProtoBufSharedObject< CSOEconGameAccountClient, k_EEconTypeGameAccountClient >
|
||||
{
|
||||
#ifdef GC
|
||||
DECLARE_CLASS_MEMPOOL( CEconGameAccountClient );
|
||||
public:
|
||||
virtual bool BIsDatabaseBacked() const { return false; }
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif //ECON_GAME_ACCOUNT_CLIENT_H
|
||||
@@ -0,0 +1,40 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Code for the CEconGameAccount object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "econ_game_account_server.h"
|
||||
|
||||
using namespace GCSDK;
|
||||
|
||||
#ifdef GC_DLL
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//---------------------------------------------------------------------------------
|
||||
IMPLEMENT_CLASS_MEMPOOL( CEconGameServerAccount, 100, UTLMEMORYPOOL_GROW_SLOW );
|
||||
|
||||
void GameServerAccount_GenerateIdentityToken( char* pIdentityToken, uint32 unMaxChars )
|
||||
{
|
||||
static const char s_ValidChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./+!$%^-_+?<>()&~:";
|
||||
const int nLastValidIndex = ARRAYSIZE(s_ValidChars) - 2; // last = size - 1, minus another one for null terminator
|
||||
|
||||
// create a randomized token
|
||||
for ( uint32 i = 0; i < unMaxChars - 1; ++i )
|
||||
{
|
||||
pIdentityToken[i] = s_ValidChars[ RandomInt( 0, nLastValidIndex ) ];
|
||||
}
|
||||
pIdentityToken[unMaxChars - 1] = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: Selective account-level data for game servers
|
||||
//---------------------------------------------------------------------------------
|
||||
IMPLEMENT_CLASS_MEMPOOL( CEconGameAccountForGameServers, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
@@ -0,0 +1,110 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds the CEconGameServerAccount object
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ECON_GAME_SERVER_ACCOUNT_H
|
||||
#define ECON_GAME_SERVER_ACCOUNT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
enum eGameServerOrigin
|
||||
{
|
||||
kGSAOrigin_Player = 0,
|
||||
kGSAOrigin_Support = 1,
|
||||
kGSAOrigin_AutoRegister = 2, // for valve-owned servers
|
||||
};
|
||||
|
||||
enum eGameServerScoreStanding
|
||||
{
|
||||
kGSStanding_Good,
|
||||
kGSStanding_Bad,
|
||||
};
|
||||
|
||||
enum eGameServerScoreStandingTrend
|
||||
{
|
||||
kGSStandingTrend_Up,
|
||||
kGSStandingTrend_SteadyUp,
|
||||
kGSStandingTrend_Steady,
|
||||
kGSStandingTrend_SteadyDown,
|
||||
kGSStandingTrend_Down,
|
||||
};
|
||||
|
||||
#ifdef GC
|
||||
#include "gcsdk/schemasharedobject.h"
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//---------------------------------------------------------------------------------
|
||||
class CEconGameServerAccount : public GCSDK::CSchemaSharedObject< CSchGameServerAccount, k_EEconTypeGameServerAccount >
|
||||
{
|
||||
#ifdef GC_DLL
|
||||
DECLARE_CLASS_MEMPOOL( CEconGameServerAccount );
|
||||
#endif
|
||||
|
||||
public:
|
||||
CEconGameServerAccount() {}
|
||||
CEconGameServerAccount( uint32 unAccountID )
|
||||
{
|
||||
Obj().m_unAccountID = unAccountID;
|
||||
}
|
||||
};
|
||||
|
||||
void GameServerAccount_GenerateIdentityToken( char* pIdentityToken, uint32 unMaxChars );
|
||||
#endif // GC
|
||||
|
||||
inline const char *GameServerAccount_GetStandingString( eGameServerScoreStanding standing )
|
||||
{
|
||||
const char *pStanding = "Good";
|
||||
switch ( standing )
|
||||
{
|
||||
case kGSStanding_Good:
|
||||
pStanding = "Good";
|
||||
break;
|
||||
case kGSStanding_Bad:
|
||||
pStanding = "Bad";
|
||||
break;
|
||||
} // switch
|
||||
return pStanding;
|
||||
}
|
||||
|
||||
inline const char *GameServerAccount_GetStandingTrendString( eGameServerScoreStandingTrend trend )
|
||||
{
|
||||
const char *pStandingTrend = "Steady";
|
||||
switch ( trend )
|
||||
{
|
||||
case kGSStandingTrend_Up:
|
||||
pStandingTrend = "Upward Fast";
|
||||
break;
|
||||
case kGSStandingTrend_SteadyUp:
|
||||
pStandingTrend = "Slightly Upward";
|
||||
break;
|
||||
case kGSStandingTrend_Steady:
|
||||
pStandingTrend = "Steady";
|
||||
break;
|
||||
case kGSStandingTrend_SteadyDown:
|
||||
pStandingTrend = "Slightly Downward";
|
||||
break;
|
||||
case kGSStandingTrend_Down:
|
||||
pStandingTrend = "Downward Fast";
|
||||
break;
|
||||
} // switch
|
||||
return pStandingTrend;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: Selective account-level data for game servers
|
||||
//---------------------------------------------------------------------------------
|
||||
class CEconGameAccountForGameServers : public GCSDK::CProtoBufSharedObject < CSOEconGameAccountForGameServers, k_EEconTypeGameAccountForGameServers >
|
||||
{
|
||||
#ifdef GC
|
||||
DECLARE_CLASS_MEMPOOL( CEconGameAccountForGameServers );
|
||||
public:
|
||||
virtual bool BIsDatabaseBacked() const { return false; }
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif //ECON_GAME_SERVER_ACCOUNT_H
|
||||
@@ -0,0 +1,345 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: This file defines all of our over-the-wire net protocols for the
|
||||
// Game Coordinator for the item system. Note that we never use types
|
||||
// with undefined length (like int). Always use an explicit type
|
||||
// (like int32).
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ITEM_GCMESSAGES_H
|
||||
#define ITEM_GCMESSAGES_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "econ_gcmessages.pb.h"
|
||||
|
||||
#pragma pack( push, 1 )
|
||||
|
||||
|
||||
// generic zero-length message struct
|
||||
struct MsgGCEmpty_t
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// k_EMsgGCSetItemPosition
|
||||
struct MsgGCSetItemPosition_t
|
||||
{
|
||||
uint64 m_unItemID;
|
||||
uint32 m_unNewPosition;
|
||||
};
|
||||
|
||||
// k_EMsgGCCraft
|
||||
struct MsgGCCraft_t
|
||||
{
|
||||
int16 m_nRecipeDefIndex;
|
||||
uint16 m_nItemCount;
|
||||
// list of m_nItemCount uint64 item IDs
|
||||
};
|
||||
|
||||
// k_EMsgGCDelete
|
||||
struct MsgGCDelete_t
|
||||
{
|
||||
uint64 m_unItemID;
|
||||
};
|
||||
|
||||
// k_EMsgGCCraftResponse
|
||||
struct MsgGCStandardResponse_t
|
||||
{
|
||||
int16 m_nResponseIndex;
|
||||
uint32 m_eResponse;
|
||||
};
|
||||
|
||||
// k_EMsgGCVerifyCacheSubscription
|
||||
struct MsgGCVerifyCacheSubscription_t
|
||||
{
|
||||
uint64 m_ulSteamID;
|
||||
};
|
||||
|
||||
// k_EMsgGCNameItem
|
||||
struct MsgGCNameItem_t
|
||||
{
|
||||
uint64 m_unToolItemID; // the Nametag item
|
||||
uint64 m_unSubjectItemID; // the item to be renamed
|
||||
bool m_bDescription;
|
||||
// Varchar: Item name
|
||||
};
|
||||
|
||||
// k_EMsgGCNameBaseItem
|
||||
struct MsgGCNameBaseItem_t
|
||||
{
|
||||
uint64 m_unToolItemID; // the Nametag item
|
||||
uint32 m_unBaseItemDefinitionID; // the base item definition to be renamed
|
||||
bool m_bDescription;
|
||||
// Varchar: Item name
|
||||
};
|
||||
|
||||
// k_EMsgGCUnlockCrate
|
||||
struct MsgGCUnlockCrate_t
|
||||
{
|
||||
uint64 m_unToolItemID; // the crate key
|
||||
uint64 m_unSubjectItemID; // the crate to be decoded
|
||||
};
|
||||
|
||||
// k_EMsgGCPaintItem
|
||||
struct MsgGCPaintItem_t
|
||||
{
|
||||
uint64 m_unToolItemID; // the Paint Can item
|
||||
uint64 m_unSubjectItemID; // the item to be painted
|
||||
};
|
||||
|
||||
// k_EMsgGCGiftWrapItem
|
||||
struct MsgGCGiftWrapItem_t
|
||||
{
|
||||
uint64 m_unToolItemID; // the Gift Wrap item
|
||||
uint64 m_unSubjectItemID; // the item to be wrapped
|
||||
};
|
||||
|
||||
// k_EMsgGCDeliverGift
|
||||
struct MsgGCDeliverGift_t
|
||||
{
|
||||
uint64 m_unGiftID;
|
||||
uint64 m_ulGiverSteamID;
|
||||
uint64 m_ulTargetSteamID;
|
||||
};
|
||||
|
||||
// k_EMsgGCUnwrapGiftRequest
|
||||
struct MsgGCUnwrapGiftRequest_t
|
||||
{
|
||||
uint64 m_unItemID;
|
||||
};
|
||||
|
||||
// k_EMsgGCMOTDRequest
|
||||
struct MsgGCMOTDRequest_t
|
||||
{
|
||||
RTime32 m_nLastMOTDRequest; // Time at which the client last asked for MOTDs. GC will send back all MOTDs posted since.
|
||||
int16 m_eLanguage;
|
||||
};
|
||||
|
||||
// k_EMsgGCMOTDRequestResponse
|
||||
struct MsgGCMOTDRequestResponse_t
|
||||
{
|
||||
int16 m_nEntries;
|
||||
};
|
||||
|
||||
// k_EMsgGCCustomizeItemTexture
|
||||
struct MsgGCCustomizeItemTexture_t
|
||||
{
|
||||
uint64 m_unToolItemID; // the tool
|
||||
uint64 m_unSubjectItemID; // the item wants the texture
|
||||
uint64 m_unImageUGCHandle; // cloud ID of image file (UGCHandle_t)
|
||||
};
|
||||
|
||||
// k_EMsgGCSetItemStyle
|
||||
struct MsgGCSetItemStyle_t
|
||||
{
|
||||
uint64 m_unItemID;
|
||||
uint8 m_iStyle;
|
||||
};
|
||||
|
||||
// k_EMsgGCItemPreviewCheckStatus
|
||||
struct MsgGCCheckItemPreviewStatus_t
|
||||
{
|
||||
uint32 m_unItemDefIndex;
|
||||
};
|
||||
|
||||
// k_EMsgGCItemPreviewCheckStatusResponse
|
||||
struct MsgGCItemPreviewCheckStatusResponse_t
|
||||
{
|
||||
uint32 m_unItemDefIndex;
|
||||
uint32 m_eResponse;
|
||||
RTime32 m_timePreviewTime;
|
||||
};
|
||||
|
||||
// k_EMsgGCItemPreviewRequest
|
||||
struct MsgGCItemPreviewRequest_t
|
||||
{
|
||||
uint32 m_unItemDefIndex;
|
||||
};
|
||||
|
||||
// k_EMsgGCItemPreviewRequestResponse
|
||||
struct MsgGCItemPreviewRequestResponse_t
|
||||
{
|
||||
uint32 m_unItemDefIndex;
|
||||
uint32 m_eResponse;
|
||||
};
|
||||
|
||||
// k_EMsgGCItemPreviewExpire
|
||||
struct MsgGCItemPreviewExpire_t
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// k_EMsgGCItemPreviewExpireNotification
|
||||
struct MsgGCItemPreviewExpireNotification_t
|
||||
{
|
||||
uint32 m_unItemDefIndex;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// k_EMsgGCUseItemResponse
|
||||
enum EGCMsgUseItemResponse
|
||||
{
|
||||
k_EGCMsgUseItemResponse_ItemUsed = 0,
|
||||
k_EGCMsgUseItemResponse_GiftNoOtherPlayers = 1,
|
||||
k_EGCMsgUseItemResponse_ServerError = 2,
|
||||
k_EGCMsgUseItemResponse_MiniGameAlreadyStarted = 3,
|
||||
k_EGCMsgUseItemResponse_ItemUsed_ItemsGranted = 4,
|
||||
k_EGCMsgUseItemResponse_CannotBeUsedByAccount = 5,
|
||||
k_EGCMsgUseItemResponse_ForceSizeInt = 0x7FFFFFFF
|
||||
};
|
||||
|
||||
// k_EMsgGCUseItemResponse
|
||||
struct MsgGCUseItemResponse_t
|
||||
{
|
||||
uint32 m_eResponse;
|
||||
};
|
||||
|
||||
// k_EMsgGCSpawnItem
|
||||
struct MsgGCSpawnItem_t
|
||||
{
|
||||
uint64 m_ulInitiatorSteamID;
|
||||
uint32 m_unItemDefinitionID;
|
||||
// other data dynamically added:
|
||||
// string of initiator name
|
||||
};
|
||||
|
||||
// k_EMsgGCRespawnPostLoadoutChange
|
||||
struct MsgGCRespawnPostLoadoutChange_t
|
||||
{
|
||||
uint64 m_ulInitiatorSteamID;
|
||||
};
|
||||
|
||||
// k_EMsgGCRemoveItemName
|
||||
struct MsgGCRemoveItemName_t
|
||||
{
|
||||
uint64 m_unItemID;
|
||||
bool m_bDescription;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Trading
|
||||
|
||||
// k_EMsgGCTrading_InitiateTradeRequest
|
||||
struct MsgGCTrading_InitiateTradeRequest_t
|
||||
{
|
||||
uint32 m_unTradeRequestID;
|
||||
uint64 m_ulOtherSteamID;
|
||||
// @note player A's name as string when sent to party B
|
||||
};
|
||||
|
||||
enum EGCMsgInitiateTradeResponse
|
||||
{
|
||||
k_EGCMsgInitiateTradeResponse_Accepted = 0,
|
||||
k_EGCMsgInitiateTradeResponse_Declined = 1,
|
||||
k_EGCMsgInitiateTradeResponse_VAC_Banned_Initiator = 2,
|
||||
k_EGCMsgInitiateTradeResponse_VAC_Banned_Target = 3,
|
||||
k_EGCMsgInitiateTradeResponse_Target_Already_Trading = 4,
|
||||
k_EGCMsgInitiateTradeResponse_Disabled = 5,
|
||||
k_EGCMsgInitiateTradeResponse_NotLoggedIn = 6,
|
||||
k_EGCMsgInitiateTradeResponse_Cancel = 7,
|
||||
k_EGCMsgInitiateTradeResponse_TooSoon = 8,
|
||||
k_EGCMsgInitiateTradeResponse_TooSoonPenalty = 9,
|
||||
k_EGCMsgInitiateTradeResponse_Trade_Banned_Initiator = 10,
|
||||
k_EGCMsgInitiateTradeResponse_Trade_Banned_Target = 11,
|
||||
k_EGCMsgInitiateTradeResponse_Free_Account_Initiator_DEPRECATED = 12, // free accounts can initiate trades now
|
||||
k_EGCMsgInitiateTradeResponse_Shared_Account_Initiator= 13,
|
||||
k_EGCMsgInitiateTradeResponse_Service_Unavailable = 14,
|
||||
k_EGCMsgInitiateTradeResponse_Target_Blocked = 15,
|
||||
k_EGCMsgInitiateTradeResponse_NeedVerifiedEmail = 16,
|
||||
k_EGCMsgInitiateTradeResponse_NeedSteamGuard = 17,
|
||||
k_EGCMsgInitiateTradeResponse_SteamGuardDuration = 18,
|
||||
k_EGCMsgInitiateTradeResponse_TheyCannotTrade = 19,
|
||||
k_EGCMsgInitiateTradeResponse_Recent_Password_Reset = 20,
|
||||
k_EGCMsgInitiateTradeResponse_Using_New_Device = 21,
|
||||
k_EGCMsgInitiateTradeResponse_Sent_Invalid_Cookie = 22,
|
||||
|
||||
k_EGCMsgInitiateTradeResponse_Count,
|
||||
k_EGCMsgInitiateTradeResponse_ForceSizeInt = 0x7FFFFFFF
|
||||
};
|
||||
|
||||
// k_EMsgGCTrading_InitiateTradeResponse
|
||||
struct MsgGCTrading_InitiateTradeResponse_t
|
||||
{
|
||||
uint32 m_eResponse;
|
||||
uint32 m_unTradeRequestID;
|
||||
};
|
||||
|
||||
// k_EMsgGCTrading_StartSession
|
||||
struct MsgGCTrading_StartSession_t
|
||||
{
|
||||
uint32 m_unSessionVersion;
|
||||
uint64 m_ulSteamIDPartyA;
|
||||
uint64 m_ulSteamIDPartyB;
|
||||
// @note strings from player names will be added to the message
|
||||
};
|
||||
|
||||
// k_EMsgGCTrading_CancelSession
|
||||
struct MsgGCTrading_CancelSession_t
|
||||
{
|
||||
};
|
||||
|
||||
// k_EMsgGCUsedClaimCodeItem
|
||||
struct MsgGCUsedClaimCodeItem_t
|
||||
{
|
||||
// string of URL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ServerBrowser messages
|
||||
|
||||
enum EGCMsgServerBrowser
|
||||
{
|
||||
k_EGCMsgServerBrowser_FromServerBrowser = 0,
|
||||
k_EGCMsgServerBrowser_FromAutoAskDialog = 1,
|
||||
};
|
||||
|
||||
// k_EMsgGCServerBrowser_FavoriteServer
|
||||
// k_EMsgGCServerBrowser_BlacklistServer
|
||||
struct MsgGCServerBrowser_Server_t
|
||||
{
|
||||
uint32 m_unIP;
|
||||
int m_usPort;
|
||||
uint8 m_ubSource; // 0=serverbrowser, 1=auto-ask dialog
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public facing loot lists.
|
||||
|
||||
// k_EMsgGC_RevolvingLootList
|
||||
struct MsgGC_RevolvingLootList_t
|
||||
{
|
||||
uint8 m_usListID; // Id of this list.
|
||||
// Var Data:
|
||||
// Serialized Lootlist KV
|
||||
};
|
||||
|
||||
|
||||
// k_EMsgGCLookupAccount
|
||||
struct MsgGCLookupAccount_t
|
||||
{
|
||||
uint16 m_uiFindType;
|
||||
|
||||
// Var Data
|
||||
// string containing Persona / URL / etc
|
||||
};
|
||||
|
||||
// k_EMsgGCLookupAccountName
|
||||
struct MsgGCLookupAccountName_t
|
||||
{
|
||||
uint32 m_unAccountID;
|
||||
};
|
||||
|
||||
// k_EMsgGCLookupAccountNameResponse
|
||||
struct MsgGCLookupAccountNameResponse_t
|
||||
{
|
||||
uint32 m_unAccountID;
|
||||
// string containing persona name
|
||||
};
|
||||
|
||||
#pragma pack( pop )
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,644 @@
|
||||
//====== Copyright 1996-2010, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: The file defines our Google Protocol Buffers which are used in over
|
||||
// the wire messages between servers as well as between the TF GC and TF gameservers
|
||||
// and clients.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
// We care more about speed than code size
|
||||
option optimize_for = SPEED;
|
||||
|
||||
// We don't use the service generation functionality
|
||||
option cc_generic_services = false;
|
||||
|
||||
|
||||
//
|
||||
// STYLE NOTES:
|
||||
//
|
||||
// Use CamelCase CMsgMyMessageName style names for messages.
|
||||
//
|
||||
// Use lowercase _ delimited names like my_steam_id for field names, this is non-standard for Steam,
|
||||
// but plays nice with the Google formatted code generation.
|
||||
//
|
||||
// Try not to use required fields ever. Only do so if you are really really sure you'll never want them removed.
|
||||
// Optional should be preffered as it will make versioning easier and cleaner in the future if someone refactors
|
||||
// your message and wants to remove or rename fields.
|
||||
//
|
||||
// Use fixed64 for JobId_t, GID_t, or SteamID. This is appropriate for any field that is normally
|
||||
// going to be larger than 2^56. Otherwise use int64 for 64 bit values that are frequently smaller
|
||||
// than 2^56 as it will safe space on the wire in those cases.
|
||||
//
|
||||
// Similar to fixed64, use fixed32 for RTime32 or other 32 bit values that are frequently larger than
|
||||
// 2^28. It will save space in those cases, otherwise use int32 which will safe space for smaller values.
|
||||
// An exception to this rule for RTime32 is if the value will frequently be zero rather than set to an actual
|
||||
// time.
|
||||
//
|
||||
|
||||
import "steammessages.proto";
|
||||
|
||||
enum EGCItemMsg
|
||||
{
|
||||
k_EMsgGCBase = 1000;
|
||||
k_EMsgGCSetSingleItemPosition = 1001; // uses old-school struct for a single item. Prefer k_EMsgGCSetItemPositions
|
||||
k_EMsgGCCraft = 1002;
|
||||
k_EMsgGCCraftResponse = 1003;
|
||||
k_EMsgGCDelete = 1004;
|
||||
k_EMsgGCVerifyCacheSubscription = 1005; // sent by gameservers who don't have a cache they expect
|
||||
k_EMsgGCNameItem = 1006;
|
||||
k_EMsgGCUnlockCrate = 1007; // used by decoder rings to unlock supply crates
|
||||
k_EMsgGCUnlockCrateResponse = 1008;
|
||||
k_EMsgGCPaintItem = 1009; // used by paint cans to paint items
|
||||
k_EMsgGCPaintItemResponse = 1010;
|
||||
k_EMsgGCGoldenWrenchBroadcast = 1011; // sent to all users when a Golden Wrench is crafted or deleted
|
||||
k_EMsgGCMOTDRequest = 1012; // client is asking for a set of MOTDs
|
||||
k_EMsgGCMOTDRequestResponse = 1013;
|
||||
|
||||
// k_EMsgGCAddItemToSocket_DEPRECATED = 1014;
|
||||
// k_EMsgGCAddItemToSocketResponse_DEPRECATED = 1015;
|
||||
// k_EMsgGCAddSocketToBaseItem_DEPRECATED = 1016;
|
||||
// k_EMsgGCAddSocketToItem_DEPRECATED = 1017;
|
||||
// k_EMsgGCAddSocketToItemResponse_DEPRECATED = 1018;
|
||||
|
||||
k_EMsgGCNameBaseItem = 1019;
|
||||
k_EMsgGCNameBaseItemResponse = 1020;
|
||||
|
||||
k_EMsgGCRemoveSocketItem_DEPRECATED = 1021;
|
||||
k_EMsgGCRemoveSocketItemResponse_DEPRECATED = 1022;
|
||||
|
||||
k_EMsgGCCustomizeItemTexture = 1023;
|
||||
k_EMsgGCCustomizeItemTextureResponse = 1024;
|
||||
k_EMsgGCUseItemRequest = 1025; // client/game server => GC
|
||||
k_EMsgGCUseItemResponse = 1026; // GC => client/game server
|
||||
|
||||
// k_EMsgGCSpawnItem_DEPRECATED = 1028; // GC => game server
|
||||
k_EMsgGCRespawnPostLoadoutChange = 1029; // client => GC => game server
|
||||
k_EMsgGCRemoveItemName = 1030; // client => GC
|
||||
k_EMsgGCRemoveItemPaint = 1031; // client => GC
|
||||
k_EMsgGCGiftWrapItem = 1032; // client => GC (the player requests an item to be gift wrapped)
|
||||
k_EMsgGCGiftWrapItemResponse = 1033; // GC => client (confirmation that an item was gift wrapped)
|
||||
k_EMsgGCDeliverGift = 1034;
|
||||
k_EMsgGCDeliverGiftResponseReceiver = 1036;
|
||||
k_EMsgGCUnwrapGiftRequest = 1037;
|
||||
k_EMsgGCUnwrapGiftResponse = 1038;
|
||||
k_EMsgGCSetItemStyle = 1039;
|
||||
|
||||
k_EMsgGCUsedClaimCodeItem = 1040;
|
||||
k_EMsgGCSortItems = 1041;
|
||||
|
||||
k_EMsgGC_RevolvingLootList_DEPRECATED= 1042; // GC => client; revolving loot list
|
||||
|
||||
k_EMsgGCLookupAccount = 1043; // client is requesting a lookup of an account
|
||||
k_EMsgGCLookupAccountResponse = 1044;
|
||||
k_EMsgGCLookupAccountName = 1045; // old-school struct for single account. client is requesting a lookup of an account name
|
||||
k_EMsgGCLookupAccountNameResponse = 1046;
|
||||
|
||||
//k_EMsgGCStartupCheck = 1047; // GC => client
|
||||
//k_EMsgGCStartupCheckResponse = 1048; // client => GC
|
||||
k_EMsgGCUpdateItemSchema = 1049; // GC => client
|
||||
k_EMsgGCRequestInventoryRefresh = 1050; // client => GC
|
||||
|
||||
k_EMsgGCRemoveCustomTexture = 1051; // client => GC
|
||||
k_EMsgGCRemoveCustomTextureResponse = 1052; // GC => client
|
||||
k_EMsgGCRemoveMakersMark = 1053; // client => GC
|
||||
k_EMsgGCRemoveMakersMarkResponse = 1054; // GC => client
|
||||
k_EMsgGCRemoveUniqueCraftIndex = 1055; // client => GC
|
||||
k_EMsgGCRemoveUniqueCraftIndexResponse = 1056; // GC => client
|
||||
|
||||
k_EMsgGCSaxxyBroadcast = 1057; // sent to all users when a Saxxy is deleted
|
||||
|
||||
k_EMsgGCBackpackSortFinished = 1058; // GC => client
|
||||
k_EMsgGCAdjustItemEquippedState = 1059; // GC => client
|
||||
// k_EMsgGCRequestItemSchemaData_DEPRECATED = 1060; // client => GC Should only be used in dev universe
|
||||
|
||||
k_EMsgGCCollectItem = 1061;
|
||||
|
||||
k_EMsgGCItemAcknowledged = 1062; // sent to a dedicated server when a client acknowledges an item
|
||||
|
||||
// item presets
|
||||
k_EMsgGCPresets_SelectPresetForClass = 1063; // client => GC
|
||||
k_EMsgGCPresets_SetItemPosition = 1064; // client => GC
|
||||
|
||||
// Abuse reporting
|
||||
k_EMsgGC_ReportAbuse = 1065; // client => GC
|
||||
k_EMsgGC_ReportAbuseResponse = 1066; // GC => client
|
||||
|
||||
// more item presets
|
||||
k_EMsgGCPresets_SelectPresetForClassReply = 1067; // GC => client
|
||||
|
||||
// item naming broadcast
|
||||
k_EMsgGCNameItemNotification = 1068; // GC => client
|
||||
|
||||
// !FIXME! DOTAMERGE
|
||||
// these messages are particular to DOTA, or
|
||||
// conflict with corresponding TF messages
|
||||
//
|
||||
// k_EMsgGCGiftedItems = 1027; // GC => game server
|
||||
// k_EMsgGCDeliverGiftResponseGiver = 1035;
|
||||
//
|
||||
// k_EMsgGCApplyConsumableEffects = 1069;
|
||||
//
|
||||
// k_EMsgGCConsumableExhausted = 1070;
|
||||
// k_EMsgGCApplyStrangePart = 1073; // GC => client
|
||||
// k_EMsgGCShowItemsPickedUp = 1071;
|
||||
//
|
||||
// // generic broadcast
|
||||
// k_EMsgGCClientDisplayNotification = 1072; // GC => client
|
||||
//
|
||||
//// OBSOLETE k_EMsgGC_IncrementKillCountAttribute = 1074; // client => GC
|
||||
// k_EMsgGC_IncrementKillCountResponse = 1075; // GC => client
|
||||
// k_EMsgGCApplyPennantUpgrade = 1076; // GC => client
|
||||
//
|
||||
// k_EMsgGCSetItemPositions = 1077; // client => GC; protobuf batched item position update
|
||||
//
|
||||
// k_EMsgGCUnlockItemStyle = 1080;
|
||||
// k_EMsgGCUnlockItemStyleResponse = 1081;
|
||||
//
|
||||
// k_EMsgGCFulfillDynamicRecipeComponent = 1082;
|
||||
// k_EMsgGCFulfillDynamicRecipeComponentResponse = 1083;
|
||||
// k_EMsgGCApplyEggEssence = 1078;
|
||||
// k_EMsgGCNameEggEssenceResponse = 1079;
|
||||
//
|
||||
// k_EMsgGCClientRequestMarketData = 1084;
|
||||
// k_EMsgGCClientRequestMarketDataResponse = 1085;
|
||||
// k_EMsgGCExtractGems = 1086;
|
||||
// k_EMsgGCAddSocket = 1087; // client -> GC
|
||||
// k_EMsgGCAddItemToSocket = 1088; // client -> GC
|
||||
// k_EMsgGCAddItemToSocketResponse = 1089; // GC -> client
|
||||
// k_EMsgGCAddSocketResponse = 1090; // GC -> client
|
||||
//
|
||||
// k_EMsgGCResetStrangeGemCount = 1091; // client -> GC
|
||||
|
||||
// << DOTA
|
||||
|
||||
// TF >>
|
||||
|
||||
// generic broadcast
|
||||
k_EMsgGCClientDisplayNotification = 1069; // GC => client
|
||||
|
||||
k_EMsgGCApplyStrangePart = 1070; // GC => client
|
||||
k_EMsgGC_IncrementKillCountAttribute = 1071; // client => GC
|
||||
k_EMsgGC_IncrementKillCountResponse = 1072; // GC => client
|
||||
k_EMsgGCRemoveStrangePart = 1073; // GC => client
|
||||
k_EMsgGCResetStrangeScores = 1074; // client => GC
|
||||
|
||||
k_EMsgGCGiftedItems = 1075; // GC => game server
|
||||
|
||||
k_EMsgGCApplyUpgradeCard = 1077; // client => GC
|
||||
k_EMsgGCRemoveUpgradeCard = 1078; // client => GC
|
||||
|
||||
k_EMsgGCApplyStrangeRestriction = 1079; // client => GC
|
||||
|
||||
k_EMsgGCClientRequestMarketData = 1080; // client => GC
|
||||
k_EMsgGCClientRequestMarketDataResponse = 1081; // GC => client
|
||||
|
||||
k_EMsgGCApplyXifier = 1082; // client => GC
|
||||
k_EMsgGCApplyXifierResponse = 1083; // GC => Client
|
||||
|
||||
k_EMsgGC_TrackUniquePlayerPairEvent = 1084; // client => GC
|
||||
k_EMsgGCFulfillDynamicRecipeComponent = 1085; // client => GC
|
||||
k_EMsgGCFulfillDynamicRecipeComponentResponse = 1086; // GC => client
|
||||
|
||||
k_EMsgGCSetItemEffectVerticalOffset = 1087; // client => GC
|
||||
k_EMsgGCSetHatEffectUseHeadOrigin = 1088; // client => GC
|
||||
|
||||
k_EMsgGCItemEaterRecharger = 1089; // client => GC
|
||||
k_EMsgGCItemEaterRechargerResponse = 1090; // GC => Client
|
||||
|
||||
k_EMsgGCApplyBaseItemXifier = 1091; // client => GC
|
||||
|
||||
k_EMsgGCApplyClassTransmogrifier = 1092; // client => GC
|
||||
k_EMsgGCApplyHalloweenSpellbookPage = 1093; // client => GC
|
||||
|
||||
k_EMsgGCRemoveKillStreak = 1094; // client => GC
|
||||
k_EMsgGCRemoveKillStreakResponse = 1095; // GC => client
|
||||
|
||||
k_EMsgGCTFSpecificItemBroadcast = 1096; // GC => client (broadcast)
|
||||
k_EMsgGC_IncrementKillCountAttribute_Multiple = 1097; // client (game server) => GC
|
||||
k_EMsgGCDeliverGiftResponseGiver = 1098;
|
||||
|
||||
k_EMsgGCSetItemPositions = 1100; // client => GC; protobuf batched item position update
|
||||
|
||||
// << TF
|
||||
|
||||
k_EMsgGCLookupMultipleAccountNames = 1101;
|
||||
k_EMsgGCLookupMultipleAccountNamesResponse = 1102;
|
||||
|
||||
// trading!
|
||||
k_EMsgGCTradingBase = 1500;
|
||||
k_EMsgGCTrading_InitiateTradeRequest = 1501; // client A -> GC and then GC -> client B
|
||||
k_EMsgGCTrading_InitiateTradeResponse = 1502; // client B -> GC or GC -> client A
|
||||
k_EMsgGCTrading_StartSession = 1503; // GC -> client A & B
|
||||
// k_EMsgGCTrading_SetItem = 1504; // client -> GC
|
||||
// k_EMsgGCTrading_RemoveItem = 1505; // client -> GC
|
||||
// k_EMsgGCTrading_UpdateTradeInfo = 1506; // GC -> client A & B in response to SetItem or RemoveItem message
|
||||
// k_EMsgGCTrading_SetReadiness = 1507; // client -> GC
|
||||
// k_EMsgGCTrading_ReadinessResponse = 1508; // GC -> client A & B
|
||||
k_EMsgGCTrading_SessionClosed = 1509; // GC -> client A & B
|
||||
k_EMsgGCTrading_CancelSession = 1510; // client -> GC
|
||||
// k_EMsgGCTrading_TradeChatMsg = 1511; // client -> GC and then GC -> other client
|
||||
// k_EMsgGCTrading_ConfirmOffer = 1512; // client -> GC
|
||||
// k_EMsgGCTrading_TradeTypingChatMsg = 1513; // client -> GC and then GC -> other client
|
||||
k_EMsgGCTrading_InitiateTradeRequestResponse = 1514; // GC -> client
|
||||
|
||||
// serverbrowser messages
|
||||
k_EMsgGCServerBrowser_FavoriteServer = 1601;
|
||||
k_EMsgGCServerBrowser_BlacklistServer = 1602;
|
||||
|
||||
// rentals & previews
|
||||
k_EMsgGCServerRentalsBase = 1700;
|
||||
k_EMsgGCItemPreviewCheckStatus = 1701;
|
||||
k_EMsgGCItemPreviewStatusResponse = 1702;
|
||||
k_EMsgGCItemPreviewRequest = 1703;
|
||||
k_EMsgGCItemPreviewRequestResponse = 1704;
|
||||
k_EMsgGCItemPreviewExpire = 1705;
|
||||
k_EMsgGCItemPreviewExpireNotification = 1706;
|
||||
|
||||
// !FIXME! DOTAMERGE
|
||||
// This message is 1707 in DOTA, but it came from TF, where it was 1707 at one time, then switched to 1708
|
||||
// when the message format changed.
|
||||
// k_EMsgGCItemPreviewItemBoughtNotification = 1707;
|
||||
k_EMsgGCItemPreviewItemBoughtNotification = 1708;
|
||||
|
||||
// Development only messages
|
||||
k_EMsgGCDev_NewItemRequest = 2001;
|
||||
k_EMsgGCDev_NewItemRequestResponse = 2002;
|
||||
k_EMsgGCDev_DebugRollLootRequest = 2003;
|
||||
|
||||
// Microtransaction messages
|
||||
k_EMsgGCStoreGetUserData = 2500; // Gets the current price sheet from the GC
|
||||
k_EMsgGCStoreGetUserDataResponse = 2501; // Response
|
||||
k_EMsgGCStorePurchaseInit_DEPRECATED = 2502; // Initiate a purchase (old pre-protobuff format -- deprecated!)
|
||||
k_EMsgGCStorePurchaseInitResponse_DEPRECATED = 2503; // Response
|
||||
|
||||
// !FIXME! DOTAMERGE
|
||||
// These messages have different values in TF and DOTA.
|
||||
// k_EMsgGCStorePurchaseFinalize = 2504; // Finalize a purchase
|
||||
// k_EMsgGCStorePurchaseFinalizeResponse = 2505; // Response
|
||||
// k_EMsgGCStorePurchaseCancel = 2506; // Cancel a purchase
|
||||
// k_EMsgGCStorePurchaseCancelResponse = 2507; // Response
|
||||
k_EMsgGCStorePurchaseFinalize = 2512; // Finalize a purchase
|
||||
k_EMsgGCStorePurchaseFinalizeResponse = 2513; // Response
|
||||
k_EMsgGCStorePurchaseCancel = 2514; // Cancel a purchase
|
||||
k_EMsgGCStorePurchaseCancelResponse = 2515; // Response
|
||||
|
||||
k_EMsgGCStorePurchaseQueryTxn = 2508; // Query the status of a transaction
|
||||
k_EMsgGCStorePurchaseQueryTxnResponse = 2509; // Response
|
||||
k_EMsgGCStorePurchaseInit = 2510; // Initiate a purchase
|
||||
k_EMsgGCStorePurchaseInitResponse = 2511; // Response
|
||||
|
||||
// !FIXME! DOTAMERGE
|
||||
// Conflict with TF messages
|
||||
// k_EMsgGCBannedWordListRequest = 2512; // Request a list of new banned words
|
||||
// k_EMsgGCBannedWordListResponse = 2513; // response to a request, or a push of a new banned word update to clients
|
||||
// k_EMsgGCToGCBannedWordListBroadcast = 2514; // sent from GC to GC so the main GC can broadcast a banned word change to clients
|
||||
// k_EMsgGCToGCBannedWordListUpdated = 2515; // sent from GC to other GCs so that they can be kept in sync with banned word list updates
|
||||
|
||||
k_EMsgGCToGCDirtySDOCache = 2516; // when an SDO cache needs to be dirtied on another GC
|
||||
k_EMsgGCToGCDirtyMultipleSDOCache = 2517; // when a list of SDO caches needs to be dirtied on another GC
|
||||
|
||||
k_EMsgGCToGCUpdateSQLKeyValue = 2518; // when a key value changes and needs to be updated on other GCs
|
||||
// k_EMsgGCToGCIsTrustedServer = 2519; // Is the specified server trusted?
|
||||
// k_EMsgGCToGCIsTrustedServerResponse = 2520; // response to whether or not this is a trusted server
|
||||
k_EMsgGCToGCBroadcastConsoleCommand = 2521; // run a console command remotely on another GC from a GC
|
||||
|
||||
k_EMsgGCServerVersionUpdated = 2522; // Sent when the active version of a server changes so servers can restart
|
||||
|
||||
k_EMsgGCApplyAutograph = 2523; //
|
||||
k_EMsgGCToGCWebAPIAccountChanged = 2524;
|
||||
k_EMsgGCRequestAnnouncements = 2525; //
|
||||
k_EMsgGCRequestAnnouncementsResponse = 2526; //
|
||||
k_EMsgGCRequestPassportItemGrant = 2527;
|
||||
|
||||
k_EMsgGCClientVersionUpdated = 2528; // Sent when the client doesn't match the appropriate version
|
||||
|
||||
k_EMsgGCItemPurgatory_FinalizePurchase = 2531; // Sent for Korean government requirement - move a purchased item from the "maybe box" (referred to as item purgatory in code) to the backpack
|
||||
k_EMsgGCItemPurgatory_FinalizePurchaseResponse = 2532;
|
||||
k_EMsgGCItemPurgatory_RefundPurchase = 2533;
|
||||
k_EMsgGCItemPurgatory_RefundPurchaseResponse = 2534;
|
||||
|
||||
k_EMsgGCToGCPlayerStrangeCountAdjustments = 2535;
|
||||
|
||||
k_EMsgGCRequestStoreSalesData = 2536; // get which items are currently on sale
|
||||
k_EMsgGCRequestStoreSalesDataResponse = 2537;
|
||||
k_EMsgGCRequestStoreSalesDataUpToDateResponse = 2538;
|
||||
|
||||
k_EMsgGCToGCPingRequest = 2539;
|
||||
k_EMsgGCToGCPingResponse = 2540;
|
||||
|
||||
k_EMsgGCToGCGetUserSessionServer = 2541; // GC->GC, see what the steam ID is of the server that this user is on
|
||||
k_EMsgGCToGCGetUserSessionServerResponse = 2542; // --response
|
||||
k_EMsgGCToGCGetUserServerMembers = 2543; // GC->GC, what members are on the server and spectating
|
||||
k_EMsgGCToGCGetUserServerMembersResponse = 2544; // --response
|
||||
|
||||
k_EMsgGCToGCGrantSelfMadeItemToAccount = 2555; // GC->GC, via SQL message queue, grant one specific self-made item to this contributor account ID
|
||||
k_EMsgGCToGCThankedByNewUser = 2556; // GC->GC, via SQL message queue, this account was thanked by a new user account, so grant a thanked item or level up the current item
|
||||
|
||||
k_EMsgGCShuffleCrateContents = 2557; // game client->GC, shuffle the contents of the line item loot list for this crate
|
||||
|
||||
k_EMsgGCQuestObjective_Progress = 2558; // client/game -> GC, report progress in a quest objective
|
||||
k_EMsgGCQuestCompleted = 2559; // GC -> client, report completion of a quest
|
||||
|
||||
k_EMsgGCApplyDuckToken = 2560; // client => GC
|
||||
|
||||
k_EMsgGCQuestComplete_Request = 2561; // client -> GC
|
||||
k_EMsgGCQuestObjective_PointsChange = 2562; // server -> GC
|
||||
k_EMsgGCQuestObjective_RequestLoanerItems = 2564; // client -> GC
|
||||
k_EMsgGCQuestObjective_RequestLoanerResponse = 2565; // GC -> client
|
||||
|
||||
k_EMsgGCApplyStrangeCountTransfer = 2566; // client => GC
|
||||
k_EMsgGCCraftCollectionUpgrade = 2567; // client => GC
|
||||
k_EMsgGCCraftHalloweenOffering = 2568; // client => GC
|
||||
|
||||
k_EMsgGCQuestDiscard_Request = 2569; // client => GC
|
||||
|
||||
k_EMsgGCRemoveGiftedBy = 2570; // client => GC
|
||||
k_EMsgGCRemoveGiftedByResponse = 2571; // GC => client
|
||||
|
||||
k_EMsgGCRemoveFestivizer = 2572; // client => GC
|
||||
k_EMsgGCRemoveFestivizerResponse = 2573; // GC => client
|
||||
|
||||
k_EMsgGCCraftCommonStatClock = 2574; // client => GC
|
||||
|
||||
// Game specific messages start at 5000 and GCGameBase messages start at 3000
|
||||
// So all these must be < 3000
|
||||
};
|
||||
|
||||
enum EGCMsgResponse
|
||||
{
|
||||
k_EGCMsgResponseOK = 0; // Request succeeded
|
||||
k_EGCMsgResponseDenied = 1; // Request denied
|
||||
k_EGCMsgResponseServerError = 2; // Request failed due to a temporary server error
|
||||
k_EGCMsgResponseTimeout = 3; // Request timed out
|
||||
k_EGCMsgResponseInvalid = 4; // Request was corrupt
|
||||
k_EGCMsgResponseNoMatch = 5; // No item definition matched the request
|
||||
k_EGCMsgResponseUnknownError = 6; // Request failed with an unknown error
|
||||
k_EGCMsgResponseNotLoggedOn = 7; // Client not logged on to steam
|
||||
k_EGCMsgFailedToCreate = 8; // Failed to create whatever object the GC was asked to create
|
||||
|
||||
// k_EGCMsgResponseForceSizeInt = 0x7FFFFFFF
|
||||
};
|
||||
|
||||
enum EUnlockStyle
|
||||
{
|
||||
k_UnlockStyle_Succeeded = 0;
|
||||
k_UnlockStyle_Failed_PreReq = 1;
|
||||
k_UnlockStyle_Failed_CantAfford = 2;
|
||||
k_UnlockStyle_Failed_CantCommit = 3;
|
||||
k_UnlockStyle_Failed_CantLockCache = 4;
|
||||
k_UnlockStyle_Failed_CantAffordAttrib = 5;
|
||||
k_UnlockStyle_Failed_CantAffordGem = 6;
|
||||
};
|
||||
|
||||
enum EItemPurgatoryResponse_Finalize
|
||||
{
|
||||
k_ItemPurgatoryResponse_Finalize_Succeeded = 0;
|
||||
k_ItemPurgatoryResponse_Finalize_Failed_Incomplete = 1; // Some but not all finalized
|
||||
k_ItemPurgatoryResponse_Finalize_Failed_ItemsNotInPurgatory = 2; // Item ID's sent up were not in purgatory
|
||||
k_ItemPurgatoryResponse_Finalize_Failed_CouldNotFindItems = 3; // One or more items do not belong to the given steam ID or were deleted, etc.
|
||||
k_ItemPurgatoryResponse_Finalize_Failed_NoSOCache = 4; // Couldn't load the user's SO cache
|
||||
k_ItemPurgatoryResponse_Finalize_BackpackFull = 5; // Backpack was full. We may have finalized some items.
|
||||
};
|
||||
|
||||
enum EItemPurgatoryResponse_Refund
|
||||
{
|
||||
k_ItemPurgatoryResponse_Refund_Succeeded = 0;
|
||||
k_ItemPurgatoryResponse_Refund_Failed_ItemNotInPurgatory = 1; // Item ID's sent up were not in purgatory
|
||||
k_ItemPurgatoryResponse_Refund_Failed_CouldNotFindItem = 2; // One or more items do not belong to the given steam ID or were deleted, etc.
|
||||
k_ItemPurgatoryResponse_Refund_Failed_NoSOCache = 3; // Couldn't load the user's SO cache
|
||||
k_ItemPurgatoryResponse_Refund_Failed_NoDetail = 4; // Generic error to avoid giving the client too much detail
|
||||
k_ItemPurgatoryResponse_Refund_Failed_NexonWebAPI = 5; // The Nexon WebAPI failed
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCApplyAutograph
|
||||
//
|
||||
message CMsgApplyAutograph
|
||||
{
|
||||
optional uint64 autograph_item_id = 1; // which autograph?
|
||||
optional uint64 item_item_id = 2; // which item is getting this autograph
|
||||
};
|
||||
|
||||
|
||||
// k_EMsgGCToGCPlayerStrangeCountAdjustments
|
||||
// Used in the GC SQL Msg queue and in match signout
|
||||
message CMsgEconPlayerStrangeCountAdjustment
|
||||
{
|
||||
message CStrangeCountAdjustment
|
||||
{
|
||||
optional uint32 event_type = 1;
|
||||
optional uint64 item_id = 2;
|
||||
optional uint32 adjustment = 3;
|
||||
};
|
||||
|
||||
optional uint32 account_id = 1;
|
||||
repeated CStrangeCountAdjustment strange_count_adjustments = 2;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// k_EMsgGCItemPurgatory_FinalizePurchase
|
||||
//
|
||||
message CMsgRequestItemPurgatory_FinalizePurchase
|
||||
{
|
||||
repeated uint64 item_ids = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCItemPurgatory_FinalizePurchaseResponse
|
||||
//
|
||||
message CMsgRequestItemPurgatory_FinalizePurchaseResponse
|
||||
{
|
||||
optional uint32 result = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCItemPurgatory_RefundPurchase
|
||||
//
|
||||
message CMsgRequestItemPurgatory_RefundPurchase
|
||||
{
|
||||
optional uint64 item_id = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCItemPurgatory_RefundPurchaseResponse
|
||||
//
|
||||
message CMsgRequestItemPurgatory_RefundPurchaseResponse
|
||||
{
|
||||
optional uint32 result = 1;
|
||||
};
|
||||
|
||||
message CMsgCraftingResponse
|
||||
{
|
||||
repeated uint64 item_ids = 1;
|
||||
};
|
||||
|
||||
// k_EMsgGCRequestStoreSalesData
|
||||
message CMsgGCRequestStoreSalesData
|
||||
{
|
||||
optional uint32 version = 1; // the last received version (used to identify when sales data may have changed)
|
||||
optional uint32 currency = 2; // which currency we want the sales values for
|
||||
};
|
||||
|
||||
// k_EMsgGCRequestStoreSalesDataResponse
|
||||
message CMsgGCRequestStoreSalesDataResponse
|
||||
{
|
||||
message Price
|
||||
{
|
||||
optional uint32 item_def = 1;
|
||||
optional uint32 price = 2;
|
||||
};
|
||||
repeated Price sale_price = 1; // the list of items on sale and their sale price for the requested currency
|
||||
optional uint32 version = 2; // the version of this data, future sale requests should provide this value so redundant requests can be ignored
|
||||
optional uint32 expiration_time = 3; // the time after which this sale is likely to expire. It could expire sooner than this if the GC restarts
|
||||
};
|
||||
|
||||
// k_EMsgGCRequestStoreSalesDataUpToDateResponse
|
||||
message CMsgGCRequestStoreSalesDataUpToDateResponse
|
||||
{
|
||||
optional uint32 version = 1; // the last received version (used to identify when sales data may have changed)
|
||||
optional uint32 expiration_time = 2; // the time after which this sale is likely to expire. It could expire sooner than this if the GC restarts
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCPingRequest
|
||||
message CMsgGCToGCPingRequest
|
||||
{
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCPingResponse
|
||||
message CMsgGCToGCPingResponse
|
||||
{
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCGetUserSessionServer
|
||||
message CMsgGCToGCGetUserSessionServer
|
||||
{
|
||||
optional uint32 account_id = 1; // the user to lookup the server information for
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCGetUserSessionServerResponse
|
||||
message CMsgGCToGCGetUserSessionServerResponse
|
||||
{
|
||||
optional fixed64 server_steam_id = 1; // zero if this user is not online or not on a server
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCGetUserServerMembers
|
||||
message CMsgGCToGCGetUserServerMembers
|
||||
{
|
||||
optional uint32 account_id = 1; // the account ID to look up the server and spectators from
|
||||
optional uint32 max_spectators = 2; // do you want spectators? If so what is the limit of how many will be returned (otherwise specify zero)
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCGetUserServerMembersResponse
|
||||
message CMsgGCToGCGetUserServerMembersResponse
|
||||
{
|
||||
repeated uint32 member_account_id = 1; // the list of other server members or spectators
|
||||
};
|
||||
|
||||
// k_EMsgGCLookupMultipleAccountNames
|
||||
message CMsgLookupMultipleAccountNames
|
||||
{
|
||||
repeated uint32 accountids = 1 [ packed=true ];
|
||||
};
|
||||
|
||||
// k_EMsgGCLookupMultipleAccountNamesResponse
|
||||
message CMsgLookupMultipleAccountNamesResponse
|
||||
{
|
||||
message Account
|
||||
{
|
||||
optional uint32 accountid = 1;
|
||||
optional string persona = 2;
|
||||
}
|
||||
repeated Account accounts = 1;
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCGrantSelfMadeItemToAccount
|
||||
message CMsgGCToGCGrantSelfMadeItemToAccount
|
||||
{
|
||||
optional uint32 item_def_index = 1;
|
||||
optional uint32 accountid = 2;
|
||||
}
|
||||
|
||||
// k_EMsgGCToGCThankedByNewUser
|
||||
message CMsgGCToGCThankedByNewUser
|
||||
{
|
||||
optional uint32 new_user_accountid = 1; // guy who did the thanking
|
||||
optional uint32 thanked_user_accountid = 2; // guy who was thanked
|
||||
}
|
||||
|
||||
// k_EMsgGCShuffleCrateContents
|
||||
message CMsgGCShuffleCrateContents
|
||||
{
|
||||
optional uint64 crate_item_id = 1;
|
||||
optional string user_code_string = 2;
|
||||
}
|
||||
|
||||
// k_EMsgGCQuestObjective_Progress
|
||||
message CMsgGCQuestObjective_Progress
|
||||
{
|
||||
optional uint64 quest_item_id = 1;
|
||||
optional uint32 quest_attrib_index = 2;
|
||||
optional uint32 delta = 3;
|
||||
optional fixed64 owner_steamid = 4;
|
||||
}
|
||||
|
||||
// CMsgGCQuestObjective_PointsChange
|
||||
message CMsgGCQuestObjective_PointsChange
|
||||
{
|
||||
optional uint64 quest_item_id = 1;
|
||||
optional uint32 standard_points = 2;
|
||||
optional uint32 bonus_points = 3;
|
||||
optional fixed64 owner_steamid = 4;
|
||||
optional bool update_base_points = 5 [default = false];
|
||||
}
|
||||
|
||||
// k_EMsgGCQuestComplete_Request
|
||||
message CMsgGCQuestComplete_Request
|
||||
{
|
||||
optional uint64 quest_item_id = 1;
|
||||
}
|
||||
|
||||
// k_EMsgGCQuestCompleted
|
||||
message CMsgGCQuestCompleted
|
||||
{
|
||||
}
|
||||
|
||||
// k_EMsgGCQuestObjective_RequestLoanerItems
|
||||
message CMsgGCQuestObjective_RequestLoanerItems
|
||||
{
|
||||
optional uint64 quest_item_id = 1;
|
||||
}
|
||||
|
||||
// k_EMsgGCQuestObjective_RequestLoanerResponse
|
||||
message CMsgGCQuestObjective_RequestLoanerResponse
|
||||
{
|
||||
}
|
||||
|
||||
// k_EMsgGCCraftCollectionUpgrader
|
||||
message CMsgCraftCollectionUpgrade
|
||||
{
|
||||
repeated uint64 item_id = 1; // list of item ids
|
||||
};
|
||||
|
||||
// k_EMsgGCCraftHalloweenOffering
|
||||
message CMsgCraftHalloweenOffering
|
||||
{
|
||||
optional uint64 tool_id = 1; // tool that is invoking this call
|
||||
repeated uint64 item_id = 2; // list of item ids
|
||||
};
|
||||
|
||||
// k_EMsgGCCraftCommonStatClock
|
||||
message CMsgCraftCommonStatClock
|
||||
{
|
||||
optional uint64 tool_id = 1; // tool that is invoking this call
|
||||
repeated uint64 item_id = 2; // list of item ids
|
||||
};
|
||||
|
||||
// k_EMsgGCQuestDiscard_Request
|
||||
message CMsgGCQuestDiscard_Request
|
||||
{
|
||||
optional uint64 quest_item_id = 1;
|
||||
}
|
||||
|
||||
// Do not remove this comment due to a bug on the Mac OS X protobuf compiler - lol
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "rtime.h"
|
||||
#include "econ_holidays.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Interface that answers the simple question "on the passed-in time,
|
||||
// would this holiday be active?". Any caching of calculations is left
|
||||
// up to subclasses.
|
||||
//-----------------------------------------------------------------------------
|
||||
class IIsHolidayActive
|
||||
{
|
||||
public:
|
||||
IIsHolidayActive( const char *pszHolidayName ) : m_pszHolidayName( pszHolidayName ) { }
|
||||
virtual ~IIsHolidayActive ( ) { }
|
||||
virtual bool IsActive( const CRTime& timeCurrent ) = 0;
|
||||
|
||||
const char *GetHolidayName() const { return m_pszHolidayName; }
|
||||
|
||||
private:
|
||||
const char *m_pszHolidayName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Always-disabled. Dummy event needed to map to slot zero for "disabled
|
||||
// holiday".
|
||||
//-----------------------------------------------------------------------------
|
||||
class CNoHoliday : public IIsHolidayActive
|
||||
{
|
||||
public:
|
||||
CNoHoliday() : IIsHolidayActive( "none" ) { }
|
||||
|
||||
virtual bool IsActive( const CRTime& timeCurrent )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A holiday that lasts exactly one and only one day.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSingleDayHoliday : public IIsHolidayActive
|
||||
{
|
||||
public:
|
||||
CSingleDayHoliday( const char *pszName, int iMonth, int iDay )
|
||||
: IIsHolidayActive( pszName )
|
||||
, m_iMonth( iMonth )
|
||||
, m_iDay( iDay )
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
virtual bool IsActive( const CRTime& timeCurrent )
|
||||
{
|
||||
return m_iMonth == timeCurrent.GetMonth()
|
||||
&& m_iDay == timeCurrent.GetDayOfMonth();
|
||||
}
|
||||
|
||||
private:
|
||||
int m_iMonth;
|
||||
int m_iDay;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: We want "week long" holidays to encompass at least two weekends,
|
||||
// so that players get plenty of time interacting with the holiday
|
||||
// features.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CWeeksBasedHoliday : public IIsHolidayActive
|
||||
{
|
||||
public:
|
||||
CWeeksBasedHoliday( const char *pszName, int iMonth, int iDay, int iExtraWeeks )
|
||||
: IIsHolidayActive( pszName )
|
||||
, m_iMonth( iMonth )
|
||||
, m_iDay( iDay )
|
||||
, m_iExtraWeeks( iExtraWeeks )
|
||||
, m_iCachedCalculatedYear( 0 )
|
||||
{
|
||||
// We'll calculate the interval the first time we call IsActive().
|
||||
}
|
||||
|
||||
void RecalculateTimeActiveInterval( int iYear )
|
||||
{
|
||||
// Get the date of the holiday.
|
||||
tm holiday_tm = { };
|
||||
holiday_tm.tm_mday = m_iDay;
|
||||
holiday_tm.tm_mon = m_iMonth - 1;
|
||||
holiday_tm.tm_year = iYear - 1900; // convert to years since 1900
|
||||
mktime( &holiday_tm );
|
||||
|
||||
// The event starts on the first Friday at least four days prior to the holiday.
|
||||
tm start_time_tm( holiday_tm );
|
||||
start_time_tm.tm_mday -= 4; // Move back four days.
|
||||
mktime( &start_time_tm );
|
||||
int days_offset = start_time_tm.tm_wday - kFriday; // Find the nearest prior Friday.
|
||||
if ( days_offset < 0 )
|
||||
days_offset += 7;
|
||||
start_time_tm.tm_mday -= days_offset;
|
||||
time_t start_time = mktime( &start_time_tm );
|
||||
|
||||
// The event ends on the first Monday after the holiday, maybe plus some additional fudge
|
||||
// time.
|
||||
tm end_time_tm( holiday_tm );
|
||||
days_offset = 7 - (end_time_tm.tm_wday - kMonday);
|
||||
if ( days_offset >= 7 )
|
||||
days_offset -= 7;
|
||||
end_time_tm.tm_mday += days_offset + 7 * m_iExtraWeeks;
|
||||
time_t end_time = mktime( &end_time_tm );
|
||||
|
||||
#ifdef GC_DLL
|
||||
char rgchDateStartBuf[ 128 ];
|
||||
BGetLocalFormattedDate( start_time, rgchDateStartBuf, sizeof( rgchDateStartBuf) );
|
||||
|
||||
char rgchDateEndBuf[ 128 ];
|
||||
BGetLocalFormattedDate( end_time, rgchDateEndBuf, sizeof( rgchDateEndBuf ) );
|
||||
|
||||
EmitInfo( GCSDK::SPEW_GC, 4, LOG_ALWAYS, "Holiday - '%s' event starts on '%s' and ends on '%s'.\n", GetHolidayName(), rgchDateStartBuf, rgchDateEndBuf );
|
||||
#endif // GC_DLL
|
||||
|
||||
m_timeStart = start_time;
|
||||
m_timeEnd = end_time;
|
||||
|
||||
// We're done and our interval data is cached.
|
||||
m_iCachedCalculatedYear = iYear;
|
||||
}
|
||||
|
||||
virtual bool IsActive( const CRTime& timeCurrent )
|
||||
{
|
||||
const int iCurrentYear = timeCurrent.GetYear();
|
||||
if ( m_iCachedCalculatedYear != iCurrentYear )
|
||||
RecalculateTimeActiveInterval( iCurrentYear );
|
||||
|
||||
return timeCurrent.GetRTime32() > m_timeStart
|
||||
&& timeCurrent.GetRTime32() < m_timeEnd;
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kMonday = 1;
|
||||
static const int kFriday = 5;
|
||||
|
||||
int m_iMonth;
|
||||
int m_iDay;
|
||||
int m_iExtraWeeks;
|
||||
|
||||
// Filled out from RecalculateTimeActiveInterval().
|
||||
int m_iCachedCalculatedYear;
|
||||
|
||||
RTime32 m_timeStart;
|
||||
RTime32 m_timeEnd;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A holiday that repeats on a certain time interval, like "every N days"
|
||||
// or "once every two months" or, uh, "any time there's a full moon".
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCyclicalHoliday : public IIsHolidayActive
|
||||
{
|
||||
public:
|
||||
CCyclicalHoliday( const char *pszName, int iMonth, int iDay, int iYear, float fCycleLengthInDays, float fBonusTimeInDays )
|
||||
: IIsHolidayActive( pszName )
|
||||
, m_fCycleLengthInDays( fCycleLengthInDays )
|
||||
, m_fBonusTimeInDays( fBonusTimeInDays )
|
||||
{
|
||||
// When is our initial interval?
|
||||
tm holiday_tm = { };
|
||||
holiday_tm.tm_mday = iDay;
|
||||
holiday_tm.tm_mon = iMonth - 1;
|
||||
holiday_tm.tm_year = iYear - 1900; // convert to years since 1900
|
||||
m_timeInitial = mktime( &holiday_tm );
|
||||
}
|
||||
|
||||
virtual bool IsActive( const CRTime& timeCurrent )
|
||||
{
|
||||
// Days-to-seconds conversion.
|
||||
const int iSecondsPerDay = 24 * 60 * 60;
|
||||
|
||||
// Convert our cycle/buffer times to seconds.
|
||||
const int iCycleLengthInSeconds = (int)(m_fCycleLengthInDays * iSecondsPerDay);
|
||||
const int iBufferTimeInSeconds = (int)(m_fBonusTimeInDays * iSecondsPerDay);
|
||||
|
||||
// How long has it been since we started this cycle?
|
||||
int iSecondsIntoCycle = (timeCurrent.GetRTime32() - m_timeInitial) % iCycleLengthInSeconds;
|
||||
|
||||
// If we're within the buffer period right after the start of a cycle, we're active.
|
||||
if ( iSecondsIntoCycle < iBufferTimeInSeconds )
|
||||
return true;
|
||||
|
||||
// If we're within the buffer period towards the end of a cycle, we're active.
|
||||
if ( iSecondsIntoCycle > iCycleLengthInSeconds - iBufferTimeInSeconds )
|
||||
return true;
|
||||
|
||||
// Alas, normal mode for us.
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
time_t m_timeInitial ;
|
||||
|
||||
float m_fCycleLengthInDays;
|
||||
float m_fBonusTimeInDays;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A pseudo-holiday that is active when either of its child holidays
|
||||
// is active. Works through pointers but does not manage memory.
|
||||
//-----------------------------------------------------------------------------
|
||||
class COrHoliday : public IIsHolidayActive
|
||||
{
|
||||
public:
|
||||
COrHoliday( const char *pszName, IIsHolidayActive *pA, IIsHolidayActive *pB )
|
||||
: IIsHolidayActive( pszName )
|
||||
, m_pA( pA )
|
||||
, m_pB( pB )
|
||||
{
|
||||
Assert( pA );
|
||||
Assert( pB );
|
||||
Assert( pA != pB );
|
||||
}
|
||||
|
||||
virtual bool IsActive( const CRTime& timeCurrent )
|
||||
{
|
||||
return m_pA->IsActive( timeCurrent )
|
||||
|| m_pB->IsActive( timeCurrent );
|
||||
}
|
||||
|
||||
private:
|
||||
IIsHolidayActive *m_pA;
|
||||
IIsHolidayActive *m_pB;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Holiday that is defined by a start and end date
|
||||
//-----------------------------------------------------------------------------
|
||||
class CDateBasedHoliday : public IIsHolidayActive
|
||||
{
|
||||
public:
|
||||
CDateBasedHoliday( const char *pszName, const char *pszStartTime, const char *pszEndTime )
|
||||
: IIsHolidayActive( pszName )
|
||||
{
|
||||
m_rtStartTime = CRTime::RTime32FromString( pszStartTime );
|
||||
m_rtEndTime = CRTime::RTime32FromString( pszEndTime );
|
||||
}
|
||||
|
||||
virtual bool IsActive( const CRTime& timeCurrent )
|
||||
{
|
||||
return ( ( timeCurrent >= m_rtStartTime ) && ( timeCurrent <= m_rtEndTime ) );
|
||||
}
|
||||
|
||||
RTime32 GetEndRTime() const
|
||||
{
|
||||
return m_rtEndTime.GetRTime32();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
CRTime m_rtStartTime;
|
||||
CRTime m_rtEndTime;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Holiday that is defined by a start and end date with no year specified
|
||||
//-----------------------------------------------------------------------------
|
||||
class CDateBasedHolidayNoSpecificYear : public IIsHolidayActive
|
||||
{
|
||||
public:
|
||||
CDateBasedHolidayNoSpecificYear( const char *pszName, const char *pszStartTime, const char *pszEndTime )
|
||||
: IIsHolidayActive( pszName )
|
||||
, m_pszStartTime( pszStartTime )
|
||||
, m_pszEndTime( pszEndTime )
|
||||
, m_iCachedYear( -1 )
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool IsActive( const CRTime& timeCurrent )
|
||||
{
|
||||
const int iYear = timeCurrent.GetYear();
|
||||
|
||||
if ( iYear != m_iCachedYear )
|
||||
{
|
||||
char m_szStartTime[k_RTimeRenderBufferSize];
|
||||
char m_szEndTime[k_RTimeRenderBufferSize];
|
||||
|
||||
V_sprintf_safe( m_szStartTime, "%d-%s", iYear, m_pszStartTime );
|
||||
V_sprintf_safe( m_szEndTime, "%d-%s", iYear, m_pszEndTime );
|
||||
|
||||
m_iCachedYear = iYear;
|
||||
m_rtCachedStartTime = CRTime::RTime32FromString( m_szStartTime );
|
||||
m_rtCachedEndTime = CRTime::RTime32FromString( m_szEndTime );
|
||||
}
|
||||
|
||||
return ( ( timeCurrent >= m_rtCachedStartTime ) && ( timeCurrent <= m_rtCachedEndTime ) );
|
||||
}
|
||||
|
||||
private:
|
||||
const char *m_pszStartTime;
|
||||
const char *m_pszEndTime;
|
||||
|
||||
int m_iCachedYear;
|
||||
CRTime m_rtCachedStartTime;
|
||||
CRTime m_rtCachedEndTime;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Actual holiday implementation objects.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static CNoHoliday g_Holiday_NoHoliday;
|
||||
|
||||
static CDateBasedHolidayNoSpecificYear g_Holiday_TF2Birthday ( "birthday", "08-23", "08-25" );
|
||||
|
||||
static CDateBasedHoliday g_Holiday_Halloween ( "halloween", "2016-10-19", "2016-11-18" );
|
||||
|
||||
static CDateBasedHoliday g_Holiday_Christmas ( "christmas", "2016-11-28", "2017-01-12" );
|
||||
|
||||
static CDateBasedHolidayNoSpecificYear g_Holiday_ValentinesDay ( "valentines", "02-13", "02-15" );
|
||||
|
||||
static CDateBasedHoliday g_Holiday_MeetThePyro ( "meet_the_pyro", "2012-06-26", "2012-07-05" );
|
||||
/* starting date cycle length in days bonus time in days on both sides */
|
||||
static CCyclicalHoliday g_Holiday_FullMoon ( "fullmoon", 5, 21, 2016, 29.53f, 1.0f );
|
||||
// note: the cycle length is 29.5 instead of 29.53 so that the time calculations always start at noon based on the way CCyclicalHoliday works
|
||||
static COrHoliday g_Holiday_HalloweenOrFullMoon ( "halloween_or_fullmoon", &g_Holiday_Halloween, &g_Holiday_FullMoon );
|
||||
|
||||
static COrHoliday g_Holiday_HalloweenOrFullMoonOrValentines ( "halloween_or_fullmoon_or_valentines", &g_Holiday_HalloweenOrFullMoon, &g_Holiday_ValentinesDay );
|
||||
|
||||
static CDateBasedHolidayNoSpecificYear g_Holiday_AprilFools ( "april_fools", "03-31", "04-02" );
|
||||
|
||||
static CDateBasedHoliday g_Holiday_EndOfTheLine ( "eotl_launch", "2014-12-03", "2015-01-05" );
|
||||
|
||||
static CDateBasedHoliday g_Holiday_CommunityUpdate ( "community_update", "2015-09-01", "2015-11-05" );
|
||||
|
||||
// ORDER NEEDS TO MATCH enum EHoliday
|
||||
static IIsHolidayActive *s_HolidayChecks[] =
|
||||
{
|
||||
&g_Holiday_NoHoliday, // kHoliday_None
|
||||
&g_Holiday_TF2Birthday, // kHoliday_TFBirthday
|
||||
&g_Holiday_Halloween, // kHoliday_Halloween
|
||||
&g_Holiday_Christmas, // kHoliday_Christmas
|
||||
&g_Holiday_CommunityUpdate, // kHoliday_CommunityUpdate
|
||||
&g_Holiday_EndOfTheLine, // kHoliday_EOTL
|
||||
&g_Holiday_ValentinesDay, // kHoliday_Valentines
|
||||
&g_Holiday_MeetThePyro, // kHoliday_MeetThePyro
|
||||
&g_Holiday_FullMoon, // kHoliday_FullMoon
|
||||
&g_Holiday_HalloweenOrFullMoon, // kHoliday_HalloweenOrFullMoon
|
||||
&g_Holiday_HalloweenOrFullMoonOrValentines, // kHoliday_HalloweenOrFullMoonOrValentines
|
||||
&g_Holiday_AprilFools, // kHoliday_AprilFools
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( s_HolidayChecks ) == kHolidayCount );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool EconHolidays_IsHolidayActive( int iHolidayIndex, const CRTime& timeCurrent )
|
||||
{
|
||||
if ( iHolidayIndex < 0 || iHolidayIndex >= kHolidayCount )
|
||||
return false;
|
||||
|
||||
Assert( s_HolidayChecks[iHolidayIndex] );
|
||||
if ( !s_HolidayChecks[iHolidayIndex] )
|
||||
return false;
|
||||
|
||||
return s_HolidayChecks[iHolidayIndex]->IsActive( timeCurrent );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int EconHolidays_GetHolidayForString( const char* pszHolidayName )
|
||||
{
|
||||
for ( int iHoliday = 0; iHoliday < kHolidayCount; ++iHoliday )
|
||||
{
|
||||
Assert( s_HolidayChecks[iHoliday] );
|
||||
if ( s_HolidayChecks[iHoliday] &&
|
||||
0 == Q_stricmp( pszHolidayName, s_HolidayChecks[iHoliday]->GetHolidayName() ) )
|
||||
{
|
||||
return iHoliday;
|
||||
}
|
||||
}
|
||||
|
||||
return kHoliday_None;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *EconHolidays_GetActiveHolidayString()
|
||||
{
|
||||
CRTime timeNow;
|
||||
timeNow.SetToCurrentTime();
|
||||
timeNow.SetToGMT( true );
|
||||
|
||||
for ( int iHoliday = 0; iHoliday < kHolidayCount; iHoliday++ )
|
||||
{
|
||||
if ( EconHolidays_IsHolidayActive( iHoliday, timeNow ) )
|
||||
{
|
||||
Assert( s_HolidayChecks[iHoliday] );
|
||||
return s_HolidayChecks[iHoliday]->GetHolidayName();
|
||||
}
|
||||
}
|
||||
|
||||
// No holidays currently active.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
RTime32 EconHolidays_TerribleHack_GetHalloweenEndData()
|
||||
{
|
||||
return g_Holiday_Halloween.GetEndRTime();
|
||||
}
|
||||
#endif // defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
|
||||
@@ -0,0 +1,18 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
|
||||
#ifndef ECON_HOLIDAYS_H
|
||||
#define ECON_HOLIDAYS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
bool EconHolidays_IsHolidayActive( int iHolidayIndex, const class CRTime& timeCurrent );
|
||||
int EconHolidays_GetHolidayForString( const char* pszHolidayName );
|
||||
const char *EconHolidays_GetActiveHolidayString();
|
||||
|
||||
#if defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
|
||||
RTime32 EconHolidays_TerribleHack_GetHalloweenEndData();
|
||||
#endif // defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
|
||||
|
||||
#endif // ECON_HOLIDAYS_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,864 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: CEconItem, a shared object for econ items
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECONITEM_H
|
||||
#define ECONITEM_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "gcsdk/gcclientsdk.h"
|
||||
#include "base_gcmessages.pb.h"
|
||||
|
||||
#include "econ_item_constants.h"
|
||||
#include "econ_item_interface.h"
|
||||
#include "econ_item_schema.h"
|
||||
|
||||
#include <typeinfo> // needed for typeid()
|
||||
|
||||
#define ENABLE_TYPED_ATTRIBUTE_PARANOIA 1
|
||||
|
||||
#ifdef GC_DLL
|
||||
class CSchItem;
|
||||
class CEconSharedObjectCache;
|
||||
#endif
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
class CColumnSet;
|
||||
#ifdef GC_DLL
|
||||
class CWebAPIValues;
|
||||
#endif
|
||||
};
|
||||
|
||||
class CEconItem;
|
||||
class CSOEconItem;
|
||||
class CEconItemCustomData;
|
||||
class CEconSessionItemAudit;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Stats tracking for the attributes attached to CEconItem instances.
|
||||
//-----------------------------------------------------------------------------
|
||||
struct schema_attribute_stat_bucket_t
|
||||
{
|
||||
const schema_attribute_stat_bucket_t *m_pNext;
|
||||
|
||||
const char *m_pszDesc;
|
||||
uint64 m_unLiveInlineCount;
|
||||
uint64 m_unLifetimeInlineCount;
|
||||
uint64 m_unLiveHeapCount;
|
||||
uint64 m_unLifetimeHeapCount;
|
||||
|
||||
void OnAllocateInlineInstance() { m_unLiveInlineCount++; m_unLifetimeInlineCount++; }
|
||||
void OnFreeInlineInstance() { Assert( m_unLiveInlineCount > 0 ); m_unLiveInlineCount--; }
|
||||
void OnAllocateHeapInstance() { m_unLiveHeapCount++; m_unLifetimeHeapCount++; }
|
||||
void OnFreeHeapInstance() { Assert( m_unLiveHeapCount ); m_unLiveHeapCount--; }
|
||||
};
|
||||
|
||||
class CSchemaAttributeStats
|
||||
{
|
||||
public:
|
||||
template < typename TAttribStatsStorageClass, typename TAttribInMemoryType >
|
||||
static void RegisterAttributeType()
|
||||
{
|
||||
TAttribStatsStorageClass::s_InstanceStats.m_pszDesc = typeid( TAttribInMemoryType ).name();
|
||||
TAttribStatsStorageClass::s_InstanceStats.m_pNext = m_pHead;
|
||||
|
||||
m_pHead = &TAttribStatsStorageClass::s_InstanceStats;
|
||||
}
|
||||
|
||||
static const schema_attribute_stat_bucket_t *GetFirstStatBucket()
|
||||
{
|
||||
return m_pHead;
|
||||
}
|
||||
|
||||
private:
|
||||
static const schema_attribute_stat_bucket_t *m_pHead;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Base class interface for attributes of a certain in-memory type.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int Internal_GetAttributeTypeUniqueIdentifierNextValue();
|
||||
|
||||
template < typename T >
|
||||
unsigned int GetAttributeTypeUniqueIdentifier()
|
||||
{
|
||||
static unsigned int s_unUniqueCounter = Internal_GetAttributeTypeUniqueIdentifierNextValue();
|
||||
return s_unUniqueCounter;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Base class interface for attributes of a certain in-memory type.
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename TAttribInMemoryType >
|
||||
class ISchemaAttributeTypeBase : public ISchemaAttributeType
|
||||
{
|
||||
friend class CSchemaAttributeStats;
|
||||
|
||||
public:
|
||||
ISchemaAttributeTypeBase()
|
||||
{
|
||||
CSchemaAttributeStats::RegisterAttributeType< ISchemaAttributeTypeBase<TAttribInMemoryType>, TAttribInMemoryType >();
|
||||
|
||||
// The implementation of the attributes-in-memory system is such that it may or may not behave according to
|
||||
// expectations. Rather than have to stare at all the details to answer questions about where memory is allocated
|
||||
// or managed, or when it will be freed, for all our current use cases it makes more sense to just disable raw
|
||||
// pointer types from being an attribute-in-memory type and instead steer people towards this message explaining
|
||||
// why.
|
||||
COMPILE_TIME_ASSERT( !IsPointerType<TAttribInMemoryType>::kValue );
|
||||
}
|
||||
|
||||
#ifdef GC_DLL
|
||||
// By default, without a specific type we don't support any sort of custom value generation, so all we can do
|
||||
// to load an attribute is to copy the value out from the generic format (union) and turn it into whatever our
|
||||
// type is, and then add that type to the item as an attribute.
|
||||
//
|
||||
// Unlike most of the functions in this class, this is not meant to be a catch-all default implementation but
|
||||
// is instead a base implementation. Subclasses are intended to override to add or change functionality.
|
||||
virtual void LoadOrGenerateEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount ) const OVERRIDE
|
||||
{
|
||||
Assert( pTargetItem );
|
||||
Assert( pAttrDef );
|
||||
AssertMsg( !staticAttrib.m_pKVCustomData, "Default implementation of LoadOrGenerateEconAttributeValue() doesn't support custom value generation!" );
|
||||
AssertMsg( pGameAccount || !staticAttrib.m_pKVCustomData, "Cannot run custom logic with no game account object! Passing in NULL for pGameAccount is only supported when we know we won't be running custom value generation code!" );
|
||||
|
||||
LoadEconAttributeValue( pTargetItem, pAttrDef, staticAttrib.m_value );
|
||||
}
|
||||
|
||||
// By default, we dont generate any custom value
|
||||
virtual void GenerateEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount, attribute_data_union_t* out_pValue ) const OVERRIDE
|
||||
{
|
||||
Assert( pAttrDef );
|
||||
Assert( pGameAccount );
|
||||
Assert( out_pValue );
|
||||
}
|
||||
#endif // GC_DLL
|
||||
|
||||
virtual void LoadEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const union attribute_data_union_t& value ) const OVERRIDE;
|
||||
|
||||
// Returns a unique identifier per run based on the type of <TAttribInMemoryType>.
|
||||
virtual unsigned int GetTypeUniqueIdentifier() const OVERRIDE
|
||||
{
|
||||
return GetAttributeTypeUniqueIdentifier<TAttribInMemoryType>();
|
||||
}
|
||||
|
||||
// Takes the value specified in [typedValue] and stores it in the most appropriate way
|
||||
// somewhere attached to [out_pValue]. This may hit the heap. The storage itself is
|
||||
// intended to be opaque but can be reversed by calling GetTypedValueContentsFromEconAttributeValue().
|
||||
void ConvertTypedValueToEconAttributeValue( const TAttribInMemoryType& typedValue, attribute_data_union_t *out_pValue ) const
|
||||
{
|
||||
// If our type is smaller than an int, we don't know how to copy the memory into our flat structure. We could write
|
||||
// this code but we have no use case for it now so this is set up to fail so if someone does come up with a use case
|
||||
// they know where to fix.
|
||||
COMPILE_TIME_ASSERT( sizeof( TAttribInMemoryType ) >= sizeof( uint32 ) );
|
||||
|
||||
// Do we fit in the bottom 32-bits?
|
||||
if ( sizeof( TAttribInMemoryType ) <= sizeof( uint32 ) )
|
||||
{
|
||||
*reinterpret_cast<TAttribInMemoryType *>( &out_pValue->asUint32 ) = typedValue;
|
||||
}
|
||||
// What about in the full 64-bits (if we're running a 64-bit build)?
|
||||
else if ( sizeof( TAttribInMemoryType ) <= sizeof( void * ) )
|
||||
{
|
||||
*reinterpret_cast<TAttribInMemoryType *>( &out_pValue->asBlobPointer ) = typedValue;
|
||||
}
|
||||
// We're too big for our flat structure. We need to allocate space somewhere outside our attribute instance and point
|
||||
// to that.
|
||||
else
|
||||
{
|
||||
Assert( out_pValue->asBlobPointer );
|
||||
*reinterpret_cast<TAttribInMemoryType *>( out_pValue->asBlobPointer ) = typedValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Guaranteed to return a valid reference (or assert/crash if calling code is behaving inappropriately and calling
|
||||
// this before an attribute value is allocated/set).
|
||||
const TAttribInMemoryType& GetTypedValueContentsFromEconAttributeValue( const attribute_data_union_t& value ) const
|
||||
{
|
||||
COMPILE_TIME_ASSERT( sizeof( TAttribInMemoryType ) >= sizeof( uint32 ) );
|
||||
|
||||
// Do we fit in the bottom 32-bits?
|
||||
if ( sizeof( TAttribInMemoryType ) <= sizeof( uint32 ) )
|
||||
return *reinterpret_cast<const TAttribInMemoryType *>( &value.asUint32 );
|
||||
|
||||
// What about in the full 64-bits (if we're running a 64-bit build)?
|
||||
if ( sizeof( TAttribInMemoryType ) <= sizeof( void * ) )
|
||||
return *reinterpret_cast<const TAttribInMemoryType *>( &value.asBlobPointer );
|
||||
|
||||
// We don't expect to get to a "read value" call without having written a value, which would
|
||||
// have allocated this memory.
|
||||
Assert( value.asBlobPointer );
|
||||
|
||||
return *reinterpret_cast<const TAttribInMemoryType *>( value.asBlobPointer );
|
||||
}
|
||||
|
||||
void ConvertEconAttributeValueToTypedValue( const attribute_data_union_t& value, TAttribInMemoryType *out_pTypedValue ) const
|
||||
{
|
||||
Assert( out_pTypedValue );
|
||||
|
||||
*out_pTypedValue = GetTypedValueContentsFromEconAttributeValue( value );
|
||||
}
|
||||
|
||||
void InitializeNewEconAttributeValue( attribute_data_union_t *out_pValue ) const OVERRIDE
|
||||
{
|
||||
if ( sizeof( TAttribInMemoryType ) <= sizeof( uint32 ) )
|
||||
{
|
||||
new( &out_pValue->asUint32 ) TAttribInMemoryType;
|
||||
s_InstanceStats.OnAllocateInlineInstance();
|
||||
}
|
||||
else if ( sizeof( TAttribInMemoryType ) <= sizeof( void * ) )
|
||||
{
|
||||
new( &out_pValue->asBlobPointer ) TAttribInMemoryType;
|
||||
s_InstanceStats.OnAllocateInlineInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
out_pValue->asBlobPointer = reinterpret_cast<byte *>( new TAttribInMemoryType );
|
||||
s_InstanceStats.OnAllocateHeapInstance();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UnloadEconAttributeValue( attribute_data_union_t *out_pValue ) const OVERRIDE
|
||||
{
|
||||
COMPILE_TIME_ASSERT( sizeof( TAttribInMemoryType ) >= sizeof( uint32 ) );
|
||||
|
||||
// For smaller types, anything that fits inside the bits of a void pointer, we store the contents
|
||||
// inline and only have to worry about calling the correct destructor. We check against the small-/
|
||||
// size/medium-size values separately to not worry about which bits we're storing the uint32 in.
|
||||
if ( sizeof( TAttribInMemoryType ) <= sizeof( uint32 ) )
|
||||
{
|
||||
(reinterpret_cast<TAttribInMemoryType *>( &out_pValue->asUint32 ))->~TAttribInMemoryType();
|
||||
s_InstanceStats.OnFreeInlineInstance();
|
||||
}
|
||||
else if ( sizeof( TAttribInMemoryType ) <= sizeof( void * ) )
|
||||
{
|
||||
(reinterpret_cast<TAttribInMemoryType *>( &out_pValue->asBlobPointer ))->~TAttribInMemoryType();
|
||||
s_InstanceStats.OnFreeInlineInstance();
|
||||
}
|
||||
// For larger types, we have the memory stored on the heap somewhere. We don't have to manually
|
||||
// destruct, but we do have to manually free.
|
||||
else
|
||||
{
|
||||
Assert( out_pValue->asBlobPointer );
|
||||
|
||||
delete reinterpret_cast<TAttribInMemoryType *>( out_pValue->asBlobPointer );
|
||||
s_InstanceStats.OnFreeHeapInstance();
|
||||
}
|
||||
}
|
||||
|
||||
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, GetTypedValueContentsFromEconAttributeValue( value ) );
|
||||
}
|
||||
|
||||
virtual void LoadByteStreamToEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const std::string& sBytes ) const OVERRIDE;
|
||||
virtual void ConvertEconAttributeValueToByteStream( const attribute_data_union_t& value, ::std::string *out_psBytes ) const;
|
||||
|
||||
virtual void ConvertTypedValueToByteStream( const TAttribInMemoryType& typedValue, ::std::string *out_psBytes ) const = 0;
|
||||
virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, TAttribInMemoryType *out_pTypedValue ) const = 0;
|
||||
|
||||
private:
|
||||
static schema_attribute_stat_bucket_t s_InstanceStats;
|
||||
};
|
||||
|
||||
// This function exists only to back-convert code that relies on the old untyped
|
||||
// attribute system, doing things like shoving floating-point bits into a uint32
|
||||
// value in the database.
|
||||
//
|
||||
// There is no reason to use this function moving forward! If you're writing new
|
||||
// code and calling this function seems like the only way to get the effect you
|
||||
// want, it probably just means that there is no attribute type for what you're
|
||||
// trying to do yet.
|
||||
template < typename T > uint32 WrapDeprecatedUntypedEconItemAttribute( T tValue ) { COMPILE_TIME_ASSERT( sizeof( T ) == sizeof( uint32 ) ); return *reinterpret_cast<uint32 *>( &tValue ); }
|
||||
|
||||
template < typename TAttribInMemoryType >
|
||||
schema_attribute_stat_bucket_t ISchemaAttributeTypeBase<TAttribInMemoryType>::s_InstanceStats;
|
||||
|
||||
class CEconItem : public GCSDK::CSharedObject, public CMaterialOverrideContainer< IEconItemInterface >
|
||||
{
|
||||
#ifdef GC_DLL
|
||||
DECLARE_CLASS_MEMPOOL( CEconItem );
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef GCSDK::CSharedObject BaseClass;
|
||||
|
||||
struct attribute_t
|
||||
{
|
||||
attrib_definition_index_t m_unDefinitionIndex; // stored as ints here for memory efficiency on the GC
|
||||
attribute_data_union_t m_value;
|
||||
|
||||
private:
|
||||
void operator=( const attribute_t& rhs );
|
||||
};
|
||||
|
||||
struct EquippedInstance_t
|
||||
{
|
||||
EquippedInstance_t() : m_unEquippedClass( 0 ), m_unEquippedSlot( INVALID_EQUIPPED_SLOT ) {}
|
||||
EquippedInstance_t( equipped_class_t unClass, equipped_slot_t unSlot ) : m_unEquippedClass( unClass ), m_unEquippedSlot( unSlot ) {}
|
||||
equipped_class_t m_unEquippedClass;
|
||||
equipped_slot_t m_unEquippedSlot;
|
||||
};
|
||||
|
||||
#ifdef GC_DLL
|
||||
class CAuditEntry
|
||||
{
|
||||
public:
|
||||
CAuditEntry( EItemAction eAction, uint32 unData ) : m_eAction( eAction ), m_unData( unData ) { }
|
||||
|
||||
bool BAddAuditEntryToTransaction( CSQLAccess& sqlAccess, const CEconItem *pItem ) const;
|
||||
|
||||
private:
|
||||
EItemAction m_eAction;
|
||||
uint32 m_unData;
|
||||
};
|
||||
|
||||
// Set only the top 16 bits for field ID types! These will be or'd into the index of
|
||||
// the field itself and then pulled apart later.
|
||||
enum
|
||||
{
|
||||
kUpdateFieldIDType_FieldID = 0x00000000, // this must stay as 0 for legacy code
|
||||
kUpdateFieldIDType_AttributeID = 0x00010000,
|
||||
};
|
||||
#endif // GC_DLL
|
||||
|
||||
const static int k_nTypeID = k_EEconTypeItem;
|
||||
virtual int GetTypeID() const { return k_nTypeID; }
|
||||
|
||||
CEconItem();
|
||||
CEconItem( const CEconItem& rhs );
|
||||
virtual ~CEconItem();
|
||||
|
||||
CEconItem &operator=( const CEconItem& rhs );
|
||||
|
||||
//called to determine if this item is tradable or not. This will return the time after which it can be traded. If 0 it can be traded. This is
|
||||
//needed since the base implementation of this is protected
|
||||
RTime32 GetTradableAfterDateTime() const { return IEconItemInterface::GetTradableAfterDateTime(); }
|
||||
|
||||
//called to set a tradable after date/time value onto this item (this avoids a lot of potential inefficiencies around this process)
|
||||
void SetTradableAfterDateTime( RTime32 rtTime );
|
||||
|
||||
// IEconItemInterface interface.
|
||||
const GameItemDefinition_t *GetItemDefinition() const;
|
||||
public:
|
||||
|
||||
virtual void IterateAttributes( class IEconItemAttributeIterator *pIterator ) const OVERRIDE;
|
||||
virtual itemid_t GetID() const { return GetItemID(); }
|
||||
|
||||
// Accessors/Settors
|
||||
itemid_t GetItemID() const { return m_ulID; }
|
||||
void SetItemID( uint64 ulID );
|
||||
|
||||
itemid_t GetOriginalID() const;
|
||||
void SetOriginalID( uint64 ulOriginalID );
|
||||
|
||||
uint32 GetAccountID() const { return m_unAccountID; }
|
||||
void SetAccountID( uint32 unAccountID ) { m_unAccountID = unAccountID; }
|
||||
|
||||
uint32 GetDefinitionIndex() const { return m_unDefIndex; }
|
||||
void SetDefinitionIndex( uint32 unDefinitionIndex ) { m_unDefIndex = unDefinitionIndex; }
|
||||
|
||||
uint32 GetItemLevel() const { return m_unLevel; }
|
||||
void SetItemLevel( uint32 unItemLevel ) { m_unLevel = unItemLevel; }
|
||||
|
||||
int32 GetQuality() const { return m_nQuality; }
|
||||
void SetQuality( int32 nQuality ) { m_nQuality = nQuality; }
|
||||
|
||||
uint32 GetInventoryToken() const { return m_unInventory; }
|
||||
void SetInventoryToken( uint32 unToken ) { m_unInventory = unToken; }
|
||||
|
||||
int GetQuantity() const;
|
||||
void SetQuantity( uint16 unQuantity );
|
||||
|
||||
uint8 GetFlags() const { return m_unFlags; }
|
||||
void SetFlags( uint8 unFlags ) { m_unFlags = unFlags; }
|
||||
|
||||
void SetFlag( uint8 unFlag ) { m_unFlags |= unFlag; }
|
||||
void ClearFlag( uint8 unFlag ) { m_unFlags &= ~unFlag; }
|
||||
bool CheckFlags( uint8 unFlags ) const { return ( m_unFlags & unFlags ) != 0; }
|
||||
|
||||
eEconItemOrigin GetOrigin() const { return (eEconItemOrigin)m_unOrigin; }
|
||||
void SetOrigin( eEconItemOrigin unOrigin ) { m_unOrigin = unOrigin; Assert( m_unOrigin == unOrigin ); }
|
||||
bool IsForeign() const { return m_unOrigin == kEconItemOrigin_Foreign; }
|
||||
|
||||
style_index_t GetStyle() const;
|
||||
void SetStyle( uint8 unStyle ) { m_unStyle = unStyle; DirtyIconURL(); }
|
||||
|
||||
const char *GetIconURLSmall() const;
|
||||
const char *GetIconURLLarge() const;
|
||||
|
||||
const char *GetCustomName() const;
|
||||
void SetCustomName( const char *pName );
|
||||
|
||||
const char *GetCustomDesc() const;
|
||||
void SetCustomDesc( const char *pDesc );
|
||||
|
||||
bool IsEquipped() const;
|
||||
bool IsEquippedForClass( equipped_class_t unClass ) const;
|
||||
equipped_slot_t GetEquippedPositionForClass( equipped_class_t unClass ) const;
|
||||
|
||||
void Equip( equipped_class_t unClass, equipped_slot_t unSlot );
|
||||
void Unequip();
|
||||
void UnequipFromClass( equipped_class_t unClass );
|
||||
|
||||
// This should really only used for the WebAPIs, debugging, etc. Data manipulation during gameplay should use
|
||||
// the above functions.
|
||||
int GetEquippedInstanceCount() const;
|
||||
const EquippedInstance_t &GetEquippedInstance( int iIdx ) const;
|
||||
|
||||
virtual bool GetInUse() const;
|
||||
void SetInUse( bool bInUse );
|
||||
|
||||
bool IsTradable() const;
|
||||
bool IsMarketable() const;
|
||||
bool IsCommodity() const;
|
||||
|
||||
void AdoptMoreRestrictedTradabilityFromItem( const CEconItem *pOther, uint32 nTradabilityFlagsToAccept = 0xFFFFFFFF );
|
||||
void AdoptMoreRestrictedTradability( uint32 nTradabilityFlags, RTime32 nUntradableTime );
|
||||
bool IsUsableInCrafting() const;
|
||||
|
||||
#ifdef GC_DLL
|
||||
RTime32 GetAssetInfoExpirationCacheExpirationTime() const;
|
||||
#endif // GC_DLL
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Typed attributes. These are methods for accessing and setting values of attributes with
|
||||
// some semblance of type information and type safety.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
// Assign the value of the attribute [pAttrDef] to [value]. Passing in a type for [value] that
|
||||
// doesn't match the storage type specified by the attribute definition will fail asserts a bunch
|
||||
// of asserts all the way down the stack and may or may not crash -- it would be nice to make this
|
||||
// fail asserts at compile time.
|
||||
//
|
||||
// This function has undefined results (besides asserting) if called to add a dynamic version of
|
||||
// an attrib that's already specified statically.
|
||||
template < typename T >
|
||||
void SetDynamicAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const T& value )
|
||||
{
|
||||
Assert( pAttrDef );
|
||||
|
||||
const ISchemaAttributeTypeBase<T> *pAttrType = GetTypedAttributeType<T>( pAttrDef );
|
||||
#ifdef GC_DLL
|
||||
// The GC is expected to always have internally-consistent information and so be able to access the
|
||||
// type information of any attribute if we started up successfully.
|
||||
Assert( pAttrType );
|
||||
#else
|
||||
// Game clients and servers may be running code that doesn't have all of the types for the new attributes
|
||||
// for a GC that just propped. Because we're not authoritative over items here, about the best we can do
|
||||
// here is abort entirely. This means that the client may not display certain attributes at all, or even
|
||||
// have them in the attribute list in memory, but we don't understand those attributes anyway.
|
||||
if ( !pAttrType )
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Fail right off the bat if we're trying to write a dynamic attribute value for an item that already
|
||||
// has this as a static value.
|
||||
AssertMsg4( !::FindAttribute( GetItemDefinition(), pAttrDef ),
|
||||
"Item id %llu (%s) attempting to set dynamic attribute value for '%s' (%d) when static attribute exists!",
|
||||
GetItemID(), GetItemDefinition()->GetDefinitionName(), pAttrDef->GetDefinitionName(), pAttrDef->GetDefinitionIndex() );
|
||||
|
||||
// Alright, we have a data type match so we can safely store data. Some types may need to initialize
|
||||
// their data to a current state if it's the first time we're writing to this value (as opposed to
|
||||
// updating an existing value).
|
||||
attribute_t *pEconAttrib = FindDynamicAttributeInternal( pAttrDef );
|
||||
|
||||
if ( !pEconAttrib )
|
||||
{
|
||||
pEconAttrib = &(AddDynamicAttributeInternal());
|
||||
pEconAttrib->m_unDefinitionIndex = pAttrDef->GetDefinitionIndex();
|
||||
pAttrType->InitializeNewEconAttributeValue( &pEconAttrib->m_value );
|
||||
}
|
||||
|
||||
pAttrType->ConvertTypedValueToEconAttributeValue( value, &pEconAttrib->m_value );
|
||||
|
||||
#if ENABLE_TYPED_ATTRIBUTE_PARANOIA
|
||||
// Paranoia!: make sure that our read/write functions are mirrored correctly, and that if we attempt
|
||||
// to read back a value we get something identical to what we just wrote. We do this via converting
|
||||
// to strings and then comparing those because there may or not be equality comparisons for our type
|
||||
// T that make sense (ie., protobufs).
|
||||
{
|
||||
T readValue;
|
||||
DbgVerify( FindAttribute( pAttrDef, &readValue ) );
|
||||
|
||||
std::string sBytes, sReadBytes;
|
||||
pAttrType->ConvertTypedValueToByteStream( value, &sBytes );
|
||||
pAttrType->ConvertTypedValueToByteStream( readValue, &sReadBytes );
|
||||
AssertMsg1( sBytes == sReadBytes, "SetDynamicAttributeValue(): read/write mismatch for attribute '%s'.", pAttrDef->GetDefinitionName() );
|
||||
}
|
||||
#endif // ENABLE_TYPED_ATTRIBUTE_PARANOIA
|
||||
}
|
||||
|
||||
// Called to set a time stamp dynamic attribute on this item. But it will first check the current value assigned to this item, and will
|
||||
// only set it if this new time extends beyond the current one
|
||||
void SetDynamicMaxTimeAttributeValue( const CEconItemAttributeDefinition *pAttrDef, RTime32 rtTime );
|
||||
|
||||
// Remove an instance of an attribute from this item. This will also free any dynamic memory associated
|
||||
// with that instance if any was allocated.
|
||||
void RemoveDynamicAttribute( const CEconItemAttributeDefinition *pAttrDef );
|
||||
|
||||
// Copy all attributes and values in a type-safe way from [source] to ourself. Attributes that we have
|
||||
// that don't exist on [source] will maintain their current values. All other attributes will get their
|
||||
// values set to whatever [source] specifies.
|
||||
void CopyAttributesFrom( const CEconItem& source );
|
||||
|
||||
bool BHasDynamicAttributes() const { return GetDynamicAttributeCountInternal() > 0; }
|
||||
|
||||
private:
|
||||
const char* FindIconURL( bool bLarge ) const;
|
||||
|
||||
void Init();
|
||||
|
||||
template < typename T >
|
||||
static const ISchemaAttributeTypeBase<T> *GetTypedAttributeType( const CEconItemAttributeDefinition *pAttrDef )
|
||||
{
|
||||
// Make sure the type of data we're passing in matches the type of data we're claiming that we can
|
||||
// store in the attribute definition.
|
||||
const ISchemaAttributeType *pIAttr = pAttrDef->GetAttributeType();
|
||||
Assert( pIAttr );
|
||||
Assert( pIAttr->GetTypeUniqueIdentifier() == GetAttributeTypeUniqueIdentifier<T>() );
|
||||
|
||||
#if ENABLE_TYPED_ATTRIBUTE_PARANOIA
|
||||
return dynamic_cast<const ISchemaAttributeTypeBase<T> *>( pIAttr );
|
||||
#else
|
||||
return static_cast<const ISchemaAttributeTypeBase<T> *>( pIAttr );
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
void Compact();
|
||||
|
||||
#ifdef GC
|
||||
bool BDeserializeFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors );
|
||||
#endif // GC
|
||||
|
||||
#ifdef GC_DLL
|
||||
void ExportToAPI( GCSDK::CWebAPIValues *pValues ) const;
|
||||
bool BImportFromAPI( GCSDK::CWebAPIValues *pValues );
|
||||
#endif // GC_DLL
|
||||
|
||||
// these are overridden to handle attributes
|
||||
#ifdef GC_DLL
|
||||
virtual bool BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess );
|
||||
virtual bool BYieldingAddWriteToTransaction( GCSDK::CSQLAccess & sqlAccess, const CUtlVector< int > &fields );
|
||||
virtual bool BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess & sqlAccess );
|
||||
|
||||
void SerializeToSchemaItem( CSchItem &item ) const;
|
||||
void DeserializeFromSchemaItem( const CSchItem &item );
|
||||
|
||||
void SetInteriorItem( CEconItem* pInteriorItem );
|
||||
#endif // GC_DLL
|
||||
virtual bool BParseFromMessage( const CUtlBuffer &buffer ) OVERRIDE;
|
||||
virtual bool BParseFromMessage( const std::string &buffer ) OVERRIDE;
|
||||
virtual bool BUpdateFromNetwork( const CSharedObject & objUpdate ) OVERRIDE;
|
||||
|
||||
#ifdef GC
|
||||
virtual bool BAddToMessage( CUtlBuffer & bufOutput ) const OVERRIDE;
|
||||
virtual bool BAddToMessage( std::string *pBuffer ) const OVERRIDE; // short cut to remove an extra copy
|
||||
virtual bool BAddDestroyToMessage( CUtlBuffer & bufDestroy ) const OVERRIDE;
|
||||
virtual bool BAddDestroyToMessage( std::string *pBuffer ) const OVERRIDE;
|
||||
|
||||
bool BYieldingSerializeFromDatabase( itemid_t ulItemID );
|
||||
#endif
|
||||
|
||||
virtual bool BIsKeyLess( const CSharedObject & soRHS ) const ;
|
||||
virtual void Copy( const CSharedObject & soRHS );
|
||||
virtual void Dump() const;
|
||||
virtual CUtlString GetDebugString() const OVERRIDE;
|
||||
|
||||
void SerializeToProtoBufItem( CSOEconItem &msgItem ) const;
|
||||
void DeserializeFromProtoBufItem( const CSOEconItem &msgItem );
|
||||
|
||||
#ifdef GC_DLL
|
||||
CEconItem* YieldingGetInteriorItem();
|
||||
const CEconItem* YieldingGetInteriorItem() const { return const_cast<CEconItem *>(this)->YieldingGetInteriorItem(); }
|
||||
|
||||
void SetEquippedThisGameServerSession( bool bEquipped ) { m_bEquippedThisGameServerSession = bEquipped; }
|
||||
bool EquippedThisGameServerSession() const { return m_bEquippedThisGameServerSession; }
|
||||
#endif
|
||||
|
||||
// Non-yielding -- will return current interior item if it exists and is already loaded
|
||||
// but will make no attempt to load.
|
||||
CEconItem* GetInteriorItem();
|
||||
const CEconItem* GetInteriorItem() const { return const_cast<CEconItem *>(this)->GetInteriorItem(); }
|
||||
|
||||
const CEconItemCustomData* GetCustomData() const { return m_pCustomData; }
|
||||
|
||||
void OnTraded( uint32 unTradabilityDelaySeconds );
|
||||
void OnReceivedFromMarket( bool bFromRollback );
|
||||
|
||||
protected:
|
||||
|
||||
// Call this when the appearance of this item changes (ex. paintkit, style, festive). This will
|
||||
// cause the icon to be lazily re-evaluated (ie. so that changing the style will change the icon)
|
||||
void DirtyIconURL() { m_pszLargeIcon = NULL; m_pszSmallIcon = NULL; }
|
||||
// CSharedObject
|
||||
// adapted from CSchemaSharedObject
|
||||
void GetDirtyColumnSet( const CUtlVector< int > &fields, GCSDK::CColumnSet &cs ) const;
|
||||
|
||||
void EnsureCustomDataExists();
|
||||
|
||||
bool BYieldingLoadInteriorItem();
|
||||
|
||||
void OnTransferredOwnership();
|
||||
|
||||
// Internal attribute interface.
|
||||
friend class CWebAPIStringExporterAttributeIterator;
|
||||
friend class CAttributeToStringIterator;
|
||||
|
||||
attribute_t& AddDynamicAttributeInternal(); // add another chunk of data to our internal storage to store a new attribute -- initialization is the responsibility of the caller
|
||||
attribute_t *FindDynamicAttributeInternal( const CEconItemAttributeDefinition *pAttrDef ); // search for an instance of a dynamic attribute with this definition -- ignores static properties, etc. and will return NULL if not found
|
||||
int GetDynamicAttributeCountInternal() const; // how many attributes are there attached to this instance?
|
||||
attribute_t& GetMutableDynamicAttributeInternal( int iAttrIndexIntoArray ); // get a writable version of our attribute memory base chunk (added by AddDynamicAttributeInternal) for this index (same "array" as GetDynamicAttributeCountInternal)
|
||||
const attribute_t& GetDynamicAttributeInternal( int iAttrIndexIntoArray ) const // read-only version of our attribute memory base chunk for this index (same "array" as GetDynamicAttributeCountInternal)
|
||||
{
|
||||
return const_cast<CEconItem *>( this )->GetMutableDynamicAttributeInternal( iAttrIndexIntoArray );
|
||||
}
|
||||
|
||||
const EquippedInstance_t *FindEquippedInstanceForClass( equipped_class_t nClass ) const;
|
||||
void InternalVerifyEquipInstanceIntegrity() const;
|
||||
|
||||
struct dirty_bits_t
|
||||
{
|
||||
// other
|
||||
uint8 m_bInUse : 1;
|
||||
uint8 m_bHasEquipSingleton : 1;
|
||||
uint8 m_bHasAttribSingleton: 1;
|
||||
};
|
||||
|
||||
mutable const char* m_pszSmallIcon;
|
||||
mutable const char* m_pszLargeIcon;
|
||||
public:
|
||||
// data that is most commonly changed
|
||||
uint64 m_ulID; // Item ID
|
||||
uint32 m_unAccountID; // Item Owner
|
||||
uint32 m_unInventory; // App managed int representing inventory placement
|
||||
item_definition_index_t m_unDefIndex; // Item definition index
|
||||
uint8 m_unLevel; // Item Level
|
||||
uint8 m_nQuality; // Item quality (rarity)
|
||||
uint8 m_unFlags; // Flags
|
||||
uint8 m_unOrigin; // Origin (eEconItemOrigin)
|
||||
style_index_t m_unStyle; // Style
|
||||
|
||||
dirty_bits_t m_dirtyBits; // dirty bits
|
||||
|
||||
// Fields that we often have zero or one of, but not often more
|
||||
EquippedInstance_t m_EquipInstanceSingleton; // Where the item is equipped. Valid only if m_bHasEquipSingleton and there is no custom data
|
||||
attribute_t m_CustomAttribSingleton; // Custom attribute. Valid only if m_bHasAttribSingleton and there is no custom data
|
||||
|
||||
// optional data (custom name, additional attributes, etc.)
|
||||
CEconItemCustomData *m_pCustomData;
|
||||
|
||||
#ifdef GC_DLL
|
||||
private:
|
||||
bool m_bEquippedThisGameServerSession;
|
||||
#endif // GC_DLL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Storage for data that is not commonly changed in CEconItem, primarily
|
||||
// as a memory savings mechanism.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemCustomData
|
||||
{
|
||||
public:
|
||||
CEconItemCustomData()
|
||||
: m_pInteriorItem( NULL )
|
||||
, m_ulOriginalID( INVALID_ITEM_ID )
|
||||
, m_unQuantity( 1 )
|
||||
, m_vecAttributes( /* grow size: */ 1, /* init size: */ 0 )
|
||||
, m_vecEquipped( /* grow size: */ 1, /* init size: */ 0 )
|
||||
{}
|
||||
|
||||
~CEconItemCustomData();
|
||||
|
||||
CUtlVector< CEconItem::attribute_t > m_vecAttributes;
|
||||
CEconItem* m_pInteriorItem;
|
||||
uint64 m_ulOriginalID; // Original Item ID
|
||||
uint16 m_unQuantity; // Consumable stack count (ammo, money, etc)
|
||||
|
||||
CUtlVector<CEconItem::EquippedInstance_t> m_vecEquipped;
|
||||
|
||||
static void FreeAttributeMemory( CEconItem::attribute_t *pAttrib );
|
||||
|
||||
#ifdef GC_DLL
|
||||
DECLARE_CLASS_MEMPOOL( CEconItemCustomData );
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename TAttribInMemoryType >
|
||||
/*virtual*/ void ISchemaAttributeTypeBase<TAttribInMemoryType>::LoadByteStreamToEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const std::string& sBytes ) const
|
||||
{
|
||||
Assert( pTargetItem );
|
||||
Assert( pAttrDef );
|
||||
|
||||
TAttribInMemoryType typedValue;
|
||||
ConvertByteStreamToTypedValue( sBytes, &typedValue );
|
||||
|
||||
pTargetItem->SetDynamicAttributeValue( pAttrDef, typedValue );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename TAttribInMemoryType >
|
||||
/*virtual*/ void ISchemaAttributeTypeBase<TAttribInMemoryType>::ConvertEconAttributeValueToByteStream( const attribute_data_union_t& value, ::std::string *out_psBytes ) const
|
||||
{
|
||||
ConvertTypedValueToByteStream( GetTypedValueContentsFromEconAttributeValue( value ), out_psBytes );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename TAttribInMemoryType >
|
||||
/*virtual*/ void ISchemaAttributeTypeBase<TAttribInMemoryType>::LoadEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const union attribute_data_union_t& value ) const
|
||||
{
|
||||
pTargetItem->SetDynamicAttributeValue( pAttrDef, GetTypedValueContentsFromEconAttributeValue( value ) );
|
||||
}
|
||||
|
||||
#ifdef GC_DLL
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
struct CEconItemEquipInstanceHelpers
|
||||
{
|
||||
static void AssignItemToSlot( CEconSharedObjectCache *pSOCache, CEconItem *pItem, equipped_class_t unClass, equipped_slot_t unSlot, CEconUserSession *pOptionalSession = NULL );
|
||||
};
|
||||
#endif // GC_DLL
|
||||
|
||||
void YieldingAddAuditRecord( GCSDK::CSQLAccess *sqlAccess, CEconItem *pItem, uint32 unOwnerID, EItemAction eAction, uint32 unData );
|
||||
void YieldingAddAuditRecord( GCSDK::CSQLAccess *sqlAccess, uint64 ulItemID, uint32 unOwnerID, EItemAction eAction, uint32 unData );
|
||||
bool YieldingAddItemToDatabase( CEconItem *pItem, const CSteamID & steamID, EItemAction eAction, uint32 unData );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: wrap the idea of "get a loot list from this item"; some loot lists
|
||||
// are static definitions and some are temporary heap-allocated objects
|
||||
// and this means you don't care which you're dealing with until we
|
||||
// come up with a better interface
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCrateLootListWrapper
|
||||
{
|
||||
public:
|
||||
CCrateLootListWrapper( const IEconItemInterface *pEconItem )
|
||||
: m_pLootList( NULL )
|
||||
, m_unAuditDetailData( 0 )
|
||||
, m_bIsDynamicallyAllocatedLootList( false )
|
||||
{
|
||||
Assert( pEconItem );
|
||||
|
||||
if ( !BAttemptCrateSeriesInitialization( pEconItem )
|
||||
&& !BAttemptLootListStringInitialization( pEconItem )
|
||||
&& !BAttemptLineItemInitialization( pEconItem ) )
|
||||
{
|
||||
// We don't actually have anything to do here. We'll return NULL when someone asks for our
|
||||
// loot list and we're done.
|
||||
}
|
||||
}
|
||||
|
||||
~CCrateLootListWrapper()
|
||||
{
|
||||
if ( m_bIsDynamicallyAllocatedLootList )
|
||||
{
|
||||
delete m_pLootList;
|
||||
}
|
||||
}
|
||||
|
||||
const IEconLootList *GetEconLootList() const
|
||||
{
|
||||
return m_pLootList;
|
||||
}
|
||||
|
||||
uint32 GetAuditDetailData() const
|
||||
{
|
||||
return m_unAuditDetailData;
|
||||
}
|
||||
|
||||
private:
|
||||
CCrateLootListWrapper( const CCrateLootListWrapper& ); // intentionally unimplemented
|
||||
void operator=( const CCrateLootListWrapper& ); // intentionally unimplemented
|
||||
|
||||
private:
|
||||
// Look for an attribute that specifies a crate series.
|
||||
MUST_CHECK_RETURN bool BAttemptCrateSeriesInitialization( const IEconItemInterface *pEconItem );
|
||||
|
||||
// Look for an attribute that specifies a loot list by string name.
|
||||
MUST_CHECK_RETURN bool BAttemptLootListStringInitialization( const IEconItemInterface *pEconItem );
|
||||
|
||||
// Look for a line-item-per-attribute list.
|
||||
MUST_CHECK_RETURN bool BAttemptLineItemInitialization( const IEconItemInterface *pEconItem );
|
||||
|
||||
private:
|
||||
const IEconLootList *m_pLootList;
|
||||
uint32 m_unAuditDetailData;
|
||||
bool m_bIsDynamicallyAllocatedLootList;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Maintains a handle to an CEconItem. If the item gets deleted, this
|
||||
// handle will return NULL when dereferenced
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemHandle : GCSDK::ISharedObjectListener
|
||||
{
|
||||
public:
|
||||
CEconItemHandle()
|
||||
: m_pItem( NULL )
|
||||
, m_iItemID( INVALID_ITEM_ID )
|
||||
{}
|
||||
|
||||
CEconItemHandle( CEconItem* pItem )
|
||||
: m_pItem( pItem )
|
||||
{
|
||||
SetItem( pItem );
|
||||
}
|
||||
|
||||
virtual ~CEconItemHandle();
|
||||
|
||||
void SetItem( CEconItem* pItem );
|
||||
|
||||
operator CEconItem *( void ) const
|
||||
{
|
||||
return m_pItem;
|
||||
}
|
||||
|
||||
CEconItem* operator->( void ) const
|
||||
{
|
||||
return m_pItem;
|
||||
}
|
||||
|
||||
CEconItem* operator=( CEconItem* pRhs )
|
||||
{
|
||||
SetItem( pRhs );
|
||||
return m_pItem;
|
||||
}
|
||||
|
||||
virtual void SODestroyed( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||||
|
||||
virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||||
virtual void SOCreated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||||
virtual void SOUpdated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||||
|
||||
virtual void PreSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE{}
|
||||
virtual void PostSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE{}
|
||||
virtual void SOCacheSubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE{}
|
||||
|
||||
private:
|
||||
|
||||
void UnsubscribeFromSOEvents();
|
||||
|
||||
CEconItem* m_pItem; // The item
|
||||
itemid_t m_iItemID; // The stored itemID
|
||||
CSteamID m_OwnerSteamID; // Steam ID of the item owner. Used for registering/unregistering from SOCache
|
||||
};
|
||||
|
||||
#endif // ECONITEM_H
|
||||
@@ -0,0 +1,970 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds constants for the econ item system
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *g_szQualityStrings[] =
|
||||
{
|
||||
"Normal",
|
||||
"rarity1", // Genuine
|
||||
"rarity2", // Customized
|
||||
"vintage", // Vintage has to stay at 3 for backwards compatibility
|
||||
"rarity3", // Well-Designed
|
||||
"rarity4", // Unusual
|
||||
"Unique",
|
||||
"community",
|
||||
"developer",
|
||||
"selfmade",
|
||||
"customized",
|
||||
"strange",
|
||||
"completed",
|
||||
"haunted",
|
||||
"collectors",
|
||||
"paintkitWeapon",
|
||||
|
||||
"default", // AE_RARITY_DEFAULT,
|
||||
"common", // AE_RARITY_COMMON,
|
||||
"uncommon", // AE_RARITY_UNCOMMON,
|
||||
"rare", // AE_RARITY_RARE,
|
||||
"mythical", // AE_RARITY_MYTHICAL,
|
||||
"legendary", // AE_RARITY_LEGENDARY,
|
||||
"ancient", // AE_RARITY_ANCIENT,
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szQualityStrings ) == AE_MAX_TYPES );
|
||||
|
||||
const char *EconQuality_GetQualityString( EEconItemQuality eQuality )
|
||||
{
|
||||
// This is a runtime check and not an assert because we could theoretically bounce the GC with new
|
||||
// qualities while the client is running.
|
||||
if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
|
||||
return g_szQualityStrings[ eQuality ];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EEconItemQuality EconQuality_GetQualityFromString( const char* pszQuality )
|
||||
{
|
||||
// Convert to lowercase
|
||||
CUtlString strLoweredInput( pszQuality );
|
||||
strLoweredInput.ToLower();
|
||||
|
||||
// Guaranteed with the compile time assert above that AE_MAX_TYPES is
|
||||
// the size of the string qualities
|
||||
for( int i = 0; i < AE_MAX_TYPES; ++i )
|
||||
{
|
||||
// Convert to lowercase
|
||||
CUtlString strLoweredQuality( g_szQualityStrings[i] );
|
||||
strLoweredQuality.ToLower();
|
||||
|
||||
if( !Q_stricmp( strLoweredInput.Get(), strLoweredQuality.Get() ) )
|
||||
return EEconItemQuality(i);
|
||||
}
|
||||
|
||||
return AE_UNDEFINED;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *g_szQualityColorStrings[] =
|
||||
{
|
||||
"QualityColorNormal",
|
||||
"QualityColorrarity1",
|
||||
"QualityColorrarity2",
|
||||
"QualityColorVintage",
|
||||
"QualityColorrarity3",
|
||||
"QualityColorrarity4", // AE_UNUSUAL
|
||||
"QualityColorUnique",
|
||||
"QualityColorCommunity",
|
||||
"QualityColorDeveloper",
|
||||
"QualityColorSelfMade",
|
||||
"QualityColorSelfMadeCustomized",
|
||||
"QualityColorStrange",
|
||||
"QualityColorCompleted",
|
||||
"QualityColorHaunted", // AE_HAUNTED
|
||||
"QualityColorCollectors", // AE_COLLECTORS
|
||||
"QualityColorPaintkitWeapon", // AE_PAINTKITWEAPON
|
||||
|
||||
"ItemRarityDefault" , // AE_RARITY_DEFAULT,
|
||||
"ItemRarityCommon" , // AE_RARITY_COMMON,
|
||||
"ItemRarityUncommon" , // AE_RARITY_UNCOMMON,
|
||||
"ItemRarityRare" , // AE_RARITY_RARE,
|
||||
"ItemRarityMythical" , // AE_RARITY_MYTHICAL,
|
||||
"ItemRarityLegendary" , // AE_RARITY_LEGENDARY,
|
||||
"ItemRarityAncient" , // AE_RARITY_ANCIENT,
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szQualityColorStrings ) == AE_MAX_TYPES );
|
||||
|
||||
const char *EconQuality_GetColorString( EEconItemQuality eQuality )
|
||||
{
|
||||
if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
|
||||
return g_szQualityColorStrings[ eQuality ];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *g_szQualityLocalizationStrings[] =
|
||||
{
|
||||
"#Normal",
|
||||
"#rarity1", // Genuine
|
||||
"#rarity2",
|
||||
"#vintage",
|
||||
"#rarity3", // Artisan
|
||||
"#rarity4", // Unusual
|
||||
"#unique",
|
||||
"#community",
|
||||
"#developer",
|
||||
"#selfmade",
|
||||
"#customized",
|
||||
"#strange",
|
||||
"#completed",
|
||||
"#haunted",
|
||||
"#collectors",
|
||||
"#paintkitWeapon",
|
||||
|
||||
"#Rarity_Default",
|
||||
"#Rarity_Common",
|
||||
"#Rarity_Uncommon",
|
||||
"#Rarity_Rare",
|
||||
"#Rarity_Mythical",
|
||||
"#Rarity_Legendary",
|
||||
"#Rarity_Ancient"
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szQualityLocalizationStrings ) == AE_MAX_TYPES );
|
||||
|
||||
const char *EconQuality_GetLocalizationString( EEconItemQuality eQuality )
|
||||
{
|
||||
if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
|
||||
return g_szQualityLocalizationStrings[ eQuality ];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sort order for rarities
|
||||
// Small Numbers sort to front
|
||||
//-----------------------------------------------------------------------------
|
||||
int g_nRarityScores[] =
|
||||
{
|
||||
15, // AE_NORMAL,
|
||||
10, // AE_RARITY1, // Geniune
|
||||
102, // AE_RARITY2, // Customized (unused)
|
||||
11, // AE_VINTAGE,
|
||||
101, // AE_RARITY3, // Artisan (unused)
|
||||
0, // AE_UNUSUAL,
|
||||
14, // AE_UNIQUE,
|
||||
-1, // AE_COMMUNITY,
|
||||
-3, // AE_DEVELOPER,
|
||||
-2, // AE_SELFMADE,
|
||||
100, // AE_CUSTOMIZED, // Unused
|
||||
9, // AE_STRANGE,
|
||||
103, // AE_COMPLETED, // Unused
|
||||
13, // AE_HAUNTED
|
||||
12, // AE_COLLECTORS
|
||||
8, // AE_PAINTKITWEAPON
|
||||
7, // AE_RARITY_DEFAULT,
|
||||
6, // AE_RARITY_COMMON,
|
||||
5, // AE_RARITY_UNCOMMON,
|
||||
4, // AE_RARITY_RARE,
|
||||
3, // AE_RARITY_MYTHICAL,
|
||||
2, // AE_RARITY_LEGENDARY,
|
||||
1, // AE_RARITY_ANCIENT,
|
||||
};
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( g_nRarityScores ) == AE_MAX_TYPES );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int EconQuality_GetRarityScore( EEconItemQuality eQuality )
|
||||
{
|
||||
if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
|
||||
return g_nRarityScores[ eQuality ];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *g_pchWearAmountStrings[] =
|
||||
{
|
||||
"#TFUI_InvTooltip_None",
|
||||
"#TFUI_InvTooltip_FactoryNew",
|
||||
"#TFUI_InvTooltip_MinimalWear",
|
||||
"#TFUI_InvTooltip_FieldTested",
|
||||
"#TFUI_InvTooltip_WellWorn",
|
||||
"#TFUI_InvTooltip_BattleScared"
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int EconWear_ToIntCategory( float flWear )
|
||||
{
|
||||
if ( flWear <= 0.2f )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if ( flWear <= 0.4f )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else if ( flWear <= 0.6f )
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
else if ( flWear <= 0.8f )
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
else if ( flWear <= 1.0f )
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
return 3; // default wear
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Shim to return a value for buckets. For strange we bucket all of them in to 1 non-instance data group
|
||||
int EconStrange_ToStrangeBucket( float value )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
float EconStrange_FromStrangeBucket( int value )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *GetWearLocalizationString( float flWear )
|
||||
{
|
||||
int nIndex = EconWear_ToIntCategory( flWear );
|
||||
return g_pchWearAmountStrings[ nIndex ];
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
bool EconWear_IsValidValue( int nWear )
|
||||
{
|
||||
return nWear > 0 && nWear <= 5;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CSchemaColorDefHandle g_AttribColorDefs[] =
|
||||
{
|
||||
CSchemaColorDefHandle( "desc_level" ), // ATTRIB_COL_LEVEL
|
||||
CSchemaColorDefHandle( "desc_attrib_neutral" ), // ATTRIB_COL_NEUTRAL
|
||||
CSchemaColorDefHandle( "desc_attrib_positive" ), // ATTRIB_COL_POSITIVE
|
||||
CSchemaColorDefHandle( "desc_attrib_negative" ), // ATTRIB_COL_NEGATIVE
|
||||
CSchemaColorDefHandle( "desc_itemset_name" ), // ATTRIB_COL_ITEMSET_NAME
|
||||
CSchemaColorDefHandle( "desc_itemset_equipped" ), // ATTRIB_COL_ITEMSET_EQUIPPED
|
||||
CSchemaColorDefHandle( "desc_itemset_missing" ), // ATTRIB_COL_ITEMSET_MISSING
|
||||
CSchemaColorDefHandle( "desc_bundle" ), // ATTRIB_COL_BUNDLE_ITEM
|
||||
CSchemaColorDefHandle( "desc_limited_use" ), // ATTRIB_COL_LIMITED_USE
|
||||
CSchemaColorDefHandle( "desc_flags" ), // ATTRIB_COL_component_flags
|
||||
CSchemaColorDefHandle( "desc_limited_quantity" ), // ATTRIB_COL_LIMITED_QUANTITY
|
||||
|
||||
CSchemaColorDefHandle( "desc_default" ), // ATTRIB_COL_RARITY_DEFAULT
|
||||
CSchemaColorDefHandle( "desc_common" ), // ATTRIB_COL_RARITY_COMMON
|
||||
CSchemaColorDefHandle( "desc_uncommon" ), // ATTRIB_COL_RARITY_UNCOMMON
|
||||
CSchemaColorDefHandle( "desc_rare" ), // ATTRIB_COL_RARITY_RARE
|
||||
CSchemaColorDefHandle( "desc_mythical" ), // ATTRIB_COL_RARITY_MYTHICAL
|
||||
CSchemaColorDefHandle( "desc_legendary" ), // ATTRIB_COL_RARITY_LEGENDARY
|
||||
CSchemaColorDefHandle( "desc_ancient" ), // ATTRIB_COL_RARITY_ANCIENT
|
||||
CSchemaColorDefHandle( "desc_immortal" ), // ATTRIB_COL_RARITY_IMMORTAL
|
||||
CSchemaColorDefHandle( "desc_arcana" ), // ATTRIB_COL_RARITY_ARCANA
|
||||
|
||||
CSchemaColorDefHandle( "desc_strange" ), // ATTRIB_COL_STRANGE
|
||||
CSchemaColorDefHandle( "desc_unusual" ), // ATTRIB_COL_UNUSUAL
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( g_AttribColorDefs ) == NUM_ATTRIB_COLORS );
|
||||
|
||||
attrib_colors_t GetAttribColorIndexForName( const char* pszName )
|
||||
{
|
||||
for ( int i = 0; i < NUM_ATTRIB_COLORS; ++i )
|
||||
{
|
||||
if ( !Q_strcmp( g_AttribColorDefs[i].GetName(), pszName ) )
|
||||
return (attrib_colors_t)i;
|
||||
}
|
||||
|
||||
return (attrib_colors_t)0;
|
||||
}
|
||||
|
||||
const char *GetColorNameForAttribColor( attrib_colors_t unAttribColor )
|
||||
{
|
||||
Assert( unAttribColor >= 0 );
|
||||
Assert( unAttribColor < NUM_ATTRIB_COLORS );
|
||||
|
||||
return g_AttribColorDefs[unAttribColor]
|
||||
? g_AttribColorDefs[unAttribColor]->GetColorName()
|
||||
: "ItemAttribNeutral";
|
||||
}
|
||||
|
||||
const char *GetHexColorForAttribColor( attrib_colors_t unAttribColor )
|
||||
{
|
||||
Assert( unAttribColor >= 0 );
|
||||
Assert( unAttribColor < NUM_ATTRIB_COLORS );
|
||||
|
||||
return g_AttribColorDefs[unAttribColor]
|
||||
? g_AttribColorDefs[unAttribColor]->GetHexColor()
|
||||
: "#ebe2ca";
|
||||
}
|
||||
|
||||
entityquality_t GetItemQualityFromString( const char *sQuality )
|
||||
{
|
||||
for ( int i = 0; i < AE_MAX_TYPES; i++ )
|
||||
{
|
||||
if ( !Q_strnicmp( sQuality, g_szQualityStrings[i], 16 ) )
|
||||
return (entityquality_t)i;
|
||||
}
|
||||
|
||||
return AE_NORMAL;
|
||||
}
|
||||
|
||||
const char *g_szRecipeCategoryStrings[] =
|
||||
{
|
||||
"crafting", // RECIPE_CATEGORY_CRAFTINGITEMS = 0,
|
||||
"commonitem", // RECIPE_CATEGORY_COMMONITEMS,
|
||||
"rareitem", // RECIPE_CATEGORY_RAREITEMS,
|
||||
"special", // RECIPE_CATEGORY_SPECIAL,
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szRecipeCategoryStrings ) == NUM_RECIPE_CATEGORIES );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Item acquisition.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Strings shown to the local player in the pickup dialog
|
||||
const char *g_pszItemPickupMethodStrings[] =
|
||||
{
|
||||
"#NewItemMethod_Dropped", // UNACK_ITEM_DROPPED = 1,
|
||||
"#NewItemMethod_Crafted", // UNACK_ITEM_CRAFTED,
|
||||
"#NewItemMethod_Traded", // UNACK_ITEM_TRADED,
|
||||
"#NewItemMethod_Purchased", // UNACK_ITEM_PURCHASED,
|
||||
"#NewItemMethod_FoundInCrate", // UNACK_ITEM_FOUND_IN_CRATE,
|
||||
"#NewItemMethod_Gifted", // UNACK_ITEM_GIFTED,
|
||||
"#NewItemMethod_Support", // UNACK_ITEM_SUPPORT,
|
||||
"#NewItemMethod_Promotion", // UNACK_ITEM_PROMOTION,
|
||||
"#NewItemMethod_Earned", // UNACK_ITEM_EARNED,
|
||||
"#NewItemMethod_Refunded", // UNACK_ITEM_REFUNDED,
|
||||
"#NewItemMethod_GiftWrapped", // UNACK_ITEM_GIFT_WRAPPED,
|
||||
"#NewItemMethod_Foreign", // UNACK_ITEM_FOREIGN,
|
||||
"#NewItemMethod_CollectionReward", // UNACK_ITEM_COLLECTION_REWARD
|
||||
"#NewItemMethod_PreviewItem", // UNACK_ITEM_PREVIEW_ITEM
|
||||
"#NewItemMethod_PreviewItemPurchased", // UNACK_ITEM_PREVIEW_ITEM_PURCHASED
|
||||
"#NewItemMethod_PeriodicScoreReward",// UNACK_ITEM_PERIODIC_SCORE_REWARD
|
||||
"#NewItemMethod_MvMBadgeCompletionReward",// UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD
|
||||
"#NewItemMethod_MvMSquadSurplusReward",// UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD
|
||||
"#NewItemMethod_HolidayGift", // UNACK_ITEM_FOUND_HOLIDAY_GIFT
|
||||
"#NewItemMethod_CommunityMarketPurchase", // UNACK_ITEM_COMMUNITY_MARKET_PURCHASE
|
||||
"#NewItemMethod_RecipeOutput", // UNACK_ITEM_RECIPE_OUTPUT
|
||||
NULL, // UNACK_ITEM_HIDDEN_QUEST_ITEM
|
||||
"#NewItemMethod_QuestOutput", // UNACK_ITEM_QUEST_OUTPUT
|
||||
"#NewItemMethod_QuestLoaner", // UNACK_ITEM_QUEST_LOANER
|
||||
"#NewItemMethod_TradeUp", // UNACK_ITEM_TRADE_UP
|
||||
"#NewItemMethod_QuestMerasmissionOutput", //UNACK_ITEM_QUEST_MERASMISSION_OUTPUT
|
||||
"#NewItemMethod_ViralCompetitiveBetaPassSpread", //UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD
|
||||
#ifdef ENABLE_STORE_RENTAL_BACKEND
|
||||
"#NewItemMethod_RentalPurchase", // UNACK_ITEM_RENTAL_PURCHASE
|
||||
#endif
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszItemPickupMethodStrings ) == (UNACK_NUM_METHODS - 1) ); // -1 because UNACK_ITEM_DROPPED is index 1, not 0
|
||||
|
||||
const char *g_pszItemPickupMethodStringsUnloc[] =
|
||||
{
|
||||
"dropped", // UNACK_ITEM_DROPPED = 1,
|
||||
"crafted", // UNACK_ITEM_CRAFTED,
|
||||
"traded", // UNACK_ITEM_TRADED,
|
||||
"purchased", // UNACK_ITEM_PURCHASED,
|
||||
"found_in_crate", // UNACK_ITEM_FOUND_IN_CRATE,
|
||||
"gifted", // UNACK_ITEM_GIFTED,
|
||||
"support", // UNACK_ITEM_SUPPORT,
|
||||
"promotion", // UNACK_ITEM_PROMOTION,
|
||||
"earned", // UNACK_ITEM_EARNED,
|
||||
"refunded", // UNACK_ITEM_REFUNDED,
|
||||
"gift_wrapped", // UNACK_ITEM_GIFT_WRAPPED
|
||||
"foreign", // UNACK_ITEM_FOREIGN
|
||||
"collection_reward",// UNACK_ITEM_COLLECTION_REWARD
|
||||
"preview_item", // UNACK_ITEM_PREVIEW_ITEM
|
||||
"preview_item_purchased", // UNACK_ITEM_PREVIEW_ITEM_PURCHASED
|
||||
"periodic_score_reward", // UNACK_ITEM_PERIODIC_SCORE_REWARD
|
||||
"mvm_badge_completion_reward", // UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD
|
||||
"mvm_squad_surplus_reward", // UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD
|
||||
"holiday_gift", // UNACK_ITEM_FOUND_HOLIDAY_GIFT
|
||||
"market_purchase", // UNACK_ITEM_COMMUNITY_MARKET_PURCHASE
|
||||
"recipe_output", // UNACK_ITEM_RECIPE_OUTPUT
|
||||
"hidden_quest", // UNACK_ITEM_HIDDEN_QUEST_ITEM
|
||||
"quest_output", // UNACK_ITEM_QUEST_OUTPUT
|
||||
"trade_up", // UNACK_ITEM_TRADE_UP
|
||||
"quest_output", // UNACK_ITEM_QUEST_MERASMISSION_OUTPUT
|
||||
"viral_competitive_beta_pass", //UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD
|
||||
#ifdef ENABLE_STORE_RENTAL_BACKEND
|
||||
"rental_purchase", // UNACK_ITEM_RENTAL_PURCHASE
|
||||
#endif
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszItemPickupMethodStringsUnloc ) == (UNACK_NUM_METHODS - 1) );
|
||||
|
||||
// Strings shown to other players in the chat dialog
|
||||
const char *g_pszItemFoundMethodStrings[] =
|
||||
{
|
||||
"#Item_Found", // UNACK_ITEM_DROPPED = 1,
|
||||
"#Item_Crafted", // UNACK_ITEM_CRAFTED,
|
||||
"#Item_Traded", // UNACK_ITEM_TRADED,
|
||||
NULL, // UNACK_ITEM_PURCHASED,
|
||||
"#Item_FoundInCrate", // UNACK_ITEM_FOUND_IN_CRATE,
|
||||
"#Item_Gifted", // UNACK_ITEM_GIFTED,
|
||||
NULL, // UNACK_ITEM_SUPPORT,
|
||||
NULL, // UNACK_ITEM_PROMOTION
|
||||
"#Item_Earned", // UNACK_ITEM_EARNED
|
||||
"#Item_Refunded", // UNACK_ITEM_REFUNDED
|
||||
"#Item_GiftWrapped", // UNACK_ITEM_GIFT_WRAPPED
|
||||
"#Item_Foreign", // UNACK_ITEM_FOREIGN
|
||||
"#Item_CollectionReward", // UNACK_ITEM_COLLECTION_REWARD
|
||||
"#Item_PreviewItem", // UNACK_ITEM_PREVIEW_ITEM
|
||||
"#Item_PreviewItemPurchased",// UNACK_ITEM_PREVIEW_ITEM_PURCHASED
|
||||
"#Item_PeriodicScoreReward",// UNACK_ITEM_PERIODIC_SCORE_REWARD
|
||||
"#Item_MvMBadgeCompletionReward",// UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD
|
||||
"#Item_MvMSquadSurplusReward",// UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD
|
||||
"#Item_HolidayGift", // UNACK_ITEM_FOUND_HOLIDAY_GIFT
|
||||
NULL, // UNACK_ITEM_COMMUNITY_MARKET_PURCHASE
|
||||
"#Item_RecipeOutput", // UNACK_ITEM_RECIPE_OUTPUT
|
||||
NULL, // UNACK_ITEM_HIDDEN_QUEST_ITEM
|
||||
"#Item_QuestOutput", // UNACK_ITEM_QUEST_OUTPUT
|
||||
NULL, // UNACK_ITEM_QUEST_LOANER
|
||||
"#Item_TradeUp", // UNACK_ITEM_TRADE_UP
|
||||
"#Item_QuestMerasmissionOutput", // UNACK_ITEM_QUEST_MERASMISSION_OUTPUT
|
||||
"#Item_ViralCompetitiveBetaPassSpread", //UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD
|
||||
#ifdef ENABLE_STORE_RENTAL_BACKEND
|
||||
NULL, // UNACK_ITEM_RENTAL_PURCHASE
|
||||
#endif
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszItemFoundMethodStrings ) == (UNACK_NUM_METHODS - 1) );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
struct strange_attr_set_t
|
||||
{
|
||||
strange_attr_set_t( const char *pScoreAttrName, const char *pTypeAttrName, const char *pRestrictionAttrName, const char *pRestrictionValueAttrName, bool bIsUserCustomizable )
|
||||
: m_attrScore( pScoreAttrName )
|
||||
, m_attrType( pTypeAttrName )
|
||||
, m_attrRestriction( pRestrictionAttrName )
|
||||
, m_attrRestrictionValue( pRestrictionValueAttrName )
|
||||
, m_bIsUserCustomizable( bIsUserCustomizable )
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
CSchemaAttributeDefHandle m_attrScore;
|
||||
CSchemaAttributeDefHandle m_attrType;
|
||||
CSchemaAttributeDefHandle m_attrRestriction;
|
||||
CSchemaAttributeDefHandle m_attrRestrictionValue;
|
||||
bool m_bIsUserCustomizable;
|
||||
};
|
||||
|
||||
strange_attr_set_t g_KillEaterAttr[] =
|
||||
{
|
||||
strange_attr_set_t( "kill eater", "kill eater score type", "strange restriction type 1", "strange restriction value 1", false ),
|
||||
strange_attr_set_t( "kill eater 2", "kill eater score type 2", "strange restriction type 2", "strange restriction value 2", false ),
|
||||
strange_attr_set_t( "kill eater 3", "kill eater score type 3", "strange restriction type 3", "strange restriction value 3", false ),
|
||||
|
||||
// assumption: all of the user-customizable attributes will follow all of the schema-specified attributes
|
||||
strange_attr_set_t( "kill eater user 1", "kill eater user score type 1", "strange restriction user type 1", "strange restriction user value 1", true ),
|
||||
strange_attr_set_t( "kill eater user 2", "kill eater user score type 2", "strange restriction user type 2", "strange restriction user value 2", true ),
|
||||
strange_attr_set_t( "kill eater user 3", "kill eater user score type 3", "strange restriction user type 3", "strange restriction user value 3", true ),
|
||||
};
|
||||
|
||||
int GetKillEaterAttrCount()
|
||||
{
|
||||
#ifdef DBGFLAG_ASSERT
|
||||
// Verify our commented assumption that all of the non-user-customizable attributes will be followed by
|
||||
// all of the user-customizable attributes.
|
||||
bool bInUserCustomizableBlock = false;
|
||||
|
||||
for ( int i = 0; i < ARRAYSIZE( g_KillEaterAttr ); i++ )
|
||||
{
|
||||
if ( bInUserCustomizableBlock )
|
||||
{
|
||||
AssertMsg( g_KillEaterAttr[i].m_bIsUserCustomizable, "Ordering assumption for g_KillEaterAttr violated! User-customizable attributes should all be at the end of the list!" );
|
||||
}
|
||||
|
||||
bInUserCustomizableBlock |= g_KillEaterAttr[i].m_bIsUserCustomizable;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ARRAYSIZE( g_KillEaterAttr );
|
||||
}
|
||||
|
||||
int GetKillEaterAttrCount_UserCustomizable()
|
||||
{
|
||||
int iCount = 0;
|
||||
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
|
||||
{
|
||||
if ( GetKillEaterAttr_IsUserCustomizable( i ) )
|
||||
{
|
||||
iCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return iCount;
|
||||
}
|
||||
|
||||
const CEconItemAttributeDefinition *GetKillEaterAttr_Score( int i )
|
||||
{
|
||||
Assert( i >= 0 );
|
||||
Assert( i < GetKillEaterAttrCount() );
|
||||
|
||||
const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrScore;
|
||||
AssertMsg1( pAttrRes, "Missing Killeater attr score %s", g_KillEaterAttr[ i ].m_attrScore.GetName() );
|
||||
|
||||
return pAttrRes;
|
||||
}
|
||||
|
||||
const CEconItemAttributeDefinition *GetKillEaterAttr_Type( int i )
|
||||
{
|
||||
Assert( i >= 0 );
|
||||
Assert( i < GetKillEaterAttrCount() );
|
||||
|
||||
const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrType;
|
||||
AssertMsg1( pAttrRes, "Missing Killeater attr type %s", g_KillEaterAttr[ i ].m_attrType.GetName() );
|
||||
|
||||
return pAttrRes;
|
||||
}
|
||||
|
||||
const CEconItemAttributeDefinition *GetKillEaterAttr_Restriction( int i )
|
||||
{
|
||||
Assert( i >= 0 );
|
||||
Assert( i < GetKillEaterAttrCount() );
|
||||
|
||||
const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrRestriction;
|
||||
AssertMsg1( pAttrRes, "Missing Killeater attr restriction %s", g_KillEaterAttr[ i ].m_attrRestriction.GetName() );
|
||||
|
||||
return pAttrRes;
|
||||
}
|
||||
|
||||
const CEconItemAttributeDefinition *GetKillEaterAttr_RestrictionValue( int i )
|
||||
{
|
||||
Assert( i >= 0 );
|
||||
Assert( i < GetKillEaterAttrCount() );
|
||||
|
||||
const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrRestrictionValue;
|
||||
AssertMsg1( pAttrRes, "Missing Killeater attr restriction value %s", g_KillEaterAttr[ i ].m_attrRestrictionValue.GetName() );
|
||||
|
||||
return pAttrRes;
|
||||
}
|
||||
|
||||
bool GetKillEaterAttr_IsUserCustomizable( int i )
|
||||
{
|
||||
Assert( i >= 0 );
|
||||
Assert( i < GetKillEaterAttrCount() );
|
||||
|
||||
return g_KillEaterAttr[i].m_bIsUserCustomizable;
|
||||
}
|
||||
|
||||
|
||||
bool GetKilleaterValueByEvent( const IEconItemInterface* pItem, const kill_eater_event_t& EEventType, uint32& value )
|
||||
{
|
||||
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
|
||||
{
|
||||
const CEconItemAttributeDefinition *pAttribKillEater = GetKillEaterAttr_Score( i );
|
||||
const CEconItemAttributeDefinition *pAttribKillEaterScoreType = GetKillEaterAttr_Type( i );
|
||||
|
||||
Assert( pAttribKillEater && pAttribKillEaterScoreType );
|
||||
if ( !pAttribKillEater || !pAttribKillEaterScoreType )
|
||||
return false;
|
||||
|
||||
// make sure this item even has a kill count attribute we're looking for
|
||||
uint32 unKillEaterAttrValue;
|
||||
if ( !pItem->FindAttribute( pAttribKillEater, &unKillEaterAttrValue ) )
|
||||
continue;
|
||||
|
||||
uint32 unKillEaterScoreTypeAttrValue = kKillEaterEvent_PlayerKill;
|
||||
|
||||
float fKillEaterScoreTypeAttrValue;
|
||||
if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttribKillEaterScoreType, &fKillEaterScoreTypeAttrValue ) )
|
||||
{
|
||||
unKillEaterScoreTypeAttrValue = (uint32)fKillEaterScoreTypeAttrValue;
|
||||
}
|
||||
|
||||
// this isn't the attribute we're trying to find
|
||||
if ( EEventType != (kill_eater_event_t)unKillEaterScoreTypeAttrValue )
|
||||
continue;
|
||||
|
||||
value = unKillEaterAttrValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Does this thing have kill eater
|
||||
bool BIsItemStrange( const IEconItemInterface *pItem )
|
||||
{
|
||||
// Go over the attributes of the item, if it has any strange attributes the item is strange and don't apply
|
||||
uint32 unKillEaterAttr;
|
||||
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
|
||||
{
|
||||
if ( pItem->FindAttribute( GetKillEaterAttr_Score( i ), &unKillEaterAttr ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get a localization token that describes why an item is not usable
|
||||
// in the trade-up crafting. Returns NULL if no reason. Can pass in
|
||||
// another item to compare against, which causes extra consistency checks
|
||||
//-----------------------------------------------------------------------------
|
||||
const char* GetCollectionCraftingInvalidReason( const IEconItemInterface *pTestItem, const IEconItemInterface *pSourceItem )
|
||||
{
|
||||
if ( !pTestItem )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoItem";
|
||||
}
|
||||
|
||||
// Needs to have a collection
|
||||
const CEconItemCollectionDefinition* pTestCollection = pTestItem->GetItemDefinition()->GetItemCollectionDefinition();
|
||||
if ( !pTestCollection )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoCollection";
|
||||
}
|
||||
|
||||
// Make sure this item is a part of the collection it claims to be in
|
||||
{
|
||||
item_definition_index_t nThisDefIndex = pTestItem->GetItemDefIndex();
|
||||
bool bFound = false;
|
||||
for( int i=0; i < pTestCollection->m_iItemDefs.Count() && !bFound; ++i )
|
||||
{
|
||||
bFound |= pTestCollection->m_iItemDefs[i] == nThisDefIndex;
|
||||
}
|
||||
|
||||
if ( !bFound )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoCollection";
|
||||
}
|
||||
}
|
||||
|
||||
// Needs rarity
|
||||
uint8 nRarity = pTestItem->GetItemDefinition()->GetRarity();
|
||||
if( nRarity == k_unItemRarity_Any )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoRarity";
|
||||
}
|
||||
|
||||
// Can't use items with rarity at the "top" of a collection (what would they craft into?)
|
||||
if ( nRarity == pTestCollection->GetMaxRarity() )
|
||||
{
|
||||
return "#TF_CollectionCrafting_MaxRarity";
|
||||
}
|
||||
|
||||
// No self mades or community items
|
||||
uint32 eQuality = pTestItem->GetQuality();
|
||||
if ( eQuality == AE_SELFMADE || eQuality == AE_COMMUNITY )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoUnusual";
|
||||
}
|
||||
|
||||
// This is how we test for unusuals. Don't let unusuals be crafted
|
||||
static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
|
||||
if ( pTestItem->FindAttribute( pAttrDef_ParticleEffect ) )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoUnusual";
|
||||
}
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
|
||||
if ( pTestItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoUnusual";
|
||||
}
|
||||
|
||||
// Not allowed to be crafted?
|
||||
if ( !pTestItem->IsUsableInCrafting() )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NotCraftable";
|
||||
}
|
||||
|
||||
// If another item was passed in, we have a few consistency checks to make
|
||||
if ( pSourceItem )
|
||||
{
|
||||
// Need to have the same rarity
|
||||
if ( nRarity != pSourceItem->GetItemDefinition()->GetRarity() )
|
||||
{
|
||||
return "#TF_CollectionCrafting_MismatchRarity";
|
||||
}
|
||||
|
||||
// Need to have the same strangeness
|
||||
if ( BIsItemStrange( pSourceItem ) != BIsItemStrange( pTestItem ) )
|
||||
{
|
||||
return "#TF_CollectionCrafting_MismatchStrange";
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get a localization token that describes why an item is not usable
|
||||
// in the Halloween Offering. Returns NULL if no reason. Can pass in
|
||||
// another item to compare against, which causes extra consistency checks
|
||||
//-----------------------------------------------------------------------------
|
||||
const char* GetHalloweenOfferingInvalidReason( const IEconItemInterface *pTestItem, const IEconItemInterface *pSourceItem )
|
||||
{
|
||||
// Must either be a Cosmetic
|
||||
// Taunt
|
||||
// Allowable Tool (Strange part, Paint, name tag, killstreak). Not crates, keys
|
||||
// Marketable Weapon ie Strange, Genuine, Vintage, paintkit
|
||||
|
||||
// Cannot be Unusual
|
||||
|
||||
if ( !pTestItem )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoItem";
|
||||
}
|
||||
|
||||
// No self mades or community items
|
||||
uint32 eQuality = pTestItem->GetQuality();
|
||||
if ( eQuality == AE_SELFMADE || eQuality == AE_COMMUNITY )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoUnusual";
|
||||
}
|
||||
|
||||
// This is how we test for unusuals. Don't let unusuals be crafted
|
||||
static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
|
||||
if ( pTestItem->FindAttribute( pAttrDef_ParticleEffect ) )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoUnusual";
|
||||
}
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
|
||||
if ( pTestItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoUnusual";
|
||||
}
|
||||
|
||||
// Invalid Items
|
||||
static CSchemaAttributeDefHandle pAttrDef_CannotTransmute( "cannot_transmute" );
|
||||
if ( pTestItem->FindAttribute( pAttrDef_CannotTransmute ) )
|
||||
{
|
||||
return "#TF_HalloweenOffering_Invalid";
|
||||
}
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_CannotDelete( "cannot delete" );
|
||||
if ( pTestItem->FindAttribute( pAttrDef_CannotDelete ) )
|
||||
{
|
||||
return "#TF_HalloweenOffering_Invalid";
|
||||
}
|
||||
|
||||
const CEconItemDefinition *pItemDef = pTestItem->GetItemDefinition();
|
||||
if ( pItemDef == NULL )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoItem";
|
||||
}
|
||||
|
||||
if ( pTestItem->IsTemporaryItem() )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoItem";
|
||||
}
|
||||
|
||||
// If you are a taunt or a cosmetic you are allowed
|
||||
if ( pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MISC || pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_TAUNT )
|
||||
{
|
||||
// do not 'medal' equip region items
|
||||
if ( pTestItem->GetItemDefinition()->GetEquipRegionMask() & GetItemSchema()->GetEquipRegionBitMaskByName( "medal" ) )
|
||||
{
|
||||
return "#TF_HalloweenOffering_Invalid";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Do not allow Crates
|
||||
if ( ( pItemDef->GetCapabilities() & ITEM_CAP_DECODABLE ) != 0 )
|
||||
{
|
||||
return "#TF_HalloweenOffering_Invalid";
|
||||
}
|
||||
|
||||
// Cause of weird legacy items lets be explicit about what we allow
|
||||
if ( pItemDef->IsTool() )
|
||||
{
|
||||
// ignore everything that is not a paint can tool
|
||||
const IEconTool *pEconTool = pItemDef->GetEconTool();
|
||||
if ( !pEconTool )
|
||||
return "#TF_HalloweenOffering_Invalid";
|
||||
|
||||
const char *pToolType = pEconTool->GetTypeName();
|
||||
|
||||
if ( !V_strcmp( pToolType, "paint_can" ) )
|
||||
return NULL;
|
||||
else if ( !V_strcmp( pToolType, "strange_part" ) )
|
||||
return NULL;
|
||||
else if ( !V_strcmp( pToolType, "name" ) )
|
||||
return NULL;
|
||||
else if ( !V_strcmp( pToolType, "desc" ) )
|
||||
return NULL;
|
||||
else if ( !V_strcmp( pToolType, "killstreakifier" ) )
|
||||
return NULL;
|
||||
else if ( !V_strcmp( pToolType, "strangifier" ) )
|
||||
return NULL;
|
||||
|
||||
// Not a tool we are allowing
|
||||
return "#TF_HalloweenOffering_Invalid";
|
||||
}
|
||||
|
||||
// Otherwise you must be a weapon or we won't allow
|
||||
if ( pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_PRIMARY
|
||||
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_SECONDARY
|
||||
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MELEE
|
||||
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_BUILDING
|
||||
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_PDA
|
||||
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_PDA2
|
||||
) {
|
||||
// Must be strange, genuine, vintage, haunted or paintkit (ie a marketable weapon)
|
||||
eQuality = pTestItem->GetQuality();
|
||||
if ( eQuality == AE_RARITY1
|
||||
|| eQuality == AE_VINTAGE
|
||||
|| eQuality == AE_HAUNTED
|
||||
|| eQuality == AE_COLLECTORS
|
||||
|| eQuality == AE_PAINTKITWEAPON
|
||||
) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Weapons with rarity are allowed
|
||||
uint8 nRarity = pTestItem->GetItemDefinition()->GetRarity();
|
||||
if ( nRarity != k_unItemRarity_Any )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Strange items. Dont just check for strange quality, actually check for a strange attribute.
|
||||
// See if we've got any strange attributes.
|
||||
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
|
||||
{
|
||||
if ( pTestItem->FindAttribute( GetKillEaterAttr_Score( i ) ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "#TF_HalloweenOffering_Invalid";
|
||||
}
|
||||
|
||||
const char* GetCraftCommonStatClockInvalidReason( const class IEconItemInterface *pTestItem, const class IEconItemInterface *pSourceItem )
|
||||
{
|
||||
if ( !pTestItem )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NoItem";
|
||||
}
|
||||
|
||||
// Not allowed to be crafted?
|
||||
if ( !pTestItem->IsUsableInCrafting() )
|
||||
{
|
||||
return "#TF_CollectionCrafting_NotCraftable";
|
||||
}
|
||||
|
||||
// No self mades or community items
|
||||
uint32 eQuality = pTestItem->GetQuality();
|
||||
if ( eQuality == AE_SELFMADE || eQuality == AE_COMMUNITY )
|
||||
return "#TF_CollectionCrafting_NoUnusual";
|
||||
|
||||
// This is how we test for unusuals. Don't let unusuals be crafted
|
||||
static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
|
||||
if ( pTestItem->FindAttribute( pAttrDef_ParticleEffect ) )
|
||||
return "#TF_CollectionCrafting_NoUnusual";
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
|
||||
if ( pTestItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
|
||||
return "#TF_CollectionCrafting_NoUnusual";
|
||||
|
||||
const CEconItemDefinition *pItemDef = pTestItem->GetItemDefinition();
|
||||
if ( pItemDef == NULL )
|
||||
return "#TF_CollectionCrafting_NoItem";
|
||||
|
||||
if ( pTestItem->IsTemporaryItem() )
|
||||
return "#TF_CollectionCrafting_NoItem";
|
||||
|
||||
// Strange items. Dont just check for strange quality, actually check for a strange attribute.
|
||||
// See if we've got any strange attributes.
|
||||
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
|
||||
{
|
||||
if ( pTestItem->FindAttribute( GetKillEaterAttr_Score( i ) ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Needs Rarity
|
||||
uint8 nRarity = pTestItem->GetItemDefinition()->GetRarity();
|
||||
if ( nRarity != k_unItemRarity_Any && nRarity > 1 ) // do not allow default nor common rarity
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "#TF_MannCoTrade_ItemInvalid";
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
enum { kMaxCardUpgradesPerItem = 2 };
|
||||
|
||||
int GetMaxCardUpgradesPerItem()
|
||||
{
|
||||
return kMaxCardUpgradesPerItem;
|
||||
}
|
||||
|
||||
const CEconItemAttributeDefinition *GetCardUpgradeForIndex( const IEconItemInterface *pItem, int i )
|
||||
{
|
||||
Assert( pItem );
|
||||
Assert( i >= 0 );
|
||||
Assert( i < kMaxCardUpgradesPerItem );
|
||||
|
||||
class CGetNthUserGeneratedAttributeIterator : public IEconItemUntypedAttributeIterator
|
||||
{
|
||||
public:
|
||||
CGetNthUserGeneratedAttributeIterator( int iTargetIndex )
|
||||
: m_iCount( iTargetIndex )
|
||||
, m_pAttrDef( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValueUntyped( const CEconItemAttributeDefinition *pAttrDef ) OVERRIDE
|
||||
{
|
||||
if ( pAttrDef->GetUserGenerationType() != 0 && m_iCount-- == 0 )
|
||||
{
|
||||
m_pAttrDef = pAttrDef;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const CEconItemAttributeDefinition *GetAttrDef() const { return m_pAttrDef; }
|
||||
|
||||
private:
|
||||
int m_iCount;
|
||||
const CEconItemAttributeDefinition *m_pAttrDef;
|
||||
};
|
||||
|
||||
CGetNthUserGeneratedAttributeIterator findNthAttrIterator( i );
|
||||
pItem->IterateAttributes( &findNthAttrIterator );
|
||||
|
||||
return findNthAttrIterator.GetAttrDef();
|
||||
}
|
||||
@@ -0,0 +1,965 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ACTUAL_ECON_ITEM_CONSTANTS_H // ECON_ITEM_CONSTANTS_H is used by src/common/econ_item_view.h
|
||||
#define ACTUAL_ECON_ITEM_CONSTANTS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// To avoid #include dependency chains, this file should
|
||||
// contain only constants that do not depend on other
|
||||
// header files.
|
||||
// This file is #included in cbase.h to allow schema compiles
|
||||
// to use these constants to ensure correlation between
|
||||
// code data structures and database entries
|
||||
//=============================================================================
|
||||
|
||||
typedef uint32 item_price_t; // this is the type that is used to hold currency values for transactions! don't change this without changing the relevant code/databases/etc.
|
||||
typedef uint8 item_transaction_quantity_t;
|
||||
|
||||
class CLocalizationProvider;
|
||||
|
||||
enum { kLocalizedPriceSizeInChararacters = 64 };
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Econ Item testing
|
||||
//-----------------------------------------------------------------------------
|
||||
enum testitem_itemtypes_t
|
||||
{
|
||||
TI_TYPE_UNKNOWN = -1,
|
||||
|
||||
TI_TYPE_WEAPON = 0,
|
||||
TI_TYPE_HEADGEAR,
|
||||
TI_TYPE_MISC1,
|
||||
TI_TYPE_MISC2,
|
||||
|
||||
TI_TYPE_COUNT,
|
||||
};
|
||||
#define TESTITEM_DEFINITIONS_BEGIN_AT 40000
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Type IDs for economy classes. These are part of the client-GC protocol and
|
||||
// should not change if it can be helped
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EEconTypeID
|
||||
{
|
||||
k_EEconTypeItem =1,
|
||||
k_EEconTypePlayerInfo =2,
|
||||
k_EEconTypeClaimCode =3,
|
||||
k_EEconTypeRecipe =5,
|
||||
k_EEconTypeGameAccountClient =7,
|
||||
k_EEconTypeGameAccount =8,
|
||||
k_EEconTypeDuelSummary =19,
|
||||
k_EEconTypeExperiment =20,
|
||||
k_EEconTypeMapContribution =28,
|
||||
k_EEconTypeGameServerAccount =29,
|
||||
k_EEconTypeCoachRating =30,
|
||||
// k_EEconTypeEquipInstance =31, // DEPRECATED
|
||||
k_EEconTypeSelectedItemPreset =35,
|
||||
k_EEconTypeItemPresetInstance =36,
|
||||
k_EEconTypeGameAccountForGameServers =37,
|
||||
k_EEConTypeWarData =38,
|
||||
k_EEConTypeLadderData =39,
|
||||
k_EEConTypeMatchResultPlayerInfo =40,
|
||||
k_EEconTypeXPSource =41,
|
||||
k_EEconTypeNotification =42,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Actions for the ItemAudit table
|
||||
//-----------------------------------------------------------------------------
|
||||
// WARNING!!! Values stored in DB. Do not renumber!
|
||||
enum EItemAction
|
||||
{
|
||||
k_EItemActionInvalid = -1,
|
||||
k_EItemActionGSCreate = 0,
|
||||
k_EItemActionUnpurchase = 1,
|
||||
k_EItemActionDelete = 2,
|
||||
k_EItemActionAwardAchievement = 3,
|
||||
k_EItemActionBanned = 4,
|
||||
k_EItemActionQuantityChanged = 5,
|
||||
k_EItemActionRestored = 6,
|
||||
k_EItemActionAwardTime = 7,
|
||||
k_EItemActionManualCreate = 8,
|
||||
k_EItemActionDrop = 9,
|
||||
k_EItemActionPickUp = 10,
|
||||
k_EItemActionCraftDestroy = 11,
|
||||
k_EItemActionCraftCreate = 12,
|
||||
k_EItemActionLimitExceeded = 13,
|
||||
k_EItemActionPurchase = 14,
|
||||
k_EItemActionNameChanged_Add = 15,
|
||||
k_EItemActionUnlockCrate_Add = 16,
|
||||
k_EItemActionPaintItem_Add = 17,
|
||||
k_EItemActionAutoGrantItem = 18,
|
||||
k_EItemActionCrossGameAchievement = 19,
|
||||
k_EItemActionAddItemToSocket_Add = 20,
|
||||
k_EItemActionAddSocketToItem_Add = 21,
|
||||
k_EItemActionRemoveSocketItem_Add = 22,
|
||||
k_EItemActionCustomizeItemTexture_Add = 23,
|
||||
k_EItemActionItemTraded_Add = 24,
|
||||
k_EItemActionUseItem = 25,
|
||||
k_EItemActionAwardGift_Receiver = 26,
|
||||
k_EItemActionNameChanged_Remove = 27,
|
||||
k_EItemActionUnlockCrate_Remove = 28,
|
||||
k_EItemActionPaintItem_Remove = 29,
|
||||
k_EItemActionAddItemToSocket_Remove = 30,
|
||||
k_EItemActionAddSocketToItem_Remove = 31,
|
||||
k_EItemActionRemoveSocketItem_Remove = 32,
|
||||
k_EItemActionCustomizeItemTexture_Remove = 33,
|
||||
k_EItemActionItemTraded_Remove = 34,
|
||||
k_EItemActionUnpackItemBundle = 35,
|
||||
k_EItemActionCreateItemFromBundle = 36,
|
||||
k_EItemActionAwardStorePromotionItem = 37,
|
||||
k_EItemActionConvertItem = 38,
|
||||
k_EItemActionEarnedItem = 39,
|
||||
k_EItemActionAwardGift_Giver = 40,
|
||||
k_EItemActionRefundedItem = 41,
|
||||
k_EItemActionAwardThirdPartyPromo = 42,
|
||||
k_EItemActionRemoveItemName_Remove = 43,
|
||||
k_EItemActionRemoveItemName_Add = 44,
|
||||
k_EItemActionRemoveItemPaint_Remove = 45,
|
||||
k_EItemActionRemoveItemPaint_Add = 46,
|
||||
k_EItemActionHalloweenDrop = 47,
|
||||
k_EItemActionSteamWorkshopContributor = 48,
|
||||
k_EItemActionManualOwnershipChange = 49, // when we have bad bugs that corrupt item data and have to fix up rows in the DB by hand
|
||||
k_EItemActionSupportDelete = 50,
|
||||
k_EItemActionSupportCreatedByUndo = 51,
|
||||
k_EItemActionSupportDeletedByUndo = 52,
|
||||
k_EItemActionSupportQuantityChangedByUndo = 53,
|
||||
k_EItemActionSupportRename_Add = 54,
|
||||
k_EItemActionSupportRename_Remove = 55,
|
||||
k_EItemActionSupportDescribe_Add = 56,
|
||||
k_EItemActionSupportDescribe_Remove = 57,
|
||||
|
||||
k_EItemActionStrangePartApply_Add = 58,
|
||||
k_EItemActionStrangePartApply_Remove = 59,
|
||||
k_EItemActionStrangeScoreReset_Add = 60,
|
||||
k_EItemActionStrangeScoreReset_Remove = 61,
|
||||
k_EItemActionStrangePartRemove_Add = 62,
|
||||
k_EItemActionStrangePartRemove_Remove = 63,
|
||||
|
||||
k_EItemActionSupportStrangify_Add = 64,
|
||||
k_EItemActionSupportStrangify_Remove = 65,
|
||||
|
||||
k_EItemActionUpgradeCardApply_Add = 66,
|
||||
k_EItemActionUpgradeCardApply_Remove = 67,
|
||||
k_EItemActionUpgradeCardRemove_Add = 68,
|
||||
k_EItemActionUpgradeCardRemove_Remove = 69,
|
||||
|
||||
k_EItemActionStrangeRestrictionApply_Add = 70,
|
||||
k_EItemActionStrangeRestrictionApply_Remove = 71,
|
||||
k_EItemActionTransmogrify_Add = 72,
|
||||
k_EItemActionTransmogrify_Remove = 73,
|
||||
k_EItemActionHalloweenSpellPageAdd_Add = 74,
|
||||
k_EItemActionHalloweenSpellPageAdd_Remove = 75,
|
||||
|
||||
k_EItemActionDev_ClientLootListRoll = 90,
|
||||
|
||||
k_EItemActionGiftWrap_Add = 100,
|
||||
k_EItemActionGiftWrap_Remove = 101,
|
||||
k_EItemActionGiftDelivery_Add = 102,
|
||||
k_EItemActionGiftDelivery_Remove = 103,
|
||||
k_EItemActionGiftUnwrap_Add = 104,
|
||||
k_EItemActionGiftUnwrap_Remove = 105,
|
||||
k_EItemActionPackageItem = 106,
|
||||
k_EItemActionPackageItem_Revoked = 107,
|
||||
k_EItemActionHandleMapToken = 108,
|
||||
k_EItemActionCafeOrSchoolItem_Remove = 109,
|
||||
k_EItemActionVACBanned_Remove = 110,
|
||||
k_EItemActionUpgradeThirdPartyPromo = 111,
|
||||
k_EItemActionExpired = 112,
|
||||
k_EItemActionTradeRollback_Add = 113,
|
||||
k_EItemActionTradeRollback_Remove = 114,
|
||||
k_EItemActionCDKeyGrant = 115,
|
||||
k_EItemActionCDKeyRevoke = 116,
|
||||
k_EItemActionWeddingRing_Add = 117,
|
||||
k_EItemActionWeddingRing_Remove = 118,
|
||||
k_EItemActionWeddingRing_AddPartner = 119,
|
||||
k_EItemActionEconSetUnowned = 120,
|
||||
k_EItemActionEconSetOwned = 121,
|
||||
k_EItemActionStrangifyItem_Add = 122,
|
||||
k_EItemActionStrangifyItem_Remove = 123,
|
||||
k_EItemActionConsumeItem_Consume_ToolRemove = 124,
|
||||
k_EItemActionConsumeItem_Consume_ToolAdd = 125,
|
||||
k_EItemActionConsumeItem_Consume_InputRemove = 126,
|
||||
k_EItemActionConsumeItem_Complete_OutputAdd = 127,
|
||||
k_EItemActionConsumeItem_Complete_ToolRemove = 128,
|
||||
k_EItemActionItemEaterRecharge_Add = 129,
|
||||
k_EItemActionItemEaterRecharge_Remove = 130,
|
||||
|
||||
k_EItemActionRemoveItemCraftIndex_Remove = 150,
|
||||
k_EItemActionRemoveItemCraftIndex_Add = 151,
|
||||
k_EItemActionRemoveItemMakersMark_Remove = 152, // early versions of this will be in the database as 150
|
||||
k_EItemActionRemoveItemMakersMark_Add = 153, // early versions of this will be in the database as 151 because I am a terrible person
|
||||
|
||||
k_EItemActionCollectItem_CollectedItem = 154,
|
||||
k_EItemActionCollectItem_UpdateCollection = 155,
|
||||
k_EItemActionCollectItem_RemoveCollection = 156,
|
||||
k_EItemActionCollectItem_RedeemCollectionReward = 157,
|
||||
|
||||
k_EItemActionPreviewItem_BeginPreviewPeriod = 158,
|
||||
k_EItemActionPreviewItem_EndPreviewPeriodExpired = 159,
|
||||
k_EItemActionPreviewItem_EndPreviewPeriodItemBought = 160,
|
||||
|
||||
k_EItemActionPeriodicScoreReward_Add = 170,
|
||||
k_EItemActionPeriodicScoreReward_Remove = 171,
|
||||
|
||||
k_EItemActionMvM_ChallengeCompleted_RemoveTicket = 180, // we completed a challenge and consumed this ticket as the cost
|
||||
k_EItemActionMvM_ChallengeCompleted_GrantBadge = 181, // we completed a challenge and granted the player a badge because they didn't have one
|
||||
k_EItemActionMvM_ChallengeCompleted_UpdateBadgeStamps_Remove = 182, // we completed a challenge and we're crossing an entry off our badge checklist (this may also reset the badge back down to empty if this was the last line item)
|
||||
k_EItemActionMvM_ChallengeCompleted_UpdateBadgeStamps_Add = 183, // (other half of the above)
|
||||
k_EItemActionMvM_ChallengeCompleted_GrantMissionCompletionLoot = 184, // we completed a mission in MvM
|
||||
k_EItemActionMvM_RemoveSquadSurplusVoucher = 185,
|
||||
k_EItemActionMvM_AwardSquadSurplus_Receiver = 186,
|
||||
k_EItemActionMvM_AwardSquadSurplus_Giver = 187,
|
||||
k_EItemActionMvM_ChallengeCompleted_GrantTourCompletionLoot = 188, // we completed a full tour in MvM
|
||||
k_EItemActionMvM_AwardHelpANoobBonus_Helper = 189,
|
||||
|
||||
k_EItemActionHalloween_UpdateMerasmusLootLevel_Add = 200, // set the level of the merasmus loot
|
||||
k_EItemActionHalloween_UpdateMerasmusLootLevel_Remove = 201,
|
||||
|
||||
k_EItemActionRemoveItemKillStreak_Remove = 202,
|
||||
k_EItemActionRemoveItemKillStreak_Add = 203,
|
||||
|
||||
k_EItemActionSupportAddOrModifyAttribute_Remove = 204,
|
||||
k_EItemActionSupportAddOrModifyAttribute_Add = 205,
|
||||
|
||||
k_EItemActionSpyVsEngyWar_JoinedWar = 206,
|
||||
|
||||
k_EItemAction_UpdateDuckBadgeLevel_Add = 207,
|
||||
k_EItemAction_UpdateDuckBadgeLevel_Remove = 208,
|
||||
|
||||
k_EItemAction_QuestDrop = 209,
|
||||
|
||||
k_EItemAction_OperationPass_Add = 210,
|
||||
|
||||
k_EItemActionMarket_Add = 211,
|
||||
k_EItemActionMarket_Remove = 212,
|
||||
|
||||
k_EItemAction_QuestComplete_Reward = 213,
|
||||
k_EItemAction_QuestComplete_Remove = 214,
|
||||
|
||||
k_EItemAction_QuestLoaner_Add = 215,
|
||||
k_EItemActionStrangeCountTransfer_Add = 216,
|
||||
k_EItemActionStrangeCountTransfer_Remove = 217,
|
||||
|
||||
k_EItemActionCraftCollectionUpgrade_Add = 218,
|
||||
k_EItemActionCraftCollectionUpgrade_Remove = 219,
|
||||
|
||||
k_EItemActionCraftHalloweenOffering_Add = 220,
|
||||
k_EItemActionCraftHalloweenOffering_Remove = 221,
|
||||
|
||||
k_EItemActionRemoveItemGiftedBy_Remove = 222,
|
||||
k_EItemActionRemoveItemGiftedBy_Add = 223,
|
||||
|
||||
k_EItemActionAddParticleVerticalAttr_Remove = 224,
|
||||
k_EItemActionAddParticleVerticalAttr_Add = 225,
|
||||
|
||||
k_EItemActionAddParticleUseHeadOriginAttr_Remove = 226,
|
||||
k_EItemActionAddParticleUseHeadOriginAttr_Add = 227,
|
||||
|
||||
k_EItemActionRemoveItemDynamicAttr_Add = 228,
|
||||
k_EItemActionRemoveItemDynamicAttr_Remove = 229,
|
||||
|
||||
k_EItemActionCraftStatClockTradeUp_Add = 230,
|
||||
k_EItemActionCraftStatClockTradeUp_Remove = 231,
|
||||
|
||||
k_EItemActionViralCompetitiveBetaPass_Drop = 232,
|
||||
|
||||
k_EItemActionSupportDeleteAttribute_Remove = 233,
|
||||
k_EItemActionSupportDeleteAttribute_Add = 234,
|
||||
|
||||
// Let's be consistent with the underscores please.
|
||||
// k_EItemActionYourNewAction, not k_EItemAction_YourNewAction
|
||||
// Yes, it matters. See PchLocalizedNameFromEItemAction for why.
|
||||
};
|
||||
extern const char *PchNameFromEItemAction( EItemAction eAction );
|
||||
extern const char *PchNameFromEItemActionUnsafe( EItemAction eAction );
|
||||
|
||||
extern bool BIsActionCreative( EItemAction );
|
||||
extern bool BIsActionDestructive( EItemAction );
|
||||
|
||||
enum EItemActionMissingBehavior { kEItemAction_FriendlyNameLookup_ReturnNULLIfMissing, kEItemAction_FriendlyNameLookup_ReturnDummyStringIfMissing };
|
||||
extern const char *PchFriendlyNameFromEItemAction( EItemAction eAction, EItemActionMissingBehavior eMissingBehavior );
|
||||
extern const char *PchLocalizedNameFromEItemAction( EItemAction eAction, CLocalizationProvider &localizationProvider );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Used to pass audit actions to asset servers for SetUnowned and
|
||||
// SetOwned methods.
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EEconOwnershipAction
|
||||
{
|
||||
k_EEconOwnershipAction_Invalid = 0,
|
||||
|
||||
k_EEconOwnershipAction_TradeBase = 100,
|
||||
k_EEconOwnershipAction_TradeCommit = 101, // precommit and docommit step of a trade. Reference is trade ID
|
||||
k_EEconOwnershipAction_TradeRollback = 102, // cancelcommit and rollbackcommit step of a trade. Reference is trade ID
|
||||
};
|
||||
|
||||
// old
|
||||
enum eEconItemFlags_Deprecated
|
||||
{
|
||||
kDeprecated_EconItemFlag_AchievementGrantedItem = 1 << 0,
|
||||
kDeprecated_EconItemFlag_CannotTrade = 1 << 1,
|
||||
kDeprecated_EconItemFlag_Purchased = 1 << 2,
|
||||
kDeprecated_EconItemFlag_CannotBeUsedInCrafting = 1 << 3,
|
||||
kDeprecated_EconItemFlag_Promotion = 1 << 4,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Periodic score events
|
||||
//-----------------------------------------------------------------------------
|
||||
enum eEconPeriodicScoreEvents
|
||||
{
|
||||
kPeriodicScoreEvent_GiftsDistributed = 0,
|
||||
kPeriodicScoreEvent_DuelsWon = 1,
|
||||
kPeriodicScoreEvent_MapStampsPurchased = 2,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Flags for CEconItem
|
||||
//-----------------------------------------------------------------------------
|
||||
// WARNING!!! Values stored in DB. DO NOT CHANGE EXISTING VALUES. Add values to the end.
|
||||
enum eEconItemFlags
|
||||
{
|
||||
kEconItemFlag_CannotTrade = 1 << 0,
|
||||
kEconItemFlag_CannotBeUsedInCrafting = 1 << 1,
|
||||
kEconItemFlag_CanBeTradedByFreeAccounts = 1 << 2,
|
||||
kEconItemFlag_NonEconomy = 1 << 3, // used for items that are meant to not interact in the economy -- these can't be traded, gift-wrapped, crafted, etc.
|
||||
kEconItemFlag_PurchasedAfterStoreCraftabilityChanges2012 = 1 << 4, // cosmetic items coming from the store are now usable in crafting; this flag is set on all items purchased from the store after this change was made
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#ifdef TF_CLIENT_DLL
|
||||
kEconItemFlagClient_ForceBlueTeam = 1 << 5,
|
||||
#endif // TF_CLIENT_DLL
|
||||
kEconItemFlagClient_StoreItem = 1 << 6,
|
||||
kEconItemFlagClient_Preview = 1 << 7, // only set on the client; means "this item is being previewed"
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
// combination of the above flags used in code
|
||||
kEconItemFlags_CheckFlags_AllGCFlags = kEconItemFlag_CannotTrade | kEconItemFlag_CannotBeUsedInCrafting | kEconItemFlag_CanBeTradedByFreeAccounts | kEconItemFlag_NonEconomy | kEconItemFlag_PurchasedAfterStoreCraftabilityChanges2012,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Origin for an item for CEconItem
|
||||
//-----------------------------------------------------------------------------
|
||||
// WARNING!!! Values stored in DB. DO NOT CHANGE EXISTING VALUES. Add values to the end.
|
||||
enum eEconItemOrigin
|
||||
{
|
||||
kEconItemOrigin_Invalid = -1, // should never be stored in the DB! used to indicate "invalid" for in-memory objects only
|
||||
|
||||
kEconItemOrigin_Drop = 0,
|
||||
kEconItemOrigin_Achievement,
|
||||
kEconItemOrigin_Purchased,
|
||||
kEconItemOrigin_Traded,
|
||||
kEconItemOrigin_Crafted,
|
||||
kEconItemOrigin_StorePromotion,
|
||||
kEconItemOrigin_Gifted,
|
||||
kEconItemOrigin_SupportGranted,
|
||||
kEconItemOrigin_FoundInCrate,
|
||||
kEconItemOrigin_Earned,
|
||||
kEconItemOrigin_ThirdPartyPromotion,
|
||||
kEconItemOrigin_GiftWrapped,
|
||||
kEconItemOrigin_HalloweenDrop,
|
||||
kEconItemOrigin_PackageItem,
|
||||
kEconItemOrigin_Foreign,
|
||||
kEconItemOrigin_CDKey,
|
||||
kEconItemOrigin_CollectionReward,
|
||||
kEconItemOrigin_PreviewItem,
|
||||
kEconItemOrigin_SteamWorkshopContribution,
|
||||
kEconItemOrigin_PeriodicScoreReward,
|
||||
kEconItemOrigin_MvMMissionCompletionReward, // includes loot from both "mission completed" and "tour completed" events
|
||||
kEconItemOrigin_MvMSquadSurplusReward,
|
||||
kEconItemOrigin_RecipeOutput,
|
||||
kEconItemOrigin_QuestDrop,
|
||||
kEconItemOrigin_QuestLoanerItem,
|
||||
kEconItemOrigin_TradeUp,
|
||||
kEconItemOrigin_ViralCompetitiveBetaPassSpread,
|
||||
|
||||
kEconItemOrigin_Max,
|
||||
};
|
||||
extern const char *PchNameFromeEconItemOrigin( eEconItemOrigin eOrigin );
|
||||
|
||||
// The Steam backend representation of a unique item index
|
||||
typedef uint64 itemid_t;
|
||||
typedef uint16 item_definition_index_t;
|
||||
typedef uint16 attrib_definition_index_t;
|
||||
typedef uint32 attrib_value_t;
|
||||
typedef uint32 operation_definition_index_t;
|
||||
typedef uint8 war_definition_index_t;
|
||||
typedef uint8 war_side_t;
|
||||
|
||||
// Misc typedefs for clarity.
|
||||
typedef uint32 equip_region_mask_t;
|
||||
typedef uint8 style_index_t;
|
||||
|
||||
const uint64 INVALID_ITEM_ID = (itemid_t)-1;
|
||||
const item_definition_index_t INVALID_ITEM_DEF_INDEX = ((item_definition_index_t)-1);
|
||||
const attrib_definition_index_t INVALID_ATTRIB_DEF_INDEX= ((attrib_definition_index_t)-1);
|
||||
const war_definition_index_t INVALID_WAR_DEF_INDEX = ((war_definition_index_t)-1);
|
||||
const war_side_t INVALID_WAR_SIDE = ((war_side_t)-1);
|
||||
// Hard code the pyro/heavy stuff. Must be in sync with the schema.
|
||||
const war_definition_index_t PYRO_VS_HEAVY_WAR_DEF_INDEX= ((war_definition_index_t)0);
|
||||
const war_side_t PYRO_VS_HEAVY_WAR_SIDE_HEAVY = ((war_side_t)0);
|
||||
const war_side_t PYRO_VS_HEAVY_WAR_SIDE_PYRO = ((war_side_t)1);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Standard/default backpack size
|
||||
#define DEFAULT_NUM_BACKPACK_SLOTS 300
|
||||
#define DEFAULT_NUM_BACKPACK_SLOTS_FREE_TRIAL_ACCOUNT 50
|
||||
#define MAX_NUM_BACKPACK_SLOTS 2000
|
||||
|
||||
// Current item level range
|
||||
#define MIN_ITEM_LEVEL 0
|
||||
#define MAX_ITEM_LEVEL 100
|
||||
|
||||
// Maximum number of attributes allowed on a single item
|
||||
#define MAX_ATTRIBUTES_PER_ITEM 15
|
||||
// The maximum length of a single attribute's description
|
||||
// divide by locchar_t, so we can ensure 192 bytes, whether that's 128 wchars on client or 256 utf-8 bytes on gc
|
||||
#define MAX_ATTRIBUTE_DESCRIPTION_LENGTH ( 256 / sizeof( locchar_t ) )
|
||||
|
||||
// The maximum length of an item's name
|
||||
#define MAX_ITEM_NAME_LENGTH 128
|
||||
#define MAX_ITEM_DESC_LENGTH 256
|
||||
// The maximum length of an item description. (Extra +1 line is for the base item type line)
|
||||
#define MAX_ITEM_DESCRIPTION_LENGTH ((MAX_ATTRIBUTES_PER_ITEM+1) * MAX_ATTRIBUTE_DESCRIPTION_LENGTH)
|
||||
|
||||
// For custom user-naming of econ items.
|
||||
#define MAX_ITEM_CUSTOM_NAME_LENGTH 40
|
||||
#define MAX_ITEM_CUSTOM_NAME_DATABASE_SIZE ((4 * MAX_ITEM_CUSTOM_NAME_LENGTH) + 1) // Ensures we can store MAX_ITEM_CUSTOM_NAME_LENGTH
|
||||
// characters worth of obscure unicode characters in UTF8
|
||||
#define MAX_ITEM_CUSTOM_DESC_LENGTH 80
|
||||
#define MAX_ITEM_CUSTOM_DESC_DATABASE_SIZE ((4 * MAX_ITEM_CUSTOM_DESC_LENGTH) + 1)
|
||||
|
||||
#define MAX_KILLCAM_MESSAGE_LENGTH 40
|
||||
#define MAX_KILLCAM_MESSAGE_DATABASE_SIZE ((4 * MAX_KILLCAM_MESSAGE_LENGTH) + 1)
|
||||
|
||||
// max length in the DB for claim codes
|
||||
#define MAX_CLAIM_CODE_LENGTH 128
|
||||
|
||||
// The item definition index reserved for the preview item
|
||||
#define PREVIEW_ITEM_DEFINITION_INDEX (item_definition_index_t)-1
|
||||
|
||||
// The number of items to work on in a job before checking if a yield is necessary
|
||||
#define MAX_ITEMS_BEFORE_YIELD 50
|
||||
|
||||
// TF team-color paints (moved from econ_item_view.h)
|
||||
#define RGB_INT_RED 12073019
|
||||
#define RGB_INT_BLUE 5801378
|
||||
|
||||
// Custom textures
|
||||
const int k_nCustomImageSize = 128;
|
||||
const int k_nMaxCustomImageFileSize = k_nCustomImageSize*k_nCustomImageSize*4 + 4*1024; // Is this about right?
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Quality types of items
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef int32 entityquality_t;
|
||||
enum EEconItemQuality
|
||||
{
|
||||
AE_UNDEFINED = -1,
|
||||
|
||||
AE_NORMAL = 0,
|
||||
AE_RARITY1 = 1, // Genuine
|
||||
AE_RARITY2 = 2, // Customized (unused)
|
||||
AE_VINTAGE = 3, // Vintage has to stay at 3 for backwards compatibility
|
||||
AE_RARITY3, // Artisan
|
||||
AE_UNUSUAL, // Unusual
|
||||
AE_UNIQUE,
|
||||
AE_COMMUNITY,
|
||||
AE_DEVELOPER,
|
||||
AE_SELFMADE,
|
||||
AE_CUSTOMIZED, // (unused)
|
||||
AE_STRANGE,
|
||||
AE_COMPLETED,
|
||||
AE_HAUNTED,
|
||||
AE_COLLECTORS,
|
||||
AE_PAINTKITWEAPON,
|
||||
|
||||
AE_RARITY_DEFAULT,
|
||||
AE_RARITY_COMMON,
|
||||
AE_RARITY_UNCOMMON,
|
||||
AE_RARITY_RARE,
|
||||
AE_RARITY_MYTHICAL,
|
||||
AE_RARITY_LEGENDARY,
|
||||
AE_RARITY_ANCIENT,
|
||||
|
||||
AE_MAX_TYPES,
|
||||
AE_DEPRECATED_UNIQUE = 3,
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: colors used in the display of attributes
|
||||
//-----------------------------------------------------------------------------
|
||||
enum attrib_colors_t
|
||||
{
|
||||
ATTRIB_COL_LEVEL = 0,
|
||||
ATTRIB_COL_NEUTRAL,
|
||||
ATTRIB_COL_POSITIVE,
|
||||
ATTRIB_COL_NEGATIVE,
|
||||
ATTRIB_COL_ITEMSET_NAME,
|
||||
ATTRIB_COL_ITEMSET_EQUIPPED,
|
||||
ATTRIB_COL_ITEMSET_MISSING,
|
||||
ATTRIB_COL_BUNDLE_ITEM,
|
||||
ATTRIB_COL_LIMITED_USE,
|
||||
ATTRIB_COL_component_flags,
|
||||
ATTRIB_COL_LIMITED_QUANTITY,
|
||||
|
||||
ATTRIB_COL_RARITY_DEFAULT,
|
||||
ATTRIB_COL_RARITY_COMMON,
|
||||
ATTRIB_COL_RARITY_UNCOMMON,
|
||||
ATTRIB_COL_RARITY_RARE,
|
||||
ATTRIB_COL_RARITY_MYTHICAL,
|
||||
ATTRIB_COL_RARITY_LEGENDARY,
|
||||
ATTRIB_COL_RARITY_ANCIENT,
|
||||
ATTRIB_COL_RARITY_IMMORTAL,
|
||||
ATTRIB_COL_RARITY_ARCANA,
|
||||
|
||||
ATTRIB_COL_STRANGE,
|
||||
ATTRIB_COL_UNUSUAL,
|
||||
|
||||
NUM_ATTRIB_COLORS,
|
||||
};
|
||||
|
||||
|
||||
#define AE_USE_SCRIPT_VALUE 9999 // Can't be -1, due to unsigned ints used on the backend
|
||||
|
||||
const char *EconQuality_GetQualityString( EEconItemQuality eQuality );
|
||||
const char *EconQuality_GetColorString( EEconItemQuality eQuality );
|
||||
const char *EconQuality_GetLocalizationString( EEconItemQuality eQuality );
|
||||
EEconItemQuality EconQuality_GetQualityFromString( const char* pszQuality );
|
||||
|
||||
// Sort order for rarities
|
||||
int EconQuality_GetRarityScore( EEconItemQuality eQuality );
|
||||
|
||||
extern attrib_colors_t GetAttribColorIndexForName( const char* pszName );
|
||||
extern const char *GetColorNameForAttribColor( attrib_colors_t unAttribColor );
|
||||
extern const char *GetHexColorForAttribColor( attrib_colors_t unAttribColor );
|
||||
|
||||
// Utility function that'll get you an item quality from a string
|
||||
entityquality_t GetItemQualityFromString( const char *sQuality );
|
||||
|
||||
enum recipecategories_t
|
||||
{
|
||||
RECIPE_CATEGORY_CRAFTINGITEMS = 0,
|
||||
RECIPE_CATEGORY_COMMONITEMS,
|
||||
RECIPE_CATEGORY_RAREITEMS,
|
||||
RECIPE_CATEGORY_SPECIAL,
|
||||
|
||||
NUM_RECIPE_CATEGORIES
|
||||
};
|
||||
extern const char *g_szRecipeCategoryStrings[NUM_RECIPE_CATEGORIES];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Kill eater support.
|
||||
// Strange counters and strange parts
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined( TF_DLL ) || defined( TF_GC_DLL ) || defined( TF_CLIENT_DLL )
|
||||
enum kill_eater_event_t
|
||||
{
|
||||
kKillEaterEvent_PlayerKill = 0, // default; items with no event type specified use this
|
||||
kKillEaterEvent_UberActivated,
|
||||
kKillEaterEvent_PlayerKillAssist,
|
||||
kKillEaterEvent_PlayerKillsBySentry, // your sentry you built with this item killed someone
|
||||
kKillEaterEvent_PeeVictims, // this game is great
|
||||
kKillEaterEvent_BackstabAbsorbed, // you're a sniper and you got a spy to stab your Razorback
|
||||
kKillEaterEvent_HeadsTaken, // this also tracks kills but with different flavor text
|
||||
kKillEaterEvent_Humiliations, // fish kills!
|
||||
kKillEaterEvent_GiftsGiven, // number of gifts given
|
||||
kKillEaterEvent_DeathsFeigned, // number of deaths successfully feigned with the Dead Ringer
|
||||
kKillEaterEvent_ScoutKill, // (part)
|
||||
kKillEaterEvent_SniperKill, // (part)
|
||||
kKillEaterEvent_SoldierKill, // (part)
|
||||
kKillEaterEvent_DemomanKill, // (part)
|
||||
kKillEaterEvent_HeavyKill, // (part)
|
||||
kKillEaterEvent_PyroKill, // (part)
|
||||
kKillEaterEvent_SpyKill, // (part)
|
||||
kKillEaterEvent_EngineerKill, // (part)
|
||||
kKillEaterEvent_MedicKill, // (part)
|
||||
kKillEaterEvent_BuildingDestroyed, // (part)
|
||||
kKillEaterEvent_ProjectileReflect, // (part)
|
||||
kKillEaterEvent_HeadshotKill, // (part)
|
||||
kKillEaterEvent_AirborneEnemyKill, // (part) (enemy is in the air when they die)
|
||||
kKillEaterEvent_GibKill, // (part)
|
||||
kKillEaterEvent_BuildingSapped, // a sapper was doing damage to this building while it was destroyed
|
||||
kKillEaterEvent_PlayerTickle, // we used our comedy holiday gloves to force someone else to laugh
|
||||
kKillEaterEvent_PlayerKillByBootStomp, // we killed a player by transferring our falling damage onto them
|
||||
kKillEaterEvent_PlayerKillDuringFullMoon, // (part) we killed a player during the full moon holiday event (GC-updated)
|
||||
kKillEaterEvent_PlayerKillStartDomination, // (part) we killed a player and this kill was enough to start our domination of them
|
||||
kKillEaterEvent_PlayerKillAlreadyDominated, // (part) we killed a player with this weapon that we were already dominating
|
||||
kKillEaterEvent_PlayerKillRevenge, // (part) we killed a player with this weapon when that player was dominating us
|
||||
kKillEaterEvent_PlayerKillPosthumous, // (part) we killed a player after we were already dead (afterburn, stray rocket, etc.)
|
||||
kKillEaterEvent_BurningAllyExtinguished, // (part) we used urine/milk/flamethrower/whatever to put out the fire on an ally that was burning
|
||||
kKillEaterEvent_PlayerKillCritical, // (part) we killed a player with a shot that was a critical
|
||||
kKillEaterEvent_PlayerKillWhileExplosiveJumping, // (part) we killed a player while we were rocket/sticky-jumping
|
||||
kKillEaterEvent_PlayerKillFriend, // (part) we killed a player who is a Steam friend (GC-updated)
|
||||
kKillEaterEvent_SapperDestroyed, // (part) we destroyed a sapper that was on a friendly building
|
||||
kKillEaterEvent_InvisibleSpiesKilled, // (part) we killed an invisible spy
|
||||
kKillEaterEvent_MedicsWithFullUberKilled, // (part) we killed a fully ubered medic
|
||||
kKillEaterEvent_RobotsDestroyed, // (part) we killed a robot in MvM
|
||||
kKillEaterEvent_MinibossRobotsDestroyed, // (part) we killed a miniboss robot in MvM
|
||||
kKillEaterEvent_RobotsDestroyedAfterPenetration, // (part) we killed a robot with a shot that had already penetrated another robot
|
||||
kKillEaterEvent_RobotHeadshotKills, // (part) like kKillEaterEvent_HeadshotKill, but only for robots
|
||||
kKillEaterEvent_RobotsSlowed, // (part) we hit some robots with Jarate and now they're slow
|
||||
kKillEaterEvent_KillWhileLowHealth, // (part) we killed someone while we had <10% max health
|
||||
kKillEaterEvent_HalloweenKill, // (part) we killed someone during the Halloween holiday
|
||||
kKillEaterEvent_HalloweenKillRobot, // (part) we killed a robot in MvM during the Halloween holiday
|
||||
kKillEaterEvent_DefenderKill, // (part) we killed someone carrying the intel, pushing the cart, or capping a point
|
||||
kKillEaterEvent_UnderwaterKill, // (part) we killed someone who was completely submerged
|
||||
kKillEaterEvent_KillWhileUbercharged, // (part) we killed someone while we were invulnerable
|
||||
kKillEaterEvent_FoodEaten, // We ate our food
|
||||
kKillEaterEvent_BannersDeployed, // We deployed a banner buff
|
||||
kKillEaterEvent_NEGATIVE_SniperShotsMissed, // (part) we shot our sniper rifle and didnt hit anything
|
||||
kKillEaterEvent_NEGATIVE_UbersDropped, // (part) we died with a full ubercharge
|
||||
kKillEaterEvent_NEGATIVE_DeathsWhileCarryingBuilding, // (part) we died while carrying a building
|
||||
kKillEaterEvent_NEGATIVE_DeathsFromCratering, // (part) we died from cratering
|
||||
kKillEaterEvent_NEGATIVE_DeathsFromEnvironment, // (part) we died from environmental damage
|
||||
kKillEaterEvent_NEGATIVE_Deaths, // (part) we died :(
|
||||
kKillEaterEvent_TimeCloaked, // Time we are cloaked
|
||||
kKillEaterEvent_HealingProvided, // Health Provided to Allies
|
||||
kKillEaterEvent_TeleportsProvided, // Teleports Provided to Allies
|
||||
kKillEaterEvent_TanksDestroyed, // (part) we dealt the killing blow to a tank in MvM
|
||||
kKillEaterEvent_LongDistanceKill, // (part) we dealt the killing blow (while alive) from far away
|
||||
kKillEaterEvent_UniqueEvent__KilledAccountWithItem, // (part) (unique event) how many individual accounts have we killed?
|
||||
// kKillEaterEvent_UniqueEvent__PlayedWithAccountIDWhileWearingItem, // (part) (unique event) how many individual accounts have we played a round with?
|
||||
kKillEaterEvent_PointsScored, // How many score points we've accumulated
|
||||
kKillEaterEvent_DoubleDonks, // Double-Donks scored with the loose cannon
|
||||
kKillEaterEvent_TeammatesWhipped, // Whipped Teammates with the Disciplinary Action
|
||||
kKillEaterEvent_VictoryTimeKill, // Kills while in Victory / Bonus Time
|
||||
kKillEaterEvent_RobotScoutKill, // (part)
|
||||
kKillEaterEvent_RobotSniperKill, // (part) Not yet shipped
|
||||
kKillEaterEvent_RobotSoldierKill, // (part) Not yet shipped
|
||||
kKillEaterEvent_RobotDemomanKill, // (part) Not yet shipped
|
||||
kKillEaterEvent_RobotHeavyKill, // (part) Not yet shipped
|
||||
kKillEaterEvent_RobotPyroKill, // (part) Not yet shipped
|
||||
kKillEaterEvent_RobotSpyKill, // (part)
|
||||
kKillEaterEvent_RobotEngineerKill, // (part) Not yet shipped
|
||||
kKillEaterEvent_RobotMedicKill, // (part) Not yet shipped
|
||||
kKillEaterEvent_TauntKill, // Taunt Kills
|
||||
kKillEaterEvent_PlayersWearingUnusualKill, // (part) we killed someone wearing an unusual hat (!)
|
||||
kKillEaterEvent_BurningEnemyKill, // (part) we killed someone who was on fire up until they died
|
||||
kKillEaterEvent_KillstreaksEnded, // (part) we killed someone who was on a killstreak
|
||||
kKillEaterEvent_KillcamTaunts, // (cosmetic part) we appeared wearing this item in the killcam taunting
|
||||
kKillEaterEvent_DamageDealt, // (part) we have dealt this much damage to people
|
||||
kKillEaterEvent_FiresSurvived, // (cosmetic part) we were lit on fire wearing this item and then the fire went out and we were still alive
|
||||
kKillEaterEvent_AllyHealingDone, // (part) we have healed this much (directly, so doesn't count Mad Milk, etc. because we lose the item pointer at some point); also ignores self heal (ie., Concheror buff, MvM upgrades)
|
||||
kKillEaterEvent_PointBlankKills, // (part) we killed someone while standing right next to them
|
||||
kKillEaterEvent_PlayerKillsByManualControlOfSentry, // Kills from wrangled a sentry
|
||||
kKillEaterEvent_CosmeticKills, // (cosmetic part) kills
|
||||
kKillEaterEvent_FullHealthKills, // (part) Kills while at fullhealth
|
||||
kKillEaterEvent_TauntingPlayerKills, // (part) Taunting Player Kills
|
||||
kKillEaterEvent_Halloween_OverworldKills,
|
||||
kKillEaterEvent_Halloween_UnderworldKills,
|
||||
kKillEaterEvent_Halloween_MinigamesWon,
|
||||
kKillEaterEvent_NonCritKills, // part kills that are not crit or mini crit
|
||||
kKillEaterEvent_PlayersHit, // part
|
||||
kKillEaterEvent_CosmeticAssists, // Cosmetic part
|
||||
kKillEaterEvent_CosmeticOperationContractsCompleted, // Operation Stat Tracker
|
||||
kKillEaterEvent_CosmeticOperationKills, // Operation Stat Tracker
|
||||
kKillEaterEvent_CosmeticOperationContractsPoints,
|
||||
kKillEaterEvent_CosmeticOperationBonusPoints,
|
||||
kKillEaterEvent_TauntsPerformed, // Strange Taunts
|
||||
kKillEaterEvent_InvasionKills, // Kills During Invasion Event. Locked after Operation
|
||||
kKillEaterEvent_InvasionKillsOnMap01,
|
||||
kKillEaterEvent_InvasionKillsOnMap02,
|
||||
kKillEaterEvent_InvasionKillsOnMap03,
|
||||
kKillEaterEvent_InvasionKillsOnMap04,
|
||||
kKillEaterEvent_HalloweenSouls, // Halloween
|
||||
kKillEaterEvent_HalloweenContractsCompleted,
|
||||
kKillEaterEvent_HalloweenOfferings,
|
||||
kKillEaterEvent_PowerupBottlesUsed,
|
||||
|
||||
// NEW ENTRIES MUST BE ADDED AT THE BOTTOM
|
||||
};
|
||||
#else
|
||||
// projects that actually want to implement kill-eater functionality will want to put their list somewhere around here,
|
||||
// but unfortunately the base code relies on this specific definition being entry 0
|
||||
static const uint32 kKillEaterEvent_PlayerKill = 0;
|
||||
#endif // defined( TF_DLL ) || defined( TF_GC_DLL ) || defined( TF_CLIENT_DLL )
|
||||
|
||||
enum strange_event_restriction_t
|
||||
{
|
||||
kStrangeEventRestriction_None = 0, // default -- unassigned, all events pass
|
||||
kStrangeEventRestriction_VictimSteamAccount, // the victim must have a specific Steam ID
|
||||
#if defined( TF_DLL ) || defined( TF_GC_DLL ) || defined( TF_CLIENT_DLL )
|
||||
kStrangeEventRestriction_Map, // must be playing on a certain map when the event takes place
|
||||
kStrangeEventRestriction_Competitive, // must be playing in a competitive game
|
||||
#endif // defined( TF_DLL ) || defined( TF_GC_DLL ) || defined( TF_CLIENT_DLL )
|
||||
kStrangeEventRestrictionCount
|
||||
};
|
||||
|
||||
// Ugh -- these are shared between the GC and the client. Maybe #define is slightly better than
|
||||
// magic string literals?
|
||||
#define KILL_EATER_RANK_LEVEL_BLOCK_NAME "KillEaterRank"
|
||||
|
||||
#ifdef TF_DLL
|
||||
class CTFWeaponBase *GetKilleaterWeaponFromDamageInfo( const class CTakeDamageInfo *pInfo );
|
||||
// A specific CEconEntity caused a kill eater event to happen. For example, a weapon might cause a
|
||||
// player kill event so we want to update the stats for that specific weapon.
|
||||
void EconEntity_OnOwnerKillEaterEvent( class CEconEntity *pEconEntity, class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
void EconItemInterface_OnOwnerKillEaterEvent( class IEconItemInterface *pEconEntity, class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
void EconEntity_OnOwnerKillEaterEventNoPartner( class CEconEntity *pEconEntity, class CTFPlayer *pOwner, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
void EconItemInterface_OnOwnerKillEaterEventNoPartner( class IEconItemInterface *pEconEntity, class CTFPlayer *pOwner, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
|
||||
void HatAndMiscEconEntities_OnOwnerKillEaterEvent( class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
void HatAndMiscEconEntities_OnOwnerKillEaterEventNoParter( class CTFPlayer *pOwner, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
|
||||
void EconEntity_NonEquippedItemKillTracking_NoPartner( class CTFPlayer *pOwner, item_definition_index_t iDefIndex, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
void EconEntity_NonEquippedItemKillTracking_NoPartnerBatched( class CTFPlayer *pOwner, item_definition_index_t iDefIndex, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
// Batching system for frequent events (ie., damage dealing). The game server will flush all batches
|
||||
// at specific time intervals and send up one composite message to avoid flooding the GC. Batched
|
||||
// messages will only work correctly for types that support increment values. Because the game client
|
||||
// and game server don't know which event types support increment values we can't do any checking
|
||||
// before we send the message.
|
||||
void EconEntity_OnOwnerKillEaterEvent_Batched( class CEconEntity *pEconEntity, class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
void EconItemInterface_OnOwnerKillEaterEvent_Batched( class IEconItemInterface *pEconEntity, class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
|
||||
void KillEaterEvents_FlushBatches();
|
||||
#endif // TF_DLL
|
||||
|
||||
int GetKillEaterAttrCount();
|
||||
int GetKillEaterAttrCount_UserCustomizable();
|
||||
const class CEconItemAttributeDefinition *GetKillEaterAttr_Score( int i );
|
||||
const class CEconItemAttributeDefinition *GetKillEaterAttr_Type( int i );
|
||||
const class CEconItemAttributeDefinition *GetKillEaterAttr_Restriction( int i );
|
||||
const class CEconItemAttributeDefinition *GetKillEaterAttr_RestrictionValue( int i );
|
||||
bool GetKillEaterAttr_IsUserCustomizable( int i );
|
||||
bool GetKilleaterValueByEvent( const class IEconItemInterface* pItem, const kill_eater_event_t& EEventType, uint32& value );
|
||||
bool BIsItemStrange( const class IEconItemInterface *pItem );
|
||||
|
||||
const int COLLECTION_CRAFTING_ITEM_COUNT = 10;
|
||||
const char* GetCollectionCraftingInvalidReason( const class IEconItemInterface *pTestItem, const class IEconItemInterface *pSourceItem );
|
||||
|
||||
const int HALLOWEEN_OFFERING_ITEM_COUNT = 3;
|
||||
const char* GetHalloweenOfferingInvalidReason( const class IEconItemInterface *pTestItem, const class IEconItemInterface *pSourceItem );
|
||||
|
||||
const int CRAFT_COMMON_STATCLOCK_ITEM_COUNT = 5;
|
||||
const char* GetCraftCommonStatClockInvalidReason( const class IEconItemInterface *pTestItem, const class IEconItemInterface *pSourceItem );
|
||||
|
||||
int GetMaxCardUpgradesPerItem();
|
||||
const class CEconItemAttributeDefinition *GetCardUpgradeForIndex( const class IEconItemInterface *pItem, int i );
|
||||
|
||||
#define GUARANTEED_OUTPUT (1<<0)
|
||||
#define GUARANTEED_INPUT (1<<1)
|
||||
|
||||
#define DYNAMIC_RECIPE_FLAG_IS_OUTPUT (1<<0)
|
||||
#define DYNAMIC_RECIPE_FLAG_IS_UNTRADABLE (1<<1)
|
||||
#define DYNAMIC_RECIPE_FLAG_PARAM_ITEM_DEF_SET (1<<2)
|
||||
#define DYNAMIC_RECIPE_FLAG_PARAM_QUALITY_SET (1<<3)
|
||||
#define DYNAMIC_RECIPE_FLAG_PARAM_ATTRIBUTE_SET_ALL (1<<4)
|
||||
#define DYNAMIC_RECIPE_FLAG_PARAM_ATTRIBUTE_SET_ANY (1<<5)
|
||||
|
||||
#define k_ObjectiveTrackerFlag_OwnerClient (1<<0)
|
||||
#define k_ObjectiveTrackerFlag_Servers (1<<1)
|
||||
#define k_ObjectiveTrackerFlag_AllClients (1<<2)
|
||||
|
||||
#define k_ObjectiveTrackerFlag_ClientAndServer ( k_ObjectiveTrackerFlag_OwnerClient | k_ObjectiveTrackerFlag_Servers )
|
||||
|
||||
const float k_MaxElapsedQuestReportTime = 10.f;
|
||||
|
||||
//===============================================================================================================
|
||||
// POSITION HANDLING
|
||||
//===============================================================================================================
|
||||
// TF Inventory Position cracking
|
||||
|
||||
// REALLY OLD FORMAT (??):
|
||||
// We store a bag index in the highbits of the inventory position.
|
||||
// The lowbit stores the position of the item within the bag.
|
||||
//
|
||||
// LESS OLD FORMAT (up through July, 2011):
|
||||
// If Bit 31 is 0:
|
||||
// Bits 1-16 are the backpack position.
|
||||
// Bits 17-26 are a bool for whether the item is equipped in the matching class.
|
||||
// Otherwise, if Bit 31 is 1:
|
||||
// Item hasn't been acknowledged by the player yet.
|
||||
// Bits 1-16 are the method by the player found the item (see unacknowledged_item_inventory_positions_t)
|
||||
// Bit 32 is 1, to note the new format.
|
||||
//
|
||||
// CURRENT FORMAT:
|
||||
// If Bit 31 is 0:
|
||||
// Bits 1-16 are the backpack position.
|
||||
// Otherwise, if Bit 31 is 1:
|
||||
// Item hasn't been acknowledged by the player yet.
|
||||
// Bits 1-16 are the method by the player found the item (see unacknowledged_item_inventory_positions_t)
|
||||
// Equipped state is stored elsewhere.
|
||||
// This is the only format that should exist on clients.
|
||||
// Note (1/15/2013) For backwards compatibility, if the value is 0 item is considered unacknowledged too
|
||||
|
||||
|
||||
enum unacknowledged_item_inventory_positions_t
|
||||
{
|
||||
UNACK_ITEM_UNKNOWN = 0,
|
||||
UNACK_ITEM_DROPPED = 1,
|
||||
UNACK_ITEM_CRAFTED,
|
||||
UNACK_ITEM_TRADED,
|
||||
UNACK_ITEM_PURCHASED,
|
||||
UNACK_ITEM_FOUND_IN_CRATE,
|
||||
UNACK_ITEM_GIFTED,
|
||||
UNACK_ITEM_SUPPORT,
|
||||
UNACK_ITEM_PROMOTION,
|
||||
UNACK_ITEM_EARNED,
|
||||
UNACK_ITEM_REFUNDED,
|
||||
UNACK_ITEM_GIFT_WRAPPED,
|
||||
UNACK_ITEM_FOREIGN,
|
||||
UNACK_ITEM_COLLECTION_REWARD,
|
||||
UNACK_ITEM_PREVIEW_ITEM,
|
||||
UNACK_ITEM_PREVIEW_ITEM_PURCHASED,
|
||||
UNACK_ITEM_PERIODIC_SCORE_REWARD,
|
||||
UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD,
|
||||
UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD,
|
||||
UNACK_ITEM_FOUND_HOLIDAY_GIFT,
|
||||
UNACK_ITEM_COMMUNITY_MARKET_PURCHASE,
|
||||
UNACK_ITEM_RECIPE_OUTPUT,
|
||||
UNACK_ITEM_HIDDEN_QUEST_ITEM,
|
||||
UNACK_ITEM_QUEST_OUTPUT,
|
||||
UNACK_ITEM_QUEST_LOANER,
|
||||
UNACK_ITEM_TRADE_UP,
|
||||
UNACK_ITEM_QUEST_MERASMISSION_OUTPUT,
|
||||
UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD,
|
||||
#ifdef ENABLE_STORE_RENTAL_BACKEND
|
||||
UNACK_ITEM_RENTAL_PURCHASE,
|
||||
#endif
|
||||
|
||||
UNACK_NUM_METHODS,
|
||||
};
|
||||
|
||||
extern const char *g_pszItemPickupMethodStrings[UNACK_NUM_METHODS - 1]; // -1 because UNACK_ITEM_DROPPED is index 1, not 0
|
||||
extern const char *g_pszItemPickupMethodStringsUnloc[UNACK_NUM_METHODS - 1];
|
||||
extern const char *g_pszItemFoundMethodStrings[UNACK_NUM_METHODS - 1];
|
||||
|
||||
enum
|
||||
{
|
||||
kGCItemSort_NoSort = 0, // this won't do anything, but can be used as a safe "header" value
|
||||
|
||||
kGCItemSort_SortByName = 1,
|
||||
kGCItemSort_SortByDefIndex = 2,
|
||||
kGCItemSort_SortByRarity = 3,
|
||||
kGCItemSort_SortByType = 4,
|
||||
kGCItemSort_SortByDate = 5,
|
||||
|
||||
kGCItemSort_GameSpecificBase = 100,
|
||||
};
|
||||
|
||||
// FIXME: these should be moved... somewhere; where?
|
||||
enum
|
||||
{
|
||||
kTFGCItemSort_SortByClass = kGCItemSort_GameSpecificBase + 1,
|
||||
kTFGCItemSort_SortBySlot = kGCItemSort_GameSpecificBase + 2,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kBackendPosition_Unacked = 1 << 30,
|
||||
kBackendPosition_NewFormat = 1 << 31,
|
||||
|
||||
kBackendPositionMask_Position = 0x0000ffff,
|
||||
kBackendPositionMask_FormatFlags = (kBackendPosition_Unacked | kBackendPosition_NewFormat),
|
||||
};
|
||||
|
||||
inline void SetBackpackPosition( uint32 *pPosition, uint32 iPackPosition )
|
||||
{
|
||||
(*pPosition) = iPackPosition;
|
||||
|
||||
// Remove the unack'd flag
|
||||
(*pPosition) &= ~kBackendPosition_Unacked;
|
||||
}
|
||||
|
||||
inline bool IsNewPositionFormat( uint32 iBackendPosition )
|
||||
{
|
||||
return ( iBackendPosition & kBackendPosition_NewFormat ) != 0;
|
||||
}
|
||||
|
||||
inline bool IsUnacknowledged( uint32 iBackendPosition )
|
||||
{
|
||||
// For backwards compatibility, we consider position 0 as unacknowledged too
|
||||
return (iBackendPosition == 0 || (iBackendPosition & kBackendPosition_Unacked) != 0);
|
||||
}
|
||||
|
||||
inline int ExtractBackpackPositionFromBackend( uint32 iBackendPosition )
|
||||
{
|
||||
if ( IsUnacknowledged( iBackendPosition) )
|
||||
return 0;
|
||||
|
||||
return iBackendPosition & kBackendPositionMask_Position;
|
||||
}
|
||||
|
||||
inline unacknowledged_item_inventory_positions_t GetUnacknowledgedReason( uint32 iBackendPosition )
|
||||
{
|
||||
return (unacknowledged_item_inventory_positions_t)( iBackendPosition &= ~kBackendPositionMask_FormatFlags );
|
||||
}
|
||||
|
||||
inline uint32 GetUnacknowledgedPositionFor( unacknowledged_item_inventory_positions_t iMethod )
|
||||
{
|
||||
return (iMethod | kBackendPosition_Unacked | kBackendPosition_NewFormat);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Item Preview event IDs for logging.
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EEconItemPreviewEventIDs
|
||||
{
|
||||
k_EEconItemPreview_Start =1,
|
||||
k_EEconItemPreview_Expired =2,
|
||||
k_EEconItemPreview_ItemPurchased =3,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// List of holidays. These are sorted by priority. Needs to match static IIsHolidayActive *s_HolidayChecks
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EHoliday
|
||||
{
|
||||
kHoliday_None = 0, // must stay at zero for backwards compatibility
|
||||
kHoliday_TFBirthday,
|
||||
kHoliday_Halloween,
|
||||
kHoliday_Christmas,
|
||||
kHoliday_CommunityUpdate,
|
||||
kHoliday_EOTL,
|
||||
kHoliday_Valentines,
|
||||
kHoliday_MeetThePyro,
|
||||
kHoliday_FullMoon,
|
||||
kHoliday_HalloweenOrFullMoon,
|
||||
kHoliday_HalloweenOrFullMoonOrValentines,
|
||||
kHoliday_AprilFools,
|
||||
kHolidayCount,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
enum ECartItemType
|
||||
{
|
||||
kCartItem_Purchase, // a normal lifetime purchase (needs to stay as entry 0!)
|
||||
kCartItem_TryOutUpgrade, // an upgrade from "try-it-out"
|
||||
kCartItem_Rental_1Day,
|
||||
kCartItem_Rental_3Day,
|
||||
kCartItem_Rental_7Day,
|
||||
};
|
||||
|
||||
inline bool IsRentalCartItemType( ECartItemType eCartType )
|
||||
{
|
||||
return eCartType == kCartItem_Rental_1Day
|
||||
|| eCartType == kCartItem_Rental_3Day
|
||||
|| eCartType == kCartItem_Rental_7Day;
|
||||
}
|
||||
|
||||
const uint8 k_unItemRarity_Any = 0xFF;
|
||||
const uint8 k_unItemQuality_Any = 0xFF;
|
||||
|
||||
typedef int econ_tag_handle_t;
|
||||
|
||||
enum EItemUntradability
|
||||
{
|
||||
k_Untradability_Temporary = 1<<1,
|
||||
k_Untradability_Permanent = 1<<2,
|
||||
};
|
||||
|
||||
#define INVALID_ECON_TAG_HANDLE ((econ_tag_handle_t)-1)
|
||||
|
||||
#endif // ACTUAL_ECON_ITEM_CONSTANTS_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,536 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
|
||||
#ifndef ECONITEMDESCRIPTION_H
|
||||
#define ECONITEMDESCRIPTION_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "localization_provider.h" // needed for locchar_t type
|
||||
|
||||
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
|
||||
#define PROJECT_TF
|
||||
#endif
|
||||
|
||||
#define TF_ANTI_IDLEBOT_VERIFICATION defined( PROJECT_TF )
|
||||
|
||||
#if TF_ANTI_IDLEBOT_VERIFICATION
|
||||
#define TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA ,
|
||||
#define TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( arg ) arg
|
||||
#else
|
||||
#define TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA
|
||||
#define TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( arg )
|
||||
#endif
|
||||
|
||||
#if TF_ANTI_IDLEBOT_VERIFICATION
|
||||
#include "checksum_md5.h"
|
||||
#include "tf_gcmessages.pb.h"
|
||||
#include "tf_gcmessages.h"
|
||||
#ifdef CLIENT_DLL
|
||||
#include "gc_clientsystem.h"
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
#endif // TF_ANTI_IDLEBOT_VERIFICATION
|
||||
|
||||
#ifdef GC_DLL
|
||||
#include "gcsdk/gclogger.h"
|
||||
using namespace GCSDK;
|
||||
#endif
|
||||
|
||||
class IEconItemInterface;
|
||||
namespace GCSDK
|
||||
{
|
||||
class CSharedObjectTypeCache;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generate a description block for an IEconItemInterface. What the
|
||||
// client does with the description is anyone's guess, but this will
|
||||
// generate a block of UTF16 lines of text with meta/color data that
|
||||
// can be used for whatever.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
enum EDescriptionLineMetaFlags
|
||||
{
|
||||
kDescLineFlag_Name = 0x001, // the item name (can be renamed by user)
|
||||
kDescLineFlag_Type = 0x002, // the item type (ie., "Level 5 Rocket Launcher")
|
||||
kDescLineFlag_Desc = 0x004, // base item description (description from the item definition, level, etc.)
|
||||
kDescLineFlag_Attribute = 0x008, // some sort of gameplay-affecting attribute
|
||||
kDescLineFlag_Misc = 0x010, // not an attribute, not name/level
|
||||
kDescLineFlag_Empty = 0x020, // line with no content that needs to be displayed; meant for spacing
|
||||
kDescLineFlag_Set = 0x040, // this line is associated with item sets somehow
|
||||
kDescLineFlag_LimitedUse= 0x080, // this is a limited use item
|
||||
kDescLineFlag_SetName = 0x100, // this line is the title for an item set
|
||||
kDescLineFlag_Collection = 0x200, // this line is associated with item collections
|
||||
kDescLineFlag_CollectionCurrentItem = 0x400, // this line is the current item being describe
|
||||
kDescLineFlag_CollectionName = 0x800, // this line is the collection name
|
||||
|
||||
kDescLineFlagSet_DisplayInAttributeBlock = ~(kDescLineFlag_Name | kDescLineFlag_Type),
|
||||
};
|
||||
|
||||
struct econ_item_description_line_t
|
||||
{
|
||||
attrib_colors_t eColor; // desired color type for this line -- will likely be looked up either in VGUI or in the schema
|
||||
uint32 unMetaType; // type information for this line -- "item name"? "item level"?; etc.; can be game-specific
|
||||
CUtlConstStringBase<locchar_t> sText; // actual text for this, post-localization
|
||||
item_definition_index_t unDefIndex; // item def index for description lines which represent names of other items (used by bundles)
|
||||
bool bIsItemForSale; // if this line is an item (eg in the case where a bundle description lists its contained items) - is the given item for sale?
|
||||
};
|
||||
|
||||
class IEconItemDescription
|
||||
{
|
||||
public:
|
||||
// This may yield on the GC and should never yield on the client.
|
||||
static void YieldingFillOutEconItemDescription( IEconItemDescription *out_pDescription, CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
|
||||
public:
|
||||
IEconItemDescription() { }
|
||||
virtual ~IEconItemDescription() { }
|
||||
|
||||
uint32 GetLineCount() const { return m_vecDescLines.Count(); }
|
||||
const econ_item_description_line_t& GetLine( int i ) const { return m_vecDescLines[i]; }
|
||||
|
||||
// Finds and returns the first line with *all* of the passed in search flags. Will return NULL if a line
|
||||
// will all of the flags cannot be found.
|
||||
const econ_item_description_line_t *GetFirstLineWithMetaType( uint32 unMetaTypeSearchFlags ) const;
|
||||
|
||||
private:
|
||||
// When generating an item description, this is guaranteed to be called once and only once before GenerateDescription()
|
||||
// is called. Any data that may yield but will be needed somewhere deep inside GenerateDescription() should be determined
|
||||
// and cached off here.
|
||||
virtual void YieldingCacheDescriptionData( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem ) { }
|
||||
|
||||
// Take the properties off our pEconItem, and anything that we calculated in YieldingCacheDescriptionData() above and
|
||||
// fill out all of our description lines.
|
||||
virtual void GenerateDescriptionLines( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem ) = 0;
|
||||
|
||||
protected:
|
||||
CUtlVector<econ_item_description_line_t> m_vecDescLines;
|
||||
};
|
||||
|
||||
// This will be defined as either 1 or 0 depending on which project we're in. We test its value explicitly
|
||||
// rather than just checking defined() because otherwise failing to include this header file will silently
|
||||
// result in it appearing to be undefined.
|
||||
#define BUILD_ITEM_NAME_AND_DESC (defined( CLIENT_DLL ) || defined( GC_DLL ))
|
||||
|
||||
#if BUILD_ITEM_NAME_AND_DESC
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class IAccountPersonaLocalizer
|
||||
{
|
||||
public:
|
||||
virtual const locchar_t *FindAccountPersonaName( uint32 unAccountID ) const = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemDescription : public IEconItemDescription, public IAccountPersonaLocalizer
|
||||
{
|
||||
public:
|
||||
// Instances should be filled out via YieldingFillOutEconItemDescription().
|
||||
CEconItemDescription()
|
||||
#if TF_ANTI_IDLEBOT_VERIFICATION
|
||||
: m_pHashContext( NULL )
|
||||
, m_bIsVerbose( false )
|
||||
#ifdef GC_DLL
|
||||
, m_bTextModeEnabled( false )
|
||||
#else // if defined( CLIENT_DLL )
|
||||
, m_bUnknownPlayer( false )
|
||||
#endif // GC_DLL
|
||||
#endif // TF_ANTI_IDLEBOT_VERIFICATION
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
// External helper interface, also used internally. This should only be used to add lines
|
||||
// that are not a part of the properties of the item, but are instead a part of the environment
|
||||
// around the item (ie., "this item cannot be equipped in this slot because another item is
|
||||
// equipped that has conflicting regions").
|
||||
//
|
||||
// The final argument is an optional target array to use for the description lines instead of
|
||||
// our internal storage. We can use this to queue up and then batch-submit/-discard lines. Passing
|
||||
// in NULL means "use the internal array".
|
||||
virtual void AddDescLine( const locchar_t *pString, attrib_colors_t eColor, uint32 unMetaType, CUtlVector<econ_item_description_line_t> *out_pOptionalDescLineDest = NULL, item_definition_index_t unDefIndex = INVALID_ITEM_DEF_INDEX, bool bIsItemForSale = true );
|
||||
virtual void AddEmptyDescLine( CUtlVector<econ_item_description_line_t> *out_pOptionalDescLineDest = NULL );
|
||||
virtual void LocalizedAddDescLine( const CLocalizationProvider *pLocalizationProvider, const char *pLocalizationToken, attrib_colors_t eColor, uint32 unMetaType, CUtlVector<econ_item_description_line_t> *out_pOptionalDescLineDest = NULL, item_definition_index_t unDefIndex = INVALID_ITEM_DEF_INDEX, bool bIsItemForSale = true );
|
||||
|
||||
// A helper class to iterate all attributes that we expect to appear on an item description. This
|
||||
// is useable from outside CEconItemDescription. Attributes can be accessed in iteration order or
|
||||
// manually sorted to be grouped by positive/negative status, etc.
|
||||
class CVisibleAttributeDisplayer : public IEconItemAttributeIterator
|
||||
{
|
||||
public:
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) OVERRIDE;
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value ) OVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64& value ) OVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value ) OVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& value ) OVERRIDE
|
||||
{
|
||||
// Don't show these
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria& value ) OVERRIDE
|
||||
{
|
||||
// Don't show these
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement& value ) OVERRIDE
|
||||
{
|
||||
// Don't show these
|
||||
return true;
|
||||
}
|
||||
|
||||
void SortAttributes();
|
||||
void Finalize( const IEconItemInterface *pEconItem, CEconItemDescription *pEconItemDescription, const CLocalizationProvider *pLocalizationProvider );
|
||||
|
||||
private:
|
||||
struct attrib_iterator_value_t
|
||||
{
|
||||
const CEconItemAttributeDefinition *m_pAttrDef;
|
||||
attrib_value_t m_value;
|
||||
};
|
||||
|
||||
CUtlVector<attrib_iterator_value_t> m_vecAttributes;
|
||||
};
|
||||
|
||||
class CRecipeNameAttributeDisplayer : public CVisibleAttributeDisplayer
|
||||
{
|
||||
public:
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) OVERRIDE;
|
||||
};
|
||||
|
||||
#if TF_ANTI_IDLEBOT_VERIFICATION
|
||||
void SetHashContext( MD5Context_t *pHashContext )
|
||||
{
|
||||
AssertMsg( pHashContext == NULL || m_pHashContext == NULL, "Only one hash context allowed per item description!" );
|
||||
|
||||
m_pHashContext = pHashContext;
|
||||
}
|
||||
|
||||
void SetVerbose( bool bIsVerbose )
|
||||
{
|
||||
m_bIsVerbose = bIsVerbose;
|
||||
}
|
||||
|
||||
#ifdef GC_DLL
|
||||
void SetHashGCTextModeEnabled( bool bTextModeEnabled )
|
||||
{
|
||||
m_bTextModeEnabled = bTextModeEnabled;
|
||||
}
|
||||
#endif // GC_DLL
|
||||
#endif // TF_ANTI_IDLEBOT_VERIFICATION
|
||||
|
||||
#ifdef GC_DLL
|
||||
bool HasUnknownPlayer( ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else // if defined( CLIENT_DLL )
|
||||
bool HasUnknownPlayer( ) const
|
||||
{
|
||||
return m_bUnknownPlayer;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
// IEconItemDescription interface.
|
||||
virtual void YieldingCacheDescriptionData( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void GenerateDescriptionLines( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
|
||||
private:
|
||||
// Internal.
|
||||
virtual void AddAttributeDescription( const CLocalizationProvider *pLocalizationProvider, const CEconItemAttributeDefinition *pAttribDef, attrib_value_t value, attrib_colors_t eOverrideDisplayColor = NUM_ATTRIB_COLORS );
|
||||
|
||||
virtual void Generate_ItemName( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_ItemLevelDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
#if defined( STAGING_ONLY ) && defined( CLIENT_DLL )
|
||||
virtual void Generate_DebugInformation( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
#endif // defined( DEBUG ) && defined( CLIENT_DLL )
|
||||
virtual void Generate_CraftTag( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_StyleDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_HolidayRestriction( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_QualityDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_ItemRarityDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_WearAmountDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_ItemDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_Bundle( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_GiftedBy( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
#ifdef PROJECT_TF
|
||||
virtual void Generate_DuelingMedal( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_MapContributor( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_FriendlyHat( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_SaxxyAwardDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_MvmChallenges( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_SquadSurplusClaimedBy( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_DynamicRecipe( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_Leaderboard( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
#endif // PROJECT_TF
|
||||
virtual void Generate_XifierToolTargetItem( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_Painted( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_Uses( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_LootListDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_EventDetail( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_ItemSetDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_CollectionDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_ExpirationDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_MarketInformation( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_FlagsAttributes( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_DropPeriodDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
|
||||
virtual void Generate_VisibleAttributes( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
virtual void Generate_DirectX8Warning( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
|
||||
|
||||
// Helpers for the above.
|
||||
virtual void Generate_ItemLevelDesc_Default( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem, const locchar_t *locTypename );
|
||||
virtual bool BGenerate_ItemLevelDesc_StrangeNameAndStats( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem, const locchar_t *locTypename ); // returns true if generated a level/desc based on strange stats or false if nothing was generated
|
||||
const locchar_t *GetLocalizedStringForStrangeRestrictionAttr( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem, int iAttrIndex ) const;
|
||||
|
||||
// Internal data.
|
||||
void YieldingFillOutAccountPersonaName( const CLocalizationProvider *pLocalizationProvider, uint32 unAccountID );
|
||||
const locchar_t *FindAccountPersonaName( uint32 unAccountID ) const;
|
||||
|
||||
void YieldingFillOutAccountTypeCache( uint32 unAccountID, int nClassID );
|
||||
GCSDK::CSharedObjectTypeCache *FindAccountTypeCache( uint32 unAccountID, int nClassID ) const;
|
||||
|
||||
// Defined in source file -- not meant for external access.
|
||||
template < typename T >
|
||||
const T *FindAccountTypeCacheSingleton( uint32 unAccountID, int nClassID ) const;
|
||||
|
||||
// Precache data.
|
||||
struct steam_account_persona_name_t
|
||||
{
|
||||
uint32 unAccountID;
|
||||
CUtlConstStringBase<locchar_t> loc_sPersonaName;
|
||||
};
|
||||
|
||||
CUtlVector<steam_account_persona_name_t> vecPersonaNames;
|
||||
|
||||
struct steam_account_type_cache_t
|
||||
{
|
||||
uint32 unAccountID;
|
||||
int nClassID;
|
||||
GCSDK::CSharedObjectTypeCache *pTypeCache;
|
||||
};
|
||||
|
||||
CUtlVector<steam_account_type_cache_t> vecTypeCaches;
|
||||
|
||||
#if TF_ANTI_IDLEBOT_VERIFICATION
|
||||
MD5Context_t *m_pHashContext;
|
||||
bool m_bIsVerbose;
|
||||
#ifdef GC_DLL
|
||||
bool m_bTextModeEnabled;
|
||||
#else // if defined( CLIENT_DLL )
|
||||
bool m_bUnknownPlayer;
|
||||
#endif // GC_DLL
|
||||
#endif // TF_ANTI_IDLEBOT_VERIFICATION
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconAttributeDescription
|
||||
{
|
||||
private:
|
||||
// Internal constructor.
|
||||
void InternalConstruct
|
||||
(
|
||||
const CLocalizationProvider *pLocalizationProvider,
|
||||
const CEconItemAttributeDefinition *pAttribDef,
|
||||
attrib_value_t value,
|
||||
TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( MD5Context_t *pHashContext ) TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA
|
||||
IAccountPersonaLocalizer *pOptionalAccountPersonaLocalizer
|
||||
);
|
||||
|
||||
public:
|
||||
// Outward-facing constructor. Pass in whatever you want for "value" and we'll
|
||||
// use the raw bits for their value interpreted however the attribute says.
|
||||
template < typename T >
|
||||
CEconAttributeDescription
|
||||
(
|
||||
const CLocalizationProvider *pLocalizationProvider,
|
||||
const CEconItemAttributeDefinition *pAttribDef,
|
||||
T value,
|
||||
TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( MD5Context_t *pHashContext = NULL ) TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA
|
||||
IAccountPersonaLocalizer *pOptionalAccountPersonaLocalizer = NULL
|
||||
)
|
||||
{
|
||||
COMPILE_TIME_ASSERT( sizeof( T ) == sizeof( attrib_value_t ) );
|
||||
|
||||
InternalConstruct( pLocalizationProvider, pAttribDef, *(attrib_value_t *)&value, TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( pHashContext ) TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA pOptionalAccountPersonaLocalizer );
|
||||
}
|
||||
|
||||
const CUtlConstStringBase<locchar_t>& GetDescription() const { return m_loc_sValue; }
|
||||
const CUtlConstStringBase<locchar_t>& GetShortDescription() const { return m_loc_sShortValue; }
|
||||
attrib_colors_t GetDefaultColor() const { return m_eDefaultColor; }
|
||||
|
||||
private:
|
||||
CUtlConstStringBase<locchar_t> m_loc_sValue;
|
||||
CUtlConstStringBase<locchar_t> m_loc_sShortValue;
|
||||
attrib_colors_t m_eDefaultColor;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: control how item name is generated
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EGenerateLocalizedFullItemNameFlag_t
|
||||
{
|
||||
k_EGenerateLocalizedFullItemName_Default = 0,
|
||||
k_EGenerateLocalizedFullItemName_WithPaintWear = ( 1 << 0 ),
|
||||
k_EGenerateLocalizedFullItemName_WithoutCustomName = ( 1 << 1 ),
|
||||
k_EGenerateLocalizedFullItemName_WithoutQuality = ( 1 << 2 ),
|
||||
k_EGenerateLocalizedFullItemName_WithPaintkitNoItem = ( 1 << 3 ),
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemLocalizedFullNameGenerator
|
||||
{
|
||||
public:
|
||||
CEconItemLocalizedFullNameGenerator( const CLocalizationProvider *pLocalizationProvider, const CEconItemDefinition *pItemDef, bool bUseingHashContext = true, entityquality_t eQuality = AE_UNIQUE );
|
||||
|
||||
const locchar_t *GetFullName() const { return m_loc_LocalizedItemName; }
|
||||
|
||||
private:
|
||||
locchar_t m_loc_LocalizedItemName[ MAX_ITEM_NAME_LENGTH ];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemLocalizedMarketNameGenerator
|
||||
{
|
||||
public:
|
||||
CEconItemLocalizedMarketNameGenerator( const CLocalizationProvider *pLocalizationProvider, CEconItem *pItem, bool bUseingHashContext = true );
|
||||
|
||||
const locchar_t *GetFullName() const { return m_loc_LocalizedItemName; }
|
||||
|
||||
private:
|
||||
locchar_t m_loc_LocalizedItemName[ MAX_ITEM_NAME_LENGTH ];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSteamAccountIDAttributeCollector : public CEconItemSpecificAttributeIterator
|
||||
{
|
||||
public:
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) OVERRIDE
|
||||
{
|
||||
if ( pAttrDef->GetDescriptionFormat() == ATTDESCFORM_VALUE_IS_ACCOUNT_ID )
|
||||
{
|
||||
m_vecSteamAccountIDs.AddToTail( value );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Data access.
|
||||
const CUtlVector<uint32>& GetAccountIDs()
|
||||
{
|
||||
return m_vecSteamAccountIDs;
|
||||
}
|
||||
|
||||
private:
|
||||
CUtlVector<uint32> m_vecSteamAccountIDs;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
#if TF_ANTI_IDLEBOT_VERIFICATION
|
||||
|
||||
#include "checksum_md5.h"
|
||||
|
||||
enum
|
||||
{
|
||||
kTFDescriptionHash_TextmodeArbitraryKey = 0x19a04480,
|
||||
kTFDescriptionHash_ValidArbitraryKey = 0xa0939180,
|
||||
kTFDescriptionHash_MultiRunArbitraryKey = 0x5790a31d,
|
||||
kTFDescriptionHash_ChallengeXorShenanigans = 0x1870f0d2,
|
||||
};
|
||||
|
||||
// Global function/variable names show up in Mac binaries so we give them names that will stand out less
|
||||
// here and then #define them back so the code is readable.
|
||||
#define TF_Description_HashDataMungeContents CompressFragments
|
||||
inline void TFDescription_HashDataMungeContents( MD5Context_t *out_pContext, const void *pContents, size_t unContentLength, bool bIsVerbose, const char* pszInfo )
|
||||
{
|
||||
Assert( out_pContext );
|
||||
Assert( pContents );
|
||||
|
||||
MD5Update( out_pContext, static_cast<const uint8 *>( pContents ), unContentLength );
|
||||
|
||||
// if Verbose, report the contents to the GC
|
||||
if ( bIsVerbose )
|
||||
{
|
||||
MD5Context_t md5ContextEx = *out_pContext;
|
||||
MD5Value_t md5ResultEx;
|
||||
MD5Final( &md5ResultEx.bits[0], &md5ContextEx );
|
||||
|
||||
#ifdef GC_DLL
|
||||
EmitInfo( SPEW_GC, SPEW_ALWAYS, LOG_ALWAYS, "Verbose Verification GC : [ %s ] - [ %s ] \n", MD5_Print( md5ResultEx.bits, MD5_DIGEST_LENGTH ), pszInfo );
|
||||
#else
|
||||
// Client reports this to the GC
|
||||
GCSDK::CProtoBufMsg<CGCMsgTFSyncEx> msgResponse( k_EMsgGC_ClientVerificationVerboseResponse );
|
||||
msgResponse.Body().set_version_checksum( pszInfo ); // before
|
||||
msgResponse.Body().set_version_checksum_ex( &md5ResultEx.bits[0], MD5_DIGEST_LENGTH ); // after
|
||||
GCClientSystem()->BSendMessage( msgResponse );
|
||||
#endif
|
||||
//delete [] pArr;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, this one is actually just a helper macro.
|
||||
#define TFDescription_HashDataMunge( context, field, bIsVerbose, pszInfo ) \
|
||||
{ \
|
||||
TFDescription_HashDataMungeContents( context, (void *)&field, sizeof( field ), bIsVerbose, pszInfo ); \
|
||||
}
|
||||
|
||||
#endif // TF_ANTI_IDLEBOT_VERIFICATION
|
||||
|
||||
#endif // BUILD_ITEM_NAME_AND_DESC
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
struct CLocalizedRTime32
|
||||
{
|
||||
RTime32 m_unTime;
|
||||
bool m_bForceGMTOnClient; // display this time in GMT on the client? by default, clients show local time; the GC will ignore this flag and always display GMT
|
||||
const CLocalizationProvider *m_pLocalizationProvider;
|
||||
TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( MD5Context_t *m_pHashContext; )
|
||||
};
|
||||
|
||||
template < >
|
||||
class CLocalizedStringArg<CLocalizedRTime32>
|
||||
{
|
||||
public:
|
||||
enum { kIsValid = true };
|
||||
|
||||
CLocalizedStringArg( const CLocalizedRTime32& cTimeIn );
|
||||
|
||||
const locchar_t *GetLocArg() const { return m_Str.Get(); }
|
||||
|
||||
private:
|
||||
CUtlConstStringBase<locchar_t> m_Str;
|
||||
};
|
||||
|
||||
#endif // ECONITEMDESCRIPTION_H
|
||||
@@ -0,0 +1,331 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: EconItemFactory: Manages rolling for items requested by the game server
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
#include "econ/econ_assetapi_context.h"
|
||||
|
||||
|
||||
using namespace GCSDK;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CEconItemFactory::CEconItemFactory( )
|
||||
: m_ulNextObjID( 0 )
|
||||
, m_bIsInitialized( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initializes the item factory and schema. Return false if init failed
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CEconItemFactory::BYieldingInit()
|
||||
{
|
||||
CUtlVector< CUtlString > vecErrors;
|
||||
bool bRet = m_schema.BInit( "scripts/items/unencrypted/items_master.txt", "GAME", &vecErrors );
|
||||
|
||||
FOR_EACH_VEC( vecErrors, nError )
|
||||
{
|
||||
EmitError( SPEW_GC, "%s\n", vecErrors[nError].Get() );
|
||||
}
|
||||
|
||||
static const char *pchMaxIDQuery = "SELECT MAX( ID ) FROM "
|
||||
"( select max(ID) AS ID FROM Item UNION SELECT MAX(ID) AS ID FROM ForeignItem ) as tbl";
|
||||
|
||||
CSQLAccess sqlAccess;
|
||||
if( !sqlAccess.BYieldingExecuteSingleResult<uint64, uint64>( NULL, pchMaxIDQuery, k_EGCSQLType_int64, &m_ulNextObjID, NULL ) )
|
||||
{
|
||||
EmitError( SPEW_GC, "Failed to read max item ID" );
|
||||
return false;
|
||||
}
|
||||
m_ulNextObjID++; // our next ID is one past the current max ID
|
||||
|
||||
m_bIsInitialized = bRet;
|
||||
return bRet;
|
||||
}
|
||||
|
||||
static const CEconItemQualityDefinition *GetQualityDefinitionForItemCreation( const CItemSelectionCriteria *pOptionalCriteria, const CEconItemDefinition *pItemDef )
|
||||
{
|
||||
Assert( pItemDef );
|
||||
|
||||
// Do we have a quality specified? If so, is it a valid quality? If not, we fall back to the
|
||||
// quality specified by the item definition, the schema, etc.
|
||||
uint8 unQuality = k_unItemQuality_Any;
|
||||
|
||||
// Quality specified in generation request via criteria?
|
||||
if ( pOptionalCriteria && pOptionalCriteria->BQualitySet() )
|
||||
{
|
||||
unQuality = pOptionalCriteria->GetQuality();
|
||||
}
|
||||
|
||||
// If not: quality specified in item definition?
|
||||
if ( unQuality == k_unItemQuality_Any )
|
||||
{
|
||||
unQuality = pItemDef->GetQuality();
|
||||
}
|
||||
|
||||
// Final fallback: default quality in schema.
|
||||
if ( unQuality == k_unItemQuality_Any )
|
||||
{
|
||||
unQuality = GetItemSchema()->GetDefaultQuality();
|
||||
}
|
||||
|
||||
AssertMsg( unQuality != k_unItemQuality_Any, "Unable to locate valid quality!" );
|
||||
|
||||
return GetItemSchema()->GetQualityDefinition( unQuality );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates an item matching the incoming item selection criteria
|
||||
// Input: pItem - Pointer to the item to fill in
|
||||
// criteria - The criteria that the generated item must match
|
||||
// Output: True if a matching item could be generated, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
CEconItem *CEconItemFactory::CreateRandomItem( const CEconGameAccount *pGameAccount, const CItemSelectionCriteria &criteria )
|
||||
{
|
||||
// Find a matching item definition.
|
||||
const CEconItemDefinition *pItemDef = RollItemDefinition( criteria );
|
||||
if ( NULL == pItemDef )
|
||||
{
|
||||
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateRandomItem(): Item creation request with no matching definition\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const CEconItemQualityDefinition *pQualityDef = GetQualityDefinitionForItemCreation( &criteria, pItemDef );
|
||||
if ( NULL == pQualityDef )
|
||||
{
|
||||
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateRandomItem(): Item creation request with unknown quality\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// At this point we have everything that can fail will already have failed, so we can safely
|
||||
// create an item and just move properties over to it.
|
||||
CEconItem *pItem = new CEconItem();
|
||||
pItem->SetItemID( GetNextID() );
|
||||
pItem->SetDefinitionIndex( pItemDef->GetDefinitionIndex() );
|
||||
pItem->SetItemLevel( criteria.BItemLevelSet() ? criteria.GetItemLevel() : pItemDef->RollItemLevel() );
|
||||
pItem->SetQuality( pQualityDef->GetDBValue() );
|
||||
pItem->SetInventoryToken( criteria.GetInitialInventory() );
|
||||
pItem->SetQuantity( criteria.BInitialQuantitySet() ? criteria.GetInitialQuantity() : pItemDef->GetDefaultDropQuantity() );
|
||||
// don't set account ID
|
||||
|
||||
// Add any custom attributes we need
|
||||
if( !BAddGCGeneratedAttributesToItem( pGameAccount, pItem ) )
|
||||
{
|
||||
delete pItem;
|
||||
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Failed to generate attributes\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates an item based on a specific item definition index
|
||||
// Input: pItem - Pointer to the item to fill in
|
||||
// unDefinitionIndex - The definition index of the item to create
|
||||
// Output: True if a matching item could be generated, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
CEconItem *CEconItemFactory::CreateSpecificItem( const CEconGameAccount *pGameAccount, item_definition_index_t unDefinitionIndex )
|
||||
{
|
||||
// Find the matching index
|
||||
const CEconItemDefinition *pItemDef = m_schema.GetItemDefinition( unDefinitionIndex );
|
||||
if ( NULL == pItemDef )
|
||||
{
|
||||
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Item creation request with no matching definition (def index %u)\n", unDefinitionIndex );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const CEconItemQualityDefinition *pQualityDef = GetQualityDefinitionForItemCreation( NULL, pItemDef );
|
||||
if ( NULL == pQualityDef )
|
||||
{
|
||||
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Item creation request with unknown quality\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CEconItem *pItem = new CEconItem();
|
||||
if ( pGameAccount != NULL )
|
||||
pItem->SetItemID( GetNextID() );
|
||||
pItem->SetDefinitionIndex( unDefinitionIndex );
|
||||
pItem->SetItemLevel( pItemDef->RollItemLevel() );
|
||||
pItem->SetQuality( pQualityDef->GetDBValue() );
|
||||
// don't set inventory token
|
||||
pItem->SetQuantity( MAX( 1, pItemDef->GetDefaultDropQuantity() ) );
|
||||
|
||||
// Startup test code calls this with a null pGameAccount.
|
||||
if ( pGameAccount != NULL )
|
||||
{
|
||||
pItem->SetAccountID( pGameAccount->Obj().m_unAccountID );
|
||||
|
||||
// Add any custom attributes we need
|
||||
if( !BAddGCGeneratedAttributesToItem( pGameAccount, pItem ) )
|
||||
{
|
||||
delete pItem;
|
||||
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Failed to generate attributes\n" );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Randomly chooses an item definition that matches the criteria
|
||||
// Input: sCriteria - The criteria that the generated item must match
|
||||
// Output: The chosen item definition, or NULL if no item could be selected
|
||||
//-----------------------------------------------------------------------------
|
||||
const CEconItemDefinition *CEconItemFactory::RollItemDefinition( const CItemSelectionCriteria &criteria ) const
|
||||
{
|
||||
// Determine which item templates match the criteria
|
||||
CUtlVector<item_definition_index_t> vecMatches;
|
||||
const CEconItemSchema::ItemDefinitionMap_t &mapDefs = m_schema.GetItemDefinitionMap();
|
||||
|
||||
FOR_EACH_MAP_FAST( mapDefs, i )
|
||||
{
|
||||
if ( criteria.BEvaluate( mapDefs[i] ) )
|
||||
{
|
||||
vecMatches.AddToTail( mapDefs.Key( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 == vecMatches.Count() )
|
||||
return NULL;
|
||||
|
||||
// Choose a random match
|
||||
int iIndex = RandomInt( 0, vecMatches.Count() - 1 );
|
||||
return m_schema.GetItemDefinition( vecMatches[iIndex] );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generates attributes that the item definition insists it always has, but must be generated by the GC
|
||||
// Input:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CEconItemFactory::BAddGCGeneratedAttributesToItem( const CEconGameAccount *pGameAccount, CEconItem *pItem ) const
|
||||
{
|
||||
const CEconItemDefinition *pDef = m_schema.GetItemDefinition( pItem->GetDefinitionIndex() );
|
||||
if ( !pDef )
|
||||
return false;
|
||||
|
||||
const CUtlVector<static_attrib_t> &vecStaticAttribs = pDef->GetStaticAttributes();
|
||||
|
||||
// Only generate attributes that force the GC to generate them (so they vary per item created)
|
||||
FOR_EACH_VEC( vecStaticAttribs, i )
|
||||
{
|
||||
if ( vecStaticAttribs[i].bForceGCToGenerate )
|
||||
{
|
||||
ApplyStaticAttributeToItem( pItem, vecStaticAttribs[i], pGameAccount );
|
||||
}
|
||||
}
|
||||
|
||||
const IEconTool* pTool = pDef->GetEconTool();
|
||||
if( pTool )
|
||||
{
|
||||
if( !pTool->BGenerateDynamicAttributes( pItem, pGameAccount ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !pDef->BApplyPropertyGenerators( pItem ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconItemFactory::ApplyStaticAttributeToItem( CEconItem *pItem, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount ) const
|
||||
{
|
||||
static CSchemaAttributeDefHandle pAttr_ElevateQuality( "elevate quality" );
|
||||
static CSchemaAttributeDefHandle pAttr_ElevateToUnusual( "elevate to unusual if applicable" );
|
||||
|
||||
static CSchemaAttributeDefHandle pAttr_Particle( "attach particle effect" );
|
||||
static CSchemaAttributeDefHandle pAttr_HatUnusual( "hat only unusual effect" );
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_TauntUnusual( "taunt only unusual effect" );
|
||||
static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
|
||||
|
||||
const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( staticAttrib.iDefIndex );
|
||||
Assert( pAttrDef );
|
||||
|
||||
// Special-case the elevate-quality attribute.
|
||||
if ( pAttrDef == pAttr_ElevateQuality )
|
||||
{
|
||||
//AssertMsg( CEconItem::GetTypedAttributeType<CSchemaAttributeType_Default>( pAttrDef ), "Elevate quality attribute doesn't have the right type!" );
|
||||
int iQuality = (int)staticAttrib.m_value.asFloat;
|
||||
|
||||
// Do not change the quality of an item to Strange if it is not basic
|
||||
if ( iQuality == AE_STRANGE )
|
||||
{
|
||||
if ( pItem->GetQuality() == AE_UNIQUE || pItem->GetQuality() == AE_PAINTKITWEAPON || pItem->GetQuality() == AE_NORMAL )
|
||||
{
|
||||
pItem->SetQuality( iQuality );
|
||||
}
|
||||
// If the quality is strange, strangify this item
|
||||
StrangifyItemInPlace( pItem );
|
||||
}
|
||||
else
|
||||
{
|
||||
pItem->SetQuality( iQuality );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
// Special-case to elevate-quality only if item has particles. This 'attr' needs to be added LAST in a lootlist
|
||||
// Or rather after particles may have been granted
|
||||
else if ( pAttrDef == pAttr_ElevateToUnusual )
|
||||
{
|
||||
// Scan all attributes.
|
||||
if ( pItem->FindAttribute( pAttr_Particle ) || pItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
|
||||
{
|
||||
pItem->SetQuality( AE_UNUSUAL );
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if ( pAttrDef == pAttr_HatUnusual )
|
||||
{
|
||||
// Ensure the target item is a hat, if it is not bail, if it is setup a particle effect attr (Whole head items are considered 'hats' for purposes of unusuals )
|
||||
|
||||
if ( !(pItem->GetItemDefinition()->GetEquipRegionMask() & GetItemSchema()->GetEquipRegionBitMaskByName( "hat" ) )
|
||||
&& !(pItem->GetItemDefinition()->GetEquipRegionMask() & GetItemSchema()->GetEquipRegionBitMaskByName( "whole_head" ) )
|
||||
) {
|
||||
// does not match, bail
|
||||
return;
|
||||
}
|
||||
|
||||
// create a new static attrib
|
||||
static_attrib_t unusualAttr( staticAttrib );
|
||||
|
||||
// load the normal attach effect instead
|
||||
pAttr_Particle->GetAttributeType()->LoadOrGenerateEconAttributeValue( pItem, pAttr_Particle, unusualAttr, pGameAccount );
|
||||
return;
|
||||
}
|
||||
else if ( pAttrDef == pAttrDef_TauntUnusual )
|
||||
{
|
||||
// Ensure the target item is a taunt, if it is not bail
|
||||
if ( pItem->GetItemDefinition()->GetLoadoutSlot( 0 ) != LOADOUT_POSITION_TAUNT )
|
||||
{
|
||||
// does not match, bail
|
||||
CFmtStr fmtStr( "Attempted to put an unusual taunt effect onto item %s, but it's not a taunt! Check which lootlists it appears in and remove it from any that are trying to unusualize it!", pItem->GetItemDefinition()->GetItemDefinitionName() );
|
||||
EmitError( SPEW_GC, "%s\n", fmtStr.Get() );
|
||||
return;
|
||||
}
|
||||
|
||||
// create a new static attrib
|
||||
static_attrib_t unusualAttr( staticAttrib );
|
||||
|
||||
// load the normal attach effect instead
|
||||
pAttrDef_TauntUnusualAttr->GetAttributeType()->LoadOrGenerateEconAttributeValue( pItem, pAttrDef_TauntUnusualAttr, unusualAttr, pGameAccount );
|
||||
return;
|
||||
}
|
||||
|
||||
// Custom attribute initialization code?
|
||||
pAttrDef->GetAttributeType()->LoadOrGenerateEconAttributeValue( pItem, pAttrDef, staticAttrib, pGameAccount );
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: EconItemFactory: Manages rolling for items requested by the game server
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECONITEMFACTORY_H
|
||||
#define ECONITEMFACTORY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
class CEconItem;
|
||||
class CEconGameAccount;
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
class CGCSharedObjectCache;
|
||||
}
|
||||
|
||||
#include "game_item_schema.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CEconItemFactory
|
||||
// Factory responsible for rolling random items
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemFactory
|
||||
{
|
||||
public:
|
||||
CEconItemFactory( );
|
||||
|
||||
// Gets a pointer to the underlying item schema the factory is using
|
||||
GameItemSchema_t &GetSchema() { return m_schema; }
|
||||
|
||||
// Create a random item based on the incoming item selection criteria
|
||||
CEconItem *CreateRandomItem( const CEconGameAccount *pGameAccount, const CItemSelectionCriteria &criteria );
|
||||
|
||||
// Create an item from a specific definition index
|
||||
CEconItem *CreateSpecificItem( const CEconGameAccount *pGameAccount, item_definition_index_t unDefinitionIndex );
|
||||
|
||||
CEconItem *CreateSpecificItem( GCSDK::CGCSharedObjectCache *pUserSOCache, item_definition_index_t unDefinitionIndex )
|
||||
{
|
||||
return CreateSpecificItem( pUserSOCache->GetSingleton<CEconGameAccount>(), unDefinitionIndex );
|
||||
}
|
||||
|
||||
uint64 GetNextID() { Assert( m_bIsInitialized ); return m_ulNextObjID++; }
|
||||
|
||||
bool BYieldingInit();
|
||||
bool BIsInitialized() { return m_bIsInitialized; }
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
virtual void Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
VALIDATE_SCOPE();
|
||||
ValidateObj( m_schema );
|
||||
}
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
|
||||
void ApplyStaticAttributeToItem( CEconItem *pItem, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount ) const;
|
||||
const CEconItemDefinition *RollItemDefinition( const CItemSelectionCriteria &criteria ) const;
|
||||
|
||||
private:
|
||||
bool BAddGCGeneratedAttributesToItem( const CEconGameAccount *pGameAccount, CEconItem *pItem ) const;
|
||||
|
||||
private:
|
||||
|
||||
// The schema this factory uses to create items
|
||||
GameItemSchema_t m_schema;
|
||||
|
||||
// the next item ID to give out
|
||||
itemid_t m_ulNextObjID;
|
||||
bool m_bIsInitialized;
|
||||
};
|
||||
|
||||
#endif //ECONITEMFACTORY_H
|
||||
@@ -0,0 +1,412 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "econ_item_interface.h"
|
||||
#include "econ_item_tools.h" // needed for CEconTool_WrappedGift definition for IsMarketable()
|
||||
#include "rtime.h"
|
||||
|
||||
#ifdef STAGING_ONLY
|
||||
ConVar tf_paint_kit_force_wear( "tf_paint_kit_force_wear", "0", FCVAR_REPLICATED, "Set to force the wear level of paink kit weapons and ignore the GC dynamic attribute value." );
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
bool IEconItemInterface::GetCustomPaintKitWear( float &flWear ) const
|
||||
{
|
||||
|
||||
#ifdef STAGING_ONLY
|
||||
// don't assert in staging if this ConVar is set
|
||||
if ( tf_paint_kit_force_wear.GetInt() > 0 )
|
||||
{
|
||||
flWear = tf_paint_kit_force_wear.GetFloat();
|
||||
return true;
|
||||
}
|
||||
#endif // STAGING_ONLY
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_PaintKitWear( "set_item_texture_wear" );
|
||||
float flPaintKitWear = 0;
|
||||
if ( pAttrDef_PaintKitWear && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttrDef_PaintKitWear, &flPaintKitWear ) )
|
||||
{
|
||||
flWear = flPaintKitWear;
|
||||
return true;
|
||||
}
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrDef_DefaultWear( "texture_wear_default" );
|
||||
if ( pAttrDef_DefaultWear && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttrDef_DefaultWear, &flPaintKitWear ) )
|
||||
{
|
||||
flWear = flPaintKitWear;
|
||||
return true;
|
||||
}
|
||||
// If you have no wear, you also should not have a paint kit
|
||||
AssertMsg( !GetCustomPainkKitDefinition(), "No Wear Found on Item [%llu - %s] that has a Paintkit!", GetID(), GetItemDefinition()->GetDefinitionName() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
bool IEconItemInterface::IsTemporaryItem() const
|
||||
{
|
||||
// store preview items are also temporary
|
||||
if ( GetOrigin() == kEconItemOrigin_PreviewItem )
|
||||
return true;
|
||||
|
||||
RTime32 rtTime = GetExpirationDate();
|
||||
if ( rtTime > 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
RTime32 IEconItemInterface::GetExpirationDate() const
|
||||
{
|
||||
COMPILE_TIME_ASSERT( sizeof( float ) == sizeof( RTime32 ) );
|
||||
|
||||
// dynamic attributes, if present, will override any static expiration timer
|
||||
static CSchemaAttributeDefHandle pAttrib_ExpirationDate( "expiration date" );
|
||||
|
||||
attrib_value_t unAttribExpirationTimeBits;
|
||||
COMPILE_TIME_ASSERT( sizeof( unAttribExpirationTimeBits ) == sizeof( RTime32 ) );
|
||||
|
||||
if ( pAttrib_ExpirationDate && FindAttribute( pAttrib_ExpirationDate, &unAttribExpirationTimeBits ) )
|
||||
return *(RTime32 *)&unAttribExpirationTimeBits;
|
||||
|
||||
// do we have a static timer set in the schema for all instances to expire?
|
||||
return GetItemDefinition()
|
||||
? GetItemDefinition()->GetExpirationDate()
|
||||
: RTime32( 0 );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
RTime32 IEconItemInterface::GetTradableAfterDateTime() const
|
||||
{
|
||||
static CSchemaAttributeDefHandle pAttrib_TradableAfter( "tradable after date" );
|
||||
Assert( pAttrib_TradableAfter );
|
||||
|
||||
if ( !pAttrib_TradableAfter )
|
||||
return 0;
|
||||
|
||||
RTime32 rtTimestamp;
|
||||
if ( !FindAttribute( pAttrib_TradableAfter, &rtTimestamp ) )
|
||||
return 0;
|
||||
|
||||
return rtTimestamp;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose: Return true if this item can never be traded
|
||||
// --------------------------------------------------------------------------
|
||||
bool IEconItemInterface::IsPermanentlyUntradable() const
|
||||
{
|
||||
if ( GetItemDefinition() == NULL )
|
||||
return true;
|
||||
|
||||
// tagged to not be a part of the economy?
|
||||
if ( ( kEconItemFlag_NonEconomy & GetFlags() ) != 0 )
|
||||
return true;
|
||||
|
||||
// check attributes
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrib_AlwaysTradable( "always tradable" );
|
||||
static CSchemaAttributeDefHandle pAttrib_CannotTrade( "cannot trade" );
|
||||
static CSchemaAttributeDefHandle pAttrib_NonEconomy( "non economy" );
|
||||
|
||||
Assert( pAttrib_AlwaysTradable != NULL );
|
||||
Assert( pAttrib_CannotTrade != NULL );
|
||||
|
||||
if ( pAttrib_AlwaysTradable == NULL || pAttrib_CannotTrade == NULL || pAttrib_NonEconomy == NULL )
|
||||
return true;
|
||||
|
||||
// Order matters, check for nonecon first. Always tradable overrides cannot trade.
|
||||
if ( FindAttribute( pAttrib_NonEconomy ) )
|
||||
return true;
|
||||
|
||||
if ( FindAttribute( pAttrib_AlwaysTradable ) ) // *sigh*
|
||||
return false;
|
||||
|
||||
if ( FindAttribute( pAttrib_CannotTrade ) )
|
||||
return true;
|
||||
|
||||
// items gained in this way are not tradable
|
||||
switch ( GetOrigin() )
|
||||
{
|
||||
case kEconItemOrigin_Invalid:
|
||||
case kEconItemOrigin_Achievement:
|
||||
case kEconItemOrigin_Foreign:
|
||||
case kEconItemOrigin_PreviewItem:
|
||||
case kEconItemOrigin_SteamWorkshopContribution:
|
||||
return true;
|
||||
}
|
||||
|
||||
// temporary items (items that will expire for any reason) cannot be traded
|
||||
if ( IsTemporaryItem() )
|
||||
return true;
|
||||
|
||||
// certain quality levels are not tradable
|
||||
if ( GetQuality() >= AE_COMMUNITY && GetQuality() <= AE_SELFMADE )
|
||||
return true;
|
||||
|
||||
// explicitly marked cannot trade?
|
||||
if ( ( kEconItemFlag_CannotTrade & GetFlags() ) != 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose: Return true if this item is a commodity on the Market (can place buy orders)
|
||||
// --------------------------------------------------------------------------
|
||||
bool IEconItemInterface::IsCommodity() const
|
||||
{
|
||||
if ( GetItemDefinition() == NULL )
|
||||
return false;
|
||||
|
||||
static CSchemaAttributeDefHandle pAttrib_IsCommodity( "is commodity" );
|
||||
if ( FindAttribute( pAttrib_IsCommodity ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose: Return true if temporarily untradable
|
||||
// --------------------------------------------------------------------------
|
||||
bool IEconItemInterface::IsTemporarilyUntradable() const
|
||||
{
|
||||
// Temporary untradability does NOT take "always tradable" into account
|
||||
if ( GetTradableAfterDateTime() >= CRTime::RTime32TimeCur() )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose: Return true if this item is untradable
|
||||
// --------------------------------------------------------------------------
|
||||
bool IEconItemInterface::IsTradable() const
|
||||
{
|
||||
// Items that are expired are never listable, regardless of other rules.
|
||||
//RTime32 timeExpirationDate = GetExpirationDate();
|
||||
//if ( timeExpirationDate > 0 && timeExpirationDate < CRTime::RTime32TimeCur() )
|
||||
// return false;
|
||||
|
||||
return GetUntradabilityFlags() == 0;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose: Return untradability flags
|
||||
// --------------------------------------------------------------------------
|
||||
int IEconItemInterface::GetUntradabilityFlags() const
|
||||
{
|
||||
int nFlags = 0;
|
||||
if ( IsTemporarilyUntradable() )
|
||||
{
|
||||
nFlags |= k_Untradability_Temporary;
|
||||
}
|
||||
|
||||
if ( IsPermanentlyUntradable() )
|
||||
{
|
||||
nFlags |= k_Untradability_Permanent;
|
||||
}
|
||||
|
||||
return nFlags;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
bool IEconItemInterface::IsUsableInCrafting() const
|
||||
{
|
||||
if ( GetItemDefinition() == NULL )
|
||||
return false;
|
||||
|
||||
// tagged to not be a part of the economy?
|
||||
if ( ( kEconItemFlag_NonEconomy & GetFlags() ) != 0 )
|
||||
return false;
|
||||
|
||||
// always craftable?
|
||||
static CSchemaAttributeDefHandle pAttrib_AlwaysUsableInCraft( "always tradable" );
|
||||
Assert( pAttrib_AlwaysUsableInCraft );
|
||||
|
||||
if ( FindAttribute( pAttrib_AlwaysUsableInCraft ) )
|
||||
return true;
|
||||
|
||||
// never craftable?
|
||||
static CSchemaAttributeDefHandle pAttrib_NeverCraftable( "never craftable" );
|
||||
Assert( pAttrib_NeverCraftable );
|
||||
|
||||
if ( FindAttribute( pAttrib_NeverCraftable ) )
|
||||
return false;
|
||||
|
||||
// temporary items (items that will expire for any reason) cannot be turned into
|
||||
// permanent items
|
||||
if ( IsTemporaryItem() )
|
||||
return false;
|
||||
|
||||
// explicitly marked not usable in crafting?
|
||||
if ( ( kEconItemFlag_CannotBeUsedInCrafting & GetFlags() ) != 0 )
|
||||
return false;
|
||||
|
||||
// items gained in this way are not craftable
|
||||
switch ( GetOrigin() )
|
||||
{
|
||||
case kEconItemOrigin_Invalid:
|
||||
case kEconItemOrigin_Foreign:
|
||||
case kEconItemOrigin_StorePromotion:
|
||||
case kEconItemOrigin_SteamWorkshopContribution:
|
||||
return false;
|
||||
|
||||
// purchased items can be used in crafting if explicitly tagged, but not by default
|
||||
case kEconItemOrigin_Purchased:
|
||||
// deny items the GC didn't flag at purchase time
|
||||
if ( (GetFlags() & kEconItemFlag_PurchasedAfterStoreCraftabilityChanges2012) == 0 )
|
||||
return false;
|
||||
|
||||
// deny items that can never be used
|
||||
if ( (GetItemDefinition()->GetCapabilities() & ITEM_CAP_CAN_BE_CRAFTED_IF_PURCHASED) == 0 )
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// certain quality levels are not craftable
|
||||
if ( GetQuality() >= AE_COMMUNITY && GetQuality() <= AE_SELFMADE )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
bool IEconItemInterface::IsMarketable() const
|
||||
{
|
||||
const CEconItemDefinition *pItemDef = GetItemDefinition();
|
||||
if ( pItemDef == NULL )
|
||||
return false;
|
||||
|
||||
// Untradeable items can never be marketed, regardless of other rules.
|
||||
// Temporarily untradable items can be marketed, only permanent untradable items cannot be marketed
|
||||
if ( IsPermanentlyUntradable() )
|
||||
return false;
|
||||
|
||||
// Items that are expired are never listable, regardless of other rules.
|
||||
RTime32 timeExpirationDate = GetExpirationDate();
|
||||
if ( timeExpirationDate > 0 && timeExpirationDate < CRTime::RTime32TimeCur() )
|
||||
return false;
|
||||
|
||||
// Initially, only TF2 supports listing items in the Marketplace.
|
||||
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
|
||||
{
|
||||
// User-created wrapped gifts are untradeable for the moment. This would provide a backdoor
|
||||
// for users to sell anything they wanted, which is interesting but not what we want in
|
||||
// the initial launch.
|
||||
if ( pItemDef->GetTypedEconTool<CEconTool_WrappedGift>() )
|
||||
return false;
|
||||
|
||||
// All other tools are listable. This includes keys, paints, backpack expanders, strange
|
||||
// parts, Halloween spells, wedding rings, etc. It does not includes gifts (see above),
|
||||
// noisemakers, or crates (see below).
|
||||
if ( pItemDef->IsTool() )
|
||||
return true;
|
||||
|
||||
// All crates are listable. Anything with the "decodable" flag is considered a crate.
|
||||
if ( (pItemDef->GetCapabilities() & ITEM_CAP_DECODABLE) != 0 )
|
||||
return true;
|
||||
|
||||
// Genuine-quality items come from time-limited purchase promos and are listable. Vintage
|
||||
// items are from one-time transitions and are all finite quality. Haunted quality items are
|
||||
// TF-Halloween-event specific. Some of the older haunted items didn't generate revenue, but
|
||||
// the content is all old and there seems to be little harm in letting it be listed. The
|
||||
// haunted items from 2013 all come from crates, which means they all generated revenue.
|
||||
// Collectors items are created from a finite set of recipes.
|
||||
// Paintkit Weapons are from cases or operations
|
||||
if ( GetQuality() == AE_RARITY1 || GetQuality() == AE_VINTAGE || GetQuality() == AE_HAUNTED
|
||||
|| GetQuality() == AE_COLLECTORS || GetQuality() == AE_PAINTKITWEAPON )
|
||||
return true;
|
||||
|
||||
// All festive items are from time-limited holiday crates and are listable. This code seems
|
||||
// safe. (...) (This code is in fact so safe that if we just do a substring match we'll also
|
||||
// allow "A Rather Festive Tree".)
|
||||
if ( !V_strncmp( pItemDef->GetDefinitionName(), "Festive", 7 ) )
|
||||
return true;
|
||||
|
||||
// All botkiller items come from MvM rewards and are listable. This does a substring search
|
||||
// to find all varieties (gold, silver, rust, etc.), etc.
|
||||
if ( V_strstr( pItemDef->GetDefinitionName(), " Botkiller " ) )
|
||||
return true;
|
||||
|
||||
// Mvm V2 Robit Parts
|
||||
if ( V_strstr( pItemDef->GetDefinitionName(), "Robits " ) )
|
||||
return true;
|
||||
|
||||
// MvM Killstreak Weapons
|
||||
static CSchemaAttributeDefHandle pAttr_killstreak( "killstreak tier" );
|
||||
if ( FindAttribute( pAttr_killstreak ) )
|
||||
return true;
|
||||
|
||||
// Australium Items
|
||||
static CSchemaAttributeDefHandle pAttrDef_IsAustralium( "is australium item" );
|
||||
if ( FindAttribute( pAttrDef_IsAustralium ) )
|
||||
return true;
|
||||
|
||||
// Glitch GateHat Replacement Item
|
||||
static CSchemaItemDefHandle pItemDef_GlitchedCircuit( "Glitched Circuit Board" );
|
||||
if ( pItemDef == pItemDef_GlitchedCircuit )
|
||||
return true;
|
||||
|
||||
// Anything that says it wants to be marketable.
|
||||
static CSchemaAttributeDefHandle pAttrDef_IsMarketable( "is marketable" );
|
||||
if ( FindAttribute( pAttrDef_IsMarketable ) )
|
||||
return true;
|
||||
|
||||
// Anything that is of limited quantity (ie limited promos)
|
||||
static CSchemaAttributeDefHandle pAttrDef_IsLimited( "limited quantity item" );
|
||||
if ( FindAttribute( pAttrDef_IsLimited ) )
|
||||
return true;
|
||||
|
||||
// Allow the Giving items (not a wrapped_gift but a gift, ie Secret Saxton, Pile O Gifts, Pallet of Keys)
|
||||
const CEconTool_Gift *pEconToolGift = pItemDef->GetTypedEconTool<CEconTool_Gift>();
|
||||
if ( pEconToolGift )
|
||||
return true;
|
||||
|
||||
// Unusual Cosmetics and Taunts
|
||||
if ( GetQuality() == AE_UNUSUAL && ( GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MISC || GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_TAUNT ) )
|
||||
return true;
|
||||
|
||||
// Strange items. Dont just check for strange quality, actually check for a strange attribute.
|
||||
// See if we've got any strange attributes.
|
||||
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
|
||||
{
|
||||
if ( FindAttribute( GetKillEaterAttr_Score( i ) ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
|
||||
|
||||
// By default, items aren't listable.
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
const char *IEconItemInterface::GetDefinitionString( const char *pszKeyName, const char *pszDefaultValue ) const
|
||||
{
|
||||
const GameItemDefinition_t *pDef = GetItemDefinition();
|
||||
if ( pDef )
|
||||
return pDef->GetDefinitionString( pszKeyName, pszDefaultValue );
|
||||
return pszDefaultValue;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
KeyValues *IEconItemInterface::GetDefinitionKey( const char *pszKeyName ) const
|
||||
{
|
||||
const GameItemDefinition_t *pDef = GetItemDefinition();
|
||||
if ( pDef )
|
||||
return pDef->GetDefinitionKey( pszKeyName );
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,546 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: CEconItem, a shared object for econ items
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECONITEMINTERFACE_H
|
||||
#define ECONITEMINTERFACE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "game_item_schema.h" // needed for GameItemDefinition_t
|
||||
|
||||
class CAttribute_String;
|
||||
class CAttribute_DynamicRecipeComponent;
|
||||
class CAttribute_ItemSlotCriteria;
|
||||
class CAttribute_WorldItemPlacement;
|
||||
class IMaterial;
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Template helper classes for dealing with types.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// StripConstIfPresent<T> will take an input type T and "return" via ResultType:
|
||||
//
|
||||
// - T: T
|
||||
// - const T: T
|
||||
//
|
||||
// This is used to prevent having to have different specializations for "T" versus
|
||||
// "const T" when checking for equivalent template type arguments, etc.
|
||||
template < typename T >
|
||||
struct StripConstIfPresent { typedef T ResultType; };
|
||||
|
||||
template < typename T > struct StripConstIfPresent<const T> { typedef T ResultType; };
|
||||
|
||||
// AreTypesIdentical<T, U> takes two input types and "returns" via kValue whether the
|
||||
// types are exactly equal. This is intended for checking type equivalence at compile-time
|
||||
// in ways that template specializations for functions/classes may not be ideal for.
|
||||
//
|
||||
// We use it in the attribute code to guarantee that we're only doing The Old, Scary Path
|
||||
// when dealing with attributes of The Old, Scary Type.
|
||||
template < typename T, typename U >
|
||||
struct AreTypesIdentical { enum { kValue = false }; };
|
||||
|
||||
template < typename T > struct AreTypesIdentical<T, T> { enum { kValue = true }; };
|
||||
|
||||
// IsPointerType<T> takes one input and "returns" via kValue whether the type is a pointer
|
||||
// type in any way, const, volatile, whatever.
|
||||
template < typename T >
|
||||
struct IsPointerType { enum { kValue = false }; };
|
||||
|
||||
template < typename T > struct IsPointerType<T *> { enum { kValue = true }; };
|
||||
|
||||
// IsValidAttributeValueTypeImpl<T> is a hand-made specialization for what types we want
|
||||
// to consider valid attribute data types. This is used as a sanity check to make sure we
|
||||
// don't pass in completely arbitrary types to things like FindAttribute(). (Doing so
|
||||
// would cause an assert at runtime, but it seems like getting compile-time asserts is
|
||||
// advantageous, and probably worth paying the small cost of adding to this list whenever
|
||||
// a new attribute type is added.)
|
||||
template < typename T>
|
||||
struct IsValidAttributeValueTypeImpl { enum { kValue = false }; };
|
||||
|
||||
template < > struct IsValidAttributeValueTypeImpl<attrib_value_t> { enum { kValue = true }; };
|
||||
template < > struct IsValidAttributeValueTypeImpl<float> { enum { kValue = true }; };
|
||||
template < > struct IsValidAttributeValueTypeImpl<uint64> { enum { kValue = true }; };
|
||||
template < > struct IsValidAttributeValueTypeImpl<CAttribute_String> { enum { kValue = true }; };
|
||||
template < > struct IsValidAttributeValueTypeImpl<CAttribute_DynamicRecipeComponent> { enum { kValue = true }; };
|
||||
template < > struct IsValidAttributeValueTypeImpl < CAttribute_ItemSlotCriteria > { enum { kValue = true }; };
|
||||
template < > struct IsValidAttributeValueTypeImpl < CAttribute_WorldItemPlacement > { enum { kValue = true }; };
|
||||
|
||||
template < typename T >
|
||||
struct IsValidAttributeValueType : public IsValidAttributeValueTypeImpl< typename StripConstIfPresent<T>::ResultType > { };
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Interface for callback functions per-attribute-data-type. When adding
|
||||
// a new attribute data type that can't be converted to any existing type,
|
||||
// you'll need to add a new virtual function here or the code will fail
|
||||
// to compile.
|
||||
//-----------------------------------------------------------------------------
|
||||
class IEconItemAttributeIterator
|
||||
{
|
||||
public:
|
||||
virtual ~IEconItemAttributeIterator ( ) { }
|
||||
|
||||
// Returns whether to continue iteration after this element.
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) = 0;
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value ) = 0;
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64& value ) = 0;
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value ) = 0;
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& value ) = 0;
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria& value ) = 0;
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement& value ) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Iterator where each callback is default implemented, but the value
|
||||
// is ignored. Derive from this iterator when you only care about certain
|
||||
// attribute types.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemSpecificAttributeIterator : public IEconItemAttributeIterator
|
||||
{
|
||||
// By default, always return true
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) { return true; }
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value ) { return true; }
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64& value ) { return true; }
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value ) { return true; }
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& value ) { return true; }
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria& value ) { return true; }
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement& value ) { return true; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Interface for a single callback function per-attribute, regardless of
|
||||
// what type of data it stores and what the value is. This can be used
|
||||
// to count attributes, display generic information about definitions, etc.
|
||||
// but can't be used to pull data.
|
||||
//
|
||||
// To implement a subclass, override the OnIterateAttributeValueUntyped()
|
||||
// method.
|
||||
//-----------------------------------------------------------------------------
|
||||
class IEconItemUntypedAttributeIterator : public IEconItemAttributeIterator
|
||||
{
|
||||
public:
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueUntyped( pAttrDef );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueUntyped( pAttrDef );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64& ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueUntyped( pAttrDef );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueUntyped( pAttrDef );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueUntyped( pAttrDef );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria& ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueUntyped( pAttrDef );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement& ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueUntyped( pAttrDef );
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
virtual bool OnIterateAttributeValueUntyped( const CEconItemAttributeDefinition *pAttrDef ) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Simple class to answer the question "does this attribute exist" without
|
||||
// regards to what value it might have. Intended to be used by FindAttribute()
|
||||
// but made global because why not.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAttributeIterator_HasAttribute : public IEconItemUntypedAttributeIterator
|
||||
{
|
||||
public:
|
||||
CAttributeIterator_HasAttribute( const CEconItemAttributeDefinition *pAttrDef )
|
||||
: m_pAttrDef( pAttrDef )
|
||||
, m_bFound( false )
|
||||
{
|
||||
Assert( m_pAttrDef );
|
||||
}
|
||||
|
||||
bool WasFound() const
|
||||
{
|
||||
return m_bFound;
|
||||
}
|
||||
|
||||
private:
|
||||
bool OnIterateAttributeValueUntyped( const CEconItemAttributeDefinition *pAttrDef ) OVERRIDE
|
||||
{
|
||||
// We don't assert because we might be reusing the same iterator between calls.
|
||||
// Assert( !m_bFound );
|
||||
|
||||
if ( m_pAttrDef == pAttrDef )
|
||||
{
|
||||
m_bFound = true;
|
||||
}
|
||||
|
||||
return !m_bFound;
|
||||
}
|
||||
|
||||
private:
|
||||
const CEconItemAttributeDefinition *m_pAttrDef;
|
||||
bool m_bFound;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Helper class to answer the question "does this attribute exist? and if
|
||||
// so what is its value?". There are some template shenanigans that happen
|
||||
// to make things as safe as possible, and to catch errors as early as
|
||||
// possible.
|
||||
//
|
||||
// TActualTypeInMemory: the in-memory type of the data we're going to try
|
||||
// to read out (ie., "attrib_value_t", "CAttribute_String",
|
||||
// etc.
|
||||
//
|
||||
// TTreatAsThisType: if TActualTypeInMemory is "attrib_value_t", then we're
|
||||
// dealing with the old attribute system and so maybe we
|
||||
// want to treat these bits as a float, or a bitmask, or
|
||||
// who knows! Specifying this type for non-attrib_value_t
|
||||
// in-memory types is invalid and will fail to compile.
|
||||
//
|
||||
// This class isn't intended to be used directly but instead called from
|
||||
// either FindAttribute() or FindAttribute_UnsafeBitwiseCast(). It's
|
||||
// global because C++ doesn't support template member functions on a
|
||||
// template class inside a standalone template function. Weird.
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename TActualTypeInMemory, typename TTreatAsThisType = TActualTypeInMemory >
|
||||
class CAttributeIterator_GetTypedAttributeValue : public IEconItemAttributeIterator
|
||||
{
|
||||
public:
|
||||
CAttributeIterator_GetTypedAttributeValue( const CEconItemAttributeDefinition *pAttrDef, TTreatAsThisType *outpValue )
|
||||
: m_pAttrDef( pAttrDef )
|
||||
, m_outpValue( outpValue )
|
||||
, m_bFound( false )
|
||||
{
|
||||
// If this fails, it means that the type TActualTypeInMemory isn't something the attribute
|
||||
// system is prepared to recognize as a valid attribute storage type. The list of valid types
|
||||
// are IsValidAttributeValueTypeImpl<> specializations.
|
||||
//
|
||||
// If you added a new type and didn't make a specialization for it, this will fail. If you
|
||||
// *didn't* add a new type, it probably means you're passing a pointer of an incorrect type
|
||||
// in to FindAttribute().
|
||||
COMPILE_TIME_ASSERT( IsValidAttributeValueType<TActualTypeInMemory>::kValue );
|
||||
|
||||
// The only reason we allow callers to specify a different TTreatAsThisType (versus having
|
||||
// it always match TActualTypeInMemory) is to deal with the old attribute system, which sometimes
|
||||
// had attributes have int/float types and sometimes had attribute data values that were 32
|
||||
// arbitrary bits. We test here to make sure that we're only using the "treat these bits as
|
||||
// a different type" behavior code when dealing with attributes using the old storage system
|
||||
// (attrib_value_t) or when we're trying to get the pointer to buffer contents for a string.
|
||||
COMPILE_TIME_ASSERT( ((AreTypesIdentical<TActualTypeInMemory, attrib_value_t>::kValue && AreTypesIdentical<TTreatAsThisType, float>::kValue) ||
|
||||
(AreTypesIdentical<TActualTypeInMemory, CAttribute_String>::kValue && AreTypesIdentical<TTreatAsThisType, const char *>::kValue) ||
|
||||
AreTypesIdentical<TActualTypeInMemory, TTreatAsThisType>::kValue) );
|
||||
|
||||
Assert( m_pAttrDef );
|
||||
Assert( outpValue );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueTyped( pAttrDef, value );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueTyped( pAttrDef, value );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64 & value ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueTyped( pAttrDef, value );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String & value ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueTyped( pAttrDef, value );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent & value ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueTyped( pAttrDef, value );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria & value ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueTyped( pAttrDef, value );
|
||||
}
|
||||
|
||||
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement & value ) OVERRIDE
|
||||
{
|
||||
return OnIterateAttributeValueTyped( pAttrDef, value );
|
||||
}
|
||||
|
||||
bool WasFound() const
|
||||
{
|
||||
return m_bFound;
|
||||
}
|
||||
|
||||
private:
|
||||
// Generic template function for handling any attribute value of any type besides the one that we're looking
|
||||
// for. For example, if we say "we're looking for attribute 'damage multiplier' and give me back a float", then
|
||||
// all other attribute value types (strings, structures, etc.) will go through this code, which does nothing
|
||||
// except look for caller errors.
|
||||
//
|
||||
// If you call FindAttribute() and specify the wrong type for an attribute (ie., using the above example, looking
|
||||
// for "damage multiplier" but feeding in a string), it will get found in this function, which will assert and
|
||||
// tell you you've got the wrong type. (FindAttribute() in that case will return false because it's impossible
|
||||
// for us to safely copy the value out.)
|
||||
template < typename TAnyOtherType >
|
||||
bool OnIterateAttributeValueTyped( const CEconItemAttributeDefinition *pAttrDef, const TAnyOtherType& value )
|
||||
{
|
||||
COMPILE_TIME_ASSERT( IsValidAttributeValueType<TAnyOtherType>::kValue );
|
||||
|
||||
// We don't assert because we might be reusing the same iterator between calls.
|
||||
// Assert( !m_bFound );
|
||||
AssertMsg( m_pAttrDef != pAttrDef, "Incorrect type found for attribute during iteration." );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overload for attributes of the data type we're looking for. ie., if we say "we're looking for attribute
|
||||
// 'damage multiplier' and give me back a float", this will be the <float> specialization. We assume that
|
||||
// we're only going to find at most one attribute per definition and stop looking after we've found the first.
|
||||
//
|
||||
// Note that this is just a normal member function, but is *not* a template member function, which would compile
|
||||
// under VC but otherwise be illegal.
|
||||
bool OnIterateAttributeValueTyped( const CEconItemAttributeDefinition *pAttrDef, const TActualTypeInMemory& value )
|
||||
{
|
||||
// We don't assert because we might be reusing the same iterator between calls.
|
||||
// Assert( !m_bFound );
|
||||
|
||||
if ( m_pAttrDef == pAttrDef )
|
||||
{
|
||||
m_bFound = true;
|
||||
CopyAttributeValueToOutput( &value, reinterpret_cast<TTreatAsThisType *>( m_outpValue ) );
|
||||
}
|
||||
|
||||
return !m_bFound;
|
||||
}
|
||||
|
||||
private:
|
||||
static void CopyAttributeValueToOutput( const TActualTypeInMemory *pValue, TTreatAsThisType *out_pValue )
|
||||
{
|
||||
// Even if we are using the old attribute type system, we need to guarantee that the type
|
||||
// in memory (ie., uint32) and the type we're considering it as (ie., float) are the same size
|
||||
// because we're going to be doing bitwise casts.
|
||||
COMPILE_TIME_ASSERT( sizeof( TActualTypeInMemory ) == sizeof( TTreatAsThisType ) );
|
||||
|
||||
Assert( pValue );
|
||||
Assert( out_pValue );
|
||||
|
||||
*out_pValue = *reinterpret_cast<const TTreatAsThisType *>( pValue );
|
||||
}
|
||||
|
||||
private:
|
||||
const CEconItemAttributeDefinition *m_pAttrDef;
|
||||
TTreatAsThisType *m_outpValue;
|
||||
bool m_bFound;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Custom code path to support getting the char * result from an
|
||||
// attribute of type CAttribute_String.
|
||||
//
|
||||
// We can't specify the implementation here because we may or may not
|
||||
// have the definition of CAttribute_String in scope. We also can't
|
||||
// declare the template specialization here and define it later because
|
||||
// that would violate the standard, so instead we have the template
|
||||
// function call a declared-but-not-defined non-template function that
|
||||
// we can define later.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CopyStringAttributeValueToCharPointerOutput( const CAttribute_String *pValue, const char **out_pValue );
|
||||
|
||||
template < >
|
||||
inline void CAttributeIterator_GetTypedAttributeValue<CAttribute_String, const char *>::CopyAttributeValueToOutput( const CAttribute_String *pValue, const char **out_pValue )
|
||||
{
|
||||
CopyStringAttributeValueToCharPointerOutput( pValue, out_pValue );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Look for the existence/nonexistence of an attribute with the
|
||||
// definition [pAttrDef]. Can be called on anything with an IterateAttributes()
|
||||
// member functions (IEconItemInterface, CEconItemDefinition).
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename TAttributeContainerType >
|
||||
bool FindAttribute( const TAttributeContainerType *pSomethingThatHasAnIterateAttributesFunction, const CEconItemAttributeDefinition *pAttrDef )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
VPROF_BUDGET( "IEconItemInterface::FindAttribute", VPROF_BUDGETGROUP_FINDATTRIBUTE );
|
||||
#endif
|
||||
if ( !pAttrDef )
|
||||
return false;
|
||||
|
||||
CAttributeIterator_HasAttribute it( pAttrDef );
|
||||
pSomethingThatHasAnIterateAttributesFunction->IterateAttributes( &it );
|
||||
return it.WasFound();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename TActualTypeInMemory, typename TTreatAsThisType, typename TAttributeContainerType >
|
||||
bool FindAttribute_UnsafeBitwiseCast( const TAttributeContainerType *pSomethingThatHasAnIterateAttributesFunction, const CEconItemAttributeDefinition *pAttrDef, TTreatAsThisType *out_pValue )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
VPROF_BUDGET( "IEconItemInterface::FindAttribute_UnsafeBitwiseCast", VPROF_BUDGETGROUP_FINDATTRIBUTEUNSAFE );
|
||||
#endif
|
||||
if ( !pAttrDef )
|
||||
return false;
|
||||
|
||||
CAttributeIterator_GetTypedAttributeValue<TActualTypeInMemory, TTreatAsThisType> it( pAttrDef, out_pValue );
|
||||
pSomethingThatHasAnIterateAttributesFunction->IterateAttributes( &it );
|
||||
return it.WasFound();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename TAttributeContainerType, typename T >
|
||||
bool FindAttribute( const TAttributeContainerType *pSomethingThatHasAnIterateAttributesFunction, const CEconItemAttributeDefinition *pAttrDef, T *out_pValue )
|
||||
{
|
||||
return FindAttribute_UnsafeBitwiseCast<T, T, TAttributeContainerType>( pSomethingThatHasAnIterateAttributesFunction, pAttrDef, out_pValue );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class IEconItemInterface
|
||||
{
|
||||
public:
|
||||
virtual ~IEconItemInterface() { }
|
||||
|
||||
// Is an attribute present? We neither know nor care anything about the attribute
|
||||
// value stored.
|
||||
bool FindAttribute( const CEconItemAttributeDefinition *pAttrDef ) const
|
||||
{
|
||||
return ::FindAttribute( this, pAttrDef );
|
||||
}
|
||||
|
||||
// If an attribute is present, it will copy the value into out_pValue and return true.
|
||||
// If the attribute is not present, it will return false and not touch the value in
|
||||
// out_pValue. If a T is passed in that is not a type the attribute system understands,
|
||||
// this function will fail to compile.
|
||||
template < typename T >
|
||||
bool FindAttribute( const CEconItemAttributeDefinition *pAttrDef, T *out_pValue ) const
|
||||
{
|
||||
return ::FindAttribute( this, pAttrDef, out_pValue );
|
||||
}
|
||||
|
||||
// Helpers to look for specific attribute values
|
||||
virtual CEconItemPaintKitDefinition *GetCustomPainkKitDefinition( void ) const { return GetItemDefinition() ? GetItemDefinition()->GetCustomPainkKitDefinition() : NULL; }
|
||||
virtual bool GetCustomPaintKitWear( float &flWear ) const;
|
||||
|
||||
// IEconItemInterface common implementation.
|
||||
virtual bool IsTradable() const;
|
||||
virtual int GetUntradabilityFlags() const;
|
||||
virtual bool IsCommodity() const;
|
||||
virtual bool IsUsableInCrafting() const;
|
||||
virtual bool IsMarketable() const; // can this item be listed on the Marketplace?
|
||||
|
||||
bool IsTemporaryItem() const; // returns whether this item is a temporary instance of an item that is not by nature temporary (ie., a preview item, an item with an attribute expiration timer)
|
||||
RTime32 GetExpirationDate() const; // will return RTime32( 0 ) if this item will not expire, otherwise the time that it will auto-delete itself; this looks at both static and dynamic ways of expiring timers
|
||||
|
||||
// IEconItemInterface interface.
|
||||
virtual const GameItemDefinition_t *GetItemDefinition() const = 0;
|
||||
|
||||
virtual itemid_t GetID() const = 0; // intentionally not called GetItemID to avoid stomping non-virtual GetItemID() on CEconItem
|
||||
virtual uint32 GetAccountID() const = 0;
|
||||
virtual int32 GetQuality() const = 0;
|
||||
virtual style_index_t GetStyle() const = 0;
|
||||
virtual uint8 GetFlags() const = 0;
|
||||
virtual eEconItemOrigin GetOrigin() const = 0;
|
||||
virtual int GetQuantity() const = 0;
|
||||
virtual uint32 GetItemLevel() const = 0;
|
||||
virtual bool GetInUse() const = 0; // is this item in use somewhere in the backend? (ie., cross-game trading)
|
||||
|
||||
virtual const char *GetCustomName() const = 0; // get a user-generated name, if present, otherwise NULL; return value is UTF8
|
||||
virtual const char *GetCustomDesc() const = 0; // get a user-generated flavor text, if present, otherwise NULL; return value is UTF8
|
||||
|
||||
// IEconItemInterface attribute iteration interface. This is not meant to be used for
|
||||
// attribute lookup! This is meant for anything that requires iterating over the full
|
||||
// attribute list.
|
||||
virtual void IterateAttributes( IEconItemAttributeIterator *pIterator ) const = 0;
|
||||
|
||||
// Fetch values from the definition
|
||||
const char *GetDefinitionString( const char *pszKeyName, const char *pszDefaultValue = "" ) const;
|
||||
KeyValues *GetDefinitionKey( const char *pszKeyName ) const;
|
||||
|
||||
RTime32 GetTradableAfterDateTime() const;
|
||||
|
||||
virtual item_definition_index_t GetItemDefIndex() const { return GetItemDefinition() ? GetItemDefinition()->GetDefinitionIndex() : INVALID_ITEM_DEF_INDEX; }
|
||||
|
||||
virtual IMaterial* GetMaterialOverride( int iTeam ) = 0;
|
||||
|
||||
protected:
|
||||
bool IsPermanentlyUntradable() const;
|
||||
bool IsTemporarilyUntradable() const;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Classes that want default behavior for GetMaterialOverride, which
|
||||
// currently derive from IEconItemInterface can instead derive from
|
||||
// CMaterialOverrideContainer< IEconItemInterface > and have the details
|
||||
// of material overrides hidden from them.
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename TBaseClass>
|
||||
class CMaterialOverrideContainer : public TBaseClass
|
||||
{
|
||||
public:
|
||||
virtual IMaterial* GetMaterialOverride( int iTeam ) OVERRIDE
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
Assert( iTeam >= 0 && iTeam < ARRAYSIZE( m_materialOverrides ) );
|
||||
|
||||
if ( m_materialOverrides[ iTeam ].IsValid() )
|
||||
return m_materialOverrides[ iTeam ];
|
||||
|
||||
if ( !this->GetItemDefinition() )
|
||||
return NULL;
|
||||
|
||||
const char* pName = this->GetItemDefinition()->GetMaterialOverride( iTeam );
|
||||
if ( pName == NULL )
|
||||
return NULL;
|
||||
|
||||
m_materialOverrides[ iTeam ].Init( pName, TEXTURE_GROUP_CLIENT_EFFECTS );
|
||||
return m_materialOverrides[ iTeam ];
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
void ResetMaterialOverrides()
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
for ( int i = 0; i < TF_TEAM_COUNT; ++i )
|
||||
m_materialOverrides[ i ].Shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef CLIENT_DLL
|
||||
CMaterialReference m_materialOverrides[ TF_TEAM_COUNT ];
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // ECONITEMINTERFACE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,472 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Container that allows client & server access to data in player inventories & loadouts
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ITEM_INVENTORY_H
|
||||
#define ITEM_INVENTORY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "igamesystem.h"
|
||||
#include "econ_entity.h"
|
||||
#include "gamestringpool.h"
|
||||
#include "econ_item_view.h"
|
||||
#include "UtlSortVector.h"
|
||||
#include "econ_gcmessages.h"
|
||||
#include "gc_clientsystem.h"
|
||||
|
||||
#if !defined(NO_STEAM)
|
||||
#include "steam/steam_api.h"
|
||||
#include "gcsdk/gcclientsdk.h"
|
||||
#endif // NO_STEAM
|
||||
|
||||
|
||||
class CPlayerInventory;
|
||||
class CEconItem;
|
||||
struct baseitemcriteria_t;
|
||||
class CEconItemViewHandle;
|
||||
#ifdef CLIENT_DLL
|
||||
class ITexture;
|
||||
#endif
|
||||
|
||||
// Inventory Less function.
|
||||
// Used to sort the inventory items into their positions.
|
||||
class CInventoryListLess
|
||||
{
|
||||
public:
|
||||
bool Less( const CEconItemView &src1, const CEconItemView &src2, void *pCtx );
|
||||
};
|
||||
|
||||
// A class that wants notifications when an inventory is updated
|
||||
class IInventoryUpdateListener : public GCSDK::ISharedObjectListener
|
||||
{
|
||||
public:
|
||||
virtual void InventoryUpdated( CPlayerInventory *pInventory ) = 0;
|
||||
|
||||
virtual void SOCreated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
|
||||
virtual void PreSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
|
||||
virtual void SOUpdated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
|
||||
virtual void PostSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
|
||||
virtual void SODestroyed( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
|
||||
virtual void SOCacheSubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
|
||||
virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A single player's inventory.
|
||||
// On the client, the inventory manager contains an instance of this for the local player.
|
||||
// On the server, each player contains an instance of this.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CPlayerInventory : public GCSDK::ISharedObjectListener
|
||||
{
|
||||
DECLARE_CLASS_NOBASE( CPlayerInventory );
|
||||
public:
|
||||
CPlayerInventory();
|
||||
virtual ~CPlayerInventory();
|
||||
|
||||
void Clear();
|
||||
|
||||
// Returns true if this inventory has been filled out by Steam.
|
||||
bool RetrievedInventoryFromSteam( void ) { return m_bGotItemsFromSteam; }
|
||||
bool IsWaitingForSteam( void ) { return (m_iPendingRequests > 0); }
|
||||
|
||||
// Inventory access
|
||||
CSteamID &GetOwner( void ) { return m_OwnerID; }
|
||||
int GetItemCount( void ) const { return m_aInventoryItems.Count(); }
|
||||
virtual bool CanPurchaseItems( int iItemCount ) const { return GetMaxItemCount() - GetItemCount() >= iItemCount; }
|
||||
virtual int GetMaxItemCount( void ) const { return DEFAULT_NUM_BACKPACK_SLOTS; }
|
||||
CEconItemView *GetItem( int i ) { return &m_aInventoryItems[i]; }
|
||||
|
||||
virtual CEconItemView *GetItemInLoadout( int iClass, int iSlot ) { AssertMsg( 0, "Implement me!" ); return NULL; }
|
||||
|
||||
// Get the item object cache data for the specified item
|
||||
CEconItem *GetSOCDataForItem( itemid_t iItemID );
|
||||
GCSDK::CGCClientSharedObjectCache *GetSOC( void ) { return m_pSOCache; }
|
||||
|
||||
// tells the GC systems to forget about this listener
|
||||
void RemoveListener( GCSDK::ISharedObjectListener *pListener );
|
||||
|
||||
// Finds the item in our inventory that matches the specified global index
|
||||
CEconItemView *GetInventoryItemByItemID( itemid_t iIndex, int *pIndex = NULL );
|
||||
|
||||
// Finds the item in our inventory that matches the specified global original id
|
||||
CEconItemView *GetInventoryItemByOriginalID( itemid_t iOriginalID, int *pIndex = NULL );
|
||||
|
||||
// Finds the item in our inventory in the specified position
|
||||
CEconItemView *GetItemByPosition( int iPosition, int *pIndex = NULL );
|
||||
|
||||
// Finds the first item in our backpack with match itemdef
|
||||
CEconItemView *FindFirstItembyItemDef( item_definition_index_t iItemDef );
|
||||
|
||||
// Used to reject items on the backend for inclusion into this inventory.
|
||||
// Mostly used for division of bags into different in-game inventories.
|
||||
virtual bool ItemShouldBeIncluded( int iItemPosition ) { return true; }
|
||||
|
||||
// Debugging
|
||||
virtual void DumpInventoryToConsole( bool bRoot );
|
||||
|
||||
// Extracts the position that should be used to sort items in the inventory from the backend position.
|
||||
// Necessary if your inventory packs a bunch of info into the position instead of using it just as a position.
|
||||
virtual int ExtractInventorySortPosition( uint32 iBackendPosition ) { return iBackendPosition; }
|
||||
|
||||
// Recipe access
|
||||
int GetRecipeCount( void ) const;
|
||||
const CEconCraftingRecipeDefinition *GetRecipeDef( int iIndex );
|
||||
const CEconCraftingRecipeDefinition *GetRecipeDefByDefIndex( uint16 iDefIndex );
|
||||
|
||||
// Item previews
|
||||
virtual int GetPreviewItemDef( void ) const { return 0; };
|
||||
|
||||
// Access helpers
|
||||
virtual void SOClear();
|
||||
|
||||
virtual void NotifyHasNewItems() {}
|
||||
|
||||
void AddItemHandle( CEconItemViewHandle* pHandle );
|
||||
void RemoveItemHandle( CEconItemViewHandle* pHandle );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual ITexture *GetWeaponSkinBaseLowRes( itemid_t nItemId, int iTeam ) const { return NULL; }
|
||||
#endif
|
||||
|
||||
|
||||
protected:
|
||||
// Inventory updating, called by the Inventory Manager only. If you want an inventory updated,
|
||||
// use the SteamRequestX functions in CInventoryManager.
|
||||
void RequestInventory( CSteamID pSteamID );
|
||||
void AddListener( GCSDK::ISharedObjectListener *pListener );
|
||||
virtual bool AddEconItem( CEconItem * pItem, bool bUpdateAckFile, bool bWriteAckFile, bool bCheckForNewItems );
|
||||
virtual void RemoveItem( itemid_t iItemID );
|
||||
bool FilloutItemFromEconItem( CEconItemView *pScriptItem, CEconItem *pEconItem );
|
||||
void SendInventoryUpdateEvent();
|
||||
virtual void OnHasNewItems() {}
|
||||
virtual void OnItemChangedPosition( CEconItemView *pItem, uint32 iOldPos ) { return; }
|
||||
|
||||
virtual void SOCreated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||||
virtual void PreSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
|
||||
virtual void SOUpdated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||||
virtual void PostSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
|
||||
virtual void SODestroyed( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||||
virtual void SOCacheSubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||||
virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||||
|
||||
void ResortInventory( void ) { m_aInventoryItems.RedoSort( true ); }
|
||||
virtual void ValidateInventoryPositions( void );
|
||||
|
||||
// Derived inventory hooks
|
||||
virtual void ItemHasBeenUpdated( CEconItemView *pItem, bool bUpdateAckFile, bool bWriteAckFile );
|
||||
virtual void ItemIsBeingRemoved( CEconItemView *pItem ) { return; }
|
||||
|
||||
// Get the index for the item in our inventory utlvector
|
||||
int GetIndexForItem( CEconItemView *pItem );
|
||||
|
||||
void DirtyItemHandles();
|
||||
|
||||
protected:
|
||||
// The Steam Id of the player who owns this inventory
|
||||
CSteamID m_OwnerID;
|
||||
|
||||
// The items the player has in his inventory, received from steam.
|
||||
CUtlSortVector<CEconItemView,CInventoryListLess> m_aInventoryItems;
|
||||
|
||||
int m_iPendingRequests;
|
||||
bool m_bGotItemsFromSteam;
|
||||
|
||||
GCSDK::CGCClientSharedObjectCache *m_pSOCache;
|
||||
|
||||
CUtlVector<GCSDK::ISharedObjectListener *> m_vecListeners;
|
||||
|
||||
CUtlVector< CEconItemViewHandle* > m_vecItemHandles;
|
||||
|
||||
friend class CInventoryManager;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInventoryManager : public CAutoGameSystemPerFrame
|
||||
{
|
||||
DECLARE_CLASS_GAMEROOT( CInventoryManager, CAutoGameSystem );
|
||||
public:
|
||||
CInventoryManager( void );
|
||||
|
||||
// Adds the inventory to the list of inventories that should be maintained.
|
||||
// This causes the game to load the items for the SteamID into this inventory.
|
||||
// NOTE: This fires off a request to Steam. The data will not be filled out immediately.
|
||||
void SteamRequestInventory( CPlayerInventory *pInventory, CSteamID pSteamID, IInventoryUpdateListener *pListener = NULL );
|
||||
|
||||
void PreInitGC();
|
||||
void PostInitGC();
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
void DropItem( itemid_t iItemID );
|
||||
int DeleteUnknowns( CPlayerInventory *pInventory );
|
||||
#endif
|
||||
|
||||
public:
|
||||
//-----------------------------------------------------------------------
|
||||
// IAutoServerSystem
|
||||
//-----------------------------------------------------------------------
|
||||
virtual bool Init( void ) OVERRIDE;
|
||||
virtual void PostInit( void ) OVERRIDE;
|
||||
virtual void Shutdown() OVERRIDE;
|
||||
virtual void LevelInitPreEntity( void ) OVERRIDE;
|
||||
virtual void LevelShutdownPostEntity( void ) OVERRIDE;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
// Gets called each frame
|
||||
virtual void Update( float frametime ) OVERRIDE;
|
||||
#endif
|
||||
|
||||
void GameServerSteamAPIActivated();
|
||||
|
||||
virtual CPlayerInventory *GetInventoryForAccount( uint32 iAccountID );
|
||||
|
||||
// We're generating a base item. We need to add the game-specific keys to the criteria so that it'll find the right base item.
|
||||
virtual void AddBaseItemCriteria( baseitemcriteria_t *pCriteria, CItemSelectionCriteria *pSelectionCriteria ) { return; }
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
// Must be implemented by derived class
|
||||
virtual bool EquipItemInLoadout( int iClass, int iSlot, itemid_t iItemID ) = 0;
|
||||
|
||||
virtual CPlayerInventory *GeneratePlayerInventoryObject() const { return new CPlayerInventory; }
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// ITEM PRESETS
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// Is the given preset index valid?
|
||||
bool IsPresetIndexValid( equipped_preset_t unPreset );
|
||||
|
||||
// Equip all items for the given class and preset (all the work is done on the GC -- this just
|
||||
// sends the message up)
|
||||
bool LoadPreset( equipped_class_t unClass, equipped_preset_t unPreset );
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// LOCAL INVENTORY
|
||||
//
|
||||
// On the client, we have a single inventory for the local player. Stored here, instead of in the
|
||||
// local player entity, because players need to access it while not being connected to a server.
|
||||
// Override GetLocalInventory() in your inventory manager and return your custom local inventory.
|
||||
//-----------------------------------------------------------------------
|
||||
virtual void UpdateLocalInventory( void );
|
||||
virtual CPlayerInventory *GetLocalInventory( void ) { return NULL; }
|
||||
|
||||
// The local inventory is used to track discards & responses to. We need to
|
||||
// make a decision about inventory space right after sending a delete request,
|
||||
// so we predict the request will work.
|
||||
void OnItemDeleted( CPlayerInventory *pInventory ) { if ( pInventory == GetLocalInventory() ) m_iPredictedDiscards--; }
|
||||
|
||||
virtual void PersonaName_Precache( uint32 unAccountID );
|
||||
virtual const char *PersonaName_Get( uint32 unAccountID );
|
||||
virtual void PersonaName_Store( uint32 unAccountID, const char *pPersonaName );
|
||||
|
||||
static void SendGCConnectedEvent( void );
|
||||
|
||||
// Returns the item at the specified backpack position
|
||||
virtual CEconItemView *GetItemByBackpackPosition( int iBackpackPosition );
|
||||
|
||||
// Moves the item to the specified backpack position. If there's another item as that spot, it swaps positions with it.
|
||||
virtual void MoveItemToBackpackPosition( CEconItemView *pItem, int iBackpackPosition );
|
||||
|
||||
// Tries to set the item to the specified backpack position. Passing in 0 will find the first empty position.
|
||||
// FAILS if the backpack is full, or if that spot isn't clear. Returns false in that case.
|
||||
virtual bool SetItemBackpackPosition( CEconItemView *pItem, uint32 iPosition = 0, bool bForceUnequip = false, bool bAllowOverflow = false );
|
||||
|
||||
// Sort the backpack items by the specified type
|
||||
virtual void SortBackpackBy( uint32 iSortType );
|
||||
void SortBackpackFinished( void );
|
||||
bool IsInBackpackSort( void ) { return m_bInBackpackSort; }
|
||||
|
||||
void PredictedBackpackPosFilled( int iBackpackPos ) { m_PredictedFilledSlots.FindAndRemove( iBackpackPos ); }
|
||||
|
||||
// Tell the backend to move an item to a specified backend position
|
||||
virtual void UpdateInventoryPosition( CPlayerInventory *pInventory, uint64 ulItemID, uint32 unNewInventoryPos );
|
||||
|
||||
virtual void UpdateInventoryEquippedState( CPlayerInventory *pInventory, uint64 ulItemID, equipped_class_t unClass, equipped_slot_t unSlot );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// CLIENT PICKUP UI HANDLING
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// Get the number of items picked up
|
||||
virtual int GetNumItemPickedUpItems( void ) { return 0; }
|
||||
|
||||
// Show the player a pickup screen with any items they've collected recently, if any
|
||||
virtual bool ShowItemsPickedUp( bool bForce = false, bool bReturnToGame = true, bool bNoPanel = false );
|
||||
|
||||
// Show the player a pickup screen with the items they've crafted
|
||||
virtual void ShowItemsCrafted( CUtlVector<itemid_t> *vecCraftedIndices ) { return; }
|
||||
|
||||
// Force the player to discard an item to make room for a new item, if they have one.
|
||||
// Returns true if the discard panel has been brought up, and the player will be forced to discard an item.
|
||||
virtual bool CheckForRoomAndForceDiscard( void );
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// CLIENT ITEM PICKUP ACKNOWLEDGEMENT FILES
|
||||
//
|
||||
// This system avoids showing multiple pickups for items that we've found, but haven't been
|
||||
// able to move out of unack'd position due to the GC being unavailable. We keep a list of
|
||||
// items we've ack'd in a client file, and don't re-show pickups for them. When a GC item
|
||||
// update tells us the item has moved out of the unack'd position, we remove it from our file.
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
virtual void AcknowledgeItem ( CEconItemView *pItem, bool bMoveToBackpack = true ); // Client Acknowledges an item and moves it in to the backpack
|
||||
bool HasBeenAckedByClient( CEconItemView *pItem ); // Returns true if it's in our client file
|
||||
void SetAckedByClient( CEconItemView *pItem ); // Adds it to our client file
|
||||
void SetAckedByGC( CEconItemView *pItem, bool bSave ); // Removes it from our client file
|
||||
KeyValues *GetAckKeyForItem( CEconItemView *pItem );
|
||||
void CleanAckFile( void );
|
||||
void SaveAckFile( void );
|
||||
|
||||
private:
|
||||
void VerifyAckFileLoaded( void );
|
||||
KeyValues *m_pkvItemClientAckFile;
|
||||
bool m_bClientAckDirty;
|
||||
|
||||
private:
|
||||
// As we move items around in batches (on pickups usually) we need to know what slots will be filled
|
||||
// by items we've moved, and haven't received a response from Steam.
|
||||
CUtlVector<int> m_PredictedFilledSlots;
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual int GetBackpackPositionFromBackend( uint32 iBackendPosition ) { return ExtractBackpackPositionFromBackend(iBackendPosition); }
|
||||
|
||||
private:
|
||||
//-----------------------------------------------------------------------
|
||||
// Pending inventory requests
|
||||
struct pendingreq_t
|
||||
{
|
||||
CPlayerInventory *pInventory;
|
||||
CSteamID pID;
|
||||
};
|
||||
CUtlVector<pendingreq_t> m_hPendingInventoryRequests;
|
||||
void RemovePendingRequest( CSteamID *pSteamID );
|
||||
|
||||
protected:
|
||||
//-----------------------------------------------------------------------
|
||||
// Inventory registry
|
||||
void DeregisterInventory( CPlayerInventory *pInventory );
|
||||
struct inventories_t
|
||||
{
|
||||
CPlayerInventory *pInventory;
|
||||
IInventoryUpdateListener *pListener;
|
||||
};
|
||||
CUtlVector<inventories_t> m_pInventories;
|
||||
|
||||
friend class CPlayerInventory;
|
||||
|
||||
inline bool IsValidPlayerClass( equipped_class_t unClass );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
// Keep track of the number of items we've tried to discard, but haven't recieved responses on
|
||||
int m_iPredictedDiscards;
|
||||
|
||||
typedef CUtlMap< uint32, CUtlString, int > tPersonaNamesByAccountID;
|
||||
tPersonaNamesByAccountID m_mapPersonaNamesCache;
|
||||
|
||||
bool m_bInBackpackSort;
|
||||
|
||||
float m_flNextLoadPresetChange;
|
||||
|
||||
CMsgSetItemPositions m_msgPendingSetItemPositions;
|
||||
CMsgLookupMultipleAccountNames m_msgPendingLookupAccountNames;
|
||||
|
||||
void OnPersonaStateChanged( PersonaStateChange_t *info );
|
||||
CCallback< CInventoryManager, PersonaStateChange_t, false > m_sPersonaStateChangedCallback;
|
||||
CUtlMap< uint64, bool > m_personaNameRequests;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
//=================================================================================
|
||||
// Implement these functions in your game code to create custom derived versions
|
||||
CInventoryManager *InventoryManager( void );
|
||||
|
||||
CBasePlayer *GetPlayerBySteamID( const CSteamID &steamID );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Maintains a handle to an CEconItemView within an inventory. When
|
||||
// the inventory gets updated and shuffles CEconItemViews around, this
|
||||
// handle automatically updates its pointer to point to the new
|
||||
// CEconItemView that has the same item_id
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemViewHandle
|
||||
{
|
||||
public:
|
||||
CEconItemViewHandle()
|
||||
: m_pItem( NULL )
|
||||
, m_pInv( NULL )
|
||||
, m_bPointerDirty( false )
|
||||
{}
|
||||
|
||||
CEconItemViewHandle( CEconItemView* pItem )
|
||||
: m_pItem( pItem )
|
||||
, m_pInv( NULL )
|
||||
, m_bPointerDirty( false )
|
||||
{
|
||||
SetItem( pItem );
|
||||
}
|
||||
|
||||
virtual ~CEconItemViewHandle()
|
||||
{
|
||||
// Unregister us
|
||||
if ( m_pInv )
|
||||
{
|
||||
m_pInv->RemoveItemHandle( this );
|
||||
}
|
||||
}
|
||||
|
||||
void SetItem( CEconItemView* pItem );
|
||||
|
||||
operator CEconItemView *( void ) const
|
||||
{
|
||||
return Get();
|
||||
}
|
||||
|
||||
CEconItemView* operator->( void ) const
|
||||
{
|
||||
return Get();
|
||||
}
|
||||
|
||||
void ItemIsBeingDeleted( const CEconItemView* pItem )
|
||||
{
|
||||
m_bPointerDirty = true;
|
||||
|
||||
// Inventory told us the item is going away
|
||||
if ( m_pItem == pItem )
|
||||
{
|
||||
m_pItem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryIsBeingDeleted()
|
||||
{
|
||||
m_pInv = NULL;
|
||||
m_pItem = NULL;
|
||||
m_bPointerDirty = false; // So we dont keep trying to look up the item
|
||||
}
|
||||
|
||||
void MarkDirty()
|
||||
{
|
||||
m_bPointerDirty = true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
CEconItemView* Get() const;
|
||||
|
||||
mutable bool m_bPointerDirty; // Used to mark when m_pItem is no longer valid
|
||||
CPlayerInventory *m_pInv; // Inventory the item belongs to. Used to look up new CEconItemView
|
||||
mutable CEconItemView* m_pItem; // The item.
|
||||
uint64 m_nItemID; // ID of the item
|
||||
CSteamID m_OwnerSteamID; // Steam ID of the item owner
|
||||
};
|
||||
|
||||
|
||||
#endif // ITEM_INVENTORY_H
|
||||
@@ -0,0 +1,338 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
//===================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "econ_item_preset.h"
|
||||
#include "tier1/generichash.h"
|
||||
|
||||
#ifdef GC_DLL
|
||||
#include "gcsdk/sqlaccess/sqlaccess.h"
|
||||
#endif
|
||||
|
||||
using namespace GCSDK;
|
||||
|
||||
#ifdef GC_DLL
|
||||
IMPLEMENT_CLASS_MEMPOOL( CEconItemPerClassPresetData, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
CEconItemPerClassPresetData::CEconItemPerClassPresetData()
|
||||
: m_unAccountID( 0 )
|
||||
, m_unClassID( (equipped_class_t)-1 )
|
||||
, m_unActivePreset( INVALID_PRESET_INDEX )
|
||||
{
|
||||
}
|
||||
|
||||
CEconItemPerClassPresetData::CEconItemPerClassPresetData( uint32 unAccountID, equipped_class_t unClassID )
|
||||
: m_unAccountID( unAccountID )
|
||||
, m_unClassID( unClassID )
|
||||
, m_unActivePreset( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void CEconItemPerClassPresetData::SerializeToProtoBufItem( CSOClassPresetClientData& msgPresetData ) const
|
||||
{
|
||||
msgPresetData.set_account_id( m_unAccountID );
|
||||
msgPresetData.set_class_id( m_unClassID );
|
||||
msgPresetData.set_active_preset_id( m_unActivePreset );
|
||||
}
|
||||
|
||||
void CEconItemPerClassPresetData::DeserializeFromProtoBufItem( const CSOClassPresetClientData &msgPresetData )
|
||||
{
|
||||
m_unAccountID = msgPresetData.account_id();
|
||||
m_unClassID = msgPresetData.class_id();
|
||||
m_unActivePreset = msgPresetData.active_preset_id();
|
||||
}
|
||||
|
||||
bool CEconItemPerClassPresetData::BIsKeyLess( const CSharedObject& soRHS ) const
|
||||
{
|
||||
const CEconItemPerClassPresetData *soPresetData = assert_cast< const CEconItemPerClassPresetData * >( &soRHS );
|
||||
|
||||
Assert( m_unAccountID == soPresetData->m_unAccountID );
|
||||
|
||||
return m_unClassID < soPresetData->m_unClassID;
|
||||
}
|
||||
|
||||
#ifdef GC
|
||||
static bool BYieldingAddPresetItemRowsForSpecificPreset( GCSDK::CSQLAccess &sqlAccess, CSchItemPresetInstance& schItemPresetInstance, const CUtlVector<PresetSlotItem_t>& vecPresetData )
|
||||
{
|
||||
FOR_EACH_VEC( vecPresetData, j )
|
||||
{
|
||||
schItemPresetInstance.m_unSlotID = vecPresetData[j].m_unSlotID;
|
||||
schItemPresetInstance.m_ulItemID = vecPresetData[j].m_ulItemOriginalID;
|
||||
if ( !sqlAccess.BYieldingInsertRecord( &schItemPresetInstance ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEconItemPerClassPresetData::BYieldingAddInsertToTransaction( GCSDK::CSQLAccess &sqlAccess )
|
||||
{
|
||||
// Write out the preset data for our selected items.
|
||||
CSchItemPresetInstance schItemPresetInstance;
|
||||
schItemPresetInstance.m_unAccountID = m_unAccountID;
|
||||
schItemPresetInstance.m_unClassID = m_unClassID;
|
||||
|
||||
for ( int i = 0; i < ARRAYSIZE( m_PresetData ); i++ )
|
||||
{
|
||||
schItemPresetInstance.m_unPresetID = i;
|
||||
|
||||
if ( !BYieldingAddPresetItemRowsForSpecificPreset( sqlAccess, schItemPresetInstance, m_PresetData[i] ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write out the data for which preset is active for this class.
|
||||
CSchSelectedItemPreset schSelectedItemPreset;
|
||||
schSelectedItemPreset.m_unAccountID = m_unAccountID;
|
||||
schSelectedItemPreset.m_unClassID = m_unClassID;
|
||||
schSelectedItemPreset.m_unPresetID = m_unActivePreset;
|
||||
|
||||
if ( !sqlAccess.BYieldingInsertRecord( &schSelectedItemPreset ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEconItemPerClassPresetData::BYieldingAddWriteToTransaction( GCSDK::CSQLAccess &sqlAccess, const CUtlVector< int > &fields )
|
||||
{
|
||||
Assert( sqlAccess.BInTransaction() );
|
||||
|
||||
FOR_EACH_VEC( fields, i )
|
||||
{
|
||||
const int iField = fields[i];
|
||||
|
||||
if ( iField == kPerClassPresetDataDirtyField_ActivePreset )
|
||||
{
|
||||
CSchSelectedItemPreset schSelectedItemPreset;
|
||||
schSelectedItemPreset.m_unAccountID = m_unAccountID;
|
||||
schSelectedItemPreset.m_unClassID = m_unClassID;
|
||||
schSelectedItemPreset.m_unPresetID = m_unActivePreset;
|
||||
|
||||
if ( !sqlAccess.BYieldingUpdateRecord( schSelectedItemPreset, CSET_2_COL( CSchSelectedItemPreset, k_iField_unAccountID, k_iField_unClassID ), CSET_1_COL( CSchSelectedItemPreset, k_iField_unPresetID ) ) )
|
||||
return false;
|
||||
}
|
||||
else if ( iField >= kPerClassPresetDataDirtyField_PresetData_Base )
|
||||
{
|
||||
int iDirtyPreset = iField - kPerClassPresetDataDirtyField_PresetData_Base;
|
||||
Assert( iDirtyPreset >= 0 );
|
||||
Assert( iDirtyPreset < ARRAYSIZE( m_PresetData ) );
|
||||
|
||||
// First, remove any existing rows for this preset.
|
||||
CSchItemPresetInstance schItemPresetInstance;
|
||||
schItemPresetInstance.m_unAccountID = m_unAccountID;
|
||||
schItemPresetInstance.m_unClassID = m_unClassID;
|
||||
schItemPresetInstance.m_unPresetID = iDirtyPreset;
|
||||
|
||||
if ( !sqlAccess.BYieldingDeleteRecords( schItemPresetInstance, CSET_3_COL( CSchItemPresetInstance, k_iField_unAccountID, k_iField_unPresetID, k_iField_unClassID ) ) )
|
||||
return false;
|
||||
|
||||
// Don't write out data for our currently-equipped items. We'll handle these by
|
||||
// writing them out as actually equipped.
|
||||
if ( iDirtyPreset != GetActivePreset() )
|
||||
{
|
||||
// Add our new rows.
|
||||
if ( !BYieldingAddPresetItemRowsForSpecificPreset( sqlAccess, schItemPresetInstance, m_PresetData[iDirtyPreset] ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEconItemPerClassPresetData::BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess &sqlAccess )
|
||||
{
|
||||
CSchItemPresetInstance schItemPresetInstance;
|
||||
schItemPresetInstance.m_unAccountID = m_unAccountID;
|
||||
schItemPresetInstance.m_unClassID = m_unClassID;
|
||||
|
||||
if ( !sqlAccess.BYieldingDeleteRecords( schItemPresetInstance, CSET_2_COL( CSchItemPresetInstance, k_iField_unAccountID, k_iField_unClassID ) ) )
|
||||
return false;
|
||||
|
||||
CSchSelectedItemPreset schSelectedItemPreset;
|
||||
schSelectedItemPreset.m_unAccountID = m_unAccountID;
|
||||
schSelectedItemPreset.m_unClassID = m_unClassID;
|
||||
|
||||
if ( !sqlAccess.BYieldingDeleteRecords( schSelectedItemPreset, CSET_2_COL( CSchSelectedItemPreset, k_iField_unAccountID, k_iField_unClassID ) ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
bool CEconItemPerClassPresetData::BAddToMessage( CUtlBuffer & bufOutput ) const
|
||||
{
|
||||
CSOClassPresetClientData msgClientPresetData;
|
||||
SerializeToProtoBufItem( msgClientPresetData );
|
||||
return CProtoBufSharedObjectBase::SerializeToBuffer( msgClientPresetData, bufOutput );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
bool CEconItemPerClassPresetData::BAddToMessage( std::string *pBuffer ) const
|
||||
{
|
||||
CSOClassPresetClientData msgClientPresetData;
|
||||
SerializeToProtoBufItem( msgClientPresetData );
|
||||
return msgClientPresetData.SerializeToString( pBuffer );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Purpose: Adds just the item ID to the message so that the client can find
|
||||
// which item to destroy
|
||||
//----------------------------------------------------------------------------
|
||||
bool CEconItemPerClassPresetData::BAddDestroyToMessage( CUtlBuffer & bufDestroy ) const
|
||||
{
|
||||
CSOClassPresetClientData msgClientPresetData;
|
||||
msgClientPresetData.set_class_id( m_unClassID );
|
||||
return CProtoBufSharedObjectBase::SerializeToBuffer( msgClientPresetData, bufDestroy );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Purpose: Adds just the item ID to the message so that the client can find
|
||||
// which item to destroy
|
||||
//----------------------------------------------------------------------------
|
||||
bool CEconItemPerClassPresetData::BAddDestroyToMessage( std::string *pBuffer ) const
|
||||
{
|
||||
CSOClassPresetClientData msgClientPresetData;
|
||||
msgClientPresetData.set_class_id( m_unClassID );
|
||||
return msgClientPresetData.SerializeToString( pBuffer );
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CEconItemPerClassPresetData::BParseFromMessage( const CUtlBuffer & buffer )
|
||||
{
|
||||
CSOClassPresetClientData msgClientPresetData;
|
||||
if( !msgClientPresetData.ParseFromArray( buffer.Base(), buffer.TellMaxPut() ) )
|
||||
return false;
|
||||
|
||||
DeserializeFromProtoBufItem( msgClientPresetData );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEconItemPerClassPresetData::BParseFromMessage( const std::string &buffer )
|
||||
{
|
||||
CSOClassPresetClientData msgClientPresetData;
|
||||
if( !msgClientPresetData.ParseFromString( buffer ) )
|
||||
return false;
|
||||
|
||||
DeserializeFromProtoBufItem( msgClientPresetData );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//----------------------------------------------------------------------------
|
||||
bool CEconItemPerClassPresetData::BUpdateFromNetwork( const CSharedObject & objUpdate )
|
||||
{
|
||||
Copy( objUpdate );
|
||||
return true;
|
||||
}
|
||||
|
||||
void CEconItemPerClassPresetData::Copy( const CSharedObject & soRHS )
|
||||
{
|
||||
const CEconItemPerClassPresetData& rhs = static_cast<const CEconItemPerClassPresetData&>( soRHS );
|
||||
|
||||
m_unAccountID = rhs.m_unAccountID;
|
||||
m_unClassID = rhs.m_unClassID;
|
||||
m_unActivePreset = rhs.m_unActivePreset;
|
||||
|
||||
for ( int i = 0; i < ARRAYSIZE( m_PresetData ); i++ )
|
||||
{
|
||||
m_PresetData[i].CopyArray( rhs.m_PresetData[i].Base(), rhs.m_PresetData[i].Count() );
|
||||
}
|
||||
}
|
||||
|
||||
void CEconItemPerClassPresetData::Dump() const
|
||||
{
|
||||
#if 0
|
||||
EmitInfo( SPEW_GC, SPEW_ALWAYS, LOG_ALWAYS, "preset id=%d class id=%d slot id=%d item id=%llu\n",
|
||||
m_unPresetID, m_unClassID, m_unSlotID, m_ulItemID );
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef GC_DLL
|
||||
//----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//----------------------------------------------------------------------------
|
||||
const CUtlVector<PresetSlotItem_t> *CEconItemPerClassPresetData::FindItemsForPresetIndex( equipped_preset_t unPreset ) const
|
||||
{
|
||||
if ( unPreset >= ARRAYSIZE( m_PresetData ) )
|
||||
return NULL;
|
||||
|
||||
return &m_PresetData[ unPreset ];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//----------------------------------------------------------------------------
|
||||
void CEconItemPerClassPresetData::SetActivePreset( equipped_preset_t unPreset )
|
||||
{
|
||||
if ( unPreset >= ARRAYSIZE( m_PresetData ) )
|
||||
return;
|
||||
|
||||
m_unActivePreset = unPreset;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//----------------------------------------------------------------------------
|
||||
void CEconItemPerClassPresetData::EquipItemIntoActivePresetSlot( equipped_slot_t unSlot, itemid_t unOriginalItemID )
|
||||
{
|
||||
Assert( GetItemSchema()->IsValidItemSlot( unSlot, EQUIP_TYPE_CLASS ) );
|
||||
Assert( m_unActivePreset < ARRAYSIZE( m_PresetData ) );
|
||||
|
||||
auto& PresetData = m_PresetData[m_unActivePreset];
|
||||
|
||||
FOR_EACH_VEC( PresetData, i )
|
||||
{
|
||||
if ( PresetData[i].m_unSlotID == unSlot )
|
||||
{
|
||||
// If we're unequipping, stop tracking this slot.
|
||||
if ( unOriginalItemID == INVALID_ITEM_ID )
|
||||
{
|
||||
PresetData.FastRemove( i );
|
||||
}
|
||||
// Otherwise store the current reference.
|
||||
else
|
||||
{
|
||||
PresetData[i].m_ulItemOriginalID = unOriginalItemID;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't expect to get here without having an item equipped already, but it's possible if
|
||||
// items get swapped around on the back end, or if we process messages out of order and/or drop
|
||||
// some.
|
||||
if ( unOriginalItemID != INVALID_ITEM_ID )
|
||||
{
|
||||
PresetSlotItem_t PresetSlotItem;
|
||||
PresetSlotItem.m_unSlotID = unSlot;
|
||||
PresetSlotItem.m_ulItemOriginalID = unOriginalItemID;
|
||||
PresetData.AddToTail( PresetSlotItem );
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//----------------------------------------------------------------------------
|
||||
void CEconItemPerClassPresetData::RemoveAllItemsFromPresetIndex( equipped_preset_t unPreset )
|
||||
{
|
||||
if ( unPreset >= ARRAYSIZE( m_PresetData ) )
|
||||
return;
|
||||
|
||||
m_PresetData[unPreset].Purge();
|
||||
}
|
||||
#endif // GC_DLL
|
||||
@@ -0,0 +1,102 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
//===================================================================
|
||||
|
||||
#ifndef ECONITEMPRESET_H
|
||||
#define ECONITEMPRESET_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "gcsdk/protobufsharedobject.h"
|
||||
#include "gcsdk/gcclientsdk.h"
|
||||
#include "base_gcmessages.pb.h"
|
||||
|
||||
#include "econ/econ_item_constants.h"
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
class CSQLAccess;
|
||||
};
|
||||
|
||||
class CSOClassPresetClientData;
|
||||
|
||||
typedef uint8 equipped_preset_t;
|
||||
|
||||
struct PresetSlotItem_t
|
||||
{
|
||||
#ifdef GC_DLL
|
||||
DECLARE_CLASS_MEMPOOL( PresetSlotItem_t );
|
||||
#endif
|
||||
|
||||
equipped_slot_t m_unSlotID;
|
||||
itemid_t m_ulItemOriginalID; // Original ID of the item in this slot. We store this instead of the current ID to avoid breaking presets when items get renamed, etc.
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------------
|
||||
class CEconItemPerClassPresetData : public GCSDK::CSharedObject
|
||||
{
|
||||
#ifdef GC_DLL
|
||||
DECLARE_CLASS_MEMPOOL( CEconItemPerClassPresetData );
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef GCSDK::CSharedObject BaseClass;
|
||||
|
||||
const static int k_nTypeID = k_EEconTypeItemPresetInstance;
|
||||
virtual int GetTypeID() const OVERRIDE { return k_nTypeID; }
|
||||
|
||||
CEconItemPerClassPresetData();
|
||||
CEconItemPerClassPresetData( uint32 unAccountID, equipped_class_t unClassID );
|
||||
|
||||
virtual bool BIsKeyLess( const CSharedObject& soRHS ) const;
|
||||
|
||||
#ifdef GC
|
||||
virtual bool BYieldingAddInsertToTransaction( GCSDK::CSQLAccess &sqlAccess ) OVERRIDE;
|
||||
virtual bool BYieldingAddWriteToTransaction( GCSDK::CSQLAccess &sqlAccess, const CUtlVector< int > &fields ) OVERRIDE;
|
||||
virtual bool BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess &sqlAccess ) OVERRIDE;
|
||||
virtual bool BAddToMessage( CUtlBuffer & bufOutput ) const OVERRIDE;
|
||||
virtual bool BAddToMessage( std::string *pBuffer ) const OVERRIDE;
|
||||
virtual bool BAddDestroyToMessage( CUtlBuffer & bufDestroy ) const OVERRIDE;
|
||||
virtual bool BAddDestroyToMessage( std::string *pBuffer ) const OVERRIDE;
|
||||
#endif
|
||||
|
||||
virtual bool BParseFromMessage( const CUtlBuffer & buffer ) OVERRIDE;
|
||||
virtual bool BParseFromMessage( const std::string &buffer ) OVERRIDE;
|
||||
virtual bool BUpdateFromNetwork( const CSharedObject & objUpdate ) OVERRIDE;
|
||||
virtual void Copy( const CSharedObject & soRHS );
|
||||
virtual void Dump() const;
|
||||
|
||||
void SerializeToProtoBufItem( CSOClassPresetClientData &msgPresetInstance ) const;
|
||||
void DeserializeFromProtoBufItem( const CSOClassPresetClientData &msgPresetIntance );
|
||||
|
||||
enum
|
||||
{
|
||||
kPerClassPresetDataDirtyField_ActivePreset,
|
||||
kPerClassPresetDataDirtyField_PresetData_Base,
|
||||
};
|
||||
|
||||
#ifdef GC_DLL
|
||||
const CUtlVector<PresetSlotItem_t> *FindItemsForPresetIndex( equipped_preset_t unPreset ) const;
|
||||
void EquipItemIntoActivePresetSlot( equipped_slot_t unSlot, itemid_t unOriginalItemID );
|
||||
void RemoveAllItemsFromPresetIndex( equipped_preset_t unPreset );
|
||||
|
||||
void SetActivePreset( equipped_preset_t unPreset );
|
||||
equipped_class_t GetClass() const { return m_unClassID; }
|
||||
#endif // GC_DLL
|
||||
equipped_preset_t GetActivePreset() const { return m_unActivePreset; }
|
||||
|
||||
private:
|
||||
CEconItemPerClassPresetData( const CEconItemPerClassPresetData& ) = delete;
|
||||
void operator=( const CEconItemPerClassPresetData& ) = delete;
|
||||
|
||||
private:
|
||||
uint32 m_unAccountID;
|
||||
equipped_class_t m_unClassID;
|
||||
equipped_preset_t m_unActivePreset;
|
||||
CUtlVector<PresetSlotItem_t> m_PresetData[ CEconItemSchema::kMaxItemPresetCount ];
|
||||
};
|
||||
|
||||
#endif // ECONITEMPRESET_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,694 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "tier1/KeyValues.h"
|
||||
#include "econ_gcmessages.h"
|
||||
#include "econ_item_system.h"
|
||||
#include "econ_item_inventory.h"
|
||||
#include "game_item_schema.h"
|
||||
#include "gc_clientsystem.h"
|
||||
|
||||
#include "utldict.h"
|
||||
#include "filesystem.h"
|
||||
#include "steam/isteamhttp.h"
|
||||
|
||||
|
||||
#if defined(CLIENT_DLL) || defined(GAME_DLL)
|
||||
#include "gamestringpool.h"
|
||||
#include "ihasattributes.h"
|
||||
#include "tier0/icommandline.h"
|
||||
#endif
|
||||
|
||||
#if defined(CLIENT_DLL)
|
||||
#include "igameevents.h"
|
||||
#endif
|
||||
|
||||
// FIXME FIXME FIXME
|
||||
#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
|
||||
#include "tf_item_system.h"
|
||||
#endif // defined(TF_DLL) || defined(TF_CLIENT_DLL)
|
||||
|
||||
#if defined (DOTA_CLIENT_DLL) || defined (DOTA_DLL)
|
||||
#include "econ/dota_item_system.h"
|
||||
#endif // defined (DOTA_CLIENT_DLL) || defined (DOTA_DLL)
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#if ( defined( GAME_DLL ) || defined( CLIENT_DLL ) ) && ( defined( _DEBUG ) || defined( STAGING_ONLY ) )
|
||||
ConVar item_debug( "item_debug", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY );
|
||||
ConVar items_game_use_gc_copy( "items_game_use_gc_copy", "1", FCVAR_CHEAT | FCVAR_REPLICATED | FCVAR_ARCHIVE, "If set, items_game.txt will be stomped by the GC." );
|
||||
ConVar item_debug_validation( "item_debug_validation", "1", FCVAR_REPLICATED | FCVAR_ARCHIVE, "If set, CEconEntity::ValidateEntityAttachedToPlayer behaves as it would in release builds and also allows bot players to take the same code path as real players." );
|
||||
#endif
|
||||
|
||||
static ConVar item_quality_chance_unique( "item_quality_chance_unique", "0.1", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Percentage chance that a random item is unique." );
|
||||
static ConVar item_quality_chance_rare( "item_quality_chance_rare", "0.5", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Percentage chance that a random item is a rare." );
|
||||
static ConVar item_quality_chance_common( "item_quality_chance_common", "1.0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Percentage chance that a random item is common." );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get at the global item system
|
||||
//-----------------------------------------------------------------------------
|
||||
CEconItemSystem *ItemSystem( void )
|
||||
{
|
||||
static GameItemSystem_t *pSystem = NULL;
|
||||
if ( !pSystem )
|
||||
{
|
||||
pSystem = new GameItemSystem_t();
|
||||
}
|
||||
|
||||
return pSystem;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Global schema access, declared in game_item_schema.h
|
||||
//-----------------------------------------------------------------------------
|
||||
GameItemSchema_t *GetItemSchema()
|
||||
{
|
||||
return ItemSystem()->GetItemSchema();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CEconItemSystem::CEconItemSystem( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CEconItemSystem::~CEconItemSystem( void )
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Parse in our data files.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconItemSystem::Init( void )
|
||||
{
|
||||
#if defined(USES_ECON_ITEMS)
|
||||
ParseItemSchemaFile( "scripts/items/items_game.txt" );
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
IGameEvent *event = gameeventmanager->CreateEvent( "item_schema_initialized" );
|
||||
if ( event )
|
||||
{
|
||||
gameeventmanager->FireEventClientSide( event );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconItemSystem::Shutdown( void )
|
||||
{
|
||||
}
|
||||
|
||||
extern ConVar mp_tournament;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
ConVar mp_tournament_whitelist( "mp_tournament_whitelist", "item_whitelist.txt", FCVAR_NONE, "Specifies the item whitelist file to use." );
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconItemSystem::ReloadWhitelist( void )
|
||||
{
|
||||
// Default state of items depends on whether we're in tourney mode, and whether there's a whitelist
|
||||
bool bDefault = true;
|
||||
bool bFoundWhitelist = false;
|
||||
|
||||
KeyValues *pWhitelistKV = new KeyValues( "item_whitelist" );
|
||||
|
||||
#ifdef GAME_DLL
|
||||
if ( mp_tournament.GetBool() && mp_tournament_whitelist.GetString() )
|
||||
{
|
||||
const char *pszWhitelistFile = mp_tournament_whitelist.GetString();
|
||||
if ( pWhitelistKV->LoadFromFile( filesystem, pszWhitelistFile ) )
|
||||
{
|
||||
// Allow the whitelist to override the default, so they can turn it into a blacklist if they want to
|
||||
bDefault = pWhitelistKV->GetBool( "unlisted_items_default_to" );
|
||||
bFoundWhitelist = true;
|
||||
}
|
||||
else if ( pszWhitelistFile && pszWhitelistFile[0] )
|
||||
{
|
||||
Msg("Item Whitelist file '%s' could not be found. All items will be allowed.\n", pszWhitelistFile );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const CEconItemSchema::ItemDefinitionMap_t& mapItemDefs = m_itemSchema.GetItemDefinitionMap();
|
||||
FOR_EACH_MAP_FAST( mapItemDefs, i )
|
||||
{
|
||||
mapItemDefs[i]->SetAllowedInMatch( bDefault );
|
||||
}
|
||||
|
||||
// If we didn't find a file, we're done.
|
||||
if ( !bFoundWhitelist )
|
||||
return;
|
||||
|
||||
// Otherwise, go through the KVs and turn on the matching items.
|
||||
Msg("Parsing item whitelist (default: %s)\n", bDefault ? "allowed" : "disallowed" );
|
||||
pWhitelistKV = pWhitelistKV->GetFirstSubKey();
|
||||
while ( pWhitelistKV )
|
||||
{
|
||||
bool bAllow = pWhitelistKV->GetBool();
|
||||
|
||||
const char *pszItemName = pWhitelistKV->GetName();
|
||||
if ( pszItemName && pszItemName[0] && !FStrEq("unlisted_items_default_to", pszItemName) )
|
||||
{
|
||||
CEconItemDefinition *pItemDef = m_itemSchema.GetItemDefinitionByName( pszItemName );
|
||||
if ( pItemDef )
|
||||
{
|
||||
pItemDef->SetAllowedInMatch( bAllow );
|
||||
Msg(" -> %s '%s'\n", bAllow ? "Allowing" : "Removing", pszItemName );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning(" -> Could not find an item definition named '%s'\n", pszItemName );
|
||||
}
|
||||
}
|
||||
|
||||
pWhitelistKV = pWhitelistKV->GetNextKey();
|
||||
}
|
||||
Msg("Finished.\n");
|
||||
}
|
||||
|
||||
#ifdef GAME_DLL
|
||||
CON_COMMAND_F( item_show_whitelistable_definitions, "Lists the item definitions that can be whitelisted in the item_whitelist.txt file in tournament mode.", FCVAR_CHEAT )
|
||||
{
|
||||
Msg("Available item definitions for whitelisting:\n");
|
||||
const CEconItemSchema::SortedItemDefinitionMap_t& mapItemDefs = ItemSystem()->GetItemSchema()->GetSortedItemDefinitionMap();
|
||||
FOR_EACH_MAP( mapItemDefs, i )
|
||||
{
|
||||
const CEconItemDefinition *pItemDef = mapItemDefs[i];
|
||||
if ( pItemDef && pItemDef->GetQuality() != AE_NORMAL && !pItemDef->IsHidden() )
|
||||
{
|
||||
Msg(" '%s'\n", pItemDef->GetDefinitionName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // GAME_DLL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconItemSystem::ResetAttribStringCache( void )
|
||||
{
|
||||
const CUtlMap<int, CEconItemAttributeDefinition, int> &mapDefs = m_itemSchema.GetAttributeDefinitionMap();
|
||||
FOR_EACH_MAP_FAST( mapDefs, i )
|
||||
{
|
||||
mapDefs[i].ClearStringCache();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CEconItemSystem::DecryptItemFiles( KeyValues *pKV, const char *pName )
|
||||
{
|
||||
char szFullName[512];
|
||||
Q_snprintf(szFullName,sizeof(szFullName), "%s.ctx", pName );
|
||||
|
||||
FileHandle_t f = filesystem->Open( szFullName, "rb", "MOD" );
|
||||
|
||||
if (!f)
|
||||
{
|
||||
#if !defined(CSTRIKE_DLL)
|
||||
Warning("No %s file found. May be unable to create items.\n", pName );
|
||||
#endif // CSTRIKE_DLL
|
||||
return false;
|
||||
}
|
||||
|
||||
int fileSize = filesystem->Size(f);
|
||||
char *buffer = (char*)MemAllocScratch(fileSize + 1);
|
||||
|
||||
Assert(buffer);
|
||||
|
||||
filesystem->Read(buffer, fileSize, f); // read into local buffer
|
||||
buffer[fileSize] = 0; // null terminate file as EOF
|
||||
filesystem->Close( f ); // close file after reading
|
||||
|
||||
UTIL_DecodeICE( (unsigned char*)buffer, fileSize, GetEncryptionKey() );
|
||||
|
||||
bool retOK = pKV->LoadFromBuffer( szFullName, buffer, filesystem );
|
||||
|
||||
MemFreeScratch();
|
||||
|
||||
if ( !retOK )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Read the specified item schema file. Init the item schema with the contents
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconItemSystem::ParseItemSchemaFile( const char *pFilename )
|
||||
{
|
||||
CUtlVector< CUtlString > vecErrors;
|
||||
bool bSuccess = m_itemSchema.BInit( pFilename, "MOD", &vecErrors );
|
||||
|
||||
if( !bSuccess )
|
||||
{
|
||||
FOR_EACH_VEC( vecErrors, nError )
|
||||
{
|
||||
// we want this to be an Error because several
|
||||
// places rely on loading a valid item schema
|
||||
Error( "%s\n", vecErrors[nError].String() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generate a random item matching the specified criteria
|
||||
//-----------------------------------------------------------------------------
|
||||
item_definition_index_t CEconItemSystem::GenerateRandomItem( CItemSelectionCriteria *pCriteria, entityquality_t *outEntityQuality )
|
||||
{
|
||||
// First, pick a random item quality (use the one passed in first)
|
||||
if ( !pCriteria->BQualitySet() )
|
||||
{
|
||||
pCriteria->SetQuality( GetRandomQualityForItem() );
|
||||
}
|
||||
|
||||
pCriteria->SetIgnoreEnabledFlag( true );
|
||||
|
||||
// Determine which item templates match the criteria
|
||||
CUtlVector<item_definition_index_t> vecMatches;
|
||||
const CEconItemSchema::ItemDefinitionMap_t &mapDefs = m_itemSchema.GetItemDefinitionMap();
|
||||
|
||||
HackMakeValidList:
|
||||
FOR_EACH_MAP_FAST( mapDefs, i )
|
||||
{
|
||||
if ( pCriteria->BEvaluate( mapDefs[i] ) )
|
||||
{
|
||||
vecMatches.AddToTail( mapDefs.Key( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
// No valid items?
|
||||
int iValidItems = vecMatches.Count();
|
||||
if ( !iValidItems )
|
||||
{
|
||||
// If we were searching for a unique item, drop back to a non-unique
|
||||
if ( pCriteria->GetQuality() == AE_UNIQUE )
|
||||
{
|
||||
pCriteria->SetQuality( GetRandomQualityForItem( true ) );
|
||||
goto HackMakeValidList;
|
||||
}
|
||||
return INVALID_ITEM_DEF_INDEX;
|
||||
}
|
||||
|
||||
// Choose a random match
|
||||
int iChosenIdx = RandomInt( 0, (iValidItems-1) );
|
||||
item_definition_index_t iChosenItem = vecMatches[iChosenIdx];
|
||||
|
||||
const CEconItemDefinition *pItemDef = m_itemSchema.GetItemDefinition( iChosenItem );
|
||||
if ( !pItemDef )
|
||||
return INVALID_ITEM_DEF_INDEX;
|
||||
|
||||
// If we haven't specified an entity quality, we want to use the item's specified one
|
||||
if ( pCriteria->GetQuality() == AE_USE_SCRIPT_VALUE )
|
||||
{
|
||||
int32 iScriptQuality = pItemDef->GetQuality();
|
||||
pCriteria->SetQuality( iScriptQuality == AE_UNDEFINED ? GetRandomQualityForItem( true ) : iScriptQuality );
|
||||
}
|
||||
|
||||
// If we haven't specified an item level, we want to use the item's specified one.
|
||||
if ( !pCriteria->BItemLevelSet() )
|
||||
{
|
||||
pCriteria->SetItemLevel( RandomInt( pItemDef->GetMinLevel(), pItemDef->GetMaxLevel() ) );
|
||||
}
|
||||
|
||||
if ( outEntityQuality )
|
||||
{
|
||||
*outEntityQuality = pCriteria->GetQuality();
|
||||
}
|
||||
return iChosenItem;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return a random quality for the item specified
|
||||
//-----------------------------------------------------------------------------
|
||||
entityquality_t CEconItemSystem::GetRandomQualityForItem( bool bPreventUnique )
|
||||
{
|
||||
// Start on the rarest, and work backwards
|
||||
if ( !bPreventUnique )
|
||||
{
|
||||
if ( RandomFloat(0,1) < item_quality_chance_unique.GetFloat() )
|
||||
return AE_UNIQUE;
|
||||
}
|
||||
|
||||
if ( RandomFloat(0,1) < item_quality_chance_rare.GetFloat() )
|
||||
return AE_RARITY2;
|
||||
|
||||
if ( RandomFloat(0,1) < item_quality_chance_common.GetFloat() )
|
||||
return AE_RARITY1;
|
||||
|
||||
return AE_NORMAL;
|
||||
}
|
||||
|
||||
static ISteamHTTP *GetISteamHTTP()
|
||||
{
|
||||
if ( steamapicontext != NULL && steamapicontext->SteamHTTP() )
|
||||
{
|
||||
return steamapicontext->SteamHTTP();
|
||||
}
|
||||
#ifndef CLIENT_DLL
|
||||
if ( steamgameserverapicontext != NULL )
|
||||
{
|
||||
return steamgameserverapicontext->SteamHTTP();
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Common functionality for using our raw buffer data to initialize
|
||||
// the schema when safe.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool IDelayedSchemaData::InitializeSchemaInternal( CEconItemSchema *pItemSchema, CUtlBuffer& bufRawData, bool bInitAsBinary, uint32 nExpectedVersion )
|
||||
{
|
||||
Msg( "Applying new item schema, version %08X\n", nExpectedVersion );
|
||||
|
||||
CUtlVector<CUtlString> vecErrors;
|
||||
bool bSuccess = bInitAsBinary
|
||||
? pItemSchema->BInitBinaryBuffer( bufRawData, &vecErrors )
|
||||
: pItemSchema->BInitTextBuffer( bufRawData, &vecErrors );
|
||||
if( bSuccess )
|
||||
{
|
||||
// Sanity-check that we received the version that they sent us
|
||||
uint32 nOurVersion = pItemSchema->GetVersion();
|
||||
if ( nExpectedVersion != 0 && nOurVersion != nExpectedVersion )
|
||||
{
|
||||
Warning( "**WARNING** Item schema mismatch after update!\n" );
|
||||
Warning( "GC told us to expect %08X, we got %08X\n", nExpectedVersion, nOurVersion );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "**WARNING** Failed to apply item schema!\n" );
|
||||
FOR_EACH_VEC( vecErrors, nError )
|
||||
{
|
||||
Warning( "%s\n", vecErrors[nError].Get() );
|
||||
}
|
||||
}
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The GC sent us a single block of binary data.
|
||||
//-----------------------------------------------------------------------------
|
||||
class DelayedSchemaData_GCDirectData : public IDelayedSchemaData
|
||||
{
|
||||
public:
|
||||
DelayedSchemaData_GCDirectData( const std::string& strBuffer )
|
||||
: m_bufRawData( strBuffer.data(), strBuffer.size(), CUtlBuffer::READ_ONLY )
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
virtual bool InitializeSchema( CEconItemSchema *pItemSchema )
|
||||
{
|
||||
return InitializeSchemaInternal( pItemSchema, m_bufRawData, true, 0 );
|
||||
}
|
||||
|
||||
private:
|
||||
CUtlBuffer m_bufRawData;
|
||||
};
|
||||
|
||||
extern bool CheckValveSignature( const void *data, uint32 nDataSize, const void *signature, uint32 nSignatureSize );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: We received a text file from an HTML request.
|
||||
//-----------------------------------------------------------------------------
|
||||
class DelayedSchemaData_HTTPResponseData : public IDelayedSchemaData
|
||||
{
|
||||
public:
|
||||
DelayedSchemaData_HTTPResponseData( ISteamHTTP *pHTTP, HTTPRequestHandle handleHTTPRequest, uint32 unBodySize, uint32 nExpectedVersion, const std::string &sSignature )
|
||||
: m_nExpectedVersion( nExpectedVersion )
|
||||
{
|
||||
Assert( pHTTP );
|
||||
|
||||
m_bufRawData.SetBufferType( true, true );
|
||||
m_bufRawData.SeekPut( CUtlBuffer::SEEK_HEAD, unBodySize );
|
||||
|
||||
m_bValid = pHTTP->GetHTTPResponseBodyData( handleHTTPRequest, (uint8*)m_bufRawData.Base(), m_bufRawData.TellPut() );
|
||||
if ( m_bValid )
|
||||
m_bValid = CheckValveSignature( m_bufRawData.Base(), m_bufRawData.TellPut(), sSignature.c_str(), sSignature.length() );
|
||||
}
|
||||
|
||||
virtual bool InitializeSchema( CEconItemSchema *pItemSchema )
|
||||
{
|
||||
if ( !m_bValid )
|
||||
return false;
|
||||
|
||||
return InitializeSchemaInternal( pItemSchema, m_bufRawData, false, m_nExpectedVersion );
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_bValid;
|
||||
CUtlBuffer m_bufRawData;
|
||||
uint32 m_nExpectedVersion;
|
||||
};
|
||||
|
||||
#define GC_ITEM_SCHEMA_UPDATE_APPLIED "Applied updated item schema from GC. %d bytes, version %08X.\n"
|
||||
#define GC_ITEM_SCHEMA_UPDATE_QUEUED "Received %d bytes item schema version %08X direct data; update is queued.\n"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update the item schema from the GC
|
||||
//-----------------------------------------------------------------------------
|
||||
class CGCUpdateItemSchema : public GCSDK::CGCClientJob
|
||||
{
|
||||
public:
|
||||
CGCUpdateItemSchema( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {
|
||||
m_szUrl[0] = '\0';
|
||||
m_nExpectedVersion = 0;
|
||||
bHTTPCompleted = false;
|
||||
}
|
||||
|
||||
char m_szUrl[512];
|
||||
uint32 m_nExpectedVersion;
|
||||
bool bHTTPCompleted;
|
||||
CCallResult< CGCUpdateItemSchema, HTTPRequestCompleted_t > callback;
|
||||
std::string m_sSignature;
|
||||
|
||||
virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
|
||||
{
|
||||
GCSDK::CProtoBufMsg< CMsgUpdateItemSchema > msg( pNetPacket );
|
||||
|
||||
#if ( defined( GAME_DLL ) || defined( CLIENT_DLL ) ) && ( defined( _DEBUG ) || defined( STAGING_ONLY ) )
|
||||
const bool bUseGCCopy = items_game_use_gc_copy.GetBool();
|
||||
#else
|
||||
const bool bUseGCCopy = true;
|
||||
#endif
|
||||
|
||||
if ( bUseGCCopy == false && k_EUniversePublic != GetUniverse() )
|
||||
{
|
||||
Msg( "Loading item schema from local file.\n" );
|
||||
KeyValuesAD pItemsGameKV( "ItemsGameFile" );
|
||||
if ( pItemsGameKV->LoadFromFile( g_pFullFileSystem, "scripts/items/items_game.txt", "GAME" ) )
|
||||
{
|
||||
CUtlBuffer buffer;
|
||||
pItemsGameKV->WriteAsBinary( buffer );
|
||||
|
||||
CUtlVector< CUtlString > vecErrors;
|
||||
bool bSuccess = ItemSystem()->GetItemSchema()->BInitBinaryBuffer( buffer, &vecErrors );
|
||||
if( !bSuccess )
|
||||
{
|
||||
FOR_EACH_VEC( vecErrors, nError )
|
||||
{
|
||||
Warning( "%s\n", vecErrors[nError].Get() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if we're already up-to-date
|
||||
m_nExpectedVersion = msg.Body().item_schema_version();
|
||||
uint32 nCurrentSchemaVersion = ItemSystem()->GetItemSchema()->GetVersion();
|
||||
if ( m_nExpectedVersion != 0 && m_nExpectedVersion == nCurrentSchemaVersion )
|
||||
{
|
||||
Msg( "Current item schema is up-to-date with version %08X.\n", nCurrentSchemaVersion );
|
||||
return true;
|
||||
}
|
||||
|
||||
m_sSignature = msg.Body().signature();
|
||||
|
||||
// !TEST!
|
||||
//const char *szURL = "http://cdn.beta.steampowered.com/apps/440/scripts/items/items_game.b8b7a85b4dd98b139957004b86ec0bc070a59d18.txt";
|
||||
if ( msg.Body().has_items_game() )
|
||||
{
|
||||
bool bDidInit = ItemSystem()->GetItemSchema()->MaybeInitFromBuffer( new DelayedSchemaData_GCDirectData( msg.Body().items_game() ) );
|
||||
Msg( bDidInit ? GC_ITEM_SCHEMA_UPDATE_APPLIED : GC_ITEM_SCHEMA_UPDATE_QUEUED, (int)msg.Body().items_game().size(), m_nExpectedVersion );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remember URL
|
||||
const char *szURL = msg.Body().items_game_url().c_str();
|
||||
if ( !szURL || !szURL[0] )
|
||||
{
|
||||
Warning( "GC sent malformed CGCUpdateItemSchema message: No schema data, no URL\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncpy( m_szUrl, szURL, sizeof( m_szUrl ) );
|
||||
//Msg( "Fetching %s to update item schema\n", m_szUrl );
|
||||
|
||||
// Send an HTTP request for the file
|
||||
ISteamHTTP *pHTTP = GetISteamHTTP();
|
||||
if ( !pHTTP )
|
||||
{
|
||||
//Warning( "Can't get ISteamHTTP to update item schema\n");
|
||||
return true;
|
||||
}
|
||||
HTTPRequestHandle hReq = pHTTP->CreateHTTPRequest( k_EHTTPMethodGET, m_szUrl );
|
||||
pHTTP->SetHTTPRequestNetworkActivityTimeout( hReq, 10 );
|
||||
SteamAPICall_t hCall;
|
||||
if ( !pHTTP->SendHTTPRequest( hReq, &hCall ) )
|
||||
{
|
||||
Warning( "Failed to update item schema: couldn't fetch %s\n", m_szUrl );
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// *Wait* for completion.
|
||||
//
|
||||
// This is important. The GC needs to be able to safely assume that
|
||||
// we will not process the next message until we have finished
|
||||
// dealing with this one.
|
||||
//
|
||||
bHTTPCompleted = false;
|
||||
#ifndef CLIENT_DLL
|
||||
if ( steamgameserverapicontext != NULL && pHTTP == steamgameserverapicontext->SteamHTTP() )
|
||||
{
|
||||
callback.SetGameserverFlag();
|
||||
}
|
||||
#endif
|
||||
callback.Set( hCall, this, &CGCUpdateItemSchema::OnHTTPCompleted );
|
||||
|
||||
// Wait for it to finish.
|
||||
while ( !bHTTPCompleted )
|
||||
{
|
||||
BYieldingWaitOneFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnHTTPCompleted( HTTPRequestCompleted_t *arg, bool bFailed )
|
||||
{
|
||||
// Clear flag, no matter what else, so we can stop yielding
|
||||
bHTTPCompleted = true;
|
||||
|
||||
ISteamHTTP *pHTTP = GetISteamHTTP();
|
||||
Assert( pHTTP );
|
||||
if ( !pHTTP ) return;
|
||||
|
||||
if ( arg->m_eStatusCode != k_EHTTPStatusCode200OK )
|
||||
{
|
||||
Warning( "Failed to update item schema: HTTP status %d fetching %s\n", arg->m_eStatusCode, m_szUrl );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !arg->m_bRequestSuccessful )
|
||||
{
|
||||
bFailed = true;
|
||||
}
|
||||
if ( !bFailed )
|
||||
{
|
||||
uint32 unBodySize;
|
||||
if ( !pHTTP->GetHTTPResponseBodySize( arg->m_hRequest, &unBodySize ) )
|
||||
{
|
||||
Assert( false );
|
||||
bFailed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bDidInit = ItemSystem()->GetItemSchema()->MaybeInitFromBuffer( new DelayedSchemaData_HTTPResponseData( pHTTP, arg->m_hRequest, unBodySize, m_nExpectedVersion, m_sSignature ) );
|
||||
Msg( bDidInit ? GC_ITEM_SCHEMA_UPDATE_APPLIED : GC_ITEM_SCHEMA_UPDATE_QUEUED, unBodySize, m_nExpectedVersion );
|
||||
}
|
||||
}
|
||||
|
||||
if ( bFailed )
|
||||
{
|
||||
Warning( "Failed to update item schema from %s\n", m_szUrl );
|
||||
}
|
||||
}
|
||||
|
||||
pHTTP->ReleaseHTTPRequest( arg->m_hRequest );
|
||||
}
|
||||
};
|
||||
GC_REG_JOB( GCSDK::CGCClient, CGCUpdateItemSchema, "CGCUpdateItemSchema", k_EMsgGCUpdateItemSchema, GCSDK::k_EServerTypeGCClient );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update the item schema from the GC
|
||||
//-----------------------------------------------------------------------------
|
||||
CON_COMMAND_F( econ_show_items_with_tag, "Lists the item definitions that have a specified tag.", FCVAR_CLIENTDLL )
|
||||
{
|
||||
if ( args.ArgC() != 2 )
|
||||
return;
|
||||
|
||||
econ_tag_handle_t tagHandle = GetItemSchema()->GetHandleForTag( args.Arg( 1 ) );
|
||||
FOR_EACH_MAP( GetItemSchema()->GetSortedItemDefinitionMap(), i )
|
||||
{
|
||||
const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinitionMap()[i];
|
||||
|
||||
if ( pItemDef->HasEconTag( tagHandle ) )
|
||||
{
|
||||
Msg(" '%s'\n", pItemDef->GetDefinitionName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
#ifdef STAGING_ONLY
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update the item schema from the GC
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef CLIENT_DLL
|
||||
CON_COMMAND_F( cl_reload_local_item_schema, "Reloads the local item schema copy.", FCVAR_CLIENTDLL )
|
||||
#else
|
||||
CON_COMMAND_F( sv_reload_local_item_schema, "Reloads the local item schema copy.", FCVAR_GAMEDLL )
|
||||
#endif
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
engine->ClientCmd_Unrestricted( "cmd sv_reload_local_item_schema" );
|
||||
#endif
|
||||
|
||||
Msg( "Loading item schema from local file.\n" );
|
||||
KeyValuesAD pItemsGameKV( "ItemsGameFile" );
|
||||
if ( pItemsGameKV->LoadFromFile( g_pFullFileSystem, "scripts/items/items_game.txt", "GAME" ) )
|
||||
{
|
||||
CUtlBuffer buffer;
|
||||
pItemsGameKV->WriteAsBinary( buffer );
|
||||
|
||||
CUtlVector< CUtlString > vecErrors;
|
||||
bool bSuccess = ItemSystem()->GetItemSchema()->BInitBinaryBuffer( buffer, &vecErrors );
|
||||
if( !bSuccess )
|
||||
{
|
||||
FOR_EACH_VEC( vecErrors, nError )
|
||||
{
|
||||
Warning( "%s\n", vecErrors[nError].Get() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECON_ITEM_SYSTEM_H
|
||||
#define ECON_ITEM_SYSTEM_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "econ_item_view.h"
|
||||
#include "game_item_schema.h"
|
||||
|
||||
//==================================================================================
|
||||
// ITEM SYSTEM
|
||||
//==================================================================================
|
||||
|
||||
#define GC_MOTD_CACHE_FILE "cfg/motd_entries.txt"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemSystem
|
||||
{
|
||||
public:
|
||||
CEconItemSystem( void );
|
||||
virtual ~CEconItemSystem( void );
|
||||
|
||||
// Setup & parse in the item data files.
|
||||
void Init( void );
|
||||
void Shutdown( void );
|
||||
|
||||
// Return the static item data for the specified item index
|
||||
GameItemDefinition_t *GetStaticDataForItemByDefIndex( item_definition_index_t iItemDefIndex )
|
||||
{
|
||||
return (GameItemDefinition_t *)m_itemSchema.GetItemDefinition( iItemDefIndex );
|
||||
}
|
||||
CEconItemDefinition *GetStaticDataForItemByName( const char *pszDefName )
|
||||
{
|
||||
return m_itemSchema.GetItemDefinitionByName( pszDefName );
|
||||
}
|
||||
CEconItemAttributeDefinition *GetStaticDataForAttributeByDefIndex( attrib_definition_index_t iAttribDefinitionIndex )
|
||||
{
|
||||
return m_itemSchema.GetAttributeDefinition( iAttribDefinitionIndex );
|
||||
}
|
||||
CEconItemAttributeDefinition *GetStaticDataForAttributeByName( const char *pszDefName )
|
||||
{
|
||||
return m_itemSchema.GetAttributeDefinitionByName( pszDefName );
|
||||
}
|
||||
|
||||
// Select and return a random item's definition index matching the specified criteria
|
||||
item_definition_index_t GenerateRandomItem( CItemSelectionCriteria *pCriteria, entityquality_t *outEntityQuality );
|
||||
|
||||
// Select and return the base item definition index for a class's load-out slot
|
||||
// Note: baseitemcriteria_t is game-specific and/or may not exist!
|
||||
virtual item_definition_index_t GenerateBaseItem( struct baseitemcriteria_t *pCriteria ) { return INVALID_ITEM_DEF_INDEX; }
|
||||
|
||||
// Return a random item quality
|
||||
entityquality_t GetRandomQualityForItem( bool bPreventUnique = false );
|
||||
|
||||
// Decrypt the item files and return the keyvalue
|
||||
bool DecryptItemFiles( KeyValues *pKV, const char *pName );
|
||||
|
||||
GameItemSchema_t *GetItemSchema() { return &m_itemSchema; }
|
||||
|
||||
// Open the server's whitelist, and if it exists, set the appropriate items allowed.
|
||||
void ReloadWhitelist( void );
|
||||
|
||||
void ResetAttribStringCache( void );
|
||||
|
||||
protected:
|
||||
// Read the specified item schema file. Init the item schema with the contents
|
||||
void ParseItemSchemaFile( const char *pFilename );
|
||||
|
||||
// Key to decrypt the item description files
|
||||
const unsigned char *GetEncryptionKey( void ) { return (unsigned char *)"A5fSXbf7"; }
|
||||
|
||||
private:
|
||||
GameItemSchema_t m_itemSchema;
|
||||
};
|
||||
|
||||
CEconItemSystem *ItemSystem( void );
|
||||
|
||||
#endif // ECON_ITEM_SYSTEM_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,455 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECON_ITEM_CONSTANTS_H
|
||||
#define ECON_ITEM_CONSTANTS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "game_item_schema.h"
|
||||
#include "econ_item_constants.h"
|
||||
#include "localization_provider.h"
|
||||
#include "econ_item_interface.h"
|
||||
#include "econ_item.h"
|
||||
|
||||
#if defined(CLIENT_DLL)
|
||||
#include "iclientrenderable.h"
|
||||
#endif
|
||||
|
||||
#if defined(TF_DLL)
|
||||
#include "tf_item_schema.h"
|
||||
#endif
|
||||
|
||||
#if defined(CLIENT_DLL)
|
||||
#define CEconItemView C_EconItemView
|
||||
#endif
|
||||
|
||||
#if defined(GC_DLL)
|
||||
#error "econ_item_view.h is not intended to be built on the GC!"
|
||||
#endif
|
||||
|
||||
#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
|
||||
#define ENABLE_ATTRIBUTE_CURRENCY_TRACKING 1
|
||||
#else
|
||||
#define ENABLE_ATTRIBUTE_CURRENCY_TRACKING 0
|
||||
#endif
|
||||
|
||||
class CEconItemAttribute;
|
||||
class CAttributeManager;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAttributeList
|
||||
{
|
||||
friend class CEconItemView;
|
||||
friend class CTFPlayer;
|
||||
|
||||
DECLARE_CLASS_NOBASE( CAttributeList );
|
||||
public:
|
||||
DECLARE_EMBEDDED_NETWORKVAR();
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CAttributeList();
|
||||
void operator=( const CAttributeList &src );
|
||||
|
||||
void Init();
|
||||
void SetManager( CAttributeManager *pManager );
|
||||
|
||||
void IterateAttributes( class IEconItemAttributeIterator *pIterator ) const;
|
||||
|
||||
// Remove all attributes on this item
|
||||
void DestroyAllAttributes( void );
|
||||
|
||||
void AddAttribute( CEconItemAttribute *pAttribute );
|
||||
|
||||
// Remove an attribute by name
|
||||
void RemoveAttribute( const CEconItemAttributeDefinition *pAttrDef );
|
||||
void RemoveAttributeByIndex( int iIndex );
|
||||
|
||||
public:
|
||||
// Returns the attribute that matches the attribute defname
|
||||
const CEconItemAttribute *GetAttributeByName( const char *pszAttribDefName ) const;
|
||||
|
||||
// Returns the attribute that matches the attribute id
|
||||
const CEconItemAttribute *GetAttributeByID( int iAttributeID ) const;
|
||||
|
||||
// The only way to set the value of an attribute after its creation is through the attribute list
|
||||
// that contains it. This way the matching attribute manager is told one of its attributes has changed.
|
||||
void SetRuntimeAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float flValue );
|
||||
#if ENABLE_ATTRIBUTE_CURRENCY_TRACKING
|
||||
void SetRuntimeAttributeRefundableCurrency( const CEconItemAttributeDefinition *pAttrDef, int iRefundableCurrency );
|
||||
int GetRuntimeAttributeRefundableCurrency( const CEconItemAttributeDefinition *pAttrDef ) const;
|
||||
|
||||
void AdjustRuntimeAttributeRefundableCurrency( const CEconItemAttributeDefinition *pAttrDef, int iRefundableCurrencyAdjustment )
|
||||
{
|
||||
SetRuntimeAttributeRefundableCurrency( pAttrDef, GetRuntimeAttributeRefundableCurrency( pAttrDef ) + iRefundableCurrencyAdjustment );
|
||||
}
|
||||
#endif // ENABLE_ATTRIBUTE_CURRENCY_TRACKING
|
||||
|
||||
private:
|
||||
void NotifyManagerOfAttributeValueChanges();
|
||||
|
||||
// Attribute accessing
|
||||
int GetNumAttributes( void ) const { return m_Attributes.Count(); }
|
||||
CEconItemAttribute *GetAttribute( int iIndex ) { Assert( iIndex >= 0 && iIndex < m_Attributes.Count()); return &m_Attributes[iIndex]; }
|
||||
const CEconItemAttribute *GetAttribute( int iIndex ) const { Assert( iIndex >= 0 && iIndex < m_Attributes.Count()); return &m_Attributes[iIndex]; }
|
||||
|
||||
// Our list of attributes
|
||||
CUtlVector<CEconItemAttribute> m_Attributes;
|
||||
|
||||
CAttributeManager *m_pManager;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: An attribute that knows how to read itself from a datafile, describe itself to the user,
|
||||
// and serialize itself between Servers, Clients, and Steam.
|
||||
// Unlike the attributes created in the Game DLL, this attribute doesn't know how to actually
|
||||
// do anything in the game, it just knows how to describe itself.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconItemAttribute
|
||||
{
|
||||
DECLARE_CLASS_NOBASE( CEconItemAttribute );
|
||||
public:
|
||||
DECLARE_EMBEDDED_NETWORKVAR();
|
||||
|
||||
CEconItemAttribute();
|
||||
CEconItemAttribute( const attrib_definition_index_t iAttributeIndex, float flValue );
|
||||
CEconItemAttribute( const attrib_definition_index_t iAttributeIndex, uint32 unValue );
|
||||
|
||||
void operator=( const CEconItemAttribute &val );
|
||||
|
||||
// Get the index of this attribute's definition inside the script file
|
||||
attrib_definition_index_t GetAttribIndex( void ) const { return m_iAttributeDefinitionIndex; }
|
||||
void SetAttribIndex( attrib_definition_index_t iIndex ) { m_iAttributeDefinitionIndex = iIndex; }
|
||||
|
||||
// Get the static data contained in this attribute's definition
|
||||
const CEconItemAttributeDefinition *GetStaticData( void ) const;
|
||||
|
||||
// Get the float value of this attribute.
|
||||
//float GetValue( void ) const;
|
||||
|
||||
#if ENABLE_ATTRIBUTE_CURRENCY_TRACKING
|
||||
int GetRefundableCurrency( void ) const { return m_nRefundableCurrency; }
|
||||
#endif // ENABLE_ATTRIBUTE_CURRENCY_TRACKING
|
||||
|
||||
private:
|
||||
// The only way to set the value of an attribute after its creation is through the attribute list
|
||||
// that contains it. This way the matching attribute manager is told one of its attributes has changed.
|
||||
|
||||
// Set the float value of this attribute.
|
||||
// Note that the value must be stored as a float!
|
||||
void SetValue( float flValue );
|
||||
|
||||
// Set the value of this attribute as an unsigned integer.
|
||||
// Note that the value must be stored as an integer!
|
||||
// See CEconItemAttributeDefinition
|
||||
void SetIntValue( uint32 unValue );
|
||||
|
||||
friend class CAttributeList;
|
||||
|
||||
void Init( void );
|
||||
|
||||
//--------------------------------------------------------
|
||||
private:
|
||||
// This is the index of the attribute into the attributes read from the data files
|
||||
CNetworkVar( attrib_definition_index_t, m_iAttributeDefinitionIndex );
|
||||
|
||||
// This is the value of the attribute. Used to modify the item's variables.
|
||||
CNetworkVar( float, m_flValue );
|
||||
|
||||
#if ENABLE_ATTRIBUTE_CURRENCY_TRACKING
|
||||
// This is the value that the attribute was first set to by an item definition
|
||||
CNetworkVar( int, m_nRefundableCurrency );
|
||||
#endif // ENABLE_ATTRIBUTE_CURRENCY_TRACKING
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: An item that knows how to read itself from a datafile, describe itself to the user,
|
||||
// and serialize itself between Servers, Clients, and Steam.
|
||||
//
|
||||
// In the client DLL, we derive it from CDefaultClientRenderable so that
|
||||
// it can be passed in the pProxyData parameter of material proxies.
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined(CLIENT_DLL)
|
||||
class CEconItemView : public CDefaultClientRenderable, public CMaterialOverrideContainer< IEconItemInterface >
|
||||
#else
|
||||
class CEconItemView : public CMaterialOverrideContainer< IEconItemInterface >
|
||||
#endif
|
||||
{
|
||||
DECLARE_CLASS_NOBASE( CEconItemView );
|
||||
public:
|
||||
DECLARE_EMBEDDED_NETWORKVAR();
|
||||
DECLARE_DATADESC();
|
||||
|
||||
public:
|
||||
CEconItemView();
|
||||
CEconItemView( const CEconItemView &src );
|
||||
~CEconItemView();
|
||||
CEconItemView& operator=( const CEconItemView &src );
|
||||
bool operator==( const CEconItemView &other ) const;
|
||||
bool operator!=( const CEconItemView &other ) const { return !operator==( other ); }
|
||||
|
||||
virtual const GameItemDefinition_t *GetItemDefinition() const
|
||||
{
|
||||
return GetStaticData();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// IEconItemInterface implementation.
|
||||
virtual itemid_t GetID() const { return GetItemID(); }
|
||||
virtual int32 GetQuality() const;
|
||||
virtual style_index_t GetStyle() const;
|
||||
virtual uint8 GetFlags() const;
|
||||
virtual eEconItemOrigin GetOrigin() const;
|
||||
virtual int GetQuantity() const;
|
||||
uint64 GetOriginalID() const { return GetSOCData() ? GetSOCData()->GetOriginalID() : 0; }
|
||||
|
||||
virtual const char *GetCustomName() const;
|
||||
virtual const char *GetCustomDesc() const;
|
||||
|
||||
virtual bool GetInUse() const { return GetSOCData() ? GetSOCData()->GetInUse() : false; }
|
||||
|
||||
virtual void IterateAttributes( class IEconItemAttributeIterator *pIterator ) const OVERRIDE;
|
||||
|
||||
bool IsValid( void ) const { return m_bInitialized; }
|
||||
void Invalidate( void ) { m_bInitialized = false; m_iItemDefinitionIndex = INVALID_ITEM_DEF_INDEX; m_iItemID = INVALID_ITEM_ID; }
|
||||
void InvalidateColor() { m_bColorInit = false; }
|
||||
void InvalidateOverrideColor() { m_bPaintOverrideInit = false; }
|
||||
|
||||
// Initialize from the specified data
|
||||
// client will load SO cache as needed
|
||||
void Init( int iDefIndex, int iQuality, int iLevel, uint32 iAccountID = 0 );
|
||||
void SetInitialized( bool bInit ) { m_bInitialized = bInit; }
|
||||
|
||||
// Get the static data contained in this item's definition
|
||||
GameItemDefinition_t *GetStaticData( void ) const;
|
||||
|
||||
void SetNonSOEconItem( CEconItem* pItem ) { m_pNonSOEconItem.SetItem( pItem ); }
|
||||
|
||||
void OnAttributeValuesChanged()
|
||||
{
|
||||
NetworkStateChanged();
|
||||
MarkDescriptionDirty();
|
||||
}
|
||||
|
||||
private:
|
||||
void EnsureDescriptionIsBuilt( void ) const;
|
||||
void MarkDescriptionDirty( void );
|
||||
public:
|
||||
void SetGrayedOutReason( const char *pszGrayedOutReason );
|
||||
|
||||
// Set & Get the index of this item's definition inside the script file
|
||||
void SetItemDefIndex( item_definition_index_t iIndex ) { m_iItemDefinitionIndex = iIndex; MarkDescriptionDirty(); }
|
||||
virtual item_definition_index_t GetItemDefIndex( void ) const { return m_iItemDefinitionIndex; }
|
||||
|
||||
// Set & Get the quality & level of this item.
|
||||
void SetItemQuality( int iQuality ) { m_iEntityQuality = iQuality; MarkDescriptionDirty(); }
|
||||
int GetItemQuality( void ) const { return m_iEntityQuality; }
|
||||
void SetItemLevel( uint32 unLevel ) { m_iEntityLevel = unLevel; MarkDescriptionDirty(); }
|
||||
uint32 GetItemLevel( void ) const { return m_iEntityLevel; }
|
||||
|
||||
int GetItemQuantity() const;
|
||||
#ifdef CLIENT_DLL
|
||||
void SetIsTradeItem( bool bIsTradeItem ) { m_bIsTradeItem = bIsTradeItem; MarkDescriptionDirty(); }
|
||||
void SetItemQuantity( int iQuantity ) { m_iEntityQuantity = iQuantity; MarkDescriptionDirty(); }
|
||||
void SetClientItemFlags( uint8 unFlags );
|
||||
|
||||
void SetItemStyleOverride( style_index_t unNewStyleOverride );
|
||||
void SetItemOriginOverride( eEconItemOrigin unNewOriginOverride );
|
||||
#endif
|
||||
style_index_t GetItemStyle() const;
|
||||
|
||||
// Access the worldwide global index of this item
|
||||
void SetItemID( itemid_t iIdx ) { m_iItemID = iIdx; m_iItemIDHigh = (m_iItemID >> 32); m_iItemIDLow = (m_iItemID & 0xFFFFFFFF); }
|
||||
#ifdef CLIENT_DLL
|
||||
// On the client, we need to rebuild it from the high & low networked pieces
|
||||
itemid_t GetItemID( void ) const { uint64 iTmp = ((((int64)m_iItemIDHigh)<<32) | m_iItemIDLow); return (itemid_t)iTmp; }
|
||||
#else
|
||||
itemid_t GetItemID( void ) const { return m_iItemID; }
|
||||
#endif
|
||||
|
||||
uint32 GetAccountID( void ) const { return m_iAccountID; }
|
||||
void SetOverrideAccountID( uint32 nAccountID ) { m_iAccountID = nAccountID; }
|
||||
|
||||
// Access the inventory position of this item
|
||||
void SetInventoryPosition( uint32 iPosition ) { m_iInventoryPosition = iPosition; }
|
||||
const uint32 GetInventoryPosition( void ) const { return m_iInventoryPosition; }
|
||||
|
||||
// Return the model to use for model panels containing this item
|
||||
const char *GetInventoryModel( void );
|
||||
// Return the image to use for model panels containing this item
|
||||
const char *GetInventoryImage( void );
|
||||
bool GetInventoryImageData( int *iPosition, int *iSize );
|
||||
const char *GetInventoryOverlayImage( int idx );
|
||||
int GetInventoryOverlayImageCount( void );
|
||||
|
||||
// Return the model to use when displaying this model on the player character model, if any
|
||||
const char *GetPlayerDisplayModel( int iClass, int iTeam ) const;
|
||||
|
||||
// Return the model to use when displaying this model in the world. See the notes on this in econ_item_schema.h
|
||||
const char *GetWorldDisplayModel() const;
|
||||
const char *GetExtraWearableModel() const;
|
||||
const char *GetExtraWearableViewModel() const;
|
||||
const char *GetVisionFilteredDisplayModel() const;
|
||||
|
||||
// Return the load-out slot that this item must be placed into
|
||||
int GetAnimationSlot( void ) const;
|
||||
|
||||
// Return an int that indicates whether the item should be dropped from a dead owner.
|
||||
int GetDropType( void );
|
||||
|
||||
// Remove all attributes on this item
|
||||
void DestroyAllAttributes( void );
|
||||
|
||||
void InitNetworkedDynamicAttributesForDemos( void );
|
||||
|
||||
// Items that have attributes that modify their RGB values
|
||||
int GetModifiedRGBValue( bool bAltColor=false );
|
||||
|
||||
// Returns the UGC file ID of the custom texture assigned to this item. If non-zero, then it has a custom texture.
|
||||
uint64 GetCustomUserTextureID();
|
||||
|
||||
CEconItem *GetSOCData( void ) const;
|
||||
|
||||
bool IsEquipped( void ) const { return GetSOCData() && GetSOCData()->IsEquipped(); }
|
||||
bool IsEquippedForClass( equipped_class_t unClass ) const { return GetSOCData() && GetSOCData()->IsEquippedForClass( unClass ); }
|
||||
equipped_slot_t GetEquippedPositionForClass( equipped_class_t unClass ) const { return GetSOCData() ? GetSOCData()->GetEquippedPositionForClass( unClass ) : INVALID_EQUIPPED_SLOT; }
|
||||
|
||||
// Attached particle systems
|
||||
int GetQualityParticleType() const;
|
||||
|
||||
int GetSkin( int iTeam, bool bViewmodel = false ) const;
|
||||
|
||||
public:
|
||||
// ...
|
||||
CAttributeList *GetAttributeList() { return &m_AttributeList; }
|
||||
const CAttributeList *GetAttributeList() const { return &m_AttributeList; }
|
||||
|
||||
public:
|
||||
virtual CEconItemPaintKitDefinition *GetCustomPainkKitDefinition( void ) const { return GetItemDefinition()->GetCustomPainkKitDefinition(); }
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
void SetWeaponSkinBase( ITexture* pBaseTex );
|
||||
void SetWeaponSkinBaseCompositor( ITextureCompositor * pTexCompositor );
|
||||
inline void SetWeaponSkinGeneration( RTime32 nGeneration ) { m_nWeaponSkinGeneration = nGeneration; }
|
||||
inline void SetWeaponSkinGenerationTeam( int iTeam ) { m_iLastGeneratedTeamSkin = iTeam; }
|
||||
inline void SetWeaponSkinBaseCreateFlags( uint32 flags ) { m_unWeaponSkinBaseCreateFlags = flags; }
|
||||
void CancelWeaponSkinComposite( );
|
||||
inline void SetWeaponSkinUseHighRes( bool bUseHighRes ) { m_bWeaponSkinUseHighRes = bUseHighRes; }
|
||||
inline void SetWeaponSkinUseLowRes( bool bUseLowRes ) { m_bWeaponSkinUseLowRes = bUseLowRes; }
|
||||
|
||||
inline ITexture *GetWeaponSkinBase() const { return m_pWeaponSkinBase; }
|
||||
inline ITextureCompositor *GetWeaponSkinBaseCompositor() const { return m_pWeaponSkinBaseCompositor; }
|
||||
inline uint32 GetWeaponSkinBaseCreateFlags() const { return m_unWeaponSkinBaseCreateFlags; }
|
||||
|
||||
inline RTime32 GetWeaponSkinGeneration() const { return m_nWeaponSkinGeneration; }
|
||||
inline int GetWeaponSkinGenerationTeam() const { return m_iLastGeneratedTeamSkin; }
|
||||
|
||||
inline bool ShouldWeaponSkinUseHighRes() const { return m_bWeaponSkinUseHighRes; }
|
||||
inline bool ShouldWeaponSkinUseLowRes() const { return m_bWeaponSkinUseLowRes; }
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
inline int GetTeamNumber() const { return m_iTeamNumber; }
|
||||
inline void SetTeamNumber( int iTeamNumber ) { m_iTeamNumber = iTeamNumber; }
|
||||
|
||||
protected:
|
||||
// Index of the item definition in the item script file.
|
||||
CNetworkVar( item_definition_index_t, m_iItemDefinitionIndex );
|
||||
|
||||
// The quality of this item.
|
||||
CNetworkVar( int, m_iEntityQuality );
|
||||
|
||||
// The level of this item.
|
||||
CNetworkVar( uint32, m_iEntityLevel );
|
||||
|
||||
// The global index of this item, worldwide.
|
||||
itemid_t m_iItemID;
|
||||
CNetworkVar( uint32, m_iItemIDHigh );
|
||||
CNetworkVar( uint32, m_iItemIDLow );
|
||||
|
||||
// Account ID of the person who has this in their inventory
|
||||
CNetworkVar( uint32, m_iAccountID );
|
||||
|
||||
// Position inside the player's inventory
|
||||
CNetworkVar( uint32, m_iInventoryPosition );
|
||||
|
||||
// This is an alternate source of data, if this item models something that isn't in the SO cache.
|
||||
CEconItemHandle m_pNonSOEconItem;
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
// exist on the client only
|
||||
bool m_bIsTradeItem;
|
||||
int m_iEntityQuantity;
|
||||
uint8 m_unClientFlags;
|
||||
|
||||
// clients have the ability to force a style on an item view -- this is used for store previews,
|
||||
// character panels, etc.
|
||||
style_index_t m_unOverrideStyle;
|
||||
// clients can also force an origin on an item view -- this is used for crafting item previews
|
||||
eEconItemOrigin m_unOverrideOrigin;
|
||||
#endif
|
||||
|
||||
bool m_bColorInit;
|
||||
bool m_bPaintOverrideInit;
|
||||
bool m_bHasPaintOverride;
|
||||
float m_flOverrideIndex;
|
||||
uint32 m_unRGB;
|
||||
uint32 m_unAltRGB;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
ITexture* m_pWeaponSkinBase;
|
||||
ITextureCompositor* m_pWeaponSkinBaseCompositor;
|
||||
RTime32 m_nWeaponSkinGeneration;
|
||||
uint32 m_unWeaponSkinBaseCreateFlags;
|
||||
int m_iLastGeneratedTeamSkin;
|
||||
bool m_bWeaponSkinUseHighRes;
|
||||
bool m_bWeaponSkinUseLowRes;
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
CNetworkVar( int, m_iTeamNumber );
|
||||
|
||||
CNetworkVar( bool, m_bInitialized );
|
||||
|
||||
#ifdef CLIENT_DLL // we avoid using "BUILD_ITEM_NAME_AND_DESC" to prevent everything depending on the CEconItemDescription
|
||||
public:
|
||||
// Return the single-line name of this item.
|
||||
const wchar_t *GetItemName( void ) const;
|
||||
|
||||
// Return the full structure with all of our description lines.
|
||||
const class CEconItemDescription *GetDescription() const { EnsureDescriptionIsBuilt(); return m_pDescription; }
|
||||
|
||||
private:
|
||||
mutable class CEconItemDescription *m_pDescription;
|
||||
mutable char *m_pszGrayedOutReason;
|
||||
|
||||
// IClientRenderable
|
||||
virtual const Vector& GetRenderOrigin( void ) { return vec3_origin; }
|
||||
virtual const QAngle& GetRenderAngles( void ) { return vec3_angle; }
|
||||
virtual bool ShouldDraw( void ) { return false; }
|
||||
virtual bool IsTransparent( void ) { return false;}
|
||||
virtual const matrix3x4_t &RenderableToWorldTransform() { static matrix3x4_t mat; SetIdentityMatrix( mat ); return mat; }
|
||||
virtual void GetRenderBounds( Vector& mins, Vector& maxs );
|
||||
#endif
|
||||
|
||||
private:
|
||||
CNetworkVarEmbedded( CAttributeList, m_AttributeList );
|
||||
CNetworkVarEmbedded( CAttributeList, m_NetworkedDynamicAttributesForDemos );
|
||||
|
||||
// Some custom gamemodes are using server plugins to modify weapon attributes.
|
||||
// This variable allows them to completely set their own attributes on a weapon
|
||||
// and have the client and server ignore the static attributes.
|
||||
CNetworkVar( bool, m_bOnlyIterateItemViewAttributes );
|
||||
};
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
bool DoesItemPassSearchFilter( const class IEconItemDescription *pDescription, const wchar_t* wszFilter );
|
||||
CBasePlayer *GetPlayerByAccountID( uint32 unAccountID );
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
#endif // ECON_ITEM_CONSTANTS_H
|
||||
@@ -0,0 +1,71 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Functions related to dynamic recipes
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#include "cbase.h"
|
||||
#include "econ_quests.h"
|
||||
#ifndef GC_DLL
|
||||
#include "quest_objective_manager.h"
|
||||
#endif
|
||||
|
||||
bool IsQuestItemUnidentified( const CEconItem* pQuestItem )
|
||||
{
|
||||
return pQuestItem && IsUnacknowledged( pQuestItem->GetInventoryToken() );
|
||||
}
|
||||
|
||||
bool IsQuestItemReadyToTurnIn( const IEconItemInterface* pQuestItem )
|
||||
{
|
||||
uint32 nRequiredPoints = pQuestItem->GetItemDefinition()->GetQuestDef()->GetMaxStandardPoints();
|
||||
uint32 nEarnedStandardPoints = GetEarnedStandardPoints( pQuestItem );
|
||||
uint32 nEarnedBonusPoints = GetEarnedBonusPoints( pQuestItem );
|
||||
|
||||
return ( nEarnedStandardPoints + nEarnedBonusPoints ) >= nRequiredPoints;
|
||||
}
|
||||
|
||||
bool IsQuestItemFullyCompleted( const IEconItemInterface* pQuestItem )
|
||||
{
|
||||
uint32 nRequiredStandardPoints = pQuestItem->GetItemDefinition()->GetQuestDef()->GetMaxStandardPoints();
|
||||
uint32 nRequiredBonusPoints = pQuestItem->GetItemDefinition()->GetQuestDef()->GetMaxBonusPoints();
|
||||
uint32 nEarnedStandardPoints = GetEarnedStandardPoints( pQuestItem );
|
||||
uint32 nEarnedBonusPoints = GetEarnedBonusPoints( pQuestItem );
|
||||
|
||||
return ( nEarnedStandardPoints + nEarnedBonusPoints ) == ( nRequiredStandardPoints + nRequiredBonusPoints );
|
||||
}
|
||||
|
||||
uint32 GetEarnedStandardPoints( const IEconItemInterface* pQuestItem )
|
||||
{
|
||||
#ifndef GC_DLL
|
||||
const CQuestItemTracker* pItemTracker = assert_cast< const CQuestItemTracker* >( QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( pQuestItem->GetID() ) );
|
||||
if ( pItemTracker )
|
||||
{
|
||||
return pItemTracker->GetEarnedStandardPoints();
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32 nEarnedStandardPoints = 0;
|
||||
static CSchemaAttributeDefHandle pAttribDef_EarnedStandardPoints( "quest earned standard points" );
|
||||
pQuestItem->FindAttribute( pAttribDef_EarnedStandardPoints, &nEarnedStandardPoints );
|
||||
|
||||
|
||||
return nEarnedStandardPoints;
|
||||
}
|
||||
|
||||
uint32 GetEarnedBonusPoints( const IEconItemInterface* pQuestItem )
|
||||
{
|
||||
|
||||
#ifndef GC_DLL
|
||||
const CQuestItemTracker* pItemTracker = assert_cast< const CQuestItemTracker* >( QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( pQuestItem->GetID() ) );
|
||||
if ( pItemTracker )
|
||||
{
|
||||
return pItemTracker->GetEarnedBonusPoints();
|
||||
}
|
||||
#endif
|
||||
uint32 nEarnedBonusPoints = 0;
|
||||
static CSchemaAttributeDefHandle pAttribDef_EarnedBonusPoints( "quest earned bonus points" );
|
||||
pQuestItem->FindAttribute( pAttribDef_EarnedBonusPoints, &nEarnedBonusPoints );
|
||||
|
||||
return nEarnedBonusPoints;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Functions related to quests
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECON_QUESTS
|
||||
#define ECON_QUESTS
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Given a quest item, return if the quest is considered "unidentified"
|
||||
//-----------------------------------------------------------------------------
|
||||
bool IsQuestItemUnidentified( const CEconItem* pQuestItem );
|
||||
bool IsQuestItemReadyToTurnIn( const IEconItemInterface* pQuestItem );
|
||||
bool IsQuestItemFullyCompleted( const IEconItemInterface* pQuestItem );
|
||||
uint32 GetEarnedStandardPoints( const IEconItemInterface* pQuestItem );
|
||||
uint32 GetEarnedBonusPoints( const IEconItemInterface* pQuestItem );
|
||||
|
||||
#endif // ECON_QUESTS
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,621 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Common objects and utilities related to the in-game item store
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECON_STORE_H
|
||||
#define ECON_STORE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "UtlSortVector.h"
|
||||
#include "vstdlib/IKeyValuesSystem.h"
|
||||
#include "econ/econ_storecategory.h"
|
||||
#ifdef CLIENT_DLL
|
||||
#include "client_community_market.h"
|
||||
#endif // CLIENT_DLL
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Error code enum for purchase messages
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EPurchaseResult
|
||||
{
|
||||
k_EPurchaseResultOK = 1, // Success
|
||||
k_EPurchaseResultFail = 2, // Generic error
|
||||
k_EPurchaseResultInvalidParam = 3, // Invalid parameter
|
||||
k_EPurchaseResultInternalError = 4, // Internal error
|
||||
k_EPurchaseResultNotApproved = 5, // Tried to finalize a transaction that has not yet been approved
|
||||
k_EPurchaseResultAlreadyCommitted = 6, // Tried to finalize a transaction that has already been committed
|
||||
k_EPurchaseResultUserNotLoggedIn = 7, // User is not logged into Steam
|
||||
k_EPurchaseResultWrongCurrency = 8, // Microtransaction's currency does not match user's wallet currency
|
||||
k_EPurchaseResultAccountError = 9, // User's account does not exist or is temporarily unavailable
|
||||
k_EPurchaseResultInvalidItem = 10, // User is trying to purchase an item that doesn't exist or is not for sale
|
||||
k_EPurchaseResultNotEnoughBackpackSpace = 11, // User did not have enough backpack space
|
||||
k_EPurchaseResultLimitedQuantityItemsUnavailable = 12, // User tried to purchase limited-quantity items but there weren't enough left in stock
|
||||
|
||||
k_EPurchaseResultInsufficientFunds = 100, // User does not have wallet funds
|
||||
k_EPurchaseResultTimedOut = 101, // Time limit for finalization has been exceeded
|
||||
k_EPurchaseResultAcctDisabled = 102, // Steam account is disabled
|
||||
k_EPurchaseResultAcctCannotPurchase = 103, // Steam account is not allowed to make a purchase
|
||||
k_EMicroTxnResultFailedFraudChecks = 104, // Fraud checks inside of Steam failed
|
||||
|
||||
k_EPurchaseResultOldPriceSheet = 150, // Information on the purchase didn't match the current price sheet
|
||||
k_EPurchaseResultTxnNotFound = 151 // Could not find the transaction specified
|
||||
};
|
||||
|
||||
|
||||
const char *PchNameFromEPurchaseResult( EPurchaseResult ePurchaseState );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: State of a transaction
|
||||
//
|
||||
// WARNING: VALUES STORED IN DATABASE. DO NOT RENUMBER!!!
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EPurchaseState
|
||||
{
|
||||
k_EPurchaseStateInvalid = 0, // Invalid
|
||||
k_EPurchaseStateInit = 1, // We have sent InitPurchase to Steam
|
||||
k_EPurchaseStateWaitingForAuthorization = 2, // We have gotten initial authorization from Steam. Waiting for user to authorize.
|
||||
k_EPurchaseStatePending = 3, // We are attempting to commit the transaction
|
||||
k_EPurchaseStateComplete = 4, // The transaction was successful
|
||||
k_EPurchaseStateFailed = 5, // The transaction failed
|
||||
k_EPurchaseStateCanceled = 6, // The transaction was canceled
|
||||
k_EPurchaseStateRefunded = 7, // The transaction was refunded
|
||||
k_EPurchaseStateChargeback = 8, // The transaction was charged back
|
||||
k_EPurchaseStateChargebackReversed = 9, // A chargeback has failed and we got the money
|
||||
k_EPurchaseStateLast = k_EPurchaseStateChargebackReversed,
|
||||
};
|
||||
|
||||
const char *PchNameFromEPurchaseState( EPurchaseState ePurchaseState );
|
||||
|
||||
// DO NOT RENUMBER! These values are stored in the audit log table.
|
||||
enum EGCTransactionAuditReason
|
||||
{
|
||||
k_EGCTransactionAudit_GCTransactionCompleted = 0, // The transaction completed successfully on the GC.
|
||||
k_EGCTransactionAudit_GCTransactionInit = 1, // The transaction was initialized.
|
||||
k_EGCTransactionAudit_GCTransactionPostInit = 2, // The result of attempting to initialize the transaction. This is where the SteamTxnID is set.
|
||||
k_EGCTransactionAudit_GCTransactionFinalize = 3, // We have started to finalize the transaction (so probably set it to pending).
|
||||
k_EGCTransactionAudit_GCTransactionFinalizeFailed = 4, // Our attempt to finalize the transaction failed for some reason (not due to a timeout).
|
||||
k_EGCTransactionAudit_GCTransactionCanceled = 5, // The client requested that we cancel the transaction.
|
||||
k_EGCTransactionAudit_SteamFailedMismatch = 6, // Steam failed the transaction but we did not.
|
||||
k_EGCTransactionAudit_GCRemovePurchasedItems = 7, // We are attempting to remove the purchased items from their backpack (due to rollback or failure).
|
||||
k_EGCTransactionAudit_GCTransactionInsert = 8, // We are inserting a transaction, usually one created by a web interface (i.e.: a cd-key operation) instead of a standard store interaction.
|
||||
k_EGCTransactionAudit_GCTransactionCompletedPostChargeback = 9, // We thought this transaction had been charged back but Steam came back later and told us it was successful after all.
|
||||
|
||||
k_EGCTransactionAuditLast = k_EGCTransactionAudit_GCTransactionCompletedPostChargeback,
|
||||
};
|
||||
|
||||
const char *PchNameFromEGCTransactionAuditReason( EGCTransactionAuditReason eAuditReason );
|
||||
|
||||
enum EGCTransactionAuditInsertReason
|
||||
{
|
||||
k_EGCTransactionAuditInsert_Invalid = 0, //
|
||||
k_EGCTransactionAuditInsert_CDKey = 1, // A CD Key was used for this transaction.
|
||||
k_EGCTransactionAuditInsert_SettlementNoMatch_Failed = 2, // We inserted a failed record during settlement to unblock the process.
|
||||
k_EGCTransactionAuditInsert_SettlementNoMatch_Pending = 3, // We inserted a pending record during settlement to unblock the process.
|
||||
|
||||
k_EGCTransactionAuditInsertLast = k_EGCTransactionAuditInsert_SettlementNoMatch_Pending,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Currencies we support
|
||||
//
|
||||
// WARNING: VALUES STORED IN DATABASE. DO NOT RENUMBER!!!
|
||||
// WARNING: THESE DON'T MATCH THE STEAM NUMERIC IDS!!! WE TALK USING CURRENCY
|
||||
// CODES LIKE "VND" AND IF YOU SAY "15" TERRIBLE THINGS WILL HAPPEN
|
||||
//-----------------------------------------------------------------------------
|
||||
enum ECurrency
|
||||
{
|
||||
k_ECurrencyFirst = 0,
|
||||
k_ECurrencyUSD = 0,
|
||||
k_ECurrencyGBP = 1,
|
||||
k_ECurrencyEUR = 2,
|
||||
k_ECurrencyRUB = 3,
|
||||
k_ECurrencyBRL = 4,
|
||||
// space for Dota currencies
|
||||
k_ECurrencyJPY = 8,
|
||||
k_ECurrencyNOK = 9,
|
||||
k_ECurrencyIDR = 10,
|
||||
k_ECurrencyMYR = 11,
|
||||
k_ECurrencyPHP = 12,
|
||||
k_ECurrencySGD = 13,
|
||||
k_ECurrencyTHB = 14,
|
||||
k_ECurrencyVND = 15,
|
||||
k_ECurrencyKRW = 16,
|
||||
k_ECurrencyTRY = 17,
|
||||
k_ECurrencyUAH = 18,
|
||||
k_ECurrencyMXN = 19,
|
||||
k_ECurrencyCAD = 20,
|
||||
k_ECurrencyAUD = 21,
|
||||
k_ECurrencyNZD = 22,
|
||||
k_ECurrencyPLN = 23,
|
||||
k_ECurrencyCHF = 24,
|
||||
k_ECurrencyCNY = 25,
|
||||
k_ECurrencyTWD = 26,
|
||||
k_ECurrencyHKD = 27,
|
||||
k_ECurrencyINR = 28,
|
||||
k_ECurrencyAED = 29,
|
||||
k_ECurrencySAR = 30,
|
||||
k_ECurrencyZAR = 31,
|
||||
k_ECurrencyCOP = 32,
|
||||
k_ECurrencyPEN = 33,
|
||||
k_ECurrencyCLP = 34,
|
||||
|
||||
// NOTE: Not actually the Maximum currency value, but the Terminator for the possible currency code range.
|
||||
k_ECurrencyMax = 35,
|
||||
|
||||
// make this a big number so we can avoid having to move it when we add another currency type
|
||||
k_ECurrencyInvalid = 255,
|
||||
k_ECurrencyCDKeyTransaction = k_ECurrencyInvalid,
|
||||
};
|
||||
|
||||
// Macro for looping across all valid currencies
|
||||
#define FOR_EACH_CURRENCY( _i ) for ( ECurrency _i = GetFirstValidCurrency(); _i != k_ECurrencyInvalid; _i = GetNextValidCurrency( _i ) )
|
||||
|
||||
const char *PchNameFromECurrency( ECurrency eCurrency ); // NOTE: Defined with ENUMSTRINGS_START/ENUMSTRINGS_REVERSE macros
|
||||
ECurrency ECurrencyFromName( const char *pchName ); //
|
||||
|
||||
inline bool BIsCurrencyValid( ECurrency eCurrency )
|
||||
{
|
||||
switch ( eCurrency )
|
||||
{
|
||||
case k_ECurrencyUSD:
|
||||
case k_ECurrencyGBP:
|
||||
case k_ECurrencyEUR:
|
||||
case k_ECurrencyRUB:
|
||||
case k_ECurrencyBRL:
|
||||
case k_ECurrencyJPY:
|
||||
case k_ECurrencyNOK:
|
||||
case k_ECurrencyIDR:
|
||||
case k_ECurrencyMYR:
|
||||
case k_ECurrencyPHP:
|
||||
case k_ECurrencySGD:
|
||||
case k_ECurrencyTHB:
|
||||
case k_ECurrencyVND:
|
||||
case k_ECurrencyKRW:
|
||||
case k_ECurrencyTRY:
|
||||
case k_ECurrencyUAH:
|
||||
case k_ECurrencyMXN:
|
||||
case k_ECurrencyCAD:
|
||||
case k_ECurrencyAUD:
|
||||
case k_ECurrencyNZD:
|
||||
//case k_ECurrencyPLN:
|
||||
case k_ECurrencyCHF:
|
||||
case k_ECurrencyCNY:
|
||||
case k_ECurrencyTWD:
|
||||
case k_ECurrencyHKD:
|
||||
case k_ECurrencyINR:
|
||||
case k_ECurrencyAED:
|
||||
case k_ECurrencySAR:
|
||||
case k_ECurrencyZAR:
|
||||
case k_ECurrencyCOP:
|
||||
case k_ECurrencyPEN:
|
||||
case k_ECurrencyCLP:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline ECurrency GetFirstValidCurrency()
|
||||
{
|
||||
for ( int i = k_ECurrencyFirst; i < k_ECurrencyMax; i++ )
|
||||
{
|
||||
if ( BIsCurrencyValid( (ECurrency)i ) )
|
||||
return (ECurrency)i;
|
||||
}
|
||||
return k_ECurrencyInvalid;
|
||||
}
|
||||
|
||||
inline ECurrency GetNextValidCurrency( ECurrency ePrevious )
|
||||
{
|
||||
for ( int i = ePrevious + 1; i < k_ECurrencyMax; i++ )
|
||||
{
|
||||
if ( BIsCurrencyValid( (ECurrency)i ) )
|
||||
return (ECurrency)i;
|
||||
}
|
||||
return k_ECurrencyInvalid;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Simple struct for pairing a sort type with a localization string
|
||||
//-----------------------------------------------------------------------------
|
||||
struct ItemSortTypeData_t
|
||||
{
|
||||
const char *szSortDesc; // localization string
|
||||
uint32 iSortType; // maps to the GC-specific sort value
|
||||
};
|
||||
|
||||
// Description of a single item for sale
|
||||
struct econ_store_entry_t
|
||||
{
|
||||
// Constructor
|
||||
econ_store_entry_t()
|
||||
: m_pchCategoryTags( NULL ),
|
||||
m_unGiftSteamPackageID( 0 ),
|
||||
m_bHighlighted( false )
|
||||
{
|
||||
V_memset( m_unBaseCosts, 0, sizeof(m_unBaseCosts) );
|
||||
V_memset( m_unSaleCosts, 0, sizeof(m_unSaleCosts) );
|
||||
}
|
||||
|
||||
void SetItemDefinitionIndex( item_definition_index_t usDefIndex );
|
||||
item_definition_index_t GetItemDefinitionIndex() const { return m_usDefIndex; }
|
||||
|
||||
void InitCategoryTags( const char *pTags ); // Sets m_pchCategoryTags and initializes m_vecTagIds and m_fRentalPriceScale
|
||||
|
||||
bool IsListedInCategory( StoreCategoryID_t unID ) const; // Is this item listed in the given category?
|
||||
bool IsListedInSubcategories( const CEconStoreCategoryManager::StoreCategory_t &Category ) const; // Is this item listed in one of Category's subcategories?
|
||||
bool IsListedInCategoryOrSubcategories( const CEconStoreCategoryManager::StoreCategory_t &Category ) const; // Is this item listed in Category or one of Category's subcategories?
|
||||
|
||||
bool IsOnSale( ECurrency eCurrency ) const;
|
||||
bool IsRentable() const;
|
||||
#ifdef CLIENT_DLL
|
||||
bool HasDiscount( ECurrency eCurrency, item_price_t *out_punOptionalBasePrice ) const; // returns true if we're on sale or if we're a bundle with a discounted total price
|
||||
#endif // CLIENT_DLL
|
||||
item_price_t GetCurrentPrice( ECurrency eCurrency ) const;
|
||||
float GetRentalPriceScale() const;
|
||||
|
||||
uint32 GetGiftSteamPackageID() const { return m_unGiftSteamPackageID; }
|
||||
|
||||
// Helper function -- so we do this calculation in a single place.
|
||||
static item_price_t GetDiscountedPrice( ECurrency eCurrency, item_price_t unBasePrice, float fDiscountPercentage );
|
||||
|
||||
static item_price_t CalculateSalePrice( const econ_store_entry_t* pSaleStoreEntry, ECurrency eCurrency, float fDiscountPercentage, int32 *out_pAdjustedDiscountPercentage = NULL );
|
||||
|
||||
item_price_t GetBasePrice( ECurrency eCurrency ) const
|
||||
{
|
||||
Assert( eCurrency >= k_ECurrencyFirst );
|
||||
Assert( eCurrency < k_ECurrencyMax );
|
||||
if ( !( eCurrency >= 0 && eCurrency < k_ECurrencyMax ) )
|
||||
return 0;
|
||||
#ifdef CLIENT_DLL
|
||||
if ( m_bIsMarketItem )
|
||||
{
|
||||
const client_market_data_t *pClientMarketData = GetClientMarketData( GetItemDefinitionIndex(), AE_UNIQUE );
|
||||
if ( !pClientMarketData )
|
||||
return 0;
|
||||
return pClientMarketData->m_unLowestPrice;
|
||||
}
|
||||
#endif
|
||||
// Weird-looking pattern: we're making sure that the value we're about to return fits correctly
|
||||
// into the variable we're about to put it into. We do this to avoid integer conversion problems,
|
||||
// especially overflow (!) where someone changes one of the return type or the storage type but
|
||||
// not the other.
|
||||
Assert( (item_price_t)m_unBaseCosts[eCurrency] == m_unBaseCosts[eCurrency] );
|
||||
return m_unBaseCosts[eCurrency];
|
||||
}
|
||||
|
||||
item_price_t GetSalePrice( ECurrency eCurrency ) const
|
||||
{
|
||||
Assert( eCurrency >= k_ECurrencyFirst );
|
||||
Assert( eCurrency < k_ECurrencyMax );
|
||||
if ( !( eCurrency >= 0 && eCurrency < k_ECurrencyMax ) )
|
||||
return 0;
|
||||
#ifdef CLIENT_DLL
|
||||
if ( m_bIsMarketItem )
|
||||
{
|
||||
const client_market_data_t *pClientMarketData = GetClientMarketData( GetItemDefinitionIndex(), AE_UNIQUE );
|
||||
if ( !pClientMarketData )
|
||||
return 0;
|
||||
return pClientMarketData->m_unLowestPrice;
|
||||
}
|
||||
#endif
|
||||
// Weird-looking pattern: we're making sure that the value we're about to return fits correctly
|
||||
// into the variable we're about to put it into. We do this to avoid integer conversion problems,
|
||||
// especially overflow (!) where someone changes one of the return type or the storage type but
|
||||
// not the other.
|
||||
Assert( (item_price_t)m_unSaleCosts[eCurrency] == m_unSaleCosts[eCurrency] );
|
||||
return m_unSaleCosts[eCurrency];
|
||||
}
|
||||
|
||||
uint16 GetQuantity() const
|
||||
{
|
||||
return m_usQuantity;
|
||||
}
|
||||
|
||||
const char* GetDate() const
|
||||
{
|
||||
return m_strDate.Get();
|
||||
}
|
||||
|
||||
bool CanPreview() const
|
||||
{
|
||||
// No previewing of new items or weapons.
|
||||
return m_bPreviewAllowed;
|
||||
}
|
||||
|
||||
void SetQuantity( uint16 usQuantity )
|
||||
{
|
||||
Assert( usQuantity > 0 );
|
||||
m_usQuantity = usQuantity;
|
||||
}
|
||||
|
||||
void ValidatePrice( ECurrency eCurrency, item_price_t unPrice );
|
||||
|
||||
void SetBasePrice( ECurrency eCurrency, item_price_t unPrice )
|
||||
{
|
||||
Assert( eCurrency >= k_ECurrencyFirst );
|
||||
Assert( eCurrency < k_ECurrencyMax );
|
||||
if ( !( eCurrency >= 0 && eCurrency < k_ECurrencyMax ) )
|
||||
return;
|
||||
|
||||
ValidatePrice( eCurrency, unPrice );
|
||||
|
||||
m_unBaseCosts[eCurrency] = unPrice;
|
||||
}
|
||||
|
||||
void SetSalePrice( ECurrency eCurrency, item_price_t unPrice )
|
||||
{
|
||||
Assert( eCurrency >= k_ECurrencyFirst );
|
||||
Assert( eCurrency < k_ECurrencyMax );
|
||||
if ( !( eCurrency >= 0 && eCurrency < k_ECurrencyMax ) )
|
||||
return;
|
||||
|
||||
ValidatePrice( eCurrency, unPrice );
|
||||
|
||||
// It's legal to have a sale price of zero, meaninig "this item is not on sale" in this
|
||||
// currency.
|
||||
// Assert( unPrice > 0 );
|
||||
m_unSaleCosts[eCurrency] = unPrice;
|
||||
}
|
||||
|
||||
void SetSteamGiftPackageID( uint32 unGiftSteamPackageID )
|
||||
{
|
||||
m_unGiftSteamPackageID = unGiftSteamPackageID;
|
||||
}
|
||||
|
||||
void SetDate( const char* pszDate )
|
||||
{
|
||||
m_strDate.Set( pszDate );
|
||||
}
|
||||
|
||||
|
||||
bool IsValidCategoryTagIndex( uint32 iIndex ) const
|
||||
{
|
||||
AssertMsg( m_vecCategoryTags.IsValidIndex( iIndex ), "Category tag index out of range." );
|
||||
return m_vecCategoryTags.IsValidIndex( iIndex );
|
||||
}
|
||||
|
||||
uint32 GetCategoryTagCount() const
|
||||
{
|
||||
return m_vecCategoryTags.Count();
|
||||
}
|
||||
|
||||
const char *GetCategoryTagNameFromIndex( uint32 iIndex ) const
|
||||
{
|
||||
if ( !IsValidCategoryTagIndex( iIndex ) )
|
||||
return NULL;
|
||||
|
||||
return m_vecCategoryTags[ iIndex ].m_strName;
|
||||
}
|
||||
|
||||
StoreCategoryID_t GetCategoryTagIDFromIndex( uint32 iIndex ) const;
|
||||
|
||||
const char *GetCategoryTagString() const
|
||||
{
|
||||
return m_pchCategoryTags;
|
||||
}
|
||||
|
||||
bool m_bLimited; // Item is a limited sale
|
||||
bool m_bNew; // Item is new
|
||||
bool m_bHighlighted; // Item is highlighted
|
||||
CUtlString m_strDate; // Date Added
|
||||
bool m_bSoldOut; // True if the item is sold out from the store (for example if the item is a ticket or another physical item)
|
||||
bool m_bPreviewAllowed; // Is this item previewable?
|
||||
bool m_bIsPackItem; // Is this item a pack item? Pack items are items which are not individually for sale, but are sold via a bundle known as a "pack bundle"
|
||||
|
||||
bool m_bIsMarketItem; // Is Market Item Link
|
||||
|
||||
private:
|
||||
item_definition_index_t m_usDefIndex; // DefIndex of the item
|
||||
|
||||
// Private data so that we can check in the accessor functions that the data fits before returning it.
|
||||
item_price_t m_unBaseCosts[k_ECurrencyMax]; // Costs of the items indexed by ECurrency -- if the items are on sale, this will be the current sale price
|
||||
item_price_t m_unSaleCosts[k_ECurrencyMax]; // Original costs of the items indexed by ECurrency -- if the items are on sale, this will be the pre-sale price
|
||||
uint16 m_usQuantity; // Quantity sold in a single purchase (ie., dueling pistols come in stacks of five)
|
||||
float m_fRentalPriceScale; // 100.0 or greater means "unavailable to rent"
|
||||
uint32 m_unGiftSteamPackageID; // if non-zero, when this item is purchased (including inside bundles, etc.), grant a gift copy of this Steam package
|
||||
|
||||
struct CategoryTag_t
|
||||
{
|
||||
CUtlString m_strName; // Individual tag name, like "Weapons," "New," etc.
|
||||
StoreCategoryID_t m_unID; // The category ID
|
||||
};
|
||||
CCopyableUtlVector< CategoryTag_t > m_vecCategoryTags; // Category tag data
|
||||
|
||||
const char *m_pchCategoryTags; // All tags - this string will something like: "New" or "Weapons+New" etc.
|
||||
};
|
||||
|
||||
#ifdef GC_DLL
|
||||
struct econ_store_timed_sale_item_t
|
||||
{
|
||||
item_definition_index_t m_unItemDef;
|
||||
float m_fPricePercentage; // 100.0 = regular price; 50.0 = half price
|
||||
};
|
||||
|
||||
struct econ_store_timed_sale_t
|
||||
{
|
||||
bool m_bSaleCurrentlyActive; // set in ::UpdatePricesForTimedSales()
|
||||
CUtlConstString m_sIdentifier; // can't point to memory in the base KV because we toss it afterwards
|
||||
RTime32 m_SaleStartTime;
|
||||
RTime32 m_SaleEndTime;
|
||||
CUtlVector<econ_store_timed_sale_item_t> m_vecSaleItems;
|
||||
|
||||
// Work around protected default vector constructor.
|
||||
econ_store_timed_sale_t() { }
|
||||
econ_store_timed_sale_t( const econ_store_timed_sale_t& other )
|
||||
: m_bSaleCurrentlyActive( other.m_bSaleCurrentlyActive )
|
||||
, m_sIdentifier( other.m_sIdentifier )
|
||||
, m_SaleStartTime( other.m_SaleStartTime )
|
||||
, m_SaleEndTime( other.m_SaleEndTime )
|
||||
{
|
||||
m_vecSaleItems.CopyArray( other.m_vecSaleItems.Base(), other.m_vecSaleItems.Count() );
|
||||
}
|
||||
};
|
||||
#endif // GC_DLL
|
||||
|
||||
// Spend xxx amount of money, get a free item from the loot list
|
||||
struct store_promotion_spend_for_free_item_t
|
||||
{
|
||||
const CEconItemDefinition *m_pItemDef;
|
||||
item_price_t m_rgusPriceThreshold[k_ECurrencyMax]; // Price threshold to get an item from the loot list indexed by ECurrency
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Class that represents what's currently for sale in TF
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef enum
|
||||
{
|
||||
kEconStoreSortType_Price_HighestToLowest = 0,
|
||||
kEconStoreSortType_Price_LowestToHighest = 1,
|
||||
kEconStoreSortType_DevName_AToZ = 2,
|
||||
kEconStoreSortType_DevName_ZToA = 3,
|
||||
kEconStoreSortType_Name_AToZ = 4,
|
||||
kEconStoreSortType_Name_ZToA = 5,
|
||||
kEconStoreSortType_ItemDefIndex = 6,
|
||||
kEconStoreSortType_ReverseItemDefIndex = 7,
|
||||
kEconStoreSortType_DateNewest = 8,
|
||||
kEconStoreSortType_DateOldest = 9,
|
||||
} eEconStoreSortType;
|
||||
|
||||
struct price_point_map_key_t
|
||||
{
|
||||
item_price_t m_unPriceUSD;
|
||||
ECurrency m_eCurrency;
|
||||
|
||||
static bool Less( const price_point_map_key_t& a, const price_point_map_key_t& b )
|
||||
{
|
||||
if ( a.m_eCurrency == b.m_eCurrency )
|
||||
return a.m_unPriceUSD < b.m_unPriceUSD;
|
||||
|
||||
return a.m_eCurrency < b.m_eCurrency;
|
||||
}
|
||||
};
|
||||
|
||||
typedef CUtlMap<price_point_map_key_t, item_price_t> CurrencyPricePointMap_t;
|
||||
|
||||
class CEconStorePriceSheet
|
||||
{
|
||||
public:
|
||||
typedef CUtlMap<item_definition_index_t, econ_store_entry_t> StoreEntryMap_t;
|
||||
typedef CUtlMap<const char *, float> RentalPriceScaleMap_t;
|
||||
typedef CUtlVector<item_definition_index_t> FeaturedItems_t;
|
||||
|
||||
CEconStorePriceSheet();
|
||||
~CEconStorePriceSheet();
|
||||
|
||||
bool InitFromKV( KeyValues *pKVPrices );
|
||||
|
||||
// Gets or sets the version stamp. This is just a number the GC can use
|
||||
// to know if the client is in sync without sending it down on every
|
||||
// request.
|
||||
RTime32 GetVersionStamp( void ) const { return m_RTimeVersionStamp; }
|
||||
void SetVersionStamp( RTime32 stamp ) { m_RTimeVersionStamp = stamp; }
|
||||
|
||||
uint32 GetHashForAllItems() const { return m_unHashForAllItems; }
|
||||
|
||||
typedef CUtlMap<uint16, econ_store_entry_t> EconStoreEntryMap_t;
|
||||
EconStoreEntryMap_t &GetEntries() { return m_mapEntries; }
|
||||
|
||||
#ifdef GC_DLL
|
||||
econ_store_entry_t *GetEntryWriteable( item_definition_index_t unDefIndex );
|
||||
#endif // GC_DLL
|
||||
|
||||
const StoreEntryMap_t &GetEntries() const { return m_mapEntries; }
|
||||
const CEconStoreCategoryManager::StoreCategory_t *GetFeaturedItems( void ) { return &m_FeaturedItems; }
|
||||
const econ_store_entry_t *GetEntry( item_definition_index_t usDefIndex ) const;
|
||||
|
||||
uint32 GetFeaturedItemIndex() const { return m_unFeaturedItemIndex; }
|
||||
void SetFeaturedItemIndex( uint32 unIdx ) { m_unFeaturedItemIndex = unIdx; }
|
||||
|
||||
void SetEconStoreSortType( eEconStoreSortType eType ) { m_eEconStoreSortType = eType; }
|
||||
eEconStoreSortType GetEconStoreSortType() { return m_eEconStoreSortType; }
|
||||
|
||||
const store_promotion_spend_for_free_item_t *GetStorePromotion_SpendForFreeItem() const { return &m_StorePromotionSpendForFreeItem; }
|
||||
const CEconItemDefinition * GetStorePromotion_FirstTimePurchaseItem() const { return m_pStorePromotionFirstTimePurchaseItem; }
|
||||
const CEconItemDefinition * GetStorePromotion_FirstTimeWebPurchaseItem() const { return m_pStorePromotionFirstTimeWebPurchaseItem; }
|
||||
|
||||
uint32 GetPreviewPeriod() const { return m_unPreviewPeriod; }
|
||||
uint32 GetBonusDiscountPeriod() const { return m_unBonusDiscountPeriod; }
|
||||
float GetPreviewPeriodDiscount() const { return m_flPreviewPeriodDiscount; }
|
||||
|
||||
bool BItemExistsInPriceSheet( item_definition_index_t unDefIndex ) const;
|
||||
|
||||
float GetRentalPriceScale( const char *pszCategory ) const
|
||||
{
|
||||
RentalPriceScaleMap_t::IndexType_t i = m_mapRentalPriceScales.Find( pszCategory );
|
||||
if ( i == RentalPriceScaleMap_t::InvalidIndex() )
|
||||
return 1.0f;
|
||||
|
||||
return m_mapRentalPriceScales[i];
|
||||
}
|
||||
|
||||
KeyValues *GetRawData() const { return m_pKVRaw; }
|
||||
|
||||
#ifdef GC_DLL
|
||||
void UpdatePricesForTimedSales( const RTime32 curTime );
|
||||
void DumpTimeSaleState( const RTime32 curTime ) const;
|
||||
#endif // GC_DLL
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
const FeaturedItems_t& GetFeaturedItems() const { return m_vecFeaturedItems; }
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
private:
|
||||
bool BInitEntryFromKV( KeyValues *pKVEntry );
|
||||
#ifdef CLIENT_DLL
|
||||
bool BInitMarketEntryFromKV( KeyValues *pKVEntry );
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
#ifdef GC_DLL
|
||||
bool InitTimedSaleEntryFromKV( KeyValues *pKVTimedSaleEntry );
|
||||
bool VerifyTimedSaleEntries();
|
||||
#endif // GC_DLL
|
||||
|
||||
private:
|
||||
void Clear();
|
||||
uint32 CalculateHashFromItems() const;
|
||||
|
||||
KeyValues *m_pKVRaw;
|
||||
RTime32 m_RTimeVersionStamp;
|
||||
CEconStoreCategoryManager::StoreCategory_t m_FeaturedItems; // Special section, not a tab, kept outside m_vecContents
|
||||
StoreEntryMap_t m_mapEntries;
|
||||
RentalPriceScaleMap_t m_mapRentalPriceScales;
|
||||
store_promotion_spend_for_free_item_t m_StorePromotionSpendForFreeItem;
|
||||
CEconItemDefinition* m_pStorePromotionFirstTimePurchaseItem;
|
||||
CEconItemDefinition* m_pStorePromotionFirstTimeWebPurchaseItem;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
FeaturedItems_t m_vecFeaturedItems;
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
#ifdef GC_DLL
|
||||
CUtlVector<econ_store_timed_sale_t> m_vecTimedSales;
|
||||
#endif // GC_DLL
|
||||
|
||||
// changes based on experiments
|
||||
uint32 m_unFeaturedItemIndex;
|
||||
eEconStoreSortType m_eEconStoreSortType;
|
||||
|
||||
uint32 m_unPreviewPeriod;
|
||||
uint32 m_unBonusDiscountPeriod;
|
||||
float m_flPreviewPeriodDiscount;
|
||||
uint32 m_unHashForAllItems;
|
||||
|
||||
// price point lookup
|
||||
CurrencyPricePointMap_t m_mapCurrencyPricePoints;
|
||||
};
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
void MakeMoneyString( wchar_t *pchDest, uint32 nDest, item_price_t unPrice, ECurrency eCurrencyCode );
|
||||
|
||||
bool ShouldUseNewStore();
|
||||
int GetStoreVersion();
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
const CEconStorePriceSheet *GetEconPriceSheet();
|
||||
|
||||
#endif // ECON_STORE_H
|
||||
@@ -0,0 +1,267 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Base class for generating store meta data. Abstract methods need
|
||||
// to be overridden on a per-product basis.
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "cbase.h"
|
||||
#include "econ_storecategory.h"
|
||||
#include "econ_store.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Invalid = (StoreCategoryID_t)0;
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_New = CEconStoreCategoryManager::GetCategoryID( "New" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Weapons = CEconStoreCategoryManager::GetCategoryID( "Weapons" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Limited = CEconStoreCategoryManager::GetCategoryID( "Limited" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Maps = CEconStoreCategoryManager::GetCategoryID( "Maps" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Cosmetics = CEconStoreCategoryManager::GetCategoryID( "Cosmetics" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Taunts = CEconStoreCategoryManager::GetCategoryID( "Taunts" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Tools = CEconStoreCategoryManager::GetCategoryID( "Tools" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Bundles = CEconStoreCategoryManager::GetCategoryID( "Bundles" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Collections= CEconStoreCategoryManager::GetCategoryID( "Collections" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Popular = CEconStoreCategoryManager::GetCategoryID( "Popular" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_OnSale = CEconStoreCategoryManager::GetCategoryID( "OnSale" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Featured = CEconStoreCategoryManager::GetCategoryID( "Featured" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_ClassBundles = CEconStoreCategoryManager::GetCategoryID( "Class_Bundles" );
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Highlighted = CEconStoreCategoryManager::GetCategoryID( "Highlighted" );
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
CEconStoreCategoryManager::CEconStoreCategoryManager()
|
||||
{
|
||||
m_unHomeCategoryID = k_CategoryID_Invalid;
|
||||
}
|
||||
|
||||
bool CEconStoreCategoryManager::BInit( CEconStorePriceSheet *pPriceSheet, KeyValues *pStoreMetaDataKV )
|
||||
{
|
||||
KeyValues *pCategoriesKV = pStoreMetaDataKV->FindKey( "categories" );
|
||||
if ( !pCategoriesKV )
|
||||
{
|
||||
AssertMsg( 0, "Could not find 'categories' subkey!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
FOR_EACH_TRUE_SUBKEY( pCategoriesKV, pKVCurCategory )
|
||||
{
|
||||
const int iIndex = m_vecCategories.AddToTail();
|
||||
StoreCategory_t &curCategory = m_vecCategories[ iIndex ];
|
||||
if ( !BInitCategory( pPriceSheet, &curCategory, pKVCurCategory ) )
|
||||
return false;
|
||||
|
||||
// If the current category is the home page, cache off its ID
|
||||
if ( curCategory.m_bIsHome )
|
||||
{
|
||||
m_unHomeCategoryID = curCategory.m_unID;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that any parents point to valid categories
|
||||
FOR_EACH_VEC( m_vecCategories, i )
|
||||
{
|
||||
const StoreCategory_t &curCategory = m_vecCategories[i];
|
||||
|
||||
// Skip current category if it refers to invalid, which is fine
|
||||
if ( curCategory.m_unParentCategoryID == k_CategoryID_Invalid )
|
||||
continue;
|
||||
|
||||
// A category can't be a parent to itself
|
||||
if ( curCategory.m_unID == curCategory.m_unParentCategoryID )
|
||||
{
|
||||
AssertMsg( 0, "Store category %s is using itself as a parent category!", curCategory.m_pchName );
|
||||
}
|
||||
|
||||
// Attempt to find the current section's parent ID
|
||||
bool bFound = false;
|
||||
FOR_EACH_VEC( m_vecCategories, j )
|
||||
{
|
||||
// Don't compare against self
|
||||
if ( i == j )
|
||||
continue;
|
||||
|
||||
if ( m_vecCategories[j].m_unID == curCategory.m_unParentCategoryID )
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we couldn't find the current section's parent ID, assert
|
||||
if ( !bFound )
|
||||
{
|
||||
AssertMsg( 0, "Category %s refers to an unknown parent category - check your spelling!", curCategory.m_pchName );
|
||||
}
|
||||
}
|
||||
|
||||
// Setup child category lists - looping twice to keep this code clean and easy to read
|
||||
FOR_EACH_VEC( m_vecCategories, i )
|
||||
{
|
||||
const StoreCategory_t &curCategory = m_vecCategories[i];
|
||||
|
||||
if ( k_CategoryID_Invalid == curCategory.m_unParentCategoryID )
|
||||
continue;
|
||||
|
||||
StoreCategory_t *pParentCategory = GetStoreCategoryFromID( curCategory.m_unParentCategoryID );
|
||||
if ( !pParentCategory )
|
||||
continue;
|
||||
|
||||
pParentCategory->m_vecSubcategories.AddToTail( &curCategory );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
bool CEconStoreCategoryManager::BInitCategory( CEconStorePriceSheet *pPriceSheet, StoreCategory_t *pCategory, KeyValues* pKVTab )
|
||||
{
|
||||
const char *pDefaultResFile = "Resource/UI/econ/store/v2/StorePage.res";
|
||||
|
||||
// Get the main category name
|
||||
const char* pCategoryName = pKVTab->GetName();
|
||||
if ( !pCategoryName || !pCategoryName[0] )
|
||||
{
|
||||
AssertMsg( 0, "Invalid category name!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool bIsHome = pKVTab->GetBool( "home", false );
|
||||
pCategory->m_bIsHome = bIsHome;
|
||||
|
||||
pCategory->m_pchRawName = pCategoryName;
|
||||
pCategory->m_unID = GetCategoryID( pCategoryName );
|
||||
|
||||
pCategory->m_bUseLargeCells = pKVTab->GetBool( "use_large_cells", false );
|
||||
pCategory->m_bVisible = pKVTab->GetBool( "visible", true );
|
||||
pCategory->m_bInGameOnly = pKVTab->GetBool( "ingame_only", false );
|
||||
pCategory->m_bDefaultTab = pKVTab->GetBool( "default", false );
|
||||
|
||||
#if defined( GC_DLL )
|
||||
// Until we replace the in-game store with the web store, we have this hacky override property, so
|
||||
// that we can call the home page "HOME" in the game client and "TOP SELLERS" on the web. The home page
|
||||
// will be evolving shortly to include a lot more than just a list of top sellers.
|
||||
const char *pchLabelTokenWebOverride = pKVTab->GetString( "web_label_token_override", NULL );
|
||||
#else
|
||||
const char *pchLabelTokenWebOverride = NULL;
|
||||
#endif
|
||||
pCategory->m_pchName = pchLabelTokenWebOverride ? pchLabelTokenWebOverride : pKVTab->GetString( "label_token", "#Store_Unknown" );
|
||||
|
||||
pCategory->m_pchPageClass = pKVTab->GetString( "page_class", "CStorePage" );
|
||||
pCategory->m_pchPageRes = pKVTab->GetString( "page_res", pDefaultResFile );
|
||||
pCategory->m_pchSortType = pKVTab->GetString( "sort_type", "" );
|
||||
|
||||
// Important for web store but not needed for VGUI store
|
||||
#if defined( GC_DLL )
|
||||
if ( !bIsHome )
|
||||
{
|
||||
const char *pchDropdownPrefabName = pKVTab->GetString( "dropdown_prefab", NULL );
|
||||
pCategory->m_pDropdownPrefab = GEconStoreMetaData()->FindDropdownPrefab( pchDropdownPrefabName );
|
||||
if ( !pCategory->m_pDropdownPrefab )
|
||||
{
|
||||
AssertMsg( pCategory->m_pDropdownPrefab, CFmtStr( "Invalid dropdown prefab name, '%s'!", pchDropdownPrefabName ).Access() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pCategory->m_pDropdownPrefab = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Look for a parent category for non-home categories
|
||||
if ( !bIsHome )
|
||||
{
|
||||
const char *pParentCategoryName = pKVTab->GetString( "parent", NULL );
|
||||
if ( pParentCategoryName )
|
||||
{
|
||||
pCategory->m_unParentCategoryID = GetCategoryID( pParentCategoryName );
|
||||
}
|
||||
else
|
||||
{
|
||||
pCategory->m_unParentCategoryID = k_CategoryID_Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEconStoreCategoryManager::BOnPriceSheetLoaded( CEconStorePriceSheet *pPriceSheet )
|
||||
{
|
||||
// Go through all categories/subcategories and add a list of items to each.
|
||||
// If an item belongs to a subcategory, it will also be added to its parent category. For example,
|
||||
// a hat will be added to both the "hats" subcategory and the "items" parent category.
|
||||
FOR_EACH_VEC( m_vecCategories, iCategory )
|
||||
{
|
||||
StoreCategory_t &Category = m_vecCategories[iCategory];
|
||||
|
||||
// find all entries that match
|
||||
const CEconStorePriceSheet::EconStoreEntryMap_t &mapEntries = pPriceSheet->GetEntries();
|
||||
FOR_EACH_MAP_FAST( mapEntries, idx )
|
||||
{
|
||||
const econ_store_entry_t &entry = mapEntries[idx];
|
||||
|
||||
if ( entry.IsListedInCategoryOrSubcategories( Category ) )
|
||||
{
|
||||
Category.m_vecEntries.InsertNoSort( entry.GetItemDefinitionIndex() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::GetCategoryID( const char *pCategoryName )
|
||||
{
|
||||
// Make the input lower case
|
||||
CUtlString strLowerCase = pCategoryName;
|
||||
strLowerCase.ToLower();
|
||||
|
||||
return CRC32_ProcessSingleBuffer( (void*)strLowerCase.Get(), strLowerCase.Length() );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const CEconStoreCategoryManager::StoreCategory_t *CEconStoreCategoryManager::GetStoreCategoryFromID( StoreCategoryID_t unID ) const
|
||||
{
|
||||
return const_cast< CEconStoreCategoryManager * >( this )->GetStoreCategoryFromID( unID );
|
||||
}
|
||||
|
||||
CEconStoreCategoryManager::StoreCategory_t *CEconStoreCategoryManager::GetStoreCategoryFromID( StoreCategoryID_t unID )
|
||||
{
|
||||
if ( k_CategoryID_Invalid != unID )
|
||||
{
|
||||
FOR_EACH_VEC( m_vecCategories, i )
|
||||
{
|
||||
if ( unID == m_vecCategories[i].m_unID )
|
||||
return &m_vecCategories[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
static CEconStoreCategoryManager *gs_pEconStoreCategoryManager = NULL;
|
||||
CEconStoreCategoryManager *GEconStoreCategoryManager()
|
||||
{
|
||||
if ( !gs_pEconStoreCategoryManager )
|
||||
{
|
||||
gs_pEconStoreCategoryManager = new CEconStoreCategoryManager();
|
||||
}
|
||||
|
||||
return gs_pEconStoreCategoryManager;
|
||||
}
|
||||
|
||||
void ClearEconStoreCategoryManager()
|
||||
{
|
||||
delete gs_pEconStoreCategoryManager;
|
||||
gs_pEconStoreCategoryManager = NULL;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef ECON_STORECATEGORY_H
|
||||
#define ECON_STORECATEGORY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined( GC_DLL )
|
||||
#include "econ/econ_storemetadata.h"
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
typedef CRC32_t StoreCategoryID_t;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// sort by price highest to lowest
|
||||
class CEconStoreEntryLess
|
||||
{
|
||||
public:
|
||||
bool Less( const uint16& lhs, const uint16& rhs, void *pContext );
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class CEconStoreCategoryManager
|
||||
{
|
||||
public:
|
||||
CEconStoreCategoryManager();
|
||||
|
||||
bool BInit( CEconStorePriceSheet *pPriceSheet, KeyValues *pStoreMetaDataKV );
|
||||
bool BOnPriceSheetLoaded( CEconStorePriceSheet *pPriceSheet );
|
||||
|
||||
static StoreCategoryID_t GetCategoryID( const char *pCategoryName );
|
||||
|
||||
static StoreCategoryID_t k_CategoryID_Invalid;
|
||||
static StoreCategoryID_t k_CategoryID_New;
|
||||
static StoreCategoryID_t k_CategoryID_Weapons;
|
||||
static StoreCategoryID_t k_CategoryID_Limited;
|
||||
static StoreCategoryID_t k_CategoryID_Maps;
|
||||
static StoreCategoryID_t k_CategoryID_Cosmetics;
|
||||
static StoreCategoryID_t k_CategoryID_Taunts;
|
||||
static StoreCategoryID_t k_CategoryID_Tools;
|
||||
static StoreCategoryID_t k_CategoryID_Bundles;
|
||||
static StoreCategoryID_t k_CategoryID_Collections;
|
||||
static StoreCategoryID_t k_CategoryID_Popular;
|
||||
static StoreCategoryID_t k_CategoryID_OnSale;
|
||||
static StoreCategoryID_t k_CategoryID_Featured;
|
||||
static StoreCategoryID_t k_CategoryID_ClassBundles;
|
||||
static StoreCategoryID_t k_CategoryID_Highlighted;
|
||||
|
||||
struct StoreCategory_t
|
||||
{
|
||||
StoreCategory_t() { V_memset( this, 0, sizeof( StoreCategory_t ) ); }
|
||||
|
||||
int GetNumSubcategories() const { return m_vecSubcategories.Count(); }
|
||||
bool HasSubcategories() const { return m_vecSubcategories.Count() > 1; }
|
||||
bool BIsSubcategory() const { return m_unParentCategoryID != CEconStoreCategoryManager::k_CategoryID_Invalid; }
|
||||
|
||||
bool m_bIsHome:1; // Home page? Default=no.
|
||||
bool m_bUseLargeCells:1; // Display large icons in the store. Default=no.
|
||||
bool m_bDefaultTab:1; // Is this the default tab? Default=no
|
||||
bool m_bVisible:1; // Should this tab be displayed in the store? Default=yes.
|
||||
bool m_bInGameOnly:1; // Is this category only to be displayed in the in-game store (vs. the web store)?
|
||||
const char *m_pchRawName; // Raw name of the tab
|
||||
const char *m_pchName; // Name of the tab
|
||||
const char *m_pchPageClass; // Code class of the store page.
|
||||
const char *m_pchSortType; // How to sort the page.
|
||||
const char *m_pchPageRes; // Res file to use for the page.
|
||||
StoreCategoryID_t m_unID; // A unique ID that is stable across sessions
|
||||
StoreCategoryID_t m_unParentCategoryID;
|
||||
CUtlVector<const StoreCategory_t *> m_vecSubcategories; // A list of ID's for all subcategories
|
||||
CUtlSortVector<uint16, CEconStoreEntryLess> m_vecEntries; // Vector of items for sale
|
||||
#if defined( GC_DLL )
|
||||
const CEconStoreMetaData::DropdownPrefabInfo_t *m_pDropdownPrefab;
|
||||
#endif
|
||||
};
|
||||
|
||||
const StoreCategoryID_t GetHomeCategoryID() const { Assert( m_unHomeCategoryID != k_CategoryID_Invalid ); return m_unHomeCategoryID; }
|
||||
|
||||
const StoreCategory_t *GetStoreCategoryFromID( StoreCategoryID_t unID ) const;
|
||||
int GetNumCategories( void ) const { return m_vecCategories.Count(); }
|
||||
const StoreCategory_t *GetCategoryFromIndex( int i ) const { Assert(i >= 0 && i < m_vecCategories.Count()); return &m_vecCategories[i]; }
|
||||
|
||||
StoreCategory_t *GetFeaturedItems() const { return NULL; }
|
||||
|
||||
private:
|
||||
bool BInitCategory( CEconStorePriceSheet *pPriceSheet, StoreCategory_t *pCategory, KeyValues *pKVTab );
|
||||
|
||||
StoreCategory_t *GetStoreCategoryFromID( StoreCategoryID_t unID );
|
||||
|
||||
CUtlVector< StoreCategory_t > m_vecCategories;
|
||||
|
||||
StoreCategoryID_t m_unHomeCategoryID; // The ID for the home tab
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
CEconStoreCategoryManager *GEconStoreCategoryManager();
|
||||
void ClearEconStoreCategoryManager();
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,860 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "econ_wearable.h"
|
||||
#include "vcollide_parse.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "functionproxy.h"
|
||||
#include "c_te_effect_dispatch.h"
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
#ifdef TF_CLIENT_DLL
|
||||
#include "c_team.h"
|
||||
#include "tf_shareddefs.h"
|
||||
#include "tf_weapon_jar.h"
|
||||
#include "c_tf_player.h"
|
||||
#endif // TF_CLIENT_DLL
|
||||
|
||||
#ifdef TF_DLL
|
||||
#include "tf_player.h"
|
||||
#endif // TF_DLL
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
LINK_ENTITY_TO_CLASS( wearable_item, CEconWearable );
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( EconWearable, DT_WearableItem )
|
||||
|
||||
// Network Table --
|
||||
BEGIN_NETWORK_TABLE( CEconWearable, DT_WearableItem )
|
||||
END_NETWORK_TABLE()
|
||||
// -- Network Table
|
||||
|
||||
// Data Desc --
|
||||
BEGIN_DATADESC( CEconWearable )
|
||||
END_DATADESC()
|
||||
// -- Data Desc
|
||||
|
||||
PRECACHE_REGISTER( wearable_item );
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( TFWearableItem, DT_TFWearableItem )
|
||||
|
||||
// Network Table --
|
||||
BEGIN_NETWORK_TABLE( CTFWearableItem, DT_TFWearableItem )
|
||||
END_NETWORK_TABLE()
|
||||
// -- Network Table
|
||||
|
||||
// Data Desc --
|
||||
BEGIN_DATADESC( CTFWearableItem )
|
||||
END_DATADESC()
|
||||
// -- Data Desc
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SHARED CODE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CEconWearable::CEconWearable()
|
||||
{
|
||||
m_bAlwaysAllow = false;
|
||||
};
|
||||
|
||||
void CEconWearable::InternalSetPlayerDisplayModel( void )
|
||||
{
|
||||
int iClass = 0;
|
||||
int iTeam = 0;
|
||||
|
||||
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
|
||||
CTFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() );
|
||||
if ( pTFPlayer )
|
||||
{
|
||||
iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
|
||||
iTeam = pTFPlayer->GetTeamNumber();
|
||||
}
|
||||
#endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL )
|
||||
|
||||
// Set our model to the player model
|
||||
CEconItemView *pItem = GetAttributeContainer()->GetItem();
|
||||
if ( pItem && pItem->IsValid() )
|
||||
{
|
||||
const char *pszPlayerDisplayModel = pItem->GetPlayerDisplayModel( iClass, iTeam );
|
||||
if ( pszPlayerDisplayModel )
|
||||
{
|
||||
if ( pItem->GetStaticData()->IsContentStreamable() )
|
||||
{
|
||||
modelinfo->RegisterDynamicModel( pszPlayerDisplayModel, IsClient() );
|
||||
|
||||
if ( pItem->GetVisionFilteredDisplayModel() && pItem->GetVisionFilteredDisplayModel()[ 0 ] != '\0' )
|
||||
{
|
||||
modelinfo->RegisterDynamicModel( pItem->GetVisionFilteredDisplayModel(), IsClient() );
|
||||
}
|
||||
}
|
||||
SetModel( pszPlayerDisplayModel );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set up the item. GC data may not be available here depending on
|
||||
// where we're called from.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconWearable::Spawn( void )
|
||||
{
|
||||
InitializeAttributes();
|
||||
|
||||
Precache();
|
||||
|
||||
InternalSetPlayerDisplayModel();
|
||||
|
||||
BaseClass::Spawn();
|
||||
|
||||
AddEffects( EF_BONEMERGE );
|
||||
AddEffects( EF_BONEMERGE_FASTCULL );
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
SetCollisionGroup( COLLISION_GROUP_WEAPON );
|
||||
SetBlocksLOS( false );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Player touches the item. Currently wearables don't appear in the
|
||||
// world, so this is only called directly during equipment assignment.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconWearable::GiveTo( CBaseEntity *pOther )
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer(pOther);
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
pPlayer->EquipWearable( this );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconWearable::RemoveFrom( CBaseEntity *pOther )
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer(pOther);
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
pPlayer->RemoveWearable( this );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CEconWearable::GetSkin( void )
|
||||
{
|
||||
CEconItemView *pItem = GetAttributeContainer()->GetItem(); // Safe. Checked in base class call.
|
||||
if ( pItem )
|
||||
{
|
||||
int iSkin = pItem->GetSkin( GetTeamNumber() );
|
||||
if ( iSkin > -1 )
|
||||
{
|
||||
return iSkin;
|
||||
}
|
||||
}
|
||||
|
||||
return ( GetTeamNumber() == (LAST_SHARED_TEAM+1) ) ? 0 : 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches the item to the player.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconWearable::Equip( CBasePlayer* pOwner )
|
||||
{
|
||||
if ( !CanEquip( pOwner ) )
|
||||
{
|
||||
RemoveFrom( pOwner );
|
||||
return;
|
||||
}
|
||||
|
||||
SetTouch( NULL );
|
||||
SetAbsVelocity( vec3_origin );
|
||||
|
||||
CBaseEntity *pFollowEntity = pOwner;
|
||||
|
||||
if ( IsViewModelWearable() )
|
||||
{
|
||||
pFollowEntity = pOwner->GetViewModel();
|
||||
}
|
||||
|
||||
FollowEntity( pFollowEntity, true );
|
||||
|
||||
SetOwnerEntity( pOwner );
|
||||
|
||||
ReapplyProvision();
|
||||
|
||||
ChangeTeam( pOwner->GetTeamNumber() );
|
||||
m_nSkin = GetSkin();
|
||||
|
||||
#ifdef GAME_DLL
|
||||
UpdateModelToClass();
|
||||
UpdateBodygroups( pOwner, true );
|
||||
PlayAnimForPlaybackEvent( WAP_ON_SPAWN );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Remove item from the player.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconWearable::UnEquip( CBasePlayer* pOwner )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
SetParticleSystemsVisible( PARTICLE_SYSTEM_STATE_NOT_VISIBLE );
|
||||
#endif
|
||||
|
||||
#ifdef GAME_DLL
|
||||
UpdateBodygroups( pOwner, false );
|
||||
#endif
|
||||
|
||||
StopFollowingEntity();
|
||||
SetOwnerEntity( NULL );
|
||||
|
||||
ReapplyProvision();
|
||||
}
|
||||
/*
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hides or shows masked bodygroups associated with this item.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CEconWearable::UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState )
|
||||
{
|
||||
if ( !pOwner )
|
||||
return false;
|
||||
|
||||
CAttributeContainer *pCont = GetAttributeContainer();
|
||||
if ( !pCont )
|
||||
return false;
|
||||
|
||||
CEconItemView *pItem = pCont->GetItem();
|
||||
if ( !pItem )
|
||||
return false;
|
||||
|
||||
int iTeam = pOwner->GetTeamNumber();
|
||||
int iNumBodyGroups = pItem->GetNumModifiedBodyGroups( iTeam );
|
||||
for ( int i=0; i<iNumBodyGroups; ++i )
|
||||
{
|
||||
int iBody = 0;
|
||||
const char *pszBodyGroup = pItem->GetModifiedBodyGroup( iTeam, i, iBody );
|
||||
int iBodyGroup = pOwner->FindBodygroupByName( pszBodyGroup );
|
||||
|
||||
if ( iBodyGroup == -1 )
|
||||
continue;
|
||||
|
||||
pOwner->SetBodygroup( iBodyGroup, iState );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconWearable::OnWearerDeath( void )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
UpdateParticleSystems();
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CEconWearable::GetDropType()
|
||||
{
|
||||
CAttributeContainer *pCont = GetAttributeContainer();
|
||||
if ( !pCont )
|
||||
return 0;
|
||||
|
||||
CEconItemView *pItem = pCont->GetItem();
|
||||
if ( pItem )
|
||||
return pItem->GetDropType();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Ensures that a player's correct body groups are enabled on client respawn.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconWearable::UpdateWearableBodyGroups( CBasePlayer* pPlayer )
|
||||
{
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
for ( int i=0; i<pPlayer->GetNumWearables(); ++i )
|
||||
{
|
||||
CEconWearable* pItem = pPlayer->GetWearable(i);
|
||||
if ( !pItem )
|
||||
continue;
|
||||
|
||||
// Dynamic models which are not yet rendering do not modify bodygroups
|
||||
if ( pItem->IsDynamicModelLoading() )
|
||||
continue;
|
||||
|
||||
// On the client, ignore items that aren't valid.
|
||||
#ifdef TF_CLIENT_DLL
|
||||
if ( pItem->EntityDeemedInvalid() )
|
||||
continue;
|
||||
#endif
|
||||
|
||||
int nVisibleState = 1;
|
||||
#ifdef TF_CLIENT_DLL
|
||||
if ( pItem->ShouldHideForVisionFilterFlags() )
|
||||
{
|
||||
// Items that shouldn't draw (pyro-vision filtered) shouldn't change any body group states
|
||||
// unless they have no model (hatless hats)
|
||||
nVisibleState = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
pItem->UpdateBodygroups( pPlayer, nVisibleState );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CTFWearableItem::CTFWearableItem()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SERVER ONLY CODE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined( GAME_DLL )
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CLIENT ONLY CODE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Mirror should draw logic.
|
||||
//-----------------------------------------------------------------------------
|
||||
ShadowType_t CEconWearable::ShadowCastType()
|
||||
{
|
||||
if ( ShouldDraw() )
|
||||
{
|
||||
return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
|
||||
}
|
||||
|
||||
return SHADOWS_NONE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CEconWearable::ShouldDraw( void )
|
||||
{
|
||||
CBasePlayer *pPlayerOwner = ToBasePlayer( GetOwnerEntity() );
|
||||
if ( !pPlayerOwner )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bUseViewModel = !pPlayerOwner->ShouldDrawThisPlayer();
|
||||
|
||||
// Don't show view models if we're drawing the real player, and don't show non view models if using view models.
|
||||
if ( bUseViewModel )
|
||||
{
|
||||
// VM mode.
|
||||
if ( !IsViewModelWearable() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-viewmodel mode.
|
||||
if ( IsViewModelWearable() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !ShouldDrawWhenPlayerIsDead() && !pPlayerOwner->IsAlive() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( pPlayerOwner->GetTeamNumber() == TEAM_SPECTATOR )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return BaseClass::ShouldDraw();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconWearable::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
}
|
||||
|
||||
// Update our visibility in case our parents' has changed.
|
||||
UpdateVisibility();
|
||||
UpdateParticleSystems();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEconWearable::ClientThink( void )
|
||||
{
|
||||
BaseClass::ClientThink();
|
||||
|
||||
UpdateParticleSystems();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CEconWearable::ShouldDrawParticleSystems( void )
|
||||
{
|
||||
// Make sure the entity we're attaching to is being drawn
|
||||
CBasePlayer *pPlayerOwner = ToBasePlayer( GetOwnerEntity() );
|
||||
if ( !pPlayerOwner )
|
||||
{
|
||||
Assert ( "CEconWearable has no owner?" ); // Not sure what this means - is is visible or not?
|
||||
return false;
|
||||
}
|
||||
if ( pPlayerOwner->ShouldDrawThisPlayer() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderGroup_t CEconWearable::GetRenderGroup()
|
||||
{
|
||||
if ( IsViewModelWearable() )
|
||||
return RENDER_GROUP_VIEW_MODEL_TRANSLUCENT;
|
||||
|
||||
return BaseClass::GetRenderGroup();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Wearable tint colors
|
||||
//-----------------------------------------------------------------------------
|
||||
class CProxyItemTintColor : public CResultProxy
|
||||
{
|
||||
public:
|
||||
void OnBind( void *pC_BaseEntity )
|
||||
{
|
||||
Assert( m_pResult );
|
||||
Vector vResult = Vector( 0, 0, 0 );
|
||||
|
||||
if ( pC_BaseEntity )
|
||||
{
|
||||
CEconItemView *pScriptItem = NULL;
|
||||
|
||||
IClientRenderable *pRend = (IClientRenderable *)pC_BaseEntity;
|
||||
C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
if ( pEntity )
|
||||
{
|
||||
CEconEntity *pItem = dynamic_cast< CEconEntity* >( pEntity );
|
||||
if ( pItem )
|
||||
{
|
||||
pScriptItem = pItem->GetAttributeContainer()->GetItem();
|
||||
}
|
||||
else if ( pEntity->GetOwnerEntity() )
|
||||
{
|
||||
// Try the owner (for viewmodels, etc).
|
||||
pEntity = pEntity->GetOwnerEntity();
|
||||
pItem = dynamic_cast< CEconEntity* >( pEntity );
|
||||
if ( pItem )
|
||||
{
|
||||
pScriptItem = pItem->GetAttributeContainer()->GetItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Proxy data can be a script created item itself, if we're in a vgui CModelPanel
|
||||
pScriptItem = dynamic_cast< CEconItemView* >( pRend );
|
||||
}
|
||||
|
||||
#ifdef TF_CLIENT_DLL
|
||||
if ( !pScriptItem )
|
||||
{
|
||||
// Might be a throwable
|
||||
CTFWeaponBaseGrenadeProj *pProjectile = dynamic_cast< CTFWeaponBaseGrenadeProj* >( pEntity );
|
||||
if ( pProjectile )
|
||||
{
|
||||
CEconEntity *pItem = dynamic_cast< CEconEntity* >( pProjectile->GetLauncher() );
|
||||
if ( pItem )
|
||||
{
|
||||
pScriptItem = pItem->GetAttributeContainer()->GetItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( pScriptItem && pScriptItem->IsValid() )
|
||||
{
|
||||
const bool bAltColor = pEntity && pEntity->GetTeam() > 0
|
||||
? pEntity->GetTeam()->GetTeamNumber() == TF_TEAM_BLUE
|
||||
: pScriptItem->GetFlags() & kEconItemFlagClient_ForceBlueTeam
|
||||
? true
|
||||
: false;
|
||||
|
||||
int iModifiedRGB = pScriptItem->GetModifiedRGBValue( bAltColor );
|
||||
if ( iModifiedRGB )
|
||||
{
|
||||
// The attrib returns a packed RGB with values between 0 & 255 packed into the bottom 3 bytes.
|
||||
Color clr = Color( ((iModifiedRGB & 0xFF0000) >> 16), ((iModifiedRGB & 0xFF00) >> 8), (iModifiedRGB & 0xFF) );
|
||||
|
||||
vResult.x = clamp( clr.r() * (1.f / 255.0f), 0.f, 1.0f );
|
||||
vResult.y = clamp( clr.g() * (1.f / 255.0f), 0.f, 1.0f );
|
||||
vResult.z = clamp( clr.b() * (1.f / 255.0f), 0.f, 1.0f );
|
||||
}
|
||||
}
|
||||
#endif // TF_CLIENT_DLL
|
||||
}
|
||||
|
||||
m_pResult->SetVecValue( vResult.x, vResult.y, vResult.z );
|
||||
}
|
||||
};
|
||||
EXPOSE_INTERFACE( CProxyItemTintColor, IMaterialProxy, "ItemTintColor" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
|
||||
|
||||
|
||||
//============================================================================================================================
|
||||
extern ConVar r_propsmaxdist;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_EconWearableGib::C_EconWearableGib()
|
||||
{
|
||||
m_fDeathTime = -1;
|
||||
m_iHealth = 0;
|
||||
m_bParented = false;
|
||||
m_bDelayedInit = false;
|
||||
}
|
||||
|
||||
C_EconWearableGib::~C_EconWearableGib()
|
||||
{
|
||||
PhysCleanupFrictionSounds( this );
|
||||
VPhysicsDestroyObject();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_EconWearableGib::Initialize( bool bWillBeParented )
|
||||
{
|
||||
m_bParented = bWillBeParented;
|
||||
return InitializeAsClientEntity( STRING( GetModelName() ), RENDER_GROUP_OPAQUE_ENTITY );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CStudioHdr* C_EconWearableGib::OnNewModel()
|
||||
{
|
||||
CStudioHdr* pCStudioHdr = BaseClass::OnNewModel();
|
||||
if ( m_bDelayedInit && !IsDynamicModelLoading() )
|
||||
{
|
||||
FinishModelInitialization();
|
||||
}
|
||||
return pCStudioHdr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EconWearableGib::SpawnClientEntity( void )
|
||||
{
|
||||
if ( !IsDynamicModelLoading() )
|
||||
{
|
||||
FinishModelInitialization();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bDelayedInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_EconWearableGib::FinishModelInitialization( void )
|
||||
{
|
||||
UpdateThinkState();
|
||||
|
||||
const model_t *mod = GetModel();
|
||||
if ( mod )
|
||||
{
|
||||
Vector mins, maxs;
|
||||
modelinfo->GetModelBounds( mod, mins, maxs );
|
||||
SetCollisionBounds( mins, maxs );
|
||||
}
|
||||
|
||||
if ( !m_bParented )
|
||||
{
|
||||
// Create the object in the physics system
|
||||
solid_t tmpSolid;
|
||||
if ( !PhysModelParseSolid( tmpSolid, this, GetModelIndex() ) )
|
||||
{
|
||||
DevMsg("C_EconWearableGib::FinishModelInitialization: PhysModelParseSolid failed for entity %i.\n", GetModelIndex() );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPhysicsObject = VPhysicsInitNormal( SOLID_VPHYSICS, 0, false, &tmpSolid );
|
||||
|
||||
if ( !m_pPhysicsObject )
|
||||
{
|
||||
// failed to create a physics object
|
||||
DevMsg(" C_EconWearableGib::FinishModelInitialization: VPhysicsInitNormal() failed for %s.\n", STRING(GetModelName()) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spawn();
|
||||
|
||||
if ( m_fadeMinDist < 0 )
|
||||
{
|
||||
// start fading out at 75% of r_propsmaxdist
|
||||
m_fadeMaxDist = r_propsmaxdist.GetFloat();
|
||||
m_fadeMinDist = r_propsmaxdist.GetFloat() * 0.75f;
|
||||
}
|
||||
|
||||
SetCollisionGroup( COLLISION_GROUP_DEBRIS );
|
||||
|
||||
UpdatePartitionListEntry();
|
||||
|
||||
CollisionProp()->UpdatePartition();
|
||||
|
||||
SetBlocksLOS( false ); // this should be a small object
|
||||
|
||||
// Set up shadows; do it here so that objects can change shadowcasting state
|
||||
CreateShadow();
|
||||
|
||||
UpdateVisibility();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EconWearableGib::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
m_takedamage = DAMAGE_EVENTS_ONLY;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_EconWearableGib::ValidateEntityAttachedToPlayer( bool &bShouldRetry )
|
||||
{
|
||||
bShouldRetry = false;
|
||||
|
||||
// Always valid as long as we're not parented to anything
|
||||
return (GetMoveParent() == NULL);
|
||||
}
|
||||
|
||||
#define WEARABLE_FADEOUT_TIME 1.0f
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Figure out if we need to think or not
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_EconWearableGib::UpdateThinkState( void )
|
||||
{
|
||||
if ( m_fDeathTime > 0 )
|
||||
{
|
||||
// If we're in the active fadeout portion, think rapidly. Otherwise, wait for that time.
|
||||
if ( (m_fDeathTime - gpGlobals->curtime) > WEARABLE_FADEOUT_TIME )
|
||||
{
|
||||
SetNextClientThink( m_fDeathTime - WEARABLE_FADEOUT_TIME );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SetNextClientThink( CLIENT_THINK_NEVER );
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EconWearableGib::ClientThink( void )
|
||||
{
|
||||
if ( (m_fDeathTime > 0) && ((m_fDeathTime - gpGlobals->curtime) <= WEARABLE_FADEOUT_TIME) )
|
||||
{
|
||||
if ( m_fDeathTime <= gpGlobals->curtime )
|
||||
{
|
||||
Release(); // Die
|
||||
return;
|
||||
}
|
||||
|
||||
// fade out
|
||||
float alpha = (m_fDeathTime - gpGlobals->curtime) / WEARABLE_FADEOUT_TIME;
|
||||
SetRenderMode( kRenderTransTexture );
|
||||
SetRenderColorA( alpha * 256 );
|
||||
}
|
||||
|
||||
UpdateThinkState();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EconWearableGib::StartFadeOut( float fDelay )
|
||||
{
|
||||
m_fDeathTime = gpGlobals->curtime + fDelay + WEARABLE_FADEOUT_TIME;
|
||||
UpdateThinkState();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EconWearableGib::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName )
|
||||
{
|
||||
IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
|
||||
|
||||
if( !pPhysicsObject )
|
||||
return;
|
||||
|
||||
Vector dir = pTrace->endpos - pTrace->startpos;
|
||||
int iDamage = 0;
|
||||
|
||||
if ( iDamageType & DMG_BLAST )
|
||||
{
|
||||
iDamage = VectorLength( dir );
|
||||
dir *= 500; // adjust impact strenght
|
||||
|
||||
// apply force at object mass center
|
||||
pPhysicsObject->ApplyForceCenter( dir );
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector hitpos;
|
||||
|
||||
VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos );
|
||||
VectorNormalize( dir );
|
||||
|
||||
// guess avg damage
|
||||
if ( iDamageType == DMG_BULLET )
|
||||
{
|
||||
iDamage = 30;
|
||||
}
|
||||
else
|
||||
{
|
||||
iDamage = 50;
|
||||
}
|
||||
|
||||
dir *= 4000; // adjust impact strenght
|
||||
|
||||
// apply force where we hit it
|
||||
pPhysicsObject->ApplyForceOffset( dir, hitpos );
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifdef _DEBUG
|
||||
#include "econ_item_system.h"
|
||||
|
||||
static CUtlVector< const char * > s_possibleModels;
|
||||
static CUtlVector< const GameItemDefinition_t * > s_possibleDefinitions;
|
||||
void Dbg_TestDynamicWearableGibs( void )
|
||||
{
|
||||
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
if ( !pLocalPlayer )
|
||||
return;
|
||||
|
||||
C_EconWearableGib *pEntity = new C_EconWearableGib();
|
||||
if ( !pEntity )
|
||||
return;
|
||||
|
||||
Vector forward;
|
||||
pLocalPlayer->EyeVectors( &forward );
|
||||
trace_t tr;
|
||||
UTIL_TraceLine( pLocalPlayer->EyePosition(), pLocalPlayer->EyePosition() + (forward * 256), MASK_NPCSOLID, pLocalPlayer, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
Vector position = tr.endpos;
|
||||
|
||||
if ( s_possibleModels.Count() == 0 )
|
||||
{
|
||||
FOR_EACH_MAP( ItemSystem()->GetItemSchema()->GetItemDefinitionMap(), nDefn )
|
||||
{
|
||||
const GameItemDefinition_t *pDefn = dynamic_cast<GameItemDefinition_t *>( ItemSystem()->GetItemSchema()->GetItemDefinitionMap()[nDefn] );
|
||||
if ( !pDefn )
|
||||
continue;
|
||||
|
||||
const char *pszModel = pDefn->GetPlayerDisplayModel( 0 );
|
||||
if ( pszModel && pszModel[0] && pszModel[0] != '?' && pDefn->BLoadOnDemand() && pDefn->GetDropType() == ITEM_DROP_TYPE_DROP )
|
||||
{
|
||||
s_possibleModels.AddToTail( pszModel );
|
||||
s_possibleDefinitions.AddToTail( pDefn );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert( s_possibleModels.Count() );
|
||||
|
||||
int spawnIndex = random->RandomInt( 0, s_possibleModels.Count() - 1 );
|
||||
const char *pszModelName = s_possibleModels[ spawnIndex ];
|
||||
const GameItemDefinition_t *pDefn = s_possibleDefinitions[ spawnIndex ];
|
||||
Msg( "Spawning: %s\n", pszModelName );
|
||||
pEntity->SetModelName( AllocPooledString( pszModelName ) );
|
||||
pEntity->SetAbsOrigin( position );
|
||||
pEntity->SetAbsAngles( vec3_angle );
|
||||
pEntity->SetOwnerEntity( pLocalPlayer );
|
||||
pEntity->ChangeTeam( pLocalPlayer->GetTeamNumber() ); // our gibs will match our team; this will probably not be used for anything besides team coloring
|
||||
// Copy the script created item data over
|
||||
pEntity->GetAttributeContainer()->GetItem()->Init( pDefn->GetDefinitionIndex(), pDefn->GetQuality(), pDefn->GetMinLevel(), true );
|
||||
|
||||
if ( !pEntity->Initialize( false ) )
|
||||
{
|
||||
pEntity->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
pEntity->StartFadeOut( 15.0f );
|
||||
return;
|
||||
|
||||
IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
|
||||
if ( !pPhysicsObject )
|
||||
{
|
||||
pEntity->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
// randomize velocity by 5%
|
||||
Vector rndVel = Vector(0,0,100);
|
||||
pPhysicsObject->AddVelocity( &rndVel, &vec3_origin );
|
||||
}
|
||||
static ConCommand dbg_testdynamicwearablegib( "dbg_testdynamicwearablegib", Dbg_TestDynamicWearableGibs, "", FCVAR_CHEAT );
|
||||
#endif // _DEBUG
|
||||
#endif
|
||||
|
||||
#endif // client only
|
||||
@@ -0,0 +1,138 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ECON_WEARABLE_H
|
||||
#define ECON_WEARABLE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "econ_entity.h"
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_WEARABLES_SENT_FROM_SERVER =
|
||||
#ifdef LOADOUT_MAX_WEARABLES_COUNT // we actually do want to just check for macro definition here -- undefined means "fall back to whatever default"
|
||||
LOADOUT_MAX_WEARABLES_COUNT
|
||||
#else
|
||||
8 // hard-coded constant to match old behavior
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CEconWearable C_EconWearable
|
||||
#define CTFWearableItem C_TFWearableItem
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
ITEM_DROP_TYPE_NULL,
|
||||
ITEM_DROP_TYPE_NONE,
|
||||
ITEM_DROP_TYPE_DROP,
|
||||
ITEM_DROP_TYPE_BREAK,
|
||||
};
|
||||
|
||||
class CEconWearable : public CEconEntity
|
||||
{
|
||||
DECLARE_CLASS( CEconWearable, CEconEntity );
|
||||
public:
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CEconWearable();
|
||||
|
||||
virtual bool IsWearable( void ) const { return true; }
|
||||
|
||||
// Shared
|
||||
virtual void Spawn( void );
|
||||
virtual void GiveTo( CBaseEntity *pOther );
|
||||
virtual void RemoveFrom( CBaseEntity *pOther );
|
||||
virtual bool CanEquip( CBaseEntity *pOther ) { return true; }
|
||||
virtual void Equip( CBasePlayer *pOwner );
|
||||
virtual void UnEquip( CBasePlayer* pOwner );
|
||||
virtual void OnWearerDeath( void );
|
||||
virtual int GetDropType( void );
|
||||
// virtual bool UpdateBodygroups( CBasePlayer* pOwner, int iState );
|
||||
|
||||
void SetAlwaysAllow( bool bVal ) { m_bAlwaysAllow = bVal; }
|
||||
bool AlwaysAllow( void ) { return m_bAlwaysAllow; }
|
||||
|
||||
virtual bool IsViewModelWearable( void ) { return false; }
|
||||
|
||||
// Server
|
||||
#if defined( GAME_DLL )
|
||||
#endif
|
||||
|
||||
// Client
|
||||
#if defined( CLIENT_DLL )
|
||||
virtual ShadowType_t ShadowCastType() OVERRIDE;
|
||||
virtual bool ShouldDraw();
|
||||
virtual bool ShouldDrawWhenPlayerIsDead() { return true; }
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void ClientThink( void );
|
||||
virtual bool ShouldDrawParticleSystems( void );
|
||||
virtual RenderGroup_t GetRenderGroup();
|
||||
#endif
|
||||
|
||||
virtual int GetSkin( void );
|
||||
|
||||
// Static
|
||||
static void UpdateWearableBodyGroups( CBasePlayer *pPlayer );
|
||||
|
||||
protected:
|
||||
virtual void InternalSetPlayerDisplayModel( void );
|
||||
|
||||
private:
|
||||
bool m_bAlwaysAllow; // Wearable will not be removed by ManageRegularWeapons. Only use this for wearables managed by other items!
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: For backwards compatibility with older demos
|
||||
//-----------------------------------------------------------------------------
|
||||
class CTFWearableItem : public CEconWearable
|
||||
{
|
||||
DECLARE_CLASS( CTFWearableItem, CEconWearable );
|
||||
public:
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CTFWearableItem();
|
||||
};
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
// Clientside wearable physics props. Used to have wearables fall off dying players.
|
||||
class C_EconWearableGib : public CEconEntity
|
||||
{
|
||||
DECLARE_CLASS( C_EconWearableGib, CEconEntity );
|
||||
public:
|
||||
C_EconWearableGib();
|
||||
~C_EconWearableGib();
|
||||
|
||||
bool Initialize( bool bWillBeParented );
|
||||
bool FinishModelInitialization( void );
|
||||
|
||||
virtual CStudioHdr *OnNewModel( void );
|
||||
|
||||
virtual bool ValidateEntityAttachedToPlayer( bool &bShouldRetry );
|
||||
|
||||
virtual void SpawnClientEntity();
|
||||
virtual void Spawn();
|
||||
virtual void ClientThink( void );
|
||||
void StartFadeOut( float fDelay );
|
||||
virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName );
|
||||
virtual CollideType_t GetCollideType( void ) { return ENTITY_SHOULD_RESPOND; }
|
||||
|
||||
bool UpdateThinkState( void );
|
||||
|
||||
private:
|
||||
bool m_bParented;
|
||||
bool m_bDelayedInit;
|
||||
float m_fDeathTime; // Point at which this object self destructs.
|
||||
// The default of -1 indicates the object shouldn't destruct.
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // ECON_WEARABLE_H
|
||||
@@ -0,0 +1,49 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
#ifndef GAME_ITEM_SCHEMA_H
|
||||
#define GAME_ITEM_SCHEMA_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
|
||||
// TF
|
||||
class CTFItemSchema;
|
||||
class CTFItemDefinition;
|
||||
class CTFItemSystem;
|
||||
|
||||
typedef CTFItemSchema GameItemSchema_t;
|
||||
typedef CTFItemDefinition GameItemDefinition_t;
|
||||
typedef CTFItemSystem GameItemSystem_t;
|
||||
|
||||
#include "tf_item_schema.h"
|
||||
#elif defined( DOTA_CLIENT_DLL ) || defined( DOTA_DLL ) || defined ( DOTA_GC_DLL )
|
||||
// DOTA
|
||||
class CDOTAItemSchema;
|
||||
class CDOTAItemDefinition;
|
||||
class CDOTAItemSystem;
|
||||
|
||||
typedef CDOTAItemSchema GameItemSchema_t;
|
||||
typedef CDOTAItemDefinition GameItemDefinition_t;
|
||||
typedef CDOTAItemSystem GameItemSystem_t;
|
||||
|
||||
#include "econ/dota_item_schema.h"
|
||||
#else
|
||||
// Fallback Case
|
||||
class CEconItemSchema;
|
||||
class CEconItemDefinition;
|
||||
class CEconItemSystem;
|
||||
|
||||
typedef CEconItemSchema GameItemSchema_t;
|
||||
typedef CEconItemDefinition GameItemDefinition_t;
|
||||
typedef CEconItemSystem GameItemSystem_t;
|
||||
|
||||
#include "econ_item_schema.h"
|
||||
#endif
|
||||
|
||||
extern GameItemSchema_t *GetItemSchema();
|
||||
|
||||
#endif // GAME_ITEM_SYSTEM_H
|
||||
@@ -0,0 +1,46 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef IHASATTRIBUTES_H
|
||||
#define IHASATTRIBUTES_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//#include "attribute_manager.h"
|
||||
|
||||
class CAttributeManager;
|
||||
class CAttributeContainer;
|
||||
class CBaseEntity;
|
||||
class CAttributeList;
|
||||
|
||||
// To allow an entity to have attributes, derive it from IHasAttributes and
|
||||
// contain an CAttributeManager in it. Then:
|
||||
// - Call InitializeAttributes() before your entity's Spawn()
|
||||
// - Call AddAttribute() to add attributes to the entity
|
||||
// - Call all the CAttributeManager hooks at the appropriate times in your entity.
|
||||
// To get networking of the attributes to work on your entity:
|
||||
// - Add this to your entity's send table:
|
||||
// SendPropDataTable( SENDINFO_DT( m_AttributeManager ), &REFERENCE_SEND_TABLE(DT_AttributeManager) ),
|
||||
// - Call this inside your entity's OnDataChanged():
|
||||
// GetAttributeManager()->OnDataChanged( updateType );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Derive from this if your entity wants to contain attributes.
|
||||
//-----------------------------------------------------------------------------
|
||||
class IHasAttributes
|
||||
{
|
||||
public:
|
||||
virtual CAttributeManager *GetAttributeManager( void ) = 0;
|
||||
virtual CAttributeContainer *GetAttributeContainer( void ) = 0;
|
||||
virtual CBaseEntity *GetAttributeOwner( void ) = 0;
|
||||
virtual CAttributeList *GetAttributeList( void ) = 0;
|
||||
|
||||
// Reapply yourself to whoever you should be providing attributes to.
|
||||
virtual void ReapplyProvision( void ) = 0;
|
||||
};
|
||||
|
||||
#endif // IHASATTRIBUTES_H
|
||||
@@ -0,0 +1,24 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef IHASOWNER_H
|
||||
#define IHASOWNER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
class CBaseEntity;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allows an entity to access its owner regardless of entity type
|
||||
//-----------------------------------------------------------------------------
|
||||
class IHasOwner
|
||||
{
|
||||
public:
|
||||
virtual CBaseEntity *GetOwnerViaInterface( void ) = 0;
|
||||
};
|
||||
|
||||
#endif // IHASOWNER_H
|
||||
@@ -0,0 +1,614 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: CItemSelectionCriteria, which serves as a criteria for selection
|
||||
// of a econ item
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#include "cbase.h"
|
||||
#include "item_selection_criteria.h"
|
||||
|
||||
#include "gcsdk/gcsystemmsgs.h"
|
||||
|
||||
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
|
||||
#include "tf_gcmessages.h"
|
||||
#endif
|
||||
|
||||
#include "gcsdk/enumutils.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
// copied from \common\econ_item_view.h
|
||||
#define AE_USE_SCRIPT_VALUE 9999 // Can't be -1, due to unsigned ints used on the backend
|
||||
|
||||
ENUMSTRINGS_START( EItemCriteriaOperator )
|
||||
{ k_EOperator_String_EQ, "string==" },
|
||||
{ k_EOperator_String_Not_EQ, "!string==" },
|
||||
{ k_EOperator_Float_EQ, "float==" },
|
||||
{ k_EOperator_Float_Not_EQ, "!float==" },
|
||||
{ k_EOperator_Float_LT, "float<" },
|
||||
{ k_EOperator_Float_Not_LT, "!float<" },
|
||||
{ k_EOperator_Float_LTE, "float<=" },
|
||||
{ k_EOperator_Float_Not_LTE, "!float<=" },
|
||||
{ k_EOperator_Float_GT, "float>" },
|
||||
{ k_EOperator_Float_Not_GT, "!float>" },
|
||||
{ k_EOperator_Float_GTE, "float>=" },
|
||||
{ k_EOperator_Float_Not_GTE, "!float>=" },
|
||||
{ k_EOperator_Subkey_Contains, "contains" },
|
||||
{ k_EOperator_Subkey_Not_Contains, "!contains" },
|
||||
ENUMSTRINGS_REVERSE( EItemCriteriaOperator, k_EItemCriteriaOperator_Count )
|
||||
|
||||
using namespace GCSDK;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Copy Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CItemSelectionCriteria::CItemSelectionCriteria( const CItemSelectionCriteria &that )
|
||||
{
|
||||
(*this) = that;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Operator=
|
||||
//-----------------------------------------------------------------------------
|
||||
CItemSelectionCriteria &CItemSelectionCriteria::operator=( const CItemSelectionCriteria &rhs )
|
||||
{
|
||||
|
||||
// Leverage the serialization code we already have for the copy
|
||||
CSOItemCriteria msgTemp;
|
||||
rhs.BSerializeToMsg( msgTemp );
|
||||
BDeserializeFromMsg( msgTemp );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CItemSelectionCriteria::~CItemSelectionCriteria( void )
|
||||
{
|
||||
m_vecConditions.PurgeAndDeleteElements();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Look through our conditions and find the first of the specified type,
|
||||
// and return the value it's looking for.
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CItemSelectionCriteria::GetValueForFirstConditionOfType( EItemCriteriaOperator eType ) const
|
||||
{
|
||||
// Only supporting this for string conditions right now
|
||||
Assert( eType == k_EOperator_String_EQ || eType == k_EOperator_String_Not_EQ );
|
||||
|
||||
FOR_EACH_VEC( m_vecConditions, i )
|
||||
{
|
||||
if ( m_vecConditions[i]->GetEOp() == eType )
|
||||
return m_vecConditions[i]->GetValue();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Look through our conditions and find the first of the specified type,
|
||||
// and return the value it's looking for.
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CItemSelectionCriteria::GetFieldForFirstConditionOfType( EItemCriteriaOperator eType ) const
|
||||
{
|
||||
FOR_EACH_VEC( m_vecConditions, i )
|
||||
{
|
||||
if ( m_vecConditions[i]->GetEOp() == eType )
|
||||
return m_vecConditions[i]->GetField();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initialize from a KV structure
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::BInitFromKV( KeyValues *pKVCriteria )
|
||||
{
|
||||
// Read in the base fields
|
||||
if ( pKVCriteria->FindKey( "level" ) )
|
||||
{
|
||||
SetItemLevel( pKVCriteria->GetInt( "level" ) );
|
||||
}
|
||||
|
||||
if ( pKVCriteria->FindKey( "quality" ) )
|
||||
{
|
||||
uint8 nQuality;
|
||||
if ( !GetItemSchema()->BGetItemQualityFromName( pKVCriteria->GetString( "quality" ), &nQuality ) )
|
||||
return false;
|
||||
|
||||
SetQuality( nQuality );
|
||||
}
|
||||
|
||||
if ( pKVCriteria->FindKey( "inventoryPos" ) )
|
||||
{
|
||||
SetInitialInventory( pKVCriteria->GetInt( "inventoryPos" ) );
|
||||
}
|
||||
|
||||
if ( pKVCriteria->FindKey( "quantity" ) )
|
||||
{
|
||||
SetInitialQuantity( pKVCriteria->GetInt( "quantity" ) );
|
||||
}
|
||||
|
||||
if ( pKVCriteria->FindKey( "ignore_enabled" ) )
|
||||
{
|
||||
SetIgnoreEnabledFlag( pKVCriteria->GetBool( "ignore_enabled" ) );
|
||||
}
|
||||
|
||||
if ( pKVCriteria->FindKey( "tags" ) )
|
||||
{
|
||||
SetTags( pKVCriteria->GetString( "tags" ) );
|
||||
}
|
||||
|
||||
KeyValues *pKVConditions = pKVCriteria->FindKey( "conditions", true );
|
||||
|
||||
FOR_EACH_TRUE_SUBKEY( pKVConditions, pKVElement )
|
||||
{
|
||||
// Check for required fields
|
||||
if ( !pKVElement->FindKey( "field" ) ||
|
||||
!pKVElement->FindKey( "operator" ) ||
|
||||
!pKVElement->FindKey( "value" ) )
|
||||
return false;
|
||||
|
||||
const char *pszField = pKVElement->GetString( "field" );
|
||||
bool bRequired = pKVElement->GetBool( "required" );
|
||||
const char *pszValue = pKVElement->GetString( "value" );
|
||||
|
||||
// Get the operator
|
||||
const char *pszOperator = pKVElement->GetString( "operator" );
|
||||
EItemCriteriaOperator eOp = EItemCriteriaOperatorFromName( pszOperator );
|
||||
if ( k_EItemCriteriaOperator_Count == eOp )
|
||||
return false;
|
||||
|
||||
BAddCondition( pszField, eOp, pszValue, bRequired );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CItemSelectionCriteria::SetTags( const char *pszTags )
|
||||
{
|
||||
m_vecTags.Purge();
|
||||
|
||||
m_strTags = pszTags;
|
||||
CSplitString splitString( pszTags, " " );
|
||||
for ( int i=0; i<splitString.Count(); ++i )
|
||||
{
|
||||
econ_tag_handle_t tagHandle = GetItemSchema()->GetHandleForTag( splitString[i] );
|
||||
if ( !m_vecTags.HasElement( tagHandle ) )
|
||||
{
|
||||
m_vecTags.AddToTail( tagHandle );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::BAddCondition( CItemSelectionCriteria::ICondition *pCondition )
|
||||
{
|
||||
CPlainAutoPtr<ICondition> pConditionPtr( pCondition );
|
||||
|
||||
// Check for condition limit
|
||||
if ( UCHAR_MAX == GetConditionsCount() )
|
||||
{
|
||||
AssertMsg( false, "Too many conditions on a a CItemSelectionCriteria. Max: 255" );
|
||||
return false;
|
||||
}
|
||||
|
||||
m_vecConditions.AddToTail( pConditionPtr.Detach() );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Adds a condition to the selection criteria
|
||||
// Input: pszField - Field to evaluate on
|
||||
// eOp - Operator to apply to the value of the field
|
||||
// flValue - The value to compare.
|
||||
// bRequired - When true, causes BEvauluate to fail if pszField doesn't
|
||||
// exist in the KV being checked.
|
||||
// Output: True if the condition was added, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::BAddCondition( const char *pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired )
|
||||
{
|
||||
// Enforce maximum string lengths
|
||||
if ( Q_strlen( pszField ) >= k_cchCreateItemLen )
|
||||
return false;
|
||||
|
||||
// Create the appropriate condition for the operator
|
||||
switch ( eOp )
|
||||
{
|
||||
case k_EOperator_Float_EQ:
|
||||
case k_EOperator_Float_Not_EQ:
|
||||
case k_EOperator_Float_LT:
|
||||
case k_EOperator_Float_Not_LT:
|
||||
case k_EOperator_Float_LTE:
|
||||
case k_EOperator_Float_Not_LTE:
|
||||
case k_EOperator_Float_GT:
|
||||
case k_EOperator_Float_Not_GT:
|
||||
case k_EOperator_Float_GTE:
|
||||
case k_EOperator_Float_Not_GTE:
|
||||
return BAddCondition( new CFloatCondition( pszField, eOp, flValue, bRequired ) );
|
||||
|
||||
default:
|
||||
AssertMsg1( false, "Bad operator (%d) passed to BAddCondition. Float based operator required for this overload.", eOp );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Adds a condition to the selection criteria
|
||||
// Input: pszField - Field to evaluate on
|
||||
// eOp - Operator to apply to the value of the field
|
||||
// pszValue - The value to compare.
|
||||
// bRequired - When true, causes BEvauluate to fail if pszField doesn't
|
||||
// exist in the KV being checked.
|
||||
// Output: True if the condition was added, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::BAddCondition( const char *pszField, EItemCriteriaOperator eOp, const char * pszValue, bool bRequired )
|
||||
{
|
||||
// Enforce maximum string lengths
|
||||
if ( Q_strlen( pszField ) >= k_cchCreateItemLen || Q_strlen( pszValue ) >= k_cchCreateItemLen )
|
||||
return false;
|
||||
|
||||
// Create the appropriate condition for the operator
|
||||
switch ( eOp )
|
||||
{
|
||||
case k_EOperator_String_EQ:
|
||||
case k_EOperator_String_Not_EQ:
|
||||
return BAddCondition( new CStringCondition( pszField, eOp, pszValue, bRequired ) );
|
||||
return true;
|
||||
|
||||
case k_EOperator_Subkey_Contains:
|
||||
case k_EOperator_Subkey_Not_Contains:
|
||||
return BAddCondition( new CSetCondition( pszField, eOp, pszValue, bRequired ) );
|
||||
return true;
|
||||
|
||||
default:
|
||||
// Try the float operators
|
||||
return BAddCondition( pszField, eOp, Q_atof( pszValue ), bRequired );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Checks if a given item matches the item selection criteria
|
||||
// Input: itemDef - The item definition to evaluate against
|
||||
// Output: True is the item passes the filter, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::BEvaluate( const CEconItemDefinition* pItemDef ) const
|
||||
{
|
||||
// Disabled items never match
|
||||
if ( !m_bIgnoreEnabledFlag && !pItemDef->BEnabled() )
|
||||
return false;
|
||||
|
||||
// Filter against level
|
||||
if ( BItemLevelSet() && (GetItemLevel() != AE_USE_SCRIPT_VALUE) &&
|
||||
( GetItemLevel() < pItemDef->GetMinLevel() || GetItemLevel() > pItemDef->GetMaxLevel() ) )
|
||||
return false;
|
||||
|
||||
// Filter against quality
|
||||
if ( BQualitySet() && (GetQuality() != AE_USE_SCRIPT_VALUE) )
|
||||
{
|
||||
if ( GetQuality() != pItemDef->GetQuality() )
|
||||
{
|
||||
// Filter out item defs that have a non-any quality if we have a non-matching & non-any quality criteria
|
||||
if ( k_unItemQuality_Any != GetQuality() && k_unItemQuality_Any != pItemDef->GetQuality() )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter against the additional conditions
|
||||
FOR_EACH_VEC( m_vecConditions, i )
|
||||
{
|
||||
if ( !m_vecConditions[i]->BItemDefinitionPassesCriteria( pItemDef ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we have "any" tags
|
||||
if ( m_vecTags.Count() > 0 )
|
||||
{
|
||||
bool bHasTag = false;
|
||||
FOR_EACH_VEC( m_vecTags, i )
|
||||
{
|
||||
if ( pItemDef->HasEconTag( m_vecTags[i] ) )
|
||||
{
|
||||
bHasTag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !bHasTag )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Determines if the item matches this condition of the criteria
|
||||
// Input: pKVItem - Pointer to the raw KeyValues definition of the item
|
||||
// Output: True is the item matches, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::CCondition::BEvaluate( KeyValues *pKVItem ) const
|
||||
{
|
||||
KeyValues *pKVField = pKVItem->FindKey( m_sField.String() );
|
||||
|
||||
// Treat an empty string as a missing field as well.
|
||||
bool bIsEmptyString = false;
|
||||
if ( m_EOp == k_EOperator_String_EQ || m_EOp == k_EOperator_String_Not_EQ )
|
||||
{
|
||||
const char *pszItemVal = pKVField ? pKVField->GetString() : NULL;
|
||||
bIsEmptyString = ( pszItemVal == NULL || pszItemVal[0] == '\0' );
|
||||
}
|
||||
|
||||
// Deal with missing fields
|
||||
if ( NULL == pKVField || bIsEmptyString )
|
||||
{
|
||||
if ( m_bRequired )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
// Run the operator specific check
|
||||
bool bRet = BInternalEvaluate( pKVItem );
|
||||
|
||||
// If this is a "not" operator, reverse the result
|
||||
if ( m_EOp & k_EOperator_Not )
|
||||
return !bRet;
|
||||
else
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Runs the operator specific check for this condition
|
||||
// Input: pKVItem - Pointer to the raw KeyValues definition of the item
|
||||
// Output: True is the item matches, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::CStringCondition::BInternalEvaluate( KeyValues *pKVItem ) const
|
||||
{
|
||||
Assert( k_EOperator_String_EQ == m_EOp || k_EOperator_String_Not_EQ == m_EOp );
|
||||
if( !( k_EOperator_String_EQ == m_EOp || k_EOperator_String_Not_EQ == m_EOp ) )
|
||||
return false;
|
||||
|
||||
const char *pszItemVal = pKVItem->GetString( m_sField.String() );
|
||||
return ( 0 == Q_stricmp( m_sValue.String(), pszItemVal ) );
|
||||
}
|
||||
|
||||
bool CItemSelectionCriteria::CStringCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
|
||||
{
|
||||
CCondition::BSerializeToMsg( msg );
|
||||
msg.set_string_value( m_sValue.Get() );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Runs the operator specific check for this condition
|
||||
// Input: pKVItem - Pointer to the raw KeyValues definition of the item
|
||||
// Output: True is the item matches, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::CSetCondition::BInternalEvaluate( KeyValues *pKVItem ) const
|
||||
{
|
||||
Assert( k_EOperator_Subkey_Contains == m_EOp || k_EOperator_Subkey_Not_Contains == m_EOp );
|
||||
if( !( k_EOperator_Subkey_Contains == m_EOp || k_EOperator_Subkey_Not_Contains == m_EOp ) )
|
||||
return false;
|
||||
|
||||
return ( NULL != pKVItem->FindKey( m_sField.String() )->FindKey( m_sValue.String() ) );
|
||||
}
|
||||
|
||||
bool CItemSelectionCriteria::CSetCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
|
||||
{
|
||||
CCondition::BSerializeToMsg( msg );
|
||||
msg.set_string_value( m_sValue.Get() );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Runs the operator specific check for this condition
|
||||
// Input: pKVItem - Pointer to the raw KeyValues definition of the item
|
||||
// Output: True is the item matches, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::CFloatCondition::BInternalEvaluate( KeyValues *pKVItem ) const
|
||||
{
|
||||
float itemValue = pKVItem->GetFloat( m_sField.String() );
|
||||
|
||||
switch ( m_EOp )
|
||||
{
|
||||
case k_EOperator_Float_EQ:
|
||||
case k_EOperator_Float_Not_EQ:
|
||||
return ( itemValue == m_flValue );
|
||||
|
||||
case k_EOperator_Float_LT:
|
||||
case k_EOperator_Float_Not_LT:
|
||||
return ( itemValue < m_flValue );
|
||||
|
||||
case k_EOperator_Float_LTE:
|
||||
case k_EOperator_Float_Not_LTE:
|
||||
return ( itemValue <= m_flValue );
|
||||
|
||||
case k_EOperator_Float_GT:
|
||||
case k_EOperator_Float_Not_GT:
|
||||
return ( itemValue > m_flValue );
|
||||
|
||||
case k_EOperator_Float_GTE:
|
||||
case k_EOperator_Float_Not_GTE:
|
||||
return ( itemValue >= m_flValue );
|
||||
|
||||
default:
|
||||
AssertMsg1( false, "Unknown operator: %d", m_EOp );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CItemSelectionCriteria::CFloatCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
|
||||
{
|
||||
CCondition::BSerializeToMsg( msg );
|
||||
msg.set_float_value( m_flValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Serialize the item selection criteria to the given message
|
||||
// Input: msg - The message to serialize to.
|
||||
// Output: True if the operation was successful, false otherwise.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::BSerializeToMsg( CSOItemCriteria & msg ) const
|
||||
{
|
||||
msg.set_item_level( m_unItemLevel );
|
||||
msg.set_item_quality( m_nItemQuality );
|
||||
msg.set_item_level_set( m_bItemLevelSet );
|
||||
msg.set_item_quality_set( m_bQualitySet );
|
||||
msg.set_initial_inventory( m_unInitialInventory );
|
||||
msg.set_initial_quantity( m_unInitialQuantity );
|
||||
msg.set_ignore_enabled_flag( m_bIgnoreEnabledFlag );
|
||||
msg.set_tags( m_strTags );
|
||||
|
||||
FOR_EACH_VEC( m_vecConditions, i )
|
||||
{
|
||||
CSOItemCriteriaCondition *pConditionMsg = msg.add_conditions();
|
||||
m_vecConditions[i]->BSerializeToMsg( *pConditionMsg );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Deserializes the item selection criteria from the given message
|
||||
// Input: msg - The message to deserialize from.
|
||||
// Output: True if the operation was successful, false otherwise.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::BDeserializeFromMsg( const CSOItemCriteria & msg )
|
||||
{
|
||||
m_unItemLevel = msg.item_level();
|
||||
m_nItemQuality = msg.item_quality();
|
||||
m_bItemLevelSet = msg.item_level_set();
|
||||
m_bQualitySet = msg.item_quality_set();
|
||||
m_unInitialInventory = msg.initial_inventory();
|
||||
m_unInitialQuantity = msg.initial_quantity();
|
||||
m_bIgnoreEnabledFlag = msg.ignore_enabled_flag();
|
||||
|
||||
SetTags( msg.tags().c_str() );
|
||||
|
||||
uint32 unCount = msg.conditions_size();
|
||||
m_vecConditions.EnsureCapacity( unCount );
|
||||
|
||||
for ( uint32 i = 0; i < unCount; i++ )
|
||||
{
|
||||
const CSOItemCriteriaCondition & cond = msg.conditions( i );
|
||||
EItemCriteriaOperator eOp = (EItemCriteriaOperator)cond.op();
|
||||
bool bRequired = cond.required();
|
||||
|
||||
// Read the value specific to the condition and add the condition
|
||||
switch ( eOp )
|
||||
{
|
||||
case k_EOperator_Float_EQ:
|
||||
case k_EOperator_Float_Not_EQ:
|
||||
case k_EOperator_Float_LT:
|
||||
case k_EOperator_Float_Not_LT:
|
||||
case k_EOperator_Float_LTE:
|
||||
case k_EOperator_Float_Not_LTE:
|
||||
case k_EOperator_Float_GT:
|
||||
case k_EOperator_Float_Not_GT:
|
||||
case k_EOperator_Float_GTE:
|
||||
case k_EOperator_Float_Not_GTE:
|
||||
{
|
||||
if ( !BAddCondition( cond.field().c_str(), eOp, cond.float_value(), bRequired ) ) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case k_EOperator_String_EQ:
|
||||
case k_EOperator_String_Not_EQ:
|
||||
case k_EOperator_Subkey_Contains:
|
||||
case k_EOperator_Subkey_Not_Contains:
|
||||
{
|
||||
if ( !BAddCondition( cond.field().c_str(), eOp, cond.string_value().c_str(), bRequired ) ) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
AssertMsg1( false, "Unknown operator (%d) read.", eOp );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Serializes a condition to a message.
|
||||
// Input: msg - The message to serialize to.
|
||||
// Output: True if the operation was successful, false otherwise.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::CCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
|
||||
{
|
||||
msg.set_op( m_EOp );
|
||||
msg.set_field( m_sField.String() );
|
||||
msg.set_required( m_bRequired );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CItemSelectionCriteria::CCondition::BItemDefinitionPassesCriteria( const CEconItemDefinition *pItemDef ) const
|
||||
{
|
||||
return BEvaluate( pItemDef->GetRawDefinition() );
|
||||
}
|
||||
|
||||
// Validation
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Run a global validation pass on all of our data structures and memory
|
||||
// allocations.
|
||||
// Input: validator - Our global validator object
|
||||
// pchName - Our name (typically a member var in our container)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CItemSelectionCriteria::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
VALIDATE_SCOPE();
|
||||
ValidateObj( m_vecConditions );
|
||||
FOR_EACH_VEC( m_vecConditions, i )
|
||||
{
|
||||
ValidatePtr( m_vecConditions[i] );
|
||||
}
|
||||
}
|
||||
|
||||
void CItemSelectionCriteria::CCondition::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
ValidateObj( m_sField );
|
||||
}
|
||||
|
||||
void CItemSelectionCriteria::CStringCondition::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
CCondition::Validate( validator, pchName );
|
||||
ValidateObj( m_sValue );
|
||||
}
|
||||
|
||||
void CItemSelectionCriteria::CSetCondition::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
CCondition::Validate( validator, pchName );
|
||||
ValidateObj( m_sValue );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,290 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: CItemSelectionCriteria, which serves as a criteria for selection
|
||||
// of a econ item
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ITEM_SELECTION_CRITERIA_H
|
||||
#define ITEM_SELECTION_CRITERIA_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// Maximum string length in item create APIs
|
||||
const int k_cchCreateItemLen = 64;
|
||||
|
||||
// Operators for BAddNewItemCriteria
|
||||
enum EItemCriteriaOperator
|
||||
{
|
||||
k_EOperator_String_EQ = 0, // Field is string equal to value
|
||||
k_EOperator_Not = 1, // Logical not
|
||||
k_EOperator_String_Not_EQ = 1, // Field is not string equal to value
|
||||
k_EOperator_Float_EQ = 2, // Field as a float is equal to value
|
||||
k_EOperator_Float_Not_EQ = 3, // Field as a float is not equal to value
|
||||
k_EOperator_Float_LT = 4, // Field as a float is less than value
|
||||
k_EOperator_Float_Not_LT = 5, // Field as a float is not less than value
|
||||
k_EOperator_Float_LTE = 6, // Field as a float is less than or equal value
|
||||
k_EOperator_Float_Not_LTE = 7, // Field as a float is not less than or equal value
|
||||
k_EOperator_Float_GT = 8, // Field as a float is greater than value
|
||||
k_EOperator_Float_Not_GT = 9, // Field as a float is not greater than value
|
||||
k_EOperator_Float_GTE = 10, // Field as a float is greater than or equal value
|
||||
k_EOperator_Float_Not_GTE = 11, // Field as a float is not greater than or equal value
|
||||
k_EOperator_Subkey_Contains = 12, // Field contains value as a subkey
|
||||
k_EOperator_Subkey_Not_Contains = 13, // Field does not contain value as a subkey
|
||||
|
||||
// Must be last
|
||||
k_EItemCriteriaOperator_Count = 14,
|
||||
};
|
||||
|
||||
|
||||
EItemCriteriaOperator EItemCriteriaOperatorFromName( const char *pch );
|
||||
const char *PchNameFromEItemCriteriaOperator( int eItemCriteriaOperator );
|
||||
|
||||
class CEconItemSchema;
|
||||
class CEconItemDefinition;
|
||||
class CSOItemCriteria;
|
||||
class CSOItemCriteriaCondition;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CItemSelectionCriteria
|
||||
// A class that contains all the conditions a server needs to specify what
|
||||
// kind of random item they wish to generate.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CItemSelectionCriteria
|
||||
{
|
||||
public:
|
||||
// Constructors and destructor
|
||||
CItemSelectionCriteria() :
|
||||
m_bItemLevelSet( false ),
|
||||
m_unItemLevel( 0 ),
|
||||
m_bQualitySet( false ),
|
||||
m_nItemQuality( k_unItemQuality_Any ),
|
||||
m_unInitialInventory( 0 ),
|
||||
m_bInitialQuantitySet( false ),
|
||||
m_unInitialQuantity( 1 ),
|
||||
m_bIgnoreEnabledFlag( false )
|
||||
{
|
||||
}
|
||||
|
||||
CItemSelectionCriteria( const CItemSelectionCriteria &that );
|
||||
CItemSelectionCriteria &operator=( const CItemSelectionCriteria& rhs );
|
||||
~CItemSelectionCriteria();
|
||||
|
||||
// Accessors and Settors
|
||||
bool BItemLevelSet( void ) const { return m_bItemLevelSet; }
|
||||
uint32 GetItemLevel( void ) const { Assert( m_bItemLevelSet ); return m_unItemLevel; }
|
||||
void SetItemLevel( uint32 unLevel ) { m_unItemLevel = unLevel; m_bItemLevelSet = true; }
|
||||
bool BQualitySet( void ) const { return m_bQualitySet; }
|
||||
int32 GetQuality( void ) const { Assert( m_bQualitySet ); return m_nItemQuality; }
|
||||
void SetQuality( int32 nQuality ) { m_nItemQuality = nQuality; m_bQualitySet = true; }
|
||||
uint32 GetInitialInventory( void ) const { return m_unInitialInventory; }
|
||||
void SetInitialInventory( uint32 unInventory ) { m_unInitialInventory = unInventory; }
|
||||
bool BInitialQuantitySet( void ) const { return m_bQualitySet; }
|
||||
uint32 GetInitialQuantity( void ) const { Assert( m_bQualitySet ); return m_unInitialQuantity; }
|
||||
void SetInitialQuantity( uint32 unQuantity ) { m_unInitialQuantity = unQuantity; m_bInitialQuantitySet = true; }
|
||||
void SetIgnoreEnabledFlag( bool bIgnore ) { m_bIgnoreEnabledFlag = bIgnore; }
|
||||
|
||||
// Tags
|
||||
void SetTags( const char *pszTags );
|
||||
|
||||
|
||||
// Add conditions to the criteria
|
||||
class ICondition
|
||||
{
|
||||
public:
|
||||
virtual ~ICondition() { }
|
||||
|
||||
virtual bool BItemDefinitionPassesCriteria( const CEconItemDefinition *pItemDef ) const = 0;
|
||||
|
||||
virtual EItemCriteriaOperator GetEOp() const { return k_EItemCriteriaOperator_Count; }
|
||||
virtual const char *GetField() const { return ""; }
|
||||
virtual const char *GetValue() const { return ""; }
|
||||
|
||||
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const { Assert( !"BSerializeToMsg() called on for unimplementing ICondition!" ); return false; }
|
||||
};
|
||||
|
||||
bool BAddCondition( const char *pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired );
|
||||
bool BAddCondition( const char *pszField, EItemCriteriaOperator eOp, const char * pszValue, bool bRequired );
|
||||
bool BAddCondition( ICondition *pCondition );
|
||||
int GetConditionsCount() { return m_vecConditions.Count(); }
|
||||
const char *GetValueForFirstConditionOfType( EItemCriteriaOperator eType ) const;
|
||||
const char *GetFieldForFirstConditionOfType( EItemCriteriaOperator eType ) const;
|
||||
|
||||
// Alternate ways of initializing
|
||||
bool BInitFromKV( KeyValues *pKVCriteria );
|
||||
|
||||
// Serializes the criteria to and from messages
|
||||
bool BSerializeToMsg( CSOItemCriteria & msg ) const;
|
||||
bool BDeserializeFromMsg( const CSOItemCriteria & msg );
|
||||
|
||||
// Evaluates an item definition against this criteria. Returns true if
|
||||
// the definition passes the filter
|
||||
bool BEvaluate( const CEconItemDefinition* pItemDef ) const;
|
||||
|
||||
// Validation
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void Validate( CValidator &validator, const char *pchName );
|
||||
#endif
|
||||
|
||||
private:
|
||||
//-----------------------------------------------------------------------------
|
||||
// CItemSelectionCriteria::CCondition
|
||||
// Represents one condition of the criteria
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCondition : public ICondition
|
||||
{
|
||||
public:
|
||||
CCondition( const char *pszField, EItemCriteriaOperator eOp, bool bRequired )
|
||||
: m_sField( pszField ), m_EOp( eOp ), m_bRequired( bRequired )
|
||||
{
|
||||
}
|
||||
|
||||
// ICondition interface.
|
||||
virtual bool BItemDefinitionPassesCriteria( const CEconItemDefinition *pItemDef ) const OVERRIDE;
|
||||
|
||||
// Serializes the condition to the message
|
||||
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const;
|
||||
|
||||
// Validation
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
virtual void Validate( CValidator &validator, const char *pchName );
|
||||
#endif
|
||||
|
||||
EItemCriteriaOperator GetEOp( void ) const OVERRIDE { return m_EOp; }
|
||||
virtual const char *GetField( void ) const OVERRIDE { return m_sField.Get(); }
|
||||
virtual const char *GetValue( void ) const OVERRIDE { Assert(0); return NULL; }
|
||||
|
||||
private:
|
||||
// Returns if the given KeyValues block passes this condition
|
||||
// Performs common checks and calls BInternalEvaluate
|
||||
bool BEvaluate( KeyValues *pKVItem ) const;
|
||||
|
||||
protected:
|
||||
// Returns true if applying the element's operator on m_sField of
|
||||
// pKVItem returns true. This is only called if m_pszField exists in pKVItem
|
||||
virtual bool BInternalEvaluate( KeyValues *pKVItem ) const = 0;
|
||||
|
||||
// The field of the raw KeyValue form of the item definition to check
|
||||
CUtlString m_sField;
|
||||
// The operator this clause uses
|
||||
EItemCriteriaOperator m_EOp;
|
||||
// When true, BEvaluate returns false if m_sField does not exist in pKVItem
|
||||
bool m_bRequired;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CItemSelectionCriteria::CStringCondition
|
||||
// CCondition that handles the string-based operators
|
||||
//-----------------------------------------------------------------------------
|
||||
class CStringCondition : public CCondition
|
||||
{
|
||||
public:
|
||||
CStringCondition( const char *pszField, EItemCriteriaOperator eOp, const char *pszValue, bool bRequired )
|
||||
: CCondition( pszField, eOp, bRequired ), m_sValue( pszValue )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CStringCondition( ) { }
|
||||
|
||||
virtual const char *GetValue( void ) const OVERRIDE { return m_sValue.Get(); }
|
||||
|
||||
// Validation
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
virtual void Validate( CValidator &validator, const char *pchName );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual bool BInternalEvaluate( KeyValues *pKVItem ) const;
|
||||
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const;
|
||||
|
||||
// The value to check against
|
||||
CUtlString m_sValue;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CItemSelectionCriteria::CFloatCondition
|
||||
// CCondition that handles the float-based operators
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFloatCondition : public CCondition
|
||||
{
|
||||
public:
|
||||
CFloatCondition( const char *pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired )
|
||||
: CCondition( pszField, eOp, bRequired ), m_flValue( flValue )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CFloatCondition( ) { }
|
||||
|
||||
protected:
|
||||
virtual bool BInternalEvaluate( KeyValues *pKVItem ) const;
|
||||
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const;
|
||||
|
||||
// The value to check against
|
||||
float m_flValue;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CItemSelectionCriteria::CSetCondition
|
||||
// CCondition that handles subkey checks
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSetCondition : public CCondition
|
||||
{
|
||||
public:
|
||||
CSetCondition( const char *pszField, EItemCriteriaOperator eOp, const char *pszValue, bool bRequired )
|
||||
: CCondition( pszField, eOp, bRequired ), m_sValue( pszValue )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CSetCondition( ) { }
|
||||
|
||||
// Validation
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
virtual void Validate( CValidator &validator, const char *pchName );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual bool BInternalEvaluate( KeyValues *pKVItem ) const;
|
||||
|
||||
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const;
|
||||
|
||||
// The subkey to look for
|
||||
CUtlString m_sValue;
|
||||
};
|
||||
|
||||
// True if item level is specified in this criteria
|
||||
bool m_bItemLevelSet;
|
||||
// The level of the item to generate
|
||||
uint32 m_unItemLevel;
|
||||
// True if quality is specified in this criteria
|
||||
bool m_bQualitySet;
|
||||
// The quality of the item to generate
|
||||
int32 m_nItemQuality;
|
||||
// The initial inventory token of the item
|
||||
uint32 m_unInitialInventory;
|
||||
// True if initial quantity is specified in this criteria.
|
||||
bool m_bInitialQuantitySet;
|
||||
// The initial quantity of the item
|
||||
uint32 m_unInitialQuantity;
|
||||
// Enforced explicit quality matching
|
||||
bool m_bForcedQualityMatch;
|
||||
// Ignoring enabled flag (used when crafting)
|
||||
bool m_bIgnoreEnabledFlag;
|
||||
|
||||
// A list of tags
|
||||
CUtlString m_strTags;
|
||||
CUtlVector<econ_tag_handle_t> m_vecTags;
|
||||
|
||||
// A list of the conditions
|
||||
CUtlVector<ICondition *> m_vecConditions;
|
||||
};
|
||||
|
||||
|
||||
#endif //ITEM_SELECTION_CRITERIA_H
|
||||
@@ -0,0 +1,199 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "localization_provider.h"
|
||||
|
||||
enum { kScratchBufferSize = 1024 };
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Find a localized string, but return something safe if the key is null or the localized
|
||||
// string is missing.
|
||||
// ----------------------------------------------------------------------------
|
||||
locchar_t* CLocalizationProvider::FindSafe( const char* pchKey ) const
|
||||
{
|
||||
if ( pchKey )
|
||||
{
|
||||
locchar_t* wszLocalized = Find( pchKey );
|
||||
if ( !wszLocalized )
|
||||
{
|
||||
#ifdef STAGING_ONLY
|
||||
return const_cast< locchar_t* >(LOCCHAR("<NULL LOC STRING>")); // Super janky cast alert! This method should really return a const locchar_t* but making that change breaks all the callsites...fix later.
|
||||
#else
|
||||
return const_cast<locchar_t*>(LOCCHAR(""));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
return wszLocalized;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef STAGING_ONLY
|
||||
return const_cast<locchar_t*>(LOCCHAR("<NULL LOC KEY>"));
|
||||
#else
|
||||
return const_cast<locchar_t*>(LOCCHAR(""));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GC
|
||||
#include "gcsdk/gcbase.h"
|
||||
|
||||
// GC Localization implementation
|
||||
|
||||
static CGCLocalizationProvider *GGCLocalizationProvider()
|
||||
{
|
||||
static CGCLocalizationProvider *g_pGCLocalizationProvider = NULL;
|
||||
if ( !g_pGCLocalizationProvider )
|
||||
g_pGCLocalizationProvider = new CGCLocalizationProvider( GGCGameBase() );
|
||||
return g_pGCLocalizationProvider;
|
||||
}
|
||||
|
||||
CLocalizationProvider *GLocalizationProvider()
|
||||
{
|
||||
AssertMsg( false, "Using global localization provider in GC - All strings will be in English. For proper localization, CLocalizationProvider instance should be created and passed in." );
|
||||
return GGCLocalizationProvider();
|
||||
}
|
||||
|
||||
locchar_t *CGCLocalizationProvider::Find( const char *pchKey ) const
|
||||
{
|
||||
// we emulate VGUI's behavior of returning an empty string for keys that are not found
|
||||
return (locchar_t*)m_pGC->LocalizeToken( pchKey, m_eLang, false );
|
||||
}
|
||||
|
||||
bool CGCLocalizationProvider::BEnsureCleanUTF8Truncation( char *unicodeOutput )
|
||||
{
|
||||
int nStringLength = V_strlen( unicodeOutput );
|
||||
|
||||
// make sure we're not in the middle of a multibyte character
|
||||
int iPos = nStringLength - 1;
|
||||
char c = unicodeOutput[iPos];
|
||||
if ( (c & 0x80) != 0 )
|
||||
{
|
||||
// not an ascii char, so do some multibyte char checking
|
||||
int cBytes = 0;
|
||||
// count up all continuation bytes
|
||||
while ( (c & 0xC0) == 0x80 && iPos > 0 ) // first two bits are 10xxxx, continuation
|
||||
{
|
||||
cBytes++;
|
||||
c = unicodeOutput[--iPos];
|
||||
}
|
||||
|
||||
// make sure we had the expected number of continuation bytes for the last
|
||||
// multibyte lead character
|
||||
bool bTruncateOK = true;
|
||||
if ( ( c & 0xF8 ) == 0xF0 ) // first 5 bits are 11110, should be 3 following bytes
|
||||
bTruncateOK = ( cBytes == 3 );
|
||||
else if ( ( c & 0xF0 ) == 0xE0 ) // first 4 bits are 1110, should be 2 following bytes
|
||||
bTruncateOK = ( cBytes == 2 );
|
||||
else if ( ( c & 0xE0 ) == 0xC0 ) // first 3 bits are 110, should be 1 following byte
|
||||
bTruncateOK = ( cBytes == 1 );
|
||||
|
||||
// if we truncated in the middle of a multi-byte char, move the end point back to this character
|
||||
if ( !bTruncateOK )
|
||||
unicodeOutput[iPos] = '\0';
|
||||
|
||||
return !bTruncateOK;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CGCLocalizationProvider::ConvertLoccharToANSI( const locchar_t *loc_In, CUtlConstString *out_ansi ) const
|
||||
{
|
||||
*out_ansi = loc_In;
|
||||
}
|
||||
|
||||
void CGCLocalizationProvider::ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const
|
||||
{
|
||||
wchar_t utf16_Scratch[kScratchBufferSize];
|
||||
|
||||
V_UTF8ToUnicode( loc_In, utf16_Scratch, kScratchBufferSize );
|
||||
*out_unicode = utf16_Scratch;
|
||||
}
|
||||
|
||||
void CGCLocalizationProvider::ConvertUTF8ToLocchar( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const
|
||||
{
|
||||
*out_loc = utf8_In;
|
||||
}
|
||||
|
||||
int CGCLocalizationProvider::ConvertLoccharToANSI( const locchar_t *loc, char *ansi, int ansiBufferSize ) const
|
||||
{
|
||||
Q_strncpy( ansi, loc, ansiBufferSize );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CGCLocalizationProvider::ConvertLoccharToUnicode( const locchar_t *loc, wchar_t *unicode, int unicodeBufferSize ) const
|
||||
{
|
||||
return V_UTF8ToUnicode( loc, unicode, unicodeBufferSize );
|
||||
}
|
||||
|
||||
|
||||
void CGCLocalizationProvider::ConvertUTF8ToLocchar( const char *utf8, locchar_t *locchar, int loccharBufferSize ) const
|
||||
{
|
||||
Q_strncpy( locchar, utf8, loccharBufferSize );
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
CLocalizationProvider *GLocalizationProvider()
|
||||
{
|
||||
static CVGUILocalizationProvider g_VGUILocalizationProvider;
|
||||
return &g_VGUILocalizationProvider;
|
||||
}
|
||||
|
||||
// vgui localization implementation
|
||||
|
||||
CVGUILocalizationProvider::CVGUILocalizationProvider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
locchar_t *CVGUILocalizationProvider::Find( const char *pchKey ) const
|
||||
{
|
||||
return (locchar_t*)g_pVGuiLocalize->Find( pchKey );
|
||||
}
|
||||
|
||||
void CVGUILocalizationProvider::ConvertLoccharToANSI( const locchar_t *loc_In, CUtlConstString *out_ansi ) const
|
||||
{
|
||||
char ansi_Scratch[kScratchBufferSize];
|
||||
|
||||
g_pVGuiLocalize->ConvertUnicodeToANSI( loc_In, ansi_Scratch, kScratchBufferSize );
|
||||
*out_ansi = ansi_Scratch;
|
||||
}
|
||||
|
||||
void CVGUILocalizationProvider::ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const
|
||||
{
|
||||
*out_unicode = loc_In;
|
||||
}
|
||||
|
||||
void CVGUILocalizationProvider::ConvertUTF8ToLocchar( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const
|
||||
{
|
||||
locchar_t loc_Scratch[kScratchBufferSize];
|
||||
|
||||
V_UTF8ToUnicode( utf8_In, loc_Scratch, kScratchBufferSize );
|
||||
*out_loc = loc_Scratch;
|
||||
}
|
||||
|
||||
void CVGUILocalizationProvider::ConvertUTF8ToLocchar( const char *utf8, locchar_t *locchar, int loccharBufferSize ) const
|
||||
{
|
||||
V_UTF8ToUnicode( utf8, locchar, loccharBufferSize );
|
||||
}
|
||||
|
||||
int CVGUILocalizationProvider::ConvertLoccharToANSI( const locchar_t *loc, char *ansi, int ansiBufferSize ) const
|
||||
{
|
||||
return g_pVGuiLocalize->ConvertUnicodeToANSI( loc, ansi, ansiBufferSize );
|
||||
}
|
||||
|
||||
int CVGUILocalizationProvider::ConvertLoccharToUnicode( const locchar_t *loc, wchar_t *unicode, int unicodeBufferSize ) const
|
||||
{
|
||||
Q_wcsncpy( unicode, loc, unicodeBufferSize );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,103 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: provide a layer of abstraction between GC and vgui localization systems
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef LOCALIZATION_PROVIDER_H
|
||||
#define LOCALIZATION_PROVIDER_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "language.h"
|
||||
#include "ilocalize.h"
|
||||
|
||||
|
||||
// interface matches a subset of VGUI functions
|
||||
class CLocalizationProvider
|
||||
{
|
||||
public:
|
||||
virtual locchar_t *Find( const char *pchKey ) const = 0;
|
||||
locchar_t* FindSafe( const char* pchKey ) const;
|
||||
|
||||
// new interface
|
||||
virtual void ConvertLoccharToANSI ( const locchar_t *loc_In, CUtlConstString *out_ansi ) const = 0;
|
||||
virtual void ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const = 0;
|
||||
virtual void ConvertUTF8ToLocchar ( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const = 0;
|
||||
|
||||
// old C-style interface
|
||||
virtual int ConvertLoccharToANSI( const locchar_t *loc, OUT_Z_BYTECAP(ansiBufferSize) char *ansi, int ansiBufferSize ) const = 0;
|
||||
virtual int ConvertLoccharToUnicode( const locchar_t *loc, OUT_Z_BYTECAP(unicodeBufferSize) wchar_t *unicode, int unicodeBufferSize ) const = 0;
|
||||
|
||||
virtual void ConvertUTF8ToLocchar( const char *utf8, OUT_Z_BYTECAP(loccharBufferSize) locchar_t *locchar, int loccharBufferSize ) const = 0;
|
||||
|
||||
virtual ELanguage GetELang() const = 0;
|
||||
};
|
||||
CLocalizationProvider *GLocalizationProvider();
|
||||
|
||||
#ifdef GC
|
||||
// GC localization is handled by the GC itself
|
||||
class CGCLocalizationProvider : public CLocalizationProvider
|
||||
{
|
||||
public:
|
||||
CGCLocalizationProvider( CGCGameBase *pGC, ELanguage eLang = k_Lang_English )
|
||||
{
|
||||
m_pGC = pGC;
|
||||
m_eLang = eLang;
|
||||
}
|
||||
|
||||
static bool BEnsureCleanUTF8Truncation( char *unicodeOutput );
|
||||
|
||||
virtual locchar_t *Find( const char *pchKey ) const;
|
||||
|
||||
// new interface
|
||||
virtual void ConvertLoccharToANSI ( const locchar_t *loc_In, CUtlConstString *out_ansi ) const;
|
||||
virtual void ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const;
|
||||
virtual void ConvertUTF8ToLocchar ( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const;
|
||||
|
||||
// old C-style interface
|
||||
virtual int ConvertLoccharToANSI( const locchar_t *loc, char *ansi, int ansiBufferSize ) const;
|
||||
virtual int ConvertLoccharToUnicode( const locchar_t *loc, wchar_t *unicode, int unicodeBufferSize ) const;
|
||||
|
||||
virtual void ConvertUTF8ToLocchar( const char *utf8, locchar_t *locchar, int loccharBufferSize ) const;
|
||||
|
||||
virtual ELanguage GetELang() const { return m_eLang; }
|
||||
|
||||
private:
|
||||
CGCGameBase *m_pGC;
|
||||
ELanguage m_eLang;
|
||||
};
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#include "vgui/ILocalize.h"
|
||||
extern vgui::ILocalize *g_pVGuiLocalize;
|
||||
|
||||
// Game localization is handled by vgui
|
||||
class CVGUILocalizationProvider : public CLocalizationProvider
|
||||
{
|
||||
public:
|
||||
CVGUILocalizationProvider();
|
||||
|
||||
virtual locchar_t *Find( const char *pchKey ) const;
|
||||
|
||||
// new interface
|
||||
virtual void ConvertLoccharToANSI ( const locchar_t *loc_In, CUtlConstString *out_ansi ) const;
|
||||
virtual void ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const;
|
||||
virtual void ConvertUTF8ToLocchar ( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const;
|
||||
|
||||
// old C-style interface
|
||||
virtual int ConvertLoccharToANSI( const locchar_t *loc, char *ansi, int ansiBufferSize ) const;
|
||||
virtual int ConvertLoccharToUnicode( const locchar_t *loc, wchar_t *unicode, int unicodeBufferSize ) const;
|
||||
|
||||
virtual void ConvertUTF8ToLocchar( const char *utf8, locchar_t *locchar, int loccharBufferSize ) const;
|
||||
|
||||
virtual ELanguage GetELang() const { return k_Lang_None; }
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // LOCALIZATION_PROVIDER_H
|
||||
Reference in New Issue
Block a user