/
/*****************************************************************************************
 *                       DDDDD        A        RRRRRRR     K    K                        *
 *                       D    D      A A       R      R    K   K                         *
 *                       D     D    A   A      R      R    KK K                          *
 *                       D     D   A     A     RRRRRRR     K K                           *
 *                       D     D  AAAAAAAAA    R    R      K  K                          *
 *                       D    D  A         A   R     R     K   K                         *
 *                       DDDDD  A           A  R      R    K    K                        *
 *                                                                                       *
 *                                                                                       *
 *W      WW      W    A        RRRRRRR   RRRRRRR   IIIIIIII    OOOO   RRRRRRR     SSSSS  *
 * W    W  W    W    A A       R      R  R      R     II      O    O  R      R   S       *
 * W    W  W    W   A   A      R      R  R      R     II     O      O R      R   S       *
 * W    W  W    W  A     A     RRRRRRR   RRRRRRR      II     O      O RRRRRRR     SSSSS  *
 *  W  W    W  W  AAAAAAAAA    R    R    R    R       II     O      O R    R           S *
 *  W W     W W  A         A   R     R   R     R      II      O    O  R     R          S *
 *   W       W  A           A  R      R  R      R  IIIIIIII    OOOO   R      R    SSSSS  *
 *                                                                                       *
 *****************************************************************************************
 *                                                                                       *
 * Dark Warrior Code additions and changes from the Star Wars Reality code copyright (c) *
 * 2003 by Michael Ervin, Mark Gottselig, Gavin Mogan                                    *
 *                                                                                       *
 * Star Wars Reality Code Additions and changes from the Smaug Code copyright (c) 1997   *
 * by Sean Cooper                                                                        *
 *                                                                                       *
 * Starwars and Starwars Names copyright(c) Lucas Film Ltd.                              *
 *****************************************************************************************
 *                           ^     +----- |  / ^     ^ |     | +-\                       *
 *                          / \    |      | /  |\   /| |     | |  \                      *
 *                         /   \   +---   |<   | \ / | |     | |  |                      *
 *                        /-----\  |      | \  |  v  | |     | |  /                      *
 *                       /       \ |      |  \ |     | +-----+ +-/                       *
 *****************************************************************************************
 *                                                                                       *
 * AFKMud Copyright 1997-2003 by Roger Libiez (Samson), Levi Beckerson (Whir),           *
 * Michael Ward (Tarl), Erik Wolfe (Dwip), Cameron Carroll (Cam), Cyberfox, Karangi,     *
 * Rathian, Raine, and Adjani. All Rights Reserved.                                      *
 *                                                                                       *
 * Original SMAUG 1.4a written by Thoric (Derek Snider) with Altrag, Blodkai, Haus, Narn,*
 * Scryn, Swordbearer, Tricops, Gorog, Rennard, Grishnakh, Fireblade, and Nivek.         *
 *                                                                                       *
 * Original MERC 2.1 code by Hatchet, Furey, and Kahn.                                   *
 *                                                                                       *
 * Original DikuMUD code by: Hans Staerfeldt, Katja Nyboe, Tom Madsen, Michael Seifert,  *
 * and Sebastian Hammer.                                                                 *
 *****************************************************************************************
 *                          SWR Hotboot module                                           *
 ****************************************************************************************/


#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>
#include "mud.h"
#ifdef CHANGES
#include "changes.h"
#endif

#ifdef I3
bool      I3_is_connected(void);
void      I3_savemudlist(void);
void      I3_savechanlist(void);
void      I3_loadhistory(void);
void      I3_savehistory(void);
extern int I3_socket;
#endif
#ifdef IMC
void      imc_shutdown(bool reconnect);
#endif

#define MAX_NEST	100
static OBJ_DATA *rgObjNest[MAX_NEST];

#ifdef MCCP
bool      write_to_descriptor(DESCRIPTOR_DATA * d, char *txt, int length);
bool      write_to_descriptor_old(int desc, char *txt, int length);
#else
bool      write_to_descriptor(int desc, char *txt, int length);
#endif

extern ROOM_INDEX_DATA *room_index_hash[MAX_KEY_HASH];
extern int port;    /* Port number to be used       */

#if defined(KEY)
#undef KEY
#endif

#define KEY( literal, field, value )					\
				if ( !strcmp( word, literal ) )	\
				{					\
				    field  = value;			\
				    fMatch = TRUE;			\
				    break;				\
				}

/*
 * Save the world's ship files
 */
void write_ship(FILE * fp, SHIP_DATA * ship)
{
        if (!fp)
                return;
        /*
         * What other conditions? 
         */
        /*
         * How about only ones that landed 
         */
        if (ship->shipstate == SHIP_DOCKED)
                return;
        if (ship->class > SHIP_PLATFORM)
                return;

        fprintf(fp, "%s", "#SHIP\n");
        fprintf(fp, "Shipfname	%s~\n", ship->filename);
        if (ship->currspeed != 0)
                fprintf(fp, "Currspeed %d\n", ship->currspeed);
        if (ship->chaff != ship->maxchaff)
                fprintf(fp, "Chaff %d\n", ship->chaff);
        if (ship->shield != ship->maxshield)
                fprintf(fp, "Shield %d\n", ship->shield);
        if (ship->missiles != ship->maxmissiles)
                fprintf(fp, "Missiles %d\n", ship->missiles);
        if (ship->torpedos != ship->maxtorpedos)
                fprintf(fp, "Torpedos %d\n", ship->torpedos);
        if (ship->rockets != ship->maxrockets)
                fprintf(fp, "Rockets %d\n", ship->rockets);
        fprintf(fp, "Autorecharge %d\n", ship->autorecharge);
        fprintf(fp, "Autotrack %d\n", ship->autotrack);
        fprintf(fp, "Autospeed %d\n", ship->autospeed);
        fprintf(fp, "Autopilot %d\n", ship->autopilot);

        fprintf(fp, "VX %d\n", (int) ship->vx);
        fprintf(fp, "VY %d\n", (int) ship->vy);
        fprintf(fp, "VZ %d\n", (int) ship->vz);

        fprintf(fp, "HX %d\n", (int) ship->hx);
        fprintf(fp, "HY %d\n", (int) ship->hy);
        fprintf(fp, "HZ %d\n", (int) ship->hz);

        fprintf(fp, "JX %d\n", (int) ship->jx);
        fprintf(fp, "JY %d\n", (int) ship->jy);
        fprintf(fp, "JZ %d\n", (int) ship->jz);

        if (ship->target0)
                fprintf(fp, "Target0 %s~\n", ship->target0->name);
        if (ship->target1)
                fprintf(fp, "Target1 %s~\n", ship->target1->name);
        if (ship->target2)
                fprintf(fp, "Target2 %s~\n", ship->target2->name);

        fprintf(fp, "Shipstate %d\n", ship->shipstate);
        if (ship->dest != NULL && ship->dest[0] != '\0')
        {
                fprintf(fp, "LandDest %s~\n", ship->dest);
        }

        if (ship->shipstate == SHIP_HYPERSPACE)
        {
                fprintf(fp, "Hyperdistance %d\n", ship->hyperdistance);
                fprintf(fp, "Currjump %s~\n", ship->currjump->name);
        }
        if (ship->energy != ship->maxenergy)
                fprintf(fp, "Energy %d\n", ship->energy);
        if (ship->hull != ship->maxhull)
                fprintf(fp, "Hull %d\n", ship->hull);

        if (ship->starsystem)
                fprintf(fp, "Starsystem %s~\n", ship->starsystem->name);
        fprintf(fp, "%s", "EndShip\n\n");
        return;
}

SHIP_DATA *load_ship(FILE * fp)
{
        SHIP_DATA *ship = NULL;
        const char *word;
        bool      fMatch;

        word = feof(fp) ? "EndShip" : fread_word(fp);
        if (!str_cmp(word, "EndShip"))
                return NULL;

        if (!str_cmp(word, "SHIPFNAME"))
        {
                char     *name = fread_string_nohash(fp);   /* is this right? - Gavin */
                SHIP_DATA *temp_ship = NULL;

                for (temp_ship = first_ship; temp_ship;
                     temp_ship = temp_ship->next)
                {
                        if (!str_cmp(name, temp_ship->filename))
                        {
                                ship = temp_ship;
                                break;
                        }
                }

                if (ship == NULL)
                {
                        bug("load_ship: No ship data for filename %s", name);
                        DISPOSE(name);
                        return NULL;

                        for (;;)
                        {
                                word = feof(fp) ? "EndShip" : fread_word(fp);
                                if (!str_cmp(word, "EndShip"))
                                        break;
                        }

                }

                DISPOSE(name);
        }
        else
        {
                for (;;)
                {
                        word = feof(fp) ? "EndShip" : fread_word(fp);
                        if (!str_cmp(word, "EndShip"))
                                break;
                }
                bug("load_ship: shipfname not found");
                return NULL;
        }
        for (;;)
        {
                word = feof(fp) ? "EndShip" : fread_word(fp);
                fMatch = FALSE;
                switch (UPPER(word[0]))
                {
                case '*':
                        fMatch = TRUE;
                        fread_to_eol(fp);
                        break;
                        /*
                         * case '#':
                         * if ( !str_cmp( word, "#TORPEDO" ) )
                         * {
                         * mob->tempnum = -9999; 
                         * fread_obj( mob, fp, OS_CARRY );
                         * }
                         */
                case 'A':
                        KEY("Autorecharge", ship->autorecharge,
                            (bool) fread_number(fp));
                        KEY("Autotrack", ship->autotrack,
                            (bool) fread_number(fp));
                        KEY("Autospeed", ship->autospeed,
                            (bool) fread_number(fp));
                        KEY("Autopilot", ship->autopilot,
                            (bool) fread_number(fp));
                        break;
                case 'C':
                        KEY("Currspeed", ship->currspeed, fread_number(fp));
                        if (!str_cmp(word, "Currjump"))
                        {
                                char     *temp = fread_string_nohash(fp);

                                extract_ship(ship);
                                ship->location = 0;
                                ship->currjump = starsystem_from_name(temp);
                                DISPOSE(temp);
                                fMatch = TRUE;
                                break;
                        }
                        KEY("Chaff", ship->chaff, fread_number(fp));
                        break;

                case 'E':
                        KEY("Energy", ship->energy, fread_number(fp));
                        if (!str_cmp(word, "EndShip"))
                        {
                                return ship;
                        }
                        if (!str_cmp(word, "End"))  /* End of object, need to ignore this. sometimes they creep in there somehow -- Scion */
                                fMatch = TRUE;  /* Trick the system into thinking it matched something */
                        break;

                case 'H':
                        KEY("Hull", ship->hull, fread_number(fp));
                        KEY("HX", ship->hx, (float) fread_number(fp));
                        KEY("HY", ship->hy, (float) fread_number(fp));
                        KEY("HZ", ship->hz, (float) fread_number(fp));
                        KEY("Hyperdistance", ship->hyperdistance,
                            fread_number(fp));
                        break;

                case 'J':
                        KEY("JX", ship->jx, (float) fread_number(fp));
                        KEY("JY", ship->jy, (float) fread_number(fp));
                        KEY("JZ", ship->jz, (float) fread_number(fp));
                        break;
                case 'L':
                        if (!str_cmp(word, "Landdest"))
                        {
                                if (ship->dest != NULL)
                                        STRFREE(ship->dest);
                                ship->dest = fread_string(fp);
                                fMatch = TRUE;
                                break;
                        }
                        break;

                case 'M':
                        KEY("Missiles", ship->missiles, fread_number(fp));
                        break;
                case 'R':
                        KEY("Rockets", ship->rockets, fread_number(fp));
                        break;
                case 'S':
                        KEY("Shield", ship->shield, fread_number(fp));
                        KEY("Shipstate", ship->shipstate, fread_number(fp));

                        if (!str_cmp(word, "Starsystem"))
                        {
                                char     *star_name = fread_string_nohash(fp);
                                SPACE_DATA *starsystem =
                                        starsystem_from_name(star_name);
                                DISPOSE(star_name);
                                fMatch = TRUE;

                                extract_ship(ship);
                                ship->location = 0;
                                if (ship->starsystem)
                                        ship_from_starsystem(ship,
                                                             starsystem);
                                ship_to_starsystem(ship, starsystem);
                                break;
                        }
                        break;
                case 'T':
                        KEY("Torpedos", ship->torpedos, fread_number(fp));
                        if (!str_cmp(word, "target0"))
                        {
                                char     *temp = fread_string(fp);
                                SHIP_DATA *target = get_ship(temp);

                                ship->target0 = target;
                                DISPOSE(temp);
                        }
                        if (!str_cmp(word, "target1"))
                        {
                                char     *temp = fread_string(fp);
                                SHIP_DATA *target = get_ship(temp);

                                ship->target1 = target;
                                DISPOSE(temp);
                        }
                        if (!str_cmp(word, "target2"))
                        {
                                char     *temp = fread_string(fp);
                                SHIP_DATA *target = get_ship(temp);

                                ship->target2 = target;
                                DISPOSE(temp);
                        }

                        break;
                case 'V':
                        KEY("VX", ship->vx, (float) fread_number(fp));
                        KEY("VY", ship->vy, (float) fread_number(fp));
                        KEY("VZ", ship->vz, (float) fread_number(fp));
                        break;

                }
                if (!fMatch && str_cmp(word, "End"))
                        bug("load_mobile: no match: %s", word);
        }
        return NULL;
}

/*
 * Save the world's objects and mobs in their current positions -- Scion
 */
void save_mobile(FILE * fp, CHAR_DATA * mob)
{
        AFFECT_DATA *paf;
        SKILLTYPE *skill = NULL;

        if (!IS_NPC(mob) || !fp)
                return;
        fprintf(fp, "%s", "#MOBILE\n");
        fprintf(fp, "Vnum	%d\n", mob->pIndexData->vnum);
        fprintf(fp, "Level   %d\n", mob->top_level);
        fprintf(fp, "Gold	%d\n", mob->gold);
        if (mob->in_room)
        {
                if (IS_SET(mob->act, ACT_SENTINEL))
                {
                        /*
                         * Sentinel mobs get stamped with a "home room" when they are created
                         * by create_mobile(), so we need to save them in their home room regardless
                         * of where they are right now, so they will go to their home room when they
                         * enter the game from a reboot or copyover -- Scion 
                         */
                        fprintf(fp, "Room	%d\n", mob->home_vnum);
                }
                else
                        fprintf(fp, "Room	%d\n", mob->in_room->vnum);
        }
        else
                fprintf(fp, "Room	%d\n", ROOM_VNUM_LIMBO);
#ifdef OVERLANDCODE
        fprintf(fp, "Coordinates  %d %d %d\n", mob->x, mob->y, mob->map);
#endif
        if (QUICKMATCH(mob->name, mob->pIndexData->player_name) == 0)
                fprintf(fp, "Name     %s~\n", mob->name);
        if (QUICKMATCH(mob->short_descr, mob->pIndexData->short_descr) == 0)
                fprintf(fp, "Short	%s~\n", mob->short_descr);
        if (QUICKMATCH(mob->long_descr, mob->pIndexData->long_descr) == 0)
                fprintf(fp, "Long	%s~\n", mob->long_descr);
        if (QUICKMATCH(mob->description, mob->pIndexData->description) == 0)
                fprintf(fp, "Description %s~\n", mob->description);
        fprintf(fp, "HpManaMove   %d %d %d %d %d %d\n",
                mob->hit, mob->max_hit, mob->mana, mob->max_mana, mob->move,
                mob->max_move);
        fprintf(fp, "Position %d\n", mob->position);
        fprintf(fp, "Flags %d\n", mob->act);
        fprintf(fp, "AffectedBy   %d\n", mob->affected_by);

        for (paf = mob->first_affect; paf; paf = paf->next)
        {
                if (paf->type >= 0
                    && (skill = get_skilltype(paf->type)) == NULL)
                        continue;

                if (paf->type >= 0 && paf->type < TYPE_PERSONAL)
                        fprintf(fp, "AffectData   '%s' %3d %3d %3d %d\n",
                                skill->name, paf->duration, paf->modifier,
                                paf->location, paf->bitvector);
                else
                        fprintf(fp, "Affect       %3d %3d %3d %3d %d\n",
                                paf->type, paf->duration, paf->modifier,
                                paf->location, paf->bitvector);
        }

        de_equip_char(mob);

        if (mob->first_carrying)
                fwrite_obj(mob, mob->last_carrying, fp, 0, OS_CARRY, TRUE);

        re_equip_char(mob);

        fprintf(fp, "%s", "EndMobile\n\n");
        return;
}

void save_world(CHAR_DATA * ch)
{
        FILE     *mobfp;
        FILE     *objfp;
        FILE     *shipfp;
        int       mobfile = 0;
        int       shipfile = 0;
        char      filename[256];
        CHAR_DATA *rch;
        ROOM_INDEX_DATA *pRoomIndex;
        int       iHash;

        log_string("Preserving world state....");

        snprintf(filename, 256, "%s%s", SYSTEM_DIR, MOB_FILE);
        if ((mobfp = fopen(filename, "w")) == NULL)
        {
                bug("%s", "save_world: fopen mob file");
                perror(filename);
        }
        else
                mobfile++;

        snprintf(filename, 256, "%s%s", SYSTEM_DIR, SHIP_FILE);
        if ((shipfp = fopen(filename, "w")) == NULL)
        {
                bug("%s", "save_world: fopen ship file");
                perror(filename);
        }
        else
                shipfile++;

        for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
        {
                for (pRoomIndex = room_index_hash[iHash]; pRoomIndex;
                     pRoomIndex = pRoomIndex->next)
                {
                        if (pRoomIndex)
                        {
                                if (!pRoomIndex->first_content  /* Skip room if nothing in it */
                                    || IS_SET(pRoomIndex->room_flags, ROOM_CLANSTOREROOM)   /* These rooms save on their own */
                                        )
                                        continue;

                                snprintf(filename, 256, "%s%d", HOTBOOT_DIR,
                                         pRoomIndex->vnum);
                                if ((objfp = fopen(filename, "w")) == NULL)
                                {
                                        bug("save_world: fopen %d",
                                            pRoomIndex->vnum);
                                        perror(filename);
                                        continue;
                                }
                                fwrite_obj(NULL, pRoomIndex->last_content,
                                           objfp, 0, OS_CARRY, TRUE);
                                fprintf(objfp, "%s", "#END\n");
                                FCLOSE(objfp);
                        }
                }
        }

        if (mobfile)
        {
                for (rch = first_char; rch; rch = rch->next)
                {
                        if (!IS_NPC(rch) || rch == supermob
                            || IS_SET(rch->act, ACT_PROTOTYPE)
                            || IS_SET(rch->act, ACT_PET))
                                continue;
                        else
                                save_mobile(mobfp, rch);
                }
                fprintf(mobfp, "%s", "#END\n");
                FCLOSE(mobfp);
        }

        if (shipfile)
        {
                SHIP_DATA *ship = NULL;

                for (ship = first_ship; ship; ship = ship->next)
                {
                        write_ship(shipfp, ship);
                }
                fprintf(shipfp, "%s", "#END\n");
                FCLOSE(shipfp);
        }

        return;
}

#if defined(KEY)
#undef KEY
#endif

#define KEY( literal, field, value )					\
				if ( !strcmp( word, literal ) )	\
				{					\
				    field  = value;			\
				    fMatch = TRUE;			\
				    break;				\
				}

CHAR_DATA *load_mobile(FILE * fp)
{
        CHAR_DATA *mob = NULL;
        char     *word;
        bool      fMatch;
        int       inroom = 0;
        ROOM_INDEX_DATA *pRoomIndex = NULL;

        word = feof(fp) ? "EndMobile" : fread_word(fp);
        if (!str_cmp(word, "Vnum"))
        {
                int       vnum;

                vnum = fread_number(fp);
                if (get_mob_index(vnum) == NULL)
                {
                        bug("load_mobile: No index data for vnum %d", vnum);
                        return NULL;
                }
                mob = create_mobile(get_mob_index(vnum));
                if (!mob)
                {
                        for (;;)
                        {
                                word = feof(fp) ? "EndMobile" :
                                        fread_word(fp);
                                /*
                                 * So we don't get so many bug messages when something messes up
                                 * * --Shaddai 
                                 */
                                if (!str_cmp(word, "EndMobile"))
                                        break;
                        }
                        bug("load_mobile: Unable to create mobile for vnum %d", vnum);
                        return NULL;
                }
        }
        else
        {
                for (;;)
                {
                        word = feof(fp) ? "EndMobile" : fread_word(fp);
                        /*
                         * So we don't get so many bug messages when something messes up
                         * * --Shaddai 
                         */
                        if (!str_cmp(word, "EndMobile"))
                                break;
                }
                extract_char(mob, TRUE);
                bug("%s", "load_mobile: Vnum not found");
                return NULL;
        }
        for (;;)
        {
                word = feof(fp) ? "EndMobile" : fread_word(fp);
                fMatch = FALSE;
                switch (UPPER(word[0]))
                {
                case '*':
                        fMatch = TRUE;
                        fread_to_eol(fp);
                        break;
                case '#':
                        if (!str_cmp(word, "#OBJECT"))
                        {
                                mob->tempnum = -9999;   /* Hackish, yes. Works though doesn't it? */
                                fread_obj(mob, fp, OS_CARRY);
                        }
                case 'A':
                        if (!str_cmp(word, "Affect")
                            || !str_cmp(word, "AffectData"))
                        {
                                AFFECT_DATA *paf;

                                CREATE(paf, AFFECT_DATA, 1);
                                if (!str_cmp(word, "Affect"))
                                {
                                        paf->type = fread_number(fp);
                                }
                                else
                                {
                                        int       sn;
                                        char     *sname = fread_word(fp);

                                        if ((sn = skill_lookup(sname)) < 0)
                                        {
                                                if ((sn =
                                                     herb_lookup(sname)) < 0)
                                                        bug("%s",
                                                            "load_mobile: unknown skill.");
                                                else
                                                        sn += TYPE_HERB;
                                        }
                                        paf->type = sn;
                                }

                                paf->duration = fread_number(fp);
                                paf->modifier = fread_number(fp);
                                paf->location = fread_number(fp);
                                if (paf->location == APPLY_WEAPONSPELL
                                    || paf->location == APPLY_WEARSPELL
                                    || paf->location == APPLY_REMOVESPELL
                                    || paf->location == APPLY_STRIPSN)
                                        paf->modifier =
                                                slot_lookup(paf->modifier);
                                paf->bitvector = fread_number(fp);
                                LINK(paf, mob->first_affect, mob->last_affect,
                                     next, prev);
                                fMatch = TRUE;
                                break;
                        }
                        KEY("AffectedBy", mob->affected_by, fread_number(fp));
                        break;
#ifdef OVERLANDCODE
                case 'C':
                        if (!str_cmp(word, "Coordinates"))
                        {
                                mob->x = fread_number(fp);
                                mob->y = fread_number(fp);
                                mob->map = fread_number(fp);

                                fMatch = TRUE;
                                break;
                        }
                        break;
#endif
                case 'D':
                        KEY("Description", mob->description,
                            fread_string(fp));
                        break;
                case 'E':
                        if (!str_cmp(word, "EndMobile"))
                        {
                                if (inroom == 0)
                                        inroom = ROOM_VNUM_LIMBO;
                                pRoomIndex = get_room_index(inroom);
                                if (!pRoomIndex)
                                        pRoomIndex =
                                                get_room_index
                                                (ROOM_VNUM_LIMBO);
                                char_to_room(mob, pRoomIndex);
                                mob->tempnum = -9998;   /* Yet another hackish fix! */
                                return mob;
                        }
                        if (!str_cmp(word, "End"))  /* End of object, need to ignore this. sometimes they creep in there somehow -- Scion */
                                fMatch = TRUE;  /* Trick the system into thinking it matched something */
                        break;
                case 'F':
                        KEY("Flags", mob->act, fread_number(fp));
                case 'G':
                        KEY("Gold", mob->gold, fread_number(fp));
                        break;
                case 'H':
                        if (!str_cmp(word, "HpManaMove"))
                        {
                                mob->hit = fread_number(fp);
                                mob->max_hit = fread_number(fp);
                                mob->mana = fread_number(fp);
                                mob->max_mana = fread_number(fp);
                                mob->move = fread_number(fp);
                                mob->max_move = fread_number(fp);

                                if (mob->max_move <= 0)
                                        mob->max_move = 150;

                                fMatch = TRUE;
                                break;
                        }
                        break;
                case 'L':
                        KEY("Long", mob->long_descr, fread_string(fp));
                        KEY("Level", mob->top_level, fread_number(fp));
                        break;
                case 'M':
                        KEY("Mobclan", mob->mob_clan, fread_string(fp));
                        break;
                case 'N':
                        KEY("Name", mob->name, fread_string(fp));
                        break;
                case 'P':
                        KEY("Position", mob->position, fread_number(fp));
                        break;
                case 'R':
                        KEY("Room", inroom, fread_number(fp));
                        break;
                case 'S':
                        KEY("Short", mob->short_descr, fread_string(fp));
                        break;
                }
                if (!fMatch && str_cmp(word, "End"))
                        bug("load_mobile: no match: %s", word);
        }
        return NULL;
}

void read_obj_file(char *dirname, char *filename)
{
        ROOM_INDEX_DATA *room;
        FILE     *fp;
        char      fname[256];
        int       vnum;

        vnum = atoi(filename);

        if ((room = get_room_index(vnum)) == NULL)
        {
                bug("read_obj_file: ARGH! Missing room index for %d!", vnum);
                return;
        }

        snprintf(fname, 256, "%s%s", dirname, filename);
        if ((fp = fopen(fname, "r")) != NULL)
        {
                sh_int    iNest;
                bool      found;
                OBJ_DATA *tobj, *tobj_next;

                rset_supermob(room);
                for (iNest = 0; iNest < MAX_NEST; iNest++)
                        rgObjNest[iNest] = NULL;

                found = TRUE;
                for (;;)
                {
                        char      letter;
                        char     *word;

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

                        if (letter != '#')
                        {
                                bug("%s", "read_obj_file: # not found.");
                                break;
                        }

                        word = fread_word(fp);
                        if (!str_cmp(word, "OBJECT"))   /* Objects  */
                                fread_obj(supermob, fp, OS_CARRY);
                        else if (!str_cmp(word, "END")) /* Done     */
                                break;
                        else
                        {
                                bug("read_obj_file: bad section: %s", word);
                                break;
                        }
                }
                FCLOSE(fp);
                unlink(fname);
                for (tobj = supermob->first_carrying; tobj; tobj = tobj_next)
                {
                        tobj_next = tobj->next_content;
#ifdef OVERLANDCODE
                        if (IS_OBJ_STAT(tobj, ITEM_ONMAP))
                        {
                                SET_ACT_FLAG(supermob, ACT_ONMAP);
                                supermob->map = tobj->map;
                                supermob->x = tobj->x;
                                supermob->y = tobj->y;
                        }
#endif
                        obj_from_char(tobj);
#ifndef OVERLANDCODE
                        obj_to_room(tobj, room);
#else
                        obj_to_room(tobj, room, supermob);
                        REMOVE_ACT_FLAG(supermob, ACT_ONMAP);
                        supermob->map = -1;
                        supermob->x = -1;
                        supermob->y = -1;
#endif
                }
                release_supermob();
        }
        else
                log_string("Cannot open obj file");

        return;
}

void load_obj_files(void)
{
        DIR      *dp;
        struct dirent *dentry;
        char      directory_name[100];

        log_string("World state: loading objs");
        snprintf(directory_name, 100, "%s", HOTBOOT_DIR);
        dp = opendir(directory_name);
        dentry = readdir(dp);
        while (dentry)
        {
                /*
                 * Added by Tarl 3 Dec 02 because we are now using CVS 
                 */
                if (!str_cmp(dentry->d_name, "CVS"))
                {
                        dentry = readdir(dp);
                        continue;
                }
                if (dentry->d_name[0] != '.')
                        read_obj_file(directory_name, dentry->d_name);
                dentry = readdir(dp);
        }
        closedir(dp);
        return;
}

void load_world(CHAR_DATA * ch)
{
        FILE     *mobfp;
        FILE     *shipfp;
        char      file1[256];
        char      file2[256];
        char     *word;
        int       done = 0;
        bool      mobfile = FALSE;
        bool      shipfile = FALSE;

        snprintf(file1, 256, "%s%s", SYSTEM_DIR, MOB_FILE);
        if ((mobfp = fopen(file1, "r")) == NULL)
        {
                bug("%s", "load_world: fopen mob file");
                perror(file1);
        }
        else
                mobfile = TRUE;

        snprintf(file2, 256, "%s%s", SYSTEM_DIR, SHIP_FILE);
        if ((shipfp = fopen(file2, "r")) == NULL)
        {
                bug("%s", "load_world: fopen ship file");
                perror(file1);
        }
        else
                shipfile = TRUE;

        if (mobfile)
        {
                log_string("World state: loading mobs");
                while (done == 0)
                {
                        if (feof(mobfp))
                                done++;
                        else
                        {
                                word = fread_word(mobfp);
                                if (str_cmp(word, "#END"))
                                        load_mobile(mobfp);
                                else
                                        done++;
                        }
                }
                FCLOSE(mobfp);
        }

        load_obj_files();

        if (shipfile)
        {
                done = 0;
                log_string("World state: loading ships");
                while (done == 0)
                {
                        if (feof(shipfp))
                                done++;
                        else
                        {
                                word = fread_word(shipfp);
                                if (str_cmp(word, "#END"))
                                        load_ship(shipfp);
                                else
                                        done++;
                        }
                }
                FCLOSE(shipfp);
        }



        /*
         * Once loaded, the data needs to be purged in the event it causes a crash so that it won't try to reload 
         */
        unlink(file1);
        unlink(file2);
        return;
}

/*  Warm reboot stuff, gotta make sure to thank Erwin for this :) */
void do_hotboot(CHAR_DATA * ch, char *argument)
{
        FILE     *fp;
        CHAR_DATA *victim = NULL;
        DESCRIPTOR_DATA *d, *de_next;
        char      buf[100], buf2[100], buf3[100], buf4[100], buf5[100],
                buf6[100];
        extern int control;
        int       count = 0;
        bool      found = FALSE;

        for (d = first_descriptor; d; d = d->next)
        {
                if ((d->connected == CON_PLAYING
                     || d->connected == CON_EDITING)
                    && (victim = d->character) != NULL && !IS_NPC(victim)
                    && victim->in_room && victim->fighting
                    && victim->top_level >= 1
                    && victim->top_level <= MAX_LEVEL)
                {
                        found = TRUE;
                        count++;
                }
        }

        if (found)
        {
                ch_printf(ch,
                          "Cannot hotboot at this time. There are %d combats in progress.\n\r",
                          count);
                return;
        }

        found = FALSE;
        for (d = first_descriptor; d; d = d->next)
        {
                if (d->connected == CON_EDITING && d->character)
                {
                        found = TRUE;
                        break;
                }
        }

        if (found)
        {
                send_to_char
                        ("Cannot hotboot at this time. Someone is using the line editor.\n\r",
                         ch);
                return;
        }

        sprintf(log_buf, "Hotboot initiated by %s.", ch->name);
        log_string(log_buf);

        fp = fopen(HOTBOOT_FILE, "w");

        if (!fp)
        {
                send_to_char("Hotboot file not writeable, aborted.\n\r", ch);
                bug("Could not write to hotboot file: %s. Hotboot aborted.",
                    HOTBOOT_FILE);
                perror("do_copyover:fopen");
                return;
        }

        /*
         * And this one here will save the status of all objects and mobs in the game.
         * * This really should ONLY ever be used here. The less we do stuff like this the better.
         */
        save_world(ch);

#ifdef IMC
        imc_shutdown(FALSE);
#endif

#ifdef OLC_SHUTTLE
        {
                SHUTTLE_DATA *tshuttle;

                for (tshuttle = first_shuttle; tshuttle;
                     tshuttle = tshuttle->next)
                        save_shuttle(tshuttle);
        }
#endif

        log_string("Saving player files and connection states....");
        if (ch && ch->desc)
                write_to_descriptor(ch->desc->descriptor, "\e[0m", 0);
        sprintf(buf, "\n\rYou feel a great disturbance in the Force.");
        /*
         * For each playing descriptor, save its state 
         */
        for (d = first_descriptor; d; d = de_next)
        {
                CHAR_DATA *och = CH(d);

                de_next = d->next;  /* We delete from the list , so need to save this */
                if (!d->character || d->connected < CON_PLAYING)    /* drop those logging on */
                {
                        write_to_descriptor(d->descriptor,
                                            "\n\rSorry, we are rebooting. Come back in a few minutes.\n\r",
                                            0);
                        close_socket(d, FALSE); /* throw'em out */
                }
                else
                {
/* 			For test purposes
			flush_buffer(d, TRUE);*/
                        fprintf(fp, "%d %d %d %d %s %s\n", d->descriptor,
                                och->in_room->vnum, d->port, d->idle,
                                och->name, d->host);
                        /*
                         * One of two places this gets changed 
                         */
                        och->pcdata->hotboot = TRUE;
                        save_char_obj(och);
                        write_to_descriptor(d->descriptor, buf, 0);
                }
        }

        fprintf(fp, "%s", "-1");
        FCLOSE(fp);

#ifdef I3
        if (I3_is_connected())
        {
                I3_savechanlist();
                I3_savemudlist();
                I3_savehistory();
        }
#endif

        /*
         * added this in case there's a need to debug the contents of the various files 
         */
        if (argument && !str_cmp(argument, "debug"))
        {
                log_string("Hotboot debug - Aborting before execl");
                return;
        }

        log_string("Executing hotboot....");
        /*
         * Close reserve and other always-open files and release other resources 
         */
        FCLOSE(fpReserve);
        FCLOSE(fpLOG);

        /*
         * exec - descriptors are inherited 
         */
        snprintf(buf, 100, "%d", port);
        snprintf(buf2, 100, "%d", control);
        snprintf(buf3, 100, "%d", 0);
        snprintf(buf4, 100, "%d", 0);
        snprintf(buf5, 100, "%d", 0);
#ifdef I3
        snprintf(buf6, 100, "%d", I3_socket);
#else
        strncpy(buf6, "-1", 100);
#endif

        /*
         * Uncomment this bfd_close line if you've installed the dlsym snippet, you'll need it. 
         */
        // dlclose( sysdata.dlHandle );
        execl(EXE_FILE, "swreality", buf, "hotboot", buf2, buf3, buf4,
              buf5, buf6, (char *) NULL);

        /*
         * Failed - sucessful exec will not return 
         */
        perror("do_hotboot: execl");

        /*
         * Here you might want to reopen fpReserve 
         */
        /*
         * Since I'm a neophyte type guy, I'll assume this is a good idea and cut and past from main()  
         */

        if ((fpReserve = fopen(NULL_FILE, "r")) == NULL)
        {
                perror(NULL_FILE);
                exit(1);
        }
        if ((fpLOG = fopen(NULL_FILE, "r")) == NULL)
        {
                perror(NULL_FILE);
                exit(1);
        }
        bug("%s", "Hotboot execution failed!!");
        send_to_char("Hotboot FAILED!\n\r", ch);
}

/* Recover from a hotboot - load players */
void hotboot_recover(void)
{
        DESCRIPTOR_DATA *d = NULL;
        FILE     *fp;
        char      name[100];
        char      host[MAX_STRING_LENGTH];
        int       desc, room, dport, idle, maxp = 0;
        bool      fOld;

        fp = fopen(HOTBOOT_FILE, "r");

        if (!fp)    /* there are some descriptors open which will hang forever then ? */
        {
                perror("hotboot_recover: fopen");
                bug("%s", "Hotboot file not found. Exitting.");
                exit(1);
        }

        unlink(HOTBOOT_FILE);   /* In case something crashes - doesn't prevent reading */
        for (;;)
        {
                d = NULL;

                fscanf(fp, "%d %d %d %d %s %s\n", &desc, &room, &dport, &idle,
                       name, host);

                if (desc == -1 || feof(fp))
                        break;

                if (!str_cmp(name, "maxp") || !str_cmp(host, "maxp"))
                {
                        maxp = idle;
                        continue;
                }

                /*
                 * Write something, and check if it goes error-free 
                 */
                if (!write_to_descriptor
                    (desc, "\n\rThe Force swirls around you.\n\r", 0))
                {
                        close(desc);    /* nope */
                        continue;
                }

                CREATE(d, DESCRIPTOR_DATA, 1);

                d->next = NULL;
                d->descriptor = desc;
                d->connected = CON_GET_NAME;
                d->outsize = 2000;
                d->idle = 0;
                d->lines = 0;
                d->scrlen = 24;
                d->newstate = 0;
                d->prevcolor = 0x08;

                CREATE(d->outbuf, char, d->outsize);

                d->host = STRALLOC(host);
                d->port = dport;
                d->idle = idle;
                LINK(d, first_descriptor, last_descriptor, next, prev);
                d->connected = CON_COPYOVER_RECOVER;    /* negative so close_socket will cut them off */

                /*
                 * Now, find the pfile 
                 */
                fOld = load_char_obj(d, name, FALSE, TRUE);

                if (!fOld)  /* Player file not found?! */
                {
                        write_to_descriptor(d->descriptor,
                                            "\n\rSomehow, your character was lost during hotboot. Contact the immortals ASAP.\n\r",
                                            0);
                        close_socket(d, FALSE);
                }
                else    /* ok! */
                {
                        write_to_descriptor(d->descriptor,
                                            "Suddenly, you remember nothing as the Force continues into the Galaxy.\n\r",
                                            0);
                        d->character->in_room = get_room_index(room);
                        if (!d->character->in_room)
                                d->character->in_room =
                                        get_room_index(ROOM_VNUM_TEMPLE);

                        /*
                         * Insert in the char_list 
                         */
                        LINK(d->character, first_char, last_char, next, prev);

                        char_to_room(d->character, d->character->in_room);
                        act(AT_MAGIC, "You appear in a swirl of the Force!",
                            d->character, NULL, NULL, TO_CHAR);
                        act(AT_MAGIC, "$n appears in a swrrl of the Force!",
                            d->character, NULL, NULL, TO_ROOM);
                        d->connected = CON_PLAYING;
                        if (++num_descriptors > sysdata.maxplayers)
                                sysdata.maxplayers = num_descriptors;
#ifdef AUTO_AUTH
                        check_auth_state(d->character); /* new auth */
#endif
                }
        }
        FCLOSE(fp);
        if (maxp > sysdata.maxplayers)
                sysdata.maxplayers = maxp;
        log_string("Hotboot recovery complete.");
        return;
}