diff options
Diffstat (limited to 'game/shared/tf/tf_shareddefs.cpp')
| -rw-r--r-- | game/shared/tf/tf_shareddefs.cpp | 2011 |
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; +} |