blob: 2dbdc75ad3112e307016a017eaec74e2fcec7c1d [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.
Zesstra7459f252022-02-23 22:47:26 +010068private nosave struct kobold_buffer_s kobold = (<kobold_buffer_s>
MG Mud User88f12472016-06-24 23:31:02 +020069 buf: allocate(32),
70 index: -1,);
Zesstra7459f252022-02-23 22:47:26 +010071// Vault fuer Offline-TMs
72// Der KOBOLD (/secure/kobold) muss immer eine Referenz auf dieses Objekt
73// halten.
74private nosave lwobject "/std/player/comm_vault" commvault;
MG Mud User88f12472016-06-24 23:31:02 +020075
Zesstra3a261e52022-02-10 14:00:31 +010076// Colourmap
77// TODO: spaeter konfigurierbar machen
78private mapping build_colourmap(string ttype="ansi");
79private nosave mapping colourmap = build_colourmap();
80
MG Mud User88f12472016-06-24 23:31:02 +020081varargs string name(int casus, int demonst);
82
83//local property prototypes
84static int _query_intermud();
85public int RemoveIgnore(string ign);
86public int AddIgnore(string ign);
87
88public varargs int ReceiveMsg(string msg, int msg_type, string msg_action,
89 string msg_prefix, object origin);
Zesstra7459f252022-02-23 22:47:26 +010090private int check_ignores(string msg, int msg_type, string msg_action,
91 string msg_prefix, object|string origin);
92private varargs void add_struct_tell_history(struct kobold_msg_s msg,
93 int sent, int recv, int flags );
MG Mud User88f12472016-06-24 23:31:02 +020094
95// erzeugt sortierte Liste an Kommunikationspartnern
96private string *sorted_commpartners(int reversed);
97
Zesstra7459f252022-02-23 22:47:26 +010098protected void create()
MG Mud User88f12472016-06-24 23:31:02 +020099{
100 ::create();
Bugfix3afcb792022-01-21 22:32:42 +0100101 Set(P_ALERT, SAVE, F_MODE_AS);
MG Mud User88f12472016-06-24 23:31:02 +0200102 Set(P_EARMUFFS, 0);
103 Set(P_EARMUFFS, SAVE, F_MODE);
104 Set(P_EARMUFFS, SECURED, F_MODE);
105 Set(P_INTERMUD, SAVE, F_MODE);
106 Set(P_IGNORE, ([]), F_VALUE);
107 Set(P_IGNORE, SAVE, F_MODE);
108 Set(P_BUFFER, SAVE, F_MODE);
Zesstra7459f252022-02-23 22:47:26 +0100109 SetProp(P_BUFFER, KOBOLD_OFFLINE);
MG Mud User88f12472016-06-24 23:31:02 +0200110 Set(P_MESSAGE_PREPEND, SAVE, F_MODE_AS);
111 Set(P_MESSAGE_BEEP, SAVE, F_MODE_AS);
112}
113
114void create_super()
115{
116 set_next_reset(-1);
117}
118
Zesstra3a261e52022-02-10 14:00:31 +0100119private mapping build_colourmap(string ttype)
120{
121 mapping res = ([0:""]);
122 switch(ttype)
123 {
124 case "dumb":
125 return res;
126 case "ansi":
127 res = ([ 0:ANSI_NORMAL, "normal": ANSI_NORMAL,
128 "bold": ANSI_BOLD, "underlined": ANSI_UNDERL,
129 "blink": ANSI_BLINK, "invers": ANSI_INVERS,
130 "black": ANSI_BLACK, "red": ANSI_RED,
131 "green": ANSI_GREEN, "yellow": ANSI_YELLOW,
132 "blue": ANSI_BLUE, "purple": ANSI_PURPLE,
133 "cyan": ANSI_CYAN, "white": ANSI_WHITE,
134 "bg_black": ANSI_BG_BLACK, "bg_red": ANSI_BG_RED,
135 "bg_green": ANSI_BG_GREEN, "bg_yellow": ANSI_BG_YELLOW,
136 "bg_blue": ANSI_BG_BLUE, "bg_purple": ANSI_BG_PURPLE,
137 "bg_cyan": ANSI_BG_CYAN, "bg_white": ANSI_BG_WHITE,
138 "mention": ANSI_BOLD+ANSI_BG_BLUE,
139 ]);
140 break;
141 case "vt100":
142 res += ([0:ANSI_NORMAL, "normal": ANSI_NORMAL,
143 "bold": ANSI_BOLD, "underlined": ANSI_UNDERL,
144 "blink": ANSI_BLINK, "invers": ANSI_INVERS,
145 "mention": ANSI_BOLD,
146 ]);
147 break;
148 default:
149 assert(1, "Ungueltiger Terminaltyp in build_colourmap");
150 }
151 return res;
152}
153
154protected void set_colourmap(string ttype="ansi")
155{
156 colourmap = build_colourmap(ttype);
157}
158
Zesstra7459f252022-02-23 22:47:26 +0100159private void setup_comm_vault()
160{
161 if (!commvault && (QueryProp(P_BUFFER) & KOBOLD_OFFLINE))
MG Mud User88f12472016-06-24 23:31:02 +0200162 {
Zesstra7459f252022-02-23 22:47:26 +0100163 // Schauen, ob ein Vault im KOBOLD existiert.
164 commvault = KOBOLD->RetrieveVault();
165 // Wenn nicht, aber eins gewuenscht ist, wird eins erstellt und in KOBOLD
166 // hinterlegt.
167 if (!commvault)
168 {
169 commvault = new_lwobject("/std/player/comm_vault");
170 KOBOLD->DepositVault(commvault);
171 }
MG Mud User88f12472016-06-24 23:31:02 +0200172 }
173}
174
Zesstra2504b2d2020-05-22 12:30:17 +0200175static int set_report(string str)
176{
MG Mud User88f12472016-06-24 23:31:02 +0200177 int canflags = QueryProp(P_CAN_FLAGS);
MG Mud User88f12472016-06-24 23:31:02 +0200178 if(!str)
179 {
Zesstracf8f2952020-05-22 12:07:52 +0200180 if (stat_reports)
181 {
182 string *res=({});
183 if (stat_reports & DO_REPORT_HP)
184 res+=({"Lebenspunkte"});
185 if (stat_reports & DO_REPORT_SP)
186 res+=({"Konzentrationspunkte"});
187 if (stat_reports & DO_REPORT_POISON)
188 res+=({"Vergiftungen"});
189 if (stat_reports & DO_REPORT_WIMPY)
190 res+=({"Vorsicht"});
MG Mud User88f12472016-06-24 23:31:02 +0200191
Zesstracf8f2952020-05-22 12:07:52 +0200192 tell_object(ME,break_string(
MG Mud User88f12472016-06-24 23:31:02 +0200193 "Dir werden jetzt Veraenderungen Deiner "
194 +CountUp(res) + " berichtet.",78));
Zesstra86ec63b2020-05-22 12:09:56 +0200195 if (GMCP_Status("MG.char") || GMCP_Status("char")
196 || GMCP_Status("Char"))
197 {
198 tell_object(ME,break_string(
199 "Achtung: Dein Client laesst sich den Report per GMCP "
Zesstra2504b2d2020-05-22 12:30:17 +0200200 "(s. 'hilfe GMCP') uebermitteln. Daher wird er Dir nicht "
Zesstra86ec63b2020-05-22 12:09:56 +0200201 "in der Textausgabe des Spiels angezeigt! Moechtest Du "
202 "dies nicht, schalte bitte in Deinem Client GMCP-Module mit "
203 "Namen wie 'MG.char', 'char', 'Char' oder aehnliche aus."));
204 }
MG Mud User88f12472016-06-24 23:31:02 +0200205 }
206 else
207 tell_object(ME,
208 "Alle Statusreports sind ausgeschaltet.\n");
209
210 return 1;
211 }
Zesstra2504b2d2020-05-22 12:30:17 +0200212 else if (str == "aus")
213 {
214 if (stat_reports & DO_REPORT_HP || stat_reports & DO_REPORT_WIMPY)
215 {
MG Mud User88f12472016-06-24 23:31:02 +0200216 string s="";
Zesstra2504b2d2020-05-22 12:30:17 +0200217 if (stat_reports & DO_REPORT_HP)
218 {
MG Mud User88f12472016-06-24 23:31:02 +0200219 str="ebenfalls ";
220 tell_object(ME, "Der Report wurde ausgeschaltet.\n");
221 }
Zesstra2504b2d2020-05-22 12:30:17 +0200222 if ( stat_reports & DO_REPORT_WIMPY )
223 {
MG Mud User88f12472016-06-24 23:31:02 +0200224 tell_object(ME, "Der Vorsicht-Report wurde "+s+
225 "ausgeschaltet.\n");
226 }
227 stat_reports=0;
228 }
Zesstra2504b2d2020-05-22 12:30:17 +0200229 else
230 {
MG Mud User88f12472016-06-24 23:31:02 +0200231 tell_object(ME, "Der Report ist bereits ausgeschaltet.\n");
232 }
233 return 1;
234 }
Zesstra2504b2d2020-05-22 12:30:17 +0200235 else if (str == "ein")
236 {
237 if ( stat_reports & DO_REPORT_HP )
238 {
MG Mud User88f12472016-06-24 23:31:02 +0200239 tell_object(ME, "Der Report ist bereits eingeschaltet.\n");
240 return 1;
241 }
242 tell_object(ME, "Der Report wurde eingeschaltet.\n");
243 stat_reports |= DO_REPORT_HP;
Zesstra2504b2d2020-05-22 12:30:17 +0200244 if (!(canflags & CAN_REPORT_SP))
245 {
246 if (QueryQuest("Hilf den Gnarfen")==1)
247 {
MG Mud User88f12472016-06-24 23:31:02 +0200248 SetProp(P_CAN_FLAGS, canflags | CAN_REPORT_SP);
249 stat_reports |= DO_REPORT_SP;
250 }
Zesstra2504b2d2020-05-22 12:30:17 +0200251 else
252 {
MG Mud User88f12472016-06-24 23:31:02 +0200253 tell_object(ME, break_string(
254 "Fuer den Statusreport Deiner Konzentration musst Du jedoch "
255 "zunaechst die Quest \"Hilf den Gnarfen\" bestehen.",78));
256 }
257 }
Zesstra2504b2d2020-05-22 12:30:17 +0200258 else
259 {
MG Mud User88f12472016-06-24 23:31:02 +0200260 stat_reports |= DO_REPORT_SP;
261 }
Zesstra2504b2d2020-05-22 12:30:17 +0200262 if (!(canflags & CAN_REPORT_POISON))
263 {
264 if (QueryQuest("Katzenjammer")==1)
265 {
MG Mud User88f12472016-06-24 23:31:02 +0200266 SetProp(P_CAN_FLAGS, canflags | CAN_REPORT_POISON);
267 stat_reports |= DO_REPORT_POISON;
268 }
Zesstra2504b2d2020-05-22 12:30:17 +0200269 else
270 {
MG Mud User88f12472016-06-24 23:31:02 +0200271 tell_object(ME, break_string(
272 "Fuer den Statusreport Deiner Vergiftung musst Du jedoch "
273 "zunaechst die Quest \"Katzenjammer\" bestehen.",78));
274 }
275 }
Zesstra2504b2d2020-05-22 12:30:17 +0200276 else
277 {
MG Mud User88f12472016-06-24 23:31:02 +0200278 stat_reports |= DO_REPORT_POISON;
279 }
280 // Cache loeschen, damit beim naechsten Report-Event alle Daten neu
281 // eingetragen werden muessen. Muss beim Einschalten des Reports
282 // passieren, weil auch in der inaktiven Zeit weiterhin Aenderungen in
283 // status_report() eingehen, so dass der Cache zwar erst einmal leer ist,
284 // aber beim Wiedereinschalten nicht mehr ungueltig waere und somit
285 // veraltete Daten an den Spieler ausgegeben werden. Im unguenstigsten
286 // Fall wuerde das sogar dazu fuehren, dass die veralteten Daten lange
287 // Zeit nicht aktualisiert werden, wenn z.B. P_HP == P_MAX_HP, so dass
288 // kein P_HP-Event mehr eingeht.
289 report_cache=0;
Zesstra2504b2d2020-05-22 12:30:17 +0200290 // Fall-through fuer Statusausgabe
MG Mud User88f12472016-06-24 23:31:02 +0200291 }
Zesstra2504b2d2020-05-22 12:30:17 +0200292 else if (str == "vorsicht")
293 {
294 if (!(canflags & CAN_REPORT_WIMPY))
295 {
296 if (QueryQuest("Schrat kann nicht einschlafen")==1)
297 {
MG Mud User88f12472016-06-24 23:31:02 +0200298 SetProp(P_CAN_FLAGS, canflags | CAN_REPORT_WIMPY);
299 tell_object(ME, "Der Vorsicht-Report wurde eingeschaltet.\n");
300 stat_reports |= DO_REPORT_WIMPY;
301 }
Zesstra2504b2d2020-05-22 12:30:17 +0200302 else
303 {
MG Mud User88f12472016-06-24 23:31:02 +0200304 tell_object(ME, break_string(
305 "Fuer den Statusreport Deiner Vorsicht musst Du "
306 "zunaechst die Quest \"Schrat kann nicht einschlafen\" "
307 "bestehen.",78));
308 }
309 }
310 else
311 {
312 stat_reports |= DO_REPORT_WIMPY;
313 }
314 // fuer Seher auch Bericht der Fluchtrichtung einschalten.
315 if ((stat_reports & DO_REPORT_WIMPY)
316 && !(stat_reports & DO_REPORT_WIMPY_DIR)
317 && ((canflags & CAN_REPORT_WIMPY) || IS_SEER(ME)))
318 {
Zesstra2504b2d2020-05-22 12:30:17 +0200319 stat_reports |= DO_REPORT_WIMPY_DIR;
MG Mud User88f12472016-06-24 23:31:02 +0200320 }
Zesstra2504b2d2020-05-22 12:30:17 +0200321 // Fall-through fuer Statusausgabe
MG Mud User88f12472016-06-24 23:31:02 +0200322 }
323 // sendet einmalig genau jetzt den konfigurierten report. Kann zum testen
324 // (von Triggern) oder beim Login benutzt werden, wenn man einen initialen
325 // Datenbestand erhalten will.
326 else if (str=="senden")
327 {
328 // Es wird Ausgabe von LP und Vorsicht getriggert, das sendet beide
329 // Zeilen.
330 status_report(DO_REPORT_HP, QueryProp(P_HP));
331 status_report(DO_REPORT_WIMPY, QueryProp(P_WIMPY));
332 return 1;
333 }
334 else
335 return 0;
336 // nur aktuellen Zustand berichten
337 set_report(0);
338 return 1;
339}
340
341private string get_poison_desc(int p) {
342 string ret;
343 if ( intp(p) ) {
344 switch(p) {
345 case 0: ret="keins"; break;
346 case 1..3: ret="leicht"; break;
347 case 4..8: ret="gefaehrlich"; break;
348 default: ret="sehr ernst"; break;
349 }
350 return ret;
351 }
352 else return "(nicht verfuegbar)";
353}
354
355// sprintf()-Formatstrings fuer die Reportausgabe.
356#define REPORTLINE "LP: %3d, KP: %3s, Gift: %s.\n"
357#define REPORTLINE_WIMPY "Vorsicht: %d, Fluchtrichtung: %s.\n"
358// Defines zur Adressierung der Cache-Eintraege
359#define REP_HP 0
360#define REP_SP 1
361#define REP_POISON 2
362
363protected void status_report(int type, mixed val) {
364 // Wenn der Spieler GMCP hat und das sich um die Information kuemmert,
365 // erfolgt keine textuelle Ausgabe mehr. Daher return, wenn GMCP_Char()
366 // erfolg vermeldet hat.
367 int flags = QueryProp(P_CAN_FLAGS);
368 switch (type) {
369 case DO_REPORT_HP:
370 if (GMCP_Char( ([ P_HP: val ]) ) ) return;
371 break;
372 case DO_REPORT_SP:
373 if (!(flags & CAN_REPORT_SP)) return;
374 if (GMCP_Char( ([ P_SP: val ]) ) ) return;
375 break;
376 case DO_REPORT_POISON:
377 if (!(flags & CAN_REPORT_POISON)) return;
378 if (GMCP_Char( ([ P_POISON: val ]) ) ) return;
379 break;
380 case DO_REPORT_WIMPY:
381 if (!(flags & CAN_REPORT_WIMPY)) return;
382 if (GMCP_Char( ([ P_WIMPY: val ]) ) ) return;
383 break;
384 case DO_REPORT_WIMPY_DIR:
385 if (!(flags & CAN_REPORT_WIMPY_DIR)) return;
386 if (GMCP_Char( ([ P_WIMPY_DIRECTION: val ]) ) ) return;
387 break;
388 }
389
390 // konventionelle textuelle Ausgabe des Reports ab hier.
391 if (!(type & stat_reports))
392 return;
393
394 if ( !report_cache ) {
395 report_cache = ({
396 QueryProp(P_HP),
397 (stat_reports&DO_REPORT_SP) ? to_string(QueryProp(P_SP)) : "###",
398 (stat_reports&DO_REPORT_POISON) ?
399 get_poison_desc(QueryProp(P_POISON)) : "(nicht verfuegbar)"
400 });
401 }
402
403 switch(type) {
404 // LP berichten: Cache aktualisieren und Meldung ausgeben.
405 case DO_REPORT_HP:
406 report_cache[REP_HP]=val;
407 tell_object(ME, sprintf(REPORTLINE, report_cache[REP_HP],
408 report_cache[REP_SP], report_cache[REP_POISON]));
409 break;
410 // KP berichten: Wenn der Spieler den Report freigeschaltet hat,
411 // wird bei Aenderungen gemeldet. Wenn nicht, aendert sich nur der
412 // Cache-Eintrag. So wird verhindert, dass ein Spieler ueber KP-
413 // Veraenderungen auch dann informiert wuerde, wenn er den KP-Report
414 // gar nicht benutzen koennte.
415 case DO_REPORT_SP:
416 report_cache[REP_SP]=to_string(val);
417 tell_object(ME, sprintf(REPORTLINE, report_cache[REP_HP],
418 report_cache[REP_SP], report_cache[REP_POISON]));
419 break;
420 // Giftstatus berichten: Wenn der Giftreport freigeschaltet ist,
421 // Cache aktualisieren und berichten. Wenn nicht, aendert sich nur
422 // der Cache-Eintrag. Erlaeuterung hierzu s.o. beim KP-Report.
423 case DO_REPORT_POISON:
424 report_cache[REP_POISON] = get_poison_desc(val);
425 tell_object(ME, sprintf(REPORTLINE, report_cache[REP_HP],
426 report_cache[REP_SP], report_cache[REP_POISON]));
427 break;
428 // Vorsicht-Report: kann ohne weitere Abfragen ausgegeben werden, da
429 // alle noetigen Checks schon zu Beginn dieser Funktion erledigt wurden.
430 // Lediglich der Inhalt der Meldung muss abhaengig vom Seherstatus
431 // konfiguriert werden.
432 case DO_REPORT_WIMPY:
433 string res;
434 if (IS_SEER(ME)) {
435 // QueryProp() aus Kostengruenden im if(), damit die Aufruf-
436 // Haeufigkeit zumindest ein wenig reduziert wird.
437 string dir = QueryProp(P_WIMPY_DIRECTION)||"keine";
438 res = sprintf(REPORTLINE_WIMPY, val, dir);
439 }
440 else
441 res = sprintf(REPORTLINE_WIMPY, val, "(nicht verfuegbar)");
442 tell_object(ME, res);
443 break;
444 // Fluchtrichtungs-Report: wird nur bei Sehern ausgegeben, damit
445 // nicht auch Spieler eine VS-/FR-Meldung bekommen, wenn z.B. eine
446 // externe Manipulation der Fluchtrichtung stattfindet, sie aber den
447 // Report mangels Seherstatus gar nicht freigeschaltet haben.
448 case DO_REPORT_WIMPY_DIR:
449 if (IS_SEER(ME)) {
450 if (!val) val = "keine";
451 tell_object(ME,sprintf(REPORTLINE_WIMPY, QueryProp(P_WIMPY), val));
452 }
453 break;
454 }
455}
456
457#undef REPORTLINE
458#undef REPORTLINE_WIMPY
459#undef REP_HP
460#undef REP_SP
461#undef REP_POISON
462
463private string permutate(string msg)
464{
465 // Kontrollzeichen rausfiltern. *seufz*
466 msg = regreplace(msg,"[[:cntrl:]]","",RE_PCRE|RE_GLOBAL);
467 object ob=QueryProp(P_PERM_STRING);
468 if (!objectp(ob))
469 return msg;
470
Zesstra04f613c2019-11-27 23:32:54 +0100471 return ({string})ob->permutate_string(msg)||"";
MG Mud User88f12472016-06-24 23:31:02 +0200472}
473
474// neue nachricht an den Kobold anhaengen
475// Rueckgabewerte: MSG_BUFFER_FULL oder MSG_BUFFERED
476private int add_to_kobold(string msg, int msg_type, string msg_action,
477 string msg_prefix, object origin)
478{
479 // Nachricht soll im Kobold gespeichert werden.
480 // Kobold speichert Rohdaten und gibt spaeter das ganze auch wieder via
481 // ReceiveMsg() aus - dabei wird MSG_DONT_BUFFER | MSG_DONT_STORE gesetz,
482 // damit keine erneute Speicher in Kobold oder Komm-History erfolgt.
483
484 // wenn der Puffer zu klein ist, Groesse verdoppeln, wenn noch unterhalb
485 // des Limits.
486 if (kobold->index >= sizeof(kobold->buf)-1) {
487 if (sizeof(kobold->buf) < MAX_KOBOLD_LIMIT)
488 kobold->buf += allocate(sizeof(kobold->buf));
489 else
490 return MSG_BUFFER_FULL;
491 }
492 kobold->index = kobold->index +1;
493 // neue Nachricht an den Puffer anhaengen.
494 string sendername = query_once_interactive(origin) ?
495 origin->query_real_name() :
496 origin->name(WER) || "<Unbekannt>";
Zesstraa5fda4a2022-01-06 17:31:44 +0100497 kobold->buf[kobold->index] = (<kobold_msg_s> msg: msg,
MG Mud User88f12472016-06-24 23:31:02 +0200498 type : msg_type, action : msg_action, prefix : msg_prefix,
499 sendername : sendername);
500 return MSG_BUFFERED;
501}
502
Zesstra7459f252022-02-23 22:47:26 +0100503// speichert den Inhalt vom commvault im Kobold und der TM-History
504private void process_comm_vault(lwobject "/std/player/comm_vault" vault)
505{
506 struct kobold_msg_s *buffer = vault.Retrieve();
507 if (!sizeof(buffer))
508 return;
509 foreach(struct kobold_msg_s msg: buffer)
510 {
511 // Spieler-definiertes Ignoriere? (nur typen uebergeben, keine Flags)
512 int res = check_ignores(msg.msg, msg.type, msg.action, msg.prefix,
513 msg.sendername);
514 if (res) {
515 // Nachricht wegwerfen. Aber ggf. den Absender informieren, wenn der
516 // online ist und wir nicht Invis
517 object pl = find_player(msg.sendername);
518 if (pl &&
519 (!QueryProp(P_INVIS) || IS_LEARNER(pl)) )
520 pl->ReceiveNotify(sprintf("Deine Nachricht an %s wurde "
521 "ignoriert.",capitalize(getuid(this_object()))), MA_TELL);
522 continue;
523 }
524
525 // wenn der Puffer zu klein ist, Groesse verdoppeln.
526 // Keine Pruefung hier, weil das vault schon die Groesse beschraenkt und
527 // der Inhalt auf jeden Fall passen soll.
528 if (kobold->index >= sizeof(kobold->buf)-1)
529 kobold->buf += allocate(sizeof(kobold->buf));
530 kobold->index += 1;
531 kobold->buf[kobold->index] = msg;
532
533 // TM-History
534 add_struct_tell_history(msg, 0, 1, MSGFLAG_TELL);
535 }
536 vault.Empty();
537}
538
MG Mud User88f12472016-06-24 23:31:02 +0200539private void _flush_cache(int verbose) {
540 // nur mit genug Evalticks ausgeben.
Zesstra7459f252022-02-23 22:47:26 +0100541 if (get_eval_cost() < 500000) return;
MG Mud User88f12472016-06-24 23:31:02 +0200542 if (kobold->index >= 0)
543 {
544 ReceiveMsg("Ein kleiner Kobold teilt Dir folgendes mit:",
545 MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_BUFFER,
546 0, 0, this_object());
547 int prepend = QueryProp(P_MESSAGE_PREPEND);
548 foreach(int i: 0 .. kobold->index) // '0 ..' ist wichtig!
549 {
Zesstraa5fda4a2022-01-06 17:31:44 +0100550 struct kobold_msg_s msg = kobold->buf[i];
MG Mud User88f12472016-06-24 23:31:02 +0200551 // dies ist dient der Fehlerabsicherung, falls es nen Fehler (z.B. TLE)
552 // in der Schleife unten gab: dann ist index nicht auf -1 gesetzt
553 // worden, aber einige Nachrichten sind schon geloescht.
554 if (!structp(msg)) continue;
Zesstra7459f252022-02-23 22:47:26 +0100555 // Im folgenden nicht den string in der struct aendern (die wird ggf.
556 // auch noch von der TM-History gebraucht).
557 string msgstr = msg.msg;
558 // Wenn Nachricht schon laenger her ist, Uhrzeit anhaengen, aber ggf.
559 // muss ein \n abgeschnitten werden.
560 if (msg.timestamp < time() - 3600)
561 {
562 if (msgstr[<1] == '\n')
563 msgstr = msgstr[0..<2]
564 + " [" + strftime("%d.%m.%y %T", msg.timestamp) + "]";
565 else
566 msgstr = msgstr
567 + " [" + strftime("%d.%m.%y %T", msg.timestamp) + "]";
568 }
MG Mud User88f12472016-06-24 23:31:02 +0200569 // Ausgabe via efun::tell_object(), weil die Arbeit von ReceiveMsg()
Zesstra3a261e52022-02-10 14:00:31 +0100570 // schon getan wurde. Allerdings muessen wir uns noch um den Umbruch
571 // und Farben kuemmern.
Zesstra7459f252022-02-23 22:47:26 +0100572 msgstr = terminal_colour(msgstr, colourmap);
MG Mud User88f12472016-06-24 23:31:02 +0200573 if ((msg->type) & MSG_DONT_WRAP)
Zesstra7459f252022-02-23 22:47:26 +0100574 msgstr = (msg->prefix ? msg->prefix : "") + msgstr;
MG Mud User88f12472016-06-24 23:31:02 +0200575 else
576 {
577 int bsflags = msg->type & MSG_ALL_BS_FLAGS;
578 if (prepend)
579 bsflags |= BS_PREPEND_INDENT;
Zesstra7459f252022-02-23 22:47:26 +0100580 msgstr = break_string(msgstr, 78, msg->prefix, bsflags);
MG Mud User88f12472016-06-24 23:31:02 +0200581 }
Zesstra7459f252022-02-23 22:47:26 +0100582 efun::tell_object(this_object(), msgstr);
MG Mud User88f12472016-06-24 23:31:02 +0200583 kobold->buf[i]=0;
584 }
585 kobold->index=-1;
586 }
587 else if (verbose)
588 {
589 ReceiveMsg("Der kleine Kobold hat leider nichts Neues fuer Dich.",
590 MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_BUFFER,
591 0, 0, this_object());
592 }
593}
594
595varargs int cmd_kobold(string arg)
596{
Zesstra7459f252022-02-23 22:47:26 +0100597 if (!sizeof(arg))
598 {
599 _flush_cache(1);
600 return 1;
601 }
MG Mud User88f12472016-06-24 23:31:02 +0200602 switch(arg)
603 {
604 case "ein":
Zesstra7459f252022-02-23 22:47:26 +0100605 SetProp(P_BUFFER, KOBOLD_ONLINE|KOBOLD_OFFLINE);
606 ReceiveNotify("Der Kobold merkt sich jetzt alles!");
607 break;
608 case "online":
609 SetProp(P_BUFFER, KOBOLD_ONLINE);
610 ReceiveNotify("Der Kobold merkt sich jetzt alles, "
611 "wenn Du online bist!");
612 break;
613 case "offline":
614 SetProp(P_BUFFER, KOBOLD_OFFLINE);
615 ReceiveNotify("Der Kobold merkt sich jetzt alles, "
616 "wenn Du offline bist!");
617 break;
MG Mud User88f12472016-06-24 23:31:02 +0200618 case "aus":
619 SetProp(P_BUFFER, 0);
Zesstra7459f252022-02-23 22:47:26 +0100620 ReceiveNotify("Der Kobold wird Dich nicht stoeren!");
621 break;
622 default:
623 ReceiveNotify("Der Kobold sagt: Was soll ich mir denn merken? "
624 "('ein', 'aus', 'offline' oder 'online')");
625 return 1;
MG Mud User88f12472016-06-24 23:31:02 +0200626 }
Zesstra7459f252022-02-23 22:47:26 +0100627 if (QueryProp(P_BUFFER) & KOBOLD_OFFLINE)
628 setup_comm_vault();
629 else
630 {
631 // Comm-Vault entfernen. Aber zur Sicherheit nochmal abrufen und
632 // verarbeiten (sollte aber eigentlich ueberfluessig sein)
633 commvault = KOBOLD->ForgetVault();
634 if (commvault) {
635 process_comm_vault(commvault);
636 commvault = 0;
637 }
638 }
MG Mud User88f12472016-06-24 23:31:02 +0200639 return 1;
640}
641
642public int TestIgnoreSimple(string *arg)
Zesstrade642d22019-11-23 17:22:34 +0100643{ mapping ignore;
MG Mud User88f12472016-06-24 23:31:02 +0200644
645 if (!pointerp(arg) || !mappingp(ignore=Query(P_IGNORE,F_VALUE)))
646 return 0;
647 foreach(string s: arg)
648 {
649 if (member(ignore,s))
650 return 1;
651 }
652 return 0;
653}
654
655//TODO: deprecated - entfernen, wenn Message() entfernt wird.
656private int check_ignore(mixed ignore, string verb, string name)
657{
658 if (ignore == verb)
659 return 1;
660 ignore = explode(ignore, ".");
661 return ((sizeof(ignore) > 1) &&
662 (name == ignore[0] && member(ignore[1..], verb) != -1));
663}
664
Zesstra3a261e52022-02-10 14:00:31 +0100665// Die Nachricht kommt mit einem Alert oder Mention. comm_beep() prueft, ob
666// ein Piepston ausgegeben werden soll (langfristig andere Benachrichtigungen
667// geplant!).
668// Ueblicherweise werden nur alle <P_MESSAGE_BEEP> Sekunden Toene
669// uebermittelt.
670private void comm_beep(string msg_action, int mention=0)
Bugfix60f5bc62022-01-21 11:09:56 +0100671{
Zesstra1cc6cf32022-02-09 11:49:31 +0100672 // Wenn Alerts komplett abgeschaltet sind, gibts nix.
673 int alert_config = ({int})QueryProp(P_ALERT);
674 if (alert_config & AL_NO_SOUND)
675 return; // kein ton
676 // und maximal alle P_MESSAGE_BEEP Sekunden aufmerksam machen; bei 0s ist
677 // jedes Mal erlaubt.
Zesstra04f613c2019-11-27 23:32:54 +0100678 int beep_interval=({int})QueryProp(P_MESSAGE_BEEP);
Zesstra1cc6cf32022-02-09 11:49:31 +0100679 if ((time()-last_beep_time) < beep_interval)
680 return;
681 int required;
682 switch(msg_action)
Bugfix60f5bc62022-01-21 11:09:56 +0100683 {
Zesstra1cc6cf32022-02-09 11:49:31 +0100684 case MA_TELL:
685 required |= MB_TELL;
686 break;
687 case MA_SAY:
688 required |= MB_SAY;
689 break;
690 case MA_CHANNEL:
691 required |= MB_CHANNEL;
692 break;
693 case MA_SHOUT:
694 required |= MB_SHOUT;
695 break;
696 default:
697 // Alle anderen Aktionen, die keine gesonderten Aktionsfilter haben
698 required |= MB_MISC;
699 break;
Bugfix60f5bc62022-01-21 11:09:56 +0100700 }
Zesstra3a261e52022-02-10 14:00:31 +0100701 if (mention)
702 required |= MB_MENTION;
703
Zesstra1cc6cf32022-02-09 11:49:31 +0100704 // wenn in alert min. ein notwendiges Flag drin ist darf gepiepst werden
705 if (required & alert_config)
706 {
707 last_beep_time = time();
708 binary_message(b"\a", 1);
709 }
MG Mud User88f12472016-06-24 23:31:02 +0200710}
711
Zesstra7459f252022-02-23 22:47:26 +0100712private varargs void add_struct_tell_history(struct kobold_msg_s msg,
713 int sent, int recv, int flags )
MG Mud User88f12472016-06-24 23:31:02 +0200714{
715 /* tell_history ist ein Mapping mit UIDs der Gespraechspartner als Key.
716 Als Wert ist eine Strukur vom Typ chat_s eingetragen.
Zesstra7459f252022-02-23 22:47:26 +0100717 Strukturen chat_s und kobold_msg_s sind in /std/player/comm_structs.c
MG Mud User88f12472016-06-24 23:31:02 +0200718 definiert.
719 TODO fuer spaeter, gerade keine Zeit fuer:
720 Als Wert ist ein Array von chat_s enthalten, wobei das 0. Element das
721 jeweils juengste Gespraech mit diesem Gespraechspartner ist und alle
722 weiteren Elemente in der zeitlichen Reihenfolge kommen (also letztes
723 Element ist aeltestes Gespraech).
724 */
725
Zesstra996bafe2022-02-14 22:42:39 +0100726 // Gespraechspartner fuer erwidere auch ohne tmhist speichern.
Zesstraa31cd5c2016-12-17 20:11:07 +0100727 if (flags & (MSGFLAG_TELL|MSGFLAG_RTELL))
Zesstra7459f252022-02-23 22:47:26 +0100728 last_comm_partner = msg.sendername;
MG Mud User88f12472016-06-24 23:31:02 +0200729
730 // ist ein sortiertes Array von max. MAX_SAVED_CHATS Groesse, welches die
731 // Spieler enthaelt, denen man schon was mitgeteilt hat. Aktuellste am
732 // Anfang.
733 if (sent) {
734 if (!sizeof(commreceivers))
Zesstra7459f252022-02-23 22:47:26 +0100735 commreceivers = ({msg.sendername});
736 else if (commreceivers[0] != msg.sendername) {
MG Mud User88f12472016-06-24 23:31:02 +0200737 // nur wenn der aktuelle Partner nicht am Anfang steht, muss man hier was
738 // tun. Comm-Partner an den Anfang stellen und ggf. alten Eintrag
739 // entfernen.
740 // TODO: Effizienter gestalten.
Zesstra7459f252022-02-23 22:47:26 +0100741 commreceivers = ({msg.sendername}) + (commreceivers-({msg.sendername}));
MG Mud User88f12472016-06-24 23:31:02 +0200742 // ggf. kuerzen. (wenn !tell_history_enabled, wird es ggf. unten
743 // gemacht, denn die Hist muss min. alle UID enthalten, die auch in
744 // commreceivers drin sind.)
745 if (!tell_history_enabled && sizeof(commreceivers) > MAX_SAVED_CHATS)
746 commreceivers = commreceivers[0..MAX_SAVED_CHATS];
747 }
748 }
749
Zesstra996bafe2022-02-14 22:42:39 +0100750 // mit eingeschalteter History weitere Details speichern.
MG Mud User88f12472016-06-24 23:31:02 +0200751 if (!tell_history_enabled)
752 return;
753
Zesstra7459f252022-02-23 22:47:26 +0100754 if (msg.msg[<1] == '\n')
755 msg.msg = msg.msg[..<2];
MG Mud User88f12472016-06-24 23:31:02 +0200756
757 struct chat_s chat;
758 // Gespraechspartner unbekannt?
Zesstra7459f252022-02-23 22:47:26 +0100759 if (!member(tell_history, msg.sendername)) {
MG Mud User88f12472016-06-24 23:31:02 +0200760 // zuviele Gespraeche in Hist? >= ist Absicht weil ja gleich noch eins
761 // dazu kommt.
762 if (sizeof(tell_history) >= MAX_SAVED_CHATS) {
763 string deluid;
764 int zeit = __INT_MAX__;
765 foreach(string tuid, chat : tell_history) {
766 // aeltestes Gespraech suchen
767 if (zeit > chat->time_last_msg) {
768 deluid = tuid;
769 zeit = chat->time_last_msg;
770 }
771 }
772 // aeltestes Gespraech raus.
773 m_delete(tell_history, deluid);
774 if (member(commreceivers,deluid)>-1)
775 commreceivers-=({deluid});
776 }
777 // neues Gespraech anlegen
Zesstra7459f252022-02-23 22:47:26 +0100778 chat = (<chat_s> uid: msg.sendername, time_first_msg: msg.timestamp,
779 time_last_msg: msg.timestamp,
MG Mud User88f12472016-06-24 23:31:02 +0200780 sentcount: sent, recvcount: recv,
781 msgbuf: 0, ptr: 0 );
Zesstra7459f252022-02-23 22:47:26 +0100782 tell_history[msg.sendername] = chat;
MG Mud User88f12472016-06-24 23:31:02 +0200783 }
784 else {
785 // Gespraechspartner bekannt, altes Gespraech weiterbenutzen
Zesstra7459f252022-02-23 22:47:26 +0100786 chat = tell_history[msg.sendername];
787 chat->time_last_msg = msg.timestamp;
MG Mud User88f12472016-06-24 23:31:02 +0200788 chat->sentcount += sent;
789 chat->recvcount += recv;
790 }
791
Zesstra996bafe2022-02-14 22:42:39 +0100792 // ggf. auch INhalte von Gespraechen speichern
MG Mud User88f12472016-06-24 23:31:02 +0200793 if (tell_history_enabled < TELLHIST_ENABLED)
794 return;
795
796 // ggf. Array fuer Messages anlegen
797 if (!pointerp(chat->msgbuf))
798 chat->msgbuf = allocate(MAX_SAVED_MESSAGES);
799
Zesstra7459f252022-02-23 22:47:26 +0100800 // neue Struct ins Array schreiben
801 chat->msgbuf[chat->ptr] = msg;
MG Mud User88f12472016-06-24 23:31:02 +0200802 // Index auf naechste Messagestruktur ermitteln
803 chat->ptr = (chat->ptr + 1) % MAX_SAVED_MESSAGES;
Zesstra7459f252022-02-23 22:47:26 +0100804}
805
806private varargs void add_to_tell_history( string uid, int sent, int recv,
807 string message, string indent, int flags )
808{
809 //TODO: Entfernen, wenn das nicht mehr passiert.
810 if (!stringp(uid))
811 {
812 ReceiveMsg(sprintf(
813 "\nadd_to_tell_history(): got bad uid argument %O."
814 "sent: %d, recv: %d, flags: %d, msg: %s",
815 uid, sent, recv, flags, message),MT_DEBUG|MSG_BS_LEAVE_LFS,0,0,ME);
816 }
817 // Message-Struktur anlegen
818 struct kobold_msg_s msg = (<kobold_msg_s> msg: message, prefix: indent,
819 sendername: uid, timestamp: time());
820 add_struct_tell_history(msg, sent, recv, flags);
MG Mud User88f12472016-06-24 23:31:02 +0200821}
822
Zesstra996bafe2022-02-14 22:42:39 +0100823protected void clear_tell_history(int force)
MG Mud User88f12472016-06-24 23:31:02 +0200824{
825 /* Nach einem "schlafe ein" werden die gespeicherten Mitteilungen geloescht,
826 sofern der Spieler nichts abweichendes eingestellt hat. */
827
Zesstra996bafe2022-02-14 22:42:39 +0100828 // bei manuellem Loeschen (force==1) immer loeschen, ansonsten nur, wenn die
829 // History nicht "long-life" ist.
830 if (tell_history_enabled < TELLHIST_LONGLIFE || force)
831 {
832 tell_history = ([]);
833 commreceivers = ({});
834 }
MG Mud User88f12472016-06-24 23:31:02 +0200835}
836
837protected void reset(void)
838{
839 /* Wird 15 Minuten nach dem Verlust der Verbindung aufgerufen. Falls der
840 Spieler nicht inzwischen eine Verbindung wiederhergestellt hat, werden
841 wie bei einem "schlafe ein" die Mitteilungen geloescht. */
842
843 if (!interactive())
Zesstra996bafe2022-02-14 22:42:39 +0100844 clear_tell_history(0);
MG Mud User88f12472016-06-24 23:31:02 +0200845
846}
847
848// gerufen, wenn zielgerichtet mit jemandem kommuniziert wird _und_ das
849// Ergebnis des ReceiveMsg() geprueft werden und eine Meldung ausgegeben
850// werden soll.
851private void _send(object ob, string msg, int msg_type,
852 string msg_action, string msg_prefix)
853{
854 int res = ob->ReceiveMsg(msg, msg_type, msg_action, msg_prefix, ME);
Zesstra8b5320e2022-02-18 21:10:26 +0100855
MG Mud User88f12472016-06-24 23:31:02 +0200856 switch(res) {
857 case MSG_DELIVERED:
858 break; // nix machen
859 case MSG_BUFFERED:
Zesstra62b4a862022-12-23 20:08:16 +0100860 ReceiveMsg(ob->Name(WER) + " moechte gerade nicht gestoert werden. "
MG Mud User88f12472016-06-24 23:31:02 +0200861 "Die Mitteilung wurde von einem kleinen Kobold in Empfang "
862 "genommen. Er wird sie spaeter weiterleiten!",
863 MT_NOTIFICATION, msg_action, 0, this_object());
864 break;
865 case MSG_IGNORED:
866 case MSG_VERB_IGN:
867 case MSG_MUD_IGN:
868 ReceiveMsg(ob->Name(WER) + " hoert gar nicht zu, was Du sagst.",
869 MT_NOTIFICATION, msg_action, 0, this_object());
870 break;
871 case MSG_SENSE_BLOCK:
872 ReceiveMsg(ob->Name(WER) + " kann Dich leider nicht wahrnehmen.",
873 MT_NOTIFICATION, msg_action, 0, this_object());
874 break;
875 case MSG_BUFFER_FULL:
Zesstra62b4a862022-12-23 20:08:16 +0100876 ReceiveMsg(ob->Name(WER) + " moechte gerade nicht gestoert werden. "
MG Mud User88f12472016-06-24 23:31:02 +0200877 "Die Mitteilung ging verloren, denn der Kobold kann sich "
878 "nichts mehr merken!", MT_NOTIFICATION, msg_action,
879 0, this_object());
880 break;
881 default:
882 ReceiveMsg(ob->Name(WER) + " hat Deine Nachricht leider nicht "
883 "mitbekommen.", MT_NOTIFICATION, msg_action, 0, this_object());
884 break;
885 }
886}
887
Zesstra8b5320e2022-02-18 21:10:26 +0100888// aehnlich wie _send(), aber gerufen, wenn die Empfaengerin nicht online ist,
889// aber ein Kobold-Vault deponiert hat und versucht werden soll, dort eine
890// Nachricht zu hinterlegen.
891private void _send_to_kobold(string pluid, string msg, int msg_type,
892 string msg_action, string msg_prefix)
893{
894 int res = KOBOLD->DepositMsg(pluid, msg, msg_type, msg_action,
895 msg_prefix, ME);
896 switch(res) {
897 case MSG_BUFFERED:
898 ReceiveMsg(sprintf("%s ist gerade nicht online, aber Deine Botschaft "
899 "wurde von einem fuer kleinen Kobold aufgeschrieben und er wird "
900 "versuchen, sie %s bei naechster Gelegenheit zu uebermitteln. "
901 "Der Kobold macht Dich darauf aufmerksam, dass er aber keine "
902 "Uebermittlung garantieren kann.",
903 capitalize(pluid), capitalize(pluid)),
904 MT_NOTIFICATION, msg_action, 0, this_object());
905 break;
906 case MSG_BUFFER_FULL:
907 ReceiveMsg(sprintf("%s ist gerade nicht online und leider ist auf "
908 "der Schriftrolle des kleinen Kobolds kein Platz mehr fuer "
909 "Deine Botschaft. Vielleicht schickst Du %s besser einen Brief.",
910 capitalize(pluid), capitalize(pluid)),
911 MT_NOTIFICATION, msg_action, 0, this_object());
912 break;
913 default:
914 ReceiveMsg(sprintf("%s ist gerade nicht online und leider konnte "
915 "sich der kleine Kobold Deine Botschaft nicht merken. "
916 "Vielleicht schickst Du %s besser einen Brief.",
917 capitalize(pluid),capitalize(pluid)),
918 MT_NOTIFICATION, msg_action, 0, this_object());
919 break;
920 }
921}
922
MG Mud User88f12472016-06-24 23:31:02 +0200923// Ausgabe an das Objekt selber und Aufzeichnung in der Kommhistory, falls
924// noetig. Wird bei _ausgehenden_ Nachrichten im eigenen Objekt gerufen, damit
925// die Nachricht ggf. in den Kommhistory erfasst wird.
926// TODO: entfernen, wenn alles Aufrufer ersetzt sind durch ReceiveMsg().
927protected varargs int _recv(object ob, string message, int flag, string indent)
928{
929 write(break_string(message, 78, indent,
930 QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0));
931 if ((flag & MSGFLAG_TELL || flag & MSGFLAG_REMOTE) &&
932 query_once_interactive(ob))
933 {
934 if (flag & MSGFLAG_WHISPER)
935 add_to_tell_history(getuid(ob), 1, 0,
936 "Du fluesterst " + ob->name(WEM) + " aus der Ferne etwas zu.", 0,
937 flag);
938 else
939 add_to_tell_history(getuid(ob), 1, 0, message, indent, flag);
940 }
941 return 1;
942}
943
944// <sender> sollte ein Objekt sein. In seltenen Faellen (z.B.
945// Fehlerbehandlung) ist es jedoch auch mal ein String.
946varargs int Message(string msg, int flag, string indent,
947 string cname, mixed sender)
948{
949 object ti;
950 string verb, reply, *ignore, tin;
951 int em, te;
952 mixed deaf;
953
954 // Bei den Kanaelen 'Debug' und 'Entwicklung' kann man gezielt Bugs
955 // einzelner Magier ignorieren. Dazu wird der Kanalname zum 'verb',
956 // damit 'ignoriere name.debug' funktioniert.
957 if( flag == MSGFLAG_CHANNEL ){
958 if((msg[1..5] == "Debug" || msg[1..11] == "Entwicklung"
959 || msg[1..9]=="Warnungen"))
960 {
961 // Missbrauch der Variable 'ignore' als Zwischenspeicher
962 ignore = regexplode( msg, ":| |\\]" );
963 verb = lower_case(ignore[0][1..]);
964 tin = lower_case(ignore[2]);
965 }
966 else
967 {
968 if(cname)
969 verb=lower_case(cname);
970 else
971 verb=query_verb();
972 if( ti = this_interactive() )
973 {
974 tin = getuid(this_interactive());
975 }
976 else
977 {
978 //falls doch kein Objekt...
979 if (objectp(sender))
980 tin=lower_case(sender->name(RAW)||"<Unbekannt>");
981 }
982 }
983 }
984 else {
985 if( ti = this_interactive() )
986 tin = getuid(this_interactive());
987 verb = query_verb();
988 }
989
990 te = flag & (MSGFLAG_TELL | MSGFLAG_WHISPER);
991
992 // fuer "erwidere"
993 if (ti && (flag & MSGFLAG_TELL || flag & MSGFLAG_REMOTE)) {
994 if (!ti->QueryProp(P_INVIS)||IS_LEARNER(ME)) {
995 if (flag & MSGFLAG_WHISPER)
996 add_to_tell_history(getuid(ti), 0, 1,
997 capitalize((((IS_LEARNER(ti) && !ti->QueryProp(P_INVIS) &&
998 (ti->QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ?
999 ti->QueryProp(P_PRESAY) : "") + ti->name()) || "") +
1000 " fluestert Dir aus der Ferne etwas zu.", 0, flag, 0);
1001 else
1002 add_to_tell_history(getuid(ti), 0, 1, msg, indent, flag, 0);
1003 }
1004 }
1005 // Hoert der Spieler nicht?
1006 em = (ti &&
1007 (te || flag & MSGFLAG_SHOUT) &&
1008 (QueryProp(P_EARMUFFS) &&
1009 (query_wiz_level(ti) < QueryProp(P_EARMUFFS))));
1010 ignore = (pointerp(ignore = QueryProp(P_IGNORE)) ? ignore : ({}));
1011
1012 // Werden der Sender oder das Verb ignoriert?
1013 if(!ti && tin && flag == MSGFLAG_CHANNEL)
1014 {
1015 if((member(ignore, tin) != -1))
1016 {
1017 return MESSAGE_IGNORE_YOU;
1018 }
1019 if(verb && sizeof(filter(ignore, #'check_ignore, verb, tin)) )
1020 {
1021 return MESSAGE_IGNORE_YOU;
1022 }
1023 }
1024 if (ti && (member(ignore, getuid(ti)) != -1)) {
1025 if(te && (IS_LEARNER(ti)||!QueryProp(P_INVIS)))
1026 efun::tell_object(ti, capitalize(name())+
1027 " hoert gar nicht zu, was Du sagst.\n");
1028 return MESSAGE_IGNORE_YOU;
1029 }
1030 if(tin && verb &&
1031 sizeof(filter(ignore, #'check_ignore/*'*/, verb, tin)))
1032 {
1033 if(ti && verb[0..2] != "ruf" && verb[0..3] != "mruf" &&
1034 verb[0..3] != "echo" && verb[0] != '-' && !(flag & MSGFLAG_CHANNEL) )
1035 efun::tell_object(ti, name()+" wehrt \""+verb+"\" ab.\n");
1036 return MESSAGE_IGNORE_VERB;
1037 }
1038 if (flag & MSGFLAG_RTELL) {
1039 int at;
1040
1041 verb = lower_case(old_explode(msg, " ")[0][1..]);
1042 at = member(verb, '@');
1043 /* verb wird hier eh missbraucht, also auch fuer ein intermud-erwidere*/
1044 add_to_tell_history(verb, 0, 1, msg, indent, flag, 0);
1045
1046 if ((member(ignore, verb) >= 0) || (member(ignore,verb[0..at]) >= 0))
1047 return MESSAGE_IGNORE_YOU;
1048 else if (at > 0 && member(ignore, verb[at..]) >= 0)
1049 return MESSAGE_IGNORE_MUD;
1050 }
1051
1052 // Taubheit/Oropax
1053 te |= (flag & MSGFLAG_SAY);
1054
1055 if (QueryProp(P_DEAF) && (flag & MSGFLAG_DEAFCHK) && !(flag & MSGFLAG_CHIST)) {
1056 deaf = QueryProp(P_DEAF);
1057 if (te)
1058 reply = stringp(deaf) ?
1059 capitalize(sprintf(deaf, name())) :
1060 capitalize(name())+" ist momentan leider taub.\n";
1061 }
1062 else if (em)
1063 reply = capitalize(name())+" hat Oropax in den Ohren.\n";
1064
1065 msg = break_string(msg, 78, indent,
1066 (QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0) | BS_LEAVE_MY_LFS);
1067
Zesstra7459f252022-02-23 22:47:26 +01001068 if((QueryProp(P_BUFFER) & KOBOLD_ONLINE) &&
MG Mud User88f12472016-06-24 23:31:02 +02001069 (deaf ||
1070 query_editing(this_object()) ||
1071 query_input_pending(this_object())))
1072 {
1073 deaf = MESSAGE_DEAF;
1074 if(flag & MSGFLAG_CACHE)
1075 {
1076 if(!stringp(reply))
1077 reply = name()+" moechte gerade nicht gestoert werden.\n";
1078
1079 msg = msg[0..<2]+" [" + strftime("%H:%M",time()) + "]\n";
1080
1081 int res = add_to_kobold(msg, 0, 0, 0,
1082 objectp(sender) ? sender : ME);
1083 if(res == MSG_BUFFERED)
1084 {
1085
1086 reply += "Die Mitteilung wurde von einem kleinen Kobold in Empfang "+
1087 "genommen.\nEr wird sie spaeter weiterleiten!";
1088 deaf = MESSAGE_CACHE;
1089 }
1090 else {
1091 reply += "Die Mitteilung ging verloren, denn "+
1092 "der Kobold kann sich nichts mehr merken!";
1093 deaf = MESSAGE_CACHE_FULL;
1094 }
1095 if(ti && (IS_LEARNER(ti)||!QueryProp(P_INVIS)))
1096 efun::tell_object(ti, reply+"\n");
1097 }
1098 return deaf;
1099 }
1100 else if((deaf || em) &&
1101 ( (flag & MSGFLAG_RTELL) ||
1102 (ti && (IS_LEARNER(ti)||!QueryProp(P_INVIS))))) {
1103 if (te && ti)
1104 efun::tell_object(ti, reply);
1105 return MESSAGE_DEAF;
1106 }
1107
1108 _flush_cache(0);
1109 if(te && QueryProp(P_AWAY))
1110 msg = msg[0..<2]+" [" + strftime("%H:%M",time()) + "]\n";
1111
Zesstra1cc6cf32022-02-09 11:49:31 +01001112 if(!objectp(sender) || sender != ME)
Bugfix60f5bc62022-01-21 11:09:56 +01001113 {
Zesstra1cc6cf32022-02-09 11:49:31 +01001114 if (flag & MSGFLAG_SAY)
1115 comm_beep(MA_SAY);
1116 else if (flag & MSGFLAG_TELL)
1117 comm_beep(MA_TELL);
1118 else if (flag & MSGFLAG_CHANNEL)
1119 comm_beep(MA_CHANNEL);
1120 else if (flag & MSGFLAG_SHOUT)
1121 comm_beep(MA_SHOUT);
MG Mud User88f12472016-06-24 23:31:02 +02001122 }
1123 efun::tell_object(ME, msg);
1124 return MESSAGE_OK;
1125}
1126
1127static int ignoriere(string str)
1128{
1129 str = _unparsed_args(1);
1130 mapping ignore=Query(P_IGNORE, F_VALUE);
1131
1132 if (!str)
1133 {
1134 string* ignarr = m_indices(ignore);
1135 if (!sizeof(ignarr))
1136 tell_object(ME, "Du ignorierst niemanden.\n");
1137 else
1138 ReceiveMsg("Du ignorierst:\n"
1139 + break_string(CountUp(map(sort_array(ignarr, #'> ),
1140 #'capitalize )
1141 ) + ".",78),
1142 MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE|MSG_DONT_WRAP,
1143 0,0,this_object());
1144 return 1;
1145 }
1146 // trim spaces from args and convert to lower case.
1147 str = lower_case(trim(str, TRIM_BOTH));
1148
1149 if (member(ignore, str))
1150 {
1151 RemoveIgnore(str);
1152 tell_object(ME, sprintf("Du ignorierst %s nicht mehr.\n", capitalize(str)));
1153 }
1154 else if (sizeof(ignore)>100)
1155 {
1156 tell_object(ME, "Du ignorierst schon genuegend!\n");
1157 }
1158 else if (AddIgnore(str) == 1)
1159 {
1160 tell_object(ME,
1161 sprintf("Du ignorierst jetzt %s.\n", capitalize(str)));
1162 }
1163 else
1164 {
1165 tell_object(ME,
1166 sprintf("'%s' kannst Du nicht ignorieren.\n",str));
1167 }
1168 return 1;
1169}
1170
1171
Zesstra1cc6cf32022-02-09 11:49:31 +01001172private int _alert_filter_flags(int flag, string text)
Bugfix60f5bc62022-01-21 11:09:56 +01001173{
1174 return (flag & QueryProp(P_ALERT));
1175}
1176
Zesstra1cc6cf32022-02-09 11:49:31 +01001177static int _msg_beep(string str)
1178{
1179 int beep_interval;
1180
1181 notify_fail(
1182 "Syntax:\n"
1183 "- klingelton <1 bis 3600 Sekunden>\n"
1184 "- klingelton aus\n"
1185 "- klingelton ein\n"
1186 "- klingelton <+/-><tm / sag / ebenen / ruf / erwaehnung / sonstige / alle / >\n");
1187
1188 if(!sizeof(str))
1189 return 0;
1190 if (regmatch(str,"^[[:alpha:]]", RE_PCRE))
Bugfix60f5bc62022-01-21 11:09:56 +01001191 {
MG Mud User88f12472016-06-24 23:31:02 +02001192 if (str=="aus")
Zesstra1cc6cf32022-02-09 11:49:31 +01001193 SetProp(P_ALERT, QueryProp(P_ALERT) | AL_NO_SOUND);
1194 else if (str=="ein")
1195 SetProp(P_ALERT, QueryProp(P_ALERT) & ~AL_NO_SOUND);
Bugfix60f5bc62022-01-21 11:09:56 +01001196 else
1197 {
1198 mapping flags = ([
Zesstra1cc6cf32022-02-09 11:49:31 +01001199 "tm": MB_TELL, "teilemit": MB_TELL,
1200 "sag": MB_SAY, "sage": MB_SAY,
1201 "ebene": MB_CHANNEL, "ebenen": MB_CHANNEL,
1202 "ruf": MB_SHOUT, "rufe": MB_SHOUT,
Zesstra3a261e52022-02-10 14:00:31 +01001203 "erwaehnung": MB_MENTION, "erwaehnungen": MB_MENTION,
Zesstra1cc6cf32022-02-09 11:49:31 +01001204 "sonstige": MB_MISC, "sonstiges": MB_MISC,
1205 "alle": MB_ALL, "alles": MB_ALL,
1206 ]);
Bugfix60f5bc62022-01-21 11:09:56 +01001207 foreach(string part : explode(str, " ") - ({""}))
1208 {
1209 if(!(part[1..] in flags)) continue;
1210 if(part[0] == '+')
1211 {
1212 SetProp(P_ALERT,
1213 QueryProp(P_ALERT) | flags[part[1..]]);
1214 }
1215 else if(part[0] == '-')
1216 {
1217 SetProp(P_ALERT,
1218 QueryProp(P_ALERT) & ~ flags[part[1..]]);
1219 }
1220 }
1221 }
MG Mud User88f12472016-06-24 23:31:02 +02001222 }
Zesstra1cc6cf32022-02-09 11:49:31 +01001223 else
1224 {
1225 beep_interval = to_int(str);
1226 if(beep_interval >= 0)
1227 {
1228 SetProp(P_MESSAGE_BEEP, beep_interval);
1229 }
1230 }
MG Mud User88f12472016-06-24 23:31:02 +02001231
Zesstra593b2c72019-11-27 23:37:03 +01001232 beep_interval=({int})QueryProp(P_MESSAGE_BEEP);
Bugfix60f5bc62022-01-21 11:09:56 +01001233 mapping text = ([
1234 MB_SAY: "sage",
1235 MB_TELL: "teile mit",
1236 MB_CHANNEL: "Ebenenmeldungen",
Zesstra3a261e52022-02-10 14:00:31 +01001237 MB_MENTION: "Erwaehnungen",
Zesstra1cc6cf32022-02-09 11:49:31 +01001238 MB_SHOUT: "rufe",
1239 MB_MISC: "sonstige",]);
1240 string types = CountUp(map(filter(m_indices(text), #'_alert_filter_flags), text));
Bugfix60f5bc62022-01-21 11:09:56 +01001241 if(!sizeof(types))
1242 {
1243 types = "nichts";
1244 }
1245 ReceiveNotify(
1246 "Klingelton bei "
1247 + types
Zesstra1cc6cf32022-02-09 11:49:31 +01001248 + (beep_interval ? ", alle " + beep_interval + " Sekunden." : ", immer.")
1249 + (QueryProp(P_ALERT) & AL_NO_SOUND ? " Allerdings sind Toene insgesamt "
1250 "bei Dir abgeschaltet. (\'hilfe ton\')" : ""),
Bugfix60f5bc62022-01-21 11:09:56 +01001251 query_verb());
MG Mud User88f12472016-06-24 23:31:02 +02001252 return 1;
1253}
1254
1255static int _msg_prepend(string str) {
MG Mud User88f12472016-06-24 23:31:02 +02001256 notify_fail("Syntax: senderwiederholung ein/aus\n");
1257 if (stringp(str)) {
1258 if (str=="aus")
1259 SetProp(P_MESSAGE_PREPEND,1);
1260 else if (str=="ein")
1261 SetProp(P_MESSAGE_PREPEND,0);
1262 else return 0;
1263 }
1264
Bugfixb1d9b4d2021-09-14 20:07:04 +02001265 ReceiveNotify("Senderwiederholung bei Mitteilungen: "+
Zesstra04f613c2019-11-27 23:32:54 +01001266 (({int})QueryProp(P_MESSAGE_PREPEND) ? "aus" : "ein")+".",
MG Mud User88f12472016-06-24 23:31:02 +02001267 query_verb());
1268
1269 return 1;
1270}
1271
1272static int _communicate(mixed str, int silent)
1273{
1274 string verb;
1275 string myname;
1276 string msg;
1277
1278 if (!str || extern_call()) str=_unparsed_args()||"";
1279 /* str=_unparsed_args()||""; */
1280 verb = query_verb();
1281 if(stringp(verb) && verb[0] == '\'') str = verb[1..] + " " + str;
1282 if (str==""||str==" "||!str)
1283 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001284 ReceiveNotify("Was willst Du sagen?",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001285 return 1;
1286 }
1287 msg=permutate(str);
1288
1289 myname=(((QueryProp(P_INVIS)||!IS_LEARNER(ME))||
1290 !(QueryProp(P_CAN_FLAGS)&CAN_PRESAY)?
1291 "":QueryProp(P_PRESAY))+name())||"";
1292
1293 // an alles im Raum senden. (MT_LISTEN, weil dies gesprochene Kommunikation
1294 // ist, keine MT_COMM)
Zesstrabd1236a2022-02-09 22:35:59 +01001295 send_room(environment(), msg, MT_LISTEN|MSG_ALERT, MA_SAY,
MG Mud User88f12472016-06-24 23:31:02 +02001296 capitalize(myname)+" sagt: ", ({this_object()}) );
1297
1298 if(!silent)
1299 {
1300 ReceiveMsg(msg, MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE,
1301 MA_SAY, "Du sagst: ", ME);
1302 }
1303 return 1;
1304}
1305
1306static int _shout_to_all(mixed str)
1307{
1308 string pre, myname, realname, wizards_msg, players_msg;
1309 string wizard_prefix, player_prefix;
1310 int chars;
1311
1312 if (!(str=_unparsed_args()))
1313 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001314 ReceiveNotify("Was willst Du rufen?",MA_SHOUT);
MG Mud User88f12472016-06-24 23:31:02 +02001315 return 1;
1316 }
1317 chars=sizeof(str)/2;
1318 if (chars<4) chars=4;
1319 pre = (!IS_LEARNER(ME) ||
1320 QueryProp(P_INVIS) ||
1321 !(QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ? "" : QueryProp(P_PRESAY);
1322 realname = capitalize((pre + capitalize(getuid()))||"");
1323 myname = capitalize(pre + name()||"");
1324 if (QueryProp(P_INVIS))
1325 realname = "("+realname+")";
1326
1327 wizards_msg = permutate(str);
1328 wizard_prefix = myname+" ruft: ";
1329
1330 if(QueryProp(P_FROG)) {
1331 players_msg = "Quaaak, quaaaaak, quuuuaaaaaaaaaaaaaaaaaaaak !!";
1332 player_prefix = myname+" quakt: ";
1333 }
1334 else {
1335 players_msg = wizards_msg;
1336 player_prefix = wizard_prefix;
1337 }
1338
1339 if(!IS_LEARNER(this_player()))
1340 {
1341 if(QueryProp(P_GHOST)) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001342 ReceiveNotify("So ganz ohne Koerper bekommst Du keinen Ton heraus.",
MG Mud User88f12472016-06-24 23:31:02 +02001343 MA_SHOUT);
1344 return 1;
1345 }
1346 if (QueryProp(P_SP) <(chars+20))
1347 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001348 ReceiveNotify("Du musst erst wieder magische Kraefte sammeln.",
MG Mud User88f12472016-06-24 23:31:02 +02001349 MA_SHOUT);
Bugfixb1d9b4d2021-09-14 20:07:04 +02001350 ReceiveNotify("Tip: Benutz doch mal die Ebenen (Hilfe dazu mit 'hilfe "
MG Mud User88f12472016-06-24 23:31:02 +02001351 "Ebenen').", MA_SHOUT);
1352 return 1;
1353 }
1354 SetProp(P_SP, QueryProp(P_SP) - chars - 20);
1355 }
1356
1357 ReceiveMsg(wizards_msg, MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE,
Zesstrabd1236a2022-02-09 22:35:59 +01001358 MA_SHOUT, "Du rufst: ", ME);
MG Mud User88f12472016-06-24 23:31:02 +02001359
1360 foreach ( object ob : users()-({this_object()}) )
1361 if ( IS_LEARNER(ob) )
Zesstrabd1236a2022-02-09 22:35:59 +01001362 ob->ReceiveMsg(wizards_msg, MT_LISTEN|MT_FAR|MSG_ALERT, MA_SHOUT,
1363 wizard_prefix, this_object());
MG Mud User88f12472016-06-24 23:31:02 +02001364 else
Zesstrabd1236a2022-02-09 22:35:59 +01001365 ob->ReceiveMsg(players_msg, MT_LISTEN|MT_FAR|MSG_ALERT, MA_SHOUT,
1366 player_prefix, this_object());
MG Mud User88f12472016-06-24 23:31:02 +02001367
1368 return 1;
1369}
1370
1371varargs int _tell(string who, mixed msg)
1372{
1373 object ob;
1374 string away,myname,ret;
MG Mud User88f12472016-06-24 23:31:02 +02001375 string *xname;
1376 int i,visflag;
1377
1378 if (extern_call() && this_interactive()!=ME) return 1;
1379 if (!who || !msg) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001380 ReceiveNotify("Was willst Du mitteilen?",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001381 return 1;
1382 }
1383
1384 if(who == ERWIDER_PARAM)
1385 {
1386 if (!last_comm_partner)
1387 {
1388 _notify_fail("Du hast aber noch keine Mitteilungen erhalten, auf die "
1389 "Du was erwidern\nkoenntest.\n");
1390 return 0;
1391 }
1392 who=last_comm_partner;
1393 }
1394
1395 // teile .x mit teilt bisherigen Gespraechspartnern etwas mit.
1396 if (who == ".")
1397 who = ".1";
1398
1399 if ( sscanf(who, ".%d", i) == 1 ) {
1400 if(i > 0 && i <= sizeof(commreceivers))
1401 who = commreceivers[i-1];
1402 else {
1403 _notify_fail("So vielen Leuten hast Du noch nichts mitgeteilt!\n");
1404 return 0;
1405 }
1406 }
1407
1408 xname = explode(who, "@");
1409
Zesstrabd1236a2022-02-09 22:35:59 +01001410 if (sizeof(xname) == 2)
MG Mud User88f12472016-06-24 23:31:02 +02001411 {
1412 if ( QueryProp(P_QP) )
1413 {
Zesstra04f613c2019-11-27 23:32:54 +01001414 if (ret=({string})INETD->_send_udp(xname[1],
MG Mud User88f12472016-06-24 23:31:02 +02001415 ([ REQUEST: "tell",
1416 RECIPIENT: xname[0],
1417 SENDER: getuid(ME),
1418 DATA: msg ]), 1))
1419 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001420 ReceiveNotify(ret, MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001421 }
1422 else
1423 {
1424 write("Nachricht abgeschickt.\n");
1425 add_to_tell_history(who, 1, 0, msg,
Zesstraa31cd5c2016-12-17 20:11:07 +01001426 "Du teilst " + capitalize(who) + " mit: ", MSGFLAG_RTELL, 1);
MG Mud User88f12472016-06-24 23:31:02 +02001427 }
1428 }
1429 else
1430 write("Du hast nicht genug Abenteuerpunkte, um Spielern in anderen \n"
1431 "Muds etwas mitteilen zu koennen.\n");
1432 return 1;
1433 }
1434
Zesstra8b5320e2022-02-18 21:10:26 +01001435 string|int lname = lower_case(who);
1436 if (!ob=find_player(lname))
MG Mud User88f12472016-06-24 23:31:02 +02001437 {
Zesstra8b5320e2022-02-18 21:10:26 +01001438 lname = match_living(lname, 0);
1439 if (!stringp(lname))
1440 {
1441 switch(lname)
1442 {
MG Mud User88f12472016-06-24 23:31:02 +02001443 case -1:
Bugfixb1d9b4d2021-09-14 20:07:04 +02001444 ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001445 return 1;
1446 case -2:
Zesstra8b5320e2022-02-18 21:10:26 +01001447 // check KOBOLD
Zesstra7459f252022-02-23 22:47:26 +01001448 ob = load_object(KOBOLD);
Zesstra8b5320e2022-02-18 21:10:26 +01001449 lname = ({string|int})ob->find_player(lower_case(who));
1450 if (lname == -1) {
1451 ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
1452 return 1;
1453 }
1454 else if (!stringp(lname)) {
1455 ReceiveNotify("Kein solcher Spieler (online)!",MA_TELL);
1456 return 1;
1457 }
MG Mud User88f12472016-06-24 23:31:02 +02001458 }
Zesstra8b5320e2022-02-18 21:10:26 +01001459 // jetzt ist ob der KOBOLD und lname die UID eines Spielers.
1460 }
1461 // Wenn wir noch kein ob haben, sollte lname jetzt aber durch das
1462 // match_living() der Name eines Livings sein, dessen Objekt wir noch
1463 // brauchen.
1464 if (!ob)
1465 ob = find_player(lname) || find_living(lname);
MG Mud User88f12472016-06-24 23:31:02 +02001466 if(!ob) {
Zesstra8b5320e2022-02-18 21:10:26 +01001467 ReceiveNotify("Kein solcher Spieler (online)!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001468 return 1;
1469 }
1470 }
1471
Zesstra8b5320e2022-02-18 21:10:26 +01001472 if(QueryProp(P_INVIS))
1473 {
MG Mud User88f12472016-06-24 23:31:02 +02001474 if(!IS_LEARNER(ob))
1475 myname = name();
1476 else
1477 myname="("+
1478 ((QueryProp(P_CAN_FLAGS) & CAN_PRESAY)?QueryProp(P_PRESAY):"")+
1479 capitalize(getuid()) + ")";
1480 }
1481 else
1482 myname=((IS_LEARNER(ME) && (QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ?
Bugfix45f88ce2017-03-06 14:41:56 +01001483 QueryProp(P_PRESAY):"") + capitalize(getuid(ME));
Zesstra8b5320e2022-02-18 21:10:26 +01001484 if (myname && sizeof(myname))
1485 myname=capitalize(myname);
1486
1487 // Wir haben Zielobjekt und unseren eigenen Namen. Erstmal an Empfaenger
1488 // senden.
1489 if (living(ob))
1490 _send(ob, permutate(msg), MT_COMM|MT_FAR|MSG_ALERT, MA_TELL,
1491 myname + " teilt Dir mit: ");
1492 else
1493 _send_to_kobold(lname, permutate(msg), MT_COMM|MT_FAR|MSG_ALERT, MA_TELL,
1494 myname + " teilt Dir mit: ");
MG Mud User88f12472016-06-24 23:31:02 +02001495
1496 // dann evtl. noch an Absender ausgeben...
Zesstra8b5320e2022-02-18 21:10:26 +01001497 visflag = !ob->QueryProp(P_INVIS);
1498 if (visflag || IS_LEARNER(this_player()))
1499 _recv(ob, msg, MSGFLAG_TELL, "Du teilst " + capitalize(lname) + " mit: ");
MG Mud User88f12472016-06-24 23:31:02 +02001500 // oder irgendwas anderes an den Absender ausgeben...
1501 if (!visflag && interactive(ob))
Zesstra8b5320e2022-02-18 21:10:26 +01001502 ReceiveNotify("Kein solcher Spieler online!",MA_TELL);
Zesstra04f613c2019-11-27 23:32:54 +01001503 else if (away = ({string})ob->QueryProp(P_AWAY))
Zesstra8b5320e2022-02-18 21:10:26 +01001504 ReceiveMsg( break_string( away, 78, capitalize(lname)
MG Mud User88f12472016-06-24 23:31:02 +02001505 + " ist gerade nicht da: ", BS_INDENT_ONCE ),
1506 MT_NOTIFICATION|MSG_DONT_WRAP|MSG_DONT_IGNORE,
1507 MA_TELL, 0, this_object());
1508 else if (interactive(ob) && (i=query_idle(ob))>=600)
1509 { //ab 10 Mins
1510 if (i<3600)
1511 away=time2string("%m %M",i);
1512 else
1513 away=time2string("%h %H und %m %M",i);
1514
Bugfixb1d9b4d2021-09-14 20:07:04 +02001515 ReceiveNotify(sprintf("%s ist seit %s voellig untaetig.",
Zesstra8b5320e2022-02-18 21:10:26 +01001516 capitalize(lname),away),
MG Mud User88f12472016-06-24 23:31:02 +02001517 MA_TELL);
1518 }
1519
1520 return 1;
1521}
1522
1523static int _teile(string str)
1524{
1525 string who, message;
1526 if (!(str=_unparsed_args())) return 0;
1527 if (sscanf(str, "%s mit %s", who, message) == 2)
1528 return _tell(who, message,1);
1529 return 0;
1530}
1531static int _teile_mit_alias(string str)
1532{
1533 str = _unparsed_args(), TRIM_LEFT;
1534 if (!str) return 0;
1535 str = trim(str, TRIM_LEFT);
1536 // Ziel muss min. 2 Buchstaben haben (.<nr>)
1537 if (sizeof(str) < 4) return 0;
1538 int pos = strstr(str, " ");
1539 if (pos >= 2)
1540 return _tell(str[..pos-1], str[pos+1..]);
1541 return 0;
1542}
1543
1544static int _erzaehle(string str)
1545{
1546 string who, message;
1547
1548 if (!(str=_unparsed_args())) return 0;
1549 if (sscanf(str, "%s %s", who, message) == 2)
1550 return _tell(who, message,1);
1551 return 0;
1552}
1553
1554static int _whisper(string str)
1555{
1556 object ob;
1557 string who;
1558 string msg;
1559 string myname;
1560
1561 if (!(str=_unparsed_args()) ||
1562 (sscanf(str, "%s zu %s", who, msg) != 2 &&
1563 sscanf(str, "%s %s", who, msg) !=2 )) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001564 ReceiveNotify("Was willst Du wem zufluestern?",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001565 return 1;
1566 }
Zesstra6e88b6a2019-11-08 00:25:39 +01001567 who = lower_case(who);
MG Mud User88f12472016-06-24 23:31:02 +02001568 if (!(ob = present(who, environment(this_player()))) || !living(ob)) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001569 ReceiveNotify(capitalize(who)+" ist nicht in diesem Raum.",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001570 return 1;
1571 }
1572
1573 myname = capitalize((((IS_LEARNER(ME) &&
1574 !QueryProp(P_INVIS) &&
1575 (QueryProp(P_CAN_FLAGS) & CAN_PRESAY))?
1576 QueryProp(P_PRESAY) : "") + name()) || "");
1577
1578 _send(ob, permutate(msg), MT_LISTEN|MSG_DONT_STORE,
Bugfixdbdbed52022-01-21 11:14:35 +01001579 MA_SAY, myname + " fluestert Dir zu: ");
MG Mud User88f12472016-06-24 23:31:02 +02001580 send_room(environment(),
1581 myname + " fluestert " + ob->name(WEM, 1) + " etwas zu.",
1582 MT_LISTEN|MSG_DONT_STORE, MA_SAY, 0, ({this_object(),ob}));
1583
1584 _recv(ob, msg, MSGFLAG_WHISPER, "Du fluesterst " + ob->name(WEM) + " zu: ");
1585
1586
1587 return 1;
1588}
1589
1590static int _remote_whisper(string str)
1591{
1592 /* Wie 'teile mit', nur mit MSGFLAG_WHISPER. Dadurch wird der Inhalt der
1593 Nachricht nicht in der tell_history verewigt. */
1594
1595 object ob;
Zesstra8b5320e2022-02-18 21:10:26 +01001596 string who;
MG Mud User88f12472016-06-24 23:31:02 +02001597 string msg;
1598 string myname;
1599
1600 if (!(str=_unparsed_args()) ||
1601 (sscanf(str, "%s zu %s", who, msg) != 2 &&
1602 sscanf(str, "%s %s", who, msg) !=2 )) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001603 ReceiveNotify("Was willst Du wem aus der Ferne zufluestern?",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001604 return 1;
1605 }
1606
Zesstra8b5320e2022-02-18 21:10:26 +01001607 string|int lname = lower_case(who);
1608 if (!ob=find_player(lname))
MG Mud User88f12472016-06-24 23:31:02 +02001609 {
Zesstra8b5320e2022-02-18 21:10:26 +01001610 lname = match_living(lname, 0);
1611 if (!stringp(lname))
1612 {
1613 switch(lname)
1614 {
MG Mud User88f12472016-06-24 23:31:02 +02001615 case -1:
Zesstra8b5320e2022-02-18 21:10:26 +01001616 ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001617 return 1;
1618 case -2:
Zesstra8b5320e2022-02-18 21:10:26 +01001619 // rfluester benutzt keinen KOBOLD.
1620 ReceiveNotify("Kein solcher Spieler!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001621 return 1;
1622 }
Zesstra8b5320e2022-02-18 21:10:26 +01001623 }
1624 // lname sollte nun eindeutig sein.
1625 ob = find_player(lname) || find_living(lname);
1626 if(!ob) {
1627 ReceiveNotify("Kein solcher Spieler online!",MA_TELL);
MG Mud User88f12472016-06-24 23:31:02 +02001628 return 1;
1629 }
1630 }
Zesstra8b5320e2022-02-18 21:10:26 +01001631
MG Mud User88f12472016-06-24 23:31:02 +02001632 if (environment(ob) == environment()) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001633 ReceiveNotify("Wenn jemand neben Dir steht, nimm fluester.",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001634 return 1;
1635 }
1636
1637 myname = capitalize((((IS_LEARNER(ME) &&
1638 !QueryProp(P_INVIS) &&
1639 (QueryProp(P_CAN_FLAGS) & CAN_PRESAY))?
1640 QueryProp(P_PRESAY) : "") + name()) || "");
1641
1642 // An Empfaenger senden.
Zesstrabd1236a2022-02-09 22:35:59 +01001643 _send(ob, permutate(msg), MT_COMM|MT_FAR|MSG_DONT_STORE,
1644 MA_EMOTE, myname + " fluestert Dir aus der Ferne zu: ");
MG Mud User88f12472016-06-24 23:31:02 +02001645 // wenn Empfaenger invis und wir kein Magier , ggf. fakefehler ausgeben.
1646 if (ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player())) {
Zesstra8b5320e2022-02-18 21:10:26 +01001647 ReceiveNotify("Kein solcher Spieler online!",MA_EMOTE);
MG Mud User88f12472016-06-24 23:31:02 +02001648 return 1;
1649 }
1650 // sonst eigene Meldung via _recv() ausgeben.
1651 else
1652 _recv(ob, msg, MSGFLAG_WHISPER | MSGFLAG_REMOTE,
1653 "Du fluesterst " + ob->name(WEM) + " aus der Ferne zu: ");
1654
1655 return 1;
1656}
1657
1658static int _converse(string arg)
1659{
Bugfixb1d9b4d2021-09-14 20:07:04 +02001660 ReceiveNotify("Mit '**' wird das Gespraech beendet.",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001661 if (stringp(arg) && strstr(arg, "-s") == 0)
1662 input_to("_converse_more", INPUT_PROMPT, "]", 1);
1663 else
1664 input_to("_converse_more", INPUT_PROMPT, "]", 0);
1665 return 1;
1666}
1667
1668static int _converse_more(mixed str, int silent)
1669{
1670 if (str == "**") {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001671 ReceiveNotify("Ok.",MA_SAY);
MG Mud User88f12472016-06-24 23:31:02 +02001672 return 0;
1673 }
1674
1675 if(str != "")
1676 _communicate(str, silent);
1677
1678 input_to("_converse_more", INPUT_PROMPT, "]", silent);
1679 return 1;
1680}
1681
1682private int is_learner(object o) { return IS_LEARNER(o); }
1683
1684static int _shout_to_wizards(mixed str)
1685{
MG Mud User88f12472016-06-24 23:31:02 +02001686 string myname;
MG Mud User88f12472016-06-24 23:31:02 +02001687
1688 str = _unparsed_args();
1689 if (!str||!sizeof(str)) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001690 ReceiveNotify("Was willst Du den Magiern zurufen?",MA_SHOUT);
MG Mud User88f12472016-06-24 23:31:02 +02001691 return 1;
1692 }
1693 // Kontrollzeichen rausfiltern.
1694 str = regreplace(str,"[[:cntrl:]]","",RE_PCRE|RE_GLOBAL);
1695 myname = capitalize(getuid(this_object()));
1696 if (!IS_LEARNER(this_object()))
1697 _recv(0, str, MSGFLAG_MECHO, "Du teilst allen Magiern mit: ");
1698
1699 // mrufe ist nicht ignorierbar, da es nur fuer schwere Probleme gedacht ist.
1700 filter(users(), #'is_learner)->ReceiveMsg(str,
Zesstrabd1236a2022-02-09 22:35:59 +01001701 MT_COMM|MT_FAR|MSG_DONT_IGNORE|MSG_DONT_STORE|MSG_ALERT,
MG Mud User88f12472016-06-24 23:31:02 +02001702 MA_SHOUT, myname+" an alle Magier: ", this_object());
1703
1704 return 1;
1705}
1706
1707static int _echo(string str) {
1708 if (!IS_SEER(ME) || (!IS_LEARNER(ME)
1709 && !(QueryProp(P_CAN_FLAGS) & CAN_ECHO)))
1710 return 0;
1711
1712 if (!(str=_unparsed_args())) {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001713 ReceiveNotify("Was moechtest Du 'echoen'?", 0);
MG Mud User88f12472016-06-24 23:31:02 +02001714 return 1;
1715 }
1716
1717 if (!IS_LEARNER(this_interactive()))
1718 {
1719 if (QueryProp(P_GHOST))
1720 {
1721 _notify_fail("Ohne Koerper fehlt Dir dazu die noetige magische Kraft.\n");
1722 return 0;
1723 }
1724 if (QueryProp(P_SP)<ECHO_COST)
1725 {
1726 _notify_fail("Du musst erst wieder magische Kraefte sammeln.\n");
1727 return 0;
1728 }
1729 SetProp(P_SP,QueryProp(P_SP)-ECHO_COST);
1730 str=">\b"+str;
1731 log_file("ARCH/ECHO_SEHER", sprintf("%s %s: %s\n", dtime(time()), getuid(),
1732 str));
1733 }
1734 // An den Raum senden. Typ ist MT_COMM, aber das Echo soll weder in der
1735 // Kommhistory noch im Kobold landen.
1736 send_room(environment(ME), str, MT_COMM|MSG_DONT_STORE|MSG_DONT_BUFFER,
1737 MA_UNKNOWN, 0, 0);
1738 return 1;
1739}
1740
1741// Dient als Verteidigung gegen Leute, die eher unbedacht reinschreiben, nicht
1742// gegen Leute, die da absichtlich reinschreiben. Die werden geteert
1743// und gefedert.
1744static string *_set_ignore(mixed arg)
1745{
1746 raise_error("Direktes Setzen von P_IGNORE ist nicht erlaubt. "
1747 "Benutze AddIgnore/RemoveIgnore()!\n");
1748}
1749// Kompatibiltaet zum alten Ignore: Array von Indices liefern. Aendert aber
1750// nix dran, dass alle TestIgnore() & Co benutzen sollen.
1751static string *_query_ignore() {
1752 mixed ign=Query(P_IGNORE, F_VALUE);
1753 if (mappingp(ign))
1754 return m_indices(ign);
1755 return ({});
1756}
1757
1758public int AddIgnore(string ign) {
1759 // Einige strings sind nicht erlaubt, z.B. konsekutive .
1760 if (!sizeof(ign)
1761 || regmatch(ign,"[.]{2,}",RE_PCRE)
1762 || regmatch(ign," ",RE_PCRE)
1763 || sizeof(explode(ign,"."))>3)
1764 return 0;
1765
1766 mapping ignores=Query(P_IGNORE, F_VALUE);
1767 ignores[ign]=time();
1768 // kein Set() noetig.
1769 return 1;
1770}
1771
1772public int RemoveIgnore(string ign)
1773{
1774 mapping ignores=Query(P_IGNORE,F_VALUE);
1775 m_delete(ignores,ign);
1776 // Kein Set() noetig
1777 return 1;
1778}
1779
1780static int _query_intermud()
1781{
1782 mixed tmp;
1783 return member(pointerp(tmp=Query(P_CHANNELS))?tmp:({}), "Intermud") > -1;
1784}
1785
1786
1787int erwidere(string str)
1788{
1789 str=_unparsed_args();
1790 if (!str) return 0;
1791 return _tell(ERWIDER_PARAM, str ,1);
1792}
1793
1794static int tmhist(string str)
1795{
1796
1797 if (str == "aus") {
1798 tell_history_enabled = TELLHIST_DISABLED;
1799 write("Ok, es wird nichts mehr gespeichert.\n");
1800 if (sizeof(tell_history)) {
Zesstra996bafe2022-02-14 22:42:39 +01001801 clear_tell_history(1);
MG Mud User88f12472016-06-24 23:31:02 +02001802 write("Deine Mitteilungsgeschichte wurde geloescht.\n");
1803 }
1804 return 1;
1805 }
Zesstra996bafe2022-02-14 22:42:39 +01001806 if (str == "loeschen")
1807 {
1808 if (sizeof(tell_history)) {
1809 clear_tell_history(1);
1810 write("Deine Mitteilungsgeschichte wurde geloescht.\n");
1811 }
1812 else
1813 write("Deine Mitteilungsgeschichte war schon leer.\n");
1814 return 1;
1815 }
MG Mud User88f12472016-06-24 23:31:02 +02001816
1817 if (str == "namen") {
1818 int flag;
1819 tell_history_enabled = TELLHIST_NO_MESSAGE;
1820 write("Ok, die Namen zukuenftiger Gespraechspartner werden gespeichert.\n");
1821 foreach (string uid, struct chat_s chat: tell_history)
1822 if (pointerp(chat->msgbuf)) {
1823 chat->msgbuf = 0;
1824 chat->ptr = 0;
1825 flag = 1;
1826 }
1827 if (flag)
1828 write("Der Inhalt Deiner Mitteilungen wurde geloescht.\n");
1829 return 1;
1830 }
1831
1832 if (str == "ein" || str == "an") {
1833 tell_history_enabled = TELLHIST_ENABLED;
1834 write("Ok, zukuenftige Mitteilungen werden gespeichert.\n");
1835 return 1;
1836 }
1837
MG Mud User88f12472016-06-24 23:31:02 +02001838 if (str == "langlebig") {
1839 tell_history_enabled = TELLHIST_LONGLIFE;
1840 write("Ok, zukuenftige Mitteilungen werden jeweils bis zum naechsten "
1841 "Ende/Crash/\nReboot gespeichert.\n");
1842 return 1;
1843 }
MG Mud User88f12472016-06-24 23:31:02 +02001844
1845 if (str == "status") {
1846 switch (tell_history_enabled) {
1847 case TELLHIST_DISABLED:
1848 write("Die Namen Deiner Gespraechspartner werden nicht gespeichert.\n");
1849 break;
1850 case TELLHIST_NO_MESSAGE:
1851 write("Die Namen Deiner Gespraechspartner werden gespeichert.\n");
1852 break;
1853 case TELLHIST_ENABLED:
1854 write("Deine Mitteilungen werden gespeichert.\n");
1855 break;
MG Mud User88f12472016-06-24 23:31:02 +02001856 case TELLHIST_LONGLIFE:
1857 write("Deine Mitteilungen werden jeweils bis zum naechsten Ende/"
1858 "Crash/Reboot\ngespeichert.\n");
1859 break;
MG Mud User88f12472016-06-24 23:31:02 +02001860 }
1861 return 1;
1862 }
1863
1864 if (tell_history_enabled == TELLHIST_DISABLED) {
1865 _notify_fail("Deine Gespraechspartner werden nicht gespeichert.\n");
1866 return 0;
1867 }
1868
1869 if (!sizeof(tell_history)) {
1870 _notify_fail("Du hast noch keinem etwas mitgeteilt "
1871 "und noch keine Mitteilungen erhalten.\n");
1872 return 0;
1873 }
1874
1875 if (str && sizeof(str)) {
1876
1877 if (tell_history_enabled < TELLHIST_ENABLED) {
1878 _notify_fail("Der Inhalt Deiner Mitteilungen wird nicht gespeichert.\n");
1879 return 0;
1880 }
1881
1882 string uid;
1883 if (member(tell_history, str)) {
1884 // Name gewuenscht, da der String in der History vorkommt.
1885 uid = str;
1886 }
1887 else {
1888 // evtl. ne Zahl angegeben.
1889 int i;
1890 string *partners = sorted_commpartners(0);
1891 if ((i = to_int(str) - 1) >= 0 && i < sizeof(partners))
1892 uid = partners[i];
1893 else {
1894 notify_fail("Mit so vielen Leuten hast Du nicht gesprochen!\n");
1895 return 0;
1896 }
1897 }
1898
1899 mixed *data = tell_history[uid]->msgbuf;
1900 if (!data) {
1901 _notify_fail(
1902 "Der Inhalt dieser Mitteilung ist nicht (mehr) gespeichert.\n");
1903 return 0;
1904 }
1905
1906 int ptr = tell_history[uid]->ptr;
1907
1908 More(sprintf("%@s", map(data[ptr..MAX_SAVED_MESSAGES-1] +
1909 data[0..ptr-1],
Zesstra7459f252022-02-23 22:47:26 +01001910 function string (struct kobold_msg_s msg) {
MG Mud User88f12472016-06-24 23:31:02 +02001911 if (!structp(msg)) return "";
Zesstra3a261e52022-02-10 14:00:31 +01001912 return break_string(terminal_colour(msg->msg, colourmap)
Zesstra7459f252022-02-23 22:47:26 +01001913 + " ["
1914 + strftime("%H:%M:%S",msg->timestamp) + "]", 78,
MG Mud User88f12472016-06-24 23:31:02 +02001915 msg->prefix || "", msg->prefix ? BS_LEAVE_MY_LFS : 0);
1916 } ) ) );
1917 return 1;
1918 }
1919
1920 string history = "Folgende Gespraeche hast Du bereits gefuehrt:\n";
1921 int i;
1922 foreach (string uid : sorted_commpartners(0) ) {
1923 int j;
1924 struct chat_s chat = tell_history[uid];
1925 history += sprintf("%2d.%-4s %s %-11s %d gesendet/%d empfangen\n", ++i,
1926 ((j=member(commreceivers,uid))>-1 ? sprintf("/%2d.",j+1) : ""),
1927 strftime("%a, %e.%m.%y",chat->time_last_msg),
1928 capitalize(chat->uid), chat->sentcount, chat->recvcount);
1929 }
1930
1931 More(history);
1932
1933 return 1;
1934}
1935
1936static mixed _query_localcmds()
1937{
1938 return ({
1939 ({"kobold", "cmd_kobold",0,0}),
1940 ({"sag","_communicate",0,0}),
1941 ({"sage","_communicate",0,0}),
1942 ({"'","_communicate",1,0}),
1943 ({"mruf","_shout_to_wizards",0,0}),
1944 ({"mrufe","_shout_to_wizards",0,0}),
1945 ({"ruf","_shout_to_all",0,0}),
1946 ({"rufe","_shout_to_all",0,0}),
1947 ({"erzaehl","_erzaehle",0,0}),
1948 ({"erzaehle","_erzaehle",0,0}),
1949 ({"teil","_teile",0,0}),
1950 ({"teile","_teile",0,0}),
1951 ({"tm","_teile_mit_alias",0,0}),
1952 ({"fluester","_whisper",0,0}),
1953 ({"fluestere","_whisper",0,0}),
1954 ({"rfluester","_remote_whisper",0,0}),
1955 ({"rfluestere","_remote_whisper",0,0}),
1956 ({"gespraech","_converse",0,0}),
1957 ({"echo","_echo",0,0}),
1958 ({"ignorier","ignoriere",0,0}),
1959 ({"ignoriere","ignoriere",0,0}),
1960 ({"tmhist","tmhist",0,0}),
1961 ({"erwider","erwidere",0,0}),
1962 ({"erwidere","erwidere",0,0}),
1963 ({"klingelton","_msg_beep",0,0}),
1964 ({"senderwiederholung","_msg_prepend",0,0}),
1965 ({"report","set_report",0,0}),
1966 })+channel::_query_localcmds();
1967}
1968
1969private string *sorted_commpartners(int reversed) {
1970 return sort_array(m_indices(tell_history),
1971 function int (string uid1, string uid2) {
1972 if (reversed)
1973 return tell_history[uid1]->time_last_msg >
1974 tell_history[uid2]->time_last_msg;
1975 else
1976 return tell_history[uid1]->time_last_msg <=
1977 tell_history[uid2]->time_last_msg;
1978 } );
1979}
1980
Zesstra0712bac2020-06-12 09:41:24 +02001981// Setzt den Prompt eines Interactives. Gerufen bei Objekterstellung,
1982// Reconnect und bei Magiern, wenn diese ihren Prompt oder ihr aktuelles
1983// Verzeichnis aendern.
MG Mud User88f12472016-06-24 23:31:02 +02001984static void modify_prompt() {
1985 string text = Query(P_PROMPT, F_VALUE);
1986
1987 if ( !stringp(text) || !sizeof(text) )
1988 text = "> ";
1989 else {
1990 string path = Query(P_CURRENTDIR, F_VALUE);
1991 if (stringp(path) && sizeof(path))
1992 text = regreplace(text,"\\w",path,0); // Pfad einsetzen
1993 }
1994 configure_interactive(this_object(), IC_PROMPT, text);
1995}
1996
1997// Prueft auf Ingoriereeintraege.
1998// Rueckgabe: 0 (nicht ignoriert) oder MSG_IGNORED
MG Mud User88f12472016-06-24 23:31:02 +02001999public int TestIgnore(string|string* srcnames)
MG Mud User88f12472016-06-24 23:31:02 +02002000{
2001 mapping ign = Query(P_IGNORE, F_VALUE);
2002 if (stringp(srcnames))
2003 srcnames = ({srcnames});
2004
2005 foreach(string srcname: srcnames)
2006 {
2007 // einfachster Fall, exakter Match
2008 if (member(ign, srcname))
2009 return MSG_IGNORED;
2010 // ansonsten muss aufgetrennt werden.
2011 if (strstr(srcname,".") > -1)
2012 {
2013 string *srcparts=explode(srcname,".");
2014 switch(sizeof(srcparts))
2015 {
2016 // case 0 und 1 kann nicht passieren.
2017 case 3:
2018 // zu pruefen: [sender].aktion.qualifizierer.
2019 // Der Fall, dass der Spieler dies _genau_ _so_ ignoriert hat, wird
2020 // oben schon geprueft. im Spieler geprueft werden muss noch:
2021 // spieler, .aktion, spieler.aktion und .aktion.qualifizierer
2022 if ( (sizeof(srcparts[0]) && member(ign,srcparts[0])) // spieler
2023 || member(ign, "."+srcparts[1]) // .aktion
2024 || member(ign, srcparts[0]+"."+srcparts[1]) // [spieler].aktion
2025 || member(ign, "."+srcparts[1]+"."+srcparts[2]) // .akt.qual
2026 )
2027 {
2028 return MSG_IGNORED;
2029 }
2030 break;
2031 case 2:
2032 // zu pruefen: spieler.aktion
2033 // Der Fall, dass der Spieler das _genau_ _so_ eingegeben hat, ist
2034 // oben schon geprueft. Im Spieler zu pruefen ist noch:
2035 // spieler und .aktion
2036 if ((sizeof(srcparts[0]) && member(ign,srcparts[0]))
2037 || member(ign, "."+srcparts[1]))
2038 {
2039 return MSG_IGNORED;
2040 }
2041 break;
2042 default: // mehr als 3 Teile...
2043 raise_error(sprintf("TestIgnoreExt(): too many qualifiers, only 1 "
2044 "is supported. Got: %s\n",srcname));
MG Mud User88f12472016-06-24 23:31:02 +02002045 }
2046 }
2047 }
2048 // Default: nicht ignorieren.
2049 return 0;
2050}
2051
2052#ifdef __LPC_UNIONS__
2053public int TestIgnoreExt(string|string* srcnames)
2054#else
2055public int TestIgnoreExt(mixed srcnames)
2056#endif
2057{
2058 return TestIgnore(srcnames);
2059}
2060
2061// Prueft fuer ReceiveMsg() auf Ingoriereeintraege. Ignoriert aber nicht alle
2062// Typen.
2063// Rueckgabe: 0 oder MSG_IGNORED | MSG_VERB_IGN | MSG_MUD_IGN
2064private int check_ignores(string msg, int msg_type, string msg_action,
Zesstra7459f252022-02-23 22:47:26 +01002065 string msg_prefix, object|string origin)
MG Mud User88f12472016-06-24 23:31:02 +02002066{
2067 // Einige Dinge lassen sich nicht ignorieren.
2068 if (msg_type & (MT_NEWS|MT_NOTIFICATION))
2069 return 0;
2070 // alles andere geht zur zeit erstmal, wenn origin bekannt UND NICHT das
2071 // eigene Objekt ist. Waer ggf. sonst doof. Ausserdem muss es natuerlich
2072 // eine ignorierbare msg_action geben.
2073 else if (stringp(msg_action) && origin && origin != ME)
2074 {
Zesstra7459f252022-02-23 22:47:26 +01002075 string srcname;
2076 if (objectp(origin))
2077 srcname =
MG Mud User88f12472016-06-24 23:31:02 +02002078 (query_once_interactive(origin) ? origin->query_real_name()
2079 : origin->name(WER) || "");
Zesstra7459f252022-02-23 22:47:26 +01002080 else
2081 srcname = origin;
2082
MG Mud User88f12472016-06-24 23:31:02 +02002083 mapping ign = Query(P_IGNORE, F_VALUE);
2084
2085 if (member(ign, srcname))
2086 return MSG_IGNORED;
2087 // vielleicht wird irgendwas a la name.aktion ignoriert?
2088 // dies ignoriert auch spieler.ebenen.<ebene> (s. msg_action bei
2089 // Ebenenmeldungen)
2090 if (member(ign, srcname+"."+msg_action))
2091 return MSG_VERB_IGN;
2092 // Oder die Aktion komplett? Dies ignoriert auch .ebenen.<ebene>, obwohl
2093 // das reichlich sinnfrei ist.
2094 if (member(ign, "."+msg_action))
2095 return MSG_VERB_IGN;
2096 // Spieler auf Ebenen ignoriert?
2097 // msg_action ist hier nach diesem Muster: MA_CHANNEL.<ebene>
2098 if (strstr(msg_action, MA_CHANNEL) == 0)
2099 {
2100 // spieler.ebenen? (spieler.ebenen.<ebene> oben schon geprueft)
2101 if (member(ign, srcname + "."MA_CHANNEL))
2102 return MSG_IGNORED;
2103 // spieler.ebenen.ebenenname ist oben schon abgedeckt.
2104 // .ebenen halte ich fuer sinnfrei, nicht geprueft.
2105 }
2106 // Spieler aus anderem mud? *seufz*
2107 if (strstr(srcname,"@") > -1)
2108 {
2109 string *srcparts = explode(srcname,"@");
2110 if (sizeof(srcparts)==2)
2111 {
2112 // spieler@?
2113 if (member(ign, srcparts[0]+"@"))
2114 return MSG_IGNORED;
2115 // oder Mud per @mud?
2116 if (member(ign, "@" + srcparts[1]))
2117 return MSG_MUD_IGN;
2118 // BTW: spieler@mud wurde schon ganz oben erfasst.
2119 }
2120 }
2121 }
2122 // Default: nicht ignorieren.
2123 return 0;
2124}
2125
2126// Wird die nachricht wahrgenommen? Die Pruefung erfolgt aufgrund von
2127// msg_type. Zur wird MT_LOOK und MT_LISTEN beruecksichtigt (Pruefung auf
Bugfixe0fc68f2022-01-07 15:30:54 +01002128// BLindheit/Taubheit). In Zukunft koennten aber weitere Typen und weitere
2129// Kriterien wichtig werden und weitere Argumente uebergeben werden. (Dies
2130// bitte beachten, falls diese Funktion protected/public werden sollte.)
MG Mud User88f12472016-06-24 23:31:02 +02002131// Wichtig: enthaelt msg_action weder MT_LOOK noch MT_LISTEN, wird die
2132// Nachricht wahrgenommen, da davon ausgegangen wird, dass sie mit den beiden
2133// Sinn gar nix zu tun hat.
2134// Rueckgabe: 0 oder MSG_SENSE_BLOCK
Bugfixe0fc68f2022-01-07 15:30:54 +01002135private int check_senses(int msg_type)
MG Mud User88f12472016-06-24 23:31:02 +02002136{
2137 int senses = msg_type & (MT_LOOK|MT_LISTEN);
2138 // Wenn von vorherein kein Sinn angesprochen, dann ist es eine nachricht,
2139 // die von keinem der beiden wahrgenommen wird und sollte demnach nicht
2140 // unterdrueckt werden.
2141 if (!senses)
2142 return 0;
Bugfix427a5812022-01-07 15:41:24 +01002143
2144 int orig_senses = senses;
2145
MG Mud User88f12472016-06-24 23:31:02 +02002146 if ((senses & MT_LOOK) && CannotSee(1))
2147 senses &= ~MT_LOOK; // Sinn loeschen
2148
2149 if ((senses & MT_LISTEN) && QueryProp(P_DEAF))
2150 senses &= ~MT_LISTEN;
2151
Bugfix427a5812022-01-07 15:41:24 +01002152 // Wenn kein Sinn mehr ueber ist oder all_types gesetzt ist und nicht mehr
2153 // alle Sinne vorhanden sind, wird die Nachricht nicht wahrgenommen.
2154 if (orig_senses == senses // kein Sinn geloescht, haeufigster Fall
2155 || (!(msg_type&MSG_ALL_SENSES) && senses) ) // min. ein Sinn uebrig
2156 return 0;
MG Mud User88f12472016-06-24 23:31:02 +02002157
Bugfix427a5812022-01-07 15:41:24 +01002158 return MSG_SENSE_BLOCK;
MG Mud User88f12472016-06-24 23:31:02 +02002159}
2160
2161public varargs int ReceiveMsg(string msg, int msg_type, string msg_action,
2162 string msg_prefix, object origin)
2163{
2164 if (!msg) return MSG_FAILED;
2165
2166 // Flags und Typen spalten
2167 int flags = msg_type & MSG_ALL_FLAGS;
2168 int type = msg_type & ~flags;
2169
2170 // ggf. defaults ermitteln
2171 origin ||= previous_object();
2172 msg_action ||= comm_guess_action();
2173 type ||= comm_guess_message_type(msg_action, origin);
2174
2175 // Debugmeldungen nur an Magier oder Testspieler mit P_WIZ_DEBUG
2176 if (msg_type & MT_DEBUG)
2177 {
2178 if (!QueryProp(P_WIZ_DEBUG)
2179 || (!IS_LEARNER(ME) && !QueryProp(P_TESTPLAYER)) )
2180 return MSG_FAILED;
2181 }
2182
2183 // Zuerst werden Sinne und P_IGNORE sowie ggf. sonstige Filter geprueft. In
2184 // dem Fall ist direkt Ende, kein Kobold, keine Komm-History, keine
2185 // Weiterbearbeitung.
2186 // aber bestimmte Dinge lassen sich einfach nicht ignorieren.
2187 if (!(flags & MSG_DONT_IGNORE))
2188 {
Bugfix427a5812022-01-07 15:41:24 +01002189 // Sinne pruefen.
2190 int res=check_senses(msg_type);
MG Mud User88f12472016-06-24 23:31:02 +02002191 if (res) return res;
2192
2193 // Spieler-definiertes Ignoriere? (nur typen uebergeben, keine Flags)
2194 res=check_ignores(msg, type, msg_action, msg_prefix, origin);
2195 if (res) return res;
2196 }
2197
Zesstra3a261e52022-02-10 14:00:31 +01002198 // Mentions in der Form @Charname werden in Kommunikation oder beim Hoeren
2199 // von Rufen und Sagen markiert und gegebenfalls gibt es ein Pieps dafuer
2200 int mention;
2201 if ((type & MT_COMM)
2202 || ((type & MT_LISTEN) && msg_action in ({MA_SAY, MA_SHOUT}))
2203 )
2204 {
2205 // Um den Charnamen Tags fuer terminal_colour() einfuegen.
2206 // Lookahead und Lookbehind assertions um die Whitespaces um das Wort
2207 // nicht in den Match einzuschliessen (und zu ersetzen).
2208 string tmp = regreplace(msg,
2209 sprintf("(?<=\\s)@%s(?=\\s*)",getuid(ME)),
2210 sprintf("%%^mention%%^@%s%%^normal%%^",
2211 capitalize(getuid(ME))),
2212 RE_PCRE|RE_GLOBAL|RE_CASELESS);
2213 send_debug(ME, tmp);
2214 // Der Vergleich ist weniger schlimm als es aussieht, weil die Strings
2215 // unterschiedlich gross sein werden und daher nicht zeichenweise
2216 // verglichen werden muessen. Es ist dann jedenfalls schneller als
2217 // getrennt mit regmatch oder strstr zu schauen, ob @charname
2218 // vorkommt.
2219 if (tmp != msg)
2220 {
2221 msg = tmp;
2222 mention = 1;
2223 }
2224 }
2225
MG Mud User88f12472016-06-24 23:31:02 +02002226 // Fuer MT_COMM gibt es ein paar Sonderdinge zu machen.
2227 if ((type & MT_COMM))
2228 {
2229 // erstmal in der Komm-History ablegen, wenn gewuenscht.
2230 if ((!(flags & MSG_DONT_STORE)))
2231 {
2232 string uid;
2233 if (query_once_interactive(origin))
2234 uid = origin->query_real_name();
2235 else
2236 uid = origin->name(WER) || "<unbekannt>";
Zesstraa31cd5c2016-12-17 20:11:07 +01002237 add_to_tell_history(uid, 0, 1, msg, msg_prefix,
2238 (msg_action == MA_TELL ? MSGFLAG_TELL : 0 ) );
MG Mud User88f12472016-06-24 23:31:02 +02002239 }
2240
2241 // ggf. Uhrzeit bei abwesenden Spielern anhaengen, aber nicht bei
2242 // Ebenenmeldungen. (Die haben ggf. schon.)
2243 if (stringp(msg_action) && QueryProp(P_AWAY)
2244 && strstr(msg_action, MA_CHANNEL) != 0)
2245 {
2246 // Uhrzeit anhaengen, aber ggf. muss ein \n abgeschnitten werden.
2247 if (msg[<1] == '\n')
2248 msg = msg[0..<2]+" [" + strftime("%H:%M",time()) + "]\n";
2249 else
2250 msg = msg + " [" + strftime("%H:%M",time()) + "]";
2251 }
2252 // Kobold erlaubt und gewuenscht? Kobold ist fuer die
2253 // direkte Kommunikation mittels MT_COMM vorgesehen.
2254 // Oropax von Magiern leitet inzwischen auch nur in Kobold um statt zu
2255 // ignorieren.
2256 // die if-Konstruktion ist so, weil ich das _flush_cache() im else
2257 // brauche.
2258 if (query_editing(this_object()) || query_input_pending(this_object())
2259 || QueryProp(P_EARMUFFS))
2260 {
2261 if (!(flags & MSG_DONT_BUFFER)
Zesstra7459f252022-02-23 22:47:26 +01002262 && (QueryProp(P_BUFFER) & KOBOLD_ONLINE))
MG Mud User88f12472016-06-24 23:31:02 +02002263 {
2264 // Nachricht soll im Kobold gespeichert werden.
2265 return add_to_kobold(msg, msg_type, msg_action, msg_prefix, origin);
2266 }
2267 }
2268 else
2269 {
2270 // wenn nicht in Editor/input_to, mal versuchen, den Kobold zu
2271 // entleeren.
2272 _flush_cache(0);
2273 }
Bugfix3afcb792022-01-21 22:32:42 +01002274 }
2275
Zesstra3a261e52022-02-10 14:00:31 +01002276 // Farbtags ersetzen
2277 msg = terminal_colour(msg, colourmap);
2278
2279 // Alertton senden?
2280 if ((msg_type & MSG_ALERT) || mention)
2281 comm_beep(msg_action, mention);
MG Mud User88f12472016-06-24 23:31:02 +02002282
2283 // Ausgabenachricht bauen und an den Spieler senden.
2284 if (flags & MSG_DONT_WRAP)
2285 msg = (msg_prefix ? msg_prefix : "") + msg;
2286 else
2287 {
2288 int bsflags = flags & MSG_ALL_BS_FLAGS;
2289 if (QueryProp(P_MESSAGE_PREPEND))
2290 bsflags |= BS_PREPEND_INDENT;
2291 msg = break_string(msg, 78, msg_prefix, bsflags);
2292 }
2293 efun::tell_object(ME, msg);
2294
2295 return MSG_DELIVERED;
2296}
Zesstra7459f252022-02-23 22:47:26 +01002297
2298// called from base.c in Reconnect()
2299protected void reconnect() {
2300 // Cache fuer den report zuruecksetzen, der koennte veraltet sein (insb.
2301 // falls in der letzten Session GMCP benutzt wurde und jetzt nicht).
2302 report_cache = 0;
2303}
2304
2305protected void updates_after_restore(int newflag) {
2306 // Colourmap aktualisieren nach Restore
2307 colourmap = build_colourmap(QueryProp(P_TTY));
2308
2309 // Altes Ignoriere loeschen...
2310 mixed ign = Query(P_IGNORE,F_VALUE);
2311 if (!mappingp(ign))
2312 {
2313 if (pointerp(ign))
2314 ReceiveNotify(break_string(
2315 "Deine Ignoriere-Einstellungen wurden soeben geloescht, "
2316 "weil es eine Aktualisierung der Ignorierefunktion gab, "
2317 "bei der eine Konversion der Daten leider nicht "
2318 "moeglich war.",78), 0);
2319
2320 Set(P_IGNORE, ([]), F_VALUE);
2321 }
2322 // ggf. Comm-Vault abrufen oder neu erstellen.
2323 setup_comm_vault();
2324 // Wenn es eins gibt, den Inhalt zu unserem internen Koboldpuffer
2325 // hinzufuegen, von wo es spaeter angezeigt wird.
2326 if (commvault)
2327 process_comm_vault(commvault);
2328}
2329