blob: 6784d5048ed976b771b096167eccce38a03d6ff3 [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
MG Mud User88f12472016-06-24 23:31:02 +020010
11#define NEED_PROTOTYPES
12#include <util.h>
13#include <thing/properties.h>
14#include <living/comm.h>
15#include <player.h>
16#include <player/comm.h>
17#include <daemon.h>
18#include <player/gmcp.h>
19#undef NEED_PROTOTYPES
20
21#include <wizlevels.h>
22#include <defines.h>
23#include <properties.h>
24#include <sys_debug.h>
25#include <regexp.h>
26
27#define P_SWAP_CHANNELS "swap_channels"
28#define P_CHANNEL_SHORT "short_channels"
29
30#define CHANNELCMDS "[#@%$&()<>a-zA-Z0-9\\-]"
31
32#define DEFAULT_CHANNELS ({"Abenteuer", "Anfaenger","Grats","Tod", "ZT"})
33#define DEFAULT_SHORTCUTS \
34([ \
35 "b":"Abenteuer", \
36 "a":"Allgemein", \
37 "B":"Beileid", \
38 "q":"D-chat", \
39 "G":"Grats", \
40 "M":"Moerder", \
41 "h":"Seher", \
42 "T":"Tod", \
43])
44
45#define WIZARD_SHORTCUTS \
46([ \
47 "P":"D-code", \
48 "D":"Debug", \
49 "O":"Intercode", \
50 "I":"Intermud", \
51 "m":"Magier", \
52])
53
54
55private nosave mapping shortcut;
56private nosave int c_status;
57
58void create()
59{
60 Set(P_CHANNELS, SAVE, F_MODE);
61 Set(P_CHANNELS, DEFAULT_CHANNELS);
62 Set(P_SWAP_CHANNELS, SAVE, F_MODE);
63 Set(P_STD_CHANNEL, "Allgemein");
64 Set(P_STD_CHANNEL, SAVE, F_MODE);
65 Set(P_CHANNEL_SHORT, SAVE, F_MODE);
66 Set(P_CHANNEL_SHORT, DEFAULT_SHORTCUTS
67 + (IS_LEARNER(this_object()) ? WIZARD_SHORTCUTS : ([])));
68}
69
Arathorn00764692019-11-27 22:09:31 +010070static <int|string>** _query_localcmds()
MG Mud User88f12472016-06-24 23:31:02 +020071{
72 return ({({"-","ChannelParser", 1, 0}),
73 ({"ebene", "ChannelAdmin", 0, 0}),
74 ({"ebenen", "ChannelAdmin", 1, 0}),
75 });
76}
77
Arathorn00764692019-11-27 22:09:31 +010078string* RegisterChannels()
MG Mud User88f12472016-06-24 23:31:02 +020079{
Arathorn00764692019-11-27 22:09:31 +010080 string* err;
Zesstraf1137e82019-11-27 23:37:30 +010081
MG Mud User88f12472016-06-24 23:31:02 +020082 if(extern_call() &&
Zesstraf1137e82019-11-27 23:37:30 +010083 previous_object() != find_object(CHMASTER))
84 return 0;
85
MG Mud User88f12472016-06-24 23:31:02 +020086 c_status = 0;
87 shortcut = QueryProp(P_CHANNEL_SHORT);
88 SetProp(P_CHANNELS, map(QueryProp(P_CHANNELS) || ({}),
Zesstra57a693e2019-01-06 22:08:24 +010089 #'lower_case));
MG Mud User88f12472016-06-24 23:31:02 +020090 err = filter(QueryProp(P_CHANNELS),
91 symbol_function("join", CHMASTER),
92 this_object());
93 if(QueryProp(P_LEVEL) < 5) return err;
94 while(sizeof(err)) {
95 CHMASTER->new(err[0], this_object());
96 err[0..0] = ({});
97 }
98 return err;
99}
100
Arathorn00764692019-11-27 22:09:31 +0100101string* RemoveChannels()
MG Mud User88f12472016-06-24 23:31:02 +0200102{
103 closure cl;
Arathorn00764692019-11-27 22:09:31 +0100104 string* err=({});
Zesstraf1137e82019-11-27 23:37:30 +0100105
MG Mud User88f12472016-06-24 23:31:02 +0200106 if(extern_call() &&
Zesstraf1137e82019-11-27 23:37:30 +0100107 previous_object() != find_object(CHMASTER))
108 return 0;
109
MG Mud User88f12472016-06-24 23:31:02 +0200110 if(!c_status) c_status = 1;
111 else return ({});
112 cl=symbol_function("leave", CHMASTER);
113 if (closurep(cl)) {
114 err = filter(QueryProp(P_CHANNELS), cl, this_object());
115 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) - err);
116 }
117 return err;
118}
119
Arathorn00764692019-11-27 22:09:31 +0100120varargs private string getName(string|object|closure x, int fall) {
121 string|object o = closurep(x) ? query_closure_object(x) : x;
122 if(stringp(o) && sizeof(o) && (x = find_object(o)))
MG Mud User88f12472016-06-24 23:31:02 +0200123 o = x;
124
125 // Objekte
126 if (objectp(o)) {
127 // Magier sehen unsichtbare nicht nur als "Jemand"
128 if (o->QueryProp(P_INVIS) && IS_LEARNING(this_object()))
129 return "("+capitalize(getuid(o))+")";
130 // Froesche mit Namen versorgen.
131 if (o->QueryProp(P_FROG))
132 return "Frosch "+capitalize(getuid(o));
133 // Default (Unsichtbare als "Jemand" (s. Name()))
134 return o->Name(fall, 2)||"<Unbekannt>";
135 }
136 // Strings
137 else if (stringp(o) && sizeof(o)) {
138 if (o[0] == '/') {
139 // unsichtbare Objekte...
140 int p = strstr(o, "$");
141 if (p != -1) {
Zesstra57a693e2019-01-06 22:08:24 +0100142 // Magier im Magiermodus kriegen den Realnamen, andere nicht.
143 if (IS_LEARNING(this_object()))
144 return o[1..p-1];
145 else
146 return o[p+1..];
MG Mud User88f12472016-06-24 23:31:02 +0200147 }
148 else
Zesstra57a693e2019-01-06 22:08:24 +0100149 // doch nicht unsichtbar
150 return (fall == WESSEN ? o+"s" : o);
MG Mud User88f12472016-06-24 23:31:02 +0200151 }
152 else
153 // nicht unsichtbar
154 return (fall == WESSEN ? o+"s" : o);
155 }
156 // Fall-through
157 return "<Unbekannt>";
158}
159
Arathorn69d6ddd2019-11-25 21:06:34 +0100160// <nonint> unterdrueckt die Ausgabe an den Spieler und liefert den Text
MG Mud User88f12472016-06-24 23:31:02 +0200161// zurueck. Wird nur fuer die Ebenenhistory benutzt.
Arathorn69d6ddd2019-11-25 21:06:34 +0100162string ChannelMessage(<string|object|int>* msg, int nonint)
MG Mud User88f12472016-06-24 23:31:02 +0200163{
164 string channel_message;
165 string channel=msg[0];
Arathorn69d6ddd2019-11-25 21:06:34 +0100166
167 // Wenn eine Ebenenmeldung ausgegeben werden soll, ist msg[1] ein Objekt,
168 // im Fall der History aber ein String. Daher wird <sender> als Union
169 // deklariert. Das ist unproblematisch, weil die beiden Datentypen
170 // komplett getrennte Wege nehmen: ein Objekt wird an ReceiveMsg()
171 // durchgereicht (Ebenenmeldung). Ein String wird direkt in die Meldung
172 // (History) eingebaut, diese an den ChannelParser() zurueckgegeben, der
173 // sie via More() ausgibt.
174 string|object sender=msg[1];
MG Mud User88f12472016-06-24 23:31:02 +0200175 string message=msg[2];
176 int msg_type = msg[3];
177
178 if ( previous_object() != find_object(CHMASTER) &&
179 previous_object() != ME )
180 return 0;
181
182 string sender_name = getName(sender, msg_type == MSG_GEMOTE ? WESSEN : WER);
183 int prepend_indent_flag=QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0;
184 switch(msg_type) {
185 case MSG_EMPTY:
186 channel_message= message+"\n";
187 break;
188 case MSG_GEMOTE:
189 case MSG_EMOTE:
190 channel_message = break_string(sender_name + " "+ message+"]",
191 78, sprintf("[%s:", channel),
192 BS_INDENT_ONCE|prepend_indent_flag);
193 break;
194 case MSG_SAY:
195 default:
196 string presay=sprintf("[%s:%s] ", channel, sender_name);
197 channel_message = break_string(message, max(78,sizeof(presay)+10),
198 presay, prepend_indent_flag);
199 break;
200 }
201 if(nonint)
202 return channel_message;
203
204 // Wenn GMCP sich um Uebertragung der Nachricht kuemmert, wird ReceiveMsg()
Zesstra7ccec732019-01-06 22:10:09 +0100205 // nicht mehr aufgerufen. getName leider nochmal aufrufen, weil GMCP den
206 // Namen im Nominativ braucht.
207 if (msg_type == MSG_GEMOTE)
208 sender_name = getName(sender, WER);
MG Mud User88f12472016-06-24 23:31:02 +0200209 if (GMCP_Channel(channel_message, channel, sender_name) != 1)
210 {
211 // Der Ebenenname muss in Kleinbuchstaben uebergeben werden, damit die
212 // Ignorierepruefung funktioniert. Die ignorierestrings sind naemlich alle
213 // kleingeschrieben.
214 ReceiveMsg(channel_message,
215 MT_COMM|MT_FAR|MSG_DONT_STORE|MSG_DONT_WRAP,
216 MA_CHANNEL"." + lower_case(channel), 0, sender);
217 }
218 return 0;
219}
220
221private void createList(string n, mixed a, mixed m, mixed l)
222{
Arathorn00764692019-11-27 22:09:31 +0100223 int pos = member(map(m_values(shortcut), #'lower_case/*'*/), n);
224 string sh = "";
225 if(pos != -1)
MG Mud User88f12472016-06-24 23:31:02 +0200226 sh = m_indices(shortcut)[pos];
Arathorn00764692019-11-27 22:09:31 +0100227
228 string* mem=map(a[I_MEMBER],#'getName/*'*/, WER);
MG Mud User88f12472016-06-24 23:31:02 +0200229 mem-=({"<MasteR>"});
230 l += ({ sprintf("%-12.12'.'s %c[%-1.1s] %|12.12' 's (%-|3' 'd) %-42.42s\n",
231 a[I_NAME], (member(m, n) != -1 ? '*' : ' '), sh,
232 a[I_MASTER] ?
233 getName(a[I_MASTER]) : getName(a[I_ACCESS]),
234 sizeof(mem),
235 (closurep(a[I_INFO]) && objectp(query_closure_object(a[I_INFO]))) ?
236 funcall(a[I_INFO]) || "- Keine Beschreibung -" :
237 (stringp(a[I_INFO]) ? a[I_INFO] : "- Keine Beschreibung -")
238 ) });
239}
240
241private mixed getChannel(string ch)
242{
Arathorn00764692019-11-27 22:09:31 +0100243 if(!sizeof(ch))
244 ch = QueryProp(P_STD_CHANNEL);
245 if(shortcut && shortcut[ch])
246 ch = shortcut[ch];
MG Mud User88f12472016-06-24 23:31:02 +0200247 return CHMASTER->find(ch, this_object());
248}
249
250#ifndef DEBUG
251#define DEBUG(x) if (funcall(symbol_function('find_player),"zesstra"))\
252 tell_object(funcall(symbol_function('find_player),"zesstra"),\
Zesstra57a693e2019-01-06 22:08:24 +0100253 "MDBG: "+x+"\n")
MG Mud User88f12472016-06-24 23:31:02 +0200254#endif
255int ChannelParser(string args)
256{
Arathorn6d465642019-11-25 21:06:07 +0100257 mixed ch;
MG Mud User88f12472016-06-24 23:31:02 +0200258 int pos, type, err;
Arathorn6d465642019-11-25 21:06:07 +0100259 string txt, tmp;
260 string|string* cmd = query_verb();
MG Mud User88f12472016-06-24 23:31:02 +0200261 args = _unparsed_args();
262 notify_fail("Benutzung: -<Ebene>[ ]['|:|;]<Text>\n"
263 " -<Ebene>[+|-|?|!|*]\n"
264 " -?\n");
265 if(!cmd && !args) return 0;
266 if(!args) args = "";
267 cmd = cmd[1..];
268 if(sizeof(cmd = regexplode(cmd,
269 "^" CHANNELCMDS "*"
270 "([+-]|\\!|\\?|\\*)*")) > 1)
271 {
272 //z.B. cmd= ({"","allgemein",":testet"})
273 if(sizeof(cmd[1]) > 1 &&
274 strstr("+-?!*", cmd[1][<1..<1]) > -1)
275 tmp = cmd[1][0..<2];
276 else
277 tmp = cmd[1];
278 if(cmd[1] != "?" && cmd[1] != "!")
Zesstra57a693e2019-01-06 22:08:24 +0100279 {
280 ch = getChannel(tmp);
281 if(pointerp(ch))
MG Mud User88f12472016-06-24 23:31:02 +0200282 {
283 notify_fail("Diese Angabe war nicht eindeutig! "
284 "Folgende Ebenen passen:\n"
285 +implode(ch, ", ")+"\n");
286 return 0;
287 }
Zesstra57a693e2019-01-06 22:08:24 +0100288 else if(!ch)
289 return (notify_fail("Die Ebene '"+tmp
290 + "' gibt es nicht!\n"), 0);
291 }
MG Mud User88f12472016-06-24 23:31:02 +0200292 //DEBUG(sprintf("ChanCmd: %O\n",cmd));
293 if (sizeof(cmd[1])) {
294 switch(cmd[1][<1]) {
295 case '+':
296 switch(CHMASTER->join(ch, this_object()))
297 {
298 case E_ACCESS_DENIED:
299 notify_fail("Du darfst an die Ebene '"+ch+"' nicht heran.\n");
300 return 0;
301 case E_ALREADY_JOINED:
302 notify_fail("Du hast diese Ebene schon betreten!\n");
303 return 0;
304 default: break;
305 }
306 write("Du betrittst die Ebene '"+ch+"'.\n");
307 if(member(QueryProp(P_CHANNELS), ch = lower_case(ch)) == -1)
308 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({ ch }));
309 return 1;
310 case '-':
311 switch(CHMASTER->leave(ch, this_object()))
312 {
313 case E_ACCESS_DENIED:
314 write("Du kannst die Ebene '"+ch+"' nicht verlassen.\n");
315 break;
316 case E_NOT_MEMBER:
317 write("Wie willst Du eine Ebene verlassen, welche Du nicht "
318 "betreten hast?\n");
319 break;
320 default:
321 write("Du verlaesst die Ebene '"+ch+"'.\n");
322 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) - ({ lower_case(ch), ch }));
323 break;
324 }
325 return 1;
326 case '!':
327 case '?':
328 {
329 mapping l;
330 if(mappingp(l = CHMASTER->list(this_object())))
Zesstra57a693e2019-01-06 22:08:24 +0100331 {
MG Mud User88f12472016-06-24 23:31:02 +0200332 if(stringp(ch) && sizeof(ch) && pointerp(l[ch = lower_case(ch)]))
333 {
334 int c; object o; string n; string *m;
335 m=sort_array(map(l[ch][I_MEMBER],#'getName/*'*/, WER),#'>/*'*/);
336 m-=({"<MasteR>"});
337 write(l[ch][I_NAME]+", "+funcall(l[ch][I_INFO])+".\n");
338 write("Du siehst "+((c = sizeof(m)) > 0
339 ? (c == 1 ? "ein Gesicht" : c+" Gesichter")
340 : "niemanden")+" auf der Ebene '"
341 +l[ch][I_NAME]+"':\n");
342 write(break_string(implode(m,", "), 78));
343 write((l[ch][I_MASTER] ?
344 getName(l[ch][I_MASTER]) : getName(l[ch][I_ACCESS], WER))
345 +" hat das Sagen auf dieser Ebene.\n");
346 }
347 else
348 {
Arathorn00764692019-11-27 22:09:31 +0100349 string* list = ({});
MG Mud User88f12472016-06-24 23:31:02 +0200350 if(cmd[1][<1] == '!')
351 l -= mkmapping(m_indices(l) - QueryProp(P_CHANNELS));
352 walk_mapping(l, #'createList/*'*/, QueryProp(P_CHANNELS), &list);
353 list = sort_array(list, #'>/*'*/);
354 txt = sprintf("%-12.12' 's [A] %|12' 's (%-3' 's) %-42.42s\n",
355 "Name", "Eigner", "Sp", "Beschreibung")
356 + "-------------------------------------------------------"
357 + "-----------------------\n"
358 + implode(list, "");
359 More(txt);
360 }
Zesstra57a693e2019-01-06 22:08:24 +0100361 }
MG Mud User88f12472016-06-24 23:31:02 +0200362 return 1;
Zesstra57a693e2019-01-06 22:08:24 +0100363
MG Mud User88f12472016-06-24 23:31:02 +0200364 }
365 case '*':
366 {
Arathorn00764692019-11-27 22:09:31 +0100367 mixed hist = CHMASTER->history(ch, this_object());
368 if(!pointerp(hist) || !sizeof(hist))
MG Mud User88f12472016-06-24 23:31:02 +0200369 {
370 write("Es ist keine Geschichte fuer '"+ch+"' verfuegbar.\n");
371 return 1;
372 }
Arathorn00764692019-11-27 22:09:31 +0100373
MG Mud User88f12472016-06-24 23:31:02 +0200374 //(Zesstra) cmd hat offenbar immer 3 Elemente...
375 //bei -all* ({"","all*",""})
376 //bei -all*10 ({"","all*,"10"})
377 //also ist bei -all* amount immer == 0 und es funktioniert eher zufaellig.
378 /*if(sizeof(cmd) > 2)
379 amount = to_int(cmd[2]);
380 else
381 amount=sizeof(hist);*/
Arathorn00764692019-11-27 22:09:31 +0100382 int amount=to_int(cmd[2]);
MG Mud User88f12472016-06-24 23:31:02 +0200383 if (amount <= 0 || amount >= sizeof(hist))
384 amount=sizeof(hist);
385
386 txt = "Folgendes ist auf '"+ch+"' passiert:\n"
387 + implode(map(hist[<amount..], #'ChannelMessage/*'*/, 1), "");
388 More(txt);
389 return 1;
390 }
391 default:
392 break;
393 }
394 }
395 }
396 if(sizeof(cmd = implode(cmd[2..], "")))
397 args = cmd + (sizeof(args) ? " " : "") + args;
398
399 // KOntrollchars ausfiltern.
400 args = regreplace(args,"[[:cntrl:]]","",RE_PCRE|RE_GLOBAL);
401 if(!sizeof(args)) return 0;
402
403 //Wenn cmd leer ist: MSG_SAY
404 if (!sizeof(cmd)) type=MSG_SAY;
405 else {
406 switch(cmd[0])
407 {
408 case ':' :
409 type = MSG_EMOTE;
410 args = args[1..];
411 break;
412 case ';' :
413 type = MSG_GEMOTE;
414 args = args[1..];
415 break;
416 case '\'':
417 args = args[1..];
418 default : type = MSG_SAY; break;
419 }
420 }
421 if(!ch || !sizeof(ch)) ch = QueryProp(P_STD_CHANNEL);
422 if((err = CHMASTER->send(ch, this_object(), args, type)) < 0)
423 if(!(err = CHMASTER->join(ch, this_object())))
424 {
425 if(member(QueryProp(P_CHANNELS), ch = lower_case(ch)) == -1)
426 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({ ch }));
427 err = CHMASTER->send(ch, this_object(), args, type);
428 }
429
430 switch(err)
431 {
432 case E_ACCESS_DENIED:
433 notify_fail("Auf der Ebene '"+ch+"' darfst Du nichts sagen.\n");
434 return 0;
435 case E_NOT_MEMBER:
436 notify_fail("Du hast die Ebene '"+ch+"' nicht betreten!\n");
437 return 0;
438 }
439 return 1;
440}
441
442int ChannelAdmin(string args)
443{
444 string n, descr, sh, cn;
Arathorn00764692019-11-27 22:09:31 +0100445 mixed tmp;
MG Mud User88f12472016-06-24 23:31:02 +0200446 args = _unparsed_args();
447 notify_fail("Benutzung: ebene <Abkuerzung>=<Ebene>\n"
448 " ebene <Abkuerzung>=\n"
449 " ebene abkuerzungen [standard]\n"
450 " ebene standard <Ebene>\n"
451 " ebene an|ein|aus\n"
452 +(QueryProp(P_LEVEL) >= 5 ?
453 " ebene neu <Name> <Bezeichnung>\n"
454 " ebene beschreibung <Name> <Beschreibung>\n" : "")
455 +(IS_ARCH(this_object()) ?
456 " ebene kill <Name>\n"
Zesstra57a693e2019-01-06 22:08:24 +0100457 " ebene clear <Name>\n": ""));
MG Mud User88f12472016-06-24 23:31:02 +0200458 if(!args || !sizeof(args)) return 0;
459 if(sscanf(args, "kill %s", n) && IS_ARCH(this_object()))
460 {
461 if(!(cn = CHMASTER->find(n, this_object()))) cn = n;
462 switch(CHMASTER->remove(cn, this_object()))
463 {
464 case E_ACCESS_DENIED:
465 notify_fail("Die Ebene '"+cn+"' lies sich nicht entfernen!\n");
466 return 0;
467 }
468 write("Du entfernst die Ebene '"+cn+"'.\n");
469 return 1;
470 }
471 if(sscanf(args, "clear %s", n) && IS_ARCH(this_object()))
472 {
473 if(!(cn = CHMASTER->find(n, this_object()))) cn = n;
474 switch(CHMASTER->clear_history(cn, this_object()))
475 {
476 case E_ACCESS_DENIED:
477 notify_fail("Der Verlauf zur Ebene '"+cn+"' lies sich nicht entfernen!\n");
478 return 0;
479 }
480 write("Du entfernst den Verlauf zur Ebene '"+cn+"'.\n");
481 return 1;
482 }
483 if(sscanf(args, "neu %s %s", n, descr) == 2)
484 {
485 mixed x;
486 if(QueryProp(P_LEVEL) < 5)
487 return (notify_fail("Neue Ebenen zu erstellen ist dir verwehrt.\n"), 0);
488 if(!sizeof(regexp(({ n }), "^" CHANNELCMDS CHANNELCMDS "*")))
489 return (notify_fail("Der Name '"+n+"' ist nicht konform!\n"), 0);
490 if (sizeof(n) > 20 )
491 return(notify_fail("Der Name '"+n+"' ist zu lang.\n"), 0);
492 switch(x = CHMASTER->new(n, this_object(), descr))
493 {
494 case E_ACCESS_DENIED:
495 notify_fail("Diese Ebene darfst du nicht erschaffen!\n"); break;
496 default:
497 write("Du erschaffst die Ebene '"+n+"'.\n");
498 SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({ lower_case(n) }));
499 return 1;
500 }
501 }
502 if(sscanf(args, "beschreibung %s %s", n, descr) == 2)
503 {
504 mixed ch;
505 cn = CHMASTER->find(n, this_object());
506 if(!cn || pointerp(cn))
507 return (notify_fail("Die Ebene '"+n+"' existiert nicht oder die Angabe "
508 "war nicht eindeutig.\n"), 0);
509 ch = CHMASTER->list(this_object());
510 if(ch[lower_case(cn)][I_MASTER] != this_object())
511 return (notify_fail("Du bist nicht berechtigt die Beschreibung der Ebene"
512 " '"+cn+"' zu aendern.\n"), 0);
513 ch[lower_case(cn)][I_INFO] = descr;
514 write("Die Ebene '"+cn+"' hat ab sofort die Beschreibung:\n"+descr+"\n");
515 return 1;
516 }
517 if(sscanf(args, "%s=%s", sh, n) == 2 && sizeof(n))
518 {
519 mapping sc;
520 if(pointerp(tmp = CHMASTER->find(n, this_object())) || !tmp)
521 return (notify_fail("Benutzung: ebene <Abkuerzung>=<Ebene>\n"
522 +(pointerp(tmp) ? implode(tmp, ", ") + "\n" :
523 "Ebene '"+n+"' nicht gefunden!\n")), 0);
524 sc = QueryProp(P_CHANNEL_SHORT);
525 if(!sc) sc = ([]);
526 sc[sh] = tmp;
527 SetProp(P_CHANNEL_SHORT, sc);
528 shortcut = QueryProp(P_CHANNEL_SHORT);
529 write("'"+sh+"' wird jetzt als Abkuerzung fuer '"+tmp+"' anerkannt.\n");
530 return 1;
531 }
532 if(sscanf(args, "%s=", sh))
533 {
534 SetProp(P_CHANNEL_SHORT, m_copy_delete(QueryProp(P_CHANNEL_SHORT) || ([]), sh));
535 shortcut = QueryProp(P_CHANNEL_SHORT);
536 write("Du loeschst die Abkuerzung '"+sh+"'.\n");
537 return 1;
538 }
539 if(args == "an" || args == "ein")
540 {
541 mixed excl;
542 if(pointerp(QueryProp(P_SWAP_CHANNELS)))
543 SetProp(P_CHANNELS, QueryProp(P_SWAP_CHANNELS));
544 else
545 SetProp(P_CHANNELS, m_indices(CHMASTER->list(this_object())));
546 excl = RegisterChannels();
547 write("Du schaltest folgende Ebenen ein:\n"
548 +break_string(implode(QueryProp(P_CHANNELS) - excl, ", "), 78));
549 SetProp(P_SWAP_CHANNELS, 0);
550 return 1;
551 }
552 if(args == "aus")
553 {
554 SetProp(P_SWAP_CHANNELS, QueryProp(P_CHANNELS));
555 RemoveChannels();
556 SetProp(P_CHANNELS, ({}));
557 write("Du stellst die Ebenen ab.\n");
558 return 1;
559 }
Arathorn00764692019-11-27 22:09:31 +0100560 string* pa = old_explode(args, " ");
MG Mud User88f12472016-06-24 23:31:02 +0200561 if(!strstr("abkuerzungen", pa[0]))
562 {
563 string txt; txt = "";
564 if(sizeof(pa) > 1 && !strstr("standard", pa[1]))
565 {
566 write("Die Standard Abkuerzungen werden gesetzt.\n");
567 SetProp(P_CHANNEL_SHORT, DEFAULT_SHORTCUTS
568 + (IS_LEARNER(this_object()) ? WIZARD_SHORTCUTS : ([])));
569 }
Arathorndc28afc2018-11-26 22:20:59 +0100570 foreach(string abk, string ch_name : QueryProp(P_CHANNEL_SHORT)) {
571 txt += sprintf("%5.5s = %s\n", abk, ch_name);
572 }
MG Mud User88f12472016-06-24 23:31:02 +0200573 txt = sprintf("Folgende Abkuerzungen sind definiert:\n%-78#s\n",
574 implode(sort_array(old_explode(txt, "\n"), #'>/*'*/), "\n"));
575 More(txt);
576 return 1;
577 }
578 if(!strstr("standard", pa[0]))
579 if(sizeof(pa) < 2)
580 return (notify_fail("Benutzung: ebene standard <Ebene>\n"
581 +(QueryProp(P_STD_CHANNEL)
582 ? "Momentan ist '"+QueryProp(P_STD_CHANNEL)
583 +"' eingestellt.\n"
584 : "Es ist keine Standardebene eingestellt.\n")),0);
585 else
586 if(pointerp(tmp = CHMASTER->find(pa[1], this_object())))
587 return (notify_fail("Das war keine eindeutige Angabe! "
588 "Folgende Ebenen passen:\n"
589 +break_string(implode(tmp, ", "), 78)), 0);
590 else
591 if(!tmp) return (notify_fail("Ebene '"+pa[1]+"' nicht gefunden!\n"),0);
592 else
593 {
594 write("'"+tmp+"' ist jetzt die Standardebene.\n");
595 SetProp(P_STD_CHANNEL, tmp);
596 return 1;
597 }
598 return(0);
599}
600