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