ServUO Version
Publish 57
Ultima Expansion
Endless Journey
I'm attempting to make a Magic Wand that reveals Hidden Items and Mobiles. The revealing part works as expected, however in the OnAdded method I am trying to passively detect hidden objects. This is what I have, which compiles, but doesn't passively detect.

Code:
  public static void OnAdded(object parent, Mobile src)
  {
      int reqCharges = 1;
      if (src == null || src.Map == null || src.Location == Point3D.Zero || src.IsStaff())
          return;

      IPooledEnumerable eable = src.Map.GetMobilesInRange(src.Location, 4);

      if (eable == null)
          return;

      foreach (Mobile m in eable)
      {
          if (m == null || m == src || !CanRBDetect(src, m, false))
              continue;

          if (src.AccessLevel >= m.AccessLevel)
          {
              m.RevealingAction();
              m.SendLocalizedMessage(500814); // You have been revealed!
          }
      }

      eable.Free();

      eable = src.Map.GetItemsInRange(src.Location, 8);

      foreach (Item item in eable)
      {
          if (!item.Visible && item is RBRevealableItem)
          {
              src.SendMessage("You detect a hidden object nearby..."); 
          }
      }

      eable.Free();
  }
 
If it is like a mobile, I would say it is detecting as an internal map still. Maybe try using

OnAfterSpawn
 
If it is like a mobile, I would say it is detecting as an internal map still. Maybe try using

OnAfterSpawn
?what? ... While the wand is equiped player supposed to get a message a hidden item is nearby.
currently it doesn't recognize hidden mobiles or items.
 
Still no luck :p

Tried:
public static void OnMovement
public virtual void OnAfterMove

Might have to change my strategy here.
 
A couple of of questions:

1. Why do you have an INT set for "reqCharges" when it is never used?
2. Why are you searching for items when nothing in the game (as far as I know) hides items. Wouldn't that find things like spawners on the ground, or teleporters?

I didn't test this, but I just added the code from the REVEAL spell.

C#:
public static void OnAdded(object parent, Mobile src)
{
    List<Mobile> targets = new List<Mobile>();

    Map map = src.Map;

    if ( map != null )
    {
        IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( src.Location ), 4 );

        foreach ( Mobile m in eable )
        {
            if ( m is Mobiles.ShadowKnight && (m.X != p.X || m.Y != p.Y) )
                continue;

            if ( m.Hidden && (src.AccessLevel >= m.AccessLevel) )
                targets.Add( m );
        }

        eable.Free();
    }

    for ( int i = 0; i < targets.Count; ++i )
    {
        Mobile m = targets[i];

        m.RevealingAction();

        m.FixedParticles( 0x375A, 9, 20, 5049, EffectLayer.Head );
        m.PlaySound( 0x1FD );
    }
}
 
This works for the OnMove method in PlayerMobile, note that if the character is Staff, the OnMove method is not triggered.
I had to comment out a few lines that used some kind of custom method in your code

C#:
int reqCharges = 1;
            /* if (src == null || src.Map == null || src.Location == Point3D.Zero || src.IsStaff())
                return; */

            //IPooledEnumerable eable = this.Map.GetMobilesInRange(this.Location, 4);
            IPooledEnumerable eable = this.GetMobilesInRange(4);

            foreach (Mobile m in eable)
            {
                if (m == null || m == this /* || !CanRBDetect(this, m, false) */)
                    continue;

                if (m.Hidden && this.AccessLevel >= m.AccessLevel)
                {
                    m.RevealingAction();
                    m.SendLocalizedMessage(500814); // You have been revealed!
                }
            }

            eable.Free();

            eable = this.Map.GetItemsInRange(this.Location, 8);

            foreach (Item item in eable)
            {
                if (!item.Visible /* && item is RBRevealableItem */)
                {
                    this.SendMessage("You detect a hidden object nearby...");
                }
            }

            eable.Free();

Also, use this to check if the player has the wand equipped

C#:
if(m.FindItemOnLayer(Layer.FirstValid) is RevealyWand)

For additional context, I added the code to the bottom of the OnMove method to be sure any & all over OnMove code is processed first as a priority and to avoid potential bugs or weird behavior.

Here's my full OnMove method from PlayerMobile

C#:
protected override bool OnMove(Direction d)
        {
            if (Party != null && NetState != null)
            {
                Waypoints.UpdateToParty(this);
            }

            if (IsStaff())
            {
                return true;
            }

            if (Hidden && DesignContext.Find(this) == null) //Hidden & NOT customizing a house
            {
                if (!Mounted && Skills.Stealth.Value >= 25.0)
                {
                    bool running = (d & Direction.Running) != 0;

                    if (running)
                    {
                        if ((AllowedStealthSteps -= 2) <= 0)
                        {
                            RevealingAction();
                        }
                    }
                    else if (AllowedStealthSteps-- <= 0)
                    {
                        Stealth.OnUse(this);
                    }
                }
                else
                {
                    RevealingAction();
                }
            }

            if (InvisibilityPotion.HasTimer(this))
            {
                InvisibilityPotion.Iterrupt(this);
            }

            if (m.FindItemOnLayer(Layer.FirstValid) is RevealyWand)
            {
                /* if (src == null || src.Map == null || src.Location == Point3D.Zero || src.IsStaff())
                    return; */

                IPooledEnumerable eable = this.GetMobilesInRange(4);

                foreach (Mobile m in eable)
                {
                    if (m == null || m == this /* || !CanRBDetect(this, m, false) */)
                        continue;

                    if (m.Hidden && this.AccessLevel >= m.AccessLevel)
                    {
                        m.RevealingAction();
                        m.SendLocalizedMessage(500814); // You have been revealed!
                    }
                }

                eable.Free();

                eable = this.Map.GetItemsInRange(this.Location, 8);

                foreach (Item item in eable)
                {
                    if (!item.Visible /* && item is RBRevealableItem */)
                    {
                        this.SendMessage("You detect a hidden object nearby...");
                    }
                }

                eable.Free();
            }

            return true;
        }
 
I made hidden Items (item is RBRevealableItem) for an event in which I want everyone to have the same chance to discover. Players with detect hidden cannot monopolize this aspect of the event. My wand uses charge on double click if a hidden object is targeted (this works great). Would be ideal if it also used charges on detect. Once I get it to work I will address the charges issue.

A couple of of questions:

1. Why do you have an INT set for "reqCharges" when it is never used?
2. Why are you searching for items when nothing in the game (as far as I know) hides items. Wouldn't that find things like spawners on the ground, or teleporters?

I didn't test this, but I just added the code from the REVEAL spell.

C#:
public static void OnAdded(object parent, Mobile src)
{
    List<Mobile> targets = new List<Mobile>();

    Map map = src.Map;

    if ( map != null )
    {
        IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( src.Location ), 4 );

        foreach ( Mobile m in eable )
        {
            if ( m is Mobiles.ShadowKnight && (m.X != p.X || m.Y != p.Y) )
                continue;

            if ( m.Hidden && (src.AccessLevel >= m.AccessLevel) )
                targets.Add( m );
        }

        eable.Free();
    }

    for ( int i = 0; i < targets.Count; ++i )
    {
        Mobile m = targets[i];

        m.RevealingAction();

        m.FixedParticles( 0x375A, 9, 20, 5049, EffectLayer.Head );
        m.PlaySound( 0x1FD );
    }
}
Appreciate that. Idea is just to detect item nearby not reveal. once detect you double-click wand to attempt to reveal. My reveal portion works fine.

This works for the OnMove method in PlayerMobile, note that if the character is Staff, the OnMove method is not triggered.
I had to comment out a few lines that used some kind of custom method in your code

C#:
int reqCharges = 1;
            /* if (src == null || src.Map == null || src.Location == Point3D.Zero || src.IsStaff())
                return; */

            //IPooledEnumerable eable = this.Map.GetMobilesInRange(this.Location, 4);
            IPooledEnumerable eable = this.GetMobilesInRange(4);

            foreach (Mobile m in eable)
            {
                if (m == null || m == this /* || !CanRBDetect(this, m, false) */)
                    continue;

                if (m.Hidden && this.AccessLevel >= m.AccessLevel)
                {
                    m.RevealingAction();
                    m.SendLocalizedMessage(500814); // You have been revealed!
                }
            }

            eable.Free();

            eable = this.Map.GetItemsInRange(this.Location, 8);

            foreach (Item item in eable)
            {
                if (!item.Visible /* && item is RBRevealableItem */)
                {
                    this.SendMessage("You detect a hidden object nearby...");
                }
            }

            eable.Free();

Also, use this to check if the player has the wand equipped

C#:
if(m.FindItemOnLayer(Layer.FirstValid) is RevealyWand)

For additional context, I added the code to the bottom of the OnMove method to be sure any & all over OnMove code is processed first as a priority and to avoid potential bugs or weird behavior.

Here's my full OnMove method from PlayerMobile

C#:
protected override bool OnMove(Direction d)
        {
            if (Party != null && NetState != null)
            {
                Waypoints.UpdateToParty(this);
            }

            if (IsStaff())
            {
                return true;
            }

            if (Hidden && DesignContext.Find(this) == null) //Hidden & NOT customizing a house
            {
                if (!Mounted && Skills.Stealth.Value >= 25.0)
                {
                    bool running = (d & Direction.Running) != 0;

                    if (running)
                    {
                        if ((AllowedStealthSteps -= 2) <= 0)
                        {
                            RevealingAction();
                        }
                    }
                    else if (AllowedStealthSteps-- <= 0)
                    {
                        Stealth.OnUse(this);
                    }
                }
                else
                {
                    RevealingAction();
                }
            }

            if (InvisibilityPotion.HasTimer(this))
            {
                InvisibilityPotion.Iterrupt(this);
            }

            if (m.FindItemOnLayer(Layer.FirstValid) is RevealyWand)
            {
                /* if (src == null || src.Map == null || src.Location == Point3D.Zero || src.IsStaff())
                    return; */

                IPooledEnumerable eable = this.GetMobilesInRange(4);

                foreach (Mobile m in eable)
                {
                    if (m == null || m == this /* || !CanRBDetect(this, m, false) */)
                        continue;

                    if (m.Hidden && this.AccessLevel >= m.AccessLevel)
                    {
                        m.RevealingAction();
                        m.SendLocalizedMessage(500814); // You have been revealed!
                    }
                }

                eable.Free();

                eable = this.Map.GetItemsInRange(this.Location, 8);

                foreach (Item item in eable)
                {
                    if (!item.Visible /* && item is RBRevealableItem */)
                    {
                        this.SendMessage("You detect a hidden object nearby...");
                    }
                }

                eable.Free();
            }

            return true;
        }
Appreciate the help, thank you.

On double click to reveal this works fine. When equipped able want ability to detect when close by, this part that not work. I will try this code without reveal bits.

This works for the OnMove method in PlayerMobile, note that if the character is Staff, the OnMove method is not triggered.
I had to comment out a few lines that used some kind of custom method in your code

C#:
int reqCharges = 1;
            /* if (src == null || src.Map == null || src.Location == Point3D.Zero || src.IsStaff())
                return; */

            //IPooledEnumerable eable = this.Map.GetMobilesInRange(this.Location, 4);
            IPooledEnumerable eable = this.GetMobilesInRange(4);

            foreach (Mobile m in eable)
            {
                if (m == null || m == this /* || !CanRBDetect(this, m, false) */)
                    continue;

                if (m.Hidden && this.AccessLevel >= m.AccessLevel)
                {
                    m.RevealingAction();
                    m.SendLocalizedMessage(500814); // You have been revealed!
                }
            }

            eable.Free();

            eable = this.Map.GetItemsInRange(this.Location, 8);

            foreach (Item item in eable)
            {
                if (!item.Visible /* && item is RBRevealableItem */)
                {
                    this.SendMessage("You detect a hidden object nearby...");
                }
            }

            eable.Free();

Also, use this to check if the player has the wand equipped

C#:
if(m.FindItemOnLayer(Layer.FirstValid) is RevealyWand)

For additional context, I added the code to the bottom of the OnMove method to be sure any & all over OnMove code is processed first as a priority and to avoid potential bugs or weird behavior.

Here's my full OnMove method from PlayerMobile

C#:
protected override bool OnMove(Direction d)
        {
            if (Party != null && NetState != null)
            {
                Waypoints.UpdateToParty(this);
            }

            if (IsStaff())
            {
                return true;
            }

            if (Hidden && DesignContext.Find(this) == null) //Hidden & NOT customizing a house
            {
                if (!Mounted && Skills.Stealth.Value >= 25.0)
                {
                    bool running = (d & Direction.Running) != 0;

                    if (running)
                    {
                        if ((AllowedStealthSteps -= 2) <= 0)
                        {
                            RevealingAction();
                        }
                    }
                    else if (AllowedStealthSteps-- <= 0)
                    {
                        Stealth.OnUse(this);
                    }
                }
                else
                {
                    RevealingAction();
                }
            }

            if (InvisibilityPotion.HasTimer(this))
            {
                InvisibilityPotion.Iterrupt(this);
            }

            if (m.FindItemOnLayer(Layer.FirstValid) is RevealyWand)
            {
                /* if (src == null || src.Map == null || src.Location == Point3D.Zero || src.IsStaff())
                    return; */

                IPooledEnumerable eable = this.GetMobilesInRange(4);

                foreach (Mobile m in eable)
                {
                    if (m == null || m == this /* || !CanRBDetect(this, m, false) */)
                        continue;

                    if (m.Hidden && this.AccessLevel >= m.AccessLevel)
                    {
                        m.RevealingAction();
                        m.SendLocalizedMessage(500814); // You have been revealed!
                    }
                }

                eable.Free();

                eable = this.Map.GetItemsInRange(this.Location, 8);

                foreach (Item item in eable)
                {
                    if (!item.Visible /* && item is RBRevealableItem */)
                    {
                        this.SendMessage("You detect a hidden object nearby...");
                    }
                }

                eable.Free();
            }

            return true;
        }
 
Last edited:
When equipped able want ability to detect when close by, this part that not work. I will try this code without reveal bits.

Adding it to the OnMove method of PlayerMobile worked perfectly for this.
If you still want it to reduce charges, that just takes an extra line or two of code.

Let me know if you need anymore help with it
 
Back