/
2.0.5/doc/
2.0.5/gnu/
2.0.5/sha/
/* match.c */

#include "config.h"

/*
 *		       This file is part of TeenyMUD II.
 *		 Copyright(C) 1993, 1994, 1995 by Jason Downs.
 *                           All rights reserved.
 * 
 * TeenyMUD II is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * TeenyMUD II is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file 'COPYING'); if not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif			/* HAVE_STDLIB_H */
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif			/* HAVE_STRING_H */
#include <ctype.h>

#include "conf.h"
#include "teeny.h"
#include "ptable.h"
#include "externs.h"

/* new TeenyMUD matching library. */

static int match_token _ANSI_ARGS_((char *, char *));
static int match_exname _ANSI_ARGS_((char *, char *));
static int choose_match _ANSI_ARGS_((int, int, int, int, int));

/* match list struct. */
struct mat_list {
  int obj;

  struct mat_list *next;
};

static struct mat_list *mlist = (struct mat_list *)NULL;
static struct mat_list *mcurr = (struct mat_list *)NULL;

#define MATVAL_EXACT	8192

/* match for tokens within a string. */
/* returns the 'value' of the match. */
static int match_token(substr, str)
    register char *substr, *str;
{
  register int mat_len;

  if(*substr) {
    /* special exact match check. */
    if(strcasecmp(substr, str) == 0)
      return(MATVAL_EXACT);

    while(*str) {
      if((mat_len = stringprefix(str, substr)))
        return(mat_len);
      while(*str && !isspace(*str))
        str++;
      while(*str && isspace(*str))
        str++;
    }
  }
  return(0);
}

/* match for tokens within a string, exit wise. */
/* returns the 'value' of the match. */
static int match_exname(substr, str)
    char *substr;
    register char *str;
{
  register int mat_len;
  register char *ptr;

  while(*str) {
    ptr = substr;
    mat_len = 0;

    /* trim leading spaces first. */
    while(*str && isspace(*str))
      str++;
    /* if we run out here, we loose. */
    if(*str == '\0')
      break;

    while(*ptr && (to_lower(*str) == to_lower(*ptr)) && (*str != ';')) {
      str++;
      ptr++;
      mat_len++;
    }
    /* did we match? */
    if(*ptr == '\0') {
      while(*str && isspace(*str))
        str++;
      if((*str == '\0') || (*str == ';'))
        return(mat_len);
    }
    /* nope, skip to next word. */
    while(*str && (*str != ';'))
      str++;
    while(*str && (*str == ';'))
      str++;
  }
  return(0);
}

/* choose between two equal matches. */
/* returns the better match, or picks at random. */
static int choose_match(player, cause, match1, match2, flags)
    int player, cause, match1, match2, flags;
{
  int lock1, lock2;
  int type1, type2;

  /* make sure they're both valid. */
  if(!exists_object(match1)) {
    return(match2);
  } else if(!exists_object(match2)) {
    return(match1);
  }

  type1 = Typeof(match1);
  type2 = Typeof(match2);
  /* check types. */
  if(!(flags & MAT_ANYTHING)) {
    if(Typeof(match1) != Typeof(match2)){
      /* see if there's a prefered type. */
      if(flags & MAT_THINGS) {
        if((type1 == TYP_THING) && (type2 != TYP_THING)) {
	  return(match1);
	} else if((type2 == TYP_THING) && (type1 != TYP_THING)) {
	  return(match2);
	}
      } else if(flags & MAT_PLAYERS) {
        if((type1 == TYP_PLAYER) && (type2 != TYP_PLAYER)) {
	  return(match1);
	} else if((type2 == TYP_PLAYER) && (type1 != TYP_PLAYER)) {
	  return(match2);
	}
      } else if(flags & MAT_EXITS) {
        if((type1 == TYP_EXIT) && (type2 != TYP_EXIT)) {
	  return(match1);
	} else if((type2 == TYP_EXIT) && (type1 != TYP_EXIT)) {
	  return(match2);
	}
      }
    }
  }

  /* check locks. */
  if(flags & MAT_LOCKS) {
    lock1 = islocked(player, cause, match1, LOCK);
    lock2 = islocked(player, cause, match2, LOCK);

    if(!lock1 && lock2) {
      return(match1);
    } else if(!lock2 && lock1) {
      return(match2);
    }
  }

  /* if all else fails... */
  return((random() % 2) ? match1 : match2);
}

static int best_match, best_value;

/* match within a contents list. */
int match_contents(player, cause, str, list, flags)
    int player, cause;
    char *str;
    int list, flags;
{
  int curr_value, aflags;
  char *name, *alias;

  best_match = -1;
  best_value = 0;

  while(list != -1) {
    if(get_str_elt(list, NAME, &name) != -1) {
      if((curr_value = match_token(str, name))) {
        /* decide what to do with it */
	if(curr_value > best_value) {
	  best_match = list;
	  best_value = curr_value;
	} else if(curr_value == best_value) {
	  best_match = choose_match(player, cause, best_match, list, flags);
	}
      }
    } else
      logfile(LOG_ERROR, "match_contents: bad name on object #%d\n", list);

    if((flags & MAT_PLAYERS) && isPLAYER(list)) {
      if(attr_get(list, ALIAS, &alias, &aflags) != -1) {
	if((alias != (char *)NULL) && alias[0]
	   && (curr_value = match_token(str, alias))) {
	  /* decide what to do with it */
	  if(curr_value > best_value) {
	    best_match = list;
	    best_value = curr_value;
	  } else if(curr_value == best_value) {
	    best_match = choose_match(player, cause, best_match, list, flags);
	  }
	}
      } else
	logfile(LOG_ERROR, "match_contents: bad name on object #%d\n", list);
    }

    if(get_int_elt(list, NEXT, &list) == -1) {
      logfile(LOG_ERROR, "match_contents: bad next element on object #%d\n",
	      list);
      break;
    }
  }
  return(best_match);
}

/* match within an exits list. */
int match_exits(player, cause, str, list, flags)
    int player, cause;
    char *str;
    int list, flags;
{
  int curr_value;
  char *name;

  best_match = -1;
  best_value = 0;

  while(list != -1) {
    if(get_str_elt(list, NAME, &name) != -1) {
      if(((flags & MAT_EXTERNAL) && isEXTERNAL(list)) ||
      	 ((flags & MAT_INTERNAL) && !isEXTERNAL(list))) {
        if((curr_value = match_exname(str, name))) {
          /* decide what to do with it */
          if(curr_value > best_value) {
            best_match = list;
            best_value = curr_value;
          } else if(curr_value == best_value) {
            best_match = choose_match(player, cause, best_match, list, flags);
          }
        }
      }
    } else
      logfile(LOG_ERROR, "match_exits: bad name on object #%d\n", list);
    if(get_int_elt(list, NEXT, &list) == -1) {
      logfile(LOG_ERROR, "match_exits: bad next element on object #%d\n", list);
      break;
    }
  }
  return(best_match);
}

/* regexp match utilities. */
int match_first()
{
  mcurr = mlist;

  if(mcurr == (struct mat_list *)NULL)
    return(-1);
  return(mcurr->obj);
}

int match_next()
{
  if((mcurr == (struct mat_list *)NULL)
     || (mcurr->next == (struct mat_list *)NULL))
    return(-1);

  mcurr = mcurr->next;
  return(mcurr->obj);
}

void match_free()
{
  struct mat_list *mnext;

  for(mcurr = mlist; mcurr != (struct mat_list *)NULL; mcurr = mnext) {
    mnext = mcurr->next;

    ty_free((VOID *)mcurr);
  }
  mlist = (struct mat_list *)NULL;
}

/* wrapper for all of the above. */
int match_here(player, cause, where, str, flags)
    int player, cause, where;
    char *str;
    int flags;
{
  int list, location;
  int match = -1;
  char *ptr;

  /* check 'me' and 'here' first. */
  if((get_int_elt(player, LOC, &location) != -1) && exists_object(location)){
    if((where == location) && (strcasecmp(str, "me") == 0)) {
      return(player);
    } else if(strcasecmp(str, "here") == 0) {
      return(location);
    }
  } else {
    logfile(LOG_ERROR, "match_here: bad location on object #%d\n", player);
    return(-1);
  }

  /* check absolute number next. */
  if(str[0] == '#') {
    match = (int)strtol(&str[1], &ptr, 10);
    if ((ptr != &str[1]) && exists_object(match)) {
      if(get_int_elt(match, LOC, &location) == -1) {
        logfile(LOG_ERROR, "match_here: bad location on object #%d\n", match);
	return(-1);
      }
      if(location == where) {
        switch(Typeof(match)) {
	case TYP_THING:
	  if(flags & MAT_THINGS)
	    return(match);
	case TYP_PLAYER:
	  if(flags & MAT_PLAYERS)
	    return(match);
	case TYP_EXIT:
	  if(flags & MAT_EXITS)
	    return(match);
	}
      }
    }
  }

  if(flags & MAT_EXITS) {
    if(get_int_elt(where, EXITS, &list) != -1) {
      if((match = match_exits(player, cause, str, list, flags)) != -1)
        return(match);
    } else {
      logfile(LOG_ERROR, "match_here: bad exits list on object #%d\n", where);
      return(-1);
    }
  }
  if((flags & MAT_THINGS) || (flags & MAT_PLAYERS)) {
    if(get_int_elt(where, CONTENTS, &list) != -1) {
      if((match = match_contents(player, cause, str, list, flags)) != -1)
        return(match);
    } else {
      logfile(LOG_ERROR, "match_here: bad contents list on object #%d\n",
	      where);
      return(-1);
    }
  }
  return(-1);
}

/* this is what we have to do to match an exit 'command'. */
int match_exit_command(player, cause, cmd)
    int player, cause;
    char *cmd;
{
  int match, here, list, contents, parent;
  int last_match, last_value;

  /* check for EXTERNAL exits on player. */
  if(get_int_elt(player, EXITS, &list) != -1){
    match = match_exits(player, cause, cmd, list, MAT_EXTERNAL|MAT_LOCKS);
    if(match != -1)
      return(match);
  } else {
    logfile(LOG_ERROR, "match_exit_command: bad exits list on object #%d\n",
	    player);
    return(-1);
  }

  /* check for EXTERNAL exits on inventory. */
  if(get_int_elt(player, CONTENTS, &contents) != -1) {
    last_match = -1;
    last_value = 0;

    while(contents != -1){
      if(!isPLAYER(contents) && (contents != player)){
        if(get_int_elt(contents, EXITS, &list) == -1) {
	  logfile(LOG_ERROR,
		  "match_exit_command: bad exits list on object #%d\n",
	  	  contents);
	  return(-1);
	}
        match = match_exits(player, cause, cmd, list, 
			    MAT_EXTERNAL|MAT_LOCKS|MAT_EXITS);
	if(match != -1) {
	  if(best_value > last_value) {
	    last_value = best_value;
	    last_match = match;
	  } else if(best_value == last_value) {
	    last_match = choose_match(player, cause, last_match, match,
	    			      MAT_EXTERNAL|MAT_LOCKS|MAT_EXITS);
	  }
	}
      }
      if(get_int_elt(contents, NEXT, &contents) == -1) {
        logfile(LOG_ERROR,
		"match_exit_command: bad next element on object #%d\n",
	    	contents);
	return(-1);
      }
    }
    if(last_match != -1)
      return(last_match);
  } else {
    logfile(LOG_ERROR, "match_exit_command: bad contents list on object #%d\n",
	    player);
    return(-1);
  }

  /* check for exits on location. */
  if((get_int_elt(player, LOC, &here) != -1) && exists_object(here)){
    if(get_int_elt(here, EXITS, &list) == -1) {
      logfile(LOG_ERROR, "match_exit_command: bad exits list on object #%d\n",
	      here);
      return(-1);
    }
    match = match_exits(player, cause, cmd, list,
    			isROOM(here) ? MAT_EXTERNAL|MAT_INTERNAL|MAT_LOCKS :
			MAT_INTERNAL|MAT_LOCKS);
    if(match != -1)
      return(match);
  } else {
    logfile(LOG_ERROR, "match_exit_command: bad location on object #%d\n",
	    player);
    return(-1);
  }

  /* check for EXTERNAL exits on contents. */
  if(get_int_elt(here, CONTENTS, &contents) == -1) {
    logfile(LOG_ERROR, "match_exit_command: bad contents list on object #%d\n",
	    player);
    return(-1);
  }
  last_match = -1;
  last_value = 0;
  while(contents != -1) {
    if(!isPLAYER(contents) && (contents != player)) {
      if(get_int_elt(contents, EXITS, &list) == -1) {
        logfile(LOG_ERROR, "match_exit_command: bad exits list on object #%d\n",
		contents);
	return(-1);
      }
      match = match_exits(player, cause, cmd, list,
                	  MAT_EXTERNAL|MAT_LOCKS|MAT_EXITS);
      if(match != -1) {
        if(best_value > last_value) {
          last_value = best_value;
          last_match = match;
        } else if(best_value == last_value) {
          last_match = choose_match(player, cause, last_match, match,
                                    MAT_EXTERNAL|MAT_LOCKS|MAT_EXITS);
        }
      }
    }
    if(get_int_elt(contents, NEXT, &contents) == -1) {
      logfile(LOG_ERROR, "match_exit_command: bad next element on object #%d\n",
      	      contents);
      return(-1);
    }
  }
  if(last_match != -1)
    return(last_match);

  /* check room locations. */
  if(isROOM(here)) {
    register int depth = 0;

    parent = here;
    do {
      if (get_int_elt(parent, LOC, &parent) == -1) {
        logfile(LOG_ERROR, "match_exit_command: bad parent ref on #%d\n",
		parent);
        return (-1);
      }
      if (get_int_elt(parent, EXITS, &list) == -1) {
        logfile(LOG_ERROR, "match_exit_command: bad exit ref on #%d\n", parent);
        return (-1);
      }
      match = match_exits(player, cause, cmd, list,
			  MAT_INTERNAL|MAT_LOCKS);
      if(match != -1)
	return(match);
      depth++;
    } while((depth <= mudconf.room_depth)
    	    && (parent != mudconf.root_location));
  } else {
    if(get_int_elt(mudconf.root_location, EXITS, &list) == -1) {
      logfile(LOG_ERROR, "match_exit_command: bad exits list on ROOT!\n");
      return(-1);
    }
    match = match_exits(player, cause, cmd, list,
			MAT_INTERNAL|MAT_LOCKS);
    if(match != -1)
      return(match);
  }
  return(-1);
}

static void resolve_mesg _ANSI_ARGS_((int, int, int, int));

/* display the appropiate message. */
static void resolve_mesg(player, cause, match, type)
    int player, cause, match, type;
{
  switch(type){
  case TYP_PLAYER:
    switch(match){
    case -1:
      notify_player(player, cause, player,
      		    "I don't see that player here.", NOT_QUIET);
      break;
    case -2:
      notify_player(player, cause, player, 
		    "I can't tell which player you mean.", NOT_QUIET);
      break;
    }
    break;
  case TYP_EXIT:
    switch(match){
    case -1:
      notify_player(player, cause, player,
      		    "I don't see that exit here.", NOT_QUIET);
      break;
    case -2:
      notify_player(player, cause, player,
		    "I can't tell which exit you mean.", NOT_QUIET);
      break;
    }
    break;
  case TYP_ROOM:
    switch(match){
    case -1:
      notify_player(player, cause, player,
      		    "I don't see that room here.", NOT_QUIET);
      break;
    case -2:
      notify_player(player, cause, player,
		    "I can't tell which room you mean.", NOT_QUIET);
      break;
    }
    break;
  default:
    switch(match){
    case -1:
      notify_player(player, cause, player,
      		    "I don't see that here.", NOT_QUIET);
      break;
    case -2:
      notify_player(player, cause, player, 
		    "I can't tell which one you mean.", NOT_QUIET);
      break;
    }
    break;
  }
}

#define domesg(_x)	((_x & RSLV_NOISY) && !(_x & RSLV_RECURSE))

int resolve_object(player, cause, name, flags)
    int player, cause;
    char *name;
    int flags;
{
  int location, list;
  register int matched;
  register int curr_match = -1;
  register int curr_value = 0;
  char *ptr;

  if ((name == (char *)NULL) || (name[0] == '\0')) {
    if (domesg(flags))
      notify_player(player, cause, player,
      		    "I don't see that here.", NOT_QUIET);
    return (-1);		/* no match */
  }
  if ((*name == '#') && isdigit(name[1])) {
    name++;
    matched = (int)strtol(name, &ptr, 10);
    if(ptr == name)
      return(-1);

    if (exists_object(matched) && ((!(flags & RSLV_EXITS)
			 && !isEXIT(matched)) || (flags & RSLV_EXITS))) {
      return (matched);
    } else {
      if (domesg(flags))
	notify_player(player, cause, player,
		      "I don't see that here.", NOT_QUIET);
      return (-1);
    }
  }

  /* Check these first.  Don't want to confuse these. */
  if (strcasecmp("me", name) == 0)
    return (player);
  if ((get_int_elt(player, LOC, &location) == -1)
      || !exists_object(location)) {
    logfile(LOG_ERROR, "resolve_object: couldn't get location of player #%d\n",
	    player);
    if (domesg(flags))
      notify_player(player, cause, player, "You have no location!", NOT_QUIET);
    return (-1);
  }
  if (strcasecmp("here", name) == 0)
    return (location);
  if ((flags & RSLV_HOME) && (strcasecmp("home", name) == 0))
    return (-3);

  /* match player's inventory first. objects now take precedence over exits. */
  if(get_int_elt(player, CONTENTS, &list) == -1) {
    logfile(LOG_ERROR, "resolve_object: bad contents list on object #%d\n",
	    player);
    if(domesg(flags))
      resolve_mesg(player, cause, curr_match, -1);
    return(curr_match);
  }
  matched = match_contents(player, cause, name, list, MAT_THINGS|MAT_PLAYERS);
  if(best_value > curr_value) {
    curr_match = matched;
    curr_value = best_value;
  }
  if(get_int_elt(player, EXITS, &list) == -1) {
    logfile(LOG_ERROR, "resolve_object: bad exits list on object #%d\n",
	    player);
    if(domesg(flags))
      resolve_mesg(player, cause, curr_match, -1);
    return(curr_match);
  }
  matched = match_exits(player, cause, name, list,
  			MAT_EXITS|MAT_INTERNAL|MAT_EXTERNAL);
  if(best_value > curr_value) {
    curr_match = matched;
    curr_value = best_value;
  }

  /* match location things. */
  if(get_int_elt(location, CONTENTS, &list) == -1) {
    logfile(LOG_ERROR, "resolve_object: bad contents list on object #%d\n",
	    location);
    if(domesg(flags))
      resolve_mesg(player, cause, curr_match, -1);
    return(curr_match);
  }
  matched = match_contents(player, cause, name, list, MAT_THINGS);
  if(best_value > curr_value) {
    curr_match = matched;
    curr_value = best_value;
  }

  /* match location players. */
  matched = match_contents(player, cause, name, list, MAT_PLAYERS);
  if(best_value > curr_value) {
    curr_match = matched;
    curr_value = best_value;
  }

  /* match location exits. */
  if(flags & RSLV_EXITS) {
    if(get_int_elt(location, EXITS, &list) == -1) {
      logfile(LOG_ERROR, "resolve_object: bad exits list on object #%d\n",
	      location);
      if(domesg(flags))
        resolve_mesg(player, cause, curr_match, -1);
      return(curr_match);
    }
    matched = match_exits(player, cause, name, list,
    			  MAT_EXITS|MAT_INTERNAL|MAT_EXTERNAL);
    if(best_value > curr_value){
      curr_match = matched;
      curr_value = best_value;
    }
  }

  if (curr_match == -1) {
    switch (name[0]) {
    case '*':
      if ((flags & RSLV_SPLATOK) || isWIZARD(player)) {
	name++;
	if (exists_object((matched = match_active_player(name)))) {
	  curr_match = matched;
	} else {
	  curr_match = match_player(name);
	}
      } else
	curr_match = -1;
      break;
    case '@':
      if (flags & RSLV_ATOK) {
        name++;

        matched = match_active_player(name);
	if(!exists_object(matched))
	  matched = match_player(name);
	if(!exists_object(matched))
	  matched = resolve_object(player, cause, name,
				   ((flags & ~RSLV_ATOK)|RSLV_RECURSE));
	if(exists_object(matched)) {
	  int nmat;

	  if(get_int_elt(matched, LOC, &nmat) == -1) {
	    logfile(LOG_ERROR, "resolve_object: bad location on object #%d\n",
	    	    matched);
	    if(domesg(flags))
	      notify_player(player, cause, player,
	      		    "That has no location!", NOT_QUIET);
	    return(-1);
	  } else {
	    matched = nmat;
	    curr_match = matched;
	  }
	} else
	  curr_match = -1;
      }
      break;
    default:
      curr_match = -1;
    }
  }

  if (domesg(flags))
    resolve_mesg(player, cause, curr_match, -1);
  return (curr_match);
}

int resolve_player(player, cause, name, flags)
    int player, cause;
    char *name;
    int flags;
{
  int loc, list;
  char *ptr;
  register int matched;
  register curr_match = -1;
  register curr_value = 0;

  if ((name == (char *)NULL) || (name[0] == '\0')) {
    if (domesg(flags))
      notify_player(player, cause, player,
      		    "I don't see that here.", NOT_QUIET);
    return (-1);		/* no match */
  }
  if ((get_int_elt(player, LOC, &loc) == -1) || !exists_object(loc)) {
    logfile(LOG_ERROR, "resolve_player: couldn't get location of player #%d\n",
	    player);
    if (domesg(flags))
      notify_player(player, cause, player, "You have no location!", NOT_QUIET);
    return (-1);
  }

  /* Check these first.  Don't want to confuse these. */
  if (strcasecmp("me", name) == 0)
    return (player);
  if (could_hear(loc) && (strcasecmp("here", name) == 0))
    return (loc);

  if(get_int_elt(player, CONTENTS, &list) == -1) {
    logfile(LOG_ERROR, "resolve_player: bad contents list on object #%d\n",
	    player);
    if(domesg(flags))
      resolve_mesg(player, cause, curr_match, TYP_PLAYER);
    return(curr_match);
  }
  matched = match_contents(player, cause, name, list, MAT_THINGS|MAT_PLAYERS);
  if(best_value > curr_value){
    curr_match = matched;
    curr_value = best_value;
  }

  if(get_int_elt(loc, CONTENTS, &list) == -1) {
    logfile(LOG_ERROR, "resolve_player: bad contents list on object #%d\n",
	    loc);
    if(domesg(flags))
      resolve_mesg(player, cause, curr_match, TYP_PLAYER);
    return(curr_match);
  }
  matched = match_contents(player, cause, name, list, MAT_THINGS|MAT_PLAYERS);
  if(best_value > curr_value) {
    curr_match = matched;
    curr_value = best_value;
  }

  if (curr_match == -1) {
    switch(name[0]) {
    case '#':
      if(isWIZARD(player)) {
	name++;

        matched = (int)strtol(name, &ptr, 10);
        if ((ptr != name) && exists_object(matched) && isPLAYER(matched)) {
	  curr_match = matched;
        } else {
	  curr_match = -1;
        }
      }
      break;
    case '*':
      if((flags & RSLV_ALLOK) || (flags & RSLV_SPLATOK) || isWIZARD(player)) {
        name++;

        matched = match_active_player(name);
        if (exists_object(matched)) {
	  curr_match = matched;
        } else {
	  curr_match = match_player(name);
        }
      }
      break;
    case '@':
      if (flags & RSLV_ATOK) {
        name++;

	matched = match_active_player(name);
	if(!exists_object(matched))
	  matched = match_player(name);
	if(!exists_object(matched))
	  matched = resolve_player(player, cause, name,
				   ((flags & ~RSLV_ATOK)|RSLV_RECURSE));
	if(exists_object(matched)) {
	  int nmat;

	  if(get_int_elt(matched, LOC, &nmat) == -1) {
	    logfile(LOG_ERROR, "resolve_player: bad location on object #%d\n",
	  	    matched);
	    if(domesg(flags))
	      notify_player(player, cause, player,
			    "That has no location!", NOT_QUIET);
	    return(-1);
	  } else {
	    matched = nmat;
	    curr_match = matched;
	  }
	} else
	  curr_match = -1;
      }
      break;
    default:
      /* If all else fails. */
      if((flags & RSLV_ALLOK) || isWIZARD(player)) {
        matched = match_active_player(name);
        if (exists_object(matched)) {
	  curr_match = matched;
        } else {
	  curr_match = match_player(name);
        }
      } else
	curr_match = -1;
    }
  }

  if (domesg(flags))
    resolve_mesg(player, cause, curr_match, TYP_PLAYER);
  return (curr_match);
}

int resolve_exit(player, cause, name, flags)
    int player, cause;
    char *name;
    int flags;
{
  int location, list;
  char *ptr;
  register int matched;
  register int curr_match = -1;
  register int curr_value = 0;

  if ((name == (char *)NULL) || (name[0] == '\0')) {
    if (domesg(flags))
      notify_player(player, cause, player,
      		    "I don't see that here.", NOT_QUIET);
    return (-1);		/* no match */
  }
  if ((get_int_elt(player, LOC, &location) == -1)
      || !exists_object(location)) {
    logfile(LOG_ERROR, "resolve_exit: couldn't get location of player #%d\n",
	    player);
    if (domesg(flags))
      notify_player(player, cause, player, "You have no location!", NOT_QUIET);
    return (-1);
  }

  if(get_int_elt(player, EXITS, &list) == -1) {
    logfile(LOG_ERROR, "resolve_exit: bad exits list on object #%d\n", player);
    if(domesg(flags))
      resolve_mesg(player, cause, curr_match, TYP_EXIT);
    return(curr_match);
  }
  matched = match_exits(player, cause, name, list,
  			MAT_EXITS|MAT_INTERNAL|MAT_EXTERNAL);
  if(best_value > curr_value) {
    curr_match = matched;
    curr_value = best_value;
  }

  if(get_int_elt(location, EXITS, &list) == -1) {
    logfile(LOG_ERROR, "resolve_exit: bad exits list on object #%d\n",
	    location);
    if(domesg(flags))
      resolve_mesg(player, cause, curr_match, TYP_EXIT);
    return(curr_match);
  }
  matched = match_exits(player, cause, name, list,
			MAT_EXITS|MAT_INTERNAL|MAT_EXTERNAL);
  if(best_value > curr_value) {
    curr_match = matched;
    curr_value = best_value;
  }

  if (curr_match == -1) {
    if (*name && (*name == '#')) {
      name++;

      curr_match = (int)strtol(name, &ptr, 10);
      if ((ptr == name) || !exists_object(curr_match) || !isEXIT(curr_match))
	curr_match = -1;
    }
  }

  if (domesg(flags))
    resolve_mesg(player, cause, curr_match, TYP_EXIT);
  return (curr_match);
}