| /* |
| * 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; |
| } |