Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/std/living/put_and_get.c b/std/living/put_and_get.c
new file mode 100644
index 0000000..4e1a97f
--- /dev/null
+++ b/std/living/put_and_get.c
@@ -0,0 +1,1243 @@
+// MorgenGrauen MUDlib
+//
+// living/put_and_get.c -- taking and putting things
+//
+// $Id: put_and_get.c 8755 2014-04-26 13:13:40Z Zesstra $
+
+/*
+ Grundlegend neu strukturiert von Amynthor im April-Juni 2007
+
+Die eigentlichen Funktionen:
+
+ private string put_or_get(object o, object dest)
+ Bewegt ein einzelnes Objekt mit automatisch bestimmter Method. Gibt im
+ Erfolgsfall 0 zurueck, sonst die auszugebende Fehlermeldung.
+
+ varargs int drop(object o, mixed msg)
+ varargs int put(object o, object dest, mixed msg)
+ varargs int pick(object o, mixed msg)
+ varargs int give(object o, object dest, mixed msg)
+ varargs int show(object o, object dest, mixed msg)
+ Der Spieler nimmt/legt/gibt/zeigt/laesst ein Objekt fallen, wobei die
+ entsprechenden oder optional abweichende (im Format von P_XXX_MSG) oder
+ gar keine (msg == 1) Meldungen ausgegeben werden. Es liegt in der
+ Verantwortung des Rufenden, sinnvolle Werte zu uebergeben; insbesondere
+ wird nicht geprueft, ob sich die Objekte in der Reichweite des Spielers
+ befinden. Gibt 1 zurueck, wenn das Objekt bewegt wurde, sonst 0.
+
+Hilfsfunktionen:
+
+ private object *__find_objects(string *tokens, object env, int is_source)
+ object *find_objects(string what, object env, int is_source)
+ Sucht im Raum und im Spieler (oder alternativ in der angegebenen Umgebung)
+ nach den in tokens/what bezeichneten Objekten. is_source bestimmt die
+ erwartete grammatische Form (0 fuer "topf auf herd" und 1 fuer "topf von
+ herd", siehe Manpage).
+
+ varargs int drop_objects(string str, mixed msg)
+ varargs int put_objects(string str, int casus, string verb, mixed msg)
+ varargs int pick_objects(string str, mixed msg, int flag)
+ varargs int give_objects(string str, mixed msg)
+ varargs int show_objects(string str, mixed msg)
+ Ein Befehl wie "wirf waffen weg" resultiert in einem Aufruf von
+ drop_objects("waffen"). Diese Funktionen sind hauptsaechlich fuer die
+ Behandlung der jeweiligen Kommandos vorgesehen, koennen jedoch auch fuer
+ eigene Befehle verwendet werden. put_objects() erwartet ausserdem den
+ Kasus ("Du kannst nichts an DER Pinwand befestigen.") und das verwendete
+ Verb in der Gundform ("befestigen"). Das Flag fuer pick_objects() gibt
+ an, ob das Objekt auch einfach herumliegen darf ("nimm ...") oder nicht
+ ("hole ..."). Gibt bei Erfolg 1, sonst 0 zurueck.
+
+ object *moved_objects()
+ object moved_where()
+ Gibt die eben fallengelassenen/gesteckten/... Objekte zurueck und wohin
+ sie gesteckt/wem sie gegeben/gezeigt wurden. Fuer den Fall, dass man
+ anschliessend noch etwas mit ihnen machen moechte.
+
+Die einzelnen Kommandos:
+ static int fallenlassen(string str)
+ static int werfen(string str)
+ static int legen(string str)
+ static int stecken(string str)
+ static int holen(string str)
+ static int nehmen(string str)
+ static int geben(string str)
+ Minimale Wrapper fuer XXX_objects(), entfernen "fallen", "weg" bzw. "ab"
+ aus den Argumenten und setzen entsprechende Standard-Fehlermeldungen.
+
+ protected void add_put_and_get_commands()
+ Registriert obige Funktionen per add_action().
+
+Aus reinen Kompatibilitaetsgruenden weiterhin enthalten:
+
+ object* find_obs(string str, int meth)
+ int pick_obj(object ob)
+ int drop_obj(object ob)
+ int put_obj(object ob, object where)
+ int give_obj(object ob, object where)
+ siehe Manpages
+
+*/
+
+/*
+ 21. Okt 1998 komplette neu programmierung von put_and_get.c (Padreic)
+- die Gruppenauswahlen alles, waffen und ruestungen sind jetzt immer moeglich
+ die Gruppen sind sehr leicht erweiterbar und man sollte sich nicht scheuen
+ davon gebrauch zu machen...
+- mit "in mir" und "im raum" kann man den abzusuchenden Raum selbst eingrenzen
+- mit "alle|jede|jeden|jedes <id>" kann man auch ganze objektgruppen auswaehlen
+*/
+
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <language.h>
+#include <thing/description.h>
+#include <thing/properties.h>
+#include <moving.h>
+#include <container.h>
+#undef NEED_PROTOTYPES
+
+#include <defines.h>
+#include <properties.h>
+#include <wizlevels.h>
+
+#define TME(str) tell_object(this_object(), \
+ break_string(str, 78, 0, BS_LEAVE_MY_LFS))
+#define TOB(ob,str) tell_object(ob, break_string(str, 78, 0, BS_LEAVE_MY_LFS))
+#define SAY(str) tell_room(environment(), \
+ break_string(str, 78, 0, BS_LEAVE_MY_LFS), ({this_object()}))
+#define SAY2(obs, str) tell_room(environment(), \
+ break_string(str, 78, 0, BS_LEAVE_MY_LFS), ({this_object()}) + obs)
+#define NF(str) _notify_fail(break_string(str, 78, 0, BS_LEAVE_MY_LFS))
+
+private nosave closure cl;
+private nosave string wen0, wen1, wer0;
+private nosave object *last_moved_objects;
+private nosave object last_moved_where;
+
+
+/*********************** Die eigentlichen Funktionen ************************/
+
+private string put_or_get(object o, object dest)
+
+/* Bewegt ein einzelnes Objekt <o> in das Zielobjekt <dest>. Verwendet dazu
+ * je nach Umstaenden (Ziel ist der Spieler, die Umgebung, ein Lebewesen) den
+ * entsprechenden Wert fuer <method>. Gibt im Erfolgsfall 0 zurueck, erstellt
+ * sonst die auszugebende Fehlermeldung und gibt diese zurueck.
+ */
+
+{
+ int method, ret;
+ string str;
+
+ //if (living(o))
+ // raise_error(sprintf("Lebendes Argument fuer put_or_get: %O\n", o));
+
+ if (dest == this_object()) /* pick */
+ method = M_GET;
+ else if (dest == environment()) /* drop */
+ method = M_PUT;
+ else if (living(dest)) /* give */
+ method = M_GIVE;
+ else { /* put */
+ method = M_PUT | M_GET;
+ if (first_inventory(o))
+ return o->Name(WER, 1) + " ist nicht leer!";
+ }
+
+ if ((ret = o->move(dest, method)) > 0)
+ return 0;
+
+ switch (ret) {
+ case ME_TOO_HEAVY:
+ if (dest == this_object())
+ if (QueryProp(P_GHOST))
+ return "Als Geist kannst Du nichts mitnehmen.";
+ else
+ return "Du kannst " + wen1 + " nicht mehr tragen.";
+
+ if (stringp(str = dest->QueryProp(P_TOO_HEAVY_MSG)))
+ return capitalize(replace_personal(str, ({o, dest}), 1));
+
+ if (living(dest)) {
+ if (dest->QueryProp(P_GHOST))
+ return "Als Geist kann " + dest->name(WER, 1) +
+ " nichts mitnehmen.";
+ else
+ return dest->Name(WER, 1) + " kann " +
+ wen0 + " nicht mehr tragen.";
+ }
+
+ if (dest == environment())
+ return (stringp(str = dest->Name(WER, 1)) && sizeof(str) ?
+ str : "Der Raum") + " wuerde dann zu schwer werden.";
+
+ return capitalize(wer0 + " passt in " + dest->name(WEN, 1) +
+ " nicht mehr rein.");
+
+ case ME_CANT_BE_DROPPED:
+ if (o && stringp(str = o->QueryProp(P_NODROP)))
+ return str;
+
+ if (dest == environment())
+ return "Du kannst " + wen1 + " nicht wegwerfen!";
+
+ if (living(dest))
+ return "Du kannst " + wen1 + " nicht weggeben.";
+
+ return "So wirst Du " + wen1 + " nicht los...";
+
+ case ME_CANT_BE_TAKEN:
+ if (o && stringp(str = o->QueryProp(P_NOGET)))
+ return str;
+
+ if (stringp(str = environment(o)->QueryProp(P_NOLEAVE_MSG)))
+ return capitalize(
+ replace_personal(str, ({o, environment(o)}), 1));
+
+ //if (dest != environment())
+ // return "Du kannst " + wen1 + " nicht einmal nehmen.";
+
+ return "Du kannst " + wen1 + " nicht nehmen.";
+
+ case ME_CANT_BE_INSERTED:
+ if (stringp(str = dest->QueryProp(P_NOINSERT_MSG)))
+ return capitalize(replace_personal(str, ({o, dest}), 1));
+
+ if (dest == environment())
+ return "Das darfst Du hier nicht ablegen.";
+
+ if (dest == this_object())
+ return "Du kannst " + wen1 + " nicht nehmen.";
+
+ if (living(dest))
+ return "Das kannst Du " + dest->name(WEM, 1) + " nicht geben.";
+
+ return capitalize(wen0 + " kannst Du dort nicht hineinstecken.");
+
+ case ME_CANT_LEAVE_ENV:
+ // ME_CANT_LEAVE_ENV kann nur auftreten, wenn o ein Environment
+ // hat, deshalb kein Check dadrauf
+ if (stringp(str = environment(o)->QueryProp(P_NOLEAVE_MSG)))
+ return capitalize(
+ replace_personal(str, ({o, environment(o)}), 1));
+
+ if (environment(o) != this_object())
+ return "Du kannst " + wen1 + " nicht nehmen.";
+
+ if (dest == environment())
+ return "Du kannst " + wen1 + " nicht wegwerfen!";
+
+ if (living(dest))
+ return "Du kannst " + wen1 + " nicht weggeben.";
+
+ return "So wirst Du " + wen1 + " nicht los...";
+
+ case ME_TOO_HEAVY_FOR_ENV:
+ if (stringp(str = dest->QueryProp(P_ENV_TOO_HEAVY_MSG)))
+ return capitalize(replace_personal(str, ({o, dest}), 1));
+
+ if (environment(dest) == this_object())
+ return dest->Name(WER, 1) +
+ " wuerde Dir dann zu schwer werden.";
+
+ return (stringp(str = environment(dest)->Name(WER, 1))
+ && sizeof(str) ? str : "Der Raum") +
+ " wuerde dann zu schwer werden.";
+
+ case TOO_MANY_OBJECTS:
+ if (stringp(str = dest->QueryProp(P_TOO_MANY_MSG)))
+ return capitalize(replace_personal(str, ({o, dest}), 1));
+
+ if (dest == this_object())
+ return "Soviele Gegenstaende kannst Du unmoeglich tragen!";
+
+ if (dest == environment())
+ return "Dafuer ist hier nicht mehr genug Platz.";
+
+ if (living(dest))
+ return dest->Name(WER, 1) + " kann " + wen0 +
+ " nicht mehr tragen.";
+
+ return "Dafuer ist nicht mehr genug Platz in " +
+ dest->name(WEM, 1) + ".";
+
+ default:
+ if (dest == this_object())
+ return "Du kannst " + wen1 + " nicht nehmen.";
+
+ if (dest == environment())
+ return "Du kannst " + wen1 + " nicht wegwerfen!";
+
+ if (living(dest))
+ return "Du kannst " + wen1 + " nicht weggeben.";
+
+ return capitalize(wen0 + " kannst Du dort nicht hineinstecken.");
+ }
+ return 0; // NOT REACHED
+}
+
+
+/* varargs int drop(object o, mixed msg)
+ * varargs int put(object o, object dest, mixed msg)
+ * varargs int pick(object o, mixed msg)
+ * varargs int give(object o, object dest, mixed msg)
+ * varargs int show(object o, object dest, mixed msg)
+ *
+ * Der Spieler nimmt/legt/gibt/zeigt/laesst ein Objekt fallen, wobei die
+ * entsprechenden oder optional abweichende (im Format von P_XXX_MSG) oder
+ * gar keine (msg == 1) Meldungen ausgegeben werden. Es liegt in der
+ * Verantwortung des Rufenden, sinnvolle Werte zu uebergeben; insbesondere
+ * wird nicht geprueft, ob sich die Objekte in der Reichweite des Spielers
+ * befinden. Gibt 1 zurueck, wenn das Objekt bewegt wurde, sonst 0.
+ */
+
+varargs int drop(object o, mixed msg)
+{
+ string str;
+
+ // vorher speichern, falls das Objekt zerstoert wird
+ cl = symbol_function("name", o);
+ wen0 = funcall(cl, WEN, 0);
+ wen1 = funcall(cl, WEN, 1);
+ wer0 = 0;
+
+ if (!msg)
+ msg = o->QueryProp(P_DROP_MSG);
+
+ if (str = put_or_get(o, environment())) {
+ TME(str);
+ return 0;
+ }
+
+ if (!msg) {
+ TME("Du laesst " + wen1 + " fallen.");
+ SAY(Name(WER,1) + " laesst " + wen0 + " fallen.");
+ } else if (pointerp(msg))
+ switch (sizeof(msg)) {
+ // Wenn es zwei Strings gibt, geht die 2. ans Environment
+ case 2:
+ SAY(replace_personal(msg[1], ({this_object(), o||wen0}), 1));
+ case 1:
+ TME(replace_personal(msg[0], ({this_object(), o||wen1}), 1));
+ break;
+ default:
+ raise_error(sprintf(
+ "Falsches Format fuer P_DROP_MSG: %O\n", o||wen1));
+ }
+
+ return 1;
+}
+
+varargs int put(object o, object dest, mixed msg)
+{
+ string str;
+
+ // Falls das jemand von aussen ruft und Schrott uebergibt...
+ //if (living(dest))
+ // raise_error(sprintf("Lebendes Ziel fuer put(): %O\n", dest));
+ if (dest == environment())
+ raise_error("Ziel fuer put() ist Umgebung des Spielers\n");
+
+ // vorher speichern, falls das Objekt zerstoert wird
+ cl = symbol_function("name", o);
+ wen0 = funcall(cl, WEN, 0);
+ wen1 = funcall(cl, WEN, 1);
+ wer0 = funcall(cl, WER, 0);
+
+ if (!msg)
+ msg = o->QueryProp(P_PUT_MSG);
+
+ if (str = put_or_get(o, dest)) {
+ TME(str);
+ return 0;
+ }
+
+
+ if (!msg) {
+ TME("Du steckst " + wen1 + " in " + dest->name(WEN, 1) + ".");
+ if (environment())
+ SAY(Name(WER, 1) + " steckt " + wen0 +
+ " in " + dest->name(WEN, 0) + ".");
+ }
+ else if (pointerp(msg)) {
+ switch (sizeof(msg)) {
+ case 2:
+ if (environment())
+ SAY(replace_personal(msg[1], ({this_object(), o||wen0, dest}), 1));
+ case 1:
+ TME(replace_personal(msg[0], ({this_object(), o||wen1, dest}), 1));
+ break;
+ default:
+ raise_error(sprintf(
+ "Falsches Format fuer P_PUT_MSG: %O\n",o||wen1));
+ }
+ }
+
+ return 1;
+}
+
+varargs int pick(object o, mixed msg)
+{
+ string str;
+
+ // vorher speichern, falls das Objekt zerstoert wird
+ cl = symbol_function("name", o);
+ wen0 = 0;
+ wen1 = funcall(cl, WEN, 1);
+ wer0 = 0;
+
+ if (!msg)
+ msg = o->QueryProp(P_PICK_MSG);
+
+ if (str = put_or_get(o, this_object())) {
+ TME(str);
+ return 0;
+ }
+
+ if (!msg) {
+ TME("Du nimmst " + wen1 + ".");
+ SAY(Name(WER, 1) + " nimmt " + wen1 + ".");
+ } else if (pointerp(msg))
+ switch (sizeof(msg)) {
+ case 2:
+ SAY(replace_personal(msg[1], ({this_object(), o||wen1}), 1));
+ case 1:
+ TME(replace_personal(msg[0], ({this_object(), o||wen1}), 1));
+ break;
+ default:
+ raise_error(sprintf(
+ "Falsches Format fuer P_PICK_MSG: %O\n", o||wen1));
+ }
+
+ return 1;
+}
+
+varargs int give(object o, object dest, mixed msg)
+{
+ string zname, gname;
+ string str;
+
+ // Falls das jemand von aussen ruft und Schrott uebergibt...
+ if (!living(dest))
+ raise_error(sprintf("Totes Ziel fuer give(): %O\n", dest));
+
+ zname = dest->name(WEM, 1);
+ gname = Name(WER, 1);
+
+ // vorher speichern, falls das Objekt zerstoert wird
+ cl = symbol_function("name", o);
+ wen0 = funcall(cl, WEN, 0);
+ wen1 = funcall(cl, WEN, 1);
+ wer0 = 0;
+
+ if (!msg)
+ msg = o->QueryProp(P_GIVE_MSG);
+
+ if (str = put_or_get(o, dest)) {
+ TME(str);
+ return 0;
+ }
+
+ if (!msg) {
+ TME("Du gibst " + zname + " " + wen1 + ".");
+ TOB(dest, gname + " gibt Dir " + wen0 + ".");
+ SAY2(({dest}), gname + " gibt " + zname + " " + wen0 + ".");
+ } else if (pointerp(msg))
+ switch (sizeof(msg)) {
+ case 3:
+ TOB(dest, replace_personal(
+ msg[2], ({this_object(), o||wen0, dest||zname}), 1));
+ case 2:
+ SAY2(({dest, this_object()}), replace_personal(
+ msg[1], ({this_object(), o||wen0, dest||zname}), 1));
+ case 1:
+ TME(replace_personal(
+ msg[0], ({this_object(), o||wen1, dest||zname}), 1));
+ break;
+ default:
+ raise_error(sprintf(
+ "Falsches Format fuer P_GIVE_MSG: %O\n", o||wen1));
+ }
+
+ if (!query_once_interactive(dest))
+ dest->give_notify(o);
+
+ return 1;
+}
+
+varargs int show(object o, object whom, mixed msg)
+{
+ string zname, gname;
+ string wen0, wen2, long;
+
+ zname = whom ? whom->name(WEM, 1) : "allen";
+ gname = Name(WER, 1);
+
+ if (!msg)
+ msg = o->QueryProp(P_SHOW_MSG);
+
+ if (environment(o) == this_object() ||
+ environment(environment(o)) == this_object()) {
+ wen0 = o->name(WEN, 0);
+
+ /* Der Akkusativ muss mit dem unbestimmten Artikel gebildet werden,
+ * damit eventuelle Adjektive die richtige Endung besitzen.
+ * (ein kleines Schwert -> kleines Schwert -> Dein kleines Schwert)
+ */
+
+ if (o->QueryProp(P_ARTICLE) && member(wen0, ' ') >= 0) {
+ int obgender = o->QueryProp(P_GENDER);
+ int obnum = o->QueryProp(P_AMOUNT) > 1 ? PLURAL : SINGULAR;
+
+ // Wichtig: P_AMOUNT ist 0 fuer Objekte, die nicht von unit erben.
+ // Da unit.c kein P_AMOUNT==0 zulaesst, nehmen wir diesen Fall als
+ // singular an. *Rumata
+
+ wen2 = wen0[member(wen0, ' ')..];
+ wen0 = QueryPossPronoun(o, WEN, obnum) + wen2;
+
+ if (obnum == PLURAL || obgender == FEMALE)
+ wen2 = "Deine" + wen2;
+ else if (obgender == MALE)
+ wen2 = "Deinen" + wen2;
+ else
+ wen2 = "Dein" + wen2;
+ } else
+ wen2 = wen0;
+ } else
+ wen2 = wen0 = o->name(WEN, 1);
+
+ // vorher speichern, falls das Objekt im catch_tell() zerstoert wird
+ long = o->long(4);
+
+ if (!msg) {
+ TME("Du zeigst " + zname + " " + wen2 + ".");
+ if (!whom)
+ SAY(gname + " zeigt Dir " + wen0 + ".");
+ else {
+ TOB(whom, gname + " zeigt Dir " + wen0 + ".");
+ SAY2(({whom}), gname + " zeigt " + zname + " " + wen0 + ".");
+ }
+ } else if (pointerp(msg))
+ switch (sizeof(msg)) {
+ case 3:
+ if (whom)
+ TOB(whom, replace_personal(
+ msg[2], ({this_object(), o||wen0, whom||zname}), 1));
+ else
+ SAY(replace_personal(
+ msg[2], ({this_object(), o||wen0, whom||zname}), 1));
+ case 2:
+ if (whom)
+ SAY2(({whom, this_object()}), replace_personal(
+ msg[1], ({this_object(), o||wen0, whom||zname}), 1));
+ case 1:
+ TME(replace_personal(
+ msg[0], ({this_object(), o||wen2, whom||zname}), 1));
+ break;
+ default:
+ raise_error(sprintf(
+ "Falsches Format fuer P_SHOW_MSG: %O\n", o||wen0));
+ }
+
+ if (!whom)
+ SAY(long);
+ else {
+ TOB(whom, long);
+ if (!query_once_interactive(whom))
+ whom->show_notify(o);
+ }
+
+ return 1;
+}
+
+
+/***************************** Hilfsfunktionen *****************************/
+
+/* private object *__find_objects(string *tokens, object env, int is_source);
+ * object *find_objects(string what, object env, int is_source);
+ *
+ * Sucht im Raum und im Spieler (oder alternativ in der angegebenen Umgebung)
+ * nach den in tokens/what bezeichneten Objekten. is_source bestimmt die
+ * erwartete grammatische Form (0 fuer "topf auf herd" und 1 fuer "topf von
+ * herd", siehe Manpage).
+ */
+
+private object *__find_objects(string *tokens, object env, int is_source)
+{
+ object ob, *obs;
+
+ // is_source == 0: Objekt soll nicht bewegt werden ("topf auf herd")
+ // 1: Objekt soll bewegt werden ("topf von herd")
+ // 2: intern
+
+ if (!env && sizeof(tokens) > 1 && tokens[<1] == "hier") {
+ tokens = tokens[..<2];
+ env = environment();
+ }
+ else if (!env && sizeof(tokens) > 2 && tokens[<2] == "in")
+ {
+ if (tokens[<1] == "mir" ||
+ tokens[<1] == "dir") {
+ tokens = tokens[..<3];
+ env = this_object();
+ }
+ else if (tokens[<1] == "raum") {
+ tokens = tokens[..<3];
+ env = environment();
+ }
+ }
+
+ for (int i = sizeof(tokens)-1; i > 1; i--) {
+ if (env)
+ ob = present(implode(tokens[i..], " "), env);
+ else
+ ob = present(implode(tokens[i..], " "), environment()) ||
+ present(implode(tokens[i..], " "), this_object());
+
+ if (!ob)
+ continue;
+
+ if (living(ob)) {
+ NF("Aber " + ob->name(WER, 1) + " lebt doch!");
+ continue;
+ }
+
+ if (ob->QueryProp(P_CNT_STATUS)) {
+ NF("Aber " + ob->name(WER, 1) + " ist doch geschlossen!");
+ continue;
+ }
+
+ if (is_source != 0 &&
+ tokens[i-1] == ob->QueryProp(P_SOURCE_PREPOSITION))
+ return ob->present_objects(implode(tokens[..i-2], " "));
+
+ if (tokens[i-1] == ob->QueryProp(P_PREPOSITION))
+ return __find_objects(tokens[..i-2], ob, is_source ? 2 : 0);
+
+ NF("Du kannst nichts " + tokens[i-1] + " " +
+ ob->name(WEM, 1) + " nehmen.");
+ }
+
+ if (is_source == 2)
+ return ({});
+
+ if (env)
+ return env->present_objects(implode(tokens, " "));
+
+ if (environment() &&
+ sizeof(obs = environment()->present_objects(implode(tokens, " "))))
+ return obs;
+
+ return present_objects(implode(tokens, " "));
+}
+
+object *find_objects(string what, object env, int is_source)
+{
+ if (!stringp(what) || !sizeof(what))
+ return ({});
+ return __find_objects(explode(what, " "), env, is_source);
+}
+
+
+/* varargs int drop_objects(string str, mixed msg);
+ * varargs int put_objects(string str, int casus, string verb, mixed msg);
+ * varargs int pick_objects(string str, int flag, mixed msg);
+ * varargs int give_objects(string str, mixed msg);
+ * varargs int show_objects(string str, mixed msg);
+ *
+ * Ein Befehl wie "wirf waffen weg" resultiert in einem Aufruf von
+ * drop_objects("waffen"). Diese Funktionen sind hauptsaechlich fuer die
+ * Behandlung der jeweiligen Kommandos vorgesehen, koennen jedoch auch fuer
+ * eigene Befehle verwendet werden. put_objects() erwartet ausserdem den
+ * Kasus ("Du kannst nichts an DER Pinwand befestigen.") und das verwendete
+ * Verb in der Gundform ("befestigen"). Das Flag fuer pick_objects() gibt
+ * an, ob das Objekt auch einfach herumliegen darf ("nimm ...") oder nicht
+ * ("hole ..."). Gibt bei Erfolg 1, sonst 0 zurueck.
+ */
+
+varargs int drop_objects(string str, mixed msg)
+{
+ object *obs;
+
+ if (!sizeof(obs = find_objects(str, this_object(), 1)))
+ return 0;
+
+ foreach (object o: obs) {
+ if (objectp(o))
+ drop(o, msg);
+
+ if (get_eval_cost() < 100000) {
+ TME("Den Rest behaeltst Du erst mal.");
+ last_moved_objects = obs[..member(obs, o)];
+ last_moved_where = 0;
+ return 1;
+ }
+ }
+
+ last_moved_objects = obs;
+ last_moved_where = 0;
+ return 1;
+}
+
+varargs int put_objects(string str, int casus, string verb, mixed msg)
+{
+ object *obs, dest, *no_move;
+
+ if (!stringp(str) || !sizeof(str)) return 0;
+
+ string *tokens = explode(str, " ");
+ int allow_room = 1;
+ int allow_me = 1;
+
+ if (sizeof(tokens) > 1 && tokens[<1] == "hier") {
+ tokens = tokens[..<2];
+ allow_me = 0;
+ } else if (sizeof(tokens) > 2 && tokens[<2] == "in")
+ if (tokens[<1] == "mir" ||
+ tokens[<1] == "dir") {
+ tokens = tokens[..<3];
+ allow_room = 0;
+ } else if (tokens[<1] == "raum") {
+ tokens = tokens[..<3];
+ allow_me = 0;
+ }
+
+ for (int i = sizeof(tokens)-1; i > 1; i--) {
+ if (!(dest = allow_room && present(implode(tokens[i..], " "),
+ environment())) &&
+ !(dest = allow_me && present(implode(tokens[i..], " "),
+ this_object())))
+ continue;
+
+ if (living(dest)) {
+ NF("Aber " + dest->name(WER, 1) + " lebt doch!");
+ continue;
+ }
+/*
+ if (verb == "legen" && !dest->QueryProp(P_TRAY)) {
+ NF("Du kannst nichts auf " + dest->name(WEN, 1) + " legen.");
+ continue;
+ }
+*/
+ if (verb == "stecken" && !dest->QueryProp(P_CONTAINER)) {
+ NF("Du kannst in " + dest->name(WEN, 1) + " nichts reinstecken.");
+ continue;
+ }
+
+ if (dest->QueryProp(P_CNT_STATUS)) {
+ NF("Aber " + dest->name(WER, 1) + " ist doch geschlossen!");
+ continue;
+ }
+
+ if (tokens[i-1] != dest->QueryProp(P_DEST_PREPOSITION)) {
+ NF("Du kannst nichts " + tokens[i-1] + " " +
+ dest->name(casus, 1) + " " + verb + ".");
+ continue;
+ }
+
+ if (!sizeof(obs = __find_objects(tokens[..i-2], 0, 1) - ({ dest }))) {
+ NF("WAS moechtest Du " + tokens[i-1] + " " +
+ dest->name(casus, 1) + " " + verb + "?");
+ return 0;
+ }
+
+ if (sizeof(no_move = obs & all_inventory(dest))) {
+ TME(capitalize(CountUp(map_objects(no_move, "name", WER, 1))) +
+ (sizeof(no_move) == 1 ? " ist" : " sind") +
+ " doch bereits in " + dest->name(WEM,1) + ".");
+ if (!sizeof(obs -= no_move))
+ return 0;
+ }
+
+ foreach (object o: obs) {
+ if (objectp(o))
+ put(o, dest, msg);
+
+ if (get_eval_cost() < 100000) {
+ TME("Den Rest laesst Du erst mal, wo er ist.");
+ last_moved_objects = obs[..member(obs, o)];
+ last_moved_where = dest;
+ return 1;
+ }
+ }
+
+ last_moved_objects = obs;
+ last_moved_where = dest;
+ return 1;
+ }
+
+ return 0;
+}
+
+varargs int pick_objects(string str, int flag, mixed msg)
+{
+ object *obs;
+
+ if (((int)QueryProp(P_MAX_HANDS)) < 1){
+ NF("Ohne Haende kannst Du nichts nehmen.");
+ return 0;
+ }
+
+ if (!sizeof(obs = find_objects(str, 0, 1) - all_inventory()
+ - (flag ? all_inventory(environment()) : ({}))))
+ return 0;
+
+ foreach (object o: obs) {
+ if (objectp(o))
+ pick(o, msg);
+
+ if (get_eval_cost() < 100000) {
+ TME("Den Rest laesst Du erst mal liegen.");
+ last_moved_objects = obs[..member(obs, o)];
+ last_moved_where = 0;
+ return 1;
+ }
+ }
+
+ last_moved_objects = obs;
+ last_moved_where = 0;
+ return 1;
+}
+
+varargs int give_objects(string str, mixed msg)
+{
+ object *obs, dest;
+
+ if (!stringp(str) || !sizeof(str)) return 0;
+
+ string *tokens = explode(str, " ");
+
+ if (((int)QueryProp(P_MAX_HANDS)) < 1){
+ NF("Ohne Haende kannst Du nichts weggeben.");
+ return 0;
+ }
+
+ for (int i = 0; i < sizeof(tokens)-1; i++) {
+ if (!(dest = present(implode(tokens[..i], " "), environment())))
+ continue;
+
+ if (!living(dest)) {
+ NF("Aber " + dest->name(WER, 1) + " lebt doch gar nicht!");
+ dest = 0;
+ continue;
+ }
+
+ if (!sizeof(obs = __find_objects(tokens[i+1..], 0, 1))) {
+ NF("WAS moechtest Du " + dest->name(WEM, 1)+" geben?");
+ dest = 0;
+ } else
+ break;
+ }
+
+ if (!dest) {
+ int pos;
+
+ if ((pos = strrstr(str, " an ")) >= 0) {
+ dest = present(str[pos+4..], environment());
+ // zu gebende Objekte in Env + Living suchen
+ obs = find_objects(str[..pos-1], 0, 1);
+ }
+ }
+
+ if (!dest || !living(dest) || !sizeof(obs))
+ return 0;
+
+ foreach (object o: obs) {
+ if (objectp(o))
+ give(o, dest, msg);
+
+ if (get_eval_cost() < 100000) {
+ TME("Den Rest behaeltst Du erst mal.");
+ last_moved_objects = obs[..member(obs, o)];
+ last_moved_where = dest;
+ return 1;
+ }
+ }
+
+ last_moved_objects = obs;
+ last_moved_where = dest;
+ return 1;
+}
+
+varargs int show_objects(string str, mixed msg)
+{
+ object *obs, whom;
+
+ if (!stringp(str) || !sizeof(str))
+ return 0;
+
+ string *tokens = explode(str, " ");
+
+ for (int i = 0; i < sizeof(tokens)-1; i++) {
+ if (whom = present(implode(tokens[..i], " "), environment())) {
+ if (!living(whom)) {
+ NF("Aber " + whom->name(WER, 1) + " lebt doch gar nicht!");
+ continue;
+ }
+ } else {
+ if (i != 0 || tokens[0] != "allen")
+ continue;
+
+ if (!sizeof(filter(all_inventory(environment()) -
+ ({ this_object() }), #'living))) {
+ NF("Hier ist niemand, dem Du etwas zeigen koenntest!");
+ continue;
+ }
+ }
+
+ if (whom == this_object()) {
+ NF("Dazu solltest Du dann besser 'schau' benutzen!\n");
+ continue;
+ }
+
+ if (!sizeof(obs = __find_objects(tokens[i+1..], this_object(), 0)) &&
+ !sizeof(obs = __find_objects(tokens[i+1..], 0, 0)
+ - ({ this_object(), whom }))) {
+ NF("WAS moechtest Du " + (whom ? whom->name(WEM, 1) : "allen") +
+ " zeigen?");
+ continue;
+ }
+
+ foreach (object o: obs) {
+ if (objectp(o))
+ show(o, whom, msg);
+
+ if (get_eval_cost() < 100000) {
+ TME("Das reicht erst mal.");
+ last_moved_objects = obs[..member(obs, o)];
+ last_moved_where = whom;
+ return 1;
+ }
+ }
+
+ last_moved_objects = obs;
+ last_moved_where = whom;
+ return 1;
+ }
+
+ return 0;
+}
+
+object *moved_objects(void)
+{
+ return last_moved_objects;
+}
+
+object moved_where(void)
+{
+ return last_moved_where;
+}
+
+
+/************************* Die einzelnen Kommandos **************************/
+
+/* static int fallenlassen(string str)
+ * static int werfen(string str)
+ * static int legen(string str)
+ * static int stecken(string str)
+ * static int holen(string str)
+ * static int nehmen(string str)
+ * static int geben(string str)
+ * Minimale Wrapper fuer XXX_objects(), entfernen "fallen", "weg" bzw. "ab"
+ * aus den Argumenten und setzen entsprechende Standard-Fehlermeldungen.
+ *
+ * protected void add_put_and_get_commands()
+ * Registriert obige Funktionen per add_action().
+ */
+
+static int fallenlassen(string str)
+{
+ if (QueryProp(P_GHOST)) {
+ _notify_fail("Als Geist kannst Du nichts fallenlassen.\n");
+ return 0;
+ }
+
+ if (!str || str[<7..] != " fallen") {
+ _notify_fail("Lass etwas FALLEN, oder was meinst Du?\n");
+ return 0;
+ }
+
+ _notify_fail("WAS moechtest Du fallenlassen?\n");
+ return drop_objects(str[0..<8]);
+}
+
+static int werfen(string str)
+{
+ if (QueryProp(P_GHOST)) {
+ _notify_fail("Als Geist kannst Du nichts wegwerfen.\n");
+ return 0;
+ }
+
+ if (!str || str[<4..] != " weg") {
+ _notify_fail("Wirf etwas WEG, oder was meinst Du?\n");
+ return 0;
+ }
+
+ _notify_fail("WAS moechtest Du loswerden?\n");
+ return drop_objects(str[0..<5]);
+}
+
+static int legen(string str)
+{
+ if (QueryProp(P_GHOST)) {
+ _notify_fail("Als Geist kannst Du nichts weglegen.\n");
+ return 0;
+ }
+
+ if (!str) {
+ _notify_fail("Lege etwas AB, oder was meinst Du?\n");
+ return 0;
+ }
+
+ if (str[<3..] == " ab") {
+ _notify_fail("WAS moechtest Du ablegen?\n");
+ return drop_objects(str[0..<4]);
+ }
+
+ if (str[<4..] == " weg") {
+ _notify_fail("WAS moechtest Du weglegen?\n");
+ return drop_objects(str[0..<5]);
+ }
+
+ _notify_fail("WAS moechtest Du WOHIN legen?\n");
+ return put_objects(str, WEN, "legen");
+}
+
+static int stecken(string str)
+{
+ if (QueryProp(P_GHOST)) {
+ _notify_fail("Das kannst Du in Deinem immateriellen Zustand nicht.\n");
+ return 0;
+ }
+
+ _notify_fail("WAS moechtest Du WOHIN stecken?\n");
+ return put_objects(str, WEN, "stecken");
+}
+
+static int holen(string str)
+{
+ if (QueryProp(P_GHOST)) {
+ _notify_fail("Als Geist kannst Du nichts nehmen.\n");
+ return 0;
+ }
+
+ _notify_fail("WAS moechtest Du aus WAS holen?\n");
+ return pick_objects(str, 1);
+}
+
+static int nehmen(string str)
+{
+ if (QueryProp(P_GHOST)) {
+ _notify_fail("Als Geist kannst Du nichts nehmen.\n");
+ return 0;
+ }
+
+ _notify_fail("WAS moechtest Du nehmen?\n");
+ return pick_objects(str, 0);
+}
+
+static int geben(string str)
+{
+ if (QueryProp(P_GHOST)) {
+ _notify_fail("Als Geist kannst Du nichts weggeben.\n");
+ return 0;
+ }
+
+ _notify_fail("WEM moechtest Du WAS geben?\n");
+ return give_objects(str);
+}
+
+static int zeigen(string str)
+{
+ if (QueryProp(P_GHOST)) {
+ _notify_fail("Als Geist kannst Du niemandem etwas zeigen.\n");
+ return 0;
+ }
+
+ _notify_fail("WEM moechtest Du WAS zeigen?\n");
+ return show_objects(str);
+}
+
+protected void add_put_and_get_commands(void)
+{
+ add_action("fallenlassen", "lass");
+ add_action("fallenlassen", "lasse");
+ add_action("werfen", "wirf");
+ add_action("werfen", "werf");
+ add_action("werfen", "werfe");
+ add_action("legen", "leg");
+ add_action("legen", "lege");
+ add_action("stecken", "steck");
+ add_action("stecken", "stecke");
+ add_action("holen", "hol");
+ add_action("holen", "hole");
+ add_action("nehmen", "nimm");
+ add_action("nehmen", "nehm");
+ add_action("nehmen", "nehme");
+ add_action("geben", "gebe");
+ add_action("geben", "gib");
+ add_action("zeigen", "zeig");
+ add_action("zeigen", "zeige");
+}
+
+
+/********** Aus reinen Kompatibilitaetsgruenden weiterhin enthalten *********/
+
+object* find_obs(string str, int meth)
+// gibt ein array zurueck mit allen Objekten die mit str angesprochen werden
+{
+ object inv;
+ if (!str) return 0;
+ if (str[<7..]==" in mir") {
+ inv=ME;
+ str=str[0..<8];
+ }
+ else if (str[<8..]==" in raum") {
+ if (meth & PUT_GET_DROP) { // man kann nichts aus dem Raum wegwerfen
+ _notify_fail("Du kannst nichts wegwerfen, das Du gar nicht hast.\n");
+ return 0;
+ }
+ inv=environment();
+ str=str[0..<9];
+ }
+ else if (meth & PUT_GET_DROP) inv=ME; // Raum bei drop uninteressant
+ // else kein besonderes inv ausgewaehlt also inv=0
+ if (!sizeof(str))
+ return 0; // hier passt die bereits gesetzte _notify_fail
+ else {
+ object *obs;
+ string con;
+ if (sscanf(str, "%s aus %s", str, con)==2 ||
+ sscanf(str, "%s in %s", str, con)==2 ||
+ sscanf(str, "%s von %s", str, con)==2 ||
+ sscanf(str, "%s vom %s", str, con)==2) {
+ if (!inv) {
+ if (!environment() || !(inv=present(con, environment())))
+ inv=present(con, ME); // sowohl im env als auch im inv suchen
+ }
+ else inv=present(con, inv); // nur in ausgewaehltem inv suchen
+ if (inv==ME) inv=0;
+ if (!inv || !(inv->short())) {
+ _notify_fail(break_string("Du hast hier aber kein '"+capitalize(con)
+ +"'.",78));
+ return 0;
+ }
+ if (living(inv)) {
+ _notify_fail(break_string("Aber "+inv->name(WER,1)+" lebt doch!",78));
+ return 0;
+ }
+ // wieso man aus Objekten die von std/tray abgeleitet werden etwas
+ // nehmen koennen soll, versteh ich zwar nicht so ganz...
+ if (!(inv->QueryProp(P_CONTAINER)) && !(inv->QueryProp(P_TRAY))) {
+ _notify_fail(break_string("Du kannst nichts aus "+inv->name(WEM,1)
+ +" nehmen.",78));
+ return 0;
+ }
+ if (inv->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
+ _notify_fail(break_string("Aber "+inv->name(WER,1)
+ +" ist doch geschlossen.", 78));
+ return 0;
+ }
+ }
+ else if (inv==ME && (meth & PUT_GET_TAKE)) { // nichts aus sich nehmen
+ _notify_fail("Du kannst nichts nehmen, "
+ "was Du schon bei Dir traegst.\n");
+ return 0;
+ }
+ if (!inv && (meth & PUT_GET_TAKE))
+ inv=environment(); // nichts nehmen was man schon hat
+
+ if (!inv) {
+ if (environment()) {
+ obs=(environment()->present_objects(str)||({}));
+ if (!sizeof(obs)) obs+=(ME->present_objects(str)||({}));
+ }
+ else obs=(ME->present_objects(str) || ({}));
+ }
+ else obs=(inv->present_objects(str) || ({}));
+ return obs-({ ME });
+ }
+ return(0);
+}
+
+int pick_obj(object ob)
+{
+ object env;
+
+ if (!ob || ob == this_object() || environment(ob) == this_object()) return 0;
+ if ((env=environment(ob)) != environment()) {
+ if (!env->QueryProp(P_CONTAINER) && !env->QueryProp(P_TRAY)) {
+ TME("Du kannst nichts aus " + env->name(WEM,1) + " nehmen.");
+ return 1;
+ }
+ else if (env->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
+ TME("Aber " + env->name(WER, 1) + " ist doch geschlossen.");
+ return 1;
+ }
+ }
+ if (ob->IsUnit() && ob->QueryProp(P_AMOUNT)<0) {
+ TME("Du kannst nicht mehr nehmen als da ist.");
+ return 1;
+ }
+ pick(ob);
+ return 1;
+}
+
+int drop_obj(object ob)
+{
+ if (!ob || ob==this_object() || environment(ob)!=this_object()) return 0;
+ drop(ob);
+ return 1;
+}
+
+int put_obj(object ob, object where)
+{
+ object env;
+
+ if (ob == this_object() || ob == where || environment(ob) == where) return 0;
+ env=environment(ob);
+ if (!where->QueryProp(P_CONTAINER)) {
+ TME("Du kannst in " + where->name(WEN,1) + " nix reinstecken.");
+ return 1;
+ }
+ if (where->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
+ TME("Aber " + where->name(WER, 1) + " ist doch geschlossen.");
+ return 1;
+ }
+ if (env!=environment(this_object()) && env!=this_object()) {
+ _notify_fail("Da kommst du so nicht ran.\n");
+ return 0;
+ }
+ put(ob, where);
+ return 1;
+}
+
+int give_obj(object ob, object where)
+{
+ object env;
+
+ if (environment(ob)!=this_object()) {
+ TME("Das solltest Du erstmal nehmen.");
+ return 1;
+ }
+ if (!ob || ob == this_object() || ob == where ||
+ environment(where)!=environment())
+ return 0;
+ if (environment(ob) == where) {
+ _notify_fail("Das Ziel ist in dem zu gebenden Object enthalten!\n");
+ return 0;
+ }
+ if (environment(ob)!=this_object()) {
+ TME("Das hast Du nicht.");
+ return 1;
+ }
+ give(ob, where);
+ return 1;
+}