blob: 456aced76fa9ea2ed6bf0d018c3147ae9b00a26d [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();
Bugfix99adc422021-10-07 16:56:30 +020074# ifndef __TESTMUD__
MG Mud User88f12472016-06-24 23:31:02 +020075 call_out("wandern",25);
Bugfix99adc422021-10-07 16:56:30 +020076# endif
MG Mud User88f12472016-06-24 23:31:02 +020077 move("/gilden/abenteurer",0);
78 MBanishListe = m_allocate(0,2);
79 restore_object(SAVEFILE);
bugfixd94d0932020-04-08 11:27:13 +020080 ({int})EVENTD->RegisterEvent(EVT_LIB_PLAYER_CREATION, "player_change", ME);
81 ({int})EVENTD->RegisterEvent(EVT_LIB_LOGIN, "player_change", ME);
MG Mud User88f12472016-06-24 23:31:02 +020082 // absichtlich kein EVT_LIB_LOGOUT, s. Kommentar zu notify_player_leave().
83}
84
85string _query_kill_name()
86{
87 return "Ein genervter Merlin";
88}
89
90int move(mixed ob,int methods)
91{
92 object tmp;
93
94 if (methods&M_GET)
95 return ME_CANT_BE_TAKEN;
96
97 if (stringp(ob))
98 {
99 if (!(tmp=find_object(ob)))
100 {
101 call_other(ob,"?");
102 tmp=find_object(ob);
103 }
104 ob=tmp;
105 }
106 if (!objectp(ob))
107 return 0;
108 if (environment())
109 tell_room(environment(),"Merlin zieht weiter.\n");
110 tell_room(ob,"Merlin kommt an.\n");
111 move_object(ob);
112 return 1;
113}
114
115mixed QueryProp(string str)
116{
117 if (!stringp(str)||str=="")
118 return 0;
bugfixd94d0932020-04-08 11:27:13 +0200119 return ({mixed})call_other(this_object(),"_query_"+str);
MG Mud User88f12472016-06-24 23:31:02 +0200120}
121
122varargs int id(string str)
123{
124 return (str=="merlin");
125}
126
127varargs string name(int casus, int demon)
128{
129 if (casus!=WESSEN)
130 return "Merlin";
131 return "Merlins";
132}
133
134varargs string Name(int casus, int daemon)
135{
136 return name(casus,daemon);
137}
138
139string QueryDu(int casus, int gender, int zahl)
140{
141 return
142 ({ ({ ({ "du", "ihr"}), ({ "du", "ihr"}), ({ "du", "ihr"}) }),
143 ({({"deines","deiner"}),({"deines","deiner"}),({"deiner","deiner"})}),
144 ({({"dir","euch"}),({"dir","euch"}),({"dir","euch"})}),
145 ({({"dich","euch"}),({"dich","euch"}),({"dich","euch"})})
146 })[casus][gender][zahl];
147}
148
149string long()
150{
bugfixd94d0932020-04-08 11:27:13 +0200151 ({int})EPMASTER->GiveExplorationPoint("merlin");
MG Mud User88f12472016-06-24 23:31:02 +0200152 return break_string(
153 "Merlin - der maechtige Urvater aller Magier - ist ein hagerer "
154 "Mann, der einen blauen, mit Monden und Sternen uebersaeten Umhang "
155 "traegt und sich auf einen knorrigen Stock stuetzt. Sein langer weisser "
156 "Bart reicht ihm fast bis zur Guertelschnalle, sein Haupthaar ist fast "
157 "ebenso lang. Auf seinem Kopf traegt er einen spitzen Hut, der ihn noch "
158 "groesser macht, als er ohnehin schon ist.\nEr ist unangreifbar, denn "
159 "er steht ueber solchen Dingen.",78,BS_LEAVE_MY_LFS);
160}
161
162string GetDetail(string key,mixed race,int sense) {
163 switch( sense ) {
164 case SENSE_SMELL: return 0;
165 case SENSE_SOUND: return 0;
166 }
167 switch( key ) {
168 case "nase": case "nasenhaare": case "hakennase":
169 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.");
170 case "brille": case "glaeser": case "form": case "halbmond":
171 return "Merlins Brille besitzt Glaeser in Form eines Halbmondes.\n";
172 case "bart":
173 return "Merlins Bart ist sehr lang - Er reicht fast bis ueber die Guertelschnalle.\n";
174 case "haare" :
175 return "Sie reichen ihm bis zwischen die Schulterblaetter.\n";
176 case "schulterblaetter": case "schulterblatt":
177 return "Seine langen Haare bedecken die Schulterblaetter.\n";
178 case "gewand": case "robe":
179 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.");
180 case "zweck":
181 return BS("Der Zweck des Gewandes besteht darn, Merlin standesgemaess zu bekleiden. Diesem Zweck kommt das Gewand in Vollendung nach.");
182 case "vollendung":
183 return "Nichts ist vollkommen.\n";
184 case "hut":
185 return BS("Ein langer, spitzer Hut, der in der gleichen Weise wie seine Robe mit Monden und Sternen bestickt ist.");
186 case "mond": case "monde": case "stern": case "sterne":
187 return BS("Die Monde und die Sterne sind mit silbrigen Faeden gestickt, die das Licht funkelnd zurueckwerfen.");
188 case "faden": case "faeden":
189 return BS("Schwer zu sagen, woraus die Faeden sind. Mithril? "
190 "Mondsilber?");
191 case "licht": case "mondsilber": case "mithril":
Arathorn9dd23332020-12-28 11:06:10 +0100192 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 +0200193 case "abstand":
194 return BS("Von so einem Magier sollte man aus Respekt einen Schritt Abstand halten.");
195 case "respekt":
196 return "Du hast sicher mehr Respekt vor Merlin, als er vor Dir.\n";
197 case "schritt":
198 return "Wessen Schritt??\n";
199 case "hand": case "haende":
200 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.");
201 case "gichtknoten": case "gicht":
202 return BS("Durch die Gichtknoten sehen seine Haende fast so knorrig wie sein Gehstock aus.");
203 case "finger": case "fingernaegel": case "fingernagel":
204 return BS("Seine Finger sind voller Gichtknoten und seine gelben Fingernaegel koennte Merlin auch mal wieder schneiden.");
205 case "gehstock": case "stock":
206 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?");
207 case "zauberstab": case "magierstab":
208 return BS("Merlin stuetzt sich auf einen knorrigen Gehstock. Das koennte sein Zauberstab sein - aber vielleicht ist es auch nur ein Gehstock.");
209 case "guertel": case "guertelschnalle":
210 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.'");
211 }
212 return 0;
213}
214
215
216string short()
217{
218 return "Merlin, der Urvater aller Magier.\n";
219}
220
221string _query_race()
222{
223 return "Magier";
224}
225
226int _query_gender()
227{
228 return 1;
229}
230
231string QueryPossPronoun( mixed what, int casus, int number )
232{
233 int gen2;
bugfixd94d0932020-04-08 11:27:13 +0200234 gen2 = ( intp( what ) ) ? what : ({int})what->QueryProp(P_GENDER);
MG Mud User88f12472016-06-24 23:31:02 +0200235 return "sein" + query_g_suffix( gen2, casus, number );
236}
237
238string query_g_suffix( int gen, int casus, int anzahl )
239{
240 return ({ ({ ({"","e"}), ({"es","er"}), ({"em","en"}), ({"","e"}) }),
241 ({ ({"","e"}), ({"es","er"}), ({"em","en"}), ({"en","e"}) }),
242 ({ ({"e","e"}), ({"er","er"}), ({"er","en"}), ({"e","e"}) }) })
243 [gen][casus][anzahl];
244}
245
246string QueryPronoun(int casus)
247{
248 switch(casus) {
Zesstrac27c7c22021-05-13 14:36:40 +0200249 case WER: return "er";
MG Mud User88f12472016-06-24 23:31:02 +0200250 case WEM: return "ihm";
251 }
252 return "ihn";
253}
254
255string _query_short()
256{
257 return short();
258}
259
260string _query_long()
261{
262 return long();
263}
264
265string _query_name()
266{
267 return "Merlin";
268}
269
270int _query_weight()
271{
272 return 75000;
273}
274
275static void PostSeher(string who, int g)
276{
277 mixed *art;
278
279 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 +0200280 ({int})"/secure/news"->WriteNote(art,1);
MG Mud User88f12472016-06-24 23:31:02 +0200281}
282
283static void PostMagier(string who, string prom, int gender)
284{
285 mixed *art;
286
287 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,
288(gender==2?"r":"m"),(gender==2?"Tochter":"Sohn"))});
bugfixd94d0932020-04-08 11:27:13 +0200289 ({int})"/secure/news"->WriteNote(art,1);
MG Mud User88f12472016-06-24 23:31:02 +0200290}
291
292
293private void GibFehlerteufel(object wiz) {
294 if (!objectp(wiz))
295 return;
296
bugfixd94d0932020-04-08 11:27:13 +0200297 ({int})clone_object(FEHLERTEUFEL)->move(wiz, M_NOCHECK|M_GET);
MG Mud User88f12472016-06-24 23:31:02 +0200298 tell_object(wiz, break_string(
bugfixd94d0932020-04-08 11:27:13 +0200299 "Huhu "+({string})wiz->Name(WER) + "! Ich habe gesehen, dass Du keinen "
MG Mud User88f12472016-06-24 23:31:02 +0200300 "Fehlerteufel hast. Dieses Tool ist zum Debuggen von Fehlern im "
301 "Mud sehr praktisch. Bitte schau ihn Dir mal an. :-) Die Hilfe zum "
302 "Fehlerteufel kannst Du mit 'man fehlerteufel' lesen. BTW: Wenn "
303 "Du den Fehlerteufel nicht willst, kannst Du ihn zerstoeren, ich "
304 "werde Dich kein zweites Mal damit belaestigen.",78,
305 "Merlin teilt Dir mit: ")
306 + "Merlin ueberreicht Dir aus der Ferne einen knusprig gebratenen "
307 "Fehlerteufel.\n\n");
308}
309
310private void notify_player_change(string who,int rein)
311{
312 if (!stringp(who))
313 return;
314
315 // Max-user festhalten
316 if (file_size("/etc/maxusers")<=0)
317 maxusers=0;
318 if (sizeof(users())>=maxusers)
319 {
320 maxusers=sizeof(users());
321 write_file("etc/maxusers",sprintf("%d user: %s (%s)\n",
322 maxusers,dtime(time()),query_load_average()),1);
323 }
324
325 // allen Magiern ab Level 20, die keinen Fehlerteufel haben und deren
326 // letzter Logout vor "Die, 17. Mar 2009, 23:40:04" => 1237329604 war,
327 // einen Fehlerteufel clonen und nen Hiwneis mitteilen.
328 object ob = find_player(who);
329 if (ob && rein && IS_WIZARD(ob)
330 && !present_clone(FEHLERTEUFEL,ob)
bugfixd94d0932020-04-08 11:27:13 +0200331 && ({int})ob->QueryProp(P_LAST_LOGOUT) < 1237329604 )
MG Mud User88f12472016-06-24 23:31:02 +0200332 GibFehlerteufel(ob);
333}
334
335private void AnnounceNewPlayer(object pl) {
336
337 if (!pl || !interactive(pl))
338 return;
339
Zesstra31ae1582019-07-30 20:09:01 +0200340 // verzoegern, bis der Spieler wirklich fertig und in /d/ angekommen ist,
341 // weil dann der initiale Scroll abgeklungen ist und der Spieler die
342 // Willkommensmeldungen von Merlin und Spielern hoffentlich auch wahrnimmt.
343 if (!environment(pl)
344 || strstr(object_name(environment(pl)), "/"DOMAINDIR"/") != 0)
345 {
346 call_out(#'AnnounceNewPlayer,20,pl);
MG Mud User88f12472016-06-24 23:31:02 +0200347 return;
348 }
349
bugfixd94d0932020-04-08 11:27:13 +0200350 if (!({int})pl->QueryGuest()) {
Arathornd5c9c022020-01-08 22:04:28 +0100351 string plname = ({string})pl->Name(WER);
MG Mud User88f12472016-06-24 23:31:02 +0200352 CHMASTER->send("Anfaenger", this_object(),
353 sprintf("%s macht nun ebenfalls das Morgengrauen unsicher. "
354 "Herzlich Willkommen %s!", plname, plname)
355 );
356 }
357}
358
Zesstrac27c7c22021-05-13 14:36:40 +0200359// Spielerobjekte aufgrund eines Bugs bei der Berechnung der Schutzwirkung
360// von P_BODY erneuern
361#if __BOOT_TIME__ < 1620557318
362#define BUGTIME 1620409462
363#define BUGFIXTIME 1620635153
MG Mud User88f12472016-06-24 23:31:02 +0200364void renew_player(string plname, int force) {
365 object pl;
366 mixed err;
367
368 pl = find_player(plname);
369 if (!objectp(pl) || !query_once_interactive(pl)) return;
370
371 // jung oder alt genug, Abbruch. ;-)
372 if ((object_time(pl) > BUGFIXTIME)
373 || object_time(pl) < BUGTIME)
374 return;
375
376 if (get_eval_cost() < 1000000 || !force ) {
377 call_out("renew_player",8,plname,1);
378 tell_object(pl,break_string(sprintf("Huhu %s, um einen Bug in "
379 "Deinem Spielerobjekt zu beheben, wirst Du in ca. 8s "
380 "neugeladen. Bitte warte bis dahin ab und bleibe, wo "
bugfixd94d0932020-04-08 11:27:13 +0200381 "Du gerade bist.",({string})pl->Name()),78,"Merlin teilt Dir mit: "));
MG Mud User88f12472016-06-24 23:31:02 +0200382 return;
383 }
384
385 plname=getuid(pl);
386 tell_object(pl,break_string(sprintf("Huhu %s, um einen Bug in "
387 "Deinem Spielerobjekt zu beheben, wirst Du jetzt "
bugfixd94d0932020-04-08 11:27:13 +0200388 "neugeladen.",({string})pl->Name()),78,"Merlin teilt Dir mit: "));
MG Mud User88f12472016-06-24 23:31:02 +0200389
bugfixd94d0932020-04-08 11:27:13 +0200390 if (err=catch(({int})master()->renew_player_object(pl);publish)) {
MG Mud User88f12472016-06-24 23:31:02 +0200391 log_file("zesstra/failed_rewew.log",sprintf("%s: Fehler %O beim "
392 "Renew von %s\n",dtime(time()),err,plname));
393 tell_object(pl,break_string("Beim Neuladen Deines Spielerobjekts "
394 "gab es einen Fehler. Bitte wende Dich an einen EM.",78,
395 "Merlin teilt Dir mit: "));
396 }
397 else {
398 log_file("zesstra/renewed.log",sprintf("%s: %s wurde renewed.\n",
399 dtime(time()),plname));
400 if (objectp(find_player(plname)))
401 tell_object(find_player(plname),
402 break_string("Dein Spielerobjekt wurde neugeladen. Du "
403 "kannst jetzt normal weiterspielen. Falls Du etwas ungewoehnliches "
404 "bemerkst, melde Dich bitte bei einem Erzmagier. Viel Spass im "
405 "Spiel!",78, "Merlin teilt Dir mit: "));
406 }
407}
408#endif
409
410void player_change(string eid, object trigob, mixed data) {
411
412 if (!trigob || !interactive(trigob))
413 return;
414
415 switch(eid) {
416 case EVT_LIB_PLAYER_CREATION:
417 call_out(#'AnnounceNewPlayer, 5, trigob);
418 break;
419 case EVT_LIB_LOGIN:
420 notify_player_change(data[E_PLNAME],1);
Zesstrac27c7c22021-05-13 14:36:40 +0200421#if __BOOT_TIME__ < 1620557318
422 // Spieler evtl. renewen?
MG Mud User88f12472016-06-24 23:31:02 +0200423 renew_player(data[E_PLNAME],0);
424#endif
425 break;
426 }
427}
428
429
430//besser P_NO_ATTACK als Defend()...
431mixed _query_no_attack() {
432 if (!living(PL) || !objectp(environment(PL)) ) return(1);
433
434 tell_room(environment(), "Merlin schimpft: Lass das!!!\n",({PL}));
435 tell_room(environment(),sprintf(
436 "Merlin gibt %s eine schallende Ohrfeige.\n",
Arathornd5c9c022020-01-08 22:04:28 +0100437 capitalize(({string})this_player()->name(WEM))), ({this_player()}));
MG Mud User88f12472016-06-24 23:31:02 +0200438 return("Merlin schimpft: Lass das!!!\n"
439 "Merlin gibt Dir eine schallende Ohrfeige.\n");
440}
441
442/*
443int Defend(int dam, string dam_type, int spell, object enemy)
444{
445 object en;
446 if (!en=previous_object() || !living(en))
447 en = this_player();
448 tell_room(environment(), "Merlin schimpft: Lass das!!!\n");
449 write("Merlin gibt Dir eine schallende Ohrfeige.\n");
450 say(sprintf("Merlin gibt %s eine schallende Ohrfeige.\n",
451 capitalize((string)this_player()->name(WEM))), this_player());
bugfixd94d0932020-04-08 11:27:13 +0200452 ({int})en->StopHuntFor(this_object(), 1);
MG Mud User88f12472016-06-24 23:31:02 +0200453}
454*/
455void shoutansw()
456{
457 object env,ti;
458 string *path;
459 string ans;
460
461 if (!(env=environment()))
462 return;
bugfixd94d0932020-04-08 11:27:13 +0200463 if (!(ti=this_interactive())||({int})ti->QueryProp(P_LEVEL)<19||({int})ti->QueryProp(P_GHOST))
MG Mud User88f12472016-06-24 23:31:02 +0200464 return;
465 tell_object(ti,"Du spuerst einen sengenden Schmerz.\n");
bugfixd94d0932020-04-08 11:27:13 +0200466 ({int})ti->do_damage( ({int})ti->QueryProp(P_HP) / 2 + 5);
467 if(({int})ti->QueryProp(P_GHOST)) return;
MG Mud User88f12472016-06-24 23:31:02 +0200468 ans="ich hab nicht die leiseste Idee, wo ich hier bin ...\n";
469 path=old_explode(object_name(env),"/");
470 if (path[0]=="d")
471 {
472 ans="werweisswo ..";
473 switch(path[1])
474 {
475 case "gebirge":
476 case "wald":
477 case "dschungel":
478 ans="im "+capitalize(path[1]);
479 break;
480 case "inseln":
481 ans="auf den Inseln";
482 break;
483 case "polar":
484 ans="im Polargebiet";
485 break;
486 case "unterwelt":
487 case "ebene":
488 case "wueste":
489 ans="in der "+capitalize(path[1]);
490 break;
491 case "vland":
492 ans="im Verlorenen Land";
493 break;
494 case "fernwest":
495 ans="in Fernwest";
496 break;
497 }
498 ans="ich bin "+ans+".\n";
499 }
500 if (path[0]=="players")
501 ans="ich hab mich verlaufen - ich schaetze, "+capitalize(path[1])+
502 " hat was damit zu tun...\n";
503 if (path[0]=="gilden") {
504 switch(path[1]) {
505 case "abenteurer":
506 ans="der Abenteurergilde";
507 break;
508 case "bierschuettler":
509 ans="der Bierschuettlergilde";
510 break;
511 case "chaos":
512 ans="der Gilde der Chaoten";
513 break;
514 case "kaempfer":
515 ans="der Kaempfergilde";
516 break;
517 case "karate":
518 ans="einem Karatedojo";
519 break;
520 case "klerus":
521 ans="einem Tempel der Kleriker";
522 break;
523 case "zauberer":
524 ans="der Akademie der Zauberer";
525 break;
526 default:
527 ans="irgendeiner Gilde";
528 }
529 ans="ich stehe in "+ans+".\n";
530 }
531 if( path[0]=="p" && path[1]=="verein" ) {
532 ans="ich stehe in Port Vain.";
533 }
bugfixd94d0932020-04-08 11:27:13 +0200534 if (!({int})this_interactive()->QueryProp(P_INVIS))
535 ans=({string})this_interactive()->Name(WER)+", "+ans;
MG Mud User88f12472016-06-24 23:31:02 +0200536 else ans=capitalize(ans);
537 call_out("myshout",0,break_string(ans, 78, "Merlin ruft: "));
538}
539
540void myshout(string s)
541{
542 write(s);
543 shout(s);
544}
545
546void catch_tell(string str)
547{
Zesstrac27c7c22021-05-13 14:36:40 +0200548 string name; mixed message;
549 int i;
MG Mud User88f12472016-06-24 23:31:02 +0200550
551 if (!this_player())
552 return;
553
554 if (environment()==environment(this_player()) && previous_object()!=ME)
555 tell_room(this_object(),"*"+str);
556
557 if (this_player() != this_interactive())
558 return;
559
560 if (busy) {
561 tell_object(this_player(),
562 "Merlin teilt Dir mit: Ich bin beschaeftigt.\n");
563 return;
564 }
565
566 str=lower_case(str);
567
568 if ((strstr(str, "teilt dir mit:") != -1)
569 && (strstr(str, "wo bist du") !=-1)) {
570 shoutansw();
571 return;
572 }
573
574 if ((strstr(str, "teilt dir mit:") != -1) &&
575 ((strstr(str, "seher") != -1 || strstr(str, "seherin") != -1)))
576 {
577 create_seer(this_player());
578 return;
579 }
580
Zesstrac27c7c22021-05-13 14:36:40 +0200581 if (sscanf(str,"%~s %s sagt: %s",name,message)!=3)
MG Mud User88f12472016-06-24 23:31:02 +0200582 if (sscanf(str,"%s sagt: %s",name,message)!=2)
583 return;
584
bugfixd94d0932020-04-08 11:27:13 +0200585 if (!name || !sizeof(name) || !({int})master()->find_userinfo(name))
MG Mud User88f12472016-06-24 23:31:02 +0200586 return;
587
588 if (name!=getuid(this_interactive()) && !ARCH_SECURITY)
589 {
590 if (flag==getuid(this_interactive())+"##"+name)
591 return;
592 call_out("do_say",0,"Merlin sagt: "+capitalize(getuid(this_interactive()))+" hat gerade so getan, als wuerde "+capitalize(name)+" etwas sagen!\n");
593 flag=getuid(this_interactive())+"##"+name;
594 call_out("clear_flag",0);
595 return;
596 }
597 flag=0;
598 for (i=0;i<sizeof(whitespaces);i++)
599 {
600 message=old_explode(message,whitespaces[i]);
601 if (!pointerp(message)||sizeof(message)==0)
602 return;
603 message=implode(message," ");
604 }
605
606 message=old_explode(message," ");
607
608 if (!pointerp(message) || !sizeof(message))
609 return;
610
611 message-=({0})-({""});
612
613 if (!message || sizeof(message)==0)
614 return;
615
616 if (member(message, "merlin")==-1)
617 return;
618
619 message-=({"merlin"});
620
621 message=implode(message," ");
622
623 if (!message || message=="")
624 return;
625
626 determine_action(message, name);
627}
628
629static int determine_action(string mess, string name)
630{
631 string str;
632
633 if (mess=="mach mich zum magier" || mess=="mach mich zur magierin")
634 return create_wizard(name,name);
635
636 if (sscanf(mess,"mach %s zum magier",str)==1||sscanf(mess,"mach %s zur magierin",str)==1)
637 return create_wizard(lower_case(str),name);
638
639 give_help(name);
640 return 0;
641}
642
643#define Say(str) say(str,who)
644#define Write(str) tell_object(who,str)
645
646int QueryBedingungen(object pl,string was)
647{
MG Mud User88f12472016-06-24 23:31:02 +0200648 if (IS_SEER(pl))
649 return 1;
650
bugfixd94d0932020-04-08 11:27:13 +0200651 if (({int})LEPMASTER->QueryReadyForWiz(pl)==1)
MG Mud User88f12472016-06-24 23:31:02 +0200652 return 1;
653
Zesstrac27c7c22021-05-13 14:36:40 +0200654 string s=({string})LEPMASTER->QueryReadyForWizText(pl);
MG Mud User88f12472016-06-24 23:31:02 +0200655
656 tell_object(pl, break_string("Merlin gruebelt ein wenig und teilt Dir "
657 "nach einigem Ueberlegen mit:\n\n", 78,0,1));
658
659 tell_object(pl, s+"\n");
660
661 tell_object(pl, break_string("Da ist wohl fuer Dich noch etwas zu tun...",
662 78, "Merlin teilt Dir mit: "));
663
664 if (environment() == environment(pl))
bugfixd94d0932020-04-08 11:27:13 +0200665 say(({string})pl->name(WER)
Arathornd5c9c022020-01-08 22:04:28 +0100666 +" erfuellt noch nicht alle Anforderungen fuer den "+was+
667 "status.\n",pl);
MG Mud User88f12472016-06-24 23:31:02 +0200668
669 return 0;
670}
671
672static int create_wizard(mixed who, mixed promoter)
673{
674 mixed *domains;
675 object vertrag;
676 int ret;
MG Mud User88f12472016-06-24 23:31:02 +0200677
678 who=find_player(who);
679 promoter=find_player(promoter);
680 if (!who || !promoter)
681 return 0;
682 //
683 // player not interactive?
684 //
685 if (!interactive(who))
686 {
687 write(capitalize(getuid(who))+" ist nicht aktiv.\n");
688 return 0;
689 }
690 //
691 // player is second?
692 //
bugfixd94d0932020-04-08 11:27:13 +0200693 if (({string})who->QueryProp(P_SECOND))
MG Mud User88f12472016-06-24 23:31:02 +0200694 {
695 tell_object(who,"Du bist ein Zweitspieler und kannst als solcher kein Magier werden.\n"
696 +"Versuchs Doch mal mit Deinem Erstie.\n");
bugfixd94d0932020-04-08 11:27:13 +0200697 write("Du kannst "+({string})who->name()+" nicht zum Magier machen. Das geht bei "
MG Mud User88f12472016-06-24 23:31:02 +0200698 +"Zweities\nleider nicht. Frag doch mal nach dem Erstie.\n");
699 return 1;
700 }
701 //
702 // wants to advance himself?
703 //
704 if (who==promoter)
705 {
706 write("Du kannst Dich nicht selber befoerdern. Such Dir dazu bitte einen "+
707 "Vollmagier,\nder Dir einen Vertrag gibt.\n");
708 return 1;
709 }
710 //
711 // banished?
712 //
713 if (MBanishListe[who,1])
714 {
715 tell_object(promoter,capitalize(who)+" darf nur von einem Erzmagier zum "+
716 "Magier gemacht werden.\n");
bugfixd94d0932020-04-08 11:27:13 +0200717 say(({string})promoter->name(WER)+" ist kein Erzmagier und darf "+capitalize(who)+
MG Mud User88f12472016-06-24 23:31:02 +0200718 " nicht zum Magier machen.\n");
719 return 1;
720 }
721 //
722 // player has PK?
723 //
bugfixd94d0932020-04-08 11:27:13 +0200724 if (({string})who->QueryProp("playerkills")) {
725 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 +0200726 "Am besten den Sheriff oder einen Erzmagier verstaendigen.\n");
727 return 1;
728 }
729 //
730 // already dom_member?
731 //
732 if (IS_DOMAINMEMBER(who))
733 {
734 Write("Fuer Dich kann ich nichts mehr tun. Du bist doch schon Magier!\n");
735 return 1;
736 }
737
738 //
739 // "advanced learner"?
740 //
741 if (query_wiz_level(who) == 20)
742 {
743 if (!ARCH_SECURITY) {
744 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
bugfixd94d0932020-04-08 11:27:13 +0200745 Say("Nur ein Erzmagier kann "+({string})who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
MG Mud User88f12472016-06-24 23:31:02 +0200746 return 0;
747 }
Arathornd5c9c022020-01-08 22:04:28 +0100748 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),21);
MG Mud User88f12472016-06-24 23:31:02 +0200749 if (ret<=0)
750 {
751 say("Merlin: error "+ret+"\n");
752 write("Merlin: error "+ret+"\n");
753 }
bugfixd94d0932020-04-08 11:27:13 +0200754 write("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 shout("Merlin ruft: "+({string})who->name(WER)+" ist in den Kreis der Magier "+
MG Mud User88f12472016-06-24 23:31:02 +0200757 "aufgenommen worden!\n");
bugfixd94d0932020-04-08 11:27:13 +0200758 ({int})"secure/master"->renew_player_object(who);
MG Mud User88f12472016-06-24 23:31:02 +0200759 return 1;
760 }
761
762 //
763 // already wizard?
764 //
765 if (IS_WIZARD(who))
766 {
Arathornd5c9c022020-01-08 22:04:28 +0100767 domains=({string*})"secure/master"->get_domain_homes(getuid(who));
MG Mud User88f12472016-06-24 23:31:02 +0200768 if (!domains || !pointerp(domains) || !sizeof(domains))
769 {
bugfixd94d0932020-04-08 11:27:13 +0200770 Say(({string})who->name(WER)+" gehoert noch keiner Region an und kann daher noch "+
MG Mud User88f12472016-06-24 23:31:02 +0200771 "kein Voll-\nmagier werden.\n");
772 Write("Du gehoerst noch keiner Region an. Schliess Dich zunaechst einer "+
773 "an und komm\ndann wieder!\n");
774 return 0;
775 }
Arathornd5c9c022020-01-08 22:04:28 +0100776 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),25);
MG Mud User88f12472016-06-24 23:31:02 +0200777 if(ret>0)
778 {
bugfixd94d0932020-04-08 11:27:13 +0200779 shout(({string})who->name(WER)+" arbeitet jetzt an einer Region mit!\n");
780 ({int})"secure/master"->renew_player_object(who);
MG Mud User88f12472016-06-24 23:31:02 +0200781 return 1;
782 }
783 write("RETURNVALUE "+ret+"\n");
784 say("RETURNVALUE "+ret+"\n");
785 return 0;
786 }
787
788 //
789 // still learner?
790 //
791 if (IS_LEARNER(who))
792 {
793 if (!ARCH_SECURITY) {
794 Write("Dich kann nur ein Erzmagier zum \"richtigen\" Magier machen!\n");
bugfixd94d0932020-04-08 11:27:13 +0200795 Say("Nur ein Erzmagier kann "+({string})who->name(WEN)+" zum \"richtigen\" Magier machen!\n");
MG Mud User88f12472016-06-24 23:31:02 +0200796 return 0;
797 }
Arathornd5c9c022020-01-08 22:04:28 +0100798 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),20);
MG Mud User88f12472016-06-24 23:31:02 +0200799 if (ret<=0)
800 {
801 say("Merlin: error "+ret+"\n");
802 write("Merlin: error "+ret+"\n");
803 }
Arathornd5c9c022020-01-08 22:04:28 +0100804 string wizname = ({string})who->query_real_name();
bugfixd94d0932020-04-08 11:27:13 +0200805 ({int})"secure/master"->renew_player_object(who);
MG Mud User88f12472016-06-24 23:31:02 +0200806 // Fehlerteufel geben
807 call_out(#'GibFehlerteufel,4,find_player(wizname));
808 return 1;
809 }
810
811 //
812 // promoter's level is not >DOMAINMEMBER_LVL+1
813 //
814 if (secure_level()<=DOMAINMEMBER_LVL)
815 {
816 tell_object(promoter,"Du musst derzeit mindestens Level "+
817 (DOMAINMEMBER_LVL+1)+" haben, um jemanden befoerden zu "+
818 "koennen.\n");
bugfixd94d0932020-04-08 11:27:13 +0200819 say(({string})promoter->name(WER)+" ist kein Vollmagier und darf daher niemanden "+
MG Mud User88f12472016-06-24 23:31:02 +0200820 "zum Vollmagier machen.\n");
821 return 1;
822 }
823
824 // der Check auf den Blutprintnamen ist fast ueberfluessig, aber nur fast.
825 // Er schlaegt fehl, wenn der Vertrag der Clone einer alten BP ist.
826 if (!(vertrag=present_clone("/obj/vertrag",who)) ||
827 object_name(blueprint(vertrag))!="/obj/vertrag" ||
bugfixd94d0932020-04-08 11:27:13 +0200828 !(({int})vertrag->is_unterschrieben()) )
MG Mud User88f12472016-06-24 23:31:02 +0200829 {
830 Write("Du hast ja gar keinen unterschriebenen Vertrag bei Dir. Besorg Dir "+
831 "einen Ver-\ntrag, unterschreibe ihn und komm dann wieder!\n");
bugfixd94d0932020-04-08 11:27:13 +0200832 Say(({string})who->name(WER)+" hat keinen unterschriebenen Vertrag.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200833 return 1;
834 }
835 if (geteuid(vertrag)!=secure_euid())
836 {
837 tell_object(promoter,"Das geht nicht, er hat einen Vertrag von "+
838 capitalize(geteuid(vertrag))+" bei sich.\n");
bugfixd94d0932020-04-08 11:27:13 +0200839 say(({string})promoter->name(WER)+" versucht, "+({string})who->name(WER)+" zum Magier zu "+
840 "machen, doch "+({string})who->name(WER)+" hat einen Vertrag\nvon "+
MG Mud User88f12472016-06-24 23:31:02 +0200841 capitalize(geteuid(vertrag))+" bei sich.\n",promoter);
842 return 0;
843 }
844 if (!QueryBedingungen(who,"Magier"))
845 return 0;
Arathornd5c9c022020-01-08 22:04:28 +0100846 ret=({int})"secure/master"->advance_wizlevel(geteuid(who),15);
MG Mud User88f12472016-06-24 23:31:02 +0200847 if (ret>0)
848 {
Zesstra68ee1e52020-04-20 23:24:15 +0200849 // Log ("Magierstammbuch") nach /data/etc loggen, weil SPONSOR ein
850 // langfristlog.
851 write_data("/etc/SPONSOR",dtime(time())+": "+capitalize(getuid(promoter))+" macht "+
bugfixd94d0932020-04-08 11:27:13 +0200852 ({string})who->name(WER)+" zum Learner.\n");
853 write(({string})who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
854 shout(({string})who->name(WER)+" ist in den Kreis der Magier aufgenommen worden!\n");
Zesstra68ee1e52020-04-20 23:24:15 +0200855 PostMagier(capitalize(getuid(who)),
856 capitalize(secure_euid()),
857 ({int})who->QueryProp(P_GENDER));
bugfixd94d0932020-04-08 11:27:13 +0200858 if (({int})"secure/master"->set_player_object(geteuid(who),"/std/shells/magier")
MG Mud User88f12472016-06-24 23:31:02 +0200859 <=0)
860 {
861 say("MERLIN: konnte Magiershell nicht einstellen.\n");
862 write("MERLIN: konnte Magiershell nicht einstellen.\n");
863 }
bugfixd94d0932020-04-08 11:27:13 +0200864 ({int})"secure/master"->renew_player_object(who);
Zesstra388cc222020-04-21 23:49:52 +0200865 call_out(function void ()
Zesstra2f85ed72020-04-21 01:28:08 +0200866 { write_data("/etc/SPONSOR.html",wiztree_html(), 1); }, 2);
MG Mud User88f12472016-06-24 23:31:02 +0200867 return 1;
868 }
869 write(" --RETURNVALUE IS "+ret+"\n");
870 say(" --RETURNVALUE IS "+ret+"\n");
871
872 return(ret); //non-void funktion
873}
874
875void clear_flag()
876{
877 flag=0;
878}
879
880void do_say(string str)
881{
882 say(str);
883}
884
885
886
Zesstrab16348b2019-05-21 19:41:36 +0200887void seer_sequenz3(object player, string plname)
MG Mud User88f12472016-06-24 23:31:02 +0200888{
889 string playername;
890 object faq;
891 string text;
892
Zesstra60d9e252019-05-21 20:02:56 +0200893 if (!objectp(player) || !interactive(player)) {
MG Mud User88f12472016-06-24 23:31:02 +0200894 tell_room(environment(), sprintf("Merlin sagt: Na, wo ist denn %s "
895 "hin?\n", plname));
896 busy = 0;
897 return;
898 }
899 if (environment() != environment(player))
900 move(environment(player), M_TPORT);
901
902 tell_object(player,break_string("\n\nEs macht *PUFF* und eine Schwefelwolke "
903 +"steigt um Dich herum auf.\n\nDie Aura "
904 +"verschwindet langsam und Du fuehlst Dich "
905 +"nun viel erfahrener.", 78,0,1));
906 tell_room(environment(),
907 break_string(sprintf(
908 "\n\nEs macht *PUFF* und eine Schwefelwolke steigt "
909 +"um %s herum auf.\n\nDie Aura verschwindet langsam.\n",
910 plname),78,0,1), ({player}));
911
bugfixd94d0932020-04-08 11:27:13 +0200912 if (({int})"secure/master"->advance_wizlevel(geteuid(player),1)<=0)
MG Mud User88f12472016-06-24 23:31:02 +0200913 {
914 write("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
915 say("Merlin sagt: Da geht was schief ... sag mal Zook Bescheid.\n");
916 busy = 0;
917 return;
918 }
919 playername = geteuid(player);
bugfixd94d0932020-04-08 11:27:13 +0200920 ({int})"secure/master"->renew_player_object(player);
MG Mud User88f12472016-06-24 23:31:02 +0200921 player = find_player(playername);
922 text = sprintf(" ist jetzt ein%s Seher%s!\n",
bugfixd94d0932020-04-08 11:27:13 +0200923 ((({int})player->QueryProp(P_GENDER))==2?"e":""),
924 ((({int})player->QueryProp(P_GENDER))==2?"in":""));
MG Mud User88f12472016-06-24 23:31:02 +0200925 write("Merlin ruft: "+capitalize(playername)+text);
926 shout("Merlin ruft: "+capitalize(playername)+text);
Vanion50652322020-03-10 21:13:25 +0100927 PostSeher(capitalize(playername),({int})player->QueryProp(P_GENDER));
MG Mud User88f12472016-06-24 23:31:02 +0200928 if(!catch(
929 faq=clone_object("/d/seher/haeuser/special/seherfaqmobil") ;publish))
930 {
bugfixd94d0932020-04-08 11:27:13 +0200931 ({int})faq->move(player,M_NOCHECK);
MG Mud User88f12472016-06-24 23:31:02 +0200932 tell_object(player, "Aus dem Nichts erscheint eine kleine Belohnung fuer Dich.\n");
933 }
934
935 tell_object(player, "\n\nDu laechelst gluecklich in die Runde.\n\n");
936 tell_room(environment(), sprintf("\n\n%s laechelt gluecklich in die Runde.\n\n", plname), ({player}));
937
938 busy=0;
939}
940
Zesstrab16348b2019-05-21 19:41:36 +0200941void seer_sequenz2(object player, string plname)
MG Mud User88f12472016-06-24 23:31:02 +0200942{
Zesstra60d9e252019-05-21 20:02:56 +0200943 if (!objectp(player) || !interactive(player)) {
MG Mud User88f12472016-06-24 23:31:02 +0200944 tell_room(environment(), sprintf(
945 "Merlin sagt: Na, wo ist denn %s hin?\n",
946 plname));
947 busy = 0;
948 return;
949 }
950 if (environment() != environment(player))
951 move(environment(player), M_TPORT);
952
zesstra70a0a3e2016-07-06 20:35:40 +0200953 tell_object(player, break_string("\nMerlin hebt die Arme "
MG Mud User88f12472016-06-24 23:31:02 +0200954 +"und macht einige beschwoerende Gesten. Um Dich herum erscheint "
955 +"eine gelbliche Aura, die immer heller wird, bis Du Deine "
956 +"Umwelt kaum mehr erkennen kannst.\n\n",
957 78,0,1));
958 tell_room(environment(),
959 break_string(sprintf("\nMerlin hebt die Arme und macht einige "
960 +"beschwoerende Gesten. Um %s erscheint eine "
961 +"gelbliche Aura, die immer heller wird, bis "
962 +"man %s kaum mehr erkennen kann.\n\n",
963 plname, plname),78,0,1), ({player}));
964
965 call_out("seer_sequenz3", 7, player, plname);
966}
967
Zesstrab16348b2019-05-21 19:41:36 +0200968void seer_sequenz1(object player, string plname)
MG Mud User88f12472016-06-24 23:31:02 +0200969{
Zesstra60d9e252019-05-21 20:02:56 +0200970 if (!objectp(player) || !interactive(player))
MG Mud User88f12472016-06-24 23:31:02 +0200971 return;
972
973 move(environment(player), M_TPORT);
974
975 tell_room(environment(),
976 break_string(sprintf("Das ist eine grosse Freude. %s hat sich "
977 "tapfer durch das "MUDNAME" geschlagen und mittlerweile alle "
978 "Anforderungen erfuellt, um %s zu werden.",
bugfixd94d0932020-04-08 11:27:13 +0200979 plname, (({int})player->QueryProp(P_GENDER))==1?"Seher":"Seherin"),
MG Mud User88f12472016-06-24 23:31:02 +0200980 78, "Merlin sagt: "));
981
982 call_out("seer_sequenz2", 4, player, plname);
983}
984
985
Zesstrab16348b2019-05-21 19:41:36 +0200986static int create_seer(object player)
MG Mud User88f12472016-06-24 23:31:02 +0200987{
Zesstra60d9e252019-05-21 20:02:56 +0200988 if (!objectp(player) || !interactive(player))
MG Mud User88f12472016-06-24 23:31:02 +0200989 return 0;
990 if (IS_SEER(player))
991 {
992 write(break_string("Du bist doch schon kein normaler Spieler mehr, "
993 +"was soll es also?", 78, "Merlin teilt Dir mit: "));
994 return 1;
995 }
996
997 if (!QueryBedingungen(player,"Seher"))
998 return -1;
999
1000
1001 write(break_string("Grosse Freude! Du hast alle Anforderungen "
1002 "erfuellt. Warte einen Moment...", 78,
1003 "Merlin teilt Dir mit: "));
1004 busy=1;
bugfixd94d0932020-04-08 11:27:13 +02001005 call_out("seer_sequenz1",4,player, ({string})player->Name());
MG Mud User88f12472016-06-24 23:31:02 +02001006 return(0); //non-void funktion
1007}
1008
1009static void give_help(mixed player)
1010{
1011 if (!objectp(player))
1012 return;
1013
1014 tell_object(player,
1015 break_string("Ich weiss nicht, was ich fuer Dich tun kann. "
1016 +"Ich kann Dich zum Seher oder zum Magier "
1017 +"machen, wenn Du mich darum bittest.", 78,
1018 "Merlin teilt Dir mit: "));
1019}
1020
1021
1022void reset()
1023{
1024}
1025
1026public int remove(int silent) {
bugfixd94d0932020-04-08 11:27:13 +02001027 ({int})EVENTD->UnregisterEvent(EVT_LIB_LOGIN, ME);
1028 ({int})EVENTD->UnregisterEvent(EVT_LIB_PLAYER_CREATION, ME);
MG Mud User88f12472016-06-24 23:31:02 +02001029 destruct(this_object());
1030 return 1;
1031}
1032
1033void wandern()
1034{
MG Mud User88f12472016-06-24 23:31:02 +02001035 while (remove_call_out("wandern")>=0);
1036 call_out("wandern",45+random(100));
1037 if (busy) return;
1038 if (delay)
1039 {
1040 delay=0;
1041 return;
1042 }
Zesstra1b6b7362019-04-25 14:08:02 +02001043 if (!environment())
MG Mud User88f12472016-06-24 23:31:02 +02001044 {
1045 move("/gilden/abenteurer",0);
MG Mud User88f12472016-06-24 23:31:02 +02001046 }
1047 //ueber Inv iterieren, ob da ein nicht-idelnder Spieler mit genug XP
Zesstra1b6b7362019-04-25 14:08:02 +02001048 //rumhaengt. In diesem Raum bleiben, wenn ja.
1049 foreach(object ob: all_inventory(environment()))
1050 {
1051 if (interactive(ob) && query_idle(ob)<180
bugfixd94d0932020-04-08 11:27:13 +02001052 && ({int})ob->QueryProp(P_XP)>999999)
MG Mud User88f12472016-06-24 23:31:02 +02001053 return;
1054 }
Zesstra1b6b7362019-04-25 14:08:02 +02001055 // Ausgaenge durchsuchen
Arathornd5c9c022020-01-08 22:04:28 +01001056 mapping ex=({mapping})environment()->QueryProp(P_EXITS);
MG Mud User88f12472016-06-24 23:31:02 +02001057 if (!mappingp(ex))
1058 return;
Arathorne2956b52021-09-06 19:26:49 +02001059 mapping rooms = ([]);
Zesstra1b6b7362019-04-25 14:08:02 +02001060 foreach(string cmd, string|closure dest, string msg : ex)
MG Mud User88f12472016-06-24 23:31:02 +02001061 {
Zesstra1b6b7362019-04-25 14:08:02 +02001062 // nur normale Ausgaenge benutzen
Arathorne2956b52021-09-06 19:26:49 +02001063 if (!stringp(dest) || dest == object_name(environment()))
MG Mud User88f12472016-06-24 23:31:02 +02001064 continue;
Arathorne2956b52021-09-06 19:26:49 +02001065 m_add(rooms, dest);
MG Mud User88f12472016-06-24 23:31:02 +02001066 }
Arathorne2956b52021-09-06 19:26:49 +02001067 if (!sizeof(rooms)) {
1068 move("/gilden/abenteurer",0);
Zesstra1b6b7362019-04-25 14:08:02 +02001069 return;
Arathorne2956b52021-09-06 19:26:49 +02001070 }
Zesstra1b6b7362019-04-25 14:08:02 +02001071
1072 // Und nicht zuruecklatschen, wenn moeglich.
MG Mud User88f12472016-06-24 23:31:02 +02001073 if (prev_room && sizeof(m_indices(rooms))>1)
Arathorne2956b52021-09-06 19:26:49 +02001074 m_delete(rooms, prev_room);
Zesstra1b6b7362019-04-25 14:08:02 +02001075 prev_room=object_name(environment());
1076
1077 string *raeume=m_indices(rooms);
Arathorne2956b52021-09-06 19:26:49 +02001078 move(raeume[random(sizeof(raeume))],0);
MG Mud User88f12472016-06-24 23:31:02 +02001079}
1080
1081string int_short()
1082{
1083 return "Du bist im allseits beliebten Wizclub \"Zum lustigen Merlin\".\n";
1084}
1085
Arathorne2956b52021-09-06 19:26:49 +02001086string _query_int_short() {
1087 return "Der Wizclub \"Zum lustigen Merlin\"";
1088}
1089
MG Mud User88f12472016-06-24 23:31:02 +02001090string int_long(object who,mixed where)
1091{
1092 string descr;
1093
bugfixd94d0932020-04-08 11:27:13 +02001094 if( IS_LEARNER(who) && ({int})who->QueryProp( P_WANTS_TO_LEARN ) )
MG Mud User88f12472016-06-24 23:31:02 +02001095 descr = "[" + object_name(ME) + "]\n";
1096 else
1097 descr = "";
1098 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 +02001099 if ( ({int})who->QueryProp(P_SHOW_EXITS) )
MG Mud User88f12472016-06-24 23:31:02 +02001100 descr += "Es gibt 2 sichtbare Ausgaenge: raus und gilde.\n";
1101 descr += make_invlist(who, all_inventory(ME) - ({ who }));
1102 if( environment())
1103 descr += "\nAusserhalb siehst Du:\n"
bugfixd94d0932020-04-08 11:27:13 +02001104 + ({string})environment()->int_short(who,ME);
MG Mud User88f12472016-06-24 23:31:02 +02001105 return descr;
1106}
1107
1108string make_invlist(object viewer,object *inv)
1109{
1110 int i, iswiz;
1111 string descr;
1112
1113 descr = "";
bugfixd94d0932020-04-08 11:27:13 +02001114 iswiz = IS_LEARNER( viewer ) && ({int})viewer->QueryProp(P_WANTS_TO_LEARN);
MG Mud User88f12472016-06-24 23:31:02 +02001115
1116 for (i = 0; i < sizeof(inv); i++)
1117 {
1118 string sh;
Arathornd5c9c022020-01-08 22:04:28 +01001119 sh = ({string})inv[i]->short();
MG Mud User88f12472016-06-24 23:31:02 +02001120 if (iswiz)
1121 {
1122 if (sh) sh = sh[0..<2] + " ["+object_name(inv[i])+"]\n";
1123 else sh = "["+object_name(inv[i])+"]\n";
1124 }
1125 if (sh) descr += sh;
1126 }
1127 return descr;
1128}
1129
1130void init()
1131{
1132 if (interactive(this_player()) && environment(this_player())==ME)
1133 add_action("gehen","",1);
1134 add_action("befoerdere","befoerder",1);
1135}
1136
1137int befoerdere(string str)
1138{
1139 string wen;
1140 int ret,stufe,l;
1141
1142 if (!LORD_SECURITY) return 0;
1143 if (!str||sscanf(str,"%s auf stufe %d",wen,stufe)<2)
1144 {
1145 notify_fail("Syntax: befoerdere <name> auf stufe <stufe>\n");
1146 return 0;
1147 }
1148 if (stufe>29)
1149 {
1150 write("Maximum ist Stufe 29!\n");
1151 return 1;
1152 }
1153 l=query_wiz_level(wen);
1154 if (l<25)
1155 {
1156 printf("%s muss mindestens zwecks Weiterbefoerderung mindestens Stufe 25 haben.\n",
1157 capitalize(wen));
1158 return 1;
1159 }
1160 if (l>=stufe)
1161 {
1162 printf("%s ist schon Stufe %d.\n",capitalize(wen),l);
1163 return 1;
1164 }
Arathornd5c9c022020-01-08 22:04:28 +01001165 ret=({int})"secure/master"->advance_wizlevel(wen,stufe);
MG Mud User88f12472016-06-24 23:31:02 +02001166 if (ret<=0)
1167 printf("Errorcode %d\n",ret);
1168 else
1169 write("ok\n");
1170 return 1;
1171}
1172
1173int sag(mixed str)
1174{
1175 int i;
1176
1177 if (str==0)
1178 str="";
1179 str = old_explode(break_string(str, 60 ), "\n");
1180 if (busy) {
1181 tell_room(ME, "Merlin mault: Ich bin beschaeftigt.\n");
1182 return 0;
1183 }
1184 for (i = 0; i < sizeof(str); i++)
1185 {
1186 if (!str[i])
1187 str[i]="";
1188 tell_room(environment(),"Merlin sagt: "+str[i]+"\n");
1189 tell_room(ME,"*Merlin sagt: "+str[i]+"\n");
1190 }
1191 return 1;
1192}
1193
1194void show_exits()
1195{
bugfixd94d0932020-04-08 11:27:13 +02001196 printf("%s",({string})environment()->GetExits());
MG Mud User88f12472016-06-24 23:31:02 +02001197}
1198
1199int gehen(string str)
1200{
MG Mud User88f12472016-06-24 23:31:02 +02001201 if (busy) {
1202 write("Merlin mault: Ich bin beschaeftigt.\n");
1203 return 0;
1204 }
1205
Arathornd5c9c022020-01-08 22:04:28 +01001206 str=({string})this_interactive()->_unparsed_args();
Zesstra1b6b7362019-04-25 14:08:02 +02001207 switch (query_verb())
MG Mud User88f12472016-06-24 23:31:02 +02001208 {
1209 case "gilde":
bugfixd94d0932020-04-08 11:27:13 +02001210 ({int})this_player()->move("/gilden/abenteurer",M_GO,"in die Gilde");
MG Mud User88f12472016-06-24 23:31:02 +02001211 return 1;
1212 case "raus":
bugfixd94d0932020-04-08 11:27:13 +02001213 ({int})this_player()->move(environment(),M_GO,"raus");
MG Mud User88f12472016-06-24 23:31:02 +02001214 return 1;
1215 }
1216 if (!IS_WIZARD(this_interactive()))
1217 return 0;
Zesstra1b6b7362019-04-25 14:08:02 +02001218 if (query_verb()!="merlin")
MG Mud User88f12472016-06-24 23:31:02 +02001219 return 0;
1220 delay=1;
Arathornd5c9c022020-01-08 22:04:28 +01001221 mapping exits=({mapping})environment()->QueryProp(P_EXITS);
MG Mud User88f12472016-06-24 23:31:02 +02001222 if (!str||str=="")
1223 {
bugfixd94d0932020-04-08 11:27:13 +02001224 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001225 show_exits();
1226 return 1;
1227 }
1228 if (old_explode(str," ")[0]=="sag")
1229 return sag(implode(old_explode(str," ")[1..]," "));
1230 if (str[0]==';')
1231 {
1232 tell_room(environment(ME),"Merlins "+str[1..]+"\n");
1233 tell_room(ME,"*Merlins "+str[1..]+"\n");
1234 return 1;
1235 }
1236 if (str[0]==':')
1237 {
1238 tell_room(environment(ME),"Merlin "+str[1..]+"\n");
1239 tell_room(ME,"*Merlin "+str[1..]+"\n");
1240 return 1;
1241 }
1242 if (str[0]=='*')
1243 {
1244 goto(str[1..]);
bugfixd94d0932020-04-08 11:27:13 +02001245 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001246 show_exits();
1247 return 1;
1248 }
1249 if (!exits[str])
1250 return 0;
1251 move(exits[str],0);
1252 write("Merlin sagt: Jawoll, Chef.\n");
bugfixd94d0932020-04-08 11:27:13 +02001253 printf(({string})environment()->int_short(ME,ME));
MG Mud User88f12472016-06-24 23:31:02 +02001254 show_exits();
1255 return 1;
1256}
1257
1258int goto(mixed dest)
1259{
1260 object ob;
1261 string path;
1262 mixed ret;
1263
1264 if (busy) {
1265 write("Merlin mault: Ich bin beschaeftigt.\n");
1266 return 1;
1267 }
1268
1269 if (!dest) {
1270 write("Wohin moechtest Du Merlin bringen ?\n");
1271 return 1;
1272 }
1273 ob = find_living(dest);
1274 if (ob) {
1275 ob = environment(ob);
1276 move(object_name(ob),0);
1277 return 1;
1278 }
Arathornd5c9c022020-01-08 22:04:28 +01001279 path = ({string})master()->make_path_absolute(dest);
MG Mud User88f12472016-06-24 23:31:02 +02001280 ret=catch(load_object(path);publish);
1281 if (ret && file_size(path)<0)
1282 {
1283 dest=match_living(dest,1);
1284 if (stringp(dest))
1285 {
1286 ob = environment(find_living(dest));
1287 move(object_name(ob),M_TPORT|M_NOCHECK);
1288 return 1;
1289 }
1290 printf("Fehler beim Teleport nach %O: No such file.\n",path);
1291 return 1;
1292 }
1293 if (ret)
1294 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1295 ret=catch(move(path,M_TPORT|M_NOCHECK);publish);
1296 if (stringp(ret))
1297 ret=implode(old_explode(ret,"\n"),"");
1298 if (ret)
1299 printf("Fehler beim Teleport nach %O: %O\n",dest,ret);
1300 return 1;
1301}
1302
1303mixed locate_objects(string complex_desc)
1304{
1305 object ob;
1306
1307 if (complex_desc=="alles" || complex_desc=="alle")
1308 return filter_objects(all_inventory(this_object()),"short");
1309 if (ob = present(complex_desc,this_object()) )
1310 return ({ ob });
1311 return ({}) ;
1312}
1313
1314void MBanishInsert(string name, string grund, object wer)
1315{
1316 if ( !name || !stringp(name) || !sizeof(name) ||
1317 !grund || !stringp(grund) || !sizeof(grund) ||
1318 !wer || !objectp(wer) || getuid(wer) != secure_euid() ||
1319 !IS_DEPUTY(wer) )
1320 return;
1321
1322 MBanishListe += ([name:grund;getuid(wer)]);
1323 save_object(SAVEFILE);
1324}
1325
1326mapping MBanishList()
1327{
1328 if ( !IS_DEPUTY(secure_euid()) )
1329 return 0;
1330
1331 return deep_copy(MBanishListe);
1332}
1333
1334void MBanishDelete(string name)
1335{
1336 if ( !name || !stringp(name) || !sizeof(name) || !ARCH_SECURITY )
1337 return 0;
1338
1339 MBanishListe = m_copy_delete( MBanishListe, name );
1340 save_object(SAVEFILE);
1341}
1342
1343string _query_noget()
1344{
1345 return "Merlin mag das nicht!\n";
1346}
1347
Zesstra2f85ed72020-04-21 01:28:08 +02001348private mapping create_wizard_tree()
1349{
1350 // Jof als root-elemente des Baums wird per Hand angelegt. Erstes Element
1351 // ist der Magierlevel, zweites das Mapping mit den Kindern (der Ast mit den
1352 // Kindern)
1353 mapping mtree = ([ "Jof": 111; m_allocate(100,2) ]);
1354 // Der Cache dient nur dazu, das zu einem Magier gehoerende Mapping der
1355 // Kinder schneller zu finden und verweist auf das Mapping im zweiten
1356 // Value in mtree.
1357 mapping cacheptr = m_allocate(500,1);
1358 cacheptr["Jof"] = mtree["Jof",1];
1359
1360 // Dann Log lesen und parsen.
1361 foreach(string line: explode(read_file("/data/etc/SPONSOR"),"\n"))
1362 {
1363 string parent, child;
1364 if (sscanf(line,"%!s: %s macht %s zum Learner.",parent,child) != 2)
1365 continue;
1366
1367 parent = capitalize(lower_case(parent));
1368 child = capitalize(lower_case(child));
1369
1370 // Das Kind sollte noch nicht existieren... (Tut es aber leider
1371 // gelegentlich.)
1372 if (member(cacheptr, child))
1373// raise_error(sprintf("Neu berufene Magierin ist schon Magierin: "
1374// "%s\n",child));
1375 continue;
1376 // Der Elter muss existieren...
1377 if (!member(cacheptr, parent))
1378 raise_error(sprintf("Sponsor ist keine Magierin: %s\n", parent));
1379
1380 // Mapping mit allen Kindern des Elter holen. Das Mapping in cacheptr ist
1381 // dasselbe Mapping wie in mtree, d.h. wir muessen den Elter nicht im
1382 // verschachtelten mtree suchen.
1383 mapping parent_children = cacheptr[parent];
1384 // neues Kind anlegen
1385 m_add(parent_children, child,
Zesstra4f44c822020-04-23 20:45:32 +02001386 ({int})master()->query_userlist(lower_case(child), USER_LEVEL),
Zesstra2f85ed72020-04-21 01:28:08 +02001387 m_allocate(2,2) );
1388 // und im cacheptr das (noch leere) Mapping fuer die Kinder vom child hinterlegen
1389 m_add(cacheptr, child, parent_children[child, 1]);
1390 }
1391 //printf("mtree: %O\n",mtree);
1392 //printf("cache: %O\n",cacheptr);
1393 return mtree;
1394}
1395
1396// Starte mit dem Magier <node> in <mtree> und laeuft rekursiv durch den
1397// ganzen (Sub-)Baum. Erzeugt eine geschachtelte Struktur von <ul>-Elementen,
1398// bei denen Magier ein <li> sind und die jeweiligen Kinder wieder in ein
1399// tiefer liegendes <ul> kommen. Letztendlich wieder eine Baumstruktur.
1400private string print_mtree_node(mapping mtree, string node, int indent)
1401{
1402 mapping branch = mtree[node, 1];
1403 if (!branch)
1404 raise_error(sprintf("Magier %s existiert nicht.\n",node));
1405
1406 indent += 2;
1407 string res;
1408 // Geloeschte Magier werden durchgestrichen, Vollmagier kriegen ein
1409 // "class=magier" Attribut, was dafuer sorgt, dass die fettgedruckt werden.
1410 if (mtree[node, 0] == 0)
1411 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\">"
1412 "<del>%s</del></a></li>\n", " "*indent, node, node);
1413 else if (mtree[node, 0] < DOMAINMEMBER_LVL)
1414 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\">"
1415 "%s</a></li>\n", " "*indent, node, node);
1416 else
1417 res = sprintf("%s<li><a href=\"/cgi-bin/mudwww.pl?REQ=finger&USER=%s\""
1418 " class=\"wiz\">%s</a></li>\n", " "*indent, node, node);
1419
1420 // Wenn ein Magier Kinder hat, kommt nun ein neues <ul> dran, welches wieder
1421 // alle Kinder enthaelt.
1422 if (sizeof(branch))
1423 {
1424 // Das root-ul von Jof bekommt das Attribute "id=jof", alle anderen nicht.
1425 res += sprintf("%s<ul%s>\n", " "*indent,
1426 (node == "Jof" ? " id=\"jof\"" : ""));
1427 foreach(string child, int lvl, mapping grandchildren : branch)
1428 {
1429 res += print_mtree_node(branch, child, indent);
1430 }
1431 res += sprintf("%s</ul>\n", " "*indent);
1432 }
1433 return res;
1434}
1435
1436public string wiztree_html()
1437{
1438 mapping mtree = create_wizard_tree();
1439 return sprintf("<ul>\n%s</ul>\n",print_mtree_node(mtree, "Jof", 2));
1440}
1441