/* $Header: match.c,v 1.1 90/04/14 14:56:46 lachesis Exp $
* $Log: match.c,v $
* Revision 1.1 90/04/14 14:56:46 lachesis
* Initial revision
*
*/
#include "copyright.h"
/* Routines for parsing arguments */
#include "os.h"
#include "db.h"
#include "config.h"
#include "match.h"
#include "externs.h"
#include "interface.h"
#define DOWNCASE(x) (isupper(x) ? tolower(x) : (x))
static dbref exact_match = NOTHING; /* holds result of exact match */
static int check_keys = 0; /* if non-zero, check for keys */
static dbref last_match = NOTHING; /* holds result of last match */
static int match_count; /* holds total number of inexact matches */
static dbref match_who; /* player who is being matched around */
static const char *match_name; /* name to match */
static int preferred_type = NOTYPE; /* preferred type */
void init_match (dbref player, const char *name, int type)
{
exact_match = last_match = NOTHING;
match_count = 0;
match_who = player;
match_name = name;
check_keys = 0;
preferred_type = type;
}
void init_match_check_keys (dbref player, const char *name, int type)
{
init_match (player, name, type);
check_keys = 1;
}
static dbref choose_thing (dbref thing1, dbref thing2)
{
int has1;
int has2;
if (thing1 == NOTHING) {
return thing2;
} else if (thing2 == NOTHING) {
return thing1;
}
if (preferred_type != NOTYPE) {
if (Typeof (thing1) == preferred_type) {
if (Typeof (thing2) != preferred_type) {
return thing1;
}
} else if (Typeof (thing2) == preferred_type) {
return thing2;
}
}
if (check_keys) {
has1 = could_doit (match_who, thing1);
has2 = could_doit (match_who, thing2);
if (has1 && !has2) {
return thing1;
} else if (has2 && !has1) {
return thing2;
}
/* else fall through */
}
return (OS_RAND () % 2 ? thing1 : thing2);
}
void match_player (void)
{
dbref match;
const char *p;
if (*match_name == LOOKUP_TOKEN && payfor (match_who, LOOKUP_COST)) {
for (p = match_name + 1; isspace (*p); p++)
/*EMPTY*/;
if ((match = lookup_player (p)) != NOTHING) {
exact_match = match;
}
}
}
/* returns nnn if name = #nnn, else NOTHING */
static dbref absolute_name (void)
{
dbref match;
if (*match_name == NUMBER_TOKEN) {
match = parse_dbref (match_name + 1);
if (match < 0 || match >= db_top) {
return NOTHING;
} else {
return match;
}
} else {
return NOTHING;
}
}
void match_absolute (void)
{
dbref match;
if ((match = absolute_name ()) != NOTHING) {
exact_match = match;
}
}
void match_me (void)
{
if (!string_compare (match_name, "me")) {
exact_match = match_who;
}
}
void match_home (void)
{
if (!string_compare (match_name, "home")) {
exact_match = HOME;
}
}
void match_here (void)
{
if (!string_compare (match_name, "here")
&& db[match_who].location != NOTHING) {
exact_match = db[match_who].location;
}
}
static void match_list (dbref first)
{
dbref absolute;
absolute = absolute_name ();
if (!controls (match_who, absolute))
absolute = NOTHING;
DOLIST (first, first) {
if (first == absolute) {
exact_match = first;
return;
} else if (!string_compare (db[first].name, match_name)) {
/* if there are multiple exact matches, randomly choose one */
exact_match = choose_thing (exact_match, first);
} else if (string_match (db[first].name, match_name) != NULL) {
last_match = first;
match_count++;
}
}
}
void match_possession (void)
{
match_list (db[match_who].contents);
}
void match_neighbor (void)
{
dbref loc;
if ((loc = db[match_who].location) != NOTHING) {
match_list (db[loc].contents);
}
}
/*
* 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)
{
dbref exit, absolute;
const char *exitname, *p;
if (first == NOTHING)
return; /* Easy fail match */
if ((db[match_who].location) == NOTHING)
return;
absolute = absolute_name (); /* parse #nnn entries */
if (!controls (match_who, absolute))
absolute = NOTHING;
DOLIST (exit, first) {
if (exit == absolute) {
exact_match = exit;
continue;
}
exitname = db[exit].name;
while (*exitname) { /* for all exit aliases */
for (p = match_name; /* check out 1 alias */
*p && DOWNCASE (*p) == DOWNCASE (*exitname)
&& *exitname != EXIT_DELIMITER; p++, exitname++)
/*EMPTY*/;
/* did we get a match on this alias? */
if (*p == '\0') {
/* make sure there's nothing afterwards */
while (isspace (*exitname))
exitname++;
if (*exitname == '\0' || *exitname == EXIT_DELIMITER) {
/* we got a match on this alias */
exact_match = choose_thing (exact_match, exit);
goto next_exit;
}
}
/* we didn't get it, go on to next alias */
while (*exitname && *exitname++ != EXIT_DELIMITER)
/*EMPTY*/;
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 (void)
{
dbref loc;
if ((loc = db[match_who].location) == NOTHING)
return;
if (Typeof (loc) != TYPE_ROOM)
return;
if (db[loc].sp.room.exits != NOTHING) {
match_exits (db[loc].sp.room.exits);
}
}
/*
* match_invobj_actions
* matches actions attached to objects in inventory
*/
void match_invobj_actions (void)
{
dbref thing;
if (db[match_who].contents == NOTHING)
return;
DOLIST (thing, db[match_who].contents) {
if (Typeof (thing) == TYPE_THING && db[thing].sp.thing.actions != NOTHING) {
match_exits (db[thing].sp.thing.actions);
}
}
}
/*
* match_roomobj_actions
* matches actions attached to objects in the room
*/
void match_roomobj_actions (void)
{
dbref thing, loc;
if ((loc = db[match_who].location) == NOTHING)
return;
if (db[loc].contents == NOTHING)
return;
DOLIST (thing, db[loc].contents) {
if (Typeof (thing) == TYPE_THING && db[thing].sp.thing.actions != NOTHING) {
match_exits (db[thing].sp.thing.actions);
}
}
}
/*
* match_player_actions
* matches actions attached to player
*/
void match_player_actions (void)
{
if (db[match_who].sp.player.actions == NOTHING)
return;
match_exits (db[match_who].sp.player.actions);
}
/*
* 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 (void)
{
match_roomobj_actions ();
match_invobj_actions ();
match_player_actions ();
match_room_exits ();
}
void match_everything (void)
{
match_all_exits ();
match_neighbor ();
match_possession ();
match_me ();
match_here ();
if (Wizard (match_who)) {
match_absolute ();
match_player ();
}
}
dbref match_result (void)
{
if (exact_match != NOTHING) {
return exact_match;
} else {
switch (match_count) {
case 0:
return NOTHING;
case 1:
return last_match;
default:
return AMBIGUOUS;
}
}
}
/* use this if you don't care about ambiguity */
dbref last_match_result (void)
{
if (exact_match != NOTHING) {
return exact_match;
} else {
return last_match;
}
}
dbref noisy_match_result (void)
{
dbref match;
switch (match = match_result ()) {
case NOTHING:
notify (match_who, NOMATCH_MESSAGE);
return NOTHING;
case AMBIGUOUS:
notify (match_who, AMBIGUOUS_MESSAGE);
return NOTHING;
default:
return match;
}
}