blob: bd2d0c89fcc55fac3dda90f9d61c881f3dd346fc [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// player/base.c -- the basic player object
4//
5// $Id: base.c 9467 2016-02-19 19:48:24Z Zesstra $
6#pragma strong_types
7#pragma save_types
8#pragma range_check
9#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +020010
11#include <sys_debug.h>
12#include <regexp.h>
13#include <input_to.h>
Zesstra9ab40222020-01-16 23:07:12 +010014#include <configuration.h>
MG Mud User88f12472016-06-24 23:31:02 +020015#include <logging.h>
16#include <werliste.h>
17#include <time.h>
18#include <errord.h>
19#include <wizlevels.h>
20#include <money.h>
21
22inherit "/std/hook_provider";
23inherit "/std/player/restrictions";
Zesstra44030452018-11-12 22:34:02 +010024inherit "/std/player/vitems";
MG Mud User88f12472016-06-24 23:31:02 +020025inherit "/std/living/attributes";
26inherit "/std/living/put_and_get";
27inherit "/std/living/clothing";
28inherit "/std/thing/properties";
29inherit "/std/player/util";
30inherit "/std/thing/language";
31inherit "/std/player/travel";
32inherit "/std/player/combat";
33inherit "/std/player/description";
34inherit "/std/player/moving";
35inherit "/std/player/life";
36inherit "/std/player/comm";
37inherit "/std/player/viewcmd";
38inherit "/std/player/moneyhandler";
39inherit "/std/player/command";
40inherit "/std/living/skill_attributes";
41inherit "/std/living/light";
42inherit "/std/player/skills";
43inherit "/std/player/quests";
44inherit "/std/player/potion";
45inherit "/std/player/soul";
46inherit "/std/more";
47inherit "/std/user_filter";
48inherit "/secure/telnetneg";
49inherit "/std/player/guide";
50inherit "/std/player/reputation";
51inherit "/std/player/protocols/gmcp";
52inherit "/std/living/helpers";
53
54#define NEED_PROTOTYPES
55#include <player/skills.h>
56#include <player/gmcp.h>
Zesstraa64deb12016-08-31 22:22:07 +020057#include <player/base.h>
MG Mud User88f12472016-06-24 23:31:02 +020058#undef NEED_PROTOTYPES
59#include <player.h>
60#include <properties.h>
61#include <udp.h>
62#include <config.h>
63#include <ansi.h>
64#include <wizlevels.h>
65#include <living.h>
66#include <attributes.h>
67#include <language.h>
68#include <moving.h>
69#include <defines.h>
70#include <terminal.h>
71#include <new_skills.h>
72#include <pager.h>
73#include <combat.h>
74#include "/secure/questmaster.h"
75#include "/secure/lepmaster.h"
76#include <events.h>
Zesstra268e3fd2019-07-25 14:29:01 +020077#include <player/telnetneg.h>
MG Mud User88f12472016-06-24 23:31:02 +020078
79#undef NAME /* DEFINED BY UDP.H; BAD NAME CLASH :( */
80#define NAME(who) capitalize(getuid(who))
81
82mapping autoload; /* autoload-mapping */
83int hc_play;
84
85private nosave mapping autoload_rest;
86private nosave string *autoload_error;
Zesstraca502032020-02-05 19:56:09 +010087private nosave string realip;
MG Mud User88f12472016-06-24 23:31:02 +020088
MG Mud User88f12472016-06-24 23:31:02 +020089// HB-Zaehler. Wenn 0 erreicht wird, wird ein Telnet TM Paket als Keep-Alive
90// an den Client gesendet und der Counter wieder auf hochgesetzt.
91// Wenn == 0, ist das Keep-Alive abgeschaltet.
92private int telnet_tm_counter;
93
94nosave string default_home; /* Where to move us if we dont have a home set */
95
96nosave int ndead_lasttime;
97nosave mixed ndead_location;
98nosave string ndead_l_filename;
99nosave int ndead_currently;
100nosave int ndead_next_check;
101nosave object *hb_obs;
102
103private nosave string default_pray_room;
104
105nosave mixed env_ndead_info;
106
107static int _set_invis(int a);
108static string _set_tty(string str);
109static mixed _set_fraternitasdonoarchmagorum(mixed arg);
110
111
112static string al_to_title(int a);
113
114static void ndead_revive();
115
116static int wegmeldung(string player);
117
118int quit();
119void save_me(mixed value_items);
120varargs int remove(mixed arg);
121mixed RaceDefault(string arg);
122
123/** Setzt Defaultwerte vor dem Laden des Savefiles.
124 Nur die Werte bleiben spaeter uebrig, die NICHT aus dem Savefile geladen
125 werden und diese hier ersetzen.
126 Ausserdem kann man hier nicht mit den Werten aus den Savefiles arbeiten.
127 Hierzu muss man updates_after_restore() verwenden.
128*/
129protected void create()
130{
131 if(QueryProp(P_LEVEL))
132 {
133 return; // darf nur EINMAL gemacht werden
134 }
135 call_out("checkConsistency", 0);
136
137 ndead_next_check=NETDEAD_CHECK_TIME;
138 ndead_lasttime=0;
139 ndead_location=0;
140 ndead_l_filename=0;
141 ndead_currently=0;
142 ndead_next_check=0;
143 hc_play=0;
144
145 command::create();
146 properties::create();
147 description::create();
148 light::create();
149 attributes::create();
150 clothing::create();
151 combat::create();
152 life::create();
153 comm::create();
154 viewcmd::create();
155 quests::create();
156 restrictions::create();
157 moving::create();
158 travel::create();
159 skills::create();
Bugfix98ea85e2021-01-23 14:30:33 +0100160 helpers::create();
MG Mud User88f12472016-06-24 23:31:02 +0200161
162 SetProp(P_LEVEL, -1);
163 Set(P_LEVEL, SAVE|SECURED, F_MODE_AS);
164 Set(P_GHOST, SAVE, F_MODE_AS);
165 SetProp(P_SCREENSIZE, -1);
166 Set(P_SCREENSIZE, SAVE,F_MODE_AS);
167 Set(P_MORE_FLAGS, SAVE, F_MODE_AS);
168 SetProp(P_WEIGHT_PERCENT,100);
169 SetProp(P_LONG, 0);
170 SetProp(P_TITLE, "der hoffnungsvolle Anfaenger");
171 SetProp(P_ALIGN, 0);
172 SetProp(P_GENDER, NEUTER);
173 Set(P_GENDER, SAVE, F_MODE_AS);
Zesstra224e78f2022-02-10 12:07:34 +0100174 SetProp(P_TTY, "ansi");
MG Mud User88f12472016-06-24 23:31:02 +0200175 Set(P_TTY, SAVE, F_MODE_AS);
176 SetProp(P_WEIGHT, 75000);
177 SetProp(P_MAX_HP,50);
178 SetProp(P_MAX_SP,50);
179 SetProp(P_MAX_FOOD,100);
180 SetProp(P_MAX_DRINK,100);
181 SetProp(P_MAX_ALCOHOL,100);
182 Set( P_WIMPY, 20, F_VALUE);
183
184 SetProp(P_HANDS, ({" mit blossen Haenden", 30}));
185 Set(P_HANDS, SAVE, F_MODE_AS);
186 SetProp(P_MAX_HANDS, 2);
187
188 Set(P_MARRIED, SAVE, F_MODE_AS);
189 Set(P_EXTRA_LOOK, SAVE, F_MODE_AS);
190 Set(P_SHOW_EXITS, SAVE, F_MODE_AS);
191 Set(P_SHOW_EXITS, 1);
192 Set(P_WANTS_TO_LEARN, SAVE, F_MODE_AS);
193 Set(P_CAN_FLAGS, SAVE, F_MODE_AS);
194 Set(P_TESTPLAYER, SAVE|PROTECTED, F_MODE_AS);
195 Set(P_ALLOWED_SHADOW, SAVE|SECURED, F_MODE_AS);
196 Set(P_SECOND, SAVE, F_MODE_AS);
197 Set(P_INVIS, SAVE, F_MODE_AS);
198 Set(P_READ_NEWS, SAVE, F_MODE_AS);
199 Set(P_START_HOME, SAVE, F_MODE_AS);
200 Set(P_PRAY_ROOM, SAVE, F_MODE_AS);
201 Set(P_MAILADDR, SAVE, F_MODE_AS);
202 Set(P_HOMEPAGE, SAVE, F_MODE_AS);
203 Set(P_ICQ, SAVE, F_MODE_AS);
204 Set(P_MESSENGER, SAVE, F_MODE_AS);
205 Set(P_LOCATION, SAVE, F_MODE_AS);
206
207 Set(P_NO_ASCII_ART, SAVE, F_MODE_AS);
208
209 Set(P_VISUALBELL, SAVE, F_MODE_AS);
210 Set(P_CARRIED_VALUE, SAVE, F_MODE_AS);
211
212 Set(P_PROMPT, "> ");
213 Set(P_PROMPT, SAVE, F_MODE_AS);
214 Set(P_CALLED_FROM_IP, SAVE, F_MODE_AS);
215 Set(P_INFORMME,SAVE|PROTECTED,F_MODE_AS);
216 Set(P_WAITFOR,SAVE|PROTECTED,F_MODE_AS);
217 Set(P_WAITFOR_REASON,SAVE|PROTECTED,F_MODE_AS);
218 Set(P_DAILY_PLAYTIME,SAVE|PROTECTED,F_MODE_AS);
219 Set(P_NETDEAD_ENV, PROTECTED|NOSETMETHOD, F_MODE_AS);
220
221 autoload = ([]);
222 autoload_rest = ([]);
223 autoload_error = ({});
224 SetProp(P_ARTICLE,0);
225 Set(P_GUILD,SAVE,F_MODE_AS);
226 Set(P_GUILD_TITLE,SAVE,F_MODE_AS);
227 Set(P_GUILD_LEVEL,SAVE,F_MODE_AS);
228 Set(P_GUILD_RATING,SAVE,F_MODE_AS);
229 Set(P_NEWSKILLS,SAVE,F_MODE_AS);
230 Set(P_NEEDED_QP,REQ_QP);
231 Set(P_DEADS,0);
232 Set(P_DEADS, NOSETMETHOD,F_SET_METHOD);
233 Set(P_DEADS,SAVE|PROTECTED|SECURED,F_MODE_AS);
234 Set(P_LAST_LOGIN,-1);
235 Set(P_LAST_LOGIN, NOSETMETHOD,F_SET_METHOD);
236 Set(P_LAST_LOGIN,SAVE|PROTECTED|SECURED,F_MODE_AS);
237 Set(P_LAST_LOGOUT,-1);
238 Set(P_LAST_LOGOUT, NOSETMETHOD,F_SET_METHOD);
239 Set(P_LAST_LOGOUT,SAVE|PROTECTED|SECURED,F_MODE_AS);
240 Set(P_CLOCKMSG,SAVE,F_MODE_AS);
241 Set(P_TIMEZONE,SAVE,F_MODE_AS);
242 Set(P_SHOWEMAIL,SAVE,F_MODE_AS);
243 Set(P_LAST_QUIT,SAVE|PROTECTED|SECURED,F_MODE_AS);
244
245 Set(P_CMSG, 0, F_MODE); // to clean out the old clone messages
246 Set(P_DMSG, 0, F_MODE);
247 Set(P_CLONE_MSG, SAVE, F_MODE);
248 SetProp(P_CLONE_MSG, "zaubert etwas hervor");
249 Set(P_DESTRUCT_MSG, SAVE, F_MODE);
250 SetProp(P_DESTRUCT_MSG, "verschwindet einfach");
251
252 Set(P_FAO, SAVE|SECURED, F_MODE_AS);
253 Set(P_FAO_PORTALS, SAVE, F_MODE_AS);
254
255 SetProp(P_NEWBIE_GUIDE,0);
256 Set(P_NEWBIE_GUIDE,SAVE,F_MODE_AS);
257
Zesstra9ab40222020-01-16 23:07:12 +0100258 // Daran sollte nicht jeder von aussen rumspielen.
259 Set(P_TELNET_CHARSET, PROTECTED|SAVE, F_MODE_AS);
MG Mud User88f12472016-06-24 23:31:02 +0200260
261 AddId("Interactive");
MG Mud User88f12472016-06-24 23:31:02 +0200262}
263
264// ACHTUNG: Falls hier mal sonst noch weitere Resets geerbt werden, muss das
265// hier ordentlich definiert werden!
266void reset() {
267 comm::reset();
268 // momentan kann der Reset jetzt abgeschaltet werden, da er nur die
269 // TM-History loescht und ggf. von Netdead() und Disconnect() reaktiviert
270 // wird.
271 set_next_reset(-1);
272}
273
274protected void NotifyMove(object dest, object oldenv, int method)
275{
276 moving::NotifyMove(dest,oldenv,method);
277 // ggf. Daten ueber neues Env per GMCP senden.
278 if (dest != oldenv)
279 GMCP_Room();
280}
281
Bugfix5a9775f2017-02-17 13:48:56 +0100282public void NotifyInsert(object ob, object oldenv)
283{
284 restrictions::NotifyInsert(ob,oldenv);
285 description::NotifyInsert(ob,oldenv);
286}
287
288public void NotifyLeave(object ob, object dest)
289{
290 restrictions::NotifyLeave(ob,dest);
Zesstra0d5a9d02018-08-01 21:13:21 +0200291 // Die Inserthooks machen oefter mal Objekte kaputt...
292 if (objectp(ob))
293 description::NotifyLeave(ob,dest);
Bugfix5a9775f2017-02-17 13:48:56 +0100294}
295
MG Mud User88f12472016-06-24 23:31:02 +0200296string Forschung()
297{
298 return LEPMASTER->QueryForschung();
299}
300
301/** Setzt Defaultwerte fuer Rassen - wird von den Shells ueberschrieben.
302*/
303mixed RaceDefault(string arg)
304{
305 if (!arg)
306 return 0;
307 switch(arg)
308 {
309 case P_HANDS :
310 return ({" mit blossen Haenden",30,DT_BLUDGEON});
311 case P_BODY :
312 return 0;
313 }
314 return 0;
315}
316
317/** Prueft Spielerobjekt auf Konsistenz.
318 Ueberprueft das Spielerobjekt nach kompletter Initialisierung (im
319 callout) auf korrekte Werte einiger Props.
320*/
321void checkConsistency()
322{ mixed h;
323 int m;
324
325 if (pointerp(h=RaceDefault(P_HANDS)) && sizeof(h)>1)
Zesstra04f613c2019-11-27 23:32:54 +0100326 m=h[1];
MG Mud User88f12472016-06-24 23:31:02 +0200327 else
328 m=30;
329 if((h=Query(P_HANDS))[1] > m && !IS_LEARNER(this_object())) {
330 log_file("inconsistent", sprintf(
331 "[%s] %O: HANDS: %d\n", dtime(time()), this_player(), h[1]));
332 h[1] = m;
333 Set(P_HANDS,h);
334 }
335
336 if (Query(P_BODY)!=(m=RaceDefault(P_BODY)))
337 Set(P_BODY,m);
338
339 if (!Query(P_SECOND_MARK,F_MODE))
340 Set(P_SECOND_MARK,SAVE|PROTECTED,F_MODE_AS);
341 if (!Query(P_TTY_SHOW,F_MODE)&SAVE)
342 {
343 Set(P_TTY_SHOW,0,F_VALUE);
344 Set(P_TTY_SHOW,SAVE,F_MODE_AS);
345 }
346 if (Query(P_TTY_COLS,F_MODE)&SAVE)
347 {
348 Set(P_TTY_COLS,SAVE,F_MODE_AD);
349 Set(P_TTY_ROWS,SAVE,F_MODE_AD);
350 Set(P_TTY_TYPE,SAVE,F_MODE_AD);
351 }
352}
353
354/** Bittet das Spielerobjekt, sich zu zerstoeren.
355 \param[in] silent Flag, ob ohne Textausgaben zerstoert werden soll
356 \return Erfolg der Selbstzerstoerung
357*/
358varargs int remove(int silent)
359{
360 return moving::remove(silent);
361}
362
363/** Schaltet in allen Objekten im Inv HBs aus.
364 Schaltet im Inv in allen Objekten (rekursiv, deep_inventory)
365 die Heartbeats aus. Falls obs uebergeben wird, werden diese Objekte
366 statt des Inventars benutzt.
367 Speichert die Objekte, die einen HB hatten, in der glob. Var. hb_obs.
368 @param[in] obs mixed - Objekte, in denen der HB abgeschaltet werden soll.
369 Container werden rekursiv behandelt.
370 @attention Achtung! Niemals zweimal hintereinander rufen, ohne
371 zwischendurch restart_heart_beats() gerufen zu haben!
372 @sa restart_heart_beats
373*/
374varargs static void stop_heart_beats(mixed obs)
375{
MG Mud User88f12472016-06-24 23:31:02 +0200376 if (!obs)
377 {
378 hb_obs=({});
379 obs=deep_inventory(ME);
380 }
381 foreach(mixed ob: obs) {
382 if (pointerp(ob))
383 stop_heart_beats(ob);
384 else if (set_object_heart_beat(ob,0))
385 hb_obs+=({ob});
386 }
387}
388
389/** Schaltet HBs in Objekten im Inv wieder ein.
390 Schaltet in allen Objekten in hb_obs den Heartbeat ein.
391 In hb_obs (glob. Var.) stehen alle Objekte, die beim letzten Aufruf von
392 stop_heart_beats() einen HB hatten.
393 @sa stop_heart_beats
394*/
395static void restart_heart_beats()
396{
MG Mud User88f12472016-06-24 23:31:02 +0200397 if (pointerp(hb_obs))
398 {
399 foreach(object ob: hb_obs)
400 set_object_heart_beat(ob,1);
401 hb_obs=0;
402 }
403}
404
405/** Prueft auf abgelaufene Spielzeit.
406 Prueft in Spielerobjekten, ob die taegliche Maximalspielzeit
407 abgelaufen ist.
408 Wird im heart_beat() gerufen.
409 @return int - Flag, ob Spielzeit abgelaufen und Logout erfolgen soll
410*/
411static int CheckDailyPlaytime() {
412 int *spieldauer,d;
413
414 if (!pointerp(spieldauer=Query(P_DAILY_PLAYTIME)))
415 return 0;
416 // 0:Minuten pro Tag, 1:Nr. des letzen Tages, 2:Nr. des angefangenen Tages,
417 // 3:letzte Zeitpruefung, 4:verbleibende Zeit
418 d=time()/86400;
419 if (spieldauer[1]<=d) { // Ende der zeitbeschraenkten Tage?
420 Set(P_DAILY_PLAYTIME,0);
421 return 0;
422 } else if (spieldauer[2]!=d) { // Neuer Tag?
423 spieldauer[4]=spieldauer[0];
424 spieldauer[2]=d;
425 } else {
426 spieldauer[4]-=(time()-spieldauer[3]);
427 }
428 spieldauer[3]=time(); // Letzte Zeitpruefung
429 Set(P_DAILY_PLAYTIME,spieldauer);
430 if (spieldauer[4]<0) { // Keine Zeit mehr uebrig fuer heute
431 if (!interactive(ME))
432 return 1;
433 write("Du hast lange genug gemuddet fuer heute.\n");
434 say(Name(WER)+" hat fuer heute genug gemuddet.\n");
435 remove_interactive(ME);
436 return 1;
437 }
438 return 0;
439}
440
441/** Gibt Erwartemeldung mit Grund aus.
442 @param[in] who string - Wer ist hereingekommen?
443 @param[in] invis int - Ist der Spieler Invis?
444*/
445static void Show_WaitFor_Reason(string who, int invis)
446{
447 mixed list;
448 string reason,name;
449
450 if (invis) name="("+who+")";
451 else name=who;
452 if ((mappingp(list=QueryProp(P_WAITFOR_REASON))) && (reason=list[who]))
453 tell_object(ME,sprintf("\nDu erwartest %s wegen:\n%s\n",name,reason));
454 else
455 tell_object(ME,sprintf("Du erwartest %s aus keinem bestimmten Grund.\n",
456 name));
457}
458
459/** Gibt Liste der Erwarteten Spieler an this_player() aus.
460*/
461static void ListAwaited() //Anwesende Erwartete auflisten
462{
463 string *list;
464 mixed mlist;
465 object ob;
466 int mag;
467
468 mag=IS_LEARNER(ME);
469
470 list=({});
471 foreach(string erwartet : QueryProp(P_WAITFOR)) {
472 if (objectp(ob=find_player(lower_case(erwartet)))) {
473 if (ob->QueryProp(P_INVIS)) {
474 if (mag) list+=({ sprintf("(%s)",erwartet) });
475 }
476 else list+=({erwartet});
477 }
478 }
479 if (sizeof(list))
480 printf("Anwesende Erwartete: %s.\n",
481 CountUp(sort_array(list,#'>)));
482
483 if ((mappingp(mlist=QueryProp(P_WAITFOR_REASON))) && (sizeof(mlist)))
484 {
485 foreach(string erwartet : mlist) {
486 if (!(ob=find_player(lower_case(erwartet))) ||
487 (!mag && ob->QueryProp(P_INVIS)));
488 else Show_WaitFor_Reason(erwartet,ob->QueryProp(P_INVIS));
489 }
490 }
491}
492/** Teilt den Gilden und anderen Spielern mit, wer reingekommen ist.
493 Ausserdem wird ggf. PlayerQuit() im Environment gerufen.
494 \param[in] rein int - wahr, wenn der Spieler einloggt.
495*/
496protected void call_notify_player_change(int rein)
497{
498 string wer = getuid(ME);
499 // erst die Gilde informieren
500 string gilde = QueryProp(P_GUILD);
501 if (stringp(gilde) && (find_object("/gilden/"+gilde)
502 || file_size("/gilden/"+gilde+".c")>0))
503 catch(("/gilden/"+gilde)->notify_player_change(ME, rein); publish);
504
505 // dann die anderen Spieler
506 int mag = IS_LEARNER(ME);
507 int invis = QueryProp(P_INVIS);
508 object *u = users() - ({ME}); // sich selber nicht melden
509 if (mag && invis) { // Invismagier nur Magiern melden
510 u = filter(u, function int (object o)
511 { return query_wiz_level(o) >= LEARNER_LVL; }
512 );
513 }
514 u->notify_player_change(capitalize(wer),rein,invis);
MG Mud User88f12472016-06-24 23:31:02 +0200515}
516
517/** Ruft im uebergebenen Objekt ein init() auf, sofern notwendig.
518 Ruft in ob ein init() auf, falls das Objekt nach dem
519 letzten Ausloggen geschaffen wurde.
520 \param[in] ob object - Objekt, in dem init() gerufen wird.
521 \param[in] logout int - Letzter Logout
522 \return 1, falls init() gerufen wurde. 0 sonst.
523*/
524static int call_init( object ob, int logout )
525{
526 if ( objectp(ob) && object_time(ob) > logout )
527 return catch(ob->init(); publish), 1;
528 return(0);
529}
530
531/** Holt seit dem letzten Ausloggen ausgefallene Inits nach.
532 Ruft in den uebergebenen Objekten call_init(), was einen init()
533 ausloest, falls das Objekt seit dem letzten Ausloggen erstellt wurde.
534 \param[in] logout Zeitpunkt des letzten Logouts
535 \param[in] obs Array von Objekten
536 \sa call_init()
537*/
538static void inits_nachholen( int logout, object *obs )
539{
540 filter( obs, "call_init", ME, logout );
541}
542
Zesstra9ab40222020-01-16 23:07:12 +0100543// Zeichensatz konfigurieren.
544// Wenn es einen manuell konfigurierten Zeichensatz gibt (der jetzt ja
545// eingelesen ist), wird der erstmal eingestellt.
546private void set_manual_encoding()
547{
548 string enc = QueryProp(P_TELNET_CHARSET);
549 if (enc)
550 {
551 if (stringp(enc) &&
552 !catch(configure_interactive(ME, IC_ENCODING, enc); publish))
553 {
554 // hat geklappt fertig
555 return;
556 }
557 // wenn kein string oder nicht erfolgreich -> Prop zuruecksetzen
558 tell_object(ME, sprintf(
559 "Der von Dir eingestellte Zeichensatz \'%s\' konnte nicht "
560 "eingestellt werden. Die Voreinstellung \'%s\' wurde wieder "
561 "eingestellt.", enc,
562 interactive_info(ME, IC_ENCODING)));
563 SetProp(P_TELNET_CHARSET, 0);
564 }
565}
566
MG Mud User88f12472016-06-24 23:31:02 +0200567/** Belebt einen Netztoten wieder.
568 Wird im Login gerufen, wenn der Spieler netztot war. Aequivalent zu
569 start_player()
570 @param[in] silent Wenn Flag gesetzt, werden keine Meldung an den Raum
571 ausgegeben.
572 @param[in] ip Textuelle Repraesentation der IP-Adresse, von der der Spieler
573 kommt.
574 @see start_player()
575*/
576varargs void Reconnect( int silent )
577{
578 int num;
579 string called_from_ip;
580 object *inv;
581
582 if ( query_once_interactive(ME) )
583 {
Zesstra9ab40222020-01-16 23:07:12 +0100584 // Erstmal - sofern vorhanden - den manuell konfigurierten Zeichensatz
585 // einstellen. Im folgenden wird dann versucht, die TELOP CHARSET
586 // auszuhandeln, die aendert das evtl. nochmal.
587 set_manual_encoding();
MG Mud User88f12472016-06-24 23:31:02 +0200588 // perform the telnet negotiations. (all that are available)
589 "*"::startup_telnet_negs();
590 Set( P_LAST_LOGIN, time() );
591 }
592
593 enable_commands();
594 set_living_name( getuid() );
595 _remove_netdead();
596 set_heart_beat(1);
597 // Hunttimes aktualisieren und ggf. Feinde vergessen.
598 update_hunt_times((time()-QueryProp(P_LAST_LOGOUT)) /__HEART_BEAT_INTERVAL__);
599 // Heartbeats in Objekten im Inv reaktiveren.
600 restart_heart_beats();
Zesstra0681c732020-10-31 19:45:47 +0100601 // einige geerbte Module wollen ggf. was aufraeumen, neu initialisieren...
602 "*"::reconnect();
MG Mud User88f12472016-06-24 23:31:02 +0200603
Zesstrae88826c2016-09-24 20:37:05 +0200604 log_file( "syslog/shell/REENTER", sprintf( "%-11s %s, %-15s (%s).\n",
MG Mud User88f12472016-06-24 23:31:02 +0200605 capitalize(getuid(ME)), ctime(time())[4..15],
606 query_ip_number(ME)||"Unknown",
607 query_ip_name(ME)||"Unknown" ),
608 200000 );
609
610 if ( ndead_currently )
611 ndead_revive();
612
613 if ( !silent && interactive(ME) )
614 call_notify_player_change(1);
615
MG Mud User88f12472016-06-24 23:31:02 +0200616 if ( query_once_interactive(ME) )
617 modify_prompt();
618
619 // Login-event ausloesen
620 EVENTD->TriggerEvent(EVT_LIB_LOGIN, ([
621 E_OBJECT: ME,
622 E_PLNAME: getuid(ME),
623 E_ENVIRONMENT: environment() ]) );
624
625 catch( num = "secure/mailer"->FingerMail(geteuid());publish );
626
627 if ( num )
628 write( "Du hast " + num + " neue" + (num == 1 ? "n Brief" : " Briefe")
629 + " im Postamt liegen.\n" );
630
631 if ( QueryProp(P_AWAY) )
632 write( break_string( "Du bist als abwesend gekennzeichnet: " +
633 QueryProp(P_AWAY) + ".", 78 ) );
634
635 catch( RegisterChannels(); publish );
636
637 if ( (called_from_ip = Query(P_CALLED_FROM_IP)) &&
638 query_ip_number(ME) != called_from_ip ) {
639 string tmp;
640
641 if ( stringp(tmp = query_ip_name(called_from_ip)) &&
642 tmp != called_from_ip )
643 tmp = " [" + tmp + "]";
644 else
645 tmp = "";
646
647 write( "Das letzte Mal kamst Du von " + called_from_ip + tmp + ".\n" );
648 }
649
650 Set( P_CALLED_FROM_IP, query_ip_number(ME) );
651
652 // falls Gegenstaende mit 'upd -ar' upgedated wurden, muessen die
653 // "verloren gegangenen" init()'s nachgeholt werden
654 if ( query_once_interactive(ME) && !IS_LEARNER(ME) )
655 call_out( "inits_nachholen", 0, Query(P_LAST_LOGOUT),
656 all_inventory(ME) );
657
658 // noch nicht geclonte Autoloader "nach"clonen
659 while ( remove_call_out("load_auto_objects") != -1 )
660 /* do nothing */;
661
662 if ( sizeof(autoload_rest) )
663 call_out( "load_auto_objects", 0, autoload_rest );
664
665 if (ndead_location) {
666 catch( ndead_location->BecomesNetAlive(ME);publish );
667 inv = all_inventory(ndead_location);
668 ndead_location = 0;
669 }
670 else
671 inv = ({});
672
673 inv += deep_inventory(ME);
674
675 //ZZ foreach statt call_other(), damit nen bug in BNA nicht die anderen
676 //BNA verhindert.
677 foreach(object ob: inv) {
678 //es ist nicht auszuschliessen, dass Items durch BecomesNetAlive()
679 //eines anderen zerstoert werden.
680 if (objectp(ob))
681 catch( call_other(ob, "BecomesNetAlive", ME);publish );
682 }
683
684 // Erst an dieser Stelle, weil der Spieler u.U. durch ein BecomesNetAlive()
685 // noch bewegt wurde.
686 if ( !silent && environment() && object_name(environment()) != NETDEAD_ROOM )
687 {
688 if(query_hc_play()<=1)
689 tell_room(environment(),QueryProp(P_NAME) + " weilt wieder unter den Lebenden.\n",({ME}) );
690 else
691 tell_room(environment(),QueryProp(P_NAME) + " weilt wieder unter den Verstorbenen.\n",({ME}) );
692 }
693
694 NewbieIntroMsg();
695
696 if ( query_once_interactive(ME) )
697 ListAwaited();
698}
699
700/** Loggt einen Spieler aus und macht ihn netztot.
701 Bewegt einen Spieler in den Netztotenraum, deaktiviert Heartbeats im
702 Inventar, ruft BecomesNetDead(), loest Erwartemeldungen aus, triggert
703 Ausloggevent.
704*/
705void NetDead()
706{
707 object *inv;
MG Mud User88f12472016-06-24 23:31:02 +0200708
709 catch(RemoveChannels();publish);
710
711 if(query_hc_play()>1)
712 say("Ploetzlich weicht alle spirituelle Energie aus "+QueryProp(P_NAME)+".\n");
713 else
714 say("Ploetzlich weicht alles Leben aus "+QueryProp(P_NAME)+".\n");
715
716 _set_netdead();
717 remove_call_out("quit");
718 remove_living_name();
719 // Wird zwar im save_me() gemacht, aber die Zeitunterschiede beim
720 // fingern direkt nach dem Ausloggen fuehren immer wieder zu Verwirrungen
721 if(query_once_interactive(ME) && !QueryProp(P_INVIS))
722 Set(P_LAST_LOGOUT,time());
723 if (ME)
724 ndead_location = environment();
725
726 if (query_once_interactive(ME))
727 call_notify_player_change(0);
728
729 // Logout-event ausloesen
730 EVENTD->TriggerEvent(EVT_LIB_LOGOUT, ([
731 E_OBJECT: ME,
732 E_PLNAME: getuid(ME),
733 E_ENVIRONMENT: environment() ]) );
734
735 set_next_reset(900);
736 /* Bei Nicht-Magier-Shells wird comm::reset() aufgerufen, das prueft, ob
737 der Spieler immer noch netztot ist, und falls ja, die tmhist loescht.
738 Die Methode wird von /std/shells/magier.c ueberschrieben, netztote
739 Magier (die eigentlich schon anderweitig beseitigt worden sein sollten)
740 werden remove()d und destruct()ed. --Amynthor 05.05.2008 */
741
742 if (environment()) {
743 catch(environment()->BecomesNetDead(ME);publish);
744 inv = deep_inventory(ME)+all_inventory(environment());
745 }
746 else inv=deep_inventory(ME);
747 foreach(object ob: inv) {
748 if (objectp(ob)) //man weiss nie was BND() macht...
749 catch( call_other(ob, "BecomesNetDead", ME);publish );
750 }
751}
752
753
754/** Sendet ggf. Telnet Timing Marks als Keep-Alive Pakete an den Client.
755 * Wird in heart_beat() gerufen.
756 * @return 1, falls der Spieler Keep-Alive Paket wuenscht, sonst 0.
757 * @see heart_beat()
758*/
Zesstra268e3fd2019-07-25 14:29:01 +0200759protected int CheckTelnetKeepAlive(int delay) {
MG Mud User88f12472016-06-24 23:31:02 +0200760 if (telnet_tm_counter > 0) {
761 // Spieler hat offenbar ein Keep-Alive konfiguriert ...
762 if (!(--telnet_tm_counter)) {
763 // und das Intervall ist gerade abgelaufen.
764 // Prop offenbar gesetzt, FEature ist wirklich gewuenscht,
765 // Telnet Timing Mark senden
766 send_telnet_timing_mark();
767 // alle 120 HBs (240s, 4min).
768 // sollte eigentlich 240 / __HEART_BEAT_INTERVAL__ sein. Aber spart
769 // eine Operation im HB. ;-)
Zesstra268e3fd2019-07-25 14:29:01 +0200770 telnet_tm_counter = delay || 120;
MG Mud User88f12472016-06-24 23:31:02 +0200771 }
772 return 1; // Keep-Alive ist eingeschaltet
773 }
774 return 0;
775}
776
777static void ndead_move_me();
778
779/** Heartbeat des Spielerobjektes.
780 Prueft taegliche Spielzeit, speichert regelmaessig den Spieler,
781 bewegt Netztote in den Netztodenraum, ruft die HBs aus living/combat und
782 player/life.
783*/
784protected void heart_beat() {
785 if (!ME)
786 return;
787 if (ndead_currently)
788 {
789 if (interactive(ME))
790 {
791 ndead_revive();
792 ndead_location=0;
793 }
794 else return;
795 }
796 else
797 if (!(ndead_next_check--))
798 {
799 ndead_next_check=NETDEAD_CHECK_TIME;
800 if (!interactive(ME))
801 if (ndead_lasttime)
802 {
803 save_me(1);
804 if (IS_LEARNER(ME))
805 {
806 quit();
807 if (ME)
808 remove();
809 if (ME)
810 destruct(ME);
811 return;
812 }
813 ndead_move_me();
814 // Zumindest bei Gaesten ist das Objekt jetzt zerstoert
815 if (!objectp(this_object()))
816 return;
817 }
818 else
819 ndead_lasttime=1;
820 }
821 if (ME && ndead_lasttime && interactive(ME))
822 ndead_lasttime=0;
823 if (CheckDailyPlaytime())
824 return;
825
Zesstra268e3fd2019-07-25 14:29:01 +0200826 CheckTelnetKeepAlive(QueryProp(P_TELNET_KEEPALIVE_DELAY));
MG Mud User88f12472016-06-24 23:31:02 +0200827
828 life::heart_beat();
829 combat::heart_beat();
830 skills::heart_beat();
831}
832
833/** ID-Funktion fuer Spielerobjekte.
834 * id() fuer Spieler. Besondere Behandlung fuer Froesche und Geister,
835 * sowie Invis-Status.
836 * Gibt immer 0 zurueck, wenn P_INVIS && lvl < P_LEVEL
837 * @param[in] str angefragter ID-String
838 * @param[in] lvl Level des Anfragenden
839 * @return 1, falls str auf den Spieler zutrifft, 0 sonst.
840 */
841varargs int id(string str, int lvl)
842{
843 if (::id(str))
844 return 1;
845 if (Query(P_INVIS) && lvl < QueryProp(P_LEVEL))
846 return 0;
847 if (QueryProp(P_GHOST)&& str == "geist von "+ lower_case(QueryProp(P_NAME)))
848 return 1;
849 if (QueryProp(P_FROG) && str == "frosch") return 1;
850 return(0);
851}
852
853/** Setzt Spielerhomepage (Spielerkommando).
854 * @param[in] str Spielereingabe
855 * @return 1 bei Erfolg, 0 sonst.
856 */
857static int set_homepage(string str)
858{
859 mixed tmp;
860 if (!(str=_unparsed_args())) {
861 if (!QueryProp(P_HOMEPAGE))
862 write("Du hast keine URL-Adresse gesetzt!\n");
863 else
864 write("Deine offizielle URL-Adresse lautet: " + QueryProp(P_HOMEPAGE)
865 +"\n");
866 return 1;
867 }
868 write("Deine offizielle URL-Adresse wurde geaendert.\n");
869 if (str=="keine")
870 SetProp(P_HOMEPAGE, 0);
871 else {
Arathorndc28afc2018-11-26 22:20:59 +0100872 tmp = filter(regexplode(str, "[<][^>]*[>]"), function int (string e) {
873 return (e[0] != '<');
874 });
MG Mud User88f12472016-06-24 23:31:02 +0200875 write("Sie lautet jetzt: "+(str = implode(tmp, ""))+"\n");
876 SetProp(P_HOMEPAGE, str);
877 }
878 return 1;
879}
880
881/** Setzt Spieler-Wohnort (Spielerkommando).
882 * \param[in] str Spielereingabe
883 * \return 1 bei Erfolg, 0 sonst.
884 */
885static int set_location( string str )
886{
MG Mud User88f12472016-06-24 23:31:02 +0200887 if ( str == "0" || str == "loeschen" ){
888 Set( P_LOCATION, 0 );
889 write( "Du loescht Deine Ortsangabe.\n" );
890 return 1;
891 }
892
893 if ( stringp(str = _unparsed_args()) && str != "" ){
894 Set( P_LOCATION, capitalize(str) );
895 printf( "Du aenderst Deine Ortsangabe auf \"%s\".\n",
896 Query(P_LOCATION) );
897 }
Arathorn5513dfc2021-03-16 21:52:20 +0100898 else if ( stringp(Query(P_LOCATION)) )
MG Mud User88f12472016-06-24 23:31:02 +0200899 printf( "Deine Ortsangabe lautet \"%s\".\n", Query(P_LOCATION) );
900 else{
901 Set( P_LOCATION, 0, F_VALUE );
902 write( "Du hast keine Ortsangabe gesetzt.\n" );
903 }
904
905 return 1;
906}
907
908/** Setzt ICQ-UIN des Spielers (Spielerkommando).
909 * \param[in] str Spielereingabe
910 * \return 1 bei Erfolg, 0 sonst.
911 */
912static int set_icq(string str) {
913 int num;
914
915 if (!str || str=="") {
916 if (!num=QueryProp(P_ICQ))
917 write("Du hast keine ICQ-Nummer gesetzt!\n");
918 else
919 printf("Deine ICQ-Nummer lautet: %d\n",num);
920 return 1;
921 }
922 if (sscanf(str,"%d",num)!=1 || !num) {
923 write("Deine ICQ-Nummer wurde geloescht.\n");
924 SetProp(P_ICQ, 0);
925 } else {
926 write("Deine ICQ-Nummer wurde geaendert.\n");
927 printf("Sie lautet jetzt: %d\n",num);
928 SetProp(P_ICQ, num);
929 }
930 return 1;
931}
932
933/** Setzt Instant Messanger vom Spieler (Spielerkommando).
934 * \param[in] str Spielereingabe
935 * \return 1 bei Erfolg, 0 sonst.
936 */
937static int set_messenger(string str) {
938 int num;
939 string s;
940
941 if (!str || str=="") {
942 if (!s=QueryProp(P_MESSENGER))
943 if (!num=QueryProp(P_ICQ))
944 write("Du hast keine Messenger-ID gesetzt.\n");
945 else
946 printf("Du hast keine Messenger-ID gesetzt, aber eine ICQ-Nummer: %d\n", num);
947 else
948 printf("Deine Messenger-ID lautet: %s\n", s);
949 return 1;
950 }
951 if (str=="loeschen" || str=="keine") {
952 write("Deine Messenger-ID wurde geloescht.\n");
953 SetProp(P_MESSENGER, 0);
954 } else {
955 s = _unparsed_args();
956 printf("Deine Messenger-ID lautet nun: %s\n", s);
957 SetProp(P_MESSENGER, s);
958 }
959 return 1;
960}
961
962
963// Prueft, ob der String vermutlich eine eMail-Adresse ist.
964// dies ist nicht narrensicher, wird aber die meisten eMail-Adressen zulassen
965// und viel Schrott ablehnen.
966private string check_email(string str) {
967 if (!stringp(str)) return 0;
968 return regmatch(lower_case(str),
969 "[a-z0-9._%+-]+@(?:[a-z0-9-]+\.)+[a-z]{2,4}",RE_PCRE);
970}
971
972/** Setzt Email-Adresse des Spielers (Spielerkommando).
973 * \param[in] str Spielereingabe
974 * \return 1 bei Erfolg, 0 sonst.
975 */
976static int set_email(string str)
977{
978 if (!(str=_unparsed_args())) {
979 write("Deine offizielle Email-Adresse lautet: " + QueryProp(P_MAILADDR)
980 +"\n");
981 return 1;
982 }
983 str = check_email(str);
984 if (!str) {
985 notify_fail("Deine Eingabe scheint keine gueltige EMail-Adresse "
986 "zu sein.\n");
987 return 0;
988 }
989 write("Deine EMail-Adresse wurde geaendert zu:\n"
990 +str+"\n");
991 SetProp(P_MAILADDR, str);
992 return 1;
993}
994
995/** Spielerkommando 'selbstloeschung'.
996 * Gibt Meldung aus und fragt nach einer Bestaetigung.
997 * \return 1 bei Erfolg, 0 sonst.
998 */
999static int self_delete()
1000{
Zesstra0dc75be2017-01-29 12:34:13 +01001001 string msg = sprintf("%s\n"
Zesstra54b691e2018-12-27 10:57:15 +01001002 "Wenn Du Dich selbstloeschen willst, ist Dein Charakter UNWIDERRUFLICH "
1003 "verloren. Es gibt KEINE Moeglichkeit, ihn wiederzuerschaffen. Solltest "
1004 "Du nur zeitweilig vom "MUDNAME" wegbleiben wollen, so benutze bitte "
MG Mud User88f12472016-06-24 23:31:02 +02001005 "den Befehl 'spielpause'.\n"+
Arathorne4d26072023-01-09 19:39:18 +01001006 "Falls Du %s immer noch selbstloeschen willst, gib Dein Passwort "
Zesstra0dc75be2017-01-29 12:34:13 +01001007 "ein.\n\n",
1008 (QueryProp(P_NO_ASCII_ART) ? "Bist Du Dir wirklich sicher?\n"
1009 : " B I S T D U D I R W I R K L I C H S I C H E R ???????\n"),
Zaphobf67f7192022-08-11 12:00:31 +02001010 capitalize(query_real_name()));
Zesstra0dc75be2017-01-29 12:34:13 +01001011 write(break_string(msg,78,0,BS_LEAVE_MY_LFS));
Zaphobf67f7192022-08-11 12:00:31 +02001012 input_to("self_delete2",INPUT_PROMPT|INPUT_NOECHO, "Bitte das Passwort angeben: ");
MG Mud User88f12472016-06-24 23:31:02 +02001013 return 1;
1014}
1015
1016/** Spielerkommando 'selbstloeschung'.
1017 * Empfaengt Bestaetigung des Spielers und ruft Loeschfunktion in
1018 * /secure/master auf.
1019 * \param[in] str Spielereingabe
1020 * \return 1 bei Erfolg, 0 sonst.
1021 */
1022int self_delete2(string str)
1023{
1024 int ret;
Zesstra04f613c2019-11-27 23:32:54 +01001025 ret=({int})"secure/master"->delete_player(str, getuid(PL));
MG Mud User88f12472016-06-24 23:31:02 +02001026 if (!ret)
1027 {
Zesstra7fd01782019-02-04 21:54:40 +01001028 write("Das hat nicht hingehauen (Jof sei Dank ....)\n");
MG Mud User88f12472016-06-24 23:31:02 +02001029 return 1;
1030 }
1031 if (QueryProp(P_GUILD)&&file_size(GUILD_DIR+QueryProp(P_GUILD)+".c")>-1)
1032 catch(call_other(GUILD_DIR+QueryProp(P_GUILD), "austreten");publish);
1033
1034 if (QueryProp(P_DEADS) < 5) {
1035 write("Adios! Man sieht sich.\n");
1036 say(name(WER,1)+" hat sich gerade selbst zerstoert.\n");
1037 }
1038 else {
1039 write(
1040 "\nTod kommt auf seinem weissen Pferd angeritten.\n"
1041 +"Er steigt ab, baut sich drohend vor Dir auf und mustert Dich schadenfroh.\n"
1042 +"\nTod sagt: ENDLICH! NUN KANN DIR AUCH LARS NICHT MEHR HELFEN!\n"
1043 +"\nTod holt weit mit seiner Sense aus. Mit grossem Schwung laesst er sie auf\n"
1044 +"Dich zusausen und dann...\n");
1045 say(name(WER,1)+" schied gerade endgueltig von uns.\n");
1046 }
1047
1048 // Event ausloesen. ;-)
1049 EVENTD->TriggerEvent(EVT_LIB_PLAYER_DELETION, ([
1050 E_PLNAME: getuid(ME),
1051 E_ENVIRONMENT: environment(),
1052 E_GUILDNAME: QueryProp(P_GUILD) ]) );
1053
1054 remove(1);
1055 return 1;
1056}
1057
1058/** Setzt neue taegliche Spieldauer (Spielerkommando).
1059 * \param[in] str Spielereingabe
1060 * \return 1 bei Erfolg, 0 sonst.
1061 */
1062static int spieldauer(string str) {
1063 int min,day;
MG Mud User88f12472016-06-24 23:31:02 +02001064
1065 notify_fail(" spieldauer <x> minuten fuer %d tage\noder\n"+
1066 " spieldauer <x> stunden fuer %d tage\n");
1067 if (!str)
1068 return 0;
Arathorn5513dfc2021-03-16 21:52:20 +01001069 if (sscanf(str,"%d stunde%~s fuer %d tag%~s",min,day)==4)
MG Mud User88f12472016-06-24 23:31:02 +02001070 min*=60;
Arathorn5513dfc2021-03-16 21:52:20 +01001071 else if (sscanf(str,"%d minute%~s fuer %d tag%~s",min,day)!=4)
MG Mud User88f12472016-06-24 23:31:02 +02001072 return 0;
1073 if (min<5)
1074 min=5;
1075 if (min>=1440)
1076 return notify_fail("Witzbold.\n"),0;
1077
1078 Set(P_DAILY_PLAYTIME,
1079 ({min*60,time()/86400+day,time()/86400,time(),min*60}));
1080 // 0:Minuten pro Tag, 1:Nr. des letzen Tages, 2:Nr. des angefangenen Tages,
1081 // 3:letzte Zeitpruefung, 4:verbleibende Zeit
1082 printf("Du darfst die naechsten %d Tag(e) nur noch\n"+
1083 "%d Minuten am Tag mudden.\n",day,min);
1084 return 1;
1085}
1086
1087/** Interpretiert Angabe des Spielers fuer Spielpause.
1088 * \param[in] a Zeitangabe fuer Spielpause.
1089 * \return Zeitpunkt, Ende der Spielpause.
1090 */
1091private int InterpretTime(string a){
1092 // akzeptiert folgende Formate:
1093 // dd.mm.jj (Rueckgabe: 0:00 des entsprechenden Tages)
1094
1095 int *ts = allocate(9);
1096 int i,j,k,nrargs;
1097
1098 if ((nrargs=sscanf(a,"%d.%d.%d",i,j,k))==3 ||
1099 (nrargs=sscanf(a,"%d.%d.",i,j))==2) {
1100 // wenn kein jahr angegeben ist, das aktuelle nehmen.
1101 if (nrargs == 2)
1102 ts[TM_YEAR] = localtime()[TM_YEAR];
1103 else {
1104 // Zwei-Ziffern-Angabe des Jahres...
1105 if (k<100)
1106 k += 2000;
1107 ts[TM_YEAR] = k;
1108 }
1109 ts[TM_MDAY] = i;
1110 ts[TM_MON] = j - 1;
1111
1112 int zeit = mktime(ts);
1113
1114 // negative und vergangene Zeiten pruefen.
1115 if (zeit <= time()) {
1116 write("Dieser Zeitpunkt liegt in der Vergangenheit.\n");
1117 return 0;
1118 }
1119 return zeit;
1120 }
1121 return 0;
1122}
1123
1124/** Setzt neue Spielpause (Spielerkommando).
1125 * Fragt vorher nach Bestaetigung durch den Spieler.
1126 * \param[in] str Spielereingabe
1127 * \return 1 bei Erfolg, 0 sonst.
1128 * \sa spielpause2()
1129 */
1130static int spielpause(string str)
1131{
1132 int days,endezeit;
1133 string foo;
1134
1135 notify_fail("spielpause <x> tage oder\n"+
1136 "spielpause bis tt.mm[.jj]\n");
1137 if (!str) return 0;
1138 if(sscanf(_unparsed_args(),"bis %s",foo)==1) {
1139 endezeit = InterpretTime(foo);
1140 if (endezeit == 0)
1141 return 0;
1142 days = ((endezeit - time()) / 86400) + 1;
1143 }
1144 else if(sscanf(str, "%d tag%s", days, foo) == 2) {
1145 if (days < 0)
1146 days = -1;
1147 else
1148 endezeit = (time()/86400) * 86400 + days * 86400;
1149 }
1150 else return 0;
1151
1152 if (days > 0)
1153 write(strftime("Du wirst Dich erst wieder am %d.%m.%Y einloggen koennen!\n",
1154 endezeit));
1155 else if (days < 0)
1156 write( "Du wirst Dich auf unbestimmte Zeit nicht mehr einloggen koennen.\n"
1157 +"Wenn Du wieder spielen willst, musst Du Dich an einen Gott oder\n"
1158 +"Erzmagier wenden (mit einem Gast oder Mail von aussen).\n" );
1159 else {
1160 write( "Die Spielpause ist aufgehoben.\n" );
1161 master()->TBanishName(getuid(this_object()), 0);
1162 return 1;
1163 }
1164 write( "Wenn Du das wirklich willst, gib jetzt 'ja' ein.\n" );
1165 input_to( "spielpause2", INPUT_PROMPT, "]", days);
1166 return 1;
1167}
1168
1169/** Setzt neue taegliche Spieldauer, wird ueber spielpause() gerufen.
1170 * \param[in] str Spielereingabe, Bestaetigung
1171 * \param[in] days Dauer der Spielpause (in Tagen).
1172 * \sa spielpause()
1173 */
1174static void spielpause2(string str, int days)
1175{
1176 if (str && (str == "ja" || str == "Ja" || str == "JA")) {
1177 master()->TBanishName(getuid(this_object()), days);
1178 write(
1179 "Ok, die Spielpause wird mit dem naechsten Ausloggen wirksam.\n"
1180 +"Solltest Du es Dir bis dahin noch einmal ueberlegt haben, so kannst\n"
1181 +"Du den Vorgang mit 'spielpause 0 tage' wieder rueckgaengig machen.\n" );
1182 return;
1183 }
1184 write("Vorgang wurde abgebrochen.\n" );
1185}
1186
1187/** Setzt neues Passwort (Spielerkommando).
1188 * Fragt nach altem Passwort und ruft change_password2().
1189 * \return 1 bei Erfolg, 0 sonst.
1190 * \sa change_password2(), change_password3(), change_password4()
1191 */
1192static int change_password() {
1193 string verb;
1194 verb=query_verb();
1195 if (verb!="passwd"&&verb!="password"&&verb!="passwort")
1196 return 0;
1197 input_to("change_password2",INPUT_NOECHO|INPUT_PROMPT,
1198 "Bitte das ALTE Passwort angeben: ");
1199 return 1;
1200}
1201
1202/** Setzt neues Passwort (Spielerkommando).
1203 * Prueft altes Passwort, fragt nach neuem Passwort und ruft
1204 * change_password3().
1205 * \param[in] str Spielereingabe des alten Passwortes
1206 * \return 1 bei Erfolg, 0 sonst.
1207 * \sa change_password(), change_password3(), change_password4()
1208 */
1209static int change_password2(string str) {
1210 write("\n");
1211 if (!str)
1212 str="";
1213 if (MASTER->update_password(str,str) == 0) {
1214 write("Falsches Passwort!\n");
1215 return 1;
1216 }
MG Mud User88f12472016-06-24 23:31:02 +02001217 input_to("change_password3",INPUT_NOECHO|INPUT_PROMPT,
Zesstrac780d7d2019-07-26 15:40:14 +02001218 "Bitte das NEUE Passwort eingeben: ", str);
MG Mud User88f12472016-06-24 23:31:02 +02001219 return 1;
1220}
1221
1222/** Setzt neues Passwort (Spielerkommando).
1223 * Prueft neues Passwort, fragt nach Bestaetigung des neues
1224 * Passwortes und ruft change_password4().
1225 * \param[in] str Spielereingabe des neuen Passwortes
1226 * \return 1 bei Erfolg, 0 sonst.
1227 * \sa change_password(), change_password2(), change_password4()
1228 */
Zesstrac780d7d2019-07-26 15:40:14 +02001229static int change_password3( string str, string passwold )
MG Mud User88f12472016-06-24 23:31:02 +02001230{
1231 write( "\n" );
1232
1233 if ( !str || str == "" ){
1234 write( "Abgebrochen !\n" );
MG Mud User88f12472016-06-24 23:31:02 +02001235 return 1;
1236 }
1237
1238 if ( passwold == str ){
1239 write( "Das war Dein altes Passwort.\n" );
1240 input_to( "change_password3", INPUT_NOECHO|INPUT_PROMPT,
Zesstrac780d7d2019-07-26 15:40:14 +02001241 "Bitte das NEUE Passwort eingeben (zum Abbruch Return "
1242 "druecken): ", passwold);
MG Mud User88f12472016-06-24 23:31:02 +02001243 return 1;
1244 }
1245
1246 if ( !MASTER->good_password( str, getuid(ME) ) ){
1247 input_to( "change_password3", INPUT_NOECHO|INPUT_PROMPT,
Zesstrac780d7d2019-07-26 15:40:14 +02001248 "Bitte das NEUE Passwort eingeben: ", passwold);
MG Mud User88f12472016-06-24 23:31:02 +02001249 return 1;
1250 }
1251
MG Mud User88f12472016-06-24 23:31:02 +02001252 input_to( "change_password4", INPUT_NOECHO|INPUT_PROMPT,
Zesstrac780d7d2019-07-26 15:40:14 +02001253 "Bitte nochmal: ", passwold, str);
MG Mud User88f12472016-06-24 23:31:02 +02001254 return 1;
1255}
1256
1257/** Setzt neues Passwort (Spielerkommando).
1258 * Prueft neues Passwort und setzt neues Passwort.
1259 * \param[in] str Spielereingabe des neuen Passwortes
1260 * \return 1 bei Erfolg, 0 sonst.
1261 * \sa change_password(), change_password2(), change_password3()
1262 */
Zesstrac780d7d2019-07-26 15:40:14 +02001263static int change_password4( string str, string passwold, string passwnew )
MG Mud User88f12472016-06-24 23:31:02 +02001264{
1265 write( "\n" );
1266
Zesstrac780d7d2019-07-26 15:40:14 +02001267 if ( !str || str != passwnew ){
MG Mud User88f12472016-06-24 23:31:02 +02001268 write( "Das war verschieden! Passwort NICHT geaendert.\n" );
MG Mud User88f12472016-06-24 23:31:02 +02001269 return 1;
1270 }
1271
Zesstrac780d7d2019-07-26 15:40:14 +02001272 if ( MASTER->update_password( passwold, passwnew ) )
MG Mud User88f12472016-06-24 23:31:02 +02001273 write( "Passwort geaendert.\n" );
1274 else
1275 write( "Hat nicht geklappt!\n" );
1276
MG Mud User88f12472016-06-24 23:31:02 +02001277 return 1;
1278}
1279
1280
1281/*
1282 *-----------------------------------------------------------------
1283 * Rueckmeldungen von Spielern an Magier
1284 *-----------------------------------------------------------------
1285 */
1286static int fehlerhilfe(string str) {
Bugfixa75344d2017-06-16 14:04:48 +02001287 ReceiveMsg("Welche Art von Fehler moechtest Du denn melden?\n"
MG Mud User88f12472016-06-24 23:31:02 +02001288 "Fehlfunktionen -> bug\n"
1289 "Ideen/Anregungen -> idee\n"
1290 "Tippfehler/Typos -> typo\n"
Bugfixa75344d2017-06-16 14:04:48 +02001291 "fehlende Details -> detail\n"
1292 "Syntax-Probleme -> syntaxhinweis",
1293 MT_NOTIFICATION|MSG_BS_LEAVE_LFS);
MG Mud User88f12472016-06-24 23:31:02 +02001294
1295 return 1;
1296}
1297
Arathorn3437e392016-08-26 22:41:39 +02001298static varargs int ReportError2(string player_input, string error_type)
1299{
1300 if ( stringp(player_input) && sizeof(player_input) &&
1301 player_input != "~q" && player_input != ".." )
1302 {
1303 object obj;
1304 // Eingabe am : aufsplitten, da dieser als Trennzeichen verwendet wird,
1305 // wenn sich die Eingabe auf ein bestimmtes Objekt beziehen soll. Das
1306 // erste Element im Ergebnisarray wird dann als dessen ID aufgefasst,
1307 // nach der weiter unten gesucht wird.
1308 // Zusaetzlich Whitespace drumherum wegschneiden.
1309 string *input_segments = regexplode(player_input,
1310 "[[:blank:]]*:[[:blank:]]*", RE_OMIT_DELIM | RE_PCRE);
1311
1312 // Wenn mind. 2 Segmente erzeugt wurden, soll offenbar ein bestimmtes
1313 // Objekt angesprochen werden, so dass dieses nun gesucht werden kann.
1314 if ( sizeof(input_segments) > 1 )
1315 {
1316 // Findet sich hinter dem ersten : nur ein Leerstring, wird davon
1317 // ausgegangen, dass da keine Meldung kam.
1318 // Fuer seltene Sonderfaelle wie mehrfache ":" wird noch geprueft, ob
1319 // von der rekonstruierten Meldung abzueglich der ":" ein Leerstring
1320 // uebrigbleibt. Wenn ja, war es wohl wirklich eine unbrauchbare
1321 // Meldung, und es wird eine neue angefordert.
1322 if ( input_segments[1] == "" &&
1323 implode(input_segments[1..],"") == "" )
1324 {
1325 _notify("Du hast hinter dem : nix eingegeben, bitte nochmal "
1326 "versuchen.\n", MA_UNKNOWN);
1327 // Eine neue Eingabe wird aber nur angefordert, wenn der aktuelle
1328 // Input ohnehin schon aus einem input_to()-Durchlauf stammte.
1329 // In diesem Fall ist extern_call() wahr.
1330 if ( extern_call() )
1331 input_to("ReportError2", INPUT_PROMPT, "]", error_type);
1332 return 1;
1333 }
1334
1335 // ID kleinschreiben, denn nur eine solche kann von Spielern eingegeben
1336 // werden, um ein Objekt anzusprechen, wir haben aber die Eingabe
1337 // per _unparsed_args(0) geholt, d.h. ggf. mit Grossbuchstaben.
1338 string obnam = lower_case(input_segments[0]);
Zesstra6da96cc2019-06-12 23:32:21 +02001339 if (obnam == "hier" || obnam == "raum")
1340 obj = environment(this_player());
1341 else
1342 {
1343 // Und das Objekt suchen, dabei zuerst im env() schauen. Nur present()
1344 // ginge auch, wuerde aber zuerst im Inv suchen, was aber nicht
1345 // gewuenscht ist.
1346 obj = present(obnam, environment(this_object())) || present(obnam);
1347 }
Arathorn3437e392016-08-26 22:41:39 +02001348
1349 // Wenn das Objekt gefunden wird, wird nur der Teil hinter dem ersten
1350 // : rekonstruiert und als Fehlermeldung abgesetzt.
1351 // Gibt es ein solches Objekt nicht, wird der Raum als Fallback
1352 // verwendet. Die Eingabe vor dem : gehoerte dann offenbar zur Meldung
1353 // dazu, und es wird dann spaeter die gesamte Spielereingabe im Original
1354 // als Fehlermeldung abgesetzt.
1355 if ( objectp(obj) )
1356 player_input = implode(input_segments[1..],":");
1357 else
1358 obj = environment(this_object());
1359 }
1360 else
1361 {
1362 // Hat der Spieler keinen : verwendet, verwenden wir das Bezugsobjekt
1363 // oder den aktuellen Raum.
1364 obj = QueryProp(P_REFERENCE_OBJECT);
1365 if (!objectp(obj) || !present(obj))
1366 obj = environment(this_interactive());
1367 }
Arathorn3437e392016-08-26 22:41:39 +02001368 smart_log(error_type, player_input, obj);
MG Mud User88f12472016-06-24 23:31:02 +02001369 }
Arathorn3437e392016-08-26 22:41:39 +02001370 else
1371 _notify("Eingabe abgebrochen.\n", MA_UNKNOWN);
MG Mud User88f12472016-06-24 23:31:02 +02001372 return 1;
1373}
1374
Arathorn3437e392016-08-26 22:41:39 +02001375static int ReportError(string player_input)
1376{
1377 // ungeparstes Kommando einlesen, um die Meldung unmodifiziert zu erhalten
1378 player_input = _unparsed_args(0);
1379 string pl_msg, error_type;
MG Mud User88f12472016-06-24 23:31:02 +02001380
Arathorn3437e392016-08-26 22:41:39 +02001381 // Anhand des eingegebenen Kommandoverbs wird der Typ der Fehlermeldung
1382 // ermittelt.
1383 switch(query_verb())
1384 {
1385 case "idee":
1386 pl_msg = "Was fuer eine Idee hast Du denn?\n";
1387 error_type = "IDEA";
1388 break;
1389 case "md":
1390 case "detail":
1391 pl_msg = "Fuer welches Detail fehlt denn die Beschreibung?\n";
1392 error_type = "DETAILS";
1393 break;
1394 case "typo":
1395 pl_msg = "Wo ist denn der Tippfehler?\n";
1396 error_type = "TYPO";
1397 break;
1398 case "bug":
1399 pl_msg = "Wie sieht der Fehler denn aus?\n";
1400 error_type = "BUGS";
1401 break;
Bugfixa75344d2017-06-16 14:04:48 +02001402 case "syntaxhinweis":
1403 pl_msg = "Mit welcher Syntax gibt es denn was fuer Probleme?\n";
1404 error_type = "SYNTAX";
1405 break;
MG Mud User88f12472016-06-24 23:31:02 +02001406 }
MG Mud User88f12472016-06-24 23:31:02 +02001407
Arathorn3437e392016-08-26 22:41:39 +02001408 // Hat der Spieler etwas eingegeben, wird die Eingabe direkt an die Hilfs-
1409 // funktion weitergereicht. Ansonsten wird eine Meldung ausgegeben und die
1410 // Eingabe manuell per input_to() abgefragt.
1411 if ( stringp(player_input) && sizeof(player_input) )
1412 {
1413 return ReportError2(player_input, error_type);
MG Mud User88f12472016-06-24 23:31:02 +02001414 }
Arathorn3437e392016-08-26 22:41:39 +02001415 ReceiveMsg(pl_msg, MT_NOTIFICATION);
1416 input_to("ReportError2", INPUT_PROMPT, "]", error_type);
MG Mud User88f12472016-06-24 23:31:02 +02001417 return 1;
1418}
1419
Zesstrad8331fe2021-02-13 19:04:21 +01001420static void confirm_error(string answer, object obj, string str,
1421 string myname, string desc, mapping err)
1422{
1423 if (answer != "j" && answer != "ja")
1424 {
1425 _notify("Eingabe abgebrochen.\n", MA_UNKNOWN);
1426 return;
1427 }
1428 if (!obj)
1429 {
1430 _notify(sprintf("Leider existiert das Objekt nicht mehr, an dem Du "
1431 "D%s melden wolltest.", desc), MA_UNKNOWN);
1432 return;
1433 }
1434
1435 // ggf. will das Objekte selber loggen, dann wird nicht zentral geloggt.
1436 if (obj->SmartLog(0, myname, str, strftime("%d. %b %Y")))
1437 {
1438 _notify(sprintf(
1439 "Du hast an %s erfolgreich %s abgesetzt.\n"
1440 "Hinweis: Das Objekt selber hat die Meldung protokolliert.",
1441 (obj->IsRoom() ? "diesem Raum" : obj->name(WEM,1)),desc),
1442 MA_UNKNOWN);
1443 }
1444 else
1445 {
1446 // Eintragung in die Fehler-DB
1447 string hashkey = ({string})ERRORD->LogReportedError(err);
1448 _notify(sprintf(
1449 "Ein kleiner Fehlerteufel hat D%s an %s unter der ID %s "
1450 "notiert.", desc,
1451 (obj->IsRoom() ? "diesem Raum" : obj->name(WEM,1)),
1452 hashkey || "N/A"),
1453 MA_UNKNOWN);
1454 }
1455 _notify("Vielen Dank fuer die Hilfe.\n", MA_UNKNOWN);
1456}
1457
MG Mud User88f12472016-06-24 23:31:02 +02001458/** Loggt eine Spielermeldung an Magier.
1459 * Loggt die Spielermeldung in das passende File unter /log/report/ oder im
1460 * vom Magier gewuenschten File. Hierbei werden Fehler, Ideen, MDs und Typos
1461 * in getrennte Files sortiert.
1462 * \param[in] str Spielermeldung
1463 * \param[in] myname Art der Spielermeldung (DETAILS, BUG, TYPO, MD)
1464 * @see md(string), idea(string), bug(string), typo(string)
1465 */
Zesstra42594f82019-11-11 21:07:02 +01001466protected void smart_log(string myname, string str, object obj)
MG Mud User88f12472016-06-24 23:31:02 +02001467{
MG Mud User88f12472016-06-24 23:31:02 +02001468 mapping err = ([ F_PROG: "unbekannt",
1469 F_LINE: 0,
1470 F_MSG: str,
1471 F_OBJ: obj
1472 ]);
1473
1474 string desc="etwas unbekanntes";
1475 switch(myname) {
1476 case "BUGS":
1477 desc="einen Fehler";
1478 err[F_TYPE]=T_REPORTED_ERR;
1479 break;
1480 case "DETAILS":
1481 desc="ein fehlendes Detail";
1482 err[F_TYPE]=T_REPORTED_MD;
1483 break;
1484 case "IDEA":
1485 desc="eine Idee";
1486 err[F_TYPE]=T_REPORTED_IDEA;
1487 break;
1488 case "TYPO":
1489 desc="einen Typo";
1490 err[F_TYPE]=T_REPORTED_TYPO;
1491 break;
Bugfixa75344d2017-06-16 14:04:48 +02001492 case "SYNTAX":
1493 desc="einen Syntaxhinweis";
1494 err[F_TYPE]=T_REPORTED_SYNTAX;
1495 break;
MG Mud User88f12472016-06-24 23:31:02 +02001496 }
Zesstrad8331fe2021-02-13 19:04:21 +01001497 _notify(sprintf(
1498 "Du hast %s an %s mit der Beschreibung \"%s\" eingegeben. "
Bugfixa8148802022-09-25 19:40:21 +02001499 "Wurde das richtige Zielobjekt ausgewaehlt und moechtest Du "
1500 "speichern?", desc,
Zesstra9c0bd262019-12-03 19:04:45 +01001501 (obj->IsRoom() ? "diesem Raum" : obj->name(WEM,1)),
Zesstrad8331fe2021-02-13 19:04:21 +01001502 str), MA_UNKNOWN);
1503 input_to("confirm_error", INPUT_PROMPT, "]", obj, str, myname, desc, err);
MG Mud User88f12472016-06-24 23:31:02 +02001504}
1505
1506/** Speichert den Spieler und loggt ihn aus (Spielerkommando 'ende').
1507 * Der Spieler wird vollstaendig ausgeloggt, d.h. das Spielerobjekt
1508 * zerstoert.
1509 * \return 1 bei Erfolg, 0 sonst.
1510 * @see disconnect()
1511 */
1512int quit()
1513{
MG Mud User88f12472016-06-24 23:31:02 +02001514 SetProp(P_LAST_QUIT,time());
1515 catch(RemoveChannels();publish);
1516 if(!QueryGuest())
1517 {
1518 save_me(0);
1519 tell_object(ME,"Speichere "+QueryProp(P_NAME)+".\n");
1520 }
1521
Arathornf35df872021-10-31 13:24:51 +01001522 if (interactive(ME)) {
MG Mud User88f12472016-06-24 23:31:02 +02001523 call_notify_player_change(0);
Arathornf35df872021-10-31 13:24:51 +01001524 if(environment())
1525 catch(environment()->PlayerQuit(ME);publish);
1526 }
MG Mud User88f12472016-06-24 23:31:02 +02001527
1528 remove_living_name();
1529 // EVT_LIB_LOGOUT wird in remove() getriggert.
1530 if(catch(remove();publish)) destruct(ME);
1531 return 1;
1532}
1533
1534/** Wrapper im quit() herum, verhindert 'ende', falls Spieler kaempft.
Bugfix8f4df942022-01-19 13:39:56 +01001535 * Wenn der Spieler unter Level 10 ist, wird gefragt, ob er sich wirklich
1536 * mit Ende ausloggen will, um Verwechslungen mit schlafe ein zu vermeiden.
1537 * \return 0 bei Abbruch wegen Kampf, 1 bei Nachfrage per ask_quit(), sonst Rueckgabewert von quit()
1538 * @see quit(), ask_quit()
MG Mud User88f12472016-06-24 23:31:02 +02001539 */
1540static int new_quit() {
1541 notify_fail("Du bist in Gedanken noch bei Deinem letzten Kampf.\n"+
1542 "Warte noch etwas bevor Du das Spiel verlaesst,\n"+
1543 "damit Du so nicht in RL weitermachst...\n");
1544 if (time()-Query(P_LAST_COMBAT_TIME)<120 && !IS_LEARNING(ME))
1545 return 0;
Bugfix8f4df942022-01-19 13:39:56 +01001546 // Absicherung fuer kleine Spielern gegen Verwechslung mit schlafe ein
1547 if(QueryProp(P_LEVEL) < 10)
1548 {
1549 write(break_string(
1550 "Moechtest Du wirklich \"ende\" benutzen?\n"
Arathorne4d26072023-01-09 19:39:18 +01001551 "Du verlierst Deine Ausruestung und beginnst wieder an Deinem "
Bugfix8f4df942022-01-19 13:39:56 +01001552 "Rassenstartpunkt. \n"
Arathorne4d26072023-01-09 19:39:18 +01001553 "Wenn Du Dich einfach nur ausloggen und spaeter weiter spielen "
Bugfix8f4df942022-01-19 13:39:56 +01001554 "willst, dann benutze besser \"schlafe ein\".\n\n", 78, 0,
1555 BS_LEAVE_MY_LFS));
1556 input_to(
1557 function void (string str) {
1558 if(str != "ja" && str != "Ja")
1559 write("Ok, \"ende\" wird nicht ausgefuehrt.\n");
1560 else
1561 quit();
1562 },
1563 INPUT_PROMPT,
1564 "Mittels \"ende\" ausloggen? (ja/nein):");
1565 return 1;
1566 }
MG Mud User88f12472016-06-24 23:31:02 +02001567 return quit();
1568}
1569
1570/** Gibt die Infos ueber den Char an den Spieler aus (Spielerkommando 'info').
1571 * \param[in] arg Wenn arg=="short", wird eine Kurzuebersicht ausgegeben.
1572 * \return 1
1573 * @see short_score()
1574 */
1575static int score(string arg) {
Arathorn5513dfc2021-03-16 21:52:20 +01001576 int val;
MG Mud User88f12472016-06-24 23:31:02 +02001577 mixed ind;
1578 object *enem1, *enem2, *inv;
1579
1580 if (QueryProp(P_GHOST)) {
1581 write("Im ewigen Leben gibt es keine Punkte.\n");
1582 return 1;
1583 }
1584
1585 int plev = LEPMASTER->QueryLevel();
Zesstra0d1bd1d2019-11-23 10:19:15 +01001586 <string|int> tmp = QueryProp(P_GENDER);
1587 string gender;
1588 switch(tmp) {
MG Mud User88f12472016-06-24 23:31:02 +02001589 case MALE: gender = "maennlich"; break;
1590 case FEMALE: gender = "weiblich"; break;
1591 case NEUTER: gender = "neutral"; break;
Zesstra0d1bd1d2019-11-23 10:19:15 +01001592 default: gender = "unbekannt";
MG Mud User88f12472016-06-24 23:31:02 +02001593 }
1594
1595 ind = m_indices(QueryProp(P_ATTRIBUTES));
1596 tmp = "";
1597 foreach(string index: ind) {
1598 string aname;
1599 switch (index) {
1600 case "int": aname = "Intelligenz"; break;
1601 case "con": aname = "Ausdauer"; break;
1602 case "dex": aname = "Geschicklichkeit"; break;
1603 case "str": aname = "Kraft"; break;
1604 default:
1605 if(stringp(index)) aname = capitalize(index);
1606 else aname = "Unbekannt";
1607 }
1608 aname = sprintf("%-18'.'s %2.2d", aname+" ", QueryRealAttribute(index));
1609 if((val = QueryAttributeOffset(index)))
1610 aname += sprintf(" (%s%d)", (val>=0?"+":""), val);
1611 tmp += aname + "\n";
1612 }
1613
1614 printf("- %-'-'68s\n",
1615 TeamPrefix()+capitalize(implode(explode(short()||"","\n"),""))+" ");
1616 if(arg!="short") {
1617 printf("Rasse ............ %-' '18s Abenteuer ........ %d %s\n",
1618 QueryProp(P_RACE), QueryProp(P_QP),
1619 (val = QM->QueryTotalQP()) == QueryProp(P_QP) ? "" : "("+val+")");
1620 printf("Geschlecht ....... %-' '18s Groesse .......... %d cm\n",
1621 gender, QueryProp(P_SIZE));
1622 printf("Stufe ............ %-3.3d %-' '14s Gewicht .......... %d kg\n",
1623 QueryProp(P_LEVEL), (QueryProp(P_LEVEL) < plev ? "("+plev+")" : ""),
1624 QueryProp(P_WEIGHT) / 1000);
1625 printf("Gilde ............ %-' '18s Gildenstufe ...... %d\n",
1626 capitalize(QueryProp(P_GUILD)), QueryProp(P_GUILD_LEVEL));
1627 }
Rumatabd442262021-09-27 11:02:50 +02001628 printf("Erfahrung ........ %-' '18s Gesinnung ........ %-s\n\n",
MG Mud User88f12472016-06-24 23:31:02 +02001629 QueryProp(P_XP)+ " Punkte", al_to_title(QueryProp(P_ALIGN)));
1630 printf("%#-76.2s\n\n", tmp);
1631 printf("Gesundheit ....... %-3.3d %-' '14s Gift ............. %s\n",
1632 QueryProp(P_HP),
1633 (QueryProp(P_HP) == (val = QueryProp(P_MAX_HP)) ? "" : "("+val+")"),
1634 ((val = QueryProp(P_POISON)) ?
1635 (val < 4 ? "leicht" : "gefaehrlich") : "gesund"));
1636 printf("Konzentration .... %-3.3d %-' '14s Vorsicht ......... %s\n",
1637 QueryProp(P_SP),
1638 (QueryProp(P_SP) == (val = QueryProp(P_MAX_SP)) ? "" : "("+val+")"),
1639 ((ind = QueryProp(P_WIMPY)) ? ""+ind : "mutig"));
1640 printf("Todesfolgen....... %-' '18s %s\n",
1641 ((val = death_suffering()) ? ""+((val+9)/10) : "kein Malus"),
1642 (QueryProp(P_WIMPY) && ind=QueryProp(P_WIMPY_DIRECTION))
1643 ? sprintf("Fluchtrichtung ... %O", ind) : "");
1644 printf("%s",
1645 (time()-Query(P_LAST_COMBAT_TIME)<120 && !IS_LEARNING(ME)) ?
1646 "Spiel verlassen .. nicht moeglich\n" : ""
1647 );
1648
1649 if(arg!="short") {
1650 write(break_string(Forschung(), 70));
1651 if(ind=QueryProp(P_AWAY))
1652 printf("Du bist nicht ansprechbar: %O\n",ind);
1653 }
1654
Zesstra04f613c2019-11-27 23:32:54 +01001655 if(sizeof(enem1=(QueryEnemies())[0])) {
MG Mud User88f12472016-06-24 23:31:02 +02001656 enem2=({});
1657 inv=all_inventory(environment(ME));
1658 foreach(object en: enem1) {
1659 if (member(inv,en)==-1) // Ist unser Feind und ist nicht hier
1660 enem2+=({en});
1661 }
1662 if(sizeof(enem2))
1663 {
1664 write(break_string(
1665 "Du verfolgst " + CountUp(map_objects(enem2, "name", WEN))+".",
1666 78));
1667 }
1668 }
1669 if(arg!="short") show_age();
1670 printf("%-'-'70s\n", "");
1671 return 1;
1672}
1673
1674/** Gibt eine kuerzere Info ueber den Char aus (Spielerkommando punkte|score).
1675 Ruft score("short").
1676 * \param[in] arg UNUSED
1677 * \return 1 bei Erfolg, 0 sonst.
1678 * @see score(string), very_short_score()
1679 */
1680static int short_score(string arg) {
1681 return score("short");
1682}
1683
1684/** Gibt eine Miniinfo ueber LP / KP aus (Spielerkommando: kurzinfo)
1685 * \return 1
1686 * @see score(string), short_score(string)
1687 */
1688static int very_short_score(string arg) {
1689 int lp,mlp,xlp,kp,mkp,xkp;
1690 string bar;
1691
1692 lp=QueryProp(P_HP); mlp=QueryProp(P_MAX_HP);
1693 kp=QueryProp(P_SP); mkp=QueryProp(P_MAX_SP);
1694 if (mlp)
1695 xlp=(lp*40/mlp);
1696 if (mkp)
1697 xkp=(kp*40/mkp);
1698 bar=" . . . . . . . . ";
1699 if (QueryProp(P_NO_ASCII_ART) || arg == "-k")
1700 printf("Gesundheit: %3.3d (%3.3d), Konzentration: %3.3d (%3.3d)\n",
1701 lp, mlp, kp, mkp);
1702 else
1703 printf("Gesundheit: 0 |%'#'40.40s| %3.3d%s\n"+
1704 "Konzentration: 0 |%'#'40.40s| %3.3d%s\n",
1705 (xlp<0?bar:bar[xlp..]),lp,(lp==mlp?"":sprintf(" (%d)",mlp)),
1706 (xkp<0?bar:bar[xkp..]),kp,(kp==mkp?"":sprintf(" (%d)",mkp))
1707 );
1708 return 1;
1709}
1710
1711/** Gibt eine Manpage/Hilfeseite an den Spieler aus.
1712 Beruecksichtigt hierbei die Synonymliste aus dir/.synonym, um die richtige
1713 Manpage auszugeben.
1714 * \param[in] dir Verzeichnis der gewuenschten Manpage
1715 * \param[in] page Name der gewuenschten Manpage
1716 * \return String der gewuenschten Manpage
1717 */
1718static string getmanpage(string dir, string page)
1719{
1720 string text, *syn;
1721 int i;
1722
1723 if (dir[<1] != '/')
1724 dir += "/";
1725
1726 if ((text=read_file(dir+page)) && sizeof(text))
1727 return text;
1728
1729 if (text = read_file(dir+".synonym")) {
1730 syn = regexplode(text, "([ \t][ \t]*|\n)");
1731 if ((i=member(syn, page))!=-1)
1732 return read_file(dir+syn[i+2]);
1733 }
1734 return 0;
1735}
1736
1737/** Gibt eine Hilfeseite an den Spieler aus (Spielerkommando hilfe|man).
1738 * Die Hilfeseite wird in div. Verzeichnissen gesucht (je nach Gilde,
1739 * Magier-/Spielerstatus).
1740 * \param[in] str Name der gewuenschten Hilfeseite.
1741 * \return 1
1742 */
1743static int help(string str) {
1744 string verb, rest, text, gilde;
1745 mixed found;
1746
1747 found=0;
1748 text = "";
1749 if (str) {
1750 str = implode( explode(str, ".." ), "");
1751
1752 if ( sscanf( str, "gilde %s %s", gilde, rest)==2)
1753 str=rest;
1754 else
1755 gilde=QueryProp(P_GUILD);
1756 if (!gilde) gilde="abenteurer";
1757
1758 if ( sscanf( str, "%s %s",verb,rest )==2 ) str = verb;
1759
1760 if ((IS_LEARNER(PL)) ) {
1761 if (rest = getmanpage("/doc/wiz/",str)) {
1762 found = 1;
1763 text += rest;
1764 }
1765 else if (rest = getmanpage("/doc/mcmd/", str)) {
1766 found = 1;
1767 text += rest;
1768 }
1769 }
1770
1771 if ((IS_SEER(PL)) /*&& !found*/ ) {
1772 if (rest = getmanpage("/doc/scmd/",str)) {
1773 if (found)
1774 text += "\n--------------------\n";
1775 found = 1;
1776 text += rest;
1777 }
1778 }
1779
1780 if (rest = getmanpage("/doc/g."+gilde+"/",str)) {
1781 if (found)
1782 text += "\n--------------------\n";
1783 found = 1;
1784 text += rest;
1785 } else {
1786 if (rest = getmanpage("/doc/help/",str)) {
1787 if (found)
1788 text += "\n--------------------\n";
1789 found = 1;
1790 text += rest;
1791 }
1792 else if (rest = getmanpage("/doc/pcmd/",str)) {
1793 if (found)
1794 text += "\n--------------------\n";
1795 found = 1;
1796 text += rest;
1797 }
1798 else if (rest = getmanpage("/doc/REGELN/",str)) {
1799 if (found)
1800 text += "\n--------------------\n";
1801 found = 1;
1802 text += rest;
1803 }
1804 }
1805
1806 if (!found)
1807 text = "Dazu ist keine Hilfe verfuegbar.\n";
1808
1809 More(text,0);
1810 return 1;
1811 }
1812 if (IS_LEARNER(PL))
1813 text = read_file("/doc/hilfe.magier");
1814 else if (IS_SEER(PL))
1815 text = read_file("/doc/hilfe.seher");
1816
1817 More(text + read_file("/doc/hilfe.spieler"), 0);
1818 return 1;
1819}
1820
1821/** Ermittelt angebene Optionen fuer das Spielerkommando 'wer'.
1822 * \param[in] str vom Spieler spezifizierter String von Filteroptionen: -k,
1823 * -v, -a, -s (+ Langformen).
1824 * \return Array von Spieleroptionen als veroderte Int-Flags und Rest der
1825 * Spielereingabe ohne die Optionen.
1826 */
1827static mixed filter_who_options(string str)
1828{
Arathorn5513dfc2021-03-16 21:52:20 +01001829 string* opt;
MG Mud User88f12472016-06-24 23:31:02 +02001830 int i,len,res;
1831
1832 opt = explode(str," "); len=sizeof(opt);
MG Mud User88f12472016-06-24 23:31:02 +02001833 res = 0;
1834 for(i=0;i<len;i++)
1835 switch(opt[i]){
1836 case "-k":
1837 case "-kurz":
1838 res |= WHO_SHORT; break;
1839 case "-v":
1840 case "-vertikal":
1841 res |= WHO_VERTICAL; break;
1842 case "-alphabetisch":
1843 case "-a":
1844 case "-alpha":
1845 res |= WHO_ALPHA; break;
1846 case "-s":
1847 case "-spieler":
1848 res |= WHO_PLAYER_VIEW; break;
1849 default:
1850 return ({ res, implode(opt[i..]," ") });
1851 }
1852 return ({ res, 0 });
1853
1854}
1855
1856/** Spielerkommando 'wer', fragt /obj/werliste ab.
1857 * \param[in] str Spielereingabe mit Optionen fuer wer.
1858 * \return 1
1859 */
1860static int who(string str) {
1861 int i,shrt;
1862 string ret;
1863 mixed ans;
1864
1865 if ((str=_unparsed_args())&&str[0..0]!="-") {
1866 ans = filter_who_options(str);
1867 shrt = ans[0];
1868 str = ans[1];
1869 if (!shrt) {
1870 if (ret=INETD->_send_udp(str,
1871 ([ REQUEST: "who", SENDER: getuid(ME) ]), 1 ))
1872 write(ret);
1873 else
1874 write("Anfrage abgeschickt.\n");
1875 return 1;
1876 }
1877 }
1878 if (str) i=(member(str,'o')>0); else i=0;
1879 if (sizeof(str)>1 && str[0] == '-') str = str[1..1];
1880 More(implode( "/obj/werliste"->QueryWhoListe(
1881 IS_LEARNER(ME) && QueryProp(P_WANTS_TO_LEARN),shrt,0,str,i),"\n"),0);
1882 return 1;
1883}
1884
1885/** Spielerkommando 'kwer', fragt /obj/werliste ab.
1886 * \param[in] str Spielereingabe mit Optionen fuer wer.
1887 * \return 1
1888 */
1889static int kwho(string str)
1890{
1891 int shrt;
1892 mixed res;
1893
1894 if(str) {
1895 res = filter_who_options(str);
1896 shrt = res[0];
1897 str = res[1];
1898 }
1899 More(implode( "/obj/werliste"->QueryWhoListe(
1900 IS_LEARNER(ME) && QueryProp(P_WANTS_TO_LEARN), shrt|WHO_SHORT ,0,str),
1901 "\n")+"\n\n",0);
1902 return 1;
1903}
1904
1905/** Spielerkommando 'kkwer', gibt eine einfache Liste der Anwesenden aus.
1906 Filtert unsichtbare Spieler aus, falls SPielerobjekt kein Magier ist.
1907 * \param[in] str Spielereingabe mit Optionen fuer wer.
1908 * \return 1
1909 */
1910static varargs int kkwho(string str) {
1911 object *obs;
1912 string *namen;
1913
1914 obs=filter_users(str);
1915 namen=({});
1916 if (IS_LEARNER(this_player())) {
1917 foreach(object ob: obs) {
1918 if (environment(ob))
1919 namen+=({capitalize(geteuid(ob))});
1920 }
1921 }
1922 else {
1923 foreach(object ob: obs) {
1924 if (!ob->QueryProp(P_INVIS) && environment(ob))
1925 namen+=({capitalize(geteuid(ob))});
1926 }
1927 }
1928 if (sizeof(namen))
1929 write(break_string(CountUp(sort_array(namen,#'>),", ", ", ")+".",75));
1930 else
1931 write("Keine passenden Spieler gefunden.\n");
1932
1933 return 1;
1934}
1935
1936/** Spielerkommando 'toete'.
1937 * Prueft auf Geist, Gast, toten HC-Spieler, Waffe/freie Hand. Versucht einen
1938 * Gegner zu finden und ruft dann Kill(string).
1939 * \param[in] str Spielereingabe
1940 * \return 1 oder 0, falls kein potentieller Gegner bei 'toete alle' gefunden
1941 * wird.
1942 */
1943static int kill(string str) {
Arathorn5513dfc2021-03-16 21:52:20 +01001944 object eob;
MG Mud User88f12472016-06-24 23:31:02 +02001945
1946 if (QueryProp(P_GHOST))
1947 {
1948 write("Das kannst Du in Deinem immateriellen Zustand nicht.\n");
1949 return 1;
1950 }
1951
1952 if(hc_play>1)
1953 {
1954 write("DAS HAST DU HINTER DIR.\n");
1955 return 1;
1956 }
1957
1958 if (QueryGuest())
1959 {
1960 write("Du bist doch nur Gast hier.\n");
1961 return 1;
1962 }
1963 if (!str || str == "") {
1964 write("WEN willst Du toeten?\n");
1965 return 1;
1966 }
1967 if( !QueryProp(P_WEAPON) && QueryProp(P_FREE_HANDS)==0 ) {
1968 write(
1969 "Dazu solltest Du eine Waffe gezueckt oder eine Hand frei haben.\n");
1970 return 1;
1971 }
1972 str=lower_case(str);
1973 if (str=="alle") {
Arathornf499db72019-11-25 21:30:42 +01001974 object* livs = filter(all_inventory(environment(PL)),
MG Mud User88f12472016-06-24 23:31:02 +02001975 function int (object ob) {
1976 if (living(ob) && !query_once_interactive(ob)
1977 && !ob->QueryProp(P_INVIS)
1978 && !ob->QueryProp(P_NO_GLOBAL_ATTACK)
1979 && !ob->QueryProp(P_FRIEND))
1980 {
1981 Kill(ob);
1982 return 1;
1983 }
1984 return 0;
1985 } );
1986 // wenn Gegner gefunden, raus, ansonsten kommt die Fehlermeldung unten.
1987 if (sizeof(livs)) return 1;
1988 }
1989 else {
1990 int i=1;
1991 while(objectp(eob = present(str,i++,environment(PL)))) {
1992 if (living(eob) && !eob->QueryProp(P_INVIS))
1993 break;
1994 else
1995 eob=0;
1996 }
1997 }
1998 if (!objectp(eob)) {
1999 // per write und return 1 ist hier mal ok, weil dies Kommando im Spieler
2000 // eh zuletzt in der Kommandokette ausgefuehrt wird und per return 0 eh
2001 // kein anderes mehr zum Zug kommt.
2002 write("Du siehst hier kein derartiges Wesen!\n");
2003 return 1;
2004 }
2005 else if (eob == PL) {
2006 write("Selbstmord ist keine Loesung!\n");
2007 return 1;
2008 }
2009
2010 /* Kill him */
2011 Kill(eob);
2012 return 1;
2013}
2014
2015/** Spielerkommando 'stop'.
2016 * Loescht die Gegnerliste, sofern man nicht InFight() ist.
2017 * \param[in] str Spielereingabe, wird ignoriert.
2018 * \return 1
2019 */
2020static int stop( string str )
2021{
2022 if ( InFight() ){
2023 write( "Das geht nicht mitten im Kampf.\n" );
2024 return 1;
2025 }
2026
2027 if ( !str ){
2028 StopHuntingMode();
2029 write( "Ok.\n" );
2030 return 1;
2031 }
2032
2033 if ( !StopHuntID(str) )
2034 write( "So jemanden verfolgst Du nicht!\n" );
2035
2036 return 1;
2037}
2038
2039/** Spielerkommando fuers emoten ':'.
2040 * \param[in] str Spielereingabe
2041 * \param[in] genitiv Genetivflag
2042 * \return 1 oder 0, falls Spieler nicht emoten kann (kein CAN_EMOTE Flag in
2043 * P_CAN_FLAGS).
2044 */
2045int emote(string str,int genitiv)
2046{
2047 string *commands,message,verb;
2048 object living;
Arathorn5513dfc2021-03-16 21:52:20 +01002049 int size;
MG Mud User88f12472016-06-24 23:31:02 +02002050
2051 if (!(Query(P_CAN_FLAGS)&CAN_EMOTE)) return 0;
2052 if (query_verb()[0]==';') genitiv=1;
2053 if (query_verb()[0]==':'||query_verb()[0]==';')
2054 verb=query_verb()[1..]+" ";
2055 else
2056 verb="";
2057 str=this_player()->_unparsed_args();
2058 commands=explode(verb+(str||""),"#");
2059 message=break_string((IS_SEER(ME) ? "" : ">")
2060 +capitalize(genitiv ? name(WESSEN) :
2061 name())
2062 +" "+commands[0],78);
2063 size=sizeof(commands);
2064 if(size>=3)
2065 {
2066 living=find_living(lower_case(commands[1]));
2067 if(!living || environment(living)!=environment() ||
2068 (living->QueryProp(P_INVIS)) && !IS_LEARNER(ME))
2069 {
2070 write(capitalize(commands[1])+" sehe ich hier nicht!\n");
2071 return 1;
2072 }
2073 if(living!=this_object())
2074 tell_object(living,break_string((IS_SEER(this_player()) ? "" : ">")
2075 +capitalize(genitiv ?
2076 this_player()->name(WESSEN) :
2077 this_player()->name())
2078 +" "+commands[2],78));
2079 }
2080 if(size>=4)
2081 write(break_string(commands[3],78));
2082 else
2083 write(message);
2084 tell_room(environment(),message,({this_object(),living}));
2085 return 1;
2086}
2087
2088/** Spielerkommando fuers remoten 'r:'.
2089 * \param[in] str Spielereingabe
2090 * \param[in] flag Genetivflag
2091 * \return 1 oder 0, falls Spieler nicht emoten kann (kein CAN_REMOTE Flag in
2092 * P_CAN_FLAGS).
2093 */
2094static int remote(string str, int flag)
2095{
2096 int m;
2097 string tmp, dest;
2098 string *exstr;
2099 object destpl;
2100
2101 if ( !(Query(P_CAN_FLAGS) & CAN_REMOTE) )
2102 return 0;
2103
2104 if ( !(str=_unparsed_args()) ||
2105 sizeof( (exstr=explode(str," ")) - ({""}) ) <= 1 ){
2106 write("Was willst Du zu wem `emoten`?\n");
2107 return 1;
2108 }
2109
2110 dest = lower_case(exstr[0]);
2111
2112 if( !(destpl=find_player( dest ) ) ||
2113 (destpl->QueryProp(P_INVIS) && !IS_LEARNER(ME)) ){
2114 write("Einen solchen Spieler gibt es derzeit nicht.\n");
2115 return 1;
2116 }
2117
2118 tmp = implode( exstr[1..], " " );
2119
2120 tmp = regreplace( tmp, "(^|[^#])#($|[^#])", "\\1aus der Ferne\\2", 1 );
2121 tmp = regreplace( tmp, "(^|[^\\^])\\^($|[^\\^])", "\\1in der Ferne\\2", 1 );
2122 tmp = regreplace( tmp, "##", "#", 1 );
2123 tmp = regreplace( tmp, "\\^\\^", "^", 1 );
2124
2125 if ( strstr( tmp, "aus der Ferne" ) == -1
2126 && strstr( tmp, "in der Ferne" ) == -1 )
2127 tmp += " aus der Ferne";
2128
2129 if ( QueryProp(P_INVIS) && IS_LEARNER(destpl) ){
2130 str = "(" + capitalize(getuid(ME));
2131 if ( flag )
2132 str += member( "sxz", str[<1] ) == -1 ? "s" : "'";
2133 str += ")";
2134 }
2135 else
2136 str = (flag ? capitalize(name(WESSEN)) : capitalize(name(WER)));
2137
2138 str += " " + tmp + (member( ".?!", tmp[<1] ) == -1 ? "." : "") + "\n";
2139
2140 m = destpl->ReceiveMsg(str, MT_COMM|MT_FAR, MA_EMOTE,0, ME);
2141 switch(m)
2142 {
2143 case MSG_DELIVERED:
Bugfix70d66a52017-03-06 14:27:35 +01002144 // Als origin muss der Empfaenger uebergeben werden, sonst kann die
2145 // Meldung in der tmhist nicht richtig zugeordnet werden.
Zesstra4eb67dc2016-12-17 19:56:31 +01002146 ReceiveMsg(capitalize(destpl->name()) + "->" + str, MT_COMM|MT_FAR,
Bugfix70d66a52017-03-06 14:27:35 +01002147 MA_EMOTE, 0, destpl);
MG Mud User88f12472016-06-24 23:31:02 +02002148 break;
2149 case MSG_BUFFERED:
2150 write( capitalize(destpl->name(WER) + " ist gerade beschaeftigt.\n") );
2151 break;
2152 case MSG_IGNORED:
2153 write( capitalize(destpl->name(WER) + " ignoriert Dich.\n") );
2154 break;
2155 case MSG_VERB_IGN:
2156 case MSG_MUD_IGN:
2157 write( capitalize(destpl->name(WER) + " ignoriert Deine Meldung.\n") );
2158 break;
2159 default:
2160 write( capitalize(destpl->name(WER) + " kann Dich gerade nicht "
2161 "wahrnehmen.\n") );
2162 }
2163 return 1;
2164}
2165
2166/** Spielerkommando fuers emoten im Genitiv ';'.
2167 * Ruft emote(string,int) auf.
2168 */
2169static int gemote(string str)
2170{
2171 return emote(str, 1);
2172}
2173
2174/** Spielerkommando fuers remoten im Genitiv 'r;'.
2175 * Ruft remote(string, int) auf.
2176 */
2177static int gremote(string str)
2178{
2179 return remote(str, 1);
2180}
2181
2182static void load_auto_objects(mapping map_ldfied);
2183
2184private void InitPlayer();
2185private void InitPlayer2();
2186private void InitPlayer3();
2187
2188/** Gibt eine Zufallszahl um P_AVERAGE_SIZE herum zurueck.
2189 * \return Zufaellige Groesse.
2190 */
2191private int RandomSize()
2192{
2193 return (100+random(13)-random(13)+random(13)-random(13))*
2194 (QueryProp(P_AVERAGE_SIZE)||170)/100;
2195}
2196
2197/** Setzt bestimmte Props im Spieler, falls diese nicht gesetzt sind oder
2198 * loescht obsolete Props. Repariert bestimmte Datenstrukturen im Spieler.
2199 * Wird von start_player() nach Laden des Savefiles gerufen.
2200 * Momentan wird z.B. die Groesse gesetzt, falls sie bisher 0 ist und die
2201 * Skills des Spielers initialisiert bzw. repariert oder auf die aktuellste
2202 * Version des Skillsystems
2203 * Ruft ggf. InitSkills() und FixSkills().
2204 * @param[in] newflag Gibt an, ob es ein neuerstellter Spieler ist.
2205 * @sa start_player(), InitSkills(), FixSkills()
2206 */
2207private void updates_after_restore(int newflag) {
MG Mud User88f12472016-06-24 23:31:02 +02002208 // Seher duerfen die Fluchtrichtung uebermitteln lassen.
2209 // Eigentlich koennte es Merlin machen. Dummerweise gibt es ja auch alte
2210 // Seher und dann kann es gleiche fuer alle hier gemacht werden. (Ob der
2211 // Code jemals rauskann?)
2212 //TODO: Irgendwann alle Seher korrigieren und Code nach Merlin schieben...
2213 if (IS_SEER(ME))
2214 SetProp(P_CAN_FLAGS,QueryProp(P_CAN_FLAGS) | CAN_REPORT_WIMPY_DIR);
2215
2216 // ggf. Invis-Eigenschaft aus dem Loginobjekt abrufen (Invislogin), koennte
2217 // ja anders als aus Savefile sein. Gesetztes P_INVIS aus diesem aber
2218 // beibehalten.
2219 if (IS_LEARNER(ME) && !QueryProp(P_INVIS)
2220// && load_name(previous_object()) == "/secure/login"
2221 )
2222 {
2223 SetProp(P_INVIS, previous_object()->query_invis());
2224 if (QueryProp(P_INVIS))
2225 tell_object(ME, "DU BIST UNSICHTBAR!\n" );
2226 }
2227 "*"::updates_after_restore(newflag);
2228
2229 attributes::UpdateAttributes();
2230
2231 int size=Query(P_SIZE);
2232 if (!size) size=RandomSize();
2233 while(size==QueryProp(P_AVERAGE_SIZE))
2234 size=RandomSize();
2235 Set(P_SIZE,size);
2236
Zesstraab834bb2020-01-21 13:11:45 +01002237 // Props werden nicht mehr genutzt. TODO: irgendwann entfernen, wenn
2238 // sinnvoll oder Savefiles extern bereinigt.
MG Mud User88f12472016-06-24 23:31:02 +02002239 Set(P_SECOND_LIST, SAVE, F_MODE_AD);
2240 Set(P_SECOND_LIST, 0, F_VALUE);
Zesstraab834bb2020-01-21 13:11:45 +01002241 Set("creation_date", SAVE|SECURED|PROTECTED, F_MODE_AD);
MG Mud User88f12472016-06-24 23:31:02 +02002242}
2243
2244
2245/** Setzt den HC-Modus.
2246 */
2247varargs nomask void set_hc_play(string str,int val)
2248{
2249 string str1;
2250
2251 str1 = explode( object_name(previous_object()), "#" )[0];
2252
2253 if ( str1 != "/secure/login" &&
2254 previous_object()!=this_object() &&
2255 extern_call() &&
2256 (!geteuid(ME) || geteuid(ME) != getuid(ME) ||
2257 capitalize(geteuid(ME)) != str ||
2258 geteuid(ME) != geteuid(previous_object())) ){
2259 write( "DIESER VERSUCH WAR ILLEGAL !!\n" );
2260 return;
2261 }
2262
2263 hc_play=val;
2264}
2265
2266/** gibt den HC-Modus zurueck.
2267 */
2268nomask int query_hc_play()
2269{
2270 return hc_play;
2271}
2272
2273/** Initialisiert und aktiviert das Spielerobjekt.
2274 * Kann nur von /secure/login oder /secure/master gerufen werden.
2275 * Startet Telnet Negotiation, laedt Savefile, setzt einige Props.
2276 * Ruft updates_after_restore(), um div. Daten zu aktualisieren/reparieren.
2277 * Ruft create() aus /std/player/potion.c.
2278 * Bei neuem Spieler wird der entsprechende Event ausgeloest die Attribute
2279 * auf die Startwerte gesetzt.
2280 * Prueft Zweitiemarkierungen.
2281 * Ruft InitPlayer().
2282 * @param[in] str Name des Charakters, der geladen werden soll.
2283 * @param[in] ip textuelle Repraesentation der IP-Adresse des Spielers.
2284 * @return 1 bei Erfolg, 0 sonst.
2285 * @todo Div. Reparaturen/Updates nach updates_after_restore() auslagern.
2286 */
2287varargs nomask int start_player( string str, string ip )
2288{
2289 mixed second;
2290 int newflag; /* could player be restored? */
2291 string str1;
2292
2293 call_out( "disconnect", 600 );
2294
2295 str1 = explode( object_name(previous_object()), "#" )[0];
2296
2297 if ( str1 != "/secure/login" &&
2298 str1 != "/secure/master" &&
2299 (!geteuid(ME) || geteuid(ME) != getuid(ME) ||
2300 capitalize(geteuid(ME)) != str ||
2301 geteuid(ME) != geteuid(previous_object())) ){
2302 write( "DIESER VERSUCH WAR ILLEGAL !!\n" );
2303 destruct(ME);
2304 return 0;
2305 }
2306
2307 /* try to restore player. If it doesn't exist, set the new flag */
Zesstraf3f22662017-01-30 15:54:29 +01002308 newflag = !restore_object( SAVEPATH + lower_case(str)[0..0] + "/"
MG Mud User88f12472016-06-24 23:31:02 +02002309 +lower_case(str) );
2310
2311 updates_after_restore(newflag);
2312
Zesstra9ab40222020-01-16 23:07:12 +01002313 if ( query_once_interactive(ME) )
MG Mud User88f12472016-06-24 23:31:02 +02002314 {
Zesstra9ab40222020-01-16 23:07:12 +01002315 // Erstmal - sofern vorhanden - den manuell konfigurierten Zeichensatz
2316 // einstellen. Im folgenden wird dann versucht, die TELOP CHARSET
2317 // auszuhandeln, die aendert das evtl. nochmal.
2318 set_manual_encoding();
MG Mud User88f12472016-06-24 23:31:02 +02002319 // Telnet-Negotiations durchfuehren, aber nur die grundlegenden aus
2320 // telnetneg. Alle anderen sollten erst spaeter, nach vollstaendiger
2321 // Initialisierung gemacht werden.
Zesstra9ab40222020-01-16 23:07:12 +01002322 telnetneg::startup_telnet_negs();
2323 modify_prompt();
2324 Set( P_LAST_LOGIN, time(), F_VALUE );
MG Mud User88f12472016-06-24 23:31:02 +02002325 }
2326
2327 Set( P_WANTS_TO_LEARN, 1 ); // 1 sollte der default sein !!!
2328 Set( P_WANTS_TO_LEARN, PROTECTED, F_MODE_AS );
2329 // Eingefuegt 18.11.99, kann nach einem Jahr wieder raus:
2330 Set( P_TESTPLAYER, PROTECTED, F_MODE_AS );
2331
2332 if ( IS_LEARNER(ME) )
2333 SetProp( P_CAN_FLAGS, QueryProp(P_CAN_FLAGS)|CAN_REMOTE );
2334
2335 Set( P_NAME, str );
2336 Set( P_NAME, SECURED, F_MODE_AS );
2337
2338 if ( !QueryProp(P_NEEDED_QP) )
2339 SetProp( P_NEEDED_QP, REQ_QP );
2340
2341 Set( P_NEEDED_QP, NOSETMETHOD, F_SET_METHOD );
2342 Set( P_NEEDED_QP, SAVE|SECURED, F_MODE_AS );
2343
2344 /* autosave the player after 500 heartbeats */
2345 time_to_save = age + 500;
2346 potion::create(); /* DO IT HERE AFTER THE RESTORE !! */
2347
2348 AddId( getuid() );
2349 SetProp( P_AC, 0 );
2350 SetProp( P_WEAPON, 0 );
2351
2352 /* Set some things which wont be set when all is OK */
2353 SetProp( P_MAX_HP, (QueryAttribute(A_CON) * 8 + 42 ));
2354 SetProp( P_MAX_SP, (QueryAttribute(A_INT) * 8 + 42 ));
2355
2356 catch( bb = "/secure/bbmaster"->query_bb() );
2357
2358 /* If this is a new character, we call the adventurers guild to get
2359 * our first title !
2360 */
2361 if ( newflag ) {
2362 if ( QueryGuest())
2363 SetProp( P_TITLE, "ueberkommt das "MUDNAME" ..." );
2364
2365 Set( P_LEVEL, -1 );
2366 SetProp( P_ATTRIBUTES, ([ A_STR:1, A_CON:1, A_INT:1, A_DEX:1 ]) );
2367 SetProp( P_HP, QueryProp(P_MAX_HP) );
2368
2369 // Event ausloesen
2370 EVENTD->TriggerEvent(EVT_LIB_PLAYER_CREATION, ([
2371 E_OBJECT: ME,
2372 E_PLNAME: getuid(ME) ]) );
2373 }
2374
2375 InitPlayer();
2376
2377 // Padreic 01.02.1999
Zesstra85576452017-01-30 15:43:21 +01002378 if ( !IS_LEARNER(ME) && (second = QueryProp(P_SECOND)) )
2379 {
2380 if ( stringp(second) && lower_case(second)[0..3] == "von " )
2381 {
MG Mud User88f12472016-06-24 23:31:02 +02002382 second = lower_case(second[4..]);
2383 SetProp( P_SECOND, second );
2384 }
2385
2386 if ( !stringp(second ) ||
Zesstra85576452017-01-30 15:43:21 +01002387 !master()->find_userinfo(second))
2388 {
2389 // Wenns nur an Gross-/Kleinschreibung liegt, wird automatisch
2390 // korrigiert.
MG Mud User88f12472016-06-24 23:31:02 +02002391 if ( stringp(second) &&
Zesstra85576452017-01-30 15:43:21 +01002392 master()->find_userinfo(lower_case(second)))
2393 {
MG Mud User88f12472016-06-24 23:31:02 +02002394 SetProp( P_SECOND, lower_case(second) );
2395 log_file( "WRONG_SECOND",
2396 sprintf( "%s: %s: P_SECOND = %O -> Automatisch "
2397 "korrigiert,\n",
2398 dtime(time()), object_name(), second ) );
2399 }
2400 else {
2401 tell_object( ME,
2402 "*\n*\n* Deine Zweitiemarkierung ist ungueltig, "
2403 "bitte aendere diese und sprich im\n* Zweifel "
2404 "bitte einen Erzmagier an.\n*\n*\n" );
2405
2406 log_file( "WRONG_SECOND",
2407 sprintf( "%s: %s: P_SECOND = %O\n",
2408 dtime(time()), object_name(), second ) );
2409 // ein bisschen deutlicher auffordern.. Padreic 08.04.1999
2410 move( "/d/gebirge/room/zwafflad", M_GO );
2411 }
2412 }
2413 }
2414 return(0);
2415}
2416
2417/** Letzte Phase der Spielerinitialisierung beim Laden des Charakters.
2418 * Ruft enable_commands(), aktiviert den Heartbeat und aktiviert die
2419 * Kommandos aus den geerbten command.c, put_and_get.c, team.c, soul.c,
2420 * guide.c, setzt den Living Name.
2421 * Registriert UseSpell() als Catchall-Kommando.
2422 * Laesst den Spieler ggf. einen Level per /std/gilde aufsteigen, ruft
2423 * call_notify_player_change(), loest Login-Event aus.
2424 * Gibt Willkommenstexte, News und neue Mails aus.
2425 * Findet den Startraum und bewegt den Spieler dorthin.
2426 * Ruft FinalSetup() (aus den Rassenshells).
2427 * Begrenzt Geldmenge im Spieler (wegen Bankzweities) nach Tragkraft und
2428 * erstattet Geld bei Reboot.
2429 * Ruft set_is_wizard().
2430 * Startet Clonen der Autoloader.
2431 * @sa InitPlayer3(),InitPlayer2(), InitPlayer(), start_player().
2432 */
2433private void InitPlayer4()
2434{
2435 int num, str, ski;
2436 string err, called_from_ip;
2437 mixed start_place;
2438 object mon;
2439
2440 enable_commands();
2441 set_heart_beat(1);
2442 command::initialize();
2443 add_put_and_get_commands();
2444 add_team_commands();
2445 add_soul_commands();
2446 add_guide_commands();
2447 add_action( "UseSpell", "", 1 );
2448 set_living_name( getuid() );
2449 while ( remove_call_out("disconnect") != -1 )
2450 ;
2451
2452 if ( QueryProp(P_LEVEL) == -1 )
2453 {
2454 catch( "/std/gilde"->try_player_advance(this_object()) ;publish );
2455 }
2456
2457 if ( interactive(ME) )
2458 call_notify_player_change(1);
2459
2460 if ( interactive(this_object()) ) {
2461 cat( "/etc/NEWS" );
2462
2463 NewbieIntroMsg();
2464
2465 if ( QueryProp(P_INVIS) && !IS_WIZARD(ME) )
2466 SetProp( P_INVIS, 0 );
2467
2468 catch( num = "secure/mailer"->FingerMail(getuid());publish );
2469
2470 if ( num )
2471 write( "Du hast " + num + " neue" +
2472 (num == 1 ? "n Brief" : " Briefe")+" im Postamt liegen.\n" );
2473
2474 catch( RegisterChannels();publish );
2475
2476 if ( (called_from_ip = Query(P_CALLED_FROM_IP)) &&
2477 query_ip_number(ME) != called_from_ip ){
2478 string tmp;
2479
2480 if ( stringp(tmp = query_ip_name(called_from_ip)) &&
2481 tmp != called_from_ip )
2482 tmp = " [" + tmp + "]";
2483 else
2484 tmp = "";
2485
2486 write( "Das letzte Mal kamst Du von " + called_from_ip
2487 + tmp + ".\n" );
2488 }
2489
2490 Set( P_CALLED_FROM_IP, query_ip_number(ME) );
2491 }
2492
2493 if ( !stringp(default_home) || default_home == "" )
2494 default_home = "/gilden/abenteurer";
2495
2496 if ( IS_SEER(ME) && !IS_LEARNER(ME) )
2497 catch( start_place = HAUSVERWALTER->FindeHaus(getuid(ME));publish );
2498 // wenn der Spieler noch ganz frisch ist und noch wenig Stufenpunkte
2499 // gekriegt hat und das Tutorial noch nicht gemacht hat, startet er im
2500 // Tutorial.
2501 else if (QueryProp(P_LEP) <= 120
2502 && QM->HasMiniQuest(this_object(),
2503 "/d/anfaenger/ennox/tutorial/npcs/verkaeufer") != 1)
2504 start_place = "/room/welcome/"+ getuid(this_object());
2505 else
2506 start_place = 0;
2507
2508 if ( !start_place )
2509 start_place = QueryProp(P_START_HOME);
2510
2511 if( objectp(start_place) || (stringp(start_place) && start_place != "" ) ){
2512 if ((err = catch(move( start_place, M_GO|M_SILENT|M_NO_SHOW );publish))
2513 || !environment() )
2514 err = catch(move( default_home, M_GO|M_SILENT|M_NO_SHOW );publish);
2515 }
2516 else
2517 err = catch(move( default_home, M_GO|M_SILENT|M_NO_SHOW );publish);
2518
2519 if ( err )
2520 catch(move( "/gilden/abenteurer", M_GO|M_SILENT|M_NO_SHOW );publish);
2521
2522 // Die Shell muss FinalSetup() nicht implementieren. Daher Callother
2523 catch( ME->FinalSetup();publish );
2524
2525 // Login-event ausloesen
2526 EVENTD->TriggerEvent(EVT_LIB_LOGIN, ([
2527 E_OBJECT: ME,
2528 E_PLNAME: getuid(ME),
2529 E_ENVIRONMENT: environment() ]) );
2530
2531 // erst jetzt GMCP freigeben und zu verhandeln.
2532 gmcp::startup_telnet_negs();
2533
2534 // Schonmal sichern, falls ein Bug (Evalcost...) dazwischen kommen sollte.
2535 autoload_rest = autoload;
2536
2537 // Um Geld-Xties mit illegal viel Geld zu vermeiden, kommt ein Check:
2538 if ( !IS_LEARNER(ME) && !Query(P_TESTPLAYER) &&
2539 mon = present( "\ngeld", ME ) ){
2540 // maximale Kraft, die der Spieler haette haben koennen
2541 str = QueryAttribute(A_STR) + 4;
2542 if ( Query(P_FROG) )
2543 str += 30;
2544 if ( str < 1 )
2545 str = QueryRealAttribute(A_STR) + 4;
2546 if ( str > 30 )
2547 str = 30;
2548
2549 // Trageskill beachten
2550 ski = to_int(UseSkill( SK_CARRY, ([SI_SKILLARG : str ]) ));
2551 if ( !intp(ski) )
2552 ski = 0;
2553
2554 // Wieviel konnte der Spieler insgesamt maximal tragen?
2555 num = 9200 + str * 800 + ski;
2556 if ( num < 3000 )
2557 num = 3000;
2558
2559 // Verdoppeln fuer einen guten Container und nochmal 20% draufschlagen
2560 // zur Sicherheit. Das Ganze danach *4, um die maximale Anzahl Muenzen
2561 // zu erhalten.
2562 num = (int) (num * 8.8);
2563
2564 // Geld, das zuviel ist, auf den Maximalwert kuerzen.
2565 // Zur Sicherheit wird mitgeloggt. Falls ein Spieler sich (zu recht)
2566 // beschwert, kann man immer noch wieder die Summe korrigieren ;-)
2567 if ( (str = mon->QueryProp(P_AMOUNT)) > num ){
2568 mon->SetProp( P_AMOUNT, num );
2569 log_file( "ZUVIEL_GELD", sprintf( "%s: %s hatte %d Muenzen bei "
2570 "sich. Korrigiert auf %d.\n ",
2571 ctime(time())[4..],
2572 capitalize(getuid(ME)),
2573 str, num ) );
2574 }
2575 }
2576 int entschaedigung = QueryProp(P_CARRIED_VALUE);
2577 if ( entschaedigung > 0 )
2578 {
2579 write( "Du findest " + entschaedigung +
2580 " Muenzen, die Du beim letzten Mal verloren hast.\n" );
2581
2582 if ( MayAddWeight( entschaedigung / 4 ) ){
2583 write( "Weil Du nicht mehr soviel tragen kannst, spendest Du den "+
2584 "Rest der Zentralbank.\n" );
2585
2586 num = (QueryProp(P_MAX_WEIGHT) - query_weight_contents()) * 4;
2587 entschaedigung = (num < 0) ? 0 : num;
2588 }
2589
2590 AddMoney( entschaedigung );
2591 SetProp(P_CARRIED_VALUE,0);
2592 }
2593
2594 if ( !QueryProp(P_INVIS) )
2595 say( capitalize(name(WER)) + " betritt diese Welt.\n" );
2596 else
2597 write( "DU BIST UNSICHTBAR!\n\n" );
2598#if __EFUN_DEFINED__(set_is_wizard)
2599 if ( IS_WIZARD(getuid(ME)) )
2600 set_is_wizard( ME, 1 );
2601 else
2602 set_is_wizard( ME, 0 );
2603#endif
2604 if ( query_once_interactive(ME) )
2605 ListAwaited();
2606
2607 // Autoloader werden ganz zum Schluss geclont, da das bis zum bitteren
2608 // (Evalcost-)Ende geschieht und danach u.U. keine Rechenzeit fuer
2609 // andere Aktionen mehr ueber ist
2610 load_auto_objects( autoload );
2611}
2612
2613/** Setzt die Spielerinitialisierung nach start_player() fort.
2614 * Prueft den Wert der vom Spieler getragenen Sachen (fuer Entschaedigung
2615 * nach Reboot).
2616 * Setzt div. Properties des "Spielerkoerpers", die eigentlich gespeichert
2617 * werden, nach einem Reboot zurueck.
2618 * Fragt ggf. nach eMail-Adresse und uebergibt per input_to an
2619 * InitPlayer2().
2620 * @sa InitPlayer3(),InitPlayer2(), InitPlayer(), start_player().
2621*/
2622private void InitPlayer()
2623{
2624 string mailaddr;
2625
2626 // wenn es einen Crash gab, sollen Spieler nicht noch extra bestraft werden
2627 if ( file_time( "/save/" + getuid()[0..0] + "/" + getuid() + ".o" )
2628 < last_reboot_time() ){
2629 SetProp( P_FOOD, 0 );
2630 SetProp( P_DRINK, 0 );
2631 SetProp( P_ALCOHOL, 0 );
2632 SetProp( P_BLIND, 0 );
2633 SetProp( P_DEAF, 0 );
2634 SetProp( P_POISON, 0 );
2635 SetProp( P_GHOST, 0 );
2636 SetProp( P_FROG, 0 );
2637 SetProp( P_HP, QueryProp(P_MAX_HP) );
2638 SetProp( P_SP, QueryProp(P_MAX_SP) );
2639 }
2640
2641 if ( QueryGuest() )
2642 Set( P_MAILADDR, "none" );
2643 else if ( !(mailaddr = Query(P_MAILADDR)) || mailaddr == "" ) {
2644 write(break_string(
2645 "Eine gueltige EMail-Adresse erleichtert es erheblich, Dir "
2646 "ein neues Passwort setzen zu lassen, falls Du einmal Dein "
2647 "Passwort vergisst.",78));
2648 input_to( "getmailaddr",INPUT_PROMPT,
2649 "Gib bitte Deine EMail-Adresse an: " );
2650 return;
2651 }
2652 InitPlayer2();
2653}
2654
2655/** liest eMail-Adresse vom Spieler ein und speichert sie.
2656 * Uebergibt anschliessend an InitPlayer2()
2657 * @param[in] maddr Spielereingabe der Emailadresse.
2658 * @sa InitPlayer2().
2659 */
2660static void getmailaddr( string maddr )
2661{
2662 maddr = check_email(maddr);
2663
2664 if ( !stringp(maddr)) {
2665 write("Deine Eingabe scheint keine gueltige EMail-Adresse gewesen "
2666 "zu sein.\n");
2667 input_to( "getmailaddr", INPUT_PROMPT,
2668 "Gib bitte Deine EMail-Adresse an: " );
2669 return;
2670 }
2671 Set( P_MAILADDR, maddr );
2672 InitPlayer2();
2673}
2674
2675
2676/** Prueft Geschlecht des Spielers und fragt ggf. beim Spieler nach.
2677 * Uebergibt an InitPlayer3() oder get_gender().
2678 * @sa InitPlayer3(), get_gender().
2679 */
2680private void InitPlayer2()
2681{
2682 if( member(({ MALE, FEMALE }), QueryProp(P_GENDER) ) == -1 ) {
2683 input_to( "getgender", INPUT_PROMPT,
2684 "Bist Du maennlich oder weiblich: ");
2685 return;
2686 }
2687
2688 InitPlayer3();
2689}
2690
2691/** Liest Spielerantwort auf die Frage nach dem Geschlecht des Chars ein.
2692 * Wird gerufen von input_to().
2693 * Uebergibt an InitPlayer3().
2694 * @sa InitPlayer3().
2695 */
2696static void getgender( string gender_string )
2697{
2698 gender_string = lower_case( gender_string );
2699
2700 if ( sizeof(gender_string)==1 && gender_string[0] == 'm' ){
2701 write( "Willkommen, mein Herr!\n" );
2702 SetProp( P_GENDER, MALE );
2703 }
2704 else if ( sizeof(gender_string)==1 && gender_string[0] == 'w' ){
2705 write( "Willkommen, gnae' Frau!\n" );
2706 SetProp( P_GENDER, FEMALE );
2707 }
2708 else {
2709 write( "Wie? Was? Verstehe ich nicht!\n" );
2710 input_to( "getgender", INPUT_PROMPT,
2711 "Bist Du maennlich oder weiblich? (tippe m oder w): ");
2712 return;
2713 }
2714
2715 InitPlayer3();
2716}
2717
2718
2719/** Prueft Terminaltyp des Spielers und fragt ggf. beim Spieler nach.
2720 * Uebergibt an InitPlayer4() oder gettty().
2721 * @sa InitPlayer4(), gettty().
2722 */
2723private void InitPlayer3()
2724{
2725 if ( !QueryProp(P_TTY) || QueryProp(P_TTY) == "none" )
2726 {
2727 write( "Waehle einen Terminaltyp (kann spaeter mit <stty> geaendert "
Zesstra224e78f2022-02-10 12:07:34 +01002728 "werden).\n");
2729 input_to( "gettty", INPUT_PROMPT, "vt100, ansi, dumb (Standard: ansi): " );
MG Mud User88f12472016-06-24 23:31:02 +02002730 return;
2731 }
2732 InitPlayer4();
2733}
2734
2735/** Liest Spielerantwort auf die Frage nach dem Terminaltyp ein.
2736 * Wird gerufen von input_to().
2737 * Uebergibt an InitPlayer4().
2738 * @sa InitPlayer4().
2739 */
2740static void gettty( string ttystr )
2741{
2742 if ( !ttystr || ttystr == "" )
Zesstrabb7a4b32022-02-10 14:20:31 +01002743 ttystr = "ansi";
MG Mud User88f12472016-06-24 23:31:02 +02002744
2745 ttystr = lower_case(ttystr);
2746
2747 if ( ttystr == "vt100" ){
2748 write( "Dies sollte " + ANSI_BOLD + "fett" + ANSI_NORMAL + " sein.\n" );
2749 SetProp( P_TTY, ttystr );
2750 }
2751 else
2752 if ( ttystr == "ansi" ){
2753 write( "Dies sollte " + ANSI_RED + "rot" + ANSI_NORMAL +
2754 " sein.\n" );
2755 SetProp( P_TTY, "ansi" );
2756 }
2757 else if ( ttystr == "dumb" ){
2758 write( "Ohje, oede! Besorg Dir ein besseres Terminal!\n" );
2759 SetProp( P_TTY, "dumb" );
2760 }
2761 else {
2762 write( "Dieser Terminaltyp wird nicht unterstuetzt. Nimm bitte "
2763 "einen aus:\nvt100, ansi or dumb (Standard ist dumb).\n" );
2764 input_to( "gettty", INPUT_PROMPT,
2765 "vt100, ansi or dumb (Standard ist dumb): ");
2766 return;
2767 }
2768
2769 InitPlayer4();
2770}
2771
2772
2773/** Liefert die UID des Charakters zurueck, also den Charakternamen.
2774 * @return UID des Objekts (Charaktername).
2775 */
2776nomask string query_real_name() {
2777 /* ACHTUNG !! DIES LFUN DARF NICHT ENTFERNT WERDEN !!! */
2778 /* Sie wird vom Gamedriver (zB bei F_ED) aufgerufen !! */
2779 /* Ich bin da zwar nicht so ueberzeugt von, dass der Driver die heutzutage
2780 * noch ruft, aber die halbe Mudlib ruft sie. ;-) (Zesstra, 27.4.08)
2781 */
2782 return getuid();
2783}
2784
2785/*
2786 * the wizard command review: show player moving messages
2787 */
2788int review() {
2789 string *msg;
2790 write(short());
2791 write("Deine Bewegungen werden wie folgt gemeldet:\n"+
2792 "mout: "+name(WER)+" "+(msg=explode(QueryProp(P_MSGOUT),"#"))[0]
2793 +" <Richtung>"+(sizeof(msg)>1 ? msg[1] : "")+".\n"+
2794 "min: "+name(WER)+" "+QueryProp(P_MSGIN)+".\n"+
2795 "mmout: "+name(WER)+" "+QueryProp(P_MMSGOUT)+".\n"+
2796 "mmin: "+name(WER)+" "+QueryProp(P_MMSGIN)+".\n"+
2797 (IS_LEARNER(ME) ?
2798 "cmsg: "+name(WER)+" "+QueryProp(P_CLONE_MSG)+".\n"+
2799 "dmsg: <Irgendetwas> "+QueryProp(P_DESTRUCT_MSG)+".\n"
2800 : "")+
2801 "Wenn Du jemanden angreifst, sieht das so aus:\n"+
2802 name(WER)+" greift Dich"+QueryProp(P_HANDS)[0]+" an.\n");
2803 return 1;
2804}
2805
2806/*
2807 * set player moving messages
2808 */
2809
2810static int setmin(string str)
2811{
2812 SetProp(P_MSGIN, _unparsed_args()||"kommt an");
2813 write("Ok.\n");
2814 return 1;
2815}
2816
2817static int setmout(string str)
2818{
2819 string *msg;
2820
2821 if(sizeof(msg=explode((_unparsed_args()||"geht"),"#"))>2)
2822 {
2823 write("Du darfst nur einmal '#' fuer die Richtung angeben.\n");
2824 return 1;
2825 }
2826 if(sizeof(msg)>1)
2827 {
2828 if (msg[0]!="" && msg[0][<1]==' ') msg[0]=msg[0][0..<2];
2829 SetProp(P_MSGOUT, msg[0]+"#"+msg[1]);
2830 }
2831 else
2832 SetProp(P_MSGOUT, _unparsed_args()||"geht");
2833 write("Ok.\n");
2834 return 1;
2835}
2836
2837static int setmmin(string str)
2838{
2839 SetProp(P_MMSGIN, _unparsed_args()||"erscheint");
2840 write("Ok.\n");
2841 return 1;
2842}
2843
2844static int setmmout(string str)
2845{
2846 SetProp(P_MMSGOUT, _unparsed_args()||"verschwindet");
2847 write("Ok.\n");
2848 return 1;
2849}
2850
2851static int setcmsg(string str)
2852{
2853 SetProp(P_CLONE_MSG, _unparsed_args()||"zaubert etwas aus "
2854 + QueryPossPronoun(MALE,WEM) + " Aermel hervor");
2855 write("Ok.\n");
2856 return 1;
2857}
2858
2859static int setdmsg(string str)
2860{
2861 SetProp(P_DESTRUCT_MSG, _unparsed_args()||"wird von " + name(WER,1)
2862 + " zerstaeubt");
2863 write("Ok.\n");
2864 return 1;
2865}
2866
2867static int set_title(string str)
2868{
2869 string bonus;
2870
2871 if(!IS_SEER(this_object()) && !FAO_HAS_TITLE_GIFT(this_object()) )
2872 {
2873 return 0;
2874 }
2875
2876 bonus = "";
2877 if (!(str=_unparsed_args()))
2878 str = "";
2879 else if( str[0..2]=="\\b," || str[0..2]=="\\b'" )
2880 {
2881 bonus = "\b"; // ein backspace fuer ein (hoch)komma ist ok! :-)
2882 str = str[2..];
2883 }
2884 if(str=="0") // damit der Gildentitel zum Vorschein kommen kann
2885 SetProp(P_TITLE, 0);
2886 else
2887 SetProp(P_TITLE, bonus+str);
2888 write("Ok.\n");
2889 return 1;
2890}
2891
2892static int extra_input(string str, string look)
2893{
2894 if (str=="**")
2895 {
2896 if (look=="")
2897 SetProp(P_EXTRA_LOOK,0);
2898 else
2899 SetProp(P_EXTRA_LOOK,look);
2900 write("Ok.\n");
2901 return 1;
2902 }
2903 input_to("extra_input",INPUT_PROMPT, "]" ,look+str+"\n");
2904 return 1;
2905}
2906
2907static int extralook(mixed str)
2908{
2909 if( str=="?" )
2910 {
2911 write( "Dein Extralook ist : "+QueryProp(P_EXTRA_LOOK) + "\n");
2912 return 1;
2913 }
2914 write("Bitte gib Deinen Extra-Look ein. Beenden mit **:\n");
2915 input_to("extra_input",INPUT_PROMPT,"]","");
2916 return 1;
2917}
2918
2919static void calculate_value()
2920{
Arathorn5513dfc2021-03-16 21:52:20 +01002921 int carried_value, value;
MG Mud User88f12472016-06-24 23:31:02 +02002922
2923 carried_value=0;
2924 foreach(object ob: deep_inventory(ME)) {
2925 if (!ob->QueryProp(P_AUTOLOADOBJ))
Zesstra04f613c2019-11-27 23:32:54 +01002926 carried_value+=((value=({int})ob->QueryProp(P_VALUE)) > 1000 ? 1000 : value);
MG Mud User88f12472016-06-24 23:31:02 +02002927 }
2928 SetProp(P_CARRIED_VALUE, carried_value);
2929}
2930
MG Mud User88f12472016-06-24 23:31:02 +02002931void save_me(mixed value_items)
2932{
2933 // Gaeste werden nicht gespeichert
2934 if( getuid()[0..3]=="gast" )
2935 return;
2936
2937 // Autoloader identifizieren und speichern
2938 autoload=([]);
2939 foreach(object ob: deep_inventory(ME)) {
Arathorn82f47272019-11-25 21:21:39 +01002940 mixed val = ob->QueryProp( P_AUTOLOADOBJ );
MG Mud User88f12472016-06-24 23:31:02 +02002941 if (val && clonep(ob))
2942 {
2943 string obname=load_name(ob);
2944 if (obname == GELD)
2945 autoload[obname] += val;
2946 else
2947 autoload += ([obname:val]);
2948 }
2949 }
2950 // An noch nicht geclonte Autoloader denken!
2951 autoload += autoload_rest;
2952
2953 // Im Bedarfsfall Wert des Inventory bestimmen
2954 if (value_items)
2955 calculate_value();
2956 else
2957 SetProp(P_CARRIED_VALUE, 0);
2958
2959 // Logout-Zeit speichern
2960 if(query_once_interactive(ME) && !QueryProp(P_INVIS))
2961 Set(P_LAST_LOGOUT,time());
2962
2963 // Funktion zur Bestimmung des Gildenrating aufrufen
2964 string gilde=GUILD_DIR+QueryProp(P_GUILD);
2965 if (find_object(gilde) || file_size(gilde+".c")>-1)
2966 catch(call_other(gilde,"GuildRating",this_object());publish);
2967
2968 // Speichern des Spielers
Zesstra3162c892017-01-30 15:55:22 +01002969 save_object(SAVEPATH+getuid()[0..0]+"/" + getuid());
MG Mud User88f12472016-06-24 23:31:02 +02002970}
2971
2972static varargs void log_autoload( string file, string reason, mixed data, string error )
2973{
2974 if (member(autoload_error,file)!=-1) return;
2975 log_file(SHELLLOG("NO_AUTO_FILE"),sprintf("%s: %s: %s\nreason: cannot %s file\ndata: %O\n%s\n",
2976 ctime()[4..15],capitalize(getuid()),file,reason,data,
2977 (error?"Fehlermeldung: "+error+"\n":"")));
2978 autoload_error+=({file});
2979}
2980
2981// tics, die fuer autoloader reichen sollten:
2982#define SAFE_FOR_AUTOLOADER __MAX_EVAL_COST__/4
2983
2984private void load_auto_object( string file, mixed data )
2985{
2986 object ob;
2987 string error;
2988
2989 if( get_eval_cost() < SAFE_FOR_AUTOLOADER ) return;
2990 m_delete( autoload_rest, file );
2991 autoload_error-=({file});
2992
2993 if ( file == "/obj/money" )
2994 file = "/items/money";
2995 if ( file == "/obj/seercard" )
2996 file = "/items/seercard";
2997
2998 ob = find_object(file);
2999
3000 if (!ob)
3001 {
3002 if (file_size(file+".c")<0&&
3003 file_size(implode(explode(file,"/")[0..<2],"/")+
3004 "/virtual_compiler.c")<0)
3005 {
3006 log_autoload(file,"find",data,0);
3007 return;
3008 }
3009 if (error = catch(load_object(file); publish))
3010 {
3011 log_autoload(file,"load",data,error);
3012 return;
3013 }
3014 }
3015 if ( error = catch(ob = clone_object(file); publish) )
3016 {
3017 log_autoload(file,"clone",data, error);
3018 return;
3019 }
3020
3021 if ( error = catch(ob->SetProp( P_AUTOLOADOBJ, data ); publish) )
3022 {
3023 log_autoload(file,"SetProp",data, error);
3024 ob->remove(1);
3025 if (ob) destruct(ob);
3026 return;
3027 }
3028
3029 if ( error = catch(ob->move( ME, M_NOCHECK );publish) ) {
3030 log_autoload(file,"move",data, error);
3031 ob->remove(1);
3032 if(ob) destruct(ob);
3033 return;
3034 }
3035}
3036
3037static void load_auto_objects( mapping map_ldfied )
3038{
3039 if ( (!mappingp(map_ldfied) || !sizeof(map_ldfied)) && !sizeof(autoload_rest) )
3040 return;
3041
3042 // Mit Netztoten Spielern rechnen manche Autoloader nicht. Also
3043 // das Clonen unterbrechen und in Reconnect() wieder anwerfen.
3044 if ( !interactive() )
3045 return;
3046
3047 // Kleiner Hack: autoload_rest ist eine globale Variable, die beim
3048 // Clonen der einzelnen Autoloader direkt veraendert wird.
3049 // So lange das Mapping noch Eintraege hat, muessen wir noch fehlende
3050 // Autoloader clonen.
3051 if ( !sizeof(autoload_rest) )
3052 autoload_rest = map_ldfied;
3053
3054 // Schon hier einen call_out() zum "Nach"clonen von noch nicht geclonten
3055 // Autoloadern starten, da spaeter u.U. keine Rechenzeit mehr dafuer da ist.
3056 while ( remove_call_out("load_auto_objects") != -1 )
3057 /* do nothing */;
3058
3059 // Mit Parameter '0' aufrufen, da das globale Mapping benutzt wird.
3060 // Verzoegerung 0 in rekursiven Callouts ist bloed, also 1s Delay
3061 call_out( "load_auto_objects", 2, 0 );
3062
3063 // Mit catch() gegen die Evalcost-Falle!
3064 // Mit Absicht das walk_mapping() aus der "alten" Version erhalten und
3065 // nicht durch eine (einfachere) Schleife inkl. get_eval_cost() ersetzt,
3066 // da eine Schleife gegenueber der walk_mapping()-Loesung den Aufbau
3067 // der previous_object()-Kette veraendern wuerde; darauf testen aber
3068 // manche Objekte.
3069 catch( walk_mapping( autoload_rest, #'load_auto_object/*'*/ ) );
3070}
3071
3072/*
3073 * al_to_title: Make the numeric alignment value into a string
3074 */
3075static string al_to_title(int a)
3076{
3077 if (a >= KILL_NEUTRAL_ALIGNMENT * 100)
3078 return "heilig";
3079 if (a > KILL_NEUTRAL_ALIGNMENT * 20)
3080 return "gut";
3081 if (a > KILL_NEUTRAL_ALIGNMENT * 4)
3082 return "nett";
3083 if (a > - KILL_NEUTRAL_ALIGNMENT * 4)
3084 return "neutral";
3085 if (a > - KILL_NEUTRAL_ALIGNMENT * 20)
3086 return "frech";
3087 if (a > - KILL_NEUTRAL_ALIGNMENT * 100)
3088 return "boese";
3089 return "satanisch";
3090}
3091
3092static int toggle_whimpy_dir(string str) {
3093 SetProp(P_WIMPY_DIRECTION,str=_unparsed_args()||str);
3094 if (str)
3095 printf("Ok, Fluchtrichtung %O.\n",str);
3096 else
3097 printf("Ok, bevorzugte Fluchtrichtung deaktiviert.\n");
3098 return 1;
3099}
3100
3101static int toggle_whimpy(string str)
3102{
3103 int i;
3104
3105 if(!str || str=="" || (sscanf(str,"%d",i)<0))
3106 {
3107 write("vorsicht <hp>, 0<=hp<"+QueryProp(P_MAX_HP)+"\n");
3108 return 1;
3109 }
3110 if(i>=QueryProp(P_MAX_HP) || i<0)
3111 {
3112 write("Der Wert ist nicht erlaubt.\n");
3113 return 1;
3114 }
3115 if(!i) write("Prinz Eisenherz-Modus.\n");
3116 else write("Vorsicht-Modus ("+i+")\n");
3117 SetProp(P_WIMPY,i);
3118 return 1;
3119}
3120
3121/** Bestimmt, ob das Spielerobjekt beschattet werden darf.
3122 * Beschatten ist nur fuer Objekte erlaubt, die in /std/player/shadows
3123 * abgelegt sind.
3124 * Ausnahme: Testspieler mit gesetztem P_ALLOWED_SHADOW
3125 * @param[in] obj Objekt, was beschatten moechte.
3126 * @return 0, wenn Beschatten erlaubt, 1 sonst.
3127 */
3128varargs nomask int query_prevent_shadow(object obj)
3129{
3130 string what, allowed_shadow;
MG Mud User88f12472016-06-24 23:31:02 +02003131
3132// if ( Query(P_TESTPLAYER) )
3133// return 0;
3134
3135 if (obj){
3136 what=object_name(obj);
3137 if (what && what != "" &&
Arathorn5513dfc2021-03-16 21:52:20 +01003138 sscanf(what,"/std/player/shadows/%s#%~d",what)==2)
MG Mud User88f12472016-06-24 23:31:02 +02003139 return 0;
3140
3141 // Einem Testspieler kann man P_ALLOWED_SHADOW auf einen zu testenden
3142 // Shadow setzen.
3143 if ( Query(P_TESTPLAYER) &&
3144 stringp(what) &&
3145 stringp(allowed_shadow=Query(P_ALLOWED_SHADOW)) &&
3146 strstr(what, allowed_shadow)==0)
3147 return 0;
3148 }
3149 return 1;
3150}
3151
3152static int uhrzeit()
3153{
3154 write(dtime(time()+QueryProp(P_TIMEZONE)*3600)+".\n");
3155 return 1;
3156}
3157
3158protected string SetDefaultHome(string str)
3159{
3160 return default_home=str;
3161}
3162
3163string QueryDefaultHome()
3164{
3165 return default_home;
3166}
3167
3168protected string SetDefaultPrayRoom(string str)
3169{
3170 if(hc_play>1)
3171 {
3172 default_pray_room="/room/nirvana";
3173 }
3174 else
3175 default_pray_room=str;
3176
3177 return default_pray_room;
3178}
3179
3180string QueryPrayRoom()
3181{
3182 if(hc_play>1)
3183 {
3184 return "/room/nirvana";
3185 }
3186 string room = QueryProp(P_PRAY_ROOM);
3187 if (stringp(room))
3188 return room;
3189 else if (default_pray_room)
3190 return default_pray_room;
3191 // hoffentlich ist das wenigstens gesetzt.
3192 return default_home;
3193}
3194
3195void _restart_beat()
3196{
3197 tell_object(ME,
3198 "Der GameDriver teilt Dir mit: Dein Herzschlag hat wieder eingesetzt.\n");
3199 set_heart_beat(1);
3200}
3201
3202static int weg(string str)
3203{
3204 if (!(str=_unparsed_args()))
3205 {
3206 printf("Du bist nicht%s als abwesend gekennzeichnet.\n",
3207 QueryProp(P_AWAY) ? " mehr" : "");
3208 SetProp(P_AWAY, 0);
3209 return 1;
3210 }
3211 write("Du bist jetzt als abwesend gekennzeichnet.\n");
3212 SetProp(P_AWAY, str);
3213 return 1;
3214}
3215
3216/* Ein Befehl zum anschauen der Wegmeldung anderer Spieler */
3217static int wegmeldung(string player)
3218{
3219
3220 object player_ob;
3221 string weg;
3222
3223 if ( !player || player=="" ||
3224 player==lowerstring(this_player()->QueryProp(P_NAME)))
3225 {
3226 weg=this_player()->QueryProp(P_AWAY);
3227 write ("Du bist "+(weg?"":"nicht ")+"als abwesend gekennzeichnet.\n");
3228 if (weg)
3229 write(break_string(weg, 78,"Grund: ",BS_INDENT_ONCE));
3230 return 1;
3231 }
3232
3233 // Welcher Spieler ist gemeint?
3234 player_ob=find_player(player);
3235
3236 // Spieler nicht da oder Invis und Anfrager is kein Magier
3237 if (!player_ob ||
3238 (player_ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player())))
3239 {
3240 write(capitalize(player)+" ist gerade nicht im Spiel.\n");
3241 return 1;
3242 }
3243
3244 weg=player_ob->QueryProp(P_AWAY);
3245
3246 // player_ob->Name() gibt bei invis-Magiern "Jemand" zurueck
3247 write (player_ob->QueryProp(P_NAME)+" ist "+
3248 (weg?"":"nicht ")+"als abwesend gekennzeichnet.\n");
3249
3250 if (weg)
3251 write(break_string(weg, 78,"Grund: ",BS_INDENT_ONCE));
3252
3253 return 1;
3254}
3255
3256static string timediff(int time)
3257{
3258 string ret;
3259
3260 ret="";
3261 if(time>=86400) {
3262 ret+=time/86400+"d ";
3263 time%=86400;
3264 }
3265 if(time<36000) ret+="0";
3266 ret+=time/3600+":";
3267 time%=3600;
3268 if(time<600) ret+="0";
3269 ret+=time/60+":";
3270 time%=60;
3271 if(time<10) ret+="0";
3272 ret+=time+"";
3273 return ret;
3274}
3275
3276
3277/* Ein Befehl zum anschauen der Idlezeit anderer Spieler */
3278static int idlezeit(string player)
3279{
3280
3281 object player_ob;
3282 int idle;
3283
3284 if ( !player || player=="" ||
3285 player==lowerstring(this_player()->QueryProp(P_NAME)))
3286 {
3287 write ("Du bist selber natuerlich gerade nicht idle.\n");
3288 return 1;
3289 }
3290
3291 // Welcher Spieler ist gemeint?
3292 player_ob=find_player(player);
3293
3294 // Spieler nicht da oder Invis und Anfrager is kein Magier
3295 if (!player_ob ||
3296 (player_ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player())))
3297 {
3298 write(capitalize(player)+" ist gerade nicht im Spiel.\n");
3299 return 1;
3300 }
3301
3302 idle=query_idle(player_ob);
3303
3304 // player_ob->Name() gibt bei invis-Magiern "Jemand" zurueck
3305 write (player_ob->QueryProp(P_NAME)+" ist "+
3306 (idle>=60?timediff(idle):"nicht")+" passiv.\n");
3307
3308 return 1;
3309}
3310
3311
3312/** Belebt einen netztoten Spieler wieder.
3313 * Reaktiviert Heartbeats, bewegt den Spieler zurueck an den Ort, der eim
3314 * Einschlafen zum Aufwachen ermittelt wurde (im einfachsten Fall der Raum,
3315 * wo man eingeschlafen ist).
3316 */
3317static void ndead_revive()
3318{
Bugfix7bf5d4d2022-09-28 11:11:00 +02003319 string fname;
3320 int ret;
MG Mud User88f12472016-06-24 23:31:02 +02003321
Bugfix7bf5d4d2022-09-28 11:11:00 +02003322 set_heart_beat(1);
3323 ndead_next_check = NETDEAD_CHECK_TIME;
3324 ndead_currently = 0;
3325 ndead_lasttime = 0;
MG Mud User88f12472016-06-24 23:31:02 +02003326
Bugfix7bf5d4d2022-09-28 11:11:00 +02003327 if ( !objectp(ndead_location) &&
3328 stringp(ndead_l_filename) && sizeof(ndead_l_filename))
3329 {
3330 if ( member( ndead_l_filename, '#' ) == -1 )
3331 {
3332 catch(load_object( ndead_l_filename); publish);
3333 ndead_location = find_object(ndead_l_filename);
MG Mud User88f12472016-06-24 23:31:02 +02003334 }
Bugfix7bf5d4d2022-09-28 11:11:00 +02003335 else
3336 {
3337 ndead_location = find_object(ndead_l_filename);
3338 if ( !ndead_location && env_ndead_info )
3339 {
3340 fname = explode( ndead_l_filename, "#" )[0];
3341 catch(ndead_location =
3342 (load_object(fname)->SetProp(P_NETDEAD_INFO, env_ndead_info));
3343 publish);
3344 if ( !objectp(ndead_location) )
3345 {
3346 catch(load_object( ndead_location);publish);
3347 ndead_location = find_object(ndead_location);
3348 }
3349 }
MG Mud User88f12472016-06-24 23:31:02 +02003350 }
Bugfix7bf5d4d2022-09-28 11:11:00 +02003351 }
MG Mud User88f12472016-06-24 23:31:02 +02003352
Bugfix215c0912022-09-28 11:20:51 +02003353 // Wenn immer noch kein ndead_location da oder die Bewegung dahin nicht
3354 // klappt, ist das naechste Fallback das default_home der Shell.
Bugfix7bf5d4d2022-09-28 11:11:00 +02003355 if ( !objectp(ndead_location)
3356 || catch(ret = move( ndead_location, M_GO|M_SILENT );publish)
Bugfix215c0912022-09-28 11:20:51 +02003357 || ret != MOVE_OK )
Bugfix7bf5d4d2022-09-28 11:11:00 +02003358 {
Bugfix215c0912022-09-28 11:20:51 +02003359 ret = 0;
3360 if(catch(ret = move(default_home, M_GO | M_SILENT); publish) ||
3361 ret != MOVE_OK)
3362 {
3363 // und wenn auch das nicht klappt, bleibt die Abenteurergilde, die
3364 // hoffentlich erreichbar ist. Wenn nicht, dann solls hart abbrechen...
3365 move("/gilden/abenteurer", M_GO | M_SILENT);
3366 }
Bugfix7bf5d4d2022-09-28 11:11:00 +02003367 ndead_location = environment();
3368 }
3369
Bugfix7bf5d4d2022-09-28 11:11:00 +02003370 ndead_l_filename = 0;
3371 env_ndead_info = 0;
MG Mud User88f12472016-06-24 23:31:02 +02003372}
3373
3374/** Bewegt einen netztoten Spieler in den Netztotenraum
3375 * Gerufen von heartbeat().
3376 * Zerstoert Gaeste, verlaesst ggf. das Team, ermittelt, ob der Spieler beim
3377 * Aufwachen in das alte Environment bewegt werden soll oder in einen anderen
3378 * Raum, hierzu wird im Environment P_NETDEAD_INFO abgefragt.
3379 * Deaktiviert die Kommandos per disable_commands().
3380 */
3381static void ndead_move_me() {
3382 object team;
MG Mud User88f12472016-06-24 23:31:02 +02003383
3384 set_heart_beat(0);
3385 stop_heart_beats();
3386 if (QueryGuest()) {
3387 quit();
3388 if (ME)
3389 remove();
3390 if (ME)
3391 destruct(ME);
3392 return;
3393 }
3394 ndead_next_check=NETDEAD_CHECK_TIME;
3395 ndead_currently=1;
3396 ndead_lasttime=0;
3397 ndead_location=environment();
3398 if (objectp(ndead_location))
3399 ndead_l_filename=object_name(ndead_location);
3400
3401 if (objectp(environment())
3402 && sizeof(explode(object_name(environment()),"#")) > 1)
3403 env_ndead_info=environment()->QueryProp(P_NETDEAD_INFO);
3404 else
3405 env_ndead_info=0;
3406
3407 if ( objectp(team=Query(P_TEAM)) )
3408 // Der Test auf assoziierte Teammitglieder (== FolgeNPCs)
3409 // verhindert, dass Spieler nach "schlafe ein" aus dem
3410 // Team ausgetragen werden. -- 29.01.2002 Tiamak
3411 // && !objectp(amem=Query(P_TEAM_ASSOC_MEMBERS))
3412 // && !(pointerp(amem) && sizeof(amem)))
3413 team->RemoveMember(ME);
3414
3415 disable_commands();
3416 move(NETDEAD_ROOM,M_GO|M_NO_ATTACK|M_NOCHECK,"ins Reich der Netztoten");
3417}
3418
3419/** Ist dieser Character ein Gast?
3420 * @return 1, wenn Gast, 0 sonst.
3421 */
3422int QueryGuest()
3423{
Arathorn5513dfc2021-03-16 21:52:20 +01003424 return sscanf(getuid(),"gast%~d");
MG Mud User88f12472016-06-24 23:31:02 +02003425}
3426
3427/** Spielerkommando 'schlafe ein'.
3428 * Ruft remove_interactive() bei Spielern, bei Magiern wird quit() gerufen,
3429 * um das Magierobjekt zu zerstoeren.
3430 * @sa quit()
3431 */
3432int disconnect(string str)
3433{
3434 string verb;
3435 string desc = break_string(
3436 "\"schlafe ein\" beendet Deine Verbindung mit "MUDNAME". Du behaeltst "
3437 "Deine Sachen.\nFalls "MUDNAME" jedoch abstuerzt oder neu gestartet "
3438 "wird, waehrend Du weg bist, verlierst Du die meisten allerdings "
3439 "(genauso, als wenn Du Deine Verbindung mit \"ende\" beendet haettest). "
3440 "In diesem Fall bekommst Du dann eine kleine Entschaedigung."
3441 ,78,0,BS_LEAVE_MY_LFS);
3442
3443 verb=query_verb();
3444 if (!verb)
3445 verb="AUTOCALL";
3446 if (verb[0..5]=="schlaf" && str!="ein")
3447 {
3448 notify_fail(desc);
3449 return 0;
3450 }
3451 if (IS_LEARNER(this_object()))
3452 return quit();
3453
3454 tell_object(this_object(), desc);
3455
3456 if (clonep(environment()) && !environment()->QueryProp(P_NETDEAD_INFO))
3457 tell_object(this_object(),break_string(
3458 "\nACHTUNG: Wenn Du hier laengere Zeit schlaefst, "
3459 "kommst Du vermutlich nicht an diesen Ort zurueck!",78));
3460
3461 say(capitalize(name(WER))+" hat gerade die Verbindung zu "MUDNAME" gekappt.\n");
3462 remove_interactive(ME);
3463 call_out(#'clear_tell_history,4);
3464 return 1;
3465}
3466
3467static int finger (string str)
3468{
3469 string ret;
3470 mixed xname;
3471
3472 if (!str || str==""
3473 || sizeof(explode(str," ")-({"-n","-p","-s","-v","-a"}))>1)
3474 {
3475 write("finger <spielername> oder finger <spielername@mudname>\n"+
3476 "Bitte nur den reinen Spielernamen verwenden, keine Namensvorsaetze oder Titel\n");
3477 return 1;
3478 }
3479 xname=explode(str,"@");
3480 if(sizeof(xname)==2)
3481 {
3482 if (xname[0]=="-n " || xname[0]=="-p " || xname[0]=="-s ") {
3483 write("finger <spielername>@<mudname> - der Spielername fehlt.\n");
3484 return 1;
3485 }
3486 if (ret=INETD->_send_udp(xname[1],([
3487 REQUEST: "finger",
3488 SENDER: getuid(ME),
3489 DATA: (explode(xname[0]," ")-({"-n","-p","-s"}))[0]
3490 ]), 1))
3491 write(ret);
3492 else
3493 write("Anfrage abgeschickt.\n");
3494 return 1;
3495 }
3496 "/p/daemon/finger"->finger_single(str,1);
3497 return 1;
3498}
3499
3500string lalign(string str, int wid)
3501{
3502 return (str+" "+
3503 " ")[0..wid-1];
3504}
3505
3506#define MUDS_BAR "\
3507-------------------------------------------------------------------------------"
3508
3509private void format(mixed mud, mixed hosts, string output)
3510{
3511 output += lalign(hosts[mud][HOST_NAME], 20) + " " +
3512 (hosts[mud][HOST_STATUS] ?
3513 hosts[mud][HOST_STATUS] > 0 ?
3514 "UP " + ctime(hosts[mud][HOST_STATUS])[4..15] :
3515 "DOWN " + ctime(-hosts[mud][HOST_STATUS])[4..15]
3516 : "UNKNOWN Never accessed.") + "\n";
3517}
3518
3519static int muds() {
3520 mapping hosts;
MG Mud User88f12472016-06-24 23:31:02 +02003521 mixed muds, output;
3522
3523 output = lalign("Mudname", 20) + " Status Last access";
3524 output += "\n" + MUDS_BAR[0..sizeof(output)] + "\n";
3525 muds = sort_array(m_indices(hosts = INETD->query("hosts")),#'>);
3526 map(muds, #'format, hosts, &output);
3527 More(output);
3528 return 1;
3529}
3530
3531// **** local property methods
3532static int _set_level(int i)
3533{
3534 if (!intp(i)) return -1;
3535 if (i<1) return -1;
3536 Set(P_LEVEL, i);
3537 GMCP_Char( ([P_LEVEL: i]) );
3538 return i;
3539}
3540
3541static int _set_invis(int a)
3542{
3543 return Set(P_INVIS, intp(a) ? a : !Query(P_INVIS));
3544}
3545
3546/* sets the terminal type */
3547/* note: support vt100 (b/w), ansi (color), dumb (none) */
3548static string _set_tty(string str) {
3549 if(str != "dumb" && str != "vt100" && str != "ansi")
3550 return Query(P_TTY);
3551 return Set(P_TTY, str);
3552}
3553
3554static int stty(string str)
3555{
3556 if(str!="dumb"&&str!="vt100"&&str!="ansi"&&str!="reset")
3557 {
3558 write("Kommando: stty dumb|vt100|ansi oder reset\n");
3559 }
3560 if(str == "reset") {
3561 printf("Dieser Text sollte lesbar sein!\n");
3562 return 1;
3563 }
3564
3565 write("TTY steht jetzt auf "+SetProp(P_TTY,str)+".\n");
3566 if(str == "ansi" || str == "vt100") {
3567 printf("Terminal Test:\n");
3568 printf("VT100: fett unterstrichen "+
3569 "blinkend invers\n");
3570 if(str == "ansi") {
3571 printf("ANSI Farben und VT100 Attribute:\n");
3572 foreach(int fg: 30 .. 37) {
3573 foreach(int bg: 40 .. 47) {
3574 printf("[%d;%dm@", fg, bg);
3575 printf("[%d;%dm@", fg, bg);
3576 printf("[%d;%dm@", fg, bg);
3577 printf("[%d;%dm@", fg, bg);
3578 }
3579 printf("\n");
3580 }
Zesstra37125992019-08-08 21:10:00 +02003581 printf("Sollte dieser Text hier nicht richtig lesbar\nsein, "+
3582 "benutze das Kommando 'stty reset'.\n");
MG Mud User88f12472016-06-24 23:31:02 +02003583 }
3584
3585 }
3586 return 1;
3587}
3588
3589int set_ascii_art(string str)
3590{
3591 if (str!="ein"&&str!="aus")
3592 {
3593 printf("Du moechtest 'Grafik' "+(QueryProp(P_NO_ASCII_ART)?"NICHT ":"")+
3594 "sehen.\n");
3595 }
3596
3597 if (str=="ein") {
3598 SetProp(P_NO_ASCII_ART, 0);
3599 printf("Zukuenftig moechtest Du 'Grafik' sehen.\n");
3600 }
3601
3602 if (str=="aus") {
3603 SetProp(P_NO_ASCII_ART, 1);
3604 printf("Zukuenftig moechtest Du KEINE 'Grafik' mehr sehen.\n");
3605 }
3606
3607
3608 return 1;
3609}
3610
3611int _set_shell_version(int arg)
3612{
3613 if (!intp(arg))
3614 return -1;
3615 Set(P_SHELL_VERSION,({QueryProp(P_RACE),arg}));
3616 return 1;
3617}
3618
3619int _query_shell_version()
3620{ mixed sv;
3621
3622 if (!(sv=Query(P_SHELL_VERSION)) || !pointerp(sv) || sizeof(sv)!=2 ||
3623 sv[0]!=QueryProp(P_RACE) || !intp(sv[1]))
3624 return 0;
3625 return sv[1];
3626}
3627
3628// XxXxXxXxXx
3629
3630int more(string str)
3631{
3632 if(!str)
3633 {
3634 notify_fail("Usage: more <file>\n");
3635 return 0;
3636 }
3637 if (file_size(str) <= 0) {
3638 notify_fail(str+": No such file\n");
3639 return 0;
3640 }
3641 More(str, 1);
3642 return 1;
3643}
3644
3645static int set_visualbell(string str)
3646{
3647 if(!str)
3648 {
3649 write("Derzeitige Einstellung fuer Tonausgabe: "+
3650 (QueryProp(P_VISUALBELL)?"AUS":"EIN")+".\n");
3651 return 1;
3652 }
3653 if (str=="ein")
3654 {
3655 if(!QueryProp(P_VISUALBELL))
3656 write("Die Tonausgabe stand schon auf EIN.\n");
3657 else
3658 {
3659 SetProp(P_VISUALBELL,0);
3660 write("OK, Tonausgabe auf EIN gestellt.\n");
3661 }
3662 }
3663 else
3664 if (str=="aus")
3665 {
3666 if(QueryProp(P_VISUALBELL))
3667 write("Die Tonausgabe stand schon auf AUS.\n");
3668 else
3669 {
3670 SetProp(P_VISUALBELL,1);
3671 write("OK, Tonausgabe auf AUS gestellt.\n");
3672 }
3673 }
3674 else
3675 write("Syntax: ton [ein|aus]\n");
3676 return 1;
3677}
3678
3679static int set_screensize(string str)
3680{
3681 int size;
3682
3683 if (str && (str[0..2] == "abs" || str[0..2]=="rel")) {
3684 size = QueryProp(P_MORE_FLAGS);
3685 if (str[0..2] == "abs") {
3686 size |= E_ABS;
3687 write("Es wird beim Prompt die Zeilenzahl des Textes angegeben.\n");
3688 }
3689 else {
3690 size &= ~E_ABS;
3691 write("Es wird beim Prompt der prozentuale Anteil des Textes angegeben.\n");
3692 }
3693 SetProp(P_MORE_FLAGS, size);
3694 return 1;
3695 }
3696
3697 if ( str && (str=="auto" || sscanf( str, "auto %d", size )) ){
3698 if ( size > 0 ){
3699 write("Ungueltiger Wert! "
3700 "In Verbindung mit 'auto' sind nur negative Werte erlaubt.\n");
3701 return 1;
3702 }
3703
3704 SetProp( P_SCREENSIZE, size-1 );
3705
3706 write("Ok, Deine Zeilenzahl wird nun automatisch ermittelt (derzeit "+
3707 QueryProp(P_SCREENSIZE)+").\n"+
3708 break_string("Bitte beachte, dass dies nur einwandfrei "
3709 "funktioniert, wenn Dein Client Telnetnegotiations "
3710 "unterstuetzt (siehe auch \"hilfe telnegs\").") );
3711 return 1;
3712 }
3713
3714 if ( !str || str=="" || !sscanf( str, "%d", size ) || size < 0 || size > 100){
3715 write(break_string(
3716 sprintf("Mit dem Befehl 'zeilen <groesse>' kannst Du einstellen, "
3717 "wieviele Zeilen bei mehrseitigen Texten auf einmal ausgegeben "
3718 "werden. Die angegebene Groesse muss zwischen 0 und 100 liegen. "
3719 "Bei Groesse 0 wird einfach alles ausgegeben (ohne Pause). Mit "
3720 "der Einstellung 'auto' wird die Groesse automatisch ueber "
3721 "die Telnetnegotiations ermittelt (siehe auch 'hilfe telnegs'). "
3722 "Um nach einer Seite Text noch etwas Platz zu haben, kann man z.B. "
3723 "'zeilen auto -3' einstellen.\n"
3724 "Die Voreinstellung ist 20 Zeilen.\n"
3725 "Mit 'zeilen abs[olut]' und 'zeilen rel[ativ]' kannst Du fest"
3726 "legen, ob im Prompt bei langen Texten die aktuelle Zeilennummer "
3727 "oder eine prozentuale Angabe ausgegeben wird.\n"
3728 "Deine aktuelle Einstellung ist %d%s Zeilen (%s).",
3729 QueryProp(P_SCREENSIZE),
3730 Query(P_SCREENSIZE) < 0 ? " 'automatische'" : "",
3731 QueryProp(P_MORE_FLAGS) & E_ABS ? "absolut" : "relativ"),78,0,1));
3732 return 1;
3733 }
3734
3735 SetProp( P_SCREENSIZE, size );
3736
3737 printf( "Okay, Deine Zeilenzahl steht nun auf %d.\n", size );
3738 return 1;
3739}
3740
3741static int _query_screensize()
3742{
3743 int sz,rows;
3744
3745 if ( (sz=Query(P_SCREENSIZE)) >= 0 )
3746 return sz;
3747
3748 if ( !rows=QueryProp(P_TTY_ROWS) )
3749 return 0;
3750
3751 return (rows+=sz) >= 5 ? rows : 5;
3752}
3753
3754static int presay(string str)
3755{
3756 if (!str=_unparsed_args())
3757 write("Dein Presay ist jetzt geloescht.\n");
3758 else
3759 printf("Dein Presay lautet jetzt: \"%s\".\n",str=capitalize(str));
3760 SetProp(P_PRESAY,str);
3761 return 1;
3762}
3763
3764static int sethands(string str)
3765{
3766 mixed *hands;
3767
3768 if (!(str=_unparsed_args()))
3769 {
3770 write("sethands <message>\n");
3771 return 1;
3772 }
3773 if (str=="0")
3774 hands=RaceDefault(P_HANDS);
3775 if (!hands || !pointerp(hands))
3776 hands=Query(P_HANDS);
3777 hands[0]=" "+str;
3778 Set(P_HANDS,hands);
3779 write("Ok.\n");
3780 return 1;
3781}
3782
3783static int inform(string str)
3784{
3785 switch (str) {
3786 case "on":
3787 case "ein":
3788 case "an":
3789 if (Query(P_INFORMME))
3790 write("Das hattest Du schon so eingestellt.\n");
3791 else
3792 {
3793 write("Kuenftig wirst Du informiert, wenn jemand das "MUDNAME" verlaesst/betritt.\n");
3794 Set(P_INFORMME,1);
3795 }
3796 return 1;
3797 case "aus":
3798 case "off":
3799 if (!Query(P_INFORMME))
3800 write("Das hattest Du schon so eingestellt.\n");
3801 else
3802 {
3803 write("Ok.\n");
3804 Set(P_INFORMME,0);
3805 }
3806 return 1;
3807 case 0:
3808 write("Inform-Mode ist "+(Query(P_INFORMME)?"an":"aus")+"geschaltet.\n");
3809 return 1;
3810 }
3811 write("inform an oder inform aus, bitte.\n");
3812 return 1;
3813}
3814
3815void delayed_write(mixed *what)
3816{
3817 if (!pointerp(what)||!sizeof(what)||!pointerp(what[0]))
3818 return;
3819 tell_object(ME,what[0][0]);
3820 if (sizeof(what)>1&&sizeof(what[0])>1)
3821 call_out("delayed_write",what[0][1],what[1..]);
3822}
3823
3824void notify_player_change(string who, int rein, int invis)
3825{
3826 string *list,name;
3827 mixed mlist;
3828
3829 if (invis) name="("+who+")";
3830 else name=who;
3831
3832 if (Query(P_INFORMME))
3833 {
3834 if (rein)
3835 tell_object(ME,name+" ist gerade ins "MUDNAME" gekommen.\n");
3836 else
3837 tell_object(ME,name+" hat gerade das "MUDNAME" verlassen.\n");
3838 }
3839
3840 if(Query(P_WAITFOR_FLAGS) & (0x01))return ;
3841
3842 if(pointerp(list=Query(P_WAITFOR)) && sizeof(list) && member(list,who)!=-1)
3843 {
3844 if (!QueryProp(P_VISUALBELL))
3845 name+=sprintf("%c",7); // Char fuer Pieps an den String anhaengen.
3846 // Moechte der Spieler keine ASCII-Grafik sehen, wird diese Meldung ohne
3847 // Leerzeichen formatiert, so dass sie von Screenreadern vorgelesen wird.
3848 // Anderenfalls wuerde sie einzeln buchstabiert.
3849 if ( QueryProp(P_NO_ASCII_ART) )
3850 {
Bugfixe6503fb2025-02-21 18:44:47 +01003851 delayed_write( ({ ({ sprintf("%s IST JETZT %sDA!!!\n",
MG Mud User88f12472016-06-24 23:31:02 +02003852 name, (rein?"":"NICHT MEHR ")) }) }) );
3853 }
3854 else
3855 {
3856 delayed_write( ({ ({ sprintf("%s I S T J E T Z T %sD A !!!\n",
3857 name, (rein?"":"N I C H T M E H R ")) }) }) );
3858 }
3859 }
3860
3861 if (rein && (sizeof(mlist=QueryProp(P_WAITFOR_REASON))) &&
3862 (mappingp(mlist)) && (mlist[who]))
3863 Show_WaitFor_Reason(who,invis);
3864}
3865
3866static int erwarte(string str)
3867{
3868 string *list,*str1;
3869 mixed mlist;
MG Mud User88f12472016-06-24 23:31:02 +02003870
3871 if (!mappingp(mlist=QueryProp(P_WAITFOR_REASON)))
3872 mlist=([]);
3873 if (!pointerp(list=Query(P_WAITFOR)))
3874 list=({});
3875
3876 if (!str || str=="-u")
3877 {
3878 if(Query(P_WAITFOR_FLAGS)&0x01)
3879 write("Du hast 'erwarte' temporaer deaktiviert.\n");
3880 write("Du erwartest jetzt");
3881 if (!sizeof(list))
3882 write(" niemanden mehr.\n");
3883 else
3884 {
3885 write(":\n");
3886 if (!str) list=sort_array(list,#'>);
3887 More(break_string(CountUp(list),78));
3888 }
3889 return 1;
3890 }
3891 if(str=="aus"){
3892 Set(P_WAITFOR_FLAGS,Query(P_WAITFOR_FLAGS)|0x01);
3893 write("Erwarte ist jetzt deaktiviert.\n");
3894 return 1;
3895 }
3896 if(str=="an" || str=="ein"){
3897 Set(P_WAITFOR_FLAGS,Query(P_WAITFOR_FLAGS)&0xFE);
3898 write("Erwarte ist jetzt aktiv.\n");
3899 return 1;
3900 }
3901
3902 str1=explode(_unparsed_args()||""," ");
3903 if (sizeof(str1)==1)
3904 {
3905 if (str1[0]!="wegen")
3906 {
3907 str=capitalize(lower_case(str));
3908 if (member(list,str)!=-1)
3909 {
3910 SetProp(P_WAITFOR_REASON,m_copy_delete(mlist,str));
3911 list-=({str});
3912 write(str+" aus der Liste entfernt.\n");
3913 } else
3914 {
3915 if (sizeof(list)>1000)
3916 {
3917 write("Du erwartest schon genuegend!\n");
3918 return 1;
3919 }
3920 list+=({str});
3921 write(str+" an die Liste angehaengt.\n");
3922 }
3923 Set(P_WAITFOR,list);
3924 }
3925 else
3926 {
Zesstraf253faa2018-07-27 13:05:13 +02003927 if (sizeof(mlist))
MG Mud User88f12472016-06-24 23:31:02 +02003928 {
3929 write("Du erwartest aus einem bestimmten Grund:\n");
Zesstraf253faa2018-07-27 13:05:13 +02003930 write(break_string(CountUp(sort_array(m_indices(mlist),
3931 #'>))+".",78));
MG Mud User88f12472016-06-24 23:31:02 +02003932 }
3933 else write("Du erwartest niemanden aus einem bestimmten Grund.\n");
3934 }
3935 return 1;
3936 }
3937 notify_fail("Falsche Syntax, siehe 'hilfe erwarte'!\n");
3938 if (str1[1]!="wegen") return 0;
3939 if (sizeof(str1)==2)
3940 Show_WaitFor_Reason(capitalize(lower_case(str1[0])),0);
3941 else {
3942 string s=capitalize(lower_case(str1[0]));
3943 if (sizeof(str1)==3 && (str1[2]=="nichts" || str1[2]=="loeschen"))
3944 if (!mlist[s])
3945 write("Du hast "+s+" aus keinem bestimmten Grund erwartet!\n");
3946 else
3947 {
3948 SetProp(P_WAITFOR_REASON,m_copy_delete(mlist,s));
3949 write("Du erwartest "+s+" aus keinem bestimmten Grund mehr!\n");
3950 }
3951 else
3952 {
Zesstra27649642018-07-27 12:59:25 +02003953 // Menge an erwarte-wegen Eintraegen begrenzen.
Zesstra5d9a0d72018-07-27 13:19:14 +02003954 int lim;
Zesstra27649642018-07-27 12:59:25 +02003955 if (IS_ARCH(ME)) lim=120;
3956 else if (IS_LEARNER(ME)) lim=80;
3957 else if (IS_SEER(ME)) lim=60;
3958 else lim=30;
3959 if (!mlist[s] && sizeof(mlist)>=lim)
MG Mud User88f12472016-06-24 23:31:02 +02003960 write("Sorry, aber Du erwartest schon genuegend Leute!\n");
3961 else
3962 {
Arathorn9b05bb42019-11-14 13:24:29 +01003963 // Meldung wieder zusammensetzen
3964 string meldung = implode(str1[2..], " ");
3965 // und Laenge auf 78 Zeichen abschneiden.
3966 meldung = sprintf("%.78s", meldung);
3967 m_add(mlist, s, meldung);
3968 SetProp(P_WAITFOR_REASON, mlist);
MG Mud User88f12472016-06-24 23:31:02 +02003969 Show_WaitFor_Reason(s,0);
3970 }
3971 }
3972 }
3973 return 1;
3974}
3975
3976static int uhrmeldung(string str)
3977{
3978 if (!(str=_unparsed_args()))
3979 {
3980 str=QueryProp(P_CLOCKMSG);
3981 if (!str)
3982 {
3983 write("Du hast die Standard-Uhrmeldung.\n");
3984 return 1;
3985 }
3986 if( !stringp(str) ) str = sprintf("%O\n",str);
3987 printf("Deine Uhrmeldung ist:\n%s\n",str[0..<2]);
3988 return 1;
3989 }
3990 if (str=="0")
3991 {
3992 SetProp(P_CLOCKMSG,0);
3993 write("Ok, Du hast jetzt wieder die Standard-Meldung.\n");
3994 return 1;
3995 }
3996 if (sizeof(explode(str,"%d"))>2)
3997 {
3998 write("Fehler, es darf nur ein %d in der Meldung vorkommen.\n");
3999 return 1;
4000 }
4001 /* Mehrere %-Parameter verursachen das Abschalten der Uhr zur vollen Stunde.
4002 */
4003 if (sizeof(explode(str,"%"))>2)
4004 {
4005 write("Fehler: Zuviele %-Parameter in der Meldung.\n");
4006 return 1;
4007 }
4008 /* Nur ein %-Parameter, aber der falsche: nicht sinnvoll. */
4009 else
4010 {
4011 int i = strstr(str,"%",0);
4012 if ( i>-1 && ( i==sizeof(str)-1 || str[i+1]!='d'))
4013 {
4014 write("Fehler: Falscher %-Parameter in der Meldung.\n");
4015 return 1;
4016 }
4017 }
4018 str+="\n";
4019 SetProp(P_CLOCKMSG,str);
4020 write("Ok.\n");
4021 return 1;
4022}
4023
4024static int zeitzone(string str)
4025{
4026 int zt;
4027 if(!str || str==""){
4028 if(!(zt=QueryProp(P_TIMEZONE)))
4029 write("Du hast derzeit die gleiche Zeitzone wie das "MUDNAME" "+
4030 "eingestellt.\n");
4031 else if(zt>0)
4032 printf("Deine Zeitzone ist auf %d Stunden vor (oestlich) von Berlin "+
4033 "eingestellt.\n",zt);
4034 else
4035 printf("Deine Zeitzone ist auf %d Stunden nach (westlich) von "+
4036 "Berlin eingestellt.\n",-zt);
4037 return 1;
4038 }
4039 if(sscanf(str,"utc %d",zt)==1) zt=(zt-1)%24;
4040 else zt=to_int(str)%24;
4041
4042 SetProp(P_TIMEZONE,zt);
4043
4044 if(!zt)
4045 write("Du hast derzeit die gleiche Zeitzone wie das "MUDNAME" "+
4046 "eingestellt.\n");
4047 else if(zt>0)
4048 printf("Deine Zeitzone ist auf %d Stunden vor (oestlich) von Berlin "+
4049 "eingestellt.\n",zt);
4050 else
4051 printf("Deine Zeitzone ist auf %d Stunden nach (westlich) von "+
4052 "Berlin eingestellt.\n",-zt);
4053 return 1;
4054}
4055
4056static int emailanzeige(string str){
4057 notify_fail("Syntax: emailanzeige [alle|freunde|niemand]\n");
4058 if(!str || str==""){
4059 if(!(str=QueryProp(P_SHOWEMAIL)))str="Niemandem";
4060 else if(str=="alle")str="allen";
4061 else if(str=="freunde")str="Deinen Freunden";
4062 else if(str=="niemand")str="niemandem";
4063 else{
4064 SetProp(P_SHOWEMAIL,0);
4065 str="Niemandem";
4066 }
4067 write("Deine Email wird "+str+" angezeigt.\n");
4068 return 1;
4069 }
4070 else if(member(({"alle","freunde","niemand"}),str)==-1)return 0;
4071
4072 SetProp(P_SHOWEMAIL,str);
4073
4074 if(str=="alle")str="allen";
4075 else if(str=="freunde")str="Deinen Freunden";
4076 else str="niemandem";
4077 write("Deine Email wird "+str+" angezeigt.\n");
4078 return 1;
4079}
4080
4081static int zaubertraenke()
4082{
4083 More("/room/orakel"->TipListe());
4084 return 1;
4085}
4086
4087varargs static int angriffsmeldung(string arg) {
4088 if (arg=="ein" || arg=="an")
4089 SetProp(P_SHOW_ATTACK_MSG,1);
4090 else if (arg=="aus")
4091 SetProp(P_SHOW_ATTACK_MSG,0);
4092 if (QueryProp(P_SHOW_ATTACK_MSG))
4093 write("Du siehst saemtliche Angriffsmeldungen von Dir.\n");
4094 else
4095 write("Du siehst nur neue Angriffsmeldungen von Dir.\n");
4096 return 1;
4097}
4098
4099static mixed _query_localcmds()
4100{
4101 return ({({"zeilen","set_screensize",0,0}),
4102 ({"email","set_email",0,0}),
4103 ({"url","set_homepage",0,0}),
4104 ({"icq","set_icq",0,0}),
4105 ({"messenger", "set_messenger", 0, 0}),
4106 ({"ort","set_location",0,0}),
4107 ({"punkte","short_score",0,0}),
4108 ({"score","short_score",0,0}),
4109 ({"info","score",0,0}),
4110 ({"kurzinfo","very_short_score",0,0}),
4111 ({"quit","new_quit",0,0}),
4112 ({"ende","new_quit",0,0}),
4113 ({"disconnect","disconnect",0,0}),
4114 ({"schlaf","disconnect",1,0}),
MG Mud User88f12472016-06-24 23:31:02 +02004115 ({"toete","kill",0,0}),
4116 ({"angriffsmeldung","angriffsmeldung",0,0}),
4117 ({"passw","change_password",1,0}),
4118 ({"hilfe","help",1,0}),
4119 ({"selbstloeschung","self_delete",0,0}),
4120 ({"spielpause","spielpause",0,0}),
4121 ({"spieldauer","spieldauer",0,0}),
Arathorn3437e392016-08-26 22:41:39 +02004122 ({"idee","ReportError",0,0}),
4123 ({"typo","ReportError",0,0}),
4124 ({"bug","ReportError",0,0}),
MG Mud User88f12472016-06-24 23:31:02 +02004125 ({"fehler","fehlerhilfe",0,0}),
Arathorn3437e392016-08-26 22:41:39 +02004126 ({"md","ReportError",0,0}),
4127 ({"detail","ReportError",0,0}),
Bugfixa75344d2017-06-16 14:04:48 +02004128 ({"syntaxhinweis","ReportError",0,0}),
MG Mud User88f12472016-06-24 23:31:02 +02004129 ({"vorsicht","toggle_whimpy",0,0}),
4130 ({"stop","stop",0,0}),
4131 ({"kwho","kwho",0,0}),
4132 ({"kwer","kwho",0,0}),
4133 ({"kkwer","kkwho",0,0}),
4134 ({"kkwho","kkwho",0,0}),
4135 ({"who","who",0,0}),
4136 ({"wer","who",0,0}),
4137 ({"zeit","uhrzeit",0,0}),
4138 ({"uhrzeit","uhrzeit",0,0}),
4139 ({"weg","weg",0,0}),
4140 ({"wegmeldung", "wegmeldung", 0, 0}),
4141 ({"idlezeit", "idlezeit", 0, 0}),
4142 ({"finger","finger",0,0}),
4143 ({"muds","muds",0,0}),
4144 ({"emote","emote",0,0}),
4145 ({":","emote",1,0}),
4146 ({";","emote",1,0}),
4147 ({"remote","remote",0,SEER_LVL}),
4148 ({"r:","remote",1,0}),
4149 ({"r;","gremote",1,0}),
4150 ({"titel","set_title",0,0}),
4151 ({"review","review",0,SEER_LVL}),
4152 ({"setmin","setmin",0,SEER_LVL}),
4153 ({"setmout","setmout",0,SEER_LVL}),
4154 ({"setmmin","setmmin",0,SEER_LVL}),
4155 ({"setmmout","setmmout",0,SEER_LVL}),
4156 ({"sethands","sethands",0,SEER_LVL}),
4157 ({"presay","presay",0,SEER_LVL}),
4158 ({"extralook","extralook",0,SEER_LVL}),
4159 ({"fluchtrichtung","toggle_whimpy_dir",0,SEER_LVL}),
4160 ({"inform","inform",0,0}),
4161 ({"erwarte","erwarte",0,0}),
4162 ({"stty","stty",0,0}),
4163 ({"grafik", "set_ascii_art", 0, 0}),
4164 ({"uhrmeldung","uhrmeldung",0,0}),
4165 ({"zeitzone","zeitzone",0,0}),
4166 ({"behalte","behalte",0,0}),
4167 ({"zweitiemarkierung","zweitiemarkierung",0,0}),
4168 ({"emailanzeige","emailanzeige",0,0}),
4169 ({"topliste","topliste",0,0}),
4170 ({"ton","set_visualbell",0,0}),
4171 ({"telnegs","show_telnegs",0,0}),
4172 ({"spotte", "spotte", 0, 0}),
4173 ({"reise","reise",0,0}),
4174 ({"zaubertraenke","zaubertraenke",0,0}),
4175 ({"telnet","telnet_cmd",0,0}),
4176 })+
4177 command::_query_localcmds()+
4178 viewcmd::_query_localcmds()+
4179 comm::_query_localcmds()+
4180 skills::_query_localcmds()+
4181 description::_query_localcmds();
4182}
4183
4184static int _check_keep(object ob)
4185{
4186 return (ob->QueryProp(P_KEEP_ON_SELL))==geteuid(ME);
4187}
4188
4189static mixed _set_testplayer(mixed arg) {
4190 mixed res;
4191 object setob;
4192
4193 setob=this_player();
4194 if (!objectp(setob) || !query_once_interactive(setob))
4195 setob=this_interactive();
4196 if (!objectp(setob))
4197 setob=previous_object();
4198 if (setob && !IS_DEPUTY(setob)) {
4199 arg=geteuid(setob);
4200 if (!arg || arg=="NOBODY")
4201 arg=getuid(setob);
4202 arg=capitalize(arg);
4203 }
4204 res=Set(P_TESTPLAYER,arg);
4205 Set(P_TESTPLAYER,PROTECTED,F_MODE_AS);
4206 return res;
4207}
4208
4209int zweitiemarkierung(string arg)
4210{
4211 if (!QueryProp(P_SECOND))
4212 return _notify_fail("Aber Du bist doch gar kein Zweiti.\n"),0;
4213 notify_fail("Syntax: zweitiemarkierung [unsichtbar|sichtbar|name]\n");
4214 if (!arg)
4215 return 0;
4216 switch (arg)
4217 {
4218 case "unsichtbar" :
4219 SetProp(P_SECOND_MARK,-1);
4220 write("Jetzt sieht kein Spieler mehr, dass Du ein Zweiti bist.\n");
4221 return 1;
4222 case "sichtbar" :
4223 SetProp(P_SECOND_MARK,0);
4224 write("Jetzt sieht kein Spieler mehr, wessen Zweiti Du bist.\n");
4225 return 1;
4226 case "name" :
4227 SetProp(P_SECOND_MARK,1);
4228 write("Jetzt koennen alle sehen, wessen Zweiti Du bist.\n");
4229 return 1;
4230 }
4231 return 0;
4232}
4233
4234int topliste(string arg)
4235{
4236 if (!arg)
4237 {
4238 printf("Du hast Dich fuer die Topliste %s.\n",
4239 (QueryProp(P_NO_TOPLIST) ? "gesperrt" : "freigegeben"));
4240 return 1;
4241 }
4242 else if (member(({"j","ja","n","nein"}),arg)==-1)
4243 return _notify_fail("Syntax: topliste [ja|nein]\n"),0;
4244 if (arg[0]=='j')
4245 {
4246 SetProp(P_NO_TOPLIST,0);
4247 write("Du kannst jetzt (theoretisch) in der Topliste auftauchen.\n");
4248 }
4249 else
4250 {
4251 SetProp(P_NO_TOPLIST,1);
Zesstradd2d1982017-01-28 14:03:19 +01004252 "/secure/topliste"->DeletePlayer();
4253 write("Du wirst jetzt nicht (mehr) in den Toplisten auftauchen.\n");
MG Mud User88f12472016-06-24 23:31:02 +02004254 }
4255 Set(P_NO_TOPLIST,SAVE|PROTECTED,F_MODE_AS);
4256 return 1;
4257}
4258
4259int show_telnegs(string arg)
4260{
4261 if (!arg)
4262 {
4263 write("Du bekommst Aenderungen Deiner Fenstergroesse "+
4264 (QueryProp(P_TTY_SHOW)?"":"nicht ")+"angezeigt.\n");
4265 return 1;
4266 }
4267 if (member(({"ein","an","aus"}),arg)==-1)
4268 {
4269 write("Syntax: telnegs [ein|aus]\n");
4270 return 1;
4271 }
4272 if (arg=="ein" || arg=="an")
4273 {
4274 write("Du bekommst "+(QueryProp(P_TTY_SHOW)?"":"nun ")+
4275 "Aenderungen Deiner Fenstergroesse angezeigt.\n");
4276 Set(P_TTY_SHOW,1);
4277 return 1;
4278 }
4279 write("Du bekommst "+(QueryProp(P_TTY_SHOW)?"nun ":"")+
4280 "Aenderungen Deiner Fenstergroesse nicht "+
4281 (QueryProp(P_TTY_SHOW)?"mehr ":"")+"angezeigt.\n");
4282 Set(P_TTY_SHOW,0);
4283 return 1;
4284}
4285
4286private int set_keep_alive(string str) {
4287 if (str == "ein") {
Zesstra268e3fd2019-07-25 14:29:01 +02004288 telnet_tm_counter = QueryProp(P_TELNET_KEEPALIVE_DELAY) || (240 / __HEART_BEAT_INTERVAL__);
4289 tell_object(this_object(), break_string( sprintf(
4290 "An Deinen Client werden jetzt alle %i Sekunden unsichtbare Daten "
MG Mud User88f12472016-06-24 23:31:02 +02004291 "geschickt, um zu verhindern, dass Deine Verbindung zum "MUDNAME
Zesstra268e3fd2019-07-25 14:29:01 +02004292 " beendet wird.",
4293 telnet_tm_counter*__HEART_BEAT_INTERVAL__), 78));
4294 // Bei Magiern ist der HB evtl. ausgeschaltet und muss eingeschaltet
4295 // werden.
4296 if (!object_info(this_object(), OC_HEART_BEAT))
4297 configure_object(this_object(), OC_HEART_BEAT, 1);
MG Mud User88f12472016-06-24 23:31:02 +02004298 }
4299 else if (str == "aus") {
4300 telnet_tm_counter = 0;
4301 tell_object(this_object(),break_string(
4302 "Du hast das Senden von unsichtbaren Daten (Keep-Alive-Pakete) an "
4303 "Deinen Client ausgeschaltet.",78));
4304 }
4305 else {
4306 if (!telnet_tm_counter)
4307 tell_object(this_object(), break_string(
4308 "An Deinen Client werden keine Keep-Alive-Pakete geschickt.",78));
4309 else
Bugfix5e832512022-10-26 17:13:07 +02004310 {
MG Mud User88f12472016-06-24 23:31:02 +02004311 tell_object(this_object(), break_string(
Bugfix5e832512022-10-26 17:13:07 +02004312 "An Deinen Client werden alle "
4313 + QueryProp(P_TELNET_KEEPALIVE_DELAY) * __HEART_BEAT_INTERVAL__
4314 + " Sekunden unsichtbare Daten geschickt, damit Deine Verbindung "
MG Mud User88f12472016-06-24 23:31:02 +02004315 "zum "MUDNAME" nicht beendet wird.",78));
Bugfix5e832512022-10-26 17:13:07 +02004316 }
MG Mud User88f12472016-06-24 23:31:02 +02004317 }
4318 return 1;
4319}
4320
4321private int print_telnet_rttime() {
4322 int rtt = QueryProp(P_TELNET_RTTIME);
4323 if (rtt>0)
4324 tell_object(ME, break_string(
4325 "Die letzte gemessene 'round-trip' Zeit vom MG zu Deinem Client "
4326 "und zurueck betrug " + rtt + " us.",78));
4327 else
4328 tell_object(ME, break_string(
4329 "Bislang wurde die 'round-trip' Zeit vom MG zu Deinem Client "
4330 "noch nicht gemessen oder Dein Client unterstuetzt dieses "
4331 "nicht.",78));
4332 return 1;
4333}
4334
Zesstra57cdbc32020-01-20 23:17:10 +01004335// Falls es eine per telnet vom Client ausgehandelte Einstellung fuer CHARSET
4336// gibt, hat die manuelle Einstellung von Spielern hier geringere Prioritaet
4337// und bildet nur den Fallback.
Zesstra9ab40222020-01-16 23:07:12 +01004338private int set_telnet_charset(string enc) {
Zesstra57cdbc32020-01-20 23:17:10 +01004339 struct telopt_s tdata = query_telnet_neg()[TELOPT_CHARSET];
Zesstra9ab40222020-01-16 23:07:12 +01004340 if (!sizeof(enc))
4341 {
Zesstra57cdbc32020-01-20 23:17:10 +01004342 if (!tdata->data || !tdata->data["accepted_charset"])
4343 {
4344 tell_object(ME, break_string(sprintf(
4345 "Zur Zeit ist der Zeichensatz \'%s\' aktiv. "
4346 "Alle Ausgaben an Dich werden in diesem Zeichensatz gesendet "
4347 "und wir erwarten alle Eingaben von Dir in diesem Zeichensatz. ",
4348 interactive_info(ME, IC_ENCODING)), 78));
4349 }
4350 else
4351 {
4352 tell_object(ME, break_string(sprintf(
Zesstra9ab40222020-01-16 23:07:12 +01004353 "Zur Zeit ist der Zeichensatz \'%s\' aktiv. "
4354 "Alle Ausgaben an Dich werden in diesem Zeichensatz gesendet "
4355 "und wir erwarten alle Eingaben von Dir in diesem Zeichensatz. "
Zesstra57cdbc32020-01-20 23:17:10 +01004356 "Dieser Zeichensatz wurde von Deinem Client ausgehandelt.",
4357 interactive_info(ME, IC_ENCODING)), 78));
4358 if (QueryProp(P_TELNET_CHARSET))
4359 tell_object(ME, break_string(sprintf(
4360 "Dein manuell eingestellter Zeichensatz ist \'%s\', welcher "
4361 "aber nur genutzt wird, wenn Dein Client keinen Zeichensatz "
4362 "aushandelt.", QueryProp(P_TELNET_CHARSET)),78));
4363
4364 }
Zesstra9ab40222020-01-16 23:07:12 +01004365 }
Zesstra57cdbc32020-01-20 23:17:10 +01004366 // Wenn es "loeschen" ist, wird die Prop genullt und wir stellen den Default
4367 // ein. Allerdings nur, wenn nix per telnet ausgehandelt wurde, dann wird
4368 // das beibehalten.
Zesstra9ab40222020-01-16 23:07:12 +01004369 else if (lower_case(enc) == "loeschen")
4370 {
4371 SetProp(P_TELNET_CHARSET, 0);
Zesstra57cdbc32020-01-20 23:17:10 +01004372 // wurde was per telnet option charset ausgehandelt? dann wird (weiterhin)
4373 // das genommen und nicht umgestellt.
4374 if (!tdata->data || !tdata->data["accepted_charset"])
4375 {
4376 configure_interactive(ME, IC_ENCODING, interactive_info(0,IC_ENCODING));
4377 tell_object(ME, break_string(sprintf(
Zesstra9ab40222020-01-16 23:07:12 +01004378 "Der Default \'%s\' wurde wieder hergestellt. "
4379 "Alle Ausgaben an Dich werden in diesem Zeichensatz gesendet "
4380 "und wir erwarten alle Eingaben von Dir in diesem Zeichensatz. "
4381 "Sollte Dein Client die Telnet-Option CHARSET unterstuetzen, kann "
Zesstra57cdbc32020-01-20 23:17:10 +01004382 "dieser allerdings direkt einen Zeichensatz aushandeln oder "
4383 "ausgehandelt haben, der dann stattdessen gilt.",
Zesstra9ab40222020-01-16 23:07:12 +01004384 interactive_info(ME, IC_ENCODING)), 78));
Zesstra57cdbc32020-01-20 23:17:10 +01004385 }
4386 else
4387 {
4388 tell_object(ME, break_string(sprintf(
4389 "Der Default \'%s\' wurde wieder hergestellt. Allerdings hat "
4390 "Dein Client mit dem MG den Zeichensatz \'%s\' ausgehandelt, "
4391 "welcher immer noch aktiv ist.",
4392 interactive_info(0, IC_ENCODING),
4393 interactive_info(ME, IC_ENCODING)), 78));
4394 }
Zesstra9ab40222020-01-16 23:07:12 +01004395 }
4396 else
4397 {
Zesstra57cdbc32020-01-20 23:17:10 +01004398 // Wenn der Zeichensatz keine //-Variante ist, machen wir den zu
Zesstra9ab40222020-01-16 23:07:12 +01004399 // einer. Das verhindert letztlich eine Menge Laufzeitfehler, wenn ein
4400 // Zeichen mal nicht darstellbar ist.
Zesstra57cdbc32020-01-20 23:17:10 +01004401 if (strstr(enc, "//") == -1)
Zesstra9ab40222020-01-16 23:07:12 +01004402 enc += "//TRANSLIT";
4403 if (catch(configure_interactive(ME, IC_ENCODING, enc); nolog))
4404 {
4405 tell_object(ME, break_string(sprintf(
4406 "Der Zeichensatz \'%s\' ist nicht gueltig oder zumindest auf "
4407 "diesem System nicht verwendbar.", enc),78));
4408 }
4409 else
4410 {
4411 SetProp(P_TELNET_CHARSET, interactive_info(ME, IC_ENCODING));
Zesstra57cdbc32020-01-20 23:17:10 +01004412 if (!tdata->data || !tdata->data["accepted_charset"])
4413 {
4414 tell_object(ME, break_string(sprintf(
Zesstra9ab40222020-01-16 23:07:12 +01004415 "Der Zeichensatz \'%s\' wurde eingestellt. Alle Ausgaben an "
4416 "Dich werden in diesem Zeichensatz gesendet und wir erwarten "
4417 "alle Eingaben von Dir in diesem Zeichensatz. Sollte Dein "
4418 "Client die Telnet-Option CHARSET unterstuetzen, kann "
4419 "dieser allerdings direkt einen Zeichensatz aushandeln, der "
4420 "dann stattdessen gilt.",
4421 interactive_info(ME, IC_ENCODING)),78));
Zesstra57cdbc32020-01-20 23:17:10 +01004422 }
4423 else
4424 {
4425 // Der via telnet ausgehandelte Charset muss wieder hergestellt
4426 // werden.
4427 configure_interactive(ME, IC_ENCODING,
4428 tdata->data["accepted_charset"]);
4429 tell_object(ME, break_string(sprintf(
4430 "Der Zeichensatz \'%s\' wurde gespeichert. Allerdings hat "
4431 "Dein Client mit dem MG den Zeichensatz \'%s\' ausgehandelt, "
4432 "welcher immer noch aktiv ist.",
4433 QueryProp(P_TELNET_CHARSET),
4434 interactive_info(ME, IC_ENCODING)), 78));
4435 }
Zesstra9ab40222020-01-16 23:07:12 +01004436 }
Zesstra57cdbc32020-01-20 23:17:10 +01004437
Zesstra9ab40222020-01-16 23:07:12 +01004438 }
4439 return 1;
4440}
4441
MG Mud User88f12472016-06-24 23:31:02 +02004442int telnet_cmd(string str) {
4443 if (!str) return 0;
4444 string *args = explode(str, " ");
4445 string newargs;
4446 if (sizeof(args) > 1)
4447 newargs = implode(args[1..], " ");
4448 else
4449 newargs = "";
4450
4451 switch(args[0])
4452 {
4453 case "keepalive":
4454 return set_keep_alive(newargs);
4455 case "rttime":
4456 return print_telnet_rttime();
Zesstra9ab40222020-01-16 23:07:12 +01004457 case "charset":
4458 return set_telnet_charset(newargs);
Zesstraab567652019-01-15 00:20:05 +01004459 case "tls":
Zesstra035bc7b2021-07-06 22:24:32 +02004460#if __EFUN_DEFINED__(tls_query_connection_state)
Zesstra363b1382019-01-15 00:36:24 +01004461 if (tls_query_connection_state(ME) > 0)
Zesstraab567652019-01-15 00:20:05 +01004462 tell_object(ME,
4463 "Deine Verbindung zum Morgengrauen ist TLS-verschluesselt.\n");
4464 else
Zesstra035bc7b2021-07-06 22:24:32 +02004465#endif
Zesstraab567652019-01-15 00:20:05 +01004466 tell_object(ME,
4467 "Deine Verbindung zum Morgengrauen ist nicht verschluesselt.\n");
4468 return 1;
Zesstrac7723982021-06-10 23:13:16 +02004469 case "client-gui":
Zesstra57e78832022-11-11 22:55:04 +01004470 case "gui":
Zesstrac7723982021-06-10 23:13:16 +02004471 GMCP_offer_clientgui(newargs);
4472 return 1;
MG Mud User88f12472016-06-24 23:31:02 +02004473 }
4474 return 0;
4475}
4476
4477int spotte( string str )
4478{
4479 _notify_fail( "Hier ist nichts, was Du verspotten koenntest!\n" );
4480 return 0;
4481}
4482
4483int behalte(string str)
4484{
4485 object ob,*obs;
4486 string s;
4487
4488 if (str)
4489 {
4490 if (str=="alles") {
4491 filter_objects(all_inventory(), "SetProp", P_KEEP_ON_SELL, getuid());
4492 write("Ok!\n");
4493 return 1;
4494 }
4495 if (str=="nichts") {
4496 filter_objects(all_inventory(), "SetProp", P_KEEP_ON_SELL, 0);
4497 write("Ok!\n");
4498 return 1;
4499 }
Arathorndfbf8d22021-03-25 21:17:10 +01004500 if (!sizeof(obs=find_obs(str,PUT_GET_DROP)))
MG Mud User88f12472016-06-24 23:31:02 +02004501 {
4502 _notify_fail("Aber sowas hast Du nicht dabei!\n");
4503 return 0;
4504 }
4505 else ob=obs[0];
4506
4507 if (ob->QueryProp(P_KEEP_ON_SELL)==geteuid(ME))
4508 ob->SetProp(P_KEEP_ON_SELL,0);
4509 else
4510 ob->SetProp(P_KEEP_ON_SELL,geteuid(ME));
4511
4512 // erneut abfragen, da sich der Wert nicht geaendert haben muss
4513 if (ob->QueryProp(P_KEEP_ON_SELL)==geteuid(ME))
4514 write(break_string(sprintf("Ok, Du wirst %s jetzt bei 'verkaufe alles' "
4515 "behalten.\n",ob->name(WEN)),78));
4516 else
4517 write(break_string(sprintf("Ok, Du wirst %s beim naechsten 'verkaufe "
4518 "alles' mitverkaufen!\n",ob->name(WEN)),78));
4519
4520 return 1;
4521 }
4522 s=make_invlist(ME,filter(all_inventory(ME),#'_check_keep)); //'));
4523 More(s);
4524 return 1;
4525}
4526
4527static int _query_lep()
4528{
4529 int val;
4530 val = LEPMASTER->QueryLEP();
4531 Set( P_LEP, val );
4532 return val;
4533}
4534
4535static mixed _set_fraternitasdonoarchmagorum(mixed arg)
4536{
4537 if (!intp(arg)) return -1;
4538
4539 if ((!previous_object(1)||object_name(previous_object(1))!=FAO_MASTER) &&
4540 (!this_interactive() || !IS_ARCH(this_interactive())))
4541 return -1;
4542
4543 if (!intp(arg)) return -1;
4544
4545 log_file("fao/P_FAO",sprintf("%s - %s P_FAO gesetzt auf %O\n",
4546 dtime(time()),query_real_name(),arg) );
4547 return Set(P_FAO,arg);
4548}
4549
Zesstraca502032020-02-05 19:56:09 +01004550nomask public string set_realip(string str)
MG Mud User88f12472016-06-24 23:31:02 +02004551{
Zesstraca502032020-02-05 19:56:09 +01004552 if(previous_object()
4553 && strstr(object_name(previous_object()),"/secure")==0)
MG Mud User88f12472016-06-24 23:31:02 +02004554 {
4555 realip=str;
4556 }
Zesstraca502032020-02-05 19:56:09 +01004557 return realip;
MG Mud User88f12472016-06-24 23:31:02 +02004558}
4559
Zesstraca502032020-02-05 19:56:09 +01004560nomask public string query_realip()
MG Mud User88f12472016-06-24 23:31:02 +02004561{
Zesstraca502032020-02-05 19:56:09 +01004562 return realip ? realip : 0;
MG Mud User88f12472016-06-24 23:31:02 +02004563}
4564
4565mixed _query_netdead_env() {
4566 return ndead_location || ndead_l_filename;
4567}