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