rasputin/bin/
rasputin/cnf/
rasputin/doc/cwg/
rasputin/lib/
rasputin/lib/etc/
rasputin/lib/etc/boards/
rasputin/lib/house/
rasputin/lib/misc/
rasputin/lib/plralias/A-E/
rasputin/lib/plralias/F-J/
rasputin/lib/plralias/K-O/
rasputin/lib/plralias/P-T/
rasputin/lib/plralias/U-Z/
rasputin/lib/plralias/ZZZ/
rasputin/lib/plrfiles/
rasputin/lib/plrfiles/A-E/
rasputin/lib/plrfiles/F-J/
rasputin/lib/plrfiles/K-O/
rasputin/lib/plrfiles/P-T/
rasputin/lib/plrfiles/U-Z/
rasputin/lib/plrfiles/ZZZ/
rasputin/lib/plrobjs/
rasputin/lib/plrobjs/A-E/
rasputin/lib/plrobjs/F-J/
rasputin/lib/plrobjs/K-O/
rasputin/lib/plrobjs/P-T/
rasputin/lib/plrobjs/U-Z/
rasputin/lib/plrobjs/ZZZ/
rasputin/lib/plrvars/A-E/
rasputin/lib/plrvars/F-J/
rasputin/lib/plrvars/K-O/
rasputin/lib/plrvars/P-T/
rasputin/lib/plrvars/U-Z/
rasputin/lib/plrvars/ZZZ/
rasputin/lib/world/gld/
rasputin/lib/world/trg/
rasputin/src/
rasputin/src/doc/
/************************************************************************
 * OasisOLC - Objects / oedit.c					v2.0	*
 * Original author: Levork						*
 * Copyright 1996 by Harvey Gilpin					*
 * Copyright 1997-2001 by George Greer (greerga@circlemud.org)		*
 ************************************************************************/

#include "conf.h"
#include "sysdep.h"

CVSHEADER("$CVSHeader: cwg/rasputin/src/oedit.c,v 1.12 2005/05/29 18:36:38 zizazat Exp $");

#include "structs.h"
#include "comm.h"
#include "interpreter.h"
#include "spells.h"
#include "utils.h"
#include "db.h"
#include "handler.h"
#include "boards.h"
#include "constants.h"
#include "shop.h"
#include "genolc.h"
#include "genobj.h"
#include "genzon.h"
#include "oasis.h"
#include "improved-edit.h"
#include "dg_olc.h"
#include "feats.h"

/*------------------------------------------------------------------------*/

/*
 * External variable declarations.
 */

extern struct obj_data *obj_proto;
extern struct index_data *obj_index;
extern struct obj_data *object_list;
extern obj_rnum top_of_objt;
extern struct zone_data *zone_table;
extern zone_rnum top_of_zone_table;
extern struct shop_data *shop_index;
extern struct attack_hit_type attack_hit_text[];
extern struct spell_info_type spell_info[];
extern struct board_info *bboards;
extern struct descriptor_data *descriptor_list;
extern const char *material_names[];
extern long max_obj_id;

/*------------------------------------------------------------------------*/
extern zone_rnum real_zone_by_thing(room_vnum vznum);

/*
 * Handy macros.
 */
#define S_PRODUCT(s, i) ((s)->producing[(i)])

/*------------------------------------------------------------------------*\
  Utility and exported functions
\*------------------------------------------------------------------------*/

ACMD(do_oasis_oedit)
{
  int number = NOWHERE, save = 0, real_num;
  struct descriptor_data *d;
  char *buf3;
  char buf1[MAX_STRING_LENGTH];
  char buf2[MAX_STRING_LENGTH];
  
  /****************************************************************************/
  /** Parse any arguments.                                                   **/
  /****************************************************************************/
  buf3 = two_arguments(argument, buf1, buf2);
  
  /****************************************************************************/
  /** If there aren't any arguments...well...they can't modify nothing now   **/
  /** can they?                                                              **/
  /****************************************************************************/
  if (!*buf1) {
    send_to_char(ch, "Specify an object VNUM to edit.\r\n");
    return;
  } else if (!isdigit(*buf1)) {
    if (str_cmp("save", buf1) != 0) {
      send_to_char(ch, "Yikes!  Stop that, someone will get hurt!\r\n");
      return;
    }
    
    save = TRUE;
    
    if (is_number(buf2))
      number = atoi(buf2);
    else if (GET_OLC_ZONE(ch) > 0) {
      zone_rnum zlok;
      
      if ((zlok = real_zone(GET_OLC_ZONE(ch))) == NOWHERE)
        number = NOWHERE;
      else
        number = genolc_zone_bottom(zlok);
    }
    
    if (number == NOWHERE) {
      send_to_char(ch, "Save which zone?\r\n");
      return;
    }
  }
  
  /****************************************************************************/
  /** If a numeric argument was given, get it.                               **/
  /****************************************************************************/
  if (number == NOWHERE)
    number = atoi(buf1);
  
  /****************************************************************************/
  /** Check that whatever it is isn't already being edited.                  **/
  /****************************************************************************/
  for (d = descriptor_list; d; d = d->next) {
    if (STATE(d) == CON_OEDIT) {
      if (d->olc && OLC_NUM(d) == number) {
        send_to_char(ch, "That object is currently being edited by %s.\r\n",
          PERS(d->character, ch));
        return;
      }
    }
  }
  
  /****************************************************************************/
  /** Point d to the builder's descriptor (for easier typing later).         **/
  /****************************************************************************/
  d = ch->desc;
  
  /****************************************************************************/
  /** Give the descriptor an OLC structure.                                  **/
  /****************************************************************************/
  if (d->olc) {
    mudlog(BRF, ADMLVL_IMMORT, TRUE,
      "SYSERR: do_oasis: Player already had olc structure.");
    free(d->olc);
  }
  
  CREATE(d->olc, struct oasis_olc_data, 1);
  
  /****************************************************************************/
  /** Find the zone.                                                         **/
  /****************************************************************************/
  OLC_ZNUM(d) = save ? real_zone(number) : real_zone_by_thing(number);
  if (OLC_ZNUM(d) == NOWHERE) {
    send_to_char(ch, "Sorry, there is no zone for that number!\r\n");
    
    /**************************************************************************/
    /** Free the descriptor's OLC structure.                                 **/
    /**************************************************************************/
    free(d->olc);
    d->olc = NULL;
    return;
  }
  
  /****************************************************************************/
  /** Everyone but IMPLs can only edit zones they have been assigned.        **/
  /****************************************************************************/
  if (!can_edit_zone(ch, OLC_ZNUM(d))) {
    send_to_char(ch, "You do not have permission to edit this zone.\r\n");
    mudlog(BRF, ADMLVL_IMPL, TRUE, "OLC: %s tried to edit zone %d allowed zone %d",
      GET_NAME(ch), zone_table[OLC_ZNUM(d)].number, GET_OLC_ZONE(ch));
    
    /**************************************************************************/
    /** Free the descriptor's OLC structure.                                 **/
    /**************************************************************************/
    free(d->olc);
    d->olc = NULL;
    return;
  }
  
  /****************************************************************************/
  /** If we need to save, save the objects.                                  **/
  /****************************************************************************/
  if (save) {
    send_to_char(ch, "Saving all objects in zone %d.\r\n",
      zone_table[OLC_ZNUM(d)].number);
    mudlog(CMP, MAX(ADMLVL_BUILDER, GET_INVIS_LEV(ch)), TRUE,
      "OLC: %s saves object info for zone %d.", GET_NAME(ch),
      zone_table[OLC_ZNUM(d)].number);
    
    /**************************************************************************/
    /** Save the objects in this zone.                                       **/
    /**************************************************************************/
    save_objects(OLC_ZNUM(d));
    
    /**************************************************************************/
    /** Free the descriptor's OLC structure.                                 **/
    /**************************************************************************/
    free(d->olc);
    d->olc = NULL;
    return;
  }
  
  OLC_NUM(d) = number;
  
  /****************************************************************************/
  /** If this is a new object, setup a new object, otherwise setup the       **/
  /** existing object.                                                       **/
  /****************************************************************************/
  if ((real_num = real_object(number)) != NOTHING)
    oedit_setup_existing(d, real_num);
  else
    oedit_setup_new(d);
    
  STATE(d) = CON_OEDIT;
  
  /****************************************************************************/
  /** Send the OLC message to the players in the same room as the builder.   **/
  /****************************************************************************/
  act("$n starts using OLC.", TRUE, d->character, 0, 0, TO_ROOM);
  SET_BIT_AR(PLR_FLAGS(ch), PLR_WRITING);
  
  /****************************************************************************/
  /** Log the OLC message.                                                   **/
  /****************************************************************************/
  mudlog(BRF, ADMLVL_IMMORT, TRUE, "OLC: %s starts editing zone %d allowed zone %d",
    GET_NAME(ch), zone_table[OLC_ZNUM(d)].number, GET_OLC_ZONE(ch));
}

void oedit_setup_new(struct descriptor_data *d)
{
  CREATE(OLC_OBJ(d), struct obj_data, 1);

  clear_object(OLC_OBJ(d));
  OLC_OBJ(d)->name = strdup("unfinished object");
  OLC_OBJ(d)->description = strdup("An unfinished object is lying here.");
  OLC_OBJ(d)->short_description = strdup("an unfinished object");
  SET_BIT_AR(GET_OBJ_WEAR(OLC_OBJ(d)), ITEM_WEAR_TAKE);
  OLC_VAL(d) = 0;
  OLC_ITEM_TYPE(d) = OBJ_TRIGGER;

  SCRIPT(OLC_OBJ(d)) = NULL;
  OLC_OBJ(d)->proto_script = OLC_SCRIPT(d) = NULL;

  oedit_disp_menu(d);
}

/*------------------------------------------------------------------------*/

void oedit_setup_existing(struct descriptor_data *d, int real_num)
{
  struct obj_data *obj;

  /*
   * Allocate object in memory.
   */
  CREATE(obj, struct obj_data, 1);
  copy_object(obj, &obj_proto[real_num]);

  /*
   * Attach new object to player's descriptor.
   */
  OLC_OBJ(d) = obj;
  OLC_VAL(d) = 0;
  OLC_ITEM_TYPE(d) = OBJ_TRIGGER;
  dg_olc_script_copy(d);
  /*
   * The edited obj must not have a script.
   * It will be assigned to the updated obj later, after editing.
   */
  SCRIPT(obj) = NULL;
  OLC_OBJ(d)->proto_script = NULL;

  oedit_disp_menu(d);
}

/*------------------------------------------------------------------------*/

void oedit_save_internally(struct descriptor_data *d)
{
  int i;
  obj_rnum robj_num;
  struct descriptor_data *dsc;
  struct obj_data *obj;

  i = (real_object(OLC_NUM(d)) == NOTHING);

  if ((robj_num = add_object(OLC_OBJ(d), OLC_NUM(d))) == NOTHING) {
    log("oedit_save_internally: add_object failed.");
    return;
  }

  /* Update triggers : */
  /* Free old proto list  */
  if (obj_proto[robj_num].proto_script &&
      obj_proto[robj_num].proto_script != OLC_SCRIPT(d)) 
    free_proto_script(&obj_proto[robj_num], OBJ_TRIGGER);   
  /* this will handle new instances of the object: */
  obj_proto[robj_num].proto_script = OLC_SCRIPT(d);

  /* this takes care of the objects currently in-game */
  for (obj = object_list; obj; obj = obj->next) {
    if (obj->item_number != robj_num)
      continue;
    /* remove any old scripts */
    if (SCRIPT(obj)) 
      extract_script(obj, OBJ_TRIGGER);

    free_proto_script(obj, OBJ_TRIGGER);
    copy_proto_script(&obj_proto[robj_num], obj, OBJ_TRIGGER);
    assign_triggers(obj, OBJ_TRIGGER);
  }
  /* end trigger update */

  if (!i)	/* If it's not a new object, don't renumber. */
    return;

  /*
   * Renumber produce in shops being edited.
   */
  for (dsc = descriptor_list; dsc; dsc = dsc->next)
    if (STATE(dsc) == CON_SEDIT)
      for (i = 0; S_PRODUCT(OLC_SHOP(dsc), i) != NOTHING; i++)
	if (S_PRODUCT(OLC_SHOP(dsc), i) >= robj_num)
	  S_PRODUCT(OLC_SHOP(dsc), i)++;


  /* Update other people in zedit too. From: C.Raehl 4/27/99 */
  for (dsc = descriptor_list; dsc; dsc = dsc->next)
    if (STATE(dsc) == CON_ZEDIT)
      for (i = 0; OLC_ZONE(dsc)->cmd[i].command != 'S'; i++)
        switch (OLC_ZONE(dsc)->cmd[i].command) {
          case 'P':
            OLC_ZONE(dsc)->cmd[i].arg3 += (OLC_ZONE(dsc)->cmd[i].arg3 >= robj_num);
            /* Fall through. */
          case 'E':
          case 'G':
          case 'O':
            OLC_ZONE(dsc)->cmd[i].arg1 += (OLC_ZONE(dsc)->cmd[i].arg1 >= robj_num);
            break;
          case 'R':
            OLC_ZONE(dsc)->cmd[i].arg2 += (OLC_ZONE(dsc)->cmd[i].arg2 >= robj_num);
            break;
          default:
          break;
        }
}

/*------------------------------------------------------------------------*/

void oedit_save_to_disk(int zone_num)
{
  save_objects(zone_num);
}

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

/*
 * For container flags.
 */
void oedit_disp_container_flags_menu(struct descriptor_data *d)
{
  char bits[MAX_STRING_LENGTH];
  clear_screen(d);

  sprintbit(GET_OBJ_VAL(OLC_OBJ(d), 1), container_bits, bits, sizeof(bits));
  write_to_output(d, 
	  "@g1@n) CLOSEABLE\r\n"
	  "@g2@n) PICKPROOF\r\n"
	  "@g3@n) CLOSED\r\n"
	  "@g4@n) LOCKED\r\n"
	  "Container flags: @c%s@n\r\n"
	  "Enter flag, 0 to quit : ",
	  bits);
}

/*
 * For extra descriptions.
 */
void oedit_disp_extradesc_menu(struct descriptor_data *d)
{
  struct extra_descr_data *extra_desc = OLC_DESC(d);

  clear_screen(d);
  write_to_output(d,
	  "Extra desc menu\r\n"
	  "@g1@n) Keyword: @y%s@n\r\n"
	  "@g2@n) Description:\r\n@y%s@n\r\n"
	  "@g3@n) Goto next description: %s\r\n"
	  "@g0@n) Quit\r\n"
	  "Enter choice : ",

     	  (extra_desc->keyword && *extra_desc->keyword) ? extra_desc->keyword : "<NONE>",
	  (extra_desc->description && *extra_desc->description) ? extra_desc->description : "<NONE>",
	  !extra_desc->next ? "<Not set>\r\n" : "Set.");
  OLC_MODE(d) = OEDIT_EXTRADESC_MENU;
}

/*
 * Ask for *which* apply to edit.
 */
void oedit_disp_prompt_apply_menu(struct descriptor_data *d)
{
  char apply_buf[MAX_STRING_LENGTH];
  int counter;

  clear_screen(d);

  for (counter = 0; counter < MAX_OBJ_AFFECT; counter++) {
    if (OLC_OBJ(d)->affected[counter].modifier) {
      sprinttype(OLC_OBJ(d)->affected[counter].location, apply_types, apply_buf, sizeof(apply_buf));
      write_to_output(d, " @g%d@n) %+d to @b%s@n", counter + 1,
                      OLC_OBJ(d)->affected[counter].modifier, apply_buf);
      switch (OLC_OBJ(d)->affected[counter].location) {
      case APPLY_FEAT:
        write_to_output(d, " (%s)", feat_list[OLC_OBJ(d)->affected[counter].specific].name);
        break;
      case APPLY_SKILL:
        write_to_output(d, " (%s)", spell_info[OLC_OBJ(d)->affected[counter].specific].name);
        break;
      }
      write_to_output(d, "\r\n");
    } else {
      write_to_output(d, " @g%d@n) None.\r\n", counter + 1);
    }
  }
  write_to_output(d, "\r\nEnter affection to modify (0 to quit) : ");
  OLC_MODE(d) = OEDIT_PROMPT_APPLY;
}

void oedit_disp_prompt_spellbook_menu(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < SPELLBOOK_SIZE; counter++) {
    if (OLC_OBJ(d)->sbinfo && OLC_OBJ(d)->sbinfo[counter].spellname != 0 ) {
      write_to_output(d, " @g%3d@n) %-20.20s %s", counter + 1,
             spell_info[OLC_OBJ(d)->sbinfo[counter].spellname].name, !(++columns % 3) ? "\r\n" : "");
    } else {
      write_to_output(d, " @g%3d@n) None.%s", counter + 1, !(++columns % 3) ? "\r\n" : "");
    }
  }
  write_to_output(d, "\r\nEnter spell to modify (0 to quit) : ");
  OLC_MODE(d) = OEDIT_PROMPT_SPELLBOOK;
}

void oedit_disp_spellbook_menu(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < SKILL_TABLE_SIZE; counter++) {
    if (spell_info[counter].skilltype == SKTYPE_SPELL)
      write_to_output(d, "@g%3d@n) @y%-20.20s@n%s", counter,
               spell_info[counter].name, !(++columns % 3) ? "\r\n" : "");
  }
  write_to_output(d, "@n\r\nEnter spell number (0 is no spell) : ");
  OLC_MODE(d) = OEDIT_SPELLBOOK;
}


/*
 * Some applies require parameters (skills, feats)
 */
void oedit_disp_apply_spec_menu(struct descriptor_data *d)
{
  char *buf;

  switch (OLC_OBJ(d)->affected[OLC_VAL(d)].location) {
  case APPLY_FEAT:
    buf = "What feat should be modified : ";
    break;
  case APPLY_SKILL:
    buf = "What skill should be modified : ";
    break;
  default:
    oedit_disp_prompt_apply_menu(d);
    return;
  }

  write_to_output(d, "\r\n%s", buf);
  OLC_MODE(d) = OEDIT_APPLYSPEC;
}

/*
 * Ask for liquid type.
 */
void oedit_liquid_type(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < NUM_LIQ_TYPES; counter++) {
    write_to_output(d, " @g%2d@n) @y%-20.20s@n%s", counter,
	    drinks[counter], !(++columns % 2) ? "\r\n" : "");
  }
  write_to_output(d, "\r\n@nEnter drink type : ");
  OLC_MODE(d) = OEDIT_VALUE_3;
}

/*
 * The actual apply to set.
 */
void oedit_disp_apply_menu(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < NUM_APPLIES; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s %s", counter,
		apply_types[counter], !(++columns % 2) ? "\r\n" : "");
  }
  write_to_output(d, "\r\nEnter apply type (0 is no apply) : ");
  OLC_MODE(d) = OEDIT_APPLY;
}

/*
 * Weapon critical type.
 */
void oedit_disp_crittype_menu(struct descriptor_data *d)
{
  extern const char *crit_type[];
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter <= MAX_CRIT_TYPE; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s %s", counter,
		crit_type[counter], !(++columns % 2) ? "\r\n" : "");
  }
  write_to_output(d, "\r\nEnter critical type : ");
}

/*
 * Weapon type.
 */
void oedit_disp_weapon_menu(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < NUM_ATTACK_TYPES; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s %s", counter,
		attack_hit_text[counter].singular,
		!(++columns % 2) ? "\r\n" : "");
  }
  write_to_output(d, "\r\nEnter weapon type : ");
}

/*
 * Armor type.
 */
void oedit_disp_armor_menu(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter <= MAX_ARMOR_TYPES; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s %s", counter,
		armor_type[counter],
		!(++columns % 2) ? "\r\n" : "");
  }
  write_to_output(d, "\r\nEnter armor proficiency type : ");
}

/*
 * Spell type.
 */
void oedit_disp_spells_menu(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < SKILL_TABLE_SIZE; counter++) {
    if (IS_SET(skill_type(counter), SKTYPE_SPELL))
      write_to_output(d, "@g%2d@n) @y%-20.20s@n%s", counter,
		      spell_info[counter].name, !(++columns % 3) ? "\r\n" : "");
  }
  write_to_output(d, "\r\n@nEnter spell choice (-1 for none) : ");
}

/*
 * Material type.
 */
void oedit_disp_material_menu(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < NUM_MATERIALS; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s%s", counter,
                material_names[counter],
                !(++columns % 2) ? "\r\n" : "");
  }
  write_to_output(d, "\r\n@nEnter material type : ");
}

/*
 * Object value #1
 */
void oedit_disp_val1_menu(struct descriptor_data *d)
{
  int counter, columns = 0;
  OLC_MODE(d) = OEDIT_VALUE_1;
  switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
  case ITEM_LIGHT:
    /*
     * values 0 and 1 are unused.. jump to 2 
     */
    oedit_disp_val3_menu(d);
    break;
  case ITEM_SCROLL:
  case ITEM_WAND:
  case ITEM_STAFF:
  case ITEM_POTION:
    write_to_output(d, "Spell level : ");
    break;
  case ITEM_WEAPON:
    /*
     * This is now used to control the weapon type used by the weapon object
     */
    for (counter = 0; counter <= MAX_WEAPON_TYPES; counter++) {
      write_to_output(d, "@g%2d@n) %-20.20s %s", counter,
                weapon_type[counter], !(++columns % 2) ? "\r\n" : "");
    }
    write_to_output(d, "\r\nEnter the weapon type for determining proficiencies: \r\n");
    break;
  case ITEM_ARMOR:
    write_to_output(d, "Apply to AC : ");
    break;
  case ITEM_CONTAINER:
    write_to_output(d, "Max weight to contain : ");
    break;
  case ITEM_DRINKCON:
  case ITEM_FOUNTAIN:
    write_to_output(d, "Max drink units : ");
    break;
  case ITEM_FOOD:
    write_to_output(d, "Hours to fill stomach : ");
    break;
  case ITEM_MONEY:
    write_to_output(d, "Number of gold coins : ");
    break;
  case ITEM_NOTE:
    /*
     * This is supposed to be language, but it's unused.
     */
    break;
  case ITEM_VEHICLE:
    write_to_output(d, "Enter room vnum of vehicle interior : ");
    break;
  case ITEM_HATCH:
    write_to_output(d, "Enter vnum of the vehicle this hatch belongs to : ");
    break;
  case ITEM_WINDOW:
    write_to_output(d, "Enter vnum of the vehicle this window belongs to, or -1 to specify the viewport room : ");
    break;
  case ITEM_CONTROL:
    write_to_output(d, "Enter vnum of the vehicle these controls belong to : ");
    break;
  case ITEM_PORTAL:
    write_to_output(d, "Which room number is the destination? : ");
    break;
  case ITEM_BOARD:
    write_to_output(d, "Enter the minimum level to read this board: ");
    break;
  default:
    oedit_disp_val5_menu(d);
  }
}

/*
 * Object value #2
 */
void oedit_disp_val2_menu(struct descriptor_data *d)
{
  OLC_MODE(d) = OEDIT_VALUE_2;
  switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
  case ITEM_SCROLL:
  case ITEM_POTION:
    oedit_disp_spells_menu(d);
    break;
  case ITEM_WAND:
  case ITEM_STAFF:
    write_to_output(d, "Max number of charges : ");
    break;
  case ITEM_WEAPON:
    write_to_output(d, "Number of damage dice : ");
    break;
  case ITEM_ARMOR:
    oedit_disp_armor_menu(d);
    break;
  case ITEM_FOOD:
    /*
     * Values 2 and 3 are unused, jump to 4...Odd.
     */
    oedit_disp_val4_menu(d);
    break;
  case ITEM_CONTAINER:
  case ITEM_VEHICLE:
  case ITEM_HATCH:
  case ITEM_WINDOW:
  case ITEM_PORTAL:
    /*
     * These are flags, needs a bit of special handling.
     */
    oedit_disp_container_flags_menu(d);
    break;
  case ITEM_DRINKCON:
  case ITEM_FOUNTAIN:
    write_to_output(d, "Initial drink units : ");
    break;
  case ITEM_BOARD:
    write_to_output(d, "Minimum level to write: ");
    break;
  default:
    oedit_disp_val5_menu(d);
  }
}

/*
 * Object value #3
 */
void oedit_disp_val3_menu(struct descriptor_data *d)
{
  OLC_MODE(d) = OEDIT_VALUE_3;
  switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
  case ITEM_LIGHT:
    write_to_output(d, "Number of hours (0 = burnt, -1 is infinite) : ");
    break;
    break;
  case ITEM_WAND:
  case ITEM_STAFF:
    write_to_output(d, "Number of charges remaining : ");
    break;
  case ITEM_WEAPON:
    write_to_output(d, "Size of damage dice : ");
    break;
  case ITEM_ARMOR:
    write_to_output(d, "Max dex bonus : ");
    break;
  case ITEM_CONTAINER:
    write_to_output(d, "Vnum of key to open container (-1 for no key) : ");
    break;
  case ITEM_DRINKCON:
  case ITEM_FOUNTAIN:
    oedit_liquid_type(d);
    break;
  case ITEM_VEHICLE:
    write_to_output(d, "Vnum of key to unlock vehicle (-1 for no key) : ");
    break;
  case ITEM_HATCH:
    write_to_output(d, "Vnum of key to unlock hatch (-1 for no key) : ");
    break;
  case ITEM_WINDOW:
    write_to_output(d, "Vnum of key to unlock window (-1 for no key) : ");
    break;
  case ITEM_PORTAL:
    write_to_output(d, "Vnum of the key to unlock portal (-1 for no key) : ");
    break;
  case ITEM_BOARD:
    write_to_output(d, "Minimum level to remove messages: ");
    break;
  default:
    oedit_disp_val5_menu(d);
  }
}

/*
 * Object value #4
 */
void oedit_disp_val4_menu(struct descriptor_data *d)
{
  OLC_MODE(d) = OEDIT_VALUE_4;
  switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
  case ITEM_WAND:
  case ITEM_STAFF:
    oedit_disp_spells_menu(d);
    break;
  case ITEM_WEAPON:
    oedit_disp_weapon_menu(d);
    break;
  case ITEM_ARMOR:
    write_to_output(d, "Armor check penalty : ");
    break;
  case ITEM_DRINKCON:
  case ITEM_FOUNTAIN:
  case ITEM_FOOD:
    write_to_output(d, "Poisoned (0 = not poison) : ");
    break;
  case ITEM_VEHICLE:
    write_to_output(d, "What is the vehicle's appearance? (-1 for transparent) : ");
    break;
  case ITEM_PORTAL:
    write_to_output(d, "What is the portal's appearance? (-1 for transparent) : ");
    break;
  case ITEM_WINDOW:
    if (GET_OBJ_VAL(OLC_OBJ(d), 0) < 0)
      write_to_output(d, "What is the viewport room vnum (-1 for default location) : ");
    else
      oedit_disp_menu(d);
    break;
  default:
    oedit_disp_val5_menu(d);
  }
}

/*
 * Object value #5
 */
void oedit_disp_val5_menu(struct descriptor_data *d)
{
  OLC_MODE(d) = OEDIT_VALUE_5;
  write_to_output(d, "Enter object default quality percentage (100%% MAX): ");
}

/*
 * Object value #7
 */
void oedit_disp_val7_menu(struct descriptor_data *d)
{
  OLC_MODE(d) = OEDIT_VALUE_7;

  switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
  case ITEM_WEAPON:
    oedit_disp_crittype_menu(d);
    break;
  case ITEM_ARMOR:
    write_to_output(d, "Arcane spell failure %% : ");
    break;
  default:
    oedit_disp_val9_menu(d);
    break;
  }
}

/*
 * Object value #9
 */
void oedit_disp_val9_menu(struct descriptor_data *d)
{
  OLC_MODE(d) = OEDIT_VALUE_9;

  switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
  case ITEM_WEAPON:
    write_to_output(d, "Default crit is only on natural 20. Extend this range by: ");
    break;
  default:
    oedit_disp_menu(d);
    break;
  }
}

/*
 * Object type.
 */
void oedit_disp_type_menu(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < NUM_ITEM_TYPES; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s %s", counter,
		item_types[counter], !(++columns % 2) ? "\r\n" : "");
  }
  write_to_output(d, "\r\nEnter object type : ");
}

/*
 * Object extra flags.
 */
void oedit_disp_extra_menu(struct descriptor_data *d)
{
  char bits[MAX_STRING_LENGTH];
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < NUM_ITEM_FLAGS; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s %s", counter + 1,
		extra_bits[counter], !(++columns % 2) ? "\r\n" : "");
  }
  sprintbitarray(GET_OBJ_EXTRA(OLC_OBJ(d)), extra_bits, EF_ARRAY_MAX, bits);
  write_to_output(d, "\r\nObject flags: @c%s@n\r\n"
	  "Enter object extra flag (0 to quit) : ",
	  bits);
}

/*
 * Object perm flags.
 */
void oedit_disp_perm_menu(struct descriptor_data *d)
{
  char bitbuf[MAX_STRING_LENGTH];
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 1; counter < NUM_AFF_FLAGS; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s%s", counter, 
		affected_bits[counter], !(++columns % 2) ? "\r\n" : "");
  }
  sprintbitarray(GET_OBJ_PERM(OLC_OBJ(d)), affected_bits, EF_ARRAY_MAX, bitbuf);
  write_to_output(d, "\r\nObject permanent flags: @c%s@n\r\n"
          "Enter object perm flag (0 to quit) : ", bitbuf);
}

/*
 * Object size
 */
void oedit_disp_size_menu(struct descriptor_data *d)
{
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < NUM_SIZES; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s%s", counter + 1, 
		size_names[counter], !(++columns % 2) ? "\r\n" : "");
  }
  write_to_output(d, "\r\nEnter object size : ");
}

/*
 * Object wear flags.
 */
void oedit_disp_wear_menu(struct descriptor_data *d)
{
  char bits[MAX_STRING_LENGTH];
  int counter, columns = 0;

  clear_screen(d);

  for (counter = 0; counter < NUM_ITEM_WEARS; counter++) {
    write_to_output(d, "@g%2d@n) %-20.20s %s", counter + 1,
		wear_bits[counter], !(++columns % 2) ? "\r\n" : "");
  }
  sprintbitarray(GET_OBJ_WEAR(OLC_OBJ(d)), wear_bits, TW_ARRAY_MAX, bits);
  write_to_output(d, "\r\nWear flags: @c%s@n\r\n"
	  "Enter wear flag, 0 to quit : ", bits);
}

/*
 * Display main menu.
 */
void oedit_disp_menu(struct descriptor_data *d)
{
  char tbitbuf[MAX_INPUT_LENGTH], ebitbuf[MAX_INPUT_LENGTH];
  struct obj_data *obj;

  obj = OLC_OBJ(d);
  clear_screen(d);

  /*
   * Build buffers for first part of menu.
   */
  sprinttype(GET_OBJ_TYPE(obj), item_types, tbitbuf, sizeof(tbitbuf));
  sprintbitarray(GET_OBJ_EXTRA(obj), extra_bits, EF_ARRAY_MAX, ebitbuf);

  /*
   * Build first half of menu.
   */
  write_to_output(d,
	  "-- Item number : [@c%d@n]\r\n"
	  "@g1@n) Namelist : @y%s@n\r\n"
	  "@g2@n) S-Desc   : @y%s@n\r\n"
	  "@g3@n) L-Desc   :-\r\n@y%s@n\r\n"
	  "@g4@n) A-Desc   :-\r\n@y%s@n"
	  "@g5@n) Type        : @c%s@n\r\n"
	  "@g6@n) Extra flags : @c%s@n\r\n",

	  OLC_NUM(d),
	  (obj->name && *obj->name) ? obj->name : "undefined",
	  (obj->short_description && *obj->short_description) ? obj->short_description : "undefined",
	  (obj->description && *obj->description) ? obj->description : "undefined",
	  (obj->action_description && *obj->action_description) ? obj->action_description : "<not set>\r\n",
	  tbitbuf,
	  ebitbuf
	  );
  /*
   * Send first half.
   */

  /*
   * Build second half of menu.
   */
  sprintbitarray(GET_OBJ_WEAR(OLC_OBJ(d)), wear_bits, EF_ARRAY_MAX, tbitbuf);
  sprintbitarray(GET_OBJ_PERM(OLC_OBJ(d)), affected_bits, EF_ARRAY_MAX, ebitbuf);

  write_to_output(d,
	  "@g7@n) Wear flags  : @c%s@n\r\n"
	  "@g8@n) Weight      : @c%d@n\r\n"
	  "@g9@n) Cost        : @c%d@n\r\n"
	  "@gA@n) Cost/Day    : @c%d@n\r\n"
	  "@gB@n) Timer       : @c%d@n\r\n"
	  "@gC@n) Values      : @c%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d@n\r\n"
	  "@gD@n) Applies menu@n\r\n"
	  "@gE@n) Extra descriptions menu@n\r\n"
          "@gM@n) Min Level   : @c%d@n\r\n"
          "@gN@n) Material    : @c%s@n\r\n"
          "@gP@n) Perm Affects: @c%s@n\r\n"
          "@gS@n) Script      : @c%s@n\r\n"
          "@gT@n) Spellbook menu\r\n"
          "@gZ@n) Size        : @c%s@n\r\n"
	  "@gQ@n) Quit\r\n"
	  "Enter choice : ",

	  tbitbuf, GET_OBJ_WEIGHT(obj), GET_OBJ_COST(obj), GET_OBJ_RENT(obj),
	  GET_OBJ_TIMER(obj), GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 1),
          GET_OBJ_VAL(obj, 2), GET_OBJ_VAL(obj, 3), GET_OBJ_VAL(obj, 4),
          GET_OBJ_VAL(obj, 5), GET_OBJ_VAL(obj, 6), GET_OBJ_VAL(obj, 7),
          GET_OBJ_VAL(obj, 8), GET_OBJ_VAL(obj, 9), GET_OBJ_VAL(obj, 10),
          GET_OBJ_VAL(obj, 11), GET_OBJ_VAL(obj, 12), GET_OBJ_VAL(obj, 13),
          GET_OBJ_VAL(obj, 14), GET_OBJ_VAL(obj, 15),
          GET_OBJ_LEVEL(obj), material_names[(int)GET_OBJ_MATERIAL(obj)],
          ebitbuf, OLC_SCRIPT(d) ? "Set." : "Not Set.",
          size_names[GET_OBJ_SIZE(obj)]
  );
  OLC_MODE(d) = OEDIT_MAIN_MENU;
}

/***************************************************************************
 main loop (of sorts).. basically interpreter throws all input to here
 ***************************************************************************/

void oedit_parse(struct descriptor_data *d, char *arg)
{
  int number, max_val, min_val;
  char *oldtext = NULL;
  struct board_info *tmp;
  struct obj_data *obj;
  obj_rnum robj;

  switch (OLC_MODE(d)) {

  case OEDIT_CONFIRM_SAVESTRING:
    switch (*arg) {
    case 'y':
    case 'Y':
      oedit_save_internally(d);
      mudlog(CMP, MAX(ADMLVL_BUILDER, GET_INVIS_LEV(d->character)), TRUE,
	"OLC: %s edits obj %d", GET_NAME(d->character), OLC_NUM(d));
      if (CONFIG_OLC_SAVE) {
	oedit_save_to_disk(real_zone_by_thing(OLC_NUM(d)));
	write_to_output(d, "Object saved to disk.\r\n");
      } else
        write_to_output(d, "Object saved to memory.\r\n");
      if(GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_BOARD) {
	if((tmp=locate_board(GET_OBJ_VNUM(OLC_OBJ(d)))) != NULL) {
	  save_board(tmp);
	} else {
	  tmp = create_new_board(GET_OBJ_VNUM(OLC_OBJ(d)));
	  BOARD_NEXT(tmp) = bboards;
	  bboards = tmp;
	}
      }
      /* Fall through. */
    case 'n':
    case 'N':
      cleanup_olc(d, CLEANUP_ALL);
      return;
    case 'a': /* abort quit */
    case 'A':
      oedit_disp_menu(d);
      return;
    default:
      write_to_output(d, "Invalid choice!\r\n");
      write_to_output(d, "Do you wish to save this object?\r\n");
      return;
    }

  case OEDIT_MAIN_MENU:
    /*
     * Throw us out to whichever edit mode based on user input.
     */
    switch (*arg) {
    case 'q':
    case 'Q':
      if (STATE(d) != CON_IEDIT) {
      if (OLC_VAL(d)) {	/* Something has been modified. */
	write_to_output(d, "Do you wish to save this object? : ");
	OLC_MODE(d) = OEDIT_CONFIRM_SAVESTRING;
      } else
	cleanup_olc(d, CLEANUP_ALL);
      } else {
        send_to_char(d->character, "\r\nCommitting iedit changes.\r\n");
        obj = OLC_IOBJ(d);
        *obj = *(OLC_OBJ(d));
        GET_ID(obj) = max_obj_id++;
        /* find_obj helper */
        add_to_lookup_table(GET_ID(obj), (void *)obj);
        if (GET_OBJ_VNUM(obj) != NOTHING) {
          /* remove any old scripts */
          if (SCRIPT(obj)) {
            extract_script(obj, OBJ_TRIGGER);
            SCRIPT(obj) = NULL;
          }

          free_proto_script(obj, OBJ_TRIGGER);
          robj = real_object(GET_OBJ_VNUM(obj));
          copy_proto_script(&obj_proto[robj], obj, OBJ_TRIGGER);
          assign_triggers(obj, OBJ_TRIGGER);
        }
        SET_BIT_AR(GET_OBJ_EXTRA(obj), ITEM_UNIQUE_SAVE);
  /* Xap - ought to save the old pointer, free after assignment I suppose */
        mudlog(CMP, MAX(ADMLVL_BUILDER, GET_INVIS_LEV(d->character)), TRUE,
               "OLC: %s iedit a unique #%d", GET_NAME(d->character), GET_OBJ_VNUM(obj));
        if (d->character) {
          REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_WRITING);
          STATE(d) = CON_PLAYING;
          act("$n stops using OLC.", TRUE, d->character, 0, 0, TO_ROOM);
        }
        free(d->olc);
        d->olc = NULL;
      }
      return;
    case '1':
      write_to_output(d, "Enter namelist : ");
      OLC_MODE(d) = OEDIT_EDIT_NAMELIST;
      break;
    case '2':
      write_to_output(d, "Enter short desc : ");
      OLC_MODE(d) = OEDIT_SHORTDESC;
      break;
    case '3':
      write_to_output(d, "Enter long desc :-\r\n| ");
      OLC_MODE(d) = OEDIT_LONGDESC;
      break;
    case '4':
      OLC_MODE(d) = OEDIT_ACTDESC;
      send_editor_help(d);
      write_to_output(d, "Enter action description:\r\n\r\n");
      if (OLC_OBJ(d)->action_description) {
	write_to_output(d, "%s", OLC_OBJ(d)->action_description);
	oldtext = strdup(OLC_OBJ(d)->action_description);
      }
      string_write(d, &OLC_OBJ(d)->action_description, MAX_MESSAGE_LENGTH, 0, oldtext);
      OLC_VAL(d) = 1;
      break;
    case '5':
      oedit_disp_type_menu(d);
      OLC_MODE(d) = OEDIT_TYPE;
      break;
    case '6':
      oedit_disp_extra_menu(d);
      OLC_MODE(d) = OEDIT_EXTRAS;
      break;
    case '7':
      oedit_disp_wear_menu(d);
      OLC_MODE(d) = OEDIT_WEAR;
      break;
    case '8':
      write_to_output(d, "Enter weight : ");
      OLC_MODE(d) = OEDIT_WEIGHT;
      break;
    case '9':
      write_to_output(d, "Enter cost : ");
      OLC_MODE(d) = OEDIT_COST;
      break;
    case 'a':
    case 'A':
      write_to_output(d, "Enter cost per day : ");
      OLC_MODE(d) = OEDIT_COSTPERDAY;
      break;
    case 'b':
    case 'B':
      write_to_output(d, "Enter timer : ");
      OLC_MODE(d) = OEDIT_TIMER;
      break;
    case 'c':
    case 'C':
      /*
       * Clear any old values  
       */
      GET_OBJ_VAL(OLC_OBJ(d), 0) = 0;
      GET_OBJ_VAL(OLC_OBJ(d), 1) = 0;
      GET_OBJ_VAL(OLC_OBJ(d), 2) = 0;
      GET_OBJ_VAL(OLC_OBJ(d), 3) = 0;
      GET_OBJ_VAL(OLC_OBJ(d), 4) = 0;
      GET_OBJ_VAL(OLC_OBJ(d), 5) = 0;
      GET_OBJ_VAL(OLC_OBJ(d), 6) = 0;
      OLC_VAL(d) = 1;
      oedit_disp_val1_menu(d);
      break;
    case 'd':
    case 'D':
      oedit_disp_prompt_apply_menu(d);
      break;
    case 'e':
    case 'E':
      /*
       * If extra descriptions don't exist.
       */
      if (OLC_OBJ(d)->ex_description == NULL) {
	CREATE(OLC_OBJ(d)->ex_description, struct extra_descr_data, 1);
	OLC_OBJ(d)->ex_description->next = NULL;
      }
      OLC_DESC(d) = OLC_OBJ(d)->ex_description;
      oedit_disp_extradesc_menu(d);
      break;
    case 'm':
    case 'M':
      write_to_output(d, "Enter new minimum level: ");
      OLC_MODE(d) = OEDIT_LEVEL;
      break;
    case 'n':
    case 'N':
      OLC_MODE(d) = OEDIT_MATERIAL;
      oedit_disp_material_menu(d);
      break;
    case 'p':
    case 'P':
      oedit_disp_perm_menu(d);
      OLC_MODE(d) = OEDIT_PERM;
      break;
    case 's':
    case 'S':
      if (STATE(d) != CON_IEDIT) {
      OLC_SCRIPT_EDIT_MODE(d) = SCRIPT_MAIN_MENU;
      dg_script_menu(d);
      } else {
        write_to_output(d, "\r\nScripts cannot be modified on individual objects.\r\nEnter choice : ");
      }
      return;
    case 't':
    case 'T':
      oedit_disp_prompt_spellbook_menu(d);
      break;
    case 'z':
    case 'Z':
      oedit_disp_size_menu(d);
      OLC_MODE(d) = OEDIT_SIZE;
      break;
    default:
      oedit_disp_menu(d);
      break;
    }
    return;			/*
				 * end of OEDIT_MAIN_MENU 
				 */

  case OLC_SCRIPT_EDIT:
    if (dg_script_edit_parse(d, arg)) return;
    break;

  case OEDIT_EDIT_NAMELIST:
    if (!genolc_checkstring(d, arg))
      break;
    if (OLC_OBJ(d)->name)
      free(OLC_OBJ(d)->name);
    OLC_OBJ(d)->name = str_udup(arg);
    break;

  case OEDIT_SHORTDESC:
    if (!genolc_checkstring(d, arg))
      break;
    if (OLC_OBJ(d)->short_description)
      free(OLC_OBJ(d)->short_description);
    OLC_OBJ(d)->short_description = str_udup(arg);
    break;

  case OEDIT_LONGDESC:
    if (!genolc_checkstring(d, arg))
      break;
    if (OLC_OBJ(d)->description)
      free(OLC_OBJ(d)->description);
    OLC_OBJ(d)->description = str_udup(arg);
    break;

  case OEDIT_TYPE:
    number = atoi(arg);
    if ((number < 1) || (number >= NUM_ITEM_TYPES)) {
      write_to_output(d, "Invalid choice, try again : ");
      return;
    } else
      GET_OBJ_TYPE(OLC_OBJ(d)) = number;
    /* what's the boundschecking worth if we don't do this ? -- Welcor */
    GET_OBJ_VAL(OLC_OBJ(d), 0) = GET_OBJ_VAL(OLC_OBJ(d), 1) =
      GET_OBJ_VAL(OLC_OBJ(d), 2) = GET_OBJ_VAL(OLC_OBJ(d), 3) = 0;
    break;

  case OEDIT_EXTRAS:
    number = atoi(arg);
    if ((number < 0) || (number > NUM_ITEM_FLAGS)) {
      oedit_disp_extra_menu(d);
      return;
    } else if (number == 0)
      break;
    else {
      TOGGLE_BIT_AR(GET_OBJ_EXTRA(OLC_OBJ(d)), number);
      oedit_disp_extra_menu(d);
      return;
    }

  case OEDIT_WEAR:
    number = atoi(arg);
    if ((number < 0) || (number > NUM_ITEM_WEARS)) {
      write_to_output(d, "That's not a valid choice!\r\n");
      oedit_disp_wear_menu(d);
      return;
    } else if (number == 0)	/* Quit. */
      break;
    else {
      TOGGLE_BIT_AR(GET_OBJ_WEAR(OLC_OBJ(d)), (number - 1));
      oedit_disp_wear_menu(d);
      return;
    }

  case OEDIT_WEIGHT:
    GET_OBJ_WEIGHT(OLC_OBJ(d)) = LIMIT(atoi(arg), 0, MAX_OBJ_WEIGHT);
    break;

  case OEDIT_COST:
    GET_OBJ_COST(OLC_OBJ(d)) = LIMIT(atoi(arg), 0, MAX_OBJ_COST);
    break;

  case OEDIT_COSTPERDAY:
    GET_OBJ_RENT(OLC_OBJ(d)) = LIMIT(atoi(arg), 0, MAX_OBJ_RENT);
    break;

  case OEDIT_TIMER:
    switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
      case ITEM_PORTAL:
        GET_OBJ_TIMER(OLC_OBJ(d)) = LIMIT(atoi(arg), -1, MAX_OBJ_TIMER);
        break;
      default:
        GET_OBJ_TIMER(OLC_OBJ(d)) = LIMIT(atoi(arg), 0, MAX_OBJ_TIMER);
        break;
    }
    break;


  case OEDIT_LEVEL:
    GET_OBJ_LEVEL(OLC_OBJ(d)) = MAX(atoi(arg), 0);
    break;

  case OEDIT_MATERIAL:
    GET_OBJ_MATERIAL(OLC_OBJ(d)) = LIMIT(atoi(arg), 0, NUM_MATERIALS);
    break;

  case OEDIT_PERM:
    if ((number = atoi(arg)) == 0)
      break;
    if (number > 0 && number <= NUM_AFF_FLAGS)
      TOGGLE_BIT_AR(GET_OBJ_PERM(OLC_OBJ(d)), number - 1);
    oedit_disp_perm_menu(d);
    return;

  case OEDIT_SIZE:
    number = atoi(arg) - 1;
    GET_OBJ_SIZE(OLC_OBJ(d)) = LIMIT(number, 0, NUM_SIZES - 1);
    break;

  case OEDIT_VALUE_1:
    /*
     * Lucky, I don't need to check any of these for out of range values.
     * Hmm, I'm not so sure - Rv  
     */
    switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
      case ITEM_WEAPON:
        GET_OBJ_VAL(OLC_OBJ(d), 0) = LIMIT(atoi(arg), WEAPON_TYPE_UNARMED, MAX_WEAPON_TYPES); 
        break;
      case ITEM_CONTAINER:
        GET_OBJ_VAL(OLC_OBJ(d), 0) = LIMIT(atoi(arg), 0, MAX_CONTAINER_SIZE); 
        break;
      default:
    GET_OBJ_VAL(OLC_OBJ(d), 0) = atoi(arg);
    }
    /*
     * proceed to menu 2 
     */
    oedit_disp_val2_menu(d);
    return;
  case OEDIT_VALUE_2:
    /*
     * Here, I do need to check for out of range values.
     */
    number = atoi(arg);
    switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
    case ITEM_SCROLL:
    case ITEM_POTION:
      if (number == 0 || number == -1)
	GET_OBJ_VAL(OLC_OBJ(d), 1) = -1;
      else
        GET_OBJ_VAL(OLC_OBJ(d), 1) = LIMIT(number, 1, SKILL_TABLE_SIZE);
	oedit_disp_val3_menu(d);
      break;
    case ITEM_CONTAINER:
    case ITEM_VEHICLE:
    case ITEM_HATCH:
    case ITEM_WINDOW:
    case ITEM_PORTAL:
      /*
       * Needs some special handling since we are dealing with flag values
       * here.
       */
      if (number < 0 || number > 4)
	oedit_disp_container_flags_menu(d);
      else if (number != 0) {
        TOGGLE_BIT(GET_OBJ_VAL(OLC_OBJ(d), 1), 1 << (number - 1));
        OLC_VAL(d) = 1;
	oedit_disp_val2_menu(d);
      } else
	oedit_disp_val3_menu(d);
      break;
    case ITEM_WEAPON:
      GET_OBJ_VAL(OLC_OBJ(d), 1) = LIMIT(number, 1, MAX_WEAPON_NDICE); 
      oedit_disp_val3_menu(d);
      break;

    default:
      GET_OBJ_VAL(OLC_OBJ(d), 1) = number;
      oedit_disp_val3_menu(d);
    }
    return;

  case OEDIT_VALUE_3:
    number = atoi(arg);
    /*
     * Quick'n'easy error checking.
     */
    switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
    case ITEM_WEAPON:
      min_val = 1;
      max_val = MAX_WEAPON_SDICE;
      break;
    case ITEM_ARMOR:
      min_val = 0;
      max_val = 100;
    case ITEM_WAND:
    case ITEM_STAFF:
      min_val = 0;
      max_val = 20;
      break;
    case ITEM_DRINKCON:
    case ITEM_FOUNTAIN:
      min_val = 0;
      max_val = NUM_LIQ_TYPES - 1;
      break;
    case ITEM_KEY:
      min_val = 0;
      max_val = 32099;
      break;
    default:
      min_val = -32000;
      max_val = 32000;
    }
    GET_OBJ_VAL(OLC_OBJ(d), 2) = LIMIT(number, min_val, max_val);
    oedit_disp_val4_menu(d);
    return;

  case OEDIT_VALUE_4:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
    case ITEM_WAND:
    case ITEM_STAFF:
      min_val = 1;
      max_val = SKILL_TABLE_SIZE - 1;
      break;
    case ITEM_WEAPON:
      min_val = 0;
      max_val = NUM_ATTACK_TYPES - 1;
      break;
    case ITEM_ARMOR:
      if (number < 0) /* We're storing armor checks as positive numbers */
        number = 0 - number;
      min_val = 0;
      max_val = 20;
      break;
    default:
      min_val = -32000;
      max_val = 32000;
      break;
    }
    GET_OBJ_VAL(OLC_OBJ(d), 3) = LIMIT(number, min_val, max_val);
    oedit_disp_val5_menu(d);
    return;

  case OEDIT_VALUE_5:
    min_val = 1;
    max_val = 100;
    GET_OBJ_VAL(OLC_OBJ(d), 4) = LIMIT(atoi(arg), min_val, max_val);
    GET_OBJ_VAL(OLC_OBJ(d), 5) = LIMIT(atoi(arg), min_val, max_val);
    oedit_disp_val7_menu(d);
    return;

  case OEDIT_VALUE_7:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
    case ITEM_WEAPON:
      min_val = 0;
      max_val = MAX_CRIT_TYPE;
      break;
    case ITEM_ARMOR:
      min_val = -100; /* Want to allow weird armor that improves casting */
      max_val = 100;
      break;
    default:
      min_val = -32000;
      max_val = 32000;
      break;
    }
    GET_OBJ_VAL(OLC_OBJ(d), 6) = LIMIT(atoi(arg), min_val, max_val);
    oedit_disp_val9_menu(d);
    return;

  case OEDIT_VALUE_9:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
    case ITEM_WEAPON:
      min_val = 0;
      max_val = 19;
      break;
    default:
      min_val = -32000;
      max_val = 32000;
      break;
    }
    GET_OBJ_VAL(OLC_OBJ(d), 8) = LIMIT(atoi(arg), min_val, max_val);
  break;

  case OEDIT_PROMPT_APPLY:
    if ((number = atoi(arg)) == 0)
      break;
    else if (number < 0 || number > MAX_OBJ_AFFECT) {
      oedit_disp_prompt_apply_menu(d);
      return;
    }
    OLC_VAL(d) = number - 1;
    OLC_MODE(d) = OEDIT_APPLY;
    oedit_disp_apply_menu(d);
    return;

  case OEDIT_APPLY:
    if ((number = atoi(arg)) == 0) {
      OLC_OBJ(d)->affected[OLC_VAL(d)].location = 0;
      OLC_OBJ(d)->affected[OLC_VAL(d)].modifier = 0;
      oedit_disp_prompt_apply_menu(d);
    } else if (number < 0 || number >= NUM_APPLIES)
      oedit_disp_apply_menu(d);
    else {
      int counter;

      /* add in check here if already applied.. deny builders another */
      if (GET_ADMLEVEL(d->character) < ADMLVL_GRGOD) {
        for (counter = 0; counter < MAX_OBJ_AFFECT; counter++) {
          if (OLC_OBJ(d)->affected[counter].location == number) {
            write_to_output(d, "Object already has that apply.");
            return;
          }
        }
      }

      OLC_OBJ(d)->affected[OLC_VAL(d)].location = number;
      write_to_output(d, "Modifier : ");
      OLC_MODE(d) = OEDIT_APPLYMOD;
    }
    return;

  case OEDIT_APPLYMOD:
    OLC_OBJ(d)->affected[OLC_VAL(d)].modifier = atoi(arg);
    oedit_disp_apply_spec_menu(d);
    return;

  case OEDIT_APPLYSPEC:
    if (isdigit(*arg))
      OLC_OBJ(d)->affected[OLC_VAL(d)].specific = atoi(arg);
    else switch (OLC_OBJ(d)->affected[OLC_VAL(d)].location) {
      case APPLY_SKILL:
        number = find_skill_num(arg);
        if (number > -1)
          OLC_OBJ(d)->affected[OLC_VAL(d)].specific = number;
        break;
      case APPLY_FEAT:
        number = find_feat_num(arg);
        if (number > -1)
          OLC_OBJ(d)->affected[OLC_VAL(d)].specific = number;
        break;
      default:
          OLC_OBJ(d)->affected[OLC_VAL(d)].specific = 0;
        break;
      }
    oedit_disp_prompt_apply_menu(d);
    return;

  case OEDIT_EXTRADESC_KEY:
    if (genolc_checkstring(d, arg)) {
      if (OLC_DESC(d)->keyword)
        free(OLC_DESC(d)->keyword);
      OLC_DESC(d)->keyword = str_udup(arg);
    }
    oedit_disp_extradesc_menu(d);
    return;

  case OEDIT_EXTRADESC_MENU:
    switch ((number = atoi(arg))) {
    case 0:
      if (!OLC_DESC(d)->keyword || !OLC_DESC(d)->description) {
        struct extra_descr_data *temp;

	if (OLC_DESC(d)->keyword)
	  free(OLC_DESC(d)->keyword);
	if (OLC_DESC(d)->description)
	  free(OLC_DESC(d)->description);

	/*
	 * Clean up pointers  
	 */
	REMOVE_FROM_LIST(OLC_DESC(d), OLC_OBJ(d)->ex_description, next);
	free(OLC_DESC(d));
	OLC_DESC(d) = NULL;
      }
    break;

    case 1:
      OLC_MODE(d) = OEDIT_EXTRADESC_KEY;
      write_to_output(d, "Enter keywords, separated by spaces :-\r\n| ");
      return;

    case 2:
      OLC_MODE(d) = OEDIT_EXTRADESC_DESCRIPTION;
      send_editor_help(d);
      write_to_output(d, "Enter the extra description:\r\n\r\n");
      if (OLC_DESC(d)->description) {
	write_to_output(d, "%s", OLC_DESC(d)->description);
	oldtext = strdup(OLC_DESC(d)->description);
      }
      string_write(d, &OLC_DESC(d)->description, MAX_MESSAGE_LENGTH, 0, oldtext);
      OLC_VAL(d) = 1;
      return;

    case 3:
      /*
       * Only go to the next description if this one is finished.
       */
      if (OLC_DESC(d)->keyword && OLC_DESC(d)->description) {
	struct extra_descr_data *new_extra;

	if (OLC_DESC(d)->next)
	  OLC_DESC(d) = OLC_DESC(d)->next;
	else {	/* Make new extra description and attach at end. */
	  CREATE(new_extra, struct extra_descr_data, 1);
	  OLC_DESC(d)->next = new_extra;
	  OLC_DESC(d) = OLC_DESC(d)->next;
	}
      }
      /*
       * No break - drop into default case.
       */
    default:
      oedit_disp_extradesc_menu(d);
      return;
    }
    break;

  case OEDIT_PROMPT_SPELLBOOK:
    if ((number = atoi(arg)) == 0)
      break;
    else if (number < 0 || number > SKILL_TABLE_SIZE) {
      oedit_disp_prompt_spellbook_menu(d);
      return;
    }
    OLC_VAL(d) = number - 1;
    OLC_MODE(d) = OEDIT_SPELLBOOK;
    oedit_disp_spellbook_menu(d);
    return;

  case OEDIT_SPELLBOOK:
    if ((number = atoi(arg)) == 0) {
      if (OLC_OBJ(d)->sbinfo) {
        OLC_OBJ(d)->sbinfo[OLC_VAL(d)].spellname = 0;
        OLC_OBJ(d)->sbinfo[OLC_VAL(d)].pages = 0;
      } else {
        CREATE(OLC_OBJ(d)->sbinfo, struct obj_spellbook_spell, SPELLBOOK_SIZE);
        OLC_OBJ(d)->sbinfo[OLC_VAL(d)].spellname = 0;
        OLC_OBJ(d)->sbinfo[OLC_VAL(d)].pages = 0;
      }
      oedit_disp_prompt_spellbook_menu(d);
    } else if (number < 0 || number >= SKILL_TABLE_SIZE)
      oedit_disp_spellbook_menu(d);
    else {
      int counter;

      /* add in check here if already applied.. deny builders another */
      if (GET_LEVEL(d->character) < ADMLVL_IMPL) {
        for (counter = 0; counter < SKILL_TABLE_SIZE; counter++) {
          if (OLC_OBJ(d)->sbinfo && OLC_OBJ(d)->sbinfo[counter].spellname == number) {
            write_to_output(d, "Object already has that spell.");
            return;
          }
        }
      }

      if (!OLC_OBJ(d)->sbinfo)
        CREATE(OLC_OBJ(d)->sbinfo, struct obj_spellbook_spell, SPELLBOOK_SIZE);

      OLC_OBJ(d)->sbinfo[OLC_VAL(d)].spellname = number;
      OLC_OBJ(d)->sbinfo[OLC_VAL(d)].pages = MAX(1, spell_info[number].spell_level * 2);
      oedit_disp_prompt_spellbook_menu(d);
    }
    return;

  default:
    mudlog(BRF, ADMLVL_BUILDER, TRUE, "SYSERR: OLC: Reached default case in oedit_parse()!");
    write_to_output(d, "Oops...\r\n");
    break;
  }

  /*
   * If we get here, we have changed something.  
   */
  OLC_VAL(d) = 1;
  oedit_disp_menu(d);
}

void oedit_string_cleanup(struct descriptor_data *d, int terminator)
{
  switch (OLC_MODE(d)) {
  case OEDIT_ACTDESC:
    oedit_disp_menu(d);
    break;
  case OEDIT_EXTRADESC_DESCRIPTION:
    oedit_disp_extradesc_menu(d);
    break;
  }
}

/* this is all iedit stuff */
void iedit_setup_existing(struct descriptor_data *d, struct obj_data *real_num)
{
  struct obj_data *obj;

  OLC_IOBJ(d) = real_num;

  obj = create_obj();
  copy_object(obj,real_num);

  /* free any assigned scripts */
  if (SCRIPT(obj))
    extract_script(obj, OBJ_TRIGGER);
  SCRIPT(obj) = NULL;
  /* find_obj helper */
  remove_from_lookup_table(GET_ID(obj));

  OLC_OBJ(d) = obj;
  OLC_IOBJ(d) = real_num;
  OLC_VAL(d) = 0;
  oedit_disp_menu(d);
}

ACMD(do_iedit) {
  struct obj_data *k;
  int found=0;
  extern struct room_data *world;
  char arg[MAX_INPUT_LENGTH];

  one_argument(argument, arg);

  if(!*arg || !*argument) {
    send_to_char(ch, "You must supply an object name.\r\n");
  }

  if ((k = get_obj_in_equip_vis(ch, arg, NULL, ch->equipment))) {
    found=1;
  } else if ((k = get_obj_in_list_vis(ch, arg, NULL, ch->carrying))) {
    found=1;
  } else if ((k = get_obj_in_list_vis(ch, arg, NULL, world[ch->in_room].contents))) {
    found =1;
  } else if ((k = get_obj_vis(ch, arg, NULL))) {
    found=1;
  }

  if (!found) {
    send_to_char(ch, "Couldn't find that object. Sorry.\r\n");
    return;
  }

                /* set up here */
  CREATE(OLC(ch->desc), struct oasis_olc_data, 1);
  SET_BIT_AR(GET_OBJ_EXTRA(k), ITEM_UNIQUE_SAVE);

  SET_BIT_AR(PLR_FLAGS(ch), PLR_WRITING);
  iedit_setup_existing(ch->desc,k);
  OLC_VAL(ch->desc) = 0;

  act("$n starts using OLC.", TRUE, ch, 0, 0, TO_ROOM);

  STATE(ch->desc) = CON_IEDIT;

  return;
}