blob: 0ce1de7b7ddd64dbe7bd9a3829df6cec5e5708fd [file] [log] [blame]
#pragma strong_types,save_types
#pragma no_clone,no_shadow
#include <thing/properties.h>
#define SAVEFILE "/p/daemon/save/tmp_prop_master"
#define PROPMASTER "/p/daemon/tmp_prop_master"
#define INDEX(a,b) (object_name(a)+"##"+b)
#ifdef DEBUG
# undef DEBUG
#endif
#ifdef DEBUG
# define DBG(x) if ( find_player("rikus") ) \
tell_object( find_player("rikus"), x );
#else
# define DBG(x)
#endif
mixed *reset_times;
mapping in_progress;
varargs public int remove( int silent );
public void reset();
public void print_debug_info();
static void call_next_update();
static void do_update();
public int IsTmpProp( object ob, string prop );
public void RemoveTmpProp( string prop );
varargs public void SetTmpProp( object ob, string prop, mixed newval,
int tm, int sp );
public void create()
{
seteuid(getuid(this_object()));
if ( !restore_object(SAVEFILE) ){
in_progress = ([]);
reset_times = ({});
}
call_next_update();
}
varargs public int remove( int silent )
{
save_object(SAVEFILE);
destruct(this_object());
return 1;
}
public void reset()
{
save_object(SAVEFILE);
}
public void print_debug_info()
{
printf( "in_progress: %O\nreset_times: %O\n", in_progress, reset_times );
}
static void call_next_update()
{
int dt;
while ( remove_call_out("do_update") != -1 )
;
if ( sizeof(reset_times) ){
dt = reset_times[0][0] - time();
if ( dt <= 0 )
dt = 5;
call_out( "do_update", dt );
}
}
static void do_update()
{
int i, max;
string index;
mixed *val;
DBG( "do_update() aufgerufen!\n" );
while ( remove_call_out("do_update") != -1 )
;
call_out( "do_update", 30 ); // Zur Sicherheit...
if ( !(max = sizeof(reset_times)) )
return;
for ( i = 0; i < max && reset_times[i][0] <= time(); i++ ){
index = reset_times[i][1];
if ( !pointerp(val = in_progress[index]) || !objectp(val[0]) )
{
m_delete( in_progress ,index );
continue;
}
DBG( sprintf("Entferne Eintrag %O!\n", index) );
if ( val[4] ){
if ( val[0]->Query(val[1], F_VALUE) == val[3] ){
DBG( "Alte Property per SetProp() restauriert!\n" );
val[0]->SetProp( val[1], val[2] );
}
}
else {
if ( val[0]->Query( val[1], F_QUERY_METHOD ) == val[2] ){
val[0]->Set( val[1], 0, F_QUERY_METHOD );
DBG( "F_QUERY_METHOD entfernt!\n" );
}
if ( val[0]->Query( val[1], F_SET_METHOD ) == val[3] ){
val[0]->Set( val[1], 0, F_SET_METHOD );
DBG( "F_SET_METHOD entfernt!\n" );
}
}
m_delete( in_progress ,index );
}
reset_times = reset_times[i..];
call_next_update();
}
// Zur Abfrage, ob eine temporaere Property schon gesetzt ist
public int IsTmpProp( object ob, string prop )
{
mixed oldval;
if ( !objectp(ob) || !prop )
return 0;
if ( (oldval = in_progress[INDEX(ob, prop)])
&& ob == oldval[0] && prop == oldval[1] )
return 1;
return 0;
}
// Entfernen einer temporaeren Property.
// Ist nicht zum Entfernen per Hand gedacht, sondern kann nur vom Objekt selber
// aufgerufen werden. Geschieht, wenn bei gesetzter temporaerer F_SET_METHOD
// ein fremdes SetProp() auf die Property kommt.
public void RemoveTmpProp( string prop )
{
string index;
mixed *val;
int i;
DBG( "RemoveTmpProp!\n");
if ( !previous_object() || !stringp(prop) || !sizeof(prop) )
return;
index = INDEX(previous_object(), prop);
DBG( sprintf("RemoveTmpProp(%O)!\n", index) );
if ( !(val = in_progress[index]) ){
DBG( "Kein Eintrag vorhanden!\n" );
return;
}
if ( objectp(val[0]) ){
DBG( "Restauriere alten Zustand ...\n" );
if ( val[4] ){
if ( val[0]->Query(val[1], F_VALUE) == val[3] ){
DBG( "Alte Property per SetProp() restauriert!\n" );
val[0]->SetProp( val[1], val[2] );
}
}
else {
if ( val[0]->Query( val[1], F_QUERY_METHOD ) == val[2] ){
val[0]->Set( val[1], 0, F_QUERY_METHOD );
DBG( "F_QUERY_METHOD entfernt!\n" );
}
if ( val[0]->Query( val[1], F_SET_METHOD ) == val[3] ){
val[0]->Set( val[1], 0, F_SET_METHOD );
DBG( "F_SET_METHOD entfernt!\n" );
}
}
}
for ( i = sizeof(reset_times); i--; )
if ( reset_times[i][1] == index ){
reset_times[i..i] = ({});
break;
}
DBG( "Eintrag entfernt!\n" );
m_delete( in_progress, index );
}
// Property 'prop' im Objekt 'ob' fuer 'tm' Sekunden auf Wert 'newval' setzen.
// Wenn der Schalter 'sp' gesetzt ist, wird dafuer SetProp() verwendet,
// anstatt eine F_QUERY_METHOD zu benutzen.
//
// ACHTUNG:
//
// Das Setzen von 'sp' ist hoechst fehleranfaellig und sollte nur in wenigen
// Spezialfaellen geschehen, in denen eine SET-Methode aufgerufen werden muss
// (wie bei P_LIGHT z.B.). Ansonsten bitte den Default-Aufruf ohne 'sp'
// verwenden!
//
// Es besteht sonst die Gefahr, dass die Property nicht korrekt zurueckgesetzt
// wird (wenn dieser Master oder 'ob' zerstoert wird - oder beides wie bei einem
// Crash) oder dass durch Wechselwirkungen mit anderen Query- oder Set-Methoden
// ein falscher Wert "restauriert" wird.
varargs public void SetTmpProp( object ob, string prop, mixed newval,
int tm, int sp )
{
string index;
mixed oldval, tmp;
int max, pos, l, r;
closure a, b;
if ( !objectp(ob) || !stringp(prop) || !sizeof(prop) || tm <= 0 )
return;
index = INDEX(ob, prop);
DBG( sprintf("SetTmpProp( %O, %O, %O, %O, %O )!\n", ob, prop, newval,
tm, sp) );
// wenn bereits ein temporaerer Prozess laeuft, diesen nun beenden!
if ( (oldval = in_progress[index])
&& ob == oldval[0] && prop == oldval[1] ){
DBG( "Es laeuft bereits ein Vorgang fuer diese Property!\n" );
// Wurde die alte temporaere Property per SetProp() gesetzt, muss der
// urspruengliche Wert erst restauriert werden.
if ( oldval[4] ){
if ( oldval[0]->Query(oldval[1], F_VALUE) == oldval[3] ){
DBG( "Alte Property per SetProp() restauriert!\n" );
oldval[0]->SetProp( oldval[1], oldval[2] );
}
}
// Ansonsten einfach die F_QUERY- und F_SET_METHOD loeschen.
else {
if ( oldval[0]->Query( oldval[1], F_QUERY_METHOD ) == oldval[2] ){
oldval[0]->Set( oldval[1], 0, F_QUERY_METHOD );
DBG( "F_QUERY_METHOD entfernt!\n" );
}
if ( oldval[0]->Query( oldval[1], F_SET_METHOD ) == oldval[3] ){
oldval[0]->Set( oldval[1], 0, F_SET_METHOD );
DBG( "F_SET_METHOD entfernt!\n" );
}
}
for ( l = sizeof(reset_times); l--; )
if ( reset_times[l][1] == index ){
reset_times[l..l] = ({});
DBG( "Timer-Eintrag entfernt!\n" );
break;
}
}
if ( tm < 1000000 )
tm += time();
if ( tm < time() )
return;
if ( !sp ){
// Default: F_QUERY_METHOD setzen
oldval = ob->Set( prop, newval, F_QUERY_METHOD );
// F_SET_METHOD, damit die temporaere Property keinen zwischenzeitlich
// gesetzten anderen Wert wieder "restauriert".
a=symbol_function("RemoveTmpProp",this_object());
b=symbol_function("SetProp",ob);
tmp=ob->Set(prop,lambda(({'set_value,'prop_name}),({#',,({a,'prop_name}),({#'return,({b,'prop_name,'set_value})})})),F_SET_METHOD);
}
else{
// Fuer Spezialfaelle (P_LIGHT z.B.) wird die Property direkt mit
// SetProp() gesetzt und spaeter mit dem alten Wert restauriert.
// Achtung - extrem fehleranfaellig und wirklich nur fuer Spezialfaelle!
// Alten Wert mit Query() sichern anstatt mit QueryProp(), um nicht
// irgendwelchen F_QUERY_METHODs auf den Leim zu gehen.
oldval = ob->Query( prop, F_VALUE );
// Rueckgabewert des SetProp() speichern, um spaeter erkennen zu
// koennen, ob die Property zwischenzeitlich veraendert wurde.
tmp = ob->SetProp( prop, newval );
}
in_progress[index] = ({ ob, prop, oldval, tmp, sp });
if ( !(max = sizeof(reset_times)) )
pos = 0;
else{
l = 0;
r = max - 1;
while ( l < r ){
pos = (l + r) / 2;
if ( tm < reset_times[pos][0] )
r = --pos;
else
l = ++pos;
}
while ( pos >= 0 && pos < max && tm < reset_times[pos][0] )
pos--;
}
reset_times = reset_times[0..pos] + ({ ({tm, index}) })
+ reset_times[pos+1..];
DBG( sprintf("Property an Stelle %O eingefuegt!\n", pos+1) );
call_next_update();
}