Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/d/seher/haeuser/hausverwalter.c b/d/seher/haeuser/hausverwalter.c
new file mode 100644
index 0000000..26643d1
--- /dev/null
+++ b/d/seher/haeuser/hausverwalter.c
@@ -0,0 +1,621 @@
+/*
+ * hausverwalter.c -- Verwaltung der Seherhaeuser
+ *
+ * Das Grundobjekt stammt von Boing, Fortfuehrung erfolgte durch Jof.
+ * Letzte Aenderungen verschuldet durch Wargon ;)
+ *
+ * $Date: 1997/09/09 17:19:29 $
+ * $Revision: 2.3 $
+ * $Log: hausverwalter.c,v $
+ * Revision 2.3 1997/09/09 17:19:29 Wargon
+ * Bugfix beim Verlegen/Loeschen eines Hauses
+ *
+ * Revision 2.2 1996/02/21 18:15:02 Wargon
+ * *** empty log message ***
+ *
+ * Revision 2.0 1994/11/17 13:48:27 Wargon
+ * Modifikationen fuer die Trennung Haus/Raum.
+ *
+ * Revision 1.5 1994/10/24 08:21:55 Wargon
+ * Parameter fuer NeuesHaus geaendert.
+ * Fuer Sicherheitscheck secure() eingebaut.
+ * VerlegeHaus() eingebaut, falls ein Haus mal verlegt werden muss.
+ *
+ * Revision 1.4 1994/10/10 21:50:59 Wargon
+ * NeuesHaus() und LoescheHaus() bedienen nun auch den OBJECTD.
+ * PruefeHaus() wurde damit hinfaellig.
+ *
+ * Revision 1.3 1994/10/09 20:11:48 Wargon
+ * Beschreibung der Haeuser vom Hausverwalter abgekoppelt!
+ * Die megamap enthaelt nur noch Besitzer und Standort des Hauses.
+ * Infolgedessen sind Save() und build() rausgeflogen...
+ *
+ * Revision 1.2 1994/10/07 22:19:48 Wargon
+ * AUFBAU DES MAPPINGS GEAENDERT! Der Filename des Raumes, in dem das
+ * Haus steht, steht jetzt als erster Eintrag im Mapping! Alle anderen
+ * Eintraege sind um 1 weitergewandert.
+ * Beim Laden des Verwalters werden nicht mehr alle Seherhaeuser ge-
+ * laden. Ein Haus wird erst geladen, wenn der Raum, in dem es steht,
+ * geladen wird (PruefeHaus(), siehe auch std/room::create()).
+ *
+ * Revision 1.1 1994/10/07 14:19:36 Wargon
+ * Initial revision
+ *
+ */
+#pragma strict_types
+#include <properties.h>
+#include <wizlevels.h>
+#include <rooms.h>
+#include <moving.h>
+#include "haus.h"
+
+#define H_MAX_ROOMS 9
+
+mapping megamap;
+
+// Haus fuer owner im Raum env erstellen. Wird i.d.R nur vom Instanthaus gemacht.
+void NeuesHaus(string owner, object env);
+
+// Haus von owner loeschen (samt Savefile!). Dieser Vorgang ist unwiderruflich!
+int LoescheHaus(string owner);
+
+// Loescht den letzten hinzugefuegten Raum im Seherhaus von 'owner'.
+void LoescheRaum(string owner);
+
+// Fuegt einen Raum zum Seherhaus von 'owner' hinzu.
+void NeuerRaum(string owner);
+
+// Haus von owner vom Raum 'von' in den Raum 'nach' verschieben.
+int VerlegeHaus(string owner, string von, string nach);
+
+// Kann in ob ein Haus gebaut werden? 0: Ja, sonst Fehler!
+int Unbebaubar(object ob);
+
+// Jemandem im Haus Zusatzrechte einraeumen/entziehen
+string *Erlaube(string owner, string *wer);
+string *Verbiete(string owner, string *wer);
+
+// Eigenschaften aus der megamap abfragen
+mixed HausProp(string owner, int prop);
+
+// Propertymapping deduplizieren
+mixed PCrunch(mapping prop);
+
+// Lade Seherhaus von Besitzer 'owner'
+object _LadeHaus(string owner);
+
+// Lade im Seherhaus von 'owner' den Raum mit der Nummer 'num'
+object _LadeRaum(string owner, int num);
+
+// returnt das Seherhaus von Besitzer 'owner'
+object FindeHaus(string owner);
+
+void create()
+{
+ if (!restore_object(SAVEFILE))
+ megamap = ([ ]);
+ seteuid(getuid(this_object()));
+}
+
+int query_prevent_shadow(object ob)
+{
+ HLOG("SHADOW",sprintf( "%s, von %O im Verwalter.\n",dtime(time())[5..], ob));
+ return 1;
+}
+
+private int
+secure()
+{
+ int ar;
+
+ if (!this_interactive())
+ return 0;
+
+ // das tragbare Instanthaus und die Hausausgabe duerfen:
+ if ((load_name(previous_object()) == PATH+"traghaus") ||
+ (load_name(previous_object()) == PATH+"sb_ausgabe")) {
+ return 1;
+ }
+
+ catch(ar = (int)(PATH+"access_rights")->access_rights(geteuid(this_interactive()), "haus.h"));
+
+ // Erzmagier und alle mit Schreibrechten auf haus.h duerfen
+ if ( (this_interactive() == this_player()) &&
+ (IS_ARCH(this_interactive()) || ar ) )
+ return 1;
+ return 0;
+}
+
+// ersetzt das HAEUSER logfile mit neuer Statistik
+private void
+dump()
+{
+ string *ind;
+ int i, hnum, rnum = 0;
+
+ // loesche logfile
+ rm(PATH+"HAEUSER");
+
+ // betrachte alle Seherhaeuser
+ ind = m_indices(megamap);
+ if (hnum=sizeof(ind)) {
+ write_file(PATH+"HAEUSER", sprintf("Es gibt %d Seherhaeuser:\n", hnum));
+ ind = sort_array(ind,#'>); //'
+ // alle Haeuser sortiert nach Besitzername durchgehen:
+ for(i = 0; i < hnum; ++i) {
+ // zaehle Raeume
+ ++rnum; // Hauptraum
+ rnum += (megamap[ind[i], HP_ROOMS]); // Nebenraeume
+ // Eine Zeile pro Haus: Besitzername (Raumanzahl) Standort-Pfad
+ write_file(PATH+"HAEUSER",
+ sprintf( "%-13s (%d) %s\n",
+ capitalize(ind[i]),
+ megamap[ind[i],HP_ROOMS],
+ megamap[ind[i],HP_ENV] ) );
+ }
+ write_file(PATH+"HAEUSER", sprintf("Es gibt insgesamt %d Raeume.\n", rnum));
+ }
+ else
+ write_file(PATH+"HAEUSER", "KEINE HAEUSER!\n");
+}
+
+// Gegenrichtungen
+#define X_EXIT (["oben":"unten", "unten":"oben",\
+ "westen":"osten", "osten":"westen",\
+ "sueden":"norden", "norden":"sueden",\
+ "nordosten":"suedwesten", "suedwesten":"nordosten",\
+ "nordwesten":"suedosten", "suedosten":"nordwesten" ])
+
+// fuer jeden Raum im Haus [max .. 0] betrachte alle Ausgaenge;
+// zaehle alle Ausgaenge ausser der Haustuer in Raeume,
+// die nicht zu diesem Seherhaus gehoeren
+// (dies sollten Uebergaenge zu anderen Seherhaeusern sein)
+// falls rem != 0 loesche die Gegenrichtung zu diesen Ausgaengen,
+// d.h. kappe alle Uebergaenge aus anderen Seherhaeusern in dieses
+private int
+check_exits(string owner, int max, int rem)
+{
+ int x, nr, bar;
+ string hname, foo;
+ object here, there;
+
+ x = 0;
+ for (nr = max; nr >= 0; --nr) {
+ // betrachte jeden Seherhausraum mit index max .. 0
+ hname = RAUMNAME(owner, nr);
+
+ if (catch(here = load_object(hname);publish)) {
+ printf("error loading %O!\n", hname);
+ continue;
+ }
+ foreach (string dir, string path : (mapping)(here->QueryProp(P_EXITS))) {
+ // betrachte alle Ausgaenge
+ if (dir == "raus") {
+ // Haustuer aus dem Hauptraum darf natuerlich rausfuehren
+ continue;
+ }
+ if ((sscanf(path, PATH+"%sraum%d", foo, bar) != 2) || (foo != owner)) {
+ // Raum in den der Ausgang fuehrt ist nicht in diesem Seherhaus
+ ++x;
+ if (rem) {
+ catch(there = load_object(path);publish);
+ if (there) {
+ // loesche die Gegenrichtung zu dem Ausgang
+ there->RemoveExit(X_EXIT[dir]);
+ there->Save();
+ }
+ }
+ }
+ }
+ }
+ return x;
+}
+
+// Haus fuer owner im Raum env erstellen.
+// Wird i.d.R nur vom Instanthaus gemacht.
+void NeuesHaus(string owner, object env)
+{
+ object h;
+
+ // keine passenden Rechte
+ if (!secure())
+ return;
+
+ // neuen Eintrag im Verwalter-Mapping fuer das Haus erstellen
+ megamap += ([ owner : object_name(env); 0; ({}) ]);
+ // Haus am Bauplatz laden, falls moeglich
+ catch(h = load_object(HAUSNAME(owner));publish);
+ if (!h)
+ return;
+
+ // Haus Speichern und als Raumautoloader eintragen
+ h->Save();
+ OBJECTD->AddObject(h, object_name(env));
+ // Bauplatz auf never clean setzen und Verwalter abspeichern
+ env->SetProp(P_NEVER_CLEAN, 1);
+ save_object(SAVEFILE);
+
+ // Hauptraum des Seherhauses laden
+ h = load_object(RAUMNAME(owner,0));
+ h->SetProp(H_CHEST,1);
+ // Hauptraum speichern
+ h->Save();
+ // Truhe laden
+ h->Load();
+ // Statistik ueber alle Seherhaeuser erneuern
+ dump();
+}
+
+// loescht den letzten hinzufuegten Raum im Seherhaus von 'owner'
+void LoescheRaum(string owner)
+{
+ object raumob;
+ int nr;
+
+ // kein passendes Seherhaus verwaltet oder kein Recht das zu tun
+ if (!member(megamap, owner) || !secure())
+ return;
+
+ nr = megamap[owner, HP_ROOMS];
+ // falls das Haus ueberhaupt zusaetzliche Raeume (neben Hauptraum) hat
+ if (nr > 0 ) {
+ // falls geladen, remove Raum-Objekt
+ raumob = find_object(RAUMNAME(owner,(megamap[owner,HP_ROOMS])));
+ if (objectp(raumob))
+ raumob->remove(1);
+
+ // loesche Raum aus Verwalter-Mapping durch Anzahl um eins erniedrigen
+ --megamap[owner, HP_ROOMS];
+
+ // savefile muss per Hand geloescht werden:
+ tell_object(this_interactive(),
+ break_string(sprintf("Vergiss nicht, das Savefile zu loeschen, "
+ "also: "+HAUSSAVEPATH+"%s%d.o\n",
+ owner, nr),
+ 78));
+ // speicher Hausverwaltung ab und erneuer Statistik ueber alle Seherhaeuser
+ save_object(SAVEFILE);
+ dump();
+ }
+}
+
+// Fuegt einen Raum zum Seherhaus von 'owner' hinzu.
+void NeuerRaum(string owner)
+{
+ object raumob;
+
+ // kein passendes Seherhaus verwaltet oder kein Recht das zu tun
+ if (!member(megamap, owner) || !secure())
+ return;
+
+ // ist die Maximalanzahl von Raeumen schon erreicht?
+ if (megamap[owner, HP_ROOMS] < H_MAX_ROOMS)
+ {
+ // erhoehe Raumzaehler in Verwalter-Mapping
+ megamap[owner, HP_ROOMS]++;
+ // lade neuen Raum, falls moeglich
+ catch(raumob = load_object((RAUMNAME(owner,(megamap[owner,
+ HP_ROOMS]))));publish);
+ if(objectp(raumob))
+ // speicher neuen Raum
+ raumob->Save();
+
+ // speicher Verwalter-Mapping und erneuer Statistik ueber alle Seherhaeuser
+ save_object(SAVEFILE);
+ dump();
+ }
+}
+
+// Lade Seherhaus von Besitzer 'owner'
+object _LadeHaus(string owner)
+{
+ object haus;
+ string o;
+
+ // es wird kein passendes Seherhaus verwaltet
+ if (!member(megamap, owner))
+ return 0;
+
+ // Haus ist bereits geladen
+ if (haus=find_object(HAUSNAME(owner)))
+ return haus;
+
+ // lade Bauplatz
+ o = megamap[owner];
+ if (catch(load_object(o);publish))
+ {
+ write_file(PATH+"hauserror", o+" konnte nicht geladen werden.\n");
+ return 0;
+ }
+ // Haus ist durch Laden des Bauplatzes nun geladen
+ if (haus = find_object(HAUSNAME(owner)))
+ return haus;
+
+ // clone Standard-Haus, setze Besitzer
+ haus = clone_object(HAUS);
+ haus->move(o, M_NOCHECK);
+ haus->SetOwner(owner, find_object(RAUMNAME(owner,0)));
+ // lade individualisiertes Haus aus dem Savefile
+ haus->Load();
+
+ return haus;
+}
+
+// Lade im Seherhaus von 'owner' den Raum mit der Nummer 'num'
+object _LadeRaum(string owner, int num)
+{
+ object raum;
+
+ // es wird kein passendes Seherhaus verwaltet
+ if (!member(megamap, owner))
+ return 0;
+
+ // Raumnummer nicht zwischen 0 und letzter Raumnummer
+ if (num < 0 || num > megamap[owner,HP_ROOMS])
+ return 0;
+
+ // Raum ist bereits geladen
+ if (raum = find_object(RAUMNAME(owner,num)))
+ return raum;
+
+ // clone passenden Raum (0: Hauptraum, X: Nebenraum X) und setze Besitzer
+ raum = clone_object(num ? (RAUM) : (PATH+"raum0"));
+ raum->SetOwner(owner, num);
+ // lade Moebel, z.B. Seherhaustruhe
+ raum->Load();
+ // Hauptraum bekommt Haustuer-Ausgang zum Bauplatz
+ if (!num)
+ raum->AddExitNoCheck("raus", megamap[owner]);
+
+ return raum;
+}
+
+// returnt das Seherhaus-Objekt von Besitzer 'ow'
+// nur zum Loeschen oder Wegbewegen daher einfacher als _LadeHaus
+object FindeHaus(string ow)
+{
+ // es wird kein passendes Seherhaus verwaltet
+ if (!member(megamap, ow))
+ return 0;
+ return load_object(HAUSNAME(ow));
+}
+
+// Haus von owner loeschen (samt Savefile!). Dieser Vorgang ist unwiderruflich!
+int LoescheHaus(string owner)
+{
+ object haus;
+ int rooms;
+ string tmp;
+
+ // keine passenden Rechte fuers Loeschen
+ if (!secure())
+ return -1;
+
+ // Haus-Objekt finden, als Raumautoloader im Bauplatz austragen und entfernen
+ haus = FindeHaus(owner);
+ if (!haus)
+ return -2;
+ OBJECTD->RemoveObject(haus, object_name(environment(haus)));
+ environment(haus)->RemoveItem(object_name(haus));
+
+ // Raumanzahl merken
+ rooms = megamap[owner,HP_ROOMS];
+
+ // Haus aus Verwalter-Mapping loeschen
+ megamap = m_delete(megamap, owner);
+
+ // Verwalter-Mapping abspeichern
+ save_object(SAVEFILE);
+
+ // Uebergaenge von anderen Seherhaeusern zu diesem entfernen
+ check_exits(owner, rooms, 1);
+
+ // Savefile fuer das Haus entfernen
+ if (file_size(HAUSSAVEPATH+owner+".o")>0)
+ rm(HAUSSAVEPATH+owner+".o");
+
+ // Savefiles fuer die Raeume entfernen
+ do {
+ if (file_size(tmp = sprintf((HAUSSAVEPATH+"%s%d.o"),owner,rooms))>0)
+ rm(tmp);
+ } while (--rooms >= 0);
+
+ // Savefile fuer die Truhe loeschen
+ if (file_size(HAUSSAVEPATH+owner+"truhe.o")>0)
+ rm(HAUSSAVEPATH+owner+"truhe.o");
+
+ // Repfile fuer das Seherhaus loeschen
+ // TODO: Eintraege aus ERRORD loeschen.
+ if (file_size(PATH+"rep/"+owner+".rep") > 0)
+ rm(PATH+"rep/"+owner+".rep");
+
+ // Statistik ueber alle Seherhaeuser erneuern
+ dump();
+ return 1;
+}
+
+// Haus von owner vom Raum 'von' in den Raum 'nach' verschieben.
+int VerlegeHaus(string owner, string von, string nach)
+{
+ object h, ziel;
+
+ // kein Recht das zu tun
+ if (!secure())
+ return -111;
+
+ // zu verlegendes Haus nicht auffindbar
+ if (!(h=FindeHaus(owner)))
+ return -1;
+
+ // aktueller Standort des Hauses ist nicht Startpunkt von
+ if (object_name(environment(h)) != von)
+ return -2;
+
+ // Ziel-Standort nicht ladbar
+ catch(ziel = load_object(nach);publish);
+ if (!ziel)
+ return -3;
+
+ // Am Zielort darf kein Haus gebaut werden
+ if (Unbebaubar(ziel))
+ return -4;
+
+ // Seherhaus ist mit anderem Seherhaus verbunden und kann daher nicht
+ // verschoben werden
+ if (check_exits(owner, megamap[owner,HP_ROOMS], 0))
+ return -5;
+
+ // neuen Standort in Verwalter-Mapping eintragen
+ megamap[owner] = nach;
+ // Raumautoloader am alten Standort austragen und am neuen eintragen
+ OBJECTD->RemoveObject(h, von);
+ OBJECTD->AddObject(h, nach);
+ // Haus bewegen
+ h->move(nach, M_NOCHECK);
+ // Haustuer-Ausgang umtragen und Hauptraum speichern
+ catch(RAUMNAME(owner,0)->AddExitNoCheck("raus", nach);publish);
+ catch(RAUMNAME(owner,0)->Save();publish);
+ // Verwalter-Mapping speichern
+ save_object(SAVEFILE);
+ // Haus als Inmventar des alten Bauplatzes austragen
+ von->RemoveItem(object_name(h));
+ // Statistik ueber alle Seherhaeuser erneuern
+ dump();
+
+ return 1;
+}
+
+// Kann in ob ein Haus gebaut werden? 0: Ja, sonst Fehler!
+int Unbebaubar(object ob)
+{
+ // Raum ist geclont oder hat kein eigenes Filet, z.B. VC
+ if (clonep(ob) || file_size(object_name(ob)+".c")<0)
+ return 1;
+
+ // Innenraum
+ if (ob->QueryProp(P_INDOORS))
+ return 2;
+
+ // Bauplatz-Property nicht gesetzt
+ if (!(ob->QueryProp(P_HAUS_ERLAUBT)))
+ return 3;
+
+ return 0;
+}
+
+// Jemandem im Haus Zusatzrechte einraeumen
+string *Erlaube(string owner, string *wer)
+{
+ string *all;
+
+ // es wird kein passendes Seherhaus verwaltet
+ if (!member(megamap, owner))
+ return 0;
+
+ all = megamap[owner, HP_ALLOWED];
+ // fuege wer zu all dazu ohne doppelte Eintraege zu erzeugen:
+ all += wer-all;
+ // aender Rechteliste in der Verwaltung
+ megamap[owner, HP_ALLOWED] = all;
+ // speicher Verwalter-Mapping
+ save_object(SAVEFILE);
+ // return Liste der aktuellen Rechteinhaber
+ return all;
+}
+
+// Jemandem im Haus Zusatzrechte entziehen
+string *Verbiete(string owner, string *wer)
+{
+ // es wird kein passendes Seherhaus verwaltet
+ if (!member(megamap, owner))
+ return 0;
+
+ // aender Rechteliste in der Verwaltung
+ megamap[owner, HP_ALLOWED] -= wer;
+ // speicher Verwalter-Mapping
+ save_object(SAVEFILE);
+ // return Liste der aktuellen Rechteinhaber
+ return megamap[owner, HP_ALLOWED];
+}
+
+// Abfrage von Property 'prop' im Haus von 'owner'
+// prop gleich HP_ENV, HP_ROOMS oder HP_ALLOWED aus haus.h
+mixed HausProp(string owner, int prop)
+{
+ // es wird kein passendes Seherhaus verwaltet
+ if (!member(megamap, owner))
+ return 0;
+
+ return megamap[owner,prop];
+}
+
+// zerlegt das mapping, fasst indices mit gleichen values zusammen
+// und packt das ganze in ein array -> Deduplizieren
+// Das Ergebnis enthaelt
+// a) fuer jedes Detail ein Array, welches als erstes Element ein Array von
+// Schluesseln und als zweites Element einen String enthaelt.
+// b) fuer jedes Kommando ein Array, welches als erstes Element ein Array von
+// Syntaxen und zwei folgende Elemente mit Strings (Meldungen) enthaelt.
+// Beides ist in einem Format, dass die Elemente unmodifiziert an die
+// entsprechenden Add...()-Aufrufe gegeben werden koennen.
+
+// ([ "key1" : A, "key2" : B, "key3" : A ])
+// => ({ ({ ({ "key1", "key3" }), A )}, ({ ({ "key2" }), B )} })
+
+// ([ "key1" : ([ "key11" : A; B, "key12" : C; B, "key13" : A, B ]),
+// "key2" : ([ "key21" : A; B, "key22" : C; A ]) ])
+// => ({ ({ ({ "key1 key11", "key1 key13", "key2 key21" }), A, B }),
+// ({ ({ "key1 key12" }), C, B }),
+// ({ ({ "key2 key22" }), C, A }) })
+mixed PCrunch(mapping prop)
+{
+ mixed ret = ({});
+ int done = 0;
+ foreach(string key, mixed entry : prop)
+ {
+ if(mappingp(entry))
+ {
+ // mapping breite 2 im mapping fuer H_COMMANDS
+ foreach(string subkey, string val1, string val2 : entry)
+ {
+ done = 0;
+ foreach(mixed retset : ret)
+ {
+ // falls es schon im ergebnis-array etwas mit den selben werten gibt,
+ // fuege den index dort dazu
+ if(sizeof(retset) == 3 && retset[1] == val1 && retset[2] == val2)
+ {
+ retset[0] += ({ key+" "+subkey });
+ done = 1;
+ break;
+ }
+ }
+ // falls es noch nix im ergebnis-array mit den selben werten gab,
+ // fuege einen neuen eintrag hinzu
+ if(!done)
+ ret += ({ ({ ({ key+" "+subkey }), val1, val2 }) });
+ }
+ }
+ else
+ {
+ // einzelne Werte im Mapping fuer P_DETAILS und P_READ_DETAILS
+ done = 0;
+ foreach(mixed retset : ret)
+ {
+ // falls es schon im ergebnis-array etwas mit dem selben wert gibt,
+ // fuege den index dort dazu
+ if(sizeof(retset) == 2 && retset[1] == entry)
+ {
+ retset[0] += ({ key });
+ done = 1;
+ break;
+ }
+ }
+ // falls es noch nix im ergebnis-array mit dem selben wert gab,
+ // fuege einen neuen eintrag hinzu
+ if(!done)
+ ret += ({ ({ ({ key }), entry }) });
+ }
+ }
+ return ret;
+}