diff --git a/Projects/UOContent/Spells/Bushido/Confidence.cs b/Projects/UOContent/Spells/Bushido/Confidence.cs index e8eab62dc..46db09174 100644 --- a/Projects/UOContent/Spells/Bushido/Confidence.cs +++ b/Projects/UOContent/Spells/Bushido/Confidence.cs @@ -1,125 +1,139 @@ using System; using System.Collections.Generic; -namespace Server.Spells.Bushido +namespace Server.Spells.Bushido; + +public class Confidence : SamuraiSpell { - public class Confidence : SamuraiSpell + private static readonly SpellInfo _info = new( + "Confidence", + null, + -1, + 9002 + ); + + private static readonly Dictionary _table = new(); + private static readonly Dictionary _regenTable = new(); + + public Confidence(Mobile caster, Item scroll) : base(caster, scroll, _info) { - private static readonly SpellInfo _info = new( - "Confidence", - null, - -1, - 9002 + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); + + public override double RequiredSkill => 25.0; + public override int RequiredMana => 10; + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.FixedEffect(0x37C4, 10, 7, 4, 3); + } + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.SendLocalizedMessage(1063115); // You exude confidence. + + Caster.FixedParticles(0x375A, 1, 17, 0x7DA, 0x960, 0x3, EffectLayer.Waist); + Caster.PlaySound(0x51A); + + OnCastSuccessful(Caster); + + BeginConfidence(Caster); + BeginRegenerating(Caster); + } + + FinishSequence(); + } + + public static bool IsConfident(Mobile m) => _table.ContainsKey(m); + + public static void BeginConfidence(Mobile m) + { + StopConfidenceTimer(m); + + Timer.StartTimer(TimeSpan.FromSeconds(30.0), + () => + { + EndConfidence(m); + m.SendLocalizedMessage(1063116); // Your confidence wanes. + }, + out var timerToken ); - private static readonly Dictionary _table = new(); - private static readonly Dictionary m_RegenTable = new(); + _table[m] = timerToken; - public Confidence(Mobile caster, Item scroll) : base(caster, scroll, _info) + if (Core.HS) { + var bushido = m.Skills.Bushido.Fixed; + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Confidence, 1060596, 1153809, TimeSpan.FromSeconds(30), m, + $"{bushido / 120}\t{bushido / 50}\t{"100"}" + )); + } + else + { + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Confidence, 1060596, TimeSpan.FromSeconds(30), m)); + } + } + + private static bool StopConfidenceTimer(Mobile m) + { + if (_table.Remove(m, out var timerToken)) + { + timerToken.Cancel(); + return true; } - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); + return false; + } - public override double RequiredSkill => 25.0; - public override int RequiredMana => 10; + public static void EndConfidence(Mobile m) + { + StopRegenerating(m); - public override void OnBeginCast() + if (StopConfidenceTimer(m)) { - base.OnBeginCast(); - - Caster.FixedEffect(0x37C4, 10, 7, 4, 3); + OnEffectEnd(m, typeof(Confidence)); + BuffInfo.RemoveBuff(m, BuffIcon.Confidence); } + } - public override void OnCast() - { - if (CheckSequence()) + public static bool IsRegenerating(Mobile m) => _regenTable.ContainsKey(m); + + // TODO: Move this to a central regeneration so it actually works properly + public static void BeginRegenerating(Mobile m) + { + StopRegenerating(m); + + // RunUO says this goes for 5 seconds, but UOGuide says 4 seconds during normal regeneration + var hits = (15 + m.Skills.Bushido.Fixed * m.Skills.Bushido.Fixed / 57600) / 4; + + TimerExecutionToken timerToken = default; + Timer.StartTimer(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), 4, + () => { - Caster.SendLocalizedMessage(1063115); // You exude confidence. - - Caster.FixedParticles(0x375A, 1, 17, 0x7DA, 0x960, 0x3, EffectLayer.Waist); - Caster.PlaySound(0x51A); - - OnCastSuccessful(Caster); - - BeginConfidence(Caster); - BeginRegenerating(Caster); - } - - FinishSequence(); - } - - public static bool IsConfident(Mobile m) => _table.ContainsKey(m); - - public static void BeginConfidence(Mobile m) - { - StopConfidenceTimer(m); - - Timer.StartTimer(TimeSpan.FromSeconds(30.0), - () => + // ReSharper disable once AccessToModifiedClosure + if (timerToken.RemainingCount == 0) { - EndConfidence(m); - m.SendLocalizedMessage(1063116); // Your confidence wanes. - }, - out var timerToken - ); + StopRegenerating(m); + } - _table[m] = timerToken; - } + m.Hits += hits; + }, + out timerToken + ); - private static bool StopConfidenceTimer(Mobile m) + _regenTable[m] = timerToken; + } + + public static void StopRegenerating(Mobile m) + { + if (_regenTable.Remove(m, out var timer)) { - if (_table.Remove(m, out var timerToken)) - { - timerToken.Cancel(); - return true; - } - - return false; - } - - public static void EndConfidence(Mobile m) - { - if (StopConfidenceTimer(m)) - { - OnEffectEnd(m, typeof(Confidence)); - } - } - - public static bool IsRegenerating(Mobile m) => m_RegenTable.ContainsKey(m); - - // TODO: Move this to a central regeneration so it actually works properly - public static void BeginRegenerating(Mobile m) - { - StopRegenerating(m); - - // RunUO says this goes for 5 seconds, but UOGuide says 4 seconds during normal regeneration - var hits = (15 + m.Skills.Bushido.Fixed * m.Skills.Bushido.Fixed / 57600) / 4; - - TimerExecutionToken timerToken = default; - Timer.StartTimer(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), 4, - () => - { - // ReSharper disable once AccessToModifiedClosure - if (timerToken.RemainingCount == 0) - { - StopRegenerating(m); - } - - m.Hits += hits; - }, - out timerToken - ); - - m_RegenTable[m] = timerToken; - } - - public static void StopRegenerating(Mobile m) - { - if (m_RegenTable.Remove(m, out var timer)) - { - timer.Cancel(); - } + timer.Cancel(); } } } diff --git a/Projects/UOContent/Spells/Bushido/HonorableExecution.cs b/Projects/UOContent/Spells/Bushido/HonorableExecution.cs index f582ab56b..0cb0cd3e2 100644 --- a/Projects/UOContent/Spells/Bushido/HonorableExecution.cs +++ b/Projects/UOContent/Spells/Bushido/HonorableExecution.cs @@ -1,163 +1,196 @@ using System; using System.Collections.Generic; -namespace Server.Spells.Bushido +namespace Server.Spells.Bushido; + +public class HonorableExecution : SamuraiMove { - public class HonorableExecution : SamuraiMove + private static readonly Dictionary _table = new(); + + public override int BaseMana => 0; + public override double RequiredSkill => 25.0; + + // You better kill your enemy with your next hit or you'll be rather sorry... + public override TextDefinition AbilityMessage { get; } = 1063122; + + public override double GetDamageScalar(Mobile attacker, Mobile defender) => + // TODO: 20 -> Perfection + 1.0 + attacker.Skills.Bushido.Value * 20 / 10000; + + public override void OnHit(Mobile attacker, Mobile defender, int damage) { - private static readonly Dictionary _table = new(); - - public override int BaseMana => 0; - public override double RequiredSkill => 25.0; - - // You better kill your enemy with your next hit or you'll be rather sorry... - public override TextDefinition AbilityMessage { get; } = 1063122; - - public override double GetDamageScalar(Mobile attacker, Mobile defender) => - // TODO: 20 -> Perfection - 1.0 + attacker.Skills.Bushido.Value * 20 / 10000; - - public override void OnHit(Mobile attacker, Mobile defender, int damage) + if (!Validate(attacker) || !CheckMana(attacker, true)) { - if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + } + + ClearCurrentMove(attacker); + RemovePenalty(attacker); + + HonorableExecutionTimer timer; + + if (!defender.Alive) + { + attacker.FixedParticles(0x373A, 1, 17, 0x7E2, EffectLayer.Waist); + + var bushido = attacker.Skills.Bushido.Value; + bushido *= bushido; + + attacker.Hits += 20 + (int)(bushido / 480.0); + + var swingBonus = Math.Max(1, (int)(bushido / 720.0)); + + timer = new HonorableExecutionTimer(attacker, swingBonus); + + BuffInfo.AddBuff( + attacker, + new BuffInfo( + BuffIcon.HonorableExecution, + 1060595, + 1153807, + TimeSpan.FromSeconds(20.0), + attacker, + $"{swingBonus}" + ) + ); + } + else + { + var mods = new List + { + new ResistanceMod(ResistanceType.Physical, "PhysicalResistHonorableExecution", -40), + new ResistanceMod(ResistanceType.Fire, "FireResistHonorableExecution", -40), + new ResistanceMod(ResistanceType.Cold, "ColdResistHonorableExecution", -40), + new ResistanceMod(ResistanceType.Poison, "PoisonResistHonorableExecution", -40), + new ResistanceMod(ResistanceType.Energy, "EnergyResistHonorableExecution", -40) + }; + + var resSpells = attacker.Skills.MagicResist.Value; + + if (resSpells > 0.0) + { + mods.Add(new DefaultSkillMod(SkillName.MagicResist, "MagicResistHonorableExecution", true, -resSpells)); + } + + timer = new HonorableExecutionTimer(attacker, mods); + + if (Core.HS) + { + BuffInfo.AddBuff( + attacker, + new BuffInfo( + BuffIcon.HonorableExecution, + 1060595, + 1153808, + TimeSpan.FromSeconds(7.0), + attacker, + $"{resSpells}\t{40}\t{40}\t{40}\t{40}\t{40}" + ) + ); + } + else + { + BuffInfo.AddBuff( + attacker, + new BuffInfo(BuffIcon.HonorableExecution, 1060595, TimeSpan.FromSeconds(7.0), attacker) + ); + } + } + + _table[attacker] = timer; + timer.Start(); + + attacker.Delta(MobileDelta.WeaponDamage); + CheckGain(attacker); + } + + public static int GetSwingBonus(Mobile target) => _table.TryGetValue(target, out var info) ? info.m_SwingBonus : 0; + + public static bool IsUnderPenalty(Mobile target) => _table.TryGetValue(target, out var info) && info.m_Penalty; + + public static void RemovePenalty(Mobile target) + { + if (_table.Remove(target, out var timer)) + { + timer.Clear(); + } + } + + private class HonorableExecutionTimer : Timer + { + public readonly Mobile m_Mobile; + public readonly List m_Mods; + public readonly bool m_Penalty; + public readonly int m_SwingBonus; + + public HonorableExecutionTimer(Mobile from, List mods) : this(TimeSpan.FromSeconds(7.0), from, 0, mods, mods != null) + { + } + + public HonorableExecutionTimer(Mobile from, int swingBonus) : this(TimeSpan.FromSeconds(20.0), from, swingBonus) + { + } + + public HonorableExecutionTimer( + TimeSpan duration, Mobile from, int swingBonus, List mods = null, bool penalty = false + ) : base(duration) + { + m_Mobile = from; + m_SwingBonus = swingBonus; + m_Mods = mods; + m_Penalty = penalty; + + Apply(); + } + + protected override void OnTick() + { + m_Mobile?.Delta(MobileDelta.WeaponDamage); + RemovePenalty(m_Mobile); + } + + public void Apply() + { + if (m_Mods == null) { return; } - ClearCurrentMove(attacker); - RemovePenalty(attacker); - - HonorableExecutionTimer timer; - - if (!defender.Alive) + for (var i = 0; i < m_Mods.Count; ++i) { - attacker.FixedParticles(0x373A, 1, 17, 0x7E2, EffectLayer.Waist); + var mod = m_Mods[i]; - var bushido = attacker.Skills.Bushido.Value; - bushido *= bushido; - - attacker.Hits += 20 + (int)(bushido / 480.0); - - var swingBonus = Math.Max(1, (int)(bushido / 720.0)); - - timer = new HonorableExecutionTimer(attacker, swingBonus); - } - else - { - var mods = new List + if (mod is ResistanceMod resistanceMod) { - new ResistanceMod(ResistanceType.Physical, "PhysicalResistHonorableExecution", -40), - new ResistanceMod(ResistanceType.Fire, "FireResistHonorableExecution", -40), - new ResistanceMod(ResistanceType.Cold, "ColdResistHonorableExecution", -40), - new ResistanceMod(ResistanceType.Poison, "PoisonResistHonorableExecution", -40), - new ResistanceMod(ResistanceType.Energy, "EnergyResistHonorableExecution", -40) - }; - - var resSpells = attacker.Skills.MagicResist.Value; - - if (resSpells > 0.0) - { - mods.Add(new DefaultSkillMod(SkillName.MagicResist, "MagicResistHonorableExecution", true, -resSpells)); + m_Mobile.AddResistanceMod(resistanceMod); + } + else if (mod is SkillMod skillMod) + { + m_Mobile.AddSkillMod(skillMod); } - - timer = new HonorableExecutionTimer(attacker, mods); - } - - _table[attacker] = timer; - timer.Start(); - - attacker.Delta(MobileDelta.WeaponDamage); - CheckGain(attacker); - } - - public static int GetSwingBonus(Mobile target) => _table.TryGetValue(target, out var info) ? info.m_SwingBonus : 0; - - public static bool IsUnderPenalty(Mobile target) => _table.TryGetValue(target, out var info) && info.m_Penalty; - - public static void RemovePenalty(Mobile target) - { - if (_table.Remove(target, out var timer)) - { - timer.Clear(); } } - private class HonorableExecutionTimer : Timer + public void Clear() { - public readonly Mobile m_Mobile; - public readonly List m_Mods; - public readonly bool m_Penalty; - public readonly int m_SwingBonus; + Stop(); - public HonorableExecutionTimer(Mobile from, List mods) : this(TimeSpan.FromSeconds(7.0), from, 0, mods, mods != null) + if (m_Mods == null) { + return; } - public HonorableExecutionTimer(Mobile from, int swingBonus) : this(TimeSpan.FromSeconds(20.0), from, swingBonus) + for (var i = 0; i < m_Mods.Count; ++i) { - } + var mod = m_Mods[i]; - public HonorableExecutionTimer( - TimeSpan duration, Mobile from, int swingBonus, List mods = null, bool penalty = false - ) : base(duration) - { - m_Mobile = from; - m_SwingBonus = swingBonus; - m_Mods = mods; - m_Penalty = penalty; - - Apply(); - } - - protected override void OnTick() - { - m_Mobile?.Delta(MobileDelta.WeaponDamage); - RemovePenalty(m_Mobile); - } - - public void Apply() - { - if (m_Mods == null) + if (mod is ResistanceMod resistanceMod) { - return; + m_Mobile?.RemoveResistanceMod(resistanceMod); } - - for (var i = 0; i < m_Mods.Count; ++i) + else if (mod is SkillMod skillMod) { - var mod = m_Mods[i]; - - if (mod is ResistanceMod resistanceMod) - { - m_Mobile.AddResistanceMod(resistanceMod); - } - else if (mod is SkillMod skillMod) - { - m_Mobile.AddSkillMod(skillMod); - } - } - } - - public void Clear() - { - Stop(); - - if (m_Mods == null) - { - return; - } - - for (var i = 0; i < m_Mods.Count; ++i) - { - var mod = m_Mods[i]; - - if (mod is ResistanceMod resistanceMod) - { - m_Mobile?.RemoveResistanceMod(resistanceMod); - } - else if (mod is SkillMod skillMod) - { - m_Mobile?.RemoveSkillMod(skillMod); - } + m_Mobile?.RemoveSkillMod(skillMod); } } } diff --git a/Projects/UOContent/Spells/Chivalry/DivineFury.cs b/Projects/UOContent/Spells/Chivalry/DivineFury.cs index 1fd76cf14..c2afcfa36 100644 --- a/Projects/UOContent/Spells/Chivalry/DivineFury.cs +++ b/Projects/UOContent/Spells/Chivalry/DivineFury.cs @@ -116,6 +116,7 @@ public class DivineFurySpell : PaladinSpell RemoveTimer(m); m.Delta(MobileDelta.WeaponDamage); m.PlaySound(0xF8); + BuffInfo.RemoveBuff(m, BuffIcon.DivineFury); } public static bool UnderEffect(Mobile m) => _table.ContainsKey(m);