#region Arthea License
/***********************************************************************
* Arthea MUD by R. Jennings (2007) http://arthea.googlecode.com/ *
* By using this code you comply with the Artistic and GPLv2 Licenses. *
***********************************************************************/
#endregion
using System;
using System.Text;
using System.Xml.Serialization;
using Arthea.Connections.Players;
using Arthea.Environment;
namespace Arthea.Connections.Colors
{
/// <summary>
/// Implements a color
/// </summary>
public class Color
{
#region Constants
/// <summary>
/// The attribute of a color
/// </summary>
public const int Attribute = 0;
/// <summary>
/// The background of a color
/// </summary>
public const int Background = 2;
/// <summary>
/// The color escape code
/// </summary>
public const char CODE = '~';
/// <summary>
/// Escape code
/// </summary>
public const string ESC = "\x1B[";
/// <summary>
/// The foreground of a color
/// </summary>
public const int Foreground = 1;
#endregion
private const int Max = 3;
private static readonly Color[] lastColor = new Color[2];
private static int lastColorIndex = 0;
private int saveValue;
private int[] values = new int[Max];
#region Constructors (3)
/// <summary>
/// Initializes the <see cref="Color"/> class.
/// </summary>
static Color()
{
lastColor[0] = new Color();
lastColor[1] = new Color();
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> class.
/// </summary>
public Color()
{
Clear();
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> class.
/// </summary>
/// <param name="c">The c.</param>
public Color(char c)
{
Clear();
Set(c);
}
#endregion
#region Properties (1)
/// <summary>
/// Gets or sets the values.
/// </summary>
/// <value>The values.</value>
[XmlIgnore]
public int[] Values
{
get { return values; }
set { values = value; }
}
#endregion
#region Methods
/// <summary>
/// Toes the string.
/// </summary>
/// <param name="saveFlag">The save flag.</param>
/// <returns></returns>
public string ToString(int saveFlag)
{
StringBuilder buf = new StringBuilder();
buf.Append(values[Attribute]);
buf.Append("-");
buf.Append(values[Foreground]);
if (ValidColor(Background, values[Background]))
{
buf.Append("-");
buf.Append(values[Background]);
}
return buf.ToString();
}
/// <summary>
/// Parses the specified word to color values (#-#-# format).
/// </summary>
/// <param name="word">The word.</param>
/// <returns></returns>
public static Color Parse(string word)
{
string[] words = word.Split('-');
Color color = new Color();
for (int i = 0; i < words.Length; i++)
{
color.values[i] = int.Parse(words[i]);
}
return color;
}
/// <summary>
/// Initializes this instance.
/// </summary>
private void Clear()
{
for (int i = 0; i < values.Length; i++)
values[i] = ColorValue.None;
saveValue = ColorValue.Mod;
}
/// <summary>
/// Copies the from the specified color.
/// </summary>
/// <param name="from">From.</param>
public void Copy(Color from)
{
for (int x = 0; x < values.Length; x++)
values[x] = from.values[x];
saveValue = from.saveValue;
}
/// <summary>
/// Sets the specified part of the color.
/// </summary>
/// <param name="part">The part.</param>
/// <param name="value">The value.</param>
public void Set(int part, int value)
{
if (part < values.Length)
values[part] = value;
else
saveValue = value;
}
/// <summary>
/// Sets the color based on a code.
/// </summary>
/// <param name="c">The c.</param>
public void Set(char c)
{
if (char.IsUpper(c))
values[Attribute] = ColorValue.Bright;
else
values[Attribute] = ColorValue.None;
switch (char.ToLower(c))
{
case '?':
case '`':
values[Attribute] = ColorValue.Random;
values[Foreground] = ColorValue.Random;
break;
case 'z':
values[Attribute] = ColorValue.Random;
values[Background] = ColorValue.Random;
break;
case 'b':
values[Foreground] = ColorValue.Blue;
break;
case 'c':
values[Foreground] = ColorValue.Cyan;
break;
case 'g':
values[Foreground] = ColorValue.Green;
break;
case 'm':
values[Foreground] = ColorValue.Magenta;
break;
case 'd':
values[Foreground] = ColorValue.Black;
break;
case 'r':
values[Foreground] = ColorValue.Red;
break;
case 'y':
values[Foreground] = ColorValue.Yellow;
break;
case 'w':
values[Foreground] = ColorValue.White;
break;
default:
break;
}
}
/// <summary>
/// Validates this instance.
/// </summary>
private void Validate()
{
for (int i = 0; i < values.Length; i++)
{
if (values[i] == ColorValue.Random)
{
values[i] = RandomColor(i);
}
}
if (ValidColor(Foreground, saveValue))
{
if (ValidColor(Foreground, values[Foreground]))
values[Background] = (values[Foreground] + ColorValue.Mod);
values[Foreground] = saveValue;
}
if (ValidColor(Attribute, saveValue))
values[Attribute] = saveValue;
saveValue = ColorValue.Mod;
}
/// <summary>
/// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
/// </returns>
public override string ToString()
{
Validate();
StringBuilder buf = new StringBuilder();
for (int i = 0; i < values.Length; i++)
{
if (ValidColor(i, values[i]))
{
buf.Append(";");
buf.Append(values[i]);
}
}
if (buf.Length > 0)
buf.Remove(0, 1);
else
buf.Append("0");
buf.Append("m");
return ESC + buf;
}
#endregion
/// <summary>
/// A random part of a color.
/// </summary>
/// <param name="part">The part.</param>
/// <returns></returns>
private static int RandomColor(int part)
{
int i;
switch (part)
{
case Attribute:
i = Randomizer.Next(ColorValue.None, ColorValue.Bright);
break;
case Foreground:
i = Randomizer.Next(ColorValue.Red, ColorValue.White);
break;
case Background:
i = Randomizer.Next(ColorValue.RedBG, ColorValue.WhiteBG);
break;
default:
return ColorValue.None;
}
return i;
}
/// <summary>
/// Validates part of the color.
/// </summary>
/// <param name="part">The part.</param>
/// <param name="code">The code.</param>
/// <returns></returns>
public static bool ValidColor(int part, int code)
{
switch (part)
{
case Foreground:
return (code >= ColorValue.Black && code <= ColorValue.White);
case Background:
return (code >= ColorValue.BlackBG && code <= ColorValue.WhiteBG);
case Attribute:
return (code >= ColorValue.None && code <= ColorValue.Hidden);
default:
return false;
}
}
/// <summary>
/// Converts the specified text.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="player">The player.</param>
/// <returns></returns>
public static string Convert(string text, Player player)
{
if (text == null)
return "";
Color col = new Color();
CharEnumerator ps = text.GetEnumerator();
StringBuilder buf = new StringBuilder();
ps.MoveNext();
do
{
if (ps.Current == CODE)
{
if (!ps.MoveNext())
break;
if (char.IsDigit(ps.Current))
{
int slot = (ps.Current - '0');
/*
* Use a number code to set an ansi colour attribute
*/
if (ValidColor(Attribute, slot))
{
col.Set(col.Values.Length, slot);
}
/*
* Use a '+' sign to add any colour codes, ex. {5G for
* blinking green text {5G=B for blinking green text on a
* blue background
*/
if (!ps.MoveNext())
break;
if (ps.Current == '+')
{
if (!ps.MoveNext())
break;
}
else
{
continue;
}
}
/*
* User a '=' sign to point to a background colour ex. "CT(_VHIT)" sets a
* blue background colour
*/
if (ps.Current == '=')
{
if (!ps.MoveNext())
break;
col.Set(col.Values.Length, col.Values[Foreground]);
}
if (player.Config.Has(PlayerConfig.Color))
{
switch (ps.Current)
{
case 'n':
/*
* Enter the mud's name
*/
buf.Append("Arthea MUD");
break;
case 'N':
/*
* Enter capitalized mud name
*/
buf.Append("Arthea MUD".ToUpper());
break;
case 'P':
case 'p':
case '*':
buf.Append("\007");
break;
case CODE:
buf.Append(CODE);
break;
case 'x':
col.Copy(lastColor[(lastColorIndex + 1)%2]);
buf.Append(col);
break;
case 'X':
col.Clear();
buf.Append(col);
break;
default:
col.Set(ps.Current);
++lastColorIndex;
lastColor[lastColorIndex %= 2] = col;
buf.Append(col);
break;
} // end case
}
}
else if (ps.Current == CustomColor.BEGIN)
{
int slot = -1;
bool fail = false;
do
{
if (!ps.MoveNext())
{
fail = true;
break;
}
if (char.IsDigit(ps.Current))
{
if (slot == -1)
slot = 0;
slot = (slot*10) + (ps.Current - '0');
}
} while (ps.Current != CustomColor.END);
if (fail)
break;
if (player.Config.Has(PlayerConfig.Color))
{
if (CustomColor.Valid(slot))
{
++lastColorIndex;
lastColor[lastColorIndex %= 2] = player.Colors[slot];
buf.Append(player.Colors[slot]);
}
}
}
else
{
buf.Append(ps.Current);
}
} while (ps.MoveNext());
return buf.ToString();
}
}
}