/
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.Collections.Generic;
using Arthea.Abilities;
using Arthea.Connections.Players;
using Arthea.Continents.Areas.Characters;
using Arthea.Continents.Areas.Characters.Enums;
using Arthea.Environment;

namespace Arthea.Collections
{
    /// <summary>
    /// Implementation of combat.
    /// </summary>
    public class Combat : List<Character>
    {
        #region [rgn] Constructors (2)

        /// <summary>
        /// Initializes a new instance of the <see cref="Combat"/> class.
        /// </summary>
        /// <param name="collection">The collection whose elements are copied to the new list.</param>
        /// <exception cref="T:System.ArgumentNullException">collection is null.</exception>
        public Combat(IEnumerable<Character> collection) : base(collection)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Combat"/> class.
        /// </summary>
        public Combat()
        {
        }

        #endregion [rgn]

        #region [rgn] Methods (6)

        // [rgn] Public Methods (5)

        /// <summary>
        /// Damages the specified skill.
        /// </summary>
        /// <param name="skill">The skill.</param>
        /// <param name="killer">The killer.</param>
        /// <param name="victim">The victim.</param>
        /// <param name="dam">The dam.</param>
        public static void Damage(Ability skill, Character killer, Character victim, int dam)
        {
            if (victim.Position == Position.Dead)
                return;

            if (victim.Fighting == null)
                victim.Fighting = killer;

            if (killer.Fighting == null)
                killer.Fighting = victim;

            DamMessage(skill, killer, victim, dam);

            victim.Hit -= dam;

            if (victim.Hit <= 0)
            {
                killer.Act(null, victim, Act.ToPlayer, "$N is dead!");
                killer.Act(null, victim, Act.ToVictim, "$n has killed you!");
                killer.Act(null, victim, Act.ToRoom, "$n has killed $N!");

                killer.Fighting = null;
                victim.Fighting = null;

                if (victim is Player)
                {
                    victim.Room = Lists.Rooms[Globals.Limbo];
                }
                else
                {
                    victim.Release();
                }

                if (killer is Player)
                {
                    Player p = killer as Player;
                    int xp = CalcExp(p, victim);
                    p.Experience += xp;
                    p.WriteLine("You gain {0} experience points!", xp);
                    if (p.CanGainLevel())
                    {
                        p.WriteLine("You can gain another level.");
                    }
                }
            }
        }

        /// <summary>
        /// The damage message.
        /// </summary>
        /// <param name="skill">The skill.</param>
        /// <param name="killer">The killer.</param>
        /// <param name="victim">The victim.</param>
        /// <param name="dam">The dam.</param>
        public static void DamMessage(Ability skill, Character killer, Character victim, int dam)
        {
            int damp = (dam*100)/victim.MaxHit;
            string vs, vp, punc;

            if (damp <= 0)
            {
                vs = "miss";
                vp = "misses";
            }
            else if (damp <= 2)
            {
                vs = "bruise";
                vp = "bruises";
            }
            else if (damp <= 5)
            {
                vs = "scratch";
                vp = "scratches";
            }
            else if (damp <= 9)
            {
                vs = "hit";
                vp = "hits";
            }
            else if (damp <= 13)
            {
                vs = "scar";
                vp = "scars";
            }
            else if (damp <= 18)
            {
                vs = "injure";
                vp = "injures";
            }
            else if (damp <= 23)
            {
                vs = "wound";
                vp = "wounds";
            }
            else if (damp <= 28)
            {
                vs = "maul";
                vp = "mauls";
            }
            else if (damp <= 34)
            {
                vs = "DECIMATE";
                vp = "DECIMATES";
            }
            else if (damp <= 40)
            {
                vs = "DEVASTATE";
                vp = "DEVASTATES";
            }
            else if (damp <= 46)
            {
                vs = "OBLITERATE";
                vp = "OBLITERATES";
            }
            else if (damp <= 53)
            {
                vs = "MUTILATE";
                vp = "MUTILATES";
            }
            else if (damp <= 60)
            {
                vs = "DISEMBOWEL";
                vp = "DISEMBOWELS";
            }
            else if (damp <= 67)
            {
                vs = "*** DEMOLISH ***";
                vp = "*** DEMOLISHES ***";
            }
            else if (damp <= 75)
            {
                vs = "-=- PULVERIZE -=-";
                vp = "-=- PULVERIZES -=-";
            }
            else if (damp <= 83)
            {
                vs = "<-&-> WASTE <-&->";
                vp = "<-&-> WASTES <-&->";
            }
            else if (damp <= 91)
            {
                vs = "<::><::> DISFIGURE <::><::>";
                vp = "<::><::> DISFIGURES <::><::>";
            }
            else
            {
                vs = "inflict UNIMAGINABLE PAIN on";
                vp = "inflicts UNIMAGINABLE PAIN on";
            }

            punc = damp < 10
                       ? "."
                       : damp < 30
                             ? "!"
                             : damp < 45
                                   ? "!!"
                                   :
                                       damp < 60 ? "!!!" : damp < 75 ? "!!!!" : damp < 90 ? "!!!!!!" : "!!!!!!!!";

            if (skill == null)
            {
                if (killer == victim)
                {
                    killer.Act(null, null, Act.ToRoom, "$n {0} $m{1}", vp, punc);
                    killer.Act(null, null, Act.ToPlayer, "You {0} yourself{1}", vs, punc);
                }
                else
                {
                    killer.Act(null, victim, Act.ToPlayer, "You {0} $N{1}", vs, punc);
                    killer.Act(null, victim, Act.ToVictim, "$n {0} you{1}", vp, punc);
                    killer.Act(null, victim, Act.ToRoom, "$n {0} $N{1}", vp, punc);
                }
            }
            else
            {
                if (killer == victim)
                {
                    killer.Act(null, null, Act.ToRoom, "$n's {0} {1} $m{2}", skill.DamageNoun, vp, punc);
                    killer.Act(null, null, Act.ToPlayer, "Your {0} {1} yourself{2}", skill.DamageNoun, vp, punc);
                }
                else
                {
                    killer.Act(null, victim, Act.ToPlayer, "Your {0} {1} $N{2}", skill.DamageNoun, vp, punc);
                    killer.Act(null, victim, Act.ToVictim, "$n's {0} {1} you{2}", skill.DamageNoun, vp, punc);
                    killer.Act(null, victim, Act.ToRoom, "$n's {0} {1} $N{2}", skill.DamageNoun, vp, punc);
                }
            }
        }

        /// <summary>
        /// Multis the hit.
        /// </summary>
        /// <param name="killer">The killer.</param>
        /// <param name="victim">The victim.</param>
        public static void MultiHit(Character killer, Character victim)
        {
            OneHit(killer, victim);
        }

        /// <summary>
        /// Ones the hit.
        /// </summary>
        /// <param name="killer">The killer.</param>
        /// <param name="victim">The victim.</param>
        public static void OneHit(Character killer, Character victim)
        {
            int ac = 10 + victim.Armor;

            int roll = Randomizer.Next(20);

            if (killer is Player)
            {
                roll *= (killer as Player).Class.BaseAttackMod;
                roll /= 100;
            }

            if (roll < ac)
            {
                killer.Act(null, victim, Act.ToPlayer, "You miss $N.");
                killer.Act(null, victim, Act.ToVictim, "$n misses you.");
                killer.Act(null, victim, Act.ToRoom, "$n misses $N.");
                return;
            }

            int dam = Randomizer.Next(killer.Level/3, killer.Level);

            Damage(null, killer, victim, dam);
        }

        /// <summary>
        /// Updates this instance.
        /// </summary>
        public void Update()
        {
            if (Count == 0)
            {
                return;
            }

            // leading line
            foreach (Character ch in this)
            {
                if (ch is Player)
                    ch.WriteLine();
            }

            for (int i = 0; i < Count;)
            {
                if (this[i].Fighting == null)
                {
                    RemoveAt(i);
                    continue;
                }
                if (this[i].Room != this[i].Fighting.Room)
                {
                    this[i].Fighting = null;
                    continue;
                }
                MultiHit(this[i], this[i].Fighting);
                i++;
            }
        }

        // [rgn] Private Methods (1)

        private static int CalcExp(Character killer, Character victim)
        {
            int levelRange = victim.Level - killer.Level;
            int xp;

            switch (levelRange)
            {
                default:
                    xp = 0;
                    break;
                case -9:
                    xp = 1;
                    break;
                case -8:
                    xp = 2;
                    break;
                case -7:
                    xp = 5;
                    break;
                case -6:
                    xp = 9;
                    break;
                case -5:
                    xp = 11;
                    break;
                case -4:
                    xp = 22;
                    break;
                case -3:
                    xp = 33;
                    break;
                case -2:
                    xp = 50;
                    break;
                case -1:
                    xp = 66;
                    break;
                case 0:
                    xp = 83;
                    break;
                case 1:
                    xp = 99;
                    break;
                case 2:
                    xp = 121;
                    break;
                case 3:
                    xp = 143;
                    break;
                case 4:
                    xp = 165;
                    break;
            }

            if (levelRange > 4)
                xp = 160 + 20*(levelRange - 4);

            return Randomizer.Next(xp*3/4, xp*5/4);
        }

        #endregion [rgn]
    }
}