/*
 * Rooms.c
 */

#include <stdlib.h>
#include <ctype.h>
#include <memory.h>
#include <string.h>

#include "config.h"
#include "player.h"
#include "fix.h"
#include "dynamic.h"

/* externs */

extern player       *find_player_absolute_quiet(char *);
extern void         to_room1(room *, char *, player *);
extern void         to_room2(room *, char *, player *, player *);
extern saved_player *find_saved_player();
extern char         *store_string(), *store_int(), *store_word();
extern char         *get_string(), *get_int(), *get_word();
extern char         *end_string(), *next_space();
extern void         match_commands(), sub_command(), view_sub_commands(),
                    pstack_mid();
extern struct       command room_list[];
extern struct       command keyroom_list[];
extern player       *find_player_global(), *find_player_global_quiet(),
                    *create_player();
extern file         load_file();
extern list_ent     *fle_from_save(), *find_list_entry();
extern int          global_tag();
extern char         *tag_string(), *name_string();
extern void         set_update();
extern saved_player *find_top_player();
extern dfile        *dynamic_init(char *,int);
extern room         *colony, *comfy, *boot_room;

/* interns */

void                do_room_inform(player *, room *, int);
void                do_str_inform(player *, char *);
void                delete_room(player *p,char *str);

dfile *room_df;

/* change decompress room to get from disk */

int decompress_room(room *r)
{
    int length;
    char *oldstack,*tmp;
    oldstack=stack;
    if (!(r->flags&COMPRESSED)) return 1;

/*    printf("DEcompress key = %d, id = %s\n",r->data_key,r->id); */
    length=dynamic_load(room_df,r->data_key,stack);
    if (length<=0) {
      current_room=r;
      delete_room(current_player,0);
      return 0;
    }
    tmp=stack;
    stack+=length;

    tmp=get_string(stack,tmp);
    length=strlen(stack)+1;
    r->text.length=length;
    if (r->text.where) FREE(r->text.where);
    r->text.where=(char *)MALLOC(length);
    strcpy(r->text.where,stack);

    tmp=get_string(stack,tmp);
    length=strlen(stack)+1;
    if (length==1) {
      r->exits.length=0;
      r->exits.where=0;
    }
    else {
      r->exits.length=length;
      if (r->exits.where) FREE(r->exits.where);
      r->exits.where=(char *)MALLOC(length);
      strcpy(r->exits.where,stack);
    }
    tmp=get_string(stack,tmp);
    length=strlen(stack)+1;
    if (length==1) {
      r->automessage.length=0;
      r->automessage.where=0;
    }
    else {
      r->automessage.length=length;
      if (r->automessage.where) FREE(r->automessage.where);
      r->automessage.where=(char *)MALLOC(length);
      strcpy(r->automessage.where,stack);
    }
    r->flags &= ~(COMPRESSED|ROOM_UPDATED);
    stack=oldstack;
    return 1;
}


/* and the compress room chugs to the disk */

void compress_room(room *r) {
  int length;
  char *oldstack;
  oldstack=stack;

  if (r->flags&COMPRESSED) return;
  if (r->owner && r->owner->residency==STANDARD_ROOMS) return;
/*  printf("compress key = %d, id = %s\n",r->data_key,r->id); */
  if (r->flags&ROOM_UPDATED) {
    if (r->text.where) stack=store_string(stack,r->text.where);
    else stack=store_string(stack,"");
    if (r->exits.where) stack=store_string(stack,r->exits.where);
    else stack=store_string(stack,"");
    if (r->automessage.where) stack=store_string(stack,r->automessage.where);
    else stack=store_string(stack,"");
    length=(int)stack-(int)oldstack;
    r->data_key=dynamic_save(room_df,oldstack,length,r->data_key);
  }
  if (r->text.where) FREE(r->text.where);
  r->text.where=0;
  r->text.length=0;
  if (r->exits.where) FREE(r->exits.where);
  r->exits.where=0;
  r->exits.length=0;
  if (r->automessage.where) FREE(r->automessage.where);
  r->automessage.where=0;
  r->automessage.length=0;
  r->flags |= COMPRESSED;
  r->flags &= ~ROOM_UPDATED;
  stack=oldstack;
 }


 /* decompress room text */

void old_decompress_room(room *r)
{
    int length;
    if (!(r->flags&COMPRESSED)) return;
    (void) get_string(stack,r->text.where);
    length=strlen(stack)+1;
    r->text.length=length;
    if (r->text.where) FREE(r->text.where);
    r->text.where=(char *)MALLOC(length);
    strcpy(r->text.where,stack);

    if (r->exits.where) {
   (void) get_string(stack,r->exits.where);
   length=strlen(stack)+1;
   r->exits.length=length;
   FREE(r->exits.where);
   r->exits.where=(char *)MALLOC(length);
   strcpy(r->exits.where,stack);
    }
    if (r->automessage.where) {
   (void) get_string(stack,r->automessage.where);
   length=strlen(stack)+1;
   r->automessage.length=length;
   FREE(r->automessage.where);
   r->automessage.where=(char *)MALLOC(length);
   strcpy(r->automessage.where,stack);
    }
    r->flags &= ~COMPRESSED;
}

/* creates a new standard room */

room *create_room(player * p)
{
   room *r, *scan;
   saved_player   *sp;
   int             number, home = 1, unique = 1;
   char            id[MAX_ID];
   sp = p->saved;
   if (!sp)
   {
      tell_player(p, " You must save first before you can create a room.\n");
      return 0;
   }
   sprintf(id, "room.%d", unique);
   do
   {
      for (scan = sp->rooms, number = 1; scan; number++, scan = scan->next)
      {
    if (!strcmp(scan->id, id))
    {
       unique++;
       sprintf(id, "room.%d", unique);
       break;
    }
    if (scan->flags & HOME_ROOM)
       home = 0;
      }
   } while (scan);

   if (number > p->max_rooms)
   {
      tell_player(p, " Can't create room, reached max room limit.\n");
      return 0;
   }
   r = (room *) MALLOC(sizeof(room));
   memset(r, 0, sizeof(room));
   strcpy(r->id, id);
   sprintf(r->name, "in somewhere belonging to %s.", p->name);
   sprintf(r->enter_msg, "goes to a room belonging to %s.", p->name);
   r->flags = (home * HOME_ROOM)|ROOM_UPDATED;
   sprintf(stack, "\n A bare room, belonging to %s.\n"
      " Isn't it time to write a description ?\n", p->name);
   number = strlen(stack) + 1;
   r->text.where = (char *) MALLOC(number);
   memcpy(r->text.where, stack, number);
   r->text.length = number;
   r->exits.length = 0;
   r->exits.where = 0;
   r->auto_base = 30;
   r->automessage.length = 0;
   r->automessage.where = 0;
   r->owner = sp;
   r->players_top = 0;
   r->next = sp->rooms;
   sp->rooms = r;
   r->flags |= ROOM_UPDATED;
   return r;
}

 /* destroy all the room data */

 void free_room_data(saved_player *sp)
 {
   room *room_list,*next;
   if (!sp->rooms) return;
   room_list=sp->rooms;
   while(room_list) {
     next=room_list->next;
     if (room_list->text.where) FREE(room_list->text.where);
     if (room_list->exits.where)  FREE(room_list->exits.where);
     if (room_list->automessage.where)  FREE(room_list->automessage.where);
     dynamic_free(room_df,room_list->data_key);
     FREE(room_list);
     room_list=next;
   }
   sp->rooms=0;
 }

/* collect all the room data ready for saving */

 void construct_room_save(saved_player *sp)
 {
   room *room_list;
   char *tmpstack;
   int length;
   for(room_list=sp->rooms;room_list;room_list=room_list->next) {
     if (!room_list->players_top || (sys_flags&(SHUTDOWN|PANIC)))
       compress_room(room_list);
     tmpstack=stack;
     stack+=4;
     stack=store_string(stack,room_list->name);
     stack=store_string(stack,room_list->id);
     stack=store_string(stack,room_list->enter_msg);
     stack=store_int(stack,room_list->auto_base);
     stack=store_int(stack,room_list->flags);
     stack=store_int(stack,room_list->data_key);
     length=(int)stack-(int)tmpstack;
     (void) store_int(tmpstack,length);
   }
   stack=store_int(stack,0);
 }

/* retrieve room data from a save file */

char *retrieve_room_data(saved_player *sp,char *where)
{
    int length;
    room *r,**last;
    free_room_data(sp);
    last=&sp->rooms;
    where=get_int(&length,where);
    for(;length;where=get_int(&length,where)) {
   r=(room *)MALLOC(sizeof(room));
   memset(r,0,sizeof(room));
   where=get_string(r->name,where);
   where=get_string(r->id,where);
   where=get_string(r->enter_msg,where);
   where=get_int(&r->auto_base,where);
   where=get_int(&r->flags,where);
        where=get_int(&r->data_key,where);
/*
   if (r->flags&OPEN)
     printf("[%s.%s]\t%s\n",sp->lower_name,r->id,r->name);
   else
     printf("[%s.%s]\t%s (CLOSED)\n",sp->lower_name,r->id,r->name);
  */
        r->flags|=COMPRESSED;
   *last=r;
   last=&r->next;
   r->owner=sp;
   r->players_top=0;
   r->next=0;
    }
    *last=0;
    return where;
}
 
 /* the old retrieve room data routine with a decompress added
 
char *retrieve_room_data(saved_player *sp,char *where)
{
    int length;
    room *r,**last;
    free_room_data(sp);
    last=&sp->rooms;
    where=get_int(&length,where);
    for(;length;where=get_int(&length,where)) {
   r=(room *)MALLOC(sizeof(room));
   memset(r,0,sizeof(room));
   where=get_string(r->name,where);
   where=get_string(r->id,where);
   where=get_string(r->enter_msg,where);
   where=get_int(&r->auto_base,where);
   where=get_int(&r->flags,where);
   where=get_int(&r->text.length,where);
   r->text.where=(char *)MALLOC(r->text.length);
   memcpy(r->text.where,where,r->text.length);
   where+=r->text.length;
   where=get_int(&r->exits.length,where);
   if (!r->exits.length) r->exits.where=0;
   else {
       r->exits.where=(char *)MALLOC(r->exits.length);
       memcpy(r->exits.where,where,r->exits.length);
       where+=r->exits.length;
   }
   where=get_int(&r->automessage.length,where);
   if (!r->automessage.length) r->automessage.where=0;
   else {
       r->automessage.where=(char *)MALLOC(r->automessage.length);
       memcpy(r->automessage.where,where,r->automessage.length);
       where+=r->automessage.length;
   }
   *last=r;
   last=&r->next;
   r->owner=sp;
   r->players_top=0;
   r->next=0;
   old_decompress_room(r);
   r->flags |= ROOM_UPDATED;
    }
    return where;
    *last=0;
}*/

/* convert a room string into an actual room */

room *convert_room_verbose(player *p,char *str,int verbose)
{
  char *scan,*oldstack;
  saved_player *sp;
  room *r;
  
  oldstack=stack;
  scan=str;
  while(*scan && *scan!='.')
    *stack++=*scan++;
  if (!*scan)
    {
      if (verbose)
	tell_player(p," Room IDs should be of the form <owner-name>."
		    "<roomid>\n");
      stack=oldstack;
      return 0;
    }
  *stack++=0;
  scan++;
  if (!*oldstack)
    strcpy(oldstack,p->name);
  lower_case(oldstack);
  sp=find_saved_player(oldstack);
  if (!sp)
    {
      if (verbose)
	{
          sprintf(oldstack," Can't find player for room '%s'.\n",str);
          stack=end_string(oldstack);
          tell_player(p,oldstack);
	}
      stack=oldstack;
      return 0;
    }
  strcpy(oldstack,scan);
  lower_case(oldstack);
  stack=end_string(oldstack);
  r=sp->rooms;
  while(r)
    {
      strcpy(stack,r->id);
      lower_case(stack);
      if (!strcmp(stack,oldstack))
	{
	  stack=oldstack;
	  current_room=r;
	  if (!decompress_room(r))
	    return 0;
	  return r;
	}
      if (!sp)
	{
	  if (verbose)
	    {
	      sprintf(oldstack, " Can't find player for room '%s'.\n",str);
	      stack=end_string(oldstack);
	      tell_player(p,oldstack);
	    }
	  stack=oldstack;
	  return 0;
	}
      strcpy(oldstack,scan);
      lower_case(oldstack);
      stack=end_string(oldstack);
      r=sp->rooms;
      while(r)
	{
	  strcpy(stack,r->id);
	  lower_case(stack);
	  if (!strcmp(stack,oldstack))
	    {
	      stack=oldstack;
	      current_room=r;
	      if (!decompress_room(r))
		return 0;
	      return r;
	    }
	  r=r->next;
	}
      if (verbose)
	{
	  sprintf(oldstack," Can't find room '%s'.\n",scan);
	  stack=end_string(oldstack);
	  tell_player(p,oldstack);
	}
      stack=oldstack;
      return 0;
    }
  return r;
}

room           *convert_room(player *p, char *str)
{
   return convert_room_verbose(p, str, 1);
}


/* create a new room  the player command */

void create_new_room(player * p, char *str)
{
   room *r;
   char *oldstack;

   oldstack = stack;
   r = create_room(p);
   if (r)
   {
      sprintf(oldstack, " New room created with an id of %s.%s\n", p->name,
         r->id);
      stack = end_string(oldstack);
      tell_player(p, oldstack);
   }
   stack = oldstack;
}


/* add an exit to a room */

void add_exit(player * p, char *str)
{
   room *r;
   char *oldstack, *scan, *test;
   int count = 1;

   oldstack = stack;
   if (!current_room)
   {
      tell_player(p, " Strange, you don't actually seem to be anywhere ?!\n");
      return;
   }
   r = current_room;
   if (!convert_room(p, str))
      return;
   if (r == current_room)
   {
      tell_player(p, " You can't make a link from a room to itself.\n");
      return;
   }
   sprintf(stack, "%s.%s\n", current_room->owner->lower_name, current_room->id);
   lower_case(stack);
   stack = end_string(stack);

   scan = r->exits.where;
   test = stack;
   if (scan)
   {
      for (; *scan; count++, stack = test)
      {
         while (*scan != '\n')
            *stack++ = *scan++;
         *stack++ = '\n';
         *stack++ = 0;
         *scan++;
         if (!strcmp(test, oldstack))
         {
            tell_player(p, " There already exists an exit to that room.\n");
            stack = oldstack;
            return;
         }
      }
   }
   if (count >= 3 && strcmp(p->lower_name, p->location->owner->lower_name)
          && !(p->residency & ADMIN))
   {
      tell_player(p, " Sorry, there are already 3 exits to this room.\n");
      stack = oldstack;
      return;
   }
   if (count > p->max_exits)
   {
      tell_player(p, " Sorry, you have reached you maximum exit limit "
                     "in this room.\n");
      stack = oldstack;
      return;
   }
   if (r->exits.where)
      strcat(oldstack, r->exits.where);
   r->exits.length = strlen(oldstack) + 1;
   if (r->exits.where)
      FREE(r->exits.where);
   r->exits.where = (char *) MALLOC(r->exits.length);
   strcpy(r->exits.where, oldstack);
   r->flags |= ROOM_UPDATED;
   tell_player(p, " New exit added.\n");
   stack = oldstack;
}


/* remove exit */

void            remove_exit_verbose(player * p, char *str, int verbose)
{
   char           *exits, *oldstack, *last;
   room           *r;
   oldstack = stack;
   if (!current_room)
   {
      tell_player(p, " Strange, you don't seem to be anywhere.\n");
      return;
   }
   r = current_room;
   exits = r->exits.where;
   if (!exits)
   {
      tell_player(p, " This room has no exits to delete.\n");
      return;
   }
   lower_case(str);
   while (*exits)
   {
      last = stack;
      while (*exits != '\n')
    *stack++ = *exits++;
      *stack++ = 0;
      if (!strcmp(last, str))
    break;
      if (convert_room_verbose(p, last, verbose))
      {
    strcpy(stack, current_room->id);
    lower_case(stack);
    if (!strcmp(str, stack))
       break;
      }
      *(--stack) = '\n';
      stack++;
      exits++;
   }
   if (!*exits)
   {
      if (verbose)
    tell_player(p, " No such exit to remove.\n");
      else
      {
    stack = oldstack;
    sprintf(stack, "auto-remove exit- '%s':", str);
    stack = strchr(stack, 0);
    sprintf(stack, " room: %s.%s", p->location->owner->lower_name,
       p->location->id);
    stack = end_string(stack);
    log("error", oldstack);
    stack = oldstack;
    *stack = 0;
      }
      stack = oldstack;
      return;
   }
   exits++;
   stack = last;
   while (*exits)
      *stack++ = *exits++;
   *stack++ = 0;
   r->exits.length = strlen(oldstack) + 1;
   if (r->exits.where)
      FREE(r->exits.where);
   if (r->exits.length == 1)
   {
      r->exits.where = 0;
      r->exits.length = 0;
   } else
   {
      r->exits.where = (char *) MALLOC(r->exits.length);
      strcpy(r->exits.where, oldstack);
   }
   r->flags |= ROOM_UPDATED;
   if (verbose)
      tell_player(p, " Exit removed.\n");
   stack = oldstack;
}

void            remove_exit(player * p, char *str)
{
   remove_exit_verbose(p, str, 1);
}

/* quick check to view stuff about a room */

void            check_room(player * p, char *str)
{
   char           *oldstack;
   room           *r;
   oldstack = stack;
   r = current_room;
   if (!r)
   {
      tell_player(p, " Strange ! You don't appear to be anywhere.\n");
      return;
   }
   sprintf(stack, " [ %s.%s ]\n %s\n Someone %s\n",
      r->owner->lower_name, r->id, r->name, r->enter_msg);
   stack = strchr(stack, 0);
   if (r->flags & LOCKABLE)
   {
      strcpy(stack, " This room is lockable by everybody.\n");
      stack = strchr(stack, 0);
   }
   if (r->flags & LINKABLE)
   {
      strcpy(stack, " This room is linkable by everyone.\n");
      stack = strchr(stack, 0);
   }
   if (r->flags & KEYLOCKED)
   {
      strcpy(stack, " This room is locked to those with keys.\n");
      stack = strchr(stack, 0);
   }
   if (r->flags & LOCKED)
   {
      strcpy(stack, " This room is locked.\n");
      stack = strchr(stack, 0);
   }
   if (r->flags & OPEN)
   {
      strcpy(stack, " This room is open.\n");
      stack = strchr(stack, 0);
   }
   *stack++ = 0;
   tell_player(p, oldstack);
   stack = oldstack;
}

/* check all the exits from a room */

void            check_exits(player * p, char *str)
{
   char           *exits, *scan, *oldstack, *text, *end, *mark;
   int             count = 0, fill = 0, temp = 0;
   room           *r;
   oldstack = stack;
   if (!current_room)
   {
      tell_player(p, " Hmm, that room doesn't exist.\n");
      return;
   }
   if (!decompress_room(current_room))
   {
      tell_player(p, " Eeek! Where did that room go?\n");
      return;
   }
   exits = current_room->exits.where;
   if (!exits)
   {
      tell_player(p, " This room has no exits.\n");
      return;
   }
   while (*exits)
   {
      while (*exits && *exits != '\n')
    *stack++ = *exits++;
      if ((*exits) == '\n')
    exits++;
      *stack++ = 0;
      count++;
   }
   end = stack;
   text = stack;
   temp = count;
   for (scan = oldstack; count > 0; count--)
   {
      r = convert_room_verbose(p, scan, 0);
      if (!r)
      {
    /*
     * erase a dud link (I hope)  mark=stack; stack=end;
     * remove_exit_verbose(p,scan,0); temp--; stack=mark;
     * stack=strchr(stack,0);
     */

    sprintf(stack, " Found a dud link to '%s'.\n", scan);
    stack = strchr(stack, 0);
      } else
      {
    for (fill = strlen(r->id); fill < MAX_ID; fill++)
       *stack++ = ' ';
    sprintf(stack, "%s -", r->id);
    stack = strchr(stack, 0);
    if (!possible_move(p, r, 0))
    {
       if (r->flags & LOCKED)
          *stack++ = 'L';
       else
          *stack++ = ' ';
    } else
       *stack++ = '>';
    sprintf(stack, " %s\n", r->name);
    stack = strchr(stack, 0);
      }
      scan = end_string(scan);
   }
   if (temp == 1)
      strcpy(stack, "\n There is one exit to this place.\n\n");
   else if (temp == 0)
      strcpy(stack, "\n There are no exits from here\n\n");
   else
      sprintf(stack, "\n There are %s exits from here.\n\n",
         number2string(temp));
   stack = strchr(stack, 0);

   *stack++ = 0;
   tell_player(p, text);
   stack = oldstack;
}

/* add an automessage to a room  (based around add exit) */

void            add_auto(player * p, char *str)
{
   room           *r;
   char           *oldstack, *scan;
   int             count = 0;

   oldstack = stack;
   if (!*str)
   {
      tell_player(p, " Format +auto <string>\n");
      return;
   }
   if (!current_room)
   {
      tell_player(p, " Strange, you don't actually seem to be anywhere ?!\n");
      return;
   }
   r = current_room;
   if (strlen(str) > MAX_AUTOMESSAGE)
   {
      tell_player(p, " Thats a bit long isnt it ? Try something shorter ..\n");
      return;
   }
   while (*str)
      *stack++ = *str++;
   *stack++ = '\n';
   if (r->automessage.where)
   {
      for (scan = r->automessage.where; *scan; count++)
      {
         while (*scan != '\n')
            *stack++ = *scan++;
         *stack++ = *scan++;
      }
   }
   *stack++ = 0;
   if (count >= p->max_autos)
   {
      tell_player(p, " Sorry but you have already reached your maximum "
        "number of automessages.\n");
      stack = oldstack;
      return;
   }
   r->automessage.length = strlen(oldstack) + 1;
   if (r->automessage.where)
      FREE(r->automessage.where);
   r->automessage.where = (char *) MALLOC(r->automessage.length);
   strcpy(r->automessage.where, oldstack);
   r->flags |= ROOM_UPDATED;
   tell_player(p, " New message added.\n");
   stack = oldstack;
}


/* remove auto message */

void            remove_auto(player * p, char *str)
{
   char           *oldstack, *scan;
   int             count;
   room           *r;
   oldstack = stack;
   r = current_room;
   if (!r)
   {
      tell_player(p, " Strange, you don't seem to be anywhere.\n");
      return;
   }
   count = atoi(str);
   if (!count)
   {
      tell_player(p, " Format: -auto <number>\n");
      return;
   }
   scan = r->automessage.where;
   if (!scan)
   {
      tell_player(p, " No automessages in this room to delete.\n");
      return;
   }
   for (scan = r->automessage.where; count > 1; count--)
      if (!*scan)
      {
    tell_player(p, " No automessage of that number.\n");
    stack = oldstack;
    return;
      } else
      {
    while (*scan != '\n')
       *stack++ = *scan++;
    *stack++ = *scan++;
      }

   while (*scan != '\n')
      scan++;
   scan++;

   while (*scan)
      *stack++ = *scan++;
   *stack++ = 0;

   r->automessage.length = strlen(oldstack) + 1;
   if (r->automessage.where)
      FREE(r->automessage.where);
   if (r->automessage.length == 1)
   {
      r->automessage.where = 0;
      r->automessage.length = 0;
   } else
   {
      r->automessage.where = (char *) MALLOC(r->automessage.length);
      strcpy(r->automessage.where, oldstack);
   }
   r->flags |= ROOM_UPDATED;
   tell_player(p, " Message removed.\n");
   stack = oldstack;
}

/* list automessages */

void            check_autos(player * p, char *str)
{
   char           *oldstack, *scan;
   int             number = 1;

   oldstack = stack;

   scan = current_room->automessage.where;
   if (!scan)
   {
      tell_player(p, " This room has no automessages.\n");
      return;
   }
   if (current_room->flags & AUTO_MESSAGE)
      strcpy(stack, " Automessages are currently turned on.\n\n");
   else
      strcpy(stack, " Automessages are currently off ...\n");
   stack = strchr(stack, 0);
   sprintf(stack, " Minimum time for an automessage set to %d seconds\n\n",
      current_room->auto_base);
   stack = strchr(stack, 0);
   while (*scan)
   {
      sprintf(stack, " [%d] ", number);
      stack = strchr(stack, 0);
      while (*scan != '\n')
    *stack++ = *scan++;
      *stack++ = *scan++;
      number++;
   }
   *stack++ = 0;
   tell_player(p, oldstack);
   stack = oldstack;
}

/* auto command */

void            autos_com(player * p, char *str)
{
   if (!strcasecmp("on", str))
   {
      current_room->flags |= AUTO_MESSAGE;
      tell_player(p, " Auto messages turned on in this room.\n");
      current_room->auto_count = 10 + (rand() & 63);
      return;
   }
   if (!strcasecmp("off", str))
   {
      current_room->flags &= ~AUTO_MESSAGE;
      tell_player(p, " Auto messages turned off in this room.\n");
      return;
   }
   check_autos(p, str);
}


/* the check room command */

void            check_rooms(player * p, char *str)
{
    /* NOTE: system players, those players to whom the system rooms
       belong, do NOT seem to have a complete player record available.
       There are several bodges in here to avoid printing nonsense
       values. */

   saved_player   *sp;
   char           *oldstack, *cpy;
   int             count = 0;
   room           *scan;
   player         *in;
   player dummy;

   oldstack = stack;
   if (*str && p->residency & (SU | ADMIN))
   {
      strcpy(stack, str);
      lower_case(stack);
      sp = find_saved_player(stack);
   } else
      sp = p->saved;
   if (!sp)
   {
      tell_player(p, " You have no save information, and therefore, no "
        "rooms either.\n");
      return;
   }
   strcpy(dummy.lower_name, sp->lower_name);
   dummy.fd = p->fd;
   load_player(&dummy);
   /* bodge to avoid crap being displayed as the name if the name
      being checked is a system room name */
   if (dummy.residency & SYSTEM_ROOM)
       strcpy(dummy.name, dummy.lower_name);

   for (scan = sp->rooms; scan; scan = scan->next)
      count++;
   if (p->saved == sp)
      sprintf(stack, " You have created %d out of a maximum of %d rooms.\n",
         count, p->max_rooms);
   else
       /* avoid printing crap as the room limit if a system player */
       if (dummy.residency & SYSTEM_ROOM)
	   sprintf(stack, " %s has created %d rooms.\n",
		   dummy.name, count);
       else
	   sprintf(stack, " %s has created %d rooms, from a maximum of %d.\n",
		   dummy.name, count, dummy.max_rooms);
   stack = strchr(stack, 0);
   if (count)
   {
      strcpy(stack, "\n [NO.] [ID]            hLBOAlE  [NAME]\n");
      stack = strchr(stack, 0);
      for (scan = sp->rooms; scan; scan = scan->next)
      {
         for (count = 0, in = scan->players_top; in; in = in->room_next)
            count++;
         sprintf(stack, " [%d]", count);
         for (count = 0; *stack; stack++)
            count++;
         for (; count < 6; count++)
            *stack++ = ' ';
         for (count = 0, cpy = scan->id; *cpy; count++)
            *stack++ = *cpy++;
         for (; count < MAX_ID; count++)
            *stack++ = ' ';
         *stack++ = ' ';
         if (scan->flags & HOME_ROOM)
            *stack++ = 'h';
         else
            *stack++ = '-';
         if (scan->flags & LOCKED)
            *stack++ = 'L';
         else
            *stack++ = '-';
         if (scan->flags & KEYLOCKED)
            *stack++ = 'B';
         else
            *stack++ = '-';
         if (scan->flags & OPEN)
            *stack++ = 'O';
         else
            *stack++ = '-';
         if (scan->flags & LOCKABLE)
            *stack++ = 'A';
         else
            *stack++ = '-';
         if (scan->flags & LINKABLE)
            *stack++ = 'l';
         else
            *stack++ = '-';
         if (scan->flags & CONFERENCE)
            *stack++ = 'E';
         else
            *stack++ = '-';
         *stack++ = ' ';
         for (cpy = scan->name; *cpy;)
            *stack++ = *cpy++;
         *stack++ = '\n';
      }
   }
   *stack++ = 0;
   tell_player(p, oldstack);
   stack = oldstack;
}

static char    *keycommands[] = {"commands", "exits", "check", "lock", "lockable",
   "linkable", "open", "entermsg", "+exit", "-exit", "info",
"name", "look", "go", "trans", "?", "help", 0};

/* the room command */

void            room_command(player * p, char *str)
{
   char           *rol;
   list_ent       *l;
   saved_player   *sp;

   if (p->edit_info)
   {
      tell_player(p, " Can't do room commands whilst in editor.\n");
      return;
   }
   if ((*str == '/') && (p->input_to_fn == room_command))
   {
      match_commands(p, str + 1);
      if (!(p->flags & PANIC) && (p->input_to_fn == room_command))
      {
         do_prompt(p, " Room Mode >");
         p->mode |= ROOMEDIT;
      }
      return;
   }
   if (*str == '@')
   {
      rol = next_space(str);
      *rol++ = 0;
      if (!convert_room(p, str + 1))
         return;
   } else
   {
      rol = str;
      current_room = p->location;
   }
   if (!*rol)
   {
      if (p->input_to_fn == room_command)
      {
         tell_player(p, " Format: (room) <action>\n");
         if (!(p->flags & PANIC) && (p->input_to_fn == room_command))
         {
            do_prompt(p, " Room Mode >");
            p->mode |= ROOMEDIT;
         }
         return;
      } else
      {
         tell_player(p, " Entering room mode. Use 'end' to leave.\n"
                        " '/<command>' does normal commands.\n");
         p->flags &= ~PROMPT;
         p->input_to_fn = room_command;
      }
   } else
   {
      sp = p->saved;
      l = fle_from_save(current_room->owner, p->lower_name);
      if (!l && p->residency & SU)
	l = fle_from_save(current_room->owner,"sus");
      if (!l && p->residency == NON_RESIDENT)
	l = fle_from_save(current_room->owner,"newbies");
      if (!l)
	l = fle_from_save(current_room->owner,"everyone");

      if ((current_room->flags & LINKABLE) && (!strncmp("+exit", rol, 5)) &&
           (!l || !(l->flags & KEY)))
         sub_command(p, rol, room_list);
      else if ((current_room->owner != sp) && !(p->residency & ADMIN)
          && strcasecmp("end", rol) && strcasecmp("create", rol))
      {
         if (l && l->flags & KEY)
         {
            int             scan;
            char           *found_space;
            found_space = (char *) strchr(rol, ' ');
            if (found_space)
               *found_space = 0;
            for (scan = 0; (scan != -1) && keycommands[scan]; scan++)
               if (!strcasecmp(keycommands[scan], rol))
               {
                  if (found_space)
                     *found_space = ' ';
                  sub_command(p, rol, keyroom_list);
                  scan = -2;
               }
            if (scan != -1)
            {
               if (found_space)
                  *found_space = ' ';
               tell_player(p, " You cannot do room operations on a "
                              "room that isn't yours.\n");
            }
         } else
         {
            tell_player(p, " You cannot do room operations on a room "
                             "that isn't yours.\n");
         }
      } else
         sub_command(p, rol, room_list);
   }
   if (!(p->flags & PANIC) && (p->input_to_fn == room_command))
   {
      do_prompt(p, "Room Mode >");
      p->mode |= ROOMEDIT;
   }
}

/* view room commands */

void            view_room_commands(player * p, char *str)
{
   view_sub_commands(p, room_list);
}

/* Key sub-commands */

void            view_room_key_commands(player * p, char *str)
{
   view_sub_commands(p, keyroom_list);
}


/* exit room mode */

void            exit_room_mode(player * p, char *str)
{
   if (p->input_to_fn != room_command)
      return;
   tell_player(p, " Leaving room mode.\n");
   p->input_to_fn = 0;
   p->flags |= PROMPT;
   p->mode &= ~ROOMEDIT;
}


/* change the name of a room */

void            change_room_name(player * p, char *str)
{
   char           *oldstack;
   oldstack = stack;
   if (!*str)
   {
      sprintf(stack, " Current name of this room is ...\n%s\n",
         current_room->name);
      stack = end_string(stack);
      tell_player(p, oldstack);
      stack = oldstack;
      return;
   }
   if (!current_room)
      return;
   if ((strlen(str) + 1) >= MAX_ROOM_NAME)
   {
      tell_player(p, " Sorry that name is too long.\n");
      stack = oldstack;
      return;
   }
   strncpy(current_room->name, str, MAX_ROOM_NAME - 1);
   sprintf(stack, " The name of room %s.%s has been changed to ...\n"
      "%s\n", p->name, current_room->id, current_room->name);
   stack = end_string(oldstack);
   tell_player(p, oldstack);
   stack = oldstack;
}

/* change the id of a room */

void            change_room_id(player * p, char *str)
{
   char           *oldstack, *check;
   room           *scan;
   oldstack = stack;
   if (!*str)
   {
      sprintf(stack, " Current id for this room is %s.%s\n",
         current_room->owner->lower_name, current_room->id);
      stack = end_string(stack);
      tell_player(p, oldstack);
      stack = oldstack;
      return;
   }
   if (!current_room)
      return;
   strcpy(stack, str);
   lower_case(stack);
   stack = end_string(stack);
   scan = current_room->owner->rooms;
   for (; scan; scan = scan->next)
   {
      strcpy(stack, scan->id);
      lower_case(stack);
      if (!strcmp(stack, oldstack))
      {
    tell_player(p, " A room with that ID already exists.\n");
    stack = oldstack;
    return;
      }
   }
   if ((strlen(str) + 1) >= MAX_ID)
   {
      tell_player(p, " Sorry that name is too long.\n");
      stack = oldstack;
      return;
   }
   for (check = str; *check; check++)
      if (!(isalpha(*check) || isdigit(*check)))
      {
         tell_player(p, " A room-id can contain alphanumeric characters"
                        " only.\n");
         stack = oldstack;
         return;
      }
   strncpy(current_room->id, str, MAX_ID - 1);
   sprintf(oldstack, " The id of the room is now %s.%s\n", p->name,
      current_room->id);
   stack = end_string(oldstack);
   tell_player(p, oldstack);
   stack = oldstack;
}


/* change the entermsg of a room */

void            change_room_entermsg(player * p, char *str)
{
   char           *oldstack;
   oldstack = stack;
   if (!*str)
   {
      sprintf(stack, " Current enter message for this room is ...\n"
                     " Someone %s\n",
         current_room->enter_msg);
      stack = end_string(stack);
      tell_player(p, oldstack);
      stack = oldstack;
      return;
   }
   if (!current_room)
      return;
   strncpy(current_room->enter_msg, str, MAX_ENTER_MSG - 2);
   sprintf(oldstack, " The enter message for this room is now set to ...\n"
      " Someone %s\n", current_room->enter_msg);
   stack = end_string(oldstack);
   tell_player(p, oldstack);
   stack = oldstack;
}


/* unlink a player from the rooms */

void            unlink_from_room(player * p, char *str)
{
   player         *p2;
   player         *scan, *previous;
   if (*str)
   {
      p2 = find_player_global(str);
      if (!p2)
    return;
      if (p2->residency > p->residency)
      {
    tell_player(p, " You can't do that !!.\n");
    return;
      }
   } else
      p2 = p;
   if (p->location)
   {
      previous = 0;
      scan = p->location->players_top;
      while (scan && scan != p)
      {
    previous = scan;
    scan = scan->room_next;
      }
      if (!scan)
    log("error", "Bad Location list");
      else if (!previous)
    p->location->players_top = p->room_next;
      else
    previous->room_next = p->room_next;
      tell_player(p, " Unlinked from location ...\n");
      return;
   } else
      tell_player(p, " Strange, you don't seem to be anywhere ?!\n");
}

/* the look command */

void            look(player * p, char *str)
{
   room           *r;
   char           *oldstack, *text;
   int             count = 0, i;
   player         *scan, **list;


   r = p->location;
   if (!r)
   {
      tell_player(p, " Strange, you don't seem to actually be anywhere ?!\n");
      return;
   }
   oldstack = stack;

   if (!decompress_room(r))
   {
      tell_player(p, " Eeek, where did that room go?\n");
      return;
   }

   align(stack);
   list = (player **) stack;

   for (scan = r->players_top; scan; scan = scan->room_next)
      if (scan != p)
      {
    *(player **) stack = scan;
    stack += sizeof(player **);
    count++;
      }
   text = stack;

   /* str can be NULL, say when a person logs in */
   if ((str == NULL) || strcmp(str,"-"))
   {
       /* omit room desc if argument is "-" */
       strcpy(stack, r->text.where);
       stack = strchr(stack, 0);
   }

   if (count)
   {
      if (count == 1)
    strcpy(stack, "\n\nThere is only one other person here ...\n");
      else
    sprintf(stack, "\n\nThere are %s other people here ...\n",
       number2string(count));
      stack = strchr(stack, 0);
      if (count > 16)
    construct_name_list(list, count);
      else
    for (i = count; i; i--, list++)
    {
       sprintf(stack, "%s %s\n", (*list)->name, (*list)->title);
       stack = strchr(stack, 0);
    }
   } else
   {
      strcpy(stack, "\n\nThere is nobody here but you.\n");
      stack = strchr(stack, 0);
   }
   *stack++ = 0;
   tell_player(p, text);
   stack = oldstack;
}

/* trans, move without messages */

void trans_to(player *p,char *str)
{
    room *r;
    player *previous,*scan;
    r=convert_room(p,str);
    if (!r)
	return;
    if (r == p->location)
	return;  
    if (p->location)
    {
	previous=0;
	scan=p->location->players_top;
	while(scan && scan!=p)
	{
	    previous=scan;
	    scan=scan->room_next;
	}
	if (!scan)
	    log("error","Bad Location list");
	else if (!previous)
	{
	    p->location->players_top=p->room_next;
	   if (!(p->location->players_top))
	       compress_room(p->location);
	} else
	    previous->room_next=p->room_next;
    }
    p->room_next=r->players_top;
    r->players_top=p;
    p->location=r;
    look(p,0);
}

/* check for possible move */

int             possible_move(player * p, room * r, int verbose)
{
   list_ent       *l;
   if (!strcmp(r->owner->lower_name, p->lower_name))
      return 1;
   l = fle_from_save(current_room->owner, p->lower_name);
   if (!l && p->residency & SU)
     l = fle_from_save(current_room->owner, "sus");
   if (!l && p->residency == NON_RESIDENT)
     l = fle_from_save(current_room->owner, "newbies");
   if (!l)
     l = fle_from_save(current_room->owner, "everyone");

   if ((r->flags & LOCKED && !(l && l->flags & KEY)))
   {
      if (verbose)
    tell_player(p, " You can't enter that place, because it is locked.\n");
      return 0;
   }
   if (r->flags & KEYLOCKED)
   {
      if (verbose)
    tell_player(p, " You can't enter that place, because it is bolted.\n");
      return 0;
   }
   if (l && l->flags & KEY)
      return 1;
   if (!(r->flags & OPEN))
      if (!l || !(l->flags & INVITE))
      {
    if (verbose)
       tell_player(p, " You have no invite to enter that "
         "place.\n");
    return 0;
      }
   if (l && l->flags & BAR)
   {
      if (verbose)
    tell_player(p, " You have been barred from entering "
           "that place.\n");
      return 0;
   }
   return 1;
}


/* normal move routine, with messages */
/* moveflag is 0:normal  1:grab  */

void move_to(player * p, char *str, int moveflag)
{
   room *r, *old_room;
   player *previous, *scan, *old_current;
   char *oldstack;

   oldstack = stack;
   r = convert_room(p, str);
   if (!r)
      return;
   if (r == p->location)
   {
      tell_player(p, " But you're already there!\n");
      return;
   }
   if (!(command_type & ADMIN_BARGE))
   {
      if (moveflag != 1 && !possible_move(p, r, 1))
         return;
      if ((r->flags & LOCKED || r->flags & KEYLOCKED) && moveflag == 1
               && current_player->location->owner != current_player->saved)
      {
         tell_current(" The room is locked !\n");
         return;
      }
   }
   old_current = current_player;
   current_player = p;

   old_room = p->location;

   if (old_room)
   {
      scan = old_room->players_top;
      if (scan == p)
         old_room->players_top = p->room_next;
      else
      {
         while (scan && scan != p)
         {
            previous = scan;
            scan = scan->room_next;
         }
         if (!scan)
            log("error", "Bad Location list");
         else
            previous->room_next = p->room_next;
      }

      if (old_room->players_top)
      {
         if (!moveflag)
            sprintf(stack, " %s %s\n", p->name, r->enter_msg);
         else
            sprintf(stack, " A hand reaches down from the sky and grabs %s"
                           " ...\n", p->name);
         stack = end_string(stack);
         tell_room(p->location, oldstack);
         stack = oldstack;
      } else
      {
         compress_room(old_room);
         if ((old_room->flags & (LOCKABLE | LOCKED)) == (LOCKABLE | LOCKED))
            old_room->flags &= ~LOCKED;
      }
   }
   p->room_next = r->players_top;
   r->players_top = p;
   p->location = r;
   if (moveflag)
      sprintf(stack, " %s spins rapidly into being ...\n", p->name);
   else
      sprintf(stack, " %s %s\n", p->name, p->enter_msg);
   stack = end_string(stack);
   tell_room(p->location, oldstack);
   stack = oldstack;
   look(p, 0);
   if (p->saved_flags & SHOW_EXITS)
      check_exits(p, 0);
   current_player = old_current;
}


/* trans command */

void            trans_fn(player * p, char *str)
{
   if (!*str)
   {
      tell_player(p, " Format: trans <someone.some-room-id>\n");
      return;
   }
   if (p->no_move)
   {
      tell_player(p, " You appear to be stuck to the ground.\n");
      return;
   }
   move_to(p, str, 0);
   do_str_inform(p, str);
}


/* go, the normal move command */

void            go_room(player * p, char *str)
{
   char           *exits, *oldstack, *start;

   if (!*str)
   {
      tell_player(p, " Format: go <room>\n");
      return;
   }
   oldstack = stack;
   if (!p->location)
   {
      tell_player(p, " Strange, you don't seem to be anyhwere.\n");
      return;
   }
   exits = p->location->exits.where;
   if (!exits)
   {
      tell_player(p, " Eek ! this place hasn't got any exits.\n");
      return;
   }
   lower_case(str);
   while (*exits)
   {
      start = exits;
      while (*exits != '.')
    exits++;
      exits++;
      while (*exits != '\n')
    *stack++ = tolower(*exits++);
      *stack++ = 0;
      stack = oldstack;
      if (match_player(oldstack, str))
    break;
      exits++;
   }
   if (!*exits)
   {
      sprintf(oldstack, " Can't find exit '%s' to go through.\n", str);
      stack = end_string(oldstack);
      tell_player(p, oldstack);
      stack = oldstack;
      return;
   }
   while (*start != '\n')
      *stack++ = *start++;
   *stack++ = 0;
   move_to(p, oldstack, 0);
   sprintf(stack, "%s.%s", p->location->owner->lower_name, p->location->id);
   if (!strcasecmp(oldstack, stack))
      do_str_inform(p, oldstack);
   stack = oldstack;
}

/* load in the standard rooms and initialise */

char           *get_line(file * f)
{
   char           *start;
   while (*(f->where) == '#')
   {
      while ((f->length > 0) && *(f->where) != '\n')
      {
    f->where++;
    f->length--;
      }
      if (f->length == 0)
    return 0;
      f->where++;
      f->length--;
   }
   start = f->where;
   while (*(f->where) && *(f->where) != '\n' && *(f->where) != '\r')
   {
      f->where++;
      f->length--;
   }
   if (*(f->where))
   {
      *(f->where)++ = 0;
      f->length--;
   }
   if (*(f->where) == '\r' || *(f->where) == '\n')
   {
      *(f->where)++ = 0;
      f->length--;
   }
   return start;
}

void init_room(char *name, file rf)
{
   char *line, *oldstack, *file_start;
   saved_player *sp;
   room *r;
   player np;

   oldstack = stack;

   /* if (!malloc_verify()) printf("wrong HERE 1\n"); */

   file_start = rf.where;

   sp = find_saved_player(name);
   if (!sp)
   {
      memset(&np, 0, sizeof(player));
      np.fd = 0;
      np.location = (room *) - 1;
      restore_player(&np, name);
      np.residency = SYSTEM_ROOM;
      np.saved_residency = SYSTEM_ROOM;
      np.email[0] = -1;
      np.password[0] = -1;
      np.max_exits=30;
      np.max_rooms=30;
      np.max_autos=30;
      np.max_list=1;
      save_player(&np);
      sp = find_saved_player(name);
      sp->list_top = 0;
   }

   sp->residency=SYSTEM_ROOM;
   sp->rooms = 0;

   /* if (!malloc_verify()) printf("wrong HERE 2\n"); */

   while (rf.length > 0)
   {
      line = get_line(&rf);
      if (rf.length <= 0 || !(*line))
    break;
      r = (room *) MALLOC(sizeof(room));
      memset(r, 0, sizeof(room));
      r->owner = sp;
      r->players_top = 0;
      r->next = sp->rooms;
      sp->rooms = r;
      strncpy(r->id, line, MAX_ID - 2);
      line = get_line(&rf);
      strncpy(r->name, line, MAX_ROOM_NAME - 2);
      line = get_line(&rf);
      strncpy(r->enter_msg, line, MAX_ENTER_MSG - 2);
      r->flags = OPEN | ROOM_UPDATED;

      while (*(rf.where) != '#')
    if (*(rf.where) != '\r')
    {
       *stack++ = *rf.where++;
       rf.length--;
    } else
    {
       rf.where++;
       rf.length--;
    }
      *stack++ = 0;
      r->text.length = strlen(oldstack) + 1;
      r->text.where = (char *) MALLOC(r->text.length);
      strcpy(r->text.where, oldstack);
      stack = oldstack;
      line = get_line(&rf);
      while (strcasecmp(line, "end"))
      {
    while (*line)
       *stack++ = *line++;
    *stack++ = '\n';
    line = get_line(&rf);
      }
      *stack++ = 0;
      r->exits.length = strlen(oldstack) + 1;
      if (r->exits.length == 1)
      {
    r->exits.where = 0;
    r->exits.length = 0;
      } else
      {
    r->exits.where = (char *) MALLOC(r->exits.length);
    strcpy(r->exits.where, oldstack);
      }
      stack = oldstack;

      line = get_line(&rf);
      while (strcasecmp(line, "end"))
      {
    while (*line)
       *stack++ = *line++;
    *stack++ = '\n';
    line = get_line(&rf);
      }
      *stack++ = 0;
      r->automessage.length = strlen(oldstack) + 1;
      if (r->automessage.length == 1)
      {
    r->automessage.where = 0;
    r->automessage.length = 0;
      } else
      {
    r->automessage.where = (char *) MALLOC(r->automessage.length);
    strcpy(r->automessage.where, oldstack);
    r->flags |= AUTO_MESSAGE;
      }
      stack = oldstack;
   }
   /* if (!malloc_verify()) printf("wrong HERE 3\n"); */
   FREE(file_start);
   stack = oldstack;
}


void init_rooms()
{
   file lf;
   player dummy;
   room *r;

   if (sys_flags & VERBOSE)
      log("boot", "Loading rooms.");

   room_df=dynamic_init("rooms", 256);

#ifdef PC
   lf = load_file("files\\system.roo");
      init_room("system", lf);
   lf = load_file("files\\boot.roo");
      init_room("boot", lf);
#else
   lf = load_file("files/system.rooms");
      init_room("system", lf);
   lf = load_file("files/summink.rooms");
      init_room("summink", lf);
   lf = load_file("files/boot.rooms");
      init_room("boot", lf);
#endif

   entrance_room = convert_room(stdout_player, ENTRANCE_ROOM);
   entrance_room->auto_base = 924;
   prison = convert_room(stdout_player, "system.prison");
   colony = convert_room(stdout_player, "summink.colony");
   comfy = convert_room(stdout_player, "summink.comfy");
   comfy->flags |= OPEN;
   comfy->flags |= LOCKED;
   comfy->flags |= CONFERENCE;
   boot_room = convert_room(stdout_player, "boot.one");

   if (sys_flags & VERBOSE)
      log("boot", "Common rooms loaded.");
}


/* delete room */

void            delete_room(player * p, char *str)
{
   char           *oldstack;
   room           *scan, **previous, *r;
   oldstack = stack;
   if (!current_room)
   {
      tell_player(p, " Strange you don't appear to be anywhere.\n");
      return;
   }
   if (!strcmp("system", current_room->owner->lower_name) &&
       !strcmp("void", current_room->id))
   {
      tell_player(p, " You can't delete the void !\n");
      return;
   }
   r = current_room;
   while (r->players_top)
   {
      tell_player(r->players_top, " The room around you vanishes !\n");
      trans_to(r->players_top, "system.void");
   }
   previous = &(r->owner->rooms);
   scan = *previous;
   for (; scan && scan != r; scan = scan->next)
      previous = &(scan->next);
   if (scan)
   {
      *previous = scan->next;
      if (scan->text.where)
    FREE(scan->text.where);
      if (scan->exits.where)
    FREE(scan->exits.where);
      if (scan->automessage.where)
    FREE(scan->automessage.where);
      dynamic_free(room_df,scan->data_key);
      FREE(scan);
   } else
      *previous = 0;
   if (p)
      tell_player(p, " Room deleted.\n");
   stack = oldstack;
}

/* the where command */

void            stack_where_string(player * p, player * test)
{
  char           namestring[MAX_PRETITLE+MAX_NAME+10];
  list_ent       *l;
  int             entry = 0;
  
  if (p->saved_flags & NOPREFIX || strlen(test->pretitle) == 0)
    sprintf(namestring, " %s", test->name);
  else
    sprintf(namestring, " %s %s", test->pretitle, test->name);

  if (p == test && test->location)
      /* where the person doing the command is */
  {
      if (!(test->location))
      {
	  sprintf(stack, " You find yourself, *eek*!!! Nowhere at all!\n");
      } 
      else
      {
	  sprintf(stack, " You find yourself %s\n", test->location->name);
      }
      stack = strchr(stack, 0);
      return;
  }

  /* now consider where other people are */
  if (!(test->location))
      /* if they're nowhere, wibble and exit */
    {
      sprintf(stack, " %s is, *eek*!!! Nowhere at all!\n", namestring);
      stack = strchr(stack, 0);
      return;
    }
  sprintf(stack, "%s.%s", test->location->owner->lower_name,
	  test->location->id);

  if (!strcmp(stack, ENTRANCE_ROOM))
      /* if they are in the main room */
    {
      sprintf(stack, " %s is %s\n", namestring, test->location->name);
      stack = strchr(stack, 0);
      return;
    }
  
  if (test->location->owner == p->saved)
  {
      sprintf(stack, " %s is %s\n", namestring, test->location->name);
      stack = strchr(stack, 0);
      return;
  }
  l = find_list_entry(test, p->lower_name);
  if (!l && p->residency & SU)
    l = find_list_entry(test,"sus");
  if (!l && p->residency == NON_RESIDENT)
    l = find_list_entry(test,"newbies");
  if (!l)
    l = find_list_entry(test,"everyone");
  if (l)
    entry = l->flags;
  if ((test->saved_flags & HIDING) && !(p->residency & ADMIN) &&
      !(entry & FIND))
    {
      sprintf(stack, " %s is hiding away.\n", namestring);
      stack = strchr(stack, 0);
      return;
    }
  if (!test->location)
    {
      sprintf(stack, " Wierd, %s doesn't appear to be anywhere.\n",
	      namestring);
      stack = strchr(stack, 0);
      return;
    }
  sprintf(stack, " %s is %s", namestring, test->location->name);
  stack = strchr(stack, 0);
  if (test->saved_flags & HIDING)
    {
      strcpy(stack, " (hiding)");
      stack = strchr(stack, 0);
    }
  if (p->residency & ADMIN)
    {
      sprintf(stack, " ( %s.%s )\n", test->location->owner->lower_name,
	      test->location->id);
      stack = strchr(stack, 0);
    }
  else
    {
      *stack++ = '\n';
      *stack = 0;
    }
}

/*
 * void where_friends(player *p) { char *oldstack; list_ent *l; player *p2;
 * int count=0;
 * 
 * oldstack=stack; l=p->saved->list_top; while (l) {
 * p2=find_player_global_quiet(l->name); if (p2) { stack_where_string(p,p2);
 * count++; } l=l->next; } stack++=0; if (!count) tell_player(p,"You have no
 * friends on at the moment.\n"); else tell_player(p,oldstack); }
 */


void where(player * p, char *str)
{
   player **list, **step;
   int i,n;
   player *scan;
   char *oldstack, middle[80], *wh;
   int page, pages, count;

   oldstack = stack;
   command_type |= SEE_ERROR;
   if (isalpha(*str) && !strstr(str, "everyone"))
   {
      if (!strcasecmp(str, "am i"))
      {
         sprintf(stack, " You are %s\n", p->location->name);
         stack = end_string(stack);
         tell_player(p, oldstack);
         stack = oldstack;
         return;
      }
      align(stack);
      list = (player **) stack;
      n = global_tag(p, str);
      if (!n)
      {
         stack = oldstack;
         return;
      }
      wh = stack;
      for (step = list, i = 0; i < n; i++, step++)
      {
         stack_where_string(p, *step);
         stack++;
         tell_player(p, wh);
         stack = wh;
      }
      cleanup_tag(list, n);
      stack = oldstack;
      return;
   }
   if (strstr(str, "everyone"))
   {
      wh = str;
      str = strchr(str, ' ');
      if (!str)
      {
         str = wh;
         *str++ = '1';
         *str = 0;
      }
   }
   page = atoi(str);
   if (page <= 0)
      page = 1;
   page--;

   pages = (current_players - 1) / (TERM_LINES - 2);
   if (page > pages)
      page = pages;

   if (current_players == 1)
   {
      strcpy(middle, " There is only you on the program at the moment");
   } else
   {
      sprintf(middle, " There are %s people on the program",
              number2string(current_players));
   }
   pstack_mid(middle);

   count = page * (TERM_LINES - 2);
   for (scan = flatlist_start; count; scan = scan->flat_next)
   {
      if (!scan)
      {
         tell_player(p, " Bad where listing, abort.\n");
         log("error", "Bad where list");
         stack = oldstack;
         return;
      } else if (scan->name[0])
      {
         count--;
      }
   }

   for (count = 0; (count < (TERM_LINES - 1) && scan); scan = scan->flat_next)
   {
      if (scan->name[0] && scan->location)
      {
         stack_where_string(p, scan);
         count++;
      }
   }
   sprintf(middle, "Page %d of %d", page + 1, pages + 1);
   pstack_mid(middle);

   *stack++ = 0;
   tell_player(p, oldstack);
   stack = oldstack;
}


/* change room flags */

void            room_entry(player * p, char *str)
{
   if (current_room->owner != p->saved)
   {
      tell_player(p, " This is not your room, though!\n");
      return;
   }
   current_room->flags ^= CONFERENCE;
   if (current_room->flags & CONFERENCE)
      tell_player(p, " People are now able to connect to this room.\n");
   else
      tell_player(p, " People are now unable to connect to this room.\n");
}



void            room_lock(player * p, char *str)
{
  list_ent       *l;
  char           *oldstack;
  
  oldstack = stack;
  l = fle_from_save(current_room->owner, p->lower_name);
  if (!l && p->residency & SU)
    l = fle_from_save(current_room->owner, "sus");
  if (!l && p->residency == NON_RESIDENT)
    l = fle_from_save(current_room->owner, "newbies");
  if (!l)
    l = fle_from_save(current_room->owner, "everyone");
  
    
  if (strcmp(current_room->owner->lower_name, p->lower_name) &&
      !(current_room->flags & LOCKABLE) && !(p->residency & ADMIN)
      && (!(l && l->flags & KEY)))
    {
      tell_player(p, " This is not your room to lock.\n");
      return;
    }
  if (!strcasecmp("off", str))
    current_room->flags &= ~LOCKED;
  else if (!strcasecmp("on", str))
    current_room->flags |= LOCKED;
  else
    current_room->flags ^= LOCKED;
  
  if (current_room->flags & LOCKED)
    {
      tell_player(p, " Room is now locked.\n");
      sprintf(stack, " %s turns the key in the door, locking the room ...\n",
	      p->name);
    }
  else
    {
      tell_player(p, " Room is now unlocked.\n");
      sprintf(stack, " %s unlocks the door ...\n", p->name);
    }
  stack = end_string(stack);
  to_room1(p->location, oldstack, p);
  stack = oldstack;
}

/* Make room lockable by all */

void            room_lockable(player * p, char *str)
{
   if (!strcasecmp("off", str))
      current_room->flags &= ~LOCKABLE;
   else if (!strcasecmp("on", str))
      current_room->flags |= LOCKABLE;
   else
      current_room->flags ^= LOCKABLE;

   if (current_room->flags & LOCKABLE)
      tell_player(p, " Room is now lockable by everyone.\n");
   else
      tell_player(p, " Room is now lockable only by keyholders.\n");
}

/* Make room linkable by all */

void            room_linkable(player * p, char *str)
{
   if (!strcasecmp("off", str))
      current_room->flags &= ~LINKABLE;
   else if (!strcasecmp("on", str))
      current_room->flags |= LINKABLE;
   else
      current_room->flags ^= LINKABLE;

   if (current_room->flags & LINKABLE)
      tell_player(p, " Room is now linkable by all. (ie. People can make "
        "links _from_ it.)\n");
   else
      tell_player(p, " Room is now not linkable by all.\n");
}

void            room_open(player * p, char *str)
{
   char           *oldstack;

   oldstack = stack;

   if (!strcasecmp("off", str))
      current_room->flags &= ~OPEN;
   else if (!strcasecmp("on", str))
      current_room->flags |= OPEN;
   else
      current_room->flags ^= OPEN;

   if (current_room->flags & OPEN)
   {
      tell_player(p, " Room is now open for all to come inside.\n");
      sprintf(stack, " %s opens up the room to the rabble outside ...\n",
         p->name);
   } else
   {
      tell_player(p, " Room is now open for invites only.\n");
      sprintf(stack, " %s closes the room ...\n", p->name);
   }
   stack = end_string(stack);
   to_room1(p->location, oldstack, p);
   stack = oldstack;
}

/* HARD lock the room (noone at all can get in) */

void            room_bolt(player * p, char *str)
{
   char           *oldstack;

   oldstack = stack;
   if (!strcasecmp("off", str))
      current_room->flags &= ~KEYLOCKED;
   else if (!strcasecmp("on", str))
      current_room->flags |= KEYLOCKED;
   else
      current_room->flags ^= KEYLOCKED;
   if (current_room->flags & KEYLOCKED)
   {
      tell_player(p, " Room is now totally locked to anyone but you.\n");
      sprintf(stack, " %s bolts the door of the room ...\n", p->name);
   } else
   {
      tell_player(p, " Room is now not totally locked.\n");
      sprintf(stack, " %s unbolts the door ...\n", p->name);
   }
   stack = end_string(stack);
   to_room1(p->location, oldstack, p);
   stack = oldstack;
}


void            set_home(player * p, char *str)
{
   room           *r;
   if (!p->saved)
   {
      tell_player(p, " Strange, you appear to have no save file.\n");
      return;
   }
   r = p->saved->rooms;
   if (!r)
   {
      tell_player(p, " Strange, you appear to have no rooms.\n");
      return;
   }
   for (; r; r = r->next)
      r->flags &= ~HOME_ROOM;
   current_room->flags |= HOME_ROOM;
   tell_player(p, " Current room is now home room.\n");
}



/* go home */

void            go_home(player * p, char *str)
{
   room           *r;
   char           *oldstack;

   oldstack = stack;
   if (!p->saved)
   {
      tell_player(p, " You have no save files, and therefore no home.\n");
      return;
   }
   if (p->no_move)
   {
      tell_player(p, " You appear to be stuck to the ground.\n");
      return;
   }
   r = p->saved->rooms;
   if (!r)
   {
      tell_player(p, " You have no rooms in which to have a home.\n");
      return;
   }
   for (; r; r = r->next)
      if (r->flags & HOME_ROOM)
         break;
   if (!r)
   {
      tell_player(p, " You don't appear to have a home room.\n");
      return;
   }
   sprintf(oldstack, "%s.%s", r->owner->lower_name, r->id);
   stack = end_string(oldstack);
   move_to(p, oldstack, 0);
   stack = oldstack;
}

/* visit someone */

void            visit(player * p, char *str)
{
   room           *r;
   saved_player   *sp;
   player         *p2;
   char           *oldstack;
   oldstack = stack;

   if (p->no_move)
   {
      tell_player(p, " You appear to be stuck to the ground.\n");
      return;
   }
   strcpy(stack, str);
   lower_case(stack);
   stack = end_string(stack);
   p2 = find_player_global_quiet(oldstack);
   if (p2)
   {
      sp = p2->saved;
      if (!sp)
      {
         tell_player(p, " That player has no rooms.\n");
         stack = oldstack;
         return;
      }
   } else
   {
      sp = find_saved_player(oldstack);
   }
   if (!sp)
   {
      sprintf(oldstack, " Can't find player '%s' in save files.\n", str);
      stack = end_string(oldstack);
      tell_player(p, oldstack);
      stack = oldstack;
      return;
   }
   r = sp->rooms;
   if (!r)
   {
      tell_player(p, " That person has no rooms.\n");
      stack = oldstack;
      return;
   }
   for (; r; r = r->next)
   {
      if (r->flags & HOME_ROOM)
      {
         break;
      }
   }
   if (!r)
   {
      tell_player(p, " That player doesn't appear to have a home room.\n");
      stack = oldstack;
      return;
   }
   sprintf(oldstack, "%s.%s", r->owner->lower_name, r->id);
   stack = end_string(oldstack);
   move_to(p, oldstack, 0);
   do_room_inform(p, r, 4);
   stack = oldstack;
}

/* back to start */

void            go_main(player * p, char *str)
{
   if (p->location && !strcmp(p->location->owner->lower_name, "summink") &&
       !(strcmp(p->location->id, "main")))
   {
      tell_player(p, " You are already in the main room.\n");
      return;
   }
   if (p->no_move)
   {
      tell_player(p, " You seem to be stuck to the ground\n");
      return;
   }
   if (!strcmp(ENTRANCE_ROOM, stack))
   {
      tell_player(p, " You are already standing in the main room.\n");
      return;
   }
   move_to(p, ENTRANCE_ROOM, 0);
}


/* grab someone */

void            grab_once(player * p, player * p2)
{
   char           *oldstack;
   list_ent       *l;
   oldstack = stack;

   if (!(p->residency & ADMIN))
   {
      if ((p->location->flags & LOCKED || p->location->flags & KEYLOCKED)
          && p->location->owner != p->saved && !(p->residency & ADMIN))
      {
         tell_player(p, " You can't grab people into locked rooms ...\n");
         sys_flags |= FAILED_COMMAND;
         return;
      }
      if (!(p2->location))
      {
         sprintf(oldstack, " '%s' doesn't appear to be anywhere !!\n",
                 p2->name);
         stack = end_string(oldstack);
         tell_player(p, oldstack);
         sys_flags |= FAILED_COMMAND;
         stack = oldstack;
         return;
      }
      if (p2->location == prison)
      {
         sprintf(oldstack, " You fail to grab %s from prison!!\n", p2->name);
         stack = end_string(oldstack);
         tell_player(p, oldstack);
         sys_flags |= FAILED_COMMAND;
         stack = oldstack;
         return;
      }
      if (!(p->residency & PSU) && p2->location == boot_room)
      {
         sprintf(oldstack, " You fail to grab %s from the boot room!!\n",
                 p2->name);
         stack = end_string(oldstack);
         tell_player(p, oldstack);
         sys_flags |= FAILED_COMMAND;
         stack = oldstack;
         return;
      }
      if (!(p2->residency == NON_RESIDENT && p->residency & SU))
      { 
         l = find_list_entry(p2, p->lower_name);
	 if (!l && p->residency & SU)
	   l = find_list_entry(p2, "sus");
	 if (!l && p->residency == NON_RESIDENT)
	   l = find_list_entry(p2, "newbies");
         if (!l)
	   l = find_list_entry(p2, "everyone");
         if (!l || !(l->flags & GRAB))
         {
            sprintf(oldstack, " You can't grab %s !!\n", p2->name);
            stack = end_string(oldstack);
            tell_player(p, oldstack);
            sys_flags |= FAILED_COMMAND;
            stack = oldstack;
            return;
         }
      }
   } else
   {
      command_type |= ADMIN_BARGE;
   }
   if (p2->location == p->location)
   {
      sprintf(oldstack, " %s is already in the same room as you.\n", p2->name);
      stack = end_string(oldstack);
      tell_player(p, oldstack);
      stack = oldstack;
      return;
   }
   sprintf(oldstack, " %s stretches out and grabs you !!!!!!\n", p->name);
   stack = end_string(oldstack);
   tell_player(p2, oldstack);

   if (p2->no_move && (!(p->residency & ADMIN)))
   {
      tell_player(p2, " You can't move as you seem to be stuck to the "
                      "ground.\n");
      sprintf(oldstack, " %s appears to be stuck to the ground !!!\n",
         p2->name);
      stack = end_string(oldstack);
      tell_player(p, oldstack);
      sys_flags |= FAILED_COMMAND;
      stack = oldstack;
      return;
   }
   sprintf(oldstack, "%s.%s", current_room->owner->lower_name,
           current_room->id);
   stack = end_string(oldstack);
   move_to(p2, oldstack, 1);
   do_room_inform(p2, current_room, 3);
   if (p2->location != p->location)
   {
      sprintf(oldstack, " You fail to grab %s.\n", p2->name);
      stack = end_string(oldstack);
      tell_player(p, oldstack);
      sys_flags |= FAILED_COMMAND;
      stack = oldstack;
      return;
   }
}


void            do_grab(player * p, char *str)
{
   player        **list, **step;
   char           *oldstack, *text, *pstring;
   int             n, i;
   oldstack = stack;

   align(stack);
   list = (player **) stack;

   if (!*str)
   {
      tell_player(p, " Format : grab <player(s)>\n");
      return;
   }
   n = global_tag(p, str);
   if (!n)
      return;

   for (step = list, i = 0; i < n; i++, step++)
   {
      if (p != *step)
         grab_once(p, *step);
      else
      {
         text = stack;
         sprintf(stack, " %s grabs %s, oooer !!\n", p->name, name_string(0, p));
         stack = end_string(stack);
         tell_room(p->location, text);
         stack = text;
      }
   }

   if (!(sys_flags & FAILED_COMMAND))
   {
      pstring = tag_string(p, list, n);
      text = stack;
      sprintf(text, " You successfully grab %s.\n", pstring);
      stack = end_string(text);
      tell_player(p, text);
      stack = text;
   }
   cleanup_tag(list, n);
   stack = oldstack;
}



/* stuff for editing a room */

void            quit_room_edit(player * p)
{
   tell_player(p, " Leaving editor WITHOUT storing changes.\n");
   p->mode &= ~ROOMEDIT;
}

void            end_room_edit(player * p)
{
   room           *r;
   if (!p->saved)
   {
      tell_player(p, " You don't seem to have a saved file.\n");
      return;
   }
   r = (room *) p->edit_info->misc;
   if (r->text.where)
      FREE(r->text.where);
   r->text.length = p->edit_info->size;
   r->text.where = (char *) MALLOC(r->text.length);
   memcpy(r->text.where, p->edit_info->buffer, r->text.length);
   r->flags |= ROOM_UPDATED;
   tell_player(p, " Ending edit and KEEPING changes.\n");
   p->mode &= ~ROOMEDIT;
   if (p->edit_info->input_copy == room_command)
   {
      do_prompt(p, "Room Mode >");
      p->mode |= ROOMEDIT;
   }
}

void            room_edit(player * p, char *str)
{
   start_edit(p, MAX_ROOM_SIZE, end_room_edit, quit_room_edit,
         current_room->text.where);
   if (!p->edit_info)
      return;
   p->edit_info->misc = (void *) current_room;
   p->mode |= ROOMEDIT;
}

#ifdef this_is_not_ready_yet
/* check for a room being bounceable to. Novelty admin value only */

void check_bounceable(player * p, char *str)
/* WARNING this routine makes NO checks on ownership of the rooms
   in question */
{
    /* the basic game plan is to check if the room the player is in, or
       has specified, is the top of its hash chain & letter. If so it's
       theoretically bounceable */

    if (!*str)
    {
	/* person wants to do the current room */

	/* set the room to be the current one */
    }
    else
    {

	/* extract the room from the string */

	/* check if it exists */

	/* barf if it doesn't */
    }
    
    /* extract the first letter of the owner and find which hash
       chain it is on */
    
    /* find the top room on that hash chain/letter */
    
    /* if this room is the same as the current room, we're in luck */
    /* tell the player so */
    
    /* else */
    /* tell the player it's not bounceable */
    
    /* and return */
}
    
    
	
#endif

/* find random open room */

room *random_room()
{
   saved_player *scan;
   char letter;
   int hash;
   room *r;

   letter = (char) (rand() % 26);
   hash = (int) (rand() % HASH_SIZE);
   if (letter < 0)
      letter = -letter;
   if (hash < 0)
      hash = -hash;

   while (1)
   {
      scan = find_top_player(letter, hash);
      for (; scan; scan = scan->next)
      {
	  /* if you change the criteria, do change them above in
	     check_bounceable() too */
         for (r = scan->rooms; r; r = r->next)
            if (r->flags & OPEN && !(r->flags & LOCKED) && r != prison
                && !(r->flags & KEYLOCKED) && r != current_room)
               return r;
      }
      hash = (hash + 1) % HASH_SIZE;
      if (!hash)
	  /* hmmm - maybe a mod in here? rather unlikely to ever happen 
	     with a decent room count though */
    letter++;
   }
}


/* bounce */

void bounce(player * p, char *str)
{
    room *r;
    char *oldstack;
    player *scan;
    
    command_type = 0;
    /* check for player stuck to ground */
    if (p->no_move)
    {
	tell_player(p, " You seem to be stuck to the ground\n");
	return;
    }
    /* tell the room the leavemsg for bounce */
    oldstack = stack;
    sprintf(oldstack, " %s spins round, and bounces into the air !!\n", p->name);
    stack = end_string(oldstack);
    tell_room(p->location, oldstack);
    
    /* find a random room */
    r = random_room();
    
    /* and move there */
    sprintf(oldstack, "%s.%s", r->owner->lower_name, r->id);
    stack = end_string(oldstack);
        trans_to(p, oldstack);
    
    stack = oldstack;
    sprintf(stack, " %s %s\n", p->name, p->enter_msg);
    stack = end_string(stack);
    
    for (scan = p->location->players_top; scan; scan = scan->room_next)
	if (scan != p)
	    tell_player(scan, oldstack);
    
    do_room_inform(p, r, 2);
    
    /* Show bouncee the exits if they asked */
    if (p->saved_flags & SHOW_EXITS)
	check_exits(p, 0);
    
    stack = oldstack;
}


/* actually do a boot */

int             do_boot(player * p, player * booted)
{
  room           *r;
  list_ent       *l;
  char           *oldstack;
  
  r = (booted)->location;
  
  if (!r)
    {
      oldstack = stack;
      sprintf(stack, " %s doesn't appear to be anywhere.\n", (booted)->name);
      stack = end_string(stack);
      tell_player(p, oldstack);
      stack = oldstack;
      return 0;
    }
  command_type = 0;
  if ( (!strcmp(r->owner->lower_name, "system")
	|| !strcmp(r->owner->lower_name, "summink")
	|| !strcmp(r->owner->lower_name, "boot"))
      && ((p->residency & SU && !(sys_flags & EVERYONE_TAG))
	  || p->residency & ADMIN)
      && p->residency > booted->residency)
    {
      if ((booted->location == boot_room) && (booted->no_move > 0))
	{
	  tell_player(p, " That player is already in the boot room!\n");
	  return 0;
	}
      *((player **) stack) = booted;
      stack += sizeof(player *);
      (booted)->flags &= ~TAGGED;
      oldstack = stack;
      sprintf(stack, " %s picks you up and boots you out over the ocean.\n",
	      p->name);
      stack = end_string(stack);
      tell_player(booted, oldstack);
      sprintf(oldstack, " %s is picked up by %s and booted out over the"
	      " ocean.\n",
              (booted)->name, p->name);
      stack = end_string(oldstack);
      tell_room_but(booted, (booted)->location, oldstack);
      
      if (!strcmp(r->owner->lower_name, "boot") && !strcmp(r->id, "one"))
	{
	  strcpy(oldstack, ENTRANCE_ROOM);
	} 
      else
	{
	  strcpy(oldstack, "boot.one");
	}
      
      stack = end_string(oldstack);
      trans_to(booted, oldstack);
      sprintf(oldstack, " %s dusts %sself down after getting booted.\n",
              (booted)->name, get_gender_string(booted));
      stack = end_string(oldstack);
      tell_room_but(booted, (booted)->location, oldstack);
      stack = oldstack;
      booted->no_shout = 60;
      booted->no_move = 60;
      return 1;
    }
  l = fle_from_save(r->owner, p->lower_name);
  if (!l && p->residency & SU)
    l=fle_from_save(r->owner, "sus");
  if (!l && p->residency == NON_RESIDENT)
    l=fle_from_save(r->owner,"newbies");
  if (!l)
    l=fle_from_save(r->owner,"everyone");

  if (((r->owner) != (p->saved)) && !(p->residency & ADMIN) &&
      (!(l && l->flags & KEY)))
    {
      oldstack = stack;
      sprintf(stack, " %s is not in one of your rooms\n", (booted)->name);
      stack = end_string(stack);
      tell_player(p, oldstack);
      stack = oldstack;
      return 0;
    }
  *((player **) stack) = booted;
  stack += sizeof(player *);
  (booted)->flags &= ~TAGGED;
  oldstack = stack;
  sprintf(stack, " %s picks you up and boots you out the room.\n", p->name);
  stack = end_string(stack);
  tell_player(booted, oldstack);
  sprintf(oldstack, " %s is picked up by %s and booted out the room.\n",
	  (booted)->name, p->name);
  stack = end_string(oldstack);
  tell_room_but(booted, (booted)->location, oldstack);
  trans_to(booted, ENTRANCE_ROOM);
  sprintf(oldstack, " %s dusts %sself down after getting booted.\n",
	  (booted)->name, get_gender_string(booted));
  stack = end_string(oldstack);
  tell_room_but(booted, (booted)->location, oldstack);
  stack = oldstack;
  return 1;
}

/* the boot command */

void            boot_out(player * p, char *str)
{
  char           *pstring, *final, *space;
  char           *oldstack;
  player        **list, **step, **new_list;
  int             i, n, count = 0;
  
  command_type = SEE_ERROR;
  oldstack = stack;
  align(stack);
  list = (player **) stack;
  
  if (!*str)
    {
      tell_player(p, " Format : boot person<s>\n");
      return;
    }
  space = strchr(str, ' ');
  if (space)
    *space = 0;
  
  n = global_tag(p, str);
  if (!n)
    {
      stack = oldstack;
      return;
    }
  align(stack);
  new_list = (player **) stack;
  for (step = list, i = 0; i < n; i++, step++)
    {
      if (*step != p)
	{
	  count += do_boot(p, *step);
	}
    }
  
  if (!count)
    {
      tell_player(p, " You fail to boot anybody anywhere.\n");
  } else
    {
      pstring = tag_string(p, new_list, count);
      final = stack;
      sprintf(stack, " You boot %s out of your rooms.\n", pstring);
      stack = end_string(stack);
      tell_player(p, final);
    }
  
  cleanup_tag(list, n);
  stack = oldstack;
}



/* join someone soemwhere */

void            join(player * p, char *str)
{
   list_ent       *l;
   char           *oldstack;
   player         *p2;
   room           *r;
   oldstack = stack;

   if (!*str)
   {
      tell_player(p, " Format: join <person>\n");
      return;
   }
   if (p->no_move)
   {
      tell_player(p, " You appear to be stuck to the ground.\n");
      return;
   }
   p2 = find_player_global(str);
   if (!p2)
      return;
   if (!(p2->saved))
      l = 0;
   else
     {
       l = fle_from_save(p2->saved, p->lower_name);
       if (!l && p->residency & SU)
	 l=fle_from_save(p2->saved, "sus");
       if (!l && p->residency== NON_RESIDENT)
	 l=fle_from_save(p2->saved,"newbies");
       if (!l)
	 l=fle_from_save(p2->saved,"everyone");
     }

   if (p2->saved_flags & HIDING && !(p->residency & ADMIN) &&
       (!l || (l && !(l->flags & FIND))))
     {
       sprintf(stack, " %s is in hiding, so you don't know where %s is.\n",
	       full_name(p2), gstring(p2));
       stack = end_string(stack);
       tell_player(p, oldstack);
       stack = oldstack;
       return;
     }
   r = p2->location;
   if (!r)
     {
       sprintf(stack, " %s doesn't appear to be anywhere !\n", full_name(p2));
       stack = end_string(stack);
       tell_player(p, oldstack);
       stack = oldstack;
       return;
     }
   if (r == p->location)
     {
       sprintf(stack, " You are already in the same room as %s.\n",
	       full_name(p2));
       stack = end_string(stack);
       tell_player(p, oldstack);
       stack = oldstack;
       return;
     }
   sprintf(stack, "%s.%s", r->owner->lower_name, r->id);
   stack = end_string(stack);
   move_to(p, oldstack, 0);
   if (p->location == r)
     {
       do_room_inform(p, r, 1);
     }
   stack = oldstack;
 }



/* change the base of the auto timer */

void            change_auto_base(player * p, char *str)
{
   room           *r;
   int             i;
   char           *oldstack;
   oldstack = stack;
   r = current_room;
   if (!r)
   {
      tell_player(p, " Strange  ! You don't appear to be anywhere.\n");
      return;
   }
   i = atoi(str);
   if (i <= 0)
   {
      tell_player(p, " Format: speed <number>\n");
      return;
   }
   r->auto_base = i;
   sprintf(stack, " Autos set to minimum speed of every %d seconds.\n", i);
   stack = end_string(stack);
   tell_player(p, oldstack);
   stack = oldstack;
}



/* with command */

void            with(player * p, char *str)
{
  char           *oldstack, *text, namestring[40];
  player         *p2, **list, *scan;
  list_ent       *l;
  room           *r;
  int             count = 0, hide_count = 0, entry = 0;
  oldstack = stack;
  if (!*str)
    {
      tell_player(p, " Format: with <player>\n");
      return;
    }
  if (strcasecmp(str, "me"))
    {
      p2 = find_player_global(str);
    }
  else
    {
      p2 = p;
    }
  if (!p2)
    return;
  
  if (p->saved_flags & NOPREFIX || strlen(p2->pretitle) == 0)
    strcpy(namestring, p2->name);
  else
    sprintf(namestring, "%s %s", p2->pretitle, p2->name);
  
  l = find_list_entry(p2, p->lower_name);
  if (!l && p->residency & SU)
    l=find_list_entry(p2,"sus");
  if (!l && p->residency==NON_RESIDENT)
    l=find_list_entry(p2,"newbies");
  if (!l)
    l=find_list_entry(p2,"everyone");
  if (l)
    entry = l->flags;
  if (p2->saved_flags & HIDING && !(p->residency & ADMIN) && !(entry & FIND)
      && p != p2)
    {
      sprintf(stack, " You fail miserably trying to find '%s' never mind "
	      "anyone %s is with.\n", namestring, gstring(p2));
      stack = end_string(stack);
      tell_player(p, oldstack);
      stack = oldstack;
      return;
    }
  align(stack);
  list = (player **) stack;
  r = p2->location;
  if (!r)
    {
      tell_player(p, " That person doesn't appear to be anywhere !\n");
      stack = oldstack;
      return;
    }

  for (scan = r->players_top; scan; scan = scan->room_next)
    if (scan != p2 && !(scan->saved_flags & HIDING))
      {
	*((player **) stack) = scan;
	stack += sizeof(player *);
	count++;
      } 
    else
      {
	if (scan != p2 && p->residency & ADMIN)
	  {
	    *((player **) stack) = scan;
	    stack += sizeof(player *);
	    count++;
	  } 
	else
	  {
	    l=0;

	    l = find_list_entry(scan, p->lower_name);
	    if (!l && p->residency & SU)
	      l=find_list_entry(scan,"sus");
	    if (!l && p->residency==NON_RESIDENT)
	      l=find_list_entry(scan,"newbies");
	    if (!l)
	      l=find_list_entry(scan,"everyone");
	    if (!l)
	      hide_count++;
	  }
      }
  text = stack;
  
  if (!count && (hide_count == 1))
    {
      sprintf(text, " Aaaw, %s %s all alone.\n", namestring, isare(p2));
      stack = end_string(text);
      tell_player(p, text);
      stack = oldstack;
      return;
    }
  if (!count)
    {
      sprintf(text, " You cannot discern who is with %s.\n", namestring);
      stack = end_string(text);
      tell_player(p, text);
      stack = oldstack;
      return;
    }
  if ((hide_count != 1))
    sprintf(text, " %s %s with, among others ....\n", namestring, isare(p2));
  else
    sprintf(text, " %s %s with ...\n", namestring, isare(p2));
  stack = strchr(stack, 0);
  if (p2->saved_flags & HIDING)
    {
      sprintf(stack, " NOTE: %s %s hidden.\n", p2->name, isare(p2));
      stack = strchr(stack, 0);
    }
  if (p->saved_flags & NOPREFIX)
    sys_flags |= NO_PRETITLES;
  construct_name_list(list, count);
  if (p->saved_flags & NOPREFIX)
    sys_flags &= ~NO_PRETITLES;
  *stack++ = 0;
  tell_player(p, text);
  stack = oldstack;
}

/* grabable command */

void grabable(player * p, char *str)
{
   char *oldstack, *text;
   player **list, *scan;
   int count = 0;
   list_ent *l;

   oldstack = stack;
   align(stack);
   list = (player **) stack;

   for (scan = flatlist_start; scan; scan = scan->flat_next)
   {
      l = find_list_entry(scan, p->lower_name);
      if (!l && p->residency & SU)
	l=find_list_entry(scan,"sus");
      if (!l && p->residency==NON_RESIDENT)
	l=find_list_entry(scan,"newbies");
      if (!l)
         l = find_list_entry(scan, "everyone");
      if (l && l->flags & GRAB && scan != p)
      {
         *((player **) stack) = scan;
         stack += sizeof(player *);
         count++;
      }
   }

   text = stack;

   if (!count)
   {
      tell_player(p, " You can't grab anyone.\n");
      stack = oldstack;
      return;
   }
   strcpy(text, " You can grab ...\n");
   stack = strchr(stack, 0);
   construct_name_list(list, count);
   *stack++ = 0;
   tell_player(p, text);
   stack = oldstack;
}


/* invites: All the invites you have */

void            invites_list(player * p, char *str)
{
   char           *oldstack, *text;
   player        **list, *scan;
   int             count = 0;
   list_ent       *l;
   oldstack = stack;

   align(stack);
   list = (player **) stack;


   for (scan = flatlist_start; scan; scan = scan->flat_next)
   {
      l = find_list_entry(scan, p->lower_name);
      if (!l)
    l = find_list_entry(scan, "everyone");
      if (l && l->flags & INVITE)
      {
    *((player **) stack) = scan;
    stack += sizeof(player *);
    count++;
      }
   }

   text = stack;

   if (!count)
   {
      tell_player(p, " You aren't invited by anyone!\n");
      stack = oldstack;
      return;
   }
   strcpy(text, " You have invites from ...\n");
   stack = strchr(stack, 0);
   construct_name_list(list, count);
   *stack++ = 0;
   tell_player(p, text);
   stack = oldstack;
}

/* admin transfer room */

void            transfer_room(player * p, char *str)
{
   saved_player   *sp;
   char           *oldstack;
   room           *r, *prev, *scan;
   oldstack = stack;

   if (!*str)
   {
      tell_player(p, " Format: transfer <saved player>\n");
      return;
   }
   strcpy(stack, str);
   lower_case(stack);
   sp = find_saved_player(stack);
   if (!sp)
   {
      tell_player(" No such person in saved files.\n");
      return;
   }
   r = current_room;
   if (!r)
   {
      tell_player(p, " You don't appear to be anywhere !!\n");
      return;
   }
   scan = r->owner->rooms;
   if (scan == r)
      r->owner->rooms = r->next;
   else
   {
      while (scan && scan != r)
      {
    prev = scan;
    scan = scan->next;
      }
      if (!scan)
      {
    tell_player(p, " Eeeek, bad room listing, abort.\n");
    return;
      }
      prev->next = r->next;
   }

   r->owner = sp;
   r->next = sp->rooms;
   sp->rooms = r;

   tell_player(p, " Room transfered.\n");
   stack = oldstack;
}

void            to_room1(room * r, char *str, player * p)
{
   to_room2(r, str, p, 0);
}

void            to_room2(room * r, char *str, player * p1, player * p2)
{
   player         *scan;

   for (scan = r->players_top; scan; scan = scan->room_next)
      if ((scan != p1) && (scan != p2))
         tell_player(scan, str);
}

void            room_link(player * p, char *str)
{
   static char     roomname[80];
   room           *linkto, *r;
   int             nomove = 1;

   if (!*str)
   {
      tell_player(p, " Format: room link <owner-name>.<id>\n");
      return;
   }
   r = p->location;
   if ((linkto = convert_room_verbose(p, str, 0)) &&
       (nomove = possible_move(p, linkto, 1)) && (linkto->flags & LINKABLE ||
       !strcmp(linkto->owner->lower_name, p->saved->lower_name)) &&
       r != linkto)
   {
      tell_player(p, " Adding link to current room ...\n");
      sprintf(roomname, "%s.%s", r->owner->lower_name, r->id);
      add_exit(p, roomname);
      tell_player(p, " Adding link to other room ...\n");
      add_exit(p, str);
      return;
   }
   if (!linkto)
   {
      tell_player(p, " That other room doesn't exist.\n");
      return;
   }
   if (!nomove)
      tell_player(p, " But you're not allowed in the other room!\n");
   else
      tell_player(p, " Sorry, you can't do that.\n");
}

/* Fear this CPH rip-off */

void mindseye(player * p, char *str)
{
   char *oldstack;
   room *r;
   player *inroom;
   saved_player *sp;

   if (!p->saved || !p->saved->rooms)
   {
      tell_player(p, " You have no rooms!\n");
      return;
   }
   if (!*str)
   {
      r = p->saved->rooms;
      for (; r; r = r->next)
         if (r->flags & HOME_ROOM)
            break;
      if (!r)
      {
         tell_player(p, " You don't have a home room, do you...\n");
         return;
      }
      if (r == p->location)
      {
         tell_player(p, " You're already in that room.\n");
         return;
      }
   } else
   {
      r = convert_room_verbose(p, str, 0);
      if (!r)
      {
         lower_case(str);
         sp = find_saved_player(str);
         if (sp)
         {
            for(r = sp->rooms ; r ; r=r->next)
               if (r->flags & HOME_ROOM)
                  break;
         }
         if (!r)
         {
            tell_player(p, " Bad room id on mindseye.\n");
            return;
         }
      }
      if (strcmp(r->owner->lower_name, p->lower_name)
                && !(p->residency & ADMIN))
      {
         tell_player(p, " But you don't own that room!\n");
         return;
      }
   }
   inroom = r->players_top;
   if (!inroom)
   {
      if (r->flags & HOME_ROOM && p == (player *)r->owner)
      {
         tell_player(p, " There is no-one in your home room.\n");
      } else
      {
         tell_player(p, " There is no-one in that room.\n");
      }
      return;
   }
   oldstack = stack;
   if (r->flags & HOME_ROOM && p == (player *)r->owner)
   {
      strcpy(stack, "\n You peer into your home room, and you see ...\n");
   } else if (strcmp(str, r->owner->lower_name))
   {
      sprintf(stack, "\n You peer into \'%s\', and see ...\n", str);
   } else
   {
      sprintf(stack, "\n You peer into %s's home room, and see ...\n",
              r->owner->lower_name);
   }
   stack = strchr(stack, 0);
   while (inroom)
   {
      if (p->saved_flags & NOPREFIX)
         sprintf(stack, "  %s %s (%s idle)\n", inroom->name, inroom->title,
                 word_time(inroom->idle));
      else
         sprintf(stack, "  %s %s (%s idle)\n", full_name(inroom),
                 inroom->title, word_time(inroom->idle));
      stack = strchr(stack, 0);
      inroom = inroom->room_next;
   }
   stack = strchr(stack, 0);
   *stack++ = '\n';
   *stack++ = 0;
   tell_player(p, oldstack);
   stack = oldstack;
}

void prison_player(player * p, char *str)
{
   char *oldstack, *mark;
   char fortime[128];
   int timeout = 1;
   player *p2;

   oldstack = stack;
   if (!*str)
   {
      tell_player(p, " Format: jail <person> [<timeout>]\n");
      return;
   }
   mark = strchr(str, ' ');
   if (mark)
   {
      *mark++ = 0;
      timeout = atoi(mark);
      if (!timeout)
         timeout = 1;
   }
   if (!strcasecmp(str, "me"))
   {
      p2 = p;
      timeout = -1;
   } else
      p2 = find_player_global(str);
   if (!p2)
      return;
   if (p2==p)
   {
      p->jail_timeout=-1;
      move_to(p, "system.prison", 0);
      return;
   }
   if (p2->residency >= p->residency)
   {
      tell_player(p, " Nah na nah nah naaaahh! You can't!\n");
      return;
   }
   if (timeout > 10)
      timeout = 10;
   if (timeout > 0)
      sprintf(fortime, "for %d minutes.", timeout);
   else
   {
      sprintf(fortime, "for the rest of %s natural life.", their_player(p2));
      p2->saved_flags |= SAVEDJAIL;
   }
   command_type |= HIGHLIGHT;
   tell_player(p2, " You suddenly find yourself grabbed, and flung into the "
          "prison ...\n");
   p2->jail_timeout = (timeout * 60);
   command_type &= ~HIGHLIGHT;
   move_to(p2, "system.prison", 0);
   sprintf(stack, " You throw %s in prison ... %s\n", p2->name, fortime);
   stack = end_string(oldstack);
   tell_player(p, oldstack);
   p->flags & NO_SU_WALL;
   stack = oldstack;
   sprintf(stack, " -=> %s throws %s in jail, %s\n", p->name, p2->name, fortime);
   stack = end_string(stack);
   su_wall(oldstack);
   stack = oldstack;
}


void            set_login_room(player * p, char *str)
{
   char           *oldstack;
   room           *r;
   list_ent       *l;

   if (!*str)
   {
      tell_player(p, " You will now connect to the main room.\n");
      strcpy(p->room_connect, "");
      p->saved_flags &= ~TRANS_TO_HOME;
      return;
   }
   r = convert_room(p, str);
   if (!r)
      return;
   l = fle_from_save(r->owner, p->lower_name);
   if (!l || !(l->flags & KEY))
   {
      if (!possible_move(p, r, 1))
         return;
      if (!(r->flags & CONFERENCE))
      {
         tell_player(p, " That room is not open for connecting to.\n");
         return;
      }
   }
   oldstack = stack;
   sprintf(stack, " You will now attempt to connect to room '%s'\n", str);
   stack = end_string(stack);
   tell_player(p, oldstack);
   stack = oldstack;
   strncpy(p->room_connect, str, MAX_ROOM_CONNECT - 2);
   p->saved_flags &= ~TRANS_TO_HOME;
}

void            barge(player * p, char *str)
{
   char *oldstack;
   room *to;

   oldstack = stack;
   command_type |= ADMIN_BARGE;
   if (strchr(str, '.'))
   {
      if ((to = convert_room_verbose(p, str, 0)))
      {
         sprintf(stack, " %s %s\n", p->name, to->enter_msg);
         stack = end_string(stack);
         tell_room(p->location, oldstack);
         stack = oldstack;
         trans_to(p, str);
         sprintf(stack, " %s %s\n", p->name, p->enter_msg);
         stack = end_string(stack);
         tell_room(p->location, oldstack);
         stack = oldstack;
      }
   } else if (find_saved_player(str))
      visit(p, str);
   else
      join(p, str);
   /* just to clear the command_type (should be cleared, but what the hell */
   command_type &= ~ADMIN_BARGE;
}

void            inform_room_enter(player * p, char *str)
{
   if (p->saved_flags & ROOM_ENTER)
      tell_player(p, " You won't be informed when people enter your rooms.\n");
   else
      tell_player(p, " You will now be informed when someone enters one of"
        " your rooms.\n");
   p->saved_flags ^= ROOM_ENTER;
}

/*
 * inform owner when a room is entered.  1 == join 2 == bounce, 3 == grab, 4
 * == visit, 0 == normal move or go
 */

void            do_room_inform(player * p, room * r, int type)
{
   player         *p2;
   saved_player   *sp;
   char           *oldstack, *out;

   sp = r->owner;
   p2 = find_player_absolute_quiet(sp->lower_name);
   if (!p2 || !(p2->saved_flags & ROOM_ENTER))
      return;
   if (p2->location == p->location)
      return;

   oldstack = stack;
   if (p2->saved_flags & NOPREFIX || p->pretitle[0] == 0)
      sprintf(stack, " %s has just", p->name);
   else
      sprintf(stack, " %s %s has just", p->pretitle, p->name);
   stack = end_string(stack);
   out = stack;
   switch (type)
   {
      case 0:
    sprintf(stack, " %s entered %s.%s\n", oldstack, p2->name,
       r->id);
    break;
      case 1:
    sprintf(stack, " %s joined someone in %s.%s\n", oldstack,
       p2->name, r->id);
    break;
      case 2:
    sprintf(stack, " %s bounced into %s.%s\n", oldstack, p2->name,
       r->id);
    break;
      case 3:
    sprintf(stack, " %s been grabbed into %s.%s\n", oldstack,
       p2->name, r->id);
    break;
      case 4:
    sprintf(stack, " %s visited you.\n", oldstack);
    break;
   }
   stack = end_string(stack);
   tell_player(p2, out);
   stack = oldstack;
}

void            do_str_inform(player * p, char *str)
{
   room           *r;
   r = convert_room(p, str);
   if (!r)
      return;
   do_room_inform(p, r, 0);
}


/* Get all players out of a certain players rooms, used on nuke */

void all_players_out(saved_player *sp)
{
   room *r, *r2;
   player *p;

   for(r=sp->rooms;r;r=r->next)
   {
      for(p=(player *)r->players_top;p;p=(player *)r2)
      {
         r2 = (room *)p->room_next;
         if (strcmp(p->lower_name, sp->lower_name))
            move_to(p, "system.void", 0);
      }
   }
}

void hilltop(player *p, char *str)
{
   tell_player(p, " I see no hilltops here...\n");
}