What does this mean?

Posted by David Berthiaume on Thu 27 Oct 2005 01:06 AM — 32 posts, 135,251 views.

#0
Error number: -2146827287
Event: Execution of line 1 column 1
Description: Out of memory
Line in error:

Called by: Immediate execution
Australia Forum Administrator #1
It is pretty self-explanatory. :)

What program are you running that causes that?
#2
Mushclient, of course.
Sweden #3
Haha...not!

What Nick was asking was not if you ran MUSHClient or not but rather what SCRIPT program/plugin you loaded that crashed.
I have gotten errors like that when I have made a bo-bo in my ScriptFile.

// Fredrik
#4
No boo-boo's in the script file. Runs fine, just not for extended timer periods, the mud I play has just recently allowed idling, to encourage more people to play more, and to get people to cap certain classes to see what they need tweaking with.

Anyways, it's one script that is causing it, once I close mushclient and restart it, it is fine.
Australia Forum Administrator #5
What script language is that? I suspect that there are memory leaks associated with some script engines, I'm not absolutely sure it is a MUSHclient bug. I have tried hard to follow the guidelines for calling script engines, however sometimes the documentation can be obscure.

A possibility is that your script actually has an internal leak, not knowing which engine it is hard to say, but maybe if every time through you allocate something that is not deallocated, in time memory will fill up.
#6
I can show you the script that is setting that off...

<triggers>
  <trigger
   custom_colour="17"
   enabled="y"
   expand_variables="y"
   group="InfoBarLevelScript"
   keep_evaluating="y"
   match="^\&lt;(.*)\%XTL\&gt;$"
   omit_from_output="y"
   regexp="y"
   repeat="y"
   send_to="12"
   other_text_colour="darkcyan"
  >
  <send>world.setvariable "EXPTOLEVEL", "%1"
world.setvariable "XPNEW", "%1"
dim EXPTICK, TICK, TICKERNEW, TICKERBLANK, EXPTOLEVEL, EXPFROMLEVEL, count
dim XPOLD, XPNEW, XPDIFF
XPOLD = CInt(world.getvariable ("XPOLD"))
XPNEW = CInt(world.getvariable ("XPNEW"))
XPDIFF = (XPOLD - XPNEW)
if XPDIFF &lt; 0 then
XPDIFF = (XPDIFF + 100)
world.setvariable "XPOLD", XPNEW
world.setvariable "XPDIFF", XPDIFF
elseif XPDIFF &gt; 0 then
world.setvariable "XPOLD", XPNEW
world.setvariable "XPDIFF", XPDIFF
end if
EXPTOLEVEL = CInt(world.getvariable ("EXPTOLEVEL"))
EXPFROMLEVEL = (100 - EXPTOLEVEL)
world.setvariable "EXPFROMLEVEL", EXPFROMLEVEL
TICKERNEW = "|"
TICKERBLANK = ""
TICK = "|"
EXPTICK = ""
for count = 1 to CInt(world.getvariable ("EXPFROMLEVEL"))
TICKERBLANK = (TICKERBLANK + TICKERNEW)
next
for count = 1 to CInt(world.getvariable ("EXPTOLEVEL"))
EXPTICK = (EXPTICK + TICK)
next
dim space, space2
space = "1"
space2 = "10"
world.infoclear
world.InfoBackground "black"
world.InfoFont "Arial", 12, 1
world.infocolour "white"
world.info "("
if CInt(world.getvariable ("aaHP")) &lt;10 then
InfoColour "black"
Info space2
InfoColour "white"
Info "@aaHP"
elseif CInt(world.getvariable ("aaHP")) &lt; 100 then
InfoColour "black"
world.info space
world.infocolour "white"
world.info world.getvariable ("aaHP") &amp; "%"
else
world.infocolour "white"
world.info world.getvariable ("aaHP") &amp; "%"
end if
world.infocolour "red"
world.info "HP"
world.infocolour "white"
world.info "|"
if CInt(world.getvariable("aaMana")) &lt; 10 then
InfoColour "black"
Info space2
Infocolour "white"
Info "@aaMana"
elseif CInt(world.getvariable("aaMana")) &lt; 100 then
InfoColour "black"
world.info space
InfoColour "white"
world.info world.getvariable ("aaMana")
else
world.info world.getvariable ("aaMana")
end if
world.info "%"
world.infocolour "olive"
world.info "Mana"
world.infocolour "white"
world.info "|"
if Cint(world.getvariable ("aaMove")) &lt; 10 then
InfoColour "black"
Info space2
InfoColour "white"
Info "@aaMove"
elseif CInt(world.getvariable ("aaMove")) &lt; 100 then
InfoColour "black"
world.info space
InfoColour "white"
world.info world.getvariable ("aaMove")
else
world.info world.getvariable ("aaMove")
end if
world.info "%"
world.infocolour "darkcyan"
world.info "Move"
world.infocolour "white"
world.info ") ("
world.infocolour "lightgreen"
world.info world.getvariable ("aaHunger")
world.infocolour "white"
world.info ") "
world.info "["
if CInt(world.getvariable ("EXPTOLEVEL")) &lt; 5 then
world.InfoColour "red"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 10 then
world.InfoColour "lawngreen"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 20 then
world.InfoColour "green"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 30 then
world.InfoColour "darkorange"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 40 then
world.InfoColour "orange"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 50 then
world.InfoColour "goldenrod"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 60 then
world.InfoColour "gold"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 70 then
world.InfoColour "yellow"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 80 then
world.InfoColour "blue"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 90 then
world.InfoColour "mediumblue"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
else
world.infocolour "purple"
world.InfoFont "Arial", 12, 0
world.info EXPTICK
end if
world.infocolour "black"
world.info TICKERBLANK
world.InfoColour "white"

world.InfoFont "Arial", 12, 1
world.info "] (" 
world.infocolour "yellow"
If CInt(world.getvariable ("EXPTOLEVEL")) &lt; 10 then
InfoColour "black"
Info space2
InfoColour "yellow"
Info "@EXPTOLEVEL"
elseif CInt(world.getvariable ("EXPTOLEVEL")) &lt; 100 then
InfoColour "black"
world.info space
InfoColour "yellow"
world.info world.getvariable ("EXPTOLEVEL")
else
InfoColour "yellow"
world.info world.getvariable ("EXPTOLEVEL")
end if
world.infocolour "white"
world.info "%) | Last: " 
world.infocolour "yellow"
world.info world.getvariable ("XPDIFF")
world.infocolour "white"
world.info "% | Level: "
world.infocolour "yellow"
if world.getvariable ("CharacterInfoLevelStatus") = "subhero" then
world.info world.getvariable ("CharacterInfoLevel")
else
world.infocolour "red"
world.info world.getvariable ("CharacterInfoLevelStatus") &amp; world.getvariable ("CharacterInfoLevel")
end if
InfoColour "white"
info " |"
if GetVariable ("CharacterInfoLevelStatus") = "H" then
info " "
InfoColour "green"
world.InfoFont "Arial", 12, 1
Info "Hero Points"
InfoColour "white"
Info ": "
InfoColour "teal"
world.InfoFont "Arial", 12, 1
Info "@CharacterInfoCurrentHeroPoints"
else
end if


world.EnableGroup "Highlighted Words", 0
EnableGroup "CharacterInfoInventory", 0</send>
  </trigger>
</triggers>

#7
I've gotten the same type of error. I use vb script but the error seems random, not just from one program, but turning off the timer and triggers helps. It is not an error in my code.
I'm beginning to suspect it is the timer.
Any thing new on the subject?
Here are two snips of errors from different triggers, it keeps repeating I have to shut down mushclient and restart it.

Script error
World: aetolia mapper
Execution of line 41 column 243
Immediate execution
Out of memory
Line in error:
if world.GetVariable ("possessed")=1 and world.GetVariable ("stun")=0 and world.GetVariable ("frozen")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("balance")=1 and world.GetVariable ("sleeping")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("illusion")=0 then

Script error
World: aetolia mapper
Execution of line 123 column 37
Immediate execution
Out of memory
Line in error:
if world.GetVariable ("baldness")=1 then
USA #8
Hmm. There are known issues with stuff like Python when using direct execution via triggers, I can only guess that something in a service pack or some other change has made the same thing happen with VB. Basically, when you stick code "in the trigger", instead of calling a function in the main script, the script system has to set aside a new chunk of memory ***every time*** the trigger fires. This is often not a problem for very small amounts of code, but if the garbage collection system for the engine isn't working efficiently at cleaning up those chunks of used memory eventually the script system concludes that it doesn't have enough memory to continue to do its job, even though the real problem is that it simply *hasn't released* what it was previously using. Given the nature of this issue, and the fact that it may be tied closely to MS' active script method of making these work, I would suggest, given this is the second language (the first was python) to suffer from it, that placing script commands that are called often directly into triggers, aliases or timers, instead of calling a function, should be limited to Lua, where the nature of how it collects previously used memory, and the way it talks to the client, differ enough that the problem doesn't seem to happen there (or at least hasn't yet been reported).

Basically, either Python and VB are not correctly handling memory cleanup in such cases *or* something about active script prevents it from working quite the way its suppose to.

Mind you, that is just a guess, but it seems pretty likely, given that this problem is only happening in cases where script is executed "in" triggers, aliases or timers, not when its called (and the commands are already preloaded in memory).
Australia Forum Administrator #9
I agree with Shadowfyr - there have been reported problems with "send to script" gradually using up memory, a problem that is fixed by not doing "send to script" but instead moving the relevant script to an external script file, and putting the name of the appropriate function in the script box instead.

This would particularly apply to things that are done frequently (eg. a timer that fires every second).

I do not believe the problem applies to Lua scripting, which does not go through the "black box" which is the Windows Script Host interface.
USA #10
Windows Script Host is a black box? I thought it was a black hole...

I cleared up a clannie's memory errors by converting the "send to script" triggers into triggers which call functions within the script file. I just did it to consolidate the code to be readable, but it fixed the problem. I have never had a problem with Lua scripts, but I do not know if that is from avoiding WSH, if it has better garbage collection, or if it's because I have gotten into the habit of not filling in the "send" window with scripts.
USA #11
Strictly speaking, if we had known this was going to be a problem from the start, some method of pre-parsing "sent to script" data could have been implimented. It would have likely required limiting the use of wildcards to "data", not variable names, like we can do now, but you could take something like:

<triggers>
  <trigger
   custom_colour="17"
   enabled="y"
   expand_variables="y"
   group="InfoBarLevelScript"
   keep_evaluating="y"
   match="^\&lt;(.*)\%XTL\&gt;$"
   omit_from_output="y"
   regexp="y"
   repeat="y"
   send_to="12"
   other_text_colour="darkcyan"
  >
  <send>world.setvariable "EXPTOLEVEL", "%1"
world.setvariable "XPNEW", "%1"
..</send>
  </trigger>
</triggers>

and convert it to:

sub <some_arbitrary_number *or* the trigger name> (wild1)
  world.setvariable "EXPTOLEVEL", wild1
  world.setvariable "XPNEW", wild1
  ...
end sub


It would have only needed to be loaded/unloaded when someone a) changed the trigger, or b) first loaded the plugin/world.

Mind you, coding the converter would have been a bit of a hassle too... lol Still, it would have been one way to fix the problem, had it been a known problem in the first place. Oh well, ce la vie.
Australia Forum Administrator #12
It shouldn't be a problem, and I have spent some time trying to fix it when it was reported earlier. However memory leaks are notoriously hard to track down. For one thing, MUSHclient is continually allocating memory anyway, as each new line that arrives takes memory for the line to be stored, including each individual style run. Thus, a continuous and persistent increase in memory usage (as text arrives) is perfectly normal.

However if additional memory is used each time a timer fires, because it is doing "send to script" is not normal. There are a number of possible reasons:

  1. There is a bug in MUSHclient where something in the compile phase for "send to script" is allocated and never freed (eg. the script text itself).
  2. The memory used by the previous script is not freed (ie. from last time around).
  3. There is a bug in MUSHclient where something in the execution phase for "send to script" is allocated and never freed.
  4. There is a bug in the Windows Script Host (WSH) interface which connects the MUSHclient code to the script engine. This bug might be in the way I am using the WSH, or internal to WSH itself.
  5. There is a bug in the actual script engine (eg. VBscript) where the script writers assumed that a script would be compiled infrequently (eg. once per web page) and don't free all the memory they use (eg. for variables).


Some of these are outside my control. The source for MUSHclient is publicly available, so anyone who is familiar with implementing script interfaces is welcome to make suggestions.

As I mentioned earlier, the Lua interface is different. It does not use the WSH interface, is well documented (unlike the WSH interface), is easy to understand, and seems to work very well. I read on the Lua forums that they ran the Lua script engine through Valgrind or something similar and found absolutely no memory leaks.

Amended on Sun 27 Jan 2008 05:41 AM by Nick Gammon
USA #13
To sum up: Micro$oft did not write the Lua script interface, hence the documentation, ease of use, and the lack of memory leaks.

Now for the non-sardonic part of my post. I would honestly not expect option #5 to be the culprit, since this issue has happened with more than just VBscript. I know the same thing happens with Python and JScript. Options #1 and #4 seem to be the most probable. Tables for parsing are notorious for getting very messy very quickly. Also, since the API for WSH is not exactly user friendly, there could easily be an obfuscated flag which needs to be set somewhere for actually clearing out old data instead of keeping it allocated.

Option #2 seems to be a given, but most likely is the result of another one of the options. Option #3 just seems not terribly likely, but that certainly does not rule it out.
USA #14
Well, I didn't say it was the "only" solution, just *A* solution, if the problem happened to be 2 or 4, since it would the also the "only" solution possible.

That said... If one set up a feed, in which there is a known number of characters per line, with known numbers of color codes (or none), then presumably each "line" would take a set allocation of additional memory. One could then profile shifts in memory usage that *are not* caused by the input itself, in theory. Its a bit beyond me though. :p
#15
Thank you to everyone who helped with this issue. It has been getting frustrating.
I optimized my code and turned timers off thinking it might have been the issue, but I still got the same type of error mid-battle needless to say I didn't win.

So basically it sounds like I have to convert all my code to lua script?

I've used mushclient for approx 7 years and I would prefer to keep it over going to another client.

Is lua much different from vbscript?
Australia Forum Administrator #16
Well, converting to Lua would certainly be an option, that might make things easier in the future. However what should solve your immediate problem with less work would be to move stuff from "send to script" to scripting functions inside a separate script file.

For more details about the differences between "send to script" and a script file, see:

htp://www.mushclient.com/scripting


Basically what would be involved is:

  • Make an empty script file in the text editor
  • Select that as the script file in the scripting configuration
  • For each trigger and alias, copy the "send to script" code from within it, and paste into a separate function in the script file, like this:

    
    Sub Trigger1 (name, line, wildcards)
    
    '  
    '  --> paste the script here
    '
    
    End Sub
    

  • Change the "send to" type from "send to script" back to "send to world". This stops it trying to compile it every time, and thus avoids the memory leak.
  • Put the name of the function (eg. Trigger1 in my example) in the "script" box of the trigger/aias.
  • If you used wildcards in the trigger/alias, you need to change them from %<something> to use the wildcards array. For example:

    Old
    
    nameofmob = "%1"
    



    New
    
    nameofmob = wildcards (1)
    

  • Save the script file (make sure it is reprocessed) and test it


If you want to convert to Lua instead, then you can leave things in "send to script". Lua is fairly similar in many ways to VBscript, but there are certainly differences. For one thing, Lua is case-sensitive, so where you got away with this in VBscript:


world.note "hi there"


In Lua that has to be:


world.Note "hi there"


If you are planning to convert to Lua it would help if you posted some examples (a couple of your more complex triggers perhaps) so I could look at your general style (that is, the things in VBscript that you usually use) and advise a way of quickly converting them.
#17
Thank you I do appreciate the help. I play on Aetolia and the combat system is very complex, everyone has a 'system' for combat so I have to have one to keep up. Most do not use mushclient though and the ones who do that I have met aren't overly inclined to help.

I haven't done any real scripts, I have a background in programming but I graduated college as a Computer programmer 10 years ago, I'm just a little outdated. My strongest language is C/C++. It's been slowly coming back but the logic is still there.

I'll past the alias first, it's a simple one because the others are fairly large. The prompt which is similar to a "main" function I will post right after as the last time I was over the character limit to post.
I also do all the coding through the gui.

Alias:
CanAttack

if world.GetVariable ("erebound")=0 and world.getvariable ("hasshield")=0 then
world.Execute "ds"
end if
if world.getvariable ("erebound")=1 and world.getvariable ("hasshield")=1 then
world.Execute "rs"
end if
if world.getvariable ("erebound")=1 and world.getvariable ("hasshield")=0 then
world.Execute "rs"
end if
if world.getvariable ("erebound")=0 and world.getvariable ("hasshield")=1 then
world.Execute "rs"
end if
#18
world.SetVariable "health", "%1"
world.SetVariable "mana", "%2"
dim curhp
dim curmp
curhp=%1
curmp=%2
if curhp < 2800 and world.GetVariable ("moss")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("stun")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("anorexia")=0 then
world.Execute "emo"
world.SetVariable "moss", "0"
end if
if curhp < 3300 and world.GetVariable ("elixir")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("stun")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("belonephobia")=0 and world.GetVariable ("addiction")=0 then
world.Execute "sh"
world.SetVariable "elixir", "0"
end if
if curmp < 2500 and curhp > 2900 and world.GetVariable ("elixir")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("stun")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("belonephobia")=0 and world.GetVariable ("addiction")=0 then
world.Execute "sm"
world.SetVariable "elixir", "0"
end if
if world.GetVariable ("illusion")=1 then
world.Execute "resettemps"
end if
world.Execute "setaff"
if world.GetVariable ("indifference")=1 and world.GetVariable ("salve")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("slickness")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("stun")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("illusion")=0 then
world.Send "press oculi"
world.SetVariable "salve", "0"
end if
if world.GetVariable ("stupidity")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("illusion")=0 and world.GetVariable ("herb")=1 and world.GetVariable ("sleeping")=0 and world.GetVariable ("belonephobia")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("indifference")=0 and world.GetVariable ("stun")=0 then
world.Send "outc 2 liver slice"
world.Send "eat liver slice"
world.Send "inc liver slice"
end if
if world.GetVariable ("paralysis")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("illusion")=0 and world.GetVariable ("stupidity")=0 and world.GetVariable ("herb")=1 and world.GetVariable ("sleeping")=0 and world.GetVariable ("belonephobia")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("indifference")=0 and world.GetVariable ("stun")=0 then
world.Send "outc lung slice"
world.Send "eat lung slice"
world.SetVariable "herb", "0"
end if
if world.GetVariable ("limp_veins")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("balance")=1 and world.GetVariable ("aeon")=0 then
world.Send "Fitness"
world.SetVariable "balance", "0"
world.SetVariable "fitness", "1"
end if
if world.GetVariable ("slickness")=1 and world.GetVariable ("stun")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("limp_veins")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("illusion")=0 then
world.Execute "ia"
end if
if world.GetVariable ("belonephobia")=1 and world.GetVariable ("salve")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("slickness")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("stun")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("illusion")=0 then
world.Send "press oculi on torso"
setvariable "salve", "0"
end if
if world.GetVariable ("fsleep")=1 and world.GetVariable ("illusion")=0 and world.GetVariable ("sleeping")=1 and world.GetVariable ("aeon")=0 then
world.Execute "wake"
else
if world.GetVariable ("insomnia")=0 and getvariable ("fsleep")=0 and getvariable ("balance")=1 and getvariable ("equilibrium")=1 and getvariable ("sleeping")=0 and getvariable ("fighting")=1 then
world.Send "insomnia"
end if
end if
if getvariable ("limp_veins")=1 and getvariable ("slickness")=1 and getvariable ("belonephobia")=1 and getvariable ("paralysis")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("stun")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("illusion")=0 and world.GetVariable ("balance")=1 then
world.Send "fitness"
world.Execute "ia"
else
if getvariable ("limp_veins")=1 and getvariable ("slickness")=1 and getvariable ("belonephobia")=1 and getvariable ("paralysis")=1 and getvariable ("confusion")=1 and getvariable ("frozen")=1 then
world.SetVariable "truelock", "1"
end if
end if
if world.GetVariable ("broken_larm")=1 and world.GetVariable ("broken_rarm")=1 and world.GetVariable ("stun")=0 and world.GetVariable ("illusion")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("equilibrium")=1 then
world.Execute "restore"
end if
to be cont...
#19
if world.GetVariable ("stun")=0 and world.GetVariable ("illusion")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("herb")=1 and world.GetVariable ("sleeping")=0 and world.GetVariable ("belonephobia")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("indifference")=0 then
world.SetVariable "ccslice", "1"
else
world.SetVariable "ccslice", "0"
end if
if world.GetVariable ("salve")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("slickness")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("stun")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("illusion")=0 then
world.SetVariable "ccpoultice", "1"
else
world.SetVariable "ccpoultice", "0"
end if
if world.GetVariable ("stun")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("moss")=1 and world.GetVariable ("sleeping")=0 and world.GetVariable ("anorexia")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("illusion")=0 then
world.SetVariable "ccmoss", "1"
else
world.SetVariable "ccmoss", "0"
end if
if world.GetVariable ("stun")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("limp_veins")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("illusion")=0 then
world.SetVariable "ccsyringe", "1"
else
world.SetVariable "ccsyringe", "0"
end if
if world.GetVariable ("freedom")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("stun")=0 and world.GetVariable ("writhe")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("illusion")=0 then
world.Execute "CureWrithe"
end if
if world.GetVariable ("possessed")=1 and world.GetVariable ("stun")=0 and world.GetVariable ("frozen")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("balance")=1 and world.GetVariable ("sleeping")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("illusion")=0 then
world.Send "lose soulmaster"
end if
if world.GetVariable ("stun")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("frozen")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("fear")=1 and world.GetVariable ("aeon")=0 and world.GetVariable ("illusion")=0 then
world.Send "Compose"
end if
if world.GetVariable ("prone")=1 and world.GetVariable ("stun")=0 and world.GetVariable ("dead")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("balance")=1 and world.GetVariable ("broken_lleg")=0 and world.GetVariable ("broken_rleg")=0 and world.GetVariable ("paralysis")=0 and world.GetVariable ("freedom")=1 and world.GetVariable ("illusion")=0 then
world.Send "stand"
end if
if world.GetVariable ("freedom")=1 and world.GetVariable ("dead")=0 and world.GetVariable ("stun")=0 and world.GetVariable ("writhe")=0 and world.GetVariable ("sleeping")=0 and world.GetVariable ("aeon")=0 and world.GetVariable ("illusion")=0 then
world.Execute "CureAll"
end if
USA #20
Ummm, Nick, the Lua conversion you posted was wrong, only slightly...

world.Note "hi there"

Should be...

world.Note("hi there")

I know it is a minor slip, but still for someone learning about Lua, they need all the finer details :)

-Onoitsu2
Australia Forum Administrator #21
Actually, the code I posted does work, try it and you will see. As a special case Lua allows a single string literal to appear with the brackets. Thus you can do this:


world.Note "hi there"


or


world.Note ("hi there")


I left the brackets out because it was closer to the VB syntax.

However if you want multiple things, or variables, you must use the brackets, eg.


world.Note ("two plus two = ", 2 + 2)

Australia Forum Administrator #22
As for converting that script to Lua, this is what I did:

  1. Copied and pasted the whole thing into one of MUSHclient's notepad windows.
  2. I fixed the capitalization of function names, which Lua requires to be correct, by using the Search menu -> Global Replace (Ctrl+Shift+G), as described in the forum post "How to fix capitalization of function names in scripts":

    http://www.gammon.com.au/forum/?id=6211

    That is:

    
    
    Find Pattern: [%a%d]+
    Replacement: f
    Call function: checked
    Script:
    
    t1 = utils.functionlist ()
    t2 = {}
    
    -- keys are lower-case functions, values are original functions
    
    table.foreach (t1, function (k, v) t2 [string.lower (v)] = v end )
    
    function f (str)
      return t2 [string.lower (str)] or str
    end -- function f
    


    This changed things like world.getvariable to world.GetVariable
  3. I fixed up "if" statements by doing a global replace of "end if" to "end -- if"
  4. The word "world." is a bit redundant, so I changed "world." to nothing. So in other words:

    
    world.Execute "sh"
    


    becomes:

    
    Execute "sh"
    

  5. As Onoitsu2 pointed out, generally speaking Lua function calls have to be in brackets. In particular you were doing a lot of SetVariable without the brackets. So I used the Search menu -> Global Replace to do another big cleanup:

    
    Find Pattern: SetVariable%s*(.+)
    Replacement: SetVariable (%1)
    Call function: NOT checked
    


    This changes, for example:

    
    SetVariable "truelock", "1"
    


    to:

    
    SetVariable ("truelock", "1")
    

  6. To define local variables Lua uses "local" rather than "dim" so I changed:

    
    dim curhp
    dim curmp
    


    to

    
    local curhp
    local curmp
    

  7. Lua uses == to compare for equality, not =, so another fixup using Search menu -> Global Replace was required:

    
    Find Pattern: GetVariable%s*%(%s*(.-)%s*%)%s*=%s*(%d+)
    Replacement: GetVariable (%1) == "%2"
    Call function: NOT checked
    


    After running this lines like this:

    
    if world.GetVariable ("erebound")=0 and world.getvariable ("hasshield")=0 then
    


    changed to:

    
    if GetVariable ("erebound") == "0" and GetVariable ("hasshield") == "0" then
    


    Note also I quoted the number you are comparing to, as Lua considers "0" and 0 to be different. One is a string and one is a number.
  8. I wanted to make the long "if" statements a bit easier to read, so another Search menu -> Global Replace was used to break the long if statements after the "and", like this:

    
    Find Pattern:  and 
    Replacement:  and\n   
    Call function: NOT checked
    Escape sequences: checked
    


    The find pattern is actually: (space)and(space)
    The replace pattern is actually: (space)and\n(space)(space)(space)

    I mention that because the spaces are hard to see.

    This adds a line break after each "and".
  9. For neatness I also added a blank line after each if:

    
    Find Pattern: end %-%- if
    Replacement:  end -- if\n   
    Call function: NOT checked
    Escape sequences: checked
    

  10. I also wanted to indent the inside of an "if" like this:

    
    Find Pattern: ^Execute 
    Replacement:        Execute  
    Call function: NOT checked
    


    (That is 6 spaces before "Execute" in the replacement box).

    Ditto for the words "SetVariable" and "Send".


A couple of manual cleanups of spacing, and this is the finished result:


if GetVariable ("erebound") == "0" and
   GetVariable ("hasshield") == "0" then
      Execute "ds"
end -- if

if GetVariable ("erebound") == "1" and
   GetVariable ("hasshield") == "1" then
      Execute "rs"
end -- if

if GetVariable ("erebound") == "1" and
   GetVariable ("hasshield") == "0" then
      Execute "rs"
end -- if

if GetVariable ("erebound") == "0" and
   GetVariable ("hasshield") == "1" then
      Execute "rs"
end -- if


SetVariable ("health", "%1")
SetVariable ("mana", "%2")

local curhp
local curmp

curhp=%1
curmp=%2

if curhp < 2800 and
   GetVariable ("moss") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("stun") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("anorexia") == "0" then
      Execute "emo"
      SetVariable ("moss", "0")
end -- if

if curhp < 3300 and
   GetVariable ("elixir") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("stun") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("belonephobia") == "0" and
   GetVariable ("addiction") == "0" then
      Execute "sh"
      SetVariable ("elixir", "0")
end -- if

if curmp < 2500 and
   curhp > 2900 and
   GetVariable ("elixir") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("stun") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("belonephobia") == "0" and
   GetVariable ("addiction") == "0" then
      Execute "sm"
      SetVariable ("elixir", "0")
end -- if

if GetVariable ("illusion") == "1" then
      Execute "resettemps"
end -- if

Execute "setaff"

if GetVariable ("indifference") == "1" and
   GetVariable ("salve") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("slickness") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("stun") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("illusion") == "0" then
      Send "press oculi"
      SetVariable ("salve", "0")
end -- if

if GetVariable ("stupidity") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("illusion") == "0" and
   GetVariable ("herb") == "1" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("belonephobia") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("indifference") == "0" and
   GetVariable ("stun") == "0" then
      Send "outc 2 liver slice"
      Send "eat liver slice"
      Send "inc liver slice"
end -- if

if GetVariable ("paralysis") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("illusion") == "0" and
   GetVariable ("stupidity") == "0" and
   GetVariable ("herb") == "1" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("belonephobia") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("indifference") == "0" and
   GetVariable ("stun") == "0" then
      Send "outc lung slice"
      Send "eat lung slice"
      SetVariable ("herb", "0")
end -- if

if GetVariable ("limp_veins") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("balance") == "1" and
   GetVariable ("aeon") == "0" then
      Send "Fitness"
      SetVariable ("balance", "0")
      SetVariable ("fitness", "1")
end -- if

if GetVariable ("slickness") == "1" and
   GetVariable ("stun") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("limp_veins") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("illusion") == "0" then
      Execute "ia"
end -- if

if GetVariable ("belonephobia") == "1" and
   GetVariable ("salve") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("slickness") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("stun") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("illusion") == "0" then
      Send "press oculi on torso"
      SetVariable ("salve", "0")
end -- if

if GetVariable ("fsleep") == "1" and
   GetVariable ("illusion") == "0" and
   GetVariable ("sleeping") == "1" and
   GetVariable ("aeon") == "0" then
      Execute "wake"
else
if GetVariable ("insomnia") == "0" and
   GetVariable ("fsleep") == "0" and
   GetVariable ("balance") == "1" and
   GetVariable ("equilibrium") == "1" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("fighting") == "1" then
      Send "insomnia"
end -- if

end -- if

if GetVariable ("limp_veins") == "1" and
   GetVariable ("slickness") == "1" and
   GetVariable ("belonephobia") == "1" and
   GetVariable ("paralysis") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("stun") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("illusion") == "0" and
   GetVariable ("balance") == "1" then
      Send "fitness"
      Execute "ia"
else
if GetVariable ("limp_veins") == "1" and
   GetVariable ("slickness") == "1" and
   GetVariable ("belonephobia") == "1" and
   GetVariable ("paralysis") == "1" and
   GetVariable ("confusion") == "1" and
   GetVariable ("frozen") == "1" then
      SetVariable ("truelock", "1")
end -- if

end -- if

if GetVariable ("broken_larm") == "1" and
   GetVariable ("broken_rarm") == "1" and
   GetVariable ("stun") == "0" and
   GetVariable ("illusion") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("equilibrium") == "1" then
      Execute "restore"
end -- if


if GetVariable ("stun") == "0" and
   GetVariable ("illusion") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("herb") == "1" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("belonephobia") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("indifference") == "0" then
      SetVariable ("ccslice", "1")
else
      SetVariable ("ccslice", "0")
end -- if

if GetVariable ("salve") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("slickness") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("stun") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("illusion") == "0" then
      SetVariable ("ccpoultice", "1")
else
      SetVariable ("ccpoultice", "0")
end -- if

if GetVariable ("stun") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("moss") == "1" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("anorexia") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("illusion") == "0" then
      SetVariable ("ccmoss", "1")
else
      SetVariable ("ccmoss", "0")
end -- if

if GetVariable ("stun") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("limp_veins") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("illusion") == "0" then
      SetVariable ("ccsyringe", "1")
else
      SetVariable ("ccsyringe", "0")
end -- if

if GetVariable ("freedom") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("stun") == "0" and
   GetVariable ("writhe") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("illusion") == "0" then
      Execute "CureWrithe"
end -- if

if GetVariable ("possessed") == "1" and
   GetVariable ("stun") == "0" and
   GetVariable ("frozen") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("balance") == "1" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("illusion") == "0" then
      Send "lose soulmaster"
end -- if

if GetVariable ("stun") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("frozen") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("fear") == "1" and
   GetVariable ("aeon") == "0" and
   GetVariable ("illusion") == "0" then
      Send "Compose"
end -- if

if GetVariable ("prone") == "1" and
   GetVariable ("stun") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("balance") == "1" and
   GetVariable ("broken_lleg") == "0" and
   GetVariable ("broken_rleg") == "0" and
   GetVariable ("paralysis") == "0" and
   GetVariable ("freedom") == "1" and
   GetVariable ("illusion") == "0" then
      Send "stand"
end -- if

if GetVariable ("freedom") == "1" and
   GetVariable ("dead") == "0" and
   GetVariable ("stun") == "0" and
   GetVariable ("writhe") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("aeon") == "0" and
   GetVariable ("illusion") == "0" then
      Execute "CureAll"
end -- if


I hope that gives the general flavour of the "before" and "after". If you have hundreds of similar aliases you could write a script that effectively automated those steps. If you only have a dozen it shouldn't take too long to do them by hand. You could copy and paste them all into one notepad file (separated by hyphens or something) and do each step on the lot as a batch.
Amended on Mon 28 Jan 2008 05:51 AM by Nick Gammon
Australia Forum Administrator #23
What I mean by automating the process is ...

The Search menu -> Global Replace function in the internal notepad basically uses Lua string.gsub function to do its replacements. So you could do this:

  • Use the function GetAliasList to get a list of all the aliases.
  • For each alias, see if it uses "send to script"
  • If it uses "send to script" get a copy of the script (using GetAliasOption).
  • Run through the script doing each of the changes I mentioned, by using string.gsub. You may need a few other changes (eg. changing VB comments to Lua comments).
  • Put the corrected script back (SetAliasOption)
  • Move onto the next one


Ditto for triggers and timers.

I would certainly work on a copy of my world file, in case it doesn't work perfectly the first time.
#24
Thank you so much for the time you have put into this. I really do appreciate it.

I've been going through and just pulling the code into word pad, doing replace all and double checking to make sure it's right. Won't that do the same thing?

I'm new to coding in any sort of mud client. I've used Mushclient for years but the other muds I played didn't allow triggers or scripts so never had to use it before. Lua is also completely new to me. I at least had some background with VB. Though it does look nearly the same and I understand the concepts.

Again thank you
Katherina
Australia Forum Administrator #25
Wordpad will certainly do some of the replacements, but some of the more sophisticated ones require something like the Global Replace. For example, the table lookup of lower-case function names to the correctly-capitalized one can be done in one pass in MUSHclient, but would require you to handle each one individually in Wordpad.

Also stuff like changing:

SetVariable "something", "something"

to

SetVariable ("something", "something")

is easier using the method I suggested because it is taking the somethings in the middle and putting brackets around them.
USA #26
As useful as that conversion method would be for most people, I would only suggest using that to get started with Lua scripting. As you learn Lua, you can take advantage of many "tricks" Lua has within it, as well as taking advantage of the wonderful interface with MUSHclient (mostly due to not having to go through WSH).

When I first started using Lua, I went through and converted all of my VBscript and JScript plugins to Lua line by line. They worked alright, but once I actually learned what I was doing, I was able to completely rewrite all these files from scratch to be more elegant and efficient. It would be the same converting from Lua to VBscript or any other language. Each one has its own unique strong points.

The site that helped me out the most with learning Lua, and the one I still visit most frequently when I have questions, is on the Lua user wiki. This "tutorial" is not really a tutorial per se, but it does explain most of the functionality of Lua quite well.
http://lua-users.org/wiki/TutorialDirectory
Australia Forum Administrator #27
True, you can make it more Lua-like, although initially I wanted it to look fairly much like VB to make it easier to make the transition. Here is something you could do ...

Instead of something like this, which does a lot of GetVariable:


if GetVariable ("stun") == "0" and
   GetVariable ("sleeping") == "0" and
   GetVariable ("frozen") == "0" and
   GetVariable ("dead") == "0" and
   GetVariable ("fear") == "1" and
   GetVariable ("aeon") == "0" and
   GetVariable ("illusion") == "0" then
      Send "Compose"
end -- if


You can write a helper function that gets the variable, and compares it to "1" (being "true" I presume). The function returns true if the variable is equal to "1" and false otherwise. Thus it could look shorter, like this:


function aff (which)
  return GetVariable (which) == "1"
end -- function aff

if not aff ("stun") and
   not aff ("sleeping") and
   not aff ("frozen") and
   not aff ("dead") and
   aff ("fear") and
   not aff ("aeon") and
   not aff ("illusion") then
      Send "Compose"
end -- if


I put "not" in front of the test if I wanted to be testing for false (that is, zero).
Amended on Mon 28 Jan 2008 09:23 PM by Nick Gammon
Australia Forum Administrator #28
You can get a bit fancier by making a table with a metatable which means you can have even less typing, along these lines:


aff = {}

setmetatable (aff, 
   {
   __index = function (t, name) 
              return GetVariable (name) == "1"
             end
   }
   )

if not aff.stun and
   not aff.sleeping and
   not aff.frozen and
   not aff.dead and
   aff.fear and
   not aff.aeon and
   not aff.illusion then
      Send "Compose"
end -- if



Notice now we have not needed to quote words like "stun".

You may want to read up on Lua table handling to see what is happening here, but basically we have an empty table called "aff" with a metatable on it that is called if a key (like "stun") is not found in the table. The metatable handler then does a GetVariable to return the appropriate result.
#29
Awesome thank you both.
#30
Hi,
I'm sorry to be a bother again but I've been looking for an example for a couple of hours now of how to send with a temp variable and haven't found anything. It's 3:30am and I have to get to bed.
What I am wanting to do is this. This is the vbscript

Send "decay" & targ

where targ is the local variable

I would guess it is probably Send ("decay", targ)
but I want to be sure. I'm changing a lot of code and it's difficult to debug so I want to make sure I do it right the first time.

Australia Forum Administrator #31
As documented here:

http://www.gammon.com.au/scripts/function.php?name=Send

You can use multiple arguments to Send and they are concatentated together without a space between then so you might want to take that into account.

However the concatenation operator in Lua is .. so you could have written:


Send ("decay" .. targ)


Note the brackets, and again note that no space will be supplied. So, if targ was "fish", it would send "decayfish" without a space.