AwakeMUD-0.6Beta/doc/
AwakeMUD-0.6Beta/lib/
AwakeMUD-0.6Beta/lib/etc/
AwakeMUD-0.6Beta/lib/etc/pfiles/
AwakeMUD-0.6Beta/lib/fixer_data/
AwakeMUD-0.6Beta/lib/misc/
AwakeMUD-0.6Beta/lib/plrobjs/
AwakeMUD-0.6Beta/lib/plrobjs/A-E/
AwakeMUD-0.6Beta/lib/plrobjs/F-J/
AwakeMUD-0.6Beta/lib/plrobjs/K-O/
AwakeMUD-0.6Beta/lib/plrobjs/U-Z/
AwakeMUD-0.6Beta/lib/plrspells/A-E/
AwakeMUD-0.6Beta/lib/plrspells/F-J/
AwakeMUD-0.6Beta/lib/plrtext/A-E/
AwakeMUD-0.6Beta/lib/world/
AwakeMUD-0.6Beta/lib/world/mob/
AwakeMUD-0.6Beta/lib/world/obj/
AwakeMUD-0.6Beta/lib/world/qst/
AwakeMUD-0.6Beta/lib/world/shp/
AwakeMUD-0.6Beta/lib/world/wld/
AwakeMUD-0.6Beta/lib/world/zon/
/* ****************************************************
* File: medit.cc                                      *
* Mob Editor For AwakeOLC, a component of AwakeMUD    *
* (c)2001 The AwakeMUD Consortium, and Andrew Hynek   *
**************************************************** */


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

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


void write_mobs_to_disk(int zone);

// extern vars
extern struct char_data *mob_proto;
extern int top_of_mobt;
extern int calc_karma(struct char_data *ch, struct char_data *vict);
extern int max_ability(int i);
extern int real_zone(int vnum);
extern struct index_data *mob_index;
extern struct zone_data *zone_table;
extern struct char_data *character_list;

extern const char *action_bits[];
extern const char *affected_bits[];
extern const char *position_types[];
extern const char *genders[];
extern const char *attack_types[];
extern const char *spells[];
extern const char *npc_classes[];

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

// mem func
extern class memoryClass *Mem;

// local defines
#define MOB d->edit_mob
#define NUM_MOB_FLAGS          31
#define NUM_MOB_CLASSES        16
#define NUM_MOB_SKILLS         66
#define NUM_UNSKILLS           13
#define NUM_ATTACK_TYPES       28
#define MAX_REG_DESC_LENGTH    160

void medit_disp_menu(struct descriptor_data *d)
{
  int base = calc_karma(NULL, MOB);

  CLS(CH);
  send_to_char(CH, "Mob number: %s%d%s\r\n", CCCYN(CH, C_CMP), d->edit_number,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "1) Mob namelist: %s%s%s\r\n", CCCYN(CH, C_CMP),
               MOB->player.name, CCNRM(CH, C_CMP));
  send_to_char(CH, "2) Mob short description: %s%s%s\r\n", CCCYN(CH, C_CMP),
               MOB->player.short_descr, CCNRM(CH, C_CMP));
  send_to_char(CH, "3) Mob regular description: %s%s%s\r\n", CCCYN(CH, C_CMP),
               MOB->player.long_descr, CCNRM(CH, C_CMP));
  send_to_char(CH, "4) Mob long description:\r\n%s\r\n",
               MOB->player.description);
  sprintbit(MOB_FLAGS(MOB), action_bits, buf1);
  send_to_char(CH, "5) Mob Flags: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  sprintbit(d->edit_mob->char_specials.saved.affected_by, affected_bits, buf1);
  send_to_char(CH, "6) Affected Flags: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "7) Alignment: %s%d%s\r\n", CCCYN(CH, C_CMP),
               GET_ALIGNMENT(MOB), CCNRM(CH, C_CMP));
  send_to_char(CH, "8) Avg. nuyen: %s%6d%s      Avg. credstick value: %s%6d%s\r\n", CCCYN(CH, C_CMP),
               GET_NUYEN(MOB), CCNRM(CH, C_CMP), CCCYN(CH, C_CMP),
               GET_BANK(MOB), CCNRM(CH, C_CMP));
  send_to_char(CH, "9) Bonus karma points: %s%d%s    (Total karma points: %s%d%s)\r\n",
               CCCYN(CH, C_CMP), GET_KARMA(MOB), CCNRM(CH, C_CMP), CCCYN(CH, C_CMP), base, CCNRM(CH, C_CMP));
  if (IS_IC(MOB)) {
    sprintf(buf, "a) IC prevent directions: %s%s%s%s%s%s%s%s%s%s%s%s\r\n", CCCYN(CH, C_CMP),
           (MOB->real_abils.bod ? "n " : ""), (MOB->real_abils.qui ? "ne " : ""),
           (MOB->real_abils.str ? "e " : ""), (MOB->real_abils.cha ? "se " : ""),
           (MOB->real_abils.intel ? "s " : ""), (MOB->real_abils.wil ? "sw " : ""),
           (MOB->real_abils.rea ? "w " : ""), (MOB->real_abils.ess ? "nw " : ""),
           (GET_BALLISTIC(MOB) ? "u " : ""), (GET_IMPACT(MOB) ? "d " : ""), CCNRM(CH, C_CMP));
    send_to_char(buf, CH);
  } else send_to_char(CH, "a) Attributes: B(%s%d%s), Q(%s%d%s), S(%s%d%s), C(%s%d%s), "
                   "I(%s%d%s), W(%s%d%s), M(%s%d%s), R(%s%d%s)\r\n",
               CCCYN(CH, C_CMP), MOB->real_abils.bod, CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), MOB->real_abils.qui, CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), MOB->real_abils.str, CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), MOB->real_abils.cha, CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), MOB->real_abils.intel, CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), MOB->real_abils.wil, CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), MOB->real_abils.mag / 100, CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), MOB->real_abils.rea, CCNRM(CH, C_CMP));
  send_to_char(CH, "b) Level: %s%d%s\r\n", CCCYN(CH, C_CMP), GET_LEVEL(MOB),
               CCNRM(CH, C_CMP));
  if (!IS_IC(MOB))
    send_to_char(CH, "c) Ballistic: %s%d%s, ", CCCYN(CH, C_CMP), GET_BALLISTIC(MOB),
               CCNRM(CH, C_CMP));
  if (!IS_IC(MOB))
    send_to_char(CH, "d) Impact: %s%d%s\r\n", CCCYN(CH, C_CMP), GET_IMPACT(MOB),
               CCNRM(CH, C_CMP));
  send_to_char(CH, "e) Max physical points: %s%d%s, f) Max mental points: %s%d%s\r\n", CCCYN(CH, C_CMP),
               (int)(GET_MAX_PHYSICAL(MOB) / 100), CCNRM(CH, C_CMP), CCCYN(CH, C_CMP),
               (int)(GET_MAX_MENTAL(MOB) / 100), CCNRM(CH, C_CMP));
  sprinttype(GET_POS(MOB), position_types, buf1);
  send_to_char(CH, "g) Position: %s%s%s, ", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  sprinttype(GET_DEFAULT_POS(MOB), position_types, buf1);
  send_to_char(CH, "h) Default Position: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  sprinttype(GET_SEX(MOB), genders, buf1);
//  strcpy(buf1, genders[GET_SEX(d->edit_mob)]);
  send_to_char(CH, "i) Gender: %s%s%s, ", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "j) Weight: %s%d%s, ", CCCYN(CH, C_CMP), GET_WEIGHT(MOB),
               CCNRM(CH, C_CMP));
  send_to_char(CH, "k) Height: %s%d%s\r\n", CCCYN(CH, C_CMP), GET_HEIGHT(MOB),
               CCNRM(CH, C_CMP));
  sprinttype(GET_RACE(MOB), npc_classes, buf1);
  send_to_char(CH, "l) Mob class: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1, CCNRM(CH, C_CMP));
  // gotta subtract TYPE_HIT to make it work properly
  sprinttype(!(MOB->mob_specials.attack_type) ? 0 :
             (MOB->mob_specials.attack_type - TYPE_HIT), attack_types, buf1);
  send_to_char(CH, "m) Attack Type: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  send_to_char("n) Skill menu.\r\n", CH);
  send_to_char(CH, "o) Arrive text: ^c%s^n,  p) Leave text: ^c%s^n\r\n",
               MOB->mob_specials.arrive, MOB->mob_specials.leave);
  send_to_char("q) Quit and save\r\n", CH);
  send_to_char("x) Exit and abort\r\n", CH);
  send_to_char("Enter your choice:\r\n", CH);
  d->edit_mode = MEDIT_MAIN_MENU;
}

void medit_disp_skills(struct descriptor_data *d) {
  int c, line = 0;

  CLS(CH);
  for (c = 0; c < (SKILL_BACKSTAB - 100); c++) {
    line++;
    if ((line % 3) == 1)
      sprintf(buf, "%2d) %-20s ", c+1, spells[c+100]);
    else sprintf(buf, "%s%2d) %-20s ", buf, c+1, spells[c+100]);
    if (!(line % 3)) {
      sprintf(buf, "%s\r\n", buf);
      send_to_char(buf, CH);
    }
  }
  for (; c < NUM_MOB_SKILLS - NUM_UNSKILLS; c++) {
    line++;
    if ((line % 3) == 1)
      sprintf(buf, "%2d) %-20s ", c+1, spells[c+100+NUM_UNSKILLS]);
    else sprintf(buf, "%s%2d) %-20s ", buf, c+1, spells[c+100+NUM_UNSKILLS]);
    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);
  }
}

void medit_disp_attack_menu(struct descriptor_data *d) {
  int c;

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

  send_to_char("Enter attack type: ", CH);
}

void medit_disp_skill_menu(struct descriptor_data *d) {

  CLS(CH);
  send_to_char(CH, "1) Skill: %s%s%s (%s%d%s)\r\n", CCCYN(CH, C_CMP),
    spells[MOB->mob_specials.mob_skills[0]], CCNRM(CH, C_CMP), CCCYN(CH, C_CMP),
    MOB->mob_specials.mob_skills[1], CCNRM(CH, C_CMP));
  send_to_char(CH, "2) Skill: %s%s%s (%s%d%s)\r\n", CCCYN(CH, C_CMP),
    spells[MOB->mob_specials.mob_skills[2]], CCNRM(CH, C_CMP), CCCYN(CH, C_CMP),
    MOB->mob_specials.mob_skills[3], CCNRM(CH, C_CMP));
  send_to_char(CH, "3) Skill: %s%s%s (%s%d%s)\r\n", CCCYN(CH, C_CMP),
    spells[MOB->mob_specials.mob_skills[4]], CCNRM(CH, C_CMP), CCCYN(CH, C_CMP),
    MOB->mob_specials.mob_skills[5], CCNRM(CH, C_CMP));
  send_to_char(CH, "4) Skill: %s%s%s (%s%d%s)\r\n", CCCYN(CH, C_CMP),
    spells[MOB->mob_specials.mob_skills[6]], CCNRM(CH, C_CMP), CCCYN(CH, C_CMP),
    MOB->mob_specials.mob_skills[7], CCNRM(CH, C_CMP));
  send_to_char(CH, "5) Skill: %s%s%s (%s%d%s)\r\n", CCCYN(CH, C_CMP),
    spells[MOB->mob_specials.mob_skills[8]], CCNRM(CH, C_CMP), CCCYN(CH, C_CMP),
    MOB->mob_specials.mob_skills[9], CCNRM(CH, C_CMP));
  send_to_char("0) Quit\r\n", CH);

  send_to_char("Enter your choice: ", CH);
}



void medit_disp_mobflags_menu(struct descriptor_data *d) {

  int c;

  CLS(CH);
  for (c = 0; c < NUM_MOB_FLAGS; c += 2) {
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
            c + 1, action_bits[c],
            c + 2, c + 1 < NUM_MOB_FLAGS ?
            action_bits[c + 1] : "");
  }
  sprintbit(MOB_FLAGS(MOB), action_bits, buf1);
  send_to_char(CH, "Mob flags: %s%s%s\r\n"
                   "Enter mob flag, 0 to quit:", CCCYN(CH, C_CMP),
               buf1, CCNRM(CH, C_CMP));
}

void medit_disp_affected_menu(struct descriptor_data *d) {

  int c;

  CLS(CH);
  for (c = 0; c < NUM_AFF_FLAGS; c += 2) {
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
            c + 1, affected_bits[c],
            c + 2, c + 1 < NUM_AFF_FLAGS ?
            affected_bits[c + 1] : "");
  }
  sprintbit(AFF_FLAGS(MOB), affected_bits, buf1);
  send_to_char(CH, "Affected flags: %s%s%s\r\n"
                   "Enter affected flag, 0 to quit:", CCCYN(CH, C_CMP),
               buf1, CCNRM(CH, C_CMP));
}

void medit_disp_pos_menu(struct descriptor_data *d) {
  int c;

  CLS(CH);
  for (c = 1; c < 9; c++)
    send_to_char(CH, "%2d) %-20s\r\n", c, position_types[c]);
}

void medit_disp_gender_menu(struct descriptor_data *d) {
  send_to_char("1) Neutral\r\n2) Male\r\n3) Female\r\n"
               "\r\nEnter gender: ", CH);
}

void medit_disp_class_menu(struct descriptor_data *d) {
  int c;

  CLS(CH);
  for (c = 0; c < NUM_MOB_CLASSES; c++) {
    send_to_char(CH, "%2d) %-20s\r\n", c + 1, npc_classes[c]);
  }
  sprinttype(GET_RACE(MOB), npc_classes, buf1);
  send_to_char(CH, "Mob class: %s%s%s\r\n"
                   "Enter mob class, 0 to quit: ", CCCYN(CH, C_CMP), buf1, CCNRM(CH, C_CMP));
}

void medit_disp_att_menu(struct descriptor_data *d) {

  CLS(CH);
  if (IS_IC(MOB)) {
    send_to_char("Direction to block:\r\n"
                 "  1) North\r\n  2) Northeast\r\n  3) East\r\n  4) Southeast\r\n"
                 "  5) South\r\n  6) Southwest\r\n  7) West\r\n  8) Northwest\r\n"
                 "  9) Up\r\n  a) Down\r\n", CH);
    sprintf(buf, "IC prevent directions: %s%s%s%s%s%s%s%s%s%s%s%s\r\n", CCCYN(CH, C_CMP),
           (MOB->real_abils.bod ? "n " : ""), (MOB->real_abils.qui ? "ne " : ""),
           (MOB->real_abils.str ? "e " : ""), (MOB->real_abils.cha ? "se " : ""),
           (MOB->real_abils.intel ? "s " : ""), (MOB->real_abils.wil ? "sw " : ""),
           (MOB->real_abils.rea ? "w " : ""), (MOB->real_abils.ess ? "nw " : ""),
           (GET_BALLISTIC(MOB) ? "u " : ""), (GET_IMPACT(MOB) ? "d " : ""), CCNRM(CH, C_CMP));
    send_to_char(buf, CH);
    send_to_char("Enter a direction (0 to exit): ", CH);
    d->edit_mode = MEDIT_ATTRIBUTES;
    return;
  }
  send_to_char(CH, "1) Body:       %s%d%s\r\n", CCCYN(CH, C_CMP), MOB->real_abils.bod,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "2) Quickness:  %s%d%s\r\n", CCCYN(CH, C_CMP), MOB->real_abils.qui,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "3) Strength:   %s%d%s\r\n", CCCYN(CH, C_CMP), MOB->real_abils.str,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "4) Charisma:   %s%d%s\r\n", CCCYN(CH, C_CMP), MOB->real_abils.cha,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "5) Intel.:     %s%d%s\r\n", CCCYN(CH, C_CMP), MOB->real_abils.intel,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "6) Willpower:  %s%d%s\r\n", CCCYN(CH, C_CMP), MOB->real_abils.wil,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "7) Magic:      %s%d%s\r\n", CCCYN(CH, C_CMP), MOB->real_abils.mag / 100,
               CCNRM(CH, C_CMP));
  send_to_char(CH, "q) Quit\r\n");

  send_to_char("\r\nEnter your choice:\r\n", CH);
  d->edit_mode = MEDIT_ATTRIBUTES;
}


//**************************************************************************
//*  Main Loop                                                            *
//***************************************************************************

void medit_parse(struct descriptor_data *d, char *arg) {

  int number;
  int mob_number;  // the RNUM

  switch(d->edit_mode) {
    case MEDIT_CONFIRM_EDIT:
    /* if player hits 'Y' then edit mob */
      switch (*arg) {
        case 'y':
        case 'Y':
          medit_disp_menu(d);
          break;
        case 'n':
        case 'N':
          STATE(d) = CON_PLAYING;
          /* free up the editing mob */
          if (d->edit_mob)
            Mem->DeleteCh(d->edit_mob);
          d->edit_mob = NULL;
          d->edit_number = 0;
          REMOVE_BIT(PLR_FLAGS(d->character), PLR_EDITING);
          break;
        default:
          send_to_char("That's not a valid choice!\r\n", CH);
          send_to_char("Do you wish to edit it?\r\n", CH);
          break;
      }
      break;                      /* end of MEDIT_CONFIRM_EDIT */

    case MEDIT_CONFIRM_SAVESTRING:
      switch(*arg) {
        case 'y':
        case 'Y':
          // first write to the internal tables
          mob_number = real_mobile(d->edit_number);
          if (mob_number > 0) {
            // first we go through the entire list of mobs to find out
            // which are pointing to this prototype; if it is, it gets
            // replaced
            struct char_data *i, *temp;
            int c;
            for (i = character_list; i; i = i->next) {
              if (mob_number == i->nr) {
                // alloc a temp mobile
                temp = Mem->GetCh();
                *temp = *i;
                *i = *d->edit_mob;
                /* copy game-time dependent vars over */
                i->in_room = temp->in_room;
                i->nr = mob_number;
                i->affected = temp->affected;
                i->carrying = temp->carrying;
                i->cyberware = temp->cyberware;
                i->bioware = temp->bioware;
                // any eq worn
                for (c = 0; c < NUM_WEARS; ++c)
                   i->equipment[c] = temp->equipment[c];
                i->next_in_room = temp->next_in_room;
                i->next = temp->next;
                i->next_fighting = temp->next_fighting;
                i->followers = temp->followers;
                i->master = temp->master;
                i->char_specials.fighting = temp->char_specials.fighting;
                i->char_specials.hunting = temp->char_specials.hunting;
                i->mob_specials.last_direction = temp->mob_specials.last_direction;
                i->mob_specials.memory = temp->mob_specials.memory;
                i->mob_specials.wait_state = temp->mob_specials.wait_state;
                Mem->ClearCh(temp);
              } // end if statement

            } // end for loop

            // now you can free the old prototype and put in the new one
            if (mob_proto[mob_number].player.name)
              delete [] mob_proto[mob_number].player.name;
            if (mob_proto[mob_number].player.title)
              delete [] mob_proto[mob_number].player.title;
            if (mob_proto[mob_number].player.short_descr)
              delete [] mob_proto[mob_number].player.short_descr;
            if (mob_proto[mob_number].player.long_descr)
              delete [] mob_proto[mob_number].player.long_descr;
            if (mob_proto[mob_number].player.description)
              delete [] mob_proto[mob_number].player.description;
            if (mob_proto[mob_number].mob_specials.arrive)
              delete [] mob_proto[mob_number].mob_specials.arrive;
            if (mob_proto[mob_number].mob_specials.leave)
              delete [] mob_proto[mob_number].mob_specials.leave;


            mob_proto[mob_number] = *d->edit_mob;
            mob_proto[mob_number].nr = mob_number;

          } else {  // if not, we need to make a new spot in the list
            int realcounter;
            int             counter;
            int             found = FALSE;

            struct char_data *new_mob_proto;
            struct index_data *new_mob_index;
            struct char_data *temp_mob;

            // two because you're adding one and you need one over
            new_mob_index = new struct index_data[top_of_mobt + 2];
            new_mob_proto = new struct char_data[top_of_mobt + 2];
            // count through the tables
            for (counter = 0; counter < top_of_mobt + 1; counter++) {
              /* if we haven't found it */
              if (!found) {
                /* check if current virtual is bigger than our virtual */
                if (mob_index[counter].virt > d->edit_number) {
                  /* eureka. insert now */
                  /*---------*/
                  new_mob_index[counter].virt = d->edit_number;
                  new_mob_index[counter].number = 0;
                  new_mob_index[counter].func = NULL;
                  /*---------*/
                  new_mob_proto[counter] = *(d->edit_mob);
                  new_mob_proto[counter].in_room = NOWHERE;
                  /* it is now safe (and necessary!) to assign real number to
                   * the edit_mob, which has been -1 all this time */
                  d->edit_mob->nr = counter;
                  /* and assign to prototype as well */
                  new_mob_proto[counter].nr = counter;
                  found = TRUE;
                  /* insert the other proto at this point */
                  new_mob_index[counter + 1] = mob_index[counter];
                  new_mob_proto[counter + 1] = mob_proto[counter];
                  new_mob_proto[counter + 1].nr = counter + 1;
                } else {
                  /* just copy from old to new, no num change */
                  new_mob_proto[counter] = mob_proto[counter];
                  new_mob_index[counter] = mob_index[counter];
                }

              } else { // if !found else
              /* we HAVE already found it.. therefore copy to mobile + 1 */
                new_mob_index[counter + 1] = mob_index[counter];
                new_mob_proto[counter + 1] = mob_proto[counter];
                new_mob_proto[counter + 1].nr = counter + 1;
              }
            } // for loop through list


            /* if we STILL haven't found it, means the mobile was > than all
            * the other mobs.. so insert at end */
            if (!found) {
              new_mob_index[top_of_mobt + 1].virt = d->edit_number;
              new_mob_index[top_of_mobt + 1].number = 0;
              new_mob_index[top_of_mobt + 1].func = NULL;

              clear_char(new_mob_proto + top_of_mobt + 1);
              new_mob_proto[top_of_mobt + 1] = *(d->edit_mob);
              new_mob_proto[top_of_mobt + 1].in_room = NOWHERE;
              new_mob_proto[top_of_mobt + 1].nr = top_of_mobt + 1;
              /* it is now safe (and necessary!) to assign real number to
               * the edit_mob, which has been -1 all this time */
              d->edit_mob->nr = top_of_mobt + 1;
            }
            top_of_mobt++;

            /* we also have to renumber all the mobiles currently    *
            *  existing in the world. This is because when I start   *
            * extracting mobiles, bad things will happen!           */
            for (temp_mob = character_list; temp_mob; temp_mob = temp_mob->next)
              if (GET_MOB_RNUM (temp_mob) >= d->edit_mob->nr)
                GET_MOB_RNUM (temp_mob)++;

            /* free and replace old tables */
            delete [] mob_proto;
            delete [] mob_index;
            mob_proto = new_mob_proto;
            mob_index = new_mob_index;

            /* RENUMBER ZONE TABLES HERE, only              *
            *   because I ADDED a mobile!                   *
            *   This code shamelessly ripped off from db.c */

            extern int top_of_zone_table;
            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 'M':
                      ZCMD.arg1 = (ZCMD.arg1 >= d->edit_mob->nr ? ZCMD.arg1 + 1 : ZCMD.arg1);
                      break;
                  }

              }

          } // finally done putting the mobile into memory

          send_to_char("Writing mobile to disk...", CH);
          write_mobs_to_disk(d->character->player_specials->saved.zonenum);

        // again, here we don't delete it cause we don't want to end up
        // deleting the strings from the prototypes
        if (d->edit_mob)
          Mem->ClearCh(d->edit_mob);
        d->edit_mob = NULL;
        STATE(d) = CON_PLAYING;
        REMOVE_BIT(PLR_FLAGS(d->character), PLR_EDITING);
        send_to_char("Done.\r\n", d->character);
        break;
      case 'n':
      case 'N':
        send_to_char("Mobile not saved, aborting.\r\n", d->character);
        STATE(d) = CON_PLAYING;
        // complete nuke
        if (d->edit_mob)
          Mem->DeleteCh(d->edit_mob);
        d->edit_mob = NULL;
        d->edit_number = 0;
        d->edit_zone = 0;
        REMOVE_BIT(PLR_FLAGS(d->character), PLR_EDITING);
        break;
      default:
        send_to_char("Invalid choice!\r\n", d->character);
        send_to_char("Do you wish to save this mobile internally?\r\n", d->character);
        break;
    }

    break;

    case MEDIT_MAIN_MENU:
      switch (*arg) {
        case 'q':
        case 'Q':
          d->edit_mode = MEDIT_CONFIRM_SAVESTRING;
#if CONFIRM_SAVE
          send_to_char("Do you wish to save this mob internally?\r\n", CH);
#else
	  medit_parse(d, "y");
#endif
          break;
        case 'x':
        case 'X':
          d->edit_mode = MEDIT_CONFIRM_SAVESTRING;
#if CONFIRM_SAVE
          send_to_char("Do you wish to save this mob internally?\r\n", CH);
#else
	  medit_parse(d, "n");
#endif
          break;
        case '1':
          send_to_char("Enter namelist:", CH);
          d->edit_mode = MEDIT_EDIT_NAMELIST;
          break;
        case '2':
          send_to_char("Enter short description:", CH);
          d->edit_mode = MEDIT_SHORT_DESCR;
          break;
        case '3':
          send_to_char("Enter regular description:", CH);
          d->edit_mode = MEDIT_REG_DESCR;
          //d->str = (char **) xmalloc(sizeof(char *));
          d->str = new (char *);
          if (!d->str) {
            mudlog("Malloc failed!", NULL, LOG_SYSLOG, TRUE);
            exit(1);
          }

          *(d->str) = NULL;
          d->max_str = MAX_REG_DESC_LENGTH;
          d->mail_to = 0;
          break;
        case '4':
          // go to modify.cc
          send_to_char("Enter long description:\r\n", CH);
          d->edit_mode = MEDIT_LONG_DESCR;
          //d->str = (char **) xmalloc(sizeof(char *));
          d->str = new (char *);
          if (!d->str) {
            mudlog("Malloc failed!", NULL, LOG_SYSLOG, TRUE);
            exit(1);
          }

          *(d->str) = NULL;
          d->max_str = MAX_MESSAGE_LENGTH;
          d->mail_to = 0;
          break;
        case '5':
          medit_disp_mobflags_menu(d);
          d->edit_mode = MEDIT_MOB_FLAGS;
          break;
        case '6':
          medit_disp_affected_menu(d);
          d->edit_mode = MEDIT_AFF_FLAGS;
          break;
        case '7':
          send_to_char("Enter alignment (-1000 to 1000): ", CH);
          d->edit_mode = MEDIT_ALIGNMENT;
          break;
        case '8':
          send_to_char("Enter average nuyen: ", CH);
          d->edit_mode = MEDIT_NUYEN;
          break;
        case '9':
          send_to_char("Enter bonus karma points: ", CH);
          d->edit_mode = MEDIT_EXPERIENCE;
          break;
        case 'a':
          medit_disp_att_menu(d);
          d->edit_mode = MEDIT_ATTRIBUTES;
          break;
        case 'b':
          send_to_char("Enter level: ", CH);
          d->edit_mode = MEDIT_LEVEL;
          break;
        case 'c':
          if (IS_IC(MOB))
            medit_disp_menu(d);
          else {
            send_to_char("Enter ballistic armor points: ", CH);
            d->edit_mode = MEDIT_BALLISTIC;
          }
          break;
        case 'd':
          if (IS_IC(MOB))
            medit_disp_menu(d);
          else {
            send_to_char("Enter impact armor points: ", CH);
            d->edit_mode = MEDIT_IMPACT;
          }
          break;
        case 'e':
          send_to_char("Enter max physical points: ", CH);
          d->edit_mode = MEDIT_PHYSICAL;
          break;
        case 'f':
          send_to_char("Enter max mental points: ", CH);
          d->edit_mode = MEDIT_MENTAL;
          break;
        case 'g':
          medit_disp_pos_menu(d);
          send_to_char("Enter position: ", CH);
          d->edit_mode = MEDIT_POSITION;
          break;
        case 'h':
          medit_disp_pos_menu(d);
          send_to_char("Enter default position: ", CH);
          d->edit_mode = MEDIT_DEFAULT_POSITION;
          break;
        case 'i':
          medit_disp_gender_menu(d);
          d->edit_mode = MEDIT_GENDER;
          break;
        case 'j':
          send_to_char("Enter weight (in kilograms): ", CH);
          d->edit_mode = MEDIT_WEIGHT;
          break;
        case 'k':
          send_to_char("Enter height (in centimeters): ", CH);
          d->edit_mode = MEDIT_HEIGHT;
          break;
        case 'l':
          medit_disp_class_menu(d);
          d->edit_mode = MEDIT_CLASS;
          break;
        case 'm':
          medit_disp_attack_menu(d);
          d->edit_mode = MEDIT_ATTACK_TYPE;
          break;
        case 'n':
          medit_disp_skill_menu(d);
          d->edit_mode = MEDIT_SKILLS;
          break;
        case 'o':
          send_to_char("Enter arrive text: ", CH);
          d->edit_mode = MEDIT_ARRIVE_MSG;
          break;
        case 'p':
          send_to_char("Enter leave text: ", CH);
          d->edit_mode = MEDIT_LEAVE_MSG;
          break;

        default:
          medit_disp_menu(d);
          break;
      }
      break;

    case MEDIT_EDIT_NAMELIST:
      if (MOB->player.name)
        delete [] MOB->player.name;
      MOB->player.name = str_dup(arg);
      medit_disp_menu(d);
      break;

    case MEDIT_SHORT_DESCR:
      if (MOB->player.short_descr)
        delete [] MOB->player.short_descr;
      MOB->player.short_descr = str_dup(arg);
      medit_disp_menu(d);
      break;

    case MEDIT_ARRIVE_MSG:
      if (MOB->mob_specials.arrive)
        delete [] MOB->mob_specials.arrive;
      MOB->mob_specials.arrive = str_dup(arg);
      medit_disp_menu(d);
      break;

    case MEDIT_LEAVE_MSG:
      if (MOB->mob_specials.leave)
        delete [] MOB->mob_specials.leave;
      MOB->mob_specials.leave = str_dup(arg);
      medit_disp_menu(d);
      break;

    case MEDIT_REG_DESCR:
        // you shouldn't come here
      break;

    case MEDIT_LONG_DESCR:
        // you shouldn't come here
      break;

    case MEDIT_MOB_FLAGS:
      number = atoi(arg);
      if ((number < 0) || (number > NUM_MOB_FLAGS))
        medit_disp_mobflags_menu(d);
      else {
        if (number == 0) // 0 = quit
          medit_disp_menu(d);
        else {
          if (IS_SET(MOB_FLAGS(MOB), 1 << (number - 1)))
            REMOVE_BIT(MOB_FLAGS(MOB), 1 << (number - 1));
          else
            SET_BIT(MOB_FLAGS(MOB), 1 << (number - 1));
          medit_disp_mobflags_menu(d);
        }
      }
      break;

    case MEDIT_AFF_FLAGS:
      number = atoi(arg);
      if ((number < 0) || (number > NUM_AFF_FLAGS))
        medit_disp_affected_menu(d);
      else {
        if (number == 0) // 0 = quit
          medit_disp_menu(d);
        else {
          TOGGLE_BIT(AFF_FLAGS(MOB), 1 << (number - 1));
          medit_disp_affected_menu(d);
        }
      }
      break;

    case MEDIT_ALIGNMENT:
      number = atoi(arg);
      if ((number < -1000) || (number > 1000)) {
        send_to_char("Value must range between -1000 and 1000.\r\n", CH);
        send_to_char("Enter alignment: ", CH);
      } else {
        GET_ALIGNMENT(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_NUYEN:
      number = atoi(arg);
      if ((number < 0) || (number > 999999)) {
        send_to_char("Value must range between 0 and 999999.\r\n", CH);
        send_to_char("Enter average nuyen: ", CH);
      } else {
        GET_NUYEN(MOB) = number;
        send_to_char("Enter average credstick value: ", CH);
        d->edit_mode = MEDIT_CREDSTICK;
      }
      break;

    case MEDIT_CREDSTICK:
      number = atoi(arg);
      if ((number < 0) || (number > 999999)) {
        send_to_char("Value must range between 0 and 999999.\r\n", CH);
        send_to_char("Enter average credstick value: ", CH);
      } else {
        GET_BANK(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_EXPERIENCE:
      number = atoi(arg);
      if ((number < 0) || (number > 7500)) {
        send_to_char("Value must range between 0 and 7500.\r\n", CH);
        send_to_char("Enter bonus karma points: ", CH);
      } else {
        GET_KARMA(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_SKILLS:
      switch (*arg) {
        case '0':
          medit_disp_menu(d);
          break;
        case '1':
          medit_disp_skills(d);
          send_to_char("Enter a skill (0 to quit): ", CH);
          d->edit_mode = MEDIT_SKILL1;
          break;
        case '2':
          medit_disp_skills(d);
          send_to_char("Enter a skill (0 to quit): ", CH);
          d->edit_mode = MEDIT_SKILL2;
          break;
        case '3':
          medit_disp_skills(d);
          send_to_char("Enter a skill (0 to quit): ", CH);
          d->edit_mode = MEDIT_SKILL3;
          break;
        case '4':
          medit_disp_skills(d);
          send_to_char("Enter a skill (0 to quit): ", CH);
          d->edit_mode = MEDIT_SKILL4;
          break;
        case '5':
          medit_disp_skills(d);
          send_to_char("Enter a skill (0 to quit): ", CH);
          d->edit_mode = MEDIT_SKILL5;
          break;

        default:
          medit_disp_skill_menu(d);
          break;
      }
      break; // end of MEDIT_SKILLS

    case MEDIT_SKILL1:
      number = atoi(arg);
      if ((number < 0) || (number > NUM_MOB_SKILLS - NUM_UNSKILLS)) {
        medit_disp_skills(d);
        send_to_char(CH, "Value must range between 1 and %d.\r\n", NUM_MOB_SKILLS - NUM_UNSKILLS);
        send_to_char("Enter a skill (0 to quit): ", CH);
      } else if (number == 0) { // 0 = quit
          medit_disp_skill_menu(d);
          d->edit_mode = MEDIT_SKILLS;
        } else {
            if ((number + 99) < SKILL_BACKSTAB)
              MOB->mob_specials.mob_skills[0] = number + 99; // to adjust it
            else MOB->mob_specials.mob_skills[0] = number + 99 + NUM_UNSKILLS;
            send_to_char("Enter skill level (0 to quit): ", CH);
            d->edit_mode = MEDIT_SKILL1_VAL;
        }
      break;

    case MEDIT_SKILL2:
      number = atoi(arg);
      if ((number < 0) || (number > NUM_MOB_SKILLS - NUM_UNSKILLS)) {
        medit_disp_skills(d);
        send_to_char(CH, "Value must range between 1 and %d.\r\n", NUM_MOB_SKILLS - NUM_UNSKILLS);
        send_to_char("Enter a skill (0 to quit): ", CH);
      } else if (number == 0) { // 0 = quit
          medit_disp_skill_menu(d);
          d->edit_mode = MEDIT_SKILLS;
        } else {
            if ((number + 99) < SKILL_BACKSTAB)
              MOB->mob_specials.mob_skills[2] = number + 99; // to adjust it
            else MOB->mob_specials.mob_skills[2] = number + 99 + NUM_UNSKILLS;
            send_to_char("Enter skill level (0 to quit): ", CH);
            d->edit_mode = MEDIT_SKILL2_VAL;
        }
      break;
    case MEDIT_SKILL3:
      number = atoi(arg);
      if ((number < 0) || (number > NUM_MOB_SKILLS - NUM_UNSKILLS)) {
        medit_disp_skills(d);
        send_to_char(CH, "Value must range between 1 and %d.\r\n", NUM_MOB_SKILLS - NUM_UNSKILLS);
        send_to_char("Enter a skill (0 to quit): ", CH);
      } else if (number == 0) { // 0 = quit
          medit_disp_skill_menu(d);
          d->edit_mode = MEDIT_SKILLS;
        } else {
            if ((number + 99) < SKILL_BACKSTAB)
              MOB->mob_specials.mob_skills[4] = number + 99; // to adjust it
            else MOB->mob_specials.mob_skills[4] = number + 99 + NUM_UNSKILLS;
            send_to_char("Enter skill level (0 to quit): ", CH);
            d->edit_mode = MEDIT_SKILL3_VAL;
        }
      break;
    case MEDIT_SKILL4:
      number = atoi(arg);
      if ((number < 0) || (number > NUM_MOB_SKILLS - NUM_UNSKILLS)) {
        medit_disp_skills(d);
        send_to_char(CH, "Value must range between 1 and %d.\r\n", NUM_MOB_SKILLS - NUM_UNSKILLS);
        send_to_char("Enter a skill (0 to quit): ", CH);
      } else if (number == 0) { // 0 = quit
          medit_disp_skill_menu(d);
          d->edit_mode = MEDIT_SKILLS;
        } else {
            if ((number + 99) < SKILL_BACKSTAB)
              MOB->mob_specials.mob_skills[6] = number + 99; // to adjust it
            else MOB->mob_specials.mob_skills[6] = number + 99 + NUM_UNSKILLS;
            send_to_char("Enter skill level (0 to quit): ", CH);
            d->edit_mode = MEDIT_SKILL4_VAL;
        }
      break;
    case MEDIT_SKILL5:
      number = atoi(arg);
      if ((number < 0) || (number > NUM_MOB_SKILLS - NUM_UNSKILLS)) {
        medit_disp_skills(d);
        send_to_char(CH, "Value must range between 1 and %d.\r\n", NUM_MOB_SKILLS - NUM_UNSKILLS);
        send_to_char("Enter a skill (0 to quit): ", CH);
      } else if (number == 0) { // 0 = quit
          medit_disp_skill_menu(d);
          d->edit_mode = MEDIT_SKILLS;
        } else {
            if ((number + 99) < SKILL_BACKSTAB)
              MOB->mob_specials.mob_skills[8] = number + 99; // to adjust it
            else MOB->mob_specials.mob_skills[8] = number + 99 + NUM_UNSKILLS;
            send_to_char("Enter skill level (0 to quit): ", CH);
            d->edit_mode = MEDIT_SKILL5_VAL;
        }
      break;

    case MEDIT_SKILL1_VAL:
      number = atoi(arg);
      if ((number < 0) || (number > 50)) {
        send_to_char("Skill level must be between 1 and 50.\r\n", CH);
        send_to_char("Enter skill level: ", CH);
      } else if (number == 0) {
          MOB->mob_specials.mob_skills[0] = 0;
          MOB->mob_specials.mob_skills[1] = 0;
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        } else {
          if (MOB->mob_specials.mob_skills[0] > SKILL_PERCEPTION)
            number = MIN(number, max_ability(MOB->mob_specials.mob_skills[0]));
          MOB->mob_specials.mob_skills[1] = number;
          SET_SKILL(MOB, MOB->mob_specials.mob_skills[0],
                    MOB->mob_specials.mob_skills[1]);
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        }
      break;

    case MEDIT_SKILL2_VAL:
      number = atoi(arg);
      if ((number < 0) || (number > 50)) {
        send_to_char("Skill level must be between 1 and 50.\r\n", CH);
        send_to_char("Enter skill level: ", CH);
      } else if (number == 0) {
          MOB->mob_specials.mob_skills[2] = 0;
          MOB->mob_specials.mob_skills[3] = 0;
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        } else {
          if (MOB->mob_specials.mob_skills[2] > SKILL_PERCEPTION)
            number = MIN(number, max_ability(MOB->mob_specials.mob_skills[2]));
          MOB->mob_specials.mob_skills[3] = number;
          SET_SKILL(MOB, MOB->mob_specials.mob_skills[2],
                    MOB->mob_specials.mob_skills[3]);
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        }
      break;

    case MEDIT_SKILL3_VAL:
      number = atoi(arg);
      if ((number < 0) || (number > 50)) {
        send_to_char("Skill level must be between 1 and 50.\r\n", CH);
        send_to_char("Enter skill level: ", CH);
      } else if (number == 0) {
          MOB->mob_specials.mob_skills[4] = 0;
          MOB->mob_specials.mob_skills[5] = 0;
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        } else {
          if (MOB->mob_specials.mob_skills[4] > SKILL_PERCEPTION)
            number = MIN(number, max_ability(MOB->mob_specials.mob_skills[4]));
          MOB->mob_specials.mob_skills[5] = number;
          SET_SKILL(MOB, MOB->mob_specials.mob_skills[4],
                    MOB->mob_specials.mob_skills[5]);
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        }
      break;

    case MEDIT_SKILL4_VAL:
      number = atoi(arg);
      if ((number < 0) || (number > 50)) {
        send_to_char("Skill level must be between 1 and 50.\r\n", CH);
        send_to_char("Enter skill level: ", CH);
      } else if (number == 0) {
          MOB->mob_specials.mob_skills[6] = 0;
          MOB->mob_specials.mob_skills[7] = 0;
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        } else {
          if (MOB->mob_specials.mob_skills[6] > SKILL_PERCEPTION)
            number = MIN(number, max_ability(MOB->mob_specials.mob_skills[6]));
          MOB->mob_specials.mob_skills[7] = number;
          SET_SKILL(MOB, MOB->mob_specials.mob_skills[6],
                    MOB->mob_specials.mob_skills[7]);
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        }
      break;

    case MEDIT_SKILL5_VAL:
      number = atoi(arg);
      if ((number < 0) || (number > 50)) {
        send_to_char("Skill level must be between 1 and 50.\r\n", CH);
        send_to_char("Enter skill level: ", CH);
      } else if (number == 0) {
          MOB->mob_specials.mob_skills[8] = 0;
          MOB->mob_specials.mob_skills[9] = 0;
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        } else {
          if (MOB->mob_specials.mob_skills[8] > SKILL_PERCEPTION)
            number = MIN(number, max_ability(MOB->mob_specials.mob_skills[8]));
          MOB->mob_specials.mob_skills[9] = number;
          SET_SKILL(MOB, MOB->mob_specials.mob_skills[8],
                    MOB->mob_specials.mob_skills[9]);
          d->edit_mode = MEDIT_SKILLS;
          medit_disp_skill_menu(d);
        }
      break;


    case MEDIT_ATTRIBUTES:
      if (IS_IC(MOB)) {
        switch (*arg) {
          case '0':
            medit_disp_menu(d);
            break;
          case '1':
            if (MOB->real_abils.bod)
              MOB->real_abils.bod = 0;
            else MOB->real_abils.bod = 1;
            medit_disp_att_menu(d);
            break;
          case '2':
            if (MOB->real_abils.qui)
              MOB->real_abils.qui = 0;
            else MOB->real_abils.qui = 1;
            medit_disp_att_menu(d);
            break;
          case '3':
            if (MOB->real_abils.str)
              MOB->real_abils.str = 0;
            else MOB->real_abils.str = 1;
            medit_disp_att_menu(d);
            break;
          case '4':
            if (MOB->real_abils.cha)
              MOB->real_abils.cha = 0;
            else MOB->real_abils.cha = 1;
            medit_disp_att_menu(d);
            break;
          case '5':
            if (MOB->real_abils.intel)
              MOB->real_abils.intel = 0;
            else MOB->real_abils.intel = 1;
            medit_disp_att_menu(d);
            break;
          case '6':
            if (MOB->real_abils.wil)
              MOB->real_abils.wil = 0;
            else MOB->real_abils.wil = 1;
            medit_disp_att_menu(d);
            break;
          case '7':
            if (MOB->real_abils.rea)
              MOB->real_abils.rea = 0;
            else MOB->real_abils.rea = 1;
            medit_disp_att_menu(d);
            break;
          case '8':
            if (MOB->real_abils.ess)
              MOB->real_abils.ess = 0;
            else MOB->real_abils.ess = 1;
            medit_disp_att_menu(d);
            break;
          case '9':
            if (GET_BALLISTIC(MOB))
              GET_BALLISTIC(MOB) = 0;
            else GET_BALLISTIC(MOB) = 1;
            medit_disp_att_menu(d);
            break;
          case 'a':
            if (GET_IMPACT(MOB))
              GET_IMPACT(MOB) = 0;
            else GET_IMPACT(MOB) = 1;
            medit_disp_att_menu(d);
            break;
          default:
            medit_disp_att_menu(d);
            break;
        }
      } else {
        switch (*arg) {
          case '1':
            send_to_char("Enter body attribute: ", CH);
            d->edit_mode = MEDIT_BOD;
            break;
          case '2':
            send_to_char("Enter quickness attribute: ", CH);
            d->edit_mode = MEDIT_QUI;
            break;
          case '3':
            send_to_char("Enter strength attribute: ", CH);
            d->edit_mode = MEDIT_STR;
            break;
          case '4':
            send_to_char("Enter charisma attribute: ", CH);
            d->edit_mode = MEDIT_CHA;
            break;
          case '5':
            send_to_char("Enter intelligence attribute: ", CH);
            d->edit_mode = MEDIT_INT;
            break;
          case '6':
            send_to_char("Enter willpower attribute: ", CH);
            d->edit_mode = MEDIT_WIL;
            break;
          case '7':
            send_to_char("Enter magic attribute: ", CH);
            d->edit_mode = MEDIT_MAG;
            break;
          case 'q':
          case 'Q': // back to main menu
            medit_disp_menu(d);
            break;
          default:
            medit_disp_att_menu(d);
            break;
        }
      }
      break;

    case MEDIT_BOD:
      number = atoi(arg);
      if ((number < 1) || (number > 50)) {
        send_to_char("Value must range between 1 and 50.\r\n", CH);
        send_to_char("Enter body attribute: ", CH);
      } else {
        MOB->real_abils.bod = number;
        MOB->real_abils.bod_index = number * 100;
        medit_disp_att_menu(d);
      }
      break;

    case MEDIT_QUI:
      number = atoi(arg);
      if ((number < 1) || (number > 50)) {
        send_to_char("Value must range between 1 and 50.\r\n", CH);
        send_to_char("Enter quickness attribute: ", CH);
      } else {
        MOB->real_abils.qui = number;
        MOB->real_abils.rea = (number + MOB->real_abils.intel) >> 1;
        medit_disp_att_menu(d);
      }
      break;

    case MEDIT_STR:
      number = atoi(arg);
      if ((number < 1) || (number > 50)) {
        send_to_char("Value must range between 1 and 50.\r\n", CH);
        send_to_char("Enter strength attribute: ", CH);
      } else {
        MOB->real_abils.str = number;
        medit_disp_att_menu(d);
      }
      break;

    case MEDIT_CHA:
      number = atoi(arg);
      if ((number < 1) || (number > 50)) {
        send_to_char("Value must range between 1 and 50.\r\n", CH);
        send_to_char("Enter charisma attribute: ", CH);
      } else {
        MOB->real_abils.cha = number;
        medit_disp_att_menu(d);
      }
      break;

    case MEDIT_INT:
      number = atoi(arg);
      if ((number < 1) || (number > 50)) {
        send_to_char("Value must range between 1 and 50.\r\n", CH);
        send_to_char("Enter intelligence attribute: ", CH);
      } else {
        MOB->real_abils.intel = number;
        MOB->real_abils.rea = (number + MOB->real_abils.qui) >> 1;
        medit_disp_att_menu(d);
      }
      break;

    case MEDIT_WIL:
      number = atoi(arg);
      if ((number < 1) || (number > 50)) {
        send_to_char("Value must range between 1 and 50.\r\n", CH);
        send_to_char("Enter willpower attribute: ", CH);
      } else {
        MOB->real_abils.wil = number;
        medit_disp_att_menu(d);
      }
      break;

    case MEDIT_MAG:
      number = atoi(arg);
      if ((number < 0) || (number > 50)) {
        send_to_char("Value must range between 0 and 50.\r\n", CH);
        send_to_char("Enter magic attribute: ", CH);
      } else {
        MOB->real_abils.mag = number * 100;
        medit_disp_att_menu(d);
      }
      break;

    case MEDIT_LEVEL:
      number = atoi(arg);
      if (number < 0 || (!IS_IC(MOB) && number > LVL_PRESIDENT) || (IS_IC(MOB) && number > 15)) {
        send_to_char("Invalid choice.\r\n", CH);
        send_to_char("Enter level: ", CH);
      } else {
        GET_LEVEL(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_BALLISTIC:
      number = atoi(arg);
      if (number < 0) {
        send_to_char("Value must be greater than 0.\r\n", CH);
        send_to_char("Enter ballistic armor points: ", CH);
      } else {
        GET_BALLISTIC(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_IMPACT:
      number = atoi(arg);
      if (number < 0) {
        send_to_char("Value must be greater than 0.\r\n", CH);
        send_to_char("Enter impact armor points: ", CH);
      } else {
        GET_IMPACT(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_PHYSICAL:
      number = atoi(arg);
      if ((number < 0) || (number > 10)) {
        send_to_char("Value must range between 0 and 10.\r\n", CH);
        send_to_char("Enter max physical points: ", CH);
      } else {
        GET_MAX_PHYSICAL(MOB) = number * 100;
        GET_PHYSICAL(MOB) = number * 100;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_MENTAL:
      number = atoi(arg);
      if ((number < 0) || (number > 10)) {
        send_to_char("Value must range between 0 and 10.\r\n", CH);
        send_to_char("Enter max mental points: ", CH);
      } else {
        GET_MAX_MENTAL(MOB) = number * 100;
        GET_MENTAL(MOB) = number * 100;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_WEIGHT:
      number = atoi(arg);
      if (number < 0) {
        send_to_char("Value must be greater than 0.\r\n", CH);
        send_to_char("Enter weight (in kilograms): ", CH);
      } else {
        GET_WEIGHT(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_HEIGHT:
      number = atoi(arg);
      if (number < 0) {
        send_to_char("Value must be greater than 0.\r\n", CH);
        send_to_char("Enter height (in centimeters): ", CH);
      } else {
        GET_HEIGHT(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_CLASS:
      number = atoi(arg);
      if ((number < 1) || (number > NUM_MOB_CLASSES))
        medit_disp_class_menu(d);
      else {
        GET_RACE(MOB) = (number - 1);
        medit_disp_menu(d);
        }
      break;

    case MEDIT_POSITION:
      number = atoi(arg);
      if ((number < POS_MORTALLYW) || (number > POS_STANDING)) {
        send_to_char("Invalid choice.\r\nEnter position: ", CH);
        medit_disp_pos_menu(d);
      } else {
        GET_POS(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_DEFAULT_POSITION:
      number = atoi(arg);
      if ((number < POS_MORTALLYW) || (number > POS_STANDING)) {
        send_to_char("Invalid choice.\r\nEnter default position: ", CH);
        medit_disp_pos_menu(d);
      } else {
        GET_DEFAULT_POS(MOB) = number;
        medit_disp_menu(d);
      }
      break;

    case MEDIT_GENDER:
      number = atoi(arg);
      if ((number < 0) || (number > 3)) {
        send_to_char("Invalid choice.\r\n", CH);
        medit_disp_gender_menu(d);
      } else
        if (number != 0) // 0 = quit
          GET_SEX(MOB) = (number - 1);
      medit_disp_menu(d);
      break;

    case MEDIT_ATTACK_TYPE:
      number = atoi(arg);
      if ((number < 0) || (number > NUM_ATTACK_TYPES)) {
        send_to_char("Invalid choice.\r\n", CH);
        medit_disp_attack_menu(d);
      } else
        if (number != 0) // 0 = quit
          MOB->mob_specials.attack_type = number-1 + TYPE_HIT;
      medit_disp_menu(d);
      break;

  }
}

void write_mobs_to_disk(int zone)
{
  int counter, counter2, realcounter;
  FILE *fp;
  struct char_data *mob;
  zone = real_zone(zone);

  mob = Mem->GetCh();

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

  /* start running through all mobiles in this zone */
  for (counter = zone_table[zone].number * 100; counter <= zone_table[zone].top; counter++) {
    /* write mobile to disk */
    realcounter = real_mobile(counter);
    if (realcounter >= 0) {
      *mob = mob_proto[realcounter];
      fprintf(fp, "#%d\n", GET_MOB_VNUM(mob));
      fprintf(fp, "%s~\n", mob->player.name ? mob->player.name : "unnamed mob");
      fprintf(fp, "%s~\n", mob->player.short_descr ? mob->player.short_descr : "An unnamed mob");
      fprintf(fp, "%s~\n", cleanup(buf2, mob->player.long_descr ?
                mob->player.long_descr : "An unnamed mob."));
      fprintf(fp, "%s~\n", cleanup(buf2, mob->player.description ?
                mob->player.description : "An unnamed mob is here."));
      fprintf(fp, "%s~\n", mob->mob_specials.arrive);
      fprintf(fp, "%s~\n", mob->mob_specials.leave);
      fprintf(fp, "%ld %ld %d %d %d\n", MOB_FLAGS(mob), AFF_FLAGS(mob),
                GET_ALIGNMENT(mob), GET_BANK(mob), GET_KARMA(mob));
      fprintf(fp, "%d %d %d %d %d %d 0 %d 0\n", mob->real_abils.bod,
                mob->real_abils.qui, mob->real_abils.str, mob->real_abils.cha,
                mob->real_abils.intel, mob->real_abils.wil,
                mob->real_abils.mag / 100);
      fprintf(fp, "%d %d %d %d %d %d %d %d %d %d\n",
                mob->mob_specials.mob_skills[0], mob->mob_specials.mob_skills[1],
                mob->mob_specials.mob_skills[2], mob->mob_specials.mob_skills[3],
                mob->mob_specials.mob_skills[4], mob->mob_specials.mob_skills[5],
                mob->mob_specials.mob_skills[6], mob->mob_specials.mob_skills[7],
                mob->mob_specials.mob_skills[8], mob->mob_specials.mob_skills[9]);
      fprintf(fp, "%d %d %d %d %d %d\n", GET_LEVEL(mob),
                GET_BALLISTIC(mob), GET_IMPACT(mob),
                (int)(GET_MAX_PHYSICAL(mob) / 100),
                (int)(GET_MAX_MENTAL(mob) / 100), GET_NUYEN(mob));
      fprintf(fp, "%d %d %d %d %d %d %d\n", mob->char_specials.position,
                mob->mob_specials.default_pos, mob->player.sex,
                mob->mob_specials.attack_type, mob->player.race,
                mob->player.weight, mob->player.height);
    } // close if statement
  } // close for loop

  fprintf(fp, "$~\n");
  fclose(fp);
  // we certainly don't want to go round deleting stuff prototype
  // strings and such
  Mem->ClearCh(mob);
  write_index_file("mob");
}