SharpScript » History » Sprint/Milestone 1
Vincent Le Goff, 12/05/2018 07:59 PM
1 | 1 | Vincent Le Goff | h1. Scripting in project:cocomud-client |
---|---|---|---|
2 | |||
3 | |||
4 | |||
5 | project:cocomud-client offers a simple yet easily-extendable scripting language. This language can be used to describe macros, aliases or triggers, or more complex features in the MUD. |
||
6 | |||
7 | |||
8 | |||
9 | This document describes the syntax of SharpScript, gives examples and provides frequent questions at the bottom of each section. If you want the answer to one of these questions, just click on the question, the answer will appear on the next line. |
||
10 | |||
11 | |||
12 | |||
13 | {{toc}} |
||
14 | |||
15 | |||
16 | |||
17 | h2. The SharpScript logic |
||
18 | |||
19 | |||
20 | |||
21 | The logic of the SharpScript can be summarized in two main ideas: |
||
22 | |||
23 | |||
24 | |||
25 | * Have a very easy-to-write language to perform simple functions ; |
||
26 | |||
27 | * Allow to include Python code in this language to perform more complex tasks. |
||
28 | |||
29 | |||
30 | |||
31 | As you will see, the syntax of the SharpScript is pretty light, but it already allows interesting features. Should you need more, Python is here, and it's not exactly a limited alternative. |
||
32 | |||
33 | |||
34 | |||
35 | h2. Basic syntax |
||
36 | |||
37 | |||
38 | |||
39 | The SharpScript finds its name in its syntax. As most MUD clients, a SharpScript command begins with a sharp symbol (@#@). It can already feel like a constraint of some type, but maintaining the difference between commands to the server and to the clients is important. Unlike most MUD clients, project:cocomud-client tries to not force symbol in user input. If you want to send a message beginning with the sharp symbol, you can do so, unless you configure your client to interpret SharpScript as input. |
||
40 | |||
41 | |||
42 | |||
43 | h2. Commands |
||
44 | |||
45 | |||
46 | |||
47 | SharpScript features are kept in commands (or functions). Both terms refer to the same thing in this documentation. These commands can ask to create a [[Macro|macro]], an [[Alias|alias]], a [[Trigger|trigger]], send some message to the server, display some message to the client, prompt the client with a question, store some information about a character and so on. |
||
48 | |||
49 | |||
50 | |||
51 | Here's a single example: |
||
52 | |||
53 | |||
54 | |||
55 | <pre> |
||
56 | |||
57 | #say Hello! |
||
58 | |||
59 | </pre> |
||
60 | |||
61 | |||
62 | |||
63 | If you try this piece of SharpScript in an input that accepts SharpScript syntax, the client should display "Hello!" at the bottom of your screen. The text should also be sent to the screen reader, spoken by it and displayed on a Braille display, if supported. |
||
64 | |||
65 | |||
66 | |||
67 | The @#say@ command that we have used is very simple: It expects one argument, one information, which is the message to be displayed. |
||
68 | |||
69 | |||
70 | |||
71 | Frequent questions: |
||
72 | |||
73 | |||
74 | |||
75 | {{collapse(How to send a command with a sharp symbol (#) in it?) |
||
76 | |||
77 | By default, project:cocomud-client doesn't interfere with your playing. When you are in the input field on the client, you cannot enter SharpScript unless you enable that setting. So you can type about every symbol you want, none of them will be interpreted by the client. |
||
78 | |||
79 | |||
80 | |||
81 | However, at times, you really want to send sharp signs to the client while having SharpScript interpret part of your commands. To do so, you must precede the sharp sign (#) with another one. This syntax is only necessary at the beginning of a command or an argument: |
||
82 | |||
83 | |||
84 | |||
85 | <pre> |
||
86 | |||
87 | #say {{##I'm saying something with a #.} |
||
88 | |||
89 | </pre> |
||
90 | |||
91 | |||
92 | |||
93 | This will display: @#I'm saying something with a #.@ |
||
94 | |||
95 | |||
96 | |||
97 | Notice that only the first sharp symbol had to be kept twice (at the beginning of the argument). The other (at the end) didn't need to be escaped. |
||
98 | |||
99 | |||
100 | |||
101 | <pre> |
||
102 | |||
103 | ##forward |
||
104 | |||
105 | </pre> |
||
106 | |||
107 | |||
108 | |||
109 | This will send @#forward@ to the client. |
||
110 | |||
111 | }} |
||
112 | |||
113 | |||
114 | |||
115 | h2. Arguments with spaces |
||
116 | |||
117 | |||
118 | |||
119 | If you try to display a message with spaces, it will not work: |
||
120 | |||
121 | |||
122 | |||
123 | <pre> |
||
124 | |||
125 | #say This character isn't feeling so well. |
||
126 | |||
127 | </pre> |
||
128 | |||
129 | |||
130 | |||
131 | Some commands take more than one argument, and to separate them, they use the space (we will see examples a little below). Therefore, if you want to have spaces in your argument, you should surround it by braces ({}) : |
||
132 | |||
133 | |||
134 | |||
135 | <pre> |
||
136 | |||
137 | #say {This character isn't feeling so well.} |
||
138 | |||
139 | </pre> |
||
140 | |||
141 | |||
142 | |||
143 | Surrounding arguments by braces is only necessary if this argument contains spaces. Consider the following example, to create a [[Macro|macro]]: |
||
144 | |||
145 | |||
146 | |||
147 | <pre> |
||
148 | |||
149 | #macro F1 north |
||
150 | |||
151 | </pre> |
||
152 | |||
153 | |||
154 | |||
155 | This time, the @#macro@ command expects two arguments: |
||
156 | |||
157 | |||
158 | |||
159 | * The shortcut to which this macro should react. |
||
160 | |||
161 | * The action to be performed. |
||
162 | |||
163 | |||
164 | |||
165 | Here, when we press F1, the client will send "north" to the server. |
||
166 | |||
167 | |||
168 | |||
169 | Remember to enclose the arguments containing spaces, however: |
||
170 | |||
171 | |||
172 | |||
173 | <pre> |
||
174 | |||
175 | #macro {Ctrl + F1} north |
||
176 | |||
177 | </pre> |
||
178 | |||
179 | |||
180 | |||
181 | This time, the shortcut is Ctrl + F1. Because there are spaces in this argument, we enclose it in braces. |
||
182 | |||
183 | |||
184 | |||
185 | <pre> |
||
186 | |||
187 | #macro F8 {say Greetings!} |
||
188 | |||
189 | </pre> |
||
190 | |||
191 | |||
192 | |||
193 | When we press F8, the client will send "say greetings!" to the server. |
||
194 | |||
195 | |||
196 | |||
197 | <pre> |
||
198 | |||
199 | #macro {Ctrl + Shift + K} {look into backpack} |
||
200 | |||
201 | </pre> |
||
202 | |||
203 | |||
204 | |||
205 | Since both arguments contain spaces, we enclose them both. |
||
206 | |||
207 | |||
208 | |||
209 | Notice that if you have a doubt, use braces. It will work regardless: |
||
210 | |||
211 | |||
212 | |||
213 | <pre> |
||
214 | |||
215 | #macro {F1} {north} |
||
216 | |||
217 | </pre> |
||
218 | |||
219 | |||
220 | |||
221 | h2. Multi-line scripts |
||
222 | |||
223 | |||
224 | |||
225 | By default, SharpScript expects every command to be on a different line. This is not always a good thing for readability's sake, and sometimes it can get really complicated. |
||
226 | |||
227 | |||
228 | |||
229 | Let's say we want to create the [[Alias|alias]] as follows: When we enter "victory", the client plays a sound and sends a few commands to the server: |
||
230 | |||
231 | |||
232 | |||
233 | <pre> |
||
234 | |||
235 | #alias victory { |
||
236 | |||
237 | #play victory.wav |
||
238 | |||
239 | say I've done it! |
||
240 | |||
241 | north |
||
242 | |||
243 | #wait 3 |
||
244 | |||
245 | sheathe sword |
||
246 | |||
247 | } |
||
248 | |||
249 | </pre> |
||
250 | |||
251 | |||
252 | |||
253 | The second argument is split on several lines, because it's much more readable. Notice here that the argument contains SharpScript commands (beginning with a sharp symbol) and commands to be sent to the server. The lines not beginning with a sharp symbol (#) are sent as it to the server. This is the case for the line 3 (say I've done it!) for instance. |
||
254 | |||
255 | |||
256 | |||
257 | For readability, the second argument is indented a little on the right: Each command in this second argument stands 4 space on the right. This is not mandatory, it just makes things easier to understand. Since Python relies on indentation however, it might be a good thing to get used to it, regardless of its being necessary or not. |
||
258 | |||
259 | |||
260 | |||
261 | Frequent questions: |
||
262 | |||
263 | |||
264 | |||
265 | {{collapse(Can I put several instructions on a single line?) |
||
266 | |||
267 | You can, although it might not be very readable. The syntax to do so is to use semi-colons to separate commands on a single line. The previous example could be written on a single line like this: |
||
268 | |||
269 | |||
270 | |||
271 | <pre> |
||
272 | |||
273 | #alias victory {#play victory.wav;say I've done it!;north;#wait 3;sheathe sword} |
||
274 | |||
275 | </pre> |
||
276 | |||
277 | |||
278 | |||
279 | As you can see, it's not as readable, but this syntax may sometimes be useful. |
||
280 | |||
281 | |||
282 | |||
283 | If you want o write a semi-colon in your SharpScript command, just put two semi-colons instead of one: |
||
284 | |||
285 | |||
286 | |||
287 | <pre> |
||
288 | |||
289 | #say {I would like to display something;; but I'm not sure what.} |
||
290 | |||
291 | </pre> |
||
292 | |||
293 | }} |
||
294 | |||
295 | |||
296 | |||
297 | h2. Flags |
||
298 | |||
299 | |||
300 | |||
301 | Some commands support flags: Flags are here to influence the behavior of a function in some way. The best example available at this time is the @#say@ command we have seen. By default, it displays the provided text, sends it to the screen reader to be spoken, and to the Braille display to be displayed. There are three flags that control that: |
||
302 | |||
303 | |||
304 | |||
305 | * "screen": Should the text be displayed on the screen (as if it were coming from the server)? If you don't change it, it's on by default. |
||
306 | |||
307 | * "speech": Should the text be sent to the screen reader to be spoken aloud? Once again, if not changed, it's on. |
||
308 | |||
309 | * "braille": Should the text be sent to the Braille display? Again, this flag is on by default. |
||
310 | |||
311 | |||
312 | |||
313 | You can change flags given to a command at the end of the SharpScript line (or instruction). To set a flag on, write its name after a plus sign (+). If you want to set this flag off, write its name after a minus sign (-). |
||
314 | |||
315 | |||
316 | |||
317 | <pre> |
||
318 | |||
319 | #say {I don't want it to be displayed.} -screen |
||
320 | |||
321 | #say {And that shouldn't be spoken nor displayed in Braille.} -speech -braille |
||
322 | |||
323 | #say {This may be displayed on screen and on the Braille display.} +screen -speech +braille |
||
324 | |||
325 | </pre> |
||
326 | |||
327 | |||
328 | |||
329 | Notice that the flags "screen" and "braille" are not necessary in the last example: Both are on by default. This example is here to illustrate the syntax. |
||
330 | |||
331 | |||
332 | |||
333 | h2. Embedding Python into SharpScript |
||
334 | |||
335 | |||
336 | |||
337 | Sometimes, what we want to do is a bit too complex in SharpScript. It's possible to extend its syntax and bring new commands into it, but it's better to keep it simple and to learn to do more complex things with Python, which is a highly-readable language without few limitations. It's still a good thing to keep your script readable, not only for you (although it might be handy, should you modify it), but to potential users. |
||
338 | |||
339 | |||
340 | |||
341 | To add Python code, use the syntax for long arguments (with braces), but after the left brace, add a plus sign (+). This tells the client that what follows between the braces isn't SharpScript, but Python code. |
||
342 | |||
343 | |||
344 | |||
345 | If we want to write a script that plays different sounds depending on the XP we receive, we might do it that way: |
||
346 | |||
347 | |||
348 | |||
349 | <pre> |
||
350 | |||
351 | #trigger {You received {xp} XP.} {+ |
||
352 | |||
353 | # The 'xp' variable contains the received XP |
||
354 | |||
355 | # It might be a number, but we have to convert it |
||
356 | |||
357 | if xp.isdigit(): |
||
358 | |||
359 | if xp > 200: |
||
360 | |||
361 | play("victory.wav") |
||
362 | |||
363 | elif xp > 100: |
||
364 | |||
365 | play("notbad.wav") |
||
366 | |||
367 | elif xp > 10: |
||
368 | |||
369 | play("notalot.wav") |
||
370 | |||
371 | } |
||
372 | |||
373 | </pre> |
||
374 | |||
375 | |||
376 | |||
377 | This trigger will wait for the line @"You received *** XP."@ and will put whatever XP in the 'xp' variable, before passing it to the Python script. The Python script will convert the XP (if it's a number) and will play a different sound: |
||
378 | |||
379 | |||
380 | |||
381 | * If the received XP is over 200, it will play "victory.wav". |
||
382 | |||
383 | * If it's between 100 and 200, it will play "notbad.wav". |
||
384 | |||
385 | * If it's between 10 and 100, it will play "notalot.wav". |
||
386 | |||
387 | |||
388 | |||
389 | Notice that nothing happens if you receive less than 10 XP in this example. |
||
390 | |||
391 | |||
392 | |||
393 | It's very useful to embed Python code into SharpScript that way. It makes for clear and readable scripts that are almost limitless. Keep the indentation in this example, as it will be used by Python to determine blocks. |
||
394 | |||
395 | |||
396 | |||
397 | Frequent questions: |
||
398 | |||
399 | |||
400 | |||
401 | {{collapse(Which functions are available in embedded Python?) |
||
402 | |||
403 | All SharpScript commands are available as functions. That's why you can use the @#play@ or @#say@ command. Inside of Python, the commands are not preceded by a sharp sign and are just respect the function syntax: |
||
404 | |||
405 | |||
406 | |||
407 | <pre> |
||
408 | |||
409 | say("Could you display that?") |
||
410 | |||
411 | say("After all, just speak that.", screen=False) |
||
412 | |||
413 | play("sound/file.ogg") |
||
414 | |||
415 | </pre> |
||
416 | |||
417 | }} |
||
418 | |||
419 | {{collapse(What variables are available in embedded Python?) |
||
420 | |||
421 | Python scripts share their variable across the entire game setting. This can sometimes be confusing, but it also prevents from bad headaches if you remember that no variable defined in a script will magically disappear unless you close the program. Therefore, if you have a script like this: |
||
422 | |||
423 | |||
424 | |||
425 | <pre> |
||
426 | |||
427 | #alias todo {+ |
||
428 | |||
429 | health = 38 |
||
430 | |||
431 | } |
||
432 | |||
433 | </pre> |
||
434 | |||
435 | |||
436 | |||
437 | The variable 'health' will be available in all other Python scripts. |
||
438 | |||
439 | |||
440 | |||
441 | In some cases, other variables are defined by the client. For instance, the @#trigger@ command creates variables depending on the trigger. For more information, read [[Trigger|the section about triggers]]. |
||
442 | |||
443 | }} |