/**
* A saving room inheritable. This handles rooms which save their inventory,
* or more specifically part of their inventory.
*
* Which objects should be saved or not saved can be controlled by overriding
* test_save.
*
* Containers in this room that need to cause it to save its inventory should
* generate a save event.
*
* @see test_save
* @see event_save
*
* @author ceres
*/
#include <move_failures.h>
#include <player.h>
#define DEBUG
// This is the minimum time between saves.
#define SAVE_TIME 300
#if 0
#undef AUTO_LOAD_OB
#define AUTO_LOAD_OB "/global/auto_load_debug"
#endif
varargs void set_save_file( string file, object thing );
varargs void do_load(object thing);
mapping query_dynamic_auto_load();
void init_dynamic_arg(mapping bing);
private mapping details;
private nosave string _save_file;
private nosave int _inventory_loaded;
private nosave int _last_saved = time();
private nosave int _save_call;
private nosave int _door_opened, _door_unlocked;
/** @ignore yes */
void create() {
_save_file = "";
details = ([ ]);
} /* create() */
/**
* Set the filename that this object should use to save its inventory to.
* @param file The file.
*/
void set_save_file( string file) {
_save_file = file;
do_load();
} /* set_save_file() */
/**
* This method determines if a given object should be saved or not. When
* inheriting this room you should define your own test_save function and use
* it to decide which parts of the inventory are saved and which are not.
*
* @param ob The object to be tested.
* @return 1 for yes 0 for no.
*/
int test_save(object ob) { return 1; }
/**
* This method returns the current save file for the object.
* @return the current save file
*/
string query_save_file() {
return _save_file;
} /* query_save_file() */
/**
* Objects that need to make this room save such as containers in the room
* should generate a save event to make the room save its inventory.
* eg. event(environment(TO), "save");
*/
void event_save(object thing) {
#ifdef DEBUG
debug_printf("Save event generated by %O.", thing);
#endif
// Certain conditions must be met in order to generate a save callout.
if(!thing || !_inventory_loaded || !_save_file || _save_file == "")
return;
#ifdef DEBUG
debug_printf("call_out %d", _save_call);
#endif
// If thing is empty or this object then save. Alternatively, if
// it's something this room should save then do a save.
if(thing == TO || base_name(thing) == "/std/room/basic/door" ||
test_save(thing)) {
// Figure out when to schedule the callout for if necessary.
if(!_save_call) {
if(_last_saved > time() - SAVE_TIME)
_save_call = call_out("do_save", SAVE_TIME - (time() - _last_saved));
else
_save_call = call_out("do_save", SAVE_TIME);
#ifdef DEBUG
debug_printf("Adding call_out");
#endif
}
}
}
/** @ignore yes */
/* The following functions attempt to prevent saving when someone opens
* and then closes a door.
*/
void door_action() {
if(_door_opened || _door_unlocked)
event_save(TO);
_door_opened = 0;
_door_unlocked = 0;
}
/** @ignore yes */
void event_open(object thing) {
_door_opened++;
if(find_call_out("door_action") != -1)
remove_call_out("door_action");
call_out("door_action", 15);
}
/** @ignore yes */
void event_close(object thing) {
_door_opened--;
if(find_call_out("door_action") != -1)
remove_call_out("door_action");
call_out("door_action", 15);
}
/** @ignore yes */
void event_unlock(object thing) {
_door_unlocked++;
if(find_call_out("door_action") != -1)
remove_call_out("door_action");
call_out("door_action", 15);
}
/** @ignore yes */
void event_lock(object thing) {
_door_unlocked--;
if(find_call_out("door_action") != -1)
remove_call_out("door_action");
call_out("door_action", 15);
}
/** @ignore yes */
void do_save() {
object ob;
// No save file, no save.
if(!_save_file || _save_file == "") {
#ifdef DEBUG
log_file("ROOM_SAVE", "%s no save file for %s\n", ctime(time())[4..18],
base_name(TO));
#endif
return;
}
details = ([ ]);
details = query_dynamic_auto_load();
#ifdef DEBUG
if(unguarded((: save_object, _save_file :)))
log_file(base_name(TO) + ".log",
"%s saved.\n", ctime(time())[4..18]);
else
log_file(base_name(TO) + ".log",
"%s failed to save.\n", ctime(time())[4..18]);
foreach(ob in INV(TO)) {
if(test_save(ob))
log_file(base_name(TO) + ".log",
"%s %s contained %d items.\n", ctime(time())[4..18],
ob->query_short(), sizeof(deep_inventory(ob)));
}
#endif
_last_saved = time();
if(_save_call)
remove_call_out(_save_call);
_save_call = 0;
}
/** @ignore yes
* This causes the inventory to be loaded
*/
private void do_load( object thing ) {
if ( _save_file ) {
if ( file_size( _save_file + ".o" ) > 0 ) {
unguarded((: restore_object, _save_file :));
if ( sizeof( details ) )
init_dynamic_arg( details );
}
}
// prevent us doing a save.
_last_saved = time();
if(_save_call)
remove_call_out("do_save");
_save_call = 0;
}
/**
* @ignore yes
* Makes sure furniture is removed from the save file
* when its removed from this room.
*/
int test_remove(object thing, int flag, mixed dest) {
if(test_save(thing))
event(TO, "save", thing);
return 1;
}
/**
* @ignore yes
* Makes sure furniture is saved when its put in this room.
*/
int test_add( object ob, int flag) {
if(test_save(ob))
event(TO, "save", ob);
return 1;
}
/** @ignore yes
* This container cannot be added into other containers.
*/
int query_prevent_insert() { return 1; }
/** @ignore yes */
mapping query_dynamic_auto_load() {
mapping map;
string *obs;
map = ([ ]);
if( sizeof( TO->query_effs() ) ) {
TO->effect_freeze();
TO->effects_saving();
map["effects"] = ({ TO->query_effs(), TO->query_eeq() });
TO->effect_unfreeze();
}
obs = filter( INV(TO), "test_save");
// Try the autoload object.
catch(obs = AUTO_LOAD_OB->create_auto_load( obs, 0 ) );
map["inv"] = obs;
return map;
} /* query_dynamic_auto_load() */
/** @ignore yes */
void init_dynamic_arg( mapping bing ) {
object ob;
#ifdef DEBUG
log_file(base_name(TO) + ".log",
"%s Loading.\n", ctime(time())[4..18]);
#endif
if ( !mappingp( bing ) ) {
#ifdef DEBUG
log_file(base_name(TO) + ".log",
"%s no mapping to load.\n", ctime(time())[4..18]);
#endif
return;
}
if( bing[ "effects" ] ) {
TO->set_effs( bing[ "effects" ][ 0 ] );
TO->set_eeq( bing[ "effects" ][ 1 ] );
TO->init_after_save();
}
#ifdef DEBUG
log_file(base_name(TO) + ".log",
"%s done effects.\n", ctime(time())[4..18]);
#endif
/*
* Potential order of inventory generation problem here... Where the
* upper parts of the container don't initialise until after we
* return...
*/
if ( bing[ "inv" ] && !_inventory_loaded) {
#ifdef DEBUG
log_file(base_name(TO) + ".log",
"%s starting inventory.\n", ctime(time())[4..18]);
#endif
AUTO_LOAD_OB->load_auto_load_to_inventory( bing["inv"], TO,
TP,
(: $1->move(TO) :) );
_inventory_loaded = 1;
} else {
#ifdef DEBUG
log_file(base_name(TO) + ".log",
"%s inventory_loaded already set.\n", ctime(time())[4..18]);
#endif
}
#ifdef DEBUG
log_file(base_name(TO) + ".log",
"%s done inventory.\n", ctime(time())[4..18]);
foreach(ob in INV(TO)) {
if(test_save(ob))
log_file(base_name(TO) + ".log",
"%s %s contains %d items.\n", ctime(time())[4..18],
ob->query_short(), sizeof(deep_inventory(ob)));
}
if(!sizeof(INV(TO)))
log_file(base_name(TO) + ".log",
"%s room has no inventory.\n", ctime(time())[4..18]);
#endif
} /* init_dynamic_arg() */
/** @ignore yes */
void check_euid() {
if ( PO ) {
seteuid( geteuid( PO ) );
}
} /* check_euid() */