fix: Fixes buff icons for confidence, honorable excution, and divine fury (#1291)
This commit is contained in:
parent
1745faa28c
commit
284186359d
3 changed files with 282 additions and 234 deletions
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue