class xPlayer extends UnrealPlayer
    DependsOn(xUtil);

#exec OBJ LOAD File=ROMenuSounds.uax

// attract mode
var AttractCamera camlist[20];
var int numcams, curcam;
var Pawn attracttarget, attracttarget2;
var float camtime, targettime, gibwatchtime;
var Vector focuspoint;

// combos
const MinComboKeyTime = 0.05;   // keys pressed faster than this will be considered a double-press
const MaxComboKeyTime = 0.35;   // max time player has between button presses

var transient int InputHistory[4];
var transient float LastKeyTime;
var transient int OldKey;
var float MinAdrenalineCost;
var string ComboNameList[16];
var class<Combo> ComboList[16];

var xUtil.PlayerRecord PawnSetupRecord;
var float LastRulesRequestTime;
var float LastMapListRequestTime;

var bool autozoom;
var globalconfig bool bClassicTrans;
var bool bHighBeaconTrajectory;
var bool bWaitingForPRI, bWaitingForVRI;
var config bool bDebuggingVoiceChat;

var config bool bAutoDemoRec;

delegate ProcessRule(string NewRule);	// Should be assigned elsewhere
delegate ProcessMapName(string NewMap);

replication
{
	// client to server
	reliable if ( Role < ROLE_Authority )
		ServerDoCombo, ServerRequestRules, ServerRequestMapList, AdminMenu, ServerRequestPlayerInfo,
        ServerSpecViewGoal, ServerSetClassicTrans;
	unreliable if( Role < ROLE_Authority )
		L33tPhrase;
    reliable if ( Role == ROLE_Authority)
    	ClientReceiveRule, ClientReceiveMapName, ClientReceiveCombo, ClientReceiveBan;
}

exec function CheckPriority()
{
	local Inventory Inv;
	local int Count;

	if ( Pawn == None )
	{
		DebugMessage("Pawn is none - returning");
		return;
	}

	for( Inv = Pawn.Inventory; Inv != None && Count < 1000; Inv = Inv.Inventory )
	{
		if ( Weapon(Inv) != None )
			DebugMessage("Weapon:"$Inv.Name@"Priority:"$Weapon(Inv).Priority,'PriorityDebug');

		Count++;
	}
}

simulated function DebugMessage(string DebugString, optional name Type)
{
	ClientMessage(DebugString);
	log(DebugString,Type);
}


simulated function String GetRoleString()
{
	local String T;

	T = "Role: ";
	Switch(Role)
	{
		case ROLE_None: T=T$"None"; break;
		case ROLE_DumbProxy: T=T$"DumbProxy"; break;
		case ROLE_SimulatedProxy: T=T$"SimulatedProxy"; break;
		case ROLE_AutonomousProxy: T=T$"AutonomousProxy"; break;
		case ROLE_Authority: T=T$"Authority"; break;
	}

	return T;
}

simulated function String GetPhysicsString()
{
	Local String T;

	T = "Physics: ";
	Switch( Pawn.Physics )
	{
		case PHYS_None: T=T$"None"; break;
		case PHYS_Walking: T=T$"Walking"; break;
		case PHYS_Falling: T=T$"Falling"; break;
		case PHYS_Swimming: T=T$"Swimming"; break;
		case PHYS_Flying: T=T$"Flying"; break;
		case PHYS_Rotating: T=T$"Rotating"; break;
		case PHYS_Projectile: T=T$"Projectile"; break;
		case PHYS_Interpolating: T=T$"Interpolating"; break;
		case PHYS_MovingBrush: T=T$"MovingBrush"; break;
		case PHYS_Spider: T=T$"Spider"; break;
		case PHYS_Trailer: T=T$"Trailer"; break;
		case PHYS_Ladder: T=T$"Ladder"; break;
		case PHYS_Karma: T=T$"Karma"; break;
	}
	return T;
}

// Voice chat debug

function ServerRequestRules()
{
 	local GameInfo.ServerResponseLine Response;
    local int i;


    if ( Level.Pauser == None && Level.TimeSeconds - LastRulesRequestTime < 3.0)
    {
    	log("ServerRequestRules Level.TimeSeconds:"$Level.TimeSeconds@"LastRequestTime:"$LastRulesRequestTime);
		return;
	}

    LastRulesRequestTime = Level.TimeSeconds;
    Level.Game.GetServerDetails(Response);
    ClientReceiveRule("");
    for (i=0;i<Response.ServerInfo.Length;i++)
	   	ClientReceiveRule(Response.ServerInfo[i].Key$"="$Response.ServerInfo[i].Value);
}

function ClientReceiveRule(string NewRule)
{
	ProcessRule(NewRule);
}

function ServerRequestMapList()
{
	local int x;
	local array<string> MapList;

	if ( Level.Pauser == None &&
		(Level.TimeSeconds - LastMapListRequestTime < 3.0 || Level.Game.MapListType == "") )
		return;

	LastMapListRequestTime = Level.TimeSeconds;
	MapList = Level.Game.GetMapRotation();

	ClientReceiveMapName("");
	for (x = 0; x < MapList.length; x++)
		ClientReceiveMapName(MapList[x]);
}

function ClientReceiveMapName(string NewMap)
{
	ProcessMapName(NewMap);
}

function StopFiring()
{
}

simulated function PlayBeepSound()
{
	// Replaceme , this sound
    if ( ViewTarget != None )
		ViewTarget.PlaySound(sound'ROMenuSounds.msfxMouseClick', SLOT_None,,,,,false);
}

simulated function float RateWeapon(Weapon w)
{
    return w.Default.Priority;
}

exec function L33TPhrase( int phraseNum )
{
	SendMessage(None, 'HIDDEN', phraseNum, 5, 'GLOBAL');
}

simulated event PostBeginPlay()
{
    local int c;

    Super.PostBeginPlay();

    for (c = 0; c < ArrayCount(ComboList); c++)
    {
        if ( ComboNameList[c] != "" )
        {
 			ComboList[c] = class<Combo>(DynamicLoadObject(ComboNameList[c],class'Class'));
			if ( ComboList[c] == None )
				break;
			MinAdrenalineCost = FMin(MinAdrenalineCost,ComboList[c].Default.AdrenalineCost);
		}
    }
    FillCameraList();
    LastKillTime = -5.0;
}

simulated event PostNetBeginPlay()
{
	super.PostNetBeginPlay();
	if ( Level.NetMode != NM_DedicatedServer )
		ServerSetClassicTrans(bClassicTrans);
}

function ServerSetClassicTrans(bool B)
{
	bHighBeaconTrajectory = B;
}

simulated function ClientReceiveCombo(string NewCombo)
{
	local int i;

	for ( i=0; i<16; i++ )
	{
		if ( ComboNameList[i] ~= NewCombo )
			return;
		else if ( ComboNameList[i] == "" )
		{
			ComboNameList[i] = NewCombo;
 			ComboList[i] = class<Combo>(DynamicLoadObject(ComboNameList[i],class'Class'));
			if ( ComboList[i] == None )
				return;
			MinAdrenalineCost = FMin(MinAdrenalineCost,ComboList[i].Default.AdrenalineCost);
			return;
		}
	}
}

event PlayerTick( float DeltaTime )
{
    local int CurrentKey, DiffKey;
    local int c, i;
	local bool bFullBuffer,bMatch;

	Super.PlayerTick(DeltaTime);

	if ( Viewport(Player) == None )
		return;

    if ( (Pawn == None) || !bAdrenalineEnabled || (Adrenaline < MinAdrenalineCost) )
    {
		InputHistory[0] = 0;
		return;
	}
    CurrentKey = 0;

    if (aForward > 0)		CurrentKey = CurrentKey | 1; // CK_Up
    else if (aForward < 0)  CurrentKey = CurrentKey | 2; // CK_Down
    if (aStrafe > 0)		CurrentKey = CurrentKey | 4; // CK_Left
    else if (aStrafe < 0)   CurrentKey = CurrentKey | 8; // CK_Right

    if ( CurrentKey != OldKey )
    {
        DiffKey = CurrentKey & ~OldKey; // keys that are pressed now but were not last frame

        if (DiffKey != 0)
        {
            if (Level.TimeSeconds - LastKeyTime < MinComboKeyTime) // if the time was too short between the last keypress, consider it a double press
            {
                InputHistory[0] = InputHistory[0] | DiffKey;
            }
            else if (Level.TimeSeconds - LastKeyTime > MaxComboKeyTime) // wipe the buffer if too long since last keypress
            {
                InputHistory[0] = Diffkey;
                InputHistory[1] = 0;
                LastKeyTime = Level.TimeSeconds;
            }
            else
            {
				bFullBuffer = true;
                for ( i=3; i>0; i-- )
                {
                    InputHistory[i] = InputHistory[i - 1];
                    if ( InputHistory[i] == 0 )
						bFullBuffer = false;
				}
                InputHistory[0] = DiffKey;
                LastKeyTime = Level.TimeSeconds;
            }

            // check for combo matches
            if ( bFullBuffer )
            {
                for ( c=0; c<16; c++ )
                {
                    if ( ComboList[c] == None )
                        break;
                    else if ( (ComboList[c].Default.species == None) || (ComboList[c].Default.species == xPawn(Pawn).Species) )
                    {
						bMatch = true;
                        for ( i=0; i <4; i++)
                            if ( InputHistory[i] != ComboList[c].Default.keys[i] )
                            {
								bMatch = false;
                                break;
                            }

                        if ( bMatch )
                        {
                            DoCombo(ComboList[c]);
                            InputHistory[0] = 0;
                        }
                    }
                }
            }
        }

        OldKey = CurrentKey;
    }
}

function DoCombo( class<Combo> ComboClass )
{
    if (Adrenaline >= ComboClass.default.AdrenalineCost && !Pawn.InCurrentCombo() )
    {
        ServerDoCombo( ComboClass );
    }
}

function ServerDoCombo( class<Combo> ComboClass )
{
	if ( (ComboClass == None) || (xPawn(Pawn) == None) )
		return;
    if (Adrenaline >= ComboClass.default.AdrenalineCost && !Pawn.InCurrentCombo() )
    {
        if (ComboClass.default.ExecMessage != "")
        // Temp commented out - Ramm
        //    ReceiveLocalizedMessage( class'ComboMessage', , , , ComboClass );

        xPawn(Pawn).DoCombo( ComboClass );
    }
}

state AttractMode
{
	ignores SwitchWeapon, RestartLevel, ClientRestart, Suicide,
	 ThrowWeapon, NotifyPhysicsVolumeChange, NotifyHeadVolumeChange,
     Say, TeamSay;

	function bool IsSpectating()
	{
		return true;
	}

	function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
	{
	}

	function PlayerMove(float DeltaTime)
	{
        local float deltayaw, destyaw;
        local Rotator newrot;

        if ( attracttarget == None )
			return;

        // updates camera yaw to smoothly rotate to the pawn facing
        if ( bBehindView )
        {
			if ( (attracttarget.Controller == None) || (AttractTarget.Controller.Enemy == None) )
				return;
            NewRot = Rotator(attracttarget.controller.Enemy.location - attracttarget.location);
			destyaw = NewRot.Yaw;
            deltayaw = (destyaw & 65535) - (rotation.yaw & 65535);
            if (deltayaw < -32768) deltayaw += 65536;
            else if (deltayaw > 32768) deltayaw -= 65536;

            newrot = rotation;
            newrot.yaw += deltayaw * DeltaTime;
            SetRotation(newrot);
        }
        else
        {
            newrot = CameraTrack(attracttarget, DeltaTime);
            SetRotation(newrot);
        }
	}

	exec function NextWeapon()
	{
	}

	exec function PrevWeapon()
	{
	}

	exec function Fire( optional float F )
	{
        // start playing
	}

	exec function AltFire( optional float F )
	{
        Fire(F);
	}

	function BeginState()
	{
		if ( Pawn != None )
		{
			SetLocation(Pawn.Location);
		}
		bCollideWorld = true;
        if ( curcam == -1 )
        {
            FillCameraList();
            camtime = 0;
            targettime = 0;
            autozoom = true;
            curcam = -1;
        }

        Timer();
        SetTimer(0.5, true);
	}

	function EndState()
	{
		PlayerReplicationInfo.bIsSpectator = false;
		bCollideWorld = false;
        curcam = -1;
	}

    function Timer()
    {
        local bool switchedbots;
        local Vector newloc;
        local int newcam;

        camtime += 0.5;
        targettime += 0.5;
        bFrozen = false;

        // keep watching a target for a few seconds after it dies
        if (gibwatchtime > 0)
        {
            gibwatchtime -= 0.5;
            if (gibwatchtime <= 0)
                attracttarget = None;
            else
                return;
        }
        else if ( attracttarget != None && attracttarget.Health <= 0 )
        {
            gibwatchtime = 4;
            //Log("attract: watching gib");
        }

        // switch targets //
        if (attracttarget == None
            || targettime > 30 )
        {
            attracttarget = PickNextBot(attracttarget);
            switchedbots = true;
            targettime = 0;
         }

        if (attracttarget == None)
            return;

        // switch views //
        if (
            switchedbots ||
            camtime > 10 ||
            bBehindView == false && (rotation.pitch < -10000 || !LineOfSight(curcam, attracttarget))
        )
        {
            camtime = 0;
            FovAngle = default.FovAngle;
            SetViewTarget(self);
	    	bBehindView = false;

            // look for a placed camera
            if (FindFixedCam(attracttarget, newcam))
            {
                focuspoint = attracttarget.Location;
                curcam = newcam;
                SetLocation(camlist[curcam].Location);
                FovAngle = camlist[curcam].ViewAngle;

                SetRotation(CameraTrack(attracttarget, 0));
                //Log("attract: camera "$camlist[curcam]);
            }
            // use a floating camera
            else if (FRand() < 0.5)
            {
                newloc = FindFloatingCam(attracttarget);
                focuspoint = attracttarget.Location;
                curcam = -1;
                SetLocation(newloc);

                SetRotation(CameraTrack(attracttarget, 0));
                //Log("attract: free camera");
            }
            // chase mode
            else
            {
                curcam = -1;
    		    SetViewTarget(attracttarget);
	    	    bBehindView = true;
                SetRotation(attracttarget.rotation);
                CameraDeltaRotation.Pitch = -3000;
                CameraDist = 6;
                //Log("attract: chase camera");
            }
        }
    }
}

state ViewPlayer extends PlayerWalking
{
	function PlayerMove(float DeltaTime)
	{
        Super.PlayerMove(DeltaTime);

        CameraSwivel = CameraTrack(pawn, DeltaTime);
    }

    function PlayerCalcView(out actor ViewActor, out vector CameraLocation, out rotator CameraRotation )
    {
        // not calling super
        CameraRotation = CameraSwivel;
        CameraLocation = location; //camlist[curcam].location;
        ViewActor = self;
    }

    function BeginState()
    {
        FillCameraList();
        bBehindView = true;
        SetViewTarget(self);
        curcam = -2;
        autozoom = true;
        Timer();
        SetTimer(0.5, true);
    }

    function EndState()
    {
        CameraSwivel = rot(0,0,0);
        bBehindView = false;
        FovAngle = default.FovAngle;
        DesiredFOV = FovAngle;
        SetViewTarget(pawn);
    }

    function Timer()
    {
        local Vector newloc;
        local int newcam;

        if (curcam == -2 || !LineOfSight(curcam, pawn))
        {
            //Log("attract: switch camera");

            camtime = 0;

            if (FindFixedCam(pawn, newcam))
            {
                if (curcam != newcam)
                {
                    focuspoint = pawn.Location;
                    curcam = newcam;
                    SetLocation(camlist[curcam].location);
                    FovAngle = camlist[curcam].ViewAngle;
                    //Log("attract: viewing from "$camlist[curcam]);
                }
                else
                {
                    //Log("attract: zoinks! this shouldn't happen");
                }
            }
            else
            {
                newloc = FindFloatingCam(pawn);
                SetLocation(newloc);
                curcam = -1;
                FovAngle = default.FovAngle;
                focuspoint = pawn.Location;
                //Log("attract: floating");
            }

            CameraSwivel = CameraTrack(pawn, 0);
        }
    }

    exec function TogglePlayerAttract()
    {
        GotoState('PlayerWalking');
    }
}

function FillCameraList()
{
    local AttractCamera cam;
    numcams = 0;
    foreach AllActors(class'AttractCamera', cam)
    {
        camlist[numcams++] = cam;
        if (numcams == 20) break;
    }
}

function bool FindFixedCam(Pawn target, out int newcam)
{
    local int c, bestc;
    local float dist, bestdist;

    bestc = -1;

    for (c = 0; c < numcams; c++)
    {
        dist = VSize(target.location - camlist[c].location);

        if ((bestc == -1 || dist < bestdist) && LineOfSight(c, target))
        {
            bestc = c;
            bestdist = dist;
        }
    }

    if (bestc == -1) return false;

    newcam = bestc;
    return true;
}

function Vector FindFloatingCam(Pawn target)
{
    local Vector v1, v2, d;
    local Rotator r;
    local Vector hitloc, hitnormal;
    local Actor hitactor;
    local int tries;

    while (tries++ < 10)
    {
        v1 = target.Location;
        r = target.Rotation;
        r.Pitch = FRand()*12000 - 2000;
        if (VSize(target.Velocity) < 100)
            r.Yaw += FRand()*24000;
        else
            r.Yaw += FRand()*12000;
        d = Vector(r);
        v2 = v1 + d*2000;
        v1 += d*50;

        hitactor = Trace(hitloc, hitnormal, v2, v1, false);

        if (hitactor != None && VSize(hitloc - v1) > 250)
        {
            return (hitloc - d*50);
        }
    }
    // no good spots found, return something reasonable
    if (hitactor != None)
        return (hitloc - d*50);
    else
        return v2;
}

function Pawn PickNextBot(Pawn current)
{
    local Controller con;
    local int b;

    if (current != None) con = current.Controller;
    for (b=0; b<Level.Game.NumBots; b++)
    {
        if (con != None) con = con.NextController;
        if (con == None) con = Level.ControllerList;
        if (con.IsA('Bot') && con.Pawn != None && !con.IsInState('PlayerWaiting'))
        {
            return con.Pawn;
        }
    }
    return None;
}

function bool LineOfSight(int c, Pawn target)
{
    local vector v1, v2;
    local AttractCamera cam;
    local Vector hitloc, hitnormal;

    if (c >= 0) {
        cam = camlist[c];
        v1 = cam.location;
    } else {
        v1 = self.location;
    }
    v2 = target.location;
    v2.z += target.eyeheight;
    v2 += Normal(v1 - v2) * 100;
    return (Trace(hitloc, hitnormal, v1, v2, false) == None);
}

function Rotator CameraTrack(Pawn target, float DeltaTime)
{
    local float dist;
    local Vector lead;
    local float minzoomdist, maxzoomdist, viewangle, viewwidth;

    // update focuspoint
    lead = target.location + Vect(0,0,2) * Target.CollisionHeight; // + target.Velocity*0.5;
    dist = VSize(lead - focuspoint);
    if (dist > 20)
    {
        focuspoint += Normal(lead - focuspoint) * dist * DeltaTime * 2.0;
    }

    // adjust zoom within bounds (FovAngle 30-100)
    if (autozoom)
    {
        dist = VSize(Location - target.Location);

        if (curcam >= 0)
        {
            minzoomdist = camlist[curcam].minzoomdist;
            maxzoomdist = camlist[curcam].maxzoomdist;
            viewangle = camlist[curcam].ViewAngle;
        }
        else
        {
            minzoomdist = 600;
            maxzoomdist = 1200;
            viewangle = default.FovAngle;
        }

        if (dist < minzoomdist)
        {
            FovAngle = viewangle;
        }
        else if (dist < maxzoomdist)
        {
            viewwidth = minzoomdist*Tan(viewangle*PI/180 / 2);
            FovAngle = Atan(viewwidth, dist) * 180/PI * 2;
        }

        DesiredFOV = FovAngle;
    }

    return Rotator(focuspoint - location);
}

function PawnDied(Pawn P)
{
	if ( Pawn != P )
		return;
    bBehindview = true;
	LastKillTime = -5.0;

    if (Pawn != None)
    {
        curcam = -1;
        SetLocation(FindFloatingCam(Pawn));
        SetRotation(CameraTrack(Pawn, 0));
    }

    Super.PawnDied(P);
}

function SetPawnClass(string inClass, string inCharacter)
{
    local class<xPawn> pClass;

    if ( inClass != "" )
	{
		pClass = class<xPawn>(DynamicLoadObject(inClass, class'Class'));
		if ( (pClass != None) && pClass.Default.bCanPickupInventory )
			PawnClass = pClass;
	}

    PawnSetupRecord = class'xUtil'.static.FindPlayerRecord(inCharacter);
    PlayerReplicationInfo.SetCharacterName(inCharacter);
}

function SetPawnFemale()
{
	if ( PawnSetupRecord.Species == None )
		PlayerReplicationInfo.bIsFemale = true;
}

function Possess( Pawn aPawn )
{
    local xPawn xp;

    Super.Possess( aPawn );

    xp = xPawn(aPawn);
	if(xp != None)
		xp.Setup(PawnSetupRecord, true);
	if ( Level.NetMode != NM_DedicatedServer )
		ServerSetClassicTrans(bClassicTrans);
}

// for changing character on the fly (for next respawn)
exec function ChangeCharacter(string newCharacter, optional string inClass)
{
    SetPawnClass(string(PawnClass), newCharacter);
	UpdateURL("Character", newCharacter, true);
    SaveConfig();
}

simulated function bool NeedNetNotify()
{
	return Super.NeedNetNotify() || bWaitingForPRI || (bVoiceChatEnabled && bWaitingForVRI);
}

simulated event PostNetReceive()
{
    local xUtil.PlayerRecord rec;

	Super.PostNetReceive();

	if ( PlayerReplicationInfo != None && bWaitingForPRI )
    {
		bWaitingForPRI = False;

        	rec = class'xUtil'.static.FindPlayerRecord(PlayerReplicationInfo.CharacterName);

		if ( rec.Species != None )
		{
			if ( PlayerReplicationInfo.Team == None )
				rec.Species.static.LoadResources(rec, Level, PlayerReplicationInfo, 255);
			else
				rec.Species.static.LoadResources(rec, Level, PlayerReplicationInfo, PlayerReplicationInfo.Team.TeamIndex);
		}

        // Handle auto Demo Recording

		if ( bAutoDemoRec && level.NetMode==NM_Client && !bDemoOwner )
			Player.Console.DelayedConsoleCommand("demorec");
    }

	if ( VoiceReplicationInfo != None && bWaitingForVRI )
	{
		if ( PlayerReplicationInfo != None && !PlayerReplicationInfo.NeedNetNotify() )
		{
			bWaitingForVRI = VoiceReplicationInfo.GetPublicChannelCount(true) == 0;
			if ( !bWaitingForVRI )
			{
				VoiceReplicationInfo.SetOwner(Self);
				if ( bVoiceChatEnabled )
					InitializeVoiceChat();
				else DisableVoiceChat();
			}
		}
	}

	bNetNotify = NeedNetNotify();
}

exec function AdminMenu( string CommandLine )
{
}

function ServerRequestPlayerInfo()
{
	local Controller C;
    local xPlayer xPC;

    for (C=Level.ControllerList;C!=None;C=C.NextController)
    {
    	xPC = XPlayer(C);
        if (xPC!=None)
			ClientReceiveRule(xPC.PlayerReplicationInfo.PlayerName$chr(27)$xPC.GetPlayerIDHash()$chr(27)$xPC.GetPlayerNetworkAddress());
		else
        	ClientReceiveRule(C.PlayerReplicationInfo.PlayerName$chr(27)$"AI Controlled"$chr(27)$"BOT");
	}

	ClientReceiveRule("Done");
}

exec function SpecViewGoal()
{
	ServerSpecViewGoal();
}

function ServerSpecViewGoal()
{
 	local actor NewGoal;

    if ( PlayerReplicationInfo.bOnlySpectator && IsInState('Spectating') )
    {
    	NewGoal = Level.Game.FindSpecGoalFor(PlayerReplicationInfo,0);
        if (NewGoal!=None)
        {
        	if ( Pawn(NewGoal)!=None )
            {
                SetViewTarget(NewGoal);
			    ClientSetViewTarget(NewGoal);
		        bBehindView = true; //bChaseCam;
        	}
            else
            {
            	SetViewTarget(None);
                ClientSetViewTarget(None);
                bBehindView = false;

                SetLocation(NewGoal.Location);
                ClientSetLocation(NewGoal.Location,Rotation);
            }
        }
    }
}

// =====================================================================================================================
// =====================================================================================================================
//  Chat Manager
// =====================================================================================================================
// =====================================================================================================================
function ServerRequestBanInfo(int PlayerID)
{
	local array<PlayerController> CArr;
	local int i;
	//log(Name@"ServerRequestBanInfo:"$PlayerID,'ChatManager');
	if ( Level != None && Level.Game != None )
	{
		Level.Game.GetPlayerControllerList(CArr);
		for (i = 0; i < CArr.Length; i++)
		{
			// Don't send our own info
			if ( CArr[i] == Self )
				continue;

			//log(Name@"ServerRequestBanInfo CArr["$i$"]:"$CArr[i]@"ID:"$CArr[i].PlayerReplicationInfo.PlayerID,'ChatManager');
			if ( PlayerID == -1 || CArr[i].PlayerReplicationInfo.PlayerID == PlayerID )
			{
				log(Name@"Sending BanInfo To Client PlayerID:"$CArr[i].PlayerReplicationInfo.PlayerID@"Hash:"$CArr[i].GetPlayerIDHash()@"Address:"$CArr[i].GetPlayerNetworkAddress(),'ChatManager');
				ChatManager.TrackNewPlayer(CArr[i].PlayerReplicationInfo.PlayerID, CArr[i].GetPlayerIDHash(), CArr[i].GetPlayerNetworkAddress());
				ClientReceiveBan(CArr[i].PlayerReplicationInfo.PlayerID$Chr(27)$CArr[i].GetPlayerIDHash()$chr(27)$CArr[i].GetPlayerNetworkAddress());
			}
		}
	}
}

function ClientReceiveBan(string BanInfo)
{
	if ( UnrealPlayerChatManager(ChatManager) != None )
		UnrealPlayerChatManager(ChatManager).ReceiveBanInfo(BanInfo);
}


// =====================================================================================================================
// =====================================================================================================================
//  Voice Chat
// =====================================================================================================================
// =====================================================================================================================
simulated function InitializeVoiceChat()
{
	Super.InitializeVoiceChat();

	// Check player hashes for all players on the server
	ServerRequestBanInfo(-1);
}

simulated exec function ShowAliases()
{
	local array<string> Output;
	local Security S;
	local int i;

	S = Spawn(class'Engine.Security');
	if (S!=None)
	{
		S.LocalPerform(100,"","",Output);
		Log("No of Aliases:"@Output.Length);
		for (i=0;i<Output.Length;i++)
		  log("   Alias"@i$":"@Output[i]);

		S.Destroy();
	}
}

simulated exec function ShowBindings()
{
	local array<string> Output;
	local Security S;
	local int i;

	S = Spawn(class'Engine.Security');
	if (S!=None)
	{
		S.LocalPerform(101,"","",Output);
		Log("No of Bindings:"@Output.Length);
		for (i=0;i<Output.Length;i++)
		  log("   Binding"@i$":"@Output[i]);

		S.Destroy();
	}
}

exec function check()
{
	local decoration d;
	foreach allactors(class'decoration',d)
		log("#### D:"@D@vsize(pawn.location - d.location));
}

defaultproperties
{
	bClassicTrans=false
	bHighBeaconTrajectory=false
    bNetNotify=true
    bWaitingForPRI=True
    bWaitingForVRI=True
    TeamBeaconTexture=none//Texture'TeamSymbols.TeamBeaconT'
    LinkBeaconTexture=none//Texture'TeamSymbols.LinkBeaconT'
	SpeakingBeaconTexture=Texture'InterfaceArt_tex.SoundBeacon_a00'
    curcam=-1
    // if _RO_
    //ComboNameList(0)="XGame.ComboSpeed"
    //ComboNameList(1)="XGame.ComboBerserk"
    //ComboNameList(2)="XGame.ComboDefensive"
    //ComboNameList(3)="XGame.ComboInvis"
    PlayerReplicationInfoClass=Class'xGame.xPlayerReplicationInfo'
    PawnClass=class'xGame.xPawn'
    MinAdrenalineCost=100.0
    bAutoDemoRec=false
}
