Lua version of "elsif"? NEW: more if/then questions

Posted by Caelen on Sat 10 Jul 2010 08:32 AM — 20 posts, 77,297 views.

#0
How would I make an "else if" argument in Lua? I'm trying to make a multi-stage conditional trigger to fill three different pipes or light any of three different pipes, based on the item I put inside them.


alias: fillpipe *
if "%1" == "elm" then
 Send "outr 1 elm"
 Send "fill @elmpipe with elm"
else if "%1" == "valerian" then
 Send "outr 1 valerian"
 Send "fill @valerianpipe with valerian"
else if "%1" == "skullcap" then
 Send "outr 1 skullcap"
 Send "fill @skullcappipe with skullcap"
else
 print "fillpipe with elm, valerian, or skullcap only."
end


I haven't found any documentation on Lua's version of the old "elsif" to work with, and "elsif" doesn't seem to work.
Amended on Sat 10 Jul 2010 08:37 AM by Caelen
USA #1
It's just "elseif". ;)
Amended on Sat 10 Jul 2010 08:44 AM by Twisol
#2
Oy, figures it'd be something simple. XD
USA #3
Also, this probably won't matter much in this case, but here's a nice little trick for when you need to check the same variable against a bunch of values:

local pipeherbs = {
  elm = true,
  valerian = true,
  skullcap = true,
}

if pipeherbs["%1"] then
  Send("outr 1 %1")
  Send("fill " .. GetVariable("%1pipe") .. "with %1")
else
  print("fillpipe with elm, valerian, or skullcap only.")
end


It semi-emulates a switch statement.
#4
Oooh, handy. I'll remember that one.

The final draft, tested and functional,


<aliases>
  <alias
   match="fillpipe *"
   enabled="y"
   expand_variables="y"
   group="Pipe"
   send_to="12"
   sequence="100"
  >
  <send>if "%1" == "elm" then
 Send "outr 1 elm"
 Send "put elm in @elmpipe"
elseif "%1" == "valerian" then
 Send "outr 1 valerian"
 Send "put valerian in @valerianpipe"
elseif "%1" == "skullcap" then
 Send "outr 1 skullcap"
 Send "put skullcap in @skullcappipe"
else
 print "fillpipe with elm, valerian, or skullcap only."
end</send>
  </alias>
  <alias
   match="lightpipe *"
   enabled="y"
   expand_variables="y"
   group="Pipe"
   send_to="12"
   sequence="100"
  >
  <send>if "%1" == "elm" then
 Send "light @elmpipe"
elseif "%1" == "valerian" then
 Send "light @valerianpipe"
elseif "%1" == "skullcap" then
 Send "light @skullcappipe"
else
 print "lightpipe with elm, valerian, or skullcap only."
end</send>
  </alias>
</aliases>

#5

<triggers>
  <trigger
   enabled="y"
   expand_variables="y"
   match="You reel your line in and stop with the hook at * feet."
   send_to="12"
   sequence="100"
  >
  <send>require "wait"

wait.make (function ()
if %1 &gt; 30 then
 Send "reel in"
else
 wait.time (5)
 if (GetVariable("caughtafish")) == "yes" then
  wait.time(45)
  print "5"
  wait.time(1)
  print "4"
  wait.time(1)
  print "3"
  wait.time(1)
  print "2"
  wait.time(1)
  print "1"
  wait.time(1)
  print "REEL IN"
 else
  Send "reel all the way"
 end
end
end)</send>
  </trigger>
</triggers>


I'd like to make the second if/then check for one of two things (if the variable is true OR if the wildcard is greater than 10) and return as true and continue the timer. I want it to be continue the timer if one or both of the conditions are met, but not if neither of them are. How can I do this?

My other option is to just make a second trigger that picks up the same thing, have it keep evaluating and push the sequence up a bit, and have it set the variable in question, but I'm sure there's an easier way... I saw something with a (<text>|<text>) format for an OR setup, but I'm not sure how to use that within an if/then.
USA #6
The first thing you need to realize is that the regexp syntax - stuff like ^I (like|hate) pie\.$ - is not Lua. It's parsed by a separate engine called PCRE. So it's probably not a good idea to take syntactic cues from regexp syntax. :)

At any rate, you can do exactly what you're asking for. Example without it:

if a then
  if c then
    Note("foo")
  elseif d then
    Note("foo")
  end
elseif b then
  if c then
    Note("foo")
  elseif d then
    Note("foo")
  end
end


That can be straightened out to:

if (a or b) and (c or d) then
  Note("foo")
end


Basically, the "or" corresponds to two branches having the same content, while the "and" corresponds to an if within an if. I hope that made sense!

Also, a/b/c/d above are just placeholders. You could drop in other boolean expressions like %1 > 10 as you asked for below. And parentheses are important! I can never remember the precedence rules for and/or/not, so I just avoid the issue with parentheses so it's abundantly obvious what it does.
#7
Brings me back to my old college classes in logic with that setup... and yeah, I see it now. Thanks! Even showed me how to do the "and" arguments too :3
#8
Since I love ifs, more questions! Since I can now use "true" and "false" as my variables (I forgot to get 4.53... now I have 4.54 <3 ), would I be able to shorten

if (GetVariable("asdf")) == "true" then

to

if (GetVariable("asdf")) then

and get the same effect?
Australia Forum Administrator #9
You need to distinguish between MUSHclient variables (which are saved in the world file) and Lua variables (which are not, unless you "serialize" them).

MUSHclient variables are always strings (ie. alphanumeric) and in Lua a string is always true.

That is:


x = "true"

if x then
  print "this is true"
end -- if

x = "false"

if x then
  print "this is true"
end -- if


Compare to:



x = true

if x then
  print "this is true"
end -- if

x = false

if x then
  print "this is true"
end -- if


If you try this out, the first example will print "this is true" both times, the second one, only the first time.

For simple tests within triggers etc. you are better off just using Lua variables, in which case you can use "if x then ...".

But if you want to use MUSHclient variables, you have to stick to testing the string, eg. "if GetVariable ("x") == "true" then ...".
Amended on Wed 21 Jul 2010 12:03 AM by Nick Gammon
USA #10
The only values considered boolean-false in Lua are nil and false. A string in a boolean context (as in your "if GetVariable('foo')" question) is always considered true, even if it's empty. That's why you do need the comparison to "true", because it compares the two strings and tells you if they're identical.

Lua variables are more versatile and arguably easier to use in general. I usually reserve MUSHclient variables for tasks like regexp interpolation (like ^(@!friends) waves hello\.$), serialization, and communication between plugins, because those are the only common things Lua variables can't readily do.
#11
Hmm... alright, I think I see it. But, that raises another question. What is a Lua variable, compared to a MUSH variable?
USA #12
Lua:
local x = 42 -- Lua variable, setting.
Note(x)      -- Lua variable, using.


MC:
SetVariable("x", "42") -- MC variable, setting. STRING, not number.
Note(GetVariable("x"))       -- MC variable, getting.


MC variables are just storage slots, cubbyholes you can drop data into. To do anything with the data, you need to get it back and then do whatever. Lua variables, while also fundamentally "storage", can be manipulated directly.

It should be noted that GetVariable() returns a string, which is a Lua value. Likewise, SetVariable() takes a string. The main difference is that they can only be strings, and you have to get them back with the function before you can mess with them. MC variables are not fundamentally different beyond this indirection.
#13
When you set a variable, is it stored and ready to use by any trigger or alias that might call on it? I use assorted triggers to set variables that are used to say what to do, like, one variable per affliction to cure in Achaea, and a single "healme" alias that cures one affliction per use in the order I want them cured. Can I do the same thing with Lua variables instead of MUSH variables?
USA #14
Yes, but you just remove the 'local' prefix. When you use 'local', it's only available within the block it's defined in. A trigger's send box basically counts as a block.

When you remove the 'local' prefix, the variable is set into the "environment", or in other words becomes a global. It can be accessed from anywhere as long as there isn't another local variable of the same name hiding it.


Basically, just use 'local' for temporary variables and don't use 'local' when you want to use the same data within more than one block.
USA #15
Quote:
When you set a variable, is it stored and ready to use by any trigger or alias that might call on it?

For MC variables, yes; for Lua variables, no. Even a 'global' Lua variable is constrained to its plugin's environment, if I remember correctly. Beyond that are the issues of block-locality that Twisol explained.

Even if the Lua global were truly global, it would only be to the Lua state and not usable by other languages, or in triggers etc.; that's where the MC variables come in.
USA #16
David Haley said:
For MC variables, yes;

With the stipulation that you have to use GetPluginVariable() to access another plugin's variables, and you can't set them.

David Haley said:
Even a 'global' Lua variable is constrained to its plugin's environment, if I remember correctly. [...]

Even if the Lua global were truly global, it would only be to the Lua state and not usable by other languages, or in triggers etc. [...]


I'm confused by what you're trying to say. If you set a variable in a trigger or alias, and it doesn't have 'local' on it, then it's added to the Lua environment table _G. If a variable lives in _G, it's called a global. I'm not seeing how it's not "truly" global except where it can't be accessed from other plugins, which is logical because they each get their own instance of the Lua interpreter. Care to clarify?
Amended on Wed 21 Jul 2010 05:08 PM by Twisol
USA #17
Twisol said:
I'm not seeing how it's not "truly" global except where it can't be accessed from other plugins

Exactly, hence it's not "truly" global... why do you say that you don't understand why it's not truly global when you add your own caveats explaining why it's not? ;)

The question was about variables across triggers, aliases, etc., and whether Lua variables can be used to do the same thing as MC variables. And the answer is no, not really, because a plugin's "global variable" is not truly global to MC.
Australia Forum Administrator #18
Just to clarify for the original poster, plugins are intended to have separate script and variable spaces. This is so that, whether you use MUSHclient variables, or script variables, there is no clash between one plugin and another.

For example, one plugin author might have a variable "count" which is a count of mobs killed, and another one might have a variable "count" which is a count of the times you levelled.

The "main world" file (that is, outside any plugin) is effectively another script and variable space again (so plugins don't clash with non-plugins).

So, in the main world file, or inside a particular plugin, you have two ways of storing and accessing variables:

  • MUSHclient variables
  • Script-language variables (whatever the language is)


The MUSHclient variables have the advantage you can access them from triggers (like matching on @mobname in a trigger). They are also saved from one session to another, to disk, assuming you save your world file. Plugin variables are saved to disk if you enable the "save state" flag when writing the plugin.

Script language variables on the other hand are easier to use. Compare:


count = count + 1  -- script variable

SetVariable ("count",  tonumber (GetVariable ("count")) + 1) -- MUSHclient variable


Also script language variables are not saved to disk unless you take steps to do so. This is called serialization, and often takes the form of converting script variables to MUSHclient variables at the last moment, so they get saved to disk. Then next time the world is opened you have to convert them back.

Moving onto the "local" issue - Lua variables are generally speaking "global" - that is, available to every alias, plugin, or script in general. This means a count of mobs killed you might add to in a trigger, is also accessible in an alias.

However if you use the "local" keyword, then that variable is not stored in the "global environment" and becomes local to the block where it is declared. For example:


local x

x = 22
x = x + 1


This code (if in a trigger or alias script) would not change a variable "x" used "globally" elsewhere. This may well be what you want, if you are just using "x" as a "work" variable.

So, like with many things, it is a case of using the right tool for the job. Local variables have their uses, and MUSHclient variables have their uses too. Choose one that suits what you are trying to do.
#19
It all makes sense now! I will just continue to use the slightly more lengthy mush variables for my assorted triggers, since I usually want my variables saved to the disk. I don't think I've needed a temporary variable for anything yet... I'll keep it in mind though. Never know when something I have no use for will suddenly decide it's time to be used!