blob: f16b8c3689fabdddc888a12cebb2545ebba6a67c [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.
Arathornd5c9c022020-01-08 22:04:28 +010017inherit "/std/npc/comm.c";
MG Mud User88f12472016-06-24 23:31:02 +020018
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"
Zesstra2f85ed72020-04-21 01:28:08 +020033#include <userinfo.h>
MG Mud User88f12472016-06-24 23:31:02 +020034
35#ifndef DEBUG
36#define DEBUG(x) if (find_player("zook")) tell_object(find_player("zook"),x)
37#endif
38
39#define SAVEFILE "/secure/ARCH/merlin"
40#define BS(x) break_string((x),78)
41#define FEHLERTEUFEL "/obj/tools/fehlerteufel"
42
43mixed QueryProp(string prop);
44int move(mixed dest, int method);
45string query_g_suffix(int gen, int casus, int anzahl);
46string make_invlist(object viewer,object *inv);
47static int determine_action(string mess, string name);
48static int create_wizard(mixed who, mixed promoter);
Zesstrab16348b2019-05-21 19:41:36 +020049static int create_seer(object who);
MG Mud User88f12472016-06-24 23:31:02 +020050static void give_help(mixed who);
51int goto(mixed dest);
Zesstra2f85ed72020-04-21 01:28:08 +020052public string wiztree_html();
MG Mud User88f12472016-06-24 23:31:02 +020053
54nosave string *whitespaces=({",",".","?",";",":","-","!","\n","\t"});
Zesstra1b6b7362019-04-25 14:08:02 +020055nosave string prev_room;
MG Mud User88f12472016-06-24 23:31:02 +020056nosave int delay,maxusers,busy;
57nosave string flag;
58
59mapping MBanishListe;
60
61void create()
62{
63 string s;
64 seteuid(ROOTID);
65 if (file_size("/etc/maxusers")<=0)
66 maxusers=0;
67 else
68 {
69 s=read_file("/etc/maxusers",0,1);
70 sscanf(s,"%d",maxusers);
71 }
72 set_living_name("merlin");
73 enable_commands();
74 call_out("wandern",25);
75 move("/gilden/abenteurer",0);
76 MBanishListe = m_allocate(0,2);
77 restore_object(SAVEFILE);
bugfixd94d0932020-04-08 11:27:13 +020078 ({int})EVENTD->RegisterEvent(EVT_LIB_PLAYER_CREATION, "player_change", ME);
79 ({int})EVENTD->RegisterEvent(EVT_LIB_LOGIN, "player_change", ME);
MG Mud User88f12472016-06-24 23:31:02 +020080 // absichtlich kein EVT_LIB_LOGOUT, s. Kommentar zu notify_player_leave().
81}
82
83string _query_kill_name()
84{
85 return "Ein genervter Merlin";
86}
87
88int move(mixed ob,int methods)
89{
90 object tmp;
91
92 if (methods&M_GET)
93 return ME_CANT_BE_TAKEN;
94
95 if (stringp(ob))
96 {
97 if (!(tmp=find_object(ob)))
98 {
99 call_other(ob,"?");
100 tmp=find_object(ob);
101 }
102 ob=tmp;
103 }
104 if (!objectp(ob))
105 return 0;
106 if (environment())
107 tell_room(environment(),"Merlin zieht weiter.\n");
108 tell_room(ob,"Merlin kommt an.\n");
109 move_object(ob);
110 return 1;
111}
112
113mixed QueryProp(string str)
114{
115 if (!stringp(str)||str=="")
116 return 0;
bugfixd94d0932020-04-08 11:27:13 +0200117 return ({mixed})call_other(this_object(),"_query_"+str);
MG Mud User88f12472016-06-24 23:31:02 +0200118}
119
120varargs int id(string str)
121{
122 return (str=="merlin");
123}
124
125varargs string name(int casus, int demon)
126{
127 if (casus!=WESSEN)
128 return "Merlin";
129 return "Merlins";
130}
131
132varargs string Name(int casus, int daemon)
133{
134 return name(casus,daemon);
135}
136
137string QueryDu(int casus, int gender, int zahl)
138{
139 return
140 ({ ({ ({ "du", "ihr"}), ({ "du", "ihr"}), ({ "du", "ihr"}) }),
141 ({({"deines","deiner"}),({"deines","deiner"}),({"deiner","deiner"})}),
142 ({({"dir","euch"}),({"dir","euch"}),({"dir","euch"})}),
143 ({({"dich","euch"}),({"dich","euch"}),({"dich","euch"})})
144 })[casus][gender][zahl];
145}
146
147string long()
148{
bugfixd94d0932020-04-08 11:27:13 +0200149 ({int})EPMASTER->GiveExplorationPoint("merlin");
MG Mud User88f12472016-06-24 23:31:02 +0200150 return break_string(
151 "Merlin - der maechtige Urvater aller Magier - ist ein hagerer "
152 "Mann, der einen blauen, mit Monden und Sternen uebersaeten Umhang "
153 "traegt und sich auf einen knorrigen Stock stuetzt. Sein langer weisser "
154 "Bart reicht ihm fast bis zur Guertelschnalle, sein Haupthaar ist fast "
155 "ebenso lang. Auf seinem Kopf traegt er einen spitzen Hut, der ihn noch "
156 "groesser macht, als er ohnehin schon ist.\nEr ist unangreifbar, denn "
157 "er steht ueber solchen Dingen.",78,BS_LEAVE_MY_LFS);
158}
159
160string GetDetail(string key,mixed race,int sense) {
161 switch( sense ) {
162 case SENSE_SMELL: return 0;
163 case SENSE_SOUND: return 0;
164 }
165 switch( key ) {
166 case "nase": case "nasenhaare": case "hakennase":
167 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.");
168 case "brille": case "glaeser": case "form": case "halbmond":
169 return "Merlins Brille besitzt Glaeser in Form eines Halbmondes.\n";
170 case "bart":
171 return "Merlins Bart ist sehr lang - Er reicht fast bis ueber die Guertelschnalle.\n";
172 case "haare" :
173 return "Sie reichen ihm bis zwischen die Schulterblaetter.\n";
174 case "schulterblaetter": case "schulterblatt":
175 return "Seine langen Haare bedecken die Schulterblaetter.\n";
176 case "gewand": case "robe":
177 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.");
178 case "zweck":
179 return BS("Der Zweck des Gewandes besteht darn, Merlin standesgemaess zu bekleiden. Diesem Zweck kommt das Gewand in Vollendung nach.");
180 case "vollendung":
181 return "Nichts ist vollkommen.\n";
182 case "hut":
183 return BS("Ein langer, spitzer Hut, der in der gleichen Weise wie seine Robe mit Monden und Sternen bestickt ist.");
184 case "mond": case "monde": case "stern": case "sterne":
185 return BS("Die Monde und die Sterne sind mit silbrigen Faeden gestickt, die das Licht funkelnd zurueckwerfen.");
186 case "faden": case "faeden":
187 return BS("Schwer zu sagen, woraus die Faeden sind. Mithril? "
188 "Mondsilber?");
189 case "licht": case "mondsilber": case "mithril":
190 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.");
191 case "abstand":
192 return BS("Von so einem Magier sollte man aus Respekt einen Schritt Abstand halten.");
193 case "respekt":
194 return "Du hast sicher mehr Respekt vor Merlin, als er vor Dir.\n";
195 case "schritt":
196 return "Wessen Schritt??\n";
197 case "hand": case "haende":
198 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.");
199 case "gichtknoten": case "gicht":
200 return BS("Durch die Gichtknoten sehen seine Haende fast so knorrig wie sein Gehstock aus.");
201 case "finger": case "fingernaegel": case "fingernagel":
202 return BS("Seine Finger sind voller Gichtknoten und seine gelben Fingernaegel koennte Merlin auch mal wieder schneiden.");
203 case "gehstock": case "stock":
204 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?");
205 case "zauberstab": case "magierstab":
206 return BS("Merlin stuetzt sich auf einen knorrigen Gehstock. Das koennte sein Zauberstab sein - aber vielleicht ist es auch nur ein Gehstock.");
207 case "guertel": case "guertelschnalle":
208 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.'");
209 }
210 return 0;
211}
212
213
214string short()
215{
216 return "Merlin, der Urvater aller Magier.\n";
217}
218
219string _query_race()
220{
221 return "Magier";
222}
223
224int _query_gender()
225{
226 return 1;
227}
228
229string QueryPossPronoun( mixed what, int casus, int number )
230{
231 int gen2;
bugfixd94d0932020-04-08 11:27:13 +0200232 gen2 = ( intp( what ) ) ? what : ({int})what->QueryProp(P_GENDER);
MG Mud User88f12472016-06-24 23:31:02 +0200233 return "sein" + query_g_suffix( gen2, casus, number );
234}
235
236string query_g_suffix( int gen, int casus, int anzahl )
237{
238 return ({ ({ ({"","e"}), ({"es","er"}), ({"em","en"}), ({"","e"}) }),
239 ({ ({"","e"}), ({"es","er"}), ({"em","en"}), ({"en","e"}) }),
240 ({ ({"e","e"}), ({"er","er"}), ({"er","en"}), ({"e","e"}) }) })
241 [gen][casus][anzahl];
242}
243
244string QueryPronoun(int casus)
245{
246 switch(casus) {
247 case WER: return "er"; break;
248 case WEM: return "ihm";
249 }
250 return "ihn";
251}
252
253string _query_short()
254{
255 return short();
256}
257
258string _query_long()
259{
260 return long();
261}
262
263string _query_name()
264{
265 return "Merlin";
266}
267
268int _query_weight()
269{
270 return 75000;
271}
272
273static void PostSeher(string who, int g)
274{
275 mixed *art;
276
277 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)});
bugfixd94d0932020-04-08 11:27:13 +0200278 ({int})"/secure/news"->WriteNote(art,1);
MG Mud User88f12472016-06-24 23:31:02 +0200279}
280
281static void PostMagier(string who, string prom, int gender)
282{
283 mixed *art;
284
285 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,
286(gender==2?"r":"m"),(gender==2?"Tochter":"Sohn"))});
bugfixd94d0932020-04-08 11:27:13 +0200287 ({int})"/secure/news"->WriteNote(art,1);
MG Mud User88f12472016-06-24 23:31:02 +0200288}
289
290
291private void GibFehlerteufel(object wiz) {
292 if (!objectp(wiz))
293 return;
294
bugfixd94d0932020-04-08 11:27:13 +0200295 ({int})clone_object(FEHLERTEUFEL)->move(wiz, M_NOCHECK|M_GET);
MG Mud User88f12472016-06-24 23:31:02 +0200296 tell_object(wiz, break_string(
bugfixd94d0932020-04-08 11:27:13 +0200297 "Huhu "+({string})wiz->Name(WER) + "! Ich habe gesehen, dass Du keinen "
MG Mud User88f12472016-06-24 23:31:02 +0200298 "Fehlerteufel hast. Dieses Tool ist zum Debuggen von Fehlern im "
299 "Mud sehr praktisch. Bitte schau ihn Dir mal an. :-) Die Hilfe zum "
300 "Fehlerteufel kannst Du mit 'man fehlerteufel' lesen. BTW: Wenn "
301 "Du den Fehlerteufel nicht willst, kannst Du ihn zerstoeren, ich "
302 "werde Dich kein zweites Mal damit belaestigen.",78,
303 "Merlin teilt Dir mit: ")
304 + "Merlin ueberreicht Dir aus der Ferne einen knusprig gebratenen "
305 "Fehlerteufel.\n\n");
306}
307
308private void notify_player_change(string who,int rein)
309{
310 if (!stringp(who))
311 return;
312
313 // Max-user festhalten
314 if (file_size("/etc/maxusers")<=0)
315 maxusers=0;
316 if (sizeof(users())>=maxusers)
317 {
318 maxusers=sizeof(users());
319 write_file("etc/maxusers",sprintf("%d user: %s (%s)\n",
320 maxusers,dtime(time()),query_load_average()),1);
321 }
322
323 // allen Magiern ab Level 20, die keinen Fehlerteufel haben und deren
324 // letzter Logout vor "Die, 17. Mar 2009, 23:40:04" => 1237329604 war,
325 // einen Fehlerteufel clonen und nen Hiwneis mitteilen.
326 object ob = find_player(who);
327 if (ob && rein && IS_WIZARD(ob)
328 && !present_clone(FEHLERTEUFEL,ob)
bugfixd94d0932020-04-08 11:27:13 +0200329 && ({int})ob->QueryProp(P_LAST_LOGOUT) < 1237329604 )
MG Mud User88f12472016-06-24 23:31:02 +0200330 GibFehlerteufel(ob);
331}
332
333private void AnnounceNewPlayer(object pl) {
334
335 if (!pl || !interactive(pl))
336 return;
337
Zesstra31ae1582019-07-30 20:09:01 +0200338 // verzoegern, bis der Spieler wirklich fertig und in /d/ angekommen ist,
339 // weil dann der initiale Scroll abgeklungen ist und der Spieler die
340 // Willkommensmeldungen von Merlin und Spielern hoffentlich auch wahrnimmt.
341 if (!environment(pl)
342 || strstr(object_name(environment(pl)), "/"DOMAINDIR"/") != 0)
343 {
344 call_out(#'AnnounceNewPlayer,20,pl);
MG Mud User88f12472016-06-24 23:31:02 +0200345 return;
346 }
347
bugfixd94d0932020-04-08 11:27:13 +0200348 if (!({int})pl->QueryGuest()) {
Arathornd5c9c022020-01-08 22:04:28 +0100349 string plname = ({string})pl->Name(WER);
MG Mud User88f12472016-06-24 23:31:02 +0200350 CHMASTER->send("Anfaenger", this_object(),
351 sprintf("%s macht nun ebenfalls das Morgengrauen unsicher. "
352 "Herzlich Willkommen %s!", plname, plname)
353 );
354 }
355}
356
357// Kann bei reboot wieder raus... zesstra, 16.03.2007
358#if __BOOT_TIME__ < 1318110723
359#define BUGTIME 1318003200
360#define BUGFIXTIME 1318109421
361void renew_player(string plname, int force) {
362 object pl;
363 mixed err;
364
365 pl = find_player(plname);
366 if (!objectp(pl) || !query_once_interactive(pl)) return;
367
368 // jung oder alt genug, Abbruch. ;-)
369 if ((object_time(pl) > BUGFIXTIME)
370 || object_time(pl) < BUGTIME)
371 return;
372
373 if (get_eval_cost() < 1000000 || !force ) {
374 call_out("renew_player",8,plname,1);
375 tell_object(pl,break_string(sprintf("Huhu %s, um einen Bug in "
376 "Deinem Spielerobjekt zu beheben, wirst Du in ca. 8s "
377 "neugeladen. Bitte warte bis dahin ab und bleibe, wo "
bugfixd94d0932020-04-08 11:27:13 +0200378 "Du gerade bist.",({string})pl->Name()),78,"Merlin teilt Dir mit: "));
MG Mud User88f12472016-06-24 23:31:02 +0200379 return;
380 }
381
382 plname=getuid(pl);
383 tell_object(pl,break_string(sprintf("Huhu %s, um einen Bug in "
384 "Deinem Spielerobjekt zu beheben, wirst Du jetzt "
bugfixd94d0932020-04-08 11:27:13 +0200385 "neugeladen.",({string})pl->Name()),78,"Merlin teilt Dir mit: "));
MG Mud User88f12472016-06-24 23:31:02 +0200386
bugfixd94d0932020-04-08 11:27:13 +0200387 if (err=catch(({int})master()->renew_player_object(pl);publish)) {
MG Mud User88f12472016-06-24 23:31:02 +0200388 log_file("zesstra/failed_rewew.log",sprintf("%s: Fehler %O beim "
389 "Renew von %s\n",dtime(time()),err,plname));
390 tell_object(pl,break_string("Beim Neuladen Deines Spielerobjekts "
391 "gab es einen Fehler. Bitte wende Dich an einen EM.",78,
392 "Merlin teilt Dir mit: "));
393 }
394 else {
395 log_file("zesstra/renewed.log",sprintf("%s: %s wurde renewed.\n",
396 dtime(time()),plname));
397 if (objectp(find_player(plname)))
398 tell_object(find_player(plname),
399 break_string("Dein Spielerobjekt wurde neugeladen. Du "
400 "kannst jetzt normal weiterspielen. Falls Du etwas ungewoehnliches "
401 "bemerkst, melde Dich bitte bei einem Erzmagier. Viel Spass im "
402 "Spiel!",78, "Merlin teilt Dir mit: "));
403 }
404}
405#endif
406
407void player_change(string eid, object trigob, mixed data) {
408
409 if (!trigob || !interactive(trigob))
410 return;
411
412 switch(eid) {
413 case EVT_LIB_PLAYER_CREATION:
414 call_out(#'AnnounceNewPlayer, 5, trigob);
415 break;
416 case EVT_LIB_LOGIN:
417 notify_player_change(data[E_PLNAME],1);
418#if __BOOT_TIME__ < 1318110723
419 // Spieler evtl. renewen? Bei reboot raus (08.10.2011)
420 renew_player(data[E_PLNAME],0);
421#endif
422 break;
423 }
424}
425
426
427//besser P_NO_ATTACK als Defend()...
428mixed _query_no_attack() {
429 if (!living(PL) || !objectp(environment(PL)) ) return(1);
430
431 tell_room(environment(), "Merlin schimpft: Lass das!!!\n",({PL}));
432 tell_room(environment(),sprintf(
433 "Merlin gibt %s eine schallende Ohrfeige.\n",
Arathornd5c9c022020-01-08 22:04:28 +0100434 capitalize(({string})this_player()->name(WEM))), ({this_player()}));
MG Mud User88f12472016-06-24 23:31:02 +0200435 return("Merlin schimpft: Lass das!!!\n"
436 "Merlin gibt Dir eine schallende Ohrfeige.\n");
437}
438
439/*
440int Defend(int dam, string dam_type, int spell, object enemy)
441{
442 object en;
443 if (!en=previous_object() || !living(en))
444 en = this_player();
445 tell_room(environment(), "Merlin schimpft: Lass das!!!\n");
446 write("Merlin gibt Dir eine schallende Ohrfeige.\n");
447 say(sprintf("Merlin gibt %s eine schallende Ohrfeige.\n",
448 capitalize((string)this_player()->name(WEM))), this_player());
bugfixd94d0932020-04-08 11:27:13 +0200449 ({int})en->StopHuntFor(this_object(), 1);
MG Mud User88f12472016-06-24 23:31:02 +0200450}
451*/
452void shoutansw()
453{
454 object env,ti;
455 string *path;
456 string ans;
457
458 if (!(env=environment()))
459 return;
bugfixd94d0932020-04-08 11:27:13 +0200460 if (!(ti=this_interactive())||({int})ti->QueryProp(P_LEVEL)<19||({int})ti->QueryProp(P_GHOST))
MG Mud User88f12472016-06-24 23:31:02 +0200461 return;
462 tell_object(ti,"Du spuerst einen sengenden Schmerz.\n");
bugfixd94d0932020-04-08 11:27:13 +0200463 ({int})ti->do_damage( ({int})ti->QueryProp(P_HP) / 2 + 5);
464 if(({int})ti->QueryProp(P_GHOST)) return;
MG Mud User88f12472016-06-24 23:31:02 +0200465 ans="ich hab nicht die leiseste Idee, wo ich hier bin ...\n";
466 path=old_explode(object_name(env),"/");
467 if (path[0]=="d")
468 {
469 ans="werweisswo ..";
470 switch(path[1])
471 {
472 case "gebirge":
473 case "wald":
474 case "dschungel":
475 ans="im "+capitalize(path[1]);
476 break;
477 case "inseln":
478 ans="auf den Inseln";
479 break;
480 case "polar":
481 ans="im Polargebiet";
482 break;
483 case "unterwelt":
484 case "ebene":
485 case "wueste":
486 ans="in der "+capitalize(path[1]);
487 break;
488 case "vland":
489 ans="im Verlorenen Land";
490 break;
491 case "fernwest":
492 ans="in Fernwest";
493 break;
494 }
495 ans="ich bin "+ans+".\n";
496 }
497 if (path[0]=="players")
498 ans="ich hab mich verlaufen - ich schaetze, "+capitalize(path[1])+
499 " hat was damit zu tun...\n";
500 if (path[0]=="gilden") {
501 switch(path[1]) {
502 case "abenteurer":
503 ans="der Abenteurergilde";
504 break;
505 case "bierschuettler":
506 ans="der Bierschuettlergilde";
507 break;
508 case "chaos":
509 ans="der Gilde der Chaoten";
510 break;
511 case "kaempfer":
512 ans="der Kaempfergilde";
513 break;
514 case "karate":
515 ans="einem Karatedojo";
516 break;
517 case "klerus":
518 ans="einem Tempel der Kleriker";
519 break;
520 case "zauberer":
521 ans="der Akademie der Zauberer";
522 break;
523 default:
524 ans="irgendeiner Gilde";
525 }
526 ans="ich stehe in "+ans+".\n";
527 }
528 if( path[0]=="p" && path[1]=="verein" ) {
529 ans="ich stehe in Port Vain.";
530 }
bugfixd94d0932020-04-08 11:27:13 +0200531 if (!({int})this_interactive()->QueryProp(P_INVIS))
532 ans=({string})this_interactive()->Name(WER)+", "+ans;
MG Mud User88f12472016-06-24 23:31:02 +0200533 else ans=capitalize(ans);
534 call_out("myshout",0,break_string(ans, 78, "Merlin ruft: "));
535}
536
537void myshout(string s)
538{
539 write(s);
540 shout(s);
541}
542
543void catch_tell(string str)
544{
545 string name, dummy; mixed message;
546 int i,s;
547
548 if (!this_player())
549 return;
550
551 if (environment()==environment(this_player()) && previous_object()!=ME)
552 tell_room(this_object(),"*"+str);
553
554 if (this_player() != this_interactive())
555 return;
556
557 if (busy) {
558 tell_object(this_player(),
559 "Merlin teilt Dir mit: Ich bin beschaeftigt.\n");
560 return;
561 }
562
563 str=lower_case(str);
564
565 if ((strstr(str, "teilt dir mit:") != -1)
566 && (strstr(str, "wo bist du") !=-1)) {
567 shoutansw();
568 return;
569 }
570
571 if ((strstr(str, "teilt dir mit:") != -1) &&
572 ((strstr(str, "seher") != -1 || strstr(str, "seherin") != -1)))
573 {
574 create_seer(this_player());
575 return;
576 }
577
578 if (sscanf(str,"%s %s sagt: %s",dummy,name,message)!=3)
579 if (sscanf(str,"%s sagt: %s",name,message)!=2)
580 return;
581
bugfixd94d0932020-04-08 11:27:13 +0200582 if (!name || !sizeof(name) || !({int})master()->find_userinfo(name))
MG Mud User88f12472016-06-24 23:31:02 +0200583 return;
584
585 if (name!=getuid(this_interactive()) && !ARCH_SECURITY)
586 {
587 if (flag==getuid(this_interactive())+"##"+name)
588 return;
589 call_out("do_say",0,"Merlin sagt: "+capitalize(getuid(this_interactive()))+" hat gerade so getan, als wuerde "+capitalize(name)+" etwas sagen!\n");
590 flag=getuid(this_interactive())+"##"+name;
591 call_out("clear_flag",0);
592 return;
593 }
594 flag=0;
595 for (i=0;i<sizeof(whitespaces);i++)
596 {
597 message=old_explode(message,whitespaces[i]);
598 if (!pointerp(message)||sizeof(message)==0)
599 return;
600 message=implode(message," ");
601 }
602
603 message=old_explode(message," ");
604
605 if (!pointerp(message) || !sizeof(message))
606 return;
607
608 message-=({0})-({""});
609
610 if (!message || sizeof(message)==0)
611 return;
612
613 if (member(message, "merlin")==-1)
614 return;
615
616 message-=({"merlin"});
617
618 message=implode(message," ");
619
620 if (!message || message=="")
621 return;
622
623 determine_action(message, name);
624}
625
626static int determine_action(string mess, string name)
627{
628 string str;
629
630 if (mess=="mach mich zum magier" || mess=="mach mich zur magierin")
631 return create_wizard(name,name);
632
633 if (sscanf(mess,"mach %s zum magier",str)==1||sscanf(mess,"mach %s zur magierin",str)==1)
634 return create_wizard(lower_case(str),name);
635
636 give_help(name);
637 return 0;
638}
639
640#define Say(str) say(str,who)
641#define Write(str) tell_object(who,str)
642
643int QueryBedingungen(object pl,string was)
644{
645 int ret,i,gen;
646 string s;
647
648 if (IS_SEER(pl))
649 return 1;
650
bugfixd94d0932020-04-08 11:27:13 +0200651 if (({int})LEPMASTER->QueryReadyForWiz(pl)==1)
MG Mud User88f12472016-06-24 23:31:02 +0200652 return 1;
653
Arathornd5c9c022020-01-08 22:04:28 +0100654 s=({string})LEPMASTER->QueryReadyForWizText(pl);
MG Mud User88f12472016-06-24 23:31:02 +0200655
656 tell_object(pl, break_string("Merlin gruebelt ein wenig und teilt Dir "
657 "nach einigem Ueberlegen mit:\n\n", 78,0,1));
658
659 tell_object(pl, s+"\n");
660
661 tell_object(pl, break_string("Da ist wohl fuer Dich noch etwas zu tun...",
662 78, "Merlin teilt Dir mit: "));
663
664 if (environment() == environment(pl))
bugfixd94d0932020-04-08 11:27:13 +0200665 say(({string})pl->name(WER)
Arathornd5c9c022020-01-08 22:04:28 +0100666 +" erfuellt noch nicht alle Anforderungen fuer den "+was+
667 "status.\n",pl);
MG Mud User88f12472016-06-24 23:31:02 +0200668
669 return 0;
670}
671
672static int create_wizard(mixed who, mixed promoter)
673{
674 mixed *domains;
675 object vertrag;
676 int ret;
677 string gen;
678
679 who=find_player(who);
680 promoter=find_player(promoter);
681 if (!who || !promoter)
682 return 0;
683 //
684 // player not interactive?
685 //
686 if (!interactive(who))
687 {
688 write(capitalize(getuid(who))+" ist nicht aktiv.\n");
689 return 0;
690 }
691 //
692 // player is second?
693 //
bugfixd94d0932020-04-08 11:27:13 +0200694 if (({string})who->QueryProp(P_SECOND))
MG Mud User88f12472016-06-24 23:31:02 +0200695 {
696 tell_object(who,"Du bist ein Zweitspieler und kannst als solcher kein Magier werden.\n"
697 +"Versuchs Doch mal mit Deinem Erstie.\n");
bugfixd94d0932020-04-08 11:27:13 +0200698 write("Du kannst "+({string})who->name()+" nicht zum Magier machen. Das geht bei "
MG Mud User88f12472016-06-24 23:31:02 +0200699 +"Zweities\nleider nicht. Frag doch mal nach dem Erstie.\n");
700 return 1;
701 }
702 //
703 // wants to advance himself?
704 //
705 if (who==promoter)
706 {
707 write("Du kannst Dich nicht selber befoerdern. Such Dir dazu bitte einen "+
708 "Vollmagier,\nder Dir einen Vertrag gibt.\n");
709 return 1;
710 }
711 //
712 // banished?
713 //
714 if (MBanishListe[who,1])
715 {
716 tell_object(promoter,capitalize(who)+" darf nur von einem Erzmagier zum "+
717 "Magier gemacht werden.\n");
bugfixd94d0932020-04-08 11:27:13 +0200718 say(({string})promoter->name(WER)+" ist kein Erzmagier und darf "+capitalize(who)+
MG Mud User88f12472016-06-24 23:31:02 +0200719 " nicht zum Magier machen.\n");
720 return 1;
721 }
722 //
723 // player has PK?
724 //
bugfixd94d0932020-04-08 11:27:13 +0200725 if (({string})who->QueryProp("playerkills")) {
726 tell_room(environment(who),({string})who->name()+" hat noch einen Playerkill und kann somit kein Magier werden.\n"
MG Mud User88f12472016-06-24 23:31:02 +0200727 "Am besten den Sheriff oder einen Erzmagier verstaendigen.\n");
728 return 1;
729 }
730 //
731 // already dom_member?
732 //
733 if (IS_DOMAINMEMBER(who))
734 {
735 Write("Fuer Dich kann ich nichts mehr tun. Du bist doch schon Magier!\n");
736 return 1;
737 }
738
739 //
740 // "advanced learner"?
741 //
742 if (query_wiz_level(who) == 20)
743 {
744 if (!ARCH_SECURITY) {
745 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
bugfixd94d0932020-04-08 11:27:13 +0200746 Say("Nur ein Erzmagier kann "+({string})who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
MG Mud User88f12472016-06-24 23:31:02 +0200747 return 0;
748 }
Arathornd5c9c022020-01-08 22:04:28 +0100749 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),21);
MG Mud User88f12472016-06-24 23:31:02 +0200750 if (ret<=0)
751 {
752 say("Merlin: error "+ret+"\n");
753 write("Merlin: error "+ret+"\n");
754 }
bugfixd94d0932020-04-08 11:27:13 +0200755 write("Merlin ruft: "+({string})who->name(WER)+" ist in den Kreis der Magier "+
MG Mud User88f12472016-06-24 23:31:02 +0200756 "aufgenommen worden!\n");
bugfixd94d0932020-04-08 11:27:13 +0200757 shout("Merlin ruft: "+({string})who->name(WER)+" ist in den Kreis der Magier "+
MG Mud User88f12472016-06-24 23:31:02 +0200758 "aufgenommen worden!\n");
bugfixd94d0932020-04-08 11:27:13 +0200759 ({int})"secure/master"->renew_player_object(who);
MG Mud User88f12472016-06-24 23:31:02 +0200760 return 1;
761 }
762
763 //
764 // already wizard?
765 //
766 if (IS_WIZARD(who))
767 {
Arathornd5c9c022020-01-08 22:04:28 +0100768 domains=({string*})"secure/master"->get_domain_homes(getuid(who));
MG Mud User88f12472016-06-24 23:31:02 +0200769 if (!domains || !pointerp(domains) || !sizeof(domains))
770 {
bugfixd94d0932020-04-08 11:27:13 +0200771 Say(({string})who->name(WER)+" gehoert noch keiner Region an und kann daher noch "+
MG Mud User88f12472016-06-24 23:31:02 +0200772 "kein Voll-\nmagier werden.\n");
773 Write("Du gehoerst noch keiner Region an. Schliess Dich zunaechst einer "+
774 "an und komm\ndann wieder!\n");
775 return 0;
776 }
Arathornd5c9c022020-01-08 22:04:28 +0100777 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),25);
MG Mud User88f12472016-06-24 23:31:02 +0200778 if(ret>0)
779 {
bugfixd94d0932020-04-08 11:27:13 +0200780 shout(({string})who->name(WER)+" arbeitet jetzt an einer Region mit!\n");
781 ({int})"secure/master"->renew_player_object(who);
MG Mud User88f12472016-06-24 23:31:02 +0200782 return 1;
783 }
784 write("RETURNVALUE "+ret+"\n");
785 say("RETURNVALUE "+ret+"\n");
786 return 0;
787 }
788
789 //
790 // still learner?
791 //
792 if (IS_LEARNER(who))
793 {
794 if (!ARCH_SECURITY) {
795 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
bugfixd94d0932020-04-08 11:27:13 +0200796 Say("Nur ein Erzmagier kann "+({string})who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
MG Mud User88f12472016-06-24 23:31:02 +0200797 return 0;
798 }
Arathornd5c9c022020-01-08 22:04:28 +0100799 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),20);
MG Mud User88f12472016-06-24 23:31:02 +0200800 if (ret<=0)
801 {
802 say("Merlin: error "+ret+"\n");
803 write("Merlin: error "+ret+"\n");
804 }
Arathornd5c9c022020-01-08 22:04:28 +0100805 string wizname = ({string})who->query_real_name();
bugfixd94d0932020-04-08 11:27:13 +0200806 ({int})"secure/master"->renew_player_object(who);
MG Mud User88f12472016-06-24 23:31:02 +0200807 // Fehlerteufel geben
808 call_out(#'GibFehlerteufel,4,find_player(wizname));
809 return 1;
810 }
811
812 //
813 // promoter's level is not >DOMAINMEMBER_LVL+1
814 //
815 if (secure_level()<=DOMAINMEMBER_LVL)
816 {
817 tell_object(promoter,"Du musst derzeit mindestens Level "+
818 (DOMAINMEMBER_LVL+1)+" haben, um jemanden befoerden zu "+
819 "koennen.\n");
bugfixd94d0932020-04-08 11:27:13 +0200820 say(({string})promoter->name(WER)+" ist kein Vollmagier und darf daher niemanden "+
MG Mud User88f12472016-06-24 23:31:02 +0200821 "zum Vollmagier machen.\n");
822 return 1;
823 }
824
825 // der Check auf den Blutprintnamen ist fast ueberfluessig, aber nur fast.
826 // Er schlaegt fehl, wenn der Vertrag der Clone einer alten BP ist.
827 if (!(vertrag=present_clone("/obj/vertrag",who)) ||
828 object_name(blueprint(vertrag))!="/obj/vertrag" ||
bugfixd94d0932020-04-08 11:27:13 +0200829 !(({int})vertrag->is_unterschrieben()) )
MG Mud User88f12472016-06-24 23:31:02 +0200830 {
831 Write("Du hast ja gar keinen unterschriebenen Vertrag bei Dir. Besorg Dir "+
832 "einen Ver-\ntrag, unterschreibe ihn und komm dann wieder!\n");
bugfixd94d0932020-04-08 11:27:13 +0200833 Say(({string})who->name(WER)+" hat keinen unterschriebenen Vertrag.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200834 return 1;
835 }
836 if (geteuid(vertrag)!=secure_euid())
837 {
838 tell_object(promoter,"Das geht nicht, er hat einen Vertrag von "+
839 capitalize(geteuid(vertrag))+" bei sich.\n");
bugfixd94d0932020-04-08 11:27:13 +0200840 say(({string})promoter->name(WER)+" versucht, "+({string})who->name(WER)+" zum Magier zu "+
841 "machen, doch "+({string})who->name(WER)+" hat einen Vertrag\nvon "+
MG Mud User88f12472016-06-24 23:31:02 +0200842 capitalize(geteuid(vertrag))+" bei sich.\n",promoter);
843 return 0;
844 }
845 if (!QueryBedingungen(who,"Magier"))
846 return 0;
Arathornd5c9c022020-01-08 22:04:28 +0100847 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),15);
MG Mud User88f12472016-06-24 23:31:02 +0200848 if (ret>0)
849 {
Zesstra68ee1e52020-04-20 23:24:15 +0200850 // Log ("Magierstammbuch") nach /data/etc loggen, weil SPONSOR ein
851 // langfristlog.
852 write_data("/etc/SPONSOR",dtime(time())+": "+capitalize(getuid(promoter))+" macht "+
bugfixd94d0932020-04-08 11:27:13 +0200853 ({string})who->name(WER)+" zum Learner.\n");
854 write(({string})who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
855 shout(({string})who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
Zesstra68ee1e52020-04-20 23:24:15 +0200856 PostMagier(capitalize(getuid(who)),
857 capitalize(secure_euid()),
858 ({int})who->QueryProp(P_GENDER));
bugfixd94d0932020-04-08 11:27:13 +0200859 if (({int})"secure/master"->set_player_object(geteuid(who),"/std/shells/magier")
MG Mud User88f12472016-06-24 23:31:02 +0200860 <=0)
861 {
862 say("MERLIN: konnte Magiershell nicht einstellen.\n");
863 write("MERLIN: konnte Magiershell nicht einstellen.\n");
864 }
bugfixd94d0932020-04-08 11:27:13 +0200865 ({int})"secure/master"->renew_player_object(who);
Zesstra388cc222020-04-21 23:49:52 +0200866 call_out(function void ()
Zesstra2f85ed72020-04-21 01:28:08 +0200867 { write_data("/etc/SPONSOR.html",wiztree_html(), 1); }, 2);
MG Mud User88f12472016-06-24 23:31:02 +0200868 return 1;
869 }
870 write(" --RETURNVALUE IS "+ret+"\n");
871 say(" --RETURNVALUE IS "+ret+"\n");
872
873 return(ret); //non-void funktion
874}
875
876void clear_flag()
877{
878 flag=0;
879}
880
881void do_say(string str)
882{
883 say(str);
884}
885
886
887
Zesstrab16348b2019-05-21 19:41:36 +0200888void seer_sequenz3(object player, string plname)
MG Mud User88f12472016-06-24 23:31:02 +0200889{
890 string playername;
891 object faq;
892 string text;
893
Zesstra60d9e252019-05-21 20:02:56 +0200894 if (!objectp(player) || !interactive(player)) {
MG Mud User88f12472016-06-24 23:31:02 +0200895 tell_room(environment(), sprintf("Merlin sagt: Na, wo ist denn %s "
896 "hin?\n", plname));
897 busy = 0;
898 return;
899 }
900 if (environment() != environment(player))
901 move(environment(player), M_TPORT);
902
903 tell_object(player,break_string("\n\nEs macht *PUFF* und eine Schwefelwolke "
904 +"steigt um Dich herum auf.\n\nDie Aura "
905 +"verschwindet langsam und Du fuehlst Dich "
906 +"nun viel erfahrener.", 78,0,1));
907 tell_room(environment(),
908 break_string(sprintf(
909 "\n\nEs macht *PUFF* und eine Schwefelwolke steigt "
910 +"um %s herum auf.\n\nDie Aura verschwindet langsam.\n",
911 plname),78,0,1), ({player}));
912
bugfixd94d0932020-04-08 11:27:13 +0200913 if (({int})"secure/master"->advance_wizlevel(geteuid(player),1)<=0)
MG Mud User88f12472016-06-24 23:31:02 +0200914 {
915 write("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
916 say("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
917 busy = 0;
918 return;
919 }
920 playername = geteuid(player);
bugfixd94d0932020-04-08 11:27:13 +0200921 ({int})"secure/master"->renew_player_object(player);
MG Mud User88f12472016-06-24 23:31:02 +0200922 player = find_player(playername);
923 text = sprintf(" ist jetzt ein%s Seher%s!\n",
bugfixd94d0932020-04-08 11:27:13 +0200924 ((({int})player->QueryProp(P_GENDER))==2?"e":""),
925 ((({int})player->QueryProp(P_GENDER))==2?"in":""));
MG Mud User88f12472016-06-24 23:31:02 +0200926 write("Merlin ruft: "+capitalize(playername)+text);
927 shout("Merlin ruft: "+capitalize(playername)+text);
Vanion50652322020-03-10 21:13:25 +0100928 PostSeher(capitalize(playername),({int})player->QueryProp(P_GENDER));
MG Mud User88f12472016-06-24 23:31:02 +0200929 if(!catch(
930 faq=clone_object("/d/seher/haeuser/special/seherfaqmobil") ;publish))
931 {
bugfixd94d0932020-04-08 11:27:13 +0200932 ({int})faq->move(player,M_NOCHECK);
MG Mud User88f12472016-06-24 23:31:02 +0200933 tell_object(player, "Aus dem Nichts erscheint eine kleine Belohnung fuer Dich.\n");
934 }
935
936 tell_object(player, "\n\nDu laechelst gluecklich in die Runde.\n\n");
937 tell_room(environment(), sprintf("\n\n%s laechelt gluecklich in die Runde.\n\n", plname), ({player}));
938
939 busy=0;
940}
941
Zesstrab16348b2019-05-21 19:41:36 +0200942void seer_sequenz2(object player, string plname)
MG Mud User88f12472016-06-24 23:31:02 +0200943{
Zesstra60d9e252019-05-21 20:02:56 +0200944 if (!objectp(player) || !interactive(player)) {
MG Mud User88f12472016-06-24 23:31:02 +0200945 tell_room(environment(), sprintf(
946 "Merlin sagt: Na, wo ist denn %s hin?\n",
947 plname));
948 busy = 0;
949 return;
950 }
951 if (environment() != environment(player))
952 move(environment(player), M_TPORT);
953
zesstra70a0a3e2016-07-06 20:35:40 +0200954 tell_object(player, break_string("\nMerlin hebt die Arme "
MG Mud User88f12472016-06-24 23:31:02 +0200955 +"und macht einige beschwoerende Gesten. Um Dich herum erscheint "
956 +"eine gelbliche Aura, die immer heller wird, bis Du Deine "
957 +"Umwelt kaum mehr erkennen kannst.\n\n",
958 78,0,1));
959 tell_room(environment(),
960 break_string(sprintf("\nMerlin hebt die Arme und macht einige "
961 +"beschwoerende Gesten. Um %s erscheint eine "
962 +"gelbliche Aura, die immer heller wird, bis "
963 +"man %s kaum mehr erkennen kann.\n\n",
964 plname, plname),78,0,1), ({player}));
965
966 call_out("seer_sequenz3", 7, player, plname);
967}
968
Zesstrab16348b2019-05-21 19:41:36 +0200969void seer_sequenz1(object player, string plname)
MG Mud User88f12472016-06-24 23:31:02 +0200970{
Zesstra60d9e252019-05-21 20:02:56 +0200971 if (!objectp(player) || !interactive(player))
MG Mud User88f12472016-06-24 23:31:02 +0200972 return;
973
974 move(environment(player), M_TPORT);
975
976 tell_room(environment(),
977 break_string(sprintf("Das ist eine grosse Freude. %s hat sich "
978 "tapfer durch das "MUDNAME" geschlagen und mittlerweile alle "
979 "Anforderungen erfuellt, um %s zu werden.",
bugfixd94d0932020-04-08 11:27:13 +0200980 plname, (({int})player->QueryProp(P_GENDER))==1?"Seher":"Seherin"),
MG Mud User88f12472016-06-24 23:31:02 +0200981 78, "Merlin sagt: "));
982
983 call_out("seer_sequenz2", 4, player, plname);
984}
985
986
Zesstrab16348b2019-05-21 19:41:36 +0200987static int create_seer(object player)
MG Mud User88f12472016-06-24 23:31:02 +0200988{
Zesstra60d9e252019-05-21 20:02:56 +0200989 if (!objectp(player) || !interactive(player))
MG Mud User88f12472016-06-24 23:31:02 +0200990 return 0;
991 if (IS_SEER(player))
992 {
993 write(break_string("Du bist doch schon kein normaler Spieler mehr, "
994 +"was soll es also?", 78, "Merlin teilt Dir mit: "));
995 return 1;
996 }
997
998 if (!QueryBedingungen(player,"Seher"))
999 return -1;
1000
1001
1002 write(break_string("Grosse Freude! Du hast alle Anforderungen "
1003 "erfuellt. Warte einen Moment...", 78,
1004 "Merlin teilt Dir mit: "));
1005 busy=1;
bugfixd94d0932020-04-08 11:27:13 +02001006 call_out("seer_sequenz1",4,player, ({string})player->Name());
MG Mud User88f12472016-06-24 23:31:02 +02001007 return(0); //non-void funktion
1008}
1009
1010static void give_help(mixed player)
1011{
1012 if (!objectp(player))
1013 return;
1014
1015 tell_object(player,
1016 break_string("Ich weiss nicht, was ich fuer Dich tun kann. "
1017 +"Ich kann Dich zum Seher oder zum Magier "
1018 +"machen, wenn Du mich darum bittest.", 78,
1019 "Merlin teilt Dir mit: "));
1020}
1021
1022
1023void reset()
1024{
1025}
1026
1027public int remove(int silent) {
bugfixd94d0932020-04-08 11:27:13 +02001028 ({int})EVENTD->UnregisterEvent(EVT_LIB_LOGIN, ME);
1029 ({int})EVENTD->UnregisterEvent(EVT_LIB_PLAYER_CREATION, ME);
MG Mud User88f12472016-06-24 23:31:02 +02001030 destruct(this_object());
1031 return 1;
1032}
1033
1034void wandern()
1035{
MG Mud User88f12472016-06-24 23:31:02 +02001036 while (remove_call_out("wandern")>=0);
1037 call_out("wandern",45+random(100));
1038 if (busy) return;
1039 if (delay)
1040 {
1041 delay=0;
1042 return;
1043 }
Zesstra1b6b7362019-04-25 14:08:02 +02001044 if (!environment())
MG Mud User88f12472016-06-24 23:31:02 +02001045 {
1046 move("/gilden/abenteurer",0);
MG Mud User88f12472016-06-24 23:31:02 +02001047 }
1048 //ueber Inv iterieren, ob da ein nicht-idelnder Spieler mit genug XP
Zesstra1b6b7362019-04-25 14:08:02 +02001049 //rumhaengt. In diesem Raum bleiben, wenn ja.
1050 foreach(object ob: all_inventory(environment()))
1051 {
1052 if (interactive(ob) && query_idle(ob)<180
bugfixd94d0932020-04-08 11:27:13 +02001053 && ({int})ob->QueryProp(P_XP)>999999)
MG Mud User88f12472016-06-24 23:31:02 +02001054 return;
1055 }
Zesstra1b6b7362019-04-25 14:08:02 +02001056 // Ausgaenge durchsuchen
Arathornd5c9c022020-01-08 22:04:28 +01001057 mapping ex=({mapping})environment()->QueryProp(P_EXITS);
MG Mud User88f12472016-06-24 23:31:02 +02001058 if (!mappingp(ex))
1059 return;
Zesstra1b6b7362019-04-25 14:08:02 +02001060 mapping rooms = m_allocate(sizeof(ex));
1061 foreach(string cmd, string|closure dest, string msg : ex)
MG Mud User88f12472016-06-24 23:31:02 +02001062 {
Zesstra1b6b7362019-04-25 14:08:02 +02001063 object ob;
1064 // nur normale Ausgaenge benutzen
1065 if (!stringp(dest)
1066 || dest = object_name(environment()))
MG Mud User88f12472016-06-24 23:31:02 +02001067 continue;
Zesstra1b6b7362019-04-25 14:08:02 +02001068 rooms += ([dest]);
MG Mud User88f12472016-06-24 23:31:02 +02001069 }
Zesstra1b6b7362019-04-25 14:08:02 +02001070 if (!sizeof(rooms))
1071 return;
1072
1073 // Und nicht zuruecklatschen, wenn moeglich.
MG Mud User88f12472016-06-24 23:31:02 +02001074 if (prev_room && sizeof(m_indices(rooms))>1)
1075 rooms-=([prev_room]);
Zesstra1b6b7362019-04-25 14:08:02 +02001076 prev_room=object_name(environment());
1077
1078 string *raeume=m_indices(rooms);
1079 move(raeume[sizeof(raeume)],0);
MG Mud User88f12472016-06-24 23:31:02 +02001080}
1081
1082string int_short()
1083{
1084 return "Du bist im allseits beliebten Wizclub \"Zum lustigen Merlin\".\n";
1085}
1086
1087string int_long(object who,mixed where)
1088{
1089 string descr;
1090
bugfixd94d0932020-04-08 11:27:13 +02001091 if( IS_LEARNER(who) && ({int})who->QueryProp( P_WANTS_TO_LEARN ) )
MG Mud User88f12472016-06-24 23:31:02 +02001092 descr = "[" + object_name(ME) + "]\n";
1093 else
1094 descr = "";
1095 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";
bugfixd94d0932020-04-08 11:27:13 +02001096 if ( ({int})who->QueryProp(P_SHOW_EXITS) )
MG Mud User88f12472016-06-24 23:31:02 +02001097 descr += "Es gibt 2 sichtbare Ausgaenge: raus und gilde.\n";
1098 descr += make_invlist(who, all_inventory(ME) - ({ who }));
1099 if( environment())
1100 descr += "\nAusserhalb siehst Du:\n"
bugfixd94d0932020-04-08 11:27:13 +02001101 + ({string})environment()->int_short(who,ME);
MG Mud User88f12472016-06-24 23:31:02 +02001102 return descr;
1103}
1104
1105string make_invlist(object viewer,object *inv)
1106{
1107 int i, iswiz;
1108 string descr;
1109
1110 descr = "";
bugfixd94d0932020-04-08 11:27:13 +02001111 iswiz = IS_LEARNER( viewer ) && ({int})viewer->QueryProp(P_WANTS_TO_LEARN);
MG Mud User88f12472016-06-24 23:31:02 +02001112
1113 for (i = 0; i < sizeof(inv); i++)
1114 {
1115 string sh;
Arathornd5c9c022020-01-08 22:04:28 +01001116 sh = ({string})inv[i]->short();
MG Mud User88f12472016-06-24 23:31:02 +02001117 if (iswiz)
1118 {
1119 if (sh) sh = sh[0..<2] + " ["+object_name(inv[i])+"]\n";
1120 else sh = "["+object_name(inv[i])+"]\n";
1121 }
1122 if (sh) descr += sh;
1123 }
1124 return descr;
1125}
1126
1127void init()
1128{
1129 if (interactive(this_player()) && environment(this_player())==ME)
1130 add_action("gehen","",1);
1131 add_action("befoerdere","befoerder",1);
1132}
1133
1134int befoerdere(string str)
1135{
1136 string wen;
1137 int ret,stufe,l;
1138
1139 if (!LORD_SECURITY) return 0;
1140 if (!str||sscanf(str,"%s auf stufe %d",wen,stufe)<2)
1141 {
1142 notify_fail("Syntax: befoerdere <name> auf stufe <stufe>\n");
1143 return 0;
1144 }
1145 if (stufe>29)
1146 {
1147 write("Maximum ist Stufe 29!\n");
1148 return 1;
1149 }
1150 l=query_wiz_level(wen);
1151 if (l<25)
1152 {
1153 printf("%s muss mindestens zwecks Weiterbefoerderung mindestens Stufe 25 haben.\n",
1154 capitalize(wen));
1155 return 1;
1156 }
1157 if (l>=stufe)
1158 {
1159 printf("%s ist schon Stufe %d.\n",capitalize(wen),l);
1160 return 1;
1161 }
Arathornd5c9c022020-01-08 22:04:28 +01001162 ret=({int})"secure/master"->advance_wizlevel(wen,stufe);
MG Mud User88f12472016-06-24 23:31:02 +02001163 if (ret<=0)
1164 printf("Errorcode %d\n",ret);
1165 else
1166 write("ok\n");
1167 return 1;
1168}
1169
1170int sag(mixed str)
1171{
1172 int i;
1173
1174 if (str==0)
1175 str="";
1176 str = old_explode(break_string(str, 60 ), "\n");
1177 if (busy) {
1178 tell_room(ME, "Merlin mault: Ich bin beschaeftigt.\n");
1179 return 0;
1180 }
1181 for (i = 0; i < sizeof(str); i++)
1182 {
1183 if (!str[i])
1184 str[i]="";
1185 tell_room(environment(),"Merlin sagt: "+str[i]+"\n");
1186 tell_room(ME,"*Merlin sagt: "+str[i]+"\n");
1187 }
1188 return 1;
1189}
1190
1191void show_exits()
1192{
bugfixd94d0932020-04-08 11:27:13 +02001193 printf("%s",({string})environment()->GetExits());
MG Mud User88f12472016-06-24 23:31:02 +02001194}
1195
1196int gehen(string str)
1197{
MG Mud User88f12472016-06-24 23:31:02 +02001198 if (busy) {
1199 write("Merlin mault: Ich bin beschaeftigt.\n");
1200 return 0;
1201 }
1202
Arathornd5c9c022020-01-08 22:04:28 +01001203 str=({string})this_interactive()->_unparsed_args();
Zesstra1b6b7362019-04-25 14:08:02 +02001204 switch (query_verb())
MG Mud User88f12472016-06-24 23:31:02 +02001205 {
1206 case "gilde":
bugfixd94d0932020-04-08 11:27:13 +02001207 ({int})this_player()->move("/gilden/abenteurer",M_GO,"in die Gilde");
MG Mud User88f12472016-06-24 23:31:02 +02001208 return 1;
1209 case "raus":
bugfixd94d0932020-04-08 11:27:13 +02001210 ({int})this_player()->move(environment(),M_GO,"raus");
MG Mud User88f12472016-06-24 23:31:02 +02001211 return 1;
1212 }
1213 if (!IS_WIZARD(this_interactive()))
1214 return 0;
Zesstra1b6b7362019-04-25 14:08:02 +02001215 if (query_verb()!="merlin")
MG Mud User88f12472016-06-24 23:31:02 +02001216 return 0;
1217 delay=1;
Arathornd5c9c022020-01-08 22:04:28 +01001218 mapping exits=({mapping})environment()->QueryProp(P_EXITS);
MG Mud User88f12472016-06-24 23:31:02 +02001219 if (!str||str=="")
1220 {
bugfixd94d0932020-04-08 11:27:13 +02001221 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001222 show_exits();
1223 return 1;
1224 }
1225 if (old_explode(str," ")[0]=="sag")
1226 return sag(implode(old_explode(str," ")[1..]," "));
1227 if (str[0]==';')
1228 {
1229 tell_room(environment(ME),"Merlins "+str[1..]+"\n");
1230 tell_room(ME,"*Merlins "+str[1..]+"\n");
1231 return 1;
1232 }
1233 if (str[0]==':')
1234 {
1235 tell_room(environment(ME),"Merlin "+str[1..]+"\n");
1236 tell_room(ME,"*Merlin "+str[1..]+"\n");
1237 return 1;
1238 }
1239 if (str[0]=='*')
1240 {
1241 goto(str[1..]);
bugfixd94d0932020-04-08 11:27:13 +02001242 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001243 show_exits();
1244 return 1;
1245 }
1246 if (!exits[str])
1247 return 0;
1248 move(exits[str],0);
1249 write("Merlin sagt: Jawoll, Chef.\n");
bugfixd94d0932020-04-08 11:27:13 +02001250 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001251 show_exits();
1252 return 1;
1253}
1254
1255int goto(mixed dest)
1256{
1257 object ob;
1258 string path;
1259 mixed ret;
1260
1261 if (busy) {
1262 write("Merlin mault: Ich bin beschaeftigt.\n");
1263 return 1;
1264 }
1265
1266 if (!dest) {
1267 write("Wohin moechtest Du Merlin bringen ?\n");
1268 return 1;
1269 }
1270 ob = find_living(dest);
1271 if (ob) {
1272 ob = environment(ob);
1273 move(object_name(ob),0);
1274 return 1;
1275 }
Arathornd5c9c022020-01-08 22:04:28 +01001276 path = ({string})master()->make_path_absolute(dest);
MG Mud User88f12472016-06-24 23:31:02 +02001277 ret=catch(load_object(path);publish);
1278 if (ret && file_size(path)<0)
1279 {
1280 dest=match_living(dest,1);
1281 if (stringp(dest))
1282 {
1283 ob = environment(find_living(dest));
1284 move(object_name(ob),M_TPORT|M_NOCHECK);
1285 return 1;
1286 }
1287 printf("Fehler beim Teleport nach %O: No such file.\n",path);
1288 return 1;
1289 }
1290 if (ret)
1291 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1292 ret=catch(move(path,M_TPORT|M_NOCHECK);publish);
1293 if (stringp(ret))
1294 ret=implode(old_explode(ret,"\n"),"");
1295 if (ret)
1296 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1297 return 1;
1298}
1299
1300mixed locate_objects(string complex_desc)
1301{
1302 object ob;
1303
1304 if (complex_desc=="alles" || complex_desc=="alle")
1305 return filter_objects(all_inventory(this_object()),"short");
1306 if (ob = present(complex_desc,this_object()) )
1307 return ({ ob });
1308 return ({}) ;
1309}
1310
1311void MBanishInsert(string name, string grund, object wer)
1312{
1313 if ( !name || !stringp(name) || !sizeof(name) ||
1314 !grund || !stringp(grund) || !sizeof(grund) ||
1315 !wer || !objectp(wer) || getuid(wer) != secure_euid() ||
1316 !IS_DEPUTY(wer) )
1317 return;
1318
1319 MBanishListe += ([name:grund;getuid(wer)]);
1320 save_object(SAVEFILE);
1321}
1322
1323mapping MBanishList()
1324{
1325 if ( !IS_DEPUTY(secure_euid()) )
1326 return 0;
1327
1328 return deep_copy(MBanishListe);
1329}
1330
1331void MBanishDelete(string name)
1332{
1333 if ( !name || !stringp(name) || !sizeof(name) || !ARCH_SECURITY )
1334 return 0;
1335
1336 MBanishListe = m_copy_delete( MBanishListe, name );
1337 save_object(SAVEFILE);
1338}
1339
1340string _query_noget()
1341{
1342 return "Merlin mag das nicht!\n";
1343}
1344
Zesstra2f85ed72020-04-21 01:28:08 +02001345private mapping create_wizard_tree()
1346{
1347 // Jof als root-elemente des Baums wird per Hand angelegt. Erstes Element
1348 // ist der Magierlevel, zweites das Mapping mit den Kindern (der Ast mit den
1349 // Kindern)
1350 mapping mtree = ([ "Jof": 111; m_allocate(100,2) ]);
1351 // Der Cache dient nur dazu, das zu einem Magier gehoerende Mapping der
1352 // Kinder schneller zu finden und verweist auf das Mapping im zweiten
1353 // Value in mtree.
1354 mapping cacheptr = m_allocate(500,1);
1355 cacheptr["Jof"] = mtree["Jof",1];
1356
1357 // Dann Log lesen und parsen.
1358 foreach(string line: explode(read_file("/data/etc/SPONSOR"),"\n"))
1359 {
1360 string parent, child;
1361 if (sscanf(line,"%!s: %s macht %s zum Learner.",parent,child) != 2)
1362 continue;
1363
1364 parent = capitalize(lower_case(parent));
1365 child = capitalize(lower_case(child));
1366
1367 // Das Kind sollte noch nicht existieren... (Tut es aber leider
1368 // gelegentlich.)
1369 if (member(cacheptr, child))
1370// raise_error(sprintf("Neu berufene Magierin ist schon Magierin: "
1371// "%s\n",child));
1372 continue;
1373 // Der Elter muss existieren...
1374 if (!member(cacheptr, parent))
1375 raise_error(sprintf("Sponsor ist keine Magierin: %s\n", parent));
1376
1377 // Mapping mit allen Kindern des Elter holen. Das Mapping in cacheptr ist
1378 // dasselbe Mapping wie in mtree, d.h. wir muessen den Elter nicht im
1379 // verschachtelten mtree suchen.
1380 mapping parent_children = cacheptr[parent];
1381 // neues Kind anlegen
1382 m_add(parent_children, child,
1383 master()->query_userlist(lower_case(child), USER_LEVEL),
1384 m_allocate(2,2) );
1385 // und im cacheptr das (noch leere) Mapping fuer die Kinder vom child hinterlegen
1386 m_add(cacheptr, child, parent_children[child, 1]);
1387 }
1388 //printf("mtree: %O\n",mtree);
1389 //printf("cache: %O\n",cacheptr);
1390 return mtree;
1391}
1392
1393// Starte mit dem Magier <node> in <mtree> und laeuft rekursiv durch den
1394// ganzen (Sub-)Baum. Erzeugt eine geschachtelte Struktur von <ul>-Elementen,
1395// bei denen Magier ein <li> sind und die jeweiligen Kinder wieder in ein
1396// tiefer liegendes <ul> kommen. Letztendlich wieder eine Baumstruktur.
1397private string print_mtree_node(mapping mtree, string node, int indent)
1398{
1399 mapping branch = mtree[node, 1];
1400 if (!branch)
1401 raise_error(sprintf("Magier %s existiert nicht.\n",node));
1402
1403 indent += 2;
1404 string res;
1405 // Geloeschte Magier werden durchgestrichen, Vollmagier kriegen ein
1406 // "class=magier" Attribut, was dafuer sorgt, dass die fettgedruckt werden.
1407 if (mtree[node, 0] == 0)
1408 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\">"
1409 "<del>%s</del></a></li>\n", " "*indent, node, node);
1410 else if (mtree[node, 0] < DOMAINMEMBER_LVL)
1411 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\">"
1412 "%s</a></li>\n", " "*indent, node, node);
1413 else
1414 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\""
1415 " class=\"wiz\">%s</a></li>\n", " "*indent, node, node);
1416
1417 // Wenn ein Magier Kinder hat, kommt nun ein neues <ul> dran, welches wieder
1418 // alle Kinder enthaelt.
1419 if (sizeof(branch))
1420 {
1421 // Das root-ul von Jof bekommt das Attribute "id=jof", alle anderen nicht.
1422 res += sprintf("%s<ul%s>\n", " "*indent,
1423 (node == "Jof" ? " id=\"jof\"" : ""));
1424 foreach(string child, int lvl, mapping grandchildren : branch)
1425 {
1426 res += print_mtree_node(branch, child, indent);
1427 }
1428 res += sprintf("%s</ul>\n", " "*indent);
1429 }
1430 return res;
1431}
1432
1433public string wiztree_html()
1434{
1435 mapping mtree = create_wizard_tree();
1436 return sprintf("<ul>\n%s</ul>\n",print_mtree_node(mtree, "Jof", 2));
1437}
1438