#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