/* Mod'ed to save two copies of area... one in Ack! format, and one
* in 'Standard' Envy format... -S-
*/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "merc.h"
/* Way this works:
Mud reads in area files, stores details in data lists.
Edit rooms, objects, resets.
type savearea.
Sets bool saving_area to true.
Incrementally saves an area, using data lists.
*/
#define SAVEQUEUESIZE 50
#define NOT_SAVING 0
#define START_SAVING 1
#define AM_SAVING 2
#define BUILD_OK -1
#define BUILD_CANTSAVE 1
#define BUILD_TOOMANY 2
#define BUILD_SEC_AREA 1
#define BUILD_SEC_HELP 2
#define BUILD_SEC_ROOMS 3
#define BUILD_SEC_MOBILES 4
#define BUILD_SEC_MOBPROGS 5
#define BUILD_SEC_OBJECTS 6
#define BUILD_SEC_SHOPS 7
#define BUILD_SEC_RESETS 8
#define BUILD_SEC_SPECIALS 9
#define BUILD_SEC_OBJFUNS 10 /* -S- Mod */
#define BUILD_SEC_END 11
struct save_queue_type
{
AREA_DATA * area;
CHAR_DATA * ch;
int loops;
} SaveQ[SAVEQUEUESIZE];
/* Semi-local vars. */
int saving_area=0;
/* local */
int offset;
int ToBeSaved=0;
int CurrentSaving=-1;
AREA_DATA * CurSaveArea=NULL;
CHAR_DATA * CurSaveChar=NULL;
int CurLoops=1;
int Section;
BUILD_DATA_LIST * Pointer;
RESET_DATA * ResetPointer;
FILE * SaveFile;
FILE * Envy;
int AreasModified=0;
/* Local functions */
/* void build_save(); proto in merc.h */
void build_save_area(void);
void build_save_help(void);
void build_save_mobs(void);
void build_save_mobprogs(void);
void build_save_objects(void);
void build_save_rooms(void);
void build_save_shops(void);
void build_save_resets(void);
void build_save_specs(void);
void build_save_objfuns(void);
void build_save_end(void);
char * mprog_type_to_name(int);
void vuild_save_flush(void);
/* int convert(int lev); */
/* Convert levels from ack -> envy! */
/* int convert(int lev) */
/* { */
/* return( lev - ( lev/5 ) ); */
/* } */
void do_savearea( CHAR_DATA *ch, char *argument )
{
AREA_DATA * SaveArea;
int loops;
/* char first_arg[MAX_INPUT_LENGTH]; unused? */
if (ch==NULL)
{
SaveArea=(AREA_DATA *) argument;
loops=10;
}
else
{
if (ch->in_room==NULL)
{
send_to_char("Do not know what room you are in!!, cannot save.\n",ch);
return;
}
SaveArea=(ch->in_room)->area;
if (SaveArea==NULL)
{
send_to_char("Do not know what area you are in!!, cannot save.\n",ch);
return;
}
if (*argument != '\0')
{
loops=atoi(argument);
if (loops<1)
loops=1;
}
else
loops=1;
}
if (ToBeSaved==CurrentSaving)
{
send_to_char("Too many areas in queue, please try later.\n",ch);
return;
}
SaveQ[ToBeSaved].area=SaveArea;
SaveQ[ToBeSaved].ch=ch;
SaveQ[ToBeSaved].loops=loops;
ToBeSaved=(ToBeSaved + 1) % SAVEQUEUESIZE;
if (saving_area==NOT_SAVING)
saving_area=START_SAVING;
else
send_to_char("Save is queued, please wait. \n",ch);
build_save();
return;
}
void build_save()
{
int a;
char filename[255];
char buf[MAX_STRING_LENGTH];
for (a=0;a<CurLoops && saving_area>0;a++)
{
if ( saving_area== START_SAVING)
{
CurrentSaving=(CurrentSaving+1) % SAVEQUEUESIZE;
CurSaveArea=SaveQ[CurrentSaving].area;
CurSaveChar=SaveQ[CurrentSaving].ch;
CurLoops=SaveQ[CurrentSaving].loops;
send_to_char("Starting Save.\n",CurSaveChar);
sprintf(filename,"%s.new",CurSaveArea->filename);
SaveFile=fopen(filename,"w");
if (SaveFile==NULL)
{
if (CurrentSaving==ToBeSaved)
saving_area=NOT_SAVING;
send_to_char("Can not open file for saving.\n",CurSaveChar);
return;
}
/* Open second file for saving in envy format */
sprintf( buf, "Starting to save %s", CurSaveArea->filename );
monitor_chan( buf, MONITOR_AREA_SAVING );
Section=1;
offset=CurSaveArea->offset;
saving_area=AM_SAVING;
Pointer=NULL;
ResetPointer=NULL;
}
switch (Section)
{
case BUILD_SEC_AREA: build_save_area(); break;
case BUILD_SEC_HELP: build_save_help(); break;
case BUILD_SEC_ROOMS: build_save_rooms(); break;
case BUILD_SEC_MOBILES: build_save_mobs(); break;
case BUILD_SEC_MOBPROGS: build_save_mobprogs(); break;
case BUILD_SEC_OBJECTS: build_save_objects(); break;
case BUILD_SEC_SHOPS: build_save_shops(); break;
case BUILD_SEC_RESETS: build_save_resets(); break;
case BUILD_SEC_SPECIALS: build_save_specs(); break;
case BUILD_SEC_OBJFUNS: build_save_objfuns(); break;
case BUILD_SEC_END: build_save_end(); break;
}
}
return;
}
void build_save_area()
{
fprintf(SaveFile,"#AREA\n");
fprintf(SaveFile,"%s~\n",CurSaveArea->name);
fprintf(SaveFile,"K %s~\n",CurSaveArea->keyword);
fprintf(SaveFile,"L %s~\n",CurSaveArea->level_label);
fprintf(SaveFile,"N %i\n",CurSaveArea->area_num);
fprintf(SaveFile,"I %i %i\n",CurSaveArea->min_level,CurSaveArea->max_level);
fprintf(SaveFile,"V %i %i\n",CurSaveArea->min_vnum,CurSaveArea->max_vnum);
fprintf(SaveFile,"X %i\n", CurSaveArea->offset );
fprintf(SaveFile,"F %i\n", CurSaveArea->reset_rate );
fprintf(SaveFile,"U %s~\n",CurSaveArea->reset_msg );
if (CurSaveArea->owner != NULL)
fprintf(SaveFile,"O %s~\n",CurSaveArea->owner);
if (CurSaveArea->can_read != NULL)
fprintf(SaveFile,"R %s~\n",CurSaveArea->can_read);
if (CurSaveArea->can_write != NULL)
fprintf(SaveFile,"W %s~\n",CurSaveArea->can_write);
if (IS_SET(CurSaveArea->flags,AREA_PAYAREA))
fprintf(SaveFile,"P This is a pay area.\n");
if (IS_SET(CurSaveArea->flags,AREA_TELEPORT))
fprintf(SaveFile,"T You can teleport into here\n");
if (IS_SET(CurSaveArea->flags,AREA_BUILDING))
fprintf(SaveFile,"B Currently building area.\n");
if ( IS_SET( CurSaveArea->flags, AREA_NOSHOW ) )
fprintf( SaveFile, "S Title not shown on area list.\n" );
if ( IS_SET( CurSaveArea->flags, AREA_NO_ROOM_AFF ) )
fprintf( SaveFile, "M No bad room spells allowed.\n" );
/* fprintf( Envy, "#AREA\n" ); remove save bug */
/* fprintf( Envy, "%s~\n", CurSaveArea->name ); */
Section++;
}
void build_save_help()
{
HELP_DATA *pHelp;
if (Pointer==NULL) /* Start */
{
if (CurSaveArea->first_area_help_text==NULL)
{
Section++;
return;
}
send_to_char("Saving help section.\n",CurSaveChar);
fprintf(SaveFile,"#HELPS\n");
Pointer=CurSaveArea->first_area_help_text;
}
pHelp=Pointer->data;
fprintf(SaveFile,"%i %s~\n",pHelp->level,pHelp->keyword);
if (isspace(pHelp->text[0]))
fprintf(SaveFile,".%s~\n",pHelp->text);
else
fprintf(SaveFile,"%s~\n",pHelp->text);
Pointer=Pointer->next;
if (Pointer==NULL) /* End */
{
fprintf(SaveFile,"0 $~\n");
Section++;
}
/* No saving helps for envy format */
return;
}
void build_save_mobs()
{
MOB_INDEX_DATA *pMobIndex;
MPROG_DATA* mprg;
int finish_progs;
if (Pointer==NULL) /* Start */
{
if (CurSaveArea->first_area_mobile==NULL)
{
Section++;
return;
}
send_to_char("Saving mobs.\n",CurSaveChar);
fprintf(SaveFile,"#MOBILES\n");
Pointer=CurSaveArea->first_area_mobile;
}
pMobIndex=Pointer->data;
fprintf(SaveFile,"#%i\n",pMobIndex->vnum);
fprintf(SaveFile,"%s~\n",pMobIndex->player_name);
fprintf(SaveFile,"%s~\n",pMobIndex->short_descr);
fprintf(SaveFile,"%s~\n",pMobIndex->long_descr);
fprintf(SaveFile,"%s~\n",pMobIndex->description);
fprintf(SaveFile,"%i %i %i S\n",pMobIndex->act,
pMobIndex->affected_by,pMobIndex->alignment);
fprintf(SaveFile,"%i %i\n",pMobIndex->level,pMobIndex->sex);
fprintf(SaveFile,"%i %i %i\n",pMobIndex->ac_mod, pMobIndex->hr_mod,
pMobIndex->dr_mod);
/* Save in Envy format.... */
/* fprintf(Envy,"#%i\n",((pMobIndex->vnum)+offset) ); */
/* fprintf(Envy,"%s~\n",pMobIndex->player_name); */
/* fprintf(Envy,"%s~\n",pMobIndex->short_descr); */
/* fprintf(Envy,"%s~\n",pMobIndex->long_descr); */
/* fprintf(Envy,"%s~\n",pMobIndex->description); */
/* fprintf(Envy,"%i %i %i S\n",pMobIndex->act, */
/* pMobIndex->affected_by,pMobIndex->alignment); */
/* fprintf(Envy,"%i 0 0 0d0+0 0d0+0\n0 0\n0 0 */
/* %i\n",convert(pMobIndex->level),pMobIndex->sex); */
/* Write out new details - clan, class, race and skills
* The '!' signifies new section to load_mobiles() in db.c
*/
fprintf( SaveFile, "! %i %i %i %i %i %i %i\n",
pMobIndex->class,
pMobIndex->clan,
pMobIndex->race,
pMobIndex->position,
pMobIndex->skills,
pMobIndex->cast,
pMobIndex->def );
mprg=pMobIndex->first_mprog;
finish_progs=0;
while (mprg)
{
if (mprg->filename == NULL)
{
fprintf(SaveFile,">%s ",mprog_type_to_name(mprg->type));
fprintf(SaveFile,"%s~\n",mprg->arglist);
fprintf(SaveFile,"%s~\n",mprg->comlist);
finish_progs=1;
}
mprg=mprg->next;
}
if (finish_progs)
{
fprintf(SaveFile,"|\n");
}
Pointer=Pointer->next;
if (Pointer==NULL) /* End */
{
fprintf(SaveFile,"#0\n");
Section++;
}
return;
}
void build_save_mobprogs()
{
MOB_INDEX_DATA * pMobIndex;
MOBPROG_ITEM * pItem;
if (Pointer==NULL) /* Start */
{
if (CurSaveArea->first_area_mobprog==NULL)
{
Section++;
return;
}
send_to_char("Saving mobprogs.\n",CurSaveChar);
fprintf(SaveFile,"#MOBPROGS\n");
Pointer=CurSaveArea->first_area_mobprog;
}
pItem=Pointer->data;
pMobIndex=pItem->mob;
fprintf(SaveFile,"M %i %s\n",pMobIndex->vnum,pItem->filename);
Pointer=Pointer->next;
if (Pointer==NULL) /* End */
{
fprintf(SaveFile,"S\n");
Section++;
}
return;
}
void build_save_objects()
{
OBJ_INDEX_DATA *pObject;
AFFECT_DATA * pAf;
EXTRA_DESCR_DATA *pEd;
int val0,val1,val2,val3;
if (Pointer==NULL) /* Start */
{
if (CurSaveArea->first_area_object==NULL)
{
Section++;
return;
}
send_to_char("Saving objects.\n",CurSaveChar);
fprintf(SaveFile,"#OBJECTS\n");
Pointer=CurSaveArea->first_area_object;
}
pObject=Pointer->data;
fprintf(SaveFile,"#%i\n",pObject->vnum);
fprintf(SaveFile,"%s~\n",pObject->name);
fprintf(SaveFile,"%s~\n",pObject->short_descr);
fprintf(SaveFile,"%s~\n",pObject->description);
fprintf(SaveFile,"%i %i %i %i\n",pObject->item_type,pObject->extra_flags,
pObject->wear_flags,pObject->item_apply);
/* Check for pills, potions, scrolls, staffs and wands. */
val0=pObject->value[0];
val1=pObject->value[1];
val2=pObject->value[2];
val3=pObject->value[3];
switch ( pObject->item_type )
{
case ITEM_PILL:
case ITEM_POTION:
case ITEM_SCROLL:
val1=val1<0 ? -1 : skill_table[val1].slot;
val2=val2<0 ? -1 : skill_table[val2].slot;
val3=val3<0 ? -1 : skill_table[val3].slot;
break;
case ITEM_STAFF:
case ITEM_WAND:
val3=val3<0 ? -1 : skill_table[val3].slot;
break;
}
fprintf(SaveFile,"%i %i %i %i\n",val0,val1,val2,val3);
fprintf(SaveFile,"%i\n",pObject->weight);
pAf=pObject->first_apply;
while (pAf)
{
fprintf(SaveFile,"A\n");
fprintf(SaveFile,"%i %i\n",pAf->location,pAf->modifier);
pAf=pAf->next;
}
pEd=pObject->first_exdesc;
while (pEd)
{
fprintf(SaveFile,"E\n");
fprintf(SaveFile,"%s~\n",pEd->keyword);
fprintf(SaveFile,"%s~\n",pEd->description);
pEd=pEd->next;
}
if ( ( pObject->level > 1 ) && (pObject->level < 130 ) )
{
fprintf(SaveFile, "L\n");
fprintf(SaveFile,"%d\n",pObject->level);
}
else
{
fprintf(SaveFile, "L\n");
fprintf(SaveFile,"%d\n", 1);
}
/* Now for Envy... taken from my OLC :P */
Pointer=Pointer->next;
if (Pointer==NULL) /* End */
{
fprintf(SaveFile,"#0\n");
Section++;
}
return;
}
void build_save_rooms()
{
ROOM_INDEX_DATA *pRoomIndex;
EXTRA_DESCR_DATA *pEd;
int d;
EXIT_DATA *pexit;
int locks=0;
if (Pointer==NULL) /* Start */
{
if (CurSaveArea->first_area_room==NULL)
{
Section++;
return;
}
send_to_char("Saving rooms.\n",CurSaveChar);
fprintf(SaveFile,"#ROOMS\n");
Pointer=CurSaveArea->first_area_room;
}
pRoomIndex=Pointer->data;
fprintf(SaveFile,"#%i\n",pRoomIndex->vnum);
fprintf(SaveFile,"%s~\n",pRoomIndex->name);
fprintf(SaveFile,"%s~\n",pRoomIndex->description);
fprintf(SaveFile,"%i %i\n",pRoomIndex->room_flags,pRoomIndex->sector_type);
/* Now do doors. */
for (d=0;d<6;d++)
{
if (pRoomIndex->exit[d] )
{
fprintf(SaveFile,"D%i\n",d);
pexit=pRoomIndex->exit[d];
fprintf(SaveFile,"%s~\n",pexit->description);
fprintf(SaveFile,"%s~\n",pexit->keyword);
/* Deal with locks */
/* -S- Mod: Filter out EX_LOCKED and EX_CLOSED and save exit_info */
locks=pexit->exit_info;
if ( IS_SET( locks, EX_CLOSED ) )
REMOVE_BIT( locks, EX_CLOSED );
if ( IS_SET( locks, EX_LOCKED ) )
REMOVE_BIT( locks, EX_LOCKED );
#if 0
/* BUG: before, an isdoor OR pickproof flag alone would give locks=1 */
if (pexit->exit_info & EX_ISDOOR)
locks++;
if (pexit->exit_info & EX_PICKPROOF)
locks++;
#endif
fprintf(SaveFile,"%i %i %i\n",locks,pexit->key,pexit->vnum);
}
}
/* Now do extra descripts.. */
pEd=pRoomIndex->first_exdesc;
while (pEd)
{
fprintf(SaveFile,"E\n");
fprintf(SaveFile,"%s~\n",pEd->keyword);
fprintf(SaveFile,"%s~\n",pEd->description);
pEd=pEd->next;
}
/* End of one room */
fprintf(SaveFile,"S\n");
Pointer=Pointer->next;
if (Pointer==NULL) /* End */
{
fprintf(SaveFile,"#0\n");
Section++;
}
return;
}
void build_save_shops()
{
SHOP_DATA *pShop;
int iTrade;
if (Pointer==NULL) /* Start */
{
if (CurSaveArea->first_area_shop==NULL)
{
Section++;
return;
}
send_to_char("Saving shops.\n",CurSaveChar);
fprintf(SaveFile,"#SHOPS\n");
Pointer=CurSaveArea->first_area_shop;
}
pShop=Pointer->data;
fprintf(SaveFile,"%i ",pShop->keeper);
for ( iTrade = 0; iTrade < MAX_TRADE; iTrade++ )
fprintf(SaveFile,"%i ",pShop->buy_type[iTrade]);
fprintf(SaveFile,"%i %i %i %i\n",pShop->profit_buy,pShop->profit_sell,
pShop->open_hour,pShop->close_hour);
Pointer=Pointer->next;
if (Pointer==NULL) /* End */
{
fprintf(SaveFile,"0\n");
Section++;
}
return;
}
void build_save_specs()
{
MOB_INDEX_DATA *pMob;
if (Pointer==NULL) /* Start */
{
if (CurSaveArea->first_area_specfunc==NULL)
{
Section++;
return;
}
send_to_char("Saving specials.\n",CurSaveChar);
fprintf(SaveFile,"#SPECIALS\n");
Pointer=CurSaveArea->first_area_specfunc;
}
pMob=Pointer->data;
fprintf(SaveFile,"M %i ",pMob->vnum);
fprintf(SaveFile,"%s\n",rev_spec_lookup(pMob->spec_fun));
Pointer=Pointer->next;
if (Pointer==NULL) /* End */
{
fprintf(SaveFile,"S\n");
Section++;
}
return;
}
void build_save_objfuns()
{
OBJ_INDEX_DATA *pObj;
if (Pointer==NULL) /* Start */
{
if (CurSaveArea->first_area_objfunc==NULL)
{
Section++;
return;
}
send_to_char("Saving objfuns.\n",CurSaveChar);
fprintf( SaveFile, "#OBJFUNS\n" );
Pointer=CurSaveArea->first_area_objfunc;
}
pObj=Pointer->data;
fprintf(SaveFile,"O %i ",pObj->vnum);
fprintf(SaveFile,"%s\n",rev_obj_fun_lookup(pObj->obj_fun));
Pointer=Pointer->next;
if (Pointer==NULL) /* End */
{
fprintf(SaveFile,"S\n");
Section++;
}
return;
}
void build_save_resets()
{
if (ResetPointer==NULL) /* Start */
{
if (CurSaveArea->first_reset==NULL)
{
Section++;
return;
}
send_to_char("Saving resets.\n",CurSaveChar);
fprintf(SaveFile,"#RESETS\n");
ResetPointer=CurSaveArea->first_reset;
}
fprintf(SaveFile,"%c %i %i %i ",ResetPointer->command,ResetPointer->ifflag,
ResetPointer->arg1, ResetPointer->arg2);
if (ResetPointer->command=='G' || ResetPointer->command=='R')
fprintf(SaveFile,"%s\n",ResetPointer->notes);
else
fprintf(SaveFile,"%i %s\n",ResetPointer->arg3,ResetPointer->notes);
ResetPointer=ResetPointer->next;
if (ResetPointer==NULL) /* End */
{
fprintf(SaveFile,"S\n");
Section++;
}
return;
}
void build_save_end()
{
char filename[255];
char buf[MAX_STRING_LENGTH];
sprintf( buf, "Finished saving %s", CurSaveArea->filename );
monitor_chan( buf, MONITOR_AREA_SAVING );
fprintf(SaveFile,"#$\n");
send_to_char("Finished saving.\n",CurSaveChar);
fclose(SaveFile);
/* Save backup */
sprintf(filename,"%s.old",CurSaveArea->filename);
rename(CurSaveArea->filename,filename);
/* And rename .new to area filename */
sprintf(filename,"%s.new",CurSaveArea->filename);
rename(filename,CurSaveArea->filename);
Section=0;
if (ToBeSaved==(CurrentSaving+1) % SAVEQUEUESIZE)
saving_area=NOT_SAVING;
else
saving_area=START_SAVING;
}
void build_save_flush()
{
AREA_DATA * pArea;
if (AreasModified == 0)
return;
for (pArea=first_area; pArea != NULL; pArea=pArea->next)
{
if (pArea->modified)
{
pArea->modified=0;
do_savearea(NULL,(char *) pArea);
}
}
AreasModified=0;
}
void area_modified(AREA_DATA * pArea)
{
pArea->modified=1;
AreasModified=1;
}