//=============================================================================
// DeathMatchGame.
//=============================================================================
class DeathMatchGame expands UnrealGameInfo
	config;

var() config bool	bNoExit; //FIXME - USE - disallow level changes by non-admin
var() config int	MaxPlayers; 
var   int			NumPlayers;
var() config int	FragLimit; 
var() config int	TimeLimit; // time limit in minutes
var() config bool	bCoopWeaponMode;

event playerpawn Login
(
	string[32]     Portal,
	string[120]    Options,
	out string[80] Error,
	class          SpawnClass
)
{
	local playerpawn NewPlayer;

	if ( (MaxPlayers > 0) && (NumPlayers >= MaxPlayers) )
		return None;
	
	NewPlayer = CallParent.Login(Portal, Options, Error, SpawnClass );
	if ( NewPlayer != None )
		NumPlayers++;

	return NewPlayer;
}

function Logout(pawn Exiting)
{
	CallParent.Logout(Exiting);
	NumPlayers--;
}
	
function Timer()
{
	if ( (TimeLimit > 0) && (60 * TimeLimit > Level.TimeSeconds - StartTime) )
		EndGame();
}

/* FindPlayerStart()
returns the 'best' player start for this player to start from.
Re-implement for each game type
*/
function NavigationPoint FindPlayerStart(optional byte Team, optional string[32] incomingName)
{
	local PlayerStart Dest, Candidate[5], Best;
	local float Score[5], BestScore, NextDist;
	local pawn OtherPlayer;
	local int i, num;
	local Teleporter Tel;

	if( incomingName!="" )
		foreach AllActors( class 'Teleporter', Tel )
			if( string(Tel.Tag)~=incomingName )
				return Tel;

	num = 0;
	//choose candidates	
	foreach AllActors( class 'PlayerStart', Dest )
	{
		if (num<5)
			Candidate[num] = Dest;
		else if (Rand(num) < 5)
			Candidate[Rand(5)] = Dest;
		num++;
	}
	
	if (num>5) num = 5;
	else if (num == 0)
		return None;
		
	//assess candidates
	for (i=0;i<num;i++)
		Score[i] = 4000 * FRand(); //randomize
		
	foreach AllActors( class 'Pawn', OtherPlayer )
		if (OtherPlayer.bIsPlayer)
			for (i=0;i<num;i++)
			{
				NextDist = Size(OtherPlayer.Location - Candidate[i].Location);
				Score[i] += NextDist;
				if (NextDist < CollisionRadius + CollisionHeight)
					Score[i] -= 1000000.0;
				else if (OtherPlayer.LineOfSightTo(Candidate[i]))
					Score[i] -= 2000.0;
			}
	
	BestScore = Score[0];
	Best = Candidate[0];
	for (i=1;i<num;i++)
		if (Score[i] > BestScore)
		{
			BestScore = Score[i];
			Best = Candidate[i];
		}

	return Best;
}

/* AcceptInventory()
Examine the passed player's inventory, and accept or discard each item
* AcceptInventory needs to gracefully handle the case of some inventory
being accepted but other inventory not being accepted (such as the default
weapon).  There are several things that can go wrong: A weapon's
AmmoType not being accepted but the weapon being accepted -- the weapon
should be killed off. Or the player's selected inventory item, active
weapon, etc. not being accepted, leaving the player weaponless or leaving
the HUD inventory rendering messed up (AcceptInventory should pick another
applicable weapon/item as current).
*/
function AcceptInventory(pawn PlayerPawn)
{
	//deathmatch accepts no inventory
	local inventory Inv;
	for( Inv=PlayerPawn.Inventory; Inv!=None; Inv=Inv.Inventory )
		Inv.Destroy();
	PlayerPawn.Weapon = None;
	PlayerPawn.SelectedItem = None;
	AddDefaultInventory( PlayerPawn );
}

function ChangeName(Pawn Other, coerce string[32] S, bool bNameChange)
{
	local pawn APlayer;

	if ( S == "" )
		return;

	if (Other.PlayerName~=S)
		return;
		
	ForEach AllActors(class 'Pawn', APlayer)
		if ( APlayer.bIsPlayer && (APlayer.PlayerName~=S) )
		{
			Other.ClientMessage(S$" is already in use");
			return;
		}

	if (bNameChange)
		BroadcastMessage(Other.PlayerName$" changed name to "$S);
			
	Other.PlayerName = S;
}

function bool ShouldRespawn(Actor Other)
{
	if ( bCoopWeaponMode && Other.IsA('Weapon') )
	{
		Inventory(Other).ReSpawnTime = 1.0;
		return true;
	}
	return ( (Inventory(Other) != None) && (Inventory(Other).ReSpawnTime!=0.0) );
}

function bool CanSpectate( pawn Viewer, actor ViewTarget )
{
	return ( Spectator(Viewer) != None );
}

// Called when this pawn he has a chance to pick Item up (i.e. when 
// the pawn touches a weapon pickup). The pawn should return true if 
// he wants to pick it up, false if he does not want it.
//
// Note that Item is not in this pawn's inventory when this function is 
// called, and this pawn should not do anything with Item.

function bool PickupQuery(Pawn Other, Inventory item)
{
	if ( bCoopWeaponMode && item.IsA('Weapon') && (Other.FindInventoryType(item.class) != None) )
		return false;
	else
		return CallParent.PickupQuery(Other, item);
}

// Monitor killed messages for fraglimit
function Killed(pawn killer, pawn Other, name damageType)
{
	CallParent.Killed(killer, Other, damageType);

	if ( (FragLimit > 0) && (killer.Score >= FragLimit) )
		EndGame();
}	

