//
// AVP_Multiplayer_GameCore.cpp
//
// Created by JG - 03 July 2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "Multiplayer/AVP_Multiplayer_GameCore.h"

// Engine headers
#include "Core/Asura_Timers.h"
#include "Network/Asura_Network.h"
#ifdef ASURA_SUPPORT_LOBBY
#include "Network/Online/Asura_Lobby.h"
#endif

// Game headers
#include "Blueprint/AVP_Blueprint_HashIDs.h"
#include "Core/AVP_GameStatus.h"
#include "Entity/GameMode/AVP_ServerEntity_GameMode.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Entity/PlayerInfo/AVP_ServerEntity_PlayerInfo.h"
#include "Entity/PlayerInfo/AVP_ClientEntity_PlayerInfo.h"
#include "Multiplayer/AVP_Multiplayer_DamageCounter.h"
#include "Multiplayer/AVP_Multiplayer_GameMessageSystem.h"
#include "Multiplayer/AVP_Multiplayer_GameRules.h"
#include "Multiplayer/AVP_Multiplayer_InverseSurvivorRank.h"
#include "Multiplayer/AVP_Multiplayer_KillCounter.h"
#include "Multiplayer/AVP_Multiplayer_ScoreBoard.h"
#include "Multiplayer/AVP_Multiplayer_ScoreRules.h"
#include "Multiplayer/AVP_Multiplayer_SpawnSystem.h"
#include "Multiplayer/AVP_Multiplayer_TeamScore.h"

////////////////////////////////////////////////////////////
//  Class implementation
////////////////////////////////////////////////////////////

float AVP_Multiplayer_GameCore::s_fCurrentMatchStartTime = 0.0f; 
bool AVP_Multiplayer_GameCore::s_bMultiplayerMatchInProgress = false; 

// Previous state of cheats, overriden in multiplayer games
static bool s_bPreviousStateGodModeCheat = false; 
static bool s_bPreviousStateInfAmmoCheat = false; 

void AVP_Multiplayer_GameCore::Initialise()
{
	// No cheats in multiplayer games, please
	s_bPreviousStateGodModeCheat = AVP_Settings::GetGodMode(); 
	s_bPreviousStateInfAmmoCheat = AVP_Settings::GetInfiniteAmmo(); 

	AVP_Settings::SetGodMode(false); 
	AVP_Settings::SetInfiniteAmmo(false); 

	// Initialise all score tables
	AVP_Multiplayer_ScoreRules::Initialise(); 

	// Initialise score board system
	AVP_Multiplayer_ScoreBoard::Initialise(); 

	// Initialise game message system
	AVP_Multiplayer_GameMessageSystem::Initialise(); 

	// Initialise the player spawning control system
	AVP_Multiplayer_SpawnSystem::Initialise(); 
}

void AVP_Multiplayer_GameCore::Reset()
{
	// Destroy the team score entries
	AVP_Multiplayer_TeamScore::DestroyAll(); 

	// Shutdown the spawn control system
	AVP_Multiplayer_SpawnSystem::Shutdown(); 
}

void AVP_Multiplayer_GameCore::Update()
{
	// Update the game message system
	AVP_Multiplayer_GameMessageSystem::Update();

	// Update team scores
	AVP_Multiplayer_TeamScore::Update(); 

	// Update the score board
	AVP_Multiplayer_ScoreBoard::Update();

	// Update the spawn control system
	AVP_Multiplayer_SpawnSystem::Update(); 

	// Check game mode correctness
	DoGameModeSanityChecks(); 
}

void AVP_Multiplayer_GameCore::Render()
{
	// Render all score board related stuff  
	AVP_Multiplayer_ScoreBoard::RenderDebugInfo();
	AVP_Multiplayer_ScoreBoard::Render();	

	// Render in game messages here
	AVP_Multiplayer_GameMessageSystem::Render(); 	

}

void AVP_Multiplayer_GameCore::Shutdown()
{
#ifdef ASURA_SUPPORT_LOBBY
	// tell the lobby system we've finished the round. Do it before shutting down the scoring data.
	if(Asura_Lobby_System::IsInitialised())
	{
		Asura_Lobby_System::EndGame();
	}
#endif
	// Destroy the score board system
	AVP_Multiplayer_ScoreBoard::Shutdown(); 

	// Destroy all game score rules
	AVP_Multiplayer_ScoreRules::Shutdown(); 

	// Shutdown the game message system
	AVP_Multiplayer_GameMessageSystem::Shutdown(); 

	// We are finished here, cheat as much as you want
	AVP_Settings::SetGodMode(s_bPreviousStateGodModeCheat); 
	AVP_Settings::SetInfiniteAmmo(s_bPreviousStateInfAmmoCheat); 

}

void AVP_Multiplayer_GameCore::BeginMultiplayerMatch(float fStartTime)
{
	// There is a game in progress from now on
	s_bMultiplayerMatchInProgress = true; 
	
	// Remember when this multiplayer match started
	s_fCurrentMatchStartTime = fStartTime; 

	// Activate the appropiate game mode in this map
	ActivateGameModeNode(AVP_Settings::GetGameType());

	// Reset the players score and other multiplayer info, in case this is not the first game session
	AVP_ServerEntity_PlayerInfo::ResetMultiplayerInfoForAllPlayers(); 
	AVP_Multiplayer_InverseSurvivorRank::Reset(); 
}

void AVP_Multiplayer_GameCore::EndMultiplayerMatch()
{
#ifdef ASURA_SUPPORT_LOBBY
	if (s_bMultiplayerMatchInProgress)
	{
		bool bCompleted = false;
		if (Asura_Network::IsServer())
		{
			// On the server the only way to complete the game is to get to the game over state.
			bCompleted = AVP_GameStatus::GetGameOver();
		}
		else
		{
			// On the client we complete the game if the server completes, quits or disappears
			// (which we assume is a network issue). So quitting or turning the power off on the
			// client before reaching game over, will result in non-completion.
			// If the client pulls out his network cable it'll probably incorrectly count as completion.
			// However in that case the completion stat won't be written back to the stats server
			// and the client will need to reconnect, which should cause the netlink manager to
			// reload the stats from the server overwriting the bogus completion stat.
			bCompleted = !AVP_GameStatus::GetQuitApplication() && !AVP_GameStatus::GetExitGame();
		}

		Asura_Lobby_System::CompletedGame(bCompleted);
	}
#endif //ifdef ASURA_SUPPORT_LOBBY

	if (Asura_Network::IsServer())
	{
		// Update score in survival games for the last round
		if (AVP_Settings::GetGameType() == AVP_Settings::AVP_GAMETYPE_SURVIVOR)
		{
			AVP_Multiplayer_InverseSurvivorRank::UpdatePlayersScoreOnRoundEnd();
		}
	}

	// The match is finished
	s_bMultiplayerMatchInProgress = false; 

	// CAH if we have to store info/data for the scoreboard and rankings this could be a good place to do it. (?)
}

bool AVP_Multiplayer_GameCore::ShouldEndMultiplayerMatch()
{
	// Check for end of game conditions

	// Are we the server?
	if (Asura_Network::IsServer())
	{
		// Is there a time limit set for this match?
		if (AVP_Multiplayer_GameRules::GetTimeLimit() > 0)
		{
			// Yes, check if we have played for that long
			float fMatchTime = Asura_Timers::GetServerAbsoluteTime() - s_fCurrentMatchStartTime; 
			Asura_Assert( fMatchTime >= 0.0f, "Unexpected multiplayer match start time!");

			// Convert to the lowest minute
			int iMatchTimeInMinutes; 
			iMatchTimeInMinutes = Asura_Maths::FloatToInt_Chop(fMatchTime / 60.0f); 

			if (iMatchTimeInMinutes >= AVP_Multiplayer_GameRules::GetTimeLimit())
			{
				return true; 
			}
		}

		// Is there an individual score limit set for this match?
		if (AVP_Multiplayer_GameRules::GetPlayerScoreLimit() > 0)
		{
			// Yes, check if any of the players have reached that score
			int iMaxScore = 0;
			Asura_Hashed_List_ConstIt<AVP_ServerEntity_PlayerInfo> xPlayerInfoConstIt( AVP_ServerEntity_PlayerInfo::GetList() ); 
			
			while ( !xPlayerInfoConstIt.Done() )
			{
				const AVP_ServerEntity_PlayerInfo* pxPlayerInfo = xPlayerInfoConstIt.GetCurrent(); 
				if (pxPlayerInfo)
				{
					const AVP_Multiplayer_PlayerScore& xPlayerScore = pxPlayerInfo->GetPlayerScore(); 
					int iPlayerScore = xPlayerScore.GetIndividualScore();
					iMaxScore = iPlayerScore > iMaxScore ? iPlayerScore : iMaxScore; 
				}
				else
				{
					Asura_Assert(pxPlayerInfo, "Invalid player info pointer"); 
				}
				xPlayerInfoConstIt.Next(); 
			}
			
			if (iMaxScore >= AVP_Multiplayer_GameRules::GetPlayerScoreLimit())
			{
				return true; 
			}
		}

		// End of game conditions for team based games
		if (AVP_Multiplayer_GameRules::IsTeamBasedGame())
		{
			// Is there a team score limit set for this match?
			if (AVP_Multiplayer_GameRules::GetTeamScoreLimit() > 0)
			{
				// Yes, check if any of the teams have reached that score
				int iMaxScore = 0;
				Asura_List_It<AVP_Multiplayer_TeamScore> xTeamScoreIt( AVP_Multiplayer_TeamScore::GetList() ); 
				
				while ( !xTeamScoreIt.Done() )
				{
					AVP_Multiplayer_TeamScore* pxTeamScore = xTeamScoreIt.GetCurrent(); 
					if (pxTeamScore)
					{
						int iTeamScore = pxTeamScore->GetTeamScore();
						iMaxScore = iTeamScore > iMaxScore ? iTeamScore : iMaxScore; 
					}
					else
					{
						Asura_Assert(pxTeamScore, "Invalid team score pointer"); 
					}
					xTeamScoreIt.Next(); 
				}
				
				if (iMaxScore >= AVP_Multiplayer_GameRules::GetTeamScoreLimit())
				{
					return true; 
				}
			}

			// Is there a fixed number of lives per team?
			if (AVP_Multiplayer_GameRules::GetTeamLivesOn())
			{
				// Check if any of the teams run out of lives
				Asura_List_It<AVP_Multiplayer_TeamScore> xTeamScoreIt( AVP_Multiplayer_TeamScore::GetList() ); 
				u_int uActiveTeams = 0; 
				while ( !xTeamScoreIt.Done() )
				{
					AVP_Multiplayer_TeamScore* pxTeamScore = xTeamScoreIt.GetCurrent(); 
					if (pxTeamScore)
					{
						int iTeamLives = pxTeamScore->GetNumberOfTeamLives();
						if (iTeamLives <= 0)
						{
							// Check if there are any players alive on this team
							Asura_Hashed_List_ConstIt<AVP_ServerEntity_PlayerInfo> xPlayerInfoConstIt( AVP_ServerEntity_PlayerInfo::GetList() ); 
							while ( !xPlayerInfoConstIt.Done() )
							{
								const AVP_ServerEntity_PlayerInfo* pxPlayerInfo = xPlayerInfoConstIt.GetCurrent(); 
								if (pxPlayerInfo)
								{
									// Check if this player is still active
									// TODO: is this correct? Any player who is spawned it will be controlling a puppet
									if (pxPlayerInfo->GetMultiplayerTeam() == pxTeamScore->GetTeam() && pxPlayerInfo->GetPuppetGuid() != ASURA_GUID_UNREGISTERED)
									{
										// There is a player active in this team, so this team is active
										++uActiveTeams; 
										// We don't want to keep checking players in this team, break the loop
										break; 
									}
								}
								else
								{
									Asura_Assert( pxPlayerInfo, "Invalid player info pointer" ); 
								}
								xPlayerInfoConstIt.Next();
							}
						}
						else
						{
							// This team still has lives remaining, is active
							++uActiveTeams; 
						}

					}
					else
					{
						Asura_Assert(pxTeamScore, "Invalid team score pointer"); 
					}
					xTeamScoreIt.Next(); 
				}

				// Sanity checkings
				Asura_Assert( uActiveTeams > 0, "Unlikely number of active teams, did all people kill each other at the same time?" ); 
				Asura_Assert( uActiveTeams <= AVP_Settings::AVP_NUM_TEAMS, "Unexpected number of active teams, error in the counter or in team score list" ); 

				// Is there only one active team?
				// TODO: is this game rule correctly applied? When there is only one active team, the match should end
				if (uActiveTeams == 1)
				{
					// TODO: this shouldn't be necessary once we have people joining a team game from the lobby and proper 
					// team asssignments
					// Temporarily, check that there is a number of teams playing, to allow a single player in the host to 
					// start a team based game with lives and don't finish it instantly as it is the only active player / team!
					if ( AVP_Multiplayer_TeamScore::GetList().GetNumEntries() > 1 )
					{
						return true; 
					}
				}
			}
		}
	}
	return false; 
}

float AVP_Multiplayer_GameCore::GetMatchTimeLeft( void )
{
	float fMatchTime = Asura_Timers::GetServerAbsoluteTime() - s_fCurrentMatchStartTime;
	float fRemainingMatchTime = static_cast<float>( AVP_Multiplayer_GameRules::GetTimeLimit() * 60 ) - fMatchTime;
	return fRemainingMatchTime;
}

////////////////////////////////////////////////////////////
// List of players
////////////////////////////////////////////////////////////
int AVP_Multiplayer_GameCore::GetNumberOfPlayers()
{
	int iNumberOfPlayers = 0; 
	const Asura_Hashed_List<AVP_ClientEntity_PlayerInfo>* pxPlayerInfoList(AVP_ClientEntity_PlayerInfo::GetList()); 
	if (pxPlayerInfoList)
	{
		iNumberOfPlayers = pxPlayerInfoList->GetNumEntries(); 
	}
	return iNumberOfPlayers; 
}

Asura_Guid AVP_Multiplayer_GameCore::FindNextPlayer(Asura_Guid uCurrentPlayerGuid)
{
	Asura_Guid uNextPlayerGuid = ASURA_GUID_UNREGISTERED; 
	
	int iCurrentPlayerIndex = FindPlayerIndexByGuid(uCurrentPlayerGuid);
	
	if (iCurrentPlayerIndex >= 0)
	{
		int iNumberOfPlayers = GetNumberOfPlayers(); 
		int iNextPlayerIndex = (iCurrentPlayerIndex + 1) % iNumberOfPlayers; 
		uNextPlayerGuid = FindPlayerGuidByIndex(iNextPlayerIndex); 
	}

	return uNextPlayerGuid; 
}

Asura_Guid AVP_Multiplayer_GameCore::FindPreviousPlayer(Asura_Guid uCurrentPlayerGuid)
{
	Asura_Guid uPrevPlayerGuid = ASURA_GUID_UNREGISTERED; 
	
	int iCurrentPlayerIndex = FindPlayerIndexByGuid(uCurrentPlayerGuid);
	
	if (iCurrentPlayerIndex >= 0)
	{
		int iNumberOfPlayers = GetNumberOfPlayers(); 
		int iPrevPlayerIndex = (iCurrentPlayerIndex + iNumberOfPlayers - 1) % iNumberOfPlayers; 
		uPrevPlayerGuid = FindPlayerGuidByIndex(iPrevPlayerIndex); 
	}

	return uPrevPlayerGuid; 
}

Asura_Guid AVP_Multiplayer_GameCore::FindFirstPlayerAlive(void)
{
	Asura_Guid uFirstPlayerGuid = ASURA_GUID_UNREGISTERED; 

	// Iterate through the player list until the end or until the required player is found
	bool bFound = false; 
	Asura_Hashed_List_ConstIt<AVP_ClientEntity_PlayerInfo> xPlayerInfoListContIt(AVP_ClientEntity_PlayerInfo::GetList());
	while (!bFound && !xPlayerInfoListContIt.Done())
	{
		const AVP_ClientEntity_PlayerInfo* pxCurrentPlayerInfo = xPlayerInfoListContIt.GetCurrent();
		if (pxCurrentPlayerInfo)
		{
			uFirstPlayerGuid = pxCurrentPlayerInfo->GetGuid(); 
			Asura_Assert(uFirstPlayerGuid != ASURA_GUID_UNREGISTERED, "unregistered player found in client player info list"); 
			bFound = pxCurrentPlayerInfo->GetPuppetGuid() != ASURA_GUID_UNREGISTERED;
		}
		xPlayerInfoListContIt.Next();
	}

	return uFirstPlayerGuid; 
}

int AVP_Multiplayer_GameCore::FindPlayerIndexByGuid(Asura_Guid uPlayerGuid)
{
	// Check for valid guid
	if (uPlayerGuid == ASURA_GUID_UNREGISTERED) return -1; 

	// Iterate through the player list until the end or until the required player is found
	bool bFound = false; 
	int iIndex = 0; 
	Asura_Hashed_List_ConstIt<AVP_ClientEntity_PlayerInfo> xPlayerInfoListContIt(AVP_ClientEntity_PlayerInfo::GetList());
	while (!bFound && !xPlayerInfoListContIt.Done())
	{
		const AVP_ClientEntity_PlayerInfo* pxCurrentPlayerInfo = xPlayerInfoListContIt.GetCurrent();
		if (pxCurrentPlayerInfo)
		{
			bFound = pxCurrentPlayerInfo->GetGuid() == uPlayerGuid;
		}
		
		if (!bFound)
		{
			++iIndex; 
		}
		xPlayerInfoListContIt.Next();
	}

	// Found it?
	if (bFound)
	{
		return iIndex;
	}

	// It's not in the list
	return -1;
}

Asura_Guid AVP_Multiplayer_GameCore::FindPlayerGuidByIndex(int iRequiredIndex)
{
	// Check for valid index
	int iNumberOfPlayers = GetNumberOfPlayers(); 
	if (iRequiredIndex < 0 || iRequiredIndex >= iNumberOfPlayers) return ASURA_GUID_UNREGISTERED; 

	// Iterate through the player list until we reach the required index
	Asura_Guid uPlayerGuid = ASURA_GUID_UNREGISTERED;
	bool bFound = false;
	int iIndex = 0; 
	Asura_Hashed_List_ConstIt<AVP_ClientEntity_PlayerInfo> xPlayerInfoListContIt(AVP_ClientEntity_PlayerInfo::GetList());
	while (!bFound && !xPlayerInfoListContIt.Done())
	{
		bFound = (iRequiredIndex == iIndex); 
		if (bFound)
		{
			const AVP_ClientEntity_PlayerInfo* pxCurrentPlayerInfo = xPlayerInfoListContIt.GetCurrent();
			if (pxCurrentPlayerInfo)
			{
				uPlayerGuid = pxCurrentPlayerInfo->GetGuid(); 
			}
		}
		else
		{
			++iIndex;
		}
		xPlayerInfoListContIt.Next(); 
	}

	return uPlayerGuid;
}

void AVP_Multiplayer_GameCore::ActivateGameModeNode(int iGameMode)
{
	// Is this the server?
	if (Asura_Network::IsServer())
	{
		// Loop through all game mode nodes for this level
		const Asura_Hashed_List<AVP_ServerEntity_GameMode>* pxGameModeNodeList = AVP_ServerEntity_GameMode::GetList();
		Asura_Hashed_List_It<AVP_ServerEntity_GameMode> xGameModeListIterator( pxGameModeNodeList ); 

		// Find the game type requested
		AVP_Settings::GameType eGameType = static_cast<AVP_Settings::GameType>(iGameMode);
		bool bFound = false; 
		
		while (!xGameModeListIterator.Done())
		{
			AVP_ServerEntity_GameMode* pxGameModeNode = xGameModeListIterator.GetCurrent();
			if (pxGameModeNode->GetGameMode() == eGameType)
			{
				// Found it, make this game mode active
				pxGameModeNode->SendActivateMessage(); 
				bFound = true; 
				break; 
			}
			xGameModeListIterator.Next();
		}
		Asura_Assertf( bFound, ( "Couldn't find game mode entity for game mode %s", AVP_Settings::GetGameTypeName(eGameType) )); 
	}
}

void AVP_Multiplayer_GameCore::DoGameModeSanityChecks()
{
	// Is this the server?
	if (Asura_Network::IsServer())
	{
		// Hunt mode
		if (AVP_Settings::GetGameType() == AVP_Settings::AVP_GAMETYPE_HUNT)
		{
			// Always there should be a hunter
			const Asura_Hashed_List<AVP_ServerEntity_PlayerInfo>* pxPlayerInfoList = AVP_ServerEntity_PlayerInfo::GetList(); 
			Asura_Hashed_List_It<AVP_ServerEntity_PlayerInfo> xPlayerInfoIt( pxPlayerInfoList ); 
			u_int uNumberOfHunters = 0; 

			// Counting the number of hunter players
			// Also checking that the rest of the players are prey
			while (!xPlayerInfoIt.Done())
			{
				AVP_ServerEntity_PlayerInfo* pxCurrentPlayerInfo = xPlayerInfoIt.GetCurrent(); 
				if (pxCurrentPlayerInfo->GetMultiplayerRole() == AVP_Settings::AVP_ROLE_HUNTER)
				{
					++uNumberOfHunters;
				}
				else if (pxCurrentPlayerInfo->GetMultiplayerRole() != AVP_Settings::AVP_ROLE_PREY)
				{
					Asura_Assert(false, "Unexpected multiplayer role, assuming this player is a prey");
					pxCurrentPlayerInfo->SetMultiplayerRole( AVP_Settings::AVP_ROLE_PREY ); 
				}
				xPlayerInfoIt.Next(); 
			}

			if (uNumberOfHunters != 1)
			{
				if (uNumberOfHunters == 0)
				{
					Asura_Assert( false, "No hunter, the last hunter player quit or disconnected? Choosing a new hunter now"); 
					Asura_Guid uNewHunterGuid = FindFirstPlayerAlive(); 
					if (uNewHunterGuid != ASURA_GUID_UNREGISTERED)
					{
						AVP_ServerEntity_PlayerInfo* pxNewHunterPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( uNewHunterGuid ); 
						if (pxNewHunterPlayerInfo)
						{
							pxNewHunterPlayerInfo->SetMultiplayerRole(AVP_Settings::AVP_ROLE_HUNTER); 
							AVP_ServerEntity_Actor* pxNewHunterActor = AVP_ServerEntity_Actor::FindEntity( pxNewHunterPlayerInfo->GetPuppetGuid() ); 

							pxNewHunterPlayerInfo->SetPuppetGuid(ASURA_GUID_UNREGISTERED);
							if (pxNewHunterActor)
							{
								pxNewHunterActor->SetEntityActive(false);
							}
						}
					}
				}
				else
				{
					Asura_Assert( uNumberOfHunters <= 1, "Too many hunters! This is completely unexpected, please report as multiplayer bug"); 
				}
			}
		}

		// Survivor mode
		if (AVP_Settings::GetGameType() == AVP_Settings::AVP_GAMETYPE_SURVIVOR)
		{
			// Always there should be a hunter
			const Asura_Hashed_List<AVP_ServerEntity_PlayerInfo>* pxPlayerInfoList = AVP_ServerEntity_PlayerInfo::GetList(); 
			Asura_Hashed_List_It<AVP_ServerEntity_PlayerInfo> xPlayerInfoIt( pxPlayerInfoList ); 
			u_int uNumberOfHunters = 0;
			u_int uNumberOfPreys = 0; 

			// Counting the number of hunter and prey players
			while (!xPlayerInfoIt.Done())
			{
				AVP_ServerEntity_PlayerInfo* pxCurrentPlayerInfo = xPlayerInfoIt.GetCurrent(); 
				if (pxCurrentPlayerInfo->GetMultiplayerRole() == AVP_Settings::AVP_ROLE_HUNTER)
				{
					++uNumberOfHunters;
				}
				else if (pxCurrentPlayerInfo->GetMultiplayerRole() == AVP_Settings::AVP_ROLE_PREY)
				{
					++uNumberOfPreys; 
				}
				else
				{
					Asura_Assert(false, "Unexpected multiplayer role, assuming this player is a prey");
					pxCurrentPlayerInfo->SetMultiplayerRole( AVP_Settings::AVP_ROLE_PREY ); 
					++uNumberOfPreys; 
				}
				xPlayerInfoIt.Next(); 
			}

			if (uNumberOfHunters == 0)
			{
				Asura_Assert( false, "No hunter, the last hunter player quit or disconnected? Choosing a new hunter now"); 
				Asura_Guid uNewHunterGuid = FindFirstPlayerAlive(); 
				if (uNewHunterGuid != ASURA_GUID_UNREGISTERED)
				{
					AVP_ServerEntity_PlayerInfo* pxNewHunterPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( uNewHunterGuid ); 
					if (pxNewHunterPlayerInfo)
					{
						pxNewHunterPlayerInfo->SetMultiplayerRole(AVP_Settings::AVP_ROLE_HUNTER); 
						AVP_ServerEntity_Actor* pxNewHunterActor = AVP_ServerEntity_Actor::FindEntity( pxNewHunterPlayerInfo->GetPuppetGuid() ); 

						pxNewHunterPlayerInfo->SetPuppetGuid(ASURA_GUID_UNREGISTERED);
						if (pxNewHunterActor)
						{
							pxNewHunterActor->SetEntityActive(false);
						}
					}
				}
			}

			u_int uNumberOfPlayers = pxPlayerInfoList->GetNumEntries(); 
			// TODO: there are some limit conditions here I'm relaxing to allow hosting games during development 
			if (uNumberOfPreys == 0 && uNumberOfPlayers > 1)
			{
				// Calculate score for this round
				AVP_Multiplayer_InverseSurvivorRank::UpdatePlayersScoreOnRoundEnd();

				// Start a new round
				xPlayerInfoIt.Restart(); 
				u_int uPlayerIndex = 0; 
				
				// TODO: better arbitration than randomly choosing the next hunter
				u_int uNewPlayerHunterIndex = Asura_Random::GetIntU(0, uNumberOfPlayers - 1); 

				// Deactivate all player puppets, assign new roles for the next round
				while (!xPlayerInfoIt.Done())
				{
					AVP_ServerEntity_PlayerInfo* pxCurrentPlayerInfo = xPlayerInfoIt.GetCurrent();
					if (pxCurrentPlayerInfo)
					{
						pxCurrentPlayerInfo->SetMultiplayerRole(AVP_Settings::AVP_ROLE_PREY); 
						if (uPlayerIndex == uNewPlayerHunterIndex)
						{
							pxCurrentPlayerInfo->SetMultiplayerRole(AVP_Settings::AVP_ROLE_HUNTER); 
						}
					}

					AVP_ServerEntity_Actor* pxCurrentActor = AVP_ServerEntity_Actor::FindEntity( pxCurrentPlayerInfo->GetPuppetGuid() ); 
					if (pxCurrentActor)
					{
						pxCurrentActor->SetEntityActive( false ); 
					}
					
					pxCurrentPlayerInfo->SetPuppetGuid( ASURA_GUID_UNREGISTERED );

					xPlayerInfoIt.Next(); 
					++uPlayerIndex; 
				}
			}
		}
	}
}

////////////////////////////////////////////////////////////
//  Multiplayer game events
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//  NAME     :  OnActorGetsKilled()
//  CREATED  :  JG (1.8.2008)
//  DESC     :  Updates multiplayer info when an actor gets killed, mostly score
//				but also team lives, new species / role etc.
////////////////////////////////////////////////////////////////////////////////
void AVP_Multiplayer_GameCore::OnActorGetsKilled( Asura_Guid uExecutorGuid, Asura_Guid uVictimGuid )
{
	// Only the server can update the scoreboard
	if ( !Asura_Network::IsServer() )
	{
		Asura_Assert(false, "Trying to update score board from a client, it shouldn't be doing that"); 
		return; 
	}

	AVP_ServerEntity_Actor* pxVictimActor = AVP_ServerEntity_Actor::FindEntity( uVictimGuid ); 
	if (pxVictimActor)
	{
		// Only score when killing a player
		if (pxVictimActor->IsPlayer())
		{
			// We are an actor, and we have been killed
			// Find player info
			AVP_ServerEntity_PlayerInfo* pxVictimPlayerInfo = AVP_ServerEntity_PlayerInfo::GetList()->FindEntity( pxVictimActor->GetPlayerInfoGuid() ); 

			if (pxVictimPlayerInfo)			
			{
				// Get the score information for that player and update it
				AVP_Multiplayer_PlayerScore& xVictimPlayerScore = pxVictimPlayerInfo->GetPlayerScore(); 
				xVictimPlayerScore.SetNumberOfTimesKilled( xVictimPlayerScore.GetNumberOfTimesKilled() + 1 ); 
			}
			else
			{
				Asura_Assert(pxVictimPlayerInfo, "A player with no player info, this doesn't look right" );
				return; 
			}

			// Find if we were killed by a 'hazard', any damage that is not registered with any actor / player
			// will fall in this category and won't count for score calculations
			if (uExecutorGuid != ASURA_GUID_UNREGISTERED)
			{
				// Find who killed us
				AVP_ServerEntity_Actor* pxExecutorActor = AVP_ServerEntity_Actor::FindEntity( uExecutorGuid ); 
				if (pxExecutorActor)
				{
					// Did a player kill another player?
					if (pxExecutorActor->IsPlayer() && pxVictimActor->IsPlayer())
					{
						// Find the executor player info
						AVP_ServerEntity_PlayerInfo* pxExecutorPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( pxExecutorActor->GetPlayerInfoGuid() ); 
						if (pxExecutorPlayerInfo)
						{
							// Another kill! Update our score information
							AVP_Multiplayer_PlayerScore& xExecutorPlayerScore = pxExecutorPlayerInfo->GetPlayerScore(); 
							bool bKillCountsForStats = true;

							// Get the species for both players
							AVP_Settings::Species eExecutorSpecies = pxExecutorActor->GetSpeciesByClassification(); 
							AVP_Settings::Species eVictimSpecies = pxVictimActor->GetSpeciesByClassification(); 
							
							// Get the team for both players
							AVP_Settings::Team eExecutorTeam = pxExecutorPlayerInfo->GetMultiplayerTeam(); 
							AVP_Settings::Team eVictimTeam = pxVictimPlayerInfo->GetMultiplayerTeam(); 	
							
							int iScoreIncrement = 0; 
							AVP_Multiplayer_ScoreRules* pxScoreTable = AVP_Multiplayer_ScoreRules::GetScoreTable( eExecutorSpecies, AVP_Settings::GetGameType() ); 
							
							// Check that the player didn't kill himself
							if ( uExecutorGuid == uVictimGuid )
							{
								// Suicide kill
								bKillCountsForStats = false; 
								iScoreIncrement = pxScoreTable->GetScoreKillYourself(); 
							}
							else if ( AVP_Multiplayer_GameRules::IsTeamBasedGame() && eExecutorTeam == eVictimTeam )
							{
								// Kill a team mate 
								bKillCountsForStats = false; 
								iScoreIncrement = pxScoreTable->GetScoreKillTeammate();
							}
							else if ( AVP_Multiplayer_GameRules::IsDominationBasedGame() )
							{
								// Domination score rules are different
								
								// Sanity checkings 
								Asura_Assert( eExecutorTeam != AVP_Settings::AVP_TEAM_NONE, "Invalid executor team" ); 
								Asura_Assert( eVictimTeam != AVP_Settings::AVP_TEAM_NONE, "Invalid victim team" ); 
								Asura_Assert( eExecutorTeam != eVictimTeam, "Unhandled friendly kill" );

								// Hunter kills
								if (eExecutorTeam == AVP_Settings::AVP_TEAM_THREE)
								{
									// Check for winning team 
									// Team 1 and Team 2 score
									AVP_Multiplayer_TeamScore* pxTeamOneScore = AVP_Multiplayer_TeamScore::FindTeamScore( AVP_Settings::AVP_TEAM_ONE ); 
									AVP_Multiplayer_TeamScore* pxTeamTwoScore = AVP_Multiplayer_TeamScore::FindTeamScore( AVP_Settings::AVP_TEAM_TWO ); 
									int iTeamOneScore = 0; 
									int iTeamTwoScore = 0;
									if (pxTeamOneScore)
									{
										iTeamOneScore = pxTeamOneScore->GetTeamScore(); 
									}
									else
									{
										Asura_Assert( false, "Couldn't find team score for team 1" ); 
									}
									if (pxTeamTwoScore)
									{
										iTeamTwoScore = pxTeamTwoScore->GetTeamScore(); 
									}
									else
									{
										Asura_Assert( false, "Couldn't find team score for team 2" ); 
									}

									// Target team: AVP_TEAM_NONE means any team is our target
									// Otherwise, the team winning this match is our target
									AVP_Settings::Team eTargetTeam = AVP_Settings::AVP_TEAM_NONE; 
									if (iTeamOneScore > iTeamTwoScore)
									{
										eTargetTeam = AVP_Settings::AVP_TEAM_ONE; 
									}
									else if (iTeamTwoScore > iTeamOneScore)
									{
										eTargetTeam = AVP_Settings::AVP_TEAM_TWO; 
									}

									if (eTargetTeam == AVP_Settings::AVP_TEAM_NONE || eVictimTeam == eTargetTeam)
									{
										// Get the score based on both species (executor and victim)
										iScoreIncrement = pxScoreTable->GetScoreKillSpecies( eVictimSpecies ); 
									}
									else
									{
										// At the moment, consider this as killing a friendly and apply the penalty
										iScoreIncrement = pxScoreTable->GetScoreKillTeammate(); 
									}
								}
								else
								{
									// Get the score based on both species (executor and victim)
									iScoreIncrement = pxScoreTable->GetScoreKillSpecies( eVictimSpecies ); 
								}							
							}
							else if ( AVP_Settings::GetGameType() == AVP_Settings::AVP_GAMETYPE_HUNT )
							{
								AVP_Settings::Role eExecutorRole = pxExecutorPlayerInfo->GetMultiplayerRole(); 
								AVP_Settings::Role eVictimRole = pxVictimPlayerInfo->GetMultiplayerRole();

								// Sanity checkings
								Asura_Assert(eExecutorRole != AVP_Settings::AVP_ROLE_NORMAL, "Unexpected executor role"); 
								Asura_Assert(eVictimRole != AVP_Settings::AVP_ROLE_NORMAL, "Unexpected victim role"); 

								// Generally kills don't count for stats in this game mode
								bKillCountsForStats = false; 

								if (eExecutorRole == AVP_Settings::AVP_ROLE_HUNTER &&
									eVictimRole == AVP_Settings::AVP_ROLE_PREY)
								{
									// Hunter scores
									iScoreIncrement = pxScoreTable->GetScoreKillSpecies(eVictimSpecies); 
									iScoreIncrement += AVP_Multiplayer_GameRules::GetPlayerScoreHunterKillPrimaryPreyBonus(); 
									bKillCountsForStats = true; 

								}
								else if (eExecutorRole == AVP_Settings::AVP_ROLE_PREY &&
	  									 eVictimRole == AVP_Settings::AVP_ROLE_HUNTER)
								{
									// Swap roles
									pxExecutorPlayerInfo->SetMultiplayerRole(AVP_Settings::AVP_ROLE_HUNTER); 
									pxVictimPlayerInfo->SetMultiplayerRole(AVP_Settings::AVP_ROLE_PREY); 
									
									// TODO: better transition from prey to hunter, at the moment you just dissapear and respawn
									// leaving no corpse behind 
									pxExecutorPlayerInfo->SetPuppetGuid(ASURA_GUID_UNREGISTERED);
									pxExecutorActor->SetEntityActive(false);

									// Prey scores
									iScoreIncrement = pxScoreTable->GetScoreKillSpecies(eVictimSpecies); 
									iScoreIncrement += AVP_Multiplayer_GameRules::GetPlayerScorePreyKillHunterBonus();
									bKillCountsForStats = true; 
								}
							}
							else if ( AVP_Settings::GetGameType() == AVP_Settings::AVP_GAMETYPE_SURVIVOR )
							{
								AVP_Settings::Role eExecutorRole = pxExecutorPlayerInfo->GetMultiplayerRole(); 
								AVP_Settings::Role eVictimRole = pxVictimPlayerInfo->GetMultiplayerRole();

								// Sanity checkings
								Asura_Assert(eExecutorRole != AVP_Settings::AVP_ROLE_NORMAL, "Unexpected executor role"); 
								Asura_Assert(eVictimRole != AVP_Settings::AVP_ROLE_NORMAL, "Unexpected victim role"); 

								// Generally kills don't count for stats in this game mode
								bKillCountsForStats = false; 

								if (eExecutorRole == AVP_Settings::AVP_ROLE_HUNTER &&
									eVictimRole == AVP_Settings::AVP_ROLE_PREY)
								{
									// Hunter scores
									iScoreIncrement = pxScoreTable->GetScoreKillSpecies(eVictimSpecies); 
									iScoreIncrement += AVP_Multiplayer_GameRules::GetPlayerScoreHunterKillPrimaryPreyBonus(); 
									bKillCountsForStats = true; 
									
									// New role for the victim, becomes a hunter
									pxVictimPlayerInfo->SetMultiplayerRole(AVP_Settings::AVP_ROLE_HUNTER); 

									// Update survivor rank for this victim
									AVP_Multiplayer_InverseSurvivorRank::AddPlayerToInverseRank( pxVictimPlayerInfo->GetGuid() ); 
								}
								else if (eExecutorRole == AVP_Settings::AVP_ROLE_PREY &&
	  									 eVictimRole == AVP_Settings::AVP_ROLE_HUNTER)
								{
									// Prey scores
									iScoreIncrement = pxScoreTable->GetScoreKillSpecies(eVictimSpecies); 
									iScoreIncrement += AVP_Multiplayer_GameRules::GetPlayerScorePreyKillHunterBonus();
									bKillCountsForStats = true; 
								}
							}
							else
							{
								// Get the score based on both species (executor and victim)
								iScoreIncrement = pxScoreTable->GetScoreKillSpecies( eVictimSpecies ); 
							}
							// Update individual score
							xExecutorPlayerScore.SetIndividualScore( xExecutorPlayerScore.GetIndividualScore() + iScoreIncrement ); 
							if (AVP_Multiplayer_GameRules::IsTeamBasedGame() && AVP_Multiplayer_GameRules::GetTeamScoreKillsAddToScore())
							{
								// Add this kill / penalty to the team score
								// TODO: maybe should move this into bKillCountForStats to avoid substracting from the team score, seems a little
								// bit unfair, or maybe clamp negative scores to zero
								AVP_Multiplayer_TeamScore* pxExecutorTeamScore = AVP_Multiplayer_TeamScore::FindTeamScore( eExecutorTeam ); 
								if (pxExecutorTeamScore)
								{
									pxExecutorTeamScore->SetTeamScore( pxExecutorTeamScore->GetTeamScore() + iScoreIncrement ); 
								}
								else
								{
									Asura_Assert( false, "Couldn't find executor team score, wrong game type?" ); 
								}
							}
							
							if (bKillCountsForStats)
							{
								if (AVP_Multiplayer_GameRules::GetPersecutorModeOn())
								{
									// Update the kill counter for the executor player 
									Asura_Hashed_List<AVP_Multiplayer_KillCounter>& xExecutorKillCounterList = pxExecutorPlayerInfo->GetKillCounterList(); 
									AVP_Multiplayer_KillCounter* pxExecutorKillCounter = xExecutorKillCounterList.FindEntity( pxVictimPlayerInfo->GetGuid() ); 
									if (!pxExecutorKillCounter)
									{
										// This is the first time we kill this player, create a new kill counter for it
										pxExecutorKillCounter = new AVP_Multiplayer_KillCounter( pxVictimPlayerInfo->GetGuid() ); 
										pxExecutorKillCounter->SetNumberOfKills( 0 ); 
										xExecutorKillCounterList.AddToList( pxExecutorKillCounter ); 
									}

									// We've killed this player again, update the relevant counter
									pxExecutorKillCounter->SetNumberOfKills( pxExecutorKillCounter->GetNumberOfKills() + 1 ); 

									// Also, reset the kill counter the victim could have for the executor
									Asura_Hashed_List<AVP_Multiplayer_KillCounter>& xVictimKillCounterList = pxVictimPlayerInfo->GetKillCounterList(); 
									AVP_Multiplayer_KillCounter* pxVictimKillCounter = xVictimKillCounterList.FindEntity( pxExecutorPlayerInfo->GetGuid() ); 

									if (pxVictimKillCounter)
									{
										pxVictimKillCounter->Reset();
									}
									else
									{
										// This is fine, the victim hasn't killed us yet
										// Nothing to reset
									}
									
									// Check if we are becoming persecutor after killing this player
									int iNewKillCounter = pxExecutorKillCounter->GetNumberOfKills();
									if (iNewKillCounter >= AVP_Multiplayer_GameRules::GetKillsNeededToPersecute())
									{
										// Yes, let the victim know
										pxVictimPlayerInfo->SetPersecutorGuid( pxExecutorPlayerInfo->GetGuid() ); 
									}

									// Check if the victim was persecuting the executor
									if (pxExecutorPlayerInfo->GetPersecutorGuid() == pxVictimPlayerInfo->GetGuid())
									{
										// Revenge, at last!
										xExecutorPlayerScore.SetIndividualScore( xExecutorPlayerScore.GetIndividualScore() 
											+ pxScoreTable->GetScoreKillPersecutorBonus() );

										// Finish the relationship between this two players
										pxExecutorPlayerInfo->SetPersecutorGuid( ASURA_GUID_UNREGISTERED );
									}
								}

								// Update the number of kills as species for the executor
								switch (eExecutorSpecies)
								{
									case AVP_Settings::AVP_SPECIES_ALIEN:
									{
										xExecutorPlayerScore.SetNumberOfKillsAsAlien( xExecutorPlayerScore.GetNumberOfKillsAsAlien() + 1 ); 
										break;
									}
									case AVP_Settings::AVP_SPECIES_PREDATOR:
									{
										xExecutorPlayerScore.SetNumberOfKillsAsPredator( xExecutorPlayerScore.GetNumberOfKillsAsPredator() + 1 ); 
										break;
									}
									case AVP_Settings::AVP_SPECIES_HUMAN:
									default:
									{
										xExecutorPlayerScore.SetNumberOfKillsAsMarine( xExecutorPlayerScore.GetNumberOfKillsAsMarine() + 1 ); 
									}
								}

								// Update the executor actor kill streak
								pxExecutorActor->SetKillStreak( pxExecutorActor->GetKillStreak() + 1 ); 

								// Check if the new kill streak is better than the previous one
								if (pxExecutorActor->GetKillStreak() > xExecutorPlayerScore.GetKillStreak())
								{
									// Yes, we've got a new higher kill streak, update accordingly
									xExecutorPlayerScore.SetKillStreak( pxExecutorActor->GetKillStreak() ); 
								}
							}
						}
						else
						{
							Asura_Assert(pxExecutorPlayerInfo, "This actor was killed by a player with no player info, this doesn't look right"); 
						}
					}
				}
			}

			// Check for kill assists
			Asura_Guid uActorGuidMaxDamage = ASURA_GUID_UNREGISTERED; 
			float fMaxDamage = 0.0f; 

			const Asura_Hashed_List<AVP_Multiplayer_DamageCounter>* pxReceivedDamageList = pxVictimActor->GetReceivedDamageList(); 
			if (pxReceivedDamageList)
			{
				// Find the actor who dealt more damage to the victim 
				// (and is not the executor)
				Asura_Hashed_List_ConstIt<AVP_Multiplayer_DamageCounter> xReceivedDamageListConstIt( pxReceivedDamageList );
				while (!xReceivedDamageListConstIt.Done())
				{
					const AVP_Multiplayer_DamageCounter* pxDamageCounter = xReceivedDamageListConstIt.GetCurrent();
					if (pxDamageCounter->GetDamage() > fMaxDamage && pxDamageCounter->GetGuid() != uExecutorGuid )
					{
						uActorGuidMaxDamage = pxDamageCounter->GetGuid();
						fMaxDamage = pxDamageCounter->GetDamage(); 
					}
					xReceivedDamageListConstIt.Next(); 
				}
			}

			// TODO: check that the kill assist is valid (i.e. not members of the same team, not a suicide...)
			
			// Find the player info from the actor who assisted in this kill 
			AVP_ServerEntity_Actor* pxKillAssistantActor = AVP_ServerEntity_Actor::FindEntity( uActorGuidMaxDamage );
			if (pxKillAssistantActor)
			{
				// This should always be true, as we check when constructing the damage list, but just in case something
				// went wrong
				if (pxKillAssistantActor->IsPlayer())
				{
					AVP_ServerEntity_PlayerInfo* pxKillAssistantPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( pxKillAssistantActor->GetPlayerInfoGuid() ); 
					if (pxKillAssistantPlayerInfo)
					{
						// Update the score, add the number of kill assists
						AVP_Multiplayer_PlayerScore& xKillAssistantPlayerScore = pxKillAssistantPlayerInfo->GetPlayerScore(); 
						AVP_Settings::Species eExecutorSpecies = pxKillAssistantActor->GetSpeciesByClassification(); 
						AVP_Multiplayer_ScoreRules* pxScoreTable = AVP_Multiplayer_ScoreRules::GetScoreTable( eExecutorSpecies, AVP_Settings::GetGameType() ); 
						xKillAssistantPlayerScore.SetNumberOfKillAssists( xKillAssistantPlayerScore.GetNumberOfKillAssists() + 1 ); 
						xKillAssistantPlayerScore.SetIndividualScore( 
							xKillAssistantPlayerScore.GetIndividualScore() + pxScoreTable->GetScoreKillAssist() ); 
					}
					else
					{
						Asura_Assert( false, "An actor registered damage but it hasn't got player info associated" ); 
					}
				}
				else
				{
					Asura_Assert( false, "This actor registered damage from an actor who is not a player, that shouldn't happen" ); 
				}
			}
			else
			{
				// Maybe is dead, there is nothing we can do in that case as we don't know who was controlling this actor
				// TODO: find the next candidate?
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
//  NAME     :  OnActorPerformsSpecialKill()
//  CREATED  :  JG (27.8.2008)
//  DESC     :  Update the score board when an actor performs a special kill
//				(i.e. trophy kill, head bite)
////////////////////////////////////////////////////////////////////////////////
void AVP_Multiplayer_GameCore::OnActorPerformsSpecialKill(Asura_Guid uExecutorGuid)
{
	// Only the server can update the scoreboard
	if ( !Asura_Network::IsServer() )
	{
		Asura_Assert(false, "Trying to update score board from a client, it shouldn't be doing that"); 
		return; 
	}

	AVP_ServerEntity_Actor* pxExecutorActor = AVP_ServerEntity_Actor::FindEntity( uExecutorGuid ); 
	if (pxExecutorActor)
	{
		// Only update the score for players
		if (pxExecutorActor->IsPlayer())
		{
			// Find player info
			AVP_ServerEntity_PlayerInfo* pxExecutorPlayerInfo = AVP_ServerEntity_PlayerInfo::GetList()->FindEntity( pxExecutorActor->GetPlayerInfoGuid() ); 
			if (pxExecutorPlayerInfo)			
			{
				// Get an accessor to this player score
				AVP_Multiplayer_PlayerScore& xExecutorPlayerScore = pxExecutorPlayerInfo->GetPlayerScore(); 

				// Find the executor player species
				AVP_Settings::Species eExecutorSpecies = pxExecutorActor->GetSpeciesByClassification(); 

				switch( eExecutorSpecies )
				{
				case AVP_Settings::AVP_SPECIES_PREDATOR:
					{
						// Another trophy kill
						xExecutorPlayerScore.SetNumberOfTrophies( xExecutorPlayerScore.GetNumberOfTrophies() + 1 ); 
						break; 
					}
					case AVP_Settings::AVP_SPECIES_ALIEN:
					{
						// Another head bite
						xExecutorPlayerScore.SetNumberOfHeadbites( xExecutorPlayerScore.GetNumberOfHeadbites() + 1 ); 
						break; 
					}
					case AVP_Settings::AVP_SPECIES_HUMAN:
					default:
					{
						// Another headshot
						xExecutorPlayerScore.SetNumberOfHeadshots( xExecutorPlayerScore.GetNumberOfHeadshots() + 1 ); 
						break; 
					}
				}
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
//  CLASS    :  AVP_Multiplayer_ScoreBoard
//  NAME     :  OnActorCapturesCommandPost()
//  CREATED  :  JG (20.1.2009)
//  DESC     :  Updates the score board when a CP gets captured
////////////////////////////////////////////////////////////////////////////////
void AVP_Multiplayer_GameCore::OnActorCapturesCommandPost(Asura_Guid uCapturerGuid)
{
	// Only the server can update the scoreboard
	if ( !Asura_Network::IsServer() )
	{
		Asura_Assert(false, "Trying to update score board from a client, it shouldn't be doing that"); 
		return; 
	}

	AVP_ServerEntity_Actor* pxCapturerActor = AVP_ServerEntity_Actor::FindEntity( uCapturerGuid ); 
	if (pxCapturerActor)
	{
		// Only update the score for players
		if (pxCapturerActor->IsPlayer())
		{
			// Find player info
			AVP_ServerEntity_PlayerInfo* pxCapturerPlayerInfo = AVP_ServerEntity_PlayerInfo::GetList()->FindEntity( pxCapturerActor->GetPlayerInfoGuid() ); 
			if (pxCapturerPlayerInfo)			
			{
				// Get an accessor to this player score
				AVP_Multiplayer_PlayerScore& xCapturerPlayerScore = pxCapturerPlayerInfo->GetPlayerScore(); 

				// Update the score
				xCapturerPlayerScore.SetIndividualScore( xCapturerPlayerScore.GetIndividualScore() + AVP_Multiplayer_GameRules::GetPlayerScoreCaptureControlPoint() ); 
			}
		}
	}
}
