blob: b1a4824b40bbaf6f35232c2811d73bd747331e41 [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;
Zesstra1b6b7362019-04-25 14:08:02 +02001057 mapping rooms = m_allocate(sizeof(ex));
1058 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
1061 if (!stringp(dest)
1062 || dest = object_name(environment()))
MG Mud User88f12472016-06-24 23:31:02 +02001063 continue;
Zesstra1b6b7362019-04-25 14:08:02 +02001064 rooms += ([dest]);
MG Mud User88f12472016-06-24 23:31:02 +02001065 }
Zesstra1b6b7362019-04-25 14:08:02 +02001066 if (!sizeof(rooms))
1067 return;
1068
1069 // Und nicht zuruecklatschen, wenn moeglich.
MG Mud User88f12472016-06-24 23:31:02 +02001070 if (prev_room && sizeof(m_indices(rooms))>1)
1071 rooms-=([prev_room]);
Zesstra1b6b7362019-04-25 14:08:02 +02001072 prev_room=object_name(environment());
1073
1074 string *raeume=m_indices(rooms);
1075 move(raeume[sizeof(raeume)],0);
MG Mud User88f12472016-06-24 23:31:02 +02001076}
1077
1078string int_short()
1079{
1080 return "Du bist im allseits beliebten Wizclub \"Zum lustigen Merlin\".\n";
1081}
1082
1083string int_long(object who,mixed where)
1084{
1085 string descr;
1086
bugfixd94d0932020-04-08 11:27:13 +02001087 if( IS_LEARNER(who) && ({int})who->QueryProp( P_WANTS_TO_LEARN ) )
MG Mud User88f12472016-06-24 23:31:02 +02001088 descr = "[" + object_name(ME) + "]\n";
1089 else
1090 descr = "";
1091 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 +02001092 if ( ({int})who->QueryProp(P_SHOW_EXITS) )
MG Mud User88f12472016-06-24 23:31:02 +02001093 descr += "Es gibt 2 sichtbare Ausgaenge: raus und gilde.\n";
1094 descr += make_invlist(who, all_inventory(ME) - ({ who }));
1095 if( environment())
1096 descr += "\nAusserhalb siehst Du:\n"
bugfixd94d0932020-04-08 11:27:13 +02001097 + ({string})environment()->int_short(who,ME);
MG Mud User88f12472016-06-24 23:31:02 +02001098 return descr;
1099}
1100
1101string make_invlist(object viewer,object *inv)
1102{
1103 int i, iswiz;
1104 string descr;
1105
1106 descr = "";
bugfixd94d0932020-04-08 11:27:13 +02001107 iswiz = IS_LEARNER( viewer ) && ({int})viewer->QueryProp(P_WANTS_TO_LEARN);
MG Mud User88f12472016-06-24 23:31:02 +02001108
1109 for (i = 0; i < sizeof(inv); i++)
1110 {
1111 string sh;
Arathornd5c9c022020-01-08 22:04:28 +01001112 sh = ({string})inv[i]->short();
MG Mud User88f12472016-06-24 23:31:02 +02001113 if (iswiz)
1114 {
1115 if (sh) sh = sh[0..<2] + " ["+object_name(inv[i])+"]\n";
1116 else sh = "["+object_name(inv[i])+"]\n";
1117 }
1118 if (sh) descr += sh;
1119 }
1120 return descr;
1121}
1122
1123void init()
1124{
1125 if (interactive(this_player()) && environment(this_player())==ME)
1126 add_action("gehen","",1);
1127 add_action("befoerdere","befoerder",1);
1128}
1129
1130int befoerdere(string str)
1131{
1132 string wen;
1133 int ret,stufe,l;
1134
1135 if (!LORD_SECURITY) return 0;
1136 if (!str||sscanf(str,"%s auf stufe %d",wen,stufe)<2)
1137 {
1138 notify_fail("Syntax: befoerdere <name> auf stufe <stufe>\n");
1139 return 0;
1140 }
1141 if (stufe>29)
1142 {
1143 write("Maximum ist Stufe 29!\n");
1144 return 1;
1145 }
1146 l=query_wiz_level(wen);
1147 if (l<25)
1148 {
1149 printf("%s muss mindestens zwecks Weiterbefoerderung mindestens Stufe 25 haben.\n",
1150 capitalize(wen));
1151 return 1;
1152 }
1153 if (l>=stufe)
1154 {
1155 printf("%s ist schon Stufe %d.\n",capitalize(wen),l);
1156 return 1;
1157 }
Arathornd5c9c022020-01-08 22:04:28 +01001158 ret=({int})"secure/master"->advance_wizlevel(wen,stufe);
MG Mud User88f12472016-06-24 23:31:02 +02001159 if (ret<=0)
1160 printf("Errorcode %d\n",ret);
1161 else
1162 write("ok\n");
1163 return 1;
1164}
1165
1166int sag(mixed str)
1167{
1168 int i;
1169
1170 if (str==0)
1171 str="";
1172 str = old_explode(break_string(str, 60 ), "\n");
1173 if (busy) {
1174 tell_room(ME, "Merlin mault: Ich bin beschaeftigt.\n");
1175 return 0;
1176 }
1177 for (i = 0; i < sizeof(str); i++)
1178 {
1179 if (!str[i])
1180 str[i]="";
1181 tell_room(environment(),"Merlin sagt: "+str[i]+"\n");
1182 tell_room(ME,"*Merlin sagt: "+str[i]+"\n");
1183 }
1184 return 1;
1185}
1186
1187void show_exits()
1188{
bugfixd94d0932020-04-08 11:27:13 +02001189 printf("%s",({string})environment()->GetExits());
MG Mud User88f12472016-06-24 23:31:02 +02001190}
1191
1192int gehen(string str)
1193{
MG Mud User88f12472016-06-24 23:31:02 +02001194 if (busy) {
1195 write("Merlin mault: Ich bin beschaeftigt.\n");
1196 return 0;
1197 }
1198
Arathornd5c9c022020-01-08 22:04:28 +01001199 str=({string})this_interactive()->_unparsed_args();
Zesstra1b6b7362019-04-25 14:08:02 +02001200 switch (query_verb())
MG Mud User88f12472016-06-24 23:31:02 +02001201 {
1202 case "gilde":
bugfixd94d0932020-04-08 11:27:13 +02001203 ({int})this_player()->move("/gilden/abenteurer",M_GO,"in die Gilde");
MG Mud User88f12472016-06-24 23:31:02 +02001204 return 1;
1205 case "raus":
bugfixd94d0932020-04-08 11:27:13 +02001206 ({int})this_player()->move(environment(),M_GO,"raus");
MG Mud User88f12472016-06-24 23:31:02 +02001207 return 1;
1208 }
1209 if (!IS_WIZARD(this_interactive()))
1210 return 0;
Zesstra1b6b7362019-04-25 14:08:02 +02001211 if (query_verb()!="merlin")
MG Mud User88f12472016-06-24 23:31:02 +02001212 return 0;
1213 delay=1;
Arathornd5c9c022020-01-08 22:04:28 +01001214 mapping exits=({mapping})environment()->QueryProp(P_EXITS);
MG Mud User88f12472016-06-24 23:31:02 +02001215 if (!str||str=="")
1216 {
bugfixd94d0932020-04-08 11:27:13 +02001217 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001218 show_exits();
1219 return 1;
1220 }
1221 if (old_explode(str," ")[0]=="sag")
1222 return sag(implode(old_explode(str," ")[1..]," "));
1223 if (str[0]==';')
1224 {
1225 tell_room(environment(ME),"Merlins "+str[1..]+"\n");
1226 tell_room(ME,"*Merlins "+str[1..]+"\n");
1227 return 1;
1228 }
1229 if (str[0]==':')
1230 {
1231 tell_room(environment(ME),"Merlin "+str[1..]+"\n");
1232 tell_room(ME,"*Merlin "+str[1..]+"\n");
1233 return 1;
1234 }
1235 if (str[0]=='*')
1236 {
1237 goto(str[1..]);
bugfixd94d0932020-04-08 11:27:13 +02001238 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001239 show_exits();
1240 return 1;
1241 }
1242 if (!exits[str])
1243 return 0;
1244 move(exits[str],0);
1245 write("Merlin sagt: Jawoll, Chef.\n");
bugfixd94d0932020-04-08 11:27:13 +02001246 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001247 show_exits();
1248 return 1;
1249}
1250
1251int goto(mixed dest)
1252{
1253 object ob;
1254 string path;
1255 mixed ret;
1256
1257 if (busy) {
1258 write("Merlin mault: Ich bin beschaeftigt.\n");
1259 return 1;
1260 }
1261
1262 if (!dest) {
1263 write("Wohin moechtest Du Merlin bringen ?\n");
1264 return 1;
1265 }
1266 ob = find_living(dest);
1267 if (ob) {
1268 ob = environment(ob);
1269 move(object_name(ob),0);
1270 return 1;
1271 }
Arathornd5c9c022020-01-08 22:04:28 +01001272 path = ({string})master()->make_path_absolute(dest);
MG Mud User88f12472016-06-24 23:31:02 +02001273 ret=catch(load_object(path);publish);
1274 if (ret && file_size(path)<0)
1275 {
1276 dest=match_living(dest,1);
1277 if (stringp(dest))
1278 {
1279 ob = environment(find_living(dest));
1280 move(object_name(ob),M_TPORT|M_NOCHECK);
1281 return 1;
1282 }
1283 printf("Fehler beim Teleport nach %O: No such file.\n",path);
1284 return 1;
1285 }
1286 if (ret)
1287 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1288 ret=catch(move(path,M_TPORT|M_NOCHECK);publish);
1289 if (stringp(ret))
1290 ret=implode(old_explode(ret,"\n"),"");
1291 if (ret)
1292 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1293 return 1;
1294}
1295
1296mixed locate_objects(string complex_desc)
1297{
1298 object ob;
1299
1300 if (complex_desc=="alles" || complex_desc=="alle")
1301 return filter_objects(all_inventory(this_object()),"short");
1302 if (ob = present(complex_desc,this_object()) )
1303 return ({ ob });
1304 return ({}) ;
1305}
1306
1307void MBanishInsert(string name, string grund, object wer)
1308{
1309 if ( !name || !stringp(name) || !sizeof(name) ||
1310 !grund || !stringp(grund) || !sizeof(grund) ||
1311 !wer || !objectp(wer) || getuid(wer) != secure_euid() ||
1312 !IS_DEPUTY(wer) )
1313 return;
1314
1315 MBanishListe += ([name:grund;getuid(wer)]);
1316 save_object(SAVEFILE);
1317}
1318
1319mapping MBanishList()
1320{
1321 if ( !IS_DEPUTY(secure_euid()) )
1322 return 0;
1323
1324 return deep_copy(MBanishListe);
1325}
1326
1327void MBanishDelete(string name)
1328{
1329 if ( !name || !stringp(name) || !sizeof(name) || !ARCH_SECURITY )
1330 return 0;
1331
1332 MBanishListe = m_copy_delete( MBanishListe, name );
1333 save_object(SAVEFILE);
1334}
1335
1336string _query_noget()
1337{
1338 return "Merlin mag das nicht!\n";
1339}
1340
Zesstra2f85ed72020-04-21 01:28:08 +02001341private mapping create_wizard_tree()
1342{
1343 // Jof als root-elemente des Baums wird per Hand angelegt. Erstes Element
1344 // ist der Magierlevel, zweites das Mapping mit den Kindern (der Ast mit den
1345 // Kindern)
1346 mapping mtree = ([ "Jof": 111; m_allocate(100,2) ]);
1347 // Der Cache dient nur dazu, das zu einem Magier gehoerende Mapping der
1348 // Kinder schneller zu finden und verweist auf das Mapping im zweiten
1349 // Value in mtree.
1350 mapping cacheptr = m_allocate(500,1);
1351 cacheptr["Jof"] = mtree["Jof",1];
1352
1353 // Dann Log lesen und parsen.
1354 foreach(string line: explode(read_file("/data/etc/SPONSOR"),"\n"))
1355 {
1356 string parent, child;
1357 if (sscanf(line,"%!s: %s macht %s zum Learner.",parent,child) != 2)
1358 continue;
1359
1360 parent = capitalize(lower_case(parent));
1361 child = capitalize(lower_case(child));
1362
1363 // Das Kind sollte noch nicht existieren... (Tut es aber leider
1364 // gelegentlich.)
1365 if (member(cacheptr, child))
1366// raise_error(sprintf("Neu berufene Magierin ist schon Magierin: "
1367// "%s\n",child));
1368 continue;
1369 // Der Elter muss existieren...
1370 if (!member(cacheptr, parent))
1371 raise_error(sprintf("Sponsor ist keine Magierin: %s\n", parent));
1372
1373 // Mapping mit allen Kindern des Elter holen. Das Mapping in cacheptr ist
1374 // dasselbe Mapping wie in mtree, d.h. wir muessen den Elter nicht im
1375 // verschachtelten mtree suchen.
1376 mapping parent_children = cacheptr[parent];
1377 // neues Kind anlegen
1378 m_add(parent_children, child,
Zesstra4f44c822020-04-23 20:45:32 +02001379 ({int})master()->query_userlist(lower_case(child), USER_LEVEL),
Zesstra2f85ed72020-04-21 01:28:08 +02001380 m_allocate(2,2) );
1381 // und im cacheptr das (noch leere) Mapping fuer die Kinder vom child hinterlegen
1382 m_add(cacheptr, child, parent_children[child, 1]);
1383 }
1384 //printf("mtree: %O\n",mtree);
1385 //printf("cache: %O\n",cacheptr);
1386 return mtree;
1387}
1388
1389// Starte mit dem Magier <node> in <mtree> und laeuft rekursiv durch den
1390// ganzen (Sub-)Baum. Erzeugt eine geschachtelte Struktur von <ul>-Elementen,
1391// bei denen Magier ein <li> sind und die jeweiligen Kinder wieder in ein
1392// tiefer liegendes <ul> kommen. Letztendlich wieder eine Baumstruktur.
1393private string print_mtree_node(mapping mtree, string node, int indent)
1394{
1395 mapping branch = mtree[node, 1];
1396 if (!branch)
1397 raise_error(sprintf("Magier %s existiert nicht.\n",node));
1398
1399 indent += 2;
1400 string res;
1401 // Geloeschte Magier werden durchgestrichen, Vollmagier kriegen ein
1402 // "class=magier" Attribut, was dafuer sorgt, dass die fettgedruckt werden.
1403 if (mtree[node, 0] == 0)
1404 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\">"
1405 "<del>%s</del></a></li>\n", " "*indent, node, node);
1406 else if (mtree[node, 0] < DOMAINMEMBER_LVL)
1407 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\">"
1408 "%s</a></li>\n", " "*indent, node, node);
1409 else
1410 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\""
1411 " class=\"wiz\">%s</a></li>\n", " "*indent, node, node);
1412
1413 // Wenn ein Magier Kinder hat, kommt nun ein neues <ul> dran, welches wieder
1414 // alle Kinder enthaelt.
1415 if (sizeof(branch))
1416 {
1417 // Das root-ul von Jof bekommt das Attribute "id=jof", alle anderen nicht.
1418 res += sprintf("%s<ul%s>\n", " "*indent,
1419 (node == "Jof" ? " id=\"jof\"" : ""));
1420 foreach(string child, int lvl, mapping grandchildren : branch)
1421 {
1422 res += print_mtree_node(branch, child, indent);
1423 }
1424 res += sprintf("%s</ul>\n", " "*indent);
1425 }
1426 return res;
1427}
1428
1429public string wiztree_html()
1430{
1431 mapping mtree = create_wizard_tree();
1432 return sprintf("<ul>\n%s</ul>\n",print_mtree_node(mtree, "Jof", 2));
1433}
1434