#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]
}
}