/*
* Console.cs
* Authors: August Zinsser
*
* Copyright Matthew Belmonte 2007
*/
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
namespace tAC_Engine
{
///
/// A simple text console that can be drawn over the game. Allows the user to input lua commands at runtime.
/// Only enabled if the game is in Debug mode.
///
public static class Console
{
#if DEBUG
///
/// Used by the history to tell if each item was a command entered into the console, or just text
/// that was printed to the console
///
private struct HistoryItem
{
public enum Code { Command, Output, Error };
public HistoryItem(string text, Code codeType)
{
Text = text;
CodeType = codeType;
}
public string Text;
public Code CodeType;
}
static SpriteBatch mSpriteBatch; // Internal drawing buffer
static int mLeft = 5; // Graphical layout (in pixels)
static int mBottom = 15; // ''
static int mSpacing = 20; // ''
static float mScreenPercentage = .333f; // Amount of the screen that the console takes up
static bool mVisible = false; // Show or hide the entire console
static bool mHoldingDownVisibleKey = false; // True when the user holds down the toggle visibility key
static float mDeleteTimer = 0f; // Only register the delete funcitonality if the timer is 0
static float mDeleteHoldDelay = 1f; // Time that must pass before holding the delete key works
static string mCursor = "> "; // Shows the user where he/she is typing
static string mCommandString = ""; // The text being entered by the user
static List mHistory; // The previous commands
static int mHistoryCount = 25; // The size of the list to remember
static int mHistoryIndex = 0; // When pressing the up arrow, which history is recalled
static bool mWasInputLocked; // True if the input was locked before the console was brought up
#endif
///
/// Allocate variables
///
static Console()
{
#if DEBUG
mHistory = new List();
mSpriteBatch = new SpriteBatch(GenericBaseApplication.GameManager.GraphicsDevice);
#endif
}
///
/// Prints the given text in to the console (Console must be visible to read it, so only has
/// an effect in Debug mode).
///
public static void Print(string text)
{
#if DEBUG
mHistory.Insert(0, new HistoryItem(text, HistoryItem.Code.Output));
#endif
}
///
/// Does nothing if not in Debug mode
///
public static void Update()
{
#if DEBUG
// Remember original input lock state
if (!mVisible)
{
mWasInputLocked = InputState.Locked;
}
// Unlock the inputstate for this update to allow typing
InputState.Locked = false;
// Check visibility settings
if (InputState.IsKeyDown(Keys.OemTilde) && !mHoldingDownVisibleKey)
{
mVisible = !mVisible;
mHoldingDownVisibleKey = true;
}
else if (InputState.IsKeyUp(Keys.OemTilde))
{
mHoldingDownVisibleKey = false;
}
if (mVisible)
{
// Update the command line
mCommandString += InputState.GetTextInput();
// Check for delete/backspace
// Since XNA can't detect the Backspace key (hopefully it will in a future release),
// use the left arrow or delete to delete characters
if (InputState.IsKeyDown(Keys.Left) || InputState.IsKeyDown(Keys.Delete) || InputState.IsKeyDown(Keys.Back))
{
if (mDeleteTimer < 0 || mDeleteTimer == mDeleteHoldDelay)
{
mCommandString = mCommandString.Substring(0, Math.Max(mCommandString.Length - 1, 0));
}
mDeleteTimer -= GenericBaseApplication.GameManager.ElapsedSeconds;
}
else
mDeleteTimer = mDeleteHoldDelay;
// Check for an up or down arrow and iterate through the history accordingly
if (mHistory.Count > 0)
{
if (InputState.IsKeyDown(Keys.Up) && InputState.WasKeyUp(Keys.Up))
{
// Find the next command history item
int oldIndex = mHistoryIndex;
mHistoryIndex++;
while (mHistoryIndex < mHistory.Count && mHistory[mHistoryIndex].CodeType != HistoryItem.Code.Command)
{
mHistoryIndex++;
}
if (mHistoryIndex >= mHistory.Count)
mHistoryIndex = oldIndex;
if (mHistory[mHistoryIndex].CodeType == HistoryItem.Code.Command)
mCommandString = mHistory[mHistoryIndex].Text;
}
else if (InputState.IsKeyDown(Keys.Down) && InputState.WasKeyUp(Keys.Down))
{
// Find the next command history item
int oldIndex = mHistoryIndex;
mHistoryIndex--;
while (mHistoryIndex > 0 && mHistory[mHistoryIndex].CodeType != HistoryItem.Code.Command)
{
mHistoryIndex--;
}
if (mHistoryIndex < 0)
mHistoryIndex = oldIndex;
if (mHistoryIndex >= 0 && mHistory[mHistoryIndex].CodeType == HistoryItem.Code.Command)
mCommandString = mHistory[mHistoryIndex].Text;
}
}
// Check for a commit (Enter key)
if (InputState.IsKeyDown(Keys.Enter) && mCommandString != "")
{
// Send the command the Lua Virtual Machine
try
{
GenericBaseApplication.GameManager.LuaGameManagerVM.DoString(mCommandString);
}
catch (Exception e)
{
mHistory.Insert(0, new HistoryItem(e.Message, HistoryItem.Code.Error));
}
finally
{
}
// Update console commands
mHistory.Insert(0, new HistoryItem(mCommandString, HistoryItem.Code.Command));
mCommandString = "";
mHistoryIndex = -1;
}
// Update history lines
while (mHistory.Count > mHistoryCount)
{
mHistory.RemoveAt(mHistory.Count - 1);
}
// Lock inputstate so things under the console don't get keyboard input
InputState.Locked = true;
}
else
{
InputState.Locked = mWasInputLocked;
}
#endif
}
///
/// Draws a semi-transparent box with a luac command line and history lines on top of everything else.
/// Only draws things in Debug mode.
///
public static void Draw()
{
#if DEBUG
// Check visibility
if (mVisible)
{
mSpriteBatch.Begin(SpriteBlendMode.Additive, SpriteSortMode.Immediate, SaveStateMode.None);
// Draw the box
int lineY = (int)(GenericBaseApplication.GameManager.ScreenHeight * mScreenPercentage);
Texture2D lineTex = TextureManager.Load(@"Content\General\White");
mSpriteBatch.Draw(
lineTex,
new Rectangle(0, 0, GenericBaseApplication.GameManager.ScreenWidth, (int)(GenericBaseApplication.GameManager.ScreenHeight * mScreenPercentage)),
null,
new Color(75, 75, 155, 180),
0f,
Vector2.Zero,
SpriteEffects.None,
0f);
mSpriteBatch.Draw(
lineTex,
new Rectangle(0, (int)(lineY - 2), GenericBaseApplication.GameManager.ScreenWidth, 4),
null,
new Color(200, 200, 200, 200),
0f,
Vector2.Zero,
SpriteEffects.None,
0f);
mSpriteBatch.End();
// Draw the command line
Rectangle cursorSize = GenericBaseApplication.GameManager.StandardFont.MeasureString(mCursor);
GenericBaseApplication.GameManager.StandardFont.DrawString(
new Vector2(mLeft, lineY - mBottom),
mCursor,
new Color(255, 150, 0, 255));
GenericBaseApplication.GameManager.StandardFont.DrawString(
new Vector2(mLeft + (int)cursorSize.Width, lineY - mBottom),
mCommandString,
new Color(255, 255, 175, 255));
// Draw the history lines
Color color;
for (int i = 0; i < mHistory.Count; i++)
{
int y = lineY - (mSpacing) * (i + 2);
if (mHistoryIndex == i)
GenericBaseApplication.GameManager.StandardFont.DrawString(
new Vector2(mLeft, y),
mCursor,
new Color(200, 150, 0, 200));
if (mHistory[i].CodeType == HistoryItem.Code.Command)
color = new Color(200, 200, 150, 255);
else if (mHistory[i].CodeType == HistoryItem.Code.Output)
color = new Color(155, 255, 255, 255);
else
color = new Color(255, 0, 0, 255);
GenericBaseApplication.GameManager.StandardFont.DrawString(
new Vector2(mLeft + (int)cursorSize.Width, y),
mHistory[i].Text,
color);
}
}
#endif
}
}
}