fix: Fixes skill requirements and cleans up magery spells (#870)
* Preps damage stacking for mysticism, necromancy fixes, and spellweaving * Removes extra LINQ allocations * Fixes skill requirements for magery spells.
This commit is contained in:
parent
1cf7b6c056
commit
4f9714818d
16 changed files with 311 additions and 382 deletions
|
|
@ -17,19 +17,16 @@ namespace Server.Spells
|
|||
public abstract class Spell : ISpell
|
||||
{
|
||||
private static readonly TimeSpan NextSpellDelay = TimeSpan.FromSeconds(0.75);
|
||||
|
||||
private static readonly TimeSpan AnimateDelay = TimeSpan.FromSeconds(1.5);
|
||||
// In reality, it's ANY delayed Damage spell Post-AoS that can't stack, but, only
|
||||
// Expo & Magic Arrow have enough delay and a short enough cast time to bring up
|
||||
// the possibility of stacking 'em. Note that a MA & an Explosion will stack, but
|
||||
// of course, two MA's won't.
|
||||
|
||||
private static readonly Dictionary<Type, DelayedDamageContextWrapper> m_ContextTable =
|
||||
new();
|
||||
private static readonly Dictionary<Type, DelayedDamageContextWrapper> _contextTable = new();
|
||||
|
||||
private AnimTimer m_AnimTimer;
|
||||
|
||||
private CastTimer m_CastTimer;
|
||||
private AnimTimer _animTimer;
|
||||
private CastTimer _castTimer;
|
||||
|
||||
public Spell(Mobile caster, Item scroll, SpellInfo info)
|
||||
{
|
||||
|
|
@ -60,13 +57,17 @@ namespace Server.Spells
|
|||
|
||||
public virtual bool DelayedDamage => false;
|
||||
|
||||
public virtual bool DelayedDamageStacking => true;
|
||||
public static readonly Type[] AOSNoDelayedDamageStackingSelf = Core.AOS ? Array.Empty<Type>() : null;
|
||||
|
||||
// Null means stacking is allowed while empty indicates no stacking with self
|
||||
// More than zero means no stacking with self and other spells
|
||||
public virtual Type[] DelayedDamageSpellFamilyStacking => null;
|
||||
|
||||
public virtual bool BlockedByHorrificBeast => true;
|
||||
public virtual bool BlockedByAnimalForm => true;
|
||||
public virtual bool BlocksMovement => true;
|
||||
|
||||
public virtual bool CheckNextSpellTime => !(Scroll is BaseWand);
|
||||
public virtual bool CheckNextSpellTime => Scroll is not BaseWand;
|
||||
|
||||
public virtual int CastRecoveryBase => 6;
|
||||
public virtual int CastRecoveryFastScalar => 1;
|
||||
|
|
@ -149,22 +150,39 @@ namespace Server.Spells
|
|||
|
||||
public void StartDelayedDamageContext(Mobile m, Timer t)
|
||||
{
|
||||
if (DelayedDamageStacking)
|
||||
var damageStacking = DelayedDamageSpellFamilyStacking;
|
||||
if (damageStacking == null)
|
||||
{
|
||||
return; // Sanity
|
||||
}
|
||||
|
||||
if (!m_ContextTable.TryGetValue(GetType(), out var contexts))
|
||||
var type = GetType();
|
||||
|
||||
if (!_contextTable.TryGetValue(type, out var context))
|
||||
{
|
||||
m_ContextTable[GetType()] = contexts = new DelayedDamageContextWrapper();
|
||||
_contextTable[type] = context = new DelayedDamageContextWrapper();
|
||||
|
||||
for (int i = 0; i < damageStacking.Length; i++)
|
||||
{
|
||||
_contextTable.Add(damageStacking[i], context);
|
||||
}
|
||||
}
|
||||
|
||||
contexts.Add(m, t);
|
||||
context.Add(m, t);
|
||||
}
|
||||
|
||||
public bool HasDelayedDamageContext(Mobile m) =>
|
||||
DelayedDamageSpellFamilyStacking != null &&
|
||||
_contextTable.TryGetValue(GetType(), out var context) && context.Contains(m);
|
||||
|
||||
public void RemoveDelayedDamageContext(Mobile m)
|
||||
{
|
||||
if (m_ContextTable.TryGetValue(GetType(), out var contexts))
|
||||
if (m == null || DelayedDamageSpellFamilyStacking == null)
|
||||
{
|
||||
return; // Sanity
|
||||
}
|
||||
|
||||
if (_contextTable.TryGetValue(GetType(), out var contexts))
|
||||
{
|
||||
contexts.Remove(m);
|
||||
}
|
||||
|
|
@ -389,8 +407,8 @@ namespace Server.Spells
|
|||
{
|
||||
OnDisturb(type, true);
|
||||
|
||||
m_CastTimer?.Stop();
|
||||
m_AnimTimer?.Stop();
|
||||
_castTimer?.Stop();
|
||||
_animTimer?.Stop();
|
||||
|
||||
if (Core.AOS && Caster.Player && type == DisturbType.Hurt)
|
||||
{
|
||||
|
|
@ -469,7 +487,7 @@ namespace Server.Spells
|
|||
{
|
||||
Caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form.
|
||||
}
|
||||
else if (!(Scroll is BaseWand) && (Caster.Paralyzed || Caster.Frozen))
|
||||
else if (Scroll is not BaseWand && (Caster.Paralyzed || Caster.Frozen))
|
||||
{
|
||||
Caster.SendLocalizedMessage(502643); // You can not cast a spell while frozen.
|
||||
}
|
||||
|
|
@ -492,7 +510,7 @@ namespace Server.Spells
|
|||
State = SpellState.Casting;
|
||||
Caster.Spell = this;
|
||||
|
||||
if (!(Scroll is BaseWand) && RevealOnCast)
|
||||
if (Scroll is not BaseWand && RevealOnCast)
|
||||
{
|
||||
Caster.RevealingAction();
|
||||
}
|
||||
|
|
@ -507,8 +525,8 @@ namespace Server.Spells
|
|||
|
||||
if (count != 0)
|
||||
{
|
||||
m_AnimTimer = new AnimTimer(this, count);
|
||||
m_AnimTimer.Start();
|
||||
_animTimer = new AnimTimer(this, count);
|
||||
_animTimer.Start();
|
||||
}
|
||||
|
||||
if (Info.LeftHandEffect > 0)
|
||||
|
|
@ -532,18 +550,18 @@ namespace Server.Spells
|
|||
WeaponAbility.ClearCurrentAbility(Caster);
|
||||
}
|
||||
|
||||
m_CastTimer = new CastTimer(this, castDelay);
|
||||
_castTimer = new CastTimer(this, castDelay);
|
||||
// m_CastTimer.Start();
|
||||
|
||||
OnBeginCast();
|
||||
|
||||
if (castDelay > TimeSpan.Zero)
|
||||
{
|
||||
m_CastTimer.Start();
|
||||
_castTimer.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CastTimer.Tick();
|
||||
_castTimer.Tick();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -647,11 +665,6 @@ namespace Server.Spells
|
|||
return TimeSpan.FromSeconds((double)delay / CastRecoveryPerSecond);
|
||||
}
|
||||
|
||||
// public virtual int CastDelayBase{ get{ return 3; } }
|
||||
// public virtual int CastDelayFastScalar{ get{ return 1; } }
|
||||
// public virtual int CastDelayPerSecond{ get{ return 4; } }
|
||||
// public virtual int CastDelayMinimum{ get{ return 1; } }
|
||||
|
||||
public virtual TimeSpan GetCastDelay()
|
||||
{
|
||||
if (Scroll is BaseWand)
|
||||
|
|
@ -665,7 +678,7 @@ namespace Server.Spells
|
|||
// Paladins with magery of 70.0 or above are subject to a faster casting cap of 2
|
||||
var fcMax = 4;
|
||||
|
||||
if (CastSkill == SkillName.Magery || CastSkill == SkillName.Necromancy ||
|
||||
if (CastSkill is SkillName.Magery or SkillName.Necromancy ||
|
||||
CastSkill == SkillName.Chivalry && Caster.Skills.Magery.Value >= 70.0)
|
||||
{
|
||||
fcMax = 2;
|
||||
|
|
@ -749,12 +762,9 @@ namespace Server.Spells
|
|||
|
||||
Scroll.Movable = m;
|
||||
}
|
||||
else
|
||||
else if (ClearHandsOnCast)
|
||||
{
|
||||
if (ClearHandsOnCast)
|
||||
{
|
||||
Caster.ClearHands();
|
||||
}
|
||||
Caster.ClearHands();
|
||||
}
|
||||
|
||||
var karma = ComputeKarmaAward();
|
||||
|
|
@ -838,10 +848,14 @@ namespace Server.Spells
|
|||
m_Contexts.Add(m, t);
|
||||
}
|
||||
|
||||
public bool Contains(Mobile m) => m_Contexts.ContainsKey(m);
|
||||
|
||||
public void Remove(Mobile m)
|
||||
{
|
||||
m_Contexts.Remove(m);
|
||||
// TODO: Should we stop the timer?
|
||||
if (m_Contexts.Remove(m, out var t))
|
||||
{
|
||||
t.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -876,7 +890,7 @@ namespace Server.Spells
|
|||
|
||||
if (!Running)
|
||||
{
|
||||
m_Spell.m_AnimTimer = null;
|
||||
m_Spell._animTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -900,7 +914,7 @@ namespace Server.Spells
|
|||
if (m_Spell.State == SpellState.Casting && m_Spell.Caster.Spell == m_Spell)
|
||||
{
|
||||
m_Spell.State = SpellState.Sequencing;
|
||||
m_Spell.m_CastTimer = null;
|
||||
m_Spell._castTimer = null;
|
||||
m_Spell.Caster.OnSpellCast(m_Spell);
|
||||
m_Spell.Caster.Region?.OnSpellCast(m_Spell.Caster, m_Spell);
|
||||
m_Spell.Caster.NextSpellTime =
|
||||
|
|
@ -915,7 +929,7 @@ namespace Server.Spells
|
|||
m_Spell.Caster.Target?.BeginTimeout(m_Spell.Caster, 30000); // 30 seconds
|
||||
}
|
||||
|
||||
m_Spell.m_CastTimer = null;
|
||||
m_Spell._castTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue