=======================
target resolution
=======================

how we find what the player is talking about.

the problem
===========

when a player types "attack goblin" or "get sword", we need to figure out
which goblin, which sword. could be multiple matches. could be an alias.
could be "2.goblin" to mean the second one.

the system uses graceful degradation: try exact matches, fall back to prefix
matches, then aliases, then ordinal selection.

parsing the raw input
=====================

``parse_target(raw)`` extracts ordinal prefixes::

    "goblin"     → (1, "goblin")
    "2.goblin"   → (2, "goblin")
    "3.rat"      → (3, "rat")

only ordinals >= 1 are valid. "0.goblin" or "-1.goblin" are treated as literal
names (weird, but no crash).

matching priority
=================

``resolve_target(name, candidates, key=None)`` uses a priority-based matching
flow:

**four match priorities** (checked in order, stops at first non-empty result):

1. exact name match (case-insensitive)
2. name prefix match ("gob" matches "goblin")
3. exact alias match
4. alias prefix match ("gobb" matches alias "gobby")

collects ALL matches at each priority level before moving to the next. this
prevents a prefix match from shadowing a later exact alias match.

**ordinal selection**: if an ordinal was parsed (e.g., "2.goblin"), picks the
Nth match from whichever priority level produced results.

**fallback**: returns None if no matches found at any level.

custom key function lets you adapt to non-standard objects (e.g., dicts with
a "name" field).

finding entities
================

``find_entity_on_tile(name, player, z_filter=True)`` searches players and mobs
on the same tile.

filters:
- excludes the player themselves
- skips dead mobs
- z-axis filtering: only matches entities on same z-level (both grounded or
  both flying). flying creatures can't attack grounded ones by default.

sorts results to prefer Players over Mobs.

finding things
==============

``find_thing_on_tile(name, zone, x, y)`` searches ground items at coordinates.
only Thing instances.

``find_in_inventory(name, player)`` searches player inventory. only Thing
instances.

ordinal disambiguation
======================

if there are three goblins, you can target the second with "2.goblin"::

    attack 2.goblin

the ordinal is parsed, then resolve_target collects matches and picks the Nth
one. ordinal selection happens after all four priority levels have been tried,
operating on whichever level produced matches.

case sensitivity
================

all matching is case-insensitive. "Goblin", "goblin", "GOBLIN" all work.

code
====

- ``src/mudlib/commands/targeting.py`` - parse and resolve functions
- ``tests/test_targeting.py`` - test coverage for all priority levels
