Help me learn

RilunaRiluna Member Posts: 1,089 Mythical
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

  • LeradLerad Member Posts: 2,396 Transcendent
    edited March 2015
    What you want to do is to tell your system to remember what hands you set illuminati hands to, so that it will use the bash command for whichever hands you are doing.

    To "set" your hands, you have to therefore send 2 things - the command to the game to make your transmology hands whichever type you want, as well as a command to Mudlet to tell it to remember you've just done this. We use variables for this. So, for example, look at this alias:

    Pattern: ^cut hands$
    Codebox:
    send("fleshcall hands claws")
    handstype = "cutting"

    This is an alias that performs the two things I mentioned above. The variable named "handstype" now has a value "cutting".

    Next, in your bash alias, you do this:

    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

    And it will send the claw version if you used CUT HANDS, and the crush version if you used BLUNT HANDS. Obviously, you'll need to make a BLUNT HANDS alias to set the "handstype" variable to blunt.

    Setting variables and making the system check variables with if-else-end logic statements are the basics of coding, but they can do a lot of things once you get the hang of it. When I was PKing in another IRE before I came to lusternia, I made a system using only if-else-end statements, pretty much. Hope this gets you started.

    Edit: There're a few things I glossed over, like regex, code syntax etc. For that, you'll have to learn by trial and error, and repeated referring to the manual. Mudlet will let you know when you type in code that is wrong, so you can go back and try and look for it.

  • RykiniaRykinia Member Posts: 81 Adept
    edited March 2015
    Hello! - Here's a post I managed to dig up from Imperian forums that Iniar posted over there, it should help you out, I think. It's been simplified as much as possible--- Might help others out, too, so I'll repost it here.

    A Baby's Guide to Mudlet
    =====================================
    1) Definitions

    'server' - where Imperian is hosted
    'client' - where you receive information from Imperian, this could be programs like Mudlet or CMUD
    'serverside' - this happens on Imperian's end, and has nothing to do with your computer, Mudlet/CMUD, or internet connection
    'clientside' - this happens on your end, and -usually- means Mudlet/CMUD

    'alias'
    - 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
    'macro' - similar to 'alias' but is instantly sent without you hitting the 'Enter' key or 'Return' key
    'variable' - a container for your client (Mudlet/CMUD) to hold information
    'trigger'
    - 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

    'table' - a collection of 'variables', for example, 200 maidenhair, 100 kelp, 50 toadstool
    'function'
    - a machine that interprets some data and returns you something else,
    for example, your ATM machine processes your card and gives you your money
    'event
    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!)

    'pseudo-code'
    - 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
    image
    Picture 1:
    if you click this button here and click 'Add Item' (see below), you will create a new trigger

    image

    Picture 2:
    1 - this is your new trigger
    2
    - 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.
    3
    - 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)
    4
    - 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'
    5 - this is the 'pattern box'! Here is where you put in your 'triggers'
    6
    - 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!
    7 - this is the multiline tick box, which we'll explain a little later


    3) Triggers
    Bit longer of a spoiler...

    Let's make a really basic trigger!
    We met a crazy woman named Aleutia, and she often smiles (wickedly) at you! What you see in your screen is something like this:
    Aleutia rubs her hands together and grins evilly at you.
    If you put this line in the 'pattern box' (5), you'll now respond to Aleutia grinning at you evilly.
    What shall we do?
    Let us stick our tongue out at her!
    See that 'code box'? (3)
    In it, type:
    send("tongue Aleutia")

    Hit Save Item, and make sure your box is checked green.
    Now everytime Aleutia grins evilly at you, you will stick your tongue out at her!

    'trigger types'
     
    - there are several types of trigger types, and the ones I use the most
    are 'regex', 'Lua function' and the occasional 'color trigger'
      - the default substring type is otherwise very useful

    'regex'
      - 'regex' stands for 'regular expression' but that doesn't really mean anything
     
    - 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 other way we could work it is to use 'regex'.
     
    - 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!
      - but do we really want to stick our tongue out at Aleutia when it's Aulani grinning at us??

    'captures'
      - in comes the concept of captures!
     
    - 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.'
      - let's change that to '(\w+) rubs her hands together and grins evilly at you.'
      - we put in parentheses '()'
     
    - 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!
      - how can we access this 'capture'? By using the Mudlet-only 'matches' command
     
    - 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]
      - matches[2] is the first capture in the trigger, matches[3] is the second capture and so on and so forth
      - now we can stick our tongue back at the right person! How?
      - look at your 'code box' (3); let's change the code to: 
    send("tongue "..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!
      - something very important happened here!
      - see how we did "tongue Aleutia" earlier, and now we did "tongue "..matches[2]?
      - why can't we do "tongue matches[2]" ??

    'variables'
      - we come to variables. Remember that variables are 'a container for your client (Mudlet/CMUD) to hold information'
     
    - 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, because of this, send("name") and send(name) are two very different things!
      - if for example, earlier on in some other random script, we did this:
    name = "Ozreas"
        then when we do send(name), it will be changed into send("Ozreas") and this will send the word "Ozreas" to the 'server'
        on the other hand, send("name") will send the word "name" to the 'server'
      - this is the basic concept of a variable!
      - to join "name" and name, you'll want to do this! send("name"..name), or better yet, send("say my name is "..name)!
     
    - 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'

    'permission lists!'
      - what if you only want to tongue certain people??
      - let's look at tables!
      - tables are essentially like a shopping list
      - on it, you can put almost -anything-
      - in Lua (the language of Mudlet), a table looks like this: 
    this_awesome_table = { "apple", "Svorai", "Jeremy" }
        'this_awesome_table' is the name of our table
        the { and } are the boundaries of our table
        and each item in the table are things on our shopping list!
      - so, let us say, we only want to 'tongue' Aulani and Aleutia, and we want to totally ignore Svorai!
      - let us change our table to this:
    this_awesome_table = { "apple", "Jeremy", "Aulani", "Aleutia" }
      - notice how we took out Svorai and added Aulani/Aleutia in?
      - where do I put this table, you say? Go to your code box (3), and above send("tongue "..matches[2]), paste it in!
      - now we have a list of people we want to respond to, ooer!
      - let us now change the code in our code box (3) to only respond to the people on our awesome list
      - delete send("tongue "..matches[2])
      - in its place, put this:
    if table.contains( this_awesome_table, matches[2] ) then
    send("tongue "..matches[2])
    end
      - simply put, this checks the table for the 'capture' and then responds if it is present!

    'if!'
      - the IF!
      - IF is amazing.
      - it lets us check things before running our code!
      - IF I am on fire, THEN stop-drop-and-roll END
      - that is the basic pattern of the IF
      - let's look at a practical example!
      - IF my_health < 100 THEN send("eat toadstool") END
      - but we can't eat toadstool without a balance, correct?
      - IF my_health < 100 AND toadstool_balance == true THEN send("eat toadstool") END
      - you can also specify what to do if you don't fulfil the condition!
      - IF (I am awesome) THEN send("scream I am awesome!") ELSE send("say I'm sadly not awesome") END
      - take a look at these:
        - IF rebounding == true THEN send("rsl "..target) ELSE send("dsl "..target) END
        - IF shield == true THEN send("touch hammer "..target) ELSE send("kill "..target) END
        - IF wielding == "tablet" AND class == "Deathknight" THEN send("wield sabre") END
     
    - so IFs are really powerful when you check the right 'variables'! and
    you'll get the right 'variables' if you 'capture' them properly!

    'functions'
      - notice in our earlier example, we did; if table.contains( this_awesome_table, matches[2] ) then etc. etc.
      - what is table.contains()?
      - this is a 'function'
      - remember, a function is: a machine that interprets some data and returns you something else
     
    - 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'!
      - let's look at a quick example of a function:
    function my_awesome_function( argument_one, argument_two )
    if argument_one == "Iniar" and argument_two == "awesome" then
    send("say Iniar is awesome")
    else
    send("say Iniar is "..argument_two)
    end
    end

       - we can now 'use' our function like this:
       my_awesome_function( "Aulani", "awesomest" ) <- this would send 'say Iniar is awesomest'
       my_awesome_function( "Iniar", "cheesy" ) <- this would send 'say Iniar is cheesy'
       my_awesome_function( "Iniar", "awesome" ) <- this would send 'say Iniar is awesome'

       - finally, we can get functions to return values into 'variables'
       - for example,
    function is_potato( name )
    if name == "Ahkan" then
    return true
    else
    return "No potatoes here"
    end
    end

       - 'return' stops the 'function' cold, and can send a value back, so we could use our new function like this:
       my_potato = is_potato("Iluv")
       send(my_potato) would expand into send("No potatoes here")
       my_potato = is_potato("Ahkan")
       send(my_potato) would expand into send(true)

  • RykiniaRykinia Member Posts: 81 Adept
    Omg spoiler tags are being hella lame D:
  • AltreaAltrea Member Posts: 193 Gifted
    Rykinia's stuff is pretty good there, and I'm not actually a Mudlet user, so I'm just going to go into detail about Regex (Regular Expressions) more than her guide there, mainly because they seem to be a huge point of grief for everybody on both clients. Regex seems almost arcane, but at its core, it's actually pretty simple.

    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..
  • RilunaRiluna Member Posts: 1,089 Mythical
    Thanks so much. :) That's not nearly as dense as the "beginners guide" I was trying to learn from, @Altrea, even if I don't completely understand it all yet,. It's just a lot of information. Can I combine this with what @Lerad said, and make it all into one thing, like this?

    ^(cut|blunt|magic) hands$

    And if so, how do I get the code from matches[2], matches[3] into just making one variable? Will it just ignore the words it doesn't match as a "nil" and move on?

    Because this doesn't seem to be working:

    send("outskin lovashi")
    send("outskin cluuvia")
    if matches[2] then
    send("fleshcall hands claws")
    handstype = "cutting"
    elseif matches[3] then
    send("fleshcall hands giant")
    handstype = "blunt"
    elseif matches[4] then
    send("fleshcall hands ethereal")
    handstype = "psychic"
    end

    Mayor Steingrim, the Grand Schema says to you, "Well, as I recall you kinda leave a mark whereever you go."
  • ShuyinShuyin The pug life chose me. Member Posts: 1,611 Transcendent
    edited March 2015

    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.

    Post edited by Shuyin on
    image
  • AltreaAltrea Member Posts: 193 Gifted
    edited March 2015
    Yeah, as Shuyin said, a single group will all go into a single backreference as a string, which you can match against another string with == (or ~= or any various number of things really). Beyond that, your code is completely correct.

    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).
  • RilunaRiluna Member Posts: 1,089 Mythical
    Thank you all very much. :)

    Mayor Steingrim, the Grand Schema says to you, "Well, as I recall you kinda leave a mark whereever you go."
  • ShaddusShaddus His Imperial Altness Outside your window.Member Posts: 7,620 Transcendent
    This is a plugin that someone coded for me long ago. It may very well be outdated, but it makes a series of clickable links on the upper right corner of Mudlet, then you can click them to do your fleshforms. I -think- you can float your cursor over them to see what they do, but it's been IRL years since I've used it. Just install it, restart your mudlet/profile, and you're set.
    2017/04/23 00:29:14 - Nefara honoured Shaddus for: For his dedication to the Earthen Lords and Lady, 
    and willingness to assist our young Pupils. Despite his choosing to not progress himself further, he 
    still works for the Geomancers, and the Engine, in any way he is capable. Also comes with a healthy 
    dose of rebellion, to ensure us of the Council can not be too relaxed.
  • RiviusRivius Your resident wolf puppy Member Posts: 1,608 Transcendent
    Hey there. I don't use mudlet, but I can provide general lua and regex resources that helped me a lot:

    http://regexpal.com/ is a pretty nice web client that highlights regex and lets you know if what you have is matching. It gives you a quick reference sheet as well. Very good for testing regex until you get the hang of it.

    While this article was written by the programmer of mushclient, it details principles behind regex that you can apply anywhere:

    The lua users wiki is really great, and breaks things down with excellent examples:

    And if you wish, the official lua document is also available for reference, though is a bit more comprehensive:
Sign In or Register to comment.