/*
* $Id: olc_save.c,v 1.66 1999/04/16 15:52:25 fjoe Exp $
*/
/**************************************************************************
* 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.
*/
#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"
#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, ...);
/*****************************************************************************
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)
return;
for (pArea = area_first; pArea; pArea = pArea->next)
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");
}
/*****************************************************************************
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;
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 ", format_flags(pMobIndex->imm_flags & ~r->imm));
fprintf(fp, "%s ", format_flags(pMobIndex->res_flags & ~r->res));
fprintf(fp, "%s\n", format_flags(pMobIndex->vuln_flags & ~r->vuln));
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, "%s ", flag_string(size_table, 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->imm, pMobIndex->imm_flags)))
fprintf(fp, "F imm %s\n", format_flags(temp));
if ((temp = DIF(r->res, pMobIndex->res_flags)))
fprintf(fp, "F res %s\n", format_flags(temp));
if ((temp = DIF(r->vuln, pMobIndex->vuln_flags)))
fprintf(fp, "F vul %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->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;
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:
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,
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_IMMUNE:
fprintf(fp, "I ");
break;
case TO_RESIST:
fprintf(fp, "R ");
break;
case TO_VULN:
fprintf(fp, "V ");
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,
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));
}
/*****************************************************************************
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;
fprintf(fp, "#%d\n", pRoomIndex->vnum);
mlstr_fwrite(fp, NULL, pRoomIndex->name);
mlstr_fwrite(fp, NULL, pRoomIndex->description);
fprintf(fp, "0 ");
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) )
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\n",
format_flags(pExit->rs_flags | EX_BITVAL),
pExit->key,
pExit->to_room.r->vnum);
}
}
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));
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[i] != NULL)
fprintf(fp, "O %d %s %s\t* `%s'\n",
pObjIndex->vnum,
optype_table[i],
oprog_name_lookup(pObjIndex->oprogs[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) {
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;
if ((fp = dfopen(AREA_PATH, pArea->file_name, "w")) == NULL)
return;
fprintf(fp, "#AREADATA\n");
fprintf(fp, "Name %s~\n", pArea->name);
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;
if (flags)
fwrite_string(fp, "Flags", flag_string(area_flags, flags));
if (pArea->clan)
fwrite_string(fp, "Clan", clan_name(pArea->clan));
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_helps(fp, pArea);
fprintf(fp, "#$\n");
fclose(fp);
}
void save_skills()
{
}
void save_clan(CHAR_DATA *ch, clan_t *clan)
{
int i;
FILE *fp;
/* save clan data */
if ((fp = dfopen(CLANS_PATH, clan->file_name, "w")) == NULL) {
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->recall_vnum)
fprintf(fp, "Recall %d\n", clan->recall_vnum);
if (clan->obj_vnum)
fprintf(fp, "Item %d\n", clan->obj_vnum);
if (clan->mark_vnum)
fprintf(fp, "Mark %d\n", clan->mark_vnum);
if (clan->altar_vnum)
fprintf(fp, "Altar %d\n", clan->altar_vnum);
REMOVE_BIT(clan->flags, CLAN_CHANGED);
if (clan->flags)
fprintf(fp, "Flags %s~\n",
flag_string(clan_flags, clan->flags));
for (i = 0; i < clan->skills.nused; i++) {
clskill_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);
}
fprintf(fp, "End\n\n"
"#$\n");
fclose(fp);
/* save plists */
if ((fp = dfopen(PLISTS_PATH, clan->file_name, "w")) == NULL) {
save_print(ch, "%s%c%s: %s", PLISTS_PATH,
PATH_SEPARATOR, clan->file_name,
strerror(errno));
return;
}
fprintf(fp, "#PLISTS\n");
fwrite_string(fp, "Leaders", clan->leader_list);
fwrite_string(fp, "Seconds", clan->second_list);
fwrite_string(fp, "Members", clan->member_list);
fprintf(fp, "End\n\n"
"#$\n");
fclose(fp);
save_print(ch, " %s (%s)", clan->name, clan->file_name);
}
void save_clans(CHAR_DATA *ch)
{
int i;
FILE *fp;
bool found = FALSE;
int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;
if (sec < SECURITY_CLAN) {
save_print(ch, "Insufficient security to save clans.");
return;
}
if ((fp = dfopen(CLANS_PATH, CLAN_LIST, "w")) == 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));
found = TRUE;
}
}
fprintf(fp, "$\n");
fclose(fp);
if (!found)
save_print(ch, " None.");
}
void save_msgdb(CHAR_DATA *ch)
{
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;
}
if ((fp = dfopen(ETC_PATH, MSG_FILE, "w")) == 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;
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;
if ((fp = dfopen(LANG_PATH, l->file_name, "w")) == 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)
{
int lang;
bool list = FALSE;
int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;
if (sec < SECURITY_MSGDB) {
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)
{
int lang;
int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;
if (sec < SECURITY_MSGDB) {
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_social(FILE *fp, social_t *soc)
{
fprintf(fp, "#SOCIAL\n");
fprintf(fp, "name %s\n", soc->name);
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, "notfound_char", soc->notfound_char);
fprintf(fp, "end\n\n");
}
void save_socials(CHAR_DATA *ch)
{
int i;
FILE *fp;
int sec = ch ? (IS_NPC(ch) ? 0 : ch->pcdata->security) : 9;
if (sec < 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 save_areas(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;
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();
}
/*****************************************************************************
Name: do_asave
Purpose: Entry point for saving area data.
Called by: interpreter(interp.c)
****************************************************************************/
void do_asave(CHAR_DATA *ch, const char *argument)
{
if (argument[0] == '\0') {
if (ch)
do_help(ch, "'OLC ASAVE'");
return;
}
/* Save the world, only authorized areas. */
/* -------------------------------------- */
if (!str_cmp("world", argument)) {
save_areas(ch, 0);
if (ch)
char_puts("You saved the world.\n", ch);
else
log("Saved the world");
return;
}
/* Save changed areas, only authorized areas. */
/* ------------------------------------------ */
if (!str_cmp("changed", argument)) {
save_areas(ch, AREA_CHANGED);
if (ch)
char_puts("You saved changed areas.\n", ch);
else
log("Saved changed areas");
return;
}
if (!str_cmp("skills", argument)) {
save_skills(ch);
if (ch)
char_puts("You saved skills table.\n", ch);
else
log("Saved skills table");
return;
}
if (!str_cmp("rules", argument)) {
save_rules(ch);
return;
}
if (!str_cmp("clans", argument)) {
save_clans(ch);
return;
}
if (!str_cmp("msgdb", argument)) {
save_msgdb(ch);
return;
}
if (!str_cmp("langs", argument)) {
save_langs(ch);
return;
}
if (!str_cmp("socials", argument)) {
save_socials(ch);
return;
}
/* Show correct syntax. */
/* -------------------- */
if (ch)
do_asave(ch, str_empty);
}
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);
}