Toz's Intro to Coding

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!

Variables:
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...
Logic/Loops:
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.

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

Wildcards:
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.
becomes
(\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.

Aliases
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.

Triggers
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!

Script
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 fucking awfulness Toz
---------------------------
Didi's voice resonates across the land, "Yay tox."
---------------------------

Ictinus11/01/2021

Block Toz
---------------------------

limToday at 10:38 PM


you disgust me
---------------------------
(Web): Bryn says, "Toz is why we can't have nice things."

TragerDrahkunaMoireanAlexinaRiluoAloliLeanaVyxsisKalinaarKelliaraZailaTirria

Comments

  • You typoed 'rou'. It should be 'ruo'. 
  • 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 fucking awfulness Toz
    ---------------------------
    Didi's voice resonates across the land, "Yay tox."
    ---------------------------

    Ictinus11/01/2021

    Block Toz
    ---------------------------

    limToday at 10:38 PM


    you disgust me
    ---------------------------
    (Web): Bryn says, "Toz is why we can't have nice things."

    TragerRiluoKalinaarAloli
  • TozToz
    edited May 2018
    Toz uses Necromancy Revive.
    LOGIC BLOCKS and BOOLEAN LOGIC are today's topics, thanks to @Mordion asking me a few questions earlier today.

    First off, I'm going to start off with something super duper simple that I absolutely adore, BOOLEAN LOGIC.

    BOOLEAN is a very simple type of variable. Mudlet isn't super particular about your variables, but if you declare a bool or boolean variable in most languages, it only holds 2 values (basically, I know C++ and other languages are weird but that's outside the scope) - true or false. It can also be nil or null but I mean, that's the absence of a value so it isn't really 'holding' it, it's just the void. Hail Babel. Anyway, those two values are 'on' or 'off' states- they indicate the presence or lack thereof, of some thing. And they're making up the framework of your offense, your defense, all sorts of things.

    For some of you on older systems, you might have a 1 and a 0, where 1 maps to TRUE and 0 maps to FALSE and then if they're insane they use like 2 for MAYBE and -1 for ON FIRE or whatever insanity they came up with. Stop reading @Eliadon's code. We're gonna stick with TRUE and FALSE for now, and if you use 1 and 0 (like GMCP does), I'd suggest mapping those to TRUE and FALSE using a custom function:
    function toBool(num) if num == 0 then return false else return true end end //end toBool
    The above code will turn 0s to falses (just like GMomCP makes) and 1s/whatever elses to trues. And then we're gonna screw around with those two concepts to build whatever we want.

    Using three operators you can describe/shape basically the entire world. These operators are NOT, OR, and AND.

    These are exactly what you think they are, too- you'd theoretically be able to tell me what 'not alive' means, and we can either express this in Mudlet with 'not alive' or '~= alive' depending on what we were doing.

    OR is a choice. Pie or cake? Now, there is a funny part of OR but we will get to that in juuuust a moment.

    AND is a combination. Pie AND cake!

    So imagine we have two variables, A and B. There's something called a 'truth table' that I'm going to use below for a quick demonstration. I'll be using some logical shorthand as well, with ! standing in for not. We're gonna mash BOOLEANS together with this LOGIC to make... BOOLEAN LOGIC. Because you totally didn't see that coming.

    So, A can be either true or false, right? It's boolean that's what it means. And B can be true or false too. So all the options we have are shown below, for the AND operator:

    AB | A!B TRUE | FALSE ================== !AB | !A!B FALSE | FALSE

    What this means is, essentially, if it is NOT A then it cannot be true. If it is NOT B then it cannot be true. If it is NOT A and NOT B then it cannot be true. So AND will only check for the two values it links being true. That's some pointed phrasing too - I'll clarify in a bit!

    For the OR operator, we have the following though:
    AB | A!B TRUE | TRUE ================== !AB | !A!B TRUE | FALSE

    Notice the differences - if only ONE is true (A OR B ) then it's still true. But also, if it's BOTH of them it's true. So the next time someone asks if you want to do one thing or the other, you can reply 'yes' and you're 100% accurate and completely unhelpful. That's the funny part I mentioned above, too - in English there's an understood 'XOR' operator when you say 'do you want to go to the bar or the club?' - you're only supposed to pick one. XOR means EXCLUSIVE OR, which would return false on the AB case above. But we're not messing with XOR and thus, yes. Yes we want to go to the bar or the club.

    So, who cares, right? I'm over here telling you about YES and MAYBE when you just wanna build a bot to #rek that guy who was shouting stupid things at you. So, lemme introduce you to someone who cares. The IF BLOCK.

    You've seen code, maybe. Which means you've seen this:
    if demoVariable == nil then echo("demoVariable does not exist") elseif...
    And if you haven't, you're a liar because it's printed right above this line.

    Now, that's an IF BLOCK. How does it work? Magic, as far as you need to know. Here are the rules for invoking the Decision Daemon:
    - Begin the incantation with IF, and conclude it with END.
    - There must always be a THEN, for every IF
    - Place your query between the IF and the THEN
    - If the Daemon finds merit in your plea, it will do whatever you have asked for after the THEN but before the next IF, ELSEIF (!!!), ELSE(!!!!!!!!) or END.
    - You only get 1 wish, at most, from the Daemon. It does the first thing it can.

    So, in English and not BoredToz talk?
    IF <condition> THEN <CODE TO EXECUTE> END
    This is the basic IF statement. So you'll see, for instance:

    IF enemy.shielded THEN
    send("raze "..enemy)
    END

    This is a very simple IF statement. IF the value enemy.shielded is true, THEN it will send that code. It will only fire once per time the script/alias/trigger/whatever it's in gets called. If there are multiple if statements:

    IF enemy.shielded THEN
    send("raze "..enemy)
    END

    IF enemy.prone THEN
    send("axk "..enemy)
    END

    You're going to try to raze them AND axk them. Which is confusing because monks can't raze. And also because that's probably not what you wanted to do - you wanted to pick! One or the other, computer! Stupid thing. So, try the ELSEIF!

    IF enemy.shielded THEN
    send("raze "..enemy)
    ELSEIF enemy.prone THEN
    send("axk "..enemy)
    END

    Now this! THIS will ask a question: is the enemy.shielded variable true? IF it is, it does the code, and stops asking questions. IF it isn't though, it asks the NEXT question. Only one of those two things can EVER be sent by this code, and that's the beauty of it. If you have a CHOICE to make, and you want very much to just pick ONE thing? You should contain that choice within a single IF block.

    So, sometimes we have choices to make and we don't care if the conditions are true. Buuuut sometimes, you know, you have some apathy. You don't want to like, check if their shoes are tied and it's a Tuesday and your tongue is out to the left and you're getting paid, you just want to do something if none of those are true. You don't have to get REAL specific with that ELSEIF, instead:

    IF enemy.shoesUntied THEN
    snip
    ELSEIF enemy.isTuesday THEN
    snip
    ELSEIF self.tongueOut.left THEN
    snip
    ELSEIF gettingMoney THEN
    snip
    ELSE
    send("riot")
    END

    So if their shoes are tied, it's a Friday, your tongue is safely in your head and you're not getting paid? You'll riot. IF any of those other things were true though, you'd stop going down the IF BLOCK and instead do the appropriate snip, and not riot. One thing per IF BLOCK, per customer.

    Now, that BOOLEAN LOGIC comes into play here as well! Because IF is asking 'True?' - so you can link two things together:

    IF enemy.shoesUntied and enemy.isTuesday THEN

    END


    That totally works. If both things are true, it fires. Otherwise it doesn't. Same for OR! And same for NOT modifiers, like if NOT enemy.shoesUntied will work for false or that value not existing. You can also go HOG WILD with it, and check like a billion things with a string of ANDs. With ANDs, if a single one is false the whole thing is false. With ORs, so long as one is true, the whole line evaluates true. You can get CREATIVE too, though. Anything in ()s will return TRUE or FALSE after evaluating, like it's in its own little world. So you can do (left_leg_broken OR right_leg_broken) AND (left_arm_broken OR right_arm_broken) to check if a leg AND an arm is broken, and it will only be TRUE overall so long as those two ()s evaluate TRUE, since we used an AND.

    Hopefully all that made sense, and I'll answer questions in here as they roll in as I can- it's a lot to chew on, but hopefully I explained it clearly.

    Originally I had planned to do a FOR LOOP tutorial, but I'll save that for next time.

    Sorry for no pictures, but I don't have near the spare time I did 4 years ago, getting this cranked out in between RL aggro took all night.

    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 fucking awfulness Toz
    ---------------------------
    Didi's voice resonates across the land, "Yay tox."
    ---------------------------

    Ictinus11/01/2021

    Block Toz
    ---------------------------

    limToday at 10:38 PM


    you disgust me
    ---------------------------
    (Web): Bryn says, "Toz is why we can't have nice things."

    SatomiLeanaAloliVyxsisXeniaKalinaarKelliaraEliadonTirria
  • @Toz, you made one fatal mistake. You used Necromancy Revive instead of Soul Call.

    Shame on you.

  • Satomi said:

    @Toz, you made one fatal mistake. You used Necromancy Revive instead of Soul Call.

    Shame on you.

    It's called forum NECROMANCY not forum DEATHLORE.

    Memes transcend class.

    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 fucking awfulness Toz
    ---------------------------
    Didi's voice resonates across the land, "Yay tox."
    ---------------------------

    Ictinus11/01/2021

    Block Toz
    ---------------------------

    limToday at 10:38 PM


    you disgust me
    ---------------------------
    (Web): Bryn says, "Toz is why we can't have nice things."

    VyxsisXeniaLeanaSatomiKelliaraEowynEliadonAloli
  • Thank you Toz! This definitely cleared a lot up for me.
  • Mudlet is a pain for me. I'm struggling along. Just something as simple as a prompt trigger is giving me fits.

  • Easy prompt trigger for mudlet
    Toz says, "Dishonor on you (Mjoll), dishonor on your family (Seirath), dishonor on your cow (Bulrok)"
    TozMordionKalinaar
  • 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!

    MjollKalinaar
  • 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!

    SatomiTozMordionVyxsis
  • 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.

    (Illuminai): Saltz says, "Moxie is just doing the Moxie thing to do, often misinterpreted."

    (Tells): Sir Iames Gallant, the Executioner tells you, "The one Illuminai beyond prayer, I swear."

    Valingar: "How could a daughter of me, the most noble man in the south, be so heartless?"

    (Tells): Haven Locke, Illuminai Khimaira tells you, "Be that as it may, I've also seen the strength in you. You can take care of yourself."
    Kalinaar
  • 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.
    seconded. 
    Moxie
  • Oh boy I love requests. Alright, here we go. First, let's establish what Lua is:


    A table. Everything is a table. We are all tables on this blessed language. Etc. That's why you see matches[2]- it's the second entry in the string capture table generated by a perl regex trigger line (have a look at display(matches[1]) from a trigger some time)

    So, that takes us obviously to the next question: what is a TABLE?
    An associative array is an array that can be indexed not only with numbers, but also with strings or any other value of the language, except nil. Moreover, tables have no fixed size; you can add as many elements as you want to a table dynamically.

    - Some person on Lua.org

    They're correct, but that's not necessarily helpful to anyone who's new, so I'm going to propose a different definition:
    A table is a cabinet that you can cram crap into (including other cabinets). And you can add more drawers or take away more drawers any time you feel like it, because this is America because Lua lets you.

    - Toz

    So, with the disclaimer that I never use 'ipairs' so someone will probably show up and correct me, I'm going to put it this way:
    - ipairs(cabinet) starts at the very first entry in the cabinet. And then it goes to the second. And the third. And the fourth. All the way until it hits a nil element. That is, it drops down the filing cabinet until it hits a drawer that you've ripped out and flung across the room in a rage (or it gets through all your drawers). And then it stops.
    - pairs(cabinet) starts at the first KEY in the TABLE (oh boy vocab words) and then goes to the next KEY in the TABLE, which means it has the potential to jump all over the place if you don't strictly define things, wildly flinging open drawers and rummaging, like it's committing corporate espionage.

    Full disclosure again, I'm not sure WHAT the mechanics behind assigning a key is, or the order for it, when you just sort of lazily insert crap into a Lua table. 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).

    So, let's hit the specifics now of making a table, because we need to know what a filing cabinet looks like.
    local someTableBob = { "1", "2", "3", "4", "5", "6", }
    This is a table. It has 6 entries in it, 1-6. Coincidentially, these entries are the same value as what their KEY is. Much like a filing cabinet IRL, a KEY is what gets you into the drawer, which is where all the good stuff is kept. So, to get "3" out of someTableBob, we need to provide it with the KEY that corresponds to the VALUE. (keep k, v in mind for later). So here, we'd simply need to say someTableBob[3], which would go to the third entry in someTableBob and pull the value out - in this case, "3". So let's get a little more complex, just to show you I'm not cheating by making my KEYs and VALUEs match:
    local someTargets = { "Moxie", "Stine", "Kalinaar", "Arista", "Benedicto", "Kandra", }
    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". I can reference this in an alias:
    expandAlias("t "..someTargets[2]), I can call it in a script: tizzy.target = someTargets[2], whatever.

    Now, MORE typically we don't want a very specific number from a table, right? We want to evaluate the list, and find something out using it. Typically you'll see your offenses coded this way- so we're going to use that for an example.
    local someAffs = { "asthma", "prone", "disrupt", "haemophilia", }

    Now, with these affs in mind, we want to pick an affliction to give our target. Presumably we can't give all of these affs at once unless another lifer class got revamped while I was typing this, so we're going to have to pick one (or more, but that's a little further advanced than we're going to go). So what we're going to do is iterate through our table and ask some questions. Meet your savior:
    for key, value in pairs(someAffs) do if not enemyHas(value) then affliction = value break end end echo(affliction)

    So to take the above piece by piece, what we've done is created a FOR loop. What that tells the system is "while you have a valid value coming back from asking this question over and over, execute this set of steps". And since we're feeding the 'for loop' a table, it's going to iterate through all the KEYs and PAIRS of the table someAffs until we tell it to stop, or it runs out of things on the table. Remember where I said keep 'k, v' in mind? I've done that above, just with clearer names. K, V are the shorthands people around here use, and since I'm a self-taught Lua coder I have no idea if that's normal or just some localized oddness, but you'll see it a ton.

    As a brief aside, all we're doing is assigning a local variable to the loop - that means you don't HAVE to put anything really there for it- for _, value or for key, _ is sort of the 'shorthand' for 'we only care about values' or 'we only care about keys' - pairs() is going to return two values (key/value) each time, but if you're only saving one you don't have to bother with naming them both.

    So now on to the code above, since I've just covered for loops in like 10 seconds - FOR every value in this table which is returning you keys and values, DO some junk
    - Namely, check if enemyHas(that affliction we got from the table) and if they DO have that affliction...
    - - Set the value affliction to it, so we know what to give them later
    - - break - exit the loop. Quit checking the table, we got what we want

    This for loop will continue any time we reach 'end' - it jumps back to the for statement and pulls the next value. However, if we break, we break out of the for loop and continue to code BENEATH it - that echo(affliction). In this way, we are using pairs() to generate an affliction to give to the target.

    So, let's get slightly more complex, because tables can be given EXPLICIT keys as well. We don't have to just rely on 1, 2, 3, whatever gets generated by Lua itself. Some classes have attacks that map to a specific affliction, like Luminary. Since a Luminary main asked the question, let's set up a swap for them:
    local lumAffs = { ["asthma"] = "slam", ["haemophilia"] = "slam", prone = "bash", disrupt = "crash", }

    If you notice, I use two different ways to name these variables. ["This is good for variables with spaces"], andThisWorks for ones that don't have spaces- you can do either, though ["This"] helps make things look prettier IMO and also avoids oddities with special characters and the like.

    So we get an affliction from our previous table- saved to the 'affliction' variable. Now we can go through THESE drawers and find one that fits the affliction we have:
    for key, value in pairs(lumAffs) do if key == affliction then shieldHit = value break end end

    What this will do is ask "Hey give me a key/value pair from the lumAffs table" and so Lua will go "Yeah okay here you go". So let's say our value is prone, we want to knock 'em down. It'll check key (asthma) == "prone"? And then be like nah. So then it hits that end, at the end of the for loop, and boop it hops right back up to the start. And then it goes "okay next value pair is haemophilia for the key?" and then it asks "Is haemophilia prone?" And, naturally, no it isn't. So we repeat again. And then the table is like "Okay try prone/bash?" and so we ask "hey is prone == prone?" and when Mudlet goes "Uh yes duh also how did you get in my house", it goes into the if case, assigns "bash" to shieldHit, and we break from the for loop. Now you're thinking with keys.

    **So nobody yells at me, I'm also going to point out this feature, even though it's not directly related to loops:
    If you know the table name, and you know what the key is, you can instantly return the value. So that for loop is less efficient than what you could do, it was just staged this way for ease of demonstration. If you ACTUALLY had a table like lumAffs, and you had the affliction name, you'd just need to do lumAffs[affliction] and that would pop you out whatever the corresponding VALUE is that matches the KEY. If you do lumAffs["web"], it returns nil, because web isn't a valid KEY - the only corresponding value is the absolute nothingness of the void.

    Hail Babel.

    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 fucking awfulness Toz
    ---------------------------
    Didi's voice resonates across the land, "Yay tox."
    ---------------------------

    Ictinus11/01/2021

    Block Toz
    ---------------------------

    limToday at 10:38 PM


    you disgust me
    ---------------------------
    (Web): Bryn says, "Toz is why we can't have nice things."

    StineMoxieVyxsisKalinaarTeaniAloliLim
  • 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 :(
    MoxieVyxsisKalinaarTozMjollTeaniAloli
  • 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

    (Illuminai): Saltz says, "Moxie is just doing the Moxie thing to do, often misinterpreted."

    (Tells): Sir Iames Gallant, the Executioner tells you, "The one Illuminai beyond prayer, I swear."

    Valingar: "How could a daughter of me, the most noble man in the south, be so heartless?"

    (Tells): Haven Locke, Illuminai Khimaira tells you, "Be that as it may, I've also seen the strength in you. You can take care of yourself."
  • 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. 
  • edited March 2019
    Nevermind I can't read :(
  • EliadonEliadon Somewhere Over the Rainbow
    edited March 2019
    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);
    end
    One = 1
    Quatro = 4
    San = 3
    Zwei = 2

    BOOM

    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"

    TozAloli
  • edited March 2019
    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:
       one
       two
       three
       four
    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.
    AloliTozLim
  • AloliAloli Between Books
    This is really helpful, thank you all for taking the time!
    Between what is said and not meant, and what is meant and not said, most of love is lost. - Khalil Gibran
    Kalinaar
  • TozToz
    edited March 2019
    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 fucking awfulness Toz
    ---------------------------
    Didi's voice resonates across the land, "Yay tox."
    ---------------------------

    Ictinus11/01/2021

    Block Toz
    ---------------------------

    limToday at 10:38 PM


    you disgust me
    ---------------------------
    (Web): Bryn says, "Toz is why we can't have nice things."

  • Wanted to necro this because of how helpful this is.
    MoxieSeurimasTozRhine
Sign In or Register to comment.