You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
605 lines
19 KiB
605 lines
19 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Data shared between the client & game dlls |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "tf_shareddefs.h" |
|
#include "tier0/dbg.h" |
|
#include "basetypes.h" |
|
#include <KeyValues.h> |
|
|
|
#ifndef CLIENT_DLL |
|
|
|
#include "tf_team.h" |
|
#include "tf_class_commando.h" |
|
#include "tf_class_defender.h" |
|
#include "tf_class_escort.h" |
|
#include "tf_class_infiltrator.h" |
|
#include "tf_class_medic.h" |
|
#include "tf_class_recon.h" |
|
#include "tf_class_sniper.h" |
|
#include "tf_class_support.h" |
|
#include "tf_class_sapper.h" |
|
#include "tf_class_pyro.h" |
|
|
|
#else |
|
|
|
#include "c_tfteam.h" |
|
#include "c_tf_class_commando.h" |
|
#include "c_tf_class_defender.h" |
|
#include "c_tf_class_escort.h" |
|
#include "c_tf_class_infiltrator.h" |
|
#include "c_tf_class_medic.h" |
|
#include "c_tf_class_recon.h" |
|
#include "c_tf_class_sniper.h" |
|
#include "c_tf_class_support.h" |
|
#include "c_tf_class_sapper.h" |
|
#include "c_tf_class_pyro.h" |
|
|
|
#define CTFTeam C_TFTeam |
|
#endif |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
ConVar inv_demo( "inv_demo","0", FCVAR_REPLICATED, "Invasion demo." ); |
|
ConVar lod_effect_distance( "lod_effect_distance","3240000", FCVAR_REPLICATED, "Distance at which effects LOD." ); |
|
ConVar tf_cheapobjects( "tf_cheapobjects","0", FCVAR_REPLICATED, "Set to 1 and all objects will cost 0" ); |
|
|
|
|
|
//-------------------------------------------------------------------------- |
|
// OBJECTS |
|
//-------------------------------------------------------------------------- |
|
static int g_iClassInfo_Undecided[] = |
|
{ |
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Recon[] = |
|
{ |
|
OBJ_WAGON, |
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Commando[] = |
|
{ |
|
OBJ_POWERPACK, |
|
OBJ_VEHICLE_BOOST, |
|
OBJ_DRAGONSTEETH, |
|
OBJ_MANNED_MISSILELAUNCHER, |
|
OBJ_SANDBAG_BUNKER, |
|
OBJ_DRAGONSTEETH, |
|
|
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Medic[] = |
|
{ |
|
OBJ_POWERPACK, |
|
OBJ_SELFHEAL, |
|
OBJ_BUFF_STATION, |
|
OBJ_MANNED_PLASMAGUN, |
|
OBJ_SANDBAG_BUNKER, |
|
OBJ_BUNKER, |
|
OBJ_DRAGONSTEETH, |
|
OBJ_SHIELDWALL, |
|
|
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Defender[] = |
|
{ |
|
OBJ_POWERPACK, |
|
OBJ_SENTRYGUN_PLASMA, |
|
OBJ_MANNED_MISSILELAUNCHER, |
|
OBJ_BARBED_WIRE, |
|
OBJ_DRAGONSTEETH, |
|
OBJ_TOWER, |
|
OBJ_SANDBAG_BUNKER, |
|
OBJ_BUNKER, |
|
OBJ_DRIVER_MACHINEGUN, |
|
//OBJ_MORTAR, |
|
|
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Sniper[] = |
|
{ |
|
OBJ_WAGON, |
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Support[] = |
|
{ |
|
OBJ_WAGON, |
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Escort[] = |
|
{ |
|
OBJ_SHIELDWALL, |
|
OBJ_MANNED_SHIELD, |
|
OBJ_SANDBAG_BUNKER, |
|
OBJ_BUNKER, |
|
|
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Sapper[] = |
|
{ |
|
OBJ_POWERPACK, |
|
OBJ_DRAGONSTEETH, |
|
OBJ_TOWER, |
|
OBJ_SANDBAG_BUNKER, |
|
OBJ_MANNED_PLASMAGUN, |
|
|
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Infiltrator[] = |
|
{ |
|
OBJ_WAGON, |
|
OBJ_LAST |
|
}; |
|
|
|
static int g_iClassInfo_Pyro[] = |
|
{ |
|
OBJ_WAGON, |
|
OBJ_LAST |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool IsObjectAnUpgrade( int iObjectType ) |
|
{ |
|
return ( iObjectType >= OBJ_SELFHEAL && iObjectType < OBJ_BATTERING_RAM ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool IsObjectAVehicle( int iObjectType ) |
|
{ |
|
return ( iObjectType >= OBJ_BATTERING_RAM && iObjectType < OBJ_TOWER ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool IsObjectADefensiveBuilding( int iObjectType ) |
|
{ |
|
return ( iObjectType >= OBJ_TOWER ); |
|
} |
|
|
|
//-------------------------------------------------------------------------- |
|
// PLAYER CLASSES |
|
//-------------------------------------------------------------------------- |
|
|
|
#if defined( CLIENT_DLL ) |
|
|
|
#define DEFINE_PLAYERCLASS_ALLOC_FNS( className, iClass ) \ |
|
C_PlayerClass* AllocClient##className##( C_BaseTFPlayer *pPlayer ) \ |
|
{ \ |
|
return new C_PlayerClass##className##( pPlayer ); \ |
|
} \ |
|
CPlayerClass* AllocServer##className##( CBaseTFPlayer *pPlayer ) \ |
|
{ \ |
|
Assert( false ); \ |
|
return NULL; \ |
|
} |
|
|
|
#define GENERATE_PLAYERCLASS_INFO( className ) \ |
|
AllocClient##className##, AllocServer##className, NULL |
|
|
|
|
|
// ------------------------------------------------------------------------------------- // |
|
// DT_AllPlayerClasses recv table. |
|
// ------------------------------------------------------------------------------------- // |
|
|
|
BEGIN_RECV_TABLE_NOBASE( C_AllPlayerClasses, DT_AllPlayerClasses ) |
|
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_COMMANDO]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassCommandoData ), DataTableRecvProxy_PointerDataTable ), |
|
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_DEFENDER]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassDefenderData ), DataTableRecvProxy_PointerDataTable ), |
|
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_ESCORT]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassEscortData ), DataTableRecvProxy_PointerDataTable ), |
|
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_INFILTRATOR]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassInfiltratorData ), DataTableRecvProxy_PointerDataTable ), |
|
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_MEDIC]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassMedicData ), DataTableRecvProxy_PointerDataTable ), |
|
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_RECON]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassReconData ), DataTableRecvProxy_PointerDataTable ), |
|
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_SNIPER]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassSniperData ), DataTableRecvProxy_PointerDataTable ), |
|
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_SUPPORT]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassSupportData ), DataTableRecvProxy_PointerDataTable ), |
|
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_SAPPER]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassSapperData ), DataTableRecvProxy_PointerDataTable ) |
|
END_RECV_TABLE() |
|
|
|
#else |
|
|
|
#define DEFINE_PLAYERCLASS_ALLOC_FNS( className, iClass ) \ |
|
ConVar class_##className##_health( "class_" #className "_health", "0", FCVAR_NONE, #className "'s max health" ); \ |
|
C_PlayerClass* AllocClient##className##( C_BaseTFPlayer *pPlayer ) \ |
|
{ \ |
|
Assert( false ); \ |
|
return NULL; \ |
|
} \ |
|
CPlayerClass* AllocServer##className##( CBaseTFPlayer *pPlayer ) \ |
|
{ \ |
|
return new CPlayerClass##className##( pPlayer, iClass ); \ |
|
} |
|
|
|
#define GENERATE_PLAYERCLASS_INFO( className ) \ |
|
AllocClient##className##, AllocServer##className, &class_##className##_health |
|
|
|
|
|
// ------------------------------------------------------------------------------------- // |
|
// DT_AllPlayerClasses recv table. |
|
// ------------------------------------------------------------------------------------- // |
|
|
|
BEGIN_SEND_TABLE_NOBASE( CAllPlayerClasses, DT_AllPlayerClasses ) |
|
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_COMMANDO]), &REFERENCE_SEND_TABLE( DT_PlayerClassCommandoData ), SendProxy_DataTablePtrToDataTable ), |
|
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_DEFENDER]), &REFERENCE_SEND_TABLE( DT_PlayerClassDefenderData ), SendProxy_DataTablePtrToDataTable ), |
|
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_ESCORT]), &REFERENCE_SEND_TABLE( DT_PlayerClassEscortData ), SendProxy_DataTablePtrToDataTable ), |
|
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_INFILTRATOR]),&REFERENCE_SEND_TABLE( DT_PlayerClassInfiltratorData ), SendProxy_DataTablePtrToDataTable ), |
|
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_MEDIC]), &REFERENCE_SEND_TABLE( DT_PlayerClassMedicData ), SendProxy_DataTablePtrToDataTable ), |
|
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_RECON]), &REFERENCE_SEND_TABLE( DT_PlayerClassReconData ), SendProxy_DataTablePtrToDataTable ), |
|
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_SNIPER]), &REFERENCE_SEND_TABLE( DT_PlayerClassSniperData ), SendProxy_DataTablePtrToDataTable ), |
|
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_SUPPORT]), &REFERENCE_SEND_TABLE( DT_PlayerClassSupportData ), SendProxy_DataTablePtrToDataTable ), |
|
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_SAPPER]), &REFERENCE_SEND_TABLE( DT_PlayerClassSapperData ), SendProxy_DataTablePtrToDataTable ) |
|
END_SEND_TABLE() |
|
|
|
#endif |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------- // |
|
// CAllPlayerClasses implementation. |
|
// ------------------------------------------------------------------------------------- // |
|
|
|
CAllPlayerClasses::CAllPlayerClasses( PLAYER_TYPE *pPlayer ) |
|
{ |
|
for ( int i=0; i < TFCLASS_CLASS_COUNT; i++ ) |
|
{ |
|
m_pClasses[i] = NULL; |
|
|
|
#if defined( CLIENT_DLL ) |
|
if ( GetTFClassInfo( i )->m_pClientAlloc ) |
|
m_pClasses[i] = GetTFClassInfo( i )->m_pClientAlloc( pPlayer ); |
|
#else |
|
if ( GetTFClassInfo( i )->m_pServerAlloc ) |
|
m_pClasses[i] = GetTFClassInfo( i )->m_pServerAlloc( pPlayer ); |
|
#endif |
|
} |
|
} |
|
|
|
CAllPlayerClasses::~CAllPlayerClasses() |
|
{ |
|
for ( int i=0; i < TFCLASS_CLASS_COUNT; i++ ) |
|
{ |
|
delete m_pClasses[i]; |
|
} |
|
} |
|
|
|
PLAYER_CLASS_TYPE* CAllPlayerClasses::GetPlayerClass( int iClass ) |
|
{ |
|
Assert( iClass >= 0 && iClass < TFCLASS_CLASS_COUNT ); |
|
return m_pClasses[iClass]; |
|
} |
|
|
|
|
|
|
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Recon, TFCLASS_RECON ); |
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Commando, TFCLASS_COMMANDO ); |
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Medic, TFCLASS_MEDIC ); |
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Defender, TFCLASS_DEFENDER ); |
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Sniper, TFCLASS_SNIPER ); |
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Support, TFCLASS_SUPPORT ); |
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Escort, TFCLASS_ESCORT ); |
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Sapper, TFCLASS_SAPPER ); |
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Infiltrator, TFCLASS_INFILTRATOR ); |
|
DEFINE_PLAYERCLASS_ALLOC_FNS( Pyro, TFCLASS_PYRO ); |
|
|
|
CTFClassInfo g_TFClassInfos[ TFCLASS_CLASS_COUNT ] = |
|
{ |
|
{ "Undecided", g_iClassInfo_Undecided, false, NULL, NULL, NULL }, |
|
{ "Recon", g_iClassInfo_Recon, false, GENERATE_PLAYERCLASS_INFO( Recon ) }, |
|
{ "Commando", g_iClassInfo_Commando, true, GENERATE_PLAYERCLASS_INFO( Commando ) }, |
|
{ "Medic", g_iClassInfo_Medic, true, GENERATE_PLAYERCLASS_INFO( Medic ) }, |
|
{ "Defender", g_iClassInfo_Defender, true, GENERATE_PLAYERCLASS_INFO( Defender ) }, |
|
{ "Sniper", g_iClassInfo_Sniper, false, GENERATE_PLAYERCLASS_INFO( Sniper ) }, |
|
{ "Support", g_iClassInfo_Support, false, GENERATE_PLAYERCLASS_INFO( Support ) }, |
|
{ "Escort", g_iClassInfo_Escort, true, GENERATE_PLAYERCLASS_INFO( Escort ) }, |
|
{ "Sapper", g_iClassInfo_Sapper, true, GENERATE_PLAYERCLASS_INFO( Sapper ) }, |
|
{ "Infiltrator",g_iClassInfo_Infiltrator, false, GENERATE_PLAYERCLASS_INFO( Infiltrator ) }, |
|
{ "Pyro", g_iClassInfo_Pyro, false, GENERATE_PLAYERCLASS_INFO( Pyro ) } |
|
}; |
|
|
|
|
|
const CTFClassInfo* GetTFClassInfo( int i ) |
|
{ |
|
Assert( i >= 0 && i < TFCLASS_CLASS_COUNT ); |
|
return &g_TFClassInfos[i]; |
|
} |
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ // |
|
// CObjectInfo tables. |
|
// ------------------------------------------------------------------------------------------------ // |
|
|
|
CObjectInfo::CObjectInfo( char *pObjectName ) |
|
{ |
|
m_pObjectName = pObjectName; |
|
m_pClassName = NULL; |
|
m_flBuildTime = -9999; |
|
m_nMaxObjects = -9999; |
|
m_Cost = -9999; |
|
m_CostMultiplierPerInstance = -999; |
|
m_UpgradeCost = -9999; |
|
m_MaxUpgradeLevel = -9999; |
|
m_pBuilderWeaponName = NULL; |
|
m_pBuilderPlacementString = NULL; |
|
m_SelectionSlot = -9999; |
|
m_SelectionPosition = -9999; |
|
m_bSolidToPlayerMovement = false; |
|
m_flSapperAttachTime = -9999; |
|
m_pIconActive = NULL; |
|
} |
|
|
|
|
|
CObjectInfo::~CObjectInfo() |
|
{ |
|
delete [] m_pClassName; |
|
delete [] m_pStatusName; |
|
delete [] m_pBuilderWeaponName; |
|
delete [] m_pBuilderPlacementString; |
|
delete [] m_pIconActive; |
|
} |
|
|
|
|
|
CObjectInfo g_ObjectInfos[OBJ_LAST] = |
|
{ |
|
CObjectInfo( "OBJ_POWERPACK" ), |
|
CObjectInfo( "OBJ_RESUPPLY" ), |
|
CObjectInfo( "OBJ_SENTRYGUN_PLASMA" ), |
|
CObjectInfo( "OBJ_SENTRYGUN_ROCKET_LAUNCHER" ), |
|
CObjectInfo( "OBJ_SHIELDWALL" ), |
|
CObjectInfo( "OBJ_RESOURCEPUMP" ), |
|
CObjectInfo( "OBJ_RESPAWN_STATION" ), |
|
CObjectInfo( "OBJ_RALLYFLAG" ), |
|
CObjectInfo( "OBJ_MANNED_PLASMAGUN" ), |
|
CObjectInfo( "OBJ_MANNED_MISSILELAUNCHER" ), |
|
CObjectInfo( "OBJ_MANNED_SHIELD" ), |
|
CObjectInfo( "OBJ_EMPGENERATOR" ), |
|
CObjectInfo( "OBJ_BUFF_STATION" ), |
|
CObjectInfo( "OBJ_BARBED_WIRE" ), |
|
CObjectInfo( "OBJ_MCV_SELECTION_PANEL" ), |
|
CObjectInfo( "OBJ_MAPDEFINED" ), |
|
CObjectInfo( "OBJ_MORTAR" ), |
|
CObjectInfo( "OBJ_SELFHEAL" ), |
|
CObjectInfo( "OBJ_ARMOR_UPGRADE" ), |
|
CObjectInfo( "OBJ_VEHICLE_BOOST" ), |
|
CObjectInfo( "OBJ_EXPLOSIVES" ), |
|
CObjectInfo( "OBJ_DRIVER_MACHINEGUN" ), |
|
CObjectInfo( "OBJ_BATTERING_RAM" ), |
|
CObjectInfo( "OBJ_SIEGE_TOWER" ), |
|
CObjectInfo( "OBJ_WAGON" ), |
|
CObjectInfo( "OBJ_FLATBED" ), |
|
CObjectInfo( "OBJ_VEHICLE_MORTAR" ), |
|
CObjectInfo( "OBJ_VEHICLE_TELEPORT_STATION" ), |
|
CObjectInfo( "OBJ_VEHICLE_TANK" ), |
|
CObjectInfo( "OBJ_VEHICLE_MOTORCYCLE" ), |
|
CObjectInfo( "OBJ_WALKER_STRIDER" ), |
|
CObjectInfo( "OBJ_WALKER_MINI_STRIDER" ), |
|
CObjectInfo( "OBJ_TOWER" ), |
|
CObjectInfo( "OBJ_TUNNEL" ), |
|
CObjectInfo( "OBJ_SANDBAG_BUNKER" ), |
|
CObjectInfo( "OBJ_BUNKER" ), |
|
CObjectInfo( "OBJ_DRAGONSTEETH" ), |
|
}; |
|
|
|
|
|
char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename ) |
|
{ |
|
const char *pValue = pSub->GetString( pName, NULL ); |
|
if ( !pValue ) |
|
{ |
|
DevWarning( "Can't get key value '%s' from file '%s'.\n", pName, pFilename ); |
|
return ""; |
|
} |
|
|
|
int len = Q_strlen( pValue ) + 1; |
|
char *pAlloced = new char[ len ]; |
|
Assert( pAlloced ); |
|
Q_strncpy( pAlloced, pValue, len ); |
|
return pAlloced; |
|
} |
|
|
|
|
|
bool AreObjectInfosLoaded() |
|
{ |
|
return g_ObjectInfos[0].m_pClassName != NULL; |
|
} |
|
|
|
|
|
void LoadObjectInfos( IBaseFileSystem *pFileSystem ) |
|
{ |
|
const char *pFilename = "scripts/objects.txt"; |
|
|
|
// Make sure this stuff hasn't already been loaded. |
|
Assert( !AreObjectInfosLoaded() ); |
|
|
|
KeyValues *pValues = new KeyValues( "Object descriptions" ); |
|
if ( !pValues->LoadFromFile( pFileSystem, pFilename, "GAME" ) ) |
|
{ |
|
Error( "Can't open %s for object info.", pFilename ); |
|
pValues->deleteThis(); |
|
return; |
|
} |
|
|
|
// Now read each class's information in. |
|
for ( int iObj=0; iObj < ARRAYSIZE( g_ObjectInfos ); iObj++ ) |
|
{ |
|
CObjectInfo *pInfo = &g_ObjectInfos[iObj]; |
|
KeyValues *pSub = pValues->FindKey( pInfo->m_pObjectName ); |
|
if ( !pSub ) |
|
{ |
|
Error( "Missing section '%s' from %s.", pInfo->m_pObjectName, pFilename ); |
|
pValues->deleteThis(); |
|
return; |
|
} |
|
|
|
// Read all the info in. |
|
if ( (pInfo->m_flBuildTime = pSub->GetFloat( "BuildTime", -999 )) == -999 || |
|
(pInfo->m_nMaxObjects = pSub->GetInt( "MaxObjects", -999 )) == -999 || |
|
(pInfo->m_Cost = pSub->GetInt( "Cost", -999 )) == -999 || |
|
(pInfo->m_CostMultiplierPerInstance = pSub->GetFloat( "CostMultiplier", -999 )) == -999 || |
|
(pInfo->m_UpgradeCost = pSub->GetInt( "UpgradeCost", -999 )) == -999 || |
|
(pInfo->m_MaxUpgradeLevel = pSub->GetInt( "MaxUpgradeLevel", -999 )) == -999 || |
|
(pInfo->m_SelectionSlot = pSub->GetInt( "SelectionSlot", -999 )) == -999 || |
|
(pInfo->m_SelectionPosition = pSub->GetInt( "SelectionPosition", -999 )) == -999 || |
|
(pInfo->m_flSapperAttachTime = pSub->GetInt( "SapperAttachTime", -999 )) == -999 ) |
|
{ |
|
Error( "Missing data for object '%s' in %s.", pInfo->m_pObjectName, pFilename ); |
|
pValues->deleteThis(); |
|
return; |
|
} |
|
|
|
pInfo->m_pClassName = ReadAndAllocStringValue( pSub, "ClassName", pFilename ); |
|
pInfo->m_pStatusName = ReadAndAllocStringValue( pSub, "StatusName", pFilename ); |
|
pInfo->m_pBuilderWeaponName = ReadAndAllocStringValue( pSub, "BuilderWeaponName", pFilename ); |
|
pInfo->m_pBuilderPlacementString = ReadAndAllocStringValue( pSub, "BuilderPlacementString", pFilename ); |
|
pInfo->m_bSolidToPlayerMovement = pSub->GetInt( "SolidToPlayerMovement", 0 ) ? true : false; |
|
pInfo->m_pIconActive = ReadAndAllocStringValue( pSub, "Icon", pFilename ); |
|
} |
|
|
|
pValues->deleteThis(); |
|
} |
|
|
|
|
|
const CObjectInfo* GetObjectInfo( int iObject ) |
|
{ |
|
Assert( iObject >= 0 && iObject < OBJ_LAST ); |
|
Assert( AreObjectInfosLoaded() ); |
|
return &g_ObjectInfos[iObject]; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return true if the specified class is allowed to build the specified object type |
|
//----------------------------------------------------------------------------- |
|
bool ClassCanBuild( int iClass, int iObjectType ) |
|
{ |
|
for ( int i = 0; i < OBJ_LAST; i++ ) |
|
{ |
|
// Hit the end? |
|
if ( g_TFClassInfos[iClass].m_pClassObjects[i] == OBJ_LAST ) |
|
return false; |
|
|
|
// Found it? |
|
if ( g_TFClassInfos[iClass].m_pClassObjects[i] == iObjectType ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return the cost of another object of the specified type |
|
// If bLast is set, return the cost of the last built object of the specified type |
|
//----------------------------------------------------------------------------- |
|
|
|
int CalculateObjectCost( int iObjectType, int iNumberOfObjects, int iTeam, bool bLast ) |
|
{ |
|
if ( tf_cheapobjects.GetInt() ) |
|
{ |
|
return 0; |
|
} |
|
|
|
// Find out how much the next object should cost |
|
if ( bLast ) |
|
{ |
|
iNumberOfObjects = MAX(0,iNumberOfObjects-1); |
|
} |
|
|
|
int iCost = GetObjectInfo( iObjectType )->m_Cost; |
|
|
|
// If a cost is negative, it means the first object of that type is free, and then |
|
// it counts up as normal, using the negative value. |
|
if ( iCost < 0 ) |
|
{ |
|
if ( iNumberOfObjects == 0 ) |
|
return 0; |
|
iCost *= -1; |
|
iNumberOfObjects--; |
|
} |
|
|
|
// MCVs have special rules: The team's first one is always free |
|
if ( iObjectType == OBJ_VEHICLE_TELEPORT_STATION ) |
|
{ |
|
CTFTeam *pTeam = (CTFTeam *)GetGlobalTeam(iTeam); |
|
if ( pTeam && pTeam->GetNumObjects(OBJ_VEHICLE_TELEPORT_STATION) == 0 ) |
|
{ |
|
iCost = 0; |
|
} |
|
} |
|
|
|
// Human objects cost less across the board |
|
if ( iTeam == TEAM_HUMANS ) |
|
{ |
|
iCost = ( ((float)iCost) * 0.8 ); |
|
} |
|
|
|
// Calculate the cost based upon the number of objects |
|
for ( int i = 0; i < iNumberOfObjects; i++ ) |
|
{ |
|
iCost *= GetObjectInfo( iObjectType )->m_CostMultiplierPerInstance; |
|
} |
|
|
|
return iCost; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Calculate the cost to upgrade an object of a specific type |
|
//----------------------------------------------------------------------------- |
|
int CalculateObjectUpgrade( int iObjectType, int iObjectLevel ) |
|
{ |
|
// Max level? |
|
if ( iObjectLevel >= GetObjectInfo( iObjectType )->m_MaxUpgradeLevel ) |
|
return 0; |
|
|
|
int iCost = GetObjectInfo( iObjectType )->m_UpgradeCost; |
|
for ( int i = 0; i < (iObjectLevel - 1); i++ ) |
|
{ |
|
iCost *= OBJECT_UPGRADE_COST_MULTIPLIER_PER_LEVEL; |
|
} |
|
|
|
return iCost; |
|
} |
|
|
|
//-------------------------------------------------------------------------- |
|
// MORTAR |
|
//-------------------------------------------------------------------------- |
|
// Names for each mortar ammo type |
|
char *MortarAmmoNames[ MA_LASTAMMOTYPE ] = |
|
{ |
|
"Normal Rounds", |
|
//"Smoke Rounds", |
|
"Cluster Rounds", |
|
"Starburst Rounds", |
|
}; |
|
|
|
// Techs needs for each mortar ammo type |
|
char *MortarAmmoTechs[ MA_LASTAMMOTYPE ] = |
|
{ |
|
"", |
|
//"mortar_ammo_smoke", |
|
"mortar_ammo_cluster", |
|
"mortar_ammo_starburst", |
|
}; |
|
|
|
// Max amounts of each mortar ammo type in a single mortar |
|
int MortarAmmoMax[ MA_LASTAMMOTYPE ] = |
|
{ |
|
-1, // -1 is infinite ammo |
|
//20, |
|
20, |
|
10, |
|
};
|
|
|