blob: b0d4b12460a8ad61da4fede0a0afc8884fb8200a [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// usercmd.c -- Modul fuer benutzerdefinierte Befehle
2//
3// (c) 1995 Wargon@MorgenGrauen
4//
5// $Id: usercmd.c,v 1.4 2003/11/15 13:48:46 mud Exp $
6//
7
8#define NEED_PROTOTYPES
9#include "../haus.h"
10#include <properties.h>
11#include <wizlevels.h>
12#include <thing/properties.h>
Zesstraefd3aa52016-08-31 22:38:26 +020013#include <thing/commands.h>
MG Mud User88f12472016-06-24 23:31:02 +020014
15private string ucFilter(string str);
16private string ucText(string str);
17private void splitCmd(string *cmd, string *verb, string *para);
18
Zesstraefd3aa52016-08-31 22:38:26 +020019protected void create()
MG Mud User88f12472016-06-24 23:31:02 +020020{
21 Set(H_COMMANDS, SAVE, F_MODE);
22 Set(H_COMMANDS, ([]));
23
24 AddCmd("", "userCommands", 1);
25}
26
27/*
28 * AddUserCmd: eigenes Kommando hinzufuegen
29 * cmd: String oder Array von Strings. Enthaelt entweder nur die Verben oder
30 * die kompletten Befehle (Verb + Parameter). Siehe auch pa.
31 * pa: Zahl oder Array von Strings. Falls pa eine Zahl ist, so enthaelt cmd
32 * die kompletten Befehle (samt Parametern). Ansonsten enthaelt pa die
33 * Parameter fuer das entsprechende Verb in cmd.
34 * Ist pa = ({ "@NF@"}) , so handelt es sich um ein notify_fail, das an
35 * die Beschreibung des Verbs (falls vorhanden) angehaengt wird.
36 * me: Text fuer den Ausfuehrenden. Der Text muss schon geparsed worden
37 * sein!
38 * oth: Text fuer die Umstehenden oder 0. Der Text muss schon geparsed wor-
39 * den sein!
40 */
41varargs void
42AddUserCmd(mixed cmd, mixed pa, string me, string oth)
43{
44 int v,p;
45 mapping cmds, desc;
46 string *verb, *para, txt;
47
48 cmds = Query(H_COMMANDS);
49 if (stringp(cmd))
50 verb = ({ cmd });
51 else
52 verb = cmd;
53
54 if (intp(pa))
55 splitCmd(verb[0..], &verb, &para);
56 else {
57 if (stringp(pa))
58 para = ({ pa });
59 else if (pointerp(pa))
60 para = pa;
61 for (desc = ([]), p=sizeof(para)-1; p>=0; p--)
62 desc += ([ para[p] : me; oth ]);
63 }
64
65 for (v = sizeof(verb)-1; v>= 0; v--) {
66 if (member(cmds, verb[v])) {
67 if (intp(pa))
68 cmds[verb[v]] += ([para[v] : me; oth ]);
69 else
70 cmds[verb[v]] += desc;
71 }
72 else {
73 if (intp(pa))
74 cmds += ([ verb[v] : ([para[v] : me; oth ]) ]);
75 else
76 cmds += ([ verb[v] : desc ]);
77 }
78 }
79 Set(H_COMMANDS, cmds);
80}
81
82/*
83 * RemUserCmd: Kommando(s) wieder entfernen
84 * com: String oder Array von Strings. Enthaelt das zu loeschende Kommando
85 * (Verb oder Verb + Parameter).
86 * all: Falls != 0, so werden die Verben aus com komplett mit allen Para-
87 * metern geloescht.
88 */
89varargs void
90RemUserCmd(mixed com, int all)
91{
92 mapping cmd, tmp;
93 string *verb, *para;
94 int v, p;
95
96 cmd = Query(H_COMMANDS);
97 splitCmd(stringp(com) ? ({com}) : com, &verb, &para);
98
99 if (all)
100 for (v=sizeof(verb)-1; v>=0; v--)
101 cmd = m_copy_delete(cmd, verb[v]);
102 else {
103 for (v=sizeof(verb)-1; v>=0; v--) {
104 if (tmp = cmd[verb[v]]) {
105 for (p=sizeof(para)-1; p>=0; p--)
106 tmp = m_copy_delete(tmp, para[p]);
107 cmd[verb[v]] = tmp;
108 }
109 }
110 }
111 Set(H_COMMANDS,cmd);
112}
113
114/*
115 * userCommands: Auswertung der benutzerdefinierten Befehle.
116 */
117static int
118userCommands(string str)
119{
120 mapping ucmd, uparm;
121 string *parts, text;
122 int i;
123
124 ucmd = QueryProp(H_COMMANDS);
125 str = this_player()->_unparsed_args(1)||"";
126 if (uparm = ucmd[query_verb()]) {
127 if (member(uparm, str)) {
128 text = ucText(uparm[str,0]);
129 if (sizeof(old_explode(text, "\n")) >= this_player()->QueryProp(P_SCREENSIZE))
130 this_player()->More(capitalize(text)[0..<2]);
131 else
132 write(capitalize(text));
133
134 if (uparm[str,1])
135 say(ucText(uparm[str,1]));
136
137 if (member(m_indices(QueryProp(P_EXITS)), query_verb()) == -1)
138 return 1;
139 }
140 else {
141 if (str && str != "" && text = uparm["@NF@"])
142 notify_fail(implode(old_explode(text,"@F"),str));
143 }
144 }
145 return 0;
146}
147
148/*** Functions private to this module... ***/
149
150/*
151 * ucFilter: Ersetzen von Name, Personal- und Possessivpronomen.
152 * Gibt den ersetzten String zurueck.
153 */
154private string
155ucFilter(string str)
156{
157 int p,g;
158
159 switch(str[0..1]) {
160 case "@W": // Name in entsprechendem Fall...
161 return this_player()->name(to_int(str[2..2]));
162 case "@P": // Personalpronomen in entprechendem Fall...
163 return this_player()->QueryPronoun(to_int(str[2..2]));
164 case "@B": // Possesivpronomen in entprechendem Fall...
165 p = to_int(str[4..4]);
166 g = to_int(str[3..3]);
167 return this_player()->QueryPossPronoun(g, to_int(str[2..2]), p);
168 }
169 return str;
170}
171
172/*
173 * ucText: Rassen- und geschlechtsspezifische Teile bearbeiten sowie
174 * Namen und Pronomina einsetzen.
175 *
176 * str enthaelt den String, der beim Beschreiben des Befehls
177 * eingegeben wurde. Bis auf den Default-Text sind alle Teile
178 * optional. Der String kann folgenden Aufbau haben:
179 * ------ schnipp ------
180 * Default-Text, der ausgegeben wird, wenn die folgenden spezielleren
181 * Texte nicht auftreten oder auf den Ausfuehrenden nicht zutreffen
182 * @NAME:nameA
183 * Text, der ausgegeben wird, wenn der Spieler "nameA" das Kommando
184 * eingegeben hat
185 * @NAME:nameB
186 * Und so weiter fuer Spieler "nameB" etc...
187 * @RA
188 * Text, der ausgegeben wird, wenn der Ausfuehrende auf der Erlaube-
189 * Liste des Hauses steht.
190 * @RE
191 * Text, der ausgegeben wird, wenn der Ausfuehrende ein Elf
192 * ist. Ebenso gibt es @RD fuer Dunkelelfen, @RF fuer Felinen,
193 * @RH fuer Hobbits, @RM fuer Menschen, @RG fuer Goblins und @RZ
194 * fuer Zwerge.
195 * ------ schnapp ------
196 *
197 * Der Default-Text muss immer am Anfang stehen. Die anderen Bloecke
198 * koennen in beliebiger Reihenfolge folgen. Die Reihenfolge, in der
199 * die Bloecke betrachtet werden, ist dabei folgende:
200 * - zuerst werden @NAME-Bloecke untersucht
201 * - dann wird @RA (Erlaube-Liste) getestet
202 * - danach wird die Rasse ueberprueft (@RD/@RE/@RF/@RH/@RM/@RZ/@RG)
203 * - zuletzt wird der Default-Text betrachtet
204 *
205 * Innerhalb jedes der Bloecke kann man noch mit @G zwischen
206 * maennlichen und weiblichen Vertretern unterscheiden (bei @NAME:
207 * macht das aber wenig Sinn). Beispiel:
208 * ------ schnipp ------
209 * @RZ
210 * Der Zwerg war maennlich
211 * @G
212 * Der Zwerg war weiblich
213 * ------ schnapp ------
214 *
215 * Die Funktion gibt den fuer den Ausfuehrenden zutreffenden Text
216 * zurueck.
217 */
218private string
219ucText(string str)
220{
221 string *parts, *names, *lnames;
222 int i, n;
223
224 // Text nach Namen- und Rassentrennern aufteilen
225 parts = regexplode(str, "(@NAME:[A-Za-z1-9]*\n)|(@R[A-Z]\n)");
226 i = -1;
227
228 if (sizeof(parts) > 1) {
229
230 // Zuerst wird nach Namenstrennern gesucht
231 names = regexp(parts, "@NAME:");
232
233 if (sizeof(names) > 0) {
234 // ein kleiner Umweg, da der Name im Eingabestring nicht
235 // notwendigerweise in Kleinbuchstaben vorliegt.
236 lnames = map(names, #'lower_case);
237 n = member(lnames, "@name:"+getuid(this_player())+"\n");
238
239 if (n >= 0) {
240 i = member(parts, names[n]);
241 }
242 }
243
244 // Kein passender Namenstrenner gefunden: Erlaube-Liste
245 // ueberpruefen
246 if (i<0 && allowed_check(this_player())) {
247 i=member(parts, "@RA\n");
248 }
249
250 // Weder Namenstrenner noch Erlaube-Liste passen: Rasse
251 // ueberpruefen
252 if (i<0) {
253 switch(this_player()->QueryProp(P_RACE)) {
254 case "Zwerg":
255 i=member(parts, "@RZ\n");
256 break;
257 case "Elf":
258 i=member(parts, "@RE\n");
259 break;
260 case "Feline":
261 i=member(parts, "@RF\n");
262 break;
263 case "Hobbit":
264 i = member(parts, "@RH\n");
265 break;
266 case "Dunkelelf":
267 i = member(parts, "@RD\n");
268 break;
269 case "Goblin":
270 i = member(parts, "@RG\n");
271 break;
272 case "Ork":
273 i = member(parts, "@RO\n");
274 break;
275 default:
276 i=member(parts, "@RM\n");
277 break;
278 }
279 }
280
281 // Den richtigen Teil des Strings herauspicken
282 if (i>-1)
283 str = parts[i+1];
284 else
285 str = parts[0];
286 }
287 if (sizeof(parts = old_explode(str, "@G\n"))==2)
288 str = parts[(this_player()->QueryProp(P_GENDER) == MALE ? 0 : 1)];
289
290 parts = regexplode(str, "(@W[0-3]|@P[0-3]|@B[0-3][0-2][0-1])");
291 parts = map(parts, #'ucFilter);
292 return implode(parts, "");
293}
294
295/*
296 * splitCmd: Komplettes Kommando in Arrays von Verben und Parametern zerlegen.
297 * cmd: Array von Strings. Dieses Array enthaelt die aufzuspaltenden Befehle.
298 * verb: Referenz auf ein Array von Strings fuer die Verben.
299 * para: Referenz auf ein Array von Strings fuer die Parameter.
300 */
301private void splitCmd(string *cmd, string *verb, string *para)
302{
303 int c, sp;
304
305 for (verb = ({}), para = ({}), c = sizeof(cmd)-1; c>=0; c--) {
306 if ((sp=member(cmd[c], ' ')) >= 0) {
307 verb += ({ cmd[c][0..sp-1] });
308 para += ({ cmd[c][sp+1..] });
309 }
310 else {
311 verb += ({ cmd[c] });
312 para += ({ "" });
313 }
314 }
315}
316
317// $Log: usercmd.c,v $
318// Revision 1.4 2003/11/15 13:48:46 mud
319// @RD als Trenner fuer Dunkelelfen
320//
321// Revision 1.3 2000/12/03 17:15:40 mud
322// ucText: Neuer Trenner @NAME:foo, mit dem man in Seherhausbefehlen
323// Texte fuer bestimmte Spieler vorsehen kann.
324//
325// Revision 1.2 2000/08/20 20:38:40 mud
326// @RF als Trenner fuer Felinen
327//
328// Revision 1.1.1.1 2000/08/20 20:22:42 mud
329// Ins CVS eingecheckt
330//
331// Revision 1.4 1996/04/19 23:10:52 Wargon
332// @RA fuer Leute mit Erlaubnis
333//
334// Revision 1.3 1995/10/31 12:59:52 Wargon
335// @RH fuer Hobbits
336//
337// Revision 1.2 1995/06/22 19:48:31 Wargon
338// Bugfix in userCommands()
339//
340// Revision 1.1 1995/04/21 09:22:50 Wargon
341// Initial revision
342//