/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/match.c,v 1.8 90/09/18 08:00:31 rearl Exp $ */ /* * $Log: match.c,v $ * Revision 1.8 90/09/18 08:00:31 rearl * Changed upper/lowercase lookup. * * Revision 1.7 90/09/16 04:42:29 rearl * Preparation code added for disk-based MUCK. * * Revision 1.6 90/09/05 02:33:24 rearl * Fixed room exit matching so everything in the room is checked before * checking parent rooms. * * Revision 1.5 90/08/27 03:31:25 rearl * Added environment support. * * Revision 1.4 90/08/11 04:05:55 rearl * *** empty log message *** * * Revision 1.3 90/08/05 03:19:41 rearl * Redid matching routines. * * Revision 1.2 90/07/29 17:40:53 rearl * match_rmatch (for MUF programs) checks exits/actions on * rooms/players/objects. * * Revision 1.1 90/07/19 23:03:54 casie * Initial revision * * */ #include "copyright.h" #include "config.h" /* Routines for parsing arguments */ #include <ctype.h> #include "db.h" #include "params.h" #include "match.h" #define DOWNCASE(x) (lowercase[x]) char match_args[BUFSIZ]; /* remaining text */ void init_match(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_name = name; md -> check_keys = 0; md -> preferred_type = type; md -> longest_match = 0; } void init_match_check_keys(dbref player, const char *name, int type, struct match_data *md) { init_match(player, name, type, md); md -> check_keys = 1; } static dbref choose_thing(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(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); } void match_player(struct match_data *md) { dbref match; const char *p; if(*(md -> match_name) == LOOKUP_TOKEN && payfor(md -> match_who, LOOKUP_COST)) { 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 */ 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(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)) { if(md->last_match != first) { /* 4 people inside themselves. */ md -> last_match = first; (md -> match_count)++; } } } } void match_possession(struct match_data *md) { match_list(DBFETCH(md -> match_who)->contents, md); } void match_neighbor(struct 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 first, struct match_data *md) { dbref exit, absolute; const char *exitname, *p; int i,exitprog; if (first == NOTHING) return; /* Easy fail match */ if ((DBFETCH(md -> match_who)->location) == NOTHING) return; absolute = absolute_name(md); /* parse #nnn entries */ if (!controls(md -> match_who, absolute)) absolute = NOTHING; DOLIST(exit, first) { if((md->exact_match==NOTHING)) { if (exit == absolute) { md -> exact_match = exit; continue; } exitprog = 0; 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; exitname = NAME(exit); while (*exitname) { /* for all exit aliases */ for (p = 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 = exit; md -> longest_match = strlen(md -> match_name)-strlen(p); if (*p == ' ') strcpy(match_args, p+1); else *match_args = '\0'; } else if (strlen(md -> match_name)-strlen(p) == md -> longest_match) { md -> exact_match = choose_thing(md -> exact_match, exit, md); if (md -> exact_match == exit) if (*p == ' ') strcpy(match_args, p+1); else *match_args = '\0'; } 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, struct match_data *md) { if (Typeof(loc) != TYPE_ROOM) return; if (DBFETCH(loc)->exits != NOTHING) match_exits(DBFETCH(loc)->exits, md); } /* * match_invobj_actions * matches actions attached to objects in inventory */ void match_invobj_actions(struct match_data *md) { dbref thing; if (DBFETCH(md -> match_who)->contents == NOTHING) return; DOLIST(thing, DBFETCH(md -> match_who)->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_who)->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) { if (DBFETCH(md -> match_who)->exits == NOTHING) return; match_exits(DBFETCH(md -> match_who)->exits, 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 x=0; strcpy(match_args, "\0"); 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); if(Typeof(loc)!=TYPE_ROOM) loc=DBFETCH(GLOBAL_ENVIRONMENT)->contents; /* Eewww.. */ while ((loc = DBFETCH(loc)->location) != NOTHING) { if(x++>30) loc=GLOBAL_ENVIRONMENT; /* a loop.. get out of it. */ match_room_exits(loc, md); } } void match_everything(struct match_data *md) { match_all_exits(md); match_neighbor(md); match_possession(md); match_me(md); match_here(md); /* if(Wizard(md -> match_who)||(Cont(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: match_list(DBFETCH(arg1)->contents, md); match_exits(DBFETCH(arg1)->exits, md); break; case TYPE_ROOM: match_list(DBFETCH(arg1)->contents, md); match_exits(DBFETCH(arg1)->exits, md); break; case TYPE_THING: match_exits(DBFETCH(arg1)->exits, md); match_list(DBFETCH(arg1)->contents,md); break; } }