fix: Cleans up more spells (#1121)
This commit is contained in:
parent
fa3515f930
commit
068bafd9b6
32 changed files with 339 additions and 439 deletions
|
|
@ -45,20 +45,15 @@ namespace Server.Spells.Bushido
|
||||||
|
|
||||||
if (Caster.Skills[CastSkill].Value < RequiredSkill)
|
if (Caster.Skills[CastSkill].Value < RequiredSkill)
|
||||||
{
|
{
|
||||||
var args = $"{RequiredSkill:0.#}\t{CastSkill.ToString()}\t ";
|
// You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
|
||||||
Caster.SendLocalizedMessage(
|
Caster.SendLocalizedMessage(1063013, $"{RequiredSkill:0.#}\t{CastSkill.ToString()}\t ");
|
||||||
1063013, // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
|
|
||||||
args
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Caster.Mana < mana)
|
if (Caster.Mana < mana)
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
||||||
1060174, // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
Caster.SendLocalizedMessage(1060174, mana.ToString());
|
||||||
mana.ToString()
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,19 +66,15 @@ namespace Server.Spells.Bushido
|
||||||
|
|
||||||
if (Caster.Skills[CastSkill].Value < RequiredSkill)
|
if (Caster.Skills[CastSkill].Value < RequiredSkill)
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
|
||||||
1070768, // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
|
Caster.SendLocalizedMessage(1070768, RequiredSkill.ToString("F1"));
|
||||||
RequiredSkill.ToString("F1")
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Caster.Mana < mana)
|
if (Caster.Mana < mana)
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
||||||
1060174, // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
Caster.SendLocalizedMessage(1060174, mana.ToString());
|
||||||
mana.ToString()
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Server.Spells.Chivalry
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(1060178); // You are too far away to perform that action!
|
Caster.SendLocalizedMessage(1060178); // You are too far away to perform that action!
|
||||||
}
|
}
|
||||||
else if (m is BaseCreature creature && creature.IsAnimatedDead)
|
else if (m is BaseCreature { IsAnimatedDead: true })
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive.
|
Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive.
|
||||||
}
|
}
|
||||||
|
|
@ -72,10 +72,8 @@ namespace Server.Spells.Chivalry
|
||||||
|
|
||||||
SpellHelper.Heal(toHeal, m, Caster, false);
|
SpellHelper.Heal(toHeal, m, Caster, false);
|
||||||
|
|
||||||
m.SendLocalizedMessage(
|
// You have had ~1_HEALED_AMOUNT~ hit points of damage healed.
|
||||||
1060203,
|
m.SendLocalizedMessage(1060203, toHeal.ToString());
|
||||||
toHeal.ToString()
|
|
||||||
); // You have had ~1_HEALED_AMOUNT~ hit points of damage healed.
|
|
||||||
|
|
||||||
m.PlaySound(0x202);
|
m.PlaySound(0x202);
|
||||||
m.FixedParticles(0x376A, 1, 62, 9923, 3, 3, EffectLayer.Waist);
|
m.FixedParticles(0x376A, 1, 62, 9923, 3, 3, EffectLayer.Waist);
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,23 @@ namespace Server.Spells.Chivalry
|
||||||
switch (weapon.Skill)
|
switch (weapon.Skill)
|
||||||
{
|
{
|
||||||
case SkillName.Macing:
|
case SkillName.Macing:
|
||||||
itemID = 0xFB4;
|
{
|
||||||
soundID = 0x232;
|
itemID = 0xFB4;
|
||||||
break;
|
soundID = 0x232;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SkillName.Archery:
|
case SkillName.Archery:
|
||||||
itemID = 0x13B1;
|
{
|
||||||
soundID = 0x145;
|
itemID = 0x13B1;
|
||||||
break;
|
soundID = 0x145;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
itemID = 0xF5F;
|
{
|
||||||
soundID = 0x56;
|
itemID = 0xF5F;
|
||||||
break;
|
soundID = 0x56;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Caster.PlaySound(0x20C);
|
Caster.PlaySound(0x20C);
|
||||||
|
|
@ -101,18 +107,15 @@ namespace Server.Spells.Chivalry
|
||||||
|
|
||||||
private class ExpireTimer : Timer
|
private class ExpireTimer : Timer
|
||||||
{
|
{
|
||||||
private readonly BaseWeapon m_Weapon;
|
private BaseWeapon _weapon;
|
||||||
|
|
||||||
public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay)
|
public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay) => _weapon = weapon;
|
||||||
{
|
|
||||||
m_Weapon = weapon;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnTick()
|
protected override void OnTick()
|
||||||
{
|
{
|
||||||
m_Weapon.Consecrated = false;
|
_weapon.Consecrated = false;
|
||||||
Effects.PlaySound(m_Weapon.GetWorldLocation(), m_Weapon.Map, 0x1F8);
|
Effects.PlaySound(_weapon.GetWorldLocation(), _weapon.Map, 0x1F8);
|
||||||
_table.Remove(m_Weapon);
|
_table.Remove(_weapon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Server.Collections;
|
||||||
using Server.Gumps;
|
using Server.Gumps;
|
||||||
using Server.Items;
|
using Server.Items;
|
||||||
using Server.Mobiles;
|
using Server.Mobiles;
|
||||||
|
|
@ -34,21 +35,20 @@ namespace Server.Spells.Chivalry
|
||||||
{
|
{
|
||||||
if (CheckSequence())
|
if (CheckSequence())
|
||||||
{
|
{
|
||||||
var targets = new List<Mobile>();
|
var eable = Caster.GetMobilesInRange(3);
|
||||||
|
using var pool = PooledRefQueue<Mobile>.Create();
|
||||||
|
|
||||||
foreach (var m in Caster.GetMobilesInRange(3)) // TODO: Validate range
|
foreach (var m in eable)
|
||||||
{
|
{
|
||||||
if (m is BaseCreature creature && creature.IsAnimatedDead)
|
if (m is not BaseCreature { IsAnimatedDead: true } && Caster != m && m.InLOS(Caster) &&
|
||||||
|
Caster.CanBeBeneficial(m, false, true) && m is not Golem)
|
||||||
{
|
{
|
||||||
continue;
|
pool.Enqueue(m);
|
||||||
}
|
|
||||||
|
|
||||||
if (Caster != m && m.InLOS(Caster) && Caster.CanBeBeneficial(m, false, true) && m is not Golem)
|
|
||||||
{
|
|
||||||
targets.Add(m);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eable.Free();
|
||||||
|
|
||||||
Caster.PlaySound(0x244);
|
Caster.PlaySound(0x244);
|
||||||
Caster.FixedParticles(0x3709, 1, 30, 9965, 5, 7, EffectLayer.Waist);
|
Caster.FixedParticles(0x3709, 1, 30, 9965, 5, 7, EffectLayer.Waist);
|
||||||
Caster.FixedParticles(0x376A, 1, 30, 9502, 5, 3, EffectLayer.Waist);
|
Caster.FixedParticles(0x376A, 1, 30, 9502, 5, 3, EffectLayer.Waist);
|
||||||
|
|
@ -62,19 +62,18 @@ namespace Server.Spells.Chivalry
|
||||||
var sacrifice = false;
|
var sacrifice = false;
|
||||||
|
|
||||||
// TODO: Is there really a resurrection chance?
|
// TODO: Is there really a resurrection chance?
|
||||||
var resChance = 0.1 + 0.9 * Caster.Karma / 10000.0d;
|
var resChance = 0.1 + 0.9 * Caster.Karma / 10000;
|
||||||
|
|
||||||
for (var i = 0; i < targets.Count; ++i)
|
while (pool.Count > 0)
|
||||||
{
|
{
|
||||||
var m = targets[i];
|
var m = pool.Dequeue();
|
||||||
|
|
||||||
if (!m.Alive)
|
if (!m.Alive)
|
||||||
{
|
{
|
||||||
if (m.Region?.IsPartOf("Khaldun") == true)
|
if (m.Region?.IsPartOf("Khaldun") == true)
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// The veil of death in this area is too strong and resists thy efforts to restore life.
|
||||||
1010395
|
Caster.SendLocalizedMessage(1010395);
|
||||||
); // The veil of death in this area is too strong and resists thy efforts to restore life.
|
|
||||||
}
|
}
|
||||||
else if (resChance > Utility.RandomDouble())
|
else if (resChance > Utility.RandomDouble())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ namespace Server.Spells.Chivalry
|
||||||
else if (!SpellHelper.CheckTravel(Caster, map, loc, TravelCheckType.RecallTo))
|
else if (!SpellHelper.CheckTravel(Caster, map, loc, TravelCheckType.RecallTo))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
else if (map == Map.Felucca && Caster is PlayerMobile mobile && mobile.Young)
|
else if (map == Map.Felucca && Caster is PlayerMobile { Young: true } mobile)
|
||||||
{
|
{
|
||||||
mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young.
|
mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace Server.Spells.Necromancy
|
||||||
Reagent.DaemonBlood
|
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();
|
private static readonly Dictionary<Mobile, ExpireTimer> _table = new();
|
||||||
|
|
||||||
public BloodOathSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
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.
|
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.
|
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)
|
if (m.Player)
|
||||||
{
|
{
|
||||||
|
|
@ -67,8 +67,8 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
RemoveCurse(m);
|
RemoveCurse(m);
|
||||||
|
|
||||||
m_OathTable[Caster] = Caster;
|
_oathTable[Caster] = Caster;
|
||||||
m_OathTable[m] = Caster;
|
_oathTable[m] = Caster;
|
||||||
|
|
||||||
m.Spell?.OnCasterHurt();
|
m.Spell?.OnCasterHurt();
|
||||||
|
|
||||||
|
|
@ -106,12 +106,12 @@ namespace Server.Spells.Necromancy
|
||||||
if (_table.Remove(target, out var timer))
|
if (_table.Remove(target, out var timer))
|
||||||
{
|
{
|
||||||
var caster = timer.Caster;
|
var caster = timer.Caster;
|
||||||
if (m_OathTable.Remove(caster))
|
if (_oathTable.Remove(caster))
|
||||||
{
|
{
|
||||||
caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
|
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.
|
target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ namespace Server.Spells.Necromancy
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Mobile GetBloodOath(Mobile m) =>
|
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
|
private class ExpireTimer : Timer
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -114,30 +114,30 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
private class ExpireTimer : Timer
|
private class ExpireTimer : Timer
|
||||||
{
|
{
|
||||||
private readonly Mobile m_Mobile;
|
private Mobile _mobile;
|
||||||
private readonly ResistanceMod[] m_Mods;
|
private ResistanceMod[] _mods;
|
||||||
|
|
||||||
public ExpireTimer(Mobile m, ResistanceMod[] mods, TimeSpan delay) : base(delay)
|
public ExpireTimer(Mobile m, ResistanceMod[] mods, TimeSpan delay) : base(delay)
|
||||||
{
|
{
|
||||||
m_Mobile = m;
|
_mobile = m;
|
||||||
m_Mods = mods;
|
_mods = mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DoExpire()
|
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();
|
Stop();
|
||||||
BuffInfo.RemoveBuff(m_Mobile, BuffIcon.CorpseSkin);
|
BuffInfo.RemoveBuff(_mobile, BuffIcon.CorpseSkin);
|
||||||
_table.Remove(m_Mobile);
|
_table.Remove(_mobile);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnTick()
|
protected override void OnTick()
|
||||||
{
|
{
|
||||||
m_Mobile.SendLocalizedMessage(1061688); // Your skin returns to normal.
|
_mobile.SendLocalizedMessage(1061688); // Your skin returns to normal.
|
||||||
DoExpire();
|
DoExpire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Server.Spells.Necromancy
|
||||||
Caster.PlaySound(0x387);
|
Caster.PlaySound(0x387);
|
||||||
Caster.FixedParticles(0x3779, 1, 15, 9905, 32, 2, EffectLayer.Head);
|
Caster.FixedParticles(0x3779, 1, 15, 9905, 32, 2, EffectLayer.Head);
|
||||||
Caster.FixedParticles(0x37B9, 1, 14, 9502, 32, 5, (EffectLayer)255);
|
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);
|
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 class ExpireTimer : Timer
|
||||||
{
|
{
|
||||||
private readonly BaseWeapon m_Weapon;
|
private BaseWeapon _weapon;
|
||||||
|
|
||||||
public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay)
|
public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay) => _weapon = weapon;
|
||||||
{
|
|
||||||
m_Weapon = weapon;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnTick()
|
protected override void OnTick()
|
||||||
{
|
{
|
||||||
m_Weapon.Cursed = false;
|
_weapon.Cursed = false;
|
||||||
Effects.PlaySound(m_Weapon.GetWorldLocation(), m_Weapon.Map, 0xFA);
|
Effects.PlaySound(_weapon.GetWorldLocation(), _weapon.Map, 0xFA);
|
||||||
_table.Remove(m_Weapon);
|
_table.Remove(_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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Server.Spells.Necromancy
|
||||||
Reagent.DaemonBlood
|
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)
|
public MindRotSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
{
|
{
|
||||||
|
|
@ -52,13 +52,10 @@ namespace Server.Spells.Necromancy
|
||||||
m.PlaySound(0x258);
|
m.PlaySound(0x258);
|
||||||
m.FixedParticles(0x373A, 1, 17, 9903, 15, 4, EffectLayer.Head);
|
m.FixedParticles(0x373A, 1, 17, 9903, 15, 4, EffectLayer.Head);
|
||||||
|
|
||||||
var duration =
|
var duration = ((GetDamageSkill(Caster) - GetResistSkill(m)) / 5.0 + 20.0) * (m.Player ? 1.0 : 2.0);
|
||||||
TimeSpan.FromSeconds(
|
|
||||||
((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
|
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);
|
HarmfulSpell(m);
|
||||||
}
|
}
|
||||||
|
|
@ -73,11 +70,12 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
public static bool ClearMindRotScalar(Mobile m)
|
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.
|
m.SendLocalizedMessage(1060872); // Your mind feels normal again.
|
||||||
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot);
|
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,9 +86,9 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
public static bool GetMindRotScalar(Mobile m, ref double scalar)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,10 +99,11 @@ namespace Server.Spells.Necromancy
|
||||||
{
|
{
|
||||||
if (!_table.ContainsKey(target))
|
if (!_table.ContainsKey(target))
|
||||||
{
|
{
|
||||||
var tmpB = new MRBucket(scalar, new MRExpireTimer(target, duration));
|
var timer = new MRExpireTimer(target, scalar, duration);
|
||||||
_table.Add(target, tmpB);
|
timer.Start();
|
||||||
|
_table[target] = timer;
|
||||||
|
|
||||||
BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target));
|
BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target));
|
||||||
tmpB.m_MRExpireTimer.Start();
|
|
||||||
target.SendLocalizedMessage(1074384);
|
target.SendLocalizedMessage(1074384);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -112,37 +111,27 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
public class MRExpireTimer : Timer
|
public class MRExpireTimer : Timer
|
||||||
{
|
{
|
||||||
private readonly DateTime m_End;
|
private DateTime _end;
|
||||||
private readonly Mobile m_Target;
|
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),
|
||||||
TimeSpan.FromSeconds(1.0)
|
TimeSpan.FromSeconds(1.0)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
m_Target = target;
|
_double = scalar;
|
||||||
m_End = Core.Now + delay;
|
_target = target;
|
||||||
|
_end = Core.Now + delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnTick()
|
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;
|
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 =>
|
public override double CastDelayFastScalar =>
|
||||||
Core.SE
|
Core.SE ? base.CastDelayFastScalar : 0;
|
||||||
? base.CastDelayFastScalar
|
|
||||||
: 0; // Necromancer spells are not affected by fast cast items, though they are by fast cast recovery
|
|
||||||
|
|
||||||
public override int ComputeKarmaAward()
|
public override int ComputeKarmaAward()
|
||||||
{
|
{
|
||||||
|
|
@ -29,8 +28,8 @@ namespace Server.Spells.Necromancy
|
||||||
// int karma = -(70 + (10 * (int)Circle));
|
// int karma = -(70 + (10 * (int)Circle));
|
||||||
var karma = -(40 + (int)(10 * (CastDelayBase.TotalSeconds / CastDelaySecondsPerTick)));
|
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));
|
karma += AOS.Scale(karma, AosAttributes.GetValue(Caster, AosAttribute.IncreasedKarmaLoss));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,26 +90,26 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
private class InternalTimer : Timer
|
private class InternalTimer : Timer
|
||||||
{
|
{
|
||||||
private readonly Mobile m_Mobile;
|
private Mobile _mobile;
|
||||||
private readonly int m_ToRestore;
|
private int _toRestore;
|
||||||
|
|
||||||
public InternalTimer(Mobile m, double toRestore) : base(TimeSpan.FromSeconds(10.0))
|
public InternalTimer(Mobile m, double toRestore) : base(TimeSpan.FromSeconds(10.0))
|
||||||
{
|
{
|
||||||
|
|
||||||
m_Mobile = m;
|
_mobile = m;
|
||||||
m_ToRestore = (int)toRestore;
|
_toRestore = (int)toRestore;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnTick()
|
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;
|
||||||
using System.Collections.Generic;
|
using Server.Collections;
|
||||||
using Server.Items;
|
using Server.Items;
|
||||||
using Server.Mobiles;
|
using Server.Mobiles;
|
||||||
using Server.Targeting;
|
using Server.Targeting;
|
||||||
|
|
@ -16,8 +16,7 @@ namespace Server.Spells.Necromancy
|
||||||
Reagent.NoxCrystal
|
Reagent.NoxCrystal
|
||||||
);
|
);
|
||||||
|
|
||||||
public PoisonStrikeSpell(Mobile caster, Item scroll = null)
|
public PoisonStrikeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,11 +29,6 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
public void Target(Mobile m)
|
public void Target(Mobile m)
|
||||||
{
|
{
|
||||||
if (m == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CheckHSequence(m))
|
if (CheckHSequence(m))
|
||||||
{
|
{
|
||||||
SpellHelper.Turn(Caster, m);
|
SpellHelper.Turn(Caster, m);
|
||||||
|
|
@ -48,39 +42,39 @@ namespace Server.Spells.Necromancy
|
||||||
// Check magic resist for skill, but do not use return value
|
// Check magic resist for skill, but do not use return value
|
||||||
// reports from OSI: Necro spells don't give Resist gain
|
// 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;
|
var map = m.Map;
|
||||||
|
|
||||||
if (map != null)
|
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))
|
if (Caster.CanBeHarmful(m, false))
|
||||||
{
|
{
|
||||||
targets.Add(m);
|
pool.Enqueue(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
var eable = m.GetMobilesInRange(2);
|
var eable = m.GetMobilesInRange(2);
|
||||||
|
|
@ -92,15 +86,15 @@ namespace Server.Spells.Necromancy
|
||||||
SpellHelper.ValidIndirectTarget(Caster, targ) &&
|
SpellHelper.ValidIndirectTarget(Caster, targ) &&
|
||||||
Caster.CanBeHarmful(targ, false))
|
Caster.CanBeHarmful(targ, false))
|
||||||
{
|
{
|
||||||
targets.Add(targ);
|
pool.Enqueue(targ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eable.Free();
|
eable.Free();
|
||||||
|
|
||||||
for (var i = 0; i < targets.Count; ++i)
|
while (pool.Count > 0)
|
||||||
{
|
{
|
||||||
var targ = targets[i];
|
var targ = pool.Dequeue();
|
||||||
int num;
|
int num;
|
||||||
|
|
||||||
if (targ.InRange(m.Location, 0))
|
if (targ.InRange(m.Location, 0))
|
||||||
|
|
|
||||||
|
|
@ -70,42 +70,38 @@ namespace Server.Spells.Necromancy
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculations for the buff bar
|
// Calculations for the buff bar
|
||||||
var spiritlevel = Caster.Skills.SpiritSpeak.Value / 10;
|
var spiritlevel = Math.Min(4, Caster.Skills.SpiritSpeak.Value / 10);
|
||||||
if (spiritlevel < 4)
|
|
||||||
|
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;
|
--count;
|
||||||
}
|
if (hitDelay > 1)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (i_MaxCount < 5)
|
if (maxCount < 5)
|
||||||
{
|
{
|
||||||
--i_HitDelay;
|
--hitDelay;
|
||||||
}
|
}
|
||||||
else
|
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));
|
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, 1075795, t_Duration, m, args));
|
||||||
|
|
||||||
FinishSequence();
|
FinishSequence();
|
||||||
|
|
@ -130,106 +126,98 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
private class InternalTimer : Timer
|
private class InternalTimer : Timer
|
||||||
{
|
{
|
||||||
private readonly Mobile m_From;
|
private Mobile _from;
|
||||||
private readonly double m_MaxBaseDamage;
|
private double _maxBaseDamage;
|
||||||
private readonly int m_MaxCount;
|
private int _maxCount;
|
||||||
private readonly double m_MinBaseDamage;
|
private double _minBaseDamage;
|
||||||
private readonly Mobile m_Target;
|
private Mobile _target;
|
||||||
private int m_Count;
|
private int _count;
|
||||||
private int m_HitDelay;
|
private int _hitDelay;
|
||||||
|
private DateTime _nextHit;
|
||||||
private DateTime m_NextHit;
|
|
||||||
|
|
||||||
public InternalTimer(Mobile target, Mobile from) : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))
|
public InternalTimer(Mobile target, Mobile from) : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))
|
||||||
{
|
{
|
||||||
|
|
||||||
m_Target = target;
|
_target = target;
|
||||||
m_From = from;
|
_from = from;
|
||||||
|
|
||||||
var spiritLevel = from.Skills.SpiritSpeak.Value / 10;
|
var spiritLevel = from.Skills.SpiritSpeak.Value / 10;
|
||||||
|
|
||||||
m_MinBaseDamage = spiritLevel - 2;
|
_minBaseDamage = spiritLevel - 2;
|
||||||
m_MaxBaseDamage = spiritLevel + 1;
|
_maxBaseDamage = spiritLevel + 1;
|
||||||
|
|
||||||
m_HitDelay = 5;
|
_hitDelay = 5;
|
||||||
m_NextHit = Core.Now + TimeSpan.FromSeconds(m_HitDelay);
|
_nextHit = Core.Now + TimeSpan.FromSeconds(_hitDelay);
|
||||||
|
|
||||||
m_Count = (int)spiritLevel;
|
_maxCount = _count = Math.Min(4, (int)spiritLevel);
|
||||||
|
|
||||||
if (m_Count < 4)
|
|
||||||
{
|
|
||||||
m_Count = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_MaxCount = m_Count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnTick()
|
protected override void OnTick()
|
||||||
{
|
{
|
||||||
if (!m_Target.Alive)
|
if (!_target.Alive)
|
||||||
{
|
{
|
||||||
_table.Remove(m_Target);
|
_table.Remove(_target);
|
||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_Target.Alive || Core.Now < m_NextHit)
|
if (!_target.Alive || Core.Now < _nextHit)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
--m_Count;
|
--_count;
|
||||||
|
|
||||||
if (m_HitDelay > 1)
|
if (_hitDelay > 1)
|
||||||
{
|
{
|
||||||
if (m_MaxCount < 5)
|
if (_maxCount < 5)
|
||||||
{
|
{
|
||||||
--m_HitDelay;
|
--_hitDelay;
|
||||||
}
|
}
|
||||||
else
|
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)
|
if (delay <= 5)
|
||||||
{
|
{
|
||||||
m_HitDelay = delay;
|
_hitDelay = delay;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_HitDelay = 5;
|
_hitDelay = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Count == 0)
|
if (_count == 0)
|
||||||
{
|
{
|
||||||
m_Target.SendLocalizedMessage(1061687); // You can breath normally again.
|
_target.SendLocalizedMessage(1061687); // You can breath normally again.
|
||||||
_table.Remove(m_Target);
|
_table.Remove(_target);
|
||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
else
|
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)
|
if (damage < 1)
|
||||||
{
|
{
|
||||||
damage = 1;
|
damage = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_Target.Player)
|
if (!_target.Player)
|
||||||
{
|
{
|
||||||
damage *= 1.75;
|
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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Server.Collections;
|
||||||
using Server.Items;
|
using Server.Items;
|
||||||
using Server.Mobiles;
|
using Server.Mobiles;
|
||||||
|
|
||||||
|
|
@ -42,35 +43,40 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
if (map != null)
|
if (map != null)
|
||||||
{
|
{
|
||||||
var targets = new List<Mobile>();
|
using var pool = PooledRefQueue<Mobile>.Create();
|
||||||
|
|
||||||
var cbc = Caster as BaseCreature;
|
var cbc = Caster as BaseCreature;
|
||||||
var isMonster = cbc?.Controlled == false && !cbc.Summoned;
|
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)) &&
|
if (Caster == m || !Caster.InLOS(m) || (!isMonster && !SpellHelper.ValidIndirectTarget(Caster, m)) ||
|
||||||
Caster.CanBeHarmful(m, false))
|
!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)
|
||||||
{
|
|
||||||
if (!bc.Controlled && !bc.Summoned && bc.Team == cbc.Team)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!m.Player)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!m.Player)
|
||||||
targets.Add(m);
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pool.Enqueue(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eable.Free();
|
||||||
|
|
||||||
Effects.PlaySound(Caster.Location, map, 0x1FB);
|
Effects.PlaySound(Caster.Location, map, 0x1FB);
|
||||||
Effects.PlaySound(Caster.Location, map, 0x10B);
|
Effects.PlaySound(Caster.Location, map, 0x10B);
|
||||||
Effects.SendLocationParticles(
|
Effects.SendLocationParticles(
|
||||||
|
|
@ -84,9 +90,9 @@ namespace Server.Spells.Necromancy
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
for (var i = 0; i < targets.Count; ++i)
|
while (pool.Count > 0)
|
||||||
{
|
{
|
||||||
var m = targets[i];
|
var m = pool.Dequeue();
|
||||||
|
|
||||||
Caster.DoHarmful(m);
|
Caster.DoHarmful(m);
|
||||||
m.FixedParticles(0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255);
|
m.FixedParticles(0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ namespace Server.Spells.Necromancy
|
||||||
|
|
||||||
public override void RemoveEffect(Mobile m)
|
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;
|
mobile.IgnoreMobiles = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,7 @@ namespace Server.Spells.Ninjitsu
|
||||||
|
|
||||||
private bool m_WasMoving;
|
private bool m_WasMoving;
|
||||||
|
|
||||||
public AnimalForm(Mobile caster, Item scroll)
|
public AnimalForm(Mobile caster, Item scroll) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -477,10 +476,8 @@ namespace Server.Spells.Ninjitsu
|
||||||
|
|
||||||
if (mana > m_Caster.Mana)
|
if (mana > m_Caster.Mana)
|
||||||
{
|
{
|
||||||
m_Caster.SendLocalizedMessage(
|
// You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
||||||
1060174, // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
m_Caster.SendLocalizedMessage(1060174, mana.ToString());
|
||||||
mana.ToString()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
else if (m_Caster is PlayerMobile mobile && mobile.MountBlockReason != BlockMountType.None)
|
else if (m_Caster is PlayerMobile mobile && mobile.MountBlockReason != BlockMountType.None)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,8 @@ namespace Server.Spells.Ninjitsu
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClearCurrentMove(attacker);
|
||||||
|
|
||||||
if (GetBonus(attacker) == 0.0)
|
if (GetBonus(attacker) == 0.0)
|
||||||
{
|
{
|
||||||
attacker.SendLocalizedMessage(1063101); // You were too close to your target to cause any additional damage.
|
attacker.SendLocalizedMessage(1063101); // You were too close to your target to cause any additional damage.
|
||||||
|
|
@ -73,15 +75,12 @@ namespace Server.Spells.Ninjitsu
|
||||||
attacker.FixedParticles(0x37BE, 1, 5, 0x26BD, 0x0, 0x1, EffectLayer.Waist);
|
attacker.FixedParticles(0x37BE, 1, 5, 0x26BD, 0x0, 0x1, EffectLayer.Waist);
|
||||||
attacker.PlaySound(0x510);
|
attacker.PlaySound(0x510);
|
||||||
|
|
||||||
attacker.SendLocalizedMessage(
|
// Your quick flight to your target causes extra damage as you strike!
|
||||||
1063100
|
attacker.SendLocalizedMessage(1063100);
|
||||||
); // Your quick flight to your target causes extra damage as you strike!
|
|
||||||
defender.FixedParticles(0x37BE, 1, 5, 0x26BD, 0, 0x1, EffectLayer.Waist);
|
defender.FixedParticles(0x37BE, 1, 5, 0x26BD, 0, 0x1, EffectLayer.Waist);
|
||||||
|
|
||||||
CheckGain(attacker);
|
CheckGain(attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearCurrentMove(attacker);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnClearMove(Mobile from)
|
public override void OnClearMove(Mobile from)
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,8 @@ namespace Server.Spells.Ninjitsu
|
||||||
|
|
||||||
if (Caster.Followers + 1 > Caster.FollowersMax)
|
if (Caster.Followers + 1 > Caster.FollowersMax)
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// You cannot summon a mirror image because you have too many followers.
|
||||||
1063133
|
Caster.SendLocalizedMessage(1063133);
|
||||||
); // You cannot summon a mirror image because you have too many followers.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,9 +100,8 @@ namespace Server.Spells.Ninjitsu
|
||||||
}
|
}
|
||||||
else if (Caster.Followers + 1 > Caster.FollowersMax)
|
else if (Caster.Followers + 1 > Caster.FollowersMax)
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// You cannot summon a mirror image because you have too many followers.
|
||||||
1063133
|
Caster.SendLocalizedMessage(1063133);
|
||||||
); // You cannot summon a mirror image because you have too many followers.
|
|
||||||
}
|
}
|
||||||
else if (TransformationSpellHelper.UnderTransformation(Caster, typeof(HorrificBeastSpell)))
|
else if (TransformationSpellHelper.UnderTransformation(Caster, typeof(HorrificBeastSpell)))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -44,20 +44,15 @@ namespace Server.Spells.Ninjitsu
|
||||||
|
|
||||||
if (Caster.Skills[CastSkill].Value < RequiredSkill)
|
if (Caster.Skills[CastSkill].Value < RequiredSkill)
|
||||||
{
|
{
|
||||||
var args = $"{RequiredSkill:F1}\t{CastSkill.ToString()}\t ";
|
// You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
|
||||||
Caster.SendLocalizedMessage(
|
Caster.SendLocalizedMessage(1063013, $"{RequiredSkill:F1}\t{CastSkill.ToString()}\t ");
|
||||||
1063013,
|
|
||||||
args
|
|
||||||
); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Caster.Mana < mana)
|
if (Caster.Mana < mana)
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
||||||
1060174,
|
Caster.SendLocalizedMessage(1060174, mana.ToString());
|
||||||
mana.ToString()
|
|
||||||
); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,19 +65,15 @@ namespace Server.Spells.Ninjitsu
|
||||||
|
|
||||||
if (Caster.Skills[CastSkill].Value < RequiredSkill)
|
if (Caster.Skills[CastSkill].Value < RequiredSkill)
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack!
|
||||||
1063352,
|
Caster.SendLocalizedMessage(1063352, RequiredSkill.ToString("F1"));
|
||||||
RequiredSkill.ToString("F1")
|
|
||||||
); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack!
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Caster.Mana < mana)
|
if (Caster.Mana < mana)
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
||||||
1060174,
|
Caster.SendLocalizedMessage(1060174, mana.ToString());
|
||||||
mana.ToString()
|
|
||||||
); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using Server.Collections;
|
||||||
using Server.Items;
|
using Server.Items;
|
||||||
using Server.Mobiles;
|
using Server.Mobiles;
|
||||||
|
|
||||||
|
|
@ -13,8 +13,7 @@ namespace Server.Spells.Spellweaving
|
||||||
-1
|
-1
|
||||||
);
|
);
|
||||||
|
|
||||||
public ArcaneCircleSpell(Mobile caster, Item scroll = null)
|
public ArcaneCircleSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,13 +26,12 @@ namespace Server.Spells.Spellweaving
|
||||||
{
|
{
|
||||||
if (!IsValidLocation(Caster.Location, Caster.Map))
|
if (!IsValidLocation(Caster.Location, Caster.Map))
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(
|
// You must be standing on an arcane circle, pentagram or abattoir to use this spell.
|
||||||
1072705
|
Caster.SendLocalizedMessage(1072705);
|
||||||
); // You must be standing on an arcane circle, pentagram or abbatoir to use this spell.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetArcanists().Count < 2)
|
if (!CheckArcanists())
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(1080452); // There are not enough spellweavers present to create an Arcane Focus.
|
Caster.SendLocalizedMessage(1080452); // There are not enough spellweavers present to create an Arcane Focus.
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -49,21 +47,18 @@ namespace Server.Spells.Spellweaving
|
||||||
Caster.FixedParticles(0x3779, 10, 20, 0x0, EffectLayer.Waist);
|
Caster.FixedParticles(0x3779, 10, 20, 0x0, EffectLayer.Waist);
|
||||||
Caster.PlaySound(0x5C0);
|
Caster.PlaySound(0x5C0);
|
||||||
|
|
||||||
var Arcanists = GetArcanists();
|
var spellWeaving = Caster.Skills.Spellweaving.Value;
|
||||||
|
using var pool = GetArcanists(spellWeaving);
|
||||||
|
|
||||||
var duration = TimeSpan.FromHours(Math.Max(1, (int)(Caster.Skills.Spellweaving.Value / 24)));
|
var duration = TimeSpan.FromHours(Math.Max(1, (int)(spellWeaving / 24)));
|
||||||
|
|
||||||
var strengthBonus =
|
var strengthBonus =
|
||||||
Math.Min(
|
Math.Min(pool.Count, IsSanctuary(Caster.Location, Caster.Map) ? 6 : 5);
|
||||||
Arcanists.Count,
|
|
||||||
IsSanctuary(Caster.Location, Caster.Map)
|
|
||||||
? 6
|
|
||||||
: 5
|
|
||||||
); // The Sanctuary is a special, single location place
|
|
||||||
|
|
||||||
for (var i = 0; i < Arcanists.Count; i++)
|
while (pool.Count > 0)
|
||||||
{
|
{
|
||||||
GiveArcaneFocus(Arcanists[i], duration, strengthBonus);
|
var m = pool.Dequeue();
|
||||||
|
GiveArcaneFocus(m, duration, strengthBonus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,6 +103,7 @@ namespace Server.Spells.Spellweaving
|
||||||
{
|
{
|
||||||
if (item.Z + item.ItemData.CalcHeight == location.Z && IsValidTile(item.ItemID))
|
if (item.Z + item.ItemData.CalcHeight == location.Z && IsValidTile(item.ItemID))
|
||||||
{
|
{
|
||||||
|
eable.Free();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -120,27 +116,43 @@ namespace Server.Spells.Spellweaving
|
||||||
public static bool IsValidTile(int itemID) =>
|
public static bool IsValidTile(int itemID) =>
|
||||||
itemID is 0xFEA or 0x1216 or 0x307F or 0x1D10 or 0x1D0F or 0x1D1F or 0x1D12;
|
itemID is 0xFEA or 0x1216 or 0x307F or 0x1D10 or 0x1D0F or 0x1D1F or 0x1D12;
|
||||||
|
|
||||||
private List<Mobile> GetArcanists()
|
private bool CheckArcanists()
|
||||||
{
|
{
|
||||||
var weavers = new List<Mobile> { Caster };
|
var spellWeaving = Caster.Skills.Spellweaving.Value;
|
||||||
|
var eable = Caster.GetMobilesInRange(1);
|
||||||
|
foreach (var m in eable)
|
||||||
|
{
|
||||||
|
if (m != Caster && m is PlayerMobile && Caster.CanBeBeneficial(m, false) &&
|
||||||
|
Math.Abs(spellWeaving - m.Skills.Spellweaving.Value) <= 20)
|
||||||
|
{
|
||||||
|
eable.Free();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eable.Free();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PooledRefQueue<Mobile> GetArcanists(double spellWeaving)
|
||||||
|
{
|
||||||
// OSI Verified: Even enemies/combatants count
|
// OSI Verified: Even enemies/combatants count
|
||||||
// Everyone gets the Arcane Focus, power capped elsewhere
|
// Everyone gets the Arcane Focus, power capped elsewhere
|
||||||
|
|
||||||
|
var pool = PooledRefQueue<Mobile>.Create();
|
||||||
var eable = Caster.GetMobilesInRange(1);
|
var eable = Caster.GetMobilesInRange(1);
|
||||||
|
|
||||||
foreach (var m in eable)
|
foreach (var m in eable)
|
||||||
{
|
{
|
||||||
if (m != Caster && m is PlayerMobile && Caster.CanBeBeneficial(m, false) &&
|
if (m != Caster && m is PlayerMobile && Caster.CanBeBeneficial(m, false) &&
|
||||||
Math.Abs(Caster.Skills.Spellweaving.Value - m.Skills.Spellweaving.Value) <= 20)
|
Math.Abs(spellWeaving - m.Skills.Spellweaving.Value) <= 20)
|
||||||
{
|
{
|
||||||
weavers.Add(m);
|
pool.Enqueue(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eable.Free();
|
eable.Free();
|
||||||
|
return pool;
|
||||||
return weavers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GiveArcaneFocus(Mobile to, TimeSpan duration, int strengthBonus)
|
private void GiveArcaneFocus(Mobile to, TimeSpan duration, int strengthBonus)
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,7 @@ namespace Server.Spells.Spellweaving
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CheckCast()
|
public override bool CheckCast() => TransformationSpellHelper.CheckCast(Caster, this) && base.CheckCast();
|
||||||
{
|
|
||||||
if (!TransformationSpellHelper.CheckCast(Caster, this))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.CheckCast();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnCast()
|
public override void OnCast()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,7 @@ namespace Server.Spells.Spellweaving
|
||||||
{
|
{
|
||||||
private int m_CastTimeFocusLevel;
|
private int m_CastTimeFocusLevel;
|
||||||
|
|
||||||
public ArcanistSpell(Mobile caster, Item scroll, SpellInfo info)
|
public ArcanistSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info)
|
||||||
: base(caster, scroll, info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,9 +46,8 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
if (!CheckExpansion(caster))
|
if (!CheckExpansion(caster))
|
||||||
{
|
{
|
||||||
caster.SendLocalizedMessage(
|
// You must upgrade to the Mondain's Legacy Expansion Pack before using that ability
|
||||||
1072176
|
caster.SendLocalizedMessage(1072176);
|
||||||
); // You must upgrade to the Mondain's Legacy Expansion Pack before using that ability
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,9 +57,8 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
if (context?.Spellweaving != true)
|
if (context?.Spellweaving != true)
|
||||||
{
|
{
|
||||||
mobile.SendLocalizedMessage(
|
// You must have completed the epic arcanist quest to use this ability.
|
||||||
1073220
|
mobile.SendLocalizedMessage(1073220);
|
||||||
); // You must have completed the epic arcanist quest to use this ability.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -70,19 +67,15 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
if (caster.Mana < mana)
|
if (caster.Mana < mana)
|
||||||
{
|
{
|
||||||
caster.SendLocalizedMessage(
|
// You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
||||||
1060174,
|
caster.SendLocalizedMessage(1060174, mana.ToString());
|
||||||
mana.ToString()
|
|
||||||
); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (caster.Skills[CastSkill].Value < RequiredSkill)
|
if (caster.Skills[CastSkill].Value < RequiredSkill)
|
||||||
{
|
{
|
||||||
caster.SendLocalizedMessage(
|
// You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
|
||||||
1063013,
|
caster.SendLocalizedMessage(1063013, $"{RequiredSkill:F1}\t{"#1044114"}");
|
||||||
$"{RequiredSkill:F1}\t{"#1044114"}"
|
|
||||||
); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,17 +130,12 @@ namespace Server.Spells.Spellweaving
|
||||||
(50 + 2 * (GetResistSkill(m) - GetDamageSkill(Caster))) /
|
(50 + 2 * (GetResistSkill(m) - GetDamageSkill(Caster))) /
|
||||||
100; // TODO: According to the guide this is it.. but.. is it correct per OSI?
|
100; // TODO: According to the guide this is it.. but.. is it correct per OSI?
|
||||||
|
|
||||||
if (percent <= 0)
|
return percent switch
|
||||||
{
|
{
|
||||||
return false;
|
<= 0 => false,
|
||||||
}
|
>= 1.0 => true,
|
||||||
|
_ => percent >= Utility.RandomDouble()
|
||||||
if (percent >= 1.0)
|
};
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return percent >= Utility.RandomDouble();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,10 +83,8 @@ namespace Server.Spells.Spellweaving
|
||||||
damage -= absorbed;
|
damage -= absorbed;
|
||||||
defender.MeleeDamageAbsorb -= absorbed;
|
defender.MeleeDamageAbsorb -= absorbed;
|
||||||
|
|
||||||
defender.SendLocalizedMessage(
|
// ~1_damage~ point(s) of damage have been absorbed. A total of ~2_remaining~ point(s) of shielding remain.
|
||||||
1075127,
|
defender.SendLocalizedMessage(1075127, $"{absorbed}\t{defender.MeleeDamageAbsorb}");
|
||||||
$"{absorbed}\t{defender.MeleeDamageAbsorb}"
|
|
||||||
); // ~1_damage~ point(s) of damage have been absorbed. A total of ~2_remaining~ point(s) of shielding remain.
|
|
||||||
|
|
||||||
if (defender.MeleeDamageAbsorb <= 0)
|
if (defender.MeleeDamageAbsorb <= 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,7 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
BuffInfo.AddBuff(
|
BuffInfo.AddBuff(
|
||||||
m,
|
m,
|
||||||
new BuffInfo(
|
new BuffInfo(BuffIcon.EssenceOfWind, 1075802, duration, m, $"{fcMalus}\t{ssiMalus}")
|
||||||
BuffIcon.EssenceOfWind,
|
|
||||||
1075802,
|
|
||||||
duration,
|
|
||||||
m,
|
|
||||||
$"{fcMalus.ToString()}\t{ssiMalus.ToString()}"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,19 +76,19 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
public static bool IsDebuffed(Mobile m) => _table.ContainsKey(m);
|
public static bool IsDebuffed(Mobile m) => _table.ContainsKey(m);
|
||||||
|
|
||||||
public static void StopDebuffing(Mobile m, bool message)
|
public static void StopDebuffing(Mobile m)
|
||||||
{
|
{
|
||||||
if (_table.TryGetValue(m, out var timer))
|
if (_table.TryGetValue(m, out var timer))
|
||||||
{
|
{
|
||||||
timer.DoExpire(message);
|
timer.DoExpire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class EssenceOfWindTimer : Timer
|
private class EssenceOfWindTimer : Timer
|
||||||
{
|
{
|
||||||
private readonly Mobile _defender;
|
private Mobile _defender;
|
||||||
internal readonly int _fcMalus;
|
internal int _fcMalus;
|
||||||
internal readonly int _ssiMalus;
|
internal int _ssiMalus;
|
||||||
|
|
||||||
internal EssenceOfWindTimer(Mobile defender, int fcMalus, int ssiMalus, TimeSpan duration) : base(duration)
|
internal EssenceOfWindTimer(Mobile defender, int fcMalus, int ssiMalus, TimeSpan duration) : base(duration)
|
||||||
{
|
{
|
||||||
|
|
@ -108,7 +102,7 @@ namespace Server.Spells.Spellweaving
|
||||||
DoExpire();
|
DoExpire();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void DoExpire(bool message = true)
|
internal void DoExpire()
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
_table.Remove(_defender);
|
_table.Remove(_defender);
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@ namespace Server.Spells.Spellweaving
|
||||||
-1
|
-1
|
||||||
);
|
);
|
||||||
|
|
||||||
public EtherealVoyageSpell(Mobile caster, Item scroll = null)
|
public EtherealVoyageSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,9 +68,8 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
Timer.StartTimer(duration, () => RemoveEffect(Caster));
|
Timer.StartTimer(duration, () => RemoveEffect(Caster));
|
||||||
|
|
||||||
Caster.BeginAction(
|
// Cannot cast this spell for another 5 minutes(300sec) after effect removed.
|
||||||
typeof(EtherealVoyageSpell)
|
Caster.BeginAction<EtherealVoyageSpell>();
|
||||||
); // Cannot cast this spell for another 5 minutes(300sec) after effect removed.
|
|
||||||
|
|
||||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.EtherealVoyage, 1031613, 1075805, duration, Caster));
|
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.EtherealVoyage, 1031613, 1075805, duration, Caster));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,7 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
private static readonly Dictionary<Mobile, ExpireTimer> _table = new();
|
private static readonly Dictionary<Mobile, ExpireTimer> _table = new();
|
||||||
|
|
||||||
public GiftOfLifeSpell(Mobile caster, Item scroll = null)
|
public GiftOfLifeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,7 +33,7 @@ namespace Server.Spells.Spellweaving
|
||||||
{
|
{
|
||||||
// As per Osi: Nothing happens.
|
// As per Osi: Nothing happens.
|
||||||
}
|
}
|
||||||
else if (m != Caster && !(m is BaseCreature bc && bc.IsBonded && bc.ControlMaster == Caster))
|
else if (m != Caster && !(m is BaseCreature { IsBonded: true } bc && bc.ControlMaster == Caster))
|
||||||
{
|
{
|
||||||
Caster.SendLocalizedMessage(1072077); // You may only cast this spell on yourself or a bonded pet.
|
Caster.SendLocalizedMessage(1072077); // You may only cast this spell on yourself or a bonded pet.
|
||||||
}
|
}
|
||||||
|
|
@ -148,12 +147,11 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
private class ExpireTimer : Timer
|
private class ExpireTimer : Timer
|
||||||
{
|
{
|
||||||
private readonly Mobile m_Mobile;
|
private Mobile _mobile;
|
||||||
|
|
||||||
public ExpireTimer(Mobile m, TimeSpan delay, GiftOfLifeSpell spell)
|
public ExpireTimer(Mobile m, TimeSpan delay, GiftOfLifeSpell spell) : base(delay)
|
||||||
: base(delay)
|
|
||||||
{
|
{
|
||||||
m_Mobile = m;
|
_mobile = m;
|
||||||
Spell = spell;
|
Spell = spell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,10 +166,10 @@ namespace Server.Spells.Spellweaving
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
m_Mobile.SendLocalizedMessage(1074776); // You are no longer protected with Gift of Life.
|
_mobile.SendLocalizedMessage(1074776); // You are no longer protected with Gift of Life.
|
||||||
_table.Remove(m_Mobile);
|
_table.Remove(_mobile);
|
||||||
|
|
||||||
BuffInfo.RemoveBuff(m_Mobile, BuffIcon.GiftOfLife);
|
BuffInfo.RemoveBuff(_mobile, BuffIcon.GiftOfLife);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
private static readonly Dictionary<Mobile, GiftOfRenewalTimer> _table = new();
|
private static readonly Dictionary<Mobile, GiftOfRenewalTimer> _table = new();
|
||||||
|
|
||||||
public GiftOfRenewalSpell(Mobile caster, Item scroll = null)
|
public GiftOfRenewalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,7 +81,7 @@ namespace Server.Spells.Spellweaving
|
||||||
if (_table.Remove(m, out var timer))
|
if (_table.Remove(m, out var timer))
|
||||||
{
|
{
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
Timer.StartTimer(TimeSpan.FromSeconds(60), timer.m_Caster.EndAction<GiftOfRenewalSpell>);
|
Timer.StartTimer(TimeSpan.FromSeconds(60), timer._caster.EndAction<GiftOfRenewalSpell>);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,52 +90,50 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
private class GiftOfRenewalTimer : Timer
|
private class GiftOfRenewalTimer : Timer
|
||||||
{
|
{
|
||||||
public readonly Mobile m_Caster;
|
public Mobile _caster;
|
||||||
public readonly int m_HitsPerRound;
|
public int _hitsPerRound;
|
||||||
public readonly Mobile m_Mobile;
|
public Mobile _mobile;
|
||||||
|
|
||||||
internal GiftOfRenewalTimer(Mobile caster, Mobile mobile, int hitsPerRound, int duration)
|
internal GiftOfRenewalTimer(Mobile caster, Mobile mobile, int hitsPerRound, int duration)
|
||||||
: base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0), duration / 2)
|
: base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0), duration / 2)
|
||||||
{
|
{
|
||||||
m_Caster = caster;
|
_caster = caster;
|
||||||
m_Mobile = mobile;
|
_mobile = mobile;
|
||||||
m_HitsPerRound = hitsPerRound;
|
_hitsPerRound = hitsPerRound;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnTick()
|
protected override void OnTick()
|
||||||
{
|
{
|
||||||
if (Index + 1 == Count)
|
if (Index + 1 == Count)
|
||||||
{
|
{
|
||||||
StopEffect(m_Mobile);
|
StopEffect(_mobile);
|
||||||
m_Mobile.PlaySound(0x455);
|
_mobile.PlaySound(0x455);
|
||||||
m_Mobile.SendLocalizedMessage(1075071); // The Gift of Renewal has faded.
|
_mobile.SendLocalizedMessage(1075071); // The Gift of Renewal has faded.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var m = m_Mobile;
|
if (!_table.ContainsKey(_mobile))
|
||||||
|
|
||||||
if (!_table.ContainsKey(m))
|
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m.Alive)
|
if (!_mobile.Alive)
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
StopEffect(m);
|
StopEffect(_mobile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m.Hits >= m.HitsMax)
|
if (_mobile.Hits >= _mobile.HitsMax)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var toHeal = m_HitsPerRound;
|
var toHeal = _hitsPerRound;
|
||||||
|
|
||||||
SpellHelper.Heal(toHeal, m, m_Caster);
|
SpellHelper.Heal(toHeal, _mobile, _caster);
|
||||||
m.FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist);
|
_mobile.FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
private static readonly Dictionary<BaseWeapon, ImmolatingWeaponTimer> _table = new();
|
private static readonly Dictionary<BaseWeapon, ImmolatingWeaponTimer> _table = new();
|
||||||
|
|
||||||
public ImmolatingWeaponSpell(Mobile caster, Item scroll = null)
|
public ImmolatingWeaponSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,9 +96,9 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
private class ImmolatingWeaponTimer : Timer
|
private class ImmolatingWeaponTimer : Timer
|
||||||
{
|
{
|
||||||
public readonly Mobile _caster;
|
public Mobile _caster;
|
||||||
public readonly int _damage;
|
public int _damage;
|
||||||
public readonly BaseWeapon _weapon;
|
public BaseWeapon _weapon;
|
||||||
|
|
||||||
public ImmolatingWeaponTimer(TimeSpan duration, int damage, Mobile caster, BaseWeapon weapon) : base(duration)
|
public ImmolatingWeaponTimer(TimeSpan duration, int damage, Mobile caster, BaseWeapon weapon) : base(duration)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ namespace Server.Spells.Spellweaving
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
public NatureFurySpell(Mobile caster, Item scroll = null)
|
public NatureFurySpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,22 +78,21 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
private class InternalTimer : Timer
|
private class InternalTimer : Timer
|
||||||
{
|
{
|
||||||
private readonly NatureFury m_NatureFury;
|
private readonly NatureFury _natureFury;
|
||||||
|
|
||||||
public InternalTimer(NatureFury nf)
|
public InternalTimer(NatureFury nf) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) =>
|
||||||
: base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) =>
|
_natureFury = nf;
|
||||||
m_NatureFury = nf;
|
|
||||||
|
|
||||||
protected override void OnTick()
|
protected override void OnTick()
|
||||||
{
|
{
|
||||||
if (m_NatureFury.Deleted || !m_NatureFury.Alive || m_NatureFury.DamageMin > 20)
|
if (_natureFury.Deleted || !_natureFury.Alive || _natureFury.DamageMin > 20)
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++m_NatureFury.DamageMin;
|
++_natureFury.DamageMin;
|
||||||
++m_NatureFury.DamageMax;
|
++_natureFury.DamageMax;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ namespace Server.Spells.Spellweaving
|
||||||
-1
|
-1
|
||||||
);
|
);
|
||||||
|
|
||||||
public SummonFeySpell(Mobile caster, Item scroll = null)
|
public SummonFeySpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,18 +25,15 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
public override bool CheckSequence()
|
public override bool CheckSequence()
|
||||||
{
|
{
|
||||||
var caster = Caster;
|
|
||||||
|
|
||||||
// This is done after casting completes
|
// This is done after casting completes
|
||||||
if (caster is PlayerMobile mobile)
|
if (Caster is PlayerMobile mobile)
|
||||||
{
|
{
|
||||||
var context = MLQuestSystem.GetContext(mobile);
|
var context = MLQuestSystem.GetContext(mobile);
|
||||||
|
|
||||||
if (context?.SummonFey != true)
|
if (context?.SummonFey != true)
|
||||||
{
|
{
|
||||||
mobile.SendLocalizedMessage(
|
// You haven't forged a friendship with the fey and are unable to summon their aid.
|
||||||
1074563
|
mobile.SendLocalizedMessage(1074563);
|
||||||
); // You haven't forged a friendship with the fey and are unable to summon their aid.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ namespace Server.Spells.Spellweaving
|
||||||
-1
|
-1
|
||||||
);
|
);
|
||||||
|
|
||||||
public SummonFiendSpell(Mobile caster, Item scroll = null)
|
public SummonFiendSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,10 +25,8 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
public override bool CheckSequence()
|
public override bool CheckSequence()
|
||||||
{
|
{
|
||||||
var caster = Caster;
|
|
||||||
|
|
||||||
// This is done after casting completes
|
// This is done after casting completes
|
||||||
if (caster is PlayerMobile mobile)
|
if (Caster is PlayerMobile mobile)
|
||||||
{
|
{
|
||||||
var context = MLQuestSystem.GetContext(mobile);
|
var context = MLQuestSystem.GetContext(mobile);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@ namespace Server.Spells.Spellweaving
|
||||||
|
|
||||||
private static readonly Dictionary<Mobile, TimerExecutionToken> _table = new();
|
private static readonly Dictionary<Mobile, TimerExecutionToken> _table = new();
|
||||||
|
|
||||||
public ThunderstormSpell(Mobile caster, Item scroll = null)
|
public ThunderstormSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||||
: base(caster, scroll, _info)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue