Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
820
Scripts/Mobiles/AI/Magical AI/SpellbinderAI.cs
Normal file
820
Scripts/Mobiles/AI/Magical AI/SpellbinderAI.cs
Normal file
@@ -0,0 +1,820 @@
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Spells;
|
||||
using Server.Spells.Fifth;
|
||||
using Server.Spells.First;
|
||||
using Server.Spells.Fourth;
|
||||
using Server.Spells.Necromancy;
|
||||
using Server.Spells.Second;
|
||||
using Server.Spells.Seventh;
|
||||
using Server.Spells.Sixth;
|
||||
using Server.Spells.Third;
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class SpellbinderAI : BaseAI
|
||||
{
|
||||
private static readonly int[] m_Offsets =
|
||||
{
|
||||
-1, -1, -1, 0, -1, 1, 0, -1, 0, 1, 1, -1, 1, 0, 1, 1, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -1, -2, -1, 2, 0, -2, 0,
|
||||
2, 1, -2, 1, 2, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2
|
||||
};
|
||||
|
||||
private const double HealChance = 0.05; // 5% chance to heal at gm necromancy, uses spirit speak healing
|
||||
private const double TeleportChance = 0.05; // 5% chance to teleport at gm magery
|
||||
private const double DispelChance = 0.75; // 75% chance to dispel at gm magery
|
||||
private DateTime m_NextCastTime;
|
||||
private DateTime m_NextHealTime = DateTime.UtcNow;
|
||||
|
||||
public SpellbinderAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool Think()
|
||||
{
|
||||
if (m_Mobile.Deleted)
|
||||
return false;
|
||||
|
||||
var targ = m_Mobile.Target;
|
||||
|
||||
if (targ != null)
|
||||
{
|
||||
ProcessTarget(targ);
|
||||
|
||||
return true;
|
||||
}
|
||||
return base.Think();
|
||||
}
|
||||
|
||||
public virtual double ScaleByNecromancy(double v)
|
||||
{
|
||||
return m_Mobile.Skills[SkillName.Necromancy].Value * v * 0.01;
|
||||
}
|
||||
|
||||
public virtual double ScaleByMagery(double v)
|
||||
{
|
||||
return m_Mobile.Skills[SkillName.Magery].Value * v * 0.01;
|
||||
}
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
m_NextCastTime = DateTime.UtcNow;
|
||||
}
|
||||
else if (m_Mobile.Mana < m_Mobile.ManaMax)
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to meditate");
|
||||
|
||||
m_Mobile.UseSkill(SkillName.Meditation);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am wandering");
|
||||
|
||||
m_Mobile.Warmode = false;
|
||||
|
||||
base.DoActionWander();
|
||||
|
||||
if (m_Mobile.Poisoned)
|
||||
{
|
||||
new CureSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (!m_Mobile.Summoned)
|
||||
{
|
||||
if (m_Mobile.Hits < (m_Mobile.HitsMax - 50))
|
||||
{
|
||||
if (!new GreaterHealSpell(m_Mobile, null).Cast())
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (m_Mobile.Hits < (m_Mobile.HitsMax - 10))
|
||||
{
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RunTo(Mobile m)
|
||||
{
|
||||
if (m.Paralyzed || m.Frozen)
|
||||
{
|
||||
if (m_Mobile.InRange(m, 1))
|
||||
RunFrom(m);
|
||||
else if (!m_Mobile.InRange(m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2) && !MoveTo(m, true, 1))
|
||||
OnFailedMove();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_Mobile.InRange(m, m_Mobile.RangeFight))
|
||||
{
|
||||
if (!MoveTo(m, true, 1))
|
||||
OnFailedMove();
|
||||
}
|
||||
else if (m_Mobile.InRange(m, m_Mobile.RangeFight - 1))
|
||||
{
|
||||
RunFrom(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RunFrom(IDamageable m)
|
||||
{
|
||||
Run((Direction)((int)m_Mobile.GetDirectionTo(m) - 4) & Direction.Mask);
|
||||
}
|
||||
|
||||
public void OnFailedMove()
|
||||
{
|
||||
if (!m_Mobile.DisallowAllMoves && ScaleByMagery(TeleportChance) > Utility.RandomDouble())
|
||||
{
|
||||
if (m_Mobile.Target != null)
|
||||
m_Mobile.Target.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
|
||||
new TeleportSpell(m_Mobile, null).Cast();
|
||||
|
||||
m_Mobile.DebugSay("I am stuck, I'm going to try teleporting away");
|
||||
}
|
||||
else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am stuck");
|
||||
}
|
||||
}
|
||||
|
||||
public void Run(Direction d)
|
||||
{
|
||||
if ((m_Mobile.Spell != null && m_Mobile.Spell.IsCasting) || !m_Mobile.CanMove || m_Mobile.Paralyzed ||
|
||||
m_Mobile.Frozen || m_Mobile.DisallowAllMoves)
|
||||
return;
|
||||
|
||||
m_Mobile.Direction = d | Direction.Running;
|
||||
|
||||
if (!DoMove(m_Mobile.Direction, true))
|
||||
OnFailedMove();
|
||||
}
|
||||
|
||||
public virtual Spell GetRandomCurseSpell()
|
||||
{
|
||||
var necro = (int)((m_Mobile.Skills[SkillName.Necromancy].Value + 50.0) / (100.0 / 7.0));
|
||||
var mage = (int)((m_Mobile.Skills[SkillName.Magery].Value + 50.0) / (100.0 / 7.0));
|
||||
|
||||
if (mage < 1)
|
||||
mage = 1;
|
||||
|
||||
if (necro < 1)
|
||||
necro = 1;
|
||||
|
||||
if (m_Mobile.Skills[SkillName.Necromancy].Value > 30 && Utility.Random(necro) > Utility.Random(mage))
|
||||
{
|
||||
switch (Utility.Random(necro - 5))
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return new CorpseSkinSpell(m_Mobile, null);
|
||||
case 2:
|
||||
case 3:
|
||||
return new MindRotSpell(m_Mobile, null);
|
||||
default:
|
||||
return new MindRotSpell(m_Mobile, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (Utility.RandomBool() && mage > 3)
|
||||
return new CurseSpell(m_Mobile, null);
|
||||
|
||||
switch (Utility.Random(3))
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
return new WeakenSpell(m_Mobile, null);
|
||||
case 1:
|
||||
return new ClumsySpell(m_Mobile, null);
|
||||
case 2:
|
||||
return new FeeblemindSpell(m_Mobile, null);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Spell GetRandomManaDrainSpell()
|
||||
{
|
||||
if (Utility.RandomBool())
|
||||
{
|
||||
if (m_Mobile.Skills[SkillName.Magery].Value >= 80.0)
|
||||
return new ManaVampireSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return new ManaDrainSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
public virtual Spell DoDispel(Mobile toDispel)
|
||||
{
|
||||
if (ScaleByMagery(DispelChance) > Utility.RandomDouble())
|
||||
return new DispelSpell(m_Mobile, null);
|
||||
|
||||
return ChooseSpell(toDispel);
|
||||
}
|
||||
|
||||
public virtual Spell ChooseSpell(IDamageable c)
|
||||
{
|
||||
var spell = CheckCastHealingSpell();
|
||||
|
||||
if (spell != null)
|
||||
return spell;
|
||||
|
||||
if (!(c is Mobile))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var mob = c as Mobile;
|
||||
var damage = ((m_Mobile.Skills[SkillName.SpiritSpeak].Value - mob.Skills[SkillName.MagicResist].Value) / 10) +
|
||||
(mob.Player ? 18 : 30);
|
||||
|
||||
if (damage > c.Hits)
|
||||
spell = new ManaDrainSpell(m_Mobile, null);
|
||||
|
||||
switch (Utility.Random(16))
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2: // Poison them
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to BloodOath");
|
||||
|
||||
if (!mob.Poisoned)
|
||||
spell = new BloodOathSpell(m_Mobile, null);
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // Bless ourselves.
|
||||
{
|
||||
m_Mobile.DebugSay("Blessing myself");
|
||||
|
||||
spell = new BlessSpell(m_Mobile, null);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
case 5:
|
||||
case 6: // Curse them.
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to curse");
|
||||
|
||||
spell = GetRandomCurseSpell();
|
||||
break;
|
||||
}
|
||||
case 7: // Paralyze them.
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to paralyze");
|
||||
|
||||
if (m_Mobile.Skills[SkillName.Magery].Value > 50.0)
|
||||
spell = new ParalyzeSpell(m_Mobile, null);
|
||||
|
||||
break;
|
||||
}
|
||||
case 8: // Drain mana
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to drain mana");
|
||||
|
||||
spell = GetRandomManaDrainSpell();
|
||||
break;
|
||||
}
|
||||
case 9: // Blood oath them
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to blood oath");
|
||||
|
||||
if (m_Mobile.Skills[SkillName.Necromancy].Value > 30 && BloodOathSpell.GetBloodOath(mob) != m_Mobile)
|
||||
spell = new BloodOathSpell(m_Mobile, null);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return spell;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
var c = m_Mobile.Combatant;
|
||||
m_Mobile.Warmode = true;
|
||||
|
||||
if (c == null || c.Deleted || !c.Alive || (c is Mobile && ((Mobile)c).IsDeadBondedPet) || !m_Mobile.CanSee(c) ||
|
||||
!m_Mobile.CanBeHarmful(c, false) || c.Map != m_Mobile.Map)
|
||||
{
|
||||
// Our combatant is deleted, dead, hidden, or we cannot hurt them
|
||||
// Try to find another combatant
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("Something happened to my combatant, so I am going to fight {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = c = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("Something happened to my combatant, and nothing is around. I am on guard.");
|
||||
Action = ActionType.Guard;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_Mobile.InLOS(c))
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.Combatant = c = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_Mobile.StunReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 &&
|
||||
m_Mobile.Skills[SkillName.Anatomy].Value >= 80.0)
|
||||
EventSink.InvokeStunRequest(new StunRequestEventArgs(m_Mobile));
|
||||
|
||||
if (!m_Mobile.InRange(c, m_Mobile.RangePerception))
|
||||
{
|
||||
// They are somewhat far away, can we find something else?
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
else if (!m_Mobile.InRange(c, m_Mobile.RangePerception * 3))
|
||||
{
|
||||
m_Mobile.Combatant = null;
|
||||
}
|
||||
|
||||
c = m_Mobile.Combatant;
|
||||
|
||||
if (c == null)
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant has fled, so I am on guard");
|
||||
Action = ActionType.Guard;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee)
|
||||
{
|
||||
if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100)
|
||||
{
|
||||
// We are low on health, should we flee?
|
||||
if (Utility.Random(100) <= Math.Max(10, 10 + c.Hits - m_Mobile.Hits))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to flee from {0}", c.Name);
|
||||
Action = ActionType.Flee;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Mobile.Spell == null && DateTime.UtcNow > m_NextCastTime && m_Mobile.InRange(c, 12))
|
||||
{
|
||||
// We are ready to cast a spell
|
||||
Spell spell = null;
|
||||
var toDispel = FindDispelTarget(true);
|
||||
|
||||
if (m_Mobile.Poisoned) // Top cast priority is cure
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to cure myself");
|
||||
|
||||
spell = new CureSpell(m_Mobile, null);
|
||||
}
|
||||
else if (toDispel != null) // Something dispellable is attacking us
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to dispel {0}", toDispel);
|
||||
|
||||
spell = DoDispel(toDispel);
|
||||
}
|
||||
else if (c is Mobile && (((Mobile)c).Spell is HealSpell || ((Mobile)c).Spell is GreaterHealSpell) &&
|
||||
!((Mobile)c).Poisoned) // They have a heal spell out
|
||||
{
|
||||
spell = new BloodOathSpell(m_Mobile, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
spell = ChooseSpell(c);
|
||||
}
|
||||
|
||||
// Now we have a spell picked
|
||||
// Move first before casting
|
||||
|
||||
if (toDispel != null)
|
||||
{
|
||||
if (m_Mobile.InRange(toDispel, 10))
|
||||
RunFrom(toDispel);
|
||||
else if (!m_Mobile.InRange(toDispel, 12))
|
||||
RunTo(toDispel);
|
||||
}
|
||||
else if (c is Mobile)
|
||||
{
|
||||
RunTo((Mobile)c);
|
||||
}
|
||||
|
||||
if (spell != null)
|
||||
spell.Cast();
|
||||
|
||||
TimeSpan delay;
|
||||
|
||||
if (spell is DispelSpell)
|
||||
delay = TimeSpan.FromSeconds(m_Mobile.ActiveSpeed);
|
||||
else
|
||||
delay = GetDelay();
|
||||
|
||||
m_NextCastTime = DateTime.UtcNow + delay;
|
||||
}
|
||||
else if (c is Mobile && (m_Mobile.Spell == null || !m_Mobile.Spell.IsCasting))
|
||||
{
|
||||
RunTo((Mobile)c);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionGuard()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.Poisoned)
|
||||
{
|
||||
new CureSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (!m_Mobile.Summoned && ((ScaleByMagery(HealChance) > Utility.RandomDouble())))
|
||||
{
|
||||
if (m_Mobile.Hits < (m_Mobile.HitsMax - 50))
|
||||
{
|
||||
if (!new GreaterHealSpell(m_Mobile, null).Cast())
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (m_Mobile.Hits < (m_Mobile.HitsMax - 10))
|
||||
{
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionFlee()
|
||||
{
|
||||
var c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if ((m_Mobile.Mana > 20 || m_Mobile.Mana == m_Mobile.ManaMax) && m_Mobile.Hits > (m_Mobile.HitsMax / 2))
|
||||
{
|
||||
// If I have a target, go back and fight them
|
||||
if (c != null && m_Mobile.GetDistanceToSqrt(c) <= m_Mobile.RangePerception * 2)
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, reengaging {0}", c.Name);
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, my guard is up");
|
||||
Action = ActionType.Guard;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionFlee();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Mobile FindDispelTarget(bool activeOnly)
|
||||
{
|
||||
if (m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel(m_Mobile) || m_Mobile.AutoDispel)
|
||||
return null;
|
||||
|
||||
if (activeOnly)
|
||||
{
|
||||
var aggressed = m_Mobile.Aggressed;
|
||||
var aggressors = m_Mobile.Aggressors;
|
||||
|
||||
Mobile active = null;
|
||||
var activePrio = 0.0;
|
||||
|
||||
var comb = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && m_Mobile.InRange(comb, 12) &&
|
||||
CanDispel(comb))
|
||||
{
|
||||
active = comb;
|
||||
activePrio = m_Mobile.GetDistanceToSqrt(comb);
|
||||
|
||||
if (activePrio <= 2)
|
||||
return active;
|
||||
}
|
||||
|
||||
for (var i = 0; i < aggressed.Count; ++i)
|
||||
{
|
||||
var info = aggressed[i];
|
||||
var m = info.Defender;
|
||||
|
||||
if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, 12) && CanDispel(m))
|
||||
{
|
||||
var prio = m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (active == null || prio < activePrio)
|
||||
{
|
||||
active = m;
|
||||
activePrio = prio;
|
||||
|
||||
if (activePrio <= 2)
|
||||
return active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < aggressors.Count; ++i)
|
||||
{
|
||||
var info = aggressors[i];
|
||||
var m = info.Attacker;
|
||||
|
||||
if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, 12) && CanDispel(m))
|
||||
{
|
||||
var prio = m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (active == null || prio < activePrio)
|
||||
{
|
||||
active = m;
|
||||
activePrio = prio;
|
||||
|
||||
if (activePrio <= 2)
|
||||
return active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
var map = m_Mobile.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Mobile active = null, inactive = null;
|
||||
double actPrio = 0.0, inactPrio = 0.0;
|
||||
|
||||
var comb = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && CanDispel(comb))
|
||||
{
|
||||
active = inactive = comb;
|
||||
actPrio = inactPrio = m_Mobile.GetDistanceToSqrt(comb);
|
||||
}
|
||||
|
||||
IPooledEnumerable eable = m_Mobile.GetMobilesInRange(12);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m != m_Mobile && CanDispel(m))
|
||||
{
|
||||
var prio = m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (!activeOnly && (inactive == null || prio < inactPrio))
|
||||
{
|
||||
inactive = m;
|
||||
inactPrio = prio;
|
||||
}
|
||||
|
||||
if ((m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio))
|
||||
{
|
||||
active = m;
|
||||
actPrio = prio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
return active != null ? active : inactive;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool CanDispel(Mobile m)
|
||||
{
|
||||
return (m is BaseCreature && ((BaseCreature)m).Summoned && m_Mobile.CanBeHarmful(m, false) &&
|
||||
!((BaseCreature)m).IsAnimatedDead);
|
||||
}
|
||||
|
||||
private Spell CheckCastHealingSpell()
|
||||
{
|
||||
// If I'm poisoned, always attempt to cure.
|
||||
if (m_Mobile.Poisoned)
|
||||
return new CureSpell(m_Mobile, null);
|
||||
|
||||
// Summoned creatures never heal themselves.
|
||||
if (m_Mobile.Summoned)
|
||||
return null;
|
||||
|
||||
if (m_Mobile.Controlled)
|
||||
{
|
||||
if (DateTime.UtcNow < m_NextHealTime)
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ScaleByMagery(HealChance) < Utility.RandomDouble())
|
||||
return null;
|
||||
|
||||
Spell spell = null;
|
||||
|
||||
if (m_Mobile.Hits < (m_Mobile.HitsMax - 50))
|
||||
{
|
||||
spell = new GreaterHealSpell(m_Mobile, null);
|
||||
|
||||
if (spell == null)
|
||||
spell = new HealSpell(m_Mobile, null);
|
||||
}
|
||||
else if (m_Mobile.Hits < (m_Mobile.HitsMax - 10))
|
||||
spell = new HealSpell(m_Mobile, null);
|
||||
|
||||
double delay;
|
||||
|
||||
if (m_Mobile.Int >= 500)
|
||||
delay = Utility.RandomMinMax(7, 10);
|
||||
else
|
||||
delay = Math.Sqrt(600 - m_Mobile.Int);
|
||||
|
||||
m_Mobile.UseSkill(SkillName.SpiritSpeak);
|
||||
|
||||
m_NextHealTime = DateTime.UtcNow + TimeSpan.FromSeconds(delay);
|
||||
|
||||
return spell;
|
||||
}
|
||||
|
||||
private TimeSpan GetDelay()
|
||||
{
|
||||
var del = ScaleByMagery(3.0);
|
||||
var min = 6.0 - (del * 0.75);
|
||||
var max = 6.0 - (del * 1.25);
|
||||
|
||||
return TimeSpan.FromSeconds(min + ((max - min) * Utility.RandomDouble()));
|
||||
}
|
||||
|
||||
private void ProcessTarget(Target targ)
|
||||
{
|
||||
var isDispel = (targ is DispelSpell.InternalTarget);
|
||||
var isParalyze = (targ is ParalyzeSpell.InternalTarget);
|
||||
var isTeleport = (targ is TeleportSpell.InternalTarget);
|
||||
var teleportAway = false;
|
||||
|
||||
Mobile toTarget;
|
||||
|
||||
if (isDispel)
|
||||
{
|
||||
toTarget = FindDispelTarget(false);
|
||||
|
||||
if (toTarget != null && m_Mobile.InRange(toTarget, 10))
|
||||
RunFrom(toTarget);
|
||||
}
|
||||
else if (isParalyze || isTeleport)
|
||||
{
|
||||
toTarget = FindDispelTarget(true);
|
||||
|
||||
if (toTarget == null)
|
||||
{
|
||||
toTarget = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (toTarget != null)
|
||||
RunTo(toTarget);
|
||||
}
|
||||
else if (m_Mobile.InRange(toTarget, 10))
|
||||
{
|
||||
RunFrom(toTarget);
|
||||
teleportAway = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
teleportAway = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
toTarget = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (toTarget != null)
|
||||
RunTo(toTarget);
|
||||
}
|
||||
|
||||
if ((targ.Flags & TargetFlags.Harmful) != 0 && toTarget != null)
|
||||
{
|
||||
if ((targ.Range == -1 || m_Mobile.InRange(toTarget, targ.Range)) && m_Mobile.CanSee(toTarget) &&
|
||||
m_Mobile.InLOS(toTarget))
|
||||
{
|
||||
targ.Invoke(m_Mobile, toTarget);
|
||||
}
|
||||
else if (isDispel)
|
||||
{
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
}
|
||||
}
|
||||
else if ((targ.Flags & TargetFlags.Beneficial) != 0)
|
||||
{
|
||||
targ.Invoke(m_Mobile, m_Mobile);
|
||||
}
|
||||
else if (isTeleport && toTarget != null)
|
||||
{
|
||||
var map = m_Mobile.Map;
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
int px, py;
|
||||
|
||||
if (teleportAway)
|
||||
{
|
||||
var rx = m_Mobile.X - toTarget.X;
|
||||
var ry = m_Mobile.Y - toTarget.Y;
|
||||
|
||||
var d = m_Mobile.GetDistanceToSqrt(toTarget);
|
||||
|
||||
px = toTarget.X + (int)(rx * (10 / d));
|
||||
py = toTarget.Y + (int)(ry * (10 / d));
|
||||
}
|
||||
else
|
||||
{
|
||||
px = toTarget.X;
|
||||
py = toTarget.Y;
|
||||
}
|
||||
|
||||
for (var i = 0; i < m_Offsets.Length; i += 2)
|
||||
{
|
||||
int x = m_Offsets[i], y = m_Offsets[i + 1];
|
||||
|
||||
var p = new Point3D(px + x, py + y, 0);
|
||||
|
||||
var lt = new LandTarget(p, map);
|
||||
|
||||
if ((targ.Range == -1 || m_Mobile.InRange(p, targ.Range)) && m_Mobile.InLOS(lt) &&
|
||||
map.CanSpawnMobile(px + x, py + y, lt.Z) && !SpellHelper.CheckMulti(p, map))
|
||||
{
|
||||
targ.Invoke(m_Mobile, lt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var teleRange = targ.Range;
|
||||
|
||||
if (teleRange < 0)
|
||||
teleRange = 12;
|
||||
|
||||
for (var i = 0; i < 10; ++i)
|
||||
{
|
||||
var randomPoint = new Point3D(
|
||||
m_Mobile.X - teleRange + Utility.Random(teleRange * 2 + 1),
|
||||
m_Mobile.Y - teleRange + Utility.Random(teleRange * 2 + 1),
|
||||
0);
|
||||
|
||||
var lt = new LandTarget(randomPoint, map);
|
||||
|
||||
if (m_Mobile.InLOS(lt) && map.CanSpawnMobile(lt.X, lt.Y, lt.Z) && !SpellHelper.CheckMulti(randomPoint, map))
|
||||
{
|
||||
targ.Invoke(m_Mobile, new LandTarget(randomPoint, map));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
}
|
||||
else
|
||||
{
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user