Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/std/npc/chat.c b/std/npc/chat.c
new file mode 100644
index 0000000..7f4f89b
--- /dev/null
+++ b/std/npc/chat.c
@@ -0,0 +1,66 @@
+// MorgenGrauen MUDlib
+//
+// npc/chat.c -- Labernde NPCs
+//
+// $Id: chat.c 6801 2008-03-21 23:34:46Z Zesstra $
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <properties.h>
+#define NEED_PROTOTYPES
+#include <living/combat.h>
+#include <thing/properties.h>
+#undef NEED_PROTOTYPES
+
+#define ME this_object()
+
+/*
+ * Some simple chat variables
+ */
+
+/*
+ * heart_beat is called so the monster may chat.
+ */
+void SetChats(int chance, mixed strs) {
+  if (!pointerp(strs))
+    return;
+  SetProp(P_CHAT_CHANCE,chance);
+  SetProp(P_CHATS,strs);
+}
+
+void SetAttackChats(int chance, mixed strs) {
+  if (!pointerp(strs))
+    return;
+  SetProp(P_ACHAT_CHANCE,chance);
+  SetProp(P_ACHATS,strs);
+}
+
+void DoAttackChat() {
+  string* c;
+  if (!ME || !environment(ME))
+    return;
+  if (QueryProp(P_DISABLE_ATTACK)>0)return ;
+  if (random(100) < QueryProp(P_ACHAT_CHANCE))
+    if ((c = QueryProp(P_ACHATS)) && sizeof(c)) 
+      tell_room(environment(ME),
+		process_string(c[random(sizeof(c))]));
+}
+
+void DoChat() {
+  string *c;
+  if (!ME || !environment(ME))
+    return;
+  if (random(100) < QueryProp(P_CHAT_CHANCE))
+    if ((c = QueryProp(P_CHATS)) && sizeof(c)) 
+      tell_room(environment(ME),
+		process_string(c[random(sizeof(c))]));
+}
+
+protected void heart_beat()
+{
+  if( InFight() ) DoAttackChat();
+  else            DoChat();
+}
diff --git a/std/npc/combat.c b/std/npc/combat.c
new file mode 100644
index 0000000..747714b
--- /dev/null
+++ b/std/npc/combat.c
@@ -0,0 +1,407 @@
+// MorgenGrauen MUDlib
+//
+// npc/combat.c -- NPC-spezifische Kampffunktionen
+//
+// $Id: combat.c 9488 2016-02-19 21:24:04Z Arathorn $
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+inherit "std/living/combat";
+
+#include <combat.h>
+#include <language.h>
+#include <properties.h>
+#include <wizlevels.h>
+#include <health.h>
+#include <new_skills.h>
+
+#define NEED_PROTOTYPES 1
+#include <living/life.h>
+#undef NEED_PROTOTYPES
+
+#define HB_CHECK 7
+#define ME this_object()
+#define STATMASTER "/p/service/rochus/guildstat/master"
+
+nosave int heartbeat, beatcount;
+
+private void catch_up_hbs();
+
+protected void create() {
+  ::create();
+  beatcount=1;
+  heartbeat=1;
+}
+
+protected void create_super() {
+  set_next_reset(-1);
+}
+
+// aktuelles Lebewesen, fuer das dieser NPC gerade taetig ist. Default:
+// Spieler, bei dem er als Helfer-NPC registriert ist.
+public object QueryUser()
+{
+  mixed helperdata = QueryProp(P_HELPER_NPC);
+  if (pointerp(helperdata) && objectp(helperdata[0]))
+    return helperdata[0];
+  return 0;
+}
+
+// ggf. Feinde expiren. Soll das Problem verringern, dass Spieler nach Tagen
+// erst die Meldung kriegen, dass der NPC sie nicht mehr jagt, wenn der HB
+// reaktivert wird.
+void reset() {
+  // ggf. die abgeschalteten HBs nachholen.
+  if (!heartbeat)
+    catch_up_hbs();
+  // ggf. P_ENEMY_DAMAGE zuruecksetzen
+  ResetEnemyDamage();
+}
+
+static void _set_max_hp(int i) {
+  Set(P_MAX_HP,i);
+  SetProp(P_HP,i);
+}
+
+static void _set_max_sp(int i) {
+  Set(P_MAX_SP,i);
+  SetProp(P_SP,i);
+}
+
+
+// Check-Funktion fuer die P_NO_ATTACK-QueryMethod
+static mixed _check_immortality()
+{
+    int t;
+
+    if ( !(t = Query("time_to_mortality")) || time() > t ){
+        // Zeit ist abgelaufen - wieder angreifbar machen
+        Set( P_NO_ATTACK, 0, F_QUERY_METHOD );
+        heartbeat = 1;
+        beatcount = 1;
+        set_heart_beat(1);
+
+        return 0;
+    }
+
+    // der NPC ist noch unangreifbar
+    return break_string( capitalize(name( WER, 1 )) + " versteckt sich hinter "
+                         "einem Fehler im Raum-Zeit-Gefuege und entgeht so "
+                         "voruebergehend allen Angriffen.", 78 );
+}
+
+
+// wenn der HeartBeat buggt, wird diese Funktion vom Master aufgerufen
+public void make_immortal()
+{
+    // fuer 5 Minuten unangreifbar machen
+    Set( P_NO_ATTACK, #'_check_immortality, F_QUERY_METHOD );
+
+    Set( "time_to_mortality", time() + 300, F_VALUE );
+
+    // damit die Spieler keinen Vorteil durch den Bug haben, heilen
+    heal_self(10000);
+
+    // da nun der Heartbeat abgeschaltet ist und normalerweise erst
+    // reaktiviert wird, sobald jemand nach 5min P_NO_ATTACK abfragt, muss man
+    // aber auf Viecher achten, die immer nen Heartbeat haben wollen. In dem
+    // fall per call_out selber die Prop abfragen.
+    if (QueryProp(P_HB))
+      call_out(#'QueryProp, 301, P_NO_ATTACK);
+}
+
+
+// Damit NPCs gegeneinander weiterkaempfen, auch wenn kein Spieler
+// in der Naehe ist:
+static int _query_hb()
+{
+    // TODO: return InFight() || Query(P_HB, F_VALUE), sobald InFight()
+    // geaendert.
+    return (InFight() || Query(P_HB,F_VALUE)) ? 1 : 0;
+}
+
+
+#define SPELL_TOTALRATE 0
+#define SPELL_DAMAGE 1
+#define SPELL_TEXT_FOR_ENEMY 2
+#define SPELL_TEXT_FOR_OTHERS 3
+#define SPELL_DAMTYPE 4
+#define SPELL_FUNC 5
+#define SPELL_ARG 6
+
+varargs int AddSpell(int rate, int damage, string TextForEnemy,
+                     string TextForOthers, string|string* dam_type, string func,
+                     int|mapping spellarg) {
+  mixed *spells;
+  int total_rates;
+
+  if (rate<0 || damage<=0 || !stringp(TextForEnemy) ||
+      !stringp(TextForOthers))
+     return 0;
+
+  if (stringp(dam_type))
+     dam_type = ({dam_type});
+  else if (!pointerp(dam_type))
+      dam_type = ({DT_MAGIC});
+  
+  // Tatsaechlich ist es immer ein nicht-physischer Angriff, wenn spellarg ein
+  // int ist, weil wenn spellarg==0 ist der Default nicht-physischer Angriff
+  // und bei spellarg!=0 auch. Nur mit einem mapping kann man einen phys.
+  // Angriff erzeugen.
+  if (intp(spellarg))
+    spellarg = ([SP_PHYSICAL_ATTACK: 0]);
+
+  // Falls vorhanden, alte Syntax auf die von replace_personal() anpassen,
+  // die im heart_beat() beim Ausgeben der Meldung verwendet wird.
+  if ( strstr(TextForOthers, "@", 0) != -1 )
+  {
+    // Zeichen nach @WER & Co in runde Klammern einschliessen, damit es als
+    // Sub-Pattern im Ausgabestring wiederholt werden kann. Ansonsten wuerde
+    // es mit ersetzt.
+    TextForOthers = regreplace(TextForOthers, "@WER([^1-9])", "@WER1\\1", 1);
+    TextForOthers = regreplace(TextForOthers, "@WESSEN([^1-9])",
+                               "@WESSEN1\\1", 1);
+    TextForOthers = regreplace(TextForOthers, "@WEM([^1-9])", "@WEM1\\1", 1);
+    TextForOthers = regreplace(TextForOthers, "@WEN([^1-9])", "@WEN1\\1", 1);
+  }
+  total_rates=Query("npc:total_rates")+rate;
+  spells=Query(P_SPELLS);
+  if (!pointerp(spells))
+    spells=({});
+  spells+=({({total_rates, damage, TextForEnemy, TextForOthers,
+              dam_type, func, spellarg})});
+  Set(P_SPELLS,spells);
+  Set("npc:total_rates",total_rates);
+  return 1;
+}
+
+int AutoAttack(object ob) {
+  mixed m;
+
+  if (!query_once_interactive(ob))
+    return 0;
+  if (mappingp(m=QueryProp(P_AGGRESSIVE))) {
+    mixed *ind,x,z;
+    float f;
+    int i,n;
+
+    ind=m_indices(m)-({0});n=0;f=0.0;
+    for (i=sizeof(ind)-1;i>=0;i--) {
+      x=ind[i];
+      if ((z=m[x][ob->QueryProp(x)]) || (z=m[x][0])) {
+  f=f+(float)z;
+  n++;
+      }
+    }
+    if (n)
+      m=f/((float)n);
+    else
+      m=m[0];
+  }
+  if (((int)(100*(m+ob->QueryProp(P_AGGRESSIVE))))<=random(100))
+    return 0;
+  if  (IS_LEARNER(ob)
+       && (ob->QueryProp(P_INVIS)
+     || ob->QueryProp(P_WANTS_TO_LEARN)))
+    return 0;
+  return 1;
+}
+
+void SpellAttack(object enemy) {
+}
+
+#if 0
+TJ(string s) {
+  object o;
+  if (o=find_player("jof"))
+    tell_object(o,sprintf("%O: %s\n",this_object(),s));
+}
+#else
+#define TJ(x)
+#endif
+
+protected void heart_beat() {
+  int r,i;
+  mixed env,*spells, sinfo;
+  object enemy;
+
+  if ( --beatcount < 0 )
+      beatcount = 0;
+  
+  if (!beatcount && !Query(P_HB)) {
+    if (!environment()) {
+      set_heart_beat(0);
+      heartbeat = 0;
+      if( clonep(this_object()) ) remove();
+      return;
+    }
+    if (!QueryProp(P_POISON)) {
+      // Spieler anwesend?
+      env = filter(all_inventory(environment()), #'query_once_interactive);
+      if (!sizeof(env)) {
+	// Nein, HBs abschalten.
+	set_heart_beat(0);
+	heartbeat=0;
+	TJ("OFF\n");
+	beatcount=HB_CHECK;
+	Set("npc:beat_off_num",absolute_hb_count());
+	return;
+      }
+    }
+  }
+  ::heart_beat();
+  if (!ME)
+      return;
+  enemy=SelectEnemy();
+  if (QueryProp(P_AGGRESSIVE)
+      && (!enemy || environment()!=environment(enemy))
+      && !beatcount) {
+    beatcount=HB_CHECK;
+    env=filter(all_inventory(environment()),#'AutoAttack);
+    if (!sizeof(env))
+       return;
+    i=random(sizeof(env));
+    Kill(env[i]);
+  }
+  else if (!beatcount)
+    beatcount=HB_CHECK;
+  if (!objectp(enemy) ||QueryProp(P_DISABLE_ATTACK)>0)
+    return;
+  SpellAttack(enemy);
+
+  if (!pointerp(spells=Query(P_SPELLS))
+      || !sizeof(spells)
+      || !objectp(enemy=SelectEnemy())
+      || environment(enemy)!=environment()
+      || (QueryProp(P_DISABLE_ATTACK)>0)
+      || random(100)>Query(P_SPELLRATE))
+    return;
+  r=random(Query("npc:total_rates"));
+  for (i=sizeof(spells)-1;(i>0 && spells[i-1][SPELL_TOTALRATE]>r);i--)
+    ;
+  string akt_spell_mess = spells[i][SPELL_TEXT_FOR_ENEMY];
+  if ( sizeof(akt_spell_mess) )
+    tell_object(enemy, break_string(akt_spell_mess, 78));
+  akt_spell_mess = spells[i][SPELL_TEXT_FOR_OTHERS];
+  // Nur, wenn ueberhaupt eine Meldung gesetzt wurde, muss diese verarbeitet
+  // werden.
+  if (stringp(akt_spell_mess) && sizeof(akt_spell_mess))
+  {
+    akt_spell_mess = replace_personal(akt_spell_mess, ({enemy}), 1);
+    say(break_string(akt_spell_mess, 78),({enemy, this_object()}));
+  }
+  sinfo = deep_copy(spells[i][SPELL_ARG]);
+  if(!mappingp(sinfo))
+    sinfo=([ SI_MAGIC_TYPE :({ MT_ANGRIFF }) ]);
+  else if(!sinfo[SI_MAGIC_TYPE])
+    sinfo[ SI_MAGIC_TYPE]=({ MT_ANGRIFF });
+  if(!sinfo[SP_PHYSICAL_ATTACK] &&
+     (enemy->SpellDefend(this_object(),sinfo) >
+      random(MAX_ABILITY+QueryProp(P_LEVEL)*50))){
+    tell_object(enemy,"Du wehrst den Spruch ab.\n");
+    say(enemy->Name(WER,1)+" wehrt den Spruch ab.\n",
+        ({ enemy, this_object()}));
+    return ;
+  }
+  int damage = random(spells[i][SPELL_DAMAGE])+1;
+  enemy->Defend(damage, spells[i][SPELL_DAMTYPE],
+                spells[i][SPELL_ARG],
+                this_object());
+
+  // Falls der Gegner (oder wir) im Defend stirbt, hier abbrechen
+  if ( !objectp(ME) || !objectp(enemy) 
+      || enemy->QueryProp(P_GHOST) ) return;
+  
+  if (spells[i][SPELL_FUNC] && stringp(spells[i][SPELL_FUNC]))
+    catch(call_other(this_object(),
+         spells[i][SPELL_FUNC],
+         enemy,
+         damage,
+         spells[i][SPELL_DAMTYPE]);publish);
+}
+
+// Heartbeats nachholen.
+private void catch_up_hbs() {
+  // gibt es HBs zum nachholen?
+  int beat_off_num = Query("npc:beat_off_num");
+  if (!beat_off_num)
+    return; // nein.
+  // wieviele HBs nachholen?
+  beat_off_num = absolute_hb_count() - beat_off_num;
+  
+  if (beat_off_num>0) {
+    // Nicht ausgefuehrtes HEILEN nachholen
+    int rlock=QueryProp(P_NO_REGENERATION);
+    int hp=QueryProp(P_HP);
+    int sp=QueryProp(P_SP);
+    int alc=QueryProp(P_ALCOHOL);
+    if (!(rlock & NO_REG_HP)) {
+      hp+=beat_off_num/HEAL_DELAY+alc/ALCOHOL_DELAY;
+      SetProp(P_HP,hp);
+    }
+    if (!(rlock & NO_REG_SP)) {
+      sp+=beat_off_num/HEAL_DELAY+alc/ALCOHOL_DELAY;
+      SetProp(P_SP,sp);
+    }
+    alc-=beat_off_num/ALCOHOL_DELAY;
+    if ( alc < 0 )
+      alc = 0;
+    SetProp(P_ALCOHOL,alc);
+    int da = QueryProp(P_DISABLE_ATTACK);
+    // Paralysen abbauen
+    if ( da > 0 ) {
+      da -= beat_off_num;
+      if ( da < 0 )
+	da = 0;
+      SetProp( P_DISABLE_ATTACK, da );
+    }
+    // Hunttimes aktualisieren, Feinde expiren
+    update_hunt_times(beat_off_num);
+    if (!heartbeat)
+      // HBs immer noch abgeschaltet, naechstes Mal HBs seit jetzt nachholen.
+      Set("npc:beat_off_num",absolute_hb_count());
+    else
+      // HB laeuft wieder, nix mehr nachholen, bis zur naechsten Abschaltung.
+      Set("npc:beat_off_num",0);
+  }
+}
+
+void init() {
+
+  // ggf. Heartbeats nachholen und wieder einschalten.
+  if (!heartbeat) {
+    set_heart_beat(1);
+    heartbeat=1;
+    catch_up_hbs();
+  }
+
+  if (AutoAttack(this_player()))
+    Kill(this_player());
+}
+
+private nosave closure mod_att_stat;
+
+int Defend(int dam, mixed dam_type, mixed spell, object enemy) {
+  if (objectp(enemy=(enemy||this_player()))
+      && query_once_interactive(enemy)
+      && !IS_LEARNER(enemy)) {
+    if (!objectp(get_type_info(mod_att_stat,2))) {
+      object ma;
+      if (!objectp(ma=find_object(STATMASTER)))
+        return ::Defend(dam,dam_type,spell,enemy);
+      // Keine Statistik wenn Master nicht geladen ist.
+      mod_att_stat=symbol_function("ModifyAttackStat",ma);
+    }
+    funcall(mod_att_stat,
+            enemy->QueryProp(P_GUILD),
+            enemy->QueryProp(P_GUILD_LEVEL),
+            dam,
+            dam_type,
+            spell);
+  }
+
+  return ::Defend(dam,dam_type,spell,enemy);
+}
diff --git a/std/npc/comm.c b/std/npc/comm.c
new file mode 100644
index 0000000..892d8fa
--- /dev/null
+++ b/std/npc/comm.c
@@ -0,0 +1,57 @@
+// MorgenGrauen MUDlib
+//
+// npc/comm.c -- Basiskommunikation fuer NPCs
+//
+// $Id: comm.c 9358 2015-10-22 18:35:04Z Zesstra $
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+inherit "/std/living/comm";
+
+#include <language.h>
+#include <living/comm.h>
+#define NEED_PROTOTYPES
+#include <thing/description.h>
+
+
+void create() {
+  add_action( "sage", "sag", 1 );
+  add_action( "echo", "echo" );
+  add_action( "emote", "emote" );
+}
+
+int echo( string str ) {
+  say( str + "\n" );
+  return 1;
+}
+
+int sage( string str ) {
+  say( break_string(str, 78, capitalize(name(WER,2))+" sagt: "));
+  return 1;
+}
+
+int emote( string str ) {
+  say( capitalize(name(WER,2))+" "+str+"\n" );
+  return 1;
+}
+
+// zum ueberschreiben - DEPRECATED! USE ReceiveMsg()!
+public void catch_msg(mixed *arr, object obj) {}
+public void catch_tell(string str) {}
+
+// by default, the msg is delivered to catch_tell() for compatibility reasons
+// and otherwise ignored.
+public varargs int ReceiveMsg(string msg, int msg_typ, string msg_action,
+                              string msg_prefix, object origin)
+{
+  // compatibility...
+  if (msg_typ & MSG_DONT_WRAP)
+    catch_tell(sprintf("%s%s", msg_prefix||"", msg));
+  else
+    catch_tell(sprintf("%s%s\n", msg_prefix||"", msg));
+  return MSG_DELIVERED;
+}
+
diff --git a/std/npc/info.c b/std/npc/info.c
new file mode 100644
index 0000000..d66ee26
--- /dev/null
+++ b/std/npc/info.c
@@ -0,0 +1,345 @@
+// MorgenGrauen MUDlib
+//
+// npc/info.c -- Behandeln von Fragen an den NPC
+//
+// $Id: info.c 9522 2016-03-01 19:20:10Z Arathorn $
+
+/* Letzte Aenderungen von Wim 8.1.99
+ *
+ * AddInfo( schluessel, antwort [, indent [, [silent [, casebased] ] ] )
+ *  Wenn ein Spieler dieses Monster nach "schluessel" fragt, so gib die
+ *  Programmierte Antwort aus.
+ *  Erweiterung von Wim: ist silent gesetzt, so erfolgt eine "persoenliche"
+ *    Antwort. d.h. umstehende Personen bekommen bei silent==1 keinen, bei
+ *    stringp(silent), den String ausgegeben, dabei kann er auch die Schluessel-
+ *    Worte @WER @WESSEN @WEM @WEN enthalten.
+ *  - Ergaenzt um @CAP_WER... fuer zwangs-capitalisierte Namen an Satzanfaengen.
+ *    ist bei fragenden NPCs und PCs mit Tarnkappe wichtig! (Silvana)
+ *  - Auch in der Antwort des fragenden wird nun ersetzt (Vanion)
+ *  Enthaelt casedbased einen Funktionsnamen oder verweist auf eine closure, so
+ *    wird die Beantwortung der Frage von dem return-Wert abhaengig gemacht.
+ *    Bei 0 wird die Frage normal beantwortet, bei 1 erfolgt die Ausgabe des
+ *    unter DEFAULT_NOINFO gespeicherten Textes.
+ *    Wird ein String zurueckgegeben, so wird er unter Beachtung von ident an
+ *    Stelle der urspruenglichen Information ausgegeben.
+ *
+ * RemoveInfo( schluessel )
+ *  Das Monster antwortet nicht mehr auf diesen Schluessel.
+ *
+ * SetProp( P_DEFAULT_INFO, antwort [, indent ] )
+ *  Setze die Antwort, die das Monster auf unverstaendliche Fragen geben
+ *  soll. (Diese Funktion ist obsolet! Benutze stattdessen
+ *  AddInfo( "\ndefault info", antwort [, indent ] );
+ *
+ * GetInfo( [schluessel] )
+ *  Wenn Schluessel gesetzt ist, so wird die dazugehoerige Info,
+ *  ansonsten werden alle Infos zurueckgegeben.
+ *
+ * Die Antworten sollten wie emote - kommandos aussehen.
+ * Der optionale Indent wird zum Umbrechen von langen Infos benutzt.
+ * (Typischerweise sollte indent="sagt: " sein.)
+ *
+ * In den Infos darf mit process_string gearbeitet werden. Das Ergebnis von
+ * process_string wird dann mit umgebrochen!
+ *
+ *---------------------------------------------------------------------------
+ */
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <thing/description.h>
+#include <thing/properties.h>
+#include <npc.h>
+#undef NEED_PROTOTYPES
+
+#include <properties.h>
+#include <language.h>
+#include <defines.h>
+#include <config.h>
+#include <exploration.h>
+
+// TODO: langfristig waer hier private schoen.
+nosave mapping infos;
+
+protected void create()
+{
+    // Initialisierung nur wenn noetig, damit beim virtuellen Erben von
+    // /std/npc in npc1 und npc2 dann in npc3 beim npc1::create();
+    // npc2:create(); im zweiten create() die Infos nicht
+    // ueberschrieben/geloescht werden.
+    if (!mappingp(infos)) {
+        infos = ([
+            DEFAULT_INFO:"schaut Dich fragend an.\n";0;
+            "schaut @WEN fragend an.\n";0,
+            DEFAULT_NOINFO:"moechte Dir nicht antworten.\n";0;
+            "verweigert @WEM die Antwort.\n";1
+            ]);
+    }
+}
+
+
+void init() {
+  add_action( "frage", "frag", 1 );
+}
+
+
+static void smart_npc_log(string str)
+{
+  string creat, creat_det;
+
+  if (!stringp(creat=QueryProp(P_LOG_INFO))) {
+    creat = MASTER->creator_file(this_object());
+    if (creat == ROOTID)
+      creat = "ROOT";
+    else if( creat==BACKBONEID )
+      creat="STD";
+    creat_det="report/"+explode(creat, ".")[<1]+"_INFO.rep";
+    creat="report/"+explode(creat, ".")[<1]+".rep";
+  }
+  log_file(creat,
+           sprintf("INFO von %s [%s] (%s):\n%s\n",
+                   getuid(this_interactive()),
+                   explode(object_name(this_object()),"#")[0],
+                   strftime("%d. %b %Y"),
+                   str));
+  if (stringp(creat_det) && sizeof(creat_det))
+    log_file(creat_det,
+             sprintf("INFO von %s [%s] (%s):\n%s\n",
+                     getuid(this_interactive()),
+                     explode(object_name(this_object()),"#")[0],
+                     strftime("%d. %b %Y"),
+                     str));
+}
+
+public int frage(string str) {
+  string myname, text;
+
+  str=(extern_call()?this_player()->_unparsed_args():str);
+  if( !str || sscanf( str, "%s nach %s", myname, text ) != 2 ) {
+    _notify_fail( "WEN willst Du nach WAS fragen?\n" );
+    return 0;
+  }
+
+  if( !id( lower_case(myname) )
+    || QueryProp(P_INVIS) ) {
+    _notify_fail( "So jemanden findest Du hier nicht.\n" );
+    return 0;
+  }
+  say( capitalize(this_player()->name(WER))+" fragt " +
+    name(WEN,2)+" nach "+capitalize(text)+".\n",
+      this_player() );
+
+  text = lower_case(text);
+  GiveEP(EP_INFO, text);
+
+  return do_frage( text );
+}
+
+static string infoDefaultReplace(string pstring, object pl)
+{
+  pstring=" "+pstring;
+  if (strstr(pstring,"@WER",0) >-1 )
+    pstring= regreplace(pstring,"@WER",pl->name(WER,1),1);
+  if (strstr(pstring,"@WESSEN",0) >-1 )
+    pstring= regreplace(pstring,"@WESSEN",pl->name(WESSEN,1),1);
+  if (strstr(pstring,"@WEM",0) >-1 )
+    pstring= regreplace(pstring,"@WEM",pl->name(WEM,1),1);
+  if (strstr(pstring,"@WEN",0) >-1 )
+    pstring= regreplace(pstring,"@WEN",pl->name(WEN,1),1);
+  if (strstr(pstring,"@CAP_WER",0) >-1 )
+    pstring= regreplace(pstring,"@CAP_WER",pl->Name(WER,1),1);
+  if (strstr(pstring,"@CAP_WESSEN",0) >-1 )
+    pstring= regreplace(pstring,"@CAP_WESSEN",pl->Name(WESSEN,1),1);
+  if (strstr(pstring,"@CAP_WEM",0) >-1 )
+    pstring= regreplace(pstring,"@CAP_WEM",pl->Name(WEM,1),1);
+  if (strstr(pstring,"@CAP_WEN",0) >-1 )
+    pstring= regreplace(pstring,"@CAP_WEN",pl->Name(WEN,1),1);
+
+  return pstring[1..];
+}
+
+static mixed *GetInfoArr(string str)
+{  
+   return ({ infos[str, 0], infos[str, 1], infos[str,2], infos[str, 3] });
+}
+
+public int do_frage(string text)
+{
+  string indent,answer;
+  mixed silent, preinfo, noanswer;
+  mixed *info;
+
+  if (stringp(preinfo = QueryProp(P_PRE_INFO)))
+  {
+     // Die message action wird auf "frage" fixiert, damit dies immer das
+     // gleiche ist, egal, mit welchem Verb man in diese Funktion kommt.
+     this_player()->ReceiveMsg(preinfo, MT_LISTEN, "frage",
+                               Name(WER,2)+" ",this_object());
+     send_room(environment(this_object()),
+               "ist nicht gewillt, "+this_player()->Name(WEM,2)
+               +" zu antworten.",
+               MT_LISTEN, "frage",
+               Name(WER,2)+" ",
+               ({this_player()}) );
+     return 1;
+  }
+  else
+  {
+    if (intp(preinfo) && preinfo > 0)
+      return 1;
+  }
+
+  info=GetInfoArr(text);
+  if (!info[0])
+  {
+    if( this_interactive() && QueryProp(P_LOG_INFO) )
+      smart_npc_log(text);
+    text = DEFAULT_INFO;
+    info=GetInfoArr(text);
+  }
+
+  if (closurep(info[0]) ) {
+    answer=funcall(info[0]);
+    if( !answer || answer=="") return 1;
+  } else {
+    answer=process_string(info[0]);
+  }
+
+  if (closurep(info[3]) )
+   {
+    noanswer=funcall(info[3]);
+    if ( intp(noanswer) && noanswer > 0)
+     {
+       text = DEFAULT_NOINFO;
+       info = GetInfoArr(text);
+       if (closurep(info[0]) ) {
+         answer=funcall(info[0]);
+         if( !answer || answer=="") return 1;
+       } else {
+         answer=process_string(info[0]);
+       }
+     }
+    else if ( stringp(noanswer) )
+      answer = noanswer;
+   }
+
+  silent=info[2];
+
+  // Replacements gehen auch in der Antwort des NPC. Das gibt den Antworten 
+  // eine persoenliche Note, und so teuer is das auch nicht :)
+  answer = infoDefaultReplace(answer, this_player());
+
+  if( indent=info[1] )
+  {
+    if (stringp(silent) || (intp(silent) && silent > 0) )
+    {  // Persoenliche Antwort mit indent
+       this_player()->ReceiveMsg(answer, MT_LISTEN|MSG_BS_LEAVE_LFS,
+                                 "frage",
+                                 Name(WER,2)+" "+indent,
+                                 this_object());
+       if (stringp(silent))
+       {
+          silent=infoDefaultReplace(silent, this_player());
+          send_room(environment(), silent, MT_LISTEN, "frage",
+                    Name(WER,2)+" ", ({this_player()}));
+       }
+    }
+    else // "normale Antwort" mit Indent
+    {
+      send_room(environment(), answer, MT_LISTEN|MSG_BS_LEAVE_LFS,
+                "frage",
+                Name(WER,2)+" "+indent, ({this_object()}));
+    }
+  }
+  else
+  {
+    if (stringp(silent) || (intp(silent) && silent > 0) )
+    {  // Persoenliche Antwort ohne indent
+       this_player()->ReceiveMsg(answer, MT_LISTEN|MSG_DONT_WRAP,
+                                 "frage",
+                                 Name(WER,2)+" ",
+                                 this_object());
+       if (stringp(silent))
+       {
+          silent=infoDefaultReplace(silent, this_player());
+          send_room(environment(), silent, MT_LISTEN, "frage",
+                    Name(WER,2)+" ", ({this_player()}) );
+       }
+    }
+    else // "normale Antwort" ohne Indent
+      send_room(environment(), answer, MT_LISTEN|MSG_DONT_WRAP,
+                "frage", Name(WER,2)+" ");
+  }
+  return 1;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ * Setzen von Infos
+ *---------------------------------------------------------------------------
+ */
+
+public varargs void AddInfo(mixed key, mixed info, string indent, 
+                            mixed silent, mixed casebased ) {
+
+  if (stringp(casebased))
+    casebased=symbol_function(casebased,this_object());
+
+  if( pointerp( key ) ) {
+    int i;
+    for ( i=sizeof( key )-1; i>=0; i-- )
+      infos += ([ key[i]: info; indent; silent; casebased ]);
+  }
+  else
+    infos += ([ key: info; indent; silent; casebased ]);
+}
+
+public varargs void AddSpecialInfo(mixed keys, string functionname, 
+                      string indent, mixed silent, mixed casebased )
+{
+  int i;
+  closure cl;
+
+  if(!(cl=symbol_function(functionname,this_object()))) return;
+  return AddInfo(keys,cl,indent,silent,casebased);
+}
+
+
+public void RemoveInfo( string key )
+{
+  m_delete(infos,key);
+}
+
+static varargs void _set_default_info( mixed info )
+{
+  if (pointerp(info))
+    apply(#'AddInfo/*'*/,DEFAULT_INFO,info);
+  else
+    AddInfo(DEFAULT_INFO,info);
+}
+
+public varargs mixed GetInfo(string str)
+{
+  if (!str) return deep_copy(infos);
+  return infos[str];
+}
+
+
+static mapping _query_npc_info()
+{
+    return deep_copy(infos);
+}
+
+
+static mapping _set_npc_info( mapping map_ldfied )
+{
+    if ( !mappingp(map_ldfied) )
+        return 0;
+
+    return infos = map_ldfied;
+}
+
diff --git a/std/npc/items.c b/std/npc/items.c
new file mode 100644
index 0000000..f0260cf
--- /dev/null
+++ b/std/npc/items.c
@@ -0,0 +1,240 @@
+// MorgenGrauen MUDlib
+//
+// /std/npc/items.c -- Item-Verwaltung fuer NPCs
+//
+// $Id: items.c 8146 2012-10-30 18:18:14Z Zesstra $
+//
+// (c) by Padreic (Padreic@mg.mud.de)
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <thing/properties.h>
+#include <thing/description.h>
+#include <living/combat.h>
+#undef NEED_PROTOTYPES
+#include <npc.h>
+#include <properties.h>
+#include <combat.h>
+#include <config.h>
+#include <moving.h>
+#include <sys_debug.h>
+
+protected void create()
+{
+  // dieses flag ist nur bis zum ersten move gesetzt. Nimmt danach also auch
+   Set(NPC_NEEDS_ITEM_INIT, 1);  // keinen Speicher mehr in Anspruch.
+   // Set(P_ITEMS, ({})); // keine initialisierung spart Speicher  
+}
+
+protected void create_super() {
+      set_next_reset(-1);
+}
+
+protected object* maybe_own_stuff() {
+  object* obs = all_inventory(environment());
+  object haufen = present("\nhaufen "+name(WEM),environment());
+  if( objectp(haufen) ) obs += all_inventory(haufen);
+  object leiche = present("\nleiche "+name(WEM),environment());
+  if( objectp(leiche) ) obs += all_inventory(leiche);
+  return obs;
+}
+
+// clont alle Objekte die geclont werden muessen...
+protected void _clone_items()
+{
+  int i, j, mode, refresh;
+  object ob, *inv1;
+  mixed  props, *items;
+  string file, *inv2;
+
+  if (!pointerp(items=QueryProp(P_ITEMS))) return;
+  if (environment()) { // Liste mit filenamen (inv2) erstellen.
+    inv1 = maybe_own_stuff();
+    inv2 = map(inv1, #'load_name);
+  }
+  else inv2=({}); // inv1 wird gar nicht mehr benoetigt
+
+  for (i=sizeof(items)-1; i>=0; i--) {
+    ob = items[i][RITEM_OBJECT];
+    file = items[i][RITEM_FILE];
+    mode = items[i][RITEM_REFRESH];
+    refresh = mode & 0x0000ffff;
+    props = items[i][RITEM_PROPS];
+    if (props && intp(props)) { // unique Gegenstand?
+      ob=find_object(file);
+      if (ob) {
+        // kann ob aufgenommen werden? Wenn das Objekt in inv1 drin ist, ist es
+        // im Env oder in einer Leiche oder einem Haufen.
+        if (member(inv1,ob) > -1) {
+          if (environment()) {
+            if (environment(ob) == environment())
+              tell_room(environment(),
+                  capitalize(name(WER))+" hebt "+ob->name(WEN)+" auf.\n");
+            else
+              tell_room(environment(),break_string(
+                  capitalize(name(WER))+" nimmt "+ob->name(WEN)+ " aus "
+                  +environment(ob)->name(WEM) + ".",78));
+          }
+          ob->remove();  // zerstoeren und neuladen.
+          if (ob) destruct(ob);
+          if (catch(ob=load_object(file);publish))             
+              raise_error(sprintf(
+                "_clone_items(): %O does not exist or is not loadable\n", file)); 
+          ob->move(this_object(), M_NOCHECK);
+          items[i][RITEM_OBJECT]=ob;
+        }
+        else switch( refresh ) {
+          case REFRESH_DESTRUCT:
+            if (environment(ob)) {
+              ob=0; // nicht zuecken, tragen, initialisieren...
+              break;
+            }
+          case REFRESH_ALWAYS:
+          case REFRESH_REMOVE:                
+            ob->remove();
+            if (ob) destruct(ob);
+            if (catch(ob=load_object(file);publish)) 
+                raise_error(sprintf("_clone_items(): "
+                      "%O does not exist or is not loadable\n", file));
+            ob->move(this_object(), M_NOCHECK);
+            items[i][RITEM_OBJECT]=ob;
+            break;
+          case REFRESH_NONE:
+          default: ob=0; // nicht zuecken, tragen, initialisieren...
+        }
+      }
+      else {
+        if (catch(ob=load_object(file);publish)) raise_error(sprintf(
+          "_clone_items(): %O does not exist or is not loadable\n", file));
+        if (objectp(ob)) ob->move(this_object(), M_NOCHECK);
+        items[i][RITEM_OBJECT]=ob;
+      }
+    } // if (props ...) // also nicht unique
+    else {
+      switch( refresh ) {
+        case REFRESH_DESTRUCT: // erfuellt auch REFRESH_REMOVE Bedingung...
+          if (ob) {
+            ob=0; // nicht zuecken, tragen, initialisieren...
+            break;
+          }
+        case REFRESH_REMOVE:
+          if (ob) {
+            if(present(ob, this_object())) {
+              ob=0; // nicht zuecken, tragen, initialisieren...
+              break;
+            }
+            else {
+              if ((member(inv2, file))==-1) {  
+                ob=0;
+              }
+            }
+          }
+        case REFRESH_NONE: // wird entfernt nach dem ersten clonen!!!
+        case REFRESH_ALWAYS:
+          // schauen ob der Gegenstand im environment liegt.
+          if ((j=member(inv2, file))!=-1) {
+            ob=inv1[j]; // inv1 kann leer sein, aber dann ist inv2 auch leer
+            inv1[j]=0; // wichtig falls mehrere gleiche AddItems
+            inv2[j]=0; // = 0 setzen um Array kopieren zu vermeiden
+            if (environment()) {
+              if (environment() == environment(ob))
+                tell_room(environment(),
+                    capitalize(name(WER))+" hebt "+ob->name(WEN)+" auf.\n");
+              else
+                tell_room(environment(),break_string(
+                    capitalize(name(WER))+" nimmt "+ob->name(WEN)+" aus "
+                    +environment(ob)->name(WEM) + ".",78));
+            }
+          }
+          if (ob) {
+            ob->remove();
+            if (ob) destruct(ob);
+          }
+          if (catch(ob=clone_object(file);publish)) raise_error(sprintf(
+            "_clone_items(): %O does not exist or is not loadable\n", file));
+          ob->move(this_object(), M_NOCHECK);
+          switch( refresh ) {
+          case REFRESH_NONE:
+            items[i] = 0; // Speicher freimachen
+            break;
+          case REFRESH_ALWAYS:
+            items[i][RITEM_OBJECT] = 0; // Objekt "vergessen"
+            break;
+          default:
+            items[i][RITEM_OBJECT] = ob;
+          }
+          break;
+        default: ob=0; // nicht zuecken, tragen, initialisieren...
+      }
+    } // if (props ...) else 
+    if (ob) {
+      if (mappingp(props)) walk_mapping(props, symbol_function("SetProp", ob));
+      // Eigentlich will man hier sowas wie command("zuecke schwert")
+      // machen, aber das handling der id's kann nicht sicherstellen,
+      // dass der NPC die richtige Waffe erwischt, deshalb machen wir
+      // das tragen hier von Hand.
+      if (mode & CLONE_WEAR) {
+        if( mode & CLONE_NO_CHECK ) {
+          object *armours;
+          ob->DoUnwear(); // evtl. dem Vorgaenger abnehmen.
+          UseHands(ob, ob->QueryProp(P_NR_HANDS));
+          armours=QueryProp(P_ARMOURS)+({ ob });
+          SetProp(P_ARMOURS, armours);
+          SetProp(P_TOTAL_AC, QueryProp(P_TOTAL_AC)+ob->QueryProp(P_AC));
+          ob->SetProp(P_WORN, this_object());
+        } else {
+          command( "trage \n"+object_name(ob) );
+        }
+      }
+      if (mode & CLONE_WIELD) {
+        if( mode & CLONE_NO_CHECK ) {
+          ob->DoUnwield(); // evtl. dem Vorgaenger abnehmen. 
+          UseHands(ob, ob->QueryProp(P_NR_HANDS));
+          SetProp(P_WEAPON, ob);
+          SetProp(P_TOTAL_WC, ob->QueryProp(P_WC));
+          ob->SetProp(P_WIELDED, this_object());
+        } else {
+          command( "zuecke \n"+object_name(ob) );
+        }
+      }
+    } // if (ob) 
+  } // for i
+  items-=({ 0 }); // REFRESH_NONEs von nicht unique Objekten 
+  if (!sizeof(items)) items=0; // Speicher sparen...
+  SetProp(P_ITEMS, items);
+  Set(NPC_NEEDS_ITEM_INIT, 0);
+}
+
+public varargs object AddItem(mixed filename, int refresh, mixed props)
+{
+  // Aus Array ein Element auswaehlen
+  if (pointerp(filename)) 
+    filename = filename[random(sizeof(filename))];
+ 
+  // Kein String? -> Fehler
+  if (!stringp(filename)){
+    raise_error("AddItem: filename or array of filenames expected.\n"); 
+  } else {
+    // Pfad normieren und eventuell vorhandenes ".c" entfernen
+    filename = MASTER->_get_path(
+                  filename[<2..]==".c"?filename=filename[0..<3]
+                                        : filename,"?"); 
+    // Property setzen
+    SetProp(P_ITEMS, (QueryProp(P_ITEMS)||({}))+
+                     ({ ({ 0, filename, refresh, props }) }));
+
+  if (environment()) _clone_items();
+  }
+  return 0;
+}
+
+void reset()
+// fuer REFRESH_ Objekte...
+{
+  _clone_items();
+}
+
diff --git a/std/npc/moving.c b/std/npc/moving.c
new file mode 100644
index 0000000..f06e0da
--- /dev/null
+++ b/std/npc/moving.c
@@ -0,0 +1,39 @@
+// MorgenGrauen MUDlib
+//
+// living/moving.c -- moving of living objects
+//
+// $Id$
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+inherit "/std/living/moving";
+
+#include <hook.h>
+#define NEED_PROTOTYPES
+#include <moving.h>
+
+//<int|<string|closure>* >* GuardExit(object room, int hookid,
+//                                    <string|closure>* hdata)
+//{
+//}
+
+protected int _reg_exit_hook(object dest, object oldenv)
+{
+  closure cl = symbol_function("GuardExit", this_object());
+  if (cl)
+  {
+    if (oldenv)
+      oldenv->HUnregisterFromHook(H_HOOK_EXIT_USE, cl);
+    return dest->HRegisterModifier(H_HOOK_EXIT_USE, cl);
+  }
+  return 0;
+}
+// Krams nach dem Move machen und nebenbei zum Ueberschreiben.
+protected void NotifyMove(object dest, object oldenv, int method)
+{
+  _reg_exit_hook(dest, oldenv);
+  return ::NotifyMove(dest, oldenv, method);
+}
diff --git a/std/npc/put_and_get.c b/std/npc/put_and_get.c
new file mode 100644
index 0000000..8b72cf4
--- /dev/null
+++ b/std/npc/put_and_get.c
@@ -0,0 +1,36 @@
+// MorgenGrauen MUDlib
+//
+// npc/put_and_get.c.c -- Geben und nehmen fuer NPCs
+//
+// $Id: put_and_get.c 6371 2007-07-17 22:46:50Z Zesstra $
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+inherit "std/living/put_and_get";
+#include <moving.h>
+#include <properties.h>
+
+void give_notify( object obj )
+{
+   mixed* msg;
+   if (pointerp(msg=QueryProp(P_REJECT))) {
+      switch(msg[0]) {
+         case REJECT_GIVE:
+            say(msg[1]);
+            give_obj( obj, this_player() );
+            break;
+         case REJECT_LIGHT_MODIFIER:
+            if (obj->QueryProp(P_LIGHT_MODIFIER) ||
+                obj->QueryProp(P_LIGHT)) break;
+         case REJECT_DROP:
+            say(msg[1]);
+            drop_obj( obj );
+            break;
+         case REJECT_KEEP:
+         default: say(msg[1]); /* keep it */
+    }
+  }
+}
diff --git a/std/npc/sequencer.c b/std/npc/sequencer.c
new file mode 100644
index 0000000..50c85e3
--- /dev/null
+++ b/std/npc/sequencer.c
@@ -0,0 +1,125 @@
+// MorgenGrauen MUDlib
+//
+// npc/sequencer.c -- Scripte und Trigger fuer NPCs :)
+//
+// $Id: sequencer.c 7526 2010-04-02 00:01:26Z Arathorn $
+
+// seq2.c
+// Version 2.0 des Sequencers von Don Rumata 28.06.93
+// 
+// Sinn:
+//   Bereitstellung von Funktionen, ddamit ein npc mehrere Befehle
+//   bei Eintritt eines bestimmten Ereignisses nacheinander
+//   automatisch durchfuehrt.
+//
+// Ereignisse:
+//   TellEvent: Es wird etwas in dem Raum, in dem der npc sich
+//              befindet, gesagt.
+//   GiveEvent: Es wird dem npc etwas gegeben.
+//
+// Programm:
+//   Ein Programm ist eine Liste von Befehlen.
+//   Jeder Befehl ist eine Liste, bestehend aus einem Kommando
+//   und einer Zahl.
+//   Das Kommendo wird aehnlich der Befehle, die ein Spieler ein-
+//   gibt ausgefuehrt.
+//   Vorsicht: NPCs koennen nur einen Teil der Befehle, die ein
+//   Spieler kann, dafuer aber immer 'echo' und 'emote'.
+//   Die Zahl gibt die Anzahl der Sekunden an, in der der naechste
+//   Befehl ausgefuehrt wird.
+//
+// Funktionen:
+//   RegisterTell( funktion, programm )
+//     Wenn dem npc etwas gesagt wird, so wird die gesagte Meldung
+//     an die Funktion uebergeben. Gibt die Funktionen nicht 0
+//     zurueck, wird das Programm gestartet.
+//   RegisterGive( funktion, programm )
+//     Wird dem npc etwas gegeben, so wird das Objekt an die
+//     Funktion uebergeben. Gibt die Funktion nicht 0 zurueck, so
+//     wird das Programm gestartet.
+//   Load( programm )
+//     Starte das angegebene Programm.
+//
+//   give_notify() gibt eine 1 zurueck, wenn das Objekt akzeptiert
+//     wurde. (Es muss - falls gewuenscht - dann von Hand zuruech-
+//     gegeben werden. (give_obj(ob,this_player())) in der Funk.)
+//   mittels add_action() kann man im create() ds NPCs eigene
+//     Verben fuer den NPC einfuehren.
+//
+// Es kann immer nur eine Funktion (egal ob Tell oder Give) angemeldet
+// sein. Es kann immer nur ein Programm gleichzeitig laufen.
+//
+// Ideen und Bugreports an Rumata
+
+string givefun, tellfun;
+mixed *program;
+int isRunning;
+
+// zur sicherheit nicht von aussen aufrufbar !!!!
+static string RegisterGive( string fun, mixed prog )
+{
+  if( isRunning ) return 0;
+  program = prog;
+  tellfun = 0;
+  return givefun = fun;
+}
+
+// zur sicherheit nicht von aussen aufrufbar !!!!
+static string RegisterTell( string fun, mixed prog )
+{
+  if( isRunning ) return 0;
+  program = prog;
+  givefun = 0;
+  return tellfun = fun;
+}
+
+// zur sicherheit nicht von aussen aufrufbar !!!!
+static void Start()
+{
+  if( isRunning || !objectp(this_object())) return;
+  isRunning = 1;
+  call_out( "nextStep", 0, 0 );
+}
+
+static void Load( mixed prog )
+{
+  if( isRunning ) return;
+  program = prog;
+  Start();
+}
+
+public void catch_tell( string str )
+{
+  if( isRunning || previous_object()==this_object()) return;
+  if( stringp(tellfun) && call_other( this_object(), tellfun, str ) )
+    Start();
+}
+
+int give_notify( object ob )
+{
+  if( isRunning ) return 0;
+  if( stringp(givefun) && call_other( this_object(), givefun, ob ) )
+  {
+    Start();
+    return 1;
+  }
+  return 0;
+}
+
+static void nextStep( int line )
+{
+  if( !isRunning ) return;
+  if( line >= sizeof( program ) )
+  {
+    isRunning = 0;
+    return;
+  }
+  command( process_string( program[line][0] ) );
+  if( !isRunning || !objectp(this_object()) ) return;
+  call_out( "nextStep", program[line][1], line+1 );
+}
+
+mixed QueryProg()
+{
+  return program[0..];
+}