/*
* Util.DialogScreen.cs
* Authors: Adam Nabinger
* Copyright (c) 2007-2008 Cornell University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Util
{
///
/// Which corner the image for the dialog will appear, with the text adjacent to it horizontally.
///
public enum Corner
{
///
/// The Top Left Corner.
///
TopLeft,
///
/// The Top Right Corner.
///
TopRight,
///
/// The Bottom Left Corner.
///
BottomLeft,
///
/// The Bottom Right Corner.
///
BottomRight
};
///
/// An individual dialog to appear on the screen.
///
public sealed class Dialog : IDisposable
{
#region Constants
// Rate at which text appears
private const float mScrollRate = 80f;
// Default path name for dialog font
private const string defaultfontname = @"Fonts\dialogfont";
// Defualt path name for label dialog font
private const string defaultlabelfontname = @"Fonts\dialoglabelfont";
// String giving the appropriate message for advancing between dialogs
private const string nextString = "(Press the space bar to continue)";
#endregion
#region Fields
// Coloring of shadow
private readonly Color ShadowColor = new Color(0, 0, 0, 140);
// Coloring of tint
private readonly Color Tint = Color.White;
// Character label for dialog text
private readonly string mLabel;
// Current text to display
private string mText;
// Path name of the sprite font to use for dialog text
private readonly string mFontName = defaultfontname;
// Path name of the sprite font to use for dialog label text
private readonly string mLabelFontName = defaultlabelfontname;
// Path name to the texture file for the dialog
private readonly string mIconTextureName;
// Path name to the sound file to play - UNIMPLEMENTED
//private readonly string mSound;
// Position of the dialog screen
private readonly Corner mPosition;
// Location of the dialog label
private Vector2 LabelLocation;
// Location of the label's shadow
private Vector2 LabelShadowLocation;
// Location of the text
private Vector2 TextLocation;
// Location of the text's shadow
private Vector2 TextShadowLocation;
// The texture for the background image of the dialog screen
private Texture2D backgroundTexture;
// The location and dimnsions of the dialog screen's background
private Rectangle backgroundLocation;
// Location of the next string
private Vector2 nextStringLocation;
// Location of the next string's shadow
private Vector2 nextStringShadowLocation;
// Location of the icon iamge
private Rectangle IconLocation;
// Flip effect to apply to the icon texture
private SpriteEffects Flip;
// Texture for the icon in the dialog screen
private Texture2D IconTexture;
// Sprite Font used to render the dialog text
private SpriteFont Font;
// Label font used to render the dialog label
private SpriteFont LabelFont;
// Length of the current text
private float CurrentLength;
// Current text being displayed in the dialog screen
private string CurrentText;
///
/// Is the user allow to skip this dialog?
///
internal readonly bool mSkipAllowed;
///
/// Is this dialog timed?
///
internal readonly bool Timed;
///
/// The time remaining for displaying the rest of the text
///
internal float TimeRemaining;
///
/// Whether or not the dialog is ready to skip
///
internal bool readyToSkip;
#endregion
#region Creation
///
/// Constructor
///
/// The character label for the dialog text
/// The dialog text to be displayed
/// File path name to the texture image to use
/// Position of the dialog screen
/// Time duration in which text appears
/// Whether or not this dialog is skippable
public Dialog(string label, string text, string iconTextureName, Corner position, float time, bool skip)
{
mLabel = label;
mText = text;
mIconTextureName = iconTextureName;
mSkipAllowed = skip;
mPosition = position;
if (time <= 0)
{
return;
}
Timed = true;
TimeRemaining = time;
}
///
/// Constructor
///
/// The character label for the dialog text
/// The dialog text to be displayed
/// File path name to the texture image to use
/// Position of the dialog screen
/// Time duration in which text appears
/// Whether or not this dialog is skippable
/// File path name of the spritefont to use for the text
/// File path name of the sprite font to use for the label
public Dialog(string label, string text, string iconTextureName, Corner position, float time, bool skip, string fontName, string labelFontName)
{
mLabel = label;
mText = text;
mFontName = fontName;
mLabelFontName = labelFontName;
mIconTextureName = iconTextureName;
mSkipAllowed = skip;
mPosition = position;
if (time <= 0)
{
return;
}
Timed = true;
TimeRemaining = time;
}
#endregion
#region Initialization
///
/// Initializes any needed objects upon creation
///
/// The viewport in which this is displayed in
public void Initialize(Viewport viewport)
{
int screenWidth = viewport.Width;
int screenHeight = viewport.Height;
switch (mPosition)
{
case Corner.BottomLeft:
backgroundLocation = new Rectangle(0, (int)(screenHeight * 0.750f), screenWidth, (int)(screenHeight * 0.250f));
//nextArrowLocation = new Rectangle((int)(screenWidth * 0.950f), (int)(screenHeight * 0.950f), (int)(screenWidth * 0.030f), (int)(screenHeight * 0.030f));
Flip = SpriteEffects.FlipHorizontally;
IconLocation = new Rectangle(0, (int)(screenHeight * 0.750f), (int)(screenWidth * 0.250f), (int)(screenHeight * 0.330f));
LabelLocation = new Vector2(screenWidth * 0.250f, screenHeight * 0.800f);
nextStringLocation = new Vector2(screenWidth * 0.255f, screenHeight * 0.985f);
break;
case Corner.BottomRight:
backgroundLocation = new Rectangle(0, (int)(screenHeight * 0.750f), screenWidth, (int)(screenHeight * 0.250f));
//nextArrowLocation = new Rectangle((int)(screenWidth * 0.720f), (int)(screenHeight * 0.950f), (int)(screenWidth * 0.030f), (int)(screenHeight * 0.030f));
Flip = SpriteEffects.None;
IconLocation = new Rectangle((int)(screenWidth * 0.800f), (int)(screenHeight * 0.750f), (int)(screenWidth * 0.250f), (int)(screenHeight * 0.330f));
LabelLocation = new Vector2(screenWidth * 0.025f, screenHeight * 0.800f);
nextStringLocation = new Vector2(screenWidth * 0.030f, screenHeight * 0.985f);
break;
case Corner.TopLeft:
backgroundLocation = new Rectangle(0, 0, screenWidth, (int)(screenHeight * 0.250f));
//nextArrowLocation = new Rectangle((int)(screenWidth * 0.950f), (int)(screenHeight * 0.200f), (int)(screenWidth * 0.030f), (int)(screenHeight * 0.030f));
Flip = SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically;
IconLocation = new Rectangle(0, 0, (int)(screenWidth * 0.250f), (int)(screenHeight * 0.330f));
LabelLocation = new Vector2(screenWidth * 0.250f, screenHeight * 0.050f);
nextStringLocation = new Vector2(screenWidth * 0.255f, screenHeight * 0.235f);
break;
case Corner.TopRight:
backgroundLocation = new Rectangle(0, 0, screenWidth, (int)(screenHeight * 0.250f));
//nextArrowLocation = new Rectangle((int)(screenWidth * 0.720f), (int)(screenHeight * 0.200f), (int)(screenWidth * 0.030f), (int)(screenHeight * 0.030f));
Flip = SpriteEffects.FlipVertically;
IconLocation = new Rectangle((int)(screenWidth * 0.800f), 0, (int)(screenWidth * 0.330f), (int)(screenHeight * 0.250f));
LabelLocation = new Vector2(screenWidth * 0.025f, screenHeight * 0.050f);
nextStringLocation = new Vector2(screenWidth * 0.030f, screenHeight * 0.235f);
break;
}
float maxTextLength = screenWidth * 0.7f;
string[] data = mText.Split(new char[] { '\n' }, StringSplitOptions.None);
List result = new List();
foreach (string s in data)
{
result.AddRange(TextUtility.BreakString(s, maxTextLength, Font));
}
StringBuilder sb = new StringBuilder();
foreach (string s in result)
{
sb.AppendLine(s);
}
mText = sb.ToString();
TextLocation = LabelLocation;
TextLocation.Y += screenHeight * 0.040f;
nextStringLocation.Y -= Font.MeasureString(nextString).Y;
LabelShadowLocation = LabelLocation + new Vector2(screenWidth * 0.003f, screenHeight * 0.003f);
TextShadowLocation = TextLocation + new Vector2(screenWidth * 0.003f, screenHeight * 0.003f);
nextStringShadowLocation = nextStringLocation + new Vector2(screenWidth * 0.003f, screenHeight * 0.003f);
CurrentText = string.Empty;
}
#endregion
#region Management
///
/// Loads in all the information needed for content dependent objects
///
/// The current content manager used for content loading
public void LoadContent(ContentManager content)
{
backgroundTexture = content.Load(@"General\DialogBackground");
//nextArrowTexture = content.Load(@"General\NextArrow");
Font = content.Load(mFontName);
LabelFont = content.Load(mLabelFontName);
if (!string.IsNullOrEmpty(mIconTextureName))
{
IconTexture = content.Load(mIconTextureName);
}
}
///
/// Disposes of any unmanaged objects
/// TODO: actually implement
///
public void Dispose() { }
#endregion
#region Update
///
/// Updates the dialog screen
///
/// Time that has passed in seconds
public void Update(float seconds)
{
if (Timed)
{
TimeRemaining -= seconds;
}
if (mSkipAllowed && CurrentLength >= mText.Length)
{
readyToSkip = true;
}
if (readyToSkip)
{
CurrentText = mText;
}
else
{
CurrentLength += seconds * mScrollRate;
CurrentText = mText.Substring(0, Math.Min((int)CurrentLength, mText.Length));
}
}
#endregion
#region Render
///
/// Renders the dialog screen
///
public void Draw(SpriteBatch sb)
{
sb.Begin(SpriteBlendMode.AlphaBlend);
sb.Draw(backgroundTexture, backgroundLocation, Tint);
if (IconTexture != null)
{
sb.Draw(IconTexture, IconLocation, null, Tint, 0f, Vector2.Zero, Flip, 0f);
}
sb.DrawString(LabelFont, mLabel + ":", LabelShadowLocation, ShadowColor);
sb.DrawString(Font, CurrentText, TextShadowLocation, ShadowColor);
sb.DrawString(LabelFont, mLabel + ":", LabelLocation, Tint);
sb.DrawString(Font, CurrentText, TextLocation, Tint);
if (readyToSkip)
{
//sb.Draw(nextArrowTexture, nextArrowLocation, Tint);
sb.DrawString(Font, nextString, nextStringShadowLocation, ShadowColor);
sb.DrawString(Font, nextString, nextStringLocation, Tint);
}
sb.End();
}
#endregion
}
///
/// A screen for displaying a series of dialogs.
///
public sealed class DialogScreen : GameScreen
{
#region Fields
// Whether or not this dialog screen is skippable
private readonly bool mSkippable;
// The array of dialogs
private readonly Dialog[] dialogs;
// The current index in dialogs
private int index;
// The sprite batch to use for rendering
private SpriteBatch sb;
// The input handler for handling all the input for the dialog screen
private InputHandler inputHandler;
#endregion
#region Creation
///
/// Create a new dialog screen, giving an ordered list of dialogs to show.
///
/// List of dialogs to display
public DialogScreen(List