/
etc/
lib/
src/Abilities/
src/Abilities/Skills/
src/Abilities/Spells/
src/Abilities/Spells/Enums/
src/Affects/
src/ArtheaConsole/
src/ArtheaConsole/Properties/
src/ArtheaGUI/Properties/
src/Clans/Enums/
src/Commands/Communication/
src/Commands/ItemCommands/
src/Connections/
src/Connections/Colors/
src/Connections/Enums/
src/Connections/Players/
src/Connections/Players/Enums/
src/Continents/
src/Continents/Areas/
src/Continents/Areas/Characters/
src/Continents/Areas/Characters/Enums/
src/Continents/Areas/Items/
src/Continents/Areas/Items/Enums/
src/Continents/Areas/Rooms/
src/Continents/Areas/Rooms/Enums/
src/Continents/Areas/Rooms/Exits/
src/Creation/
src/Creation/Attributes/
src/Creation/Interfaces/
src/Database/
src/Database/Interfaces/
src/Environment/
src/Properties/
src/Scripts/Enums/
src/Scripts/Interfaces/
#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.Xml.Serialization;
using Arthea.Affects;
using Arthea.Connections.Players;
using Arthea.Continents.Areas.Characters.Enums;
using Arthea.Continents.Areas.Items;
using Arthea.Continents.Areas.Items.Enums;
using Arthea.Continents.Areas.Rooms;
using Arthea.Creation.Attributes;
using Arthea.Environment;
using Arthea.Interfaces;
using Arthea.Races;
using Arthea.Scripts;

namespace Arthea.Continents.Areas.Characters
{
    /// <summary>
    /// An entity with a role to play in the game.
    /// </summary>
    public class Character : Scriptable
    {
        #region [rgn] Fields (24)

        private const int defautVitals = 100;
        private AffectList affects = new AffectList();
        private int armor;
        [EditShow] private ItemList carrying = new ItemList();
        private string description;
        [XmlIgnore, EditIgnore] private Character fighting;
        private int hit = defautVitals;
        [EditShow] private CharIndex index;
        private byte level;
        private int mana = defautVitals;
        private int maxHit = defautVitals;
        private int maxMana = defautVitals;
        private int maxMove = defautVitals;
        private int move = defautVitals;
        private string name;
        private Position position = Position.Standing;
        private Race race;
        [EditShow] private Room room;
        private string roomDescr;

        /// <summary>
        /// True if RoomDescr should be serialized
        /// </summary>
        [EditIgnore, XmlIgnore] public bool RoomDescrSpecified = true;

        private Sex sex;
        private string shortDescr;

        /// <summary>
        /// True if ShortDescr should be serialized
        /// </summary>
        [EditIgnore, XmlIgnore] public bool ShortDescrSpecified = true;

        /// <summary>
        /// True if XmlIndex should be serialized
        /// </summary>
        [XmlIgnore, EditIgnore] public bool XmlIndexSpecified = true;

        #endregion [rgn]

        #region [rgn] Constructors (3)

        /// <summary>
        /// Initializes a new instance of the <see cref="Character"/> class.
        /// </summary>
        /// <param name="level">The level.</param>
        /// <param name="name">The name.</param>
        public Character(byte level, string name)
        {
            this.level = level;
            this.name = name;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Character"/> class.
        /// </summary>
        /// <param name="index">The index.</param>
        public Character(CharIndex index)
        {
            this.index = index;
            level = index.Level;
            name = index.Name;
            shortDescr = index.ShortDescr;
            roomDescr = index.RoomDescr;
            description = index.Description;
            hit = maxHit = index.MaxHit;
            mana = maxMana = index.MaxMana;
            move = maxMove = index.MaxMove;
            position = index.Position;
            sex = index.Sex;
            race = index.Race;
            affects = index.Affects;
            affects.Add(index.Race.Affects);
        }

        /// <summary>
        /// Default Constructor
        /// </summary>
        public Character()
        {
        }

        #endregion [rgn]

        #region [rgn] Properties (26)

        /// <summary>
        /// Gets or sets the affects.
        /// </summary>
        /// <value>The affects.</value>
        public AffectList Affects
        {
            get { return affects; }
            set { affects = value; }
        }

        /// <summary>
        /// Gets the area.
        /// </summary>
        /// <value>The area.</value>
        public virtual Area Area
        {
            get { return index.Area; }
        }

        /// <summary>
        /// Gets or sets the armor.
        /// </summary>
        /// <value>The armor.</value>
        public int Armor
        {
            get { return armor; }
            set { armor = value; }
        }

        /// <summary>
        /// Gets or sets the carrying.
        /// </summary>
        /// <value>The carrying.</value>
        public ItemList Carrying
        {
            get { return carrying; }
            set { carrying = value; }
        }

        /// <summary>
        /// Gets or sets the description.
        /// </summary>
        /// <value>The description.</value>
        public string Description
        {
            get { return description; }
            set { description = value; }
        }

        /// <summary>
        /// Gets or sets the fighting.
        /// </summary>
        /// <value>The fighting.</value>
        [XmlIgnore]
        public Character Fighting
        {
            get { return fighting; }
            set
            {
                fighting = value;
                if (value != null)
                {
                    Lists.Fights.Add(this);
                    position = Position.Fighting;
                }
                else
                {
                    Lists.Fights.Remove(this);
                    position = Position.Standing;
                }
            }
        }

        /// <summary>
        /// Gets or sets the hit.
        /// </summary>
        /// <value>The hit.</value>
        public int Hit
        {
            get { return hit; }
            set
            {
                hit = value;
                if (hit > maxHit)
                    hit = maxHit;
            }
        }

        /// <summary>
        /// Gets the id.
        /// </summary>
        /// <value>The id.</value>
        public uint Id
        {
            get
            {
                if (index != null)
                    return index.Id;
                else
                    return 0;
            }
        }

        /// <summary>
        /// Gets or sets the code.
        /// </summary>
        /// <value>The code.</value>
        [XmlIgnore]
        public CharIndex Index
        {
            get { return index; }
            set { index = value; }
        }

        /// <summary>
        /// Gets or sets the level.
        /// </summary>
        /// <value>The level.</value>
        public byte Level
        {
            get { return level; }
            set { level = value; }
        }

        /// <summary>
        /// Gets or sets the mana.
        /// </summary>
        /// <value>The mana.</value>
        public int Mana
        {
            get { return mana; }
            set
            {
                mana = value;
                if (mana > maxMana)
                    mana = maxMana;
            }
        }

        /// <summary>
        /// Gets or sets the max hit.
        /// </summary>
        /// <value>The max hit.</value>
        public int MaxHit
        {
            get { return maxHit; }
            set { maxHit = value; }
        }

        /// <summary>
        /// Gets or sets the max mana.
        /// </summary>
        /// <value>The max mana.</value>
        public int MaxMana
        {
            get { return maxMana; }
            set { maxMana = value; }
        }

        /// <summary>
        /// Gets or sets the max move.
        /// </summary>
        /// <value>The max move.</value>
        public int MaxMove
        {
            get { return maxMove; }
            set { maxMove = value; }
        }

        /// <summary>
        /// Gets or sets the move.
        /// </summary>
        /// <value>The move.</value>
        public int Move
        {
            get { return move; }
            set
            {
                move = value;
                if (move > maxMove)
                    move = maxMove;
            }
        }

        /// <summary>
        /// Gets or sets the position.
        /// </summary>
        /// <value>The position.</value>
        public Position Position
        {
            get { return position; }
            set { position = value; }
        }

        /// <summary>
        /// Gets or sets the race.
        /// </summary>
        /// <value>The race.</value>
        [XmlIgnore]
        public Race Race
        {
            get { return race; }
            set { race = value; }
        }

        /// <summary>
        /// Gets/sets the character room.
        /// </summary>
        [XmlIgnore]
        public Room Room
        {
            get { return room; }
            set
            {
                if (room != null && room != value && room.Characters.Contains(this))
                {
                    room.Characters.Remove(this);
                    if (this is Player)
                        room.Area.Players--;
                }

                room = value;

                if (room != null && !room.Characters.Contains(this))
                {
                    room.Characters.Add(this);
                    if (this is Player)
                        room.Area.Players++;
                }
            }
        }

        /// <summary>
        /// Gets or sets the room descr.
        /// </summary>
        /// <value>The room descr.</value>
        public virtual string RoomDescr
        {
            get { return roomDescr; }
            set { roomDescr = value; }
        }

        /// <summary>
        /// Gets or sets the sex.
        /// </summary>
        /// <value>The sex.</value>
        public Sex Sex
        {
            get { return sex; }
            set { sex = value; }
        }

        /// <summary>
        /// Gets the size.
        /// </summary>
        /// <value>The size.</value>
        public Size Size
        {
            get { return race == null ? Size.Medium : race.Size; }
        }

        /// <summary>
        /// Gets or sets the code id.
        /// </summary>
        /// <value>The code id.</value>
        [XmlElement("Code")]
        public virtual uint XmlIndex
        {
            get { return index.Id; }
            set { index = Lists.CharIndexes[value]; }
        }

        /// <summary>
        /// Gets or sets the race as a string.
        /// </summary>
        /// <value>The race as a string.</value>
        [XmlElement("Race")]
        public string XmlRace
        {
            get { return race.Name; }
            set { race = Lists.Races.FindName(value); }
        }

        /// <summary>
        /// Gets or sets the room id.
        /// </summary>
        /// <value>The room id.</value>
        [XmlElement("Room")]
        public uint XmlRoom
        {
            get { return room != null ? room.Id : Globals.Limbo; }
            set { Room = Lists.Rooms[value]; }
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Gets or sets the short descr.
        /// </summary>
        /// <value>The short descr.</value>
        public virtual string ShortDescr
        {
            get { return shortDescr; }
            set { shortDescr = value; }
        }

        #endregion [rgn]

        #region [rgn] Methods (13)

        // [rgn] Public Methods (13)

        /// <summary>
        /// Performs an action message.
        /// </summary>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="type">The type.</param>
        /// <param name="text">The text.</param>
        /// <param name="args">The args.</param>
        public void Act(object arg1, object arg2, ulong type, string text, params object[] args)
        {
            Act(arg1, arg2, type, string.Format(text, args));
        }

        /// <summary>
        /// Performs an action message
        /// </summary>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="type">The type.</param>
        /// <param name="text">The text.</param>
        public void Act(object arg1, object arg2, ulong type, string text)
        {
            Act bitArray = new Act(type);
            Character vict = arg2 as Character;

            if (bitArray.Has(Arthea.Act.ToPlayer))
            {
                Arthea.Act.Show(this, arg1, arg2, this, text);
            }

            if (bitArray.Has(Arthea.Act.ToVictim))
            {
                if (vict != null && vict != this)
                    Arthea.Act.Show(this, arg1, arg2, vict, text);
            }

            if (bitArray.Has(Arthea.Act.ToRoom | Arthea.Act.ToNotVict))
            {
                Item item1 = arg1 as Item;
                Item item2 = arg2 as Item;
                Room currentRoom = null;

                if (Room != null)
                {
                    currentRoom = Room;
                }
                else if (item1 != null && item1.Room != null)
                {
                    currentRoom = item1.Room;
                }
                else if (item2 != null && item2.Room != null)
                {
                    currentRoom = item2.Room;
                }
                else
                {
                    Log.Bug("Act.Show: Bad room.");
                }

                if (currentRoom != null)
                {
                    foreach (Character rch in currentRoom.Characters)
                    {
                        if (rch == this || rch == vict)
                            continue;

                        Arthea.Act.Show(this, arg1, arg2, rch, text);
                    }
                }
            }

            if (bitArray.Has(Arthea.Act.ToWorld))
            {
                foreach (Player p in Lists.Players)
                {
                    if (p == this)
                        continue;

                    Arthea.Act.Show(this, arg1, arg2, p, text);
                }
            }
        }

        /// <summary>
        /// Attaches this instance.
        /// </summary>
        public virtual void Attach()
        {
            Lists.Characters.Add(this);
        }

        /// <summary>
        /// Equips the specified item.
        /// </summary>
        /// <param name="item">The item.</param>
        public void Equip(Item item)
        {
            item.WearLoc = item.Index.WearLoc;
            affects.Add(item.Affects);
        }

        /// <summary>
        /// Gets the equip.
        /// </summary>
        /// <param eqName="eqName">The eqName.</param>
        /// <returns></returns>
        public Item GetEquip(String eqName)
        {
            foreach (Item item in carrying)
            {
                if (item.WearLoc == WearLocation.None)
                    continue;

                if (eqName.IsPrefixOf(item.Name))
                {
                    return item;
                }
            }
            return null;
        }

        /// <summary>
        /// Removes character from lists
        /// </summary>
        public virtual void Release()
        {
            Lists.Characters.Remove(this);

            if (room != null)
            {
                room.Characters.Remove(this);

                room = null;
            }

            while (carrying.Count > 0)
            {
                carrying[0].Release();
            }

            Fighting = null;
        }

        /// <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()
        {
            return shortDescr;
        }

        /// <summary>
        /// A string representation for a character.
        /// </summary>
        /// <param name="looker">The looker.</param>
        /// <returns></returns>
        public string ToString(Character looker)
        {
            return ShortDescr;
        }

        /// <summary>
        /// Uns the equip.
        /// </summary>
        /// <param name="item">The item.</param>
        public void UnEquip(Item item)
        {
            item.WearLoc = WearLocation.None;
            affects.Remove(item.Affects);
        }

        /// <summary>
        /// Writes the specified text.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="args">The args.</param>
        public virtual void Write(string text, params object[] args)
        {
            Player player;
            if (this is Player && (player = this as Player) != null)
            {
                player.Write(text, args);
            }
        }

        /// <summary>
        /// Writes the specified text.
        /// </summary>
        /// <param name="text">The text.</param>
        public virtual void Write(string text)
        {
            Player player;
            if (this is Player && (player = this as Player) != null)
            {
                player.Write(text);
            }
        }

        /// <summary>
        /// Writes a line.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="args">The args.</param>
        public virtual void WriteLine(string text, params object[] args)
        {
            Player player;
            if (this is Player && (player = this as Player) != null)
                player.WriteLine(text, args);
        }

        /// <summary>
        /// Writes the line.
        /// </summary>
        public virtual void WriteLine()
        {
            Player player;

            if (this is Player && (player = this as Player) != null)
            {
                player.WriteLine();
            }
        }

        #endregion [rgn]

        #region Scriptable Members

        /// <summary>
        /// Creates a script of proper type.
        /// </summary>
        /// <returns></returns>
        public Script CreateScript(ScriptCode code, String trigger)
        {
            return new CharScript(code, trigger);
        }

        #endregion
    }
}