fix(spells): Fixes interruption of spells (#702)

This commit is contained in:
Kamron Batman 2021-08-18 12:17:42 -07:00 committed by GitHub
parent 50dd7a1146
commit e6de7a5898
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 64 additions and 55 deletions

View file

@ -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)
{ {

View file

@ -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;

View file

@ -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)))
{ {

View file

@ -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);

View file

@ -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;

View file

@ -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);