Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/std/player/life.c b/std/player/life.c
new file mode 100644
index 0000000..73f1ff7
--- /dev/null
+++ b/std/player/life.c
@@ -0,0 +1,841 @@
+// MorgenGrauen MUDlib
+//
+// player/life.c -- player life handling
+//
+// $Id: life.c 9397 2015-12-11 20:29:26Z Zesstra $
+
+// Defines some things which are different than in living.c
+// One example is the heart_beat().
+
+// Properties
+//  P_AGE           -- Age
+
+#pragma strong_types, save_types, rtt_checks
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+inherit "/std/living/life";
+
+#include <rtlimits.h>
+#include <debug_info.h>
+
+#define NEED_PROTOTYPES
+#include <thing/properties.h>
+#include <player/base.h>
+#include <player/life.h>
+#include <moving.h>
+#include <player/comm.h>
+#include <player/gmcp.h>
+#undef NEED_PROTOTYPES
+
+#include <config.h>
+#include <wizlevels.h>
+#include <defines.h>
+#include <language.h>
+#include <properties.h>
+#include <hook.h>
+
+#include <living/life.h>
+#include <player/pklog.h>
+#include <player/combat.h>
+#include <health.h>
+#include <living/combat.h>
+#include <attributes.h>
+#include <defuel.h>
+#include <new_skills.h>
+
+// Die Folgen eines Todes wirken 4 Stunden lang nach
+#define SUFFER_TIME 7200
+#define P_DEATH_INFO "death_info"
+
+int age;                  /* Number of heart beats of this character. */
+
+private int suffer_time;
+static int time_to_save;  /* when to next save player */
+private nosave int die_in_progress; // semaphore fuer die()-Aufrufe.
+
+static int _set_playerkills( int val );
+
+protected void create()
+{
+    ::create();
+    Set(P_AGE, -1, F_SET_METHOD);
+    Set(P_AGE, PROTECTED, F_MODE);
+    Set( P_KILLS, SAVE|SECURED, F_MODE_AS );
+    Set( P_GHOST, SAVE, F_MODE_AS );
+    Set( P_TIMING_MAP, SAVE|SECURED, F_MODE_AS );
+    Set( P_LAST_DEATH_TIME, SAVE|SECURED, F_MODE_AS );
+    Set( P_DEATH_INFO, SAVE|SECURED, F_MODE_AS );
+    Set( P_DEFUEL_LIMIT_FOOD,PROTECTED,F_MODE_AS);
+    Set( P_DEFUEL_LIMIT_DRINK,PROTECTED,F_MODE_AS);
+    Set( P_DEFUEL_TIME_FOOD,PROTECTED,F_MODE_AS);
+    Set( P_DEFUEL_TIME_DRINK,PROTECTED,F_MODE_AS);
+    Set( P_DEFUEL_AMOUNT_FOOD,PROTECTED,F_MODE_AS);
+    Set( P_DEFUEL_AMOUNT_DRINK,PROTECTED,F_MODE_AS);
+    offerHook(H_HOOK_HP,1);
+    offerHook(H_HOOK_SP,1);
+    // P_TIMING_MAP aufraeumen, aber zeitverzoegert, weil jetzt die Daten noch
+    // nicht aus dem Savefile geladen wurden.
+    call_out(#'expire_timing_map, 4);
+}
+
+// called from base.c in Reconnect()
+protected void reconnect() {
+  expire_timing_map();
+}
+
+static int _set_playerkills( int val )
+{
+    string tmp;
+    int playerkills;
+
+    // ist der Setzer in einer Arena/Schattenwelt. Dann nicht. (Ja, Bug ist,
+    // dass EMs aus Schattenwelt/Arena heraus auch das PK-Flag nicht
+    // zuruecksetzen koennen.)
+    if ( previous_object(1) && environment(previous_object(1)) &&
+         (tmp = object_name(environment(previous_object(1)))) &&
+         CheckArenaFight(previous_object(1)) )
+        return 0;
+
+    tmp = sprintf( "%O: %s %O %s",
+                   previous_object(1) || this_interactive() || this_player(),
+                   getuid(ME), val, dtime(time()) );
+
+    playerkills = Query(P_KILLS);
+
+    if( intp(val) && val >= 0 )
+        if( previous_object(1) && IS_ARCH(getuid(previous_object(1))) &&
+            this_interactive() && IS_ARCH(this_interactive()) )
+            playerkills = val;
+        else
+            tmp += " ILLEGAL!";
+    else
+        playerkills++;
+
+    if ( !previous_object(1) || !query_once_interactive(previous_object(1)) ||
+         IS_LEARNER(previous_object(1)) )
+        log_file( "SET_KILLS", tmp + "\n" );
+
+    return Set( P_KILLS, playerkills );
+}
+
+
+public int death_suffering()
+{
+    if ( suffer_time <= 0 )
+    return suffer_time = 0;
+
+    return 1 + (10 * suffer_time) / SUFFER_TIME;
+}
+
+
+protected void heart_beat()
+{
+    mapping di, mods;
+
+    ++age; // erstmal altern ;-)
+
+    ::heart_beat();
+
+    if ( age > time_to_save ){
+        save_me(1);
+        time_to_save = age + 500;
+    }
+
+    // als geist hat man mit den meisten weltlichen Dingen nicht allzuviel zu
+    // tun.
+    if ( QueryProp(P_GHOST) )
+        return;
+
+    if ( suffer_time > 0 )
+        suffer_time--;
+
+    // Todesfolgen nur alle 20 Sekunden (10 HB) checken.
+    // Das ist immer noch oft genug und spart Rechenzeit.
+    if ( (age % 10) || !mappingp(di = QueryProp(P_DEATH_INFO)) )
+        return;
+
+    mods = QueryProp(P_ATTRIBUTES_MODIFIER)["#death"];
+    if (!mappingp(mods)) return;
+
+    if ( mods[A_STR] && --di[A_STR] <= 0) {
+        // einen Attributspunkt regenerieren
+        if ( mods[A_STR] < -1 ) {
+            mods[A_STR]++;
+            di[A_STR] = (110 + 5 * (di[A_STR, 1] + mods[A_STR])) / 10;
+        }
+        else {
+            m_delete( mods, A_STR );
+            m_delete( di, A_STR );
+        }
+    }
+
+    if ( mods[A_CON] && --di[A_CON] <= 0) {
+        // einen Attributspunkt regenerieren
+        if ( mods[A_CON] < -1 ){
+            mods[A_CON]++;
+            di[A_CON] = (110 + 5 * (di[A_CON, 1] + mods[A_CON])) / 10;
+        }
+        else {
+            m_delete( mods, A_CON );
+            m_delete( di, A_CON );
+        }
+    }
+
+    if ( mods[A_DEX] && --di[A_DEX] <= 0) {
+        // einen Attributspunkt regenerieren
+        if ( mods[A_DEX] < -1 ){
+            mods[A_DEX]++;
+            di[A_DEX] = (110 + 5 * (di[A_DEX, 1] + mods[A_DEX])) / 10;
+        }
+        else {
+            m_delete( mods, A_DEX );
+            m_delete( di, A_DEX );
+        }
+    }
+
+    if ( mods[A_INT] && --di[A_INT] <= 0) {
+        // einen Attributspunkt regenerieren
+        if ( mods[A_INT] < -1 ){
+            mods[A_INT]++;
+            di[A_INT] = (110 + 5 * (di[A_INT, 1] + mods[A_INT])) / 10;
+        }
+        else {
+            m_delete( mods, A_INT );
+            m_delete( di, A_INT );
+        }
+    }
+
+    if ( sizeof(di) && sizeof(mods))
+        SetProp( P_DEATH_INFO, di );
+    else
+        SetProp( P_DEATH_INFO, 0 );
+
+    SetProp( P_ATTRIBUTES_MODIFIER, ({ "#death", mods }) );
+}
+
+
+public void force_save() {
+    time_to_save = 0;
+}
+
+
+nomask public int do_damage( int dam, object enemy )
+{
+    int hit_point;
+
+    if( QueryProp(P_GHOST) || dam <= 0 )
+        return 0;
+
+    hit_point = QueryProp(P_HP);
+
+    if ( query_once_interactive(ME) && dam >= hit_point && IS_LEARNING(ME) ){
+        tell_object( ME, "Deine magischen Kraefte verhindern Deinen Tod.\n" );
+        return 0;
+    }
+
+    if ( !objectp(enemy) )
+        enemy = previous_object() || this_interactive() || this_player();
+
+    hit_point -= dam;
+
+    if( hit_point < 0 ){
+        if ( !interactive(ME) )
+            // Netztote sterben nicht
+            hit_point = 10;
+        else {
+            if ( objectp(enemy) && interactive( enemy ) && enemy != ME &&
+                 !QueryProp(P_TESTPLAYER) && !IS_WIZARD(ME) &&
+                 !CheckArenaFight(ME) ) {
+                if ( QueryPlAttacked(enemy) )
+                    hit_point = 1;
+                else {
+                    hit_point = 0;
+                    enemy->SetProp( P_KILLS, -1 );
+                }
+
+                log_file( "KILLER",
+                          sprintf( "%s %s(%d/%d) toetete %s(%d/%d)%s\n",
+                                   ctime(time()),
+                                   getuid(enemy), query_wiz_level(enemy),
+                                   (int) enemy->QueryProp(P_LEVEL), getuid(ME),
+                                   query_wiz_level(ME), QueryProp(P_LEVEL),
+                                   (hit_point ? " NOTWEHR=>KEIN PK" : "") ) );
+            }
+            else { 
+                string killername;
+                if (objectp(enemy))
+                    killername=sprintf("%s (%s)",
+                        BLUE_NAME(enemy), REAL_UID(enemy));
+                else
+                    killername="??? (???)"; 
+
+                if ( !QueryProp(P_TESTPLAYER) )
+                    create_kill_log_entry(killername, enemy );
+            }
+
+            if ( enemy )
+                enemy->StopHuntFor( ME, 1 );
+
+            map_objects( QueryEnemies()[0], "StopHuntFor", ME, 1 );
+            StopHuntingMode(1);
+
+            Set( P_KILLER, enemy );
+            die();
+        }
+    }
+
+    SetProp( P_HP, hit_point );
+    return dam;
+}
+
+
+// Loescht im sterbenden Spieler die 'koerperabhaengigen' Properties
+private void reset_my_properties()
+{
+  // Loeschen der Properties
+  if ( QueryProp(P_POISON) )
+  {
+     // Don't die twice 'cause of the same poison
+     Set( P_POISON, 0, F_SET_METHOD );
+     Set( P_POISON, 0, F_QUERY_METHOD );
+     SetProp( P_POISON, 0 );
+  }
+
+  Set( P_FROG, 0, F_QUERY_METHOD ); 
+  Set( P_FROG, 0, F_SET_METHOD );
+  SetProp( P_FROG, 0 ); // Damit die Attribute auch stimmen.
+  Set( P_ALCOHOL, 0, F_QUERY_METHOD );
+  Set( P_ALCOHOL, 0, F_SET_METHOD );
+  SetProp(P_ALCOHOL, 0 );
+  Set( P_DRINK, 0, F_QUERY_METHOD );
+  Set( P_DRINK, 0, F_SET_METHOD );
+  SetProp(P_DRINK, 0 );
+  Set( P_FOOD, 0, F_QUERY_METHOD );
+  Set( P_FOOD, 0, F_SET_METHOD );
+  SetProp(P_FOOD, 0 );
+  Set( P_BLIND, 0, F_QUERY_METHOD );
+  Set( P_BLIND, 0, F_SET_METHOD );
+  SetProp(P_BLIND, 0 );
+  Set( P_DEAF, 0, F_QUERY_METHOD );
+  Set( P_DEAF, 0, F_SET_METHOD );
+  SetProp(P_DEAF, 0 );
+  Set( P_MAX_HANDS, 0, F_QUERY_METHOD );
+  Set( P_MAX_HANDS, 0, F_SET_METHOD );
+  SetProp( P_MAX_HANDS, 2 );
+  Set( P_HANDS_USED_BY, 0, F_QUERY_METHOD );
+  Set( P_HANDS_USED_BY, 0, F_SET_METHOD );
+  SetProp( P_HANDS_USED_BY, ({}) );
+  Set( P_PARA, 0 );
+  Set( P_NO_REGENERATION, 0, F_QUERY_METHOD );
+  Set( P_NO_REGENERATION, 0, F_SET_METHOD );
+  SetProp(P_NO_REGENERATION, 0 );
+  Set( P_TMP_MOVE_HOOK, 0, F_QUERY_METHOD );
+  Set( P_TMP_MOVE_HOOK, 0, F_SET_METHOD );
+  SetProp(P_TMP_MOVE_HOOK, 0 );
+  Set( P_LAST_DEATH_TIME , time() );
+  // damit der Teddy o.ae. mitbekommt, dass man jetzt tot ist ]:->
+  SetProp( P_HP, 0 );
+  SetProp( P_SP, 0 );
+}
+
+varargs protected int second_life( object corpse )
+{
+    int lost_exp, level;
+    // Es gibt Funktionen, die sollte man nicht per Hand aufrufen duerfen ;-)
+    if ( extern_call() && previous_object() != ME )
+        return 0;
+
+    if ( query_once_interactive(ME) && IS_LEARNING(ME) ){
+        tell_object( ME, "Sei froh, dass Du unsterblich bist, sonst waere "
+                     "es eben zu Ende gewesen.\n" );
+        return 1;
+    }
+
+    if ( !IS_SEER(ME) || (level = QueryProp(P_LEVEL)) < 20 )
+        lost_exp = QueryProp(P_XP) / 3;
+    else
+        lost_exp = QueryProp(P_XP) / (level - 17);
+
+    AddExp(-lost_exp);
+
+
+    // Todesfolgen setzen....
+    //SetProp( P_DEATH_INFO, 1);
+    if ( !IS_LEARNING(ME) && !QueryProp(P_TESTPLAYER) ) {
+
+        mapping attr = QueryProp(P_ATTRIBUTES);
+        mapping mods = QueryProp(P_ATTRIBUTES_MODIFIER)["#death"] || ([]);
+
+        // Attribute auf 75% vom aktuellen Wert senken
+        mods[A_STR] = -attr[A_STR] + (3 * (attr[A_STR] + mods[A_STR]) / 4);
+        mods[A_CON] = -attr[A_CON] + (3 * (attr[A_CON] + mods[A_CON]) / 4);
+        mods[A_DEX] = -attr[A_DEX] + (3 * (attr[A_DEX] + mods[A_DEX]) / 4);
+        mods[A_INT] = -attr[A_INT] + (3 * (attr[A_INT] + mods[A_INT]) / 4);
+
+        SetProp( P_ATTRIBUTES_MODIFIER, ({ "#death", mods }) );
+
+        int offs = 220;  // 220 heart_beats == 7min20
+        // Die 220 HB sind fix, dazu kommen noch 5 HB pro realem 
+        // Attributspunkt. Geteilt wird das ganze noch durch 10, weil im HB
+        // nur alle 10 HBs die TF gecheckt werden. Da wird dann alle 10 HB ein
+        // Punkt abgezogen und wenn 0 erreicht ist, wird das Attribut um eins
+        // regeneriert.
+        SetProp( P_DEATH_INFO, ([ 
+            A_STR: (offs + 5 * (attr[A_STR] + mods[A_STR]))/10; attr[A_STR],
+            A_CON: (offs + 5 * (attr[A_CON] + mods[A_CON]))/10; attr[A_CON],
+            A_DEX: (offs + 5 * (attr[A_DEX] + mods[A_DEX]))/10; attr[A_DEX],
+            A_INT: (offs + 5 * (attr[A_INT] + mods[A_INT]))/10; attr[A_INT]
+                  ]) );
+
+        // die suffer_time wird via death_suffering() von
+        // QuerySkillAttribute() abgefragt und geht dann als Malus in
+        // SA_QUALITY mit ein.
+        if ( suffer_time <= 2*SUFFER_TIME )
+            suffer_time += SUFFER_TIME - 1;
+        else
+            suffer_time = 3 * SUFFER_TIME - 1;
+    }
+
+    // Die verschiedenen NotifyPlayerDeath-Funktionen koennen u.U. schlecht
+    // programmiert sein und zuviel Rechenzeit ziehen. Deshalb werden sie mit
+    // einem Limits von 150k bzw. 80k aufgerufen. Ausserdem werden sie nur
+    // gerufen, solange noch min. 25k Ticks da sind.
+    int *limits=query_limits();
+    limits[LIMIT_EVAL] = 150000;
+    limits[LIMIT_COST] = LIMIT_DEFAULT;
+
+    mixed killer = QueryProp(P_KILLER);
+    mixed gi = QueryProp(P_GUILD);
+    if (stringp(gi))
+        gi = find_object("/gilden/"+gi);
+    // jedes Objekt nur einmal, aber nicht via m_indices(mkmapping)) wegen
+    // Verlust der Reihenfolge.
+    object *items = ({killer});
+    if (environment() != killer)
+        items += ({environment()});
+    if (gi != killer && gi != environment())
+        items += ({gi});
+    foreach(object item: items) {
+        if (get_eval_cost() < limits[LIMIT_EVAL] + 20000)
+            break;
+        // falls ein NPD() implizit andere Objekt zerstoert hat.
+        if (objectp(item)) {
+            catch(limited(#'call_other, limits, item, "NotifyPlayerDeath",
+                  ME, killer, lost_exp);publish);
+        }
+    }
+    // jetzt den Rest.
+    limits[LIMIT_EVAL] = 80000;
+    foreach(object item: (environment() ? all_inventory(environment()) : ({}))
+                        + deep_inventory(ME)
+                        + (objectp(corpse) ? deep_inventory(corpse) : ({}))
+                        - items ) {
+        // wenn nicht mehr genug Ticks, haben die restlichen Pech gehabt.
+        if (get_eval_cost() < limits[LIMIT_EVAL] + 20000)
+            break;
+        // NPD() koennen andere Objekt zerstoeren.
+        if (objectp(item)) {
+            catch(limited(#'call_other, limits, item, "NotifyPlayerDeath",
+                                    ME, killer, lost_exp);publish);
+        }
+    }
+
+    // Properties zuruecksetzen, sollte nach dem NotifyPlayerDeath()
+    // passieren, weil Objekte sich darin evtl. erstmal noch aufraeumen und
+    // props manipulieren.
+    reset_my_properties();
+    UpdateAttributes(); // Beim Tod werden Dinge entfernt, Attribute pruefen
+    
+    // Auch Bewegung erst nach den NPD(), da diese den Spieler bewegen
+    // koennten, was eine Bewegung aus dem Todesraum waere, wenn die Bewegung
+    // vor dem NPD() stattfaende.
+    SetProp( P_GHOST, 1 ); // nach reset_my_properties() !
+    clone_object( "room/death/death_mark" )->move( ME, M_NOCHECK ); 
+
+    return 1;
+}
+
+
+public int AddHpHook( object ob )
+{
+    object *hooks;
+
+    if ( !objectp(ob) )
+        return 0;
+
+    if ( !pointerp(hooks = Query(P_HP_HOOKS)) ){
+        Set( P_HP_HOOKS, ({ ob }) );
+        return 1;
+    }
+
+    if ( member( hooks, ob ) >= 0 )
+        return 0;
+
+    Set( P_HP_HOOKS, (hooks - ({0})) + ({ ob }) );
+    return 1;
+}
+
+
+public int RemoveHpHook( object ob )
+{
+    object *hooks;
+
+    if ( !pointerp(hooks = Query(P_HP_HOOKS)) )
+        return 0;
+
+    Set( P_HP_HOOKS, hooks - ({ ob, 0 }) );
+    return 1;
+}
+
+
+static int _query_age() {
+    return Set(P_AGE, age, F_VALUE);
+}
+
+static int _set_hp( int hp )
+{
+    object *hooks;
+    int ret, i, old;
+
+    if ( (old = Query(P_HP, F_VALUE)) == hp )
+        return old;
+
+    ret = life::_set_hp(hp);
+
+    if ( ret == old )
+        return ret;
+
+    // Call old hooks in all objects... destructed objects will be ignored.
+    if (pointerp(hooks = Query(P_HP_HOOKS)))
+      call_other(hooks, "NotifyHpChange");
+
+    // Call new hooks.
+    HookFlow(H_HOOK_HP,ret);
+
+    // Report-ausgabe
+    status_report(DO_REPORT_HP, ret);
+
+    return ret;
+}
+
+
+static int _set_sp( int sp )
+{
+    object *hooks;
+    int ret, i, old;
+
+    if ( (old = Query(P_SP,F_VALUE)) == sp )
+        return old;
+
+    ret = life::_set_sp(sp);
+
+    if ( ret == old )
+        return ret;
+
+    // Call old hooks in all objects... destructed objects will be ignored.
+    if (pointerp(hooks = Query(P_HP_HOOKS)))
+      call_other(hooks, "NotifyHpChange");
+
+    // Call new hooks.
+    HookFlow(H_HOOK_SP,ret);
+
+    // Report-ausgabe
+    status_report(DO_REPORT_SP, ret);
+
+    return ret;
+}
+
+static int _set_poison(int n)
+{
+  int old = Query(P_POISON, F_VALUE);
+  if (old == n )
+      return old;
+  n = life::_set_poison(n);
+  if ( n == old )
+      return n;
+  // ggf. Statusreport ausgeben
+  if (interactive(ME))
+    status_report(DO_REPORT_POISON, n);
+  return n;
+}
+
+static int _set_max_poison(int n)
+{
+  if (n >= 0)
+  {
+    Set(P_MAX_POISON, n, F_VALUE);
+    int maxp=QueryProp(P_MAX_POISON); // koennte ne Querymethode drauf sein...
+    if (QueryProp(P_POISON) > maxp)
+      SetProp(P_POISON, maxp);
+  }
+  GMCP_Char( ([P_MAX_POISON: n]) );
+  return n;
+}
+
+static int _set_max_hp( int hp )
+{
+  if (hp >= 0)
+  {
+    Set(P_MAX_HP, hp, F_VALUE);
+    int maxhp=QueryProp(P_MAX_HP); // koennte ne Querymethode drauf sein...
+    if (QueryProp(P_HP) > maxhp)
+      SetProp(P_HP, maxhp);
+  }
+  GMCP_Char( ([P_MAX_HP: hp]) );
+  return hp;
+}
+
+static int _set_max_sp( int sp )
+{
+  if (sp >= 0)
+  {
+    Set(P_MAX_SP, sp, F_VALUE);
+    int maxsp=QueryProp(P_MAX_SP); // koennte ne Querymethode drauf sein...
+    if (QueryProp(P_SP) > maxsp)
+      SetProp(P_SP, maxsp);
+  }
+  GMCP_Char( ([P_MAX_SP: sp]) );
+  return sp;
+}
+
+static int _set_ghost( int g ) {
+    object team;
+
+    if(!g && query_hc_play()>1)
+    {
+      write("HAHAHA, DU BIST AUF EWIG MEIN.\n");
+      return Query(P_GHOST);
+    }
+
+    g = Set( P_GHOST, g );
+
+    if ( g && objectp(team = Query(P_TEAM)) )
+        team->RemoveMember(ME);
+
+    return g;
+}
+
+
+public int undie()
+{
+    mixed x, di;
+    mapping attr, mods;
+
+    if ( !this_interactive() || !previous_object() )
+        return 0;
+
+    if ( !IS_ARCH(this_interactive()) || !IS_ARCH(getuid(previous_object())) ||
+         process_call() )
+        log_file( "UNDIE", sprintf( "%s %O -> %O\n", dtime(time())[5..16],
+                                    this_interactive(), ME ) );
+
+    if ( x = Query(P_DEADS) )
+        x--;
+
+    Set( P_DEADS, x );
+
+    x = QueryProp(P_XP);
+
+    if ( (di = QueryProp(P_LEVEL)) < 20 || !IS_SEER(ME) )
+        x = (int)(x * 1.5);
+    else
+        // Umweg ueber float, weil bei hohen XP+Level sonst 32Bit nicht
+        // mehr ausreichen -> negative XP
+        x = (int) ( x * ((float) (di - 17) / (di - 18)) );
+
+    Set( P_XP, x );
+
+    attr = QueryProp(P_ATTRIBUTES) || ([]);
+    mods = QueryProp(P_ATTRIBUTES_MODIFIER)["#death"] || ([]);
+
+    if ( mappingp(di = QueryProp(P_DEATH_INFO)) ){
+        // Beim naechsten heart_beat checken
+        // Zesstra: Wieso eigentlich? Die Modifier werden doch direkt hier
+        // geloescht. So expired man auch einen Teil von nicht-undie-ten Toden
+        // vorzeitig...? Mal auskommentiert. 29.10.2007
+        //di[A_STR] = 1;
+        //di[A_DEX] = 1;
+        //di[A_INT] = 1;
+        //di[A_CON] = 1;
+    }
+    else
+      di = ([]);
+    
+    mods[A_STR] = ((4 * (attr[A_STR] + mods[A_STR])) / 3) - attr[A_STR];
+    mods[A_DEX] = ((4 * (attr[A_DEX] + mods[A_DEX])) / 3) - attr[A_DEX];
+    mods[A_INT] = ((4 * (attr[A_INT] + mods[A_INT])) / 3) - attr[A_INT];
+    mods[A_CON] = ((4 * (attr[A_CON] + mods[A_CON])) / 3) - attr[A_CON];
+
+    if ( mods[A_STR] >= 0 ) {
+        m_delete( mods, A_STR );
+        m_delete( di, A_STR);
+    }
+    if ( mods[A_DEX] >= 0 ) {
+        m_delete( mods, A_DEX );
+        m_delete( di, A_DEX);
+    }
+    if ( mods[A_INT] >= 0 ) {
+        m_delete( mods, A_INT );
+        m_delete( di, A_INT);
+    }
+    if ( mods[A_CON] >= 0 ) {
+        m_delete( mods, A_CON );
+        m_delete( di, A_CON);
+    }
+
+    SetProp( P_ATTRIBUTES_MODIFIER, ({ "#death", mods }) );
+    if (sizeof(di))
+      SetProp( P_DEATH_INFO, di );
+    else
+      SetProp( P_DEATH_INFO, 0);
+
+    suffer_time -= ((SUFFER_TIME)-1);
+
+    if ( suffer_time < 0 )
+        suffer_time = 0;
+
+    Set( P_GHOST, 0 );
+    return 1;
+}
+
+
+varargs public void die( int poisondeath, int extern)
+{
+    // laeuft schon ein die()? Fehler ausloesen, Ursache rekursiver die() soll
+    // gefunden werden. DINFO_EVAL_NUMBER wird in jedem Top-Level Call im
+    // driver erhoeht, d.h. gleiche Zahl signalisiert ein rekursives die().
+
+    if (die_in_progress == debug_info(DINFO_EVAL_NUMBER))
+    {
+      // TODO: ist das die_in_progress aus dem letzten Backend-Cycle?
+      raise_error(sprintf(
+            "die() in %O gerufen, aber die() laeuft bereits!\n",
+            this_object()));
+    }
+    die_in_progress = debug_info(DINFO_EVAL_NUMBER);
+    
+    // Fuer HC-Player ists jetzt gelaufen...
+    if(query_hc_play()==1)
+    {
+      set_hc_play(capitalize(geteuid(ME)),time());
+      SetDefaultHome("/room/nirvana");
+      SetDefaultPrayRoom("/room/nirvana");
+      SetProp(P_START_HOME,"/room/nirvana");
+      log_file("HCDEAD",dtime(time())+" "+capitalize(geteuid(ME))
+          +" geht in das Nirvana ein!\n");
+    }
+
+    // Wenn das die() direkt von aussen gerufen wurde, muss P_KILLER hier
+    // gespeichert werden.
+    if (extern_call())
+        SetProp(P_KILLER, previous_object());
+
+    // Sichern der zu loeschenden Properties. Diese Props werden im Verlauf des
+    // Todes zurueckgesetzt. Einige Magier wollen diese Daten aber spaeter
+    // noch haben und fragen teilweise P_LAST_DEATH_PROPS im
+    // NotifyPlayerDeath() ab. Daher wird der Kram jetzt hier schonmal
+    // gesichert.
+    // BTW: Props mit Mappings/Arrays sollten kopiert werden.
+    SetProp(P_LAST_DEATH_PROPS, ([
+      P_POISON          : QueryProp(P_POISON),
+      P_FROG            : QueryProp(P_FROG),
+      P_ALCOHOL         : QueryProp(P_ALCOHOL),
+      P_DRINK           : QueryProp(P_DRINK),
+      P_FOOD            : QueryProp(P_FOOD),
+      P_BLIND           : QueryProp(P_BLIND),
+      P_DEAF            : QueryProp(P_DEAF),
+      P_MAX_HANDS       : QueryProp(P_MAX_HANDS),
+      P_PARA            : QueryProp(P_PARA),
+      P_NO_REGENERATION : QueryProp(P_NO_REGENERATION),
+      P_HP              : QueryProp(P_HP),
+      P_SP              : QueryProp(P_SP),
+      P_LAST_DEATH_TIME : QueryProp(P_LAST_DEATH_TIME )
+    ]) );
+
+    // call the inherited die() with 10 Mio Ticks which will be accounted as 1
+    // Tick... ;-)
+    int *limits = query_limits();
+    limits[LIMIT_EVAL] == 10000000;
+    limits[LIMIT_COST] == LIMIT_UNLIMITED;
+    limited(#'::die, limits, poisondeath, (extern_call() ? 1 : 0)); 
+
+    // nach dem Tod sollte man auch keine LP mehr haben.
+    SetProp(P_HP, 0);
+
+    // naechster Tod kann kommen. Dekrementierung, da 0 ein gueltiger Wert
+    // fuer DINFO_EVAL_NUMBER waere. abs(), um nicht  -__INT_MAX__ zu
+    // dekrementieren.
+    die_in_progress = abs(die_in_progress) - 1;
+}
+
+int defuel_food()
+{
+    int ret;
+    object prev;
+    
+    ret=::defuel_food();
+    prev=previous_object();
+    if(!prev || !objectp(prev))
+    {
+        prev=this_object();
+    }
+    
+    if(ret<=0)
+    {
+            call_other(FUELSTAT,"addDefuelStatEntry",prev,this_object(),0,1,0,1);
+    }
+    else
+    {
+            call_other(FUELSTAT,"addDefuelStatEntry",prev,this_object(),0,0,ret,1);
+    }
+    return ret;
+}
+
+int defuel_drink()
+{
+    int ret;
+    object prev;
+    
+    ret=::defuel_drink();
+    prev=previous_object();
+    if(!prev || !objectp(prev))
+    {
+        prev=this_object();
+    }
+    
+    if(ret<=0)
+    {
+            call_other(FUELSTAT,"addDefuelStatEntry",prev,this_object(),0,1,0,0);
+    }
+    else
+    {
+            call_other(FUELSTAT,"addDefuelStatEntry",prev,this_object(),0,0,ret,0);
+    }
+    return ret;
+}
+
+public void show_age()
+{ int i,j;
+
+    write("Alter:\t");
+    i = QueryProp(P_AGE);
+    if ((j=i/43200))
+    {
+      write(j + " Tag"+(j==1?" ":"e "));
+      i %= 43200;
+    }
+    if ((j=i/1800))
+    {
+      write(j + " Stunde"+(j==1?" ":"n "));
+      i %= 1800;
+    }
+    if ((j=i/30))
+    {
+      write(j + " Minute"+(j==1?" ":"n "));
+      i %= 30;
+    }
+    write(i*2 + " Sekunden.\n");
+}
+