#include <stdio.h>
#include "structs.h"
#include "interpreter.h"
#include "comm.h"
#include "spells.h"
#include "utils.h"
#include "db.h"
#include <stdlib.h>
#include "boards.h"

/* change this depending on the number of flags you have defined */
#define NUM_ROOM_SECTORS 12
#define NUM_ROOM_FLAGS   17

extern int      top_of_world;
extern struct room_data *world;
extern struct obj_data *obj_proto;
extern struct char_data *mob_proto;
extern char    *room_bits[];
extern char    *sector_types[];
extern char    *exit_bits[];
extern struct zone_data *zone_table;
extern sh_int r_mortal_start_room;
extern sh_int r_immort_start_room;
extern sh_int r_frozen_start_room;
extern sh_int mortal_start_room;
extern sh_int immort_start_room;
extern sh_int frozen_start_room;

/* function protos */
void redit_disp_extradesc_menu(struct descriptor_data * d);
void redit_disp_exit_menu(struct descriptor_data * d);
void redit_disp_exit_flag_menu(struct descriptor_data * d);
void redit_disp_flag_menu(struct descriptor_data * d);
void redit_disp_sector_menu(struct descriptor_data * d);
void redit_disp_menu(struct descriptor_data * d);
void redit_parse(struct descriptor_data * d, char *arg);

/**************************************************************************
 Menu functions 
 **************************************************************************/

/* For extra descriptions */
void redit_disp_extradesc_menu(struct descriptor_data * d)
{
  struct extra_descr_data *extra_desc =
  (struct extra_descr_data *) * d->misc_data;

  send_to_char("Extra desc menu\r\n", d->character);
  send_to_char("0) Quit\r\n", d->character);
  sprintf(buf, "1) Keyword: %s\r\n", extra_desc->keyword
	  ? extra_desc->keyword : "<NONE>");
  send_to_char(buf, d->character);
  sprintf(buf, "2) Description:\r\n%s\r\n", extra_desc->description ?
	  extra_desc->description : "<NONE>");
  send_to_char(buf, d->character);
  if (!extra_desc->next)
    send_to_char("3) <NOT SET>\r\n", d->character);
  else
    send_to_char("3) Set. <NOT VIEWED>\r\n", d->character);
  send_to_char("Enter choice:\r\n", d->character);
  d->edit_mode = REDIT_EXTRADESC_MENU;
}

/* For exits */
void redit_disp_exit_menu(struct descriptor_data * d)
{
  /* if exit doesn't exist, alloc/create it */
  if(!d->edit_room->dir_option[d->edit_number2])
    CREATE(d->edit_room->dir_option[d->edit_number2],
	   struct room_direction_data, 1);
  sprintf(buf, "1) Exit to :     %d\r\n",
	  d->edit_room->dir_option[d->edit_number2]->to_room_vnum);
  send_to_char(buf, d->character);
  sprintf(buf, "2) Description : %s\r\n",
	  d->edit_room->dir_option[d->edit_number2]->general_description ?
	  d->edit_room->dir_option[d->edit_number2]->general_description :
	  "<NONE>");
  send_to_char(buf, d->character);
  sprintf(buf, "3) Door name :   %s\r\n",
	  d->edit_room->dir_option[d->edit_number2]->keyword ?
	  d->edit_room->dir_option[d->edit_number2]->keyword :
	  "<NONE>");
  send_to_char(buf, d->character);
  sprintf(buf, "4) Key :         %d\r\n",
	  d->edit_room->dir_option[d->edit_number2]->key);
  send_to_char(buf, d->character);
  /* weird door handling! */
  if (IS_SET(d->edit_room->dir_option[d->edit_number2]->exit_info,
	     EX_ISDOOR)) {
    if (IS_SET(d->edit_room->dir_option[d->edit_number2]->exit_info,
	       EX_PICKPROOF))
      strcpy(buf2, "Pickproof door");
    else
      strcpy(buf2, "Normal door");
  } else
    strcpy(buf2, "No door");
  if (IS_SET(d->edit_room->dir_option[d->edit_number2]->exit_info,
		EX_HIDDEN))
	sprintf(buf2, "%s; Hidden", buf2);
  sprintf(buf, "5) Door flags :  %s\r\n",
	  buf2);
  send_to_char(buf, d->character);
  send_to_char("6) Purge exit.\r\n", d->character);
  send_to_char("Enter choice, 0 to quit:", d->character);
  d->edit_mode = REDIT_EXIT_MENU;
}

/* For exit flags */
void redit_disp_exit_flag_menu(struct descriptor_data * d)
{
  send_to_char("0) No door\r\n", d->character);
  send_to_char("1) Closeable door\r\n", d->character);
  send_to_char("2) Pickproof\r\n", d->character);
  send_to_char("3) Hidden passage\r\n", d->character);
  send_to_char("4) Hidden door\r\n", d->character);
  send_to_char("5) Hidden Pickproof door\r\n", d->character);
  send_to_char("Enter choice:", d->character);
}

/* For room flags */
void redit_disp_flag_menu(struct descriptor_data * d)
{
  int             counter;

  send_to_char("", d->character);
  for (counter = 0; counter < NUM_ROOM_FLAGS; counter += 2) {
    sprintf(buf, "%2d) %20.20s %2d) %20.20s\r\n",
	    counter + 1, room_bits[counter],
	    counter + 2, counter + 1 < NUM_ROOM_FLAGS ?
	    room_bits[counter + 1] : "");
    send_to_char(buf, d->character);
  }
  sprintbit(d->edit_room->room_flags, room_bits, buf1);
  sprintf(buf, "Room flags: %s\r\n", buf1);
  send_to_char(buf, d->character);
  send_to_char("Enter room flags, 0 to quit:", d->character);
  d->edit_mode = REDIT_FLAGS;
}

/* for sector type */
void redit_disp_sector_menu(struct descriptor_data * d)
{
  int             counter;

  send_to_char("", d->character);
  for (counter = 0; counter < NUM_ROOM_SECTORS; counter += 2) {
    sprintf(buf, "%2d) %20.20s %2d) %20.20s\r\n",
	    counter, sector_types[counter],
	    counter + 1, counter + 1 < NUM_ROOM_SECTORS ?
	    sector_types[counter + 1] : "");
    send_to_char(buf, d->character);
  }
  send_to_char("Enter sector type:", d->character);
  d->edit_mode = REDIT_SECTOR;
}

/* the main menu */
void redit_disp_menu(struct descriptor_data * d)
{

  send_to_char("", d->character);
  d->edit_mode = REDIT_MAIN_MENU;
  sprintf(buf, "Room number: %d\r\n", d->edit_number);
  send_to_char(buf, d->character);
  sprintf(buf, "1) Room name: %s\r\n", d->edit_room->name);
  send_to_char(buf, d->character);
  sprintf(buf, "2) Room Desc:\r\n%s\r\n", d->edit_room->description);
  send_to_char(buf, d->character);
  sprintf(buf, "Room zone: %d\r\n",
	  zone_table[d->edit_room->zone].number);
  send_to_char(buf, d->character);
  sprintbit((long) d->edit_room->room_flags, room_bits, buf2);
  sprintf(buf, "3) Room flags: %s\r\n", buf2);
  send_to_char(buf, d->character);
  sprinttype(d->edit_room->sector_type, sector_types, buf2);
  sprintf(buf, "4) Sector type: %s\r\n", buf2);
  send_to_char(buf, d->character);
  if (d->edit_room->dir_option[NORTH])
    sprintf(buf2, "%d", d->edit_room->dir_option[NORTH]->to_room_vnum);
  else
    strcpy(buf2, "<NONE>");
  sprintf(buf, "5) Exit north to: %s\r\n", buf2);
  send_to_char(buf, d->character);
  if (d->edit_room->dir_option[EAST])
    sprintf(buf2, "%d", d->edit_room->dir_option[EAST]->to_room_vnum);
  else
    strcpy(buf2, "<NONE>");
  sprintf(buf, "6) Exit east to:  %s\r\n", buf2);
  send_to_char(buf, d->character);
  if (d->edit_room->dir_option[SOUTH])
    sprintf(buf2, "%d", d->edit_room->dir_option[SOUTH]->to_room_vnum);
  else
    strcpy(buf2, "<NONE>");
  sprintf(buf, "7) Exit south to: %s\r\n", buf2);
  send_to_char(buf, d->character);

  if (d->edit_room->dir_option[WEST])
    sprintf(buf2, "%d", d->edit_room->dir_option[WEST]->to_room_vnum);
  else
    strcpy(buf2, "<NONE>");
  sprintf(buf, "8) Exit west to:  %s\r\n", buf2);
  send_to_char(buf, d->character);
  if (d->edit_room->dir_option[UP])
    sprintf(buf2, "%d", d->edit_room->dir_option[UP]->to_room_vnum);
  else
    strcpy(buf2, "<NONE>");
  sprintf(buf, "9) Exit up to:    %s\r\n", buf2);
  send_to_char(buf, d->character);
  if (d->edit_room->dir_option[DOWN])
    sprintf(buf2, "%d", d->edit_room->dir_option[DOWN]->to_room_vnum);
  else
    strcpy(buf2, "<NONE>");
  sprintf(buf, "a) Exit down to:  %s\r\n", buf2);
  send_to_char(buf, d->character);
  send_to_char("b) Extra descriptions\r\n", d->character);
  send_to_char("q) Quit\r\n", d->character);
  send_to_char("Enter your choice:\r\n", d->character);
}



/**************************************************************************
  The main loop
 **************************************************************************/

void redit_parse(struct descriptor_data * d, char *arg)
{
  extern struct room_data *world;
  int             number;
  int             room_num;
  switch (d->edit_mode) {
  case REDIT_CONFIRM_EDIT:
    switch (*arg) {
    case 'y':
    case 'Y':
      redit_disp_menu(d);
      break;
    case 'n':
    case 'N':
      /* player doesn't want to edit, free entire temp room */
      STATE(d) = CON_PLAYING;
      if (d->edit_room)
	free_room(d->edit_room);
      d->edit_room = NULL;
      REMOVE_BIT(PLR_FLAGS(d->character), PLR_EDITING);
      break;
    default:
      send_to_char("That's not a valid choice!\r\n", d->character);
      send_to_char("Do you wish to edit it?\r\n", d->character);
      break;
    }
    break; /* end of REDIT_CONFIRM_EDIT */
  case REDIT_CONFIRM_SAVEDB:
    switch (*arg) {
    case 'y':
    case 'Y':
      send_to_char("Writing room to disk.\r\n", d->character);

      {
	/* this code writes the entire zone containing
	   the edited room to disk */
	int             counter, counter2, realcounter;
	FILE           *fp;
	struct room_data *room;
	struct extra_descr_data *ex_desc;

	/* not really necessary, but I"m lazy :) */
	CREATE(room, struct room_data, 1);

	sprintf(buf, "%s/%d.wld", WLD_PREFIX,
		zone_table[d->edit_zone].number);
	fp = fopen(buf, "w+");
	for (counter = zone_table[d->edit_zone].number * 100;
	     counter <= zone_table[d->edit_zone].top;
	     counter++) {
	  realcounter = real_room(counter);
	  if (realcounter >= 0) {
	    *room = world[realcounter];
	    fprintf(fp, "#%d\n", counter);
	    fprintf(fp, "%s~\n", room->name);
	    fprintf(fp, "%s~\n", room->description);
	    fprintf(fp, "%d %d %d\n",
		    zone_table[room->zone].number,
		    room->room_flags, room->sector_type);
	    for (counter2 = 0; counter2 < NUM_OF_DIRS; counter2++) {
	      if (room->dir_option[counter2]) {
		int             temp_door_flag;
		fprintf(fp, "D%d\n", counter2);
		fprintf(fp, "%s~\n",
			room->dir_option[counter2]->general_description ?
			room->dir_option[counter2]->general_description :
			"");
		fprintf(fp, "%s~\n", room->dir_option[counter2]->keyword ?
			room->dir_option[counter2]->keyword :
			"");
		/* door flags need special handling, unfortunately. argh! */
		if (IS_SET(room->dir_option[counter2]->exit_info, EX_ISDOOR)) {
		  if (IS_SET(room->dir_option[counter2]->exit_info, EX_PICKPROOF))
		    temp_door_flag = 2;
		  else
		    temp_door_flag = 1;
		} else
		  temp_door_flag = 0;
                if (IS_SET(room->dir_option[counter2]->exit_info, EX_HIDDEN))
		  temp_door_flag += 3;
		fprintf(fp, "%d %d %d\n",
			temp_door_flag,
			room->dir_option[counter2]->key,
			room->dir_option[counter2]->to_room_vnum);
	      }
	    }
	    if (room->ex_description) {
	      for (ex_desc = room->ex_description; ex_desc; ex_desc = ex_desc->next) {
		fprintf(fp, "E\n");
		fprintf(fp, "%s~\n", ex_desc->keyword);
		fprintf(fp, "%s~\n", ex_desc->description);
	      }
	    }
	    fprintf(fp, "S\n");
	  }
	}
	/* free temporary */
	free(room);
	/* write final line and close */
	fprintf(fp, "$~\n");
	fclose(fp);
	send_to_char("Saved.\r\n", d->character);
	/* do NOT free strings! just the room structure */
	free(d->edit_room);
	d->edit_room = NULL;
	REMOVE_BIT(PLR_FLAGS(d->character), PLR_EDITING);
	STATE(d) = CON_PLAYING;
	send_to_char("Done.\r\n", d->character);
      }
      break;
    case 'n':
    case 'N':
      send_to_char("Room not saved to disk, available until next reboot.\r\n", d->character);
      /* I can free the room structure, but I cannot free the string / exit
       * pointers! */
      free(d->edit_room);
      d->edit_room = NULL;
      REMOVE_BIT(PLR_FLAGS(d->character), PLR_EDITING);
      STATE(d) = CON_PLAYING;
      send_to_char("Done.\r\n", d->character);
      break;
    default:
      send_to_char("Invalid choice!\r\n", d->character);
      send_to_char("Do you wish to write this room to disk?", d->character);
      break;
    }
    break; /* end of REDIT_CONFIRM_SAVEDB */
  case REDIT_CONFIRM_SAVESTRING:
    switch (*arg) {
    case 'y':
    case 'Y':
      {
	int             counter;
	struct extra_descr_data *this, *next_one;
	room_num = real_room(d->edit_number);
	if (room_num > 0) {
	  /* copy people/object pointers over to the temp room
	     as a temporary measure */
	  d->edit_room->contents = world[room_num].contents;
	  d->edit_room->people = world[room_num].people;
	  /* find the original room, and free all strings/pointers */
	  if (world[room_num].name)
	    free(world[room_num].name);
	  if (world[room_num].description)
	    free(world[room_num].description);
	  for (counter = 0; counter < NUM_OF_DIRS; counter++) {
	    if (world[room_num].dir_option[counter]) {
	      if (world[room_num].dir_option[counter]->general_description)
		free(world[room_num].dir_option[counter]->general_description);
	      if (world[room_num].dir_option[counter]->keyword)
		free(world[room_num].dir_option[counter]->keyword);
	    }
	  }
	  if (world[room_num].ex_description)
	    for (this = world[room_num].ex_description; this; this = next_one) 
	      {
		next_one = this->next;
		if (this->keyword)
		  free(this->keyword);
		if (this->description)
		  free(this->description);
		free(this);
	      }
	  /* now copy everything over! */
	  world[room_num] = *d->edit_room;
	  /* resolve all vnum doors to rnum doors in the newly edited room */
	  for (counter = 0; counter < NUM_OF_DIRS; counter++) {
	    if (world[room_num].dir_option[counter]) {
	      world[room_num].dir_option[counter]->to_room =
		real_room(world[room_num].dir_option[counter]->to_room_vnum);
	    }
	  }

	} else {
	  /* hm, we can't just copy.. gotta insert a new room */
	  int             counter;
	  int             counter2;
	  int             found = 0;
	  /* make a new world table with one more spot */
	  struct room_data *new_world;
	  CREATE(new_world, struct room_data, top_of_world + 2);
	  /* count thru world tables */
	  for (counter = 0; counter < top_of_world + 1; counter++) {
	    /* if we haven't found place to insert  */
	    if (!found) {
	      struct char_data *temp_ch;
	      struct obj_data *temp_obj;
	      /* check if current virtual is bigger than our virtual */
	      if (world[counter].number > d->edit_number) {
		/* eureka! insert now */
		new_world[counter] = *(d->edit_room);
		new_world[counter].number = d->edit_number;
		new_world[counter].func = NULL;
		found = 1;
		/* people in this room must have their numbers moved */
		for (temp_ch = world[counter].people; temp_ch;
		     temp_ch = temp_ch->next_in_room)
		  if (temp_ch->in_room != -1)
		    temp_ch->in_room = counter + 1;
		/* move objects */
		for (temp_obj = world[counter].contents; temp_obj;
		     temp_obj = temp_obj->next_content)
		  if (temp_obj->in_room != -1)
		    temp_obj->in_room = counter + 1;
		/* copy from world to new_world + 1 */
		new_world[counter + 1] = world[counter];
	      } else {
		/* just copy everything over if current virtual
		   is not bigger */
		new_world[counter] = world[counter];
	      }
	    } else {		/* we have found it */
	      /* people in this room must have their in_rooms moved */
	      struct char_data *temp_ch;
	      struct obj_data *temp_obj;
	      for (temp_ch = world[counter].people; temp_ch;
		   temp_ch = temp_ch->next_in_room)
		if (temp_ch->in_room != -1)
		  temp_ch->in_room = counter + 1;
	      /* move objects */
	      for (temp_obj = world[counter].contents; temp_obj;
		   temp_obj = temp_obj->next_content)
		if (temp_obj->in_room != -1)
		  temp_obj->in_room = counter + 1;

	      new_world[counter + 1] = world[counter];
	    }
	  }
	  top_of_world++;
	  /* copy world table over */
	  free(world);
	  world = new_world;
	  /* we have to update the start rooms */
	  r_mortal_start_room = real_room(mortal_start_room);
	  r_immort_start_room = real_room(immort_start_room);
	  r_frozen_start_room = real_room(frozen_start_room);
	  /* now this is the *real* room_num */
	  room_num = real_room(d->edit_number);
	  /* go through the world. if any of the old rooms indicated an exit
	   * to our new room, we have to change it */
	  for (counter = 0; counter < top_of_world + 1; counter++)
	    for (counter2 = 0; counter2 < NUM_OF_DIRS; counter2++) {
	      /* if exit exists */
	      if (world[counter].dir_option[counter2]) {
		/* increment r_nums for rooms bigger than or equal to new one
		 * because we inserted room */
		if (world[counter].dir_option[counter2]->to_room >= room_num)
		  world[counter].dir_option[counter2]->to_room =
		    world[counter].dir_option[counter2]->to_room + 1;
		/* if an exit to the new room is indicated, change to_room */
		if (world[counter].dir_option[counter2]->to_room_vnum
		    == d->edit_number)
		  world[counter].dir_option[counter2]->to_room =
		    room_num;
	      }
	    }
	  /* resolve all vnum doors to rnum doors in the newly edited room */
	  for (counter2 = 0; counter2 < NUM_OF_DIRS; counter2++) {
	    if (world[room_num].dir_option[counter2]) {
	      world[room_num].dir_option[counter2]->to_room =
		real_room(world[room_num].dir_option[counter2]->to_room_vnum);
	    }
	  }
	}
	send_to_char("Do you want to write this room to disk?\r\n",
		     d->character);
	d->edit_mode = REDIT_CONFIRM_SAVEDB;
      }
      break;
    case 'n':
    case 'N':
      send_to_char("Room not saved, aborting.\r\n", d->character);
      STATE(d) = CON_PLAYING;
      REMOVE_BIT(PLR_FLAGS(d->character), PLR_EDITING);
      /* free everything up, including strings etc */
      if (d->edit_room)
	free_room(d->edit_room);
      d->edit_room = NULL;
      d->edit_number = 0;
      break;
    default:
      send_to_char("Invalid choice!\r\n", d->character);
      send_to_char("Do you wish to save this room internally?", d->character);
      break;
    }
    break; /* end of REDIT_CONFIRM_SAVESTRING */
  case REDIT_MAIN_MENU:
    switch (*arg) {
    case 'q':
    case 'Q':
      send_to_char("Do you wish to save this room internally?\r\n", d->character);
      d->edit_mode = REDIT_CONFIRM_SAVESTRING;
      break;
    case '1':
      send_to_char("Enter room name:", d->character);
      d->edit_mode = REDIT_NAME;
      break;
    case '2':
      send_to_char("Enter room description:\r\n", d->character);
      d->edit_mode = REDIT_DESC;
      d->str = (char **) malloc(sizeof(char *));
      *(d->str) = NULL;
      d->max_str = MAX_MESSAGE_LENGTH;
      d->mail_to = 0;
      break;
    case '3':
      redit_disp_flag_menu(d);
      break;
    case '4':
      redit_disp_sector_menu(d);
      break;
    case '5':
      d->edit_number2 = NORTH;
      redit_disp_exit_menu(d);
      break;
    case '6':
      d->edit_number2 = EAST;
      redit_disp_exit_menu(d);
      break;
    case '7':
      d->edit_number2 = SOUTH;
      redit_disp_exit_menu(d);
      break;
    case '8':
      d->edit_number2 = WEST;
      redit_disp_exit_menu(d);
      break;
    case '9':
      d->edit_number2 = UP;
      redit_disp_exit_menu(d);
      break;
    case 'a':
    case 'A':
      d->edit_number2 = DOWN;
      redit_disp_exit_menu(d);
      break;
    case 'b':
    case 'B':
      /* if extra desc doesn't exist . */
      if (!d->edit_room->ex_description) {
	CREATE(d->edit_room->ex_description, struct extra_descr_data, 1);
	d->edit_room->ex_description->next = NULL;
      }
      d->misc_data = (void **) &(d->edit_room->ex_description);
      redit_disp_extradesc_menu(d);
      break;
    default:
      send_to_char("Invalid choice!", d->character);
      redit_disp_menu(d);
      break;
    }
    break;
  case REDIT_NAME:
    if (d->edit_room->name)
      free(d->edit_room->name);
    d->edit_room->name = str_dup(arg);
    redit_disp_menu(d);
    break;
  case REDIT_DESC:
    /* we will NEVER get here */
    break;
  case REDIT_FLAGS:
    number = atoi(arg);
    if ((number < 0) || (number > NUM_ROOM_FLAGS)) {
      send_to_char("That's not a valid choice!\r\n", d->character);
      redit_disp_flag_menu(d);
    } else {
      if (number == 0)
	/* back out */
	redit_disp_menu(d);
      else {
	/* toggle bits */
	if (IS_SET(d->edit_room->room_flags, 1 << (number - 1)))
	  REMOVE_BIT(d->edit_room->room_flags, 1 << (number - 1));
	else
	  SET_BIT(d->edit_room->room_flags, 1 << (number - 1));
	redit_disp_flag_menu(d);
      }
    }
    break;
  case REDIT_SECTOR:
    number = atoi(arg);
    if (number < 0 || number >= NUM_ROOM_SECTORS) {
      send_to_char("Invalid choice!", d->character);
      redit_disp_sector_menu(d);
    } else {
      d->edit_room->sector_type = number;
      redit_disp_menu(d);
    }
    break;
  case REDIT_EXIT_MENU:
    switch (*arg) {
    case '0':
      redit_disp_menu(d);
      break;
    case '1':
      d->edit_mode = REDIT_EXIT_NUMBER;
      send_to_char("Exit to room number:", d->character);
      break;
    case '2':
      d->edit_mode = REDIT_EXIT_DESCRIPTION;
      d->str = (char **) malloc(sizeof(char *));
      *(d->str) = NULL;
      d->max_str = MAX_MESSAGE_LENGTH;
      d->mail_to = 0;
      send_to_char("Enter exit description:\r\n", d->character);
      break;
    case '3':
      d->edit_mode = REDIT_EXIT_KEYWORD;
      send_to_char("Enter keywords:", d->character);
      break;
    case '4':
      d->edit_mode = REDIT_EXIT_KEY;
      send_to_char("Enter key number:", d->character);
      break;
    case '5':
      redit_disp_exit_flag_menu(d);
      d->edit_mode = REDIT_EXIT_DOORFLAGS;
      break;
    case '6':
      /* delete exit */
      if (d->edit_room->dir_option[d->edit_number2]->keyword)
	free(d->edit_room->dir_option[d->edit_number2]->keyword);
      if (d->edit_room->dir_option[d->edit_number2]->general_description)
	free(d->edit_room->dir_option[d->edit_number2]->general_description);
      free(d->edit_room->dir_option[d->edit_number2]);
      d->edit_room->dir_option[d->edit_number2] = NULL;
      redit_disp_menu(d);
      break;
    default:
      send_to_char("Invalid choice!\r\n", d->character);
      break;
    }
    break;
  case REDIT_EXIT_NUMBER:
    number = atoi(arg);
    if (number < 0)
      send_to_char("Invalid choice!\r\nExit to room number:", d->character);
    else {
      d->edit_room->dir_option[d->edit_number2]->to_room_vnum = number;
      redit_disp_exit_menu(d);
    }
    break;
  case REDIT_EXIT_DESCRIPTION:
    /* we should NEVER get here */
    break;
  case REDIT_EXIT_KEYWORD:
    if (d->edit_room->dir_option[d->edit_number2]->keyword)
      free(d->edit_room->dir_option[d->edit_number2]->keyword);
    d->edit_room->dir_option[d->edit_number2]->keyword = str_dup(arg);
    redit_disp_exit_menu(d);
    break;
  case REDIT_EXIT_KEY:
    number = atoi(arg);
    d->edit_room->dir_option[d->edit_number2]->key = number;
    redit_disp_exit_menu(d);
    break;
  case REDIT_EXIT_DOORFLAGS:
    number = atoi(arg);
    if ((number < 0) || (number > 5)) {
      send_to_char("That's not a valid choice!\r\n", d->character);
      redit_disp_exit_flag_menu(d);
    } else {
      /* doors are a bit idiotic, don't you think? :) */
      d->edit_room->dir_option[d->edit_number2]->exit_info = 0;
      if (number == 1)
	d->edit_room->dir_option[d->edit_number2]->exit_info = EX_ISDOOR;
      else if (number == 2)
	d->edit_room->dir_option[d->edit_number2]->exit_info =
	  EX_ISDOOR | EX_PICKPROOF;
      else if (number == 3)
	d->edit_room->dir_option[d->edit_number2]->exit_info = EX_HIDDEN;
      else if (number == 4)
	d->edit_room->dir_option[d->edit_number2]->exit_info = EX_ISDOOR | EX_HIDDEN;
      else if (number == 5)
	d->edit_room->dir_option[d->edit_number2]->exit_info =
	  EX_ISDOOR | EX_PICKPROOF | EX_HIDDEN;
      /* jump out to menu */
      redit_disp_exit_menu(d);
    }
    break;
  case REDIT_EXTRADESC_KEY:
    ((struct extra_descr_data *) * d->misc_data)->keyword = str_dup(arg);
    redit_disp_extradesc_menu(d);
    break;
  case REDIT_EXTRADESC_MENU:
    number = atoi(arg);
    switch (number) {
    case 0:
      {
	/* if something got left out, delete the extra desc
	 when backing out to menu */
	if (!((struct extra_descr_data *) * d->misc_data)->keyword ||
	    !((struct extra_descr_data *) * d->misc_data)->description) {
	  if (((struct extra_descr_data *) * d->misc_data)->keyword)
	    free(((struct extra_descr_data *) * d->misc_data)->keyword);
	  if (((struct extra_descr_data *) * d->misc_data)->description)
	    free(((struct extra_descr_data *) * d->misc_data)->description);

	  free(*d->misc_data);
	  *d->misc_data = NULL;
	}
	/* else, we don't need to do anything.. jump to menu */
	redit_disp_menu(d);
      }
      break;
    case 1:
      d->edit_mode = REDIT_EXTRADESC_KEY;
      send_to_char("Enter keywords, separated by spaces:", d->character);
      break;
    case 2:
      d->edit_mode = REDIT_EXTRADESC_DESCRIPTION;
      send_to_char("Enter extra description:\r\n", d->character);
      /* send out to modify.c */
      d->str = (char **) malloc(sizeof(char *));
      *(d->str) = NULL;
      d->max_str = MAX_MESSAGE_LENGTH;
      d->mail_to = 0;
      break;
    case 3:
      if (!((struct extra_descr_data *) d->misc_data)->keyword ||
	  !((struct extra_descr_data *) d->misc_data)->description) {
	send_to_char("You can't edit the next extra desc without completing this one.\r\n", d->character);
	redit_disp_extradesc_menu(d);
      } else {
	struct extra_descr_data *new_extra;

	if (((struct extra_descr_data *) * d->misc_data)->next)
	  d->misc_data = (void **) &((struct extra_descr_data *) * d->misc_data)->next;
	else {
	  /* make new extra, attach at end */
	  CREATE(new_extra, struct extra_descr_data, 1);
	  ((struct extra_descr_data *) * d->misc_data)->next = new_extra;
	  d->misc_data =
	    (void **) &((struct extra_descr_data *) * d->misc_data)->next;
	}
	redit_disp_extradesc_menu(d);
      }
    }
    break;
  default:
    /* we should never get here */
    break;
  }
}