muddy/
muddy/CVS/
muddy/area/
muddy/area/CVS/
muddy/clans/CVS/
muddy/classes/CVS/
muddy/doc/
muddy/doc/CVS/
muddy/etc/CVS/
muddy/etc/i3/
muddy/etc/i3/CVS/
muddy/imc/CVS/
muddy/lang/CVS/
muddy/licenses/CVS/
muddy/msgdb/CVS/
muddy/new/CVS/
muddy/notes/
muddy/player/
muddy/races/CVS/
muddy/religions/CVS/
muddy/src/CVS/
muddy/src/comm/CVS/
muddy/src/db/CVS/
muddy/src/intermud/
muddy/src/intermud/CVS/
muddy/src/irc/CVS/
muddy/src/olc/CVS/
/* $Id: olc_save.c,v 1.666 2004/09/20 10:50:30 shrike Exp $ */

/************************************************************************************
 *    Copyright 2004 Astrum Metaphora consortium                                    *
 *                                                                                  *
 *    Licensed under the Apache License, Version 2.0 (the "License");               *
 *    you may not use this file except in compliance with the License.              *
 *    You may obtain a copy of the License at                                       *
 *                                                                                  *
 *    http://www.apache.org/licenses/LICENSE-2.0                                    *
 *                                                                                  *
 *    Unless required by applicable law or agreed to in writing, software           *
 *    distributed under the License is distributed on an "AS IS" BASIS,             *
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.      *
 *    See the License for the specific language governing permissions and           *
 *    limitations under the License.                                                *
 *                                                                                  *
 ************************************************************************************/
/************************************************************************************
 *     ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR           *
 *     ANATOLIA has been brought to you by ANATOLIA consortium                      *
 *       Serdar BULUT {Chronos}         bulut@rorqual.cc.metu.edu.tr                *
 *       Ibrahim Canpunar  {Asena}      canpunar@rorqual.cc.metu.edu.tr             *
 *       Murat BICER  {KIO}             mbicer@rorqual.cc.metu.edu.tr               *
 *       D.Baris ACAR {Powerman}        dbacar@rorqual.cc.metu.edu.tr               *
 *     By using this code, you have agreed to follow the terms of the               *
 *     ANATOLIA license, in the file Anatolia/anatolia.licence                      *
 ***********************************************************************************/

/************************************************************************************
 *  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.                                                           *
 ************************************************************************************/

/************************************************************************************
*       ROM 2.4 is copyright 1993-1995 Russ Taylor                                  *
*       ROM has been brought to you by the ROM consortium                           *
*           Russ Taylor (rtaylor@pacinfo.com)                                       *
*           Gabrielle Taylor (gtaylor@pacinfo.com)                                  *
*           Brian Moore (rom@rom.efn.org)                                           *
*       By using this code, you have agreed to follow the terms of the              *
*       ROM license, in the file Rom24/doc/rom.license                              *
*************************************************************************************/

/************************************************************************************
 * Copyright (c) 1998 fjoe <fjoe@iclub.nsu.ru>                                      *
 * All rights reserved.                                                             *
 *                                                                                  *
 * Redistribution and use in source and binary forms, with or without               *
 * modification, are permitted provided that the following conditions               *
 * are met:                                                                         *
 * 1. Redistributions of source code must retain the above copyright                *
 *    notice, this list of conditions and the following disclaimer.                 *
 * 2. Redistributions in binary form must reproduce the above copyright             *
 *    notice, this list of conditions and the following disclaimer in the           *
 *    documentation and/or other materials provided with the distribution.          *
 *                                                                                  *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND           *
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE            *
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE       *
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE          *
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL       *
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS          *
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)            *
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT       *
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY        *
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF           *
 * SUCH DAMAGE.                                                                     *
 ************************************************************************************/
 
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include "merc.h"
#include "obj_prog.h"
#include "olc.h"
#include "db/db.h"
#include "db/lang.h"
#include "db/socials.h"
#include "religion.h"
#include "price.h"
#include "riddle.h"
#include "material.h"
#include "class.h"

#define DIF(a,b) (~((~a)|(b)))

/*
 *  Verbose writes reset data in plain english into the comments
 *  section of the resets.  It makes areas considerably larger but
 *  may aid in debugging.
 */
#define VERBOSE

static void save_print(CHAR_DATA *ch, const char *format, ...);

extern MPCODE *get_prog_index(int vnum, int type);

/*****************************************************************************
 Name:      save_area_list
 Purpose:   Saves the listing of files to be loaded at startup.
 Called by: do_asave(olc_save.c).
 ****************************************************************************/
void save_area_list()
{
    FILE *fp;
    AREA_DATA *pArea;

    if ((fp = dfopen(AREA_PATH, AREA_LIST, "w")) == NULL)
    {
        bug("Save_area_list: fopen", 0);
        perror(AREA_LIST);
        return;
    }

    for (pArea = area_first; pArea; pArea = pArea->next)
        if (!IS_SET(pArea->flags, AREA_TEMPORARY))
            fprintf(fp, "%s\n", pArea->file_name);

    fprintf(fp, "$\n");
    fclose(fp);
}

void save_mobprogs(FILE *fp, AREA_DATA *pArea)
{
    MPCODE *mpcode;
    int i;
    bool found = FALSE;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
    {
        if ((mpcode = mpcode_lookup(i)) != NULL)
        {
            if (!found)
            {
                fprintf(fp, "#MOBPROGS\n");
                found = TRUE;
            }
            fprintf(fp, "#%d\n", i);
            fwrite_string(fp, NULL, mpcode->code);
        }
    }

    if (found)
        fprintf(fp,"#0\n\n");
}

void save_objprogs( FILE *fp, AREA_DATA *pArea )
{
    MPCODE *pOprog;
    int i;

    fprintf(fp, "#OBJPROGS\n");

    for ( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
    {
        if ((pOprog = get_prog_index(i, PRG_OPROG)) != NULL)
        {
            fprintf(fp, "#%d\n", i);
            fprintf(fp, "%s~\n", fix_string(pOprog->code));
        }
    }

    fprintf(fp,"#0\n\n");
    return;
}

void save_roomprogs( FILE *fp, AREA_DATA *pArea )
{
    MPCODE *pRprog;
    int i;

    fprintf(fp, "#ROOMPROGS\n");

    for ( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
    {
        if ( (pRprog = get_prog_index(i,PRG_RPROG) ) != NULL)
        {
            fprintf(fp, "#%d\n", i);
            fprintf(fp, "%s~\n", fix_string(pRprog->code));
        }
    }

    fprintf(fp,"#0\n\n");
    return;
}


/*****************************************************************************
 Name:      save_mobile
 Purpose:   Save one mobile to file, new format -- Hugin
 Called by: save_mobiles (below).
 ****************************************************************************/
void save_mobile(FILE *fp, MOB_INDEX_DATA *pMobIndex)
{
    race_t *r = race_lookup(pMobIndex->race);
    MPTRIG *mptrig;
    flag64_t temp;
    int i;

    if (r == NULL)
    {
        log_printf("save_mobile: %d: unknown race", pMobIndex->race);
        return;
    }

    fprintf(fp, "#%d\n",    pMobIndex->vnum);
    fwrite_string(fp, NULL, pMobIndex->name);
    mlstr_fwrite(fp, NULL,  pMobIndex->short_descr);
    mlstr_fwrite(fp, NULL,  pMobIndex->long_descr);
    mlstr_fwrite(fp, NULL,  pMobIndex->description);
    fwrite_string(fp, NULL, r->name);
    fprintf(fp, "%s ",      format_flags(pMobIndex->act & ~r->act));
    fprintf(fp, "%s ",      format_flags(pMobIndex->affected_by & ~r->aff));
    fprintf(fp, "%d %d\n",  pMobIndex->alignment , pMobIndex->group);
    fprintf(fp, "%d ",      pMobIndex->level);
    fprintf(fp, "%d ",      pMobIndex->hitroll);
    fprintf(fp, "%dd%d+%d ",    pMobIndex->hit[DICE_NUMBER],
            pMobIndex->hit[DICE_TYPE],
            pMobIndex->hit[DICE_BONUS]);
    fprintf(fp, "%dd%d+%d ",    pMobIndex->mana[DICE_NUMBER],
            pMobIndex->mana[DICE_TYPE],
            pMobIndex->mana[DICE_BONUS]);
    fprintf(fp, "%dd%d+%d ",    pMobIndex->damage[DICE_NUMBER],
            pMobIndex->damage[DICE_TYPE],
            pMobIndex->damage[DICE_BONUS]);
    fprintf(fp, "%s\n",     attack_table[pMobIndex->dam_type].name);
    fprintf(fp, "%d %d %d %d\n",
            pMobIndex->ac[AC_PIERCE] / 10,
            pMobIndex->ac[AC_BASH]   / 10,
            pMobIndex->ac[AC_SLASH]  / 10,
            pMobIndex->ac[AC_EXOTIC] / 10);
    fprintf(fp, "%s ",      format_flags(pMobIndex->off_flags & ~r->off));
    fprintf(fp, "%s %s %s %d\n",
            flag_string(position_table, pMobIndex->start_pos),
            flag_string(position_table, pMobIndex->default_pos),
            flag_string(sex_table, pMobIndex->sex),
            pMobIndex->wealth);
    fprintf(fp, "%s ",      format_flags(pMobIndex->form & ~r->form));
    fprintf(fp, "%s ",      format_flags(pMobIndex->parts & ~r->parts));

    fprintf(fp, "%d ",      pMobIndex->size);
    fprintf(fp, "%s\n", IS_NULLSTR(pMobIndex->material) ? pMobIndex->material : "unknown");

/* save diffs */
    if ((temp = DIF(r->act, pMobIndex->act)))
        fprintf(fp, "F act %s\n", format_flags(temp));

    if ((temp = DIF(r->aff, pMobIndex->affected_by)))
        fprintf(fp, "F aff %s\n", format_flags(temp));

    if ((temp = DIF(r->off, pMobIndex->off_flags)))
        fprintf(fp, "F off %s\n", format_flags(temp));

    if ((temp = DIF(r->form, pMobIndex->form)))
        fprintf(fp, "F for %s\n", format_flags(temp));

    if ((temp = DIF(r->parts, pMobIndex->parts)))
        fprintf(fp, "F par %s\n", format_flags(temp));

    for (mptrig = pMobIndex->mptrig_list; mptrig; mptrig = mptrig->next)
    {
        fprintf(fp, "M %s %d %s~\n",
                flag_string(mptrig_types, mptrig->type), mptrig->vnum,
                fix_string(mptrig->phrase));
    }

    if (pMobIndex->clan)
        fwrite_string(fp, "C", clan_name(pMobIndex->clan));
    if (pMobIndex->invis_level)
        fprintf(fp, "I %d\n", pMobIndex->invis_level);
    if (pMobIndex->immunes)
        fwrite_string(fp, "Immunes", flag_string(imm_flags, pMobIndex->immunes));

    for (i = 0; i < MAX_DAM; i++)
    if (pMobIndex->resists[i])
    {
        fprintf(fp, "R %s %d\n",
            flag_string(dam_flags, i), pMobIndex->resists[i]);
    }

    if (pMobIndex->listen_data)
    {
        fprintf(fp, "L ");
        mlstr_fwrite(fp, NULL,  pMobIndex->listen_data);
    }

//  if (pMobIndex->fvnum)
//      fprintf(fp, "V %d\n", pMobIndex->fvnum);
}

/*****************************************************************************
 Name:      save_mobiles
 Purpose:   Save #MOBILES secion of an area file.
 Called by: save_area(olc_save.c).
 Notes:         Changed for ROM OLC.
 ****************************************************************************/
void save_mobiles(FILE *fp, AREA_DATA *pArea)
{
    int i;
    MOB_INDEX_DATA *pMob;
    bool found = FALSE;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pMob = get_mob_index(i)))
        {
            if (!found)
            {
                fprintf(fp, "#MOBILES\n");
                found = TRUE;
            }
            save_mobile(fp, pMob);
        }

    if (found)
        fprintf(fp, "#0\n\n");
}

/*****************************************************************************
 Name:      save_object
 Purpose:   Save one object to file.
                new ROM format saving -- Hugin
 Called by: save_objects (below).
 ****************************************************************************/
void save_object(FILE *fp, OBJ_INDEX_DATA *pObjIndex)
{
    char letter;
    AFFECT_DATA *pAf;
    ED_DATA *pEd;
    MPTRIG *oprogs;

    fprintf(fp, "#%d\n",    pObjIndex->vnum);
    fwrite_string(fp, NULL, pObjIndex->name);
    mlstr_fwrite(fp, NULL,  pObjIndex->short_descr);
    mlstr_fwrite(fp, NULL,  pObjIndex->description);
    fwrite_string(fp, NULL, pObjIndex->material);
    fprintf(fp, "%s ",      flag_string(item_types, pObjIndex->item_type));
    fprintf(fp, "%s ",      format_flags(pObjIndex->extra_flags &
                                         ~(ITEM_ENCHANTED |
                                           ITEM_OLDSTYLE)));
    fprintf(fp, "%s\n",     format_flags(pObjIndex->wear_flags));

/*
 *  Using format_flags to write most values gives a strange
 *  looking area file, consider making a case for each
 *  item type later.
 */

    switch (pObjIndex->item_type)
    {
    default:
        fprintf(fp, "%s %s %s %s %s\n",
                format_flags(pObjIndex->value[0]),
                format_flags(pObjIndex->value[1]),
                format_flags(pObjIndex->value[2]),
                format_flags(pObjIndex->value[3]),
                format_flags(pObjIndex->value[4]));
        break;

    case ITEM_MONEY:
    case ITEM_ARMOR:
    case ITEM_RIDDLE:
    case ITEM_SCABBARD:
        fprintf(fp, "%d %d %d %d %d\n",
                pObjIndex->value[0],
                pObjIndex->value[1],
                pObjIndex->value[2],
                pObjIndex->value[3],
                pObjIndex->value[4]);
        break;

    case ITEM_DRINK_CON:
    case ITEM_FOUNTAIN:
        fprintf(fp, "%d %d '%s' %d %d\n",
                pObjIndex->value[0],
                pObjIndex->value[1],
                //liq_table[pObjIndex->value[2]].liq_name,
                liquid_name(pObjIndex->value[2]),
                pObjIndex->value[3],
                pObjIndex->value[4]);
        break;

    case ITEM_CONTAINER:
        fprintf(fp, "%d %s %d %d %d\n",
                pObjIndex->value[0],
                format_flags(pObjIndex->value[1]),
                pObjIndex->value[2],
                pObjIndex->value[3],
                pObjIndex->value[4]);
        break;

    case ITEM_WEAPON:
        fprintf(fp, "%s %d %d %s %s\n",
                flag_string(weapon_class, pObjIndex->value[0]),
                pObjIndex->value[1],
                pObjIndex->value[2],
                attack_table[pObjIndex->value[3]].name,
                format_flags(pObjIndex->value[4]));
        break;

    case ITEM_PILL:
    case ITEM_POTION:
    case ITEM_SCROLL:
        fprintf(fp, "%d '%s' '%s' '%s' '%s'\n",
/* no negative numbers */
                pObjIndex->value[0] > 0 ? pObjIndex->value[0] : 0,
                pObjIndex->value[1] != -1 ?
                skill_name(pObjIndex->value[1]) : str_empty,
                pObjIndex->value[2] != -1 ?
                skill_name(pObjIndex->value[2]) : str_empty,
                pObjIndex->value[3] != -1 ?
                skill_name(pObjIndex->value[3]) : str_empty,
                pObjIndex->value[4] != -1 ?
                skill_name(pObjIndex->value[4]) : str_empty);
        break;

    case ITEM_STAFF:
    case ITEM_WAND:
        fprintf(fp, "%d %d %d '%s' %d\n",
                pObjIndex->value[0],
                pObjIndex->value[1],
                pObjIndex->value[2],
                pObjIndex->value[3] != -1 ?
                skill_name(pObjIndex->value[3]) : str_empty,
                pObjIndex->value[4]);
        break;
    case ITEM_PORTAL:
        fprintf(fp, "%s %s %s %d %s\n",
                format_flags(pObjIndex->value[0]),
                format_flags(pObjIndex->value[1]),
                format_flags(pObjIndex->value[2]),
                pObjIndex->value[3],
                format_flags(pObjIndex->value[4]));
        break;
    case ITEM_LIGHT:
    case ITEM_TATTOO:
    case ITEM_TREASURE:
        fprintf(fp, "%s %s %d %s %s\n",
                format_flags(pObjIndex->value[0]),
                format_flags(pObjIndex->value[1]),
                pObjIndex->value[2],
                format_flags(pObjIndex->value[3]),
                format_flags(pObjIndex->value[4]));
        break;
    }

    fprintf(fp, "%d ", pObjIndex->level);
    fprintf(fp, "%d ", pObjIndex->weight);
    fprintf(fp, "%d ", pObjIndex->cost);

    if (pObjIndex->condition >       90) letter = 'P';
    else if (pObjIndex->condition >  75) letter = 'G';
    else if (pObjIndex->condition >  50) letter = 'A';
    else if (pObjIndex->condition >  25) letter = 'W';
    else if (pObjIndex->condition >  10) letter = 'D';
    else if (pObjIndex->condition >   0) letter = 'B';
    else                                 letter = 'R';

    fprintf(fp, "%c\n", letter);

    for (pAf = pObjIndex->affected; pAf; pAf = pAf->next)
    {
        if (pAf->where == TO_OBJECT || pAf->bitvector == 0)
            fprintf(fp, "A\n%d %d\n",  pAf->location, pAf->modifier);
        else
        {
            fprintf(fp, "F\n");

            switch (pAf->where)
            {
            case TO_AFFECTS:
                fprintf(fp, "A ");
                break;
            case TO_RESIST:
                fprintf(fp, "R ");
                break;
            case TO_IMMUNE:
                fprintf(fp, "I ");
                break;
            default:
                log_printf("olc_save: vnum %d: "
                           "invalid affect->where: %d",
                           pObjIndex->vnum, pAf->where);
                break;
            }

            fprintf(fp, "%d %d %s\n", pAf->location, pAf->modifier,
                    pAf->where == TO_RESIST
                ? flag_string(dam_flags, pAf->bitvector)
                : format_flags(pAf->bitvector));
        }
    }

    for (pEd = pObjIndex->ed; pEd; pEd = pEd->next)
        ed_fwrite(fp, pEd);

    if (pObjIndex->clan)
        fwrite_string(fp, "C", clan_name(pObjIndex->clan));
    fprintf(fp, "G %s\n", flag_string(gender_table, pObjIndex->gender));

    if (pObjIndex->riddle)
        fprintf(fp, "D %d\n",     pObjIndex->riddle);

    if (pObjIndex->size)
        fprintf(fp, "S %d\n",     pObjIndex->size);

    for (oprogs = pObjIndex->oprogs; oprogs; oprogs = oprogs->next)
    {
        fprintf(fp, "O %s %d %s~\n",
                flag_string(oprog_flags, oprogs->type), oprogs->vnum,
                fix_string(oprogs->phrase));
    }

}

/*****************************************************************************
 Name:      save_objects
 Purpose:   Save #OBJECTS section of an area file.
 Called by: save_area(olc_save.c).
 Notes:         Changed for ROM OLC.
 ****************************************************************************/
void save_objects(FILE *fp, AREA_DATA *pArea)
{
    int i;
    OBJ_INDEX_DATA *pObj;
    bool found = FALSE;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pObj = get_obj_index(i)))
        {
            if (!found)
            {
                fprintf(fp, "#OBJECTS\n");
                found = TRUE;
            }
            save_object(fp, pObj);
        }

    if (found)
        fprintf(fp, "#0\n\n");
}

static int exitcmp(const void *p1, const void *p2)
{
    return(*(EXIT_DATA**)p1)->orig_door - (*(EXIT_DATA**)p2)->orig_door;
}

void save_room(FILE *fp, ROOM_INDEX_DATA *pRoomIndex)
{
    int door;
    ED_DATA *pEd;
    EXIT_DATA *pExit;
    EXIT_DATA *exit[MAX_DIR];
    int max_door;
    MPTRIG *rprogs;

    fprintf(fp, "#%d\n",    pRoomIndex->vnum);
    mlstr_fwrite(fp, NULL,  pRoomIndex->name);
    mlstr_fwrite(fp, NULL,  pRoomIndex->description);
    fprintf(fp, "%d ",  pRoomIndex->space);
    fprintf(fp, "%s ",  format_flags(pRoomIndex->room_flags));
    fprintf(fp, "%s\n", flag_string(sector_types,
                                    pRoomIndex->sector_type));

    for (pEd = pRoomIndex->ed; pEd; pEd = pEd->next)
        ed_fwrite(fp, pEd);

    /* sort exits (to minimize diffs) */
    for (max_door = 0, door = 0; door < MAX_DIR; door++)
        if ((pExit = pRoomIndex->exit[door]))
            exit[max_door++] = pExit;
    qsort(exit, max_door, sizeof(*exit), exitcmp);

    for (door = 0; door < max_door; door++)
    {
        pExit = exit[door];
        if (pExit->to_room.r)
        {

            /* HACK : TO PREVENT EX_LOCKED etc without EX_ISDOOR
               to stop booting the mud */
            if (IS_SET(pExit->rs_flags, EX_CLOSED)
                ||  IS_SET(pExit->rs_flags, EX_LOCKED)
                ||  IS_SET(pExit->rs_flags, EX_PICKPROOF)
                ||  IS_SET(pExit->rs_flags, EX_NOPASS)
                ||  IS_SET(pExit->rs_flags, EX_EASY)
                ||  IS_SET(pExit->rs_flags, EX_HARD)
                ||  IS_SET(pExit->rs_flags, EX_INFURIATING)
                ||  IS_SET(pExit->rs_flags, EX_NOCLOSE)
                ||  IS_SET(pExit->rs_flags, EX_NOLOCK)
                ||  IS_SET(pExit->rs_flags, EX_INVIS) )
                SET_BIT(pExit->rs_flags, EX_ISDOOR);
            else
                REMOVE_BIT(pExit->rs_flags, EX_ISDOOR);

            fprintf(fp, "D%d\n",      pExit->orig_door);
            mlstr_fwrite(fp, NULL,    pExit->description);
            fprintf(fp, "%s~\n",      pExit->keyword);
            fprintf(fp, "%s %d %d %d\n",
                    format_flags(pExit->rs_flags | EX_BITVAL),
                    pExit->key, pExit->to_room.r->vnum,
                    pExit->size);
        }
    }

    if (pRoomIndex->mana_rate != 100 || pRoomIndex->heal_rate != 100)
        fprintf (fp, "M %d H %d\n", pRoomIndex->mana_rate,
                 pRoomIndex->heal_rate);

    if (!IS_NULLSTR(pRoomIndex->owner))
        fprintf (fp, "O %s~\n" , pRoomIndex->owner);

    if (pRoomIndex->clan)
        fwrite_string(fp, "C", clan_name(pRoomIndex->clan));

    for (rprogs = pRoomIndex->rprogs; rprogs; rprogs = rprogs->next)
    {
        fprintf(fp, "R %s %d %s~\n",
                flag_string(rprog_flags, rprogs->type), rprogs->vnum,
                fix_string(rprogs->phrase));
    }

    fprintf(fp, "S\n");
}

/*****************************************************************************
 Name:      save_rooms
 Purpose:   Save #ROOMS section of an area file.
 Called by: save_area(olc_save.c).
 ****************************************************************************/
void save_rooms(FILE *fp, AREA_DATA *pArea)
{
    ROOM_INDEX_DATA *pRoomIndex;
    bool found = FALSE;
    int i;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pRoomIndex = get_room_index(i)))
        {
            if (!found)
            {
                fprintf(fp, "#ROOMS\n");
                found = TRUE;
            }
            save_room(fp, pRoomIndex);
        }

    if (found)
        fprintf(fp, "#0\n\n");
}

void save_special(FILE *fp, MOB_INDEX_DATA *pMobIndex)
{
#if defined(VERBOSE)
    fprintf(fp, "M %d %s\t* %s\n",
            pMobIndex->vnum,
            spec_name(pMobIndex->spec_fun),
            mlstr_mval(pMobIndex->short_descr));
#else
    fprintf(fp, "M %d %s\n",
            pMobIndex->vnum, spec_name(pMobIndex->spec_fun));
#endif
}

/*****************************************************************************
 Name:      save_specials
 Purpose:   Save #SPECIALS section of area file.
 Called by: save_area(olc_save.c).
 ****************************************************************************/
void save_specials(FILE *fp, AREA_DATA *pArea)
{
    int i;
    MOB_INDEX_DATA *pMobIndex;
    bool found = FALSE;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pMobIndex = get_mob_index(i))
            &&  pMobIndex->spec_fun)
        {
            if (!found)
            {
                fprintf(fp, "#SPECIALS\n");
                found = TRUE;
            }
            save_special(fp, pMobIndex);
        }

    if (found)
        fprintf(fp, "S\n\n");
}

/*
 * This function is obsolete.  It it not needed but has been left here
 * for historical reasons.  It is used currently for the same reason.
 *
 * I don't think it's obsolete in ROM -- Hugin.
 */
void save_door_reset(FILE *fp, ROOM_INDEX_DATA *pRoomIndex, EXIT_DATA *pExit)
{
#if defined(VERBOSE)
    fprintf(fp,
            "D 0 %d %d %d\t* %s: door to the %s: %s\n",
            pRoomIndex->vnum,
            pExit->orig_door,
            IS_SET(pExit->rs_flags, EX_LOCKED) ? 2 : 1,
            mlstr_mval(pRoomIndex->name),
            dir_name[pExit->orig_door],
            IS_SET(pExit->rs_flags, EX_LOCKED) ?
            "closed and locked" : "closed");
#else
    fprintf(fp, "D 0 %d %d %d\n",
            pRoomIndex->vnum,
            pExit->orig_door,
            IS_SET(pExit->rs_flags, EX_LOCKED) ? 2 : 1);
#endif
}

void save_reset(FILE *fp, AREA_DATA *pArea,
                ROOM_INDEX_DATA *pRoomIndex, RESET_DATA *pReset)
{
    switch (pReset->command)
    {
    default:
        bug("Save_resets: bad command %c.", pReset->command);
        break;

#if defined(VERBOSE)
    case 'M':
        fprintf(fp, "M 0 %d %d %d %d\t* %s (%s)\n",
                pReset->arg1,
                pReset->arg2,
                pReset->arg3,
                pReset->arg4,
                mlstr_mval(get_mob_index(pReset->arg1)->short_descr),
                mlstr_mval(get_room_index(pReset->arg3)->name));
        break;

    case 'O':
        fprintf(fp, "O 0 %d 0 %d\t* %s (%s)\n",
                pReset->arg1,
                pReset->arg3,
                mlstr_mval(get_obj_index(pReset->arg1)->short_descr),
                mlstr_mval(get_room_index(pReset->arg3)->name));
        break;

    case 'P':
        fprintf(fp, "P 0 %d %d %d %d\t* %s: %s\n",
                pReset->arg1,
                pReset->arg2,
                pReset->arg3,
                pReset->arg4,
                mlstr_mval(get_obj_index(pReset->arg3)->short_descr),
                mlstr_mval(get_obj_index(pReset->arg1)->short_descr));
        break;

    case 'G':
        fprintf(fp, "G 0 %d 0\t\t*\t%s\n",
                pReset->arg1,
                mlstr_mval(get_obj_index(pReset->arg1)->short_descr));
        break;

    case 'E':
        fprintf(fp, "E 0 %d 0 %d\t\t*\t%s: %s\n",
                pReset->arg1,
                pReset->arg3,
                mlstr_mval(get_obj_index(pReset->arg1)->short_descr),
                flag_string(wear_loc_strings, pReset->arg3));
        break;

    case 'D':
        break;

    case 'R':
        pRoomIndex = get_room_index(pReset->arg1);
        fprintf(fp, "R 0 %d %d\t* %s: randomize\n",
                pReset->arg1,
                pReset->arg2,
                mlstr_mval(pRoomIndex->name));
        break;
#else
    case 'M':
        fprintf(fp, "M 0 %d %d %d %d\n",
                pReset->arg1,
                pReset->arg2,
                pReset->arg3,
                pReset->arg4);
        break;

    case 'O':
        fprintf(fp, "O 0 %d 0 %d\n",
                pReset->arg1,
                pReset->arg3);
        break;

    case 'P':
        fprintf(fp, "P 0 %d %d %d %d\n",
                pReset->arg1,
                pReset->arg2,
                pReset->arg3,
                pReset->arg4);
        break;

    case 'G':
        fprintf(fp, "G 0 %d 0\n", pReset->arg1);
        break;

    case 'E':
        fprintf(fp, "E 0 %d 0 %d\n",
                pReset->arg1,
                pReset->arg3);
        break;

    case 'D':
        break;

    case 'R':
        fprintf(fp, "R 0 %d %d\n",
                pReset->arg1,
                pReset->arg2);
        break;
#endif
    }
}

/*****************************************************************************
 Name:      save_resets
 Purpose:   Saves the #RESETS section of an area file.
 Called by: save_area(olc_save.c)
 ****************************************************************************/
void save_resets(FILE *fp, AREA_DATA *pArea)
{
    ROOM_INDEX_DATA *pRoomIndex;
    RESET_DATA *pReset;
    EXIT_DATA *pExit;
    int door;
    bool found = FALSE;
    int i;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pRoomIndex = get_room_index(i)))
            for (door = 0; door < MAX_DIR; door++)
                if ((pExit = pRoomIndex->exit[door])
                    &&  pExit->to_room.r
                    &&  (IS_SET(pExit->rs_flags, EX_CLOSED) ||
                         IS_SET(pExit->rs_flags, EX_LOCKED)))
                {
                    if (!found)
                    {
                        fprintf(fp, "#RESETS\n");
                        found = TRUE;
                    }
                    save_door_reset(fp, pRoomIndex, pExit);
                }

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pRoomIndex = get_room_index(i)))
            for (pReset = pRoomIndex->reset_first; pReset; pReset = pReset->next)
            {
                if (!found)
                {
                    fprintf(fp, "#RESETS\n");
                    found = TRUE;
                }
                save_reset(fp, pArea, pRoomIndex, pReset);
            }

    if (found)
        fprintf(fp, "S\n\n");
}

void save_shop(FILE *fp, MOB_INDEX_DATA *pMobIndex)
{
    SHOP_DATA *pShopIndex;
    int iTrade;

    pShopIndex = pMobIndex->pShop;

    fprintf(fp, "%d ", pShopIndex->keeper);
    for (iTrade = 0; iTrade < MAX_TRADE; iTrade++)
    {
        if (pShopIndex->buy_type[iTrade] != 0)
            fprintf(fp, "%d ", pShopIndex->buy_type[iTrade]);
        else
            fprintf(fp, "0 ");
    }
    fprintf(fp, "%d %d ", pShopIndex->profit_buy, pShopIndex->profit_sell);
    fprintf(fp, "%d %d\n", pShopIndex->open_hour, pShopIndex->close_hour);
}

/*****************************************************************************
 Name:      save_shops
 Purpose:   Saves the #SHOPS section of an area file.
 Called by: save_area(olc_save.c)
 ****************************************************************************/
void save_shops(FILE *fp, AREA_DATA *pArea)
{
    MOB_INDEX_DATA *pMobIndex;
    int i;
    bool found = FALSE;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pMobIndex = get_mob_index(i))
            &&  pMobIndex->pShop)
        {
            if (!found)
            {
                fprintf(fp, "#SHOPS\n");
                found = TRUE;
            }
            save_shop(fp, pMobIndex);
        }

    if (found)
        fprintf(fp, "0\n\n");
}

void save_olimits(FILE *fp, AREA_DATA *pArea)
{
    int i;
    OBJ_INDEX_DATA *pObj;
    bool found = FALSE;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pObj = get_obj_index(i)) != NULL
            &&  pObj->limit != -1)
        {
            if (!found)
            {
                fprintf(fp, "#OLIMITS\n");
                found = TRUE;
            }
            fprintf(fp, "O %d %d\t* %s\n",
                    i, pObj->limit, mlstr_mval(pObj->short_descr));
        }

    if (found)
        fprintf(fp, "S\n\n");
}

void save_omprog(FILE *fp, OBJ_INDEX_DATA *pObjIndex)
{
    int i;

    for (i = 0; i < OPROG_MAX; i++)
        if (pObjIndex->oprogs_old[i] != NULL)
            fprintf(fp, "O %d %s %s\t* `%s'\n",
                    pObjIndex->vnum,
                    optype_table[i],
                    oprog_name_lookup(pObjIndex->oprogs_old[i]),
                    mlstr_mval(pObjIndex->short_descr));
}

void save_omprogs(FILE *fp, AREA_DATA *pArea)
{
    int i;
    OBJ_INDEX_DATA *pObjIndex;
    bool found = FALSE;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pObjIndex = get_obj_index(i)) != NULL
            &&  pObjIndex->oprogs_old)
        {
            if (!found)
            {
                fprintf(fp, "#OMPROGS\n");
                found = TRUE;
            }
            save_omprog(fp, pObjIndex);
        }

    if (found)
        fprintf(fp, "S\n\n");
}

void save_practicers(FILE *fp, AREA_DATA *pArea)
{
    int i;
    MOB_INDEX_DATA *pMobIndex;
    bool found = FALSE;

    for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
        if ((pMobIndex = get_mob_index(i)) != NULL
            &&  pMobIndex->practicer != 0)
        {
            if (!found)
            {
                fprintf(fp, "#PRACTICERS\n");
                found = TRUE;
            }
            fprintf(fp, "M %d %s~\t* %s\n",
                    pMobIndex->vnum,
                    flag_string(skill_groups, pMobIndex->practicer),
                    mlstr_mval(pMobIndex->short_descr));
        }

    if (found)
        fprintf(fp, "S\n\n");
}

void save_helps(FILE *fp, AREA_DATA *pArea)
{
    HELP_DATA *pHelp = pArea->help_first;

    if (pHelp == NULL)
        return;

    fprintf(fp, "#HELPS\n");

    for (; pHelp; pHelp = pHelp->next_in_area)
    {
        fprintf(fp, "%d %s~\n",
                pHelp->level, fix_string(pHelp->keyword));
        mlstr_fwrite(fp, NULL, pHelp->text);
    }

    fprintf(fp, "-1 $~\n\n");
}

/*****************************************************************************
 Name:      save_area
 Purpose:   Save an area, note that this format is new.
 Called by: do_asave(olc_save.c).
 ****************************************************************************/
void save_area(AREA_DATA *pArea)
{
    FILE *fp;
    int flags;
    int climat;

    fclose(fpReserve);
    if ((fp = dfopen(AREA_PATH, pArea->file_name, "w")) == NULL)
    {
        bug("Open_area: fopen", 0);
        perror(pArea->file_name);
        return;
    }

    fprintf(fp, "#AREADATA\n");
    fprintf(fp, "Name %s~\n",   pArea->name);
    if (!mlstr_null(pArea->mlname))
        mlstr_fwrite(fp, "MLName", pArea->mlname);
    fprintf(fp, "Version %.2f\n", CUR_AREA_VERSION);
    fwrite_string(fp, "Builders", pArea->builders);
    fprintf(fp, "VNUMs %d %d\n",    pArea->min_vnum, pArea->max_vnum);
    fwrite_string(fp, "Credits", pArea->credits);
    fprintf(fp, "Security %d\n",    pArea->security);
    fprintf(fp, "LevelRange %d %d\n", pArea->min_level, pArea->max_level);
    if (!mlstr_null(pArea->resetmsg))
        mlstr_fwrite(fp, "ResetMessage", pArea->resetmsg);
    flags = pArea->flags & ~AREA_CHANGED;
    flags = flags        & ~AREA_GQACTIVE; // omit saving this flag
    flags = flags        & ~AREA_WAR_ACTIVE; // omit saving this flag

    fwrite_string(fp, "Planet", flag_string(planet_flags, pArea->planet));

    climat = pArea->climat_type;

    if (flags)
        fwrite_string(fp, "Flags", flag_string(area_flags, flags));

    if (climat)
        fwrite_string(fp, "Climat", flag_string(climat_flags, climat));

    if (pArea->clan)
        fwrite_string(fp, "Clan", clan_name(pArea->clan));

    if (pArea->max_guard_count)
    {
        int i;
        fprintf(fp, "GuardCount %d\n", pArea->max_guard_count);
        fprintf(fp, "GuardVNUMs ");
        for (i = 0; i < pArea->max_guard_count; ++i)
            fprintf(fp, "%d ", pArea->guard_room_vnums[i]);
        fprintf(fp, "\n");
    }
    if (pArea->conq_enabled) // save it if only enabled
        fprintf(fp, "ConqEnabled %d\n", pArea->conq_enabled);
    if (pArea->explore_required)
        fprintf(fp, "ExploreReq %d\n", pArea->explore_required);

    fprintf(fp, "End\n\n");

    if (pArea->min_vnum && pArea->max_vnum)
    {
        save_mobiles(fp, pArea);
        save_objects(fp, pArea);
        save_rooms(fp, pArea);
        save_specials(fp, pArea);
        save_resets(fp, pArea);
        save_shops(fp, pArea);
        save_olimits(fp, pArea);
        save_mobprogs(fp, pArea);
        save_practicers(fp, pArea);
        save_omprogs(fp, pArea);
        save_objprogs(fp, pArea );
        save_roomprogs(fp, pArea );
    }
    save_helps(fp, pArea);

    fprintf(fp, "#$\n");

    fclose(fp);
    fpReserve = fopen(NULL_FILE, "r");
}


void save_clan(CHAR_DATA *ch, clan_t *clan, bool message)
{
    int i;
    FILE *fp;

/* save clan data */
    if ((fp = dfopen(CLANS_PATH, clan->file_name, "w")) == NULL)
    {
        if (message)
            save_print(ch, "%s%c%s: %s",
                       CLANS_PATH, PATH_SEPARATOR, clan->file_name,
                       strerror(errno));
        return;
    }

    fprintf(fp, "#CLAN\n");

    fwrite_string(fp, "Name", clan->name);
    if (clan->clan_align)
        fprintf(fp, "ClanAlign %d\n", clan->clan_align);
    if (clan->recall_vnum)
        fprintf(fp, "Recall %d\n", clan->recall_vnum);
    fwrite_string(fp, "MsgPrays", clan->msg_prays);
    fwrite_string(fp, "MsgVanishes", clan->msg_vanishes);
    fprintf(fp, "BankGold %d\n", clan->bank_gold);
    fprintf(fp, "BankQuestp %d\n", clan->bank_questp);
    fprintf(fp, "BankBonus %d\n", clan->bank_bonus);
    fprintf(fp, "BankGems %d\n", clan->bank_gems);
    fprintf(fp, "BankRGems %d\n", clan->bank_rgems);
    fprintf(fp, "BankBGems %d\n", clan->bank_bgems);
    fprintf(fp, "BankGGems %d\n", clan->bank_ggems);
    fprintf(fp, "BankMGems %d\n", clan->bank_mgems);
    fprintf(fp, "BankWGems %d\n", clan->bank_wgems);
    fprintf(fp, "BankYGems %d\n", clan->bank_ygems);
    fprintf(fp, "MaxMembers %d\n", clan->max_clan_members);
    fprintf(fp, "MinLevel %d\n", clan->min_clan_level);
    fprintf(fp, "AllianceAllow %s~\n",  flag_string(aliance_allow_flag, clan->allow_alliance));

    REMOVE_BIT(clan->flags, CLAN_CHANGED);
    if (clan->flags)
        fprintf(fp, "Flags %s~\n",  flag_string(clan_flags, clan->flags));

    if (clan->obj_vnum)
        fprintf(fp, "Item %d\n", clan->obj_vnum);
    if (clan->item_at)
        fprintf(fp, "WhereItem %d\n", clan->item_at);
    if (clan->altar_vnum)
        fprintf(fp, "Altar %d\n", clan->altar_vnum);
    if (clan->altar_trophy_vnum)
        fprintf(fp, "AltarTrophy %d\n", clan->altar_trophy_vnum);
    if (clan->mark_vnum)
        fprintf(fp, "ClanMark %d\n", clan->mark_vnum);

    fprintf(fp, "Diplomacy");
    for (i = 0; i < MAX_CLANS-1; i++ )
        fprintf(fp, " %d", clan->diplomacy[i]);
    fprintf(fp, "\n");

    for (i = 0; i < clan->skills.nused; i++)
    {
        clan_skill_t *cs = VARR_GET(&clan->skills, i);

        if (cs->sn > 0)
            fprintf(fp, "Skill '%s' %d %d\n",
                    skill_name(cs->sn), cs->level, cs->percent);
    }

    if (clan->standard_areaguard_vnum)
        fprintf(fp, "AreaGuardStandard %d\n", clan->standard_areaguard_vnum);
    if (clan->veteran_areaguard_vnum)
        fprintf(fp, "AreaGuardVeteran %d\n", clan->veteran_areaguard_vnum);
    if (clan->veteran_areaguard_vnum)
        fprintf(fp, "AreaGuardElite %d\n", clan->elite_areaguard_vnum);

    fprintf(fp, "End\n\n"
            "#$\n");
    fclose(fp);

    if (message && ch)
        save_print(ch, "    %s (%s)", clan->name, clan->file_name);
}

void save_clans(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    bool found = FALSE;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_CLANS)
    {
        save_print(ch, "Insufficient security to save clans.");
        return;
    }

    fp = dfopen(CLANS_PATH, CLAN_LIST, "w");
    if (fp == NULL)
    {
        save_print(ch, "%s%c%s: %s", CLANS_PATH, PATH_SEPARATOR, CLAN_LIST,
                   strerror(errno));
        return;
    }

    save_print(ch, "Saved clans:");

    for (i = 0; i < clans.nused; i++)
    {
        fprintf(fp, "%s\n", CLAN(i)->file_name);
        if (IS_SET(CLAN(i)->flags, CLAN_CHANGED))
        {
            save_clan(ch, CLAN(i), TRUE);
            found = TRUE;
        }
    }

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

    if (!found)
        save_print(ch, "    None.");
}

void save_class(CHAR_DATA *ch, class_t *cl, bool message)
{
    int i;
    FILE *fp;

/* save class data */
    if ((fp = dfopen(CLASSES_PATH, cl->file_name, "w")) == NULL)
    {
        if (message)
            save_print(ch, "%s%c%s: %s", CLASSES_PATH, PATH_SEPARATOR, cl->file_name, strerror(errno));
        return;
    }

        //varr_qsort(&cl->skills, cmp_skill_int);

    fprintf(fp, "#CLASS\n");

    fwrite_string(fp, "Name", cl->name);
    fwrite_string(fp, "ShortName", cl->who_name);
    fprintf(fp, "SchoolWeapon %d\n", cl->weapon);

    if (cl->guild)
        for (i = 0; i < cl->guild->nused; i++)
            fprintf(fp, "GuildRoom %d\n", *(int*) VARR_GET(cl->guild, i));

    fprintf(fp, "SkillAdept %d\n", cl->skill_adept);
    if (cl->dodge > 0)
                fprintf(fp, "Dodge %d\n", cl->dodge);
    fprintf(fp, "Thac0_00 %d\n", cl->thac0_00);
    fprintf(fp, "Thac0_32 %d\n", cl->thac0_32);
    fprintf(fp, "HPRate %d\n", cl->hp_rate);
    fprintf(fp, "ManaRate %d\n", cl->mana_rate);

    REMOVE_BIT(cl->flags, CLASS_CHANGED);

    if (cl->flags)
        fprintf(fp, "Flags %s~\n", flag_string(class_flags, cl->flags));

    fprintf(fp, "AddExp %d\n", cl->points);

    fprintf(fp, "StatMod");
    for (i = 0; i < MAX_STATS; i++)
        fprintf(fp, " %d", cl->stats[i]);
    fprintf(fp, "\n");

    fprintf(fp, "WearLoc");
    for (i = 0; i < MAX_WEAR; i++)
        fprintf(fp, " %d", cl->wear_loc[i]);
    fprintf(fp, "\n");

    if (cl->restrict_sex)
        fprintf(fp, "RestrictSex %s~\n",    flag_string(restrict_sex_table, cl->restrict_sex));
    if (cl->restrict_align)
        fprintf(fp, "RestrictAlign %s~\n",  flag_string(ralign_names, cl->restrict_align));
    if (cl->restrict_ethos)
        fprintf(fp, "RestrictEthos %s~\n",  flag_string(ethos_table, cl->restrict_ethos));

    for (i = 0; i < cl->skills.nused; i++)
    {
        class_skill_t *cs = VARR_GET(&cl->skills, i);

        if (cs->sn > 0)
            fprintf(fp, "Skill '%s' %d %d %d\n",
                    skill_name(cs->sn), cs->level, cs->rating, cs->max_percent);
    }

    for (i = 0; i < MAX_LEVEL; i++)
    {
        fprintf(fp, "Title %d %s %s~\n", i, "male", cl->titles[i][0]);
        fprintf(fp, "Title %d %s %s~\n", i, "female", cl->titles[i][1]);
    }

    fprintf(fp, "End\n\n"
            "#$\n");
    fclose(fp);

    if (message && ch)
        save_print(ch, "    %s (%s)", cl->name, cl->file_name);
}

void save_classes(CHAR_DATA *ch, const char *argument)
{
    int       i;
    FILE     *fp;
    bool      found = FALSE;


    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

        if (sec < SECURITY_CLASSES)
    {
        save_print(ch, "Insufficient security to save classes.");
        return;
    }

    fp = dfopen(CLASSES_PATH, CLASS_LIST, "w");
    if (fp == NULL)
    {
        save_print(ch, "%s%c%s: %s", CLASSES_PATH, PATH_SEPARATOR, CLASS_LIST,
                   strerror(errno));
        return;
    }

    save_print(ch, "Saved classes:");

    for (i = 0; i < classes.nused; i++)
    {
        fprintf(fp, "%s\n", CLASS(i)->file_name);
        if (IS_SET(CLASS(i)->flags, CLASS_CHANGED))
        {
            //class_t *cl = CLASS(i);
            //varr_qsort(&CLASS(i)->skills, cmp_skill_int);
            save_class(ch, CLASS(i), TRUE);
            found = TRUE;
        }
    }

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

    if (!found)
        save_print(ch, "    None.");
}

void save_religion(CHAR_DATA *ch, religion_t *religion, bool message)
{
    int i;
    FILE *fp;

/* save religion data */
    if ((fp = dfopen(RELIGIONS_PATH, religion->file_name, "w")) == NULL)
    {
        if (message)
            save_print(ch, "%s%c%s: %s",
                       RELIGIONS_PATH, PATH_SEPARATOR, religion->file_name,
                       strerror(errno));
        return;
    }

    fprintf(fp, "#RELIGION\n");
    fprintf(fp, "Name %s~\n", religion->name);
    if (religion->tattoo_vnum)
        fprintf(fp, "Tattoo %d\n", religion->tattoo_vnum);
    if (religion->tattoo_master_vnum)
        fprintf(fp, "TattooMaster %d\n", religion->tattoo_master_vnum);
    if (religion->recall_vnum)
        fprintf(fp, "Recall %d\n", religion->recall_vnum);
    if (religion->msg_prays)
        fprintf(fp, "MsgPrays %s~\n", religion->msg_prays);
    if (religion->msg_vanishes)
        fprintf(fp, "MsgVanishes %s~\n", religion->msg_vanishes);
    if (religion->rtalk_self)
        fprintf(fp, "RtalkSelf %s~\n", religion->rtalk_self);
    if (religion->rtalk_other)
        fprintf(fp, "RtalkOther %s~\n", religion->rtalk_other);

    REMOVE_BIT(religion->flags, RELIGION_CHANGED);
    if (religion->flags)
        fprintf(fp, "Flags %s~\n", flag_string(religion_flags, religion->flags));
    if (religion->restrict_align)
        fprintf(fp, "RestrictAlign %s~\n", flag_string(ralign_names, religion->restrict_align));
    if (religion->restrict_sex)
        fprintf(fp, "RestrictSex %s~\n", flag_string(restrict_sex_table, religion->restrict_sex));
    if (religion->restrict_ethos)
        fprintf(fp, "RestrictEthos %s~\n", flag_string(ethos_table, religion->restrict_ethos));
    for (i = 0; i < religion->classes.nused; i++)
    {
        rlclass_t *religion_class = VARR_GET(&religion->classes, i);
        fprintf(fp, "Class '%s' %s~\n", religion_class->name, flag_string(status_table, religion_class->status));
    }
    for (i = 0; i < religion->races.nused; i++)
    {
        rlrace_t *religion_race = VARR_GET(&religion->races, i);
        fprintf(fp, "Race '%s' %s~\n", religion_race->name, flag_string(status_table, religion_race->status));
    }
    for (i = 0; i < religion->skills.nused; i++)
    {
        religion_skill_t *religion_skill = VARR_GET(&religion->skills, i);
        fprintf(fp, "Skill '%s' %d %d\n",
                        skill_name(religion_skill->sn),
                        religion_skill->level,
                        religion_skill->percent);
    }
    for (i = 0; i < religion->stats.nused; i++)
    {
        restrict_stat_t *stat = VARR_GET(&religion->stats, i);
        fprintf(fp, "Stat '%s' %d\n",
                        flag_string(stat_names, stat->stat),
                        stat->min);
    }

    fprintf(fp, "End\n\n"
            "#$\n");
    fclose(fp);

    if (message && ch)
        save_print(ch, "    %s (%s)", religion->name, religion->file_name);

}

void save_religions(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    bool found = FALSE;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_RELIGIONS)
    {
        save_print(ch, "Insufficient security to save religions.");
        return;
    }

    fp = dfopen(RELIGIONS_PATH, RELIGION_LIST, "w");
    if (fp == NULL)
    {
        save_print(ch, "%s%c%s: %s", RELIGIONS_PATH, PATH_SEPARATOR, RELIGION_LIST,  strerror(errno));
        return;
    }

    save_print(ch, "Saved religions:");

    for (i = 0; i < religions.nused; i++)
    {
        fprintf(fp, "%s\n", RELIGION(i)->file_name);
        if (IS_SET(RELIGION(i)->flags, RELIGION_CHANGED))
        {
            save_religion(ch, RELIGION(i), TRUE);
            found = TRUE;
        }
    }

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

    if (!found)
        save_print(ch, "    None.");
}

/////////////////////////////////////////////////////////////////////////////

void save_msgdb(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_MSGDB)
    {
        save_print(ch, "Insufficient security to save msgdb.");
        return;
    }

    fp = dfopen(ETC_PATH, MSG_FILE, "w");
    if (fp == NULL)
    {
        save_print(ch, "%s%c%s: %s", ETC_PATH, PATH_SEPARATOR, MSG_FILE,  strerror(errno));
        return;
    }

    for (i = 0; i < MAX_MSG_HASH; i++)
    {
        varr *v = msg_hash_table+i;
        int j;

        if (v == NULL)
            continue;

        for (j = 0; j < v->nused; j++)
        {
            mlstring **mlp = VARR_GET(v, j);
            if (!mlstr_nlang(*mlp))
                continue;
            mlstr_fwrite(fp, NULL, *mlp);
        }
    }

    fprintf(fp, "$~\n");
    fclose(fp);
    save_print(ch, "Msgdb saved.");
}

bool save_lang(CHAR_DATA *ch, lang_t *l)
{
    int i;
    FILE *fp;
    lang_t *sl;
    int flags;

    fp = dfopen(LANG_PATH, l->file_name, "w");
    if (fp == NULL)
    {
        save_print(ch, "%s%c%s: %s", LANG_PATH, PATH_SEPARATOR, l->file_name,  strerror(errno));
        return FALSE;
    }

    fprintf(fp, "#LANG\n"
            "Name %s\n", l->name);
    if ((sl = varr_get(&langs, l->slang_of)))
        fprintf(fp, "SlangOf %s\n", sl->name);
    flags = l->flags & ~(LANG_CHANGED);
    if (flags)
        fprintf(fp, "Flags %s~\n", flag_string(lang_flags, flags));
    fprintf(fp, "End\n\n");

    for (i = 0; i < MAX_RULECL; i++)
    {
        rulecl_t *rcl = l->rules + i;

        if (!IS_NULLSTR(rcl->file_impl)
            ||  !IS_NULLSTR(rcl->file_expl))
        {
            fprintf(fp, "#RULECLASS\n"
                    "Class %s\n",
                    flag_string(rulecl_names, i));
            fwrite_string(fp, "Impl", rcl->file_impl);
            fwrite_string(fp, "Expl", rcl->file_expl);
            fprintf(fp, "End\n\n");
        }
    }

    fprintf(fp, "#$\n");
    fclose(fp);
    return TRUE;
}

void save_langs(CHAR_DATA *ch, const char *argument)
{
    int lang;
    bool list = FALSE;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_LANGS)
    {
        save_print(ch, "Insufficient security to save langs.");
        return;
    }

    for (lang = 0; lang < langs.nused; lang++)
    {
        lang_t *l = VARR_GET(&langs, lang);

        if (IS_SET(l->flags, LANG_CHANGED)
            &&  save_lang(ch, l))
        {
            save_print(ch, "Language '%s' saved (%s%c%s).",
                       l->name, LANG_PATH, PATH_SEPARATOR,
                       l->file_name);
            l->flags &= ~LANG_CHANGED;
            list = TRUE;
        }
    }

    if (list)
    {
        FILE *fp;

        if ((fp = dfopen(LANG_PATH, LANG_LIST, "w")) == NULL)
        {
            save_print(ch, "%s%c%s: %s",
                       LANG_PATH, PATH_SEPARATOR, LANG_LIST,
                       strerror(errno));
            return;
        }

        for (lang = 0; lang < langs.nused; lang++)
        {
            lang_t *l = VARR_GET(&langs, lang);
            fprintf(fp, "%s\n", l->file_name);
        }
        fprintf(fp, "$\n");
        fclose(fp);
    }
}

void save_rule(FILE *fp, rule_t *r)
{
    int i;

    fprintf(fp, "#RULE\n"
            "Name %s~\n", r->name);
    if (r->arg)
        fprintf(fp, "BaseLen %d\n", r->arg);
    for (i = 0; i < r->f->v.nused; i++)
    {
        char **p = VARR_GET(&r->f->v, i);
        if (IS_NULLSTR(*p))
            continue;
        fprintf(fp, "Form %d %s~\n", i, *p);
    }
    fprintf(fp, "End\n\n");
}

void save_expl(CHAR_DATA *ch, lang_t *l, rulecl_t *rcl)
{
    int i;
    FILE *fp;

    if (!IS_SET(rcl->flags, RULES_EXPL_CHANGED))
        return;

    if ((fp = dfopen(LANG_PATH, rcl->file_expl, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",
                   LANG_PATH, PATH_SEPARATOR, rcl->file_expl,
                   strerror(errno));
        return;
    }

    for (i = 0; i < MAX_RULE_HASH; i++)
    {
        int j;

        for (j = 0; j < rcl->expl[i].nused; j++)
        {
            rule_t *r = VARR_GET(rcl->expl+i, j);
            save_rule(fp, r);
        }
    }

    fprintf(fp, "#$\n");
    fclose(fp);

    save_print(ch, "Explicit rules (%s%c%s) saved "
               "(lang '%s', rules type '%s').",
               LANG_PATH, PATH_SEPARATOR, rcl->file_expl,
               l->name, flag_string(rulecl_names, rcl->rulecl));
    rcl->flags &= ~RULES_EXPL_CHANGED;
}

void save_impl(CHAR_DATA *ch, lang_t *l, rulecl_t *rcl)
{
    int i;
    FILE *fp;

    if (!IS_SET(rcl->flags, RULES_IMPL_CHANGED))
        return;

    if ((fp = dfopen(LANG_PATH, rcl->file_impl, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",
                   LANG_PATH, PATH_SEPARATOR, rcl->file_impl,
                   strerror(errno));
        return;
    }

    for (i = 0; i < rcl->impl.nused; i++)
    {
        rule_t *r = VARR_GET(&rcl->impl, i);
        save_rule(fp, r);
    }

    fprintf(fp, "#$\n");
    fclose(fp);

    save_print(ch, "Implicit rules (%s%c%s) saved "
                   "(lang '%s', rules type '%s').",
               LANG_PATH, PATH_SEPARATOR, rcl->file_impl,
               l->name, flag_string(rulecl_names, rcl->rulecl));
    rcl->flags &= ~RULES_IMPL_CHANGED;
}

void save_rules(CHAR_DATA *ch, const char *argument)
{
    int lang;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_RULES)
    {
        save_print(ch, "Insufficient security to save rules.");
        return;
    }

    for (lang = 0; lang < langs.nused; lang++)
    {
        int i;
        lang_t *l = VARR_GET(&langs, lang);

        for (i = 0; i < MAX_RULECL; i++)
        {
            save_expl(ch, l, l->rules+i);
            save_impl(ch, l, l->rules+i);
        }
    }
}


void save_alias(FILE *fp, alias_t *alias)
{
    fprintf(fp, "#ALIAS\n");
    fprintf(fp, "Name %s~\n", alias->name);
    if (alias->command)
        fprintf(fp, "Command %s~\n", alias->command->name);

    fprintf(fp, "End\n\n");
}

void save_skill_alias(FILE *fp, skill_alias_t *alias)
{
    if (alias->skill)
    {
        fprintf(fp, "#SKILLALIAS\n");
        fprintf(fp, "Name %s~\n", alias->name);
        fprintf(fp, "Skill %s~\n", alias->skill->name);

        fprintf(fp, "End\n\n");
    }
}

void save_aliases(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_ALIASES)
    {
        save_print(ch, "Insufficient security to save aliases.");
        return;
    }

    if ((fp = dfopen(ETC_PATH, ALIASES_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",
                   ETC_PATH, PATH_SEPARATOR, ALIASES_CONF,
                   strerror(errno));
        return;
    }

    for (i = 0; i < aliases.nused; i++)
    {
        alias_t *alias = VARR_GET(&aliases, i);
        save_alias(fp, alias);
    }

    for (i = 0; i < skill_aliases.nused; i++)
    {
        skill_alias_t *alias = VARR_GET(&skill_aliases, i);
        save_skill_alias(fp, alias);
    }

    fprintf(fp, "#$\n");
    fclose(fp);
    save_print(ch, "Aliases saved.");
}

void save_command(FILE *fp, command_t *command)
{
    fprintf(fp, "#COMMAND\n");
    fprintf(fp, "Name %s~\n", command->name);
    if (command->do_fun)
        fprintf(fp, "DoFun %s\n", namedp_name(dofun_table, command->do_fun));
    if (command->position)
        fprintf(fp, "MinPos %s\n",
                        flag_string(position_table, command->position));
    if (command->level)
        fprintf(fp, "Level %d\n", command->level);
    if (command->log)
        fprintf(fp, "Log %s\n", flag_string(log_flags, command->log));
    if (command->flags)
        fwrite_string(fp, "Flags", flag_string(command_flags, command->flags));

    fprintf(fp, "End\n\n");
}

void save_commands(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_COMMANDS)
    {
        save_print(ch, "Insufficient security to save commands.");
        return;
    }

    if ((fp = dfopen(ETC_PATH, COMMANDS_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",
                   ETC_PATH, PATH_SEPARATOR, COMMANDS_CONF,
                   strerror(errno));
        return;
    }

    for (i = 0; i < commands.nused; i++)
    {
        command_t *command = VARR_GET(&commands, i);
        save_command(fp, command);
    }

    fprintf(fp, "#$\n");
    fclose(fp);
    save_print(ch, "Commands saved.");
}

void save_skill(FILE *fp, skill_t *sk)
{
    fprintf(fp, "#SKILL\n");
    fwrite_string(fp, "Name", sk->name);
    fprintf(fp, "Type %s\n", flag_string(skill_types, sk->type));
    if (sk->group)
        fwrite_string(fp, "Group", flag_string(skill_groups, sk->group));
    else
        fwrite_string(fp, "Group", "none");

    if (sk->discipline)
        fwrite_string(fp, "Discipline", flag_string(psi_disciplines, sk->discipline));
    if (sk->flags)
        fwrite_string(fp, "Flags", flag_string(skill_flags, sk->flags));
    if (sk->pgsn)
        fprintf(fp, "Gsn %s\n", namedp_name(gsn_table, sk->pgsn));
    if (sk->beats)
        fprintf(fp, "Beats %d\n", sk->beats);
    if (sk->delay)
        fprintf(fp, "Delay %d\n", sk->delay);
    if (sk->spell_fun)
        fprintf(fp, "SpellFun %s\n", namedp_name(spellfn_table, sk->spell_fun));
    if (sk->do_fun)
        fprintf(fp, "DoFun %s\n", namedp_name(dofun_table, sk->do_fun));
    fprintf(fp, "Target %s\n", flag_string(skill_targets, sk->target));
    if (sk->gender)
        fprintf(fp, "SkillGender %d\n", sk->gender);
    fprintf(fp, "MinPos %s\n", flag_string(position_table, sk->min_pos));
    if (sk->min_mana)
        fprintf(fp, "MinMana %d\n", sk->min_mana);
    if (sk->initial)
        fprintf(fp, "InitialCost %d\n", sk->initial);
    if (sk->clan_energy)
        fprintf(fp, "ClanEnergy %d\n", sk->clan_energy);
    if (sk->maintain)
        fprintf(fp, "MaintainCost %d\n", sk->maintain);
    if (sk->slot)
        fprintf(fp, "Slot %d\n", sk->slot);
    if (sk->stat1 >= 0)
        fprintf(fp, "Stat1 %s\n", flag_string(stat_names, sk->stat1));
    if (sk->stat2 >= 0)
        fprintf(fp, "Stat2 %s\n", flag_string(stat_names, sk->stat2));
    if (sk->stat3 >= 0)
        fprintf(fp, "Stat3 %s\n", flag_string(stat_names, sk->stat3));
    if (sk->bonus)
        fprintf(fp, "Bonus %d\n", sk->bonus);
    if (sk->learnmult[0] > 1 || sk->learnmult[1] > 1)
        fprintf(fp, "LearnMult %d %d\n", sk->learnmult[0], sk->learnmult[1]);
    if (sk->noun_damage)
        fwrite_string(fp, "NounDamage", sk->noun_damage);
    if (sk->noun_rus)
        fwrite_string(fp, "NounRus", sk->noun_rus);
    if (sk->msg_off)
        fwrite_string(fp, "WearOff", sk->msg_off);
    if (sk->msg_off)
        fwrite_string(fp, "WearOffOther", sk->msg_off_other);
    if (sk->msg_obj)
        fwrite_string(fp, "ObjWearOff", sk->msg_obj);

    fprintf(fp, "End\n\n");
}

void save_skills(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_SKILLS)
    {
        save_print(ch, "Insufficient security to save skills.");
        return;
    }

    if ((fp = dfopen(ETC_PATH, SKILLS_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",  ETC_PATH, PATH_SEPARATOR, SKILLS_CONF,  strerror(errno));
        return;
    }

    for (i = 0; i < skills.nused; i++)
    {
        skill_t *sk = VARR_GET(&skills, i);
        save_skill(fp, sk);
    }

    fprintf(fp, "#$\n");
    fclose(fp);
    save_print(ch, "Skills saved.");
}

void save_social(FILE *fp, social_t *soc)
{
    fprintf(fp, "#SOCIAL\n");
    fprintf(fp, "Name %s\n", soc->name);
    fwrite_string(fp, "alias", soc->alias);
    fwrite_string(fp, "desc", soc->description);
    fprintf(fp, "min_pos %s\n",   flag_string(position_table, soc->min_pos));
    fwrite_string(fp, "found_char", soc->found_char);
    fwrite_string(fp, "found_vict", soc->found_vict);
    fwrite_string(fp, "found_notvict", soc->found_notvict);
    fwrite_string(fp, "noarg_char", soc->noarg_char);
    fwrite_string(fp, "noarg_room", soc->noarg_room);
    fwrite_string(fp, "self_char", soc->self_char);
    fwrite_string(fp, "self_room", soc->self_room);
    fwrite_string(fp, "all_char",  soc->all_char);
    fwrite_string(fp, "all_room",  soc->all_room);
    fwrite_string(fp, "all_self",  soc->all_self);
    fwrite_string(fp, "notfound_char", soc->notfound_char);
    fprintf(fp, "level %d\n", soc->level);
    fprintf(fp, "age %d\n", soc->age);
    fprintf(fp, "End\n\n");
}

void save_socials(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;

    if (!char_security(ch,"SECURITY_SOCIALS"))
    {
        save_print(ch, "Insufficient security to save socials.");
        return;
    }

    if ((fp = dfopen(ETC_PATH, SOCIALS_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",
                   ETC_PATH, PATH_SEPARATOR, SOCIALS_CONF,
                   strerror(errno));
        return;
    }

    for (i = 0; i < socials.nused; i++)
    {
        social_t *soc = VARR_GET(&socials, i);
        save_social(fp, soc);
    }

    fprintf(fp, "#$\n");
    fclose(fp);
    save_print(ch, "Socials saved.");
}

//////////////////////////////////////////////////////////////////////////////

void do_asave_raw(CHAR_DATA *ch, int flags)
{
    AREA_DATA *pArea;
    bool found = FALSE;
    int sec;

    if (!ch)       /* Do an autosave */
        sec = 9;
    else if (!IS_NPC(ch))
        sec = ch->pcdata->security;
    else
        sec = 0;

    if (ch)
        char_puts("Saved zones:\n", ch);
    else
        log("Saved zones:");

    for (pArea = area_first; pArea; pArea = pArea->next)
    {
        /* Builder must be assigned this area. */
        if (ch && !IS_BUILDER(ch, pArea))
            continue;

        if (flags && !IS_SET(pArea->flags, flags))
            continue;

        if (IS_SET(pArea->flags, AREA_TEMPORARY))
            continue;

        found = TRUE;
        save_area(pArea);

        if (ch)
            char_printf(ch, "    %s (%s)\n",
                        pArea->name, pArea->file_name);
        else
            log_printf("    %s (%s)",
                       pArea->name, pArea->file_name);
        REMOVE_BIT(pArea->flags, flags);
    }

    if (!found)
    {
        if (ch)
            char_puts("    None.\n", ch);
        else
            log("    None.");
    } else
        save_area_list();
}

static void save_print(CHAR_DATA *ch, const char *format, ...)
{
    char buf[MAX_STRING_LENGTH];
    va_list ap;

    va_start(ap, format);
    vsnprintf(buf, sizeof(buf), format, ap);
    va_end(ap);

    if (ch)
        char_printf(ch, "%s\n", buf);
    else
        log(buf);
    wiznet("$t", ch, buf, WIZ_OLC, 0, 0);
}

void save_price(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_PRICES)
    {
        save_print(ch, "Insufficient security to save prices.");
        return;
    }

    if ((fp = dfopen( ETC_PATH, PRICES_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",
                       ETC_PATH, PATH_SEPARATOR, PRICES_CONF,
                       strerror(errno));
        return;
    }

    for (i = 0; i < prices.nused; i++)
    {
        price_t *price = VARR_GET(&prices, i);
        fprintf(fp, "#PRICE\n");
        fprintf(fp, "Name %s~\n", price->name);
        fprintf(fp, "Descriptor %s~\n", price->descriptor);
        fprintf(fp, "Amount %d\n", price->amount);
        fprintf(fp, "Type %ld\n", (long int) price->amount_type);
        fprintf(fp, "End\n\n");
    }

        fprintf(fp, "\n#$\n");
        fclose(fp);

        save_print(ch, "Prices saved.");

}

void save_security(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_SECS)
    {
        save_print(ch, "Insufficient security to save security.");
        return;
    }

    if ((fp = dfopen( ETC_PATH, SECURITY_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s", ETC_PATH, PATH_SEPARATOR, SECURITY_CONF,  strerror(errno));
        return;
    }

    for (i = 0; i < securitys.nused; i++)
    {
        security_t *security = VARR_GET(&securitys, i);
        fprintf(fp, "#SEC\n");
        fprintf(fp, "Name %s~\n", security->name);
        fprintf(fp, "Level %d\n", security->level);
        fprintf(fp, "End\n\n");
    }

    fprintf(fp, "\n#$\n");
    fclose(fp);
    save_print(ch, "Security saved.");
}


void save_meteor(CHAR_DATA *ch, const char *argument)
{
    int i;
    int j;
    FILE *fp;
    int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;

    if (sec < SECURITY_METEORS)
    {
        save_print(ch, "Insufficient security to save meteors.");
        return;
    }

    if ((fp = dfopen( ETC_PATH, METEORS_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",
                       ETC_PATH, PATH_SEPARATOR, METEORS_CONF,
                       strerror(errno));
        return;
    }

    for (i = 0; i < meteors.nused; i++)
    {
        meteor_t *meteor = VARR_GET(&meteors, i);
        fprintf(fp, "#METEOR\n");
        fprintf(fp, "Name %s~\n",       meteor->name);
        fprintf(fp, "Autostart %s~\n",  flag_string(meteor_bool_flags, meteor->auto_start));
        fprintf(fp, "Wait %d\n",        meteor->wait_tick);
        fprintf(fp, "Size %d\n",        meteor->size);
        fprintf(fp, "Damage %d\n",      meteor->damage);
        fprintf(fp, "Nopk %s~\n",       flag_string(meteor_bool_flags, meteor->nopk_damage));
        fprintf(fp, "RoomAffect %s~\n", flag_string(meteor_bool_flags, meteor->room_affect));

        for (j = 0; j < meteor->objects.nused; j++)
        {
                mobject_t *mobject = VARR_GET(&meteor->objects, j);
                fprintf(fp, "Objects %d %d %d\n", mobject->obj_vnum, mobject->obj_count, mobject->chanse);
        }

        fprintf(fp, "End\n\n");

    }

    fprintf(fp, "\n#$\n");
    fclose(fp);
    save_print(ch, "Meteors saved.");

}

void save_riddles(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;


    if (!char_security(ch, "SECURITY_RIDDLE"))
    {
        save_print(ch, "Insufficient security to save riddles.");
        return;
    }

    if ((fp = dfopen( ETC_PATH, RIDDLES_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",
                       ETC_PATH, PATH_SEPARATOR, RIDDLES_CONF,
                       strerror(errno));
        return;
    }

    for (i = 0; i < riddles.nused; i++)
    {
        riddle_t *riddle = VARR_GET(&riddles, i);

        fprintf(fp, "#RIDDLE\n");
        mlstr_fwrite(fp, "Question", riddle->question);
        fprintf(fp, "Answer %s~\n", riddle->answer);
        fprintf(fp, "End\n\n");
    }

    fprintf(fp, "\n#$\n");
    fclose(fp);
    save_print(ch, "Riddles saved.");
}

void save_immortal(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;


    if (!char_security(ch, "SECURITY_OLC_IMMORTAL"))
    {
        save_print(ch, "Insufficient security to save immortal.");
        return;
    }

    if ((fp = dfopen( ETC_PATH, IMMORTAL_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s", ETC_PATH, PATH_SEPARATOR, IMMORTAL_CONF, strerror(errno));
        return;
    }

    for (i = 0; i < immortals.nused; i++)
    {
        immortal_t *immortal = VARR_GET(&immortals, i);

        fprintf(fp, "#IMMORTAL\n");
        fprintf(fp, "Name %s~\n",        immortal->name);
        fprintf(fp, "Level %d\n",        immortal->level);
        fprintf(fp, "RealName %s~\n",    immortal->realname);
        fprintf(fp, "Comment %s~\n",     immortal->comment);
        fprintf(fp, "Phone %s~\n",       immortal->phone);
        fprintf(fp, "AccessTime %s~\n",  immortal->phone_time_access);
        fprintf(fp, "PhoneSec %d\n",     immortal->phone_sec_level);
        fprintf(fp, "Email %s~\n",       immortal->email);
        fprintf(fp, "EmailSec %d\n",     immortal->email_sec_level);
        fprintf(fp, "ICQ %s~\n",         immortal->icq);
        fprintf(fp, "ICQSec %d\n",       immortal->icq_sec_level);
        fprintf(fp, "Birthday %s~\n",    immortal->birthday);
        fprintf(fp, "End\n\n");
    }

    fprintf(fp, "\n#$\n");
    fclose(fp);
    save_print(ch, "Immortals saved.");
}

void save_tattoo(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    int comp;

    if ((fp = dfopen( ETC_PATH, TATTOO_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s", ETC_PATH, PATH_SEPARATOR, TATTOO_CONF, strerror(errno));
        return;
    }

    for (i = 0; i < tattooes.nused; i++)
    {
        tattoo_t * tattoo = VARR_GET(&tattooes, i);

        fprintf(fp, "#TATTOO\n");
        fwrite_string (fp, "Name", tattoo->name);
        mlstr_fwrite (fp, "Desc", tattoo->desc);
        for (comp = 0; comp < MAX_TATTOO_COMP; ++comp)
            if (tattoo->paint_comp[comp] != 0)
                fprintf (fp, "PaintComp %d %d\n", comp, tattoo->paint_comp[comp]);
        for (comp = 0; comp < MAX_TATTOO_COMP; ++comp)
            if (tattoo->act_comp[comp] != 0)
                fprintf (fp, "ActComp %d %d\n", comp, tattoo->act_comp[comp]);
        fprintf (fp, "WaitPaint %d\n", tattoo->wait_paint);
        fprintf (fp, "WaitAct %d\n", tattoo->wait_act);
        fprintf (fp, "MinSkill %d\n", tattoo->min_skill);
        fprintf (fp, "MaxAct %d\n", tattoo->max_activations);
        fprintf (fp, "WearLoc %s\n", format_flags (tattoo->wear_loc));
        fprintf (fp, "Paints %s\n", format_flags (tattoo->paints));
        fprintf (fp, "Extra %s\n", format_flags (tattoo->extra));
        fprintf (fp, "End\n\n");
    }

    fprintf(fp, "\n#$\n");
    fclose(fp);
    save_print(ch, "Tattooes saved.");
}

void save_ritual(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    int comp;

    if ((fp = dfopen( ETC_PATH, RITUAL_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s", ETC_PATH, PATH_SEPARATOR, RITUAL_CONF, strerror(errno));
        return;
    }

    for (i = 0; i < rituals.nused; i++)
    {
        ritual_t * ritual = VARR_GET(&rituals, i);

        fprintf(fp, "#RITUAL\n");
        fwrite_string (fp, "Name", ritual->name);
        fprintf (fp, "Duration %d\n", ritual->duration);
        fprintf (fp, "MinSkill %d\n", ritual->min_skill);
        fprintf (fp, "Sector %s\n", format_flags (ritual->sector));
        fprintf (fp, "Period %s\n", format_flags (ritual->time));
        fprintf (fp, "Extra %s\n", format_flags (ritual->extra));
        for (comp = 0; comp < MAX_RITUAL_COMP; ++comp)
            if (ritual->components[comp] != 0)
                fprintf (fp, "Component %d %d\n", comp, ritual->components[comp]);

        fprintf(fp, "End\n\n");
    }

    fprintf(fp, "\n#$\n");
    fclose(fp);
    save_print(ch, "Rituals saved.");
}

void save_paint(CHAR_DATA *ch, const char *argument)
{
    int i;
    FILE *fp;
    int comp;

    if ((fp = dfopen( ETC_PATH, PAINT_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s", ETC_PATH, PATH_SEPARATOR, PAINT_CONF, strerror(errno));
        return;
    }

    for (i = 0; i < paints.nused; i++)
    {
        paint_t * paint = VARR_GET(&paints, i);

        fprintf(fp, "#PAINT\n");
        fwrite_string (fp, "Name", paint->name);
        fwrite_string (fp, "ObjName", paint->obj_name);
        mlstr_fwrite (fp, "Short", paint->short_desc);
        mlstr_fwrite (fp, "Long", paint->desc);
        fprintf (fp, "MinSkill %d\n", paint->min_skill);
        fprintf (fp, "Color %d\n", paint->color);
        fprintf (fp, "Mana %d\n", paint->mana_cost);
        fprintf (fp, "MaxPort %d\n", paint->max_portions);
        fprintf (fp, "Power %d\n", paint->power);
        for (comp = 0; comp < MAX_PAINT_COMP; ++comp)
            if (paint->components[comp] != 0)
                fprintf (fp, "Component %d %d\n", comp, paint->components[comp]);
        fprintf(fp, "End\n\n");
    }

    fprintf(fp, "\n#$\n");
    fclose(fp);
    save_print(ch, "Paints saved.");
}

/*
 * Save materials
 */


void save_material(CHAR_DATA *ch, const char *argument)
{
    int   i,j;
    FILE *fp;


    if (!char_security(ch, "SECURITY_OLC_MATERIAL"))
    {
        save_print(ch, "Insufficient security to save material.");
        return;
    }

    if ((fp = dfopen( ETC_PATH, MATERIAL_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s",
                       ETC_PATH, PATH_SEPARATOR, MATERIAL_CONF,
                       strerror(errno));
        return;
    }

    for (i = 0; i < materials.nused; i++)
    {
        material_t *material = VARR_GET(&materials, i);

        fprintf(fp, "#MATERIAL\n");
        fprintf(fp, "Ename %s~\n",       material->ename);
        fprintf(fp, "Rname %s~\n",       material->rname);
        fprintf(fp, "Density %d\n",      material->density);
        fprintf(fp, "Fragility %d\n",    material->fragility);
        fprintf(fp, "Rigidity %d\n",     material->rigidity);
        fprintf(fp, "Flags %s~\n",       flag_string(material_flags, material->flag));

        for (j = 0; j < material->races.nused; j++)
        {
            mtrace_t *mrace = VARR_GET(&material->races, j);
            fprintf(fp, "Race '%s' %s~\n", mrace->name, flag_string(material_wear_status, mrace->status));
        }

        for (j = 0; j < material->repairer.nused; j++)
        {
            mrepair_t *mrepair = VARR_GET(&material->repairer, j);
            fprintf(fp, "Repair %d %d\n", mrepair->vnum, mrepair->repair_rate);
        }

        fprintf(fp, "End\n\n");
    }

    fprintf(fp, "\n#$\n");
    fclose(fp);
    save_print(ch, "Materials saved.");
}


/*
 * Save liquids
 */


void save_liquids(CHAR_DATA *ch, const char *argument)
{
    int   i;
    FILE *fp;


    if (!char_security(ch, "SECURITY_OLC_LIQUID"))
    {
        save_print(ch, "Insufficient security to save liquids.");
        return;
    }

    if ((fp = dfopen( ETC_PATH, LIQUID_CONF, "w")) == NULL)
    {
        save_print(ch, "%s%c%s: %s", ETC_PATH, PATH_SEPARATOR, LIQUID_CONF, strerror(errno));
        return;
    }

    for (i = 0; i < liquids.nused; i++)
    {
        liquid_t *liquid = VARR_GET(&liquids, i);

        fprintf(fp, "#LIQUID\n");
        fprintf(fp, "Name %s~\n",       liquid->name);
        fprintf(fp, "Color %s~\n",      liquid->color);
        fprintf(fp, "Food %d\n",        liquid->food);
        fprintf(fp, "Full %d\n",        liquid->full);
        fprintf(fp, "Proof %d\n",       liquid->proof);
        fprintf(fp, "Thirst %d\n",      liquid->thirst);
        fprintf(fp, "Ssize %d\n",       liquid->ssize);
        fprintf(fp, "Flags %s~\n",      flag_string(liquid_flags, liquid->flag));
        fprintf(fp, "End\n\n");
    }

    fprintf(fp, "\n#$\n");
    fclose(fp);
    save_print(ch, "Liquids saved.");
}



void save_race(CHAR_DATA *ch, race_t *race, bool message)
{
    int       i;
    FILE     *fp;
    pcrace_t *pcr;


    if ((fp = dfopen(RACES_PATH, race->file_name, "w")) == NULL)
    {
        if (message)
            save_print(ch, "%s%c%s: %s",
                       RACES_PATH, PATH_SEPARATOR, race->file_name,
                       strerror(errno));
        return;
    }


    fprintf(fp, "#RACE\n");

    fwrite_string(fp, "Name",      race->name);
    if (race->act)           fprintf(fp, "Act %s~\n",       flag_string(act_flags, race->act));
    if (race->aff)           fprintf(fp, "Aff %s~\n",       flag_string(affect_flags, race->aff));
    if (race->off)           fprintf(fp, "Off %s~\n",       flag_string(off_flags, race->off));
    if (race->immunes)       fprintf(fp, "Immune %s~\n",    flag_string(imm_flags, race->immunes));
    if (race->loved_sectors) fprintf(fp, "LoveSect %s~\n",  flag_string(sector_flag_types, race->loved_sectors));
    if (race->hated_sectors) fprintf(fp, "HateSect %s~\n",  flag_string(sector_flag_types, race->hated_sectors));

    for (i = 0; i < MAX_DAM; i++)
            if (race->resists[i])
                fprintf(fp, "Resist %s %d\n", flag_string(dam_flags, i), race->resists[i]);

    fprintf(fp, "Form %s~\n",    flag_string(form_flags, race->form     ));
    fprintf(fp, "Parts %s~\n",   flag_string(part_flags, race->parts    ));

    for (i = 0; i < MAX_SPEC_PARTS; ++i)
    {
        if (race->spec_parts[i] != 0)
            fprintf(fp, "SP %d %d %d %d\n", i, race->spec_parts[i], race->spec_prob[i], race->spec_levels[i]);
    }
    if (race->wear_loc)
    {
         fprintf(fp, "WearLoc ");

         for (i = 0; i < MAX_WEAR; i++)
              fprintf(fp, " %d", race->wear_loc[i]);

         fprintf(fp, "\n");
    }

    REMOVE_BIT(race->flags, RACE_CHANGED);
    if (race->flags)
        fprintf(fp, "Flags %s~\n",
                flag_string(race_flags, race->flags));

    fprintf(fp, "Dodge %d\n",    race->dodge);

    fprintf(fp, "End\n\n");

    if ((pcr = race->pcdata))
    {
         fprintf(fp, "#PCRACE\n");
         fwrite_string(fp, "Shortname",      pcr->who_name);
         fprintf(fp, "Points %d\n",         pcr->points);

         for (i = 0; i < pcr->classes.nused; i++)
         {
             rclass_t *race_class = VARR_GET(&pcr->classes, i);
             int cn;

             if ((cn = cn_lookup(race_class->name)) < 0)
                  continue;

             fprintf(fp, "Class '%s' %d\n", CLASS(cn)->name, race_class->mult);
         }

         fwrite_string(fp, "BonusSkills",      pcr->bonus_skills);

         for (i = 0; i < pcr->skills.nused; i++)
         {
             race_skill_t *race_skill = VARR_GET(&pcr->skills, i);
             skill_t *skill;

             if (race_skill->sn <= 0  || (skill = skill_lookup(race_skill->sn)) == NULL)
                  continue;

             fprintf(fp, "Skill '%s' %d\n", skill->name, race_skill->level);
         }

         if (pcr->stats)
         {
              fprintf(fp, "Stats");

              for (i = 0; i < MAX_STATS; i++)
                   fprintf(fp, " %d", pcr->stats[i]);

              fprintf(fp, "\n");
         }

         if (pcr->max_stats)
         {
              fprintf(fp, "MaxStats");

              for (i = 0; i < MAX_STATS; i++)
                   fprintf(fp, " %d", pcr->max_stats[i]);

              fprintf(fp, "\n");
         }

        fprintf(fp, "Size %d\n",       pcr->size);
        fprintf(fp, "HPBonus %d\n",    pcr->hp_bonus);
        fprintf(fp, "ManaBonus %d\n",  pcr->mana_bonus);
        fprintf(fp, "PracBonus %d\n",  pcr->prac_bonus);
        fprintf(fp, "Slang %d\n",      pcr->slang);

        if (pcr->restrict_align)       fprintf(fp, "RestrictAlign %s~\n",       flag_string(ralign_names, pcr->restrict_align));
        if (pcr->restrict_sex)         fprintf(fp, "RestrictSex %s~\n",         flag_string(restrict_sex_table, pcr->restrict_sex));
        if (pcr->restrict_ethos)       fprintf(fp, "RestrictEthos %s~\n",       flag_string(ethos_table, pcr->restrict_ethos));

        fprintf(fp, "End\n\n");
    }


    fprintf(fp, "#$\n");
    fclose(fp);

    if (message && ch)
        save_print(ch, "    %s (%s)", race->name, race->file_name);
}


void save_races(CHAR_DATA *ch, const char *argument)
{
    int       i;
    FILE     *fp;
    bool      found = FALSE;


    if (ch->pcdata->security < SECURITY_RACES)
    {
        save_print(ch, "Insufficient security to save races.");
        return;
    }

    fp = dfopen(RACES_PATH, RACE_LIST, "w");
    if (fp == NULL)
    {
        save_print(ch, "%s%c%s: %s", CLASSES_PATH, PATH_SEPARATOR, RACE_LIST,
                   strerror(errno));
        return;
    }

    save_print(ch, "Saved races:");

    for (i = 0; i < races.nused; i++)
    {
        fprintf(fp, "%s\n", RACE(i)->file_name);
        if (IS_SET(RACE(i)->flags, RACE_CHANGED))
        {
            save_race(ch, RACE(i), TRUE);
            found = TRUE;
        }
    }

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

    if (!found)
        save_print(ch, "    None.");
}

void save_system(CHAR_DATA *ch, const char *argument)
{
    int       i;
    FILE     *fp;


    if ((fp = dfopen(ETC_PATH, SYSTEM_CONF, "w")) == NULL)
    {
        save_print(ch, "Error write muddy flag to file: %s%c%s: %s", ETC_PATH, PATH_SEPARATOR, SYSTEM_CONF, strerror(errno));
        return;
    }


    fprintf(fp, "#CONF\n");
    fprintf(fp, "Flags %d\n", bdflags) ;

    for (i = 0 ; i < 10 ; i++)
         fprintf(fp, "BD%d %s~\n", i, bdmsg[i]);

    fprintf(fp, "GC_Enabled %d\n",     gc.enabled);
    fprintf(fp, "GC_CharEnabled %d\n", gc.char_enabled);
    fprintf(fp, "GC_RoomEnabled %d\n", gc.room_enabled);
    fprintf(fp, "GC_CharPulse %d\n",   gc.pulse_char_default);
    fprintf(fp, "GC_RoomPulse %d\n",   gc.pulse_room_default);

/* TODO: temporary disabled
    fprintf(fp, "RWAR_Enabled %d\n",   rwar.enabled);
    fprintf(fp, "RWAR_Base %d\n",      rwar.base_price);
    fprintf(fp ,"RWAR_Extar %d\n",     rwar.price_per_level);
*/
    fprintf(fp, "Muddy %s~\n",  flag_string(muddy_flags, muddy_mode));

    fprintf(fp, "End\n\n"
            "#$\n");

    fclose(fp);

    if (ch)
        save_print(ch, "Saving: %s", SYSTEM_CONF);
}



/*****************************************************************************
 Name:      do_asave
 Purpose:   Entry point for saving area data.
 Called by: interpreter(interp.c)
 ****************************************************************************/

static ASAVE_CMD    asave_cmds [] =
{
    { "help",       asave_help,          "This help",                                                        },
    { "system",     save_system,         "Save system parameters",       ASAVE_CMD_ALL                       },
    { "races",      save_races,          "Save races",                   ASAVE_CMD_ALL | ASAVE_CMD_CHANGED   },
    { "classes",    save_classes,        "Save classes",                 ASAVE_CMD_ALL | ASAVE_CMD_CHANGED   },
    { "langs",      save_langs,          "Save languages",               ASAVE_CMD_ALL | ASAVE_CMD_CHANGED   },
    { "rules",      save_rules,          "Save rules",                   ASAVE_CMD_ALL | ASAVE_CMD_CHANGED   },
    { "msgdb",      save_msgdb,          "Save translation messages",    ASAVE_CMD_ALL | ASAVE_CMD_CHANGED   },
    { "meteors",    save_meteor,         "Save meteors info",            ASAVE_CMD_ALL                       },
    { "security",   save_security,       "Save security info",           ASAVE_CMD_ALL                       },
    { "aliases",    save_aliases,        "Save command & spell aliases", ASAVE_CMD_ALL                      },
    { "spellaliases",save_aliases,       "Save command & spell aliases", ASAVE_CMD_ALL                       },
    { "commands",   save_commands,       "Sace commands",                ASAVE_CMD_ALL                       },
    { "socials",    save_socials,        "Save socials",                 ASAVE_CMD_ALL                       },
    { "skills",     save_skills,         "Save skills",                  ASAVE_CMD_ALL                       },
    { "clans",      save_clans,          "Save clan info",               ASAVE_CMD_ALL                       },
    { "religions",  save_religions,      "Save religion info",           ASAVE_CMD_ALL | ASAVE_CMD_CHANGED   },
    { "prices",     save_price,          "Save prices",                  ASAVE_CMD_ALL                       },
    { "riddles",    save_riddles,        "Save riddles",                 ASAVE_CMD_ALL                       },
    { "immortals",  save_immortal,       "Save immortals database",      ASAVE_CMD_ALL                       },
    { "tattoo",     save_tattoo,         "Save tattooes",                ASAVE_CMD_ALL                       },
    { "paint",      save_paint,          "Save paints",                  ASAVE_CMD_ALL                       },
    { "ritual",     save_ritual,         "Save rituals",                 ASAVE_CMD_ALL                       },
    { "materials",  save_material,       "Save materials database",      ASAVE_CMD_ALL                       },
    { "liquids",    save_liquids,        "Save liquids database",        ASAVE_CMD_ALL                       },
    { "all",        save_all,            "Save all",                     0                                   },
    { "world",      save_world,          "Save world",                   0                                   },
    { "changed",    save_changed,        "Save changed area & database", 0                                   },
    { NULL }
};

void save_all (CHAR_DATA* ch, const char* argument)
{
    ASAVE_CMD*  cmd ;

    for (cmd = asave_cmds ; cmd->name ; ++cmd)
        if (IS_SET(cmd->asave_cmd_flag, ASAVE_CMD_ALL))
                (*cmd->fun) (ch, argument);

    do_asave_raw(ch, 0);

        if (ch)
            char_puts("You saved {CAstrum Metaphora{x.\n", ch);
        else
            log("Saved all");
}

void asave_help(CHAR_DATA *ch, const char *argument)
{
     ASAVE_CMD *cmd;

     char_printf(ch, "Avialable arguments for asave:\n");

     for (cmd = asave_cmds ; cmd->name ; ++cmd)
        char_printf (ch, "%-12s - %-40s{x\n", cmd->name, cmd->description);

     char_printf (ch, "\n") ;
}

void save_world (CHAR_DATA* ch, const char* argument)
{

    do_asave_raw(ch, 0);

     if (ch)
          char_puts("You saved the world.\n", ch);
     else
          log("Saved the world.");
}

void do_asave (CHAR_DATA* ch, const char* argument)
{
    ASAVE_CMD*  cmd ;
    static char command [MAX_INPUT_LENGTH] ;

    argument = one_argument (argument, command, sizeof (command)) ;

    for (cmd = asave_cmds ; cmd->name ; ++cmd)
    {
          if (str_prefix (command, cmd->name))
                continue ;

          (*cmd->fun) (ch, argument) ;
          return ;
    }

    (asave_help) (ch, argument);

}

void save_changed (CHAR_DATA* ch, const char* argument)
{
    ASAVE_CMD*  cmd ;

    for (cmd = asave_cmds ; cmd->name ; ++cmd)
        if (IS_SET(cmd->asave_cmd_flag, ASAVE_CMD_CHANGED))
                (*cmd->fun) (ch, argument);

    do_asave_raw(ch, AREA_CHANGED);

    if (ch)
        char_puts("You saved changed areas and database.\n", ch);
    else
        log("Saved changed areas and database.");
    return;
}