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)))
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue