public CombatSkillResult Use(Creature attacker, Skill skill, long targetEntityId)
{
// Get target
var mainTarget = attacker.Region.GetCreature(targetEntityId);
if (mainTarget == null)
return CombatSkillResult.InvalidTarget;
// Actions
var cap = new CombatActionPack(attacker, skill.Info.Id);
var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, targetEntityId);
aAction.Set(AttackerOptions.Result);
aAction.Stun = AttackerStun;
cap.Add(aAction);
// Hit by chance
var chance = attacker.AimMeter.GetAimChance(mainTarget);
var rnd = RandomProvider.Get();
if (rnd.NextDouble() * 100 < chance)
{
aAction.Set(AttackerOptions.KnockBackHit2);
// Get targets, incl. splash.
// Splash happens from r5 onwards, but we'll base it on Var4,
// which is the splash damage and first != 0 on r5.
var targets = new HashSet<Creature>() { mainTarget };
if (skill.RankData.Var4 != 0)
{
var targetPosition = mainTarget.GetPosition();
var direction = attacker.GetPosition().GetDirection(targetPosition);
targets.UnionWith(attacker.GetTargetableCreaturesInCone(targetPosition, direction, skill.RankData.Var5, skill.RankData.Var6));
}
// Damage
var mainDamage = this.GetDamage(attacker, skill);
foreach (var target in targets)
{
var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
tAction.Set(TargetOptions.Result | TargetOptions.CleanHit);
tAction.Stun = TargetStun;
cap.Add(tAction);
// Damage
var damage = mainDamage;
// Elementals
damage *= attacker.CalculateElementalDamageMultiplier(target);
// More damage with fire arrow
// XXX: Does this affect the element?
if (attacker.Temp.FireArrow)
damage *= FireBonus;
// Splash modifier
if (target != mainTarget)
damage *= (skill.RankData.Var4 / 100f);
// Critical Hit
var critChance = attacker.GetRightCritChance(target.Protection);
CriticalHit.Handle(attacker, critChance, ref damage, tAction);
// Subtract target def/prot
SkillHelper.HandleDefenseProtection(target, ref damage);
// Conditions
SkillHelper.HandleConditions(attacker, target, ref damage);
// Mana Shield
ManaShield.Handle(target, ref damage, tAction);
// Natural Shield
// Ignore delay reduction, as knock downs shouldn't be shortened
NaturalShield.Handle(attacker, target, ref damage, tAction);
// Deal with it!
if (damage > 0)
{
target.TakeDamage(tAction.Damage = damage, attacker);
SkillHelper.HandleInjury(attacker, target, damage);
}
// Knock down
// If target is using a shield and defense, don't KD.
var targetLeftHand = target.LeftHand;
if (tAction.SkillId != SkillId.Defense || targetLeftHand == null || !targetLeftHand.IsShield)
{
// TODO: We have to calculate knockback distance right
attacker.Shove(target, KnockBackDistance);
tAction.Set(TargetOptions.KnockDownFinish);
}
// Aggro
if (target == mainTarget)
target.Aggro(attacker);
if (target.IsDead)
{
tAction.Set(TargetOptions.Finished);
if (target == mainTarget)
aAction.Set(AttackerOptions.KnockBackHit1);
}
}
}
else
{
aAction.Set(AttackerOptions.Missed);
}
// Update current weapon
SkillHelper.UpdateWeapon(attacker, mainTarget, ProficiencyGainType.Ranged, attacker.RightHand);
// Reduce arrows
if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
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;
}