/**************************************************************
* Locker Code *
* *
* /|\ Life always travels forward. *
* /-|-\ Always look ahead, never back. *
* /--|--\ To do so is to loose sight of the future, *
* /---|---\ while travelling on the highways of life. *
* Code by Aidan 5/4/2006 *
* *
* This code has been written as freeware *
* and may be used without any limitations *
* of any sort whatsoever. Contact me at *
* immortal@chaos-ascending.com if you *
* need help or have questions. --Aidan *
* *
**************************************************************/
/*
* Just an addendum for use in a helpfile if you wish.
*
* The Locker system has been designed and setup to
* save items that have not been setup on a reset
* in rooms that have been flagged as a "locker" room.
* Just a side note on this. To minimize the amount of
* objects being saved over reboots in every locker room
* the max objects has been limited to 20.
*
* This can be adjusted by changing MAX_ITEM_SAVE which
* is defined below.
*
* Player corpses will be saved throughout the world,
* no matter where they are or how many items are in
* the room. This is helpful if you are in development
* and suffer a crash, etc.
* I suggest putting a call to save_lockers( ) in the
* raw_kill function located in fight.c for Merc/Rom
* derivitives.
*
* An important thing to remember. A call to save_lockers( )
* should be included in copyover, reboot, shutdown, etc, to
* insure proper saving of locker things on normal game resets.
*
* You have to call load_lockers in int boot_db located in db.c
* so that these items are re-loaded when you start the game up.
* This should optimally be done near the end when the function
* is starting to finish up the last minute boot up items and
* before copyover_recover. The reason for this is we can't sit
* and load a lot of items that don't exist yet into rooms that
* don't exist yet.
*/
#include "merc.h"
#define MAX_NEST 100
#define MAX_ITEM_SAVE 20
#define LOCKER_FILE "../area/lockers.txt"
void do_save_lockers(CHAR_DATA *ch, char *argument)
{
save_lockers();
send_to_char("Lockers have been saved.\n\r",ch);
return;
}
void save_lockers( )
{
FILE *LockerFile;
ROOM_INDEX_DATA *room;
RESET_DATA *reset;
/* Close the reserve file */
fclose(fpReserve);
/* Open the Locker File for saving */
LockerFile = fopen(LOCKER_FILE,"w");
/* Okay, lets loop through all of the rooms on the game */
for(vnum = 0; vnum < 32768; vnum++)
{
if((room = get_room_index(vnum)) != NULL)
{
OBJ_DATA *obj = NULL;
int count = 0;
for(obj = room->contents; obj; obj = obj->next_content)
{
bool hasReset = FALSE;
/* Are we being carried? Are we in a valid room? */
if(obj->carried_by)
continue;
/* Is this a Locker Room? Is it a player corpse? */
if(!IS_SET(room->room_flags, ROOM_LOCKER) && obj->item_type != ITME_CORPSE_PC)
continue;
/* Okay, so now let's see if the item is on a reset */
for(reset = room->reset_first; reset; reset = reset->next)
{
if(((reset->command == 'O'
|| reset->command == 'P')
&& reset->vnum == obj->pIndexData->vnum)
|| (reset->command == 'E'
&& reset->vnum == obj->pIndexData->vnum))
{
hasReset = TRUE;
break;
}
}
/* No saving items on reset */
if(hasReset)
continue;
/* No saving items above MAX_ITEM_SAVE */
if(++count > MAX_ITEM_SAVE && obj->item_type != ITEM_CORPSE_PC)
continue;
/* Write the obj to file */
fwrite_locker(obj,LockerFile,0);
}
}
}
/* Print the end statement */
fprintf(LockerFile,"#END\n");
/* Close the LockerFile */
fclose(LockerFile);
/* Re-Open the reserve file */
fpReserve = fopen(NULL_FILE,"r");
return;
}
/*
* fwrite_locker is used to write the locker
* data out to file. This file is called on
* boot to replace stored items.
*/
void fwrite_locker(OBJ_DATA *obj, FILE *fp, int iNest)
{
EXTRA_DESCR_DATA *ed;
AFFECT_DATA *af;
if(obj->next_content && iNet > 0)
fwrite_locker(obj->next_content,fp,iNest);
fprintf(fp,"#O\n"); // Object ID
fprintf(fp,"Vnum %d\n", obj->pIndexData->vnum); // Object Vnum
if(obj->enchanged) // Enchanted?
fprintf(fp,"Enchanged\n");
fprintf(fp,"Nest %d\n",iNest); // Nest
if(obj->name != obj->pIndexData->name) // Name
fprintf(fp,"Name %s~\n",obj->name);
if(obj->short_descr != obj->pIndexData->short_descr) // Short Desc
fprintf(fp,"ShD %s~\n",obj->short_descr);
if(obj->description != obj->pIndexData->description) // Long Desc
fprintf(fp,"Desc %s~\n",obj->description);
fprintf(fp,"Wear %lld\n",obj->wear_loc); // Wear Locations
fprintf(fp,"Lev %d\n",obj->level); // Level
if(obj->timer != 0)
fprintf(fp,"Time %d\n",obj->timer); // Timer
if(obj->in_room)
fprintf(fp,"InRm %d\n",obj->in_room->vnum); // room vnum
if(obj->value[0] != obj->pIndexData->value[0] // V Slots
|| obj->value[1] != obj->pIndexData->value[1]
|| obj->value[2] != obj->pIndexData->value[2]
|| obj->value[3] != obj->pIndexData->value[3]
|| obj->value[4] != obj->pIndexData->value[4] )
fprintf(fp,"Val %d %d %d %d %d\n",
obj->value[0],
obj->value[1],
obj->value[2],
obj->value[3],
obj->value[4]);
for(af = obj->affected; af; af = af->next) // Affects
{
if(!skill_table[af->type].name)
continue;
fprintf(fp,"AffD '%s' %d %d %d %d %d\n",
skill_table[af->type].name,
af->level,
af->duration,
af->modifier,
af->location,
af->bitvector);
}
for(ed = obj->extra_descr; ed; ed = ed->next) // Extended Descs
fprintf(fp,"ExDe %s~ %s~\n",ed->keyword, ed->description);
fprintf(fp,"End\n\n");
if(obj->contains)
fwrite_locker(obj->contains,fp,iNest+1);
return;
}
void load_lockers( )
{
FILE *LockerFile;
fclose(fpReserve);
if((LockerFile = fopen(LOCKER_FILE,"r")) == NULL)
{
log_string("No locker file found.");
fclose(LockerFile);
fpReserve = fopen(NULL_FILE,"r");
return;
}
for( ; ; )
{
char *letter;
char letter = fread_letter(LockerFile);
if(letter != '#')
{
bug("Load_Lockers: # not found.",0);
break;
}
word = fread_word(LockerFile);
if(!str_cmp(word,"O"))
fread_locker_obj(LockerFile);
else if(!str_cmp(word,"END"))
break;
else
{
bug("Load_Lockers: bad section.",0);
break;
}
}
fclose(LockerFile);
fpReserve = fopen(NULL_FILE,"r");
return;
}
void fread_locker_obj(FILE *fp);
{
OBJ_DATA *obj = NULL;
char *word = NULL;
int iNest = 0;
bool fMatch = FALSE;
bool fNest = FALSE;
bool fVnum = FALSE;
bool first = TRUE;
bool new_format = FALSE;
bool make_new = FALSE;
word = feof(fp) ? (char *)"End" : fread_word(fp);
if(!str_cmp(word,"Vnum"))
{
int vnum = fread_number(fp);
first = FALSE;
if(get_obj_index(vnum) == NULL)
bug("Fread_obj: bad vnum %d.",vnum);
else
{
obj = create_object(get_obj_index(vnum),-1);
new_format = TRUE;
}
}
if(!obj)
{
obj = new_obj( );
obj->name = str_dup("");
obj->short_descr = str_dup("");
obj->description = str_dup("");
}
fVnum = TRUE;
for( ; ; )
{
fMatch = FALSE;
if(first)
first = FALSE;
else
word = feof(fp) ? (char *)"End" : fread_word(fp);
switch(UPPER(word[0]))
{
case 'A':
if(!str_cmp(word,"AffD"))
{
AFFECT_DATA *af;
char *skill;
int sn;
af = new_affect( );
skill = fread_word(fp);
sn = skill_lookup(skill);
if(sn < 0)
bug("Fread_obj: unknown skill.",0);
else
{
paf->type = sn;
paf->level = fread_number(fp);
paf->duration = fread_number(fp);
paf->modifier = fread_number(fp);
paf->location = fread_number(fp);
paf->bitvector = fread_number(fp);
paf->next = obj->affected;
obj->affected = af;
fMatch = TRUE;
break;
}
}
break;
case 'E':
if(!str_cmp(word,"Enchanged"))
{
obj->enchanted = TRUE;
fMatch = TRUE;
break;
}
if(!str_cmp(word,"ExDe"))
{
EXTRA_DESCR_DATA *ed;
ed = new_extra_descr( );
ed->keyword = fread_string(fp);
ed->description = fread_string(fp);
ed->next = obj->extra_descr;
obj->extra_descr = ed;
fMatch = TRUE;
break;
}
if(!str_cmp(word,"End"))
{
if(!fNest || !fVnum || !obj->pIndexData)
{
bug("Fread_obj: incomplete object.",0);
free_obj(obj);
return;
}
else
{
if(!new_format)
{
obj->next = object_list;
object_list = obj;
obj->pIndexData->count++;
}
if(make_new)
{
int wear = obj->wear_loc;
extract_obj(obj);
obj = create_object(obj->pIndexData,0);
obj->wear_loc = wear;
}
if(iNest == 0 || rgObjNest[iNest] == NULL)
obj_to_room(obj,obj->in_room);
else
obj_to_obj(obj,rgObjNest[iNest-1]);
return;
}
}
break;
case 'D':
KEY("Desc", obj->description, fread_string(fp));
break;
case 'I':
KEY("InRm", obj->in_room, fread_number(fp));
break;
case 'L':
KEY("Lev", obj->level, fread_number(fp));
break;
case 'N':
KEY("Name", obj->name, fread_string(fp);
if(!str_cmp(word,"Nest"))
{
iNest = fread_number(fp);
if(iNest < 0 || iNest >= MAX_NEST)
bug("Fread_obj: bad nest %d.",iNest);
else
{
rgObjiNest[iNest] = obj;
fNest = TRUE;
}
fMatch = TRUE;
break;
}
break;
case 'S':
KEY("ShD", obj->short_descr, fread_string(fp);
break;
case 'T':
KEY("Time", obj->timer, fread_number(fp));
break;
case 'V':
if(!str_cmp(word,"Val"))
{
int i;
for(i = 0; i < 5; i++)
obj->value[i] = fread_number(fp);
fMatch = TRUE;
break;
}
break;
if(!str_cmp(word,"Vnum"))
{
int vnum = fread_number(fp);
if((obj->pIndexData = get_obj_index(vnum)) == NULL)
bug("Fread_obj: bad vnum %d.",vnum);
else
fVnum = TRUE;
fMatch = TRUE;
break;
}
break;
case 'W':
KEY("Wear", obj->wear_loc, fread_number(fp));
break;
}
if(!fMatch)
{
bug("Fread_obj: no match.",0);
fread_to_eol(fp);
}
}
return;
}