blob: 312f7e502ccd4ffd24e97975113082501949da4a [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>
21#undef NEED_PROTOTYPES
22
23#include <sys_debug.h>
24
25#include <thing/properties.h>
26#include <player/comm.h>
27#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,);
71#define MAX_KOBOLD_LIMIT 256
72
Zesstra3a261e52022-02-10 14:00:31 +010073// Colourmap
74// TODO: spaeter konfigurierbar machen
75private mapping build_colourmap(string ttype="ansi");
76private nosave mapping colourmap = build_colourmap();
77
MG Mud User88f12472016-06-24 23:31:02 +020078varargs string name(int casus, int demonst);
79
80//local property prototypes
81static int _query_intermud();
82public int RemoveIgnore(string ign);
83public int AddIgnore(string ign);
84
85public varargs int ReceiveMsg(string msg, int msg_type, string msg_action,
86 string msg_prefix, object origin);
87
88// erzeugt sortierte Liste an Kommunikationspartnern
89private string *sorted_commpartners(int reversed);
90
MG Mud User88f12472016-06-24 23:31:02 +020091void create()
92{
93 ::create();
Bugfix3afcb792022-01-21 22:32:42 +010094 Set(P_ALERT, SAVE, F_MODE_AS);
MG Mud User88f12472016-06-24 23:31:02 +020095 Set(P_EARMUFFS, 0);
96 Set(P_EARMUFFS, SAVE, F_MODE);
97 Set(P_EARMUFFS, SECURED, F_MODE);
98 Set(P_INTERMUD, SAVE, F_MODE);
99 Set(P_IGNORE, ([]), F_VALUE);
100 Set(P_IGNORE, SAVE, F_MODE);
101 Set(P_BUFFER, SAVE, F_MODE);
102 Set(P_MESSAGE_PREPEND, SAVE, F_MODE_AS);
103 Set(P_MESSAGE_BEEP, SAVE, F_MODE_AS);
104}
105
106void create_super()
107{
108 set_next_reset(-1);
109}
110
Zesstra3a261e52022-02-10 14:00:31 +0100111private mapping build_colourmap(string ttype)
112{
113 mapping res = ([0:""]);
114 switch(ttype)
115 {
116 case "dumb":
117 return res;
118 case "ansi":
119 res = ([ 0:ANSI_NORMAL, "normal": ANSI_NORMAL,
120 "bold": ANSI_BOLD, "underlined": ANSI_UNDERL,
121 "blink": ANSI_BLINK, "invers": ANSI_INVERS,
122 "black": ANSI_BLACK, "red": ANSI_RED,
123 "green": ANSI_GREEN, "yellow": ANSI_YELLOW,
124 "blue": ANSI_BLUE, "purple": ANSI_PURPLE,
125 "cyan": ANSI_CYAN, "white": ANSI_WHITE,
126 "bg_black": ANSI_BG_BLACK, "bg_red": ANSI_BG_RED,
127 "bg_green": ANSI_BG_GREEN, "bg_yellow": ANSI_BG_YELLOW,
128 "bg_blue": ANSI_BG_BLUE, "bg_purple": ANSI_BG_PURPLE,
129 "bg_cyan": ANSI_BG_CYAN, "bg_white": ANSI_BG_WHITE,
130 "mention": ANSI_BOLD+ANSI_BG_BLUE,
131 ]);
132 break;
133 case "vt100":
134 res += ([0:ANSI_NORMAL, "normal": ANSI_NORMAL,
135 "bold": ANSI_BOLD, "underlined": ANSI_UNDERL,
136 "blink": ANSI_BLINK, "invers": ANSI_INVERS,
137 "mention": ANSI_BOLD,
138 ]);
139 break;
140 default:
141 assert(1, "Ungueltiger Terminaltyp in build_colourmap");
142 }
143 return res;
144}
145
146protected void set_colourmap(string ttype="ansi")
147{
148 colourmap = build_colourmap(ttype);
149}
150
Zesstra0681c732020-10-31 19:45:47 +0100151// called from base.c in Reconnect()
152protected void reconnect() {
153 // Cache fuer den report zuruecksetzen, der koennte veraltet sein (insb.
154 // falls in der letzten Session GMCP benutzt wurde und jetzt nicht).
155 report_cache = 0;
156}
157
MG Mud User88f12472016-06-24 23:31:02 +0200158protected void updates_after_restore(int newflag) {
Zesstra3a261e52022-02-10 14:00:31 +0100159 // Colourmap aktualisieren nach Restore
160 colourmap = build_colourmap(QueryProp(P_TTY));
161
MG Mud User88f12472016-06-24 23:31:02 +0200162 // Altes Ignoriere loeschen...
163 mixed ign = Query(P_IGNORE,F_VALUE);
164 if (!mappingp(ign))
165 {
166 if (pointerp(ign))
Bugfixb1d9b4d2021-09-14 20:07:04 +0200167 ReceiveNotify(break_string(
MG Mud User88f12472016-06-24 23:31:02 +0200168 "Deine Ignoriere-Einstellungen wurden soeben geloescht, "
169 "weil es eine Aktualisierung der Ignorierefunktion gab, "
170 "bei der eine Konversion der Daten leider nicht "
171 "moeglich war.",78), 0);
172
173 Set(P_IGNORE, ([]), F_VALUE);
174 }
175}
176
Zesstra2504b2d2020-05-22 12:30:17 +0200177static int set_report(string str)
178{
MG Mud User88f12472016-06-24 23:31:02 +0200179 int canflags = QueryProp(P_CAN_FLAGS);
MG Mud User88f12472016-06-24 23:31:02 +0200180 if(!str)
181 {
Zesstracf8f2952020-05-22 12:07:52 +0200182 if (stat_reports)
183 {
184 string *res=({});
185 if (stat_reports & DO_REPORT_HP)
186 res+=({"Lebenspunkte"});
187 if (stat_reports & DO_REPORT_SP)
188 res+=({"Konzentrationspunkte"});
189 if (stat_reports & DO_REPORT_POISON)
190 res+=({"Vergiftungen"});
191 if (stat_reports & DO_REPORT_WIMPY)
192 res+=({"Vorsicht"});
MG Mud User88f12472016-06-24 23:31:02 +0200193
Zesstracf8f2952020-05-22 12:07:52 +0200194 tell_object(ME,break_string(
MG Mud User88f12472016-06-24 23:31:02 +0200195 "Dir werden jetzt Veraenderungen Deiner "
196 +CountUp(res) + " berichtet.",78));
Zesstra86ec63b2020-05-22 12:09:56 +0200197 if (GMCP_Status("MG.char") || GMCP_Status("char")
198 || GMCP_Status("Char"))
199 {
200 tell_object(ME,break_string(
201 "Achtung: Dein Client laesst sich den Report per GMCP "
Zesstra2504b2d2020-05-22 12:30:17 +0200202 "(s. 'hilfe GMCP') uebermitteln. Daher wird er Dir nicht "
Zesstra86ec63b2020-05-22 12:09:56 +0200203 "in der Textausgabe des Spiels angezeigt! Moechtest Du "
204 "dies nicht, schalte bitte in Deinem Client GMCP-Module mit "
205 "Namen wie 'MG.char', 'char', 'Char' oder aehnliche aus."));
206 }
MG Mud User88f12472016-06-24 23:31:02 +0200207 }
208 else
209 tell_object(ME,
210 "Alle Statusreports sind ausgeschaltet.\n");
211
212 return 1;
213 }
Zesstra2504b2d2020-05-22 12:30:17 +0200214 else if (str == "aus")
215 {
216 if (stat_reports & DO_REPORT_HP || stat_reports & DO_REPORT_WIMPY)
217 {
MG Mud User88f12472016-06-24 23:31:02 +0200218 string s="";
Zesstra2504b2d2020-05-22 12:30:17 +0200219 if (stat_reports & DO_REPORT_HP)
220 {
MG Mud User88f12472016-06-24 23:31:02 +0200221 str="ebenfalls ";
222 tell_object(ME, "Der Report wurde ausgeschaltet.\n");
223 }
Zesstra2504b2d2020-05-22 12:30:17 +0200224 if ( stat_reports & DO_REPORT_WIMPY )
225 {
MG Mud User88f12472016-06-24 23:31:02 +0200226 tell_object(ME, "Der Vorsicht-Report wurde "+s+
227 "ausgeschaltet.\n");
228 }
229 stat_reports=0;
230 }
Zesstra2504b2d2020-05-22 12:30:17 +0200231 else
232 {
MG Mud User88f12472016-06-24 23:31:02 +0200233 tell_object(ME, "Der Report ist bereits ausgeschaltet.\n");
234 }
235 return 1;
236 }
Zesstra2504b2d2020-05-22 12:30:17 +0200237 else if (str == "ein")
238 {
239 if ( stat_reports & DO_REPORT_HP )
240 {
MG Mud User88f12472016-06-24 23:31:02 +0200241 tell_object(ME, "Der Report ist bereits eingeschaltet.\n");
242 return 1;
243 }
244 tell_object(ME, "Der Report wurde eingeschaltet.\n");
245 stat_reports |= DO_REPORT_HP;
Zesstra2504b2d2020-05-22 12:30:17 +0200246 if (!(canflags & CAN_REPORT_SP))
247 {
248 if (QueryQuest("Hilf den Gnarfen")==1)
249 {
MG Mud User88f12472016-06-24 23:31:02 +0200250 SetProp(P_CAN_FLAGS, canflags | CAN_REPORT_SP);
251 stat_reports |= DO_REPORT_SP;
252 }
Zesstra2504b2d2020-05-22 12:30:17 +0200253 else
254 {
MG Mud User88f12472016-06-24 23:31:02 +0200255 tell_object(ME, break_string(
256 "Fuer den Statusreport Deiner Konzentration musst Du jedoch "
257 "zunaechst die Quest \"Hilf den Gnarfen\" bestehen.",78));
258 }
259 }
Zesstra2504b2d2020-05-22 12:30:17 +0200260 else
261 {
MG Mud User88f12472016-06-24 23:31:02 +0200262 stat_reports |= DO_REPORT_SP;
263 }
Zesstra2504b2d2020-05-22 12:30:17 +0200264 if (!(canflags & CAN_REPORT_POISON))
265 {
266 if (QueryQuest("Katzenjammer")==1)
267 {
MG Mud User88f12472016-06-24 23:31:02 +0200268 SetProp(P_CAN_FLAGS, canflags | CAN_REPORT_POISON);
269 stat_reports |= DO_REPORT_POISON;
270 }
Zesstra2504b2d2020-05-22 12:30:17 +0200271 else
272 {
MG Mud User88f12472016-06-24 23:31:02 +0200273 tell_object(ME, break_string(
274 "Fuer den Statusreport Deiner Vergiftung musst Du jedoch "
275 "zunaechst die Quest \"Katzenjammer\" bestehen.",78));
276 }
277 }
Zesstra2504b2d2020-05-22 12:30:17 +0200278 else
279 {
MG Mud User88f12472016-06-24 23:31:02 +0200280 stat_reports |= DO_REPORT_POISON;
281 }
282 // Cache loeschen, damit beim naechsten Report-Event alle Daten neu
283 // eingetragen werden muessen. Muss beim Einschalten des Reports
284 // passieren, weil auch in der inaktiven Zeit weiterhin Aenderungen in
285 // status_report() eingehen, so dass der Cache zwar erst einmal leer ist,
286 // aber beim Wiedereinschalten nicht mehr ungueltig waere und somit
287 // veraltete Daten an den Spieler ausgegeben werden. Im unguenstigsten
288 // Fall wuerde das sogar dazu fuehren, dass die veralteten Daten lange
289 // Zeit nicht aktualisiert werden, wenn z.B. P_HP == P_MAX_HP, so dass
290 // kein P_HP-Event mehr eingeht.
291 report_cache=0;
Zesstra2504b2d2020-05-22 12:30:17 +0200292 // Fall-through fuer Statusausgabe
MG Mud User88f12472016-06-24 23:31:02 +0200293 }
Zesstra2504b2d2020-05-22 12:30:17 +0200294 else if (str == "vorsicht")
295 {
296 if (!(canflags & CAN_REPORT_WIMPY))
297 {
298 if (QueryQuest("Schrat kann nicht einschlafen")==1)
299 {
MG Mud User88f12472016-06-24 23:31:02 +0200300 SetProp(P_CAN_FLAGS, canflags | CAN_REPORT_WIMPY);
301 tell_object(ME, "Der Vorsicht-Report wurde eingeschaltet.\n");
302 stat_reports |= DO_REPORT_WIMPY;
303 }
Zesstra2504b2d2020-05-22 12:30:17 +0200304 else
305 {
MG Mud User88f12472016-06-24 23:31:02 +0200306 tell_object(ME, break_string(
307 "Fuer den Statusreport Deiner Vorsicht musst Du "
308 "zunaechst die Quest \"Schrat kann nicht einschlafen\" "
309 "bestehen.",78));
310 }
311 }
312 else
313 {
314 stat_reports |= DO_REPORT_WIMPY;
315 }
316 // fuer Seher auch Bericht der Fluchtrichtung einschalten.
317 if ((stat_reports & DO_REPORT_WIMPY)
318 && !(stat_reports & DO_REPORT_WIMPY_DIR)
319 && ((canflags & CAN_REPORT_WIMPY) || IS_SEER(ME)))
320 {
Zesstra2504b2d2020-05-22 12:30:17 +0200321 stat_reports |= DO_REPORT_WIMPY_DIR;
MG Mud User88f12472016-06-24 23:31:02 +0200322 }
Zesstra2504b2d2020-05-22 12:30:17 +0200323 // Fall-through fuer Statusausgabe
MG Mud User88f12472016-06-24 23:31:02 +0200324 }
325 // sendet einmalig genau jetzt den konfigurierten report. Kann zum testen
326 // (von Triggern) oder beim Login benutzt werden, wenn man einen initialen
327 // Datenbestand erhalten will.
328 else if (str=="senden")
329 {
330 // Es wird Ausgabe von LP und Vorsicht getriggert, das sendet beide
331 // Zeilen.
332 status_report(DO_REPORT_HP, QueryProp(P_HP));
333 status_report(DO_REPORT_WIMPY, QueryProp(P_WIMPY));
334 return 1;
335 }
336 else
337 return 0;
338 // nur aktuellen Zustand berichten
339 set_report(0);
340 return 1;
341}
342
343private string get_poison_desc(int p) {
344 string ret;
345 if ( intp(p) ) {
346 switch(p) {
347 case 0: ret="keins"; break;
348 case 1..3: ret="leicht"; break;
349 case 4..8: ret="gefaehrlich"; break;
350 default: ret="sehr ernst"; break;
351 }
352 return ret;
353 }
354 else return "(nicht verfuegbar)";
355}
356
357// sprintf()-Formatstrings fuer die Reportausgabe.
358#define REPORTLINE "LP: %3d, KP: %3s, Gift: %s.\n"
359#define REPORTLINE_WIMPY "Vorsicht: %d, Fluchtrichtung: %s.\n"
360// Defines zur Adressierung der Cache-Eintraege
361#define REP_HP 0
362#define REP_SP 1
363#define REP_POISON 2
364
365protected void status_report(int type, mixed val) {
366 // Wenn der Spieler GMCP hat und das sich um die Information kuemmert,
367 // erfolgt keine textuelle Ausgabe mehr. Daher return, wenn GMCP_Char()
368 // erfolg vermeldet hat.
369 int flags = QueryProp(P_CAN_FLAGS);
370 switch (type) {
371 case DO_REPORT_HP:
372 if (GMCP_Char( ([ P_HP: val ]) ) ) return;
373 break;
374 case DO_REPORT_SP:
375 if (!(flags & CAN_REPORT_SP)) return;
376 if (GMCP_Char( ([ P_SP: val ]) ) ) return;
377 break;
378 case DO_REPORT_POISON:
379 if (!(flags & CAN_REPORT_POISON)) return;
380 if (GMCP_Char( ([ P_POISON: val ]) ) ) return;
381 break;
382 case DO_REPORT_WIMPY:
383 if (!(flags & CAN_REPORT_WIMPY)) return;
384 if (GMCP_Char( ([ P_WIMPY: val ]) ) ) return;
385 break;
386 case DO_REPORT_WIMPY_DIR:
387 if (!(flags & CAN_REPORT_WIMPY_DIR)) return;
388 if (GMCP_Char( ([ P_WIMPY_DIRECTION: val ]) ) ) return;
389 break;
390 }
391
392 // konventionelle textuelle Ausgabe des Reports ab hier.
393 if (!(type & stat_reports))
394 return;
395
396 if ( !report_cache ) {
397 report_cache = ({
398 QueryProp(P_HP),
399 (stat_reports&DO_REPORT_SP) ? to_string(QueryProp(P_SP)) : "###",
400 (stat_reports&DO_REPORT_POISON) ?
401 get_poison_desc(QueryProp(P_POISON)) : "(nicht verfuegbar)"
402 });
403 }
404
405 switch(type) {
406 // LP berichten: Cache aktualisieren und Meldung ausgeben.
407 case DO_REPORT_HP:
408 report_cache[REP_HP]=val;
409 tell_object(ME, sprintf(REPORTLINE, report_cache[REP_HP],
410 report_cache[REP_SP], report_cache[REP_POISON]));
411 break;
412 // KP berichten: Wenn der Spieler den Report freigeschaltet hat,
413 // wird bei Aenderungen gemeldet. Wenn nicht, aendert sich nur der
414 // Cache-Eintrag. So wird verhindert, dass ein Spieler ueber KP-
415 // Veraenderungen auch dann informiert wuerde, wenn er den KP-Report
416 // gar nicht benutzen koennte.
417 case DO_REPORT_SP:
418 report_cache[REP_SP]=to_string(val);
419 tell_object(ME, sprintf(REPORTLINE, report_cache[REP_HP],
420 report_cache[REP_SP], report_cache[REP_POISON]));
421 break;
422 // Giftstatus berichten: Wenn der Giftreport freigeschaltet ist,
423 // Cache aktualisieren und berichten. Wenn nicht, aendert sich nur
424 // der Cache-Eintrag. Erlaeuterung hierzu s.o. beim KP-Report.
425 case DO_REPORT_POISON:
426 report_cache[REP_POISON] = get_poison_desc(val);
427 tell_object(ME, sprintf(REPORTLINE, report_cache[REP_HP],
428 report_cache[REP_SP], report_cache[REP_POISON]));
429 break;
430 // Vorsicht-Report: kann ohne weitere Abfragen ausgegeben werden, da
431 // alle noetigen Checks schon zu Beginn dieser Funktion erledigt wurden.
432 // Lediglich der Inhalt der Meldung muss abhaengig vom Seherstatus
433 // konfiguriert werden.
434 case DO_REPORT_WIMPY:
435 string res;
436 if (IS_SEER(ME)) {
437 // QueryProp() aus Kostengruenden im if(), damit die Aufruf-
438 // Haeufigkeit zumindest ein wenig reduziert wird.
439 string dir = QueryProp(P_WIMPY_DIRECTION)||"keine";
440 res = sprintf(REPORTLINE_WIMPY, val, dir);
441 }
442 else
443 res = sprintf(REPORTLINE_WIMPY, val, "(nicht verfuegbar)");
444 tell_object(ME, res);
445 break;
446 // Fluchtrichtungs-Report: wird nur bei Sehern ausgegeben, damit
447 // nicht auch Spieler eine VS-/FR-Meldung bekommen, wenn z.B. eine
448 // externe Manipulation der Fluchtrichtung stattfindet, sie aber den
449 // Report mangels Seherstatus gar nicht freigeschaltet haben.
450 case DO_REPORT_WIMPY_DIR:
451 if (IS_SEER(ME)) {
452 if (!val) val = "keine";
453 tell_object(ME,sprintf(REPORTLINE_WIMPY, QueryProp(P_WIMPY), val));
454 }
455 break;
456 }
457}
458
459#undef REPORTLINE
460#undef REPORTLINE_WIMPY
461#undef REP_HP
462#undef REP_SP
463#undef REP_POISON
464
465private string permutate(string msg)
466{
467 // Kontrollzeichen rausfiltern. *seufz*
468 msg = regreplace(msg,"[[:cntrl:]]","",RE_PCRE|RE_GLOBAL);
469 object ob=QueryProp(P_PERM_STRING);
470 if (!objectp(ob))
471 return msg;
472
Zesstra04f613c2019-11-27 23:32:54 +0100473 return ({string})ob->permutate_string(msg)||"";
MG Mud User88f12472016-06-24 23:31:02 +0200474}
475
476// neue nachricht an den Kobold anhaengen
477// Rueckgabewerte: MSG_BUFFER_FULL oder MSG_BUFFERED
478private int add_to_kobold(string msg, int msg_type, string msg_action,
479 string msg_prefix, object origin)
480{
481 // Nachricht soll im Kobold gespeichert werden.
482 // Kobold speichert Rohdaten und gibt spaeter das ganze auch wieder via
483 // ReceiveMsg() aus - dabei wird MSG_DONT_BUFFER | MSG_DONT_STORE gesetz,
484 // damit keine erneute Speicher in Kobold oder Komm-History erfolgt.
485
486 // wenn der Puffer zu klein ist, Groesse verdoppeln, wenn noch unterhalb
487 // des Limits.
488 if (kobold->index >= sizeof(kobold->buf)-1) {
489 if (sizeof(kobold->buf) < MAX_KOBOLD_LIMIT)
490 kobold->buf += allocate(sizeof(kobold->buf));
491 else
492 return MSG_BUFFER_FULL;
493 }
494 kobold->index = kobold->index +1;
495 // neue Nachricht an den Puffer anhaengen.
496 string sendername = query_once_interactive(origin) ?
497 origin->query_real_name() :
498 origin->name(WER) || "<Unbekannt>";
Zesstraa5fda4a2022-01-06 17:31:44 +0100499 kobold->buf[kobold->index] = (<kobold_msg_s> msg: msg,
MG Mud User88f12472016-06-24 23:31:02 +0200500 type : msg_type, action : msg_action, prefix : msg_prefix,
501 sendername : sendername);
502 return MSG_BUFFERED;
503}
504
505private void _flush_cache(int verbose) {
506 // nur mit genug Evalticks ausgeben.
507 if (get_eval_cost() < 100000) return;
508 if (kobold->index >= 0)
509 {
510 ReceiveMsg("Ein kleiner Kobold teilt Dir folgendes mit:",
511 MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_BUFFER,
512 0, 0, this_object());
513 int prepend = QueryProp(P_MESSAGE_PREPEND);
514 foreach(int i: 0 .. kobold->index) // '0 ..' ist wichtig!
515 {
Zesstraa5fda4a2022-01-06 17:31:44 +0100516 struct kobold_msg_s msg = kobold->buf[i];
MG Mud User88f12472016-06-24 23:31:02 +0200517 // dies ist dient der Fehlerabsicherung, falls es nen Fehler (z.B. TLE)
518 // in der Schleife unten gab: dann ist index nicht auf -1 gesetzt
519 // worden, aber einige Nachrichten sind schon geloescht.
520 if (!structp(msg)) continue;
521 // Ausgabe via efun::tell_object(), weil die Arbeit von ReceiveMsg()
Zesstra3a261e52022-02-10 14:00:31 +0100522 // schon getan wurde. Allerdings muessen wir uns noch um den Umbruch
523 // und Farben kuemmern.
524 msg->msg = terminal_colour(msg->msg, colourmap);
MG Mud User88f12472016-06-24 23:31:02 +0200525 if ((msg->type) & MSG_DONT_WRAP)
526 msg->msg = (msg->prefix ? msg->prefix : "") + msg->msg;
527 else
528 {
529 int bsflags = msg->type & MSG_ALL_BS_FLAGS;
530 if (prepend)
531 bsflags |= BS_PREPEND_INDENT;
532 msg->msg = break_string(msg->msg, 78, msg->prefix, bsflags);
533 }
534 efun::tell_object(this_object(), msg->msg);
535 kobold->buf[i]=0;
536 }
537 kobold->index=-1;
538 }
539 else if (verbose)
540 {
541 ReceiveMsg("Der kleine Kobold hat leider nichts Neues fuer Dich.",
542 MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_BUFFER,
543 0, 0, this_object());
544 }
545}
546
547varargs int cmd_kobold(string arg)
548{
549 switch(arg)
550 {
551 case "ein":
552 SetProp(P_BUFFER, 1);
553 printf("Der Kobold merkt sich jetzt alles!\n"); break;
554 case "aus":
555 SetProp(P_BUFFER, 0);
556 printf("Der Kobold wird Dich nicht stoeren!\n"); break;
557 default: if(arg) printf("Der Kobold sagt: kobold ein oder kobold aus\n");
558 }
559 _flush_cache(1);
560 return 1;
561}
562
563public int TestIgnoreSimple(string *arg)
Zesstrade642d22019-11-23 17:22:34 +0100564{ mapping ignore;
MG Mud User88f12472016-06-24 23:31:02 +0200565
566 if (!pointerp(arg) || !mappingp(ignore=Query(P_IGNORE,F_VALUE)))
567 return 0;
568 foreach(string s: arg)
569 {
570 if (member(ignore,s))
571 return 1;
572 }
573 return 0;
574}
575
576//TODO: deprecated - entfernen, wenn Message() entfernt wird.
577private int check_ignore(mixed ignore, string verb, string name)
578{
579 if (ignore == verb)
580 return 1;
581 ignore = explode(ignore, ".");
582 return ((sizeof(ignore) > 1) &&
583 (name == ignore[0] && member(ignore[1..], verb) != -1));
584}
585
Zesstra3a261e52022-02-10 14:00:31 +0100586// Die Nachricht kommt mit einem Alert oder Mention. comm_beep() prueft, ob
587// ein Piepston ausgegeben werden soll (langfristig andere Benachrichtigungen
588// geplant!).
589// Ueblicherweise werden nur alle <P_MESSAGE_BEEP> Sekunden Toene
590// uebermittelt.
591private void comm_beep(string msg_action, int mention=0)
Bugfix60f5bc62022-01-21 11:09:56 +0100592{
Zesstra1cc6cf32022-02-09 11:49:31 +0100593 // Wenn Alerts komplett abgeschaltet sind, gibts nix.
594 int alert_config = ({int})QueryProp(P_ALERT);
595 if (alert_config & AL_NO_SOUND)
596 return; // kein ton
597 // und maximal alle P_MESSAGE_BEEP Sekunden aufmerksam machen; bei 0s ist
598 // jedes Mal erlaubt.
Zesstra04f613c2019-11-27 23:32:54 +0100599 int beep_interval=({int})QueryProp(P_MESSAGE_BEEP);
Zesstra1cc6cf32022-02-09 11:49:31 +0100600 if ((time()-last_beep_time) < beep_interval)
601 return;
602 int required;
603 switch(msg_action)
Bugfix60f5bc62022-01-21 11:09:56 +0100604 {
Zesstra1cc6cf32022-02-09 11:49:31 +0100605 case MA_TELL:
606 required |= MB_TELL;
607 break;
608 case MA_SAY:
609 required |= MB_SAY;
610 break;
611 case MA_CHANNEL:
612 required |= MB_CHANNEL;
613 break;
614 case MA_SHOUT:
615 required |= MB_SHOUT;
616 break;
617 default:
618 // Alle anderen Aktionen, die keine gesonderten Aktionsfilter haben
619 required |= MB_MISC;
620 break;
Bugfix60f5bc62022-01-21 11:09:56 +0100621 }
Zesstra3a261e52022-02-10 14:00:31 +0100622 if (mention)
623 required |= MB_MENTION;
624
Zesstra1cc6cf32022-02-09 11:49:31 +0100625 // wenn in alert min. ein notwendiges Flag drin ist darf gepiepst werden
626 if (required & alert_config)
627 {
628 last_beep_time = time();
629 binary_message(b"\a", 1);
630 }
MG Mud User88f12472016-06-24 23:31:02 +0200631}
632
633private varargs void add_to_tell_history( string uid, int sent, int recv,
634 string message, string indent, int flags )
635{
636 /* tell_history ist ein Mapping mit UIDs der Gespraechspartner als Key.
637 Als Wert ist eine Strukur vom Typ chat_s eingetragen.
638 Strukturen chat_s und stored_msg_s sind in /std/player/comm_structs.c
639 definiert.
640 TODO fuer spaeter, gerade keine Zeit fuer:
641 Als Wert ist ein Array von chat_s enthalten, wobei das 0. Element das
642 jeweils juengste Gespraech mit diesem Gespraechspartner ist und alle
643 weiteren Elemente in der zeitlichen Reihenfolge kommen (also letztes
644 Element ist aeltestes Gespraech).
645 */
646
647 //TODO: Entfernen, wenn das nicht mehr passiert.
648 if (!stringp(uid))
649 {
650 ReceiveMsg(sprintf(
651 "\nadd_to_tell_history(): got bad uid argument %O."
652 "sent: %d, recv: %d, flags: %d, msg: %s",
Zesstra996bafe2022-02-14 22:42:39 +0100653 uid, sent, recv, flags, message),MT_DEBUG|MSG_BS_LEAVE_LFS,0,0,ME);
MG Mud User88f12472016-06-24 23:31:02 +0200654 }
Zesstraa31cd5c2016-12-17 20:11:07 +0100655
Zesstra996bafe2022-02-14 22:42:39 +0100656 // Gespraechspartner fuer erwidere auch ohne tmhist speichern.
Zesstraa31cd5c2016-12-17 20:11:07 +0100657 if (flags & (MSGFLAG_TELL|MSGFLAG_RTELL))
MG Mud User88f12472016-06-24 23:31:02 +0200658 last_comm_partner = uid;
659
660 // ist ein sortiertes Array von max. MAX_SAVED_CHATS Groesse, welches die
661 // Spieler enthaelt, denen man schon was mitgeteilt hat. Aktuellste am
662 // Anfang.
663 if (sent) {
664 if (!sizeof(commreceivers))
665 commreceivers = ({uid});
666 else if (commreceivers[0] != uid) {
667 // nur wenn der aktuelle Partner nicht am Anfang steht, muss man hier was
668 // tun. Comm-Partner an den Anfang stellen und ggf. alten Eintrag
669 // entfernen.
670 // TODO: Effizienter gestalten.
671 commreceivers = ({uid}) + (commreceivers-({uid}));
672 // ggf. kuerzen. (wenn !tell_history_enabled, wird es ggf. unten
673 // gemacht, denn die Hist muss min. alle UID enthalten, die auch in
674 // commreceivers drin sind.)
675 if (!tell_history_enabled && sizeof(commreceivers) > MAX_SAVED_CHATS)
676 commreceivers = commreceivers[0..MAX_SAVED_CHATS];
677 }
678 }
679
Zesstra996bafe2022-02-14 22:42:39 +0100680 // mit eingeschalteter History weitere Details speichern.
MG Mud User88f12472016-06-24 23:31:02 +0200681 if (!tell_history_enabled)
682 return;
683
684 if (!indent && message[<1] == 10)
685 message = message[..<2];
686
687 struct chat_s chat;
688 // Gespraechspartner unbekannt?
689 if (!member(tell_history, uid)) {
690 // zuviele Gespraeche in Hist? >= ist Absicht weil ja gleich noch eins
691 // dazu kommt.
692 if (sizeof(tell_history) >= MAX_SAVED_CHATS) {
693 string deluid;
694 int zeit = __INT_MAX__;
695 foreach(string tuid, chat : tell_history) {
696 // aeltestes Gespraech suchen
697 if (zeit > chat->time_last_msg) {
698 deluid = tuid;
699 zeit = chat->time_last_msg;
700 }
701 }
702 // aeltestes Gespraech raus.
703 m_delete(tell_history, deluid);
704 if (member(commreceivers,deluid)>-1)
705 commreceivers-=({deluid});
706 }
707 // neues Gespraech anlegen
708 chat = (<chat_s> uid: uid, time_first_msg: time(),
709 time_last_msg: time(),
710 sentcount: sent, recvcount: recv,
711 msgbuf: 0, ptr: 0 );
712 tell_history[uid] = chat;
713 }
714 else {
715 // Gespraechspartner bekannt, altes Gespraech weiterbenutzen
716 chat = tell_history[uid];
717 chat->time_last_msg = time();
718 chat->sentcount += sent;
719 chat->recvcount += recv;
720 }
721
Zesstra996bafe2022-02-14 22:42:39 +0100722 // ggf. auch INhalte von Gespraechen speichern
MG Mud User88f12472016-06-24 23:31:02 +0200723 if (tell_history_enabled < TELLHIST_ENABLED)
724 return;
725
726 // ggf. Array fuer Messages anlegen
727 if (!pointerp(chat->msgbuf))
728 chat->msgbuf = allocate(MAX_SAVED_MESSAGES);
729
730 // Message-Struktur ermitteln oder neu anlegen
731 struct stored_msg_s msg;
732 if (!structp(chat->msgbuf[chat->ptr])) {
733 // neue Struct ins Array schreiben
734 chat->msgbuf[chat->ptr] = msg = (<stored_msg_s>);
735 }
736 else {
737 // alte Struct ueberschreiben
738 msg = chat->msgbuf[chat->ptr];
739 }
740 // Index auf naechste Messagestruktur ermitteln
741 chat->ptr = (chat->ptr + 1) % MAX_SAVED_MESSAGES;
742 // Message speichern
743 msg->msg = message;
744 msg->prefix = indent;
745 msg->timestamp = time();
746}
747
Zesstra996bafe2022-02-14 22:42:39 +0100748protected void clear_tell_history(int force)
MG Mud User88f12472016-06-24 23:31:02 +0200749{
750 /* Nach einem "schlafe ein" werden die gespeicherten Mitteilungen geloescht,
751 sofern der Spieler nichts abweichendes eingestellt hat. */
752
Zesstra996bafe2022-02-14 22:42:39 +0100753 // bei manuellem Loeschen (force==1) immer loeschen, ansonsten nur, wenn die
754 // History nicht "long-life" ist.
755 if (tell_history_enabled < TELLHIST_LONGLIFE || force)
756 {
757 tell_history = ([]);
758 commreceivers = ({});
759 }
MG Mud User88f12472016-06-24 23:31:02 +0200760}
761
762protected void reset(void)
763{
764 /* Wird 15 Minuten nach dem Verlust der Verbindung aufgerufen. Falls der
765 Spieler nicht inzwischen eine Verbindung wiederhergestellt hat, werden
766 wie bei einem "schlafe ein" die Mitteilungen geloescht. */
767
768 if (!interactive())
Zesstra996bafe2022-02-14 22:42:39 +0100769 clear_tell_history(0);
MG Mud User88f12472016-06-24 23:31:02 +0200770
771}
772
773// gerufen, wenn zielgerichtet mit jemandem kommuniziert wird _und_ das
774// Ergebnis des ReceiveMsg() geprueft werden und eine Meldung ausgegeben
775// werden soll.
776private void _send(object ob, string msg, int msg_type,
777 string msg_action, string msg_prefix)
778{
779 int res = ob->ReceiveMsg(msg, msg_type, msg_action, msg_prefix, ME);
780 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
812// Ausgabe an das Objekt selber und Aufzeichnung in der Kommhistory, falls
813// noetig. Wird bei _ausgehenden_ Nachrichten im eigenen Objekt gerufen, damit
814// die Nachricht ggf. in den Kommhistory erfasst wird.
815// TODO: entfernen, wenn alles Aufrufer ersetzt sind durch ReceiveMsg().
816protected varargs int _recv(object ob, string message, int flag, string indent)
817{
818 write(break_string(message, 78, indent,
819 QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0));
820 if ((flag & MSGFLAG_TELL || flag & MSGFLAG_REMOTE) &&
821 query_once_interactive(ob))
822 {
823 if (flag & MSGFLAG_WHISPER)
824 add_to_tell_history(getuid(ob), 1, 0,
825 "Du fluesterst " + ob->name(WEM) + " aus der Ferne etwas zu.", 0,
826 flag);
827 else
828 add_to_tell_history(getuid(ob), 1, 0, message, indent, flag);
829 }
830 return 1;
831}
832
833// <sender> sollte ein Objekt sein. In seltenen Faellen (z.B.
834// Fehlerbehandlung) ist es jedoch auch mal ein String.
835varargs int Message(string msg, int flag, string indent,
836 string cname, mixed sender)
837{
838 object ti;
839 string verb, reply, *ignore, tin;
840 int em, te;
841 mixed deaf;
842
843 // Bei den Kanaelen 'Debug' und 'Entwicklung' kann man gezielt Bugs
844 // einzelner Magier ignorieren. Dazu wird der Kanalname zum 'verb',
845 // damit 'ignoriere name.debug' funktioniert.
846 if( flag == MSGFLAG_CHANNEL ){
847 if((msg[1..5] == "Debug" || msg[1..11] == "Entwicklung"
848 || msg[1..9]=="Warnungen"))
849 {
850 // Missbrauch der Variable 'ignore' als Zwischenspeicher
851 ignore = regexplode( msg, ":| |\\]" );
852 verb = lower_case(ignore[0][1..]);
853 tin = lower_case(ignore[2]);
854 }
855 else
856 {
857 if(cname)
858 verb=lower_case(cname);
859 else
860 verb=query_verb();
861 if( ti = this_interactive() )
862 {
863 tin = getuid(this_interactive());
864 }
865 else
866 {
867 //falls doch kein Objekt...
868 if (objectp(sender))
869 tin=lower_case(sender->name(RAW)||"<Unbekannt>");
870 }
871 }
872 }
873 else {
874 if( ti = this_interactive() )
875 tin = getuid(this_interactive());
876 verb = query_verb();
877 }
878
879 te = flag & (MSGFLAG_TELL | MSGFLAG_WHISPER);
880
881 // fuer "erwidere"
882 if (ti && (flag & MSGFLAG_TELL || flag & MSGFLAG_REMOTE)) {
883 if (!ti->QueryProp(P_INVIS)||IS_LEARNER(ME)) {
884 if (flag & MSGFLAG_WHISPER)
885 add_to_tell_history(getuid(ti), 0, 1,
886 capitalize((((IS_LEARNER(ti) && !ti->QueryProp(P_INVIS) &&
887 (ti->QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ?
888 ti->QueryProp(P_PRESAY) : "") + ti->name()) || "") +
889 " fluestert Dir aus der Ferne etwas zu.", 0, flag, 0);
890 else
891 add_to_tell_history(getuid(ti), 0, 1, msg, indent, flag, 0);
892 }
893 }
894 // Hoert der Spieler nicht?
895 em = (ti &&
896 (te || flag & MSGFLAG_SHOUT) &&
897 (QueryProp(P_EARMUFFS) &&
898 (query_wiz_level(ti) < QueryProp(P_EARMUFFS))));
899 ignore = (pointerp(ignore = QueryProp(P_IGNORE)) ? ignore : ({}));
900
901 // Werden der Sender oder das Verb ignoriert?
902 if(!ti && tin && flag == MSGFLAG_CHANNEL)
903 {
904 if((member(ignore, tin) != -1))
905 {
906 return MESSAGE_IGNORE_YOU;
907 }
908 if(verb && sizeof(filter(ignore, #'check_ignore, verb, tin)) )
909 {
910 return MESSAGE_IGNORE_YOU;
911 }
912 }
913 if (ti && (member(ignore, getuid(ti)) != -1)) {
914 if(te && (IS_LEARNER(ti)||!QueryProp(P_INVIS)))
915 efun::tell_object(ti, capitalize(name())+
916 " hoert gar nicht zu, was Du sagst.\n");
917 return MESSAGE_IGNORE_YOU;
918 }
919 if(tin && verb &&
920 sizeof(filter(ignore, #'check_ignore/*'*/, verb, tin)))
921 {
922 if(ti && verb[0..2] != "ruf" && verb[0..3] != "mruf" &&
923 verb[0..3] != "echo" && verb[0] != '-' && !(flag & MSGFLAG_CHANNEL) )
924 efun::tell_object(ti, name()+" wehrt \""+verb+"\" ab.\n");
925 return MESSAGE_IGNORE_VERB;
926 }
927 if (flag & MSGFLAG_RTELL) {
928 int at;
929
930 verb = lower_case(old_explode(msg, " ")[0][1..]);
931 at = member(verb, '@');
932 /* verb wird hier eh missbraucht, also auch fuer ein intermud-erwidere*/
933 add_to_tell_history(verb, 0, 1, msg, indent, flag, 0);
934
935 if ((member(ignore, verb) >= 0) || (member(ignore,verb[0..at]) >= 0))
936 return MESSAGE_IGNORE_YOU;
937 else if (at > 0 && member(ignore, verb[at..]) >= 0)
938 return MESSAGE_IGNORE_MUD;
939 }
940
941 // Taubheit/Oropax
942 te |= (flag & MSGFLAG_SAY);
943
944 if (QueryProp(P_DEAF) && (flag & MSGFLAG_DEAFCHK) && !(flag & MSGFLAG_CHIST)) {
945 deaf = QueryProp(P_DEAF);
946 if (te)
947 reply = stringp(deaf) ?
948 capitalize(sprintf(deaf, name())) :
949 capitalize(name())+" ist momentan leider taub.\n";
950 }
951 else if (em)
952 reply = capitalize(name())+" hat Oropax in den Ohren.\n";
953
954 msg = break_string(msg, 78, indent,
955 (QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0) | BS_LEAVE_MY_LFS);
956
957 if(QueryProp(P_BUFFER) &&
958 (deaf ||
959 query_editing(this_object()) ||
960 query_input_pending(this_object())))
961 {
962 deaf = MESSAGE_DEAF;
963 if(flag & MSGFLAG_CACHE)
964 {
965 if(!stringp(reply))
966 reply = name()+" moechte gerade nicht gestoert werden.\n";
967
968 msg = msg[0..<2]+" [" + strftime("%H:%M",time()) + "]\n";
969
970 int res = add_to_kobold(msg, 0, 0, 0,
971 objectp(sender) ? sender : ME);
972 if(res == MSG_BUFFERED)
973 {
974
975 reply += "Die Mitteilung wurde von einem kleinen Kobold in Empfang "+
976 "genommen.\nEr wird sie spaeter weiterleiten!";
977 deaf = MESSAGE_CACHE;
978 }
979 else {
980 reply += "Die Mitteilung ging verloren, denn "+
981 "der Kobold kann sich nichts mehr merken!";
982 deaf = MESSAGE_CACHE_FULL;
983 }
984 if(ti && (IS_LEARNER(ti)||!QueryProp(P_INVIS)))
985 efun::tell_object(ti, reply+"\n");
986 }
987 return deaf;
988 }
989 else if((deaf || em) &&
990 ( (flag & MSGFLAG_RTELL) ||
991 (ti && (IS_LEARNER(ti)||!QueryProp(P_INVIS))))) {
992 if (te && ti)
993 efun::tell_object(ti, reply);
994 return MESSAGE_DEAF;
995 }
996
997 _flush_cache(0);
998 if(te && QueryProp(P_AWAY))
999 msg = msg[0..<2]+" [" + strftime("%H:%M",time()) + "]\n";
1000
Zesstra1cc6cf32022-02-09 11:49:31 +01001001 if(!objectp(sender) || sender != ME)
Bugfix60f5bc62022-01-21 11:09:56 +01001002 {
Zesstra1cc6cf32022-02-09 11:49:31 +01001003 if (flag & MSGFLAG_SAY)
1004 comm_beep(MA_SAY);
1005 else if (flag & MSGFLAG_TELL)
1006 comm_beep(MA_TELL);
1007 else if (flag & MSGFLAG_CHANNEL)
1008 comm_beep(MA_CHANNEL);
1009 else if (flag & MSGFLAG_SHOUT)
1010 comm_beep(MA_SHOUT);
MG Mud User88f12472016-06-24 23:31:02 +02001011 }
1012 efun::tell_object(ME, msg);
1013 return MESSAGE_OK;
1014}
1015
1016static int ignoriere(string str)
1017{
1018 str = _unparsed_args(1);
1019 mapping ignore=Query(P_IGNORE, F_VALUE);
1020
1021 if (!str)
1022 {
1023 string* ignarr = m_indices(ignore);
1024 if (!sizeof(ignarr))
1025 tell_object(ME, "Du ignorierst niemanden.\n");
1026 else
1027 ReceiveMsg("Du ignorierst:\n"
1028 + break_string(CountUp(map(sort_array(ignarr, #'> ),
1029 #'capitalize )
1030 ) + ".",78),
1031 MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE|MSG_DONT_WRAP,
1032 0,0,this_object());
1033 return 1;
1034 }
1035 // trim spaces from args and convert to lower case.
1036 str = lower_case(trim(str, TRIM_BOTH));
1037
1038 if (member(ignore, str))
1039 {
1040 RemoveIgnore(str);
1041 tell_object(ME, sprintf("Du ignorierst %s nicht mehr.\n", capitalize(str)));
1042 }
1043 else if (sizeof(ignore)>100)
1044 {
1045 tell_object(ME, "Du ignorierst schon genuegend!\n");
1046 }
1047 else if (AddIgnore(str) == 1)
1048 {
1049 tell_object(ME,
1050 sprintf("Du ignorierst jetzt %s.\n", capitalize(str)));
1051 }
1052 else
1053 {
1054 tell_object(ME,
1055 sprintf("'%s' kannst Du nicht ignorieren.\n",str));
1056 }
1057 return 1;
1058}
1059
1060
Zesstra1cc6cf32022-02-09 11:49:31 +01001061private int _alert_filter_flags(int flag, string text)
Bugfix60f5bc62022-01-21 11:09:56 +01001062{
1063 return (flag & QueryProp(P_ALERT));
1064}
1065
Zesstra1cc6cf32022-02-09 11:49:31 +01001066static int _msg_beep(string str)
1067{
1068 int beep_interval;
1069
1070 notify_fail(
1071 "Syntax:\n"
1072 "- klingelton <1 bis 3600 Sekunden>\n"
1073 "- klingelton aus\n"
1074 "- klingelton ein\n"
1075 "- klingelton <+/-><tm / sag / ebenen / ruf / erwaehnung / sonstige / alle / >\n");
1076
1077 if(!sizeof(str))
1078 return 0;
1079 if (regmatch(str,"^[[:alpha:]]", RE_PCRE))
Bugfix60f5bc62022-01-21 11:09:56 +01001080 {
MG Mud User88f12472016-06-24 23:31:02 +02001081 if (str=="aus")
Zesstra1cc6cf32022-02-09 11:49:31 +01001082 SetProp(P_ALERT, QueryProp(P_ALERT) | AL_NO_SOUND);
1083 else if (str=="ein")
1084 SetProp(P_ALERT, QueryProp(P_ALERT) & ~AL_NO_SOUND);
Bugfix60f5bc62022-01-21 11:09:56 +01001085 else
1086 {
1087 mapping flags = ([
Zesstra1cc6cf32022-02-09 11:49:31 +01001088 "tm": MB_TELL, "teilemit": MB_TELL,
1089 "sag": MB_SAY, "sage": MB_SAY,
1090 "ebene": MB_CHANNEL, "ebenen": MB_CHANNEL,
1091 "ruf": MB_SHOUT, "rufe": MB_SHOUT,
Zesstra3a261e52022-02-10 14:00:31 +01001092 "erwaehnung": MB_MENTION, "erwaehnungen": MB_MENTION,
Zesstra1cc6cf32022-02-09 11:49:31 +01001093 "sonstige": MB_MISC, "sonstiges": MB_MISC,
1094 "alle": MB_ALL, "alles": MB_ALL,
1095 ]);
Bugfix60f5bc62022-01-21 11:09:56 +01001096 foreach(string part : explode(str, " ") - ({""}))
1097 {
1098 if(!(part[1..] in flags)) continue;
1099 if(part[0] == '+')
1100 {
1101 SetProp(P_ALERT,
1102 QueryProp(P_ALERT) | flags[part[1..]]);
1103 }
1104 else if(part[0] == '-')
1105 {
1106 SetProp(P_ALERT,
1107 QueryProp(P_ALERT) & ~ flags[part[1..]]);
1108 }
1109 }
1110 }
MG Mud User88f12472016-06-24 23:31:02 +02001111 }
Zesstra1cc6cf32022-02-09 11:49:31 +01001112 else
1113 {
1114 beep_interval = to_int(str);
1115 if(beep_interval >= 0)
1116 {
1117 SetProp(P_MESSAGE_BEEP, beep_interval);
1118 }
1119 }
MG Mud User88f12472016-06-24 23:31:02 +02001120
Zesstra593b2c72019-11-27 23:37:03 +01001121 beep_interval=({int})QueryProp(P_MESSAGE_BEEP);
Bugfix60f5bc62022-01-21 11:09:56 +01001122 mapping text = ([
1123 MB_SAY: "sage",
1124 MB_TELL: "teile mit",
1125 MB_CHANNEL: "Ebenenmeldungen",
Zesstra3a261e52022-02-10 14:00:31 +01001126 MB_MENTION: "Erwaehnungen",
Zesstra1cc6cf32022-02-09 11:49:31 +01001127 MB_SHOUT: "rufe",
1128 MB_MISC: "sonstige",]);
1129 string types = CountUp(map(filter(m_indices(text), #'_alert_filter_flags), text));
Bugfix60f5bc62022-01-21 11:09:56 +01001130 if(!sizeof(types))
1131 {
1132 types = "nichts";
1133 }
1134 ReceiveNotify(
1135 "Klingelton bei "
1136 + types
Zesstra1cc6cf32022-02-09 11:49:31 +01001137 + (beep_interval ? ", alle " + beep_interval + " Sekunden." : ", immer.")
1138 + (QueryProp(P_ALERT) & AL_NO_SOUND ? " Allerdings sind Toene insgesamt "
1139 "bei Dir abgeschaltet. (\'hilfe ton\')" : ""),
Bugfix60f5bc62022-01-21 11:09:56 +01001140 query_verb());
MG Mud User88f12472016-06-24 23:31:02 +02001141 return 1;
1142}
1143
1144static int _msg_prepend(string str) {
MG Mud User88f12472016-06-24 23:31:02 +02001145 notify_fail("Syntax: senderwiederholung ein/aus\n");
1146 if (stringp(str)) {
1147 if (str=="aus")
1148 SetProp(P_MESSAGE_PREPEND,1);
1149 else if (str=="ein")
1150 SetProp(P_MESSAGE_PREPEND,0);
1151 else return 0;
1152 }
1153
Bugfixb1d9b4d2021-09-14 20:07:04 +02001154 ReceiveNotify("Senderwiederholung bei Mitteilungen: "+
Zesstra04f613c2019-11-27 23:32:54 +01001155 (({int})QueryProp(P_MESSAGE_PREPEND) ? "aus" : "ein")+".",
MG Mud User88f12472016-06-24 23:31:02 +02001156 query_verb());
1157
1158 return 1;
1159}
1160
1161static int _communicate(mixed str, int silent)
1162{
1163 string verb;
1164 string myname;
1165 string msg;
1166
1167 if (!str || extern_call()) str=_unparsed_args()||"";
1168 /* str=_unparsed_args()||""; */
1169 verb = query_verb();
1170 if(stringp(verb) && verb[0] == '\'') str = verb[1..] + " " + str;
1171 if (str==""||str==" "||!str)
1172 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001173 ReceiveNotify("Was willst Du sagen?",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001174 return 1;
1175 }
1176 msg=permutate(str);
1177
1178 myname=(((QueryProp(P_INVIS)||!IS_LEARNER(ME))||
1179 !(QueryProp(P_CAN_FLAGS)&CAN_PRESAY)?
1180 "":QueryProp(P_PRESAY))+name())||"";
1181
1182 // an alles im Raum senden. (MT_LISTEN, weil dies gesprochene Kommunikation
1183 // ist, keine MT_COMM)
Zesstrabd1236a2022-02-09 22:35:59 +01001184 send_room(environment(), msg, MT_LISTEN|MSG_ALERT, MA_SAY,
MG Mud User88f12472016-06-24 23:31:02 +02001185 capitalize(myname)+" sagt: ", ({this_object()}) );
1186
1187 if(!silent)
1188 {
1189 ReceiveMsg(msg, MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE,
1190 MA_SAY, "Du sagst: ", ME);
1191 }
1192 return 1;
1193}
1194
1195static int _shout_to_all(mixed str)
1196{
1197 string pre, myname, realname, wizards_msg, players_msg;
1198 string wizard_prefix, player_prefix;
1199 int chars;
1200
1201 if (!(str=_unparsed_args()))
1202 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001203 ReceiveNotify("Was willst Du rufen?",MA_SHOUT);
MG Mud User88f12472016-06-24 23:31:02 +02001204 return 1;
1205 }
1206 chars=sizeof(str)/2;
1207 if (chars<4) chars=4;
1208 pre = (!IS_LEARNER(ME) ||
1209 QueryProp(P_INVIS) ||
1210 !(QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ? "" : QueryProp(P_PRESAY);
1211 realname = capitalize((pre + capitalize(getuid()))||"");
1212 myname = capitalize(pre + name()||"");
1213 if (QueryProp(P_INVIS))
1214 realname = "("+realname+")";
1215
1216 wizards_msg = permutate(str);
1217 wizard_prefix = myname+" ruft: ";
1218
1219 if(QueryProp(P_FROG)) {
1220 players_msg = "Quaaak, quaaaaak, quuuuaaaaaaaaaaaaaaaaaaaak !!";
1221 player_prefix = myname+" quakt: ";
1222 }
1223 else {
1224 players_msg = wizards_msg;
1225 player_prefix = wizard_prefix;
1226 }
1227
1228 if(!IS_LEARNER(this_player()))
1229 {
1230 if(QueryProp(P_GHOST)) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001231 ReceiveNotify("So ganz ohne Koerper bekommst Du keinen Ton heraus.",
MG Mud User88f12472016-06-24 23:31:02 +02001232 MA_SHOUT);
1233 return 1;
1234 }
1235 if (QueryProp(P_SP) <(chars+20))
1236 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001237 ReceiveNotify("Du musst erst wieder magische Kraefte sammeln.",
MG Mud User88f12472016-06-24 23:31:02 +02001238 MA_SHOUT);
Bugfixb1d9b4d2021-09-14 20:07:04 +02001239 ReceiveNotify("Tip: Benutz doch mal die Ebenen (Hilfe dazu mit 'hilfe "
MG Mud User88f12472016-06-24 23:31:02 +02001240 "Ebenen').", MA_SHOUT);
1241 return 1;
1242 }
1243 SetProp(P_SP, QueryProp(P_SP) - chars - 20);
1244 }
1245
1246 ReceiveMsg(wizards_msg, MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE,
Zesstrabd1236a2022-02-09 22:35:59 +01001247 MA_SHOUT, "Du rufst: ", ME);
MG Mud User88f12472016-06-24 23:31:02 +02001248
1249 foreach ( object ob : users()-({this_object()}) )
1250 if ( IS_LEARNER(ob) )
Zesstrabd1236a2022-02-09 22:35:59 +01001251 ob->ReceiveMsg(wizards_msg, MT_LISTEN|MT_FAR|MSG_ALERT, MA_SHOUT,
1252 wizard_prefix, this_object());
MG Mud User88f12472016-06-24 23:31:02 +02001253 else
Zesstrabd1236a2022-02-09 22:35:59 +01001254 ob->ReceiveMsg(players_msg, MT_LISTEN|MT_FAR|MSG_ALERT, MA_SHOUT,
1255 player_prefix, this_object());
MG Mud User88f12472016-06-24 23:31:02 +02001256
1257 return 1;
1258}
1259
1260varargs int _tell(string who, mixed msg)
1261{
1262 object ob;
1263 string away,myname,ret;
Arathornb3051452021-05-13 21:13:03 +02001264 mixed it;
MG Mud User88f12472016-06-24 23:31:02 +02001265 string *xname;
1266 int i,visflag;
1267
1268 if (extern_call() && this_interactive()!=ME) return 1;
1269 if (!who || !msg) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001270 ReceiveNotify("Was willst Du mitteilen?",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001271 return 1;
1272 }
1273
1274 if(who == ERWIDER_PARAM)
1275 {
1276 if (!last_comm_partner)
1277 {
1278 _notify_fail("Du hast aber noch keine Mitteilungen erhalten, auf die "
1279 "Du was erwidern\nkoenntest.\n");
1280 return 0;
1281 }
1282 who=last_comm_partner;
1283 }
1284
1285 // teile .x mit teilt bisherigen Gespraechspartnern etwas mit.
1286 if (who == ".")
1287 who = ".1";
1288
1289 if ( sscanf(who, ".%d", i) == 1 ) {
1290 if(i > 0 && i <= sizeof(commreceivers))
1291 who = commreceivers[i-1];
1292 else {
1293 _notify_fail("So vielen Leuten hast Du noch nichts mitgeteilt!\n");
1294 return 0;
1295 }
1296 }
1297
1298 xname = explode(who, "@");
1299
Zesstrabd1236a2022-02-09 22:35:59 +01001300 if (sizeof(xname) == 2)
MG Mud User88f12472016-06-24 23:31:02 +02001301 {
1302 if ( QueryProp(P_QP) )
1303 {
Zesstra04f613c2019-11-27 23:32:54 +01001304 if (ret=({string})INETD->_send_udp(xname[1],
MG Mud User88f12472016-06-24 23:31:02 +02001305 ([ REQUEST: "tell",
1306 RECIPIENT: xname[0],
1307 SENDER: getuid(ME),
1308 DATA: msg ]), 1))
1309 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001310 ReceiveNotify(ret, MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001311 }
1312 else
1313 {
1314 write("Nachricht abgeschickt.\n");
1315 add_to_tell_history(who, 1, 0, msg,
Zesstraa31cd5c2016-12-17 20:11:07 +01001316 "Du teilst " + capitalize(who) + " mit: ", MSGFLAG_RTELL, 1);
MG Mud User88f12472016-06-24 23:31:02 +02001317 }
1318 }
1319 else
1320 write("Du hast nicht genug Abenteuerpunkte, um Spielern in anderen \n"
1321 "Muds etwas mitteilen zu koennen.\n");
1322 return 1;
1323 }
1324
1325 if (!ob=find_player(it = lower_case(who)))
1326 {
1327 it = match_living(it, 0);
1328 if (!stringp(it))
1329 switch(it) {
1330 case -1:
Bugfixb1d9b4d2021-09-14 20:07:04 +02001331 ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001332 return 1;
1333 case -2:
Bugfixb1d9b4d2021-09-14 20:07:04 +02001334 ReceiveNotify("Kein solcher Spieler!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001335 return 1;
1336 }
1337 ob = find_player(it) || find_living(it);
1338 if(!ob) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001339 ReceiveNotify("Kein solcher Spieler!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001340 return 1;
1341 }
1342 }
1343
1344 if(QueryProp(P_INVIS)){
1345 if(!IS_LEARNER(ob))
1346 myname = name();
1347 else
1348 myname="("+
1349 ((QueryProp(P_CAN_FLAGS) & CAN_PRESAY)?QueryProp(P_PRESAY):"")+
1350 capitalize(getuid()) + ")";
1351 }
1352 else
1353 myname=((IS_LEARNER(ME) && (QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ?
Bugfix45f88ce2017-03-06 14:41:56 +01001354 QueryProp(P_PRESAY):"") + capitalize(getuid(ME));
MG Mud User88f12472016-06-24 23:31:02 +02001355 if (myname && sizeof(myname)) myname=capitalize(myname);
1356 // erstmal an Empfaenger senden
Zesstrabd1236a2022-02-09 22:35:59 +01001357 _send(ob, permutate(msg), MT_COMM|MT_FAR|MSG_ALERT, MA_TELL,
MG Mud User88f12472016-06-24 23:31:02 +02001358 myname + " teilt Dir mit: ");
1359
1360 // dann evtl. noch an Absender ausgeben...
1361 if (visflag = !ob->QueryProp(P_INVIS) || IS_LEARNER(this_player()))
1362 _recv(ob, msg, MSGFLAG_TELL, "Du teilst " + capitalize(it) + " mit: ");
1363 // oder irgendwas anderes an den Absender ausgeben...
1364 if (!visflag && interactive(ob))
Bugfixb1d9b4d2021-09-14 20:07:04 +02001365 ReceiveNotify("Kein solcher Spieler!",MA_TELL);
Zesstra04f613c2019-11-27 23:32:54 +01001366 else if (away = ({string})ob->QueryProp(P_AWAY))
MG Mud User88f12472016-06-24 23:31:02 +02001367 ReceiveMsg( break_string( away, 78, capitalize(it)
1368 + " ist gerade nicht da: ", BS_INDENT_ONCE ),
1369 MT_NOTIFICATION|MSG_DONT_WRAP|MSG_DONT_IGNORE,
1370 MA_TELL, 0, this_object());
1371 else if (interactive(ob) && (i=query_idle(ob))>=600)
1372 { //ab 10 Mins
1373 if (i<3600)
1374 away=time2string("%m %M",i);
1375 else
1376 away=time2string("%h %H und %m %M",i);
1377
Bugfixb1d9b4d2021-09-14 20:07:04 +02001378 ReceiveNotify(sprintf("%s ist seit %s voellig untaetig.",
MG Mud User88f12472016-06-24 23:31:02 +02001379 capitalize(it),away),
1380 MA_TELL);
1381 }
1382
1383 return 1;
1384}
1385
1386static int _teile(string str)
1387{
1388 string who, message;
1389 if (!(str=_unparsed_args())) return 0;
1390 if (sscanf(str, "%s mit %s", who, message) == 2)
1391 return _tell(who, message,1);
1392 return 0;
1393}
1394static int _teile_mit_alias(string str)
1395{
1396 str = _unparsed_args(), TRIM_LEFT;
1397 if (!str) return 0;
1398 str = trim(str, TRIM_LEFT);
1399 // Ziel muss min. 2 Buchstaben haben (.<nr>)
1400 if (sizeof(str) < 4) return 0;
1401 int pos = strstr(str, " ");
1402 if (pos >= 2)
1403 return _tell(str[..pos-1], str[pos+1..]);
1404 return 0;
1405}
1406
1407static int _erzaehle(string str)
1408{
1409 string who, message;
1410
1411 if (!(str=_unparsed_args())) return 0;
1412 if (sscanf(str, "%s %s", who, message) == 2)
1413 return _tell(who, message,1);
1414 return 0;
1415}
1416
1417static int _whisper(string str)
1418{
1419 object ob;
1420 string who;
1421 string msg;
1422 string myname;
1423
1424 if (!(str=_unparsed_args()) ||
1425 (sscanf(str, "%s zu %s", who, msg) != 2 &&
1426 sscanf(str, "%s %s", who, msg) !=2 )) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001427 ReceiveNotify("Was willst Du wem zufluestern?",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001428 return 1;
1429 }
Zesstra6e88b6a2019-11-08 00:25:39 +01001430 who = lower_case(who);
MG Mud User88f12472016-06-24 23:31:02 +02001431 if (!(ob = present(who, environment(this_player()))) || !living(ob)) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001432 ReceiveNotify(capitalize(who)+" ist nicht in diesem Raum.",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001433 return 1;
1434 }
1435
1436 myname = capitalize((((IS_LEARNER(ME) &&
1437 !QueryProp(P_INVIS) &&
1438 (QueryProp(P_CAN_FLAGS) & CAN_PRESAY))?
1439 QueryProp(P_PRESAY) : "") + name()) || "");
1440
1441 _send(ob, permutate(msg), MT_LISTEN|MSG_DONT_STORE,
Bugfixdbdbed52022-01-21 11:14:35 +01001442 MA_SAY, myname + " fluestert Dir zu: ");
MG Mud User88f12472016-06-24 23:31:02 +02001443 send_room(environment(),
1444 myname + " fluestert " + ob->name(WEM, 1) + " etwas zu.",
1445 MT_LISTEN|MSG_DONT_STORE, MA_SAY, 0, ({this_object(),ob}));
1446
1447 _recv(ob, msg, MSGFLAG_WHISPER, "Du fluesterst " + ob->name(WEM) + " zu: ");
1448
1449
1450 return 1;
1451}
1452
1453static int _remote_whisper(string str)
1454{
1455 /* Wie 'teile mit', nur mit MSGFLAG_WHISPER. Dadurch wird der Inhalt der
1456 Nachricht nicht in der tell_history verewigt. */
1457
1458 object ob;
1459 string who, it;
1460 string msg;
1461 string myname;
1462
1463 if (!(str=_unparsed_args()) ||
1464 (sscanf(str, "%s zu %s", who, msg) != 2 &&
1465 sscanf(str, "%s %s", who, msg) !=2 )) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001466 ReceiveNotify("Was willst Du wem aus der Ferne zufluestern?",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001467 return 1;
1468 }
1469
1470 if (!ob=find_player(it = lower_case(who)))
1471 {
1472 it = match_living(it, 0);
1473 if (!stringp(it))
1474 switch(it){
1475 case -1:
Bugfixb1d9b4d2021-09-14 20:07:04 +02001476 ReceiveNotify("Das war nicht eindeutig!",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001477 return 1;
1478 case -2:
Bugfixb1d9b4d2021-09-14 20:07:04 +02001479 ReceiveNotify("Kein solcher Spieler!",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001480 return 1;
1481 }
1482 ob = find_player(it);
1483 if(!ob) ob = find_living(it);
1484 if(!ob){
Bugfixb1d9b4d2021-09-14 20:07:04 +02001485 ReceiveNotify("Kein solcher Spieler!",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001486 return 1;
1487 }
1488 }
1489 if (environment(ob) == environment()) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001490 ReceiveNotify("Wenn jemand neben Dir steht, nimm fluester.",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001491 return 1;
1492 }
1493
1494 myname = capitalize((((IS_LEARNER(ME) &&
1495 !QueryProp(P_INVIS) &&
1496 (QueryProp(P_CAN_FLAGS) & CAN_PRESAY))?
1497 QueryProp(P_PRESAY) : "") + name()) || "");
1498
1499 // An Empfaenger senden.
Zesstrabd1236a2022-02-09 22:35:59 +01001500 _send(ob, permutate(msg), MT_COMM|MT_FAR|MSG_DONT_STORE,
1501 MA_EMOTE, myname + " fluestert Dir aus der Ferne zu: ");
MG Mud User88f12472016-06-24 23:31:02 +02001502
1503 // wenn Empfaenger invis und wir kein Magier , ggf. fakefehler ausgeben.
1504 if (ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player())) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001505 ReceiveNotify("Kein solcher Spieler!",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001506 return 1;
1507 }
1508 // sonst eigene Meldung via _recv() ausgeben.
1509 else
1510 _recv(ob, msg, MSGFLAG_WHISPER | MSGFLAG_REMOTE,
1511 "Du fluesterst " + ob->name(WEM) + " aus der Ferne zu: ");
1512
1513 return 1;
1514}
1515
1516static int _converse(string arg)
1517{
Bugfixb1d9b4d2021-09-14 20:07:04 +02001518 ReceiveNotify("Mit '**' wird das Gespraech beendet.",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001519 if (stringp(arg) && strstr(arg, "-s") == 0)
1520 input_to("_converse_more", INPUT_PROMPT, "]", 1);
1521 else
1522 input_to("_converse_more", INPUT_PROMPT, "]", 0);
1523 return 1;
1524}
1525
1526static int _converse_more(mixed str, int silent)
1527{
1528 if (str == "**") {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001529 ReceiveNotify("Ok.",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001530 return 0;
1531 }
1532
1533 if(str != "")
1534 _communicate(str, silent);
1535
1536 input_to("_converse_more", INPUT_PROMPT, "]", silent);
1537 return 1;
1538}
1539
1540private int is_learner(object o) { return IS_LEARNER(o); }
1541
1542static int _shout_to_wizards(mixed str)
1543{
MG Mud User88f12472016-06-24 23:31:02 +02001544 string myname;
MG Mud User88f12472016-06-24 23:31:02 +02001545
1546 str = _unparsed_args();
1547 if (!str||!sizeof(str)) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001548 ReceiveNotify("Was willst Du den Magiern zurufen?",MA_SHOUT);
MG Mud User88f12472016-06-24 23:31:02 +02001549 return 1;
1550 }
1551 // Kontrollzeichen rausfiltern.
1552 str = regreplace(str,"[[:cntrl:]]","",RE_PCRE|RE_GLOBAL);
1553 myname = capitalize(getuid(this_object()));
1554 if (!IS_LEARNER(this_object()))
1555 _recv(0, str, MSGFLAG_MECHO, "Du teilst allen Magiern mit: ");
1556
1557 // mrufe ist nicht ignorierbar, da es nur fuer schwere Probleme gedacht ist.
1558 filter(users(), #'is_learner)->ReceiveMsg(str,
Zesstrabd1236a2022-02-09 22:35:59 +01001559 MT_COMM|MT_FAR|MSG_DONT_IGNORE|MSG_DONT_STORE|MSG_ALERT,
MG Mud User88f12472016-06-24 23:31:02 +02001560 MA_SHOUT, myname+" an alle Magier: ", this_object());
1561
1562 return 1;
1563}
1564
1565static int _echo(string str) {
1566 if (!IS_SEER(ME) || (!IS_LEARNER(ME)
1567 && !(QueryProp(P_CAN_FLAGS) & CAN_ECHO)))
1568 return 0;
1569
1570 if (!(str=_unparsed_args())) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001571 ReceiveNotify("Was moechtest Du 'echoen'?", 0);
MG Mud User88f12472016-06-24 23:31:02 +02001572 return 1;
1573 }
1574
1575 if (!IS_LEARNER(this_interactive()))
1576 {
1577 if (QueryProp(P_GHOST))
1578 {
1579 _notify_fail("Ohne Koerper fehlt Dir dazu die noetige magische Kraft.\n");
1580 return 0;
1581 }
1582 if (QueryProp(P_SP)<ECHO_COST)
1583 {
1584 _notify_fail("Du musst erst wieder magische Kraefte sammeln.\n");
1585 return 0;
1586 }
1587 SetProp(P_SP,QueryProp(P_SP)-ECHO_COST);
1588 str=">\b"+str;
1589 log_file("ARCH/ECHO_SEHER", sprintf("%s %s: %s\n", dtime(time()), getuid(),
1590 str));
1591 }
1592 // An den Raum senden. Typ ist MT_COMM, aber das Echo soll weder in der
1593 // Kommhistory noch im Kobold landen.
1594 send_room(environment(ME), str, MT_COMM|MSG_DONT_STORE|MSG_DONT_BUFFER,
1595 MA_UNKNOWN, 0, 0);
1596 return 1;
1597}
1598
1599// Dient als Verteidigung gegen Leute, die eher unbedacht reinschreiben, nicht
1600// gegen Leute, die da absichtlich reinschreiben. Die werden geteert
1601// und gefedert.
1602static string *_set_ignore(mixed arg)
1603{
1604 raise_error("Direktes Setzen von P_IGNORE ist nicht erlaubt. "
1605 "Benutze AddIgnore/RemoveIgnore()!\n");
1606}
1607// Kompatibiltaet zum alten Ignore: Array von Indices liefern. Aendert aber
1608// nix dran, dass alle TestIgnore() & Co benutzen sollen.
1609static string *_query_ignore() {
1610 mixed ign=Query(P_IGNORE, F_VALUE);
1611 if (mappingp(ign))
1612 return m_indices(ign);
1613 return ({});
1614}
1615
1616public int AddIgnore(string ign) {
1617 // Einige strings sind nicht erlaubt, z.B. konsekutive .
1618 if (!sizeof(ign)
1619 || regmatch(ign,"[.]{2,}",RE_PCRE)
1620 || regmatch(ign," ",RE_PCRE)
1621 || sizeof(explode(ign,"."))>3)
1622 return 0;
1623
1624 mapping ignores=Query(P_IGNORE, F_VALUE);
1625 ignores[ign]=time();
1626 // kein Set() noetig.
1627 return 1;
1628}
1629
1630public int RemoveIgnore(string ign)
1631{
1632 mapping ignores=Query(P_IGNORE,F_VALUE);
1633 m_delete(ignores,ign);
1634 // Kein Set() noetig
1635 return 1;
1636}
1637
1638static int _query_intermud()
1639{
1640 mixed tmp;
1641 return member(pointerp(tmp=Query(P_CHANNELS))?tmp:({}), "Intermud") > -1;
1642}
1643
1644
1645int erwidere(string str)
1646{
1647 str=_unparsed_args();
1648 if (!str) return 0;
1649 return _tell(ERWIDER_PARAM, str ,1);
1650}
1651
1652static int tmhist(string str)
1653{
1654
1655 if (str == "aus") {
1656 tell_history_enabled = TELLHIST_DISABLED;
1657 write("Ok, es wird nichts mehr gespeichert.\n");
1658 if (sizeof(tell_history)) {
Zesstra996bafe2022-02-14 22:42:39 +01001659 clear_tell_history(1);
MG Mud User88f12472016-06-24 23:31:02 +02001660 write("Deine Mitteilungsgeschichte wurde geloescht.\n");
1661 }
1662 return 1;
1663 }
Zesstra996bafe2022-02-14 22:42:39 +01001664 if (str == "loeschen")
1665 {
1666 if (sizeof(tell_history)) {
1667 clear_tell_history(1);
1668 write("Deine Mitteilungsgeschichte wurde geloescht.\n");
1669 }
1670 else
1671 write("Deine Mitteilungsgeschichte war schon leer.\n");
1672 return 1;
1673 }
MG Mud User88f12472016-06-24 23:31:02 +02001674
1675 if (str == "namen") {
1676 int flag;
1677 tell_history_enabled = TELLHIST_NO_MESSAGE;
1678 write("Ok, die Namen zukuenftiger Gespraechspartner werden gespeichert.\n");
1679 foreach (string uid, struct chat_s chat: tell_history)
1680 if (pointerp(chat->msgbuf)) {
1681 chat->msgbuf = 0;
1682 chat->ptr = 0;
1683 flag = 1;
1684 }
1685 if (flag)
1686 write("Der Inhalt Deiner Mitteilungen wurde geloescht.\n");
1687 return 1;
1688 }
1689
1690 if (str == "ein" || str == "an") {
1691 tell_history_enabled = TELLHIST_ENABLED;
1692 write("Ok, zukuenftige Mitteilungen werden gespeichert.\n");
1693 return 1;
1694 }
1695
MG Mud User88f12472016-06-24 23:31:02 +02001696 if (str == "langlebig") {
1697 tell_history_enabled = TELLHIST_LONGLIFE;
1698 write("Ok, zukuenftige Mitteilungen werden jeweils bis zum naechsten "
1699 "Ende/Crash/\nReboot gespeichert.\n");
1700 return 1;
1701 }
MG Mud User88f12472016-06-24 23:31:02 +02001702
1703 if (str == "status") {
1704 switch (tell_history_enabled) {
1705 case TELLHIST_DISABLED:
1706 write("Die Namen Deiner Gespraechspartner werden nicht gespeichert.\n");
1707 break;
1708 case TELLHIST_NO_MESSAGE:
1709 write("Die Namen Deiner Gespraechspartner werden gespeichert.\n");
1710 break;
1711 case TELLHIST_ENABLED:
1712 write("Deine Mitteilungen werden gespeichert.\n");
1713 break;
MG Mud User88f12472016-06-24 23:31:02 +02001714 case TELLHIST_LONGLIFE:
1715 write("Deine Mitteilungen werden jeweils bis zum naechsten Ende/"
1716 "Crash/Reboot\ngespeichert.\n");
1717 break;
MG Mud User88f12472016-06-24 23:31:02 +02001718 }
1719 return 1;
1720 }
1721
1722 if (tell_history_enabled == TELLHIST_DISABLED) {
1723 _notify_fail("Deine Gespraechspartner werden nicht gespeichert.\n");
1724 return 0;
1725 }
1726
1727 if (!sizeof(tell_history)) {
1728 _notify_fail("Du hast noch keinem etwas mitgeteilt "
1729 "und noch keine Mitteilungen erhalten.\n");
1730 return 0;
1731 }
1732
1733 if (str && sizeof(str)) {
1734
1735 if (tell_history_enabled < TELLHIST_ENABLED) {
1736 _notify_fail("Der Inhalt Deiner Mitteilungen wird nicht gespeichert.\n");
1737 return 0;
1738 }
1739
1740 string uid;
1741 if (member(tell_history, str)) {
1742 // Name gewuenscht, da der String in der History vorkommt.
1743 uid = str;
1744 }
1745 else {
1746 // evtl. ne Zahl angegeben.
1747 int i;
1748 string *partners = sorted_commpartners(0);
1749 if ((i = to_int(str) - 1) >= 0 && i < sizeof(partners))
1750 uid = partners[i];
1751 else {
1752 notify_fail("Mit so vielen Leuten hast Du nicht gesprochen!\n");
1753 return 0;
1754 }
1755 }
1756
1757 mixed *data = tell_history[uid]->msgbuf;
1758 if (!data) {
1759 _notify_fail(
1760 "Der Inhalt dieser Mitteilung ist nicht (mehr) gespeichert.\n");
1761 return 0;
1762 }
1763
1764 int ptr = tell_history[uid]->ptr;
1765
1766 More(sprintf("%@s", map(data[ptr..MAX_SAVED_MESSAGES-1] +
1767 data[0..ptr-1],
1768 function string (struct stored_msg_s msg) {
1769 if (!structp(msg)) return "";
Zesstra3a261e52022-02-10 14:00:31 +01001770 return break_string(terminal_colour(msg->msg, colourmap)
1771 + " <"
MG Mud User88f12472016-06-24 23:31:02 +02001772 + strftime("%H:%M:%S",msg->timestamp) + ">", 78,
1773 msg->prefix || "", msg->prefix ? BS_LEAVE_MY_LFS : 0);
1774 } ) ) );
1775 return 1;
1776 }
1777
1778 string history = "Folgende Gespraeche hast Du bereits gefuehrt:\n";
1779 int i;
1780 foreach (string uid : sorted_commpartners(0) ) {
1781 int j;
1782 struct chat_s chat = tell_history[uid];
1783 history += sprintf("%2d.%-4s %s %-11s %d gesendet/%d empfangen\n", ++i,
1784 ((j=member(commreceivers,uid))>-1 ? sprintf("/%2d.",j+1) : ""),
1785 strftime("%a, %e.%m.%y",chat->time_last_msg),
1786 capitalize(chat->uid), chat->sentcount, chat->recvcount);
1787 }
1788
1789 More(history);
1790
1791 return 1;
1792}
1793
1794static mixed _query_localcmds()
1795{
1796 return ({
1797 ({"kobold", "cmd_kobold",0,0}),
1798 ({"sag","_communicate",0,0}),
1799 ({"sage","_communicate",0,0}),
1800 ({"'","_communicate",1,0}),
1801 ({"mruf","_shout_to_wizards",0,0}),
1802 ({"mrufe","_shout_to_wizards",0,0}),
1803 ({"ruf","_shout_to_all",0,0}),
1804 ({"rufe","_shout_to_all",0,0}),
1805 ({"erzaehl","_erzaehle",0,0}),
1806 ({"erzaehle","_erzaehle",0,0}),
1807 ({"teil","_teile",0,0}),
1808 ({"teile","_teile",0,0}),
1809 ({"tm","_teile_mit_alias",0,0}),
1810 ({"fluester","_whisper",0,0}),
1811 ({"fluestere","_whisper",0,0}),
1812 ({"rfluester","_remote_whisper",0,0}),
1813 ({"rfluestere","_remote_whisper",0,0}),
1814 ({"gespraech","_converse",0,0}),
1815 ({"echo","_echo",0,0}),
1816 ({"ignorier","ignoriere",0,0}),
1817 ({"ignoriere","ignoriere",0,0}),
1818 ({"tmhist","tmhist",0,0}),
1819 ({"erwider","erwidere",0,0}),
1820 ({"erwidere","erwidere",0,0}),
1821 ({"klingelton","_msg_beep",0,0}),
1822 ({"senderwiederholung","_msg_prepend",0,0}),
1823 ({"report","set_report",0,0}),
1824 })+channel::_query_localcmds();
1825}
1826
1827private string *sorted_commpartners(int reversed) {
1828 return sort_array(m_indices(tell_history),
1829 function int (string uid1, string uid2) {
1830 if (reversed)
1831 return tell_history[uid1]->time_last_msg >
1832 tell_history[uid2]->time_last_msg;
1833 else
1834 return tell_history[uid1]->time_last_msg <=
1835 tell_history[uid2]->time_last_msg;
1836 } );
1837}
1838
Zesstra0712bac2020-06-12 09:41:24 +02001839// Setzt den Prompt eines Interactives. Gerufen bei Objekterstellung,
1840// Reconnect und bei Magiern, wenn diese ihren Prompt oder ihr aktuelles
1841// Verzeichnis aendern.
MG Mud User88f12472016-06-24 23:31:02 +02001842static void modify_prompt() {
1843 string text = Query(P_PROMPT, F_VALUE);
1844
1845 if ( !stringp(text) || !sizeof(text) )
1846 text = "> ";
1847 else {
1848 string path = Query(P_CURRENTDIR, F_VALUE);
1849 if (stringp(path) && sizeof(path))
1850 text = regreplace(text,"\\w",path,0); // Pfad einsetzen
1851 }
1852 configure_interactive(this_object(), IC_PROMPT, text);
1853}
1854
1855// Prueft auf Ingoriereeintraege.
1856// Rueckgabe: 0 (nicht ignoriert) oder MSG_IGNORED
MG Mud User88f12472016-06-24 23:31:02 +02001857public int TestIgnore(string|string* srcnames)
MG Mud User88f12472016-06-24 23:31:02 +02001858{
1859 mapping ign = Query(P_IGNORE, F_VALUE);
1860 if (stringp(srcnames))
1861 srcnames = ({srcnames});
1862
1863 foreach(string srcname: srcnames)
1864 {
1865 // einfachster Fall, exakter Match
1866 if (member(ign, srcname))
1867 return MSG_IGNORED;
1868 // ansonsten muss aufgetrennt werden.
1869 if (strstr(srcname,".") > -1)
1870 {
1871 string *srcparts=explode(srcname,".");
1872 switch(sizeof(srcparts))
1873 {
1874 // case 0 und 1 kann nicht passieren.
1875 case 3:
1876 // zu pruefen: [sender].aktion.qualifizierer.
1877 // Der Fall, dass der Spieler dies _genau_ _so_ ignoriert hat, wird
1878 // oben schon geprueft. im Spieler geprueft werden muss noch:
1879 // spieler, .aktion, spieler.aktion und .aktion.qualifizierer
1880 if ( (sizeof(srcparts[0]) && member(ign,srcparts[0])) // spieler
1881 || member(ign, "."+srcparts[1]) // .aktion
1882 || member(ign, srcparts[0]+"."+srcparts[1]) // [spieler].aktion
1883 || member(ign, "."+srcparts[1]+"."+srcparts[2]) // .akt.qual
1884 )
1885 {
1886 return MSG_IGNORED;
1887 }
1888 break;
1889 case 2:
1890 // zu pruefen: spieler.aktion
1891 // Der Fall, dass der Spieler das _genau_ _so_ eingegeben hat, ist
1892 // oben schon geprueft. Im Spieler zu pruefen ist noch:
1893 // spieler und .aktion
1894 if ((sizeof(srcparts[0]) && member(ign,srcparts[0]))
1895 || member(ign, "."+srcparts[1]))
1896 {
1897 return MSG_IGNORED;
1898 }
1899 break;
1900 default: // mehr als 3 Teile...
1901 raise_error(sprintf("TestIgnoreExt(): too many qualifiers, only 1 "
1902 "is supported. Got: %s\n",srcname));
MG Mud User88f12472016-06-24 23:31:02 +02001903 }
1904 }
1905 }
1906 // Default: nicht ignorieren.
1907 return 0;
1908}
1909
1910#ifdef __LPC_UNIONS__
1911public int TestIgnoreExt(string|string* srcnames)
1912#else
1913public int TestIgnoreExt(mixed srcnames)
1914#endif
1915{
1916 return TestIgnore(srcnames);
1917}
1918
1919// Prueft fuer ReceiveMsg() auf Ingoriereeintraege. Ignoriert aber nicht alle
1920// Typen.
1921// Rueckgabe: 0 oder MSG_IGNORED | MSG_VERB_IGN | MSG_MUD_IGN
1922private int check_ignores(string msg, int msg_type, string msg_action,
1923 string msg_prefix, object origin)
1924{
1925 // Einige Dinge lassen sich nicht ignorieren.
1926 if (msg_type & (MT_NEWS|MT_NOTIFICATION))
1927 return 0;
1928 // alles andere geht zur zeit erstmal, wenn origin bekannt UND NICHT das
1929 // eigene Objekt ist. Waer ggf. sonst doof. Ausserdem muss es natuerlich
1930 // eine ignorierbare msg_action geben.
1931 else if (stringp(msg_action) && origin && origin != ME)
1932 {
1933 string srcname =
1934 (query_once_interactive(origin) ? origin->query_real_name()
1935 : origin->name(WER) || "");
1936 mapping ign = Query(P_IGNORE, F_VALUE);
1937
1938 if (member(ign, srcname))
1939 return MSG_IGNORED;
1940 // vielleicht wird irgendwas a la name.aktion ignoriert?
1941 // dies ignoriert auch spieler.ebenen.<ebene> (s. msg_action bei
1942 // Ebenenmeldungen)
1943 if (member(ign, srcname+"."+msg_action))
1944 return MSG_VERB_IGN;
1945 // Oder die Aktion komplett? Dies ignoriert auch .ebenen.<ebene>, obwohl
1946 // das reichlich sinnfrei ist.
1947 if (member(ign, "."+msg_action))
1948 return MSG_VERB_IGN;
1949 // Spieler auf Ebenen ignoriert?
1950 // msg_action ist hier nach diesem Muster: MA_CHANNEL.<ebene>
1951 if (strstr(msg_action, MA_CHANNEL) == 0)
1952 {
1953 // spieler.ebenen? (spieler.ebenen.<ebene> oben schon geprueft)
1954 if (member(ign, srcname + "."MA_CHANNEL))
1955 return MSG_IGNORED;
1956 // spieler.ebenen.ebenenname ist oben schon abgedeckt.
1957 // .ebenen halte ich fuer sinnfrei, nicht geprueft.
1958 }
1959 // Spieler aus anderem mud? *seufz*
1960 if (strstr(srcname,"@") > -1)
1961 {
1962 string *srcparts = explode(srcname,"@");
1963 if (sizeof(srcparts)==2)
1964 {
1965 // spieler@?
1966 if (member(ign, srcparts[0]+"@"))
1967 return MSG_IGNORED;
1968 // oder Mud per @mud?
1969 if (member(ign, "@" + srcparts[1]))
1970 return MSG_MUD_IGN;
1971 // BTW: spieler@mud wurde schon ganz oben erfasst.
1972 }
1973 }
1974 }
1975 // Default: nicht ignorieren.
1976 return 0;
1977}
1978
1979// Wird die nachricht wahrgenommen? Die Pruefung erfolgt aufgrund von
1980// msg_type. Zur wird MT_LOOK und MT_LISTEN beruecksichtigt (Pruefung auf
Bugfixe0fc68f2022-01-07 15:30:54 +01001981// BLindheit/Taubheit). In Zukunft koennten aber weitere Typen und weitere
1982// Kriterien wichtig werden und weitere Argumente uebergeben werden. (Dies
1983// bitte beachten, falls diese Funktion protected/public werden sollte.)
MG Mud User88f12472016-06-24 23:31:02 +02001984// Wichtig: enthaelt msg_action weder MT_LOOK noch MT_LISTEN, wird die
1985// Nachricht wahrgenommen, da davon ausgegangen wird, dass sie mit den beiden
1986// Sinn gar nix zu tun hat.
1987// Rueckgabe: 0 oder MSG_SENSE_BLOCK
Bugfixe0fc68f2022-01-07 15:30:54 +01001988private int check_senses(int msg_type)
MG Mud User88f12472016-06-24 23:31:02 +02001989{
1990 int senses = msg_type & (MT_LOOK|MT_LISTEN);
1991 // Wenn von vorherein kein Sinn angesprochen, dann ist es eine nachricht,
1992 // die von keinem der beiden wahrgenommen wird und sollte demnach nicht
1993 // unterdrueckt werden.
1994 if (!senses)
1995 return 0;
Bugfix427a5812022-01-07 15:41:24 +01001996
1997 int orig_senses = senses;
1998
MG Mud User88f12472016-06-24 23:31:02 +02001999 if ((senses & MT_LOOK) && CannotSee(1))
2000 senses &= ~MT_LOOK; // Sinn loeschen
2001
2002 if ((senses & MT_LISTEN) && QueryProp(P_DEAF))
2003 senses &= ~MT_LISTEN;
2004
Bugfix427a5812022-01-07 15:41:24 +01002005 // Wenn kein Sinn mehr ueber ist oder all_types gesetzt ist und nicht mehr
2006 // alle Sinne vorhanden sind, wird die Nachricht nicht wahrgenommen.
2007 if (orig_senses == senses // kein Sinn geloescht, haeufigster Fall
2008 || (!(msg_type&MSG_ALL_SENSES) && senses) ) // min. ein Sinn uebrig
2009 return 0;
MG Mud User88f12472016-06-24 23:31:02 +02002010
Bugfix427a5812022-01-07 15:41:24 +01002011 return MSG_SENSE_BLOCK;
MG Mud User88f12472016-06-24 23:31:02 +02002012}
2013
2014public varargs int ReceiveMsg(string msg, int msg_type, string msg_action,
2015 string msg_prefix, object origin)
2016{
2017 if (!msg) return MSG_FAILED;
2018
2019 // Flags und Typen spalten
2020 int flags = msg_type & MSG_ALL_FLAGS;
2021 int type = msg_type & ~flags;
2022
2023 // ggf. defaults ermitteln
2024 origin ||= previous_object();
2025 msg_action ||= comm_guess_action();
2026 type ||= comm_guess_message_type(msg_action, origin);
2027
2028 // Debugmeldungen nur an Magier oder Testspieler mit P_WIZ_DEBUG
2029 if (msg_type & MT_DEBUG)
2030 {
2031 if (!QueryProp(P_WIZ_DEBUG)
2032 || (!IS_LEARNER(ME) && !QueryProp(P_TESTPLAYER)) )
2033 return MSG_FAILED;
2034 }
2035
2036 // Zuerst werden Sinne und P_IGNORE sowie ggf. sonstige Filter geprueft. In
2037 // dem Fall ist direkt Ende, kein Kobold, keine Komm-History, keine
2038 // Weiterbearbeitung.
2039 // aber bestimmte Dinge lassen sich einfach nicht ignorieren.
2040 if (!(flags & MSG_DONT_IGNORE))
2041 {
Bugfix427a5812022-01-07 15:41:24 +01002042 // Sinne pruefen.
2043 int res=check_senses(msg_type);
MG Mud User88f12472016-06-24 23:31:02 +02002044 if (res) return res;
2045
2046 // Spieler-definiertes Ignoriere? (nur typen uebergeben, keine Flags)
2047 res=check_ignores(msg, type, msg_action, msg_prefix, origin);
2048 if (res) return res;
2049 }
2050
Zesstra3a261e52022-02-10 14:00:31 +01002051 // Mentions in der Form @Charname werden in Kommunikation oder beim Hoeren
2052 // von Rufen und Sagen markiert und gegebenfalls gibt es ein Pieps dafuer
2053 int mention;
2054 if ((type & MT_COMM)
2055 || ((type & MT_LISTEN) && msg_action in ({MA_SAY, MA_SHOUT}))
2056 )
2057 {
2058 // Um den Charnamen Tags fuer terminal_colour() einfuegen.
2059 // Lookahead und Lookbehind assertions um die Whitespaces um das Wort
2060 // nicht in den Match einzuschliessen (und zu ersetzen).
2061 string tmp = regreplace(msg,
2062 sprintf("(?<=\\s)@%s(?=\\s*)",getuid(ME)),
2063 sprintf("%%^mention%%^@%s%%^normal%%^",
2064 capitalize(getuid(ME))),
2065 RE_PCRE|RE_GLOBAL|RE_CASELESS);
2066 send_debug(ME, tmp);
2067 // Der Vergleich ist weniger schlimm als es aussieht, weil die Strings
2068 // unterschiedlich gross sein werden und daher nicht zeichenweise
2069 // verglichen werden muessen. Es ist dann jedenfalls schneller als
2070 // getrennt mit regmatch oder strstr zu schauen, ob @charname
2071 // vorkommt.
2072 if (tmp != msg)
2073 {
2074 msg = tmp;
2075 mention = 1;
2076 }
2077 }
2078
MG Mud User88f12472016-06-24 23:31:02 +02002079 // Fuer MT_COMM gibt es ein paar Sonderdinge zu machen.
2080 if ((type & MT_COMM))
2081 {
2082 // erstmal in der Komm-History ablegen, wenn gewuenscht.
2083 if ((!(flags & MSG_DONT_STORE)))
2084 {
2085 string uid;
2086 if (query_once_interactive(origin))
2087 uid = origin->query_real_name();
2088 else
2089 uid = origin->name(WER) || "<unbekannt>";
Zesstraa31cd5c2016-12-17 20:11:07 +01002090 add_to_tell_history(uid, 0, 1, msg, msg_prefix,
2091 (msg_action == MA_TELL ? MSGFLAG_TELL : 0 ) );
MG Mud User88f12472016-06-24 23:31:02 +02002092 }
2093
2094 // ggf. Uhrzeit bei abwesenden Spielern anhaengen, aber nicht bei
2095 // Ebenenmeldungen. (Die haben ggf. schon.)
2096 if (stringp(msg_action) && QueryProp(P_AWAY)
2097 && strstr(msg_action, MA_CHANNEL) != 0)
2098 {
2099 // Uhrzeit anhaengen, aber ggf. muss ein \n abgeschnitten werden.
2100 if (msg[<1] == '\n')
2101 msg = msg[0..<2]+" [" + strftime("%H:%M",time()) + "]\n";
2102 else
2103 msg = msg + " [" + strftime("%H:%M",time()) + "]";
2104 }
2105 // Kobold erlaubt und gewuenscht? Kobold ist fuer die
2106 // direkte Kommunikation mittels MT_COMM vorgesehen.
2107 // Oropax von Magiern leitet inzwischen auch nur in Kobold um statt zu
2108 // ignorieren.
2109 // die if-Konstruktion ist so, weil ich das _flush_cache() im else
2110 // brauche.
2111 if (query_editing(this_object()) || query_input_pending(this_object())
2112 || QueryProp(P_EARMUFFS))
2113 {
2114 if (!(flags & MSG_DONT_BUFFER)
2115 && QueryProp(P_BUFFER))
2116 {
2117 // Nachricht soll im Kobold gespeichert werden.
2118 return add_to_kobold(msg, msg_type, msg_action, msg_prefix, origin);
2119 }
2120 }
2121 else
2122 {
2123 // wenn nicht in Editor/input_to, mal versuchen, den Kobold zu
2124 // entleeren.
2125 _flush_cache(0);
2126 }
Bugfix3afcb792022-01-21 22:32:42 +01002127 }
2128
Zesstra3a261e52022-02-10 14:00:31 +01002129 // Farbtags ersetzen
2130 msg = terminal_colour(msg, colourmap);
2131
2132 // Alertton senden?
2133 if ((msg_type & MSG_ALERT) || mention)
2134 comm_beep(msg_action, mention);
MG Mud User88f12472016-06-24 23:31:02 +02002135
2136 // Ausgabenachricht bauen und an den Spieler senden.
2137 if (flags & MSG_DONT_WRAP)
2138 msg = (msg_prefix ? msg_prefix : "") + msg;
2139 else
2140 {
2141 int bsflags = flags & MSG_ALL_BS_FLAGS;
2142 if (QueryProp(P_MESSAGE_PREPEND))
2143 bsflags |= BS_PREPEND_INDENT;
2144 msg = break_string(msg, 78, msg_prefix, bsflags);
2145 }
2146 efun::tell_object(ME, msg);
2147
2148 return MSG_DELIVERED;
2149}