Engine
Class Console

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

End Source Code