blob: e83930eb2613a8f5eaaf31828f67d3e93abae3b9 [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 {
Zesstra7fd01782019-02-04 21:54:40 +01001016 write("Das hat nicht hingehauen (Jof sei Dank ....)\n");
MG Mud User88f12472016-06-24 23:31:02 +02001017 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]);
Zesstra6da96cc2019-06-12 23:32:21 +02001332 if (obnam == "hier" || obnam == "raum")
1333 obj = environment(this_player());
1334 else
1335 {
1336 // Und das Objekt suchen, dabei zuerst im env() schauen. Nur present()
1337 // ginge auch, wuerde aber zuerst im Inv suchen, was aber nicht
1338 // gewuenscht ist.
1339 obj = present(obnam, environment(this_object())) || present(obnam);
1340 }
Arathorn3437e392016-08-26 22:41:39 +02001341
1342 // Wenn das Objekt gefunden wird, wird nur der Teil hinter dem ersten
1343 // : rekonstruiert und als Fehlermeldung abgesetzt.
1344 // Gibt es ein solches Objekt nicht, wird der Raum als Fallback
1345 // verwendet. Die Eingabe vor dem : gehoerte dann offenbar zur Meldung
1346 // dazu, und es wird dann spaeter die gesamte Spielereingabe im Original
1347 // als Fehlermeldung abgesetzt.
1348 if ( objectp(obj) )
1349 player_input = implode(input_segments[1..],":");
1350 else
1351 obj = environment(this_object());
1352 }
1353 else
1354 {
1355 // Hat der Spieler keinen : verwendet, verwenden wir das Bezugsobjekt
1356 // oder den aktuellen Raum.
1357 obj = QueryProp(P_REFERENCE_OBJECT);
1358 if (!objectp(obj) || !present(obj))
1359 obj = environment(this_interactive());
1360 }
1361 _notify("Vielen Dank fuer die Hilfe.\n", MA_UNKNOWN);
1362 smart_log(error_type, player_input, obj);
MG Mud User88f12472016-06-24 23:31:02 +02001363 }
Arathorn3437e392016-08-26 22:41:39 +02001364 else
1365 _notify("Eingabe abgebrochen.\n", MA_UNKNOWN);
MG Mud User88f12472016-06-24 23:31:02 +02001366 return 1;
1367}
1368
Arathorn3437e392016-08-26 22:41:39 +02001369static int ReportError(string player_input)
1370{
1371 // ungeparstes Kommando einlesen, um die Meldung unmodifiziert zu erhalten
1372 player_input = _unparsed_args(0);
1373 string pl_msg, error_type;
MG Mud User88f12472016-06-24 23:31:02 +02001374
Arathorn3437e392016-08-26 22:41:39 +02001375 // Anhand des eingegebenen Kommandoverbs wird der Typ der Fehlermeldung
1376 // ermittelt.
1377 switch(query_verb())
1378 {
1379 case "idee":
1380 pl_msg = "Was fuer eine Idee hast Du denn?\n";
1381 error_type = "IDEA";
1382 break;
1383 case "md":
1384 case "detail":
1385 pl_msg = "Fuer welches Detail fehlt denn die Beschreibung?\n";
1386 error_type = "DETAILS";
1387 break;
1388 case "typo":
1389 pl_msg = "Wo ist denn der Tippfehler?\n";
1390 error_type = "TYPO";
1391 break;
1392 case "bug":
1393 pl_msg = "Wie sieht der Fehler denn aus?\n";
1394 error_type = "BUGS";
1395 break;
Bugfixa75344d2017-06-16 14:04:48 +02001396 case "syntaxhinweis":
1397 pl_msg = "Mit welcher Syntax gibt es denn was fuer Probleme?\n";
1398 error_type = "SYNTAX";
1399 break;
MG Mud User88f12472016-06-24 23:31:02 +02001400 }
MG Mud User88f12472016-06-24 23:31:02 +02001401
Arathorn3437e392016-08-26 22:41:39 +02001402 // Hat der Spieler etwas eingegeben, wird die Eingabe direkt an die Hilfs-
1403 // funktion weitergereicht. Ansonsten wird eine Meldung ausgegeben und die
1404 // Eingabe manuell per input_to() abgefragt.
1405 if ( stringp(player_input) && sizeof(player_input) )
1406 {
1407 return ReportError2(player_input, error_type);
MG Mud User88f12472016-06-24 23:31:02 +02001408 }
Arathorn3437e392016-08-26 22:41:39 +02001409 ReceiveMsg(pl_msg, MT_NOTIFICATION);
1410 input_to("ReportError2", INPUT_PROMPT, "]", error_type);
MG Mud User88f12472016-06-24 23:31:02 +02001411 return 1;
1412}
1413
1414/** Loggt eine Spielermeldung an Magier.
1415 * Loggt die Spielermeldung in das passende File unter /log/report/ oder im
1416 * vom Magier gewuenschten File. Hierbei werden Fehler, Ideen, MDs und Typos
1417 * in getrennte Files sortiert.
1418 * \param[in] str Spielermeldung
1419 * \param[in] myname Art der Spielermeldung (DETAILS, BUG, TYPO, MD)
1420 * @see md(string), idea(string), bug(string), typo(string)
1421 */
Arathorn3437e392016-08-26 22:41:39 +02001422void smart_log(string myname, string str, object obj)
MG Mud User88f12472016-06-24 23:31:02 +02001423{
MG Mud User88f12472016-06-24 23:31:02 +02001424 mapping err = ([ F_PROG: "unbekannt",
1425 F_LINE: 0,
1426 F_MSG: str,
1427 F_OBJ: obj
1428 ]);
1429
1430 string desc="etwas unbekanntes";
1431 switch(myname) {
1432 case "BUGS":
1433 desc="einen Fehler";
1434 err[F_TYPE]=T_REPORTED_ERR;
1435 break;
1436 case "DETAILS":
1437 desc="ein fehlendes Detail";
1438 err[F_TYPE]=T_REPORTED_MD;
1439 break;
1440 case "IDEA":
1441 desc="eine Idee";
1442 err[F_TYPE]=T_REPORTED_IDEA;
1443 break;
1444 case "TYPO":
1445 desc="einen Typo";
1446 err[F_TYPE]=T_REPORTED_TYPO;
1447 break;
Bugfixa75344d2017-06-16 14:04:48 +02001448 case "SYNTAX":
1449 desc="einen Syntaxhinweis";
1450 err[F_TYPE]=T_REPORTED_SYNTAX;
1451 break;
MG Mud User88f12472016-06-24 23:31:02 +02001452 }
1453
1454 // Eintragung in die Fehler-DB
1455 string hashkey = (string)ERRORD->LogReportedError(err);
1456
1457 // ggf. will das Objekte mit noch irgendwas anfangen.
1458 obj->SmartLog(0, myname, str, strftime("%d. %b %Y"));
1459
1460 tell_object(this_object(), break_string( sprintf(
1461 "Du hast an %s erfolgreich %s abgesetzt.\n"
1462 "Die ID der abgesetzten Meldung lautet: %s\n",
1463 (obj->IsRoom() ? "diesem Raum" : obj->name(WEM,1)),desc,
1464 hashkey||"N/A"),78,BS_LEAVE_MY_LFS));
1465}
1466
1467/** Speichert den Spieler und loggt ihn aus (Spielerkommando 'ende').
1468 * Der Spieler wird vollstaendig ausgeloggt, d.h. das Spielerobjekt
1469 * zerstoert.
1470 * \return 1 bei Erfolg, 0 sonst.
1471 * @see disconnect()
1472 */
1473int quit()
1474{
1475 int arg;
1476 SetProp(P_LAST_QUIT,time());
1477 catch(RemoveChannels();publish);
1478 if(!QueryGuest())
1479 {
1480 save_me(0);
1481 tell_object(ME,"Speichere "+QueryProp(P_NAME)+".\n");
1482 }
1483
1484 if (interactive(ME))
1485 call_notify_player_change(0);
1486
1487 remove_living_name();
1488 // EVT_LIB_LOGOUT wird in remove() getriggert.
1489 if(catch(remove();publish)) destruct(ME);
1490 return 1;
1491}
1492
1493/** Wrapper im quit() herum, verhindert 'ende', falls Spieler kaempft.
1494 * \return 0 oder Rueckgabewert von quit()
1495 * @see quit()
1496 */
1497static int new_quit() {
1498 notify_fail("Du bist in Gedanken noch bei Deinem letzten Kampf.\n"+
1499 "Warte noch etwas bevor Du das Spiel verlaesst,\n"+
1500 "damit Du so nicht in RL weitermachst...\n");
1501 if (time()-Query(P_LAST_COMBAT_TIME)<120 && !IS_LEARNING(ME))
1502 return 0;
1503 return quit();
1504}
1505
1506/** Gibt die Infos ueber den Char an den Spieler aus (Spielerkommando 'info').
1507 * \param[in] arg Wenn arg=="short", wird eine Kurzuebersicht ausgegeben.
1508 * \return 1
1509 * @see short_score()
1510 */
1511static int score(string arg) {
1512 string tmp, gender;
1513 int i,sz,val;
1514 mixed ind;
1515 object *enem1, *enem2, *inv;
1516
1517 if (QueryProp(P_GHOST)) {
1518 write("Im ewigen Leben gibt es keine Punkte.\n");
1519 return 1;
1520 }
1521
1522 int plev = LEPMASTER->QueryLevel();
1523
1524 switch(tmp = QueryProp(P_GENDER)) {
1525 case MALE: gender = "maennlich"; break;
1526 case FEMALE: gender = "weiblich"; break;
1527 case NEUTER: gender = "neutral"; break;
1528 default: gender = lower_case(tmp);
1529 }
1530
1531 ind = m_indices(QueryProp(P_ATTRIBUTES));
1532 tmp = "";
1533 foreach(string index: ind) {
1534 string aname;
1535 switch (index) {
1536 case "int": aname = "Intelligenz"; break;
1537 case "con": aname = "Ausdauer"; break;
1538 case "dex": aname = "Geschicklichkeit"; break;
1539 case "str": aname = "Kraft"; break;
1540 default:
1541 if(stringp(index)) aname = capitalize(index);
1542 else aname = "Unbekannt";
1543 }
1544 aname = sprintf("%-18'.'s %2.2d", aname+" ", QueryRealAttribute(index));
1545 if((val = QueryAttributeOffset(index)))
1546 aname += sprintf(" (%s%d)", (val>=0?"+":""), val);
1547 tmp += aname + "\n";
1548 }
1549
1550 printf("- %-'-'68s\n",
1551 TeamPrefix()+capitalize(implode(explode(short()||"","\n"),""))+" ");
1552 if(arg!="short") {
1553 printf("Rasse ............ %-' '18s Abenteuer ........ %d %s\n",
1554 QueryProp(P_RACE), QueryProp(P_QP),
1555 (val = QM->QueryTotalQP()) == QueryProp(P_QP) ? "" : "("+val+")");
1556 printf("Geschlecht ....... %-' '18s Groesse .......... %d cm\n",
1557 gender, QueryProp(P_SIZE));
1558 printf("Stufe ............ %-3.3d %-' '14s Gewicht .......... %d kg\n",
1559 QueryProp(P_LEVEL), (QueryProp(P_LEVEL) < plev ? "("+plev+")" : ""),
1560 QueryProp(P_WEIGHT) / 1000);
1561 printf("Gilde ............ %-' '18s Gildenstufe ...... %d\n",
1562 capitalize(QueryProp(P_GUILD)), QueryProp(P_GUILD_LEVEL));
1563 }
1564 printf("Erfahrung ........ %-' '18s Charakter ........ %-s\n\n",
1565 QueryProp(P_XP)+ " Punkte", al_to_title(QueryProp(P_ALIGN)));
1566 printf("%#-76.2s\n\n", tmp);
1567 printf("Gesundheit ....... %-3.3d %-' '14s Gift ............. %s\n",
1568 QueryProp(P_HP),
1569 (QueryProp(P_HP) == (val = QueryProp(P_MAX_HP)) ? "" : "("+val+")"),
1570 ((val = QueryProp(P_POISON)) ?
1571 (val < 4 ? "leicht" : "gefaehrlich") : "gesund"));
1572 printf("Konzentration .... %-3.3d %-' '14s Vorsicht ......... %s\n",
1573 QueryProp(P_SP),
1574 (QueryProp(P_SP) == (val = QueryProp(P_MAX_SP)) ? "" : "("+val+")"),
1575 ((ind = QueryProp(P_WIMPY)) ? ""+ind : "mutig"));
1576 printf("Todesfolgen....... %-' '18s %s\n",
1577 ((val = death_suffering()) ? ""+((val+9)/10) : "kein Malus"),
1578 (QueryProp(P_WIMPY) && ind=QueryProp(P_WIMPY_DIRECTION))
1579 ? sprintf("Fluchtrichtung ... %O", ind) : "");
1580 printf("%s",
1581 (time()-Query(P_LAST_COMBAT_TIME)<120 && !IS_LEARNING(ME)) ?
1582 "Spiel verlassen .. nicht moeglich\n" : ""
1583 );
1584
1585 if(arg!="short") {
1586 write(break_string(Forschung(), 70));
1587 if(ind=QueryProp(P_AWAY))
1588 printf("Du bist nicht ansprechbar: %O\n",ind);
1589 }
1590
1591 if(sizeof(enem1=((mixed)QueryEnemies())[0])) {
1592 enem2=({});
1593 inv=all_inventory(environment(ME));
1594 foreach(object en: enem1) {
1595 if (member(inv,en)==-1) // Ist unser Feind und ist nicht hier
1596 enem2+=({en});
1597 }
1598 if(sizeof(enem2))
1599 {
1600 write(break_string(
1601 "Du verfolgst " + CountUp(map_objects(enem2, "name", WEN))+".",
1602 78));
1603 }
1604 }
1605 if(arg!="short") show_age();
1606 printf("%-'-'70s\n", "");
1607 return 1;
1608}
1609
1610/** Gibt eine kuerzere Info ueber den Char aus (Spielerkommando punkte|score).
1611 Ruft score("short").
1612 * \param[in] arg UNUSED
1613 * \return 1 bei Erfolg, 0 sonst.
1614 * @see score(string), very_short_score()
1615 */
1616static int short_score(string arg) {
1617 return score("short");
1618}
1619
1620/** Gibt eine Miniinfo ueber LP / KP aus (Spielerkommando: kurzinfo)
1621 * \return 1
1622 * @see score(string), short_score(string)
1623 */
1624static int very_short_score(string arg) {
1625 int lp,mlp,xlp,kp,mkp,xkp;
1626 string bar;
1627
1628 lp=QueryProp(P_HP); mlp=QueryProp(P_MAX_HP);
1629 kp=QueryProp(P_SP); mkp=QueryProp(P_MAX_SP);
1630 if (mlp)
1631 xlp=(lp*40/mlp);
1632 if (mkp)
1633 xkp=(kp*40/mkp);
1634 bar=" . . . . . . . . ";
1635 if (QueryProp(P_NO_ASCII_ART) || arg == "-k")
1636 printf("Gesundheit: %3.3d (%3.3d), Konzentration: %3.3d (%3.3d)\n",
1637 lp, mlp, kp, mkp);
1638 else
1639 printf("Gesundheit: 0 |%'#'40.40s| %3.3d%s\n"+
1640 "Konzentration: 0 |%'#'40.40s| %3.3d%s\n",
1641 (xlp<0?bar:bar[xlp..]),lp,(lp==mlp?"":sprintf(" (%d)",mlp)),
1642 (xkp<0?bar:bar[xkp..]),kp,(kp==mkp?"":sprintf(" (%d)",mkp))
1643 );
1644 return 1;
1645}
1646
1647/** Gibt eine Manpage/Hilfeseite an den Spieler aus.
1648 Beruecksichtigt hierbei die Synonymliste aus dir/.synonym, um die richtige
1649 Manpage auszugeben.
1650 * \param[in] dir Verzeichnis der gewuenschten Manpage
1651 * \param[in] page Name der gewuenschten Manpage
1652 * \return String der gewuenschten Manpage
1653 */
1654static string getmanpage(string dir, string page)
1655{
1656 string text, *syn;
1657 int i;
1658
1659 if (dir[<1] != '/')
1660 dir += "/";
1661
1662 if ((text=read_file(dir+page)) && sizeof(text))
1663 return text;
1664
1665 if (text = read_file(dir+".synonym")) {
1666 syn = regexplode(text, "([ \t][ \t]*|\n)");
1667 if ((i=member(syn, page))!=-1)
1668 return read_file(dir+syn[i+2]);
1669 }
1670 return 0;
1671}
1672
1673/** Gibt eine Hilfeseite an den Spieler aus (Spielerkommando hilfe|man).
1674 * Die Hilfeseite wird in div. Verzeichnissen gesucht (je nach Gilde,
1675 * Magier-/Spielerstatus).
1676 * \param[in] str Name der gewuenschten Hilfeseite.
1677 * \return 1
1678 */
1679static int help(string str) {
1680 string verb, rest, text, gilde;
1681 mixed found;
1682
1683 found=0;
1684 text = "";
1685 if (str) {
1686 str = implode( explode(str, ".." ), "");
1687
1688 if ( sscanf( str, "gilde %s %s", gilde, rest)==2)
1689 str=rest;
1690 else
1691 gilde=QueryProp(P_GUILD);
1692 if (!gilde) gilde="abenteurer";
1693
1694 if ( sscanf( str, "%s %s",verb,rest )==2 ) str = verb;
1695
1696 if ((IS_LEARNER(PL)) ) {
1697 if (rest = getmanpage("/doc/wiz/",str)) {
1698 found = 1;
1699 text += rest;
1700 }
1701 else if (rest = getmanpage("/doc/mcmd/", str)) {
1702 found = 1;
1703 text += rest;
1704 }
1705 }
1706
1707 if ((IS_SEER(PL)) /*&& !found*/ ) {
1708 if (rest = getmanpage("/doc/scmd/",str)) {
1709 if (found)
1710 text += "\n--------------------\n";
1711 found = 1;
1712 text += rest;
1713 }
1714 }
1715
1716 if (rest = getmanpage("/doc/g."+gilde+"/",str)) {
1717 if (found)
1718 text += "\n--------------------\n";
1719 found = 1;
1720 text += rest;
1721 } else {
1722 if (rest = getmanpage("/doc/help/",str)) {
1723 if (found)
1724 text += "\n--------------------\n";
1725 found = 1;
1726 text += rest;
1727 }
1728 else if (rest = getmanpage("/doc/pcmd/",str)) {
1729 if (found)
1730 text += "\n--------------------\n";
1731 found = 1;
1732 text += rest;
1733 }
1734 else if (rest = getmanpage("/doc/REGELN/",str)) {
1735 if (found)
1736 text += "\n--------------------\n";
1737 found = 1;
1738 text += rest;
1739 }
1740 }
1741
1742 if (!found)
1743 text = "Dazu ist keine Hilfe verfuegbar.\n";
1744
1745 More(text,0);
1746 return 1;
1747 }
1748 if (IS_LEARNER(PL))
1749 text = read_file("/doc/hilfe.magier");
1750 else if (IS_SEER(PL))
1751 text = read_file("/doc/hilfe.seher");
1752
1753 More(text + read_file("/doc/hilfe.spieler"), 0);
1754 return 1;
1755}
1756
1757/** Ermittelt angebene Optionen fuer das Spielerkommando 'wer'.
1758 * \param[in] str vom Spieler spezifizierter String von Filteroptionen: -k,
1759 * -v, -a, -s (+ Langformen).
1760 * \return Array von Spieleroptionen als veroderte Int-Flags und Rest der
1761 * Spielereingabe ohne die Optionen.
1762 */
1763static mixed filter_who_options(string str)
1764{
1765 string* opt, *ans;
1766 int i,len,res;
1767
1768 opt = explode(str," "); len=sizeof(opt);
1769 ans = ({});
1770 res = 0;
1771 for(i=0;i<len;i++)
1772 switch(opt[i]){
1773 case "-k":
1774 case "-kurz":
1775 res |= WHO_SHORT; break;
1776 case "-v":
1777 case "-vertikal":
1778 res |= WHO_VERTICAL; break;
1779 case "-alphabetisch":
1780 case "-a":
1781 case "-alpha":
1782 res |= WHO_ALPHA; break;
1783 case "-s":
1784 case "-spieler":
1785 res |= WHO_PLAYER_VIEW; break;
1786 default:
1787 return ({ res, implode(opt[i..]," ") });
1788 }
1789 return ({ res, 0 });
1790
1791}
1792
1793/** Spielerkommando 'wer', fragt /obj/werliste ab.
1794 * \param[in] str Spielereingabe mit Optionen fuer wer.
1795 * \return 1
1796 */
1797static int who(string str) {
1798 int i,shrt;
1799 string ret;
1800 mixed ans;
1801
1802 if ((str=_unparsed_args())&&str[0..0]!="-") {
1803 ans = filter_who_options(str);
1804 shrt = ans[0];
1805 str = ans[1];
1806 if (!shrt) {
1807 if (ret=INETD->_send_udp(str,
1808 ([ REQUEST: "who", SENDER: getuid(ME) ]), 1 ))
1809 write(ret);
1810 else
1811 write("Anfrage abgeschickt.\n");
1812 return 1;
1813 }
1814 }
1815 if (str) i=(member(str,'o')>0); else i=0;
1816 if (sizeof(str)>1 && str[0] == '-') str = str[1..1];
1817 More(implode( "/obj/werliste"->QueryWhoListe(
1818 IS_LEARNER(ME) && QueryProp(P_WANTS_TO_LEARN),shrt,0,str,i),"\n"),0);
1819 return 1;
1820}
1821
1822/** Spielerkommando 'kwer', fragt /obj/werliste ab.
1823 * \param[in] str Spielereingabe mit Optionen fuer wer.
1824 * \return 1
1825 */
1826static int kwho(string str)
1827{
1828 int shrt;
1829 mixed res;
1830
1831 if(str) {
1832 res = filter_who_options(str);
1833 shrt = res[0];
1834 str = res[1];
1835 }
1836 More(implode( "/obj/werliste"->QueryWhoListe(
1837 IS_LEARNER(ME) && QueryProp(P_WANTS_TO_LEARN), shrt|WHO_SHORT ,0,str),
1838 "\n")+"\n\n",0);
1839 return 1;
1840}
1841
1842/** Spielerkommando 'kkwer', gibt eine einfache Liste der Anwesenden aus.
1843 Filtert unsichtbare Spieler aus, falls SPielerobjekt kein Magier ist.
1844 * \param[in] str Spielereingabe mit Optionen fuer wer.
1845 * \return 1
1846 */
1847static varargs int kkwho(string str) {
1848 object *obs;
1849 string *namen;
1850
1851 obs=filter_users(str);
1852 namen=({});
1853 if (IS_LEARNER(this_player())) {
1854 foreach(object ob: obs) {
1855 if (environment(ob))
1856 namen+=({capitalize(geteuid(ob))});
1857 }
1858 }
1859 else {
1860 foreach(object ob: obs) {
1861 if (!ob->QueryProp(P_INVIS) && environment(ob))
1862 namen+=({capitalize(geteuid(ob))});
1863 }
1864 }
1865 if (sizeof(namen))
1866 write(break_string(CountUp(sort_array(namen,#'>),", ", ", ")+".",75));
1867 else
1868 write("Keine passenden Spieler gefunden.\n");
1869
1870 return 1;
1871}
1872
1873/** Spielerkommando 'toete'.
1874 * Prueft auf Geist, Gast, toten HC-Spieler, Waffe/freie Hand. Versucht einen
1875 * Gegner zu finden und ruft dann Kill(string).
1876 * \param[in] str Spielereingabe
1877 * \return 1 oder 0, falls kein potentieller Gegner bei 'toete alle' gefunden
1878 * wird.
1879 */
1880static int kill(string str) {
1881 object eob,wob;
1882
1883 if (QueryProp(P_GHOST))
1884 {
1885 write("Das kannst Du in Deinem immateriellen Zustand nicht.\n");
1886 return 1;
1887 }
1888
1889 if(hc_play>1)
1890 {
1891 write("DAS HAST DU HINTER DIR.\n");
1892 return 1;
1893 }
1894
1895 if (QueryGuest())
1896 {
1897 write("Du bist doch nur Gast hier.\n");
1898 return 1;
1899 }
1900 if (!str || str == "") {
1901 write("WEN willst Du toeten?\n");
1902 return 1;
1903 }
1904 if( !QueryProp(P_WEAPON) && QueryProp(P_FREE_HANDS)==0 ) {
1905 write(
1906 "Dazu solltest Du eine Waffe gezueckt oder eine Hand frei haben.\n");
1907 return 1;
1908 }
1909 str=lower_case(str);
1910 if (str=="alle") {
1911 object livs;
1912 livs=filter(all_inventory(environment(PL)),
1913 function int (object ob) {
1914 if (living(ob) && !query_once_interactive(ob)
1915 && !ob->QueryProp(P_INVIS)
1916 && !ob->QueryProp(P_NO_GLOBAL_ATTACK)
1917 && !ob->QueryProp(P_FRIEND))
1918 {
1919 Kill(ob);
1920 return 1;
1921 }
1922 return 0;
1923 } );
1924 // wenn Gegner gefunden, raus, ansonsten kommt die Fehlermeldung unten.
1925 if (sizeof(livs)) return 1;
1926 }
1927 else {
1928 int i=1;
1929 while(objectp(eob = present(str,i++,environment(PL)))) {
1930 if (living(eob) && !eob->QueryProp(P_INVIS))
1931 break;
1932 else
1933 eob=0;
1934 }
1935 }
1936 if (!objectp(eob)) {
1937 // per write und return 1 ist hier mal ok, weil dies Kommando im Spieler
1938 // eh zuletzt in der Kommandokette ausgefuehrt wird und per return 0 eh
1939 // kein anderes mehr zum Zug kommt.
1940 write("Du siehst hier kein derartiges Wesen!\n");
1941 return 1;
1942 }
1943 else if (eob == PL) {
1944 write("Selbstmord ist keine Loesung!\n");
1945 return 1;
1946 }
1947
1948 /* Kill him */
1949 Kill(eob);
1950 return 1;
1951}
1952
1953/** Spielerkommando 'stop'.
1954 * Loescht die Gegnerliste, sofern man nicht InFight() ist.
1955 * \param[in] str Spielereingabe, wird ignoriert.
1956 * \return 1
1957 */
1958static int stop( string str )
1959{
1960 if ( InFight() ){
1961 write( "Das geht nicht mitten im Kampf.\n" );
1962 return 1;
1963 }
1964
1965 if ( !str ){
1966 StopHuntingMode();
1967 write( "Ok.\n" );
1968 return 1;
1969 }
1970
1971 if ( !StopHuntID(str) )
1972 write( "So jemanden verfolgst Du nicht!\n" );
1973
1974 return 1;
1975}
1976
1977/** Spielerkommando fuers emoten ':'.
1978 * \param[in] str Spielereingabe
1979 * \param[in] genitiv Genetivflag
1980 * \return 1 oder 0, falls Spieler nicht emoten kann (kein CAN_EMOTE Flag in
1981 * P_CAN_FLAGS).
1982 */
1983int emote(string str,int genitiv)
1984{
1985 string *commands,message,verb;
1986 object living;
1987 int i,size;
1988
1989 if (!(Query(P_CAN_FLAGS)&CAN_EMOTE)) return 0;
1990 if (query_verb()[0]==';') genitiv=1;
1991 if (query_verb()[0]==':'||query_verb()[0]==';')
1992 verb=query_verb()[1..]+" ";
1993 else
1994 verb="";
1995 str=this_player()->_unparsed_args();
1996 commands=explode(verb+(str||""),"#");
1997 message=break_string((IS_SEER(ME) ? "" : ">")
1998 +capitalize(genitiv ? name(WESSEN) :
1999 name())
2000 +" "+commands[0],78);
2001 size=sizeof(commands);
2002 if(size>=3)
2003 {
2004 living=find_living(lower_case(commands[1]));
2005 if(!living || environment(living)!=environment() ||
2006 (living->QueryProp(P_INVIS)) && !IS_LEARNER(ME))
2007 {
2008 write(capitalize(commands[1])+" sehe ich hier nicht!\n");
2009 return 1;
2010 }
2011 if(living!=this_object())
2012 tell_object(living,break_string((IS_SEER(this_player()) ? "" : ">")
2013 +capitalize(genitiv ?
2014 this_player()->name(WESSEN) :
2015 this_player()->name())
2016 +" "+commands[2],78));
2017 }
2018 if(size>=4)
2019 write(break_string(commands[3],78));
2020 else
2021 write(message);
2022 tell_room(environment(),message,({this_object(),living}));
2023 return 1;
2024}
2025
2026/** Spielerkommando fuers remoten 'r:'.
2027 * \param[in] str Spielereingabe
2028 * \param[in] flag Genetivflag
2029 * \return 1 oder 0, falls Spieler nicht emoten kann (kein CAN_REMOTE Flag in
2030 * P_CAN_FLAGS).
2031 */
2032static int remote(string str, int flag)
2033{
2034 int m;
2035 string tmp, dest;
2036 string *exstr;
2037 object destpl;
2038
2039 if ( !(Query(P_CAN_FLAGS) & CAN_REMOTE) )
2040 return 0;
2041
2042 if ( !(str=_unparsed_args()) ||
2043 sizeof( (exstr=explode(str," ")) - ({""}) ) <= 1 ){
2044 write("Was willst Du zu wem `emoten`?\n");
2045 return 1;
2046 }
2047
2048 dest = lower_case(exstr[0]);
2049
2050 if( !(destpl=find_player( dest ) ) ||
2051 (destpl->QueryProp(P_INVIS) && !IS_LEARNER(ME)) ){
2052 write("Einen solchen Spieler gibt es derzeit nicht.\n");
2053 return 1;
2054 }
2055
2056 tmp = implode( exstr[1..], " " );
2057
2058 tmp = regreplace( tmp, "(^|[^#])#($|[^#])", "\\1aus der Ferne\\2", 1 );
2059 tmp = regreplace( tmp, "(^|[^\\^])\\^($|[^\\^])", "\\1in der Ferne\\2", 1 );
2060 tmp = regreplace( tmp, "##", "#", 1 );
2061 tmp = regreplace( tmp, "\\^\\^", "^", 1 );
2062
2063 if ( strstr( tmp, "aus der Ferne" ) == -1
2064 && strstr( tmp, "in der Ferne" ) == -1 )
2065 tmp += " aus der Ferne";
2066
2067 if ( QueryProp(P_INVIS) && IS_LEARNER(destpl) ){
2068 str = "(" + capitalize(getuid(ME));
2069 if ( flag )
2070 str += member( "sxz", str[<1] ) == -1 ? "s" : "'";
2071 str += ")";
2072 }
2073 else
2074 str = (flag ? capitalize(name(WESSEN)) : capitalize(name(WER)));
2075
2076 str += " " + tmp + (member( ".?!", tmp[<1] ) == -1 ? "." : "") + "\n";
2077
2078 m = destpl->ReceiveMsg(str, MT_COMM|MT_FAR, MA_EMOTE,0, ME);
2079 switch(m)
2080 {
2081 case MSG_DELIVERED:
Bugfix70d66a52017-03-06 14:27:35 +01002082 // Als origin muss der Empfaenger uebergeben werden, sonst kann die
2083 // Meldung in der tmhist nicht richtig zugeordnet werden.
Zesstra4eb67dc2016-12-17 19:56:31 +01002084 ReceiveMsg(capitalize(destpl->name()) + "->" + str, MT_COMM|MT_FAR,
Bugfix70d66a52017-03-06 14:27:35 +01002085 MA_EMOTE, 0, destpl);
MG Mud User88f12472016-06-24 23:31:02 +02002086 break;
2087 case MSG_BUFFERED:
2088 write( capitalize(destpl->name(WER) + " ist gerade beschaeftigt.\n") );
2089 break;
2090 case MSG_IGNORED:
2091 write( capitalize(destpl->name(WER) + " ignoriert Dich.\n") );
2092 break;
2093 case MSG_VERB_IGN:
2094 case MSG_MUD_IGN:
2095 write( capitalize(destpl->name(WER) + " ignoriert Deine Meldung.\n") );
2096 break;
2097 default:
2098 write( capitalize(destpl->name(WER) + " kann Dich gerade nicht "
2099 "wahrnehmen.\n") );
2100 }
2101 return 1;
2102}
2103
2104/** Spielerkommando fuers emoten im Genitiv ';'.
2105 * Ruft emote(string,int) auf.
2106 */
2107static int gemote(string str)
2108{
2109 return emote(str, 1);
2110}
2111
2112/** Spielerkommando fuers remoten im Genitiv 'r;'.
2113 * Ruft remote(string, int) auf.
2114 */
2115static int gremote(string str)
2116{
2117 return remote(str, 1);
2118}
2119
2120static void load_auto_objects(mapping map_ldfied);
2121
2122private void InitPlayer();
2123private void InitPlayer2();
2124private void InitPlayer3();
2125
2126/** Gibt eine Zufallszahl um P_AVERAGE_SIZE herum zurueck.
2127 * \return Zufaellige Groesse.
2128 */
2129private int RandomSize()
2130{
2131 return (100+random(13)-random(13)+random(13)-random(13))*
2132 (QueryProp(P_AVERAGE_SIZE)||170)/100;
2133}
2134
2135/** Setzt bestimmte Props im Spieler, falls diese nicht gesetzt sind oder
2136 * loescht obsolete Props. Repariert bestimmte Datenstrukturen im Spieler.
2137 * Wird von start_player() nach Laden des Savefiles gerufen.
2138 * Momentan wird z.B. die Groesse gesetzt, falls sie bisher 0 ist und die
2139 * Skills des Spielers initialisiert bzw. repariert oder auf die aktuellste
2140 * Version des Skillsystems
2141 * Ruft ggf. InitSkills() und FixSkills().
2142 * @param[in] newflag Gibt an, ob es ein neuerstellter Spieler ist.
2143 * @sa start_player(), InitSkills(), FixSkills()
2144 */
2145private void updates_after_restore(int newflag) {
2146
2147 // Seher duerfen die Fluchtrichtung uebermitteln lassen.
2148 // Eigentlich koennte es Merlin machen. Dummerweise gibt es ja auch alte
2149 // Seher und dann kann es gleiche fuer alle hier gemacht werden. (Ob der
2150 // Code jemals rauskann?)
2151 //TODO: Irgendwann alle Seher korrigieren und Code nach Merlin schieben...
2152 if (IS_SEER(ME))
2153 SetProp(P_CAN_FLAGS,QueryProp(P_CAN_FLAGS) | CAN_REPORT_WIMPY_DIR);
2154
2155 // ggf. Invis-Eigenschaft aus dem Loginobjekt abrufen (Invislogin), koennte
2156 // ja anders als aus Savefile sein. Gesetztes P_INVIS aus diesem aber
2157 // beibehalten.
2158 if (IS_LEARNER(ME) && !QueryProp(P_INVIS)
2159// && load_name(previous_object()) == "/secure/login"
2160 )
2161 {
2162 SetProp(P_INVIS, previous_object()->query_invis());
2163 if (QueryProp(P_INVIS))
2164 tell_object(ME, "DU BIST UNSICHTBAR!\n" );
2165 }
2166 "*"::updates_after_restore(newflag);
2167
2168 attributes::UpdateAttributes();
2169
2170 int size=Query(P_SIZE);
2171 if (!size) size=RandomSize();
2172 while(size==QueryProp(P_AVERAGE_SIZE))
2173 size=RandomSize();
2174 Set(P_SIZE,size);
2175
2176 // Prop wird nicht mehr genutzt. TODO: irgendwann entfernen.
2177 Set(P_SECOND_LIST, SAVE, F_MODE_AD);
2178 Set(P_SECOND_LIST, 0, F_VALUE);
2179}
2180
2181
2182/** Setzt den HC-Modus.
2183 */
2184varargs nomask void set_hc_play(string str,int val)
2185{
2186 string str1;
2187
2188 str1 = explode( object_name(previous_object()), "#" )[0];
2189
2190 if ( str1 != "/secure/login" &&
2191 previous_object()!=this_object() &&
2192 extern_call() &&
2193 (!geteuid(ME) || geteuid(ME) != getuid(ME) ||
2194 capitalize(geteuid(ME)) != str ||
2195 geteuid(ME) != geteuid(previous_object())) ){
2196 write( "DIESER VERSUCH WAR ILLEGAL !!\n" );
2197 return;
2198 }
2199
2200 hc_play=val;
2201}
2202
2203/** gibt den HC-Modus zurueck.
2204 */
2205nomask int query_hc_play()
2206{
2207 return hc_play;
2208}
2209
2210/** Initialisiert und aktiviert das Spielerobjekt.
2211 * Kann nur von /secure/login oder /secure/master gerufen werden.
2212 * Startet Telnet Negotiation, laedt Savefile, setzt einige Props.
2213 * Ruft updates_after_restore(), um div. Daten zu aktualisieren/reparieren.
2214 * Ruft create() aus /std/player/potion.c.
2215 * Bei neuem Spieler wird der entsprechende Event ausgeloest die Attribute
2216 * auf die Startwerte gesetzt.
2217 * Prueft Zweitiemarkierungen.
2218 * Ruft InitPlayer().
2219 * @param[in] str Name des Charakters, der geladen werden soll.
2220 * @param[in] ip textuelle Repraesentation der IP-Adresse des Spielers.
2221 * @return 1 bei Erfolg, 0 sonst.
2222 * @todo Div. Reparaturen/Updates nach updates_after_restore() auslagern.
2223 */
2224varargs nomask int start_player( string str, string ip )
2225{
2226 mixed second;
2227 int newflag; /* could player be restored? */
2228 string str1;
2229
2230 call_out( "disconnect", 600 );
2231
2232 str1 = explode( object_name(previous_object()), "#" )[0];
2233
2234 if ( str1 != "/secure/login" &&
2235 str1 != "/secure/master" &&
2236 (!geteuid(ME) || geteuid(ME) != getuid(ME) ||
2237 capitalize(geteuid(ME)) != str ||
2238 geteuid(ME) != geteuid(previous_object())) ){
2239 write( "DIESER VERSUCH WAR ILLEGAL !!\n" );
2240 destruct(ME);
2241 return 0;
2242 }
2243
2244 /* try to restore player. If it doesn't exist, set the new flag */
Zesstraf3f22662017-01-30 15:54:29 +01002245 newflag = !restore_object( SAVEPATH + lower_case(str)[0..0] + "/"
MG Mud User88f12472016-06-24 23:31:02 +02002246 +lower_case(str) );
2247
2248 updates_after_restore(newflag);
2249
2250 if ( query_once_interactive(ME) )
2251 {
2252 // Telnet-Negotiations durchfuehren, aber nur die grundlegenden aus
2253 // telnetneg. Alle anderen sollten erst spaeter, nach vollstaendiger
2254 // Initialisierung gemacht werden.
2255 telnetneg::startup_telnet_negs();
2256 modify_prompt();
2257 Set( P_LAST_LOGIN, time() );
2258 }
2259
2260 Set( P_WANTS_TO_LEARN, 1 ); // 1 sollte der default sein !!!
2261 Set( P_WANTS_TO_LEARN, PROTECTED, F_MODE_AS );
2262 // Eingefuegt 18.11.99, kann nach einem Jahr wieder raus:
2263 Set( P_TESTPLAYER, PROTECTED, F_MODE_AS );
2264
2265 if ( IS_LEARNER(ME) )
2266 SetProp( P_CAN_FLAGS, QueryProp(P_CAN_FLAGS)|CAN_REMOTE );
2267
2268 Set( P_NAME, str );
2269 Set( P_NAME, SECURED, F_MODE_AS );
2270
2271 if ( !QueryProp(P_NEEDED_QP) )
2272 SetProp( P_NEEDED_QP, REQ_QP );
2273
2274 Set( P_NEEDED_QP, NOSETMETHOD, F_SET_METHOD );
2275 Set( P_NEEDED_QP, SAVE|SECURED, F_MODE_AS );
2276
2277 /* autosave the player after 500 heartbeats */
2278 time_to_save = age + 500;
2279 potion::create(); /* DO IT HERE AFTER THE RESTORE !! */
2280
2281 AddId( getuid() );
2282 SetProp( P_AC, 0 );
2283 SetProp( P_WEAPON, 0 );
2284
2285 /* Set some things which wont be set when all is OK */
2286 SetProp( P_MAX_HP, (QueryAttribute(A_CON) * 8 + 42 ));
2287 SetProp( P_MAX_SP, (QueryAttribute(A_INT) * 8 + 42 ));
2288
2289 catch( bb = "/secure/bbmaster"->query_bb() );
2290
2291 /* If this is a new character, we call the adventurers guild to get
2292 * our first title !
2293 */
2294 if ( newflag ) {
2295 if ( QueryGuest())
2296 SetProp( P_TITLE, "ueberkommt das "MUDNAME" ..." );
2297
2298 Set( P_LEVEL, -1 );
2299 SetProp( P_ATTRIBUTES, ([ A_STR:1, A_CON:1, A_INT:1, A_DEX:1 ]) );
2300 SetProp( P_HP, QueryProp(P_MAX_HP) );
2301
2302 // Event ausloesen
2303 EVENTD->TriggerEvent(EVT_LIB_PLAYER_CREATION, ([
2304 E_OBJECT: ME,
2305 E_PLNAME: getuid(ME) ]) );
2306 }
2307
2308 InitPlayer();
2309
2310 // Padreic 01.02.1999
Zesstra85576452017-01-30 15:43:21 +01002311 if ( !IS_LEARNER(ME) && (second = QueryProp(P_SECOND)) )
2312 {
2313 if ( stringp(second) && lower_case(second)[0..3] == "von " )
2314 {
MG Mud User88f12472016-06-24 23:31:02 +02002315 second = lower_case(second[4..]);
2316 SetProp( P_SECOND, second );
2317 }
2318
2319 if ( !stringp(second ) ||
Zesstra85576452017-01-30 15:43:21 +01002320 !master()->find_userinfo(second))
2321 {
2322 // Wenns nur an Gross-/Kleinschreibung liegt, wird automatisch
2323 // korrigiert.
MG Mud User88f12472016-06-24 23:31:02 +02002324 if ( stringp(second) &&
Zesstra85576452017-01-30 15:43:21 +01002325 master()->find_userinfo(lower_case(second)))
2326 {
MG Mud User88f12472016-06-24 23:31:02 +02002327 SetProp( P_SECOND, lower_case(second) );
2328 log_file( "WRONG_SECOND",
2329 sprintf( "%s: %s: P_SECOND = %O -> Automatisch "
2330 "korrigiert,\n",
2331 dtime(time()), object_name(), second ) );
2332 }
2333 else {
2334 tell_object( ME,
2335 "*\n*\n* Deine Zweitiemarkierung ist ungueltig, "
2336 "bitte aendere diese und sprich im\n* Zweifel "
2337 "bitte einen Erzmagier an.\n*\n*\n" );
2338
2339 log_file( "WRONG_SECOND",
2340 sprintf( "%s: %s: P_SECOND = %O\n",
2341 dtime(time()), object_name(), second ) );
2342 // ein bisschen deutlicher auffordern.. Padreic 08.04.1999
2343 move( "/d/gebirge/room/zwafflad", M_GO );
2344 }
2345 }
2346 }
2347 return(0);
2348}
2349
2350/** Letzte Phase der Spielerinitialisierung beim Laden des Charakters.
2351 * Ruft enable_commands(), aktiviert den Heartbeat und aktiviert die
2352 * Kommandos aus den geerbten command.c, put_and_get.c, team.c, soul.c,
2353 * guide.c, setzt den Living Name.
2354 * Registriert UseSpell() als Catchall-Kommando.
2355 * Laesst den Spieler ggf. einen Level per /std/gilde aufsteigen, ruft
2356 * call_notify_player_change(), loest Login-Event aus.
2357 * Gibt Willkommenstexte, News und neue Mails aus.
2358 * Findet den Startraum und bewegt den Spieler dorthin.
2359 * Ruft FinalSetup() (aus den Rassenshells).
2360 * Begrenzt Geldmenge im Spieler (wegen Bankzweities) nach Tragkraft und
2361 * erstattet Geld bei Reboot.
2362 * Ruft set_is_wizard().
2363 * Startet Clonen der Autoloader.
2364 * @sa InitPlayer3(),InitPlayer2(), InitPlayer(), start_player().
2365 */
2366private void InitPlayer4()
2367{
2368 int num, str, ski;
2369 string err, called_from_ip;
2370 mixed start_place;
2371 object mon;
2372
2373 enable_commands();
2374 set_heart_beat(1);
2375 command::initialize();
2376 add_put_and_get_commands();
2377 add_team_commands();
2378 add_soul_commands();
2379 add_guide_commands();
2380 add_action( "UseSpell", "", 1 );
2381 set_living_name( getuid() );
2382 while ( remove_call_out("disconnect") != -1 )
2383 ;
2384
2385 if ( QueryProp(P_LEVEL) == -1 )
2386 {
2387 catch( "/std/gilde"->try_player_advance(this_object()) ;publish );
2388 }
2389
2390 if ( interactive(ME) )
2391 call_notify_player_change(1);
2392
2393 if ( interactive(this_object()) ) {
2394 cat( "/etc/NEWS" );
2395
2396 NewbieIntroMsg();
2397
2398 if ( QueryProp(P_INVIS) && !IS_WIZARD(ME) )
2399 SetProp( P_INVIS, 0 );
2400
2401 catch( num = "secure/mailer"->FingerMail(getuid());publish );
2402
2403 if ( num )
2404 write( "Du hast " + num + " neue" +
2405 (num == 1 ? "n Brief" : " Briefe")+" im Postamt liegen.\n" );
2406
2407 catch( RegisterChannels();publish );
2408
2409 if ( (called_from_ip = Query(P_CALLED_FROM_IP)) &&
2410 query_ip_number(ME) != called_from_ip ){
2411 string tmp;
2412
2413 if ( stringp(tmp = query_ip_name(called_from_ip)) &&
2414 tmp != called_from_ip )
2415 tmp = " [" + tmp + "]";
2416 else
2417 tmp = "";
2418
2419 write( "Das letzte Mal kamst Du von " + called_from_ip
2420 + tmp + ".\n" );
2421 }
2422
2423 Set( P_CALLED_FROM_IP, query_ip_number(ME) );
2424 }
2425
2426 if ( !stringp(default_home) || default_home == "" )
2427 default_home = "/gilden/abenteurer";
2428
2429 if ( IS_SEER(ME) && !IS_LEARNER(ME) )
2430 catch( start_place = HAUSVERWALTER->FindeHaus(getuid(ME));publish );
2431 // wenn der Spieler noch ganz frisch ist und noch wenig Stufenpunkte
2432 // gekriegt hat und das Tutorial noch nicht gemacht hat, startet er im
2433 // Tutorial.
2434 else if (QueryProp(P_LEP) <= 120
2435 && QM->HasMiniQuest(this_object(),
2436 "/d/anfaenger/ennox/tutorial/npcs/verkaeufer") != 1)
2437 start_place = "/room/welcome/"+ getuid(this_object());
2438 else
2439 start_place = 0;
2440
2441 if ( !start_place )
2442 start_place = QueryProp(P_START_HOME);
2443
2444 if( objectp(start_place) || (stringp(start_place) && start_place != "" ) ){
2445 if ((err = catch(move( start_place, M_GO|M_SILENT|M_NO_SHOW );publish))
2446 || !environment() )
2447 err = catch(move( default_home, M_GO|M_SILENT|M_NO_SHOW );publish);
2448 }
2449 else
2450 err = catch(move( default_home, M_GO|M_SILENT|M_NO_SHOW );publish);
2451
2452 if ( err )
2453 catch(move( "/gilden/abenteurer", M_GO|M_SILENT|M_NO_SHOW );publish);
2454
2455 // Die Shell muss FinalSetup() nicht implementieren. Daher Callother
2456 catch( ME->FinalSetup();publish );
2457
2458 // Login-event ausloesen
2459 EVENTD->TriggerEvent(EVT_LIB_LOGIN, ([
2460 E_OBJECT: ME,
2461 E_PLNAME: getuid(ME),
2462 E_ENVIRONMENT: environment() ]) );
2463
2464 // erst jetzt GMCP freigeben und zu verhandeln.
2465 gmcp::startup_telnet_negs();
2466
2467 // Schonmal sichern, falls ein Bug (Evalcost...) dazwischen kommen sollte.
2468 autoload_rest = autoload;
2469
2470 // Um Geld-Xties mit illegal viel Geld zu vermeiden, kommt ein Check:
2471 if ( !IS_LEARNER(ME) && !Query(P_TESTPLAYER) &&
2472 mon = present( "\ngeld", ME ) ){
2473 // maximale Kraft, die der Spieler haette haben koennen
2474 str = QueryAttribute(A_STR) + 4;
2475 if ( Query(P_FROG) )
2476 str += 30;
2477 if ( str < 1 )
2478 str = QueryRealAttribute(A_STR) + 4;
2479 if ( str > 30 )
2480 str = 30;
2481
2482 // Trageskill beachten
2483 ski = to_int(UseSkill( SK_CARRY, ([SI_SKILLARG : str ]) ));
2484 if ( !intp(ski) )
2485 ski = 0;
2486
2487 // Wieviel konnte der Spieler insgesamt maximal tragen?
2488 num = 9200 + str * 800 + ski;
2489 if ( num < 3000 )
2490 num = 3000;
2491
2492 // Verdoppeln fuer einen guten Container und nochmal 20% draufschlagen
2493 // zur Sicherheit. Das Ganze danach *4, um die maximale Anzahl Muenzen
2494 // zu erhalten.
2495 num = (int) (num * 8.8);
2496
2497 // Geld, das zuviel ist, auf den Maximalwert kuerzen.
2498 // Zur Sicherheit wird mitgeloggt. Falls ein Spieler sich (zu recht)
2499 // beschwert, kann man immer noch wieder die Summe korrigieren ;-)
2500 if ( (str = mon->QueryProp(P_AMOUNT)) > num ){
2501 mon->SetProp( P_AMOUNT, num );
2502 log_file( "ZUVIEL_GELD", sprintf( "%s: %s hatte %d Muenzen bei "
2503 "sich. Korrigiert auf %d.\n ",
2504 ctime(time())[4..],
2505 capitalize(getuid(ME)),
2506 str, num ) );
2507 }
2508 }
2509 int entschaedigung = QueryProp(P_CARRIED_VALUE);
2510 if ( entschaedigung > 0 )
2511 {
2512 write( "Du findest " + entschaedigung +
2513 " Muenzen, die Du beim letzten Mal verloren hast.\n" );
2514
2515 if ( MayAddWeight( entschaedigung / 4 ) ){
2516 write( "Weil Du nicht mehr soviel tragen kannst, spendest Du den "+
2517 "Rest der Zentralbank.\n" );
2518
2519 num = (QueryProp(P_MAX_WEIGHT) - query_weight_contents()) * 4;
2520 entschaedigung = (num < 0) ? 0 : num;
2521 }
2522
2523 AddMoney( entschaedigung );
2524 SetProp(P_CARRIED_VALUE,0);
2525 }
2526
2527 if ( !QueryProp(P_INVIS) )
2528 say( capitalize(name(WER)) + " betritt diese Welt.\n" );
2529 else
2530 write( "DU BIST UNSICHTBAR!\n\n" );
2531#if __EFUN_DEFINED__(set_is_wizard)
2532 if ( IS_WIZARD(getuid(ME)) )
2533 set_is_wizard( ME, 1 );
2534 else
2535 set_is_wizard( ME, 0 );
2536#endif
2537 if ( query_once_interactive(ME) )
2538 ListAwaited();
2539
2540 // Autoloader werden ganz zum Schluss geclont, da das bis zum bitteren
2541 // (Evalcost-)Ende geschieht und danach u.U. keine Rechenzeit fuer
2542 // andere Aktionen mehr ueber ist
2543 load_auto_objects( autoload );
2544}
2545
2546/** Setzt die Spielerinitialisierung nach start_player() fort.
2547 * Prueft den Wert der vom Spieler getragenen Sachen (fuer Entschaedigung
2548 * nach Reboot).
2549 * Setzt div. Properties des "Spielerkoerpers", die eigentlich gespeichert
2550 * werden, nach einem Reboot zurueck.
2551 * Fragt ggf. nach eMail-Adresse und uebergibt per input_to an
2552 * InitPlayer2().
2553 * @sa InitPlayer3(),InitPlayer2(), InitPlayer(), start_player().
2554*/
2555private void InitPlayer()
2556{
2557 string mailaddr;
2558
2559 // wenn es einen Crash gab, sollen Spieler nicht noch extra bestraft werden
2560 if ( file_time( "/save/" + getuid()[0..0] + "/" + getuid() + ".o" )
2561 < last_reboot_time() ){
2562 SetProp( P_FOOD, 0 );
2563 SetProp( P_DRINK, 0 );
2564 SetProp( P_ALCOHOL, 0 );
2565 SetProp( P_BLIND, 0 );
2566 SetProp( P_DEAF, 0 );
2567 SetProp( P_POISON, 0 );
2568 SetProp( P_GHOST, 0 );
2569 SetProp( P_FROG, 0 );
2570 SetProp( P_HP, QueryProp(P_MAX_HP) );
2571 SetProp( P_SP, QueryProp(P_MAX_SP) );
2572 }
2573
2574 if ( QueryGuest() )
2575 Set( P_MAILADDR, "none" );
2576 else if ( !(mailaddr = Query(P_MAILADDR)) || mailaddr == "" ) {
2577 write(break_string(
2578 "Eine gueltige EMail-Adresse erleichtert es erheblich, Dir "
2579 "ein neues Passwort setzen zu lassen, falls Du einmal Dein "
2580 "Passwort vergisst.",78));
2581 input_to( "getmailaddr",INPUT_PROMPT,
2582 "Gib bitte Deine EMail-Adresse an: " );
2583 return;
2584 }
2585 InitPlayer2();
2586}
2587
2588/** liest eMail-Adresse vom Spieler ein und speichert sie.
2589 * Uebergibt anschliessend an InitPlayer2()
2590 * @param[in] maddr Spielereingabe der Emailadresse.
2591 * @sa InitPlayer2().
2592 */
2593static void getmailaddr( string maddr )
2594{
2595 maddr = check_email(maddr);
2596
2597 if ( !stringp(maddr)) {
2598 write("Deine Eingabe scheint keine gueltige EMail-Adresse gewesen "
2599 "zu sein.\n");
2600 input_to( "getmailaddr", INPUT_PROMPT,
2601 "Gib bitte Deine EMail-Adresse an: " );
2602 return;
2603 }
2604 Set( P_MAILADDR, maddr );
2605 InitPlayer2();
2606}
2607
2608
2609/** Prueft Geschlecht des Spielers und fragt ggf. beim Spieler nach.
2610 * Uebergibt an InitPlayer3() oder get_gender().
2611 * @sa InitPlayer3(), get_gender().
2612 */
2613private void InitPlayer2()
2614{
2615 if( member(({ MALE, FEMALE }), QueryProp(P_GENDER) ) == -1 ) {
2616 input_to( "getgender", INPUT_PROMPT,
2617 "Bist Du maennlich oder weiblich: ");
2618 return;
2619 }
2620
2621 InitPlayer3();
2622}
2623
2624/** Liest Spielerantwort auf die Frage nach dem Geschlecht des Chars ein.
2625 * Wird gerufen von input_to().
2626 * Uebergibt an InitPlayer3().
2627 * @sa InitPlayer3().
2628 */
2629static void getgender( string gender_string )
2630{
2631 gender_string = lower_case( gender_string );
2632
2633 if ( sizeof(gender_string)==1 && gender_string[0] == 'm' ){
2634 write( "Willkommen, mein Herr!\n" );
2635 SetProp( P_GENDER, MALE );
2636 }
2637 else if ( sizeof(gender_string)==1 && gender_string[0] == 'w' ){
2638 write( "Willkommen, gnae' Frau!\n" );
2639 SetProp( P_GENDER, FEMALE );
2640 }
2641 else {
2642 write( "Wie? Was? Verstehe ich nicht!\n" );
2643 input_to( "getgender", INPUT_PROMPT,
2644 "Bist Du maennlich oder weiblich? (tippe m oder w): ");
2645 return;
2646 }
2647
2648 InitPlayer3();
2649}
2650
2651
2652/** Prueft Terminaltyp des Spielers und fragt ggf. beim Spieler nach.
2653 * Uebergibt an InitPlayer4() oder gettty().
2654 * @sa InitPlayer4(), gettty().
2655 */
2656private void InitPlayer3()
2657{
2658 if ( !QueryProp(P_TTY) || QueryProp(P_TTY) == "none" )
2659 {
2660 write( "Waehle einen Terminaltyp (kann spaeter mit <stty> geaendert "
2661 "werden)\n");
2662 input_to( "gettty", INPUT_PROMPT, "vt100, ansi, dumb (Standard: dumb): " );
2663 return;
2664 }
2665 InitPlayer4();
2666}
2667
2668/** Liest Spielerantwort auf die Frage nach dem Terminaltyp ein.
2669 * Wird gerufen von input_to().
2670 * Uebergibt an InitPlayer4().
2671 * @sa InitPlayer4().
2672 */
2673static void gettty( string ttystr )
2674{
2675 if ( !ttystr || ttystr == "" )
2676 ttystr = "dumb";
2677
2678 ttystr = lower_case(ttystr);
2679
2680 if ( ttystr == "vt100" ){
2681 write( "Dies sollte " + ANSI_BOLD + "fett" + ANSI_NORMAL + " sein.\n" );
2682 SetProp( P_TTY, ttystr );
2683 }
2684 else
2685 if ( ttystr == "ansi" ){
2686 write( "Dies sollte " + ANSI_RED + "rot" + ANSI_NORMAL +
2687 " sein.\n" );
2688 SetProp( P_TTY, "ansi" );
2689 }
2690 else if ( ttystr == "dumb" ){
2691 write( "Ohje, oede! Besorg Dir ein besseres Terminal!\n" );
2692 SetProp( P_TTY, "dumb" );
2693 }
2694 else {
2695 write( "Dieser Terminaltyp wird nicht unterstuetzt. Nimm bitte "
2696 "einen aus:\nvt100, ansi or dumb (Standard ist dumb).\n" );
2697 input_to( "gettty", INPUT_PROMPT,
2698 "vt100, ansi or dumb (Standard ist dumb): ");
2699 return;
2700 }
2701
2702 InitPlayer4();
2703}
2704
2705
2706/** Liefert die UID des Charakters zurueck, also den Charakternamen.
2707 * @return UID des Objekts (Charaktername).
2708 */
2709nomask string query_real_name() {
2710 /* ACHTUNG !! DIES LFUN DARF NICHT ENTFERNT WERDEN !!! */
2711 /* Sie wird vom Gamedriver (zB bei F_ED) aufgerufen !! */
2712 /* Ich bin da zwar nicht so ueberzeugt von, dass der Driver die heutzutage
2713 * noch ruft, aber die halbe Mudlib ruft sie. ;-) (Zesstra, 27.4.08)
2714 */
2715 return getuid();
2716}
2717
2718/*
2719 * the wizard command review: show player moving messages
2720 */
2721int review() {
2722 string *msg;
2723 write(short());
2724 write("Deine Bewegungen werden wie folgt gemeldet:\n"+
2725 "mout: "+name(WER)+" "+(msg=explode(QueryProp(P_MSGOUT),"#"))[0]
2726 +" <Richtung>"+(sizeof(msg)>1 ? msg[1] : "")+".\n"+
2727 "min: "+name(WER)+" "+QueryProp(P_MSGIN)+".\n"+
2728 "mmout: "+name(WER)+" "+QueryProp(P_MMSGOUT)+".\n"+
2729 "mmin: "+name(WER)+" "+QueryProp(P_MMSGIN)+".\n"+
2730 (IS_LEARNER(ME) ?
2731 "cmsg: "+name(WER)+" "+QueryProp(P_CLONE_MSG)+".\n"+
2732 "dmsg: <Irgendetwas> "+QueryProp(P_DESTRUCT_MSG)+".\n"
2733 : "")+
2734 "Wenn Du jemanden angreifst, sieht das so aus:\n"+
2735 name(WER)+" greift Dich"+QueryProp(P_HANDS)[0]+" an.\n");
2736 return 1;
2737}
2738
2739/*
2740 * set player moving messages
2741 */
2742
2743static int setmin(string str)
2744{
2745 SetProp(P_MSGIN, _unparsed_args()||"kommt an");
2746 write("Ok.\n");
2747 return 1;
2748}
2749
2750static int setmout(string str)
2751{
2752 string *msg;
2753
2754 if(sizeof(msg=explode((_unparsed_args()||"geht"),"#"))>2)
2755 {
2756 write("Du darfst nur einmal '#' fuer die Richtung angeben.\n");
2757 return 1;
2758 }
2759 if(sizeof(msg)>1)
2760 {
2761 if (msg[0]!="" && msg[0][<1]==' ') msg[0]=msg[0][0..<2];
2762 SetProp(P_MSGOUT, msg[0]+"#"+msg[1]);
2763 }
2764 else
2765 SetProp(P_MSGOUT, _unparsed_args()||"geht");
2766 write("Ok.\n");
2767 return 1;
2768}
2769
2770static int setmmin(string str)
2771{
2772 SetProp(P_MMSGIN, _unparsed_args()||"erscheint");
2773 write("Ok.\n");
2774 return 1;
2775}
2776
2777static int setmmout(string str)
2778{
2779 SetProp(P_MMSGOUT, _unparsed_args()||"verschwindet");
2780 write("Ok.\n");
2781 return 1;
2782}
2783
2784static int setcmsg(string str)
2785{
2786 SetProp(P_CLONE_MSG, _unparsed_args()||"zaubert etwas aus "
2787 + QueryPossPronoun(MALE,WEM) + " Aermel hervor");
2788 write("Ok.\n");
2789 return 1;
2790}
2791
2792static int setdmsg(string str)
2793{
2794 SetProp(P_DESTRUCT_MSG, _unparsed_args()||"wird von " + name(WER,1)
2795 + " zerstaeubt");
2796 write("Ok.\n");
2797 return 1;
2798}
2799
2800static int set_title(string str)
2801{
2802 string bonus;
2803
2804 if(!IS_SEER(this_object()) && !FAO_HAS_TITLE_GIFT(this_object()) )
2805 {
2806 return 0;
2807 }
2808
2809 bonus = "";
2810 if (!(str=_unparsed_args()))
2811 str = "";
2812 else if( str[0..2]=="\\b," || str[0..2]=="\\b'" )
2813 {
2814 bonus = "\b"; // ein backspace fuer ein (hoch)komma ist ok! :-)
2815 str = str[2..];
2816 }
2817 if(str=="0") // damit der Gildentitel zum Vorschein kommen kann
2818 SetProp(P_TITLE, 0);
2819 else
2820 SetProp(P_TITLE, bonus+str);
2821 write("Ok.\n");
2822 return 1;
2823}
2824
2825static int extra_input(string str, string look)
2826{
2827 if (str=="**")
2828 {
2829 if (look=="")
2830 SetProp(P_EXTRA_LOOK,0);
2831 else
2832 SetProp(P_EXTRA_LOOK,look);
2833 write("Ok.\n");
2834 return 1;
2835 }
2836 input_to("extra_input",INPUT_PROMPT, "]" ,look+str+"\n");
2837 return 1;
2838}
2839
2840static int extralook(mixed str)
2841{
2842 if( str=="?" )
2843 {
2844 write( "Dein Extralook ist : "+QueryProp(P_EXTRA_LOOK) + "\n");
2845 return 1;
2846 }
2847 write("Bitte gib Deinen Extra-Look ein. Beenden mit **:\n");
2848 input_to("extra_input",INPUT_PROMPT,"]","");
2849 return 1;
2850}
2851
2852static void calculate_value()
2853{
2854 int i, carried_value, value;
2855
2856 carried_value=0;
2857 foreach(object ob: deep_inventory(ME)) {
2858 if (!ob->QueryProp(P_AUTOLOADOBJ))
2859 carried_value+=((value=(int)ob->QueryProp(P_VALUE)) > 1000 ? 1000 : value);
2860 }
2861 SetProp(P_CARRIED_VALUE, carried_value);
2862}
2863
2864/* Called by command 'save' */
2865int save_character() {
2866 save_me(1);
2867 write("Ok.\n");
2868 return 1;
2869}
2870
2871void save_me(mixed value_items)
2872{
2873 // Gaeste werden nicht gespeichert
2874 if( getuid()[0..3]=="gast" )
2875 return;
2876
2877 // Autoloader identifizieren und speichern
2878 autoload=([]);
2879 foreach(object ob: deep_inventory(ME)) {
2880 int val = ob->QueryProp( P_AUTOLOADOBJ );
2881 if (val && clonep(ob))
2882 {
2883 string obname=load_name(ob);
2884 if (obname == GELD)
2885 autoload[obname] += val;
2886 else
2887 autoload += ([obname:val]);
2888 }
2889 }
2890 // An noch nicht geclonte Autoloader denken!
2891 autoload += autoload_rest;
2892
2893 // Im Bedarfsfall Wert des Inventory bestimmen
2894 if (value_items)
2895 calculate_value();
2896 else
2897 SetProp(P_CARRIED_VALUE, 0);
2898
2899 // Logout-Zeit speichern
2900 if(query_once_interactive(ME) && !QueryProp(P_INVIS))
2901 Set(P_LAST_LOGOUT,time());
2902
2903 // Funktion zur Bestimmung des Gildenrating aufrufen
2904 string gilde=GUILD_DIR+QueryProp(P_GUILD);
2905 if (find_object(gilde) || file_size(gilde+".c")>-1)
2906 catch(call_other(gilde,"GuildRating",this_object());publish);
2907
2908 // Speichern des Spielers
Zesstra3162c892017-01-30 15:55:22 +01002909 save_object(SAVEPATH+getuid()[0..0]+"/" + getuid());
MG Mud User88f12472016-06-24 23:31:02 +02002910}
2911
2912static varargs void log_autoload( string file, string reason, mixed data, string error )
2913{
2914 if (member(autoload_error,file)!=-1) return;
2915 log_file(SHELLLOG("NO_AUTO_FILE"),sprintf("%s: %s: %s\nreason: cannot %s file\ndata: %O\n%s\n",
2916 ctime()[4..15],capitalize(getuid()),file,reason,data,
2917 (error?"Fehlermeldung: "+error+"\n":"")));
2918 autoload_error+=({file});
2919}
2920
2921// tics, die fuer autoloader reichen sollten:
2922#define SAFE_FOR_AUTOLOADER __MAX_EVAL_COST__/4
2923
2924private void load_auto_object( string file, mixed data )
2925{
2926 object ob;
2927 string error;
2928
2929 if( get_eval_cost() < SAFE_FOR_AUTOLOADER ) return;
2930 m_delete( autoload_rest, file );
2931 autoload_error-=({file});
2932
2933 if ( file == "/obj/money" )
2934 file = "/items/money";
2935 if ( file == "/obj/seercard" )
2936 file = "/items/seercard";
2937
2938 ob = find_object(file);
2939
2940 if (!ob)
2941 {
2942 if (file_size(file+".c")<0&&
2943 file_size(implode(explode(file,"/")[0..<2],"/")+
2944 "/virtual_compiler.c")<0)
2945 {
2946 log_autoload(file,"find",data,0);
2947 return;
2948 }
2949 if (error = catch(load_object(file); publish))
2950 {
2951 log_autoload(file,"load",data,error);
2952 return;
2953 }
2954 }
2955 if ( error = catch(ob = clone_object(file); publish) )
2956 {
2957 log_autoload(file,"clone",data, error);
2958 return;
2959 }
2960
2961 if ( error = catch(ob->SetProp( P_AUTOLOADOBJ, data ); publish) )
2962 {
2963 log_autoload(file,"SetProp",data, error);
2964 ob->remove(1);
2965 if (ob) destruct(ob);
2966 return;
2967 }
2968
2969 if ( error = catch(ob->move( ME, M_NOCHECK );publish) ) {
2970 log_autoload(file,"move",data, error);
2971 ob->remove(1);
2972 if(ob) destruct(ob);
2973 return;
2974 }
2975}
2976
2977static void load_auto_objects( mapping map_ldfied )
2978{
2979 if ( (!mappingp(map_ldfied) || !sizeof(map_ldfied)) && !sizeof(autoload_rest) )
2980 return;
2981
2982 // Mit Netztoten Spielern rechnen manche Autoloader nicht. Also
2983 // das Clonen unterbrechen und in Reconnect() wieder anwerfen.
2984 if ( !interactive() )
2985 return;
2986
2987 // Kleiner Hack: autoload_rest ist eine globale Variable, die beim
2988 // Clonen der einzelnen Autoloader direkt veraendert wird.
2989 // So lange das Mapping noch Eintraege hat, muessen wir noch fehlende
2990 // Autoloader clonen.
2991 if ( !sizeof(autoload_rest) )
2992 autoload_rest = map_ldfied;
2993
2994 // Schon hier einen call_out() zum "Nach"clonen von noch nicht geclonten
2995 // Autoloadern starten, da spaeter u.U. keine Rechenzeit mehr dafuer da ist.
2996 while ( remove_call_out("load_auto_objects") != -1 )
2997 /* do nothing */;
2998
2999 // Mit Parameter '0' aufrufen, da das globale Mapping benutzt wird.
3000 // Verzoegerung 0 in rekursiven Callouts ist bloed, also 1s Delay
3001 call_out( "load_auto_objects", 2, 0 );
3002
3003 // Mit catch() gegen die Evalcost-Falle!
3004 // Mit Absicht das walk_mapping() aus der "alten" Version erhalten und
3005 // nicht durch eine (einfachere) Schleife inkl. get_eval_cost() ersetzt,
3006 // da eine Schleife gegenueber der walk_mapping()-Loesung den Aufbau
3007 // der previous_object()-Kette veraendern wuerde; darauf testen aber
3008 // manche Objekte.
3009 catch( walk_mapping( autoload_rest, #'load_auto_object/*'*/ ) );
3010}
3011
3012/*
3013 * al_to_title: Make the numeric alignment value into a string
3014 */
3015static string al_to_title(int a)
3016{
3017 if (a >= KILL_NEUTRAL_ALIGNMENT * 100)
3018 return "heilig";
3019 if (a > KILL_NEUTRAL_ALIGNMENT * 20)
3020 return "gut";
3021 if (a > KILL_NEUTRAL_ALIGNMENT * 4)
3022 return "nett";
3023 if (a > - KILL_NEUTRAL_ALIGNMENT * 4)
3024 return "neutral";
3025 if (a > - KILL_NEUTRAL_ALIGNMENT * 20)
3026 return "frech";
3027 if (a > - KILL_NEUTRAL_ALIGNMENT * 100)
3028 return "boese";
3029 return "satanisch";
3030}
3031
3032static int toggle_whimpy_dir(string str) {
3033 SetProp(P_WIMPY_DIRECTION,str=_unparsed_args()||str);
3034 if (str)
3035 printf("Ok, Fluchtrichtung %O.\n",str);
3036 else
3037 printf("Ok, bevorzugte Fluchtrichtung deaktiviert.\n");
3038 return 1;
3039}
3040
3041static int toggle_whimpy(string str)
3042{
3043 int i;
3044
3045 if(!str || str=="" || (sscanf(str,"%d",i)<0))
3046 {
3047 write("vorsicht <hp>, 0<=hp<"+QueryProp(P_MAX_HP)+"\n");
3048 return 1;
3049 }
3050 if(i>=QueryProp(P_MAX_HP) || i<0)
3051 {
3052 write("Der Wert ist nicht erlaubt.\n");
3053 return 1;
3054 }
3055 if(!i) write("Prinz Eisenherz-Modus.\n");
3056 else write("Vorsicht-Modus ("+i+")\n");
3057 SetProp(P_WIMPY,i);
3058 return 1;
3059}
3060
3061/** Bestimmt, ob das Spielerobjekt beschattet werden darf.
3062 * Beschatten ist nur fuer Objekte erlaubt, die in /std/player/shadows
3063 * abgelegt sind.
3064 * Ausnahme: Testspieler mit gesetztem P_ALLOWED_SHADOW
3065 * @param[in] obj Objekt, was beschatten moechte.
3066 * @return 0, wenn Beschatten erlaubt, 1 sonst.
3067 */
3068varargs nomask int query_prevent_shadow(object obj)
3069{
3070 string what, allowed_shadow;
3071 int dummy;
3072
3073// if ( Query(P_TESTPLAYER) )
3074// return 0;
3075
3076 if (obj){
3077 what=object_name(obj);
3078 if (what && what != "" &&
3079 sscanf(what,"/std/player/shadows/%s#%d",what,dummy)==2)
3080 return 0;
3081
3082 // Einem Testspieler kann man P_ALLOWED_SHADOW auf einen zu testenden
3083 // Shadow setzen.
3084 if ( Query(P_TESTPLAYER) &&
3085 stringp(what) &&
3086 stringp(allowed_shadow=Query(P_ALLOWED_SHADOW)) &&
3087 strstr(what, allowed_shadow)==0)
3088 return 0;
3089 }
3090 return 1;
3091}
3092
3093static int uhrzeit()
3094{
3095 write(dtime(time()+QueryProp(P_TIMEZONE)*3600)+".\n");
3096 return 1;
3097}
3098
3099protected string SetDefaultHome(string str)
3100{
3101 return default_home=str;
3102}
3103
3104string QueryDefaultHome()
3105{
3106 return default_home;
3107}
3108
3109protected string SetDefaultPrayRoom(string str)
3110{
3111 if(hc_play>1)
3112 {
3113 default_pray_room="/room/nirvana";
3114 }
3115 else
3116 default_pray_room=str;
3117
3118 return default_pray_room;
3119}
3120
3121string QueryPrayRoom()
3122{
3123 if(hc_play>1)
3124 {
3125 return "/room/nirvana";
3126 }
3127 string room = QueryProp(P_PRAY_ROOM);
3128 if (stringp(room))
3129 return room;
3130 else if (default_pray_room)
3131 return default_pray_room;
3132 // hoffentlich ist das wenigstens gesetzt.
3133 return default_home;
3134}
3135
3136void _restart_beat()
3137{
3138 tell_object(ME,
3139 "Der GameDriver teilt Dir mit: Dein Herzschlag hat wieder eingesetzt.\n");
3140 set_heart_beat(1);
3141}
3142
3143static int weg(string str)
3144{
3145 if (!(str=_unparsed_args()))
3146 {
3147 printf("Du bist nicht%s als abwesend gekennzeichnet.\n",
3148 QueryProp(P_AWAY) ? " mehr" : "");
3149 SetProp(P_AWAY, 0);
3150 return 1;
3151 }
3152 write("Du bist jetzt als abwesend gekennzeichnet.\n");
3153 SetProp(P_AWAY, str);
3154 return 1;
3155}
3156
3157/* Ein Befehl zum anschauen der Wegmeldung anderer Spieler */
3158static int wegmeldung(string player)
3159{
3160
3161 object player_ob;
3162 string weg;
3163
3164 if ( !player || player=="" ||
3165 player==lowerstring(this_player()->QueryProp(P_NAME)))
3166 {
3167 weg=this_player()->QueryProp(P_AWAY);
3168 write ("Du bist "+(weg?"":"nicht ")+"als abwesend gekennzeichnet.\n");
3169 if (weg)
3170 write(break_string(weg, 78,"Grund: ",BS_INDENT_ONCE));
3171 return 1;
3172 }
3173
3174 // Welcher Spieler ist gemeint?
3175 player_ob=find_player(player);
3176
3177 // Spieler nicht da oder Invis und Anfrager is kein Magier
3178 if (!player_ob ||
3179 (player_ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player())))
3180 {
3181 write(capitalize(player)+" ist gerade nicht im Spiel.\n");
3182 return 1;
3183 }
3184
3185 weg=player_ob->QueryProp(P_AWAY);
3186
3187 // player_ob->Name() gibt bei invis-Magiern "Jemand" zurueck
3188 write (player_ob->QueryProp(P_NAME)+" ist "+
3189 (weg?"":"nicht ")+"als abwesend gekennzeichnet.\n");
3190
3191 if (weg)
3192 write(break_string(weg, 78,"Grund: ",BS_INDENT_ONCE));
3193
3194 return 1;
3195}
3196
3197static string timediff(int time)
3198{
3199 string ret;
3200
3201 ret="";
3202 if(time>=86400) {
3203 ret+=time/86400+"d ";
3204 time%=86400;
3205 }
3206 if(time<36000) ret+="0";
3207 ret+=time/3600+":";
3208 time%=3600;
3209 if(time<600) ret+="0";
3210 ret+=time/60+":";
3211 time%=60;
3212 if(time<10) ret+="0";
3213 ret+=time+"";
3214 return ret;
3215}
3216
3217
3218/* Ein Befehl zum anschauen der Idlezeit anderer Spieler */
3219static int idlezeit(string player)
3220{
3221
3222 object player_ob;
3223 int idle;
3224
3225 if ( !player || player=="" ||
3226 player==lowerstring(this_player()->QueryProp(P_NAME)))
3227 {
3228 write ("Du bist selber natuerlich gerade nicht idle.\n");
3229 return 1;
3230 }
3231
3232 // Welcher Spieler ist gemeint?
3233 player_ob=find_player(player);
3234
3235 // Spieler nicht da oder Invis und Anfrager is kein Magier
3236 if (!player_ob ||
3237 (player_ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player())))
3238 {
3239 write(capitalize(player)+" ist gerade nicht im Spiel.\n");
3240 return 1;
3241 }
3242
3243 idle=query_idle(player_ob);
3244
3245 // player_ob->Name() gibt bei invis-Magiern "Jemand" zurueck
3246 write (player_ob->QueryProp(P_NAME)+" ist "+
3247 (idle>=60?timediff(idle):"nicht")+" passiv.\n");
3248
3249 return 1;
3250}
3251
3252
3253/** Belebt einen netztoten Spieler wieder.
3254 * Reaktiviert Heartbeats, bewegt den Spieler zurueck an den Ort, der eim
3255 * Einschlafen zum Aufwachen ermittelt wurde (im einfachsten Fall der Raum,
3256 * wo man eingeschlafen ist).
3257 */
3258static void ndead_revive()
3259{
3260 string fname;
3261 int ret;
3262
3263 set_heart_beat(1);
3264 ndead_next_check = NETDEAD_CHECK_TIME;
3265 ndead_currently = 0;
3266 ndead_lasttime = 0;
3267
3268 if ( !objectp(ndead_location) &&
3269 stringp(ndead_l_filename) && sizeof(ndead_l_filename)) {
3270
3271 if ( member( ndead_l_filename, '#' ) == -1 ){
3272 catch(load_object( ndead_l_filename); publish);
3273 ndead_location = find_object(ndead_l_filename);
3274 }
3275 else {
3276 ndead_location = find_object(ndead_l_filename);
3277 if ( !ndead_location && env_ndead_info ){
3278 fname = explode( ndead_l_filename, "#" )[0];
3279 catch(ndead_location =
3280 (load_object(fname)->SetProp(P_NETDEAD_INFO, env_ndead_info));
3281 publish);
3282 if ( !objectp(ndead_location) ){
3283 catch(load_object( ndead_location);publish);
3284 ndead_location = find_object(ndead_location);
3285 }
3286 }
3287 }
3288 }
3289
3290 if ( !objectp(ndead_location)
3291 || catch(ret = move( ndead_location, M_GO|M_SILENT );publish)
3292 || ret != 1 ) {
3293 move( "gilden/abenteurer", M_GO|M_SILENT );
3294 ndead_location = environment();
3295 }
3296
3297 // ndead_location=0;
3298 ndead_l_filename = 0;
3299 env_ndead_info = 0;
3300}
3301
3302/** Bewegt einen netztoten Spieler in den Netztotenraum
3303 * Gerufen von heartbeat().
3304 * Zerstoert Gaeste, verlaesst ggf. das Team, ermittelt, ob der Spieler beim
3305 * Aufwachen in das alte Environment bewegt werden soll oder in einen anderen
3306 * Raum, hierzu wird im Environment P_NETDEAD_INFO abgefragt.
3307 * Deaktiviert die Kommandos per disable_commands().
3308 */
3309static void ndead_move_me() {
3310 object team;
3311 mixed amem;
3312
3313 set_heart_beat(0);
3314 stop_heart_beats();
3315 if (QueryGuest()) {
3316 quit();
3317 if (ME)
3318 remove();
3319 if (ME)
3320 destruct(ME);
3321 return;
3322 }
3323 ndead_next_check=NETDEAD_CHECK_TIME;
3324 ndead_currently=1;
3325 ndead_lasttime=0;
3326 ndead_location=environment();
3327 if (objectp(ndead_location))
3328 ndead_l_filename=object_name(ndead_location);
3329
3330 if (objectp(environment())
3331 && sizeof(explode(object_name(environment()),"#")) > 1)
3332 env_ndead_info=environment()->QueryProp(P_NETDEAD_INFO);
3333 else
3334 env_ndead_info=0;
3335
3336 if ( objectp(team=Query(P_TEAM)) )
3337 // Der Test auf assoziierte Teammitglieder (== FolgeNPCs)
3338 // verhindert, dass Spieler nach "schlafe ein" aus dem
3339 // Team ausgetragen werden. -- 29.01.2002 Tiamak
3340 // && !objectp(amem=Query(P_TEAM_ASSOC_MEMBERS))
3341 // && !(pointerp(amem) && sizeof(amem)))
3342 team->RemoveMember(ME);
3343
3344 disable_commands();
3345 move(NETDEAD_ROOM,M_GO|M_NO_ATTACK|M_NOCHECK,"ins Reich der Netztoten");
3346}
3347
3348/** Ist dieser Character ein Gast?
3349 * @return 1, wenn Gast, 0 sonst.
3350 */
3351int QueryGuest()
3352{
3353 string dummy;
3354 return sscanf(getuid(),"gast%d",dummy);
3355}
3356
3357/** Spielerkommando 'schlafe ein'.
3358 * Ruft remove_interactive() bei Spielern, bei Magiern wird quit() gerufen,
3359 * um das Magierobjekt zu zerstoeren.
3360 * @sa quit()
3361 */
3362int disconnect(string str)
3363{
3364 string verb;
3365 string desc = break_string(
3366 "\"schlafe ein\" beendet Deine Verbindung mit "MUDNAME". Du behaeltst "
3367 "Deine Sachen.\nFalls "MUDNAME" jedoch abstuerzt oder neu gestartet "
3368 "wird, waehrend Du weg bist, verlierst Du die meisten allerdings "
3369 "(genauso, als wenn Du Deine Verbindung mit \"ende\" beendet haettest). "
3370 "In diesem Fall bekommst Du dann eine kleine Entschaedigung."
3371 ,78,0,BS_LEAVE_MY_LFS);
3372
3373 verb=query_verb();
3374 if (!verb)
3375 verb="AUTOCALL";
3376 if (verb[0..5]=="schlaf" && str!="ein")
3377 {
3378 notify_fail(desc);
3379 return 0;
3380 }
3381 if (IS_LEARNER(this_object()))
3382 return quit();
3383
3384 tell_object(this_object(), desc);
3385
3386 if (clonep(environment()) && !environment()->QueryProp(P_NETDEAD_INFO))
3387 tell_object(this_object(),break_string(
3388 "\nACHTUNG: Wenn Du hier laengere Zeit schlaefst, "
3389 "kommst Du vermutlich nicht an diesen Ort zurueck!",78));
3390
3391 say(capitalize(name(WER))+" hat gerade die Verbindung zu "MUDNAME" gekappt.\n");
3392 remove_interactive(ME);
3393 call_out(#'clear_tell_history,4);
3394 return 1;
3395}
3396
3397static int finger (string str)
3398{
3399 string ret;
3400 mixed xname;
3401
3402 if (!str || str==""
3403 || sizeof(explode(str," ")-({"-n","-p","-s","-v","-a"}))>1)
3404 {
3405 write("finger <spielername> oder finger <spielername@mudname>\n"+
3406 "Bitte nur den reinen Spielernamen verwenden, keine Namensvorsaetze oder Titel\n");
3407 return 1;
3408 }
3409 xname=explode(str,"@");
3410 if(sizeof(xname)==2)
3411 {
3412 if (xname[0]=="-n " || xname[0]=="-p " || xname[0]=="-s ") {
3413 write("finger <spielername>@<mudname> - der Spielername fehlt.\n");
3414 return 1;
3415 }
3416 if (ret=INETD->_send_udp(xname[1],([
3417 REQUEST: "finger",
3418 SENDER: getuid(ME),
3419 DATA: (explode(xname[0]," ")-({"-n","-p","-s"}))[0]
3420 ]), 1))
3421 write(ret);
3422 else
3423 write("Anfrage abgeschickt.\n");
3424 return 1;
3425 }
3426 "/p/daemon/finger"->finger_single(str,1);
3427 return 1;
3428}
3429
3430string lalign(string str, int wid)
3431{
3432 return (str+" "+
3433 " ")[0..wid-1];
3434}
3435
3436#define MUDS_BAR "\
3437-------------------------------------------------------------------------------"
3438
3439private void format(mixed mud, mixed hosts, string output)
3440{
3441 output += lalign(hosts[mud][HOST_NAME], 20) + " " +
3442 (hosts[mud][HOST_STATUS] ?
3443 hosts[mud][HOST_STATUS] > 0 ?
3444 "UP " + ctime(hosts[mud][HOST_STATUS])[4..15] :
3445 "DOWN " + ctime(-hosts[mud][HOST_STATUS])[4..15]
3446 : "UNKNOWN Never accessed.") + "\n";
3447}
3448
3449static int muds() {
3450 mapping hosts;
3451 int i;
3452 mixed muds, output;
3453
3454 output = lalign("Mudname", 20) + " Status Last access";
3455 output += "\n" + MUDS_BAR[0..sizeof(output)] + "\n";
3456 muds = sort_array(m_indices(hosts = INETD->query("hosts")),#'>);
3457 map(muds, #'format, hosts, &output);
3458 More(output);
3459 return 1;
3460}
3461
3462// **** local property methods
3463static int _set_level(int i)
3464{
3465 if (!intp(i)) return -1;
3466 if (i<1) return -1;
3467 Set(P_LEVEL, i);
3468 GMCP_Char( ([P_LEVEL: i]) );
3469 return i;
3470}
3471
3472static int _set_invis(int a)
3473{
3474 return Set(P_INVIS, intp(a) ? a : !Query(P_INVIS));
3475}
3476
3477/* sets the terminal type */
3478/* note: support vt100 (b/w), ansi (color), dumb (none) */
3479static string _set_tty(string str) {
3480 if(str != "dumb" && str != "vt100" && str != "ansi")
3481 return Query(P_TTY);
3482 return Set(P_TTY, str);
3483}
3484
3485static int stty(string str)
3486{
3487 if(str!="dumb"&&str!="vt100"&&str!="ansi"&&str!="reset")
3488 {
3489 write("Kommando: stty dumb|vt100|ansi oder reset\n");
3490 }
3491 if(str == "reset") {
3492 printf("Dieser Text sollte lesbar sein!\n");
3493 return 1;
3494 }
3495
3496 write("TTY steht jetzt auf "+SetProp(P_TTY,str)+".\n");
3497 if(str == "ansi" || str == "vt100") {
3498 printf("Terminal Test:\n");
3499 printf("VT100: fett unterstrichen "+
3500 "blinkend invers\n");
3501 if(str == "ansi") {
3502 printf("ANSI Farben und VT100 Attribute:\n");
3503 foreach(int fg: 30 .. 37) {
3504 foreach(int bg: 40 .. 47) {
3505 printf("[%d;%dm@", fg, bg);
3506 printf("[%d;%dm@", fg, bg);
3507 printf("[%d;%dm@", fg, bg);
3508 printf("[%d;%dm@", fg, bg);
3509 }
3510 printf("\n");
3511 }
3512 printf("Sollte dieser Text hier nicht richtig lesbar\nsein,"+
3513 "benutze das Kommando stty reset!\n");
3514 }
3515
3516 }
3517 return 1;
3518}
3519
3520int set_ascii_art(string str)
3521{
3522 if (str!="ein"&&str!="aus")
3523 {
3524 printf("Du moechtest 'Grafik' "+(QueryProp(P_NO_ASCII_ART)?"NICHT ":"")+
3525 "sehen.\n");
3526 }
3527
3528 if (str=="ein") {
3529 SetProp(P_NO_ASCII_ART, 0);
3530 printf("Zukuenftig moechtest Du 'Grafik' sehen.\n");
3531 }
3532
3533 if (str=="aus") {
3534 SetProp(P_NO_ASCII_ART, 1);
3535 printf("Zukuenftig moechtest Du KEINE 'Grafik' mehr sehen.\n");
3536 }
3537
3538
3539 return 1;
3540}
3541
3542int _set_shell_version(int arg)
3543{
3544 if (!intp(arg))
3545 return -1;
3546 Set(P_SHELL_VERSION,({QueryProp(P_RACE),arg}));
3547 return 1;
3548}
3549
3550int _query_shell_version()
3551{ mixed sv;
3552
3553 if (!(sv=Query(P_SHELL_VERSION)) || !pointerp(sv) || sizeof(sv)!=2 ||
3554 sv[0]!=QueryProp(P_RACE) || !intp(sv[1]))
3555 return 0;
3556 return sv[1];
3557}
3558
3559// XxXxXxXxXx
3560
3561int more(string str)
3562{
3563 if(!str)
3564 {
3565 notify_fail("Usage: more <file>\n");
3566 return 0;
3567 }
3568 if (file_size(str) <= 0) {
3569 notify_fail(str+": No such file\n");
3570 return 0;
3571 }
3572 More(str, 1);
3573 return 1;
3574}
3575
3576static int set_visualbell(string str)
3577{
3578 if(!str)
3579 {
3580 write("Derzeitige Einstellung fuer Tonausgabe: "+
3581 (QueryProp(P_VISUALBELL)?"AUS":"EIN")+".\n");
3582 return 1;
3583 }
3584 if (str=="ein")
3585 {
3586 if(!QueryProp(P_VISUALBELL))
3587 write("Die Tonausgabe stand schon auf EIN.\n");
3588 else
3589 {
3590 SetProp(P_VISUALBELL,0);
3591 write("OK, Tonausgabe auf EIN gestellt.\n");
3592 }
3593 }
3594 else
3595 if (str=="aus")
3596 {
3597 if(QueryProp(P_VISUALBELL))
3598 write("Die Tonausgabe stand schon auf AUS.\n");
3599 else
3600 {
3601 SetProp(P_VISUALBELL,1);
3602 write("OK, Tonausgabe auf AUS gestellt.\n");
3603 }
3604 }
3605 else
3606 write("Syntax: ton [ein|aus]\n");
3607 return 1;
3608}
3609
3610static int set_screensize(string str)
3611{
3612 int size;
3613
3614 if (str && (str[0..2] == "abs" || str[0..2]=="rel")) {
3615 size = QueryProp(P_MORE_FLAGS);
3616 if (str[0..2] == "abs") {
3617 size |= E_ABS;
3618 write("Es wird beim Prompt die Zeilenzahl des Textes angegeben.\n");
3619 }
3620 else {
3621 size &= ~E_ABS;
3622 write("Es wird beim Prompt der prozentuale Anteil des Textes angegeben.\n");
3623 }
3624 SetProp(P_MORE_FLAGS, size);
3625 return 1;
3626 }
3627
3628 if ( str && (str=="auto" || sscanf( str, "auto %d", size )) ){
3629 if ( size > 0 ){
3630 write("Ungueltiger Wert! "
3631 "In Verbindung mit 'auto' sind nur negative Werte erlaubt.\n");
3632 return 1;
3633 }
3634
3635 SetProp( P_SCREENSIZE, size-1 );
3636
3637 write("Ok, Deine Zeilenzahl wird nun automatisch ermittelt (derzeit "+
3638 QueryProp(P_SCREENSIZE)+").\n"+
3639 break_string("Bitte beachte, dass dies nur einwandfrei "
3640 "funktioniert, wenn Dein Client Telnetnegotiations "
3641 "unterstuetzt (siehe auch \"hilfe telnegs\").") );
3642 return 1;
3643 }
3644
3645 if ( !str || str=="" || !sscanf( str, "%d", size ) || size < 0 || size > 100){
3646 write(break_string(
3647 sprintf("Mit dem Befehl 'zeilen <groesse>' kannst Du einstellen, "
3648 "wieviele Zeilen bei mehrseitigen Texten auf einmal ausgegeben "
3649 "werden. Die angegebene Groesse muss zwischen 0 und 100 liegen. "
3650 "Bei Groesse 0 wird einfach alles ausgegeben (ohne Pause). Mit "
3651 "der Einstellung 'auto' wird die Groesse automatisch ueber "
3652 "die Telnetnegotiations ermittelt (siehe auch 'hilfe telnegs'). "
3653 "Um nach einer Seite Text noch etwas Platz zu haben, kann man z.B. "
3654 "'zeilen auto -3' einstellen.\n"
3655 "Die Voreinstellung ist 20 Zeilen.\n"
3656 "Mit 'zeilen abs[olut]' und 'zeilen rel[ativ]' kannst Du fest"
3657 "legen, ob im Prompt bei langen Texten die aktuelle Zeilennummer "
3658 "oder eine prozentuale Angabe ausgegeben wird.\n"
3659 "Deine aktuelle Einstellung ist %d%s Zeilen (%s).",
3660 QueryProp(P_SCREENSIZE),
3661 Query(P_SCREENSIZE) < 0 ? " 'automatische'" : "",
3662 QueryProp(P_MORE_FLAGS) & E_ABS ? "absolut" : "relativ"),78,0,1));
3663 return 1;
3664 }
3665
3666 SetProp( P_SCREENSIZE, size );
3667
3668 printf( "Okay, Deine Zeilenzahl steht nun auf %d.\n", size );
3669 return 1;
3670}
3671
3672static int _query_screensize()
3673{
3674 int sz,rows;
3675
3676 if ( (sz=Query(P_SCREENSIZE)) >= 0 )
3677 return sz;
3678
3679 if ( !rows=QueryProp(P_TTY_ROWS) )
3680 return 0;
3681
3682 return (rows+=sz) >= 5 ? rows : 5;
3683}
3684
3685static int presay(string str)
3686{
3687 if (!str=_unparsed_args())
3688 write("Dein Presay ist jetzt geloescht.\n");
3689 else
3690 printf("Dein Presay lautet jetzt: \"%s\".\n",str=capitalize(str));
3691 SetProp(P_PRESAY,str);
3692 return 1;
3693}
3694
3695static int sethands(string str)
3696{
3697 mixed *hands;
3698
3699 if (!(str=_unparsed_args()))
3700 {
3701 write("sethands <message>\n");
3702 return 1;
3703 }
3704 if (str=="0")
3705 hands=RaceDefault(P_HANDS);
3706 if (!hands || !pointerp(hands))
3707 hands=Query(P_HANDS);
3708 hands[0]=" "+str;
3709 Set(P_HANDS,hands);
3710 write("Ok.\n");
3711 return 1;
3712}
3713
3714static int inform(string str)
3715{
3716 switch (str) {
3717 case "on":
3718 case "ein":
3719 case "an":
3720 if (Query(P_INFORMME))
3721 write("Das hattest Du schon so eingestellt.\n");
3722 else
3723 {
3724 write("Kuenftig wirst Du informiert, wenn jemand das "MUDNAME" verlaesst/betritt.\n");
3725 Set(P_INFORMME,1);
3726 }
3727 return 1;
3728 case "aus":
3729 case "off":
3730 if (!Query(P_INFORMME))
3731 write("Das hattest Du schon so eingestellt.\n");
3732 else
3733 {
3734 write("Ok.\n");
3735 Set(P_INFORMME,0);
3736 }
3737 return 1;
3738 case 0:
3739 write("Inform-Mode ist "+(Query(P_INFORMME)?"an":"aus")+"geschaltet.\n");
3740 return 1;
3741 }
3742 write("inform an oder inform aus, bitte.\n");
3743 return 1;
3744}
3745
3746void delayed_write(mixed *what)
3747{
3748 if (!pointerp(what)||!sizeof(what)||!pointerp(what[0]))
3749 return;
3750 tell_object(ME,what[0][0]);
3751 if (sizeof(what)>1&&sizeof(what[0])>1)
3752 call_out("delayed_write",what[0][1],what[1..]);
3753}
3754
3755void notify_player_change(string who, int rein, int invis)
3756{
3757 string *list,name;
3758 mixed mlist;
3759
3760 if (invis) name="("+who+")";
3761 else name=who;
3762
3763 if (Query(P_INFORMME))
3764 {
3765 if (rein)
3766 tell_object(ME,name+" ist gerade ins "MUDNAME" gekommen.\n");
3767 else
3768 tell_object(ME,name+" hat gerade das "MUDNAME" verlassen.\n");
3769 }
3770
3771 if(Query(P_WAITFOR_FLAGS) & (0x01))return ;
3772
3773 if(pointerp(list=Query(P_WAITFOR)) && sizeof(list) && member(list,who)!=-1)
3774 {
3775 if (!QueryProp(P_VISUALBELL))
3776 name+=sprintf("%c",7); // Char fuer Pieps an den String anhaengen.
3777 // Moechte der Spieler keine ASCII-Grafik sehen, wird diese Meldung ohne
3778 // Leerzeichen formatiert, so dass sie von Screenreadern vorgelesen wird.
3779 // Anderenfalls wuerde sie einzeln buchstabiert.
3780 if ( QueryProp(P_NO_ASCII_ART) )
3781 {
3782 delayed_write( ({ ({ sprintf("%s IST JETZT %sDA !!!\n",
3783 name, (rein?"":"NICHT MEHR ")) }) }) );
3784 }
3785 else
3786 {
3787 delayed_write( ({ ({ sprintf("%s I S T J E T Z T %sD A !!!\n",
3788 name, (rein?"":"N I C H T M E H R ")) }) }) );
3789 }
3790 }
3791
3792 if (rein && (sizeof(mlist=QueryProp(P_WAITFOR_REASON))) &&
3793 (mappingp(mlist)) && (mlist[who]))
3794 Show_WaitFor_Reason(who,invis);
3795}
3796
3797static int erwarte(string str)
3798{
3799 string *list,*str1;
3800 mixed mlist;
MG Mud User88f12472016-06-24 23:31:02 +02003801
3802 if (!mappingp(mlist=QueryProp(P_WAITFOR_REASON)))
3803 mlist=([]);
3804 if (!pointerp(list=Query(P_WAITFOR)))
3805 list=({});
3806
3807 if (!str || str=="-u")
3808 {
3809 if(Query(P_WAITFOR_FLAGS)&0x01)
3810 write("Du hast 'erwarte' temporaer deaktiviert.\n");
3811 write("Du erwartest jetzt");
3812 if (!sizeof(list))
3813 write(" niemanden mehr.\n");
3814 else
3815 {
3816 write(":\n");
3817 if (!str) list=sort_array(list,#'>);
3818 More(break_string(CountUp(list),78));
3819 }
3820 return 1;
3821 }
3822 if(str=="aus"){
3823 Set(P_WAITFOR_FLAGS,Query(P_WAITFOR_FLAGS)|0x01);
3824 write("Erwarte ist jetzt deaktiviert.\n");
3825 return 1;
3826 }
3827 if(str=="an" || str=="ein"){
3828 Set(P_WAITFOR_FLAGS,Query(P_WAITFOR_FLAGS)&0xFE);
3829 write("Erwarte ist jetzt aktiv.\n");
3830 return 1;
3831 }
3832
3833 str1=explode(_unparsed_args()||""," ");
3834 if (sizeof(str1)==1)
3835 {
3836 if (str1[0]!="wegen")
3837 {
3838 str=capitalize(lower_case(str));
3839 if (member(list,str)!=-1)
3840 {
3841 SetProp(P_WAITFOR_REASON,m_copy_delete(mlist,str));
3842 list-=({str});
3843 write(str+" aus der Liste entfernt.\n");
3844 } else
3845 {
3846 if (sizeof(list)>1000)
3847 {
3848 write("Du erwartest schon genuegend!\n");
3849 return 1;
3850 }
3851 list+=({str});
3852 write(str+" an die Liste angehaengt.\n");
3853 }
3854 Set(P_WAITFOR,list);
3855 }
3856 else
3857 {
Zesstraf253faa2018-07-27 13:05:13 +02003858 if (sizeof(mlist))
MG Mud User88f12472016-06-24 23:31:02 +02003859 {
3860 write("Du erwartest aus einem bestimmten Grund:\n");
Zesstraf253faa2018-07-27 13:05:13 +02003861 write(break_string(CountUp(sort_array(m_indices(mlist),
3862 #'>))+".",78));
MG Mud User88f12472016-06-24 23:31:02 +02003863 }
3864 else write("Du erwartest niemanden aus einem bestimmten Grund.\n");
3865 }
3866 return 1;
3867 }
3868 notify_fail("Falsche Syntax, siehe 'hilfe erwarte'!\n");
3869 if (str1[1]!="wegen") return 0;
3870 if (sizeof(str1)==2)
3871 Show_WaitFor_Reason(capitalize(lower_case(str1[0])),0);
3872 else {
3873 string s=capitalize(lower_case(str1[0]));
3874 if (sizeof(str1)==3 && (str1[2]=="nichts" || str1[2]=="loeschen"))
3875 if (!mlist[s])
3876 write("Du hast "+s+" aus keinem bestimmten Grund erwartet!\n");
3877 else
3878 {
3879 SetProp(P_WAITFOR_REASON,m_copy_delete(mlist,s));
3880 write("Du erwartest "+s+" aus keinem bestimmten Grund mehr!\n");
3881 }
3882 else
3883 {
Zesstra27649642018-07-27 12:59:25 +02003884 // Menge an erwarte-wegen Eintraegen begrenzen.
Zesstra5d9a0d72018-07-27 13:19:14 +02003885 int lim;
Zesstra27649642018-07-27 12:59:25 +02003886 if (IS_ARCH(ME)) lim=120;
3887 else if (IS_LEARNER(ME)) lim=80;
3888 else if (IS_SEER(ME)) lim=60;
3889 else lim=30;
3890 if (!mlist[s] && sizeof(mlist)>=lim)
MG Mud User88f12472016-06-24 23:31:02 +02003891 write("Sorry, aber Du erwartest schon genuegend Leute!\n");
3892 else
3893 {
Zesstra7204adc2018-07-27 13:16:04 +02003894 SetProp(P_WAITFOR_REASON, mlist+([s:implode(str1[2..80]," ")]));
MG Mud User88f12472016-06-24 23:31:02 +02003895 Show_WaitFor_Reason(s,0);
3896 }
3897 }
3898 }
3899 return 1;
3900}
3901
3902static int uhrmeldung(string str)
3903{
3904 if (!(str=_unparsed_args()))
3905 {
3906 str=QueryProp(P_CLOCKMSG);
3907 if (!str)
3908 {
3909 write("Du hast die Standard-Uhrmeldung.\n");
3910 return 1;
3911 }
3912 if( !stringp(str) ) str = sprintf("%O\n",str);
3913 printf("Deine Uhrmeldung ist:\n%s\n",str[0..<2]);
3914 return 1;
3915 }
3916 if (str=="0")
3917 {
3918 SetProp(P_CLOCKMSG,0);
3919 write("Ok, Du hast jetzt wieder die Standard-Meldung.\n");
3920 return 1;
3921 }
3922 if (sizeof(explode(str,"%d"))>2)
3923 {
3924 write("Fehler, es darf nur ein %d in der Meldung vorkommen.\n");
3925 return 1;
3926 }
3927 /* Mehrere %-Parameter verursachen das Abschalten der Uhr zur vollen Stunde.
3928 */
3929 if (sizeof(explode(str,"%"))>2)
3930 {
3931 write("Fehler: Zuviele %-Parameter in der Meldung.\n");
3932 return 1;
3933 }
3934 /* Nur ein %-Parameter, aber der falsche: nicht sinnvoll. */
3935 else
3936 {
3937 int i = strstr(str,"%",0);
3938 if ( i>-1 && ( i==sizeof(str)-1 || str[i+1]!='d'))
3939 {
3940 write("Fehler: Falscher %-Parameter in der Meldung.\n");
3941 return 1;
3942 }
3943 }
3944 str+="\n";
3945 SetProp(P_CLOCKMSG,str);
3946 write("Ok.\n");
3947 return 1;
3948}
3949
3950static int zeitzone(string str)
3951{
3952 int zt;
3953 if(!str || str==""){
3954 if(!(zt=QueryProp(P_TIMEZONE)))
3955 write("Du hast derzeit die gleiche Zeitzone wie das "MUDNAME" "+
3956 "eingestellt.\n");
3957 else if(zt>0)
3958 printf("Deine Zeitzone ist auf %d Stunden vor (oestlich) von Berlin "+
3959 "eingestellt.\n",zt);
3960 else
3961 printf("Deine Zeitzone ist auf %d Stunden nach (westlich) von "+
3962 "Berlin eingestellt.\n",-zt);
3963 return 1;
3964 }
3965 if(sscanf(str,"utc %d",zt)==1) zt=(zt-1)%24;
3966 else zt=to_int(str)%24;
3967
3968 SetProp(P_TIMEZONE,zt);
3969
3970 if(!zt)
3971 write("Du hast derzeit die gleiche Zeitzone wie das "MUDNAME" "+
3972 "eingestellt.\n");
3973 else if(zt>0)
3974 printf("Deine Zeitzone ist auf %d Stunden vor (oestlich) von Berlin "+
3975 "eingestellt.\n",zt);
3976 else
3977 printf("Deine Zeitzone ist auf %d Stunden nach (westlich) von "+
3978 "Berlin eingestellt.\n",-zt);
3979 return 1;
3980}
3981
3982static int emailanzeige(string str){
3983 notify_fail("Syntax: emailanzeige [alle|freunde|niemand]\n");
3984 if(!str || str==""){
3985 if(!(str=QueryProp(P_SHOWEMAIL)))str="Niemandem";
3986 else if(str=="alle")str="allen";
3987 else if(str=="freunde")str="Deinen Freunden";
3988 else if(str=="niemand")str="niemandem";
3989 else{
3990 SetProp(P_SHOWEMAIL,0);
3991 str="Niemandem";
3992 }
3993 write("Deine Email wird "+str+" angezeigt.\n");
3994 return 1;
3995 }
3996 else if(member(({"alle","freunde","niemand"}),str)==-1)return 0;
3997
3998 SetProp(P_SHOWEMAIL,str);
3999
4000 if(str=="alle")str="allen";
4001 else if(str=="freunde")str="Deinen Freunden";
4002 else str="niemandem";
4003 write("Deine Email wird "+str+" angezeigt.\n");
4004 return 1;
4005}
4006
4007static int zaubertraenke()
4008{
4009 More("/room/orakel"->TipListe());
4010 return 1;
4011}
4012
4013varargs static int angriffsmeldung(string arg) {
4014 if (arg=="ein" || arg=="an")
4015 SetProp(P_SHOW_ATTACK_MSG,1);
4016 else if (arg=="aus")
4017 SetProp(P_SHOW_ATTACK_MSG,0);
4018 if (QueryProp(P_SHOW_ATTACK_MSG))
4019 write("Du siehst saemtliche Angriffsmeldungen von Dir.\n");
4020 else
4021 write("Du siehst nur neue Angriffsmeldungen von Dir.\n");
4022 return 1;
4023}
4024
4025static mixed _query_localcmds()
4026{
4027 return ({({"zeilen","set_screensize",0,0}),
4028 ({"email","set_email",0,0}),
4029 ({"url","set_homepage",0,0}),
4030 ({"icq","set_icq",0,0}),
4031 ({"messenger", "set_messenger", 0, 0}),
4032 ({"ort","set_location",0,0}),
4033 ({"punkte","short_score",0,0}),
4034 ({"score","short_score",0,0}),
4035 ({"info","score",0,0}),
4036 ({"kurzinfo","very_short_score",0,0}),
4037 ({"quit","new_quit",0,0}),
4038 ({"ende","new_quit",0,0}),
4039 ({"disconnect","disconnect",0,0}),
4040 ({"schlaf","disconnect",1,0}),
4041 ({"speichern","save_character",0,0}),
4042 ({"save","save_character",0,0}),
4043 ({"toete","kill",0,0}),
4044 ({"angriffsmeldung","angriffsmeldung",0,0}),
4045 ({"passw","change_password",1,0}),
4046 ({"hilfe","help",1,0}),
4047 ({"selbstloeschung","self_delete",0,0}),
4048 ({"spielpause","spielpause",0,0}),
4049 ({"spieldauer","spieldauer",0,0}),
Arathorn3437e392016-08-26 22:41:39 +02004050 ({"idee","ReportError",0,0}),
4051 ({"typo","ReportError",0,0}),
4052 ({"bug","ReportError",0,0}),
MG Mud User88f12472016-06-24 23:31:02 +02004053 ({"fehler","fehlerhilfe",0,0}),
Arathorn3437e392016-08-26 22:41:39 +02004054 ({"md","ReportError",0,0}),
4055 ({"detail","ReportError",0,0}),
Bugfixa75344d2017-06-16 14:04:48 +02004056 ({"syntaxhinweis","ReportError",0,0}),
MG Mud User88f12472016-06-24 23:31:02 +02004057 ({"vorsicht","toggle_whimpy",0,0}),
4058 ({"stop","stop",0,0}),
4059 ({"kwho","kwho",0,0}),
4060 ({"kwer","kwho",0,0}),
4061 ({"kkwer","kkwho",0,0}),
4062 ({"kkwho","kkwho",0,0}),
4063 ({"who","who",0,0}),
4064 ({"wer","who",0,0}),
4065 ({"zeit","uhrzeit",0,0}),
4066 ({"uhrzeit","uhrzeit",0,0}),
4067 ({"weg","weg",0,0}),
4068 ({"wegmeldung", "wegmeldung", 0, 0}),
4069 ({"idlezeit", "idlezeit", 0, 0}),
4070 ({"finger","finger",0,0}),
4071 ({"muds","muds",0,0}),
4072 ({"emote","emote",0,0}),
4073 ({":","emote",1,0}),
4074 ({";","emote",1,0}),
4075 ({"remote","remote",0,SEER_LVL}),
4076 ({"r:","remote",1,0}),
4077 ({"r;","gremote",1,0}),
4078 ({"titel","set_title",0,0}),
4079 ({"review","review",0,SEER_LVL}),
4080 ({"setmin","setmin",0,SEER_LVL}),
4081 ({"setmout","setmout",0,SEER_LVL}),
4082 ({"setmmin","setmmin",0,SEER_LVL}),
4083 ({"setmmout","setmmout",0,SEER_LVL}),
4084 ({"sethands","sethands",0,SEER_LVL}),
4085 ({"presay","presay",0,SEER_LVL}),
4086 ({"extralook","extralook",0,SEER_LVL}),
4087 ({"fluchtrichtung","toggle_whimpy_dir",0,SEER_LVL}),
4088 ({"inform","inform",0,0}),
4089 ({"erwarte","erwarte",0,0}),
4090 ({"stty","stty",0,0}),
4091 ({"grafik", "set_ascii_art", 0, 0}),
4092 ({"uhrmeldung","uhrmeldung",0,0}),
4093 ({"zeitzone","zeitzone",0,0}),
4094 ({"behalte","behalte",0,0}),
4095 ({"zweitiemarkierung","zweitiemarkierung",0,0}),
4096 ({"emailanzeige","emailanzeige",0,0}),
4097 ({"topliste","topliste",0,0}),
4098 ({"ton","set_visualbell",0,0}),
4099 ({"telnegs","show_telnegs",0,0}),
4100 ({"spotte", "spotte", 0, 0}),
4101 ({"reise","reise",0,0}),
4102 ({"zaubertraenke","zaubertraenke",0,0}),
4103 ({"telnet","telnet_cmd",0,0}),
4104 })+
4105 command::_query_localcmds()+
4106 viewcmd::_query_localcmds()+
4107 comm::_query_localcmds()+
4108 skills::_query_localcmds()+
4109 description::_query_localcmds();
4110}
4111
4112static int _check_keep(object ob)
4113{
4114 return (ob->QueryProp(P_KEEP_ON_SELL))==geteuid(ME);
4115}
4116
4117static mixed _set_testplayer(mixed arg) {
4118 mixed res;
4119 object setob;
4120
4121 setob=this_player();
4122 if (!objectp(setob) || !query_once_interactive(setob))
4123 setob=this_interactive();
4124 if (!objectp(setob))
4125 setob=previous_object();
4126 if (setob && !IS_DEPUTY(setob)) {
4127 arg=geteuid(setob);
4128 if (!arg || arg=="NOBODY")
4129 arg=getuid(setob);
4130 arg=capitalize(arg);
4131 }
4132 res=Set(P_TESTPLAYER,arg);
4133 Set(P_TESTPLAYER,PROTECTED,F_MODE_AS);
4134 return res;
4135}
4136
4137int zweitiemarkierung(string arg)
4138{
4139 if (!QueryProp(P_SECOND))
4140 return _notify_fail("Aber Du bist doch gar kein Zweiti.\n"),0;
4141 notify_fail("Syntax: zweitiemarkierung [unsichtbar|sichtbar|name]\n");
4142 if (!arg)
4143 return 0;
4144 switch (arg)
4145 {
4146 case "unsichtbar" :
4147 SetProp(P_SECOND_MARK,-1);
4148 write("Jetzt sieht kein Spieler mehr, dass Du ein Zweiti bist.\n");
4149 return 1;
4150 case "sichtbar" :
4151 SetProp(P_SECOND_MARK,0);
4152 write("Jetzt sieht kein Spieler mehr, wessen Zweiti Du bist.\n");
4153 return 1;
4154 case "name" :
4155 SetProp(P_SECOND_MARK,1);
4156 write("Jetzt koennen alle sehen, wessen Zweiti Du bist.\n");
4157 return 1;
4158 }
4159 return 0;
4160}
4161
4162int topliste(string arg)
4163{
4164 if (!arg)
4165 {
4166 printf("Du hast Dich fuer die Topliste %s.\n",
4167 (QueryProp(P_NO_TOPLIST) ? "gesperrt" : "freigegeben"));
4168 return 1;
4169 }
4170 else if (member(({"j","ja","n","nein"}),arg)==-1)
4171 return _notify_fail("Syntax: topliste [ja|nein]\n"),0;
4172 if (arg[0]=='j')
4173 {
4174 SetProp(P_NO_TOPLIST,0);
4175 write("Du kannst jetzt (theoretisch) in der Topliste auftauchen.\n");
4176 }
4177 else
4178 {
4179 SetProp(P_NO_TOPLIST,1);
Zesstradd2d1982017-01-28 14:03:19 +01004180 "/secure/topliste"->DeletePlayer();
4181 write("Du wirst jetzt nicht (mehr) in den Toplisten auftauchen.\n");
MG Mud User88f12472016-06-24 23:31:02 +02004182 }
4183 Set(P_NO_TOPLIST,SAVE|PROTECTED,F_MODE_AS);
4184 return 1;
4185}
4186
4187int show_telnegs(string arg)
4188{
4189 if (!arg)
4190 {
4191 write("Du bekommst Aenderungen Deiner Fenstergroesse "+
4192 (QueryProp(P_TTY_SHOW)?"":"nicht ")+"angezeigt.\n");
4193 return 1;
4194 }
4195 if (member(({"ein","an","aus"}),arg)==-1)
4196 {
4197 write("Syntax: telnegs [ein|aus]\n");
4198 return 1;
4199 }
4200 if (arg=="ein" || arg=="an")
4201 {
4202 write("Du bekommst "+(QueryProp(P_TTY_SHOW)?"":"nun ")+
4203 "Aenderungen Deiner Fenstergroesse angezeigt.\n");
4204 Set(P_TTY_SHOW,1);
4205 return 1;
4206 }
4207 write("Du bekommst "+(QueryProp(P_TTY_SHOW)?"nun ":"")+
4208 "Aenderungen Deiner Fenstergroesse nicht "+
4209 (QueryProp(P_TTY_SHOW)?"mehr ":"")+"angezeigt.\n");
4210 Set(P_TTY_SHOW,0);
4211 return 1;
4212}
4213
4214private int set_keep_alive(string str) {
4215 if (str == "ein") {
4216 telnet_tm_counter = 240 / __HEART_BEAT_INTERVAL__;
4217 tell_object(this_object(), break_string(
4218 "An Deinen Client werden jetzt alle 4 Minuten unsichtbare Daten "
4219 "geschickt, um zu verhindern, dass Deine Verbindung zum "MUDNAME
4220 " beendet wird.", 78));
4221 }
4222 else if (str == "aus") {
4223 telnet_tm_counter = 0;
4224 tell_object(this_object(),break_string(
4225 "Du hast das Senden von unsichtbaren Daten (Keep-Alive-Pakete) an "
4226 "Deinen Client ausgeschaltet.",78));
4227 }
4228 else {
4229 if (!telnet_tm_counter)
4230 tell_object(this_object(), break_string(
4231 "An Deinen Client werden keine Keep-Alive-Pakete geschickt.",78));
4232 else
4233 tell_object(this_object(), break_string(
4234 "An Deinen Client werden alle 4 Minuten "
4235 "unsichtbare Daten geschickt, damit Deine Verbindung "
4236 "zum "MUDNAME" nicht beendet wird.",78));
4237 }
4238 return 1;
4239}
4240
4241private int print_telnet_rttime() {
4242 int rtt = QueryProp(P_TELNET_RTTIME);
4243 if (rtt>0)
4244 tell_object(ME, break_string(
4245 "Die letzte gemessene 'round-trip' Zeit vom MG zu Deinem Client "
4246 "und zurueck betrug " + rtt + " us.",78));
4247 else
4248 tell_object(ME, break_string(
4249 "Bislang wurde die 'round-trip' Zeit vom MG zu Deinem Client "
4250 "noch nicht gemessen oder Dein Client unterstuetzt dieses "
4251 "nicht.",78));
4252 return 1;
4253}
4254
4255int telnet_cmd(string str) {
4256 if (!str) return 0;
4257 string *args = explode(str, " ");
4258 string newargs;
4259 if (sizeof(args) > 1)
4260 newargs = implode(args[1..], " ");
4261 else
4262 newargs = "";
4263
4264 switch(args[0])
4265 {
4266 case "keepalive":
4267 return set_keep_alive(newargs);
4268 case "rttime":
4269 return print_telnet_rttime();
Zesstraab567652019-01-15 00:20:05 +01004270 case "tls":
Zesstra363b1382019-01-15 00:36:24 +01004271 if (tls_query_connection_state(ME) > 0)
Zesstraab567652019-01-15 00:20:05 +01004272 tell_object(ME,
4273 "Deine Verbindung zum Morgengrauen ist TLS-verschluesselt.\n");
4274 else
4275 tell_object(ME,
4276 "Deine Verbindung zum Morgengrauen ist nicht verschluesselt.\n");
4277 return 1;
MG Mud User88f12472016-06-24 23:31:02 +02004278 }
4279 return 0;
4280}
4281
4282int spotte( string str )
4283{
4284 _notify_fail( "Hier ist nichts, was Du verspotten koenntest!\n" );
4285 return 0;
4286}
4287
4288int behalte(string str)
4289{
4290 object ob,*obs;
4291 string s;
4292
4293 if (str)
4294 {
4295 if (str=="alles") {
4296 filter_objects(all_inventory(), "SetProp", P_KEEP_ON_SELL, getuid());
4297 write("Ok!\n");
4298 return 1;
4299 }
4300 if (str=="nichts") {
4301 filter_objects(all_inventory(), "SetProp", P_KEEP_ON_SELL, 0);
4302 write("Ok!\n");
4303 return 1;
4304 }
4305 if (!sizeof(obs=find_obs(str,PUT_GET_NONE)))
4306 {
4307 _notify_fail("Aber sowas hast Du nicht dabei!\n");
4308 return 0;
4309 }
4310 else ob=obs[0];
4311
4312 if (ob->QueryProp(P_KEEP_ON_SELL)==geteuid(ME))
4313 ob->SetProp(P_KEEP_ON_SELL,0);
4314 else
4315 ob->SetProp(P_KEEP_ON_SELL,geteuid(ME));
4316
4317 // erneut abfragen, da sich der Wert nicht geaendert haben muss
4318 if (ob->QueryProp(P_KEEP_ON_SELL)==geteuid(ME))
4319 write(break_string(sprintf("Ok, Du wirst %s jetzt bei 'verkaufe alles' "
4320 "behalten.\n",ob->name(WEN)),78));
4321 else
4322 write(break_string(sprintf("Ok, Du wirst %s beim naechsten 'verkaufe "
4323 "alles' mitverkaufen!\n",ob->name(WEN)),78));
4324
4325 return 1;
4326 }
4327 s=make_invlist(ME,filter(all_inventory(ME),#'_check_keep)); //'));
4328 More(s);
4329 return 1;
4330}
4331
4332static int _query_lep()
4333{
4334 int val;
4335 val = LEPMASTER->QueryLEP();
4336 Set( P_LEP, val );
4337 return val;
4338}
4339
4340static mixed _set_fraternitasdonoarchmagorum(mixed arg)
4341{
4342 if (!intp(arg)) return -1;
4343
4344 if ((!previous_object(1)||object_name(previous_object(1))!=FAO_MASTER) &&
4345 (!this_interactive() || !IS_ARCH(this_interactive())))
4346 return -1;
4347
4348 if (!intp(arg)) return -1;
4349
4350 log_file("fao/P_FAO",sprintf("%s - %s P_FAO gesetzt auf %O\n",
4351 dtime(time()),query_real_name(),arg) );
4352 return Set(P_FAO,arg);
4353}
4354
4355nomask void set_realip(string str)
4356{
4357 if(previous_object() && strstr(object_name(previous_object()),"/secure")==0)
4358 {
4359 realip=str;
4360 }
4361}
4362
4363nomask string query_realip()
4364{
4365 return realip ? realip : "";
4366}
4367
4368mixed _query_netdead_env() {
4369 return ndead_location || ndead_l_filename;
4370}