/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements 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 *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMUD ROM Derivative (c) 2001-2002 by Ryan Jennings *
* http://1stmud.dlmud.com/ <r-jenn@shaw.ca> *
***************************************************************************/
/**************************************************************************
* File: olc_save.c *
* *
* 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. *
* *
* This code was freely distributed with the The Isles 1.1 source code, *
* and has been used here for OLC - OLC would not be what it is without *
* all the previous coders who released their source code. *
* *
***************************************************************************/
/* OLC_SAVE.C
* This takes care of saving all the .are information.
* Notes:
* -If a good syntax checker is used for setting vnum ranges of areas
* then it would become possible to just cycle through vnums instead
* of using the iHash stuff and checking that the room or reset or
* mob etc is part of that area.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "tables.h"
#include "olc.h"
#include "interp.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 */
/*****************************************************************************
Name: fix_string
Purpose: Returns a string without \r and ~.
****************************************************************************/
char *fix_string(const char *str)
{
static char strfix[MAX_STRING_LENGTH * 2];
int i;
int o;
if (str == NULL)
return '\0';
for (o = i = 0; str[i + o] != '\0'; i++)
{
if (str[i + o] == '\r' || str[i + o] == '~')
o++;
strfix[i] = str[i + o];
}
strfix[i] = '\0';
return strfix;
}
/*****************************************************************************
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 = file_open("area.lst", "w")) == NULL)
{
bug("Save_area_list: file_open", 0);
perror("area.lst");
}
else
{
fprintf(fp, "%s\n", HELP_FILE);
for (pArea = area_first; pArea; pArea = pArea->next)
{
fprintf(fp, "%s\n", pArea->file_name);
}
fprintf(fp, "$\n");
file_close(fp);
}
return;
}
#define NBUF 5
#define NBITS 52
char *fwrite_flags(flag_t flags)
{
static int cnt;
static char buf[NBUF][NBITS + 1];
flag_t count = 0, temp = 1;
cnt = (cnt + 1) % NBUF;
buf[cnt][0] = '+';
do
{
if (IS_SET(flags, (temp << count)))
buf[cnt][count + 1] = 'Y';
else
buf[cnt][count + 1] = 'n';
count++;
}
while ((temp << count) <= flags && count < 64);
buf[cnt][count + 1] = '\0';
return buf[cnt];
}
void save_mobprogs(FILE * fp, AREA_DATA * pArea)
{
PROG_CODE *pMprog;
vnum_t i;
fprintf(fp, "#MOBPROGS\n");
for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
{
if ((pMprog = get_prog_index(i, PRG_MPROG)) != NULL)
{
fprintf(fp, "#%ld\n", i);
fprintf(fp, "%s~\n", fix_string(pMprog->code));
}
}
fprintf(fp, "#0\n\n");
return;
}
void save_objprogs(FILE * fp, AREA_DATA * pArea)
{
PROG_CODE *pOprog;
vnum_t 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, "#%ld\n", i);
fprintf(fp, "%s~\n", fix_string(pOprog->code));
}
}
fprintf(fp, "#0\n\n");
return;
}
void save_roomprogs(FILE * fp, AREA_DATA * pArea)
{
PROG_CODE *pRprog;
vnum_t 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, "#%ld\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)
{
int race = pMobIndex->race;
PROG_LIST *pMprog;
flag_t temp;
fprintf(fp, "#%ld\n", pMobIndex->vnum);
fprintf(fp, "%s~\n", pMobIndex->player_name);
fprintf(fp, "%s~\n", pMobIndex->short_descr);
fprintf(fp, "%s~\n", fix_string(pMobIndex->long_descr));
fprintf(fp, "%s~\n", fix_string(pMobIndex->description));
fprintf(fp, "%s~\n", race_table[race].name);
fprintf(fp, "%s ", fwrite_flags(pMobIndex->act));
fprintf(fp, "%s ", fwrite_flags(pMobIndex->affected_by));
fprintf(fp, "%d %ld\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 ", fwrite_flags(pMobIndex->off_flags));
fprintf(fp, "%s ", fwrite_flags(pMobIndex->imm_flags));
fprintf(fp, "%s ", fwrite_flags(pMobIndex->res_flags));
fprintf(fp, "%s\n", fwrite_flags(pMobIndex->vuln_flags));
fprintf(fp, "%s %s %s %ld\n",
position_table[pMobIndex->start_pos].short_name,
position_table[pMobIndex->default_pos].short_name,
sex_table[pMobIndex->sex].name, pMobIndex->wealth);
fprintf(fp, "%s ", fwrite_flags(pMobIndex->form));
fprintf(fp, "%s ", fwrite_flags(pMobIndex->parts));
fprintf(fp, "%s ", size_table[pMobIndex->size].name);
fprintf(fp, "%s\n",
IS_NULLSTR(pMobIndex->material) ? pMobIndex->material : "unknown");
if ((temp = DIF(race_table[race].act, pMobIndex->act)))
fprintf(fp, "F act %s\n", fwrite_flags(temp));
if ((temp = DIF(race_table[race].aff, pMobIndex->affected_by)))
fprintf(fp, "F aff %s\n", fwrite_flags(temp));
if ((temp = DIF(race_table[race].off, pMobIndex->off_flags)))
fprintf(fp, "F off %s\n", fwrite_flags(temp));
if ((temp = DIF(race_table[race].imm, pMobIndex->imm_flags)))
fprintf(fp, "F imm %s\n", fwrite_flags(temp));
if ((temp = DIF(race_table[race].res, pMobIndex->res_flags)))
fprintf(fp, "F res %s\n", fwrite_flags(temp));
if ((temp = DIF(race_table[race].vuln, pMobIndex->vuln_flags)))
fprintf(fp, "F vul %s\n", fwrite_flags(temp));
if ((temp = DIF(race_table[race].form, pMobIndex->form)))
fprintf(fp, "F for %s\n", fwrite_flags(temp));
if ((temp = DIF(race_table[race].parts, pMobIndex->parts)))
fprintf(fp, "F par %s\n", fwrite_flags(temp));
for (pMprog = pMobIndex->first_mprog; pMprog; pMprog = pMprog->next)
{
fprintf(fp, "M %s %ld %s~\n",
prog_type_to_name(pMprog->trig_type), pMprog->vnum,
pMprog->trig_phrase);
}
return;
}
/*****************************************************************************
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)
{
vnum_t i;
MOB_INDEX_DATA *pMob;
fprintf(fp, "#MOBILES\n");
for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
{
if ((pMob = get_mob_index(i)))
save_mobile(fp, pMob);
}
fprintf(fp, "#0\n\n\n\n");
return;
}
/*****************************************************************************
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;
EXTRA_DESCR_DATA *pEd;
PROG_LIST *pOprog;
fprintf(fp, "#%ld\n", pObjIndex->vnum);
fprintf(fp, "%s~\n", pObjIndex->name);
fprintf(fp, "%s~\n", pObjIndex->short_descr);
fprintf(fp, "%s~\n", fix_string(pObjIndex->description));
fprintf(fp, "%s~\n", pObjIndex->material);
fprintf(fp, "%s ", item_name(pObjIndex->item_type));
fprintf(fp, "%s ", fwrite_flags(pObjIndex->extra_flags));
fprintf(fp, "%s\n", fwrite_flags(pObjIndex->wear_flags));
/*
* Using fwrite_flag 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 ", fwrite_flags(pObjIndex->value[0]));
fprintf(fp, "%s ", fwrite_flags(pObjIndex->value[1]));
fprintf(fp, "%s ", fwrite_flags(pObjIndex->value[2]));
fprintf(fp, "%s ", fwrite_flags(pObjIndex->value[3]));
fprintf(fp, "%s\n", fwrite_flags(pObjIndex->value[4]));
break;
case ITEM_DRINK_CON:
case ITEM_FOUNTAIN:
fprintf(fp, "%ld %ld '%s' %ld %ld\n", pObjIndex->value[0],
pObjIndex->value[1],
liq_table[pObjIndex->value[2]].liq_name,
pObjIndex->value[3], pObjIndex->value[4]);
break;
case ITEM_CONTAINER:
fprintf(fp, "%ld %s %ld %ld %ld\n", pObjIndex->value[0],
fwrite_flags(pObjIndex->value[1]),
pObjIndex->value[2], pObjIndex->value[3], pObjIndex->value[4]);
break;
case ITEM_WEAPON:
fprintf(fp, "%s %ld %ld %s %s\n",
weapon_name(pObjIndex->value[0]),
pObjIndex->value[1], pObjIndex->value[2],
attack_table[pObjIndex->value[3]].name,
fwrite_flags(pObjIndex->value[4]));
break;
case ITEM_PILL:
case ITEM_POTION:
case ITEM_SCROLL:
fprintf(fp, "%ld '%s' '%s' '%s' '%s'\n", pObjIndex->value[0] > 0 ? /* no negative numbers */
pObjIndex->value[0] : 0,
pObjIndex->value[1] !=
-1 ? skill_table[pObjIndex->value[1]].name : "",
pObjIndex->value[2] !=
-1 ? skill_table[pObjIndex->value[2]].name : "",
pObjIndex->value[3] !=
-1 ? skill_table[pObjIndex->value[3]].name : "",
pObjIndex->value[4] !=
-1 ? skill_table[pObjIndex->value[4]].name : "");
break;
case ITEM_STAFF:
case ITEM_WAND:
fprintf(fp, "%ld %ld %ld '%s' %ld\n", pObjIndex->value[0],
pObjIndex->value[1], pObjIndex->value[2],
pObjIndex->value[3] !=
-1 ? skill_table[pObjIndex->value[3]].name : "",
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->first_affect; 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_IMMUNE:
fprintf(fp, "I ");
break;
case TO_RESIST:
fprintf(fp, "R ");
break;
case TO_VULN:
fprintf(fp, "V ");
break;
default:
bug("olc_save: Invalid Affect->where", 0);
break;
}
fprintf(fp, "%d %d %s\n", pAf->location, pAf->modifier,
fwrite_flags(pAf->bitvector));
}
}
for (pEd = pObjIndex->first_extra_descr; pEd; pEd = pEd->next)
{
fprintf(fp, "E\n%s~\n%s~\n", pEd->keyword,
fix_string(pEd->description));
}
for (pOprog = pObjIndex->first_oprog; pOprog; pOprog = pOprog->next)
{
fprintf(fp, "O %s %ld %s~\n",
prog_type_to_name(pOprog->trig_type), pOprog->vnum,
pOprog->trig_phrase);
}
return;
}
/*****************************************************************************
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)
{
vnum_t i;
OBJ_INDEX_DATA *pObj;
fprintf(fp, "#OBJECTS\n");
for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
{
if ((pObj = get_obj_index(i)))
save_object(fp, pObj);
}
fprintf(fp, "#0\n\n\n\n");
return;
}
/*****************************************************************************
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;
EXTRA_DESCR_DATA *pEd;
EXIT_DATA *pExit;
int iHash;
int door;
PROG_LIST *pRprog;
fprintf(fp, "#ROOMS\n");
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
{
for (pRoomIndex = room_index_hash[iHash]; pRoomIndex;
pRoomIndex = pRoomIndex->next)
{
if (pRoomIndex->area == pArea)
{
fprintf(fp, "#%ld\n", pRoomIndex->vnum);
fprintf(fp, "%s~\n", pRoomIndex->name);
fprintf(fp, "%s~\n", fix_string(pRoomIndex->description));
fprintf(fp, "0 ");
fprintf(fp, "%s ", fwrite_flags(pRoomIndex->room_flags));
fprintf(fp, "%d\n", pRoomIndex->sector_type);
for (pEd = pRoomIndex->first_extra_descr; pEd; pEd = pEd->next)
{
fprintf(fp, "E\n%s~\n%s~\n",
pEd->keyword, fix_string(pEd->description));
}
for (door = 0; door < MAX_DIR; door++) /* I hate this! */
{
if ((pExit = pRoomIndex->exit[door]) && pExit->u1.to_room)
{
int locks = 0;
/* 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))
SET_BIT(pExit->rs_flags, EX_ISDOOR);
else
REMOVE_BIT(pExit->rs_flags, EX_ISDOOR);
/* THIS SUCKS but it's backwards compatible */
/* NOTE THAT EX_NOCLOSE NOLOCK etc aren't being saved */
if (IS_SET
(pExit->rs_flags, EX_ISDOOR)
&&
(!IS_SET
(pExit->rs_flags,
EX_PICKPROOF))
&& (!IS_SET(pExit->rs_flags, EX_NOPASS)))
locks = 1;
if (IS_SET
(pExit->rs_flags, EX_ISDOOR)
&&
(IS_SET
(pExit->rs_flags,
EX_PICKPROOF))
&& (!IS_SET(pExit->rs_flags, EX_NOPASS)))
locks = 2;
if (IS_SET
(pExit->rs_flags, EX_ISDOOR)
&&
(!IS_SET
(pExit->rs_flags,
EX_PICKPROOF))
&& (IS_SET(pExit->rs_flags, EX_NOPASS)))
locks = 3;
if (IS_SET
(pExit->rs_flags, EX_ISDOOR)
&&
(IS_SET
(pExit->rs_flags,
EX_PICKPROOF))
&& (IS_SET(pExit->rs_flags, EX_NOPASS)))
locks = 4;
fprintf(fp, "D%d\n", pExit->orig_door);
fprintf(fp, "%s~\n", fix_string(pExit->description));
fprintf(fp, "%s~\n", pExit->keyword);
fprintf(fp, "%d %ld %ld\n",
locks, pExit->key, pExit->u1.to_room->vnum);
}
}
if (pRoomIndex->mana_rate != 100 ||
pRoomIndex->heal_rate != 100)
fprintf(fp, "M %d H %d\n",
pRoomIndex->mana_rate, pRoomIndex->heal_rate);
if (pRoomIndex->clan > -1)
fprintf(fp, "C %s~\n", clan_table[pRoomIndex->clan].name);
if (!IS_NULLSTR(pRoomIndex->owner))
fprintf(fp, "O %s~\n", pRoomIndex->owner);
for (pRprog = pRoomIndex->first_rprog; pRprog;
pRprog = pRprog->next)
{
fprintf(fp, "R %s %ld %s~\n",
prog_type_to_name(pRprog->trig_type), pRprog->vnum,
pRprog->trig_phrase);
}
fprintf(fp, "S\n");
}
}
}
fprintf(fp, "#0\n\n\n\n");
return;
}
/*****************************************************************************
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 iHash;
MOB_INDEX_DATA *pMobIndex;
fprintf(fp, "#SPECIALS\n");
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
{
for (pMobIndex = mob_index_hash[iHash]; pMobIndex;
pMobIndex = pMobIndex->next)
{
if (pMobIndex && pMobIndex->area == pArea && pMobIndex->spec_fun)
{
#if defined( VERBOSE )
fprintf(fp, "M %d %s Load to: %s\n",
pMobIndex->vnum,
spec_name(pMobIndex->spec_fun), pMobIndex->short_descr);
#else
fprintf(fp, "M %ld %s\n", pMobIndex->vnum,
spec_name(pMobIndex->spec_fun));
#endif
}
}
}
fprintf(fp, "S\n\n\n\n");
return;
}
/*
* 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_resets(FILE * fp, AREA_DATA * pArea)
{
int iHash;
ROOM_INDEX_DATA *pRoomIndex;
EXIT_DATA *pExit;
int door;
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
{
for (pRoomIndex = room_index_hash[iHash]; pRoomIndex;
pRoomIndex = pRoomIndex->next)
{
if (pRoomIndex->area == pArea)
{
for (door = 0; door < MAX_DIR; door++)
{
if ((pExit = pRoomIndex->exit[door]) &&
pExit->u1.to_room &&
(IS_SET(pExit->rs_flags, EX_CLOSED)
|| IS_SET(pExit->rs_flags, EX_LOCKED)))
#if defined( VERBOSE )
fprintf(fp,
"D 0 %d %d %d The %s door of %s is %s\n",
pRoomIndex->vnum,
pExit->orig_door,
IS_SET(pExit->rs_flags,
EX_LOCKED) ? 2 : 1,
dir_name[pExit->orig_door],
pRoomIndex->name,
IS_SET(pExit->rs_flags,
EX_LOCKED) ?
"closed and locked" : "closed");
#endif
#if !defined( VERBOSE )
fprintf(fp, "D 0 %ld %d %d\n",
pRoomIndex->vnum,
pExit->orig_door,
IS_SET(pExit->rs_flags, EX_LOCKED) ? 2 : 1);
#endif
}
}
}
}
return;
}
/*****************************************************************************
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)
{
RESET_DATA *pReset;
MOB_INDEX_DATA *pLastMob = NULL;
OBJ_INDEX_DATA *pLastObj;
ROOM_INDEX_DATA *pRoom;
char buf[MAX_STRING_LENGTH];
int iHash;
fprintf(fp, "#RESETS\n");
save_door_resets(fp, pArea);
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
{
for (pRoom = room_index_hash[iHash]; pRoom; pRoom = pRoom->next)
{
if (pRoom->area == pArea)
{
for (pReset = pRoom->reset_first; pReset; pReset = pReset->next)
{
switch (pReset->command)
{
default:
bug("Save_resets: bad command %c.", pReset->command);
break;
#if defined( VERBOSE )
case 'M':
pLastMob = get_mob_index(pReset->arg1);
fprintf(fp,
"M 0 %ld %d %ld %d Load %s\n",
pReset->arg1,
pReset->arg2,
pReset->arg3,
pReset->arg4, pLastMob->short_descr);
break;
case 'O':
pLastObj = get_obj_index(pReset->arg1);
pRoom = get_room_index(pReset->arg3);
fprintf(fp,
"O 0 %ld 0 %ld %s loaded to %s\n",
pReset->arg1,
pReset->arg3,
capitalize(pLastObj->short_descr), pRoom->name);
break;
case 'P':
pLastObj = get_obj_index(pReset->arg1);
fprintf(fp,
"P 0 %ld %d %ld %d %s put inside %s\n",
pReset->arg1,
pReset->arg2,
pReset->arg3,
pReset->arg4,
capitalize(get_obj_index
(pReset->arg1)->short_descr),
pLastObj->short_descr);
break;
case 'G':
fprintf(fp,
"G 0 %ld 0 %s is given to %s\n",
pReset->arg1,
capitalize(get_obj_index
(pReset->arg1)->short_descr),
pLastMob ? pLastMob->short_descr : "!NO_MOB!");
if (!pLastMob)
{
sprintf(buf,
"Save_resets: !NO_MOB! in [%s]",
pArea->file_name);
bug(buf, 0);
}
break;
case 'E':
fprintf(fp,
"E 0 %ld 0 %ld %s is loaded %s of %s\n",
pReset->arg1,
pReset->arg3,
capitalize(get_obj_index
(pReset->arg1)->short_descr),
flag_string
(wear_loc_strings,
pReset->arg3),
pLastMob ? pLastMob->short_descr : "!NO_MOB!");
if (!pLastMob)
{
sprintf(buf,
"Save_resets: !NO_MOB! in [%s]",
pArea->file_name);
bug(buf, 0);
}
break;
case 'D':
break;
case 'R':
pRoom = get_room_index(pReset->arg1);
fprintf(fp,
"R 0 %ld %d Randomize %s\n",
pReset->arg1, pReset->arg2, pRoom->name);
break;
#endif
#if !defined( VERBOSE )
case 'M':
pLastMob = get_mob_index(pReset->arg1);
fprintf(fp,
"M 0 %ld %d %ld %d\n",
pReset->arg1,
pReset->arg2, pReset->arg3, pReset->arg4);
break;
case 'O':
pLastObj = get_obj_index(pReset->arg1);
pRoom = get_room_index(pReset->arg3);
fprintf(fp, "O 0 %ld 0 %ld\n",
pReset->arg1, pReset->arg3);
break;
case 'P':
pLastObj = get_obj_index(pReset->arg1);
fprintf(fp,
"P 0 %ld %d %ld %d\n",
pReset->arg1,
pReset->arg2, pReset->arg3, pReset->arg4);
break;
case 'G':
fprintf(fp, "G 0 %ld 0\n", pReset->arg1);
if (!pLastMob)
{
sprintf(buf,
"Save_resets: !NO_MOB! in [%s]",
pArea->file_name);
bug(buf, 0);
}
break;
case 'E':
fprintf(fp, "E 0 %ld 0 %ld\n",
pReset->arg1, pReset->arg3);
if (!pLastMob)
{
sprintf(buf,
"Save_resets: !NO_MOB! in [%s]",
pArea->file_name);
bug(buf, 0);
}
break;
case 'D':
break;
case 'R':
pRoom = get_room_index(pReset->arg1);
fprintf(fp, "R 0 %ld %d\n", pReset->arg1, pReset->arg2);
break;
#endif
}
}
} /* End if correct area */
} /* End for pRoom */
} /* End for iHash */
fprintf(fp, "S\n\n\n\n");
return;
}
/*****************************************************************************
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)
{
SHOP_DATA *pShopIndex;
MOB_INDEX_DATA *pMobIndex;
int iTrade;
int iHash;
fprintf(fp, "#SHOPS\n");
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
{
for (pMobIndex = mob_index_hash[iHash]; pMobIndex;
pMobIndex = pMobIndex->next)
{
if (pMobIndex && pMobIndex->area == pArea && pMobIndex->pShop)
{
pShopIndex = pMobIndex->pShop;
fprintf(fp, "%ld ", 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);
}
}
}
fprintf(fp, "0\n\n\n\n");
return;
}
void save_helps(void)
{
HELP_DATA *help;
FILE *fp;
#if !defined(WIN32)
char *TEMPFILE = HELP_FILE ".tmp";
if ((fp = file_open(TEMPFILE, "w")) != NULL)
#else
if ((fp = file_open(HELP_FILE, "w")) != NULL)
#endif
{
fprintf(fp, "#HELPS\n");
for (help = help_first; help; help = help->next)
{
fprintf(fp, "%d %s~\n", help->level, help->keyword);
fprintf(fp, "%s~\n\n", fix_string(help->text));
}
fprintf(fp, "-1 $~\n\n");
fprintf(fp, "#$\n");
}
else
bug("Error opening " HELP_FILE ".", 0);
file_close(fp);
#if !defined(WIN32)
rename(TEMPFILE, HELP_FILE);
#endif
return;
}
/*****************************************************************************
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;
if (!(fp = file_open(pArea->file_name, "w")))
{
bug("Open_area: file_open", 0);
perror(pArea->file_name);
}
REMOVE_BIT(pArea->area_flags, AREA_CHANGED);
fprintf(fp, "#AREADATA\n");
fprintf(fp, "Name %s~\n", pArea->name);
fprintf(fp, "Builders %s~\n", fix_string(pArea->builders));
fprintf(fp, "VNUMs %ld %ld\n", pArea->min_vnum, pArea->max_vnum);
fprintf(fp, "Credits %s~\n", pArea->credits);
fprintf(fp, "Security %d\n", pArea->security);
fprintf(fp, "Flags %s\n", fwrite_flags(pArea->area_flags));
fprintf(fp, "End\n\n\n\n");
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_mobprogs(fp, pArea);
save_objprogs(fp, pArea);
save_roomprogs(fp, pArea);
fprintf(fp, "#$\n");
file_close(fp);
return;
}
/*****************************************************************************
Name: do_asave
Purpose: Entry point for saving area data.
Called by: interpreter(interp.c)
****************************************************************************/
CH_CMD(do_asave)
{
char arg1[MAX_INPUT_LENGTH];
AREA_DATA *pArea;
FILE *fp;
int value, sec;
fp = NULL;
if (!ch) /* Do an autosave */
sec = 9;
else if (!IS_NPC(ch))
sec = ch->pcdata->security;
else
sec = 0;
/* {
save_area_list();
for( pArea = area_first; pArea; pArea = pArea->next )
{
save_area( pArea );
REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
}
return;
} */
smash_tilde(argument);
strcpy(arg1, argument);
if (arg1[0] == '\0')
{
if (ch)
{
chprintln(ch, "Syntax:");
chprintln(ch, " asave <vnum> - saves a particular area");
chprintln(ch, " asave list - saves the area.lst file");
chprintln(ch, " asave area - saves the area being edited");
chprintln(ch, " asave changed - saves all changed zones");
chprintln(ch, " asave world - saves the world! (db dump)");
chprintln(ch, " asave clans - saves clan data");
chprintln(ch, " asave commands - saves command data");
chprintln(ch, " asave skills - saves skill data");
chprintln(ch, " asave groups - saves group data");
chprintln(ch, " asave races - saves race data");
chprintln(ch, " asave classes - saves class data");
chprintln(ch, " asave socials - saves social data");
chprintln(ch, " asave helps - saves the help file");
chprintln(ch, " asave deity - save deity data");
chprintln(ch, "");
}
return;
}
/* Snarf the value (which need not be numeric). */
value = atoi(arg1);
if (!(pArea = get_area_data(value)) && is_number(arg1))
{
if (ch)
chprintln(ch, "That area does not exist.");
return;
}
/* Save area of given vnum. */
/* ------------------------ */
if (is_number(arg1))
{
if (ch && !IS_BUILDER(ch, pArea))
{
chprintln(ch, "You are not a builder for this area.");
return;
}
save_area_list();
save_area(pArea);
return;
}
/* Save the world, only authorized areas. */
/* -------------------------------------- */
if (!str_cmp("world", arg1))
{
save_area_list();
for (pArea = area_first; pArea; pArea = pArea->next)
{
/* Builder must be assigned this area. */
if (ch && !IS_BUILDER(ch, pArea))
continue;
save_area(pArea);
REMOVE_BIT(pArea->area_flags, AREA_CHANGED);
}
if (ch)
chprintln(ch, "You saved the world.");
save_helps();
return;
}
/* Save changed areas, only authorized areas. */
/* ------------------------------------------ */
if (!str_cmp("changed", arg1))
{
char buf[MAX_INPUT_LENGTH];
save_area_list();
if (ch)
chprintln(ch, "Saved zones:");
else
log_string("Saved zones:");
sprintf(buf, "None.\n\r");
for (pArea = area_first; pArea; pArea = pArea->next)
{
/* Builder must be assigned this area. */
if (ch && !IS_BUILDER(ch, pArea))
continue;
/* Save changed areas. */
if (IS_SET(pArea->area_flags, AREA_CHANGED))
{
save_area(pArea);
sprintf(buf, "%24s - '%s'", pArea->name, pArea->file_name);
if (ch)
{
chprint(ch, buf);
chprintln(ch, "");
}
else
log_string(buf);
REMOVE_BIT(pArea->area_flags, AREA_CHANGED);
}
}
if (!str_cmp(buf, "None.\n\r"))
{
if (ch)
chprint(ch, buf);
else
log_string("None.");
}
return;
}
/* Save the area.lst file. */
/* ----------------------- */
if (!str_cmp(arg1, "list"))
{
save_area_list();
return;
}
if (!str_cmp(arg1, "clans"))
{
save_clans();
chprint(ch, "Clans saved.");
return;
}
if (!str_cmp(arg1, "socials"))
{
save_social_table();
chprintln(ch, "Socials saved.");
return;
}
if (!str_cmp(arg1, "helps"))
{
save_area_list();
save_helps();
chprintln(ch, "Helps saved.");
return;
}
if (!str_cmp(arg1, "deity"))
{
save_deities();
if (ch)
chprintln(ch, "Deity data saved.");
return;
}
if (!str_cmp(arg1, "commands"))
{
save_commands();
chprintln(ch, "Commands saved.");
return;
}
if (!str_cmp(arg1, "skills"))
{
save_skills();
chprintln(ch, "Skills saved.");
return;
}
if (!str_cmp(arg1, "groups"))
{
save_groups();
chprintln(ch, "Groups saved.");
return;
}
if (!str_cmp(arg1, "races"))
{
save_races();
chprintln(ch, "Races saved.");
return;
}
if (!str_cmp(arg1, "classes"))
{
save_classes();
chprintln(ch, "Classes saved.");
return;
}
/* Save area being edited, if authorized. */
/* -------------------------------------- */
if (!str_cmp(arg1, "area"))
{
if (!ch || !ch->desc)
return;
/* Is character currently editing. */
if (ch->desc->editor == ED_NONE)
{
chprintln(ch, "You are not editing an area, "
"therefore an area vnum is required.");
return;
}
/* Find the area to save. */
switch (ch->desc->editor)
{
case ED_AREA:
pArea = (AREA_DATA *) ch->desc->pEdit;
break;
case ED_ROOM:
pArea = ch->in_room->area;
break;
case ED_OBJECT:
pArea = ((OBJ_INDEX_DATA *) ch->desc->pEdit)->area;
break;
case ED_MOBILE:
pArea = ((MOB_INDEX_DATA *) ch->desc->pEdit)->area;
break;
default:
pArea = ch->in_room->area;
break;
}
if (!IS_BUILDER(ch, pArea))
{
chprintln(ch, "You are not a builder for this area.");
return;
}
save_area_list();
save_area(pArea);
REMOVE_BIT(pArea->area_flags, AREA_CHANGED);
chprintln(ch, "Area saved.");
return;
}
/* Show correct syntax. */
/* -------------------- */
if (ch)
do_asave(ch, "");
return;
}