fix: Fixes buff icons for confidence, honorable excution, and divine fury (#1291)

This commit is contained in:
Kamron Batman 2022-12-04 13:52:44 -08:00 committed by GitHub
parent 1745faa28c
commit 284186359d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 282 additions and 234 deletions

View file

@ -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<Mobile, TimerExecutionToken> _table = new();
private static readonly Dictionary<Mobile, TimerExecutionToken> _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<Mobile, TimerExecutionToken> _table = new();
private static readonly Dictionary<Mobile, TimerExecutionToken> 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();
}
}
}

View file

@ -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<Mobile, HonorableExecutionTimer> _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<Mobile, HonorableExecutionTimer> _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<object>
{
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<object> m_Mods;
public readonly bool m_Penalty;
public readonly int m_SwingBonus;
public HonorableExecutionTimer(Mobile from, List<object> 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<object> 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<object>
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<object> m_Mods;
public readonly bool m_Penalty;
public readonly int m_SwingBonus;
Stop();
public HonorableExecutionTimer(Mobile from, List<object> 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<object> 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);
}
}
}

View file

@ -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);