fix(spells): Fixes interruption of spells (#702)
This commit is contained in:
parent
50dd7a1146
commit
e6de7a5898
6 changed files with 64 additions and 55 deletions
|
|
@ -262,7 +262,7 @@ namespace Server.Mobiles
|
||||||
private readonly List<Type> m_SpellAttack; // List of attack spell/power
|
private readonly List<Type> m_SpellAttack; // List of attack spell/power
|
||||||
private readonly List<Type> m_SpellDefense; // List of defensive spell/power
|
private readonly List<Type> m_SpellDefense; // List of defensive spell/power
|
||||||
|
|
||||||
private bool m_bSummoned;
|
private bool _summoned;
|
||||||
|
|
||||||
private bool m_bTamable;
|
private bool m_bTamable;
|
||||||
private int m_ColdResistance;
|
private int m_ColdResistance;
|
||||||
|
|
@ -554,7 +554,7 @@ namespace Server.Mobiles
|
||||||
Summoned && m_ControlMaster != null &&
|
Summoned && m_ControlMaster != null &&
|
||||||
SummonFamiliarSpell.Table.TryGetValue(m_ControlMaster, out var bc) && bc == this;
|
SummonFamiliarSpell.Table.TryGetValue(m_ControlMaster, out var bc) && bc == this;
|
||||||
|
|
||||||
public virtual bool DeleteCorpseOnDeath => !Core.AOS && m_bSummoned;
|
public virtual bool DeleteCorpseOnDeath => !Core.AOS && _summoned;
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.GameMaster)]
|
[CommandProperty(AccessLevel.GameMaster)]
|
||||||
public int Loyalty
|
public int Loyalty
|
||||||
|
|
@ -824,17 +824,17 @@ namespace Server.Mobiles
|
||||||
[CommandProperty(AccessLevel.Administrator)]
|
[CommandProperty(AccessLevel.Administrator)]
|
||||||
public bool Summoned
|
public bool Summoned
|
||||||
{
|
{
|
||||||
get => m_bSummoned;
|
get => _summoned;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (m_bSummoned == value)
|
if (_summoned == value)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NextReacquireTime = Core.TickCount;
|
NextReacquireTime = Core.TickCount;
|
||||||
|
|
||||||
m_bSummoned = value;
|
_summoned = value;
|
||||||
Delta(MobileDelta.Noto);
|
Delta(MobileDelta.Noto);
|
||||||
|
|
||||||
InvalidateProperties();
|
InvalidateProperties();
|
||||||
|
|
@ -855,7 +855,7 @@ namespace Server.Mobiles
|
||||||
|
|
||||||
public virtual bool CanRummageCorpses => false;
|
public virtual bool CanRummageCorpses => false;
|
||||||
|
|
||||||
public virtual bool DeleteOnRelease => m_bSummoned;
|
public virtual bool DeleteOnRelease => _summoned;
|
||||||
|
|
||||||
public virtual bool CanDrop => IsBonded;
|
public virtual bool CanDrop => IsBonded;
|
||||||
|
|
||||||
|
|
@ -1228,7 +1228,7 @@ namespace Server.Mobiles
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_Team != c.m_Team || (m_bSummoned || m_Controlled) != (c.m_bSummoned || c.m_Controlled);
|
return m_Team != c.m_Team || (_summoned || m_Controlled) != (c._summoned || c.m_Controlled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ApplyNameSuffix(string suffix)
|
public override string ApplyNameSuffix(string suffix)
|
||||||
|
|
@ -1268,28 +1268,31 @@ namespace Server.Mobiles
|
||||||
|
|
||||||
public virtual double GetControlChance(Mobile m, bool useBaseSkill = false)
|
public virtual double GetControlChance(Mobile m, bool useBaseSkill = false)
|
||||||
{
|
{
|
||||||
if (MinTameSkill <= 29.1 || m_bSummoned || m.AccessLevel >= AccessLevel.GameMaster)
|
if (MinTameSkill <= 29.1 || _summoned || m.AccessLevel >= AccessLevel.GameMaster)
|
||||||
{
|
{
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dMinTameSkill = MinTameSkill;
|
var minTameSkill = MinTameSkill;
|
||||||
|
|
||||||
if (dMinTameSkill > -24.9 && AnimalTaming.CheckMastery(m, this))
|
if (minTameSkill > -24.9 && AnimalTaming.CheckMastery(m, this))
|
||||||
{
|
{
|
||||||
dMinTameSkill = -24.9;
|
minTameSkill = -24.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
var taming =
|
var taming = useBaseSkill
|
||||||
(int)((useBaseSkill ? m.Skills.AnimalTaming.Base : m.Skills.AnimalTaming.Value) * 10);
|
? m.Skills.AnimalTaming.BaseFixedPoint
|
||||||
var lore =
|
: m.Skills.AnimalTaming.Fixed;
|
||||||
(int)((useBaseSkill ? m.Skills.AnimalLore.Base : m.Skills.AnimalLore.Value) * 10);
|
var lore = useBaseSkill
|
||||||
|
? m.Skills.AnimalLore.BaseFixedPoint
|
||||||
|
: m.Skills.AnimalLore.Fixed;
|
||||||
|
|
||||||
int bonus;
|
int bonus;
|
||||||
|
|
||||||
if (Core.ML)
|
if (Core.ML)
|
||||||
{
|
{
|
||||||
var skillBonus = taming - (int)(dMinTameSkill * 10);
|
var skillBonus = taming - (int)(minTameSkill * 10);
|
||||||
var loreBonus = lore - (int)(dMinTameSkill * 10);
|
var loreBonus = lore - (int)(minTameSkill * 10);
|
||||||
|
|
||||||
var skillMod = 6;
|
var skillMod = 6;
|
||||||
var loreMod = 6;
|
var loreMod = 6;
|
||||||
|
|
@ -1311,7 +1314,7 @@ namespace Server.Mobiles
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var difficulty = (int)(dMinTameSkill * 10);
|
var difficulty = (int)(minTameSkill * 10);
|
||||||
var weighted = (taming * 4 + lore) / 5;
|
var weighted = (taming * 4 + lore) / 5;
|
||||||
bonus = weighted - difficulty;
|
bonus = weighted - difficulty;
|
||||||
|
|
||||||
|
|
@ -1325,20 +1328,11 @@ namespace Server.Mobiles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var chance = 700 + bonus;
|
var chance = Math.Clamp(700 + bonus, 220, 990);
|
||||||
|
|
||||||
if (chance > 990)
|
|
||||||
{
|
|
||||||
chance = 990;
|
|
||||||
}
|
|
||||||
else if (chance >= 0)
|
|
||||||
{
|
|
||||||
chance = 220;
|
|
||||||
}
|
|
||||||
|
|
||||||
chance -= (MaxLoyalty - m_Loyalty) * 10;
|
chance -= (MaxLoyalty - m_Loyalty) * 10;
|
||||||
|
|
||||||
return (double)chance / 1000;
|
return chance / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Damage(int amount, Mobile from = null, bool informMount = true)
|
public override void Damage(int amount, Mobile from = null, bool informMount = true)
|
||||||
|
|
@ -1732,9 +1726,9 @@ namespace Server.Mobiles
|
||||||
// Removed in version 9
|
// Removed in version 9
|
||||||
// writer.Write( (double) m_dMaxTameSkill );
|
// writer.Write( (double) m_dMaxTameSkill );
|
||||||
writer.Write(m_bTamable);
|
writer.Write(m_bTamable);
|
||||||
writer.Write(m_bSummoned);
|
writer.Write(_summoned);
|
||||||
|
|
||||||
if (m_bSummoned)
|
if (_summoned)
|
||||||
{
|
{
|
||||||
writer.WriteDeltaTime(SummonEnd);
|
writer.WriteDeltaTime(SummonEnd);
|
||||||
}
|
}
|
||||||
|
|
@ -1899,9 +1893,9 @@ namespace Server.Mobiles
|
||||||
}
|
}
|
||||||
|
|
||||||
m_bTamable = reader.ReadBool();
|
m_bTamable = reader.ReadBool();
|
||||||
m_bSummoned = reader.ReadBool();
|
_summoned = reader.ReadBool();
|
||||||
|
|
||||||
if (m_bSummoned)
|
if (_summoned)
|
||||||
{
|
{
|
||||||
SummonEnd = reader.ReadDeltaTime();
|
SummonEnd = reader.ReadDeltaTime();
|
||||||
new UnsummonTimer(m_ControlMaster, this, SummonEnd - Core.Now).Start();
|
new UnsummonTimer(m_ControlMaster, this, SummonEnd - Core.Now).Start();
|
||||||
|
|
@ -2447,7 +2441,7 @@ namespace Server.Mobiles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aggressor.ChangingCombatant && (m_Controlled || m_bSummoned) &&
|
if (aggressor.ChangingCombatant && (m_Controlled || _summoned) &&
|
||||||
(ct == OrderType.Come || !Core.ML && ct == OrderType.Stay || ct == OrderType.Stop || ct == OrderType.None ||
|
(ct == OrderType.Come || !Core.ML && ct == OrderType.Stay || ct == OrderType.Stop || ct == OrderType.None ||
|
||||||
ct == OrderType.Follow))
|
ct == OrderType.Follow))
|
||||||
{
|
{
|
||||||
|
|
@ -3703,7 +3697,7 @@ namespace Server.Mobiles
|
||||||
return m_ControlMaster;
|
return m_ControlMaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_bSummoned && m_SummonMaster != null)
|
if (_summoned && m_SummonMaster != null)
|
||||||
{
|
{
|
||||||
return m_SummonMaster;
|
return m_SummonMaster;
|
||||||
}
|
}
|
||||||
|
|
@ -4212,7 +4206,7 @@ namespace Server.Mobiles
|
||||||
|
|
||||||
public virtual bool IsFriend(Mobile m) =>
|
public virtual bool IsFriend(Mobile m) =>
|
||||||
OppositionGroup?.IsEnemy(this, m) != true && m is BaseCreature c && m_Team == c.m_Team
|
OppositionGroup?.IsEnemy(this, m) != true && m is BaseCreature c && m_Team == c.m_Team
|
||||||
&& (m_bSummoned || m_Controlled) == (c.m_bSummoned || c.m_Controlled);
|
&& (_summoned || m_Controlled) == (c._summoned || c.m_Controlled);
|
||||||
|
|
||||||
public virtual Allegiance GetFactionAllegiance(Mobile mob)
|
public virtual Allegiance GetFactionAllegiance(Mobile mob)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,9 @@ namespace Server.SkillHandlers
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CheckMastery(Mobile tamer, BaseCreature creature) =>
|
public static bool CheckMastery(Mobile tamer, BaseCreature creature) =>
|
||||||
SummonFamiliarSpell.Table.TryGetValue(tamer, out var bc) && bc is DarkWolfFamiliar familiar &&
|
SummonFamiliarSpell.Table.TryGetValue(tamer, out var bc)
|
||||||
!familiar.Deleted && creature is DireWolf or GreyWolf or TimberWolf or WhiteWolf or BakeKitsune;
|
&& bc is DarkWolfFamiliar { Deleted: false }
|
||||||
|
&& creature is DireWolf or GreyWolf or TimberWolf or WhiteWolf or BakeKitsune;
|
||||||
|
|
||||||
public static bool MustBeSubdued(BaseCreature bc) =>
|
public static bool MustBeSubdued(BaseCreature bc) =>
|
||||||
bc.Owners.Count <= 0 && bc.SubdueBeforeTame && bc.Hits > bc.HitsMax / 10;
|
bc.Owners.Count <= 0 && bc.SubdueBeforeTame && bc.Hits > bc.HitsMax / 10;
|
||||||
|
|
|
||||||
|
|
@ -84,10 +84,13 @@ namespace Server.Spells
|
||||||
public virtual void OnCasterHurt()
|
public virtual void OnCasterHurt()
|
||||||
{
|
{
|
||||||
// Confirm: Monsters and pets cannot be disturbed.
|
// Confirm: Monsters and pets cannot be disturbed.
|
||||||
if (Caster.Player && IsCasting && ProtectionSpell.Registry.TryGetValue(Caster, out var d) &&
|
if (Caster.Player && IsCasting)
|
||||||
d <= Utility.RandomDouble() * 100.0)
|
|
||||||
{
|
{
|
||||||
Disturb(DisturbType.Hurt, false, true);
|
var hasProtection = ProtectionSpell.Registry.TryGetValue(Caster, out var d);
|
||||||
|
if (!hasProtection || d < 1000 && d < Utility.Random(1000))
|
||||||
|
{
|
||||||
|
Disturb(DisturbType.Hurt, false, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -704,7 +707,7 @@ namespace Server.Spells
|
||||||
{
|
{
|
||||||
DoFizzle();
|
DoFizzle();
|
||||||
}
|
}
|
||||||
else if (Scroll != null && !(Scroll is Runebook) &&
|
else if (Scroll != null && Scroll is not Runebook &&
|
||||||
(Scroll.Amount <= 0 || Scroll.Deleted || Scroll.RootParent != Caster || Scroll is BaseWand baseWand &&
|
(Scroll.Amount <= 0 || Scroll.Deleted || Scroll.RootParent != Caster || Scroll is BaseWand baseWand &&
|
||||||
(baseWand.Charges <= 0 || baseWand.Parent != Caster)))
|
(baseWand.Charges <= 0 || baseWand.Parent != Caster)))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using Server.Collections;
|
||||||
using Server.Engines.PartySystem;
|
using Server.Engines.PartySystem;
|
||||||
using Server.Spells.Second;
|
using Server.Spells.Second;
|
||||||
using Server.Targeting;
|
using Server.Targeting;
|
||||||
|
|
@ -53,15 +53,26 @@ namespace Server.Spells.Fourth
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targets = Caster.Map.GetMobilesInRange(loc, Core.AOS ? 2 : 3)
|
var eable = Caster.Map.GetMobilesInRange(loc, Core.AOS ? 2 : 3);
|
||||||
.Where(m => Caster.CanBeBeneficial(m, false));
|
using var targets = PooledRefQueue<Mobile>.Create();
|
||||||
|
|
||||||
|
foreach (var m in eable)
|
||||||
|
{
|
||||||
|
if (Caster.CanBeBeneficial(m, false))
|
||||||
|
{
|
||||||
|
targets.Enqueue(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eable.Free();
|
||||||
|
|
||||||
if (Core.AOS)
|
if (Core.AOS)
|
||||||
{
|
{
|
||||||
var party = Party.Get(Caster);
|
var party = Party.Get(Caster);
|
||||||
|
|
||||||
foreach (var m in targets)
|
while (targets.Count > 0)
|
||||||
{
|
{
|
||||||
|
var m = targets.Dequeue();
|
||||||
if (m == Caster || party?.Contains(m) == true)
|
if (m == Caster || party?.Contains(m) == true)
|
||||||
{
|
{
|
||||||
Caster.DoBeneficial(m);
|
Caster.DoBeneficial(m);
|
||||||
|
|
@ -73,8 +84,9 @@ namespace Server.Spells.Fourth
|
||||||
{
|
{
|
||||||
var val = (int)(Caster.Skills.Magery.Value / 10.0 + 1);
|
var val = (int)(Caster.Skills.Magery.Value / 10.0 + 1);
|
||||||
|
|
||||||
foreach (var m in targets)
|
while (targets.Count > 0)
|
||||||
{
|
{
|
||||||
|
var m = targets.Dequeue();
|
||||||
if (m.BeginAction<ArchProtectionSpell>())
|
if (m.BeginAction<ArchProtectionSpell>())
|
||||||
{
|
{
|
||||||
Caster.DoBeneficial(m);
|
Caster.DoBeneficial(m);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Server.Collections;
|
using Server.Collections;
|
||||||
using Server.Items;
|
using Server.Items;
|
||||||
using Server.Misc;
|
using Server.Misc;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Server.Spells.Second
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Dictionary<Mobile, double> Registry { get; } = new();
|
public static Dictionary<Mobile, int> Registry { get; } = new();
|
||||||
|
|
||||||
public override SpellCircle Circle => SpellCircle.Second;
|
public override SpellCircle Circle => SpellCircle.Second;
|
||||||
|
|
||||||
|
|
@ -48,6 +48,7 @@ namespace Server.Spells.Second
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AOS+ only
|
||||||
public static void Toggle(Mobile caster, Mobile target)
|
public static void Toggle(Mobile caster, Mobile target)
|
||||||
{
|
{
|
||||||
/* Players under the protection spell effect can no longer have their spells "disrupted" when hit.
|
/* Players under the protection spell effect can no longer have their spells "disrupted" when hit.
|
||||||
|
|
@ -89,7 +90,7 @@ namespace Server.Spells.Second
|
||||||
);
|
);
|
||||||
|
|
||||||
m_Table[target] = mods;
|
m_Table[target] = mods;
|
||||||
Registry[target] = 100.0;
|
Registry[target] = 1000; // 100.0% protection from disruption
|
||||||
|
|
||||||
target.AddResistanceMod(mods.Item1);
|
target.AddResistanceMod(mods.Item1);
|
||||||
target.AddSkillMod(mods.Item2);
|
target.AddSkillMod(mods.Item2);
|
||||||
|
|
@ -141,12 +142,11 @@ namespace Server.Spells.Second
|
||||||
{
|
{
|
||||||
if (Caster.BeginAction<DefensiveSpell>())
|
if (Caster.BeginAction<DefensiveSpell>())
|
||||||
{
|
{
|
||||||
double value = (int)(Caster.Skills.EvalInt.Value +
|
int value = (Caster.Skills.EvalInt.Fixed +
|
||||||
Caster.Skills.Meditation.Value +
|
Caster.Skills.Meditation.Fixed +
|
||||||
Caster.Skills.Inscribe.Value);
|
Caster.Skills.Inscribe.Fixed) / 4;
|
||||||
value /= 4;
|
|
||||||
|
|
||||||
Registry.Add(Caster, Math.Clamp(value, 0.0, 75.0));
|
Registry.Add(Caster, Math.Clamp(value, 0, 750)); // 75.0% protection from disruption
|
||||||
new InternalTimer(Caster).Start();
|
new InternalTimer(Caster).Start();
|
||||||
|
|
||||||
Caster.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist);
|
Caster.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue