ModernUO/dev-docs/claude-skills/modernuo-commands-targeting.md
Kamron Batman 1391c563fe
chore: Adds AI instructions and SKILLs for ModernUO codebase (#2347)
Summary

  - Adds CLAUDE.md at repo root with 14 terse code audit rules (always loaded, low token cost)
  - Adds pointer files for other AI tools: AGENTS.md (Codex), GEMINI.md, .github/COPILOT-INSTRUCTIONS.md (Copilot), .cursorrules (Cursor) — all redirect to CLAUDE.md as single source of truth
  - Gitignores /.claude so personal AI config isn't distributed
  - Moves Claude skills to dev-docs/claude-skills/ (opt-in, not auto-loaded)
  - Adds 14 dev-docs covering codebase conventions

  Code Audit Rules (in CLAUDE.md)

  1. LINQ tiered rules (Tier 1 free, Tier 2 warm, Tier 3 forbidden)
  2. No Console.WriteLine — use LogFactory.GetLogger()
  3. No concurrency primitives in game code
  4. No World.Mobiles/World.Items iteration
  5. Clean up refs in OnDelete()/OnAfterDelete()
  6. Cancel timers in OnDelete()/OnAfterDelete()
  7. STArrayPool<T>.Shared not ArrayPool<T>.Shared
  8. PooledRefList<T> not new List<T>() on hot paths
  9. Serialization: partial class, [Constructible], no serialized TimerExecutionToken
  10. No Task.Run/new Thread() in game code
  11. Never assume era — ask which expansion
  12. _camelCase fields, PascalCase properties/methods
  13. No empty gumps — use DisplayTo() pattern
  14. PropertyList string literals must be {} holes, cliloc-as-argument uses :#
2026-03-01 11:42:19 -08:00

6.8 KiB

name description
modernuo-commands-targeting Trigger when creating in-game commands, targeting mechanics, or working with CommandSystem/Target. When implementing [commands or player interactions.

ModernUO Commands & Targeting

When This Activates

  • Creating new in-game [ commands
  • Implementing targeting mechanics
  • Working with CommandSystem.Register() or Target class
  • Adding GM/admin tools

Key Rules

  1. Register commands in Configure() static method (called at startup)
  2. Use [Usage] and [Description] attributes on handler methods
  3. Prefix is [ by default (e.g., [mycommand)
  4. Target inherits from Target class, override OnTarget()
  5. Always validate inputs in command handlers

Command Registration

using Server.Commands;

namespace Server.Custom;

public static class MyCommands
{
    public static void Configure()
    {
        CommandSystem.Register("MyCommand", AccessLevel.GameMaster, MyCommand_OnCommand);
        CommandSystem.Register("MyOtherCmd", AccessLevel.Player, MyOtherCmd_OnCommand);
    }

    [Usage("MyCommand <name> [count]")]
    [Description("Does something with a name and optional count")]
    public static void MyCommand_OnCommand(CommandEventArgs e)
    {
        var from = e.Mobile;

        if (e.Length < 1)
        {
            from.SendMessage("Usage: [MyCommand <name> [count]");
            return;
        }

        var name = e.GetString(0);
        var count = e.Length > 1 ? e.GetInt32(1) : 1;

        from.SendMessage($"Processing {name} x{count}");
    }
}

CommandEventArgs

e.Mobile        // Mobile who issued the command
e.Command       // Command name string
e.ArgString     // Raw argument string
e.Arguments     // string[] split arguments
e.Length         // Number of arguments

// Typed argument accessors:
e.GetString(0)  // Get string at index (empty string if missing)
e.GetInt32(1)   // Get int at index (0 if missing/invalid)
e.GetUInt32(0)  // Get uint at index
e.GetBoolean(0) // Get bool at index
e.GetDouble(0)  // Get double at index
e.GetTimeSpan(0) // Get TimeSpan at index

Access Levels

AccessLevel.Player        // Regular players
AccessLevel.Counselor     // Support staff
AccessLevel.GameMaster    // GMs
AccessLevel.Seer          // Event coordinators
AccessLevel.Administrator // Server admins
AccessLevel.Developer     // Developers
AccessLevel.Owner         // Server owner

Target System

Basic Target

using Server.Targeting;

private class MyTarget : Target
{
    public MyTarget() : base(
        12,                    // Range (-1 for unlimited)
        false,                 // AllowGround
        TargetFlags.None       // None, Harmful, or Beneficial
    )
    {
        // Optional settings:
        // CheckLOS = false;      // Skip line-of-sight check
        // DisallowMultis = true; // Don't allow targeting multi objects
    }

    protected override void OnTarget(Mobile from, object targeted)
    {
        if (targeted is Mobile m)
        {
            from.SendMessage($"You targeted {m.Name}");
        }
        else if (targeted is Item item)
        {
            from.SendMessage($"You targeted item {item.Name}");
        }
        else if (targeted is LandTarget land)
        {
            from.SendMessage($"You targeted land at {land.Location}");
        }
        else if (targeted is StaticTarget st)
        {
            from.SendMessage($"You targeted static {st.ItemID}");
        }
    }

    protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
    {
        from.SendMessage("Targeting cancelled.");
    }

    protected override void OnTargetFinish(Mobile from)
    {
        // Always called after targeting completes (success or cancel)
    }
}

// Usage:
from.Target = new MyTarget();

TargetFlags

TargetFlags.None       // Neutral targeting
TargetFlags.Harmful    // Criminal check, combat targeting
TargetFlags.Beneficial // Healing, buffing

Target Object Types

  • Mobile -- a player or creature
  • Item -- an item in the world or container
  • LandTarget -- ground tile (Location, TileID, Name)
  • StaticTarget -- static map object (Location, ItemID, Name, Hue)

Command + Target Pattern

public static void Configure()
{
    CommandSystem.Register("Tame", AccessLevel.GameMaster, Tame_OnCommand);
}

[Usage("Tame")]
[Description("Force-tames a creature")]
public static void Tame_OnCommand(CommandEventArgs e)
{
    e.Mobile.SendMessage("Select a creature to tame.");
    e.Mobile.Target = new TameTarget();
}

private class TameTarget : Target
{
    public TameTarget() : base(-1, false, TargetFlags.None) { }

    protected override void OnTarget(Mobile from, object targeted)
    {
        if (targeted is BaseCreature { Tamable: true } creature)
        {
            creature.SetControlMaster(from);
            from.SendMessage($"You have tamed {creature.Name}.");
        }
        else
        {
            from.SendMessage("That cannot be tamed.");
        }
    }
}

Target Validation Overrides

// Override these for custom validation:
protected override bool CanTarget(Mobile from, Mobile mobile, ref Point3D loc, ref Map map)
protected override bool CanTarget(Mobile from, Item item, ref Point3D loc, ref Map map)
protected override bool CanTarget(Mobile from, LandTarget land, ref Point3D loc, ref Map map)
protected override bool CanTarget(Mobile from, StaticTarget st, ref Point3D loc, ref Map map)

// Error handlers:
protected override void OnTargetOutOfRange(Mobile from, object targeted)
protected override void OnTargetOutOfLOS(Mobile from, object targeted)
protected override void OnTargetNotAccessible(Mobile from, object targeted)
protected override void OnTargetDeleted(Mobile from, object targeted)
protected override void OnTargetUntargetable(Mobile from, object targeted)

Anti-Patterns

  • Registering commands outside Configure(): Won't be called during startup
  • Missing access level validation: Always set appropriate AccessLevel
  • Not checking e.Length: Accessing missing arguments returns defaults silently
  • Hardcoded range in targeting: Use -1 for unlimited, appropriate range for game mechanics

Real Examples

  • Command registration: Projects/UOContent/Commands/StaffAccess.cs
  • Target from item: Projects/UOContent/Items/Misc/InteriorDecorator.cs
  • Spell targeting: Projects/UOContent/Spells/First/MagicArrow.cs
  • Command system: Projects/Server/Commands.cs
  • Target base: Projects/Server/Targeting/Target.cs
  • Attributes: Projects/Server/Attributes.cs (Usage, Description, Aliases)

See Also

  • dev-docs/commands-targeting.md - Complete documentation
  • dev-docs/claude-skills/modernuo-gump-system.md - Commands that open gumps
  • dev-docs/claude-skills/modernuo-content-patterns.md - Content creation