using System; using System.Collections; using Server.Items; using Server.SkillHandlers; namespace Server.Spells.Ninjitsu { public class DeathStrike : NinjaMove { private static Hashtable m_Table = new Hashtable(); public override int BaseMana => 30; public override double RequiredSkill => 85.0; public override TextDefinition AbilityMessage => new TextDefinition(1063091); // You prepare to hit your opponent with a Death Strike. public override double GetDamageScalar(Mobile attacker, Mobile defender) { return 0.5; } public override void OnHit(Mobile attacker, Mobile defender, int damage) { if (!Validate(attacker) || !CheckMana(attacker, true)) return; ClearCurrentMove(attacker); double ninjitsu = attacker.Skills[SkillName.Ninjitsu].Value; double chance; bool isRanged = false; // should be defined onHit method, what if the player hit and remove the weapon before process? ;) if (attacker.Weapon is BaseRanged) isRanged = true; if (ninjitsu < 100) //This formula is an approximation from OSI data. TODO: find correct formula chance = 30 + (ninjitsu - 85) * 2.2; else chance = 63 + (ninjitsu - 100) * 1.1; if (chance / 100 < Utility.RandomDouble()) { attacker.SendLocalizedMessage(1070779); // You missed your opponent with a Death Strike. return; } DeathStrikeInfo info; int damageBonus = 0; if (m_Table.Contains(defender)) { defender.SendLocalizedMessage(1063092); // Your opponent lands another Death Strike! info = (DeathStrikeInfo)m_Table[defender]; if (info.m_Steps > 0) damageBonus = attacker.Skills[SkillName.Ninjitsu].Fixed / 150; info.m_Timer?.Stop(); m_Table.Remove(defender); } else { defender.SendLocalizedMessage(1063093); // You have been hit by a Death Strike! Move with caution! } attacker.SendLocalizedMessage(1063094); // You inflict a Death Strike upon your opponent! defender.FixedParticles(0x374A, 1, 17, 0x26BC, EffectLayer.Waist); attacker.PlaySound(attacker.Female ? 0x50D : 0x50E); info = new DeathStrikeInfo(defender, attacker, damageBonus, isRanged); info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerStateCallback(ProcessDeathStrike), defender); m_Table[defender] = info; CheckGain(attacker); } public static void AddStep(Mobile m) { DeathStrikeInfo info = m_Table[m] as DeathStrikeInfo; if (info == null) return; if (++info.m_Steps >= 5) ProcessDeathStrike(m); } private static void ProcessDeathStrike(object state) { Mobile defender = (Mobile)state; DeathStrikeInfo info = m_Table[defender] as DeathStrikeInfo; if (info == null) //sanity return; int maxDamage, damage = 0; double ninjitsu = info.m_Attacker.Skills[SkillName.Ninjitsu].Value; double stalkingBonus = Tracking.GetStalkingBonus(info.m_Attacker, info.m_Target); if (Core.ML) { double scalar = (info.m_Attacker.Skills[SkillName.Hiding].Value + info.m_Attacker.Skills[SkillName.Stealth].Value) / 220; if (scalar > 1) scalar = 1; // New formula doesn't apply DamageBonus anymore, caps must be, directly, 60/30. if (info.m_Steps >= 5) damage = (int)Math.Floor(Math.Min(60, ninjitsu / 3 * (0.3 + 0.7 * scalar) + stalkingBonus)); else damage = (int)Math.Floor(Math.Min(30, ninjitsu / 9 * (0.3 + 0.7 * scalar) + stalkingBonus)); if (info.m_isRanged) damage /= 2; } else { int divisor = info.m_Steps >= 5 ? 30 : 80; double baseDamage = ninjitsu / divisor * 10; maxDamage = info.m_Steps >= 5 ? 62 : 22; // DamageBonus is 8 at most. That brings the cap up to 70/30. damage = Math.Max(0, Math.Min(maxDamage, (int)(baseDamage + stalkingBonus))) + info.m_DamageBonus; } if (Core.ML) info.m_Target.Damage(damage, info.m_Attacker); // Damage is direct. else AOS.Damage(info.m_Target, info.m_Attacker, damage, true, 100, 0, 0, 0, 0, 0, 0, false, false, true); // Damage is physical. info.m_Timer?.Stop(); m_Table.Remove(info.m_Target); } private class DeathStrikeInfo { public Mobile m_Attacker; public int m_DamageBonus; public bool m_isRanged; public int m_Steps; public Mobile m_Target; public Timer m_Timer; public DeathStrikeInfo(Mobile target, Mobile attacker, int damageBonus, bool isRanged) { m_Target = target; m_Attacker = attacker; m_DamageBonus = damageBonus; m_isRanged = isRanged; } } } }