MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | //-------------------------------------------------------------------------------- |
| 2 | // Name des Objects: Aufbewahrungtruhe fuer Autoload-Objekte |
| 3 | // |
| 4 | // Magier: Zesstra |
| 5 | //-------------------------------------------------------------------------------- |
| 6 | #pragma strong_types,rtt_checks |
| 7 | |
| 8 | #include "schrankladen.h" |
| 9 | inherit LADEN("swift_std_container"); |
| 10 | |
| 11 | //#include <ansi.h> |
| 12 | #include <class.h> |
| 13 | #include <wizlevels.h> |
| 14 | #include "/d/seher/haeuser/haus.h" |
| 15 | |
| 16 | #define IDS 0 |
| 17 | #define NAME 1 |
| 18 | #define ALDATA 2 |
| 19 | |
| 20 | #define LOG(x,y) log_file(x,sprintf("%s [%s, %O, %O]: %s\n",dtime(time()),\ |
| 21 | (uuid?uuid:" "),PL,object_name(ME),y)) |
| 22 | #define STORELOG(x) LOG("zesstra/ALTRUHE_STORE.log",x) |
| 23 | #define PICKLOG(x) LOG("zesstra/ALTRUHE_PICK.log",x) |
| 24 | |
| 25 | #define ITEMLOG(x) log_file("zesstra/ALTRUHE_ITEMS.log",\ |
| 26 | sprintf("%s [%O]: %s\n",dtime(time()),\ |
| 27 | this_interactive()||PL,x)) |
| 28 | |
| 29 | #define ERRLOG(x) LOG("zesstra/ALTRUHE.ERR",x) |
| 30 | |
| 31 | #undef BS |
| 32 | #define BS(x) break_string(x,78) |
| 33 | |
| 34 | #define VERSION_OBJ "5" |
| 35 | |
| 36 | #ifdef MAINTAINER |
| 37 | #undef MAINTAINER |
| 38 | #endif |
| 39 | #define MAINTAINER ({"zesstra"}) |
| 40 | |
| 41 | // Savefile der Blueprint |
| 42 | #ifdef SAVEFILE |
| 43 | #undef SAVEFILE |
| 44 | #endif |
| 45 | #define SAVEFILE __FILE__[..<3] |
| 46 | |
| 47 | #define DEBUG(x) if (funcall(symbol_function('find_player),MAINTAINER[0]))\ |
| 48 | tell_object(funcall(symbol_function('find_player),MAINTAINER[0]),\ |
| 49 | "ALTruhe: "+x+"\n") |
| 50 | |
| 51 | #define ACCESS (my_secure_level() >= ARCH_LVL) |
| 52 | |
| 53 | // Diese 4 sind fuer die Blueprint (Master aller Truhen) |
| 54 | mapping whitelist=([]); // erlaubte Autoloader, alle anderen nicht erlaubt. |
| 55 | mapping blacklist=([]); // bereits explizit durch EM+ abgelehnte Autoloader |
| 56 | mapping vorschlaege=m_allocate(1,2); // vorschlaege der Spieler |
| 57 | mapping data=([]); // hier speichert die BP alle Daten der Truhen |
| 58 | // WICHTIG: dieses Mapping wird in /secure/memory |
| 59 | // abgelegt und muss auch beim Neuladen ggf. von dort |
| 60 | // wieder abgeholt werden. Ausserdem teilen sich alle |
| 61 | // Truhen eines Spielers und diese Blueprint die Mappings |
| 62 | // darin, damit Aenderungen sofort in allen Truhen und dem |
| 63 | // Master bekannt sind. |
| 64 | |
| 65 | /* die einzelnen Truhen speichern in autoloader. Format: |
| 66 | 3 Werte pro Key, Keys sind die Namen der Blueprints der Objekte: |
| 67 | ([<blueprint>: <P_IDS>; <ob->name()>; <P_AUTOLOADOBJ> ]) |
| 68 | */ |
| 69 | nosave mapping autoloader=m_allocate(1,3); |
| 70 | nosave string uuid; // UUID des Eigentuemers |
| 71 | nosave object ob_in_bewegung; // uebler Hack eigentlich. :-( |
| 72 | |
| 73 | void NotifyInsert(object ob, object oldenv); |
| 74 | static mapping QueryData(); |
| 75 | static mapping SetData(mixed data); |
| 76 | protected void save_me(); |
| 77 | protected void check_content(); |
| 78 | |
| 79 | nomask private int my_secure_level(); //Args. |
| 80 | |
| 81 | protected void create() { |
| 82 | |
| 83 | // Ja, es is Absicht, dass das create der BP erst spaeter abgebrochen wird! |
| 84 | swift_std_container::create(); |
| 85 | |
| 86 | seteuid(getuid(ME)); |
| 87 | |
| 88 | // falls dies die BP ist: |
| 89 | // 1. das Savefile zu laden. |
| 90 | // 2. versuchen, die truhendaten von /secure/memory zu holen, damit nach dem |
| 91 | // Neuladen der Master und die Client immer nach _dieselben_ Mappings |
| 92 | // haben. |
| 93 | if (!clonep(ME)) |
| 94 | { |
| 95 | // Savefile restaurieren (auch wenn data im Memory ist, muss das sein, |
| 96 | // damit die anderen Variablen wieder eingelesen sind). |
| 97 | restore_object(SAVEFILE); |
| 98 | // jetzt Daten aus Memory holen, sofern verfuegbar |
| 99 | mapping tmp = "/secure/memory"->Load("truhendaten"); |
| 100 | if (mappingp(tmp)) |
| 101 | { |
| 102 | // Daten aus Savefile durch die vom Memory ersetzen |
| 103 | data = tmp; |
| 104 | } |
| 105 | else |
| 106 | { |
| 107 | // Keine Daten in Memory. Jetzt in jedem Fall den Pointer auf das Mapping data in |
| 108 | // /secure/memory ablegen |
| 109 | if ("/secure/memory"->Save("truhendaten",data) != 1) |
| 110 | { |
| 111 | raise_error("Could not save memory to /secure/memory."); |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | else |
| 116 | { |
| 117 | // brauchen Clones nicht. |
| 118 | set_next_reset(-1); |
| 119 | data=0; // brauchen Clones nicht. |
| 120 | } |
| 121 | |
| 122 | SetProp(P_SHORT, "Eine kleine, magische Holztruhe"); |
| 123 | SetProp("cnt_version_obj", VERSION_OBJ); |
| 124 | SetProp(P_NAME, "Holztruhe"); |
| 125 | SetProp(P_GENDER, FEMALE); |
| 126 | SetProp(P_NAME_ADJ,({"klein", "magisch"})); |
| 127 | SetProp(P_LONG, BS( |
| 128 | "Die kleine Holztruhe ist aus stabilem Eichenholz gefertigt. Eigentlich " |
| 129 | "saehe sie recht unscheinbar aus, waeren da nicht die vielen kunstvollen " |
| 130 | "Runen an den Seiten und auf dem Deckel.") |
| 131 | +"@@cnt_status@@"); |
| 132 | |
| 133 | AddId(({"autoloadertruhe", "holztruhe", "truhe"})); |
| 134 | |
| 135 | // den Rest vom Create braucht die BP nicht. |
| 136 | if (!clonep(ME)) return; |
| 137 | |
| 138 | SetProp(P_LOG_FILE,"zesstra/ALTRUHE.rep"); |
| 139 | |
| 140 | SetProp(P_WEIGHT, 3000); // Gewicht 5 Kg |
| 141 | // die drei hier sind in diesme Fall eigentlich voellig ohne Bedeutung |
| 142 | SetProp(P_MAX_WEIGHT, 1000000); // Es passen fuer 1000 kg Sachen rein. |
| 143 | SetProp(P_WEIGHT_PERCENT, 100); |
| 144 | SetProp(P_MAX_OBJECTS, 100); // sind eh immer 0 echte Objekte drin. |
| 145 | |
| 146 | SetProp(P_VALUE, 0); // Kein materieller Wert. Ist eh nicht verkaufbar. |
| 147 | SetProp(P_NOBUY, 1); // Wird im Laden zerstoert, falls er verkauft wird. |
| 148 | SetProp(P_NOGET, "Das geht nicht. "+Name(WER,1)+" haftet wie magisch am Boden.\n"); |
| 149 | SetProp(P_MATERIAL, ([MAT_OAK:49, MAT_MISC_MAGIC:50, MAT_JOFIUM: 1]) ); |
| 150 | SetProp(P_INFO, BS("In diese stabile Truhe kannst Du bestimmte " |
| 151 | "Autoload-Objekte hineinlegen und sie lagern, wenn Du sie gerade " |
| 152 | "nicht brauchst. (Mit 'deponiere <was>' kannst Du etwas in der " |
| 153 | "Truhe zur Aufbewahrung deponieren, mit 'entnehme <was> oder " |
| 154 | "'nimm <was> aus truhe' kannst Du einen Gegenstand wieder " |
| 155 | "herausnehmen.)")); |
| 156 | |
| 157 | // Prop fuer rebootfeste Moebel |
| 158 | // Der endgueltige Wert (UUID des Spielers) wird per SetBesitzer() gesetzt, |
| 159 | // sobald die Truhe das erste Mal in ein Seherhaus bewegt wurde. |
| 160 | SetProp(H_FURNITURE, 1); |
| 161 | |
| 162 | AD(({"platz","groesse"}), |
| 163 | BS("Die Truhe ist recht klein, aber merkwuerdigerweise " |
| 164 | "scheint sie viel mehr an Gegenstaenden aufnehmen zu koennen, als " |
| 165 | "es von ihrer Groesse her scheint.")); |
| 166 | AD(({"gegenstand","gegenstaende"}), |
| 167 | BS("Die Truhe scheint zwar vielen Gegenstaenden Platz zu bieten, aber " |
| 168 | "dafuer nimmt sie nicht jeden Gegenstand auf.")); |
| 169 | AD(({"holz","eichenholz"}), |
| 170 | BS("Das Eichenholz ist sehr stabil. Es ist ganz glatt geschliffen und " |
| 171 | "traegt viele kunstvolle Runen in sich.")); |
| 172 | AD(({"seiten","seite"}), |
| 173 | BS("Die Truhe hat 4 Seiten, die allesamt mit Runen verziert sind.")); |
| 174 | AD(({"boden"}), |
| 175 | BS("Der Boden der Truhe traegt keinerlei Runen.")); |
| 176 | AD(({"deckel"}), |
| 177 | BS("Auch der Deckel der Truhe ist mit Runen verziert.")); |
| 178 | AD(({"runen","rune"}), |
| 179 | BS("Die Runen bedecken alle 4 Seiten und den Deckel der Truhe. Man " |
| 180 | "hat sie zweifellos in muehsamer Arbeit aus dem harten Holz " |
| 181 | "geschnitzt. Anschliessend wurden sie offenbar mit einem " |
| 182 | "Metall gefuellt. Du verstehst zwar ueberhaupt nicht, was " |
| 183 | "die Runen bedeuten, aber sie sind bestimmt magisch, denn wann immer " |
| 184 | "Du den Deckel oeffnest oder schliesst oder Gegenstaende hineinlegst " |
| 185 | "oder herausnimmst, leuchten die Runen hell auf.")); |
| 186 | AD(({"metall"}), |
| 187 | BS("Was das wohl fuer ein Metall sein mag? Zweifellos hat es auch was " |
| 188 | "mit Magie zu tun.")); |
| 189 | AD(({"magie"}), |
| 190 | BS("In dieser Truhe scheint viel Magie zu stecken, wenn selbst ein " |
| 191 | "Weltuntergang ihr nichts anhaben kann.")); |
| 192 | AD(({"arbeit","fertigung"}), |
| 193 | BS("Die Fertigung dieser Truhe muss sehr aufwendig gewesen sein. " |
| 194 | "Kein Wunder, dass die Truhe so teuer ist.")); |
| 195 | AD(({"wunder"}), |
| 196 | BS("Ein Wunder scheint es zu sein.")); |
| 197 | AD(({"weltuntergang","armageddon"}), |
| 198 | BS("Dir schaudert beim Gedanken an den Weltuntergang.")); |
| 199 | AD(({"gedanken"}), |
| 200 | BS("Denk doch lieber an was anderes...")); |
| 201 | |
| 202 | AddCmd("deponier|deponiere&@PRESENT","cmd_deponiere", |
| 203 | "Was moechtest Du in der Eichenholztruhe deponieren?"); |
| 204 | AddCmd("entnimm|entnehme|entnehm","cmd_entnehmen"); |
| 205 | |
| 206 | // bei dieser Truhe waere das Erlauben voellig sinnlos. ;-) |
| 207 | RemoveCmd(({"serlaube"})); |
| 208 | |
| 209 | } |
| 210 | |
| 211 | // keine Truhen zerstoeren, die irgendeinen INhalt haben. |
| 212 | int zertruemmern(string str) { |
| 213 | // aus swift_std_container |
| 214 | string nf_str; |
| 215 | nf_str="Syntax: zertruemmer [Objekt-Id]\n" |
| 216 | +"Bsp.: zertruemmer "+QueryProp(P_IDS)[1]+"\n"; |
| 217 | notify_fail("Fehler: Ohne Parameter klappt das nicht.\n"+nf_str); |
| 218 | if(!str) return 0; |
| 219 | notify_fail("Fehler: Du musst eine gueltige Objekt-Id angeben!\n"+nf_str); |
| 220 | if(present(str)!=TO) // Ueberpruefe, ob auch dieses Objekt gemeint ist! |
| 221 | return 0; |
| 222 | if( QueryHausbesitzer() != QueryTP() && !QueryProp("test") ) |
| 223 | { |
| 224 | write( BS("Nur "+QueryHausbesitzer()+" darf "+name(WEN,1)+" zertruemmern!")); |
| 225 | return 1; |
| 226 | } |
| 227 | // Objekte enthalten? Wenn ja, abbruch. |
| 228 | if (sizeof(autoloader)) { |
| 229 | tell_object(PL,BS("Du willst gerade zum Schlag ausholen, um " |
| 230 | +name(WEN,1)+ " zu zertruemmern, als Dir einfaellt, dass " |
| 231 | +QueryPronoun(WER)+ " ja gar nicht leer ist! Nene, wer weiss, ob " |
| 232 | "Du das nicht noch brauchen koenntest.")); |
| 233 | return 1; |
| 234 | } |
| 235 | // sonst geerbten Kram ausfuehren. |
| 236 | return ::zertruemmern(str); |
| 237 | } |
| 238 | |
| 239 | // Zesstra, 1.7.07, fuers Hoerrohr |
| 240 | string GetOwner() {return "zesstra";} |
| 241 | |
| 242 | // Prueft das Objekt auf Eignung fuer die Truhe, speichert seine Daten und |
| 243 | // zerstoert es anschliessend. NODROP-Objekte koennen nur so in die Truhe |
| 244 | // gelegt werden, alle anderen koennen auch mit "stecke ... in truhe" |
| 245 | // deponiert werden, woraufhin ebenfalls PreventInsert() und NotifyInsert() |
| 246 | // durchlaufen werden. |
| 247 | protected int cmd_deponiere(string cmd, mixed args) { |
| 248 | if (!objectp(PL)) return 0; |
| 249 | |
| 250 | notify_fail(Name(WER,1)+" ist doch geschlossen!\n"); |
| 251 | if(QueryProp(P_CNT_STATUS)!=CNT_STATUS_OPEN) return 0; |
| 252 | |
| 253 | notify_fail("Was moechtest Du in der Eichenholztruhe deponieren?\n"); |
| 254 | if (!stringp(cmd) || !sizeof(cmd) |
| 255 | || !pointerp(args) || !sizeof(args)) return 0; |
| 256 | object ob=args[0]; |
| 257 | if (!objectp(ob)) return 0; |
| 258 | // wuerde die Truhe das Objekt ueberhaupt aufnehmen? Fehlerausgabe durch |
| 259 | // PrevenInsert() |
| 260 | if (PreventInsert(ob)) return 1; |
| 261 | // Ausziehen... Schade, dass DoUnwear nix vernuenftiges an Rueckgabewert |
| 262 | // hat. :-( |
| 263 | if (objectp(ob->QueryProp(P_WORN))) { |
| 264 | ob->DoUnwear(); |
| 265 | if (objectp(ob->QueryProp(P_WORN))) { |
| 266 | tell_object(PL, BS("Du musst "+ ob->name(WEN,1)+ "zunaechst einmal " |
| 267 | "ausziehen!")); |
| 268 | return 1; |
| 269 | } |
| 270 | } |
| 271 | // wegstecken |
| 272 | if (objectp(ob->QueryProp(P_WIELDED))) { |
| 273 | ob->DoUnwield(); |
| 274 | if (objectp(ob->QueryProp(P_WIELDED))) { |
| 275 | tell_object(PL, BS("Du musst "+ ob->name(WEN,1)+ "zunaechst einmal " |
| 276 | "wegstecken!")); |
| 277 | return 1; |
| 278 | } |
| 279 | } |
| 280 | // NO_CHECK und Silent-Bewegung, Meldungen an den Spieler selber machen. |
| 281 | tell_object(PL, BS("Du steckst "+ ob->name(WEN,1) + " in " + name(WEN,1) + |
| 282 | ".")); |
| 283 | |
| 284 | tell_room(environment(),BS(PL->Name(WER) + " legt " + ob->name(WEN,0) + |
| 285 | " in " + name(WEN,1) + " hinein."),({PL})); |
| 286 | ob->move(ME, M_NOCHECK|M_SILENT); |
| 287 | return 1; |
| 288 | } |
| 289 | |
| 290 | // alternative zum "nimm bla aus truhe". Spieler wollten was kurzes dafuer |
| 291 | // haben. |
| 292 | protected int cmd_entnehmen(string cmd) { |
| 293 | int res; |
| 294 | mixed noget; |
| 295 | |
| 296 | if (!objectp(PL)) return 0; |
| 297 | |
| 298 | notify_fail(Name(WER,1)+" ist doch geschlossen!\n"); |
| 299 | if(QueryProp(P_CNT_STATUS)!=CNT_STATUS_OPEN) return 0; |
| 300 | |
| 301 | notify_fail(BS("Was moechtest Du aus "+name(WEM,1)+ " entnehmen?\n")); |
| 302 | if (!stringp(cmd) || !sizeof(cmd)) return 0; |
| 303 | |
| 304 | object *obs=present_objects(cmd); |
| 305 | |
| 306 | if (!sizeof(obs) || !objectp(obs[0])) |
| 307 | return 0; |
| 308 | |
| 309 | // NOGET ist hier bloed. So ist es zwar auch nicht richtig doll... *seufz* |
| 310 | // Die hier ist/waere aber nen uebler Hack, erstmal auskommentiert lassen. |
| 311 | // also, P_NOGET sichern. |
| 312 | /*if (!closurep(noget=ob->Query(P_NOGET,F_QUERY_METHOD))) { |
| 313 | noget=ob->Query(P_NOGET,F_VALUE); |
| 314 | ob->Set(P_NOGET,0,F_VALUE); |
| 315 | } |
| 316 | else { |
| 317 | ob->Set(P_NOGET,0,F_QUERY_METHOD); |
| 318 | }*/ |
| 319 | // nehmen. |
| 320 | res=PL->pick_obj(obs[0]); |
| 321 | // P_NOGET zurueckschreiben. (Ja, wenn eine Closure als F_VALUE drinsteht, |
| 322 | // landet die jetzt als F_QUERY_METHOD im Objekt. |
| 323 | /*if (closurep(noget)) { |
| 324 | ob->Set(P_NOGET,noget,F_QUERY_METHOD); |
| 325 | } |
| 326 | else |
| 327 | ob->Set(P_NOGET,noget,F_VALUE); |
| 328 | */ |
| 329 | return(res); |
| 330 | } |
| 331 | |
| 332 | // Hier wird auch das PreventInsert() von der Blueprint gerufen. Das |
| 333 | // erleichtert es, die Liste an erlaubten Objekten zu aendern, ohne dass man |
| 334 | // alle Clones ersetzen muss. |
| 335 | varargs int PreventInsert(object ob) { |
| 336 | string oname; |
| 337 | // Das Objekt, was die Truhe gerade selber bewegt, wird ignoriert. |
| 338 | if (!objectp(ob) || ob_in_bewegung==ob) return 0; |
| 339 | |
| 340 | oname=BLUE_NAME(ob); |
| 341 | |
| 342 | // Pruefung in Clonen: |
| 343 | if (clonep(ME)) |
| 344 | { |
| 345 | // nur Eigentuemer |
| 346 | if (!stringp(uuid) || !sizeof(uuid)) { |
| 347 | if (objectp(PL)) |
| 348 | tell_object(PL,BS(sprintf("%s gehoert Dir nicht, daher kannst Du " |
| 349 | "auch keine Gegenstaende in %s legen.", |
| 350 | Name(WER,1),QueryPronoun(WEN)))); |
| 351 | return 1; |
| 352 | } |
| 353 | if (!objectp(PL) || getuuid(PL)!=uuid) { |
| 354 | if (objectp(PL)) |
| 355 | tell_object(PL,BS(sprintf("Nur %s darf Gegenstaende in %s " |
| 356 | "hineinlegen.",capitalize(explode(uuid,"_")[0]),name(WEN,1)))); |
| 357 | return 1; |
| 358 | } |
| 359 | // jedes Objekt nur einmal. |
| 360 | if (member(autoloader,oname)) { |
| 361 | if (objectp(PL)) |
| 362 | tell_object(PL,BS(Name(WER,1)+ " kann von einem Gegenstand jeweils " |
| 363 | "nur ein Exemplar aufnehmen, es ist aber bereits " |
| 364 | +ob->name(WER,0) + " in " + QueryPronoun(WEM) + ".")); |
| 365 | return 1; |
| 366 | } |
| 367 | // jetzt Erlaubnisliste der BP fragen. |
| 368 | if (objectp(blueprint(ME))) |
| 369 | return blueprint(ME)->PreventInsert(ob); |
| 370 | else |
| 371 | return load_object(load_name(ME))->PreventInsert(ob); |
| 372 | } |
| 373 | // Ende fuer Pruefung fuer Clone. |
| 374 | |
| 375 | // ab hier jetzt die Pruefung durch die BP. |
| 376 | // Keine (freigegebener) Autoloader? Hat in diesem Container nix verloren! |
| 377 | if( !ob->QueryProp(P_AUTOLOADOBJ) ) { |
| 378 | if (objectp(PL)) |
| 379 | tell_object(PL,BS("In "+name(WEN,1) |
| 380 | +" kannst Du nur Autoload-Objekte hineinlegen. ")); |
| 381 | return 1; |
| 382 | } |
| 383 | else if (member(blacklist,oname)) { |
| 384 | if (objectp(PL)) |
| 385 | tell_object(PL,BS("In "+name(WEN,1) |
| 386 | +" kannst Du nur dafuer erlaubte Autoload-Objekte hineinlegen. " |
| 387 | +ob->Name(WER,1) + " wurde explizit als nicht erwuenscht " |
| 388 | "befunden.")); |
| 389 | return 1; |
| 390 | } |
| 391 | else if (!member(whitelist,oname)) { |
| 392 | if (!member(vorschlaege,oname)) { |
| 393 | vorschlaege[oname,0]=ob->name(WER,0) || ""; |
| 394 | vorschlaege[oname,1]=ob->short() || ""; |
| 395 | } |
| 396 | if (objectp(PL)) |
| 397 | tell_object(PL,BS("In "+name(WEN,1) |
| 398 | +" kannst Du nur dafuer erlaubte Autoload-Objekte hineinlegen. " |
| 399 | +ob->Name(WER,1) + " ist momentan nicht auf der Liste. Der " |
| 400 | "Gegenstand wurde jetzt als Vorschlag gespeichert. Bitte hab " |
| 401 | "etwas Geduld, bis sich jemand den Gegenstand angeschaut hat.")); |
| 402 | // ggf. reset reaktivieren und Maintainer informieren. |
| 403 | if (!query_next_reset()) |
| 404 | set_next_reset(1); |
| 405 | return 1; |
| 406 | } |
| 407 | // getragenes? |
| 408 | if (ob->QueryProp(P_WORN)) { |
| 409 | ob->DoUnwear(0); |
| 410 | if (ob->QueryProp(P_WORN)) { //ARGL. GRUMMEL. |
| 411 | if (objectp(PL)) |
| 412 | tell_object(PL,BS("Willst Du "+ob->name(WEN,1) + " nicht erstmal " |
| 413 | "ausziehen?")); |
| 414 | return 1; |
| 415 | } |
| 416 | } |
| 417 | // enthaelt es irgendwelche anderen Objekte? |
| 418 | if (sizeof(all_inventory(ob))) { |
| 419 | if (objectp(PL)) |
| 420 | tell_object(PL,BS(ob->Name(WER,1) + " ist nicht leer.")); |
| 421 | return 1; |
| 422 | } |
| 423 | |
| 424 | // andere Einschraenkungen, als hier geprueft werden, gibt es nicht. |
| 425 | return 0; |
| 426 | } |
| 427 | |
| 428 | // hier ist das Objekt jetzt in der Truhe, d.h. Daten speichern und Objekt |
| 429 | // destructen. ;) |
| 430 | void NotifyInsert(object ob, object oldenv) { |
| 431 | |
| 432 | // Das Objekt, was die Truhe gerade selber bewegt, wird ignoriert. |
| 433 | if (!objectp(ob) || ob==ob_in_bewegung) |
| 434 | return; |
| 435 | STORELOG(sprintf("%s deponiert %s [%O], Daten: %O",getuid(PL),ob->name(WEN,0), |
| 436 | ob,ob->QueryProp(P_AUTOLOADOBJ))); |
| 437 | // noetig sind die IDs, den Namen und die AUTOLOADOBJ-Daten des Objekts. |
| 438 | // ;-) |
| 439 | autoloader[BLUE_NAME(ob),ALDATA]=ob->QueryProp(P_AUTOLOADOBJ); |
| 440 | autoloader[BLUE_NAME(ob),IDS]=ob->QueryProp(P_IDS); |
| 441 | // Objekte, die 0 als short liefern, kriegen eine Standard-Short und werden |
| 442 | // sichtbar gemacht, da sie sonst nicht wiederzufinden sind. Objekte, die |
| 443 | // unsichtbar sein sollen, duerfen nicht erlaubt werden. |
| 444 | // TODO eine ID als Short nehmen? |
| 445 | autoloader[BLUE_NAME(ob),NAME]=capitalize((ob->short()||"<Unbekannt>.\n")[..<3]); |
| 446 | // nach dem Move die realen Objekte destructen. |
| 447 | call_out(#'check_content, 0); |
| 448 | save_me(); |
| 449 | } |
| 450 | |
| 451 | // Objekt wurde entnommen, also aus der Liste der enthaltenen Autoloader |
| 452 | // loeschen. Ausserdem Objekt konfigurieren. Dies wird erst hier gemacht und |
| 453 | // nicht in create_object(), damit es so aehnlich wie moeglich zum clonen der |
| 454 | // Autoloader beim erstellen des Spielerobjektes wird (dort wird erst bewegt, |
| 455 | // dann konfiguriert). |
| 456 | void NotifyLeave(object ob, object dest) { |
| 457 | string error, oname; |
| 458 | |
| 459 | if (!objectp(ob)) |
| 460 | return; |
| 461 | |
| 462 | oname=BLUE_NAME(ob); |
| 463 | if (!member(autoloader,oname)) { |
| 464 | // Das sollte definitiv nicht passieren. |
| 465 | ERRLOG(sprintf("Gegenstand (%O) wurde entnommen, der nicht " |
| 466 | "gespeichert war!",ob)); |
| 467 | return; |
| 468 | } |
| 469 | |
| 470 | // wenn kein Fehler: Objekt aus Liste loeschen. Sonst wird das Objekt |
| 471 | // zerstoert. Damit bleiben die Autoloader-Daten hier erhalten und der |
| 472 | // Spieler hat kein disfunktionales Objekt im Inventar. |
| 473 | if (error) { |
| 474 | ERRLOG(sprintf("Fehler beim Konfigurieren von %O. Fehlermeldung: %O." |
| 475 | "Daten: %O",ob,error,autoloader[oname,ALDATA])); |
| 476 | ob->remove(1); |
| 477 | if (objectp(ob)) |
| 478 | destruct(ob); |
| 479 | } |
| 480 | else { |
| 481 | PICKLOG(sprintf("Objekt (%O) wurde entnommen.",ob)); |
| 482 | m_delete(autoloader,oname); |
| 483 | // speichern |
| 484 | save_me(); |
| 485 | } |
| 486 | } |
| 487 | |
| 488 | protected void check_content() { |
| 489 | // wenn Objekte noch in der Truhe sind, also nicht erfolgreich in |
| 490 | // einen Spieler bewegt wurden, werden zerstoert. Datenverlust gibt es |
| 491 | // hierbei nicht, weil die Daten der Autoloader nur durch NotifyLeave() |
| 492 | // geloescht werden. |
| 493 | foreach(object ob: all_inventory()) { |
| 494 | ob->remove(1); |
| 495 | if (objectp(ob)) destruct(ob); |
| 496 | } |
| 497 | } |
| 498 | |
| 499 | // hier nochmal schauen, ob das Objekt auch in den richtigen Spieler bewegt |
| 500 | // wird... Falls das move dann hier abgebrochen wird, wird das Objekt im |
| 501 | // naechsten HB von der Truhe zerstoert. (chk_contents()) |
| 502 | varargs int PreventLeave(object ob, mixed dest) { |
| 503 | object ob2; |
| 504 | |
| 505 | //DEBUG(sprintf("PreventLeave(): Ob: %O, Dest: %O (%O)", |
| 506 | // ob,dest,(objectp(dest)?"Objekt":"Non-Object"))); |
| 507 | |
| 508 | if (!objectp(ob)) return 0; |
| 509 | // falls string uebergeben, erstmal zug. Spieler finden. |
| 510 | if (stringp(dest) && sizeof(dest)) |
| 511 | dest=find_player(dest); |
| 512 | |
| 513 | // richtiges INteractive? Dann darf das Objekt raus. Sonst nicht. ;-) |
| 514 | if (!objectp(dest) || !interactive(dest) || getuuid(dest)!=uuid) |
| 515 | return 1; |
| 516 | |
| 517 | // pruefen, ob der Spieler schon ein Objekt dieser Blueprint dabei hat. Wenn |
| 518 | // ja, Abbruch, das koennte sonst zuviele Probleme geben. |
| 519 | if (objectp(ob2=present_clone(ob,dest))) { |
| 520 | tell_object(dest,BS("Du hast bereits "+ob2->name(WEN,0) + |
| 521 | " dabei. Zwei Gegenstaende dieser Art kannst du nicht gleichzeitig " |
| 522 | "mit Dir herumtragen.")); |
| 523 | return 1; //nicht rausnehmen. |
| 524 | } |
| 525 | return 0; |
| 526 | } |
| 527 | |
| 528 | // Objekte ausgeben, die hier angeblich drin sind. ;-) Gibt aber nur die |
| 529 | // Autoloader aus, keine echten Objekt, die Container sind. Allerdings sollte |
| 530 | // sowas eh nicht vorkommen. ;-) |
| 531 | // flags: 1 - return array, 2 - don't collect equal objects ' |
| 532 | // flags: 4 - don't append infos for wizards |
| 533 | varargs mixed make_invlist(object viewer, mixed inv, int flags) { |
| 534 | int iswiz; |
| 535 | mixed objs; |
| 536 | |
| 537 | iswiz = IS_LEARNER( viewer ) && viewer->QueryProp(P_WANTS_TO_LEARN); |
| 538 | // Mapping benutzen, um multiplen Overhead fuer allokation im foreach() zu |
| 539 | // vermeiden. |
| 540 | objs=m_allocate(sizeof(autoloader),1); |
| 541 | foreach(string oname, string *ids, string sh: autoloader) { |
| 542 | if (iswiz && !(flags & 4)) |
| 543 | objs[oname]=sh + ". ["+oname+"]"; |
| 544 | else |
| 545 | objs[oname]=sh + "."; |
| 546 | } |
| 547 | if(flags & 1) return(m_values(objs)-({""})); |
| 548 | if(!sizeof(autoloader)) return ""; |
| 549 | return sprintf("%"+(sizeof(objs) > 6 ? "#" : "=")+"-78s", |
| 550 | implode(m_values(objs)-({""}), "\n")) + "\n"; |
| 551 | } |
| 552 | |
| 553 | // erzeugt das benannte Objekt und liefert es zurueck. Liefert 0 im Fehlerfall. |
| 554 | // ausserdem bewegt es das Objekt in die Truhe, damit es ein Env hat und die |
| 555 | // Truhe via NotifyLeave() mitkriegt, dass es tatsaechlich entnommen wurde. |
| 556 | private object create_object(string oname) { |
| 557 | string error; |
| 558 | object ob; |
| 559 | mixed noget; |
| 560 | if (!member(autoloader,oname)) return 0; |
| 561 | |
| 562 | //Blueprint finden (ja, das ist nicht unbedingt noetig, man koennte auch |
| 563 | //direkt clonen) |
| 564 | if (error=catch(ob=load_object(oname);publish) || |
| 565 | !objectp(ob)) { |
| 566 | ERRLOG(sprintf("Konnte %s nicht laden/finden. Fehler: %O", |
| 567 | oname,error)); |
| 568 | return 0; |
| 569 | } |
| 570 | // clonen |
| 571 | if (error=catch(ob=clone_object(oname);publish) || |
| 572 | !objectp(ob)) { |
| 573 | ERRLOG(sprintf("Konnte %s nicht clonen. Fehler: %O", |
| 574 | oname,error)); |
| 575 | return 0; |
| 576 | } |
| 577 | // konfigurieren |
| 578 | error=catch(ob->SetProp(P_AUTOLOADOBJ,autoloader[oname,ALDATA]);publish); |
| 579 | |
| 580 | //Objekt bewegen, dabei Objekt in glob. Var. merken, damit PreventInsert() |
| 581 | //und NotifyInsert() es ignorieren. *seufz* |
| 582 | ob_in_bewegung=ob; |
| 583 | ob->move(ME,M_NOCHECK); |
| 584 | ob_in_bewegung=0; |
| 585 | |
| 586 | // jetzt noch nen Callout starten, damit das Objekt zerstoert wird, wenn es |
| 587 | // nicht wirklich in einen Spieler bewegt wird. |
| 588 | call_out(#'check_content,1); |
| 589 | |
| 590 | return(ob); |
| 591 | } |
| 592 | |
| 593 | // Schauen, ob die truhe ein Objekt mit passender ID enthaelt. Wenn |
| 594 | // ja, das Objekt erzeugen und zurueckliefern. |
| 595 | // Diese Funktion hat eine Reihe von Nachteilen bzw. Defiziten ggue. der |
| 596 | // normalerweise in Containern definierten Funktion: |
| 597 | // - Nur das erste Objekt, auf das id passt. Ich hab erstmal keine Lust, |
| 598 | // hier mehrere Objekte zu erzeugen. Mal schauen, ob es so geht. Auch waere |
| 599 | // es ein Problem, wenn viele Objekt die Evalgrenze bzw. nicht alle in den |
| 600 | // Spieler bewegt werden, nachdem sie erzeugt wurden. |
| 601 | // - keine komplexen Ausdruecke, nur reine IDs. |
| 602 | // Ich halte den Aufwand fuer nicht gerechtfertigt. |
| 603 | object *present_objects( string complex_desc ) { |
| 604 | object ob; |
| 605 | if (!stringp(complex_desc) || !sizeof(complex_desc)) |
| 606 | return ({}); |
| 607 | // diese Funktion liefert nur Objete zurueck, wenn der richtige Interactive |
| 608 | // versucht, sie zu entnehmen. ;-) |
| 609 | if (!objectp(this_interactive()) || |
| 610 | getuuid(this_interactive())!=uuid) |
| 611 | return ({}); |
| 612 | |
| 613 | // "alles" liefert das erstbeste Objekt. |
| 614 | if (complex_desc=="alles" && sizeof(autoloader)) |
| 615 | { |
| 616 | string oname=m_indices(autoloader)[0]; |
| 617 | ob=create_object(oname); |
| 618 | if (objectp(ob)) return ({ob}); |
| 619 | } |
| 620 | |
| 621 | // ueber alle Eintraege gehen, bis eine ID stimmt, erstes passendes Objekt |
| 622 | // erzeugen und in einem Array zurueckliefern. |
| 623 | foreach(string oname, string *ids: autoloader) { |
| 624 | if (member(ids,complex_desc)==-1) continue; |
| 625 | ob=create_object(oname); |
| 626 | break; //objekt gefunden, fertig hier |
| 627 | } |
| 628 | if (objectp(ob)) return ({ob}); |
| 629 | return ({}); // nix gefunden |
| 630 | } |
| 631 | |
| 632 | |
| 633 | |
| 634 | // ******************* Verwaltung ********************************* |
| 635 | |
| 636 | // registriert die Truhe auf den jeweiligen Eigentuemer. |
| 637 | protected void SetBesitzer(string unused, string newuuid) { |
| 638 | if (!stringp(newuuid) || !sizeof(newuuid)) return; |
| 639 | // wenn schon registriert, abbrechen |
| 640 | if (stringp(uuid) && sizeof(uuid)) return; |
| 641 | |
| 642 | uuid=newuuid; |
| 643 | Set(H_FURNITURE,uuid,F_VALUE); //Setmethode umgehen, sonst Rekursion |
| 644 | // ab jetzt nur noch von der Truhe selber. |
| 645 | Set(H_FURNITURE,SECURED,F_MODE_AS); |
| 646 | |
| 647 | // Daten fuer den Benutzer aus der Blueprint holen (BP liefert KEINE Kopie |
| 648 | // und es darf KEINE gemacht werden!): |
| 649 | autoloader=(mapping)load_name()->GetData(uuid); |
| 650 | |
| 651 | // keine Daten gekriegt? -> Fehler loggen |
| 652 | if (!mappingp(autoloader)) |
| 653 | { |
| 654 | ERRLOG(sprintf("Keine gueltigen Daten vom Truhenmaster (BP) erhalten. " |
| 655 | "initialisiere mit leerem Mapping. :-(")); |
| 656 | raise_error(sprintf( |
| 657 | "Keine gueltigen Daten vom Truhenmaster (BP) fuer UUID %s " |
| 658 | "erhalten.\n",uuid)); |
| 659 | } |
| 660 | } |
| 661 | |
| 662 | // Set-Funktion |
| 663 | string _set_h_furniture(mixed arg) { |
| 664 | if (stringp(arg)) |
| 665 | { |
| 666 | SetBesitzer(0,arg); // bricht ab, wenn bereits registriert. |
| 667 | } |
| 668 | return(uuid); |
| 669 | } |
| 670 | |
| 671 | // Falls das Speichern in der BP nicht klappte, rufen die Clones diese |
| 672 | // Funktion. Schreiben der Daten in in Logfile zur Restaurieren per Hand. |
| 673 | private void EmergencyStore(int res) { |
| 674 | ERRLOG(sprintf("EmergencyStore() called. Rueckgabewert des " |
| 675 | "Truhenmaster (BP) war: %O. Speichere Daten in Logfile. ",res)); |
| 676 | write_file(__DIR__+"ALTRUHE.NOTFALLDATEN", |
| 677 | sprintf("Daten fuer %O:\n%O\n",uuid,autoloader)); |
| 678 | } |
| 679 | |
| 680 | protected void save_me() { |
| 681 | int res; |
| 682 | // nur BP speichern |
| 683 | if (!clonep(ME)) |
| 684 | save_object(SAVEFILE); |
| 685 | else |
| 686 | { |
| 687 | if (objectp(blueprint(ME))) |
| 688 | res=(int)blueprint(ME)->StoreData(uuid,autoloader); |
| 689 | else |
| 690 | res=(int)load_object(load_name(ME))->StoreData(uuid,autoloader); |
| 691 | |
| 692 | if (res!=1) |
| 693 | EmergencyStore(res); // Daten in einem Notfall-Logfile ablegen. |
| 694 | } |
| 695 | } |
| 696 | |
| 697 | |
| 698 | // diese Funktion wird vom Seherhausraum gerufen, sobald ein rebootfestes |
| 699 | // Moebelstueck erzeugt und konfiguriert wurde. |
| 700 | void post_create() { |
| 701 | if (!clonep()) return; |
| 702 | |
| 703 | // wenn jetzt kein Env: destructen |
| 704 | if (!objectp(environment())) { |
| 705 | remove(1); |
| 706 | return; |
| 707 | } |
| 708 | //beim Schrankmaster registrieren |
| 709 | SCHRANKMASTER->RegisterCnt(ME, QueryProp("cnt_version_std") |
| 710 | +":"+QueryProp("cnt_version_obj"), environment()->QueryOwner(), |
| 711 | environment()); |
| 712 | } |
| 713 | |
| 714 | // diese Funktion wird vom Schrankmaster gerufen, wenn dieser meint, dass |
| 715 | // dieses Objekt neu erstellt werden sollte. |
| 716 | int UpdateMe() |
| 717 | { |
| 718 | if (!clonep()) |
| 719 | return 0; |
| 720 | if (!objectp(environment())) |
| 721 | return 1; |
| 722 | object ob=clone_object(load_name(ME)); |
| 723 | if (objectp(ob)) { |
| 724 | object oldenv=environment(); |
| 725 | // UUID uebertragen |
| 726 | ob->SetProp(H_FURNITURE, uuid); |
| 727 | // hierhier bewegen, dabei werden UUID und Daten von der neuen Truhe meist |
| 728 | // automatisch geholt. |
| 729 | ob->move(oldenv,M_NOCHECK); |
| 730 | // jetzt erst post_create() rufen! |
| 731 | ob->post_create(); |
| 732 | // dieses Objekt rausbewegen (damit das Seherhaus es austraegt). |
| 733 | move("/room/void",M_NOCHECK); |
| 734 | // Seherhausraum speichern (koennte teuer sein!) |
| 735 | oldenv->Save(1); |
| 736 | // selbstzerstoeren |
| 737 | // __INT_MAX__ bedeutet: nicht speichern, die neue Truhe hat die daten |
| 738 | // schon aus der BP abgefragt. |
| 739 | remove(__INT_MAX__); |
| 740 | } |
| 741 | return(1); |
| 742 | } |
| 743 | |
| 744 | // bei Selbstzerstoerung speichern bzw. Daten an die Blueprint uebermitteln |
| 745 | // und beim Schrankmaster abmelden. |
| 746 | varargs int remove(int silent) { |
| 747 | string uid=""; |
| 748 | |
| 749 | // Blueprint speichern im Savefile, Clones uebertragen die Daten hier an die |
| 750 | // Blueprint. Clones nur, wenn nicht __INT_MAX__ uebergeben wurde. |
| 751 | if (silent!=__INT_MAX__ || !clonep()) |
| 752 | save_me(); |
| 753 | |
| 754 | if (clonep()) { |
| 755 | // Clone melden sich beim Schrankmaster ab. |
| 756 | if (objectp(environment())) { |
| 757 | uid=environment()->QueryOwner(); |
| 758 | } |
| 759 | //beim Schrankmaster deregistrieren |
| 760 | SCHRANKMASTER->RemoveCnt(ME,uid); |
| 761 | } |
| 762 | return(::remove(silent)); |
| 763 | } |
| 764 | |
| 765 | // ***************** NUR BLUEPRINTS ********************************* |
| 766 | |
| 767 | // neuen Autoloader zulassen (nur EM+!) |
| 768 | varargs int AddAutoloader(string path,string nam) { |
| 769 | object ob; |
| 770 | if (clonep(ME)) return 0; |
| 771 | if (!stringp(path) || !sizeof(path)) return -1; |
| 772 | if (!ACCESS) return -2; |
| 773 | //if (!ARCH_SECURITY) return -2; |
| 774 | if (member(whitelist,path)) return -3; |
| 775 | if (catch(ob=load_object(path);publish) |
| 776 | || !objectp(ob)) |
| 777 | return -4; |
| 778 | // wenn Name nicht angegeben und auch nicht aus BP ermittelbar: Abbruch. |
| 779 | if (!stringp(nam) || !sizeof(nam)) { |
| 780 | nam=ob->name(WER,0); |
| 781 | if (!stringp(nam) || !sizeof(nam)) return -5; |
| 782 | } |
| 783 | ITEMLOG(sprintf("%s erlaubt: %s (%s)\n",getuid(this_interactive()), |
| 784 | path,nam)); |
| 785 | whitelist+=([path:capitalize(nam)]); |
| 786 | if (member(vorschlaege,path)) |
| 787 | m_delete(vorschlaege,path); |
| 788 | save_me(); |
| 789 | return(1); |
| 790 | } |
| 791 | |
| 792 | // Autoloader aus Erlaubnisliste entfernen (nur EM+!) |
| 793 | int RemoveAutoloader(string path) { |
| 794 | if (clonep(ME)) return 0; |
| 795 | if (!stringp(path) || !sizeof(path)) return -1; |
| 796 | if (!ACCESS) return -2; |
| 797 | //if (!ARCH_SECURITY) return -2; |
| 798 | if (!member(whitelist,path)) return -3; |
| 799 | ITEMLOG(sprintf("%s widerruft Erlaubnis: %s (%s)\n",getuid(this_interactive()), |
| 800 | path,whitelist[path])); |
| 801 | whitelist-=([path]); |
| 802 | save_me(); |
| 803 | return(1); |
| 804 | } |
| 805 | |
| 806 | // erlaubte Autoloader abfragen |
| 807 | mapping QueryAutoloader() { |
| 808 | return(copy(whitelist)); |
| 809 | } |
| 810 | |
| 811 | // neuen Autoloader in Blacklist eintragen (nur EM+!) |
| 812 | varargs int AddBlacklist(string path, string nam) { |
| 813 | object ob; |
| 814 | if (clonep(ME)) return 0; |
| 815 | if (!stringp(path) || !sizeof(path)) return -1; |
| 816 | if (!ACCESS) return -2; |
| 817 | //if (!ARCH_SECURITY) return -2; |
| 818 | |
| 819 | if (member(blacklist,path)) return -3; |
| 820 | |
| 821 | if (catch(ob=load_object(path);publish) |
| 822 | || !objectp(ob)) |
| 823 | return -4; |
| 824 | // wenn Name nicht angegeben und auch nicht aus BP ermittelbar: Abbruch. |
| 825 | if (!stringp(nam) || !sizeof(nam)) { |
| 826 | nam=ob->name(WER,0); |
| 827 | if (!stringp(nam) || !sizeof(nam)) return -5; |
| 828 | } |
| 829 | // ggf. erlaubten entfernen. |
| 830 | if (member(whitelist,path)) |
| 831 | RemoveAutoloader(path); |
| 832 | ITEMLOG(sprintf("%s verbietet: %s (%s)\n",getuid(this_interactive()), |
| 833 | path,nam)); |
| 834 | |
| 835 | blacklist+=([path:capitalize(nam)]); |
| 836 | |
| 837 | if (member(vorschlaege,path)) |
| 838 | m_delete(vorschlaege,path); |
| 839 | |
| 840 | save_me(); |
| 841 | return(1); |
| 842 | } |
| 843 | |
| 844 | // Autoloader aus Blacklist entfernen (nur EM+!) |
| 845 | int RemoveBlacklist(string path) { |
| 846 | if (clonep(ME)) return 0; |
| 847 | if (!stringp(path) || !sizeof(path)) return -1; |
| 848 | if (!ACCESS) return -2; |
| 849 | //if (!ARCH_SECURITY) return -2; |
| 850 | if (member(blacklist,path)==-1) return -3; |
| 851 | ITEMLOG(sprintf("%s loescht: %s (%s) von Blacklist\n",getuid(this_interactive()), |
| 852 | path,blacklist[path])); |
| 853 | blacklist-=([path]); |
| 854 | save_me(); |
| 855 | return(1); |
| 856 | } |
| 857 | |
| 858 | // gesperrte Autoloader abfragen |
| 859 | mapping QueryBlacklist() { |
| 860 | return(copy(blacklist)); |
| 861 | } |
| 862 | |
| 863 | // vorschlaege abfragen |
| 864 | varargs mixed QueryVorschlaege(int format) { |
| 865 | string res="\n"; |
| 866 | if (!format) return(copy(vorschlaege)); |
| 867 | |
| 868 | foreach(string oname, string nam, string sh: vorschlaege) { |
| 869 | res+=sprintf("%.78s:\n %.37s,%.37s\n",oname,nam,sh); |
| 870 | } |
| 871 | |
| 872 | if (format==2 && objectp(PL)) |
| 873 | tell_object(PL,res); |
| 874 | else |
| 875 | return res; |
| 876 | return 0; |
| 877 | } |
| 878 | |
| 879 | // Wird diese funktion in der Blueprint gerufen, liefert sie die Daten fuer |
| 880 | // eine Truhe mit dieser UUID zurueck. Aber nur dann, wenn die auch von einer |
| 881 | // truhe abgerufen wird und keinem beliebigen anderen Objekt oder wenn ein EM |
| 882 | // abfragt. |
| 883 | mapping GetData(string uid) { |
| 884 | if (clonep(ME)) return 0; |
| 885 | if (extern_call()) |
| 886 | { |
| 887 | if (!objectp(previous_object())) return 0; |
| 888 | if (blueprint(previous_object()) != ME |
| 889 | && load_name(previous_object()) != __FILE__[..<3] |
| 890 | && !ACCESS) |
| 891 | return(0); |
| 892 | } |
| 893 | if (!stringp(uid)) return ([]); |
| 894 | |
| 895 | if (!member(data, uid)) |
| 896 | data[uid] = m_allocate(1,3); |
| 897 | |
| 898 | // Absichtlich keine Kopie, damit die Truhen (falls jemand mehrere kauft) |
| 899 | // sich alle eine Kopie des Mappings teilen. |
| 900 | return data[uid]; |
| 901 | } |
| 902 | |
| 903 | // Loest die Speicherung der Daten im Savefile aus, denn irgendwelche Daten |
| 904 | // haben sich in einem Clone geaendert, welche noch auf die Platte muessen. |
| 905 | // Diese Funktion speicherte frueher Daten aus den Clones wieder im Mapping |
| 906 | // des Masters (der Blueprint). Dies ist heute nicht mehr so, weil alle Truhen |
| 907 | // (eines Benutzers) sich data[uid] teilen. Daher wird hier ein Fehler |
| 908 | // ausgeloest, wenn es von einer Truhe ein Mapping kriegt, welches nicht |
| 909 | // identisch (!) mit dem data[uid] ist. |
| 910 | // liefert 0 im Fehlerfall! |
| 911 | int StoreData(string uid, mapping tmp) { |
| 912 | |
| 913 | if (clonep(ME)) return 0; |
| 914 | |
| 915 | // Aber nur dann, wenn die auch von einer truhe abgerufen wird und keinem |
| 916 | // beliebigen anderen Objekt oder wenn ein EM setzt. |
| 917 | if (extern_call()) |
| 918 | { |
| 919 | if (!objectp(previous_object())) |
| 920 | return 0; |
| 921 | if (blueprint(previous_object()) != ME |
| 922 | && load_name(previous_object()) != __FILE__[..<3] |
| 923 | && !ACCESS) |
| 924 | return 0; |
| 925 | } |
| 926 | if (!stringp(uid) || !mappingp(tmp)) |
| 927 | return(0); |
| 928 | |
| 929 | // tmp muss auf _dasselbe_ Mapping zeigen wie data[uid]. Wenn das nicht der |
| 930 | // Fall ist, ist was schiefgelaufen. Jedenfalls wird dann hier nen Fehler |
| 931 | // ausgeloest. |
| 932 | if (tmp != data[uid]) |
| 933 | { |
| 934 | // if(program_time(previous_object()) < 1400525694) |
| 935 | // data[uid]=tmp; |
| 936 | // else |
| 937 | raise_error("StoreData() gerufen und Daten sind nicht identisch " |
| 938 | "mit den bereits bekannten.\n"); |
| 939 | } |
| 940 | |
| 941 | // Absichtlich keine Kopie, damit sich alle Truhen das Mapping teilen. |
| 942 | //data[uid]=tmp; |
| 943 | |
| 944 | // Savefile muss natuerlich geschrieben werden, fuer den naechsten Reboot. |
| 945 | if (find_call_out(#'save_me)==-1) |
| 946 | call_out(#'save_me,10); // Speichervorgaenge ggf. sammeln (upd -ar ...) |
| 947 | return(1); |
| 948 | } |
| 949 | |
| 950 | // Maintainer ueber Truhenvorschlaege informieren |
| 951 | void reset() { |
| 952 | |
| 953 | if (clonep() || !sizeof(vorschlaege)) { |
| 954 | // ohne Vorschlaege ist auch kein reset noetig. |
| 955 | set_next_reset(-1); |
| 956 | return; |
| 957 | } |
| 958 | set_next_reset(12000); // alle 3-4h reicht. |
| 959 | foreach(string uid: MAINTAINER) { |
| 960 | object pl=find_player(uid); |
| 961 | if (objectp(pl) && query_idle(pl) < 1800) |
| 962 | tell_object(pl,BS("Es gibt neue Objektvorschlaege fuer die " |
| 963 | "Autoloadertruhe. Bitt schau da doch bei Gelegenheit mal drueber.")); |
| 964 | } |
| 965 | } |
| 966 | |
| 967 | |
| 968 | // ************************************************************************* |
| 969 | |
| 970 | // **************** SONSTIGES ********************************************** |
| 971 | |
| 972 | // *seufz* |
| 973 | // secure_level() aus der simul_efun ist hier momentan nicht brauchbar, weil |
| 974 | // dort auch p/seher/moebel/autoloadertruhe in der Callerkette steht und das |
| 975 | // ein levle von 0 hat. *seufz* |
| 976 | nomask private int my_secure_level() { |
| 977 | int *level; |
| 978 | //kette der Caller durchlaufen, den niedrigsten Level in der Kette |
| 979 | //zurueckgeben. Zerstoerte Objekte (Selbstzerstoerer) fuehren zur Rueckgabe |
| 980 | //von 0. |
| 981 | //caller_stack(1) fuegt dem Rueckgabearray this_interactive() hinzu bzw. 0, |
| 982 | //wenn es keinen Interactive gibt. Die 0 fuehrt dann wie bei zerstoerten |
| 983 | //Objekten zur Rueckgabe von 0, was gewuenscht ist, da es hier einen |
| 984 | //INteractive geben muss. |
| 985 | level=map(caller_stack(1),function int (object caller) |
| 986 | {if (objectp(caller)) |
| 987 | return(query_wiz_level(geteuid(caller))); |
| 988 | return(0); // kein Objekt da, 0. |
| 989 | } ); |
| 990 | return(min(level)); //den kleinsten Wert im Array zurueckgeben (ggf. 0) |
| 991 | } |
| 992 | |
| 993 | |
| 994 | // debugkram |
| 995 | mixed _query_content() { |
| 996 | //deep_copy, damit nicht jemand einfach so an den Daten rumbasteln kann. |
| 997 | return(deep_copy(autoloader)); |
| 998 | } |
| 999 | |
| 1000 | mixed _query_owner() { |
| 1001 | return(uuid); |
| 1002 | } |
| 1003 | |
| 1004 | int DeleteData(string uid) { |
| 1005 | if (clonep(ME)) return 0; |
| 1006 | if (!stringp(uid) || !sizeof(uid)) return -1; |
| 1007 | if (!ACCESS) return -2; |
| 1008 | //if (!ARCH_SECURITY) return -2; |
| 1009 | m_delete(data,uid); |
| 1010 | save_me(); |
| 1011 | return(1); |
| 1012 | } |
| 1013 | |
| 1014 | mixed testfun() {return "bin da\n";} |
| 1015 | |