### Summary - Fixes various memory leaks related to spells - Fixes Spell Plague - Added ability to determine if `sdi` should take effect for Spell Damage. - Fixes animal form timer ticking non-stop while logged out.
139 lines
No EOL
3.9 KiB
C#
139 lines
No EOL
3.9 KiB
C#
using System;
|
||
using Server.Items;
|
||
|
||
namespace Server.Spells.Mysticism;
|
||
|
||
public abstract class MysticSpell : Spell
|
||
{
|
||
private static int[] _manaTable = { 4, 6, 9, 11, 14, 20, 40, 50 };
|
||
private static double[] _requiredSkill = { 0.0, 8.0, 20.0, 33.0, 45.0, 58.0, 70.0, 83.0 };
|
||
|
||
public MysticSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info)
|
||
{
|
||
}
|
||
|
||
public abstract SpellCircle Circle { get; }
|
||
|
||
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.5 + 0.25 * (int)Circle);
|
||
|
||
public virtual double RequiredSkill
|
||
{
|
||
get
|
||
{
|
||
var circle = (int)Circle;
|
||
|
||
if (Scroll != null)
|
||
{
|
||
circle -= 2;
|
||
}
|
||
|
||
return _requiredSkill[circle];
|
||
}
|
||
}
|
||
|
||
public override SkillName CastSkill => SkillName.Mysticism;
|
||
|
||
/*
|
||
* As per OSI Publish 64:
|
||
* Imbuing is not the only skill associated with Mysticism now.
|
||
* Players can use EITHER their Focus skill or Imbuing skill.
|
||
* Evaluate Intelligence no longer has any effect on a Mystic’s spell power.
|
||
*/
|
||
public override double GetDamageSkill(Mobile m) => Math.Max(m.Skills.Imbuing.Value, m.Skills.Focus.Value);
|
||
|
||
public override int GetDamageFixed(Mobile m) => Math.Max(m.Skills.Imbuing.Fixed, m.Skills.Focus.Fixed);
|
||
|
||
public override void GetCastSkills(out double min, out double max)
|
||
{
|
||
var requiredSkill = RequiredSkill;
|
||
|
||
// As per Mysticism page at the UO Herald Playguide
|
||
// This means that we have 25% success chance at min Required Skill
|
||
min = requiredSkill - 12.5;
|
||
max = requiredSkill + 37.5;
|
||
}
|
||
|
||
public override int GetMana() => Scroll is BaseWand ? 0 : _manaTable[(int)Circle];
|
||
|
||
public override bool CheckCast()
|
||
{
|
||
if (!base.CheckCast())
|
||
{
|
||
return false;
|
||
}
|
||
|
||
var mana = ScaleMana(GetMana());
|
||
|
||
if (Caster.Mana < mana)
|
||
{
|
||
// You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
||
Caster.SendLocalizedMessage(1060174, mana.ToString());
|
||
return false;
|
||
}
|
||
|
||
var requiredSkill = RequiredSkill;
|
||
|
||
if (Caster.Skills[CastSkill].Value < requiredSkill)
|
||
{
|
||
// You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
|
||
Caster.SendLocalizedMessage(1063013, $"{requiredSkill:F1}\t{CastSkill}\t ");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
public override void OnBeginCast()
|
||
{
|
||
base.OnBeginCast();
|
||
|
||
SendCastEffect();
|
||
}
|
||
|
||
public virtual void SendCastEffect()
|
||
{
|
||
Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 0x66C, 3);
|
||
}
|
||
|
||
public static double GetBaseSkill(Mobile m) => m.Skills.Mysticism.Value;
|
||
|
||
public virtual bool CheckResisted(Mobile target)
|
||
{
|
||
var n = GetResistPercent(target);
|
||
|
||
n /= 100.0;
|
||
|
||
if (n <= 0.0)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (n >= 1.0)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
var maxSkill = (1 + (int)Circle) * 10;
|
||
maxSkill += (1 + (int)Circle / 6) * 25;
|
||
|
||
if (target.Skills.MagicResist.Value < maxSkill)
|
||
{
|
||
target.CheckSkill(SkillName.MagicResist, 0.0, target.Skills.MagicResist.Cap);
|
||
}
|
||
|
||
return n >= Utility.RandomDouble();
|
||
}
|
||
|
||
public virtual double GetResistPercentForCircle(Mobile target, SpellCircle circle)
|
||
{
|
||
var magicResist = target.Skills.MagicResist.Value;
|
||
var firstPercent = magicResist / 5.0;
|
||
var secondPercent = magicResist -
|
||
((Caster.Skills[CastSkill].Value - 20.0) / 5.0 + (1 + (int)circle) * 5.0);
|
||
|
||
// Seems should be about half of what stratics says.
|
||
return (firstPercent > secondPercent ? firstPercent : secondPercent) / 2.0;
|
||
}
|
||
|
||
public virtual double GetResistPercent(Mobile target) => GetResistPercentForCircle(target, Circle);
|
||
} |