blob: 893ca515eed2587d7e7a6f3cd3eb33668dd9e3a0 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// losa.c -- Modul fuer Laden und Speichern der Hausdaten
2//
3// (c) 1995 Wargon@MorgenGrauen
4// 2006 Vanion@MorgenGrauen, fuer die rebootfesten Moebel
5// $Id: losa.c,v 1.1.1.1 2000/08/20 20:22:42 mud Exp $
6//
7#pragma strong_types,rtt_checks
8
9#define NEED_PROTOTYPES
10#include "../haus.h"
11#include <container.h>
12#include <thing/properties.h>
13#include <room/exits.h>
14#include <thing/description.h>
15#undef NEED_PROTOTYPES
16#include <properties.h>
17#include <wizlevels.h>
18#include <moving.h>
19
20static void start_reload_furniture();
21
22private int csaved;
23
24// Variablen zur Verwaltung der Moebel im Raum.
25mapping furniture;
26mapping broken_furniture;
27
28protected void
29create()
30{
31 Set(H_CHEST, SAVE, F_MODE);
32 Set(H_CHEST, 0);
33
34 Set(H_FURNITURE, SAVE, F_MODE);
35 Set(H_FURNITURE, 0);
36
37// Set(H_SPECIAL, SAVE|SECURED, F_MODE);
38// Set(H_SPECIAL, ([:2]), F_VALUE);
39}
40
41/* Scheint nirgendwo benutzt zu werden...
42varargs int AddSpecial(int typ, string key, string extra)
43{
44 if (!this_interactive() || !IS_ARCH(this_interactive()) ||
45 !(PATH+"access_rights")->access_rights(geteuid(this_interactive()),""))
46 return -1;
47
48 if (typ != HS_EXIT && typ != HS_ITEM)
49 return 0;
50
51 Set(H_SPECIAL, Query(H_SPECIAL) + ([ key : typ; extra ]));
52 Save();
53 return 1;
54}
55
56void RemoveSpecial(string key)
57{
58 if (!this_interactive() || !IS_ARCH(this_interactive()) ||
59 !(PATH+"access_rights")->access_rights(geteuid(this_interactive()),""))
60 return;
61
62 Set(H_SPECIAL, m_delete(Query(H_SPECIAL), key));
63 Save();
64}
65*/
66
67void
68reset()
69{
70 if (QueryOwner() &&
71 !sizeof(filter(all_inventory(),#'interactive)) &&
72 !csaved)
73 Save(1);
74}
75
76// crunched komprimiert das Savefile
77varargs void
78Save(int crunched)
79{
80 mixed o1, o2, o3;
81 closure pc;
82 object *obs;
83 int i, found;
84
85 o3 = 0;
86
87 if (!(o1 = Query(P_DETAILS)))
88 Set(P_DETAILS, QueryProp(P_DETAILS), F_VALUE);
89
90 if (!(o2 = Query(P_READ_DETAILS)))
91 Set(P_READ_DETAILS, QueryProp(P_READ_DETAILS), F_VALUE);
92
93 if (csaved = crunched)
94 {
95 pc = symbol_function("PCrunch", VERWALTER);
96 Set(P_DETAILS, funcall(pc, Query(P_DETAILS)), F_VALUE);
97 Set(P_READ_DETAILS, funcall(pc, Query(P_READ_DETAILS)), F_VALUE);
98 o3 = Query(H_COMMANDS, F_VALUE);
99 Set(H_COMMANDS, funcall(pc, o3), F_VALUE);
100 }
101
102 // Autoload-Einrichtung identifizieren und speichern
103 // Code in Anlehnung an dem Autoload-Mechanismus fuer Spieler
104 furniture=([]);
105
106 // Alle Autoloader filtern
107 obs=filter_objects(all_inventory(this_object()), "QueryProp", H_FURNITURE);
108 found = 0;
109
110 // Ueber alle Moebel iteritieren
111 for( i=sizeof(obs)-1;i>=0;i--)
112 {
113 if( clonep(obs[i]))
114 {
115 if ( ++found <= MAX_FURNITURE_PER_ROOM )
116 furniture += ([ object_name(obs[i]):obs[i]->QueryProp(H_FURNITURE) ]);
117 }
118 }
119 if (found > MAX_FURNITURE_PER_ROOM)
120 {
121 tell_object(this_player(),
122 break_string("Du hast "+found+" Moebelstuecke im Raum stehen. "
123 "Gespeichert werden nur "+MAX_FURNITURE_PER_ROOM+". "
124 "Du solltest Dich von einigen Einrichtungsgegenstaenden "
125 "trennen.",78));
126
127 }
128 HDEBUG("Saving "+ sizeof (furniture) +" (plus "+sizeof(broken_furniture)+
129 " broken) objects in room "+
130 object_name(this_object()) + ".");
131
132 save_object( HAUSSAVEPATH+QueryOwner(1));
133
134 Set(P_DETAILS, o1, F_VALUE);
135 Set(P_READ_DETAILS, o2, F_VALUE);
136 if (o3)
137 Set(H_COMMANDS, o3, F_VALUE);
138}
139
140void
141Load()
142{
143 mixed prop;
144 int i;
145
146 restore_object( HAUSSAVEPATH+QueryOwner(1));
147
148 // Details und Kommandos werden beim Speichern de-dupliziert und in einem
149 // speziellen Format abgespeichert (s. PCrunch() im Hausverwalter). Sie
150 // muessen nach dem Laden durch die entsprechenden Add...()-Aufrufe
151 // wieder eingetragen werden.
152 prop=Query(P_DETAILS, F_VALUE);
153 RemoveDetail(0);
154 if (pointerp(prop))
155 {
156 foreach(<string*|string>* item : prop)
157 AddDetail(item[0], item[1]);
158 }
159 else if (mappingp(prop))
160 {
161 foreach(string key, mixed val : prop)
162 AddDetail(key, val);
163 }
164 else
165 SetProp(P_DETAILS, prop);
166
167 prop = Query(P_READ_DETAILS, F_VALUE);
168 RemoveReadDetail(0);
169 if (pointerp(prop))
170 {
171 foreach(<string*|string>* item : prop)
172 AddDetail(item[0], item[1]);
173 }
174 else if (mappingp(prop))
175 {
176 foreach(string key, mixed val : prop)
177 AddReadDetail(key, val);
178 }
179 else
180 SetProp(P_READ_DETAILS, prop);
181
182 prop = Query(P_EXITS, F_VALUE);
183 RemoveExitNoCheck(0);
184 if (mappingp(prop))
185 {
186 if (widthof(prop) <= 1)
187 {
188 foreach(string key, string dest : prop)
189 AddExitNoCheck(key, dest);
190 }
191 else
192 {
193 foreach(string key, string dest, string msg : prop)
194 {
195 if (stringp(msg))
196 _AddExit(key, dest, msg);
197 else if (stringp(dest) && strstr(dest,"#") != -1)
198 AddExitNoCheck(key, dest);
199 else
200 _AddExit(key, dest, 0);
201 }
202 }
203 }
204
205 prop=Query(H_COMMANDS, F_VALUE);
206 if (pointerp(prop))
207 {
208 Set(H_COMMANDS, ([]), F_VALUE);
209 for (i=sizeof(prop)-1; i>=0; i--)
210 this_object()->AddUserCmd(prop[i][0], 0, prop[i][1], prop[i][2]);
211 }
212
213 if (environment())
214 environment()->SetProp(P_NEVER_CLEAN, 1);
215
216 if (previous_object() && object_name(previous_object())==VERWALTER)
217 {
218 if (Query(H_CHEST))
219 this_object()->AddItem(PATH+"truhe",REFRESH_NONE,
220 ([ "owner" : QueryOwner() ]));
221/* Das scheint nirgendwo benutzt zu werden und in allen Seherhaeusern leer zu
222 * sein.
223 mapping special = Query(H_SPECIAL, F_VALUE);
224 if (special)
225 {
226 foreach(string key, int type, string extra : special)
227 {
228 switch(type)
229 {
230 case HS_ITEM:
231 AddItem(SPECIALPATH + extra, REFRESH_DESTRUCT);
232 break;
233 case HS_EXIT:
234 AddExitNoCheck(key, extra);
235 break;
236 }
237 }
238 }
239*/
240 }
241
242 // Das Laden der Autoloader wird erst am Ende angestossen.
243 // Dann ist es nicht schlimm, wenn alle Eval Ticks verbraucht werden.
244 start_reload_furniture();
245}
246
247// Mehrere Save-Anforderungen zusammenfassen.
248static void queued_save()
249{
250 HDEBUG("QS");
251 while (remove_call_out("Save")!=-1);
252 call_out("Save",3);
253}
254
255static int reload_error(string file, mixed data, string message)
256{
257 HDEBUG(message);
258 broken_furniture+=([file:data]);
259 log_file("seher/haeuser/autoloader_error",
260 dtime(time())+"\n"+
261 break_string(object_name(this_object())+" ("+QueryOwner(1)+")",78, " FILE: ",1)+
262 break_string(message, 78, " MSG: ",1)+
263 break_string(sprintf("%O", data),78, " DATA: ",1)+"\n");
264
265 return 0; // 0 fuer das filter, damit dieser Eintrag
266 // aus furniture geloescht wird.
267}
268
269// Laedt ein einzelnes Moebelstuecks
270static int load_furniture_object( string file, mixed data )
271{
272 object ob;
273 string error;
274 string blueprint;
275 closure pc;
276 // mixed data;
277
278 // Wenn genug Ticks frei sind, wird versucht, das Objekt zu erzeugen.
279 // Ansonsten ist die Gefahr zu gross, dass ein Erzeugungs-Prozess abbricht.
280 if (get_eval_cost() < 500000)
281 {
282 // HDEBUG("Suspending Object: "+file+". Only "+to_string(get_eval_cost())+" ticks left.");
283 return 1; // 1 bedeutet, dass dieser Eintrag es im Mapping bleibt.
284 }
285
286 // HDEBUG("Processing Object: "+file+" with Data: "+sprintf("%O",data)+".");
287
288 // Nummern der Clones sind beim Speichern noetig, um die Identitaeten
289 // der Objekte zu bestimmen (mehrere Objekte vom gleichen Blueprint
290 // speichern). Hier braucht man sie nicht mehr
291
292 blueprint = explode(file,"#")[0];
293
294 // Data aus dem Mapping holen
295 // data=furniture[file];
296
297 // Muss ich die Blueprint suchen?
298 ob = find_object(file);
299
300 // Nein.
301 if (!ob)
302 {
303 // Existiert die BP oder ein VC fuers File?
304 if (file_size(blueprint+".c")<0&&
305 file_size(implode(explode(blueprint,"/")[0..<2],"/")+
306 "/virtual_compiler.c")<0)
307 {
308 return reload_error(file, data, "Error in file: "+ file +
309 ". File does not exist.");
310
311 }
312
313 // File gefunden. Versuch, es zu laden.
314 if (error = catch(call_other( blueprint,"???")))
315 {
316 return reload_error(file, data, "Error loading file: "+file+". "+error);
317 }
318 }
319
320 // Clone erzeugen
321 if ( error = catch(ob = clone_object(blueprint)) )
322 {
323 return reload_error(file, data, "Error cloning object: "+file+". "+error);
324 }
325
326 HDEBUG(sprintf("%O",furniture));
327 // Autoload-Daten setzen
328 HDEBUG(object_name(ob)+"->SetProp("+sprintf("%O", data)+")");
329 if (ob)
330 catch(ob->SetProp( H_FURNITURE, data ));
331
332 // Furniture in das Seherhaus moven
333 if ( error = catch(ob->move( this_object(), M_NOCHECK )) ) {
334 ob->remove();
335 if(ob) destruct(ob);
336 return reload_error(file, data, "Error moving object: "+file+". "+error);
337 }
338
339 // post_create anstossen
340 pc=symbol_function("post_create", ob);
341 if (closurep(pc))
342 call_out(pc, 1);
343
344 return 0; // 0 bedeutet hier, dieses Objekt nicht noch einmal anstossen.
345}
346
347static void load_furniture()
348{
349 int i;
350 string rv;
351 string current_key;
352
353 // Abbruchbedingung ist, dass nichts mehr zu laden ist.
354 if (sizeof(furniture)==0) return;
355
356 // Anstoßen des naechsten Durchlaufs, falls die Ticks nicht reichen.
357 while (remove_call_out(#'load_furniture) != -1);
358 call_out(#'load_furniture, 1);
359
360 // Laden aller Moebel anstoßen
361 furniture=filter(furniture, #'load_furniture_object);
362}
363
364// Diese Funktion bereitet das Reloaden der Einrichtung vor
365static void start_reload_furniture()
366{
367 // Wenn es keine Moebel gibt, ist das Laden beendet.
368 if (!mappingp(furniture)) return;
369 if (broken_furniture==0) broken_furniture=([]);
370
371 // Falls ein Key von furniture 0 ist, wird dieser geloescht.
372 m_delete(furniture,0);
373
374 // Laden des Furniture anstossen
375 load_furniture();
376}
377
378