I'm finally trying to learn how to code some simple stuff in mudlet, or at least I feel like it should be simple. The manuals discussing regex and variables and stuff might as well be written in chinese, though, for all the sense I can make of them. Here's one example of what I'm trying to do:
I want to make one single alias for my transmology hands. So, I type "cut hands" "blunt hands" or "magic hands" and this one alias sends the relevant command.
Second, since my bashing attack is different depending on which hands I pick, I would like to type "bash" and it automatically sends the appropriate command for whichever hands I picked in the first alias.
If anybody is willing to help me here to show me exactly how to do these two aliases, I would greatly appreciate it since the majority of the other stuff I'm trying to make follows the same principles.
Mayor Steingrim, the Grand Schema says to you, "Well, as I recall you kinda leave a mark whereever you go."
Comments
Pattern: ^cut hands$
Codebox:
send("fleshcall hands claws")
handstype = "cutting"
Pattern: ^bash (\w+)$
Codebox:
if handstype == "cutting" then
send("fleshform claw " .. matches[2])
elseif handstype == "blunt" then
send("fleshform crush " .. matches[2])
else
echo("You didn't set any hands! Set it now with CUT HANDS or BLUNT HANDS!")
end
'server' - where Imperian is hosted
- a word or pattern you key in that represents something else, for
example typing in 'pg' would become 'put gold in pack' and then sent to the server
- a pattern for your client to react to, for example, someone smiling
at me could be triggered so I say hi! to the person in response
- a machine that interprets some data and returns you something else,
for example, your ATM machine processes your card and gives you your money
listener' - a machine that waits for some specific data and then
returns you something else, for example, -when- the clock hits ten
AM, the bell rings (to signal recess!), for this to work, someone (or
something) needs to pay attention to the clock... this is what we call an event listener (the person who watches the clock!)
- the lazy man's way of trying to show the ideas behind a code, that
is, it won't run, but the general idea is there!
2) Navigating Mudlet
- see how one trigger has a little ladybug over it? This means there is
something wrong with the trigger. You'll need to fix it before it
works! This little ladybug is generally true for all the other things
like scripts/aliases as well! Also see how the trigger above it has
a little green tick? This means the trigger is turned on! If the box is
not ticked, it may not work! So if something's not working, check to see if this tick is present.
- this is what I call the 'code box'! This is where all the special
stuff goes in to make it all work! That is, when the pattern is received, this is what the machine runs (executes)
- this is the 'name box'! You can name your triggers what ever you
like. There are only very few circumstances where names actually matter: a) when you want to turn them on/off with code, b) for 'event listeners'
- this is the 'trigger type box'! Here is where you decide what kind of
'trigger' your trigger grows up to be! They can meet very different conditions, so you'll want to learn to play with this!
3) Triggers
Bit longer of a spoiler...
- there are several types of trigger types, and the ones I use the most
are 'regex', 'Lua function' and the occasional 'color trigger'
- let's take for example our basic trigger from earlier! What if we
meet this really sweet woman named Aulani and she loves to grin evilly
too? What if we want to stick out our tongue at her too? We could make
another copy of the same trigger, except for swapping Aleutia with Aulani.
- the concept is this: we replace changeable words and symbols with our
own special symbols so the machine can accept more than one correct answer!
- for example, instead of 'Aleutia rubs her hands together and grins
evilly at you.', we now have '\w+ rubs her hands together and grins evilly at you.'
- now our machine will accept both 'Aleutia rubs her hands together and
grins evilly at you.' and 'Aulani rubs her hands together and grins evilly at you.' and send 'tongue Aleutia' when this happens!
- how does this happen? the symbol '\w+' is interpreted by our machine
as a 'word'! So any word would be 'OK' with it and it would run the stuff in the 'code box'! So instead of two patterns, we now have 1 pattern that will fit two (and more!) situations!
- we now change our pattern from 'Aleutia rubs her hands together and
grins evilly at you.' to '\w+ rubs her hands together and grins evilly at you.'
- what does this do? this 'captures', that is, it 'saves' or
'remembers' this information! Remember that \w+ represents a word, any word. Now the word that matches the pattern is remembered!
- In this situation, if 'Iniar rubs her hands together and grins evilly
at you.' is sent to you by the Imperian server, it will 'trigger'
off the pattern '(\w+) rubs her hands together and grins evilly at
you.' and the name 'Iniar' will be saved! To use this information, use: matches[2]
- this will now send 'tongue Aulani' when Aulani grins evilly at you,
'tongue Aleutia' when Aleutia grins evilly at you, and in fact, any female that grins evilly at you, you can stick your tongue out at them!
- take for example the word 'name'. In Lua (the language of Mudlet) if
we did "name", this would literally mean 'name' as you and I understand it
- now if we did name, by itself, without the "" (apostrophes), it is
basically a pointer telling the machine about information you and I can't see!
- so you can see, because the earlier example 'captured' Aulani's name
in matches[2], we can do send("tongue "..matches[2]), which will become send("tongue Aulani") which will send 'tongue Aulani' to the 'server'
- so IFs are really powerful when you check the right 'variables'! and
you'll get the right 'variables' if you 'capture' them properly!
- in this case, table.contains( A, B ) checks to see if table A,
contains variable B. If it does, it sends 'true' otherwise it sends
'false'!
Regex has some control characters that do fairly specific things. These are: ^$.[](){}+*?|\ (I might be missing a few). Everything other than the special characters is handled literally (as in, it does exactly what you think it does and has no special purpose in most cases).
^ means "beginning of string". For MUD clients, this usually means a single line. This can be used to force a regex to only match things starting at a beginning of a line.
$ means "end of line". Same idea.
. means 'any character'. It will match any single character. Including a '.'.
[] is a character class. The stuff inside it will allow you to match multiple characters at once. For example, [a1] will match either 'a' or '1'. You can also use ranges in these. [a-z] will match any lowercase character.
() is a group. This allows you to group a series of characters or regex control symbols or any mix of the two together. By default, these also provide backreferences, meaning anything it matches will be returned in, in Mudlet, the 'matches' table. The first group is matches[2], the second matches[3], and so on. If you do not want a group to match (there is a reason for this at times), you can put, at the first two characters after the (, ?: to prevent it from matching but still retain group functionality. For example, (a[lc]e) will match either "ale" or "ace" as a group and return it in backreference 1(matches[2]). (?:a[lc]e) will match it as a group, but won't return a backreference.
{} is where we start getting into quantifiers. With {}, you can set how many times you want something to match. w{2} will match "ww", but not "wa". It will match the first two w's in "www", though. w{1,3} will match "w", "ww", and "www" entirely, matching between 1 and 3 w's (by default, greedily. I will explain what this means later). You can actually exclude the number after the comma to match as many times as possible with a minimum. For example, w{2,} will match 2+ times. If used after the ) of a group, this quantifier (and any quantifier really) will apply to the group as a whole.
+ is a quantifier meaning "1 or more". It is equivalent to {1,}
* is a quantifier meaning "0 or more". It is equivalent to {0,}
? is a quantifier meaning "0 or 1", essentially making what it quantifies optional. For example, colou?r will match "color" or "colour". "^(pub)?stomp$" will match either "stomp" or "pubstomp".
| (pipe character. Usually shift+backspace) means "or". "(fish|trout)" will match "fish" or "trout". "(left hand|right hand)" will match "left hand" or "right hand" (side note, bad example. I would normally write that as "(left|right) hand". This was just to explain how it interacts with spaces.) For the purposes of not using | in a group, a whole regex qualifies, for the most part, as a group (and does actually have a backreference. Backreference 0(matches[1])).
\ (backspace) is a special character that prefixes other characters. \ before a control character makes it match normally (for instance, "\(" matches "(" instead of trying to open a group). That is known as 'escaping' a character. \ in front of certain letters gives special meanings, usually called 'character classes', and I will go over those a bit lower.
Character classes:
\w matches a 'letter', and is usually used with + or * to mean 'word'. This is equivalent to [a-zA-Z]
\d matches a number. Equivalent to [0-9]. Digit.
\s means whitespace. Spaces, tabs, et cetera.
\W is the opposite of \w.
\D is the opposite of \d.
\S is the opposite of \s.
There's more, but you likely won't encounter them often.
Greedy vs Lazy - What it means:
All quantifiers, by default, are greedy. This means they will take as much as they can by default. This can actually cause problems in some regexes (albeit rare), and can be used for optimization purposes (slightly advanced, but I'll go over it anyway). You can, however, make any quantifier (other than ?) lazy (matches as little as possible) by appending a ? to it. "+?" is a lazy version of "+". "*?" is a lazy version of "*". "{1,3}?" is a lazy version of "{1,3}".
WARNING - IN DEPTH TECHNICAL STUFF IN THIS LINE: The difference between lazy and greedy matching is actually a parsing one rather than a syntactic one. Greedy matching goes to the very end of the regex and decrements its position (moves backward) until it gets a match. Lazy starts from the actual position of where it should start matching and increments its position (moves forward) until it gets one. If you have a greedy quantifier with a bunch of stuff in the regex after it, it's almost always faster to use a lazy quantifier. We're really talking speed too fast for a human to be able to visibly see it, but it does add up, especially in complex code. TECHNICAL STUFF FINISHED.
Cool regex tricks:
Reverse character classes: You can have a [] character class that matches anything -but- what's specified in it by having the first character of the class being a ^. [^aeiou] will match any non-vowel character (including numbers, punctuation, whitespace, etc.)
Case sensitivity: Regex is, by default, case sensitive (meaning A will not match a, and vice versa). You can force case insensitivity by using "(?i)", and force case sensitivity afterward by using "(?-i)"
There's some more advanced stuff like named backreferences, atomics, lookarounds, and stuff like that, but it's beyond the scope of this and are rarely used anyway. If you (or anybody) have any questions, I am always willing to help people with regex or code, and can be reached via IG OOC tell or message, or via forum message as well. I apologise if I got a bit dense up above as well, as I was trying to make it understandable and explain anything that might be a bit difficult but do realise that I am horrible at doing such, and can explain anything not clear if needed..
sendAll("outskin lovashi", "outskin cluuvia", false)
if matches[2] == "cut" then
send("fleshcall hands claws", false)
handstype = "cutting"
elseif matches[2] == "blunt" then
send("fleshcall hands giant", false)
handstype = "blunt"
elseif matches[2] == "magic" then
send("fleshcall hands ethereal", false)
handstype = "psychic"
end
-----------------------
it should all be matches[2]
You don't need to send commands one at a time either, sendAll() allows you to enter multiple commands, the ", false" at the end of the sendAll() disables command echos, which you may or may not prefer.
One catch-22 I will just note (not entirely relevant, but forgot to mention it earlier) here since it does catch some people by surprise, optional groups still do provide a backreference (albeit an empty one), even if it doesn't match anything. The backreference number is solely determined by where it is in the expression (you can count the open parentheses) in case you end up encountering embedded groups (also not a relevant thing here, but again, something that should have been mentioned in my wall of text up there).