/* $Header: /cvsroot/fbmuck/fbmuck/src/match.c,v 1.6 2003/04/07 18:37:02 cutevixy Exp $ */ #include "copyright.h" #include "config.h" /* Routines for parsing arguments */ #include <ctype.h> #include "db.h" #include "props.h" #include "params.h" #include "tune.h" #include "match.h" #include "interface.h" #include "externs.h" #define DOWNCASE(x) (tolower(x)) char match_cmdname[BUFFER_LEN]; /* triggering command */ char match_args[BUFFER_LEN]; /* remaining text */ void init_match(int descr, dbref player, const char *name, int type, struct match_data *md) { md->exact_match = md->last_match = NOTHING; md->match_count = 0; md->match_who = player; md->match_from = player; md->match_descr = descr; md->match_name = name; md->check_keys = 0; md->preferred_type = type; md->longest_match = 0; md->match_level = 0; md->block_equals = 0; md->partial_exits = (TYPE_EXIT == type); } void init_match_check_keys(int descr, dbref player, const char *name, int type, struct match_data *md) { init_match(descr, player, name, type, md); md->check_keys = 1; } void init_match_remote(int descr, dbref player, dbref what, const char *name, int type, struct match_data *md) { init_match(descr, player, name, type, md); md->match_from = what; } static dbref choose_thing(int descr, dbref thing1, dbref thing2, struct match_data *md) { int has1; int has2; int preferred = md->preferred_type; if (thing1 == NOTHING) { return thing2; } else if (thing2 == NOTHING) { return thing1; } if (preferred != NOTYPE) { if (Typeof(thing1) == preferred) { if (Typeof(thing2) != preferred) { return thing1; } } else if (Typeof(thing2) == preferred) { return thing2; } } if (md->check_keys) { has1 = could_doit(descr, md->match_who, thing1); has2 = could_doit(descr, md->match_who, thing2); if (has1 && !has2) { return thing1; } else if (has2 && !has1) { return thing2; } /* else fall through */ } return (RANDOM() % 2 ? thing1 : thing2); } void match_player(struct match_data *md) { dbref match; const char *p; if (*(md->match_name) == LOOKUP_TOKEN && payfor(OWNER(md->match_from), tp_lookup_cost)) { for (p = (md->match_name) + 1; isspace(*p); p++) ; if ((match = lookup_player(p)) != NOTHING) { md->exact_match = match; } } } /* returns dbref if registered object found for name, else NOTHING */ dbref find_registered_obj(dbref player, const char *name) { dbref match; const char *p; char buf[BUFFER_LEN]; PropPtr ptr; if (*name != REGISTERED_TOKEN) return (NOTHING); for (p = name + 1; *p && isspace(*p); p++) ; if (!*p) return (NOTHING); snprintf(buf, sizeof(buf), "_reg/%s", p); ptr = envprop(&player, buf, 0); if (!ptr) return NOTHING; #ifdef DISKBASE propfetch(player, ptr); /* DISKBASE PROPVALS */ #endif switch (PropType(ptr)) { case PROP_STRTYP: p = PropDataStr(ptr); #ifdef COMPRESS p = uncompress(p); #endif if (*p == NUMBER_TOKEN) p++; if (number(p)) { match = (dbref) atoi(p); if ((match >= 0) && (match < db_top) && (Typeof(match) != TYPE_GARBAGE)) return (match); } break; case PROP_REFTYP: match = PropDataRef(ptr); if ((match >= 0) && (match < db_top) && (Typeof(match) != TYPE_GARBAGE)) return (match); break; case PROP_INTTYP: match = (dbref) PropDataVal(ptr); if ((match > 0) && (match < db_top) && (Typeof(match) != TYPE_GARBAGE)) return (match); break; case PROP_LOKTYP: return (NOTHING); break; } return (NOTHING); } void match_registered(struct match_data *md) { dbref match; match = find_registered_obj(md->match_from, md->match_name); if (match != NOTHING) md->exact_match = match; } /* returns nnn if name = #nnn, else NOTHING */ static dbref absolute_name(struct match_data *md) { dbref match; if (*(md->match_name) == NUMBER_TOKEN) { match = parse_dbref((md->match_name) + 1); if (match < 0 || match >= db_top) { return NOTHING; } else { return match; } } else { return NOTHING; } } void match_absolute(struct match_data *md) { dbref match; if ((match = absolute_name(md)) != NOTHING) { md->exact_match = match; } } void match_me(struct match_data *md) { if (!string_compare(md->match_name, "me")) { md->exact_match = md->match_who; } } void match_here(struct match_data *md) { if (!string_compare(md->match_name, "here") && DBFETCH(md->match_who)->location != NOTHING) { md->exact_match = DBFETCH(md->match_who)->location; } } void match_home(struct match_data *md) { if (!string_compare(md->match_name, "home")) md->exact_match = HOME; } static void match_list(dbref first, struct match_data *md) { dbref absolute; absolute = absolute_name(md); if (!controls(OWNER(md->match_from), absolute)) absolute = NOTHING; DOLIST(first, first) { if (first == absolute) { md->exact_match = first; return; } else if (!string_compare(RNAME(first), md->match_name)) { /* if there are multiple exact matches, randomly choose one */ md->exact_match = choose_thing(md->match_descr, md->exact_match, first, md); } else if (string_match(RNAME(first), md->match_name)) { md->last_match = first; (md->match_count)++; } } } void match_possession(struct match_data *md) { match_list(DBFETCH(md->match_from)->contents, md); } void match_neighbor(struct match_data *md) { dbref loc; if ((loc = DBFETCH(md->match_from)->location) != NOTHING) { match_list(DBFETCH(loc)->contents, md); } } /* * match_exits matches a list of exits, starting with 'first'. * It will match exits of players, rooms, or things. */ void match_exits(dbref first, struct match_data *md) { dbref exit, absolute; const char *exitname, *p; int i, exitprog, lev, partial; if (first == NOTHING) return; /* Easy fail match */ if ((DBFETCH(md->match_from)->location) == NOTHING) return; absolute = absolute_name(md); /* parse #nnn entries */ if (!controls(OWNER(md->match_from), absolute)) absolute = NOTHING; DOLIST(exit, first) { if (exit == absolute) { md->exact_match = exit; continue; } exitprog = 0; if (FLAGS(exit) & HAVEN) { exitprog = 1; } else if (DBFETCH(exit)->sp.exit.dest) { for (i = 0; i < DBFETCH(exit)->sp.exit.ndest; i++) if (Typeof((DBFETCH(exit)->sp.exit.dest)[i]) == TYPE_PROGRAM) exitprog = 1; } if (tp_enable_prefix && exitprog && md->partial_exits && (FLAGS(exit) & XFORCIBLE) && FLAGS(OWNER(exit)) & WIZARD) { partial = 1; } else { partial = 0; } exitname = NAME(exit); while (*exitname) { /* for all exit aliases */ int notnull = 0; for (p = md->match_name; /* check out 1 alias */ *p && DOWNCASE(*p) == DOWNCASE(*exitname) && *exitname != EXIT_DELIMITER; p++, exitname++) { if (!isspace(*p)) { notnull = 1; } } /* did we get a match on this alias? */ if ((partial && notnull) || ((*p == '\0') || (*p == ' ' && exitprog))) { /* make sure there's nothing afterwards */ while (isspace(*exitname)) exitname++; lev = PLevel(exit); if (tp_compatible_priorities && (lev == 1) && (DBFETCH(exit)->location == NOTHING || Typeof(DBFETCH(exit)->location) != TYPE_THING || controls(OWNER(exit), getloc(md->match_from)))) lev = 2; if (*exitname == '\0' || *exitname == EXIT_DELIMITER) { /* we got a match on this alias */ if (lev >= md->match_level) { if (strlen(md->match_name) - strlen(p) > md->longest_match) { if (lev > md->match_level) { md->match_level = lev; md->block_equals = 0; } md->exact_match = exit; md->longest_match = strlen(md->match_name) - strlen(p); if ((*p == ' ') || (partial && notnull)) { strcpy(match_args, (partial && notnull)? p : (p + 1)); { char *pp; int ip; for (ip = 0, pp = (char *) md->match_name; *pp && (pp != p); pp++) match_cmdname[ip++] = *pp; match_cmdname[ip] = '\0'; } } else { *match_args = '\0'; strcpy(match_cmdname, (char *) md->match_name); } } else if ((strlen(md->match_name) - strlen(p) == md->longest_match) && !((lev == md->match_level) && (md->block_equals))) { if (lev > md->match_level) { md->exact_match = exit; md->match_level = lev; md->block_equals = 0; } else { md->exact_match = choose_thing(md->match_descr, md->exact_match, exit, md); } if (md->exact_match == exit) { if ((*p == ' ') || (partial && notnull)) { strcpy(match_args, (partial && notnull) ? p : (p + 1)); { char *pp; int ip; for (ip = 0, pp = (char *) md->match_name; *pp && (pp != p); pp++) match_cmdname[ip++] = *pp; match_cmdname[ip] = '\0'; } } else { *match_args = '\0'; strcpy(match_cmdname, (char *) md->match_name); } } } } goto next_exit; } } /* we didn't get it, go on to next alias */ while (*exitname && *exitname++ != EXIT_DELIMITER) ; while (isspace(*exitname)) exitname++; } /* end of while alias string matches */ next_exit: ; } } /* * match_invobj_actions * matches actions attached to objects in inventory */ void match_invobj_actions(struct match_data *md) { dbref thing; if (DBFETCH(md->match_from)->contents == NOTHING) return; DOLIST(thing, DBFETCH(md->match_from)->contents) { if (Typeof(thing) == TYPE_THING && DBFETCH(thing)->exits != NOTHING) { match_exits(DBFETCH(thing)->exits, md); } } } /* * match_roomobj_actions * matches actions attached to objects in the room */ void match_roomobj_actions(struct match_data *md) { dbref thing, loc; if ((loc = DBFETCH(md->match_from)->location) == NOTHING) return; if (DBFETCH(loc)->contents == NOTHING) return; DOLIST(thing, DBFETCH(loc)->contents) { if (Typeof(thing) == TYPE_THING && DBFETCH(thing)->exits != NOTHING) { match_exits(DBFETCH(thing)->exits, md); } } } /* * match_player_actions * matches actions attached to player */ void match_player_actions(struct match_data *md) { dbref obj; switch (Typeof(md->match_from)) { case TYPE_PLAYER: case TYPE_ROOM: case TYPE_THING: obj = DBFETCH(md->match_from)->exits; break; default: obj = NOTHING; break; } if (obj == NOTHING) return; match_exits(obj, md); } /* * match_room_exits * Matches exits and actions attached to player's current room. * Formerly 'match_exit'. */ void match_room_exits(dbref loc, struct match_data *md) { dbref obj; switch (Typeof(loc)) { case TYPE_PLAYER: case TYPE_ROOM: case TYPE_THING: obj = DBFETCH(loc)->exits; break; default: obj = NOTHING; break; } if (obj == NOTHING) return; match_exits(obj, md); } /* * match_all_exits * Matches actions on player, objects in room, objects in inventory, * and room actions/exits (in reverse order of priority order). */ void match_all_exits(struct match_data *md) { dbref loc; int limit = 88; strcpy(match_args, "\0"); strcpy(match_cmdname, "\0"); if ((loc = DBFETCH(md->match_from)->location) != NOTHING) match_room_exits(loc, md); if (md->exact_match != NOTHING) md->block_equals = 1; match_invobj_actions(md); if (md->exact_match != NOTHING) md->block_equals = 1; match_roomobj_actions(md); if (md->exact_match != NOTHING) md->block_equals = 1; match_player_actions(md); if (loc == NOTHING) return; /* if player is in a vehicle, use environment of vehicle's home */ if (Typeof(loc) == TYPE_THING) { loc = THING_HOME(loc); if (loc == NOTHING) return; if (md->exact_match != NOTHING) md->block_equals = 1; match_room_exits(loc, md); } while ((loc = DBFETCH(loc)->location) != NOTHING) { if (md->exact_match != NOTHING) md->block_equals = 1; match_room_exits(loc, md); if (!limit--) break; } } void match_everything(struct match_data *md) { match_all_exits(md); match_neighbor(md); match_possession(md); match_me(md); match_here(md); match_registered(md); if (Wizard(OWNER(md->match_from)) || Wizard(md->match_who)) { match_absolute(md); match_player(md); } } dbref match_result(struct match_data *md) { if (md->exact_match != NOTHING) { return (md->exact_match); } else { switch (md->match_count) { case 0: return NOTHING; case 1: return (md->last_match); default: return AMBIGUOUS; } } } /* use this if you don't care about ambiguity */ dbref last_match_result(struct match_data * md) { if (md->exact_match != NOTHING) { return (md->exact_match); } else { return (md->last_match); } } dbref noisy_match_result(struct match_data * md) { dbref match; switch (match = match_result(md)) { case NOTHING: notify(md->match_who, NOMATCH_MESSAGE); return NOTHING; case AMBIGUOUS: notify(md->match_who, AMBIGUOUS_MESSAGE); return NOTHING; default: return match; } } void match_rmatch(dbref arg1, struct match_data *md) { if (arg1 == NOTHING) return; switch (Typeof(arg1)) { case TYPE_PLAYER: case TYPE_ROOM: case TYPE_THING: match_list(DBFETCH(arg1)->contents, md); match_exits(DBFETCH(arg1)->exits, md); break; } }