blob: 4e1a97f363caf2bc7dc1868b7c7c6f87486e125e [file] [log] [blame]
// 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;
}