blob: 53b5730c2a2403f91552a9a0f6cf623bc62e1f3c [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
583 if (!env && sizeof(tokens) > 1 && tokens[<1] == "hier") {
584 tokens = tokens[..<2];
585 env = environment();
586 }
587 else if (!env && sizeof(tokens) > 2 && tokens[<2] == "in")
588 {
589 if (tokens[<1] == "mir" ||
590 tokens[<1] == "dir") {
591 tokens = tokens[..<3];
592 env = this_object();
593 }
594 else if (tokens[<1] == "raum") {
595 tokens = tokens[..<3];
596 env = environment();
597 }
598 }
599
600 for (int i = sizeof(tokens)-1; i > 1; i--) {
601 if (env)
602 ob = present(implode(tokens[i..], " "), env);
603 else
604 ob = present(implode(tokens[i..], " "), environment()) ||
605 present(implode(tokens[i..], " "), this_object());
606
607 if (!ob)
608 continue;
609
610 if (living(ob)) {
611 NF("Aber " + ob->name(WER, 1) + " lebt doch!");
612 continue;
613 }
614
615 if (ob->QueryProp(P_CNT_STATUS)) {
616 NF("Aber " + ob->name(WER, 1) + " ist doch geschlossen!");
617 continue;
618 }
619
620 if (is_source != 0 &&
621 tokens[i-1] == ob->QueryProp(P_SOURCE_PREPOSITION))
622 return ob->present_objects(implode(tokens[..i-2], " "));
623
624 if (tokens[i-1] == ob->QueryProp(P_PREPOSITION))
625 return __find_objects(tokens[..i-2], ob, is_source ? 2 : 0);
626
627 NF("Du kannst nichts " + tokens[i-1] + " " +
628 ob->name(WEM, 1) + " nehmen.");
629 }
630
631 if (is_source == 2)
632 return ({});
633
634 if (env)
635 return env->present_objects(implode(tokens, " "));
636
637 if (environment() &&
638 sizeof(obs = environment()->present_objects(implode(tokens, " "))))
639 return obs;
640
641 return present_objects(implode(tokens, " "));
642}
643
644object *find_objects(string what, object env, int is_source)
645{
646 if (!stringp(what) || !sizeof(what))
647 return ({});
648 return __find_objects(explode(what, " "), env, is_source);
649}
650
651
652/* varargs int drop_objects(string str, mixed msg);
653 * varargs int put_objects(string str, int casus, string verb, mixed msg);
654 * varargs int pick_objects(string str, int flag, mixed msg);
655 * varargs int give_objects(string str, mixed msg);
656 * varargs int show_objects(string str, mixed msg);
657 *
658 * Ein Befehl wie "wirf waffen weg" resultiert in einem Aufruf von
659 * drop_objects("waffen"). Diese Funktionen sind hauptsaechlich fuer die
660 * Behandlung der jeweiligen Kommandos vorgesehen, koennen jedoch auch fuer
661 * eigene Befehle verwendet werden. put_objects() erwartet ausserdem den
662 * Kasus ("Du kannst nichts an DER Pinwand befestigen.") und das verwendete
663 * Verb in der Gundform ("befestigen"). Das Flag fuer pick_objects() gibt
664 * an, ob das Objekt auch einfach herumliegen darf ("nimm ...") oder nicht
665 * ("hole ..."). Gibt bei Erfolg 1, sonst 0 zurueck.
666 */
667
668varargs int drop_objects(string str, mixed msg)
669{
670 object *obs;
671
672 if (!sizeof(obs = find_objects(str, this_object(), 1)))
673 return 0;
674
675 foreach (object o: obs) {
676 if (objectp(o))
677 drop(o, msg);
678
679 if (get_eval_cost() < 100000) {
680 TME("Den Rest behaeltst Du erst mal.");
681 last_moved_objects = obs[..member(obs, o)];
682 last_moved_where = 0;
683 return 1;
684 }
685 }
686
687 last_moved_objects = obs;
688 last_moved_where = 0;
689 return 1;
690}
691
692varargs int put_objects(string str, int casus, string verb, mixed msg)
693{
694 object *obs, dest, *no_move;
695
696 if (!stringp(str) || !sizeof(str)) return 0;
697
698 string *tokens = explode(str, " ");
699 int allow_room = 1;
700 int allow_me = 1;
701
702 if (sizeof(tokens) > 1 && tokens[<1] == "hier") {
703 tokens = tokens[..<2];
704 allow_me = 0;
705 } else if (sizeof(tokens) > 2 && tokens[<2] == "in")
706 if (tokens[<1] == "mir" ||
707 tokens[<1] == "dir") {
708 tokens = tokens[..<3];
709 allow_room = 0;
710 } else if (tokens[<1] == "raum") {
711 tokens = tokens[..<3];
712 allow_me = 0;
713 }
714
715 for (int i = sizeof(tokens)-1; i > 1; i--) {
716 if (!(dest = allow_room && present(implode(tokens[i..], " "),
717 environment())) &&
718 !(dest = allow_me && present(implode(tokens[i..], " "),
719 this_object())))
720 continue;
721
722 if (living(dest)) {
723 NF("Aber " + dest->name(WER, 1) + " lebt doch!");
724 continue;
725 }
726/*
727 if (verb == "legen" && !dest->QueryProp(P_TRAY)) {
728 NF("Du kannst nichts auf " + dest->name(WEN, 1) + " legen.");
729 continue;
730 }
731*/
732 if (verb == "stecken" && !dest->QueryProp(P_CONTAINER)) {
733 NF("Du kannst in " + dest->name(WEN, 1) + " nichts reinstecken.");
734 continue;
735 }
736
737 if (dest->QueryProp(P_CNT_STATUS)) {
738 NF("Aber " + dest->name(WER, 1) + " ist doch geschlossen!");
739 continue;
740 }
741
742 if (tokens[i-1] != dest->QueryProp(P_DEST_PREPOSITION)) {
743 NF("Du kannst nichts " + tokens[i-1] + " " +
744 dest->name(casus, 1) + " " + verb + ".");
745 continue;
746 }
747
748 if (!sizeof(obs = __find_objects(tokens[..i-2], 0, 1) - ({ dest }))) {
749 NF("WAS moechtest Du " + tokens[i-1] + " " +
750 dest->name(casus, 1) + " " + verb + "?");
751 return 0;
752 }
753
754 if (sizeof(no_move = obs & all_inventory(dest))) {
755 TME(capitalize(CountUp(map_objects(no_move, "name", WER, 1))) +
756 (sizeof(no_move) == 1 ? " ist" : " sind") +
757 " doch bereits in " + dest->name(WEM,1) + ".");
758 if (!sizeof(obs -= no_move))
759 return 0;
760 }
761
762 foreach (object o: obs) {
763 if (objectp(o))
764 put(o, dest, msg);
765
766 if (get_eval_cost() < 100000) {
767 TME("Den Rest laesst Du erst mal, wo er ist.");
768 last_moved_objects = obs[..member(obs, o)];
769 last_moved_where = dest;
770 return 1;
771 }
772 }
773
774 last_moved_objects = obs;
775 last_moved_where = dest;
776 return 1;
777 }
778
779 return 0;
780}
781
782varargs int pick_objects(string str, int flag, mixed msg)
783{
784 object *obs;
785
786 if (((int)QueryProp(P_MAX_HANDS)) < 1){
787 NF("Ohne Haende kannst Du nichts nehmen.");
788 return 0;
789 }
790
791 if (!sizeof(obs = find_objects(str, 0, 1) - all_inventory()
792 - (flag ? all_inventory(environment()) : ({}))))
793 return 0;
794
795 foreach (object o: obs) {
796 if (objectp(o))
797 pick(o, msg);
798
799 if (get_eval_cost() < 100000) {
800 TME("Den Rest laesst Du erst mal liegen.");
801 last_moved_objects = obs[..member(obs, o)];
802 last_moved_where = 0;
803 return 1;
804 }
805 }
806
807 last_moved_objects = obs;
808 last_moved_where = 0;
809 return 1;
810}
811
812varargs int give_objects(string str, mixed msg)
813{
814 object *obs, dest;
815
816 if (!stringp(str) || !sizeof(str)) return 0;
817
818 string *tokens = explode(str, " ");
819
820 if (((int)QueryProp(P_MAX_HANDS)) < 1){
821 NF("Ohne Haende kannst Du nichts weggeben.");
822 return 0;
823 }
824
825 for (int i = 0; i < sizeof(tokens)-1; i++) {
826 if (!(dest = present(implode(tokens[..i], " "), environment())))
827 continue;
828
829 if (!living(dest)) {
830 NF("Aber " + dest->name(WER, 1) + " lebt doch gar nicht!");
831 dest = 0;
832 continue;
833 }
834
835 if (!sizeof(obs = __find_objects(tokens[i+1..], 0, 1))) {
836 NF("WAS moechtest Du " + dest->name(WEM, 1)+" geben?");
837 dest = 0;
838 } else
839 break;
840 }
841
842 if (!dest) {
843 int pos;
844
845 if ((pos = strrstr(str, " an ")) >= 0) {
846 dest = present(str[pos+4..], environment());
847 // zu gebende Objekte in Env + Living suchen
848 obs = find_objects(str[..pos-1], 0, 1);
849 }
850 }
851
852 if (!dest || !living(dest) || !sizeof(obs))
853 return 0;
854
855 foreach (object o: obs) {
856 if (objectp(o))
857 give(o, dest, msg);
858
859 if (get_eval_cost() < 100000) {
860 TME("Den Rest behaeltst Du erst mal.");
861 last_moved_objects = obs[..member(obs, o)];
862 last_moved_where = dest;
863 return 1;
864 }
865 }
866
867 last_moved_objects = obs;
868 last_moved_where = dest;
869 return 1;
870}
871
872varargs int show_objects(string str, mixed msg)
873{
874 object *obs, whom;
875
876 if (!stringp(str) || !sizeof(str))
877 return 0;
878
879 string *tokens = explode(str, " ");
880
881 for (int i = 0; i < sizeof(tokens)-1; i++) {
882 if (whom = present(implode(tokens[..i], " "), environment())) {
883 if (!living(whom)) {
884 NF("Aber " + whom->name(WER, 1) + " lebt doch gar nicht!");
885 continue;
886 }
887 } else {
888 if (i != 0 || tokens[0] != "allen")
889 continue;
890
891 if (!sizeof(filter(all_inventory(environment()) -
892 ({ this_object() }), #'living))) {
893 NF("Hier ist niemand, dem Du etwas zeigen koenntest!");
894 continue;
895 }
896 }
897
898 if (whom == this_object()) {
899 NF("Dazu solltest Du dann besser 'schau' benutzen!\n");
900 continue;
901 }
902
903 if (!sizeof(obs = __find_objects(tokens[i+1..], this_object(), 0)) &&
904 !sizeof(obs = __find_objects(tokens[i+1..], 0, 0)
905 - ({ this_object(), whom }))) {
906 NF("WAS moechtest Du " + (whom ? whom->name(WEM, 1) : "allen") +
907 " zeigen?");
908 continue;
909 }
910
911 foreach (object o: obs) {
912 if (objectp(o))
913 show(o, whom, msg);
914
915 if (get_eval_cost() < 100000) {
916 TME("Das reicht erst mal.");
917 last_moved_objects = obs[..member(obs, o)];
918 last_moved_where = whom;
919 return 1;
920 }
921 }
922
923 last_moved_objects = obs;
924 last_moved_where = whom;
925 return 1;
926 }
927
928 return 0;
929}
930
931object *moved_objects(void)
932{
933 return last_moved_objects;
934}
935
936object moved_where(void)
937{
938 return last_moved_where;
939}
940
941
942/************************* Die einzelnen Kommandos **************************/
943
944/* static int fallenlassen(string str)
945 * static int werfen(string str)
946 * static int legen(string str)
947 * static int stecken(string str)
948 * static int holen(string str)
949 * static int nehmen(string str)
950 * static int geben(string str)
951 * Minimale Wrapper fuer XXX_objects(), entfernen "fallen", "weg" bzw. "ab"
952 * aus den Argumenten und setzen entsprechende Standard-Fehlermeldungen.
953 *
954 * protected void add_put_and_get_commands()
955 * Registriert obige Funktionen per add_action().
956 */
957
958static int fallenlassen(string str)
959{
960 if (QueryProp(P_GHOST)) {
961 _notify_fail("Als Geist kannst Du nichts fallenlassen.\n");
962 return 0;
963 }
964
965 if (!str || str[<7..] != " fallen") {
966 _notify_fail("Lass etwas FALLEN, oder was meinst Du?\n");
967 return 0;
968 }
969
970 _notify_fail("WAS moechtest Du fallenlassen?\n");
971 return drop_objects(str[0..<8]);
972}
973
974static int werfen(string str)
975{
976 if (QueryProp(P_GHOST)) {
977 _notify_fail("Als Geist kannst Du nichts wegwerfen.\n");
978 return 0;
979 }
980
981 if (!str || str[<4..] != " weg") {
982 _notify_fail("Wirf etwas WEG, oder was meinst Du?\n");
983 return 0;
984 }
985
986 _notify_fail("WAS moechtest Du loswerden?\n");
987 return drop_objects(str[0..<5]);
988}
989
990static int legen(string str)
991{
992 if (QueryProp(P_GHOST)) {
993 _notify_fail("Als Geist kannst Du nichts weglegen.\n");
994 return 0;
995 }
996
997 if (!str) {
998 _notify_fail("Lege etwas AB, oder was meinst Du?\n");
999 return 0;
1000 }
1001
1002 if (str[<3..] == " ab") {
1003 _notify_fail("WAS moechtest Du ablegen?\n");
1004 return drop_objects(str[0..<4]);
1005 }
1006
1007 if (str[<4..] == " weg") {
1008 _notify_fail("WAS moechtest Du weglegen?\n");
1009 return drop_objects(str[0..<5]);
1010 }
1011
1012 _notify_fail("WAS moechtest Du WOHIN legen?\n");
1013 return put_objects(str, WEN, "legen");
1014}
1015
1016static int stecken(string str)
1017{
1018 if (QueryProp(P_GHOST)) {
1019 _notify_fail("Das kannst Du in Deinem immateriellen Zustand nicht.\n");
1020 return 0;
1021 }
1022
1023 _notify_fail("WAS moechtest Du WOHIN stecken?\n");
1024 return put_objects(str, WEN, "stecken");
1025}
1026
1027static int holen(string str)
1028{
1029 if (QueryProp(P_GHOST)) {
1030 _notify_fail("Als Geist kannst Du nichts nehmen.\n");
1031 return 0;
1032 }
1033
1034 _notify_fail("WAS moechtest Du aus WAS holen?\n");
1035 return pick_objects(str, 1);
1036}
1037
1038static int nehmen(string str)
1039{
1040 if (QueryProp(P_GHOST)) {
1041 _notify_fail("Als Geist kannst Du nichts nehmen.\n");
1042 return 0;
1043 }
1044
1045 _notify_fail("WAS moechtest Du nehmen?\n");
1046 return pick_objects(str, 0);
1047}
1048
1049static int geben(string str)
1050{
1051 if (QueryProp(P_GHOST)) {
1052 _notify_fail("Als Geist kannst Du nichts weggeben.\n");
1053 return 0;
1054 }
1055
1056 _notify_fail("WEM moechtest Du WAS geben?\n");
1057 return give_objects(str);
1058}
1059
1060static int zeigen(string str)
1061{
1062 if (QueryProp(P_GHOST)) {
1063 _notify_fail("Als Geist kannst Du niemandem etwas zeigen.\n");
1064 return 0;
1065 }
1066
1067 _notify_fail("WEM moechtest Du WAS zeigen?\n");
1068 return show_objects(str);
1069}
1070
1071protected void add_put_and_get_commands(void)
1072{
1073 add_action("fallenlassen", "lass");
1074 add_action("fallenlassen", "lasse");
1075 add_action("werfen", "wirf");
1076 add_action("werfen", "werf");
1077 add_action("werfen", "werfe");
1078 add_action("legen", "leg");
1079 add_action("legen", "lege");
1080 add_action("stecken", "steck");
1081 add_action("stecken", "stecke");
1082 add_action("holen", "hol");
1083 add_action("holen", "hole");
1084 add_action("nehmen", "nimm");
1085 add_action("nehmen", "nehm");
1086 add_action("nehmen", "nehme");
1087 add_action("geben", "gebe");
1088 add_action("geben", "gib");
1089 add_action("zeigen", "zeig");
1090 add_action("zeigen", "zeige");
1091}
1092
1093
1094/********** Aus reinen Kompatibilitaetsgruenden weiterhin enthalten *********/
1095
1096object* find_obs(string str, int meth)
1097// gibt ein array zurueck mit allen Objekten die mit str angesprochen werden
1098{
1099 object inv;
1100 if (!str) return 0;
1101 if (str[<7..]==" in mir") {
1102 inv=ME;
1103 str=str[0..<8];
1104 }
1105 else if (str[<8..]==" in raum") {
1106 if (meth & PUT_GET_DROP) { // man kann nichts aus dem Raum wegwerfen
1107 _notify_fail("Du kannst nichts wegwerfen, das Du gar nicht hast.\n");
1108 return 0;
1109 }
1110 inv=environment();
1111 str=str[0..<9];
1112 }
1113 else if (meth & PUT_GET_DROP) inv=ME; // Raum bei drop uninteressant
1114 // else kein besonderes inv ausgewaehlt also inv=0
1115 if (!sizeof(str))
1116 return 0; // hier passt die bereits gesetzte _notify_fail
1117 else {
1118 object *obs;
1119 string con;
1120 if (sscanf(str, "%s aus %s", str, con)==2 ||
1121 sscanf(str, "%s in %s", str, con)==2 ||
1122 sscanf(str, "%s von %s", str, con)==2 ||
1123 sscanf(str, "%s vom %s", str, con)==2) {
1124 if (!inv) {
1125 if (!environment() || !(inv=present(con, environment())))
1126 inv=present(con, ME); // sowohl im env als auch im inv suchen
1127 }
1128 else inv=present(con, inv); // nur in ausgewaehltem inv suchen
1129 if (inv==ME) inv=0;
1130 if (!inv || !(inv->short())) {
1131 _notify_fail(break_string("Du hast hier aber kein '"+capitalize(con)
1132 +"'.",78));
1133 return 0;
1134 }
1135 if (living(inv)) {
1136 _notify_fail(break_string("Aber "+inv->name(WER,1)+" lebt doch!",78));
1137 return 0;
1138 }
1139 // wieso man aus Objekten die von std/tray abgeleitet werden etwas
1140 // nehmen koennen soll, versteh ich zwar nicht so ganz...
1141 if (!(inv->QueryProp(P_CONTAINER)) && !(inv->QueryProp(P_TRAY))) {
1142 _notify_fail(break_string("Du kannst nichts aus "+inv->name(WEM,1)
1143 +" nehmen.",78));
1144 return 0;
1145 }
1146 if (inv->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1147 _notify_fail(break_string("Aber "+inv->name(WER,1)
1148 +" ist doch geschlossen.", 78));
1149 return 0;
1150 }
1151 }
1152 else if (inv==ME && (meth & PUT_GET_TAKE)) { // nichts aus sich nehmen
1153 _notify_fail("Du kannst nichts nehmen, "
1154 "was Du schon bei Dir traegst.\n");
1155 return 0;
1156 }
1157 if (!inv && (meth & PUT_GET_TAKE))
1158 inv=environment(); // nichts nehmen was man schon hat
1159
1160 if (!inv) {
1161 if (environment()) {
1162 obs=(environment()->present_objects(str)||({}));
1163 if (!sizeof(obs)) obs+=(ME->present_objects(str)||({}));
1164 }
1165 else obs=(ME->present_objects(str) || ({}));
1166 }
1167 else obs=(inv->present_objects(str) || ({}));
1168 return obs-({ ME });
1169 }
1170 return(0);
1171}
1172
1173int pick_obj(object ob)
1174{
1175 object env;
1176
1177 if (!ob || ob == this_object() || environment(ob) == this_object()) return 0;
1178 if ((env=environment(ob)) != environment()) {
1179 if (!env->QueryProp(P_CONTAINER) && !env->QueryProp(P_TRAY)) {
1180 TME("Du kannst nichts aus " + env->name(WEM,1) + " nehmen.");
1181 return 1;
1182 }
1183 else if (env->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1184 TME("Aber " + env->name(WER, 1) + " ist doch geschlossen.");
1185 return 1;
1186 }
1187 }
1188 if (ob->IsUnit() && ob->QueryProp(P_AMOUNT)<0) {
1189 TME("Du kannst nicht mehr nehmen als da ist.");
1190 return 1;
1191 }
1192 pick(ob);
1193 return 1;
1194}
1195
1196int drop_obj(object ob)
1197{
1198 if (!ob || ob==this_object() || environment(ob)!=this_object()) return 0;
1199 drop(ob);
1200 return 1;
1201}
1202
1203int put_obj(object ob, object where)
1204{
1205 object env;
1206
1207 if (ob == this_object() || ob == where || environment(ob) == where) return 0;
1208 env=environment(ob);
1209 if (!where->QueryProp(P_CONTAINER)) {
1210 TME("Du kannst in " + where->name(WEN,1) + " nix reinstecken.");
1211 return 1;
1212 }
1213 if (where->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1214 TME("Aber " + where->name(WER, 1) + " ist doch geschlossen.");
1215 return 1;
1216 }
1217 if (env!=environment(this_object()) && env!=this_object()) {
1218 _notify_fail("Da kommst du so nicht ran.\n");
1219 return 0;
1220 }
1221 put(ob, where);
1222 return 1;
1223}
1224
1225int give_obj(object ob, object where)
1226{
1227 object env;
1228
1229 if (environment(ob)!=this_object()) {
1230 TME("Das solltest Du erstmal nehmen.");
1231 return 1;
1232 }
1233 if (!ob || ob == this_object() || ob == where ||
1234 environment(where)!=environment())
1235 return 0;
1236 if (environment(ob) == where) {
1237 _notify_fail("Das Ziel ist in dem zu gebenden Object enthalten!\n");
1238 return 0;
1239 }
1240 if (environment(ob)!=this_object()) {
1241 TME("Das hast Du nicht.");
1242 return 1;
1243 }
1244 give(ob, where);
1245 return 1;
1246}