| // raum.c -- Das Rohgeruest eines Seherhauses. |
| // |
| // Grundobjekt (c) 1994 Boing@MorgenGrauen |
| // Abschliessen und Rauswerfen von Jof |
| // Fuer Aenderungen ab dem 06.10.94 verantwortlich: Wargon |
| // Ab 03.02.98 Wurzel |
| // |
| // $Id: raum.c,v 1.5 2003/11/15 14:03:58 mud Exp $ |
| #pragma strong_types,rtt_checks |
| |
| #include "haus.h" |
| |
| inherit "/std/room"; |
| inherit USERCMD; // selbstdefinierte Kommandos |
| inherit LOSA; // Load() und Save() |
| inherit "/mail/nedit"; |
| |
| #include <wizlevels.h> |
| #include <properties.h> |
| #include <defines.h> |
| #include <moving.h> |
| |
| static mixed detail; |
| static string owner; |
| static int flag, csaved; |
| static int raumNr; |
| static string *ausgaenge = ({ "oben", "norden", "nordosten", "osten", "suedosten", |
| "unten", "sueden", "suedwesten", "westen", "nordwesten" }); |
| |
| // Prototypes fuer Funktionen aus LOSA |
| varargs void Save(int crunched); |
| void Load(); |
| |
| // Prototype |
| // Falls noetig, mache einen Notausgang, falls nicht loesche vorhandenen |
| void make_emergency_exit(); |
| |
| // ersetzt @@ durch ** |
| private string normstr(string str) |
| { |
| return implode(explode(str,"@@"),"**"); |
| } |
| |
| // liefert kommagetrennte Teile ohne zusaetzliche Leerzeichen |
| // "Bla blubb , foo bar,blubber" => ({ "Bla blubb", "foo bar", "blubber" }) |
| private string *brk(string str) |
| { |
| string *t1; |
| |
| t1 = explode(str, ","); |
| map(t1, #'trim /*'*/); |
| return t1; |
| } |
| |
| // teste Befehl |
| private int befCheck(string bef) |
| { |
| // Befehl enthaelt Leerzeichen => return 0 |
| if (member(bef, ' ') > -1) |
| return 0; |
| |
| // Befehl ist bereits Kommando (ausser Oeffnen/Schliessen) |
| // oder Richtung inclusive "raus" in die kein Ausgang fuehrt |
| // => return 0 |
| if (member(m_indices(QueryProp(P_COMMANDS)) - |
| ({"oeffne","schliess","schliesse"}), bef) > -1 |
| || (member(ausgaenge+({"raus"}), bef) > -1 |
| && member(m_indices(QueryProp(P_EXITS)), bef) == -1)) |
| return 0; |
| |
| return 1; |
| } |
| |
| // Test auf Hausbesitzer |
| int tp_owner_check() |
| { |
| if(getuid(this_player()) != owner) |
| { |
| notify_fail( "Das ist nicht Dein Haus!\n" ); |
| return 0; |
| } |
| return 1; |
| } |
| |
| // Test auf Hausbesitzer oder Person mit Erlaubnis |
| int allowed_check(object _test) |
| { |
| string *ext; |
| |
| ext = VERWALTER->HausProp(owner, HP_ALLOWED) + ({ capitalize(owner) }); |
| if(member(ext, capitalize(getuid(_test))) < 0) |
| { |
| return 0; |
| } |
| else |
| { |
| return 1; |
| } |
| } |
| |
| // Funktion ersetzt durch tp_owner_check() und allowed_check(object _test) |
| // falls allowed == 0 => test ob this_player() Hausbesitzer |
| // falls allowed != 0 => test ob allowed/this_player() Hausbesitzer |
| // oder Person mit Erlaubnis |
| deprecated varargs int owner_check(mixed allowed) |
| { |
| object test; |
| |
| if(objectp(allowed) && query_once_interactive(allowed)) |
| { |
| // Parameter ist Spieler |
| test = allowed; |
| } |
| else |
| { |
| // ansonsten TP |
| test = this_player(); |
| } |
| |
| if(allowed) |
| { |
| // Test auf Hausbesitzer oder Person mit Erlaubnis |
| if(!allowed_check(test)) |
| { |
| notify_fail( "Das darfst Du in diesem Haus nicht!\n" ); |
| return 0; |
| } |
| } |
| else if(getuid(test) != owner) |
| { |
| // Test auf Hausbesitzer |
| notify_fail( "Das ist nicht Dein Haus!\n" ); |
| return 0; |
| } |
| // Erlaubnis OK |
| return 1; |
| } |
| |
| // Gestaltet Meldung aus Texten in einem Array: |
| // array leer -> melde Text in none |
| // array hat ein Element -> melde Text in one und ersetze %s durch Element |
| // array hat viele Elemente -> melde Text in many und danach |
| // sortierte Aufzaehlung der Elemente |
| // flag gesetztes Bit 2: Aufzaehlung nur mit Komma, kein 'und' |
| // flag gesetztes Bit 1: Meldung wird als String returnt, sonst per write ausgegeben |
| varargs string arr_out(mixed array, string none, string one, string many, int flag) |
| { |
| string tmp, lastsep; |
| mixed arr; |
| |
| switch(sizeof(array)) |
| { |
| case 0: |
| tmp = none; |
| break; |
| case 1: |
| tmp = sprintf(one, array[0]); |
| break; |
| default: |
| tmp = many; |
| arr = sort_array(array, #'> /*'*/); |
| lastsep = (flag & 2) ? ", " : " und "; |
| tmp += CountUp(arr, ", ", lastsep)+"."; |
| break; |
| } |
| if (flag & 1) |
| return(break_string(tmp, 75, 0, 1)); |
| else |
| write(break_string(tmp, 75, 0, 1)); |
| |
| return 0; |
| } |
| |
| protected void create() |
| { |
| if (!clonep(this_object()) && object_name(this_object())==(RAUM)) { |
| set_next_reset(-1); |
| return; |
| } |
| room::create(); |
| usercmd::create(); |
| losa::create(); |
| |
| Set(P_INT_LONG, SAVE, F_MODE_AS); |
| Set(P_INT_SHORT, SAVE, F_MODE_AS); |
| Set(P_EXITS, SAVE, F_MODE_AS); |
| Set(P_DETAILS, SAVE, F_MODE_AS); |
| Set(P_READ_DETAILS, SAVE, F_MODE_AS); |
| Set(P_LIGHT, SAVE, F_MODE_AS); |
| |
| SetProp(P_IDS, ({"raum","sehe\rhaus"})); |
| SetProp(P_NAME, "Haus"); |
| SetProp(P_GENDER, 0); |
| SetProp(P_TRANSPARENT, 0); |
| SetProp(P_NOGET, 1); |
| SetProp(P_LIGHT, 1); |
| SetProp(P_INDOORS, 1); |
| |
| AddCmd( ({ "beschreib", "beschreibe" }), "beschreiben" ); |
| AddCmd("uebersicht", "uebersicht"); |
| AddCmd("ausgang", "ausgang"); |
| AddCmd( ({"loesche", "loesch"}), "loesch"); |
| AddCmd( ({"wirf", "werf", "werfe" }), "wirf"); |
| AddCmd( ({"sperr", "sperre"}), "sperren"); |
| AddCmd( ({"kopier", "kopiere" }), "kopieren"); |
| AddCmd("licht", "licht"); |
| AddCmd( ({"aendere", "aender" }), "aendern"); |
| AddCmd( ({"meldung", "meldungen"}), "report"); |
| } |
| |
| void init() |
| { |
| object haus; |
| |
| room::init(); |
| nedit::init_rescue(); |
| |
| // Magier betritt fremdes Seherhaus |
| if (query_once_interactive(PL) && IS_LEARNER(PL) && getuid(PL) != owner) { |
| if (PL->QueryProp(P_INVIS)) |
| // Magier invis => im Raum melden |
| tell_room(this_object(), |
| capitalize(getuid(PL))+" betritt unsichtbar den Raum.\n", |
| ({PL})); |
| |
| if ((haus = load_object(HAUSNAME(owner))) && |
| (haus->QueryProp(H_DOORSTAT) & D_LOCKED)) |
| // Tuer ist zu => Magier einen Hinweis geben |
| tell_object(PL, " ******* ACHTUNG *********************************\n *\n * "+ |
| capitalize(owner)+" moechte vielleicht ungestoert bleiben!\n *\n" |
| " ******* ACHTUNG *********************************\n"); |
| } |
| } |
| |
| int PreventInsertLiving(object ob) |
| { |
| return 0; |
| } |
| |
| // Gegenstaende kommen in den Raum |
| void NotifyInsert(object ob, object oldenv) |
| { |
| object *found; |
| |
| if (!objectp(ob)) return; |
| |
| if (ob->QueryProp(H_FURNITURE)!=0) |
| { |
| // das was reinkam ist ein autoload Moebelstueck |
| // betrachte alle schon vorhandenen autoload Moebelstuecke |
| found = filter_objects(all_inventory(this_object()), |
| "QueryProp", H_FURNITURE); |
| if (sizeof(found)>=MAX_FURNITURE_PER_ROOM) |
| { |
| // Maximal-Anzahl vorhandener autoload Seherhausmoebel ist schon |
| // erreicht |
| tell_object(this_player(), break_string( |
| "Ein Raum kann nur "+MAX_FURNITURE_PER_ROOM+" rebootfeste " |
| "Moebel speichern. Hier befinden sich schon "+ |
| CountUp(map_objects(found, "name"))+".")); |
| return 0; |
| } |
| |
| queued_save(); // Speichern vorbereiten (falls mehrere Objekte |
| // gedroppt werden, wird so ein overflow verhindert. |
| } |
| } |
| |
| // Gegenstaende verlassen den Raum |
| void NotifyLeave(object ob, object dest) |
| { |
| if (!ob &&!objectp(ob)) return 0; |
| |
| // rebootfestes Moebelstueck verlaesst den Raum |
| if (ob->QueryProp(H_FURNITURE)!=0) |
| { |
| // Speichern vorbereiten (falls mehrere Objekte |
| // gedroppt werden, wird so ein overflow verhindert. |
| queued_save(); |
| } |
| return 0; |
| } |
| |
| void |
| reset() |
| { |
| room::reset(); |
| losa::reset(); |
| // Wenn ein Notausgang vorhanden ist, checken, ob der noch noetig ist. |
| if (member(m_indices(QueryProp(P_EXITS)),"notausgang")!=-1) |
| { |
| make_emergency_exit(); |
| } |
| } |
| |
| int clean_up(int arg) |
| { |
| mixed inv; |
| |
| if (arg > 1) |
| return 1; |
| |
| losa::reset(); // Evtl. gepackt speichern... |
| |
| // nichts im Raum oder nur leere Seherhaustruhe => Raum kann weg |
| if ((sizeof(inv=all_inventory()) == 0) || |
| (sizeof(inv) == 1 && inv[0]->id(TRUHE) && |
| sizeof(all_inventory(inv[0]))==0)) |
| remove(1); |
| |
| return 0; |
| } |
| |
| // Haeufungen von gleichen Objekten sind hier egal => nix tun |
| protected varargs void remove_multiple(int limit) {} |
| |
| |
| // Spieler wird im Raum Netztot |
| void BecomesNetDead(object pl) |
| { |
| // Nicht erlaubte Spieler werden rausgeworfen, alle anderen bleiben drin. |
| if(!allowed_check(pl)) |
| pl->move(VERWALTER->HausProp(owner, HP_ENV), M_GO, 0, "schlafwandelt heraus", "schlafwandelt herein" ); |
| } |
| |
| |
| /* Ist dieser Raum ein Ausgang? */ |
| int is_exit(string path) |
| { |
| return (sizeof(path) > 4) && (path[<5..] == "raum0"); |
| } |
| |
| /*Pruefung, ob es einen Hausausgang gibt*/ |
| int room_has_exit() { |
| |
| string room = object_name(this_object()); |
| // sind wir schon in einem Hauptraum mit Ausgang? |
| if (is_exit(room)) return 1; |
| |
| mapping r_todo = ([room]); |
| mapping r_done = ([:0]); |
| /* Die Schleife hat maximal 9 * Anzahl der verb. Haeuser Durchlaeufe */ |
| while (sizeof(r_todo)) |
| { |
| mapping r_exits = ([]); |
| |
| // naechsten Raumpfad abarbeiten, d.h. dessen Ausgaenge betrachten |
| room = m_indices(r_todo)[0]; |
| // abgearbeiteten Raumpfad von r_todo nach r_done schieben |
| r_done += ([room]); |
| m_delete(r_todo, room); |
| |
| // alle Ausgaenge betrachten |
| foreach(string command, string subpath : room->QueryProp(P_EXITS)) |
| { |
| // Notausgaenge nicht betrachten, da 'echte' Ausgaenge gesucht sind |
| if(command != "notausgang") |
| // alle anderen Ausgaenge sammeln |
| r_exits += ([ subpath ]); |
| } |
| // nur Raumpfade die noch nicht abgearbeitet sind testen |
| r_exits -= r_done; |
| // ist da ein Hauptraum (der dann Ausgang liefert) dabei? |
| if (sizeof(filter_indices(r_exits, #'is_exit/*'*/))) |
| return 1; |
| |
| // neue Raumpfade in die TODO-Liste aufnehmen |
| r_todo += r_exits; |
| } |
| return 0; |
| } |
| |
| // damit man Spieler nicht durch Entfernen von Ausgaengen einsperren kann |
| // werden bei Bedarf Notausgaenge in den Hauptraum ergaenzt |
| void make_emergency_exit() |
| { |
| // Ist der Raum weder Hauptraum mit Ausgang noch fuehrt ein Weg dorthin? |
| // dann Notausgang machen |
| if(!room_has_exit()) |
| { |
| // tell_room(this_object(),"DEBUG: Ein Notausgang wurde angelegt.\n"); |
| room::AddExit("notausgang", |
| "durch den Notausgang#"+to_string(this_object())[0..<2]+"0"); |
| } |
| else |
| { |
| // nicht mehr benoetigten Notausgang entfernen |
| room::RemoveExit("notausgang"); |
| } |
| } |
| |
| // ruft direkt das geerbte AddExit auf, ohne ggf. einen Notausgang zu |
| // erzeugen. Das wird vom Haus und vom Verwalter benutzt, um Ausgaenge zu |
| // erzeugen. Das ist noetig, weil der Notausgangmechanismus noch nicht |
| // funktoniert, wenn der Raum gerade geladen wird (hat noch nicht den |
| // endgueltigen Namen) und der Check waere ohnehin unnoetig. |
| public void AddExitNoCheck(mixed cmd, mixed dest) |
| { |
| room::AddExit(cmd, dest); |
| } |
| |
| // Wird benutzt beim Laden von Raeumen, um alle Ausgaenge zu loeschen. Dabei |
| // darf _kein_ Notausgang erstellt werden. |
| void RemoveExitNoCheck(mixed cmd) |
| { |
| room::RemoveExit(cmd); |
| } |
| |
| // beim Ausgang setzten testen ob vorhanderner Notausgang noch benoetigt wird |
| void AddExit(mixed cmd, mixed dest) |
| { |
| room::AddExit(cmd, dest); |
| |
| if (member(m_indices(QueryProp(P_EXITS)),"notausgang")!=-1) |
| { |
| // loescht Notausgang falls nicht mehr benoetigt |
| make_emergency_exit(); |
| } |
| } |
| |
| // beim Ausgang loeschen testen ob Notausgang benoetigt wird |
| void RemoveExit(mixed cmd) |
| { |
| room::RemoveExit(cmd); |
| // setzt Notausgang falls benoetigt |
| make_emergency_exit(); |
| } |
| |
| // der Langbeschreibung werden alle unsichtbaren Magier |
| // (ausgenommen Seherhausbesitzer) in Klammern angefuegt |
| varargs string int_long(mixed viewer, mixed viewpoint, int flags) |
| { |
| string ret; |
| object *inv; |
| string *tmp; |
| |
| ret = ::int_long(viewer, viewpoint, flags); |
| |
| // nur was machen wenn der Betrachter im Raum ist |
| if (!ret || !objectp(viewer) || environment(viewer) != this_object()) |
| return ret; |
| |
| if(viewpoint == 0) |
| viewpoint = ({ viewer }); |
| else if(!pointerp(viewpoint)) |
| viewpoint = ({ viewpoint }); |
| |
| // alle Lebewesen ausser denen aus deren Sicht betrachtet wird |
| inv = filter(all_inventory(this_object()),#'interactive) - viewpoint; |
| foreach(object pl : inv) |
| { |
| // raussuchen wer ausser Seherhausbesitzer unsichtbar ist |
| if(pl && IS_LEARNER(pl) && pl->QueryProp(P_INVIS) && getuid(pl)!=owner) |
| { |
| // Name in Klammer sammeln |
| tmp += ({ "("+capitalize(getuid(pl))+")" }); |
| } |
| } |
| return ret + break_string(CountUp(tmp), 78); |
| } |
| /* |
| // TODO: Testen ob das hier nicht das Standard-Verhalten ist |
| int lies(string str) |
| { |
| string txt; |
| |
| notify_fail("Was moechtest Du lesen?\n"); |
| if (!str) return 0; |
| |
| if (this_player()->CannotSee()) |
| return 1; |
| if (txt = QueryProp(P_READ_DETAILS)[str]) { |
| this_player()->More(txt); |
| return 1; |
| } |
| return 0; |
| } |
| */ |
| // Aktion Lebewesen oder Gegenstaende aus dem Haus werfen |
| int wirf(string str) |
| { |
| string wen, args; |
| object pl, target, *list, tp, to; |
| |
| tp = this_player(); |
| to = this_object(); |
| args = tp->_unparsed_args(1); |
| |
| // klappt nur vor Ort und mit der passenden Syntax |
| if ((environment(tp)!=to) || |
| !args || args == "" || |
| (sscanf(args,"%s raus",wen) != 1) ) |
| return 0; |
| // Raum, in dem das Haus steht, ermitteln |
| target=find_object(VERWALTER->HausProp(owner, HP_ENV)); |
| if (!target) { |
| notify_fail("Dieses Haus steht leider gerade in einem " |
| "Fehler im Raum-Zeit-Gefuege.\n"); |
| return 0; |
| } |
| // Rauswerfen darf nur der Besitzer |
| if (!tp_owner_check()) { |
| notify_fail("Aber Du kannst doch niemanden aus dem Haus von "+capitalize(owner)+" werfen!\n"); |
| return 0; |
| } |
| if (wen=="alle") { |
| // alle Lebewesen ausser tp (== Hausbesitzer) |
| list=filter(all_inventory(to),#'living)-({tp,0});//') |
| if (sizeof(list)==0) { |
| notify_fail("Aber Du bist doch allein in Deinem Haus!\n"); |
| return 0; |
| } |
| } else if (wen == "alles") { |
| // alle Gegenstaende ausser Lebewesen und Moebel |
| // (Seherhaustruhe, Autoloader-Moebel oder Seherhaus-Moebel) |
| list = filter(all_inventory(to), |
| function int(object ob) |
| { |
| return objectp(ob) && |
| !living(ob) && |
| !ob->id(TRUHE) && |
| // TODO Test auf nicht Seherhausmoebel von August |
| strstr(load_name(ob),"/d/seher/haeuser/moebel/") |
| == 0; |
| } ); |
| |
| if (sizeof(list)==0) { |
| notify_fail("Aber hier ist nichts zum wegwerfen!\n"); |
| return 0; |
| } |
| } else { |
| pl=present(wen,to); |
| if (!pl) { |
| notify_fail("So jemanden sehe ich hier nicht.\n"); |
| return 0; |
| } |
| else if (pl->id(TRUHE) || |
| // TODO Test auf Seherhausmoebel von August |
| strstr(load_name(pl),"/d/seher/haeuser/moebel/")==0 |
| ) { |
| notify_fail("Du kannst "+pl->name(WEN)+" nicht wegwerfen!\n" ); |
| return 0; |
| } |
| list=({pl}); |
| } |
| string msg_wen = sprintf("%s wirft Dich aus %s Haus.\n", |
| tp->Name(WER), |
| tp->QueryPossPronoun(NEUTER,WEM)); |
| // fuer alle rauszuwerfenden Opfer Meldungen machen und rausbewegen |
| foreach(object ob : list) |
| { |
| tell_object(ob, msg_wen); |
| tell_room(target, |
| sprintf("%s kommt in hohem Bogen aus dem Haus von %s geflogen.\n", |
| ob->Name(WER),tp->name(WEM))); |
| ob->move(target,M_SILENT|M_GO); |
| tell_room(to,sprintf("%s wirft %s aus %s Haus.\n", |
| tp->Name(WER), |
| ob->name(WEN),tp->QueryPossPronoun(NEUTER,WEM)), |
| ({tp})); |
| printf("Du wirfst %s aus Deinem Haus.\n",ob->name(WEN)); |
| // Verfolger abmelden, damit sie nicht gleich zurueckkommen |
| // TODO wenn man einzelne Lebewesen rauswirft kann das ja auch |
| // ein Verfolger von einem anderen Gast sein... |
| tp->RemovePursuer(ob); |
| } |
| return 1; |
| } |
| |
| // Besitzer und Raumnummer fuer diesen Raum setzen |
| varargs string SetOwner(string o, int num) |
| { |
| // Default Kurz- und Langbeschreibung setzen |
| SetProp(P_INT_SHORT, "Im Haus von "+capitalize(o)); |
| SetProp(P_INT_LONG, "Ein total leerer Raum.\n"); |
| // Raumnummer und Besitzer merken |
| raumNr = num; |
| return owner = o; |
| } |
| |
| // Liefert den Besitzer |
| // falls withNr != 0 mit angehaengter Raumnummer |
| varargs string QueryOwner(int withNr) |
| { |
| return (withNr ? owner+raumNr : owner); |
| } |
| |
| // Prototype |
| static int befEingabe(string *bef); |
| |
| // Aktion zum Beschreiben des Raumes |
| varargs int |
| beschreiben(string str, int f) |
| { |
| string *parts; |
| int sp, ret; |
| |
| // nur der Besitzer darf |
| if(!tp_owner_check()) |
| return 0; |
| |
| if (!f && (!(str=UP_ARGS(this_player())) || str == "")) { |
| notify_fail("Was willst Du denn beschreiben?\n" ); |
| return 0; |
| } |
| |
| sp = sizeof(parts = old_explode(str, " ")); |
| // je nachdem was beschrieben wird, setze detail und flag |
| // und starte damit Editor, bzw. behandle Befehle extra |
| detail = 0; |
| flag = f; |
| |
| switch(parts[0][0..3]) { |
| case "raum": // Lang- oder Kurzbeschreibung |
| case "haus": |
| if (sp == 1 || parts[1] == "lang") |
| flag |= LANG; |
| else if (parts[1] == "kurz") |
| flag |= KURZ; |
| printf("Bitte %sbeschreibung des %s eingeben.\n", (flag & LANG ? "Lang" : "Kurz"), (flag & AUSSEN ? "Hauses" : "Raumes") ); |
| break; |
| case "deta": // Details |
| if (sp==1) { |
| notify_fail("Welches Detail willst Du denn beschreiben?\n"); |
| return 0; |
| } |
| flag |= DETAIL; |
| str = implode(parts[1..]," "); |
| write( "Bitte Beschreibung fuer '"+str+"' eingeben.\n"); |
| break; |
| case "lesb": // lesbare Details |
| notify_fail("Welches lesbare Detail willst Du denn beschreiben?\n"); |
| if (sp == 1) return 0; |
| if (parts[1] == "details" || parts[1] == "detail") { |
| if (sp == 2) return 0; |
| str = implode(parts[2..]," "); |
| } |
| else |
| str = implode(parts[1..]," "); |
| flag |= RDETAIL; |
| write( "Bitte Beschreibung fuer '"+str+"' eingeben.\n"); |
| break; |
| case "befe": // Befehle |
| ret = 0; |
| if (sp == 1) |
| notify_fail("Welchen Befehl willst Du denn beschreiben?\n"); |
| else |
| ret = befEingabe(brk(implode(parts[1..]," "))); |
| return ret; |
| break; |
| default: |
| notify_fail("Das kannst Du nicht beschreiben! Eine Liste der Dinge, die Du hier\n" |
| +"beschreiben kannst, erhaeltst Du mit 'hilfe beschreibe'.\n" ); |
| return 0; |
| break; |
| } |
| detail = brk(str); |
| write( "(Beenden mit . oder **, Abbruch mit ~q)\n" ); |
| nedit( "beschreibung" ); |
| return 1; |
| } |
| |
| // nedit von beschreibe xxx |
| static void beschreibung(string str) |
| { |
| if (!str) { |
| write("Nichts geaendert!\n"); |
| return; |
| } |
| |
| str = normstr(str); |
| |
| if (flag & LANG) |
| { |
| // Langbeschreibung |
| if (sizeof(explode(str,"\n")) > 100 |
| || sizeof(str) > 7800) |
| { |
| // ueber 100 Zeilen oder ueber 7800 Zeichen |
| write( "Das ist fuer eine Langbeschreibung zu lang!\n" |
| "Sorry, bitte denke Dir eine andere Langbeschreibung aus.\n" ); |
| return; |
| } |
| if (flag & AUSSEN) { |
| // Langbeschreibung vom Haus |
| object haus; |
| haus = find_object(HAUSNAME(owner)); |
| haus->SetProp(P_LONG, str); |
| haus->Save(); |
| } |
| else |
| // Langbeschreibung von diesem Raum |
| SetProp(P_INT_LONG, str); |
| } |
| else if (flag & KURZ) { |
| // Kurzbeschreibung vom Raum |
| if (sizeof(old_explode(str,"\n")) > 1 || sizeof(old_explode(str,".")) > 2 || sizeof(str) > 75) { |
| write( "Das ist fuer eine Kurzbeschreibung zu lang!\nSorry, bitte denke Dir eine andere Kurzbeschreibung aus.\n" ); |
| return; |
| } |
| else |
| // Vanion, 27.07.02, Bugfix |
| // Die Zeile buggte, wenn man "." oder "\n" oder "\n." oder sowas |
| // in str hat. (also z.B. bei "beschreibe raum kurz <return> .") |
| // SetProp(P_INT_SHORT, old_explode(old_explode(str,"\n")[0],".")[0]); |
| SetProp(P_INT_SHORT, explode(explode(str,"\n")[0],".")[0]); |
| } |
| else if (flag & DETAIL) |
| // Raum-Detail |
| AddDetail(detail, str); |
| else if (flag & RDETAIL) |
| // lesbares Raum-Detail |
| AddReadDetail(detail, str); |
| else { |
| write( "Huch! Unbekanntes Flag ("+flag+")... Sag mal " |
| + CountUp(MAINTAINER, ", ", " oder ") |
| + " Bescheid...\n"); |
| return; |
| } |
| |
| write("OK.\n"); |
| Save(); |
| } |
| |
| // wird in beschreiben(str, int) 'beschreibe befehl' aufgerufen |
| static int befEingabe(string *befehle) |
| { |
| string* com = ({}); |
| |
| notify_fail("Kein Befehl zum Beschreiben uebrig... ;)\n"); |
| foreach(string bef : befehle) |
| { |
| // schon vorhandener Befehl (ausser oeffnen/schlissen), |
| // Richtung ohne zugehoerigen Ausgang, |
| // oder Befehl enthaelt Leerzeichen |
| if (!befCheck(bef)) |
| write("Der Befehl '"+bef+"' kann nicht beschrieben werden!\n"); |
| else |
| com += ({ bef }); |
| } |
| if (!sizeof(com)) |
| return 0; |
| |
| arr_out(com, 0, "Zu beschreibender Befehl: %s", |
| "Zu beschreibende Befehle:\n"); |
| |
| write( "Bitte Parameter eingeben (evtl. durch Kommata getrennt).\n]"); |
| input_to("getBefParam", 0, com); |
| return 1; |
| } |
| |
| // input_to aus befEingabe(string) zu beschreibe befehl ... |
| static void getBefParam(string param, string *bef) |
| { |
| string txt = "Gib nun bitte den Text ein, der fuer diesen Befehl " |
| "ausgegeben werden soll.\n"; |
| |
| // Fuehrende und abschliessende Leerzeichen entfernen |
| if (param) |
| param = trim(param); |
| |
| if (!param || param == "") |
| // kein Parameter, z.b. bei beschreibe befehl klopfe |
| detail = ({ bef, "" }); |
| else if (param == "@NF@" || param == "@nf@") { |
| // Parameter fuer notify fail zum Ersetzen von Wie bitte? |
| // z.B. bei beschreibe befehl druecke |
| // fuer danach Du kannst hier kein @PARA druecken, nur den Knopf! |
| detail = ({ bef, 1 }); |
| txt = "Gib nun bitte den Text ein, der als Fehlermeldung " |
| "ausgegeben werden soll.\n@PARA dient dabei als Platzhalter fuer " |
| "die ungueltige Eingabe.\n"; |
| } |
| else |
| // sonstige Parameter |
| // z.B. knopf, klingel bei beschreibe befehl druecke |
| detail = ({ bef }) + brk(lower_case(param)); |
| |
| printf(txt+"(Beenden mit . oder **, Abbruch mit ~q)\n"); |
| nedit("getBefText"); |
| } |
| |
| // Prototype |
| private string preparse(string str, string *invalid); |
| |
| // nedit fuer die Eingabe der Texte (Fehlermeldung/Meldungen) fuer den Befehl |
| static void getBefText(string text) |
| { |
| string my, *txt, *warn; |
| mixed bef; |
| |
| if (!text || text == "") { |
| write("** Abbruch! **\n"); |
| detail = 0; |
| return; |
| } |
| // gemerktes Befehls-Array |
| bef = detail[0]; |
| |
| txt = old_explode(text, "@@\n"); |
| |
| warn = ({}); |
| |
| // Meldung an this_player() parsen und in warn falsche Platzhalter sammeln |
| my = preparse(txt[0], &warn); |
| string other = 0; |
| if (sizeof(txt) > 1) |
| // Meldung an andere parsen und in warn falsche Platzhalter sammeln |
| other = preparse(txt[1], &warn); |
| |
| AddUserCmd(bef, (stringp(detail[1]) ? detail[1..] : ({ "@NF@" })), my, other); |
| Save(); |
| arr_out(warn, "OK.", "WARNUNG! Ungueltiger Platzhalter: %s", |
| "WARNUNG! Ungueltige Platzhalter: "); |
| |
| detail = 0; |
| } |
| |
| // check, ob an Position pos in txt ein Buchstabe aus dem array choice steht |
| // return 0 falls nicht, prefix + Position des Buchstabens in choice ansonsten |
| // check_placeholder(({"R","S","M","N"}), 2, "WESSEN", "X"); -> X1 |
| string check_placeholder(string* choice, int pos, string txt, string prefix) |
| { |
| int idx; |
| |
| if(sizeof(txt) < pos+1 || |
| ((idx=member(choice, txt[pos..pos])) < 0)) |
| { |
| return 0; |
| } |
| else |
| { |
| return prefix+to_string(idx); |
| } |
| } |
| |
| // Dann drueckt @PWER den Knopf -> Dann drueckt @P0 den Knopf |
| private string preparse(string str, string *invalid) |
| { |
| string *txt; |
| |
| txt = explode(str, "@"); |
| // fuer jeden Textteil nach einem @ |
| // suche Ersatz fuer den Begriff direkt nach dem @ |
| // AN: wuerde es nicht theoretisch reichen, hier nur bis i>0 |
| // runterzuzaehlen? Das erste Element des Arrays ist immer irrelevant, weil |
| // entweder Leerstring oder kein zu ersetzender Ausdruck. |
| for (int i=sizeof(txt)-1; i>=0; i--) { |
| int warn = 0; |
| string rpl = 0; |
| // falls Teil zu kurz nix ersetzen |
| if (sizeof(txt[i])<3) |
| continue; |
| // anhand der ersten Buchstaben, Ersatz bestimmen |
| // warn signalisiert, ob dies schiefging: |
| switch(txt[i][0..1]) { |
| case "WE": // Name |
| // WER -> W0 |
| // WES(SEN) -> W1 |
| // WEM -> W2 |
| // WEN -> W3 |
| rpl = check_placeholder(({"R","S","M","N"}), 2, txt[i], "W"); |
| warn = !rpl; |
| break; |
| case "PW": // Personalpronomen |
| // PWER -> P0 |
| // PWES(SEN) -> P1 |
| // PWEM -> P2 |
| // PWEN -> P3 |
| rpl = check_placeholder(({"R","S","M","N"}), 3, txt[i], "P"); |
| warn = !rpl; |
| break; |
| case "BN": // Possessivpronomen |
| case "BM": |
| case "BF": |
| // BNSWER -> B000 BMSWER -> B010 BFSWER -> B020 |
| // BNSWES(SEN) -> B100 BMSWES(SEN) -> B110 BFSWES(SEN) -> B120 |
| // BNSWEM -> B200 BMSWEM -> B210 BFSWEM -> B220 |
| // BNSWEN -> B300 BMSWEN -> B310 BFSWEN -> B320 |
| // |
| // BNPWER -> B001 BMPWER -> B011 BFPWER -> B021 |
| // BNPWES(SEN) -> B101 BMPWES(SEN) -> B111 BFPWES(SEN) -> B121 |
| // BNPWEM -> B201 BMPWEM -> B211 BFPWEM -> B221 |
| rpl = check_placeholder(({"R","S","M","N"}), 5, txt[i], "B"); |
| warn = !rpl; |
| if(!warn) |
| { |
| rpl = check_placeholder(({"N","M","F"}), 1, txt[i], rpl); |
| warn = !rpl; |
| if(!warn) |
| { |
| rpl = check_placeholder(({"S","P"}), 2, txt[i], rpl); |
| warn = !rpl; |
| } |
| } |
| break; |
| case "PA": |
| // PARA -> F |
| // kein Ersatz, sondern Textteil hier direkt ersetzen: |
| if(sizeof(txt[i]) > 4) |
| txt[i] = "F"+txt[i][4..]; |
| break; |
| default: |
| // kein Ersatz, nix aendern |
| warn = 0; |
| rpl = 0; |
| } |
| |
| // falls Ersatz vorhanden, ersetze Pronomen durch ""+rpl und lasse den Rest t2[2] wie ist |
| if (rpl) { |
| string* t2; |
| warn = sizeof(t2 = regexplode(txt[i], "(WER|WESSEN|WEM|WEN)")) < 2; |
| if (!warn) { |
| t2[1] = rpl; |
| t2[0] = ""; |
| txt[i] = implode(t2, ""); |
| } |
| } |
| // falls es Probleme gab, diese merken |
| if (warn) |
| invalid += ({ "@"+old_explode(txt[i]," ")[0] }); |
| |
| } // for (i=sizeof(txt)-1; i>=0; i--) |
| // die eventuelle teilweise ersetzetn Teile wieder zusammenfuegen |
| return implode(txt, "@"); |
| } |
| |
| static void loesch_alles(string str) |
| { |
| if (str == "ja" || str == "Ja") { |
| RemoveDetail(0); |
| RemoveReadDetail(0); |
| //SetProp(P_READ_DETAILS, ([])); |
| SetProp(H_COMMANDS, ([])); |
| write( "OK, alle Details, lesbaren Details und Befehle geloescht!\n" ); |
| Save(); |
| } |
| else |
| write( "Nichts geloescht!\n" ); |
| } |
| |
| static void loesch_etwas(string str, string prop) |
| { |
| if (str == "ja" || str == "Ja") { |
| if ( prop == P_DETAILS ) |
| RemoveDetail(0); |
| else if ( prop == P_READ_DETAILS ) |
| RemoveReadDetail(0); |
| else |
| SetProp(prop, ([])); |
| write("OK.\n"); |
| Save(); |
| } |
| else |
| write( "Nichts geloescht!\n" ); |
| } |
| |
| int loesch(string str) |
| { |
| string *s, *t, p, q; |
| int i, ret; |
| mapping com; |
| |
| if (!tp_owner_check()) |
| return 0; |
| |
| if (!(str=UP_ARGS(this_player())) || str == "") { |
| notify_fail("Welches Detail oder welchen Befehl moechtest Du loeschen?\n"); |
| return 0; |
| } |
| |
| if (str == "alles") { |
| write( "Wirklich alles loeschen (ja/nein)?\n]"); |
| input_to("loesch_alles"); |
| return 1; |
| } |
| |
| if(str=="meldungen") { |
| if(file_size(PATH+"rep/"+owner+".rep")>0) { |
| rm(PATH+"rep/"+owner+".rep"); |
| write("Meldungen geloescht.\n"); |
| }else{ |
| write("Keine Meldungen gefunden.\n"); |
| } |
| return 1; |
| } |
| |
| s = brk(str); |
| s = ({ (t=old_explode(s[0], " "))[0] })+({ implode(t[1..]," ") })+s[1..]; |
| ret = 1; |
| flag = 0; |
| |
| switch(s[0]) { |
| case "detail": |
| s = s[1..]; |
| flag |= DETAIL; |
| break; |
| case "lesbar": |
| flag |= RDETAIL; |
| s = s[1..]; |
| break; |
| case "lesbares": |
| case "lesbare": |
| flag |= RDETAIL; |
| if (s[1][0..5] =="detail") { |
| s = ({ old_explode(s[1]," ")[<1] }); |
| if (sizeof(s)>2) |
| s += s[2..]; |
| } |
| else |
| s = s[1..]; |
| break; |
| case "befehl": |
| s = s[1..]; |
| break; |
| case "alle": |
| switch (s[1]) { |
| case "details": |
| q = "Details"; |
| p = P_DETAILS; |
| break; |
| case "lesbaren details": |
| q = "lesbaren Details"; |
| p = P_READ_DETAILS; |
| break; |
| case "befehle": |
| q = "Befehle"; |
| p = H_COMMANDS; |
| break; |
| default: |
| write("Du kannst alle Befehle, alle Details und alle lesbaren Details loeschen!\n"); |
| return 1; |
| } |
| printf("Wirklich alle %s loeschen (ja/nein)?\n]", q); |
| input_to("loesch_etwas", 0, p); |
| return 1; |
| default: |
| flag |= (DETAIL|RDETAIL); |
| ret = 0; // Koennte auch ein Artikel in der Zeitung sein... |
| break; |
| } |
| for (i=sizeof(s)-1; i>=0; i--) { |
| if (!flag) { // Befehl soll geloescht werden... |
| if (member(com=Query(H_COMMANDS), s[i])) { |
| com = m_copy_delete(com, s[i]); |
| write("Befehl '"+s[i]+"' wurde geloescht.\n"); |
| } |
| else if (sizeof(t=old_explode(s[i], " ")) > 1 && |
| member(com, t[0]) && |
| member(com[t[0]], p=implode(t[1..], " "))) { |
| com[t[0]] = m_copy_delete(com[t[0]], p); |
| write("Befehl '"+s[i]+"' wurde geloescht.\n"); |
| } |
| Set(H_COMMANDS, com); |
| } |
| else { |
| if (flag & DETAIL) { |
| if (!QueryProp(P_DETAILS)[s[i]]) |
| notify_fail("Das Detail '"+s[i]+"' gibt es nicht.\n"); |
| else { |
| RemoveDetail(s[i]); |
| write("Detail '"+s[i]+"' wurde geloescht.\n"); |
| ret = 1; |
| } |
| } |
| if (flag & RDETAIL) { |
| if (!QueryProp(P_READ_DETAILS)[s[i]]) |
| notify_fail("Das lesbare Detail '"+s[i]+"' gibt es nicht.\n"); |
| else { |
| RemoveReadDetail(s[i]); |
| write("Lesbares Detail '"+s[i]+"' wurde geloescht.\n"); |
| ret = 1; |
| } |
| } |
| } |
| } |
| Save(); |
| return ret; |
| } |
| |
| int ausgang(string str) |
| { |
| int nr, maxNr, hin, zurueck; |
| string hier, da, ext; |
| closure hausProp; |
| mapping known_exits; |
| |
| if (!tp_owner_check()) { |
| return 0; |
| } |
| |
| hier = da = 0; |
| hausProp = symbol_function("HausProp",VERWALTER); |
| |
| if (!(str=UP_ARGS(this_player())) || |
| (sscanf(str, "%s %d", hier, nr) != 2 && |
| sscanf(str, "%s %s %d",hier, ext, nr) != 3) ) { |
| notify_fail( "Syntax: ausgang <richtung> [name] <nr>\n" ); |
| return 0; |
| } |
| |
| if (ext) { |
| if (funcall(hausProp, ext, HP_ENV) != funcall(hausProp, owner, HP_ENV)) { |
| printf("Das Haus von %s steht nicht im gleichen Raum wie Dein Haus!\n", |
| capitalize(ext)); |
| return 1; |
| } |
| else |
| da = RAUMNAME(ext, nr); |
| |
| // der allowed_check() wird im Eingangsraum des Zielhauses aufgerufen, |
| // da wir von anderen Raumen noch nicht wissen, ob sie ueberhaupt |
| // existieren. |
| if (!(RAUMNAME(ext, 0)->allowed_check(this_player()))) { |
| printf("Du darfst keinen Ausgang von Deinem Haus zu dem von %s legen!\n", |
| capitalize(ext)); |
| return 1; |
| } |
| } |
| else { |
| ext = owner; |
| da = RAUMNAME(ext, nr); |
| } |
| |
| maxNr = funcall(hausProp, ext, HP_ROOMS); |
| |
| if ( (hin = member(ausgaenge, lower_case(hier))) < 0) { |
| arr_out(ausgaenge, 0, 0, "Es sind nur folgende Ausgaenge moeglich:\n" ); |
| return 1; |
| } |
| else |
| zurueck = (hin + sizeof(ausgaenge)/2) % sizeof(ausgaenge); |
| |
| hier = RAUMNAME(owner, raumNr); |
| |
| // Kopie des Ausgaenge-Mappings erzeugen |
| known_exits=deep_copy(QueryProp(P_EXITS)); |
| // und den Notausgang entfernen. Somit bleiben nur die zu betrachtenden |
| // Ausgaenge ueber. |
| known_exits["notausgang"]=0; |
| |
| if (nr < 0 || nr > maxNr) |
| printf( "Die Nummer darf sich nur im Bereich zwischen 0 und %d bewegen!\n", |
| maxNr ); |
| else if ( ext == owner && nr == raumNr) |
| printf( "Aber dies IST Raum %d!\n", raumNr ); |
| else if (member(m_indices(known_exits), ausgaenge[hin]) != -1) |
| write( "Aus diesem Raum fuehrt schon ein Ausgang in diese Richtung!\n" ); |
| //else if (member(m_values(QueryProp(P_EXITS)), da) != -1) |
| // Notausgang wird hier zwar geloescht, aber im AddExit |
| // gibt's eh einen neuen, so das noetig ist, V* |
| else if (member(m_values(known_exits), da) != -1) |
| printf( "Es gibt hier schon einen Ausgang zu Raum %d!\n", nr ); |
| else if (member(m_indices(da->QueryProp(P_EXITS)), ausgaenge[zurueck]) != -1) |
| printf( "Es fuehrt schon irgendwo ein Ausgang in Richtung '%s'\n" |
| "nach Raum %d!\n", ausgaenge[hin], nr); |
| else { |
| AddExit( ausgaenge[hin], da ); |
| Save(); |
| da->AddExit(ausgaenge[zurueck], hier); |
| da->Save(); |
| printf( "OK, der Ausgang '%s' zum Raum %d wurde eingerichtet.\n", |
| ausgaenge[hin], nr ); |
| } |
| return 1; |
| } |
| |
| int |
| sperren(string str) |
| { |
| mapping ex, cmds; |
| int hin, zurueck; |
| |
| if (!tp_owner_check()) |
| return 0; |
| |
| if (!(str=UP_ARGS(this_player())) || str == "") { |
| notify_fail( "Syntax: sperre <ausgang>\n" ); |
| return 0; |
| } |
| str = lower_case(str); |
| ex = QueryProp(P_EXITS); |
| |
| if (raumNr == 0 && str == "raus") { |
| write( "Du kannst doch nicht Deine Haustuer loeschen!\n" ); |
| return 1; |
| } |
| if (!member(ex,str) || (hin = member(ausgaenge,str)) < 0) { |
| printf( "Es gibt hier keinen Ausgang '%s'!\n", str); |
| return 1; |
| } |
| else |
| zurueck = (hin + sizeof(ausgaenge)/2) % sizeof(ausgaenge); |
| |
| ex[str]->RemoveExit(ausgaenge[zurueck]); |
| tell_room(find_object(ex[str]), sprintf("Der Ausgang '%s' verschwindet ploetzlich...\n", ausgaenge[zurueck])); |
| cmds = ex[str]->QueryProp(H_COMMANDS); |
| cmds = m_copy_delete(cmds, ausgaenge[zurueck]); |
| ex[str]->SetProp(H_COMMANDS, cmds); |
| ex[str]->Save(); |
| RemoveExit(str); |
| cmds = QueryProp(H_COMMANDS); |
| cmds = m_copy_delete(cmds, str); |
| SetProp(H_COMMANDS, cmds); |
| Save(); |
| printf( "OK, der Ausgang '%s' wurde entfernt.\n", str ); |
| |
| Save(); |
| |
| return 1; |
| } |
| |
| varargs int |
| uebersicht(string dummy, string pre) |
| { |
| string *xc, *xd, o, raus, str; |
| mixed *com; |
| mapping tmp; |
| int i,j,k; |
| |
| if ( (getuid(this_player()) != owner) && |
| !(PATH+"access_rights")->access_rights(geteuid(this_player()), "") ) |
| return 0; |
| |
| i = VERWALTER->HausProp(owner, HP_ROOMS); |
| |
| if (i) |
| str = sprintf( "Dein Haus verfuegt ueber %d Raeume.\nDu stehst in Raum %d (%s).\n\n", i+1, raumNr, QueryProp(P_INT_SHORT) ); |
| else |
| str = sprintf( "Dein Haus verfuegt ueber einen Raum (%s)\n\n", QueryProp(P_INT_SHORT)); |
| |
| str += arr_out(m_indices(QueryProp(P_DETAILS)), |
| "Du hast keine Details beschrieben.", |
| "Du hast das Detail '%s' beschrieben.", |
| "Du hast folgende Details beschrieben:\n", 1 ); |
| |
| str += ("\n" + arr_out(m_indices(QueryProp(P_READ_DETAILS)), |
| "Du hast keine lesbaren Details beschrieben.", |
| "Du hast das lesbare Detail '%s' beschrieben.", |
| "Du hast folgende lesbaren Details beschrieben:\n", 1 ) ); |
| |
| tmp = Query(H_COMMANDS); |
| xc = sort_array(m_indices(tmp),#'<); |
| if (!sizeof(xc)) |
| str += ("\nDu hast keine Befehle beschrieben.\n"); |
| else { |
| if (sizeof(xc) == 1 && sizeof(xd=m_indices(tmp[xc[0]])) == 1) |
| str += ("\nDu hast den Befehl '"+ |
| xc[0]+((xd[0] == "") ? "" : " "+xd[0])+ |
| "' beschrieben.\n"); |
| else { |
| str += "\nDu hast folgende Befehle beschrieben:\n"; |
| |
| for (com = ({}), j=sizeof(xc)-1; j >= 0; j--) { |
| xd = sort_array(m_indices(tmp[xc[j]])-({"@NF@"}),#'>); |
| if ((sizeof(xd) > 1) && (xd[0] == "")) { |
| raus = "* "+xc[j]+", "+xc[j]+" "; |
| xd = xd[1..]; |
| } |
| else |
| raus = "* "+xc[j]+" "; |
| |
| str += arr_out(xd, "", raus+"%s", raus, 3); |
| } |
| } |
| } |
| |
| raus = (member(QueryProp(P_EXITS),"raus") ? "raus: Nach draussen.\n" : 0 ); |
| tmp = m_copy_delete(QueryProp(P_EXITS), "raus"); |
| m_delete(tmp, "notausgang"); |
| xc = m_indices(tmp); |
| xd = m_values(tmp); |
| |
| if (!sizeof(xc) && !raus) |
| str += "\nES GIBT KEINE AUSGAENGE!\n"; |
| else { |
| str += "\nEs gibt folgende Ausgaenge:\n"; |
| for (i=sizeof(xc)-1; i>=0; i--) |
| str += sprintf( "%s: Nach Raum %d %s(%s).\n", |
| xc[i], |
| (j=to_int(xd[i][<1..])), |
| (((o=old_explode(xd[i],"/")[<1][0..<6])==owner) ? |
| "" : "von "+capitalize(o)+" "), |
| xd[i]->QueryProp(P_INT_SHORT) ); |
| } |
| str += ((raus||"")+(pre||"")); |
| this_player()->More(str); |
| return 1; |
| } |
| |
| int kopieren(string str) |
| { |
| string was, alt, n, *neu, *par, err; |
| mixed das; |
| mapping com; |
| |
| if (!tp_owner_check()) |
| return 0; |
| |
| notify_fail("'kopiere detail <von> nach <nach>' oder\n" |
| +"'kopiere lesbares detail <von> nach <nach>' oder\n" |
| +"'kopiere befehl <befehl> [<parameter>] nach <befehl> [<parameter>]'!\n"); |
| |
| if (!(str=UP_ARGS(this_player())) || str == "") |
| return 0; |
| |
| neu = old_explode(str, " "); |
| was = neu[0][0..5]; |
| if (was == "detail" || was == "befehl") |
| str = implode(neu[1..], " "); |
| else if (was == "lesbar") |
| str = implode(neu[2..], " "); |
| else |
| return 0; |
| |
| if (sscanf(str, "%s nach %s", alt, n) != 2) |
| return 0; |
| |
| neu = brk(n); |
| switch(was) { |
| case "detail": |
| err = "Detail"; |
| if (das = GetDetail(alt)) { |
| AddDetail(neu, das); |
| Save(); |
| } |
| break; |
| case "lesbar": |
| err = "lesbares Detail"; |
| if (das = QueryProp(P_READ_DETAILS)[alt]) { |
| AddReadDetail(neu, das); |
| Save(); |
| } |
| break; |
| case "befehl": |
| err = "Befehl"; |
| was = (par=old_explode(alt, " "))[0]; |
| if (member(com=QueryProp(H_COMMANDS),was)) { |
| int i; |
| if (sizeof(par) == 1) { // <bef> nach <bef1,bef2,...> |
| das = com[was]; |
| for (i=sizeof(neu)-1; i>=0; i--) { |
| if (befCheck(neu[i])) { |
| if (com[neu[i]]) |
| com[neu[i]] += das; |
| else |
| com += ([ neu[i] : das ]); |
| } |
| else |
| write("Ungueltiger Befehl: '"+neu[i]+"'.\n"); |
| } |
| } |
| else { // <bef> <parameter> nach <bef1,bef2,...> |
| alt = implode(par[1..]-({""})," "); |
| if (das = com[was][alt]) { |
| for (i=sizeof(neu)-1; i>=0; i--) { |
| if (befCheck(neu[i])) { |
| das = ([ alt : com[was][alt];com[was][alt,1] ]); |
| if (com[neu[i]]) |
| com[neu[i]] += das; |
| else |
| com += ([ neu[i] : das ]); |
| } |
| else { |
| par = old_explode(neu[i], " "); |
| n = par[0]; |
| if (befCheck(n)) { |
| das = ([ implode(par[1..], " ") : com[was][alt];com[was][alt,1] ]); |
| if (com[n]) |
| com[n] += das; |
| else |
| com += ([ n : das ]); |
| } |
| else |
| write("Ungueltiger Befehl: '"+neu[i]+"'.\n"); |
| } |
| } |
| } |
| } |
| Save(); |
| } |
| break; |
| default: |
| write( "Du kannst nur Details, lesbare Details und Befehle kopieren!\n" ); |
| return 1; |
| } |
| if (!das) |
| printf( "Kann %s '%s' nicht finden!\n", err, alt); |
| else |
| write( "OK!\n" ); |
| |
| return 1; |
| } |
| |
| int licht(string str) |
| { |
| int ll, tl; |
| |
| if (!allowed_check(this_player())) |
| return 0; |
| |
| if (!str || (str != "an" && str != "aus")) { |
| notify_fail("Syntax: 'licht an' oder 'licht aus'\n"); |
| return 0; |
| } |
| |
| ll = QueryProp(P_LIGHT); |
| tl = PL->QueryProp(P_PLAYER_LIGHT); |
| |
| switch(str) { |
| case "an": |
| if (tl > 0) |
| write("Aber es ist doch schon hell!\n"); |
| else { |
| SetProp(P_LIGHT, 1); |
| tell_room(this_object(), "Es wird wieder hell.\n"); |
| } |
| break; |
| case "aus": |
| if (tl <= 0) |
| write("Aber es ist doch schon dunkel!\n"); |
| else { |
| SetProp(P_LIGHT, 0); |
| tell_room(this_object(), "Es wird dunkel.\n"); |
| } |
| break; |
| } |
| return 1; |
| } |
| |
| #define CASUS ({ "WER", "WESSEN", "WEM", "WEN" }) |
| static string rpXchg(string s) |
| { |
| int c,p,g; |
| |
| switch(s[0..1]) { |
| case "@W": |
| c = to_int(s[2..2]); |
| return ("@"+CASUS[c]); |
| case "@P": |
| c = to_int(s[2..2]); |
| return ("@P"+CASUS[c]); |
| case "@B": |
| c = to_int(s[2..2]); |
| g = to_int(s[3..3]); |
| p = to_int(s[4..4]); |
| return ("@B"+({"N", "M", "F"})[g]+({"S", "P"})[p]+CASUS[c]); |
| case "@F": |
| return "@PARA"; |
| } |
| return s; |
| } |
| |
| private string reParse(string s1, string s2) |
| { |
| string *p; |
| |
| if (s2) |
| s1 = s1+"@@\n"+s2; |
| |
| p = regexplode(s1, "(@W[0-3]|@P[0-3]|@B[0-3][0-2][0-1])"); |
| p = map(p, #'rpXchg); |
| return implode(p, ""); |
| } |
| |
| private string getPreText(string prop, string expr) |
| { |
| mixed crunched; |
| int i; |
| |
| crunched = VERWALTER->PCrunch(QueryProp(prop)); |
| if (!crunched || !pointerp(crunched)) |
| return 0; |
| |
| if (prop == H_COMMANDS && strstr(expr, " ") < 0) |
| expr = expr+" "; |
| |
| for (i=sizeof(crunched)-1; i>=0; i--) |
| if (member(crunched[i][0], expr) >= 0) |
| break; |
| |
| if (i<0) |
| return 0; |
| |
| detail = crunched[i][0]; |
| |
| if (prop == H_COMMANDS) |
| return reParse(crunched[i][1], crunched[i][2]); |
| else |
| return crunched[i][1]; |
| } |
| |
| varargs int |
| aendern(string str, int f) |
| { |
| string *parts, pre; |
| int sp, sr, ret; |
| |
| if (!tp_owner_check()) |
| return 0; |
| |
| if (!f && (!(str=UP_ARGS(this_player())) || str == "")) { |
| notify_fail("Was willst Du denn aendern?\n" ); |
| return 0; |
| } |
| |
| sp = sizeof(parts = old_explode(str, " ")); |
| sr = sizeof(brk(str)); |
| detail = 0; |
| flag = f; |
| |
| switch(parts[0][0..3]) { |
| case "raum": // Lang- oder Kurzbeschreibung |
| case "haus": |
| if (sp == 1 || parts[1] == "lang") |
| flag |= LANG; |
| else if (parts[1] == "kurz") { |
| write("Nimm dazu doch bitte 'beschreibe'!\n"); |
| return 1; |
| } |
| pre = ((flag & AUSSEN) ? (find_object(HAUSNAME(owner)))->QueryProp(P_LONG) : QueryProp(P_INT_LONG)); |
| break; |
| case "meld": |
| if (file_size(REPFILE(owner)) > 0) |
| pre = read_file(REPFILE(owner)); |
| else { |
| write("Ich finde keine Meldungen aus Deinem Haus!\n"); |
| return 1; |
| } |
| flag |= REPORT; |
| break; |
| case "deta": // Details |
| if (sp==1) { |
| notify_fail("Welches Detail willst Du denn aendern?\n"); |
| return 0; |
| } |
| if (sr>1) { |
| notify_fail("Du kannst immer nur ein Detail aendern!\n"); |
| return 0; |
| } |
| flag |= DETAIL; |
| pre = getPreText(P_DETAILS, implode(parts[1..], " ")); |
| break; |
| case "lesb": // lesbare Details |
| notify_fail("Welches lesbare Detail willst Du denn aendern?\n"); |
| if (sp == 1) return 0; |
| if ((parts[1] == "details" || parts[1] == "detail") && (sp==2)) |
| return 0; |
| if (sr>1) { |
| notify_fail("Du kannst immer nur ein lesbares Detail aendern!\n"); |
| return 0; |
| } |
| flag |= RDETAIL; |
| pre = getPreText(P_READ_DETAILS, implode(parts[1..], " ")); |
| break; |
| case "befe": // Befehle |
| ret = 0; |
| if (sp == 1) { |
| notify_fail("Welchen Befehl willst Du denn aendern?\n"); |
| return 0; |
| } |
| if (sr>1) { |
| notify_fail("Du kannst immer nur einen Befehl aendern!\n"); |
| return 0; |
| } |
| flag |= BEFEHL; |
| pre = getPreText(H_COMMANDS, implode(parts[1..], " ")); |
| break; |
| default: |
| notify_fail("Das kannst Du nicht aendern! Eine Liste der Dinge, die Du hier aendern\n" |
| +"kannst, erhaeltst Du mit 'hilfe aendere'.\n" ); |
| return 0; |
| break; |
| } |
| if (!pre) |
| write("Hm, sowas ist hier noch nicht beschrieben...\n"); |
| else { |
| write( "Aendere nun den Text.\n(Beenden mit . oder **, Abbruch mit ~q, Hilfe mit ~h)\n" ); |
| nedit( "aenderung", pre ); |
| } |
| return 1; |
| } |
| |
| void aenderung(string str) |
| { |
| string *warn; |
| |
| if (!str) { |
| write("Nichts geaendert!\n"); |
| return; |
| } |
| |
| if (flag && !(flag & BEFEHL)) |
| str = normstr(str); |
| |
| warn = ({ }); |
| |
| if (flag & LANG) { |
| if (flag & AUSSEN) { |
| object haus; |
| haus = find_object(HAUSNAME(owner)); |
| haus->SetProp(P_LONG, str); |
| haus->Save(); |
| } |
| else |
| SetProp(P_INT_LONG, str); |
| } |
| else if (flag & DETAIL) { |
| if (str == "") |
| RemoveDetail(detail); |
| else |
| AddDetail(detail, str); |
| } |
| else if (flag & RDETAIL) { |
| if (str == "") |
| RemoveReadDetail(detail); |
| else |
| AddReadDetail(detail, str); |
| } |
| else if (flag & BEFEHL) { |
| if (str == "") |
| RemUserCmd(detail); |
| else { |
| string *s; |
| |
| s = old_explode(preparse(str, &warn), "@@\n"); |
| if (sizeof(s) > 1 && s[1] != "") |
| AddUserCmd(detail, 0, normstr(s[0]), normstr(s[1])); |
| else |
| AddUserCmd(detail, 0, normstr(s[0]), 0); |
| } |
| } |
| else if (flag & REPORT) { |
| rm(REPFILE(owner)); |
| if (str != "") |
| write_file(REPFILE(owner), str); |
| } |
| else |
| write( "Huch! Unbekanntes Flag ("+flag+")... Sag mal Wargon Bescheid...\n"); |
| |
| arr_out(warn, "OK.", "WARNUNG! Ungueltiger Platzhalter: %s", |
| "WARNUNG! Ungueltige Platzhalter: "); |
| Save(); |
| } |
| |
| int SmartLog(string ofile, string typ, string msg, string date) |
| { |
| object home; |
| |
| // speichere Meldung im Rep-Log des Seherhaus-Besitzers |
| write_file(REPFILE(owner), sprintf("%s von %s in Raum %d (%s):\n%s\n", |
| typ, |
| capitalize(getuid(this_player())), |
| raumNr, |
| date, |
| break_string(msg,78))); |
| |
| if (IS_LEARNER(owner)) { |
| log_file("report/"+owner+".rep", |
| sprintf("MELDUNG von %s im Seherhaus, Raum %d (%s):\n" |
| +"Bitte zur Kenntnis nehmen! (Mit dem Befehl 'meldungen') -Wargon\n", |
| capitalize(getuid(this_player())), |
| raumNr, |
| date)); |
| } |
| |
| // erhoehe im Hauptraum den Rep-Zaehler und speichere |
| home = load_object(RAUMNAME(owner,0)); |
| home->Set(H_REPORT, home->Query(H_REPORT)+1); |
| home->Save(); |
| |
| return 1; |
| } |
| |
| static int report(string str) |
| { |
| string rep, *lines; |
| int rNum, l, s; |
| |
| if (!allowed_check(this_player())) |
| return 0; |
| |
| if (file_size(REPFILE(owner)) <= 0) { |
| write( "Keine Meldungen zu finden... Du bist wunschlos gluecklich.\n" ); |
| return 1; |
| } |
| rep = read_file(REPFILE(owner)); |
| |
| if (!rep) { |
| write( "Oha! Die Datei mit den Meldungen ist zu gross! Sag doch bitte mal\n" |
| +"Wargon Bescheid!\n"); |
| return 1; |
| } |
| |
| if (str) { |
| string d, *new, *tmp, prev; |
| int nr, nextNr, m; |
| |
| if (str == "hier") |
| rNum = raumNr; |
| else |
| rNum = to_int(str); |
| |
| if (rNum > VERWALTER->HausProp(owner, HP_ROOMS)) { |
| write( "So viele Raeume hast Du gar nicht!\n"); |
| return 1; |
| } |
| |
| lines = old_explode(rep, "\n"); |
| s = sizeof(lines); |
| for (l=0; prev == 0; l++) |
| if (sscanf(lines[l], "%s von %s in Raum %d %s:", d, d, nr, d)==4) |
| prev=lines[l]; |
| |
| for ( new = ({}), tmp=({}); l<s; l++) { |
| m=sscanf(lines[l], "%s von %s in Raum %d %s:", d, d, nextNr, d); |
| if (m != 4 && nr == rNum) |
| tmp += ({ lines[l] }); |
| |
| if (m==4) { |
| if (sizeof(tmp)) { |
| new = new + ({ prev }) + tmp; |
| tmp = ({}); |
| } |
| nr = nextNr; |
| prev = lines[l]; |
| } |
| } |
| if (sizeof(tmp)) |
| new = new + ({prev}) + tmp; |
| rep = implode(new, "\n"); |
| } |
| |
| this_player()->More(rep); |
| return 1; |
| } |
| |
| // $Log: raum.c,v $ |
| // Revision 1.5 2003/11/15 14:03:58 mud |
| // Lichtaenderungen von Zook |
| // |
| // Revision 1.4 2003/02/17 20:00:00 mud |
| // Im Reset wird nun getestet, ob der Raum einen Ausgang in einen Null-Raum |
| // hat. Dies wurde notwengig, damit Spieler nicht in Seherhaeuser eingesperrt |
| // werden koennen. Die Funktionen AddExit(), RemoveExit() und Reset starten |
| // gegebenenfalls den Ausgangstest. Einige Funs mussten leicht angepasst |
| // werden. |
| // Die Funktionen room_has_exit() und is_exit() wurden von Vardion@MG |
| // entwickelt und zur Verfuegung gestellt. - Vanion |
| // |
| // Revision 1.3 2001/02/04 21:21:34 mud |
| // (brk,getBefParam): Vorkehrungen gegen fuehrende und schliessende |
| // Leerzeichen in Befehlsparametern und anderen Listen. |
| // |
| // Revision 1.2 2001/01/01 18:17:47 mud |
| // (ausgang): Wenn ein Ausgang zu einem anderen Seherhaus gelegt wird, |
| // wird die Erlaubnis in dessen Eingangsraum abgefragt, und nicht in |
| // dem angeforderten Zielraum (der Eingangsraum existiert auf jeden |
| // Fall, der Zielraum vielleicht nicht). |
| // |
| // Revision 1.1.1.1 2000/08/20 20:22:42 mud |
| // Ins CVS eingecheckt |
| // |
| // 04.02.98 Meldungen koennen geloescht werden. |
| // |
| // Revision 2.16 1997/11/15 19:33:23 Wargon |
| // arr_out(), preparse(): kleine Bugfixes |
| // |
| // Revision 2.15 1997/10/06 15:24:38 Wargon |
| // Unsichtbare Magier melden/anzeigen |
| // Meldung beim Betreten abgeschlossener Haeuser fuer Magier |
| // |
| // Revision 2.14 1996/02/21 18:12:47 Wargon |
| // SmartLog() rein, dafuer die eigenen Rueckmeldungsbefehle raus |
| // |
| // Revision 2.13 1995/10/31 12:56:16 Wargon |
| // Rueckmeldungen fuer Objekte werden ans Spielerobjekt weitergegeben. |
| // |
| // Revision 2.12 1995/08/07 18:35:12 Wargon |
| // Einige Bugs bei "aendere" behoben. |
| // |
| // Revision 2.11 1995/06/29 08:57:05 Wargon |
| // Hausbesitzer, die schon Magier sind, bekommen bei Rueckmeldungen auch einen |
| // Eintrag in ihr /log/report/xyz.rep-File |
| // "licht an/aus" ist seit 2.9 drin ;) |
| // |
| // Revision 2.10 1995/06/28 08:59:57 Wargon |
| // Neue Befehle aendere, meldungen fuer den Hausbesitzer. |
| // typo, bug/fehler, idee werden dem Haus-.rep-File zugefuehrt. |
| // Jetzt koennen die Seher ihre Typos selber fixen! ;^) |
| // |
| // Revision 2.9 1995/06/20 07:49:15 Wargon |
| // *** empty log message *** |
| // |
| // Revision 2.8 1995/04/21 10:48:39 Wargon |
| // Bugfix in beschreiben(), wenn die Hausaussenbeschreibung |
| // verlangt wird (war schon seit Ewigkeiten buggy... ;) |
| // |
| // Revision 2.7 1995/04/21 08:55:32 Wargon |
| // Load()/Save() und eigene Kommandos ausgelagert. |
| // Kommandos koennen mit notify_fail() versehen werden. |
| // |
| // Revision 2.6 1995/03/07 13:55:36 Wargon |
| // Add/RemUserCmd(), Beschreibungen werden bei reset()/clean_up() |
| // gepackt gespeichert. |
| // Bei Kommandos nur noch more(), wenn es auch noetig ist. |
| // |
| // Revision 2.5 1995/02/27 20:48:26 Wargon |
| // Kleine Schoenheitsfehler in selbstdefinierten Befehlen beseitigt. |
| // |
| // Revision 2.4 1995/02/22 21:30:52 Wargon |
| // Noch mehr Aenderungen an den Befehlen: |
| // - Preparsing der Platzhalter |
| // - Platzhalter fuer Possessivpronomen |
| // - Meldung fuer Ausfuehrenden wird geMore()t |
| // - Rassen- und Geschlechtespezifische Meldungen moeglich |
| // - Auch fuer Ausgaenge koennen Befehle definiert werden |
| // (nur fuer existierende; wird der Ausgang gesperrt, wird auch |
| // der Befehl geloescht) |
| // Im Zuge des Preparsings hat sich die Befehlauswertung etwas |
| // vereinfacht. |
| // |
| // Revision 2.3 1995/02/20 22:15:44 Wargon |
| // READ_DETAILS werden jetzt mit More() ausgegeben. |
| // Selbstdefinierte Befehle: mit @PWER, ... koennen die Personalpronomina |
| // eingebaut werden; Einbau jetzt auch in die Meldung fuer den Ausloeser |
| // moeglich; _unparsed_args() in der Auswertung. |
| // |
| // Revision 2.2 1995/02/15 11:23:04 Wargon |
| // NEU: Selbstdefinierbare Befehle. |
| // |
| // Revision 2.1 1995/02/04 15:02:36 Wargon |
| // Die Truhe wird nun ueber die Property CHEST verwaltet. Der AddItem()- |
| // Aufruf wurde deshalb von create() nach Load() verlegt. Geladen wird |
| // sie nur, wenn das Load() von Hausverwalter erfolgte. |
| // clean_up(), wenn Raum leer ist oder nur eine leere Truhe drin steht. |
| // |
| // Revision 2.0 1995/02/01 20:36:49 Wargon |
| // Entruempelt und Massnahmen fuer _unparse_args() getroffen. |
| |