ServUO Version
Publish 57
Ultima Expansion
Endless Journey
Is there a way to set how close a script generated NPC gets to a monster? Specifically I have a power mage NPC but he goes right up next to whoever he's fighting. I'd like him to hold off 4 tiles as a player mage would.
 
Here's what AI did. Works pretty well.
Mega Mage:
using System;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Spells.Fifth;
using Server.Spells.Seventh;
using Server.Spells.Mysticism;

namespace Server.Mobiles
{
    [CorpseName("a mage's corpse")]
    public class MysticMage : BaseCreature
    {
        private Point3D m_LastDamagedLocation;
        private bool m_IsWalkingAway;

        [Constructable]
        public MysticMage() : base(AIType.AI_Mage, FightMode.Aggressor | FightMode.Evil, 10, 1, 0.2, 0.4)
        {
            Name = $"{NameList.RandomName("male")} the Legendary Wizard";

            Body = 0x190; // Human male body
            Hue = Utility.RandomMinMax(1001, 1010); // Lighter human skin tone

            // Appearance
            HairItemID = 0x203C; // Long hair
            HairHue = 0x481; // White
            FacialHairItemID = 0x204D; // Long beard
            FacialHairHue = 0x481; // White
AddItem(new MagicWizardsHat { Hue = 0x497 });

            // Clothing
            AddItem(new Robe() { Hue = 0x497 }); // Dark blue robe
            AddItem(new Sandals());

            // Attributes
            SetStr(150);
            SetDex(150);
            SetInt(500);

            SetHits(1000);
            SetDamage(15, 20);

            SetDamageType(ResistanceType.Physical, 100);

            SetResistance(ResistanceType.Physical, 60);
            SetResistance(ResistanceType.Fire, 60);
            SetResistance(ResistanceType.Cold, 60);
            SetResistance(ResistanceType.Poison, 60);
            SetResistance(ResistanceType.Energy, 60);

            // Skills
            SetSkill(SkillName.Magery, 300.0);
            SetSkill(SkillName.Meditation, 300.0);
            SetSkill(SkillName.SpiritSpeak, 300.0);
            SetSkill(SkillName.Wrestling, 300.0);
            SetSkill(SkillName.EvalInt, 300.0);
            SetSkill(SkillName.Mysticism, 300.0);
            SetSkill(SkillName.Focus, 300.0);

            Fame = 15000; // Maximum fame
            Karma = 15000; // Maximum karma

            VirtualArmor = 50;

            PackGold(1000, 1500);
        }

        public override void OnDamage(int amount, Mobile from, bool willKill)
        {
            base.OnDamage(amount, from, willKill);
            StartWalkingAway();
        }

        private void StartWalkingAway()
        {
            if (!m_IsWalkingAway && Combatant != null)
            {
                m_LastDamagedLocation = Location;
                m_IsWalkingAway = true;

                // Start walking away
                Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerCallback(WalkAway));
            }
        }

        private void WalkAway()
        {
            if (Deleted || Map == null || Combatant == null || Combatant.Deleted || Combatant.Map == null)
            {
                m_IsWalkingAway = false;
                return;
            }

            int currentX = Location.X;
            int currentY = Location.Y;
            int targetX = m_LastDamagedLocation.X;
            int targetY = m_LastDamagedLocation.Y;

            int xDirection = currentX > targetX ? -1 : 1;
            int yDirection = currentY > targetY ? -1 : 1;

            int newX = currentX + xDirection;
            int newY = currentY + yDirection;

            // Check if the new location is valid
            if (Map.CanSpawnMobile(newX, newY, Location.Z))
            {
                Point3D newLocation = new Point3D(newX, newY, Location.Z);
                MoveToWorld(newLocation, Map);
            }

            // Check if still need to walk away
            if (CalculateDistance(new Point2D(Location.X, Location.Y), new Point2D(m_LastDamagedLocation.X, m_LastDamagedLocation.Y)) > 2)
            {
                Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerCallback(WalkAway));
            }
            else
            {
                m_IsWalkingAway = false;
            }
        }

        private double CalculateDistance(Point2D point1, Point2D point2)
        {
            int dx = point1.X - point2.X;
            int dy = point1.Y - point2.Y;
            return Math.Sqrt(dx * dx + dy * dy);
        }

        public MysticMage(Serial serial) : base(serial)
        {
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);
            writer.Write((int)0);
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);
            int version = reader.ReadInt();
        }
    }
}
 
Back