/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/***********************************************************
Realms of Aurealis Online Creation System version 2.1
RoAOLCv2.1   -   James Rhone aka Vall of RoA

roaolc.c  (online creation system - mob/room/object/house edit files)
Adopted from Realms of Imagination's original version of OLC (7/95)

 ******** Heavily modified and expanded ********
 *** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
 ******** Heavily modified and expanded ********
 All rights reserved henceforth.  Author: James Rhone
				  Original Running Version: 0.5beta

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  Thanks to Jeremy Elson
who has provided a stable base for Realms of Aurealis.  RoA was originally
created from a CircleMUD 2.2 base, back in the dark ages, when even that
release was considered new wave.
  Since RoA is a perpetual BETA MUD, all code from it is also in BETA
stages.  I personally feel this is the best OLC ever made available for
CircleMUD and its derivatives.  My experienced builders agree.  How you
feel depends on how well you can fit into your mud.  Good luck.  There are
no patch files, no step by step instructions, and no hand holders.  All
code written for Realms of Aurealis, including that contained in this file
was written by me, James Rhone, so nobody is very familiar with it except
me.  Perhaps that will change. :)

*** 
If you do not know C, I suggest getting to know it before you attempt
to plug this into your mud.  This is not a trivial addition to any mud and
without someone there to guide you, you will inevitably get frustrated.
**

    note: zone OLC can be found in z_olc.c
    note: room OLC can be found in r_olc.c
    note: mobile OLC can be found in m_olc.c
    note: object OLC can be found in o_olc.c
**********************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "comm.h"
#include "interpreter.h"
#include "acmd.h"
#include "db.h"
#include "utils.h"
#include "mudlimits.h"
#include "handler.h"
#include "roaolc.h"
#include "magic.h"
#include "house.h"
#include "lists.h"
#include "global.h"
#include "clicomm.h"

// external functions and variables
extern char *dirs[];
extern char *room_bits[];

extern exdescdata *correct_extra_descrips(exdescdata *ths);

// no more duping this bit of code... 
BOOL olc_perms(chdata *ch, int level_override, int zone)
{
  if (GET_LEVEL(ch) < level_override &&
     (zone == 0 || zone < ch->pc_specials->saved.olc_min_zone ||
      zone > ch->pc_specials->saved.olc_max_zone))
  {
    send_to_char("RoAOLC:  Insufficient permissions.\n\r",ch);
    return FALSE;
  }
  else
    return TRUE;
}

// send version and menu title to char in RoAOLC
void menu_title_send(char *menu, chdata *ch)
{
  char buf[MAX_STRING_LENGTH];

  if (PLR_FLAGGED(ch, PLR_REFRESH))
    clrscr(ch);
  sprintf(buf, "\n\r    %%B%%5%s %s%%0\n\r", OLC_version, menu);
  S2C();
}

// assigning / revocation of building privs
ACMD(do_olc)
{
  char buf[MAX_STRING_LENGTH];
  char func[MAX_STRING_LENGTH];
  chdata *person;
  int min_zone, max_zone;

  if (IS_NPC(ch))
	return;

  if (*argument)
  {
    argument = one_argument(argument, buf);
    person = get_char_vis(ch, buf);
  }
  else
    person = ch;
    
  if (!person)
  {
    send_to_char("No such person is around.\n\r", ch);
    return;
  }

  if (IS_NPC(person))
  {
    send_to_char("NPC's don't have OLC privileges.\n\r", ch);
    return;
  }

  if (!IS_IMMORTAL(person))
  {
    send_to_char("Must be immortal.\n\r",ch);
    return;
  }

  if (GET_LEVEL(person) > GET_LEVEL(ch))
  {
    send_to_char("Pick on someone your own size.\n\r", ch);
    return;
  }
    
  if (*argument && GET_LEVEL(ch) >= LEV_AIMP)
  {
    argument = one_argument(argument, func);

    if (!*argument || !strlen(func))
    {
      send_to_char("usage: OLC <player> all <min zone> [<max zone>]\n\r", ch);
      return;
    }
    argument = one_argument(argument, buf);
    min_zone = atoi(buf);

    if (!*argument)
      max_zone = min_zone;
    else
    {
      argument = one_argument(argument, buf);
      max_zone = atoi(buf);
    }
	
    if (max_zone < min_zone)
    {
      send_to_char("The maximum zone must be greater or "
		   "equal to the minimum zone.\n\r", ch);
      return;
    }

    person->pc_specials->saved.olc_min_zone = min_zone;
    person->pc_specials->saved.olc_max_zone = max_zone;
  }

  act("RoAOLC privs for $N:", FALSE,ch,0,person,TO_CHAR);
  sprintf(buf, "Zones: %3d - %3d\n\r", person->pc_specials->saved.olc_min_zone,
	    person->pc_specials->saved.olc_max_zone);
  S2C();
}

// list rooms/chars in a particular zone
ACMD(do_zlist)
{
  rmdata *w;
  chdata *x;
  int zone;
  int i, top;
  char buf[20000];
    
    if (IS_NPC(ch))
	return;
    
    one_argument(argument, buf);
    if (!*buf || *buf == '.')
	zone = world[ch->in_room].zone;
    else
	zone = real_zone(atoi(buf));
    
    if (zone < 0)
    {
      send_to_char("That zone does not exist.\n\r",ch);
      return;
    }

    if (!olc_perms(ch, LEV_GOD, zone))
      return;

    if (ZONE_FREED(zone))
    {
      send_to_char("The rooms from that zone are not stored in memory.\n\r",ch);
      send_to_char("Use %Bzlock%0 to load them into memory.\n\r",ch);
      return;
    }

    top = zone_table[zone].top;
    for (i = zone * 100; i <= top; i++)
    {
	if (real_room(i) >= 0)
	    break;
    }

    if (i > top)
	return;
    
    buf[0] = '\0';
    while (i <= top)
    {
	if (real_room(i) < 0)
	{
	    i++;
	    continue;
	}
	w = &world[real_room(i)];

	sprintf(buf1, "[%%B%%6%5d%%0]\t%-22.22s%%0\t", i, w->name);
	sprintbit(w->room_flags, room_bits, buf2);
	strcat(buf1, buf2);
	strcat(buf1, "\n\r");
	x = w->people;	
	while (x)
	{
	  if (IS_NPC(x))
	    sprintf(buf2, "\t[%%B%2d NPC%%0]  %s\n\r", GET_LEVEL(x), x->player.name);
	  else
	    sprintf(buf2, "\t[%%5%2d %s%%0]  %s\n\r", GET_LEVEL(x), CLASS_ABBR(x), 
		    x->player.name);
	  strcat(buf1, buf2);
	  strcat(buf, buf1);
	  *buf1 = '\0';
	  x = x->next_in_room;
	}
	i++;
    }
    page_string(ch->desc, buf, 1);
}

/* simply toggles clrscreen flag for builders */
ACMD(do_refresh)
{
  if (IS_NPC(ch)) return;
  
  if (!PLR_FLAGGED(ch, PLR_REFRESH))
  {
    SET_BIT(PLR_FLAGS(ch), PLR_REFRESH);
    send_to_char("%5OLC refresh %Bon%0.\n\r",ch);
    return;
  }

  REMOVE_BIT(PLR_FLAGS(ch), PLR_REFRESH);
  send_to_char("%5OLC refresh %Boff%0.\n\r",ch);
}

// throw a string into a file -roa 
void string_to_file(char *text, char *fname)
{
  FILE *fp;
  char buffer[85000];

  strcpy(buffer, text);
  killr(buffer);
  if (!(fp = fopen(fname, "wt")))
  {
    sprintf(buf, "SYSERR: Could not open %s.", fname);
    return;
  }
  fprintf(fp, "%s", buffer);
  fclose(fp);
}

// dont push onto the stack, just jump char to this menu
int menu_jump(chdata *ch, void (*to_menu)(chdata *ch, char *input_str))
{
  MENU_HANDLER(ch) = to_menu;
  (*MENU_HANDLER(ch))(ch, NULL);
  return 1;
}

// throw current onto stack, then jump
int menu_push_jump(chdata *ch, void (*to_menu)(chdata *ch, char *input_str))
{
  menu_push(ch);
  MENU_HANDLER(ch) = to_menu;
  (*MENU_HANDLER(ch))(ch, NULL);
  return 1;
}

// OK, i'll attempt to spawn off a diff editor, after they are done
// ill put the file they editted into d->str
// then call string_add
int do_max_string_arg(chdata *ch, char *prompt, char **return_ptr)
{
  char shellfname[100];
  char fname[100];
  BOOL cliedit = FALSE;
  extern void startshell(dsdata *d, char *x, char *y);

  menu_push(ch);

  // RoA
  // OK, if using alternate editor for these large files
  // write the current *return_ptr to their edit file so
  // spico can read it
  if (PLR_FLAGGED(ch, PLR_EXEDIT))
  {
      sprintf(fname, "edits/%s.edit", GET_NAME(ch));

      // delete the file if it exists
      if (unlink(fname) < 0) {
        if (errno != ENOENT) { /* if it fails, NOT because of no file */
         sprintf(buf1, "SYSERR: deleting edit file %s (2)", fname);
         perror(buf1);
        }
      }
  }

  // add ability to send string to client for editing
  // 2/25/98 -jtrhone
  if (PLR2_FLAGGED(ch, PLR2_CLIEDIT) && ch->desc && HAS_CLIENT(ch->desc))
    cliedit = TRUE;

  if (*return_ptr)
  {
    if (PLR_FLAGGED(ch, PLR_EXEDIT))
      string_to_file(*return_ptr, fname);
    else
    if (cliedit)
    {
      client_edit(ch->desc, prompt, *return_ptr);
      send_to_char("Switch to RoAClient...", ch);
    }

    free_log(*return_ptr, "do_max_string_arg");
  }
  *return_ptr = NULL;

  MENU_HANDLER(ch) 	= menu_long_string;
  ch->desc->max_str	= MAX_STRING_LENGTH - 3;
  ch->desc->str		= return_ptr;

  if (PLR_FLAGGED(ch, PLR_EXEDIT))
  {
    MENU_PROMPT(ch) = NULL; 
    sprintf(shellfname, "%s.edit", GET_NAME(ch));
    startshell(ch->desc, "", shellfname);
  }
  else
  if (cliedit)
  {
    MENU_PROMPT(ch) = NULL; 
  }
  else
  {
    send_to_char(prompt, ch);
    MENU_PROMPT(ch) = NULL; 
  }
  return 0;
}

// set character into classic string editting mode (like writing boards)
// multi line text entry, will use cliedit now if chosen  7/9/98 -jtrhone
int do_long_string_arg(chdata *ch, char *prompt, char **return_ptr)
{
  BOOL cliedit = FALSE;

  menu_push(ch);

  if (PLR2_FLAGGED(ch, PLR2_CLIEDIT) && ch->desc && HAS_CLIENT(ch->desc))
    cliedit = TRUE;

  if (*return_ptr)
  {
    if (cliedit)
    {
      client_edit(ch->desc, prompt, *return_ptr);
      send_to_char("Switch to RoAClient...", ch);
    }
    free_log(*return_ptr, "do_long_string_arg");
  }
  *return_ptr = NULL;

  MENU_HANDLER(ch)       = menu_long_string;
  ch->desc->max_str      = 1000;
  ch->desc->str          = return_ptr;

  if (!cliedit)
    send_to_char(prompt, ch);

  MENU_PROMPT(ch) = NULL; 
  return 0;
}

// sends character into exshell editor if they are flagged to do so
// currently used for mobprocs and IMPL room descrips perhaps
int do_var_string_arg(chdata *ch, char *prompt, char **return_ptr, int length)
{
    char shellfname[100];
    char fname[100];
    BOOL cliedit = FALSE;
    extern void startshell(dsdata *d, char *x, char *y);

    menu_push(ch);

    // RoA
    // OK, if using alternate editor for these large files
    // write the current *return_ptr to their edit file so
    // spico can read it
    if (PLR_FLAGGED(ch, PLR_EXEDIT))
    {
      sprintf(fname, "edits/%s.edit", GET_NAME(ch));
      unlink(fname);

      if (*return_ptr)
        string_to_file(*return_ptr, fname);
    }

    // add ability to send string to client for editing
    // 2/25/98 -jtrhone
    if (PLR2_FLAGGED(ch, PLR2_CLIEDIT) && ch->desc && HAS_CLIENT(ch->desc))
    {
      cliedit = TRUE;
      client_edit(ch->desc, prompt, *return_ptr);
      send_to_char("Switch to RoAClient...", ch);
    }

    if (*return_ptr)
      free_log(*return_ptr, "do_var_string_arg");
    *return_ptr = NULL;

    MENU_HANDLER(ch) 	   = menu_long_string;
    ch->desc->max_str      = length;
    ch->desc->str          = return_ptr;

    if (PLR_FLAGGED(ch, PLR_EXEDIT))
    {
      MENU_PROMPT(ch) = NULL; 
      sprintf(shellfname, "%s.edit", GET_NAME(ch));
      startshell(ch->desc, "", shellfname);
    }
    else
    if (cliedit)
    {
      MENU_PROMPT(ch) = NULL; 
    }
    else
    {
      send_to_char(prompt, ch);
      MENU_PROMPT(ch) = NULL; 
    }
    return 0;
}

// one line text entry
int do_string_arg(chdata *ch, char *prompt, char **return_ptr, char *suffix)
{
    struct menu_string_arg *arg;

    CREATE(arg, struct menu_string_arg, 1);
    menu_push(ch);

    MENU_HANDLER_ARG(ch) = (void *) arg; 
    arg->return_ptr = return_ptr;
    arg->suffix = suffix;
    
    MENU_PROMPT(ch) = prompt; 
    menu_jump(ch, menu_string);
    return 0;
}

int toggle_menu(chdata *ch, char *prompt, int *return_ptr, char **strings)
{
    int i;
    struct menu_toggle_bits_arg *arg;

    CREATE(arg, struct menu_toggle_bits_arg, 1);
    menu_push(ch);

    MENU_HANDLER_ARG(ch) = (void *) arg; 
    arg->bit_field = return_ptr; 
    arg->bit_strs  = strings;
    for (i = 0; *(strings[i]) != '\n'; i++)
	;
    arg->n_bit_strs = i;
    
    MENU_PROMPT(ch) = prompt; 
    menu_jump(ch, menu_toggle_bits);
    return 0;
}

/* same as toggle_menu but with long referenced */
int toggle_menu_long(chdata *ch, char *prompt, long *return_ptr, char **strings)
{
    int i;
    struct menu_toggle_bits_long_arg *arg;

    CREATE(arg, struct menu_toggle_bits_long_arg, 1);
    menu_push(ch);

    MENU_HANDLER_ARG(ch) = (void *) arg;
    arg->bit_field = return_ptr; 
    arg->bit_strs  = strings;
    for (i = 0; *(strings[i]) != '\n'; i++)
	;
    arg->n_bit_strs = i;
    
    MENU_PROMPT(ch) = prompt; 
    menu_jump(ch, menu_toggle_bits_long);
    return 0;
}

int get_integer_arg(chdata *ch, char *prompt, void *return_ptr,
		int return_size, int min_value, int max_value)
{ 
    struct menu_get_integer_arg *arg;

    CREATE(arg, struct menu_get_integer_arg, 1);
    menu_push(ch);
    MENU_HANDLER_ARG(ch) = (void *) arg; 
    arg->min = min_value; 
    arg->max = max_value;
    arg->size = return_size; 
    arg->return_ptr = return_ptr;  
    arg->strings = NULL; 
    arg->n_strings = 0;
    arg->offset = 0;
    MENU_PROMPT(ch) = prompt; 
    menu_jump(ch, menu_get_integer);
    return 0;
}

int get_integer_list(chdata *ch, char *prompt, void *return_ptr,
		 int return_size, char **strings)
{ 
    int i;
    struct menu_get_integer_arg *arg;

    CREATE(arg, struct menu_get_integer_arg, 1);
    menu_push(ch);
    MENU_HANDLER_ARG(ch) = (void *) arg; 
    arg->min = 1; 
    arg->offset = 1;
    arg->size = return_size; 
    arg->return_ptr = return_ptr;
    arg->strings = strings;
    for (i = 0; *(strings[i]) != '\n'; i++)
	;
    arg->n_strings = i;
    arg->max = i;
    
    MENU_PROMPT(ch) = prompt; 
    menu_jump(ch, menu_get_integer);
    return 0;
}

// push a menu onto chars stack
int menu_push(chdata *ch)
{
  ch->desc->menu_args[MENU_DEPTH(ch)] = MENU_HANDLER_ARG(ch);
  ch->desc->menu_stack[MENU_DEPTH(ch)++] = MENU_HANDLER(ch);
  return 0;
}

// pop a menu off chars stack
int menu_pop(chdata *ch)
{
  MENU_HANDLER_ARG(ch) = ch->desc->menu_args[--MENU_DEPTH(ch)];
  MENU_HANDLER(ch) = ch->desc->menu_stack[MENU_DEPTH(ch)];
  return 0;
}

// pop menu off, and call menu
int menu_back(chdata *ch)
{
  menu_pop(ch);
  (*MENU_HANDLER(ch))(ch, NULL);
  return 0;
}

ROA_MENU(menu_long_string)
{   
  menu_back(ch);
}

ROA_MENU(menu_string)
{
  struct menu_string_arg *arg = MENU_HANDLER_ARG(ch);
   
  if (input_str)
  {
    FREENULL(*arg->return_ptr);
    CREATE(*arg->return_ptr, char, strlen(input_str) + strlen(arg->suffix) + 1);

    strcpy(*arg->return_ptr, input_str);
    strcat(*arg->return_ptr, arg->suffix);
    FREENULL(MENU_HANDLER_ARG(ch));
    menu_back(ch);
  }
}

ROA_MENU(menu_toggle_bits)
{
    char buf[MAX_STRING_LENGTH];
    char buf2[MAX_STRING_LENGTH];
    char *p;
    int field;
    int i;
    struct menu_toggle_bits_arg *arg = MENU_HANDLER_ARG(ch);
    int level = GET_LEVEL(ch);
    
    if (!input_str)
    {
        menu_title_send("Flag Toggle Menu", ch);
	for (i = 0; i < arg->n_bit_strs; i++)
	{
	    sprintf(buf, "%2d.) %%5%-20.20s%%0", i + 1, arg->bit_strs[i]);
	    if (!((i+1) % 3))
		strcat(buf, "\n\r");
	    send_to_char(buf, ch);
	}
	
	sprintbit(*arg->bit_field, arg->bit_strs, buf2);
	sprintf(buf, "\n\n\r%%6Bits set%%0: %%5%s%%0\n\r", buf2);
	send_to_char(buf, ch);
	return;
    }

  strcpy(buf2, input_str);

  // while numbers, set corresponding bits
  if (!*buf2)
  {
    FREENULL(MENU_HANDLER_ARG(ch));
    menu_pop(ch);
  } 
  else
  while (*buf2)
  {
    half_chop(buf2, buf, buf2);

    p = strtok(buf, " 	\n\r");
    if (p)
	field = atoi(p);
    else
	field = 0;

    if (!field)
    {
      FREENULL(MENU_HANDLER_ARG(ch));
      menu_pop(ch);
      break;
    }
    else 
    if (field > 0 && field <= arg->n_bit_strs)
    {
      switch (*arg->bit_strs[field-1]) {
        case '*':  // normally non editable
          if (level > LEV_IMPL)
	    *arg->bit_field ^= (1 << (field - 1));
          break;

        case '+':  // aimp+ only
          if (level >= LEV_AIMP)
	    *arg->bit_field ^= (1 << (field - 1));
          break;

        default:   // any builder can edit...
	  *arg->bit_field ^= (1 << (field - 1));
          break;
      }
    }
  }

  (*MENU_HANDLER(ch))(ch, NULL);
}

ROA_MENU(menu_toggle_bits_long)
{
    char buf[MAX_STRING_LENGTH];
    char buf2[MAX_STRING_LENGTH];
    char *p;
    long field;
    int i;
    struct menu_toggle_bits_long_arg *arg = MENU_HANDLER_ARG(ch);
    int level = GET_LEVEL(ch);

    if (!input_str)
    {
        menu_title_send("Flag Toggle MenuII", ch);
	for (i = 0; i < arg->n_bit_strs; i++)
	{
	    sprintf(buf, "%2d.) %%5%-20.20s%%0", i + 1, arg->bit_strs[i]);
	    if (!((i+1) % 3))
		strcat(buf, "\n\r");

	    send_to_char(buf, ch);
	}
	
	sprintbit(*arg->bit_field, arg->bit_strs, buf2);
	sprintf(buf, "\n\n\r%%6Bits set%%0: %%5%s%%0\n\r", buf2);
	send_to_char(buf, ch);
	return;
    }

  strcpy(buf2, input_str);

  // while numbers, set corresponding bits
  if (!*buf2)
  {
    FREENULL(MENU_HANDLER_ARG(ch));
    menu_pop(ch);
  } 
  else
  while (*buf2)
  {
    half_chop(buf2, buf, buf2);

    p = strtok(buf, " 	\n\r");
    if (p)
	field = atoi(p);
    else
	field = 0;

    if (!field)
    {
	FREENULL(MENU_HANDLER_ARG(ch));
	menu_pop(ch);
    }
    else 
    if (field > 0 && field <= arg->n_bit_strs)
    {
      switch (*arg->bit_strs[field-1]) {
        case '*':  // normally non editable
          if (level > LEV_IMPL)
	    *arg->bit_field ^= ((long long) 1 << (field - 1));
          break;

        case '+':  // aimp+ only
          if (level >= LEV_AIMP)
	    *arg->bit_field ^= ((long long) 1 << (field - 1));
          break;

        default:   // any builder can edit...
	  *arg->bit_field ^= ((long long) 1 << (field - 1));
          break;
      }
    }
  }

  (*MENU_HANDLER(ch))(ch, NULL);
}

ROA_MENU(menu_get_integer)
{
    struct menu_get_integer_arg *arg = MENU_HANDLER_ARG(ch);
    char *p;
    int n;
    int i;
   
    if (!input_str)
    {
        menu_title_send("Generic Selection Menu", ch);
	for (i = 0; i < arg->n_strings; i++)
	{
	    sprintf(buf, "%2d.) %%5%-21s%%0", i + 1, arg->strings[i]);
	    if ((i % 3) == 2)
		strcat(buf, "\n\r");

	    send_to_char(buf, ch);
	}
	send_to_char("\n\r",ch);
    }
    else
    {
	p = strtok(input_str, " 	\n\r");
	
	if (p)
	{
	    n = atoi(p);
	    if (n < arg->min || n > arg->max)
	    {
		char buf[80];
		
		sprintf(buf, "%%BValue must be in the range %d to %d%%0.\n\r",
			arg->min, arg->max);
		send_to_char(buf, ch);
		return;
	    }

	    n -= arg->offset;
	    
	    switch (arg->size)
	    {
	      case 1:
		*(char *)arg->return_ptr = n;
		break;
	      case 2:
		*(short *)arg->return_ptr = n;
		break;
	      case 4:
		*(int *)arg->return_ptr = n;
		break;
	    }
	}
	
	FREENULL(MENU_HANDLER_ARG(ch));
	menu_back(ch);
    }
}

/* for finding exits to void.. RoA*/
ACMD(do_voidlist)
{
    rmdata *w;
    int zone, rnum;
    int i, top, dir;
    BOOL found = FALSE;
    
    if (IS_NPC(ch))
	return;
    
    one_argument(argument, buf);
    if (!*buf || *buf == '.')
	zone = world[ch->in_room].zone;
    else
	zone = real_zone(atoi(buf));
    
    if (zone < 0)
    {
      send_to_char("Zone does not exist.\n\r",ch);
      return;
    }

    if (!olc_perms(ch, LEV_GOD, zone))
      return;

    top = zone_table[zone].top;
    for (i = zone * 100; i <= top; i++)
    {
	if (real_room(i) >= 0)
	    break;
    }

    if (i > top)
    {
	send_to_char("No rooms in that zone.\n\r",ch);
	return;
    }    

    while (i <= top)
    {
	if ((rnum = real_room(i)) < 0)
	{
	    i++;
	    continue;
	}
	w = &world[rnum];
	for (dir=0; dir < 10; dir++)
	  if (w->dir_option[dir])
            if (w->dir_option[dir]->to_room < 1)
	    {
 	      sprintf(buf, "Room %5d - %s exits to void.\n\r",i, dirs[dir]);
	      send_to_char(buf, ch);
	      found = TRUE;
	    }

        if (w->drift_to > 0 && real_room(w->drift_to) < 0)
        {
	  sprintf(buf, "Check room #%d drift to.\n\r",i);
	  S2C();
	  found = TRUE;
        }
        if (w->float_to > 0 && real_room(w->float_to) < 0)
        {
	  sprintf(buf, "Check room #%d float to.\n\r",i);
	  S2C();
	  found = TRUE;
        }
        if (w->drop_to > 0 && real_room(w->drop_to) < 0)
        {
	  sprintf(buf, "Check room #%d drop to.\n\r",i);
	  S2C();
	  found = TRUE;
        }

	if (ROOM_FLAGGED(rnum, ALTERHIT | ALTERMANA | ALTERMOVE) &&
	    !ROOM_FLAGGED(rnum, DEATH | FLY_DEATH))
        {
	  if ((w->numdice + w->numdice * w->sizedice) / 2 >= 5)
          {
	    sprintf(buf, "Room %5d - Dice exceed max average.\n\r",i);
	    S2C();
	  }
	}

	i++;
    }

    if (!found)
	send_to_char("No void exits / invalid entries found.\n\r",ch);
}