#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(); } } }