blob: 7fd0c5556107d8909bd4c17af0b2011976601587 [file] [log] [blame]
// 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.