fix: Cleans up more spells (#1121)
This commit is contained in:
parent
fa3515f930
commit
068bafd9b6
32 changed files with 339 additions and 439 deletions
|
|
@ -15,7 +15,7 @@ namespace Server.Spells.Necromancy
|
|||
Reagent.DaemonBlood
|
||||
);
|
||||
|
||||
private static readonly Dictionary<Mobile, Mobile> m_OathTable = new();
|
||||
private static readonly Dictionary<Mobile, Mobile> _oathTable = new();
|
||||
private static readonly Dictionary<Mobile, ExpireTimer> _table = new();
|
||||
|
||||
public BloodOathSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
|
|
@ -38,11 +38,11 @@ namespace Server.Spells.Necromancy
|
|||
{
|
||||
Caster.SendLocalizedMessage(1060508); // You can't curse that.
|
||||
}
|
||||
else if (m_OathTable.ContainsKey(Caster))
|
||||
else if (_oathTable.ContainsKey(Caster))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1061607); // You are already bonded in a Blood Oath.
|
||||
}
|
||||
else if (m_OathTable.ContainsKey(m))
|
||||
else if (_oathTable.ContainsKey(m))
|
||||
{
|
||||
if (m.Player)
|
||||
{
|
||||
|
|
@ -67,8 +67,8 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
RemoveCurse(m);
|
||||
|
||||
m_OathTable[Caster] = Caster;
|
||||
m_OathTable[m] = Caster;
|
||||
_oathTable[Caster] = Caster;
|
||||
_oathTable[m] = Caster;
|
||||
|
||||
m.Spell?.OnCasterHurt();
|
||||
|
||||
|
|
@ -106,12 +106,12 @@ namespace Server.Spells.Necromancy
|
|||
if (_table.Remove(target, out var timer))
|
||||
{
|
||||
var caster = timer.Caster;
|
||||
if (m_OathTable.Remove(caster))
|
||||
if (_oathTable.Remove(caster))
|
||||
{
|
||||
caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
|
||||
}
|
||||
|
||||
if (m_OathTable.Remove(target))
|
||||
if (_oathTable.Remove(target))
|
||||
{
|
||||
target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ namespace Server.Spells.Necromancy
|
|||
}
|
||||
|
||||
public static Mobile GetBloodOath(Mobile m) =>
|
||||
m == null || m_OathTable.TryGetValue(m, out var oath) && oath == m ? null : oath;
|
||||
m == null || _oathTable.TryGetValue(m, out var oath) && oath == m ? null : oath;
|
||||
|
||||
private class ExpireTimer : Timer
|
||||
{
|
||||
|
|
|
|||
|
|
@ -114,30 +114,30 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
private class ExpireTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Mobile;
|
||||
private readonly ResistanceMod[] m_Mods;
|
||||
private Mobile _mobile;
|
||||
private ResistanceMod[] _mods;
|
||||
|
||||
public ExpireTimer(Mobile m, ResistanceMod[] mods, TimeSpan delay) : base(delay)
|
||||
{
|
||||
m_Mobile = m;
|
||||
m_Mods = mods;
|
||||
_mobile = m;
|
||||
_mods = mods;
|
||||
}
|
||||
|
||||
public void DoExpire()
|
||||
{
|
||||
for (var i = 0; i < m_Mods.Length; ++i)
|
||||
for (var i = 0; i < _mods.Length; ++i)
|
||||
{
|
||||
m_Mobile.RemoveResistanceMod(m_Mods[i]);
|
||||
_mobile.RemoveResistanceMod(_mods[i]);
|
||||
}
|
||||
|
||||
Stop();
|
||||
BuffInfo.RemoveBuff(m_Mobile, BuffIcon.CorpseSkin);
|
||||
_table.Remove(m_Mobile);
|
||||
BuffInfo.RemoveBuff(_mobile, BuffIcon.CorpseSkin);
|
||||
_table.Remove(_mobile);
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Mobile.SendLocalizedMessage(1061688); // Your skin returns to normal.
|
||||
_mobile.SendLocalizedMessage(1061688); // Your skin returns to normal.
|
||||
DoExpire();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace Server.Spells.Necromancy
|
|||
Caster.PlaySound(0x387);
|
||||
Caster.FixedParticles(0x3779, 1, 15, 9905, 32, 2, EffectLayer.Head);
|
||||
Caster.FixedParticles(0x37B9, 1, 14, 9502, 32, 5, (EffectLayer)255);
|
||||
new SoundEffectTimer(Caster).Start();
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(0.75), () => Caster.PlaySound(0xFA));
|
||||
|
||||
var duration = TimeSpan.FromSeconds(Caster.Skills.SpiritSpeak.Value / 3.4 + 1.0);
|
||||
|
||||
|
|
@ -64,33 +64,15 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
private class ExpireTimer : Timer
|
||||
{
|
||||
private readonly BaseWeapon m_Weapon;
|
||||
private BaseWeapon _weapon;
|
||||
|
||||
public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay)
|
||||
{
|
||||
m_Weapon = weapon;
|
||||
}
|
||||
public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay) => _weapon = weapon;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Weapon.Cursed = false;
|
||||
Effects.PlaySound(m_Weapon.GetWorldLocation(), m_Weapon.Map, 0xFA);
|
||||
_table.Remove(m_Weapon);
|
||||
}
|
||||
}
|
||||
|
||||
private class SoundEffectTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Mobile;
|
||||
|
||||
public SoundEffectTimer(Mobile m) : base(TimeSpan.FromSeconds(0.75))
|
||||
{
|
||||
m_Mobile = m;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Mobile.PlaySound(0xFA);
|
||||
_weapon.Cursed = false;
|
||||
Effects.PlaySound(_weapon.GetWorldLocation(), _weapon.Map, 0xFA);
|
||||
_table.Remove(_weapon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Server.Spells.Necromancy
|
|||
Reagent.DaemonBlood
|
||||
);
|
||||
|
||||
private static readonly Dictionary<Mobile, MRBucket> _table = new();
|
||||
private static readonly Dictionary<Mobile, MRExpireTimer> _table = new();
|
||||
|
||||
public MindRotSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
|
|
@ -52,13 +52,10 @@ namespace Server.Spells.Necromancy
|
|||
m.PlaySound(0x258);
|
||||
m.FixedParticles(0x373A, 1, 17, 9903, 15, 4, EffectLayer.Head);
|
||||
|
||||
var duration =
|
||||
TimeSpan.FromSeconds(
|
||||
((GetDamageSkill(Caster) - GetResistSkill(m)) / 5.0 + 20.0) * (m.Player ? 1.0 : 2.0)
|
||||
);
|
||||
var duration = ((GetDamageSkill(Caster) - GetResistSkill(m)) / 5.0 + 20.0) * (m.Player ? 1.0 : 2.0);
|
||||
m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain
|
||||
|
||||
SetMindRotScalar(Caster, m, m.Player ? 1.25 : 2.00, duration);
|
||||
SetMindRotScalar(Caster, m, m.Player ? 1.25 : 2.00, TimeSpan.FromSeconds(duration));
|
||||
|
||||
HarmfulSpell(m);
|
||||
}
|
||||
|
|
@ -73,11 +70,12 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public static bool ClearMindRotScalar(Mobile m)
|
||||
{
|
||||
if (_table.Remove(m, out var tmpB))
|
||||
if (_table.Remove(m, out var timer))
|
||||
{
|
||||
tmpB.m_MRExpireTimer.Stop();
|
||||
timer.Stop();
|
||||
m.SendLocalizedMessage(1060872); // Your mind feels normal again.
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -88,9 +86,9 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public static bool GetMindRotScalar(Mobile m, ref double scalar)
|
||||
{
|
||||
if (_table.TryGetValue(m, out var tmpB))
|
||||
if (_table.TryGetValue(m, out var timer))
|
||||
{
|
||||
scalar = tmpB.m_Scalar;
|
||||
scalar = timer._double;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -101,10 +99,11 @@ namespace Server.Spells.Necromancy
|
|||
{
|
||||
if (!_table.ContainsKey(target))
|
||||
{
|
||||
var tmpB = new MRBucket(scalar, new MRExpireTimer(target, duration));
|
||||
_table.Add(target, tmpB);
|
||||
var timer = new MRExpireTimer(target, scalar, duration);
|
||||
timer.Start();
|
||||
_table[target] = timer;
|
||||
|
||||
BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target));
|
||||
tmpB.m_MRExpireTimer.Start();
|
||||
target.SendLocalizedMessage(1074384);
|
||||
}
|
||||
}
|
||||
|
|
@ -112,37 +111,27 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public class MRExpireTimer : Timer
|
||||
{
|
||||
private readonly DateTime m_End;
|
||||
private readonly Mobile m_Target;
|
||||
private DateTime _end;
|
||||
private Mobile _target;
|
||||
public double _double;
|
||||
|
||||
public MRExpireTimer(Mobile target, TimeSpan delay) : base(
|
||||
public MRExpireTimer(Mobile target, double scalar, TimeSpan delay) : base(
|
||||
TimeSpan.FromSeconds(1.0),
|
||||
TimeSpan.FromSeconds(1.0)
|
||||
)
|
||||
{
|
||||
m_Target = target;
|
||||
m_End = Core.Now + delay;
|
||||
_double = scalar;
|
||||
_target = target;
|
||||
_end = Core.Now + delay;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_Target.Deleted || !m_Target.Alive || Core.Now >= m_End)
|
||||
if (_target.Deleted || !_target.Alive || Core.Now >= _end)
|
||||
{
|
||||
MindRotSpell.ClearMindRotScalar(m_Target);
|
||||
MindRotSpell.ClearMindRotScalar(_target);
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MRBucket
|
||||
{
|
||||
public MRExpireTimer m_MRExpireTimer;
|
||||
|
||||
public double m_Scalar;
|
||||
|
||||
public MRBucket(double theScalar, MRExpireTimer theTimer)
|
||||
{
|
||||
m_Scalar = theScalar;
|
||||
m_MRExpireTimer = theTimer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,9 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public override bool ClearHandsOnCast => false;
|
||||
|
||||
// Necromancer spells are not affected by fast cast items, though they are by fast cast recovery
|
||||
public override double CastDelayFastScalar =>
|
||||
Core.SE
|
||||
? base.CastDelayFastScalar
|
||||
: 0; // Necromancer spells are not affected by fast cast items, though they are by fast cast recovery
|
||||
Core.SE ? base.CastDelayFastScalar : 0;
|
||||
|
||||
public override int ComputeKarmaAward()
|
||||
{
|
||||
|
|
@ -29,8 +28,8 @@ namespace Server.Spells.Necromancy
|
|||
// int karma = -(70 + (10 * (int)Circle));
|
||||
var karma = -(40 + (int)(10 * (CastDelayBase.TotalSeconds / CastDelaySecondsPerTick)));
|
||||
|
||||
if (Core.ML
|
||||
) // Pub 36: "Added a new property called Increased Karma Loss which grants higher karma loss for casting necromancy spells."
|
||||
// Pub 36: "Added a new property called Increased Karma Loss which grants higher karma loss for casting necromancy spells."
|
||||
if (Core.ML)
|
||||
{
|
||||
karma += AOS.Scale(karma, AosAttributes.GetValue(Caster, AosAttribute.IncreasedKarmaLoss));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,26 +90,26 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Mobile;
|
||||
private readonly int m_ToRestore;
|
||||
private Mobile _mobile;
|
||||
private int _toRestore;
|
||||
|
||||
public InternalTimer(Mobile m, double toRestore) : base(TimeSpan.FromSeconds(10.0))
|
||||
{
|
||||
|
||||
m_Mobile = m;
|
||||
m_ToRestore = (int)toRestore;
|
||||
_mobile = m;
|
||||
_toRestore = (int)toRestore;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
_table.Remove(m_Mobile);
|
||||
_table.Remove(_mobile);
|
||||
|
||||
if (m_Mobile.Alive && !m_Mobile.IsDeadBondedPet)
|
||||
if (_mobile.Alive && !_mobile.IsDeadBondedPet)
|
||||
{
|
||||
m_Mobile.Hits += m_ToRestore;
|
||||
_mobile.Hits += _toRestore;
|
||||
}
|
||||
|
||||
BuffInfo.RemoveBuff(m_Mobile, BuffIcon.PainSpike);
|
||||
BuffInfo.RemoveBuff(_mobile, BuffIcon.PainSpike);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Collections;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Targeting;
|
||||
|
|
@ -16,8 +16,7 @@ namespace Server.Spells.Necromancy
|
|||
Reagent.NoxCrystal
|
||||
);
|
||||
|
||||
public PoisonStrikeSpell(Mobile caster, Item scroll = null)
|
||||
: base(caster, scroll, _info)
|
||||
public PoisonStrikeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -30,11 +29,6 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public void Target(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckHSequence(m))
|
||||
{
|
||||
SpellHelper.Turn(Caster, m);
|
||||
|
|
@ -48,39 +42,39 @@ namespace Server.Spells.Necromancy
|
|||
// Check magic resist for skill, but do not use return value
|
||||
// reports from OSI: Necro spells don't give Resist gain
|
||||
|
||||
Effects.SendLocationParticles(
|
||||
EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration),
|
||||
0x36B0,
|
||||
1,
|
||||
14,
|
||||
63,
|
||||
7,
|
||||
9915,
|
||||
0
|
||||
);
|
||||
Effects.PlaySound(m.Location, m.Map, 0x229);
|
||||
|
||||
var damage = Utility.RandomMinMax(Core.ML ? 32 : 36, 40) * ((300 + GetDamageSkill(Caster) * 9) / 1000);
|
||||
|
||||
var sdiBonus = (double)AosAttributes.GetValue(Caster, AosAttribute.SpellDamage) / 100;
|
||||
var pvmDamage = damage * (1 + sdiBonus);
|
||||
|
||||
if (Core.ML && sdiBonus > 0.15)
|
||||
{
|
||||
sdiBonus = 0.15;
|
||||
}
|
||||
|
||||
var pvpDamage = damage * (1 + sdiBonus);
|
||||
|
||||
var map = m.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
var targets = new List<Mobile>();
|
||||
Effects.SendLocationParticles(
|
||||
EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration),
|
||||
0x36B0,
|
||||
1,
|
||||
14,
|
||||
63,
|
||||
7,
|
||||
9915,
|
||||
0
|
||||
);
|
||||
Effects.PlaySound(m.Location, m.Map, 0x229);
|
||||
|
||||
var damage = Utility.RandomMinMax(Core.ML ? 32 : 36, 40) * ((300 + GetDamageSkill(Caster) * 9) / 1000);
|
||||
|
||||
var sdiBonus = (double)AosAttributes.GetValue(Caster, AosAttribute.SpellDamage) / 100;
|
||||
var pvmDamage = damage * (1 + sdiBonus);
|
||||
|
||||
if (Core.ML && sdiBonus > 0.15)
|
||||
{
|
||||
sdiBonus = 0.15;
|
||||
}
|
||||
|
||||
var pvpDamage = damage * (1 + sdiBonus);
|
||||
|
||||
using var pool = PooledRefQueue<Mobile>.Create();
|
||||
|
||||
if (Caster.CanBeHarmful(m, false))
|
||||
{
|
||||
targets.Add(m);
|
||||
pool.Enqueue(m);
|
||||
}
|
||||
|
||||
var eable = m.GetMobilesInRange(2);
|
||||
|
|
@ -92,15 +86,15 @@ namespace Server.Spells.Necromancy
|
|||
SpellHelper.ValidIndirectTarget(Caster, targ) &&
|
||||
Caster.CanBeHarmful(targ, false))
|
||||
{
|
||||
targets.Add(targ);
|
||||
pool.Enqueue(targ);
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
for (var i = 0; i < targets.Count; ++i)
|
||||
while (pool.Count > 0)
|
||||
{
|
||||
var targ = targets[i];
|
||||
var targ = pool.Dequeue();
|
||||
int num;
|
||||
|
||||
if (targ.InRange(m.Location, 0))
|
||||
|
|
|
|||
|
|
@ -70,42 +70,38 @@ namespace Server.Spells.Necromancy
|
|||
}
|
||||
|
||||
// Calculations for the buff bar
|
||||
var spiritlevel = Caster.Skills.SpiritSpeak.Value / 10;
|
||||
if (spiritlevel < 4)
|
||||
var spiritlevel = Math.Min(4, Caster.Skills.SpiritSpeak.Value / 10);
|
||||
|
||||
const int minDamage = 4;
|
||||
var maxDamage = ((int)spiritlevel + 1) * 3;
|
||||
var args = $"{minDamage}\t{maxDamage}";
|
||||
|
||||
var count = (int)spiritlevel;
|
||||
var maxCount = count;
|
||||
var hitDelay = 5;
|
||||
var length = hitDelay;
|
||||
|
||||
while (count > 1)
|
||||
{
|
||||
spiritlevel = 4;
|
||||
}
|
||||
|
||||
var d_MinDamage = 4;
|
||||
var d_MaxDamage = ((int)spiritlevel + 1) * 3;
|
||||
var args = $"{d_MinDamage}\t{d_MaxDamage}";
|
||||
|
||||
var i_Count = (int)spiritlevel;
|
||||
var i_MaxCount = i_Count;
|
||||
var i_HitDelay = 5;
|
||||
var i_Length = i_HitDelay;
|
||||
|
||||
while (i_Count > 1)
|
||||
{
|
||||
--i_Count;
|
||||
if (i_HitDelay > 1)
|
||||
--count;
|
||||
if (hitDelay > 1)
|
||||
{
|
||||
if (i_MaxCount < 5)
|
||||
if (maxCount < 5)
|
||||
{
|
||||
--i_HitDelay;
|
||||
--hitDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
var delay = (int)Math.Ceiling((1.0 + 5 * i_Count) / i_MaxCount);
|
||||
var delay = (int)Math.Ceiling((1.0 + 5 * count) / maxCount);
|
||||
|
||||
i_HitDelay = delay <= 5 ? delay : 5;
|
||||
hitDelay = delay <= 5 ? delay : 5;
|
||||
}
|
||||
}
|
||||
|
||||
i_Length += i_HitDelay;
|
||||
length += hitDelay;
|
||||
}
|
||||
|
||||
var t_Duration = TimeSpan.FromSeconds(i_Length);
|
||||
var t_Duration = TimeSpan.FromSeconds(length);
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, 1075795, t_Duration, m, args));
|
||||
|
||||
FinishSequence();
|
||||
|
|
@ -130,106 +126,98 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_From;
|
||||
private readonly double m_MaxBaseDamage;
|
||||
private readonly int m_MaxCount;
|
||||
private readonly double m_MinBaseDamage;
|
||||
private readonly Mobile m_Target;
|
||||
private int m_Count;
|
||||
private int m_HitDelay;
|
||||
|
||||
private DateTime m_NextHit;
|
||||
private Mobile _from;
|
||||
private double _maxBaseDamage;
|
||||
private int _maxCount;
|
||||
private double _minBaseDamage;
|
||||
private Mobile _target;
|
||||
private int _count;
|
||||
private int _hitDelay;
|
||||
private DateTime _nextHit;
|
||||
|
||||
public InternalTimer(Mobile target, Mobile from) : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))
|
||||
{
|
||||
|
||||
m_Target = target;
|
||||
m_From = from;
|
||||
_target = target;
|
||||
_from = from;
|
||||
|
||||
var spiritLevel = from.Skills.SpiritSpeak.Value / 10;
|
||||
|
||||
m_MinBaseDamage = spiritLevel - 2;
|
||||
m_MaxBaseDamage = spiritLevel + 1;
|
||||
_minBaseDamage = spiritLevel - 2;
|
||||
_maxBaseDamage = spiritLevel + 1;
|
||||
|
||||
m_HitDelay = 5;
|
||||
m_NextHit = Core.Now + TimeSpan.FromSeconds(m_HitDelay);
|
||||
_hitDelay = 5;
|
||||
_nextHit = Core.Now + TimeSpan.FromSeconds(_hitDelay);
|
||||
|
||||
m_Count = (int)spiritLevel;
|
||||
|
||||
if (m_Count < 4)
|
||||
{
|
||||
m_Count = 4;
|
||||
}
|
||||
|
||||
m_MaxCount = m_Count;
|
||||
_maxCount = _count = Math.Min(4, (int)spiritLevel);
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (!m_Target.Alive)
|
||||
if (!_target.Alive)
|
||||
{
|
||||
_table.Remove(m_Target);
|
||||
_table.Remove(_target);
|
||||
Stop();
|
||||
}
|
||||
|
||||
if (!m_Target.Alive || Core.Now < m_NextHit)
|
||||
if (!_target.Alive || Core.Now < _nextHit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
--m_Count;
|
||||
--_count;
|
||||
|
||||
if (m_HitDelay > 1)
|
||||
if (_hitDelay > 1)
|
||||
{
|
||||
if (m_MaxCount < 5)
|
||||
if (_maxCount < 5)
|
||||
{
|
||||
--m_HitDelay;
|
||||
--_hitDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
var delay = (int)Math.Ceiling((1.0 + 5 * m_Count) / m_MaxCount);
|
||||
var delay = (int)Math.Ceiling((1.0 + 5 * _count) / _maxCount);
|
||||
|
||||
if (delay <= 5)
|
||||
{
|
||||
m_HitDelay = delay;
|
||||
_hitDelay = delay;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HitDelay = 5;
|
||||
_hitDelay = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Count == 0)
|
||||
if (_count == 0)
|
||||
{
|
||||
m_Target.SendLocalizedMessage(1061687); // You can breath normally again.
|
||||
_table.Remove(m_Target);
|
||||
_target.SendLocalizedMessage(1061687); // You can breath normally again.
|
||||
_table.Remove(_target);
|
||||
Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_NextHit = Core.Now + TimeSpan.FromSeconds(m_HitDelay);
|
||||
_nextHit = Core.Now + TimeSpan.FromSeconds(_hitDelay);
|
||||
|
||||
var damage = m_MinBaseDamage + Utility.RandomDouble() * (m_MaxBaseDamage - m_MinBaseDamage);
|
||||
var damage = _minBaseDamage + Utility.RandomDouble() * (_maxBaseDamage - _minBaseDamage);
|
||||
|
||||
damage *= 3 - (double)m_Target.Stam / m_Target.StamMax * 2;
|
||||
damage *= 3 - (double)_target.Stam / _target.StamMax * 2;
|
||||
|
||||
if (damage < 1)
|
||||
{
|
||||
damage = 1;
|
||||
}
|
||||
|
||||
if (!m_Target.Player)
|
||||
if (!_target.Player)
|
||||
{
|
||||
damage *= 1.75;
|
||||
}
|
||||
|
||||
AOS.Damage(m_Target, m_From, (int)damage, 0, 0, 0, 100, 0);
|
||||
AOS.Damage(_target, _from, (int)damage, 0, 0, 0, 100, 0);
|
||||
|
||||
if (Utility.RandomDouble() >= 0.60
|
||||
) // OSI: randomly revealed between first and third damage tick, guessing 60% chance
|
||||
// OSI: randomly revealed between first and third damage tick, guessing 60% chance
|
||||
if (Utility.RandomDouble() >= 0.60)
|
||||
{
|
||||
m_Target.RevealingAction();
|
||||
_target.RevealingAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Collections;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
|
|
@ -42,35 +43,40 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
if (map != null)
|
||||
{
|
||||
var targets = new List<Mobile>();
|
||||
using var pool = PooledRefQueue<Mobile>.Create();
|
||||
|
||||
var cbc = Caster as BaseCreature;
|
||||
var isMonster = cbc?.Controlled == false && !cbc.Summoned;
|
||||
|
||||
foreach (var m in Caster.GetMobilesInRange(Core.ML ? 4 : 5))
|
||||
var eable = Caster.GetMobilesInRange(Core.ML ? 4 : 5);
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (Caster != m && Caster.InLOS(m) && (isMonster || SpellHelper.ValidIndirectTarget(Caster, m)) &&
|
||||
Caster.CanBeHarmful(m, false))
|
||||
if (Caster == m || !Caster.InLOS(m) || (!isMonster && !SpellHelper.ValidIndirectTarget(Caster, m)) ||
|
||||
!Caster.CanBeHarmful(m, false))
|
||||
{
|
||||
if (isMonster)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isMonster)
|
||||
{
|
||||
if (m is BaseCreature bc)
|
||||
{
|
||||
if (m is BaseCreature bc)
|
||||
{
|
||||
if (!bc.Controlled && !bc.Summoned && bc.Team == cbc.Team)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (!m.Player)
|
||||
if (!bc.Controlled && !bc.Summoned && bc.Team == cbc.Team)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
targets.Add(m);
|
||||
else if (!m.Player)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pool.Enqueue(m);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
Effects.PlaySound(Caster.Location, map, 0x1FB);
|
||||
Effects.PlaySound(Caster.Location, map, 0x10B);
|
||||
Effects.SendLocationParticles(
|
||||
|
|
@ -84,9 +90,9 @@ namespace Server.Spells.Necromancy
|
|||
0
|
||||
);
|
||||
|
||||
for (var i = 0; i < targets.Count; ++i)
|
||||
while (pool.Count > 0)
|
||||
{
|
||||
var m = targets[i];
|
||||
var m = pool.Dequeue();
|
||||
|
||||
Caster.DoHarmful(m);
|
||||
m.FixedParticles(0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public override void RemoveEffect(Mobile m)
|
||||
{
|
||||
if (m is PlayerMobile mobile && mobile.AccessLevel == AccessLevel.Player)
|
||||
if (m is PlayerMobile { AccessLevel: AccessLevel.Player } mobile)
|
||||
{
|
||||
mobile.IgnoreMobiles = false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue