blob: 5478d8cd0ee52d2f4d9689fc593b869ab6a833bb [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// merlin.c -- Unser geliebter Merlin
4//
5// $Id: merlin.c 9405 2015-12-13 00:22:01Z Zesstra $
6#pragma strict_types
7#pragma no_clone
8#pragma no_shadow
9#pragma no_inherit
10#pragma verbose_errors
11#pragma combine_strings
12//#pragma pedantic
13//#pragma range_check
14#pragma warn_deprecated
15
16// 2014-Mai-10, Arathorn: Er soll ja weiterhin auf tm reagieren.
17inherit "std/npc/comm.c";
18
19#include <config.h>
20#include <properties.h>
21#include <language.h>
22#include <moving.h>
23#include <defines.h>
24#include <exploration.h>
25#include <news.h>
26#include <exploration.h>
27#include <events.h>
28#include <daemon/channel.h>
29#include "/secure/wizlevels.h"
30#include "/secure/config.h"
31#include "/secure/questmaster.h"
32#include "/secure/lepmaster.h"
33
34#ifndef DEBUG
35#define DEBUG(x) if (find_player("zook")) tell_object(find_player("zook"),x)
36#endif
37
38#define SAVEFILE "/secure/ARCH/merlin"
39#define BS(x) break_string((x),78)
40#define FEHLERTEUFEL "/obj/tools/fehlerteufel"
41
42mixed QueryProp(string prop);
43int move(mixed dest, int method);
44string query_g_suffix(int gen, int casus, int anzahl);
45string make_invlist(object viewer,object *inv);
46static int determine_action(string mess, string name);
47static int create_wizard(mixed who, mixed promoter);
48static int create_seer(mixed who);
49static void give_help(mixed who);
50int goto(mixed dest);
51
52nosave string *whitespaces=({",",".","?",";",":","-","!","\n","\t"});
53nosave object prev_room;
54nosave int delay,maxusers,busy;
55nosave string flag;
56
57mapping MBanishListe;
58
59void create()
60{
61 string s;
62 seteuid(ROOTID);
63 if (file_size("/etc/maxusers")<=0)
64 maxusers=0;
65 else
66 {
67 s=read_file("/etc/maxusers",0,1);
68 sscanf(s,"%d",maxusers);
69 }
70 set_living_name("merlin");
71 enable_commands();
72 call_out("wandern",25);
73 move("/gilden/abenteurer",0);
74 MBanishListe = m_allocate(0,2);
75 restore_object(SAVEFILE);
76 EVENTD->RegisterEvent(EVT_LIB_PLAYER_CREATION, "player_change", ME);
77 EVENTD->RegisterEvent(EVT_LIB_LOGIN, "player_change", ME);
78 // absichtlich kein EVT_LIB_LOGOUT, s. Kommentar zu notify_player_leave().
79}
80
81string _query_kill_name()
82{
83 return "Ein genervter Merlin";
84}
85
86int move(mixed ob,int methods)
87{
88 object tmp;
89
90 if (methods&M_GET)
91 return ME_CANT_BE_TAKEN;
92
93 if (stringp(ob))
94 {
95 if (!(tmp=find_object(ob)))
96 {
97 call_other(ob,"?");
98 tmp=find_object(ob);
99 }
100 ob=tmp;
101 }
102 if (!objectp(ob))
103 return 0;
104 if (environment())
105 tell_room(environment(),"Merlin zieht weiter.\n");
106 tell_room(ob,"Merlin kommt an.\n");
107 move_object(ob);
108 return 1;
109}
110
111mixed QueryProp(string str)
112{
113 if (!stringp(str)||str=="")
114 return 0;
115 return call_other(this_object(),"_query_"+str);
116}
117
118varargs int id(string str)
119{
120 return (str=="merlin");
121}
122
123varargs string name(int casus, int demon)
124{
125 if (casus!=WESSEN)
126 return "Merlin";
127 return "Merlins";
128}
129
130varargs string Name(int casus, int daemon)
131{
132 return name(casus,daemon);
133}
134
135string QueryDu(int casus, int gender, int zahl)
136{
137 return
138 ({ ({ ({ "du", "ihr"}), ({ "du", "ihr"}), ({ "du", "ihr"}) }),
139 ({({"deines","deiner"}),({"deines","deiner"}),({"deiner","deiner"})}),
140 ({({"dir","euch"}),({"dir","euch"}),({"dir","euch"})}),
141 ({({"dich","euch"}),({"dich","euch"}),({"dich","euch"})})
142 })[casus][gender][zahl];
143}
144
145string long()
146{
147 EPMASTER->GiveExplorationPoint("merlin");
148 return break_string(
149 "Merlin - der maechtige Urvater aller Magier - ist ein hagerer "
150 "Mann, der einen blauen, mit Monden und Sternen uebersaeten Umhang "
151 "traegt und sich auf einen knorrigen Stock stuetzt. Sein langer weisser "
152 "Bart reicht ihm fast bis zur Guertelschnalle, sein Haupthaar ist fast "
153 "ebenso lang. Auf seinem Kopf traegt er einen spitzen Hut, der ihn noch "
154 "groesser macht, als er ohnehin schon ist.\nEr ist unangreifbar, denn "
155 "er steht ueber solchen Dingen.",78,BS_LEAVE_MY_LFS);
156}
157
158string GetDetail(string key,mixed race,int sense) {
159 switch( sense ) {
160 case SENSE_SMELL: return 0;
161 case SENSE_SOUND: return 0;
162 }
163 switch( key ) {
164 case "nase": case "nasenhaare": case "hakennase":
165 return BS("Merlin hat eine lange, krumme Hakennase, aus deren Nasenloechern weisse Haare spriessen. Auf seiner Nase sitzt eine Brille mit Glaesern in Form eines Halbmondes.");
166 case "brille": case "glaeser": case "form": case "halbmond":
167 return "Merlins Brille besitzt Glaeser in Form eines Halbmondes.\n";
168 case "bart":
169 return "Merlins Bart ist sehr lang - Er reicht fast bis ueber die Guertelschnalle.\n";
170 case "haare" :
171 return "Sie reichen ihm bis zwischen die Schulterblaetter.\n";
172 case "schulterblaetter": case "schulterblatt":
173 return "Seine langen Haare bedecken die Schulterblaetter.\n";
174 case "gewand": case "robe":
175 return BS("Das Gewand ist blau und mit silbernen Monden und Sternen bestickt. Es ist uralt und schon etwas abgetragen, aber es erfuellt immer noch seinen Zweck.");
176 case "zweck":
177 return BS("Der Zweck des Gewandes besteht darn, Merlin standesgemaess zu bekleiden. Diesem Zweck kommt das Gewand in Vollendung nach.");
178 case "vollendung":
179 return "Nichts ist vollkommen.\n";
180 case "hut":
181 return BS("Ein langer, spitzer Hut, der in der gleichen Weise wie seine Robe mit Monden und Sternen bestickt ist.");
182 case "mond": case "monde": case "stern": case "sterne":
183 return BS("Die Monde und die Sterne sind mit silbrigen Faeden gestickt, die das Licht funkelnd zurueckwerfen.");
184 case "faden": case "faeden":
185 return BS("Schwer zu sagen, woraus die Faeden sind. Mithril? "
186 "Mondsilber?");
187 case "licht": case "mondsilber": case "mithril":
188 return BS("Du streckt schon Deine Hand aus, um Merlins Gewand naeher zu untersuchen, aber da trifft Dich sein strenger Blick. Schuechtern nimmst Du von Deinem Vorhaben Abstand.");
189 case "abstand":
190 return BS("Von so einem Magier sollte man aus Respekt einen Schritt Abstand halten.");
191 case "respekt":
192 return "Du hast sicher mehr Respekt vor Merlin, als er vor Dir.\n";
193 case "schritt":
194 return "Wessen Schritt??\n";
195 case "hand": case "haende":
196 return BS("Merlins Haende haben lange, gichtgeplagte Finger und gelbe lange Fingernaegel. Seine linke Hand stuetzt sich auf seinen knorrigen Gehstock. Die rechte Hand ist unter seinem Gewand verborgen.");
197 case "gichtknoten": case "gicht":
198 return BS("Durch die Gichtknoten sehen seine Haende fast so knorrig wie sein Gehstock aus.");
199 case "finger": case "fingernaegel": case "fingernagel":
200 return BS("Seine Finger sind voller Gichtknoten und seine gelben Fingernaegel koennte Merlin auch mal wieder schneiden.");
201 case "gehstock": case "stock":
202 return BS("Merlin stuetzt sich auf einen Gehstock. Der knorrige Stock scheint schon fast Eins mit seiner gichtknotigen Hand geworden zu sein. Ob es sich bei dem Stock um einen Magierstab handelt?");
203 case "zauberstab": case "magierstab":
204 return BS("Merlin stuetzt sich auf einen knorrigen Gehstock. Das koennte sein Zauberstab sein - aber vielleicht ist es auch nur ein Gehstock.");
205 case "guertel": case "guertelschnalle":
206 return BS("Sein Gewand wird von einem weissen Guertel gehalten. Vorne, unter seinem Bart, kannst Du die Guertelschnalle sehen. Auf der Guertelschnalle steht: 'Ich koennte jederzeit aufhoeren.'");
207 }
208 return 0;
209}
210
211
212string short()
213{
214 return "Merlin, der Urvater aller Magier.\n";
215}
216
217string _query_race()
218{
219 return "Magier";
220}
221
222int _query_gender()
223{
224 return 1;
225}
226
227string QueryPossPronoun( mixed what, int casus, int number )
228{
229 int gen2;
230 gen2 = ( intp( what ) ) ? what : what->QueryProp(P_GENDER);
231 return "sein" + query_g_suffix( gen2, casus, number );
232}
233
234string query_g_suffix( int gen, int casus, int anzahl )
235{
236 return ({ ({ ({"","e"}), ({"es","er"}), ({"em","en"}), ({"","e"}) }),
237 ({ ({"","e"}), ({"es","er"}), ({"em","en"}), ({"en","e"}) }),
238 ({ ({"e","e"}), ({"er","er"}), ({"er","en"}), ({"e","e"}) }) })
239 [gen][casus][anzahl];
240}
241
242string QueryPronoun(int casus)
243{
244 switch(casus) {
245 case WER: return "er"; break;
246 case WEM: return "ihm";
247 }
248 return "ihn";
249}
250
251string _query_short()
252{
253 return short();
254}
255
256string _query_long()
257{
258 return long();
259}
260
261string _query_name()
262{
263 return "Merlin";
264}
265
266int _query_weight()
267{
268 return 75000;
269}
270
271static void PostSeher(string who, int g)
272{
273 mixed *art;
274
275 art=({"stufen","Merlin",0,0,sprintf("%s ist jetzt ein%s Seher%s!",who,(g==2?"e":""),(g==2?"in":"")),sprintf("\nAm %s hat %s die noetigen Bedingungen\nerfuellt und ist vom Spielerstatus zum Seherstatus aufgestiegen. \n\n Herzlichen Glueckwunsch, %s!\n",dtime(time()),who,who)});
276 "/secure/news"->WriteNote(art,1);
277}
278
279static void PostMagier(string who, string prom, int gender)
280{
281 mixed *art;
282
283 art=({"stufen","Merlin",0,0,sprintf("%s ist jetzt ein%s Magier%s!",who,(gender==2?"e":""),(gender==2?"in":"")),sprintf("\nAm %s hat %s %s zu%s Magier%s\nberufen. Herzlichen Glueckwunsch, %s. Glueckwuensche auch an Dich,\n %s, zu Deine%s neuen %s!\n",dtime(time()),prom,who,(gender==2?"r":"m"),(gender==2?"in":""),who,prom,
284(gender==2?"r":"m"),(gender==2?"Tochter":"Sohn"))});
285 "/secure/news"->WriteNote(art,1);
286}
287
288
289private void GibFehlerteufel(object wiz) {
290 if (!objectp(wiz))
291 return;
292
293 clone_object(FEHLERTEUFEL)->move(wiz, M_NOCHECK|M_GET);
294 tell_object(wiz, break_string(
295 "Huhu "+wiz->Name(WER) + "! Ich habe gesehen, dass Du keinen "
296 "Fehlerteufel hast. Dieses Tool ist zum Debuggen von Fehlern im "
297 "Mud sehr praktisch. Bitte schau ihn Dir mal an. :-) Die Hilfe zum "
298 "Fehlerteufel kannst Du mit 'man fehlerteufel' lesen. BTW: Wenn "
299 "Du den Fehlerteufel nicht willst, kannst Du ihn zerstoeren, ich "
300 "werde Dich kein zweites Mal damit belaestigen.",78,
301 "Merlin teilt Dir mit: ")
302 + "Merlin ueberreicht Dir aus der Ferne einen knusprig gebratenen "
303 "Fehlerteufel.\n\n");
304}
305
306private void notify_player_change(string who,int rein)
307{
308 if (!stringp(who))
309 return;
310
311 // Max-user festhalten
312 if (file_size("/etc/maxusers")<=0)
313 maxusers=0;
314 if (sizeof(users())>=maxusers)
315 {
316 maxusers=sizeof(users());
317 write_file("etc/maxusers",sprintf("%d user: %s (%s)\n",
318 maxusers,dtime(time()),query_load_average()),1);
319 }
320
321 // allen Magiern ab Level 20, die keinen Fehlerteufel haben und deren
322 // letzter Logout vor "Die, 17. Mar 2009, 23:40:04" => 1237329604 war,
323 // einen Fehlerteufel clonen und nen Hiwneis mitteilen.
324 object ob = find_player(who);
325 if (ob && rein && IS_WIZARD(ob)
326 && !present_clone(FEHLERTEUFEL,ob)
327 && ob->QueryProp(P_LAST_LOGOUT) < 1237329604 )
328 GibFehlerteufel(ob);
329}
330
331private void AnnounceNewPlayer(object pl) {
332
333 if (!pl || !interactive(pl))
334 return;
335
336 // verzoegern, bis der Spieler wirklich fertig ist.
337 if (pl->QueryProp(P_LEVEL) < 0) {
338 call_out(#'AnnounceNewPlayer,10,pl);
339 return;
340 }
341
342 if (!(int)pl->QueryGuest()) {
343 string plname = (string)pl->Name(WER);
344 CHMASTER->send("Anfaenger", this_object(),
345 sprintf("%s macht nun ebenfalls das Morgengrauen unsicher. "
346 "Herzlich Willkommen %s!", plname, plname)
347 );
348 }
349}
350
351// Kann bei reboot wieder raus... zesstra, 16.03.2007
352#if __BOOT_TIME__ < 1318110723
353#define BUGTIME 1318003200
354#define BUGFIXTIME 1318109421
355void renew_player(string plname, int force) {
356 object pl;
357 mixed err;
358
359 pl = find_player(plname);
360 if (!objectp(pl) || !query_once_interactive(pl)) return;
361
362 // jung oder alt genug, Abbruch. ;-)
363 if ((object_time(pl) > BUGFIXTIME)
364 || object_time(pl) < BUGTIME)
365 return;
366
367 if (get_eval_cost() < 1000000 || !force ) {
368 call_out("renew_player",8,plname,1);
369 tell_object(pl,break_string(sprintf("Huhu %s, um einen Bug in "
370 "Deinem Spielerobjekt zu beheben, wirst Du in ca. 8s "
371 "neugeladen. Bitte warte bis dahin ab und bleibe, wo "
372 "Du gerade bist.",pl->Name()),78,"Merlin teilt Dir mit: "));
373 return;
374 }
375
376 plname=getuid(pl);
377 tell_object(pl,break_string(sprintf("Huhu %s, um einen Bug in "
378 "Deinem Spielerobjekt zu beheben, wirst Du jetzt "
379 "neugeladen.",pl->Name()),78,"Merlin teilt Dir mit: "));
380
381 if (err=catch(master()->renew_player_object(pl);publish)) {
382 log_file("zesstra/failed_rewew.log",sprintf("%s: Fehler %O beim "
383 "Renew von %s\n",dtime(time()),err,plname));
384 tell_object(pl,break_string("Beim Neuladen Deines Spielerobjekts "
385 "gab es einen Fehler. Bitte wende Dich an einen EM.",78,
386 "Merlin teilt Dir mit: "));
387 }
388 else {
389 log_file("zesstra/renewed.log",sprintf("%s: %s wurde renewed.\n",
390 dtime(time()),plname));
391 if (objectp(find_player(plname)))
392 tell_object(find_player(plname),
393 break_string("Dein Spielerobjekt wurde neugeladen. Du "
394 "kannst jetzt normal weiterspielen. Falls Du etwas ungewoehnliches "
395 "bemerkst, melde Dich bitte bei einem Erzmagier. Viel Spass im "
396 "Spiel!",78, "Merlin teilt Dir mit: "));
397 }
398}
399#endif
400
401void player_change(string eid, object trigob, mixed data) {
402
403 if (!trigob || !interactive(trigob))
404 return;
405
406 switch(eid) {
407 case EVT_LIB_PLAYER_CREATION:
408 call_out(#'AnnounceNewPlayer, 5, trigob);
409 break;
410 case EVT_LIB_LOGIN:
411 notify_player_change(data[E_PLNAME],1);
412#if __BOOT_TIME__ < 1318110723
413 // Spieler evtl. renewen? Bei reboot raus (08.10.2011)
414 renew_player(data[E_PLNAME],0);
415#endif
416 break;
417 }
418}
419
420
421//besser P_NO_ATTACK als Defend()...
422mixed _query_no_attack() {
423 if (!living(PL) || !objectp(environment(PL)) ) return(1);
424
425 tell_room(environment(), "Merlin schimpft: Lass das!!!\n",({PL}));
426 tell_room(environment(),sprintf(
427 "Merlin gibt %s eine schallende Ohrfeige.\n",
428 capitalize((string)this_player()->name(WEM))), ({this_player()}));
429 return("Merlin schimpft: Lass das!!!\n"
430 "Merlin gibt Dir eine schallende Ohrfeige.\n");
431}
432
433/*
434int Defend(int dam, string dam_type, int spell, object enemy)
435{
436 object en;
437 if (!en=previous_object() || !living(en))
438 en = this_player();
439 tell_room(environment(), "Merlin schimpft: Lass das!!!\n");
440 write("Merlin gibt Dir eine schallende Ohrfeige.\n");
441 say(sprintf("Merlin gibt %s eine schallende Ohrfeige.\n",
442 capitalize((string)this_player()->name(WEM))), this_player());
443 en->StopHuntFor(this_object(), 1);
444}
445*/
446void shoutansw()
447{
448 object env,ti;
449 string *path;
450 string ans;
451
452 if (!(env=environment()))
453 return;
454 if (!(ti=this_interactive())||(int)ti->QueryProp(P_LEVEL)<19||ti->QueryProp(P_GHOST))
455 return;
456 tell_object(ti,"Du spuerst einen sengenden Schmerz.\n");
457 ti->do_damage( ((int)ti->QueryProp(P_HP)) / 2 + 5);
458 if((int)ti->QueryProp(P_GHOST)) return;
459 ans="ich hab nicht die leiseste Idee, wo ich hier bin ...\n";
460 path=old_explode(object_name(env),"/");
461 if (path[0]=="d")
462 {
463 ans="werweisswo ..";
464 switch(path[1])
465 {
466 case "gebirge":
467 case "wald":
468 case "dschungel":
469 ans="im "+capitalize(path[1]);
470 break;
471 case "inseln":
472 ans="auf den Inseln";
473 break;
474 case "polar":
475 ans="im Polargebiet";
476 break;
477 case "unterwelt":
478 case "ebene":
479 case "wueste":
480 ans="in der "+capitalize(path[1]);
481 break;
482 case "vland":
483 ans="im Verlorenen Land";
484 break;
485 case "fernwest":
486 ans="in Fernwest";
487 break;
488 }
489 ans="ich bin "+ans+".\n";
490 }
491 if (path[0]=="players")
492 ans="ich hab mich verlaufen - ich schaetze, "+capitalize(path[1])+
493 " hat was damit zu tun...\n";
494 if (path[0]=="gilden") {
495 switch(path[1]) {
496 case "abenteurer":
497 ans="der Abenteurergilde";
498 break;
499 case "bierschuettler":
500 ans="der Bierschuettlergilde";
501 break;
502 case "chaos":
503 ans="der Gilde der Chaoten";
504 break;
505 case "kaempfer":
506 ans="der Kaempfergilde";
507 break;
508 case "karate":
509 ans="einem Karatedojo";
510 break;
511 case "klerus":
512 ans="einem Tempel der Kleriker";
513 break;
514 case "zauberer":
515 ans="der Akademie der Zauberer";
516 break;
517 default:
518 ans="irgendeiner Gilde";
519 }
520 ans="ich stehe in "+ans+".\n";
521 }
522 if( path[0]=="p" && path[1]=="verein" ) {
523 ans="ich stehe in Port Vain.";
524 }
525 if (!this_interactive()->QueryProp(P_INVIS))
526 ans=this_interactive()->Name(WER)+", "+ans;
527 else ans=capitalize(ans);
528 call_out("myshout",0,break_string(ans, 78, "Merlin ruft: "));
529}
530
531void myshout(string s)
532{
533 write(s);
534 shout(s);
535}
536
537void catch_tell(string str)
538{
539 string name, dummy; mixed message;
540 int i,s;
541
542 if (!this_player())
543 return;
544
545 if (environment()==environment(this_player()) && previous_object()!=ME)
546 tell_room(this_object(),"*"+str);
547
548 if (this_player() != this_interactive())
549 return;
550
551 if (busy) {
552 tell_object(this_player(),
553 "Merlin teilt Dir mit: Ich bin beschaeftigt.\n");
554 return;
555 }
556
557 str=lower_case(str);
558
559 if ((strstr(str, "teilt dir mit:") != -1)
560 && (strstr(str, "wo bist du") !=-1)) {
561 shoutansw();
562 return;
563 }
564
565 if ((strstr(str, "teilt dir mit:") != -1) &&
566 ((strstr(str, "seher") != -1 || strstr(str, "seherin") != -1)))
567 {
568 create_seer(this_player());
569 return;
570 }
571
572 if (sscanf(str,"%s %s sagt: %s",dummy,name,message)!=3)
573 if (sscanf(str,"%s sagt: %s",name,message)!=2)
574 return;
575
Zesstraf5a8bf32017-01-30 23:06:00 +0100576 if (!name || !sizeof(name) || !master()->find_userinfo(name))
MG Mud User88f12472016-06-24 23:31:02 +0200577 return;
578
579 if (name!=getuid(this_interactive()) && !ARCH_SECURITY)
580 {
581 if (flag==getuid(this_interactive())+"##"+name)
582 return;
583 call_out("do_say",0,"Merlin sagt: "+capitalize(getuid(this_interactive()))+" hat gerade so getan, als wuerde "+capitalize(name)+" etwas sagen!\n");
584 flag=getuid(this_interactive())+"##"+name;
585 call_out("clear_flag",0);
586 return;
587 }
588 flag=0;
589 for (i=0;i<sizeof(whitespaces);i++)
590 {
591 message=old_explode(message,whitespaces[i]);
592 if (!pointerp(message)||sizeof(message)==0)
593 return;
594 message=implode(message," ");
595 }
596
597 message=old_explode(message," ");
598
599 if (!pointerp(message) || !sizeof(message))
600 return;
601
602 message-=({0})-({""});
603
604 if (!message || sizeof(message)==0)
605 return;
606
607 if (member(message, "merlin")==-1)
608 return;
609
610 message-=({"merlin"});
611
612 message=implode(message," ");
613
614 if (!message || message=="")
615 return;
616
617 determine_action(message, name);
618}
619
620static int determine_action(string mess, string name)
621{
622 string str;
623
624 if (mess=="mach mich zum magier" || mess=="mach mich zur magierin")
625 return create_wizard(name,name);
626
627 if (sscanf(mess,"mach %s zum magier",str)==1||sscanf(mess,"mach %s zur magierin",str)==1)
628 return create_wizard(lower_case(str),name);
629
630 give_help(name);
631 return 0;
632}
633
634#define Say(str) say(str,who)
635#define Write(str) tell_object(who,str)
636
637int QueryBedingungen(object pl,string was)
638{
639 int ret,i,gen;
640 string s;
641
642 if (IS_SEER(pl))
643 return 1;
644
645 if ((int)LEPMASTER->QueryReadyForWiz(pl)==1)
646 return 1;
647
648 s=(string)LEPMASTER->QueryReadyForWizText(pl);
649
650 tell_object(pl, break_string("Merlin gruebelt ein wenig und teilt Dir "
651 "nach einigem Ueberlegen mit:\n\n", 78,0,1));
652
653 tell_object(pl, s+"\n");
654
655 tell_object(pl, break_string("Da ist wohl fuer Dich noch etwas zu tun...",
656 78, "Merlin teilt Dir mit: "));
657
658 if (environment() == environment(pl))
659 say((string)pl->name(WER)
660 +" erfuellt noch nicht alle Anforderungen fuer den "+was+"status.\n",pl);
661
662 return 0;
663}
664
665static int create_wizard(mixed who, mixed promoter)
666{
667 mixed *domains;
668 object vertrag;
669 int ret;
670 string gen;
671
672 who=find_player(who);
673 promoter=find_player(promoter);
674 if (!who || !promoter)
675 return 0;
676 //
677 // player not interactive?
678 //
679 if (!interactive(who))
680 {
681 write(capitalize(getuid(who))+" ist nicht aktiv.\n");
682 return 0;
683 }
684 //
685 // player is second?
686 //
687 if (who->QueryProp(P_SECOND))
688 {
689 tell_object(who,"Du bist ein Zweitspieler und kannst als solcher kein Magier werden.\n"
690 +"Versuchs Doch mal mit Deinem Erstie.\n");
691 write("Du kannst "+who->name()+" nicht zum Magier machen. Das geht bei "
692 +"Zweities\nleider nicht. Frag doch mal nach dem Erstie.\n");
693 return 1;
694 }
695 //
696 // wants to advance himself?
697 //
698 if (who==promoter)
699 {
700 write("Du kannst Dich nicht selber befoerdern. Such Dir dazu bitte einen "+
701 "Vollmagier,\nder Dir einen Vertrag gibt.\n");
702 return 1;
703 }
704 //
705 // banished?
706 //
707 if (MBanishListe[who,1])
708 {
709 tell_object(promoter,capitalize(who)+" darf nur von einem Erzmagier zum "+
710 "Magier gemacht werden.\n");
711 say(promoter->name(WER)+" ist kein Erzmagier und darf "+capitalize(who)+
712 " nicht zum Magier machen.\n");
713 return 1;
714 }
715 //
716 // player has PK?
717 //
718 if (who->QueryProp("playerkills")) {
719 tell_room(environment(who),who->name()+" hat noch einen Playerkill und kann somit kein Magier werden.\n"
720 "Am besten den Sheriff oder einen Erzmagier verstaendigen.\n");
721 return 1;
722 }
723 //
724 // already dom_member?
725 //
726 if (IS_DOMAINMEMBER(who))
727 {
728 Write("Fuer Dich kann ich nichts mehr tun. Du bist doch schon Magier!\n");
729 return 1;
730 }
731
732 //
733 // "advanced learner"?
734 //
735 if (query_wiz_level(who) == 20)
736 {
737 if (!ARCH_SECURITY) {
738 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
739 Say("Nur ein Erzmagier kann "+who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
740 return 0;
741 }
742 ret=(int)"secure/master"->advance_wizlevel(geteuid(who),21);
743 if (ret<=0)
744 {
745 say("Merlin: error "+ret+"\n");
746 write("Merlin: error "+ret+"\n");
747 }
748 write("Merlin ruft: "+(string)who->name(WER)+" ist in den Kreis der Magier "+
749 "aufgenommen worden!\n");
750 shout("Merlin ruft: "+(string)who->name(WER)+" ist in den Kreis der Magier "+
751 "aufgenommen worden!\n");
752 "secure/master"->renew_player_object(who);
753 return 1;
754 }
755
756 //
757 // already wizard?
758 //
759 if (IS_WIZARD(who))
760 {
761 domains=(string*)"secure/master"->get_domain_homes(getuid(who));
762 if (!domains || !pointerp(domains) || !sizeof(domains))
763 {
764 Say(who->name(WER)+" gehoert noch keiner Region an und kann daher noch "+
765 "kein Voll-\nmagier werden.\n");
766 Write("Du gehoerst noch keiner Region an. Schliess Dich zunaechst einer "+
767 "an und komm\ndann wieder!\n");
768 return 0;
769 }
770 ret=(int)"secure/master"->advance_wizlevel(geteuid(who),25);
771 if(ret>0)
772 {
773 shout(who->name(WER)+" arbeitet jetzt an einer Region mit!\n");
774 "secure/master"->renew_player_object(who);
775 return 1;
776 }
777 write("RETURNVALUE "+ret+"\n");
778 say("RETURNVALUE "+ret+"\n");
779 return 0;
780 }
781
782 //
783 // still learner?
784 //
785 if (IS_LEARNER(who))
786 {
787 if (!ARCH_SECURITY) {
788 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
789 Say("Nur ein Erzmagier kann "+who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
790 return 0;
791 }
792 ret=(int)"secure/master"->advance_wizlevel(geteuid(who),20);
793 if (ret<=0)
794 {
795 say("Merlin: error "+ret+"\n");
796 write("Merlin: error "+ret+"\n");
797 }
798 string wizname = (string)who->query_real_name();
799 "secure/master"->renew_player_object(who);
800 // Fehlerteufel geben
801 call_out(#'GibFehlerteufel,4,find_player(wizname));
802 return 1;
803 }
804
805 //
806 // promoter's level is not >DOMAINMEMBER_LVL+1
807 //
808 if (secure_level()<=DOMAINMEMBER_LVL)
809 {
810 tell_object(promoter,"Du musst derzeit mindestens Level "+
811 (DOMAINMEMBER_LVL+1)+" haben, um jemanden befoerden zu "+
812 "koennen.\n");
813 say(promoter->name(WER)+" ist kein Vollmagier und darf daher niemanden "+
814 "zum Vollmagier machen.\n");
815 return 1;
816 }
817
818 // der Check auf den Blutprintnamen ist fast ueberfluessig, aber nur fast.
819 // Er schlaegt fehl, wenn der Vertrag der Clone einer alten BP ist.
820 if (!(vertrag=present_clone("/obj/vertrag",who)) ||
821 object_name(blueprint(vertrag))!="/obj/vertrag" ||
822 !((int)vertrag->is_unterschrieben()) )
823 {
824 Write("Du hast ja gar keinen unterschriebenen Vertrag bei Dir. Besorg Dir "+
825 "einen Ver-\ntrag, unterschreibe ihn und komm dann wieder!\n");
826 Say(who->name(WER)+" hat keinen unterschriebenen Vertrag.\n");
827 return 1;
828 }
829 if (geteuid(vertrag)!=secure_euid())
830 {
831 tell_object(promoter,"Das geht nicht, er hat einen Vertrag von "+
832 capitalize(geteuid(vertrag))+" bei sich.\n");
833 say(promoter->name(WER)+" versucht, "+who->name(WER)+" zum Magier zu "+
834 "machen, doch "+who->name(WER)+" hat einen Vertrag\nvon "+
835 capitalize(geteuid(vertrag))+" bei sich.\n",promoter);
836 return 0;
837 }
838 if (!QueryBedingungen(who,"Magier"))
839 return 0;
840 ret=(int)"secure/master"->advance_wizlevel(geteuid(who),15);
841 if (ret>0)
842 {
843 PostMagier(capitalize(getuid(who)),
844 capitalize(secure_euid()),(int)who->QueryProp(P_GENDER));
845 write_file("/log/SPONSOR",dtime(time())+": "+capitalize(getuid(promoter))+" macht "+
846 who->name(WER)+" zum Learner.\n");
847 write(who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
848 shout(who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
849 if ("secure/master"->set_player_object(geteuid(who),"/std/shells/magier")
850 <=0)
851 {
852 say("MERLIN: konnte Magiershell nicht einstellen.\n");
853 write("MERLIN: konnte Magiershell nicht einstellen.\n");
854 }
855 "secure/master"->renew_player_object(who);
856 return 1;
857 }
858 write(" --RETURNVALUE IS "+ret+"\n");
859 say(" --RETURNVALUE IS "+ret+"\n");
860
861 return(ret); //non-void funktion
862}
863
864void clear_flag()
865{
866 flag=0;
867}
868
869void do_say(string str)
870{
871 say(str);
872}
873
874
875
876void seer_sequenz3(mixed player, string plname)
877{
878 string playername;
879 object faq;
880 string text;
881
882 if (!objectp(player)) {
883 tell_room(environment(), sprintf("Merlin sagt: Na, wo ist denn %s "
884 "hin?\n", plname));
885 busy = 0;
886 return;
887 }
888 if (environment() != environment(player))
889 move(environment(player), M_TPORT);
890
891 tell_object(player,break_string("\n\nEs macht *PUFF* und eine Schwefelwolke "
892 +"steigt um Dich herum auf.\n\nDie Aura "
893 +"verschwindet langsam und Du fuehlst Dich "
894 +"nun viel erfahrener.", 78,0,1));
895 tell_room(environment(),
896 break_string(sprintf(
897 "\n\nEs macht *PUFF* und eine Schwefelwolke steigt "
898 +"um %s herum auf.\n\nDie Aura verschwindet langsam.\n",
899 plname),78,0,1), ({player}));
900
901 if ("secure/master"->advance_wizlevel(geteuid(player),1)<=0)
902 {
903 write("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
904 say("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
905 busy = 0;
906 return;
907 }
908 playername = geteuid(player);
909 "secure/master"->renew_player_object(player);
910 player = find_player(playername);
911 text = sprintf(" ist jetzt ein%s Seher%s!\n",
912 (((int)player->QueryProp(P_GENDER))==2?"e":""),
913 (((int)player->QueryProp(P_GENDER))==2?"in":""));
914 write("Merlin ruft: "+capitalize(playername)+text);
915 shout("Merlin ruft: "+capitalize(playername)+text);
916 PostSeher(capitalize(playername),(int)player->QueryProp(P_GENDER));
917 if(!catch(
918 faq=clone_object("/d/seher/haeuser/special/seherfaqmobil") ;publish))
919 {
920 faq->move(player,M_NOCHECK);
921 tell_object(player, "Aus dem Nichts erscheint eine kleine Belohnung fuer Dich.\n");
922 }
923
924 tell_object(player, "\n\nDu laechelst gluecklich in die Runde.\n\n");
925 tell_room(environment(), sprintf("\n\n%s laechelt gluecklich in die Runde.\n\n", plname), ({player}));
926
927 busy=0;
928}
929
930void seer_sequenz2(mixed player, string plname)
931{
932 if (!objectp(player)) {
933 tell_room(environment(), sprintf(
934 "Merlin sagt: Na, wo ist denn %s hin?\n",
935 plname));
936 busy = 0;
937 return;
938 }
939 if (environment() != environment(player))
940 move(environment(player), M_TPORT);
941
zesstra70a0a3e2016-07-06 20:35:40 +0200942 tell_object(player, break_string("\nMerlin hebt die Arme "
MG Mud User88f12472016-06-24 23:31:02 +0200943 +"und macht einige beschwoerende Gesten. Um Dich herum erscheint "
944 +"eine gelbliche Aura, die immer heller wird, bis Du Deine "
945 +"Umwelt kaum mehr erkennen kannst.\n\n",
946 78,0,1));
947 tell_room(environment(),
948 break_string(sprintf("\nMerlin hebt die Arme und macht einige "
949 +"beschwoerende Gesten. Um %s erscheint eine "
950 +"gelbliche Aura, die immer heller wird, bis "
951 +"man %s kaum mehr erkennen kann.\n\n",
952 plname, plname),78,0,1), ({player}));
953
954 call_out("seer_sequenz3", 7, player, plname);
955}
956
957void seer_sequenz1(mixed player, string plname)
958{
959 if (!objectp(player))
960 return;
961
962 move(environment(player), M_TPORT);
963
964 tell_room(environment(),
965 break_string(sprintf("Das ist eine grosse Freude. %s hat sich "
966 "tapfer durch das "MUDNAME" geschlagen und mittlerweile alle "
967 "Anforderungen erfuellt, um %s zu werden.",
968 plname, ((int)player->QueryProp(P_GENDER))==1?"Seher":"Seherin"),
969 78, "Merlin sagt: "));
970
971 call_out("seer_sequenz2", 4, player, plname);
972}
973
974
975static int create_seer(mixed player)
976{
977 if (!objectp(player))
978 return 0;
979 if (IS_SEER(player))
980 {
981 write(break_string("Du bist doch schon kein normaler Spieler mehr, "
982 +"was soll es also?", 78, "Merlin teilt Dir mit: "));
983 return 1;
984 }
985
986 if (!QueryBedingungen(player,"Seher"))
987 return -1;
988
989
990 write(break_string("Grosse Freude! Du hast alle Anforderungen "
991 "erfuellt. Warte einen Moment...", 78,
992 "Merlin teilt Dir mit: "));
993 busy=1;
994 call_out("seer_sequenz1",4,player, player->Name());
995 return(0); //non-void funktion
996}
997
998static void give_help(mixed player)
999{
1000 if (!objectp(player))
1001 return;
1002
1003 tell_object(player,
1004 break_string("Ich weiss nicht, was ich fuer Dich tun kann. "
1005 +"Ich kann Dich zum Seher oder zum Magier "
1006 +"machen, wenn Du mich darum bittest.", 78,
1007 "Merlin teilt Dir mit: "));
1008}
1009
1010
1011void reset()
1012{
1013}
1014
1015public int remove(int silent) {
1016 EVENTD->UnregisterEvent(EVT_LIB_LOGIN, ME);
1017 EVENTD->UnregisterEvent(EVT_LIB_PLAYER_CREATION, ME);
1018 destruct(this_object());
1019 return 1;
1020}
1021
1022void wandern()
1023{
1024 mapping ex,rooms;
1025 mixed ziel;
1026 object *raeume,*laeden,env,ob;
1027 string *ind,fn;
1028 int i;
1029
1030 while (remove_call_out("wandern")>=0);
1031 call_out("wandern",45+random(100));
1032 if (busy) return;
1033 if (delay)
1034 {
1035 delay=0;
1036 return;
1037 }
1038 if (!(env=environment()))
1039 {
1040 move("/gilden/abenteurer",0);
1041 env=environment();
1042 }
1043 //ueber Inv iterieren, ob da ein nicht-idelnder Spieler mit genug XP
1044 //rumhaengt.
1045 raeume=all_inventory(env);
1046 for(i=sizeof(raeume); i-- ; ) {
1047 if (interactive(raeume[i]) && query_idle(raeume[i])<180 &&
1048 raeume[i]->QueryProp(P_XP)>999999)
1049 return;
1050 }
1051 ex=(mapping)env->QueryProp(P_EXITS);
1052 if (!mappingp(ex))
1053 return;
1054 ind=m_indices(ex);rooms=([]);laeden=({});
1055 for (i=sizeof(ind)-1;i>=0;i--)
1056 {
1057 if (!stringp(ziel=ex[ind[i]]))
1058 continue;
1059 if (!ob=find_object(ziel))
1060 continue;
1061 rooms+=([ob]);
1062 }
1063 rooms-=([env]);
1064 if (prev_room && sizeof(m_indices(rooms))>1)
1065 rooms-=([prev_room]);
1066 prev_room=env;
1067 raeume=m_indices(rooms);
1068 if (!i=sizeof(raeume))
1069 return;
1070 ob=raeume[random(i)];
1071 move(ob,0);
1072}
1073
1074string int_short()
1075{
1076 return "Du bist im allseits beliebten Wizclub \"Zum lustigen Merlin\".\n";
1077}
1078
1079string int_long(object who,mixed where)
1080{
1081 string descr;
1082
1083 if( IS_LEARNER(who) && who->QueryProp( P_WANTS_TO_LEARN ) )
1084 descr = "[" + object_name(ME) + "]\n";
1085 else
1086 descr = "";
1087 descr+="Du bist im Wizclub 'Zum lustigen Merlin'. Dieser Wizclub ist etwas besonderes -\ner hat keinen festen Standort, sondern wandert im Mud herum. Ausserdem kann er\nSpieler zu Magiern machen - aber nur, wenn man ihn von aussen aus darauf\nanspricht.\n";
1088 if ( who->QueryProp(P_SHOW_EXITS) )
1089 descr += "Es gibt 2 sichtbare Ausgaenge: raus und gilde.\n";
1090 descr += make_invlist(who, all_inventory(ME) - ({ who }));
1091 if( environment())
1092 descr += "\nAusserhalb siehst Du:\n"
1093 + environment()->int_short(who,ME);
1094 return descr;
1095}
1096
1097string make_invlist(object viewer,object *inv)
1098{
1099 int i, iswiz;
1100 string descr;
1101
1102 descr = "";
1103 iswiz = IS_LEARNER( viewer ) && viewer->QueryProp(P_WANTS_TO_LEARN);
1104
1105 for (i = 0; i < sizeof(inv); i++)
1106 {
1107 string sh;
1108 sh = (string)inv[i]->short();
1109 if (iswiz)
1110 {
1111 if (sh) sh = sh[0..<2] + " ["+object_name(inv[i])+"]\n";
1112 else sh = "["+object_name(inv[i])+"]\n";
1113 }
1114 if (sh) descr += sh;
1115 }
1116 return descr;
1117}
1118
1119void init()
1120{
1121 if (interactive(this_player()) && environment(this_player())==ME)
1122 add_action("gehen","",1);
1123 add_action("befoerdere","befoerder",1);
1124}
1125
1126int befoerdere(string str)
1127{
1128 string wen;
1129 int ret,stufe,l;
1130
1131 if (!LORD_SECURITY) return 0;
1132 if (!str||sscanf(str,"%s auf stufe %d",wen,stufe)<2)
1133 {
1134 notify_fail("Syntax: befoerdere <name> auf stufe <stufe>\n");
1135 return 0;
1136 }
1137 if (stufe>29)
1138 {
1139 write("Maximum ist Stufe 29!\n");
1140 return 1;
1141 }
1142 l=query_wiz_level(wen);
1143 if (l<25)
1144 {
1145 printf("%s muss mindestens zwecks Weiterbefoerderung mindestens Stufe 25 haben.\n",
1146 capitalize(wen));
1147 return 1;
1148 }
1149 if (l>=stufe)
1150 {
1151 printf("%s ist schon Stufe %d.\n",capitalize(wen),l);
1152 return 1;
1153 }
1154 ret=(int)"secure/master"->advance_wizlevel(wen,stufe);
1155 if (ret<=0)
1156 printf("Errorcode %d\n",ret);
1157 else
1158 write("ok\n");
1159 return 1;
1160}
1161
1162int sag(mixed str)
1163{
1164 int i;
1165
1166 if (str==0)
1167 str="";
1168 str = old_explode(break_string(str, 60 ), "\n");
1169 if (busy) {
1170 tell_room(ME, "Merlin mault: Ich bin beschaeftigt.\n");
1171 return 0;
1172 }
1173 for (i = 0; i < sizeof(str); i++)
1174 {
1175 if (!str[i])
1176 str[i]="";
1177 tell_room(environment(),"Merlin sagt: "+str[i]+"\n");
1178 tell_room(ME,"*Merlin sagt: "+str[i]+"\n");
1179 }
1180 return 1;
1181}
1182
1183void show_exits()
1184{
1185 printf("%s",environment()->GetExits());
1186}
1187
1188int gehen(string str)
1189{
1190 string verb;
1191 int i;
1192 mapping exits;
1193 string *ex;
1194
1195 if (busy) {
1196 write("Merlin mault: Ich bin beschaeftigt.\n");
1197 return 0;
1198 }
1199
1200 verb=query_verb();
1201 str=(string)this_interactive()->_unparsed_args();
1202 switch (verb)
1203 {
1204 case "gilde":
1205 this_player()->move("/gilden/abenteurer",M_GO,"in die Gilde");
1206 return 1;
1207 case "raus":
1208 this_player()->move(environment(),M_GO,"raus");
1209 return 1;
1210 }
1211 if (!IS_WIZARD(this_interactive()))
1212 return 0;
1213 if (verb!="merlin")
1214 return 0;
1215 delay=1;
1216 exits=(mapping)environment()->QueryProp(P_EXITS);
1217 if (!str||str=="")
1218 {
1219 ex=m_indices(exits);
1220 printf(environment()->int_short(ME,ME));
1221 show_exits();
1222 return 1;
1223 }
1224 if (old_explode(str," ")[0]=="sag")
1225 return sag(implode(old_explode(str," ")[1..]," "));
1226 if (str[0]==';')
1227 {
1228 tell_room(environment(ME),"Merlins "+str[1..]+"\n");
1229 tell_room(ME,"*Merlins "+str[1..]+"\n");
1230 return 1;
1231 }
1232 if (str[0]==':')
1233 {
1234 tell_room(environment(ME),"Merlin "+str[1..]+"\n");
1235 tell_room(ME,"*Merlin "+str[1..]+"\n");
1236 return 1;
1237 }
1238 if (str[0]=='*')
1239 {
1240 goto(str[1..]);
1241 printf(environment()->int_short(ME,ME));
1242 show_exits();
1243 return 1;
1244 }
1245 if (!exits[str])
1246 return 0;
1247 move(exits[str],0);
1248 write("Merlin sagt: Jawoll, Chef.\n");
1249 printf(environment()->int_short(ME,ME));
1250 show_exits();
1251 return 1;
1252}
1253
1254int goto(mixed dest)
1255{
1256 object ob;
1257 string path;
1258 mixed ret;
1259
1260 if (busy) {
1261 write("Merlin mault: Ich bin beschaeftigt.\n");
1262 return 1;
1263 }
1264
1265 if (!dest) {
1266 write("Wohin moechtest Du Merlin bringen ?\n");
1267 return 1;
1268 }
1269 ob = find_living(dest);
1270 if (ob) {
1271 ob = environment(ob);
1272 move(object_name(ob),0);
1273 return 1;
1274 }
1275 path=(mixed)"secure/master"->_get_path(dest,getuid(this_player()));
1276 ret=catch(load_object(path);publish);
1277 if (ret && file_size(path)<0)
1278 {
1279 dest=match_living(dest,1);
1280 if (stringp(dest))
1281 {
1282 ob = environment(find_living(dest));
1283 move(object_name(ob),M_TPORT|M_NOCHECK);
1284 return 1;
1285 }
1286 printf("Fehler beim Teleport nach %O: No such file.\n",path);
1287 return 1;
1288 }
1289 if (ret)
1290 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1291 ret=catch(move(path,M_TPORT|M_NOCHECK);publish);
1292 if (stringp(ret))
1293 ret=implode(old_explode(ret,"\n"),"");
1294 if (ret)
1295 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1296 return 1;
1297}
1298
1299mixed locate_objects(string complex_desc)
1300{
1301 object ob;
1302
1303 if (complex_desc=="alles" || complex_desc=="alle")
1304 return filter_objects(all_inventory(this_object()),"short");
1305 if (ob = present(complex_desc,this_object()) )
1306 return ({ ob });
1307 return ({}) ;
1308}
1309
1310void MBanishInsert(string name, string grund, object wer)
1311{
1312 if ( !name || !stringp(name) || !sizeof(name) ||
1313 !grund || !stringp(grund) || !sizeof(grund) ||
1314 !wer || !objectp(wer) || getuid(wer) != secure_euid() ||
1315 !IS_DEPUTY(wer) )
1316 return;
1317
1318 MBanishListe += ([name:grund;getuid(wer)]);
1319 save_object(SAVEFILE);
1320}
1321
1322mapping MBanishList()
1323{
1324 if ( !IS_DEPUTY(secure_euid()) )
1325 return 0;
1326
1327 return deep_copy(MBanishListe);
1328}
1329
1330void MBanishDelete(string name)
1331{
1332 if ( !name || !stringp(name) || !sizeof(name) || !ARCH_SECURITY )
1333 return 0;
1334
1335 MBanishListe = m_copy_delete( MBanishListe, name );
1336 save_object(SAVEFILE);
1337}
1338
1339string _query_noget()
1340{
1341 return "Merlin mag das nicht!\n";
1342}
1343