//---------------------------------------------------------------- // StatEvent.cpp // // Copyright 2002-2005 Raven Software //---------------------------------------------------------------- #include "../../../idlib/precompiled.h" #pragma hdrstop #include "../../Game_local.h" #include "StatManager.h" rvStatHit::rvStatHit( int t, int p, int v, int w, bool countForAccuracy ) : rvStat( t ) { playerClientNum = p; victimClientNum = v; weapon = w; trackAccuracy = countForAccuracy; type = ST_HIT; RegisterInGame( statManager->GetPlayerStats() ); } void rvStatHit::RegisterInGame( rvPlayerStat* stats ) { if( playerClientNum >= 0 && playerClientNum < MAX_CLIENTS && weapon >= 0 && weapon < MAX_WEAPONS && trackAccuracy ) { stats[ playerClientNum ].weaponHits[ weapon ]++; } idPlayer* player = (idPlayer*)gameLocal.entities[ playerClientNum ]; if( !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", weapon ) ), "weapon_railgun" ) ) { // Apparently it does the rail hit event before the rail fired event, so this is backwards for a reason if ( rvStatManager::comboKillState[ playerClientNum ] == CKS_ROCKET_HIT ) { rvStatManager::comboKillState[ playerClientNum ] = CKS_RAIL_HIT; } if ( rvStatManager::lastRailShot[ playerClientNum ] < stats[ playerClientNum ].weaponShots[ weapon ] - 1 ) { rvStatManager::lastRailShot[ playerClientNum ] = stats[ playerClientNum ].weaponShots[ weapon ]; } else { if ( rvStatManager::lastRailShot[ playerClientNum ] >= stats[ playerClientNum ].weaponShots[ weapon ] - 1 ) { if ( (rvStatManager::lastRailShotHits[ playerClientNum ] % 2) == 0 ) { statManager->GiveInGameAward( IGA_IMPRESSIVE, playerClientNum ); } ++rvStatManager::lastRailShotHits[ playerClientNum ]; } else { rvStatManager::lastRailShot[ playerClientNum ] = stats[ playerClientNum ].weaponShots[ weapon ]; } } /* rvStatHit* lastHits[ 2 ] = { NULL, NULL }; statManager->GetLastClientStats( playerClientNum, ST_HIT, gameLocal.time - 8000, 2, (rvStat**)lastHits ); if( lastHits[0] ) { if( !idStr::Icmp(player->spawnArgs.GetString( va( "def_weapon%d", ((rvStatHit*)lastHits[0])->weapon ) ), "weapon_railgun" ) ) { //Check to make sure we don't chain impressive awards. if(lastHits[1] && !idStr::Icmp(player->spawnArgs.GetString( va( "def_weapon%d", ((rvStatHit*)lastHits[1])->weapon ) ), "weapon_railgun" ) && (lastHits[1]->GetTimeStamp() - lastHits[0]->GetTimeStamp()) < 4000) { return; } if(gameLocal.time - lastHits[0]->GetTimeStamp() < 4000){ statManager->GiveInGameAward( IGA_IMPRESSIVE, playerClientNum ); } } } */ } else if( !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", weapon ) ), "weapon_rocketlauncher" ) ) { if ( rvStatManager::comboKillState[ playerClientNum ] == CKS_ROCKET_FIRED ) { rvStatManager::comboKillState[ playerClientNum ] = CKS_ROCKET_HIT; } } } rvStatKill::rvStatKill( int t, int p, int v, bool g, int mod ) : rvStat( t ) { type = ST_KILL; playerClientNum = p; victimClientNum = v; gibbed = g; methodOfDeath = mod; RegisterInGame( statManager->GetPlayerStats() ); } void rvStatKill::RegisterInGame( rvPlayerStat* stats ) { if( playerClientNum < 0 || playerClientNum >= MAX_CLIENTS || victimClientNum < 0 || victimClientNum >= MAX_CLIENTS ) { return; } idPlayer* player = (idPlayer*)gameLocal.entities[ playerClientNum ]; idPlayer* victim = (idPlayer*)gameLocal.entities[ victimClientNum ]; // no award processing for suicides if( victimClientNum == playerClientNum ) { stats[ playerClientNum ].suicides++; return; } bool teamKill = false; // don't track team kills if( !gameLocal.IsTeamGame() || player->team != victim->team ) { stats[ playerClientNum ].kills++; if( methodOfDeath >= 0 && methodOfDeath < MAX_WEAPONS ) { stats[ playerClientNum ].weaponKills[ methodOfDeath ]++; } } if( gameLocal.IsTeamGame() && player->team == victim->team ) { teamKill = true; } // check for humiliation award if( !teamKill && !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", methodOfDeath ) ), "weapon_gauntlet" ) ) { statManager->GiveInGameAward( IGA_HUMILIATION, playerClientNum ); } rvStatKill* lastKills[ 2 ] = { NULL, NULL }; statManager->GetLastClientStats( playerClientNum, ST_KILL, gameLocal.time - 5000, 2, (rvStat**)lastKills ); // check for excellent award if( !teamKill && lastKills[ 0 ] && lastKills[ 0 ]->GetTimeStamp() >= (gameLocal.time - 2000) && lastKills[ 0 ]->victimClientNum != playerClientNum && victimClientNum != playerClientNum ) { statManager->GiveInGameAward( IGA_EXCELLENT, playerClientNum ); } // check for rampage award if( !teamKill && ( gibbed && victimClientNum != playerClientNum ) && ( lastKills[ 0 ] && lastKills[ 0 ]->gibbed && lastKills[ 0 ]->victimClientNum != playerClientNum ) && ( lastKills[ 1 ] && lastKills[ 1 ]->gibbed && lastKills[ 1 ]->victimClientNum != playerClientNum ) ) { statManager->GiveInGameAward( IGA_RAMPAGE, playerClientNum ); } // check for combo kill award if( victimClientNum != playerClientNum && !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", methodOfDeath ) ), "weapon_railgun" ) ) { // the rail killing shot is the last hit, so look for the one past that rvStatHit* lastHits[ 2 ] = { NULL, NULL }; statManager->GetLastClientStats( playerClientNum, ST_HIT, gameLocal.time - 3000, 2, (rvStat**)lastHits ); if( lastHits[ 1 ] && lastHits[ 1 ]->GetVictimClientNum() != playerClientNum && !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", lastHits[ 1 ]->GetWeapon() ) ), "weapon_rocketlauncher" ) ) { if ( rvStatManager::comboKillState[ playerClientNum ] == CKS_RAIL_HIT ) { statManager->GiveInGameAward( IGA_COMBO_KILL, playerClientNum ); } } } rvStatManager::comboKillState[ playerClientNum ] = CKS_NONE; // check for defense award if( gameLocal.IsFlagGameType() && player->team != victim->team && player != victim ) { // defense is given for two conditions // assert( gameLocal.mpGame.GetFlagEntity( TEAM_STROGG ) && gameLocal.mpGame.GetFlagEntity( TEAM_MARINE ) ); assert( player->team >= 0 && player->team < TEAM_MAX ); assert( gameLocal.mpGame.GetGameState()->IsType( rvCTFGameState::GetClassType() ) ); if ( gameLocal.mpGame.GetFlagEntity( player->team ) ) { // defending your flag if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( player->team ) == FS_AT_BASE || ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( player->team ) == FS_DROPPED ) { if( ( gameLocal.mpGame.GetFlagEntity( player->team )->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin() ).LengthSqr() < 250000 ) { // give award if you're close to flag and you kill an enemy statManager->GiveInGameAward( IGA_DEFENSE, playerClientNum ); } else if ( ( gameLocal.mpGame.GetFlagEntity( player->team )->GetPhysics()->GetOrigin() - victim->GetPhysics()->GetOrigin() ).LengthSqr() < 250000 ) { // give award if enemy is close to flag and you kill them statManager->GiveInGameAward( IGA_DEFENSE, playerClientNum ); } } } // defending your teammate carrying the enemy flag if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( gameLocal.mpGame.OpposingTeam( player->team ) ) == FS_TAKEN ) { int clientNum = ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagCarrier( gameLocal.mpGame.OpposingTeam( player->team ) ); idPlayer* flagCarrier = NULL; if( clientNum >= 0 && clientNum < MAX_CLIENTS ) { flagCarrier = (idPlayer*)gameLocal.entities[ clientNum ]; } if( flagCarrier ) { if( (flagCarrier->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin()).LengthSqr() < 250000 ) { // killed enemy while close to the flag carrier statManager->GiveInGameAward( IGA_DEFENSE, playerClientNum ); } else if( (flagCarrier->GetPhysics()->GetOrigin() - victim->GetPhysics()->GetOrigin()).LengthSqr() < 250000 ) { // killed an enemy who was close to teh flag carrier statManager->GiveInGameAward( IGA_DEFENSE, playerClientNum ); } } } } // check for holy shit award if( gameLocal.IsFlagGameType() && player->team != victim->team && player != victim ) { if( (player->team == TEAM_MARINE && victim->PowerUpActive( POWERUP_CTF_MARINEFLAG )) || (player->team == TEAM_STROGG && victim->PowerUpActive( POWERUP_CTF_STROGGFLAG )) ) { if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( victim->team ) == FS_AT_BASE ) { // fixme: something is broken with the mpgame state if ( gameLocal.mpGame.GetFlagEntity( victim->team ) ) { if( (gameLocal.mpGame.GetFlagEntity( victim->team )->GetPhysics()->GetOrigin() - victim->GetPhysics()->GetOrigin()).LengthSqr() < 40000 ) { statManager->GiveInGameAward( IGA_HOLY_SHIT, playerClientNum ); } } } } } } /* ================ rvStatDeath A player died ================ */ rvStatDeath::rvStatDeath( int t, int p, int mod ) : rvStat( t ) { type = ST_DEATH; playerClientNum = p; RegisterInGame( statManager->GetPlayerStats() ); } void rvStatDeath::RegisterInGame( rvPlayerStat* stats ) { stats[ playerClientNum ].deaths++; } /* ================ rvStatDamageDealt A player damaged another player ================ */ rvStatDamageDealt::rvStatDamageDealt( int t, int p, int w, int d ) : rvStat( t ) { playerClientNum = p; weapon = w; damage = d; type = ST_DAMAGE_DEALT; RegisterInGame( statManager->GetPlayerStats() ); } void rvStatDamageDealt::RegisterInGame( rvPlayerStat* stats ) { if( playerClientNum >= 0 && playerClientNum < MAX_CLIENTS ) { stats[ playerClientNum ].damageGiven += damage; } } /* ================ rvStatDamageTaken A player took damage from another player ================ */ rvStatDamageTaken::rvStatDamageTaken( int t, int p, int w, int d ) : rvStat( t ) { playerClientNum = p; weapon = w; damage = d; type = ST_DAMAGE_TAKEN; RegisterInGame( statManager->GetPlayerStats() ); } void rvStatDamageTaken::RegisterInGame( rvPlayerStat* stats ) { if( playerClientNum >= 0 && playerClientNum < MAX_CLIENTS ) { stats[ playerClientNum ].damageTaken += damage; } } /* ================ rvStatFlagDrop A player dropped the flag (CTF) ================ */ rvStatFlagDrop::rvStatFlagDrop( int t, int p, int a, int tm ) : rvStatTeam( t, tm ) { playerClientNum = p; attacker = a; type = ST_CTF_FLAG_DROP; } /* ================ rvStatFlagReturn A player returned his teams flag ================ */ rvStatFlagReturn::rvStatFlagReturn( int t, int p, int tm ) : rvStatTeam( t, tm ) { playerClientNum = p; type = ST_CTF_FLAG_RETURN; } /* ================ rvStatFlagCapture A player captured a flag (CTF) ================ */ rvStatFlagCapture::rvStatFlagCapture( int t, int p, int f, int tm ) : rvStatTeam( t, tm ) { playerClientNum = p; flagTeam = f; type = ST_CTF_FLAG_CAPTURE; RegisterInGame( statManager->GetPlayerStats() ); } void rvStatFlagCapture::RegisterInGame( rvPlayerStat* stats ) { statManager->GiveInGameAward( IGA_CAPTURE, playerClientNum ); // figure out if we need to give an assist // see if someone carried the flag a bit, lost it, but it was capped rvStatFlagDrop* flagDrop = (rvStatFlagDrop*)statManager->GetLastTeamStat( team, ST_CTF_FLAG_DROP, gameLocal.time - 10000 ); if( flagDrop && flagDrop->GetTeam() == team ) { // only give the award if there was no flag return between the flag drop and the flag capture rvStatFlagReturn* flagReturn = (rvStatFlagReturn*)statManager->GetLastTeamStat( flagTeam, ST_CTF_FLAG_RETURN, gameLocal.time - 10000 ); if( flagReturn == NULL ) { statManager->GiveInGameAward( IGA_ASSIST, flagDrop->GetPlayerClientNum() ); } } // see if someone returned the flag, allowing a cap rvStatFlagReturn* flagReturn = (rvStatFlagReturn*)statManager->GetLastTeamStat( team, ST_CTF_FLAG_RETURN, gameLocal.time - 10000 ); if( flagReturn ) { statManager->GiveInGameAward( IGA_ASSIST, flagReturn->GetPlayerClientNum() ); } }