/*
* RAM $Id: olc_save.c 85 2009-02-08 17:09:18Z ram $
*/
/**************************************************************************
* 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 "db.h"
#include "interp.h"
#include "special.h"
#include "strings.h"
#include "act.h"
#include "olc.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] = "\0\0\0\0\0\0\0";
int i = 0;
int o = 0;
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 = NULL;
AREA_DATA *pArea = NULL;
HELP_AREA *ha = NULL;
if ( ( fp = fopen( "area.lst", "w" ) ) == NULL )
{
log_error( "Save_area_list: fopen" );
perror( "area.lst" );
}
else
{
/*
* Add any help files that need to be loaded at
* startup to this section.
*/
fprintf( fp, "social.are\n" ); /* ROM OLC */
for ( ha = had_list; ha; ha = ha->next )
if ( ha->area == NULL )
fprintf( fp, "%s\n", ha->filename );
for ( pArea = area_first; pArea; pArea = pArea->next )
{
fprintf( fp, "%s\n", pArea->file_name );
}
fprintf( fp, "$\n" );
fclose( fp );
}
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( int flags, char buf[] )
{
char offset = '\0';
char *cp = NULL;
buf[0] = '\0';
if ( flags == 0 )
{
strcpy( buf, "0" );
return buf;
}
/*
* 32 -- number of bits in an int
*/
for ( offset = 0, cp = buf; offset < 32; offset++ )
if ( flags & ( ( int ) 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 = NULL;
int i = 0;
fprintf( fp, "#MOBPROGS\n" );
for ( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
{
if ( ( pMprog = get_mprog_index( i ) ) != NULL )
{
fprintf( fp, "#%d\n", i );
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 race = pMobIndex->race;
MPROG_LIST *pMprog = NULL;
char buf[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0";
int temp = 0;
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 ", fwrite_flag( pMobIndex->affected_by, buf ) );
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 ", 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 %d\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 );
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_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 %s %d %s~\n",
mprog_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 )
{
int i = 0;
MOB_INDEX_DATA *pMob = NULL;
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 = '\0';
AFFECT_DATA *pAf = NULL;
EXTRA_DESCR_DATA *pEd = NULL;
char buf[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0";
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\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.
*/
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_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],
fwrite_flag( pObjIndex->value[1], buf ),
pObjIndex->value[2], 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_PILL:
case ITEM_POTION:
case ITEM_SCROLL:
fprintf( fp, "%d '%s' '%s' '%s' '%s'\n",
pObjIndex->value[0] > 0 ? 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, "%d %d %d '%s' %d\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->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_error( "olc_save: Invalid Affect->where" );
break;
}
fprintf( fp, "%d %d %s\n", pAf->location, pAf->modifier,
fwrite_flag( pAf->bitvector, buf ) );
}
}
for ( pEd = pObjIndex->extra_descr; pEd; pEd = pEd->next )
{
fprintf( fp, "E\n%s~\n%s~\n", pEd->keyword, fix_string( pEd->description ) );
}
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 = 0;
OBJ_INDEX_DATA *pObj = NULL;
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 = NULL;
EXTRA_DESCR_DATA *pEd = NULL;
EXIT_DATA *pExit = NULL;
int iHash = 0;
int door = 0;
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 )
{
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 %d %d\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 > 0 )
fprintf( fp, "C %s~\n", clan_table[pRoomIndex->clan].name );
if ( !IS_NULLSTR( pRoomIndex->owner ) )
fprintf( fp, "O %s~\n", pRoomIndex->owner );
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 = 0;
MOB_INDEX_DATA *pMobIndex = NULL;
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
}
}
}
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 = 0;
ROOM_INDEX_DATA *pRoomIndex = NULL;
EXIT_DATA *pExit = NULL;
int door = 0;
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 %d %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 = NULL;
MOB_INDEX_DATA *pLastMob = NULL;
OBJ_INDEX_DATA *pLastObj = NULL;
ROOM_INDEX_DATA *pRoom = NULL;
int iHash = 0;
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:
log_error( "Save_resets: bad command %c.", pReset->command );
break;
#if defined( VERBOSE )
case 'M':
pLastMob = get_mob_index( pReset->arg1 );
fprintf( fp, "M 0 %d %d %d %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 %d 0 %d %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 %d %d %d %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 %d 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 )
{
log_error( "Save_resets: !NO_MOB! in [%s]",
pArea->file_name );
}
break;
case 'E':
fprintf( fp, "E 0 %d 0 %d %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 )
{
log_error( "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 Randomize %s\n",
pReset->arg1, pReset->arg2, pRoom->name );
break;
#else
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 0 %d\n", pReset->arg1, 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 0\n", pReset->arg1 );
if ( !pLastMob )
{
log_error( "Save_resets: !NO_MOB! in [%s]",
pArea->file_name );
}
break;
case 'E':
fprintf( fp, "E 0 %d 0 %d\n", pReset->arg1, pReset->arg3 );
if ( !pLastMob )
{
log_error( "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;
#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 = NULL;
MOB_INDEX_DATA *pMobIndex = NULL;
int iTrade = 0;
int iHash = 0;
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;
}
void save_helps( FILE * fp, HELP_AREA *ha )
{
HELP_DATA *help = ha->first;
fprintf( fp, "#HELPS\n" );
for ( ; help; help = help->next_area )
{
fprintf( fp, "%d %s~\n", help->level, help->keyword );
fprintf( fp, "%s~\n\n", fix_string( help->text ) );
}
fprintf( fp, "-1 $~\n\n" );
ha->changed = false;
return;
}
void save_other_helps( CHAR_DATA *ch )
{
HELP_AREA *ha = NULL;
FILE *fp = NULL;
for ( ha = had_list; ha; ha = ha->next )
if ( ha->changed == true )
{
fp = fopen( ha->filename, "w" );
if ( !fp )
{
perror( ha->filename );
return;
}
save_helps( fp, ha );
if ( ch )
ch_printf( ch, "%s\r\n", ha->filename );
fprintf( fp, "#$\n" );
fclose( fp );
}
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 = NULL;
if ( !( fp = fopen( pArea->file_name, "w" ) ) )
{
log_error( "Open_area: fopen" );
perror( pArea->file_name );
}
fprintf( fp, "#AREADATA\n" );
fprintf( fp, "Name %s~\n", pArea->name );
fprintf( fp, "Builders %s~\n", fix_string( pArea->builders ) );
fprintf( fp, "VNUMs %d %d\n", pArea->min_vnum, pArea->max_vnum );
fprintf( fp, "Credits %s~\n", pArea->credits );
fprintf( fp, "Security %d\n", pArea->security );
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 );
if ( pArea->helps && pArea->helps->first )
save_helps( fp, pArea->helps );
fprintf( fp, "#$\n" );
fclose( fp );
return;
}
/*****************************************************************************
Name: do_asave
Purpose: Entry point for saving area data.
Called by: interpreter(interp.c)
****************************************************************************/
void do_asave( CHAR_DATA *ch, const char *argument )
{
char arg1[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char local_argument[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
AREA_DATA *pArea = NULL;
int value = 0;
int sec = 0;
if ( !ch ) /* Do an autosave */
sec = 9;
else if ( !IS_NPC( ch ) )
sec = ch->pcdata->security;
else
sec = 0;
#if 0
{
save_area_list( );
for ( pArea = area_first; pArea; pArea = pArea->next )
{
save_area( pArea );
REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
}
return;
}
#endif
strcpy( local_argument, argument );
smash_tilde( local_argument );
strcpy( arg1, local_argument );
if ( arg1[0] == '\0' )
{
if ( ch )
{
ch_printf( ch, "Syntax:\r\n" );
ch_printf( ch, " asave <vnum> - saves a particular area\r\n" );
ch_printf( ch, " asave list - saves the area.lst file\r\n" );
ch_printf( ch, " asave area - saves the area being edited\r\n" );
ch_printf( ch, " asave changed - saves all changed zones\r\n" );
ch_printf( ch, " asave world - saves the world! (db dump)\r\n" );
ch_printf( ch, "\r\n" );
}
return;
}
/*
* Snarf the value (which need not be numeric).
*/
value = atoi( arg1 );
if ( !( pArea = get_area_data( value ) ) && is_number( arg1 ) )
{
if ( ch )
ch_printf( ch, "That area does not exist.\r\n" );
return;
}
/*
* Save area of given vnum.
*/
if ( is_number( arg1 ) )
{
if ( ch && !IS_BUILDER( ch, pArea ) )
{
ch_printf( ch, "You are not a builder for this area.\r\n" );
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 )
ch_printf( ch, "You saved the world.\r\n" );
save_other_helps( NULL );
return;
}
/*
* Save changed areas, only authorized areas.
*/
if ( !str_cmp( "changed", arg1 ) )
{
char buf[MAX_INPUT_LENGTH];
save_area_list( );
if ( ch )
ch_printf( ch, "Saved zones:\r\n" );
else
log_string( "Saved zones:" );
sprintf( buf, "None.\r\n" );
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 )
{
send_to_char( buf, ch );
send_to_char( "\r\n", ch );
}
else
log_string( buf );
REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
}
}
save_other_helps( ch );
if ( !str_cmp( buf, "None.\r\n" ) )
{
if ( ch )
ch_printf( ch, "%s", buf );
else
log_string( "None." );
}
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" ) )
{
if ( !ch || !ch->desc )
return;
/*
* Is character currently editing.
*/
if ( ch->desc->editor == ED_NONE )
{
ch_printf( ch, "You are not editing an area, "
"therefore an area vnum is required.\r\n" );
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;
case ED_HELP:
ch_printf( ch, "Recording area : " );
save_other_helps( ch );
return;
default:
pArea = ch->in_room->area;
break;
}
if ( !IS_BUILDER( ch, pArea ) )
{
ch_printf( ch, "You are not a builder for this area.\r\n" );
return;
}
save_area_list( );
save_area( pArea );
REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
ch_printf( ch, "Area saved.\r\n" );
return;
}
/*
* Show correct syntax.
*/
if ( ch )
do_asave( ch, "" );
return;
}