From 504dff430444f5bb887fa1178313ad2fd2e4d519 Mon Sep 17 00:00:00 2001 From: Rick L Bird Date: Sun, 15 May 2011 15:57:48 -0400 Subject: [PATCH] Author: talvo@talvo.com Date: Tue Jan 26 06:44:56 2010 +0000 Issue 222, rewritten object matching routines in match.c Fixes #172 --- hdrs/match.h | 11 +- src/fundb.c | 27 +- src/look.c | 3 +- src/match.c | 766 +++++++++++++++++++++------------------------------ src/move.c | 8 +- src/notify.c | 1 - 6 files changed, 338 insertions(+), 478 deletions(-) diff --git a/hdrs/match.h b/hdrs/match.h index 26724ec..96a6905 100644 --- a/hdrs/match.h +++ b/hdrs/match.h @@ -19,16 +19,17 @@ #define MAT_NEIGHBOR 0x000100 #define MAT_POSSESSION 0x000200 #define MAT_EXIT 0x004000 +#define MAT_PMATCH 0x008000 /* special things to match */ #define MAT_CARRIED_EXIT 0x010000 #define MAT_CONTAINER 0x020000 #define MAT_REMOTE_CONTENTS 0x040000 #define MAT_NEAR 0x080000 #define MAT_ENGLISH 0x100000 -#define MAT_EXACT 0x200000 /* only match preferred type */ /* types of match results - used internally */ #define MAT_NOISY 0x1000000 #define MAT_LAST 0x2000000 +#define MAT_TYPE 0x4000000 /* don't accept objects of other types */ /* groups of things to match */ #define MAT_EVERYTHING (MAT_ME|MAT_HERE|MAT_ABSOLUTE|MAT_PLAYER| \ MAT_NEIGHBOR|MAT_POSSESSION|MAT_EXIT|MAT_ENGLISH) @@ -47,12 +48,12 @@ * last_match_result - returns a match or NOTHING * match_controlled - returns match if player controls, or NOTHING */ -extern dbref match_result - (const dbref who, const char *name, const int type, const long int flags); +extern dbref +match_result(dbref who, const char *xname, int type, long flags); extern dbref noisy_match_result - (const dbref who, const char *name, const int type, const long int flags); + (const dbref who, const char *name, const int type, const long flags); extern dbref last_match_result - (const dbref who, const char *name, const int type, const long int flags); + (const dbref who, const char *name, const int type, const long flags); extern dbref match_controlled(dbref player, const char *name); #define match_thing(player,name) \ diff --git a/src/fundb.c b/src/fundb.c index 4c34ea4..b6ce0a4 100644 --- a/src/fundb.c +++ b/src/fundb.c @@ -1905,9 +1905,7 @@ FUNCTION(fun_locate) int pref_type; dbref item, loc; char *p; - int keys = 0; int ambig_ok = 0; - int force_type = 0; long match_flags = 0; /* find out what we're matching in relation to */ @@ -1916,7 +1914,7 @@ FUNCTION(fun_locate) safe_str("#-1", buff, bp); return; } - if (!CanSee(executor, looker) && !controls(executor, looker)) { + if (!See_All(executor) && !controls(executor, looker)) { safe_str("#-1", buff, bp); return; } @@ -1940,14 +1938,11 @@ FUNCTION(fun_locate) case 'T': pref_type |= TYPE_THING; break; - case 'D': - pref_type |= TYPE_DIVISION; - break; case 'L': - keys = 1; + match_flags |= MAT_CHECK_KEYS; break; case 'F': - force_type = 1; + match_flags |= MAT_TYPE; break; case '*': match_flags |= MAT_EVERYTHING; @@ -1976,6 +1971,9 @@ FUNCTION(fun_locate) case 'n': match_flags |= MAT_NEIGHBOR; break; + case 'y': + match_flags |= MAT_PMATCH; + break; case 'p': match_flags |= MAT_PLAYER; break; @@ -1985,8 +1983,8 @@ FUNCTION(fun_locate) case 'X': ambig_ok = 1; /* okay to pick last match */ break; - case ' ': /* skip over spaces */ - break; + case ' ': + break; /* skip over spaces */ default: notify_format(executor, T("I don't understand switch '%c'."), *p); break; @@ -1995,8 +1993,8 @@ FUNCTION(fun_locate) if (!pref_type) pref_type = NOTYPE; - if (keys) - match_flags = MAT_CHECK_KEYS; + if (!(match_flags & ~(MAT_CHECK_KEYS | MAT_TYPE))) + match_flags |= MAT_EVERYTHING; /* report the results */ if (!ambig_ok) @@ -2009,11 +2007,6 @@ FUNCTION(fun_locate) return; } - if (force_type && !(Typeof(item) & pref_type)) { - safe_dbref(NOTHING, buff, bp); - return; - } - /* To locate it, you must either be able to examine its location * or be able to see the item. */ diff --git a/src/look.c b/src/look.c index 5bb9cce..2b6d91a 100644 --- a/src/look.c +++ b/src/look.c @@ -649,8 +649,7 @@ do_look_at(dbref player, const char *name, int key) return; } thing = - match_result(loc, name, NOTYPE, - MAT_PLAYER | MAT_REMOTE_CONTENTS | MAT_EXIT | MAT_REMOTES); + match_result(loc, name, NOTYPE, MAT_POSSESSION | MAT_CARRIED_EXIT); if (thing == NOTHING) { notify(player, T("I don't see that here.")); return; diff --git a/src/match.c b/src/match.c index ed4399c..a41f52e 100644 --- a/src/match.c +++ b/src/match.c @@ -32,6 +32,7 @@ * MAT_CONTAINER - match a container I'm in * MAT_REMOTE_CONTENTS - match the contents of a remote location * MAT_ENGLISH - match natural english 'my 2nd flower' + * MAT_TYPE - match only objects of the given type(s) * MAT_EVERYTHING - me,here,absolute,player,neighbor,possession,exit * MAT_NEARBY - everything near * MAT_OBJECTS - me,absolute,player,neigbor,possession @@ -53,94 +54,40 @@ #include "parse.h" #include "flags.h" #include "dbdefs.h" +#include "confmagic.h" +#include "attrib.h" -static dbref match_result_internal - (dbref who, const char *name, int type, long flags); -static dbref simple_matches(dbref who, const char *name, long flags); static int parse_english(char **name, long *flags); -static dbref match_me(const dbref who, const char *name); -static dbref match_here(const dbref who, const char *name); -/** Convenience alias for parse_objid */ -#define match_absolute(name) parse_objid(name) -static dbref match_player(const dbref matcher, const char *match_name); -static dbref choose_thing(const dbref match_who, const int preferred_type, - long int flags, dbref thing1, dbref thing2); +static dbref match_player(dbref who, const char *name); extern int check_alias(const char *command, const char *list); /* game.c */ +static int match_aliases(dbref who, const char *name); +static dbref choose_thing(const dbref who, const int preferred_type, long flags, dbref thing1, dbref thing2); - -/** A wrapper for returning a match, AMBIGUOUS, or NOTHING. - * This function attempts to match a name for who, and - * can return the matched dbref, AMBIGUOUS, or NOTHING. - * \param who the looker. - * \param name name to try to match. - * \param type type of object to match. - * \param flags match flags. - * \return dbref of matched object, or AMBIGUOUS, or NOTHING. - */ dbref -match_result(const dbref who, const char *name, const int type, - const long flags) +noisy_match_result(const dbref who, const char *name, const int type, const long flags) { - return match_result_internal(who, name, type, flags); -} + dbref match; -/** A noisy wrapper for returning a match or NOTHING. - * This function attempts to match a name for who, and - * can return the matched dbref or NOTHING (in ambiguous cases, - * NOTHING is returned). If no match is made, the looker is notified - * of the failure to match or ambiguity. - * \param who the looker. - * \param name name to try to match. - * \param type type of object to match. - * \param flags match flags. - * \return dbref of matched object, or NOTHING. - */ -dbref -noisy_match_result(const dbref who, const char *name, const int type, - const long flags) -{ - return match_result_internal(who, name, type, flags | MAT_NOISY); + match = match_result(who, name, type, flags | MAT_NOISY); + if (!GoodObject(match)) + return NOTHING; + else + return match; } -/** A noisy wrapper for returning a match or NOTHING. - * This function attempts to match a name for who, and - * can return the matched dbref or NOTHING. In ambiguous cases, - * the last matched thing is returned. - * \param who the looker. - * \param name name to try to match. - * \param type type of object to match. - * \param flags match flags. - * \return dbref of matched object, or NOTHING. - */ dbref -last_match_result(const dbref who, const char *name, const int type, - const long flags) +last_match_result(const dbref who, const char *name, const int type, const long flags) { - return match_result_internal(who, name, type, flags | MAT_LAST); + return match_result(who, name, type, flags | MAT_LAST); } -/** Wrapper for a noisy match with control checks. - * This function performs a noisy_match_result() and then checks that - * the looker controls the matched object before returning it. - * If the control check fails, the looker is notified and NOTHING - * is returned. - * \param player the looker. - * \param name name to try to match. - * \return dbref of matched controlled object, or NOTHING. - */ dbref match_controlled(dbref player, const char *name) { - dbref match; - match = noisy_match_result(player, name, NOTYPE, MAT_EVERYTHING); - if (GoodObject(match) && !controls(player, match)) { - notify(player, T("Permission denied.")); - return NOTHING; - } else { - return match; - } + return noisy_match_result(player, name, NOTYPE, MAT_EVERYTHING | MAT_CONTROL); } + /* The real work. Here's the spec: * str --> "me" * --> "here" @@ -169,7 +116,7 @@ match_controlled(dbref player, const char *name) * c. *player * 2. Parse for adj-phrases and restrict further matching and/or * remember the object count - * 3. Look for matches (remote contents, neighbor, inventory, exits, + * 3. Look for matches (remote contents, neighbor, inventory, exits, * containers, carried exits) * a. If we don't have an object count, collect the number of exact * and partial matches and the best partial match. @@ -184,185 +131,331 @@ match_controlled(dbref player, const char *name) * e. If we got no matches, complain */ -#define MATCH_NONE 0x0 /**< No matches were found */ -#define MATCH_EXACT 0x1 /**< At least one exact match found */ -#define MATCH_PARTIAL 0x2 /**< At least one partial match found, no exact */ -/** Prototype for matching functions */ -#define MATCH_FUNC_PROTO(fun_name) \ - /* ARGSUSED */ /* try to keep lint happy */ \ - static int fun_name(const dbref who, const char *name, const int type, \ - const long flags, dbref first, \ - dbref *match, int *exact_matches_to_go, int *matches_to_go) -/** Common declaration for matching functions */ -#define MATCH_FUNC(fun_name) \ - static int fun_name(const dbref who, const char *name, const int type, \ - const long flags, dbref first __attribute__ ((__unused__)), \ - dbref *match, int *exact_matches_to_go, int *matches_to_go) -/** Macro to execute matching and store some results */ -#define RUN_MATCH_FUNC(fun,first) \ - { \ - result = fun(who, name, type, flags, first, &match, \ - &exact_matches_to_go, &matches_to_go); \ - if (result == MATCH_EXACT) { \ - exact_match = match; \ - /* If it's the nth exact match, we're done */ \ - if (matchnum && !exact_matches_to_go) \ - goto finished; \ - /* If it's the n'th match, remember it */ \ - if (matchnum && !matches_to_go) \ - last_match = match; \ - } else if (result == MATCH_PARTIAL) { \ - if (!matchnum || !matches_to_go) \ - last_match = match; \ +/* +#define DEBUG_OBJECT_MATCHING +/**/ +#ifdef DEBUG_OBJECT_MATCHING +static dbref debugMatchTo = 1; +#endif + +#define MATCHED(full) \ + { \ + if (!MATCH_CONTROLS) { \ + /* Found a matching object, but we lack necessary control */ \ + nocontrol = 1; \ + continue; \ + } \ + if (!final) { \ + bestmatch = BEST_MATCH; \ + if (bestmatch != match) { \ + /* Previously matched item won over due to type, @lock, etc, checks */ \ + continue; \ + } \ + if (full) { \ + if (exact) { \ + /* Another exact match */ \ + curr++; \ + } else { \ + /* Ignore any previous partial matches now we have an exact match */ \ + exact = 1; \ + curr = 1; \ + } \ + } else { \ + /* Another partial match */ \ + curr++; \ + } \ + } else { \ + curr++; \ + if (curr == final) { \ + /* we've successfully found the Nth item */ \ + bestmatch = match; \ + done = 1; \ + break; \ + } \ + } \ + } + + +#define MATCH_LIST(start) \ + { \ + if (done) \ + break; /* already found the Nth object we needed */ \ + match = start; \ + DOLIST(match, match) { \ + if (!MATCH_TYPE) { \ + /* Exact-type match required, but failed */ \ + continue; \ + } else if (match == abs) { \ + /* absolute dbref match in list */ \ + MATCHED(1); \ + } else if (!can_interact(match, who, INTERACT_MATCH)) { \ + /* Not allowed to match this object */ \ + continue; \ + } else if (match_aliases(match, name) || (!IsExit(match) && !strcasecmp(Name(match), name))) { \ + /* exact name match */ \ + MATCHED(1); \ + } else if ((!exact || !GoodObject(bestmatch)) && !IsExit(match) && string_match(Name(match), name)) { \ + /* partial name match */ \ + MATCHED(0); \ + } \ } \ - } + } + +#define MATCH_CONTROLS (!(flags & MAT_CONTROL) || controls(who, match)) + +#define MATCH_TYPE ((type & Typeof(match)) ? 1 : ((flags & MAT_TYPE) ? 0 : -1)) -MATCH_FUNC_PROTO(match_possession); -MATCH_FUNC_PROTO(match_neighbor); -MATCH_FUNC_PROTO(match_exit); -MATCH_FUNC_PROTO(match_exit_internal); -MATCH_FUNC_PROTO(match_container); -MATCH_FUNC_PROTO(match_list); +#define BEST_MATCH choose_thing(who, type, flags, bestmatch, match) static dbref -match_result_internal(dbref who, const char *xname, int type, long flags) +choose_thing(const dbref who, const int preferred_type, long flags, dbref thing1, dbref thing2) { - dbref match = NOTHING, last_match = NOTHING, exact_match = NOTHING; - int exact_matches_to_go, matches_to_go; - int matchnum = 0; - int result; - char *name, *sname; + int key; + /* If there's only one valid thing, return it */ + /* Check == NOTHING, not GoodObject, to make sure we favour AMBIGUOUS over NOTHING */ + /* (Apologies to Theodor Geisel) */ + if (thing1 == NOTHING) { +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo,"Picking #%d over #%d (a nothing)", thing2, thing1); +#endif + return thing2; + } else if (thing2 == NOTHING) { +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo,"Picking #%d over #%d (a nothing)", thing1, thing2); +#endif + return thing1; + } - /* The quick ones that can never be ambiguous */ - match = simple_matches(who, xname, flags); - if (GoodObject(match)) - return match; + /* If a type is given, and only one thing is of that type, return it */ + if (preferred_type != NOTYPE) { + if (Typeof(thing1) & preferred_type) { + if (!(Typeof(thing2) & preferred_type)) { +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo,"Picking #%d over #%d (type)", thing1, thing2); +#endif + return thing1; + } + } else if (Typeof(thing2) & preferred_type) { +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo,"Picking #%d over #%d (type)", thing2, thing1); +#endif + return thing2; + } + } - sname = name = mush_strdup(xname, "mri.string"); + if (flags & MAT_CHECK_KEYS) { + key = could_doit(who, thing1); + if (!key && could_doit(who, thing2)) { +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo,"Picking #%d over #%d (unlocked)", thing2, thing1); +#endif + return thing2; + } else if (key && !could_doit(who, thing2)) { +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo,"Picking #%d over #%d (unlocked)", thing1, thing2); +#endif + return thing1; + } + } +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo,"Picking #%d over #%d (last matched)", thing2, thing1); +#endif + /* No luck. Return last match */ + return thing2; +} - if (flags & MAT_ENGLISH) { - /* Check for adjective phrases */ - matchnum = parse_english(&name, &flags); +static dbref +match_player(dbref who, const char *name) { + dbref match; + + if (*name == LOOKUP_TOKEN) { + name++; } - /* Perform matching. We've already had flags restricted by any - * adjective phrases. If matchnum is set, collect the matchnum'th - * exact match (and stop) and the matchnum'th match (exact or partial, - * and store this in case we don't get enough exact matches). - * If not, collect the number of exact and partial matches and the - * last exact and partial matches. - */ - exact_matches_to_go = matches_to_go = matchnum; - if (flags & MAT_POSSESSION) - RUN_MATCH_FUNC(match_possession, NOTHING); - if (flags & MAT_NEIGHBOR) - RUN_MATCH_FUNC(match_neighbor, NOTHING); - if (flags & MAT_REMOTE_CONTENTS) - RUN_MATCH_FUNC(match_possession, NOTHING); - if (flags & MAT_EXIT) - RUN_MATCH_FUNC(match_exit, NOTHING); - if (flags & MAT_CONTAINER) - RUN_MATCH_FUNC(match_container, NOTHING); - if (flags & MAT_CARRIED_EXIT) - RUN_MATCH_FUNC(match_exit_internal, who); - -finished: - /* Set up the default match_result behavior */ - if (matchnum) { - /* nth exact match? */ - if (!exact_matches_to_go) - match = exact_match; - else if (GoodObject(last_match)) - match = last_match; /* nth exact-or-partial match, or nothing? */ - /* This shouldn't happen, but just in case we have a valid match, - * and an invalid last_match in the matchnum case, fall through and - * use the match. - */ - } else if (GoodObject(exact_match)) { - /* How many exact matches? */ - if (exact_matches_to_go == -1) - match = exact_match; /* Good */ - else if (flags & MAT_LAST) - match = exact_match; /* Good enough */ - else - match = AMBIGUOUS; - } else { - if (!matches_to_go) - match = NOTHING; /* No matches */ - else if (matches_to_go == -1) - match = last_match; /* Good */ - else if (flags & MAT_LAST) - match = last_match; /* Good enough */ - else - match = AMBIGUOUS; + while(isspace((unsigned char) *name)) { + name++; } - /* Handle noisy_match_result */ - if (flags & MAT_NOISY) { - mush_free(sname, "mri.string"); - switch (match) { - case NOTHING: - notify(who, T("I can't see that here.")); - return NOTHING; - case AMBIGUOUS: - notify(who, T("I don't know which one you mean!")); - return NOTHING; - default: - return match; + match = lookup_player(name); + if (match != NOTHING) { + return match; + } + return visible_short_page(who, name); +} + +static int +match_aliases(dbref who, const char *name) { + + if (!IsPlayer(who) && !IsExit(who)) { + return 0; + } + + if (IsExit(who)) { + return check_alias(name, Name(who)); + } else { + char tbuf1[BUFFER_LEN]; + ATTR *a = atr_get_noparent(who, "ALIAS"); + if (!a) { + return 0; } + mush_strncpy(tbuf1, atr_value(a), BUFFER_LEN); + return check_alias(name, tbuf1); } - mush_free(sname, "mri.string"); - return match; + } -static dbref -simple_matches(dbref who, const char *name, long flags) +dbref +match_result(dbref who, const char *xname, int type, long flags) { - dbref match = NOTHING; - if (flags & MAT_ME) { - match = match_me(who, name); - if (GoodObject(match)) - return match; + dbref match, loc; + dbref bestmatch = NOTHING; + dbref abs = parse_objid(xname); + int curr = 0, final = 0, nocontrol = 0, exact = 0, done = 0; + int goodwho = GoodObject(who); + char *name, *sname; +#ifdef DEBUG_OBJECT_MATCHING + debugMatchTo = (IsPlayer(who) ? who : 1); + notify(debugMatchTo, "ENTERING MATCH_RESULT"); + notify_format(debugMatchTo, "FLAGS: %ld, TYPE: %d", flags, (type == NOTYPE)); +#endif + /* match "me" */ + match = who; + if (MATCH_TYPE && (flags & MAT_ME) && !strcasecmp(xname, "me")) { + return match; } - if (flags & MAT_HERE) { - match = match_here(who, name); - if (GoodObject(match)) + + /* match "here" */ + match = Location(who); + if ((flags & MAT_HERE) && !strcasecmp(xname, "here") && GoodObject(match) && MATCH_TYPE) { + if(MATCH_CONTROLS) { return match; + } else { + nocontrol = 1; + } } - if (!(flags & MAT_NEAR) || Long_Fingers(who)) { - if (flags & MAT_ABSOLUTE) { - match = match_absolute(name); - if (GoodObject(match) && (flags & MAT_NEAR) && !CanRemote(who, match)) - goto mat_near; - if (GoodObject(match)) { - if (flags & MAT_CONTROL) { - /* Check for control */ - if (controls(who, match) || nearby(who, match)) - return match; - } else { - return match; - } + + /* match *, or */ + match = match_player(who, xname); + if (((flags & MAT_PMATCH) || ((flags & MAT_PLAYER) && *xname == LOOKUP_TOKEN)) && MATCH_TYPE) { + if (GoodObject(match)) { + if (MATCH_CONTROLS) { + return match; + } else { + nocontrol = 1; } + } else { + bestmatch = BEST_MATCH; } - if (flags & MAT_PLAYER) { - match = match_player(who, name); - if (GoodObject(match)) - return match; + } + + /* dbref match */ + match = abs; + if (GoodObject(match) && MATCH_TYPE) { + if (!(flags & MAT_NEAR) || Long_Fingers(who) || (nearby(who, match) || controls(who, match))) { + /* valid dbref match */ + if (MATCH_CONTROLS) { + return match; + } else { + nocontrol = 1; + } } - } else { - /* We're doing a nearby match and the player doesn't have - * long_fingers, so it's a controlled absolute - */ -mat_near: - match = match_absolute(name); - if (GoodObject(match) && (controls(who, match) || nearby(who, match))) - return match; } - return NOTHING; + + sname = name = mush_strdup(xname, "mri.string"); + if (flags & MAT_ENGLISH) { + /* English-style matching */ + final = parse_english(&name, &flags); + } +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo, "AFTER ENGLISH, we have: name = %s, curr = %d, flags = %ld", name, curr, flags); +#endif + + while (1) { + loc = (goodwho ? (IsRoom(who) ? who : Location(who)) : NOTHING); +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo, "Running for #%d in #%d", who, loc); +#endif + if (goodwho && ((flags & MAT_POSSESSION) || (flags & MAT_REMOTE_CONTENTS))) { +#ifdef DEBUG_OBJECT_MATCHING + notify(debugMatchTo, "STARTING POSSESSION"); +#endif + MATCH_LIST(Contents(who)); + } + if (GoodObject(loc) && (flags & MAT_NEIGHBOR)) { +#ifdef DEBUG_OBJECT_MATCHING + notify(debugMatchTo, "STARTING NEIGHBOURS"); +#endif + MATCH_LIST(Contents(loc)); + } + if ((type & TYPE_EXIT) || !(flags & MAT_TYPE)) { + if (GoodObject(loc) && IsRoom(loc) && (flags & MAT_EXIT)) { +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo, "STARTING EXIT"); +#endif + if (flags & MAT_REMOTES && GoodObject(Zone(loc)) && IsRoom(Zone(loc))) { +#ifdef DEBUG_OBJECT_MATCHING + notify(debugMatchTo, "STARTING EXIT-REMOTE"); +#endif + MATCH_LIST(Exits(Zone(loc))); + } + if (flags & MAT_GLOBAL) { +#ifdef DEBUG_OBJECT_MATCHING + notify(debugMatchTo, "STARTING EXIT-GLOBAL"); +#endif + MATCH_LIST(Exits(MASTER_ROOM)); + } + if (GoodObject(loc) && IsRoom(loc)) { +#ifdef DEBUG_OBJECT_MATCHING + notify(debugMatchTo, "STARTING EXITS"); +#endif + MATCH_LIST(Exits(loc)); + } + } + } + if ((flags & MAT_CONTAINER) && goodwho) { +#ifdef DEBUG_OBJECT_MATCHING + notify(debugMatchTo, "STARTING CONTAINER"); +#endif + MATCH_LIST(loc); + } + if ((type & TYPE_EXIT) || !(flags & MAT_TYPE)) { + if ((flags & MAT_CARRIED_EXIT) && goodwho && IsRoom(who)) { +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo, "STARTING CEXIT"); +#endif + MATCH_LIST(Exits(who)); + } + } + break; + } +#ifdef DEBUG_OBJECT_MATCHING + notify_format(debugMatchTo, "AT END, we have: final = %d, curr = %d, bestmatch = %d", final, curr, bestmatch); +#endif + if (!GoodObject(bestmatch) && final) { + /* we never found the Nth item */ + bestmatch = NOTHING; + } else if (!final && curr > 1) { + if (!(flags & MAT_LAST)) { + bestmatch = AMBIGUOUS; + } + } + + if (!GoodObject(bestmatch) && (flags & MAT_NOISY)) { + /* give error message */ + if (bestmatch == AMBIGUOUS) { + notify(who, T("I don't know which one you mean!")); + } else if (nocontrol) { + notify(who, T("Permission denied.")); + } else { + notify(who, T("I can't see that here.")); + } + } + + return bestmatch; } -/* +/* * adj-phrase --> adj * --> adj count * --> count @@ -413,7 +506,7 @@ parse_english(char **name, long *flags) while (**name == ' ') (*name)++; - /* If the name was just 'toward' (with no object name), reset + /* If the name was just 'toward' (with no object name), reset * everything and press on. */ if (!**name) { @@ -470,228 +563,3 @@ parse_english(char **name, long *flags) return count; } - -static dbref -match_me(const dbref who, const char *name) -{ - return (!strcasecmp(name, "me")) ? who : NOTHING; -} - -static dbref -match_here(const dbref who, const char *name) -{ - return (!strcasecmp(name, "here") && GoodObject(Location(who))) ? - Location(who) : NOTHING; -} - - -static dbref -match_player(const dbref matcher, const char *match_name) -{ - dbref match; - const char *p; - - if (*match_name != LOOKUP_TOKEN) - return NOTHING; - for (p = match_name + 1; isspace((unsigned char) *p); p++) ; - /* If lookup_player fails, try a partial match on connected - * players, 2.0 style. That can return match, NOTHING, AMBIGUOUS - */ - match = lookup_player(p); - return (match != NOTHING) ? match : visible_short_page(matcher, p); -} - -/* Run down a contents list and try to match */ -MATCH_FUNC(match_list) -{ - dbref absolute; - dbref alias_match; - int match_type = MATCH_NONE; - int nth_match = (*exact_matches_to_go != 0); - - /* If we were given an absolute dbref, remember it */ - absolute = match_absolute(name); - /* If we were given a player name, remember it */ - alias_match = lookup_player(name); - - DOLIST(first, first) { - if (first == absolute) { - /* Got an absolute match, return it */ - *match = first; - (*exact_matches_to_go)--; - (*matches_to_go)--; - return MATCH_EXACT; - } else if( can_interact(first, who, INTERACT_MATCH) && (!strcasecmp(Name(first), name) || - (GoodObject(alias_match) && (alias_match == first)))) { - /* An exact match, but there may be others */ - (*exact_matches_to_go)--; - (*matches_to_go)--; - if (nth_match) { - if (!(*exact_matches_to_go)) { - /* We're done */ - *match = first; - return MATCH_EXACT; - } - } else { - if (match_type == MATCH_EXACT) - *match = choose_thing(who, type, flags, *match, first); - else - *match = first; - match_type = MATCH_EXACT; - } - } else if ((match_type != MATCH_EXACT) - && string_match(Name(first), name) - && can_interact(first, who, INTERACT_MATCH)) { - /* A partial match, and we haven't done an exact match yet */ - (*matches_to_go)--; - if (nth_match) { - if (!(*matches_to_go)) - *match = first; - } else if (match_type == MATCH_PARTIAL) - *match = choose_thing(who, type, flags, *match, first); - else - *match = first; - match_type = MATCH_PARTIAL; - } - } - /* If we've made the nth partial match in this round, there's none to go */ - if (nth_match && *matches_to_go < 0) - *matches_to_go = 0; - return match_type; -} - -/* We recursively search upwards trying to match exits */ -MATCH_FUNC(match_exit) -{ - dbref loc; - int mret = MATCH_NONE; /* FIXME: temporary workaround, see #250 */ - - loc = (IsRoom(who)) ? who : Location(who); - if (flags & MAT_REMOTES) { - if (GoodObject(loc)) - return match_exit_internal(who, name, type, flags, Zone(loc), - match, exact_matches_to_go, matches_to_go); - else - return NOTHING; - } else if (flags & MAT_GLOBAL) - return match_exit_internal(who, name, type, flags, MASTER_ROOM, - match, exact_matches_to_go, matches_to_go); - /* Recursively search upwards in locations parent tree */ - while(GoodObject(loc) && !IsGarbage(loc) && mret != MATCH_EXACT ) { - mret = match_exit_internal(who, name, type, flags, loc, - match, exact_matches_to_go, matches_to_go); - loc = Parent(loc); - } - return mret; -} - -MATCH_FUNC(match_exit_internal) -{ - dbref exit_tmp; - dbref absolute; - int match_type = MATCH_NONE; - int nth_match = (*exact_matches_to_go != 0); - - if (!GoodObject(first) || !IsRoom(first) || !name || !*name) - return NOTHING; - /* Store an absolute dbref match if given */ - absolute = match_absolute(name); - DOLIST(exit_tmp, Exits(first)) { - - if ((exit_tmp == absolute) && (can_interact(exit_tmp, who, INTERACT_MATCH))) { - /* Absolute match. Return immediately */ - *match = exit_tmp; - (*exact_matches_to_go)--; - (*matches_to_go)--; - return MATCH_EXACT; - } else if (check_alias(name, Name(exit_tmp)) - && (can_interact(exit_tmp, who, INTERACT_MATCH))) { - /* Matched an exit alias, but there may be more */ - (*exact_matches_to_go)--; - (*matches_to_go)--; - if (nth_match) { - if (!(*exact_matches_to_go)) { - /* We're done */ - *match = exit_tmp; - return MATCH_EXACT; - } - } else { - if (match_type == MATCH_EXACT) - *match = choose_thing(who, type, flags, *match, exit_tmp); - else - *match = exit_tmp; - match_type = MATCH_EXACT; - } - } - } - /* If we've made the nth partial match in this round, there's none to go */ - if (nth_match && *matches_to_go < 0) - *matches_to_go = 0; - return match_type; -} - - -MATCH_FUNC(match_possession) -{ - if (!GoodObject(who)) - return NOTHING; - return match_list(who, name, type, flags, Contents(who), match, - exact_matches_to_go, matches_to_go); -} - -MATCH_FUNC(match_container) -{ - if (!GoodObject(who)) - return NOTHING; - return match_list(who, name, type, flags, Location(who), match, - exact_matches_to_go, matches_to_go); -} - -MATCH_FUNC(match_neighbor) -{ - dbref loc; - if (!GoodObject(who)) - return NOTHING; - loc = Location(who); - if (!GoodObject(loc)) - return NOTHING; - return match_list(who, name, type, flags, Contents(loc), match, - exact_matches_to_go, matches_to_go); -} - - -static dbref -choose_thing(const dbref match_who, const int preferred_type, long flags, - dbref thing1, dbref thing2) -{ - int has1; - int has2; - /* If there's only one valid thing, return it */ - /* (Apologies to Theodor Geisel) */ - if (thing1 == NOTHING) - return thing2; - else if (thing2 == NOTHING) - return thing1; - - /* If a type is given, and only one thing is of that type, return it */ - if (preferred_type != NOTYPE) { - if (Typeof(thing1) == preferred_type) { - if (Typeof(thing2) != preferred_type) - return thing1; - } else if (Typeof(thing2) == preferred_type) - return thing2; - } - - /* If we've asked for a basic lock check, and only one passes, use that */ - if (flags & MAT_CHECK_KEYS) { - has1 = could_doit(match_who, thing1); - has2 = could_doit(match_who, thing2); - if (has1 && !has2) - return thing1; - else if (has2 && !has1) - return thing2; - } - - /* No luck. Return the higher dbref */ - return (thing1 > thing2 ? thing1 : thing2); -} diff --git a/src/move.c b/src/move.c index bd43cbc..8f2f1df 100644 --- a/src/move.c +++ b/src/move.c @@ -534,14 +534,14 @@ do_get(dbref player, const char *what) dbref thing; char tbuf1[BUFFER_LEN], tbuf2[BUFFER_LEN], *tp; long match_flags = - MAT_NEIGHBOR | MAT_ABSOLUTE | MAT_CHECK_KEYS | MAT_NEAR | MAT_ENGLISH; + MAT_NEIGHBOR | MAT_CHECK_KEYS | MAT_NEAR | MAT_ENGLISH; if (!IsRoom(loc) && !EnterOk(loc) && !controls(player, loc)) { notify(player, T("Permission denied.")); return; } - if (!Long_Fingers(player)) - match_flags |= MAT_CONTROL; + if (Long_Fingers(player)) + match_flags |= MAT_ABSOLUTE; if (match_result(player, what, TYPE_THING, match_flags) == NOTHING) { if (POSSESSIVE_GET) { dbref box; @@ -671,7 +671,7 @@ do_drop(dbref player, const char *name) return; switch (thing = match_result(player, name, TYPE_THING, - MAT_POSSESSION | MAT_ABSOLUTE | MAT_CONTROL | + MAT_POSSESSION | MAT_ABSOLUTE | MAT_ENGLISH)) { case NOTHING: notify(player, T("You don't have that!")); diff --git a/src/notify.c b/src/notify.c index b873520..273c10a 100644 --- a/src/notify.c +++ b/src/notify.c @@ -1190,7 +1190,6 @@ level_broadcast(dbref minlevel, const char *fmt, ...) { va_list args; char tbuf1[BUFFER_LEN]; DESC *d; - int ok; va_start(args, fmt); #ifdef HAS_VSNPRINTF -- 2.30.2