blob: 2dc06017e22b43ecedb0c7a72943f862b3d0a80e [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// player/comm.c-- basic player communiction commands
4//
5// $Id: comm.c 9576 2016-06-18 15:00:01Z Zesstra $
6#pragma strong_types
7#pragma save_types
8#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +02009//#pragma range_check
10
11inherit "/std/living/comm";
12inherit "/std/player/channel";
13inherit "/std/player/comm_structs";
14
15#include <input_to.h>
16
17#define NEED_PROTOTYPES
18#include <player/quest.h>
19#include <player/gmcp.h>
20#include <living/description.h>
Zesstra8b5320e2022-02-18 21:10:26 +010021#include <player/comm.h>
MG Mud User88f12472016-06-24 23:31:02 +020022#undef NEED_PROTOTYPES
23
24#include <sys_debug.h>
25
26#include <thing/properties.h>
MG Mud User88f12472016-06-24 23:31:02 +020027#include <player/base.h>
28
29#include <properties.h>
30#include <config.h>
31#include <ansi.h>
32#include <wizlevels.h>
33#include <language.h>
34#include <udp.h>
35#include <defines.h>
36#include <daemon.h>
37#include <strings.h>
38#include <regexp.h>
39#include <interactive_info.h>
Zesstra3a261e52022-02-10 14:00:31 +010040#include <ansi.h>
41#include <assert.h>
MG Mud User88f12472016-06-24 23:31:02 +020042
43#define TELLHIST_DISABLED 0
44#define TELLHIST_NO_MESSAGE 1
45#define TELLHIST_ENABLED 2
46#define TELLHIST_LONGLIFE 3
47
48#define ECHO_COST 50
49#define ERWIDER_PARAM ","
50
51#define ZDEBUG(x) if (find_player("zesstra"))\
52 efun::tell_object(find_player("zesstra"),"CommDBG: "+x+"\n")
53
54private int tell_history_enabled = TELLHIST_NO_MESSAGE;
55private nosave mapping tell_history=([]);
56private nosave string *commreceivers = ({});
57private nosave string last_comm_partner;
58private nosave int last_beep_time;
59
60// Statusreporte aktiviert? Binaere Flags (s. set_report())
61private int stat_reports;
62// interner Cache fuer die LP/KP/Gift-Werte fuer die Statusreport-Ausgaben
63// Eintraege (in dieser Reihenfolge): P_HP, P_SP, Giftstatus
64// Initialisierung erfolgt beim ersten Report nach Login
65private nosave mixed *report_cache;
66
67// Puffer fuer Kobold.
68private nosave struct msg_buffer_s kobold = (<msg_buffer_s>
69 buf: allocate(32),
70 index: -1,);
MG Mud User88f12472016-06-24 23:31:02 +020071
Zesstra3a261e52022-02-10 14:00:31 +010072// Colourmap
73// TODO: spaeter konfigurierbar machen
74private mapping build_colourmap(string ttype="ansi");
75private nosave mapping colourmap = build_colourmap();
76
MG Mud User88f12472016-06-24 23:31:02 +020077varargs string name(int casus, int demonst);
78
79//local property prototypes
80static int _query_intermud();
81public int RemoveIgnore(string ign);
82public int AddIgnore(string ign);
83
84public varargs int ReceiveMsg(string msg, int msg_type, string msg_action,
85 string msg_prefix, object origin);
86
87// erzeugt sortierte Liste an Kommunikationspartnern
88private string *sorted_commpartners(int reversed);
89
MG Mud User88f12472016-06-24 23:31:02 +020090void create()
91{
92 ::create();
Bugfix3afcb792022-01-21 22:32:42 +010093 Set(P_ALERT, SAVE, F_MODE_AS);
MG Mud User88f12472016-06-24 23:31:02 +020094 Set(P_EARMUFFS, 0);
95 Set(P_EARMUFFS, SAVE, F_MODE);
96 Set(P_EARMUFFS, SECURED, F_MODE);
97 Set(P_INTERMUD, SAVE, F_MODE);
98 Set(P_IGNORE, ([]), F_VALUE);
99 Set(P_IGNORE, SAVE, F_MODE);
100 Set(P_BUFFER, SAVE, F_MODE);
101 Set(P_MESSAGE_PREPEND, SAVE, F_MODE_AS);
102 Set(P_MESSAGE_BEEP, SAVE, F_MODE_AS);
103}
104
105void create_super()
106{
107 set_next_reset(-1);
108}
109
Zesstra3a261e52022-02-10 14:00:31 +0100110private mapping build_colourmap(string ttype)
111{
112 mapping res = ([0:""]);
113 switch(ttype)
114 {
115 case "dumb":
116 return res;
117 case "ansi":
118 res = ([ 0:ANSI_NORMAL, "normal": ANSI_NORMAL,
119 "bold": ANSI_BOLD, "underlined": ANSI_UNDERL,
120 "blink": ANSI_BLINK, "invers": ANSI_INVERS,
121 "black": ANSI_BLACK, "red": ANSI_RED,
122 "green": ANSI_GREEN, "yellow": ANSI_YELLOW,
123 "blue": ANSI_BLUE, "purple": ANSI_PURPLE,
124 "cyan": ANSI_CYAN, "white": ANSI_WHITE,
125 "bg_black": ANSI_BG_BLACK, "bg_red": ANSI_BG_RED,
126 "bg_green": ANSI_BG_GREEN, "bg_yellow": ANSI_BG_YELLOW,
127 "bg_blue": ANSI_BG_BLUE, "bg_purple": ANSI_BG_PURPLE,
128 "bg_cyan": ANSI_BG_CYAN, "bg_white": ANSI_BG_WHITE,
129 "mention": ANSI_BOLD+ANSI_BG_BLUE,
130 ]);
131 break;
132 case "vt100":
133 res += ([0:ANSI_NORMAL, "normal": ANSI_NORMAL,
134 "bold": ANSI_BOLD, "underlined": ANSI_UNDERL,
135 "blink": ANSI_BLINK, "invers": ANSI_INVERS,
136 "mention": ANSI_BOLD,
137 ]);
138 break;
139 default:
140 assert(1, "Ungueltiger Terminaltyp in build_colourmap");
141 }
142 return res;
143}
144
145protected void set_colourmap(string ttype="ansi")
146{
147 colourmap = build_colourmap(ttype);
148}
149
Zesstra0681c732020-10-31 19:45:47 +0100150// called from base.c in Reconnect()
151protected void reconnect() {
152 // Cache fuer den report zuruecksetzen, der koennte veraltet sein (insb.
153 // falls in der letzten Session GMCP benutzt wurde und jetzt nicht).
154 report_cache = 0;
155}
156
MG Mud User88f12472016-06-24 23:31:02 +0200157protected void updates_after_restore(int newflag) {
Zesstra3a261e52022-02-10 14:00:31 +0100158 // Colourmap aktualisieren nach Restore
159 colourmap = build_colourmap(QueryProp(P_TTY));
160
MG Mud User88f12472016-06-24 23:31:02 +0200161 // Altes Ignoriere loeschen...
162 mixed ign = Query(P_IGNORE,F_VALUE);
163 if (!mappingp(ign))
164 {
165 if (pointerp(ign))
Bugfixb1d9b4d2021-09-14 20:07:04 +0200166 ReceiveNotify(break_string(
MG Mud User88f12472016-06-24 23:31:02 +0200167 "Deine Ignoriere-Einstellungen wurden soeben geloescht, "
168 "weil es eine Aktualisierung der Ignorierefunktion gab, "
169 "bei der eine Konversion der Daten leider nicht "
170 "moeglich war.",78), 0);
171
172 Set(P_IGNORE, ([]), F_VALUE);
173 }
174}
175
Zesstra2504b2d2020-05-22 12:30:17 +0200176static int set_report(string str)
177{
MG Mud User88f12472016-06-24 23:31:02 +0200178 int canflags = QueryProp(P_CAN_FLAGS);
MG Mud User88f12472016-06-24 23:31:02 +0200179 if(!str)
180 {
Zesstracf8f2952020-05-22 12:07:52 +0200181 if (stat_reports)
182 {
183 string *res=({});
184 if (stat_reports & DO_REPORT_HP)
185 res+=({"Lebenspunkte"});
186 if (stat_reports & DO_REPORT_SP)
187 res+=({"Konzentrationspunkte"});
188 if (stat_reports & DO_REPORT_POISON)
189 res+=({"Vergiftungen"});
190 if (stat_reports & DO_REPORT_WIMPY)
191 res+=({"Vorsicht"});
MG Mud User88f12472016-06-24 23:31:02 +0200192
Zesstracf8f2952020-05-22 12:07:52 +0200193 tell_object(ME,break_string(
MG Mud User88f12472016-06-24 23:31:02 +0200194 "Dir werden jetzt Veraenderungen Deiner "
195 +CountUp(res) + " berichtet.",78));
Zesstra86ec63b2020-05-22 12:09:56 +0200196 if (GMCP_Status("MG.char") || GMCP_Status("char")
197 || GMCP_Status("Char"))
198 {
199 tell_object(ME,break_string(
200 "Achtung: Dein Client laesst sich den Report per GMCP "
Zesstra2504b2d2020-05-22 12:30:17 +0200201 "(s. 'hilfe GMCP') uebermitteln. Daher wird er Dir nicht "
Zesstra86ec63b2020-05-22 12:09:56 +0200202 "in der Textausgabe des Spiels angezeigt! Moechtest Du "
203 "dies nicht, schalte bitte in Deinem Client GMCP-Module mit "
204 "Namen wie 'MG.char', 'char', 'Char' oder aehnliche aus."));
205 }
MG Mud User88f12472016-06-24 23:31:02 +0200206 }
207 else
208 tell_object(ME,
209 "Alle Statusreports sind ausgeschaltet.\n");
210
211 return 1;
212 }
Zesstra2504b2d2020-05-22 12:30:17 +0200213 else if (str == "aus")
214 {
215 if (stat_reports & DO_REPORT_HP || stat_reports & DO_REPORT_WIMPY)
216 {
MG Mud User88f12472016-06-24 23:31:02 +0200217 string s="";
Zesstra2504b2d2020-05-22 12:30:17 +0200218 if (stat_reports & DO_REPORT_HP)
219 {
MG Mud User88f12472016-06-24 23:31:02 +0200220 str="ebenfalls ";
221 tell_object(ME, "Der Report wurde ausgeschaltet.\n");
222 }
Zesstra2504b2d2020-05-22 12:30:17 +0200223 if ( stat_reports & DO_REPORT_WIMPY )
224 {
MG Mud User88f12472016-06-24 23:31:02 +0200225 tell_object(ME, "Der Vorsicht-Report wurde "+s+
226 "ausgeschaltet.\n");
227 }
228 stat_reports=0;
229 }
Zesstra2504b2d2020-05-22 12:30:17 +0200230 else
231 {
MG Mud User88f12472016-06-24 23:31:02 +0200232 tell_object(ME, "Der Report ist bereits ausgeschaltet.\n");
233 }
234 return 1;
235 }
Zesstra2504b2d2020-05-22 12:30:17 +0200236 else if (str == "ein")
237 {
238 if ( stat_reports & DO_REPORT_HP )
239 {
MG Mud User88f12472016-06-24 23:31:02 +0200240 tell_object(ME, "Der Report ist bereits eingeschaltet.\n");
241 return 1;
242 }
243 tell_object(ME, "Der Report wurde eingeschaltet.\n");
244 stat_reports |= DO_REPORT_HP;
Zesstra2504b2d2020-05-22 12:30:17 +0200245 if (!(canflags & CAN_REPORT_SP))
246 {
247 if (QueryQuest("Hilf den Gnarfen")==1)
248 {
MG Mud User88f12472016-06-24 23:31:02 +0200249 SetProp(P_CAN_FLAGS, canflags | CAN_REPORT_SP);
250 stat_reports |= DO_REPORT_SP;
251 }
Zesstra2504b2d2020-05-22 12:30:17 +0200252 else
253 {
MG Mud User88f12472016-06-24 23:31:02 +0200254 tell_object(ME, break_string(
255 "Fuer den Statusreport Deiner Konzentration musst Du jedoch "
256 "zunaechst die Quest \"Hilf den Gnarfen\" bestehen.",78));
257 }
258 }
Zesstra2504b2d2020-05-22 12:30:17 +0200259 else
260 {
MG Mud User88f12472016-06-24 23:31:02 +0200261 stat_reports |= DO_REPORT_SP;
262 }
Zesstra2504b2d2020-05-22 12:30:17 +0200263 if (!(canflags & CAN_REPORT_POISON))
264 {
265 if (QueryQuest("Katzenjammer")==1)
266 {
MG Mud User88f12472016-06-24 23:31:02 +0200267 SetProp(P_CAN_FLAGS, canflags | CAN_REPORT_POISON);
268 stat_reports |= DO_REPORT_POISON;
269 }
Zesstra2504b2d2020-05-22 12:30:17 +0200270 else
271 {
MG Mud User88f12472016-06-24 23:31:02 +0200272 tell_object(ME, break_string(
273 "Fuer den Statusreport Deiner Vergiftung musst Du jedoch "
274 "zunaechst die Quest \"Katzenjammer\" bestehen.",78));
275 }
276 }
Zesstra2504b2d2020-05-22 12:30:17 +0200277 else
278 {
MG Mud User88f12472016-06-24 23:31:02 +0200279 stat_reports |= DO_REPORT_POISON;
280 }
281 // Cache loeschen, damit beim naechsten Report-Event alle Daten neu
282 // eingetragen werden muessen. Muss beim Einschalten des Reports
283 // passieren, weil auch in der inaktiven Zeit weiterhin Aenderungen in
284 // status_report() eingehen, so dass der Cache zwar erst einmal leer ist,
285 // aber beim Wiedereinschalten nicht mehr ungueltig waere und somit
286 // veraltete Daten an den Spieler ausgegeben werden. Im unguenstigsten
287 // Fall wuerde das sogar dazu fuehren, dass die veralteten Daten lange
288 // Zeit nicht aktualisiert werden, wenn z.B. P_HP == P_MAX_HP, so dass
289 // kein P_HP-Event mehr eingeht.
290 report_cache=0;
Zesstra2504b2d2020-05-22 12:30:17 +0200291 // Fall-through fuer Statusausgabe
MG Mud User88f12472016-06-24 23:31:02 +0200292 }
Zesstra2504b2d2020-05-22 12:30:17 +0200293 else if (str == "vorsicht")
294 {
295 if (!(canflags & CAN_REPORT_WIMPY))
296 {
297 if (QueryQuest("Schrat kann nicht einschlafen")==1)
298 {
MG Mud User88f12472016-06-24 23:31:02 +0200299 SetProp(P_CAN_FLAGS, canflags | CAN_REPORT_WIMPY);
300 tell_object(ME, "Der Vorsicht-Report wurde eingeschaltet.\n");
301 stat_reports |= DO_REPORT_WIMPY;
302 }
Zesstra2504b2d2020-05-22 12:30:17 +0200303 else
304 {
MG Mud User88f12472016-06-24 23:31:02 +0200305 tell_object(ME, break_string(
306 "Fuer den Statusreport Deiner Vorsicht musst Du "
307 "zunaechst die Quest \"Schrat kann nicht einschlafen\" "
308 "bestehen.",78));
309 }
310 }
311 else
312 {
313 stat_reports |= DO_REPORT_WIMPY;
314 }
315 // fuer Seher auch Bericht der Fluchtrichtung einschalten.
316 if ((stat_reports & DO_REPORT_WIMPY)
317 && !(stat_reports & DO_REPORT_WIMPY_DIR)
318 && ((canflags & CAN_REPORT_WIMPY) || IS_SEER(ME)))
319 {
Zesstra2504b2d2020-05-22 12:30:17 +0200320 stat_reports |= DO_REPORT_WIMPY_DIR;
MG Mud User88f12472016-06-24 23:31:02 +0200321 }
Zesstra2504b2d2020-05-22 12:30:17 +0200322 // Fall-through fuer Statusausgabe
MG Mud User88f12472016-06-24 23:31:02 +0200323 }
324 // sendet einmalig genau jetzt den konfigurierten report. Kann zum testen
325 // (von Triggern) oder beim Login benutzt werden, wenn man einen initialen
326 // Datenbestand erhalten will.
327 else if (str=="senden")
328 {
329 // Es wird Ausgabe von LP und Vorsicht getriggert, das sendet beide
330 // Zeilen.
331 status_report(DO_REPORT_HP, QueryProp(P_HP));
332 status_report(DO_REPORT_WIMPY, QueryProp(P_WIMPY));
333 return 1;
334 }
335 else
336 return 0;
337 // nur aktuellen Zustand berichten
338 set_report(0);
339 return 1;
340}
341
342private string get_poison_desc(int p) {
343 string ret;
344 if ( intp(p) ) {
345 switch(p) {
346 case 0: ret="keins"; break;
347 case 1..3: ret="leicht"; break;
348 case 4..8: ret="gefaehrlich"; break;
349 default: ret="sehr ernst"; break;
350 }
351 return ret;
352 }
353 else return "(nicht verfuegbar)";
354}
355
356// sprintf()-Formatstrings fuer die Reportausgabe.
357#define REPORTLINE "LP: %3d, KP: %3s, Gift: %s.\n"
358#define REPORTLINE_WIMPY "Vorsicht: %d, Fluchtrichtung: %s.\n"
359// Defines zur Adressierung der Cache-Eintraege
360#define REP_HP 0
361#define REP_SP 1
362#define REP_POISON 2
363
364protected void status_report(int type, mixed val) {
365 // Wenn der Spieler GMCP hat und das sich um die Information kuemmert,
366 // erfolgt keine textuelle Ausgabe mehr. Daher return, wenn GMCP_Char()
367 // erfolg vermeldet hat.
368 int flags = QueryProp(P_CAN_FLAGS);
369 switch (type) {
370 case DO_REPORT_HP:
371 if (GMCP_Char( ([ P_HP: val ]) ) ) return;
372 break;
373 case DO_REPORT_SP:
374 if (!(flags & CAN_REPORT_SP)) return;
375 if (GMCP_Char( ([ P_SP: val ]) ) ) return;
376 break;
377 case DO_REPORT_POISON:
378 if (!(flags & CAN_REPORT_POISON)) return;
379 if (GMCP_Char( ([ P_POISON: val ]) ) ) return;
380 break;
381 case DO_REPORT_WIMPY:
382 if (!(flags & CAN_REPORT_WIMPY)) return;
383 if (GMCP_Char( ([ P_WIMPY: val ]) ) ) return;
384 break;
385 case DO_REPORT_WIMPY_DIR:
386 if (!(flags & CAN_REPORT_WIMPY_DIR)) return;
387 if (GMCP_Char( ([ P_WIMPY_DIRECTION: val ]) ) ) return;
388 break;
389 }
390
391 // konventionelle textuelle Ausgabe des Reports ab hier.
392 if (!(type & stat_reports))
393 return;
394
395 if ( !report_cache ) {
396 report_cache = ({
397 QueryProp(P_HP),
398 (stat_reports&DO_REPORT_SP) ? to_string(QueryProp(P_SP)) : "###",
399 (stat_reports&DO_REPORT_POISON) ?
400 get_poison_desc(QueryProp(P_POISON)) : "(nicht verfuegbar)"
401 });
402 }
403
404 switch(type) {
405 // LP berichten: Cache aktualisieren und Meldung ausgeben.
406 case DO_REPORT_HP:
407 report_cache[REP_HP]=val;
408 tell_object(ME, sprintf(REPORTLINE, report_cache[REP_HP],
409 report_cache[REP_SP], report_cache[REP_POISON]));
410 break;
411 // KP berichten: Wenn der Spieler den Report freigeschaltet hat,
412 // wird bei Aenderungen gemeldet. Wenn nicht, aendert sich nur der
413 // Cache-Eintrag. So wird verhindert, dass ein Spieler ueber KP-
414 // Veraenderungen auch dann informiert wuerde, wenn er den KP-Report
415 // gar nicht benutzen koennte.
416 case DO_REPORT_SP:
417 report_cache[REP_SP]=to_string(val);
418 tell_object(ME, sprintf(REPORTLINE, report_cache[REP_HP],
419 report_cache[REP_SP], report_cache[REP_POISON]));
420 break;
421 // Giftstatus berichten: Wenn der Giftreport freigeschaltet ist,
422 // Cache aktualisieren und berichten. Wenn nicht, aendert sich nur
423 // der Cache-Eintrag. Erlaeuterung hierzu s.o. beim KP-Report.
424 case DO_REPORT_POISON:
425 report_cache[REP_POISON] = get_poison_desc(val);
426 tell_object(ME, sprintf(REPORTLINE, report_cache[REP_HP],
427 report_cache[REP_SP], report_cache[REP_POISON]));
428 break;
429 // Vorsicht-Report: kann ohne weitere Abfragen ausgegeben werden, da
430 // alle noetigen Checks schon zu Beginn dieser Funktion erledigt wurden.
431 // Lediglich der Inhalt der Meldung muss abhaengig vom Seherstatus
432 // konfiguriert werden.
433 case DO_REPORT_WIMPY:
434 string res;
435 if (IS_SEER(ME)) {
436 // QueryProp() aus Kostengruenden im if(), damit die Aufruf-
437 // Haeufigkeit zumindest ein wenig reduziert wird.
438 string dir = QueryProp(P_WIMPY_DIRECTION)||"keine";
439 res = sprintf(REPORTLINE_WIMPY, val, dir);
440 }
441 else
442 res = sprintf(REPORTLINE_WIMPY, val, "(nicht verfuegbar)");
443 tell_object(ME, res);
444 break;
445 // Fluchtrichtungs-Report: wird nur bei Sehern ausgegeben, damit
446 // nicht auch Spieler eine VS-/FR-Meldung bekommen, wenn z.B. eine
447 // externe Manipulation der Fluchtrichtung stattfindet, sie aber den
448 // Report mangels Seherstatus gar nicht freigeschaltet haben.
449 case DO_REPORT_WIMPY_DIR:
450 if (IS_SEER(ME)) {
451 if (!val) val = "keine";
452 tell_object(ME,sprintf(REPORTLINE_WIMPY, QueryProp(P_WIMPY), val));
453 }
454 break;
455 }
456}
457
458#undef REPORTLINE
459#undef REPORTLINE_WIMPY
460#undef REP_HP
461#undef REP_SP
462#undef REP_POISON
463
464private string permutate(string msg)
465{
466 // Kontrollzeichen rausfiltern. *seufz*
467 msg = regreplace(msg,"[[:cntrl:]]","",RE_PCRE|RE_GLOBAL);
468 object ob=QueryProp(P_PERM_STRING);
469 if (!objectp(ob))
470 return msg;
471
Zesstra04f613c2019-11-27 23:32:54 +0100472 return ({string})ob->permutate_string(msg)||"";
MG Mud User88f12472016-06-24 23:31:02 +0200473}
474
475// neue nachricht an den Kobold anhaengen
476// Rueckgabewerte: MSG_BUFFER_FULL oder MSG_BUFFERED
477private int add_to_kobold(string msg, int msg_type, string msg_action,
478 string msg_prefix, object origin)
479{
480 // Nachricht soll im Kobold gespeichert werden.
481 // Kobold speichert Rohdaten und gibt spaeter das ganze auch wieder via
482 // ReceiveMsg() aus - dabei wird MSG_DONT_BUFFER | MSG_DONT_STORE gesetz,
483 // damit keine erneute Speicher in Kobold oder Komm-History erfolgt.
484
485 // wenn der Puffer zu klein ist, Groesse verdoppeln, wenn noch unterhalb
486 // des Limits.
487 if (kobold->index >= sizeof(kobold->buf)-1) {
488 if (sizeof(kobold->buf) < MAX_KOBOLD_LIMIT)
489 kobold->buf += allocate(sizeof(kobold->buf));
490 else
491 return MSG_BUFFER_FULL;
492 }
493 kobold->index = kobold->index +1;
494 // neue Nachricht an den Puffer anhaengen.
495 string sendername = query_once_interactive(origin) ?
496 origin->query_real_name() :
497 origin->name(WER) || "<Unbekannt>";
Zesstraa5fda4a2022-01-06 17:31:44 +0100498 kobold->buf[kobold->index] = (<kobold_msg_s> msg: msg,
MG Mud User88f12472016-06-24 23:31:02 +0200499 type : msg_type, action : msg_action, prefix : msg_prefix,
500 sendername : sendername);
501 return MSG_BUFFERED;
502}
503
504private void _flush_cache(int verbose) {
505 // nur mit genug Evalticks ausgeben.
506 if (get_eval_cost() < 100000) return;
507 if (kobold->index >= 0)
508 {
509 ReceiveMsg("Ein kleiner Kobold teilt Dir folgendes mit:",
510 MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_BUFFER,
511 0, 0, this_object());
512 int prepend = QueryProp(P_MESSAGE_PREPEND);
513 foreach(int i: 0 .. kobold->index) // '0 ..' ist wichtig!
514 {
Zesstraa5fda4a2022-01-06 17:31:44 +0100515 struct kobold_msg_s msg = kobold->buf[i];
MG Mud User88f12472016-06-24 23:31:02 +0200516 // dies ist dient der Fehlerabsicherung, falls es nen Fehler (z.B. TLE)
517 // in der Schleife unten gab: dann ist index nicht auf -1 gesetzt
518 // worden, aber einige Nachrichten sind schon geloescht.
519 if (!structp(msg)) continue;
520 // Ausgabe via efun::tell_object(), weil die Arbeit von ReceiveMsg()
Zesstra3a261e52022-02-10 14:00:31 +0100521 // schon getan wurde. Allerdings muessen wir uns noch um den Umbruch
522 // und Farben kuemmern.
523 msg->msg = terminal_colour(msg->msg, colourmap);
MG Mud User88f12472016-06-24 23:31:02 +0200524 if ((msg->type) & MSG_DONT_WRAP)
525 msg->msg = (msg->prefix ? msg->prefix : "") + msg->msg;
526 else
527 {
528 int bsflags = msg->type & MSG_ALL_BS_FLAGS;
529 if (prepend)
530 bsflags |= BS_PREPEND_INDENT;
531 msg->msg = break_string(msg->msg, 78, msg->prefix, bsflags);
532 }
533 efun::tell_object(this_object(), msg->msg);
534 kobold->buf[i]=0;
535 }
536 kobold->index=-1;
537 }
538 else if (verbose)
539 {
540 ReceiveMsg("Der kleine Kobold hat leider nichts Neues fuer Dich.",
541 MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_BUFFER,
542 0, 0, this_object());
543 }
544}
545
546varargs int cmd_kobold(string arg)
547{
548 switch(arg)
549 {
550 case "ein":
551 SetProp(P_BUFFER, 1);
552 printf("Der Kobold merkt sich jetzt alles!\n"); break;
553 case "aus":
554 SetProp(P_BUFFER, 0);
555 printf("Der Kobold wird Dich nicht stoeren!\n"); break;
556 default: if(arg) printf("Der Kobold sagt: kobold ein oder kobold aus\n");
557 }
558 _flush_cache(1);
559 return 1;
560}
561
562public int TestIgnoreSimple(string *arg)
Zesstrade642d22019-11-23 17:22:34 +0100563{ mapping ignore;
MG Mud User88f12472016-06-24 23:31:02 +0200564
565 if (!pointerp(arg) || !mappingp(ignore=Query(P_IGNORE,F_VALUE)))
566 return 0;
567 foreach(string s: arg)
568 {
569 if (member(ignore,s))
570 return 1;
571 }
572 return 0;
573}
574
575//TODO: deprecated - entfernen, wenn Message() entfernt wird.
576private int check_ignore(mixed ignore, string verb, string name)
577{
578 if (ignore == verb)
579 return 1;
580 ignore = explode(ignore, ".");
581 return ((sizeof(ignore) > 1) &&
582 (name == ignore[0] && member(ignore[1..], verb) != -1));
583}
584
Zesstra3a261e52022-02-10 14:00:31 +0100585// Die Nachricht kommt mit einem Alert oder Mention. comm_beep() prueft, ob
586// ein Piepston ausgegeben werden soll (langfristig andere Benachrichtigungen
587// geplant!).
588// Ueblicherweise werden nur alle <P_MESSAGE_BEEP> Sekunden Toene
589// uebermittelt.
590private void comm_beep(string msg_action, int mention=0)
Bugfix60f5bc62022-01-21 11:09:56 +0100591{
Zesstra1cc6cf32022-02-09 11:49:31 +0100592 // Wenn Alerts komplett abgeschaltet sind, gibts nix.
593 int alert_config = ({int})QueryProp(P_ALERT);
594 if (alert_config & AL_NO_SOUND)
595 return; // kein ton
596 // und maximal alle P_MESSAGE_BEEP Sekunden aufmerksam machen; bei 0s ist
597 // jedes Mal erlaubt.
Zesstra04f613c2019-11-27 23:32:54 +0100598 int beep_interval=({int})QueryProp(P_MESSAGE_BEEP);
Zesstra1cc6cf32022-02-09 11:49:31 +0100599 if ((time()-last_beep_time) < beep_interval)
600 return;
601 int required;
602 switch(msg_action)
Bugfix60f5bc62022-01-21 11:09:56 +0100603 {
Zesstra1cc6cf32022-02-09 11:49:31 +0100604 case MA_TELL:
605 required |= MB_TELL;
606 break;
607 case MA_SAY:
608 required |= MB_SAY;
609 break;
610 case MA_CHANNEL:
611 required |= MB_CHANNEL;
612 break;
613 case MA_SHOUT:
614 required |= MB_SHOUT;
615 break;
616 default:
617 // Alle anderen Aktionen, die keine gesonderten Aktionsfilter haben
618 required |= MB_MISC;
619 break;
Bugfix60f5bc62022-01-21 11:09:56 +0100620 }
Zesstra3a261e52022-02-10 14:00:31 +0100621 if (mention)
622 required |= MB_MENTION;
623
Zesstra1cc6cf32022-02-09 11:49:31 +0100624 // wenn in alert min. ein notwendiges Flag drin ist darf gepiepst werden
625 if (required & alert_config)
626 {
627 last_beep_time = time();
628 binary_message(b"\a", 1);
629 }
MG Mud User88f12472016-06-24 23:31:02 +0200630}
631
632private varargs void add_to_tell_history( string uid, int sent, int recv,
633 string message, string indent, int flags )
634{
635 /* tell_history ist ein Mapping mit UIDs der Gespraechspartner als Key.
636 Als Wert ist eine Strukur vom Typ chat_s eingetragen.
637 Strukturen chat_s und stored_msg_s sind in /std/player/comm_structs.c
638 definiert.
639 TODO fuer spaeter, gerade keine Zeit fuer:
640 Als Wert ist ein Array von chat_s enthalten, wobei das 0. Element das
641 jeweils juengste Gespraech mit diesem Gespraechspartner ist und alle
642 weiteren Elemente in der zeitlichen Reihenfolge kommen (also letztes
643 Element ist aeltestes Gespraech).
644 */
645
646 //TODO: Entfernen, wenn das nicht mehr passiert.
647 if (!stringp(uid))
648 {
649 ReceiveMsg(sprintf(
650 "\nadd_to_tell_history(): got bad uid argument %O."
651 "sent: %d, recv: %d, flags: %d, msg: %s",
Zesstra996bafe2022-02-14 22:42:39 +0100652 uid, sent, recv, flags, message),MT_DEBUG|MSG_BS_LEAVE_LFS,0,0,ME);
MG Mud User88f12472016-06-24 23:31:02 +0200653 }
Zesstraa31cd5c2016-12-17 20:11:07 +0100654
Zesstra996bafe2022-02-14 22:42:39 +0100655 // Gespraechspartner fuer erwidere auch ohne tmhist speichern.
Zesstraa31cd5c2016-12-17 20:11:07 +0100656 if (flags & (MSGFLAG_TELL|MSGFLAG_RTELL))
MG Mud User88f12472016-06-24 23:31:02 +0200657 last_comm_partner = uid;
658
659 // ist ein sortiertes Array von max. MAX_SAVED_CHATS Groesse, welches die
660 // Spieler enthaelt, denen man schon was mitgeteilt hat. Aktuellste am
661 // Anfang.
662 if (sent) {
663 if (!sizeof(commreceivers))
664 commreceivers = ({uid});
665 else if (commreceivers[0] != uid) {
666 // nur wenn der aktuelle Partner nicht am Anfang steht, muss man hier was
667 // tun. Comm-Partner an den Anfang stellen und ggf. alten Eintrag
668 // entfernen.
669 // TODO: Effizienter gestalten.
670 commreceivers = ({uid}) + (commreceivers-({uid}));
671 // ggf. kuerzen. (wenn !tell_history_enabled, wird es ggf. unten
672 // gemacht, denn die Hist muss min. alle UID enthalten, die auch in
673 // commreceivers drin sind.)
674 if (!tell_history_enabled && sizeof(commreceivers) > MAX_SAVED_CHATS)
675 commreceivers = commreceivers[0..MAX_SAVED_CHATS];
676 }
677 }
678
Zesstra996bafe2022-02-14 22:42:39 +0100679 // mit eingeschalteter History weitere Details speichern.
MG Mud User88f12472016-06-24 23:31:02 +0200680 if (!tell_history_enabled)
681 return;
682
683 if (!indent && message[<1] == 10)
684 message = message[..<2];
685
686 struct chat_s chat;
687 // Gespraechspartner unbekannt?
688 if (!member(tell_history, uid)) {
689 // zuviele Gespraeche in Hist? >= ist Absicht weil ja gleich noch eins
690 // dazu kommt.
691 if (sizeof(tell_history) >= MAX_SAVED_CHATS) {
692 string deluid;
693 int zeit = __INT_MAX__;
694 foreach(string tuid, chat : tell_history) {
695 // aeltestes Gespraech suchen
696 if (zeit > chat->time_last_msg) {
697 deluid = tuid;
698 zeit = chat->time_last_msg;
699 }
700 }
701 // aeltestes Gespraech raus.
702 m_delete(tell_history, deluid);
703 if (member(commreceivers,deluid)>-1)
704 commreceivers-=({deluid});
705 }
706 // neues Gespraech anlegen
707 chat = (<chat_s> uid: uid, time_first_msg: time(),
708 time_last_msg: time(),
709 sentcount: sent, recvcount: recv,
710 msgbuf: 0, ptr: 0 );
711 tell_history[uid] = chat;
712 }
713 else {
714 // Gespraechspartner bekannt, altes Gespraech weiterbenutzen
715 chat = tell_history[uid];
716 chat->time_last_msg = time();
717 chat->sentcount += sent;
718 chat->recvcount += recv;
719 }
720
Zesstra996bafe2022-02-14 22:42:39 +0100721 // ggf. auch INhalte von Gespraechen speichern
MG Mud User88f12472016-06-24 23:31:02 +0200722 if (tell_history_enabled < TELLHIST_ENABLED)
723 return;
724
725 // ggf. Array fuer Messages anlegen
726 if (!pointerp(chat->msgbuf))
727 chat->msgbuf = allocate(MAX_SAVED_MESSAGES);
728
729 // Message-Struktur ermitteln oder neu anlegen
730 struct stored_msg_s msg;
731 if (!structp(chat->msgbuf[chat->ptr])) {
732 // neue Struct ins Array schreiben
733 chat->msgbuf[chat->ptr] = msg = (<stored_msg_s>);
734 }
735 else {
736 // alte Struct ueberschreiben
737 msg = chat->msgbuf[chat->ptr];
738 }
739 // Index auf naechste Messagestruktur ermitteln
740 chat->ptr = (chat->ptr + 1) % MAX_SAVED_MESSAGES;
741 // Message speichern
742 msg->msg = message;
743 msg->prefix = indent;
744 msg->timestamp = time();
745}
746
Zesstra996bafe2022-02-14 22:42:39 +0100747protected void clear_tell_history(int force)
MG Mud User88f12472016-06-24 23:31:02 +0200748{
749 /* Nach einem "schlafe ein" werden die gespeicherten Mitteilungen geloescht,
750 sofern der Spieler nichts abweichendes eingestellt hat. */
751
Zesstra996bafe2022-02-14 22:42:39 +0100752 // bei manuellem Loeschen (force==1) immer loeschen, ansonsten nur, wenn die
753 // History nicht "long-life" ist.
754 if (tell_history_enabled < TELLHIST_LONGLIFE || force)
755 {
756 tell_history = ([]);
757 commreceivers = ({});
758 }
MG Mud User88f12472016-06-24 23:31:02 +0200759}
760
761protected void reset(void)
762{
763 /* Wird 15 Minuten nach dem Verlust der Verbindung aufgerufen. Falls der
764 Spieler nicht inzwischen eine Verbindung wiederhergestellt hat, werden
765 wie bei einem "schlafe ein" die Mitteilungen geloescht. */
766
767 if (!interactive())
Zesstra996bafe2022-02-14 22:42:39 +0100768 clear_tell_history(0);
MG Mud User88f12472016-06-24 23:31:02 +0200769
770}
771
772// gerufen, wenn zielgerichtet mit jemandem kommuniziert wird _und_ das
773// Ergebnis des ReceiveMsg() geprueft werden und eine Meldung ausgegeben
774// werden soll.
775private void _send(object ob, string msg, int msg_type,
776 string msg_action, string msg_prefix)
777{
778 int res = ob->ReceiveMsg(msg, msg_type, msg_action, msg_prefix, ME);
Zesstra8b5320e2022-02-18 21:10:26 +0100779
MG Mud User88f12472016-06-24 23:31:02 +0200780 switch(res) {
781 case MSG_DELIVERED:
782 break; // nix machen
783 case MSG_BUFFERED:
Zesstra62b4a862022-12-23 20:08:16 +0100784 ReceiveMsg(ob->Name(WER) + " moechte gerade nicht gestoert werden. "
MG Mud User88f12472016-06-24 23:31:02 +0200785 "Die Mitteilung wurde von einem kleinen Kobold in Empfang "
786 "genommen. Er wird sie spaeter weiterleiten!",
787 MT_NOTIFICATION, msg_action, 0, this_object());
788 break;
789 case MSG_IGNORED:
790 case MSG_VERB_IGN:
791 case MSG_MUD_IGN:
792 ReceiveMsg(ob->Name(WER) + " hoert gar nicht zu, was Du sagst.",
793 MT_NOTIFICATION, msg_action, 0, this_object());
794 break;
795 case MSG_SENSE_BLOCK:
796 ReceiveMsg(ob->Name(WER) + " kann Dich leider nicht wahrnehmen.",
797 MT_NOTIFICATION, msg_action, 0, this_object());
798 break;
799 case MSG_BUFFER_FULL:
Zesstra62b4a862022-12-23 20:08:16 +0100800 ReceiveMsg(ob->Name(WER) + " moechte gerade nicht gestoert werden. "
MG Mud User88f12472016-06-24 23:31:02 +0200801 "Die Mitteilung ging verloren, denn der Kobold kann sich "
802 "nichts mehr merken!", MT_NOTIFICATION, msg_action,
803 0, this_object());
804 break;
805 default:
806 ReceiveMsg(ob->Name(WER) + " hat Deine Nachricht leider nicht "
807 "mitbekommen.", MT_NOTIFICATION, msg_action, 0, this_object());
808 break;
809 }
810}
811
Zesstra8b5320e2022-02-18 21:10:26 +0100812// aehnlich wie _send(), aber gerufen, wenn die Empfaengerin nicht online ist,
813// aber ein Kobold-Vault deponiert hat und versucht werden soll, dort eine
814// Nachricht zu hinterlegen.
815private void _send_to_kobold(string pluid, string msg, int msg_type,
816 string msg_action, string msg_prefix)
817{
818 int res = KOBOLD->DepositMsg(pluid, msg, msg_type, msg_action,
819 msg_prefix, ME);
820 switch(res) {
821 case MSG_BUFFERED:
822 ReceiveMsg(sprintf("%s ist gerade nicht online, aber Deine Botschaft "
823 "wurde von einem fuer kleinen Kobold aufgeschrieben und er wird "
824 "versuchen, sie %s bei naechster Gelegenheit zu uebermitteln. "
825 "Der Kobold macht Dich darauf aufmerksam, dass er aber keine "
826 "Uebermittlung garantieren kann.",
827 capitalize(pluid), capitalize(pluid)),
828 MT_NOTIFICATION, msg_action, 0, this_object());
829 break;
830 case MSG_BUFFER_FULL:
831 ReceiveMsg(sprintf("%s ist gerade nicht online und leider ist auf "
832 "der Schriftrolle des kleinen Kobolds kein Platz mehr fuer "
833 "Deine Botschaft. Vielleicht schickst Du %s besser einen Brief.",
834 capitalize(pluid), capitalize(pluid)),
835 MT_NOTIFICATION, msg_action, 0, this_object());
836 break;
837 default:
838 ReceiveMsg(sprintf("%s ist gerade nicht online und leider konnte "
839 "sich der kleine Kobold Deine Botschaft nicht merken. "
840 "Vielleicht schickst Du %s besser einen Brief.",
841 capitalize(pluid),capitalize(pluid)),
842 MT_NOTIFICATION, msg_action, 0, this_object());
843 break;
844 }
845}
846
MG Mud User88f12472016-06-24 23:31:02 +0200847// Ausgabe an das Objekt selber und Aufzeichnung in der Kommhistory, falls
848// noetig. Wird bei _ausgehenden_ Nachrichten im eigenen Objekt gerufen, damit
849// die Nachricht ggf. in den Kommhistory erfasst wird.
850// TODO: entfernen, wenn alles Aufrufer ersetzt sind durch ReceiveMsg().
851protected varargs int _recv(object ob, string message, int flag, string indent)
852{
853 write(break_string(message, 78, indent,
854 QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0));
855 if ((flag & MSGFLAG_TELL || flag & MSGFLAG_REMOTE) &&
856 query_once_interactive(ob))
857 {
858 if (flag & MSGFLAG_WHISPER)
859 add_to_tell_history(getuid(ob), 1, 0,
860 "Du fluesterst " + ob->name(WEM) + " aus der Ferne etwas zu.", 0,
861 flag);
862 else
863 add_to_tell_history(getuid(ob), 1, 0, message, indent, flag);
864 }
865 return 1;
866}
867
868// <sender> sollte ein Objekt sein. In seltenen Faellen (z.B.
869// Fehlerbehandlung) ist es jedoch auch mal ein String.
870varargs int Message(string msg, int flag, string indent,
871 string cname, mixed sender)
872{
873 object ti;
874 string verb, reply, *ignore, tin;
875 int em, te;
876 mixed deaf;
877
878 // Bei den Kanaelen 'Debug' und 'Entwicklung' kann man gezielt Bugs
879 // einzelner Magier ignorieren. Dazu wird der Kanalname zum 'verb',
880 // damit 'ignoriere name.debug' funktioniert.
881 if( flag == MSGFLAG_CHANNEL ){
882 if((msg[1..5] == "Debug" || msg[1..11] == "Entwicklung"
883 || msg[1..9]=="Warnungen"))
884 {
885 // Missbrauch der Variable 'ignore' als Zwischenspeicher
886 ignore = regexplode( msg, ":| |\\]" );
887 verb = lower_case(ignore[0][1..]);
888 tin = lower_case(ignore[2]);
889 }
890 else
891 {
892 if(cname)
893 verb=lower_case(cname);
894 else
895 verb=query_verb();
896 if( ti = this_interactive() )
897 {
898 tin = getuid(this_interactive());
899 }
900 else
901 {
902 //falls doch kein Objekt...
903 if (objectp(sender))
904 tin=lower_case(sender->name(RAW)||"<Unbekannt>");
905 }
906 }
907 }
908 else {
909 if( ti = this_interactive() )
910 tin = getuid(this_interactive());
911 verb = query_verb();
912 }
913
914 te = flag & (MSGFLAG_TELL | MSGFLAG_WHISPER);
915
916 // fuer "erwidere"
917 if (ti && (flag & MSGFLAG_TELL || flag & MSGFLAG_REMOTE)) {
918 if (!ti->QueryProp(P_INVIS)||IS_LEARNER(ME)) {
919 if (flag & MSGFLAG_WHISPER)
920 add_to_tell_history(getuid(ti), 0, 1,
921 capitalize((((IS_LEARNER(ti) && !ti->QueryProp(P_INVIS) &&
922 (ti->QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ?
923 ti->QueryProp(P_PRESAY) : "") + ti->name()) || "") +
924 " fluestert Dir aus der Ferne etwas zu.", 0, flag, 0);
925 else
926 add_to_tell_history(getuid(ti), 0, 1, msg, indent, flag, 0);
927 }
928 }
929 // Hoert der Spieler nicht?
930 em = (ti &&
931 (te || flag & MSGFLAG_SHOUT) &&
932 (QueryProp(P_EARMUFFS) &&
933 (query_wiz_level(ti) < QueryProp(P_EARMUFFS))));
934 ignore = (pointerp(ignore = QueryProp(P_IGNORE)) ? ignore : ({}));
935
936 // Werden der Sender oder das Verb ignoriert?
937 if(!ti && tin && flag == MSGFLAG_CHANNEL)
938 {
939 if((member(ignore, tin) != -1))
940 {
941 return MESSAGE_IGNORE_YOU;
942 }
943 if(verb && sizeof(filter(ignore, #'check_ignore, verb, tin)) )
944 {
945 return MESSAGE_IGNORE_YOU;
946 }
947 }
948 if (ti && (member(ignore, getuid(ti)) != -1)) {
949 if(te && (IS_LEARNER(ti)||!QueryProp(P_INVIS)))
950 efun::tell_object(ti, capitalize(name())+
951 " hoert gar nicht zu, was Du sagst.\n");
952 return MESSAGE_IGNORE_YOU;
953 }
954 if(tin && verb &&
955 sizeof(filter(ignore, #'check_ignore/*'*/, verb, tin)))
956 {
957 if(ti && verb[0..2] != "ruf" && verb[0..3] != "mruf" &&
958 verb[0..3] != "echo" && verb[0] != '-' && !(flag & MSGFLAG_CHANNEL) )
959 efun::tell_object(ti, name()+" wehrt \""+verb+"\" ab.\n");
960 return MESSAGE_IGNORE_VERB;
961 }
962 if (flag & MSGFLAG_RTELL) {
963 int at;
964
965 verb = lower_case(old_explode(msg, " ")[0][1..]);
966 at = member(verb, '@');
967 /* verb wird hier eh missbraucht, also auch fuer ein intermud-erwidere*/
968 add_to_tell_history(verb, 0, 1, msg, indent, flag, 0);
969
970 if ((member(ignore, verb) >= 0) || (member(ignore,verb[0..at]) >= 0))
971 return MESSAGE_IGNORE_YOU;
972 else if (at > 0 && member(ignore, verb[at..]) >= 0)
973 return MESSAGE_IGNORE_MUD;
974 }
975
976 // Taubheit/Oropax
977 te |= (flag & MSGFLAG_SAY);
978
979 if (QueryProp(P_DEAF) && (flag & MSGFLAG_DEAFCHK) && !(flag & MSGFLAG_CHIST)) {
980 deaf = QueryProp(P_DEAF);
981 if (te)
982 reply = stringp(deaf) ?
983 capitalize(sprintf(deaf, name())) :
984 capitalize(name())+" ist momentan leider taub.\n";
985 }
986 else if (em)
987 reply = capitalize(name())+" hat Oropax in den Ohren.\n";
988
989 msg = break_string(msg, 78, indent,
990 (QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0) | BS_LEAVE_MY_LFS);
991
992 if(QueryProp(P_BUFFER) &&
993 (deaf ||
994 query_editing(this_object()) ||
995 query_input_pending(this_object())))
996 {
997 deaf = MESSAGE_DEAF;
998 if(flag & MSGFLAG_CACHE)
999 {
1000 if(!stringp(reply))
1001 reply = name()+" moechte gerade nicht gestoert werden.\n";
1002
1003 msg = msg[0..<2]+" [" + strftime("%H:%M",time()) + "]\n";
1004
1005 int res = add_to_kobold(msg, 0, 0, 0,
1006 objectp(sender) ? sender : ME);
1007 if(res == MSG_BUFFERED)
1008 {
1009
1010 reply += "Die Mitteilung wurde von einem kleinen Kobold in Empfang "+
1011 "genommen.\nEr wird sie spaeter weiterleiten!";
1012 deaf = MESSAGE_CACHE;
1013 }
1014 else {
1015 reply += "Die Mitteilung ging verloren, denn "+
1016 "der Kobold kann sich nichts mehr merken!";
1017 deaf = MESSAGE_CACHE_FULL;
1018 }
1019 if(ti && (IS_LEARNER(ti)||!QueryProp(P_INVIS)))
1020 efun::tell_object(ti, reply+"\n");
1021 }
1022 return deaf;
1023 }
1024 else if((deaf || em) &&
1025 ( (flag & MSGFLAG_RTELL) ||
1026 (ti && (IS_LEARNER(ti)||!QueryProp(P_INVIS))))) {
1027 if (te && ti)
1028 efun::tell_object(ti, reply);
1029 return MESSAGE_DEAF;
1030 }
1031
1032 _flush_cache(0);
1033 if(te && QueryProp(P_AWAY))
1034 msg = msg[0..<2]+" [" + strftime("%H:%M",time()) + "]\n";
1035
Zesstra1cc6cf32022-02-09 11:49:31 +01001036 if(!objectp(sender) || sender != ME)
Bugfix60f5bc62022-01-21 11:09:56 +01001037 {
Zesstra1cc6cf32022-02-09 11:49:31 +01001038 if (flag & MSGFLAG_SAY)
1039 comm_beep(MA_SAY);
1040 else if (flag & MSGFLAG_TELL)
1041 comm_beep(MA_TELL);
1042 else if (flag & MSGFLAG_CHANNEL)
1043 comm_beep(MA_CHANNEL);
1044 else if (flag & MSGFLAG_SHOUT)
1045 comm_beep(MA_SHOUT);
MG Mud User88f12472016-06-24 23:31:02 +02001046 }
1047 efun::tell_object(ME, msg);
1048 return MESSAGE_OK;
1049}
1050
1051static int ignoriere(string str)
1052{
1053 str = _unparsed_args(1);
1054 mapping ignore=Query(P_IGNORE, F_VALUE);
1055
1056 if (!str)
1057 {
1058 string* ignarr = m_indices(ignore);
1059 if (!sizeof(ignarr))
1060 tell_object(ME, "Du ignorierst niemanden.\n");
1061 else
1062 ReceiveMsg("Du ignorierst:\n"
1063 + break_string(CountUp(map(sort_array(ignarr, #'> ),
1064 #'capitalize )
1065 ) + ".",78),
1066 MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE|MSG_DONT_WRAP,
1067 0,0,this_object());
1068 return 1;
1069 }
1070 // trim spaces from args and convert to lower case.
1071 str = lower_case(trim(str, TRIM_BOTH));
1072
1073 if (member(ignore, str))
1074 {
1075 RemoveIgnore(str);
1076 tell_object(ME, sprintf("Du ignorierst %s nicht mehr.\n", capitalize(str)));
1077 }
1078 else if (sizeof(ignore)>100)
1079 {
1080 tell_object(ME, "Du ignorierst schon genuegend!\n");
1081 }
1082 else if (AddIgnore(str) == 1)
1083 {
1084 tell_object(ME,
1085 sprintf("Du ignorierst jetzt %s.\n", capitalize(str)));
1086 }
1087 else
1088 {
1089 tell_object(ME,
1090 sprintf("'%s' kannst Du nicht ignorieren.\n",str));
1091 }
1092 return 1;
1093}
1094
1095
Zesstra1cc6cf32022-02-09 11:49:31 +01001096private int _alert_filter_flags(int flag, string text)
Bugfix60f5bc62022-01-21 11:09:56 +01001097{
1098 return (flag & QueryProp(P_ALERT));
1099}
1100
Zesstra1cc6cf32022-02-09 11:49:31 +01001101static int _msg_beep(string str)
1102{
1103 int beep_interval;
1104
1105 notify_fail(
1106 "Syntax:\n"
1107 "- klingelton <1 bis 3600 Sekunden>\n"
1108 "- klingelton aus\n"
1109 "- klingelton ein\n"
1110 "- klingelton <+/-><tm / sag / ebenen / ruf / erwaehnung / sonstige / alle / >\n");
1111
1112 if(!sizeof(str))
1113 return 0;
1114 if (regmatch(str,"^[[:alpha:]]", RE_PCRE))
Bugfix60f5bc62022-01-21 11:09:56 +01001115 {
MG Mud User88f12472016-06-24 23:31:02 +02001116 if (str=="aus")
Zesstra1cc6cf32022-02-09 11:49:31 +01001117 SetProp(P_ALERT, QueryProp(P_ALERT) | AL_NO_SOUND);
1118 else if (str=="ein")
1119 SetProp(P_ALERT, QueryProp(P_ALERT) & ~AL_NO_SOUND);
Bugfix60f5bc62022-01-21 11:09:56 +01001120 else
1121 {
1122 mapping flags = ([
Zesstra1cc6cf32022-02-09 11:49:31 +01001123 "tm": MB_TELL, "teilemit": MB_TELL,
1124 "sag": MB_SAY, "sage": MB_SAY,
1125 "ebene": MB_CHANNEL, "ebenen": MB_CHANNEL,
1126 "ruf": MB_SHOUT, "rufe": MB_SHOUT,
Zesstra3a261e52022-02-10 14:00:31 +01001127 "erwaehnung": MB_MENTION, "erwaehnungen": MB_MENTION,
Zesstra1cc6cf32022-02-09 11:49:31 +01001128 "sonstige": MB_MISC, "sonstiges": MB_MISC,
1129 "alle": MB_ALL, "alles": MB_ALL,
1130 ]);
Bugfix60f5bc62022-01-21 11:09:56 +01001131 foreach(string part : explode(str, " ") - ({""}))
1132 {
1133 if(!(part[1..] in flags)) continue;
1134 if(part[0] == '+')
1135 {
1136 SetProp(P_ALERT,
1137 QueryProp(P_ALERT) | flags[part[1..]]);
1138 }
1139 else if(part[0] == '-')
1140 {
1141 SetProp(P_ALERT,
1142 QueryProp(P_ALERT) & ~ flags[part[1..]]);
1143 }
1144 }
1145 }
MG Mud User88f12472016-06-24 23:31:02 +02001146 }
Zesstra1cc6cf32022-02-09 11:49:31 +01001147 else
1148 {
1149 beep_interval = to_int(str);
1150 if(beep_interval >= 0)
1151 {
1152 SetProp(P_MESSAGE_BEEP, beep_interval);
1153 }
1154 }
MG Mud User88f12472016-06-24 23:31:02 +02001155
Zesstra593b2c72019-11-27 23:37:03 +01001156 beep_interval=({int})QueryProp(P_MESSAGE_BEEP);
Bugfix60f5bc62022-01-21 11:09:56 +01001157 mapping text = ([
1158 MB_SAY: "sage",
1159 MB_TELL: "teile mit",
1160 MB_CHANNEL: "Ebenenmeldungen",
Zesstra3a261e52022-02-10 14:00:31 +01001161 MB_MENTION: "Erwaehnungen",
Zesstra1cc6cf32022-02-09 11:49:31 +01001162 MB_SHOUT: "rufe",
1163 MB_MISC: "sonstige",]);
1164 string types = CountUp(map(filter(m_indices(text), #'_alert_filter_flags), text));
Bugfix60f5bc62022-01-21 11:09:56 +01001165 if(!sizeof(types))
1166 {
1167 types = "nichts";
1168 }
1169 ReceiveNotify(
1170 "Klingelton bei "
1171 + types
Zesstra1cc6cf32022-02-09 11:49:31 +01001172 + (beep_interval ? ", alle " + beep_interval + " Sekunden." : ", immer.")
1173 + (QueryProp(P_ALERT) & AL_NO_SOUND ? " Allerdings sind Toene insgesamt "
1174 "bei Dir abgeschaltet. (\'hilfe ton\')" : ""),
Bugfix60f5bc62022-01-21 11:09:56 +01001175 query_verb());
MG Mud User88f12472016-06-24 23:31:02 +02001176 return 1;
1177}
1178
1179static int _msg_prepend(string str) {
MG Mud User88f12472016-06-24 23:31:02 +02001180 notify_fail("Syntax: senderwiederholung ein/aus\n");
1181 if (stringp(str)) {
1182 if (str=="aus")
1183 SetProp(P_MESSAGE_PREPEND,1);
1184 else if (str=="ein")
1185 SetProp(P_MESSAGE_PREPEND,0);
1186 else return 0;
1187 }
1188
Bugfixb1d9b4d2021-09-14 20:07:04 +02001189 ReceiveNotify("Senderwiederholung bei Mitteilungen: "+
Zesstra04f613c2019-11-27 23:32:54 +01001190 (({int})QueryProp(P_MESSAGE_PREPEND) ? "aus" : "ein")+".",
MG Mud User88f12472016-06-24 23:31:02 +02001191 query_verb());
1192
1193 return 1;
1194}
1195
1196static int _communicate(mixed str, int silent)
1197{
1198 string verb;
1199 string myname;
1200 string msg;
1201
1202 if (!str || extern_call()) str=_unparsed_args()||"";
1203 /* str=_unparsed_args()||""; */
1204 verb = query_verb();
1205 if(stringp(verb) && verb[0] == '\'') str = verb[1..] + " " + str;
1206 if (str==""||str==" "||!str)
1207 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001208 ReceiveNotify("Was willst Du sagen?",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001209 return 1;
1210 }
1211 msg=permutate(str);
1212
1213 myname=(((QueryProp(P_INVIS)||!IS_LEARNER(ME))||
1214 !(QueryProp(P_CAN_FLAGS)&CAN_PRESAY)?
1215 "":QueryProp(P_PRESAY))+name())||"";
1216
1217 // an alles im Raum senden. (MT_LISTEN, weil dies gesprochene Kommunikation
1218 // ist, keine MT_COMM)
Zesstrabd1236a2022-02-09 22:35:59 +01001219 send_room(environment(), msg, MT_LISTEN|MSG_ALERT, MA_SAY,
MG Mud User88f12472016-06-24 23:31:02 +02001220 capitalize(myname)+" sagt: ", ({this_object()}) );
1221
1222 if(!silent)
1223 {
1224 ReceiveMsg(msg, MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE,
1225 MA_SAY, "Du sagst: ", ME);
1226 }
1227 return 1;
1228}
1229
1230static int _shout_to_all(mixed str)
1231{
1232 string pre, myname, realname, wizards_msg, players_msg;
1233 string wizard_prefix, player_prefix;
1234 int chars;
1235
1236 if (!(str=_unparsed_args()))
1237 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001238 ReceiveNotify("Was willst Du rufen?",MA_SHOUT);
MG Mud User88f12472016-06-24 23:31:02 +02001239 return 1;
1240 }
1241 chars=sizeof(str)/2;
1242 if (chars<4) chars=4;
1243 pre = (!IS_LEARNER(ME) ||
1244 QueryProp(P_INVIS) ||
1245 !(QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ? "" : QueryProp(P_PRESAY);
1246 realname = capitalize((pre + capitalize(getuid()))||"");
1247 myname = capitalize(pre + name()||"");
1248 if (QueryProp(P_INVIS))
1249 realname = "("+realname+")";
1250
1251 wizards_msg = permutate(str);
1252 wizard_prefix = myname+" ruft: ";
1253
1254 if(QueryProp(P_FROG)) {
1255 players_msg = "Quaaak, quaaaaak, quuuuaaaaaaaaaaaaaaaaaaaak !!";
1256 player_prefix = myname+" quakt: ";
1257 }
1258 else {
1259 players_msg = wizards_msg;
1260 player_prefix = wizard_prefix;
1261 }
1262
1263 if(!IS_LEARNER(this_player()))
1264 {
1265 if(QueryProp(P_GHOST)) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001266 ReceiveNotify("So ganz ohne Koerper bekommst Du keinen Ton heraus.",
MG Mud User88f12472016-06-24 23:31:02 +02001267 MA_SHOUT);
1268 return 1;
1269 }
1270 if (QueryProp(P_SP) <(chars+20))
1271 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001272 ReceiveNotify("Du musst erst wieder magische Kraefte sammeln.",
MG Mud User88f12472016-06-24 23:31:02 +02001273 MA_SHOUT);
Bugfixb1d9b4d2021-09-14 20:07:04 +02001274 ReceiveNotify("Tip: Benutz doch mal die Ebenen (Hilfe dazu mit 'hilfe "
MG Mud User88f12472016-06-24 23:31:02 +02001275 "Ebenen').", MA_SHOUT);
1276 return 1;
1277 }
1278 SetProp(P_SP, QueryProp(P_SP) - chars - 20);
1279 }
1280
1281 ReceiveMsg(wizards_msg, MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE,
Zesstrabd1236a2022-02-09 22:35:59 +01001282 MA_SHOUT, "Du rufst: ", ME);
MG Mud User88f12472016-06-24 23:31:02 +02001283
1284 foreach ( object ob : users()-({this_object()}) )
1285 if ( IS_LEARNER(ob) )
Zesstrabd1236a2022-02-09 22:35:59 +01001286 ob->ReceiveMsg(wizards_msg, MT_LISTEN|MT_FAR|MSG_ALERT, MA_SHOUT,
1287 wizard_prefix, this_object());
MG Mud User88f12472016-06-24 23:31:02 +02001288 else
Zesstrabd1236a2022-02-09 22:35:59 +01001289 ob->ReceiveMsg(players_msg, MT_LISTEN|MT_FAR|MSG_ALERT, MA_SHOUT,
1290 player_prefix, this_object());
MG Mud User88f12472016-06-24 23:31:02 +02001291
1292 return 1;
1293}
1294
1295varargs int _tell(string who, mixed msg)
1296{
1297 object ob;
1298 string away,myname,ret;
MG Mud User88f12472016-06-24 23:31:02 +02001299 string *xname;
1300 int i,visflag;
1301
1302 if (extern_call() && this_interactive()!=ME) return 1;
1303 if (!who || !msg) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001304 ReceiveNotify("Was willst Du mitteilen?",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001305 return 1;
1306 }
1307
1308 if(who == ERWIDER_PARAM)
1309 {
1310 if (!last_comm_partner)
1311 {
1312 _notify_fail("Du hast aber noch keine Mitteilungen erhalten, auf die "
1313 "Du was erwidern\nkoenntest.\n");
1314 return 0;
1315 }
1316 who=last_comm_partner;
1317 }
1318
1319 // teile .x mit teilt bisherigen Gespraechspartnern etwas mit.
1320 if (who == ".")
1321 who = ".1";
1322
1323 if ( sscanf(who, ".%d", i) == 1 ) {
1324 if(i > 0 && i <= sizeof(commreceivers))
1325 who = commreceivers[i-1];
1326 else {
1327 _notify_fail("So vielen Leuten hast Du noch nichts mitgeteilt!\n");
1328 return 0;
1329 }
1330 }
1331
1332 xname = explode(who, "@");
1333
Zesstrabd1236a2022-02-09 22:35:59 +01001334 if (sizeof(xname) == 2)
MG Mud User88f12472016-06-24 23:31:02 +02001335 {
1336 if ( QueryProp(P_QP) )
1337 {
Zesstra04f613c2019-11-27 23:32:54 +01001338 if (ret=({string})INETD->_send_udp(xname[1],
MG Mud User88f12472016-06-24 23:31:02 +02001339 ([ REQUEST: "tell",
1340 RECIPIENT: xname[0],
1341 SENDER: getuid(ME),
1342 DATA: msg ]), 1))
1343 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001344 ReceiveNotify(ret, MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001345 }
1346 else
1347 {
1348 write("Nachricht abgeschickt.\n");
1349 add_to_tell_history(who, 1, 0, msg,
Zesstraa31cd5c2016-12-17 20:11:07 +01001350 "Du teilst " + capitalize(who) + " mit: ", MSGFLAG_RTELL, 1);
MG Mud User88f12472016-06-24 23:31:02 +02001351 }
1352 }
1353 else
1354 write("Du hast nicht genug Abenteuerpunkte, um Spielern in anderen \n"
1355 "Muds etwas mitteilen zu koennen.\n");
1356 return 1;
1357 }
1358
Zesstra8b5320e2022-02-18 21:10:26 +01001359 string|int lname = lower_case(who);
1360 if (!ob=find_player(lname))
MG Mud User88f12472016-06-24 23:31:02 +02001361 {
Zesstra8b5320e2022-02-18 21:10:26 +01001362 lname = match_living(lname, 0);
1363 if (!stringp(lname))
1364 {
1365 switch(lname)
1366 {
MG Mud User88f12472016-06-24 23:31:02 +02001367 case -1:
Bugfixb1d9b4d2021-09-14 20:07:04 +02001368 ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001369 return 1;
1370 case -2:
Zesstra8b5320e2022-02-18 21:10:26 +01001371 // check KOBOLD
1372 ob = find_object(KOBOLD);
1373 lname = ({string|int})ob->find_player(lower_case(who));
1374 if (lname == -1) {
1375 ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
1376 return 1;
1377 }
1378 else if (!stringp(lname)) {
1379 ReceiveNotify("Kein solcher Spieler (online)!",MA_TELL);
1380 return 1;
1381 }
MG Mud User88f12472016-06-24 23:31:02 +02001382 }
Zesstra8b5320e2022-02-18 21:10:26 +01001383 // jetzt ist ob der KOBOLD und lname die UID eines Spielers.
1384 }
1385 // Wenn wir noch kein ob haben, sollte lname jetzt aber durch das
1386 // match_living() der Name eines Livings sein, dessen Objekt wir noch
1387 // brauchen.
1388 if (!ob)
1389 ob = find_player(lname) || find_living(lname);
MG Mud User88f12472016-06-24 23:31:02 +02001390 if(!ob) {
Zesstra8b5320e2022-02-18 21:10:26 +01001391 ReceiveNotify("Kein solcher Spieler (online)!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001392 return 1;
1393 }
1394 }
1395
Zesstra8b5320e2022-02-18 21:10:26 +01001396 if(QueryProp(P_INVIS))
1397 {
MG Mud User88f12472016-06-24 23:31:02 +02001398 if(!IS_LEARNER(ob))
1399 myname = name();
1400 else
1401 myname="("+
1402 ((QueryProp(P_CAN_FLAGS) & CAN_PRESAY)?QueryProp(P_PRESAY):"")+
1403 capitalize(getuid()) + ")";
1404 }
1405 else
1406 myname=((IS_LEARNER(ME) && (QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ?
Bugfix45f88ce2017-03-06 14:41:56 +01001407 QueryProp(P_PRESAY):"") + capitalize(getuid(ME));
Zesstra8b5320e2022-02-18 21:10:26 +01001408 if (myname && sizeof(myname))
1409 myname=capitalize(myname);
1410
1411 // Wir haben Zielobjekt und unseren eigenen Namen. Erstmal an Empfaenger
1412 // senden.
1413 if (living(ob))
1414 _send(ob, permutate(msg), MT_COMM|MT_FAR|MSG_ALERT, MA_TELL,
1415 myname + " teilt Dir mit: ");
1416 else
1417 _send_to_kobold(lname, permutate(msg), MT_COMM|MT_FAR|MSG_ALERT, MA_TELL,
1418 myname + " teilt Dir mit: ");
MG Mud User88f12472016-06-24 23:31:02 +02001419
1420 // dann evtl. noch an Absender ausgeben...
Zesstra8b5320e2022-02-18 21:10:26 +01001421 visflag = !ob->QueryProp(P_INVIS);
1422 if (visflag || IS_LEARNER(this_player()))
1423 _recv(ob, msg, MSGFLAG_TELL, "Du teilst " + capitalize(lname) + " mit: ");
MG Mud User88f12472016-06-24 23:31:02 +02001424 // oder irgendwas anderes an den Absender ausgeben...
1425 if (!visflag && interactive(ob))
Zesstra8b5320e2022-02-18 21:10:26 +01001426 ReceiveNotify("Kein solcher Spieler online!",MA_TELL);
Zesstra04f613c2019-11-27 23:32:54 +01001427 else if (away = ({string})ob->QueryProp(P_AWAY))
Zesstra8b5320e2022-02-18 21:10:26 +01001428 ReceiveMsg( break_string( away, 78, capitalize(lname)
MG Mud User88f12472016-06-24 23:31:02 +02001429 + " ist gerade nicht da: ", BS_INDENT_ONCE ),
1430 MT_NOTIFICATION|MSG_DONT_WRAP|MSG_DONT_IGNORE,
1431 MA_TELL, 0, this_object());
1432 else if (interactive(ob) && (i=query_idle(ob))>=600)
1433 { //ab 10 Mins
1434 if (i<3600)
1435 away=time2string("%m %M",i);
1436 else
1437 away=time2string("%h %H und %m %M",i);
1438
Bugfixb1d9b4d2021-09-14 20:07:04 +02001439 ReceiveNotify(sprintf("%s ist seit %s voellig untaetig.",
Zesstra8b5320e2022-02-18 21:10:26 +01001440 capitalize(lname),away),
MG Mud User88f12472016-06-24 23:31:02 +02001441 MA_TELL);
1442 }
1443
1444 return 1;
1445}
1446
1447static int _teile(string str)
1448{
1449 string who, message;
1450 if (!(str=_unparsed_args())) return 0;
1451 if (sscanf(str, "%s mit %s", who, message) == 2)
1452 return _tell(who, message,1);
1453 return 0;
1454}
1455static int _teile_mit_alias(string str)
1456{
1457 str = _unparsed_args(), TRIM_LEFT;
1458 if (!str) return 0;
1459 str = trim(str, TRIM_LEFT);
1460 // Ziel muss min. 2 Buchstaben haben (.<nr>)
1461 if (sizeof(str) < 4) return 0;
1462 int pos = strstr(str, " ");
1463 if (pos >= 2)
1464 return _tell(str[..pos-1], str[pos+1..]);
1465 return 0;
1466}
1467
1468static int _erzaehle(string str)
1469{
1470 string who, message;
1471
1472 if (!(str=_unparsed_args())) return 0;
1473 if (sscanf(str, "%s %s", who, message) == 2)
1474 return _tell(who, message,1);
1475 return 0;
1476}
1477
1478static int _whisper(string str)
1479{
1480 object ob;
1481 string who;
1482 string msg;
1483 string myname;
1484
1485 if (!(str=_unparsed_args()) ||
1486 (sscanf(str, "%s zu %s", who, msg) != 2 &&
1487 sscanf(str, "%s %s", who, msg) !=2 )) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001488 ReceiveNotify("Was willst Du wem zufluestern?",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001489 return 1;
1490 }
Zesstra6e88b6a2019-11-08 00:25:39 +01001491 who = lower_case(who);
MG Mud User88f12472016-06-24 23:31:02 +02001492 if (!(ob = present(who, environment(this_player()))) || !living(ob)) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001493 ReceiveNotify(capitalize(who)+" ist nicht in diesem Raum.",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001494 return 1;
1495 }
1496
1497 myname = capitalize((((IS_LEARNER(ME) &&
1498 !QueryProp(P_INVIS) &&
1499 (QueryProp(P_CAN_FLAGS) & CAN_PRESAY))?
1500 QueryProp(P_PRESAY) : "") + name()) || "");
1501
1502 _send(ob, permutate(msg), MT_LISTEN|MSG_DONT_STORE,
Bugfixdbdbed52022-01-21 11:14:35 +01001503 MA_SAY, myname + " fluestert Dir zu: ");
MG Mud User88f12472016-06-24 23:31:02 +02001504 send_room(environment(),
1505 myname + " fluestert " + ob->name(WEM, 1) + " etwas zu.",
1506 MT_LISTEN|MSG_DONT_STORE, MA_SAY, 0, ({this_object(),ob}));
1507
1508 _recv(ob, msg, MSGFLAG_WHISPER, "Du fluesterst " + ob->name(WEM) + " zu: ");
1509
1510
1511 return 1;
1512}
1513
1514static int _remote_whisper(string str)
1515{
1516 /* Wie 'teile mit', nur mit MSGFLAG_WHISPER. Dadurch wird der Inhalt der
1517 Nachricht nicht in der tell_history verewigt. */
1518
1519 object ob;
Zesstra8b5320e2022-02-18 21:10:26 +01001520 string who;
MG Mud User88f12472016-06-24 23:31:02 +02001521 string msg;
1522 string myname;
1523
1524 if (!(str=_unparsed_args()) ||
1525 (sscanf(str, "%s zu %s", who, msg) != 2 &&
1526 sscanf(str, "%s %s", who, msg) !=2 )) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001527 ReceiveNotify("Was willst Du wem aus der Ferne zufluestern?",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001528 return 1;
1529 }
1530
Zesstra8b5320e2022-02-18 21:10:26 +01001531 string|int lname = lower_case(who);
1532 if (!ob=find_player(lname))
MG Mud User88f12472016-06-24 23:31:02 +02001533 {
Zesstra8b5320e2022-02-18 21:10:26 +01001534 lname = match_living(lname, 0);
1535 if (!stringp(lname))
1536 {
1537 switch(lname)
1538 {
MG Mud User88f12472016-06-24 23:31:02 +02001539 case -1:
Zesstra8b5320e2022-02-18 21:10:26 +01001540 ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001541 return 1;
1542 case -2:
Zesstra8b5320e2022-02-18 21:10:26 +01001543 // rfluester benutzt keinen KOBOLD.
1544 ReceiveNotify("Kein solcher Spieler!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001545 return 1;
1546 }
Zesstra8b5320e2022-02-18 21:10:26 +01001547 }
1548 // lname sollte nun eindeutig sein.
1549 ob = find_player(lname) || find_living(lname);
1550 if(!ob) {
1551 ReceiveNotify("Kein solcher Spieler online!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001552 return 1;
1553 }
1554 }
Zesstra8b5320e2022-02-18 21:10:26 +01001555
MG Mud User88f12472016-06-24 23:31:02 +02001556 if (environment(ob) == environment()) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001557 ReceiveNotify("Wenn jemand neben Dir steht, nimm fluester.",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001558 return 1;
1559 }
1560
1561 myname = capitalize((((IS_LEARNER(ME) &&
1562 !QueryProp(P_INVIS) &&
1563 (QueryProp(P_CAN_FLAGS) & CAN_PRESAY))?
1564 QueryProp(P_PRESAY) : "") + name()) || "");
1565
1566 // An Empfaenger senden.
Zesstrabd1236a2022-02-09 22:35:59 +01001567 _send(ob, permutate(msg), MT_COMM|MT_FAR|MSG_DONT_STORE,
1568 MA_EMOTE, myname + " fluestert Dir aus der Ferne zu: ");
MG Mud User88f12472016-06-24 23:31:02 +02001569 // wenn Empfaenger invis und wir kein Magier , ggf. fakefehler ausgeben.
1570 if (ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player())) {
Zesstra8b5320e2022-02-18 21:10:26 +01001571 ReceiveNotify("Kein solcher Spieler online!",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001572 return 1;
1573 }
1574 // sonst eigene Meldung via _recv() ausgeben.
1575 else
1576 _recv(ob, msg, MSGFLAG_WHISPER | MSGFLAG_REMOTE,
1577 "Du fluesterst " + ob->name(WEM) + " aus der Ferne zu: ");
1578
1579 return 1;
1580}
1581
1582static int _converse(string arg)
1583{
Bugfixb1d9b4d2021-09-14 20:07:04 +02001584 ReceiveNotify("Mit '**' wird das Gespraech beendet.",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001585 if (stringp(arg) && strstr(arg, "-s") == 0)
1586 input_to("_converse_more", INPUT_PROMPT, "]", 1);
1587 else
1588 input_to("_converse_more", INPUT_PROMPT, "]", 0);
1589 return 1;
1590}
1591
1592static int _converse_more(mixed str, int silent)
1593{
1594 if (str == "**") {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001595 ReceiveNotify("Ok.",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001596 return 0;
1597 }
1598
1599 if(str != "")
1600 _communicate(str, silent);
1601
1602 input_to("_converse_more", INPUT_PROMPT, "]", silent);
1603 return 1;
1604}
1605
1606private int is_learner(object o) { return IS_LEARNER(o); }
1607
1608static int _shout_to_wizards(mixed str)
1609{
MG Mud User88f12472016-06-24 23:31:02 +02001610 string myname;
MG Mud User88f12472016-06-24 23:31:02 +02001611
1612 str = _unparsed_args();
1613 if (!str||!sizeof(str)) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001614 ReceiveNotify("Was willst Du den Magiern zurufen?",MA_SHOUT);
MG Mud User88f12472016-06-24 23:31:02 +02001615 return 1;
1616 }
1617 // Kontrollzeichen rausfiltern.
1618 str = regreplace(str,"[[:cntrl:]]","",RE_PCRE|RE_GLOBAL);
1619 myname = capitalize(getuid(this_object()));
1620 if (!IS_LEARNER(this_object()))
1621 _recv(0, str, MSGFLAG_MECHO, "Du teilst allen Magiern mit: ");
1622
1623 // mrufe ist nicht ignorierbar, da es nur fuer schwere Probleme gedacht ist.
1624 filter(users(), #'is_learner)->ReceiveMsg(str,
Zesstrabd1236a2022-02-09 22:35:59 +01001625 MT_COMM|MT_FAR|MSG_DONT_IGNORE|MSG_DONT_STORE|MSG_ALERT,
MG Mud User88f12472016-06-24 23:31:02 +02001626 MA_SHOUT, myname+" an alle Magier: ", this_object());
1627
1628 return 1;
1629}
1630
1631static int _echo(string str) {
1632 if (!IS_SEER(ME) || (!IS_LEARNER(ME)
1633 && !(QueryProp(P_CAN_FLAGS) & CAN_ECHO)))
1634 return 0;
1635
1636 if (!(str=_unparsed_args())) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001637 ReceiveNotify("Was moechtest Du 'echoen'?", 0);
MG Mud User88f12472016-06-24 23:31:02 +02001638 return 1;
1639 }
1640
1641 if (!IS_LEARNER(this_interactive()))
1642 {
1643 if (QueryProp(P_GHOST))
1644 {
1645 _notify_fail("Ohne Koerper fehlt Dir dazu die noetige magische Kraft.\n");
1646 return 0;
1647 }
1648 if (QueryProp(P_SP)<ECHO_COST)
1649 {
1650 _notify_fail("Du musst erst wieder magische Kraefte sammeln.\n");
1651 return 0;
1652 }
1653 SetProp(P_SP,QueryProp(P_SP)-ECHO_COST);
1654 str=">\b"+str;
1655 log_file("ARCH/ECHO_SEHER", sprintf("%s %s: %s\n", dtime(time()), getuid(),
1656 str));
1657 }
1658 // An den Raum senden. Typ ist MT_COMM, aber das Echo soll weder in der
1659 // Kommhistory noch im Kobold landen.
1660 send_room(environment(ME), str, MT_COMM|MSG_DONT_STORE|MSG_DONT_BUFFER,
1661 MA_UNKNOWN, 0, 0);
1662 return 1;
1663}
1664
1665// Dient als Verteidigung gegen Leute, die eher unbedacht reinschreiben, nicht
1666// gegen Leute, die da absichtlich reinschreiben. Die werden geteert
1667// und gefedert.
1668static string *_set_ignore(mixed arg)
1669{
1670 raise_error("Direktes Setzen von P_IGNORE ist nicht erlaubt. "
1671 "Benutze AddIgnore/RemoveIgnore()!\n");
1672}
1673// Kompatibiltaet zum alten Ignore: Array von Indices liefern. Aendert aber
1674// nix dran, dass alle TestIgnore() & Co benutzen sollen.
1675static string *_query_ignore() {
1676 mixed ign=Query(P_IGNORE, F_VALUE);
1677 if (mappingp(ign))
1678 return m_indices(ign);
1679 return ({});
1680}
1681
1682public int AddIgnore(string ign) {
1683 // Einige strings sind nicht erlaubt, z.B. konsekutive .
1684 if (!sizeof(ign)
1685 || regmatch(ign,"[.]{2,}",RE_PCRE)
1686 || regmatch(ign," ",RE_PCRE)
1687 || sizeof(explode(ign,"."))>3)
1688 return 0;
1689
1690 mapping ignores=Query(P_IGNORE, F_VALUE);
1691 ignores[ign]=time();
1692 // kein Set() noetig.
1693 return 1;
1694}
1695
1696public int RemoveIgnore(string ign)
1697{
1698 mapping ignores=Query(P_IGNORE,F_VALUE);
1699 m_delete(ignores,ign);
1700 // Kein Set() noetig
1701 return 1;
1702}
1703
1704static int _query_intermud()
1705{
1706 mixed tmp;
1707 return member(pointerp(tmp=Query(P_CHANNELS))?tmp:({}), "Intermud") > -1;
1708}
1709
1710
1711int erwidere(string str)
1712{
1713 str=_unparsed_args();
1714 if (!str) return 0;
1715 return _tell(ERWIDER_PARAM, str ,1);
1716}
1717
1718static int tmhist(string str)
1719{
1720
1721 if (str == "aus") {
1722 tell_history_enabled = TELLHIST_DISABLED;
1723 write("Ok, es wird nichts mehr gespeichert.\n");
1724 if (sizeof(tell_history)) {
Zesstra996bafe2022-02-14 22:42:39 +01001725 clear_tell_history(1);
MG Mud User88f12472016-06-24 23:31:02 +02001726 write("Deine Mitteilungsgeschichte wurde geloescht.\n");
1727 }
1728 return 1;
1729 }
Zesstra996bafe2022-02-14 22:42:39 +01001730 if (str == "loeschen")
1731 {
1732 if (sizeof(tell_history)) {
1733 clear_tell_history(1);
1734 write("Deine Mitteilungsgeschichte wurde geloescht.\n");
1735 }
1736 else
1737 write("Deine Mitteilungsgeschichte war schon leer.\n");
1738 return 1;
1739 }
MG Mud User88f12472016-06-24 23:31:02 +02001740
1741 if (str == "namen") {
1742 int flag;
1743 tell_history_enabled = TELLHIST_NO_MESSAGE;
1744 write("Ok, die Namen zukuenftiger Gespraechspartner werden gespeichert.\n");
1745 foreach (string uid, struct chat_s chat: tell_history)
1746 if (pointerp(chat->msgbuf)) {
1747 chat->msgbuf = 0;
1748 chat->ptr = 0;
1749 flag = 1;
1750 }
1751 if (flag)
1752 write("Der Inhalt Deiner Mitteilungen wurde geloescht.\n");
1753 return 1;
1754 }
1755
1756 if (str == "ein" || str == "an") {
1757 tell_history_enabled = TELLHIST_ENABLED;
1758 write("Ok, zukuenftige Mitteilungen werden gespeichert.\n");
1759 return 1;
1760 }
1761
MG Mud User88f12472016-06-24 23:31:02 +02001762 if (str == "langlebig") {
1763 tell_history_enabled = TELLHIST_LONGLIFE;
1764 write("Ok, zukuenftige Mitteilungen werden jeweils bis zum naechsten "
1765 "Ende/Crash/\nReboot gespeichert.\n");
1766 return 1;
1767 }
MG Mud User88f12472016-06-24 23:31:02 +02001768
1769 if (str == "status") {
1770 switch (tell_history_enabled) {
1771 case TELLHIST_DISABLED:
1772 write("Die Namen Deiner Gespraechspartner werden nicht gespeichert.\n");
1773 break;
1774 case TELLHIST_NO_MESSAGE:
1775 write("Die Namen Deiner Gespraechspartner werden gespeichert.\n");
1776 break;
1777 case TELLHIST_ENABLED:
1778 write("Deine Mitteilungen werden gespeichert.\n");
1779 break;
MG Mud User88f12472016-06-24 23:31:02 +02001780 case TELLHIST_LONGLIFE:
1781 write("Deine Mitteilungen werden jeweils bis zum naechsten Ende/"
1782 "Crash/Reboot\ngespeichert.\n");
1783 break;
MG Mud User88f12472016-06-24 23:31:02 +02001784 }
1785 return 1;
1786 }
1787
1788 if (tell_history_enabled == TELLHIST_DISABLED) {
1789 _notify_fail("Deine Gespraechspartner werden nicht gespeichert.\n");
1790 return 0;
1791 }
1792
1793 if (!sizeof(tell_history)) {
1794 _notify_fail("Du hast noch keinem etwas mitgeteilt "
1795 "und noch keine Mitteilungen erhalten.\n");
1796 return 0;
1797 }
1798
1799 if (str && sizeof(str)) {
1800
1801 if (tell_history_enabled < TELLHIST_ENABLED) {
1802 _notify_fail("Der Inhalt Deiner Mitteilungen wird nicht gespeichert.\n");
1803 return 0;
1804 }
1805
1806 string uid;
1807 if (member(tell_history, str)) {
1808 // Name gewuenscht, da der String in der History vorkommt.
1809 uid = str;
1810 }
1811 else {
1812 // evtl. ne Zahl angegeben.
1813 int i;
1814 string *partners = sorted_commpartners(0);
1815 if ((i = to_int(str) - 1) >= 0 && i < sizeof(partners))
1816 uid = partners[i];
1817 else {
1818 notify_fail("Mit so vielen Leuten hast Du nicht gesprochen!\n");
1819 return 0;
1820 }
1821 }
1822
1823 mixed *data = tell_history[uid]->msgbuf;
1824 if (!data) {
1825 _notify_fail(
1826 "Der Inhalt dieser Mitteilung ist nicht (mehr) gespeichert.\n");
1827 return 0;
1828 }
1829
1830 int ptr = tell_history[uid]->ptr;
1831
1832 More(sprintf("%@s", map(data[ptr..MAX_SAVED_MESSAGES-1] +
1833 data[0..ptr-1],
1834 function string (struct stored_msg_s msg) {
1835 if (!structp(msg)) return "";
Zesstra3a261e52022-02-10 14:00:31 +01001836 return break_string(terminal_colour(msg->msg, colourmap)
1837 + " <"
MG Mud User88f12472016-06-24 23:31:02 +02001838 + strftime("%H:%M:%S",msg->timestamp) + ">", 78,
1839 msg->prefix || "", msg->prefix ? BS_LEAVE_MY_LFS : 0);
1840 } ) ) );
1841 return 1;
1842 }
1843
1844 string history = "Folgende Gespraeche hast Du bereits gefuehrt:\n";
1845 int i;
1846 foreach (string uid : sorted_commpartners(0) ) {
1847 int j;
1848 struct chat_s chat = tell_history[uid];
1849 history += sprintf("%2d.%-4s %s %-11s %d gesendet/%d empfangen\n", ++i,
1850 ((j=member(commreceivers,uid))>-1 ? sprintf("/%2d.",j+1) : ""),
1851 strftime("%a, %e.%m.%y",chat->time_last_msg),
1852 capitalize(chat->uid), chat->sentcount, chat->recvcount);
1853 }
1854
1855 More(history);
1856
1857 return 1;
1858}
1859
1860static mixed _query_localcmds()
1861{
1862 return ({
1863 ({"kobold", "cmd_kobold",0,0}),
1864 ({"sag","_communicate",0,0}),
1865 ({"sage","_communicate",0,0}),
1866 ({"'","_communicate",1,0}),
1867 ({"mruf","_shout_to_wizards",0,0}),
1868 ({"mrufe","_shout_to_wizards",0,0}),
1869 ({"ruf","_shout_to_all",0,0}),
1870 ({"rufe","_shout_to_all",0,0}),
1871 ({"erzaehl","_erzaehle",0,0}),
1872 ({"erzaehle","_erzaehle",0,0}),
1873 ({"teil","_teile",0,0}),
1874 ({"teile","_teile",0,0}),
1875 ({"tm","_teile_mit_alias",0,0}),
1876 ({"fluester","_whisper",0,0}),
1877 ({"fluestere","_whisper",0,0}),
1878 ({"rfluester","_remote_whisper",0,0}),
1879 ({"rfluestere","_remote_whisper",0,0}),
1880 ({"gespraech","_converse",0,0}),
1881 ({"echo","_echo",0,0}),
1882 ({"ignorier","ignoriere",0,0}),
1883 ({"ignoriere","ignoriere",0,0}),
1884 ({"tmhist","tmhist",0,0}),
1885 ({"erwider","erwidere",0,0}),
1886 ({"erwidere","erwidere",0,0}),
1887 ({"klingelton","_msg_beep",0,0}),
1888 ({"senderwiederholung","_msg_prepend",0,0}),
1889 ({"report","set_report",0,0}),
1890 })+channel::_query_localcmds();
1891}
1892
1893private string *sorted_commpartners(int reversed) {
1894 return sort_array(m_indices(tell_history),
1895 function int (string uid1, string uid2) {
1896 if (reversed)
1897 return tell_history[uid1]->time_last_msg >
1898 tell_history[uid2]->time_last_msg;
1899 else
1900 return tell_history[uid1]->time_last_msg <=
1901 tell_history[uid2]->time_last_msg;
1902 } );
1903}
1904
Zesstra0712bac2020-06-12 09:41:24 +02001905// Setzt den Prompt eines Interactives. Gerufen bei Objekterstellung,
1906// Reconnect und bei Magiern, wenn diese ihren Prompt oder ihr aktuelles
1907// Verzeichnis aendern.
MG Mud User88f12472016-06-24 23:31:02 +02001908static void modify_prompt() {
1909 string text = Query(P_PROMPT, F_VALUE);
1910
1911 if ( !stringp(text) || !sizeof(text) )
1912 text = "> ";
1913 else {
1914 string path = Query(P_CURRENTDIR, F_VALUE);
1915 if (stringp(path) && sizeof(path))
1916 text = regreplace(text,"\\w",path,0); // Pfad einsetzen
1917 }
1918 configure_interactive(this_object(), IC_PROMPT, text);
1919}
1920
1921// Prueft auf Ingoriereeintraege.
1922// Rueckgabe: 0 (nicht ignoriert) oder MSG_IGNORED
MG Mud User88f12472016-06-24 23:31:02 +02001923public int TestIgnore(string|string* srcnames)
MG Mud User88f12472016-06-24 23:31:02 +02001924{
1925 mapping ign = Query(P_IGNORE, F_VALUE);
1926 if (stringp(srcnames))
1927 srcnames = ({srcnames});
1928
1929 foreach(string srcname: srcnames)
1930 {
1931 // einfachster Fall, exakter Match
1932 if (member(ign, srcname))
1933 return MSG_IGNORED;
1934 // ansonsten muss aufgetrennt werden.
1935 if (strstr(srcname,".") > -1)
1936 {
1937 string *srcparts=explode(srcname,".");
1938 switch(sizeof(srcparts))
1939 {
1940 // case 0 und 1 kann nicht passieren.
1941 case 3:
1942 // zu pruefen: [sender].aktion.qualifizierer.
1943 // Der Fall, dass der Spieler dies _genau_ _so_ ignoriert hat, wird
1944 // oben schon geprueft. im Spieler geprueft werden muss noch:
1945 // spieler, .aktion, spieler.aktion und .aktion.qualifizierer
1946 if ( (sizeof(srcparts[0]) && member(ign,srcparts[0])) // spieler
1947 || member(ign, "."+srcparts[1]) // .aktion
1948 || member(ign, srcparts[0]+"."+srcparts[1]) // [spieler].aktion
1949 || member(ign, "."+srcparts[1]+"."+srcparts[2]) // .akt.qual
1950 )
1951 {
1952 return MSG_IGNORED;
1953 }
1954 break;
1955 case 2:
1956 // zu pruefen: spieler.aktion
1957 // Der Fall, dass der Spieler das _genau_ _so_ eingegeben hat, ist
1958 // oben schon geprueft. Im Spieler zu pruefen ist noch:
1959 // spieler und .aktion
1960 if ((sizeof(srcparts[0]) && member(ign,srcparts[0]))
1961 || member(ign, "."+srcparts[1]))
1962 {
1963 return MSG_IGNORED;
1964 }
1965 break;
1966 default: // mehr als 3 Teile...
1967 raise_error(sprintf("TestIgnoreExt(): too many qualifiers, only 1 "
1968 "is supported. Got: %s\n",srcname));
MG Mud User88f12472016-06-24 23:31:02 +02001969 }
1970 }
1971 }
1972 // Default: nicht ignorieren.
1973 return 0;
1974}
1975
1976#ifdef __LPC_UNIONS__
1977public int TestIgnoreExt(string|string* srcnames)
1978#else
1979public int TestIgnoreExt(mixed srcnames)
1980#endif
1981{
1982 return TestIgnore(srcnames);
1983}
1984
1985// Prueft fuer ReceiveMsg() auf Ingoriereeintraege. Ignoriert aber nicht alle
1986// Typen.
1987// Rueckgabe: 0 oder MSG_IGNORED | MSG_VERB_IGN | MSG_MUD_IGN
1988private int check_ignores(string msg, int msg_type, string msg_action,
1989 string msg_prefix, object origin)
1990{
1991 // Einige Dinge lassen sich nicht ignorieren.
1992 if (msg_type & (MT_NEWS|MT_NOTIFICATION))
1993 return 0;
1994 // alles andere geht zur zeit erstmal, wenn origin bekannt UND NICHT das
1995 // eigene Objekt ist. Waer ggf. sonst doof. Ausserdem muss es natuerlich
1996 // eine ignorierbare msg_action geben.
1997 else if (stringp(msg_action) && origin && origin != ME)
1998 {
1999 string srcname =
2000 (query_once_interactive(origin) ? origin->query_real_name()
2001 : origin->name(WER) || "");
2002 mapping ign = Query(P_IGNORE, F_VALUE);
2003
2004 if (member(ign, srcname))
2005 return MSG_IGNORED;
2006 // vielleicht wird irgendwas a la name.aktion ignoriert?
2007 // dies ignoriert auch spieler.ebenen.<ebene> (s. msg_action bei
2008 // Ebenenmeldungen)
2009 if (member(ign, srcname+"."+msg_action))
2010 return MSG_VERB_IGN;
2011 // Oder die Aktion komplett? Dies ignoriert auch .ebenen.<ebene>, obwohl
2012 // das reichlich sinnfrei ist.
2013 if (member(ign, "."+msg_action))
2014 return MSG_VERB_IGN;
2015 // Spieler auf Ebenen ignoriert?
2016 // msg_action ist hier nach diesem Muster: MA_CHANNEL.<ebene>
2017 if (strstr(msg_action, MA_CHANNEL) == 0)
2018 {
2019 // spieler.ebenen? (spieler.ebenen.<ebene> oben schon geprueft)
2020 if (member(ign, srcname + "."MA_CHANNEL))
2021 return MSG_IGNORED;
2022 // spieler.ebenen.ebenenname ist oben schon abgedeckt.
2023 // .ebenen halte ich fuer sinnfrei, nicht geprueft.
2024 }
2025 // Spieler aus anderem mud? *seufz*
2026 if (strstr(srcname,"@") > -1)
2027 {
2028 string *srcparts = explode(srcname,"@");
2029 if (sizeof(srcparts)==2)
2030 {
2031 // spieler@?
2032 if (member(ign, srcparts[0]+"@"))
2033 return MSG_IGNORED;
2034 // oder Mud per @mud?
2035 if (member(ign, "@" + srcparts[1]))
2036 return MSG_MUD_IGN;
2037 // BTW: spieler@mud wurde schon ganz oben erfasst.
2038 }
2039 }
2040 }
2041 // Default: nicht ignorieren.
2042 return 0;
2043}
2044
2045// Wird die nachricht wahrgenommen? Die Pruefung erfolgt aufgrund von
2046// msg_type. Zur wird MT_LOOK und MT_LISTEN beruecksichtigt (Pruefung auf
Bugfixe0fc68f2022-01-07 15:30:54 +01002047// BLindheit/Taubheit). In Zukunft koennten aber weitere Typen und weitere
2048// Kriterien wichtig werden und weitere Argumente uebergeben werden. (Dies
2049// bitte beachten, falls diese Funktion protected/public werden sollte.)
MG Mud User88f12472016-06-24 23:31:02 +02002050// Wichtig: enthaelt msg_action weder MT_LOOK noch MT_LISTEN, wird die
2051// Nachricht wahrgenommen, da davon ausgegangen wird, dass sie mit den beiden
2052// Sinn gar nix zu tun hat.
2053// Rueckgabe: 0 oder MSG_SENSE_BLOCK
Bugfixe0fc68f2022-01-07 15:30:54 +01002054private int check_senses(int msg_type)
MG Mud User88f12472016-06-24 23:31:02 +02002055{
2056 int senses = msg_type & (MT_LOOK|MT_LISTEN);
2057 // Wenn von vorherein kein Sinn angesprochen, dann ist es eine nachricht,
2058 // die von keinem der beiden wahrgenommen wird und sollte demnach nicht
2059 // unterdrueckt werden.
2060 if (!senses)
2061 return 0;
Bugfix427a5812022-01-07 15:41:24 +01002062
2063 int orig_senses = senses;
2064
MG Mud User88f12472016-06-24 23:31:02 +02002065 if ((senses & MT_LOOK) && CannotSee(1))
2066 senses &= ~MT_LOOK; // Sinn loeschen
2067
2068 if ((senses & MT_LISTEN) && QueryProp(P_DEAF))
2069 senses &= ~MT_LISTEN;
2070
Bugfix427a5812022-01-07 15:41:24 +01002071 // Wenn kein Sinn mehr ueber ist oder all_types gesetzt ist und nicht mehr
2072 // alle Sinne vorhanden sind, wird die Nachricht nicht wahrgenommen.
2073 if (orig_senses == senses // kein Sinn geloescht, haeufigster Fall
2074 || (!(msg_type&MSG_ALL_SENSES) && senses) ) // min. ein Sinn uebrig
2075 return 0;
MG Mud User88f12472016-06-24 23:31:02 +02002076
Bugfix427a5812022-01-07 15:41:24 +01002077 return MSG_SENSE_BLOCK;
MG Mud User88f12472016-06-24 23:31:02 +02002078}
2079
2080public varargs int ReceiveMsg(string msg, int msg_type, string msg_action,
2081 string msg_prefix, object origin)
2082{
2083 if (!msg) return MSG_FAILED;
2084
2085 // Flags und Typen spalten
2086 int flags = msg_type & MSG_ALL_FLAGS;
2087 int type = msg_type & ~flags;
2088
2089 // ggf. defaults ermitteln
2090 origin ||= previous_object();
2091 msg_action ||= comm_guess_action();
2092 type ||= comm_guess_message_type(msg_action, origin);
2093
2094 // Debugmeldungen nur an Magier oder Testspieler mit P_WIZ_DEBUG
2095 if (msg_type & MT_DEBUG)
2096 {
2097 if (!QueryProp(P_WIZ_DEBUG)
2098 || (!IS_LEARNER(ME) && !QueryProp(P_TESTPLAYER)) )
2099 return MSG_FAILED;
2100 }
2101
2102 // Zuerst werden Sinne und P_IGNORE sowie ggf. sonstige Filter geprueft. In
2103 // dem Fall ist direkt Ende, kein Kobold, keine Komm-History, keine
2104 // Weiterbearbeitung.
2105 // aber bestimmte Dinge lassen sich einfach nicht ignorieren.
2106 if (!(flags & MSG_DONT_IGNORE))
2107 {
Bugfix427a5812022-01-07 15:41:24 +01002108 // Sinne pruefen.
2109 int res=check_senses(msg_type);
MG Mud User88f12472016-06-24 23:31:02 +02002110 if (res) return res;
2111
2112 // Spieler-definiertes Ignoriere? (nur typen uebergeben, keine Flags)
2113 res=check_ignores(msg, type, msg_action, msg_prefix, origin);
2114 if (res) return res;
2115 }
2116
Zesstra3a261e52022-02-10 14:00:31 +01002117 // Mentions in der Form @Charname werden in Kommunikation oder beim Hoeren
2118 // von Rufen und Sagen markiert und gegebenfalls gibt es ein Pieps dafuer
2119 int mention;
2120 if ((type & MT_COMM)
2121 || ((type & MT_LISTEN) && msg_action in ({MA_SAY, MA_SHOUT}))
2122 )
2123 {
2124 // Um den Charnamen Tags fuer terminal_colour() einfuegen.
2125 // Lookahead und Lookbehind assertions um die Whitespaces um das Wort
2126 // nicht in den Match einzuschliessen (und zu ersetzen).
2127 string tmp = regreplace(msg,
2128 sprintf("(?<=\\s)@%s(?=\\s*)",getuid(ME)),
2129 sprintf("%%^mention%%^@%s%%^normal%%^",
2130 capitalize(getuid(ME))),
2131 RE_PCRE|RE_GLOBAL|RE_CASELESS);
2132 send_debug(ME, tmp);
2133 // Der Vergleich ist weniger schlimm als es aussieht, weil die Strings
2134 // unterschiedlich gross sein werden und daher nicht zeichenweise
2135 // verglichen werden muessen. Es ist dann jedenfalls schneller als
2136 // getrennt mit regmatch oder strstr zu schauen, ob @charname
2137 // vorkommt.
2138 if (tmp != msg)
2139 {
2140 msg = tmp;
2141 mention = 1;
2142 }
2143 }
2144
MG Mud User88f12472016-06-24 23:31:02 +02002145 // Fuer MT_COMM gibt es ein paar Sonderdinge zu machen.
2146 if ((type & MT_COMM))
2147 {
2148 // erstmal in der Komm-History ablegen, wenn gewuenscht.
2149 if ((!(flags & MSG_DONT_STORE)))
2150 {
2151 string uid;
2152 if (query_once_interactive(origin))
2153 uid = origin->query_real_name();
2154 else
2155 uid = origin->name(WER) || "<unbekannt>";
Zesstraa31cd5c2016-12-17 20:11:07 +01002156 add_to_tell_history(uid, 0, 1, msg, msg_prefix,
2157 (msg_action == MA_TELL ? MSGFLAG_TELL : 0 ) );
MG Mud User88f12472016-06-24 23:31:02 +02002158 }
2159
2160 // ggf. Uhrzeit bei abwesenden Spielern anhaengen, aber nicht bei
2161 // Ebenenmeldungen. (Die haben ggf. schon.)
2162 if (stringp(msg_action) && QueryProp(P_AWAY)
2163 && strstr(msg_action, MA_CHANNEL) != 0)
2164 {
2165 // Uhrzeit anhaengen, aber ggf. muss ein \n abgeschnitten werden.
2166 if (msg[<1] == '\n')
2167 msg = msg[0..<2]+" [" + strftime("%H:%M",time()) + "]\n";
2168 else
2169 msg = msg + " [" + strftime("%H:%M",time()) + "]";
2170 }
2171 // Kobold erlaubt und gewuenscht? Kobold ist fuer die
2172 // direkte Kommunikation mittels MT_COMM vorgesehen.
2173 // Oropax von Magiern leitet inzwischen auch nur in Kobold um statt zu
2174 // ignorieren.
2175 // die if-Konstruktion ist so, weil ich das _flush_cache() im else
2176 // brauche.
2177 if (query_editing(this_object()) || query_input_pending(this_object())
2178 || QueryProp(P_EARMUFFS))
2179 {
2180 if (!(flags & MSG_DONT_BUFFER)
2181 && QueryProp(P_BUFFER))
2182 {
2183 // Nachricht soll im Kobold gespeichert werden.
2184 return add_to_kobold(msg, msg_type, msg_action, msg_prefix, origin);
2185 }
2186 }
2187 else
2188 {
2189 // wenn nicht in Editor/input_to, mal versuchen, den Kobold zu
2190 // entleeren.
2191 _flush_cache(0);
2192 }
Bugfix3afcb792022-01-21 22:32:42 +01002193 }
2194
Zesstra3a261e52022-02-10 14:00:31 +01002195 // Farbtags ersetzen
2196 msg = terminal_colour(msg, colourmap);
2197
2198 // Alertton senden?
2199 if ((msg_type & MSG_ALERT) || mention)
2200 comm_beep(msg_action, mention);
MG Mud User88f12472016-06-24 23:31:02 +02002201
2202 // Ausgabenachricht bauen und an den Spieler senden.
2203 if (flags & MSG_DONT_WRAP)
2204 msg = (msg_prefix ? msg_prefix : "") + msg;
2205 else
2206 {
2207 int bsflags = flags & MSG_ALL_BS_FLAGS;
2208 if (QueryProp(P_MESSAGE_PREPEND))
2209 bsflags |= BS_PREPEND_INDENT;
2210 msg = break_string(msg, 78, msg_prefix, bsflags);
2211 }
2212 efun::tell_object(ME, msg);
2213
2214 return MSG_DELIVERED;
2215}