using System; using System.Collections.Generic; using Server.Items; namespace Server.Spells.Ninjitsu; public class KiAttack : NinjaMove { private static readonly Dictionary _table = new(); public override int BaseMana => 25; public override double RequiredSkill => 80.0; // Your Ki Attack must be complete within 2 seconds for the damage bonus! public override TextDefinition AbilityMessage { get; } = 1063099; public override void OnUse(Mobile from) { if (!Validate(from)) { return; } var t = new KiAttackTimer(from); _table[from] = t; t.Start(); } public override bool Validate(Mobile from) { if (from.Hidden && from.AllowedStealthSteps > 0) { from.SendLocalizedMessage(1063127); // You cannot use this ability while in stealth mode. return false; } if (Core.ML && from.Weapon is BaseRanged) { from.SendLocalizedMessage(1075858); // You can only use this with melee attacks. return false; } return base.Validate(from); } public override double GetDamageScalar(Mobile attacker, Mobile defender) { if (attacker.Hidden) { return 1.0; } /* * Pub40 changed pvp damage max to 55% */ return 1.0 + GetBonus(attacker) / (Core.ML && attacker.Player && defender.Player ? 40 : 10); } public override void OnHit(Mobile attacker, Mobile defender, int damage) { if (!Validate(attacker) || !CheckMana(attacker, true)) { return; } ClearCurrentMove(attacker); if (GetBonus(attacker) == 0.0) { attacker.SendLocalizedMessage(1063101); // You were too close to your target to cause any additional damage. } else { attacker.FixedParticles(0x37BE, 1, 5, 0x26BD, 0x0, 0x1, EffectLayer.Waist); attacker.PlaySound(0x510); // Your quick flight to your target causes extra damage as you strike! attacker.SendLocalizedMessage(1063100); defender.FixedParticles(0x37BE, 1, 5, 0x26BD, 0, 0x1, EffectLayer.Waist); CheckGain(attacker); } } public override void OnClearMove(Mobile from) { if (_table.Remove(from, out var t)) { t.Stop(); } } public static double GetBonus(Mobile from) { if (!_table.TryGetValue(from, out var t)) { return 0; } var xDelta = t._location.X - from.X; var yDelta = t._location.Y - from.Y; return Math.Min(Math.Sqrt(xDelta * xDelta + yDelta * yDelta), 20.0); } private class KiAttackTimer : Timer { public Mobile _mobile; public Point3D _location; public KiAttackTimer(Mobile m) : base(TimeSpan.FromSeconds(2.0)) { _mobile = m; _location = m.Location; } protected override void OnTick() { ClearCurrentMove(_mobile); _mobile.SendLocalizedMessage(1063102); // You failed to complete your Ki Attack in time. _table.Remove(_mobile); } } }