blob: 3075bec08ebba460bbb77ada0ff08bd05f8e1992 [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
576 if (!name || name=="" ||
577 catch(s=file_size("save/"+name[0..0]+"/"+name+".o");publish)
578 || s<=0 )
579 return;
580
581 if (name!=getuid(this_interactive()) && !ARCH_SECURITY)
582 {
583 if (flag==getuid(this_interactive())+"##"+name)
584 return;
585 call_out("do_say",0,"Merlin sagt: "+capitalize(getuid(this_interactive()))+" hat gerade so getan, als wuerde "+capitalize(name)+" etwas sagen!\n");
586 flag=getuid(this_interactive())+"##"+name;
587 call_out("clear_flag",0);
588 return;
589 }
590 flag=0;
591 for (i=0;i<sizeof(whitespaces);i++)
592 {
593 message=old_explode(message,whitespaces[i]);
594 if (!pointerp(message)||sizeof(message)==0)
595 return;
596 message=implode(message," ");
597 }
598
599 message=old_explode(message," ");
600
601 if (!pointerp(message) || !sizeof(message))
602 return;
603
604 message-=({0})-({""});
605
606 if (!message || sizeof(message)==0)
607 return;
608
609 if (member(message, "merlin")==-1)
610 return;
611
612 message-=({"merlin"});
613
614 message=implode(message," ");
615
616 if (!message || message=="")
617 return;
618
619 determine_action(message, name);
620}
621
622static int determine_action(string mess, string name)
623{
624 string str;
625
626 if (mess=="mach mich zum magier" || mess=="mach mich zur magierin")
627 return create_wizard(name,name);
628
629 if (sscanf(mess,"mach %s zum magier",str)==1||sscanf(mess,"mach %s zur magierin",str)==1)
630 return create_wizard(lower_case(str),name);
631
632 give_help(name);
633 return 0;
634}
635
636#define Say(str) say(str,who)
637#define Write(str) tell_object(who,str)
638
639int QueryBedingungen(object pl,string was)
640{
641 int ret,i,gen;
642 string s;
643
644 if (IS_SEER(pl))
645 return 1;
646
647 if ((int)LEPMASTER->QueryReadyForWiz(pl)==1)
648 return 1;
649
650 s=(string)LEPMASTER->QueryReadyForWizText(pl);
651
652 tell_object(pl, break_string("Merlin gruebelt ein wenig und teilt Dir "
653 "nach einigem Ueberlegen mit:\n\n", 78,0,1));
654
655 tell_object(pl, s+"\n");
656
657 tell_object(pl, break_string("Da ist wohl fuer Dich noch etwas zu tun...",
658 78, "Merlin teilt Dir mit: "));
659
660 if (environment() == environment(pl))
661 say((string)pl->name(WER)
662 +" erfuellt noch nicht alle Anforderungen fuer den "+was+"status.\n",pl);
663
664 return 0;
665}
666
667static int create_wizard(mixed who, mixed promoter)
668{
669 mixed *domains;
670 object vertrag;
671 int ret;
672 string gen;
673
674 who=find_player(who);
675 promoter=find_player(promoter);
676 if (!who || !promoter)
677 return 0;
678 //
679 // player not interactive?
680 //
681 if (!interactive(who))
682 {
683 write(capitalize(getuid(who))+" ist nicht aktiv.\n");
684 return 0;
685 }
686 //
687 // player is second?
688 //
689 if (who->QueryProp(P_SECOND))
690 {
691 tell_object(who,"Du bist ein Zweitspieler und kannst als solcher kein Magier werden.\n"
692 +"Versuchs Doch mal mit Deinem Erstie.\n");
693 write("Du kannst "+who->name()+" nicht zum Magier machen. Das geht bei "
694 +"Zweities\nleider nicht. Frag doch mal nach dem Erstie.\n");
695 return 1;
696 }
697 //
698 // wants to advance himself?
699 //
700 if (who==promoter)
701 {
702 write("Du kannst Dich nicht selber befoerdern. Such Dir dazu bitte einen "+
703 "Vollmagier,\nder Dir einen Vertrag gibt.\n");
704 return 1;
705 }
706 //
707 // banished?
708 //
709 if (MBanishListe[who,1])
710 {
711 tell_object(promoter,capitalize(who)+" darf nur von einem Erzmagier zum "+
712 "Magier gemacht werden.\n");
713 say(promoter->name(WER)+" ist kein Erzmagier und darf "+capitalize(who)+
714 " nicht zum Magier machen.\n");
715 return 1;
716 }
717 //
718 // player has PK?
719 //
720 if (who->QueryProp("playerkills")) {
721 tell_room(environment(who),who->name()+" hat noch einen Playerkill und kann somit kein Magier werden.\n"
722 "Am besten den Sheriff oder einen Erzmagier verstaendigen.\n");
723 return 1;
724 }
725 //
726 // already dom_member?
727 //
728 if (IS_DOMAINMEMBER(who))
729 {
730 Write("Fuer Dich kann ich nichts mehr tun. Du bist doch schon Magier!\n");
731 return 1;
732 }
733
734 //
735 // "advanced learner"?
736 //
737 if (query_wiz_level(who) == 20)
738 {
739 if (!ARCH_SECURITY) {
740 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
741 Say("Nur ein Erzmagier kann "+who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
742 return 0;
743 }
744 ret=(int)"secure/master"->advance_wizlevel(geteuid(who),21);
745 if (ret<=0)
746 {
747 say("Merlin: error "+ret+"\n");
748 write("Merlin: error "+ret+"\n");
749 }
750 write("Merlin ruft: "+(string)who->name(WER)+" ist in den Kreis der Magier "+
751 "aufgenommen worden!\n");
752 shout("Merlin ruft: "+(string)who->name(WER)+" ist in den Kreis der Magier "+
753 "aufgenommen worden!\n");
754 "secure/master"->renew_player_object(who);
755 return 1;
756 }
757
758 //
759 // already wizard?
760 //
761 if (IS_WIZARD(who))
762 {
763 domains=(string*)"secure/master"->get_domain_homes(getuid(who));
764 if (!domains || !pointerp(domains) || !sizeof(domains))
765 {
766 Say(who->name(WER)+" gehoert noch keiner Region an und kann daher noch "+
767 "kein Voll-\nmagier werden.\n");
768 Write("Du gehoerst noch keiner Region an. Schliess Dich zunaechst einer "+
769 "an und komm\ndann wieder!\n");
770 return 0;
771 }
772 ret=(int)"secure/master"->advance_wizlevel(geteuid(who),25);
773 if(ret>0)
774 {
775 shout(who->name(WER)+" arbeitet jetzt an einer Region mit!\n");
776 "secure/master"->renew_player_object(who);
777 return 1;
778 }
779 write("RETURNVALUE "+ret+"\n");
780 say("RETURNVALUE "+ret+"\n");
781 return 0;
782 }
783
784 //
785 // still learner?
786 //
787 if (IS_LEARNER(who))
788 {
789 if (!ARCH_SECURITY) {
790 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
791 Say("Nur ein Erzmagier kann "+who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
792 return 0;
793 }
794 ret=(int)"secure/master"->advance_wizlevel(geteuid(who),20);
795 if (ret<=0)
796 {
797 say("Merlin: error "+ret+"\n");
798 write("Merlin: error "+ret+"\n");
799 }
800 string wizname = (string)who->query_real_name();
801 "secure/master"->renew_player_object(who);
802 // Fehlerteufel geben
803 call_out(#'GibFehlerteufel,4,find_player(wizname));
804 return 1;
805 }
806
807 //
808 // promoter's level is not >DOMAINMEMBER_LVL+1
809 //
810 if (secure_level()<=DOMAINMEMBER_LVL)
811 {
812 tell_object(promoter,"Du musst derzeit mindestens Level "+
813 (DOMAINMEMBER_LVL+1)+" haben, um jemanden befoerden zu "+
814 "koennen.\n");
815 say(promoter->name(WER)+" ist kein Vollmagier und darf daher niemanden "+
816 "zum Vollmagier machen.\n");
817 return 1;
818 }
819
820 // der Check auf den Blutprintnamen ist fast ueberfluessig, aber nur fast.
821 // Er schlaegt fehl, wenn der Vertrag der Clone einer alten BP ist.
822 if (!(vertrag=present_clone("/obj/vertrag",who)) ||
823 object_name(blueprint(vertrag))!="/obj/vertrag" ||
824 !((int)vertrag->is_unterschrieben()) )
825 {
826 Write("Du hast ja gar keinen unterschriebenen Vertrag bei Dir. Besorg Dir "+
827 "einen Ver-\ntrag, unterschreibe ihn und komm dann wieder!\n");
828 Say(who->name(WER)+" hat keinen unterschriebenen Vertrag.\n");
829 return 1;
830 }
831 if (geteuid(vertrag)!=secure_euid())
832 {
833 tell_object(promoter,"Das geht nicht, er hat einen Vertrag von "+
834 capitalize(geteuid(vertrag))+" bei sich.\n");
835 say(promoter->name(WER)+" versucht, "+who->name(WER)+" zum Magier zu "+
836 "machen, doch "+who->name(WER)+" hat einen Vertrag\nvon "+
837 capitalize(geteuid(vertrag))+" bei sich.\n",promoter);
838 return 0;
839 }
840 if (!QueryBedingungen(who,"Magier"))
841 return 0;
842 ret=(int)"secure/master"->advance_wizlevel(geteuid(who),15);
843 if (ret>0)
844 {
845 PostMagier(capitalize(getuid(who)),
846 capitalize(secure_euid()),(int)who->QueryProp(P_GENDER));
847 write_file("/log/SPONSOR",dtime(time())+": "+capitalize(getuid(promoter))+" macht "+
848 who->name(WER)+" zum Learner.\n");
849 write(who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
850 shout(who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
851 if ("secure/master"->set_player_object(geteuid(who),"/std/shells/magier")
852 <=0)
853 {
854 say("MERLIN: konnte Magiershell nicht einstellen.\n");
855 write("MERLIN: konnte Magiershell nicht einstellen.\n");
856 }
857 "secure/master"->renew_player_object(who);
858 return 1;
859 }
860 write(" --RETURNVALUE IS "+ret+"\n");
861 say(" --RETURNVALUE IS "+ret+"\n");
862
863 return(ret); //non-void funktion
864}
865
866void clear_flag()
867{
868 flag=0;
869}
870
871void do_say(string str)
872{
873 say(str);
874}
875
876
877
878void seer_sequenz3(mixed player, string plname)
879{
880 string playername;
881 object faq;
882 string text;
883
884 if (!objectp(player)) {
885 tell_room(environment(), sprintf("Merlin sagt: Na, wo ist denn %s "
886 "hin?\n", plname));
887 busy = 0;
888 return;
889 }
890 if (environment() != environment(player))
891 move(environment(player), M_TPORT);
892
893 tell_object(player,break_string("\n\nEs macht *PUFF* und eine Schwefelwolke "
894 +"steigt um Dich herum auf.\n\nDie Aura "
895 +"verschwindet langsam und Du fuehlst Dich "
896 +"nun viel erfahrener.", 78,0,1));
897 tell_room(environment(),
898 break_string(sprintf(
899 "\n\nEs macht *PUFF* und eine Schwefelwolke steigt "
900 +"um %s herum auf.\n\nDie Aura verschwindet langsam.\n",
901 plname),78,0,1), ({player}));
902
903 if ("secure/master"->advance_wizlevel(geteuid(player),1)<=0)
904 {
905 write("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
906 say("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
907 busy = 0;
908 return;
909 }
910 playername = geteuid(player);
911 "secure/master"->renew_player_object(player);
912 player = find_player(playername);
913 text = sprintf(" ist jetzt ein%s Seher%s!\n",
914 (((int)player->QueryProp(P_GENDER))==2?"e":""),
915 (((int)player->QueryProp(P_GENDER))==2?"in":""));
916 write("Merlin ruft: "+capitalize(playername)+text);
917 shout("Merlin ruft: "+capitalize(playername)+text);
918 PostSeher(capitalize(playername),(int)player->QueryProp(P_GENDER));
919 if(!catch(
920 faq=clone_object("/d/seher/haeuser/special/seherfaqmobil") ;publish))
921 {
922 faq->move(player,M_NOCHECK);
923 tell_object(player, "Aus dem Nichts erscheint eine kleine Belohnung fuer Dich.\n");
924 }
925
926 tell_object(player, "\n\nDu laechelst gluecklich in die Runde.\n\n");
927 tell_room(environment(), sprintf("\n\n%s laechelt gluecklich in die Runde.\n\n", plname), ({player}));
928
929 busy=0;
930}
931
932void seer_sequenz2(mixed player, string plname)
933{
934 if (!objectp(player)) {
935 tell_room(environment(), sprintf(
936 "Merlin sagt: Na, wo ist denn %s hin?\n",
937 plname));
938 busy = 0;
939 return;
940 }
941 if (environment() != environment(player))
942 move(environment(player), M_TPORT);
943
944 tell_object(player, break_string("\nMerlin hebt die Arme und "
945 +"und macht einige beschwoerende Gesten. Um Dich herum erscheint "
946 +"eine gelbliche Aura, die immer heller wird, bis Du Deine "
947 +"Umwelt kaum mehr erkennen kannst.\n\n",
948 78,0,1));
949 tell_room(environment(),
950 break_string(sprintf("\nMerlin hebt die Arme und macht einige "
951 +"beschwoerende Gesten. Um %s erscheint eine "
952 +"gelbliche Aura, die immer heller wird, bis "
953 +"man %s kaum mehr erkennen kann.\n\n",
954 plname, plname),78,0,1), ({player}));
955
956 call_out("seer_sequenz3", 7, player, plname);
957}
958
959void seer_sequenz1(mixed player, string plname)
960{
961 if (!objectp(player))
962 return;
963
964 move(environment(player), M_TPORT);
965
966 tell_room(environment(),
967 break_string(sprintf("Das ist eine grosse Freude. %s hat sich "
968 "tapfer durch das "MUDNAME" geschlagen und mittlerweile alle "
969 "Anforderungen erfuellt, um %s zu werden.",
970 plname, ((int)player->QueryProp(P_GENDER))==1?"Seher":"Seherin"),
971 78, "Merlin sagt: "));
972
973 call_out("seer_sequenz2", 4, player, plname);
974}
975
976
977static int create_seer(mixed player)
978{
979 if (!objectp(player))
980 return 0;
981 if (IS_SEER(player))
982 {
983 write(break_string("Du bist doch schon kein normaler Spieler mehr, "
984 +"was soll es also?", 78, "Merlin teilt Dir mit: "));
985 return 1;
986 }
987
988 if (!QueryBedingungen(player,"Seher"))
989 return -1;
990
991
992 write(break_string("Grosse Freude! Du hast alle Anforderungen "
993 "erfuellt. Warte einen Moment...", 78,
994 "Merlin teilt Dir mit: "));
995 busy=1;
996 call_out("seer_sequenz1",4,player, player->Name());
997 return(0); //non-void funktion
998}
999
1000static void give_help(mixed player)
1001{
1002 if (!objectp(player))
1003 return;
1004
1005 tell_object(player,
1006 break_string("Ich weiss nicht, was ich fuer Dich tun kann. "
1007 +"Ich kann Dich zum Seher oder zum Magier "
1008 +"machen, wenn Du mich darum bittest.", 78,
1009 "Merlin teilt Dir mit: "));
1010}
1011
1012
1013void reset()
1014{
1015}
1016
1017public int remove(int silent) {
1018 EVENTD->UnregisterEvent(EVT_LIB_LOGIN, ME);
1019 EVENTD->UnregisterEvent(EVT_LIB_PLAYER_CREATION, ME);
1020 destruct(this_object());
1021 return 1;
1022}
1023
1024void wandern()
1025{
1026 mapping ex,rooms;
1027 mixed ziel;
1028 object *raeume,*laeden,env,ob;
1029 string *ind,fn;
1030 int i;
1031
1032 while (remove_call_out("wandern")>=0);
1033 call_out("wandern",45+random(100));
1034 if (busy) return;
1035 if (delay)
1036 {
1037 delay=0;
1038 return;
1039 }
1040 if (!(env=environment()))
1041 {
1042 move("/gilden/abenteurer",0);
1043 env=environment();
1044 }
1045 //ueber Inv iterieren, ob da ein nicht-idelnder Spieler mit genug XP
1046 //rumhaengt.
1047 raeume=all_inventory(env);
1048 for(i=sizeof(raeume); i-- ; ) {
1049 if (interactive(raeume[i]) && query_idle(raeume[i])<180 &&
1050 raeume[i]->QueryProp(P_XP)>999999)
1051 return;
1052 }
1053 ex=(mapping)env->QueryProp(P_EXITS);
1054 if (!mappingp(ex))
1055 return;
1056 ind=m_indices(ex);rooms=([]);laeden=({});
1057 for (i=sizeof(ind)-1;i>=0;i--)
1058 {
1059 if (!stringp(ziel=ex[ind[i]]))
1060 continue;
1061 if (!ob=find_object(ziel))
1062 continue;
1063 rooms+=([ob]);
1064 }
1065 rooms-=([env]);
1066 if (prev_room && sizeof(m_indices(rooms))>1)
1067 rooms-=([prev_room]);
1068 prev_room=env;
1069 raeume=m_indices(rooms);
1070 if (!i=sizeof(raeume))
1071 return;
1072 ob=raeume[random(i)];
1073 move(ob,0);
1074}
1075
1076string int_short()
1077{
1078 return "Du bist im allseits beliebten Wizclub \"Zum lustigen Merlin\".\n";
1079}
1080
1081string int_long(object who,mixed where)
1082{
1083 string descr;
1084
1085 if( IS_LEARNER(who) && who->QueryProp( P_WANTS_TO_LEARN ) )
1086 descr = "[" + object_name(ME) + "]\n";
1087 else
1088 descr = "";
1089 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";
1090 if ( who->QueryProp(P_SHOW_EXITS) )
1091 descr += "Es gibt 2 sichtbare Ausgaenge: raus und gilde.\n";
1092 descr += make_invlist(who, all_inventory(ME) - ({ who }));
1093 if( environment())
1094 descr += "\nAusserhalb siehst Du:\n"
1095 + environment()->int_short(who,ME);
1096 return descr;
1097}
1098
1099string make_invlist(object viewer,object *inv)
1100{
1101 int i, iswiz;
1102 string descr;
1103
1104 descr = "";
1105 iswiz = IS_LEARNER( viewer ) && viewer->QueryProp(P_WANTS_TO_LEARN);
1106
1107 for (i = 0; i < sizeof(inv); i++)
1108 {
1109 string sh;
1110 sh = (string)inv[i]->short();
1111 if (iswiz)
1112 {
1113 if (sh) sh = sh[0..<2] + " ["+object_name(inv[i])+"]\n";
1114 else sh = "["+object_name(inv[i])+"]\n";
1115 }
1116 if (sh) descr += sh;
1117 }
1118 return descr;
1119}
1120
1121void init()
1122{
1123 if (interactive(this_player()) && environment(this_player())==ME)
1124 add_action("gehen","",1);
1125 add_action("befoerdere","befoerder",1);
1126}
1127
1128int befoerdere(string str)
1129{
1130 string wen;
1131 int ret,stufe,l;
1132
1133 if (!LORD_SECURITY) return 0;
1134 if (!str||sscanf(str,"%s auf stufe %d",wen,stufe)<2)
1135 {
1136 notify_fail("Syntax: befoerdere <name> auf stufe <stufe>\n");
1137 return 0;
1138 }
1139 if (stufe>29)
1140 {
1141 write("Maximum ist Stufe 29!\n");
1142 return 1;
1143 }
1144 l=query_wiz_level(wen);
1145 if (l<25)
1146 {
1147 printf("%s muss mindestens zwecks Weiterbefoerderung mindestens Stufe 25 haben.\n",
1148 capitalize(wen));
1149 return 1;
1150 }
1151 if (l>=stufe)
1152 {
1153 printf("%s ist schon Stufe %d.\n",capitalize(wen),l);
1154 return 1;
1155 }
1156 ret=(int)"secure/master"->advance_wizlevel(wen,stufe);
1157 if (ret<=0)
1158 printf("Errorcode %d\n",ret);
1159 else
1160 write("ok\n");
1161 return 1;
1162}
1163
1164int sag(mixed str)
1165{
1166 int i;
1167
1168 if (str==0)
1169 str="";
1170 str = old_explode(break_string(str, 60 ), "\n");
1171 if (busy) {
1172 tell_room(ME, "Merlin mault: Ich bin beschaeftigt.\n");
1173 return 0;
1174 }
1175 for (i = 0; i < sizeof(str); i++)
1176 {
1177 if (!str[i])
1178 str[i]="";
1179 tell_room(environment(),"Merlin sagt: "+str[i]+"\n");
1180 tell_room(ME,"*Merlin sagt: "+str[i]+"\n");
1181 }
1182 return 1;
1183}
1184
1185void show_exits()
1186{
1187 printf("%s",environment()->GetExits());
1188}
1189
1190int gehen(string str)
1191{
1192 string verb;
1193 int i;
1194 mapping exits;
1195 string *ex;
1196
1197 if (busy) {
1198 write("Merlin mault: Ich bin beschaeftigt.\n");
1199 return 0;
1200 }
1201
1202 verb=query_verb();
1203 str=(string)this_interactive()->_unparsed_args();
1204 switch (verb)
1205 {
1206 case "gilde":
1207 this_player()->move("/gilden/abenteurer",M_GO,"in die Gilde");
1208 return 1;
1209 case "raus":
1210 this_player()->move(environment(),M_GO,"raus");
1211 return 1;
1212 }
1213 if (!IS_WIZARD(this_interactive()))
1214 return 0;
1215 if (verb!="merlin")
1216 return 0;
1217 delay=1;
1218 exits=(mapping)environment()->QueryProp(P_EXITS);
1219 if (!str||str=="")
1220 {
1221 ex=m_indices(exits);
1222 printf(environment()->int_short(ME,ME));
1223 show_exits();
1224 return 1;
1225 }
1226 if (old_explode(str," ")[0]=="sag")
1227 return sag(implode(old_explode(str," ")[1..]," "));
1228 if (str[0]==';')
1229 {
1230 tell_room(environment(ME),"Merlins "+str[1..]+"\n");
1231 tell_room(ME,"*Merlins "+str[1..]+"\n");
1232 return 1;
1233 }
1234 if (str[0]==':')
1235 {
1236 tell_room(environment(ME),"Merlin "+str[1..]+"\n");
1237 tell_room(ME,"*Merlin "+str[1..]+"\n");
1238 return 1;
1239 }
1240 if (str[0]=='*')
1241 {
1242 goto(str[1..]);
1243 printf(environment()->int_short(ME,ME));
1244 show_exits();
1245 return 1;
1246 }
1247 if (!exits[str])
1248 return 0;
1249 move(exits[str],0);
1250 write("Merlin sagt: Jawoll, Chef.\n");
1251 printf(environment()->int_short(ME,ME));
1252 show_exits();
1253 return 1;
1254}
1255
1256int goto(mixed dest)
1257{
1258 object ob;
1259 string path;
1260 mixed ret;
1261
1262 if (busy) {
1263 write("Merlin mault: Ich bin beschaeftigt.\n");
1264 return 1;
1265 }
1266
1267 if (!dest) {
1268 write("Wohin moechtest Du Merlin bringen ?\n");
1269 return 1;
1270 }
1271 ob = find_living(dest);
1272 if (ob) {
1273 ob = environment(ob);
1274 move(object_name(ob),0);
1275 return 1;
1276 }
1277 path=(mixed)"secure/master"->_get_path(dest,getuid(this_player()));
1278 ret=catch(load_object(path);publish);
1279 if (ret && file_size(path)<0)
1280 {
1281 dest=match_living(dest,1);
1282 if (stringp(dest))
1283 {
1284 ob = environment(find_living(dest));
1285 move(object_name(ob),M_TPORT|M_NOCHECK);
1286 return 1;
1287 }
1288 printf("Fehler beim Teleport nach %O: No such file.\n",path);
1289 return 1;
1290 }
1291 if (ret)
1292 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1293 ret=catch(move(path,M_TPORT|M_NOCHECK);publish);
1294 if (stringp(ret))
1295 ret=implode(old_explode(ret,"\n"),"");
1296 if (ret)
1297 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1298 return 1;
1299}
1300
1301mixed locate_objects(string complex_desc)
1302{
1303 object ob;
1304
1305 if (complex_desc=="alles" || complex_desc=="alle")
1306 return filter_objects(all_inventory(this_object()),"short");
1307 if (ob = present(complex_desc,this_object()) )
1308 return ({ ob });
1309 return ({}) ;
1310}
1311
1312void MBanishInsert(string name, string grund, object wer)
1313{
1314 if ( !name || !stringp(name) || !sizeof(name) ||
1315 !grund || !stringp(grund) || !sizeof(grund) ||
1316 !wer || !objectp(wer) || getuid(wer) != secure_euid() ||
1317 !IS_DEPUTY(wer) )
1318 return;
1319
1320 MBanishListe += ([name:grund;getuid(wer)]);
1321 save_object(SAVEFILE);
1322}
1323
1324mapping MBanishList()
1325{
1326 if ( !IS_DEPUTY(secure_euid()) )
1327 return 0;
1328
1329 return deep_copy(MBanishListe);
1330}
1331
1332void MBanishDelete(string name)
1333{
1334 if ( !name || !stringp(name) || !sizeof(name) || !ARCH_SECURITY )
1335 return 0;
1336
1337 MBanishListe = m_copy_delete( MBanishListe, name );
1338 save_object(SAVEFILE);
1339}
1340
1341string _query_noget()
1342{
1343 return "Merlin mag das nicht!\n";
1344}
1345