diff --git a/Projects/UOContent/Misc/AOS.cs b/Projects/UOContent/Misc/AOS.cs index f9a61da7b8..7b920f44f0 100644 --- a/Projects/UOContent/Misc/AOS.cs +++ b/Projects/UOContent/Misc/AOS.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using ModernUO.Serialization; using Server.Items; using Server.Mobiles; using Server.Spells; using Server.Spells.Fifth; +using Server.Spells.Mysticism; using Server.Spells.Ninjitsu; using Server.Spells.Seventh; @@ -215,9 +217,14 @@ public static int Damage( } m.Damage(totalDamage, from); + + // TODO: Move all of this somewhere else + SleepSpell.EndSleep(m); + return totalDamage; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Fix(ref int val) { if (val < 0) @@ -555,6 +562,35 @@ public static int GetValue(Mobile m, AosAttribute attribute) } } + if (attribute == AosAttribute.CastSpeed) + { + if (SleepSpell.UnderEffect(m)) + { + value -= 2; + } + } + else if (attribute == AosAttribute.CastRecovery) + { + if (SleepSpell.UnderEffect(m)) + { + value -= 3; + } + } + else if (attribute == AosAttribute.WeaponSpeed) + { + if (SleepSpell.UnderEffect(m)) + { + value -= 45; + } + } + else if (attribute == AosAttribute.AttackChance) + { + if (SleepSpell.UnderEffect(m)) + { + value -= 45; + } + } + return value; } diff --git a/Projects/UOContent/Spells/Base/SpellHelper.cs b/Projects/UOContent/Spells/Base/SpellHelper.cs index d04a16c100..ab585fdd2e 100644 --- a/Projects/UOContent/Spells/Base/SpellHelper.cs +++ b/Projects/UOContent/Spells/Base/SpellHelper.cs @@ -1019,6 +1019,8 @@ public static void Damage( DoLeech(damageGiven, from, target); } + Mysticism.SpellPlagueSpell.OnMobileDamaged(target); + WeightOverloading.DFA = DFAlgorithm.Standard; } else @@ -1172,6 +1174,8 @@ protected override void OnTick() bcTarg.OnDamagedBySpell(m_From); } + Mysticism.SpellPlagueSpell.OnMobileDamaged(m_Target); + m_Spell?.RemoveDelayedDamageContext(m_Target); } } diff --git a/Projects/UOContent/Spells/Initializer.cs b/Projects/UOContent/Spells/Initializer.cs index a7043036a1..2fb319c18b 100644 --- a/Projects/UOContent/Spells/Initializer.cs +++ b/Projects/UOContent/Spells/Initializer.cs @@ -185,12 +185,12 @@ public static void Configure() // Register(678, typeof(HealingStoneSpell)); // Register(679, typeof(PurgeMagicSpell)); // Register(680, typeof(EnchantSpell)); - // Register(681, typeof(SleepSpell)); + Register(681, typeof(SleepSpell)); Register(682, typeof(EagleStrikeSpell)); Register(683, typeof(AnimatedWeaponSpell)); Register(684, typeof(StoneFormSpell)); // Register(685, typeof(SpellTriggerSpell)); - // Register(686, typeof(MassSleepSpell)); + Register(686, typeof(MassSleepSpell)); Register(687, typeof(CleansingWindsSpell)); Register(688, typeof(BombardSpell)); Register(689, typeof(SpellPlagueSpell)); diff --git a/Projects/UOContent/Spells/Mysticism/CleansingWindsSpell.cs b/Projects/UOContent/Spells/Mysticism/CleansingWindsSpell.cs index ea380de8ba..87188824a6 100644 --- a/Projects/UOContent/Spells/Mysticism/CleansingWindsSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/CleansingWindsSpell.cs @@ -145,10 +145,10 @@ public static int RemoveCurses(Mobile m) { var curseLevel = 0; - // if (SleepSpell.EndSleep(m)) - // { - // curseLevel += 2; - // } + if (SleepSpell.EndSleep(m)) + { + curseLevel += 2; + } if (EvilOmenSpell.EndEffect(m)) { diff --git a/Projects/UOContent/Spells/Mysticism/EnchantSpell.cs b/Projects/UOContent/Spells/Mysticism/EnchantSpell.cs new file mode 100644 index 0000000000..2582b06c33 --- /dev/null +++ b/Projects/UOContent/Spells/Mysticism/EnchantSpell.cs @@ -0,0 +1,276 @@ +using Server.Gumps; +using Server.Items; +using Server.Spells.Spellweaving; +using System; +using System.Collections.Generic; +using Server.Network; + +namespace Server.Spells.Mysticism +{ + public class EnchantSpell : MysticSpell + { + public override SpellCircle Circle => SpellCircle.Second; + public override bool ClearHandsOnCast => false; + + private static readonly Dictionary _table = new(); + + private BaseWeapon _weapon; + private AosWeaponAttribute _weaponAttribute; + + private static readonly SpellInfo _info = new( + "Enchant", "In Ort Ylem", + 230, + 9022, + Reagent.SpidersSilk, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh + ); + + public EnchantSpell(Mobile caster, Item scroll) : base(caster, scroll, _info) + { + } + + public EnchantSpell(Mobile caster, Item scroll, BaseWeapon weapon, AosWeaponAttribute attribute) + : base(caster, scroll, _info) + { + _weapon = weapon; + _weaponAttribute = attribute; + } + + public override bool CheckCast() + { + if (_weapon == null) + { + if (Caster.Weapon is not BaseWeapon wep) + { + Caster.SendLocalizedMessage(501078); // You must be holding a weapon. + } + else + { + Caster.CloseGump(); + _weapon = wep; + + EnchantSpellGump gump = new EnchantSpellGump(Caster, this); + Caster.SendGump(gump); + + Timer.StartTimer(TimeSpan.FromSeconds(30), () => + { + if (Caster.CloseGump()) + { + FinishSequence(); + } + }); + } + + return false; + } + + return CanEnchantWeapon(Caster, _weapon); + } + + private static bool CanEnchantWeapon(Mobile m, BaseWeapon weapon) + { + if (IsUnderSpellEffects(m, weapon)) + { + m.SendLocalizedMessage(501775); // This spell is already in effect. + } + else if (ImmolatingWeaponSpell.IsImmolating(weapon) || weapon.Consecrated) + { + m.SendLocalizedMessage(1080128); // You cannot use this ability while your weapon is enchanted. + } + else if (weapon.FocusWeilder != null) + { + m.SendLocalizedMessage(1080446); // You cannot enchant an item that is under the effects of the ninjitsu focus attack ability. + } + else if (weapon.WeaponAttributes.HitLightning > 0 || weapon.WeaponAttributes.HitFireball > 0 + || weapon.WeaponAttributes.HitHarm > 0 + || weapon.WeaponAttributes.HitMagicArrow > 0 + || weapon.WeaponAttributes.HitDispel > 0) + { + m.SendLocalizedMessage(1080127); // This weapon already has a hit spell effect and cannot be enchanted. + } + else + { + return true; + } + + return false; + } + + public override void OnCast() + { + if (CanEnchantWeapon(Caster, _weapon) && CheckSequence() && Caster.Weapon == _weapon) + { + Caster.PlaySound(0x64E); + Caster.FixedEffect(0x36CB, 1, 9, 1915, 0); + + int prim = (int)Caster.Skills[CastSkill].Value; + int sec = (int)Caster.Skills[DamageSkill].Value; + + int value = 60 * (prim + sec) / 240; + double duration = (prim + sec) / 2.0 + 30.0; + bool malus; + + Enhancement.SetValue(Caster, _weaponAttribute, value, "EnchantSpell"); + + if (prim >= 80 && sec >= 80 && _weapon.Attributes.SpellChanneling == 0) + { + Enhancement.SetValue(Caster, AosAttribute.SpellChanneling, 1, "EnchantSpell"); + Enhancement.SetValue(Caster, AosAttribute.CastSpeed, -1, "EnchantSpell"); + malus = true; + } + + _table[Caster] = new EnchantmentTimer(Caster, _weapon, _weaponAttribute, value, malus, duration); + + int loc = _weaponAttribute switch + { + AosWeaponAttribute.HitFireball => 1060420, + AosWeaponAttribute.HitHarm => 1060421, + AosWeaponAttribute.HitMagicArrow => 1060426, + AosWeaponAttribute.HitDispel => 1060417, + _ => 1060423 // AosWeaponAttribute.HitLightning + }; + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Enchant, 1080126, loc, TimeSpan.FromSeconds(duration), Caster, value.ToString())); + + _weapon.EnchantedWeilder = Caster; + _weapon.InvalidateProperties(); + } + + FinishSequence(); + } + + public static bool IsUnderSpellEffects(Mobile m, BaseWeapon weapon) => + _table != null && _table.TryGetValue(m, out var timer) && timer._weapon == weapon; + + public static AosWeaponAttribute BonusAttribute(Mobile m) => + _table != null && _table.TryGetValue(m, out var timer) ? timer._weaponAttribute : AosWeaponAttribute.HitColdArea; + + public static int BonusValue(Mobile m) => + _table != null && _table.TryGetValue(m, out var timer) ? timer._attributeValue : 0; + + public static bool CastingMalus(Mobile m, BaseWeapon weapon) => + _table != null && _table.TryGetValue(m, out var timer) && timer._castingMalus; + + public static bool RemoveEnchantment(Mobile caster, BaseWeapon weapon = null) + { + if (_table == null || !_table.Remove(caster, out var timer) || weapon != null && timer._weapon != weapon) + { + return false; + } + + timer.Stop(); + + caster.SendLocalizedMessage(1115273); // The enchantment on your weapon has expired. + caster.PlaySound(0x1E6); + + Enhancement.RemoveMobile(caster); + + weapon?.InvalidateProperties(); + BuffInfo.RemoveBuff(caster, BuffIcon.Enchant); + + return true; + } + + public static void OnWeaponRemoved(BaseWeapon wep, Mobile from) + { + if (IsUnderSpellEffects(from, wep)) + { + RemoveEnchantment(from); + } + + wep.EnchantedWeilder = null; + } + + private class EnchantmentTimer : Timer + { + private readonly Mobile _owner; + public readonly BaseWeapon _weapon; + public readonly bool _castingMalus; + public readonly AosWeaponAttribute _weaponAttribute; + public readonly int _attributeValue; + + public EnchantmentTimer(Mobile owner, BaseWeapon wep, AosWeaponAttribute attribute, int value, bool malus, double duration) + : base(TimeSpan.FromSeconds(duration)) + { + _owner = owner; + _weapon = wep; + _weaponAttribute = attribute; + _attributeValue = value; + _castingMalus = malus; + + Start(); + } + + protected override void OnTick() + { + if (_weapon != null) + { + _weapon.EnchantedWeilder = null; + } + + RemoveEnchantment(_owner); + } + } + + public class EnchantSpellGump : Gump + { + private readonly Mobile _caster; + private readonly EnchantSpell _spell; + + public EnchantSpellGump(Mobile caster, EnchantSpell spell) : base(20, 20) + { + _spell = spell; + _caster = caster; + + AddBackground(0, 0, 260, 187, 3600); + AddAlphaRegion(5, 15, 242, 170); + + AddImageTiled(220, 15, 30, 162, 10464); + + AddItem(0, 3, 6882); + AddItem(-8, 170, 6880); + AddItem(185, 3, 6883); + AddItem(192, 170, 6881); + + AddHtmlLocalized(20, 22, 150, 16, 1080133, 0x07FF); // Select Enchant + + AddButton(20, 50, 9702, 9703, 1); + AddHtmlLocalized(45, 50, 200, 16, 1079705, 0x07FF); // Hit Lighting + + AddButton(20, 75, 9702, 9703, 2); + AddHtmlLocalized(45, 75, 200, 16, 1079703, 0x07FF); // Hit Fireball + + AddButton(20, 100, 9702, 9703, 3); + AddHtmlLocalized(45, 100, 200, 16, 1079704, 0x07FF); // Hit Harm + + AddButton(20, 125, 9702, 9703, 4); + AddHtmlLocalized(45, 125, 200, 16, 1079706, 0x07FF); // Hit Magic Arrow + + AddButton(20, 150, 9702, 9703, 5); + AddHtmlLocalized(45, 150, 200, 16, 1079702, 0x07FF); // Hit Dispel + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID is < 1 or > 5) + { + _caster.SendLocalizedMessage(1080132); // You decide not to enchant your weapon. + return; + } + + AosWeaponAttribute attr = info.ButtonID switch + { + 2 => AosWeaponAttribute.HitFireball, + 3 => AosWeaponAttribute.HitHarm, + 4 => AosWeaponAttribute.HitMagicArrow, + 5 => AosWeaponAttribute.HitDispel, + _ => AosWeaponAttribute.HitLightning + }; + + _spell._weaponAttribute = attr; + _spell.Cast(); + } + } + } +} diff --git a/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs b/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs index e5d061ac74..fb91c635f0 100644 --- a/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs @@ -1,4 +1,4 @@ -using Server.Collections; +using Server.Collections; namespace Server.Spells.Mysticism { diff --git a/Projects/UOContent/Spells/Mysticism/MassSleepSpell.cs b/Projects/UOContent/Spells/Mysticism/MassSleepSpell.cs new file mode 100644 index 0000000000..9928b25fca --- /dev/null +++ b/Projects/UOContent/Spells/Mysticism/MassSleepSpell.cs @@ -0,0 +1,58 @@ +using System; + +namespace Server.Spells.Mysticism +{ + public class MassSleepSpell : MysticSpell, ISpellTargetingPoint3D + { + public override SpellCircle Circle => SpellCircle.Fifth; + + private static readonly SpellInfo _info = new( + "Mass Sleep", "Vas Zu", + 230, + 9022, + Reagent.Ginseng, + Reagent.Nightshade, + Reagent.SpidersSilk + ); + + public MassSleepSpell(Mobile caster, Item scroll) : base(caster, scroll, _info) + { + } + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, range: 10); + } + + public void Target(IPoint3D p) + { + if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + Map map = Caster.Map; + if (map != null) + { + double duration = (Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 20 + 3; + + var eable = map.GetMobilesInRange(new Point3D(p), 3); + + foreach (var m in eable) + { + if (m == Caster || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanSee(m) || + !Caster.CanBeHarmful(m, false)) + { + continue; + } + + SleepSpell.DoSleep(Caster, m, TimeSpan.FromSeconds(duration - GetResistSkill(m) / 10)); + } + + eable.Free(); + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs b/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs index 96802faef6..8030747fe9 100644 --- a/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs @@ -1,4 +1,4 @@ -using Server.Collections; +using Server.Collections; namespace Server.Spells.Mysticism { diff --git a/Projects/UOContent/Spells/Mysticism/SleepSpell.cs b/Projects/UOContent/Spells/Mysticism/SleepSpell.cs new file mode 100644 index 0000000000..38bc2b45f7 --- /dev/null +++ b/Projects/UOContent/Spells/Mysticism/SleepSpell.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Mysticism +{ + public class SleepSpell : MysticSpell, ISpellTargetingMobile + { + public override SpellCircle Circle => SpellCircle.Third; + + private static readonly SpellInfo _info = new( + "Sleep", "In Zu", + 230, + 9022, + Reagent.Nightshade, + Reagent.SpidersSilk, + Reagent.BlackPearl + ); + + private static readonly Dictionary _table = new(); + private static readonly HashSet _immunity = new(); + + public SleepSpell(Mobile caster, Item scroll) : base(caster, scroll, _info) + { + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful); + } + + public void Target(Mobile m) + { + if (m.Paralyzed) + { + Caster.SendLocalizedMessage(1080134); // Your target is already immobilized and cannot be slept. + } + else if (_immunity.Contains(m)) + { + Caster.SendLocalizedMessage(1080135); // Your target cannot be put to sleep. + } + else if (CheckHSequence(m)) + { + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + var skill = (Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 20; + double duration = skill + 2 - GetResistSkill(m) / 10; + + // TODO: StoneForm immune + if (duration <= 0 /*|| StoneFormSpell.CheckImmunity(m)*/) + { + Caster.SendLocalizedMessage(1080136); // Your target resists sleep. + m.SendLocalizedMessage(1080137); // You resist sleep. + } + else + { + DoSleep(Caster, m, TimeSpan.FromSeconds(duration)); + } + } + + FinishSequence(); + } + + public static void DoSleep(Mobile caster, Mobile m, TimeSpan duration) + { + m.Combatant = null; + m.NetState.SendSpeedControl(SpeedControlSetting.Walk); + + if (_table.TryGetValue(m, out var timer)) + { + timer.Stop(); + } + + timer = new SleepTimer(m, (long)duration.TotalMilliseconds); + timer.Start(); + _table[m] = timer; + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Sleep, 1080139, 1080140, duration, m)); + m.Delta(MobileDelta.WeaponDamage); + caster.DoHarmful(m); + } + + public static bool UnderEffect(Mobile from) => _table.ContainsKey(from); + + public static bool EndSleep(Mobile m) + { + if (_table.Remove(m, out var timer)) + { + m.NetState.SendSpeedControl(SpeedControlSetting.Disable); + + timer.Stop(); + + BuffInfo.RemoveBuff(m, BuffIcon.Sleep); + + _immunity.Add(m); + Timer.StartTimer(TimeSpan.FromSeconds(m.Skills[SkillName.MagicResist].Value / 10), () => _immunity.Remove(m)); + + m.Delta(MobileDelta.WeaponDamage); + return true; + } + + return false; + } + + private class SleepTimer : Timer + { + private readonly Mobile _mobile; + private readonly long _end; + + public SleepTimer(Mobile target, long time) : base(TimeSpan.Zero, TimeSpan.FromSeconds(0.5)) + { + _end = Core.TickCount + time; + _mobile = target; + } + + protected override void OnTick() + { + if (Core.TickCount >= _end) + { + EndSleep(_mobile); + Stop(); + } + else + { + Effects.SendTargetParticles(_mobile, 0x3779, 1, 32, 0x13BA, EffectLayer.Head); + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Mysticism/SpellPlagueSpell.cs b/Projects/UOContent/Spells/Mysticism/SpellPlagueSpell.cs index 07fd595981..9b7b032995 100644 --- a/Projects/UOContent/Spells/Mysticism/SpellPlagueSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/SpellPlagueSpell.cs @@ -4,7 +4,7 @@ namespace Server.Spells.Mysticism { - public class SpellPlagueSpell : MysticSpell + public class SpellPlagueSpell : MysticSpell, ISpellTargetingMobile { private static readonly SpellInfo _info = new( "Spell Plague", @@ -32,7 +32,7 @@ public static void Initialize() public override void OnCast() { - Caster.Target = new InternalTarget(this); + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful); } public void Target(Mobile targeted) @@ -76,11 +76,12 @@ public void Target(Mobile targeted) public static bool UnderEffect(Mobile m) => _table.ContainsKey(m); + public static bool RemoveEffect(Mobile m) { - if (_table.Remove(m, out var context)) + if (_table.Remove(m, out var timer)) { - context.Stop(); + timer.Stop(); BuffInfo.RemoveBuff(m, BuffIcon.SpellPlague); return true; } @@ -88,9 +89,9 @@ public static bool RemoveEffect(Mobile m) return false; } - public static void CheckPlague(Mobile m) + public static void OnMobileDamaged(Mobile m) { - if (_table.TryGetValue(m, out var context)) + if (m != null && _table.TryGetValue(m, out var context)) { context.OnDamage(); } @@ -101,7 +102,7 @@ private static void OnPlayerDeath(Mobile m) RemoveEffect(m); } - protected void VisualEffect(Mobile to) + private static void VisualEffect(Mobile to) { to.PlaySound(0x658); @@ -111,109 +112,96 @@ protected void VisualEffect(Mobile to) private class SpellPlagueTimer : Timer { - private readonly SpellPlagueSpell m_Owner; - private readonly Mobile m_Target; - private int m_Explosions; - private DateTime m_LastExploded; - private SpellPlagueTimer m_Next; + private readonly SpellPlagueSpell _owner; + private readonly Mobile _target; + private int _explosions; + private DateTime _nextExplosion; + private SpellPlagueTimer _next; public SpellPlagueTimer(SpellPlagueSpell owner, Mobile target) : base(TimeSpan.FromSeconds(8.0)) { - m_Owner = owner; - m_Target = target; + _owner = owner; + _target = target; } public void SetNext(SpellPlagueTimer timer) { - if (m_Next == null) + if (_next == null) { - m_Next = timer; + _next = timer; } else { - m_Next.SetNext(timer); + _next.SetNext(timer); } } public void StartPlague() { BuffInfo.AddBuff( - m_Target, - new BuffInfo(BuffIcon.SpellPlague, 1031690, 1080167, TimeSpan.FromSeconds(8.5), m_Target) + _target, + new BuffInfo(BuffIcon.SpellPlague, 1031690, 1080167, TimeSpan.FromSeconds(8.5), _target) ); + _nextExplosion = Core.Now + TimeSpan.FromSeconds(1); Start(); } public void OnDamage() { - if (DateTime.Now <= m_LastExploded + TimeSpan.FromSeconds(2.0)) + if (Core.Now < _nextExplosion) { return; } - var exploChance = 90 - m_Explosions * 30; + var exploChance = 90 - _explosions * 30; - var resist = m_Target.Skills.MagicResist.Value; + var resist = _target.Skills.MagicResist.Fixed - 700; - if (resist >= 70) + if (resist > 0) { - exploChance -= (int)((resist - 70.0) * 3.0 / 10.0); + exploChance -= resist / 100 * 3; } if (exploChance > Utility.Random(100)) { - m_Owner.VisualEffect(m_Target); + VisualEffect(_target); - var damage = m_Owner.GetNewAosDamage(15 + m_Explosions * 3, 1, 5, m_Target); + // TODO: Add SDI bonus for Core.EJ (Publish 96) + var damage = _owner.GetNewAosDamage(15 + _explosions * 3, 1, 5, _target); - m_Explosions++; - m_LastExploded = DateTime.Now; + _explosions++; + _nextExplosion = Core.Now + TimeSpan.FromSeconds(1); - SpellHelper.Damage(m_Owner, m_Target, damage, 0, 0, 0, 0, 0, 100); + SpellHelper.Damage(_owner, _target, damage, 0, 0, 0, 0, 0, 100); - if (m_Explosions >= 3) + if (_explosions >= 3) { - EndPlague(); + Stop(); + DoNextPlague(); } } } - public void EndPlague() + private void DoNextPlague() { - if (m_Next != null) + if (_next != null) { - _table[m_Target] = m_Next; - m_Next.StartPlague(); + _table[_target] = _next; + _next.StartPlague(); } else { - _table.Remove(m_Target); - BuffInfo.RemoveBuff(m_Target, BuffIcon.SpellPlague); + _table.Remove(_target); + BuffInfo.RemoveBuff(_target, BuffIcon.SpellPlague); } Stop(); } - } - - private class InternalTarget : Target - { - private readonly SpellPlagueSpell _owner; - - public InternalTarget(SpellPlagueSpell owner) : base(12, false, TargetFlags.Harmful) => - _owner = owner; - - protected override void OnTarget(Mobile from, object o) - { - if (o is Mobile mobile) - { - _owner.Target(mobile); - } - } - protected override void OnTargetFinish(Mobile from) + protected override void OnTick() { - _owner.FinishSequence(); + DoNextPlague(); } } }