Added public files
Roughly added all public files. Probably missed some, though.
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;
+}
+