summaryrefslogtreecommitdiff
path: root/game/shared/tf/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/tf/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/tf/tf_shareddefs.cpp')
-rw-r--r--game/shared/tf/tf_shareddefs.cpp2011
1 files changed, 2011 insertions, 0 deletions
diff --git a/game/shared/tf/tf_shareddefs.cpp b/game/shared/tf/tf_shareddefs.cpp
new file mode 100644
index 0000000..4214533
--- /dev/null
+++ b/game/shared/tf/tf_shareddefs.cpp
@@ -0,0 +1,2011 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "cbase.h"
+#include "tf_shareddefs.h"
+#include "KeyValues.h"
+#include "takedamageinfo.h"
+#include "tf_gamerules.h"
+#include "filesystem.h"
+#include "tf_matchmaking_shared.h"
+
+//-----------------------------------------------------------------------------
+// Teams.
+//-----------------------------------------------------------------------------
+const char *g_aTeamNames[TF_TEAM_COUNT] =
+{
+ "Unassigned",
+ "Spectator",
+ "Red",
+ "Blue"
+};
+
+color32 g_aTeamColors[TF_TEAM_COUNT] =
+{
+ { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ { 255, 0, 0, 0 },
+ { 0, 0, 255, 0 }
+};
+
+//-----------------------------------------------------------------------------
+// Classes.
+//-----------------------------------------------------------------------------
+
+const char *g_aPlayerClassNames[TF_CLASS_MENU_BUTTONS] =
+{
+ "#TF_Class_Name_Undefined",
+ "#TF_Class_Name_Scout",
+ "#TF_Class_Name_Sniper",
+ "#TF_Class_Name_Soldier",
+ "#TF_Class_Name_Demoman",
+ "#TF_Class_Name_Medic",
+ "#TF_Class_Name_HWGuy",
+ "#TF_Class_Name_Pyro",
+ "#TF_Class_Name_Spy",
+ "#TF_Class_Name_Engineer",
+ "#TF_Class_Name_Civilian",
+ "",
+ "#TF_Random"
+};
+
+const char *g_aPlayerClassNames_NonLocalized[TF_CLASS_MENU_BUTTONS] =
+{
+ "Undefined",
+ "Scout",
+ "Sniper",
+ "Soldier",
+ "Demoman",
+ "Medic",
+ "Heavy",
+ "Pyro",
+ "Spy",
+ "Engineer",
+ "Civilian",
+ "",
+ "Random"
+};
+
+const char *g_aRawPlayerClassNamesShort[TF_CLASS_MENU_BUTTONS] =
+{
+ "undefined",
+ "scout",
+ "sniper",
+ "soldier",
+ "demo", // short
+ "medic",
+ "heavy",// short
+ "pyro",
+ "spy",
+ "engineer",
+ "civilian",
+ "",
+ "random"
+};
+
+const char *g_aRawPlayerClassNames[TF_CLASS_MENU_BUTTONS] =
+{
+ "undefined",
+ "scout",
+ "sniper",
+ "soldier",
+ "demoman",
+ "medic",
+ "heavyweapons",
+ "pyro",
+ "spy",
+ "engineer",
+ "civilian",
+ "",
+ "random"
+};
+
+const char g_szBotModels[][ MAX_PATH ] =
+{
+ "", //TF_CLASS_UNDEFINED
+
+ "models/bots/scout/bot_scout.mdl",
+ "models/bots/sniper/bot_sniper.mdl",
+ "models/bots/soldier/bot_soldier.mdl",
+ "models/bots/demo/bot_demo.mdl",
+ "models/bots/medic/bot_medic.mdl",
+ "models/bots/heavy/bot_heavy.mdl",
+ "models/bots/pyro/bot_pyro.mdl",
+ "models/bots/spy/bot_spy.mdl",
+ "models/bots/engineer/bot_engineer.mdl",
+};
+
+const char g_szPlayerRobotModels[][MAX_PATH] =
+{
+ "", //TF_CLASS_UNDEFINED
+
+ "models/bots/scout/bot_scout_human_anim.mdl",
+ "models/bots/sniper/bot_sniper_human_anim.mdl",
+ "models/bots/soldier/bot_soldier_human_anim.mdl",
+ "models/bots/demo/bot_demo_human_anim.mdl",
+ "models/bots/medic/bot_medic_human_anims.mdl",
+ "models/bots/heavy/bot_heavy_human_anims.mdl",
+ "models/bots/pyro/bot_pyro_human_anim.mdl",
+ "models/bots/spy/bot_spy_human_anims.mdl",
+ "models/bots/engineer/bot_engineer_human_anim.mdl",
+};
+
+const char g_szBotBossModels[][ MAX_PATH ] =
+{
+ "", //TF_CLASS_UNDEFINED
+
+ "models/bots/scout_boss/bot_scout_boss.mdl",
+ "models/bots/sniper/bot_sniper.mdl",
+ "models/bots/soldier_boss/bot_soldier_boss.mdl",
+ "models/bots/demo_boss/bot_demo_boss.mdl",
+ "models/bots/medic/bot_medic.mdl",
+ "models/bots/heavy_boss/bot_heavy_boss.mdl",
+ "models/bots/pyro_boss/bot_pyro_boss.mdl",
+ "models/bots/spy/bot_spy.mdl",
+ "models/bots/engineer/bot_engineer.mdl",
+};
+
+const char g_szBotBossSentryBusterModel[ MAX_PATH ] = "models/bots/demo/bot_sentry_buster.mdl";
+
+// Rome 2 promo models
+const char g_szRomePromoItems_Hat[][ MAX_PATH ] =
+{
+ "", //TF_CLASS_UNDEFINED
+
+ "tw_scoutbot_hat",
+ "tw_sniperbot_helmet",
+ "tw_soldierbot_helmet",
+ "tw_demobot_helmet",
+ "tw_medibot_hat",
+ "tw_heavybot_helmet",
+ "tw_pyrobot_helmet",
+ "tw_spybot_hood",
+ "tw_engineerbot_helmet",
+};
+
+const char g_szRomePromoItems_Misc[][ MAX_PATH ] =
+{
+ "", //TF_CLASS_UNDEFINED
+
+ "tw_scoutbot_armor",
+ "tw_sniperbot_armor",
+ "tw_soldierbot_armor",
+ "tw_demobot_armor",
+ "tw_medibot_chariot",
+ "tw_heavybot_armor",
+ "tw_pyrobot_armor",
+ "tw_spybot_armor",
+ "tw_engineerbot_armor",
+};
+
+const char *g_pszBreadModels[] =
+{
+ "models/weapons/c_models/c_bread/c_bread_baguette.mdl", // Spy
+ "models/weapons/c_models/c_bread/c_bread_burnt.mdl", // Pyro
+ "models/weapons/c_models/c_bread/c_bread_cinnamon.mdl", // Demo?
+ "models/weapons/c_models/c_bread/c_bread_cornbread.mdl", // Engineer
+ "models/weapons/c_models/c_bread/c_bread_crumpet.mdl", // Sniper?
+ "models/weapons/c_models/c_bread/c_bread_plainloaf.mdl", // Scout
+ "models/weapons/c_models/c_bread/c_bread_pretzel.mdl", // Medic
+ "models/weapons/c_models/c_bread/c_bread_ration.mdl", // Soldier
+ "models/weapons/c_models/c_bread/c_bread_russianblack.mdl", // Heavy?
+};
+
+int GetClassIndexFromString( const char *pClassName, int nLastClassIndex/*=TF_LAST_NORMAL_CLASS*/ )
+{
+ for ( int i = TF_FIRST_NORMAL_CLASS; i <= nLastClassIndex; ++i )
+ {
+ // compare first N characters to allow matching both "heavy" and "heavyweapons"
+ int classnameLength = V_strlen( g_aPlayerClassNames_NonLocalized[i] );
+
+ if ( V_strlen( pClassName ) < classnameLength )
+ continue;
+
+ if ( !V_strnicmp( g_aPlayerClassNames_NonLocalized[i], pClassName, classnameLength ) )
+ {
+ return i;
+ }
+ }
+
+ return TF_CLASS_UNDEFINED;
+}
+
+int iRemapIndexToClass[TF_CLASS_MENU_BUTTONS] =
+{
+ 0,
+ TF_CLASS_SCOUT,
+ TF_CLASS_SOLDIER,
+ TF_CLASS_PYRO,
+ TF_CLASS_DEMOMAN,
+ TF_CLASS_HEAVYWEAPONS,
+ TF_CLASS_ENGINEER,
+ TF_CLASS_MEDIC,
+ TF_CLASS_SNIPER,
+ TF_CLASS_SPY,
+ 0,
+ 0,
+ TF_CLASS_RANDOM
+};
+
+int GetRemappedMenuIndexForClass( int iClass )
+{
+ int iIndex = 0;
+
+ for ( int i = 0 ; i < TF_CLASS_MENU_BUTTONS ; i++ )
+ {
+ if ( iRemapIndexToClass[i] == iClass )
+ {
+ iIndex = i;
+ break;
+ }
+ }
+
+ return iIndex;
+}
+
+ETFCond condition_to_attribute_translation[] =
+{
+ TF_COND_BURNING, // 1 (1<<0)
+ TF_COND_AIMING, // 2 (1<<1)
+ TF_COND_ZOOMED, // 4 (1<<2)
+ TF_COND_DISGUISING, // 8 (...)
+ TF_COND_DISGUISED, // 16
+ TF_COND_STEALTHED, // 32
+ TF_COND_INVULNERABLE, // 64
+ TF_COND_TELEPORTED, // 128
+ TF_COND_TAUNTING, // 256
+ TF_COND_INVULNERABLE_WEARINGOFF, // 512
+ TF_COND_STEALTHED_BLINK, // 1024
+ TF_COND_SELECTED_TO_TELEPORT, // 2048
+ TF_COND_CRITBOOSTED, // 4096
+ TF_COND_TMPDAMAGEBONUS, // 8192
+ TF_COND_FEIGN_DEATH, // 16384
+ TF_COND_PHASE, // 32768
+ TF_COND_STUNNED, // 65536
+ TF_COND_HEALTH_BUFF, // 131072
+ TF_COND_HEALTH_OVERHEALED, // 262144
+ TF_COND_URINE, // 524288
+ TF_COND_ENERGY_BUFF, // 1048576
+
+ TF_COND_LAST // sentinel value checked against when iterating
+};
+
+ETFCond g_aDebuffConditions[] =
+{
+ TF_COND_BURNING,
+ TF_COND_URINE,
+ TF_COND_BLEEDING,
+ TF_COND_MAD_MILK,
+ TF_COND_LAST
+};
+
+bool ConditionExpiresFast( ETFCond eCond )
+{
+ return eCond == TF_COND_BURNING
+ || eCond == TF_COND_URINE
+ || eCond == TF_COND_BLEEDING
+ || eCond == TF_COND_MAD_MILK;
+}
+
+static const char *g_aConditionNames[] =
+{
+ "TF_COND_AIMING", // Sniper aiming, Heavy minigun.
+ "TF_COND_ZOOMED",
+ "TF_COND_DISGUISING",
+ "TF_COND_DISGUISED",
+ "TF_COND_STEALTHED", // Spy specific
+ "TF_COND_INVULNERABLE",
+ "TF_COND_TELEPORTED",
+ "TF_COND_TAUNTING",
+ "TF_COND_INVULNERABLE_WEARINGOFF",
+ "TF_COND_STEALTHED_BLINK",
+ "TF_COND_SELECTED_TO_TELEPORT",
+ "TF_COND_CRITBOOSTED", // DO NOT RE-USE THIS -- THIS IS FOR KRITZKRIEG AND REVENGE CRITS ONLY
+ "TF_COND_TMPDAMAGEBONUS",
+ "TF_COND_FEIGN_DEATH",
+ "TF_COND_PHASE",
+ "TF_COND_STUNNED", // Any type of stun. Check iStunFlags for more info.
+ "TF_COND_OFFENSEBUFF",
+ "TF_COND_SHIELD_CHARGE",
+ "TF_COND_DEMO_BUFF",
+ "TF_COND_ENERGY_BUFF",
+ "TF_COND_RADIUSHEAL",
+ "TF_COND_HEALTH_BUFF",
+ "TF_COND_BURNING",
+ "TF_COND_HEALTH_OVERHEALED",
+ "TF_COND_URINE",
+ "TF_COND_BLEEDING",
+ "TF_COND_DEFENSEBUFF", // 35% defense! No crit damage.
+ "TF_COND_MAD_MILK",
+ "TF_COND_MEGAHEAL",
+ "TF_COND_REGENONDAMAGEBUFF",
+ "TF_COND_MARKEDFORDEATH",
+ "TF_COND_NOHEALINGDAMAGEBUFF",
+ "TF_COND_SPEED_BOOST", // = 32
+ "TF_COND_CRITBOOSTED_PUMPKIN", // Brandon hates bits
+ "TF_COND_CRITBOOSTED_USER_BUFF",
+ "TF_COND_CRITBOOSTED_DEMO_CHARGE",
+ "TF_COND_SODAPOPPER_HYPE",
+ "TF_COND_CRITBOOSTED_FIRST_BLOOD", // arena mode first blood
+ "TF_COND_CRITBOOSTED_BONUS_TIME",
+ "TF_COND_CRITBOOSTED_CTF_CAPTURE",
+ "TF_COND_CRITBOOSTED_ON_KILL", // =40. KGB, etc.
+ "TF_COND_CANNOT_SWITCH_FROM_MELEE",
+ "TF_COND_DEFENSEBUFF_NO_CRIT_BLOCK", // 35% defense! Still damaged by crits.
+ "TF_COND_REPROGRAMMED", // Bots only
+ "TF_COND_CRITBOOSTED_RAGE_BUFF",
+ "TF_COND_DEFENSEBUFF_HIGH", // 75% defense! Still damaged by crits.
+ "TF_COND_SNIPERCHARGE_RAGE_BUFF", // Sniper Rage - Charge time speed up
+ "TF_COND_DISGUISE_WEARINGOFF", // Applied for half-second post-disguise
+ "TF_COND_MARKEDFORDEATH_SILENT", // Sans sound
+ "TF_COND_DISGUISED_AS_DISPENSER",
+ "TF_COND_SAPPED", // =50. Bots only
+ "TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED",
+ "TF_COND_INVULNERABLE_USER_BUFF",
+ "TF_COND_HALLOWEEN_BOMB_HEAD",
+ "TF_COND_HALLOWEEN_THRILLER",
+ "TF_COND_RADIUSHEAL_ON_DAMAGE",
+ "TF_COND_CRITBOOSTED_CARD_EFFECT",
+ "TF_COND_INVULNERABLE_CARD_EFFECT",
+ "TF_COND_MEDIGUN_UBER_BULLET_RESIST",
+ "TF_COND_MEDIGUN_UBER_BLAST_RESIST",
+ "TF_COND_MEDIGUN_UBER_FIRE_RESIST", // =60
+ "TF_COND_MEDIGUN_SMALL_BULLET_RESIST",
+ "TF_COND_MEDIGUN_SMALL_BLAST_RESIST",
+ "TF_COND_MEDIGUN_SMALL_FIRE_RESIST",
+ "TF_COND_STEALTHED_USER_BUFF", // Any class can have this
+ "TF_COND_MEDIGUN_DEBUFF",
+ "TF_COND_STEALTHED_USER_BUFF_FADING",
+ "TF_COND_BULLET_IMMUNE",
+ "TF_COND_BLAST_IMMUNE",
+ "TF_COND_FIRE_IMMUNE",
+ "TF_COND_PREVENT_DEATH", // =70
+ "TF_COND_MVM_BOT_STUN_RADIOWAVE", // Bots only
+ "TF_COND_HALLOWEEN_SPEED_BOOST",
+ "TF_COND_HALLOWEEN_QUICK_HEAL",
+ "TF_COND_HALLOWEEN_GIANT",
+ "TF_COND_HALLOWEEN_TINY",
+ "TF_COND_HALLOWEEN_IN_HELL",
+ "TF_COND_HALLOWEEN_GHOST_MODE", // =77
+ "TF_COND_MINICRITBOOSTED_ON_KILL",
+ "TF_COND_OBSCURED_SMOKE",
+ "TF_COND_PARACHUTE_DEPLOYED", // =80
+ "TF_COND_BLASTJUMPING",
+ "TF_COND_HALLOWEEN_KART",
+ "TF_COND_HALLOWEEN_KART_DASH",
+ "TF_COND_BALLOON_HEAD", // =84 larger head, lower-gravity-feeling jumps
+ "TF_COND_MELEE_ONLY", // =85 melee only
+ "TF_COND_SWIMMING_CURSE", // player movement become swimming movement
+ "TF_COND_FREEZE_INPUT", // freezes player input
+ "TF_COND_HALLOWEEN_KART_CAGE", // attach cage model to player while in kart
+ "TF_COND_DONOTUSE_0",
+ "TF_COND_RUNE_STRENGTH",
+ "TF_COND_RUNE_HASTE",
+ "TF_COND_RUNE_REGEN",
+ "TF_COND_RUNE_RESIST",
+ "TF_COND_RUNE_VAMPIRE",
+ "TF_COND_RUNE_REFLECT",
+ "TF_COND_RUNE_PRECISION",
+ "TF_COND_RUNE_AGILITY",
+ "TF_COND_GRAPPLINGHOOK",
+ "TF_COND_GRAPPLINGHOOK_SAFEFALL",
+ "TF_COND_GRAPPLINGHOOK_LATCHED",
+ "TF_COND_GRAPPLINGHOOK_BLEEDING",
+ "TF_COND_AFTERBURN_IMMUNE",
+ "TF_COND_RUNE_KNOCKOUT",
+ "TF_COND_RUNE_IMBALANCE",
+ "TF_COND_CRITBOOSTED_RUNE_TEMP",
+ "TF_COND_PASSTIME_INTERCEPTION",
+ "TF_COND_SWIMMING_NO_EFFECTS", // =107_DNOC_FT
+ "TF_COND_PURGATORY",
+ "TF_COND_RUNE_KING",
+ "TF_COND_RUNE_PLAGUE",
+ "TF_COND_RUNE_SUPERNOVA",
+ "TF_COND_PLAGUE",
+ "TF_COND_KING_BUFFED",
+ "TF_COND_TEAM_GLOWS", // used to show team glows to living players
+ "TF_COND_KNOCKED_INTO_AIR",
+ "TF_COND_COMPETITIVE_WINNER",
+ "TF_COND_COMPETITIVE_LOSER",
+ "TF_COND_HEALING_DEBUFF",
+ "TF_COND_PASSTIME_PENALTY_DEBUFF",
+ "TF_COND_GRAPPLED_TO_PLAYER",
+ "TF_COND_GRAPPLED_BY_PLAYER",
+
+ //
+ // ADD NEW ITEMS HERE TO AVOID BREAKING DEMOS
+ //
+
+ // ******** Keep this block last! ********
+ // Keep experimental conditions below and graduate out of it before shipping
+#ifdef STAGING_ONLY
+ "TF_COND_NO_COMBAT_SPEED_BOOST", // STAGING_ENGY
+ "TF_COND_TRANQ_SPY_BOOST", // STAGING_SPY
+ "TF_COND_TRANQ_MARKED",
+// "TF_COND_SPACE_GRAVITY",
+// "TF_COND_SELF_CONC",
+ "TF_COND_ROCKETPACK",
+ "TF_COND_STEALTHED_PHASE",
+ "TF_COND_CLIP_OVERLOAD",
+ "TF_COND_SPY_CLASS_STEAL",
+#endif // STAGING_ONLY
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_aConditionNames ) == TF_COND_LAST );
+
+const char *GetTFConditionName( ETFCond eCond )
+{
+ if ( ( eCond >= ARRAYSIZE( g_aConditionNames ) ) || ( eCond < 0 ) )
+ return NULL;
+
+ return g_aConditionNames[eCond];
+}
+
+
+ETFCond GetTFConditionFromName( const char *pszCondName )
+{
+ for( uint i=0; i<TF_COND_LAST; i++ )
+ {
+ ETFCond eCond = (ETFCond)i;
+ if ( !V_stricmp( GetTFConditionName( eCond ), pszCondName ) )
+ return eCond;
+ }
+
+ Assert( !!"Invalid Condition Name" );
+ return TF_COND_INVALID;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gametypes.
+//-----------------------------------------------------------------------------
+static const char *s_aGameTypeNames[] =
+{
+ "Undefined",
+ "#Gametype_CTF",
+ "#Gametype_CP",
+ "#Gametype_Escort",
+ "#Gametype_Arena",
+ "#Gametype_MVM",
+ "#Gametype_RobotDestruction",
+ "#GameType_Passtime",
+ "#GameType_PlayerDestruction",
+};
+COMPILE_TIME_ASSERT( TF_GAMETYPE_COUNT == ARRAYSIZE( s_aGameTypeNames ) );
+
+const char *GetGameTypeName( ETFGameType gameType )
+{
+ return s_aGameTypeNames[ gameType ];
+}
+
+static const char *s_aEnumGameTypeName[] =
+{
+ "TF_GAMETYPE_UNDEFINED",
+ "TF_GAMETYPE_CTF",
+ "TF_GAMETYPE_CP",
+ "TF_GAMETYPE_ESCORT",
+ "TF_GAMETYPE_ARENA",
+ "TF_GAMETYPE_MVM",
+ "TF_GAMETYPE_RD",
+ "TF_GAMETYPE_PASSTIME",
+ "TF_GAMETYPE_PD"
+};
+COMPILE_TIME_ASSERT( TF_GAMETYPE_COUNT == ARRAYSIZE( s_aEnumGameTypeName ) );
+
+const char *GetEnumGameTypeName( ETFGameType gameType )
+{
+ return s_aEnumGameTypeName[ gameType ];
+}
+
+ETFGameType GetGameTypeFromName( const char *pszGameType )
+{
+ for ( int i=0; i<TF_GAMETYPE_COUNT; ++i )
+ {
+ if ( FStrEq( pszGameType, s_aEnumGameTypeName[i] ) )
+ return ETFGameType(i);
+ }
+
+ return TF_GAMETYPE_UNDEFINED;
+}
+
+//-----------------------------------------------------------------------------
+// Ammo.
+//-----------------------------------------------------------------------------
+const char *g_aAmmoNames[] =
+{
+ "DUMMY AMMO",
+ "TF_AMMO_PRIMARY",
+ "TF_AMMO_SECONDARY",
+ "TF_AMMO_METAL",
+ "TF_AMMO_GRENADES1",
+ "TF_AMMO_GRENADES2",
+ "TF_AMMO_GRENADES3"
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_aAmmoNames ) == TF_AMMO_COUNT );
+
+const char *GetAmmoName( int iAmmoType )
+{
+ ETFAmmoType eAmmoType = (ETFAmmoType)iAmmoType;
+ return g_aAmmoNames[ eAmmoType ];
+}
+
+const char *g_aCTFEventNames[] =
+{
+ "",
+ "TF_FLAGEVENT_PICKUP",
+ "TF_FLAGEVENT_CAPTURE",
+ "TF_FLAGEVENT_DEFEND",
+ "TF_FLAGEVENT_DROPPED",
+ "TF_FLAGEVENT_RETURNED",
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_aCTFEventNames ) == TF_NUM_FLAG_EVENTS );
+
+const char *GetCTFEventName( ETFFlagEventTypes iEventType )
+{
+ return g_aCTFEventNames[ iEventType ];
+}
+
+ETFFlagEventTypes GetCTFEventTypeFromName( const char *pszName )
+{
+ for( int i=TF_FLAGEVENT_PICKUP; i < TF_NUM_FLAG_EVENTS; ++i )
+ {
+ if ( FStrEq( pszName, GetCTFEventName( (ETFFlagEventTypes)i ) ) )
+ {
+ return (ETFFlagEventTypes)i;
+ }
+ }
+
+ Assert( false );
+ return TF_NUM_FLAG_EVENTS;
+}
+
+
+
+const char *GetRDScoreMethodName( RDScoreMethod_t iScoreMethod )
+{
+ static const char *aRDScoreMethodNames[] =
+ {
+ "SCORE_UNDEFINED", // -1
+ "SCORE_REACTOR_CAPTURED", // 0
+ "SCORE_CORES_COLLECTED",
+ "SCORE_REACTOR_RETURNED",
+ "SCORE_REACTOR_STEAL",
+
+ "NUM_SCORE_TYPES"
+ };
+
+ return aRDScoreMethodNames[ iScoreMethod + 1 ];
+}
+
+RDScoreMethod_t GetRDScoreMethodFromName( const char *pszName )
+{
+ for( int i=SCORE_UNDEFINED; i < NUM_SCORE_TYPES; ++i )
+ {
+ if ( FStrEq( pszName, GetRDScoreMethodName( (RDScoreMethod_t)i ) ) )
+ {
+ return (RDScoreMethod_t)i;
+ }
+ }
+
+ Assert( false );
+ return SCORE_UNDEFINED;
+}
+
+//-----------------------------------------------------------------------------
+// Weapons.
+//-----------------------------------------------------------------------------
+const char *g_aWeaponNames[] =
+{
+ "TF_WEAPON_NONE",
+ "TF_WEAPON_BAT",
+ "TF_WEAPON_BAT_WOOD",
+ "TF_WEAPON_BOTTLE",
+ "TF_WEAPON_FIREAXE",
+ "TF_WEAPON_CLUB",
+ "TF_WEAPON_CROWBAR",
+ "TF_WEAPON_KNIFE",
+ "TF_WEAPON_FISTS",
+ "TF_WEAPON_SHOVEL",
+ "TF_WEAPON_WRENCH",
+ "TF_WEAPON_BONESAW",
+ "TF_WEAPON_SHOTGUN_PRIMARY",
+ "TF_WEAPON_SHOTGUN_SOLDIER",
+ "TF_WEAPON_SHOTGUN_HWG",
+ "TF_WEAPON_SHOTGUN_PYRO",
+ "TF_WEAPON_SCATTERGUN",
+ "TF_WEAPON_SNIPERRIFLE",
+ "TF_WEAPON_MINIGUN",
+ "TF_WEAPON_SMG",
+ "TF_WEAPON_SYRINGEGUN_MEDIC",
+ "TF_WEAPON_TRANQ",
+ "TF_WEAPON_ROCKETLAUNCHER",
+ "TF_WEAPON_GRENADELAUNCHER",
+ "TF_WEAPON_PIPEBOMBLAUNCHER",
+ "TF_WEAPON_FLAMETHROWER",
+ "TF_WEAPON_GRENADE_NORMAL",
+ "TF_WEAPON_GRENADE_CONCUSSION",
+ "TF_WEAPON_GRENADE_NAIL",
+ "TF_WEAPON_GRENADE_MIRV",
+ "TF_WEAPON_GRENADE_MIRV_DEMOMAN",
+ "TF_WEAPON_GRENADE_NAPALM",
+ "TF_WEAPON_GRENADE_GAS",
+ "TF_WEAPON_GRENADE_EMP",
+ "TF_WEAPON_GRENADE_CALTROP",
+ "TF_WEAPON_GRENADE_PIPEBOMB",
+ "TF_WEAPON_GRENADE_SMOKE_BOMB",
+ "TF_WEAPON_GRENADE_HEAL",
+ "TF_WEAPON_GRENADE_STUNBALL",
+ "TF_WEAPON_GRENADE_JAR",
+ "TF_WEAPON_GRENADE_JAR_MILK",
+ "TF_WEAPON_PISTOL",
+ "TF_WEAPON_PISTOL_SCOUT",
+ "TF_WEAPON_REVOLVER",
+ "TF_WEAPON_NAILGUN",
+ "TF_WEAPON_PDA",
+ "TF_WEAPON_PDA_ENGINEER_BUILD",
+ "TF_WEAPON_PDA_ENGINEER_DESTROY",
+ "TF_WEAPON_PDA_SPY",
+ "TF_WEAPON_BUILDER",
+ "TF_WEAPON_MEDIGUN",
+ "TF_WEAPON_GRENADE_MIRVBOMB",
+ "TF_WEAPON_FLAMETHROWER_ROCKET",
+ "TF_WEAPON_GRENADE_DEMOMAN",
+ "TF_WEAPON_SENTRY_BULLET",
+ "TF_WEAPON_SENTRY_ROCKET",
+ "TF_WEAPON_DISPENSER",
+ "TF_WEAPON_INVIS",
+ "TF_WEAPON_FLAREGUN",
+ "TF_WEAPON_LUNCHBOX",
+ "TF_WEAPON_JAR",
+ "TF_WEAPON_COMPOUND_BOW",
+ "TF_WEAPON_BUFF_ITEM",
+ "TF_WEAPON_PUMPKIN_BOMB",
+ "TF_WEAPON_SWORD",
+ "TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT",
+ "TF_WEAPON_LIFELINE",
+ "TF_WEAPON_LASER_POINTER",
+ "TF_WEAPON_DISPENSER_GUN",
+ "TF_WEAPON_SENTRY_REVENGE",
+ "TF_WEAPON_JAR_MILK",
+ "TF_WEAPON_HANDGUN_SCOUT_PRIMARY",
+ "TF_WEAPON_BAT_FISH",
+ "TF_WEAPON_CROSSBOW",
+ "TF_WEAPON_STICKBOMB",
+ "TF_WEAPON_HANDGUN_SCOUT_SECONDARY",
+ "TF_WEAPON_SODA_POPPER",
+ "TF_WEAPON_SNIPERRIFLE_DECAP",
+ "TF_WEAPON_RAYGUN",
+ "TF_WEAPON_PARTICLE_CANNON",
+ "TF_WEAPON_MECHANICAL_ARM",
+ "TF_WEAPON_DRG_POMSON",
+ "TF_WEAPON_BAT_GIFTWRAP",
+ "TF_WEAPON_GRENADE_ORNAMENT_BALL",
+ "TF_WEAPON_FLAREGUN_REVENGE",
+ "TF_WEAPON_PEP_BRAWLER_BLASTER",
+ "TF_WEAPON_CLEAVER",
+ "TF_WEAPON_GRENADE_CLEAVER",
+ "TF_WEAPON_STICKY_BALL_LAUNCHER",
+ "TF_WEAPON_GRENADE_STICKY_BALL",
+ "TF_WEAPON_SHOTGUN_BUILDING_RESCUE",
+ "TF_WEAPON_CANNON",
+ "TF_WEAPON_THROWABLE",
+ "TF_WEAPON_GRENADE_THROWABLE",
+ "TF_WEAPON_PDA_SPY_BUILD",
+ "TF_WEAPON_GRENADE_WATERBALLOON",
+ "TF_WEAPON_HARVESTER_SAW",
+ "TF_WEAPON_SPELLBOOK",
+ "TF_WEAPON_SPELLBOOK_PROJECTILE",
+ "TF_WEAPON_SNIPERRIFLE_CLASSIC",
+ "TF_WEAPON_PARACHUTE",
+ "TF_WEAPON_GRAPPLINGHOOK",
+ "TF_WEAPON_PASSTIME_GUN",
+#ifdef STAGING_ONLY
+ "TF_WEAPON_SNIPERRIFLE_REVOLVER",
+#endif
+ "TF_WEAPON_CHARGED_SMG",
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_aWeaponNames ) == TF_WEAPON_COUNT );
+
+int g_aWeaponDamageTypes[] =
+{
+ DMG_GENERIC, // TF_WEAPON_NONE
+ DMG_CLUB, // TF_WEAPON_BAT,
+ DMG_CLUB, // TF_WEAPON_BAT_WOOD,
+ DMG_CLUB, // TF_WEAPON_BOTTLE,
+ DMG_CLUB, // TF_WEAPON_FIREAXE,
+ DMG_CLUB, // TF_WEAPON_CLUB,
+ DMG_CLUB, // TF_WEAPON_CROWBAR,
+ DMG_SLASH, // TF_WEAPON_KNIFE,
+ DMG_CLUB, // TF_WEAPON_FISTS,
+ DMG_CLUB, // TF_WEAPON_SHOVEL,
+ DMG_CLUB, // TF_WEAPON_WRENCH,
+ DMG_SLASH, // TF_WEAPON_BONESAW,
+ DMG_BUCKSHOT | DMG_USEDISTANCEMOD, // TF_WEAPON_SHOTGUN_PRIMARY,
+ DMG_BUCKSHOT | DMG_USEDISTANCEMOD, // TF_WEAPON_SHOTGUN_SOLDIER,
+ DMG_BUCKSHOT | DMG_USEDISTANCEMOD, // TF_WEAPON_SHOTGUN_HWG,
+ DMG_BUCKSHOT | DMG_USEDISTANCEMOD, // TF_WEAPON_SHOTGUN_PYRO,
+ DMG_BUCKSHOT | DMG_USEDISTANCEMOD, // TF_WEAPON_SCATTERGUN,
+ DMG_BULLET | DMG_USE_HITLOCATIONS, // TF_WEAPON_SNIPERRIFLE,
+ DMG_BULLET | DMG_USEDISTANCEMOD, // TF_WEAPON_MINIGUN,
+ DMG_BULLET | DMG_USEDISTANCEMOD, // TF_WEAPON_SMG,
+ DMG_BULLET | DMG_USEDISTANCEMOD | DMG_NOCLOSEDISTANCEMOD | DMG_PREVENT_PHYSICS_FORCE, // TF_WEAPON_SYRINGEGUN_MEDIC,
+ DMG_BULLET | DMG_USEDISTANCEMOD | DMG_PREVENT_PHYSICS_FORCE | DMG_PARALYZE, // TF_WEAPON_TRANQ,
+ DMG_BLAST | DMG_HALF_FALLOFF | DMG_USEDISTANCEMOD, // TF_WEAPON_ROCKETLAUNCHER,
+ DMG_BLAST | DMG_HALF_FALLOFF | DMG_USEDISTANCEMOD, // TF_WEAPON_GRENADELAUNCHER,
+ DMG_BLAST | DMG_HALF_FALLOFF | DMG_NOCLOSEDISTANCEMOD, // TF_WEAPON_PIPEBOMBLAUNCHER,
+ DMG_IGNITE | DMG_PREVENT_PHYSICS_FORCE | DMG_PREVENT_PHYSICS_FORCE, // TF_WEAPON_FLAMETHROWER,
+ DMG_BLAST | DMG_HALF_FALLOFF, // TF_WEAPON_GRENADE_NORMAL,
+ DMG_SONIC | DMG_HALF_FALLOFF, // TF_WEAPON_GRENADE_CONCUSSION,
+ DMG_BULLET | DMG_HALF_FALLOFF, // TF_WEAPON_GRENADE_NAIL,
+ DMG_BLAST | DMG_HALF_FALLOFF, // TF_WEAPON_GRENADE_MIRV,
+ DMG_BLAST | DMG_HALF_FALLOFF, // TF_WEAPON_GRENADE_MIRV_DEMOMAN,
+ DMG_BURN | DMG_RADIUS_MAX, // TF_WEAPON_GRENADE_NAPALM,
+ DMG_POISON | DMG_HALF_FALLOFF, // TF_WEAPON_GRENADE_GAS,
+ DMG_BLAST | DMG_HALF_FALLOFF | DMG_PREVENT_PHYSICS_FORCE, // TF_WEAPON_GRENADE_EMP,
+ DMG_GENERIC, // TF_WEAPON_GRENADE_CALTROP,
+ DMG_BLAST | DMG_HALF_FALLOFF | DMG_NOCLOSEDISTANCEMOD, // TF_WEAPON_GRENADE_PIPEBOMB,
+ DMG_GENERIC, // TF_WEAPON_GRENADE_SMOKE_BOMB,
+ DMG_GENERIC, // TF_WEAPON_GRENADE_HEAL
+ DMG_CLUB, // TF_WEAPON_GRENADE_STUNBALL
+ DMG_CLUB, // TF_WEAPON_GRENADE_JAR
+ DMG_CLUB, // TF_WEAPON_GRENADE_JAR_MILK
+ DMG_BULLET | DMG_USEDISTANCEMOD, // TF_WEAPON_PISTOL,
+ DMG_BULLET | DMG_USEDISTANCEMOD, // TF_WEAPON_PISTOL_SCOUT,
+ DMG_BULLET | DMG_USEDISTANCEMOD, // TF_WEAPON_REVOLVER,
+ DMG_BULLET | DMG_USEDISTANCEMOD | DMG_NOCLOSEDISTANCEMOD | DMG_PREVENT_PHYSICS_FORCE, // TF_WEAPON_NAILGUN,
+ DMG_BULLET, // TF_WEAPON_PDA,
+ DMG_BULLET, // TF_WEAPON_PDA_ENGINEER_BUILD,
+ DMG_BULLET, // TF_WEAPON_PDA_ENGINEER_DESTROY,
+ DMG_BULLET, // TF_WEAPON_PDA_SPY,
+ DMG_BULLET, // TF_WEAPON_BUILDER
+ DMG_BULLET, // TF_WEAPON_MEDIGUN
+ DMG_BLAST, // TF_WEAPON_GRENADE_MIRVBOMB
+ DMG_BLAST | DMG_IGNITE | DMG_RADIUS_MAX, // TF_WEAPON_FLAMETHROWER_ROCKET
+ DMG_BLAST | DMG_HALF_FALLOFF, // TF_WEAPON_GRENADE_DEMOMAN
+ DMG_BULLET, // TF_WEAPON_SENTRY_BULLET
+ DMG_BLAST, // TF_WEAPON_SENTRY_ROCKET
+ DMG_GENERIC, // TF_WEAPON_DISPENSER
+ DMG_GENERIC, // TF_WEAPON_INVIS
+ DMG_BULLET | DMG_IGNITE, // TF_WEAPON_FLAREGUN
+ DMG_GENERIC, // TF_WEAPON_LUNCHBOX
+ DMG_GENERIC, // TF_WEAPON_JAR
+ DMG_BULLET | DMG_USE_HITLOCATIONS, // TF_WEAPON_COMPOUND_BOW
+ DMG_GENERIC, // TF_WEAPON_BUFF_ITEM
+ DMG_CLUB, // TF_WEAPON_PUMPKIN_BOMB
+ DMG_CLUB, // TF_WEAPON_SWORD
+ DMG_BLAST | DMG_HALF_FALLOFF | DMG_USEDISTANCEMOD, // TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT,
+ DMG_CLUB, // TF_WEAPON_LIFELINE
+ DMG_CLUB, // TF_WEAPON_LASER_POINTER
+ DMG_BULLET, // TF_WEAPON_DISPENSER_GUN
+ DMG_BUCKSHOT | DMG_USEDISTANCEMOD, // TF_WEAPON_SENTRY_REVENGE
+ DMG_GENERIC, // TF_WEAPON_JAR_MILK
+ DMG_BUCKSHOT | DMG_BULLET | DMG_USEDISTANCEMOD, // TF_WEAPON_HANDGUN_SCOUT_PRIMARY
+ DMG_CLUB, // TF_WEAPON_BAT_FISH
+ DMG_BULLET | DMG_USE_HITLOCATIONS,
+ DMG_CLUB, // TF_WEAPON_STICKBOMB
+ DMG_BULLET | DMG_USEDISTANCEMOD, // TF_WEAPON_HANDGUN_SCOUT_SECONDARY
+ DMG_BUCKSHOT | DMG_USEDISTANCEMOD, // TF_WEAPON_SODA_POPPER,
+ DMG_BULLET | DMG_USE_HITLOCATIONS, // TF_WEAPON_SNIPERRIFLE_DECAP,
+ DMG_BULLET | DMG_USEDISTANCEMOD | DMG_NOCLOSEDISTANCEMOD, // TF_WEAPON_RAYGUN,
+ DMG_BLAST | DMG_HALF_FALLOFF | DMG_USEDISTANCEMOD, // TF_WEAPON_PARTICLE_CANNON,
+ DMG_BULLET | DMG_USEDISTANCEMOD, // TF_WEAPON_MECHANICAL_ARM,
+ DMG_BULLET | DMG_USEDISTANCEMOD | DMG_NOCLOSEDISTANCEMOD, // TF_WEAPON_DRG_POMSON,
+ DMG_CLUB, // TF_WEAPON_BAT_GIFTWRAP,
+ DMG_CLUB, // TF_WEAPON_GRENADE_ORNAMENT_BALL
+ DMG_BULLET | DMG_IGNITE, // TF_WEAPON_FLAREGUN_REVENGE,
+ DMG_BUCKSHOT | DMG_USEDISTANCEMOD, // TF_WEAPON_PEP_BRAWLER_BLASTER,
+ DMG_GENERIC, // TF_WEAPON_CLEAVER
+ DMG_SLASH, // TF_WEAPON_GRENADE_CLEAVER
+ DMG_GENERIC, // TF_WEAPON_STICKY_BALL_LAUNCHER,
+ DMG_GENERIC, // TF_WEAPON_GRENADE_STICKY_BALL,
+ DMG_BUCKSHOT | DMG_USEDISTANCEMOD, // TF_WEAPON_SHOTGUN_BUILDING_RESCUE,
+ DMG_BLAST | DMG_HALF_FALLOFF, // TF_WEAPON_CANNON
+ DMG_BULLET, // TF_WEAPON_THROWABLE
+ DMG_BULLET, // TF_WEAPON_GRENADE_THROWABLE
+ DMG_BULLET, // TF_WEAPON_PDA_SPY_BUILD
+ DMG_BULLET, // TF_WEAPON_GRENADE_WATERBALLOON
+ DMG_SLASH, // TF_WEAPON_HARVESTER_SAW
+ DMG_GENERIC, // TF_WEAPON_SPELLBOOK
+ DMG_GENERIC, // TF_WEAPON_SPELLBOOK_PROJECTILE
+ DMG_BULLET | DMG_USE_HITLOCATIONS, // TF_WEAPON_SNIPERRIFLE_CLASSIC,
+ DMG_GENERIC, // TF_WEAPON_PARACHUTE,
+ DMG_GENERIC, // TF_WEAPON_GRAPPLINGHOOK,
+ DMG_GENERIC, // TF_WEAPON_PASSTIME_GUN
+#ifdef STAGING_ONLY
+ DMG_BULLET | DMG_USE_HITLOCATIONS, // TF_WEAPON_SNIPERRIFLE_REVOLVER,
+#endif
+ DMG_BULLET | DMG_USEDISTANCEMOD, // TF_WEAPON_CHARGED_SMG,
+};
+
+const char *g_szSpecialDamageNames[] =
+{
+ "",
+ "TF_DMG_CUSTOM_HEADSHOT",
+ "TF_DMG_CUSTOM_BACKSTAB",
+ "TF_DMG_CUSTOM_BURNING",
+ "TF_DMG_WRENCH_FIX",
+ "TF_DMG_CUSTOM_MINIGUN",
+ "TF_DMG_CUSTOM_SUICIDE",
+ "TF_DMG_CUSTOM_TAUNTATK_HADOUKEN",
+ "TF_DMG_CUSTOM_BURNING_FLARE",
+ "TF_DMG_CUSTOM_TAUNTATK_HIGH_NOON",
+ "TF_DMG_CUSTOM_TAUNTATK_GRAND_SLAM",
+ "TF_DMG_CUSTOM_PENETRATE_MY_TEAM",
+ "TF_DMG_CUSTOM_PENETRATE_ALL_PLAYERS",
+ "TF_DMG_CUSTOM_TAUNTATK_FENCING",
+ "TF_DMG_CUSTOM_PENETRATE_NONBURNING_TEAMMATE",
+ "TF_DMG_CUSTOM_TAUNTATK_ARROW_STAB",
+ "TF_DMG_CUSTOM_TELEFRAG",
+ "TF_DMG_CUSTOM_BURNING_ARROW",
+ "TF_DMG_CUSTOM_FLYINGBURN",
+ "TF_DMG_CUSTOM_PUMPKIN_BOMB",
+ "TF_DMG_CUSTOM_DECAPITATION",
+ "TF_DMG_CUSTOM_TAUNTATK_GRENADE",
+ "TF_DMG_CUSTOM_BASEBALL",
+ "TF_DMG_CUSTOM_CHARGE_IMPACT",
+ "TF_DMG_CUSTOM_TAUNTATK_BARBARIAN_SWING",
+ "TF_DMG_CUSTOM_AIR_STICKY_BURST",
+ "TF_DMG_CUSTOM_DEFENSIVE_STICKY",
+ "TF_DMG_CUSTOM_PICKAXE",
+ "TF_DMG_CUSTOM_ROCKET_DIRECTHIT",
+ "TF_DMG_CUSTOM_TAUNTATK_UBERSLICE",
+ "TF_DMG_CUSTOM_PLAYER_SENTRY",
+ "TF_DMG_CUSTOM_STANDARD_STICKY",
+ "TF_DMG_CUSTOM_SHOTGUN_REVENGE_CRIT",
+ "TF_DMG_CUSTOM_TAUNTATK_ENGINEER_GUITAR_SMASH",
+ "TF_DMG_CUSTOM_BLEEDING",
+ "TF_DMG_CUSTOM_GOLD_WRENCH",
+ "TF_DMG_CUSTOM_CARRIED_BUILDING",
+ "TF_DMG_CUSTOM_COMBO_PUNCH",
+ "TF_DMG_CUSTOM_TAUNTATK_ENGINEER_ARM_KILL",
+ "TF_DMG_CUSTOM_FISH_KILL",
+ "TF_DMG_CUSTOM_TRIGGER_HURT",
+ "TF_DMG_CUSTOM_DECAPITATION_BOSS",
+ "TF_DMG_CUSTOM_STICKBOMB_EXPLOSION",
+ "TF_DMG_CUSTOM_AEGIS_ROUND",
+ "TF_DMG_CUSTOM_FLARE_EXPLOSION",
+ "TF_DMG_CUSTOM_BOOTS_STOMP",
+ "TF_DMG_CUSTOM_PLASMA",
+ "TF_DMG_CUSTOM_PLASMA_CHARGED",
+ "TF_DMG_CUSTOM_PLASMA_GIB",
+ "TF_DMG_CUSTOM_PRACTICE_STICKY",
+ "TF_DMG_CUSTOM_EYEBALL_ROCKET",
+ "TF_DMG_CUSTOM_HEADSHOT_DECAPITATION",
+ "TF_DMG_CUSTOM_TAUNTATK_ARMAGEDDON",
+ "TF_DMG_CUSTOM_FLARE_PELLET",
+ "TF_DMG_CUSTOM_CLEAVER",
+ "TF_DMG_CUSTOM_CLEAVER_CRIT",
+ "TF_DMG_CUSTOM_SAPPER_RECORDER_DEATH",
+ "TF_DMG_CUSTOM_MERASMUS_PLAYER_BOMB",
+ "TF_DMG_CUSTOM_MERASMUS_GRENADE",
+ "TF_DMG_CUSTOM_MERASMUS_ZAP",
+ "TF_DMG_CUSTOM_MERASMUS_DECAPITATION",
+ "TF_DMG_CUSTOM_CANNONBALL_PUSH",
+ "TF_DMG_CUSTOM_TAUNTATK_ALLCLASS_GUITAR_RIFF",
+ "TF_DMG_CUSTOM_THROWABLE",
+ "TF_DMG_CUSTOM_THROWABLE_KILL",
+ "TF_DMG_CUSTOM_SPELL_TELEPORT",
+ "TF_DMG_CUSTOM_SPELL_SKELETON",
+ "TF_DMG_CUSTOM_SPELL_MIRV",
+ "TF_DMG_CUSTOM_SPELL_METEOR",
+ "TF_DMG_CUSTOM_SPELL_LIGHTNING",
+ "TF_DMG_CUSTOM_SPELL_FIREBALL",
+ "TF_DMG_CUSTOM_SPELL_MONOCULUS",
+ "TF_DMG_CUSTOM_SPELL_BLASTJUMP",
+ "TF_DMG_CUSTOM_SPELL_BATS",
+ "TF_DMG_CUSTOM_SPELL_TINY",
+ "TF_DMG_CUSTOM_KART",
+ "TF_DMG_CUSTOM_GIANT_HAMMER",
+ "TF_DMG_CUSTOM_RUNE_REFLECT",
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_szSpecialDamageNames ) == TF_DMG_CUSTOM_END );
+
+const char *GetCustomDamageName( ETFDmgCustom eDmgCustom )
+{
+ if ( ( eDmgCustom >= ARRAYSIZE( g_szSpecialDamageNames ) ) || ( eDmgCustom < 0 ) )
+ return NULL;
+
+ return g_szSpecialDamageNames[eDmgCustom];
+}
+
+ETFDmgCustom GetCustomDamageFromName( const char *pszCustomDmgName )
+{
+ for( uint i=0; i<TF_DMG_CUSTOM_END; i++ )
+ {
+ ETFDmgCustom eDmgCustom = (ETFDmgCustom)i;
+ if ( !V_stricmp( GetCustomDamageName( eDmgCustom ), pszCustomDmgName ) )
+ return eDmgCustom;
+ }
+
+ Assert( !!"Invalid Custom Damage Name" );
+ return TF_DMG_CUSTOM_NONE;
+}
+
+const char *g_szProjectileNames[] =
+{
+ "",
+ "projectile_bullet",
+ "projectile_rocket",
+ "projectile_pipe",
+ "projectile_pipe_remote",
+ "projectile_syringe",
+ "projectile_flare",
+ "projectile_jar",
+ "projectile_arrow",
+ "projectile_flame_rocket",
+ "projectile_jar_milk",
+ "projectile_healing_bolt",
+ "projectile_energy_ball",
+ "projectile_energy_ring",
+ "projectile_pipe_remote_practice",
+ "projectile_cleaver",
+ "projectile_sticky_ball",
+ "projectile_cannonball",
+ "projectile_building_repair_bolt",
+ "projectile_festive_arrow",
+ "projectile_throwable",
+ "projectile_spellfireball",
+ "projectile_festive_urine",
+ "projectile_festive_healing_bolt",
+ "projectfile_breadmonster_jarate",
+ "projectfile_breadmonster_madmilk",
+
+ "projectile_grapplinghook",
+ "projectile_sentry_rocket",
+ "projectile_bread_monster",
+
+#ifdef STAGING_ONLY
+ // Staging
+ "projectile_tranq",
+ "projectile_sniperbullet",
+ "projectile_throwing_knife",
+ "projectile_grenade_concussion",
+ "projectile_grenade_teleport",
+ "projectile_jarate_bolt",
+#endif
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_szProjectileNames ) == TF_NUM_PROJECTILES );
+
+// these map to the projectiles named in g_szProjectileNames
+int g_iProjectileWeapons[] =
+{
+ TF_WEAPON_NONE,
+ TF_WEAPON_PISTOL,
+ TF_WEAPON_ROCKETLAUNCHER,
+ TF_WEAPON_PIPEBOMBLAUNCHER,
+ TF_WEAPON_GRENADELAUNCHER,
+ TF_WEAPON_SYRINGEGUN_MEDIC,
+ TF_WEAPON_FLAREGUN,
+ TF_WEAPON_JAR,
+ TF_WEAPON_COMPOUND_BOW,
+ TF_PROJECTILE_FLAME_ROCKET,
+ TF_WEAPON_JAR_MILK,
+ TF_WEAPON_CROSSBOW,
+ TF_WEAPON_PARTICLE_CANNON,
+ TF_WEAPON_RAYGUN,
+ TF_WEAPON_GRENADELAUNCHER, // practice pipes should never kill anyone anyway
+ TF_WEAPON_CLEAVER,
+ TF_WEAPON_STICKY_BALL_LAUNCHER,
+ TF_WEAPON_CANNON,
+ TF_WEAPON_SHOTGUN_BUILDING_RESCUE,
+ TF_WEAPON_COMPOUND_BOW,
+ TF_WEAPON_THROWABLE,
+ TF_WEAPON_SPELLBOOK,
+ TF_WEAPON_JAR,
+ TF_WEAPON_CROSSBOW,
+ TF_WEAPON_JAR,
+ TF_WEAPON_JAR,
+
+ TF_PROJECTILE_GRAPPLINGHOOK,
+ TF_WEAPON_SENTRY_ROCKET,
+ TF_WEAPON_THROWABLE,
+
+#ifdef STAGING_ONLY
+ // Staging
+ TF_WEAPON_REVOLVER,
+ TF_WEAPON_SNIPERRIFLE,
+ TF_WEAPON_THROWABLE,
+ TF_WEAPON_THROWABLE,
+ TF_WEAPON_THROWABLE,
+ TF_WEAPON_CROSSBOW,
+#endif
+};
+
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_szProjectileNames ) == ARRAYSIZE( g_iProjectileWeapons ) );
+
+//-----------------------------------------------------------------------------
+// Taunt attacks
+//-----------------------------------------------------------------------------
+static const char* taunt_attack_name[] =
+{
+ "TAUNTATK_NONE",
+ "TAUNTATK_PYRO_HADOUKEN",
+ "TAUNTATK_HEAVY_EAT",
+ "TAUNTATK_HEAVY_RADIAL_BUFF",
+ "TAUNTATK_HEAVY_HIGH_NOON",
+ "TAUNTATK_SCOUT_DRINK",
+ "TAUNTATK_SCOUT_GRAND_SLAM",
+ "TAUNTATK_MEDIC_INHALE",
+ "TAUNTATK_SPY_FENCING_SLASH_A",
+ "TAUNTATK_SPY_FENCING_SLASH_B",
+ "TAUNTATK_SPY_FENCING_STAB",
+ "TAUNTATK_RPS_KILL",
+ "TAUNTATK_SNIPER_ARROW_STAB_IMPALE",
+ "TAUNTATK_SNIPER_ARROW_STAB_KILL",
+ "TAUNTATK_SOLDIER_GRENADE_KILL",
+ "TAUNTATK_DEMOMAN_BARBARIAN_SWING",
+ "TAUNTATK_MEDIC_UBERSLICE_IMPALE",
+ "TAUNTATK_MEDIC_UBERSLICE_KILL",
+ "TAUNTATK_FLIP_LAND_PARTICLE",
+ "TAUNTATK_RPS_PARTICLE",
+ "TAUNTATK_HIGHFIVE_PARTICLE",
+ "TAUNTATK_ENGINEER_GUITAR_SMASH",
+ "TAUNTATK_ENGINEER_ARM_IMPALE",
+ "TAUNTATK_ENGINEER_ARM_KILL",
+ "TAUNTATK_ENGINEER_ARM_BLEND",
+ "TAUNTATK_SOLDIER_GRENADE_KILL_WORMSIGN",
+ "TAUNTATK_SHOW_ITEM",
+ "TAUNTATK_MEDIC_RELEASE_DOVES",
+ "TAUNTATK_PYRO_ARMAGEDDON",
+ "TAUNTATK_PYRO_SCORCHSHOT",
+ "TAUNTATK_ALLCLASS_GUITAR_RIFF",
+ "TAUNTATK_MEDIC_HEROIC_TAUNT",
+
+ //
+ // INSERT NEW ITEMS HERE TO AVOID BREAKING DEMOS
+ //
+};
+
+COMPILE_TIME_ASSERT( ARRAYSIZE( taunt_attack_name ) == TAUNTATK_COUNT );
+
+taunt_attack_t GetTauntAttackByName( const char* pszTauntAttackName )
+{
+ if ( pszTauntAttackName )
+ {
+ for ( int i=0; i<ARRAYSIZE( taunt_attack_name ); ++i )
+ {
+ if ( !V_stricmp( pszTauntAttackName, taunt_attack_name[i] ) )
+ {
+ return (taunt_attack_t)i;
+ }
+ }
+ }
+
+ return TAUNTATK_NONE;
+}
+
+const char *g_pszHintMessages[] =
+{
+ "#Hint_spotted_a_friend",
+ "#Hint_spotted_an_enemy",
+ "#Hint_killing_enemies_is_good",
+ "#Hint_out_of_ammo",
+ "#Hint_turn_off_hints",
+ "#Hint_pickup_ammo",
+ "#Hint_Cannot_Teleport_With_Flag",
+ "#Hint_Cannot_Cloak_With_Flag",
+ "#Hint_Cannot_Disguise_With_Flag",
+ "#Hint_Cannot_Attack_While_Feign_Armed",
+ "#Hint_ClassMenu",
+
+// Grenades
+ "#Hint_gren_caltrops",
+ "#Hint_gren_concussion",
+ "#Hint_gren_emp",
+ "#Hint_gren_gas",
+ "#Hint_gren_mirv",
+ "#Hint_gren_nail",
+ "#Hint_gren_napalm",
+ "#Hint_gren_normal",
+
+// Altfires
+ "#Hint_altfire_sniperrifle",
+ "#Hint_altfire_flamethrower",
+ "#Hint_altfire_grenadelauncher",
+ "#Hint_altfire_pipebomblauncher",
+ "#Hint_altfire_rotate_building",
+
+// Soldier
+ "#Hint_Soldier_rpg_reload",
+
+// Engineer
+ "#Hint_Engineer_use_wrench_onown",
+ "#Hint_Engineer_use_wrench_onother",
+ "#Hint_Engineer_use_wrench_onfriend",
+ "#Hint_Engineer_build_sentrygun",
+ "#Hint_Engineer_build_dispenser",
+ "#Hint_Engineer_build_teleporters",
+ "#Hint_Engineer_pickup_metal",
+ "#Hint_Engineer_repair_object",
+ "#Hint_Engineer_metal_to_upgrade",
+ "#Hint_Engineer_upgrade_sentrygun",
+
+ "#Hint_object_has_sapper",
+
+ "#Hint_object_your_object_sapped",
+ "#Hint_enemy_using_dispenser",
+ "#Hint_enemy_using_tp_entrance",
+ "#Hint_enemy_using_tp_exit",
+
+ "#Hint_Cannot_Phase_With_Flag",
+
+ "#Hint_Cannot_Attack_While_Cloaked",
+
+ "#Hint_Cannot_Arm_Feign_Now",
+};
+
+const char *g_pszArrowModels[] =
+{
+ "models/weapons/w_models/w_arrow.mdl",
+ "models/weapons/w_models/w_repair_claw.mdl",
+ "models/weapons/w_models/w_baseball.mdl",
+ "models/weapons/w_models/w_arrow_xmas.mdl",
+ "models/weapons/w_models/w_syringe_proj.mdl",
+#ifdef STAGING_ONLY
+ "models/workshop/weapons/c_models/c_crusaders_crossbow/c_crusaders_crossbow_xmas_proj.mdl",
+#else
+ "models/weapons/c_models/c_crusaders_crossbow/c_crusaders_crossbow_xmas_proj.mdl",
+#endif
+ "models/weapons/w_models/w_breadmonster/w_breadmonster.mdl",
+ "models/weapons/c_models/c_grapple_proj/c_grapple_proj.mdl",
+
+#ifdef STAGING_ONLY
+ "models/workshop_partner/weapons/c_models/c_sd_cleaver/c_sd_cleaver.mdl"
+#else
+ "models/weapons/c_models/c_sd_cleaver/c_sd_cleaver.mdl"
+#endif
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszArrowModels ) == TF_ARROW_MODEL_COUNT );
+
+const char *g_pszCampaignMedalIcons[] =
+{
+ "",
+ // Gun Mettle Campaign
+ "../hud/coin_summer2015_gravel",
+ "../hud/coin_summer2015_bronze",
+ "../hud/coin_summer2015_silver",
+ "../hud/coin_summer2015_gold",
+
+ // Invasion Community Update
+ "../HUD/scoreboard_invasion",
+
+ // Halloween
+ "../HUD/coin_halloween2015_gravel",
+ "../HUD/coin_halloween2015_bronze",
+ "../HUD/coin_halloween2015_silver",
+ "../HUD/coin_halloween2015_gold",
+
+ // Tough Break Campaign
+ "../HUD/stamp_winter2016_gravel1",
+ "../HUD/stamp_winter2016_bronze1",
+ "../HUD/stamp_winter2016_silver1",
+ "../HUD/stamp_winter2016_gold1",
+
+ "../HUD/stamp_winter2016_gravel2",
+ "../HUD/stamp_winter2016_bronze2",
+ "../HUD/stamp_winter2016_silver2",
+ "../HUD/stamp_winter2016_gold2",
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszCampaignMedalIcons ) == CAMPAIGN_MEDAL_DISPLAY_TYPE_COUNT );
+
+//-----------------------------------------------------------------------------
+// Dead Calling Cards
+const char *g_pszDeathCallingCardModels[] =
+{
+ "", // Empty at zero
+ "models/props_gameplay/tombstone_specialdelivery.mdl", // Scout PolyCount Set
+ "models/props_gameplay/tombstone_crocostyle.mdl", // Sniper PolyCount Set
+ "models/props_gameplay/tombstone_tankbuster.mdl", // Solider PolyCount Set
+ "models/props_gameplay/tombstone_gasjockey.mdl", // Pyro PolyCount Set
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int GetWeaponId( const char *pszWeaponName )
+{
+ // if this doesn't match, you need to add missing weapons to the array
+ COMPILE_TIME_ASSERT( TF_WEAPON_COUNT == ARRAYSIZE( g_aWeaponNames ) );
+
+ for ( int iWeapon = 0; iWeapon < ARRAYSIZE( g_aWeaponNames ); ++iWeapon )
+ {
+ if ( !Q_stricmp( pszWeaponName, g_aWeaponNames[iWeapon] ) )
+ return iWeapon;
+ }
+
+ return TF_WEAPON_NONE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *WeaponIdToAlias( int iWeapon )
+{
+ // if this doesn't match, you need to add missing weapons to the array
+ COMPILE_TIME_ASSERT( TF_WEAPON_COUNT == ARRAYSIZE( g_aWeaponNames ) );
+
+ if ( ( iWeapon >= ARRAYSIZE( g_aWeaponNames ) ) || ( iWeapon < 0 ) )
+ return NULL;
+
+ return g_aWeaponNames[iWeapon];
+}
+
+#ifdef GAME_DLL
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int GetWeaponFromDamage( const CTakeDamageInfo &info )
+{
+ int iWeapon = TF_WEAPON_NONE;
+
+ const char *killer_weapon_name = "";
+
+ // Find the killer & the scorer
+ CBaseEntity *pInflictor = info.GetInflictor();
+ CBaseEntity *pKiller = info.GetAttacker();
+ CBasePlayer *pScorer = TFGameRules()->GetDeathScorer( pKiller, pInflictor, NULL );
+
+ // find the weapon the killer used
+
+ if ( pScorer ) // Is the killer a client?
+ {
+ if ( pInflictor )
+ {
+ if ( pInflictor == pScorer )
+ {
+ // If the inflictor is the killer, then it must be their current weapon doing the damage
+ if ( pScorer->GetActiveWeapon() )
+ {
+ killer_weapon_name = pScorer->GetActiveWeapon()->GetClassname();
+ }
+ }
+ else
+ {
+ killer_weapon_name = STRING( pInflictor->m_iClassname ); // it's just that easy
+ }
+ }
+ }
+ else if ( pInflictor )
+ {
+ killer_weapon_name = STRING( pInflictor->m_iClassname );
+ }
+
+ if ( !Q_strnicmp( killer_weapon_name, "tf_projectile", 13 ) )
+ {
+ for( int i = 0; i < ARRAYSIZE( g_szProjectileNames ); i++ )
+ {
+ if ( !Q_stricmp( &killer_weapon_name[ 3 ], g_szProjectileNames[ i ] ) )
+ {
+ iWeapon = g_iProjectileWeapons[ i ];
+ break;
+ }
+ }
+ }
+ else
+ {
+ int iLen = Q_strlen( killer_weapon_name );
+
+ // strip off _projectile from projectiles shot from other projectiles
+ if ( ( iLen < 256 ) && ( iLen > 11 ) && !Q_stricmp( &killer_weapon_name[ iLen - 11 ], "_projectile" ) )
+ {
+ char temp[ 256 ];
+ V_strcpy_safe( temp, killer_weapon_name );
+ temp[ iLen - 11 ] = 0;
+
+ // set the weapon used
+ iWeapon = GetWeaponId( temp );
+ }
+ else
+ {
+ // set the weapon used
+ iWeapon = GetWeaponId( killer_weapon_name );
+ }
+ }
+
+ AssertMsg( iWeapon >= 0 && iWeapon < TF_WEAPON_COUNT, "Referencing a weapon not in tf_shareddefs.h. Check to make it's defined and it's mapped correctly in g_szProjectileNames and g_iProjectileWeapons." );
+ return iWeapon;
+}
+
+#endif
+
+// ------------------------------------------------------------------------------------------------ //
+// CObjectInfo tables.
+// ------------------------------------------------------------------------------------------------ //
+
+CObjectInfo::CObjectInfo( const char *pObjectName )
+{
+ m_pObjectName = pObjectName;
+ m_pClassName = NULL;
+ m_flBuildTime = -9999;
+ m_nMaxObjects = -9999;
+ m_Cost = -9999;
+ m_CostMultiplierPerInstance = -999;
+ m_flUpgradeDuration = -999;
+ m_UpgradeCost = -9999;
+ m_MaxUpgradeLevel = -9999;
+ m_pBuilderWeaponName = NULL;
+ m_pBuilderPlacementString = NULL;
+ m_SelectionSlot = -9999;
+ m_SelectionPosition = -9999;
+ m_bSolidToPlayerMovement = false;
+ m_pIconActive = NULL;
+ m_pIconInactive = NULL;
+ m_pIconMenu = NULL;
+ m_pViewModel = NULL;
+ m_pPlayerModel = NULL;
+ m_iDisplayPriority = 0;
+ m_bVisibleInWeaponSelection = true;
+ m_pExplodeSound = NULL;
+ m_pUpgradeSound = NULL;
+ m_pExplosionParticleEffect = NULL;
+ m_bAutoSwitchTo = false;
+ m_iBuildCount = 0;
+ m_iNumAltModes = 0;
+ m_bRequiresOwnBuilder = false;
+}
+
+
+CObjectInfo::~CObjectInfo()
+{
+ delete [] m_pClassName;
+ delete [] m_pStatusName;
+ delete [] m_pBuilderWeaponName;
+ delete [] m_pBuilderPlacementString;
+ delete [] m_pIconActive;
+ delete [] m_pIconInactive;
+ delete [] m_pIconMenu;
+ delete [] m_pViewModel;
+ delete [] m_pPlayerModel;
+ delete [] m_pExplodeSound;
+ delete [] m_pUpgradeSound;
+ delete [] m_pExplosionParticleEffect;
+}
+
+CObjectInfo g_ObjectInfos[OBJ_LAST] =
+{
+ CObjectInfo( "OBJ_DISPENSER" ),
+ CObjectInfo( "OBJ_TELEPORTER" ),
+ CObjectInfo( "OBJ_SENTRYGUN" ),
+ CObjectInfo( "OBJ_ATTACHMENT_SAPPER" ),
+#ifdef STAGING_ONLY
+ CObjectInfo( "OBJ_CATAPULT" ),
+ CObjectInfo( "OBJ_SPY_TRAP" ),
+#endif
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_ObjectInfos ) == OBJ_LAST );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int GetBuildableId( const char *pszBuildableName )
+{
+ for ( int iBuildable = 0; iBuildable < OBJ_LAST; ++iBuildable )
+ {
+ if ( !Q_stricmp( pszBuildableName, g_ObjectInfos[iBuildable].m_pObjectName ) )
+ return iBuildable;
+ }
+
+ return OBJ_LAST;
+}
+
+bool AreObjectInfosLoaded()
+{
+ return g_ObjectInfos[0].m_pClassName != NULL;
+}
+
+static void SpewFileInfo( IBaseFileSystem *pFileSystem, const char *resourceName, const char *pathID, KeyValues *pValues )
+{
+ bool bFileExists = pFileSystem->FileExists( resourceName, pathID );
+ bool bFileWritable = pFileSystem->IsFileWritable( resourceName, pathID );
+ unsigned int nSize = pFileSystem->Size( resourceName, pathID );
+
+ Msg( "resourceName:%s pathID:%s bFileExists:%d size:%u writeable:%d\n", resourceName, pathID, bFileExists, nSize, bFileWritable );
+
+ unsigned int filesize = ( unsigned int )-1;
+ FileHandle_t f = filesystem->Open( resourceName, "rb", pathID );
+ if ( f )
+ {
+ filesize = filesystem->Size( f );
+ filesystem->Close( f );
+ }
+
+ Msg( " FileHandle_t:%p size:%u\n", f, filesize );
+
+ IFileSystem *pFS = (IFileSystem *)filesystem;
+
+ char cwd[ MAX_PATH ];
+ cwd[ 0 ] = 0;
+ pFS->GetCurrentDirectory( cwd, ARRAYSIZE( cwd ) );
+
+ bool bAvailable = pFS->IsFileImmediatelyAvailable( resourceName );
+
+ Msg( " IsFileImmediatelyAvailable:%d cwd:%s\n", bAvailable, cwd );
+
+ pFS->PrintSearchPaths();
+
+ if ( pValues )
+ {
+ Msg( "Keys:" );
+ KeyValuesDumpAsDevMsg( pValues, 2, 0 );
+ }
+}
+
+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" ) )
+ {
+ // Getting "Can't open scripts/objects.txt for object info." errors. Spew file information
+ // before the Error() call which should show up in the minidumps.
+ SpewFileInfo( pFileSystem, pFilename, "GAME", NULL );
+
+ 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 )
+ {
+ // Getting "Missing section 'OBJ_DISPENSER' from scripts/objects.txt" errors.
+ SpewFileInfo( pFileSystem, pFilename, "GAME", pValues );
+
+ // It seems that folks have corrupt files when these errors are seen in http://minidump.
+ // Does it make sense to call the below Steam API so it'll force a validation next startup time?
+ // Need to verify it's real corruption and not someone dorking around with their objects.txt file...
+ //
+ // From Martin Otten: If you have a file on disc and you�re 100% sure it�s
+ // corrupt, call ISteamApps::MarkContentCorrupt( false ), before you shutdown
+ // the game. This will cause a content validation in Steam.
+
+ 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_flUpgradeDuration = pSub->GetFloat( "UpgradeDuration", -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_iBuildCount = pSub->GetInt( "BuildCount", -999 )) == -999 ||
+ (pInfo->m_SelectionPosition = pSub->GetInt( "SelectionPosition", -999 )) == -999 )
+ {
+ SpewFileInfo( pFileSystem, pFilename, "GAME", pValues );
+
+ 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, "IconActive", pFilename );
+ pInfo->m_pIconInactive = ReadAndAllocStringValue( pSub, "IconInactive", pFilename );
+ pInfo->m_pIconMenu = ReadAndAllocStringValue( pSub, "IconMenu", pFilename );
+ pInfo->m_bUseItemInfo = ( pSub->GetInt( "UseItemInfo", 0 ) > 0 );
+ pInfo->m_pViewModel = ReadAndAllocStringValue( pSub, "Viewmodel", pFilename );
+ pInfo->m_pPlayerModel = ReadAndAllocStringValue( pSub, "Playermodel", pFilename );
+ pInfo->m_iDisplayPriority = pSub->GetInt( "DisplayPriority", 0 );
+ pInfo->m_pHudStatusIcon = ReadAndAllocStringValue( pSub, "HudStatusIcon", pFilename );
+ pInfo->m_bVisibleInWeaponSelection = ( pSub->GetInt( "VisibleInWeaponSelection", 1 ) > 0 );
+ pInfo->m_pExplodeSound = ReadAndAllocStringValue( pSub, "ExplodeSound", pFilename );
+ pInfo->m_pUpgradeSound = ReadAndAllocStringValue( pSub, "UpgradeSound", pFilename );
+ pInfo->m_pExplosionParticleEffect = ReadAndAllocStringValue( pSub, "ExplodeEffect", pFilename );
+ pInfo->m_bAutoSwitchTo = ( pSub->GetInt( "autoswitchto", 0 ) > 0 );
+ pInfo->m_iMetalToDropInGibs = pSub->GetInt( "MetalToDropInGibs", 0 );
+ pInfo->m_bRequiresOwnBuilder = pSub->GetBool( "RequiresOwnBuilder", 0 );
+
+ // Read the other alternate object modes.
+ KeyValues *pAltModesKey = pSub->FindKey( "AltModes" );
+ if ( pAltModesKey )
+ {
+ int iIndex = 0;
+ while ( iIndex<OBJECT_MAX_MODES )
+ {
+ char buf[256];
+ Q_snprintf( buf, sizeof(buf), "AltMode%d", iIndex );
+ KeyValues *pCurrentModeKey = pAltModesKey->FindKey( buf );
+ if ( !pCurrentModeKey )
+ break;
+
+ pInfo->m_AltModes[iIndex].pszStatusName = ReadAndAllocStringValue( pCurrentModeKey, "StatusName", pFilename );
+ pInfo->m_AltModes[iIndex].pszModeName = ReadAndAllocStringValue( pCurrentModeKey, "ModeName", pFilename );
+ pInfo->m_AltModes[iIndex].pszIconMenu = ReadAndAllocStringValue( pCurrentModeKey, "IconMenu", pFilename );
+
+ iIndex++;
+ }
+ pInfo->m_iNumAltModes = iIndex-1;
+ }
+
+ // Alternate mode 0 always matches the defaults.
+ pInfo->m_AltModes[0].pszStatusName = pInfo->m_pStatusName;
+ pInfo->m_AltModes[0].pszIconMenu = pInfo->m_pIconMenu;
+ }
+
+ pValues->deleteThis();
+}
+
+
+const CObjectInfo* GetObjectInfo( int iObject )
+{
+ Assert( iObject >= 0 && iObject < OBJ_LAST );
+ Assert( AreObjectInfosLoaded() );
+ return &g_ObjectInfos[iObject];
+}
+
+ConVar tf_cheapobjects( "tf_cheapobjects","0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Set to 1 and all objects will cost 0" );
+
+//-----------------------------------------------------------------------------
+// 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
+//
+// Note: Used to contain logic from tf2 that multiple instances of the same object
+// cost different amounts. See tf2/game_shared/tf_shareddefs.cpp for details
+//-----------------------------------------------------------------------------
+int InternalCalculateObjectCost( int iObjectType )
+{
+ if ( tf_cheapobjects.GetInt() )
+ {
+ return 0;
+ }
+
+ int iCost = GetObjectInfo( iObjectType )->m_Cost;
+
+ 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;
+}
+
+//-----------------------------------------------------------------------------
+// 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;
+ */
+
+ return ( iClass == TF_CLASS_ENGINEER );
+}
+
+const unsigned char *GetTFEncryptionKey( void )
+{
+ return (unsigned char *)"E2NcUkG2";
+}
+
+//-----------------------------------------------------------------------------
+// Per-class weapon entity translations
+//-----------------------------------------------------------------------------
+struct wpntranslation_class_weapons_t
+{
+ const char *pszWpnString;
+ const char *pszClassWpn[TF_LAST_NORMAL_CLASS];
+};
+
+wpntranslation_class_weapons_t pszWpnEntTranslationList[] =
+{
+ {
+ "tf_weapon_shotgun",
+ {
+ "", // TF_CLASS_UNDEFINED = 0,
+ "", // TF_CLASS_SCOUT,
+ "", // TF_CLASS_SNIPER,
+ "tf_weapon_shotgun_soldier",// TF_CLASS_SOLDIER,
+ "", // TF_CLASS_DEMOMAN,
+ "", // TF_CLASS_MEDIC,
+ "tf_weapon_shotgun_hwg", // TF_CLASS_HEAVYWEAPONS,
+ "tf_weapon_shotgun_pyro", // TF_CLASS_PYRO,
+ "", // TF_CLASS_SPY,
+ "tf_weapon_shotgun_primary",// TF_CLASS_ENGINEER,
+ }
+ },
+
+ {
+ "tf_weapon_pistol",
+ {
+ "", // TF_CLASS_UNDEFINED = 0,
+ "tf_weapon_pistol_scout", // TF_CLASS_SCOUT,
+ "", // TF_CLASS_SNIPER,
+ "", // TF_CLASS_SOLDIER,
+ "", // TF_CLASS_DEMOMAN,
+ "", // TF_CLASS_MEDIC,
+ "", // TF_CLASS_HEAVYWEAPONS,
+ "", // TF_CLASS_PYRO,
+ "", // TF_CLASS_SPY,
+ "tf_weapon_pistol", // TF_CLASS_ENGINEER,
+ }
+ },
+
+ {
+ "tf_weapon_shovel",
+ {
+ "", // TF_CLASS_UNDEFINED = 0,
+ "", // TF_CLASS_SCOUT,
+ "", // TF_CLASS_SNIPER,
+ "tf_weapon_shovel", // TF_CLASS_SOLDIER,
+ "tf_weapon_bottle", // TF_CLASS_DEMOMAN,
+ "", // TF_CLASS_MEDIC,
+ "", // TF_CLASS_HEAVYWEAPONS,
+ "", // TF_CLASS_PYRO,
+ "", // TF_CLASS_SPY,
+ "", // TF_CLASS_ENGINEER,
+ }
+ },
+ {
+ "tf_weapon_bottle",
+ {
+ "", // TF_CLASS_UNDEFINED = 0,
+ "", // TF_CLASS_SCOUT,
+ "", // TF_CLASS_SNIPER,
+ "tf_weapon_shovel", // TF_CLASS_SOLDIER,
+ "tf_weapon_bottle", // TF_CLASS_DEMOMAN,
+ "", // TF_CLASS_MEDIC,
+ "", // TF_CLASS_HEAVYWEAPONS,
+ "", // TF_CLASS_PYRO,
+ "", // TF_CLASS_SPY,
+ "", // TF_CLASS_ENGINEER,
+ }
+ },
+ {
+ "saxxy",
+ {
+ "", // TF_CLASS_UNDEFINED = 0,
+ "tf_weapon_bat", // TF_CLASS_SCOUT,
+ "tf_weapon_club", // TF_CLASS_SNIPER,
+ "tf_weapon_shovel", // TF_CLASS_SOLDIER,
+ "tf_weapon_bottle", // TF_CLASS_DEMOMAN,
+ "tf_weapon_bonesaw", // TF_CLASS_MEDIC,
+ "tf_weapon_fireaxe", // TF_CLASS_HEAVYWEAPONS, HWG uses a fireaxe because he doesn't have a default melee weapon of his own; also I am a terrible person
+ "tf_weapon_fireaxe", // TF_CLASS_PYRO,
+ "tf_weapon_knife", // TF_CLASS_SPY,
+ "tf_weapon_wrench", // TF_CLASS_ENGINEER,
+ }
+ },
+ {
+ "tf_weapon_throwable",
+ {
+ "", // TF_CLASS_UNDEFINED = 0,
+ "tf_weapon_throwable_secondary", // TF_CLASS_SCOUT,
+ "tf_weapon_throwable_secondary", // TF_CLASS_SNIPER,
+ "tf_weapon_throwable_secondary", // TF_CLASS_SOLDIER,
+ "tf_weapon_throwable_secondary", // TF_CLASS_DEMOMAN,
+ "tf_weapon_throwable_primary", // TF_CLASS_MEDIC,
+ "tf_weapon_throwable_secondary", // TF_CLASS_HEAVYWEAPONS
+ "tf_weapon_throwable_secondary", // TF_CLASS_PYRO,
+ "tf_weapon_throwable_secondary", // TF_CLASS_SPY,
+ "tf_weapon_throwable_secondary", // TF_CLASS_ENGINEER,
+ }
+ },
+ {
+ "tf_weapon_parachute",
+ {
+ "", // TF_CLASS_UNDEFINED = 0,
+ "", // TF_CLASS_SCOUT,
+ "", // TF_CLASS_SNIPER,
+ "tf_weapon_parachute_secondary", // TF_CLASS_SOLDIER,
+ "tf_weapon_parachute_primary", // TF_CLASS_DEMOMAN,
+ "", // TF_CLASS_MEDIC,
+ "", // TF_CLASS_HEAVYWEAPONS
+ "", // TF_CLASS_PYRO,
+ "" // TF_CLASS_SPY,
+ "", // TF_CLASS_ENGINEER,
+ }
+ },
+ {
+ "tf_weapon_revolver",
+ {
+ "", // TF_CLASS_UNDEFINED = 0,
+ "", // TF_CLASS_SCOUT,
+ "", // TF_CLASS_SNIPER,
+ "", // TF_CLASS_SOLDIER,
+ "", // TF_CLASS_DEMOMAN,
+ "", // TF_CLASS_MEDIC,
+ "", // TF_CLASS_HEAVYWEAPONS
+ "", // TF_CLASS_PYRO,
+ "tf_weapon_revolver", // TF_CLASS_SPY,
+ "tf_weapon_revolver_secondary", // TF_CLASS_ENGINEER,
+ }
+ },
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: We need to support players putting any shotgun into a shotgun slot, pistol into a pistol slot, etc.
+// For legacy reasons, different classes actually spawn different entities for their shotguns/pistols/etc.
+// To deal with this, we translate entities into the right one for the class we're playing.
+//-----------------------------------------------------------------------------
+const char *TranslateWeaponEntForClass( const char *pszName, int iClass )
+{
+ if ( pszName )
+ {
+ for ( int i = 0; i < ARRAYSIZE(pszWpnEntTranslationList); i++ )
+ {
+ if ( !Q_stricmp( pszName, pszWpnEntTranslationList[i].pszWpnString ) )
+ {
+ const char *pTransName = pszWpnEntTranslationList[i].pszClassWpn[ iClass ];
+ Assert( pTransName && pTransName[0] );
+ return pTransName;
+ }
+ }
+ }
+
+ return pszName;
+}
+
+//-----------------------------------------------------------------------------
+// Helltower Announcer lines for Redmond and Blutarch
+//-----------------------------------------------------------------------------
+helltower_vo_t g_pszHelltowerAnnouncerLines[] =
+{
+// EACH MISC PAIR SHOULD HAVE THE SAME NUMBER OF LINES
+ { "Announcer.Helltower_Red_Misc%02u", 16 },
+ { "Announcer.Helltower_Blue_Misc%02u", 16 },
+
+ { "Announcer.Helltower_Red_Misc_Rare%02u", 21 },
+ { "Announcer.Helltower_Blue_Misc_Rare%02u", 21 },
+
+// THESE PAIRS CAN HAVE DIFFERENT COUNTS
+ { "Announcer.Helltower_Red_Winning%02u", 12 },
+ { "Announcer.Helltower_Blue_Winning%02u", 13 },
+
+ { "Announcer.Helltower_Red_Winning_Rare%02u", 12 },
+ { "Announcer.Helltower_Blue_Winning_Rare%02u", 8 },
+
+ { "Announcer.Helltower_Red_Losing%02u", 15 },
+ { "Announcer.Helltower_Blue_Losing%02u", 16 },
+
+ { "Announcer.Helltower_Red_Losing_Rare%02u", 6 },
+ { "Announcer.Helltower_Blue_Losing_Rare%02u", 5 },
+
+ { "Announcer.Helltower_Red_Win%02u", 7 },
+ { "Announcer.Helltower_Blue_Win%02u", 7 },
+
+ { "Announcer.Helltower_Red_Win_Rare%02u", 1 },
+ { "Announcer.Helltower_Blue_Win_Rare%02u", 3 },
+
+ { "Announcer.Helltower_Red_Lose%02u", 7 },
+ { "Announcer.Helltower_Blue_Lose%02u", 7 },
+
+ { "Announcer.Helltower_Red_Lose_Rare%02u", 1 },
+ { "Announcer.Helltower_Blue_Lose_Rare%02u", 1 },
+
+ { "Announcer.Helltower_Red_RoundStart%02u", 4 },
+ { "Announcer.Helltower_Blue_RoundStart%02u", 2 },
+
+ { "Announcer.Helltower_Red_RoundStart_Rare%02u", 4 },
+ { "Announcer.Helltower_Blue_RoundStart_Rare%02u", 2 },
+
+ { "Announcer.Helltower_Red_Skeleton_King%02u", 4 },
+ { "Announcer.Helltower_Blue_Skeleton_King%02u", 4 },
+
+ { "Announcer.Helltower_Red_Almost_Win%02u", 1 },
+ { "Announcer.Helltower_Blue_Almost_Win%02u", 1 },
+
+ { "Announcer.Helltower_Red_Almost_Lose%02u", 1 },
+ { "Announcer.Helltower_Blue_Almost_Lose%02u", 1 },
+
+};
+
+#ifdef TF_CLIENT_DLL
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+const char *g_pszInvasionMaps[] =
+{
+ "maps/ctf_2fort_invasion.bsp",
+ "maps/koth_probed.bsp",
+ "maps/arena_byre.bsp",
+ "maps/pd_watergate.bsp"
+};
+
+bool IsPlayingInvasionMap( void )
+{
+ const char *pszCurrentMap = engine->GetLevelName();
+
+ for ( int i = 0; i < ARRAYSIZE( g_pszInvasionMaps ); i++ )
+ {
+ if ( FStrEq( g_pszInvasionMaps[i], pszCurrentMap ) )
+ return true;
+ }
+
+ return false;
+}
+
+const char *g_pszClassIcons[SCOREBOARD_CLASS_ICONS] =
+{
+ "",
+ "../hud/leaderboard_class_scout",
+ "../hud/leaderboard_class_sniper",
+ "../hud/leaderboard_class_soldier",
+ "../hud/leaderboard_class_demo",
+ "../hud/leaderboard_class_medic",
+ "../hud/leaderboard_class_heavy",
+ "../hud/leaderboard_class_pyro",
+ "../hud/leaderboard_class_spy",
+ "../hud/leaderboard_class_engineer",
+ "../hud/leaderboard_class_scout_d",
+ "../hud/leaderboard_class_sniper_d",
+ "../hud/leaderboard_class_soldier_d",
+ "../hud/leaderboard_class_demo_d",
+ "../hud/leaderboard_class_medic_d",
+ "../hud/leaderboard_class_heavy_d",
+ "../hud/leaderboard_class_pyro_d",
+ "../hud/leaderboard_class_spy_d",
+ "../hud/leaderboard_class_engineer_d",
+};
+
+const char *g_pszClassIconsAlt[SCOREBOARD_CLASS_ICONS] =
+{
+ "",
+ "class_icons/class_icon_orange_scout",
+ "class_icons/class_icon_orange_sniper",
+ "class_icons/class_icon_orange_soldier",
+ "class_icons/class_icon_orange_demo",
+ "class_icons/class_icon_orange_medic",
+ "class_icons/class_icon_orange_heavy",
+ "class_icons/class_icon_orange_pyro",
+ "class_icons/class_icon_orange_spy",
+ "class_icons/class_icon_orange_engineer",
+ "class_icons/class_icon_orange_scout_d",
+ "class_icons/class_icon_orange_sniper_d",
+ "class_icons/class_icon_orange_soldier_d",
+ "class_icons/class_icon_orange_demo_d",
+ "class_icons/class_icon_orange_medic_d",
+ "class_icons/class_icon_orange_heavy_d",
+ "class_icons/class_icon_orange_pyro_d",
+ "class_icons/class_icon_orange_spy_d",
+ "class_icons/class_icon_orange_engineer_d",
+};
+
+const char *g_pszItemClassImagesRed[] =
+{
+ "class_portraits/all_class", // TF_CLASS_UNDEFINED = 0,
+ "class_portraits/scout", // TF_CLASS_SCOUT,
+ "class_portraits/sniper", // TF_CLASS_SNIPER,
+ "class_portraits/soldier", // TF_CLASS_SOLDIER,
+ "class_portraits/demoman", // TF_CLASS_DEMOMAN,
+ "class_portraits/medic", // TF_CLASS_MEDIC,
+ "class_portraits/heavy", // TF_CLASS_HEAVYWEAPONS,
+ "class_portraits/pyro", // TF_CLASS_PYRO,
+ "class_portraits/spy", // TF_CLASS_SPY,
+ "class_portraits/engineer", // TF_CLASS_ENGINEER,
+ "class_portraits/scout_grey", // TF_CLASS_SCOUT,
+ "class_portraits/sniper_grey", // TF_CLASS_SNIPER,
+ "class_portraits/soldier_grey", // TF_CLASS_SOLDIER,
+ "class_portraits/demoman_grey", // TF_CLASS_DEMOMAN,
+ "class_portraits/medic_grey", // TF_CLASS_MEDIC,
+ "class_portraits/heavy_grey", // TF_CLASS_HEAVYWEAPONS,
+ "class_portraits/pyro_grey", // TF_CLASS_PYRO,
+ "class_portraits/spy_grey", // TF_CLASS_SPY,
+ "class_portraits/engineer_grey", // TF_CLASS_ENGINEER,
+};
+
+const char *g_pszItemClassImagesBlue[] =
+{
+ "class_portraits/all_class", // TF_CLASS_UNDEFINED = 0,
+ "class_portraits/scout_blue", // TF_CLASS_SCOUT,
+ "class_portraits/sniper_blue", // TF_CLASS_SNIPER,
+ "class_portraits/soldier_blue", // TF_CLASS_SOLDIER,
+ "class_portraits/demoman_blue", // TF_CLASS_DEMOMAN,
+ "class_portraits/medic_blue", // TF_CLASS_MEDIC,
+ "class_portraits/heavy_blue", // TF_CLASS_HEAVYWEAPONS,
+ "class_portraits/pyro_blue", // TF_CLASS_PYRO,
+ "class_portraits/spy_blue", // TF_CLASS_SPY,
+ "class_portraits/engineer_blue", // TF_CLASS_ENGINEER,
+ "class_portraits/scout_blue_grey", // TF_CLASS_SCOUT,
+ "class_portraits/sniper_blue_grey", // TF_CLASS_SNIPER,
+ "class_portraits/soldier_blue_grey", // TF_CLASS_SOLDIER,
+ "class_portraits/demoman_blue_grey", // TF_CLASS_DEMOMAN,
+ "class_portraits/medic_blue_grey", // TF_CLASS_MEDIC,
+ "class_portraits/heavy_blue_grey", // TF_CLASS_HEAVYWEAPONS,
+ "class_portraits/pyro_blue_grey", // TF_CLASS_PYRO,
+ "class_portraits/spy_blue_grey", // TF_CLASS_SPY,
+ "class_portraits/engineer_blue_grey", // TF_CLASS_ENGINEER,
+};
+
+const char *g_pszCompetitiveMedalImages[] =
+{
+ "",
+ "competitive/competitive_coin_bronze",
+ "competitive/competitive_coin_silver",
+ "competitive/competitive_coin_gold",
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszCompetitiveMedalImages ) == StatMedal_Max );
+
+#endif // TF_CLIENT_DLL
+
+
+// rune icons for each team
+static const char *s_pszRuneIcons[2][RUNE_TYPES_MAX] =
+{
+ // RED TEAM
+ {
+ "powerup_icon_strength_red",
+ "powerup_icon_haste_red",
+ "powerup_icon_regen_red",
+ "powerup_icon_resist_red",
+ "powerup_icon_vampire_red",
+ "powerup_icon_reflect_red",
+ "powerup_icon_precision_red",
+ "powerup_icon_agility_red",
+ "powerup_icon_knockout_red",
+ "powerup_icon_king_red",
+ "powerup_icon_plague_red",
+ "powerup_icon_supernova_red",
+ },
+ // BLUE TEAM
+ {
+ "powerup_icon_strength_blue",
+ "powerup_icon_haste_blue",
+ "powerup_icon_regen_blue",
+ "powerup_icon_resist_blue",
+ "powerup_icon_vampire_blue",
+ "powerup_icon_reflect_blue",
+ "powerup_icon_precision_blue",
+ "powerup_icon_agility_blue",
+ "powerup_icon_knockout_blue",
+ "powerup_icon_king_blue",
+ "powerup_icon_plague_blue",
+ "powerup_icon_supernova_blue",
+ }
+};
+COMPILE_TIME_ASSERT( ARRAYSIZE( s_pszRuneIcons[0] ) == RUNE_TYPES_MAX );
+COMPILE_TIME_ASSERT( ARRAYSIZE( s_pszRuneIcons[1] ) == RUNE_TYPES_MAX );
+
+const char *GetPowerupIconName( RuneTypes_t type, int iTeam )
+{
+ int iTeamIndex = iTeam == TF_TEAM_RED ? 0 : 1;
+ if ( type != RUNE_NONE && type < RUNE_TYPES_MAX )
+ {
+ return s_pszRuneIcons[ iTeamIndex ][ type ];
+ }
+
+ return NULL;
+}