Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/std/unit.c b/std/unit.c
new file mode 100644
index 0000000..ae715f2
--- /dev/null
+++ b/std/unit.c
@@ -0,0 +1,771 @@
+// MorgenGrauen MUDlib
+//
+// unit.c -- Basisklasse fuer Mengenobjekte
+//           (neue Version von Padreic)
+//
+// $Id: unit.c 9077 2015-01-16 23:26:00Z Zesstra $
+#pragma strong_types,save_types,rtt_checks
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+inherit "/std/thing";
+
+#define NEED_PROTOTYPES
+#include <unit.h>
+#undef NEED_PROTOTYPES
+
+#include <properties.h>
+#include <thing/properties.h>
+#include <defines.h>
+#include <language.h>
+#include <moving.h>
+#include <wizlevels.h>
+#include <debug_info.h>
+
+// zum debuggen und extra public
+public string debugmode;
+public string __set_debug(string recv) {return debugmode=recv;}
+#include <living/comm.h>
+#define ZDEBUG(x) if (stringp(debugmode) && find_player(debugmode)) \
+  find_player(debugmode)->ReceiveMsg(x,MT_DEBUG,0,object_name()+": ",ME)
+//#define ZDEBUG(x)
+
+private void _call_DoDecay(object *klone);
+
+private nosave string lastverb;
+private nosave int lastevalnumber;
+
+protected void create()
+{
+  ::create();
+  SetProp(U_IDS,({({}),({})}));
+  SetProp(P_GENDER, 1);
+  SetProp(P_AMOUNT, 1);
+  // Props sollten nicht direkt manipuliert werden, nur ueber Set-Methoden
+  Set(P_UNIT_DECAY_INTERVAL, PROTECTED, F_MODE_AS);
+  Set(P_UNIT_DECAY_QUOTA, PROTECTED, F_MODE_AS);
+} 
+
+protected void create_super() {
+  set_next_reset(-1);
+}
+
+//// Query und Set Funktionen fuer die Propertys
+
+static void check_leave()
+{  if (Query(P_AMOUNT,F_VALUE)<1) remove(1);  }
+
+static int _query_invis()
+{
+  if (QueryProp(P_AMOUNT) < 1)
+    return 1;
+  return Query(P_INVIS, F_VALUE);
+}
+
+static int _set_amount(int am)
+{
+  if (am<1)
+    call_out("check_leave",1);
+  SetProp(U_REQ, am);
+  return Set(P_AMOUNT,am, F_VALUE);
+}
+
+static int _set_u_req(int ureq)
+{
+  lastverb = query_verb();
+  lastevalnumber = debug_info(DINFO_EVAL_NUMBER);
+  return Set(U_REQ, ureq, F_VALUE);
+}
+
+static int _query_u_req()
+{
+  // Zwei Dinge benutzten, um zu entscheiden, ob U_REQ noch gueltig ist oder
+  // besser auf P_AMOUNT zurueckgesetzt werden sollte: die DINFO_EVAL_NUMBER
+  // und das Kommandoverb. Wenn eines von beiden sich geaendert hat, wird
+  // U_REQ als ungueltig betrachtet. (Und dies bleibt ein uebler Hack.)
+  if (lastevalnumber != debug_info(DINFO_EVAL_NUMBER)
+      || lastverb != query_verb())
+  {
+    return SetProp(U_REQ, Query(P_AMOUNT, F_VALUE));
+  }
+  return Query(U_REQ, F_VALUE);
+}
+
+// Gesamtwert der gerade mit U_REQ ausgewaehlten unitobjekte
+static int _query_value()
+{
+  mixed cpu;
+  cpu=Query(U_CPU);
+  if (intp(cpu)) return QueryProp(U_REQ) * cpu;
+  if (!pointerp(cpu)) return 0;
+  return (QueryProp(U_REQ) * cpu[0])/cpu[1];
+}
+
+static int _set_value(int num) {
+// Setzt den Wert fuer die derzeitige Anzahl
+  SetCoinsPerUnits(num, QueryProp(U_REQ));
+  return QueryProp(P_VALUE);
+}
+
+static int _query_weight()
+{
+  mixed gpu, req;
+  if ((req=QueryProp(U_REQ))<1) return 0;
+  gpu=Query(U_GPU);
+  if (intp(gpu)) return req * gpu;
+  if (!pointerp(gpu)) return 0;
+  return MAX(1,(req*gpu[0])/gpu[1]);
+}
+
+static int _set_weight(int num) {
+// Setzt das Gewicht fuer die derzeitige Anzahl
+    SetGramsPerUnits(num, QueryProp(U_REQ));
+    return QueryProp(P_WEIGHT);
+}
+
+static int _query_total_weight()
+{
+  mixed gpu, amount;
+  if ((amount=Query(P_AMOUNT))<1) return 0;
+  gpu=Query(U_GPU);
+  if (intp(gpu))
+    return amount*(int)gpu;
+  if (!pointerp(gpu)) return 0;
+  return MAX(1,(amount*gpu[0])/gpu[1]);
+}
+
+static int _query_plural()
+{
+  int i;
+  i=QueryProp(U_REQ); // wichtig _nicht_ QueryProp
+  return (i<=1 ? 0 : i);
+}
+
+// gibt string | string* zurueck.
+static string|string* _query_name()
+{
+  if (QueryProp(U_REQ)==1)
+    return "%s%s"+((string *)Query(P_NAME))[0];
+  return "%d %s"+((string *)Query(P_NAME))[1];
+}
+
+// gibt string | string* zurueck.
+static string|string*  _set_name(mixed names)
+{
+  if(!names)
+    return Set(P_NAME,({"",""}));
+  if(stringp(names))
+    return Set(P_NAME,({names,names}));
+  if(pointerp(names))
+    switch(sizeof(names)) {
+      case 0:  return Set(P_NAME,({"",""}));
+      case 1:  if(!stringp(names[0]))
+                 names[0]="";
+               return Set(P_NAME,({names[0],names[0]}));
+      default: if(!stringp(names[0]))
+                 names[0]="";
+               if(!stringp(names[1]))
+                 names[1]="";
+               return Set(P_NAME,names[0..1]);
+    }
+  return QueryProp(P_NAME);
+}
+
+// die Funktionen
+
+void AddSingularId(mixed str)
+{
+  string *ids;
+  if (!pointerp(str))
+    str=({str});
+  ids=Query(U_IDS);
+  Set(U_IDS,({ids[0]+str,ids[1]}));
+}
+
+void RemoveSingularId(mixed str)
+{ 
+  if(stringp(str))
+    str=({str});
+  if(pointerp(str))
+    Set(U_IDS,({Query(U_IDS)[0]-str,Query(U_IDS)[1]}));
+}
+ 
+void AddPluralId(mixed str)
+{
+  string *ids;
+  
+  if (!pointerp(str))
+    str=({str});
+  ids=Query(U_IDS);
+  Set(U_IDS,({ids[0],ids[1]+str}));
+}
+
+void RemovePluralId(mixed str)
+{ 
+  if(stringp(str))
+    str=({str});
+  if(pointerp(str))
+    Set(U_IDS,({Query(U_IDS)[0],Query(U_IDS)[1]-str}));
+}
+
+void SetCoinsPerUnits(int coins,int units)
+{
+  if (coins<0||units<=0) return;
+  if (units==1)
+    Set(U_CPU, coins);
+  else Set(U_CPU,({coins,units}));
+}
+
+void SetGramsPerUnits(int grams, int units)
+{
+  if (grams<0||units<=0) return;
+  if (units==1)
+    Set(U_GPU, grams);
+  else Set(U_GPU,({grams,units}));
+}
+
+int *QueryCoinsPerUnits()
+{
+  mixed cpu;
+  cpu=Query(U_CPU);
+  if (intp(cpu)) return ({ cpu, 1 });
+  return cpu;
+}
+
+int *QueryGramsPerUnits()
+{
+  mixed gpu;
+  gpu=Query(U_GPU);
+  if (intp(gpu)) return ({ gpu, 1 });
+  return gpu;
+}
+
+void AddAmount(int am) {
+  SetProp(P_AMOUNT, am+Query(P_AMOUNT));
+}
+
+int IsUnit() {
+  return 1;
+}
+
+int IsEqual(object ob)
+// haben ob und dieses Objekte die gleiche Blueprint?
+{
+  if (ob==this_object()) return 0; // das ist ZU gleich :)
+  return (BLUE_NAME(ME)==BLUE_NAME(ob));
+}
+
+// ueberschreiben von Standardmethoden
+
+varargs string name(int fall, int demo)
+{
+  int req;
+  mixed n_adj;
+  string adj;
+
+  if ((req=QueryProp(U_REQ))<1) return 0;
+  if (fall!=RAW && 
+      pointerp(n_adj=QueryProp(P_NAME_ADJ)) && sizeof(n_adj) )
+    adj = implode(map(n_adj, #'DeclAdj, fall, demo && req==1), "");
+  else
+    adj = "";
+
+  if (req==1)
+    return sprintf(QueryProp(P_NAME),
+                   (fall==RAW || !QueryProp(P_ARTICLE) 
+                    ? "" : QueryArticle(fall,demo,1)), adj) /* +korrektur */;
+
+  if (fall!=WEM)
+    return sprintf(QueryProp(P_NAME), req, adj);
+  else {
+     int last;
+     last=Query(P_NAME)[1][<1];
+     return sprintf(QueryProp(P_NAME), req, adj)
+                  +(last!='s' && last!='n' ? "n" : "");
+  }
+}
+
+varargs string QueryPronoun(int casus)
+{
+  if (QueryProp(U_REQ)==1)
+    return ::QueryPronoun(casus);
+  switch(casus) {
+    case WESSEN: return "ihrer";
+    case WEM:    return "ihnen";
+    //default:     return "sie";
+  }
+  return("sie"); //fall-through
+}
+
+string short()
+{
+  if (QueryProp(U_REQ)<1 || QueryProp(P_INVIS)) return 0;
+  return capitalize(name(WER,0))+".\n";
+  /*
+  if (req>1) return sprintf(QueryProp(P_NAME), req)+".\n";
+  return capitalize(sprintf(QueryProp(P_NAME), QueryArticle(WER,0,1)))+".\n";
+  */
+}
+
+varargs string long()
+{
+  return (QueryProp(P_LONG) ? process_string(QueryProp(P_LONG)) : "")+
+    sprintf("Du siehst %s.\n",name(WEN));
+}
+
+varargs int id(string str,int lvl)
+{
+
+  string s1,s2,*ids;
+  int i;
+
+  if (!str) return 0;
+  
+  // Wenn kein pos. Amount, hat dieses Objekt keine IDs mehr, damit es nicht
+  // mehr ansprechbar ist.
+  int amount=QueryProp(P_AMOUNT);
+  if (amount < 1)
+    return 0;
+
+  if (::id(str)) {
+    SetProp(U_REQ, Query(P_AMOUNT,F_VALUE));
+    return 1;
+  }
+
+ ids=Query(U_IDS);
+  if (!ids)
+    return 0;
+ 
+  //die casts auf 'mixed' sind absicht. Sonst geht der Driver offenbar davon
+  //aus, dass ids[1] ein String ist. Es ist aber aber ein Array von Strings
+  //und genau das will auch match_item() haben. ;-) Zesstra
+  if (match_item(str,(mixed)ids[1] )) {
+    SetProp(U_REQ, amount);
+    return 1;
+  }
+  if (match_item(str,(mixed)ids[0] )) {
+    SetProp(U_REQ,1);
+    return 1;
+  }
+  if (sscanf(str,"%s %s",s1,s2) && s1[0..3]=="alle" && 
+    match_item(s2,(mixed)ids[1] )) {
+    SetProp(U_REQ, amount);
+    return 1;
+  }
+  if (sscanf(str,"%d %s",i,s1)==2 && i==1 && match_item(s1,(mixed)ids[0] )) {
+    SetProp(U_REQ,1);
+    return 1;
+  }
+  if (sscanf(str,"%d %s",i,s1)==2 && match_item(s1,(mixed)ids[1] ) && 
+      i<=amount && i>0) {
+    SetProp(U_REQ,i);
+    return 1;
+  }
+  return 0;
+}
+
+// Status fuer move... *seufz*
+int _orig_amount, _move_requested;
+
+varargs int move(object|string dest,int method)
+{
+  _orig_amount = QueryProp(P_AMOUNT);
+  // Wenn M_MOVE_ALL gesetzt ist, wird IMMER ALLES bewegt.
+  if (method & M_MOVE_ALL)
+    _move_requested = _orig_amount;
+  else
+    _move_requested = QueryProp(U_REQ);
+
+  ZDEBUG(sprintf("move from %O to %O: amount %d, req %d\n",environment(),dest,_orig_amount,_move_requested));
+  // Wenn nicht alles bewegt werden soll, wird die Menge dieses Objektes
+  // erstmal reduziert und bewegt. Erst nach der Bewegung wird der Rest dann
+  // im alten Environment neu erzeugt.
+  if ( _orig_amount > _move_requested )
+  {
+     // wenn in einem alten Paket das Gewicht noch nicht neu berechnet
+     // wurde muss dies geschehn solange die Muenzen im Paket noch das
+     // volle Gewicht haben...
+     if ( environment() )
+         environment()->query_weight_contents();
+     // ab jetzt nur auf <_move_requested> Einheiten arbeiten
+     Set( P_AMOUNT, _move_requested, F_VALUE);
+     ZDEBUG(sprintf("move: amount set to %d\n",_move_requested));
+  }
+
+  int res = ::move( dest, method );
+
+  if ( res != MOVE_OK )
+  {
+      // Fehlgeschlagene Bewegung ist doof.
+      // ggf. verfruehte Aenderung (P_AMOUNT oben auf <U_REQ> Einheiten
+      // reduziert) rueckgaengig machen
+      Set( P_AMOUNT, _orig_amount, F_VALUE );
+      ZDEBUG(sprintf("move: not OK, amount restored to %d\n",_orig_amount));
+      return res;
+  }
+
+  // TODO: eigentlich sollte es nicht passieren, dass die Menge jetzt negagtiv
+  // ist. Aber bei Geld kann es durch vereinigen mit Geldboerse/Geldkarten
+  // passieren und das ist kein Fehler. Koennte man evtl. mal differenziert
+  // pruefen.
+  int finalamount= QueryProp(P_AMOUNT);
+  /*if ( finalamount < 1 )
+  {
+    ZDEBUG(sprintf("move: zerstoerung, amount %d\n",finalamount));
+    remove(1);
+    return ME_WAS_DESTRUCTED;
+  }
+  */
+  ZDEBUG(sprintf("move: OK, amount %d\n",finalamount));
+  return res;
+}
+
+
+protected void NotifyMove(object dest, object oldenv, int method)
+{
+  // Erst einen evtl. nicht zu bewegenden Rest im alten Environment wieder erzeugen.
+  if (oldenv && _orig_amount > _move_requested)
+  {
+      if ( oldenv == dest )
+      {
+          // Objekt wurde nur an den Anfang des inventory bewegt, sonst nichts.
+          // ggf. verfruehte Aenderung (oben auf <req> Einheiten reduziert)
+          // rueckgaengig machen
+          ZDEBUG(sprintf("move: same env, amount restored to %d\n",_orig_amount));
+          Set( P_AMOUNT, _orig_amount, F_VALUE );
+      }
+      else
+      {
+        // verbleibende Einheiten in einem neuen Objekte wieder zurueck ins
+        // alte Environment zurueck bewgen
+          object temp;
+          temp = clone_object(BLUE_NAME(ME));
+          temp->SetProp( P_AMOUNT, _orig_amount-_move_requested );
+          temp->move( oldenv, M_NOCHECK );
+          ZDEBUG(sprintf("move: Restmenge im alten Env erzeugt, amount %d\n",_orig_amount-_move_requested));
+      }
+  }
+
+  // Und jetzt ggf. mit den anderen Units gleichen Typs im neuen Environment
+  // vereinigen.
+  foreach(object item: all_inventory(environment()))
+  {
+      if ( IS_EQUAL(item) )
+      {
+        // Es ist ein Feature, dass auch mit Objekten mit negativen Amount
+        // vereinigt wird.
+        ZDEBUG(sprintf("move: vereinige mit %O (%d)\n",
+               item,item->QueryProp(P_AMOUNT)));
+        int mergedamount = QueryProp(P_AMOUNT) + item->QueryProp(P_AMOUNT);
+        item->Set( P_AMOUNT, 0, F_VALUE);
+        item->remove(1);
+
+        SetProp( P_AMOUNT, mergedamount);
+        // U_REQ ist jetzt auch zurueckgesetzt.
+
+        ZDEBUG(sprintf("move: nach vereinigung, amount %d\n",mergedamount));
+      }
+  }
+
+  // wenn man in frisch geclonten Units die noch kein environment haben
+  // per Hand U_REQ auf einen Wert != P_AMOUNT setzt, so gehen die
+  // restlichen Einheiten  verloren (es gibt kein Environment, in das man die
+  // Resteinheiten zurueck bewegen koennte).
+
+  // Und jetzt mal Decaykrams machen...
+
+  // wenn NO_DECAY_UNTIL_MOVE an ist und dieses ein Move ist, was von einem
+  // Env in ein anderes Env geht, loeschen. Nicht geloescht wird
+  // hingegen, wenn das move() in das allererste Env erfolgt (nach dem Clonen)
+  if ( (QueryProp(P_UNIT_DECAY_FLAGS) & NO_DECAY_UNTIL_MOVE)
+      && objectp(dest) && objectp(oldenv) && dest != oldenv)
+    SetProp(P_UNIT_DECAY_FLAGS, 
+        QueryProp(P_UNIT_DECAY_FLAGS) & ~NO_DECAY_UNTIL_MOVE );
+  ::NotifyMove(dest, oldenv, method);
+}
+
+
+void reset() {
+  if (!clonep(ME)) {
+    // Blueprint ist Master fuer zerfallende Unitobjekte
+    // das Decay sollte besser nicht durch manuellen Aufruf in der BP
+    // ausgeloest werden, daher Pruefung hier (PO == ME, falls der Reset vom
+    // Driver kommt).
+    if (previous_object() && previous_object() != ME)
+      return; 
+    int zeit = QueryProp(P_UNIT_DECAY_INTERVAL);
+    if (zeit > 0)
+    {
+      set_next_reset(zeit);
+      // Das Callout muss auf jeden Fall gemacht werden, wenn ein Decay
+      // Intervall gesetzt ist, damit die Blueprint auch den naechsten Reset
+      // kriegt, auch wenn es jetzt keine Clone gibt. Wenn es kein Quota gibt,
+      // kann der Callout wegfallen, beim Setzen eines Quota wird ja eine
+      // Funktion an diesem Objekt gerufen.
+      if (QueryProp(P_UNIT_DECAY_QUOTA) > 0)
+        call_out(#'_call_DoDecay, 1, 0);
+    }
+  }
+  else {
+    // Clones
+    if (Query(P_AMOUNT,F_VALUE)<1) remove(1);
+    else ::reset();
+  }
+}
+
+varargs int remove(int silent)
+{
+  int amount = QueryProp(P_AMOUNT);
+  int req = QueryProp(U_REQ);
+  if (amount > req)
+  {
+    ZDEBUG(sprintf("remove: reduziere amount %d um %d -> %d\n",
+           amount, req, amount-req ));
+    SetProp(P_AMOUNT, amount - req);
+    return 1;
+  }
+  ZDEBUG(sprintf("remove: restlos weg.\n"));
+  return ::remove(silent);
+}
+
+// sollte nicht von aussen gerufen werden.
+private void _call_DoDecay(object *klone) {
+  ZDEBUG(sprintf("call_DoDecay() in %O\n",ME));
+  // Clone oder kein Decay konfiguriert?
+  if (clonep()
+      || QueryProp(P_UNIT_DECAY_FLAGS) & NO_DECAY)
+    return;
+
+  if (!pointerp(klone))
+    klone = clones(2);
+  // Klone da?
+  int i=sizeof(klone);
+  if (!i)
+    return;
+
+  // in allen Klonen DoDecay rufen
+  while(get_eval_cost() > __MAX_EVAL_COST__/2 && i--) {
+    if (objectp(klone[i]))
+      catch(call_other(klone[i],"DoDecay", 0);publish);
+  }
+  // das i ist schon abgearbeitet.
+  i--;
+  // noch was uebrig?
+  if (i >= 0)
+    call_out(#'_call_DoDecay, 4, klone[0..i]);
+}
+
+// zerstoert quota Prozent der vorhandenen Units, liefert die Restmenge
+// zurueck. Ruft ggf. DoDecayMessage()
+public int DoDecay(int silent) {
+  // nur fuer Clones
+  if (!clonep())
+    return 0;
+  ZDEBUG(sprintf("DoDecay() in %O\n",ME));
+
+  // wenn das Objekt NO_DECAY oder NO_DECAY_UNTIL_MOVE in den Flags
+  // zerfaellt nix.
+  int flags = QueryProp(P_UNIT_DECAY_FLAGS);
+  if ((flags & NO_DECAY) || (flags & NO_DECAY_UNTIL_MOVE) )
+    return QueryProp(P_AMOUNT);
+
+  int quota = QueryProp(P_UNIT_DECAY_QUOTA);
+
+  // Zugewinn ist nicht. Ausserdem kann nicht mehr zerfallen, als da ist...
+  // Also ohne gueltiges Quota raus. Nur bei abs. Zerfall sind Zahlen > 10000
+  // erlaubt, bei relativen Zerfall waere das sinnlos.
+  if (quota <= 0 || 
+      (quota > 10000 && !(flags & ABSOLUTE_DECAY) ) ) 
+    return QueryProp(P_AMOUNT);
+  
+  int amount = QueryProp(P_AMOUNT);
+  int minimum = QueryProp(P_UNIT_DECAY_MIN);
+  // Zerfall nur, wenn man mehr als das Minimum hat.
+  if (amount > minimum) {
+    int zerfall;
+    if (flags & ABSOLUTE_DECAY) {
+      // Decay Quota soll einfach als abs. Zahl aufgefasst werden:
+      zerfall = quota;
+    }
+    else if (flags & INACCURATE_DECAY) {
+      // Rundungsfehler ignorieren und dafuer immer min. eine Einheit
+      // zerfallen lassein
+      zerfall = (amount * quota) / 10000;
+      if (zerfall <= 0) zerfall = 1;
+    }
+    else {
+      // Standardfall:
+      // nicht-ganzzahligen Rest als Wahrscheinlichkeit fuer den Zerfall einer
+      // Einheit auffassen
+      float tmp = amount * quota / 10000.0;
+      zerfall = to_int(tmp);
+      tmp -= zerfall; // Rest in tmp
+      // tmp*n ist eine Zahl zwischen 0 und n, wenn tmp*n > random(n)+1,
+      // dann zerfaellt eine Einheit extra. Da das Random fuer grosse Zahlen
+      // besser verteilt ist, nehm ich n = __INT_MAX__
+      if (ceil(tmp * __INT_MAX__) > random(__INT_MAX__) + 1)
+        zerfall++;
+    }
+
+    // nicht unter Minimum zerfallen
+    if (amount - zerfall < minimum)
+      zerfall = amount - minimum;
+
+    // erst ggf. Meldung ausgeben.
+    if (!silent && zerfall > 0)
+      DoDecayMessage(amount, zerfall);
+    // dann runtersetzen.
+    SetProp(P_AMOUNT, amount - zerfall);
+    ZDEBUG(sprintf("%O decayed by %d\n",ME, zerfall));
+    return amount-zerfall;
+  }
+  else if (amount < 0)
+    return 0; // neg. Anzahl gilt als "0 uebrig".
+  
+  // sonst ists wohl zwischen 0 und minimum, nix aendert sich.
+  return amount;
+}
+
+// gibt die Zerfallsmeldung aus. Wenn man mit der Standardmeldung nicht zufrieden
+// ist (duerfte der Normalfall sein), sollte man diese Funktion
+// ueberschreiben. Bekommt bisherige und jetzt gerade zerfallene Menge
+// uebergeben. Wichtig: zu diesem Zeitpunkt hat sich an der Unit noch nix (!)
+// geaendert!
+protected void DoDecayMessage(int oldamount, int zerfall) {
+  string msg;
+  if (oldamount == zerfall) {
+    if (living(environment())) {
+      tell_object(environment(), break_string(sprintf(
+          "Auf einmal %s%s zu Staub!",
+          (oldamount>1?"zerfallen Deine ":"zerfaellt D"), name(WER)),78));
+    }
+    // das tell_room() muss auf jeden fall sein, weil es "lebende" Raeume
+    // gibt. Liegt der KRam in einem solchen wuerden die Livings in diesem Raum
+    // sonst keine meldung kriegen.
+    tell_room(environment(), break_string(sprintf(
+          "Auf einmal %s %s zu Staub!",
+          (oldamount>1?"zerfallen":"zerfaellt"), name(WER)),78),
+        ({environment()}));
+  }
+  else {
+     if (living(environment())) {
+      tell_object(environment(), break_string(sprintf(
+          "Auf einmal %s %d Deiner %s zu Staub!",
+          (zerfall>1?"zerfallen":"zerfaellt"),
+          zerfall, Query(P_NAME)[1]),78));
+    }
+    // das tell_room() muss auf jeden fall sein, weil es "lebende" Raeume
+    // gibt. Liegt der KRam in einem solchen wuerden die Livings in diesem Raum
+    // sonst keine meldung kriegen.
+    tell_room(environment(), break_string(sprintf(
+          "Auf einmal %s %d %s zu Staub!",
+          (zerfall>1?"zerfallen":"zerfaellt"),
+          zerfall, Query(P_NAME)[1]),78), ({environment()}) ); 
+  }
+}
+
+static int _query_unit_decay_interval() {
+  if (clonep()) {
+    // fuer clones den Wert aus der BP liefern, der Wert in Clones ist eh
+    // uninteressant.
+    if (objectp(blueprint()))
+      return blueprint()->QueryProp(P_UNIT_DECAY_INTERVAL);
+    else
+      return load_object(load_name())->QueryProp(P_UNIT_DECAY_INTERVAL);
+  }
+  return Query(P_UNIT_DECAY_INTERVAL);
+}
+
+static int _set_unit_decay_interval(int zeit) {
+  // fuer Clones ist die Prop sinnlos und kann nicht gesetzt werden.
+  if (clonep()) {
+    if (objectp(blueprint()))
+      return blueprint()->QueryProp(P_UNIT_DECAY_INTERVAL);
+    else
+      return load_object(load_name())->QueryProp(P_UNIT_DECAY_INTERVAL);
+  }
+  // ueber diese Prop liesse sich der Reset relativ beliebig veraendern,
+  // verhindern, etc. Daher darf sie nur von diesem Objekt gesetzt werden, von
+  // Weisen+ oder eines Objektes, das die gleiche UID hat wie dieses hier oder
+  // des Programmieres dieses Objekts oder eines Magiers, der berechtigt fuer
+  // die jeweilige UID ist. Letztere beiden werden ueber den Ruf von
+  // QueryUIDsForWizard() ermittelt.
+  // erstes fremdes Objekt finden und pruefen.
+  foreach(object po: caller_stack(1)) {
+    if (po != ME) {
+      // fremden Aufrufer gefunden
+      if (getuid(po) != getuid(ME) 
+          && member(master()->QueryUIDsForWizard(getuid(po)),getuid(ME)) == -1
+          && (!this_interactive() || !IS_ELDER(this_interactive()) ) )
+        // unberechtigt, Abbruch
+        return QueryProp(P_UNIT_DECAY_INTERVAL);
+      else
+        // nur das erste ext. Objekt in der Callkette wird geprueft, raus.
+        break;
+    }
+  }
+  set_next_reset(zeit);
+  // falls dies aus dem create() gesetzt wird, muss zeitverzoegert eine
+  // Funktion von aussen am Objekt gerufen werden, da nach einem create() das
+  // Objekt als resettet gilt und sonst keinen Reset kriegt.
+  call_out("_query_unit_decay_interval",1);
+  return Set(P_UNIT_DECAY_INTERVAL, zeit, F_VALUE);
+}
+
+static int _query_unit_decay_quota() {
+  if (clonep()) {
+    // hat dieses Objekt einen eigenen wert gespeichert?
+    int quota=Query(P_UNIT_DECAY_QUOTA, F_VALUE);
+    if (quota)
+      return quota;
+    // sonst den Wert aus der Blueprint
+    if (objectp(blueprint()))
+      return blueprint()->QueryProp(P_UNIT_DECAY_QUOTA);
+    else
+      return load_object(load_name())->QueryProp(P_UNIT_DECAY_QUOTA);
+  }
+  return Query(P_UNIT_DECAY_QUOTA, F_VALUE);
+}
+
+static int _set_unit_decay_quota(int quota) { 
+  // momentan nur quota zwischen 0 und 10000
+  if (quota >= 0 && quota <=10000)
+    return Set(P_UNIT_DECAY_QUOTA, quota, F_VALUE);
+  else
+    return Query(P_UNIT_DECAY_QUOTA, F_VALUE);
+}
+
+static int _query_unit_decay_min() {
+  if (clonep()) {
+    // hat dieses Objekt einen eigenen wert gespeichert?
+    int minimum=Query(P_UNIT_DECAY_MIN, F_VALUE);
+    if (minimum)
+      return minimum;
+    // sonst den Wert aus der Blueprint
+    if (objectp(blueprint()))
+      return blueprint()->QueryProp(P_UNIT_DECAY_MIN);
+    else
+      return load_object(load_name())->QueryProp(P_UNIT_DECAY_MIN);
+  }
+  return Query(P_UNIT_DECAY_MIN, F_VALUE);
+}
+
+static int _query_unit_decay_flags() {
+  if (clonep()) {
+    // hat dieses Objekt einen eigenen wert gespeichert?
+    int flags=Query(P_UNIT_DECAY_FLAGS, F_VALUE);
+    if (flags)
+      return flags;
+    // sonst den Wert aus der Blueprint
+    if (objectp(blueprint()))
+      return blueprint()->QueryProp(P_UNIT_DECAY_FLAGS);
+    else
+      return load_object(load_name())->QueryProp(P_UNIT_DECAY_FLAGS);
+  }
+  // Die BP liefert den Wert auf jeden Fall ohne NO_DECAY_UNTIL_MOVE zurueck,
+  // weil dieses Flag im Falle der BP nicht zurueckgesetzt wird und bei Clients 
+  // ohne eigene Flags der Zerfall stoppen wuerde.
+  return Query(P_UNIT_DECAY_FLAGS, F_VALUE) & ~NO_DECAY_UNTIL_MOVE;
+}
+