This was more of a test since I've never explored this before.
So I keep getting this error when adding a custom AI...

Code:
Errors:
+ Content/Internal/MobileEngines/BaseCreature.cs:
    CS1502: Line 2526: The best overloaded method match for 'Server.Mobiles.SecurityK9AI.SecurityK9AI(Server.Mobiles.SecurityK9)' has some invalid arguments
    CS1503: Line 2526: Argument 1: cannot convert from 'Server.Mobiles.BaseCreature' to 'Server.Mobiles.SecurityK9'

I've researched and all I found was the implementation of it all:

BaseCreature.cs:

Code:
...
                case AIType.AI_FlyingPredator:
                    //m_AI = new FlyingPredatorAI(this);
                    m_AI = new FlyingMeleeAI(this);
                    break;
                case AIType.AI_FlyingThief:
                    m_AI = new FlyingThiefAI(this);
                    break;
                case AIType.AI_Omni:
                    m_AI = new OmniAI(this);
                    break;           
                case AIType.AI_SecurityK9:
                    m_AI = new SecurityK9AI(this);
                    break;
          }
}

BaseAI.cs:

Code:
...
public enum AIType
    { 
        AI_Use_Default,
        AI_Melee,
        AI_Animal,
        AI_Archer,
        AI_Healer,
        AI_Vendor,
        AI_Mage,
        AI_Berserk,
        AI_Predator,
        AI_Thief,
        AI_SecurityK9
}
...

This was modeled after the drug sniffing dog someone came up with to go along with my Harvesting system, I just wanted to separate things and make its AI a script of it's own and put it with the rest of the AIType scripts. This is the custom AI script:

Code:
using System;
using System.Collections;

using Server;
using Server.Items;
//using Server.Items.Crops;
using Server.Mobiles;
using Server.Network;
using Server.Regions;
using Server.Targeting;


namespace Server.Mobiles
{
    public class SecurityK9AI: BaseAI
    {
        /// <summary>
        /// I Can Run Away From You!
        /// </summary>
        public bool RunFrom(Mobile m)
        {
            if (m_Mobile.InRange(m, 1))
                return false;
            Run((m_Mobile.GetDirectionTo(m) - 4) & Direction.Mask);
            return true;
        }

        /// <summary>
        /// I Can Run Towards You!
        /// </summary>
        public bool RunTo(Mobile m, int range)
        {
            if (m_Mobile.InRange(m, range))
                return false;
            Run((m_Mobile.GetDirectionTo(m)) & Direction.Mask);
            return true;
        }

        // I Know Where I'm Going!
        public void Run(Direction d)
        {
            if ((m_Mobile.Spell != null && m_Mobile.Spell.IsCasting) || m_Mobile.Paralyzed || m_Mobile.Frozen || m_Mobile.DisallowAllMoves)
                return;
            if (!m_Mobile.Mounted && !m_Mobile.Body.IsHuman)
            {
                m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed;
            }
            else if (!m_Mobile.Mounted && m_Mobile.Body.IsHuman)
            {
                m_Mobile.CurrentSpeed = 0.12;
            }
            else
                m_Mobile.CurrentSpeed = 0.01;
            m_Mobile.Direction = d | Direction.Running;
            DoMove(m_Mobile.Direction, true);
        }

        public SecurityK9AI(SecurityK9 m)
            : base(m)
        {
        }

        /// <summary>
        /// I'm Waiting For The Action!
        /// </summary>
        public override bool DoActionWander()
        {
            m_Mobile.DebugSay("I have no combatant");

            if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
            {
                if (m_Mobile.Debug)
                    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 is SecurityK9)
            {
                Direction togo = Direction.South;
                Mobile mark = null;

                SecurityK9 sK9 = (SecurityK9)m_Mobile;

                if (!sK9.HasChecked)
                {
                    foreach (Mobile mob in sK9.GetMobilesInRange(10)) // How close does a player need to be for the canine to sense something is wrong?
                    {
                        if ((mob is PlayerMobile) && (mark == null))  // Canine targets player and follows them.
                        {
                            mark = mob;
                            sK9.mark = mark;
                            togo = m_Mobile.GetDirectionTo(mob);
                        }
                        else if ((mob is BaseCreature) && (mark == null))
                        {
                            BaseCreature bc = (BaseCreature)mob;
                            if (bc.Controlled)
                            {
                                if ((bc.ControlMaster != null) && (bc.ControlMaster is PlayerMobile)) // Canine targets player pet and follows them.
                                {
                                    mark = mob;
                                    sK9.mark = mark;
                                    togo = m_Mobile.GetDirectionTo(mob);
                                }
                            }
                        }
                    }

                    if ((Utility.RandomMinMax(1, 5) > 1) && (mark != null)) DoMove(togo);
                    else base.DoActionWander();
                }
                else base.DoActionWander();
            }
            else
            {
                base.DoActionWander();
            }

            return true;
        }

        public override bool DoActionGuard()
        {
            if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
            {
                m_Mobile.Combatant = m_Mobile.FocusMob; // Acquiring target... I'm going in for the attack!
                Action = ActionType.Combat;
            }
            else
            {
                base.DoActionGuard(); // I ate my target... mission accomplished!
            }

            return true;
        }

        public override bool DoActionCombat()
        {
            Mobile combatant = m_Mobile.Combatant;

            if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map || !combatant.Alive || combatant.IsDeadBondedPet)
            {
                Action = ActionType.Guard; // No target in sight, I'll be on guard!
                return true;
            }

            if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception))
            {
                if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) // Targets are somewhat far away, can we find something else?
                {
                    m_Mobile.Combatant = m_Mobile.FocusMob;
                    m_Mobile.FocusMob = null;
                }
                else if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception * 3)) // I've lost my target!
                {
                    m_Mobile.Combatant = null;
                }

                combatant = m_Mobile.Combatant;

                if (combatant == null)
                {
                    Action = ActionType.Guard; // Target has fled, I'll stand guard!
                    return true;
                }
            }

            if (MoveTo(combatant, true, m_Mobile.RangeFight))
            {
                m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); //
            }
            else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
            {
                m_Mobile.Combatant = m_Mobile.FocusMob; // My move is blocked, so I am going to attack
                Action = ActionType.Combat;
                return true;
            }
            else if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1)
            {
                Action = ActionType.Guard; // I've lost my target!
                return true;
            }
            else
            {
                // My target is too far away!
            }

            if (!m_Mobile.Controlled && !m_Mobile.Summoned && !m_Mobile.IsParagon)
            {
                if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100)
                {
                    bool flee = false; // We are low on health, should we flee?

                    if (m_Mobile.Hits < combatant.Hits)
                    {
                        int diff = combatant.Hits - m_Mobile.Hits; // We are more hurt than them - (10 + diff)% chance to flee
                        flee = (Utility.Random(0, 100) < (10 + diff));
                    }
                    else
                    {
                        flee = Utility.Random(0, 100) < 10; // 10% chance to flee
                    }

                    if (flee)
                    {
                        Action = ActionType.Flee; // Heck I'll just run away!
                    }
                }
            }

            return true;
        }

        public override bool DoActionFlee()
        {
            if (m_Mobile.Hits > m_Mobile.HitsMax / 2)
            {
                Action = ActionType.Combat; // I have healed some, my target won't get away!
            }
            else
            {
                m_Mobile.FocusMob = m_Mobile.Combatant; // Time to go, goodbye!
                RunFrom(m_Mobile.FocusMob);
            }

            return true;
        }
    }
}

And this is the mobile script that is supposed to use that AIType:

Code:
using System;
using System.Collections;

using Server;
using Server.Items;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;

namespace Server.Mobiles
{
    [TypeAlias("Server.Mobiles.Timberwolf")]
    public class SecurityK9 : BaseCreature
    {
        private Mobile m_mark = null;
        [CommandProperty(AccessLevel.GameMaster)]
        public Mobile mark
        {
            get { return m_mark; }
            set { m_mark = value; }
        }

        private bool m_HasChecked = false;
        [CommandProperty(AccessLevel.GameMaster)]
        public bool HasChecked
        {
            get { return m_HasChecked; }
            set { m_HasChecked = value; }
        }

        [Constructable]
        public SecurityK9()
            : base(AIType.SecurityK9, FightMode.Aggressor, 10, 1, 0.2, 0.4)
        {
            Name = "Guard Dog";
            Body = 225;
            Hue = 1308;
            BaseSoundID = 0x85;

            SetStr(80, 90);
            SetDex(80, 90);
            SetInt(80, 90);

            SetHits(5000, 6000);
            SetMana(0);

            SetDamage(35, 50);
            SetDamageType(ResistanceType.Physical, 100);

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

            SetSkill(SkillName.MagicResist, 100, 120);
            SetSkill(SkillName.Tactics, 100, 120);
            SetSkill(SkillName.Wrestling, 100, 120);

            Fame = 450;
            Karma = 500;

            VirtualArmor = 25;

            Tamable = false;
            ControlSlots = 1;
            MinTameSkill = 80.1;
        }

        public void Emote()
        {
            switch (Utility.Random(2))
            {
                case 0:
                    PlaySound(Female ? 818 : 1092);
                    Say("*sniff*");
                    break;
                default:
                    break;
            }
        }

        public override int Meat { get { return 1; } }
        public override int Hides { get { return 5; } }
        public override FoodType FavoriteFood { get { return FoodType.Meat; } }
        public override PackInstinct PackInstinct { get { return PackInstinct.Canine; } }

        #region Contraband Objects On Server

        public virtual bool IsContraband(Item item)
        {
            if ((item is Cake) || (item is RawRibs))
            {
                return true;
            }
            else
            {
                return false;
            }

            //if ((item is Marijuana_Leaves) || (item is Marijuana_Joint))
            //    return true;
            //return false;
        }

        #endregion

        #region Flag Players With Contraband

        public override void OnThink()
        {
            if (this.mark != null)
            {
                double markPick = GetDistanceToSqrt(mark);

                if ((markPick < 2) && (!HasChecked))
                {
                    if (mark.Backpack != null)
                    {
                        Container pouch = mark.Backpack;
                        ArrayList finalitems = new ArrayList(pouch.Items);

                        foreach (Item items in finalitems)
                        {
                            if ((items != null) && (!(items.Deleted)))
                            {
                                HasChecked = true;

                                if (IsContraband(items))
                                {
                                    if (mark is PlayerMobile)
                                    {
                                        PlayerMobile pm = (PlayerMobile)mark;
                                        pm.Criminal = true;
                                        Combatant = mark;
                                        items.Delete(); // Deletes Contraband Items
                                    }
                                    else if (mark is BaseCreature)
                                    {
                                        BaseCreature bc = (BaseCreature)mark;
                                        bc.Criminal = true;
                                        Combatant = mark;
                                        items.Delete(); // Deletes Contraband Items

                                        if ((bc.Controlled) && (bc.ControlMaster is PlayerMobile))
                                        {
                                            PlayerMobile pm = (PlayerMobile)bc.ControlMaster;
                                            pm.Criminal = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else if ((markPick > 10) && (HasChecked))
                {
                    HasChecked = false;
                    mark = null;
                }
            }
        }

        #endregion

        //protected override BaseAI ForcedAI { get { return new SecurityK9AI(this); } }

        public SecurityK9(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();
        }
    }
}

Now I know that the ForcedAI will override this issue, but I was wondering if there's a way to seamlessly intertwine the custom AI into the server like AI_Melee, AI_Animal... etc. Is there a core edit I am missing?

Any help would be appreciated. Thanks :)
 
Last edited:
Thank you Ravenwolfe!

You helped me fix the issue. All I had to do was change the way this line in the SecurityK9AI script read:

From:
Code:
public SecurityK9AI(SecurityK9 m) : base(m) {}

To This Change:
Code:
public SecurityK9AI(BaseCreature m) : base(m) {}
 
Last edited:
Back