muse1.7b4/
muse1.7b4/config/
muse1.7b4/doc/
muse1.7b4/run/
muse1.7b4/run/db/
muse1.7b4/src/
muse1.7b4/src/db/
muse1.7b4/src/files/
muse1.7b4/src/io/
muse1.7b4/src/prog/
muse1.7b4/src/util/
/* match.c */
/* $Id: match.c,v 1.5 1993/05/12 17:17:03 nils Exp $ */

#include "copyright.h"
/* Routines for parsing arguments */
#include <ctype.h>
#include "db.h"
#include "config.h"
#include "match.h"
#include "externs.h"
#ifdef __STDC__
#include <stdlib.h>
#endif


#define DOWNCASE(x) to_lower(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 char *match_name;  /* name to match */
static int preferred_type = NOTYPE; /* preferred type */
static dbref it; /* the *IT*! */

/* this probably doesn't belong here but I didn't want to make another file */

/* check case insensitively if p is prefix for s */
int is_prefix(p,s)
 char *p;
 char *s;
{
  if (!*s)
    return(0);
  while(*p)
    if (!*s || (to_upper(*p++)!=to_upper(*s++)))
      return(0);
  return(1);
}

/* check a list for objects that are prefix's for string, && are controlled
   || link_ok */
dbref pref_match(player,list,string)
     dbref player;
     dbref list;
 char *string;
{
  dbref lmatch=NOTHING;
  int mlen=0;
  while(list!=NOTHING)
    {
      if (is_prefix(db[list].name,string) && (db[list].flags & PUPPET) &&
	  (controls(player,list,POW_MODIFY) || (db[list].flags & LINK_OK)))
	{
	  if (strlen(db[list].name)>mlen)
	    {
	      lmatch=list;
	      mlen=strlen(db[list].name);
	    }
	}
      list=db[list].next;
    }
  return(lmatch);
}

void init_match(player,name,type)
     dbref player;
 char *name;
     int type;
{
  exact_match = last_match = NOTHING;
  match_count = 0;
  match_who = player;
  match_name = name;
  check_keys = 0;
  preferred_type = type;
  if((!string_compare(name,"it")) && *atr_get(player,A_IT))
    it=atoi(1+atr_get(player,A_IT));
  else
    it=NOTHING;
}

void init_match_check_keys(player,name,type)
     dbref player;
 char *name;
     int type;
{
  init_match(player, name, type);
  check_keys = 1;
}

static dbref choose_thing(thing1,thing2)
     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, A_LOCK);
    has2 = could_doit(match_who, thing2, A_LOCK);
    
    if(has1 && !has2) {
      return thing1;
    } else if (has2 && !has1) {
      return thing2;
    }
    /* else fall through */
  }
  
  return (random() % 2) ? thing1 : thing2;
}

void match_player()
{
  dbref match;
 char *p;
  if(it != NOTHING && Typeof(it)==TYPE_PLAYER) {
    exact_match=it;
    return;
  }
  if(*match_name == LOOKUP_TOKEN) {
    for(p = match_name + 1; isspace(*p); p++);
    if((match = lookup_player(p)) != NOTHING) {
      exact_match = match;
    }
  }
}

/* returns nnn if name = #nnn, else NOTHING */
static dbref absolute_name()
{
  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()
{
  dbref match;
  if(it != NOTHING) {
    exact_match=it;
    return;
  }
  if((match = absolute_name()) != NOTHING) {
    exact_match = match;
  }
}

void match_me()
{
  if((it != NOTHING) && (it == match_who)) {
    exact_match=it;
    return;
  }
  if(!string_compare(match_name, "me")) {
    exact_match = match_who;
  }
}

void match_here()
{
  if(it != NOTHING && it == db[match_who].location) {
    exact_match = it;
    return;
  }
  if(db[match_who].location != NOTHING)
    if(!string_compare(match_name, "here"))
      exact_match = db[match_who].location;
}

static void match_list(first)
     dbref first;
{
  dbref absolute;
  
  absolute = absolute_name();
  
  DOLIST(first, first) {
    Access(first);
    if(first == absolute  ||  first == it) {
      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)) {
      if (match_count>0 && !string_compare(db[last_match].name,db[first].name))
	match_count = 0;
      last_match = first;
      match_count++;
    }
  }
}

void match_possession()
{
  match_list(db[match_who].contents);
}

void match_neighbor()
{
  dbref loc;
  
  if((loc = db[match_who].location) != NOTHING) {
    match_list(db[loc].contents);
  }
}

void match_perfect()
{
  dbref loc;
  dbref first;
  
  if ((loc = db[match_who].location) != NOTHING)
    first = db[loc].contents;
  else return;
  DOLIST(first, first) {
    Access(first);
    if (!strcmp(db[first].name, match_name) &&
	((Typeof(first) == preferred_type) || (preferred_type == NOTYPE)))
      exact_match = first;
  }
}

void match_exit()
{
  dbref loc;
  dbref exit;
  dbref absolute;
 char *match;
 char *p;
  if (Typeof(db[match_who].location)!=TYPE_ROOM &&
      Typeof(db[match_who].location) !=TYPE_THING)
    return;
  if((loc = db[match_who].location) != NOTHING) {
    absolute = absolute_name();
    
    DOLIST(exit, Exits(loc)) {
      Access(exit);
      if(exit == absolute || exit == it) {
	exact_match = exit;
      } else {
	match = db[exit].name;
	while(*match) {
	  /* check out this one */
	  for(p = match_name;
	      (*p
	       && DOWNCASE(*p) == DOWNCASE(*match)
	       && *match != EXIT_DELIMITER);
	      p++, match++);
	  /* did we get it? */
	  if(*p == '\0') {
	    /* make sure there's nothing afterwards */
	    while(isspace(*match)) match++;
	    if(*match == '\0' || *match == EXIT_DELIMITER) {
	      /* we got it */
	      exact_match = choose_thing(exact_match, exit);
	      goto next_exit;     /* got this match */
	    }
	  }
	  /* we didn't get it, find next match */
	  while(*match && *match++ != EXIT_DELIMITER);
	  while(isspace(*match)) match++;
	}
      }
    next_exit:
      ;
    }
  }
}

void match_everything()
{
  match_exit();
  match_neighbor();
  match_possession();
  match_me();
  match_here();
  /*    if(power(player, TYPE_HONWIZ)) {*/
  match_absolute();
  match_player();
  /*    }*/
}

dbref match_result()
{
  if(exact_match != NOTHING) {
    store_it(exact_match);
    return exact_match;
  } else {
    switch(match_count) {
    case 0:
      return NOTHING;
    case 1:
      store_it(last_match);
      return last_match;
    default:
      return AMBIGUOUS;
    }
  }
}

/* use this if you don't care about ambiguity */
dbref last_match_result()
{
  if(exact_match != NOTHING) {
    store_it(exact_match);
    return exact_match;
  } else {
    store_it(last_match);
    return last_match;
  }
}

dbref noisy_match_result()
{
  dbref match;
  
  switch(match = match_result()) {
  case NOTHING:
    notify(match_who, tprintf(NOMATCH_PATT,match_name));
    return NOTHING;
  case AMBIGUOUS:
    notify(match_who, tprintf("I don't know which %s you mean.",match_name));
    return NOTHING;
  default:
    return match;
  }
}


void store_it(what)
     dbref what;
{
  char buf[50];
  if(what==NOTHING) return;
  sprintf(buf,"#%d",what);
  atr_add(match_who,A_IT,buf);
}