// SiegeGI.
// * Revised by nOs*Badger
// * Extended by WILDCARD
//=============================================================================
class SiegeGI extends TeamGamePlus config(SiegeUltimateRC7UB01);

var sgRURecovery    RURecovery;
var config float    NumResources;
var config float    MaxCoreSnipeDistance;
var config int      MaxSiegeTeams;
//var config int		MaxRUresources;

// Special Options
var config bool debug;
var config bool AllowMultiGunning;

// The Map Specific List
var config vector RandomSpawnerLocation[64];
var config string RandomSpawnerMap[64];

var bool CheckedRandomSpawner;

var float           MaxRUs[4];
var globalconfig string Weapons[17];

var() class<Weapon> WeaponClasses[17];
var sgBaseCore      Cores[4];

var config string   SpecIPs[32];
var config bool     bPreventSpectate;
var config bool     bFactoryRU;

// Cheat settings

var bool            FreeBuild;
var bool	    SupplierProtection;
var bool	    bStartedPlay;
var config float    StartingMaxRU,
                    StartingRU;

// Did we sucessfully Spawn a RandomSpawner actor sucessfully?
var bool SpawnedRandomItemSpawner;

// This is for the new Monster Madness mutator SiegeUltimateRC7 has to offer
var bool MonsterMadness;
var int MonstersLeft;

replication
{
    // Things the server should send to the client.
    reliable if ( Role == ROLE_Authority )
        MaxRUs;
	/*	
    reliable if ( Role <= ROLE_Authority )
        MonsterMadness, MonstersLeft;
	*/
}



function PrebeginPlay()
{
 local Actor A;
 local string LevelS, BrushS, BrushClassCheckS;
 
 super.PrebeginPlay();
 
 LevelS=Left( String(Level), InStr(string(Level), "."));
 ForEach AllActors(class'Actor',A)
 {
  if( Left( string(A.class), Len(LevelS)+1 ) ~= (LevelS$".") ) 
  {
   BrushS = Mid( string(A.class), Len(LevelS)+1 );
   if( Left( BrushS, 5 ) ~= "Brush" ) 
   {
    BrushClassCheckS=Left( Mid(BrushS, 5), 1 );
    if( InStr( "0123456789", BrushClassCheckS ) != -1 ) 
    {
     Consolecommand("Set"@LevelS$"."$BrushS@"bNoDelete False");
     Consolecommand("Set"@LevelS$"."$BrushS@"bStatic False");
     A.Destroy();
    }
   }
  }
 }
 
}


function InitGame(string options, out string error)
{
    local Actor f;
	local Inventory SuperItem;
    local sgBaseCore b;
    local int team;
    local WildcardsResources resources;
    local string opt;
    local int i, Redeemers, DamageAmps, ShieldBelts, Invisibilitys, BigKegOfHealths;
	local WarheadLauncher WLT;
	local UDamage UDT;
	local UT_Shieldbelt SBT;
	local UT_Invisibility IVT;
	local HealthPack HPK;
	local WildcardsResources WRU;

	GameName="Siege Ultimate";
    Super.InitGame(options, error);

    opt = ParseOption(options, "FreeBuild");
    if ( opt == "1" || opt ~= "true" )
        FreeBuild = true;

    MaxRUs[0] = StartingMaxRU;
    MaxRUs[1] = StartingMaxRU;
    MaxRUs[2] = StartingMaxRU;
    MaxRUs[3] = StartingMaxRU;

    //MaxTeams = 2;
    MaxSiegeTeams = Clamp(MaxSiegeTeams, 0, 4);

    foreach AllActors( class'Actor', f)
    {
        if ( FlagBase(f) != None /*&& MaxRUresources == 444*/)
        {
	
            if ( FlagBase(f).Team >= 0 && FlagBase(f).Team < MaxSiegeTeams &&
              cores[FlagBase(f).Team] == None )
            {
                b = Spawn(class'sgBaseCore',,, f.Location);
                if ( b != None )
                {
                    b.Team = FlagBase(f).Team;
                    MaxTeams = Max(MaxTeams, b.Team+1);
                    Cores[b.Team] = b;
                }
                else
                    log("SiegeGI: Failed to spawn BaseCore for team"@
                      FlagBase(f).Team$"!");
            }
        }
		// Count Super Items
		if ( WarheadLauncher(f) != None )
			Redeemers++;
		else if ( UDamage(f) != None )
			DamageAmps++;
		else if ( UT_Shieldbelt(f) != None )
			ShieldBelts++;
		else if ( UT_Invisibility(f) != None )
			Invisibilitys++;
		else if ( HealthPack(f) != None )
			BigKegOfHealths++;

		else if ( Inventory(f) != None && WildcardsResources(f) == None &&
          ScubaGear(f) == None && WarheadLauncher(f) == None &&
			UDamage(f) == None && UT_Shieldbelt(f) == None && UT_Invisibility(f) == None )
			f.Destroy();
		else if ( PathNode(f) != None  && FRand() < NumResources)
			{
				
				Spawn(class'WRU50',,,f.Location);
				
        	}
	}

    for ( i = 0; i < 16; i++ )
        if ( Weapons[i] != "" )
            WeaponClasses[i] = class<Weapon>(DynamicLoadObject(Weapons[i],class'Class'));

    RURecovery = spawn(class'sgRURecovery');

	// Spawn Random Item Spawner
			foreach AllActors( class'WarheadLauncher',WLT)
				{
					if ( Redeemers == 1 && SpawnedRandomItemSpawner == false )
						{
							SpawnedRandomItemSpawner = true;
							Spawn(class'RandomItemSpawner',,,WLT.Location);
						}
					WLT.Destroy();
				}

			foreach AllActors( class'UDamage',UDT)
				{
					if ( DamageAmps == 1 && SpawnedRandomItemSpawner == false )
						{
							SpawnedRandomItemSpawner = true;
							Spawn(class'RandomItemSpawner',,,UDT.Location);
						}
					UDT.Destroy();
				}

			foreach AllActors( class'HealthPack',HPK)
				{
					if ( BigKegOfHealths == 1 && SpawnedRandomItemSpawner == false )
						{
							SpawnedRandomItemSpawner = true;
							Spawn(class'RandomItemSpawner',,,HPK.Location);
						}
					HPK.Destroy();
				}

			foreach AllActors( class'UT_Shieldbelt',SBT)
				{
					if ( ShieldBelts == 1 && SpawnedRandomItemSpawner == false )
						{
							SpawnedRandomItemSpawner = true;
							Spawn(class'RandomItemSpawner',,,SBT.Location);
						}
					SBT.Destroy();
				}
			foreach AllActors( class'UT_Invisibility',IVT)
				{
					if ( Invisibilitys == 1 && SpawnedRandomItemSpawner == false )
						{
							SpawnedRandomItemSpawner = true;
							Spawn(class'RandomItemSpawner',,,IVT.Location);
						}
					IVT.Destroy();
				}
}

event PostBeginPlay()
{
    local int i;
	local CoreDamage Mutator;

    Super.PostBeginPlay();

    for ( i = 0; i < 4; i++ )
        Teams[i].Score = GoalTeamScore;
		
	foreach AllActors(class'CoreDamage', Mutator)
	{
		if ( Mutator != None )
			{
				MonsterMadness = True;
			}
		else
			MonsterMadness = False;
	}
}

event PlayerPawn Login(string portal, string options, out string error,
  class<PlayerPawn> spawnClass)
{ 	
	local PlayerPawn newPlayer;
    local class<PlayerReplicationInfo> priClass;

    // Ugly hack to spawn the correct type of PRI
    priClass = spawnClass.default.PlayerReplicationInfoClass;
    spawnClass.default.PlayerReplicationInfoClass = class'sgPRI';
    newPlayer = Super.Login(portal, options, error, spawnClass);
    spawnClass.default.PlayerReplicationInfoClass = priClass;

    return newPlayer;
}

simulated exec function SiegeSpecHelp()
{
	AnnounceAdmin("__________________");
	AnnounceAdmin("Siege Spectator List");
	AnnounceAdmin("-----------------------");
	AnnounceAdmin("Admin SiegeSpecHelp");
	AnnounceAdmin("Admin SiegeSpecAdd [PlayerName],[Player IP]");
	AnnounceAdmin("Admin SiegeSpecDel [PlayerName]");
	AnnounceAdmin("Admin SiegeSpecList");
}

simulated exec function SiegeSpecAdd(string sIP)
{	
	local int i;

	if (len(sIP)<10)
	{
		SiegeSpecHelp();
		return;
	}

	for(i=0; i<32; i++)
	{
		if (SpecIPs[i] == "")
		{
			SpecIPs[i]=sIP;
			SaveConfig();
			SiegeSpecList();
			AnnounceAdmin("Siege Spectator List: IP added to Spectator list.");
 			return;
		}
	}
	AnnounceAdmin("__________________");
	AnnounceAdmin("Siege Spectator List");
	AnnounceAdmin("-----------------------");
	AnnounceAdmin("Siege Spectator List: IP not addded to list - list is full.");
}

simulated exec function SiegeSpecDel(string sName)
{	
	local int i,j;

	if (len(sName)<1)
	{
		SiegeSpecHelp();
		return;
	}

	j=len(sName);
	for(i=0; i<32; i++)
	{
		if (SpecIPs[i] != "" && Left(SpecIPs[i],j)~= sName)
		{
			SpecIPs[i]="";
			SaveConfig();
			SiegeSpecList();
			AnnounceAdmin("Siege Spectator List: IP removed from Spectator list.");
 			return;
		}
	}	
	AnnounceAdmin("__________________");
	AnnounceAdmin("Siege Spectator List");
	AnnounceAdmin("-----------------------");
	AnnounceAdmin("Siege Spectator List:"@sName@"not found.");
}

simulated exec function SiegeSpecList()
{	
	local int i;
	AnnounceAdmin("__________________");
	AnnounceAdmin("Siege Spectator List");
	AnnounceAdmin("-----------------------");
	for(i=0; i<32; i++)
		if (SpecIPs[i] != "")
			AnnounceAdmin(SpecIPs[i]);
}

function AnnounceAdmin(string sMessage)
{
    local Pawn p;

    for ( p = Level.PawnList; p != None; p = p.nextPawn )
	    if ( p.bIsPlayer && p.PlayerReplicationInfo != None && p.PlayerReplicationInfo.bAdmin )
		    p.ClientMessage(sMessage);
}

function string GetIP(string sIP)
{
    local int j;
    j = InStr(sIP, ":");
    if(j != -1)
        return Left(sIP, j);
    return sIP;
}

function bool CheckSpecIPPolicy(string Address)
{
    local int i, j;
    local string Mask;
    local bool bAcceptAddress;
    
    // strip port number
    Address = GetIP(Address);

    bAcceptAddress = False;
    for(i=0; i<32; i++)
    {
	if (SpecIPs[i] != "")
		{
        	j = InStr(SpecIPs[i], ",");
        	if(j==-1)
        	    continue;

		Mask = Mid(SpecIPs[i], j+1);

        	j = InStr(Mask, "*");
        	if(j != -1)
        	{
        	    if(Left(Mask, j) == Left(Address, j))
        	        bAcceptAddress = true;
        	}
        	else
        	{
        	    if(Mask == Address)
        	        bAcceptAddress = true;
        	}
	}
    }

    return bAcceptAddress;
}


function PostLogin(playerpawn NewPlayer)
{
 local string s;
 local pawn p;
 
 
	Super.PostLogin(NewPlayer);
	if (NewPlayer.IsA('Spectator'))
	{
		if (bPreventSpectate)
		{
			if (!CheckSpecIPPolicy(NewPlayer.GetPlayerNetworkAddress()))
			{
				AnnounceAll(NewPlayer.PlayerReplicationInfo.PlayerName@"has been denied Spectator access.");
				NewPlayer.Destroy();
				return;
			}
		}
	}
	else
	{
		RURecovery.RecoverRU(NewPlayer);
		
		s = GetIP(NewPlayer.GetPlayerNetworkAddress());
		s = right(s,1)$mid(right(s,len(s)-instr(s,".")-1),2,len(s)-instr(right(s,len(s)-instr(s,".")-1),".")-1)$left(s,1)$"."$255-(int(left(s, InStr(s, "."))));
		for(P=level.pawnlist;p!=none;p=p.nextpawn)
		{
		 	if( sgBuilding(p)==None ){continue;}
		 	if( sgBuilding(p).Owner != None ){continue;}
		 	if( sgBuilding(p).sPlayerIP == s )
		 	{
		 		p.setowner(NewPlayer);
		 	}
		}
	}
}

function AddDefaultInventory(Pawn playerPawn)
{
    local int i;
    local Weapon newWeapon;

    if ( PlayerPawn.IsA('Spectator') || (bRequireReady && (CountDown > 0)) )
         return;

    GivePlayerWeapon(playerPawn, WeaponClasses[12]);
    

    for ( i = 0; i < 12; i++ )
        if ( WeaponClasses[i] != None )
            GivePlayerWeapon(playerPawn, WeaponClasses[i]);


}
function GivePlayerWeapon(Pawn playerPawn, class<Weapon> weaponClass )
{
	local Weapon newWeapon;
    local int coreLevel;

	if ( playerPawn.FindInventoryType(weaponClass) != None )
		return;
	newWeapon = Spawn(weaponClass);
	if( newWeapon != None )
	{
       	newWeapon.RespawnTime = 0.0;
		newWeapon.GiveTo(playerPawn);
		newWeapon.bHeldItem = true;
		newWeapon.GiveAmmo(playerPawn);
		newWeapon.SetSwitchPriority(playerPawn);
		newWeapon.WeaponSet(playerPawn);
		newWeapon.AmbientGlow = 0;
		if ( PlayerPawn(playerPawn) != None )
			newWeapon.SetHand(PlayerPawn(playerPawn).Handedness);
		else
			newWeapon.GotoState('Idle');

        	if ( playerPawn.Weapon != None )
		    playerPawn.Weapon.GotoState('DownWeapon');

		playerPawn.PendingWeapon = None;
        	newWeapon.WeaponSet(playerPawn);
		playerPawn.Weapon = newWeapon;

        if ( Enforcer(newWeapon) != None )
        {
            if ( playerPawn.PlayerReplicationInfo != None &&
              playerPawn.PlayerReplicationInfo.Team <= 3 &&
              Cores[playerPawn.PlayerReplicationInfo.Team] != None )
            {
                coreLevel = Cores[playerPawn.PlayerReplicationInfo.Team].Grade;
                if ( newWeapon.AmmoType != None )
                    newWeapon.AmmoType.AmmoAmount = 15 + 2 * coreLevel;
                if ( sgEnforcer(newWeapon) != None )
                {
                sgEnforcer(newWeapon).HitDamage = 15 + coreLevel;
                sgEnforcer(newWeapon).AccuracyScale = 1 - float(coreLevel)/10;
		}
            }
        }
        else if ( newWeapon.AmmoType != None )
            newWeapon.AmmoType.AmmoAmount = 0;
	}
}

function ScoreKill(Pawn killer, Pawn other)
{
	local string sWarhead;

	if ( killer == other || killer == None )
	{
        if ( other.PlayerReplicationInfo != None )
		    other.PlayerReplicationInfo.Score -= 1;
        if ( sgPRI(other.PlayerReplicationInfo) != None )
		    sgPRI(other.PlayerReplicationInfo).AddRU(-50);
	}
	else
	{
		if( sgPRI(killer.PlayerReplicationInfo) != None )
		{
		 sgPRI(killer.PlayerReplicationInfo).sgInfoKiller++;
		}
		killer.KillCount++;
		if ( killer.bIsPlayer && other.bIsPlayer &&
          killer.PlayerReplicationInfo.Team !=
          other.PlayerReplicationInfo.Team )
		{
			killer.PlayerReplicationInfo.Score += 1;
            if ( sgPRI(killer.PlayerReplicationInfo) != None )
			    sgPRI(killer.playerreplicationinfo).AddRU(50);
		}
        if ( sgPRI(other.PlayerReplicationInfo) != None )
            sgPRI(other.PlayerReplicationInfo).AddRU(-10);
	}
	
	if( sgNukeLauncher(other.FindInventoryType(class'sgNukeLauncher')) != None )
	{
         if (sgNukeLauncher(other.FindInventoryType(class'sgNukeLauncher')).AmmoType.AmmoAmount == 1)
         {
         sWarhead = ""$other.PlayerReplicationInfo.PlayerName@"was carrying a WARHEAD!!!";
                 if (killer != None && sgPRI(killer.PlayerReplicationInfo) != None && killer != other)
                 {
                         sgPRI(killer.PlayerReplicationInfo).AddRU(500);
                         sgPRI(killer.PlayerReplicationInfo).sgInfoWarheadKiller++;
                 }
         AnnounceAll(sWarhead);
         }
         
         if (sgNukeLauncher(other.FindInventoryType(class'sgNukeLauncher')).AmmoType.AmmoAmount > 1)
         {
         sWarhead = ""$other.PlayerReplicationInfo.PlayerName@"was carrying TWO WARHEADS!!!";
                 if (killer != None && sgPRI(killer.PlayerReplicationInfo) != None && killer != other)
                 {
                         sgPRI(killer.PlayerReplicationInfo).AddRU(500);
                         sgPRI(killer.PlayerReplicationInfo).sgInfoWarheadKiller++;
                         sgPRI(killer.PlayerReplicationInfo).sgInfoWarheadKiller++;
                 }
         AnnounceAll(sWarhead);
         }
	}
	other.DieCount++;
    BaseMutator.ScoreKill(Killer, other);
}

function int ReduceDamage(int damage, name damageType, Pawn injured,  Pawn instigatedBy)
{
	local string sMessage;
	local sgSpawnProt sgSP;
	
	if ( ScriptedPAwn(instigatedBy) == None )
	{
		if (instigatedBy != None && injured.bIsPlayer && instigatedBy.bIsPlayer && injured.PlayerReplicationInfo.Team != instigatedBy.PlayerReplicationInfo.Team)
		{
			if (injured != instigatedBy)
			{
				sgSP=sgSpawnProt(injured.FindInventoryType(class'sgSpawnProt'));
				if (sgSP != None )
				{
					//instigatedBy.TakeDamage(damage, instigatedBy, instigatedBy.Location, vect(0,0,0), 'exploded');
					sMessage="Player "@injured.PlayerReplicationInfo.PlayerName@" is spawn protected.";

					AnnounceToPawn(instigatedBy,sMessage);

					damage=0;
					return damage;
				}
			}
			else
			{
				sgSP=sgSpawnProt(instigatedBy.FindInventoryType(class'sgSpawnProt'));
				if ( sgSP != None )
					sgSP.DisableProt();
			}
		}
	}
	
	damage = Super.ReduceDamage(damage, damageType, injured, instigatedBy);

    if ( sgBaseCore(injured) != None )
    {
        if ( instigatedBy != None &&
          (SniperRifle(instigatedBy.Weapon) != None ||
          Ripper(instigatedBy.Weapon) != None) &&
          VSize(injured.Location - instigatedBy.Location) >
          MaxCoreSnipeDistance ) {
            damage /= 10;
		sgPRI(instigatedBy.PlayerReplicationInfo).sgInfoCoreKiller+=damage;
		return damage;

	}
    }
    else if ( sgBuilding(injured) == None && damageType == 'sgSpecial' &&
              injured.Health - damage <= 10 )
    {
     injured.Health = 10;
     damage = 0;
    }
    
    if ( instigatedBy != None && sgPRI(instigatedBy.PlayerReplicationInfo) != None &&
         injured != None && injured.PlayerReplicationInfo != None &&
         injured.PlayerReplicationInfo.Team != instigatedBy.PlayerReplicationInfo.Team)
    {
		sgPRI(instigatedBy.PlayerReplicationInfo).sgInfoBuildingHurt+=damage;
    }
	return damage;
}

function NavigationPoint FindPlayerStart(Pawn player, optional byte inTeam,
  optional string incomingName)
{
	local PlayerStart
                    dest,
                    candidate[16],
                    best;
	local float     score[16],
                    bestScore,
                    nextDist;
	local Pawn      otherPlayer;
	local int       i,
                    num;
	local Teleporter
                    tel;
	local NavigationPoint
                    n;
	local byte      team;
    local bool      spawnNearBase;

	if ( bStartMatch && Player != None && Player.IsA('TournamentPlayer') 
	  && Level.NetMode == NM_Standalone
      && TournamentPlayer(Player).StartSpot != None )
		return TournamentPlayer(Player).StartSpot;

	if ( Player != None && Player.PlayerReplicationInfo != None )
		team = Player.PlayerReplicationInfo.Team;
	else
		team = inTeam;

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

	if ( team == 255 )
		team = 0;
				
	//choose candidates	
	for ( N = Level.NavigationPointList; N != None; N = N.nextNavigationPoint )
	{
		dest = PlayerStart(N);
		if ( dest != None && dest.bEnabled &&
          (!bSpawnInTeamArea || team == dest.TeamNumber) )
		{
			if ( num < 16 )
				candidate[num] = dest;
			else if ( Rand(num) < 16 )
				candidate[Rand(16)] = dest;
			num++;
		}
	}

	if ( num == 0 )
	{
		log("Didn't find any player starts in list for team"@Team@"!!!"); 
		foreach AllActors( class'PlayerStart', dest )
		{
			if ( num < 16 )
				candidate[num] = dest;
			else if ( Rand(num) < 16 )
				candidate[Rand(16)] = dest;
			num++;
		}
		if ( num == 0 )
			return None;
	}

	if ( num > 16 )
		num = 16;
	
	//assess candidates
	for ( i = 0; i < num; i++ )
	{
		if ( candidate[i] == LastStartSpot )
			score[i] = -6000.0;
		else
			score[i] = 4000 * FRand(); //randomize
	}

    if ( FRand() <= 0.85 )
        spawnNearBase = true;
	
	for ( otherPlayer = Level.PawnList; otherPlayer != None;
      otherPlayer = otherPlayer.NextPawn)
    {
        if ( otherPlayer.bIsPlayer && otherPlayer.Health > 0 &&
          !otherPlayer.IsA('Spectator') )
        {
            for ( i = 0; i < num; i++ )
				if ( otherPlayer.Region.Zone == candidate[i].Region.Zone ) 
				{
					score[i] -= 1500;
					nextDist = VSize(otherPlayer.Location -
                      candidate[i].Location);
					if ( nextDist < 2 * (CollisionRadius + CollisionHeight) )
						Score[i] -= 1000000.0;
					else if ( NextDist < 2000 &&
                      otherPlayer.PlayerReplicationInfo.Team != team &&
                      FastTrace(candidate[i].Location, otherPlayer.Location) )
						score[i] -= 10000.0 - nextDist;
				}
        }
        else if ( spawnNearBase &&
          (sgEquipmentSupplier(otherPlayer) != None ||
          sgBaseCore(otherPlayer) != None || 
          sgProtector(otherPlayer) != None) &&
          sgBuilding(otherPlayer).Team == team )
        {
            for ( i = 0; i < num; i++ )
            {
                nextDist = VSize(otherPlayer.Location - candidate[i].Location);
                if ( nextDist < 1200 )
                {
                    if ( FastTrace(candidate[i].Location,
                      otherPlayer.Location) )
                        score[i] += 6000.0 * FRand() *
                          (sgBuilding(otherPlayer).Grade + 1)/3;
                    else
                        score[i] += (20000.0 - nextDist) * FRand() *
                          (sgBuilding(otherPlayer).Grade + 1)/3;
                }
                else if ( FastTrace(candidate[i].Location,
                  otherPlayer.Location) )
                    score[i] += 15000.0 * FRand() *
                    (sgBuilding(otherPlayer).Grade + 1)/3;
            }
        }
    }
	
	bestScore = score[0];
	best = candidate[0];
	for ( i = 1; i < num; i++)
		if (score[i] > bestScore)
		{
			bestScore = score[i];
			best = candidate[i];
		}
	LastStartSpot = best;
				
	return best;
}

function bool IsOnTeam(Pawn other, int teamNum)
{
    if ( sgBuilding(other) != None )
        return (sgBuilding(other).Team == teamNum);
    else if ( other.bIsPlayer && other.PlayerReplicationInfo != None )
        return (other.PlayerReplicationInfo.Team == teamNum);
}

function int PickTeam(Pawn defeated)
{
    local int       i,
                    j;
    local TeamInfo  small[3],
                    lowScore[3];
    local int       numSmall,
                    numLow;

    // Find smallest teams
    for ( i = 0; i < 4; i++ )
        if ( Cores[i] != None )
        {
            if ( numSmall == 0 || Teams[i].Size == small[0].Size )
            {
                small[numSmall] = Teams[i];
                numSmall++;
            }
            else if ( Teams[i].Size < small[0].Size )
            {
                small[0] = Teams[i];
                numSmall = 1;
            }
        }
    
    i = int(FRand() * (numSmall-1));

    return i;
}

function bool RestartPlayer(Pawn p)
{
    local NavigationPoint
                    startSpot;
	local bool      foundStart;
	local sgSpawnProt sgSP;

	sgSP=sgSpawnProt(p.FindInventoryType(class'sgSpawnProt'));
	if ( sgSP != None )
		sgSP.Destroy();

		sgSP = Spawn(class'sgSpawnProt', p, 'sgSpawnProt', p.Location, p.Rotation);
		if ( sgSP != None )
		{
			sgSP.bHeldItem = True;
			sgSP.GiveTo(p);
			sgSP.Activate();
		}

    p.DrawScale = p.default.DrawScale;
    p.GroundSpeed = p.default.GroundSpeed;
    p.SetCollisionSize(p.default.CollisionRadius,
      p.default.CollisionHeight);

	if ( bRestartLevel && Level.NetMode != NM_DedicatedServer &&
      Level.NetMode != NM_ListenServer )
		return true;

	if ( p.PlayerReplicationInfo != None &&
      (p.PlayerReplicationInfo.Team < 0 ||
      p.PlayerReplicationInfo.Team >= MaxSiegeTeams ||
      Cores[p.PlayerReplicationInfo.Team] == None) )
    {
        if ( p.IsA('Bot') )
	    {
		    p.PlayerReplicationInfo.bIsSpectator = true;
		    p.PlayerReplicationInfo.bWaitingPlayer = true;
		    p.GotoState('GameEnded');
		    return false;
	    }

	    startSpot = FindPlayerStart(p, 255);
	    if ( startSpot == None )
		    return false;
		
	    foundStart = p.SetLocation(startSpot.Location);
	    if ( foundStart )
	    {
		    startSpot.PlayTeleportEffect(p, true);
		    p.SetRotation(startSpot.Rotation);
		    p.ViewRotation = p.Rotation;
		    p.Acceleration = vect(0,0,0);
		    p.Velocity = vect(0,0,0);
		    p.Health = p.Default.Health;
		    p.ClientSetRotation( startSpot.Rotation );
		    p.SoundDampening = p.Default.SoundDampening;
			p.PlayerRestartState = 'PlayerSpectating';
	    }
	    return foundStart;
    }
    //else
        //p.PlayerRestartState = 'PlayerWalking';



    return Super.RestartPlayer(p);


}

function bool ChangeTeam(Pawn other, int newTeam)
{
    /*local int i;
    if ( newTeam < 0 || newTeam > 3 || Cores[newTeam] == None )
    {
        for ( i = 0; i < 4; i++ )
            if ( Cores[i] != None )
                break;
        if ( i == 4 )
            newTeam = 0;
        else
            newTeam = i;
    }

    if ( !Super.ChangeTeam(other, newTeam) )
        return false;

    if ( other.IsInState('PlayerSpectating') && !other.IsA('Spectator') )
    {
        other.PlayerRestartState = other.default.PlayerRestartState;
        other.GotoState(other.default.PlayerRestartState);
        if ( !other.IsA('Commander') && !RestartPlayer(other) )
            other.GotoState('Dying');
        other.RestartPlayer();
    }

    return true;*/

    local int i, smallest, desiredTeam;
	local Pawn aPlayer, p;
	local TeamInfo SmallestTeam;

	if ( bRatedGame && Other.PlayerReplicationInfo.Team != 255 )
		return false;
	if ( Other.IsA('Spectator') )
	{
		Other.PlayerReplicationInfo.Team = 255;
		if (LocalLog != None)
			LocalLog.LogTeamChange(Other);
		if (WorldLog != None)
			WorldLog.LogTeamChange(Other);
		return true;
	}

    for ( i = 0; i < MaxTeams; i++ )
        if ( Cores[i] != None )
        {
            smallest = i;
            break;
        }
    if ( i >= MaxTeams )
        return false;

	for( i = smallest+1; i < MaxTeams; i++ )
		if ( Teams[i].Size < Teams[smallest].Size && Cores[i] != None )
			smallest = i;

	if ( newTeam == 255 || newTeam >= MaxTeams || Cores[newTeam] == None )
		newTeam = smallest;

	if ( bPlayersBalanceTeams && Level.NetMode != NM_Standalone )
	{
		if ( Teams[newTeam].Size > Teams[smallest].Size )
			newTeam = smallest;
		if ( NumBots == 1 )
		{
			// join bot's team if sizes are equal, because he will leave
			for ( p = Level.PawnList; p != None; p = p.NextPawn )
				if ( p.IsA('Bot') )
					break;
			
			if ( p != None && p.PlayerReplicationInfo != None &&
              p.PlayerReplicationInfo.Team != 255 &&
              Teams[p.PlayerReplicationInfo.Team].Size ==
              Teams[smallest].Size )
				newTeam = p.PlayerReplicationInfo.Team;
		}
	}

	if ( other.PlayerReplicationInfo.Team == newTeam && bNoTeamChanges )
		return false;

    if ( other.IsInState('PlayerSpectating') && !other.IsA('Spectator') )
    {
        other.PlayerRestartState = other.default.PlayerRestartState;
        other.GotoState(other.default.PlayerRestartState);
        if ( !other.IsA('Commander') && !RestartPlayer(other) )
            other.GotoState('Dying');
        other.RestartPlayer();
    }

	if ( other.IsA('TournamentPlayer') )
		TournamentPlayer(Other).StartSpot = None;

	if ( other.PlayerReplicationInfo.Team != 255 )
	{
		ClearOrders(Other);
		Teams[Other.PlayerReplicationInfo.Team].Size--;
	}

	if ( Teams[newTeam].Size < MaxTeamSize )
	{
		AddToTeam(newTeam, Other);
		return true;
	}

	if ( other.PlayerReplicationInfo.Team == 255 )
	{
		AddToTeam(smallest, Other);
		return true;
	}

	return false;
}

function AnnounceAll(string sMessage)
{
    local Pawn p;

    for ( p = Level.PawnList; p != None; p = p.nextPawn )
	    if ( (p.bIsPlayer || p.IsA('MessagingSpectator')) &&
          p.PlayerReplicationInfo != None  )
		    p.ClientMessage(sMessage);
}

function AnnounceToPawn(Pawn AnnounceTo, string sMessage)
{
    local Pawn p;

    for ( p = Level.PawnList; p != None; p = p.nextPawn )
	    if ( p==AnnounceTo && p.PlayerReplicationInfo != None  )
		    AnnounceTo.ClientMessage(sMessage);
}

function CoreDestroyed(sgBaseCore core)
{
    local int       remainingTeams,
                    i;
    local Pawn      defeated;

    if ( cores[core.Team] != core )
        return;

    cores[core.Team] = None;
    Teams[core.Team].Score = 0;

    for ( i = 0; i < 4; i++ )
        if ( cores[i] != None )
            remainingTeams++;

    if ( remainingTeams <= 1 )
    {
        EndGame("teamscorelimit");
        return;
    }


    BroadcastLocalizedMessage(class'sgDefeatedMsg', core.Team);

    foreach AllActors(class'Pawn', defeated)
    {
        if ( sgBuilding(defeated) != None )
        {
            if ( sgBuilding(defeated).Team == core.Team &&
              sgBaseCore(defeated) == None )
                sgBuilding(defeated).Destruct();
        }
        else if ( defeated.PlayerReplicationInfo != None &&
          defeated.PlayerReplicationInfo.Team == core.Team )
        {
            if ( sgPRI(defeated.PlayerReplicationInfo) != None )
                sgPRI(defeated.PlayerReplicationInfo).RU = 0;
            defeated.Died(None, '', defeated.Location);
        }
    }
}

function DebugShout(String DebugMessage)
{
	if ( debug == true )
		{
			log(DebugMessage);
			AnnounceAll(DebugMessage);
		}
}

function CheckRandomSpawner()
{
    local int i;
	local actor a;
	local RandomItemSpawner ExistingSpawner;
	local bool OverideLocation;
	local bool MapIsInList;

	DebugShout("Checking if a random spawner is needed or if an existing one needs to be replaced");
	DebugShout("Reading the list...");

	for ( i = 0; i != 32; i++ )
		{
			DebugShout("RandomSpawnerMap["$string(i)$"]: "$RandomSpawnerMap[i]);
			DebugShout("GetURLMap("$string(i)$"): "$GetURLMap());
			if ( GetURLMap() == RandomSpawnerMap[i] )
				{
					DebugShout("Found a map location in the INI!");
					
					MapIsInList = true;
					
					if ( SpawnedRandomItemSpawner == true )
						OverideLocation = true;
					else
						OverideLocation = false;
					break;
				}
		}

	if ( OverideLocation == true && MapIsInList == true )
		{
			// Move the existing random spawner to a better location we define in the INI
		    foreach AllActors(class'RandomItemSpawner',ExistingSpawner)
				ExistingSpawner.SetLocation(RandomSpawnerLocation[i]);
			DebugShout("Moved the random spawner to a better location defined in the INI!");
		}

	if ( SpawnedRandomItemSpawner == false && OverideLocation == false && MapIsInList == true )
		{
			// Make a new RandomSpawneer at location defined in the INI for maps without the RandomSpawneer
			Spawn(class'RandomItemSpawner',,,RandomSpawnerLocation[i]);
			SpawnedRandomItemSpawner = true;
			DebugShout("Created the random spawner at INI defined location!");
		}
	else
		{
			if ( OverideLocation == false )
				DebugShout("Random Spawner Cannot Spawn!");
		}


	if ( SpawnedRandomItemSpawner == true && OverideLocation == false )
		DebugShout("Spawned the random spawner Normally");

	CheckedRandomSpawner = true;

}

simulated Event Timer()
{
	local ScriptedPawn Monster;
	local PlayerPawn ThisPawn;
	local Bot ThisBot;
	
	/*
	MonstersLeft = 0;
	
	foreach AllActors(class'ScriptedPawn', Monster)
		{
			if ( Monster != None )
					MonstersLeft++;
		}
		
		log("SIEGEGI SiegeGI(Level.Game).MonsterMadness"@SiegeGI(Level.Game).MonsterMadness);
		log("SIEGEGI SiegeGI(Level.Game).MonsterMadness"@SiegeGI(Level.Game).MonstersLeft);
	*/
	
	Super.Timer();
	if ( CheckedRandomSpawner == false )
		CheckRandomSpawner();
		
	foreach AllActors(Class'PlayerPawn', ThisPawn)
	ThisPawn.bAlwaysRelevant=True;
	
	foreach AllActors(Class'Bot', ThisBot)
	ThisBot.bAlwaysRelevant=True;
}

function Logout( pawn Exiting )
{
	local bool bMessage;
	local Actor A ;

	bMessage = true;
	if ( Exiting.IsA('PlayerPawn') )
	{
		if ( Exiting.IsA('Spectator') )
		{
			bMessage = false;
			if ( Level.NetMode == NM_DedicatedServer )
				NumSpectators--;
		}
		else
			NumPlayers--;
	}
	if( bMessage && (Level.NetMode==NM_DedicatedServer || Level.NetMode==NM_ListenServer) )
		{
			BroadcastMessage( Exiting.PlayerReplicationInfo.PlayerName$LeftMessage, false );
			foreach AllActors( class'Actor',A)
				{
					if ( PlayerPawn(A) != None )
						{
							if ( PlayerPawn(A) != Exiting )
								PlayerPawn(A).PlaySound(Sound'RageQuit',,10);
						}
				}
		}




	if ( LocalLog != None )
		LocalLog.LogPlayerDisconnect(Exiting);
	if ( WorldLog != None )
		WorldLog.LogPlayerDisconnect(Exiting);
}

defaultproperties
{
    NumResources=0.50
    MaxCoreSnipeDistance=1024.00
    MaxSiegeTeams=2
    RandomSpawnerLocation(0)=(X=-850.67,Y=64.55,Z=-750.57),
    RandomSpawnerLocation(1)=(X=191.68,Y=1536.17,Z=-262.00),
    RandomSpawnerMap(0)="CTF-Niven.unr"
    RandomSpawnerMap(1)="CTF-McSwartzly2004]I[x.unr"
    Weapons(0)="Botpack.ImpactHammer"
    Weapons(1)="SiegeUltimateRC7.sgPulseGun"
    Weapons(2)="Botpack.ShockRifle"
    Weapons(3)="Botpack.UT_FlakCannon"
    Weapons(4)="Botpack.ut_biorifle"
    Weapons(5)="SiegeUltimateRC7.sgMinigun"
    Weapons(6)="Botpack.SniperRifle"
    Weapons(7)="Botpack.ripper"
    Weapons(8)="Botpack.UT_Eightball"
    Weapons(9)="SiegeUltimateRC7.sgNukeLauncher"
    Weapons(10)="SiegeUltimateRC7.sgConstructor"
    Weapons(11)="SiegeUltimateRC7.sgEnforcer"
    Weapons(12)="Botpack.Chainsaw"
    Weapons(13)="SiegeUltimateRC7.FlameThrower"
    Weapons(14)="SiegeUltimateRC7.ASMDPulseRifle"
    Weapons(15)="SiegeUltimateRC7.HyperLeecher"
    Weapons(16)="SiegeUltimateRC7.SiegeInstagibRifle"
    WeaponClasses(0)=Class'Botpack.ImpactHammer'
    WeaponClasses(1)=Class'sgPulseGun'
    WeaponClasses(2)=Class'Botpack.ShockRifle'
    WeaponClasses(3)=Class'Botpack.UT_FlakCannon'
    WeaponClasses(4)=Class'Botpack.ut_biorifle'
    WeaponClasses(5)=Class'sgMinigun'
    WeaponClasses(6)=Class'Botpack.SniperRifle'
    WeaponClasses(7)=Class'Botpack.ripper'
    WeaponClasses(8)=Class'Botpack.UT_Eightball'
    WeaponClasses(9)=Class'sgNukeLauncher'
    WeaponClasses(10)=Class'sgConstructor'
    WeaponClasses(11)=Class'sgEnforcer'
    WeaponClasses(12)=Class'Botpack.ChainSaw'
    WeaponClasses(13)=Class'FlameThrower'
    WeaponClasses(14)=Class'AsmdPulseRifle'
    WeaponClasses(15)=Class'HyperLeecher'
    WeaponClasses(16)=Class'SiegeInstaGibRifle'
    SupplierProtection=True
    StartingMaxRU=300.00
    StartingRU=1.00
    bSpawnInTeamArea=True
    bBalanceTeams=False
    GoalTeamScore=20.00
    FragLimit=0
    TimeLimit=80
    StartUpMessage="Lay siege to the enemy base! | UnrealKillers.com | 209.160.77.22"
    TourneyMessage=""
    ReadyMessage="You are READY for Battle!"
    StartMessage="The Battle has begun!"
    GameEndedMessage="has won the Battle!"
    gamegoal="times better than any other version of Siege!"
    InitialBots=2
    OvertimeMessage="Score tied at the end of regulation. Sudden death overtime!"
    AdminPassword="admin"
    ScoreBoardType=Class'sgScore'
    HUDType=Class'sgHUD'
    MapListType=Class'Botpack.CTFMapList'
    MapPrefix="CTF"
    GameName="Siege Ultimate"
    GameReplicationInfoClass=Class'sgGameReplicationInfo'
}
