/* $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;
}
}