Some cleanup of contains keys and try get values (#246)
This commit is contained in:
parent
9cbb0cfd23
commit
a236617ad9
69 changed files with 3508 additions and 350 deletions
|
|
@ -82,7 +82,9 @@ namespace Server.Spells
|
|||
var scalar = 1.0;
|
||||
|
||||
if (!MindRotSpell.GetMindRotScalar(m, ref scalar))
|
||||
{
|
||||
scalar = 1.0;
|
||||
}
|
||||
|
||||
// Lower Mana Cost = 40%
|
||||
var lmc = Math.Min(AosAttributes.GetValue(m, AosAttribute.LowerManaCost), 40);
|
||||
|
|
@ -92,7 +94,9 @@ namespace Server.Spells
|
|||
var total = (int)(mana * scalar);
|
||||
|
||||
if (m.Skills[MoveSkill].Value < 50.0 && GetContext(m) != null)
|
||||
{
|
||||
total *= 2;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
|
@ -113,7 +117,9 @@ namespace Server.Spells
|
|||
if (consume)
|
||||
{
|
||||
if (!DelayedContext)
|
||||
{
|
||||
SetContext(from);
|
||||
}
|
||||
|
||||
from.Mana -= mana;
|
||||
}
|
||||
|
|
@ -124,6 +130,7 @@ namespace Server.Spells
|
|||
public virtual void SetContext(Mobile from)
|
||||
{
|
||||
if (GetContext(from) == null)
|
||||
{
|
||||
if (DelayedContext || from.Skills[MoveSkill].Value < 50.0)
|
||||
{
|
||||
Timer timer = new SpecialMoveTimer(from);
|
||||
|
|
@ -131,12 +138,15 @@ namespace Server.Spells
|
|||
|
||||
AddContext(from, new SpecialMoveContext(timer, GetType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Validate(Mobile from)
|
||||
{
|
||||
if (!from.Player)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (HonorableExecution.IsUnderPenalty(from))
|
||||
{
|
||||
|
|
@ -153,24 +163,42 @@ namespace Server.Spells
|
|||
string option = null;
|
||||
|
||||
if (this is Backstab)
|
||||
{
|
||||
option = "Backstab";
|
||||
}
|
||||
else if (this is DeathStrike)
|
||||
{
|
||||
option = "Death Strike";
|
||||
}
|
||||
else if (this is FocusAttack)
|
||||
{
|
||||
option = "Focus Attack";
|
||||
}
|
||||
else if (this is KiAttack)
|
||||
{
|
||||
option = "Ki Attack";
|
||||
}
|
||||
else if (this is SurpriseAttack)
|
||||
{
|
||||
option = "Surprise Attack";
|
||||
}
|
||||
else if (this is HonorableExecution)
|
||||
{
|
||||
option = "Honorable Execution";
|
||||
}
|
||||
else if (this is LightningStrike)
|
||||
{
|
||||
option = "Lightning Strike";
|
||||
}
|
||||
else if (this is MomentumStrike)
|
||||
{
|
||||
option = "Momentum Strike";
|
||||
}
|
||||
|
||||
if (option != null && !DuelContext.AllowSpecialMove(from, option, this))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return CheckSkills(from) && CheckMana(from, false);
|
||||
}
|
||||
|
|
@ -187,14 +215,18 @@ namespace Server.Spells
|
|||
var moveID = kvp.Key;
|
||||
|
||||
if (moveID != -1)
|
||||
{
|
||||
m.Send(new ToggleSpecialAbility(moveID + 1, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SpecialMove GetCurrentMove(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Core.SE)
|
||||
{
|
||||
|
|
@ -230,7 +262,9 @@ namespace Server.Spells
|
|||
ClearCurrentMove(m);
|
||||
|
||||
if (sameMove)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (move != null)
|
||||
{
|
||||
|
|
@ -243,7 +277,9 @@ namespace Server.Spells
|
|||
var moveID = SpellRegistry.GetRegistryNumber(move);
|
||||
|
||||
if (moveID > 0)
|
||||
{
|
||||
m.Send(new ToggleSpecialAbility(moveID + 1, true));
|
||||
}
|
||||
|
||||
TextDefinition.SendMessageTo(m, move.AbilityMessage);
|
||||
}
|
||||
|
|
@ -253,17 +289,17 @@ namespace Server.Spells
|
|||
|
||||
public static void ClearCurrentMove(Mobile m)
|
||||
{
|
||||
if (Table.TryGetValue(m, out var move))
|
||||
if (Table.Remove(m, out var move))
|
||||
{
|
||||
move.OnClearMove(m);
|
||||
|
||||
var moveID = SpellRegistry.GetRegistryNumber(move);
|
||||
|
||||
if (moveID > 0)
|
||||
{
|
||||
m.Send(new ToggleSpecialAbility(moveID + 1, false));
|
||||
}
|
||||
}
|
||||
|
||||
Table.Remove(m);
|
||||
}
|
||||
|
||||
private static void AddContext(Mobile m, SpecialMoveContext context)
|
||||
|
|
|
|||
|
|
@ -86,7 +86,9 @@ namespace Server.Spells
|
|||
// Confirm: Monsters and pets cannot be disturbed.
|
||||
if (Caster.Player && IsCasting && ProtectionSpell.Registry.TryGetValue(Caster, out var d) &&
|
||||
d <= Utility.RandomDouble() * 100.0)
|
||||
{
|
||||
Disturb(DisturbType.Hurt, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnCasterKilled()
|
||||
|
|
@ -113,7 +115,9 @@ namespace Server.Spells
|
|||
public virtual bool OnCasterEquipping(Item item)
|
||||
{
|
||||
if (IsCasting)
|
||||
{
|
||||
Disturb(DisturbType.EquipRequest);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -121,7 +125,9 @@ namespace Server.Spells
|
|||
public virtual bool OnCasterUsingObject(IEntity entity)
|
||||
{
|
||||
if (State == SpellState.Sequencing)
|
||||
{
|
||||
Disturb(DisturbType.UseRequest);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -133,16 +139,22 @@ namespace Server.Spells
|
|||
State = SpellState.None;
|
||||
|
||||
if (Caster.Spell == this)
|
||||
{
|
||||
Caster.Spell = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartDelayedDamageContext(Mobile m, Timer t)
|
||||
{
|
||||
if (DelayedDamageStacking)
|
||||
{
|
||||
return; // Sanity
|
||||
}
|
||||
|
||||
if (!m_ContextTable.TryGetValue(GetType(), out var contexts))
|
||||
{
|
||||
m_ContextTable[GetType()] = contexts = new DelayedDamageContextWrapper();
|
||||
}
|
||||
|
||||
contexts.Add(m, t);
|
||||
}
|
||||
|
|
@ -150,7 +162,9 @@ namespace Server.Spells
|
|||
public void RemoveDelayedDamageContext(Mobile m)
|
||||
{
|
||||
if (m_ContextTable.TryGetValue(GetType(), out var contexts))
|
||||
{
|
||||
contexts.Remove(m);
|
||||
}
|
||||
}
|
||||
|
||||
public void HarmfulSpell(Mobile m)
|
||||
|
|
@ -161,6 +175,7 @@ namespace Server.Spells
|
|||
public virtual int GetNewAosDamage(int bonus, uint dice, uint sides, Mobile singleTarget)
|
||||
{
|
||||
if (singleTarget != null)
|
||||
{
|
||||
return GetNewAosDamage(
|
||||
bonus,
|
||||
dice,
|
||||
|
|
@ -168,6 +183,7 @@ namespace Server.Spells
|
|||
Caster.Player && singleTarget.Player,
|
||||
GetDamageScalar(singleTarget)
|
||||
);
|
||||
}
|
||||
|
||||
return GetNewAosDamage(bonus, dice, sides, false);
|
||||
}
|
||||
|
|
@ -189,14 +205,18 @@ namespace Server.Spells
|
|||
var sdiBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage);
|
||||
// PvP spell damage increase cap of 15% from an item<65>s magic property
|
||||
if (playerVsPlayer && sdiBonus > 15)
|
||||
{
|
||||
sdiBonus = 15;
|
||||
}
|
||||
|
||||
damageBonus += sdiBonus;
|
||||
|
||||
var context = TransformationSpellHelper.GetContext(Caster);
|
||||
|
||||
if (context?.Spell is ReaperFormSpell spell)
|
||||
{
|
||||
damageBonus += spell.SpellDamageBonus;
|
||||
}
|
||||
|
||||
damage = AOS.Scale(damage, 100 + damageBonus);
|
||||
|
||||
|
|
@ -242,15 +262,21 @@ namespace Server.Spells
|
|||
// m_Caster.CheckSkill( DamageSkill, 0.0, 120.0 );
|
||||
|
||||
if (casterEI > targetRS)
|
||||
{
|
||||
scalar = 1.0 + (casterEI - targetRS) / 500.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
scalar = 1.0 + (casterEI - targetRS) / 200.0;
|
||||
}
|
||||
|
||||
// magery damage bonus, -25% at 0 skill, +0% at 100 skill, +5% at 120 skill
|
||||
scalar += (Caster.Skills[CastSkill].Value - 100.0) / 400.0;
|
||||
|
||||
if (!target.Player && !target.Body.IsHuman /*&& !Core.AOS*/)
|
||||
{
|
||||
scalar *= 2.0; // Double magery damage to monsters/animals if not AOS
|
||||
}
|
||||
}
|
||||
|
||||
(target as BaseCreature)?.AlterDamageScalarFrom(Caster, ref scalar);
|
||||
|
|
@ -258,12 +284,16 @@ namespace Server.Spells
|
|||
(Caster as BaseCreature)?.AlterDamageScalarTo(target, ref scalar);
|
||||
|
||||
if (Core.SE)
|
||||
{
|
||||
scalar *= GetSlayerDamageScalar(target);
|
||||
}
|
||||
|
||||
target.Region.SpellDamageScalar(Caster, target, ref scalar);
|
||||
|
||||
if (Evasion.CheckSpellEvasion(target)) // Only single target spells an be evaded
|
||||
{
|
||||
scalar = 0;
|
||||
}
|
||||
|
||||
return scalar;
|
||||
}
|
||||
|
|
@ -288,10 +318,14 @@ namespace Server.Spells
|
|||
|
||||
if ((atkBook.Slayer == SlayerName.Silver || atkBook.Slayer2 == SlayerName.Silver) && context != null &&
|
||||
context.Type != typeof(HorrificBeastSpell))
|
||||
{
|
||||
scalar += .25; // Every necromancer transformation other than horrific beast take an additional 25% damage
|
||||
}
|
||||
|
||||
if (scalar != 1.0)
|
||||
{
|
||||
return scalar;
|
||||
}
|
||||
}
|
||||
|
||||
var defISlayer = Spellbook.FindEquippedSpellbook(defender) ?? defender.Weapon as ISlayer;
|
||||
|
|
@ -303,7 +337,9 @@ namespace Server.Spells
|
|||
|
||||
if (defSlayer?.Group.OppositionSuperSlays(Caster) == true ||
|
||||
defSlayer2?.Group.OppositionSuperSlays(Caster) == true)
|
||||
{
|
||||
scalar = 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
return scalar;
|
||||
|
|
@ -316,9 +352,13 @@ namespace Server.Spells
|
|||
if (Caster.Player)
|
||||
{
|
||||
if (Core.AOS)
|
||||
{
|
||||
Caster.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist);
|
||||
}
|
||||
else
|
||||
{
|
||||
Caster.FixedEffect(0x3735, 6, 30);
|
||||
}
|
||||
|
||||
Caster.PlaySound(0x5C);
|
||||
}
|
||||
|
|
@ -330,12 +370,16 @@ namespace Server.Spells
|
|||
public void Disturb(DisturbType type, bool firstCircle = true, bool resistable = false)
|
||||
{
|
||||
if (!CheckDisturb(type, firstCircle, resistable))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (State == SpellState.Casting)
|
||||
{
|
||||
if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
State = SpellState.None;
|
||||
Caster.Spell = null;
|
||||
|
|
@ -347,14 +391,18 @@ namespace Server.Spells
|
|||
m_AnimTimer?.Stop();
|
||||
|
||||
if (Core.AOS && Caster.Player && type == DisturbType.Hurt)
|
||||
{
|
||||
DoHurtFizzle();
|
||||
}
|
||||
|
||||
Caster.NextSpellTime = Core.TickCount + (int)GetDisturbRecovery().TotalMilliseconds;
|
||||
}
|
||||
else if (State == SpellState.Sequencing)
|
||||
{
|
||||
if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
State = SpellState.None;
|
||||
Caster.Spell = null;
|
||||
|
|
@ -364,7 +412,9 @@ namespace Server.Spells
|
|||
Target.Cancel(Caster);
|
||||
|
||||
if (Core.AOS && Caster.Player && type == DisturbType.Hurt)
|
||||
{
|
||||
DoHurtFizzle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -377,7 +427,9 @@ namespace Server.Spells
|
|||
public virtual void OnDisturb(DisturbType type, bool message)
|
||||
{
|
||||
if (message)
|
||||
{
|
||||
Caster.SendLocalizedMessage(500641); // Your concentration is disturbed, thus ruining thy spell.
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool CheckCast() => true;
|
||||
|
|
@ -385,10 +437,14 @@ namespace Server.Spells
|
|||
public virtual void SayMantra()
|
||||
{
|
||||
if (Scroll is BaseWand)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Info.Mantra) && Caster.Player)
|
||||
{
|
||||
Caster.PublicOverheadMessage(MessageType.Spell, Caster.SpeechHue, true, Info.Mantra, false);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Cast()
|
||||
|
|
@ -396,9 +452,14 @@ namespace Server.Spells
|
|||
StartCastTime = Core.TickCount;
|
||||
|
||||
if (Core.AOS && Caster.Spell is Spell spell && spell.State == SpellState.Sequencing)
|
||||
{
|
||||
spell.Disturb(DisturbType.NewCast);
|
||||
}
|
||||
|
||||
if (!Caster.CheckAlive()) return false;
|
||||
if (!Caster.CheckAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Scroll is BaseWand && Caster.Spell?.IsCasting == true)
|
||||
{
|
||||
|
|
@ -438,7 +499,9 @@ namespace Server.Spells
|
|||
Caster.Spell = this;
|
||||
|
||||
if (!(Scroll is BaseWand) && RevealOnCast)
|
||||
{
|
||||
Caster.RevealingAction();
|
||||
}
|
||||
|
||||
SayMantra();
|
||||
|
||||
|
|
@ -455,17 +518,25 @@ namespace Server.Spells
|
|||
}
|
||||
|
||||
if (Info.LeftHandEffect > 0)
|
||||
{
|
||||
Caster.FixedParticles(0, 10, 5, Info.LeftHandEffect, EffectLayer.LeftHand);
|
||||
}
|
||||
|
||||
if (Info.RightHandEffect > 0)
|
||||
{
|
||||
Caster.FixedParticles(0, 10, 5, Info.RightHandEffect, EffectLayer.RightHand);
|
||||
}
|
||||
}
|
||||
|
||||
if (ClearHandsOnCast)
|
||||
{
|
||||
Caster.ClearHands();
|
||||
}
|
||||
|
||||
if (Core.ML)
|
||||
{
|
||||
WeaponAbility.ClearCurrentAbility(Caster);
|
||||
}
|
||||
|
||||
m_CastTimer = new CastTimer(this, castDelay);
|
||||
// m_CastTimer.Start();
|
||||
|
|
@ -473,9 +544,13 @@ namespace Server.Spells
|
|||
OnBeginCast();
|
||||
|
||||
if (castDelay > TimeSpan.Zero)
|
||||
{
|
||||
m_CastTimer.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CastTimer.Tick();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -504,12 +579,16 @@ namespace Server.Spells
|
|||
public virtual bool CheckFizzle()
|
||||
{
|
||||
if (Scroll is BaseWand)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
GetCastSkills(out var minSkill, out var maxSkill);
|
||||
|
||||
if (DamageSkill != CastSkill)
|
||||
{
|
||||
Caster.CheckSkill(DamageSkill, 0.0, Caster.Skills[DamageSkill].Cap);
|
||||
}
|
||||
|
||||
return Caster.CheckSkill(CastSkill, minSkill, maxSkill);
|
||||
}
|
||||
|
|
@ -521,12 +600,16 @@ namespace Server.Spells
|
|||
var scalar = 1.0;
|
||||
|
||||
if (!MindRotSpell.GetMindRotScalar(Caster, ref scalar))
|
||||
{
|
||||
scalar = 1.0;
|
||||
}
|
||||
|
||||
// Lower Mana Cost = 40%
|
||||
var lmc = AosAttributes.GetValue(Caster, AosAttribute.LowerManaCost);
|
||||
if (lmc > 40)
|
||||
{
|
||||
lmc = 40;
|
||||
}
|
||||
|
||||
scalar -= (double)lmc / 100;
|
||||
|
||||
|
|
@ -536,7 +619,9 @@ namespace Server.Spells
|
|||
public virtual TimeSpan GetDisturbRecovery()
|
||||
{
|
||||
if (Core.AOS)
|
||||
{
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
|
||||
var delay = Math.Max(
|
||||
1.0 - Math.Sqrt((Core.TickCount - StartCastTime) / 1000.0 / GetCastDelay().TotalSeconds),
|
||||
|
|
@ -549,7 +634,9 @@ namespace Server.Spells
|
|||
public virtual TimeSpan GetCastRecovery()
|
||||
{
|
||||
if (!Core.AOS)
|
||||
{
|
||||
return NextSpellDelay;
|
||||
}
|
||||
|
||||
var fcr = AosAttributes.GetValue(Caster, AosAttribute.CastRecovery) -
|
||||
ThunderstormSpell.GetCastRecoveryMalus(Caster);
|
||||
|
|
@ -559,7 +646,9 @@ namespace Server.Spells
|
|||
var delay = CastRecoveryBase + fcrDelay;
|
||||
|
||||
if (delay < CastRecoveryMinimum)
|
||||
{
|
||||
delay = CastRecoveryMinimum;
|
||||
}
|
||||
|
||||
return TimeSpan.FromSeconds((double)delay / CastRecoveryPerSecond);
|
||||
}
|
||||
|
|
@ -572,7 +661,9 @@ namespace Server.Spells
|
|||
public virtual TimeSpan GetCastDelay()
|
||||
{
|
||||
if (Scroll is BaseWand)
|
||||
{
|
||||
return Core.ML ? CastDelayBase : TimeSpan.Zero; // TODO: Should FC apply to wands?
|
||||
}
|
||||
|
||||
// Faster casting cap of 2 (if not using the protection spell)
|
||||
// Faster casting cap of 0 (if using the protection spell)
|
||||
|
|
@ -582,15 +673,21 @@ namespace Server.Spells
|
|||
|
||||
if (CastSkill == SkillName.Magery || CastSkill == SkillName.Necromancy ||
|
||||
CastSkill == SkillName.Chivalry && Caster.Skills.Magery.Value >= 70.0)
|
||||
{
|
||||
fcMax = 2;
|
||||
}
|
||||
|
||||
var fc = Math.Min(AosAttributes.GetValue(Caster, AosAttribute.CastSpeed), fcMax);
|
||||
|
||||
if (ProtectionSpell.Registry.ContainsKey(Caster))
|
||||
{
|
||||
fc -= 2;
|
||||
}
|
||||
|
||||
if (EssenceOfWindSpell.IsDebuffed(Caster))
|
||||
{
|
||||
fc -= EssenceOfWindSpell.GetFCMalus(Caster);
|
||||
}
|
||||
|
||||
var fcDelay = TimeSpan.FromSeconds(-(CastDelayFastScalar * fc * CastDelaySecondsPerTick));
|
||||
|
||||
|
|
@ -652,27 +749,35 @@ namespace Server.Spells
|
|||
Scroll.Movable = false;
|
||||
|
||||
if (ClearHandsOnCast)
|
||||
{
|
||||
Caster.ClearHands();
|
||||
}
|
||||
|
||||
Scroll.Movable = m;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ClearHandsOnCast)
|
||||
{
|
||||
Caster.ClearHands();
|
||||
}
|
||||
}
|
||||
|
||||
var karma = ComputeKarmaAward();
|
||||
|
||||
if (karma != 0)
|
||||
{
|
||||
Titles.AwardKarma(Caster, karma, true);
|
||||
}
|
||||
|
||||
if (TransformationSpellHelper.UnderTransformation(Caster, typeof(VampiricEmbraceSpell)))
|
||||
{
|
||||
var garlic = false;
|
||||
|
||||
for (var i = 0; !garlic && i < Info.Reagents.Length; ++i)
|
||||
{
|
||||
garlic = Info.Reagents[i] == Reagent.Garlic;
|
||||
}
|
||||
|
||||
if (garlic)
|
||||
{
|
||||
|
|
@ -770,13 +875,19 @@ namespace Server.Spells
|
|||
if (!m_Spell.Caster.Mounted && m_Spell.Info.Action >= 0)
|
||||
{
|
||||
if (m_Spell.Caster.Body.IsHuman)
|
||||
{
|
||||
m_Spell.Caster.Animate(m_Spell.Info.Action, 7, 1, true, false, 0);
|
||||
}
|
||||
else if (m_Spell.Caster.Player && m_Spell.Caster.Body.IsMonster)
|
||||
{
|
||||
m_Spell.Caster.Animate(12, 7, 1, true, false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Running)
|
||||
{
|
||||
m_Spell.m_AnimTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -793,7 +904,10 @@ namespace Server.Spells
|
|||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_Spell?.Caster == null) return;
|
||||
if (m_Spell?.Caster == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Spell.State == SpellState.Casting && m_Spell.Caster.Spell == m_Spell)
|
||||
{
|
||||
|
|
@ -809,7 +923,9 @@ namespace Server.Spells
|
|||
m_Spell.OnCast();
|
||||
|
||||
if (m_Spell.Caster.Player && m_Spell.Caster.Target != originalTarget)
|
||||
{
|
||||
m_Spell.Caster.Target?.BeginTimeout(m_Spell.Caster, TimeSpan.FromSeconds(30.0));
|
||||
}
|
||||
|
||||
m_Spell.m_CastTimer = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ namespace Server
|
|||
public static void Nullify(Mobile from)
|
||||
{
|
||||
if (!from.CanBeginAction<DefensiveSpell>())
|
||||
{
|
||||
new InternalTimer(from).Start();
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
|
|
@ -155,7 +157,9 @@ namespace Server.Spells
|
|||
public static bool CheckMulti(Point3D p, Map map, bool houses = true, int housingrange = 0)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var sector = map.GetSector(p.X, p.Y);
|
||||
|
||||
|
|
@ -166,7 +170,9 @@ namespace Server.Spells
|
|||
if (multi is BaseHouse bh)
|
||||
{
|
||||
if (houses && bh.IsInside(p, 16) || housingrange > 0 && bh.InRange(p, housingrange))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (multi.Contains(p))
|
||||
{
|
||||
|
|
@ -180,12 +186,16 @@ namespace Server.Spells
|
|||
public static void Turn(Mobile from, object to)
|
||||
{
|
||||
if (!(to is IPoint3D target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (target is Item item)
|
||||
{
|
||||
if (item.RootParent != from)
|
||||
{
|
||||
from.Direction = from.GetDirectionTo(item.GetWorldLocation());
|
||||
}
|
||||
}
|
||||
else if (from != target)
|
||||
{
|
||||
|
|
@ -196,24 +206,32 @@ namespace Server.Spells
|
|||
public static bool CheckCombat(Mobile m)
|
||||
{
|
||||
if (!RestrictTravelCombat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < m.Aggressed.Count; ++i)
|
||||
{
|
||||
var info = m.Aggressed[i];
|
||||
|
||||
if (info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Core.Expansion == Expansion.AOS)
|
||||
{
|
||||
for (var i = 0; i < m.Aggressors.Count; ++i)
|
||||
{
|
||||
var info = m.Aggressors[i];
|
||||
|
||||
if (info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -221,7 +239,9 @@ namespace Server.Spells
|
|||
public static bool AdjustField(ref Point3D p, Map map, int height, bool mobsBlock)
|
||||
{
|
||||
if (map == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var offset = 0; offset < 10; ++offset)
|
||||
{
|
||||
|
|
@ -250,7 +270,9 @@ namespace Server.Spells
|
|||
var z = t.Z;
|
||||
|
||||
if ((t.Flags & TileFlag.Surface) == 0)
|
||||
{
|
||||
z -= TileData.ItemTable[t.ItemID & TileData.MaxItemValue].CalcHeight;
|
||||
}
|
||||
|
||||
p = new Point3D(t.X, t.Y, z);
|
||||
}
|
||||
|
|
@ -331,9 +353,13 @@ namespace Server.Spells
|
|||
double percent;
|
||||
|
||||
if (curse)
|
||||
{
|
||||
percent = 8 + caster.Skills.EvalInt.Fixed / 100 - target.Skills.MagicResist.Fixed / 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
percent = 1 + caster.Skills.EvalInt.Fixed / 100;
|
||||
}
|
||||
|
||||
percent *= 0.01;
|
||||
|
||||
|
|
@ -349,7 +375,9 @@ namespace Server.Spells
|
|||
caster.CheckSkill(SkillName.EvalInt, 0.0, 120.0);
|
||||
|
||||
if (curse)
|
||||
{
|
||||
target.CheckSkill(SkillName.MagicResist, 0.0, 120.0);
|
||||
}
|
||||
}
|
||||
|
||||
var percent = GetOffsetScalar(caster, target, curse);
|
||||
|
|
@ -377,14 +405,18 @@ namespace Server.Spells
|
|||
m = c.ControlMaster;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
g = m.Guild as Guild;
|
||||
}
|
||||
|
||||
if (g == null)
|
||||
{
|
||||
m = c.SummonMaster;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
g = m.Guild as Guild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -394,10 +426,14 @@ namespace Server.Spells
|
|||
public static bool ValidIndirectTarget(Mobile from, Mobile to)
|
||||
{
|
||||
if (from == to)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (to.Hidden && to.AccessLevel > from.AccessLevel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var bcFrom = from as BaseCreature;
|
||||
var bcTarg = to as BaseCreature;
|
||||
|
|
@ -406,48 +442,70 @@ namespace Server.Spells
|
|||
PlayerMobile pmTarg;
|
||||
|
||||
if (bcFrom?.Summoned == true)
|
||||
{
|
||||
pmFrom = bcFrom.SummonMaster as PlayerMobile;
|
||||
}
|
||||
else
|
||||
{
|
||||
pmFrom = from as PlayerMobile;
|
||||
}
|
||||
|
||||
if (bcTarg?.Summoned == true)
|
||||
{
|
||||
pmTarg = bcTarg.SummonMaster as PlayerMobile;
|
||||
}
|
||||
else
|
||||
{
|
||||
pmTarg = to as PlayerMobile;
|
||||
}
|
||||
|
||||
if (pmFrom?.DuelContext != null && pmFrom.DuelContext == pmTarg?.DuelContext && pmFrom.DuelContext.Started &&
|
||||
pmFrom.DuelPlayer != null && pmTarg?.DuelPlayer != null)
|
||||
{
|
||||
return pmFrom.DuelPlayer.Participant != pmTarg.DuelPlayer.Participant;
|
||||
}
|
||||
|
||||
var fromGuild = GetGuildFor(from);
|
||||
var toGuild = GetGuildFor(to);
|
||||
|
||||
if (fromGuild != null && toGuild != null && (fromGuild == toGuild || fromGuild.IsAlly(toGuild)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var p = Party.Get(from);
|
||||
|
||||
if (p?.Contains(to) == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bcTarg != null && (bcTarg.Controlled || bcTarg.Summoned))
|
||||
{
|
||||
if (bcTarg.ControlMaster == from || bcTarg.SummonMaster == from)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p != null && (p.Contains(bcTarg.ControlMaster) || p.Contains(bcTarg.SummonMaster)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bcFrom != null && (bcFrom.Controlled || bcFrom.Summoned))
|
||||
{
|
||||
if (bcFrom.ControlMaster == to || bcFrom.SummonMaster == to)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
p = Party.Get(to);
|
||||
|
||||
if (p != null && (p.Contains(bcFrom.ControlMaster) || p.Contains(bcFrom.SummonMaster)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return bcTarg?.Controlled == false && bcTarg.InitialInnocent ||
|
||||
|
|
@ -462,12 +520,16 @@ namespace Server.Spells
|
|||
var map = caster.Map;
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var scale = 1.0 + (caster.Skills.Magery.Value - 100.0) / 200.0;
|
||||
|
||||
if (scaleDuration)
|
||||
{
|
||||
duration = TimeSpan.FromSeconds(duration.TotalSeconds * scale);
|
||||
}
|
||||
|
||||
if (scaleStats)
|
||||
{
|
||||
|
|
@ -491,12 +553,12 @@ namespace Server.Spells
|
|||
|
||||
/*
|
||||
int offset = Utility.Random( 8 ) * 2;
|
||||
|
||||
|
||||
for ( int i = 0; i < m_Offsets.Length; i += 2 )
|
||||
{
|
||||
int x = caster.X + m_Offsets[(offset + i) % m_Offsets.Length];
|
||||
int y = caster.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length];
|
||||
|
||||
|
||||
if (map.CanSpawnMobile( x, y, caster.Z ))
|
||||
{
|
||||
BaseCreature.Summon( creature, caster, new Point3D( x, y, caster.Z ), sound, duration );
|
||||
|
|
@ -505,7 +567,7 @@ namespace Server.Spells
|
|||
else
|
||||
{
|
||||
int z = map.GetAverageZ( x, y );
|
||||
|
||||
|
||||
if (map.CanSpawnMobile( x, y, z ))
|
||||
{
|
||||
BaseCreature.Summon( creature, caster, new Point3D( x, y, z ), sound, duration );
|
||||
|
|
@ -522,7 +584,9 @@ namespace Server.Spells
|
|||
public static bool FindValidSpawnLocation(Map map, ref Point3D p, bool surroundingsOnly)
|
||||
{
|
||||
if (map == null) // sanity
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!surroundingsOnly)
|
||||
{
|
||||
|
|
@ -569,11 +633,17 @@ namespace Server.Spells
|
|||
public static void SendInvalidMessage(Mobile caster, TravelCheckType type)
|
||||
{
|
||||
if (type == TravelCheckType.RecallTo || type == TravelCheckType.GateTo)
|
||||
{
|
||||
caster.SendLocalizedMessage(1019004); // You are not allowed to travel there.
|
||||
}
|
||||
else if (type == TravelCheckType.TeleportTo)
|
||||
{
|
||||
caster.SendLocalizedMessage(501035); // You cannot teleport from here to the destination.
|
||||
}
|
||||
else
|
||||
{
|
||||
caster.SendLocalizedMessage(501802); // Thy spell doth not appear to work...
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CheckTravel(Mobile caster, TravelCheckType type) =>
|
||||
|
|
@ -586,7 +656,9 @@ namespace Server.Spells
|
|||
if (IsInvalid(map, loc)) // null, internal, out of bounds
|
||||
{
|
||||
if (caster != null)
|
||||
{
|
||||
SendInvalidMessage(caster, type);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -594,7 +666,9 @@ namespace Server.Spells
|
|||
// Always allow monsters to teleport
|
||||
if (caster is BaseCreature bc && !bc.Controlled && !bc.Summoned &&
|
||||
(type == TravelCheckType.TeleportTo || type == TravelCheckType.TeleportFrom))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
m_TravelCaster = caster;
|
||||
m_TravelType = type;
|
||||
|
|
@ -608,14 +682,20 @@ namespace Server.Spells
|
|||
var current = Region.Find(caster.Location, map) as BaseRegion;
|
||||
|
||||
if (destination?.CheckTravel(caster, loc, type) == false || current?.CheckTravel(caster, loc, type) == false)
|
||||
{
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; isValid && i < m_Validators.Length; ++i)
|
||||
{
|
||||
isValid = m_Rules[v, i] || !m_Validators[i](map, loc);
|
||||
}
|
||||
|
||||
if (!isValid && caster != null)
|
||||
{
|
||||
SendInvalidMessage(caster, type);
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
|
@ -669,7 +749,9 @@ namespace Server.Spells
|
|||
public static bool IsCrystalCave(Map map, Point3D loc)
|
||||
{
|
||||
if (map != Map.Malas || loc.Z >= -80)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = loc.X, y = loc.Y;
|
||||
|
||||
|
|
@ -691,7 +773,9 @@ namespace Server.Spells
|
|||
public static bool IsDoomFerry(Map map, Point3D loc)
|
||||
{
|
||||
if (map != Map.Malas)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = loc.X, y = loc.Y;
|
||||
|
||||
|
|
@ -702,7 +786,9 @@ namespace Server.Spells
|
|||
{
|
||||
// The tokuno dungeons are really inside malas
|
||||
if (map != Map.Malas)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = loc.X, y = loc.Y, z = loc.Z;
|
||||
|
||||
|
|
@ -715,7 +801,9 @@ namespace Server.Spells
|
|||
public static bool IsDoomGauntlet(Map map, Point3D loc)
|
||||
{
|
||||
if (map != Map.Malas)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = loc.X - 256, y = loc.Y - 304;
|
||||
|
||||
|
|
@ -725,7 +813,9 @@ namespace Server.Spells
|
|||
public static bool IsLampRoom(Map map, Point3D loc)
|
||||
{
|
||||
if (map != Map.Malas)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = loc.X, y = loc.Y;
|
||||
|
||||
|
|
@ -735,7 +825,9 @@ namespace Server.Spells
|
|||
public static bool IsGuardianRoom(Map map, Point3D loc)
|
||||
{
|
||||
if (map != Map.Malas)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = loc.X, y = loc.Y;
|
||||
|
||||
|
|
@ -754,7 +846,9 @@ namespace Server.Spells
|
|||
public static bool IsInvalid(Map map, Point3D loc)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int x = loc.X, y = loc.Y;
|
||||
|
||||
|
|
@ -765,7 +859,9 @@ namespace Server.Spells
|
|||
public static bool IsTown(IPoint3D ip, Mobile caster)
|
||||
{
|
||||
if (ip is Item item)
|
||||
{
|
||||
ip = item.GetWorldLocation();
|
||||
}
|
||||
|
||||
return IsTown(new Point3D(ip), caster);
|
||||
}
|
||||
|
|
@ -775,11 +871,17 @@ namespace Server.Spells
|
|||
var map = caster.Map;
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Region.Find(loc, map).GetRegion<SafeZone>() != null)
|
||||
{
|
||||
if (caster is PlayerMobile pm && (pm.DuelContext?.Started != true || pm.DuelPlayer?.Eliminated != false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var reg = Region.Find(loc, map).GetRegion<GuardedRegion>();
|
||||
|
||||
|
|
@ -789,7 +891,9 @@ namespace Server.Spells
|
|||
public static bool CheckTown(IPoint3D ip, Mobile caster)
|
||||
{
|
||||
if (ip is Item item)
|
||||
{
|
||||
ip = item.GetWorldLocation();
|
||||
}
|
||||
|
||||
return CheckTown(new Point3D(ip), caster);
|
||||
}
|
||||
|
|
@ -953,7 +1057,9 @@ namespace Server.Spells
|
|||
var damageGiven = AOS.Damage(target, from, dmg, phys, fire, cold, pois, nrgy, chaos);
|
||||
|
||||
if (from != null) // sanity check
|
||||
{
|
||||
DoLeech(damageGiven, from, target);
|
||||
}
|
||||
|
||||
WeightOverloading.DFA = DFAlgorithm.Standard;
|
||||
}
|
||||
|
|
@ -974,7 +1080,9 @@ namespace Server.Spells
|
|||
var context = TransformationSpellHelper.GetContext(from);
|
||||
|
||||
if (context == null) /* cleanup */
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Type == typeof(WraithFormSpell))
|
||||
{
|
||||
|
|
@ -1019,7 +1127,9 @@ namespace Server.Spells
|
|||
m_Spell = s;
|
||||
|
||||
if (m_Spell?.DelayedDamage == true && !m_Spell.DelayedDamageStacking)
|
||||
{
|
||||
m_Spell.StartDelayedDamageContext(target, this);
|
||||
}
|
||||
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
}
|
||||
|
|
@ -1067,7 +1177,9 @@ namespace Server.Spells
|
|||
m_DFA = dfa;
|
||||
m_Spell = s;
|
||||
if (m_Spell?.DelayedDamage == true && !m_Spell.DelayedDamageStacking)
|
||||
{
|
||||
m_Spell.StartDelayedDamageContext(target, this);
|
||||
}
|
||||
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
}
|
||||
|
|
@ -1078,17 +1190,23 @@ namespace Server.Spells
|
|||
var bcTarg = m_Target as BaseCreature;
|
||||
|
||||
if (bcFrom != null && m_Target != null)
|
||||
{
|
||||
bcFrom.AlterSpellDamageTo(m_Target, ref m_Damage);
|
||||
}
|
||||
|
||||
if (bcTarg != null && m_From != null)
|
||||
{
|
||||
bcTarg.AlterSpellDamageFrom(m_From, ref m_Damage);
|
||||
}
|
||||
|
||||
WeightOverloading.DFA = m_DFA;
|
||||
|
||||
var damageGiven = AOS.Damage(m_Target, m_From, m_Damage, m_Phys, m_Fire, m_Cold, m_Pois, m_Nrgy, m_Chaos);
|
||||
|
||||
if (m_From != null) // sanity check
|
||||
{
|
||||
DoLeech(damageGiven, m_From, m_Target);
|
||||
}
|
||||
|
||||
WeightOverloading.DFA = DFAlgorithm.Standard;
|
||||
|
||||
|
|
@ -1133,7 +1251,9 @@ namespace Server.Spells
|
|||
public static bool OnCast(Mobile caster, Spell spell)
|
||||
{
|
||||
if (!(spell is ITransformationSpell transformSpell))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Sigil.ExistsOn(caster))
|
||||
{
|
||||
|
|
@ -1180,33 +1300,47 @@ namespace Server.Spells
|
|||
var mods = new List<ResistanceMod>();
|
||||
|
||||
if (transformSpell.PhysResistOffset != 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Physical, transformSpell.PhysResistOffset));
|
||||
}
|
||||
|
||||
if (transformSpell.FireResistOffset != 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Fire, transformSpell.FireResistOffset));
|
||||
}
|
||||
|
||||
if (transformSpell.ColdResistOffset != 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Cold, transformSpell.ColdResistOffset));
|
||||
}
|
||||
|
||||
if (transformSpell.PoisResistOffset != 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Poison, transformSpell.PoisResistOffset));
|
||||
}
|
||||
|
||||
if (transformSpell.NrgyResistOffset != 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Energy, transformSpell.NrgyResistOffset));
|
||||
}
|
||||
|
||||
if (!((Body)transformSpell.Body).IsHuman)
|
||||
{
|
||||
var mt = caster.Mount;
|
||||
|
||||
if (mt != null)
|
||||
{
|
||||
mt.Rider = null;
|
||||
}
|
||||
}
|
||||
|
||||
caster.BodyMod = transformSpell.Body;
|
||||
caster.HueMod = transformSpell.Hue;
|
||||
|
||||
for (var i = 0; i < mods.Count; ++i)
|
||||
{
|
||||
caster.AddResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
transformSpell.DoEffect(caster);
|
||||
|
||||
|
|
@ -1231,20 +1365,24 @@ namespace Server.Spells
|
|||
var context = GetContext(m);
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
RemoveContext(m, context, resetGraphics);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveContext(Mobile m, TransformContext context, bool resetGraphics)
|
||||
{
|
||||
if (!m_Table.ContainsKey(m))
|
||||
if (!m_Table.Remove(m))
|
||||
{
|
||||
return;
|
||||
|
||||
m_Table.Remove(m);
|
||||
}
|
||||
|
||||
var mods = context.Mods;
|
||||
|
||||
for (var i = 0; i < mods.Count; ++i)
|
||||
{
|
||||
m.RemoveResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
if (resetGraphics)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -75,8 +75,7 @@ namespace Server.Spells
|
|||
|
||||
m_Types[spellID] = type;
|
||||
|
||||
if (!m_IDsFromTypes.ContainsKey(type))
|
||||
m_IDsFromTypes.Add(type, spellID);
|
||||
m_IDsFromTypes.TryAdd(type, spellID);
|
||||
|
||||
if (type.IsSubclassOf(typeof(SpecialMove)))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,10 +62,9 @@ namespace Server.Spells.Bushido
|
|||
|
||||
public static void EndConfidence(Mobile m)
|
||||
{
|
||||
if (m_Table.TryGetValue(m, out var timer))
|
||||
if (m_Table.Remove(m, out var timer))
|
||||
{
|
||||
timer.Stop();
|
||||
m_Table.Remove(m);
|
||||
}
|
||||
|
||||
OnEffectEnd(m, typeof(Confidence));
|
||||
|
|
@ -85,10 +84,9 @@ namespace Server.Spells.Bushido
|
|||
|
||||
public static void StopRegenerating(Mobile m)
|
||||
{
|
||||
if (m_RegenTable.TryGetValue(m, out var timer))
|
||||
if (m_RegenTable.Remove(m, out var timer))
|
||||
{
|
||||
timer.Stop();
|
||||
m_RegenTable.Remove(m);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,10 +77,9 @@ namespace Server.Spells.Bushido
|
|||
|
||||
public static void StopCountering(Mobile m)
|
||||
{
|
||||
if (m_Table.TryGetValue(m, out var timer))
|
||||
if (m_Table.Remove(m, out var timer))
|
||||
{
|
||||
timer.Stop();
|
||||
m_Table.Remove(m);
|
||||
}
|
||||
|
||||
OnEffectEnd(m, typeof(CounterAttack));
|
||||
|
|
|
|||
|
|
@ -181,10 +181,9 @@ namespace Server.Spells.Bushido
|
|||
|
||||
public static void EndEvasion(Mobile m)
|
||||
{
|
||||
if (m_Table.TryGetValue(m, out var timer))
|
||||
if (m_Table.Remove(m, out var timer))
|
||||
{
|
||||
timer.Stop();
|
||||
m_Table.Remove(m);
|
||||
}
|
||||
|
||||
OnEffectEnd(m, typeof(Evasion));
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ namespace Server.Spells.Bushido
|
|||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ClearCurrentMove(attacker);
|
||||
|
||||
|
|
@ -64,7 +66,9 @@ namespace Server.Spells.Bushido
|
|||
var resSpells = attacker.Skills.MagicResist.Value;
|
||||
|
||||
if (resSpells > 0.0)
|
||||
{
|
||||
mods.Add(new DefaultSkillMod(SkillName.MagicResist, true, -resSpells));
|
||||
}
|
||||
|
||||
info = new HonorableExecutionInfo(attacker, mods);
|
||||
info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(7.0), RemovePenalty, info.m_Mobile);
|
||||
|
|
@ -81,12 +85,13 @@ namespace Server.Spells.Bushido
|
|||
|
||||
public static void RemovePenalty(Mobile target)
|
||||
{
|
||||
if (!m_Table.TryGetValue(target, out var info) || !info.m_Penalty)
|
||||
if (!m_Table.Remove(target, out var info) || !info.m_Penalty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
info.Clear();
|
||||
info.m_Timer?.Stop();
|
||||
m_Table.Remove(target);
|
||||
}
|
||||
|
||||
private class HonorableExecutionInfo
|
||||
|
|
@ -114,32 +119,44 @@ namespace Server.Spells.Bushido
|
|||
public void Apply()
|
||||
{
|
||||
if (m_Mods == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < m_Mods.Count; ++i)
|
||||
{
|
||||
var mod = m_Mods[i];
|
||||
|
||||
if (mod is ResistanceMod resistanceMod)
|
||||
{
|
||||
m_Mobile.AddResistanceMod(resistanceMod);
|
||||
}
|
||||
else if (mod is SkillMod skillMod)
|
||||
{
|
||||
m_Mobile.AddSkillMod(skillMod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (m_Mods == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < m_Mods.Count; ++i)
|
||||
{
|
||||
var mod = m_Mods[i];
|
||||
|
||||
if (mod is ResistanceMod resistanceMod)
|
||||
{
|
||||
m_Mobile.RemoveResistanceMod(resistanceMod);
|
||||
}
|
||||
else if (mod is SkillMod skillMod)
|
||||
{
|
||||
m_Mobile.RemoveSkillMod(skillMod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ namespace Server.Spells.Fifth
|
|||
public override bool CheckCast()
|
||||
{
|
||||
if (Core.AOS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Caster.MagicDamageAbsorb > 0)
|
||||
{
|
||||
|
|
@ -57,15 +59,15 @@ namespace Server.Spells.Fifth
|
|||
{
|
||||
var targ = Caster;
|
||||
|
||||
if (m_Table.TryGetValue(targ, out var mods))
|
||||
if (m_Table.Remove(targ, out var mods))
|
||||
{
|
||||
targ.PlaySound(0x1ED);
|
||||
targ.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist);
|
||||
|
||||
m_Table.Remove(targ);
|
||||
|
||||
for (var i = 0; i < mods.Length; ++i)
|
||||
{
|
||||
targ.RemoveResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
BuffInfo.RemoveBuff(targ, BuffIcon.MagicReflection);
|
||||
}
|
||||
|
|
@ -89,7 +91,9 @@ namespace Server.Spells.Fifth
|
|||
m_Table[targ] = mods;
|
||||
|
||||
for (var i = 0; i < mods.Length; ++i)
|
||||
{
|
||||
targ.AddResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
var buffFormat = $"{physiMod}\t+{otherMod}\t+{otherMod}\t+{otherMod}\t+{otherMod}";
|
||||
|
||||
|
|
@ -133,13 +137,16 @@ namespace Server.Spells.Fifth
|
|||
|
||||
public static void EndReflect(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var mods))
|
||||
if (!m_Table.Remove(m, out var mods))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < mods?.Length; ++i)
|
||||
{
|
||||
m.RemoveResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
m_Table.Remove(m);
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.MagicReflection);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ namespace Server.Spells.First
|
|||
public override bool CheckCast()
|
||||
{
|
||||
if (Core.AOS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Caster.MeleeDamageAbsorb > 0)
|
||||
{
|
||||
|
|
@ -59,15 +61,15 @@ namespace Server.Spells.First
|
|||
{
|
||||
var targ = Caster;
|
||||
|
||||
if (m_Table.TryGetValue(targ, out var mods))
|
||||
if (m_Table.Remove(targ, out var mods))
|
||||
{
|
||||
targ.PlaySound(0x1ED);
|
||||
targ.FixedParticles(0x376A, 9, 32, 5008, EffectLayer.Waist);
|
||||
|
||||
m_Table.Remove(targ);
|
||||
|
||||
for (var i = 0; i < mods.Length; ++i)
|
||||
{
|
||||
targ.RemoveResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.ReactiveArmor);
|
||||
}
|
||||
|
|
@ -91,7 +93,9 @@ namespace Server.Spells.First
|
|||
m_Table[targ] = mods;
|
||||
|
||||
for (var i = 0; i < mods.Length; ++i)
|
||||
{
|
||||
targ.AddResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
var physresist = 15 + (int)(targ.Skills.Inscribe.Value / 20);
|
||||
var args = $"{physresist}\t{5}\t{5}\t{5}\t{5}";
|
||||
|
|
@ -140,13 +144,16 @@ namespace Server.Spells.First
|
|||
|
||||
public static void EndArmor(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var mods))
|
||||
if (!m_Table.Remove(m, out var mods))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < mods?.Length; ++i)
|
||||
{
|
||||
m.RemoveResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
m_Table.Remove(m);
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.ReactiveArmor);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,9 +97,8 @@ namespace Server.Spells.Fourth
|
|||
|
||||
public static void RemoveEntry(Mobile m)
|
||||
{
|
||||
if (_Table.TryGetValue(m, out var v))
|
||||
if (_Table.Remove(m, out var v))
|
||||
{
|
||||
_Table.Remove(m);
|
||||
m.EndAction<ArchProtectionSpell>();
|
||||
m.VirtualArmorMod -= Math.Min(v, m.VirtualArmorMod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,9 @@ namespace Server.Spells.Mysticism
|
|||
var mount = Caster.Mount;
|
||||
|
||||
if (mount != null)
|
||||
{
|
||||
mount.Rider = null;
|
||||
}
|
||||
|
||||
Caster.BodyMod = 0x2C1;
|
||||
Caster.HueMod = 0;
|
||||
|
|
@ -112,7 +114,9 @@ namespace Server.Spells.Mysticism
|
|||
};
|
||||
|
||||
for (var i = 0; i < mods.Length; ++i)
|
||||
{
|
||||
Caster.AddResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
m_Table[Caster] = mods;
|
||||
|
||||
|
|
@ -141,17 +145,19 @@ namespace Server.Spells.Mysticism
|
|||
|
||||
public static void RemoveEffects(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var mods))
|
||||
if (!m_Table.Remove(m, out var mods))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < mods.Length; ++i)
|
||||
{
|
||||
m.RemoveResistanceMod(mods[i]);
|
||||
}
|
||||
|
||||
m.BodyMod = 0;
|
||||
m.HueMod = -1;
|
||||
|
||||
m_Table.Remove(m);
|
||||
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.StoneForm);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,7 +151,10 @@ namespace Server.Spells.Necromancy
|
|||
{
|
||||
Type type = null;
|
||||
|
||||
if (c.Owner != null) type = c.Owner.GetType();
|
||||
if (c.Owner != null)
|
||||
{
|
||||
type = c.Owner.GetType();
|
||||
}
|
||||
|
||||
if (c.ItemID != 0x2006 || c.Animated || type == typeof(PlayerMobile) || type == null ||
|
||||
c.Owner != null && c.Owner.Fame < 100 ||
|
||||
|
|
@ -217,10 +220,14 @@ namespace Server.Spells.Necromancy
|
|||
var contains = types.Length == 0;
|
||||
|
||||
for (var j = 0; !contains && j < types.Length; ++j)
|
||||
{
|
||||
contains = types[j].IsAssignableFrom(type);
|
||||
}
|
||||
|
||||
if (contains)
|
||||
return group;
|
||||
{
|
||||
return @group;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -228,41 +235,52 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public static void Unregister(Mobile master, Mobile summoned)
|
||||
{
|
||||
if (master == null)
|
||||
return;
|
||||
|
||||
if (!m_Table.TryGetValue(master, out var list))
|
||||
if (master == null || !m_Table.TryGetValue(master, out var list))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
list.Remove(summoned);
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
m_Table.Remove(master);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Register(Mobile master, Mobile summoned)
|
||||
{
|
||||
if (master == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_Table.TryGetValue(master, out var list))
|
||||
{
|
||||
m_Table[master] = list = new List<Mobile>();
|
||||
}
|
||||
|
||||
for (var i = list.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (i >= list.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var mob = list[i];
|
||||
|
||||
if (mob.Deleted)
|
||||
{
|
||||
list.RemoveAt(i--);
|
||||
}
|
||||
}
|
||||
|
||||
list.Add(summoned);
|
||||
|
||||
if (list.Count > 3)
|
||||
{
|
||||
Timer.DelayCall(list[0].Kill);
|
||||
}
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0), Summoned_Damage, summoned);
|
||||
}
|
||||
|
|
@ -270,20 +288,28 @@ namespace Server.Spells.Necromancy
|
|||
private static void Summoned_Damage(Mobile mob)
|
||||
{
|
||||
if (mob.Hits > 0)
|
||||
{
|
||||
--mob.Hits;
|
||||
}
|
||||
else
|
||||
{
|
||||
mob.Kill();
|
||||
}
|
||||
}
|
||||
|
||||
private static void SummonDelay_Callback(Mobile caster, Corpse corpse, Point3D loc, Map map, CreatureGroup group)
|
||||
{
|
||||
if (corpse.Animated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var owner = corpse.Owner;
|
||||
|
||||
if (owner == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var necromancy = caster.Skills.Necromancy.Value;
|
||||
var spiritSpeak = caster.Skills.SpiritSpeak.Value;
|
||||
|
|
@ -299,7 +325,9 @@ namespace Server.Spells.Necromancy
|
|||
var entry = entries[i];
|
||||
|
||||
if (casterAbility < entry.m_Requirement)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var animates = entry.m_ToSummon;
|
||||
|
||||
|
|
@ -307,7 +335,9 @@ namespace Server.Spells.Necromancy
|
|||
}
|
||||
|
||||
if (toSummon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mobile summoned = null;
|
||||
|
||||
|
|
@ -321,7 +351,9 @@ namespace Server.Spells.Necromancy
|
|||
}
|
||||
|
||||
if (summoned == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (summoned is BaseCreature bc)
|
||||
{
|
||||
|
|
@ -336,7 +368,9 @@ namespace Server.Spells.Necromancy
|
|||
}
|
||||
|
||||
if (summoned is SkeletalDragon dragon)
|
||||
{
|
||||
Scale(dragon, 50); // lose 50% hp and strength
|
||||
}
|
||||
|
||||
summoned.Fame = 0;
|
||||
summoned.Karma = -1500;
|
||||
|
|
@ -357,7 +391,9 @@ namespace Server.Spells.Necromancy
|
|||
toScale = bc.HitsMaxSeed;
|
||||
|
||||
if (toScale > 0)
|
||||
{
|
||||
bc.HitsMaxSeed = AOS.Scale(toScale, scalar);
|
||||
}
|
||||
|
||||
bc.Hits = bc.Hits; // refresh hits
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,9 +45,13 @@ namespace Server.Spells.Necromancy
|
|||
else if (m_OathTable.ContainsKey(m))
|
||||
{
|
||||
if (m.Player)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1061608); // That player is already bonded in a Blood Oath.
|
||||
}
|
||||
else
|
||||
{
|
||||
Caster.SendLocalizedMessage(1061609); // That creature is already bonded in a Blood Oath.
|
||||
}
|
||||
}
|
||||
else if (CheckHSequence(m))
|
||||
{
|
||||
|
|
@ -128,21 +132,22 @@ namespace Server.Spells.Necromancy
|
|||
protected override void OnTick()
|
||||
{
|
||||
if (m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive ||
|
||||
DateTime.UtcNow >= m_End) DoExpire();
|
||||
DateTime.UtcNow >= m_End)
|
||||
{
|
||||
DoExpire();
|
||||
}
|
||||
}
|
||||
|
||||
public void DoExpire()
|
||||
{
|
||||
if (m_OathTable.ContainsKey(m_Caster))
|
||||
if (m_OathTable.Remove(m_Caster))
|
||||
{
|
||||
m_Caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
|
||||
m_OathTable.Remove(m_Caster);
|
||||
}
|
||||
|
||||
if (m_OathTable.ContainsKey(m_Target))
|
||||
if (m_OathTable.Remove(m_Target))
|
||||
{
|
||||
m_Target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
|
||||
m_OathTable.Remove(m_Target);
|
||||
}
|
||||
|
||||
Stop();
|
||||
|
|
|
|||
|
|
@ -57,7 +57,9 @@ namespace Server.Spells.Necromancy
|
|||
var mod = new DefaultSkillMod(SkillName.MagicResist, false, 50.0);
|
||||
|
||||
if (m.Skills.MagicResist.Base > 50.0)
|
||||
{
|
||||
m.AddSkillMod(mod);
|
||||
}
|
||||
|
||||
m_Table[m] = mod;
|
||||
}
|
||||
|
|
@ -81,10 +83,11 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public static bool TryEndEffect(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var mod))
|
||||
if (!m_Table.Remove(m, out var mod))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Table.Remove(m);
|
||||
mod?.Remove();
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -73,12 +73,13 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public static void ClearMindRotScalar(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var tmpB))
|
||||
if (!m_Table.Remove(m, out var tmpB))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot);
|
||||
tmpB.m_MRExpireTimer.Stop();
|
||||
m_Table.Remove(m);
|
||||
m.SendLocalizedMessage(1060872); // Your mind feels normal again.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ namespace Server.Spells.Necromancy
|
|||
public void Target(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckHSequence(m))
|
||||
{
|
||||
|
|
@ -70,7 +72,10 @@ namespace Server.Spells.Necromancy
|
|||
// Calculations for the buff bar
|
||||
var spiritlevel = Caster.Skills.SpiritSpeak.Value / 10;
|
||||
if (spiritlevel < 4)
|
||||
{
|
||||
spiritlevel = 4;
|
||||
}
|
||||
|
||||
var d_MinDamage = 4;
|
||||
var d_MaxDamage = ((int)spiritlevel + 1) * 3;
|
||||
var args = $"{d_MinDamage}\t{d_MaxDamage}";
|
||||
|
|
@ -113,13 +118,13 @@ namespace Server.Spells.Necromancy
|
|||
|
||||
public static bool RemoveCurse(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var timer))
|
||||
if (!m_Table.Remove(m, out var timer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
timer.Stop();
|
||||
m.SendLocalizedMessage(1061687); // You can breath normally again.
|
||||
|
||||
m_Table.Remove(m);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +158,9 @@ namespace Server.Spells.Necromancy
|
|||
m_Count = (int)spiritLevel;
|
||||
|
||||
if (m_Count < 4)
|
||||
{
|
||||
m_Count = 4;
|
||||
}
|
||||
|
||||
m_MaxCount = m_Count;
|
||||
}
|
||||
|
|
@ -167,7 +174,9 @@ namespace Server.Spells.Necromancy
|
|||
}
|
||||
|
||||
if (!m_Target.Alive || DateTime.UtcNow < m_NextHit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
--m_Count;
|
||||
|
||||
|
|
@ -182,9 +191,13 @@ namespace Server.Spells.Necromancy
|
|||
var delay = (int)Math.Ceiling((1.0 + 5 * m_Count) / m_MaxCount);
|
||||
|
||||
if (delay <= 5)
|
||||
{
|
||||
m_HitDelay = delay;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HitDelay = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -203,16 +216,22 @@ namespace Server.Spells.Necromancy
|
|||
damage *= 3 - (double)m_Target.Stam / m_Target.StamMax * 2;
|
||||
|
||||
if (damage < 1)
|
||||
{
|
||||
damage = 1;
|
||||
}
|
||||
|
||||
if (!m_Target.Player)
|
||||
{
|
||||
damage *= 1.75;
|
||||
}
|
||||
|
||||
AOS.Damage(m_Target, m_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
|
||||
{
|
||||
m_Target.RevealingAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ namespace Server.Spells.Ninjitsu
|
|||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ClearCurrentMove(attacker);
|
||||
|
||||
|
|
@ -32,9 +34,13 @@ namespace Server.Spells.Ninjitsu
|
|||
var isRanged = attacker.Weapon is BaseRanged;
|
||||
|
||||
if (ninjitsu < 100) // This formula is an approximation from OSI data. TODO: find correct formula
|
||||
{
|
||||
chance = 30 + (ninjitsu - 85) * 2.2;
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 63 + (ninjitsu - 100) * 1.1;
|
||||
}
|
||||
|
||||
if (chance / 100 < Utility.RandomDouble())
|
||||
{
|
||||
|
|
@ -44,16 +50,16 @@ namespace Server.Spells.Ninjitsu
|
|||
|
||||
var damageBonus = 0;
|
||||
|
||||
if (m_Table.TryGetValue(defender, out var info))
|
||||
if (m_Table.Remove(defender, out var info))
|
||||
{
|
||||
defender.SendLocalizedMessage(1063092); // Your opponent lands another Death Strike!
|
||||
|
||||
if (info.m_Steps > 0)
|
||||
{
|
||||
damageBonus = attacker.Skills.Ninjitsu.Fixed / 150;
|
||||
}
|
||||
|
||||
info.m_Timer?.Stop();
|
||||
|
||||
m_Table.Remove(defender);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -78,13 +84,17 @@ namespace Server.Spells.Ninjitsu
|
|||
public static void AddStep(Mobile m)
|
||||
{
|
||||
if (m_Table.TryGetValue(m, out var info) && ++info.m_Steps >= 5)
|
||||
{
|
||||
ProcessDeathStrike(m);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessDeathStrike(Mobile defender)
|
||||
{
|
||||
if (!m_Table.TryGetValue(defender, out var info))
|
||||
if (!m_Table.Remove(defender, out var info))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int damage;
|
||||
|
||||
|
|
@ -97,16 +107,24 @@ namespace Server.Spells.Ninjitsu
|
|||
info.m_Attacker.Skills.Stealth.Value) / 220;
|
||||
|
||||
if (scalar > 1)
|
||||
{
|
||||
scalar = 1;
|
||||
}
|
||||
|
||||
// New formula doesn't apply DamageBonus anymore, caps must be, directly, 60/30.
|
||||
if (info.m_Steps >= 5)
|
||||
{
|
||||
damage = (int)Math.Floor(Math.Min(60, ninjitsu / 3 * (0.3 + 0.7 * scalar) + stalkingBonus));
|
||||
}
|
||||
else
|
||||
{
|
||||
damage = (int)Math.Floor(Math.Min(30, ninjitsu / 9 * (0.3 + 0.7 * scalar) + stalkingBonus));
|
||||
}
|
||||
|
||||
if (info.m_isRanged)
|
||||
{
|
||||
damage /= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -118,8 +136,11 @@ namespace Server.Spells.Ninjitsu
|
|||
}
|
||||
|
||||
if (Core.ML)
|
||||
{
|
||||
info.m_Target.Damage(damage, info.m_Attacker); // Damage is direct.
|
||||
}
|
||||
else
|
||||
{
|
||||
AOS.Damage(
|
||||
info.m_Target,
|
||||
info.m_Attacker,
|
||||
|
|
@ -136,10 +157,9 @@ namespace Server.Spells.Ninjitsu
|
|||
false,
|
||||
true
|
||||
); // Damage is physical.
|
||||
}
|
||||
|
||||
info.m_Timer?.Stop();
|
||||
|
||||
m_Table.Remove(info.m_Target);
|
||||
}
|
||||
|
||||
private class DeathStrikeInfo
|
||||
|
|
|
|||
|
|
@ -81,11 +81,10 @@ namespace Server.Spells.Ninjitsu
|
|||
|
||||
public override void OnClearMove(Mobile from)
|
||||
{
|
||||
if (!m_Table.TryGetValue(from, out var info))
|
||||
return;
|
||||
|
||||
info.m_Timer.Stop();
|
||||
m_Table.Remove(info.m_Mobile);
|
||||
if (m_Table.Remove(from, out var info))
|
||||
{
|
||||
info.m_Timer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public static double GetBonus(Mobile from)
|
||||
|
|
|
|||
|
|
@ -53,11 +53,9 @@ namespace Server.Spells.Ninjitsu
|
|||
|
||||
attacker.RevealingAction();
|
||||
|
||||
if (m_Table.TryGetValue(defender, out var info))
|
||||
if (m_Table.Remove(defender, out var info))
|
||||
{
|
||||
info.m_Timer?.Stop();
|
||||
|
||||
m_Table.Remove(defender);
|
||||
}
|
||||
|
||||
var ninjitsu = attacker.Skills.Ninjitsu.Fixed;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ namespace Server.Spells.Second
|
|||
public override bool CheckCast()
|
||||
{
|
||||
if (Core.AOS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Registry.ContainsKey(Caster))
|
||||
{
|
||||
|
|
@ -38,7 +40,9 @@ namespace Server.Spells.Second
|
|||
}
|
||||
|
||||
if (Caster.CanBeginAction<DefensiveSpell>())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time.
|
||||
return false;
|
||||
|
|
@ -55,12 +59,11 @@ namespace Server.Spells.Second
|
|||
* even after dying<EFBFBD>until you <EFBFBD>turn them off<EFBFBD> by casting them again.
|
||||
*/
|
||||
|
||||
if (m_Table.TryGetValue(target, out var mods))
|
||||
if (m_Table.Remove(target, out var mods))
|
||||
{
|
||||
target.PlaySound(0x1ED);
|
||||
target.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist);
|
||||
|
||||
m_Table.Remove(target);
|
||||
Registry.Remove(target);
|
||||
|
||||
target.RemoveResistanceMod(mods.Item1);
|
||||
|
|
@ -100,10 +103,11 @@ namespace Server.Spells.Second
|
|||
|
||||
public static void EndProtection(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var mods))
|
||||
if (!m_Table.Remove(m, out var mods))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Table.Remove(m);
|
||||
Registry.Remove(m);
|
||||
|
||||
m.RemoveResistanceMod(mods.Item1);
|
||||
|
|
@ -117,7 +121,9 @@ namespace Server.Spells.Second
|
|||
if (Core.AOS)
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
Toggle(Caster, Caster);
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,11 +93,10 @@ namespace Server.Spells.Sixth
|
|||
|
||||
public static void RemoveTimer(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var t))
|
||||
return;
|
||||
|
||||
t.Stop();
|
||||
m_Table.Remove(m);
|
||||
if (m_Table.Remove(m, out var t))
|
||||
{
|
||||
t.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ namespace Server.Spells.Spellweaving
|
|||
public void Target(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Caster.CanSee(m))
|
||||
{
|
||||
|
|
@ -94,10 +96,10 @@ namespace Server.Spells.Spellweaving
|
|||
|
||||
public static bool StopEffect(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var info))
|
||||
if (!m_Table.Remove(m, out var info))
|
||||
{
|
||||
return false;
|
||||
|
||||
m_Table.Remove(m);
|
||||
}
|
||||
|
||||
info.m_Timer.Stop();
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.GiftOfRenewal);
|
||||
|
|
@ -151,7 +153,9 @@ namespace Server.Spells.Spellweaving
|
|||
}
|
||||
|
||||
if (m.Hits >= m.HitsMax)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var toHeal = m_GiftInfo.m_HitsPerRound;
|
||||
|
||||
|
|
|
|||
|
|
@ -77,17 +77,20 @@ namespace Server.Spells.Spellweaving
|
|||
private static void FinishEffect(DelayedEffectEntry effect)
|
||||
{
|
||||
if (m_WeaponDamageTable.TryGetValue(effect.m_Weapon, out var entry))
|
||||
{
|
||||
AOS.Damage(effect.m_Target, entry.m_Caster, entry.m_Damage, 0, 100, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void StopImmolating(BaseWeapon weapon)
|
||||
{
|
||||
if (!m_WeaponDamageTable.TryGetValue(weapon, out var entry))
|
||||
if (!m_WeaponDamageTable.Remove(weapon, out var entry))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
entry.m_Caster?.PlaySound(0x27);
|
||||
entry.m_Timer.Stop();
|
||||
m_WeaponDamageTable.Remove(weapon);
|
||||
|
||||
weapon.InvalidateProperties();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,9 @@ namespace Server.Spells.Spellweaving
|
|||
{
|
||||
if (Caster == m || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanBeHarmful(m, false) ||
|
||||
!Caster.InLOS(m))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Caster.DoHarmful(m);
|
||||
|
||||
|
|
@ -57,7 +59,9 @@ namespace Server.Spells.Spellweaving
|
|||
SpellHelper.Damage(this, m, m.Player && Caster.Player ? pvpDamage : pvmDamage, 0, 0, 0, 0, 100);
|
||||
|
||||
if (oldSpell == null || oldSpell == m.Spell || CheckResisted(m))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_Table[m] = Timer.DelayCall(duration, DoExpire, m);
|
||||
|
||||
|
|
@ -77,11 +81,12 @@ namespace Server.Spells.Spellweaving
|
|||
|
||||
public static void DoExpire(Mobile m)
|
||||
{
|
||||
if (!m_Table.TryGetValue(m, out var t))
|
||||
if (!m_Table.Remove(m, out var t))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
t.Stop();
|
||||
m_Table.Remove(m);
|
||||
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Thunderstorm);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue