Object Matching
When a player types get sword or look here, the server must resolve
that text into an internal database reference number (dbref). This
translation—from human-readable names to dbrefs—is object matching.
The implementation lives in match.cpp and follows a precise sequence of
checks, each with a defined confidence level.
The Confidence Hierarchy
Every candidate match is assigned a confidence score built from these flags, which combine as a bitmask:
| Flag | Value | Meaning |
|---|---|---|
CON_LOCAL | 0x01 | Object is near the player |
CON_TYPE | 0x02 | Object is the preferred type |
CON_LOCK | 0x04 | Player passes the object’s lock |
CON_COMPLETE | 0x08 | Input is the object’s full name |
CON_TOKEN | 0x10 | Input is a special keyword (me, here, *player) |
CON_DBREF | 0x20 | Input is a direct dbref (#123) |
A higher confidence always wins. When two candidates share the same
confidence, one is chosen at random. Once a CON_DBREF-level match is
found, most match functions return immediately without searching further.
Match Order
The function match_everything() drives the standard search. It checks
sources in this order:
- me – The literal word
meresolves to the player’s own dbref. - here – The literal word
hereresolves to the player’s location. The location’s actual name is also checked. - Absolute dbrefs – Input beginning with
#is parsed as a number. Named references (#_name) are also resolved here. - Bare numbers – If the
MAT_NUMERICflag is set, a plain number without#is treated as a dbref. - home – If the
MAT_HOMEflag is set, the literal wordhomematches the special HOME dbref. - Player names – Input beginning with
*triggers a player-name lookup (e.g.,*Bob).
If any of these produce a CON_TOKEN-level match or better, the search
stops. Otherwise it continues to name-based searching:
- Exits – Exits carried by the player, then exits in the player’s
location. If
MAT_EXIT_PARENTSis set, parent chains are walked. - Neighbors – Objects in the contents list of the player’s location.
- Inventory – Objects in the player’s own contents list.
For neighbors and inventory, both exact and partial name matches are
attempted. An exact match earns CON_COMPLETE; a partial (substring)
match earns a lower base confidence.
Exit Matching
Exit names use a special convention: a single exit can have multiple
aliases separated by semicolons. The name North;n;no defines three ways
to refer to one exit. The function matches_exit_from_list() walks the
semicolon-delimited list and compares the player’s input against each
alias individually. The comparison is case-insensitive and Unicode-aware.
Exit matching also walks parent chains when MAT_EXIT_PARENTS is active.
The master room’s exits provide global commands available everywhere.
Zone exits offer a similar facility scoped to a zone.
The locate() Function
Softcode accesses matching through locate(<looker>, <string>, <where>).
The <where> argument is a string of single-character flags controlling
which search scopes are active:
| Flag | Scope |
|---|---|
a | Absolute references (#number) |
c | Exits carried by the looker (with parents) |
e | Exits in the looker’s location (with parents) |
h | The keyword here |
i | The looker’s inventory |
m | The keyword me |
n | Neighbors (other objects in the same room) |
p | Player names prefixed by * |
s | Possessive matching (e.g., bob's sword) |
* | All of the above |
Qualifier flags resolve ambiguity: E, P, R, and T prefer exits,
players, rooms, or things respectively. L prefers unlocked exits over
locked ones. X picks randomly among equal matches instead of returning
#-2. V sends error messages to the looker.
Return Values
| Dbref | Meaning |
|---|---|
#-1 (NOTHING) | No match found. The player sees “I don’t see that here.” |
#-2 (AMBIGUOUS) | Multiple objects match with equal confidence. The player sees “I don’t know which one you mean!” |
In softcode, locate() returns #-1 for no match and #-2 for
ambiguity (unless the X qualifier selects randomly).
The MAT_ Flags
These flags control match_everything() behavior:
| Flag | Value | Effect |
|---|---|---|
MAT_NO_EXITS | 1 | Skip all exit matching |
MAT_EXIT_PARENTS | 2 | Walk parent chains when matching exits |
MAT_NUMERIC | 4 | Accept bare numbers as dbrefs (without #) |
MAT_HOME | 8 | Recognize the keyword home |
Most commands use MAT_EXIT_PARENTS. The @open command uses
MAT_NO_EXITS since it creates exits rather than matching them.
Lock Key Matching
When @lock keys are parsed in boolexp.cpp, the lock compiler calls
init_match() and match_everything(MAT_EXIT_PARENTS) to resolve each
token in the lock expression. If the result is NOTHING, the player is
told “I don’t see X here.” If the result is AMBIGUOUS, the player is
told “I don’t know which X you mean!” In either failure case, the lock
expression falls back to TRUE_BOOLEXP (always fails to pass).
The init_match_check_keys() variant also evaluates the @lock on each
candidate during matching, adding CON_LOCK confidence to objects the
player can pass.
Common Pitfalls
- Ambiguity. If two objects named “sword” are in the same room and no
exact-match tiebreaker applies, the server returns
#-2. Use dbrefs in softcode to avoid this. - Recycled dbrefs. A dbref like
#47is stable only while the object exists. After@destroy, the number can be reused. Hardcoded dbref references in attributes can silently refer to the wrong object. - Partial matches are weak. A partial name match has lower confidence
than an exact match. If the room contains “red ball” and “red car,”
typing
redis ambiguous. Typing the full name resolves it. - Exit alias order does not matter. All semicolon-separated aliases are equally valid. The first matching alias wins for a given exit, but among multiple exits, equal-confidence matches are chosen randomly.
- Scope matters. A command that uses
MAT_NO_EXITSwill never find an exit by name. Conversely,locate()with onlyiwill never check the room’s contents.