blob: cc8030241894f03195d479e4b006f63cb0220859 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001#pragma strict_types
2#pragma no_clone
3#pragma no_shadow
4#pragma no_inherit
5#pragma verbose_errors
6#pragma combine_strings
7#pragma rtt_checks
8#pragma pedantic
9#pragma warn_deprecated
10
11#include "/secure/config.h"
12#include "/secure/wizlevels.h"
13
14#define MAX_ROOMS_PER_LIST 10
15
16// die div. Speicherorte und Pfade
17#define SAVEFILE "/secure/ARCH/potions"
18#define TIPS(x) "/secure/ARCH/ZT/"+x
19#define ORAKEL "/room/orakel"
20#define POTIONTOOL "/obj/tools/ptool"
21
22// Fuer die Dump-Funktion
23#define POTIONDUMP "/secure/ARCH/POTIONS.dump"
24#define DUMP(str) write_file(POTIONDUMP, str)
25
26// Modifikationen loggen. "event" ist eins der Events aus der Liste:
27// ADD_POTION, ACTIVATE, DEACTIVATE, MODIFY_PATH, MODIFY_LISTNO
28#define LOGFILE_MOD "/log/ARCH/POTIONS_MOD.log"
29#define MODLOG(event,num,data) write_file(LOGFILE_MOD, \
30 sprintf("%17s %-14s %-3d sEUID %s %s\n", \
31 strftime("%Y-%b-%d %R"), event, num, secure_euid(), data) )
32
33// Indizierungs-Konstanten fuer das potions-Mapping
34#define POT_ROOMNAME 0
35#define POT_LISTNO 1
36
37// Konstanten fuer div. Rueckgabewerte. Keine 0, da das eine gueltige ZT-ID
38// sein kann und abfragende Objekte verwirren koennte.
39#define POT_IS_ACTIVE 1
40#define POT_ACCESS_DENIED -1
41#define POT_WRONG_DATATYPE -2
42#define POT_NO_SUCH_ROOM -3
43#define POT_ALREADY_REGISTERED -4
44#define POT_INVALID_POTION -5
45#define POT_NO_SUCH_FILE -6
46#define POT_INVALID_LIST_NUMBER -7
47#define POT_ALREADY_ACTIVE -8
48#define POT_ALREADY_INACTIVE -9
49#define POT_NOT_INACTIVE -10
50#define POT_NOT_ACTIVE -11
51
52// Zaehler fuer den als naechsten anzulegenden ZT
53private int nextroom;
54
55// Liste aller ZTs einschl. inaktive, ([ int num : string room; int list ])
56private mapping potions = ([]);
57
58// Liste der inaktiven ZTs, ({ int num })
59private int *inactive = ({});
60
61// Cache mit den einzelnen Listen, ([ int list : int *potionlist ])
62private nosave mapping lists;
63
64// reverse_table Lookup Cache, ([string room: int number])
65private nosave mapping reverse_table = ([]);
66
67// Cache fuer die bereits von der Platte eingelesenen ZTs, um Plattenzugriffe
68// insbesondere beim Erzeugen der Tipliste durch das Orakel zu reduzieren.
69private nosave mapping tipmap = ([]);
70
71int ActivateRoom(string room);
72
73private int secure() {
74 return (!process_call() && ARCH_SECURITY);
75}
76
77mixed QueryPotionData(int num) {
78 if ( !secure() )
79 return POT_ACCESS_DENIED;
80 return ([num : potions[num,0]; potions[num,1] ]);
81}
82
83int *QueryInactivePotions() {
84 return copy(inactive);
85}
86
87private void RebuildCache() {
88 // Cache invalidieren; vor-initialisiert zur Beschleunigung des Rebuilds.
89 lists = ([0:({}),1:({}),2:({}),3:({}),4:({}),5:({}),6:({}),7:({})]);
Arathorn001e9d72018-09-01 12:42:34 +020090 reverse_table = ([]);
MG Mud User88f12472016-06-24 23:31:02 +020091 foreach (int num, string room, int list : potions) {
Arathorna586b162018-09-01 12:43:11 +020092 m_add(reverse_table, room, num);
MG Mud User88f12472016-06-24 23:31:02 +020093 lists[list] += ({num});
94 }
95 return;
96}
97
Arathornf9158242019-09-12 20:10:25 +020098int QueryActive(int|string potion) {
MG Mud User88f12472016-06-24 23:31:02 +020099 if ( extern_call() && !secure() )
100 return POT_ACCESS_DENIED;
101 int ret;
102 // Wenn nach dem Pfad des ZTs gefragt wird, diesen zuerst in die Nummer
103 // umwandeln durch Lookup im reverse_table Cache
104 if ( stringp(potion) ) {
Arathornf9158242019-09-12 20:10:25 +0200105 // Erst nachschauen, ob der ZT in der Liste ist. Wenn man stattdessen
106 // direkt den Eintrag aus dem Mapping ausliest, wird 0 zurueckgegeben,
107 // wenn der Eintrag nicht darin enthalten ist. 0 ist aber ein gueltiger
108 // ZT, d.h. falls ein Raum einen ZT vergibt, dieser aber nicht im
109 // Master enthalten ist, wird der ZT 0 stattdessen gutgeschrieben.
110 if ( member(reverse_table, potion) )
111 potion = reverse_table[potion];
112 // Falls der ZT nicht bekannt ist, geben wir einen Fehlercode
113 // zurueck.
114 else
115 return POT_INVALID_POTION;
MG Mud User88f12472016-06-24 23:31:02 +0200116 }
117 // Ein ZT ist aktiv, wenn er in der Liste potions steht und nicht in der
118 // Liste der inaktiven ZTs (inactive) steht. Dann dessen Nummer
119 // zurueckgeben; inaktive zuerst pruefen, weil die inaktiven auch in
120 // "potions" enthalten sind und somit alle ZTs ausser den ungueltigen
121 // als aktiv gemeldet wuerden.
122 if ( member(inactive,potion)>-1 )
123 ret = POT_NOT_ACTIVE;
124 else if ( member(potions,potion) && potions[potion,POT_LISTNO]!=-1 )
125 ret = potion;
126 // ansonsten ist das kein gueltiger ZT
127 else
128 ret = POT_INVALID_POTION;
129 return ret;
130}
131
132private void save_info() {
133 save_object(SAVEFILE);
134}
135
136protected void create() {
137 seteuid(getuid(this_object()));
138 if ( !restore_object(SAVEFILE) ) {
139 // Fehler ausgeben, damit es jemand merkt. Dennoch wird jetzt im Anschluss
140 // der Cache neu aufgebaut (damit die Datenstrukturen gueltig sind).
141 catch(raise_error("Potionmaster: no/corrupt savefile! Reinitializing.\n"); publish);
142 }
143 RebuildCache();
144}
145
146int AddPotionRoom(string room, int list) {
147 if ( !secure() )
148 return POT_ACCESS_DENIED;
149 // Neuer Raum muss ein gueltiger String sein.
150 if ( !stringp(room) )
151 return POT_WRONG_DATATYPE;
152 if ( !intp(list) || list<0 || list>7 )
153 return POT_WRONG_DATATYPE;
154
Zesstra5cd26092018-11-08 22:21:21 +0100155 // Pfad normalisieren - Expansion von Platzhaltern ist hier ziemlich
156 // sinnloss und faellt daher weg (Neue ZTs in /players/ gibts eh nicht
157 // mehr.)
158 room=(string)master()->make_path_absolute(room);
MG Mud User88f12472016-06-24 23:31:02 +0200159
160 // Datei mit dem ZT-Spruch muss existieren.
161 if ( file_size( TIPS(to_string(nextroom)+".zt") ) < 0 ) {
162 raise_error("Potionmaster: Tipfile missing, please create "+
163 to_string(nextroom)+".zt");
164 return POT_NO_SUCH_FILE;
165 }
166 // Neuer Raum darf noch nicht in der Liste enthalten sein.
167 if ( member(m_values(potions,POT_ROOMNAME), room)!=-1)
168 return POT_ALREADY_REGISTERED;
169 // Neuer Raum muss ladbar sein.
170 if ( catch(load_object(room); publish) )
171 return POT_NO_SUCH_ROOM;
172
173 // Jetzt kann's endlich losgehen, Raum eintragen, nextroom hochzaehlen
Arathorna586b162018-09-01 12:43:11 +0200174 m_add(potions, nextroom, room, list);
MG Mud User88f12472016-06-24 23:31:02 +0200175 MODLOG("ADD_POTION", nextroom, room);
176 // Neu eingetragene ZTs werden auch gleich aktiviert; ActivateRoom()
177 // baut den Cache selbst neu auf, daher kann das hier entfallen.
178 ActivateRoom(room);
179 nextroom++;
180 save_info();
181 return nextroom;
182}
183
184int ChangeRoomPath(string old, string new) {
185 if ( !secure() )
186 return POT_ACCESS_DENIED;
187
188 // beide Pfade muessen gueltige Strings sein
189 if ( !stringp(old) || !stringp(new) )
190 return POT_WRONG_DATATYPE;
191
Zesstra5cd26092018-11-08 22:21:21 +0100192 // Pfad normalisieren - Expansion von Platzhaltern ist hier ziemlich
193 // sinnloss und faellt daher weg (Neue ZTs in /players/ gibts eh nicht
194 // mehr.)
195 old=(string)master()->make_path_absolute(old);
196 new=(string)master()->make_path_absolute(new);
MG Mud User88f12472016-06-24 23:31:02 +0200197
198 // Der neue Raum darf nicht bereits eingetragen sein, ...
199 if ( member(reverse_table,new) )
200 return POT_ALREADY_REGISTERED;
201 // ... und der alte Raum muss noch eingetragen sein.
202 if ( !member(reverse_table,old) )
203 return POT_NO_SUCH_ROOM;
204 // Neuer Raum muss ladbar sein.
205 if (catch(load_object(new);publish))
206 return POT_NO_SUCH_ROOM;
207
Arathornf9158242019-09-12 20:10:25 +0200208 // Aktuelle ZT-Nummer des alten Pfades ermitteln.
MG Mud User88f12472016-06-24 23:31:02 +0200209 int num = reverse_table[old];
Arathornf9158242019-09-12 20:10:25 +0200210
MG Mud User88f12472016-06-24 23:31:02 +0200211 // Pfad aendern, Cache neubauen und Savefile speichern
212 potions[num,POT_ROOMNAME] = new;
213 RebuildCache();
214 save_info();
215 MODLOG("MODIFY_PATH", num, old+" => "+new);
216 return num;
217}
218
219int ActivateRoom(string room) {
220 if ( !secure() )
221 return POT_ACCESS_DENIED;
222 // Aktuelle ZT-Nummer ermitteln. Etwas umstaendlich, da im Fehlerfall -1
223 // benoetigt wird.
224 int num = member(reverse_table,room) ? reverse_table[room] : -1;
225 // Nummer muss existieren
226 if ( num == -1 )
227 return POT_INVALID_POTION;
228 // ZT ist nicht inaktiv, dann kann man ihn auch nicht aktivieren.
229 if ( member(inactive, num)==-1 )
230 return POT_ALREADY_ACTIVE;
231 inactive -= ({num});
232 RebuildCache();
233 save_info();
234 MODLOG("ACTIVATE", num, room);
235 return num;
236}
237
238int SetListNr(string room, int list) {
239 if ( !secure() )
240 return POT_ACCESS_DENIED;
241 // Aktuelle ZT-Nummer ermitteln. Etwa umstaendlich, da im Fehlerfall -1
242 // benoetigt wird.
243 int num = member(reverse_table,room) ? reverse_table[room] : -1;
244 // Nummer muss existieren
245 if ( num == -1 )
246 return POT_INVALID_POTION;
247 // Listennummer muss zwischen 0 und 7 liegen.
248 if ( list < 0 || list > 7 )
249 return POT_INVALID_LIST_NUMBER;
250
251 // alte Nummer aufschreiben zum Loggen.
252 int oldlist = potions[num,POT_LISTNO];
253 // Listennummer in der ZT-Liste aktualisieren.
254 potions[num,POT_LISTNO] = list;
255 RebuildCache();
256 save_info();
257 MODLOG("MODIFY_LISTNO", num, oldlist+" -> "+list);
258 return num;
259}
260
261int DeactivateRoom(string room) {
262 if ( !secure() )
263 return POT_ACCESS_DENIED;
264 // Aktuelle ZT-Nummer ermitteln. Etwa umstaendlich, da im Fehlerfall -1
265 // benoetigt wird.
266 int num = member(reverse_table,room) ? reverse_table[room] : -1;
267 // Nummer muss existieren
268 if ( num == -1 )
269 return POT_INVALID_POTION;
270 // ZT darf nicht bereits inaktiv sein
271 if ( member(inactive,num)>-1 )
272 return POT_ALREADY_INACTIVE;
273 inactive += ({num});
274 RebuildCache();
275 save_info();
276 MODLOG("DEACTIVATE", num, room);
277 return num;
278}
279
280private int *_create_list(int listno, int anz) {
281 int *list = ({});
282 // Listenerzeugung lohnt nur dann, wenn mind. 1 Eintrag gefordert wird und
283 // die Listennummer im gueltigen Bereich zwischen 0 und 7 ist.
284 if ( anz>0 && listno>=0 && listno<=7 ) {
285 int *tmp = lists[listno] - inactive;
286 // Wenn die Listengroesse maximal genauso gross ist wie die angeforderte
287 // Anzahl, kann diese vollstaendig uebernommen werden.
288 if ( sizeof(tmp) <= anz ) {
289 list = tmp;
290 } else { // ansonsten soviele Eintraege erzeugen wie angefordert
291 foreach(int i: anz) {
292 int j=random(sizeof(tmp));
293 list += ({tmp[j]});
294 tmp -= ({tmp[j]});
295 }
296 }
297 }
298 return list;
299}
300
301mixed *InitialList() {
302 mixed *list=({});
303 foreach(int i : 8)
304 list+=_create_list(i,MAX_ROOMS_PER_LIST);
305 return list;
306}
307
308// Aufrufe aus den Spielershells und dem Potiontool sind erlaubt
309int HasPotion(object room) {
Arathornf9158242019-09-12 20:10:25 +0200310 if ( !query_once_interactive(previous_object()) &&
MG Mud User88f12472016-06-24 23:31:02 +0200311 load_name(previous_object()) != POTIONTOOL )
312 return POT_ACCESS_DENIED;
Arathornf9158242019-09-12 20:10:25 +0200313
314 // Erst nachschauen, ob der ZT in der Liste ist. Wenn man stattdessen
315 // direkt den Eintrag aus dem Mapping ausliest, wird 0 zurueckgegeben,
316 // wenn der Eintrag nicht darin enthalten ist. 0 ist aber ein gueltiger
317 // ZT, und der darf nur rauskommen, wenn er tatsaechlich gemeint ist,
318 // nicht als Default bei allen unbekannten Raeumen.
319 if ( objectp(room) && member(reverse_table, object_name(room)) )
320 return reverse_table[object_name(room)];
321 else
322 return POT_NO_SUCH_ROOM;
MG Mud User88f12472016-06-24 23:31:02 +0200323}
324
325// Listennummer ermitteln, in der der ZT num enthalten ist.
326// Auch inaktive ZTs werden als zu einer Liste gehoerig gemeldet.
327int GetListByNumber(int num) {
328 return member(potions,num) ? potions[num,POT_LISTNO] : POT_INVALID_POTION;
329}
330
331// Listennummer ermitteln, in der der inaktive ZT num enthalten ist.
332// Da alle Zaubertraenke in einer Gesamtliste enthalten sind, kann direkt das
333// Resultat von GetListByNumber() zurueckgegeben werden.
334int GetInactListByNumber(int num) {
335 if ( member(inactive,num) > -1 )
336 return GetListByNumber(num);
337 else
338 return POT_NOT_INACTIVE;
339}
340
341// Wird nur von /obj/tools/ptool aufgerufen. Wenn der Aufruf zugelassen wird,
342// erfolgt von dort aus ein ChangeRoomPath(), und dort wird bereits geloggt.
343// Erzmagier duerfen auch aufrufen.
344mixed GetFilenameByNumber(int num) {
345 if ( extern_call() &&
346 object_name(previous_object()) != POTIONTOOL &&
347 !ARCH_SECURITY )
348 return POT_ACCESS_DENIED;
349 if ( !member(potions, num) )
350 return POT_INVALID_POTION;
351 return potions[num,POT_ROOMNAME];
352}
353
354// Wird vom Spielerobjekt gerufen; uebergeben werden der Raum, der initial
355// FindPotion() aufrief, die ZT-Liste des Spielers sowie die Liste bereits
356// gefundener ZTs.
357//
358// In std/player/potion.c ist sichergestellt, dass room ein Objekt ist und
359// dass die Listen als Int-Arrays uebergeben werden.
360//
361// Es werden aus historischen Gruenden (noch) beide ZT-Listen uebergeben,
362// aber es muss nur knownlist ueberprueft werden, da diese eine Teilmenge
363// von potionlist ist und somit jeder ZT in ersterer auf jeden Fall auch
364// in letzterer enthalten sein _muss_.
365int InList(object room, int *potionlist, int *knownlist) {
366 if ( !query_once_interactive(previous_object()) && !secure() )
367 return 0; //POT_ACCESS_DENIED;
368 int num = QueryActive(object_name(room));
369
370 // Zunaechst keinen Fehlercode zurueckgeben, weil das Spielerobjekt
371 // damit im Moment noch nicht umgehen kann.
372 if ( num < 0 )
373 return 0; //POT_INVALID_POTION;
374
375 return (member(knownlist,num)>-1);
376}
377
378// Wird vom Spielerobjekt gerufen, um einen gefundenen ZT aus dessen ZT-
379// Listen austragen zu lassen. Das Spielerobjekt stellt sicher, dass room
380// ein Objekt ist, und dass [known_]potionrooms Arrays sind.
381//
382// ACHTUNG! Sowohl potionrooms, als auch known_potionrooms sind die
383// Originaldaten aus dem Spielerobjekt, die hier ALS REFERENZ
384// uebergeben werden! Vorsicht bei Aenderungen an der Funktion!
385//
386// Wenn std/player/potions.c geaendert wird, ist diese Funktion obsolet
387// => ggf. komplett rauswerfen. Dann kann auch der Fehlercode in InList()
388// reaktiviert und deren Parameter korrigiert werden
389void RemoveList(object room, int* potionrooms, int* known_potionrooms) {
390 // ZT ist aktiv, das wurde bereits in InList() geprueft, das vor dem
391 // Aufruf von RemoveList() aus dem Spielerobjekt gerufen wird. Daher reicht
392 // es aus, die ZT-Nummer aus dem reverse_table Lookup zu holen.
Arathornf9158242019-09-12 20:10:25 +0200393 // Wenn der Pfad allerdings nicht gelistet ist, muss abgebrochen werden.
394 // Direktes Auslesen ist unguenstig, denn wenn <old> nicht enthalten ist,
395 // kommt als Default 0 zurueck, aber die Nummer 0 ist ein gueltiger ZT,
396 // die darf aber nur rauskommen, wenn wirklich der ZT 0 gemeint ist.
397 int num;
398 if ( member(reverse_table, object_name(room)) )
399 num = reverse_table[object_name(room)];
400 else
401 return;
402
MG Mud User88f12472016-06-24 23:31:02 +0200403 int tmp = member(potionrooms, num);
404 potionrooms[tmp] = -1;
405 tmp = member(known_potionrooms, num);
406 known_potionrooms[tmp] = -1;
407 return;
408}
409
410#define LISTHEADER "################## Liste %d ################## (%d)\n\n"
411#define INACT_HEADER "################## Inaktiv ################## (%d)\n\n"
412
413int DumpList() {
414 if ( !secure() )
415 return POT_ACCESS_DENIED;
416 // Zuerst die Caches neu aufbauen, um sicherzustellen, dass die Listen
417 // aktuell sind.
418 RebuildCache();
419 // Dumpfile loeschen
420 rm(POTIONDUMP);
421 // Alle Listen der Reihe nach ablaufen. Es wird in jedem Schleifendurchlauf
422 // einmal auf die Platte geschrieben. Das ist Absicht, weil es speicher-
423 // technisch sehr aufwendig waere, die Ausgabedaten stattdessen erst in
424 // einer Variablen zu sammeln und dann wegzuschreiben.
425 foreach(int *listno : sort_array(m_indices(lists),#'>)) {
426 // Zuerst den Header der ensprechenden Liste schreiben.
427 DUMP(sprintf(LISTHEADER, listno, sizeof(lists[listno])));
428 // Dann alle Potions der Liste durchgehen
429 foreach(int potion : lists[listno]) {
430 // Wenn der ZT inaktiv ist, ueberspringen wir den.
431 if ( member(inactive,potion)>-1 )
432 continue;
433 // Raumpfad aus der Gesamtliste holen.
434 string str = potions[potion,POT_ROOMNAME];
435 // Wenn der nicht existiert, entsprechenden Hinweis dumpen, ansonsten
436 // den Raumnamen.
437 //ZZ: ich finde ja, wir sollten sicherstellen, dass das nicht mehr
438 //passiert. Ist das mit dem AddPotionRoom oben nicht schon so?
439 if ( !stringp(str) || !sizeof(str) )
440 str="KEIN RAUM ZUGEORDNET!!!";
441 DUMP(sprintf("%3d. %s\n", potion, str));
442 }
443 // 2 Leerzeilen zwischen jeder Gruppe einfuegen
444 DUMP("\n\n");
445 }
446 // Zum Schluss den Header der Inaktiv-Liste schreiben.
447 DUMP(sprintf(INACT_HEADER, sizeof(inactive)));
448 // Dann alle inaktiven Potions ablaufen
449 foreach(int i : inactive) {
450 //ZZ: sonst muesste man hier wohl auch auf den fehlenden Raum pruefen.
451 DUMP(sprintf("%3d. (Liste %d) %s\n", i, GetListByNumber(i),
452 potions[i,POT_ROOMNAME]));
453 }
454 return 1;
455}
456
457//ORAKEL-Routinen
458
459/* Aufbau eines Tips:
460
461 Tralala, lalala
462 Dideldadeldum
463 Huppsdiwupps
464 XXXXX
465 Noch ein zweiter Tip
466 Dingeldong
467 %%%%%
468
469 Die Prozentzeichen sind das Endezeichen, ab hier koennen eventuelle
470 Kommentare stehen. Die 5 X sind das Trennzeichen zwischen zwei Tips
471 zum selben ZT.
472*/
473
474// TIPLOG() derzeit unbenutzt
475//#define LOGFILE_READ "ARCH/POTIONS_TIP_READ.log"
476//#define TIPLOG(x) log_file(LOGFILE_READ, x)
477
478mixed TipLesen(int num) {
479 string *ret = tipmap[num];
480 //Funktion darf nur vom Orakel und EM+ gerufen werden.
481 if ( previous_object() != find_object(ORAKEL) && !secure() )
482 return POT_ACCESS_DENIED;
483 // Derzeit kein Log, da diese Informationen tendentiell eher
484 // uninteressant sind.
485 // Timestamp ist vom Format "2012-Okt-03 14:18"
486 /*TIPLOG(sprintf("%s ZT-Tip gelesen: %d von TP: %O, PO: %O, TI: %O\n",
487 strftime("%Y-%b-%d %R"), num, this_player(), previous_object(),
488 this_interactive()));*/
489
490 // ZT-Spruch ist bereits im Tip-Cache enthalten, dann direkt ausgeben.
491 if ( pointerp(ret) )
492 return ret;
493
494 // ZT-Spruch auf grundlegende syntaktische Korrektheit pruefen:
495 // explode() liefert ein Array mit 2 Elementen, wenn die Ende-Markierung
496 // vorhanden und somit das File diesbezueglich korrekt aufgebaut ist.
497 string *tip=explode( read_file(TIPS(num+".zt"))||"", "%%%%%" );
498 if (sizeof(tip) >= 2) {
499 // Der erste Eintrag in dem Array ist dann der Spruch. Wenn dieser
500 // die Trenn-Markierung enthaelt, entstehen hier 2 Hinweise, ansonsten
501 // bleibt es bei einem.
502 tipmap[num] = explode(tip[0], "XXXXX\n");
503 return tipmap[num];
504 }
505 return POT_NO_SUCH_FILE;
506}
507
508// Datenkonvertierung alte Alists => Mappings
509/*mapping ConvertData() {
510 //if ( !secure()) ) return;
511 // all_rooms ist eine Alist der Form ({ string *room, int *number })
512 // als 3. Eintrag schreiben wir ueberall -1 rein, das wird spaeter durch die
513 // Listennummer des betreffenden ZTs ersetzt und erlaubt einen einfachen
514 // Check auf Datenkonsistenz.
515 potions = mkmapping( all_rooms[1],
516 all_rooms[0],
517 allocate(sizeof(all_rooms[0]), -1) );
518 // Alle Listen ablaufen
519 foreach(int *list: active_rooms ) {
520 // Alle ZTs dieser Liste ablaufen und die entsprechende Listennummer in
521 // der neuen Datenstruktur setzen.
522 foreach(int num: list) {
523 potions[num,POT_LISTNO] = member(active_rooms,list);
524 }
525 }
526 // inactive_rooms ist eine Alist der gleichen Form. Die Schleife addiert
527 // einfach alle Eintraege darin auf, so dass ein Int-Array entsteht, das
528 // alle inaktiven ZT-Nummern enthaelt; das allerdings nur fuer Listen mit
529 // mindestens einem Element.
530 foreach(int *list : inactive_rooms ) {
531 if ( sizeof(list) ) {
532 inactive += list;
533 // Alle ZTs dieser Liste ablaufen und die entsprechende Listennummer in
534 // der neuen Datenstruktur setzen.
535 foreach(int num : list) {
536 potions[num,POT_LISTNO] = member(inactive_rooms,list);
537 }
538 }
539 // unify array
540 inactive = m_indices(mkmapping(inactive));
541 }
542 mapping invalid = ([ POT_INVALID_LIST_NUMBER : ({}) ]);
543 walk_mapping(potions, function void (int pnum, string path, int listno) {
544 if ( listno == -1 )
545 invalid[POT_INVALID_LIST_NUMBER] += ({pnum});
546 });
547 return sizeof(invalid[POT_INVALID_LIST_NUMBER]) ? invalid : potions;
548}*/
549