Engine
Class Console

source: e:\games\UnrealTournament\Engine\Classes\Console.uc
Core.Object
   |
   +--Engine.Console
Direct Known Subclasses:WindowConsole

class Console
extends Core.Object

//============================================================================= // Console: A player console, associated with a viewport. // This is a built-in Unreal class and it shouldn't be modified. //=============================================================================
Variables
 string AvgText
 ConBackground, Border
 BorderLines, BorderPixels
 int BorderSize
 string ConnectingMessage
 ConsolePos, ConsoleDest
 float ExtraTime
 int FrameCount
 string FrameRateText
 FrameX, FrameY
 string FramesText
 HistoryBot, HistoryCur
 TypedStr, History[16]
 float LastFrameTime
 float LastSecFPS
 string LastSecText
 int LastSecondFrameCount
 float LastSecondStartTime
 string LoadingMessage
 float MaxFPS
 string MaxText
 float MinFPS
 string MinText
 PlayerReplicationInfo MsgPlayer[64]
 string MsgText[64]
 MsgTime, MsgTickTime
 float MsgTick[64]
 name MsgType[64]
 string PausedMessage
 string PrecachingMessage
 string SavingMessage
 string SecondsText
 float StartTime
 TopLine, TextLines
 Font TimeDemoFont
 viewport Viewport
 bool bNoDrawWorld
 bool bRestartTimeDemo
 bool bSaveTimeDemoToFile
 bool bStartTimeDemo
 bool bTimeDemo
 bNoStuff, bTyping
 string fpsText
 int vtblOut

States
KeyMenuing, MenuTyping, EndMenuing, Menuing, Typing

Function Summary
 void ClearMessages()
     
// Clear messages.
 bool ConsoleCommand(string S)
     
// Execute a command on this console.
 
simulated
DrawConsoleView(Canvas C)
 void DrawLevelAction(Canvas C)
 
simulated
DrawSingleView(Canvas C)
 PlayerReplicationInfo GetMsgPlayer(int Index)
 string GetMsgText(int Index)
     
//-----------------------------------------------------------------------------
// Member Access Functions.
 float GetMsgTick(int Index)
 name GetMsgType(int Index)
 void PrintActionMessage(Canvas C, string BigMessage)
 void SaveTimeDemo(string S)
 void SetMsgPlayer(int Index, PlayerReplicationInfo NewMsgPlayer)
 void SetMsgText(int Index, string NewMsgText)
 void SetMsgTick(int Index, int NewMsgTick)
 void SetMsgType(int Index, name NewMsgType)
 void Talk()
 void TeamTalk()
 void Type()
     
// Begin typing a command on the console.
 void ViewDown()
     
// Size the view down.
 void ViewUp()
     
// Size the view up.


State KeyMenuing Function Summary
 string FormatFloat(float f)
 void TimeDemoRender(Canvas C)
 void TimeDemoCalc()
 void PrintTimeDemoResult()
 void StopTimeDemo()
 void StartTimeDemo()
 void TimeDemo(bool bEnabled, optional bool)
     
//-----------------------------------------------------------------------------
// Timedemo functions
 void EndState()
 void BeginState()
 bool KeyEvent(EInputKey Key, EInputAction Action, FLOAT Delta)
 bool KeyType(EInputKey Key)


State MenuTyping Function Summary
 void EndState()
 void BeginState()
 bool KeyEvent(EInputKey Key, EInputAction Action, FLOAT Delta)
 bool KeyType(EInputKey Key)


State EndMenuing Function Summary
 bool KeyEvent(EInputKey Key, EInputAction Action, FLOAT Delta)
     
// pass all key events, not just presses


State Menuing Function Summary
 void EndState()
 void BeginState()
 bool KeyEvent(EInputKey Key, EInputAction Action, FLOAT Delta)


State Typing Function Summary
 void EndState()
 void BeginState()
 bool KeyEvent(EInputKey Key, EInputAction Action, FLOAT Delta)
 bool KeyType(EInputKey Key)
 void Type()



Source Code


00001	//=============================================================================
00002	// Console: A player console, associated with a viewport.
00003	// This is a built-in Unreal class and it shouldn't be modified.
00004	//=============================================================================
00005	class Console extends Object
00006		native
00007		noexport
00008		transient;
00009	
00010	// Imports.
00011	#exec Texture Import NAME=ConsoleBack File=Textures\Console.pcx
00012	#exec Texture Import File=Textures\Border.pcx
00013	
00014	// Internal.
00015	var private const int vtblOut;
00016	
00017	// Constants.
00018	const MaxBorder=6;
00019	const MaxLines=64;
00020	const MaxHistory=16;
00021	const TextMsgSize=128;
00022	
00023	// Variables.
00024	var viewport Viewport;
00025	var int HistoryTop, HistoryBot, HistoryCur;
00026	var string TypedStr, History[16];
00027	var int Scrollback, NumLines, TopLine, TextLines;
00028	var float MsgTime, MsgTickTime;
00029	var string MsgText[64];
00030	var name MsgType[64];
00031	var PlayerReplicationInfo MsgPlayer[64];
00032	var float MsgTick[64];
00033	var int BorderSize;
00034	var int ConsoleLines, BorderLines, BorderPixels;
00035	var float ConsolePos, ConsoleDest;
00036	var float FrameX, FrameY;
00037	var texture ConBackground, Border;
00038	var bool bNoStuff, bTyping;
00039	var bool bNoDrawWorld;
00040	
00041	// Timedemo
00042	var bool bTimeDemo;
00043	var bool bStartTimeDemo;
00044	var bool bRestartTimeDemo;
00045	var bool bSaveTimeDemoToFile;
00046	var float StartTime;
00047	var float ExtraTime;
00048	var float LastFrameTime;
00049	var float LastSecondStartTime;
00050	var int FrameCount;
00051	var int LastSecondFrameCount;
00052	var float MinFPS;
00053	var float MaxFPS;		
00054	var float LastSecFPS;
00055	var Font TimeDemoFont;
00056	
00057	var localized string LoadingMessage;
00058	var localized string SavingMessage;
00059	var localized string ConnectingMessage;
00060	var localized string PausedMessage;
00061	var localized string PrecachingMessage;
00062	
00063	
00064	var localized string FrameRateText;
00065	var localized string AvgText;
00066	var localized string LastSecText;
00067	var localized string MinText;
00068	var localized string MaxText;
00069	var localized string fpsText;
00070	var localized string SecondsText;
00071	var localized string FramesText;
00072	
00073	//-----------------------------------------------------------------------------
00074	// Input.
00075	
00076	// Input system states.
00077	enum EInputAction
00078	{
00079		IST_None,    // Not performing special input processing.
00080		IST_Press,   // Handling a keypress or button press.
00081		IST_Hold,    // Handling holding a key or button.
00082		IST_Release, // Handling a key or button release.
00083		IST_Axis,    // Handling analog axis movement.
00084	};
00085	
00086	// Input keys.
00087	enum EInputKey
00088	{
00089	/*00*/	IK_None			,IK_LeftMouse	,IK_RightMouse	,IK_Cancel		,
00090	/*04*/	IK_MiddleMouse	,IK_Unknown05	,IK_Unknown06	,IK_Unknown07	,
00091	/*08*/	IK_Backspace	,IK_Tab         ,IK_Unknown0A	,IK_Unknown0B	,
00092	/*0C*/	IK_Unknown0C	,IK_Enter	    ,IK_Unknown0E	,IK_Unknown0F	,
00093	/*10*/	IK_Shift		,IK_Ctrl	    ,IK_Alt			,IK_Pause       ,
00094	/*14*/	IK_CapsLock		,IK_Unknown15	,IK_Unknown16	,IK_Unknown17	,
00095	/*18*/	IK_Unknown18	,IK_Unknown19	,IK_Unknown1A	,IK_Escape		,
00096	/*1C*/	IK_Unknown1C	,IK_Unknown1D	,IK_Unknown1E	,IK_Unknown1F	,
00097	/*20*/	IK_Space		,IK_PageUp      ,IK_PageDown    ,IK_End         ,
00098	/*24*/	IK_Home			,IK_Left        ,IK_Up          ,IK_Right       ,
00099	/*28*/	IK_Down			,IK_Select      ,IK_Print       ,IK_Execute     ,
00100	/*2C*/	IK_PrintScrn	,IK_Insert      ,IK_Delete      ,IK_Help		,
00101	/*30*/	IK_0			,IK_1			,IK_2			,IK_3			,
00102	/*34*/	IK_4			,IK_5			,IK_6			,IK_7			,
00103	/*38*/	IK_8			,IK_9			,IK_Unknown3A	,IK_Unknown3B	,
00104	/*3C*/	IK_Unknown3C	,IK_Unknown3D	,IK_Unknown3E	,IK_Unknown3F	,
00105	/*40*/	IK_Unknown40	,IK_A			,IK_B			,IK_C			,
00106	/*44*/	IK_D			,IK_E			,IK_F			,IK_G			,
00107	/*48*/	IK_H			,IK_I			,IK_J			,IK_K			,
00108	/*4C*/	IK_L			,IK_M			,IK_N			,IK_O			,
00109	/*50*/	IK_P			,IK_Q			,IK_R			,IK_S			,
00110	/*54*/	IK_T			,IK_U			,IK_V			,IK_W			,
00111	/*58*/	IK_X			,IK_Y			,IK_Z			,IK_Unknown5B	,
00112	/*5C*/	IK_Unknown5C	,IK_Unknown5D	,IK_Unknown5E	,IK_Unknown5F	,
00113	/*60*/	IK_NumPad0		,IK_NumPad1     ,IK_NumPad2     ,IK_NumPad3     ,
00114	/*64*/	IK_NumPad4		,IK_NumPad5     ,IK_NumPad6     ,IK_NumPad7     ,
00115	/*68*/	IK_NumPad8		,IK_NumPad9     ,IK_GreyStar    ,IK_GreyPlus    ,
00116	/*6C*/	IK_Separator	,IK_GreyMinus	,IK_NumPadPeriod,IK_GreySlash   ,
00117	/*70*/	IK_F1			,IK_F2          ,IK_F3          ,IK_F4          ,
00118	/*74*/	IK_F5			,IK_F6          ,IK_F7          ,IK_F8          ,
00119	/*78*/	IK_F9           ,IK_F10         ,IK_F11         ,IK_F12         ,
00120	/*7C*/	IK_F13			,IK_F14         ,IK_F15         ,IK_F16         ,
00121	/*80*/	IK_F17			,IK_F18         ,IK_F19         ,IK_F20         ,
00122	/*84*/	IK_F21			,IK_F22         ,IK_F23         ,IK_F24         ,
00123	/*88*/	IK_Unknown88	,IK_Unknown89	,IK_Unknown8A	,IK_Unknown8B	,
00124	/*8C*/	IK_Unknown8C	,IK_Unknown8D	,IK_Unknown8E	,IK_Unknown8F	,
00125	/*90*/	IK_NumLock		,IK_ScrollLock  ,IK_Unknown92	,IK_Unknown93	,
00126	/*94*/	IK_Unknown94	,IK_Unknown95	,IK_Unknown96	,IK_Unknown97	,
00127	/*98*/	IK_Unknown98	,IK_Unknown99	,IK_Unknown9A	,IK_Unknown9B	,
00128	/*9C*/	IK_Unknown9C	,IK_Unknown9D	,IK_Unknown9E	,IK_Unknown9F	,
00129	/*A0*/	IK_LShift		,IK_RShift      ,IK_LControl    ,IK_RControl    ,
00130	/*A4*/	IK_UnknownA4	,IK_UnknownA5	,IK_UnknownA6	,IK_UnknownA7	,
00131	/*A8*/	IK_UnknownA8	,IK_UnknownA9	,IK_UnknownAA	,IK_UnknownAB	,
00132	/*AC*/	IK_UnknownAC	,IK_UnknownAD	,IK_UnknownAE	,IK_UnknownAF	,
00133	/*B0*/	IK_UnknownB0	,IK_UnknownB1	,IK_UnknownB2	,IK_UnknownB3	,
00134	/*B4*/	IK_UnknownB4	,IK_UnknownB5	,IK_UnknownB6	,IK_UnknownB7	,
00135	/*B8*/	IK_UnknownB8	,IK_UnknownB9	,IK_Semicolon	,IK_Equals		,
00136	/*BC*/	IK_Comma		,IK_Minus		,IK_Period		,IK_Slash		,
00137	/*C0*/	IK_Tilde		,IK_UnknownC1	,IK_UnknownC2	,IK_UnknownC3	,
00138	/*C4*/	IK_UnknownC4	,IK_UnknownC5	,IK_UnknownC6	,IK_UnknownC7	,
00139	/*C8*/	IK_Joy1	        ,IK_Joy2	    ,IK_Joy3	    ,IK_Joy4	    ,
00140	/*CC*/	IK_Joy5	        ,IK_Joy6	    ,IK_Joy7	    ,IK_Joy8	    ,
00141	/*D0*/	IK_Joy9	        ,IK_Joy10	    ,IK_Joy11	    ,IK_Joy12		,
00142	/*D4*/	IK_Joy13		,IK_Joy14	    ,IK_Joy15	    ,IK_Joy16	    ,
00143	/*D8*/	IK_UnknownD8	,IK_UnknownD9	,IK_UnknownDA	,IK_LeftBracket	,
00144	/*DC*/	IK_Backslash	,IK_RightBracket,IK_SingleQuote	,IK_UnknownDF	,
00145	/*E0*/  IK_JoyX			,IK_JoyY		,IK_JoyZ		,IK_JoyR		,
00146	/*E4*/	IK_MouseX		,IK_MouseY		,IK_MouseZ		,IK_MouseW		,
00147	/*E8*/	IK_JoyU			,IK_JoyV		,IK_UnknownEA	,IK_UnknownEB	,
00148	/*EC*/	IK_MouseWheelUp ,IK_MouseWheelDown,IK_Unknown10E,UK_Unknown10F  ,
00149	/*F0*/	IK_UnknownF0	,IK_UnknownF1	,IK_UnknownF2	,IK_UnknownF3	,
00150	/*F4*/	IK_UnknownF4	,IK_UnknownF5	,IK_Attn		,IK_CrSel		,
00151	/*F8*/	IK_ExSel		,IK_ErEof		,IK_Play		,IK_Zoom		,
00152	/*FC*/	IK_NoName		,IK_PA1			,IK_OEMClear
00153	};
00154	
00155	//-----------------------------------------------------------------------------
00156	// natives.
00157	
00158	// Execute a command on this console.
00159	native function bool ConsoleCommand( coerce string S );
00160	native function SaveTimeDemo( string S );
00161	
00162	//-----------------------------------------------------------------------------
00163	// Exec functions accessible from the console and key bindings.
00164	
00165	// Begin typing a command on the console.
00166	exec function Type()
00167	{
00168		TypedStr="";
00169		GotoState( 'Typing' );
00170	}
00171	 
00172	exec function Talk()
00173	{
00174		TypedStr="Say ";
00175		bNoStuff = true;
00176		GotoState( 'Typing' );
00177	}
00178	
00179	exec function TeamTalk()
00180	{
00181		TypedStr="TeamSay ";
00182		bNoStuff = true;
00183		GotoState( 'Typing' );
00184	}
00185	
00186	// Size the view up.
00187	exec function ViewUp()
00188	{
00189		BorderSize = Clamp( BorderSize-1, 0, MaxBorder );
00190	}
00191	
00192	// Size the view down.
00193	exec function ViewDown()
00194	{
00195		BorderSize = Clamp( BorderSize+1, 0, MaxBorder );
00196	}
00197	
00198	//-----------------------------------------------------------------------------
00199	// Member Access Functions.
00200	
00201	function string GetMsgText( int Index )
00202	{
00203		return MsgText[Index];
00204	}
00205	function SetMsgText( int Index, string NewMsgText )
00206	{
00207		MsgText[Index] = NewMsgText;
00208	}
00209	
00210	function name GetMsgType(int Index)
00211	{
00212		return MsgType[Index];
00213	}
00214	function SetMsgType(int Index, name NewMsgType)
00215	{
00216		MsgType[Index] = NewMsgType;
00217	}
00218	
00219	function PlayerReplicationInfo GetMsgPlayer(int Index)
00220	{
00221		return MsgPlayer[Index];
00222	}
00223	function SetMsgPlayer(int Index, PlayerReplicationInfo NewMsgPlayer)
00224	{
00225		MsgPlayer[Index] = NewMsgPlayer;
00226	}
00227	
00228	function float GetMsgTick(int Index)
00229	{
00230		return MsgTick[Index];
00231	}
00232	function SetMsgTick(int Index, int NewMsgTick)
00233	{
00234		MsgTick[Index] = NewMsgTick;
00235	}
00236	
00237	//-----------------------------------------------------------------------------
00238	// Functions.
00239	
00240	// Clear messages.
00241	function ClearMessages()
00242	{
00243		local int i;
00244	
00245		for (i=0; i<MaxLines; i++)
00246		{
00247			MsgText[i] = "";
00248			MsgType[i] = '';
00249			MsgPlayer[i] = None;
00250			MsgTick[i] = 0.0;
00251		}
00252		MsgTime = 0.0;
00253	}
00254	
00255	// Write to console.
00256	event Message( PlayerReplicationInfo PRI, coerce string Msg, name N )
00257	{
00258		if( Msg!="" )
00259		{
00260			TopLine		     = (TopLine+1) % MaxLines;
00261			NumLines	     = Min(NumLines+1,MaxLines-1);
00262			MsgType[TopLine] = N;
00263			MsgTime		     = 6.0;
00264			TextLines++;
00265			MsgText[TopLine] = Msg;
00266			MsgPlayer[TopLine] = PRI;
00267			MsgTick[TopLine] = MsgTickTime + MsgTime;
00268		}
00269	}
00270	
00271	event AddString( coerce string Msg )
00272	{
00273		if( Msg!="" )
00274		{
00275			TopLine		     = (TopLine+1) % MaxLines;
00276			NumLines	     = Min(NumLines+1,MaxLines-1);
00277			MsgType[TopLine] = 'Event';
00278			MsgTime		     = 6.0;
00279			TextLines++;
00280			MsgText[TopLine] = Msg;
00281			MsgPlayer[TopLine] = None;
00282			MsgTick[TopLine] = MsgTickTime + MsgTime;
00283		}
00284	}
00285	
00286	// Called by the engine when a single key is typed.
00287	event bool KeyType( EInputKey Key );
00288	
00289	// Called by the engine when a key, mouse, or joystick button is pressed
00290	// or released, or any analog axis movement is processed.
00291	event bool KeyEvent( EInputKey Key, EInputAction Action, FLOAT Delta )
00292	{
00293		// Ask the HUD to deal with the key event (hook for mod authors).
00294		if (Viewport.Actor.myHUD != None)
00295		{
00296			if (Viewport.Actor.myHUD.ProcessKeyEvent( Key, Action, Delta ))
00297				return true;
00298		}
00299	
00300		if( Action!=IST_Press )
00301		{
00302			return false;
00303		}
00304		else if( Key==IK_Tilde )
00305		{
00306			if( ConsoleDest==0.0 )
00307			{
00308				ConsoleDest=0.6;
00309				GotoState('Typing');
00310			}
00311			else GotoState('');
00312			return true;
00313		}
00314		else return false;
00315	}
00316	
00317	// Called each rendering iteration to update any time-based display.
00318	event Tick( float Delta )
00319	{
00320		local int I;
00321		MsgTickTime += Delta;
00322	
00323		// Slide console up or down.
00324		if( ConsolePos < ConsoleDest )
00325			ConsolePos = FMin(ConsolePos+Delta,ConsoleDest);
00326		else if( ConsolePos > ConsoleDest )
00327			ConsolePos = FMax(ConsolePos-Delta,ConsoleDest);
00328	
00329		// Update status message.
00330		if( ((MsgTime-=Delta) <= 0.0) && (TextLines > 0) )
00331			TextLines--;
00332	}
00333	
00334	// Called before rendering the world view.
00335	event PreRender( canvas C );
00336	
00337	// Called when video settings change (resolution, driver, color depth).
00338	event VideoChange();
00339	
00340	event NotifyLevelChange()
00341	{
00342		bRestartTimeDemo = True;
00343		ClearMessages();
00344	}
00345	
00346	event ConnectFailure( string FailCode, string URL );
00347	
00348	function DrawLevelAction( canvas C )
00349	{
00350		local string BigMessage;
00351	
00352		if ( (Viewport.Actor.Level.Pauser != "") && (Viewport.Actor.Level.LevelAction == LEVACT_None) )
00353		{
00354			C.Font = C.MedFont;
00355			BigMessage = PausedMessage; // Add pauser name?
00356			PrintActionMessage(C, BigMessage);
00357			return;
00358		}
00359		if ( (Viewport.Actor.Level.LevelAction == LEVACT_None)
00360			 || Viewport.Actor.bShowMenu )
00361		{
00362			BigMessage = "";
00363			return;
00364		}
00365		else if ( Viewport.Actor.Level.LevelAction == LEVACT_Loading )
00366			BigMessage = LoadingMessage;
00367		else if ( Viewport.Actor.Level.LevelAction == LEVACT_Saving )
00368			BigMessage = SavingMessage;
00369		else if ( Viewport.Actor.Level.LevelAction == LEVACT_Connecting )
00370			BigMessage = ConnectingMessage;
00371		else if ( Viewport.Actor.Level.LevelAction == LEVACT_Precaching )
00372			BigMessage = PrecachingMessage;
00373		
00374		if ( BigMessage != "" )
00375		{
00376			C.Style = 1;
00377			C.Font = C.LargeFont;	
00378			PrintActionMessage(C, BigMessage);
00379		}
00380	}
00381	
00382	function PrintActionMessage( Canvas C, string BigMessage )
00383	{
00384		local float XL, YL;
00385	
00386		C.bCenter = false;
00387		C.StrLen( BigMessage, XL, YL );
00388		C.SetPos(FrameX/2 - XL/2, FrameY/2 - YL/2);
00389		C.DrawText( BigMessage, false );
00390	}		
00391	
00392	// Add localization to hardcoded strings!!
00393	// Called after rendering the world view.
00394	event PostRender( canvas C )
00395	{
00396		local int YStart, YEnd, Y, I, J, Line, iLine;
00397	
00398		if(bNoDrawWorld)
00399		{
00400			C.SetPos(0,0);
00401			C.DrawPattern( Texture'Border', C.ClipX, C.ClipY, 1.0 );
00402		}
00403	
00404		if( bTimeDemo )
00405		{
00406			TimeDemoCalc();
00407			TimeDemoRender( C );
00408		}
00409	
00410		// call overridable "level action" rendering code to draw the "big message"
00411		DrawLevelAction( C );
00412	
00413		// If the console has changed since the previous frame, draw it.
00414		if ( ConsoleLines > 0 )
00415		{
00416			C.SetOrigin(0.0, ConsoleLines - FrameY*0.6);
00417			C.SetPos(0.0, 0.0);
00418			C.DrawTile( ConBackground, FrameX, FrameY*0.6, C.CurX, C.CurY, FrameX, FrameY );
00419		}
00420	
00421		// Draw border.
00422		if ( BorderLines > 0 || BorderPixels > 0 )
00423		{
00424			YStart 	= BorderLines + ConsoleLines;
00425			YEnd 	= FrameY - BorderLines;
00426			if ( BorderLines > 0 )
00427			{
00428				C.SetOrigin(0.0, 0.0);
00429				C.SetPos(0.0, 0.0);
00430				C.DrawPattern( Border, FrameX, BorderLines, 1.0 );
00431				C.SetPos(0.0, YEnd);
00432				C.DrawPattern( Border, FrameX, BorderLines, 1.0 );
00433			}
00434			if ( BorderPixels > 0 )
00435			{
00436				C.SetOrigin(0.0, 0.0);
00437				C.SetPos(0.0, YStart);
00438				C.DrawPattern( Border, BorderPixels, YEnd - YStart, 1.0 );
00439				C.SetPos( FrameX - BorderPixels, YStart );
00440				C.DrawPattern( Border, BorderPixels, YEnd - YStart, 1.0 );
00441			}
00442		}
00443	
00444		// Draw console text.
00445		C.SetOrigin(0.0, 0.0);
00446		if ( ConsoleLines > 0 )
00447			DrawConsoleView( C );
00448		else
00449			DrawSingleView( C );
00450	}
00451	
00452	simulated function DrawConsoleView( Canvas C )
00453	{
00454		local int Y, I, Line;
00455		local float XL, YL;
00456	
00457		// Console is visible; display console view.
00458		Y = ConsoleLines - 1;
00459		MsgText[(TopLine + 1 + MaxLines) % MaxLines] = "(>"@TypedStr;
00460		for ( I = Scrollback; I < (NumLines + 1); I++ )
00461		{
00462			// Display all text in the buffer.
00463			Line = (TopLine + MaxLines*2 - (I-1)) % MaxLines;
00464			
00465			C.Font = C.MedFont;
00466	
00467			if (( MsgType[Line] == 'Say' ) || ( MsgType[Line] == 'TeamSay' ))
00468				C.StrLen( MsgPlayer[Line].PlayerName$":"@MsgText[Line], XL, YL );				
00469			else
00470				C.StrLen( MsgText[Line], XL, YL );
00471			
00472			// Half-space blank lines.
00473			if ( YL == 0 )
00474				YL = 5;
00475				
00476			Y -= YL;
00477			if ( (Y + YL) < 0 )
00478				break;
00479			C.SetPos(4, Y);
00480			C.Font = C.MedFont;
00481	
00482			if (( MsgType[Line] == 'Say' ) || ( MsgType[Line] == 'TeamSay' ))
00483				C.DrawText( MsgPlayer[Line].PlayerName$":"@MsgText[Line], false );
00484			else
00485				C.DrawText( MsgText[Line], false );
00486		}				
00487	}
00488	
00489	simulated function DrawSingleView( Canvas C )
00490	{
00491		local string TypingPrompt;
00492		local int I, J;
00493		local float XL, YL;
00494		local string ShortMessages[4];
00495		local int ExtraSpace;
00496	
00497		// Console is hidden; display single-line view.
00498	
00499		C.SetOrigin(0.0, 0.0);
00500	
00501		// Ask the HUD to deal with messages.
00502		if ( Viewport.Actor.myHUD != None 
00503			&& Viewport.Actor.myHUD.DisplayMessages(C) )
00504			return;
00505	
00506		// If the HUD doesn't deal with messages, use the default behavior
00507		if (!Viewport.Actor.bShowMenu)
00508		{
00509			if ( bTyping )
00510			{
00511				TypingPrompt = "(>"@TypedStr$"_";
00512				C.Font = C.MedFont;
00513				C.StrLen( TypingPrompt, XL, YL );
00514				C.SetPos( 2, FrameY - ConsoleLines - YL - 1 );
00515				C.DrawText( TypingPrompt, false );
00516			}
00517		}
00518			
00519		if ( TextLines > 0 && (!Viewport.Actor.bShowMenu || Viewport.Actor.bShowScores) )
00520		{
00521			J = TopLine;
00522			I = 0;
00523			while ((I < 4) && (J >= 0))
00524			{
00525				if ((MsgText[J] != "") && (MsgTick[J] > 0.0) && (MsgTick[J] > MsgTickTime) )
00526				{
00527					if (MsgType[J] == 'Say') 
00528						ShortMessages[I] = MsgPlayer[J]$":"@MsgText[J];
00529					else
00530						ShortMessages[I] = MsgText[J];
00531					I++;
00532				}
00533				J--;
00534			}
00535	
00536			J = 0;
00537			C.Font = C.MedFont;
00538			for ( I = 0; I < 4; I++ )
00539			{
00540				if (ShortMessages[3 - I] != "")
00541				{
00542					C.SetPos(4, 2 + (10 * J) + (10 * ExtraSpace));
00543					C.StrLen( ShortMessages[3 - I], XL, YL );
00544					C.DrawText( ShortMessages[3 - I], false );
00545					if ( YL == 18.0 )
00546						ExtraSpace++;
00547					J++;
00548				}
00549			}		
00550		}
00551	}
00552	
00553	//-----------------------------------------------------------------------------
00554	// State used while typing a command on the console.
00555	
00556	state Typing
00557	{
00558		exec function Type()
00559		{
00560			TypedStr="";
00561			gotoState( '' );
00562		}
00563		function bool KeyType( EInputKey Key )
00564		{
00565			if ( bNoStuff )
00566			{
00567				bNoStuff = false;
00568				return true;
00569			}
00570			if( Key>=0x20 && Key<0x100 && Key!=Asc("~") && Key!=Asc("`") )
00571			{
00572				TypedStr = TypedStr $ Chr(Key);
00573				Scrollback=0;
00574				return true;
00575			}
00576		}
00577		function bool KeyEvent( EInputKey Key, EInputAction Action, FLOAT Delta )
00578		{
00579			local string Temp;
00580	
00581			bNoStuff = false;
00582			if( Key==IK_Escape )
00583			{
00584				if( Scrollback!=0 )
00585				{
00586					Scrollback=0;
00587				}
00588				else if( TypedStr!="" )
00589				{
00590					TypedStr="";
00591				}
00592				else
00593				{
00594					ConsoleDest=0.0;
00595					GotoState( '' );
00596				}
00597				Scrollback=0;
00598			}
00599			else if( global.KeyEvent( Key, Action, Delta ) )
00600			{
00601				return true;
00602			}
00603			else if( Action != IST_Press )
00604			{
00605				return false;
00606			}
00607			else if( Key==IK_Enter )
00608			{
00609				if( Scrollback!=0 )
00610				{
00611					Scrollback=0;
00612				}
00613				else
00614				{
00615					if( TypedStr!="" )
00616					{
00617						// Print to console.
00618						if( ConsoleLines!=0 )
00619							Message( None, "(>" @ TypedStr, 'Console' );
00620	
00621						// Update history buffer.
00622						History[HistoryCur++ % MaxHistory] = TypedStr;
00623						if( HistoryCur > HistoryBot )
00624							HistoryBot++;
00625						if( HistoryCur - HistoryTop >= MaxHistory )
00626							HistoryTop = HistoryCur - MaxHistory + 1;
00627	
00628						// Make a local copy of the string.
00629						Temp=TypedStr;
00630						TypedStr="";
00631						if( !ConsoleCommand( Temp ) )
00632							Message( None, Localize("Errors","Exec","Core"), 'Console' );
00633						Message( None, "", 'Console' );
00634					}
00635					if( ConsoleDest==0.0 )
00636						GotoState('');
00637					Scrollback=0;
00638				}
00639			}
00640			else if( Key==IK_Up )
00641			{
00642				if( HistoryCur > HistoryTop )
00643				{
00644					History[HistoryCur % MaxHistory] = TypedStr;
00645					TypedStr = History[--HistoryCur % MaxHistory];
00646				}
00647				Scrollback=0;
00648			}
00649			else if( Key==IK_Down )
00650			{
00651				History[HistoryCur % MaxHistory] = TypedStr;
00652				if( HistoryCur < HistoryBot )
00653					TypedStr = History[++HistoryCur % MaxHistory];
00654				else
00655					TypedStr="";
00656				Scrollback=0;
00657			}
00658			else if( Key==IK_PageUp )
00659			{
00660				if( ++Scrollback >= MaxLines )
00661					Scrollback = MaxLines-1;
00662			}
00663			else if( Key==IK_PageDown )
00664			{
00665				if( --Scrollback < 0 )
00666					Scrollback = 0;
00667			}
00668			else if( Key==IK_Backspace || Key==IK_Left )
00669			{
00670				if( Len(TypedStr)>0 )
00671					TypedStr = Left(TypedStr,Len(TypedStr)-1);
00672				Scrollback = 0;
00673			}
00674			return true;
00675		}
00676		function BeginState()
00677		{
00678			bTyping = true;
00679			Viewport.Actor.Typing(bTyping);
00680		}
00681		function EndState()
00682		{
00683			bTyping = false;
00684			Viewport.Actor.Typing(bTyping);
00685			//log("Console leaving Typing");
00686			ConsoleDest=0.0;
00687		}
00688	}
00689	
00690	//-----------------------------------------------------------------------------
00691	// State used while in a menu.
00692	
00693	state Menuing
00694	{
00695		function bool KeyEvent( EInputKey Key, EInputAction Action, FLOAT Delta )
00696		{
00697			if ( Action != IST_Press )
00698				return false;
00699			if ( Viewport.Actor.myHUD == None || Viewport.Actor.myHUD.MainMenu == None )
00700				return false;
00701			
00702			Viewport.Actor.myHUD.MainMenu.MenuProcessInput(Key, Action);
00703			Scrollback=0;
00704			return true;
00705		}
00706		function BeginState()
00707		{
00708			//log("Console entering Menuing");
00709		}
00710		function EndState()
00711		{
00712			//log("Console leaving Menuing");
00713		}
00714	}
00715	
00716	state EndMenuing
00717	{
00718		// pass all key events, not just presses
00719		function bool KeyEvent( EInputKey Key, EInputAction Action, FLOAT Delta )
00720		{
00721			if ( Viewport.Actor.myHUD == None || Viewport.Actor.myHUD.MainMenu == None )
00722				return false;
00723			
00724			Viewport.Actor.myHUD.MainMenu.MenuProcessInput(Key, Action);
00725			Scrollback=0;
00726			return true;
00727		}
00728	}
00729	
00730	//-----------------------------------------------------------------------------
00731	// State used while typing in a menu.
00732	
00733	state MenuTyping
00734	{
00735		function bool KeyType( EInputKey Key )
00736		{
00737			if( Key>=0x20 && Key<0x100 && Key!=Asc("~") && Key!=Asc("`") && Key!=Asc(" ") )
00738			{
00739				TypedStr = TypedStr $ Chr(Key);
00740				Scrollback=0;
00741				if ( (Viewport.Actor.myHUD != None) && (Viewport.Actor.myHUD.MainMenu != None) )
00742					Viewport.Actor.myHUD.MainMenu.ProcessMenuUpdate( TypedStr );
00743				return true;
00744			}
00745		}	
00746		function bool KeyEvent( EInputKey Key, EInputAction Action, FLOAT Delta )
00747		{
00748			local Menu PlayerMenu;
00749	
00750			if( Action != IST_Press )
00751				return false;
00752	
00753			if( Viewport.Actor.myHUD==None || Viewport.Actor.myHUD.MainMenu==None )
00754				return false;
00755			
00756			PlayerMenu = Viewport.Actor.myHUD.MainMenu;
00757	
00758			if( Key==IK_Escape )
00759			{
00760				if( Scrollback!=0 )
00761					Scrollback = 0;
00762				else if( TypedStr!="" )
00763					TypedStr="";
00764				else
00765					GotoState( 'Menuing' );
00766				PlayerMenu.ProcessMenuEscape();
00767				Scrollback=0;
00768			}
00769			else if( Key==IK_Enter )
00770			{
00771				if( Scrollback!=0 )
00772					Scrollback = 0;
00773				else
00774				{
00775					if( TypedStr!="" )
00776						PlayerMenu.ProcessMenuInput( TypedStr );	
00777					TypedStr="";
00778					GotoState( 'Menuing' );
00779					Scrollback = 0;
00780				}
00781			}
00782			else if( Key==IK_Backspace || Key==IK_Left )
00783			{
00784				if( Len(TypedStr)>0 )
00785					TypedStr = Left(TypedStr,Len(TypedStr)-1);
00786				Scrollback = 0;
00787				PlayerMenu.ProcessMenuUpdate( TypedStr );	
00788			}
00789			return true;
00790		}
00791		function BeginState()
00792		{
00793			log("Console entering MenuTyping");
00794		}
00795		function EndState()
00796		{
00797			log("Console leaving MenuTyping");
00798		}
00799	}
00800	
00801	//-----------------------------------------------------------------------------
00802	// State used while expecting single key input in a menu.
00803	
00804	state KeyMenuing
00805	{
00806		function bool KeyType( EInputKey Key )
00807		{
00808			ConsoleDest=0.0;
00809			if( Viewport.Actor.myHUD!=None && Viewport.Actor.myHUD.MainMenu!=None )
00810				Viewport.Actor.myHUD.MainMenu.ProcessMenuKey( Key, Chr(Key) );
00811			Scrollback=0;
00812			GotoState( 'Menuing' );
00813		}
00814		function bool KeyEvent( EInputKey Key, EInputAction Action, FLOAT Delta )
00815		{
00816			if( Action==IST_Press )
00817			{
00818				ConsoleDest=0.0;
00819				if( Viewport.Actor.myHUD!=None && Viewport.Actor.myHUD.MainMenu!=None )
00820					Viewport.Actor.myHUD.MainMenu.ProcessMenuKey( Key, mid(string(GetEnum(enum'EInputKey',Key)),3) );
00821				Scrollback=0;
00822				GotoState( 'Menuing' );
00823				return true;
00824			}
00825		}
00826		function BeginState()
00827		{
00828			//log( "Console entering KeyMenuing" );
00829		}
00830		function EndState()
00831		{
00832			//log( "Console leaving KeyMenuing" );
00833		}
00834	}
00835	
00836	
00837	//-----------------------------------------------------------------------------
00838	// Timedemo functions
00839	
00840	exec function TimeDemo(bool bEnabled, optional bool bSaveToFile)
00841	{
00842		bSaveTimeDemoToFile = bSaveToFile;
00843		if(bEnabled)
00844			StartTimeDemo();
00845		else
00846			StopTimeDemo();
00847	}
00848	
00849	function StartTimeDemo()
00850	{
00851		if(bTimeDemo)
00852			return;
00853		bTimeDemo = True;
00854		bStartTimeDemo = True;
00855	}
00856	
00857	function StopTimeDemo()
00858	{
00859		if(!bTimeDemo)
00860			return;
00861		bTimeDemo = False;
00862		PrintTimeDemoResult();
00863	}
00864	
00865	function PrintTimeDemoResult()
00866	{
00867		local LevelInfo Entry;
00868		local float Avg;
00869		local float Delta;
00870		local string AvgString;
00871		local string Temp;
00872	
00873		Entry = Viewport.Actor.GetEntryLevel();
00874	
00875		Delta = Entry.TimeSeconds - StartTime - ExtraTime;
00876		if(Delta <= 0)
00877			Avg = 0;
00878		else
00879			Avg = FrameCount / Delta;
00880		
00881		AvgString = string(FrameCount)@FramesText@FormatFloat(delta)@SecondsText@MinText@FormatFloat(MinFPS)@MaxText@FormatFloat(MaxFPS)@AvgText@FormatFloat(Avg)@fpsText$".";
00882		Viewport.Actor.ClientMessage(AvgString);
00883		Log(AvgString);
00884		if(bSaveTimeDemoToFile)
00885		{		
00886			Temp =
00887				FormatFloat(Avg) $ " Unreal "$ Viewport.Actor.Level.EngineVersion $ Chr(13) $ Chr(10) $
00888				FormatFloat(MinFPS) $ " Min"$ Chr(13) $ Chr(10) $
00889				FormatFloat(MaxFPS) $ " Max"$ Chr(13) $ Chr(10);
00890				
00891			SaveTimeDemo(Temp);
00892		}
00893	}
00894	
00895	function TimeDemoCalc()
00896	{
00897		local LevelInfo Entry;
00898		local float Delta;
00899		Entry = Viewport.Actor.GetEntryLevel();
00900	
00901		if( bRestartTimeDemo )
00902		{
00903			StopTimeDemo();
00904			StartTimeDemo();
00905			bRestartTimeDemo = False;
00906		}
00907	
00908		if(	bStartTimeDemo )
00909		{
00910			bStartTimeDemo = False;
00911			StartTime = Entry.TimeSeconds;
00912			ExtraTime =  0;
00913			LastFrameTime = StartTime;
00914			LastSecondStartTime = StartTime;
00915			FrameCount = 0;
00916			LastSecondFrameCount = 0;
00917			MinFPS = 0;
00918			MaxFPS = 0;		
00919			LastSecFPS = 0;
00920			return;
00921		}
00922	
00923		Delta = Entry.TimeSeconds - LastFrameTime;
00924	
00925		// If delta time is more than a half of a second, ignore frame entirely (precaching, loading etc)
00926		if( Delta > 0.5 )
00927		{
00928			ExtraTime += Delta;
00929			LastSecondStartTime = Entry.TimeSeconds;
00930			LastSecondFrameCount = 0;
00931			LastFrameTime = Entry.TimeSeconds;
00932			return;
00933		}
00934	
00935		FrameCount++;
00936		LastSecondFrameCount++;
00937	
00938		if( Entry.TimeSeconds - LastSecondStartTime > 1)
00939		{
00940			LastSecFPS = LastSecondFrameCount / (Entry.TimeSeconds - LastSecondStartTime);
00941			if( MinFPS == 0 || LastSecFPS < MinFPS )
00942				MinFPS = LastSecFPS;
00943			if( LastSecFPS > MaxFPS )
00944				MaxFPS = LastSecFPS;
00945			LastSecondFrameCount = 0;
00946			LastSecondStartTime = Entry.TimeSeconds;
00947		}
00948	
00949		LastFrameTime = Entry.TimeSeconds;
00950	}
00951	
00952	function TimeDemoRender( Canvas C )
00953	{
00954		local string AText, LText;
00955		local float W, H;
00956	
00957		C.Font = TimeDemoFont;
00958		C.DrawColor.R = 255;
00959		C.DrawColor.G = 255;
00960		C.DrawColor.B = 255;
00961	
00962		AText = AvgText @ FormatFloat(FrameCount / (Viewport.Actor.GetEntryLevel().TimeSeconds - StartTime - ExtraTime));
00963		LText = LastSecText @ FormatFloat(LastSecFPS);
00964	
00965		C.TextSize(AText, W, H);
00966		C.SetPos(C.ClipX - W, 0.3*C.ClipY);
00967		C.DrawText(AText);
00968		C.TextSize(LText, W, H);
00969		C.SetPos(C.ClipX - W, 0.3*C.ClipY+H);
00970		C.DrawText(LText);
00971	}
00972	
00973	final function string FormatFloat( float f)
00974	{
00975		local string s;
00976		local int i;
00977		s = string(f);
00978		i = InStr(s, ".");
00979		if(i != -1)
00980			s = Left(s, i+3);
00981		return s;
00982	}
00983	
00984	defaultproperties
00985	{
00986	     ConBackground=Texture'Engine.ConsoleBack'
00987	     Border=Texture'Engine.Border'
00988	     TimeDemoFont=Font'Engine.SmallFont'
00989	     LoadingMessage="LOADING"
00990	     SavingMessage="SAVING"
00991	     ConnectingMessage="CONNECTING"
00992	     PausedMessage="PAUSED"
00993	     PrecachingMessage="PRECACHING"
00994	     FrameRateText="Frame Rate"
00995	     AvgText="Avg"
00996	     LastSecText="Last Sec"
00997	     MinText="Min"
00998	     MaxText="Max"
00999	     fpsText="fps"
01000	     SecondsText="seconds."
01001	     FramesText="frames rendered in"
01002	}

End Source Code