blob: a0b95751b3fa261e7ec056312edb12dbf69b9733 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// living/put_and_get.c -- taking and putting things
4//
5// $Id: put_and_get.c 8755 2014-04-26 13:13:40Z Zesstra $
6
7/*
8 Grundlegend neu strukturiert von Amynthor im April-Juni 2007
9
10Die eigentlichen Funktionen:
11
12 private string put_or_get(object o, object dest)
13 Bewegt ein einzelnes Objekt mit automatisch bestimmter Method. Gibt im
14 Erfolgsfall 0 zurueck, sonst die auszugebende Fehlermeldung.
15
16 varargs int drop(object o, mixed msg)
17 varargs int put(object o, object dest, mixed msg)
18 varargs int pick(object o, mixed msg)
19 varargs int give(object o, object dest, mixed msg)
20 varargs int show(object o, object dest, mixed msg)
21 Der Spieler nimmt/legt/gibt/zeigt/laesst ein Objekt fallen, wobei die
22 entsprechenden oder optional abweichende (im Format von P_XXX_MSG) oder
23 gar keine (msg == 1) Meldungen ausgegeben werden. Es liegt in der
24 Verantwortung des Rufenden, sinnvolle Werte zu uebergeben; insbesondere
25 wird nicht geprueft, ob sich die Objekte in der Reichweite des Spielers
26 befinden. Gibt 1 zurueck, wenn das Objekt bewegt wurde, sonst 0.
27
28Hilfsfunktionen:
29
30 private object *__find_objects(string *tokens, object env, int is_source)
31 object *find_objects(string what, object env, int is_source)
32 Sucht im Raum und im Spieler (oder alternativ in der angegebenen Umgebung)
33 nach den in tokens/what bezeichneten Objekten. is_source bestimmt die
34 erwartete grammatische Form (0 fuer "topf auf herd" und 1 fuer "topf von
35 herd", siehe Manpage).
36
37 varargs int drop_objects(string str, mixed msg)
38 varargs int put_objects(string str, int casus, string verb, mixed msg)
39 varargs int pick_objects(string str, mixed msg, int flag)
40 varargs int give_objects(string str, mixed msg)
41 varargs int show_objects(string str, mixed msg)
42 Ein Befehl wie "wirf waffen weg" resultiert in einem Aufruf von
43 drop_objects("waffen"). Diese Funktionen sind hauptsaechlich fuer die
44 Behandlung der jeweiligen Kommandos vorgesehen, koennen jedoch auch fuer
45 eigene Befehle verwendet werden. put_objects() erwartet ausserdem den
46 Kasus ("Du kannst nichts an DER Pinwand befestigen.") und das verwendete
47 Verb in der Gundform ("befestigen"). Das Flag fuer pick_objects() gibt
48 an, ob das Objekt auch einfach herumliegen darf ("nimm ...") oder nicht
49 ("hole ..."). Gibt bei Erfolg 1, sonst 0 zurueck.
50
51 object *moved_objects()
52 object moved_where()
53 Gibt die eben fallengelassenen/gesteckten/... Objekte zurueck und wohin
54 sie gesteckt/wem sie gegeben/gezeigt wurden. Fuer den Fall, dass man
55 anschliessend noch etwas mit ihnen machen moechte.
56
57Die einzelnen Kommandos:
58 static int fallenlassen(string str)
59 static int werfen(string str)
60 static int legen(string str)
61 static int stecken(string str)
62 static int holen(string str)
63 static int nehmen(string str)
64 static int geben(string str)
65 Minimale Wrapper fuer XXX_objects(), entfernen "fallen", "weg" bzw. "ab"
66 aus den Argumenten und setzen entsprechende Standard-Fehlermeldungen.
67
68 protected void add_put_and_get_commands()
69 Registriert obige Funktionen per add_action().
70
71Aus reinen Kompatibilitaetsgruenden weiterhin enthalten:
72
73 object* find_obs(string str, int meth)
74 int pick_obj(object ob)
75 int drop_obj(object ob)
76 int put_obj(object ob, object where)
77 int give_obj(object ob, object where)
78 siehe Manpages
79
80*/
81
82/*
83 21. Okt 1998 komplette neu programmierung von put_and_get.c (Padreic)
84- die Gruppenauswahlen alles, waffen und ruestungen sind jetzt immer moeglich
85 die Gruppen sind sehr leicht erweiterbar und man sollte sich nicht scheuen
86 davon gebrauch zu machen...
87- mit "in mir" und "im raum" kann man den abzusuchenden Raum selbst eingrenzen
88- mit "alle|jede|jeden|jedes <id>" kann man auch ganze objektgruppen auswaehlen
89*/
90
91#pragma strong_types
92#pragma save_types
93#pragma range_check
94#pragma no_clone
95#pragma pedantic
96
97#define NEED_PROTOTYPES
98#include <language.h>
99#include <thing/description.h>
100#include <thing/properties.h>
101#include <moving.h>
102#include <container.h>
103#undef NEED_PROTOTYPES
104
105#include <defines.h>
106#include <properties.h>
107#include <wizlevels.h>
108
109#define TME(str) tell_object(this_object(), \
110 break_string(str, 78, 0, BS_LEAVE_MY_LFS))
111#define TOB(ob,str) tell_object(ob, break_string(str, 78, 0, BS_LEAVE_MY_LFS))
112#define SAY(str) tell_room(environment(), \
113 break_string(str, 78, 0, BS_LEAVE_MY_LFS), ({this_object()}))
114#define SAY2(obs, str) tell_room(environment(), \
115 break_string(str, 78, 0, BS_LEAVE_MY_LFS), ({this_object()}) + obs)
116#define NF(str) _notify_fail(break_string(str, 78, 0, BS_LEAVE_MY_LFS))
117
118private nosave closure cl;
119private nosave string wen0, wen1, wer0;
120private nosave object *last_moved_objects;
121private nosave object last_moved_where;
122
123
124/*********************** Die eigentlichen Funktionen ************************/
125
126private string put_or_get(object o, object dest)
127
128/* Bewegt ein einzelnes Objekt <o> in das Zielobjekt <dest>. Verwendet dazu
129 * je nach Umstaenden (Ziel ist der Spieler, die Umgebung, ein Lebewesen) den
130 * entsprechenden Wert fuer <method>. Gibt im Erfolgsfall 0 zurueck, erstellt
131 * sonst die auszugebende Fehlermeldung und gibt diese zurueck.
132 */
133
134{
135 int method, ret;
136 string str;
137
138 //if (living(o))
139 // raise_error(sprintf("Lebendes Argument fuer put_or_get: %O\n", o));
140
141 if (dest == this_object()) /* pick */
142 method = M_GET;
143 else if (dest == environment()) /* drop */
144 method = M_PUT;
145 else if (living(dest)) /* give */
146 method = M_GIVE;
147 else { /* put */
148 method = M_PUT | M_GET;
149 if (first_inventory(o))
150 return o->Name(WER, 1) + " ist nicht leer!";
151 }
152
153 if ((ret = o->move(dest, method)) > 0)
154 return 0;
155
156 switch (ret) {
157 case ME_TOO_HEAVY:
158 if (dest == this_object())
159 if (QueryProp(P_GHOST))
160 return "Als Geist kannst Du nichts mitnehmen.";
161 else
162 return "Du kannst " + wen1 + " nicht mehr tragen.";
163
164 if (stringp(str = dest->QueryProp(P_TOO_HEAVY_MSG)))
165 return capitalize(replace_personal(str, ({o, dest}), 1));
166
167 if (living(dest)) {
168 if (dest->QueryProp(P_GHOST))
169 return "Als Geist kann " + dest->name(WER, 1) +
170 " nichts mitnehmen.";
171 else
172 return dest->Name(WER, 1) + " kann " +
173 wen0 + " nicht mehr tragen.";
174 }
175
176 if (dest == environment())
177 return (stringp(str = dest->Name(WER, 1)) && sizeof(str) ?
178 str : "Der Raum") + " wuerde dann zu schwer werden.";
179
180 return capitalize(wer0 + " passt in " + dest->name(WEN, 1) +
181 " nicht mehr rein.");
182
183 case ME_CANT_BE_DROPPED:
184 if (o && stringp(str = o->QueryProp(P_NODROP)))
185 return str;
186
187 if (dest == environment())
188 return "Du kannst " + wen1 + " nicht wegwerfen!";
189
190 if (living(dest))
191 return "Du kannst " + wen1 + " nicht weggeben.";
192
193 return "So wirst Du " + wen1 + " nicht los...";
194
195 case ME_CANT_BE_TAKEN:
196 if (o && stringp(str = o->QueryProp(P_NOGET)))
197 return str;
198
199 if (stringp(str = environment(o)->QueryProp(P_NOLEAVE_MSG)))
200 return capitalize(
201 replace_personal(str, ({o, environment(o)}), 1));
202
203 //if (dest != environment())
204 // return "Du kannst " + wen1 + " nicht einmal nehmen.";
205
206 return "Du kannst " + wen1 + " nicht nehmen.";
207
208 case ME_CANT_BE_INSERTED:
209 if (stringp(str = dest->QueryProp(P_NOINSERT_MSG)))
210 return capitalize(replace_personal(str, ({o, dest}), 1));
211
212 if (dest == environment())
213 return "Das darfst Du hier nicht ablegen.";
214
215 if (dest == this_object())
216 return "Du kannst " + wen1 + " nicht nehmen.";
217
218 if (living(dest))
219 return "Das kannst Du " + dest->name(WEM, 1) + " nicht geben.";
220
221 return capitalize(wen0 + " kannst Du dort nicht hineinstecken.");
222
223 case ME_CANT_LEAVE_ENV:
224 // ME_CANT_LEAVE_ENV kann nur auftreten, wenn o ein Environment
225 // hat, deshalb kein Check dadrauf
226 if (stringp(str = environment(o)->QueryProp(P_NOLEAVE_MSG)))
227 return capitalize(
228 replace_personal(str, ({o, environment(o)}), 1));
229
230 if (environment(o) != this_object())
231 return "Du kannst " + wen1 + " nicht nehmen.";
232
233 if (dest == environment())
234 return "Du kannst " + wen1 + " nicht wegwerfen!";
235
236 if (living(dest))
237 return "Du kannst " + wen1 + " nicht weggeben.";
238
239 return "So wirst Du " + wen1 + " nicht los...";
240
241 case ME_TOO_HEAVY_FOR_ENV:
242 if (stringp(str = dest->QueryProp(P_ENV_TOO_HEAVY_MSG)))
243 return capitalize(replace_personal(str, ({o, dest}), 1));
244
245 if (environment(dest) == this_object())
246 return dest->Name(WER, 1) +
247 " wuerde Dir dann zu schwer werden.";
248
249 return (stringp(str = environment(dest)->Name(WER, 1))
250 && sizeof(str) ? str : "Der Raum") +
251 " wuerde dann zu schwer werden.";
252
253 case TOO_MANY_OBJECTS:
254 if (stringp(str = dest->QueryProp(P_TOO_MANY_MSG)))
255 return capitalize(replace_personal(str, ({o, dest}), 1));
256
257 if (dest == this_object())
258 return "Soviele Gegenstaende kannst Du unmoeglich tragen!";
259
260 if (dest == environment())
261 return "Dafuer ist hier nicht mehr genug Platz.";
262
263 if (living(dest))
264 return dest->Name(WER, 1) + " kann " + wen0 +
265 " nicht mehr tragen.";
266
267 return "Dafuer ist nicht mehr genug Platz in " +
268 dest->name(WEM, 1) + ".";
269
270 default:
271 if (dest == this_object())
272 return "Du kannst " + wen1 + " nicht nehmen.";
273
274 if (dest == environment())
275 return "Du kannst " + wen1 + " nicht wegwerfen!";
276
277 if (living(dest))
278 return "Du kannst " + wen1 + " nicht weggeben.";
279
280 return capitalize(wen0 + " kannst Du dort nicht hineinstecken.");
281 }
282 return 0; // NOT REACHED
283}
284
285
286/* varargs int drop(object o, mixed msg)
287 * varargs int put(object o, object dest, mixed msg)
288 * varargs int pick(object o, mixed msg)
289 * varargs int give(object o, object dest, mixed msg)
290 * varargs int show(object o, object dest, mixed msg)
291 *
292 * Der Spieler nimmt/legt/gibt/zeigt/laesst ein Objekt fallen, wobei die
293 * entsprechenden oder optional abweichende (im Format von P_XXX_MSG) oder
294 * gar keine (msg == 1) Meldungen ausgegeben werden. Es liegt in der
295 * Verantwortung des Rufenden, sinnvolle Werte zu uebergeben; insbesondere
296 * wird nicht geprueft, ob sich die Objekte in der Reichweite des Spielers
297 * befinden. Gibt 1 zurueck, wenn das Objekt bewegt wurde, sonst 0.
298 */
299
300varargs int drop(object o, mixed msg)
301{
302 string str;
303
304 // vorher speichern, falls das Objekt zerstoert wird
305 cl = symbol_function("name", o);
306 wen0 = funcall(cl, WEN, 0);
307 wen1 = funcall(cl, WEN, 1);
308 wer0 = 0;
309
310 if (!msg)
311 msg = o->QueryProp(P_DROP_MSG);
312
313 if (str = put_or_get(o, environment())) {
314 TME(str);
315 return 0;
316 }
317
318 if (!msg) {
319 TME("Du laesst " + wen1 + " fallen.");
320 SAY(Name(WER,1) + " laesst " + wen0 + " fallen.");
321 } else if (pointerp(msg))
322 switch (sizeof(msg)) {
323 // Wenn es zwei Strings gibt, geht die 2. ans Environment
324 case 2:
325 SAY(replace_personal(msg[1], ({this_object(), o||wen0}), 1));
326 case 1:
327 TME(replace_personal(msg[0], ({this_object(), o||wen1}), 1));
328 break;
329 default:
330 raise_error(sprintf(
331 "Falsches Format fuer P_DROP_MSG: %O\n", o||wen1));
332 }
333
334 return 1;
335}
336
337varargs int put(object o, object dest, mixed msg)
338{
339 string str;
340
341 // Falls das jemand von aussen ruft und Schrott uebergibt...
342 //if (living(dest))
343 // raise_error(sprintf("Lebendes Ziel fuer put(): %O\n", dest));
344 if (dest == environment())
345 raise_error("Ziel fuer put() ist Umgebung des Spielers\n");
346
347 // vorher speichern, falls das Objekt zerstoert wird
348 cl = symbol_function("name", o);
349 wen0 = funcall(cl, WEN, 0);
350 wen1 = funcall(cl, WEN, 1);
351 wer0 = funcall(cl, WER, 0);
352
353 if (!msg)
354 msg = o->QueryProp(P_PUT_MSG);
355
356 if (str = put_or_get(o, dest)) {
357 TME(str);
358 return 0;
359 }
360
361
362 if (!msg) {
Zesstrabc1e21c2016-07-24 14:43:54 +0200363 TME("Du steckst " + wen1 + " "
364 + dest->QueryProp(P_DEST_PREPOSITION) + " "
365 + dest->name(WEN, 1) + ".");
MG Mud User88f12472016-06-24 23:31:02 +0200366 if (environment())
Zesstrabc1e21c2016-07-24 14:43:54 +0200367 SAY(Name(WER, 1) + " steckt " + wen0 + " "
368 + dest->QueryProp(P_DEST_PREPOSITION) + " "
369 + dest->name(WEN, 0) + ".");
MG Mud User88f12472016-06-24 23:31:02 +0200370 }
371 else if (pointerp(msg)) {
372 switch (sizeof(msg)) {
373 case 2:
374 if (environment())
375 SAY(replace_personal(msg[1], ({this_object(), o||wen0, dest}), 1));
376 case 1:
377 TME(replace_personal(msg[0], ({this_object(), o||wen1, dest}), 1));
378 break;
379 default:
380 raise_error(sprintf(
381 "Falsches Format fuer P_PUT_MSG: %O\n",o||wen1));
382 }
383 }
384
385 return 1;
386}
387
388varargs int pick(object o, mixed msg)
389{
390 string str;
391
392 // vorher speichern, falls das Objekt zerstoert wird
393 cl = symbol_function("name", o);
394 wen0 = 0;
395 wen1 = funcall(cl, WEN, 1);
396 wer0 = 0;
397
398 if (!msg)
399 msg = o->QueryProp(P_PICK_MSG);
400
401 if (str = put_or_get(o, this_object())) {
402 TME(str);
403 return 0;
404 }
405
406 if (!msg) {
407 TME("Du nimmst " + wen1 + ".");
408 SAY(Name(WER, 1) + " nimmt " + wen1 + ".");
409 } else if (pointerp(msg))
410 switch (sizeof(msg)) {
411 case 2:
412 SAY(replace_personal(msg[1], ({this_object(), o||wen1}), 1));
413 case 1:
414 TME(replace_personal(msg[0], ({this_object(), o||wen1}), 1));
415 break;
416 default:
417 raise_error(sprintf(
418 "Falsches Format fuer P_PICK_MSG: %O\n", o||wen1));
419 }
420
421 return 1;
422}
423
424varargs int give(object o, object dest, mixed msg)
425{
426 string zname, gname;
427 string str;
428
429 // Falls das jemand von aussen ruft und Schrott uebergibt...
430 if (!living(dest))
431 raise_error(sprintf("Totes Ziel fuer give(): %O\n", dest));
432
433 zname = dest->name(WEM, 1);
434 gname = Name(WER, 1);
435
436 // vorher speichern, falls das Objekt zerstoert wird
437 cl = symbol_function("name", o);
438 wen0 = funcall(cl, WEN, 0);
439 wen1 = funcall(cl, WEN, 1);
440 wer0 = 0;
441
442 if (!msg)
443 msg = o->QueryProp(P_GIVE_MSG);
444
445 if (str = put_or_get(o, dest)) {
446 TME(str);
447 return 0;
448 }
449
450 if (!msg) {
451 TME("Du gibst " + zname + " " + wen1 + ".");
452 TOB(dest, gname + " gibt Dir " + wen0 + ".");
453 SAY2(({dest}), gname + " gibt " + zname + " " + wen0 + ".");
454 } else if (pointerp(msg))
455 switch (sizeof(msg)) {
456 case 3:
457 TOB(dest, replace_personal(
458 msg[2], ({this_object(), o||wen0, dest||zname}), 1));
459 case 2:
460 SAY2(({dest, this_object()}), replace_personal(
461 msg[1], ({this_object(), o||wen0, dest||zname}), 1));
462 case 1:
463 TME(replace_personal(
464 msg[0], ({this_object(), o||wen1, dest||zname}), 1));
465 break;
466 default:
467 raise_error(sprintf(
468 "Falsches Format fuer P_GIVE_MSG: %O\n", o||wen1));
469 }
470
471 if (!query_once_interactive(dest))
472 dest->give_notify(o);
473
474 return 1;
475}
476
477varargs int show(object o, object whom, mixed msg)
478{
479 string zname, gname;
480 string wen0, wen2, long;
481
482 zname = whom ? whom->name(WEM, 1) : "allen";
483 gname = Name(WER, 1);
484
485 if (!msg)
486 msg = o->QueryProp(P_SHOW_MSG);
487
488 if (environment(o) == this_object() ||
489 environment(environment(o)) == this_object()) {
490 wen0 = o->name(WEN, 0);
491
492 /* Der Akkusativ muss mit dem unbestimmten Artikel gebildet werden,
493 * damit eventuelle Adjektive die richtige Endung besitzen.
494 * (ein kleines Schwert -> kleines Schwert -> Dein kleines Schwert)
495 */
496
497 if (o->QueryProp(P_ARTICLE) && member(wen0, ' ') >= 0) {
498 int obgender = o->QueryProp(P_GENDER);
499 int obnum = o->QueryProp(P_AMOUNT) > 1 ? PLURAL : SINGULAR;
500
501 // Wichtig: P_AMOUNT ist 0 fuer Objekte, die nicht von unit erben.
502 // Da unit.c kein P_AMOUNT==0 zulaesst, nehmen wir diesen Fall als
503 // singular an. *Rumata
504
505 wen2 = wen0[member(wen0, ' ')..];
506 wen0 = QueryPossPronoun(o, WEN, obnum) + wen2;
507
508 if (obnum == PLURAL || obgender == FEMALE)
509 wen2 = "Deine" + wen2;
510 else if (obgender == MALE)
511 wen2 = "Deinen" + wen2;
512 else
513 wen2 = "Dein" + wen2;
514 } else
515 wen2 = wen0;
516 } else
517 wen2 = wen0 = o->name(WEN, 1);
518
519 // vorher speichern, falls das Objekt im catch_tell() zerstoert wird
520 long = o->long(4);
521
522 if (!msg) {
523 TME("Du zeigst " + zname + " " + wen2 + ".");
524 if (!whom)
525 SAY(gname + " zeigt Dir " + wen0 + ".");
526 else {
527 TOB(whom, gname + " zeigt Dir " + wen0 + ".");
528 SAY2(({whom}), gname + " zeigt " + zname + " " + wen0 + ".");
529 }
530 } else if (pointerp(msg))
531 switch (sizeof(msg)) {
532 case 3:
533 if (whom)
534 TOB(whom, replace_personal(
535 msg[2], ({this_object(), o||wen0, whom||zname}), 1));
536 else
537 SAY(replace_personal(
538 msg[2], ({this_object(), o||wen0, whom||zname}), 1));
539 case 2:
540 if (whom)
541 SAY2(({whom, this_object()}), replace_personal(
542 msg[1], ({this_object(), o||wen0, whom||zname}), 1));
543 case 1:
544 TME(replace_personal(
545 msg[0], ({this_object(), o||wen2, whom||zname}), 1));
546 break;
547 default:
548 raise_error(sprintf(
549 "Falsches Format fuer P_SHOW_MSG: %O\n", o||wen0));
550 }
551
552 if (!whom)
553 SAY(long);
554 else {
555 TOB(whom, long);
556 if (!query_once_interactive(whom))
557 whom->show_notify(o);
558 }
559
560 return 1;
561}
562
563
564/***************************** Hilfsfunktionen *****************************/
565
566/* private object *__find_objects(string *tokens, object env, int is_source);
567 * object *find_objects(string what, object env, int is_source);
568 *
569 * Sucht im Raum und im Spieler (oder alternativ in der angegebenen Umgebung)
570 * nach den in tokens/what bezeichneten Objekten. is_source bestimmt die
571 * erwartete grammatische Form (0 fuer "topf auf herd" und 1 fuer "topf von
572 * herd", siehe Manpage).
573 */
574
575private object *__find_objects(string *tokens, object env, int is_source)
576{
577 object ob, *obs;
578
579 // is_source == 0: Objekt soll nicht bewegt werden ("topf auf herd")
580 // 1: Objekt soll bewegt werden ("topf von herd")
581 // 2: intern
582
Zesstrae8d5a0b2018-11-16 23:21:37 +0100583 // ganz am Ende von den tokens steht ggf. der vom User gewuenschte Anfang
584 // der Suche nache dem Objekt (z.B. "fackel aus truhe hier" oder "seil aus
585 // paket in mir".
MG Mud User88f12472016-06-24 23:31:02 +0200586 if (!env && sizeof(tokens) > 1 && tokens[<1] == "hier") {
587 tokens = tokens[..<2];
588 env = environment();
589 }
590 else if (!env && sizeof(tokens) > 2 && tokens[<2] == "in")
591 {
592 if (tokens[<1] == "mir" ||
593 tokens[<1] == "dir") {
594 tokens = tokens[..<3];
595 env = this_object();
596 }
597 else if (tokens[<1] == "raum") {
598 tokens = tokens[..<3];
599 env = environment();
600 }
601 }
602
603 for (int i = sizeof(tokens)-1; i > 1; i--) {
Zesstrae8d5a0b2018-11-16 23:21:37 +0100604 // wird fangen am Ende der Tokens an und arbeiten uns wortweise nach
605 // vorne, um ein Objekt zu finden. (z.B. "... in paket 12" wuerde 2
606 // Durchlaeufe brauchen)
MG Mud User88f12472016-06-24 23:31:02 +0200607 if (env)
608 ob = present(implode(tokens[i..], " "), env);
609 else
610 ob = present(implode(tokens[i..], " "), environment()) ||
611 present(implode(tokens[i..], " "), this_object());
612
613 if (!ob)
614 continue;
615
Zesstrae8d5a0b2018-11-16 23:21:37 +0100616 // aus Lebewesen darf man nix rausnehmen oder reingucken
MG Mud User88f12472016-06-24 23:31:02 +0200617 if (living(ob)) {
618 NF("Aber " + ob->name(WER, 1) + " lebt doch!");
619 continue;
620 }
621
Zesstrae8d5a0b2018-11-16 23:21:37 +0100622 // und aus geschlossenen Containern auch nicht.
MG Mud User88f12472016-06-24 23:31:02 +0200623 if (ob->QueryProp(P_CNT_STATUS)) {
624 NF("Aber " + ob->name(WER, 1) + " ist doch geschlossen!");
625 continue;
626 }
Zesstrae8d5a0b2018-11-16 23:21:37 +0100627 // Wenn was rausgenommen werden soll und jetzt vor dem gefundenen
628 // Container die passende Praeposition steht (z.B. "aus"), wird
629 // angenommen, dass der vordere Teil der Tokens zu aus diesem
630 // Container zu nehmende Objekt bezeichnet und in present_objects
631 // dieses Containers verzweigt.
MG Mud User88f12472016-06-24 23:31:02 +0200632 if (is_source != 0 &&
633 tokens[i-1] == ob->QueryProp(P_SOURCE_PREPOSITION))
634 return ob->present_objects(implode(tokens[..i-2], " "));
635
Zesstrae8d5a0b2018-11-16 23:21:37 +0100636 // Wenn vor dem gefundenen Objekt dessen normale Praeposition steht
637 // (z.B. "in", "auf"), wird rekursiv geschaut, ob der vordere Teil der
638 // Tokens erneut einen Container bezeichnet. is_source==2 wird
639 // uebergebeb, damit in der Rekursion nur Objekte vor der
640 // P_SOURCE_PREPOSITION geliefert werden, aber keine aus
641 // Environment/this_object() (s.u. nach der Schleife).
MG Mud User88f12472016-06-24 23:31:02 +0200642 if (tokens[i-1] == ob->QueryProp(P_PREPOSITION))
643 return __find_objects(tokens[..i-2], ob, is_source ? 2 : 0);
644
645 NF("Du kannst nichts " + tokens[i-1] + " " +
646 ob->name(WEM, 1) + " nehmen.");
647 }
648
649 if (is_source == 2)
650 return ({});
Zesstrae8d5a0b2018-11-16 23:21:37 +0100651 // wenn das for keine Container gefunden hat (auch: wenn tokens zu kurz
652 // fuers for), wird im uebergebenen env geguckt, ob der vorderste Rest von
653 // tokens nen Objekt bezeichnet.
654 // geguckt, ob nen pass
MG Mud User88f12472016-06-24 23:31:02 +0200655 if (env)
656 return env->present_objects(implode(tokens, " "));
657
Zesstrae8d5a0b2018-11-16 23:21:37 +0100658 // Und wenn kein env uebergeben und gefunden wurde, wird geguckt, ob unser
659 // Environment nen passendes Objekt fuer tokens hat...
MG Mud User88f12472016-06-24 23:31:02 +0200660 if (environment() &&
661 sizeof(obs = environment()->present_objects(implode(tokens, " "))))
662 return obs;
Zesstrae8d5a0b2018-11-16 23:21:37 +0100663 // oder eben wir selbst.
MG Mud User88f12472016-06-24 23:31:02 +0200664 return present_objects(implode(tokens, " "));
665}
666
667object *find_objects(string what, object env, int is_source)
668{
669 if (!stringp(what) || !sizeof(what))
670 return ({});
671 return __find_objects(explode(what, " "), env, is_source);
672}
673
674
675/* varargs int drop_objects(string str, mixed msg);
676 * varargs int put_objects(string str, int casus, string verb, mixed msg);
677 * varargs int pick_objects(string str, int flag, mixed msg);
678 * varargs int give_objects(string str, mixed msg);
679 * varargs int show_objects(string str, mixed msg);
680 *
681 * Ein Befehl wie "wirf waffen weg" resultiert in einem Aufruf von
682 * drop_objects("waffen"). Diese Funktionen sind hauptsaechlich fuer die
683 * Behandlung der jeweiligen Kommandos vorgesehen, koennen jedoch auch fuer
684 * eigene Befehle verwendet werden. put_objects() erwartet ausserdem den
685 * Kasus ("Du kannst nichts an DER Pinwand befestigen.") und das verwendete
686 * Verb in der Gundform ("befestigen"). Das Flag fuer pick_objects() gibt
687 * an, ob das Objekt auch einfach herumliegen darf ("nimm ...") oder nicht
688 * ("hole ..."). Gibt bei Erfolg 1, sonst 0 zurueck.
689 */
690
691varargs int drop_objects(string str, mixed msg)
692{
693 object *obs;
694
695 if (!sizeof(obs = find_objects(str, this_object(), 1)))
696 return 0;
697
Zesstra7dbdec52018-11-12 22:49:03 +0100698 last_moved_objects=({});
699 last_moved_where = 0;
MG Mud User88f12472016-06-24 23:31:02 +0200700 foreach (object o: obs) {
701 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100702 if (drop(o, msg) == 1)
703 last_moved_objects+=({o});
MG Mud User88f12472016-06-24 23:31:02 +0200704
705 if (get_eval_cost() < 100000) {
706 TME("Den Rest behaeltst Du erst mal.");
MG Mud User88f12472016-06-24 23:31:02 +0200707 return 1;
708 }
709 }
MG Mud User88f12472016-06-24 23:31:02 +0200710 return 1;
711}
712
713varargs int put_objects(string str, int casus, string verb, mixed msg)
714{
715 object *obs, dest, *no_move;
716
717 if (!stringp(str) || !sizeof(str)) return 0;
718
719 string *tokens = explode(str, " ");
720 int allow_room = 1;
721 int allow_me = 1;
722
723 if (sizeof(tokens) > 1 && tokens[<1] == "hier") {
724 tokens = tokens[..<2];
725 allow_me = 0;
726 } else if (sizeof(tokens) > 2 && tokens[<2] == "in")
727 if (tokens[<1] == "mir" ||
728 tokens[<1] == "dir") {
729 tokens = tokens[..<3];
730 allow_room = 0;
731 } else if (tokens[<1] == "raum") {
732 tokens = tokens[..<3];
733 allow_me = 0;
734 }
735
736 for (int i = sizeof(tokens)-1; i > 1; i--) {
737 if (!(dest = allow_room && present(implode(tokens[i..], " "),
738 environment())) &&
739 !(dest = allow_me && present(implode(tokens[i..], " "),
740 this_object())))
741 continue;
742
743 if (living(dest)) {
744 NF("Aber " + dest->name(WER, 1) + " lebt doch!");
745 continue;
746 }
747/*
748 if (verb == "legen" && !dest->QueryProp(P_TRAY)) {
749 NF("Du kannst nichts auf " + dest->name(WEN, 1) + " legen.");
750 continue;
751 }
752*/
753 if (verb == "stecken" && !dest->QueryProp(P_CONTAINER)) {
754 NF("Du kannst in " + dest->name(WEN, 1) + " nichts reinstecken.");
755 continue;
756 }
757
758 if (dest->QueryProp(P_CNT_STATUS)) {
759 NF("Aber " + dest->name(WER, 1) + " ist doch geschlossen!");
760 continue;
761 }
762
763 if (tokens[i-1] != dest->QueryProp(P_DEST_PREPOSITION)) {
764 NF("Du kannst nichts " + tokens[i-1] + " " +
765 dest->name(casus, 1) + " " + verb + ".");
766 continue;
767 }
768
769 if (!sizeof(obs = __find_objects(tokens[..i-2], 0, 1) - ({ dest }))) {
770 NF("WAS moechtest Du " + tokens[i-1] + " " +
771 dest->name(casus, 1) + " " + verb + "?");
772 return 0;
773 }
774
775 if (sizeof(no_move = obs & all_inventory(dest))) {
776 TME(capitalize(CountUp(map_objects(no_move, "name", WER, 1))) +
777 (sizeof(no_move) == 1 ? " ist" : " sind") +
778 " doch bereits in " + dest->name(WEM,1) + ".");
779 if (!sizeof(obs -= no_move))
780 return 0;
781 }
782
Zesstra7dbdec52018-11-12 22:49:03 +0100783 last_moved_objects = ({});
784 last_moved_where = dest;
785
MG Mud User88f12472016-06-24 23:31:02 +0200786 foreach (object o: obs) {
787 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100788 if (put(o, dest, msg) == 1)
789 last_moved_objects += ({o});
MG Mud User88f12472016-06-24 23:31:02 +0200790
791 if (get_eval_cost() < 100000) {
792 TME("Den Rest laesst Du erst mal, wo er ist.");
MG Mud User88f12472016-06-24 23:31:02 +0200793 return 1;
794 }
795 }
796
MG Mud User88f12472016-06-24 23:31:02 +0200797 return 1;
798 }
799
800 return 0;
801}
802
803varargs int pick_objects(string str, int flag, mixed msg)
804{
805 object *obs;
806
807 if (((int)QueryProp(P_MAX_HANDS)) < 1){
808 NF("Ohne Haende kannst Du nichts nehmen.");
809 return 0;
810 }
811
812 if (!sizeof(obs = find_objects(str, 0, 1) - all_inventory()
Zesstra7dbdec52018-11-12 22:49:03 +0100813 - (flag ? all_inventory(environment()) : ({}))))
MG Mud User88f12472016-06-24 23:31:02 +0200814 return 0;
815
Zesstra7dbdec52018-11-12 22:49:03 +0100816 last_moved_objects = ({});
817 last_moved_where = this_object();
MG Mud User88f12472016-06-24 23:31:02 +0200818 foreach (object o: obs) {
819 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100820 if (pick(o, msg) == 1)
821 last_moved_objects += ({o});
MG Mud User88f12472016-06-24 23:31:02 +0200822
823 if (get_eval_cost() < 100000) {
824 TME("Den Rest laesst Du erst mal liegen.");
MG Mud User88f12472016-06-24 23:31:02 +0200825 return 1;
826 }
827 }
828
MG Mud User88f12472016-06-24 23:31:02 +0200829 return 1;
830}
831
832varargs int give_objects(string str, mixed msg)
833{
834 object *obs, dest;
Zesstra7dbdec52018-11-12 22:49:03 +0100835
MG Mud User88f12472016-06-24 23:31:02 +0200836 if (!stringp(str) || !sizeof(str)) return 0;
837
838 string *tokens = explode(str, " ");
839
840 if (((int)QueryProp(P_MAX_HANDS)) < 1){
841 NF("Ohne Haende kannst Du nichts weggeben.");
842 return 0;
843 }
844
845 for (int i = 0; i < sizeof(tokens)-1; i++) {
846 if (!(dest = present(implode(tokens[..i], " "), environment())))
847 continue;
848
849 if (!living(dest)) {
850 NF("Aber " + dest->name(WER, 1) + " lebt doch gar nicht!");
851 dest = 0;
852 continue;
853 }
854
855 if (!sizeof(obs = __find_objects(tokens[i+1..], 0, 1))) {
856 NF("WAS moechtest Du " + dest->name(WEM, 1)+" geben?");
857 dest = 0;
858 } else
859 break;
860 }
861
862 if (!dest) {
863 int pos;
864
865 if ((pos = strrstr(str, " an ")) >= 0) {
866 dest = present(str[pos+4..], environment());
867 // zu gebende Objekte in Env + Living suchen
868 obs = find_objects(str[..pos-1], 0, 1);
869 }
870 }
871
872 if (!dest || !living(dest) || !sizeof(obs))
873 return 0;
874
Zesstra7dbdec52018-11-12 22:49:03 +0100875 last_moved_objects = ({});
876 last_moved_where = dest;
MG Mud User88f12472016-06-24 23:31:02 +0200877 foreach (object o: obs) {
878 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100879 if (give(o, dest, msg) == 1)
880 last_moved_objects += ({o});
MG Mud User88f12472016-06-24 23:31:02 +0200881
882 if (get_eval_cost() < 100000) {
883 TME("Den Rest behaeltst Du erst mal.");
MG Mud User88f12472016-06-24 23:31:02 +0200884 return 1;
885 }
886 }
MG Mud User88f12472016-06-24 23:31:02 +0200887 return 1;
888}
889
890varargs int show_objects(string str, mixed msg)
891{
892 object *obs, whom;
Zesstra7dbdec52018-11-12 22:49:03 +0100893
MG Mud User88f12472016-06-24 23:31:02 +0200894 if (!stringp(str) || !sizeof(str))
895 return 0;
896
897 string *tokens = explode(str, " ");
898
899 for (int i = 0; i < sizeof(tokens)-1; i++) {
900 if (whom = present(implode(tokens[..i], " "), environment())) {
901 if (!living(whom)) {
902 NF("Aber " + whom->name(WER, 1) + " lebt doch gar nicht!");
903 continue;
904 }
905 } else {
906 if (i != 0 || tokens[0] != "allen")
907 continue;
908
909 if (!sizeof(filter(all_inventory(environment()) -
910 ({ this_object() }), #'living))) {
911 NF("Hier ist niemand, dem Du etwas zeigen koenntest!");
912 continue;
913 }
914 }
915
916 if (whom == this_object()) {
917 NF("Dazu solltest Du dann besser 'schau' benutzen!\n");
918 continue;
919 }
920
921 if (!sizeof(obs = __find_objects(tokens[i+1..], this_object(), 0)) &&
922 !sizeof(obs = __find_objects(tokens[i+1..], 0, 0)
923 - ({ this_object(), whom }))) {
924 NF("WAS moechtest Du " + (whom ? whom->name(WEM, 1) : "allen") +
925 " zeigen?");
926 continue;
927 }
928
Zesstra7dbdec52018-11-12 22:49:03 +0100929 last_moved_objects = ({});
930 last_moved_where = whom;
MG Mud User88f12472016-06-24 23:31:02 +0200931 foreach (object o: obs) {
932 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100933 if (show(o, whom, msg) == 1)
934 last_moved_objects += ({o});
MG Mud User88f12472016-06-24 23:31:02 +0200935
936 if (get_eval_cost() < 100000) {
937 TME("Das reicht erst mal.");
MG Mud User88f12472016-06-24 23:31:02 +0200938 return 1;
939 }
940 }
941
MG Mud User88f12472016-06-24 23:31:02 +0200942 return 1;
943 }
944
945 return 0;
946}
947
948object *moved_objects(void)
949{
950 return last_moved_objects;
951}
952
953object moved_where(void)
954{
955 return last_moved_where;
956}
957
958
959/************************* Die einzelnen Kommandos **************************/
960
961/* static int fallenlassen(string str)
962 * static int werfen(string str)
963 * static int legen(string str)
964 * static int stecken(string str)
965 * static int holen(string str)
966 * static int nehmen(string str)
967 * static int geben(string str)
968 * Minimale Wrapper fuer XXX_objects(), entfernen "fallen", "weg" bzw. "ab"
969 * aus den Argumenten und setzen entsprechende Standard-Fehlermeldungen.
970 *
971 * protected void add_put_and_get_commands()
972 * Registriert obige Funktionen per add_action().
973 */
974
975static int fallenlassen(string str)
976{
977 if (QueryProp(P_GHOST)) {
978 _notify_fail("Als Geist kannst Du nichts fallenlassen.\n");
979 return 0;
980 }
981
982 if (!str || str[<7..] != " fallen") {
983 _notify_fail("Lass etwas FALLEN, oder was meinst Du?\n");
984 return 0;
985 }
986
987 _notify_fail("WAS moechtest Du fallenlassen?\n");
988 return drop_objects(str[0..<8]);
989}
990
991static int werfen(string str)
992{
993 if (QueryProp(P_GHOST)) {
994 _notify_fail("Als Geist kannst Du nichts wegwerfen.\n");
995 return 0;
996 }
997
998 if (!str || str[<4..] != " weg") {
999 _notify_fail("Wirf etwas WEG, oder was meinst Du?\n");
1000 return 0;
1001 }
1002
1003 _notify_fail("WAS moechtest Du loswerden?\n");
1004 return drop_objects(str[0..<5]);
1005}
1006
1007static int legen(string str)
1008{
1009 if (QueryProp(P_GHOST)) {
1010 _notify_fail("Als Geist kannst Du nichts weglegen.\n");
1011 return 0;
1012 }
1013
1014 if (!str) {
1015 _notify_fail("Lege etwas AB, oder was meinst Du?\n");
1016 return 0;
1017 }
1018
1019 if (str[<3..] == " ab") {
1020 _notify_fail("WAS moechtest Du ablegen?\n");
1021 return drop_objects(str[0..<4]);
1022 }
1023
1024 if (str[<4..] == " weg") {
1025 _notify_fail("WAS moechtest Du weglegen?\n");
1026 return drop_objects(str[0..<5]);
1027 }
1028
1029 _notify_fail("WAS moechtest Du WOHIN legen?\n");
1030 return put_objects(str, WEN, "legen");
1031}
1032
1033static int stecken(string str)
1034{
1035 if (QueryProp(P_GHOST)) {
1036 _notify_fail("Das kannst Du in Deinem immateriellen Zustand nicht.\n");
1037 return 0;
1038 }
1039
1040 _notify_fail("WAS moechtest Du WOHIN stecken?\n");
1041 return put_objects(str, WEN, "stecken");
1042}
1043
1044static int holen(string str)
1045{
1046 if (QueryProp(P_GHOST)) {
1047 _notify_fail("Als Geist kannst Du nichts nehmen.\n");
1048 return 0;
1049 }
1050
1051 _notify_fail("WAS moechtest Du aus WAS holen?\n");
1052 return pick_objects(str, 1);
1053}
1054
1055static int nehmen(string str)
1056{
1057 if (QueryProp(P_GHOST)) {
1058 _notify_fail("Als Geist kannst Du nichts nehmen.\n");
1059 return 0;
1060 }
1061
1062 _notify_fail("WAS moechtest Du nehmen?\n");
1063 return pick_objects(str, 0);
1064}
1065
1066static int geben(string str)
1067{
1068 if (QueryProp(P_GHOST)) {
1069 _notify_fail("Als Geist kannst Du nichts weggeben.\n");
1070 return 0;
1071 }
1072
1073 _notify_fail("WEM moechtest Du WAS geben?\n");
1074 return give_objects(str);
1075}
1076
1077static int zeigen(string str)
1078{
1079 if (QueryProp(P_GHOST)) {
1080 _notify_fail("Als Geist kannst Du niemandem etwas zeigen.\n");
1081 return 0;
1082 }
1083
1084 _notify_fail("WEM moechtest Du WAS zeigen?\n");
1085 return show_objects(str);
1086}
1087
1088protected void add_put_and_get_commands(void)
1089{
1090 add_action("fallenlassen", "lass");
1091 add_action("fallenlassen", "lasse");
1092 add_action("werfen", "wirf");
1093 add_action("werfen", "werf");
1094 add_action("werfen", "werfe");
1095 add_action("legen", "leg");
1096 add_action("legen", "lege");
1097 add_action("stecken", "steck");
1098 add_action("stecken", "stecke");
1099 add_action("holen", "hol");
1100 add_action("holen", "hole");
1101 add_action("nehmen", "nimm");
1102 add_action("nehmen", "nehm");
1103 add_action("nehmen", "nehme");
1104 add_action("geben", "gebe");
1105 add_action("geben", "gib");
1106 add_action("zeigen", "zeig");
1107 add_action("zeigen", "zeige");
1108}
1109
1110
1111/********** Aus reinen Kompatibilitaetsgruenden weiterhin enthalten *********/
1112
1113object* find_obs(string str, int meth)
1114// gibt ein array zurueck mit allen Objekten die mit str angesprochen werden
1115{
1116 object inv;
1117 if (!str) return 0;
1118 if (str[<7..]==" in mir") {
1119 inv=ME;
1120 str=str[0..<8];
1121 }
1122 else if (str[<8..]==" in raum") {
1123 if (meth & PUT_GET_DROP) { // man kann nichts aus dem Raum wegwerfen
1124 _notify_fail("Du kannst nichts wegwerfen, das Du gar nicht hast.\n");
1125 return 0;
1126 }
1127 inv=environment();
1128 str=str[0..<9];
1129 }
1130 else if (meth & PUT_GET_DROP) inv=ME; // Raum bei drop uninteressant
1131 // else kein besonderes inv ausgewaehlt also inv=0
1132 if (!sizeof(str))
1133 return 0; // hier passt die bereits gesetzte _notify_fail
1134 else {
1135 object *obs;
1136 string con;
1137 if (sscanf(str, "%s aus %s", str, con)==2 ||
1138 sscanf(str, "%s in %s", str, con)==2 ||
1139 sscanf(str, "%s von %s", str, con)==2 ||
1140 sscanf(str, "%s vom %s", str, con)==2) {
1141 if (!inv) {
1142 if (!environment() || !(inv=present(con, environment())))
1143 inv=present(con, ME); // sowohl im env als auch im inv suchen
1144 }
1145 else inv=present(con, inv); // nur in ausgewaehltem inv suchen
1146 if (inv==ME) inv=0;
1147 if (!inv || !(inv->short())) {
1148 _notify_fail(break_string("Du hast hier aber kein '"+capitalize(con)
1149 +"'.",78));
1150 return 0;
1151 }
1152 if (living(inv)) {
1153 _notify_fail(break_string("Aber "+inv->name(WER,1)+" lebt doch!",78));
1154 return 0;
1155 }
1156 // wieso man aus Objekten die von std/tray abgeleitet werden etwas
1157 // nehmen koennen soll, versteh ich zwar nicht so ganz...
1158 if (!(inv->QueryProp(P_CONTAINER)) && !(inv->QueryProp(P_TRAY))) {
1159 _notify_fail(break_string("Du kannst nichts aus "+inv->name(WEM,1)
1160 +" nehmen.",78));
1161 return 0;
1162 }
1163 if (inv->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1164 _notify_fail(break_string("Aber "+inv->name(WER,1)
1165 +" ist doch geschlossen.", 78));
1166 return 0;
1167 }
1168 }
1169 else if (inv==ME && (meth & PUT_GET_TAKE)) { // nichts aus sich nehmen
1170 _notify_fail("Du kannst nichts nehmen, "
1171 "was Du schon bei Dir traegst.\n");
1172 return 0;
1173 }
1174 if (!inv && (meth & PUT_GET_TAKE))
1175 inv=environment(); // nichts nehmen was man schon hat
1176
1177 if (!inv) {
1178 if (environment()) {
1179 obs=(environment()->present_objects(str)||({}));
1180 if (!sizeof(obs)) obs+=(ME->present_objects(str)||({}));
1181 }
1182 else obs=(ME->present_objects(str) || ({}));
1183 }
1184 else obs=(inv->present_objects(str) || ({}));
1185 return obs-({ ME });
1186 }
1187 return(0);
1188}
1189
1190int pick_obj(object ob)
1191{
1192 object env;
1193
1194 if (!ob || ob == this_object() || environment(ob) == this_object()) return 0;
1195 if ((env=environment(ob)) != environment()) {
1196 if (!env->QueryProp(P_CONTAINER) && !env->QueryProp(P_TRAY)) {
1197 TME("Du kannst nichts aus " + env->name(WEM,1) + " nehmen.");
1198 return 1;
1199 }
1200 else if (env->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1201 TME("Aber " + env->name(WER, 1) + " ist doch geschlossen.");
1202 return 1;
1203 }
1204 }
1205 if (ob->IsUnit() && ob->QueryProp(P_AMOUNT)<0) {
1206 TME("Du kannst nicht mehr nehmen als da ist.");
1207 return 1;
1208 }
1209 pick(ob);
1210 return 1;
1211}
1212
1213int drop_obj(object ob)
1214{
1215 if (!ob || ob==this_object() || environment(ob)!=this_object()) return 0;
1216 drop(ob);
1217 return 1;
1218}
1219
1220int put_obj(object ob, object where)
1221{
1222 object env;
1223
1224 if (ob == this_object() || ob == where || environment(ob) == where) return 0;
1225 env=environment(ob);
1226 if (!where->QueryProp(P_CONTAINER)) {
1227 TME("Du kannst in " + where->name(WEN,1) + " nix reinstecken.");
1228 return 1;
1229 }
1230 if (where->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1231 TME("Aber " + where->name(WER, 1) + " ist doch geschlossen.");
1232 return 1;
1233 }
1234 if (env!=environment(this_object()) && env!=this_object()) {
1235 _notify_fail("Da kommst du so nicht ran.\n");
1236 return 0;
1237 }
1238 put(ob, where);
1239 return 1;
1240}
1241
1242int give_obj(object ob, object where)
1243{
1244 object env;
1245
1246 if (environment(ob)!=this_object()) {
1247 TME("Das solltest Du erstmal nehmen.");
1248 return 1;
1249 }
1250 if (!ob || ob == this_object() || ob == where ||
1251 environment(where)!=environment())
1252 return 0;
1253 if (environment(ob) == where) {
1254 _notify_fail("Das Ziel ist in dem zu gebenden Object enthalten!\n");
1255 return 0;
1256 }
1257 if (environment(ob)!=this_object()) {
1258 TME("Das hast Du nicht.");
1259 return 1;
1260 }
1261 give(ob, where);
1262 return 1;
1263}