Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/d/seher/haeuser/modules/usercmd.c b/d/seher/haeuser/modules/usercmd.c
new file mode 100644
index 0000000..a83b819
--- /dev/null
+++ b/d/seher/haeuser/modules/usercmd.c
@@ -0,0 +1,341 @@
+// usercmd.c -- Modul fuer benutzerdefinierte Befehle
+//
+// (c) 1995 Wargon@MorgenGrauen
+//
+// $Id: usercmd.c,v 1.4 2003/11/15 13:48:46 mud Exp $
+//
+
+#define NEED_PROTOTYPES
+#include "../haus.h"
+#include <properties.h>
+#include <wizlevels.h>
+#include <thing/properties.h>
+
+private string ucFilter(string str);
+private string ucText(string str);
+private void splitCmd(string *cmd, string *verb, string *para);
+
+create()
+{
+ Set(H_COMMANDS, SAVE, F_MODE);
+ Set(H_COMMANDS, ([]));
+
+ AddCmd("", "userCommands", 1);
+}
+
+/*
+ * AddUserCmd: eigenes Kommando hinzufuegen
+ * cmd: String oder Array von Strings. Enthaelt entweder nur die Verben oder
+ * die kompletten Befehle (Verb + Parameter). Siehe auch pa.
+ * pa: Zahl oder Array von Strings. Falls pa eine Zahl ist, so enthaelt cmd
+ * die kompletten Befehle (samt Parametern). Ansonsten enthaelt pa die
+ * Parameter fuer das entsprechende Verb in cmd.
+ * Ist pa = ({ "@NF@"}) , so handelt es sich um ein notify_fail, das an
+ * die Beschreibung des Verbs (falls vorhanden) angehaengt wird.
+ * me: Text fuer den Ausfuehrenden. Der Text muss schon geparsed worden
+ * sein!
+ * oth: Text fuer die Umstehenden oder 0. Der Text muss schon geparsed wor-
+ * den sein!
+ */
+varargs void
+AddUserCmd(mixed cmd, mixed pa, string me, string oth)
+{
+ int v,p;
+ mapping cmds, desc;
+ string *verb, *para, txt;
+
+ cmds = Query(H_COMMANDS);
+ if (stringp(cmd))
+ verb = ({ cmd });
+ else
+ verb = cmd;
+
+ if (intp(pa))
+ splitCmd(verb[0..], &verb, ¶);
+ else {
+ if (stringp(pa))
+ para = ({ pa });
+ else if (pointerp(pa))
+ para = pa;
+ for (desc = ([]), p=sizeof(para)-1; p>=0; p--)
+ desc += ([ para[p] : me; oth ]);
+ }
+
+ for (v = sizeof(verb)-1; v>= 0; v--) {
+ if (member(cmds, verb[v])) {
+ if (intp(pa))
+ cmds[verb[v]] += ([para[v] : me; oth ]);
+ else
+ cmds[verb[v]] += desc;
+ }
+ else {
+ if (intp(pa))
+ cmds += ([ verb[v] : ([para[v] : me; oth ]) ]);
+ else
+ cmds += ([ verb[v] : desc ]);
+ }
+ }
+ Set(H_COMMANDS, cmds);
+}
+
+/*
+ * RemUserCmd: Kommando(s) wieder entfernen
+ * com: String oder Array von Strings. Enthaelt das zu loeschende Kommando
+ * (Verb oder Verb + Parameter).
+ * all: Falls != 0, so werden die Verben aus com komplett mit allen Para-
+ * metern geloescht.
+ */
+varargs void
+RemUserCmd(mixed com, int all)
+{
+ mapping cmd, tmp;
+ string *verb, *para;
+ int v, p;
+
+ cmd = Query(H_COMMANDS);
+ splitCmd(stringp(com) ? ({com}) : com, &verb, ¶);
+
+ if (all)
+ for (v=sizeof(verb)-1; v>=0; v--)
+ cmd = m_copy_delete(cmd, verb[v]);
+ else {
+ for (v=sizeof(verb)-1; v>=0; v--) {
+ if (tmp = cmd[verb[v]]) {
+ for (p=sizeof(para)-1; p>=0; p--)
+ tmp = m_copy_delete(tmp, para[p]);
+ cmd[verb[v]] = tmp;
+ }
+ }
+ }
+ Set(H_COMMANDS,cmd);
+}
+
+/*
+ * userCommands: Auswertung der benutzerdefinierten Befehle.
+ */
+static int
+userCommands(string str)
+{
+ mapping ucmd, uparm;
+ string *parts, text;
+ int i;
+
+ ucmd = QueryProp(H_COMMANDS);
+ str = this_player()->_unparsed_args(1)||"";
+ if (uparm = ucmd[query_verb()]) {
+ if (member(uparm, str)) {
+ text = ucText(uparm[str,0]);
+ if (sizeof(old_explode(text, "\n")) >= this_player()->QueryProp(P_SCREENSIZE))
+ this_player()->More(capitalize(text)[0..<2]);
+ else
+ write(capitalize(text));
+
+ if (uparm[str,1])
+ say(ucText(uparm[str,1]));
+
+ if (member(m_indices(QueryProp(P_EXITS)), query_verb()) == -1)
+ return 1;
+ }
+ else {
+ if (str && str != "" && text = uparm["@NF@"])
+ notify_fail(implode(old_explode(text,"@F"),str));
+ }
+ }
+ return 0;
+}
+
+/*** Functions private to this module... ***/
+
+/*
+ * ucFilter: Ersetzen von Name, Personal- und Possessivpronomen.
+ * Gibt den ersetzten String zurueck.
+ */
+private string
+ucFilter(string str)
+{
+ int p,g;
+
+ switch(str[0..1]) {
+ case "@W": // Name in entsprechendem Fall...
+ return this_player()->name(to_int(str[2..2]));
+ case "@P": // Personalpronomen in entprechendem Fall...
+ return this_player()->QueryPronoun(to_int(str[2..2]));
+ case "@B": // Possesivpronomen in entprechendem Fall...
+ p = to_int(str[4..4]);
+ g = to_int(str[3..3]);
+ return this_player()->QueryPossPronoun(g, to_int(str[2..2]), p);
+ }
+ return str;
+}
+
+/*
+ * ucText: Rassen- und geschlechtsspezifische Teile bearbeiten sowie
+ * Namen und Pronomina einsetzen.
+ *
+ * str enthaelt den String, der beim Beschreiben des Befehls
+ * eingegeben wurde. Bis auf den Default-Text sind alle Teile
+ * optional. Der String kann folgenden Aufbau haben:
+ * ------ schnipp ------
+ * Default-Text, der ausgegeben wird, wenn die folgenden spezielleren
+ * Texte nicht auftreten oder auf den Ausfuehrenden nicht zutreffen
+ * @NAME:nameA
+ * Text, der ausgegeben wird, wenn der Spieler "nameA" das Kommando
+ * eingegeben hat
+ * @NAME:nameB
+ * Und so weiter fuer Spieler "nameB" etc...
+ * @RA
+ * Text, der ausgegeben wird, wenn der Ausfuehrende auf der Erlaube-
+ * Liste des Hauses steht.
+ * @RE
+ * Text, der ausgegeben wird, wenn der Ausfuehrende ein Elf
+ * ist. Ebenso gibt es @RD fuer Dunkelelfen, @RF fuer Felinen,
+ * @RH fuer Hobbits, @RM fuer Menschen, @RG fuer Goblins und @RZ
+ * fuer Zwerge.
+ * ------ schnapp ------
+ *
+ * Der Default-Text muss immer am Anfang stehen. Die anderen Bloecke
+ * koennen in beliebiger Reihenfolge folgen. Die Reihenfolge, in der
+ * die Bloecke betrachtet werden, ist dabei folgende:
+ * - zuerst werden @NAME-Bloecke untersucht
+ * - dann wird @RA (Erlaube-Liste) getestet
+ * - danach wird die Rasse ueberprueft (@RD/@RE/@RF/@RH/@RM/@RZ/@RG)
+ * - zuletzt wird der Default-Text betrachtet
+ *
+ * Innerhalb jedes der Bloecke kann man noch mit @G zwischen
+ * maennlichen und weiblichen Vertretern unterscheiden (bei @NAME:
+ * macht das aber wenig Sinn). Beispiel:
+ * ------ schnipp ------
+ * @RZ
+ * Der Zwerg war maennlich
+ * @G
+ * Der Zwerg war weiblich
+ * ------ schnapp ------
+ *
+ * Die Funktion gibt den fuer den Ausfuehrenden zutreffenden Text
+ * zurueck.
+ */
+private string
+ucText(string str)
+{
+ string *parts, *names, *lnames;
+ int i, n;
+
+ // Text nach Namen- und Rassentrennern aufteilen
+ parts = regexplode(str, "(@NAME:[A-Za-z1-9]*\n)|(@R[A-Z]\n)");
+ i = -1;
+
+ if (sizeof(parts) > 1) {
+
+ // Zuerst wird nach Namenstrennern gesucht
+ names = regexp(parts, "@NAME:");
+
+ if (sizeof(names) > 0) {
+ // ein kleiner Umweg, da der Name im Eingabestring nicht
+ // notwendigerweise in Kleinbuchstaben vorliegt.
+ lnames = map(names, #'lower_case);
+ n = member(lnames, "@name:"+getuid(this_player())+"\n");
+
+ if (n >= 0) {
+ i = member(parts, names[n]);
+ }
+ }
+
+ // Kein passender Namenstrenner gefunden: Erlaube-Liste
+ // ueberpruefen
+ if (i<0 && allowed_check(this_player())) {
+ i=member(parts, "@RA\n");
+ }
+
+ // Weder Namenstrenner noch Erlaube-Liste passen: Rasse
+ // ueberpruefen
+ if (i<0) {
+ switch(this_player()->QueryProp(P_RACE)) {
+ case "Zwerg":
+ i=member(parts, "@RZ\n");
+ break;
+ case "Elf":
+ i=member(parts, "@RE\n");
+ break;
+ case "Feline":
+ i=member(parts, "@RF\n");
+ break;
+ case "Hobbit":
+ i = member(parts, "@RH\n");
+ break;
+ case "Dunkelelf":
+ i = member(parts, "@RD\n");
+ break;
+ case "Goblin":
+ i = member(parts, "@RG\n");
+ break;
+ case "Ork":
+ i = member(parts, "@RO\n");
+ break;
+ default:
+ i=member(parts, "@RM\n");
+ break;
+ }
+ }
+
+ // Den richtigen Teil des Strings herauspicken
+ if (i>-1)
+ str = parts[i+1];
+ else
+ str = parts[0];
+ }
+ if (sizeof(parts = old_explode(str, "@G\n"))==2)
+ str = parts[(this_player()->QueryProp(P_GENDER) == MALE ? 0 : 1)];
+
+ parts = regexplode(str, "(@W[0-3]|@P[0-3]|@B[0-3][0-2][0-1])");
+ parts = map(parts, #'ucFilter);
+ return implode(parts, "");
+}
+
+/*
+ * splitCmd: Komplettes Kommando in Arrays von Verben und Parametern zerlegen.
+ * cmd: Array von Strings. Dieses Array enthaelt die aufzuspaltenden Befehle.
+ * verb: Referenz auf ein Array von Strings fuer die Verben.
+ * para: Referenz auf ein Array von Strings fuer die Parameter.
+ */
+private void splitCmd(string *cmd, string *verb, string *para)
+{
+ int c, sp;
+
+ for (verb = ({}), para = ({}), c = sizeof(cmd)-1; c>=0; c--) {
+ if ((sp=member(cmd[c], ' ')) >= 0) {
+ verb += ({ cmd[c][0..sp-1] });
+ para += ({ cmd[c][sp+1..] });
+ }
+ else {
+ verb += ({ cmd[c] });
+ para += ({ "" });
+ }
+ }
+}
+
+// $Log: usercmd.c,v $
+// Revision 1.4 2003/11/15 13:48:46 mud
+// @RD als Trenner fuer Dunkelelfen
+//
+// Revision 1.3 2000/12/03 17:15:40 mud
+// ucText: Neuer Trenner @NAME:foo, mit dem man in Seherhausbefehlen
+// Texte fuer bestimmte Spieler vorsehen kann.
+//
+// Revision 1.2 2000/08/20 20:38:40 mud
+// @RF als Trenner fuer Felinen
+//
+// Revision 1.1.1.1 2000/08/20 20:22:42 mud
+// Ins CVS eingecheckt
+//
+// Revision 1.4 1996/04/19 23:10:52 Wargon
+// @RA fuer Leute mit Erlaubnis
+//
+// Revision 1.3 1995/10/31 12:59:52 Wargon
+// @RH fuer Hobbits
+//
+// Revision 1.2 1995/06/22 19:48:31 Wargon
+// Bugfix in userCommands()
+//
+// Revision 1.1 1995/04/21 09:22:50 Wargon
+// Initial revision
+//