blob: 2be898f7037df58752996ac93bf91143036f27b1 [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.)
Vanion50652322020-03-10 21:13:25 +0100158 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");
MG Mud User88f12472016-06-24 23:31:02 +0200164 }
165 // Neuer Raum darf noch nicht in der Liste enthalten sein.
166 if ( member(m_values(potions,POT_ROOMNAME), room)!=-1)
167 return POT_ALREADY_REGISTERED;
168 // Neuer Raum muss ladbar sein.
169 if ( catch(load_object(room); publish) )
170 return POT_NO_SUCH_ROOM;
171
172 // Jetzt kann's endlich losgehen, Raum eintragen, nextroom hochzaehlen
Arathorna586b162018-09-01 12:43:11 +0200173 m_add(potions, nextroom, room, list);
MG Mud User88f12472016-06-24 23:31:02 +0200174 MODLOG("ADD_POTION", nextroom, room);
175 // Neu eingetragene ZTs werden auch gleich aktiviert; ActivateRoom()
176 // baut den Cache selbst neu auf, daher kann das hier entfallen.
177 ActivateRoom(room);
178 nextroom++;
179 save_info();
180 return nextroom;
181}
182
183int ChangeRoomPath(string old, string new) {
184 if ( !secure() )
185 return POT_ACCESS_DENIED;
186
187 // beide Pfade muessen gueltige Strings sein
188 if ( !stringp(old) || !stringp(new) )
189 return POT_WRONG_DATATYPE;
190
Zesstra5cd26092018-11-08 22:21:21 +0100191 // Pfad normalisieren - Expansion von Platzhaltern ist hier ziemlich
192 // sinnloss und faellt daher weg (Neue ZTs in /players/ gibts eh nicht
193 // mehr.)
Vanion50652322020-03-10 21:13:25 +0100194 old=({string})master()->make_path_absolute(old);
195 new=({string})master()->make_path_absolute(new);
MG Mud User88f12472016-06-24 23:31:02 +0200196
197 // Der neue Raum darf nicht bereits eingetragen sein, ...
198 if ( member(reverse_table,new) )
199 return POT_ALREADY_REGISTERED;
200 // ... und der alte Raum muss noch eingetragen sein.
201 if ( !member(reverse_table,old) )
202 return POT_NO_SUCH_ROOM;
203 // Neuer Raum muss ladbar sein.
204 if (catch(load_object(new);publish))
205 return POT_NO_SUCH_ROOM;
206
Arathornf9158242019-09-12 20:10:25 +0200207 // Aktuelle ZT-Nummer des alten Pfades ermitteln.
MG Mud User88f12472016-06-24 23:31:02 +0200208 int num = reverse_table[old];
Arathornf9158242019-09-12 20:10:25 +0200209
MG Mud User88f12472016-06-24 23:31:02 +0200210 // Pfad aendern, Cache neubauen und Savefile speichern
211 potions[num,POT_ROOMNAME] = new;
212 RebuildCache();
213 save_info();
214 MODLOG("MODIFY_PATH", num, old+" => "+new);
215 return num;
216}
217
218int ActivateRoom(string room) {
219 if ( !secure() )
220 return POT_ACCESS_DENIED;
221 // Aktuelle ZT-Nummer ermitteln. Etwas umstaendlich, da im Fehlerfall -1
222 // benoetigt wird.
223 int num = member(reverse_table,room) ? reverse_table[room] : -1;
224 // Nummer muss existieren
225 if ( num == -1 )
226 return POT_INVALID_POTION;
227 // ZT ist nicht inaktiv, dann kann man ihn auch nicht aktivieren.
228 if ( member(inactive, num)==-1 )
229 return POT_ALREADY_ACTIVE;
230 inactive -= ({num});
231 RebuildCache();
232 save_info();
233 MODLOG("ACTIVATE", num, room);
234 return num;
235}
236
237int SetListNr(string room, int list) {
238 if ( !secure() )
239 return POT_ACCESS_DENIED;
240 // Aktuelle ZT-Nummer ermitteln. Etwa umstaendlich, da im Fehlerfall -1
241 // benoetigt wird.
242 int num = member(reverse_table,room) ? reverse_table[room] : -1;
243 // Nummer muss existieren
244 if ( num == -1 )
245 return POT_INVALID_POTION;
246 // Listennummer muss zwischen 0 und 7 liegen.
247 if ( list < 0 || list > 7 )
248 return POT_INVALID_LIST_NUMBER;
249
250 // alte Nummer aufschreiben zum Loggen.
251 int oldlist = potions[num,POT_LISTNO];
252 // Listennummer in der ZT-Liste aktualisieren.
253 potions[num,POT_LISTNO] = list;
254 RebuildCache();
255 save_info();
256 MODLOG("MODIFY_LISTNO", num, oldlist+" -> "+list);
257 return num;
258}
259
260int DeactivateRoom(string room) {
261 if ( !secure() )
262 return POT_ACCESS_DENIED;
263 // Aktuelle ZT-Nummer ermitteln. Etwa umstaendlich, da im Fehlerfall -1
264 // benoetigt wird.
265 int num = member(reverse_table,room) ? reverse_table[room] : -1;
266 // Nummer muss existieren
267 if ( num == -1 )
268 return POT_INVALID_POTION;
269 // ZT darf nicht bereits inaktiv sein
270 if ( member(inactive,num)>-1 )
271 return POT_ALREADY_INACTIVE;
272 inactive += ({num});
273 RebuildCache();
274 save_info();
275 MODLOG("DEACTIVATE", num, room);
276 return num;
277}
278
279private int *_create_list(int listno, int anz) {
280 int *list = ({});
281 // Listenerzeugung lohnt nur dann, wenn mind. 1 Eintrag gefordert wird und
282 // die Listennummer im gueltigen Bereich zwischen 0 und 7 ist.
283 if ( anz>0 && listno>=0 && listno<=7 ) {
284 int *tmp = lists[listno] - inactive;
285 // Wenn die Listengroesse maximal genauso gross ist wie die angeforderte
286 // Anzahl, kann diese vollstaendig uebernommen werden.
287 if ( sizeof(tmp) <= anz ) {
288 list = tmp;
289 } else { // ansonsten soviele Eintraege erzeugen wie angefordert
290 foreach(int i: anz) {
291 int j=random(sizeof(tmp));
292 list += ({tmp[j]});
293 tmp -= ({tmp[j]});
294 }
295 }
296 }
297 return list;
298}
299
300mixed *InitialList() {
301 mixed *list=({});
302 foreach(int i : 8)
303 list+=_create_list(i,MAX_ROOMS_PER_LIST);
304 return list;
305}
306
307// Aufrufe aus den Spielershells und dem Potiontool sind erlaubt
308int HasPotion(object room) {
Arathornf9158242019-09-12 20:10:25 +0200309 if ( !query_once_interactive(previous_object()) &&
MG Mud User88f12472016-06-24 23:31:02 +0200310 load_name(previous_object()) != POTIONTOOL )
311 return POT_ACCESS_DENIED;
Arathornf9158242019-09-12 20:10:25 +0200312
313 // Erst nachschauen, ob der ZT in der Liste ist. Wenn man stattdessen
314 // direkt den Eintrag aus dem Mapping ausliest, wird 0 zurueckgegeben,
315 // wenn der Eintrag nicht darin enthalten ist. 0 ist aber ein gueltiger
316 // ZT, und der darf nur rauskommen, wenn er tatsaechlich gemeint ist,
317 // nicht als Default bei allen unbekannten Raeumen.
318 if ( objectp(room) && member(reverse_table, object_name(room)) )
319 return reverse_table[object_name(room)];
320 else
321 return POT_NO_SUCH_ROOM;
MG Mud User88f12472016-06-24 23:31:02 +0200322}
323
324// Listennummer ermitteln, in der der ZT num enthalten ist.
325// Auch inaktive ZTs werden als zu einer Liste gehoerig gemeldet.
326int GetListByNumber(int num) {
327 return member(potions,num) ? potions[num,POT_LISTNO] : POT_INVALID_POTION;
328}
329
330// Listennummer ermitteln, in der der inaktive ZT num enthalten ist.
331// Da alle Zaubertraenke in einer Gesamtliste enthalten sind, kann direkt das
332// Resultat von GetListByNumber() zurueckgegeben werden.
333int GetInactListByNumber(int num) {
334 if ( member(inactive,num) > -1 )
335 return GetListByNumber(num);
336 else
337 return POT_NOT_INACTIVE;
338}
339
340// Wird nur von /obj/tools/ptool aufgerufen. Wenn der Aufruf zugelassen wird,
341// erfolgt von dort aus ein ChangeRoomPath(), und dort wird bereits geloggt.
342// Erzmagier duerfen auch aufrufen.
343mixed GetFilenameByNumber(int num) {
344 if ( extern_call() &&
345 object_name(previous_object()) != POTIONTOOL &&
346 !ARCH_SECURITY )
347 return POT_ACCESS_DENIED;
348 if ( !member(potions, num) )
349 return POT_INVALID_POTION;
350 return potions[num,POT_ROOMNAME];
351}
352
353// Wird vom Spielerobjekt gerufen; uebergeben werden der Raum, der initial
354// FindPotion() aufrief, die ZT-Liste des Spielers sowie die Liste bereits
355// gefundener ZTs.
356//
357// In std/player/potion.c ist sichergestellt, dass room ein Objekt ist und
358// dass die Listen als Int-Arrays uebergeben werden.
359//
360// Es werden aus historischen Gruenden (noch) beide ZT-Listen uebergeben,
361// aber es muss nur knownlist ueberprueft werden, da diese eine Teilmenge
362// von potionlist ist und somit jeder ZT in ersterer auf jeden Fall auch
363// in letzterer enthalten sein _muss_.
364int InList(object room, int *potionlist, int *knownlist) {
365 if ( !query_once_interactive(previous_object()) && !secure() )
366 return 0; //POT_ACCESS_DENIED;
367 int num = QueryActive(object_name(room));
368
369 // Zunaechst keinen Fehlercode zurueckgeben, weil das Spielerobjekt
370 // damit im Moment noch nicht umgehen kann.
371 if ( num < 0 )
372 return 0; //POT_INVALID_POTION;
373
374 return (member(knownlist,num)>-1);
375}
376
377// Wird vom Spielerobjekt gerufen, um einen gefundenen ZT aus dessen ZT-
378// Listen austragen zu lassen. Das Spielerobjekt stellt sicher, dass room
379// ein Objekt ist, und dass [known_]potionrooms Arrays sind.
380//
381// ACHTUNG! Sowohl potionrooms, als auch known_potionrooms sind die
382// Originaldaten aus dem Spielerobjekt, die hier ALS REFERENZ
383// uebergeben werden! Vorsicht bei Aenderungen an der Funktion!
384//
385// Wenn std/player/potions.c geaendert wird, ist diese Funktion obsolet
386// => ggf. komplett rauswerfen. Dann kann auch der Fehlercode in InList()
387// reaktiviert und deren Parameter korrigiert werden
388void RemoveList(object room, int* potionrooms, int* known_potionrooms) {
389 // ZT ist aktiv, das wurde bereits in InList() geprueft, das vor dem
390 // Aufruf von RemoveList() aus dem Spielerobjekt gerufen wird. Daher reicht
391 // es aus, die ZT-Nummer aus dem reverse_table Lookup zu holen.
Arathornf9158242019-09-12 20:10:25 +0200392 // Wenn der Pfad allerdings nicht gelistet ist, muss abgebrochen werden.
393 // Direktes Auslesen ist unguenstig, denn wenn <old> nicht enthalten ist,
394 // kommt als Default 0 zurueck, aber die Nummer 0 ist ein gueltiger ZT,
395 // die darf aber nur rauskommen, wenn wirklich der ZT 0 gemeint ist.
396 int num;
397 if ( member(reverse_table, object_name(room)) )
398 num = reverse_table[object_name(room)];
399 else
400 return;
401
MG Mud User88f12472016-06-24 23:31:02 +0200402 int tmp = member(potionrooms, num);
403 potionrooms[tmp] = -1;
404 tmp = member(known_potionrooms, num);
405 known_potionrooms[tmp] = -1;
406 return;
407}
408
409#define LISTHEADER "################## Liste %d ################## (%d)\n\n"
410#define INACT_HEADER "################## Inaktiv ################## (%d)\n\n"
411
412int DumpList() {
413 if ( !secure() )
414 return POT_ACCESS_DENIED;
415 // Zuerst die Caches neu aufbauen, um sicherzustellen, dass die Listen
416 // aktuell sind.
417 RebuildCache();
418 // Dumpfile loeschen
419 rm(POTIONDUMP);
420 // Alle Listen der Reihe nach ablaufen. Es wird in jedem Schleifendurchlauf
421 // einmal auf die Platte geschrieben. Das ist Absicht, weil es speicher-
422 // technisch sehr aufwendig waere, die Ausgabedaten stattdessen erst in
423 // einer Variablen zu sammeln und dann wegzuschreiben.
424 foreach(int *listno : sort_array(m_indices(lists),#'>)) {
425 // Zuerst den Header der ensprechenden Liste schreiben.
426 DUMP(sprintf(LISTHEADER, listno, sizeof(lists[listno])));
427 // Dann alle Potions der Liste durchgehen
428 foreach(int potion : lists[listno]) {
429 // Wenn der ZT inaktiv ist, ueberspringen wir den.
430 if ( member(inactive,potion)>-1 )
431 continue;
432 // Raumpfad aus der Gesamtliste holen.
433 string str = potions[potion,POT_ROOMNAME];
434 // Wenn der nicht existiert, entsprechenden Hinweis dumpen, ansonsten
435 // den Raumnamen.
436 //ZZ: ich finde ja, wir sollten sicherstellen, dass das nicht mehr
437 //passiert. Ist das mit dem AddPotionRoom oben nicht schon so?
438 if ( !stringp(str) || !sizeof(str) )
439 str="KEIN RAUM ZUGEORDNET!!!";
440 DUMP(sprintf("%3d. %s\n", potion, str));
441 }
442 // 2 Leerzeilen zwischen jeder Gruppe einfuegen
443 DUMP("\n\n");
444 }
445 // Zum Schluss den Header der Inaktiv-Liste schreiben.
446 DUMP(sprintf(INACT_HEADER, sizeof(inactive)));
447 // Dann alle inaktiven Potions ablaufen
448 foreach(int i : inactive) {
449 //ZZ: sonst muesste man hier wohl auch auf den fehlenden Raum pruefen.
450 DUMP(sprintf("%3d. (Liste %d) %s\n", i, GetListByNumber(i),
451 potions[i,POT_ROOMNAME]));
452 }
453 return 1;
454}
455
456//ORAKEL-Routinen
457
458/* Aufbau eines Tips:
459
460 Tralala, lalala
461 Dideldadeldum
462 Huppsdiwupps
463 XXXXX
464 Noch ein zweiter Tip
465 Dingeldong
466 %%%%%
467
468 Die Prozentzeichen sind das Endezeichen, ab hier koennen eventuelle
469 Kommentare stehen. Die 5 X sind das Trennzeichen zwischen zwei Tips
470 zum selben ZT.
471*/
472
473// TIPLOG() derzeit unbenutzt
474//#define LOGFILE_READ "ARCH/POTIONS_TIP_READ.log"
475//#define TIPLOG(x) log_file(LOGFILE_READ, x)
476
477mixed TipLesen(int num) {
478 string *ret = tipmap[num];
479 //Funktion darf nur vom Orakel und EM+ gerufen werden.
480 if ( previous_object() != find_object(ORAKEL) && !secure() )
481 return POT_ACCESS_DENIED;
482 // Derzeit kein Log, da diese Informationen tendentiell eher
483 // uninteressant sind.
484 // Timestamp ist vom Format "2012-Okt-03 14:18"
485 /*TIPLOG(sprintf("%s ZT-Tip gelesen: %d von TP: %O, PO: %O, TI: %O\n",
486 strftime("%Y-%b-%d %R"), num, this_player(), previous_object(),
487 this_interactive()));*/
488
489 // ZT-Spruch ist bereits im Tip-Cache enthalten, dann direkt ausgeben.
490 if ( pointerp(ret) )
491 return ret;
492
493 // ZT-Spruch auf grundlegende syntaktische Korrektheit pruefen:
494 // explode() liefert ein Array mit 2 Elementen, wenn die Ende-Markierung
495 // vorhanden und somit das File diesbezueglich korrekt aufgebaut ist.
496 string *tip=explode( read_file(TIPS(num+".zt"))||"", "%%%%%" );
497 if (sizeof(tip) >= 2) {
498 // Der erste Eintrag in dem Array ist dann der Spruch. Wenn dieser
499 // die Trenn-Markierung enthaelt, entstehen hier 2 Hinweise, ansonsten
500 // bleibt es bei einem.
501 tipmap[num] = explode(tip[0], "XXXXX\n");
502 return tipmap[num];
503 }
504 return POT_NO_SUCH_FILE;
505}
506
507// Datenkonvertierung alte Alists => Mappings
508/*mapping ConvertData() {
509 //if ( !secure()) ) return;
510 // all_rooms ist eine Alist der Form ({ string *room, int *number })
511 // als 3. Eintrag schreiben wir ueberall -1 rein, das wird spaeter durch die
512 // Listennummer des betreffenden ZTs ersetzt und erlaubt einen einfachen
513 // Check auf Datenkonsistenz.
514 potions = mkmapping( all_rooms[1],
515 all_rooms[0],
516 allocate(sizeof(all_rooms[0]), -1) );
517 // Alle Listen ablaufen
518 foreach(int *list: active_rooms ) {
519 // Alle ZTs dieser Liste ablaufen und die entsprechende Listennummer in
520 // der neuen Datenstruktur setzen.
521 foreach(int num: list) {
522 potions[num,POT_LISTNO] = member(active_rooms,list);
523 }
524 }
525 // inactive_rooms ist eine Alist der gleichen Form. Die Schleife addiert
526 // einfach alle Eintraege darin auf, so dass ein Int-Array entsteht, das
527 // alle inaktiven ZT-Nummern enthaelt; das allerdings nur fuer Listen mit
528 // mindestens einem Element.
529 foreach(int *list : inactive_rooms ) {
530 if ( sizeof(list) ) {
531 inactive += list;
532 // Alle ZTs dieser Liste ablaufen und die entsprechende Listennummer in
533 // der neuen Datenstruktur setzen.
534 foreach(int num : list) {
535 potions[num,POT_LISTNO] = member(inactive_rooms,list);
536 }
537 }
538 // unify array
539 inactive = m_indices(mkmapping(inactive));
540 }
541 mapping invalid = ([ POT_INVALID_LIST_NUMBER : ({}) ]);
542 walk_mapping(potions, function void (int pnum, string path, int listno) {
543 if ( listno == -1 )
544 invalid[POT_INVALID_LIST_NUMBER] += ({pnum});
545 });
546 return sizeof(invalid[POT_INVALID_LIST_NUMBER]) ? invalid : potions;
547}*/
548