diff --git a/Projects/UOContent/Spells/Initializer.cs b/Projects/UOContent/Spells/Initializer.cs index 418e81da7..59a3c1177 100644 --- a/Projects/UOContent/Spells/Initializer.cs +++ b/Projects/UOContent/Spells/Initializer.cs @@ -192,7 +192,7 @@ namespace Server.Spells // Register(685, typeof(SpellTriggerSpell)); // Register(686, typeof(MassSleepSpell)); // Register(687, typeof(CleansingWindsSpell)); - // Register(688, typeof(BombardSpell)); + Register(688, typeof(BombardSpell)); Register(689, typeof(SpellPlagueSpell)); Register(690, typeof(HailStormSpell)); Register(691, typeof(NetherCycloneSpell)); diff --git a/Projects/UOContent/Spells/Mysticism/AnimatedWeaponSpell.cs b/Projects/UOContent/Spells/Mysticism/AnimatedWeaponSpell.cs index ec6876850..b54b9479b 100644 --- a/Projects/UOContent/Spells/Mysticism/AnimatedWeaponSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/AnimatedWeaponSpell.cs @@ -40,7 +40,7 @@ namespace Server.Spells.Mysticism } else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) { - var level = (int)((GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 2.0); + var level = (int)((GetBaseSkill(Caster) + GetDamageSkill(Caster)) / 2.0); var duration = TimeSpan.FromSeconds(10 + level); diff --git a/Projects/UOContent/Spells/Mysticism/BombardSpell.cs b/Projects/UOContent/Spells/Mysticism/BombardSpell.cs new file mode 100644 index 000000000..54e44f30f --- /dev/null +++ b/Projects/UOContent/Spells/Mysticism/BombardSpell.cs @@ -0,0 +1,89 @@ +using Server.Targeting; +using System; + +namespace Server.Spells.Mysticism +{ + public class BombardSpell : MysticSpell, ISpellTargetingMobile + { + private static readonly SpellInfo _info = new( + "Bombard", "Corp Por Ylem", + 230, + 9022, + Reagent.Bloodmoss, + Reagent.Garlic, + Reagent.SulfurousAsh, + Reagent.DragonsBlood + ); + + public BombardSpell(Mobile caster, Item scroll) : base(caster, scroll, _info) + { + } + + public override SpellCircle Circle => SpellCircle.Sixth; + public override bool DelayedDamage => true; + + public override Type[] DelayedDamageSpellFamilyStacking => AOSNoDelayedDamageStackingSelf; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful); + } + + public void Target(Mobile m) + { + if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + if (HasDelayedDamageContext(m)) + { + DoHurtFizzle(); + return; + } + + var source = Caster; + + if (SpellHelper.CheckReflect(6, ref source, ref m)) + { + Timer.StartTimer(TimeSpan.FromSeconds(0.5), () => + { + source.MovingEffect(m, 0x1363, 12, 1, false, true, 0, 0); + source.PlaySound(0x64B); + }); + } + + Caster.MovingEffect(m, 0x1363, 12, 1, false, true, 0, 0); + Caster.PlaySound(0x64B); + + SpellHelper.Damage(this, m, GetNewAosDamage(40, 1, 5, m), 100, 0, 0, 0, 0); + + Timer.StartTimer(TimeSpan.FromSeconds(1.2), () => + { + if (CheckResisted(m)) + { + return; + } + + var damageSkill = GetDamageSkill(Caster); + var resist = GetResistSkill(m); + + int secs = Math.Max(0, (int)(damageSkill / 10 - resist / 10)); + + if (secs > 0) + { + m.Paralyze(TimeSpan.FromSeconds(secs)); + } + + // Up to 12% chance by checking mysticism + imbuing/focus against resist + var knockBackChance = (GetBaseSkill(Caster) + damageSkill - resist) / 20; + if (knockBackChance > 0 && Utility.RandomDouble() < knockBackChance) + { + m.Move(Caster.GetDirectionTo(m)); + } + }); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Mysticism/EagleStrikeSpell.cs b/Projects/UOContent/Spells/Mysticism/EagleStrikeSpell.cs index f60095868..c8cfd430d 100644 --- a/Projects/UOContent/Spells/Mysticism/EagleStrikeSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/EagleStrikeSpell.cs @@ -24,20 +24,27 @@ namespace Server.Spells.Mysticism public void Target(Mobile m) { - if (m == null) - { - return; - } - if (CheckHSequence(m)) { - /* Conjures a magical eagle that assaults the Target with - * its talons, dealing energy damage. - */ - SpellHelper.Turn(Caster, m); - SpellHelper.CheckReflect(2, Caster, ref m); + if (Core.SA && HasDelayedDamageContext(m)) + { + DoHurtFizzle(); + return; + } + + var source = Caster; + + if (SpellHelper.CheckReflect(2, ref source, ref m)) + { + Timer.StartTimer(TimeSpan.FromSeconds(0.5), () => + { + /* Conjures a magical eagle that assaults the Target with its talons, dealing energy damage. */ + source.MovingEffect(m, 0x407A, 8, 1, false, true, 0, 0); + source.PlaySound(0x2EE); + }); + } Caster.MovingParticles(m, 0x407A, 7, 0, false, true, 0, 0, 0xBBE, 0xFA6, 0xFFFF, 0); Caster.PlaySound(0x2EE); diff --git a/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs b/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs index 57c81358c..e5d061ac7 100644 --- a/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using Server.Collections; namespace Server.Spells.Mysticism { @@ -24,62 +24,49 @@ namespace Server.Spells.Mysticism public void Target(IPoint3D p) { - if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + var loc = (p as Item)?.GetWorldLocation() ?? new Point3D(p); + + if (SpellHelper.CheckTown(loc, Caster) && CheckSequence()) { - /* Summons a storm of hailstones that strikes all Targets - * within a radius around the Target's Location, dealing - * cold damage. + /* Summons a storm of hailstones that strikes all Targets within a radius around the Target's Location, + * dealing cold damage. */ SpellHelper.Turn(Caster, p); - if (p is Item item) - { - p = item.GetWorldLocation(); - } - - var targets = new List(); - var map = Caster.Map; - var pvp = false; - if (map != null) { - var loc = new Point3D(p); + using var pool = PooledRefQueue.Create(); + var pvp = false; PlayEffect(loc, Caster.Map); foreach (var m in map.GetMobilesInRange(loc, 2)) { - if (m == Caster) + if (m == Caster || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanBeHarmful(m, false) + || !Caster.CanSee(m) || !Caster.InLOS(m)) { continue; } - if (SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && Caster.CanSee(m)) + pool.Enqueue(m); + + if (m.Player) { - if (!Caster.InLOS(m)) - { - continue; - } - - targets.Add(m); - - if (m.Player) - { - pvp = true; - } + pvp = true; } } - } - double damage = GetNewAosDamage(51, 1, 5, pvp); + double damage = GetNewAosDamage(51, 1, 5, pvp); - foreach (var m in targets) - { - Caster.DoHarmful(m); - SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); + while (pool.Count > 0) + { + var m = pool.Dequeue(); + Caster.DoHarmful(m); + SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); + } } } @@ -104,7 +91,9 @@ namespace Server.Spells.Mysticism private static void PlaySingleEffect(Point3D p, Map map, int a, int b, int c, int d) { - int x = p.X, y = p.Y, z = p.Z + 18; + var x = p.X; + var y = p.Y; + var z = p.Z + 18; SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + c, z)); SendEffectPacket(p, map, new Point3D(x + b, y + c, z), new Point3D(x + b, y + c, z)); diff --git a/Projects/UOContent/Spells/Mysticism/MysticSpell.cs b/Projects/UOContent/Spells/Mysticism/MysticSpell.cs index 8e126e22b..75317ea2f 100644 --- a/Projects/UOContent/Spells/Mysticism/MysticSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/MysticSpell.cs @@ -97,8 +97,6 @@ namespace Server.Spells.Mysticism public static double GetBaseSkill(Mobile m) => m.Skills.Mysticism.Value; - public static double GetBoostSkill(Mobile m) => Math.Max(m.Skills.Imbuing.Value, m.Skills.Focus.Value); - public virtual bool CheckResisted(Mobile target) { var n = GetResistPercent(target); diff --git a/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs b/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs index 536315e53..96802faef 100644 --- a/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using Server.Collections; namespace Server.Spells.Mysticism { @@ -23,7 +23,9 @@ namespace Server.Spells.Mysticism public void Target(IPoint3D p) { - if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + var loc = (p as Item)?.GetWorldLocation() ?? new Point3D(p); + + if (SpellHelper.CheckTown(loc, Caster) && CheckSequence()) { /* Summons a gale of lethal winds that strikes all Targets within a radius around * the Target's Location, dealing chaos damage. In addition to inflicting damage, @@ -35,20 +37,12 @@ namespace Server.Spells.Mysticism SpellHelper.Turn(Caster, p); - if (p is Item item) - { - p = item.GetWorldLocation(); - } - - var targets = new List(); - var map = Caster.Map; - var pvp = false; - if (map != null) { - var loc = new Point3D(p); + using var pool = PooledRefQueue.Create(); + var pvp = false; PlayEffect(loc, Caster.Map); @@ -66,7 +60,7 @@ namespace Server.Spells.Mysticism continue; } - targets.Add(m); + pool.Enqueue(m); if (m.Player) { @@ -74,20 +68,21 @@ namespace Server.Spells.Mysticism } } } - } - var damage = GetNewAosDamage(51, 1, 5, pvp); - var reduction = (GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 1200.0; + var damage = GetNewAosDamage(51, 1, 5, pvp); + var reduction = (GetBaseSkill(Caster) + GetDamageSkill(Caster)) / 1200.0; - foreach (var m in targets) - { - Caster.DoHarmful(m); - SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 0, 100); + while (pool.Count > 0) + { + var m = pool.Dequeue(); + Caster.DoHarmful(m); + SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 0, 100); - var resistedReduction = reduction - m.Skills.MagicResist.Value / 800.0; + var resistedReduction = reduction - m.Skills.MagicResist.Value / 800.0; - m.Stam -= (int)(m.StamMax * resistedReduction); - m.Mana -= (int)(m.ManaMax * resistedReduction); + m.Stam -= (int)(m.StamMax * resistedReduction); + m.Mana -= (int)(m.ManaMax * resistedReduction); + } } } diff --git a/Projects/UOContent/Spells/Mysticism/StoneFormSpell.cs b/Projects/UOContent/Spells/Mysticism/StoneFormSpell.cs index 59507600e..f6769b375 100644 --- a/Projects/UOContent/Spells/Mysticism/StoneFormSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/StoneFormSpell.cs @@ -97,7 +97,7 @@ namespace Server.Spells.Mysticism Caster.BodyMod = 0x2C1; Caster.HueMod = 0; - var offset = (int)((GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 24.0); + var offset = (int)((GetBaseSkill(Caster) + GetDamageSkill(Caster)) / 24.0); ResistanceMod[] mods = { @@ -134,9 +134,9 @@ namespace Server.Spells.Mysticism FinishSequence(); } - public static int GetDIBonus(Mobile m) => (int)((GetBaseSkill(m) + GetBoostSkill(m)) / 12.0); + public static int GetDIBonus(Mobile m) => (int)((GetBaseSkill(m) + GetDamageSkill(m)) / 12.0); - public static int GetResistCapBonus(Mobile m) => (int)((GetBaseSkill(m) + GetBoostSkill(m)) / 48.0); + public static int GetResistCapBonus(Mobile m) => (int)((GetBaseSkill(m) + GetDamageSkill(m)) / 48.0); public static void RemoveEffects(Mobile m) {