blob: 5e59f20cf7876ba7a048ed1a5a5a94cadb1dd57e [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// death_room.c -- Der Todesraum
4//
5// $Id: death_room.c 9138 2015-02-03 21:46:56Z Zesstra $
6
7
8#pragma strict_types
9
10#include <defines.h>
11#include <properties.h>
12#include <moving.h>
13#include <language.h>
14#include <wizlevels.h>
15#include <daemon.h>
16#include <new_skills.h>
17
18inherit "/std/room";
19
20mixed *players;
21mapping msgCache;
22
23
24private void flush( int unusedOnly );
25private string expand( string table, int value );
26private string parseText( string msg, object pl );
27private void do_remove();
28private varargs mixed get_sequence( string str );
29void add_player( object pl );
30static int filter_ldfied( string str );
31public int SmartLog( string creat, string myname, string str, string date );
32public mixed hier_geblieben( mixed dest, int methods, string direction,
33 string textout, string textin );
34public void init()
35{
36 this_player()->move("/room/death/virtual/death_room_"+getuid(this_player()),
37 M_NOCHECK|M_SILENT|M_NO_SHOW);
38 return;
39}
40
41public void create()
42{
43 if (IS_CLONE(this_object())) return;
44 ::create();
45
46 players = ({});
47 flush(0);
48
49 SetProp( P_NAME, "Lars" );
50 SetProp( P_GENDER, MALE );
51 SetProp( P_ARTICLE, 0 );
52 SetProp( P_LIGHT,1 );
53 SetProp( P_NO_TPORT, NO_TPORT_OUT );
54 SetProp( P_LOG_FILE, "TOD/Todesraum" );
55 SetProp( P_INT_SHORT, "Arbeitszimmer des Todes" );
56 SetProp( P_INT_LONG, break_string(
57 "Ein dunkler Raum, erleuchtet von dunklem Licht, das sich der "
58 "Dunkelheit nicht so sehr zu widersetzen scheint, indem es "
59 "leuchtet, als dass es der dunkelste Punkt in einer weniger "
60 "dunklen Umgebung ist. Im seltsamen Licht erkennst Du einen "+
61 "zentral aufgestellten Schreibtisch, der mit Diagrammen und "
62 "Buechern bedeckt ist. Die Waende verschwinden hinter Regalen, "
63 "die gefuellt sind mit in Leder gebundenen, dunklen Waelzern, "
64 "von denen geheimnisvolle Runen leuchten.\nTod.", 78, 0, 1 ) );
65}
66
67
68public void reset()
69{
70 ::reset();
71 flush(1);
72}
73
74private void flush( int unusedOnly )
75{
76 string *mi;
77 int i;
78
79 if ( unusedOnly ){
80 if ( i = sizeof(mi = m_indices(msgCache)) ){
81 for ( ; i--; )
82 if ( msgCache[mi[i], 1] )
83 msgCache[mi[i], 1] = 0;
84 else
85 msgCache = m_copy_delete( msgCache, mi[i] );
86 }
87 }
88 else
89 msgCache = ([]);
90}
91
92
93private string expand( string table, int value )
94{
95 int sz, wert, i;
96 string *texte;
97
98 sz = sizeof( texte = explode( table, "##" ) - ({""}) );
99
100 for ( i = 0; i < sz; i++ )
101 if ( i%2 ){
102 sscanf( texte[i], "%d", wert );
103
104 if ( value < wert )
105 break;
106 }
107 else
108 table = texte[i];
109
110 return table;
111}
112
113
114#define TOS(s) s[<1]
115#define STOS(s) s[<2]
116#define PUSH(x,s) (s+= ({ x }))
117#define POP(s) (s=s[0..<2])
118
119// ziemlich vom htmld abgekupfert ;)
120private string
121parseText( string msg, object pl )
122{
123 string *words, *texte, *todo, *done;
124 int endFlag;
125
126 int sz = sizeof( words = regexplode(msg, "[<][^>]*[>]") );
127 todo = ({ });
128 done = ({""});
129
130 for ( int i=1; i<sz; i+=2 ){
131 string cmd = words[i][1..<2];
132 TOS(done) += words[i-1];
133
134 if ( cmd[0] == '/' ){
135 endFlag = 1;
136 cmd = cmd[1..];
137 }
138 else
139 endFlag = 0;
140
141 switch( cmd[0] ){
142 case 'A': /*** Alignment ersetzen ***/
143 if (!endFlag){
144 PUSH( cmd, todo );
145 PUSH( "", done );
146 }
147 else
148 if ( todo[<1] == "A" ){
149 STOS(done) += expand(TOS(done), (int) pl->QueryProp(P_ALIGN));
150 done = done[0..<2];
151 todo = todo[0..<2];
152 }
153 break;
154
155 case 'D': /*** Tode ersetzen ***/
156 if ( !endFlag ){
157 PUSH( cmd, todo );
158 PUSH( "", done );
159 }
160 else
161 if ( todo[<1] == "D" ){
162 STOS(done) += expand(TOS(done), (int) pl->QueryProp(P_DEADS));
163 POP(done);
164 POP(todo);
165 }
166 break;
167
168 case 'L': /*** Level ersetzen ***/
169 if ( !endFlag ){
170 PUSH( cmd, todo );
171 PUSH( "", done );
172 }
173 else
174 if ( todo[<1] == "L" ){
175 STOS(done) += expand(TOS(done), (int) pl->QueryProp(P_LEVEL));
176 POP(done);
177 POP(todo);
178 }
179 break;
180
181 case 'Z': /*** Zufall ersetzen ***/
182 if ( !endFlag ){
183 PUSH( cmd, todo );
184 PUSH( "", done );
185 }
186 else{
187 if ( todo[<1][0] == 'Z'){
188 int cnt, rnd, wert, sz2;
189
190 if ( !sscanf(todo[<1], "Z=%d", rnd) )
191 STOS(done) += "\n###\n### Syntax Error in <Z>!\n###\n\n";
192 else {
193 rnd = random(rnd);
194 sz2 = sizeof( texte = explode(TOS(done), "##") );
195 wert=0;
196 cnt=0;
197
198 for ( int k = 1; k < sz2; k += 2 ){
199 sscanf( texte[k], "%d", wert );
200 cnt += wert;
201 if ( rnd < cnt ) {
202 STOS(done) += texte[k+1];
203 break;
204 }
205 }
206 }
207 POP(done);
208 POP(todo);
209 }
210 }
211 break;
212
213 case 'G': /*** Gender ersetzen ***/
214 if ( !endFlag ){
215 PUSH( cmd, todo );
216 PUSH( "", done );
217 }
218 else{
219 if( sizeof( texte = regexplode(TOS(done), ":") ) == 3 )
220 STOS(done) += texte[2*((int) pl->QueryProp(P_GENDER)
221 == FEMALE)];
222 POP(done);
223 POP(todo);
224 }
225 break;
226
227 case 'R': /*** Rasse ersetzen ***/
228 if ( !endFlag ){
229 PUSH( cmd, todo );
230 PUSH( "", done );
231 }
232 else{
233 int race;
234
235 texte = regexplode( TOS(done), "\\|" );
236 race = 2 * (member( ({ "Mensch", "Elf", "Zwerg", "Hobbit",
237 "Feline", "Dunkelelf" }),
238 (string) pl->QueryProp(P_RACE) ) + 1);
239
240 if ( race >= sizeof(texte) )
241 race = 0;
242
243 STOS(done) += texte[race];
244 POP(done);
245 POP(todo);
246 }
247 break;
248
249 case 'n': /*** Name, normal geschrieben ***/
250 TOS(done) += (string) (pl->name(RAW));
251 break;
252
253 case 'N': /*** Name, in Grossbuchstaben ***/
254 TOS(done) += upperstring(pl->name(RAW));
255 break;
256 }
257 }
258 PUSH( words[<1], done );
259 return implode( done, "" );
260}
261
262
263public void heart_beat()
264{
265 for ( int j = sizeof(players); j--; )
266 if ( !objectp(players[j][0]) ||
267 environment(players[j][0]) !=
268 find_object("/room/death/virtual/death_room_"+getuid(players[j][0])) )
269 players[j] = 0;
270
271 players -= ({0});
272
273 if ( !sizeof(players) ) {
274 set_heart_beat(0);
275 return;
276 }
277
278 for ( int j = sizeof(players); j--; ) {
279 int nr;
280 string msg;
281
282 nr = ++players[j][1];
283
284 if ( mappingp(players[j][2]) )
285 msg = players[j][2][nr];
286 else
287 msg = 0;
288
289 if ( !msg )
290 msg = players[j][3][1][nr];
291
292 if ( msg )
293 tell_object( players[j][0], parseText( msg, players[j][0] ) );
294 }
295
296 do_remove();
297}
298
299private void
300do_remove()
301{
302 int res;
303 string prayroom;
304 object plobj, pl;
305
306 for ( int j = sizeof(players); j--; ){
307 if ( players[j][1] >= players[j][3][0]){
308 pl = players[j][0];
309 while ( plobj = present("\ndeath_mark", pl) )
310 plobj->remove();
311
312 if ( !(prayroom = (string) pl->QueryPrayRoom()) )
313 prayroom="/room/pray_room";
314
315 pl->Set( P_TMP_MOVE_HOOK, 0 );
316 pl->Set( P_NO_ATTACK, 0, F_QUERY_METHOD );
317 pl->Set( P_LAST_KILLER, 0 );
318 pl->Set( P_KILLER, 0 );
319 pl->Set( P_ENEMY_DEATH_SEQUENCE, 0 );
320 pl->Set( P_NEXT_DEATH_SEQUENCE, 0 );
321 pl->Set( P_POISON, 0, F_QUERY_METHOD );
322
323 if ( catch( res = (int) pl->move(prayroom, M_GO|M_SILENT|M_NOCHECK) )
324 || res < 1 )
325 pl->move( "/room/pray_room", M_GO|M_NOCHECK );
326
327 players[j] = 0;
328 }
329 }
330
331 players -= ({0});
332
333 if ( !sizeof(players) )
334 set_heart_beat(0);
335}
336
337private varargs mixed
338get_sequence( string str )
339{
340 string *sequences;
341 int i, len, cacheable;
342
343 if ( !stringp(str) || catch( len = file_size(str) ) || len <= 0 ){
344 sequences = get_dir( "/room/death/sequences/*" ) - ({ ".", "..", ".svn" });
345 str = "/room/death/sequences/" + sequences[random( sizeof(sequences) )];
346 }
347
348 if ( cacheable = ((sizeof(str) > 21) &&
349 (str[0..21] == "/room/death/sequences/")) ){
350 if ( member(msgCache, str) ){
351 msgCache[str, 1] = 1; // Touch it!
352 return ({ msgCache[str], str });
353 }
354 }
355
356 sequences = explode( read_file(str), "\n" );
357 sscanf( sequences[0], "%d", len );
358 string seq = implode( sequences[1..], "\n" );
359 sequences = regexplode( seq, "[0-9][0-9]*:" );
360 mapping m = ([]);
361
362 for ( i = 1; i < sizeof(sequences)-1; i += 2 )
363 m[(int) sequences[i]] = sequences[i+1];
364
365 if ( cacheable )
366 msgCache += ([ str: ({ len, m }); 1 ]);
367
368 return ({ ({ len, m }), str });
369}
370
371// Description: Adds a player to the list
372void add_player( object pl )
373{
374 int kart, kgen;
375 int escaped;
376 object kill_liv, kill_ob;
377 mixed dseq, act_seq, killer_name, killer_msg;
378
379 set_heart_beat(1);
380 kgen = MALE;
381
382 foreach(object prev : caller_stack(1)) {
383 if ( !objectp(prev) || prev == pl )
384 continue;
385
386 string fn = object_name(prev);
387
388 if ( fn[0..12] == "/secure/login" && !kill_liv ){
389 escaped = 1;
390 break;
391 }
392
393 if ( fn[0..7] == "/secure/" && fn[0..13] != "/secure/merlin" )
394 continue;
395
396 if ( fn[0..21] == "/room/death/death_mark" )
397 continue;
398
399 if ( living(prev) ){
400 kill_liv = prev; // Killer
401 break;
402 }
403
404 kill_ob = prev; // killendes Objekt
405 }
406
407 object pre = (object) pl->QueryProp(P_KILLER);
408 if ( objectp(pre) ) {
409 dseq = (mixed) pre->QueryProp(P_ENEMY_DEATH_SEQUENCE);
410
411 if( !(killer_name = (mixed) pre->QueryProp(P_KILL_NAME)) ){
412 killer_name = (mixed) pre->QueryProp(P_NAME);
413 kart = (int) pre->QueryProp(P_ARTICLE);
414 kgen = (int) pre->QueryProp(P_GENDER);
415 }
416
417 killer_msg = (mixed)pre->QueryProp(P_KILL_MSG);
418 }
419
420 if ( !killer_name && kill_liv && function_exists( "QueryProp", kill_liv ) ){
421 dseq = (mixed) kill_liv->QueryProp(P_ENEMY_DEATH_SEQUENCE);
422
423 if( !(killer_name = (mixed) kill_liv->QueryProp(P_KILL_NAME)) ){
424 killer_name = (mixed) kill_liv->QueryProp(P_NAME);
425 kart = (int) kill_liv->QueryProp(P_ARTICLE);
426 kgen = (int) kill_liv->QueryProp(P_GENDER);
427 }
428
429 killer_msg = (mixed) kill_liv->QueryProp(P_KILL_MSG);
430 pre = kill_liv;
431 }
432
433 if ( !killer_name && kill_ob && function_exists( "QueryProp", kill_ob ) ){
434 dseq = (mixed) kill_ob->QueryProp(P_ENEMY_DEATH_SEQUENCE);
435
436 if( !(killer_name = (mixed) kill_ob->QueryProp(P_KILL_NAME)) ){
437 killer_name = (mixed) kill_ob->QueryProp(P_NAME);
438 kart = (int) kill_ob->QueryProp(P_ARTICLE);
439 kgen = (int) kill_ob->QueryProp(P_GENDER);
440 }
441
442 killer_msg = (mixed) kill_ob->QueryProp(P_KILL_MSG);
443 pre = kill_ob;
444 }
445
446 // falls keine Sequenz gesetzt, eventuelle eigene Todessequenz nehmen
447 if (!dseq)
448 dseq = (mixed)pl->QueryProp(P_NEXT_DEATH_SEQUENCE);
449
450 act_seq = 0;
451
452 if ( mappingp(dseq) )
453 act_seq = get_sequence( "/room/death/sequences/lars" );
454 else if ( pointerp(dseq) ) // ganze Todessequenz...
455 act_seq = ({ dseq, 0 });
456 else if ( stringp(dseq) )
457 act_seq = get_sequence(dseq);
458
459 if(pl->query_hc_play()>1)
460 {
461 act_seq=({({22,([1:"Du faellst und faellst...\n",
462 5:"und faellst...\n",
463 10:"und faellst...\n",
464 12:"direkt in die Arme von TOD.\n",
465 14:"Triumphierend laechelt er Dich an.\n",
466 16:"NUN GEHOERST DU FUER IMMER MIR!\n",
467 18:"HAHHHAHAHAAAAAAAAAAHAAAAAAAAA!\n",
468 20:"TOD schlaegt Dir mit seiner Sense den Kopf ab.\n"])}),0});
469 }
470 if ( !act_seq )
471 act_seq = get_sequence();
472
473 if ( !mappingp(dseq) )
474 dseq = 0;
475
476 int i;
477 for ( i = sizeof(players); i--; )
478 if ( players[i][0] == pl )
479 break;
480
481 if ( i == -1 )
482 players += ({ ({ pl, 0, dseq, act_seq[0], act_seq[1], pre }) });
483 else
484 players[i][5] = pre;
485
486
487 if ( escaped ){
488 killer_name = "";
489 killer_msg = upperstring(getuid(pl)) + " VERSUCHTE, MIR ZU "
490 "ENTKOMMEN - JETZT HABE ICH WIEDER EXTRA-ARBEIT MIT "+
491 ((int) pl->QueryProp(P_GENDER) != 2 ? "IHM" : "IHR") +
492 " ...";
493 }
494 else if ( !killer_name ) {
495 if ( (string) pl->QueryProp(P_KILLER) == "gift" ){
496 killer_name = "Vergiftung";
497 kgen = FEMALE;
498 kart = 1;
499 }
500 else{
501 killer_name = "Etwas Geheimnisvolles und Unbekanntes";
502 kgen = NEUTER;
503 kart = 0;
504 }
505 }
506
507 if ( !pointerp(killer_msg) )
508 killer_msg = ({ killer_msg, 0, 0 });
509 else if ( sizeof(killer_msg) < 3 )
510 killer_msg += ({ 0, 0, 0 });
511
512 if ( stringp(killer_msg[0]) )
513 killer_msg[0] = sprintf( killer_msg[0], capitalize(getuid(pl)) );
514
515 SetProp( P_NAME, killer_name );
516 SetProp( P_ARTICLE, kart );
517 SetProp( P_GENDER, kgen );
518 string killname = Name(WER);
519 SetProp( P_NAME, "Lars" );
520 SetProp( P_ARTICLE, 0 );
521 SetProp( P_GENDER,MALE );
522
523 int magiertestie;
524 string testplayer = (string) pl->QueryProp(P_TESTPLAYER);
525 if (sizeof(testplayer))
526 {
527 if (testplayer[<5..<1]!="Gilde")
528 magiertestie = 1;
529 }
530
531 string kanal;
532 if (magiertestie || IS_LEARNING(pl))
533 kanal = "TdT";
534 else
535 kanal = "Tod";
536
537 CHMASTER->join( kanal, this_object() );
538
539 if ( (!stringp(killer_name) || killer_name != "") &&
540 (sizeof(killer_msg) < 4 || !killer_msg[3]) ){
541 if ( killer_msg[2] == PLURAL )
542 CHMASTER->send( kanal, this_object(),
543 killname + " haben gerade " +
544 capitalize(getuid(pl)) + " umgebracht." );
545 else
546 CHMASTER->send( kanal, this_object(),
547 killname + " hat gerade " +
548 capitalize(getuid(pl)) + " umgebracht." );
549 }
550
551 i = (int) pl->QueryProp(P_DEADS);
552 if ( i && (getuid(pl) == "key" || i%100 == 0 || i%250 == 0) ){
553 SetProp( P_NAME, "Tod" );
554 CHMASTER->send( kanal, this_object(),
555 sprintf( "DAS WAR SCHON DAS %dTE MAL!", i ) );
556 SetProp( P_NAME, "Lars" );
557 }
558
559 if( killer_msg[0] ){
560 if ( stringp(killer_name) && killer_name == "" ){
561 CHMASTER->send( kanal, this_object(),
562 break_string( funcall(killer_msg[0]), 78,
563 "["+kanal+":] " )[0..<2],
564 MSG_EMPTY );
565 return;
566 }
567 else {
568 if ( (killer_msg[1] < MSG_SAY) || (killer_msg[1] > MSG_GEMOTE) )
569 killer_msg[1] = MSG_SAY;
570
571 SetProp( P_NAME, killer_name );
572 SetProp( P_ARTICLE, kart );
573 SetProp( P_GENDER, kgen );
574 CHMASTER->send( kanal, this_object(), funcall(killer_msg[0]),
575 killer_msg[1] );
576 SetProp( P_NAME, "Lars" );
577 SetProp( P_ARTICLE, 0 );
578 SetProp( P_GENDER, MALE );
579 }
580 }
581
582 if ( pointerp(killer_msg = (mixed) pl->QueryProp(P_DEATH_MSG)) &&
583 sizeof(killer_msg) == 2 && stringp(killer_msg[0]) &&
584 intp(killer_msg[1]) ){
585 SetProp( P_NAME, capitalize(getuid(pl)) );
586 SetProp( P_ARTICLE, 0 );
587 SetProp( P_GENDER, pl->QueryProp(P_GENDER) );
588 CHMASTER->send( kanal, this_object(), killer_msg[0],
589 killer_msg[1] );
590 SetProp( P_NAME, "Lars" );
591 SetProp( P_ARTICLE, 0 );
592 SetProp( P_GENDER, MALE );
593 }
594
595 if (pl->query_hc_play()>1){
596 SetProp( P_NAME, "Tod" );
597 CHMASTER->send( kanal, this_object(),"NUN GEHOERST DU FUER EWIG MIR!" );
598 SetProp( P_NAME, "Lars" );
599 }
600}
601
602public int
603SmartLog( string creat, string myname, string str, string date )
604{
605 int i;
606 string fn;
607
608 for ( i = sizeof(players); i--; )
609 if ( players[i][0] == this_player() )
610 break;
611
612 // Spieler (Magier?) ist in keiner Todessequenz -> normales Repfile
613 if ( i == -1 )
614 return 0;
615
616 if ( !(fn = players[i][4]) ){
617 // Spieler hat eine unbekannte Todessequenz (kein Filename, Sequenz
618 // wurde komplett in P_ENEMY_DEATH_SEQUENCE abgelegt)
619 creat = "TOD/unbekannt.rep";
620 fn = "unbekannte Todessequenz";
621 }
622 else
623 // Jede Sequenz mit nem eigenen Repfile
624 creat = "TOD/" + explode( fn, "/" )[<1] + ".rep";
625
626 log_file( creat, myname + " von " + getuid(this_interactive())
627 + " ["+fn+"] (" + date + "):\n" + str + "\n" );
628
629 return 1;
630}
631
632public mixed hier_geblieben( mixed dest, int methods, string direction,
633 string textout, string textin )
634{
635 // Magier duerfen Spieler heraustransen
636 if ( this_interactive() && IS_LEARNER(this_interactive()) &&
637 (this_interactive() != previous_object() ||
638 IS_DEPUTY(this_interactive())) ){
639 previous_object()->Set( P_TMP_MOVE_HOOK, 0 );
640 return ({ dest, methods, direction, textout, textin });
641 }
642
643 // Spieler haengt noch in der Todessequenz
644 for ( int i = sizeof(players); i--; )
645 if ( objectp(players[i][0]) && previous_object() == players[i][0] &&
646 environment(previous_object()) == find_object(
647 "/room/death/virtual/room_death_" + getuid(previous_object()))&&
648 interactive(previous_object()) ) {
649 // Move nur erlaubt, wenn das Ziel wieder der Todesraum ist.
650 // wenn mal fuer nen bestimmten Zwecks Bewegungen raus aus dem
651 // Todesraum erforderlich sind, sollten hier entsprechende
652 // Ausnahmen eingebaut werden.
653 if ( (stringp(dest) &&
654 dest == object_name(environment(previous_object()))) ||
655 (objectp(dest) &&
656 dest == environment(previous_object())) ) {
657 previous_object()->Set( P_TMP_MOVE_HOOK, 0 );
658 return ({ dest, methods, direction, textout, textin });
659 }
660 else
661 return -1;
662 }
663
664 // Spieler ist nicht mehr im Raum oder eingeschlafen
665 if ( previous_object() )
666 previous_object()->Set( P_TMP_MOVE_HOOK, 0 );
667
668 return ({ dest, methods, direction, textout, textin });
669}