Files
2025-02-19 18:36:16 -05:00

702 lines
25 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Contains an interface to log some events to the Steam Share
// timeline via ISteamTimeline
//
//===========================================================================//
#include "cbase.h"
#include "shareddefs.h"
#include "view.h"
#include "steamshare.h"
#include <vgui/ILocalize.h>
#include <tier1/fmtstr.h>
#include "basecombatweapon_shared.h"
#include "ammodef.h"
#include "c_ai_basenpc.h"
#if !defined( _X360 ) && !defined( NO_STEAM )
#include "steam/isteamtimeline.h"
#include "steam/steam_api.h"
#endif
#if defined ( TF_CLIENT_DLL )
#include "tf_gamerules.h"
#include "passtime_game_events.h"
#include "c_playerresource.h"
#endif // TF_CLIENT_DLL
#define TIMELINE_NO_PRIORITY 50
#define TIMELINE_LOW_PRIORITY 75
#define TIMELINE_MED_PRIORITY 100
#define TIMELINE_HIGH_PRIORITY 125
bool ShouldHaveLocalPlayerPickupTimelineEvents();
extern vgui::ILocalize *g_pVGuiLocalize;
static const char *GetLocalizedTitleString( const char *pszToken, const char *pszArg1 = NULL )
{
wchar_t wszLocalizedArg1[256];
const wchar_t *pwszLocalizedArg1 = nullptr;
if ( pszArg1 )
{
pwszLocalizedArg1 = g_pVGuiLocalize->Find( pszArg1 );
if ( !pwszLocalizedArg1 )
{
g_pVGuiLocalize->ConvertANSIToUnicode( pszArg1, wszLocalizedArg1, sizeof( wszLocalizedArg1 ) );
pwszLocalizedArg1 = wszLocalizedArg1;
}
}
wchar_t wszLocalizedString[ 256 ];
const wchar_t *pwszLocalizedString = nullptr;
if ( pwszLocalizedArg1 )
{
const wchar_t *pwszLocalizedToken = nullptr;
pwszLocalizedToken = g_pVGuiLocalize->Find( pszToken );
if ( !pwszLocalizedToken )
return pszToken;
g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), pwszLocalizedToken, 1, pwszLocalizedArg1 );
pwszLocalizedString = wszLocalizedString;
}
else
{
pwszLocalizedString = g_pVGuiLocalize->Find( pszToken );
if ( !pwszLocalizedString )
return pszToken;
}
static char szTitleString[ 256 ];
g_pVGuiLocalize->ConvertUnicodeToANSI( pwszLocalizedString, szTitleString, sizeof( szTitleString ) );
return szTitleString;
}
#if defined ( TF_CLIENT_DLL )
static const char *GetTimelineClassImage( int nTeam, int nClass )
{
const char *pszReturnImage = nullptr;
switch( nClass )
{
case TF_CLASS_SCOUT:
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? "scout_blu" : "scout_red";
break;
case TF_CLASS_SNIPER:
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? "sniper_blu" : "sniper_red";
break;
case TF_CLASS_SOLDIER:
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? "soldier_blu" : "soldier_red";
break;
case TF_CLASS_DEMOMAN:
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? "demoman_blu" : "demoman_red";
break;
case TF_CLASS_MEDIC:
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? "medic_blu" : "medic_red";
break;
case TF_CLASS_HEAVYWEAPONS:
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? "heavy_blu" : "heavy_red";
break;
case TF_CLASS_PYRO:
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? "pyro_blu" : "pyro_red";
break;
case TF_CLASS_SPY:
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? "spy_blu" : "spy_red";
break;
case TF_CLASS_ENGINEER:
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? "engineer_blu" : "engineer_red";
break;
default:
break;
}
return pszReturnImage;
}
static const char *GetTimelineObjectImage( int nObjType, int nObjMode, int nTeam, bool bDestroyed )
{
const char *pszReturnImage = nullptr;
switch ( nObjType )
{
case OBJ_DISPENSER:
{
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? ( bDestroyed ? "dispenser_blu_destroyed" : "dispenser_blu" ) : ( bDestroyed ? "dispenser_red_destroyed" : "dispenser_red" );
break;
}
case OBJ_TELEPORTER:
{
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? ( bDestroyed ? "teleporter_blu_destroyed" : ( nObjMode == MODE_TELEPORTER_ENTRANCE ) ? "teleporter_blu_in" : "teleporter_blu_out" ) : ( bDestroyed ? "teleporter_red_destroyed" : ( nObjMode == MODE_TELEPORTER_ENTRANCE ) ? "teleporter_red_in" : "teleporter_red_out" );
break;
}
case OBJ_SENTRYGUN:
{
pszReturnImage = ( nTeam == TF_TEAM_BLUE ) ? ( bDestroyed ? "sentry_blu_destroyed" : "sentry_blu" ) : ( bDestroyed ? "sentry_red_destroyed" : "sentry_red" );
break;
}
default:
{
break;
}
}
return pszReturnImage;
}
#endif // TF_CLIENT_DLL
//-----------------------------------------------------------------------------
// Singleton
//-----------------------------------------------------------------------------
static CSteamShareSystem g_SteamShareSystem;
IGameSystem *SteamShareSystem()
{
return &g_SteamShareSystem;
}
#if defined( TF_CLIENT_DLL ) || defined( HL2MP ) || defined( CSTRIKE_DLL ) || defined( DOD_DLL ) || defined( HL1MP_DLL )
#define STEAMSHARE_MULTIPLAYER 1
#endif
bool CSteamShareSystem::Init()
{
#if !defined( NO_STEAM )
// if we don't have the version of ISteamTimeline we need, don't bother listening for any events
// and just stub out this whole system.
if ( !steamapicontext || !SteamTimeline() )
return true;
ListenForGameEvent( "gameui_activate" );
ListenForGameEvent( "gameui_hide" );
ListenForGameEvent( "server_spawn" );
#if defined( TF_CLIENT_DLL )
ListenForGameEvent( "localplayer_builtobject" );
ListenForGameEvent( "object_destroyed" );
ListenForGameEvent( "object_detonated" );
ListenForGameEvent( "teamplay_flag_event" );
ListenForGameEvent( "teamplay_point_captured" );
ListenForGameEvent( PasstimeGameEvents::Score::s_eventName );
ListenForGameEvent( PasstimeGameEvents::BallGet::s_eventName );
ListenForGameEvent( PasstimeGameEvents::PassCaught::s_eventName );
ListenForGameEvent( PasstimeGameEvents::BallFree::s_eventName );
ListenForGameEvent( "killed_ball_carrier" );
ListenForGameEvent( "localplayer_changeteam" );
ListenForGameEvent( "localplayer_changeclass" );
ListenForGameEvent( "player_death" );
#elif defined ( STEAMSHARE_MULTIPLAYER )
ListenForGameEvent( "player_death" );
ListenForGameEvent( "weapon_equipped" );
#else
ListenForGameEvent( "single_player_death" );
ListenForGameEvent( "weapon_equipped" );
ListenForGameEvent( "entity_killed" );
#endif // !TF_CLIENT_DLL
SteamTimeline()->SetTimelineGameMode( k_ETimelineGameMode_Menus );
#endif // !NO_STEAM
return true;
}
void CSteamShareSystem::FireGameEvent( IGameEvent *event )
{
#if !defined( NO_STEAM )
if ( !V_stricmp( event->GetName(), "gameui_activate" ) )
{
SteamTimeline()->SetTimelineGameMode( k_ETimelineGameMode_Menus );
}
else if ( !V_stricmp( event->GetName(), "gameui_hide" ) )
{
SteamTimeline()->SetTimelineGameMode( k_ETimelineGameMode_Playing );
}
else if ( !V_stricmp( event->GetName(), "server_spawn" ) )
{
#if defined( STEAMSHARE_MULTIPLAYER )
const char *pszMapName = event->GetString( "mapname" );
if ( pszMapName )
{
#ifdef TF_CLIENT_DLL
pszMapName = GetMapDisplayName( pszMapName );
#endif
SteamTimeline()->SetTimelineStateDescription( pszMapName, 0 );
}
#else // defined( STEAMSHARE_MULTIPLAYER )
char buf[ 1024 ];
engine->GetChapterName( buf, sizeof( buf ) );
TrimRight( buf ); // why are chapter names left padded?
const char *pszText = nullptr;
if ( !V_isempty( buf ) )
{
pszText = g_pVGuiLocalize->FindAsUTF8( buf );
}
else
{
pszText = event->GetString( "mapname" );
}
if ( !V_isempty( pszText ) )
{
char buf2[ 1024 ];
if ( pszText[ 0 ] == '"' )
{
// If the map name is in quotes like "A RED LETTER DAY", lose the
// quotes before we had this off to Steam.
int len = V_strlen( pszText );
V_strncpy( buf2, pszText + 1, len - 2 );
}
else
{
V_strcpy_safe( buf2, pszText );
}
// TODO(joe): This is a terrible idea and will mess up UTF-8 text something fierce.
// But we only care about English for our Steam Share testing, and the
// all uppercase localized names look terrible there, so...
V_strtitlecase( buf2 );
SteamTimeline()->SetTimelineStateDescription( buf2, 0 );
}
#endif // !TF_CLIENT_DLL
}
#if defined( TF_CLIENT_DLL )
else if ( !V_stricmp( event->GetName(), "localplayer_changeteam" ) )
{
const char *pszTeam = "#TF_Spectators";
const char *pszIcon = "spectator";
if ( GetLocalPlayerTeam() == TF_TEAM_BLUE )
{
pszTeam = "#TF_BlueTeam_Name";
pszIcon = "team_blu";
}
else if ( GetLocalPlayerTeam() == TF_TEAM_RED )
{
pszTeam = "#TF_RedTeam_Name";
pszIcon = "team_red";
}
const char *pszTitle = GetLocalizedTitleString( "#TF_Timeline_ChangeTeam", pszTeam );
SteamTimeline()->AddTimelineEvent( pszIcon, pszTitle, "", TIMELINE_HIGH_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
else if ( !V_stricmp( event->GetName(), "localplayer_changeclass" ) )
{
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
if ( pLocalPlayer && pLocalPlayer->GetPlayerClass() )
{
int iClass = pLocalPlayer->GetPlayerClass()->GetClassIndex();
const char *pszIcon = GetTimelineClassImage( GetLocalPlayerTeam(), iClass );
if ( pszIcon )
{
const char *pszTitle = GetLocalizedTitleString( "#TF_Timeline_ChangeClass", g_aPlayerClassNames[ iClass ] );
SteamTimeline()->AddTimelineEvent( pszIcon, pszTitle, "", TIMELINE_HIGH_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
}
else if ( !V_stricmp( event->GetName(), "localplayer_builtobject" ) )
{
int nObjType = event->GetInt( "object" );
int nObjMode = event->GetInt( "object_mode" ); // teleporter entrance vs. exit
int nObjTeam = GetLocalPlayerTeam();
const char *pszIcon = GetTimelineObjectImage( nObjType, nObjMode, nObjTeam, false );
if ( pszIcon )
{
const char *pszTitle = GetLocalizedTitleString( "#TF_Timeline_ObjectBuiltGeneric" );
C_BaseEntity *pEntity = ClientEntityList().GetBaseEntity( event->GetInt( "index" ) );
if ( pEntity && pEntity->IsBaseObject() )
{
C_BaseObject *pObj = assert_cast<C_BaseObject *>( pEntity );
pszTitle = GetLocalizedTitleString( "#TF_Timeline_ObjectBuilt", pObj->GetStatusName() );
}
SteamTimeline()->AddTimelineEvent( pszIcon, pszTitle, "", TIMELINE_NO_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
else if ( !V_stricmp( event->GetName(), "object_destroyed" ) )
{
int nLocalPlayer = GetLocalPlayerIndex();
int nKillerID = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
int nOwnerID = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
int nAssisterID = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
if ( nKillerID == nLocalPlayer || nOwnerID == nLocalPlayer || nAssisterID == nLocalPlayer )
{
int nObjType = event->GetInt( "objecttype" );
int nObjTeam = event->GetInt( "team" );
const char *pszIcon = GetTimelineObjectImage( nObjType, -1, nObjTeam, true );
if ( pszIcon )
{
const char *pszTitle = "#TF_Timeline_ObjectDestroyedGeneric";
C_BaseEntity *pObject = ClientEntityList().GetBaseEntity( event->GetInt( "index" ) );
if ( pObject && pObject->IsBaseObject() )
{
C_BaseObject *pObj = assert_cast<C_BaseObject *>( pObject );
const char *pszTempTitle = "#TF_Timeline_ObjectDestroyed";
if ( nOwnerID == nLocalPlayer )
{
pszTempTitle = "#TF_Timeline_ObjectDestroyedYours";
}
pszTitle = GetLocalizedTitleString( pszTempTitle, pObj->GetStatusName() );
}
SteamTimeline()->AddTimelineEvent( pszIcon, pszTitle, "", TIMELINE_NO_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
}
else if ( !V_stricmp( event->GetName(), "object_detonated" ) )
{
int nLocalPlayer = GetLocalPlayerIndex();
int nOwnerID = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
if ( nOwnerID == nLocalPlayer )
{
int nObjType = event->GetInt( "objecttype" );
const char *pszIcon = GetTimelineObjectImage( nObjType, -1, GetLocalPlayerTeam(), true );
if ( pszIcon )
{
const char *pszTitle = GetLocalizedTitleString( "#TF_Timeline_ObjectDectonatedGeneric" );
C_BaseEntity *pKiller = ClientEntityList().GetBaseEntity( event->GetInt( "index" ) );
if ( pKiller && pKiller->IsBaseObject() )
{
C_BaseObject *pObj = assert_cast<C_BaseObject *>( pKiller );
pszTitle = GetLocalizedTitleString( "#TF_Timeline_ObjectDectonated", pObj->GetStatusName() );
}
SteamTimeline()->AddTimelineEvent( pszIcon, pszTitle, "", TIMELINE_NO_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
}
else if ( !V_stricmp( event->GetName(), "teamplay_flag_event" ) )
{
int nLocalPlayer = GetLocalPlayerIndex();
int nPlayer = event->GetInt( "player" );
int nEventType = event->GetInt( "eventtype" );
int nFlagTeam = event->GetInt( "team" );
if ( nPlayer == nLocalPlayer )
{
const char *pszIcon = nullptr;
const char *pszTempTitle = nullptr;
if ( nEventType == TF_FLAGEVENT_CAPTURE )
{
if ( nFlagTeam == TEAM_UNASSIGNED )
{
// kill notification says the enemy flag was captured
nFlagTeam = ( GetLocalPlayerTeam() == TF_TEAM_BLUE ) ? TF_TEAM_RED : TF_TEAM_BLUE;
}
pszIcon = ( nFlagTeam == TF_TEAM_BLUE ) ? "briefcase_blu" : "briefcase_red";
pszTempTitle = "#TF_Timeline_IntelCaptured";
}
else if ( nEventType == TF_FLAGEVENT_PICKUP )
{
pszIcon = ( nFlagTeam == TEAM_UNASSIGNED ) ? "briefcase" : ( nFlagTeam == TF_TEAM_BLUE ) ? "briefcase_blu" : "briefcase_red";
pszTempTitle = "#TF_Timeline_IntelPickedUp";
}
else if ( nEventType == TF_FLAGEVENT_DEFEND )
{
if ( nFlagTeam == TEAM_UNASSIGNED )
{
// kill notification says the enemy flag was defended
nFlagTeam = ( GetLocalPlayerTeam() == TF_TEAM_BLUE ) ? TF_TEAM_RED : TF_TEAM_BLUE;
}
pszIcon = ( nFlagTeam == TF_TEAM_BLUE ) ? "briefcase_blu_destroyed" : "briefcase_red_destroyed";
pszTempTitle = "#TF_Timeline_IntelCarrier";
}
else if ( nEventType == TF_FLAGEVENT_DROPPED )
{
if ( nFlagTeam == TEAM_UNASSIGNED )
{
// kill notification says the enemy flag was dropped
nFlagTeam = ( GetLocalPlayerTeam() == TF_TEAM_BLUE ) ? TF_TEAM_RED : TF_TEAM_BLUE;
}
pszIcon = ( nFlagTeam == TF_TEAM_BLUE ) ? "briefcase_blu_destroyed" : "briefcase_red_destroyed";
pszTempTitle = "#TF_Timeline_IntelDropped";
}
if ( pszIcon && pszTempTitle )
{
const char *pszTitle = GetLocalizedTitleString( pszTempTitle );
SteamTimeline()->AddTimelineEvent( pszIcon, pszTitle, "", TIMELINE_LOW_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
}
else if ( !V_stricmp( event->GetName(), "teamplay_point_captured" ) )
{
int nLocalPlayer = GetLocalPlayerIndex();
const char *szCappers = event->GetString( "cappers" );
int nTeam = event->GetInt( "team" );
int nNumCappers = Q_strlen( szCappers );
if ( nNumCappers > 0 )
{
for ( int i = 0; i < nNumCappers; i++ )
{
int nPlayerID = szCappers[ i ];
Assert( nPlayerID != '\0' && nPlayerID > 0 && nPlayerID <= MAX_PLAYERS );
if ( nPlayerID == nLocalPlayer )
{
if ( TFGameRules() )
{
const char *pszTitle = GetLocalizedTitleString( "#TF_Timeline_CPCaptured" );
if ( TFGameRules()->GetGameType() == TF_GAMETYPE_CP )
{
SteamTimeline()->AddTimelineEvent( ( nTeam == TF_TEAM_BLUE ) ? "control_point_blu" : "control_point_red", pszTitle, "", TIMELINE_LOW_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
else if ( TFGameRules()->GetGameType() == TF_GAMETYPE_ESCORT )
{
SteamTimeline()->AddTimelineEvent( ( nTeam == TF_TEAM_BLUE ) ? "payload_blu" : "payload_red", pszTitle, "", TIMELINE_LOW_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
break;
}
}
}
}
}
else if ( FStrEq( PasstimeGameEvents::Score::s_eventName, event->GetName() ) )
{
PasstimeGameEvents::Score ev( event );
int nLocalPlayer = GetLocalPlayerIndex();
int nScorer = ev.scorerIndex;
int nAssister = ev.assisterIndex;
if ( nScorer == nLocalPlayer || nAssister == nLocalPlayer )
{
const char *pszTitle = GetLocalizedTitleString( "#TF_Timeline_JackScore" );
SteamTimeline()->AddTimelineEvent( ( GetLocalPlayerTeam() == TF_TEAM_BLUE ) ? "passtime_blu" : "passtime_red", pszTitle, "", TIMELINE_LOW_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
else if ( FStrEq( PasstimeGameEvents::BallGet::s_eventName, event->GetName() ) )
{
PasstimeGameEvents::BallGet ev( event );
int nLocalPlayer = GetLocalPlayerIndex();
int nOwner = ev.ownerIndex;
int nTeam = ev.team;
if ( nOwner == nLocalPlayer )
{
const char *pszTitle = GetLocalizedTitleString( "#TF_Timeline_JackPickedUp" );
SteamTimeline()->AddTimelineEvent( ( nTeam == TEAM_UNASSIGNED ) ? "passtime" : ( nTeam == TF_TEAM_BLUE ) ? "passtime_blu" : "passtime_red", pszTitle, "", TIMELINE_LOW_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
else if ( FStrEq( PasstimeGameEvents::PassCaught::s_eventName, event->GetName() ) )
{
PasstimeGameEvents::PassCaught ev( event );
if ( g_PR )
{
int nLocalPlayer = GetLocalPlayerIndex();
int nCatcher = ev.catcherIndex;
int nCatcherTeam = g_PR->GetTeam( nCatcher );
int nPasserTeam = g_PR->GetTeam( ev.passerIndex );
if ( nCatcher == nLocalPlayer )
{
const char *pszTitle = nullptr;
if ( nPasserTeam == nCatcherTeam )
{
pszTitle = GetLocalizedTitleString( "#TF_Timeline_JackPass" );
}
else
{
pszTitle = GetLocalizedTitleString( "#TF_Timeline_JackIntercepted" );
}
SteamTimeline()->AddTimelineEvent( ( nCatcherTeam == TF_TEAM_BLUE ) ? "passtime_blu" : "passtime_red", pszTitle, "", TIMELINE_LOW_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
}
else if ( FStrEq( PasstimeGameEvents::BallFree::s_eventName, event->GetName() ) )
{
PasstimeGameEvents::BallFree ev( event );
int nLocalPlayer = GetLocalPlayerIndex();
int nOwner = ev.ownerIndex;
if ( nOwner == nLocalPlayer )
{
const char *pszTitle = GetLocalizedTitleString( "#TF_Timeline_JackLost" );
SteamTimeline()->AddTimelineEvent( ( GetLocalPlayerTeam() == TF_TEAM_BLUE ) ? "passtime_blu_destroyed" : "passtime_red_destroyed", pszTitle, "", TIMELINE_LOW_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
else if ( !V_stricmp( event->GetName(), "killed_ball_carrier" ) )
{
int nLocalPlayer = GetLocalPlayerIndex();
int nAttacker = event->GetInt( "attacker" );
int nAssister = event->GetInt( "assister" );
if ( nAttacker == nLocalPlayer || nAssister == nLocalPlayer )
{
const char *pszTitle = GetLocalizedTitleString( "#TF_Timeline_JackCarrier" );
SteamTimeline()->AddTimelineEvent( ( GetLocalPlayerTeam() == TF_TEAM_BLUE ) ? "passtime_red_destroyed" : "passtime_blu_destroyed", pszTitle, "", TIMELINE_LOW_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
#endif
#if defined( TF_CLIENT_DLL )
else if ( !V_stricmp( event->GetName(), "player_death" ) )
{
int nLocalPlayer = GetLocalPlayerIndex();
int nAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
int nAssister = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
int nVictim = event->GetInt( "victim_entindex" );
if ( ( nAttacker == nLocalPlayer || nAssister == nLocalPlayer ) && ( nVictim != nLocalPlayer ) )
{
C_TFPlayer *pVictim = ToTFPlayer( ClientEntityList().GetEnt( nVictim ) );
if ( pVictim && pVictim->GetPlayerClass() )
{
int iVictimClassIndex = pVictim->GetPlayerClass()->GetClassIndex();
const char *pszIcon = GetTimelineClassImage( pVictim->GetTeamNumber(), iVictimClassIndex );
if ( pszIcon )
{
const char *pszTitle = GetLocalizedTitleString( ( iVictimClassIndex == TF_CLASS_ENGINEER ) ? "#TF_Timeline_KilledEngy" : "#TF_Timeline_Killed", g_aPlayerClassNames[ iVictimClassIndex ] );
SteamTimeline()->AddTimelineEvent( pszIcon, pszTitle, "", TIMELINE_NO_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
}
else if ( nVictim == nLocalPlayer )
{
const char *pszTitle = "";
C_TFPlayer *pAttacker = ToTFPlayer( ClientEntityList().GetEnt( nAttacker ) );
if ( pAttacker && pAttacker->GetPlayerClass() )
{
int iAttackerClassIndex = pAttacker->GetPlayerClass()->GetClassIndex();
const char *pszTempTitle = ( iAttackerClassIndex == TF_CLASS_ENGINEER ) ? "#TF_Timeline_WereKilledEngy" : "#TF_Timeline_WereKilled";
if ( nAttacker == nLocalPlayer )
{
pszTempTitle = "#TF_Timeline_Suicide";
}
pszTitle = GetLocalizedTitleString( pszTempTitle, g_aPlayerClassNames[ iAttackerClassIndex ] );
}
else if ( nAttacker == 0 ) // world
{
pszTitle = GetLocalizedTitleString( "#TF_Timeline_Suicide" );
}
SteamTimeline()->AddTimelineEvent( "death", pszTitle, "", TIMELINE_MED_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Standard );
}
}
#elif defined ( STEAMSHARE_MULTIPLAYER )
else if ( !V_stricmp( event->GetName(), "player_death" ) )
{
int nLocalPlayer = GetLocalPlayerIndex();
int nAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
int nAssister = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
int nVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
if ( ( nAttacker == nLocalPlayer || nAssister == nLocalPlayer ) && ( nVictim != nLocalPlayer ) )
{
C_BasePlayer *pVictim = ToBasePlayer( ClientEntityList().GetEnt( nVictim ) );
if ( pVictim )
{
const char *pszTitle = GetLocalizedTitleString( "#Valve_Timeline_Killed", pVictim->GetPlayerName() );
SteamTimeline()->AddTimelineEvent( "steam_attack", pszTitle, "", TIMELINE_LOW_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Featured );
}
}
else if ( nVictim == nLocalPlayer )
{
const char *pszTitle = "";
C_BasePlayer *pAttacker = ToBasePlayer( ClientEntityList().GetEnt( nAttacker ) );
if ( pAttacker )
{
const char *pszTempTitle = "#Valve_Timeline_WereKilled";
if ( nAttacker == nLocalPlayer )
{
pszTempTitle = "#Valve_Timeline_Suicide";
}
pszTitle = GetLocalizedTitleString( pszTempTitle, pAttacker->GetPlayerName() );
}
else if ( nAttacker == 0 ) // world
{
pszTitle = GetLocalizedTitleString( "#Valve_Timeline_Suicide" );
}
SteamTimeline()->AddTimelineEvent( "steam_death", pszTitle, "", TIMELINE_MED_PRIORITY, 0.f, 0.f, k_ETimelineEventClipPriority_Featured );
}
}
else if ( !V_stricmp( event->GetName(), "weapon_equipped" ) )
{
int nWeaponEntindex = event->GetInt( "entindex" );
int nOwnerEntIndex = event->GetInt( "owner_entindex" );
C_BaseCombatWeapon* pWeapon = dynamic_cast<C_BaseCombatWeapon *>( ClientEntityList().GetEnt( nWeaponEntindex ) );
C_BasePlayer* pOwner = dynamic_cast<C_BasePlayer *>( ClientEntityList().GetEnt( nOwnerEntIndex ) );
if ( pWeapon && pOwner && pOwner == C_BasePlayer::GetLocalPlayer() && ShouldHaveLocalPlayerPickupTimelineEvents() )
{
const char* pchWeaponName = "weapon";
const char* pchIcon = "steam_combat";
if ( pWeapon )
{
const char* pchActualName = g_pVGuiLocalize->FindAsUTF8( pWeapon->GetPrintName() );
if ( pchActualName )
{
pchWeaponName = pchActualName;
}
const char* pszTitle = GetLocalizedTitleString( "#Valve_Timeline_Pickup", pchWeaponName );
SteamTimeline()->AddTimelineEvent( pchIcon, pszTitle, nullptr, TIMELINE_NO_PRIORITY, 0, 0, k_ETimelineEventClipPriority_Standard );
}
}
}
#else
else if ( !V_stricmp( event->GetName(), "single_player_death" ) )
{
SteamTimeline()->AddTimelineEvent( "steam_death", "Player was killed", nullptr, 40, 0, 0, k_ETimelineEventClipPriority_None );
}
else if ( !V_stricmp( event->GetName(), "weapon_equipped" ) )
{
int nWeaponEntindex = event->GetInt( "entindex" );
IClientEntity *pWeaponEntity = cl_entitylist->GetBaseEntity( nWeaponEntindex );
if ( pWeaponEntity )
{
C_BaseCombatWeapon *pWeapon = dynamic_cast<C_BaseCombatWeapon *>( pWeaponEntity );
const char *pchWeaponName = "weapon";
const char *pchIcon = "steam_combat";
if ( pWeapon )
{
const char *pchActualName = g_pVGuiLocalize->FindAsUTF8( pWeapon->GetPrintName() );
if ( pchActualName )
{
pchWeaponName = pchActualName;
}
if ( !V_stricmp( "weapon_crowbar", pWeapon->GetName() ) )
{
pchIcon = "weapon_crowbar";
}
else if ( !V_stricmp( "weapon_pistol", pWeapon->GetName() ) )
{
pchIcon = "weapon_pistol";
}
else if ( !V_stricmp( "weapon_smg1", pWeapon->GetName() ) || !V_stricmp( "weapon_smg2", pWeapon->GetName() ) )
{
pchIcon = "weapon_smg";
}
}
SteamTimeline()->AddTimelineEvent( pchIcon, CFmtStr( "Picked up %s", pchWeaponName ), nullptr, 50, 0, 0, k_ETimelineEventClipPriority_Standard );
}
}
else if ( !V_stricmp( event->GetName(), "entity_killed" ) )
{
C_AI_BaseNPC *pKilledEntity = dynamic_cast<C_AI_BaseNPC *>( cl_entitylist->GetBaseEntity( event->GetInt( "entindex_killed", 0 ) ) );
if ( pKilledEntity )
{
const char *pchClassName = pKilledEntity->GetClassname();
if ( !V_stricmp( "class C_BaseHelicopter", pchClassName ) )
{
SteamTimeline()->AddTimelineEvent( "enemy_chopper", "Killed attack chopper", nullptr, 200, -30.f, 35.f, k_ETimelineEventClipPriority_Featured );
}
C_BaseEntity *pInflictor = cl_entitylist->GetBaseEntity( event->GetInt( "entindex_inflictor", 0 ) );
const char *pchModelName = pInflictor ? modelinfo->GetModelName( modelinfo->GetModel( pInflictor->GetModelIndex() ) ) : "";
if ( nullptr != V_stristr_fast( pchModelName, "sawblade" ) )
{
SteamTimeline()->AddTimelineEvent( "sawblade_kill", "Chopped something up with a sawblade", nullptr, 50, 0, 0, k_ETimelineEventClipPriority_None );
}
}
}
#endif // !TF_CLIENT_DLL
#endif // !NO_STEAM
}