/**
* A small handler to keep track of corpses.
* @author Pinkfish
* @started Thu Jun 13 17:22:06 PDT 2002
*/
#include <player_handler.h>
#define CORPSE_SAVE_DIR "/save/corpses/"
#define CORPSE_RAM_DIR "/save/ramdisk/corpses/"
#define CORPSE_SAVE_FILE "/save/corpses/main"
#define CORPSE_OBJECT "/obj/corpse"
private mapping _corpses;
private nosave mapping _to_save;
private nosave int _save_things_id;
private int _corpse_id;
class corpse_data {
int id;
}
void create() {
seteuid(getuid());
_corpses = ([ ]);
_corpse_id = 1;
_to_save = ([ ]);
unguarded( (: restore_object(CORPSE_SAVE_FILE, 1) :));
call_out("check_corpses", 10);
}
private void save_me() {
unguarded( (: save_object(CORPSE_SAVE_FILE, 3) :));
}
/**
* This method returns the corpse data associated with the name and
* id of the corpse
* @param name the name of the player
* @param id the corpse id
*/
private class corpse_data find_corpse_data(string name, int id) {
class corpse_data corpse;
if (!_corpses[name]) {
return 0;
}
foreach (corpse in _corpses[name]) {
if (corpse->id == id) {
return corpse;
}
}
return 0;
}
/**
* This method returns the corpse data associated with the specific
* corpse objecy.
* @param ob the corpse object to find the data for
* @return the corpse data, 0 if not found
*/
private class corpse_data find_corpse_ob_data(object ob) {
string name;
int id;
name = ob->query_ownership();
id = ob->query_corpse_id();
return find_corpse_data(name, id);
}
/**
* Finds all of the corpses for the player.
* @param player the name of the player to find the corpses of
* @return the list of player corpses
*/
object* find_player_corpses(string player) {
object* corpses;
corpses = filter( children( "/obj/corpse" ),
(: $1 && $1->query_property( "player" ) &&
$1->query_ownership() == $2 :), player );
return corpses;
}
private void really_save_corpses() {
object ob, player;
class corpse_data corpse;
string data;
string fname;
// Zip through the list to find the corpses to save.
foreach (ob, corpse in _to_save) {
if(!ob)
continue;
data = ob->query_save_data();
if (stringp(data)) {
#ifdef USE_RAMDISK
fname = CORPSE_RAM_DIR + corpse->id;
#else
fname = CORPSE_SAVE_DIR + corpse->id;
#endif
unguarded((: write_file($(fname), $(data), 1) :));
} else {
tell_creator("pinkfish", "Bad corpse save %O %O\n", ob, data);
}
// Save the player when we save the corpse.
player = find_player(ob->query_owner());
if(player)
player->save_me();
}
_to_save = ([ ]);
}
/**
* This method will save the corpse data out to a nice file.
* @param ob the object to save
*/
void save_corpse(object ob) {
class corpse_data corpse;
if (!ob->query_property("player") || !ob->query_ownership()) {
return ;
}
corpse = find_corpse_ob_data(ob);
if (!corpse) {
tell_creator("pinkfish", "Cannot find the corpse to save %O [%O].\n",
ob, ob->query_ownership());
return ;
}
_to_save[ob] = corpse;
if (_save_things_id) {
remove_call_out(_save_things_id);
}
_save_things_id = call_out((: really_save_corpses :), 2);
}
/**
* This method creates the specific corpse.
* @param name the player name to create it for
* @param id the id to create
* @return the new corpse
*/
object create_corpse(string name, int id) {
class corpse_data corpse;
string data, fname;
object ob;
corpse = find_corpse_data(name, id);
#ifdef USE_RAMDISK
if(unguarded( (: file_size(CORPSE_RAM_DIR + $(corpse->id)) :)) > 0)
fname = CORPSE_RAM_DIR + corpse->id;
#endif
if(!fname)
fname = CORPSE_SAVE_DIR + corpse->id;
data = unguarded( (: read_file($(fname)) :));
if (data) {
ob = clone_object(CORPSE_OBJECT);
ob->setup_corpse_from_save(data, name, id);
return ob;
}
return 0;
}
/**
* This goes through the current list of corpses and tries to find them,
* if not it creates them.
*/
void check_corpses() {
class corpse_data* corpses;
string name;
object* obs;
int i;
int j;
//
// We check each corpse we have in the list with the ones we can
// find and see if there are any missing ones.
//
foreach (name, corpses in _corpses) {
obs = find_player_corpses(name);
for (i = 0; i < sizeof(corpses); i++) {
for (j = 0; j < sizeof(obs); j++) {
if (obs[j]->query_corpse_id() == corpses[i]->id) {
corpses = corpses[0..i -1] + corpses[i+1..];
i--;
}
}
}
if (sizeof(corpses)) {
// We need to make some.
for (i = 0; i < sizeof(corpses); i++) {
create_corpse(name, corpses[i]->id);
}
}
}
}
/**
* This method returns the next corpse id.
* @return the next corpse id
*/
int query_next_corpse_id() {
int id;
id = _corpse_id++;
save_me();
return id;
}
/**
* This method registers the corpse with us.
* @param corpse the corpse to register
*/
void register_corpse(object ob) {
string name;
int id;
class corpse_data corpse;
tell_creator("Registering %O (%O)\n", ob, ob->query_ownership());
name = ob->query_ownership();
if(PLAYER_HANDLER->test_creator(name)) {
tell_creator("pinkfish", "Not registering creator corpse %O (%O)\n",
ob, ob->query_ownership());
return;
}
id = ob->query_corpse_id();
corpse = find_corpse_ob_data(ob);
if (corpse) {
save_corpse(ob);
return ;
}
corpse = new(class corpse_data);
corpse->id = id;
if (!_corpses[name]) {
_corpses[name] = ({ corpse });
} else {
_corpses[name] += ({ corpse });
}
save_me();
save_corpse(ob);
}
/**
* This method deregisters the corpse from us. We forget about it and
* it wombles off into the ether.
* @param corpse the corpse to deregister
*/
void deregister_corpse(object ob) {
string name;
int id;
class corpse_data corpse;
int i;
if (!ob->query_property("player")) {
return ;
}
name = ob->query_ownership();
id = ob->query_corpse_id();
for (i = 0; i < sizeof(_corpses[name]); i++) {
corpse = _corpses[name][i];
// check and see if we already have it.
if (corpse->id == id) {
_corpses[name] = _corpses[name][0..i-1] + _corpses[name][i+1..];
if (!sizeof(_corpses[name])) {
map_delete(_corpses, name);
}
save_me();
unguarded( (: rm(CORPSE_SAVE_DIR + $(id)) :));
#ifdef USE_RAMDISK
unguarded( (: rm(CORPSE_RAM_DIR + $(id)) :));
#endif
return ;
}
}
}
mixed *stats() {
return ({ ({ "corpses", keys(_corpses) }) });
}