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