Files
abysmal-isle/Scripts/Mobiles/AI/OrcScoutAI.cs
Unstable Kitsune b918192e4e Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
2023-11-28 23:20:26 -05:00

330 lines
7.0 KiB
C#

#region References
using System;
using Server.Items;
using Server.Spells;
using Server.Targeting;
#endregion
namespace Server.Mobiles
{
public class OrcScoutAI : BaseAI
{
private static readonly double teleportChance = 0.04;
private static readonly int[] m_Offsets = {0, 0, -1, -1, 0, -1, 1, -1, -1, 0, 1, 0, -1, -1, 0, 1, 1, 1};
public OrcScoutAI(BaseCreature m)
: base(m)
{ }
public override bool DoActionWander()
{
m_Mobile.DebugSay("I have no combatant");
PerformHide();
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
{
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
if (m_Mobile.Combatant != null)
{
Action = ActionType.Combat;
return true;
}
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
var c = m_Mobile.Combatant as Mobile;
if (c == null || c.Deleted || c.Map != m_Mobile.Map || !c.Alive || c.IsDeadBondedPet)
{
m_Mobile.DebugSay("My combatant is gone, so my guard is up");
Action = ActionType.Guard;
return true;
}
if (Utility.RandomDouble() < teleportChance)
{
TryToTeleport();
}
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 as Mobile;
if (c == null)
{
m_Mobile.DebugSay("My combatant has fled, so I am on guard");
Action = ActionType.Guard;
return true;
}
}
if (MoveTo(c, true, m_Mobile.RangeFight))
{
if (!DirectionLocked)
m_Mobile.Direction = m_Mobile.GetDirectionTo(c);
}
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;
return true;
}
else if (m_Mobile.GetDistanceToSqrt(c) > m_Mobile.RangePerception + 1)
{
m_Mobile.DebugSay("I cannot find {0}, so my guard is up", c.Name);
Action = ActionType.Guard;
return true;
}
else
{
m_Mobile.DebugSay("I should be closer to {0}", c.Name);
}
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee)
{
/* // When we have no ammo, we flee
Container pack = m_Mobile.Backpack;
if (pack == null || pack.FindItemByType(typeof(Arrow)) == null)
{
Action = ActionType.Flee;
if (Utility.RandomDouble() < teleportChance + 0.1)
{
TryToTeleport();
}
return true;
}
*/
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;
if (Utility.RandomDouble() < teleportChance + 0.1)
{
TryToTeleport();
}
}
}
}
return true;
}
public override bool DoActionGuard()
{
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
{
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionGuard();
}
return true;
}
public override bool DoActionFlee()
{
var c = m_Mobile.Combatant as Mobile;
// Container pack = m_Mobile.Backpack;
// bool hasAmmo = !(pack == null || pack.FindItemByType(typeof(Arrow)) == null);
// They can shoot even with no ammo!
if ( /*hasAmmo && */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
{
PerformHide();
base.DoActionFlee();
}
return true;
}
private Mobile FindNearestAggressor()
{
Mobile nearest = null;
var dist = 9999.0;
IPooledEnumerable eable = m_Mobile.GetMobilesInRange(m_Mobile.RangePerception);
foreach (Mobile m in eable)
{
if (m.Player && !m.Hidden && m.IsPlayer() && m.Combatant == m_Mobile)
{
if (dist > m.GetDistanceToSqrt(m_Mobile))
{
nearest = m;
}
}
}
eable.Free();
return nearest;
}
private void TryToTeleport()
{
var m = FindNearestAggressor();
if (m == null || m.Map == null || m_Mobile.Map == null)
{
return;
}
if (m_Mobile.GetDistanceToSqrt(m) > m_Mobile.RangePerception + 1)
{
return;
}
var px = m_Mobile.X;
var py = m_Mobile.Y;
var dx = m_Mobile.X - m.X;
var dy = m_Mobile.Y - m.Y;
// get vector's length
var l = Math.Sqrt((dx * dx + dy * dy));
if (l == 0)
{
var rand = Utility.Random(8) + 1;
rand *= 2;
dx = m_Offsets[rand];
dy = m_Offsets[rand + 1];
l = Math.Sqrt((dx * dx + dy * dy));
}
// normalize vector
var dpx = (dx) / l;
var dpy = (dy) / l;
// move
px += (int)(dpx * (4 + Utility.Random(3)));
py += (int)(dpy * (4 + Utility.Random(3)));
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, m_Mobile.Map);
if (m_Mobile.InLOS(lt) && m_Mobile.Map.CanSpawnMobile(px + x, py + y, lt.Z) &&
!SpellHelper.CheckMulti(p, m_Mobile.Map))
{
m_Mobile.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
m_Mobile.PlaySound(0x1FE);
m_Mobile.Location = new Point3D(lt.X, lt.Y, lt.Z);
m_Mobile.ProcessDelta();
return;
}
}
}
private void HideSelf()
{
if (Core.TickCount >= m_Mobile.NextSkillTime)
{
Effects.SendLocationParticles(
EffectItem.Create(m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration),
0x3728,
10,
10,
2023);
m_Mobile.PlaySound(0x22F);
m_Mobile.Hidden = true;
m_Mobile.UseSkill(SkillName.Stealth);
}
}
private void PerformHide()
{
if (!m_Mobile.Alive || m_Mobile.Deleted)
{
return;
}
if (!m_Mobile.Hidden)
{
var chance = 0.05;
if (m_Mobile.Hits < 20)
{
chance = 0.1;
}
if (m_Mobile.Poisoned)
{
chance = 0.01;
}
if (Utility.RandomDouble() < chance)
{
HideSelf();
}
}
}
}
}