//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #include "cbase.h" #include "../EventLog.h" #include "team.h" #include "teamplayroundbased_gamerules.h" #include "tf_gamerules.h" #include "team_control_point_master.h" #include "team_control_point_round.h" #include "tf_team.h" #include "KeyValues.h" extern ConVar tf_flag_caps_per_round; class CTFEventLog : public CEventLog { private: typedef CEventLog BaseClass; public: bool PrintEvent( IGameEvent *event ) // override virtual function { if ( !PrintTFEvent( event ) ) // allow TF to override logging { return BaseClass::PrintEvent( event ); } else { return true; } } bool Init() { BaseClass::Init(); ListenForGameEvent( "player_death" ); ListenForGameEvent( "medic_death" ); ListenForGameEvent( "player_hurt" ); ListenForGameEvent( "player_changeclass" ); ListenForGameEvent( "tf_game_over" ); ListenForGameEvent( "player_chargedeployed" ); ListenForGameEvent( "teamplay_flag_event" ); ListenForGameEvent( "teamplay_capture_blocked" ); ListenForGameEvent( "teamplay_point_captured" ); ListenForGameEvent( "teamplay_round_stalemate" ); ListenForGameEvent( "teamplay_round_win" ); ListenForGameEvent( "teamplay_game_over" ); ListenForGameEvent( "player_builtobject" ); ListenForGameEvent( "player_carryobject" ); ListenForGameEvent( "player_dropobject" ); ListenForGameEvent( "object_removed" ); ListenForGameEvent( "object_detonated" ); ListenForGameEvent( "object_destroyed" ); return true; } protected: bool PrintTFEvent( IGameEvent *event ) // print Mod specific logs { const char *eventName = event->GetName(); if ( !Q_strncmp( eventName, "server_", strlen("server_")) ) { return false; // ignore server_ messages } if ( !Q_strncmp( eventName, "player_death", Q_strlen( "player_death" ) ) ) { const int userid = event->GetInt( "userid" ); CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid ); if ( !pPlayer ) { return false; } const int attackerid = event->GetInt( "attacker" ); const char *weapon = event->GetString( "weapon_logclassname" ); int iCustomDamage = event->GetInt( "customkill" ); CBasePlayer *pAttacker = UTIL_PlayerByUserId( attackerid ); if ( pPlayer == pAttacker ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\" (attacker_position \"%d %d %d\")\n", pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), weapon, (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); } else if ( pAttacker ) { const char *pszCustom = NULL; switch( iCustomDamage ) { case TF_DMG_CUSTOM_HEADSHOT_DECAPITATION: case TF_DMG_CUSTOM_HEADSHOT: pszCustom = "headshot"; break; case TF_DMG_CUSTOM_BACKSTAB: pszCustom = "backstab"; break; default: break; } // is the spy feigning death? if ( event->GetInt( "death_flags" ) & TF_DEATH_FEIGN_DEATH ) { pszCustom = "feign_death"; } if ( pszCustom ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\" (customkill \"%s\") (attacker_position \"%d %d %d\") (victim_position \"%d %d %d\")\n", pAttacker->GetPlayerName(), attackerid, pAttacker->GetNetworkIDString(), pAttacker->GetTeam()->GetName(), pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), weapon, pszCustom, (int)pAttacker->GetAbsOrigin().x, (int)pAttacker->GetAbsOrigin().y, (int)pAttacker->GetAbsOrigin().z, (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); } else { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\" (attacker_position \"%d %d %d\") (victim_position \"%d %d %d\")\n", pAttacker->GetPlayerName(), attackerid, pAttacker->GetNetworkIDString(), pAttacker->GetTeam()->GetName(), pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), weapon, (int)pAttacker->GetAbsOrigin().x, (int)pAttacker->GetAbsOrigin().y, (int)pAttacker->GetAbsOrigin().z, (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); } } else { int iDamageBits = event->GetInt( "damagebits" ); if ( ( iDamageBits & DMG_VEHICLE ) || ( iDamageBits & DMG_NERVEGAS ) ) { const char *pszCustomKill = "train"; if ( iDamageBits & DMG_NERVEGAS ) { pszCustomKill = "saw"; } // killed by the world UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"world\" (customkill \"%s\") (attacker_position \"%d %d %d\")\n", pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), pszCustomKill, (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); } else { // killed by the world UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"world\" (attacker_position \"%d %d %d\")\n", pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); } } // Assist kill int assistid = event->GetInt( "assister" ); CBasePlayer *pAssister = UTIL_PlayerByUserId( assistid ); if ( pAssister ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"kill assist\" against \"%s<%i><%s><%s>\" (assister_position \"%d %d %d\") (attacker_position \"%d %d %d\") (victim_position \"%d %d %d\")\n", pAssister->GetPlayerName(), assistid, pAssister->GetNetworkIDString(), pAssister->GetTeam()->GetName(), pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), (int)pAssister->GetAbsOrigin().x, (int)pAssister->GetAbsOrigin().y, (int)pAssister->GetAbsOrigin().z, pAttacker ? (int)pAttacker->GetAbsOrigin().x : 0, pAttacker ? (int)pAttacker->GetAbsOrigin().y : 0, pAttacker ? (int)pAttacker->GetAbsOrigin().z : 0, (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); } // Domination and Revenge // pAttacker //int attackerid = engine->GetPlayerForUserID( event->GetInt( "attacker" ) ); // pPlayer //int userid = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); // pAssister // assistid if ( event->GetInt( "death_flags" ) & TF_DEATH_DOMINATION && pAttacker ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"domination\" against \"%s<%i><%s><%s>\"\n", pAttacker->GetPlayerName(), attackerid, pAttacker->GetNetworkIDString(), pAttacker->GetTeam()->GetName(), pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName() ); } if ( event->GetInt( "death_flags" ) & TF_DEATH_ASSISTER_DOMINATION && pAssister ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"domination\" against \"%s<%i><%s><%s>\" (assist \"1\")\n", pAssister->GetPlayerName(), assistid, pAssister->GetNetworkIDString(), pAssister->GetTeam()->GetName(), pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName() ); } if ( event->GetInt( "death_flags" ) & TF_DEATH_REVENGE && pAttacker ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"revenge\" against \"%s<%i><%s><%s>\"\n", pAttacker->GetPlayerName(), attackerid, pAttacker->GetNetworkIDString(), pAttacker->GetTeam()->GetName(), pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName() ); } if ( event->GetInt( "death_flags" ) & TF_DEATH_ASSISTER_REVENGE && pAssister ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"revenge\" against \"%s<%i><%s><%s>\" (assist \"1\")\n", pAssister->GetPlayerName(), assistid, pAssister->GetNetworkIDString(), pAssister->GetTeam()->GetName(), pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName() ); } return true; } else if ( FStrEq( eventName, "player_changeclass" ) ) { const int userid = event->GetInt( "userid" ); CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid ); if ( !pPlayer ) { return false; } int iClass = event->GetInt("class"); if ( pPlayer->GetTeamNumber() < FIRST_GAME_TEAM ) return true; if ( iClass >= TF_FIRST_NORMAL_CLASS && iClass <= TF_LAST_NORMAL_CLASS ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed role to \"%s\"\n", pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), GetPlayerClassData( iClass )->m_szClassName ); } return true; } else if ( FStrEq( eventName, "tf_game_over" ) || FStrEq( eventName, "teamplay_game_over" ) ) { UTIL_LogPrintf( "World triggered \"Game_Over\" reason \"%s\"\n", event->GetString( "reason" ) ); UTIL_LogPrintf( "Team \"Red\" final score \"%d\" with \"%d\" players\n", GetGlobalTeam( TF_TEAM_RED )->GetScore(), GetGlobalTeam( TF_TEAM_RED )->GetNumPlayers() ); UTIL_LogPrintf( "Team \"Blue\" final score \"%d\" with \"%d\" players\n", GetGlobalTeam( TF_TEAM_BLUE )->GetScore(), GetGlobalTeam( TF_TEAM_BLUE )->GetNumPlayers() ); return true; } else if ( FStrEq( eventName, "player_chargedeployed" ) ) { const int userid = event->GetInt( "userid" ); CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid ); if ( !pPlayer ) { return false; } UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"chargedeployed\"\n", pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName() ); return true; } else if ( FStrEq( eventName, "player_builtobject" ) || FStrEq( eventName, "player_carryobject" ) || FStrEq( eventName, "player_dropobject" ) || FStrEq( eventName, "player_removed" ) || FStrEq( eventName, "object_detonated" ) ) { const int userid = event->GetInt( "userid" ); CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid ); if ( pPlayer ) { // Some events have "object" and some have "objecttype". We can't change them as there are third-party // scripts that listen for these events. const int objectid = !event->IsEmpty( "objecttype" ) ? event->GetInt( "objecttype" ) : event->GetInt( "object" ); const CObjectInfo *pInfo = ( objectid >= 0 && objectid < OBJ_LAST ) ? GetObjectInfo( objectid ) : NULL; if ( pInfo ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"%s\" (object \"%s\") (position \"%d %d %d\")\n", pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), eventName, pInfo->m_pObjectName, (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); } return true; } return false; } else if ( FStrEq( eventName, "object_destroyed" ) ) { int objectid = event->GetInt( "objecttype" ); const CObjectInfo *pInfo = ( objectid >= 0 && objectid < OBJ_LAST ) ? GetObjectInfo( objectid ) : NULL; if ( !pInfo ) return false; const int userid = event->GetInt( "userid" ); CBasePlayer *pObjectOwner = UTIL_PlayerByUserId( userid ); if ( !pObjectOwner ) return false; const int attackerid = event->GetInt( "attacker" ); CBasePlayer *pAttacker = UTIL_PlayerByUserId( attackerid ); if ( !pAttacker ) return false; const char *weapon = event->GetString( "weapon" ); // log that the person killed an object UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"killedobject\" (object \"%s\") (weapon \"%s\") (objectowner \"%s<%i><%s><%s>\") (attacker_position \"%d %d %d\")\n", pAttacker->GetPlayerName(), attackerid, pAttacker->GetNetworkIDString(), pAttacker->GetTeam()->GetName(), pInfo->m_pObjectName, weapon, pObjectOwner->GetPlayerName(), userid, pObjectOwner->GetNetworkIDString(), pObjectOwner->GetTeam()->GetName(), (int)pAttacker->GetAbsOrigin().x, (int)pAttacker->GetAbsOrigin().y, (int)pAttacker->GetAbsOrigin().z ); const int assisterid = event->GetInt( "assister" ); CBasePlayer *pAssister = UTIL_PlayerByUserId( assisterid ); if ( pAssister ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"killedobject\" (object \"%s\") (objectowner \"%s<%i><%s><%s>\") (assist \"1\") (assister_position \"%d %d %d\") (attacker_position \"%d %d %d\")\n", pAssister->GetPlayerName(), assisterid, pAssister->GetNetworkIDString(), pAssister->GetTeam()->GetName(), pInfo->m_pObjectName, pObjectOwner->GetPlayerName(), userid, pObjectOwner->GetNetworkIDString(), pObjectOwner->GetTeam()->GetName(), (int)pAssister->GetAbsOrigin().x, (int)pAssister->GetAbsOrigin().y, (int)pAssister->GetAbsOrigin().z, (int)pAttacker->GetAbsOrigin().x, (int)pAttacker->GetAbsOrigin().y, (int)pAttacker->GetAbsOrigin().z ); } } else if ( FStrEq( eventName, "teamplay_flag_event" ) ) { int playerindex = event->GetInt( "player" ); CBasePlayer *pPlayer = UTIL_PlayerByIndex( playerindex ); if ( !pPlayer ) { return false; } const char *pszEvent = "unknown"; // picked up, dropped, defended, captured int iEventType = event->GetInt( "eventtype" ); bool bPlainLogEntry = true; switch ( iEventType ) { case TF_FLAGEVENT_PICKUP: pszEvent = "picked up"; break; case TF_FLAGEVENT_CAPTURE: pszEvent = "captured"; if ( tf_flag_caps_per_round.GetInt() > 0 ) { bPlainLogEntry = false; } break; case TF_FLAGEVENT_DEFEND: pszEvent = "defended"; break; case TF_FLAGEVENT_DROPPED: pszEvent = "dropped"; break; } if ( bPlainLogEntry ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"flagevent\" (event \"%s\") (position \"%d %d %d\")\n", pPlayer->GetPlayerName(), pPlayer->GetUserID(), pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), pszEvent, (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); } else { CTFTeam *pTeam = GetGlobalTFTeam( pPlayer->GetTeamNumber() ); UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"flagevent\" (event \"%s\") (team_caps \"%d\") (caps_per_round \"%d\") (position \"%d %d %d\")\n", pPlayer->GetPlayerName(), pPlayer->GetUserID(), pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), pszEvent, pTeam->GetFlagCaptures(), tf_flag_caps_per_round.GetInt(), (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); } return true; } else if ( FStrEq( eventName, "teamplay_capture_blocked" ) ) { int blockerindex = event->GetInt( "blocker" ); CBasePlayer *pBlocker = UTIL_PlayerByIndex( blockerindex ); if ( !pBlocker ) { return true; } UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"captureblocked\" (cp \"%d\") (cpname \"%s\") (position \"%d %d %d\")\n", pBlocker->GetPlayerName(), pBlocker->GetUserID(), pBlocker->GetNetworkIDString(), pBlocker->GetTeam()->GetName(), event->GetInt( "cp" ), event->GetString( "cpname" ), (int)pBlocker->GetAbsOrigin().x, (int)pBlocker->GetAbsOrigin().y, (int)pBlocker->GetAbsOrigin().z ); } else if ( FStrEq( eventName, "teamplay_point_captured" ) ) { CTeam *pTeam = GetGlobalTeam( event->GetInt( "team" ) ); if ( !pTeam ) return true; const char *szCappers = event->GetString( "cappers" ); int iNumCappers = Q_strlen( szCappers ); if ( iNumCappers <= 0 ) return true; char buf[1024]; Q_snprintf( buf, sizeof(buf), "Team \"%s\" triggered \"pointcaptured\" (cp \"%d\") (cpname \"%s\") (numcappers \"%d\") ", pTeam->GetName(), event->GetInt( "cp" ), event->GetString( "cpname" ), iNumCappers ); for ( int i=0;i 0 && iPlayerIndex <= MAX_PLAYERS ); CBasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex ); if ( !pPlayer ) continue; char playerBuf[256]; Q_snprintf( playerBuf, sizeof(playerBuf), "(player%d \"%s<%i><%s><%s>\") (position%d \"%d %d %d\") ", i + 1, pPlayer->GetPlayerName(), pPlayer->GetUserID(), pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), i + 1, (int)pPlayer->GetAbsOrigin().x, (int)pPlayer->GetAbsOrigin().y, (int)pPlayer->GetAbsOrigin().z ); Q_strncat( buf, playerBuf, sizeof(buf), COPY_ALL_CHARACTERS ); } UTIL_LogPrintf( "%s\n", buf ); } else if ( FStrEq( eventName, "teamplay_round_stalemate" ) ) { int iReason = event->GetInt( "reason" ); if ( iReason == STALEMATE_TIMER ) { UTIL_LogPrintf( "World triggered \"Round_SuddenDeath\" reason \"round timelimit reached\"\n" ); } else if ( iReason == STALEMATE_SERVER_TIMELIMIT ) { UTIL_LogPrintf( "World triggered \"Round_SuddenDeath\" reason \"server timelimit reached\"\n" ); } else { UTIL_LogPrintf( "World triggered \"Round_SuddenDeath\"\n" ); } return true; } else if ( FStrEq( eventName, "teamplay_round_win" ) ) { bool bShowScores = true; int iTeam = event->GetInt( "team" ); bool bFullRound = event->GetBool( "full_round" ); if ( iTeam == TEAM_UNASSIGNED ) { UTIL_LogPrintf( "World triggered \"Round_Stalemate\"\n" ); } else { const char *pszWinner = "Red"; if ( iTeam == TF_TEAM_BLUE ) { pszWinner = "Blue"; } CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; if ( pMaster && pMaster->PlayingMiniRounds() ) { UTIL_LogPrintf( "World triggered \"Mini_Round_Win\" (winner \"%s\") (round \"%s\")\n", pszWinner, pMaster->GetCurrentRound()->GetEntityName().ToCStr() ); UTIL_LogPrintf( "World triggered \"Mini_Round_Length\" (seconds \"%0.2f\")\n", event->GetFloat( "round_time" ) ); bShowScores = false; } if ( bFullRound ) { UTIL_LogPrintf( "World triggered \"Round_Win\" (winner \"%s\")\n", pszWinner ); if ( !pMaster || !pMaster->PlayingMiniRounds() ) { UTIL_LogPrintf( "World triggered \"Round_Length\" (seconds \"%0.2f\")\n", event->GetFloat( "round_time" ) ); } bShowScores = true; } } if ( bShowScores ) { UTIL_LogPrintf( "Team \"Red\" current score \"%d\" with \"%d\" players\n", GetGlobalTeam( TF_TEAM_RED )->GetScore(), GetGlobalTeam( TF_TEAM_RED )->GetNumPlayers() ); UTIL_LogPrintf( "Team \"Blue\" current score \"%d\" with \"%d\" players\n", GetGlobalTeam( TF_TEAM_BLUE )->GetScore(), GetGlobalTeam( TF_TEAM_BLUE )->GetNumPlayers() ); } } else if ( FStrEq( eventName, "medic_death" ) ) { const int userid = event->GetInt( "userid" ); CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid ); if ( !pPlayer ) { return false; } const int attackerid = event->GetInt( "attacker" ); CBasePlayer *pAttacker = UTIL_PlayerByUserId( attackerid ); bool bCharged = event->GetBool( "charged" ); int iHealing = event->GetInt( "healing" ); if ( !pAttacker ) { pAttacker = pPlayer; } UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"medic_death\" against \"%s<%i><%s><%s>\" (healing \"%d\") (ubercharge \"%s\")\n", pAttacker->GetPlayerName(), attackerid, pAttacker->GetNetworkIDString(), pAttacker->GetTeam()->GetName(), pPlayer->GetPlayerName(), userid, pPlayer->GetNetworkIDString(), pPlayer->GetTeam()->GetName(), iHealing, bCharged ? "1" : "0" ); return true; } return false; } }; CTFEventLog g_TFEventLog; //----------------------------------------------------------------------------- // Singleton access //----------------------------------------------------------------------------- IGameSystem* GameLogSystem() { return &g_TFEventLog; }