Toz's Intro to Coding

TozToz Member Posts: 2,491 ✭✭✭✭✭
So, I've decided to write a basic guide for coding in MUDs. While it'll be Mudlet-oriented, the beginning bits will at least generalize to other clients as well (or so I assume). This isn't the only post I'll make (hopefully?) but it is going to be the first one for awhile (because man this took like an hour!) So, without further ado, here we go.

Basic Coding Information
I'd rather assume nothing, and leave nothing to chance. I'm sure this quick'n'dirty thing won't cover something - if you think of something easy that I missed, let me know and I'll add it!

Think of it as a box. It stores a value for you. Variables are initialized in Mudlet by doing simply variableName = value. Some examples:
number = 13 text = "This is how you store a string of text!" truefalse = true --true, false and nil are booleans. Nil means 'there's no value at all in here'. number = text --This is how you'd copy a variable's value
If we want to COMPARE variables, we use ==
if text == number then <whatever> end

This brings us to our next topic...
The statement exemplified above is an 'if' statement. It means exactly how it reads: IF the variable 'text' EQUALS the variable named 'number', THEN do whatever. And then it ends. You can do several other kinds of statements - loops. The most common one I use is the WHILE loop.
while text == number do <whatever> end
Please note that this will execute forever if text and number are the same, unless you have some way within the loop for that condition to no longer be true. And it will crash your Mudlet, and if you go have a cry I won't judge you because I do it all the damn time.

+ for addition, - for subtraction, * for multiplication and / for division. You can add/subtract/multiply/divide variables and numbers freely.

Sometimes we don't know what's going to happen. Maybe Toz punches you in the face. Maybe it's Moirean. Maybe it's you punching yourself - maybe it was always you punching yourself. Do you have 1 gold, or 100000 gold? Did you swing an elegant rapier inlaid with rubies, or a short cudgel covered in grease? These questions would matter if it wasn't for wildcards - your new best friend.
If we need a placeholder for a single word?
Toz punches you in the face.
(\w+) punches you in the face.

What if it's two words? Or...or three words? OR MORE THAN THREE?!
You suddenly feel like eating a giant pickle sundae.
can be done as
You suddenly feel like eating (.+)

...Don't look now, but there's a number behind you!
You have 2 sets.
turns into
You have (\d+) sets
OR for extra credit,
You have (\d+) (\w+)
since you can have 1 set, or 2 sets

And now time to terrify you:
A pack with 3000 gold is here.
can become, simply
A pack with (.*) is here.
Be careful with (.+) and (.*) - they're REALLY grabby. Additionally, if you have a wildcard that you don't want to save for later? Just drop off the ()s and leave it as \w+ or whatever - they won't mind.

And now that you've crammed some value into your new best friend (remind me to never be friends with you), you're going to want to pull it out some time. I...hope. To do that, we're going to touch upon another topic briefly and then run away screaming: an array. An array is a bunch of boxes that exist in numbered order. And now we scream. And scream. And ok we're back - so the values we save from a trigger are stored in an array called matches[]. To reference a specific part of an array, we use the format arrayName[value]. So for matches, we'd do matches[1] to see the WHOLE LINE. Please note this, because it messes newbies up lots. If you want the FIRST VARIABLE YOU USED A WILDCARD FOR, use matches[2]. The 2nd variable is matches[3]. Etc. It's about as clear as mud to a newbie (heh, MUD/mud) - but if you remember it, you'll be ok.

I'm sure I've left something off from here, so lemme know and I'll add it. And now onto...

The Big 3
There are four aspects to coding within Mudlet. They are Aliases, Triggers, and Scripts. Before we go any further, it is important to know what these things are, so allow me to give an overview. I'll go a little more in-depth after each is explained, so if you're already solid on these feel free to skip ahead.

An alias is nothing more than a shortcut. When you type in an alias into the input line, instead of sending the text to the MUD, it will execute the code. An example alias, and its output, is below:
Alias: ^toz$ echo("Toz is our name.\n") echo(".Eman rou si zoT")

What that will do, is any time I type in 'toz' into the input line, it will display the echoes. Specifically why that works (scripts!) is something coming up soon, but for now just know that it works - any time you type in something in the pattern line of an alias into the input line, it'll execute whatever is in the big box instead of sending what you typed in to the MUD.

A trigger is almost the opposite of an alias. Whereas aliases are active things you type in, a trigger runs reactively. When the MUD sends you a line, Mudlet (or your client) will try to match the line against all the triggers you currently have, and if a match is found, it will run the code it is supposed to. An example

To explain the above, if the line 'Password correct. Welcome to Aetolia.' appears on your screen (as it does every time you login), you'll attempt to FARSEE TOZ. Mileage/hammerage may vary, depending on how often you log in, but I digress.

A discerning eye will notice a drop-down menu that I left strategically open, to the right of the trigger line. Just know that is there, for now - I'll get to what it does later!

Ahh, scripts. You could go your entire life without ever using one, but that would also make me cry. It is the nature of problems to reoccur, with slightly different forms - so if you find yourself running into the same problem (as in, requiring the same code or similar code) over and over, you could simplify your life and put everything in a script!

A simple example of a real script I use is an infoEcho() - on the system I'm building, I like a pretty format display to come up on my screen that reads [CATS]: . So if I ran

infoEcho("The cake is a lie.")

I would see

[CATS]: The cake is a lie.

appear on my screen. Note the format for calling functions - it is functionName(things to send). Multiple things to send (parameters) can be sent using functionName(parameter, parameter2, parameter3). You can send numbers, strings, even variables to a function!

So now that you've been properly introduced to aliases, triggers and scripts, we can move on to more advanced interplay between them. This post is already fairly long, so I'm going leave you in a cliffhanger of sorts - instead of doing advanced stuff, I'm going to underscore some things in case they aren't as clear as I want them to be. Then I'll review, wrap it up, and take a break from writing!

Aliases 2: The Aliasing
Sometimes it's not enough to just type my name into the input line - an unfortunate twist of fate. Sometimes we may want to have an alias work for many different things, because we are fundamentally lazy (and that's okay!); instead of making a million different aliases for every possible solution, I'm going to reference something from the beginning: wildcards.

That's right, your best friend wildcard is back, fresh from having the last value you crammed into them (and then promptly forgot about as you read the rest of this guide) removed with the jaws of life, and they're back for more. So first let's attach some anchors!

...What is an anchor? Glad I asked! An anchor is what you use to specify the BEGINNING and END of your alias. If you don't anchor your toz alias, any time you type toz EVER, it'll trigger. If you do ^toz$ instead, it'll only ever work if you type in 'toz' with nothing around it/no spaces. So from now on, whenever we work with aliases (OR TRIGGERS, sometimes), remember to slap some anchors on it so it doesn't float away. So let's have an example! What if we want to smack someone with our weapon? Well, using the magic of wildcards, picking your target is as simple as one alias!

alias: ^smack (\w+)$ --Notice, the wildcard! send("draw smacker") send("smack "..matches[2]) --Notice we use the wildcard!

Now when we type in 'smack toz', you draw your smacker (...whatever that is), and smack me with it. But if you type in 'smack fallon', you'll hit them instead. Just use the appropriate wildcard for what you want to do, and you'll be okay!

Triggers: Tumblr EditionToz Edition
So, we've touched upon wildcards in triggers before, but I'd like to take a moment to reinforce some basics, because that's important. When you work with triggers, anchor them. Or else they'll fly away and take your entire script with them! If you know the start of the line, lead your trigger with ^. If you know the whole line, wrap it up in ^ and $. If you only know the last few bits at the end, feel free to just use $ at the end - but remember to anchor as much as you can!

Additionally, to make wildcards work with triggers, you'll need to set the type as PERL REGEX. You're using regular expression (REGEX) to capture via wildcards, so you have to let the client know. There are things in regex that exist as wildcard/functions that you may not want to be read as regex, as well - what if you wanted to (for whatever reason) trigger off seeing a '.*'? You're able to, using a backslash! \.\* tells regex to interpret those LITERALLY, that is, they're not a wildcard. They're just a dot then an asterisk.

^This is a valid trigger\.$ ^(\w+) is this\.$ is valid too\!$ ^I can do this too I can even do this, but I shouldn't\.

Arbre-Today at 7:27 PM

You're a vindictive lil unicorn

Lartus-Today at 7:16 PM

oh wait, toz is famous

Karhast-Today at 7:01 PM

You're a singularity of unicorns awfulness Toz


  • LimLim Member Posts: 591 ✭✭✭✭
    You typoed 'rou'. It should be 'ruo'. 
  • TozToz Member Posts: 2,491 ✭✭✭✭✭
    Yeah, did. Though if I only made 1 typo in the whole thing, I'm rather impressed with myself.

    Arbre-Today at 7:27 PM

    You're a vindictive lil unicorn

    Lartus-Today at 7:16 PM

    oh wait, toz is famous

    Karhast-Today at 7:01 PM

    You're a singularity of unicorns awfulness Toz
  • SatomiSatomi Member Posts: 318 ✭✭✭
    @Toz, you made one fatal mistake. You used Necromancy Revive instead of Soul Call.

    Shame on you.

  • KalinaarKalinaar Member Posts: 113 ✭✭✭
    Thank you Toz! This definitely cleared a lot up for me.
  • TirriaTirria Member Posts: 18
    Mudlet is a pain for me. I'm struggling along. Just something as simple as a prompt trigger is giving me fits.
  • MjollMjoll Member Posts: 84 ✭✭✭

    Easy prompt trigger for mudlet
  • RiannonRiannon Member Posts: 33
    Mjoll said:

    Easy prompt trigger for mudlet

    Not needed if you have a later version of mudlet, 'prompt trigger' is already a type of trigger you can set!

  • RiannonRiannon Member Posts: 33
    edited June 2018
    Hey, can I add to this as well? I got asked loads of questions over in Achaea and Imperian, figured I could share some knowledge here as well.

    Personally, something I enjoy using is event handlers. You can use these to handle a large number of things, without the need for unnecessary triggers bloating your system. GMCP has evolved significantly over the years, which has pretty heavily increased the amount of things you can do with these event handlers.

    What is an event handler, exactly? Well... It's a handler- or a function, typically- which fires only when an event is called. This could be from using raiseEvent("event name") or from a gmcp value changing/firing. For instance when you walk into a new room, generally the gmcp.Room event is going to fire. But how do you access them, without using triggers to fire them? Simple! Just observe the picture below, and the comments that follow along with it.

    Thus concludes the class on event handlers and how to properly control/run them. Hope it helps!

    I'd like to add something I don't think Toz mentioned. Everything in Lua is case-sensitive. A script called helloWorld() is not going to run if you try and use HelloWorld() or helloworld() for instance. Similar if you have a variable called daBooty, then if you try and call the value from dabooty instead, it's not going to work. So many times I ran into this when looking over code for people!

  • MoxieMoxie USAMember Posts: 55 ✭✭✭
    Hi! I have been referencing back to this a lot when I'm working with LUA and it's been very, very helpful and has caused me to inundate people with less questions. However I'm running into issues into understanding how pairs and ipairs work in mudlet and I was wondering if you could tozzify a lesson on it for those of us still learning! I would appreciate it.
    (Tells): In a deep, gravelly voice, Iesid imparts to you, "( goob isn't here so I'll say it: BUY ANOTHER ONE YA RICH MUTHAFKRR )"
    (Tells): In a deep, gravelly voice, Iesid imparts to you, "( said in Chapelle's Rick James voice )"
  • KalinaarKalinaar Member Posts: 113 ✭✭✭
    Moxie said:
    Hi! I have been referencing back to this a lot when I'm working with LUA and it's been very, very helpful and has caused me to inundate people with less questions. However I'm running into issues into understanding how pairs and ipairs work in mudlet and I was wondering if you could tozzify a lesson on it for those of us still learning! I would appreciate it.
  • MoxieMoxie USAMember Posts: 55 ✭✭✭
    Stine said:

    So now I'm fighting, which means I want a list of targets. These are the people in the room. For whatever reason I have an aversion to killing odd numbered people though (weirdos), so we're going to try to get Stine's name out first: someTargets[2] will produce the string "Stine".

    > mfw I get first targetted even in forum posts :(
    Mfw @Stine goes straight for his own name and doesn't see that Toz is calling Benedicto, Kalinaar, and I weirdos!!! *triggered* :#

    But really, seriously, thank you for the lesson!! I love it <3
    (Tells): In a deep, gravelly voice, Iesid imparts to you, "( goob isn't here so I'll say it: BUY ANOTHER ONE YA RICH MUTHAFKRR )"
    (Tells): In a deep, gravelly voice, Iesid imparts to you, "( said in Chapelle's Rick James voice )"
  • KalinaarKalinaar Member Posts: 113 ✭✭✭
    I accept my lot as a weirdo. Happy to have made a cameo regardless! Also, thank you for this. I've been wanting to make a more advanced targeting alias and I think this is what I needed to get it working. 
  • SrynSryn Member, Bot Posts: 31 ✭✭
    edited March 6
    Nevermind I can't read :(
  • EliadonEliadon Somewhere Over the RainbowMember Posts: 151 ✭✭✭
    edited March 7
    For people other than Toz, as I already PMed him:

    If anybody runs into trouble using the pairs() method where it pulls random data instead of the order you think the table's in, let me know because I'd love to see it in action and learn why/how, but it hasn't happened to me in a long time and it probably won't happen to you if you use it for the basic stuff (like an Aetolia offense).

    local testTable = {One = 1, Zwei = 2, San = 3, Quatro = 4};
    for k,v in pairs(testTable) do
    print(k .. " = " .. v);
    One = 1
    Quatro = 4
    San = 3
    Zwei = 2


    The tl;dr for that is "there's logic behind it, but if you use pairs it might not always come back in the order you're expecting"

  • SrynSryn Member, Bot Posts: 31 ✭✭
    edited March 7
    There's two types of tables. Lists and dictionaries. Lists have a pre-defined index in the table, dictionaries 'index' is generally a variable.
    aList = {"one", "two", "three", "four"} is a list. pairs() will report this in the order that it's created in.
    for v in pairs(aList) do echo("\n"..v) end
    Would show:
    List objects can also be referenced by their position, such as aList[1], aList[2] etc. Lists are also the only type of table that ipairs() works for (because lists are indexed). You also don't need to do for i,v in pairs to iterate them. You can do for _, v in pairs, or you can just do for v in pairs like I did.
    aDictionary = {one = 1, ["two"] = "2", 3 = "three", four = 4} is a dictionary. pairs() will report this in a random order.
    for k,v in pairs(aDictionary) do echo("\n "..k.." = "..v) end
    Could show
       one = 1
       two = "2"
       3 = "three"
       four = 4
    Or it could show
       four = 4
       one = 1
       3 = "three"
       two = "2"
    Or any order of options.
    This is why 'list' tables are generally used for offenses, and the attacks that give them are stored in a separate table. If you had, for instance, something like
    wantedAffs = { paresis = "attackThree", clumsiness = "attackFive", asthma = "attackOne", slickness = "attackTwo", anorexia = "attackFour", lethargy = "attackSeven", }
    The affs have a good chance of not actually being given in the order of paresis > clumsiness > asthma > slickness > anorexia > lethargy because of dictionaries not being ordered, despite being pre-written in that order.
  • AloliAloli Member Posts: 143 ✭✭✭
    This is really helpful, thank you all for taking the time!
  • TozToz Member Posts: 2,491 ✭✭✭✭✭
    edited March 7
    Yeah that's super good to know. I learned all my Lua from other people's code and never had a case where I wanted to iterate through a dictionary so that explains a lot! Always just used dictionaries for conversions, which is a key lookup not a loop search.

    Edit: or I suppose a lookup where order mattered, when looping through.

    Arbre-Today at 7:27 PM

    You're a vindictive lil unicorn

    Lartus-Today at 7:16 PM

    oh wait, toz is famous

    Karhast-Today at 7:01 PM

    You're a singularity of unicorns awfulness Toz
Sign In or Register to comment.