blob: 412a3418574e9f9a2461b94140b761c3ca24a729 [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;
Zesstra42495e72019-11-23 16:01:25 +0100136 <string|int> str;
MG Mud User88f12472016-06-24 23:31:02 +0200137
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:
Arathorn25568d42019-12-03 00:27:24 +0100184 str = o->QueryProp(P_NODROP);
185 if (o && stringp(str) && sizeof(str))
MG Mud User88f12472016-06-24 23:31:02 +0200186 return str;
187
188 if (dest == environment())
189 return "Du kannst " + wen1 + " nicht wegwerfen!";
190
191 if (living(dest))
192 return "Du kannst " + wen1 + " nicht weggeben.";
193
194 return "So wirst Du " + wen1 + " nicht los...";
195
196 case ME_CANT_BE_TAKEN:
Arathorn25568d42019-12-03 00:27:24 +0100197 str = o->QueryProp(P_NODROP);
198 if (o && stringp(str) && sizeof(str))
MG Mud User88f12472016-06-24 23:31:02 +0200199 return str;
200
201 if (stringp(str = environment(o)->QueryProp(P_NOLEAVE_MSG)))
202 return capitalize(
203 replace_personal(str, ({o, environment(o)}), 1));
204
205 //if (dest != environment())
206 // return "Du kannst " + wen1 + " nicht einmal nehmen.";
207
208 return "Du kannst " + wen1 + " nicht nehmen.";
209
210 case ME_CANT_BE_INSERTED:
211 if (stringp(str = dest->QueryProp(P_NOINSERT_MSG)))
212 return capitalize(replace_personal(str, ({o, dest}), 1));
213
214 if (dest == environment())
215 return "Das darfst Du hier nicht ablegen.";
216
217 if (dest == this_object())
218 return "Du kannst " + wen1 + " nicht nehmen.";
219
220 if (living(dest))
221 return "Das kannst Du " + dest->name(WEM, 1) + " nicht geben.";
222
223 return capitalize(wen0 + " kannst Du dort nicht hineinstecken.");
224
225 case ME_CANT_LEAVE_ENV:
226 // ME_CANT_LEAVE_ENV kann nur auftreten, wenn o ein Environment
227 // hat, deshalb kein Check dadrauf
228 if (stringp(str = environment(o)->QueryProp(P_NOLEAVE_MSG)))
229 return capitalize(
230 replace_personal(str, ({o, environment(o)}), 1));
231
232 if (environment(o) != this_object())
233 return "Du kannst " + wen1 + " nicht nehmen.";
234
235 if (dest == environment())
236 return "Du kannst " + wen1 + " nicht wegwerfen!";
237
238 if (living(dest))
239 return "Du kannst " + wen1 + " nicht weggeben.";
240
241 return "So wirst Du " + wen1 + " nicht los...";
242
243 case ME_TOO_HEAVY_FOR_ENV:
244 if (stringp(str = dest->QueryProp(P_ENV_TOO_HEAVY_MSG)))
245 return capitalize(replace_personal(str, ({o, dest}), 1));
246
247 if (environment(dest) == this_object())
248 return dest->Name(WER, 1) +
249 " wuerde Dir dann zu schwer werden.";
250
251 return (stringp(str = environment(dest)->Name(WER, 1))
252 && sizeof(str) ? str : "Der Raum") +
253 " wuerde dann zu schwer werden.";
254
255 case TOO_MANY_OBJECTS:
256 if (stringp(str = dest->QueryProp(P_TOO_MANY_MSG)))
257 return capitalize(replace_personal(str, ({o, dest}), 1));
258
259 if (dest == this_object())
260 return "Soviele Gegenstaende kannst Du unmoeglich tragen!";
261
262 if (dest == environment())
263 return "Dafuer ist hier nicht mehr genug Platz.";
264
265 if (living(dest))
266 return dest->Name(WER, 1) + " kann " + wen0 +
267 " nicht mehr tragen.";
268
269 return "Dafuer ist nicht mehr genug Platz in " +
270 dest->name(WEM, 1) + ".";
271
272 default:
273 if (dest == this_object())
274 return "Du kannst " + wen1 + " nicht nehmen.";
275
276 if (dest == environment())
277 return "Du kannst " + wen1 + " nicht wegwerfen!";
278
279 if (living(dest))
280 return "Du kannst " + wen1 + " nicht weggeben.";
281
282 return capitalize(wen0 + " kannst Du dort nicht hineinstecken.");
283 }
284 return 0; // NOT REACHED
285}
286
287
288/* varargs int drop(object o, mixed msg)
289 * varargs int put(object o, object dest, mixed msg)
290 * varargs int pick(object o, mixed msg)
291 * varargs int give(object o, object dest, mixed msg)
292 * varargs int show(object o, object dest, mixed msg)
293 *
294 * Der Spieler nimmt/legt/gibt/zeigt/laesst ein Objekt fallen, wobei die
295 * entsprechenden oder optional abweichende (im Format von P_XXX_MSG) oder
296 * gar keine (msg == 1) Meldungen ausgegeben werden. Es liegt in der
297 * Verantwortung des Rufenden, sinnvolle Werte zu uebergeben; insbesondere
298 * wird nicht geprueft, ob sich die Objekte in der Reichweite des Spielers
299 * befinden. Gibt 1 zurueck, wenn das Objekt bewegt wurde, sonst 0.
300 */
301
302varargs int drop(object o, mixed msg)
303{
304 string str;
305
306 // vorher speichern, falls das Objekt zerstoert wird
307 cl = symbol_function("name", o);
308 wen0 = funcall(cl, WEN, 0);
309 wen1 = funcall(cl, WEN, 1);
310 wer0 = 0;
311
312 if (!msg)
313 msg = o->QueryProp(P_DROP_MSG);
314
315 if (str = put_or_get(o, environment())) {
316 TME(str);
317 return 0;
318 }
319
320 if (!msg) {
321 TME("Du laesst " + wen1 + " fallen.");
322 SAY(Name(WER,1) + " laesst " + wen0 + " fallen.");
323 } else if (pointerp(msg))
324 switch (sizeof(msg)) {
325 // Wenn es zwei Strings gibt, geht die 2. ans Environment
326 case 2:
327 SAY(replace_personal(msg[1], ({this_object(), o||wen0}), 1));
328 case 1:
329 TME(replace_personal(msg[0], ({this_object(), o||wen1}), 1));
330 break;
331 default:
332 raise_error(sprintf(
333 "Falsches Format fuer P_DROP_MSG: %O\n", o||wen1));
334 }
335
336 return 1;
337}
338
339varargs int put(object o, object dest, mixed msg)
340{
341 string str;
342
343 // Falls das jemand von aussen ruft und Schrott uebergibt...
344 //if (living(dest))
345 // raise_error(sprintf("Lebendes Ziel fuer put(): %O\n", dest));
346 if (dest == environment())
347 raise_error("Ziel fuer put() ist Umgebung des Spielers\n");
348
349 // vorher speichern, falls das Objekt zerstoert wird
350 cl = symbol_function("name", o);
351 wen0 = funcall(cl, WEN, 0);
352 wen1 = funcall(cl, WEN, 1);
353 wer0 = funcall(cl, WER, 0);
354
355 if (!msg)
356 msg = o->QueryProp(P_PUT_MSG);
357
358 if (str = put_or_get(o, dest)) {
359 TME(str);
360 return 0;
361 }
362
363
364 if (!msg) {
Zesstrabc1e21c2016-07-24 14:43:54 +0200365 TME("Du steckst " + wen1 + " "
366 + dest->QueryProp(P_DEST_PREPOSITION) + " "
367 + dest->name(WEN, 1) + ".");
MG Mud User88f12472016-06-24 23:31:02 +0200368 if (environment())
Zesstrabc1e21c2016-07-24 14:43:54 +0200369 SAY(Name(WER, 1) + " steckt " + wen0 + " "
370 + dest->QueryProp(P_DEST_PREPOSITION) + " "
371 + dest->name(WEN, 0) + ".");
MG Mud User88f12472016-06-24 23:31:02 +0200372 }
373 else if (pointerp(msg)) {
374 switch (sizeof(msg)) {
375 case 2:
376 if (environment())
377 SAY(replace_personal(msg[1], ({this_object(), o||wen0, dest}), 1));
378 case 1:
379 TME(replace_personal(msg[0], ({this_object(), o||wen1, dest}), 1));
380 break;
381 default:
382 raise_error(sprintf(
383 "Falsches Format fuer P_PUT_MSG: %O\n",o||wen1));
384 }
385 }
386
387 return 1;
388}
389
390varargs int pick(object o, mixed msg)
391{
392 string str;
393
394 // vorher speichern, falls das Objekt zerstoert wird
395 cl = symbol_function("name", o);
396 wen0 = 0;
397 wen1 = funcall(cl, WEN, 1);
398 wer0 = 0;
399
400 if (!msg)
401 msg = o->QueryProp(P_PICK_MSG);
402
403 if (str = put_or_get(o, this_object())) {
404 TME(str);
405 return 0;
406 }
407
408 if (!msg) {
409 TME("Du nimmst " + wen1 + ".");
410 SAY(Name(WER, 1) + " nimmt " + wen1 + ".");
411 } else if (pointerp(msg))
412 switch (sizeof(msg)) {
413 case 2:
414 SAY(replace_personal(msg[1], ({this_object(), o||wen1}), 1));
415 case 1:
416 TME(replace_personal(msg[0], ({this_object(), o||wen1}), 1));
417 break;
418 default:
419 raise_error(sprintf(
420 "Falsches Format fuer P_PICK_MSG: %O\n", o||wen1));
421 }
422
423 return 1;
424}
425
426varargs int give(object o, object dest, mixed msg)
427{
428 string zname, gname;
429 string str;
430
431 // Falls das jemand von aussen ruft und Schrott uebergibt...
432 if (!living(dest))
433 raise_error(sprintf("Totes Ziel fuer give(): %O\n", dest));
434
435 zname = dest->name(WEM, 1);
436 gname = Name(WER, 1);
437
438 // vorher speichern, falls das Objekt zerstoert wird
439 cl = symbol_function("name", o);
440 wen0 = funcall(cl, WEN, 0);
441 wen1 = funcall(cl, WEN, 1);
442 wer0 = 0;
443
444 if (!msg)
445 msg = o->QueryProp(P_GIVE_MSG);
446
447 if (str = put_or_get(o, dest)) {
448 TME(str);
449 return 0;
450 }
451
452 if (!msg) {
453 TME("Du gibst " + zname + " " + wen1 + ".");
454 TOB(dest, gname + " gibt Dir " + wen0 + ".");
455 SAY2(({dest}), gname + " gibt " + zname + " " + wen0 + ".");
456 } else if (pointerp(msg))
457 switch (sizeof(msg)) {
458 case 3:
459 TOB(dest, replace_personal(
460 msg[2], ({this_object(), o||wen0, dest||zname}), 1));
461 case 2:
462 SAY2(({dest, this_object()}), replace_personal(
463 msg[1], ({this_object(), o||wen0, dest||zname}), 1));
464 case 1:
465 TME(replace_personal(
466 msg[0], ({this_object(), o||wen1, dest||zname}), 1));
467 break;
468 default:
469 raise_error(sprintf(
470 "Falsches Format fuer P_GIVE_MSG: %O\n", o||wen1));
471 }
472
473 if (!query_once_interactive(dest))
474 dest->give_notify(o);
475
476 return 1;
477}
478
479varargs int show(object o, object whom, mixed msg)
480{
481 string zname, gname;
482 string wen0, wen2, long;
483
484 zname = whom ? whom->name(WEM, 1) : "allen";
485 gname = Name(WER, 1);
486
487 if (!msg)
488 msg = o->QueryProp(P_SHOW_MSG);
489
490 if (environment(o) == this_object() ||
491 environment(environment(o)) == this_object()) {
492 wen0 = o->name(WEN, 0);
493
494 /* Der Akkusativ muss mit dem unbestimmten Artikel gebildet werden,
495 * damit eventuelle Adjektive die richtige Endung besitzen.
496 * (ein kleines Schwert -> kleines Schwert -> Dein kleines Schwert)
497 */
498
499 if (o->QueryProp(P_ARTICLE) && member(wen0, ' ') >= 0) {
500 int obgender = o->QueryProp(P_GENDER);
501 int obnum = o->QueryProp(P_AMOUNT) > 1 ? PLURAL : SINGULAR;
502
503 // Wichtig: P_AMOUNT ist 0 fuer Objekte, die nicht von unit erben.
504 // Da unit.c kein P_AMOUNT==0 zulaesst, nehmen wir diesen Fall als
505 // singular an. *Rumata
506
507 wen2 = wen0[member(wen0, ' ')..];
508 wen0 = QueryPossPronoun(o, WEN, obnum) + wen2;
509
510 if (obnum == PLURAL || obgender == FEMALE)
511 wen2 = "Deine" + wen2;
512 else if (obgender == MALE)
513 wen2 = "Deinen" + wen2;
514 else
515 wen2 = "Dein" + wen2;
516 } else
517 wen2 = wen0;
518 } else
519 wen2 = wen0 = o->name(WEN, 1);
520
521 // vorher speichern, falls das Objekt im catch_tell() zerstoert wird
522 long = o->long(4);
523
524 if (!msg) {
525 TME("Du zeigst " + zname + " " + wen2 + ".");
526 if (!whom)
527 SAY(gname + " zeigt Dir " + wen0 + ".");
528 else {
529 TOB(whom, gname + " zeigt Dir " + wen0 + ".");
530 SAY2(({whom}), gname + " zeigt " + zname + " " + wen0 + ".");
531 }
532 } else if (pointerp(msg))
533 switch (sizeof(msg)) {
534 case 3:
535 if (whom)
536 TOB(whom, replace_personal(
537 msg[2], ({this_object(), o||wen0, whom||zname}), 1));
538 else
539 SAY(replace_personal(
540 msg[2], ({this_object(), o||wen0, whom||zname}), 1));
541 case 2:
542 if (whom)
543 SAY2(({whom, this_object()}), replace_personal(
544 msg[1], ({this_object(), o||wen0, whom||zname}), 1));
545 case 1:
546 TME(replace_personal(
547 msg[0], ({this_object(), o||wen2, whom||zname}), 1));
548 break;
549 default:
550 raise_error(sprintf(
551 "Falsches Format fuer P_SHOW_MSG: %O\n", o||wen0));
552 }
553
554 if (!whom)
555 SAY(long);
556 else {
557 TOB(whom, long);
558 if (!query_once_interactive(whom))
559 whom->show_notify(o);
560 }
561
562 return 1;
563}
564
565
566/***************************** Hilfsfunktionen *****************************/
567
568/* private object *__find_objects(string *tokens, object env, int is_source);
569 * object *find_objects(string what, object env, int is_source);
570 *
571 * Sucht im Raum und im Spieler (oder alternativ in der angegebenen Umgebung)
572 * nach den in tokens/what bezeichneten Objekten. is_source bestimmt die
573 * erwartete grammatische Form (0 fuer "topf auf herd" und 1 fuer "topf von
574 * herd", siehe Manpage).
575 */
576
577private object *__find_objects(string *tokens, object env, int is_source)
578{
579 object ob, *obs;
580
581 // is_source == 0: Objekt soll nicht bewegt werden ("topf auf herd")
582 // 1: Objekt soll bewegt werden ("topf von herd")
Zesstra08e60732018-11-15 20:37:11 +0100583 // 2: Kennzeichnet rekursiven Aufruf, falls Objekt bewegt
584 // werden soll.
MG Mud User88f12472016-06-24 23:31:02 +0200585
Zesstrae8d5a0b2018-11-16 23:21:37 +0100586 // ganz am Ende von den tokens steht ggf. der vom User gewuenschte Anfang
587 // der Suche nache dem Objekt (z.B. "fackel aus truhe hier" oder "seil aus
588 // paket in mir".
MG Mud User88f12472016-06-24 23:31:02 +0200589 if (!env && sizeof(tokens) > 1 && tokens[<1] == "hier") {
590 tokens = tokens[..<2];
591 env = environment();
592 }
593 else if (!env && sizeof(tokens) > 2 && tokens[<2] == "in")
594 {
595 if (tokens[<1] == "mir" ||
596 tokens[<1] == "dir") {
597 tokens = tokens[..<3];
598 env = this_object();
599 }
600 else if (tokens[<1] == "raum") {
601 tokens = tokens[..<3];
602 env = environment();
603 }
604 }
605
606 for (int i = sizeof(tokens)-1; i > 1; i--) {
Zesstrae8d5a0b2018-11-16 23:21:37 +0100607 // wird fangen am Ende der Tokens an und arbeiten uns wortweise nach
608 // vorne, um ein Objekt zu finden. (z.B. "... in paket 12" wuerde 2
609 // Durchlaeufe brauchen)
MG Mud User88f12472016-06-24 23:31:02 +0200610 if (env)
611 ob = present(implode(tokens[i..], " "), env);
612 else
613 ob = present(implode(tokens[i..], " "), environment()) ||
614 present(implode(tokens[i..], " "), this_object());
615
616 if (!ob)
617 continue;
618
Zesstrae8d5a0b2018-11-16 23:21:37 +0100619 // aus Lebewesen darf man nix rausnehmen oder reingucken
MG Mud User88f12472016-06-24 23:31:02 +0200620 if (living(ob)) {
621 NF("Aber " + ob->name(WER, 1) + " lebt doch!");
622 continue;
623 }
624
Zesstrae8d5a0b2018-11-16 23:21:37 +0100625 // und aus geschlossenen Containern auch nicht.
MG Mud User88f12472016-06-24 23:31:02 +0200626 if (ob->QueryProp(P_CNT_STATUS)) {
627 NF("Aber " + ob->name(WER, 1) + " ist doch geschlossen!");
628 continue;
629 }
Zesstrae8d5a0b2018-11-16 23:21:37 +0100630 // Wenn was rausgenommen werden soll und jetzt vor dem gefundenen
631 // Container die passende Praeposition steht (z.B. "aus"), wird
632 // angenommen, dass der vordere Teil der Tokens zu aus diesem
633 // Container zu nehmende Objekt bezeichnet und in present_objects
634 // dieses Containers verzweigt.
MG Mud User88f12472016-06-24 23:31:02 +0200635 if (is_source != 0 &&
636 tokens[i-1] == ob->QueryProp(P_SOURCE_PREPOSITION))
637 return ob->present_objects(implode(tokens[..i-2], " "));
638
Zesstrae8d5a0b2018-11-16 23:21:37 +0100639 // Wenn vor dem gefundenen Objekt dessen normale Praeposition steht
640 // (z.B. "in", "auf"), wird rekursiv geschaut, ob der vordere Teil der
641 // Tokens erneut einen Container bezeichnet. is_source==2 wird
642 // uebergebeb, damit in der Rekursion nur Objekte vor der
643 // P_SOURCE_PREPOSITION geliefert werden, aber keine aus
644 // Environment/this_object() (s.u. nach der Schleife).
MG Mud User88f12472016-06-24 23:31:02 +0200645 if (tokens[i-1] == ob->QueryProp(P_PREPOSITION))
646 return __find_objects(tokens[..i-2], ob, is_source ? 2 : 0);
647
648 NF("Du kannst nichts " + tokens[i-1] + " " +
649 ob->name(WEM, 1) + " nehmen.");
650 }
651
652 if (is_source == 2)
653 return ({});
Zesstrae8d5a0b2018-11-16 23:21:37 +0100654 // wenn das for keine Container gefunden hat (auch: wenn tokens zu kurz
655 // fuers for), wird im uebergebenen env geguckt, ob der vorderste Rest von
656 // tokens nen Objekt bezeichnet.
657 // geguckt, ob nen pass
MG Mud User88f12472016-06-24 23:31:02 +0200658 if (env)
659 return env->present_objects(implode(tokens, " "));
660
Zesstrae8d5a0b2018-11-16 23:21:37 +0100661 // Und wenn kein env uebergeben und gefunden wurde, wird geguckt, ob unser
662 // Environment nen passendes Objekt fuer tokens hat...
MG Mud User88f12472016-06-24 23:31:02 +0200663 if (environment() &&
664 sizeof(obs = environment()->present_objects(implode(tokens, " "))))
665 return obs;
Zesstrae8d5a0b2018-11-16 23:21:37 +0100666 // oder eben wir selbst.
MG Mud User88f12472016-06-24 23:31:02 +0200667 return present_objects(implode(tokens, " "));
668}
669
670object *find_objects(string what, object env, int is_source)
671{
672 if (!stringp(what) || !sizeof(what))
673 return ({});
674 return __find_objects(explode(what, " "), env, is_source);
675}
676
677
678/* varargs int drop_objects(string str, mixed msg);
679 * varargs int put_objects(string str, int casus, string verb, mixed msg);
680 * varargs int pick_objects(string str, int flag, mixed msg);
681 * varargs int give_objects(string str, mixed msg);
682 * varargs int show_objects(string str, mixed msg);
683 *
684 * Ein Befehl wie "wirf waffen weg" resultiert in einem Aufruf von
685 * drop_objects("waffen"). Diese Funktionen sind hauptsaechlich fuer die
686 * Behandlung der jeweiligen Kommandos vorgesehen, koennen jedoch auch fuer
687 * eigene Befehle verwendet werden. put_objects() erwartet ausserdem den
688 * Kasus ("Du kannst nichts an DER Pinwand befestigen.") und das verwendete
689 * Verb in der Gundform ("befestigen"). Das Flag fuer pick_objects() gibt
690 * an, ob das Objekt auch einfach herumliegen darf ("nimm ...") oder nicht
691 * ("hole ..."). Gibt bei Erfolg 1, sonst 0 zurueck.
692 */
693
694varargs int drop_objects(string str, mixed msg)
695{
696 object *obs;
697
698 if (!sizeof(obs = find_objects(str, this_object(), 1)))
699 return 0;
700
Zesstra7dbdec52018-11-12 22:49:03 +0100701 last_moved_objects=({});
702 last_moved_where = 0;
MG Mud User88f12472016-06-24 23:31:02 +0200703 foreach (object o: obs) {
704 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100705 if (drop(o, msg) == 1)
706 last_moved_objects+=({o});
MG Mud User88f12472016-06-24 23:31:02 +0200707
708 if (get_eval_cost() < 100000) {
709 TME("Den Rest behaeltst Du erst mal.");
MG Mud User88f12472016-06-24 23:31:02 +0200710 return 1;
711 }
712 }
MG Mud User88f12472016-06-24 23:31:02 +0200713 return 1;
714}
715
716varargs int put_objects(string str, int casus, string verb, mixed msg)
717{
718 object *obs, dest, *no_move;
719
720 if (!stringp(str) || !sizeof(str)) return 0;
721
722 string *tokens = explode(str, " ");
723 int allow_room = 1;
724 int allow_me = 1;
725
726 if (sizeof(tokens) > 1 && tokens[<1] == "hier") {
727 tokens = tokens[..<2];
728 allow_me = 0;
729 } else if (sizeof(tokens) > 2 && tokens[<2] == "in")
730 if (tokens[<1] == "mir" ||
731 tokens[<1] == "dir") {
732 tokens = tokens[..<3];
733 allow_room = 0;
734 } else if (tokens[<1] == "raum") {
735 tokens = tokens[..<3];
736 allow_me = 0;
737 }
738
739 for (int i = sizeof(tokens)-1; i > 1; i--) {
740 if (!(dest = allow_room && present(implode(tokens[i..], " "),
741 environment())) &&
742 !(dest = allow_me && present(implode(tokens[i..], " "),
743 this_object())))
744 continue;
745
746 if (living(dest)) {
747 NF("Aber " + dest->name(WER, 1) + " lebt doch!");
748 continue;
749 }
750/*
751 if (verb == "legen" && !dest->QueryProp(P_TRAY)) {
752 NF("Du kannst nichts auf " + dest->name(WEN, 1) + " legen.");
753 continue;
754 }
755*/
756 if (verb == "stecken" && !dest->QueryProp(P_CONTAINER)) {
757 NF("Du kannst in " + dest->name(WEN, 1) + " nichts reinstecken.");
758 continue;
759 }
760
761 if (dest->QueryProp(P_CNT_STATUS)) {
762 NF("Aber " + dest->name(WER, 1) + " ist doch geschlossen!");
763 continue;
764 }
765
766 if (tokens[i-1] != dest->QueryProp(P_DEST_PREPOSITION)) {
767 NF("Du kannst nichts " + tokens[i-1] + " " +
768 dest->name(casus, 1) + " " + verb + ".");
769 continue;
770 }
771
772 if (!sizeof(obs = __find_objects(tokens[..i-2], 0, 1) - ({ dest }))) {
773 NF("WAS moechtest Du " + tokens[i-1] + " " +
774 dest->name(casus, 1) + " " + verb + "?");
775 return 0;
776 }
777
778 if (sizeof(no_move = obs & all_inventory(dest))) {
779 TME(capitalize(CountUp(map_objects(no_move, "name", WER, 1))) +
780 (sizeof(no_move) == 1 ? " ist" : " sind") +
781 " doch bereits in " + dest->name(WEM,1) + ".");
782 if (!sizeof(obs -= no_move))
783 return 0;
784 }
785
Zesstra7dbdec52018-11-12 22:49:03 +0100786 last_moved_objects = ({});
787 last_moved_where = dest;
788
MG Mud User88f12472016-06-24 23:31:02 +0200789 foreach (object o: obs) {
790 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100791 if (put(o, dest, msg) == 1)
792 last_moved_objects += ({o});
MG Mud User88f12472016-06-24 23:31:02 +0200793
794 if (get_eval_cost() < 100000) {
795 TME("Den Rest laesst Du erst mal, wo er ist.");
MG Mud User88f12472016-06-24 23:31:02 +0200796 return 1;
797 }
798 }
799
MG Mud User88f12472016-06-24 23:31:02 +0200800 return 1;
801 }
802
803 return 0;
804}
805
806varargs int pick_objects(string str, int flag, mixed msg)
807{
808 object *obs;
809
Arathorn9f22a9c2019-12-03 00:11:22 +0100810 if (QueryProp(P_MAX_HANDS) < 1){
MG Mud User88f12472016-06-24 23:31:02 +0200811 NF("Ohne Haende kannst Du nichts nehmen.");
812 return 0;
813 }
814
815 if (!sizeof(obs = find_objects(str, 0, 1) - all_inventory()
Zesstra7dbdec52018-11-12 22:49:03 +0100816 - (flag ? all_inventory(environment()) : ({}))))
MG Mud User88f12472016-06-24 23:31:02 +0200817 return 0;
818
Zesstra7dbdec52018-11-12 22:49:03 +0100819 last_moved_objects = ({});
820 last_moved_where = this_object();
MG Mud User88f12472016-06-24 23:31:02 +0200821 foreach (object o: obs) {
822 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100823 if (pick(o, msg) == 1)
824 last_moved_objects += ({o});
MG Mud User88f12472016-06-24 23:31:02 +0200825
826 if (get_eval_cost() < 100000) {
827 TME("Den Rest laesst Du erst mal liegen.");
MG Mud User88f12472016-06-24 23:31:02 +0200828 return 1;
829 }
830 }
831
MG Mud User88f12472016-06-24 23:31:02 +0200832 return 1;
833}
834
835varargs int give_objects(string str, mixed msg)
836{
837 object *obs, dest;
Zesstra7dbdec52018-11-12 22:49:03 +0100838
MG Mud User88f12472016-06-24 23:31:02 +0200839 if (!stringp(str) || !sizeof(str)) return 0;
840
841 string *tokens = explode(str, " ");
842
Arathorn9f22a9c2019-12-03 00:11:22 +0100843 if (QueryProp(P_MAX_HANDS) < 1){
MG Mud User88f12472016-06-24 23:31:02 +0200844 NF("Ohne Haende kannst Du nichts weggeben.");
845 return 0;
846 }
847
848 for (int i = 0; i < sizeof(tokens)-1; i++) {
849 if (!(dest = present(implode(tokens[..i], " "), environment())))
850 continue;
851
852 if (!living(dest)) {
853 NF("Aber " + dest->name(WER, 1) + " lebt doch gar nicht!");
854 dest = 0;
855 continue;
856 }
857
858 if (!sizeof(obs = __find_objects(tokens[i+1..], 0, 1))) {
859 NF("WAS moechtest Du " + dest->name(WEM, 1)+" geben?");
860 dest = 0;
861 } else
862 break;
863 }
864
865 if (!dest) {
866 int pos;
867
868 if ((pos = strrstr(str, " an ")) >= 0) {
869 dest = present(str[pos+4..], environment());
870 // zu gebende Objekte in Env + Living suchen
871 obs = find_objects(str[..pos-1], 0, 1);
872 }
873 }
874
875 if (!dest || !living(dest) || !sizeof(obs))
876 return 0;
877
Zesstra7dbdec52018-11-12 22:49:03 +0100878 last_moved_objects = ({});
879 last_moved_where = dest;
MG Mud User88f12472016-06-24 23:31:02 +0200880 foreach (object o: obs) {
881 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100882 if (give(o, dest, msg) == 1)
883 last_moved_objects += ({o});
MG Mud User88f12472016-06-24 23:31:02 +0200884
885 if (get_eval_cost() < 100000) {
886 TME("Den Rest behaeltst Du erst mal.");
MG Mud User88f12472016-06-24 23:31:02 +0200887 return 1;
888 }
889 }
MG Mud User88f12472016-06-24 23:31:02 +0200890 return 1;
891}
892
893varargs int show_objects(string str, mixed msg)
894{
895 object *obs, whom;
Zesstra7dbdec52018-11-12 22:49:03 +0100896
MG Mud User88f12472016-06-24 23:31:02 +0200897 if (!stringp(str) || !sizeof(str))
898 return 0;
899
900 string *tokens = explode(str, " ");
901
902 for (int i = 0; i < sizeof(tokens)-1; i++) {
903 if (whom = present(implode(tokens[..i], " "), environment())) {
904 if (!living(whom)) {
905 NF("Aber " + whom->name(WER, 1) + " lebt doch gar nicht!");
906 continue;
907 }
908 } else {
909 if (i != 0 || tokens[0] != "allen")
910 continue;
911
912 if (!sizeof(filter(all_inventory(environment()) -
913 ({ this_object() }), #'living))) {
914 NF("Hier ist niemand, dem Du etwas zeigen koenntest!");
915 continue;
916 }
917 }
918
919 if (whom == this_object()) {
920 NF("Dazu solltest Du dann besser 'schau' benutzen!\n");
921 continue;
922 }
923
924 if (!sizeof(obs = __find_objects(tokens[i+1..], this_object(), 0)) &&
925 !sizeof(obs = __find_objects(tokens[i+1..], 0, 0)
926 - ({ this_object(), whom }))) {
927 NF("WAS moechtest Du " + (whom ? whom->name(WEM, 1) : "allen") +
928 " zeigen?");
929 continue;
930 }
931
Zesstra7dbdec52018-11-12 22:49:03 +0100932 last_moved_objects = ({});
933 last_moved_where = whom;
MG Mud User88f12472016-06-24 23:31:02 +0200934 foreach (object o: obs) {
935 if (objectp(o))
Zesstra7dbdec52018-11-12 22:49:03 +0100936 if (show(o, whom, msg) == 1)
937 last_moved_objects += ({o});
MG Mud User88f12472016-06-24 23:31:02 +0200938
939 if (get_eval_cost() < 100000) {
940 TME("Das reicht erst mal.");
MG Mud User88f12472016-06-24 23:31:02 +0200941 return 1;
942 }
943 }
944
MG Mud User88f12472016-06-24 23:31:02 +0200945 return 1;
946 }
947
948 return 0;
949}
950
951object *moved_objects(void)
952{
953 return last_moved_objects;
954}
955
956object moved_where(void)
957{
958 return last_moved_where;
959}
960
961
962/************************* Die einzelnen Kommandos **************************/
963
964/* static int fallenlassen(string str)
965 * static int werfen(string str)
966 * static int legen(string str)
967 * static int stecken(string str)
968 * static int holen(string str)
969 * static int nehmen(string str)
970 * static int geben(string str)
971 * Minimale Wrapper fuer XXX_objects(), entfernen "fallen", "weg" bzw. "ab"
972 * aus den Argumenten und setzen entsprechende Standard-Fehlermeldungen.
973 *
974 * protected void add_put_and_get_commands()
975 * Registriert obige Funktionen per add_action().
976 */
977
978static int fallenlassen(string str)
979{
980 if (QueryProp(P_GHOST)) {
981 _notify_fail("Als Geist kannst Du nichts fallenlassen.\n");
982 return 0;
983 }
984
985 if (!str || str[<7..] != " fallen") {
986 _notify_fail("Lass etwas FALLEN, oder was meinst Du?\n");
987 return 0;
988 }
989
990 _notify_fail("WAS moechtest Du fallenlassen?\n");
991 return drop_objects(str[0..<8]);
992}
993
994static int werfen(string str)
995{
996 if (QueryProp(P_GHOST)) {
997 _notify_fail("Als Geist kannst Du nichts wegwerfen.\n");
998 return 0;
999 }
1000
1001 if (!str || str[<4..] != " weg") {
1002 _notify_fail("Wirf etwas WEG, oder was meinst Du?\n");
1003 return 0;
1004 }
1005
1006 _notify_fail("WAS moechtest Du loswerden?\n");
1007 return drop_objects(str[0..<5]);
1008}
1009
1010static int legen(string str)
1011{
1012 if (QueryProp(P_GHOST)) {
1013 _notify_fail("Als Geist kannst Du nichts weglegen.\n");
1014 return 0;
1015 }
1016
1017 if (!str) {
1018 _notify_fail("Lege etwas AB, oder was meinst Du?\n");
1019 return 0;
1020 }
1021
1022 if (str[<3..] == " ab") {
1023 _notify_fail("WAS moechtest Du ablegen?\n");
1024 return drop_objects(str[0..<4]);
1025 }
1026
1027 if (str[<4..] == " weg") {
1028 _notify_fail("WAS moechtest Du weglegen?\n");
1029 return drop_objects(str[0..<5]);
1030 }
1031
1032 _notify_fail("WAS moechtest Du WOHIN legen?\n");
1033 return put_objects(str, WEN, "legen");
1034}
1035
1036static int stecken(string str)
1037{
1038 if (QueryProp(P_GHOST)) {
1039 _notify_fail("Das kannst Du in Deinem immateriellen Zustand nicht.\n");
1040 return 0;
1041 }
1042
1043 _notify_fail("WAS moechtest Du WOHIN stecken?\n");
1044 return put_objects(str, WEN, "stecken");
1045}
1046
1047static int holen(string str)
1048{
1049 if (QueryProp(P_GHOST)) {
1050 _notify_fail("Als Geist kannst Du nichts nehmen.\n");
1051 return 0;
1052 }
1053
1054 _notify_fail("WAS moechtest Du aus WAS holen?\n");
1055 return pick_objects(str, 1);
1056}
1057
1058static int nehmen(string str)
1059{
1060 if (QueryProp(P_GHOST)) {
1061 _notify_fail("Als Geist kannst Du nichts nehmen.\n");
1062 return 0;
1063 }
1064
1065 _notify_fail("WAS moechtest Du nehmen?\n");
1066 return pick_objects(str, 0);
1067}
1068
1069static int geben(string str)
1070{
1071 if (QueryProp(P_GHOST)) {
1072 _notify_fail("Als Geist kannst Du nichts weggeben.\n");
1073 return 0;
1074 }
1075
1076 _notify_fail("WEM moechtest Du WAS geben?\n");
1077 return give_objects(str);
1078}
1079
1080static int zeigen(string str)
1081{
1082 if (QueryProp(P_GHOST)) {
1083 _notify_fail("Als Geist kannst Du niemandem etwas zeigen.\n");
1084 return 0;
1085 }
1086
1087 _notify_fail("WEM moechtest Du WAS zeigen?\n");
1088 return show_objects(str);
1089}
1090
1091protected void add_put_and_get_commands(void)
1092{
1093 add_action("fallenlassen", "lass");
1094 add_action("fallenlassen", "lasse");
1095 add_action("werfen", "wirf");
1096 add_action("werfen", "werf");
1097 add_action("werfen", "werfe");
1098 add_action("legen", "leg");
1099 add_action("legen", "lege");
1100 add_action("stecken", "steck");
1101 add_action("stecken", "stecke");
1102 add_action("holen", "hol");
1103 add_action("holen", "hole");
1104 add_action("nehmen", "nimm");
1105 add_action("nehmen", "nehm");
1106 add_action("nehmen", "nehme");
1107 add_action("geben", "gebe");
1108 add_action("geben", "gib");
1109 add_action("zeigen", "zeig");
1110 add_action("zeigen", "zeige");
1111}
1112
1113
1114/********** Aus reinen Kompatibilitaetsgruenden weiterhin enthalten *********/
1115
1116object* find_obs(string str, int meth)
1117// gibt ein array zurueck mit allen Objekten die mit str angesprochen werden
1118{
1119 object inv;
1120 if (!str) return 0;
1121 if (str[<7..]==" in mir") {
1122 inv=ME;
1123 str=str[0..<8];
1124 }
1125 else if (str[<8..]==" in raum") {
1126 if (meth & PUT_GET_DROP) { // man kann nichts aus dem Raum wegwerfen
1127 _notify_fail("Du kannst nichts wegwerfen, das Du gar nicht hast.\n");
1128 return 0;
1129 }
1130 inv=environment();
1131 str=str[0..<9];
1132 }
1133 else if (meth & PUT_GET_DROP) inv=ME; // Raum bei drop uninteressant
1134 // else kein besonderes inv ausgewaehlt also inv=0
1135 if (!sizeof(str))
1136 return 0; // hier passt die bereits gesetzte _notify_fail
1137 else {
1138 object *obs;
1139 string con;
1140 if (sscanf(str, "%s aus %s", str, con)==2 ||
1141 sscanf(str, "%s in %s", str, con)==2 ||
1142 sscanf(str, "%s von %s", str, con)==2 ||
1143 sscanf(str, "%s vom %s", str, con)==2) {
1144 if (!inv) {
1145 if (!environment() || !(inv=present(con, environment())))
1146 inv=present(con, ME); // sowohl im env als auch im inv suchen
1147 }
1148 else inv=present(con, inv); // nur in ausgewaehltem inv suchen
1149 if (inv==ME) inv=0;
1150 if (!inv || !(inv->short())) {
1151 _notify_fail(break_string("Du hast hier aber kein '"+capitalize(con)
1152 +"'.",78));
1153 return 0;
1154 }
1155 if (living(inv)) {
1156 _notify_fail(break_string("Aber "+inv->name(WER,1)+" lebt doch!",78));
1157 return 0;
1158 }
1159 // wieso man aus Objekten die von std/tray abgeleitet werden etwas
1160 // nehmen koennen soll, versteh ich zwar nicht so ganz...
1161 if (!(inv->QueryProp(P_CONTAINER)) && !(inv->QueryProp(P_TRAY))) {
1162 _notify_fail(break_string("Du kannst nichts aus "+inv->name(WEM,1)
1163 +" nehmen.",78));
1164 return 0;
1165 }
1166 if (inv->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1167 _notify_fail(break_string("Aber "+inv->name(WER,1)
1168 +" ist doch geschlossen.", 78));
1169 return 0;
1170 }
1171 }
1172 else if (inv==ME && (meth & PUT_GET_TAKE)) { // nichts aus sich nehmen
1173 _notify_fail("Du kannst nichts nehmen, "
1174 "was Du schon bei Dir traegst.\n");
1175 return 0;
1176 }
1177 if (!inv && (meth & PUT_GET_TAKE))
1178 inv=environment(); // nichts nehmen was man schon hat
1179
1180 if (!inv) {
1181 if (environment()) {
1182 obs=(environment()->present_objects(str)||({}));
1183 if (!sizeof(obs)) obs+=(ME->present_objects(str)||({}));
1184 }
1185 else obs=(ME->present_objects(str) || ({}));
1186 }
1187 else obs=(inv->present_objects(str) || ({}));
1188 return obs-({ ME });
1189 }
1190 return(0);
1191}
1192
1193int pick_obj(object ob)
1194{
1195 object env;
1196
1197 if (!ob || ob == this_object() || environment(ob) == this_object()) return 0;
1198 if ((env=environment(ob)) != environment()) {
1199 if (!env->QueryProp(P_CONTAINER) && !env->QueryProp(P_TRAY)) {
1200 TME("Du kannst nichts aus " + env->name(WEM,1) + " nehmen.");
1201 return 1;
1202 }
1203 else if (env->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1204 TME("Aber " + env->name(WER, 1) + " ist doch geschlossen.");
1205 return 1;
1206 }
1207 }
1208 if (ob->IsUnit() && ob->QueryProp(P_AMOUNT)<0) {
1209 TME("Du kannst nicht mehr nehmen als da ist.");
1210 return 1;
1211 }
1212 pick(ob);
1213 return 1;
1214}
1215
1216int drop_obj(object ob)
1217{
1218 if (!ob || ob==this_object() || environment(ob)!=this_object()) return 0;
1219 drop(ob);
1220 return 1;
1221}
1222
1223int put_obj(object ob, object where)
1224{
1225 object env;
1226
1227 if (ob == this_object() || ob == where || environment(ob) == where) return 0;
1228 env=environment(ob);
1229 if (!where->QueryProp(P_CONTAINER)) {
1230 TME("Du kannst in " + where->name(WEN,1) + " nix reinstecken.");
1231 return 1;
1232 }
1233 if (where->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1234 TME("Aber " + where->name(WER, 1) + " ist doch geschlossen.");
1235 return 1;
1236 }
1237 if (env!=environment(this_object()) && env!=this_object()) {
1238 _notify_fail("Da kommst du so nicht ran.\n");
1239 return 0;
1240 }
1241 put(ob, where);
1242 return 1;
1243}
1244
1245int give_obj(object ob, object where)
1246{
1247 object env;
1248
1249 if (environment(ob)!=this_object()) {
1250 TME("Das solltest Du erstmal nehmen.");
1251 return 1;
1252 }
1253 if (!ob || ob == this_object() || ob == where ||
1254 environment(where)!=environment())
1255 return 0;
1256 if (environment(ob) == where) {
1257 _notify_fail("Das Ziel ist in dem zu gebenden Object enthalten!\n");
1258 return 0;
1259 }
1260 if (environment(ob)!=this_object()) {
1261 TME("Das hast Du nicht.");
1262 return 1;
1263 }
1264 give(ob, where);
1265 return 1;
1266}