legend/
legend/area/
legend/player/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/
/***************************************************************************
 *  God Wars Mud copyright (C) 1994, 1995, 1996 by Richard Woolcock        *
 *  									   *
 *  Legend of Chrystancia copyright (C) 1999, 2000, 2001 by Matthew Little *
 *  This mud is NOT to be copied in whole or in part, or to be run without *
 *  the permission of Matthew Little. Nobody else has permission to        *
 *  authorise the use of this code.                                        *
 ***************************************************************************/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include "merc.h"
#include "olc.h"
#include "recycle.h"
#if !defined(macintosh)
extern int _filbuf args ((FILE *));
#endif

bool MAKE_WARNED;
/*
 * Globals.
 */
EMAIL_DATA *            email_list;
EMAIL_DATA *            emailing_to;

HELP_DATA *help_first;
HELP_DATA *help_last;

SHOP_DATA *shop_first;
SHOP_DATA *shop_last;

KINGDOM_DATA *king_first;
KINGDOM_DATA *king_last;
KINGDOM_DATA *kingdom_free;
MEMBER_DATA *member_free;
DIPLOMACY_DATA *diplomacy_free;
MEMBER_DATA *next;
MEMBER_DATA *prev;
CHAR_DATA *char_free;
EXTRA_DESCR_DATA *extra_descr_free;
NOTE_DATA *note_free;
OBJ_DATA *obj_free;
PC_DATA *pcdata_free;
CONFIG_DATA *config_info;

COMBAT_CONFIG_DATA	*CombatConfigData = NULL;

char bug_buf[2 * MAX_INPUT_LENGTH];
CHAR_DATA *char_list;
char *help_lowcredits;
char *help_greeting;
char *help_greeting1;
char *help_greeting2;
char *help_greeting3;
char *help_greeting4;
char *help_greeting5;
char *help_greeting6;
char log_buf[2 * MAX_INPUT_LENGTH];
KILL_DATA kill_table[MAX_LEVEL];
OBJ_DATA *object_list;
TIME_INFO_DATA time_info;
WEATHER_DATA weather_info;
AUCTION_DATA auction_info;
TRIVIA_DATA trivia_info;
sh_int gsn_backstab;
sh_int gsn_hide;
sh_int gsn_peek;
sh_int gsn_pick_lock;
sh_int gsn_sneak;
sh_int gsn_steal;
sh_int gsn_inferno;
sh_int gsn_blinky;
sh_int gsn_spiderform;
sh_int gsn_garotte;
sh_int gsn_disarm;
sh_int gsn_fastdraw;
sh_int gsn_berserk;
sh_int gsn_punch;
sh_int gsn_elbow;
sh_int gsn_spiket;
sh_int gsn_venomt;
sh_int gsn_shards;
sh_int gsn_magma;
sh_int gsn_headbutt;
sh_int gsn_quills;
sh_int gsn_fangs;
sh_int gsn_buffet;
sh_int gsn_tail;
sh_int gsn_joust;
sh_int gsn_shiroken;
sh_int gsn_sweep;
sh_int gsn_knee;
sh_int gsn_kick;
sh_int gsn_circle;
sh_int                  gsn_phenom;
sh_int gsn_rfangs;
sh_int gsn_thrustkick;
sh_int gsn_spinkick;
sh_int gsn_backfist;
sh_int gsn_elbow;
sh_int gsn_shinkick;
sh_int gsn_palmstrike;
sh_int gsn_lightningkick;
sh_int gsn_tornadokick;
sh_int gsn_jumpkick;
sh_int gsn_spinkick;
sh_int gsn_monksweep;
sh_int gsn_talon;
sh_int gsn_hurl;
sh_int gsn_rescue;
sh_int gsn_track;
sh_int gsn_polymorph;
sh_int gsn_web;
sh_int gsn_drowfire;
sh_int gsn_totalblind;		/* Monk Power - Loki */
sh_int gsn_godbless;		/* Monk Power - Loki */
sh_int gsn_llothbless;		/* drow bless -Sage */
sh_int gsn_blindness;
sh_int gsn_charm_person;
sh_int gsn_curse;
sh_int gsn_invis;
sh_int gsn_mass_invis;
sh_int gsn_poison;
sh_int gsn_sleep;

sh_int gsn_darkness;
sh_int gsn_paradox;
sh_int gsn_dart_shiroken;
sh_int gsn_spit;
sh_int gsn_waspt;
sh_int gsn_entrails;
sh_int gsn_gbreath;
sh_int gsn_bodyspikes;
sh_int gsn_shred;
sh_int gsn_darktendrils;
sh_int gsn_tendrils;
sh_int gsn_bladespin;

sh_int SLOWNS;

long long int           mobs_killed;

/*
 * Locals.
 */
MOB_INDEX_DATA *mob_index_hash[MAX_KEY_HASH];
OBJ_INDEX_DATA *obj_index_hash[MAX_KEY_HASH];
ROOM_INDEX_DATA *room_index_hash[MAX_KEY_HASH];
char *string_hash[MAX_KEY_HASH];

AREA_DATA *area_first;
AREA_DATA *area_last;

//LEADER_DATA *   leader[6];
char *string_space;
char *top_string;
char str_empty[1];

// For Crashes
int debug_stage;
int debug_counter = 0;
int debug_last_room;
char *debug_last_character;
char *debug_last_command;
char *debug_procedure[20];
bool debug_dont_run;

// Crashes ^^

int top_affect;
int top_area;
int top_rt;
int top_ed;
int top_exit;
int top_help;
int top_mob_index;
int top_obj_index;
int top_reset;
int top_room;
int top_shop;

int top_vnum_room;		/* OLC */
int top_vnum_mob;		/* OLC */
int top_vnum_obj;		/* OLC */

int                     mobile_count = 0;
int                     object_count = 0;
/*
 * Memory management.
 * Increase MAX_STRING if you have too.
 * Tune the others only if you understand what you're doing.
 */
#define			MAX_STRING	3145728
//#define                       MAX_PERM_BLOCK  262144
#define                 MAX_PERM_BLOCK  131072
#define			MAX_MEM_LIST	11

void *rgFreeList[MAX_MEM_LIST];
const int rgSizeList[MAX_MEM_LIST] = {
   16, 32, 64, 128, 256, 1024, 2048, 4096, 8192, 16384, 32768 - 64
};

int nAllocString;
int sAllocString;
int nAllocPerm;
int sAllocPerm;

/*
 * Semi-locals.
 */
bool fBootDb;
FILE *fpArea;
char strArea[MAX_INPUT_LENGTH];

/*
 * Local booting procedures.
 */
void init_mm args ((void));

void load_area args ((FILE * fp));
void load_helps args ((FILE * fp));
void load_mobiles args ((FILE * fp));
void load_objects args ((FILE * fp));
void load_resets args ((FILE * fp));
void load_rooms args ((FILE * fp));
void load_shops args ((FILE * fp));
void load_specials args ((FILE * fp));
void load_notes args ((void));
void load_artifacts args ((void));
void fix_exits args ((void));
void update_migratory_exits args ((void));
void load_changes args( (void) );
void load_quotes args( (void) );
void reset_area args ((AREA_DATA * pArea));

void new_load_area args ((FILE * fp));	/* OLC */

void copyover_recover args ((void));
void load_login args ((void));
void read_votes (void);
void    load_wizlist    args( ( void ) );

/*
 * Big mama top level function.
 */
void boot_db (bool fCopyOver)
{

   /*
    * Init some data space stuff.
    */
   {
      if ((string_space = calloc (1, MAX_STRING)) == NULL)
      {
	 bug ("Boot_db: can't alloc %d string space.", MAX_STRING);
	 exit (1);

      }
      top_string = string_space;
      fBootDb = TRUE;
      SLOWNS = TRUE;
   }

   /*
    * Init random number generator.
    */
   {
      init_mm ();
   }
   initialise_email_list();  
        emailing_to = NULL;
   first_cache = NULL;
   last_cache = NULL;
   load_dns();
   auction_info.item = NULL;
   auction_info.owner = NULL;
   auction_info.high_bidder = NULL;
   auction_info.current_bid = 0;
   auction_info.status = 0;
   auction_info.qps_held = 0;
   load_hiscores ();
   
   load_leaderboard ();
   load_socials ();

   init_wizconfig ();        /* Initialize WizConfig                 */

   /*
    * Set time and weather.
    */

   {
      extern int pulse_weather;
      long lhour, lday, lleap, lyear;
      bool leap;

      time_info.full700 = 0;
      time_info.part182 = 0;
      time_info.part018 = 0;
      time_info.full400 = 0;

      pulse_weather = ((PULSE_WEATHER / PULSE_PER_SECOND) - (current_time % (PULSE_WEATHER / PULSE_PER_SECOND))) * PULSE_PER_SECOND;
      lhour = current_time / (PULSE_WEATHER / PULSE_PER_SECOND);
      time_info.hour = lhour % 24;

      switch (time_info.hour)
      {
         case 4:
            weather_info.sunlight = SUN_DARK;
            weather_info.moonlight = MOON_SET;
            weather_info.time_of_day = NIGHT;
            break;
         case 5:
            weather_info.sunlight = SUN_DARK;
            weather_info.moonlight = MOON_DOWN;
            weather_info.time_of_day = MORNING;
            break;
         case 6:
         case 7:
         case 8:
         case 9:
            weather_info.sunlight = SUN_RISE;
            weather_info.moonlight = MOON_DOWN;
            weather_info.time_of_day = MORNING;
            break;
         case 10:
         case 11:
         case 12:
         case 13:
         case 14:
         case 15:
         case 16:
            weather_info.sunlight = SUN_RISE;
            weather_info.moonlight = MOON_DOWN;
            weather_info.time_of_day = DAY;
            break;
         case 17:
         case 18:
            weather_info.sunlight = SUN_RISE;
            weather_info.moonlight = MOON_DOWN;
            weather_info.time_of_day = EVENING;
            break;
         case 19:
            weather_info.sunlight = SUN_SET;
            weather_info.moonlight = MOON_DOWN;
            weather_info.time_of_day = EVENING;
            break;
         case 20:
            weather_info.sunlight = SUN_DARK;
            weather_info.moonlight = MOON_DOWN;
            weather_info.time_of_day = EVENING;
            break;
         case 21:
            weather_info.sunlight = SUN_DARK;
            weather_info.moonlight = MOON_RISE;
            weather_info.time_of_day = NIGHT;
            break;
         case 22:
         case 23:
         case 24:
         case 0:
         case 1:
         case 2:
         case 3:
            weather_info.sunlight = SUN_DARK;
            weather_info.moonlight = MOON_UP;
            weather_info.time_of_day = NIGHT;
            break;
      }

      lday = lhour / 24;
      lday += 297000;
      time_info.daylist = lday;

      time_info.minutelist = (((lday * 24) + time_info.hour) * 60) + (59 - (pulse_weather / 60)) + 22300;

      if ((time_info.minutelist % (36145440/850)) < (36145440/850/8))
         weather_info.moonphase = MOON_NEW;
      else if ((time_info.minutelist % (36145440/850)) < (36145440/850/8*2))
         weather_info.moonphase = MOON_CRESCENT;
      else if ((time_info.minutelist % (36145440/850)) < (36145440/850/8*3))
         weather_info.moonphase = MOON_HALF;
      else if ((time_info.minutelist % (36145440/850)) < (36145440/850/8*4))
         weather_info.moonphase = MOON_GIBBOUS;
      else if ((time_info.minutelist % (36145440/850)) < (36145440/850/8*5))
         weather_info.moonphase = MOON_FULL;
      else if ((time_info.minutelist % (36145440/850)) < (36145440/850/8*6))
         weather_info.moonphase = MOON_GIBBOUS + MOON_WANING;
      else if ((time_info.minutelist % (36145440/850)) < (36145440/850/8*7))
         weather_info.moonphase = MOON_HALF + MOON_WANING;
      else if ((time_info.minutelist % (36145440/850)) < (36145440/850))
         weather_info.moonphase = MOON_CRESCENT + MOON_WANING;

      if (lday >= 255675)
      {
	 time_info.full700++;
	 lday -= 255675;
	 if (lday >= 255675)
	 {
	    time_info.full700++;
	    lday -= 255675;
	    if (lday >= 66707)
	    {
	       time_info.part182++;
	       lday -= 66707;
	       lday += 10;	// To make up for October 5-14th
	       if (lday >= 6287)
	       {
		  time_info.part018++;
		  lday -= 6287;
		  while (lday >= 146097)
		  {
		     time_info.full400++;
		     lday -= 146097;
		  }
	       }
	    }
	 }
      }
      lleap = 366;
      leap = TRUE;
      lyear = 0;
      if (time_info.part182 == 0)
      {
	 while (lday + 1 > lleap)
	 {
	    lyear++;
	    if (leap)
	    {
	       lday -= lleap;
	       leap = FALSE;
	       lleap = 365;
	    }
	    else
	    {
	       lday -= lleap;
	       if ((lyear + 1) == (((lyear + 1) * 4) / ((lyear % 4) + 1)))
	       {
		  leap = TRUE;
		  lleap = 366;
	       }
	    }
	 }
      }
      else
      {
	 while (lday + 1 > lleap)
	 {
	    lyear++;
	    if (leap)
	    {
	       lday -= lleap;
	       leap = FALSE;
	       lleap = 365;
	    }
	    else
	    {
	       lday -= lleap;
	       if ((lyear + 1) != (((lyear + 1) * 100) / ((lyear % 100) + 1))
		   && (lyear + 1) == (((lyear + 1) * 4) / ((lyear % 4) + 1)))
	       {
		  leap = TRUE;
		  lleap = 366;
	       }
	    }
	 }
      }

      if (leap)
      {
	 if (lday <= 30)
	    time_info.month = 0;
	 else if (lday <= 59)
	    time_info.month = 1;
	 else if (lday <= 90)
	    time_info.month = 2;
	 else if (lday <= 120)
	    time_info.month = 3;
	 else if (lday <= 151)
	    time_info.month = 4;
	 else if (lday <= 181)
	    time_info.month = 5;
	 else if (lday <= 212)
	    time_info.month = 6;
	 else if (lday <= 243)
	    time_info.month = 7;
	 else if (lday <= 273)
	    time_info.month = 8;
	 else if (lday <= 304)
	    time_info.month = 9;
	 else if (lday <= 334)
	    time_info.month = 10;
	 else if (lday <= 365)
	    time_info.month = 11;

	 switch (time_info.month)
	 {
	 default:
	    time_info.day = lday % 30;
	    break;
	 case 0:
	    time_info.day = lday - 0;
	    break;
	 case 1:
	    time_info.day = lday - 31;
	    break;
	 case 2:
	    time_info.day = lday - 60;
	    break;
	 case 3:
	    time_info.day = lday - 91;
	    break;
	 case 4:
	    time_info.day = lday - 121;
	    break;
	 case 5:
	    time_info.day = lday - 152;
	    break;
	 case 6:
	    time_info.day = lday - 182;
	    break;
	 case 7:
	    time_info.day = lday - 213;
	    break;
	 case 8:
	    time_info.day = lday - 244;
	    break;
	 case 9:
	    time_info.day = lday - 274;
	    break;
	 case 10:
	    time_info.day = lday - 305;
	    break;
	 case 11:
	    time_info.day = lday - 335;
	    break;
	 }
      }
      else
      {
	 if (lday <= 30)
	    time_info.month = 0;
	 else if (lday <= 58)
	    time_info.month = 1;
	 else if (lday <= 89)
	    time_info.month = 2;
	 else if (lday <= 119)
	    time_info.month = 3;
	 else if (lday <= 150)
	    time_info.month = 4;
	 else if (lday <= 180)
	    time_info.month = 5;
	 else if (lday <= 211)
	    time_info.month = 6;
	 else if (lday <= 242)
	    time_info.month = 7;
	 else if (lday <= 272)
	    time_info.month = 8;
	 else if (lday <= 303)
	    time_info.month = 9;
	 else if (lday <= 333)
	    time_info.month = 10;
	 else if (lday <= 364)
	    time_info.month = 11;

	 switch (time_info.month)
	 {
	 default:
	    time_info.day = lday % 30;
	    break;
	 case 0:
	    time_info.day = lday;
	    break;
	 case 1:
	    time_info.day = lday - 31;
	    break;
	 case 2:
	    time_info.day = lday - 59;
	    break;
	 case 3:
	    time_info.day = lday - 90;
	    break;
	 case 4:
	    time_info.day = lday - 120;
	    break;
	 case 5:
	    time_info.day = lday - 151;
	    break;
	 case 6:
	    time_info.day = lday - 181;
	    break;
	 case 7:
	    time_info.day = lday - 212;
	    break;
	 case 8:
	    time_info.day = lday - 243;
	    break;
	 case 9:
	    time_info.day = lday - 273;
	    break;
	 case 10:
	    time_info.day = lday - 304;
	    break;
	 case 11:
	    time_info.day = lday - 334;
	    break;
	 }
      }

      time_info.year =
	 (time_info.full700 * 700) + (time_info.part182 * 182) +
	 (time_info.part018 * 18) + (time_info.full400 * 400) + lyear + 1;

      if (time_info.hour < 5)
	 weather_info.sunlight = SUN_DARK;
      else if (time_info.hour < 6)
	 weather_info.sunlight = SUN_RISE;
      else if (time_info.hour < 19)
	 weather_info.sunlight = SUN_LIGHT;
      else if (time_info.hour < 20)
	 weather_info.sunlight = SUN_SET;
      else
	 weather_info.sunlight = SUN_DARK;

        switch (time_info.month)
        {
          case 0:
          case 1:
              weather_info.season = WINTER;
              break;

          case 2:
              if (time_info.day < 22) weather_info.season = WINTER;
              else weather_info.season = SPRING;
              break;

          case 3:
          case 4:
              weather_info.season = SPRING;
              break;

          case 5:
              if (time_info.day < 22) weather_info.season = SPRING;
              else weather_info.season = SUMMER;
              break;

          case 6:
          case 7:
              weather_info.season = SUMMER;
              break;

          case 8:
              if (time_info.day < 22) weather_info.season = SUMMER;
              else weather_info.season = AUTUMN;
              break;

          case 9:
          case 10:
              weather_info.season = AUTUMN;
              break;

          case 11:
              if (time_info.day < 22) weather_info.season = AUTUMN;
              else weather_info.season = WINTER;
              break;

          default:
              break;
        }

      weather_info.change = 0;
      weather_info.mmhg = 960;
      if (time_info.month >= 3 && time_info.month <= 9)
	 weather_info.mmhg += number_range (1, 80);
      else
	 weather_info.mmhg += number_range (1, 50);

      if (weather_info.mmhg <= 980)
	 weather_info.sky = SKY_LIGHTNING;
      else if (weather_info.mmhg <= 1000)
	 weather_info.sky = SKY_RAINING;
      else if (weather_info.mmhg <= 1020)
	 weather_info.sky = SKY_CLOUDY;
      else
	 weather_info.sky = SKY_CLOUDLESS;
   }

   /*
    * Assign gsn's for skills which have them.
    */
   {
      int sn;

      for (sn = 0; sn < MAX_SKILL; sn++)
      {
	 if (skill_table[sn].pgsn != NULL)
	    *skill_table[sn].pgsn = sn;
      }
   }
   /*
    * Read in all the area files.
    */
   {
      FILE *fpList;

      if ((fpList = fopen (AREA_LIST, "r")) == NULL)
      {
	 perror (AREA_LIST);
	 exit (1);

      }

      for (;;)
      {
	 strcpy (strArea, fread_word (fpList));
	 if (strArea[0] == '$')
	    break;

	 if (strArea[0] == '-')
	 {
	    fpArea = stdin;
	 }
	 else
	 {
	    if ((fpArea = fopen (strArea, "r")) == NULL)
	    {
	       perror (strArea);
	       exit (1);

	    }
	 }
	 for (;;)
	 {
	    char *word;

	    if (fread_letter (fpArea) != '#')
	    {
	       bug ("Boot_db: # not found.", 0);
	       exit (1);

	    }

	    word = fread_word (fpArea);

	    if (word[0] == '$')
	       break;
	    else if (!str_cmp (word, "AREA"))
	       load_area (fpArea);
	    else if (!str_cmp (word, "HELPS"))
	       load_helps (fpArea);
	    else if (!str_cmp (word, "MOBILES"))
               load_mobiles (fpArea);
	    else if (!str_cmp (word, "OBJECTS"))
	       load_objects (fpArea);
	    else if (!str_cmp (word, "RESETS"))
	       load_resets (fpArea);
	    else if (!str_cmp (word, "ROOMS"))
	       load_rooms (fpArea);
	    else if (!str_cmp (word, "SHOPS"))
	       load_shops (fpArea);
	    else if (!str_cmp (word, "SPECIALS"))
	       load_specials (fpArea);
	    else if (!str_cmp (word, "AREADATA"))
	       new_load_area (fpArea);
	    else
	    {
	       bug ("Boot_db: bad section name.", 0);
	       exit (1);

	    }
	 }

	 if (fpArea != stdin)
	    fclose (fpArea);
	 fpArea = NULL;
      }
      fclose (fpList);
   }
   /*
    * Fix up exits.
    * Declare db booting over.
    * Reset all areas once.
    * Load up the notes file.
    */
   fpReserve = fopen (NULL_FILE, "r");

   {
      fix_exits ();		/* Fix up areas       */
      fBootDb = FALSE;		/* Declare db booting over    */
      //update_migratory_exits ();	// Do the migration!  Serenity
      area_update ();		/* Reset all areas once     */
      load_mudinfo ();		/* Load up Mudinfo      */
      //min_kingdom_members = 20000;
      //load_kingdoms ();		/* Load up all kingdoms     */
      load_clans();
      load_retired();
      load_polls ();		/* load all active polls    */
      load_boards ();		/* Load all boards      */
      save_notes ();		/* Archive the boards if needed   */
      load_wizlist();
      load_disabled ();		/* Load up disabled commands    */
      load_login ();		/* Load in login failure attempts       */
      load_wizconfig ();	/* Load in WizConfig settings           */
      load_coreinfo ();
      read_shitlist ();
      clearwar ();   
      load_bans ();   
      load_pieces (); 
      load_immortals ();
      load_changes ();
      load_quotes (); 
      atexit (save_pieces);
      atexit (save_artitable);
      init_artitable ();  
      load_todo ();
      //load_todo2 (); 
      load_artitable ();
      if (WizConfig->artifacts == ARTIFACTS_OAKA || WizConfig->artifacts == ARTIFACTS_HUNT) load_oaka (FALSE);
      load_lostfound ();
      bug ("Finished Loading Data Files", 0);


      arena = FIGHT_CLEAR;	/* Make sure arena is clear   */
      MAKE_WARNED = FALSE;	// Set this to false to start with -- Serenity
   }
   if (fCopyOver)
      copyover_recover ();	/* Recover from copyover    */

   /* 
    *  Rotain's Clan Table Read Settings
    */


   return;
}

/*
 * Load in the areas with out the need to 
 * reboot (WARNING HIGHLY UNSTABLE
 */
void load_area_file (FILE * fpArea);
void load_area_name (char *area);

void do_unfoldarea (CHAR_DATA * ch, char *argument)
{
   if (argument[0] == '\0')
   {
      stc ("Unfold which area?(WARNING! HIGHLY FUCKING UNSTABLE!\n\r", ch);
      return;
   }
   fBootDb = 1;
   strcpy (strArea, argument);
   strcat (strArea, ".are");
   load_area_name (argument);
   fBootDb = 0;
   strArea[0] = '$';
   fix_exits ();
   do_asave (ch, "list");
   do_asave (ch, "world");

}

void load_area_name (char *area)
{
   char buf[MSL];
   FILE *fp;

   sprintf (buf, "../area/%s.are", area);

   if ((fp = fopen (buf, "r")) == NULL)
   {
      bugf ("Area %s Not Found.", buf);
      return;
   }

   load_area_file (fp);
   fclose (fp);

   sprintf (buf, "Area(%s) Loaded", area);

   log_string (buf, NULL);
}

void load_area_file (FILE * fpArea)
{
   for (;;)
   {
      char *word;

      if (fread_letter (fpArea) != '#')
      {
	 bug ("Boot_db: # not found.", 0);
      }

      word = fread_word (fpArea);

      if (word[0] == '$')
	 break;
      else if (!str_cmp (word, "AREA"))
	 load_area (fpArea);
      else if (!str_cmp (word, "HELPS"))
	 load_helps (fpArea);
      else if (!str_cmp (word, "MOBILES"))
	 load_mobiles (fpArea);
      else if (!str_cmp (word, "OBJECTS"))
	 load_objects (fpArea);
      else if (!str_cmp (word, "RESETS"))
	 load_resets (fpArea);
      else if (!str_cmp (word, "ROOMS"))
	 load_rooms (fpArea);
      else if (!str_cmp (word, "SHOPS"))
	 load_shops (fpArea);
      else if (!str_cmp (word, "SPECIALS"))
	 load_specials (fpArea);
      else if (!str_cmp (word, "AREADATA"))	/* OLC */
	 new_load_area (fpArea);
      else
      {
	 bug ("Boot_db: bad section name.", 0);
      }
   }
}

void load_oaka (bool dead)
{
   CHAR_DATA *pMob;
   OBJ_DATA *obj;
   int i;

   if (WizConfig->artifacts != ARTIFACTS_OAKA && WizConfig->artifacts != ARTIFACTS_HUNT) return;

   pMob = create_mobile (get_mob_index (25));
   for (i = 0; i <= MAX_ARTI; i++)
   {
      if (!strcmp((IS_NPC (pMob) ? pMob->short_descr : pMob->name),arti_table[i].player))
      {
         if (!dead) obj = create_object (get_obj_index (arti_table[i].vnum), 0);
         else
         {
            int random;

            free_string (arti_table[i].player);
            arti_table[i].player = str_dup ("No One");
            free_string (arti_table[i].where);
            arti_table[i].where = str_dup ("Never");
            obj = NULL;
            while (obj == NULL)
            {
               random = number_range(0, MAX_ARTI);
               if (strcmp (arti_table[random].player, "No One"))
                  continue;
               obj = create_object (get_obj_index (arti_table[random].vnum), 0);
            }
         }
         obj_to_char (obj, pMob);
      }
   }
   if (dead) update_artitable(pMob);
   move_oaka (pMob);
   return;
}

void move_oaka (CHAR_DATA * ch)
{
   ROOM_INDEX_DATA *room = NULL;

   while (!room)
   {
          int BAD_ROOM = -1;
          while ( BAD_ROOM != 0 )
          {
              BAD_ROOM = -1;
              if (!(room = get_room_index (number_range (1, 33700)))) continue;

              if ( room->room_flags && BAD_ROOM < 0 )
              {
                         if (IS_SET( room->room_flags, ROOM_GOD ) )                       BAD_ROOM = 1;
                    else if (IS_SET( room->room_flags, ROOM_KINGDOM ) )                   BAD_ROOM = 1;
                    else if (IS_SET( room->room_flags, ROOM_PRIVATE ) )                   BAD_ROOM = 1;
                    else if (IS_SET( room->room_flags, ROOM_SOLITARY ) )                  BAD_ROOM = 1;
                    else if (IS_SET( room->room_flags, ROOM_CCHAMBER ) )                  BAD_ROOM = 1;
                    else if (IS_SET( room->room_flags, ROOM_COLOUR_ROOM ) )               BAD_ROOM = 1;
              }
              if ( room->area && BAD_ROOM < 0 )
              {
                         if ( room->area->aflags )
                         {
                                if (IS_SET( room->area->aflags, AFLAG_HQ ) )                   BAD_ROOM = 1;
                           else if (IS_SET( room->area->aflags, AFLAG_ARENA ) )                BAD_ROOM = 1;
                         }
                         if ( room->area->area_flags )
                         {
                                if (IS_SET( room->area->area_flags, AREA_UNLINKED ) )          BAD_ROOM = 1;
                           else if (IS_SET( room->area->area_flags, AREA_NO_NOMADS ) )         BAD_ROOM = 1;
                         }
              }
              if (BAD_ROOM < 0) BAD_ROOM = 0;
          }
   }
   if (ch->in_room) char_from_room (ch);
   char_to_room (ch, room);
   act ("You wander into the room and relax.", ch, NULL, NULL,
      TO_CHAR);
   act ("$n wanders into the room and seems to relax.", ch, NULL, NULL,
      TO_ROOM);
   do_say(ch, "Hmm...  This seems like a nice place to wait a bit.");
}

void load_artifacts (void)
{
   CHAR_DATA *pMob;
   OBJ_DATA *obj;

   /* Gaia */
   pMob = create_mobile (get_mob_index (32201));
   char_to_room (pMob, get_room_index (9200));
   obj = create_object (get_obj_index (29516), 0);
   obj_to_char (obj, pMob);

   /* Zombie Lord - Chaos Axe */
   pMob = create_mobile (get_mob_index (30011));
   char_to_room (pMob, get_room_index (3001));
   obj = create_object (get_obj_index (29503), 0);
   obj_to_char (obj, pMob);

   /* The Master Wizard - Visor of Vision */
   pMob = create_mobile (get_mob_index (32205));
   char_to_room (pMob, get_room_index (1498));
   obj = create_object (get_obj_index (29515), 0);
   obj_to_char (obj, pMob);

   /* Satan - Sword of Darkness */
   pMob = create_mobile (get_mob_index (32204));
   char_to_room (pMob, get_room_index (2551));
   obj = create_object (get_obj_index (29512), 0);
   obj_to_char (obj, pMob);

   /* Lloth the Spider Queen - Bracelet of Lloth */
   pMob = create_mobile (get_mob_index (32202));
   char_to_room (pMob, get_room_index (5143));
   obj = create_object (get_obj_index (29518), 0);
   obj_to_char (obj, pMob);

   /* Allah - Torc of Continual Restoration */
   pMob = create_mobile (get_mob_index (32203));
   char_to_room (pMob, get_room_index (951));
   obj = create_object (get_obj_index (29504), 0);
   obj_to_char (obj, pMob);

   /* Caine - The Armour of Resistance */
   pMob = create_mobile (get_mob_index (32200));
   char_to_room (pMob, get_room_index (3475));
   obj = create_object (get_obj_index (29514), 0);
   obj_to_char (obj, pMob);

   return;
}

void do_loadarti (CHAR_DATA * ch, char *arguments)
{
   distribute_artifacts ();
   stc ("Artifacts Distributed\n\r", ch);

}

/*
 * Snarf an 'area' header line.
 */
void load_area (FILE * fp)
{
   AREA_DATA *pArea;

   pArea = alloc_perm (sizeof (*pArea));
   pArea->reset_first = NULL;
   pArea->reset_last = NULL;
   pArea->name = fread_string (fp);
   pArea->area_flags = AREA_LOADING;	/* OLC */
   pArea->security = 1;		/* OLC */
   pArea->builders = str_dup ("None");	/* OLC */
   pArea->lvnum = 0;		/* OLC */
   pArea->uvnum = 0;		/* OLC */
   pArea->vnum = 0;		/* OLC */
   pArea->filename = str_dup (strArea);	/* OLC */
   pArea->age = 15;
   pArea->nplayer = 0;
   pArea->nimmortal = 0;
   pArea->x = -1;
   pArea->y = -1;
   pArea->start = 0;
   pArea->aflags = 0;
   pArea->owned = 0;
   pArea->creator = str_dup ("Anon");
   if (area_first == NULL)
      area_first = pArea;
   if (area_last != NULL)
   {
      area_last->next = pArea;
      REMOVE_BIT (area_last->area_flags, AREA_LOADING);	/* OLC */
   }
   area_last = pArea;
   pArea->next = NULL;

   top_area++;
   return;
}

/* OLC
 * I left the Repop field here because I though that newbie programmers
like
 * myself would want to set up something small to begin with.  To get the
 * repop field to work, you will want to go through the code and add it to
 * memory recycling routines in BUILD.C and also in the UPDATE.C file to
 * display the message.  Have fun.  Erase this comment when you are done
 * trying this.  Mail me jdinkel@mines.colorado.edu if you have trouble.
 */

/*
 * Snarf an 'area' header line.   Check this format.  MUCH better.  Add fields
 * too.
 *
 * #AREAFILE
 * Name   { All } Locke    Newbie School~
 * Repop  A teacher pops in the room and says, 'Repop coming!'~
 * Recall 3001
 * End
 */

void new_load_area (FILE * fp)
{
   AREA_DATA *pArea;
   char *word;
   bool fMatch;

   pArea = alloc_perm (sizeof (*pArea));
   pArea->age = 15;
   pArea->nplayer = 0;
   pArea->nimmortal = 0;
   pArea->filename = str_dup (strArea);
   pArea->vnum = top_area;
   pArea->name = str_dup ("New Area");
   pArea->creator = str_dup ("No One");
   pArea->builders = str_dup ("");
/*    pArea->repop        = str_dup( "Tock.\n\r" ); */
   pArea->security = 1;
   pArea->lvnum = 0;
   pArea->uvnum = 0;
   pArea->area_flags = 0;

   for (;;)
   {
      word = feof (fp) ? "End" : fread_word (fp);
      fMatch = FALSE;

      switch (UPPER (word[0]))
      {
      case 'A':
	 KEY ("Aflags", pArea->aflags, fread_number (fp));
	 break;
      case 'C':
	 SKEY ("Creator", pArea->creator);
	 break;
      case 'N':
	 SKEY ("Name", pArea->name);
	 break;
      case 'S':
	 KEY ("Security", pArea->security, fread_number (fp));
	 break;
      case 'V':
	 if (!str_cmp (word, "VNUMs"))
	 {
	    pArea->lvnum = fread_number (fp);
	    pArea->uvnum = fread_number (fp);
	 }
	 break;
      case 'E':
	 if (!str_cmp (word, "End"))
	 {
	    fMatch = TRUE;
	    if (area_first == NULL)
	       area_first = pArea;
	    if (area_last != NULL)
	       area_last->next = pArea;
	    area_last = pArea;
	    pArea->next = NULL;
	    top_area++;
	    return;
	 }
	 break;
      case 'B':
	 SKEY ("Builders", pArea->builders);
	 break;
      case 'O':
	 KEY ("Owned", pArea->owned, fread_number (fp));
	 break;
      case 'R':
/*            SKEY( "Repop",  pArea->repop ); */
	 if (!str_cmp (word, "Reset"))
	 {
	    fread_to_eol (fp);
	    fMatch = TRUE;
	 }
	 break;
      }
   }

}

/*
 * Sets vnum range for area using OLC protection features.
 */
void assign_area_vnum (int vnum)
{
   if (area_last->lvnum == 0 || area_last->uvnum == 0)
      area_last->lvnum = area_last->uvnum = vnum;
   if (vnum != URANGE (area_last->lvnum, vnum, area_last->uvnum))
   {
      if (vnum < area_last->lvnum)
	 area_last->lvnum = vnum;
      else
	 area_last->uvnum = vnum;
   }
   return;
}

/*
 * Snarf a help section.
 */
void load_helps (FILE * fp)
{
   HELP_DATA *pHelp;

   for (;;)
   {
      pHelp = alloc_perm (sizeof (*pHelp));
      pHelp->level = fread_number (fp);
      pHelp->keyword = fread_string (fp);
      if (pHelp->keyword[0] == '$')
	 break;
      pHelp->text = fread_string (fp);

      if (!str_cmp (pHelp->keyword, "greeting"))
	 help_greeting = pHelp->text;
      else if (!str_cmp (pHelp->keyword, "ogreeting1"))
	 help_greeting1 = pHelp->text;
      else if (!str_cmp (pHelp->keyword, "ogreeting2"))
	 help_greeting2 = pHelp->text;
      else if (!str_cmp (pHelp->keyword, "ogreeting3"))
	 help_greeting3 = pHelp->text;
      else if (!str_cmp (pHelp->keyword, "ogreeting4"))
	 help_greeting4 = pHelp->text;
      else if (!str_cmp (pHelp->keyword, "ogreeting5"))
	 help_greeting5 = pHelp->text;
      else if (!str_cmp (pHelp->keyword, "ogreeting6"))
	 help_greeting6 = pHelp->text;
      else if (!str_cmp (pHelp->keyword, "lowcredits"))
	 help_lowcredits = pHelp->text;

      if (help_first == NULL)
	 help_first = pHelp;
      if (help_last != NULL)
	 help_last->next = pHelp;

      help_last = pHelp;
      pHelp->next = NULL;
      top_help++;
   }
   return;

}

/*
 * Snarf a mob section.
 */
void load_mobiles (FILE * fp)
{
   MOB_INDEX_DATA *pMobIndex;

   if (area_last == NULL)	/* OLC */
   {
      bug ("Load_mobiles: no #AREA seen yet.", 0);
      exit (1);

   }

   for (;;)
   {
      int vnum;
      char letter;
      int iHash;

      letter = fread_letter (fp);
      if (letter != '#')
      {
	 bug ("Load_mobiles: # not found.", 0);
	 exit (1);

      }

      vnum = fread_number (fp);
      if (vnum == 0)
	 break;

      fBootDb = FALSE;
      if (get_mob_index (vnum) != NULL)
      {
	 bug ("Load_mobiles: vnum %d duplicated.", vnum);
	 exit (1);

      }
      fBootDb = TRUE;

      pMobIndex = alloc_perm (sizeof (*pMobIndex));
      pMobIndex->vnum = vnum;
      pMobIndex->area = area_last;	/* OLC */
      pMobIndex->player_name = fread_string (fp);
      pMobIndex->short_descr = fread_string (fp);
      pMobIndex->long_descr = fread_string (fp);
      pMobIndex->description = fread_string (fp);

      pMobIndex->long_descr[0] = UPPER (pMobIndex->long_descr[0]);
      pMobIndex->description[0] = UPPER (pMobIndex->description[0]);

      pMobIndex->act = fread_number (fp) | ACT_IS_NPC;
      pMobIndex->affected_by = fread_number (fp);
      pMobIndex->itemaffect = 0;
      pMobIndex->pShop = NULL;
      pMobIndex->alignment = fread_number (fp);
      letter = fread_letter (fp);
      pMobIndex->level = number_fuzzy (fread_number (fp));

      /*
       * The unused stuff is for imps who want to use the old-style
       * stats-in-files method.
       */
      pMobIndex->hitroll = fread_number (fp);	/* Unused */
      pMobIndex->ac = fread_number (fp);	/* Unused */
      pMobIndex->hitnodice = fread_number (fp);	/* Unused */
      /* 'd'    */ fread_letter (fp);
      /* Unused */
      pMobIndex->hitsizedice = fread_number (fp);	/* Unused */
      /* '+'    */ fread_letter (fp);
      /* Unused */
      pMobIndex->hitplus = fread_number (fp);	/* Unused */
      pMobIndex->damnodice = fread_number (fp);	/* Unused */
      /* 'd'    */ fread_letter (fp);
      /* Unused */
      pMobIndex->damsizedice = fread_number (fp);	/* Unused */
      /* '+'    */ fread_letter (fp);
      /* Unused */
      pMobIndex->damplus = fread_number (fp);	/* Unused */
      pMobIndex->gold = fread_number (fp);	/* Unused */
      /* xp can't be used! */ fread_number (fp);
      /* Unused */
      /* position */ fread_number (fp);
      /* Unused */
      /* start pos  */ fread_number (fp);
      /* Unused */

      /*
       * Back to meaningful values.
       */
      pMobIndex->sex = fread_number (fp);

      if (letter != 'S')
      {
	 bug ("Load_mobiles: vnum %d non-S.", vnum);
	 exit (1);

      }

      iHash = vnum % MAX_KEY_HASH;
      pMobIndex->next = mob_index_hash[iHash];
      mob_index_hash[iHash] = pMobIndex;
      top_mob_index++;
      top_vnum_mob = top_vnum_mob < vnum ? vnum : top_vnum_mob;	/* OLC */
      assign_area_vnum (vnum);	/* OLC */
      kill_table[URANGE (0, pMobIndex->level, MAX_LEVEL - 1)].number++;
   }

   return;
}

/*
 * Snarf an obj section.
 */
void load_objects (FILE * fp)
{
   OBJ_INDEX_DATA *pObjIndex;

   if (area_last == NULL)	/* OLC */
   {
      bug ("Load_objects: no #AREA seen yet.", 0);
      exit (1);
   }

   for (;;)
   {
      int vnum;
      char letter;
      int iHash;

      letter = fread_letter (fp);
      if (letter != '#')
      {
	 bug ("Load_objects: # not found.", 0);
	 exit (1);

      }

      vnum = fread_number (fp);
      if (vnum == 0)
	 break;

      fBootDb = FALSE;
      if (get_obj_index (vnum) != NULL)
      {
	 bug ("Load_objects: vnum %d duplicated.", vnum);
	 exit (1);

      }
      fBootDb = TRUE;

      pObjIndex = alloc_perm (sizeof (*pObjIndex));
      pObjIndex->vnum = vnum;
      pObjIndex->area = area_last;	/* OLC */
      pObjIndex->name = fread_string (fp);
      pObjIndex->short_descr = fread_string (fp);
      pObjIndex->description = fread_string (fp);
      /* Action description */ fread_string (fp);

      pObjIndex->short_descr[0] = LOWER (pObjIndex->short_descr[0]);
      pObjIndex->description[0] = UPPER (pObjIndex->description[0]);

      pObjIndex->item_type = fread_number (fp);
      pObjIndex->extra_flags = fread_number (fp);
      pObjIndex->wear_flags = fread_number (fp);
      pObjIndex->value[0] = fread_number (fp);
      pObjIndex->value[1] = fread_number (fp);
      pObjIndex->value[2] = fread_number (fp);
      pObjIndex->value[3] = fread_number (fp);
      pObjIndex->weight = fread_number (fp);
      pObjIndex->cost = fread_number (fp);	/* Unused */
      pObjIndex->affected = NULL;
      pObjIndex->extra_descr = NULL;
      pObjIndex->chpoweron = NULL;
      pObjIndex->chpoweroff = NULL;
      pObjIndex->chpoweruse = NULL;
      pObjIndex->victpoweron = NULL;
      pObjIndex->victpoweroff = NULL;
      pObjIndex->victpoweruse = NULL;
      pObjIndex->spectype = 0;
      pObjIndex->specpower = 0;
      /* Cost per day */ fread_number (fp);
/*
	if ( pObjIndex->item_type == ITEM_POTION )
	    SET_BIT(pObjIndex->extra_flags, ITEM_NODROP);
*/
      for (;;)
      {
	 char letter;

	 letter = fread_letter (fp);

	 if (letter == 'A')
	 {
	    AFFECT_DATA *paf;

	    paf = alloc_perm (sizeof (*paf));
	    paf->type = -1;
	    paf->duration = -1;
	    paf->location = fread_number (fp);
	    paf->modifier = fread_number (fp);
	    paf->bitvector = 0;
	    paf->next = pObjIndex->affected;
	    pObjIndex->affected = paf;
	    top_affect++;
	 }

	 else if (letter == 'E')
	 {
	    EXTRA_DESCR_DATA *ed;

	    ed = alloc_perm (sizeof (*ed));
	    ed->keyword = fread_string (fp);
	    ed->description = fread_string (fp);
	    ed->next = pObjIndex->extra_descr;
	    pObjIndex->extra_descr = ed;
	    top_ed++;
	 }

	 else if (letter == 'Q')
	 {
	    pObjIndex->chpoweron = fread_string (fp);
	    pObjIndex->chpoweroff = fread_string (fp);
	    pObjIndex->chpoweruse = fread_string (fp);
	    pObjIndex->victpoweron = fread_string (fp);
	    pObjIndex->victpoweroff = fread_string (fp);
	    pObjIndex->victpoweruse = fread_string (fp);
	    pObjIndex->spectype = fread_number (fp);
	    pObjIndex->specpower = fread_number (fp);
	 }

	 else
	 {
	    ungetc (letter, fp);
	    break;
	 }
      }

      /*
       * Translate spell "slot numbers" to internal "skill numbers."
       */
      switch (pObjIndex->item_type)
      {
      case ITEM_PILL:
      case ITEM_POTION:
      case ITEM_SCROLL:
	 pObjIndex->value[1] = slot_lookup (pObjIndex->value[1]);
	 pObjIndex->value[2] = slot_lookup (pObjIndex->value[2]);
	 pObjIndex->value[3] = slot_lookup (pObjIndex->value[3]);
	 break;

      case ITEM_STAFF:
      case ITEM_WAND:
	 pObjIndex->value[3] = slot_lookup (pObjIndex->value[3]);
	 break;
      }

      iHash = vnum % MAX_KEY_HASH;
      pObjIndex->next = obj_index_hash[iHash];
      obj_index_hash[iHash] = pObjIndex;
      top_obj_index++;
      top_vnum_obj = top_vnum_obj < vnum ? vnum : top_vnum_obj;	/* OLC */
      assign_area_vnum (vnum);	/* OLC */
   }

   return;
}

void load_resets (FILE * fp)	/* OLC */
{
   RESET_DATA *pReset = NULL;
   int mvn = 0;

   if (area_last == NULL)
   {
      bug ("Load_resets: no #AREA seen yet.", 0);
      exit (1);

   }

   for (;;)
   {

      EXIT_DATA *pexit;

      ROOM_INDEX_DATA *pRoomIndex;
      char letter;
      int arg1, arg2, arg3;

      if ((letter = fread_letter (fp)) == 'S')
	 break;

      if (letter == '*')
      {
	 fread_to_eol (fp);
	 continue;
      }

      /* if_flag */ fread_number (fp);
      arg1 = fread_number (fp);
      arg2 = fread_number (fp);
      arg3 = (letter == 'G' || letter == 'R') ? 0 : fread_number (fp);
      fread_to_eol (fp);

      /*
       * Validate parameters.
       * We're calling the index functions for the side effect.
       */
      switch (letter)
      {
      default:
	 bug ("Load_resets: bad command '%c'.", letter);
	 exit (1);

	 break;

      case 'M':
	 get_mob_index (arg1);
	 get_room_index (arg3);

	 pReset = alloc_perm (sizeof (*pReset));
	 pReset->arg1 = arg1;
	 pReset->arg2 = arg2;
	 pReset->arg3 = arg3;
	 pReset->command = letter;
	 mvn = arg3;

	 break;

      case 'O':
	 get_obj_index (arg1);
	 get_room_index (arg3);

	 pReset = alloc_perm (sizeof (*pReset));
	 pReset->arg1 = arg1;
	 pReset->arg2 = arg2;
	 pReset->arg3 = arg3;
	 pReset->command = letter;

	 break;

      case 'P':
	 get_obj_index (arg1);
	 get_obj_index (arg3);

	 pReset = alloc_perm (sizeof (*pReset));
	 pReset->arg1 = arg1;
	 pReset->arg2 = arg2;
	 pReset->arg3 = arg3;
	 pReset->command = letter;

	 break;

      case 'G':
      case 'E':
	 get_room_index (mvn);
	 get_obj_index (arg1);

	 pReset = alloc_perm (sizeof (*pReset));
	 pReset->arg1 = arg1;
	 pReset->arg2 = arg2;
	 pReset->arg3 = arg3;
	 pReset->command = letter;

	 break;

      case 'D':
/* kavirp */
	 pRoomIndex = get_room_index (arg1);

	 if (arg2 < 0
	     || arg2 > MAX_DIR || (pexit = pRoomIndex->exit[arg2]) == NULL)
	 {
	    bug ("Load_resets: 'D': exit %d not door.", arg2);
	    exit (1);
	 }
	 pexit->exit_info = arg3;

/*
 switch ( arg3 )
            {
                default:
                    bug( "Load_resets: 'D': bad 'locks': %d." , arg3);
                case 0:
                        SET_BIT( pexit->rs_flags, EX_ISDOOR);
                        SET_BIT( pexit->exit_info, EX_ISDOOR);
                        break;
                case 1: SET_BIT( pexit->rs_flags, EX_CLOSED | EX_ISDOOR );
                        SET_BIT( pexit->exit_info, EX_CLOSED | EX_ISDOOR ); break;
                case 2: SET_BIT( pexit->rs_flags, EX_CLOSED | EX_LOCKED | EX_ISDOOR );
                        SET_BIT( pexit->exit_info, EX_CLOSED | EX_LOCKED | EX_ISDOOR); break;
            }
*/
	 break;

      case 'R':
	 pRoomIndex = get_room_index (arg1);

	 if (arg2 < 0 || arg2 > MAX_DIR)
	 {
	    bug ("Load_resets: 'R': bad exit %d.", arg2);
	    exit (1);

	 }

	 pReset = alloc_perm (sizeof (*pReset));
	 pReset->arg1 = arg1;
	 pReset->arg2 = arg2;
	 pReset->arg3 = arg3;
	 pReset->command = letter;

	 break;
      }

      if (pReset)
      {
	 if (area_last->reset_first == NULL)
	    area_last->reset_first = pReset;
	 if (area_last->reset_last != NULL)
	    area_last->reset_last->next = pReset;

	 area_last->reset_last = pReset;
	 pReset->next = NULL;
	 top_reset++;
      }
   }

   return;
}

void load_rooms (FILE * fp)
{
   ROOM_INDEX_DATA *pRoomIndex;

   if (area_last == NULL)
   {
      bug ("Load_resets: no #AREA seen yet.", 0);	/* OLC */
      exit (1);

   }

   for (;;)
   {
      int vnum;
      char letter;
      int door;
      int iHash;
      static int prev_top_area = -1;

      letter = fread_letter (fp);
      if (letter != '#')
      {
	 bug ("Load_rooms: # not found.", 0);
	 exit (1);

      }

      vnum = fread_number (fp);
      if (vnum == 0)
	 break;

      if (prev_top_area != top_area)
      {
	 prev_top_area = top_area;
	 area_last->start = vnum;
      }

      fBootDb = FALSE;
      if (get_room_index (vnum) != NULL)
      {
	 bug ("Load_rooms: vnum %d duplicated.", vnum);
	 exit (1);

      }
      fBootDb = TRUE;

      pRoomIndex = alloc_perm (sizeof (*pRoomIndex));
      pRoomIndex->people = NULL;
      pRoomIndex->contents = NULL;
      pRoomIndex->to_obj = NULL;
      pRoomIndex->extra_descr = NULL;
      pRoomIndex->area = area_last;
      pRoomIndex->vnum = vnum;
      pRoomIndex->name = fread_string (fp);
      pRoomIndex->description = fread_string (fp);
      /* Area number */ fread_number (fp);
      pRoomIndex->room_flags = fread_number (fp);
      pRoomIndex->added_flags = 0;
      pRoomIndex->sector_type = fread_number (fp);
      pRoomIndex->light = 0;
      pRoomIndex->blood = 0;
      pRoomIndex->passed = 0;
      pRoomIndex->roomtext = NULL;
      pRoomIndex->wood = 0;
      pRoomIndex->build = 0;
      pRoomIndex->ground = 0;
      pRoomIndex->x = -1;
      pRoomIndex->y = -1;
      pRoomIndex->room = 0;

      for (door = 0; door <= 5; door++)
      {
	 pRoomIndex->track[door] = str_dup ("");
	 pRoomIndex->track_dir[door] = 0;
      }
      for (door = 0; door <= 5; door++)
	 pRoomIndex->exit[door] = NULL;

      for (;;)
      {
	 letter = fread_letter (fp);

	 if (letter == 'S')
	    break;

/*
			if (letter == 'D')
			{
				EXIT_DATA *pexit;
				int locks;

				door = fread_number(fp);
				if (door < 0 || door > 5)
				{
					bug("Fread_rooms: vnum %d has bad door number.", vnum);
					exit(1);

				}

				pexit = alloc_perm(sizeof(*pexit));
				pexit->description = fread_string(fp);
				pexit->keyword = fread_string(fp);
				pexit->exit_info = 0;
				pexit->rs_flags = 0;		
				locks = fread_number(fp);
				pexit->key = fread_number(fp);
				pexit->vnum = fread_number(fp);

				switch (locks)
				{
					case 1:
						pexit->exit_info = EX_ISDOOR;
						break;
					case 2:
						pexit->exit_info = EX_ISDOOR | EX_PICKPROOF;
						break;
				}

				pRoomIndex->exit[door] = pexit;
				top_exit++;
			}
*/
	 if (letter == 'D')
	 {
	    EXIT_DATA *pexit;
	    int locks;

	    door = fread_number (fp);
	    if (door < 0 || door > 5)
	    {
	       bug ("Fread_rooms: vnum %d has bad door number.", vnum);
	       exit (1);
	    }

	    pexit = alloc_perm (sizeof (*pexit));
	    pexit->description = fread_string (fp);
	    pexit->keyword = fread_string (fp);
	    pexit->exit_info = 0;
	    pexit->rs_flags = 0;
	    locks = fread_number (fp);
	    pexit->key = fread_number (fp);
	    pexit->vnum = fread_number (fp);
	    /*   going to go to a proper flag loading system...
	       switch ( locks )  
	       {
	       case 1: pexit->exit_info = EX_ISDOOR;
	       pexit->rs_flags  = EX_ISDOOR;
	       break;
	       case 2: pexit->exit_info = EX_ISDOOR | EX_PICKPROOF;
	       pexit->rs_flags  = EX_ISDOOR | EX_PICKPROOF;
	       break;
	       case 3: pexit->exit_info = EX_ISDOOR;
	       pexit->rs_flags  = EX_ISDOOR;
	       break;
	       case 4: pexit->exit_info = EX_ISDOOR| EX_PICKPROOF;
	       pexit->rs_flags  = EX_ISDOOR| EX_PICKPROOF;
	       break;

	       }
	     */

	    pexit->exit_info = locks;
	    pexit->rs_flags = locks;

	    pRoomIndex->exit[door] = pexit;
	    top_exit++;
	 }
	 else if (letter == 'E')
	 {
	    EXTRA_DESCR_DATA *ed;

	    ed = alloc_perm (sizeof (*ed));
	    ed->keyword = fread_string (fp);
	    ed->description = fread_string (fp);
	    ed->next = pRoomIndex->extra_descr;
	    pRoomIndex->extra_descr = ed;
	    top_ed++;
	 }
	 else if (letter == 'T')
	 {
	    ROOMTEXT_DATA *rt;

	    rt = alloc_perm (sizeof (*rt));
	    rt->input = fread_string (fp);
	    rt->output = fread_string (fp);
	    rt->choutput = fread_string (fp);
	    rt->name = fread_string (fp);
	    rt->type = fread_number (fp);
	    rt->power = fread_number (fp);
	    rt->mob = fread_number (fp);
	    rt->next = pRoomIndex->roomtext;
	    pRoomIndex->roomtext = rt;
	    top_rt++;
	 }
	 else if (letter == 'V')
	 {
	    pRoomIndex->x = fread_number (fp);
	    pRoomIndex->y = fread_number (fp);
	    area_last->x = pRoomIndex->x;
	    area_last->y = pRoomIndex->y;
	 }
	 else
	 {
	    bug ("Load_rooms: vnum %d has flag not 'DES'.", vnum);
	    exit (1);

	 }
      }

      iHash = vnum % MAX_KEY_HASH;
      pRoomIndex->next = room_index_hash[iHash];
      room_index_hash[iHash] = pRoomIndex;
      //put_area_vnum( vnum );
      top_room++;
      top_vnum_room = top_vnum_room < vnum ? vnum : top_vnum_room;	/*OLC */
      assign_area_vnum (vnum);	/* OLC */
   }

   return;
}

/*
 * Snarf a shop section.
 */
void load_shops (FILE * fp)
{
   SHOP_DATA *pShop;

   for (;;)
   {
      MOB_INDEX_DATA *pMobIndex;
      int iTrade;

      pShop = alloc_perm (sizeof (*pShop));
      pShop->keeper = fread_number (fp);
      if (pShop->keeper == 0)
	 break;
      for (iTrade = 0; iTrade < MAX_TRADE; iTrade++)
	 pShop->buy_type[iTrade] = fread_number (fp);
      pShop->profit_buy = fread_number (fp);
      pShop->profit_sell = fread_number (fp);
      pShop->open_hour = fread_number (fp);
      pShop->close_hour = fread_number (fp);
      fread_to_eol (fp);
      pMobIndex = get_mob_index (pShop->keeper);
      pMobIndex->pShop = pShop;

      if (shop_first == NULL)
	 shop_first = pShop;
      if (shop_last != NULL)
	 shop_last->next = pShop;

      shop_last = pShop;
      pShop->next = NULL;
      top_shop++;
   }

   return;
}

void load_login (void)
{
   FILE *fp;
   TRUST_DATA *ploginlast;

   fflush (fpReserve);
   fclose (fpReserve);

   if ((fp = fopen (LOGIN_FILE, "r")) == NULL)
   {
      fpReserve = fopen (NULL_FILE, "r");
      return;
   }

   ploginlast = NULL;

   for (;;)
   {
      TRUST_DATA *plogin;
      char letter;

      do
      {
	 letter = getc (fp);
	 if (feof (fp))
	 {
	    fflush (fp);
	    fclose (fp);
	    fpReserve = fopen (NULL_FILE, "r");
	    return;
	 }
      }
      while (isspace (letter));
      ungetc (letter, fp);

      if (login_free == NULL)
      {
	 plogin = alloc_perm (sizeof (*plogin));
      }
      else
      {
	 plogin = login_free;
	 login_free = login_free->next;
      }

      plogin->name = fread_string (fp);

      if (number_of_args (plogin->name) > 1)
	 break;

      plogin->level = fread_number (fp);

      plogin->next = NULL;

      if (login_list == NULL)
	 login_list = plogin;
      else
	 ploginlast->next = plogin;

      ploginlast = plogin;
   }

   strcpy (strArea, LOGIN_FILE);
   fpArea = fp;
   bug ("Load_login: too many arguments", 0);
   exit (1);

   return;
}

void load_specials (FILE * fp)
{
   for (;;)
   {
      MOB_INDEX_DATA *pMobIndex;
      char letter;

      switch (letter = fread_letter (fp))
      {
      default:
	 bug ("Load_specials: letter '%c' not *MS.", letter);
	 exit (1);

      case 'S':
	 return;

      case '*':
	 break;

      case 'M':
	 pMobIndex = get_mob_index (fread_number (fp));
	 pMobIndex->spec_name = str_dup (fread_word (fp));	/* OLC */
	 pMobIndex->spec_fun = spec_lookup (pMobIndex->spec_name);	/* OLC */
	 if (pMobIndex->spec_fun == 0)
	 {
	    bug ("Load_specials: 'M': vnum %d.", pMobIndex->vnum);
	    exit (1);

	 }
	 break;
      }

      fread_to_eol (fp);
   }
}

/*
 * Translate all room exits from virtual to real.
 * Has to be done after all rooms are read in.
 * Check for bad reverse exits.
 */
void fix_exits (void)
{
   extern const int rev_dir[];

//    extern const sh_int rev_dir [];
   char buf[MAX_STRING_LENGTH];
   ROOM_INDEX_DATA *pRoomIndex;
   ROOM_INDEX_DATA *to_room;
   EXIT_DATA *pexit;
   EXIT_DATA *pexit_rev;
   int iHash;
   int door;

   for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
   {
      for (pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL;
	   pRoomIndex = pRoomIndex->next)
      {
	 bool fexit;

	 fexit = FALSE;
	 for (door = 0; door <= 5; door++)
	 {
	    if ((pexit = pRoomIndex->exit[door]) != NULL)
	    {
	       fexit = TRUE;
	       if (pexit->vnum <= 0)
		  pexit->to_room = NULL;
	       else
		  pexit->to_room = get_room_index (pexit->vnum);
	    }
	 }

	 if (!fexit)
	    SET_BIT (pRoomIndex->room_flags, ROOM_NO_MOB);
      }
   }

   for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
   {
      for (pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL;
	   pRoomIndex = pRoomIndex->next)
      {
	 for (door = 0; door <= 5; door++)
	 {
	    if ((pexit = pRoomIndex->exit[door]) != NULL
		&& (to_room = pexit->to_room) != NULL
		&& (pexit_rev = to_room->exit[rev_dir[door]]) != NULL
		&& pexit_rev->to_room != pRoomIndex)
	    {
	       sprintf (buf, "Fix_exits: %d:%d -> %d:%d -> %d.",
			pRoomIndex->vnum, door, to_room->vnum, rev_dir[door],
			(pexit_rev->to_room ==
			 NULL) ? 0 : pexit_rev->to_room->vnum);
/*		    bug( buf, 0 ); */
	    }
	 }
      }
   }

   return;
}

/*
 * Repopulate areas periodically.
 */
void area_update (void)
{
   AREA_DATA *pArea;
   char buf[MSL];

   for (pArea = area_first; pArea != NULL; pArea = pArea->next)
   {
      CHAR_DATA *pch;

      if (++pArea->age < 3)
	 continue;

      /*
       * Check for PC's.
       */
      if (pArea->nplayer > 0 && pArea->age == 15 - 1)
      {
	 for (pch = char_list; pch != NULL; pch = pch->next)
	 {
	    if (!IS_NPC (pch) && IS_AWAKE (pch) && pch->in_room != NULL
		&& !IS_SET (pch->more, MORE_MESSAGE)
		&& pch->in_room->area == pArea)
	       switch (number_range (1, 4))
	       {
	       default:

		  send_to_char
		     ("#yYou hear an agonised scream in the distance.#n\n\r",
		      pch);
		  break;
	       case 1:
		  send_to_char
		     ("#gYou taste the odor of roasting human flesh in the air.#n\n\r",
		      pch);
		  break;
	       case 2:
		  send_to_char
		     ("#oAn icy cold wind tears at your heart.#n\n\r", pch);
		  break;
	       case 3:
		  send_to_char
		     ("#eYou feel the presence of death around you.#n\n\r",
		      pch);
		  break;
	       case 4:
		  send_to_char
		     ("#rThe urge to kill consumes your very being.#n\n\r",
		      pch);
		  break;
	       }
	 }
      }

      /*
       * Check age and reset.
       * Note: Mud School resets every 3 minutes (not 15).
       */
      if (pArea->nplayer == 0 || pArea->age >= 15)
      {
	 ROOM_INDEX_DATA *pRoomIndex;

	 reset_area (pArea);
	 sprintf (buf, "%s has just been reset.", pArea->filename);
	 wiznet (NULL, WIZ_RESETS, 9, buf);
	 pArea->age = number_range (0, 3);
	 pRoomIndex = get_room_index (ROOM_VNUM_SCHOOL);
	 if (pRoomIndex != NULL && pArea == pRoomIndex->area)
	    pArea->age = 15 - 3;
      }
   }

   return;
}

void reset_door (ROOM_INDEX_DATA * pRoom)
{
   int iExit;

   if (!pRoom)
      return;

   for (iExit = 0; iExit < MAX_DIR; iExit++)
   {
      EXIT_DATA *pExit;
      if ((pExit = pRoom->exit[iExit]))
      {
	 pExit->exit_info = pExit->rs_flags;
	 if ((pExit->to_room != NULL)
	     && (pExit = pExit->to_room->exit[rev_dir[iExit]]) != NULL)
	 {
	    pExit->exit_info = pExit->rs_flags;
	 }
      }
   }

   return;
}

/*
 * Reset one area.
 */
void reset_area (AREA_DATA * pArea)
{
   CHAR_DATA *mob;
   RESET_DATA *pReset;
   ROOM_INDEX_DATA *pRoomIndex;	/* OLC */
   int iExit;			/* OLC */
   int iHash;			/* OLC */
   int level;
   bool last;

   if (pArea == NULL)
      return;

   mob = NULL;
   last = TRUE;
   level = 0;

   {
      ROOM_INDEX_DATA *pRoomReset;
      int vnumreset;

      for (vnumreset = pArea->lvnum; vnumreset <= pArea->uvnum; vnumreset++)
      {
	 if ((pRoomReset = get_room_index (vnumreset)))
	    reset_door (pRoomReset);
      }

   }
   /*
    * OLC
    * New system saves resets as part of door structure.
    */
   for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
   {
      for (pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL;
	   pRoomIndex = pRoomIndex->next)
      {
	 if (pRoomIndex->area == pArea)
	    for (iExit = 0; iExit < MAX_DIR; iExit++)
	    {
	       EXIT_DATA *pExit;

	       if ((pExit = pRoomIndex->exit[iExit])
		   && !IS_SET (pExit->exit_info, EX_BASHED))
	       {
		  pExit->exit_info = pExit->rs_flags;
		  if ((pExit->to_room != NULL)
		      && (pExit =
			  pExit->to_room->exit[rev_dir[iExit]]) != NULL)
		  {
		     pExit->exit_info = pExit->rs_flags;
		     /* nail the other side */
		  }
	       }
	    }
      }
   }

   for (pReset = pArea->reset_first; pReset != NULL; pReset = pReset->next)
   {
      MOB_INDEX_DATA *pMobIndex;
      OBJ_INDEX_DATA *pObjIndex;
      OBJ_INDEX_DATA *pObjToIndex;
      ROOM_INDEX_DATA *pRoomIndex;
      OBJ_DATA *obj;
      OBJ_DATA *obj_to;
//      OBJ_DATA *quest;

      switch (pReset->command)
      {
      default:
	 bug ("Reset_area: bad command %c.", pReset->command);
	 break;

      case 'M':
	 if ((pMobIndex = get_mob_index (pReset->arg1)) == NULL)
	 {
	    bug ("Reset_area: 'M': bad vnum %d.", pReset->arg1);
	    continue;
	 }

	 if ((pRoomIndex = get_room_index (pReset->arg3)) == NULL)
	 {
	    bug ("Reset_area: 'R': bad vnum %d.", pReset->arg3);
	    continue;
	 }

	 level = URANGE (0, pMobIndex->level - 2, LEVEL_HERO);

	 if (pMobIndex->count >= pReset->arg2)
	 {
	    last = FALSE;
	    break;
	 }

	 mob = create_mobile (pMobIndex);
/*	 if (number_range (1, 200) == 100)
	 {

	    quest = create_object (get_obj_index (30038), 0);
	    free_string (quest->name);
	    free_string (quest->short_descr);
	    free_string (quest->description);

	    quest->name = str_dup ("treasure priceless quest gold");
	    quest->short_descr = str_dup ("A gold quest piece");
	    quest->description = str_dup ("A shiny gold coin lies here.");
	    obj_to_char (quest, mob);
	    SET_BIT (quest->quest, ITEM_EQUEST);
	    quest->cost = number_range (15, 25);
	 } */
	 /*
	  * Check for pet shop.
	  */
	 {
	    ROOM_INDEX_DATA *pRoomIndexPrev;

	    pRoomIndexPrev = get_room_index (pRoomIndex->vnum - 1);
	    if (pRoomIndexPrev != NULL
		&& IS_SET (pRoomIndexPrev->room_flags, ROOM_PET_SHOP))
	       SET_BIT (mob->act, ACT_PET);
	 }

	 if (room_is_dark (pRoomIndex))
	    SET_BIT (mob->affected_by, AFF_INFRARED);

	 char_to_room (mob, pRoomIndex);
	 level = URANGE (0, mob->level - 2, LEVEL_HERO);
	 last = TRUE;
	 break;

      case 'O':
	 if ((pObjIndex = get_obj_index (pReset->arg1)) == NULL)
	 {
	    bug ("Reset_area: 'O': bad vnum %d.", pReset->arg1);
	    continue;
	 }

	 if ((pRoomIndex = get_room_index (pReset->arg3)) == NULL)
	 {
	    bug ("Reset_area: 'R': bad vnum %d.", pReset->arg3);
	    continue;
	 }

	 if (pArea->nplayer > 0
	     || count_obj_list (pObjIndex, pRoomIndex->contents) > 0)
	 {
	    last = FALSE;
	    break;
	 }

	 obj = create_object (pObjIndex, number_range (1, 50));
	 obj->cost = 0;
	 obj_to_room (obj, pRoomIndex);
	 last = TRUE;
	 break;

      case 'P':
	 if ((pObjIndex = get_obj_index (pReset->arg1)) == NULL)
	 {
	    bug ("Reset_area: 'P': bad vnum %d.", pReset->arg1);
	    continue;
	 }

	 if ((pObjToIndex = get_obj_index (pReset->arg3)) == NULL)
	 {
	    bug ("Reset_area: 'P': bad vnum %d.", pReset->arg3);
	    continue;
	 }

	 if (pArea->nplayer > 0
	     || (obj_to = get_obj_type (pObjToIndex)) == NULL
	     || obj_to->in_room == NULL
	     || count_obj_list (pObjIndex, obj_to->contains) > 0)
	 {
	    last = FALSE;
	    break;
	 }

	 obj = create_object (pObjIndex, number_range (1, 50));
	 obj_to_obj (obj, obj_to);
	 last = TRUE;
	 break;

      case 'G':
      case 'E':
	 if ((pObjIndex = get_obj_index (pReset->arg1)) == NULL)
	 {
	    bug ("Reset_area: 'E' or 'G': bad vnum %d.", pReset->arg1);
	    continue;
	 }

	 if (!last)
	    break;

	 if (mob == NULL)
	 {
	    bug ("Reset_area: 'E' or 'G': null mob for vnum %d.",
		 pReset->arg1);
	    last = FALSE;
	    break;
	 }

	 if (mob->pIndexData->pShop != NULL)
	 {
	    int olevel;

	    switch (pObjIndex->item_type)
	    {
	    default:
	       olevel = 0;
	       break;
	    case ITEM_PILL:
	       olevel = number_range (0, 10);
	       break;
	    case ITEM_POTION:
	       olevel = number_range (0, 10);
	       break;
	    case ITEM_SCROLL:
	       olevel = number_range (5, 15);
	       break;
	    case ITEM_WAND:
	       olevel = number_range (10, 20);
	       break;
	    case ITEM_STAFF:
	       olevel = number_range (15, 25);
	       break;
	    case ITEM_ARMOR:
	       olevel = number_range (5, 15);
	       break;
	    case ITEM_WEAPON:
	       olevel = number_range (5, 15);
	       break;
	    }

	    obj = create_object (pObjIndex, olevel);
	    if (pReset->command == 'G')
	       SET_BIT (obj->extra_flags, ITEM_INVENTORY);
	 }
	 else
	 {
	    obj = create_object (pObjIndex, number_range (1, 50));
	 }
	 obj_to_char (obj, mob);
	 if (pReset->command == 'E')
	    equip_char (mob, obj, pReset->arg3);
	 last = TRUE;
	 break;

      case 'D':
/* OLC
	    if ( ( pRoomIndex = get_room_index( pReset->arg1 ) ) == NULL )
	    {
		bug( "Reset_area: 'D': bad vnum %d.", pReset->arg1 );
		continue;
	    }

	    if ( ( pexit = pRoomIndex->exit[pReset->arg2] ) == NULL )
		break;

	    switch ( pReset->arg3 )
	    {
	    case 0:
		REMOVE_BIT( pexit->exit_info, EX_CLOSED );
		REMOVE_BIT( pexit->exit_info, EX_LOCKED );
		break;

	    case 1:
		SET_BIT(    pexit->exit_info, EX_CLOSED );
		REMOVE_BIT( pexit->exit_info, EX_LOCKED );
		break;

	    case 2:
		SET_BIT(    pexit->exit_info, EX_CLOSED );
		SET_BIT(    pexit->exit_info, EX_LOCKED );
		break;
	    }

	    last = TRUE;
*/
	 break;

      case 'R':
/*
	    if ( ( pRoomIndex = get_room_index( pReset->arg1 ) ) == NULL )
	    {
		bug( "Reset_area: 'R': bad vnum %d.", pReset->arg1 );
		continue;
	    }

	    {
		int d0;
		int d1;

		for ( d0 = 0; d0 < pReset->arg2 - 1; d0++ )
		{
		    d1                   = number_range( d0, pReset->arg2-1 );
		    pexit                = pRoomIndex->exit[d0];
		    pRoomIndex->exit[d0] = pRoomIndex->exit[d1];
		    pRoomIndex->exit[d1] = pexit;
		}
	    }
*/
	 break;
      }
   }

   return;
}

/*
 * Create an instance of a mobile.
 */

CHAR_DATA *create_mobile (MOB_INDEX_DATA * pMobIndex)
{
   CHAR_DATA *mob;
   int tempvalue;

   mobile_count++;
   if (pMobIndex == NULL)
   {
      bug ("Create_mobile: NULL pMobIndex.", 0);
      exit (1);

   }

   if (char_free == NULL)
   {
      mob = alloc_perm (sizeof (*mob));
   }
   else
   {
      mob = char_free;
      char_free = char_free->next;
   }

   clear_char (mob);
   mob->pIndexData = pMobIndex;

   mob->hunting = str_dup ("");
   mob->lord = str_dup ("");
   mob->clan = str_dup ("");
   mob->morph = str_dup ("");
   mob->createtime = str_dup ("");
   mob->lasttime = str_dup ("");
   mob->lasthost = str_dup ("");
   mob->powertype = str_dup ("");
   mob->poweraction = str_dup ("");
   mob->pload = str_dup ("");
   mob->prompt = str_dup ("");
   mob->cprompt = str_dup ("");

   mob->name = str_dup (pMobIndex->player_name);
   mob->short_descr = str_dup (pMobIndex->short_descr);
   mob->long_descr = str_dup (pMobIndex->long_descr);
   mob->description = str_dup (pMobIndex->description);
   mob->empowered = str_dup ("");
   mob->spec_fun = pMobIndex->spec_fun;

   mob->home = 3001;
   mob->form = 32767;
   mob->level = number_fuzzy (pMobIndex->level);
   mob->act = pMobIndex->act;
   mob->affected_by = pMobIndex->affected_by;
   mob->alignment = pMobIndex->alignment;
   mob->stance[0] = -1;
   
   if (mob->level > 74)
   {
        int mobstance = number_fuzzy( mob->level );
        if (mobstance < 20) mobstance = 20;
        if (mobstance > 200) mobstance = 200;

        if (mobstance < 50) mobstance = 50;

        for (tempvalue = 1; tempvalue <= 10; tempvalue++)
            mob->stance[tempvalue] = mobstance;
        for (tempvalue = 0; tempvalue <= 13; tempvalue++)
            mob->wpn[tempvalue] = mobstance;       
    }

   mob->sex = pMobIndex->sex;
   mob->armor = interpolate (mob->level, 100, -100);

   tempvalue =
      mob->level * 8 + number_range (mob->level * mob->level / 4,
				     mob->level * mob->level);
   if (tempvalue > 10000000)
      mob->max_hit = 10000000;
   else
      mob->max_hit = tempvalue;

   mob->hit = mob->max_hit;

   mob->hitroll = (mob->level * 2);
   mob->damroll = (mob->level * 2);

   if (mob->level<11)
   {
      mob->max_hit /=2;
      mob->hitroll *=0.6;
      mob->damroll *=0.5;
   }

   mob->practice = mob->level * (number_range (10, 20) / 10);

   if (IS_SUPER_NPC(mob))
   {
        static PC_DATA pcdata_zero;
        if (pcdata_free == NULL)
        {
           mob->pcdata = alloc_perm (sizeof (*mob->pcdata));
        }
        else
        {
           mob->pcdata = pcdata_free;
           pcdata_free = pcdata_free->next;
        }
        *mob->pcdata = pcdata_zero;
   }

   /*
    * Insert in list.
    */
   mob->next = char_list;
   char_list = mob;
   pMobIndex->count++;
   return mob;
}

/*
 * Create an instance of an object.
 */
OBJ_DATA *create_object (OBJ_INDEX_DATA * pObjIndex, int level)
{
   static OBJ_DATA obj_zero;
   OBJ_DATA *obj;

    object_count++;

   if (pObjIndex == NULL)
   {
      sprintf (log_buf, "Create_object: Unable to find object (%d)", pObjIndex->vnum);
      bug(log_buf, 0);
      exit (1);

   }

   if (obj_free == NULL)
   {
      obj = alloc_perm (sizeof (*obj));
   }
   else
   {
      obj = obj_free;
      obj_free = obj_free->next;
   }

   *obj = obj_zero;
   obj->pIndexData = pObjIndex;
   obj->in_room = NULL;
   obj->level = level;
   obj->wear_loc = -1;

   obj->name = str_dup (pObjIndex->name);
   obj->short_descr = str_dup (pObjIndex->short_descr);
   obj->description = str_dup (pObjIndex->description);

   if (pObjIndex->chpoweron != NULL)
   {
      obj->chpoweron = pObjIndex->chpoweron;
      obj->chpoweroff = pObjIndex->chpoweroff;
      obj->chpoweruse = pObjIndex->chpoweruse;
      obj->victpoweron = pObjIndex->victpoweron;
      obj->victpoweroff = pObjIndex->victpoweroff;
      obj->victpoweruse = pObjIndex->victpoweruse;
      obj->spectype = pObjIndex->spectype;
      obj->specpower = pObjIndex->specpower;
   }
   else
   {
      obj->chpoweron = str_dup ("(null)");
      obj->chpoweroff = str_dup ("(null)");
      obj->chpoweruse = str_dup ("(null)");
      obj->victpoweron = str_dup ("(null)");
      obj->victpoweroff = str_dup ("(null)");
      obj->victpoweruse = str_dup ("(null)");
      obj->spectype = 0;
      obj->specpower = 0;
   }
   obj->questmaker = str_dup ("");
   obj->questowner = str_dup ("");

   obj->chobj = NULL;

   obj->quest = 0;
   obj->points = 0;

   obj->item_type = pObjIndex->item_type;
   obj->extra_flags = pObjIndex->extra_flags;
   obj->wear_flags = pObjIndex->wear_flags;
   obj->value[0] = pObjIndex->value[0];
   obj->value[1] = pObjIndex->value[1];
   obj->value[2] = pObjIndex->value[2];
   obj->value[3] = pObjIndex->value[3];
   obj->weight = pObjIndex->weight;
   obj->cost =
      number_fuzzy (10) * number_fuzzy (level) * number_fuzzy (level);

   if ((obj->pIndexData->vnum >= 29500 && obj->pIndexData->vnum <= 29503) ||
        obj->pIndexData->vnum == 39 || obj->pIndexData->vnum == 40 ||
        obj->pIndexData->vnum == 47)
      SET_BIT (obj->quest2, QUEST2_COLOR);
   if ((obj->pIndexData->vnum >= 29500 && obj->pIndexData->vnum <= 29599) ||
       (obj->pIndexData->vnum >= 25 && obj->pIndexData->vnum <= 47))
   {
      SET_BIT (obj->quest, QUEST_ARTIFACT);
      SET_BIT (obj->quest2, QUEST2_INDEST);
      obj->condition = 100;
      obj->toughness = 100;
      obj->resistance = 1;
      if (obj->pIndexData->vnum == 38) obj->level = 250;
      else obj->level = 60;
      obj->cost = 1000000;
   }
   else if (obj->pIndexData->vnum >= 30057 && obj->pIndexData->vnum <= 30067)
   {
      free_string (obj->questowner);
      obj->questowner = str_dup ("Tijer");
   }
   else if ((obj->pIndexData->vnum >= 27650 && obj->pIndexData->vnum <= 27670)
	    || (obj->pIndexData->vnum >= 2640
		&& obj->pIndexData->vnum <= 2660))
   {
      obj->condition = 100;
      obj->toughness = 100;
      SET_BIT (obj->quest, QUEST_RELIC);

   }
   else if (obj->pIndexData->vnum == 29689 || obj->pIndexData->vnum == 29690 || obj->pIndexData->vnum == 29695)
   {
      SET_BIT (obj->quest, QUEST_RELIC);
      obj->condition = 100;
      obj->toughness = 100;
   }
   else if (obj->pIndexData->vnum >= 29600 && obj->pIndexData->vnum <= 29613)
   {
      obj->condition = 100;
      obj->toughness = 100;
      SET_BIT (obj->spectype, SITEM_DROW);
      SET_BIT (obj->quest, QUEST_RELIC);
   }
   else if (obj->pIndexData->vnum >= 229 && obj->pIndexData->vnum <= 256)
   {
      obj->condition = 100;
      obj->toughness = 100;
      SET_BIT (obj->spectype, SITEM_FAE);
      SET_BIT (obj->quest, QUEST_RELIC);
   }
   else if (obj->pIndexData->vnum >= 29650 && obj->pIndexData->vnum <= 29661)
   {
      obj->condition = 100;
      obj->toughness = 100;
      SET_BIT (obj->spectype, SITEM_DEMONIC);
      SET_BIT (obj->quest, QUEST_RELIC);
   }
   else if (obj->pIndexData->vnum >= 29700 && obj->pIndexData->vnum <= 29702)
   {
      obj->condition = 100;
      obj->toughness = 100;
      SET_BIT (obj->spectype, SITEM_NINJA);
      SET_BIT (obj->quest, QUEST_RELIC);
   }
   else if (obj->pIndexData->vnum >= 28000 && obj->pIndexData->vnum <= 28010)
   {
      obj->condition = 100;
      obj->toughness = 100;
      SET_BIT (obj->spectype, SITEM_MONK);
      SET_BIT (obj->quest, QUEST_RELIC);
   }
   else if (obj->pIndexData->vnum == 29696)
   {
      obj->condition = 100;
      obj->toughness = 100;
      SET_BIT (obj->spectype, SITEM_WOLF);
      SET_BIT (obj->quest, QUEST_RELIC);
   }
   else
   {
      obj->condition = 100;
      obj->toughness = 5;
      obj->resistance = 25;
   }

   /*
    * Mess with object properties.
    */
   switch (obj->item_type)
   {
   default:
      bug ("Read_object: vnum %d bad type.", pObjIndex->vnum);
      break;

   case ITEM_LIGHT:
   case ITEM_TREASURE:
   case ITEM_FURNITURE:
   case ITEM_TRASH:
   case ITEM_AQUEST:
   case ITEM_CONTAINER:
   case ITEM_DRINK_CON:
   case ITEM_KEY:
   case ITEM_FOOD:
   case ITEM_BOAT:
   case ITEM_CORPSE_NPC:
   case ITEM_CORPSE_PC:
   case ITEM_FOUNTAIN:
   case ITEM_PORTAL:
   case ITEM_EGG:
   case ITEM_VOODOO:
   case ITEM_STAKE:
   case ITEM_MISSILE:
   case ITEM_AMMO:
   case ITEM_ETOKEN:
   case ITEM_QUEST:
   case ITEM_QUESTCARD:
   case ITEM_QUESTMACHINE:
   case ITEM_SYMBOL:
   case ITEM_BOOK:
   case ITEM_PAGE:
   case ITEM_TOOL:
   case ITEM_PIECE:
      break;

   case ITEM_SCROLL:
      obj->value[0] = number_fuzzy (obj->value[0]);
      break;

   case ITEM_WAND:
   case ITEM_STAFF:
      obj->value[0] = number_fuzzy (obj->value[0]);
      obj->value[1] = number_fuzzy (obj->value[1]);
      obj->value[2] = obj->value[1];
      break;

   case ITEM_WEAPON:
      if (!IS_SET (obj->quest, QUEST_ARTIFACT)
	  && !IS_SET (obj->quest, QUEST_RELIC))
      {
	 obj->value[1] = number_range (1, 10);
	 obj->value[2] =
	    number_range ((obj->value[1] + 1), (obj->value[1] * 2));
      }
      break;

   case ITEM_ARMOR:
      if (!IS_SET (obj->quest, QUEST_ARTIFACT)
	  && !IS_SET (obj->quest, QUEST_RELIC))
	 obj->value[0] = number_range (5, 15);
      break;

   case ITEM_POTION:
   case ITEM_PILL:
      obj->value[0] = number_fuzzy (number_fuzzy (obj->value[0]));
      break;

   case ITEM_MONEY:
      obj->value[0] = obj->cost;
      break;
   }

   obj->next = object_list;
   object_list = obj;
   pObjIndex->count++;

   return obj;
}

/*
 * Clear a new character.
 */
void clear_char (CHAR_DATA * ch)
{
   static CHAR_DATA ch_zero;

   *ch = ch_zero;
   ch->name = &str_empty[0];
   ch->short_descr = &str_empty[0];
   ch->long_descr = &str_empty[0];
   ch->description = &str_empty[0];
   ch->lord = &str_empty[0];
   ch->clan = &str_empty[0];
   ch->morph = &str_empty[0];
   ch->createtime = &str_empty[0];
   ch->lasthost = &str_empty[0];
   ch->lasttime = &str_empty[0];
   ch->powertype = &str_empty[0];
   ch->poweraction = &str_empty[0];
   ch->pload = &str_empty[0];
   ch->prompt = &str_empty[0];
   ch->cprompt = &str_empty[0];
   ch->hunting = &str_empty[0];

   ch->logon = current_time;
   ch->armor = 100;
   ch->position = POS_STANDING;
   ch->practice = 0;
   ch->hit = 1000;
   ch->max_hit = 1000;
   ch->mana = 1000;
   ch->max_mana = 1000;
   ch->move = 1000;
   ch->max_move = 1000;
   ch->master = NULL;
   ch->leader = NULL;
   ch->fighting = NULL;
   ch->mount = NULL;
   ch->wizard = NULL;
   ch->paradox[0] = 0;
   ch->paradox[1] = 0;
   ch->paradox[2] = 0;
   ch->damcap[0] = 1000;
   ch->damcap[1] = 0;
   return;
}

/*
 * Free a character.
 */
void free_char (CHAR_DATA * ch, bool quiet)
{
   OBJ_DATA *obj;
   OBJ_DATA *obj_next;
   AFFECT_DATA *paf;
   AFFECT_DATA *paf_next;

  if (IS_NPC(ch))
        mobile_count--;
   for (obj = ch->carrying; obj != NULL; obj = obj_next)
   {
      obj_next = obj->next_content;
      if (quiet)
	 extract_obj2 (obj);
      else
	 extract_obj (obj);
   }

   for (paf = ch->affected; paf != NULL; paf = paf_next)
   {
      paf_next = paf->next;
      affect_remove (ch, paf);
   }

   free_string (ch->name);
   free_string (ch->short_descr);
   free_string (ch->long_descr);
   free_string (ch->description);
   free_string (ch->lord);
   free_string (ch->clan);
   free_string (ch->morph);
   free_string (ch->createtime);
   free_string (ch->lasttime);
   free_string (ch->lasthost);
   free_string (ch->powertype);
   free_string (ch->poweraction);
   free_string (ch->pload);
   free_string (ch->prompt);
   free_string (ch->cprompt);
   free_string (ch->hunting);
   ch->logon = 0;
   if (ch->pcdata != NULL)
   {
      free_string (ch->pcdata->pwd);
      free_string (ch->pcdata->bamfin);
      free_string (ch->pcdata->bamfout);
      free_string (ch->pcdata->title);
      free_string (ch->pcdata->conception);
      free_string (ch->pcdata->parents);
      free_string (ch->pcdata->cparents);
      free_string (ch->pcdata->marriage);
      free_string (ch->pcdata->email);
      ch->pcdata->next = pcdata_free;
      pcdata_free = ch->pcdata;
   }

   ch->next = char_free;
   char_free = ch;
   return;
}

/*
 * Get an extra description from a list.
 */
char *get_extra_descr (const char *name, EXTRA_DESCR_DATA * ed)
{
   for (; ed != NULL; ed = ed->next)
   {
      if (is_name (name, ed->keyword))
	 return ed->description;
   }
   return NULL;
}

MOB_INDEX_DATA *get_mob_index (int vnum)
{
   MOB_INDEX_DATA *pMobIndex;

   for (pMobIndex = mob_index_hash[vnum % MAX_KEY_HASH]; pMobIndex != NULL;
	pMobIndex = pMobIndex->next)
   {
      if (pMobIndex->vnum == vnum)
	 return pMobIndex;
   }

   if (fBootDb)
   {
      bug ("Get_mob_index: bad vnum %d.", vnum);
      exit (1);

   }

   return NULL;
}

/*
 * Translates mob virtual number to its obj index struct.
 * Hash table lookup.
 */
OBJ_INDEX_DATA *get_obj_index (int vnum)
{
   OBJ_INDEX_DATA *pObjIndex;

   for (pObjIndex = obj_index_hash[vnum % MAX_KEY_HASH]; pObjIndex != NULL;
	pObjIndex = pObjIndex->next)
   {
      if (pObjIndex->vnum == vnum)
	 return pObjIndex;
   }

   if (fBootDb)
   {
      bug ("Get_obj_index: bad vnum %d.", vnum);
      exit (1);

   }

   return NULL;
}

/*
 * Translates mob virtual number to its room index struct.
 * Hash table lookup.
 */
ROOM_INDEX_DATA *get_room_index (int vnum)
{
   ROOM_INDEX_DATA *pRoomIndex;

   for (pRoomIndex = room_index_hash[vnum % MAX_KEY_HASH]; pRoomIndex != NULL;
	pRoomIndex = pRoomIndex->next)
   {
      if (pRoomIndex->vnum == vnum)
	 return pRoomIndex;
   }

   if (fBootDb)
   {
      bug ("Get_room_index: bad vnum %d.", vnum);
      exit (1);

   }

   return NULL;
}

/*
 * Read a letter from a file.
 */
char fread_letter (FILE * fp)
{
   char c;

   do
   {
      c = getc (fp);
   }
   while (isspace (c));

   return c;
}

/*
 * Read a number from a file.
 */
/*
long long int fread_long(FILE * fp)
{
        long long int number;
	bool sign;
	char c;

	do
	{
		c = getc(fp);
	}
	while (isspace(c));

	number = 0;

	sign = FALSE;
	if (c == '+')
	{
		c = getc(fp);
	}
	else if (c == '-')
	{
		sign = TRUE;
		c = getc(fp);
	}

	if (!isdigit(c))
	{
                bugf( "Fread_number: bad format. (%c)", c );
                if ( fBootDb )
                  exit( 1 );
                return 0;
	}

	while (isdigit(c))
	{
		number = number * 10 + c - '0';
		c = getc(fp);
	}

	if (sign)
		number = 0 - number;

	if (c == '|')
		number += fread_number(fp);
	else if (c != ' ')
		ungetc(c, fp);

	return number;
}
*/
long long int fread_long (FILE * fp)
{
   bool sign;
   char *ptr;
   long long int number, c;

   ptr = top_string + sizeof (char *);

   do
   {
      c = getc (fp);
      *ptr = c;
   }
   while (isspace (c));

   number = 0;
   sign = FALSE;

   if (c == '+')
   {
      c = getc (fp);
      *ptr = c;
   }
   else if (c == '-')
   {
      sign = TRUE;
      c = getc (fp);
      *ptr = c;
   }

   if (!isdigit (c))
   {
      bug ("Fread_number: bad format.", 0);
      exit (1);
   }

   while (isdigit (c))
   {
      number = number * 10 + c - '0';
      c = getc (fp);
      *ptr = c;
   }

   if (sign)
      number = 0 - number;
   if (c == '|')
      number += fread_long (fp);
   else if (c != ' ')
      ungetc (c, fp);
   return number;
}

int fread_number (FILE * fp)
{
   int number;
   bool sign;
   char c;

   do
   {
      c = getc (fp);
   }
   while (isspace (c));

   number = 0;

   sign = FALSE;
   if (c == '+')
   {
      c = getc (fp);
   }
   else if (c == '-')
   {
      sign = TRUE;
      c = getc (fp);
   }

   if (!isdigit (c))
   {
      sprintf (log_buf, "BAD NUMBER: %c", c);
      log_string (log_buf, NULL);
      bug ("Fread_number: bad format.", 0);
      exit (1);
   }

   while (isdigit (c))
   {
      number = number * 10 + c - '0';
      c = getc (fp);
   }

   if (sign)
      number = 0 - number;

   if (c == '|')
      number += fread_number (fp);
   else if (c != ' ')
      ungetc (c, fp);

   return number;
}

/*
 * Read and allocate space for a string from a file.
 * These strings are read-only and shared.
 * Strings are hashed:
 *   each string prepended with hash pointer to prev string,
 *   hash code is simply the string length.
 * This function takes 40% to 50% of boot-up time.
 */
/**MATT**/
char *fread_string (FILE * fp)
{
   char *plast;
   char c;

   plast = top_string + sizeof (char *);

   if (plast > &string_space[MAX_STRING - MAX_STRING_LENGTH])
   {
      bug ("Fread_string: MAX_STRING %d exceeded.", MAX_STRING);
      exit (1);

   }

   /*
    * Skip blanks.
    * Read first char.
    */
   do
   {
      c = getc (fp);
   }
   while (isspace (c));

   if ((*plast++ = c) == '~')
      return &str_empty[0];

   for (;;)
   {
      /*
       * Back off the char type lookup,
       *   it was too dirty for portability.
       *   -- Furey
       */
      switch (*plast = getc (fp))
      {
      default:
	 plast++;
	 break;

      case EOF:
	 sprintf (log_buf, "HERE: %c", c);
	 log_string (log_buf, NULL);
	 bug ("Fread_string: EOF", 0);
	 exit (1);
	 break;

      case '\n':
	 plast++;
	 *plast++ = '\r';
	 break;

      case '\r':
	 break;

      case '~':
	 plast++;
	 {
	    union
	    {
	       char *pc;
	       char rgc[sizeof (char *)];
	    }
	    u1;
	    int ic;
	    int iHash;
	    char *pHash;
	    char *pHashPrev;
	    char *pString;

	    plast[-1] = '\0';
	    iHash = UMIN (MAX_KEY_HASH - 1, plast - 1 - top_string);
	    for (pHash = string_hash[iHash]; pHash; pHash = pHashPrev)
	    {
	       for (ic = 0; ic < sizeof (char *); ic++)

		  u1.rgc[ic] = pHash[ic];
	       pHashPrev = u1.pc;
	       pHash += sizeof (char *);

	       if (top_string[sizeof (char *)] == pHash[0]
		   && !strcmp (top_string + sizeof (char *) + 1, pHash + 1))
		  return pHash;
	    }

	    if (fBootDb)
	    {
	       pString = top_string;
	       top_string = plast;
	       u1.pc = string_hash[iHash];
	       for (ic = 0; ic < sizeof (char *); ic++)

		  pString[ic] = u1.rgc[ic];
	       string_hash[iHash] = pString;

	       nAllocString += 1;
	       sAllocString += top_string - pString;
	       return pString + sizeof (char *);
	    }
	    else
	    {
	       return str_dup (top_string + sizeof (char *));
	    }
	 }
      }
   }
}

/*
 * Read to end of line (for comments).
 */
void fread_to_eol (FILE * fp)
{
   char c;

   do
   {
      c = getc (fp);
   }
   while (c != '\n' && c != '\r');

   do
   {
      c = getc (fp);
   }
   while (c == '\n' || c == '\r');

   ungetc (c, fp);
   return;
}

/*
 * Read one word (into static buffer).
 */
char *fread_word (FILE * fp)
{
   static char word[MAX_INPUT_LENGTH];
   char *pword;
   char cEnd;

   do
   {
      cEnd = getc (fp);
   }
   while (isspace (cEnd));

   if (cEnd == '\'' || cEnd == '"')
   {
      pword = word;
   }
   else
   {
      word[0] = cEnd;
      pword = word + 1;
      cEnd = ' ';
   }

   for (; pword < word + MAX_INPUT_LENGTH; pword++)
   {
      *pword = getc (fp);
      if (cEnd == ' ' ? isspace (*pword) : *pword == cEnd)
      {
	 if (cEnd == ' ')
	    ungetc (*pword, fp);
	 *pword = '\0';
	 return word;
      }
   }

   bug ("Fread_word: word too long.", 0);
   exit (1);
   return NULL;
}

/*
 * Allocate some ordinary memory,
 *   with the expectation of freeing it someday.
 */
void *alloc_mem (int sMem)
{
   void *pMem;
   int iList;

   for (iList = 0; iList < MAX_MEM_LIST; iList++)
   {
      if (sMem <= rgSizeList[iList])
	 break;
   }

   if (iList == MAX_MEM_LIST)
   {
      bug ("Alloc_mem: size %d too large.", sMem);
      exit (1);
   }

   if (rgFreeList[iList] == NULL)
   {
      pMem = alloc_perm (rgSizeList[iList]);
   }
   else
   {
      pMem = rgFreeList[iList];
      rgFreeList[iList] = *((void **) rgFreeList[iList]);
   }
   return pMem;
}

/*
 * Free some memory.
 * Recycle it back onto the free list for blocks of that size.
 */
void free_mem (void *pMem, int sMem)
{
   int iList;

   for (iList = 0; iList < MAX_MEM_LIST; iList++)
   {
      if (sMem <= rgSizeList[iList])
	 break;
   }

   if (iList == MAX_MEM_LIST)
   {
      bug ("Free_mem: size %d too large.", sMem);
      exit (1);
   }

   *((void **) pMem) = rgFreeList[iList];
   rgFreeList[iList] = pMem;
   return;
}

/*
 * Allocate some permanent memory.
 * Permanent memory is never freed,
 *   pointers into it may be copied safely.
 */
void *alloc_perm (int sMem)
{
   static char *pMemPerm;
   static int iMemPerm;
   void *pMem;

   while (sMem % sizeof (long) != 0)
      sMem++;

   if (sMem > MAX_PERM_BLOCK)
   {
      bug ("Alloc_perm: %d too large.", sMem);
      exit (1);
   }

   if (pMemPerm == NULL || iMemPerm + sMem > MAX_PERM_BLOCK)
   {
      iMemPerm = 0;
      if ((pMemPerm = calloc (1, MAX_PERM_BLOCK)) == NULL)
      {

	 dump_last_command ();
	 perror ("Alloc_perm");
	 exit (1);

      }
   }

   pMem = pMemPerm + iMemPerm;
   iMemPerm += sMem;
   nAllocPerm += 1;
   sAllocPerm += sMem;
   return pMem;
}

/*
 * Duplicate a string into dynamic memory.
 * Fread_strings are read-only and shared.
 */
char *str_dup (const char *str)
{
   char *str_new;

   if (str[0] == '\0')
      return &str_empty[0];

   if (str >= string_space && str < top_string)
      return (char *) str;

   str_new = alloc_mem (strlen (str) + 1);
   strcpy (str_new, str);
   return str_new;
}

/*
 * Free a string.
 * Null is legal here to simplify callers.
 * Read-only shared strings are not touched.
 */
void free_string (char *pstr)
{
   if (pstr == NULL || pstr == &str_empty[0]
       || (pstr >= string_space && pstr < top_string))
      return;

   free_mem (pstr, strlen (pstr) + 1);
   return;
}

void do_areas (CHAR_DATA * ch, char *argument)
{
   char buf[MSL];
   char inarea[MSL];
   char mcolor[MSL];
   char xcolor[MSL];
   AREA_DATA *area;
   int tog = 0;
   int count = 0;
   stc ("\n\r", ch);
   loc_to_char (ch);
   for (area = area_first; area; area = area->next)
   {

      if (IS_CLASS(ch, CLASS_MAGE) && IS_SET(area->aflags, AFLAG_NOAREA)) sprintf (mcolor,"e");
      else if (IS_CLASS(ch, CLASS_MAGE) && !IS_SET(area->aflags, AFLAG_NOAREA)) sprintf (mcolor,"b");
      else sprintf (mcolor,"e");

      if (IS_IMMORTAL(ch) && IS_SET(area->aflags, AFLAG_NOAREA)) sprintf(xcolor,"e");
      else if (IS_IMMORTAL(ch) && !IS_SET(area->aflags, AFLAG_NOAREA)) sprintf(xcolor,"b");
      else sprintf (xcolor,"e");

      if (IS_SET(area->aflags, AFLAG_NOBOMB)) { sprintf(mcolor,"e"); sprintf(xcolor,"e"); }

      if (area->nplayer > 0)
	 sprintf (inarea, "r");
      else
	 sprintf (inarea, "w");
      if (IS_IMMORTAL (ch))
	 sprintf (buf, "#%s%12.12s #%s%-27.27s ", xcolor,area->creator, inarea,
		  area->name);
      else
	 sprintf (buf, "#%s%12.12s #w%-27.27s ", mcolor,area->creator, area->name);
      stc (buf, ch);
      count++;
      if (tog)
      {
	 tog = 0;
	 stc ("\n\r", ch);
      }
      else
	 tog = 1;
   }
   stc ("\n\r", ch);
   divide7_to_char (ch);
   sprintf (buf, "#wThere are a total of #r%d#w areas.", count);
   cent_to_char (buf, ch);
   if (IS_IMMORTAL (ch))
      cent_to_char ("#wAreas in #rRED#w are currently in use!", ch);
   divide7_to_char (ch);
}
void do_memory (CHAR_DATA * ch, char *argument)
{
   char buf[MAX_STRING_LENGTH];
   int overhead = 9437184;

   sprintf (buf, "Affects   %5d\n\r", top_affect);
   send_to_char (buf, ch);
   sprintf (buf, "Areas     %5d\n\r", top_area);
   send_to_char (buf, ch);
   sprintf (buf, "RmTxt     %5d\n\r", top_rt);
   send_to_char (buf, ch);
   sprintf (buf, "ExDes     %5d\n\r", top_ed);
   send_to_char (buf, ch);
   sprintf (buf, "Exits     %5d\n\r", top_exit);
   send_to_char (buf, ch);
   sprintf (buf, "Helps     %5d\n\r", top_help);
   send_to_char (buf, ch);
   sprintf (buf, "Mobs      %5d\n\r", top_mob_index);
   send_to_char (buf, ch);
   sprintf( buf, "(in use)  %5d\n\r", mobile_count  ); send_to_char( buf, ch );
   sprintf (buf, "Objs      %5d\n\r", top_obj_index);
   send_to_char (buf, ch);
   sprintf( buf, "(loaded)  %5d\n\r", object_count  ); send_to_char( buf, ch );
   sprintf (buf, "Resets    %5d\n\r", top_reset);
   send_to_char (buf, ch);
   sprintf (buf, "Rooms     %5d\n\r", top_room);
   send_to_char (buf, ch);
   sprintf (buf, "Shops     %5d\n\r", top_shop);
   send_to_char (buf, ch);

   sprintf (buf, "Strings %5d strings of %7d bytes (max %d).\n\r",
	    nAllocString, sAllocString, MAX_STRING);
   send_to_char (buf, ch);

   sprintf (buf, "Perms   %5d blocks  of %7d bytes.\n\r", nAllocPerm,
	    sAllocPerm);
   send_to_char (buf, ch);

    sprintf( buf, "\n\rWith overhead running at %d bytes,\n\r",overhead);
    stc(buf, ch);

    sprintf( buf, "Overall usage should be %d bytes.\n\r",
        (sAllocPerm+overhead) );
    stc(buf, ch);

   return;
}

/*
 * Stick a little fuzz on a number.
 */
int number_fuzzy (int number)
{
   switch (number_bits (2))
   {
   case 0:
      number -= 1;
      break;
   case 3:
      number += 1;
      break;
   }

   return UMAX (1, number);
}

/*
 * Generate a random number.
 */
int number_range (int from, int to)
{
   int power;
   int number;

   if ((to = to - from + 1) <= 1)
      return from;

   for (power = 2; power < to; power <<= 1)
      ;

   while ((number = number_mm () & (power - 1)) >= to)
      ;

   return from + number;
}

/*
 * Generate a percentile roll.
 */
int number_percent(void)
{
/*    int percent;

    while ( ( percent = number_mm( ) & (128-1) ) > 99 )
	;

    return 1 + percent;*/
   return (number_mm() % 100) + 1;
}

/*
 * Generate a random door.
 */
int number_door (void)
{
   int door;

   while ((door = number_mm () & (8 - 1)) > 5)
      ;

   return door;
}

int number_bits (int width)
{
   return number_mm () & ((1 << width) - 1);
}

/*
 * I've gotten too many bad reports on OS-supplied random number generators.
 * This is the Mitchell-Moore algorithm from Knuth Volume II.
 * Best to leave the constants alone unless you've read Knuth.
 * -- Furey
 */
static int rgiState[2 + 55];

void init_mm ()
{
   int *piState;
   int iState;

   piState = &rgiState[2];

   piState[-2] = 55 - 55;
   piState[-1] = 55 - 24;

   piState[0] = ((int) current_time) & ((1 << 30) - 1);
   piState[1] = 1;
   for (iState = 2; iState < 55; iState++)
   {
      piState[iState] =
	 (piState[iState - 1] + piState[iState - 2]) & ((1 << 30) - 1);
   }
   return;
}

int number_mm (void)
{
   int *piState;
   int iState1;
   int iState2;
   int iRand;

   piState = &rgiState[2];
   iState1 = piState[-2];
   iState2 = piState[-1];
   iRand = (piState[iState1] + piState[iState2]) & ((1 << 30) - 1);
   piState[iState1] = iRand;
   if (++iState1 == 55)
      iState1 = 0;
   if (++iState2 == 55)
      iState2 = 0;
   piState[-2] = iState1;
   piState[-1] = iState2;
   return iRand >> 6;
}

/*
 * Roll some dice.
 */
int dice (int number, int size)
{
   int idice;
   int sum;

   switch (size)
   {
   case 0:
      return 0;
   case 1:
      return number;
   }

   for (idice = 0, sum = 0; idice < number; idice++)
      sum += number_range (1, size);

   return sum;
}

/*
 * Simple linear interpolation.
 */
int interpolate (int level, int value_00, int value_32)
{
   return value_00 + ((level * (value_32 - value_00)) / 32);
}

/*
 * Removes the tildes from a string.
 * Used for player-entered strings that go into disk files.
 */
void smash_tilde (char *str)
{
   for (; *str != '\0'; str++)
   {
      if (*str == '~')
	 *str = '-';
   }

   return;
}

/*
 * Compare strings, case insensitive.
 * Return TRUE if different
 *   (compatibility with historical functions).
 */
bool str_cmp (const char *astr, const char *bstr)
{
   if (astr == NULL)
   {
      char buf[MIL];

      bug ("Str_cmp: null astr.", 0);
      if (bstr != NULL)
      {
	 sprintf (buf, "bstr: %s", bstr);
	 bug (bstr, 0);
      }
      return TRUE;
   }

   if (bstr == NULL)
   {
      char buf[MIL];

      bug ("Str_cmp: null bstr.", 0);
      sprintf (buf, "astr: %s", astr);
      bug (astr, 0);
      return TRUE;
   }

   for (; *astr || *bstr; astr++, bstr++)
   {
      if (LOWER (*astr) != LOWER (*bstr))
	 return TRUE;
   }

   return FALSE;
}

/*
 * Compare strings, case insensitive, for prefix matching.
 * Return TRUE if astr not a prefix of bstr
 *   (compatibility with historical functions).
 */
bool str_prefix (const char *astr, const char *bstr)
{
   if (astr == NULL)
   {
      char buf[MIL];

      bug ("Str_Prefix: null astr.", 0);
      if (bstr != NULL)
      {
	 sprintf (buf, "bstr: %s", bstr);
	 bug (buf, 0);
      }
      return TRUE;
   }

   if (bstr == NULL)
   {
      char buf[MIL];

      bug ("Str_Prefix: null bstr.", 0);
      sprintf (buf, "astr: %s", astr);
      bug (buf, 0);
      return TRUE;
   }

   for (; *astr; astr++, bstr++)
   {
      if (LOWER (*astr) != LOWER (*bstr))
	 return TRUE;
   }

   return FALSE;
}

/*
 * Compare strings, case insensitive, for match anywhere.
 * Returns TRUE is astr not part of bstr.
 *   (compatibility with historical functions).
 */
bool str_infix (const char *astr, const char *bstr)
{
   int sstr1;
   int sstr2;
   int ichar;
   char c0;

   if ((c0 = LOWER (astr[0])) == '\0')
      return FALSE;

   sstr1 = strlen (astr);
   sstr2 = strlen (bstr);

   for (ichar = 0; ichar <= sstr2 - sstr1; ichar++)
   {
      if (c0 == LOWER (bstr[ichar]) && !str_prefix (astr, bstr + ichar))
	 return FALSE;
   }

   return TRUE;
}

/*
 * Compare strings, case insensitive, for suffix matching.
 * Return TRUE if astr not a suffix of bstr
 *   (compatibility with historical functions).
 */
bool str_suffix (const char *astr, const char *bstr)
{
   int sstr1;
   int sstr2;

   sstr1 = strlen (astr);
   sstr2 = strlen (bstr);
   if (sstr1 <= sstr2 && !str_cmp (astr, bstr + sstr2 - sstr1))
      return FALSE;
   else
      return TRUE;
}

/*
 * Returns an initial-capped string.
 */
char *capitalize (const char *str)
{
   static char strcap[MAX_STRING_LENGTH];
   int i;

   for (i = 0; str[i] != '\0'; i++)
      strcap[i] = LOWER (str[i]);
   strcap[i] = '\0';
   strcap[0] = UPPER (strcap[0]);
   return strcap;
}

/*
 * Append a string to a file.
 */
void append_file (CHAR_DATA * ch, char *file, char *str)
{
   FILE *fp;

   if (IS_NPC (ch) || str[0] == '\0')
      return;

   fclose (fpReserve);
   if ((fp = fopen (file, "a")) == NULL)
   {
      perror (file);
      send_to_char ("Could not open the file!\n\r", ch);
   }
   else
   {
      fprintf (fp, "[%5d] %s: %s\n", ch->in_room ? ch->in_room->vnum : 0,
	       ch->name, str);
      fclose (fp);
   }

   fpReserve = fopen (NULL_FILE, "r");
   return;
}

/*
 * Reports a bug.
 */
void bug (const char *str, int param)
{
   char buf[MAX_STRING_LENGTH];
   FILE *fp;

   if (fpArea != NULL)
   {
      int iLine;
      int iChar;

      if (fpArea == stdin)
      {
	 iLine = 0;
      }
      else
      {
	 iChar = ftell (fpArea);
	 fseek (fpArea, 0, 0);
	 for (iLine = 0; ftell (fpArea) < iChar; iLine++)
	 {
	    while (getc (fpArea) != '\n')
	       ;
	 }
	 fseek (fpArea, iChar, 0);
      }

      sprintf (buf, "[*****] FILE: %s LINE: %d", strArea, iLine);
      log_string_sil (buf);

      if ((fp = fopen ("shutdown.txt", "a")) != NULL)
      {
	 fprintf (fp, "[*****] %s\n", buf);
	 fclose (fp);
      }
   }

   strcpy (buf, "[*****] BUG: ");
   sprintf (buf + strlen (buf), str, param);
   log_string_sil (buf);
   wiznet (NULL, WIZ_DEBUG, LEVEL_JUDGE, buf);

   fclose (fpReserve);
   if ((fp = fopen (BUG_FILE, "a")) != NULL)
   {
      fprintf (fp, "%s\n", buf);
      fclose (fp);
   }
   fpReserve = fopen (NULL_FILE, "r");

   return;
}

void bugf (char *fmt, ...)
{
   char buf[2 * MSL];
   va_list args;

   va_start (args, fmt);
   vsprintf (buf, fmt, args);
   va_end (args);

   bug (buf, 0);
   return;
}

/*
 * Writes a string to the log.
 */
void log_string (const char *str, CHAR_DATA * ch)
{
   char *strtime;
   char logout[MAX_STRING_LENGTH];

   strtime = asctime(gmtime(&current_time));
   strtime[strlen (strtime) - 1] = '\0';
   fprintf (stderr, "%s :: %s\n", strtime, str);
   strcpy (logout, str);
   logchan (logout, ch);
   return;
}
void log_player (char *string, CHAR_DATA * ch, bool silent)
{
   FILE *fp;
   char file_name[MAX_STRING_LENGTH];
   char logout[MAX_STRING_LENGTH];

   if (ch == NULL)
      return;

   if (ch->desc != NULL && ch->desc->original != NULL)
      ch = ch->desc->original;

   sprintf (file_name, "%s%s", PLAYER_LOG_DIR, capitalize (ch->name));

   fflush (fpReserve);
   fclose (fpReserve);

   if ((fp = fopen (file_name, "a")) == NULL)
      perror (file_name);

   fprintf (fp, "%s :: %s\n", short_date (current_time), string);

   fflush (fp);
   fclose (fp);

   fpReserve = fopen (NULL_FILE, "r");

   strcpy (logout, string);
   if (!silent)
      plogchan (logout, ch);
   return;
}

void log_string_sil (const char *str)
{
   char *strtime;
   char logout[MAX_STRING_LENGTH];

   strtime = asctime (gmtime(&current_time));
   strtime[strlen (strtime) - 1] = '\0';
   fprintf (stderr, "%s :: %s\n", strtime, str);
   strcpy (logout, str);
   return;
}

void logsf (CHAR_DATA * ch, char *fmt, ...)
{
   char buf[2 * MAX_STRING_LENGTH];
   va_list args;

   va_start (args, fmt);
   vsprintf (buf, fmt, args);
   va_end (args);
   log_string (buf, ch);
   return;
}

void pager_printf (CHAR_DATA * ch, char *fmt, ...)
{
   char buf[MAX_STRING_LENGTH];
   va_list args;

   va_start (args, fmt);
   vsprintf (buf, fmt, args);
   va_end (args);

   page_to_char (buf, ch);
   return;
}
void stcprintf (CHAR_DATA * ch, char *txt, ...)
{
   char buf[2 * MSL];
   va_list args;

   va_start (args, txt);
   vsprintf (buf, txt, args);
   va_end (args);

   stc (buf, ch);
   return;
}

/*
 * This function is here to aid in debugging.
 * If the last expression in a function is another function call,
 *   gcc likes to generate a JMP instead of a CALL.
 * This is called "tail chaining."
 * It hoses the debugger call stack for that call.
 * So I make this the last call in certain critical functions,
 *   where I really need the call stack to be right for debugging!
 *
 * If you don't understand this, then LEAVE IT ALONE.
 * Don't remove any calls to tail_chain anywhere.
 *
 * -- Furey
 */
void tail_chain (void)
{
   return;
}

bool good_pfile (char *name)
{
   char c;
   FILE *fp;
   char strsave[MAX_STRING_LENGTH];
   bool good = FALSE;

   sprintf (strsave, "%s%s", PLAYER_DIR, capitalize (name));


   if ((fp = fopen (strsave, "r")) != NULL)
   {
      while ((c = getc (fp)) != EOF)
      {
	 if (c != '#')
	    continue;
	 if (getc (fp) != 'E')
	    continue;
	 if (getc (fp) != 'N')
	    continue;
	 if (getc (fp) != 'D')
	    continue;
	 good = TRUE;
      }
      ungetc (c, fp);
   }
   if (fp == NULL)
      bug ("db.c - good_pfile: fp == NULL", 0);
   fclose (fp);
   return good;
}

/*
 *  Based off of fix_exits, this is the magic that makes migratory exits work.
 */
void update_migratory_exits (void)
{
   extern const int rev_dir[];
   char buf[MAX_STRING_LENGTH];
   ROOM_INDEX_DATA *pRoomIndex;
   EXIT_DATA *pexit;
   int door;
   int slowmo = 1;
   bool VALID_ROOM_1 = FALSE;
   bool VALID_ROOM_2 = FALSE;
   int a_vnum = 0;
   ROOM_INDEX_DATA *a_room=NULL;
   int lrev_dir[6] = { 2, 3, 0, 1, 5, 4 };
   bool store_boot_state = fBootDb;
   EXIT_DATA *a_exit;

   fBootDb = FALSE;

   for (slowmo = 1; slowmo < MAX_ROOM_VNUM; slowmo++)
   {
      a_vnum = 0;
      VALID_ROOM_1 = FALSE;
      VALID_ROOM_2 = FALSE;
      pRoomIndex = get_room_index (slowmo);
      if (!pRoomIndex)
	 continue;
      else
      {
	 for (door = 0; door <= 5; door++)
	 {
	    if ((pexit = pRoomIndex->exit[door]) != NULL)
	    {
	       VALID_ROOM_1 = FALSE;
	       a_vnum = 0;

	       if (!IS_SET (pexit->exit_info, EX_NOMADIC))
		  continue;
	       else
	       {
		  while (!VALID_ROOM_1)
		  {
		     while (!VALID_ROOM_2)
		     {
			VALID_ROOM_2 = FALSE;
			a_vnum = number_range (1, MAX_ROOM_VNUM);
			a_room = get_room_index (a_vnum);

			if (!a_room)
			   continue;
			if (IS_SET (a_room->area->aflags, AREA_NO_NOMADS))
			   continue;	// No migrating exits to here no siree
			if (a_room->exit[lrev_dir[door]] == NULL)
			{
			   a_room->exit[lrev_dir[door]] =
			      alloc_perm (sizeof (*a_exit));
			   VALID_ROOM_2 = TRUE;
			}
			else
			{
			   if (a_room->exit[lrev_dir[door]]->vnum > 0)	// time to check for proper exit --  Serenity
			      continue;	// Aw man, two for one doesn't work?
			}
		     }
		     VALID_ROOM_1 = TRUE;	// If we get here i think it worked...
		  }
		  if (a_room->exit[lrev_dir[door]] == NULL)
		     a_room->exit[lrev_dir[door]] =
			alloc_perm (sizeof (*a_exit));
		  a_room->exit[lrev_dir[door]]->vnum = (pRoomIndex->vnum);	// Room made
		  SET_BIT (a_room->exit[lrev_dir[door]]->exit_info, EX_MIGRATORY);	// Now assign the needed flag to make it not permanent.
		  SET_BIT (a_room->exit[lrev_dir[door]]->rs_flags, EX_MIGRATORY);	// Now assign the needed flag to make it not permanent.
		  a_room->exit[lrev_dir[door]]->to_room = pRoomIndex;	// this should link 2nd room to this room.
		  pexit->to_room = a_room;	// Assign the room & assign the reverse...
		  pRoomIndex->exit[door]->vnum = a_vnum;	// Set this sides link vnum.

		  sprintf (buf,
			   "Room: %d, Exit %d made a migratory link to Room: %d, Exit %d",
			   pRoomIndex->vnum, door, a_vnum, rev_dir[door]);
		  bug (buf, 0);	// ALL done!  Next!
		  log_string_sil (buf);	// ALL done!  Next!
	       }
	    }
	 }
      }
   }
   fBootDb = store_boot_state;
   return;
}