summaryrefslogtreecommitdiff
path: root/game/shared/tf2/tf_shareddefs.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf2/tf_shareddefs.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/tf2/tf_shareddefs.cpp')
-rw-r--r--game/shared/tf2/tf_shareddefs.cpp605
1 files changed, 605 insertions, 0 deletions
diff --git a/game/shared/tf2/tf_shareddefs.cpp b/game/shared/tf2/tf_shareddefs.cpp
new file mode 100644
index 0000000..32d63be
--- /dev/null
+++ b/game/shared/tf2/tf_shareddefs.cpp
@@ -0,0 +1,605 @@
+//========= 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,
+};