AwakeMUD-0.84B/.ssh/
AwakeMUD-0.84B/doc/
AwakeMUD-0.84B/lib/
AwakeMUD-0.84B/lib/etc/pfiles/
AwakeMUD-0.84B/lib/fixer_data/
AwakeMUD-0.84B/lib/misc/
AwakeMUD-0.84B/lib/text/
AwakeMUD-0.84B/lib/text/help/
AwakeMUD-0.84B/lib/text/wizhelp/
AwakeMUD-0.84B/lib/veh/
AwakeMUD-0.84B/lib/world/
AwakeMUD-0.84B/lib/world/mob/
AwakeMUD-0.84B/lib/world/mtx/
AwakeMUD-0.84B/lib/world/qst/
AwakeMUD-0.84B/lib/world/shp/
AwakeMUD-0.84B/lib/world/veh/
/* *******************************************
*                                            *
*                  iedit.cc                  *
*              Part of AwakeOLC,             *
*          a component of AwakeMUD           *
*                                            *
*       (c)2001 Andrew Hynek, and the        *
*             AwakeMUD Consortium            *
*                                            *
******************************************* */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "structs.h"
#include "awake.h"
#include "interpreter.h"
#include "comm.h"
#include "spells.h"
#include "utils.h"
#include "db.h"
#include "dblist.h"
#include "boards.h"
#include "screen.h"
#include "olc.h"
#include "memory.h"
#include "newmagic.h"
#include "constants.h"
#include "handler.h"

extern spell_a grimoire[];

#define OBJ     d->edit_obj


void write_objs_to_disk(int zone);


// extern funcs
extern char *cleanup(char *dest, const char *src);

#define NUM_SPELLS              49
#define NUM_WEAPON_TYPES        27
#define NUM_SKILL_TYPES         20
#define NUM_DRINK_TYPES         33
#define NUM_PATCHES             4
#define NUM_CYBERWARE_TYPES     35
#define NUM_BIOWARE_TYPES        11
#define NUM_SPIRITS       17
void iedit_disp_container_flags_menu(struct descriptor_data * d);
void iedit_disp_extradesc_menu(struct descriptor_data * d);
void iedit_disp_weapon_menu(struct descriptor_data * d);
void iedit_disp_val1_menu(struct descriptor_data * d);
void iedit_disp_val2_menu(struct descriptor_data * d);
void iedit_disp_val3_menu(struct descriptor_data * d);
void iedit_disp_val4_menu(struct descriptor_data * d);
void iedit_disp_val5_menu(struct descriptor_data * d);
void iedit_disp_val6_menu(struct descriptor_data * d);
void iedit_disp_val7_menu(struct descriptor_data * d);
void iedit_disp_val8_menu(struct descriptor_data * d);
void iedit_disp_val9_menu(struct descriptor_data * d);
void iedit_disp_val10_menu(struct descriptor_data * d);


void iedit_disp_type_menu(struct descriptor_data * d);
void iedit_disp_extra_menu(struct descriptor_data * d);
void iedit_disp_wear_menu(struct descriptor_data * d);
void iedit_disp_menu(struct descriptor_data * d);
void iedit_disp_drinktype_menu(struct descriptor_data *d);

void iedit_disp_patch_menu(struct descriptor_data *d);
void iedit_parse(struct descriptor_data * d, char *arg);
void iedit_disp_spells_menu(struct descriptor_data * d);
void iedit_disp_cybertype_menu(struct descriptor_data * d);
void iedit_program_types_menu(struct descriptor_data *d);
void iedit_disp_biotype_menu(struct descriptor_data * d);


/**************************************************************************
 Menu functions
 **************************************************************************/
/* For container flags */
void iedit_disp_container_flags_menu(struct descriptor_data * d)
{
  sprintbit(GET_OBJ_VAL(d->edit_obj, 1), container_bits, buf1);
  send_to_char(CH, "1) Closeable\r\n"
               "2) Pickproof\r\n"
               "3) Closed\r\n"
               "4) Locked\r\n"
               "Container flags: %s%s%s\r\n"
               "Enter flag, 0 to quit:", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
}

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

  send_to_char(CH, "Extra desc menu\r\n"
               "0) Quit\r\n"
               "1) Keyword: %s%s%s\r\n"
               "2) Description:\r\n%s\r\n"
               "3) %s%s%s\r\n",
               CCCYN(CH, C_CMP), (extra_desc->keyword ?  extra_desc->keyword : "(none)"),
               CCNRM(CH, C_CMP), (extra_desc->description ? extra_desc->description : "(none)"),
               CCCYN(CH, C_CMP), (!extra_desc->next ? "(not set)" : "Set (not viewed)."),
               CCNRM(CH, C_CMP));
  d->edit_mode = IEDIT_EXTRADESC_MENU;
}

/* Ask for *which* apply to edit */
void iedit_disp_prompt_apply_menu(struct descriptor_data * d)
{
  int             counter;

  CLS(CH);
  for (counter = 0; counter < MAX_OBJ_AFFECT; counter++)
  {
    if (d->edit_obj->affected[counter].modifier) {
      if (GET_OBJ_TYPE(d->edit_obj) == ITEM_MOD)
        sprinttype(d->edit_obj->affected[counter].location, veh_aff, buf2);
      else
        sprinttype(d->edit_obj->affected[counter].location, apply_types, buf2);
      send_to_char(CH, " %d) %+d to %s%s%s\r\n", counter + 1,
                   d->edit_obj->affected[counter].modifier, CCCYN(CH, C_CMP), buf2,
                   CCNRM(CH, C_CMP));
    } else
      send_to_char(CH, " %d) None.\r\n", counter + 1);
  }
  send_to_char("Enter affection to modify (0 to quit):", d->character);
  d->edit_mode = IEDIT_PROMPT_APPLY;
}

/* The actual apply to set */
void iedit_disp_apply_menu(struct descriptor_data * d)
{
  int             counter;
  if (GET_OBJ_TYPE(d->edit_obj) == ITEM_MOD)
  {
    for (counter = 0; counter < VAFF_MAX; counter += 2)
      send_to_char(CH, "%2d) %-18s    %2d) %-18s\r\n",
                   counter, veh_aff[counter],
                   counter + 1, counter + 1 < VAFF_MAX ?
                   veh_aff[counter + 1] : "");
  } else
  {
    for (counter = 0; counter < AFF_MAX; counter += 2)
      send_to_char(CH, "%2d) %-18s    %2d) %-18s\r\n",
                   counter, apply_types[counter],
                   counter + 1, counter + 1 < APPLY_MAX ?
                   apply_types[counter + 1] : "");
  }
  send_to_char("Enter apply type (0 is no apply):", d->character);
  d->edit_mode = IEDIT_APPLY;
}

/* skill needed in weapon */
void iedit_disp_skill_menu(struct descriptor_data *d)
{
  CLS(CH);
  send_to_char( " 1) Edged Weapons\r\n"
                " 2) Pole Arms\r\n"
                " 3) Whips and flails\r\n"
                " 4) Clubs\r\n"
                " 5) Pistols\r\n"
                " 6) Rifles\r\n"
                " 7) Shotguns\r\n"
                " 8) Assault Rifles\r\n"
                " 9) Submachine Guns\r\n"
                "10) Grenade Launchers\r\n"
                "11) Tasers\r\n"
                "12) Machine Guns\r\n"
                "13) Missile Launchers\r\n"
                "14) Assault Cannons\r\n"
                "15) Artillery\r\n"
                "16) Bows\r\n"
                "17) Crossbows\r\n"
                "18) Non-aerodynamic throwing weapons\r\n"
                "19) Aerodynamic throwing weapons\r\n"
                "20) Unarmed Combat\r\n"
                "Enter skill needed for weapon:\r\n", CH);
}

/* weapon type */
void iedit_disp_weapon_menu(struct descriptor_data * d)
{
  CLS(CH);
  send_to_char(" 1) sting              2) whip\r\n"
               " 3) slash              4) bite\r\n"
               " 5) bludgeon           6) crush\r\n"
               " 7) pound              8) claw\r\n"
               " 9) maul              10) thrash\r\n"
               "11) pierce            12) punch\r\n"
               "13) stab              14) taser\r\n"
               "15) shuriken          16) throwing knife\r\n"
               "17) arrow/bolt        18) hand grenade\r\n"
               "19) grenade launcher  20) rocket\r\n"
               "21) pistol            22) blast\r\n"
               "23) rifle             24) shotgun\r\n"
               "25) machine gun       26) cannon\r\n"
               "Enter weapon type:\r\n", CH);
}

/* spell type */
void iedit_disp_spells_menu(struct descriptor_data * d)
{
  int             counter;

  CLS(CH);
  for (counter = 1; counter <= NUM_SPELLS; counter += 3)
    send_to_char(CH, "%2d) %-18s %2d) %-18s %2d) %-18s\r\n",
                 counter, spells[counter],
                 counter + 1, counter + 1 <= NUM_SPELLS ? spells[counter + 1] : "",
                 counter + 2, counter + 2 <= NUM_SPELLS ? spells[counter + 2] : "");

  send_to_char("Enter spell:\r\n", CH);
}

/* object value 1 */
void iedit_disp_val1_menu(struct descriptor_data * d)
{
  d->edit_mode = IEDIT_VALUE_1;
  int c, line = 0;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_WORKSHOP:
    send_to_char(CH, "0) General\r\n1) Electronic\r\n2) Microtronic\r\n3) Cyberware\r\n4) Vehicle\r\n5) Weaponry\r\n6) Medical\r\nWorkshop Type: ");
    break;
  case ITEM_CAMERA:
    send_to_char("0) Camera\r\n1) Photo\r\nObject Type: ", CH);
    break;
  case ITEM_LIGHT:
    /* values 0 and 1 are unused.. jump to 2 */
    iedit_disp_val3_menu(d);
    break;
  case ITEM_WEAPON:
  case ITEM_FIREWEAPON:
    send_to_char("Power (0 for melee weapon or bow):", d->character);
    break;
  case ITEM_MISSILE:
    send_to_char("\r\n  0) Arrow     1) Bolt\r\nMissile type: ", CH);
    break;
  case ITEM_GYRO:
    send_to_char("RATING: ", d->character);
    break;
  case ITEM_QUIVER:
    send_to_char("Max projectiles to contain: ", CH);
    break;
  case ITEM_CONTAINER:
    send_to_char("Max weight to contain: ", d->character);
    break;
  case ITEM_DRINKCON:
  case ITEM_FOUNTAIN:
    send_to_char("Max drink units: ", d->character);
    break;
  case ITEM_FOOD:
    send_to_char("Hours to fill stomach: ", d->character);
    break;
  case ITEM_MONEY:
    send_to_char("Number of nuyen: ", d->character);
    break;
  case ITEM_CYBERWARE:
  case ITEM_BIOWARE:
    send_to_char("Rating: ", CH);
    break;
  case ITEM_CYBERDECK:
    send_to_char("MPCP Rating: ", CH);
    break;
  case ITEM_PROGRAM:
    iedit_program_types_menu(d);
    break;
  case ITEM_GUN_CLIP:
    send_to_char("Number of bullets clip contains (must match max load of weapon): ", CH);
    break;
  case ITEM_DOCWAGON:
    send_to_char("  1) Basic contract\r\n  2) Gold contract\r\n  3) Platinum contract\r\nDocWagon type: ", CH);
    break;
  case ITEM_WORKING_GEAR:
    CLS(CH);
    send_to_char("  1) Medical\r\n"
                 "  2) Electronic\r\n"
                 "  3) Cyberdeck\r\n"
                 "  4) Mechanical\r\n"
                 "Enter type of kit: ", CH);
    break;
  case ITEM_PATCH:
    iedit_disp_patch_menu(d);
    break;
  case ITEM_SPELL_FORMULA:
    iedit_disp_val3_menu(d);
    break;
  case ITEM_DECK_ACCESSORY:
    send_to_char("  0) Data file\r\n  1) Upgrade\r\n  2) Computer\r\n  3) Parts\r\n  4) Chip Cooker\r\n"
                 "Accessory type: ", CH);
    break;
  case ITEM_GUN_ACCESSORY:
    send_to_char("  0) Top\r\n  1) Barrel\r\n 2) Under\r\nLocation to mount accessory: ", CH);
    break;
  case ITEM_FOCUS:
    send_to_char("  0) Specific spell\r\n  1) Spell category\r\n  2) Spirit\r\n  3) Power\r\n"
                 "  4) Spell lock\r\n  5) Weapon\r\nFocus type: ", CH);
    break;
  case ITEM_CLIMBING:
    send_to_char("Enter rating (1-3): ", CH);
    break;
  case ITEM_RADIO:
    iedit_disp_val2_menu(d);
    break;
  case ITEM_MOD:
    send_to_char("  0) Suspension\r\n"
                 "  1) Engine\r\n"
                 "  2) Steering\r\n"
                 "  3) Tires\r\n"
                 "  4) Brakes\r\n"
                 "  5) Armor Plating\r\n"
                 "  6) Computer\r\n"
                 "  7) Phones\r\n"
                 "  8) Sensors\r\n"
                 "  9) ECM\r\n"
                 "  10) Ignition\r\n"
                 "  11) Alarm\r\n"
                 "  12) Seats\r\n"
                 "  13) Body Style\r\n"
                 "  14) Radio\r\n"
                 "  15) Mount\r\n"
                 "Enter type of Mod: ", CH);
    break;
  case ITEM_HOLSTER:
    send_to_char("Type (0 - Pistol/SMG, 1 - Sword, 2 - Rifle (or larger)): ", d->character);
    break;
  case ITEM_WORN:
    send_to_char("Holster/Sheath/Quiver Space: ", d->character);
    break;
  case ITEM_RCDECK:
    send_to_char("Rating: ", d->character);
    break;
  case ITEM_PHONE:
    send_to_char("Area Code (0 - Seattle, 1 - Tacoma, 2 - Portland)): ", d->character);
    break;
  case ITEM_CHIP:
    CLS(CH);
    for (c = 0; c < MAX_SKILLS; c++) {
      line++;
      if ((line % 3) == 1)
        sprintf(buf, "%2d) %-20s ", c, skills[c].name);
      else
        sprintf(buf, "%s%2d) %-20s ", buf, c, skills[c].name);
      if (!(line % 3)) {
        sprintf(buf, "%s\r\n", buf);
        send_to_char(buf, CH);
      }
    }
    if ((line % 3) != 0) {
      sprintf(buf, "%s\r\nEnter a skill (0 to quit): ", buf);
      send_to_char(buf, CH);
    }
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object value 2 */
void iedit_disp_val2_menu(struct descriptor_data * d)
{
  d->edit_mode = IEDIT_VALUE_2;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_CHIP:
    send_to_char(CH, "Enter skillsoft rating: ");
    break;
  case ITEM_WEAPON:
  case ITEM_FIREWEAPON:
    send_to_char("Base Damage (1 - Light, 2 - Moderate, 3 - Serious, 4 - Deadly): ", d->character);
    break;
  case ITEM_DRINKCON:
  case ITEM_FOUNTAIN:
    send_to_char("Drink units left: ", CH);
    break;
  case ITEM_FOOD:
    /* values 2 and 3 are unused, jump to 4. how odd */
    iedit_disp_val4_menu(d);
    break;
  case ITEM_CONTAINER:
    /* these are flags, needs a bit of special handling */
    iedit_disp_container_flags_menu(d);
    break;
  case ITEM_QUIVER:
    send_to_char("  0) Arrows\r\n  1) Bolts\r\n  2) Shurikens\r\n  3) Throwing knives\r\n"
                 "Quiver type: ", CH);
    break;
  case ITEM_CYBERWARE:
    send_to_char("Essence cost (x 100): ", CH);
    break;
  case ITEM_BIOWARE:
    send_to_char("Body index cost (x 100): ", CH);
    break;
  case ITEM_CYBERDECK:
    send_to_char("Hardening: ", CH);
    break;
  case ITEM_PROGRAM:
    send_to_char("Program Rating: ", CH);
    break;
  case ITEM_PATCH:
    send_to_char("Rating: ", CH);
    break;
  case ITEM_DECK_ACCESSORY:
    switch (GET_OBJ_VAL(OBJ, 0)) {
    case TYPE_FILE:
      send_to_char("File size: ", CH);
      break;
    case TYPE_UPGRADE:
      send_to_char("  0) MPCP (replacement)\r\n  1) Active memory\r\n"
                   "  2) Storage memory\r\n  3) Hitcher Jack\r\n  4) IO speed\r\n"
                   "  5) Reaction increase\r\nUpgrade type: ", CH);
      break;
    case TYPE_COMPUTER:
      send_to_char("Active Memory: ", CH);
      break;
    case TYPE_PARTS:
      send_to_char("  0) General Parts\r\n  1) Memory Chips\r\n", CH);
      break;
    case TYPE_COOKER:
      send_to_char("Enter rating: ", CH);
      break;
    }
    break;
  case ITEM_GUN_ACCESSORY:
    send_to_char("  1) Smartlink\r\n  2) Scope\r\n  3) Gas vent\r\n  4) Shock pad\r\n"
                 "  5) Silencer\r\n  6) Sound Suppressor\r\nAccessory type: ", CH);
    break;
  case  ITEM_FOCUS:
    if (GET_OBJ_VAL(OBJ, 0) != FOCI_LOCK)
      send_to_char("Focus rating: ", CH);
    else
      iedit_disp_menu(d);
    break;
  case ITEM_GUN_CLIP:
    send_to_char("  1) Pistol               2) Blast\r\n"
                 "  3) Rifle                4) Shotgun\r\n"
                 "  5) Machine gun          6) Cannon\r\n"
                 "  7) Grenade launcher     8) Rocket\r\nClip type: ", CH);
    break;
  case ITEM_RADIO:
    send_to_char("Enter radio's range (0-5): ", CH);
    break;
  case ITEM_MONEY:
    send_to_char("Type (1 - cash, 2 - credstick): ", d->character);
    break;
  case ITEM_MOD:
    if (GET_OBJ_VAL(d->edit_obj, 0) == MOD_MOUNT)
      send_to_char("  0) Firmpoint Internal Fixed Mount\r\n"
                   "  1) Firmpoint External Fixed Mount\r\n"
                   "  2) Hardpoint Internal Fixed Mount\r\n"
                   "  3) Hardpoint External Fixed Mount\r\n"
                   "  4) Turret\r\n"
                   "  5) Mini-Turret\r\n"
                   "Type of Mount: ", CH);
    else
      send_to_char("Load space taken up: ", d->character);
    break;
  case ITEM_WORN:
    send_to_char("Space for clips: ", CH);
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object value 3 */
void iedit_disp_val3_menu(struct descriptor_data * d)
{
  int i;

  d->edit_mode = IEDIT_VALUE_3;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_LIGHT:
    send_to_char("Number of hours (0 = burnt, -1 is infinite): ", d->character);
    break;
  case ITEM_WEAPON:
  case ITEM_FIREWEAPON:
    send_to_char("Strength bonus for melee (0 for non-melee weapons): ", CH);
    break;
  case ITEM_CONTAINER:
    send_to_char("Vnum of key to open container (-1 for no key): ", d->character);
    break;
  case ITEM_DRINKCON:
  case ITEM_FOUNTAIN:
    iedit_disp_drinktype_menu(d);
    break;
  case ITEM_CYBERWARE:
    iedit_disp_cybertype_menu(d);
    break;
  case ITEM_BIOWARE:
    iedit_disp_biotype_menu(d);
    break;
  case ITEM_GUN_CLIP:
    send_to_char("  0) Normal             1) APDS\r\n"
                 "  2) Explosive          3) EX\r\n"
                 "  4) Flechette          5) Gel\r\n"
                 "Select Type: ", CH);
    break;
  case ITEM_CYBERDECK:
    send_to_char("Active: ", CH);
    break;
  case ITEM_PROGRAM:
    send_to_char("Program size: ", CH);
    break;
  case ITEM_SPELL_FORMULA:
    send_to_char("Force: ", CH);
    break;
  case ITEM_DECK_ACCESSORY:
    switch (GET_OBJ_VAL(OBJ, 0)) {
    case TYPE_UPGRADE:
      switch (GET_OBJ_VAL(OBJ, 1)) {
      case 0:
        send_to_char("MPCP Rating: ", CH);
        break;
      case 1:
        send_to_char("Active memory increase: ", CH);
        break;
      case 2:
        send_to_char("Storage memory increase: ", CH);
        break;
      case 3:
        iedit_disp_menu(d);
        break;
      case 4:
        send_to_char("I/O speed increase: ", CH);
        break;
      case 5:
        send_to_char("Reaction increase level: ", CH);
        break;
      }
      break;
    case TYPE_COMPUTER:
      send_to_char("Storage Memory: ", CH);
      break;
    default:
      iedit_disp_menu(d);
      break;
    }
    break;
  case ITEM_GUN_ACCESSORY:
    if (GET_OBJ_VAL(OBJ, 1) == 1)
      send_to_char("Smartlink Rating: ", CH);
    else if (GET_OBJ_VAL(OBJ, 1) == 3)
      send_to_char("Recoil modifier: ", CH);
    else
      iedit_disp_menu(d);
    break;
  case ITEM_FOCUS:
    if (GET_OBJ_VAL(OBJ, 0) == FOCI_SPIRIT) {
      CLS(CH);
      for (i = 1; *spirits[i] != '\n'; i++)
        send_to_char(CH, "%2d) %20s", i, spirits[i]);
      send_to_char("Enter spirit type: ", CH);
    } else if (GET_OBJ_VAL(OBJ, 0) == FOCI_SPELL)
      iedit_disp_spells_menu(d);
    else if (GET_OBJ_VAL(OBJ, 0) == FOCI_SPELL_CAT) {
      CLS(CH);
      for (i = 0; *spell_categories[i] != '\n'; i++)
        send_to_char(CH, "%2d %s\r\n", i + 1, spell_categories[i]);
      send_to_char("Enter spell category: ", CH);
    } else
      iedit_disp_menu(d);
    break;
  case ITEM_RADIO:
    send_to_char("Enter encryption/decryption rating (1-6): ", CH);
    break;
  case ITEM_MONEY:
    if (GET_OBJ_VAL(OBJ, 1))
      send_to_char("  1) 6-digit code\r\n  2) thumbprint\r\n  3) retinal scan\r\n"
                   "Enter credstick security: ", d->character);
    else
      iedit_disp_menu(d);
    break;
  case ITEM_MOD:
    if (GET_OBJ_VAL(d->edit_obj, 0) == MOD_RADIO)
      send_to_char("Radio Range (0-5): ", CH);
    else
      iedit_disp_val5_menu(d);
    break;
  case ITEM_WORN:
    send_to_char("Space for grenades: ", CH);
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object value 4 */
void iedit_disp_val4_menu(struct descriptor_data * d)
{
  d->edit_mode = IEDIT_VALUE_4;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_WEAPON:
  case ITEM_FIREWEAPON:
    iedit_disp_weapon_menu(d);
    break;
  case ITEM_CONTAINER:
    send_to_char("Lock level on container: ", d->character);
    break;
  case ITEM_DRINKCON:
  case ITEM_FOUNTAIN:
  case ITEM_FOOD:
    send_to_char("Poison Rating (0 = not poison): ", d->character);
    break;
  case ITEM_CYBERWARE:
    iedit_disp_val5_menu(d);
    break;
  case ITEM_CYBERDECK:
    send_to_char("Storage: ", CH);
    break;
  case ITEM_SPELL_FORMULA:
    iedit_disp_spells_menu(d);
    d->edit_mode = IEDIT_VALUE_7;
    break;
  case ITEM_DECK_ACCESSORY:
    switch (GET_OBJ_VAL(OBJ, 0)) {
    case TYPE_FILE:
      iedit_disp_menu(d);
      break;
    case TYPE_UPGRADE:
      if (GET_OBJ_VAL(OBJ, 1) == 5)
        send_to_char("MPCP to enhance: ", CH);
      else
        iedit_disp_menu(d);
      break;
    case TYPE_COMPUTER:
      iedit_disp_menu(d);
      break;
    }
    break;
  case ITEM_PROGRAM:
    if (GET_OBJ_VAL(d->edit_obj, 0) == SOFT_ATTACK)
      send_to_char("Damage Rating (1-Light 2-Moderate 3-Serious 4-Deadly): ", CH);
    else
      iedit_disp_menu(d);
    break;
  case ITEM_WORN:
    send_to_char("Space for shuriken: ", CH);
    break;
  case ITEM_MOD:
    if (GET_OBJ_VAL(d->edit_obj, 0) == MOD_RADIO)
      send_to_char("Crypt Level (0-6): ", CH);
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object value 5 */
void iedit_disp_val5_menu(struct descriptor_data * d)
{
  d->edit_mode = IEDIT_VALUE_5;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_WEAPON:
  case ITEM_FIREWEAPON:
    iedit_disp_skill_menu(d);
    break;
  case ITEM_CYBERDECK:
    send_to_char("Load: ", CH);
    break;
  case ITEM_CYBERWARE:
    if (GET_OBJ_VAL(OBJ, 2) == 2 || GET_OBJ_VAL(OBJ, 2) == 3)
      send_to_char("Enter radio's range (0-5): ", CH);
    else
      iedit_disp_menu(d);
    break;
  case ITEM_WORN:
    send_to_char("Space for Misc small items: ", CH);
    break;
  case ITEM_MOD:
    send_to_char("Designed For (0 - Vehicle, 1 - Drone, 2 - Both): ", CH);
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object value 6 */
void iedit_disp_val6_menu(struct descriptor_data * d)
{
  d->edit_mode = IEDIT_VALUE_6;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_WEAPON:
    send_to_char("Max Ammo (-1 if doesn't use ammo): ", CH);
    break;
  case ITEM_FIREWEAPON:
    send_to_char("  0) Bow\r\n  1) Crossbow\r\nType: ", CH);
    break;
  case ITEM_CYBERWARE:
    send_to_char("Enter encryption/decryption rating (1-6): ", CH);
    break;
  case ITEM_WORN:
    send_to_char("Ballistic Rating: ", CH);
    break;
  case ITEM_CYBERDECK:
    iedit_disp_val7_menu(d);
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object value 7 */
void iedit_disp_val7_menu(struct descriptor_data * d)
{
  d->edit_mode = IEDIT_VALUE_7;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_WEAPON:
    send_to_char("Current Ammo: ", CH);
    break;
  case ITEM_FIREWEAPON:
    send_to_char("Enter strength minimum: ", CH);
    break;
  case ITEM_SPELL_FORMULA:
    iedit_disp_spells_menu(d);
    break;
  case ITEM_WORN:
    send_to_char("Impact Rating: ", CH);
    break;
  case ITEM_CYBERDECK:
    send_to_char("Response Increase: ", CH);
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object value 8 */
void iedit_disp_val8_menu(struct descriptor_data * d)
{
  d->edit_mode = IEDIT_VALUE_8;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_SPELL_FORMULA:
    send_to_char("0 for mage spell, 1 for shaman spell: ", CH);
    break;
  case ITEM_WEAPON:
    if (access_level(CH, LVL_ADMIN)) {
      if (GET_OBJ_VAL(OBJ, 7) >= -1)
        send_to_char("Enter vnum of object to attach on top: ", CH);
      else
        iedit_disp_val9_menu(d);
    } else
      iedit_disp_menu(d);
    break;
  case ITEM_WORN:
    send_to_char("Concealibility rating (+harder -easier): ", CH);
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object value 9 */
void iedit_disp_val9_menu(struct descriptor_data * d)
{
  d->edit_mode = IEDIT_VALUE_9;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_WEAPON:
    if (access_level(CH, LVL_ADMIN)) {
      if (GET_OBJ_VAL(OBJ, 8) >= -1)
        send_to_char("Enter vnum of object to attach on barrel: ", CH);
      else
        iedit_disp_val10_menu(d);
    } else
      iedit_disp_menu(d);
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object value 10 */
void iedit_disp_val10_menu(struct descriptor_data * d)
{
  d->edit_mode = IEDIT_VALUE_10;
  switch (GET_OBJ_TYPE(d->edit_obj))
  {
  case ITEM_WEAPON:
    if (access_level(CH, LVL_ADMIN) && GET_OBJ_VAL(OBJ, 9) >= -1)
      send_to_char("Enter vnum of object to attach under: ", CH);
    else
      iedit_disp_menu(d);
    break;
  default:
    iedit_disp_menu(d);
  }
}

/* object type */
void iedit_disp_type_menu(struct descriptor_data * d)
{
  int counter;

  CLS(CH);
  for (counter = 1; counter <= NUM_ITEM_TYPES; counter += 2)
  {
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
                 counter, item_types[counter],
                 counter + 1, counter + 1 <= NUM_ITEM_TYPES ?
                 item_types[counter + 1] : "");
  }
  send_to_char("Enter object type (0 to quit): ", d->character);
}

void iedit_disp_drinktype_menu(struct descriptor_data *d)
{
  int counter;

  CLS(CH);
  for (counter = 0; counter < NUM_DRINK_TYPES; ++counter)
    send_to_char(CH, "%2d) %s\r\n", counter + 1, drinks[counter]);
  send_to_char("Enter drink type: ", CH);
}

void iedit_disp_material_menu(struct descriptor_data *d)
{
  CLS(CH);

  for (register int counter = 0; counter < NUM_MATERIALS; ++counter)
    send_to_char(CH, "%2d) %s\r\n", counter + 1, material_names[counter]);
  send_to_char("Enter material type, 0 to return: ", CH);
}

void iedit_disp_patch_menu(struct descriptor_data *d)
{
  CLS(CH);

  for (register int counter = 0; counter < NUM_PATCHES; ++counter)
    send_to_char(CH, "%2d) %s\r\n", counter + 1, patch_names[counter]);
  send_to_char("Enter patch type, 0 to return: ", CH);
}

void iedit_disp_spell_type(struct descriptor_data *d)
{
  CLS(CH);
  for (register int counter = 0; counter <= NUM_SPELLS; counter += 2)
  {
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
                 counter + 1, spells[counter],
                 counter + 2, counter + 1 <= NUM_SPELLS ?
                 spells[counter + 1] : "");
  }
  send_to_char("Enter spell, 0 to return: ", CH);
}

void iedit_disp_cybertype_menu(struct descriptor_data *d)
{
  CLS(CH);
  for (register int counter = 0; counter <= NUM_CYBERWARE_TYPES; counter += 2)
  {
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
                 counter + 1, cyberware_names[counter],
                 counter + 2, counter + 1 < NUM_CYBERWARE_TYPES ?
                 cyberware_names[counter + 1] : "");
  }
  send_to_char("Enter cyberware type, 0 to return: ", CH);
}

void iedit_disp_biotype_menu(struct descriptor_data *d)
{
  CLS(CH);
  for (int counter = 0; counter <= NUM_BIOWARE_TYPES; counter += 2)
  {
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
                 counter + 1, bioware_names[counter],
                 counter + 2, counter + 1 < NUM_BIOWARE_TYPES ?
                 bioware_names[counter + 1] : "");
  }
  send_to_char("Enter bioware type, 0 to return: ", CH);
}

void iedit_program_types_menu(struct descriptor_data *d)
{
  int counter;

  CLS(CH);
  for (counter = 1; counter < NUM_PROGRAMS; counter += 3)
  {
    send_to_char(CH, "  %2d) %-15s %2d) %-15s %2d) %-15s\r\n",
                 counter, program_types[counter],
                 counter + 1, counter + 1 < NUM_PROGRAMS ?
                 program_types[counter + 1] : "", counter + 2, counter + 2 < NUM_PROGRAMS ?
                 program_types[counter + 2] : "");
  }
  send_to_char("Program type: ", d->character);
}

void iedit_disp_rating_menu(struct descriptor_data *d)
{
  CLS(CH);

  for (register int counter = 0; counter < NUM_BARRIERS; ++counter)
    send_to_char(CH, "%2d) %s\r\n", counter + 1, barrier_names[counter]);
  send_to_char("Enter construction category, 0 to return: ", CH);
}

/* object extra flags */
void iedit_disp_extra_menu(struct descriptor_data * d)
{
  int             counter;

  CLS(CH);
  for (counter = 0; counter < ITEM_EXTRA_MAX; counter += 2)
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
                 counter + 1, extra_bits[counter],
                 counter + 2, counter + 1 < ITEM_EXTRA_MAX ?
                 extra_bits[counter + 1] : "");

  GET_OBJ_EXTRA(d->edit_obj).PrintBits(buf1, MAX_STRING_LENGTH,
                                       extra_bits, ITEM_EXTRA_MAX);
  send_to_char(CH, "Object flags: %s%s%s\r\n"
               "Enter object extra flag, 0 to quit: ",
               CCCYN(CH, C_CMP), buf1, CCNRM(CH, C_CMP));
}

void iedit_disp_aff_menu(struct descriptor_data *d)
{
  CLS(CH);
  for (register int counter = 0; counter < AFF_MAX; counter += 2)
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n", counter + 1,
                 affected_bits[counter], counter + 2, counter + 1 < AFF_MAX ?
                 affected_bits[counter + 1] : "");

  OBJ->obj_flags.bitvector.PrintBits(buf1, MAX_STRING_LENGTH,
                                     affected_bits, AFF_MAX);
  send_to_char(CH, "Object flags: %s%s%s\r\n"
               "Enter affected flags, 0 to quit: ", CCCYN(CH, C_CMP),
               buf1, CCNRM(CH, C_CMP));
}

/* object wear flags */
void iedit_disp_wear_menu(struct descriptor_data * d)
{
  int             counter;

  CLS(CH);
  for (counter = 0; counter < ITEM_WEAR_MAX; counter += 2)
  {
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
                 counter + 1, wear_bits[counter],
                 counter + 2, counter + 1 < ITEM_WEAR_MAX ?
                 wear_bits[counter + 1] : "");
  }

  GET_OBJ_WEAR(d->edit_obj).PrintBits(buf1, MAX_STRING_LENGTH,
                                      wear_bits, ITEM_WEAR_MAX);
  send_to_char(CH, "Wear flags: %s%s%s\r\n"
               "Enter wear flag, 0 to quit:", CCCYN(CH, C_CMP),
               buf1, CCNRM(CH, C_CMP));
}

/* display main menu */
void iedit_disp_menu(struct descriptor_data * d)
{
  CLS(CH);
  send_to_char(CH, "Item number: %s%d%s\r\n", CCCYN(CH, C_CMP), d->edit_number,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "1) Item keywords: %s%s%s\r\n",
               CCCYN(CH, C_CMP), d->edit_obj->text.keywords,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "2) Item name: %s%s%s\r\n",
               CCCYN(CH, C_CMP), d->edit_obj->text.name,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "3) Room description:\r\n%s%s%s\r\n",
               CCCYN(CH, C_CMP), d->edit_obj->text.room_desc,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "4) Look description: \r\n%s\r\n",
               d->edit_obj->text.look_desc ? d->edit_obj->text.look_desc :
               "(not set)");
  sprinttype(GET_OBJ_TYPE(d->edit_obj), item_types, buf1);
  send_to_char(CH, "5) Item type: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  GET_OBJ_EXTRA(d->edit_obj).PrintBits(buf1, MAX_STRING_LENGTH,
                                       extra_bits, ITEM_EXTRA_MAX);
  send_to_char(CH, "6) Item extra flags: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  OBJ->obj_flags.bitvector.PrintBits(buf1, MAX_STRING_LENGTH,
                                     affected_bits, AFF_MAX);
  send_to_char(CH, "7) Item affection flags: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  OBJ->obj_flags.wear_flags.PrintBits(buf1, MAX_STRING_LENGTH,
                                      wear_bits, NUM_WEARS);
  send_to_char(CH, "8) Item wear flags: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "9) Item weight: %s%.2f%s\r\n", CCCYN(CH, C_CMP),
               GET_OBJ_WEIGHT(d->edit_obj), CCNRM(CH, C_CMP));
  send_to_char(CH, "a) Item cost: %s%d%s\r\n", CCCYN(CH, C_CMP),
               GET_OBJ_COST(d->edit_obj), CCNRM(CH, C_CMP));
  send_to_char(CH, "b) Item availability: ^c%d^n/^c%.2f^n days\r\n", GET_OBJ_AVAILTN(d->edit_obj), GET_OBJ_AVAILDAY(d->edit_obj));
  send_to_char(CH, "c) Item timer: %s%d%s\r\n", CCCYN(CH, C_CMP),
               GET_OBJ_TIMER(d->edit_obj), CCNRM(CH, C_CMP));
  send_to_char(CH, "d) Item Material: %s%s%s\r\n", CCCYN(CH, C_CMP),
               material_names[(int)GET_OBJ_MATERIAL(d->edit_obj)], CCNRM(CH, C_CMP));
  send_to_char(CH, "e) Item Barrier Rating: %s%d%s\r\n", CCCYN(CH, C_CMP),
               GET_OBJ_BARRIER(d->edit_obj), CCNRM(CH, C_CMP));
  send_to_char(CH, "f) Item values: ^c%d %d %d %d %d %d %d %d %d %d^n\r\n",
               GET_OBJ_VAL(d->edit_obj, 0), GET_OBJ_VAL(d->edit_obj, 1),
               GET_OBJ_VAL(d->edit_obj, 2), GET_OBJ_VAL(d->edit_obj, 3),
               GET_OBJ_VAL(d->edit_obj, 4), GET_OBJ_VAL(d->edit_obj, 5),
               GET_OBJ_VAL(d->edit_obj, 6), GET_OBJ_VAL(d->edit_obj, 7),
               GET_OBJ_VAL(d->edit_obj, 8), GET_OBJ_VAL(d->edit_obj, 9));
  send_to_char("g) Item applies:\r\n"
               "h) Item extra descriptions:\r\n"
               "q) Quit and save\r\n"
               "x) Exit and abort\r\n"
               "Enter your choice:\r\n", CH);
  d->edit_mode = IEDIT_MAIN_MENU;
}

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


void iedit_parse(struct descriptor_data * d, char *arg)
{
  long             number, j;
  long            obj_number;   /* the RNUM */
  bool modified = FALSE;
  switch (d->edit_mode)
  {

  case IEDIT_CONFIRM_EDIT:
    /* if player hits 'Y' then edit obj */
    switch (*arg) {
    case 'y':
    case 'Y':
      iedit_disp_menu(d);
      break;
    case 'n':
    case 'N':
      STATE(d) = CON_PLAYING;
      /* free up the editing object */
      if (d->edit_obj)
        Mem->DeleteObject(d->edit_obj);
      d->edit_obj = NULL;
      d->edit_number = 0;
      PLR_FLAGS(d->character).RemoveBit(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 IEDIT_CONFIRM_EDIT */

  case IEDIT_CONFIRM_SAVESTRING:
    switch (*arg) {
    case 'y':
    case 'Y': {
        /* write to internal tables */
        if (!from_ip_zone(d->edit_number)) {
          sprintf(buf,"%s wrote new obj #%ld",
                  GET_CHAR_NAME(d->character), d->edit_number);
          mudlog(buf, d->character, LOG_WIZLOG, TRUE);
        }

        obj_number = real_object(d->edit_number);
        if (obj_number > 0) {
          /* we need to run through each and every object currently in the
           * game to see which ones are pointing to this prototype */
          struct extra_descr_data *This, *next_one;

          /* if object is pointing to this prototype, then we need to replace
           * with the new one */
          // this function updates pointers to the active list of objects
          // in the mud
          ObjList.UpdateObjs(d->edit_obj, obj_number);
          /* now safe to free old proto and write over */
          if (obj_proto[obj_number].text.keywords)
            delete [] obj_proto[obj_number].text.keywords;
          if (obj_proto[obj_number].text.name)
            delete [] obj_proto[obj_number].text.name;
          if (obj_proto[obj_number].text.room_desc)
            delete [] obj_proto[obj_number].text.room_desc;
          if (obj_proto[obj_number].text.look_desc)
            delete [] obj_proto[obj_number].text.look_desc;

          if (obj_proto[obj_number].ex_description)
            for (This = obj_proto[obj_number].ex_description;
                 This; This = next_one) {
              next_one = This->next;
              if (This->keyword)
                delete [] This->keyword;
              if (This->description)
                delete [] This->description;
              delete This;
            }

          obj_proto[obj_number] = *d->edit_obj;
          obj_proto[obj_number].item_number = obj_number;
        } else {
          /* uhoh.. need to make a new place in the object prototype table */
          long             counter;
          int             found = FALSE;

          struct obj_data *new_obj_proto;
          struct index_data *new_obj_index;

          /* + 2.. strange but true */
          new_obj_index = new struct index_data[top_of_objt + 2];
          new_obj_proto = new struct obj_data[top_of_objt + 2];
          /* start counting through both tables */
          for (counter = 0; counter < top_of_objt + 1; counter++) {
            /* if we haven't found it */
            if (!found) {
              /* check if current virtual is bigger than our virtual */
              if (OBJ_VNUM_RNUM(counter) > d->edit_number) {
                /* eureka. insert now */
                /*---------*/
                new_obj_index[counter].vnum = d->edit_number;
                new_obj_index[counter].number = 0;
                new_obj_index[counter].func = NULL;
                /*---------*/
                new_obj_proto[counter] = *(d->edit_obj);
                new_obj_proto[counter].in_room = NOWHERE;
                /* it is now safe (and necessary!) to assign real number to
                 * the edit_obj, which has been -1 all this time */
                d->edit_obj->item_number = counter;
                /* and assign to prototype as well */
                new_obj_proto[counter].item_number = counter;
                found = TRUE;
                /* insert the other proto at this point */
                new_obj_index[counter + 1] = obj_index[counter];
                new_obj_proto[counter + 1] = obj_proto[counter];
                new_obj_proto[counter + 1].item_number = counter + 1;
              } else {
                /* just copy from old to new, no num change */
                new_obj_proto[counter] = obj_proto[counter];
                new_obj_index[counter] = obj_index[counter];
              }
            } else {
              /* we HAVE already found it.. therefore copy to object + 1 */
              new_obj_index[counter + 1] = obj_index[counter];
              new_obj_proto[counter + 1] = obj_proto[counter];
              new_obj_proto[counter + 1].item_number = counter + 1;
            }
          }
          /* if we STILL haven't found it, means the object was > than all
           * the other objects.. so insert at end */
          if (!found) {
            new_obj_index[top_of_objt + 1].vnum = d->edit_number;
            new_obj_index[top_of_objt + 1].number = 0;
            new_obj_index[top_of_objt + 1].func = NULL;

            clear_object(new_obj_proto + top_of_objt + 1);
            new_obj_proto[top_of_objt + 1] = *(d->edit_obj);
            new_obj_proto[top_of_objt + 1].in_room = NOWHERE;
            new_obj_proto[top_of_objt + 1].item_number = top_of_objt + 1;
            /* it is now safe (and necessary!) to assign real number to
             * the edit_obj, which has been -1 all this time */
            d->edit_obj->item_number = top_of_objt + 1;
          }
          top_of_objt++;


          /* we also have to renumber all the objects currently
             existing in the world. This is because when I start
             extracting objects, bad things will happen! */

          ObjList.UpdateNums(d->edit_obj->item_number);

          //for (temp_obj = object_list; temp_obj; temp_obj = temp_obj->next)
          //  if (GET_OBJ_RNUM (temp_obj) >= d->edit_obj->item_number)
          //    GET_OBJ_RNUM (temp_obj)++;

          /* free and replace old tables */
          delete [] obj_proto;
          delete [] obj_index;
          obj_proto = new_obj_proto;
          obj_index = new_obj_index;

          /* RENUMBER ZONE TABLES HERE, only
             because I ADDED an object!
             This code shamelessly ripped off from db.c */
          {
            int zone, cmd_no;
            for (zone = 0; zone <= top_of_zone_table; zone++)
              for (cmd_no = 0; cmd_no < zone_table[zone].num_cmds; cmd_no++)
              {
                switch (ZCMD.command) {
                case 'O':
                  ZCMD.arg1 =
                    (ZCMD.arg1 >= d->edit_obj->item_number ?
                     ZCMD.arg1 + 1 : ZCMD.arg1);
                  break;
                case 'G':
                  ZCMD.arg1 =
                    (ZCMD.arg1 >= d->edit_obj->item_number ?
                     ZCMD.arg1 + 1 : ZCMD.arg1);
                  break;
                case 'E':
                  ZCMD.arg1 =
                    (ZCMD.arg1 >= d->edit_obj->item_number ?
                     ZCMD.arg1 + 1 : ZCMD.arg1);
                  break;
                case 'P':
                  ZCMD.arg1 =
                    (ZCMD.arg1 >= d->edit_obj->item_number ?
                     ZCMD.arg1 + 1 : ZCMD.arg1);
                  ZCMD.arg3 =
                    (ZCMD.arg3 >= d->edit_obj->item_number ?
                     ZCMD.arg3 + 1 : ZCMD.arg3);
                  break;
                case 'R': /* rem obj from room */
                  ZCMD.arg2 =
                    (ZCMD.arg2 >= d->edit_obj->item_number ?
                     ZCMD.arg2 + 1 : ZCMD.arg2);
                  break;
                }
              }
          }
          /* this fixes the creeping board problems */
          // not needed since real nums are not used with boards anymore
          /*        realcounter = real_object (d->edit_number);
                    for (counter = 0; counter < NUM_OF_BOARDS; counter++)
                      {
                        if (BOARD_RNUM (counter) >= realcounter)
                          BOARD_RNUM (counter) = BOARD_RNUM (counter) + 1;
                      } */
        }  /* end of obj insertion */

        send_to_char("Writing object to disk..", d->character);
        write_objs_to_disk(d->character->player_specials->saved.zonenum);
        // do not wanna nuke the strings, so we use ClearObject
        if (d->edit_obj)
          Mem->ClearObject(d->edit_obj);
        d->edit_obj = NULL;
        STATE(d) = CON_PLAYING;
        PLR_FLAGS(d->character).RemoveBit(PLR_EDITING);
        send_to_char("Done.\r\n", d->character);
      }
      break;
    case 'n':
    case 'N':
      send_to_char("Object not saved, aborting.\r\n", d->character);
      STATE(d) = CON_PLAYING;
      /* free up the editing object. free_obj *is* safe since
       it checks against prototype table */
      if (d->edit_obj)
        Mem->DeleteObject(d->edit_obj);
      d->edit_obj = NULL;
      d->edit_number = 0;
      PLR_FLAGS(d->character).RemoveBit(PLR_EDITING);
      break;
    default:
      send_to_char("Invalid choice!\r\n", d->character);
      send_to_char("Do you wish to save this object internally?\r\n", d->character);
      break;
    }
    break;                      /* end of IEDIT_CONFIRM_SAVESTRING */

  case IEDIT_MAIN_MENU:
    /* throw us out to whichever edit mode based on user input */
    switch (*arg) {
    case 'q':
    case 'Q':
      d->edit_mode = IEDIT_CONFIRM_SAVESTRING;
      iedit_parse(d, "y");
      break;
    case 'x':
    case 'X':
      d->edit_mode = IEDIT_CONFIRM_SAVESTRING;
      iedit_parse(d, "n");
      break;
    case '1':
      send_to_char("Enter namelist:", d->character);
      d->edit_mode = IEDIT_EDIT_NAMELIST;
      break;
    case '2':
      send_to_char("Enter short desc:", d->character);
      d->edit_mode = IEDIT_SHORTDESC;
      break;
    case '3':
      send_to_char("Enter normal desc:\r\n", d->character);
      d->edit_mode = IEDIT_DESC;
      break;
    case '4':
      /* let's go out to modify.c */
      send_to_char("Enter long desc:\r\n", d->character);
      d->edit_mode = IEDIT_LONGDESC;
      //d->str = (char **) xmalloc(sizeof(char *));
      d->str = new (char *);
      if (!d->str) {
        mudlog("Malloc failed!", NULL, LOG_SYSLOG, TRUE);
        shutdown();
      }
      *(d->str) = NULL;
      d->max_str = MAX_MESSAGE_LENGTH;
      d->mail_to = 0;
      break;
    case '5':
      iedit_disp_type_menu(d);
      d->edit_mode = IEDIT_TYPE;
      break;
    case '6':
      iedit_disp_extra_menu(d);
      d->edit_mode = IEDIT_EXTRAS;
      break;
    case '7':
      iedit_disp_aff_menu(d);
      d->edit_mode = IEDIT_AFF_BITS;
      break;
    case '8':
      iedit_disp_wear_menu(d);
      d->edit_mode = IEDIT_WEAR;
      break;
    case '9':
      send_to_char("Enter weight:", d->character);
      d->edit_mode = IEDIT_WEIGHT;
      break;
    case 'a':
    case 'A':
      send_to_char("Enter cost:", d->character);
      d->edit_mode = IEDIT_COST;
      break;
    case 'b':
    case 'B':
      send_to_char(CH, "Enter Availibilty TN: ");
      d->edit_mode = IEDIT_AVAILTN;
      break;
    case 'c':
    case 'C':
      send_to_char("Enter timer:", d->character);
      d->edit_mode = IEDIT_TIMER;
      break;
    case 'd':
    case 'D':
      iedit_disp_material_menu(d);
      d->edit_mode = IEDIT_MATERIAL;
      break;
    case 'e':
    case 'E':
      iedit_disp_rating_menu(d);
      d->edit_mode = IEDIT_RATING;
      break;
    case 'f':
    case 'F':
      iedit_disp_val1_menu(d);
      break;
    case 'g':
    case 'G':
      iedit_disp_prompt_apply_menu(d);
      break;
    case 'h':
    case 'H':
      /* if extra desc doesn't exist . */
      if (!d->edit_obj->ex_description) {
        d->edit_obj->ex_description = new extra_descr_data;
        memset((char *) d->edit_obj->ex_description, 0, sizeof(extra_descr_data));
      }
      /* There is a reason I need the double pointer. If at the extra desc
       * menu user presses '0' then I need to free the extra description.
       * Since it's at the end of list it's pointer must be pointing to
       * NULL.. thus the double pointer */
      d->misc_data = (void **) &(d->edit_obj->ex_description);
      iedit_disp_extradesc_menu(d);
      break;
    default:
      /* hm, i just realized you probably can't see this.. maybe prompt for
       * an extra RETURN. well, maybe later */
      send_to_char("That's not a valid choice!\r\n", d->character);
      iedit_disp_menu(d);
      break;
    }
    break;                      /* end of IEDIT_MAIN_MENU */

  case IEDIT_EDIT_NAMELIST:
    if (d->edit_obj->text.keywords)
      delete [] d->edit_obj->text.keywords;
    d->edit_obj->text.keywords = str_dup(arg);
    iedit_disp_menu(d);
    break;
  case IEDIT_SHORTDESC:
    if (d->edit_obj->text.name)
      delete [] d->edit_obj->text.name;
    d->edit_obj->text.name = str_dup(arg);
    iedit_disp_menu(d);
    break;
  case IEDIT_DESC:
    if (d->edit_obj->text.room_desc)
      delete [] d->edit_obj->text.room_desc;
    d->edit_obj->text.room_desc = str_dup(arg);
    iedit_disp_menu(d);
    break;
  case IEDIT_LONGDESC:
    // we should not get here
    break;
  case IEDIT_TYPE:
    number = atoi(arg);
    if ((number < 1) || (number > NUM_ITEM_TYPES) || (number == ITEM_CYBERWARE && !access_level(CH, LVL_ADMIN)) ||
        (number == ITEM_BIOWARE && !access_level(CH, LVL_ADMIN))) {
      send_to_char("That's not a valid choice!\r\n", d->character);
      iedit_disp_type_menu(d);
    } else if (number != 0) {
      GET_OBJ_TYPE(d->edit_obj) = number;
      GET_OBJ_VAL(d->edit_obj, 0) = 0;
      GET_OBJ_VAL(d->edit_obj, 1) = 0;
      GET_OBJ_VAL(d->edit_obj, 2) = 0;
      GET_OBJ_VAL(d->edit_obj, 3) = 0;
      GET_OBJ_VAL(d->edit_obj, 4) = 0;
      GET_OBJ_VAL(d->edit_obj, 5) = 0;
      GET_OBJ_VAL(d->edit_obj, 6) = 0;
      GET_OBJ_VAL(d->edit_obj, 7) = 0;
      GET_OBJ_VAL(d->edit_obj, 8) = 0;
      GET_OBJ_VAL(d->edit_obj, 9) = 0;
    }
    iedit_disp_menu(d);
    break;
  case IEDIT_EXTRAS:
    number = atoi(arg);
    if ((number < 0) || (number > ITEM_EXTRA_MAX)) {
      send_to_char("That's not a valid choice!\r\n", d->character);
      iedit_disp_extra_menu(d);
    } else {
      /* if 0, quit */
      if (number == 0)
        iedit_disp_menu(d);
      /* if already set.. remove */
      else {
        GET_OBJ_EXTRA(d->edit_obj).ToggleBit(number-1);
        iedit_disp_extra_menu(d);
      }
    }
    break;
  case IEDIT_AFF_BITS:
    number = atoi(arg);
    if ((number > 0) && (number <= AFF_MAX)) {
      OBJ->obj_flags.bitvector.ToggleBit(number-1);
    } else if (number == 0) {
      iedit_disp_menu(d);
      return;
    }
    iedit_disp_aff_menu(d);

    break;
  case IEDIT_WEAR:
    number = atoi(arg);
    if ((number < 0) || (number > ITEM_WEAR_MAX)) {
      send_to_char("That's not a valid choice!\r\n", d->character);
      iedit_disp_wear_menu(d);
    } else {
      /* if 0, quit */
      if (number == 0)
        iedit_disp_menu(d);
      /* if already set.. remove */
      else {
        GET_OBJ_WEAR(d->edit_obj).ToggleBit(number-1);
        iedit_disp_wear_menu(d);
      }
    }
    break;
  case IEDIT_WEIGHT:
    GET_OBJ_WEIGHT(d->edit_obj) = atof(arg);
    iedit_disp_menu(d);
    break;
  case IEDIT_AVAILTN:
    GET_OBJ_AVAILTN(d->edit_obj) = atoi(arg);
    send_to_char(CH, "Enter Availabilty Time in Days: ");
    d->edit_mode = IEDIT_AVAILDAY;
    break;
  case IEDIT_AVAILDAY:
    GET_OBJ_AVAILDAY(d->edit_obj) = atof(arg);
    iedit_disp_menu(d);
    break;
  case IEDIT_COST:
    GET_OBJ_COST(d->edit_obj) = atoi(arg);
    iedit_disp_menu(d);
    break;
  case IEDIT_TIMER:
    GET_OBJ_TIMER(d->edit_obj) = atoi(arg);
    iedit_disp_menu(d);
    break;
  case IEDIT_VALUE_1:
    /* lucky, I don't need to check any of these for outofrange values */
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_WORKSHOP:
      if (number < 0 || number > 6) {
        send_to_char(CH, "Invalid value. Enter Workshop Type: ");
        return;
      }
      break;
    case ITEM_CAMERA:
      if (number < 0 || number > 1) {
        send_to_char(CH,"Value must be 0 or 1: \r\n");
        return;
      }
      break;
    case ITEM_WEAPON:
      if (number < 0 || number > 50) {
        send_to_char("Value must be between 0 and 50:\r\n"
                     "Power (0 for melee weapon): ", d->character);
        return;
      }
      break;
    case ITEM_FIREWEAPON:
      if (number < 0 || number > 50) {
        send_to_char("Value must be between 0 and 50:\r\n"
                     "Power (0 for melee weapon): ", d->character);
        return;
      }
      number = 0;
      break;
    case ITEM_MISSILE:
      if (number < 0 || number > 1) {
        send_to_char("Value must be 0 or 1!\r\nMissile type: ", CH);
        return;
      }
      break;
    case ITEM_BIOWARE:
      if (number < 1 || number > 5) {
        send_to_char("Value must be between 1 and 5.\r\nRating of bioware: ", CH);
        return;
      }
      break;
    case ITEM_CYBERWARE:
      if (number < 1 || number > 10) {
        send_to_char("Value must be between 1 and 10.\r\nRating of cyberware: ", CH);
        return;
      }
      break;
    case ITEM_CYBERDECK:
      if (number < 1 || number > 30) {
        send_to_char("Value must be between 1 and 30.\r\nMPCP Rating: ", CH);
        return;
      }
      break;
    case ITEM_PROGRAM:
      if (number < 1 || number > 30) {
        iedit_program_types_menu(d);
        return;
      }
      break;
    case ITEM_WORKING_GEAR:
      if (number < 1 || number > 4) {
        CLS(CH);
        send_to_char("1) Medical\r\n"
                     "2) Electronic\r\n"
                     "3) Cyberdeck\r\n"
                     "4) Mechanical\r\n"
                     "Enter type of kit: ", CH);
        return;
      } else
        number--;
      break;
    case ITEM_DECK_ACCESSORY:
      if (number < 0 || number > 4) {
        send_to_char("Invalid option!  Accessory type: ", CH);
        return;
      }
      break;
    case ITEM_GUN_ACCESSORY:
      if (number < 0 || number > 2) {
        send_to_char("Invalid option!  Accessory location: ", CH);
        return;
      }
      break;
    case ITEM_DOCWAGON:
      if (number < 1 || number > 3) {
        send_to_char("Value must be between 1 and 3.  DocWagon type: ", CH);
        return;
      }
      break;
    case ITEM_PATCH:
      if (number < 1 || number > NUM_PATCHES) {
        iedit_disp_patch_menu(d);
        return;
      } else
        number--;
      break;
    case ITEM_FOCUS:
      if (number < FOCI_SPELL || number > FOCI_WEAPON) {
        send_to_char("Invalid option.\r\nFocus type: ", CH);
        return;
      }
      break;
    case ITEM_CLIMBING:
      if (number < 1 || number > 3) {
        send_to_char("Rating must range from 1 to 3.  Rating: ", CH);
        return;
      }
      break;
    case ITEM_MONEY:
      if (number < 0 || number > 25000) {
        send_to_char("Value must range between 0 and 25000 nuyen.\r\nValue: ", CH);
        return;
      }
      break;
    case ITEM_CHIP:
      if ((number < 0) || (number > MAX_SKILLS)) {
        send_to_char(CH, "Value must range between 1 and %d.\r\n", MAX_SKILLS);
        send_to_char("Enter a skill (0 to quit): ", CH);
        return;
      }
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 0) = number;
    /* proceed to menu 2 */
    iedit_disp_val2_menu(d);
    break;

  case IEDIT_VALUE_2:
    /* here, I do need to check for outofrange values */
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_CHIP:
      if (number < 0 || number > 15) {
        send_to_char(CH, "Rating must be between 0 and 15. Enter skillsoft rating: ");
        return;
      }
      break;
    case ITEM_POTION:
      if (number < 1 || number > NUM_SPELLS) {
        send_to_char("Invalid choice!", d->character);
        iedit_disp_val2_menu(d);
        return;
      } else {
        GET_OBJ_VAL(d->edit_obj, 1) = number;
        iedit_disp_val3_menu(d);
        return;
      }
      break;
    case ITEM_CONTAINER:
      number = atoi(arg);
      if (number < 0 || number > 4) {
        send_to_char("Invalid choice!\r\n", d->character);
        iedit_disp_container_flags_menu(d);
      } else {
        /* if 0, quit */
        if (number != 0) {
          if (IS_SET(GET_OBJ_VAL(d->edit_obj, 1), 1 << (number - 1)))
            REMOVE_BIT(GET_OBJ_VAL(d->edit_obj, 1), 1 << (number - 1));
          else
            SET_BIT(GET_OBJ_VAL(d->edit_obj, 1), 1 << (number - 1));
          iedit_disp_val2_menu(d);
          return;
        } else {
          iedit_disp_val3_menu(d);
          return;
        }
      }
      break;
    case ITEM_QUIVER:
      if (number < 0 || number > 3) {
        send_to_char("Invalid input!\r\nQuiver type: ", CH);
        return;
      }
      break;
    case ITEM_WEAPON:
    case ITEM_FIREWEAPON:
      if ((number < 1) || (number > 4)) {
        send_to_char("Value must be between 1 and 4.\r\n"
                     "Base damage (1 - Light, 2 - Moderate, 3 - Serious, 4 - Deadly): ", d->character);
        return;
      }
      break;
    case ITEM_PROGRAM:
      if (number < 1 || number > 20) {
        send_to_char("Rating must be between 1 and 20.\r\nProgram Rating: ", CH);
        return;
      }
      break;
    case ITEM_BIOWARE:
      if (number < 10 || number > 600) {
        send_to_char("Body index cost must be between 10 and 600.\r\nBody index cost (x 100): ", CH);
        return;
      }
      break;
    case ITEM_CYBERWARE:
      if (number < 10 || number > 600) {
        send_to_char("Essence cost must be between 10 and 600.\r\nEssence cost (x 100): ", CH);
        return;
      }
      break;
    case ITEM_DECK_ACCESSORY:
      switch (GET_OBJ_VAL(OBJ, 0)) {
      case TYPE_FILE:
        if (number < 0) {
          send_to_char("Size must be greater than 0.  File size: ", CH);
          return;
        }
        break;
      case TYPE_UPGRADE:
        if (number < 0 || number > 5) {
          send_to_char("Invalid choice!  Upgrade type: ", CH);
          return;
        }
      case TYPE_PARTS:
        if (number < 0 || number > 1) {
          send_to_char("Invalid choice!  Part type:", CH);
          return;
        }
      }
      break;
    case ITEM_PATCH:
      if ((number < 1) || (number > 10)) {
        send_to_char("Rating must be between 1 and 10.\r\n", CH);
        return;
      }
      break;
    case ITEM_GUN_ACCESSORY:
      if (number < 1 || number > 6) {
        send_to_char("Invalid option!  Accessory type: ", CH);
        return;
      }
      break;
    case ITEM_FOCUS:
      if (number < 1 || number > 10) {
        send_to_char("Rating must be between 1 and 10.\r\n", CH);
        return;
      }
      break;
    case ITEM_GUN_CLIP:
      if (number < 1 || number > 8) {
        send_to_char("Invalid option!\r\nClip type: ", CH);
        return;
      }
      number += 20;
      if (number == 27)
        number = 19;
      if (number == 28)
        number = 20;
      break;
    case ITEM_RADIO:
      if (number < 0 || number > 5) {
        send_to_char("Enter radio's range (0-5): ", CH);
        return;
      }
      break;
    case ITEM_MONEY:
      if (number < 1 || number > 2) {
        iedit_disp_val2_menu(d);
        return;
      }
      number--;
      break;
    default:
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 1) = number;
    iedit_disp_val3_menu(d);
    break;

  case IEDIT_VALUE_3:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_POTION:
      if (number < 1 || number > NUM_SPELLS) {
        send_to_char("Invalid choice!", d->character);
        iedit_disp_val3_menu(d);
        return;
      }
      break;
    case ITEM_DRINKCON:
    case ITEM_FOUNTAIN:
      if (number < 1 || number > NUM_DRINK_TYPES) {
        send_to_char("Invalid choice.", CH);
        iedit_disp_val4_menu(d);
        return;
      }
      number--; // to give the correct value to the object
      break;
    case ITEM_WEAPON:
    case ITEM_FIREWEAPON:
      if (number < 0 || number > 4) {
        send_to_char("Value must be between 0 and 4.\r\n", CH);
        iedit_disp_val3_menu(d);
        return;
      }
      break;
    case ITEM_BIOWARE:
      if (number < 0 || number > NUM_BIOWARE_TYPES) {
        iedit_disp_biotype_menu(d);
        return;
      }
      number--;
      break;
    case ITEM_CYBERWARE:
      if (number < 0 || number > NUM_CYBERWARE_TYPES) {
        iedit_disp_cybertype_menu(d);
        return;
      }
      number--;
      break;
    case ITEM_PROGRAM:
      if (number < 0) {
        send_to_char("Invalid input.\r\nProgram Size: ", CH);
        return;
      }
      break;
    case ITEM_DECK_ACCESSORY:
      switch (GET_OBJ_VAL(OBJ, 1)) {
      case 0:
        if (number < 1 || number > 15) {
          send_to_char("MPCP must be between 1 and 15.  MPCP Rating: ", CH);
          return;
        }
        break;
      case 1:
        if (number < 1 || number > 1000) {
          send_to_char("Invalid value!  Active memory increase: ", CH);
          return;
        }
        break;
      case 2:
        if (number < 1 || number > 20000) {
          send_to_char("Invalid value!  Storage memory increase: ", CH);
          return;
        }
        break;
      case 3:
        if (number < 1 || number > 100) {
          send_to_char("Invalid value!  Load speed increase: ", CH);
          return;
        }
        break;
      case 4:
        if (number < 1 || number > 50) {
          send_to_char("Invalid value!  I/O speed increase: ", CH);
          return;
        }
        break;
      case 5:
        if (number < 1 || number > 3) {
          send_to_char("Values must range from 1 to 3.  Reaction increase level: ", CH);
          return;
        }
      }
      break;
    case ITEM_GUN_ACCESSORY:
      if (GET_OBJ_VAL(OBJ, 1) == 3 && (number < -3 || number > -1)) {
        send_to_char("Modifier must be between -3 and -1.  Recoil modifier: ", CH);
        return;
      }
      break;
    case ITEM_FOCUS:
      if (GET_OBJ_VAL(OBJ, 0) == FOCI_SPIRIT && (number < 1 || number > NUM_SPIRITS)) {
        send_to_char("Invalid response.  Focus spirit type: ", CH);
        return;
      } else if (GET_OBJ_VAL(OBJ, 0) == FOCI_SPELL && (number < 1 || number > NUM_SPELLS)) {
        send_to_char("Invalid choice!\r\n", CH);
        iedit_disp_val3_menu(d);
        return;
      } else if (GET_OBJ_VAL(OBJ, 0) == FOCI_SPELL_CAT) {
        if (number < 1 || number > 5) {
          send_to_char("Invalid choice!  Focus spell category: ", CH);
          return;
        } else
          number--;
      }
      break;
    case ITEM_SPELL_FORMULA:
      if ((number < 1) || (number > 50)) {
        send_to_char("Force must be between 1 and 50.\r\n", CH);
        return;
      }
      break;
    case ITEM_RADIO:
      if (number < 0 || number > 20) {
        send_to_char("Enter encryption/decryption rating (1-6): ", CH);
        return;
      }
      break;
    case ITEM_MONEY:
      if (number < 1 || number > 3) {
        iedit_disp_val3_menu(d);
        return;
      }
      break;
    case ITEM_GUN_CLIP:
      if (number < 0 || number > 5) {
        send_to_char("INVALID TYPE!\r\nSelect Type: ", CH);
        return;
      }
    default:
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 2) = number;
    iedit_disp_val4_menu(d);
    break;

  case IEDIT_VALUE_4:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_WEAPON:
      if (number < 1 || (!access_level(CH, LVL_ADMIN) && number == TYPE_BIFURCATE) || number > NUM_WEAPON_TYPES) {
        send_to_char("Invalid choice!", d->character);
        iedit_disp_weapon_menu(d);
        return;
      }
      switch (number + TYPE_HIT) {
      case TYPE_PISTOL:
      case TYPE_BLAST:
        GET_OBJ_VAL(OBJ, 7) = 0;
        GET_OBJ_VAL(OBJ, 8) = -1;
        GET_OBJ_VAL(OBJ, 9) = 0;
        break;
      case TYPE_SHOTGUN:
        GET_OBJ_VAL(OBJ, 7) = 0;
        GET_OBJ_VAL(OBJ, 8) = 0;
        GET_OBJ_VAL(OBJ, 9) = -1;
        break;
      case TYPE_GRENADE_LAUNCHER:
      case TYPE_ROCKET:
      case TYPE_RIFLE:
      case TYPE_MACHINE_GUN:
      case TYPE_CANNON:
      case TYPE_BIFURCATE:
        GET_OBJ_VAL(OBJ, 7) = 0;
        GET_OBJ_VAL(OBJ, 8) = 0;
        GET_OBJ_VAL(OBJ, 9) = 0;
        break;
      default:
        GET_OBJ_VAL(OBJ, 7) = -1;
        GET_OBJ_VAL(OBJ, 8) = -1;
        GET_OBJ_VAL(OBJ, 9) = -1;
      }
      break;
    case ITEM_FIREWEAPON:
      if (number < 1 || (!access_level(CH, LVL_ADMIN) && number == TYPE_BIFURCATE) || number > NUM_WEAPON_TYPES) {
        send_to_char("Invalid choice!", d->character);
        iedit_disp_weapon_menu(d);
        return;
      }
      number = TYPE_ARROW;
      break;
    case ITEM_PROGRAM:
      if (number < 1 || number > 4) {
        send_to_char("Must be between 1 and 4: ", d->character);
        iedit_disp_val4_menu(d);
      }
      break;
    case ITEM_SPELL_FORMULA:
      return;
    case ITEM_DECK_ACCESSORY:
      if (number < 1 || number > 15) {
        send_to_char("MPCP value must be between 1 and 15!\r\nMPCP to enhance: ", CH);
        return;
      }
      break;
    default:
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 3) = number;
    if (GET_OBJ_TYPE(OBJ) == ITEM_WEAPON)
      GET_OBJ_VAL(OBJ, 3) += TYPE_HIT;
    iedit_disp_val5_menu(d);
    break;

  case IEDIT_VALUE_5:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_WEAPON:
    case ITEM_FIREWEAPON:
      if (number < 1 || number > NUM_SKILL_TYPES) {
        send_to_char("Invalid choice!", d->character);
        iedit_disp_skill_menu(d);
      } else {
        // this is to skip these general skills which are not in the list
        number += 2;
        if (number == 22) {
          number = SKILL_UNARMED_COMBAT;
          break;
        }
        if (number >= SKILL_UNARMED_COMBAT)
          number += 3;
        if (number >= SKILL_FIREARMS)
          number++;
        if (number >= SKILL_GUNNERY)
          number++;
        if (number >= SKILL_PROJECTILES)
          number++;
        if (number >= SKILL_THROWING_WEAPONS)
          number++;
      }
      break;
    case ITEM_CYBERWARE:
      if (number < 0 || number > 5) {
        send_to_char("Enter radio's range (0-5): ", CH);
        return;
      }
      break;
    default:
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 4) = number;
    iedit_disp_val6_menu(d);
    break;

  case IEDIT_VALUE_6:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_WEAPON:
      break;
    case ITEM_FIREWEAPON:
      if (number < 0 || number > 1) {
        send_to_char("Value must be 0 or 1!\r\nType: ", CH);
        return;
      }
      break;
    case ITEM_CYBERWARE:
      if (number < 1 || number > 6) {
        send_to_char("Enter encryption/decryption rating (1-6): ", CH);
        return;
      }
      break;
    default:
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 5) = number;
    iedit_disp_val7_menu(d);
    break;
  case IEDIT_VALUE_7:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_WEAPON:
      break;
    case ITEM_FIREWEAPON:
      if (number < 1 || number > 10) {
        send_to_char("Strength min. must be between 1 and 10.  Enter strength minimum: ", CH);
        return;
      }
      break;
    case ITEM_SPELL_FORMULA:
      // adjust the values from the type of spell
      if (number <= 0 || number > NUM_SPELLS) {
        iedit_disp_spells_menu(d);
        return;
      }
      GET_OBJ_VAL(OBJ, 0) = grimoire[number].physical;
      GET_OBJ_VAL(OBJ, 1) = grimoire[number].category;
      GET_OBJ_VAL(OBJ, 3) = grimoire[number].target;
      GET_OBJ_VAL(OBJ, 4) = grimoire[number].drain;
      GET_OBJ_VAL(OBJ, 5) = grimoire[number].damage;
      GET_OBJ_VAL(OBJ, 8) = SPELL_ELEMENT_NONE;
      break;
    case ITEM_CYBERDECK:
      if (number <= 0 || number > (int)(GET_OBJ_VAL(d->edit_obj, 0) / 3)) {
        send_to_char(CH, "Reaction upgrade must be between 1 and %d. Reaction Upgrade: ", (int)(GET_OBJ_VAL(d->edit_obj, 0) / 3));
        return;
      }
      break;
    default:
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 6) = number;
    iedit_disp_val8_menu(d);
    break;

  case IEDIT_VALUE_8:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_SPELL_FORMULA:
      if (number < 0 || number > 1) {
        send_to_char("0 for mage, 1 for shaman: ", CH);
        return;
      }
      break;
    case ITEM_WEAPON:
      if (!access_level(CH, LVL_ADMIN))
        if (!read_object(number, VIRTUAL)) {
          send_to_char("Invalid vnum.\r\n", CH);
          iedit_disp_val8_menu(d);
        }
      if (number > 0) {
        modified = FALSE;
        for (j = 0; (j < MAX_OBJ_AFFECT && !modified); j++)
          if (!(OBJ->affected[j].modifier)) {
            OBJ->affected[j].location = read_object(number, VIRTUAL)->affected[0].location;
            OBJ->affected[j].modifier = read_object(number, VIRTUAL)->affected[0].modifier;
            modified = TRUE;
          }
        GET_OBJ_WEIGHT(OBJ) += GET_OBJ_WEIGHT(read_object(number, VIRTUAL));
        GET_OBJ_COST(OBJ) += GET_OBJ_COST(read_object(number, VIRTUAL));
      }
      break;
    default:
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 7) = number;
    iedit_disp_val9_menu(d);
    break;

  case IEDIT_VALUE_9:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_WEAPON:
      if (!access_level(CH, LVL_ADMIN))
        if (!read_object(number, VIRTUAL)) {
          send_to_char("Invalid vnum.\r\n", CH);
          iedit_disp_val9_menu(d);
          return;
        }
      if (number > 0) {
        modified = FALSE;
        for (j = 0; (j < MAX_OBJ_AFFECT && !modified); j++)
          if (!(OBJ->affected[j].modifier)) {
            OBJ->affected[j].location = read_object(number, VIRTUAL)->affected[0].location;
            OBJ->affected[j].modifier = read_object(number, VIRTUAL)->affected[0].modifier;
            modified = TRUE;
          }
        GET_OBJ_WEIGHT(OBJ) += GET_OBJ_WEIGHT(read_object(number, VIRTUAL));
        GET_OBJ_COST(OBJ) += GET_OBJ_COST(read_object(number, VIRTUAL));
      }
      break;
    default:
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 8) = number;
    iedit_disp_val10_menu(d);
    break;

  case IEDIT_VALUE_10:
    number = atoi(arg);
    switch (GET_OBJ_TYPE(d->edit_obj)) {
    case ITEM_WEAPON:
      if (!access_level(CH, LVL_ADMIN))
        if (!read_object(number, VIRTUAL)) {
          send_to_char("Invalid vnum.\r\n", CH);
          iedit_disp_val10_menu(d);
          return;
        }
      if (number > 0) {
        modified = FALSE;
        for (j = 0; (j < MAX_OBJ_AFFECT && !modified); j++)
          if (!(OBJ->affected[j].modifier)) {
            OBJ->affected[j].location = read_object(number, VIRTUAL)->affected[0].location;
            OBJ->affected[j].modifier = read_object(number, VIRTUAL)->affected[0].modifier;
            modified = TRUE;
          }
        GET_OBJ_WEIGHT(OBJ) += GET_OBJ_WEIGHT(read_object(number, VIRTUAL));
        GET_OBJ_COST(OBJ) += GET_OBJ_COST(read_object(number, VIRTUAL));
      }
      break;
    default:
      break;
    }
    GET_OBJ_VAL(d->edit_obj, 9) = number;
    iedit_disp_menu(d);
    break;

  case IEDIT_PROMPT_APPLY:
    number = atoi(arg);
    if (number == 0) {
      iedit_disp_menu(d);
      return;
    } else if (number < 0 || number > MAX_OBJ_AFFECT) {
      send_to_char("Invalid choice!\r\n", d->character);
      iedit_disp_prompt_apply_menu(d);
    } else {
      d->edit_number2 = number - 1;
      d->edit_mode = IEDIT_APPLY;
      iedit_disp_apply_menu(d);
    }
    break;
  case IEDIT_APPLY:
    number = atoi(arg);
    if (number == 0) {
      d->edit_obj->affected[d->edit_number2].location = 0;
      d->edit_obj->affected[d->edit_number2].modifier = 0;
      iedit_disp_prompt_apply_menu(d);
    } else if ((GET_OBJ_TYPE(d->edit_obj) == ITEM_MOD && (number < 0 || number >= VAFF_MAX)) ||
               (number < 0 || number >= AFF_MAX)) {
      send_to_char("Invalid choice!\r\n", d->character);
      iedit_disp_apply_menu(d);
    } else {
      d->edit_obj->affected[d->edit_number2].location = number;
      send_to_char("Modifier:", d->character);
      d->edit_mode = IEDIT_APPLYMOD;
    }
    break;
  case IEDIT_APPLYMOD:
    number = atoi(arg);
    d->edit_obj->affected[d->edit_number2].modifier = number;
    iedit_disp_prompt_apply_menu(d);
    break;
  case IEDIT_EXTRADESC_KEY:
    if (((struct extra_descr_data *) *d->misc_data)->keyword)
      delete [] ((struct extra_descr_data *) *d->misc_data)->keyword;
    ((struct extra_descr_data *) * d->misc_data)->keyword = str_dup(arg);
    iedit_disp_extradesc_menu(d);
    break;
  case IEDIT_MATERIAL:
    number = atoi(arg);
    if (number == 0)
      iedit_disp_menu(d);
    else if (number > 0 && number < NUM_MATERIALS + 1) {
      GET_OBJ_MATERIAL(OBJ) = number - 1;
      iedit_disp_menu(d);
    } else
      iedit_disp_material_menu(d);
    break;
  case IEDIT_RATING:
    number = atoi(arg);
    if (number == 0)
      iedit_disp_menu(d);
    else if (number > 0 && number < NUM_BARRIERS + 1) {
      GET_OBJ_CONDITION(OBJ) = GET_OBJ_BARRIER(OBJ) = barrier_ratings[number - 1];
      iedit_disp_menu(d);
    } else
      iedit_disp_rating_menu(d);
    break;

  case IEDIT_EXTRADESC_MENU:
    number = atoi(arg);
    switch (number) {
    case 0: {
        /* if something got left out */
        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)
            delete [] ((struct extra_descr_data *) * d->misc_data)->keyword;
          if (((struct extra_descr_data *) * d->misc_data)->description)
            delete [] ((struct extra_descr_data *) * d->misc_data)->description;

          delete (struct extra_descr_data *) *d->misc_data;
          *d->misc_data = NULL;
        }
        /* else, we don't need to do anything.. jump to menu */
        iedit_disp_menu(d);
      }
      break;
    case 1:
      d->edit_mode = IEDIT_EXTRADESC_KEY;
      send_to_char("Enter keywords, separated by spaces:", d->character);
      break;
    case 2:
      d->edit_mode = IEDIT_EXTRADESC_DESCRIPTION;
      send_to_char("Enter description:\r\n", d->character);
      /* send out to modify.c */
      //d->str = (char **) xmalloc(sizeof(char *));
      d->str = new (char *);
      if (!d->str) {
        mudlog("Malloc failed!", NULL, LOG_SYSLOG, TRUE);
        shutdown();
      }

      *(d->str) = NULL;
      d->max_str = MAX_MESSAGE_LENGTH;
      d->mail_to = 0;
      break;
    case 3:
      /* if keyword or description has not been changed don't allow person to
       * edit next */
      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);
        iedit_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 */
          new_extra = new extra_descr_data;
          memset((char *) new_extra, 0, sizeof(extra_descr_data));

          ((struct extra_descr_data *) * d->misc_data)->next = new_extra;
          /* edit new extra, we NEED double pointer because i will set
           * *d->misc_data to NULL later */
          d->misc_data =
            (void **) &((struct extra_descr_data *) * d->misc_data)->next;

        }
        iedit_disp_extradesc_menu(d);

      }
      break;
    default:
      send_to_char("Invalid choice!\r\n", d->character);
      iedit_disp_extradesc_menu(d);
      break;
    }
    break;
  default:
    break;
  }
}

#undef OBJ

/*
Modify this code for new obj formats
*/

void write_objs_to_disk(int zone)
{
  int counter, counter2, realcounter, count = 0;
  FILE *fp;
  struct obj_data *obj;
  struct extra_descr_data *ex_desc;

  zone = real_zone(zone);

  // ideally, this would just fill a VTable with vals...maybe one day

  sprintf(buf, "%s/%d.obj", OBJ_PREFIX, zone_table[zone].number);
  fp = fopen(buf, "w+");

  /* start running through all objects in this zone */
  for (counter = zone_table[zone].number * 100;
       counter <= zone_table[zone].top;
       counter++) {
    /* write object to disk */
    realcounter = real_object(counter);

    if (realcounter >= 0) {
      obj = obj_proto+realcounter;

      if (!strcmp("an unfinished object", obj->text.name))
        continue;

      fprintf(fp, "#%ld\n", GET_OBJ_VNUM(obj));

      fprintf(fp,
              "Keywords:\t%s\n"
              "Name:\t%s\n"
              "RoomDesc:$\n%s~\n"
              "LookDesc:$\n%s~\n",
              obj->text.keywords? obj->text.keywords : "unnamed",
              obj->text.name? obj->text.name : "an unnamed object",
              obj->text.room_desc? obj->text.room_desc
              : "An unnamed object sits here",
              obj->text.look_desc? cleanup(buf2, obj->text.look_desc)
              : "You see an uncreative object.\n");

      fprintf(fp,
              "Type:\t%s\n"
              "WearFlags:\t%s\n"
              "ExtraFlags:\t%s\n"
              "AffFlags:\t%s\n"
              "Material:\t%s\n",
              item_types[(int)GET_OBJ_TYPE(obj)],
              GET_OBJ_WEAR(obj).ToString(),
              GET_OBJ_EXTRA(obj).ToString(),
              obj->obj_flags.bitvector.ToString(),
              material_names[(int)GET_OBJ_MATERIAL(obj)]);

      fprintf(fp,
              "[POINTS]\n"
              "\tWeight:\t%.2f\n"
              "\tBarrier:\t%d\n"
              "\tCost:\t%d\n"
              "\tAvailTN:\t%d\n"
              "\tAvailDay:\t%.2f\n",
              GET_OBJ_WEIGHT(obj), GET_OBJ_BARRIER(obj), GET_OBJ_COST(obj), GET_OBJ_AVAILTN(obj), GET_OBJ_AVAILDAY(obj));

      bool print_vals = false;
      int i;
      for (i = 0; i < 10; i++)
        if (GET_OBJ_VAL(obj, i) != 0) {
          print_vals = true;
          break;
        }

      if (print_vals) {
        fprintf(fp, "[VALUES]\n");
        for (i = 0; i < 10; i++)
          if (GET_OBJ_VAL(obj, i) != 0)
            fprintf(fp, "\tVal%d:\t%d\n", i, GET_OBJ_VAL(obj, i));
      }

      /* do we have extra descriptions? */
      count = 0;
      if (obj->ex_description)
        for (ex_desc = obj->ex_description; ex_desc; ex_desc = ex_desc->next) {
          if (ex_desc->keyword && ex_desc->description) {
            fprintf(fp,
                    "[EXTRADESC %d]\n"
                    "\tKeywords:\t%s\n"
                    "\tDesc:$\n%s~\n", count,
                    ex_desc->keyword, cleanup(buf2, ex_desc->description));
            count++;
          }
        }

      /* do we have affects? */
      for (counter2 = 0; counter2 < MAX_OBJ_AFFECT; counter2++) {
        obj_affected_type *af = obj->affected+counter2;

        if (af->location != APPLY_NONE && af->modifier != 0) {
          fprintf(fp,
                  "[AFFECT %d]\n"
                  "\tLocation:\t%s\n"
                  "\tModifier:\t%d\n", counter2,
                  apply_types[(int)af->location], af->modifier);
        }
      }

      fprintf(fp, "BREAK\n");
    }
  }
  /* write final line, close */
  fprintf(fp, "END\n");
  fclose(fp);

  write_index_file("obj");
}