AwakeMUD-0.8.18B/
AwakeMUD-0.8.18B/doc/
AwakeMUD-0.8.18B/lib/
AwakeMUD-0.8.18B/lib/etc/
AwakeMUD-0.8.18B/lib/etc/pfiles/
AwakeMUD-0.8.18B/lib/misc/
AwakeMUD-0.8.18B/lib/text/
AwakeMUD-0.8.18B/lib/text/help/
AwakeMUD-0.8.18B/lib/text/wizhelp/
AwakeMUD-0.8.18B/lib/veh/
AwakeMUD-0.8.18B/lib/world/
AwakeMUD-0.8.18B/lib/world/mob/
AwakeMUD-0.8.18B/lib/world/mtx/
AwakeMUD-0.8.18B/lib/world/qst/
AwakeMUD-0.8.18B/lib/world/shp/
AwakeMUD-0.8.18B/lib/world/veh/
/* ****************************************************
* 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 "handler.h"
#include "constants.h"

void write_mobs_to_disk(int zone);

// extern vars
extern int calc_karma(struct char_data *ch, struct char_data *vict);
extern int max_ability(int i);

extern const char *position_types[];
extern const char *genders[];
extern const char *attack_types[];

// 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_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) Keywords: %s%s%s\r\n", CCCYN(CH, C_CMP),
               MOB->player.physical_text.keywords, CCNRM(CH, C_CMP));
  send_to_char(CH, "2) Name: %s%s%s\r\n", CCCYN(CH, C_CMP),
               MOB->player.physical_text.name, CCNRM(CH, C_CMP));
  send_to_char(CH, "3) Room description:\r\n%s%s%s\r\n", CCCYN(CH, C_CMP),
               MOB->player.physical_text.room_desc,CCNRM(CH, C_CMP));
  send_to_char(CH, "4) Look description:\r\n%s\r\n",
               MOB->player.physical_text.look_desc);
  MOB_FLAGS(MOB).PrintBits(buf1, MAX_STRING_LENGTH, action_bits, MOB_MAX);
  send_to_char(CH, "5) Mob Flags: %s%s%s\r\n", CCCYN(CH, C_CMP), buf1,
               CCNRM(CH, C_CMP));
  MOB->char_specials.saved.affected_by.PrintBits(buf1, MAX_STRING_LENGTH,
      affected_bits, AFF_MAX);
  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, "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));
  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), GET_REAL_BOD(MOB), CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), GET_REAL_QUI(MOB), CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), GET_REAL_STR(MOB), CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), GET_REAL_CHA(MOB), CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), GET_REAL_INT(MOB), CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), GET_REAL_WIL(MOB), CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), MOB->real_abils.mag / 100, CCNRM(CH, C_CMP),
               CCCYN(CH, C_CMP), GET_REAL_REA(MOB), 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));
  send_to_char(CH, "c) Ballistic: %s%d%s, ", CCCYN(CH, C_CMP), GET_BALLISTIC(MOB),
               CCNRM(CH, C_CMP));
  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));
  send_to_char(CH, "l) Race: ^c%s^n\r\n", pc_race_types[(int)GET_RACE(MOB)]);
  // 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->char_specials.arrive, MOB->char_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 = 1; 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);
  }
}

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),
               skills[MOB->mob_specials.mob_skills[0]].name, 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),
               skills[MOB->mob_specials.mob_skills[2]].name, 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),
               skills[MOB->mob_specials.mob_skills[4]].name, 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),
               skills[MOB->mob_specials.mob_skills[6]].name, 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),
               skills[MOB->mob_specials.mob_skills[8]].name, 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 < MOB_MAX; c += 2)
  {
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
                 c + 1, action_bits[c],
                 c + 2, c + 1 < MOB_MAX ?
                 action_bits[c + 1] : "");
  }
  MOB_FLAGS(MOB).PrintBits(buf1, MAX_STRING_LENGTH, action_bits, MOB_MAX);
  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 < AFF_MAX; c += 2)
  {
    send_to_char(CH, "%2d) %-20s %2d) %-20s\r\n",
                 c + 1, affected_bits[c],
                 c + 2, c + 1 < AFF_MAX ?
                 affected_bits[c + 1] : "");
  }
  AFF_FLAGS(MOB).PrintBits(buf1, MAX_STRING_LENGTH, affected_bits, AFF_MAX);
  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)
{
  CLS(CH);
  for (int c = 1; c < NUM_RACES; c++)
    send_to_char(CH, "%2d) %-20s\r\n", c, pc_race_types[c]);
  send_to_char(CH, "Mob class: ^c%s^n\r\n"
               "Enter mob class, 0 to quit: ", pc_race_types[(int)GET_RACE(MOB)]);
}

void medit_disp_att_menu(struct descriptor_data *d)
{

  CLS(CH);
  send_to_char(CH, "1) Body:       %s%d%s\r\n", CCCYN(CH, C_CMP), GET_REAL_BOD(MOB), CCNRM(CH, C_CMP));
  send_to_char(CH, "2) Quickness:  %s%d%s\r\n", CCCYN(CH, C_CMP), GET_REAL_QUI(MOB), CCNRM(CH, C_CMP));
  send_to_char(CH, "3) Strength:   %s%d%s\r\n", CCCYN(CH, C_CMP), GET_REAL_STR(MOB), CCNRM(CH, C_CMP));
  send_to_char(CH, "4) Charisma:   %s%d%s\r\n", CCCYN(CH, C_CMP), GET_REAL_CHA(MOB), CCNRM(CH, C_CMP));
  send_to_char(CH, "5) Intel.:     %s%d%s\r\n", CCCYN(CH, C_CMP), GET_REAL_INT(MOB), CCNRM(CH, C_CMP));
  send_to_char(CH, "6) Willpower:  %s%d%s\r\n", CCCYN(CH, C_CMP), GET_REAL_WIL(MOB), 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;
      PLR_FLAGS(d->character).RemoveBit(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
      if (!from_ip_zone(d->edit_number)) {
        sprintf(buf,"%s wrote new mob #%ld",
                GET_CHAR_NAME(d->character), d->edit_number);
        mudlog(buf, d->character, LOG_WIZLOG, TRUE);
      }
      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->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.physical_text.keywords)
          delete [] mob_proto[mob_number].player.physical_text.keywords;
        if (mob_proto[mob_number].player.title)
          delete [] mob_proto[mob_number].player.title;
        if (mob_proto[mob_number].player.physical_text.name)
          delete [] mob_proto[mob_number].player.physical_text.name;
        if (mob_proto[mob_number].player.physical_text.room_desc)
          delete [] mob_proto[mob_number].player.physical_text.room_desc;
        if (mob_proto[mob_number].player.physical_text.look_desc)
          delete [] mob_proto[mob_number].player.physical_text.look_desc;
        if (mob_proto[mob_number].char_specials.arrive)
          delete [] mob_proto[mob_number].char_specials.arrive;
        if (mob_proto[mob_number].char_specials.leave)
          delete [] mob_proto[mob_number].char_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             counter;
        int             found = FALSE;

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

        // two because you are 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_VNUM_RNUM(counter) > d->edit_number) {
              /* eureka. insert now */
              /*---------*/
              new_mob_index[counter].vnum = 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].vnum = 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 */

        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;
      PLR_FLAGS(d->character).RemoveBit(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;
      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 mobile internally?\r\n", d->character);
      break;
    }

    break;

  case MEDIT_MAIN_MENU:
    switch (*arg) {
    case 'q':
    case 'Q':
      d->edit_mode = MEDIT_CONFIRM_SAVESTRING;
      medit_parse(d, "y");
      break;
    case 'x':
    case 'X':
      d->edit_mode = MEDIT_CONFIRM_SAVESTRING;
      medit_parse(d, "n");
      break;
    case '1':
      send_to_char("Enter keywords:", CH);
      d->edit_mode = MEDIT_EDIT_NAMELIST;
      break;
    case '2':
      send_to_char("Enter name:", CH);
      d->edit_mode = MEDIT_SHORT_DESCR;
      break;
    case '3':
      send_to_char("Enter room description:", CH);
      d->edit_mode = MEDIT_REG_DESCR;
      d->str = new (char *);
      if (!d->str) {
        mudlog("Malloc failed!", NULL, LOG_SYSLOG, TRUE);
        shutdown();
      }

      *(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 look description:\r\n", CH);
      d->edit_mode = MEDIT_LONG_DESCR;
      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':
      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 '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':
      send_to_char("Enter ballistic armor points: ", CH);
      d->edit_mode = MEDIT_BALLISTIC;
      break;
    case 'd':
      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.physical_text.keywords)
      delete [] MOB->player.physical_text.keywords;
    MOB->player.physical_text.keywords = str_dup(arg);
    medit_disp_menu(d);
    break;

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

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

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

  case MEDIT_REG_DESCR:
  case MEDIT_LONG_DESCR:
    break;

  case MEDIT_MOB_FLAGS:
    number = atoi(arg);
    if ((number < 0) || (number > MOB_MAX))
      medit_disp_mobflags_menu(d);
    else {
      if (number == 0) // 0 = quit
        medit_disp_menu(d);
      else {
        MOB_FLAGS(MOB).ToggleBit(number-1);
        medit_disp_mobflags_menu(d);
      }
    }
    break;

  case MEDIT_AFF_FLAGS:
    number = atoi(arg);
    if ((number < 0) || (number > AFF_MAX))
      medit_disp_affected_menu(d);
    else {
      if (number == 0) // 0 = quit
        medit_disp_menu(d);
      else {
        AFF_FLAGS(MOB).ToggleBit(number - 1);
        medit_disp_affected_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 {
      int karma;
      if (number > (karma=calc_karma(NULL, MOB))) {
        send_to_char("Bonus karma may not be higher than actual karma.  Lowering.\r\n", CH);
        number = karma;
      }
      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 > MAX_SKILLS)) {
      medit_disp_skills(d);
      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);
    } else if (number == 0) { // 0 = quit
      medit_disp_skill_menu(d);
      d->edit_mode = MEDIT_SKILLS;
    } else {
      SET_SKILL(MOB, MOB->mob_specials.mob_skills[0], 0)
      MOB->mob_specials.mob_skills[0] = number; // to adjust it
      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 > MAX_SKILLS)) {
      medit_disp_skills(d);
      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);
    } else if (number == 0) { // 0 = quit
      medit_disp_skill_menu(d);
      d->edit_mode = MEDIT_SKILLS;
    } else {
      SET_SKILL(MOB, MOB->mob_specials.mob_skills[2], 0)
      MOB->mob_specials.mob_skills[2] = number; // to adjust it
      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 > MAX_SKILLS)) {
      medit_disp_skills(d);
      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);
    } else if (number == 0) { // 0 = quit
      medit_disp_skill_menu(d);
      d->edit_mode = MEDIT_SKILLS;
    } else {
      SET_SKILL(MOB, MOB->mob_specials.mob_skills[4], 0)
      MOB->mob_specials.mob_skills[4] = number; // to adjust it
      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 > MAX_SKILLS)) {
      medit_disp_skills(d);
      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);
    } else if (number == 0) { // 0 = quit
      medit_disp_skill_menu(d);
      d->edit_mode = MEDIT_SKILLS;
    } else {
      SET_SKILL(MOB, MOB->mob_specials.mob_skills[6], 0)
      MOB->mob_specials.mob_skills[6] = number; // to adjust it
      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 > MAX_SKILLS)) {
      medit_disp_skills(d);
      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);
    } else if (number == 0) { // 0 = quit
      medit_disp_skill_menu(d);
      d->edit_mode = MEDIT_SKILLS;
    } else {
      SET_SKILL(MOB, MOB->mob_specials.mob_skills[8], 0)
      MOB->mob_specials.mob_skills[8] = number; // to adjust it
      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 {
      MOB->mob_specials.mob_skills[1] = number;
      GET_SKILL(MOB, MOB->mob_specials.mob_skills[0]) = MOB->mob_specials.mob_skills[1];
      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 {
      MOB->mob_specials.mob_skills[3] = number;
      GET_SKILL(MOB, MOB->mob_specials.mob_skills[2]) = MOB->mob_specials.mob_skills[3];
      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 {
      MOB->mob_specials.mob_skills[5] = number;
      GET_SKILL(MOB, MOB->mob_specials.mob_skills[4]) = MOB->mob_specials.mob_skills[5];
      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 {
      MOB->mob_specials.mob_skills[7] = number;
      GET_SKILL(MOB, MOB->mob_specials.mob_skills[6]) = MOB->mob_specials.mob_skills[7];
      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 {
      MOB->mob_specials.mob_skills[9] = number;
      GET_SKILL(MOB, MOB->mob_specials.mob_skills[8]) = MOB->mob_specials.mob_skills[9];
      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:
    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 {
      GET_REAL_BOD(MOB) = 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 {
      GET_REAL_QUI(MOB) = number;
      GET_REAL_REA(MOB) = (number + GET_REAL_INT(MOB)) >> 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 {
      GET_REAL_STR(MOB) = 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 {
      GET_REAL_CHA(MOB) = 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 {
      GET_REAL_INT(MOB) = number;
      GET_REAL_REA(MOB) = (number + GET_REAL_QUI(MOB)) >> 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 {
      GET_REAL_WIL(MOB) = 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) {
      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_RACES))
      medit_disp_class_menu(d);
    else {
      GET_RACE(MOB) = number;
      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, realcounter;
  FILE *fp;
  struct char_data *mob;
  zone = real_zone(zone);
  int i;

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

  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;
      if (!strcmp("an unfinished mob", GET_NAME(mob)))
        continue;
      fprintf(fp, "#%ld\n", GET_MOB_VNUM(mob));

      fprintf(fp,
              "Keywords:\t%s\n"
              "Name:\t%s\n"
              "RoomDesc:$\n%s\n~\n",
              mob->player.physical_text.keywords?
              mob->player.physical_text.keywords : "mob unnamed",
              mob->player.physical_text.name?
              mob->player.physical_text.name : "An unnamed mob",
              cleanup(buf2, mob->player.physical_text.room_desc?
                      mob->player.physical_text.room_desc : "An unnamed mob is here."));
      fprintf(fp, "LookDesc:$\n%s~\n",
              cleanup(buf2,
                      mob->player.physical_text.look_desc?
                      mob->player.physical_text.look_desc
                      : "An unnamed mob is here."));

      if (mob->char_specials.arrive)
        fprintf(fp, "ArriveMsg:\t%s\n", mob->char_specials.arrive);
      if (mob->char_specials.leave)
        fprintf(fp, "LeaveMsg:\t%s\n", mob->char_specials.leave);

      fprintf(fp,
              "MobFlags:\t%s\n"
              "AffFlags:\t%s\n"
              "Race:\t%s\n"
              "Gender:\t%s\n",
              MOB_FLAGS(mob).ToString(),
              AFF_FLAGS(mob).ToString(),
              pc_race_types[(int)mob->player.race],
              genders[(int)mob->player.sex]);

      if (mob->char_specials.position != POS_STANDING)
        fprintf(fp, "Position:\t%s\n",
                position_types[(int)mob->char_specials.position]);
      if (mob->mob_specials.default_pos)
        fprintf(fp, "DefaultPos:\t%s\n",
                position_types[(int)mob->mob_specials.default_pos]);

      if (mob->mob_specials.attack_type != TYPE_HIT)
        fprintf(fp, "AttackType:\t%s\n",
                attack_types[mob->mob_specials.attack_type-TYPE_HIT]);

      fprintf(fp,
              "[ATTRIBUTES]\n"
              "\tBod:\t%d\n"
              "\tQui:\t%d\n"
              "\tStr:\t%d\n"
              "\tCha:\t%d\n"
              "\tInt:\t%d\n"
              "\tWil:\t%d\n"
              "\tMag:\t%d\n",
              GET_REAL_BOD(mob), GET_REAL_QUI(mob), GET_REAL_STR(mob),
              GET_REAL_CHA(mob), GET_REAL_INT(mob), GET_REAL_WIL(mob),
              mob->real_abils.mag / 100);
      fprintf(fp,
              "[POINTS]\n"
              "\tHeight:\t%d\n"
              "\tWeight:\t%d\n",
              mob->player.height, mob->player.weight);

      if (GET_LEVEL(mob) > 0)
        fprintf(fp, "\tLevel:\t%d\n", GET_LEVEL(mob));
      if (int(GET_MAX_PHYSICAL(mob) / 100) != 10)
        fprintf(fp, "\tMaxPhys:\t%d\n", int(GET_MAX_PHYSICAL(mob) / 100));
      if (int(GET_MAX_MENTAL(mob) / 100) != 10)
        fprintf(fp, "\tMaxMent:\t%d\n", int(GET_MAX_MENTAL(mob) / 100));
      if (GET_BALLISTIC(mob) > 0)
        fprintf(fp, "\tBallistic:\t%d\n", GET_BALLISTIC(mob));
      if (GET_IMPACT(mob) > 0)
        fprintf(fp, "\tImpact:\t%d\n", GET_IMPACT(mob));
      if (GET_NUYEN(mob) > 0)
        fprintf(fp, "\tCash:\t%d\n", GET_NUYEN(mob));
      if (GET_BANK(mob) > 0)
        fprintf(fp, "\tBank:\t%d\n", GET_BANK(mob));
      if (GET_KARMA(mob) > 0)
        fprintf(fp, "\tKarma:\t%d\n", GET_KARMA(mob));
      fprintf(fp, "[SKILLS]\n");

      for (i = 0; i <= 8; i = i +2)
        if (mob->mob_specials.mob_skills[i])
          fprintf(fp, "\t%s:\t%d\n", skills[mob->mob_specials.mob_skills[i]].name,
                  mob->mob_specials.mob_skills[i+1]);



      fprintf(fp, "BREAK\n");
    } // close if statement
  } // close for loop

  fprintf(fp, "END\n");
  fclose(fp);

  write_index_file("mob");
}