blob: 893ca515eed2587d7e7a6f3cd3eb33668dd9e3a0 [file] [log] [blame]
// losa.c -- Modul fuer Laden und Speichern der Hausdaten
//
// (c) 1995 Wargon@MorgenGrauen
// 2006 Vanion@MorgenGrauen, fuer die rebootfesten Moebel
// $Id: losa.c,v 1.1.1.1 2000/08/20 20:22:42 mud Exp $
//
#pragma strong_types,rtt_checks
#define NEED_PROTOTYPES
#include "../haus.h"
#include <container.h>
#include <thing/properties.h>
#include <room/exits.h>
#include <thing/description.h>
#undef NEED_PROTOTYPES
#include <properties.h>
#include <wizlevels.h>
#include <moving.h>
static void start_reload_furniture();
private int csaved;
// Variablen zur Verwaltung der Moebel im Raum.
mapping furniture;
mapping broken_furniture;
protected void
create()
{
Set(H_CHEST, SAVE, F_MODE);
Set(H_CHEST, 0);
Set(H_FURNITURE, SAVE, F_MODE);
Set(H_FURNITURE, 0);
// Set(H_SPECIAL, SAVE|SECURED, F_MODE);
// Set(H_SPECIAL, ([:2]), F_VALUE);
}
/* Scheint nirgendwo benutzt zu werden...
varargs int AddSpecial(int typ, string key, string extra)
{
if (!this_interactive() || !IS_ARCH(this_interactive()) ||
!(PATH+"access_rights")->access_rights(geteuid(this_interactive()),""))
return -1;
if (typ != HS_EXIT && typ != HS_ITEM)
return 0;
Set(H_SPECIAL, Query(H_SPECIAL) + ([ key : typ; extra ]));
Save();
return 1;
}
void RemoveSpecial(string key)
{
if (!this_interactive() || !IS_ARCH(this_interactive()) ||
!(PATH+"access_rights")->access_rights(geteuid(this_interactive()),""))
return;
Set(H_SPECIAL, m_delete(Query(H_SPECIAL), key));
Save();
}
*/
void
reset()
{
if (QueryOwner() &&
!sizeof(filter(all_inventory(),#'interactive)) &&
!csaved)
Save(1);
}
// crunched komprimiert das Savefile
varargs void
Save(int crunched)
{
mixed o1, o2, o3;
closure pc;
object *obs;
int i, found;
o3 = 0;
if (!(o1 = Query(P_DETAILS)))
Set(P_DETAILS, QueryProp(P_DETAILS), F_VALUE);
if (!(o2 = Query(P_READ_DETAILS)))
Set(P_READ_DETAILS, QueryProp(P_READ_DETAILS), F_VALUE);
if (csaved = crunched)
{
pc = symbol_function("PCrunch", VERWALTER);
Set(P_DETAILS, funcall(pc, Query(P_DETAILS)), F_VALUE);
Set(P_READ_DETAILS, funcall(pc, Query(P_READ_DETAILS)), F_VALUE);
o3 = Query(H_COMMANDS, F_VALUE);
Set(H_COMMANDS, funcall(pc, o3), F_VALUE);
}
// Autoload-Einrichtung identifizieren und speichern
// Code in Anlehnung an dem Autoload-Mechanismus fuer Spieler
furniture=([]);
// Alle Autoloader filtern
obs=filter_objects(all_inventory(this_object()), "QueryProp", H_FURNITURE);
found = 0;
// Ueber alle Moebel iteritieren
for( i=sizeof(obs)-1;i>=0;i--)
{
if( clonep(obs[i]))
{
if ( ++found <= MAX_FURNITURE_PER_ROOM )
furniture += ([ object_name(obs[i]):obs[i]->QueryProp(H_FURNITURE) ]);
}
}
if (found > MAX_FURNITURE_PER_ROOM)
{
tell_object(this_player(),
break_string("Du hast "+found+" Moebelstuecke im Raum stehen. "
"Gespeichert werden nur "+MAX_FURNITURE_PER_ROOM+". "
"Du solltest Dich von einigen Einrichtungsgegenstaenden "
"trennen.",78));
}
HDEBUG("Saving "+ sizeof (furniture) +" (plus "+sizeof(broken_furniture)+
" broken) objects in room "+
object_name(this_object()) + ".");
save_object( HAUSSAVEPATH+QueryOwner(1));
Set(P_DETAILS, o1, F_VALUE);
Set(P_READ_DETAILS, o2, F_VALUE);
if (o3)
Set(H_COMMANDS, o3, F_VALUE);
}
void
Load()
{
mixed prop;
int i;
restore_object( HAUSSAVEPATH+QueryOwner(1));
// Details und Kommandos werden beim Speichern de-dupliziert und in einem
// speziellen Format abgespeichert (s. PCrunch() im Hausverwalter). Sie
// muessen nach dem Laden durch die entsprechenden Add...()-Aufrufe
// wieder eingetragen werden.
prop=Query(P_DETAILS, F_VALUE);
RemoveDetail(0);
if (pointerp(prop))
{
foreach(<string*|string>* item : prop)
AddDetail(item[0], item[1]);
}
else if (mappingp(prop))
{
foreach(string key, mixed val : prop)
AddDetail(key, val);
}
else
SetProp(P_DETAILS, prop);
prop = Query(P_READ_DETAILS, F_VALUE);
RemoveReadDetail(0);
if (pointerp(prop))
{
foreach(<string*|string>* item : prop)
AddDetail(item[0], item[1]);
}
else if (mappingp(prop))
{
foreach(string key, mixed val : prop)
AddReadDetail(key, val);
}
else
SetProp(P_READ_DETAILS, prop);
prop = Query(P_EXITS, F_VALUE);
RemoveExitNoCheck(0);
if (mappingp(prop))
{
if (widthof(prop) <= 1)
{
foreach(string key, string dest : prop)
AddExitNoCheck(key, dest);
}
else
{
foreach(string key, string dest, string msg : prop)
{
if (stringp(msg))
_AddExit(key, dest, msg);
else if (stringp(dest) && strstr(dest,"#") != -1)
AddExitNoCheck(key, dest);
else
_AddExit(key, dest, 0);
}
}
}
prop=Query(H_COMMANDS, F_VALUE);
if (pointerp(prop))
{
Set(H_COMMANDS, ([]), F_VALUE);
for (i=sizeof(prop)-1; i>=0; i--)
this_object()->AddUserCmd(prop[i][0], 0, prop[i][1], prop[i][2]);
}
if (environment())
environment()->SetProp(P_NEVER_CLEAN, 1);
if (previous_object() && object_name(previous_object())==VERWALTER)
{
if (Query(H_CHEST))
this_object()->AddItem(PATH+"truhe",REFRESH_NONE,
([ "owner" : QueryOwner() ]));
/* Das scheint nirgendwo benutzt zu werden und in allen Seherhaeusern leer zu
* sein.
mapping special = Query(H_SPECIAL, F_VALUE);
if (special)
{
foreach(string key, int type, string extra : special)
{
switch(type)
{
case HS_ITEM:
AddItem(SPECIALPATH + extra, REFRESH_DESTRUCT);
break;
case HS_EXIT:
AddExitNoCheck(key, extra);
break;
}
}
}
*/
}
// Das Laden der Autoloader wird erst am Ende angestossen.
// Dann ist es nicht schlimm, wenn alle Eval Ticks verbraucht werden.
start_reload_furniture();
}
// Mehrere Save-Anforderungen zusammenfassen.
static void queued_save()
{
HDEBUG("QS");
while (remove_call_out("Save")!=-1);
call_out("Save",3);
}
static int reload_error(string file, mixed data, string message)
{
HDEBUG(message);
broken_furniture+=([file:data]);
log_file("seher/haeuser/autoloader_error",
dtime(time())+"\n"+
break_string(object_name(this_object())+" ("+QueryOwner(1)+")",78, " FILE: ",1)+
break_string(message, 78, " MSG: ",1)+
break_string(sprintf("%O", data),78, " DATA: ",1)+"\n");
return 0; // 0 fuer das filter, damit dieser Eintrag
// aus furniture geloescht wird.
}
// Laedt ein einzelnes Moebelstuecks
static int load_furniture_object( string file, mixed data )
{
object ob;
string error;
string blueprint;
closure pc;
// mixed data;
// Wenn genug Ticks frei sind, wird versucht, das Objekt zu erzeugen.
// Ansonsten ist die Gefahr zu gross, dass ein Erzeugungs-Prozess abbricht.
if (get_eval_cost() < 500000)
{
// HDEBUG("Suspending Object: "+file+". Only "+to_string(get_eval_cost())+" ticks left.");
return 1; // 1 bedeutet, dass dieser Eintrag es im Mapping bleibt.
}
// HDEBUG("Processing Object: "+file+" with Data: "+sprintf("%O",data)+".");
// Nummern der Clones sind beim Speichern noetig, um die Identitaeten
// der Objekte zu bestimmen (mehrere Objekte vom gleichen Blueprint
// speichern). Hier braucht man sie nicht mehr
blueprint = explode(file,"#")[0];
// Data aus dem Mapping holen
// data=furniture[file];
// Muss ich die Blueprint suchen?
ob = find_object(file);
// Nein.
if (!ob)
{
// Existiert die BP oder ein VC fuers File?
if (file_size(blueprint+".c")<0&&
file_size(implode(explode(blueprint,"/")[0..<2],"/")+
"/virtual_compiler.c")<0)
{
return reload_error(file, data, "Error in file: "+ file +
". File does not exist.");
}
// File gefunden. Versuch, es zu laden.
if (error = catch(call_other( blueprint,"???")))
{
return reload_error(file, data, "Error loading file: "+file+". "+error);
}
}
// Clone erzeugen
if ( error = catch(ob = clone_object(blueprint)) )
{
return reload_error(file, data, "Error cloning object: "+file+". "+error);
}
HDEBUG(sprintf("%O",furniture));
// Autoload-Daten setzen
HDEBUG(object_name(ob)+"->SetProp("+sprintf("%O", data)+")");
if (ob)
catch(ob->SetProp( H_FURNITURE, data ));
// Furniture in das Seherhaus moven
if ( error = catch(ob->move( this_object(), M_NOCHECK )) ) {
ob->remove();
if(ob) destruct(ob);
return reload_error(file, data, "Error moving object: "+file+". "+error);
}
// post_create anstossen
pc=symbol_function("post_create", ob);
if (closurep(pc))
call_out(pc, 1);
return 0; // 0 bedeutet hier, dieses Objekt nicht noch einmal anstossen.
}
static void load_furniture()
{
int i;
string rv;
string current_key;
// Abbruchbedingung ist, dass nichts mehr zu laden ist.
if (sizeof(furniture)==0) return;
// Anstoßen des naechsten Durchlaufs, falls die Ticks nicht reichen.
while (remove_call_out(#'load_furniture) != -1);
call_out(#'load_furniture, 1);
// Laden aller Moebel anstoßen
furniture=filter(furniture, #'load_furniture_object);
}
// Diese Funktion bereitet das Reloaden der Einrichtung vor
static void start_reload_furniture()
{
// Wenn es keine Moebel gibt, ist das Laden beendet.
if (!mappingp(furniture)) return;
if (broken_furniture==0) broken_furniture=([]);
// Falls ein Key von furniture 0 ist, wird dieser geloescht.
m_delete(furniture,0);
// Laden des Furniture anstossen
load_furniture();
}