blob: 4e1a97f363caf2bc7dc1868b7c7c6f87486e125e [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) {
363 TME("Du steckst " + wen1 + " in " + dest->name(WEN, 1) + ".");
364 if (environment())
365 SAY(Name(WER, 1) + " steckt " + wen0 +
366 " in " + dest->name(WEN, 0) + ".");
367 }
368 else if (pointerp(msg)) {
369 switch (sizeof(msg)) {
370 case 2:
371 if (environment())
372 SAY(replace_personal(msg[1], ({this_object(), o||wen0, dest}), 1));
373 case 1:
374 TME(replace_personal(msg[0], ({this_object(), o||wen1, dest}), 1));
375 break;
376 default:
377 raise_error(sprintf(
378 "Falsches Format fuer P_PUT_MSG: %O\n",o||wen1));
379 }
380 }
381
382 return 1;
383}
384
385varargs int pick(object o, mixed msg)
386{
387 string str;
388
389 // vorher speichern, falls das Objekt zerstoert wird
390 cl = symbol_function("name", o);
391 wen0 = 0;
392 wen1 = funcall(cl, WEN, 1);
393 wer0 = 0;
394
395 if (!msg)
396 msg = o->QueryProp(P_PICK_MSG);
397
398 if (str = put_or_get(o, this_object())) {
399 TME(str);
400 return 0;
401 }
402
403 if (!msg) {
404 TME("Du nimmst " + wen1 + ".");
405 SAY(Name(WER, 1) + " nimmt " + wen1 + ".");
406 } else if (pointerp(msg))
407 switch (sizeof(msg)) {
408 case 2:
409 SAY(replace_personal(msg[1], ({this_object(), o||wen1}), 1));
410 case 1:
411 TME(replace_personal(msg[0], ({this_object(), o||wen1}), 1));
412 break;
413 default:
414 raise_error(sprintf(
415 "Falsches Format fuer P_PICK_MSG: %O\n", o||wen1));
416 }
417
418 return 1;
419}
420
421varargs int give(object o, object dest, mixed msg)
422{
423 string zname, gname;
424 string str;
425
426 // Falls das jemand von aussen ruft und Schrott uebergibt...
427 if (!living(dest))
428 raise_error(sprintf("Totes Ziel fuer give(): %O\n", dest));
429
430 zname = dest->name(WEM, 1);
431 gname = Name(WER, 1);
432
433 // vorher speichern, falls das Objekt zerstoert wird
434 cl = symbol_function("name", o);
435 wen0 = funcall(cl, WEN, 0);
436 wen1 = funcall(cl, WEN, 1);
437 wer0 = 0;
438
439 if (!msg)
440 msg = o->QueryProp(P_GIVE_MSG);
441
442 if (str = put_or_get(o, dest)) {
443 TME(str);
444 return 0;
445 }
446
447 if (!msg) {
448 TME("Du gibst " + zname + " " + wen1 + ".");
449 TOB(dest, gname + " gibt Dir " + wen0 + ".");
450 SAY2(({dest}), gname + " gibt " + zname + " " + wen0 + ".");
451 } else if (pointerp(msg))
452 switch (sizeof(msg)) {
453 case 3:
454 TOB(dest, replace_personal(
455 msg[2], ({this_object(), o||wen0, dest||zname}), 1));
456 case 2:
457 SAY2(({dest, this_object()}), replace_personal(
458 msg[1], ({this_object(), o||wen0, dest||zname}), 1));
459 case 1:
460 TME(replace_personal(
461 msg[0], ({this_object(), o||wen1, dest||zname}), 1));
462 break;
463 default:
464 raise_error(sprintf(
465 "Falsches Format fuer P_GIVE_MSG: %O\n", o||wen1));
466 }
467
468 if (!query_once_interactive(dest))
469 dest->give_notify(o);
470
471 return 1;
472}
473
474varargs int show(object o, object whom, mixed msg)
475{
476 string zname, gname;
477 string wen0, wen2, long;
478
479 zname = whom ? whom->name(WEM, 1) : "allen";
480 gname = Name(WER, 1);
481
482 if (!msg)
483 msg = o->QueryProp(P_SHOW_MSG);
484
485 if (environment(o) == this_object() ||
486 environment(environment(o)) == this_object()) {
487 wen0 = o->name(WEN, 0);
488
489 /* Der Akkusativ muss mit dem unbestimmten Artikel gebildet werden,
490 * damit eventuelle Adjektive die richtige Endung besitzen.
491 * (ein kleines Schwert -> kleines Schwert -> Dein kleines Schwert)
492 */
493
494 if (o->QueryProp(P_ARTICLE) && member(wen0, ' ') >= 0) {
495 int obgender = o->QueryProp(P_GENDER);
496 int obnum = o->QueryProp(P_AMOUNT) > 1 ? PLURAL : SINGULAR;
497
498 // Wichtig: P_AMOUNT ist 0 fuer Objekte, die nicht von unit erben.
499 // Da unit.c kein P_AMOUNT==0 zulaesst, nehmen wir diesen Fall als
500 // singular an. *Rumata
501
502 wen2 = wen0[member(wen0, ' ')..];
503 wen0 = QueryPossPronoun(o, WEN, obnum) + wen2;
504
505 if (obnum == PLURAL || obgender == FEMALE)
506 wen2 = "Deine" + wen2;
507 else if (obgender == MALE)
508 wen2 = "Deinen" + wen2;
509 else
510 wen2 = "Dein" + wen2;
511 } else
512 wen2 = wen0;
513 } else
514 wen2 = wen0 = o->name(WEN, 1);
515
516 // vorher speichern, falls das Objekt im catch_tell() zerstoert wird
517 long = o->long(4);
518
519 if (!msg) {
520 TME("Du zeigst " + zname + " " + wen2 + ".");
521 if (!whom)
522 SAY(gname + " zeigt Dir " + wen0 + ".");
523 else {
524 TOB(whom, gname + " zeigt Dir " + wen0 + ".");
525 SAY2(({whom}), gname + " zeigt " + zname + " " + wen0 + ".");
526 }
527 } else if (pointerp(msg))
528 switch (sizeof(msg)) {
529 case 3:
530 if (whom)
531 TOB(whom, replace_personal(
532 msg[2], ({this_object(), o||wen0, whom||zname}), 1));
533 else
534 SAY(replace_personal(
535 msg[2], ({this_object(), o||wen0, whom||zname}), 1));
536 case 2:
537 if (whom)
538 SAY2(({whom, this_object()}), replace_personal(
539 msg[1], ({this_object(), o||wen0, whom||zname}), 1));
540 case 1:
541 TME(replace_personal(
542 msg[0], ({this_object(), o||wen2, whom||zname}), 1));
543 break;
544 default:
545 raise_error(sprintf(
546 "Falsches Format fuer P_SHOW_MSG: %O\n", o||wen0));
547 }
548
549 if (!whom)
550 SAY(long);
551 else {
552 TOB(whom, long);
553 if (!query_once_interactive(whom))
554 whom->show_notify(o);
555 }
556
557 return 1;
558}
559
560
561/***************************** Hilfsfunktionen *****************************/
562
563/* private object *__find_objects(string *tokens, object env, int is_source);
564 * object *find_objects(string what, object env, int is_source);
565 *
566 * Sucht im Raum und im Spieler (oder alternativ in der angegebenen Umgebung)
567 * nach den in tokens/what bezeichneten Objekten. is_source bestimmt die
568 * erwartete grammatische Form (0 fuer "topf auf herd" und 1 fuer "topf von
569 * herd", siehe Manpage).
570 */
571
572private object *__find_objects(string *tokens, object env, int is_source)
573{
574 object ob, *obs;
575
576 // is_source == 0: Objekt soll nicht bewegt werden ("topf auf herd")
577 // 1: Objekt soll bewegt werden ("topf von herd")
578 // 2: intern
579
580 if (!env && sizeof(tokens) > 1 && tokens[<1] == "hier") {
581 tokens = tokens[..<2];
582 env = environment();
583 }
584 else if (!env && sizeof(tokens) > 2 && tokens[<2] == "in")
585 {
586 if (tokens[<1] == "mir" ||
587 tokens[<1] == "dir") {
588 tokens = tokens[..<3];
589 env = this_object();
590 }
591 else if (tokens[<1] == "raum") {
592 tokens = tokens[..<3];
593 env = environment();
594 }
595 }
596
597 for (int i = sizeof(tokens)-1; i > 1; i--) {
598 if (env)
599 ob = present(implode(tokens[i..], " "), env);
600 else
601 ob = present(implode(tokens[i..], " "), environment()) ||
602 present(implode(tokens[i..], " "), this_object());
603
604 if (!ob)
605 continue;
606
607 if (living(ob)) {
608 NF("Aber " + ob->name(WER, 1) + " lebt doch!");
609 continue;
610 }
611
612 if (ob->QueryProp(P_CNT_STATUS)) {
613 NF("Aber " + ob->name(WER, 1) + " ist doch geschlossen!");
614 continue;
615 }
616
617 if (is_source != 0 &&
618 tokens[i-1] == ob->QueryProp(P_SOURCE_PREPOSITION))
619 return ob->present_objects(implode(tokens[..i-2], " "));
620
621 if (tokens[i-1] == ob->QueryProp(P_PREPOSITION))
622 return __find_objects(tokens[..i-2], ob, is_source ? 2 : 0);
623
624 NF("Du kannst nichts " + tokens[i-1] + " " +
625 ob->name(WEM, 1) + " nehmen.");
626 }
627
628 if (is_source == 2)
629 return ({});
630
631 if (env)
632 return env->present_objects(implode(tokens, " "));
633
634 if (environment() &&
635 sizeof(obs = environment()->present_objects(implode(tokens, " "))))
636 return obs;
637
638 return present_objects(implode(tokens, " "));
639}
640
641object *find_objects(string what, object env, int is_source)
642{
643 if (!stringp(what) || !sizeof(what))
644 return ({});
645 return __find_objects(explode(what, " "), env, is_source);
646}
647
648
649/* varargs int drop_objects(string str, mixed msg);
650 * varargs int put_objects(string str, int casus, string verb, mixed msg);
651 * varargs int pick_objects(string str, int flag, mixed msg);
652 * varargs int give_objects(string str, mixed msg);
653 * varargs int show_objects(string str, mixed msg);
654 *
655 * Ein Befehl wie "wirf waffen weg" resultiert in einem Aufruf von
656 * drop_objects("waffen"). Diese Funktionen sind hauptsaechlich fuer die
657 * Behandlung der jeweiligen Kommandos vorgesehen, koennen jedoch auch fuer
658 * eigene Befehle verwendet werden. put_objects() erwartet ausserdem den
659 * Kasus ("Du kannst nichts an DER Pinwand befestigen.") und das verwendete
660 * Verb in der Gundform ("befestigen"). Das Flag fuer pick_objects() gibt
661 * an, ob das Objekt auch einfach herumliegen darf ("nimm ...") oder nicht
662 * ("hole ..."). Gibt bei Erfolg 1, sonst 0 zurueck.
663 */
664
665varargs int drop_objects(string str, mixed msg)
666{
667 object *obs;
668
669 if (!sizeof(obs = find_objects(str, this_object(), 1)))
670 return 0;
671
672 foreach (object o: obs) {
673 if (objectp(o))
674 drop(o, msg);
675
676 if (get_eval_cost() < 100000) {
677 TME("Den Rest behaeltst Du erst mal.");
678 last_moved_objects = obs[..member(obs, o)];
679 last_moved_where = 0;
680 return 1;
681 }
682 }
683
684 last_moved_objects = obs;
685 last_moved_where = 0;
686 return 1;
687}
688
689varargs int put_objects(string str, int casus, string verb, mixed msg)
690{
691 object *obs, dest, *no_move;
692
693 if (!stringp(str) || !sizeof(str)) return 0;
694
695 string *tokens = explode(str, " ");
696 int allow_room = 1;
697 int allow_me = 1;
698
699 if (sizeof(tokens) > 1 && tokens[<1] == "hier") {
700 tokens = tokens[..<2];
701 allow_me = 0;
702 } else if (sizeof(tokens) > 2 && tokens[<2] == "in")
703 if (tokens[<1] == "mir" ||
704 tokens[<1] == "dir") {
705 tokens = tokens[..<3];
706 allow_room = 0;
707 } else if (tokens[<1] == "raum") {
708 tokens = tokens[..<3];
709 allow_me = 0;
710 }
711
712 for (int i = sizeof(tokens)-1; i > 1; i--) {
713 if (!(dest = allow_room && present(implode(tokens[i..], " "),
714 environment())) &&
715 !(dest = allow_me && present(implode(tokens[i..], " "),
716 this_object())))
717 continue;
718
719 if (living(dest)) {
720 NF("Aber " + dest->name(WER, 1) + " lebt doch!");
721 continue;
722 }
723/*
724 if (verb == "legen" && !dest->QueryProp(P_TRAY)) {
725 NF("Du kannst nichts auf " + dest->name(WEN, 1) + " legen.");
726 continue;
727 }
728*/
729 if (verb == "stecken" && !dest->QueryProp(P_CONTAINER)) {
730 NF("Du kannst in " + dest->name(WEN, 1) + " nichts reinstecken.");
731 continue;
732 }
733
734 if (dest->QueryProp(P_CNT_STATUS)) {
735 NF("Aber " + dest->name(WER, 1) + " ist doch geschlossen!");
736 continue;
737 }
738
739 if (tokens[i-1] != dest->QueryProp(P_DEST_PREPOSITION)) {
740 NF("Du kannst nichts " + tokens[i-1] + " " +
741 dest->name(casus, 1) + " " + verb + ".");
742 continue;
743 }
744
745 if (!sizeof(obs = __find_objects(tokens[..i-2], 0, 1) - ({ dest }))) {
746 NF("WAS moechtest Du " + tokens[i-1] + " " +
747 dest->name(casus, 1) + " " + verb + "?");
748 return 0;
749 }
750
751 if (sizeof(no_move = obs & all_inventory(dest))) {
752 TME(capitalize(CountUp(map_objects(no_move, "name", WER, 1))) +
753 (sizeof(no_move) == 1 ? " ist" : " sind") +
754 " doch bereits in " + dest->name(WEM,1) + ".");
755 if (!sizeof(obs -= no_move))
756 return 0;
757 }
758
759 foreach (object o: obs) {
760 if (objectp(o))
761 put(o, dest, msg);
762
763 if (get_eval_cost() < 100000) {
764 TME("Den Rest laesst Du erst mal, wo er ist.");
765 last_moved_objects = obs[..member(obs, o)];
766 last_moved_where = dest;
767 return 1;
768 }
769 }
770
771 last_moved_objects = obs;
772 last_moved_where = dest;
773 return 1;
774 }
775
776 return 0;
777}
778
779varargs int pick_objects(string str, int flag, mixed msg)
780{
781 object *obs;
782
783 if (((int)QueryProp(P_MAX_HANDS)) < 1){
784 NF("Ohne Haende kannst Du nichts nehmen.");
785 return 0;
786 }
787
788 if (!sizeof(obs = find_objects(str, 0, 1) - all_inventory()
789 - (flag ? all_inventory(environment()) : ({}))))
790 return 0;
791
792 foreach (object o: obs) {
793 if (objectp(o))
794 pick(o, msg);
795
796 if (get_eval_cost() < 100000) {
797 TME("Den Rest laesst Du erst mal liegen.");
798 last_moved_objects = obs[..member(obs, o)];
799 last_moved_where = 0;
800 return 1;
801 }
802 }
803
804 last_moved_objects = obs;
805 last_moved_where = 0;
806 return 1;
807}
808
809varargs int give_objects(string str, mixed msg)
810{
811 object *obs, dest;
812
813 if (!stringp(str) || !sizeof(str)) return 0;
814
815 string *tokens = explode(str, " ");
816
817 if (((int)QueryProp(P_MAX_HANDS)) < 1){
818 NF("Ohne Haende kannst Du nichts weggeben.");
819 return 0;
820 }
821
822 for (int i = 0; i < sizeof(tokens)-1; i++) {
823 if (!(dest = present(implode(tokens[..i], " "), environment())))
824 continue;
825
826 if (!living(dest)) {
827 NF("Aber " + dest->name(WER, 1) + " lebt doch gar nicht!");
828 dest = 0;
829 continue;
830 }
831
832 if (!sizeof(obs = __find_objects(tokens[i+1..], 0, 1))) {
833 NF("WAS moechtest Du " + dest->name(WEM, 1)+" geben?");
834 dest = 0;
835 } else
836 break;
837 }
838
839 if (!dest) {
840 int pos;
841
842 if ((pos = strrstr(str, " an ")) >= 0) {
843 dest = present(str[pos+4..], environment());
844 // zu gebende Objekte in Env + Living suchen
845 obs = find_objects(str[..pos-1], 0, 1);
846 }
847 }
848
849 if (!dest || !living(dest) || !sizeof(obs))
850 return 0;
851
852 foreach (object o: obs) {
853 if (objectp(o))
854 give(o, dest, msg);
855
856 if (get_eval_cost() < 100000) {
857 TME("Den Rest behaeltst Du erst mal.");
858 last_moved_objects = obs[..member(obs, o)];
859 last_moved_where = dest;
860 return 1;
861 }
862 }
863
864 last_moved_objects = obs;
865 last_moved_where = dest;
866 return 1;
867}
868
869varargs int show_objects(string str, mixed msg)
870{
871 object *obs, whom;
872
873 if (!stringp(str) || !sizeof(str))
874 return 0;
875
876 string *tokens = explode(str, " ");
877
878 for (int i = 0; i < sizeof(tokens)-1; i++) {
879 if (whom = present(implode(tokens[..i], " "), environment())) {
880 if (!living(whom)) {
881 NF("Aber " + whom->name(WER, 1) + " lebt doch gar nicht!");
882 continue;
883 }
884 } else {
885 if (i != 0 || tokens[0] != "allen")
886 continue;
887
888 if (!sizeof(filter(all_inventory(environment()) -
889 ({ this_object() }), #'living))) {
890 NF("Hier ist niemand, dem Du etwas zeigen koenntest!");
891 continue;
892 }
893 }
894
895 if (whom == this_object()) {
896 NF("Dazu solltest Du dann besser 'schau' benutzen!\n");
897 continue;
898 }
899
900 if (!sizeof(obs = __find_objects(tokens[i+1..], this_object(), 0)) &&
901 !sizeof(obs = __find_objects(tokens[i+1..], 0, 0)
902 - ({ this_object(), whom }))) {
903 NF("WAS moechtest Du " + (whom ? whom->name(WEM, 1) : "allen") +
904 " zeigen?");
905 continue;
906 }
907
908 foreach (object o: obs) {
909 if (objectp(o))
910 show(o, whom, msg);
911
912 if (get_eval_cost() < 100000) {
913 TME("Das reicht erst mal.");
914 last_moved_objects = obs[..member(obs, o)];
915 last_moved_where = whom;
916 return 1;
917 }
918 }
919
920 last_moved_objects = obs;
921 last_moved_where = whom;
922 return 1;
923 }
924
925 return 0;
926}
927
928object *moved_objects(void)
929{
930 return last_moved_objects;
931}
932
933object moved_where(void)
934{
935 return last_moved_where;
936}
937
938
939/************************* Die einzelnen Kommandos **************************/
940
941/* static int fallenlassen(string str)
942 * static int werfen(string str)
943 * static int legen(string str)
944 * static int stecken(string str)
945 * static int holen(string str)
946 * static int nehmen(string str)
947 * static int geben(string str)
948 * Minimale Wrapper fuer XXX_objects(), entfernen "fallen", "weg" bzw. "ab"
949 * aus den Argumenten und setzen entsprechende Standard-Fehlermeldungen.
950 *
951 * protected void add_put_and_get_commands()
952 * Registriert obige Funktionen per add_action().
953 */
954
955static int fallenlassen(string str)
956{
957 if (QueryProp(P_GHOST)) {
958 _notify_fail("Als Geist kannst Du nichts fallenlassen.\n");
959 return 0;
960 }
961
962 if (!str || str[<7..] != " fallen") {
963 _notify_fail("Lass etwas FALLEN, oder was meinst Du?\n");
964 return 0;
965 }
966
967 _notify_fail("WAS moechtest Du fallenlassen?\n");
968 return drop_objects(str[0..<8]);
969}
970
971static int werfen(string str)
972{
973 if (QueryProp(P_GHOST)) {
974 _notify_fail("Als Geist kannst Du nichts wegwerfen.\n");
975 return 0;
976 }
977
978 if (!str || str[<4..] != " weg") {
979 _notify_fail("Wirf etwas WEG, oder was meinst Du?\n");
980 return 0;
981 }
982
983 _notify_fail("WAS moechtest Du loswerden?\n");
984 return drop_objects(str[0..<5]);
985}
986
987static int legen(string str)
988{
989 if (QueryProp(P_GHOST)) {
990 _notify_fail("Als Geist kannst Du nichts weglegen.\n");
991 return 0;
992 }
993
994 if (!str) {
995 _notify_fail("Lege etwas AB, oder was meinst Du?\n");
996 return 0;
997 }
998
999 if (str[<3..] == " ab") {
1000 _notify_fail("WAS moechtest Du ablegen?\n");
1001 return drop_objects(str[0..<4]);
1002 }
1003
1004 if (str[<4..] == " weg") {
1005 _notify_fail("WAS moechtest Du weglegen?\n");
1006 return drop_objects(str[0..<5]);
1007 }
1008
1009 _notify_fail("WAS moechtest Du WOHIN legen?\n");
1010 return put_objects(str, WEN, "legen");
1011}
1012
1013static int stecken(string str)
1014{
1015 if (QueryProp(P_GHOST)) {
1016 _notify_fail("Das kannst Du in Deinem immateriellen Zustand nicht.\n");
1017 return 0;
1018 }
1019
1020 _notify_fail("WAS moechtest Du WOHIN stecken?\n");
1021 return put_objects(str, WEN, "stecken");
1022}
1023
1024static int holen(string str)
1025{
1026 if (QueryProp(P_GHOST)) {
1027 _notify_fail("Als Geist kannst Du nichts nehmen.\n");
1028 return 0;
1029 }
1030
1031 _notify_fail("WAS moechtest Du aus WAS holen?\n");
1032 return pick_objects(str, 1);
1033}
1034
1035static int nehmen(string str)
1036{
1037 if (QueryProp(P_GHOST)) {
1038 _notify_fail("Als Geist kannst Du nichts nehmen.\n");
1039 return 0;
1040 }
1041
1042 _notify_fail("WAS moechtest Du nehmen?\n");
1043 return pick_objects(str, 0);
1044}
1045
1046static int geben(string str)
1047{
1048 if (QueryProp(P_GHOST)) {
1049 _notify_fail("Als Geist kannst Du nichts weggeben.\n");
1050 return 0;
1051 }
1052
1053 _notify_fail("WEM moechtest Du WAS geben?\n");
1054 return give_objects(str);
1055}
1056
1057static int zeigen(string str)
1058{
1059 if (QueryProp(P_GHOST)) {
1060 _notify_fail("Als Geist kannst Du niemandem etwas zeigen.\n");
1061 return 0;
1062 }
1063
1064 _notify_fail("WEM moechtest Du WAS zeigen?\n");
1065 return show_objects(str);
1066}
1067
1068protected void add_put_and_get_commands(void)
1069{
1070 add_action("fallenlassen", "lass");
1071 add_action("fallenlassen", "lasse");
1072 add_action("werfen", "wirf");
1073 add_action("werfen", "werf");
1074 add_action("werfen", "werfe");
1075 add_action("legen", "leg");
1076 add_action("legen", "lege");
1077 add_action("stecken", "steck");
1078 add_action("stecken", "stecke");
1079 add_action("holen", "hol");
1080 add_action("holen", "hole");
1081 add_action("nehmen", "nimm");
1082 add_action("nehmen", "nehm");
1083 add_action("nehmen", "nehme");
1084 add_action("geben", "gebe");
1085 add_action("geben", "gib");
1086 add_action("zeigen", "zeig");
1087 add_action("zeigen", "zeige");
1088}
1089
1090
1091/********** Aus reinen Kompatibilitaetsgruenden weiterhin enthalten *********/
1092
1093object* find_obs(string str, int meth)
1094// gibt ein array zurueck mit allen Objekten die mit str angesprochen werden
1095{
1096 object inv;
1097 if (!str) return 0;
1098 if (str[<7..]==" in mir") {
1099 inv=ME;
1100 str=str[0..<8];
1101 }
1102 else if (str[<8..]==" in raum") {
1103 if (meth & PUT_GET_DROP) { // man kann nichts aus dem Raum wegwerfen
1104 _notify_fail("Du kannst nichts wegwerfen, das Du gar nicht hast.\n");
1105 return 0;
1106 }
1107 inv=environment();
1108 str=str[0..<9];
1109 }
1110 else if (meth & PUT_GET_DROP) inv=ME; // Raum bei drop uninteressant
1111 // else kein besonderes inv ausgewaehlt also inv=0
1112 if (!sizeof(str))
1113 return 0; // hier passt die bereits gesetzte _notify_fail
1114 else {
1115 object *obs;
1116 string con;
1117 if (sscanf(str, "%s aus %s", str, con)==2 ||
1118 sscanf(str, "%s in %s", str, con)==2 ||
1119 sscanf(str, "%s von %s", str, con)==2 ||
1120 sscanf(str, "%s vom %s", str, con)==2) {
1121 if (!inv) {
1122 if (!environment() || !(inv=present(con, environment())))
1123 inv=present(con, ME); // sowohl im env als auch im inv suchen
1124 }
1125 else inv=present(con, inv); // nur in ausgewaehltem inv suchen
1126 if (inv==ME) inv=0;
1127 if (!inv || !(inv->short())) {
1128 _notify_fail(break_string("Du hast hier aber kein '"+capitalize(con)
1129 +"'.",78));
1130 return 0;
1131 }
1132 if (living(inv)) {
1133 _notify_fail(break_string("Aber "+inv->name(WER,1)+" lebt doch!",78));
1134 return 0;
1135 }
1136 // wieso man aus Objekten die von std/tray abgeleitet werden etwas
1137 // nehmen koennen soll, versteh ich zwar nicht so ganz...
1138 if (!(inv->QueryProp(P_CONTAINER)) && !(inv->QueryProp(P_TRAY))) {
1139 _notify_fail(break_string("Du kannst nichts aus "+inv->name(WEM,1)
1140 +" nehmen.",78));
1141 return 0;
1142 }
1143 if (inv->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1144 _notify_fail(break_string("Aber "+inv->name(WER,1)
1145 +" ist doch geschlossen.", 78));
1146 return 0;
1147 }
1148 }
1149 else if (inv==ME && (meth & PUT_GET_TAKE)) { // nichts aus sich nehmen
1150 _notify_fail("Du kannst nichts nehmen, "
1151 "was Du schon bei Dir traegst.\n");
1152 return 0;
1153 }
1154 if (!inv && (meth & PUT_GET_TAKE))
1155 inv=environment(); // nichts nehmen was man schon hat
1156
1157 if (!inv) {
1158 if (environment()) {
1159 obs=(environment()->present_objects(str)||({}));
1160 if (!sizeof(obs)) obs+=(ME->present_objects(str)||({}));
1161 }
1162 else obs=(ME->present_objects(str) || ({}));
1163 }
1164 else obs=(inv->present_objects(str) || ({}));
1165 return obs-({ ME });
1166 }
1167 return(0);
1168}
1169
1170int pick_obj(object ob)
1171{
1172 object env;
1173
1174 if (!ob || ob == this_object() || environment(ob) == this_object()) return 0;
1175 if ((env=environment(ob)) != environment()) {
1176 if (!env->QueryProp(P_CONTAINER) && !env->QueryProp(P_TRAY)) {
1177 TME("Du kannst nichts aus " + env->name(WEM,1) + " nehmen.");
1178 return 1;
1179 }
1180 else if (env->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1181 TME("Aber " + env->name(WER, 1) + " ist doch geschlossen.");
1182 return 1;
1183 }
1184 }
1185 if (ob->IsUnit() && ob->QueryProp(P_AMOUNT)<0) {
1186 TME("Du kannst nicht mehr nehmen als da ist.");
1187 return 1;
1188 }
1189 pick(ob);
1190 return 1;
1191}
1192
1193int drop_obj(object ob)
1194{
1195 if (!ob || ob==this_object() || environment(ob)!=this_object()) return 0;
1196 drop(ob);
1197 return 1;
1198}
1199
1200int put_obj(object ob, object where)
1201{
1202 object env;
1203
1204 if (ob == this_object() || ob == where || environment(ob) == where) return 0;
1205 env=environment(ob);
1206 if (!where->QueryProp(P_CONTAINER)) {
1207 TME("Du kannst in " + where->name(WEN,1) + " nix reinstecken.");
1208 return 1;
1209 }
1210 if (where->QueryProp(P_CNT_STATUS)) { // Container ist geschlossen
1211 TME("Aber " + where->name(WER, 1) + " ist doch geschlossen.");
1212 return 1;
1213 }
1214 if (env!=environment(this_object()) && env!=this_object()) {
1215 _notify_fail("Da kommst du so nicht ran.\n");
1216 return 0;
1217 }
1218 put(ob, where);
1219 return 1;
1220}
1221
1222int give_obj(object ob, object where)
1223{
1224 object env;
1225
1226 if (environment(ob)!=this_object()) {
1227 TME("Das solltest Du erstmal nehmen.");
1228 return 1;
1229 }
1230 if (!ob || ob == this_object() || ob == where ||
1231 environment(where)!=environment())
1232 return 0;
1233 if (environment(ob) == where) {
1234 _notify_fail("Das Ziel ist in dem zu gebenden Object enthalten!\n");
1235 return 0;
1236 }
1237 if (environment(ob)!=this_object()) {
1238 TME("Das hast Du nicht.");
1239 return 1;
1240 }
1241 give(ob, where);
1242 return 1;
1243}