blob: 58ee739765feb590c27f652db890d2b14812c668 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// channel.c -- channel client
4//
5// $Id: channel.c 9404 2015-12-13 00:21:44Z Zesstra $
6#pragma strong_types
7#pragma save_types
8#pragma range_check
9#pragma no_clone
Zesstraf1137e82019-11-27 23:37:30 +010010//#pragma pedantic
MG Mud User88f12472016-06-24 23:31:02 +020011
12#define NEED_PROTOTYPES
13#include <util.h>
14#include <thing/properties.h>
15#include <living/comm.h>
16#include <player.h>
17#include <player/comm.h>
18#include <daemon.h>
19#include <player/gmcp.h>
20#undef NEED_PROTOTYPES
21
22#include <wizlevels.h>
23#include <defines.h>
24#include <properties.h>
25#include <sys_debug.h>
26#include <regexp.h>
27
28#define P_SWAP_CHANNELS "swap_channels"
29#define P_CHANNEL_SHORT "short_channels"
30
31#define CHANNELCMDS "[#@%$&()<>a-zA-Z0-9\\-]"
32
33#define DEFAULT_CHANNELS ({"Abenteuer", "Anfaenger","Grats","Tod", "ZT"})
34#define DEFAULT_SHORTCUTS \
35([ \
36 "b":"Abenteuer", \
37 "a":"Allgemein", \
38 "B":"Beileid", \
39 "q":"D-chat", \
40 "G":"Grats", \
41 "M":"Moerder", \
42 "h":"Seher", \
43 "T":"Tod", \
44])
45
46#define WIZARD_SHORTCUTS \
47([ \
48 "P":"D-code", \
49 "D":"Debug", \
50 "O":"Intercode", \
51 "I":"Intermud", \
52 "m":"Magier", \
53])
54
55
56private nosave mapping shortcut;
57private nosave int c_status;
58
59void create()
60{
61 Set(P_CHANNELS, SAVE, F_MODE);
62 Set(P_CHANNELS, DEFAULT_CHANNELS);
63 Set(P_SWAP_CHANNELS, SAVE, F_MODE);
64 Set(P_STD_CHANNEL, "Allgemein");
65 Set(P_STD_CHANNEL, SAVE, F_MODE);
66 Set(P_CHANNEL_SHORT, SAVE, F_MODE);
67 Set(P_CHANNEL_SHORT, DEFAULT_SHORTCUTS
68 + (IS_LEARNER(this_object()) ? WIZARD_SHORTCUTS : ([])));
69}
70
Arathorn00764692019-11-27 22:09:31 +010071static <int|string>** _query_localcmds()
MG Mud User88f12472016-06-24 23:31:02 +020072{
73 return ({({"-","ChannelParser", 1, 0}),
74 ({"ebene", "ChannelAdmin", 0, 0}),
75 ({"ebenen", "ChannelAdmin", 1, 0}),
76 });
77}
78
Arathorn00764692019-11-27 22:09:31 +010079string* RegisterChannels()
MG Mud User88f12472016-06-24 23:31:02 +020080{
Arathorn00764692019-11-27 22:09:31 +010081 string* err;
Zesstraf1137e82019-11-27 23:37:30 +010082
MG Mud User88f12472016-06-24 23:31:02 +020083 if(extern_call() &&
Zesstraf1137e82019-11-27 23:37:30 +010084 previous_object() != find_object(CHMASTER))
85 return 0;
86
MG Mud User88f12472016-06-24 23:31:02 +020087 c_status = 0;
88 shortcut = QueryProp(P_CHANNEL_SHORT);
89 SetProp(P_CHANNELS, map(QueryProp(P_CHANNELS) || ({}),
Zesstra57a693e2019-01-06 22:08:24 +010090 #'lower_case));
MG Mud User88f12472016-06-24 23:31:02 +020091 err = filter(QueryProp(P_CHANNELS),
92 symbol_function("join", CHMASTER),
93 this_object());
94 if(QueryProp(P_LEVEL) < 5) return err;
95 while(sizeof(err)) {
96 CHMASTER->new(err[0], this_object());
97 err[0..0] = ({});
98 }
99 return err;
100}
101
Arathorn00764692019-11-27 22:09:31 +0100102string* RemoveChannels()
MG Mud User88f12472016-06-24 23:31:02 +0200103{
104 closure cl;
Arathorn00764692019-11-27 22:09:31 +0100105 string* err=({});
Zesstraf1137e82019-11-27 23:37:30 +0100106
MG Mud User88f12472016-06-24 23:31:02 +0200107 if(extern_call() &&
Zesstraf1137e82019-11-27 23:37:30 +0100108 previous_object() != find_object(CHMASTER))
109 return 0;
110
MG Mud User88f12472016-06-24 23:31:02 +0200111 if(!c_status) c_status = 1;
112 else return ({});
113 cl=symbol_function("leave", CHMASTER);
114 if (closurep(cl)) {
115 err = filter(QueryProp(P_CHANNELS), cl, this_object());
116 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) - err);
117 }
118 return err;
119}
120
Arathorn00764692019-11-27 22:09:31 +0100121varargs private string getName(string|object|closure x, int fall) {
122 string|object o = closurep(x) ? query_closure_object(x) : x;
123 if(stringp(o) && sizeof(o) && (x = find_object(o)))
MG Mud User88f12472016-06-24 23:31:02 +0200124 o = x;
125
126 // Objekte
127 if (objectp(o)) {
128 // Magier sehen unsichtbare nicht nur als "Jemand"
129 if (o->QueryProp(P_INVIS) && IS_LEARNING(this_object()))
130 return "("+capitalize(getuid(o))+")";
131 // Froesche mit Namen versorgen.
132 if (o->QueryProp(P_FROG))
133 return "Frosch "+capitalize(getuid(o));
134 // Default (Unsichtbare als "Jemand" (s. Name()))
135 return o->Name(fall, 2)||"<Unbekannt>";
136 }
137 // Strings
138 else if (stringp(o) && sizeof(o)) {
139 if (o[0] == '/') {
140 // unsichtbare Objekte...
141 int p = strstr(o, "$");
142 if (p != -1) {
Zesstra57a693e2019-01-06 22:08:24 +0100143 // Magier im Magiermodus kriegen den Realnamen, andere nicht.
144 if (IS_LEARNING(this_object()))
145 return o[1..p-1];
146 else
147 return o[p+1..];
MG Mud User88f12472016-06-24 23:31:02 +0200148 }
149 else
Zesstra57a693e2019-01-06 22:08:24 +0100150 // doch nicht unsichtbar
151 return (fall == WESSEN ? o+"s" : o);
MG Mud User88f12472016-06-24 23:31:02 +0200152 }
153 else
154 // nicht unsichtbar
155 return (fall == WESSEN ? o+"s" : o);
156 }
157 // Fall-through
158 return "<Unbekannt>";
159}
160
Arathorn69d6ddd2019-11-25 21:06:34 +0100161// <nonint> unterdrueckt die Ausgabe an den Spieler und liefert den Text
MG Mud User88f12472016-06-24 23:31:02 +0200162// zurueck. Wird nur fuer die Ebenenhistory benutzt.
Arathorn69d6ddd2019-11-25 21:06:34 +0100163string ChannelMessage(<string|object|int>* msg, int nonint)
MG Mud User88f12472016-06-24 23:31:02 +0200164{
165 string channel_message;
166 string channel=msg[0];
Arathorn69d6ddd2019-11-25 21:06:34 +0100167
168 // Wenn eine Ebenenmeldung ausgegeben werden soll, ist msg[1] ein Objekt,
169 // im Fall der History aber ein String. Daher wird <sender> als Union
170 // deklariert. Das ist unproblematisch, weil die beiden Datentypen
171 // komplett getrennte Wege nehmen: ein Objekt wird an ReceiveMsg()
172 // durchgereicht (Ebenenmeldung). Ein String wird direkt in die Meldung
173 // (History) eingebaut, diese an den ChannelParser() zurueckgegeben, der
174 // sie via More() ausgibt.
175 string|object sender=msg[1];
MG Mud User88f12472016-06-24 23:31:02 +0200176 string message=msg[2];
177 int msg_type = msg[3];
178
179 if ( previous_object() != find_object(CHMASTER) &&
180 previous_object() != ME )
181 return 0;
182
183 string sender_name = getName(sender, msg_type == MSG_GEMOTE ? WESSEN : WER);
184 int prepend_indent_flag=QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0;
185 switch(msg_type) {
186 case MSG_EMPTY:
187 channel_message= message+"\n";
188 break;
189 case MSG_GEMOTE:
190 case MSG_EMOTE:
191 channel_message = break_string(sender_name + " "+ message+"]",
192 78, sprintf("[%s:", channel),
193 BS_INDENT_ONCE|prepend_indent_flag);
194 break;
195 case MSG_SAY:
196 default:
197 string presay=sprintf("[%s:%s] ", channel, sender_name);
198 channel_message = break_string(message, max(78,sizeof(presay)+10),
199 presay, prepend_indent_flag);
200 break;
201 }
202 if(nonint)
203 return channel_message;
204
205 // Wenn GMCP sich um Uebertragung der Nachricht kuemmert, wird ReceiveMsg()
Zesstra7ccec732019-01-06 22:10:09 +0100206 // nicht mehr aufgerufen. getName leider nochmal aufrufen, weil GMCP den
207 // Namen im Nominativ braucht.
208 if (msg_type == MSG_GEMOTE)
209 sender_name = getName(sender, WER);
MG Mud User88f12472016-06-24 23:31:02 +0200210 if (GMCP_Channel(channel_message, channel, sender_name) != 1)
211 {
212 // Der Ebenenname muss in Kleinbuchstaben uebergeben werden, damit die
213 // Ignorierepruefung funktioniert. Die ignorierestrings sind naemlich alle
214 // kleingeschrieben.
215 ReceiveMsg(channel_message,
216 MT_COMM|MT_FAR|MSG_DONT_STORE|MSG_DONT_WRAP,
217 MA_CHANNEL"." + lower_case(channel), 0, sender);
218 }
219 return 0;
220}
221
222private void createList(string n, mixed a, mixed m, mixed l)
223{
Arathorn00764692019-11-27 22:09:31 +0100224 int pos = member(map(m_values(shortcut), #'lower_case/*'*/), n);
225 string sh = "";
226 if(pos != -1)
MG Mud User88f12472016-06-24 23:31:02 +0200227 sh = m_indices(shortcut)[pos];
Arathorn00764692019-11-27 22:09:31 +0100228
229 string* mem=map(a[I_MEMBER],#'getName/*'*/, WER);
MG Mud User88f12472016-06-24 23:31:02 +0200230 mem-=({"<MasteR>"});
231 l += ({ sprintf("%-12.12'.'s %c[%-1.1s] %|12.12' 's (%-|3' 'd) %-42.42s\n",
232 a[I_NAME], (member(m, n) != -1 ? '*' : ' '), sh,
233 a[I_MASTER] ?
234 getName(a[I_MASTER]) : getName(a[I_ACCESS]),
235 sizeof(mem),
236 (closurep(a[I_INFO]) && objectp(query_closure_object(a[I_INFO]))) ?
237 funcall(a[I_INFO]) || "- Keine Beschreibung -" :
238 (stringp(a[I_INFO]) ? a[I_INFO] : "- Keine Beschreibung -")
239 ) });
240}
241
242private mixed getChannel(string ch)
243{
Arathorn00764692019-11-27 22:09:31 +0100244 if(!sizeof(ch))
245 ch = QueryProp(P_STD_CHANNEL);
246 if(shortcut && shortcut[ch])
247 ch = shortcut[ch];
MG Mud User88f12472016-06-24 23:31:02 +0200248 return CHMASTER->find(ch, this_object());
249}
250
251#ifndef DEBUG
252#define DEBUG(x) if (funcall(symbol_function('find_player),"zesstra"))\
253 tell_object(funcall(symbol_function('find_player),"zesstra"),\
Zesstra57a693e2019-01-06 22:08:24 +0100254 "MDBG: "+x+"\n")
MG Mud User88f12472016-06-24 23:31:02 +0200255#endif
256int ChannelParser(string args)
257{
Arathorn6d465642019-11-25 21:06:07 +0100258 mixed ch;
MG Mud User88f12472016-06-24 23:31:02 +0200259 int pos, type, err;
Arathorn6d465642019-11-25 21:06:07 +0100260 string txt, tmp;
261 string|string* cmd = query_verb();
MG Mud User88f12472016-06-24 23:31:02 +0200262 args = _unparsed_args();
263 notify_fail("Benutzung: -<Ebene>[ ]['|:|;]<Text>\n"
264 " -<Ebene>[+|-|?|!|*]\n"
265 " -?\n");
266 if(!cmd && !args) return 0;
267 if(!args) args = "";
268 cmd = cmd[1..];
269 if(sizeof(cmd = regexplode(cmd,
270 "^" CHANNELCMDS "*"
271 "([+-]|\\!|\\?|\\*)*")) > 1)
272 {
273 //z.B. cmd= ({"","allgemein",":testet"})
274 if(sizeof(cmd[1]) > 1 &&
275 strstr("+-?!*", cmd[1][<1..<1]) > -1)
276 tmp = cmd[1][0..<2];
277 else
278 tmp = cmd[1];
279 if(cmd[1] != "?" && cmd[1] != "!")
Zesstra57a693e2019-01-06 22:08:24 +0100280 {
281 ch = getChannel(tmp);
282 if(pointerp(ch))
MG Mud User88f12472016-06-24 23:31:02 +0200283 {
284 notify_fail("Diese Angabe war nicht eindeutig! "
285 "Folgende Ebenen passen:\n"
286 +implode(ch, ", ")+"\n");
287 return 0;
288 }
Zesstra57a693e2019-01-06 22:08:24 +0100289 else if(!ch)
290 return (notify_fail("Die Ebene '"+tmp
291 + "' gibt es nicht!\n"), 0);
292 }
MG Mud User88f12472016-06-24 23:31:02 +0200293 //DEBUG(sprintf("ChanCmd: %O\n",cmd));
294 if (sizeof(cmd[1])) {
295 switch(cmd[1][<1]) {
296 case '+':
297 switch(CHMASTER->join(ch, this_object()))
298 {
299 case E_ACCESS_DENIED:
300 notify_fail("Du darfst an die Ebene '"+ch+"' nicht heran.\n");
301 return 0;
302 case E_ALREADY_JOINED:
303 notify_fail("Du hast diese Ebene schon betreten!\n");
304 return 0;
305 default: break;
306 }
307 write("Du betrittst die Ebene '"+ch+"'.\n");
308 if(member(QueryProp(P_CHANNELS), ch = lower_case(ch)) == -1)
309 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({ ch }));
310 return 1;
311 case '-':
312 switch(CHMASTER->leave(ch, this_object()))
313 {
314 case E_ACCESS_DENIED:
315 write("Du kannst die Ebene '"+ch+"' nicht verlassen.\n");
316 break;
317 case E_NOT_MEMBER:
318 write("Wie willst Du eine Ebene verlassen, welche Du nicht "
319 "betreten hast?\n");
320 break;
321 default:
322 write("Du verlaesst die Ebene '"+ch+"'.\n");
323 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) - ({ lower_case(ch), ch }));
324 break;
325 }
326 return 1;
327 case '!':
328 case '?':
329 {
330 mapping l;
331 if(mappingp(l = CHMASTER->list(this_object())))
Zesstra57a693e2019-01-06 22:08:24 +0100332 {
MG Mud User88f12472016-06-24 23:31:02 +0200333 if(stringp(ch) && sizeof(ch) && pointerp(l[ch = lower_case(ch)]))
334 {
335 int c; object o; string n; string *m;
336 m=sort_array(map(l[ch][I_MEMBER],#'getName/*'*/, WER),#'>/*'*/);
337 m-=({"<MasteR>"});
338 write(l[ch][I_NAME]+", "+funcall(l[ch][I_INFO])+".\n");
339 write("Du siehst "+((c = sizeof(m)) > 0
340 ? (c == 1 ? "ein Gesicht" : c+" Gesichter")
341 : "niemanden")+" auf der Ebene '"
342 +l[ch][I_NAME]+"':\n");
343 write(break_string(implode(m,", "), 78));
344 write((l[ch][I_MASTER] ?
345 getName(l[ch][I_MASTER]) : getName(l[ch][I_ACCESS], WER))
346 +" hat das Sagen auf dieser Ebene.\n");
347 }
348 else
349 {
Arathorn00764692019-11-27 22:09:31 +0100350 string* list = ({});
MG Mud User88f12472016-06-24 23:31:02 +0200351 if(cmd[1][<1] == '!')
352 l -= mkmapping(m_indices(l) - QueryProp(P_CHANNELS));
353 walk_mapping(l, #'createList/*'*/, QueryProp(P_CHANNELS), &list);
354 list = sort_array(list, #'>/*'*/);
355 txt = sprintf("%-12.12' 's [A] %|12' 's (%-3' 's) %-42.42s\n",
356 "Name", "Eigner", "Sp", "Beschreibung")
357 + "-------------------------------------------------------"
358 + "-----------------------\n"
359 + implode(list, "");
360 More(txt);
361 }
Zesstra57a693e2019-01-06 22:08:24 +0100362 }
MG Mud User88f12472016-06-24 23:31:02 +0200363 return 1;
Zesstra57a693e2019-01-06 22:08:24 +0100364
MG Mud User88f12472016-06-24 23:31:02 +0200365 }
366 case '*':
367 {
Arathorn00764692019-11-27 22:09:31 +0100368 mixed hist = CHMASTER->history(ch, this_object());
369 if(!pointerp(hist) || !sizeof(hist))
MG Mud User88f12472016-06-24 23:31:02 +0200370 {
371 write("Es ist keine Geschichte fuer '"+ch+"' verfuegbar.\n");
372 return 1;
373 }
Arathorn00764692019-11-27 22:09:31 +0100374
MG Mud User88f12472016-06-24 23:31:02 +0200375 //(Zesstra) cmd hat offenbar immer 3 Elemente...
376 //bei -all* ({"","all*",""})
377 //bei -all*10 ({"","all*,"10"})
378 //also ist bei -all* amount immer == 0 und es funktioniert eher zufaellig.
379 /*if(sizeof(cmd) > 2)
380 amount = to_int(cmd[2]);
381 else
382 amount=sizeof(hist);*/
Arathorn00764692019-11-27 22:09:31 +0100383 int amount=to_int(cmd[2]);
MG Mud User88f12472016-06-24 23:31:02 +0200384 if (amount <= 0 || amount >= sizeof(hist))
385 amount=sizeof(hist);
386
387 txt = "Folgendes ist auf '"+ch+"' passiert:\n"
388 + implode(map(hist[<amount..], #'ChannelMessage/*'*/, 1), "");
389 More(txt);
390 return 1;
391 }
392 default:
393 break;
394 }
395 }
396 }
397 if(sizeof(cmd = implode(cmd[2..], "")))
398 args = cmd + (sizeof(args) ? " " : "") + args;
399
400 // KOntrollchars ausfiltern.
401 args = regreplace(args,"[[:cntrl:]]","",RE_PCRE|RE_GLOBAL);
402 if(!sizeof(args)) return 0;
403
404 //Wenn cmd leer ist: MSG_SAY
405 if (!sizeof(cmd)) type=MSG_SAY;
406 else {
407 switch(cmd[0])
408 {
409 case ':' :
410 type = MSG_EMOTE;
411 args = args[1..];
412 break;
413 case ';' :
414 type = MSG_GEMOTE;
415 args = args[1..];
416 break;
417 case '\'':
418 args = args[1..];
419 default : type = MSG_SAY; break;
420 }
421 }
422 if(!ch || !sizeof(ch)) ch = QueryProp(P_STD_CHANNEL);
423 if((err = CHMASTER->send(ch, this_object(), args, type)) < 0)
424 if(!(err = CHMASTER->join(ch, this_object())))
425 {
426 if(member(QueryProp(P_CHANNELS), ch = lower_case(ch)) == -1)
427 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({ ch }));
428 err = CHMASTER->send(ch, this_object(), args, type);
429 }
430
431 switch(err)
432 {
433 case E_ACCESS_DENIED:
434 notify_fail("Auf der Ebene '"+ch+"' darfst Du nichts sagen.\n");
435 return 0;
436 case E_NOT_MEMBER:
437 notify_fail("Du hast die Ebene '"+ch+"' nicht betreten!\n");
438 return 0;
439 }
440 return 1;
441}
442
443int ChannelAdmin(string args)
444{
445 string n, descr, sh, cn;
Arathorn00764692019-11-27 22:09:31 +0100446 mixed tmp;
MG Mud User88f12472016-06-24 23:31:02 +0200447 args = _unparsed_args();
448 notify_fail("Benutzung: ebene <Abkuerzung>=<Ebene>\n"
449 " ebene <Abkuerzung>=\n"
450 " ebene abkuerzungen [standard]\n"
451 " ebene standard <Ebene>\n"
452 " ebene an|ein|aus\n"
453 +(QueryProp(P_LEVEL) >= 5 ?
454 " ebene neu <Name> <Bezeichnung>\n"
455 " ebene beschreibung <Name> <Beschreibung>\n" : "")
456 +(IS_ARCH(this_object()) ?
457 " ebene kill <Name>\n"
Zesstra57a693e2019-01-06 22:08:24 +0100458 " ebene clear <Name>\n": ""));
MG Mud User88f12472016-06-24 23:31:02 +0200459 if(!args || !sizeof(args)) return 0;
460 if(sscanf(args, "kill %s", n) && IS_ARCH(this_object()))
461 {
462 if(!(cn = CHMASTER->find(n, this_object()))) cn = n;
463 switch(CHMASTER->remove(cn, this_object()))
464 {
465 case E_ACCESS_DENIED:
466 notify_fail("Die Ebene '"+cn+"' lies sich nicht entfernen!\n");
467 return 0;
468 }
469 write("Du entfernst die Ebene '"+cn+"'.\n");
470 return 1;
471 }
472 if(sscanf(args, "clear %s", n) && IS_ARCH(this_object()))
473 {
474 if(!(cn = CHMASTER->find(n, this_object()))) cn = n;
475 switch(CHMASTER->clear_history(cn, this_object()))
476 {
477 case E_ACCESS_DENIED:
478 notify_fail("Der Verlauf zur Ebene '"+cn+"' lies sich nicht entfernen!\n");
479 return 0;
480 }
481 write("Du entfernst den Verlauf zur Ebene '"+cn+"'.\n");
482 return 1;
483 }
484 if(sscanf(args, "neu %s %s", n, descr) == 2)
485 {
486 mixed x;
487 if(QueryProp(P_LEVEL) < 5)
488 return (notify_fail("Neue Ebenen zu erstellen ist dir verwehrt.\n"), 0);
489 if(!sizeof(regexp(({ n }), "^" CHANNELCMDS CHANNELCMDS "*")))
490 return (notify_fail("Der Name '"+n+"' ist nicht konform!\n"), 0);
491 if (sizeof(n) > 20 )
492 return(notify_fail("Der Name '"+n+"' ist zu lang.\n"), 0);
493 switch(x = CHMASTER->new(n, this_object(), descr))
494 {
495 case E_ACCESS_DENIED:
496 notify_fail("Diese Ebene darfst du nicht erschaffen!\n"); break;
497 default:
498 write("Du erschaffst die Ebene '"+n+"'.\n");
499 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({ lower_case(n) }));
500 return 1;
501 }
502 }
503 if(sscanf(args, "beschreibung %s %s", n, descr) == 2)
504 {
505 mixed ch;
506 cn = CHMASTER->find(n, this_object());
507 if(!cn || pointerp(cn))
508 return (notify_fail("Die Ebene '"+n+"' existiert nicht oder die Angabe "
509 "war nicht eindeutig.\n"), 0);
510 ch = CHMASTER->list(this_object());
511 if(ch[lower_case(cn)][I_MASTER] != this_object())
512 return (notify_fail("Du bist nicht berechtigt die Beschreibung der Ebene"
513 " '"+cn+"' zu aendern.\n"), 0);
514 ch[lower_case(cn)][I_INFO] = descr;
515 write("Die Ebene '"+cn+"' hat ab sofort die Beschreibung:\n"+descr+"\n");
516 return 1;
517 }
518 if(sscanf(args, "%s=%s", sh, n) == 2 && sizeof(n))
519 {
520 mapping sc;
521 if(pointerp(tmp = CHMASTER->find(n, this_object())) || !tmp)
522 return (notify_fail("Benutzung: ebene <Abkuerzung>=<Ebene>\n"
523 +(pointerp(tmp) ? implode(tmp, ", ") + "\n" :
524 "Ebene '"+n+"' nicht gefunden!\n")), 0);
525 sc = QueryProp(P_CHANNEL_SHORT);
526 if(!sc) sc = ([]);
527 sc[sh] = tmp;
528 SetProp(P_CHANNEL_SHORT, sc);
529 shortcut = QueryProp(P_CHANNEL_SHORT);
530 write("'"+sh+"' wird jetzt als Abkuerzung fuer '"+tmp+"' anerkannt.\n");
531 return 1;
532 }
533 if(sscanf(args, "%s=", sh))
534 {
535 SetProp(P_CHANNEL_SHORT, m_copy_delete(QueryProp(P_CHANNEL_SHORT) || ([]), sh));
536 shortcut = QueryProp(P_CHANNEL_SHORT);
537 write("Du loeschst die Abkuerzung '"+sh+"'.\n");
538 return 1;
539 }
540 if(args == "an" || args == "ein")
541 {
542 mixed excl;
543 if(pointerp(QueryProp(P_SWAP_CHANNELS)))
544 SetProp(P_CHANNELS, QueryProp(P_SWAP_CHANNELS));
545 else
546 SetProp(P_CHANNELS, m_indices(CHMASTER->list(this_object())));
547 excl = RegisterChannels();
548 write("Du schaltest folgende Ebenen ein:\n"
549 +break_string(implode(QueryProp(P_CHANNELS) - excl, ", "), 78));
550 SetProp(P_SWAP_CHANNELS, 0);
551 return 1;
552 }
553 if(args == "aus")
554 {
555 SetProp(P_SWAP_CHANNELS, QueryProp(P_CHANNELS));
556 RemoveChannels();
557 SetProp(P_CHANNELS, ({}));
558 write("Du stellst die Ebenen ab.\n");
559 return 1;
560 }
Arathorn00764692019-11-27 22:09:31 +0100561 string* pa = old_explode(args, " ");
MG Mud User88f12472016-06-24 23:31:02 +0200562 if(!strstr("abkuerzungen", pa[0]))
563 {
564 string txt; txt = "";
565 if(sizeof(pa) > 1 && !strstr("standard", pa[1]))
566 {
567 write("Die Standard Abkuerzungen werden gesetzt.\n");
568 SetProp(P_CHANNEL_SHORT, DEFAULT_SHORTCUTS
569 + (IS_LEARNER(this_object()) ? WIZARD_SHORTCUTS : ([])));
570 }
Arathorndc28afc2018-11-26 22:20:59 +0100571 foreach(string abk, string ch_name : QueryProp(P_CHANNEL_SHORT)) {
572 txt += sprintf("%5.5s = %s\n", abk, ch_name);
573 }
MG Mud User88f12472016-06-24 23:31:02 +0200574 txt = sprintf("Folgende Abkuerzungen sind definiert:\n%-78#s\n",
575 implode(sort_array(old_explode(txt, "\n"), #'>/*'*/), "\n"));
576 More(txt);
577 return 1;
578 }
579 if(!strstr("standard", pa[0]))
580 if(sizeof(pa) < 2)
581 return (notify_fail("Benutzung: ebene standard <Ebene>\n"
582 +(QueryProp(P_STD_CHANNEL)
583 ? "Momentan ist '"+QueryProp(P_STD_CHANNEL)
584 +"' eingestellt.\n"
585 : "Es ist keine Standardebene eingestellt.\n")),0);
586 else
587 if(pointerp(tmp = CHMASTER->find(pa[1], this_object())))
588 return (notify_fail("Das war keine eindeutige Angabe! "
589 "Folgende Ebenen passen:\n"
590 +break_string(implode(tmp, ", "), 78)), 0);
591 else
592 if(!tmp) return (notify_fail("Ebene '"+pa[1]+"' nicht gefunden!\n"),0);
593 else
594 {
595 write("'"+tmp+"' ist jetzt die Standardebene.\n");
596 SetProp(P_STD_CHANNEL, tmp);
597 return 1;
598 }
599 return(0);
600}
601