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