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/
/* game.c */
/* $Id: game.c,v 1.39 1993/12/19 01:20:59 nils Exp $ */

int ndisrooms;

#if defined(SYSV) || defined(AIX_UNIX) || defined(SYSV_MAYBE)
#define vfork fork
#endif
#define my_exit exit

#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef __STDC__
#include <stdlib.h>
#endif
#ifdef XENIX
#include <sys/signal.h>
#else
#include <signal.h>
#include <sys/wait.h>
#endif /* xenix */

#include "nalloc.h"
#include "db.h"
#include "config.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#include "credits.h"

#include "admin.h"

/* declarations */
char dumpfile[200];
static int epoch = 0;
int reserved;
int depth=0;   /* excessive recursion prevention */
extern dbref cplr;
int unsafe=0;
/* used to allocate storage for temporary stuff, cleared before command
   execution */
NALLOC *glurp;



void do_dump(player)
     dbref player;
{
  if(power(player, POW_DB)) {
    notify(player, "Dumping...");
    fork_and_dump();
  } else {
    notify(player, "Sorry, you are in a no dumping zone.");
  }
}

extern char ccom[1024];
/* print out stuff into error file */
void report()
{
  char repbuf[5000];
  /*  fprintf(stderr,"Command:%s depth:%d\n",ccom,depth);fflush(stderr);
      if ((cplr>0) && (cplr<db_top))
      fprintf(stderr,"Player #%d location #%d\n",cplr,db[cplr].location);
      fflush(stderr);*/
  log_error("*** Reporting position ***");
  sprintf(repbuf,"Depth: %d Command: %s",depth,ccom);
  log_error(repbuf);
  sprintf(repbuf,"Player: %d location: %d",cplr,db[cplr].location);
  log_error(repbuf);
  log_error("**************************");
}

#ifdef DESTROY

void do_purge(player)
     dbref player;
{
  if (power(player, POW_DB))
    {
      fix_free_list();
      notify(player,"Purge complete.");
    }
  else
    notify(player,"@purge is a restricted command.");
}

/* this is where des_info points */
void dest_info(thing,tt)
     dbref thing;
     dbref tt;
{
  char buff[1024];
  if (thing==NOTHING) {
    if (db[tt].name) {
      sprintf(buff,"You own a disconnected room, %s(#%d)",db[tt].name,tt);
      notify(db[tt].owner,buff);
    } else {
      report();
      log_error("no name for room");
    }
    return;
  }
  switch(Typeof(thing))
    {
    case TYPE_ROOM: /* Tell all players room has gone away */
      notify_in(thing, 0, tprintf("%s, %s",
						   "The floor disappears under your feet",
						   "you fall through NOTHINGness and then:"));
      break;
    case TYPE_PLAYER: /* Show them where they arrived */
      enter_room(thing,HOME);
      break;
    }
}

#endif


dbref speaker=NOTHING;
void notify_nopup(player,msg)
     dbref player;
     char *msg;
{
  static char buff[2148],*d;

  if(player<0 || player>=db_top)
    return;
  if(depth++>7) {
    depth--;
    return;
  }
  if (db[player].owner != player) {
    strcpy(buff,msg);
    if (*(d=atr_get(player,A_LISTEN)) &&
	wild_match(d,buff)) {
      if (speaker!=player)
	did_it(speaker,player,0,NULL,0,NULL,A_AHEAR);
      else
	did_it(speaker,player,0,NULL,0,NULL,A_AMHEAR);
      did_it(speaker,player,0,NULL,0,NULL,A_AAHEAR);
      /* also pass the message on */
      /* Note: not telling player protects against two forms of recursion */
      /* player doesn't tell itself (as container) or as contents */
      /* using teleport it is possible to create a recursive loop */
      /* but this will be terminated when the depth variable exceeds 30 */
      if (db[speaker].location != player)
	notify_in(player,player,buff);
    }
    /* now check for multi listeners */
    if (speaker!=player)
      atr_match (player, speaker, '!', msg);
  }
  depth--;
}

void notify(player,msg)
     dbref player;
     char *msg;
{
  static char buff[2148];
  if ((player<0) || (player>=db_top))
    return;
  if (depth++>7) {
    depth--;
    return;
  }
  switch(Typeof(player)) {
  case TYPE_PLAYER:
    raw_notify(player,msg);
  default:
    if (db[player].flags & PUPPET) {
      sprintf(buff,"%s> %s",db[player].name,msg);
      raw_notify(db[player].owner,buff);
    }
    notify_nopup(player,msg);
  }
  depth--;
}

/* special notify, if puppet && owner is in same room don't relay */
void snotify(player,msg)
     dbref player;
     char *msg;
{
  if ((db[player].owner!=player) && (db[player].flags & PUPPET)
      && (db[player].location==db[db[player].owner].location))
    notify_nopup(player,msg);
  else
    notify(player,msg);
}

static void notify_except P((dbref, dbref, char *));
static void notify_except(first,exception,msg)
     dbref first;
     dbref exception;
     char *msg;
{
  if(first == NOTHING) return;
  DOLIST (first, first) {
    if (/*((db[first].flags & TYPE_MASK) == TYPE_PLAYER ||
	  ((db[first].flags & PUPPET) && (Typeof(first)==TYPE_THING)))
	  &&*/ first != exception) {
      snotify (first, msg);
    }
  }
}

void notify_in(room, exception, msg)
     dbref room, exception;
     char *msg;
{
  dbref z;
  DOZONE(z, room)
    notify(z,msg);
  if (room == NOTHING) return;
  if (room != exception)
    snotify(room, msg);
  notify_except(db[room].contents, exception, msg);
  notify_except(db[room].exits, exception, msg);
}

void do_shutdown(player, arg1)
     dbref player;
     char *arg1;
{
  extern int exit_status;

  if (strcmp(arg1, MUSE_NAME))  {
    if (!*arg1)
      notify(player,"You must specify the name of the muse you wish to shutdown.");
    else
      notify(player,tprintf("This is %s, not %s.",MUSE_NAME, arg1));
    return;
  }
  log_sensitive(tprintf("Shutdown attempt by %s",unparse_object(player,player)));
  if(power(player, POW_SHUTDOWN)) {
    log_important(tprintf("SHUTDOWN: by %s", unparse_object(player, player)));
    shutdown_flag = 1;
    exit_status = 0;
#ifdef USE_RWHO
    rwhocli_shutdown();
#endif
  } else {
    notify(player, "@shutdown is a restricted command.");
  }
}

void do_reboot(player, arg1)
     dbref player;
     char *arg1;
{
  extern int exit_status;

  if (strcmp(arg1, MUSE_NAME))  {
    if (!*arg1)
      notify(player,"You must specify the name of the muse you wish to reboot.");
    else
      notify(player,tprintf("This is %s, not %s.",MUSE_NAME, arg1));
    return;
  }
  
  log_sensitive(tprintf("Reboot attempt by %s", unparse_object(player, player)));
  if(power(player, POW_SHUTDOWN)) {
    log_important(tprintf("REBOOT: by %s", unparse_object(player, player)));
    shutdown_flag = 1;
    exit_status = 1;
#ifdef USE_RWHO
    rwhocli_shutdown();
#endif
  } else {
    notify(player, "@reboot is a restricted command.");
  }
}

#ifdef XENIX
/* rename hack!!! */
void rename(s1,s2)
     char *s1;
     char *s2;
{
  char buff[300];
  sprintf(buff,"mv %s %s",s1,s2);
  system(buff);
}
#endif

static void dump_database_internal()
{
  char tmpfile[2048];
  FILE *f;
  
  sprintf(tmpfile, "%s.#%d#", dumpfile, epoch - 1);
  unlink(tmpfile);            /* nuke our predecessor */
  sprintf(tmpfile, "%s.#%d#", dumpfile, epoch);
#ifdef DBCOMP
  if((f = popen(tprintf("../bin/mycompress >%s",tmpfile), "w")) != NULL) {
    db_write(f);
    if((pclose(f) == 123) ||
       (rename(tmpfile, dumpfile) < 0)) {
      no_dbdump();
      perror(tmpfile);
    }
  }
  else {
    no_dbdump();
    perror(tmpfile);
  }
#else
  if ( (f = fopen(tmpfile,"w")) != NULL )  {
    db_write(f);
    fclose(f);
    if ( rename(tmpfile,dumpfile) < 0 ) {
      perror(tmpfile);
      no_dbdump();
    }
  }
  else {
    no_dbdump();
    perror(tmpfile);
  }
#endif
}

void panic(message)
 char *message;
{
  char panicommand_loge[2048];
  FILE *f;
  int i;
  sprintf(panicommand_loge,"PANIC!! %s",message); /* kludge! */
  log_error(panicommand_loge);		/* reuse panicommand_loge later! yay! */
#ifdef SYSV_IO
  punt_all();
#endif
  
  report();
  /* turn off signals */
  for(i = 0; i < NSIG; i++) {
    signal(i, SIG_IGN);
  }
  
  /* shut down interface */
  emergency_shutdown();
  
  /* dump panic file */
  sprintf(panicommand_loge, "%s.PANIC", dumpfile);
  if((f = fopen(panicommand_loge, "w")) == NULL) {
    perror("CANNOT OPEN PANIC FILE, YOU LOSE");
    exit_nicely(136);
  } else {
    log_io(tprintf("DUMPING: %s", panicommand_loge));
    db_write(f);
    fclose(f);
    log_io(tprintf("DUMPING: %s (done)", panicommand_loge));
    exit_nicely(136);
  }
}

void dump_database()
{
  epoch++;
  
  log_io(tprintf("DUMPING: %s.#%d#", dumpfile, epoch));
  dump_database_internal();
  log_io(tprintf("DUMPING: %s.#%d# (done)", dumpfile, epoch));
}

void free_database()
{
  /* free all the objects, and everything. for malloc debugging. */
  int i;
  for (i=0; i<db_top; i++) {
    free (db[i].name);
    if (db[i].parents)
      free(db[i].parents);
    if (db[i].children)
      free(db[i].children);
    if (db[i].pows)
      free(db[i].pows);
    if (db[i].atrdefs) {
      struct atrdef *j, *next=NULL;
      for (j=db[i].atrdefs; j; j=next) {
	next = j->next;
	free(j->a.name);
	free(j);
      }
    }
    if (db[i].list) {
      ALIST *j, *next=NULL;
      for (j=db[i].list; j; j=next) {
	next = AL_NEXT(j);
	free(j);
      }
    }
  }
  bigfree(db);
}

void fork_and_dump()
{
  int child;
  static char buf[100] = "";
  
  /* first time through only, setup dump message */
  if ( *buf == '\0' )
#ifdef USE_VFORK
    sprintf(buf, "%s Database saved. Sorry for the lag.",MUSE_NAME);
#else
#ifdef NOISY_DUMP
  sprintf(buf,
	  "Saving %s DataBase. Response will be slow for a few minutes.",
	  MUSE_NAME);
#endif
#endif

#ifdef USE_SPACE
  dump_space();
#endif
  
  epoch++;
  
  log_io(tprintf("CHECKPOINTING: %s.#%d#", dumpfile, epoch));
#ifdef NOISY_DUMP
  for(i = 0; i < db_top; i++)
    if( Typeof(i) == TYPE_PLAYER && ! (db[i].flags & PLAYER_NO_WALLS) )
      notify(i, buf);
#endif
  
#ifndef NO_FORK
# ifdef USE_VFORK
  child = vfork();
# else /* USE_VFORK */
  child = fork();
  if ( child == -1 )
    child=vfork(); /* not enough memory! or something.. */
# endif /* USE_VFORK */
#else  /* NO FORK */
  child=0;
#endif /* NO_FORK */
  
  if(child == 0) {
    /* in the child */
    close(reserved);        /* get that file descriptor back */
    dump_database_internal();
#ifndef NO_FORK
    _exit(0);
#else /* NO FORK */
    reserved=open("/dev/null",O_RDWR,664);
#endif /* NO_FORK */
  }
  else if(child < 0) {
    perror("fork_and_dump: fork()");
    no_dbdump();
  }
}
void no_dbdump()
{
  do_broadcast(1,"Database save failed. Please take appropriate precautions.","");
}
static signal_type reaper (i)
     int i;
{
#if defined(XENIX) || defined(SYSV) || defined(AIX_UNIX) || defined(SYSV_MAYBE)
  int status;
  wait(&status);
#else
  union wait stat;
  while(wait3(&stat, WNOHANG, 0) > 0);
#endif
#ifdef void_signal_type
  return;
#else
  return 0;
#endif
}

void do_restart()
{
  dbref thing;
  char *s;
FILE *f;
f=fopen("nostartup","r");
if (f) {
fclose(f);
return; /* don't do startup stuff */
}
  for(thing=0;thing<db_top;thing++)
    if (!(db[thing].flags & GOING) && *(s=atr_get(thing,A_STARTUP)))
      parse_que(thing,s,thing);
}

int init_game(infile,outfile)
     char *infile;
     char *outfile;
{
  FILE *f;
  int a;
  depth=0;

  glurp=na_open(NULL);
  for(a=0;a<10;a++)
    wptr[a]=NULL;
  /* reserved=open("/dev/null",O_RDWR);  #JMS#  */
  
#ifdef DBCOMP
  if((f = popen(tprintf("uncompress <%s",infile),"r")) == NULL)
    return -1;
#else
  if ((f=fopen(infile,"r"))==NULL)
    return -1;
#endif
  
  /* ok, read it in */
  log_important(tprintf("LOADING: %s", infile));
  
  fflush(stdout);
  db_set_read(f);
  log_important(tprintf("LOADING: %s (done)", infile));
  /* everything ok */
  
  /* initialize random number generator */
  srand(getpid());
  /* set up dumper */
  strcpy(dumpfile,outfile);
  init_timer();
#ifndef XENIX
  signal(SIGCHLD, reaper);
#else /* xenix */
  signal(SIGCLD,reaper);
#endif
  
  return 0;
}

/* use this only in process
   
   _command */
#define Matched(string) { if(!string_prefix((string), command)) goto bad; }

/* the two versions of argument parsing */
char *do_argtwo(player,rest,cause,buff)
     dbref player;
     char *rest;
     dbref cause;
     char *buff;
{
  exec(&rest,buff,player,cause,0);
  return(buff);
}

char **do_argbee(player,rest,cause,arge,buff)
     dbref player;
     char *rest;
     dbref cause;
     char *arge[];
     char *buff;
{
  int a;
  
  for(a=1;a<MAX_ARG;a++)
    arge[a]= (char *) parse_up(&rest,',');
  /* rest of delimiters are ,'s */
  
  for(a=1;a<MAX_ARG;a++)
    if (arge[a])  {
      exec(&arge[a],buff,player,cause,0);
      strcpy(arge[a]=(char *)na_alloc(glurp,strlen(buff)+1),buff);
    }
  return(arge);
}

#define arg2 do_argtwo(player,rest,cause,buff)
#define argv do_argbee(player,rest,cause,arge,buff)
#ifdef NEW_COMMANDS

#endif /* NEW_COMMANDS */

#ifdef LOG_COMMANDS
FILE *command_log;
#endif



void process_command(player,command,cause)
     dbref player;
     char *command;
     dbref cause;
{
  char *arg1;
  char *q;                    /* utility */
  char *p;                    /* utility */
  /*    char args[MAX_ARG][1*/
  char buff[1024],buff2[1024];
  char *arge[MAX_ARG]; /* pointers to arguments (null for empty) */
  char unp[1024]; /* unparsed command */
  char pure[1024]; /* totally unparsed command */
  char pure2[1024];
  char *rest, *temp;
  int match, z=NOTHING;
  dbref zon;
  /* general form command arg0=arg1,arg2...arg10 */
  int slave=IS(player,TYPE_PLAYER,PLAYER_SLAVE);
  int is_direct=0;

  if (cause == NOTHING) {
    is_direct = 1;
    cause = player;
  };

  inc_pcmdc();			/* increment command stats */
  
  temp=command;
  /* skip leading space */
  while(*temp && (*temp==' ')) temp++;
  /* skip firsts word */
  while(*temp && (*temp!=' ')) temp++;
  /* skip leading space */
  if (*temp)
    temp++;
  strcpy(pure,temp);
  while(*temp && (*temp!='=')) temp++;
  if (*temp)
    temp++;
  strcpy(pure2,temp);
  func_zerolev();
  na_clear(glurp);
  depth=0;
  if(command == 0) abort();
  /* Access the player */
  Access(player);
  if (player == GOD && cause != GOD)
    return;
  /* robustify player */
  if((player < 0) || (player >= db_top)
     ){
    log_error(tprintf("process_command: bad player %d", player));
    return;
  }
  if (((db[player].flags & GOING) ||
      (db[player].flags & HAVEN)) && Typeof(player)!=TYPE_PLAYER)
    {
      notify(db[player].owner,
	     tprintf("Attempt to execute command by halted object #%d",player));
      return;
    }
  speaker=player;
  
#ifdef LOG_COMMANDS
  {
    static short counter;
    if(command_log==NULL) {
      command_log=fopen("logs/commands","w");
      setbuf(command_log, NULL);
    }
    if(command_log==NULL) command_log=stderr;
    if(db[player].location < 0 || db[player].location >= db_top) {
       fprintf(command_log, "COMMAND from %s(%d) in #%d(ACK!): %s\n",
               db[player].name, player, db[player].location, command);
       log_error(tprintf("illegal location: player %d location %d",player,db[player].location));
       return;
    }
    fprintf(command_log, "COMMAND from %s(%d) in %s(%d): %s\n",
	    db[player].name, player,
	    db[db[player].location].name, db[player].location,
	    command);
    fflush(command_log);
    if(counter++>100) {
      counter=0;
      if(command_log!=stderr)
	fclose(command_log);
      command_log=NULL;
      unlink("logs/commands~");
      rename("logs/commands","logs/commands~");
    }
  }
#endif /* LOG_COMMANDS */
  if((db[player].flags & PUPPET) && (db[player].flags & DARK)) {
    char buf[2000];
    sprintf(buf,"%s>> %s",db[player].name,command);
    raw_notify(db[player].owner,buf);
  }
  /* eat leading whitespace */
  while(*command && isspace(*command)) command++;
  /* eat extra white space */
  q = p = command;
  while(*p) {
    /* scan over word */
    while(*p && !isspace(*p)) *q++ = *p++;
    /* smash spaces */
    while(*p && isspace(*++p));
    if(*p) *q++ = ' '; /* add a space to separate next word */
  }
  /* terminate */
  *q = '\0';
  
  /* important home checking comes first! */
  if (strcmp(command,"home")==0)
    {
      do_move(player,command);
#ifdef LOG_COMMANDS
      if(command_log) {
	fputc('.',command_log);
	fflush(command_log);
      }
#endif
      return;
    }
  if (!slave && try_force(player,command)) /*||
					     ((Typeof(player)!=TYPE_PLAYER) && (Typeof(player)!=TYPE_THING)))*/ {
#ifdef LOG_COMMANDS
					       if(command_log) {
						 fputc('.',command_log);
						 fflush(command_log);
					       }
#endif
					       return;
					     }
  /* check for single-character commands */
  if(*command == SAY_TOKEN) {
    do_say(player, command+1, NULL);
  } else if(*command == POSE_TOKEN) {
    do_pose(player, command+1, NULL, 0);
  } else if(*command == NOSP_POSE) {
    do_pose(player, command+1, NULL, 1);
  } else if(*command == COM_TOKEN) {
    do_com(player, "", command+1);
  } else if(can_move(player, command)) {
    /* command is an exact match for an exit */
    do_move(player, command);
  } else
    {
      strcpy(unp,command);
      /* parse arguments */
      
      /* find arg1 */
      /* move over command word */
      for(arg1 = command; *arg1 && !isspace(*arg1); arg1++);
      /* truncate command */
      if(*arg1) *arg1++ = '\0';
      
      /* move over spaces */
      while(*arg1 && isspace(*arg1)) arg1++;
      
      arge[0]=(char *)parse_up(&arg1,'='); /* first delimiter is ='s */
      rest=arg1;  /* either arg2 or argv */
      if (arge[0])
	exec(&arge[0],buff2,player,cause,0);
      arg1=(arge[0]) ? buff2 : "";
      if (slave)
        switch(command[0]) {
	case 'l':
          Matched("look");
          do_look_at(player,arg1);
          break;
	}
      else
        switch(command[0]) {
	case '+':
	  switch(command[1]) {
	  case 'a':
	  case 'A':
	    Matched("+away");
	    do_away(player, arg1);
	    break;
	  case 'c':
	  case 'C':
	    switch (command[2]) {
	    case 'o':
	    case 'O':
	    case '\0':
	      Matched("+com");
	      do_com(player,arg1,arg2);
	      break;
	    case 'm':
	    case 'M':
	      Matched("+cmdav");
	      do_cmdav(player);
	      break;
	    case 'h':
	    case 'H':
	      Matched("+channel");
	      do_channel(player,arg1);
	      break;
	    default: goto bad;
	    }
	    break;
	  case 'e':
	  case 'E':
	    Matched("+edit");
	    do_editfile(player,arg1);
	    break;
	  case 'h':
	  case 'H':
	    Matched("+haven");
	    do_haven(player, arg1);
	    break;
	  case 'i':
	  case 'I':
	    Matched("+idle");
	    do_idle(player, arg1);
	    break;
	  case 'l':
	  case 'L':
	    switch (command[2]) {
	    case 'a':
	    case 'A':
	      Matched("+laston");
	      do_laston(player, arg1);
	      break;
	    case 's':
	    case 'S':
	      Matched("+ls");
	      do_ls(player, arg1);
	      break;
	    default: goto bad;
	    }
	    break;
	  case 'm':
	  case 'M':
	    switch(command[2]) {
	    case 'a':
	    case 'A':
	      Matched("+mail");
	      do_mail(player,arg1,arg2); 
	      break;
	    case 'k':
	    case 'K':
	      Matched("+mkdir");
	      do_mkdir(player, arg1);
	      break;
	    default: goto bad;
	    }
	    break;
	  case 'u':
	  case 'U':
	    Matched("+uptime");
	    do_uptime(player);
	    break;
	  case 'v':
	  case 'V':
	    Matched("+version");
	    do_version(player);
	    break;
	  default:
	    goto bad;
	  }
	  break;
	case '@':
	  switch(command[1]) {
	  case 'a':
	  case 'A':
	    switch(command[2]) {
	    case 'd':
	    case 'D':
	      Matched("@addparent");
	      do_addparent (player, arg1, arg2);
	      break;
	    case 'l':
	    case 'L':
	      Matched("@allquota");
	      do_allquota(player, arg1);
	      break;
	    case 'n':
	    case 'N':
	      Matched("@announce");
	      do_announce(player, arg1, arg2);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 'b':
	  case 'B':
	    switch(command[2]) {
	    case 'r':
	    case 'R':
	      Matched("@broadcast");
	      do_broadcast(player, arg1, arg2);
	      break;
	    case 'o':
	    case 'O':
	      Matched("@boot");
	      do_boot(player, arg1);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 'c':
	  case 'C':
	    /* chown, create */
	    switch(command[2]) {
	    case 'h':
	    case 'H':
	      if ( strcmp(command, "@chownall") == 0 )
		do_chownall(player, arg1, arg2);
	      else  {
		switch (command[3]) {
		case 'o':
		case 'O':
		  Matched("@chown");
		  do_chown(player, arg1, arg2);
		  break;
		case 'e':
		case 'E':
		  Matched("@check");
		  do_check (player, arg1);
		  break;
		default: goto bad;
		}
	      }
	      break;
	    case 'r':
	    case 'R':
	      Matched("@create");
	      do_create(player, arg1, atol(arg2));
	      break;
	    case 't':
	    case 'T':
	      Matched("@ctrace");
	      do_ctrace(player);
	      break;
	    case 'l':
	    case 'L':
	      switch(command[3])  {
	      case 'a':
	      case 'A':
		Matched("@class");
		do_class(player, arg1, arg2);
		break;
	      case 'o':
	      case 'O':
		Matched("@clone");
		do_clone(player,arg1,arg2);
		break;
	      default:
		goto bad;
	      }
	      break;
	    case 's':
	    case 'S':
	      Matched("@cset");
	      do_set(player,arg1,arg2,1);
	      break;
	    case 'y':
	    case 'Y':
	      Matched("@cycle");
	      do_cycle(player,arg1,argv);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 'd':
	  case 'D':
	    /* describe, dig, or dump */
	    switch(command[2]) {
	    case 'b':
	    case 'B':
	      switch (command[3]) {
	      case 'c':
		Matched("@dbck");
		do_dbck(player);
		break;
	      case 't':
		Matched("@dbtop");
		do_dbtop(player,arg1);
		break;
	      default: goto bad;
	      }
	      break;
	    case 'e':
	    case 'E':
#ifdef DESTROY
	      if (strcmp("@destroy",command)==0)
		{
		  do_destroy(player,arg1);
		}
	      else
#endif /* DESTROY */
		switch (command[3]) {
		case 'c':
		case 'C':
		  Matched("@decompile");
		  do_decompile (player, arg1, arg2);
		  break;
		case 's':
		case 'S':
		  Matched("@describe");
		  do_describe(player, arg1, arg2);
		  break;
		case 'f':
		case 'F':
		  Matched("@defattr");
		  do_defattr(player, arg1, arg2);
		  break;
		case 'l':
		case 'L':
		  Matched("@delparent");
		  do_delparent (player, arg1, arg2);
		  break;
		default: goto bad;
		}
	      break;
	    case 'i':
	    case 'I':
	      Matched("@dig");
	      do_dig(player, arg1,argv);
	      break;
	    case 'u':
	    case 'U':
	      Matched("@dump");
	      do_dump(player);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 'f':
	    /* fail, find, or force */
	    switch(command[2]) {
	    case 'a':
	    case 'A':
	      Matched("@fail");
	      do_fail(player, arg1, arg2);
	      break;
	    case 'i':
	    case 'I':
	      Matched("@find");
	      do_find(player, arg1);
	      break;
	    case 'o':
	    case 'O':
	      if (string_prefix ("@foreach", command) && strlen(command)>4) {
		Matched("@foreach");
		do_foreach(player, arg1, arg2, cause);
		break;
	      }
	      Matched("@force");
	      do_force(player, arg1, arg2);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 'e':
	  case 'E':
	    switch(command[2]) {
	    case 'c':
	    case 'C':
	      Matched("@echo");
	      do_echo(player,arg1,arg2,0);
	      break;
	    case 'd':
	    case 'D':
	      Matched("@edit");
	      do_edit(player,arg1,argv);
	      break;
	    case 'm':
	    case 'M':
	      switch(command[3]) {
	      case 'i':
	      case 'I':
		Matched("@emit");
		do_emit(player,arg1,arg2,0);
		break;
	      case 'p':
	      case 'P':
		Matched("@empower");
		do_empower(player,arg1,arg2);
		break;
	      default: goto bad;
	      }
	      break;
#ifdef EXEC
	    case 'x':
	    case 'X':
	      Matched("@exec");
	      do_exec(player,arg1,arg2);
	      break;
#endif
	    default:
	      goto bad;
	    }
	    break;
	  case 'g':
	  case 'G':
	    Matched("@giveto");
	    do_giveto(player,arg1,arg2);
	    break;
	  case 'h':
	  case 'H': /* removes all queued commands by your objects */
	    /* halt or hide */
	    switch(command[2]) {
	    case 'a':
	    case 'A':
	      Matched("@halt");
	      do_halt(player,arg2);
	      break;
	    case 'i':  /* hides player name from WHO */
	    case 'I':
	      Matched("@hide");
	      do_hide(player);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 'l':
	  case 'L':
	    /* lock or link */
	    switch(command[2]) {
	    case 'i':
	    case 'I':
	      Matched("@link");
	      do_link(player, arg1, arg2);
	      break;
/*	    case 'o':
	    case 'O':
	      Matched("@lock");
	      do_lock(player, arg1, arg2);
	      break; */
	    default:
	      goto bad;
	    }
	    break;
	  case 'm':
	  case 'M':
	    switch(command[2]) {
	    case 'i':
	    case 'I':
	      Matched("@misc"); /* miscelanious functions */
	      do_misc(player,arg1,arg2);
	      break;
	    case 'a':
	    case 'A':
	      Matched("@mailhuh");
	      if(!power(player,POW_DB)) goto bad;
	      do_mailhuh(player);
	      break;
	    default: goto bad;
	    }
	    break;
	  case 'n':
	  case 'N':
	    /* @name, @newpassword, or @nuke */
	    switch(command[2]) {
	    case 'a':
	    case 'A':
	      Matched("@name");
	      do_name(player, arg1, arg2, is_direct);
	      break;
	    case 'c':
	    case 'C':
	      Matched("@ncset");
	      do_set(player, arg1, pure2, 1);
	      break;
	    case 'e':
	    case 'E':
	      switch(command[3]) {
	      case 'c':
	      case 'C':
		Matched("@necho");
		do_echo(player,pure,NULL,1);
		break;
	      case 'w':
		if(strcmp(command, "@newpassword")) goto bad;
		do_newpassword(player, arg1, arg2);
		break;
	      case 'm':
	      case 'M':
		Matched("@nemit");
		do_emit(player,pure,NULL,1);
		break;
	     default:
		goto bad;
	      }
	      break;
	    case 'u':
	      if(string_compare(command, "@nuke")) goto bad;
	      do_nuke(player, arg1);
	      break;
	    case 'o':
	    case 'O':
	      Matched("@nopow_class");
	      do_nopow_class(player, arg1, arg2);
	      break;
	    case 'p':
	    case 'P':
	      switch(command[3]) {
	      case 'e':
	      case 'E':
		Matched("@npemit");
		do_general_emit(player, arg1, pure, 4);
		break;
	      case 'a':
	      case 'A':
		Matched("@npage");
		do_page(player, arg1, pure2);
		break;
	      default:
		goto bad;
	      }
	      break;
	    case 's':
	    case 'S':
	      Matched("@nset");
	      do_set(player, arg1, pure2, is_direct);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 'o':
	  case 'O':
	    switch(command[2]) {
	    case 'e':
	    case 'E':
	      Matched("@oemit");
	      do_general_emit(player, arg1, arg2, 2);
	      break;
	    case 'f':
	    case 'F':
	      Matched("@ofail");
	      do_ofail(player, arg1, arg2);
	      break;
	    case 'p':
	    case 'P':
	      Matched("@open");
	      do_open(player, arg1, arg2,NOTHING);
	      break;
	    case 's':
	    case 'S':
	      Matched("@osuccess");
	      do_osuccess(player, arg1, arg2);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 'p':
	  case 'P':
	    switch(command[2])
	      {
	      case 'a':
	      case 'A':
		Matched("@password");
		do_password(player, arg1, arg2);
		break;
	      case 'b':
	      case 'B':
		Matched("@pbreak");
		do_pstats(player, arg1);
		break;
	      case 'C':
	      case 'c':
		Matched("@pcreate");
		do_pcreate(player, arg1, arg2);
		break;
	      case 'e':
	      case 'E':
		Matched("@pemit");
		do_general_emit(player, arg1, arg2, 0);
		break;
	      case 'O':
	      case 'o':
		switch(command[3]) {
		case 'o':
		case 'O':
		  Matched("@Poor");
		  do_poor(player,arg1);
		  break;
		case 'w':
		case 'W':
		  Matched("@powers");
		  do_powers(player,arg1);
		  break;
		default: goto bad;
		}
		break;
	      case 'S':
	      case 's':
		Matched("@ps");
		do_queue(player);
		break;
#ifdef DESTROY
	      case 'u':
	      case 'U':/* force room destruction */
		Matched("@purge");
		do_purge(player);
		break;
#endif /* DESTROY */
	      default:
		goto bad;
	      }
	    break;
	  case 'q':
	  case 'Q':
	    Matched("@quota");
	    do_quota(player, arg1, arg2);
	    break;
	  case 'r':
	  case 'R':
	    switch(command[2]) {
	      case 'e':
	      case 'E':
		switch(command[3]) {
		case 'b':
		case 'B':
		  Matched("@reboot");
		  do_reboot(player, arg1);
		  break;
		case 'g':
		case 'G':
		  if(!string_compare(command, "@register_purge"))
		    do_register_purge(player);
		  else
		    goto bad;
		  break;
		case 'm':
		case 'M':
		  Matched("@remit");
		  do_general_emit(player,arg1,arg2,1);
		  break;
		default: goto bad;
		}
		break;
	      case 'O':
	      case 'o':
		Matched("@robot");
		do_robot(player,arg1,arg2);
		break;
#ifdef USE_RWHO
	      case 'W':
	      case 'w':
		Matched("@rwho");
		do_rwho(player,arg1);
		break;
#endif
	      default:
		goto bad;
	      }
	    break;
	  case 's':
	  case 'S':
	    /* set, shutdown, success */
	    switch(command[2]) {
	      /* case 'a':
		 case 'A': * !!! wizard only safe command !!! * 
		 if (!power(player, TYPE_ADMIN))
		 goto bad;
		 unsafe=0;
		 break; */
	    case 'e':
	    case 'E':
	      /* patched to add 'search' command */
	      switch(command[3]) {
	      case 'a':
	      case 'A':
		Matched("@search");
		do_search(player, arg1, arg2);
		break;
	      case 't':
	      case 'T':
		Matched("@set");
		do_set(player, arg1, arg2, is_direct);
		break;
	      default:
		goto bad;
	      }
	      break;
	    case 'h':
	    case 'H':
	      switch(command[3]) {
	      case 'u':
		if(strcmp(command, "@shutdown")) goto bad;
		do_shutdown(player, arg1);
		break;
	      case 'o':
	      case 'O':
		Matched("@showhash");
		do_showhash(player,arg1);
		break;
	      default:
		goto bad;
	      }
	      break;
	    case 't': case 'T':
	      Matched("@stats");
	      do_stats(player, arg1);
	      break;
	    case 'u':
	    case 'U':
	      Matched("@success");
	      do_success(player, arg1, arg2); break;
	    case 'w':
	    case 'W':
	      switch(command[3]) {
	      case 'e':
	      case 'E':
		Matched("@sweep");
		do_sweep(player, pure);
		break;
	      case 'i':
	      case 'I':
		  Matched("@switch");
		  do_switch(player,arg1,argv,cause);
		  break;
		default:
		  goto bad;
		}
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 't':
	  case 'T':
	    switch(command[2]) {
	    case 'e':
	    case 'E':
	      switch(command[3]) {
	      case 'l':
	      case 'L':
	      case '\0':
		Matched("@teleport");
		do_teleport(player, arg1, arg2);
		break;
	      case 'x':
	      case 'X':
		Matched("@text");
		do_text(player, arg1, arg2);
		break;
	      default: goto bad;
	      }
	      break;
	    case 'r':
	    case 'R':
	      switch(command[3]) {
	      case 'i':
	      case 'I':
	      case '\0':
		Matched("@trigger");
		do_trigger(player,arg1,argv);
		break;
	      case '_':
		Matched("@tr_as");
		do_trigger_as(player,arg1,argv);
		break;
	      default: goto bad;
	      };
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case 'u':
	  case 'U':
	    switch(command[2]) {
	    case 'l':
	    case 'L':
	      Matched("@ulink");
	      do_ulink(player, arg1);
	      break;
	    case 'n':
	    case 'N':
	      switch(command[3]) {
	      case 'd':
	      case 'D':
		switch(command[4]) {
		case 'e':
		case 'E':
		  switch(command[5]) {
		  case 's':
		  case 'S':
		    Matched("@undestroy");
		    do_undestroy(player, arg1);
		    break;
		  case 'f':
		  case 'F':
		    Matched ("@undefattr");
		    do_undefattr (player, arg1);
		    break;
		  default: goto bad;
		  }
		  break;
		default: goto bad;
		}
		break;
	      case 'l':
	      case 'L':
		switch(command[4]) {
		case 'i':
		case 'I':
		  Matched("@unlink");
		  do_unlink(player, arg1);
		  break;
		case 'o':
		case 'O':
		  Matched("@unlock");
		  do_unlock(player, arg1);
		  break;
		default:
		  goto bad;
		}
		break;
	      case 'h':
	      case 'H':
		Matched("@unhide");
		do_unhide(player);
		break;
	      case 'z':
	      case 'Z':
		Matched("@unzlink");
		do_unzlink(player, arg1);
		break;
	      default: goto bad;
	      }
	      break;
	    case 'p':
	    case 'P':
	      Matched("@upfront");
	      do_upfront(player,arg1,arg2);
	      break;
	    default: goto bad;
	    }
	    break;
	  case 'w':
	  case 'W':
	    if(strcmp(command, "@wall")==0) {
	      do_announce(player, arg1, arg2);
	      break;
	    }
	    if(strcmp(command, "@whereis")==0) {
	      do_whereis(player, arg1);
	      break;
	    }
	    if ( strcmp(command, "@wipeout") == 0 ) {
	      do_wipeout(player, arg1, arg2);
	      break;
	    }
	    Matched("@wait");
	    wait_que(player,atoi(arg1),arg2,cause);
	    break;
	  case 'z':
          case 'Z':
	    switch(command[2]) {
	    case 'e':
	    case 'E':
	      Matched("@zemit");
	      do_general_emit(player, arg1, arg2, 3);
	      break;
	    case 'l':
	    case 'L':
	      Matched("@zlink");
	      do_zlink(player, arg1, arg2);
	      break;
	    default: goto bad;
	    }
	    break;
	  default:
	    goto bad;
	  }
	  break;
	case 'd':
	case 'D':
	  Matched("drop");
	  do_drop(player, arg1);
	  break;
	case 'e':
	case 'E':
	  switch(command[1])
	    {
	    case 'X':
	    case 'x':
	      Matched("examine");
	      do_examine(player, arg1);
	      break;
	    case 'N':
	    case 'n':
	      Matched("enter");
	      do_enter(player,arg1);
	      break;
	    default:
	      goto bad;
	    }
	  break;
	case 'g':
	case 'G':
	  /* get, give, go, or gripe */
	  switch(command[1]) {
	  case 'e':
	  case 'E':
	    Matched("get");
	    do_get(player, arg1);
	    break;
	  case 'i':
	  case 'I':
	    Matched("give");
	    do_give(player, arg1, arg2);
	    break;
	  case 'o':
	  case 'O':
	    Matched("goto");
	    do_move(player, arg1);
	    break;
	  case 'r':
	  case 'R':
	    Matched("gripe");
	    do_gripe(player, arg1, arg2);
	    break;
	  default:
	    goto bad;
	  }
	  break;
	case 'h':
	case 'H':
	  Matched("help");
	  do_help(player, arg1, "help", HELPINDX, HELPTEXT, NULL);
	  break;
	case 'i':
	case 'I':
	  Matched("inventory");
	  do_inventory(player);
	  break;
	case 'j':
	case 'J':
	  Matched("join");
	  do_join(player, arg1);
	  break;
#ifdef KILL_MIN_COST
	case 'k':
	case 'K':
	  Matched("kill");
	  do_kill(player, arg1, atol(arg2));
	  break;
#endif
	case 'l':
	case 'L':
	  switch(command[1])
            {
	    case 'o':
	    case 'O':
	    case '\0': /* patch allow 'l' command to do a look */
              Matched("look");
              do_look_at(player, arg1);
              break;
	    case 'E':
	    case 'e':
              Matched("leave");
              do_leave(player);
              break;
	    default:
              goto bad;
            }
	  break;
	case 'm':
	case 'M':
	  switch(command[1])  {
	  case 'o':
	  case 'O':
	    switch(command[2])  {
	    case 'n':
	    case 'N':
	      Matched("money");
	      do_money(player, arg1, arg2);
	      break;
	    case 'v':
	    case 'V':
	      Matched("move");
	      do_move(player, arg1);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  default:
	    goto bad;
	  }
	  break;
	case 'n':
	case 'N':
	  /* news */
	  if(string_compare(command, "news")) goto bad;
/*	  do_news(player, arg1);*/
	  do_help(player, arg1, "news", NEWSINDX, NEWSTEXT, A_ANEWS);
	  break;
	case 'p':
	case 'P':
	  switch(command[1]) {
	  case 'a':
	  case 'A':
	  case '\0':
	    Matched("page");
	    do_page(player, arg1,arg2);
	    break;
	  case 'o':
	  case 'O':
	    Matched("pose");
	    do_pose(player,arg1,arg2,0);
	    break;
	  default:
	    goto bad;
	  }
	  break;
	case 'r':
	case 'R':
	  switch(command[1]) {
	  case 'e':
	  case 'E':
	    Matched("read"); /* undocumented alias for look at */
	    do_look_at(player, arg1);
	    break;
#ifdef USE_RWHO_DUMP
	  case 'w':
	  case 'W':
	    Matched("rwho");
	    dump_rusers(player,arg1,arg2);
	    break;
#endif
	  default:
	    goto bad;
	  }
	  break;
	case 's':
	case 'S':
	  /* say, "score" */
	  switch(command[1]) {
	  case 'a':
	  case 'A':
	    Matched("say");
	    do_say(player, arg1, arg2);
	    break;
	  case 'c':
	  case 'C':
	    Matched("score");
	    /*	    notify(player, "Note: This command will soon dissapear.");
		    notify(player, "      Please start using the command: 'money'.");
		    notify(player, " ");*/
	    do_score(player);
	    notify(player, "Warning: this command may dissapear in the future.");
	    notify(player,"Please start using the 'money' command.");
	    break;
	  case 'l':
	  case 'L':
	    Matched("slay");
	    do_slay(player, arg1);
	    break;
	  case 'u':
	  case 'U':
	    Matched("summon");
	    do_summon(player,arg1);
	    break;
	  default:
	    goto bad;
	  }
	  break;
	case 't':
	case 'T':
	  switch(command[1]) {
	  case 'a':
	  case 'A':
	    Matched("take");
	    do_get(player, arg1);
	    break;
	  case 'h':
	  case 'H':
	    Matched("throw");
	    do_drop(player, arg1);
	    break;
	  default:
	    goto bad;
	  }
	  break;
        case 'u':
        case 'U':
	  Matched("use");
	  do_use(player,arg1);
	  break;
	case 'w':
	case 'W':
	  switch(command[1]) {
	  case 'h':
	  case 'H':
	    switch(command[2]) {
	    case 'i':
	    case 'I':
	    case '\0':
	      Matched("whisper");
	      do_whisper(player,arg1,arg2);
	      break;
	    case 'o':
	    case 'O':
	      Matched("who");
	      dump_users(player,arg1,arg2,NULL);
	      break;
	    default:
	      goto bad;
	    }
	    break;
	  case '\0':
	    do_whisper(player, arg1, arg2);
	    break;
	  default:
	    goto bad;
	  }
	  break;
#ifdef USE_SPACE /* Commands installed by Michael Majere */
        case '!':
	      switch(command[1]) {
	      case 'b':
	      case 'B':
	        Matched("!boot");
	        do_spaceboot(player);
	        break;
	      case 'c':
	      case 'C':
                  switch(command[2]) {
                  case 'o':
                  case 'O':
                    switch(command[3]) {
                      case 'n':
                      case 'N':
                      Matched("!cont");
                      do_spacecont(player);
                      break;
                    case 'm':
                    case 'M':
                      Matched("!comevent");
                      do_comevent(player,arg1,argv);
                      break;
                    default:
                        goto bad;
                  }
                  break;
                  default:
                        goto bad;
                }
		break;
	      case 'd':
	      case 'D':
		switch(command[2]) {
		case 'a':
		case 'A':
		  Matched("!data");
		  do_spacedata(player, arg1);
		  break;
		case 'o':
		case 'O':
		  Matched("!dock");
		  do_spacedock(player, arg1, arg2);
		  break;
		default:
		  goto bad;
                }
		break;
              case 'e':
	      case 'E':
		switch(command[2]) {
		case 'n':
		case 'N':
	          Matched("!enter");
		  do_spaceenter(player, arg1);
		  break;
		case 'x':
		case 'X':
		  Matched("!exit");
		  do_spaceexit(player, arg1);
		  break;
		default:
		  goto bad;
                }
		break;
              case 'h':
	      case 'H':
		switch(command[2]) {
		case 'a':
		case 'A':
		  Matched("!halt");
		  do_spacehalt(player);
		  break;
	        case 'e':
	        case 'E':
		  Matched("!help");
		  do_spacehelp(player);
		  break;
		case 'y':
		case 'Y':
		  Matched("!hyper");
		  do_spacehyper(player, arg1);
		  break;
		default:
		  goto bad;
                }
		break;
              case 's':
	      case 'S':
		Matched("!senevent");
		do_senevent(player, arg1, argv);
		break;
              case 'v':
	      case 'V':
		Matched("!visevent");
		do_visevent(player, arg1, argv);
		break;
	      case 'w':
	      case 'W':
		Matched("!worm");
		do_spaceworm(player, arg1, argv);
		break;
	      default:
		goto bad;
              }
	      break;
#endif /* USE_SPACE */

	default:
	  goto bad;
	bad:
	  if (!slave && test_set(player,command,arg1,arg2, is_direct)) {
#ifdef LOG_COMMANDS
	    if(command_log) {
	      fputc('.',command_log);
	      fflush(command_log);
	    }
#endif
	    return;
	  }
	  /* try matching user defined functions before chopping */
          match = list_check(db[db[player].location].contents,player,'$',unp)
                  || list_check(db[player].contents,player,'$',unp)
                  || atr_match(db[player].location,player,'$',unp)
		    || list_check(db[db[player].location].exits,player,'$',unp);
	  DOZONE(zon, player)
	    match = list_check(z = zon,player,'$',unp) || match;

          if (!match) {
            notify(player, "Huh?  (Type \"help\" for help.)");

#ifdef LOG_FAILED_COMMANDS
	    if(!controls(player, db[player].location, POW_MODIFY) &&
	       !controls(player, get_zone_first(player), POW_MODIFY) &&
	       *atr_get(get_zone_first(player),A_HUHTO)) {
	      static char buf[2000];
	      sprintf(buf,"%05dFrom %s(%d) in %s(%d) zone %s(%d): %s",
		      get_zone_first(player), /* %05dFrom */
		      db[player].name, player, /*%s(%d) in */
		      db[db[player].location].name, /*%s(*/
		      db[player].location, /* %d) zone */
		      db[get_zone_first(player)].name, get_zone_first(player),/* %s(%d): */
		      unp /* %s */);
	      log_huh(buf);
	    }
#endif /* LOG_FAILED_COMMANDS */
	  }
	  break;
	}
    }
  {int a;for(a=0;a<10;a++)wptr[a]=NULL;}
#ifdef LOG_COMMANDS
  if(command_log) {
    fputc('.',command_log);
    fflush(command_log);
  }
#endif
}

/* get a player's or object's zone */
dbref get_zone_first(player)
     dbref player;
{
  int depth = 10;
  dbref location;

  for (location = player; depth && location!=NOTHING; depth--, location = db[location].location) {
    if (db[location].zone == NOTHING && (Typeof(location)==TYPE_THING
					 || Typeof(location)==TYPE_ROOM)
	&& location != 0 && location != db[0].zone)
      db[location].zone = db[0].zone;
    if (location == db[0].zone)
      return db[0].zone;
    else if (db[location].zone != NOTHING)
      return db[location].zone;
  }
  return db[0].zone;
}

dbref get_zone_next(player)
     dbref player;
{
  if (db[player].zone == NOTHING && player != db[0].zone)
    return db[0].zone;
  
  return db[player].zone;
}

int list_check(thing,player,type,str)
     dbref thing,player;
     int type;
     char *str;
{
  int match=0;
  while(thing!=NOTHING) {
    /* only a player can match on him/herself */
    if (((thing == player) && (Typeof(thing) != TYPE_PLAYER)) ||
	((thing != player) && (Typeof(thing) == TYPE_PLAYER))) {
      thing=db[thing].next;
    } else {
      if (atr_match(thing,player,type,str))
	match=1;
      thing=db[thing].next;
    }
  }
  return(match);
}

/* routine to check attribute list for wild card matches of certain
   type and queue them */
int atr_match(thing,player,type,str)
     dbref thing,player;
     int type; /* must be symbol not affected by compress */
     char *str; /* string to match */
{
  struct all_atr_list *ptr;
  int match=0;

  for(ptr=all_attributes(thing);ptr;ptr=ptr->next)
    if ((ptr->type!=0) && !(ptr->type->flags & AF_LOCK) &&
	(*ptr->value==type)) {
      /* decode it */
      char buff[1024];
      char *s, *p;

      strncpy(buff,uncompress(ptr->value),1024);
      /* search for first un escaped : */
      for(s=buff+1;*s && (*s!=':');s++);
      if (!*s)
	continue;
      *s++=0;
      if (*s == '/') {	/* locked attribute */
	p = ++s;
	while(*s && (*s != '/')) {
	  if (*s == '[') while (*s && (*s != ']')) s++;
	  s++;
	}
	if (!*s) continue;
	*s++ = '\0';
	if (!eval_boolexp(player, thing, p, get_zone_first(player))) continue;
      }
      if (wild_match(buff+1,str)) {
	match = 1;
	if(!eval_boolexp(player,thing,atr_get(thing,A_ULOCK),get_zone_first(player)))
	  did_it(player,thing,A_UFAIL,NULL,A_OUFAIL,NULL,A_AUFAIL);
	else parse_que(thing,s,player);
      }
    }
  return(match);
}

int Live_Player(thing)
     dbref thing;
{
  if ((Typeof(thing)==TYPE_PLAYER) && (db[thing].flags & PLAYER_CONNECT)) {
    return(1);
  } else {
    return(0); }
}

int Live_Puppet(thing)
     dbref thing;
{
  if (db[thing].flags&PUPPET &&
      (IS(thing, TYPE_PLAYER, PLAYER_CONNECT)
       || IS(db[thing].owner, TYPE_PLAYER, PLAYER_CONNECT))) {
    return(1);
  } else {
   return(0); }
}

int Listener(thing)
     dbref thing;
{
/*  ALIST *ptr; */
  struct all_atr_list *ptr;
  ATTR *type;
  char *s;

  /* if (((Typeof(thing)==TYPE_PLAYER) && (db[thing].flags & PLAYER_CONNECT))
      || (db[thing].flags & PUPPET))
    return(1);
      for(ptr=db[thing].list;ptr;ptr=AL_NEXT(ptr)) {*/
  for(ptr=all_attributes(thing); ptr; ptr=ptr->next) {
    /*    type=AL_TYPE(ptr);
	  s=AL_STR(ptr);*/
    type = ptr->type;
    s = ptr->value;
    if (!type)
      continue;
    if (type==A_LISTEN)
      return(1);
    if ((*s=='!') && !(type->flags & AF_LOCK))
      return(1);
  }
  return(0);
}

int Commer(thing)
     dbref thing;
{
/*  ALIST *ptr; */
  struct all_atr_list *ptr;
  ATTR *type;
  char *s;

/*  if (((Typeof(thing)==TYPE_PLAYER) && (db[thing].flags & PLAYER_CONNECT))
      || (db[thing].flags & PUPPET))
    return(1);
      for(ptr=db[thing].list;ptr;ptr=AL_NEXT(ptr)) {*/
  for(ptr=all_attributes(thing); ptr; ptr=ptr->next) {
    /*    type=AL_TYPE(ptr);
	  s=AL_STR(ptr);*/
    type = ptr->type;
    s = ptr->value;
    if (!type)
      continue;
    if (*s=='$')
      return(1);
  }
  return(0);
}

int Hearer(thing)
     dbref thing;
{
  if (Live_Player(thing) || Live_Puppet(thing) || Listener(thing)) {
    return(1);
} else {
  return(0); }
}

int Active(thing)
  dbref thing;
  {
    if (Live_Player(thing) || Live_Puppet(thing) || Listener(thing) ||
	Commer(thing)) {
      return(1);
    } else {
      return(0); }
  }

#undef Matched

void exit_nicely(int i)
{
  remove_muse_pid();
#ifdef MALLOCDEBUG
  mnem_writestats();
#endif
  exit(i);
}
/* End game.c */