/// <summary>
/// Uses the skill.
/// </summary>
/// <param name="attacker"></param>
/// <param name="skill"></param>
/// <param name="targetEntityId"></param>
/// <returns></returns>
public CombatSkillResult Use(Creature attacker, Skill skill, long targetEntityId)
{
// Get target
var target = attacker.Region.GetCreature(targetEntityId);
if (target == null)
return CombatSkillResult.InvalidTarget;
if (target.IsNotReadyToBeHit)
return CombatSkillResult.Okay;
var targetPos = target.GetPosition();
var attackerPos = attacker.GetPosition();
// Check range
//if (!attackerPos.InRange(targetPos, attacker.RightHand.OptionInfo.EffectiveRange + 100))
// return CombatSkillResult.OutOfRange;
// Actions
var cap = new CombatActionPack(attacker, skill.Info.Id);
var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, skill.Info.Id, targetEntityId);
aAction.Set(AttackerOptions.Result);
aAction.Stun = AttackerStun;
cap.Add(aAction);
// Hit by chance
var chance = attacker.AimMeter.GetAimChance(target);
var rnd = RandomProvider.Get();
if (rnd.NextDouble() * 100 < chance)
{
var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
tAction.Set(TargetOptions.Result);
tAction.Stun = TargetStun;
cap.Add(tAction);
// Damage
var damage = attacker.GetRndRangedDamage();
// More damage with fire arrow
if (attacker.Temp.FireArrow)
damage *= FireBonus;
// Critical Hit
var critShieldReduction = (target.LeftHand != null ? target.LeftHand.Data.DefenseBonusCrit : 0);
var critChance = attacker.GetRightCritChance(target.Protection + critShieldReduction);
CriticalHit.Handle(attacker, critChance, ref damage, tAction);
var maxDamage = damage; //Damage without Defense and Protection
// Subtract target def/prot
SkillHelper.HandleDefenseProtection(target, ref damage);
// Defense
Defense.Handle(aAction, tAction, ref damage, true);
// Mana Shield
ManaShield.Handle(target, ref damage, tAction, maxDamage);
// Deal with it!
if (damage > 0)
target.TakeDamage(tAction.Damage = damage, attacker);
// Aggro
target.Aggro(attacker);
// Death/Knockback
if (target.IsDead)
{
tAction.Set(TargetOptions.FinishingKnockDown);
attacker.Shove(target, KnockBackDistance);
}
else
{
// Insta-recover in knock down
// TODO: Tied to stability?
if (target.IsKnockedDown)
{
tAction.Stun = 0;
}
// Knock down if hit repeatedly
else if (target.Stability < 30)
{
tAction.Set(TargetOptions.KnockDown);
}
// Normal stability reduction
else
{
target.Stability -= StabilityReduction;
if (target.IsUnstable)
{
tAction.Set(TargetOptions.KnockBack);
attacker.Shove(target, KnockBackDistance);
}
}
}
}
// Skill training
if (skill.Info.Rank == SkillRank.Novice || skill.Info.Rank == SkillRank.RF)
skill.Train(1); // Try ranged attack.
// Reduce arrows
if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows)
attacker.Inventory.Decrement(attacker.Magazine);
// Disable fire arrow effect
if (attacker.Temp.FireArrow)
Send.Effect(attacker, Effect.FireArrow, false);
// "Cancels" the skill
// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
Send.SkillUse(attacker, skill.Info.Id, 800, 1);
cap.Handle();
return CombatSkillResult.Okay;
}