blob: 7fd0c5556107d8909bd4c17af0b2011976601587 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// raum.c -- Das Rohgeruest eines Seherhauses.
2//
3// Grundobjekt (c) 1994 Boing@MorgenGrauen
4// Abschliessen und Rauswerfen von Jof
5// Fuer Aenderungen ab dem 06.10.94 verantwortlich: Wargon
6// Ab 03.02.98 Wurzel
7//
8// $Id: raum.c,v 1.5 2003/11/15 14:03:58 mud Exp $
9#pragma strong_types,rtt_checks
10
11#include "haus.h"
12
13inherit "/std/room";
14inherit USERCMD; // selbstdefinierte Kommandos
15inherit LOSA; // Load() und Save()
16inherit "/mail/nedit";
17
18#include <wizlevels.h>
19#include <properties.h>
20#include <defines.h>
21#include <moving.h>
22
23static mixed detail;
24static string owner;
25static int flag, csaved;
26static int raumNr;
27static string *ausgaenge = ({ "oben", "norden", "nordosten", "osten", "suedosten",
28 "unten", "sueden", "suedwesten", "westen", "nordwesten" });
29
30// Prototypes fuer Funktionen aus LOSA
31varargs void Save(int crunched);
32void Load();
33
34// Prototype
35// Falls noetig, mache einen Notausgang, falls nicht loesche vorhandenen
36void make_emergency_exit();
37
38// ersetzt @@ durch **
39private string normstr(string str)
40{
41 return implode(explode(str,"@@"),"**");
42}
43
44// liefert kommagetrennte Teile ohne zusaetzliche Leerzeichen
45// "Bla blubb , foo bar,blubber" => ({ "Bla blubb", "foo bar", "blubber" })
46private string *brk(string str)
47{
48 string *t1;
49
50 t1 = explode(str, ",");
51 map(t1, #'trim /*'*/);
52 return t1;
53}
54
55// teste Befehl
56private int befCheck(string bef)
57{
58 // Befehl enthaelt Leerzeichen => return 0
59 if (member(bef, ' ') > -1)
60 return 0;
61
62 // Befehl ist bereits Kommando (ausser Oeffnen/Schliessen)
63 // oder Richtung inclusive "raus" in die kein Ausgang fuehrt
64 // => return 0
65 if (member(m_indices(QueryProp(P_COMMANDS)) -
66 ({"oeffne","schliess","schliesse"}), bef) > -1
67 || (member(ausgaenge+({"raus"}), bef) > -1
68 && member(m_indices(QueryProp(P_EXITS)), bef) == -1))
69 return 0;
70
71 return 1;
72}
73
74// Test auf Hausbesitzer
75int tp_owner_check()
76{
77 if(getuid(this_player()) != owner)
78 {
79 notify_fail( "Das ist nicht Dein Haus!\n" );
80 return 0;
81 }
82 return 1;
83}
84
85// Test auf Hausbesitzer oder Person mit Erlaubnis
86int allowed_check(object _test)
87{
88 string *ext;
89
90 ext = VERWALTER->HausProp(owner, HP_ALLOWED) + ({ capitalize(owner) });
91 if(member(ext, capitalize(getuid(_test))) < 0)
92 {
93 return 0;
94 }
95 else
96 {
97 return 1;
98 }
99}
100
101// Funktion ersetzt durch tp_owner_check() und allowed_check(object _test)
102// falls allowed == 0 => test ob this_player() Hausbesitzer
103// falls allowed != 0 => test ob allowed/this_player() Hausbesitzer
104// oder Person mit Erlaubnis
105deprecated varargs int owner_check(mixed allowed)
106{
107 object test;
108
109 if(objectp(allowed) && query_once_interactive(allowed))
110 {
111 // Parameter ist Spieler
112 test = allowed;
113 }
114 else
115 {
116 // ansonsten TP
117 test = this_player();
118 }
119
120 if(allowed)
121 {
122 // Test auf Hausbesitzer oder Person mit Erlaubnis
123 if(!allowed_check(test))
124 {
125 notify_fail( "Das darfst Du in diesem Haus nicht!\n" );
126 return 0;
127 }
128 }
129 else if(getuid(test) != owner)
130 {
131 // Test auf Hausbesitzer
132 notify_fail( "Das ist nicht Dein Haus!\n" );
133 return 0;
134 }
135 // Erlaubnis OK
136 return 1;
137}
138
139// Gestaltet Meldung aus Texten in einem Array:
140// array leer -> melde Text in none
141// array hat ein Element -> melde Text in one und ersetze %s durch Element
142// array hat viele Elemente -> melde Text in many und danach
143// sortierte Aufzaehlung der Elemente
144// flag gesetztes Bit 2: Aufzaehlung nur mit Komma, kein 'und'
145// flag gesetztes Bit 1: Meldung wird als String returnt, sonst per write ausgegeben
146varargs string arr_out(mixed array, string none, string one, string many, int flag)
147{
148 string tmp, lastsep;
149 mixed arr;
150
151 switch(sizeof(array))
152 {
153 case 0:
154 tmp = none;
155 break;
156 case 1:
157 tmp = sprintf(one, array[0]);
158 break;
159 default:
160 tmp = many;
161 arr = sort_array(array, #'> /*'*/);
162 lastsep = (flag & 2) ? ", " : " und ";
163 tmp += CountUp(arr, ", ", lastsep)+".";
164 break;
165 }
166 if (flag & 1)
167 return(break_string(tmp, 75, 0, 1));
168 else
169 write(break_string(tmp, 75, 0, 1));
170
171 return 0;
172}
173
174protected void create()
175{
176 if (!clonep(this_object()) && object_name(this_object())==(RAUM)) {
177 set_next_reset(-1);
178 return;
179 }
180 room::create();
181 usercmd::create();
182 losa::create();
183
184 Set(P_INT_LONG, SAVE, F_MODE_AS);
185 Set(P_INT_SHORT, SAVE, F_MODE_AS);
186 Set(P_EXITS, SAVE, F_MODE_AS);
187 Set(P_DETAILS, SAVE, F_MODE_AS);
188 Set(P_READ_DETAILS, SAVE, F_MODE_AS);
189 Set(P_LIGHT, SAVE, F_MODE_AS);
190
191 SetProp(P_IDS, ({"raum","sehe\rhaus"}));
192 SetProp(P_NAME, "Haus");
193 SetProp(P_GENDER, 0);
194 SetProp(P_TRANSPARENT, 0);
195 SetProp(P_NOGET, 1);
196 SetProp(P_LIGHT, 1);
197 SetProp(P_INDOORS, 1);
198
199 AddCmd( ({ "beschreib", "beschreibe" }), "beschreiben" );
200 AddCmd("uebersicht", "uebersicht");
201 AddCmd("ausgang", "ausgang");
202 AddCmd( ({"loesche", "loesch"}), "loesch");
203 AddCmd( ({"wirf", "werf", "werfe" }), "wirf");
204 AddCmd( ({"sperr", "sperre"}), "sperren");
205 AddCmd( ({"kopier", "kopiere" }), "kopieren");
206 AddCmd("licht", "licht");
207 AddCmd( ({"aendere", "aender" }), "aendern");
208 AddCmd( ({"meldung", "meldungen"}), "report");
209}
210
211void init()
212{
213 object haus;
214
215 room::init();
216 nedit::init_rescue();
217
218 // Magier betritt fremdes Seherhaus
219 if (query_once_interactive(PL) && IS_LEARNER(PL) && getuid(PL) != owner) {
220 if (PL->QueryProp(P_INVIS))
221 // Magier invis => im Raum melden
222 tell_room(this_object(),
223 capitalize(getuid(PL))+" betritt unsichtbar den Raum.\n",
224 ({PL}));
225
226 if ((haus = load_object(HAUSNAME(owner))) &&
227 (haus->QueryProp(H_DOORSTAT) & D_LOCKED))
228 // Tuer ist zu => Magier einen Hinweis geben
229 tell_object(PL, " ******* ACHTUNG *********************************\n *\n * "+
230 capitalize(owner)+" moechte vielleicht ungestoert bleiben!\n *\n"
231 " ******* ACHTUNG *********************************\n");
232 }
233}
234
235int PreventInsertLiving(object ob)
236{
237 return 0;
238}
239
240// Gegenstaende kommen in den Raum
241void NotifyInsert(object ob, object oldenv)
242{
243 object *found;
244
245 if (!objectp(ob)) return;
246
247 if (ob->QueryProp(H_FURNITURE)!=0)
248 {
249 // das was reinkam ist ein autoload Moebelstueck
250 // betrachte alle schon vorhandenen autoload Moebelstuecke
251 found = filter_objects(all_inventory(this_object()),
252 "QueryProp", H_FURNITURE);
253 if (sizeof(found)>=MAX_FURNITURE_PER_ROOM)
254 {
255 // Maximal-Anzahl vorhandener autoload Seherhausmoebel ist schon
256 // erreicht
257 tell_object(this_player(), break_string(
258 "Ein Raum kann nur "+MAX_FURNITURE_PER_ROOM+" rebootfeste "
259 "Moebel speichern. Hier befinden sich schon "+
260 CountUp(map_objects(found, "name"))+"."));
261 return 0;
262 }
263
264 queued_save(); // Speichern vorbereiten (falls mehrere Objekte
265 // gedroppt werden, wird so ein overflow verhindert.
266 }
267}
268
269// Gegenstaende verlassen den Raum
270void NotifyLeave(object ob, object dest)
271{
272 if (!ob &&!objectp(ob)) return 0;
273
274 // rebootfestes Moebelstueck verlaesst den Raum
275 if (ob->QueryProp(H_FURNITURE)!=0)
276 {
277 // Speichern vorbereiten (falls mehrere Objekte
278 // gedroppt werden, wird so ein overflow verhindert.
279 queued_save();
280 }
281 return 0;
282}
283
284void
285reset()
286{
287 room::reset();
288 losa::reset();
289 // Wenn ein Notausgang vorhanden ist, checken, ob der noch noetig ist.
290 if (member(m_indices(QueryProp(P_EXITS)),"notausgang")!=-1)
291 {
292 make_emergency_exit();
293 }
294}
295
296int clean_up(int arg)
297{
298 mixed inv;
299
300 if (arg > 1)
301 return 1;
302
303 losa::reset(); // Evtl. gepackt speichern...
304
305 // nichts im Raum oder nur leere Seherhaustruhe => Raum kann weg
306 if ((sizeof(inv=all_inventory()) == 0) ||
307 (sizeof(inv) == 1 && inv[0]->id(TRUHE) &&
308 sizeof(all_inventory(inv[0]))==0))
309 remove(1);
310
311 return 0;
312}
313
314// Haeufungen von gleichen Objekten sind hier egal => nix tun
315protected varargs void remove_multiple(int limit) {}
316
317
318// Spieler wird im Raum Netztot
319void BecomesNetDead(object pl)
320{
321// Nicht erlaubte Spieler werden rausgeworfen, alle anderen bleiben drin.
322 if(!allowed_check(pl))
323 pl->move(VERWALTER->HausProp(owner, HP_ENV), M_GO, 0, "schlafwandelt heraus", "schlafwandelt herein" );
324}
325
326
327/* Ist dieser Raum ein Ausgang? */
328int is_exit(string path)
329{
330 return (sizeof(path) > 4) && (path[<5..] == "raum0");
331}
332
333/*Pruefung, ob es einen Hausausgang gibt*/
334int room_has_exit() {
335
336 string room = object_name(this_object());
337 // sind wir schon in einem Hauptraum mit Ausgang?
338 if (is_exit(room)) return 1;
339
340 mapping r_todo = ([room]);
341 mapping r_done = ([:0]);
342 /* Die Schleife hat maximal 9 * Anzahl der verb. Haeuser Durchlaeufe */
343 while (sizeof(r_todo))
344 {
345 mapping r_exits = ([]);
346
347 // naechsten Raumpfad abarbeiten, d.h. dessen Ausgaenge betrachten
348 room = m_indices(r_todo)[0];
349 // abgearbeiteten Raumpfad von r_todo nach r_done schieben
350 r_done += ([room]);
351 m_delete(r_todo, room);
352
353 // alle Ausgaenge betrachten
354 foreach(string command, string subpath : room->QueryProp(P_EXITS))
355 {
356 // Notausgaenge nicht betrachten, da 'echte' Ausgaenge gesucht sind
357 if(command != "notausgang")
358 // alle anderen Ausgaenge sammeln
359 r_exits += ([ subpath ]);
360 }
361 // nur Raumpfade die noch nicht abgearbeitet sind testen
362 r_exits -= r_done;
363 // ist da ein Hauptraum (der dann Ausgang liefert) dabei?
364 if (sizeof(filter_indices(r_exits, #'is_exit/*'*/)))
365 return 1;
366
367 // neue Raumpfade in die TODO-Liste aufnehmen
368 r_todo += r_exits;
369 }
370 return 0;
371}
372
373// damit man Spieler nicht durch Entfernen von Ausgaengen einsperren kann
374// werden bei Bedarf Notausgaenge in den Hauptraum ergaenzt
375void make_emergency_exit()
376{
377 // Ist der Raum weder Hauptraum mit Ausgang noch fuehrt ein Weg dorthin?
378 // dann Notausgang machen
379 if(!room_has_exit())
380 {
381 // tell_room(this_object(),"DEBUG: Ein Notausgang wurde angelegt.\n");
382 room::AddExit("notausgang",
383 "durch den Notausgang#"+to_string(this_object())[0..<2]+"0");
384 }
385 else
386 {
387 // nicht mehr benoetigten Notausgang entfernen
388 room::RemoveExit("notausgang");
389 }
390}
391
392// ruft direkt das geerbte AddExit auf, ohne ggf. einen Notausgang zu
393// erzeugen. Das wird vom Haus und vom Verwalter benutzt, um Ausgaenge zu
394// erzeugen. Das ist noetig, weil der Notausgangmechanismus noch nicht
395// funktoniert, wenn der Raum gerade geladen wird (hat noch nicht den
396// endgueltigen Namen) und der Check waere ohnehin unnoetig.
397public void AddExitNoCheck(mixed cmd, mixed dest)
398{
399 room::AddExit(cmd, dest);
400}
401
402// Wird benutzt beim Laden von Raeumen, um alle Ausgaenge zu loeschen. Dabei
403// darf _kein_ Notausgang erstellt werden.
404void RemoveExitNoCheck(mixed cmd)
405{
406 room::RemoveExit(cmd);
407}
408
409// beim Ausgang setzten testen ob vorhanderner Notausgang noch benoetigt wird
410void AddExit(mixed cmd, mixed dest)
411{
412 room::AddExit(cmd, dest);
413
414 if (member(m_indices(QueryProp(P_EXITS)),"notausgang")!=-1)
415 {
416 // loescht Notausgang falls nicht mehr benoetigt
417 make_emergency_exit();
418 }
419}
420
421// beim Ausgang loeschen testen ob Notausgang benoetigt wird
422void RemoveExit(mixed cmd)
423{
424 room::RemoveExit(cmd);
425 // setzt Notausgang falls benoetigt
426 make_emergency_exit();
427}
428
429// der Langbeschreibung werden alle unsichtbaren Magier
430// (ausgenommen Seherhausbesitzer) in Klammern angefuegt
431varargs string int_long(mixed viewer, mixed viewpoint, int flags)
432{
433 string ret;
434 object *inv;
435 string *tmp;
436
437 ret = ::int_long(viewer, viewpoint, flags);
438
439 // nur was machen wenn der Betrachter im Raum ist
440 if (!ret || !objectp(viewer) || environment(viewer) != this_object())
441 return ret;
442
443 if(viewpoint == 0)
444 viewpoint = ({ viewer });
445 else if(!pointerp(viewpoint))
446 viewpoint = ({ viewpoint });
447
448 // alle Lebewesen ausser denen aus deren Sicht betrachtet wird
449 inv = filter(all_inventory(this_object()),#'interactive) - viewpoint;
450 foreach(object pl : inv)
451 {
452 // raussuchen wer ausser Seherhausbesitzer unsichtbar ist
453 if(pl && IS_LEARNER(pl) && pl->QueryProp(P_INVIS) && getuid(pl)!=owner)
454 {
455 // Name in Klammer sammeln
456 tmp += ({ "("+capitalize(getuid(pl))+")" });
457 }
458 }
459 return ret + break_string(CountUp(tmp), 78);
460}
461/*
462// TODO: Testen ob das hier nicht das Standard-Verhalten ist
463int lies(string str)
464{
465 string txt;
466
467 notify_fail("Was moechtest Du lesen?\n");
468 if (!str) return 0;
469
470 if (this_player()->CannotSee())
471 return 1;
472 if (txt = QueryProp(P_READ_DETAILS)[str]) {
473 this_player()->More(txt);
474 return 1;
475 }
476 return 0;
477}
478*/
479// Aktion Lebewesen oder Gegenstaende aus dem Haus werfen
480int wirf(string str)
481{
482 string wen, args;
483 object pl, target, *list, tp, to;
484
485 tp = this_player();
486 to = this_object();
487 args = tp->_unparsed_args(1);
488
489 // klappt nur vor Ort und mit der passenden Syntax
490 if ((environment(tp)!=to) ||
491 !args || args == "" ||
492 (sscanf(args,"%s raus",wen) != 1) )
493 return 0;
494 // Raum, in dem das Haus steht, ermitteln
495 target=find_object(VERWALTER->HausProp(owner, HP_ENV));
496 if (!target) {
497 notify_fail("Dieses Haus steht leider gerade in einem "
498 "Fehler im Raum-Zeit-Gefuege.\n");
499 return 0;
500 }
501 // Rauswerfen darf nur der Besitzer
502 if (!tp_owner_check()) {
503 notify_fail("Aber Du kannst doch niemanden aus dem Haus von "+capitalize(owner)+" werfen!\n");
504 return 0;
505 }
506 if (wen=="alle") {
507 // alle Lebewesen ausser tp (== Hausbesitzer)
508 list=filter(all_inventory(to),#'living)-({tp,0});//')
509 if (sizeof(list)==0) {
510 notify_fail("Aber Du bist doch allein in Deinem Haus!\n");
511 return 0;
512 }
513 } else if (wen == "alles") {
514 // alle Gegenstaende ausser Lebewesen und Moebel
515 // (Seherhaustruhe, Autoloader-Moebel oder Seherhaus-Moebel)
516 list = filter(all_inventory(to),
517 function int(object ob)
518 {
519 return objectp(ob) &&
520 !living(ob) &&
521 !ob->id(TRUHE) &&
522 // TODO Test auf nicht Seherhausmoebel von August
523 strstr(load_name(ob),"/d/seher/haeuser/moebel/")
524 == 0;
525 } );
526
527 if (sizeof(list)==0) {
528 notify_fail("Aber hier ist nichts zum wegwerfen!\n");
529 return 0;
530 }
531 } else {
532 pl=present(wen,to);
533 if (!pl) {
534 notify_fail("So jemanden sehe ich hier nicht.\n");
535 return 0;
536 }
537 else if (pl->id(TRUHE) ||
538 // TODO Test auf Seherhausmoebel von August
539 strstr(load_name(pl),"/d/seher/haeuser/moebel/")==0
540 ) {
541 notify_fail("Du kannst "+pl->name(WEN)+" nicht wegwerfen!\n" );
542 return 0;
543 }
544 list=({pl});
545 }
546 string msg_wen = sprintf("%s wirft Dich aus %s Haus.\n",
547 tp->Name(WER),
548 tp->QueryPossPronoun(NEUTER,WEM));
549 // fuer alle rauszuwerfenden Opfer Meldungen machen und rausbewegen
550 foreach(object ob : list)
551 {
552 tell_object(ob, msg_wen);
553 tell_room(target,
554 sprintf("%s kommt in hohem Bogen aus dem Haus von %s geflogen.\n",
555 ob->Name(WER),tp->name(WEM)));
556 ob->move(target,M_SILENT|M_GO);
557 tell_room(to,sprintf("%s wirft %s aus %s Haus.\n",
558 tp->Name(WER),
559 ob->name(WEN),tp->QueryPossPronoun(NEUTER,WEM)),
560 ({tp}));
561 printf("Du wirfst %s aus Deinem Haus.\n",ob->name(WEN));
562 // Verfolger abmelden, damit sie nicht gleich zurueckkommen
563 // TODO wenn man einzelne Lebewesen rauswirft kann das ja auch
564 // ein Verfolger von einem anderen Gast sein...
565 tp->RemovePursuer(ob);
566 }
567 return 1;
568}
569
570// Besitzer und Raumnummer fuer diesen Raum setzen
571varargs string SetOwner(string o, int num)
572{
573 // Default Kurz- und Langbeschreibung setzen
574 SetProp(P_INT_SHORT, "Im Haus von "+capitalize(o));
575 SetProp(P_INT_LONG, "Ein total leerer Raum.\n");
576 // Raumnummer und Besitzer merken
577 raumNr = num;
578 return owner = o;
579}
580
581// Liefert den Besitzer
582// falls withNr != 0 mit angehaengter Raumnummer
583varargs string QueryOwner(int withNr)
584{
585 return (withNr ? owner+raumNr : owner);
586}
587
588// Prototype
589static int befEingabe(string *bef);
590
591// Aktion zum Beschreiben des Raumes
592varargs int
593beschreiben(string str, int f)
594{
595 string *parts;
596 int sp, ret;
597
598 // nur der Besitzer darf
599 if(!tp_owner_check())
600 return 0;
601
602 if (!f && (!(str=UP_ARGS(this_player())) || str == "")) {
603 notify_fail("Was willst Du denn beschreiben?\n" );
604 return 0;
605 }
606
607 sp = sizeof(parts = old_explode(str, " "));
608 // je nachdem was beschrieben wird, setze detail und flag
609 // und starte damit Editor, bzw. behandle Befehle extra
610 detail = 0;
611 flag = f;
612
613 switch(parts[0][0..3]) {
614 case "raum": // Lang- oder Kurzbeschreibung
615 case "haus":
616 if (sp == 1 || parts[1] == "lang")
617 flag |= LANG;
618 else if (parts[1] == "kurz")
619 flag |= KURZ;
620 printf("Bitte %sbeschreibung des %s eingeben.\n", (flag & LANG ? "Lang" : "Kurz"), (flag & AUSSEN ? "Hauses" : "Raumes") );
621 break;
622 case "deta": // Details
623 if (sp==1) {
624 notify_fail("Welches Detail willst Du denn beschreiben?\n");
625 return 0;
626 }
627 flag |= DETAIL;
628 str = implode(parts[1..]," ");
629 write( "Bitte Beschreibung fuer '"+str+"' eingeben.\n");
630 break;
631 case "lesb": // lesbare Details
632 notify_fail("Welches lesbare Detail willst Du denn beschreiben?\n");
633 if (sp == 1) return 0;
634 if (parts[1] == "details" || parts[1] == "detail") {
635 if (sp == 2) return 0;
636 str = implode(parts[2..]," ");
637 }
638 else
639 str = implode(parts[1..]," ");
640 flag |= RDETAIL;
641 write( "Bitte Beschreibung fuer '"+str+"' eingeben.\n");
642 break;
643 case "befe": // Befehle
644 ret = 0;
645 if (sp == 1)
646 notify_fail("Welchen Befehl willst Du denn beschreiben?\n");
647 else
648 ret = befEingabe(brk(implode(parts[1..]," ")));
649 return ret;
650 break;
651 default:
652 notify_fail("Das kannst Du nicht beschreiben! Eine Liste der Dinge, die Du hier\n"
653 +"beschreiben kannst, erhaeltst Du mit 'hilfe beschreibe'.\n" );
654 return 0;
655 break;
656 }
657 detail = brk(str);
658 write( "(Beenden mit . oder **, Abbruch mit ~q)\n" );
659 nedit( "beschreibung" );
660 return 1;
661}
662
663// nedit von beschreibe xxx
664static void beschreibung(string str)
665{
666 if (!str) {
667 write("Nichts geaendert!\n");
668 return;
669 }
670
671 str = normstr(str);
672
673 if (flag & LANG)
674 {
675 // Langbeschreibung
676 if (sizeof(explode(str,"\n")) > 100
677 || sizeof(str) > 7800)
678 {
679 // ueber 100 Zeilen oder ueber 7800 Zeichen
680 write( "Das ist fuer eine Langbeschreibung zu lang!\n"
681 "Sorry, bitte denke Dir eine andere Langbeschreibung aus.\n" );
682 return;
683 }
684 if (flag & AUSSEN) {
685 // Langbeschreibung vom Haus
686 object haus;
687 haus = find_object(HAUSNAME(owner));
688 haus->SetProp(P_LONG, str);
689 haus->Save();
690 }
691 else
692 // Langbeschreibung von diesem Raum
693 SetProp(P_INT_LONG, str);
694 }
695 else if (flag & KURZ) {
696 // Kurzbeschreibung vom Raum
697 if (sizeof(old_explode(str,"\n")) > 1 || sizeof(old_explode(str,".")) > 2 || sizeof(str) > 75) {
698 write( "Das ist fuer eine Kurzbeschreibung zu lang!\nSorry, bitte denke Dir eine andere Kurzbeschreibung aus.\n" );
699 return;
700 }
701 else
702 // Vanion, 27.07.02, Bugfix
703 // Die Zeile buggte, wenn man "." oder "\n" oder "\n." oder sowas
704 // in str hat. (also z.B. bei "beschreibe raum kurz <return> .")
705 // SetProp(P_INT_SHORT, old_explode(old_explode(str,"\n")[0],".")[0]);
706 SetProp(P_INT_SHORT, explode(explode(str,"\n")[0],".")[0]);
707 }
708 else if (flag & DETAIL)
709 // Raum-Detail
710 AddDetail(detail, str);
711 else if (flag & RDETAIL)
712 // lesbares Raum-Detail
713 AddReadDetail(detail, str);
714 else {
715 write( "Huch! Unbekanntes Flag ("+flag+")... Sag mal "
716 + CountUp(MAINTAINER, ", ", " oder ")
717 + " Bescheid...\n");
718 return;
719 }
720
721 write("OK.\n");
722 Save();
723}
724
725// wird in beschreiben(str, int) 'beschreibe befehl' aufgerufen
726static int befEingabe(string *befehle)
727{
728 string* com = ({});
729
730 notify_fail("Kein Befehl zum Beschreiben uebrig... ;)\n");
731 foreach(string bef : befehle)
732 {
733 // schon vorhandener Befehl (ausser oeffnen/schlissen),
734 // Richtung ohne zugehoerigen Ausgang,
735 // oder Befehl enthaelt Leerzeichen
736 if (!befCheck(bef))
737 write("Der Befehl '"+bef+"' kann nicht beschrieben werden!\n");
738 else
739 com += ({ bef });
740 }
741 if (!sizeof(com))
742 return 0;
743
744 arr_out(com, 0, "Zu beschreibender Befehl: %s",
745 "Zu beschreibende Befehle:\n");
746
747 write( "Bitte Parameter eingeben (evtl. durch Kommata getrennt).\n]");
748 input_to("getBefParam", 0, com);
749 return 1;
750}
751
752// input_to aus befEingabe(string) zu beschreibe befehl ...
753static void getBefParam(string param, string *bef)
754{
755 string txt = "Gib nun bitte den Text ein, der fuer diesen Befehl "
756 "ausgegeben werden soll.\n";
757
758 // Fuehrende und abschliessende Leerzeichen entfernen
759 if (param)
760 param = trim(param);
761
762 if (!param || param == "")
763 // kein Parameter, z.b. bei beschreibe befehl klopfe
764 detail = ({ bef, "" });
765 else if (param == "@NF@" || param == "@nf@") {
766 // Parameter fuer notify fail zum Ersetzen von Wie bitte?
767 // z.B. bei beschreibe befehl druecke
768 // fuer danach Du kannst hier kein @PARA druecken, nur den Knopf!
769 detail = ({ bef, 1 });
770 txt = "Gib nun bitte den Text ein, der als Fehlermeldung "
771 "ausgegeben werden soll.\n@PARA dient dabei als Platzhalter fuer "
772 "die ungueltige Eingabe.\n";
773 }
774 else
775 // sonstige Parameter
776 // z.B. knopf, klingel bei beschreibe befehl druecke
777 detail = ({ bef }) + brk(lower_case(param));
778
779 printf(txt+"(Beenden mit . oder **, Abbruch mit ~q)\n");
780 nedit("getBefText");
781}
782
783// Prototype
784private string preparse(string str, string *invalid);
785
786// nedit fuer die Eingabe der Texte (Fehlermeldung/Meldungen) fuer den Befehl
787static void getBefText(string text)
788{
789 string my, *txt, *warn;
790 mixed bef;
791
792 if (!text || text == "") {
793 write("** Abbruch! **\n");
794 detail = 0;
795 return;
796 }
797 // gemerktes Befehls-Array
798 bef = detail[0];
799
800 txt = old_explode(text, "@@\n");
801
802 warn = ({});
803
804 // Meldung an this_player() parsen und in warn falsche Platzhalter sammeln
805 my = preparse(txt[0], &warn);
806 string other = 0;
807 if (sizeof(txt) > 1)
808 // Meldung an andere parsen und in warn falsche Platzhalter sammeln
809 other = preparse(txt[1], &warn);
810
811 AddUserCmd(bef, (stringp(detail[1]) ? detail[1..] : ({ "@NF@" })), my, other);
812 Save();
813 arr_out(warn, "OK.", "WARNUNG! Ungueltiger Platzhalter: %s",
814 "WARNUNG! Ungueltige Platzhalter: ");
815
816 detail = 0;
817}
818
819// check, ob an Position pos in txt ein Buchstabe aus dem array choice steht
820// return 0 falls nicht, prefix + Position des Buchstabens in choice ansonsten
821// check_placeholder(({"R","S","M","N"}), 2, "WESSEN", "X"); -> X1
822string check_placeholder(string* choice, int pos, string txt, string prefix)
823{
824 int idx;
825
826 if(sizeof(txt) < pos+1 ||
827 ((idx=member(choice, txt[pos..pos])) < 0))
828 {
829 return 0;
830 }
831 else
832 {
833 return prefix+to_string(idx);
834 }
835}
836
837// Dann drueckt @PWER den Knopf -> Dann drueckt @P0 den Knopf
838private string preparse(string str, string *invalid)
839{
840 string *txt;
841
842 txt = explode(str, "@");
843 // fuer jeden Textteil nach einem @
844 // suche Ersatz fuer den Begriff direkt nach dem @
845 // AN: wuerde es nicht theoretisch reichen, hier nur bis i>0
846 // runterzuzaehlen? Das erste Element des Arrays ist immer irrelevant, weil
847 // entweder Leerstring oder kein zu ersetzender Ausdruck.
848 for (int i=sizeof(txt)-1; i>=0; i--) {
849 int warn = 0;
850 string rpl = 0;
851 // falls Teil zu kurz nix ersetzen
852 if (sizeof(txt[i])<3)
853 continue;
854 // anhand der ersten Buchstaben, Ersatz bestimmen
855 // warn signalisiert, ob dies schiefging:
856 switch(txt[i][0..1]) {
857 case "WE": // Name
858 // WER -> W0
859 // WES(SEN) -> W1
860 // WEM -> W2
861 // WEN -> W3
862 rpl = check_placeholder(({"R","S","M","N"}), 2, txt[i], "W");
863 warn = !rpl;
864 break;
865 case "PW": // Personalpronomen
866 // PWER -> P0
867 // PWES(SEN) -> P1
868 // PWEM -> P2
869 // PWEN -> P3
870 rpl = check_placeholder(({"R","S","M","N"}), 3, txt[i], "P");
871 warn = !rpl;
872 break;
873 case "BN": // Possessivpronomen
874 case "BM":
875 case "BF":
876 // BNSWER -> B000 BMSWER -> B010 BFSWER -> B020
877 // BNSWES(SEN) -> B100 BMSWES(SEN) -> B110 BFSWES(SEN) -> B120
878 // BNSWEM -> B200 BMSWEM -> B210 BFSWEM -> B220
879 // BNSWEN -> B300 BMSWEN -> B310 BFSWEN -> B320
880 //
881 // BNPWER -> B001 BMPWER -> B011 BFPWER -> B021
882 // BNPWES(SEN) -> B101 BMPWES(SEN) -> B111 BFPWES(SEN) -> B121
883 // BNPWEM -> B201 BMPWEM -> B211 BFPWEM -> B221
884 rpl = check_placeholder(({"R","S","M","N"}), 5, txt[i], "B");
885 warn = !rpl;
886 if(!warn)
887 {
888 rpl = check_placeholder(({"N","M","F"}), 1, txt[i], rpl);
889 warn = !rpl;
890 if(!warn)
891 {
892 rpl = check_placeholder(({"S","P"}), 2, txt[i], rpl);
893 warn = !rpl;
894 }
895 }
896 break;
897 case "PA":
898 // PARA -> F
899 // kein Ersatz, sondern Textteil hier direkt ersetzen:
900 if(sizeof(txt[i]) > 4)
901 txt[i] = "F"+txt[i][4..];
902 break;
903 default:
904 // kein Ersatz, nix aendern
905 warn = 0;
906 rpl = 0;
907 }
908
909 // falls Ersatz vorhanden, ersetze Pronomen durch ""+rpl und lasse den Rest t2[2] wie ist
910 if (rpl) {
911 string* t2;
912 warn = sizeof(t2 = regexplode(txt[i], "(WER|WESSEN|WEM|WEN)")) < 2;
913 if (!warn) {
914 t2[1] = rpl;
915 t2[0] = "";
916 txt[i] = implode(t2, "");
917 }
918 }
919 // falls es Probleme gab, diese merken
920 if (warn)
921 invalid += ({ "@"+old_explode(txt[i]," ")[0] });
922
923 } // for (i=sizeof(txt)-1; i>=0; i--)
924 // die eventuelle teilweise ersetzetn Teile wieder zusammenfuegen
925 return implode(txt, "@");
926}
927
928static void loesch_alles(string str)
929{
930 if (str == "ja" || str == "Ja") {
931 RemoveDetail(0);
932 RemoveReadDetail(0);
933 //SetProp(P_READ_DETAILS, ([]));
934 SetProp(H_COMMANDS, ([]));
935 write( "OK, alle Details, lesbaren Details und Befehle geloescht!\n" );
936 Save();
937 }
938 else
939 write( "Nichts geloescht!\n" );
940}
941
942static void loesch_etwas(string str, string prop)
943{
944 if (str == "ja" || str == "Ja") {
945 if ( prop == P_DETAILS )
946 RemoveDetail(0);
947 else if ( prop == P_READ_DETAILS )
948 RemoveReadDetail(0);
949 else
950 SetProp(prop, ([]));
951 write("OK.\n");
952 Save();
953 }
954 else
955 write( "Nichts geloescht!\n" );
956}
957
958int loesch(string str)
959{
960 string *s, *t, p, q;
961 int i, ret;
962 mapping com;
963
964 if (!tp_owner_check())
965 return 0;
966
967 if (!(str=UP_ARGS(this_player())) || str == "") {
968 notify_fail("Welches Detail oder welchen Befehl moechtest Du loeschen?\n");
969 return 0;
970 }
971
972 if (str == "alles") {
973 write( "Wirklich alles loeschen (ja/nein)?\n]");
974 input_to("loesch_alles");
975 return 1;
976 }
977
978 if(str=="meldungen") {
979 if(file_size(PATH+"rep/"+owner+".rep")>0) {
980 rm(PATH+"rep/"+owner+".rep");
981 write("Meldungen geloescht.\n");
982 }else{
983 write("Keine Meldungen gefunden.\n");
984 }
985 return 1;
986 }
987
988 s = brk(str);
989 s = ({ (t=old_explode(s[0], " "))[0] })+({ implode(t[1..]," ") })+s[1..];
990 ret = 1;
991 flag = 0;
992
993 switch(s[0]) {
994 case "detail":
995 s = s[1..];
996 flag |= DETAIL;
997 break;
998 case "lesbar":
999 flag |= RDETAIL;
1000 s = s[1..];
1001 break;
1002 case "lesbares":
1003 case "lesbare":
1004 flag |= RDETAIL;
1005 if (s[1][0..5] =="detail") {
1006 s = ({ old_explode(s[1]," ")[<1] });
1007 if (sizeof(s)>2)
1008 s += s[2..];
1009 }
1010 else
1011 s = s[1..];
1012 break;
1013 case "befehl":
1014 s = s[1..];
1015 break;
1016 case "alle":
1017 switch (s[1]) {
1018 case "details":
1019 q = "Details";
1020 p = P_DETAILS;
1021 break;
1022 case "lesbaren details":
1023 q = "lesbaren Details";
1024 p = P_READ_DETAILS;
1025 break;
1026 case "befehle":
1027 q = "Befehle";
1028 p = H_COMMANDS;
1029 break;
1030 default:
1031 write("Du kannst alle Befehle, alle Details und alle lesbaren Details loeschen!\n");
1032 return 1;
1033 }
1034 printf("Wirklich alle %s loeschen (ja/nein)?\n]", q);
1035 input_to("loesch_etwas", 0, p);
1036 return 1;
1037 default:
1038 flag |= (DETAIL|RDETAIL);
1039 ret = 0; // Koennte auch ein Artikel in der Zeitung sein...
1040 break;
1041 }
1042 for (i=sizeof(s)-1; i>=0; i--) {
1043 if (!flag) { // Befehl soll geloescht werden...
1044 if (member(com=Query(H_COMMANDS), s[i])) {
1045 com = m_copy_delete(com, s[i]);
1046 write("Befehl '"+s[i]+"' wurde geloescht.\n");
1047 }
1048 else if (sizeof(t=old_explode(s[i], " ")) > 1 &&
1049 member(com, t[0]) &&
1050 member(com[t[0]], p=implode(t[1..], " "))) {
1051 com[t[0]] = m_copy_delete(com[t[0]], p);
1052 write("Befehl '"+s[i]+"' wurde geloescht.\n");
1053 }
1054 Set(H_COMMANDS, com);
1055 }
1056 else {
1057 if (flag & DETAIL) {
1058 if (!QueryProp(P_DETAILS)[s[i]])
1059 notify_fail("Das Detail '"+s[i]+"' gibt es nicht.\n");
1060 else {
1061 RemoveDetail(s[i]);
1062 write("Detail '"+s[i]+"' wurde geloescht.\n");
1063 ret = 1;
1064 }
1065 }
1066 if (flag & RDETAIL) {
1067 if (!QueryProp(P_READ_DETAILS)[s[i]])
1068 notify_fail("Das lesbare Detail '"+s[i]+"' gibt es nicht.\n");
1069 else {
1070 RemoveReadDetail(s[i]);
1071 write("Lesbares Detail '"+s[i]+"' wurde geloescht.\n");
1072 ret = 1;
1073 }
1074 }
1075 }
1076 }
1077 Save();
1078 return ret;
1079}
1080
1081int ausgang(string str)
1082{
1083 int nr, maxNr, hin, zurueck;
1084 string hier, da, ext;
1085 closure hausProp;
1086 mapping known_exits;
1087
1088 if (!tp_owner_check()) {
1089 return 0;
1090 }
1091
1092 hier = da = 0;
1093 hausProp = symbol_function("HausProp",VERWALTER);
1094
1095 if (!(str=UP_ARGS(this_player())) ||
1096 (sscanf(str, "%s %d", hier, nr) != 2 &&
1097 sscanf(str, "%s %s %d",hier, ext, nr) != 3) ) {
1098 notify_fail( "Syntax: ausgang <richtung> [name] <nr>\n" );
1099 return 0;
1100 }
1101
1102 if (ext) {
1103 if (funcall(hausProp, ext, HP_ENV) != funcall(hausProp, owner, HP_ENV)) {
1104 printf("Das Haus von %s steht nicht im gleichen Raum wie Dein Haus!\n",
1105 capitalize(ext));
1106 return 1;
1107 }
1108 else
1109 da = RAUMNAME(ext, nr);
1110
1111 // der allowed_check() wird im Eingangsraum des Zielhauses aufgerufen,
1112 // da wir von anderen Raumen noch nicht wissen, ob sie ueberhaupt
1113 // existieren.
1114 if (!(RAUMNAME(ext, 0)->allowed_check(this_player()))) {
1115 printf("Du darfst keinen Ausgang von Deinem Haus zu dem von %s legen!\n",
1116 capitalize(ext));
1117 return 1;
1118 }
1119 }
1120 else {
1121 ext = owner;
1122 da = RAUMNAME(ext, nr);
1123 }
1124
1125 maxNr = funcall(hausProp, ext, HP_ROOMS);
1126
1127 if ( (hin = member(ausgaenge, lower_case(hier))) < 0) {
1128 arr_out(ausgaenge, 0, 0, "Es sind nur folgende Ausgaenge moeglich:\n" );
1129 return 1;
1130 }
1131 else
1132 zurueck = (hin + sizeof(ausgaenge)/2) % sizeof(ausgaenge);
1133
1134 hier = RAUMNAME(owner, raumNr);
1135
1136 // Kopie des Ausgaenge-Mappings erzeugen
1137 known_exits=deep_copy(QueryProp(P_EXITS));
1138 // und den Notausgang entfernen. Somit bleiben nur die zu betrachtenden
1139 // Ausgaenge ueber.
1140 known_exits["notausgang"]=0;
1141
1142 if (nr < 0 || nr > maxNr)
1143 printf( "Die Nummer darf sich nur im Bereich zwischen 0 und %d bewegen!\n",
1144 maxNr );
1145 else if ( ext == owner && nr == raumNr)
1146 printf( "Aber dies IST Raum %d!\n", raumNr );
1147 else if (member(m_indices(known_exits), ausgaenge[hin]) != -1)
1148 write( "Aus diesem Raum fuehrt schon ein Ausgang in diese Richtung!\n" );
1149 //else if (member(m_values(QueryProp(P_EXITS)), da) != -1)
1150 // Notausgang wird hier zwar geloescht, aber im AddExit
1151 // gibt's eh einen neuen, so das noetig ist, V*
1152 else if (member(m_values(known_exits), da) != -1)
1153 printf( "Es gibt hier schon einen Ausgang zu Raum %d!\n", nr );
1154 else if (member(m_indices(da->QueryProp(P_EXITS)), ausgaenge[zurueck]) != -1)
1155 printf( "Es fuehrt schon irgendwo ein Ausgang in Richtung '%s'\n"
1156 "nach Raum %d!\n", ausgaenge[hin], nr);
1157 else {
1158 AddExit( ausgaenge[hin], da );
1159 Save();
1160 da->AddExit(ausgaenge[zurueck], hier);
1161 da->Save();
1162 printf( "OK, der Ausgang '%s' zum Raum %d wurde eingerichtet.\n",
1163 ausgaenge[hin], nr );
1164 }
1165 return 1;
1166}
1167
1168int
1169sperren(string str)
1170{
1171 mapping ex, cmds;
1172 int hin, zurueck;
1173
1174 if (!tp_owner_check())
1175 return 0;
1176
1177 if (!(str=UP_ARGS(this_player())) || str == "") {
1178 notify_fail( "Syntax: sperre <ausgang>\n" );
1179 return 0;
1180 }
1181 str = lower_case(str);
1182 ex = QueryProp(P_EXITS);
1183
1184 if (raumNr == 0 && str == "raus") {
1185 write( "Du kannst doch nicht Deine Haustuer loeschen!\n" );
1186 return 1;
1187 }
1188 if (!member(ex,str) || (hin = member(ausgaenge,str)) < 0) {
1189 printf( "Es gibt hier keinen Ausgang '%s'!\n", str);
1190 return 1;
1191 }
1192 else
1193 zurueck = (hin + sizeof(ausgaenge)/2) % sizeof(ausgaenge);
1194
1195 ex[str]->RemoveExit(ausgaenge[zurueck]);
1196 tell_room(find_object(ex[str]), sprintf("Der Ausgang '%s' verschwindet ploetzlich...\n", ausgaenge[zurueck]));
1197 cmds = ex[str]->QueryProp(H_COMMANDS);
1198 cmds = m_copy_delete(cmds, ausgaenge[zurueck]);
1199 ex[str]->SetProp(H_COMMANDS, cmds);
1200 ex[str]->Save();
1201 RemoveExit(str);
1202 cmds = QueryProp(H_COMMANDS);
1203 cmds = m_copy_delete(cmds, str);
1204 SetProp(H_COMMANDS, cmds);
1205 Save();
1206 printf( "OK, der Ausgang '%s' wurde entfernt.\n", str );
1207
1208 Save();
1209
1210 return 1;
1211}
1212
1213varargs int
1214uebersicht(string dummy, string pre)
1215{
1216 string *xc, *xd, o, raus, str;
1217 mixed *com;
1218 mapping tmp;
1219 int i,j,k;
1220
1221 if ( (getuid(this_player()) != owner) &&
1222 !(PATH+"access_rights")->access_rights(geteuid(this_player()), "") )
1223 return 0;
1224
1225 i = VERWALTER->HausProp(owner, HP_ROOMS);
1226
1227 if (i)
1228 str = sprintf( "Dein Haus verfuegt ueber %d Raeume.\nDu stehst in Raum %d (%s).\n\n", i+1, raumNr, QueryProp(P_INT_SHORT) );
1229 else
1230 str = sprintf( "Dein Haus verfuegt ueber einen Raum (%s)\n\n", QueryProp(P_INT_SHORT));
1231
1232 str += arr_out(m_indices(QueryProp(P_DETAILS)),
1233 "Du hast keine Details beschrieben.",
1234 "Du hast das Detail '%s' beschrieben.",
1235 "Du hast folgende Details beschrieben:\n", 1 );
1236
1237 str += ("\n" + arr_out(m_indices(QueryProp(P_READ_DETAILS)),
1238 "Du hast keine lesbaren Details beschrieben.",
1239 "Du hast das lesbare Detail '%s' beschrieben.",
1240 "Du hast folgende lesbaren Details beschrieben:\n", 1 ) );
1241
1242 tmp = Query(H_COMMANDS);
1243 xc = sort_array(m_indices(tmp),#'<);
1244 if (!sizeof(xc))
1245 str += ("\nDu hast keine Befehle beschrieben.\n");
1246 else {
1247 if (sizeof(xc) == 1 && sizeof(xd=m_indices(tmp[xc[0]])) == 1)
1248 str += ("\nDu hast den Befehl '"+
1249 xc[0]+((xd[0] == "") ? "" : " "+xd[0])+
1250 "' beschrieben.\n");
1251 else {
1252 str += "\nDu hast folgende Befehle beschrieben:\n";
1253
1254 for (com = ({}), j=sizeof(xc)-1; j >= 0; j--) {
1255 xd = sort_array(m_indices(tmp[xc[j]])-({"@NF@"}),#'>);
1256 if ((sizeof(xd) > 1) && (xd[0] == "")) {
1257 raus = "* "+xc[j]+", "+xc[j]+" ";
1258 xd = xd[1..];
1259 }
1260 else
1261 raus = "* "+xc[j]+" ";
1262
1263 str += arr_out(xd, "", raus+"%s", raus, 3);
1264 }
1265 }
1266 }
1267
1268 raus = (member(QueryProp(P_EXITS),"raus") ? "raus: Nach draussen.\n" : 0 );
1269 tmp = m_copy_delete(QueryProp(P_EXITS), "raus");
1270 m_delete(tmp, "notausgang");
1271 xc = m_indices(tmp);
1272 xd = m_values(tmp);
1273
1274 if (!sizeof(xc) && !raus)
1275 str += "\nES GIBT KEINE AUSGAENGE!\n";
1276 else {
1277 str += "\nEs gibt folgende Ausgaenge:\n";
1278 for (i=sizeof(xc)-1; i>=0; i--)
1279 str += sprintf( "%s: Nach Raum %d %s(%s).\n",
1280 xc[i],
1281 (j=to_int(xd[i][<1..])),
1282 (((o=old_explode(xd[i],"/")[<1][0..<6])==owner) ?
1283 "" : "von "+capitalize(o)+" "),
1284 xd[i]->QueryProp(P_INT_SHORT) );
1285 }
1286 str += ((raus||"")+(pre||""));
1287 this_player()->More(str);
1288 return 1;
1289}
1290
1291int kopieren(string str)
1292{
1293 string was, alt, n, *neu, *par, err;
1294 mixed das;
1295 mapping com;
1296
1297 if (!tp_owner_check())
1298 return 0;
1299
1300 notify_fail("'kopiere detail <von> nach <nach>' oder\n"
1301 +"'kopiere lesbares detail <von> nach <nach>' oder\n"
1302 +"'kopiere befehl <befehl> [<parameter>] nach <befehl> [<parameter>]'!\n");
1303
1304 if (!(str=UP_ARGS(this_player())) || str == "")
1305 return 0;
1306
1307 neu = old_explode(str, " ");
1308 was = neu[0][0..5];
1309 if (was == "detail" || was == "befehl")
1310 str = implode(neu[1..], " ");
1311 else if (was == "lesbar")
1312 str = implode(neu[2..], " ");
1313 else
1314 return 0;
1315
1316 if (sscanf(str, "%s nach %s", alt, n) != 2)
1317 return 0;
1318
1319 neu = brk(n);
1320 switch(was) {
1321 case "detail":
1322 err = "Detail";
1323 if (das = GetDetail(alt)) {
1324 AddDetail(neu, das);
1325 Save();
1326 }
1327 break;
1328 case "lesbar":
1329 err = "lesbares Detail";
1330 if (das = QueryProp(P_READ_DETAILS)[alt]) {
1331 AddReadDetail(neu, das);
1332 Save();
1333 }
1334 break;
1335 case "befehl":
1336 err = "Befehl";
1337 was = (par=old_explode(alt, " "))[0];
1338 if (member(com=QueryProp(H_COMMANDS),was)) {
1339 int i;
1340 if (sizeof(par) == 1) { // <bef> nach <bef1,bef2,...>
1341 das = com[was];
1342 for (i=sizeof(neu)-1; i>=0; i--) {
1343 if (befCheck(neu[i])) {
1344 if (com[neu[i]])
1345 com[neu[i]] += das;
1346 else
1347 com += ([ neu[i] : das ]);
1348 }
1349 else
1350 write("Ungueltiger Befehl: '"+neu[i]+"'.\n");
1351 }
1352 }
1353 else { // <bef> <parameter> nach <bef1,bef2,...>
1354 alt = implode(par[1..]-({""})," ");
1355 if (das = com[was][alt]) {
1356 for (i=sizeof(neu)-1; i>=0; i--) {
1357 if (befCheck(neu[i])) {
1358 das = ([ alt : com[was][alt];com[was][alt,1] ]);
1359 if (com[neu[i]])
1360 com[neu[i]] += das;
1361 else
1362 com += ([ neu[i] : das ]);
1363 }
1364 else {
1365 par = old_explode(neu[i], " ");
1366 n = par[0];
1367 if (befCheck(n)) {
1368 das = ([ implode(par[1..], " ") : com[was][alt];com[was][alt,1] ]);
1369 if (com[n])
1370 com[n] += das;
1371 else
1372 com += ([ n : das ]);
1373 }
1374 else
1375 write("Ungueltiger Befehl: '"+neu[i]+"'.\n");
1376 }
1377 }
1378 }
1379 }
1380 Save();
1381 }
1382 break;
1383 default:
1384 write( "Du kannst nur Details, lesbare Details und Befehle kopieren!\n" );
1385 return 1;
1386 }
1387 if (!das)
1388 printf( "Kann %s '%s' nicht finden!\n", err, alt);
1389 else
1390 write( "OK!\n" );
1391
1392 return 1;
1393}
1394
1395int licht(string str)
1396{
1397 int ll, tl;
1398
1399 if (!allowed_check(this_player()))
1400 return 0;
1401
1402 if (!str || (str != "an" && str != "aus")) {
1403 notify_fail("Syntax: 'licht an' oder 'licht aus'\n");
1404 return 0;
1405 }
1406
1407 ll = QueryProp(P_LIGHT);
1408 tl = PL->QueryProp(P_PLAYER_LIGHT);
1409
1410 switch(str) {
1411 case "an":
1412 if (tl > 0)
1413 write("Aber es ist doch schon hell!\n");
1414 else {
1415 SetProp(P_LIGHT, 1);
1416 tell_room(this_object(), "Es wird wieder hell.\n");
1417 }
1418 break;
1419 case "aus":
1420 if (tl <= 0)
1421 write("Aber es ist doch schon dunkel!\n");
1422 else {
1423 SetProp(P_LIGHT, 0);
1424 tell_room(this_object(), "Es wird dunkel.\n");
1425 }
1426 break;
1427 }
1428 return 1;
1429}
1430
1431#define CASUS ({ "WER", "WESSEN", "WEM", "WEN" })
1432static string rpXchg(string s)
1433{
1434 int c,p,g;
1435
1436 switch(s[0..1]) {
1437 case "@W":
1438 c = to_int(s[2..2]);
1439 return ("@"+CASUS[c]);
1440 case "@P":
1441 c = to_int(s[2..2]);
1442 return ("@P"+CASUS[c]);
1443 case "@B":
1444 c = to_int(s[2..2]);
1445 g = to_int(s[3..3]);
1446 p = to_int(s[4..4]);
1447 return ("@B"+({"N", "M", "F"})[g]+({"S", "P"})[p]+CASUS[c]);
1448 case "@F":
1449 return "@PARA";
1450 }
1451 return s;
1452}
1453
1454private string reParse(string s1, string s2)
1455{
1456 string *p;
1457
1458 if (s2)
1459 s1 = s1+"@@\n"+s2;
1460
1461 p = regexplode(s1, "(@W[0-3]|@P[0-3]|@B[0-3][0-2][0-1])");
1462 p = map(p, #'rpXchg);
1463 return implode(p, "");
1464}
1465
1466private string getPreText(string prop, string expr)
1467{
1468 mixed crunched;
1469 int i;
1470
1471 crunched = VERWALTER->PCrunch(QueryProp(prop));
1472 if (!crunched || !pointerp(crunched))
1473 return 0;
1474
1475 if (prop == H_COMMANDS && strstr(expr, " ") < 0)
1476 expr = expr+" ";
1477
1478 for (i=sizeof(crunched)-1; i>=0; i--)
1479 if (member(crunched[i][0], expr) >= 0)
1480 break;
1481
1482 if (i<0)
1483 return 0;
1484
1485 detail = crunched[i][0];
1486
1487 if (prop == H_COMMANDS)
1488 return reParse(crunched[i][1], crunched[i][2]);
1489 else
1490 return crunched[i][1];
1491}
1492
1493varargs int
1494aendern(string str, int f)
1495{
1496 string *parts, pre;
1497 int sp, sr, ret;
1498
1499 if (!tp_owner_check())
1500 return 0;
1501
1502 if (!f && (!(str=UP_ARGS(this_player())) || str == "")) {
1503 notify_fail("Was willst Du denn aendern?\n" );
1504 return 0;
1505 }
1506
1507 sp = sizeof(parts = old_explode(str, " "));
1508 sr = sizeof(brk(str));
1509 detail = 0;
1510 flag = f;
1511
1512 switch(parts[0][0..3]) {
1513 case "raum": // Lang- oder Kurzbeschreibung
1514 case "haus":
1515 if (sp == 1 || parts[1] == "lang")
1516 flag |= LANG;
1517 else if (parts[1] == "kurz") {
1518 write("Nimm dazu doch bitte 'beschreibe'!\n");
1519 return 1;
1520 }
1521 pre = ((flag & AUSSEN) ? (find_object(HAUSNAME(owner)))->QueryProp(P_LONG) : QueryProp(P_INT_LONG));
1522 break;
1523 case "meld":
1524 if (file_size(REPFILE(owner)) > 0)
1525 pre = read_file(REPFILE(owner));
1526 else {
1527 write("Ich finde keine Meldungen aus Deinem Haus!\n");
1528 return 1;
1529 }
1530 flag |= REPORT;
1531 break;
1532 case "deta": // Details
1533 if (sp==1) {
1534 notify_fail("Welches Detail willst Du denn aendern?\n");
1535 return 0;
1536 }
1537 if (sr>1) {
1538 notify_fail("Du kannst immer nur ein Detail aendern!\n");
1539 return 0;
1540 }
1541 flag |= DETAIL;
1542 pre = getPreText(P_DETAILS, implode(parts[1..], " "));
1543 break;
1544 case "lesb": // lesbare Details
1545 notify_fail("Welches lesbare Detail willst Du denn aendern?\n");
1546 if (sp == 1) return 0;
1547 if ((parts[1] == "details" || parts[1] == "detail") && (sp==2))
1548 return 0;
1549 if (sr>1) {
1550 notify_fail("Du kannst immer nur ein lesbares Detail aendern!\n");
1551 return 0;
1552 }
1553 flag |= RDETAIL;
1554 pre = getPreText(P_READ_DETAILS, implode(parts[1..], " "));
1555 break;
1556 case "befe": // Befehle
1557 ret = 0;
1558 if (sp == 1) {
1559 notify_fail("Welchen Befehl willst Du denn aendern?\n");
1560 return 0;
1561 }
1562 if (sr>1) {
1563 notify_fail("Du kannst immer nur einen Befehl aendern!\n");
1564 return 0;
1565 }
1566 flag |= BEFEHL;
1567 pre = getPreText(H_COMMANDS, implode(parts[1..], " "));
1568 break;
1569 default:
1570 notify_fail("Das kannst Du nicht aendern! Eine Liste der Dinge, die Du hier aendern\n"
1571 +"kannst, erhaeltst Du mit 'hilfe aendere'.\n" );
1572 return 0;
1573 break;
1574 }
1575 if (!pre)
1576 write("Hm, sowas ist hier noch nicht beschrieben...\n");
1577 else {
1578 write( "Aendere nun den Text.\n(Beenden mit . oder **, Abbruch mit ~q, Hilfe mit ~h)\n" );
1579 nedit( "aenderung", pre );
1580 }
1581 return 1;
1582}
1583
1584void aenderung(string str)
1585{
1586 string *warn;
1587
1588 if (!str) {
1589 write("Nichts geaendert!\n");
1590 return;
1591 }
1592
1593 if (flag && !(flag & BEFEHL))
1594 str = normstr(str);
1595
1596 warn = ({ });
1597
1598 if (flag & LANG) {
1599 if (flag & AUSSEN) {
1600 object haus;
1601 haus = find_object(HAUSNAME(owner));
1602 haus->SetProp(P_LONG, str);
1603 haus->Save();
1604 }
1605 else
1606 SetProp(P_INT_LONG, str);
1607 }
1608 else if (flag & DETAIL) {
1609 if (str == "")
1610 RemoveDetail(detail);
1611 else
1612 AddDetail(detail, str);
1613 }
1614 else if (flag & RDETAIL) {
1615 if (str == "")
1616 RemoveReadDetail(detail);
1617 else
1618 AddReadDetail(detail, str);
1619 }
1620 else if (flag & BEFEHL) {
1621 if (str == "")
1622 RemUserCmd(detail);
1623 else {
1624 string *s;
1625
1626 s = old_explode(preparse(str, &warn), "@@\n");
1627 if (sizeof(s) > 1 && s[1] != "")
1628 AddUserCmd(detail, 0, normstr(s[0]), normstr(s[1]));
1629 else
1630 AddUserCmd(detail, 0, normstr(s[0]), 0);
1631 }
1632 }
1633 else if (flag & REPORT) {
1634 rm(REPFILE(owner));
1635 if (str != "")
1636 write_file(REPFILE(owner), str);
1637 }
1638 else
1639 write( "Huch! Unbekanntes Flag ("+flag+")... Sag mal Wargon Bescheid...\n");
1640
1641 arr_out(warn, "OK.", "WARNUNG! Ungueltiger Platzhalter: %s",
1642 "WARNUNG! Ungueltige Platzhalter: ");
1643 Save();
1644}
1645
1646int SmartLog(string ofile, string typ, string msg, string date)
1647{
1648 object home;
1649
1650 // speichere Meldung im Rep-Log des Seherhaus-Besitzers
1651 write_file(REPFILE(owner), sprintf("%s von %s in Raum %d (%s):\n%s\n",
1652 typ,
1653 capitalize(getuid(this_player())),
1654 raumNr,
1655 date,
1656 break_string(msg,78)));
1657
1658 if (IS_LEARNER(owner)) {
1659 log_file("report/"+owner+".rep",
1660 sprintf("MELDUNG von %s im Seherhaus, Raum %d (%s):\n"
1661 +"Bitte zur Kenntnis nehmen! (Mit dem Befehl 'meldungen') -Wargon\n",
1662 capitalize(getuid(this_player())),
1663 raumNr,
1664 date));
1665 }
1666
1667 // erhoehe im Hauptraum den Rep-Zaehler und speichere
1668 home = load_object(RAUMNAME(owner,0));
1669 home->Set(H_REPORT, home->Query(H_REPORT)+1);
1670 home->Save();
1671
1672 return 1;
1673}
1674
1675static int report(string str)
1676{
1677 string rep, *lines;
1678 int rNum, l, s;
1679
1680 if (!allowed_check(this_player()))
1681 return 0;
1682
1683 if (file_size(REPFILE(owner)) <= 0) {
1684 write( "Keine Meldungen zu finden... Du bist wunschlos gluecklich.\n" );
1685 return 1;
1686 }
1687 rep = read_file(REPFILE(owner));
1688
1689 if (!rep) {
1690 write( "Oha! Die Datei mit den Meldungen ist zu gross! Sag doch bitte mal\n"
1691 +"Wargon Bescheid!\n");
1692 return 1;
1693 }
1694
1695 if (str) {
1696 string d, *new, *tmp, prev;
1697 int nr, nextNr, m;
1698
1699 if (str == "hier")
1700 rNum = raumNr;
1701 else
1702 rNum = to_int(str);
1703
1704 if (rNum > VERWALTER->HausProp(owner, HP_ROOMS)) {
1705 write( "So viele Raeume hast Du gar nicht!\n");
1706 return 1;
1707 }
1708
1709 lines = old_explode(rep, "\n");
1710 s = sizeof(lines);
1711 for (l=0; prev == 0; l++)
1712 if (sscanf(lines[l], "%s von %s in Raum %d %s:", d, d, nr, d)==4)
1713 prev=lines[l];
1714
1715 for ( new = ({}), tmp=({}); l<s; l++) {
1716 m=sscanf(lines[l], "%s von %s in Raum %d %s:", d, d, nextNr, d);
1717 if (m != 4 && nr == rNum)
1718 tmp += ({ lines[l] });
1719
1720 if (m==4) {
1721 if (sizeof(tmp)) {
1722 new = new + ({ prev }) + tmp;
1723 tmp = ({});
1724 }
1725 nr = nextNr;
1726 prev = lines[l];
1727 }
1728 }
1729 if (sizeof(tmp))
1730 new = new + ({prev}) + tmp;
1731 rep = implode(new, "\n");
1732 }
1733
1734 this_player()->More(rep);
1735 return 1;
1736}
1737
1738// $Log: raum.c,v $
1739// Revision 1.5 2003/11/15 14:03:58 mud
1740// Lichtaenderungen von Zook
1741//
1742// Revision 1.4 2003/02/17 20:00:00 mud
1743// Im Reset wird nun getestet, ob der Raum einen Ausgang in einen Null-Raum
1744// hat. Dies wurde notwengig, damit Spieler nicht in Seherhaeuser eingesperrt
1745// werden koennen. Die Funktionen AddExit(), RemoveExit() und Reset starten
1746// gegebenenfalls den Ausgangstest. Einige Funs mussten leicht angepasst
1747// werden.
1748// Die Funktionen room_has_exit() und is_exit() wurden von Vardion@MG
1749// entwickelt und zur Verfuegung gestellt. - Vanion
1750//
1751// Revision 1.3 2001/02/04 21:21:34 mud
1752// (brk,getBefParam): Vorkehrungen gegen fuehrende und schliessende
1753// Leerzeichen in Befehlsparametern und anderen Listen.
1754//
1755// Revision 1.2 2001/01/01 18:17:47 mud
1756// (ausgang): Wenn ein Ausgang zu einem anderen Seherhaus gelegt wird,
1757// wird die Erlaubnis in dessen Eingangsraum abgefragt, und nicht in
1758// dem angeforderten Zielraum (der Eingangsraum existiert auf jeden
1759// Fall, der Zielraum vielleicht nicht).
1760//
1761// Revision 1.1.1.1 2000/08/20 20:22:42 mud
1762// Ins CVS eingecheckt
1763//
1764// 04.02.98 Meldungen koennen geloescht werden.
1765//
1766// Revision 2.16 1997/11/15 19:33:23 Wargon
1767// arr_out(), preparse(): kleine Bugfixes
1768//
1769// Revision 2.15 1997/10/06 15:24:38 Wargon
1770// Unsichtbare Magier melden/anzeigen
1771// Meldung beim Betreten abgeschlossener Haeuser fuer Magier
1772//
1773// Revision 2.14 1996/02/21 18:12:47 Wargon
1774// SmartLog() rein, dafuer die eigenen Rueckmeldungsbefehle raus
1775//
1776// Revision 2.13 1995/10/31 12:56:16 Wargon
1777// Rueckmeldungen fuer Objekte werden ans Spielerobjekt weitergegeben.
1778//
1779// Revision 2.12 1995/08/07 18:35:12 Wargon
1780// Einige Bugs bei "aendere" behoben.
1781//
1782// Revision 2.11 1995/06/29 08:57:05 Wargon
1783// Hausbesitzer, die schon Magier sind, bekommen bei Rueckmeldungen auch einen
1784// Eintrag in ihr /log/report/xyz.rep-File
1785// "licht an/aus" ist seit 2.9 drin ;)
1786//
1787// Revision 2.10 1995/06/28 08:59:57 Wargon
1788// Neue Befehle aendere, meldungen fuer den Hausbesitzer.
1789// typo, bug/fehler, idee werden dem Haus-.rep-File zugefuehrt.
1790// Jetzt koennen die Seher ihre Typos selber fixen! ;^)
1791//
1792// Revision 2.9 1995/06/20 07:49:15 Wargon
1793// *** empty log message ***
1794//
1795// Revision 2.8 1995/04/21 10:48:39 Wargon
1796// Bugfix in beschreiben(), wenn die Hausaussenbeschreibung
1797// verlangt wird (war schon seit Ewigkeiten buggy... ;)
1798//
1799// Revision 2.7 1995/04/21 08:55:32 Wargon
1800// Load()/Save() und eigene Kommandos ausgelagert.
1801// Kommandos koennen mit notify_fail() versehen werden.
1802//
1803// Revision 2.6 1995/03/07 13:55:36 Wargon
1804// Add/RemUserCmd(), Beschreibungen werden bei reset()/clean_up()
1805// gepackt gespeichert.
1806// Bei Kommandos nur noch more(), wenn es auch noetig ist.
1807//
1808// Revision 2.5 1995/02/27 20:48:26 Wargon
1809// Kleine Schoenheitsfehler in selbstdefinierten Befehlen beseitigt.
1810//
1811// Revision 2.4 1995/02/22 21:30:52 Wargon
1812// Noch mehr Aenderungen an den Befehlen:
1813// - Preparsing der Platzhalter
1814// - Platzhalter fuer Possessivpronomen
1815// - Meldung fuer Ausfuehrenden wird geMore()t
1816// - Rassen- und Geschlechtespezifische Meldungen moeglich
1817// - Auch fuer Ausgaenge koennen Befehle definiert werden
1818// (nur fuer existierende; wird der Ausgang gesperrt, wird auch
1819// der Befehl geloescht)
1820// Im Zuge des Preparsings hat sich die Befehlauswertung etwas
1821// vereinfacht.
1822//
1823// Revision 2.3 1995/02/20 22:15:44 Wargon
1824// READ_DETAILS werden jetzt mit More() ausgegeben.
1825// Selbstdefinierte Befehle: mit @PWER, ... koennen die Personalpronomina
1826// eingebaut werden; Einbau jetzt auch in die Meldung fuer den Ausloeser
1827// moeglich; _unparsed_args() in der Auswertung.
1828//
1829// Revision 2.2 1995/02/15 11:23:04 Wargon
1830// NEU: Selbstdefinierbare Befehle.
1831//
1832// Revision 2.1 1995/02/04 15:02:36 Wargon
1833// Die Truhe wird nun ueber die Property CHEST verwaltet. Der AddItem()-
1834// Aufruf wurde deshalb von create() nach Load() verlegt. Geladen wird
1835// sie nur, wenn das Load() von Hausverwalter erfolgte.
1836// clean_up(), wenn Raum leer ist oder nur eine leere Truhe drin steht.
1837//
1838// Revision 2.0 1995/02/01 20:36:49 Wargon
1839// Entruempelt und Massnahmen fuer _unparse_args() getroffen.
1840