/**************************************************************************/
// olc_save.cpp - saves area files etc
/***************************************************************************
* The Dawn of Time v1.69r (c)1997-2004 Michael Garratt *
* >> A number of people have contributed to the Dawn codebase, with the *
* majority of code written by Michael Garratt - www.dawnoftime.org *
* >> To use this source code, you must fully comply with the dawn license *
* in licenses.txt... In particular, you may not remove this copyright *
* notice. *
**************************************************************************/
/***************************************************************************
* 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 "include.h" // dawn standard includes
#include "areas.h"
#include "olc.h"
#include "immquest.h"
#include "offmoot.h"
#include "interp.h"
#include "help.h"
#include "lockers.h"
char *gamble_name( GAMBLE_FUN *function);
void save_attunes( FILE *fp, AREA_DATA *pArea );
void save_mix_db( void);
DECLARE_DO_FUN( do_saveherbs );
#define DIF(a,b) (~((~a)|(b)))
// areas.cpp
void save_rooms_NAFF( FILE *fp, AREA_DATA *pArea );
void save_object_NAFF( FILE *fp, OBJ_INDEX_DATA *pObjIndex );
void save_mobile_NAFF( FILE *fp, MOB_INDEX_DATA *pMobIndex );
/*
* 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 int mri; // multi result index
static char *multi_result[5]; // circular managed result buffer
// nothing to do with empty strings
if( IS_NULLSTR(str)){
return "";
}
// rotate buffers
++mri%=5;
manage_dynamic_buffer(&multi_result[mri], str_len(str)+2); // maintain result so always has enough space
char *result=multi_result[mri]; // managed result buffer
const char *in=str;
char *out=result;
while(*in!='\0') // loop thru, copying into result
{
while ((*in== '\r' || *in== '~')){
in++;
}
if(*in!='\0'){
*out++= *in++;
}
}
*out = '\0'; // terminate the string
return result;
}
/*****************************************************************************
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 = fopen( AREA_LIST".write", "w" ) ) == NULL ){
bugf("save_area_list(): fopen '%s' for write - error %d (%s)",
AREA_LIST".write", errno, strerror( errno));
}else{
for( pArea = area_first; pArea; pArea = pArea->next ){
fprintf( fp, "%s\n", pArea->file_name);
}
int bytes_written=fprintf( fp, "$\n" );
fclose( fp );
if( bytes_written != str_len("$\n") ){
bugf("save_area_list(): fprintf to '%s' - error %d (%s)",
AREA_LIST".write", errno, strerror( errno));
bugf("Incomplete write of " AREA_LIST ".write, write aborted - check diskspace!");
}else{
unlink(AREA_LIST);
rename(AREA_LIST".write", AREA_LIST);
}
}
return;
}
/**************************************************************************/
/*
* ROM OLC
* Used in save_mobile and save_object below. Writes
* flags on the form fread_flag reads.
*
* buf[] must hold at least 32+1 characters.
*
* -- Hugin
*/
char *fwrite_flag( long flags, char buf[] )
{
char offset;
char *cp;
static char local_buf[33];
if(buf==NULL){
buf=local_buf;
}
buf[0] = '\0';
if ( flags == 0 )
{
strcpy( buf, "0" );
return buf;
}
/* 32 -- number of bits in a long */
for ( offset = 0, cp = buf; offset < 32; offset++ ){
if ( flags & ( (long)1 << offset ) )
{
if ( offset <= 'Z' - 'A' ){
*(cp++) = 'A' + offset;
}else{
*(cp++) = 'a' + offset - ( 'Z' - 'A' + 1 );
}
}
}
*cp = '\0';
return buf;
}
/**************************************************************************/
void save_mobprogs( FILE *fp, AREA_DATA *pArea )
{
MPROG_CODE *pMprog;
int i;
fprintf(fp, "#MOBPROGS\n");
for( i = pArea->max_vnum; i>=pArea->min_vnum; i-- )
{
if ( (pMprog = get_mprog_index(i) ) != NULL)
{
fprintf(fp, "#%d\n", i);
// mobprog names from version 4 up
if (area_last->version>3)
{
fprintf(fp, "%s~\n", pMprog->title?fix_string(pMprog->title):"");
fprintf(fp, "%s~\n", pMprog->author?fix_string(pMprog->author):"");
fprintf(fp, "%s~\n", pMprog->last_editor?fix_string(pMprog->last_editor):"");
fprintf(fp, "%ld\n", (long)pMprog->last_editdate);
}
fprintf(fp, "%s~\n", fix_string(pMprog->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 version)
{
sh_int race = pMobIndex->race;
MPROG_LIST *pMprog;
char buf[MSL];
long temp;
fprintf( fp, "#%d\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_flag( pMobIndex->act, buf ) );
fprintf( fp, "%s\n", fwrite_flag( pMobIndex->act2, buf ) );
fprintf( fp, "%s ", fwrite_flag( pMobIndex->affected_by, buf ) );
fprintf( fp, "%s\n", fwrite_flag( pMobIndex->affected_by2, buf ) );
fprintf( fp, "%d %d\n", pMobIndex->tendency, pMobIndex->alliance );
fprintf( fp, "%d\n", pMobIndex->xp_mod );
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 );
if(version<6){ // Area files versions 5 and lower divided ac by 10 in storage
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 );
}else{
fprintf( fp, "%d %d %d %d\n", pMobIndex->ac[AC_PIERCE],
pMobIndex->ac[AC_BASH],
pMobIndex->ac[AC_SLASH],
pMobIndex->ac[AC_EXOTIC]);
}
fprintf( fp, "%s ", fwrite_flag( pMobIndex->off_flags, buf ) );
fprintf( fp, "%s ", fwrite_flag( pMobIndex->imm_flags, buf ) );
fprintf( fp, "%s ", fwrite_flag( pMobIndex->res_flags, buf ) );
fprintf( fp, "%s\n", fwrite_flag( pMobIndex->vuln_flags, buf ) );
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_flag( pMobIndex->form, buf ) );
fprintf( fp, "%s ", fwrite_flag( pMobIndex->parts, buf ) );
fprintf( fp, "%s ", size_table[pMobIndex->size].name );
sprintf(buf, "%s", IS_NULLSTR(pMobIndex->material)? "unknown":pMobIndex->material);
if (has_space(buf)){
fprintf( fp, "'%s'\n" , buf); //quotes around materials with 2 words
}else{
fprintf( fp, "%s\n" , buf);
}
if (pMobIndex->group){
fprintf( fp, "G %d\n", pMobIndex->group);
}
if (pMobIndex->helpgroup){
fprintf( fp, "H %d\n", pMobIndex->helpgroup);
}
if ((temp = DIF(race_table[race]->act,pMobIndex->act)))
fprintf( fp, "F act %s\n", fwrite_flag(temp, buf) );
if ((temp = DIF(race_table[race]->aff,pMobIndex->affected_by)))
fprintf( fp, "F aff %s\n", fwrite_flag(temp, buf) );
if ((temp = DIF(race_table[race]->off,pMobIndex->off_flags)))
fprintf( fp, "F off %s\n", fwrite_flag(temp, buf) );
if ((temp = DIF(race_table[race]->imm,pMobIndex->imm_flags)))
fprintf( fp, "F imm %s\n", fwrite_flag(temp, buf) );
if ((temp = DIF(race_table[race]->res,pMobIndex->res_flags)))
fprintf( fp, "F res %s\n", fwrite_flag(temp, buf) );
if ((temp = DIF(race_table[race]->vuln,pMobIndex->vuln_flags)))
fprintf( fp, "F vul %s\n", fwrite_flag(temp, buf) );
if ((temp = DIF(race_table[race]->form,pMobIndex->form)))
fprintf( fp, "F for %s\n", fwrite_flag(temp, buf) );
if ((temp = DIF(race_table[race]->parts,pMobIndex->parts)))
fprintf( fp, "F par %s\n", fwrite_flag(temp, buf) );
for (pMprog = pMobIndex->mprogs; pMprog; pMprog = pMprog->next)
{
fprintf(fp, "M ");
if(pMprog->pos_flags){ // encode a little = so say position flags flow
fprintf(fp, "= %s ", flags_print(pMprog->pos_flags));
}
fprintf(fp, "%s %d %s~\n",
mprog_type_to_name(pMprog->trig_type), pMprog->prog->vnum,
pMprog->trig_phrase);
}
fprintf(fp, "\n");
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 )
{
int 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 )) )
if ( pArea->version<11){
save_mobile( fp, pMob, pArea->version);
}else{
save_mobile_NAFF( fp, pMob );
}
}
fprintf( fp, "#0\n\n\n\n" );
return;
}
/**************************************************************************/
// write the object values to fp
void save_object_values( FILE *fp, OBJ_INDEX_DATA *pObjIndex )
{
assertp(fp);
char buf[MSL], buf2[MSL];
switch ( pObjIndex->item_type )
{
default:
fprintf( fp, "%s ", fwrite_flag( pObjIndex->value[0], buf ) );
fprintf( fp, "%s ", fwrite_flag( pObjIndex->value[1], buf ) );
fprintf( fp, "%s ", fwrite_flag( pObjIndex->value[2], buf ) );
fprintf( fp, "%s ", fwrite_flag( pObjIndex->value[3], buf ) );
fprintf( fp, "%s\n",fwrite_flag( pObjIndex->value[4], buf ) );
break;
case ITEM_LIGHT:
fprintf( fp, "0 0 %d 0 0\n",
pObjIndex->value[2] < 1 ? -1 : pObjIndex->value[2] ); // infinite
break;
case ITEM_INSTRUMENT:
fprintf( fp, "%d %d 0 0 0\n",
pObjIndex->value[0],
pObjIndex->value[1] );
break;
case ITEM_MONEY:
fprintf( fp, "%d %d 0 0 0\n",
pObjIndex->value[0],
pObjIndex->value[1]);
break;
case ITEM_DRINK_CON:
fprintf( fp, "%d %d %s %d 0\n",
pObjIndex->value[0],
pObjIndex->value[1],
pack_word(liq_table[pObjIndex->value[2]].liq_name),
pObjIndex->value[3]);
break;
case ITEM_FOUNTAIN:
fprintf( fp, "%d %d %s %d 0\n",
pObjIndex->value[0],
pObjIndex->value[1],
pack_word(liq_table[pObjIndex->value[2]].liq_name),
pObjIndex->value[3]);
break;
case ITEM_CONTAINER:
case ITEM_CAULDRON:
case ITEM_FLASK:
case ITEM_MORTAR:
fprintf( fp, "%d %s %d %d %d\n",
pObjIndex->value[0],
fwrite_flag( pObjIndex->value[1], buf ),
pObjIndex->value[2],
pObjIndex->value[3],
pObjIndex->value[4]);
break;
case ITEM_COMPONENT:
fprintf( fp, "%d %s 0 0 0\n",
pObjIndex->value[0], // charges
pObjIndex->value[1]==-1?"none": // spell name
pack_word(skill_table[pObjIndex->value[1]].name));
break;
case ITEM_FOOD:
fprintf( fp, "%d %d 0 %s 0\n",
pObjIndex->value[0],
pObjIndex->value[1],
fwrite_flag( pObjIndex->value[3], buf ) );
break;
case ITEM_PORTAL:
fprintf( fp, "%d %s %s %d 0\n",
pObjIndex->value[0],
fwrite_flag( pObjIndex->value[1], buf ),
fwrite_flag( pObjIndex->value[2], buf2 ),
pObjIndex->value[3]);
break;
case ITEM_FURNITURE:
fprintf( fp, "%d %d %s %d %d\n",
pObjIndex->value[0],
pObjIndex->value[1],
fwrite_flag( pObjIndex->value[2], buf),
pObjIndex->value[3],
pObjIndex->value[4]);
break;
case ITEM_WEAPON:
fprintf( fp, "%s %d %d %s %s\n",
weapon_name(pObjIndex->value[0]),
pObjIndex->value[1],
pObjIndex->value[2],
attack_table[pObjIndex->value[3]].name,
fwrite_flag( pObjIndex->value[4], buf ) );
break;
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_PILL:
case ITEM_POTION:
case ITEM_SCROLL:
fprintf( fp, "%d %s %s %s %s\n",
pObjIndex->value[0] > 0 ? // no negative numbers
pObjIndex->value[0]
: 0,
pObjIndex->value[1] != -1 ?
pack_word(skill_table[pObjIndex->value[1]].name)
: "''",
pObjIndex->value[2] != -1 ?
pack_word(skill_table[pObjIndex->value[2]].name)
: "''",
pObjIndex->value[3] != -1 ?
pack_word(skill_table[pObjIndex->value[3]].name)
: "''",
pObjIndex->value[4] != -1 ?
pack_word(skill_table[pObjIndex->value[4]].name)
: "''");
break;
case ITEM_PARCHMENT:
fprintf( fp, "%d ", pObjIndex->value[0] );
fprintf( fp, "%d ", pObjIndex->value[1] );
fprintf( fp, "%d ", pObjIndex->value[2] );
fprintf( fp, "%s ", language_safe_lookup_by_id(pObjIndex->value[3])->name);
fprintf( fp, "%d ", pObjIndex->value[4] );
break;
case ITEM_POULTICE:
case ITEM_STAFF:
case ITEM_WAND:
fprintf( fp, "%d ", pObjIndex->value[0] );
fprintf( fp, "%d ", pObjIndex->value[1] );
fprintf( fp, "%d %s 0\n",
pObjIndex->value[2],
pObjIndex->value[3] != -1 ?
pack_word(skill_table[pObjIndex->value[3]].name)
: 0 );
break;
}
}
/*****************************************************************************
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=NULL;
EXTRA_DESCR_DATA *pEd;
char buf[MSL];
fprintf( fp, "#%d\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_flag( pObjIndex->extra_flags, buf ));
fprintf( fp, "%s ", fwrite_flag( pObjIndex->extra2_flags, buf ));
//fprintf( fp, "%s ", fwrite_flag( pObjIndex->extra3_flags, buf ));
if ( IS_TRAPPED( pObjIndex ))
{
fprintf( fp, "%ld %d %d %d ",
(long)pObjIndex->trap_trig,
pObjIndex->trap_dtype,
pObjIndex->trap_charge,
pObjIndex->trap_modifier );
}
fprintf( fp, "%s\n", fwrite_flag( pObjIndex->wear_flags, buf ));
/*
* Using fwrite_flag to write most values gives a strange
* looking area file, consider making a case for each
* item type later.
*/
save_object_values( fp, pObjIndex );
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 > 1 ) letter = 'B';
else letter = 'R';
fprintf( fp, "%c\n", letter );
fprintf( fp, "%d %d\n",
pObjIndex->absolute_size,
pObjIndex->relative_size);
// fprintf( fp, "%s\n", fwrite_flag(pObjIndex->clss_restriction, buf) );
for( pAf = pObjIndex->affected; pAf; pAf = pAf->next )
{
// if (pAf->where == WHERE_OBJEXTRA || pAf->bitvector == 0)
if (pAf->where == WHERE_OBJEXTRA)
fprintf( fp, "A %d %d\n", reverse_translate_old_apply_number(pAf->location), pAf->modifier );
else if (pAf->where == WHERE_OBJEXTRA2)
fprintf( fp, "B %d %d\n", reverse_translate_old_apply_number(pAf->location), pAf->modifier );
/*else if (pAf->where == WHERE_OBJEXTRA3)
fprintf( fp, "B %d %d\n", reverse_translate_old_apply_number(pAf->location), pAf->modifier
);*/
else
{
fprintf( fp, "F " );
switch(pAf->where)
{
case WHERE_AFFECTS:
fprintf( fp, "A " );
break;
case WHERE_AFFECTS2:
fprintf( fp, "B " );
break;
case WHERE_IMMUNE:
fprintf( fp, "I " );
break;
case WHERE_RESIST:
fprintf( fp, "R " );
break;
case WHERE_VULN:
fprintf( fp, "V " );
break;
case WHERE_SKILLS:
fprintf( fp, "K " );
break;
case WHERE_OBJECTSPELL:
fprintf( fp, "Z " );
break;
default:
bug("olc_save: Invalid Affect->where");
break;
}
if ( pAf->where == WHERE_SKILLS ) {
fprintf( fp, "'%s' %d\n", skill_table[pAf->type].name, pAf->modifier );
} else if (pAf->where == WHERE_OBJECTSPELL){
fprintf( fp, "'%s' %d %d %s\n", skill_table[pAf->type].name,
pAf->level, pAf->duration, fwrite_flag( pAf->bitvector, buf ));
}else{
fprintf( fp, "%d %d %s\n", reverse_translate_old_apply_number(pAf->location), pAf->modifier,
fwrite_flag( pAf->bitvector, buf ) );
}
}
}
// optional object stuff below here
if(pObjIndex->class_allowances){
//fwrite_wordflag(classnames_types, pObjIndex->class_allowances,"C ",fp);
fwrite_wordflag(classnames_flags, pObjIndex->class_allowances,"_CA ",fp);
}
// save classgroup object restrictions
{
OBJRESTRICT_LIST_DATA *pr;
for( pr = pObjIndex->restrict; pr; pr = pr->next )
{
fprintf( fp, "R %s %s %d 0\n",
pr->classgroup->name,
pr->affectprofile->
name,
pr->priority);
}
}
for( pEd = pObjIndex->extra_descr; pEd; pEd = pEd->next )
{
if (is_space(pEd->description[0]))
{
fprintf( fp, "E\n%s~\n.%s~\n", pEd->keyword,
fix_string( pEd->description ) );
}
else
{
fprintf( fp, "E\n%s~\n%s~\n", pEd->keyword,
fix_string( pEd->description ) );
}
}
fprintf(fp, "\n");
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 )
{
int 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 )) ){
if ( pArea->version<11){
save_object( fp, pObj );
}else{
save_object_NAFF( fp, pObj );
}
}
}
fprintf( fp, "#0\n\n\n\n" );
return;
}
/*****************************************************************************
Name: save_attunes
Purpose: Save #ATTUNE section of an area file.
Called by: save_area(olc_save.c).
****************************************************************************/
void save_attunes( FILE *fp, AREA_DATA *pArea )
{
OBJ_INDEX_DATA *pObj;
int i;
char buf[MSL];
fprintf( fp, "#ATTUNE\n" );
for ( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
{
if (( pObj = get_obj_index(i)))
{
if ( IS_SET( pObj->attune_flags, ATTUNE_NEED_TO_USE ))
{
fprintf( fp, "O %d %s\n",
pObj->vnum,
fwrite_flag( pObj->attune_flags, buf ));
}
}
}
fprintf( fp, "S\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;
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, "#%d\n", pRoomIndex->vnum );
fprintf( fp, "%s~\n", pRoomIndex->name );
fprintf( fp, "%s~\n", fix_string( pRoomIndex->description ) );
fprintf( fp, "0 " );
fprintf( fp, "%d ", pRoomIndex->room_flags );
fprintf( fp, "%d\n", pRoomIndex->sector_type );
for ( pEd = pRoomIndex->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 )
{
fprintf( fp, "D%d\n", door );
fprintf( fp, "%s~\n", fix_string( pExit->description ) );
fprintf( fp, "%s~\n", pExit->keyword );
fprintf( fp, "%s %d %d\n", // locks
flags_print(pExit->rs_flags),
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){
fprintf ( fp, "C %s~\n" , pRoomIndex->clan->savename());
}
if (pRoomIndex->owner && str_cmp(pRoomIndex->owner,""))
fprintf ( fp, "O %s~\n" , pRoomIndex->owner );
if (pRoomIndex->msp_sound)
fprintf ( fp, "X %s~\n" , pRoomIndex->msp_sound );
fprintf( fp, "S\n\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;
OBJ_INDEX_DATA *pObjIndex;
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 %d %s\n", pMobIndex->vnum,
spec_name( pMobIndex->spec_fun ) );
#endif
}
}
// Go through the objects and save their obj_spec_funs too :)
for( pObjIndex = obj_index_hash[iHash]; pObjIndex; pObjIndex = pObjIndex->next )
{
if ( pObjIndex && pObjIndex->area == pArea && pObjIndex->ospec_fun )
{
fprintf( fp, "O %d %s Load to: %s\n", pObjIndex->vnum,
ospec_name( pObjIndex->ospec_fun ),
pObjIndex->short_descr );
}
}
}
fprintf( fp, "S\n\n\n\n" );
return;
}
/*****************************************************************************
Name: save_gamble
Purpose: Save #GAMBLE section of area file.
Called by: save_area(olc_save.c).
****************************************************************************/
void save_gamble( FILE *fp, AREA_DATA *pArea )
{
int iHash;
MOB_INDEX_DATA *pMobIndex;
fprintf( fp, "#GAMBLE\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->gamble_fun )
{
fprintf( fp, "M %d %s\n", pMobIndex->vnum,
gamble_name( pMobIndex->gamble_fun ));
}
}
}
fprintf( fp, "S\n\n\n\n" );
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;
int iHash;
fprintf( fp, "#RESETS2\n" );
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:
bugf( "Save_resets: bad command %c.", pReset->command );
break;
case 'M':
pLastMob = get_mob_index( pReset->arg1 );
fprintf( fp, "M 0 %d %d %d %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 %d %d %d\n",
pReset->arg1, pReset->arg2,
pReset->arg3 );
break;
case 'P':
pLastObj = get_obj_index( pReset->arg1 );
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 %d\n", pReset->arg1, pReset->arg2);
if ( !pLastMob )
{
bugf("Save_resets: !NO_MOB! in [%s]", pArea->file_name );
}
break;
case 'E':
// reset_version 1 format
//fprintf( fp, "E 0 %d %d %d\n",
// pReset->arg1, pReset->arg2, pReset->arg3 );
fprintf( fp, "E 0 %d %d",pReset->arg1, pReset->arg2);
fwrite_wordflag( wear_location_types, pReset->arg3, "", fp);
if ( !pLastMob )
{
bugf( "Save_resets: !NO_MOB! in [%s]", pArea->file_name );
}
break;
case 'D':
break;
case 'R':
pRoom = get_room_index( pReset->arg1 );
fprintf( fp, "R 0 %d %d\n",
pReset->arg1,
pReset->arg2 );
break;
}
}
} /* 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, "%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 );
}
}
}
fprintf( fp, "0\n\n\n\n" );
return;
}
/**************************************************************************/
extern bool gio_abort_fwrite_wordflag_with_undefined_flags; // gio code
/**************************************************************************/
void fwrite_areaecho(area_echo_data *pAe, FILE *fp)
{
fprintf(fp, "AreaEcho %2d %2d %3d %s~\n", pAe->firsthour, pAe->lasthour,
pAe->percentage,pack_string(pAe->echotext));
}
/**************************************************************************/
void fwrite_areaecho_recursive(area_echo_data *pAe, FILE *fp)
{
if(!pAe)
{
return;
}
fwrite_areaecho_recursive(pAe->next, fp);
fwrite_areaecho(pAe, fp);
}
/*****************************************************************************
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 )
{
pArea->version = 11; // force all areas to use NAFF
// pArea->version = 6; // force all areas to save in old format
FILE *fp;
fclose( fpReserve );
char newfilename[MIL];
sprintf(newfilename, "%s%s.save", BACKUP_AREA_DIR, pArea->file_name);
logf("save_area(): saving %s...", pArea->file_name);
if ( !( fp = fopen( newfilename, "w" ) ) )
{
bugf("save_area(): fopen '%s' for write - error %d (%s)",
newfilename, errno, strerror( errno));
exit_error( 1 , "save_area", "fopen for write error");
}
if(IS_SET(pArea->olc_flags, OLCAREA_IGNORE_UNDEFINED_FLAGS)){
gio_abort_fwrite_wordflag_with_undefined_flags=false;
}else{
gio_abort_fwrite_wordflag_with_undefined_flags=true;
}
if(pArea->version>=11){
fprintf( fp, "#DAWNAREADATA\n" );
}else{
fprintf( fp, "#AREADATA\n" );
}
fprintf( fp, "Version %d\n", pArea->version);
fprintf( fp, "FromMUD %s~\n", MUD_NAME); // could aid in importing from other dawn based muds in future
if(pArea->version>=11){
fprintf( fp, "*parent_codebase %s\n", DAWN_RELEASE_VERSION);
}
fprintf( fp, "Name %s~\n", pArea->name );
if(pArea->version>10){
fprintf( fp, "ShortName %s~\n", pack_string(pArea->short_name));
}
fprintf( fp, "Builders %s~\n", fix_string(ltrim_string(rtrim_string(pArea->builders ))) );
if(!IS_NULLSTR(pArea->credits)){
fprintf( fp, "Credits %s~\n", fix_string(ltrim_string(rtrim_string(pArea->credits))) );
}
// builder restrictions - write to the file
for (int br=0;br<MAX_BUILD_RESTRICTS;br++)
{
if(!IS_NULLSTR(pArea->build_restricts[br])){
fprintf( fp, "build_restricts '%s' %s~\n",
flag_string(buildrestrict_types, br),
fix_string( pArea->build_restricts[br]) );
}
}
fprintf( fp, "VNUMs %d %d\n", pArea->min_vnum, pArea->max_vnum );
if (!IS_NULLSTR(pArea->lcomment))
{
fprintf( fp, "LComment %s\n", fix_string( pArea->lcomment) );
}
if(pArea->version<11){
char buf[MIL];
fprintf( fp, "AreaFlags %s\n", fwrite_flag(pArea->area_flags, buf) );
}else{
fwrite_wordflag( area_flags, pArea->area_flags, "AFlags ", fp );
}
if (pArea->low_level>-1)
fprintf( fp, "LRange %d %d\n", pArea->low_level, pArea->high_level );
fprintf( fp, "Security %d\n", pArea->security );
fprintf( fp, "Colour %s~\n", pArea->colour);
fprintf( fp, "colourcode %c\n", pArea->colourcode);
fprintf( fp, "MapScale %d\n", pArea->mapscale);
fprintf( fp, "MapLevel %d\n", pArea->maplevel);
fprintf( fp, "Vnum_offset %d\n", pArea->vnum_offset);
if(pArea->continent){
fprintf( fp, "Continent %s~\n", pArea->continent->name );
}
fwrite_areaecho_recursive(pArea->echoes, fp);
if(pArea->version>=11){
fprintf( fp, "*LastSaved %.24s~\n", ctime(¤t_time));
}
fprintf( fp, "End\n\n\n\n" );
save_mobiles( fp, pArea );
save_objects( fp, pArea );
if ( pArea->version<11){
save_rooms( fp, pArea );
}else{
save_rooms_NAFF( fp, pArea );
}
save_specials( fp, pArea );
save_resets( fp, pArea );
if ( pArea->version>=11){
save_shops_NAFF(fp, pArea );
save_mobprogs_NAFF( fp, pArea );
}else{
save_shops( fp, pArea );
save_mobprogs( fp, pArea );
save_gamble( fp, pArea ); // NAFF saves gambling in with mob
save_attunes( fp, pArea ); // NAFF saves attunes in with object
}
fprintf( fp, "#$\n" );
fclose( fp );
fpReserve = fopen( NULL_FILE, "r" );
// rename area/*.are to bak_area/*.are.old,
// then bak_area/*.are.save to area/*.are
{
char old_areafilename[MIL];
sprintf(old_areafilename, "%s%s.old", BACKUP_AREA_DIR, pArea->file_name);
char areafilename[MIL];
sprintf(areafilename, "%s%s", AREA_DIR, pArea->file_name);
#ifdef WIN32
unlink(old_areafilename);
#endif
if(file_exists(areafilename)){
if(rename(areafilename,old_areafilename)!=0){
bugf("Error %d occured renaming '%s' to '%s'!.. exiting to avoid area file corruption.",
errno, areafilename, old_areafilename);
exit_error( 1 , "save_area", "error renaming old filename");
}
}
if(rename(newfilename, areafilename)!=0){
bugf("Error %d occured renaming '%s' to '%s'!.. exiting to avoid area file corruption.",
errno, newfilename, areafilename);
exit_error( 1 , "save_area", "error renaming new filename");
}
}
logf("save_area(): save complete.");
if(IS_SET(pArea->olc_flags, OLCAREA_IGNORE_UNDEFINED_FLAGS)){
gio_abort_fwrite_wordflag_with_undefined_flags=true;
}
return;
}
/*****************************************************************************
Name: save_world_onefile
Purpose: Save an area, note that this format is new.
Called by: do_asave(olc_save.c).
****************************************************************************/
void save_world_onefile( void )
{
AREA_DATA *pArea;
pArea = new_area();
pArea->min_vnum = 0;
pArea->max_vnum = 32700;
SET_BIT( pArea->olc_flags, OLCAREA_ADDED );
pArea->file_name= str_dup("onefile.are");
pArea->name= str_dup("allinone");
pArea->security =9;
save_area(pArea);
return;
}
/*****************************************************************************
Name: do_asave
Purpose: Entry point for saving area data.
Called by: interpreter(interp.c)
****************************************************************************/
void do_asave( char_data *ch, char *argument )
{
char arg1[MIL];
AREA_DATA *pArea;
FILE *fp;
int value;
fp = NULL;
if (IS_NPC(ch) || ch->pcdata->security<2)
{
ch->println("You must have an olc security 2 or higher to use this command.");
return;
}
if ( !ch ) // Do an autosave
{
log_string("Doing autosave of areas.");
save_area_list();
for( pArea = area_first; pArea; pArea = pArea->next )
{
save_area( pArea );
REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
}
log_string("Autosave completed.");
return;
} // end of autosave
smash_tilde( argument );
strcpy( arg1, argument );
if ( arg1[0] == '\0' )
{
ch->println("Syntax:");
ch->println(" asave <vnum> - saves a particular area");
ch->println(" asave list - saves the area.lst file");
ch->println(" asave area - saves the area being edited");
ch->println(" asave . - saves all changed zones");
ch->println(" asave changed - saves all changed zones");
ch->println(" asave world - saves the world! (db dump)");
ch->println(" asave onefile - saves the whole world into one file! (db dump)");
return;
}
// Snarf the value (which need not be numeric).
value = atoi( arg1 );
if ( !( pArea = get_area_data( value ) ) && is_number( arg1 ) )
{
ch->println("That area does not exist.");
return;
}
// Save area of given vnum.
// ------------------------
if ( is_number( arg1 ) )
{
if ( !IS_BUILDER( ch, pArea, BUILDRESTRICT_OTHER ) )
{
ch->println("You are not a builder for this area.");
return;
}
save_area_list();
save_area( pArea );
ch->printlnf("Saved area %d (%s)", pArea->vnum, pArea->name);
return;
}
// Save the world, only authorized areas. //
// -------------------------------------- //
if ( !str_cmp( "world", arg1 ) )
{
if(!IS_ADMIN(ch)){
ch->println("Only admin can asave the world.");
return;
}
if(!HAS_SECURITY(ch,9)){
ch->println("You require security 9 to asave the world.");
return;
}
save_area_list();
for( pArea = area_first; pArea; pArea = pArea->next )
{
// Builder must be assigned this area.
if ( !IS_BUILDER( ch, pArea, BUILDRESTRICT_OTHER ) )
continue;
save_area( pArea );
REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
}
ch->println( "You saved all area files.");
/*ch->wrapln( "`RNOTE:`x It is strongly recommended that you use `=Casave .`x to save the area you are working on!"
"- asave world forces the mud to resave EVERY area and usually lags the game.\r\n");*/
return;
}
// Save the world into one file. //
// ----------------------------- //
if ( !str_cmp( "onefile", arg1 ) )
{
save_world_onefile();
ch->println("You saved the world into onefile.are.");
return;
}
/* Save changed areas, only authorized areas. */
/* ------------------------------------------ */
if ( !str_cmp( "changed", arg1 ) || !str_cmp( ".", arg1 ) )
{
char buf[MIL];
save_area_list();
ch->println("Saved zones:");
sprintf( buf, "None.\r\n" );
for( pArea = area_first; pArea; pArea = pArea->next )
{
// Builder must be assigned this area.
if ( !IS_BUILDER( ch, pArea, BUILDRESTRICT_OTHER ) )
continue;
// Save changed areas
if ( IS_SET(pArea->olc_flags, OLCAREA_CHANGED) )
{
save_area( pArea );
ch->printlnf("%24s - '%s'", pArea->name, pArea->file_name );
buf[0] = '\0';
REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
}
}
if ( !str_cmp( buf, "None.\r\n" ) ){
ch->print( buf);
}
if(!str_cmp( "changed", arg1 )){
ch->println("Note: you can use 'asave .' as shorthand for 'asave changed'");
}
return;
}
/* Save the area.lst file. */
/* ----------------------- */
if ( !str_cmp( arg1, "list" ) )
{
save_area_list();
return;
}
/* Save area being edited, if authorized. */
/* -------------------------------------- */
if ( !str_cmp( arg1, "area" ) )
{
// Is character currently editing
if ( ch->desc->editor == 0 )
{
ch->println("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, BUILDRESTRICT_OTHER ) )
{
ch->println("You are not a builder for this area.");
return;
}
save_area_list();
save_area( pArea );
REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
ch->println("Area saved.");
return;
}
/* Show correct syntax. */
/* -------------------- */
do_asave( ch, "" );
return;
}
/*****************************************************************************
Name: do_asave
Purpose: Entry point for saving area data.
Called by: interpreter(interp.c)
****************************************************************************/
// prototype
void save_clan_db( void );
void reboot_autosave( char_data *ch)
{
char buf [MSL];
AREA_DATA *pArea;
log_string("Starting reboot_autosave():");
// inform the person doing the reboot
if (ch && ch->desc && ch->desc->connected_socket){
ch->desc->write( "starting auto changed area save.\r\n",0);
}
// areas
{
bool none= true;
for( pArea = area_first; pArea; pArea = pArea->next )
{
// Save changed areas.
if ( IS_SET(pArea->olc_flags, OLCAREA_CHANGED) )
{
save_area( pArea );
sprintf( buf, "**%s -> %s", pArea->name, pArea->file_name );
log_string( buf);
if (ch && ch->desc && ch->desc->connected_socket)
{
ch->desc->write(buf,0);
ch->desc->write("\r\n",0);
}
REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
none= false;
}
}
if (none)
{
log_string("No areas needed saving.");
if (ch && ch->desc)
ch->desc->write("No areas needed saving.\r\n",0);
}
else
{
save_area_list();
}
log_string("reboot area autosave completed.");
}
// room invite lists
{
bool none= true;
for( pArea = area_first; pArea; pArea = pArea->next )
{
// Save changed room invite lists.
if ( IS_SET(pArea->olc_flags, OLCAREA_INVITELISTCHANGED) )
{
save_area_roominvitelist( pArea );
sprintf( buf, "**%s room invite list.", pArea->name);
log_string( buf);
if (ch && ch->desc && ch->desc->connected_socket)
{
ch->desc->write(buf,0);
ch->desc->write("\r\n",0);
}
REMOVE_BIT( pArea->olc_flags, OLCAREA_INVITELISTCHANGED);
none= false;
}
}
if(none)
{
if(GAMESETTING4(GAMESET4_ROOM_INVITES_DISABLED)){
log_string("No room invite lists needed saving - room invites are disabled.");
}else{
log_string("No room invite lists needed saving.");
}
if (ch && ch->desc)
ch->desc->write("No room invite lists needed saving.\r\n",0);
}
log_string("reboot area autosave completed.");
}
if (IS_SET(SKILL_TABLE_FLAGS,SEDIT_CHANGED)){
log_string("Autosaving " SKILLS_FILE);
do_write_skills(NULL,"");
REMOVE_BIT(SKILL_TABLE_FLAGS,SEDIT_CHANGED);
log_string("Skills autosave complete.");
}
if (IS_SET(CLASS_TABLE_FLAGS,CLASSEDIT_CHANGED)){
log_string("Autosaving " CLASSES_LIST);
do_write_classes(NULL,"");
REMOVE_BIT(CLASS_TABLE_FLAGS,CLASSEDIT_CHANGED);
log_string("Class table autosave complete.");
}
// Save Command Table if it was changed
if (IS_SET(COM_TABLE_FLAGS,COMEDIT_CHANGED)){
log_string("Autosaving " COMMANDS_FILE);
do_write_commandtable(NULL,"");
REMOVE_BIT(COM_TABLE_FLAGS,COMEDIT_CHANGED);
log_string("Autosave complete.");
}
// Save Deity Table if it was changed
if (IS_SET(DEITY_FLAGS,DEDIT_CHANGED)){
log_string("Autosaving " DEITY_FILE);
do_savedeities(NULL,"");
REMOVE_BIT(DEITY_FLAGS,DEDIT_CHANGED);
log_string("Autosave complete.");
}
// Save Herb Table if it was changed
if ( IS_SET( HERB_FLAGS,DEDIT_CHANGED)){ // using dedit_changed cause I'm too lazy to make an herb_changed :)
log_string("Autosaving " HERB_FILE );
do_saveherbs(NULL,"");
REMOVE_BIT( HERB_FLAGS, DEDIT_CHANGED);
log_string("Autosave complete.");
}
if (IS_SET(QUEST_TABLE_FLAGS,QEDIT_CHANGED)){
log_string("Autosaving " QUEST_FILE);
save_quest_db();
REMOVE_BIT(QUEST_TABLE_FLAGS,QEDIT_CHANGED);
log_string("Autosave complete.");
}
if (IS_SET(MIX_FLAGS,DEDIT_CHANGED)){
log_string("Autosaving " MIX_FILE);
save_mix_db();
REMOVE_BIT(MIX_FLAGS,DEDIT_CHANGED);
log_string("Autosave complete.");
}
if (IS_SET(CLAN_FLAGS,DEDIT_CHANGED)){
log_string("Autosaving " CLAN_FILE);
save_clan_db();
REMOVE_BIT(CLAN_FLAGS,DEDIT_CHANGED);
log_string("Autosave complete.");
}
if (IS_SET(SKILLGROUPEDIT_FLAGS, DEDIT_CHANGED)){
log_string("Autosaving " SKILLGROUPS_FILE);
do_write_skillgroups(NULL,"");
REMOVE_BIT(SKILLGROUPEDIT_FLAGS,DEDIT_CHANGED);
log_string("Autosave complete.");
}
if (LANGUAGE_NEEDS_SAVING){
log_string("Autosaving languages");
do_write_languages(NULL,"");
LANGUAGE_NEEDS_SAVING=false;
log_string("Autosave complete.");
}
do_hsave(NULL,"");
lockers->lockers_save_db();
}
/**************************************************************************/
void do_hsave( char_data *ch, char *argument)
{
helpfile_data *pHelpFD;
bool nonesaved= true;
// if it isn't the code doing it
if (ch){
if (!HAS_SECURITY(ch,1)){
ch->println("The hsave command is an olc command, you dont have olc permissions.");
return;
}
if (!HAS_SECURITY(ch,7)){
ch->println("security 7 required for hsave, you dont have olc permissions.");
return;
}
}
for ( pHelpFD = helpfile_first; pHelpFD; pHelpFD = pHelpFD->next )
{
if (IS_SET(pHelpFD->flags, HELPFILE_CHANGED) || !str_cmp("all", argument))
{
if (ch)
{
ch->printlnf("Saving helpfile: %s", pHelpFD->file_name);
}
nonesaved = false;
logf("Saving help: %s", pHelpFD->file_name);
//save_helpfile(pHelpFD);
save_helpfile_NAFF(pHelpFD);
REMOVE_BIT(pHelpFD->flags, HELPFILE_CHANGED);
}
}
if (ch && nonesaved)
{
ch->println("No helpfiles needed saving.");
}
if(!nonesaved){
logf("Helpfile saving completed.");
}
return;
}
/**************************************************************************/
// Name: save_helpfile
// Purpose: Save a helpfile,
// Called by: do_hsave(olc_save.c).
/**************************************************************************/
void save_helpfile( helpfile_data *pHelpfile )
{
FILE *fp;
char buf[MSL];
fclose( fpReserve );
sprintf (buf, "%s%s", HELP_DIR, pHelpfile->file_name);
if ( !( fp = fopen( buf , "w" ) ) ){
bugf("save_helpfile(): fopen '%s' for write - error %d (%s)",
buf, errno, strerror( errno));
exit_error( 1 , "save_helpfile", "fopen for write error");
}
fprintf( fp, "#HELPS\n\n" );
save_helpentries( fp, pHelpfile );
fprintf( fp, "#$\n" );
fclose( fp );
fpReserve = fopen( NULL_FILE, "r" );
return;
}
/**************************************************************************/
void save_helpentries( FILE *fp, helpfile_data *pHelpfile )
{
help_data *pHelp;
for ( pHelp = help_first; pHelp != NULL; pHelp = pHelp->next )
{
if (pHelp->helpfile==pHelpfile && !IS_SET(pHelp->flags, HELP_REMOVEHELP))
{
fprintf(fp, "-2 2~\n" );
fprintf(fp, "%d %s~\n", pHelp->level, fix_string(pHelp->keyword));
fwrite_wordflag( help_flags, pHelp->flags, " ", fp );
if ( is_space(pHelp->text[0]) )
{
fprintf(fp, ".");
}
hide_tilde (pHelp->text);
// add a little . to maintain formating in help entries if required
if (is_space(pHelp->text[0]))
{
fprintf(fp, ".");
}
fprintf(fp, "%s~\n\n\n", fix_string(pHelp->text));
show_tilde (pHelp->text);
}
}
// mark the end of the helps section
fprintf( fp, "0 $~\n");
return;
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/