#include "copyright.h" #include "config.h" #include "interface.h" #include "mush.h" /* Routines for parsing arguments */ #include <ctype.h> #include "db.h" #include "params.h" #include "match.h" #include "externs.h" extern char *uppercase, *lowercase; #define DOWNCASE(x) (lowercase[x]) char match_args[BUFSIZ]; /* remaining text */ #ifdef PREP char match_cmdname[BUFFER_LEN]; /* triggering command */ #endif void init_match(dbref player, char *name, int type, match_data *md) { md->exact_match = md->last_match = NOTHING; md->match_count = 0; md->match_who = player; md->match_name = name; md->check_keys = 0; md->preferred_type = type; md->longest_match = 0; } void init_match_check_keys(dbref player, char *name, int type, match_data *md) { init_match(player, name, type, md); md->check_keys = 1; } static dbref choose_thing(dbref thing1, dbref thing2, 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(md->match_who, thing1); has2 = could_doit(md->match_who, thing2); if(has1 && !has2) return thing1; else if (has2 && !has1) return thing2; /* else fall through */ } return (random() % 2 ? thing1 : thing2); } #ifdef MUSH void match_controlled_absolute(match_data *md) { /* this exists to provide mortals with a way of controlling their objects * via dbref number, if they own the object. Unlike match_absolute(), * here, a control check is done. * alternatively, if the two objects are "nearby", the absolute * match also succeeds. This allows players to get out of situations * where there are several identically-named objects, and the game * refuses to allow them to pick one by anything other than number. */ dbref match; if (((match = absolute_name(md)) != NOTHING) && (controls(md->match_who, match) || nearby(md->match_who, match))) { md->exact_match = match; } } void match_nearby(match_data *md) { dbref loc; match_me(md); match_here(md); if (Wizard(md->match_who)) { match_absolute(md); match_player(md); } else match_controlled_absolute(md); if (match_result(md) == NOTHING) { match_neighbor(md); match_possession(md); if ((loc = DBFETCH(md->match_who)->location) != NOTHING) match_room_exits(loc, md); } } void match_near_things(match_data *md) { match_me(md); if (Wizard(md->match_who)) { match_absolute(md); match_player(md); } else match_controlled_absolute(md); if (match_result(md) == NOTHING) { match_neighbor(md); match_possession(md); } } void match_container(match_data *md) { dbref loc; loc = DBFETCH(md->match_who)->location; if (loc != NOTHING) match_list(loc, md); } #endif void match_player(match_data *md) { dbref match; char *p; if(*(md->match_name) == LOOKUP_TOKEN) { for(p = (md->match_name) + 1; isspace(*p); p++); if((match = lookup_player(p)) != NOTHING) md->exact_match = match; } } /* returns nnn if name = #nnn, else NOTHING */ dbref absolute_name(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(match_data *md) { dbref match; if((match = absolute_name(md)) != NOTHING) { md->exact_match = match; } } void match_me(match_data *md) { if(!string_compare(md->match_name, "me")) { md->exact_match = md->match_who; } } void match_here(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(match_data *md) { if (!string_compare(md->match_name, "home")) md->exact_match = HOME; } void match_list(dbref first, match_data *md) { dbref absolute; absolute = absolute_name(md); if(!controls(md->match_who, absolute)) absolute = NOTHING; DOLIST(first, first) { if(first == absolute) { md->exact_match = first; return; } else if(!string_compare(NAME(first), md->match_name)) { /* if there are multiple exact matches, randomly choose one */ md->exact_match = choose_thing(md->exact_match, first, md); } else if(string_match(NAME(first), md->match_name)) { md->last_match = first; (md->match_count)++; } } } void match_possession(match_data *md) { match_list(DBFETCH(md->match_who)->contents, md); } void match_neighbor(match_data *md) { dbref loc; if((loc = DBFETCH(md->match_who)->location) != NOTHING) { match_list(DBFETCH(loc)->contents, md); } } /* * match_exits matches a list of exits, starting with 'first'. * It is will match exits of players, rooms, or things. */ void match_exits(dbref thing, match_data *md) { dbref exit1, absolute; char *exitname, *p; int i,exitprog; if ((thing == NOTHING) || (DBFETCH(thing)->exits == NOTHING)) return; if ((DBFETCH(md->match_who)->location) == NOTHING) return; absolute = absolute_name(md); /* parse #nnn entries */ if (!controls(md->match_who, absolute)) absolute = NOTHING; DOLIST(exit1, DBFETCH(thing)->exits) { if (exit1 == absolute) { md->exact_match = exit1; for (p = (char *)md->match_name; p && (*p != ' '); p++); if (p) strcpy (match_args, p + 1); else *match_args = '\0'; continue; } if((Typeof(thing) == TYPE_PLAYER) && !(FLAGS(exit1) & JUMP_OK) && (md->match_who != thing) && (DBFETCH(md->match_who)->location != thing)) continue; exitprog = 0; if (DBFETCH(exit1)->sp.exit.dest) { for (i=0;i<DBFETCH(exit1)->sp.exit.ndest;i++) { if (Typeof((DBFETCH(exit1)->sp.exit.dest)[i]) == TYPE_PROGRAM) exitprog = 1; } } exitname = NAME(exit1); while (*exitname) /* for all exit aliases */ { for (p = (char *)md->match_name; /* check out 1 alias */ *p && DOWNCASE(*p) == DOWNCASE(*exitname) && *exitname != EXIT_DELIMITER; p++, exitname++); /* did we get a match on this alias? */ if (*p == '\0' || (*p == ' ' && exitprog)) { /* make sure there's nothing afterwards */ while (isspace(*exitname)) exitname++; if (*exitname == '\0' || *exitname == EXIT_DELIMITER) { /* we got a match on this alias */ if (strlen(md->match_name) - strlen(p) > md->longest_match) { md->exact_match = exit1; md->longest_match = strlen(md->match_name) - strlen(p); if (*p == ' ') { strcpy(match_args, p+1); #ifdef PREP { char *pp; int ip; for (ip = 0, pp = (char *) md->match_name; *pp && (pp != p); pp++) match_cmdname[ip++] = *pp; match_cmdname[ip] = '\0'; } #endif } else { *match_args = '\0'; #ifdef PREP strcpy(match_cmdname, (char *) md->match_name); #endif } } else if (strlen(md->match_name) - strlen(p) == md->longest_match) { md->exact_match = choose_thing(md->exact_match, exit1, md); if (md->exact_match == exit1) { if (*p == ' ') { strcpy(match_args, p + 1); #ifdef PREP { char *pp; int ip; for (ip = 0, pp = (char *) md->match_name; *pp && (pp != p); pp++) match_cmdname[ip++] = *pp; match_cmdname[ip] = '\0'; } #endif } else { *match_args = '\0'; #ifdef PREP *match_cmdname = '\0'; #endif } } } 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_room_exits * Matches exits and actions attached to player's current room. * Formerly 'match_exit'. */ void match_room_exits(dbref loc, match_data *md) { if (DBFETCH(loc)->exits != NOTHING) match_exits(loc, md); } /* * match_invobj_actions * matches actions attached to objects in inventory */ void match_invobj_actions(match_data *md) { dbref thing; if (DBFETCH(md->match_who)->contents == NOTHING) return; DOLIST(thing, DBFETCH(md->match_who)->contents) { match_exits(thing, md); } } /* * match_roomobj_actions * matches actions attached to objects in the room */ void match_roomobj_actions(match_data *md) { dbref thing, loc; if ((loc = DBFETCH(md->match_who)->location) == NOTHING) return; if (DBFETCH(loc)->contents == NOTHING) return; DOLIST(thing, DBFETCH(loc)->contents) { if (Typeof(thing) != TYPE_ROOM) match_exits(thing, md); } } /* * match_player_actions * matches actions attached to player */ void match_player_actions(match_data *md) { if (Typeof(md->match_who) != TYPE_PLAYER) return; match_exits(md->match_who, 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(match_data *md) { dbref loc; strcpy(match_args, "\0"); #ifdef PREP strcpy(match_cmdname, "\0"); #endif if ((loc = DBFETCH(md->match_who)->location) != NOTHING) match_room_exits(loc, md); if (md->exact_match == NOTHING) match_invobj_actions(md); if (md->exact_match == NOTHING) match_roomobj_actions(md); if (md->exact_match == NOTHING) match_player_actions(md); #ifdef MUSH if(Typeof(loc) == TYPE_ROOM && find_property(loc, "LALIAS", ACCESS_WI)) loc = DBFETCH(loc)->location; #endif while (md->exact_match == NOTHING && (loc = DBFETCH(loc)->location) != NOTHING) match_room_exits(loc, md); if ((md->exact_match == NOTHING) && (Wizard(md->match_who))) match_absolute(md); } void match_everything(match_data *md) { match_all_exits(md); match_neighbor(md); match_possession(md); match_me(md); match_here(md); match_absolute(md); match_player(md); } dbref match_result(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(match_data *md) { if(md->exact_match != NOTHING) return (md->exact_match); else return (md->last_match); } dbref noisy_match_result(match_data *md) { dbref match; switch(match = match_result(md)) { case NOTHING: notify(md->match_who, md->match_who, NOMATCH_MESSAGE); return NOTHING; case AMBIGUOUS: notify(md->match_who, md->match_who, AMBIGUOUS_MESSAGE); return NOTHING; default: return match; } } void match_rmatch(dbref arg1, match_data *md) { if (arg1 == NOTHING) return; match_list(DBFETCH(arg1)->contents, md); match_exits(arg1, md); } #ifdef PREP dbref find_registered_obj(dbref player, char *name); /* returns dbref if registered object found for name, else NOTHING */ dbref find_registered_obj(dbref player, char *name) { dbref match; char *p; char buf[BUFFER_LEN]; if (*name != REGISTERED_TOKEN) return (NOTHING); for (p = name + 1; *p && isspace(*p); p++); if (!*p) return (NOTHING); sprintf(buf, "_reg/%s", p); if ((p = (char *) envpropstr(&player, buf))) { if (*p == '#') p++; match = (dbref) atoi(p); if ((match > 0) && (match < db_top) && (Typeof(match) != TYPE_GARBAGE)) return (match); } return (NOTHING); } void match_registered(struct match_data * md) { dbref match; match = find_registered_obj(md->match_who, md->match_name); if (match != NOTHING) md->exact_match = match; } #endif