blob: 20d581886f50adc024b8c90518d0a59a83b4bc10 [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":
Arathorn9dd23332020-12-28 11:06:10 +0100190 return BS("Du streckst schon Deine Hand aus, um Merlins Gewand naeher zu untersuchen, aber da trifft Dich sein strenger Blick. Schuechtern nimmst Du von Deinem Vorhaben Abstand.");
MG Mud User88f12472016-06-24 23:31:02 +0200191 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) {
Zesstrac27c7c22021-05-13 14:36:40 +0200247 case WER: return "er";
MG Mud User88f12472016-06-24 23:31:02 +0200248 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
Zesstrac27c7c22021-05-13 14:36:40 +0200357// Spielerobjekte aufgrund eines Bugs bei der Berechnung der Schutzwirkung
358// von P_BODY erneuern
359#if __BOOT_TIME__ < 1620557318
360#define BUGTIME 1620409462
361#define BUGFIXTIME 1620635153
MG Mud User88f12472016-06-24 23:31:02 +0200362void renew_player(string plname, int force) {
363 object pl;
364 mixed err;
365
366 pl = find_player(plname);
367 if (!objectp(pl) || !query_once_interactive(pl)) return;
368
369 // jung oder alt genug, Abbruch. ;-)
370 if ((object_time(pl) > BUGFIXTIME)
371 || object_time(pl) < BUGTIME)
372 return;
373
374 if (get_eval_cost() < 1000000 || !force ) {
375 call_out("renew_player",8,plname,1);
376 tell_object(pl,break_string(sprintf("Huhu %s, um einen Bug in "
377 "Deinem Spielerobjekt zu beheben, wirst Du in ca. 8s "
378 "neugeladen. Bitte warte bis dahin ab und bleibe, wo "
bugfixd94d0932020-04-08 11:27:13 +0200379 "Du gerade bist.",({string})pl->Name()),78,"Merlin teilt Dir mit: "));
MG Mud User88f12472016-06-24 23:31:02 +0200380 return;
381 }
382
383 plname=getuid(pl);
384 tell_object(pl,break_string(sprintf("Huhu %s, um einen Bug in "
385 "Deinem Spielerobjekt zu beheben, wirst Du jetzt "
bugfixd94d0932020-04-08 11:27:13 +0200386 "neugeladen.",({string})pl->Name()),78,"Merlin teilt Dir mit: "));
MG Mud User88f12472016-06-24 23:31:02 +0200387
bugfixd94d0932020-04-08 11:27:13 +0200388 if (err=catch(({int})master()->renew_player_object(pl);publish)) {
MG Mud User88f12472016-06-24 23:31:02 +0200389 log_file("zesstra/failed_rewew.log",sprintf("%s: Fehler %O beim "
390 "Renew von %s\n",dtime(time()),err,plname));
391 tell_object(pl,break_string("Beim Neuladen Deines Spielerobjekts "
392 "gab es einen Fehler. Bitte wende Dich an einen EM.",78,
393 "Merlin teilt Dir mit: "));
394 }
395 else {
396 log_file("zesstra/renewed.log",sprintf("%s: %s wurde renewed.\n",
397 dtime(time()),plname));
398 if (objectp(find_player(plname)))
399 tell_object(find_player(plname),
400 break_string("Dein Spielerobjekt wurde neugeladen. Du "
401 "kannst jetzt normal weiterspielen. Falls Du etwas ungewoehnliches "
402 "bemerkst, melde Dich bitte bei einem Erzmagier. Viel Spass im "
403 "Spiel!",78, "Merlin teilt Dir mit: "));
404 }
405}
406#endif
407
408void player_change(string eid, object trigob, mixed data) {
409
410 if (!trigob || !interactive(trigob))
411 return;
412
413 switch(eid) {
414 case EVT_LIB_PLAYER_CREATION:
415 call_out(#'AnnounceNewPlayer, 5, trigob);
416 break;
417 case EVT_LIB_LOGIN:
418 notify_player_change(data[E_PLNAME],1);
Zesstrac27c7c22021-05-13 14:36:40 +0200419#if __BOOT_TIME__ < 1620557318
420 // Spieler evtl. renewen?
MG Mud User88f12472016-06-24 23:31:02 +0200421 renew_player(data[E_PLNAME],0);
422#endif
423 break;
424 }
425}
426
427
428//besser P_NO_ATTACK als Defend()...
429mixed _query_no_attack() {
430 if (!living(PL) || !objectp(environment(PL)) ) return(1);
431
432 tell_room(environment(), "Merlin schimpft: Lass das!!!\n",({PL}));
433 tell_room(environment(),sprintf(
434 "Merlin gibt %s eine schallende Ohrfeige.\n",
Arathornd5c9c022020-01-08 22:04:28 +0100435 capitalize(({string})this_player()->name(WEM))), ({this_player()}));
MG Mud User88f12472016-06-24 23:31:02 +0200436 return("Merlin schimpft: Lass das!!!\n"
437 "Merlin gibt Dir eine schallende Ohrfeige.\n");
438}
439
440/*
441int Defend(int dam, string dam_type, int spell, object enemy)
442{
443 object en;
444 if (!en=previous_object() || !living(en))
445 en = this_player();
446 tell_room(environment(), "Merlin schimpft: Lass das!!!\n");
447 write("Merlin gibt Dir eine schallende Ohrfeige.\n");
448 say(sprintf("Merlin gibt %s eine schallende Ohrfeige.\n",
449 capitalize((string)this_player()->name(WEM))), this_player());
bugfixd94d0932020-04-08 11:27:13 +0200450 ({int})en->StopHuntFor(this_object(), 1);
MG Mud User88f12472016-06-24 23:31:02 +0200451}
452*/
453void shoutansw()
454{
455 object env,ti;
456 string *path;
457 string ans;
458
459 if (!(env=environment()))
460 return;
bugfixd94d0932020-04-08 11:27:13 +0200461 if (!(ti=this_interactive())||({int})ti->QueryProp(P_LEVEL)<19||({int})ti->QueryProp(P_GHOST))
MG Mud User88f12472016-06-24 23:31:02 +0200462 return;
463 tell_object(ti,"Du spuerst einen sengenden Schmerz.\n");
bugfixd94d0932020-04-08 11:27:13 +0200464 ({int})ti->do_damage( ({int})ti->QueryProp(P_HP) / 2 + 5);
465 if(({int})ti->QueryProp(P_GHOST)) return;
MG Mud User88f12472016-06-24 23:31:02 +0200466 ans="ich hab nicht die leiseste Idee, wo ich hier bin ...\n";
467 path=old_explode(object_name(env),"/");
468 if (path[0]=="d")
469 {
470 ans="werweisswo ..";
471 switch(path[1])
472 {
473 case "gebirge":
474 case "wald":
475 case "dschungel":
476 ans="im "+capitalize(path[1]);
477 break;
478 case "inseln":
479 ans="auf den Inseln";
480 break;
481 case "polar":
482 ans="im Polargebiet";
483 break;
484 case "unterwelt":
485 case "ebene":
486 case "wueste":
487 ans="in der "+capitalize(path[1]);
488 break;
489 case "vland":
490 ans="im Verlorenen Land";
491 break;
492 case "fernwest":
493 ans="in Fernwest";
494 break;
495 }
496 ans="ich bin "+ans+".\n";
497 }
498 if (path[0]=="players")
499 ans="ich hab mich verlaufen - ich schaetze, "+capitalize(path[1])+
500 " hat was damit zu tun...\n";
501 if (path[0]=="gilden") {
502 switch(path[1]) {
503 case "abenteurer":
504 ans="der Abenteurergilde";
505 break;
506 case "bierschuettler":
507 ans="der Bierschuettlergilde";
508 break;
509 case "chaos":
510 ans="der Gilde der Chaoten";
511 break;
512 case "kaempfer":
513 ans="der Kaempfergilde";
514 break;
515 case "karate":
516 ans="einem Karatedojo";
517 break;
518 case "klerus":
519 ans="einem Tempel der Kleriker";
520 break;
521 case "zauberer":
522 ans="der Akademie der Zauberer";
523 break;
524 default:
525 ans="irgendeiner Gilde";
526 }
527 ans="ich stehe in "+ans+".\n";
528 }
529 if( path[0]=="p" && path[1]=="verein" ) {
530 ans="ich stehe in Port Vain.";
531 }
bugfixd94d0932020-04-08 11:27:13 +0200532 if (!({int})this_interactive()->QueryProp(P_INVIS))
533 ans=({string})this_interactive()->Name(WER)+", "+ans;
MG Mud User88f12472016-06-24 23:31:02 +0200534 else ans=capitalize(ans);
535 call_out("myshout",0,break_string(ans, 78, "Merlin ruft: "));
536}
537
538void myshout(string s)
539{
540 write(s);
541 shout(s);
542}
543
544void catch_tell(string str)
545{
Zesstrac27c7c22021-05-13 14:36:40 +0200546 string name; mixed message;
547 int i;
MG Mud User88f12472016-06-24 23:31:02 +0200548
549 if (!this_player())
550 return;
551
552 if (environment()==environment(this_player()) && previous_object()!=ME)
553 tell_room(this_object(),"*"+str);
554
555 if (this_player() != this_interactive())
556 return;
557
558 if (busy) {
559 tell_object(this_player(),
560 "Merlin teilt Dir mit: Ich bin beschaeftigt.\n");
561 return;
562 }
563
564 str=lower_case(str);
565
566 if ((strstr(str, "teilt dir mit:") != -1)
567 && (strstr(str, "wo bist du") !=-1)) {
568 shoutansw();
569 return;
570 }
571
572 if ((strstr(str, "teilt dir mit:") != -1) &&
573 ((strstr(str, "seher") != -1 || strstr(str, "seherin") != -1)))
574 {
575 create_seer(this_player());
576 return;
577 }
578
Zesstrac27c7c22021-05-13 14:36:40 +0200579 if (sscanf(str,"%~s %s sagt: %s",name,message)!=3)
MG Mud User88f12472016-06-24 23:31:02 +0200580 if (sscanf(str,"%s sagt: %s",name,message)!=2)
581 return;
582
bugfixd94d0932020-04-08 11:27:13 +0200583 if (!name || !sizeof(name) || !({int})master()->find_userinfo(name))
MG Mud User88f12472016-06-24 23:31:02 +0200584 return;
585
586 if (name!=getuid(this_interactive()) && !ARCH_SECURITY)
587 {
588 if (flag==getuid(this_interactive())+"##"+name)
589 return;
590 call_out("do_say",0,"Merlin sagt: "+capitalize(getuid(this_interactive()))+" hat gerade so getan, als wuerde "+capitalize(name)+" etwas sagen!\n");
591 flag=getuid(this_interactive())+"##"+name;
592 call_out("clear_flag",0);
593 return;
594 }
595 flag=0;
596 for (i=0;i<sizeof(whitespaces);i++)
597 {
598 message=old_explode(message,whitespaces[i]);
599 if (!pointerp(message)||sizeof(message)==0)
600 return;
601 message=implode(message," ");
602 }
603
604 message=old_explode(message," ");
605
606 if (!pointerp(message) || !sizeof(message))
607 return;
608
609 message-=({0})-({""});
610
611 if (!message || sizeof(message)==0)
612 return;
613
614 if (member(message, "merlin")==-1)
615 return;
616
617 message-=({"merlin"});
618
619 message=implode(message," ");
620
621 if (!message || message=="")
622 return;
623
624 determine_action(message, name);
625}
626
627static int determine_action(string mess, string name)
628{
629 string str;
630
631 if (mess=="mach mich zum magier" || mess=="mach mich zur magierin")
632 return create_wizard(name,name);
633
634 if (sscanf(mess,"mach %s zum magier",str)==1||sscanf(mess,"mach %s zur magierin",str)==1)
635 return create_wizard(lower_case(str),name);
636
637 give_help(name);
638 return 0;
639}
640
641#define Say(str) say(str,who)
642#define Write(str) tell_object(who,str)
643
644int QueryBedingungen(object pl,string was)
645{
MG Mud User88f12472016-06-24 23:31:02 +0200646 if (IS_SEER(pl))
647 return 1;
648
bugfixd94d0932020-04-08 11:27:13 +0200649 if (({int})LEPMASTER->QueryReadyForWiz(pl)==1)
MG Mud User88f12472016-06-24 23:31:02 +0200650 return 1;
651
Zesstrac27c7c22021-05-13 14:36:40 +0200652 string s=({string})LEPMASTER->QueryReadyForWizText(pl);
MG Mud User88f12472016-06-24 23:31:02 +0200653
654 tell_object(pl, break_string("Merlin gruebelt ein wenig und teilt Dir "
655 "nach einigem Ueberlegen mit:\n\n", 78,0,1));
656
657 tell_object(pl, s+"\n");
658
659 tell_object(pl, break_string("Da ist wohl fuer Dich noch etwas zu tun...",
660 78, "Merlin teilt Dir mit: "));
661
662 if (environment() == environment(pl))
bugfixd94d0932020-04-08 11:27:13 +0200663 say(({string})pl->name(WER)
Arathornd5c9c022020-01-08 22:04:28 +0100664 +" erfuellt noch nicht alle Anforderungen fuer den "+was+
665 "status.\n",pl);
MG Mud User88f12472016-06-24 23:31:02 +0200666
667 return 0;
668}
669
670static int create_wizard(mixed who, mixed promoter)
671{
672 mixed *domains;
673 object vertrag;
674 int ret;
MG Mud User88f12472016-06-24 23:31:02 +0200675
676 who=find_player(who);
677 promoter=find_player(promoter);
678 if (!who || !promoter)
679 return 0;
680 //
681 // player not interactive?
682 //
683 if (!interactive(who))
684 {
685 write(capitalize(getuid(who))+" ist nicht aktiv.\n");
686 return 0;
687 }
688 //
689 // player is second?
690 //
bugfixd94d0932020-04-08 11:27:13 +0200691 if (({string})who->QueryProp(P_SECOND))
MG Mud User88f12472016-06-24 23:31:02 +0200692 {
693 tell_object(who,"Du bist ein Zweitspieler und kannst als solcher kein Magier werden.\n"
694 +"Versuchs Doch mal mit Deinem Erstie.\n");
bugfixd94d0932020-04-08 11:27:13 +0200695 write("Du kannst "+({string})who->name()+" nicht zum Magier machen. Das geht bei "
MG Mud User88f12472016-06-24 23:31:02 +0200696 +"Zweities\nleider nicht. Frag doch mal nach dem Erstie.\n");
697 return 1;
698 }
699 //
700 // wants to advance himself?
701 //
702 if (who==promoter)
703 {
704 write("Du kannst Dich nicht selber befoerdern. Such Dir dazu bitte einen "+
705 "Vollmagier,\nder Dir einen Vertrag gibt.\n");
706 return 1;
707 }
708 //
709 // banished?
710 //
711 if (MBanishListe[who,1])
712 {
713 tell_object(promoter,capitalize(who)+" darf nur von einem Erzmagier zum "+
714 "Magier gemacht werden.\n");
bugfixd94d0932020-04-08 11:27:13 +0200715 say(({string})promoter->name(WER)+" ist kein Erzmagier und darf "+capitalize(who)+
MG Mud User88f12472016-06-24 23:31:02 +0200716 " nicht zum Magier machen.\n");
717 return 1;
718 }
719 //
720 // player has PK?
721 //
bugfixd94d0932020-04-08 11:27:13 +0200722 if (({string})who->QueryProp("playerkills")) {
723 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 +0200724 "Am besten den Sheriff oder einen Erzmagier verstaendigen.\n");
725 return 1;
726 }
727 //
728 // already dom_member?
729 //
730 if (IS_DOMAINMEMBER(who))
731 {
732 Write("Fuer Dich kann ich nichts mehr tun. Du bist doch schon Magier!\n");
733 return 1;
734 }
735
736 //
737 // "advanced learner"?
738 //
739 if (query_wiz_level(who) == 20)
740 {
741 if (!ARCH_SECURITY) {
742 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
bugfixd94d0932020-04-08 11:27:13 +0200743 Say("Nur ein Erzmagier kann "+({string})who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
MG Mud User88f12472016-06-24 23:31:02 +0200744 return 0;
745 }
Arathornd5c9c022020-01-08 22:04:28 +0100746 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),21);
MG Mud User88f12472016-06-24 23:31:02 +0200747 if (ret<=0)
748 {
749 say("Merlin: error "+ret+"\n");
750 write("Merlin: error "+ret+"\n");
751 }
bugfixd94d0932020-04-08 11:27:13 +0200752 write("Merlin ruft: "+({string})who->name(WER)+" ist in den Kreis der Magier "+
MG Mud User88f12472016-06-24 23:31:02 +0200753 "aufgenommen worden!\n");
bugfixd94d0932020-04-08 11:27:13 +0200754 shout("Merlin ruft: "+({string})who->name(WER)+" ist in den Kreis der Magier "+
MG Mud User88f12472016-06-24 23:31:02 +0200755 "aufgenommen worden!\n");
bugfixd94d0932020-04-08 11:27:13 +0200756 ({int})"secure/master"->renew_player_object(who);
MG Mud User88f12472016-06-24 23:31:02 +0200757 return 1;
758 }
759
760 //
761 // already wizard?
762 //
763 if (IS_WIZARD(who))
764 {
Arathornd5c9c022020-01-08 22:04:28 +0100765 domains=({string*})"secure/master"->get_domain_homes(getuid(who));
MG Mud User88f12472016-06-24 23:31:02 +0200766 if (!domains || !pointerp(domains) || !sizeof(domains))
767 {
bugfixd94d0932020-04-08 11:27:13 +0200768 Say(({string})who->name(WER)+" gehoert noch keiner Region an und kann daher noch "+
MG Mud User88f12472016-06-24 23:31:02 +0200769 "kein Voll-\nmagier werden.\n");
770 Write("Du gehoerst noch keiner Region an. Schliess Dich zunaechst einer "+
771 "an und komm\ndann wieder!\n");
772 return 0;
773 }
Arathornd5c9c022020-01-08 22:04:28 +0100774 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),25);
MG Mud User88f12472016-06-24 23:31:02 +0200775 if(ret>0)
776 {
bugfixd94d0932020-04-08 11:27:13 +0200777 shout(({string})who->name(WER)+" arbeitet jetzt an einer Region mit!\n");
778 ({int})"secure/master"->renew_player_object(who);
MG Mud User88f12472016-06-24 23:31:02 +0200779 return 1;
780 }
781 write("RETURNVALUE "+ret+"\n");
782 say("RETURNVALUE "+ret+"\n");
783 return 0;
784 }
785
786 //
787 // still learner?
788 //
789 if (IS_LEARNER(who))
790 {
791 if (!ARCH_SECURITY) {
792 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
bugfixd94d0932020-04-08 11:27:13 +0200793 Say("Nur ein Erzmagier kann "+({string})who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
MG Mud User88f12472016-06-24 23:31:02 +0200794 return 0;
795 }
Arathornd5c9c022020-01-08 22:04:28 +0100796 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),20);
MG Mud User88f12472016-06-24 23:31:02 +0200797 if (ret<=0)
798 {
799 say("Merlin: error "+ret+"\n");
800 write("Merlin: error "+ret+"\n");
801 }
Arathornd5c9c022020-01-08 22:04:28 +0100802 string wizname = ({string})who->query_real_name();
bugfixd94d0932020-04-08 11:27:13 +0200803 ({int})"secure/master"->renew_player_object(who);
MG Mud User88f12472016-06-24 23:31:02 +0200804 // Fehlerteufel geben
805 call_out(#'GibFehlerteufel,4,find_player(wizname));
806 return 1;
807 }
808
809 //
810 // promoter's level is not >DOMAINMEMBER_LVL+1
811 //
812 if (secure_level()<=DOMAINMEMBER_LVL)
813 {
814 tell_object(promoter,"Du musst derzeit mindestens Level "+
815 (DOMAINMEMBER_LVL+1)+" haben, um jemanden befoerden zu "+
816 "koennen.\n");
bugfixd94d0932020-04-08 11:27:13 +0200817 say(({string})promoter->name(WER)+" ist kein Vollmagier und darf daher niemanden "+
MG Mud User88f12472016-06-24 23:31:02 +0200818 "zum Vollmagier machen.\n");
819 return 1;
820 }
821
822 // der Check auf den Blutprintnamen ist fast ueberfluessig, aber nur fast.
823 // Er schlaegt fehl, wenn der Vertrag der Clone einer alten BP ist.
824 if (!(vertrag=present_clone("/obj/vertrag",who)) ||
825 object_name(blueprint(vertrag))!="/obj/vertrag" ||
bugfixd94d0932020-04-08 11:27:13 +0200826 !(({int})vertrag->is_unterschrieben()) )
MG Mud User88f12472016-06-24 23:31:02 +0200827 {
828 Write("Du hast ja gar keinen unterschriebenen Vertrag bei Dir. Besorg Dir "+
829 "einen Ver-\ntrag, unterschreibe ihn und komm dann wieder!\n");
bugfixd94d0932020-04-08 11:27:13 +0200830 Say(({string})who->name(WER)+" hat keinen unterschriebenen Vertrag.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200831 return 1;
832 }
833 if (geteuid(vertrag)!=secure_euid())
834 {
835 tell_object(promoter,"Das geht nicht, er hat einen Vertrag von "+
836 capitalize(geteuid(vertrag))+" bei sich.\n");
bugfixd94d0932020-04-08 11:27:13 +0200837 say(({string})promoter->name(WER)+" versucht, "+({string})who->name(WER)+" zum Magier zu "+
838 "machen, doch "+({string})who->name(WER)+" hat einen Vertrag\nvon "+
MG Mud User88f12472016-06-24 23:31:02 +0200839 capitalize(geteuid(vertrag))+" bei sich.\n",promoter);
840 return 0;
841 }
842 if (!QueryBedingungen(who,"Magier"))
843 return 0;
Arathornd5c9c022020-01-08 22:04:28 +0100844 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),15);
MG Mud User88f12472016-06-24 23:31:02 +0200845 if (ret>0)
846 {
Zesstra68ee1e52020-04-20 23:24:15 +0200847 // Log ("Magierstammbuch") nach /data/etc loggen, weil SPONSOR ein
848 // langfristlog.
849 write_data("/etc/SPONSOR",dtime(time())+": "+capitalize(getuid(promoter))+" macht "+
bugfixd94d0932020-04-08 11:27:13 +0200850 ({string})who->name(WER)+" zum Learner.\n");
851 write(({string})who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
852 shout(({string})who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
Zesstra68ee1e52020-04-20 23:24:15 +0200853 PostMagier(capitalize(getuid(who)),
854 capitalize(secure_euid()),
855 ({int})who->QueryProp(P_GENDER));
bugfixd94d0932020-04-08 11:27:13 +0200856 if (({int})"secure/master"->set_player_object(geteuid(who),"/std/shells/magier")
MG Mud User88f12472016-06-24 23:31:02 +0200857 <=0)
858 {
859 say("MERLIN: konnte Magiershell nicht einstellen.\n");
860 write("MERLIN: konnte Magiershell nicht einstellen.\n");
861 }
bugfixd94d0932020-04-08 11:27:13 +0200862 ({int})"secure/master"->renew_player_object(who);
Zesstra388cc222020-04-21 23:49:52 +0200863 call_out(function void ()
Zesstra2f85ed72020-04-21 01:28:08 +0200864 { write_data("/etc/SPONSOR.html",wiztree_html(), 1); }, 2);
MG Mud User88f12472016-06-24 23:31:02 +0200865 return 1;
866 }
867 write(" --RETURNVALUE IS "+ret+"\n");
868 say(" --RETURNVALUE IS "+ret+"\n");
869
870 return(ret); //non-void funktion
871}
872
873void clear_flag()
874{
875 flag=0;
876}
877
878void do_say(string str)
879{
880 say(str);
881}
882
883
884
Zesstrab16348b2019-05-21 19:41:36 +0200885void seer_sequenz3(object player, string plname)
MG Mud User88f12472016-06-24 23:31:02 +0200886{
887 string playername;
888 object faq;
889 string text;
890
Zesstra60d9e252019-05-21 20:02:56 +0200891 if (!objectp(player) || !interactive(player)) {
MG Mud User88f12472016-06-24 23:31:02 +0200892 tell_room(environment(), sprintf("Merlin sagt: Na, wo ist denn %s "
893 "hin?\n", plname));
894 busy = 0;
895 return;
896 }
897 if (environment() != environment(player))
898 move(environment(player), M_TPORT);
899
900 tell_object(player,break_string("\n\nEs macht *PUFF* und eine Schwefelwolke "
901 +"steigt um Dich herum auf.\n\nDie Aura "
902 +"verschwindet langsam und Du fuehlst Dich "
903 +"nun viel erfahrener.", 78,0,1));
904 tell_room(environment(),
905 break_string(sprintf(
906 "\n\nEs macht *PUFF* und eine Schwefelwolke steigt "
907 +"um %s herum auf.\n\nDie Aura verschwindet langsam.\n",
908 plname),78,0,1), ({player}));
909
bugfixd94d0932020-04-08 11:27:13 +0200910 if (({int})"secure/master"->advance_wizlevel(geteuid(player),1)<=0)
MG Mud User88f12472016-06-24 23:31:02 +0200911 {
912 write("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
913 say("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
914 busy = 0;
915 return;
916 }
917 playername = geteuid(player);
bugfixd94d0932020-04-08 11:27:13 +0200918 ({int})"secure/master"->renew_player_object(player);
MG Mud User88f12472016-06-24 23:31:02 +0200919 player = find_player(playername);
920 text = sprintf(" ist jetzt ein%s Seher%s!\n",
bugfixd94d0932020-04-08 11:27:13 +0200921 ((({int})player->QueryProp(P_GENDER))==2?"e":""),
922 ((({int})player->QueryProp(P_GENDER))==2?"in":""));
MG Mud User88f12472016-06-24 23:31:02 +0200923 write("Merlin ruft: "+capitalize(playername)+text);
924 shout("Merlin ruft: "+capitalize(playername)+text);
Vanion50652322020-03-10 21:13:25 +0100925 PostSeher(capitalize(playername),({int})player->QueryProp(P_GENDER));
MG Mud User88f12472016-06-24 23:31:02 +0200926 if(!catch(
927 faq=clone_object("/d/seher/haeuser/special/seherfaqmobil") ;publish))
928 {
bugfixd94d0932020-04-08 11:27:13 +0200929 ({int})faq->move(player,M_NOCHECK);
MG Mud User88f12472016-06-24 23:31:02 +0200930 tell_object(player, "Aus dem Nichts erscheint eine kleine Belohnung fuer Dich.\n");
931 }
932
933 tell_object(player, "\n\nDu laechelst gluecklich in die Runde.\n\n");
934 tell_room(environment(), sprintf("\n\n%s laechelt gluecklich in die Runde.\n\n", plname), ({player}));
935
936 busy=0;
937}
938
Zesstrab16348b2019-05-21 19:41:36 +0200939void seer_sequenz2(object player, string plname)
MG Mud User88f12472016-06-24 23:31:02 +0200940{
Zesstra60d9e252019-05-21 20:02:56 +0200941 if (!objectp(player) || !interactive(player)) {
MG Mud User88f12472016-06-24 23:31:02 +0200942 tell_room(environment(), sprintf(
943 "Merlin sagt: Na, wo ist denn %s hin?\n",
944 plname));
945 busy = 0;
946 return;
947 }
948 if (environment() != environment(player))
949 move(environment(player), M_TPORT);
950
zesstra70a0a3e2016-07-06 20:35:40 +0200951 tell_object(player, break_string("\nMerlin hebt die Arme "
MG Mud User88f12472016-06-24 23:31:02 +0200952 +"und macht einige beschwoerende Gesten. Um Dich herum erscheint "
953 +"eine gelbliche Aura, die immer heller wird, bis Du Deine "
954 +"Umwelt kaum mehr erkennen kannst.\n\n",
955 78,0,1));
956 tell_room(environment(),
957 break_string(sprintf("\nMerlin hebt die Arme und macht einige "
958 +"beschwoerende Gesten. Um %s erscheint eine "
959 +"gelbliche Aura, die immer heller wird, bis "
960 +"man %s kaum mehr erkennen kann.\n\n",
961 plname, plname),78,0,1), ({player}));
962
963 call_out("seer_sequenz3", 7, player, plname);
964}
965
Zesstrab16348b2019-05-21 19:41:36 +0200966void seer_sequenz1(object player, string plname)
MG Mud User88f12472016-06-24 23:31:02 +0200967{
Zesstra60d9e252019-05-21 20:02:56 +0200968 if (!objectp(player) || !interactive(player))
MG Mud User88f12472016-06-24 23:31:02 +0200969 return;
970
971 move(environment(player), M_TPORT);
972
973 tell_room(environment(),
974 break_string(sprintf("Das ist eine grosse Freude. %s hat sich "
975 "tapfer durch das "MUDNAME" geschlagen und mittlerweile alle "
976 "Anforderungen erfuellt, um %s zu werden.",
bugfixd94d0932020-04-08 11:27:13 +0200977 plname, (({int})player->QueryProp(P_GENDER))==1?"Seher":"Seherin"),
MG Mud User88f12472016-06-24 23:31:02 +0200978 78, "Merlin sagt: "));
979
980 call_out("seer_sequenz2", 4, player, plname);
981}
982
983
Zesstrab16348b2019-05-21 19:41:36 +0200984static int create_seer(object player)
MG Mud User88f12472016-06-24 23:31:02 +0200985{
Zesstra60d9e252019-05-21 20:02:56 +0200986 if (!objectp(player) || !interactive(player))
MG Mud User88f12472016-06-24 23:31:02 +0200987 return 0;
988 if (IS_SEER(player))
989 {
990 write(break_string("Du bist doch schon kein normaler Spieler mehr, "
991 +"was soll es also?", 78, "Merlin teilt Dir mit: "));
992 return 1;
993 }
994
995 if (!QueryBedingungen(player,"Seher"))
996 return -1;
997
998
999 write(break_string("Grosse Freude! Du hast alle Anforderungen "
1000 "erfuellt. Warte einen Moment...", 78,
1001 "Merlin teilt Dir mit: "));
1002 busy=1;
bugfixd94d0932020-04-08 11:27:13 +02001003 call_out("seer_sequenz1",4,player, ({string})player->Name());
MG Mud User88f12472016-06-24 23:31:02 +02001004 return(0); //non-void funktion
1005}
1006
1007static void give_help(mixed player)
1008{
1009 if (!objectp(player))
1010 return;
1011
1012 tell_object(player,
1013 break_string("Ich weiss nicht, was ich fuer Dich tun kann. "
1014 +"Ich kann Dich zum Seher oder zum Magier "
1015 +"machen, wenn Du mich darum bittest.", 78,
1016 "Merlin teilt Dir mit: "));
1017}
1018
1019
1020void reset()
1021{
1022}
1023
1024public int remove(int silent) {
bugfixd94d0932020-04-08 11:27:13 +02001025 ({int})EVENTD->UnregisterEvent(EVT_LIB_LOGIN, ME);
1026 ({int})EVENTD->UnregisterEvent(EVT_LIB_PLAYER_CREATION, ME);
MG Mud User88f12472016-06-24 23:31:02 +02001027 destruct(this_object());
1028 return 1;
1029}
1030
1031void wandern()
1032{
MG Mud User88f12472016-06-24 23:31:02 +02001033 while (remove_call_out("wandern")>=0);
1034 call_out("wandern",45+random(100));
1035 if (busy) return;
1036 if (delay)
1037 {
1038 delay=0;
1039 return;
1040 }
Zesstra1b6b7362019-04-25 14:08:02 +02001041 if (!environment())
MG Mud User88f12472016-06-24 23:31:02 +02001042 {
1043 move("/gilden/abenteurer",0);
MG Mud User88f12472016-06-24 23:31:02 +02001044 }
1045 //ueber Inv iterieren, ob da ein nicht-idelnder Spieler mit genug XP
Zesstra1b6b7362019-04-25 14:08:02 +02001046 //rumhaengt. In diesem Raum bleiben, wenn ja.
1047 foreach(object ob: all_inventory(environment()))
1048 {
1049 if (interactive(ob) && query_idle(ob)<180
bugfixd94d0932020-04-08 11:27:13 +02001050 && ({int})ob->QueryProp(P_XP)>999999)
MG Mud User88f12472016-06-24 23:31:02 +02001051 return;
1052 }
Zesstra1b6b7362019-04-25 14:08:02 +02001053 // Ausgaenge durchsuchen
Arathornd5c9c022020-01-08 22:04:28 +01001054 mapping ex=({mapping})environment()->QueryProp(P_EXITS);
MG Mud User88f12472016-06-24 23:31:02 +02001055 if (!mappingp(ex))
1056 return;
Arathorne2956b52021-09-06 19:26:49 +02001057 mapping rooms = ([]);
Zesstra1b6b7362019-04-25 14:08:02 +02001058 foreach(string cmd, string|closure dest, string msg : ex)
MG Mud User88f12472016-06-24 23:31:02 +02001059 {
Zesstra1b6b7362019-04-25 14:08:02 +02001060 // nur normale Ausgaenge benutzen
Arathorne2956b52021-09-06 19:26:49 +02001061 if (!stringp(dest) || dest == object_name(environment()))
MG Mud User88f12472016-06-24 23:31:02 +02001062 continue;
Arathorne2956b52021-09-06 19:26:49 +02001063 m_add(rooms, dest);
MG Mud User88f12472016-06-24 23:31:02 +02001064 }
Arathorne2956b52021-09-06 19:26:49 +02001065 if (!sizeof(rooms)) {
1066 move("/gilden/abenteurer",0);
Zesstra1b6b7362019-04-25 14:08:02 +02001067 return;
Arathorne2956b52021-09-06 19:26:49 +02001068 }
Zesstra1b6b7362019-04-25 14:08:02 +02001069
1070 // Und nicht zuruecklatschen, wenn moeglich.
MG Mud User88f12472016-06-24 23:31:02 +02001071 if (prev_room && sizeof(m_indices(rooms))>1)
Arathorne2956b52021-09-06 19:26:49 +02001072 m_delete(rooms, prev_room);
Zesstra1b6b7362019-04-25 14:08:02 +02001073 prev_room=object_name(environment());
1074
1075 string *raeume=m_indices(rooms);
Arathorne2956b52021-09-06 19:26:49 +02001076 move(raeume[random(sizeof(raeume))],0);
MG Mud User88f12472016-06-24 23:31:02 +02001077}
1078
1079string int_short()
1080{
1081 return "Du bist im allseits beliebten Wizclub \"Zum lustigen Merlin\".\n";
1082}
1083
Arathorne2956b52021-09-06 19:26:49 +02001084string _query_int_short() {
1085 return "Der Wizclub \"Zum lustigen Merlin\"";
1086}
1087
MG Mud User88f12472016-06-24 23:31:02 +02001088string int_long(object who,mixed where)
1089{
1090 string descr;
1091
bugfixd94d0932020-04-08 11:27:13 +02001092 if( IS_LEARNER(who) && ({int})who->QueryProp( P_WANTS_TO_LEARN ) )
MG Mud User88f12472016-06-24 23:31:02 +02001093 descr = "[" + object_name(ME) + "]\n";
1094 else
1095 descr = "";
1096 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 +02001097 if ( ({int})who->QueryProp(P_SHOW_EXITS) )
MG Mud User88f12472016-06-24 23:31:02 +02001098 descr += "Es gibt 2 sichtbare Ausgaenge: raus und gilde.\n";
1099 descr += make_invlist(who, all_inventory(ME) - ({ who }));
1100 if( environment())
1101 descr += "\nAusserhalb siehst Du:\n"
bugfixd94d0932020-04-08 11:27:13 +02001102 + ({string})environment()->int_short(who,ME);
MG Mud User88f12472016-06-24 23:31:02 +02001103 return descr;
1104}
1105
1106string make_invlist(object viewer,object *inv)
1107{
1108 int i, iswiz;
1109 string descr;
1110
1111 descr = "";
bugfixd94d0932020-04-08 11:27:13 +02001112 iswiz = IS_LEARNER( viewer ) && ({int})viewer->QueryProp(P_WANTS_TO_LEARN);
MG Mud User88f12472016-06-24 23:31:02 +02001113
1114 for (i = 0; i < sizeof(inv); i++)
1115 {
1116 string sh;
Arathornd5c9c022020-01-08 22:04:28 +01001117 sh = ({string})inv[i]->short();
MG Mud User88f12472016-06-24 23:31:02 +02001118 if (iswiz)
1119 {
1120 if (sh) sh = sh[0..<2] + " ["+object_name(inv[i])+"]\n";
1121 else sh = "["+object_name(inv[i])+"]\n";
1122 }
1123 if (sh) descr += sh;
1124 }
1125 return descr;
1126}
1127
1128void init()
1129{
1130 if (interactive(this_player()) && environment(this_player())==ME)
1131 add_action("gehen","",1);
1132 add_action("befoerdere","befoerder",1);
1133}
1134
1135int befoerdere(string str)
1136{
1137 string wen;
1138 int ret,stufe,l;
1139
1140 if (!LORD_SECURITY) return 0;
1141 if (!str||sscanf(str,"%s auf stufe %d",wen,stufe)<2)
1142 {
1143 notify_fail("Syntax: befoerdere <name> auf stufe <stufe>\n");
1144 return 0;
1145 }
1146 if (stufe>29)
1147 {
1148 write("Maximum ist Stufe 29!\n");
1149 return 1;
1150 }
1151 l=query_wiz_level(wen);
1152 if (l<25)
1153 {
1154 printf("%s muss mindestens zwecks Weiterbefoerderung mindestens Stufe 25 haben.\n",
1155 capitalize(wen));
1156 return 1;
1157 }
1158 if (l>=stufe)
1159 {
1160 printf("%s ist schon Stufe %d.\n",capitalize(wen),l);
1161 return 1;
1162 }
Arathornd5c9c022020-01-08 22:04:28 +01001163 ret=({int})"secure/master"->advance_wizlevel(wen,stufe);
MG Mud User88f12472016-06-24 23:31:02 +02001164 if (ret<=0)
1165 printf("Errorcode %d\n",ret);
1166 else
1167 write("ok\n");
1168 return 1;
1169}
1170
1171int sag(mixed str)
1172{
1173 int i;
1174
1175 if (str==0)
1176 str="";
1177 str = old_explode(break_string(str, 60 ), "\n");
1178 if (busy) {
1179 tell_room(ME, "Merlin mault: Ich bin beschaeftigt.\n");
1180 return 0;
1181 }
1182 for (i = 0; i < sizeof(str); i++)
1183 {
1184 if (!str[i])
1185 str[i]="";
1186 tell_room(environment(),"Merlin sagt: "+str[i]+"\n");
1187 tell_room(ME,"*Merlin sagt: "+str[i]+"\n");
1188 }
1189 return 1;
1190}
1191
1192void show_exits()
1193{
bugfixd94d0932020-04-08 11:27:13 +02001194 printf("%s",({string})environment()->GetExits());
MG Mud User88f12472016-06-24 23:31:02 +02001195}
1196
1197int gehen(string str)
1198{
MG Mud User88f12472016-06-24 23:31:02 +02001199 if (busy) {
1200 write("Merlin mault: Ich bin beschaeftigt.\n");
1201 return 0;
1202 }
1203
Arathornd5c9c022020-01-08 22:04:28 +01001204 str=({string})this_interactive()->_unparsed_args();
Zesstra1b6b7362019-04-25 14:08:02 +02001205 switch (query_verb())
MG Mud User88f12472016-06-24 23:31:02 +02001206 {
1207 case "gilde":
bugfixd94d0932020-04-08 11:27:13 +02001208 ({int})this_player()->move("/gilden/abenteurer",M_GO,"in die Gilde");
MG Mud User88f12472016-06-24 23:31:02 +02001209 return 1;
1210 case "raus":
bugfixd94d0932020-04-08 11:27:13 +02001211 ({int})this_player()->move(environment(),M_GO,"raus");
MG Mud User88f12472016-06-24 23:31:02 +02001212 return 1;
1213 }
1214 if (!IS_WIZARD(this_interactive()))
1215 return 0;
Zesstra1b6b7362019-04-25 14:08:02 +02001216 if (query_verb()!="merlin")
MG Mud User88f12472016-06-24 23:31:02 +02001217 return 0;
1218 delay=1;
Arathornd5c9c022020-01-08 22:04:28 +01001219 mapping exits=({mapping})environment()->QueryProp(P_EXITS);
MG Mud User88f12472016-06-24 23:31:02 +02001220 if (!str||str=="")
1221 {
bugfixd94d0932020-04-08 11:27:13 +02001222 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001223 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..]);
bugfixd94d0932020-04-08 11:27:13 +02001243 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001244 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");
bugfixd94d0932020-04-08 11:27:13 +02001251 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001252 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 }
Arathornd5c9c022020-01-08 22:04:28 +01001277 path = ({string})master()->make_path_absolute(dest);
MG Mud User88f12472016-06-24 23:31:02 +02001278 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
Zesstra2f85ed72020-04-21 01:28:08 +02001346private mapping create_wizard_tree()
1347{
1348 // Jof als root-elemente des Baums wird per Hand angelegt. Erstes Element
1349 // ist der Magierlevel, zweites das Mapping mit den Kindern (der Ast mit den
1350 // Kindern)
1351 mapping mtree = ([ "Jof": 111; m_allocate(100,2) ]);
1352 // Der Cache dient nur dazu, das zu einem Magier gehoerende Mapping der
1353 // Kinder schneller zu finden und verweist auf das Mapping im zweiten
1354 // Value in mtree.
1355 mapping cacheptr = m_allocate(500,1);
1356 cacheptr["Jof"] = mtree["Jof",1];
1357
1358 // Dann Log lesen und parsen.
1359 foreach(string line: explode(read_file("/data/etc/SPONSOR"),"\n"))
1360 {
1361 string parent, child;
1362 if (sscanf(line,"%!s: %s macht %s zum Learner.",parent,child) != 2)
1363 continue;
1364
1365 parent = capitalize(lower_case(parent));
1366 child = capitalize(lower_case(child));
1367
1368 // Das Kind sollte noch nicht existieren... (Tut es aber leider
1369 // gelegentlich.)
1370 if (member(cacheptr, child))
1371// raise_error(sprintf("Neu berufene Magierin ist schon Magierin: "
1372// "%s\n",child));
1373 continue;
1374 // Der Elter muss existieren...
1375 if (!member(cacheptr, parent))
1376 raise_error(sprintf("Sponsor ist keine Magierin: %s\n", parent));
1377
1378 // Mapping mit allen Kindern des Elter holen. Das Mapping in cacheptr ist
1379 // dasselbe Mapping wie in mtree, d.h. wir muessen den Elter nicht im
1380 // verschachtelten mtree suchen.
1381 mapping parent_children = cacheptr[parent];
1382 // neues Kind anlegen
1383 m_add(parent_children, child,
Zesstra4f44c822020-04-23 20:45:32 +02001384 ({int})master()->query_userlist(lower_case(child), USER_LEVEL),
Zesstra2f85ed72020-04-21 01:28:08 +02001385 m_allocate(2,2) );
1386 // und im cacheptr das (noch leere) Mapping fuer die Kinder vom child hinterlegen
1387 m_add(cacheptr, child, parent_children[child, 1]);
1388 }
1389 //printf("mtree: %O\n",mtree);
1390 //printf("cache: %O\n",cacheptr);
1391 return mtree;
1392}
1393
1394// Starte mit dem Magier <node> in <mtree> und laeuft rekursiv durch den
1395// ganzen (Sub-)Baum. Erzeugt eine geschachtelte Struktur von <ul>-Elementen,
1396// bei denen Magier ein <li> sind und die jeweiligen Kinder wieder in ein
1397// tiefer liegendes <ul> kommen. Letztendlich wieder eine Baumstruktur.
1398private string print_mtree_node(mapping mtree, string node, int indent)
1399{
1400 mapping branch = mtree[node, 1];
1401 if (!branch)
1402 raise_error(sprintf("Magier %s existiert nicht.\n",node));
1403
1404 indent += 2;
1405 string res;
1406 // Geloeschte Magier werden durchgestrichen, Vollmagier kriegen ein
1407 // "class=magier" Attribut, was dafuer sorgt, dass die fettgedruckt werden.
1408 if (mtree[node, 0] == 0)
1409 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\">"
1410 "<del>%s</del></a></li>\n", " "*indent, node, node);
1411 else if (mtree[node, 0] < DOMAINMEMBER_LVL)
1412 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\">"
1413 "%s</a></li>\n", " "*indent, node, node);
1414 else
1415 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\""
1416 " class=\"wiz\">%s</a></li>\n", " "*indent, node, node);
1417
1418 // Wenn ein Magier Kinder hat, kommt nun ein neues <ul> dran, welches wieder
1419 // alle Kinder enthaelt.
1420 if (sizeof(branch))
1421 {
1422 // Das root-ul von Jof bekommt das Attribute "id=jof", alle anderen nicht.
1423 res += sprintf("%s<ul%s>\n", " "*indent,
1424 (node == "Jof" ? " id=\"jof\"" : ""));
1425 foreach(string child, int lvl, mapping grandchildren : branch)
1426 {
1427 res += print_mtree_node(branch, child, indent);
1428 }
1429 res += sprintf("%s</ul>\n", " "*indent);
1430 }
1431 return res;
1432}
1433
1434public string wiztree_html()
1435{
1436 mapping mtree = create_wizard_tree();
1437 return sprintf("<ul>\n%s</ul>\n",print_mtree_node(mtree, "Jof", 2));
1438}
1439