class HudBase extends HUD
    config(user)
    native;

// RO
//#exec OBJ LOAD FILE=HudContent.utx

cpptext
{

	void	CalcPivotCoords( EDrawPivot DrawPivot, FLOAT& ScreenX, FLOAT& ScreenY, FLOAT ScreenDX, FLOAT ScreenDY );
	UBOOL	MemoryIsZero( const void* Memory, size_t Size );

	void DrawSpriteWidget( UCanvas* Canvas, FSpriteWidget* Widget );
	void DrawNumericWidget( UCanvas* Canvas, FNumericWidget* Widget, FDigitSet* D );
}

enum EScaleMode
{
    SM_None,
    SM_Up,
    SM_Down,
    SM_Left,
    SM_Right
};

struct native DigitSet
{
    var Material DigitTexture;
    var IntBox TextureCoords[11]; // 0-9, 11th element is negative sign
};

struct native SpriteWidget
{
    var Material WidgetTexture;

    var ERenderStyle RenderStyle;

    var IntBox TextureCoords;
    var float TextureScale;

    var EDrawPivot DrawPivot;
    var float PosX, PosY;
    var int OffsetX, OffsetY;

    var EScaleMode ScaleMode;
    var float Scale;

    var Color Tints[2];
};

struct native NumericWidget
{
    var ERenderStyle RenderStyle;

    var int MinDigitCount;

    var float TextureScale;

    var EDrawPivot DrawPivot;
    var float PosX, PosY;
    var int OffsetX, OffsetY;

    var Color Tints[2];

    var int bPadWithZeroes;

    var transient int Value;
};

var() transient int TeamIndex;

var() transient ERenderStyle PassStyle; // For debugging.

struct native HudLocalizedMessage
{
    // The following block of variables are set when the message is entered;
    // (Message being set indicates that a message is in the list).

	var class<LocalMessage> Message;
	var String StringMessage;
	var int Switch;
	var PlayerReplicationInfo RelatedPRI, RelatedPRI2;
	var Object OptionalObject;
	var float EndOfLife;
	var float LifeTime;

    // The following block of variables are cached on first render;
    // (StringFont being set indicates that they've been rendered).

	var Font StringFont;
	var Color DrawColor;
    var EDrawPivot DrawPivot;
    var LocalMessage.EStackMode StackMode;
	var float PosX, PosY;
	var float DX, DY;

	var bool Drawn;
};

var() transient HudLocalizedMessage LocalMessages[8];
var() class<Actor> VoteMenuClass;						// hook for mod authors

// targeting
var Material TargetMaterial;
var transient bool bShowTargeting;
var transient Vector TargetingLocation;
var transient float TargetingSize;

// instruction
var() string InstructionText;
var() string InstructionKeyText;
var() float InstructTextBorderX;
var() float InstructTextBorderY;
var() float InstrDelta;
var() float InstrRate;
var() localized string InstructionFontName;
var() font InstructionFontFont;

var bool bUsingCustomHUDColor;
var() bool DoCropping;
var bool bIsCinematic;

var   byte FontsPrecached;
var globalconfig bool bHideWeaponName;

var() float CroppingAmount;
var() Material CroppingMaterial;

var string LastWeaponName;
var float  WeaponDrawTimer;
var color  WeaponDrawColor;

var() localized String text;
var() localized String LevelActionLoading, LevelActionPaused;
var() localized String LevelActionFontName;
var localized string WonMatchPrefix, WonMatchPostFix, WaitingToSpawn, AtMenus;
var localized string YouveWonTheMatch, YouveLostTheMatch, NowViewing,ScoreText;
var localized string InitialViewingString;

var Material LocationDot;

var color DamageFlash[4];
var float DamageTime[4];
var() byte Emphasized[4];

var() array<SpriteWidget> Crosshairs;
var globalconfig color CustomHUDColor;
var globalconfig bool bUseCustomWeaponCrosshairs;

// G15 LCD Updates

var float LastLCDUpdateTime;
var config float LCDUpdateFreq;
var config int LCDDisplayMode;
var int LCDPage;

// Derived HUDs override UpdateHud to update variables before rendering;
// NO draw code should be in derived DrawHud's; they should instead override
// DrawHudPass[A-D] and call their base class' DrawHudPass[A-D] (This cuts
// down on render state changes).

simulated function UpdateHud();

simulated function DrawHudPassA (Canvas C); // Alpha Pass
simulated function DrawHudPassB (Canvas C); // Additive Pass
simulated function DrawHudPassC (Canvas C); // Alpha Pass
simulated function DrawHudPassD (Canvas C); // Alternate Texture Pass

simulated function PrecacheFonts(Canvas C)
{
	FontsPrecached++;
	C.Font = GetConsoleFont(C);
	C.SetPos(0,0);
	C.DrawText("<>_Aa1");

	C.Font = GetFontSizeIndex(C,-2);
	C.SetPos(0,0);
	C.DrawText("Aa1");

	C.Font = GetFontSizeIndex(C,-4);
	C.SetPos(0,0);
	C.DrawText("Aa1");

	C.Font = GetFontSizeIndex(C,MessageFontOffset);
	C.SetPos(0,0);
	C.DrawText("Aa1");

	C.Font = GetFontSizeIndex(C,1 + MessageFontOffset);
	C.SetPos(0,0);
	C.DrawText("Aa1");

	C.Font = GetFontSizeIndex(C,2 + MessageFontOffset);
	C.SetPos(0,0);
	C.DrawText("Aa1");

	C.Font = GetFontSizeIndex(C,3 + MessageFontOffset);
	C.SetPos(0,0);
	C.DrawText("Aa1");
}

function PostBeginPlay()
{
	Super.PostBeginPlay();

	if (CustomHUDColorAllowed())
		SetCustomHUDColor();
}

function bool CustomHUDColorAllowed()
{
	return false;
}

function SetCustomHUDColor();

/* DisplayHit()
Directions are
0 = top
1 = bottom
2 = right
3 = left
*/
function DisplayHit(vector HitDir, int Damage, class<DamageType> damageType)
{
	local int i;
	local vector X,Y,Z;
	local byte Ignore[4];
	local rotator LookDir;
	local float NewDamageTime,Forward,Left;

	LookDir = PawnOwner.Rotation;
	LookDir.Pitch = 0;
	GetAxes(LookDir, X,Y,Z);
	HitDir.Z = 0;
	HitDir = Normal(HitDir);

	Forward = HitDir Dot X;
	Left = HitDir Dot Y;

	if ( Forward > 0 )
	{
		if ( Forward > 0.7 )
			Emphasized[0] = 1;
		Ignore[1] = 1;
	}
	else
	{
		if ( Forward < -0.7 )
			Emphasized[1] = 1;
		Ignore[0] = 1;
	}
	if ( Left > 0 )
	{
		if ( Left > 0.7 )
			Emphasized[3] = 1;
		Ignore[2] = 1;
	}
	else
	{
		if ( Left < -0.7 )
			Emphasized[2] = 1;
		Ignore[3] = 1;
	}

	NewDamageTime = 5 * Clamp(Damage,20,30);
	for ( i=0; i<4; i++ )
		if ( Ignore[i] != 1 )
		{
			DamageFlash[i].R = 255;
			DamageTime[i] = NewDamageTime;
		}
}

function DrawDamageIndicators(Canvas C)
{
// if _RO_
/*
// end if _RO_
	if ( DamageTime[0] > 0 )
	{
		C.SetPos(0,0);
		C.DrawColor = DamageFlash[0];
		C.DrawColor.A = DamageTime[0];
		if ( Emphasized[0] == 1 )
			C.DrawTile( Texture'HudContent.HUD', C.ClipX, 0.15*C.ClipY, 395, 219, 21, -10);
		else
			C.DrawTile( Texture'HudContent.HUD', C.ClipX, 0.05*C.ClipY, 395, 219, 21, -10);
	}
	else
		Emphasized[0] = 0;

	if ( DamageTime[1] > 0 )
	{
		C.DrawColor = DamageFlash[1];
		C.DrawColor.A = DamageTime[1];
		if ( Emphasized[1] == 1 )
		{
			C.SetPos(0,0.85*C.ClipY);
			C.DrawTile( Texture'HudContent.HUD', C.ClipX, 0.15*C.ClipY, 395, 209, 21, 10);
		}
		else
		{
			C.SetPos(0,0.9*C.ClipY);
			C.DrawTile( Texture'HudContent.HUD', C.ClipX, 0.1*C.ClipY, 395, 209, 21, 10);
		}
	}
	else
		Emphasized[1] = 0;

	if ( DamageTime[2] > 0 )
	{
		C.SetPos(0,0);
		C.DrawColor = DamageFlash[2];
		C.DrawColor.A = DamageTime[2];
		if ( Emphasized[2] == 1 )
			C.DrawTile( Texture'HudContent.HUD', 0.15*C.ClipX, C.ClipY, 404, 182, 12, 21);
		else
			C.DrawTile( Texture'HudContent.HUD', 0.05*C.ClipX, C.ClipY, 404, 182, 12, 21);
	}
	else
		Emphasized[2] = 0;

	if ( DamageTime[3] > 0 )
	{
		C.DrawColor = DamageFlash[3];
		C.DrawColor.A = DamageTime[3];
		if ( Emphasized[3] == 1 )
		{
			C.SetPos(0.85*C.ClipX,0);
			C.DrawTile( Texture'HudContent.HUD', 0.15*C.ClipX, C.ClipY, 416, 182, -12, 21);
		}
		else
		{
			C.SetPos(0.95*C.ClipX,0);
			C.DrawTile( Texture'HudContent.HUD', 0.05*C.ClipX, C.ClipY, 416, 182, -12, 21);
		}
	}
	else
		Emphasized[3] = 0;
// if _RO_
*/
// end if _RO_

}

simulated function Tick(float deltaTime)
{
	local int i;

	for ( i=0; i<4; i++ )
		if ( DamageTime[i] > 0 )
		{
			DamageTime[i] -= 120 * DeltaTime;
			if ( DamageTime[i] < 1 )
				DamageTime[i] = 0;
		}
}

simulated function DrawHeadShotSphere() // Dave@Psyonix
{
    local coords CO;
    local Pawn P;
    local vector HeadLoc;

    foreach DynamicActors(class'Pawn', P)
    {
        if (P != None && P.HeadBone != '')
        {
            CO = P.GetBoneCoords(P.HeadBone);
            HeadLoc = CO.Origin + (P.HeadHeight * P.HeadScale * CO.XAxis);
            P.DrawDebugSphere(HeadLoc, P.HeadRadius * P.HeadScale, 10, 0, 255, 0);
        }
    }
}

simulated function DrawHud (Canvas C)
{
	if ( FontsPrecached < 2 )
		PrecacheFonts(C);
    Super.DrawHud(C);

    UpdateHud();

    if( bShowTargeting )
        DrawTargeting(C);

    PassStyle = STY_Alpha;
	DrawDamageIndicators(C);
    DrawHudPassA(C);
    PassStyle = STY_Additive;
    DrawHudPassB(C);
    PassStyle = STY_Alpha;
    DrawHudPassC(C);
    PassStyle = STY_None;
    DrawHudPassD(C);

    DisplayLocalMessages(C);
    DrawWeaponName(C);
    DrawVehicleName(C);
//    DrawHeadShotSphere();
}

native simulated function DrawSpriteWidget (Canvas C, out SpriteWidget W);
native simulated function DrawNumericWidget (Canvas C, out NumericWidget W, out DigitSet D);

simulated function ClearMessage( out HudLocalizedMessage M )
{
	M.Message = None;
    M.StringFont = None;
}

simulated function Message( PlayerReplicationInfo PRI, coerce string Msg, name MsgType )
{
	local Class<LocalMessage> LocalMessageClass;

	switch( MsgType )
	{
		case 'Say':
			if ( PRI == None )
				return;
			Msg = PRI.PlayerName$": "$Msg;
			LocalMessageClass = class'SayMessagePlus';
			break;
		case 'TeamSay':
			if ( PRI == None )
				return;
			Msg = PRI.PlayerName$"("$PRI.GetLocationName()$"): "$Msg;
			LocalMessageClass = class'TeamSayMessagePlus';
			break;
		case 'CriticalEvent':
			LocalMessageClass = class'CriticalEventPlus';
			LocalizedMessage( LocalMessageClass, 0, None, None, None, Msg );
			return;
		case 'DeathMessage':
			LocalMessageClass = class'xDeathMessage';
			break;
		default:
			LocalMessageClass = class'StringMessagePlus';
			break;
	}

	AddTextMessage(Msg,LocalMessageClass,PRI);
}

simulated function LocalizedMessage( class<LocalMessage> Message, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject, optional String CriticalString)
{
	local int i;
	local PlayerReplicationInfo HUDPRI;

    if( Message == None )
        return;

    if( bIsCinematic && !ClassIsChildOf(Message,class'ActionMessage') )
		return;

    if( CriticalString == "" )
    {
		if ( (PawnOwner != None) && (PawnOwner.PlayerReplicationInfo != None) )
			HUDPRI = PawnOwner.PlayerReplicationInfo;
		else
			HUDPRI = PlayerOwner.PlayerReplicationInfo;
		if ( HUDPRI == RelatedPRI_1 )
			CriticalString = Message.static.GetRelatedString( Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
		else
			CriticalString = Message.static.GetString( Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
	}

	if( bMessageBeep && Message.default.bBeep )
		PlayerOwner.PlayBeepSound();

    if( !Message.default.bIsSpecial )
    {
		if ( PlayerOwner.bDemoOwner )
		{
			for( i=0; i<ConsoleMessageCount; i++ )
				if ( i >= ArrayCount(TextMessages) || TextMessages[i].Text == "" )
					break;

			if ( i > 0 && TextMessages[i-1].Text == CriticalString )
				return;
		}
	    AddTextMessage( CriticalString, Message,RelatedPRI_1 );
        return;
    }

    i = ArrayCount(LocalMessages);
	if( Message.default.bIsUnique )
	{
		for( i = 0; i < ArrayCount(LocalMessages); i++ )
		{
		    if( LocalMessages[i].Message == None )
                continue;

		    if( LocalMessages[i].Message == Message )
                break;
		}
	}
	else if ( Message.default.bIsPartiallyUnique || PlayerOwner.bDemoOwner )
	{
		for( i = 0; i < ArrayCount(LocalMessages); i++ )
		{
		    if( LocalMessages[i].Message == None )
                continue;

		    if( ( LocalMessages[i].Message == Message ) && ( LocalMessages[i].Switch == Switch ) )
                break;
        }
	}

    if( i == ArrayCount(LocalMessages) )
    {
	    for( i = 0; i < ArrayCount(LocalMessages); i++ )
	    {
		    if( LocalMessages[i].Message == None )
                break;
	    }
    }

    if( i == ArrayCount(LocalMessages) )
    {
	    for( i = 0; i < ArrayCount(LocalMessages) - 1; i++ )
		    LocalMessages[i] = LocalMessages[i+1];
    }

    ClearMessage( LocalMessages[i] );

	LocalMessages[i].Message = Message;
	LocalMessages[i].Switch = Switch;
	LocalMessages[i].RelatedPRI = RelatedPRI_1;
	LocalMessages[i].RelatedPRI2 = RelatedPRI_2;
	LocalMessages[i].OptionalObject = OptionalObject;
	LocalMessages[i].EndOfLife = Message.static.GetLifetime(Switch) + Level.TimeSeconds;
	LocalMessages[i].StringMessage = CriticalString;
	LocalMessages[i].LifeTime = Message.static.GetLifetime(Switch);
}

static function color GetTeamColor(byte TeamNum)
{
	return Default.BlackColor;
}

function GetLocalStatsScreen()
{
	if ( (PlayerOwner != None) && (TeamPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo) != None)
		&& (TeamPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).LocalStatsScreenClass != None) )
		LocalStatsScreen = spawn(TeamPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).LocalStatsScreenClass, Owner);
}

simulated function LayoutMessage( out HudLocalizedMessage Message, Canvas C )
{
    local int FontSize;

    FontSize = Message.Message.static.GetFontSize( Message.Switch, Message.RelatedPRI, Message.RelatedPRI2, PlayerOwner.PlayerReplicationInfo );
    FontSize += MessageFontOffset;
    Message.StringFont = GetFontSizeIndex(C,FontSize);
	Message.DrawColor = Message.Message.static.GetColor( Message.Switch, Message.RelatedPRI, Message.RelatedPRI2 );
    Message.Message.static.GetPos( Message.Switch, Message.DrawPivot, Message.StackMode, Message.PosX, Message.PosY );
    C.Font = Message.StringFont;
    C.TextSize( Message.StringMessage, Message.DX, Message.DY );
}

simulated function GetScreenCoords(float PosX, float PosY, out float ScreenX, out float ScreenY, out HudLocalizedMessage Message, Canvas C )
{
    ScreenX = (PosX * HudCanvasScale * C.ClipX) + (((1.0f - HudCanvasScale) * 0.5f) * C.ClipX);
    ScreenY = (PosY * HudCanvasScale * C.ClipY) + (((1.0f - HudCanvasScale) * 0.5f) * C.ClipY);

    switch( Message.DrawPivot )
    {
        case DP_UpperLeft:
            break;

        case DP_UpperMiddle:
            ScreenX -= Message.DX * 0.5;
            break;

        case DP_UpperRight:
            ScreenX -= Message.DX;
            break;

        case DP_MiddleRight:
            ScreenX -= Message.DX;
            ScreenY -= Message.DY * 0.5;
            break;

        case DP_LowerRight:
            ScreenX -= Message.DX;
            ScreenY -= Message.DY;
            break;

        case DP_LowerMiddle:
            ScreenX -= Message.DX * 0.5;
            ScreenY -= Message.DY;
            break;

        case DP_LowerLeft:
            ScreenY -= Message.DY;
            break;

        case DP_MiddleLeft:
            ScreenY -= Message.DY * 0.5;
            break;

        case DP_MiddleMiddle:
            ScreenX -= Message.DX * 0.5;
            ScreenY -= Message.DY * 0.5;
            break;

    }
}

simulated function DrawMessage( Canvas C, int i, float PosX, float PosY, out float DX, out float DY )
{
    local float FadeValue;
    local float ScreenX, ScreenY;

	if ( !LocalMessages[i].Message.default.bFadeMessage )
		C.DrawColor = LocalMessages[i].DrawColor;
	else
	{
		FadeValue = (LocalMessages[i].EndOfLife - Level.TimeSeconds);
		C.DrawColor = LocalMessages[i].DrawColor;
		C.DrawColor.A = LocalMessages[i].DrawColor.A * (FadeValue/LocalMessages[i].LifeTime);
	}

	C.Font = LocalMessages[i].StringFont;
	GetScreenCoords( PosX, PosY, ScreenX, ScreenY, LocalMessages[i], C );
	C.SetPos( ScreenX, ScreenY );
	DX = LocalMessages[i].DX / C.ClipX;
    DY = LocalMessages[i].DY / C.ClipY;

	if ( LocalMessages[i].Message.default.bComplexString )
	{
		LocalMessages[i].Message.static.RenderComplexMessage( C, LocalMessages[i].DX, LocalMessages[i].DY,
			LocalMessages[i].StringMessage, LocalMessages[i].Switch, LocalMessages[i].RelatedPRI,
			LocalMessages[i].RelatedPRI2, LocalMessages[i].OptionalObject );
	}
	else
	{
		C.DrawTextClipped( LocalMessages[i].StringMessage, false );
	}

    LocalMessages[i].Drawn = true;
}

simulated function DisplayLocalMessages( Canvas C )
{
	local float PosX, PosY, DY, DX;
    local int i, j;
    local float FadeValue;
    local Plane OldCM;

    OldCM=C.ColorModulate;
	C.Reset();
    C.ColorModulate = OldCM;

    // Pass 1: Layout anything that needs it and cull dead stuff.

    for( i = 0; i < ArrayCount(LocalMessages); i++ )
    {
		if( LocalMessages[i].Message == None )
            break;

        LocalMessages[i].Drawn = false;

        if( LocalMessages[i].StringFont == None )
            LayoutMessage( LocalMessages[i], C );

        if( LocalMessages[i].StringFont == None )
        {
            log( "LayoutMessage("$LocalMessages[i].Message$") failed!", 'Error' );

	        for( j = i; j < ArrayCount(LocalMessages) - 1; j++ )
		        LocalMessages[j] = LocalMessages[j+1];
            ClearMessage( LocalMessages[j] );
            i--;
            continue;
        }

		if( LocalMessages[i].Message.default.bFadeMessage )
		{
			FadeValue = (LocalMessages[i].EndOfLife - Level.TimeSeconds);

			if( FadeValue <= 0.0 )
            {
	            for( j = i; j < ArrayCount(LocalMessages) - 1; j++ )
		            LocalMessages[j] = LocalMessages[j+1];
                ClearMessage( LocalMessages[j] );
                i--;
                continue;
            }
        }
    }

    // Pass 2: Go through the list and draw each stack:

    for( i = 0; i < ArrayCount(LocalMessages); i++ )
	{
		if( LocalMessages[i].Message == None )
            break;

        if( LocalMessages[i].Drawn )
            continue;

	    PosX = LocalMessages[i].PosX;
	    PosY = LocalMessages[i].PosY;

        if( LocalMessages[i].StackMode == SM_None )
        {
            DrawMessage( C, i, PosX, PosY, DX, DY );
            continue;
        }

        for( j = i; j < ArrayCount(LocalMessages); j++ )
        {
            if( LocalMessages[j].Drawn )
                continue;

            if( LocalMessages[i].PosX != LocalMessages[j].PosX )
                continue;

            if( LocalMessages[i].PosY != LocalMessages[j].PosY )
                continue;

            if( LocalMessages[i].DrawPivot != LocalMessages[j].DrawPivot )
                continue;

            if( LocalMessages[i].StackMode != LocalMessages[j].StackMode )
                continue;

            DrawMessage( C, j, PosX, PosY, DX, DY );

            switch( LocalMessages[j].StackMode )
            {
                case SM_Up:
                    PosY -= DY;
                    break;

                case SM_Down:
                    PosY += DY;
                    break;
            }
        }
    }
}

simulated function CreateKeyMenus() // create vote/speech menus here
{
	if ( (PlayerController(Owner).PlayerReplicationInfo != None)
		&& PlayerController(Owner).PlayerReplicationInfo.bOnlySpectator )
		return;
    if( VoteMenuClass != None )
        VoteMenu = Spawn(VoteMenuClass,self);
}

function Draw2DLocationDot(Canvas C, vector Loc,float OffsetX, float OffsetY, float ScaleX, float ScaleY)
{
	local rotator Dir;
	local float Angle, Scaling;
	local Actor Start;

	if ( PawnOwner == None )
		Start = PlayerOwner;
	else
		Start = PawnOwner;

	Dir = rotator(Loc - Start.Location);
	Angle = ((Dir.Yaw - PlayerOwner.Rotation.Yaw) & 65535) * 6.2832/65536;
	C.Style = ERenderStyle.STY_Alpha;
	C.SetPos(OffsetX * C.ClipX + ScaleX * C.ClipX * sin(Angle),
			OffsetY * C.ClipY - ScaleY * C.ClipY * cos(Angle));

	Scaling = 24*C.ClipX*HUDScale/1600;

// if _RO_
	C.DrawTile(LocationDot, Scaling, Scaling,0,0,31,31);
// else
//	C.DrawTile(LocationDot, Scaling, Scaling,340,432,78,78);
// end if _ROR
}

simulated function SetTargeting( bool bShow, optional Vector TargetLocation, optional float Size )
{
    bShowTargeting = bShow;
    if( bShow )
    {
        TargetingLocation = TargetLocation;
        if( Size != 0.0 )
            TargetingSize = Size;
    }
}

simulated function DrawTargeting( Canvas C )
{
    local int XPos, YPos;
    local vector ScreenPos;
    local vector X,Y,Z,Dir;
    local float RatioX, RatioY;
    local float tileX, tileY;
    local float Dist;

    local float SizeX;
    local float SizeY;

    SizeX = TargetingSize * 96.0;
    SizeY = TargetingSize * 96.0;

    if( !bShowTargeting )
        return;

    ScreenPos = C.WorldToScreen( TargetingLocation );

    RatioX = C.SizeX / 640.0;
    RatioY = C.SizeY / 480.0;

    tileX = sizeX * RatioX;
    tileY = sizeY * RatioX;

    GetAxes(PlayerOwner.Rotation, X,Y,Z);
	Dir = TargetingLocation - PawnOwner.Location;
	Dist = VSize(Dir);
	Dir = Dir/Dist;

    if ( (Dir Dot X) > 0.6 ) // don't draw if it's behind the eye
	{
		XPos = ScreenPos.X;
		YPos = ScreenPos.Y;
        C.Style = ERenderStyle.STY_Additive;
        C.DrawColor.R = 255;
        C.DrawColor.G = 255;
        C.DrawColor.B = 255;
        C.DrawColor.A = 255;
		C.SetPos(XPos - tileX*0.5, YPos - tileY*0.5);
        C.DrawTile( TargetMaterial, tileX, tileY, 0.0, 0.0, 256, 256); //--- TODO : Fix HARDCODED USIZE
        //log("Drawing passtarget focus1");
	}
}

simulated function SetCropping( bool Active )
{
    DoCropping = active;
}

simulated function DrawInstructionGfx(Canvas C)
{
    local float CropHeight;

    //log("DrawInstructionGfx");

    DrawCrosshair(C);
    DrawTargeting(C);
    if( DoCropping )
    {
        // todo: lerp the crop height
        CropHeight = (C.SizeY * CroppingAmount) * 0.5;
        C.SetPos(0, 0);
        C.DrawTile( Texture'Engine.BlackTexture', C.SizeX, CropHeight, 0.0, 0.0, 64, 64 );
        C.SetPos( 0, C.SizeY-CropHeight );
        C.DrawTile( Texture'Engine.BlackTexture', C.SizeX, CropHeight, 0.0, 0.0, 64, 64 );
    }
    DrawInstructionText(C);
    DrawInstructionKeyText(C);
}

simulated function DrawInstructionText(Canvas C)
{
    if( InstructionText == "" )
        return;

    C.Font = LoadInstructionFont();

    C.SetOrigin( InstructTextBorderX, InstructTextBorderY );
    C.SetClip( C.SizeX-InstructTextBorderX, C.SizeY );
    C.SetPos(0,0);

	C.DrawText( InstructionText );

    C.SetOrigin(0.0, 0.0);
    C.SetClip( C.SizeX, C.SizeY );
}

simulated function DrawInstructionKeyText(Canvas C)
{
    local float strX;
    local float strY;

    if( InstructionKeyText == "" )
        return;

    C.Font = LoadInstructionFont();
    C.SetOrigin( InstructTextBorderX, InstructTextBorderY );
    C.SetClip( C.SizeX-InstructTextBorderX, C.SizeY );

    C.StrLen( InstructionKeyText, strX, strY );

    C.SetOrigin( InstructTextBorderX, C.SizeY-strY-InstructTextBorderY );
    C.SetClip( C.SizeX-InstructTextBorderX, C.SizeY );
    C.SetPos(0,0);

	C.DrawText( InstructionKeyText );

    C.SetOrigin(0.0, 0.0);
    C.SetClip( C.SizeX, C.SizeY );
}

simulated function SetInstructionText( string text )
{
    InstructionText = text;
}

simulated function SetInstructionKeyText( string text )
{
    InstructionKeyText = text;
}

simulated function font LoadInstructionFont()
{
	if( InstructionFontFont == None )
	{
		InstructionFontFont = Font(DynamicLoadObject(InstructionFontName, class'Font'));
		if( InstructionFontFont == None )
			Log("Warning: "$Self$" Couldn't dynamically load font "$InstructionFontName);
	}
	return InstructionFontFont;
}

simulated function DrawWeaponName(Canvas C)
{
	local string CurWeaponName;
    local float XL,YL, Fade;

	if (bHideWeaponName)
    	return;

	if (WeaponDrawTimer>Level.TimeSeconds)
    {
	    C.Font = GetMediumFontFor(C);
        C.DrawColor = WeaponDrawColor;

		Fade = WeaponDrawTimer - Level.TimeSeconds;

        if (Fade<=1)
        	C.DrawColor.A = 255 * Fade;


		C.Strlen(LastWeaponName,XL,YL);
        C.SetPos( (C.ClipX/2) - (XL/2), C.ClipY*0.8-YL);
        C.DrawText(LastWeaponName);
    }

	if (  PawnOwner==None || PawnOwner.PendingWeapon==None )
    	return;

	CurWeaponName = PawnOwner.PendingWeapon.GetHumanReadableName();
    if (CurWeaponName!=LastWeaponName)
    {
    	WeaponDrawTimer = Level.TimeSeconds+1.5;
        WeaponDrawColor = PawnOwner.PendingWeapon.HudColor;
    }

   	LastWeaponName = CurWeaponName;
}

function DrawVehicleName(Canvas C);

/* called when viewing a Matinee cinematic */
simulated function DrawCinematicHUD(Canvas C)
{
	Super.DrawCinematicHUD(C);

	if (SubTitles != None)
		DrawIntroSubtitles(C);
	else if (bHideHUD)
		DisplayLocalMessages(C);
}

simulated function DrawIntroSubtitles( Canvas C )
{
	local String	CurrentSubTitles;
	local float		XL, YL, YO;
	local Array<String>	OutArray;
	local int		i;

	CurrentSubTitles = SubTitles.GetSubTitles();
	if ( CurrentSubTitles == "" )
		return;

	C.DrawColor = WhiteColor;
	C.Style		= ERenderStyle.STY_Alpha;
	C.Font		= GetFontSizeIndex( C, -1 );

	C.WrapStringToArray(CurrentSubTitles, OutArray, C.ClipX*0.75);
	C.StrLen( OutArray[i], XL, YL );
	YO = FMin(C.ClipY*0.9 - YL*0.5*OutArray.Length, C.ClipY - (OutArray.Length+1.1)*YL);

	for (i=0; i<OutArray.Length; i++)
	{
		C.StrLen( OutArray[i], XL, YL );
		C.SetPos( (C.ClipX-XL)*0.5, YO + YL*i );
		C.DrawText( OutArray[i], false );
	}
}

// G15 support

simulated event PostRender( canvas Canvas )
{
	super.PostRender(Canvas);

	if (GUIController(PlayerOwner.Player.GUIController).bLCDAvailable() )
	{
		if (Level.TimeSeconds  - LastLCDUpdateTime > LCDUpdateFreq)
		{
			LastLCDUpdateTime = Level.TimeSeconds;
			DrawLCDUpdate(Canvas);
		}
	}
}

simulated function DrawLCDUpdate(Canvas C)
{
	local GUIController GC;

	GC = GUIController(PlayerOwner.Player.GUIController);

	switch (LCDDisplayMode)
	{
		case 0: 		// Player Status
			DrawLCDPlayerStatus(C,GC);
			break;

		case 1: 		// Objectives
			DrawLCDObjectives(C,GC);
			break;

		case 2:			// Score
			DrawLCDScore(C,GC);
			break;

		case 3:			// Ping and Packet Loss
			DrawLCDNetStat(C,GC);
			break;
	}
}

// Implemented in subclasses
simulated function DrawLCDObjectives(Canvas C, GUIController GC){}
simulated function DrawLCDPlayerStatus(Canvas C, GUIController GC){}

simulated function DrawLCDNetStat(Canvas C, GUIController GC)
{
	GC.LCDCls();
	GC.LCDDrawTile(GC.LCDLogo,0,0,50,43,0,0,50,43);
	GC.LCDDrawText(PlayerOwner.PlayerReplicationInfo.PlayerName,55,0,GC.LCDTinyFont);
	GC.LCDDrawTile(Texture'engine.WhiteSquareTexture',55,10,95,1,0,0,1,1);
	GC.LCDDrawText(""$(4*PlayerOwner.PlayerReplicationInfo.Ping)$"ms",55,15,GC.LCDMedFont);
	GC.LCDDrawText("Packet Loss:"@PlayerOwner.PlayerReplicationInfo.PacketLoss$"%",55,35,GC.LCDTinyFont);
	GC.LCDRepaint();
}

simulated function DrawLCDScore(Canvas C, GUIController GC)
{
	local int i,cnt,Rank,xl,yl,byl;
	local string s;

	GC.LCDCls();

	if (!Level.GRI.bMatchHasBegun)
	{
		GC.LCDDrawTile(GC.LCDLogo,0,0,50,43,0,0,50,43);
		s = "Waiting to";
		GC.LCDStrLen(s,GC.LCDMedFont,xl,yl);
		GC.LCDDrawText(s,100-(XL/2),0,GC.LCDMedFont);

		s = "Start!";
		GC.LCDStrLen(s,GC.LCDMedFont,xl,yl);
		GC.LCDDrawText(s,100-(XL/2),2+yl,GC.LCDMedFont);

		for (i=0;i<Level.GRI.PRIArray.Length;i++)
		{
			if (!Level.GRI.PRIArray[i].bOnlySpectator)
				cnt++;
		}

	    GC.LCDDrawText(""$cnt$" players waiting.",55,35,GC.LCDTinyFont);
	}

	else if (Level.GRI.Winner != none)
	{
		for (i=0;i<Level.GRI.PRIArray.Length;i++)
		{
			if (!Level.GRI.PRIArray[i].bOnlySpectator)
			{
				if (Level.GRI.PRIArray[i] == PlayerOwner.PlayerReplicationInfo)
				{
					Rank = i+1;
				}
				cnt++;
			}
		}
		GC.LCDStrLen("You Placed",GC.LCDSmallFont,xl,yl);
		GC.LCDDrawText("You Placed",80-(XL/2),0,GC.LCDSmallFont);

		if (Rank == 1)
			S = "1st";
		else if (Rank == 2)
			S = "2nd";
		else if (Rank == 3)
			S = "3rd";
		else
			s = ""$Rank$"th";

		GC.LCDStrLen(s,GC.LCDMedFont,xl,byl);
		GC.LCDDrawText(s,80-(XL/2),yl+2,GC.LCDMedFont);

		if (Rank==1)
		{
			s = "You beat"@cnt-1@"other players";
		}
		else
		{
			s = ""$cnt$" players | Lost by"@INT(Level.GRI.PRIArray[0].Score - PlayerOwner.PlayerReplicationInfo.Score);
		}

		GC.LCDStrLen(s,GC.LCDTinyFont,xl,yl);
		GC.LCDDrawText(s,80-(XL/2),42-yl,GC.LCDTinyFont);
		GC.LCDDrawTile(Texture'engine.WhiteSquareTexture',5,80-YL+2,150,1,0,0,1,1);
	}
	else
	{
		for (i=0;i<Level.GRI.PRIArray.Length;i++)
		{
			if (!Level.GRI.PRIArray[i].bOnlySpectator)
			{
				if (Level.GRI.PRIArray[i] == PlayerOwner.PlayerReplicationInfo)
				{
					Rank = i+1;
				}
				cnt++;
			}
		}

   		S = ""@Int(PlayerOwner.PlayerReplicationInfo.Deaths)@"Deaths";
		GC.LCDStrLen(s,GC.LCDTinyFont,xl,yl);
		GC.LCDDrawText(s,160-xl,0,GC.LCDTinyFont);

		S = ""@Int(PlayerOwner.PlayerReplicationInfo.Score)@GetScoreTitle();
		GC.LCDStrLen(s,GC.LCDSmallFont,xl,yl);
		GC.LCDDrawText(s,0,0,GC.LCDSmallFont);

		GC.LCDDrawTile(Texture'engine.WhiteSquareTexture',0,yl,160,1,0,0,1,1);

        DrawLCDLeaderBoard(C,GC,yl+3);
	}

	GC.LCDRepaint();
}

simulated function string GetScoreTitle()
{
	return "Frags";
}

simulated function DrawLCDLeaderBoard(Canvas C, GUIController GC, int Y)
{
	local int i,xl,yl;
	local string s;
	for (i=0;i<3;i++)
	{
		if (Level.GRI.PRIArray[i] != none)
		{
			s = "" $ (i+1) $ "." @ Level.GRI.PRIArray[i].PlayerName;
			GC.LCDDrawText(s,2,y,GC.LCDTinyFont);
			S = ""$Int(Level.GRI.PRIArray[i].Score);
			GC.LCDStrLen(S,GC.LCDTinyFont,xl,yl);
			GC.LCDDrawText(s,158-xl,y,GC.LCDTinyFont);
			y+=8;
		}
	}
}

// G15 Support
simulated event HandleG15SoftButtonPress( int PressedButton )
{
 	SetLCDMode( PressedButton );
}

simulated function SetLCDMode( int newMode )
{
	if (NewMode<0 || NewMode>3)
		return;

	if(NewMode == LCDDisplayMode)
	{
		LCDPage++;

		if (LCDPage>1)
			LCDPage=0;
	}
	else
	{
		LCDPage=0;
	}

	LCDDisplayMode = NewMode;
	Saveconfig();
}
// end G15 support

defaultproperties
{
    TargetMaterial=Texture'InterfaceArt_tex.Menu.changeme_texture' //Material'InterfaceContent.Hud.fbBombFocus'

    ProgressFontName="ROFonts.ROBtsrmVr12"//"UT2003Fonts.FontMedium"

	FontArrayNames(0)="ROFonts.ROBtsrmVr38"//"UT2003Fonts.FontEurostile37"
    FontArrayNames(1)="ROFonts.ROBtsrmVr28"//"UT2003Fonts.FontEurostile29"
    FontArrayNames(2)="ROFonts.ROBtsrmVr24"//"UT2003Fonts.FontEurostile24"
    FontArrayNames(3)="ROFonts.ROBtsrmVr22"//"UT2003Fonts.FontEurostile21"
    FontArrayNames(4)="ROFonts.ROBtsrmVr18"//"UT2003Fonts.FontEurostile17"
    FontArrayNames(5)="ROFonts.ROBtsrmVr14"//"UT2003Fonts.FontEurostile14"
    FontArrayNames(6)="ROFonts.ROBtsrmVr12"//"UT2003Fonts.FontEurostile12"
    FontArrayNames(7)="ROFonts.ROBtsrmVr9"//"UT2003Fonts.FontEurostile9"
    FontArrayNames(8)="ROFonts.ROBtsrmVr7"//"UT2003Fonts.FontSmallText"		//6

    FontScreenWidthMedium(0)=2048
    FontScreenWidthMedium(1)=1600
    FontScreenWidthMedium(2)=1280
    FontScreenWidthMedium(3)=1024
    FontScreenWidthMedium(4)=800
    FontScreenWidthMedium(5)=640
    FontScreenWidthMedium(6)=512
    FontScreenWidthMedium(7)=400
    FontScreenWidthMedium(8)=320

    FontScreenWidthSmall(0)=4096
    FontScreenWidthSmall(1)=3200
    FontScreenWidthSmall(2)=2560
    FontScreenWidthSmall(3)=2048
    FontScreenWidthSmall(4)=1600
    FontScreenWidthSmall(5)=1280
    FontScreenWidthSmall(6)=1024
    FontScreenWidthSmall(7)=800
    FontScreenWidthSmall(8)=640

    CroppingAmount=0.25
    InstructTextBorderX=10.0
    InstructTextBorderY=10.0
	InstructionFontName="ROFonts.ROBtsrmVr7"//"UT2003Fonts.jFontMono800x600"

	WonMatchPrefix=""
	WonMatchPostFix=" won the match!"

	YouveWonTheMatch="You've won the match!"
	YouveLostTheMatch="You've lost the match."
	AtMenus="Press [ESC] to close menu"
	WaitingToSpawn="Press [Fire] to join the match!"
	NowViewing="Now viewing"
    Scoretext="Score"
	InitialViewingString="Press Fire to View a different Player"
    LevelActionLoading="LOADING..."
    LevelActionPaused="PAUSED"
    LevelActionFontName="ROFonts.ROBtsrmVr12"//"UT2003Fonts.FontMedium"
// if _RO_
    LocationDot=Texture'InterfaceArt_tex.Menu.checkBoxBall_b'
// else
//    LocationDot=Material'HudContent.Generic.HUD'
// end if _RO_

	bUseCustomWeaponCrosshairs=true
// if _RO_
	Crosshairs(0)=(WidgetTexture=Texture'InterfaceArt_tex.Cursors.Crosshair_Cross2',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.750000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
// else
//	Crosshairs(0)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Cross1',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.750000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(1)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Cross2',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.750000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(2)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Cross3',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.750000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(3)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Cross4',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.750000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(4)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Cross5',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.750000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(5)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Dot',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.750000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(6)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Pointer',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.600000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(7)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Triad1',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.700000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(8)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Triad2',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.700000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(9)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Triad3',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.700000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(10)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Bracket1',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.600000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(11)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Bracket2',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.600000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(12)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Circle1',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.400000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
//	Crosshairs(13)=(WidgetTexture=Texture'Crosshairs.HUD.Crosshair_Circle2',RenderStyle=STY_Alpha,TextureCoords=(X2=64,Y2=64),TextureScale=0.400000,DrawPivot=DP_MiddleMiddle,PosX=0.500000,PosY=0.500000,Scale=1.000000,Tints[0]=(B=255,G=255,R=255,A=255),Tints[1]=(B=255,G=255,R=255,A=255))
// end if _RO_

// G15 Support
	LCDUpdateFreq=1.0
	LCDDisplayMode=0
}
