Alias is too large

Posted by Blixel on Sat 30 Mar 2019 01:51 PM — 17 posts, 60,111 views.

#0
I have created an alias that I use to gain experience for my character. It's a big while loop that essentially does these things:

  • Make sure the character is maxed out on health items.
  • Walk through dungeon, room by room to kill mobs to grind out experience.
  • When the character is running low on health items, return home and repeat the loop.


My alias works really well, but I have reached a point where my alias is so long that I can't seem to add anything more to it.

So my question is ... is there a way I can keep adding to my alias? (Like using an external editor?) I know if I go to World Settings -> Scripting -> Scripts, I can set up an external editor ... but I don't have any such option for aliases or triggers.

Here is the alias ... this version of it still has room to add more, but I can't add very many more rooms before I hit the limit.


require "wait"

-- Before we do anything, make sure we are in the Apothecary
-- at Stygia. Otherwise this entire script will go very
-- wrong, very fast.
stygiaApothecary = false

allstop = false

wait.make (function ()
  EnableTrigger("stygiaApothecaryCheck", true)
  wait.time(0.25)
  Send("look")
  wait.time(0.25)
  EnableTrigger("stygiaApothecaryCheck", false)


if (stygiaApothecary == true) then
  advancedDungeonCount = 0
  explorePath          = 0
  roomTime             = 90
  extraTime            = 60
  roomClearTime        = 3
  isRoomClearTime      = 0.25
  stopadp              = false
  EnableTrigger("bbsShutdown", true)

  while (stopadp == false) do

    autokill   = false
    werekill   = false
    undeadkill = false
    giveup     = false

    -- To make sure we explore as many rooms as posible,
    -- every other time we go through the dungeon, we
    -- will take a slightly different path.
    if (explorePath == 0) then
      explorePath = 1
    else
      explorePath = 0
    end

  -- Buy and eat a ration before heading out
  if (stopadp == false) then
    Send("west")
    wait.time(0.5)
    Send("west")
    wait.time(0.5)
      
    Execute("br")
    wait.time(3)

    Send("east")
    wait.time(0.5)
    Send("east")
    wait.time(0.5)
  end

  -- Drink a flask before heading out
  if (stopadp == false) then
    Send("drink flask")
    wait.time (1)
  end

  -- This block of code is to buy and set a key at the
  -- Apothecary. We try to do some checking so that we
  -- don't leave without getting our key set.
  if (stopadp == false) then

    -- We may already have a key, and it may be set, so
    -- this section of the code tries to drop a key (in
    -- case we do have one) so that it gets reset. If we
    -- did drop a key, we will pick it back up and reset
    -- it rather than buy a new one.
    needKey = false
    EnableTrigger("dropKeyCheck", true)
    Send("drop key")
    wait.time (0.5)
    if (needKey == true) then
      Execute("sk")
      wait.time (0.5)
    else
      Send("get key")
      wait.time(0.5)
      Send("rub key")
      wait.time(0.5)
    end
    EnableTrigger("dropKeyCheck", false)
  end

  -- This block of code is to make sure we are topped out
  -- on flasks before we go. We always drop 1 flask at
  -- the end to make sure we have inventory space to pick
  -- something up later.
  if (stopadp == false) then  
    Send("get flask")
    wait.time (1)
    Send("get flask")
    wait.time (1)
    Send("get flask")
    wait.time (1)
    Execute("bf")
    wait.time (10)
    Send("drop flask")
    wait.time (1)
    Execute("countflasks")
    wait.time (1) 
  end

  -- This trigger will restart the loop if we end up walking
  -- into a wall. If we walk into a wall, it means our path
  -- got of sync, so we need to start over.
  if (stopadp == false and flaskcount > 0) then
    EnableTrigger("advancedDungeonGoneWrong", true)
  end

  -- Walk to the Dungeon entrance
  if (stopadp == false and flaskcount > 0) then
    Send("west")
    wait.time(0.5)
    Send("north")
    wait.time(0.5)
  end
 
  -- Turn on autokill
  if (stopadp == false and flaskcount > 0) then
    autokill   = true
    -- There are no were creatures in the advanced realm,
    -- so there's no need to have werekill on.
    werekill   = false
    undeadkill = true
    giveup     = false
  end

    -- Enter the dungeon here
  if (stopadp == false and flaskcount > 0) then
    Send("down")
	wait.time(isRoomClearTime)
	Execute("isroomclear")
  end
  
  
  -- Take this path if explorePath is 0
  if (explorePath == 0) then
    if (stopadp == false and flaskcount > 0) then
      if (noMobs == false) then
        wait.time (roomTime)
	  else
	    wait.time(roomClearTime)
	  end
    end

    if (stopadp == false and flaskcount > 0) then
      Execute("nextRoom west")
	  wait.time(isRoomClearTime)
	  Execute("isroomclear")
    end

    if (stopadp == false and flaskcount > 0) then
      if (noMobs == false) then
        wait.time (roomTime)
	  else
	    wait.time(roomClearTime)
	  end
    end

    if (stopadp == false and flaskcount > 0) then
      Execute("nextRoom south")
	  wait.time(isRoomClearTime)
	  Execute("isroomclear")
    end

  -- Take this path if explorePath is 1
  else
    if (stopadp == false and flaskcount > 0) then
      if (noMobs == false) then
        wait.time (roomTime)
	  else
	    wait.time(roomClearTime)
	  end
    end


  -- Dozens of more rooms were cut out at this point.

  -- Return to Stygia and repeat the loop

  if (stopadp == false and flaskcount > 0) then
    Send("rub key")
    wait.time (1)
    advancedDungeonCount = advancedDungeonCount + 1
  end

end -- while
else
  ColourNote("white", "blue", "Not in Stygia. Exiting...")
end -- if
end) -- wait
USA Global Moderator #1
Main world aliases and triggers are stored inside your world file (.mcl), which you can open with a text editor.
#2
Fiendish said:

Main world aliases and triggers are stored inside your world file (.mcl), which you can open with a text editor.


Ok... so if I edit the mcl file directly, I can make the alias as large as I want? I assume I have to save the world file and exit the program before editing it?
USA Global Moderator #3
Yes, but you might consider moving it into a plugin so that you're not accidentally tempted to use the built-in editor.
#4
Fiendish said:

Yes, but you might consider moving it into a plugin so that you're not accidentally tempted to use the built-in editor.


I tried moving just the alias to a plugin, but the alias stops working when I do that. I really don't want to move the entire world file into a plugin. Hmmm...
USA Global Moderator #5
Quote:
but the alias stops working when I do that

If you get an error message, you could post what error you get here.
#6
Fiendish said:

Quote:
but the alias stops working when I do that

If you get an error message, you could post what error you get here.


It's not an error that I'm getting. What happens at the very beginning of the alias is that it starts a trigger to determine if I'm in the right room. If I'm not in the right room, it bypasses the entire alias and quits.

require "wait"

-- Before we do anything, make sure we are in the Apothecary
-- at Stygia. Otherwise this entire script will go very
-- wrong, very fast.
stygiaApothecary = false

allstop = false

wait.make (function ()
  EnableTrigger("stygiaApothecaryCheck", true)
  wait.time(0.25)
  Send("look")
  wait.time(0.25)
  EnableTrigger("stygiaApothecaryCheck", false)


if (stygiaApothecary == true) then
-- do all the level grinding stuff
else
  ColourNote("white", "blue", "Not in Stygia. Exiting...")
end -- if


When I put the alias into a plugin, it gives me the message saying I'm not in the right room. So it acts like it's behaving correctly ... in the sense that I'm not getting any error code spewing out onto the screen. But for whatever reason, it's not running the triggers? Or if it is running them, then they aren't working in conjunction with the alias plugin.
USA Global Moderator #7
Ah, yeah, you'd need to put the triggers also inside the plugin.
#8
Fiendish said:

Ah, yeah, you'd need to put the triggers also inside the plugin.


And probably all other triggers and aliases that are called from this alias? At which point I will probably have a good part of the world file in that one plugin. Which would probably be ok ... but making quit edits from within MUSHclient is so much more convenient. Having to close down the program every time I want to test a new value for a variable is kind of inconvenient.
USA Global Moderator #9
Quote:
Having to close down the program every time I want to test a new value for a variable is kind of inconvenient.

You can reload plugins without closing down the program.
#10
Fiendish said:

You can reload plugins without closing down the program.


I tried putting the alias and the trigger into a plugin file, and now I am generating this error:

No. of flasks : 10
>
Error raised in timer function (in wait module).
stack traceback:
        [string "Alias: "]:114: in function <[string "Alias: "]:10>
Run-time error
Plugin: advancedDungeonPatrol (called from world: blixelFL2)
Function/Sub: wait.timer_resume called by timer
Reason: processing timer "wait_timer_2614421"
C:\Program Files (x86)\MUSHclient\lua\wait.lua:51: [string "Alias: "]:114: attempt to compare number with nil
stack traceback:
        [C]: in function 'error'
        C:\Program Files (x86)\MUSHclient\lua\wait.lua:51: in function <C:\Program Files (x86)\MUSHclient\lua\wait.lua:43>,


I think the main part is "attempt to compare number with nil" ... but I'm not sure what's happening.
USA Global Moderator #11
Where do you store flaskcount?

Quote:
stack traceback: [string "Alias: "]:114:
points us to the 114th line in the alias.
#12
Fiendish said:

Where do you store flaskcount?

Quote:
stack traceback: [string "Alias: "]:114:
points us to the 114th line in the alias.


I'm guessing these 8 header lines don't count as lines in the alias.
  <alias
   match="adp"
   enabled="y"   
   group="Patrol the Advanced Dungeon"
   send_to="12"
   sequence="100"
  >
  <send>


So I would be looking at line 114+8 then I'm assuming. Below is lines 114-132

    wait.time (1)
    Execute("countflasks")
    wait.time (1) 
  end

  -- This trigger will restart the loop if we end up walking
  -- into a wall. If we walk into a wall, it means our path
  -- got of sync, so we need to start over.
  if (stopadp == false and flaskcount &gt; 0) then
    EnableTrigger("advancedDungeonGoneWrong", true)
  end

  -- Walk to the Dungeon entrance
  if (stopadp == false and flaskcount &gt; 0) then
    Send("west")
    wait.time(0.5)
    Send("north")
    wait.time(0.5)
  end


flaskcount is used all over the place, but I suppose it's first introduced by a series of aliases and triggers that checks my inventory and counts how many flasks I have.

  <alias
   name="CountFlasks"
   match="countflasks"
   enabled="y"
   group="Flask Count"
   send_to="12"
   sequence="100"
  >
  <send>EnableTrigger("InvStart", true) 
Send ("inventory")</send>
  </alias>



  <trigger
   group="Flask Count"
   keep_evaluating="y"
   match="^You are carrying (.+)"
   name="InvStart"
   omit_from_output="y"
   regexp="y"
   send_to="12"
   sequence="99"
  >
  <send>myinv = "%0"

if string.sub(myinv, string.len(myinv) - 6, string.len(myinv)) == "pieces." then
  EnableTrigger("InvStart", false)
  Execute ("FlaskCount")
else
  EnableTrigger("InvFull", true)
end
</send>
  </trigger>


  <trigger
   group="Flask Count"
   keep_evaluating="y"
   match="^(.+)"
   name="InvFull"
   omit_from_output="y"
   regexp="y"
   send_to="12"
   sequence="99"
  >
  <send>myinv = myinv .. "%0"

if string.sub(myinv, string.len(myinv) - 6, string.len(myinv)) == "pieces." then
  EnableTrigger("InvStart", false)
  EnableTrigger("InvFull", false)
  Execute ("FlaskCount")
end</send>
  </trigger>


  <alias
   name="FlaskCount"
   match="FlaskCount"
   enabled="y"
   group="Flask Count"
   send_to="12"
   sequence="100"
  >
  <send>flaskcount = 0

for word in string.gmatch(myinv, "flask") do
  flaskcount = flaskcount + 1
end

Note("No. of flasks : " .. flaskcount)
</send>
  </alias>
USA Global Moderator #13
When I counted 114 lines into your original posted code, I got to
  if (stopadp == false and flaskcount > 0) then


Then I saw that nothing in your code set flaskcount, so if you reach this line before anything else sets it then you will get an error about comparing a number (0) to nil (flaskcount). I think my analysis should still hold. Are your flask counting aliases also inside the plugin or are they outside? The flaskcount variable has to be set and visible from inside the plugin.
Amended on Sat 30 Mar 2019 09:50 PM by Fiendish
#14
Fiendish said:

When I counted 114 lines into your original posted code, I got to
  if (stopadp == false and flaskcount > 0) then


Then I saw that nothing in your code set flaskcount, so if you reach this line before anything else sets it then you will get an error about comparing a number (0) to nil (flaskcount). I think my analysis should still hold. Are your flask counting aliases also inside the plugin or are they outside? The flaskcount variable has to be set and visible from inside the plugin.


I run my flaskcount alias right after buying as many flasks as my character can hold. And that is immediately before going down into the dungeon. So I thought flaskcount would be globally known at that point.

But I guess plugins have their own variable scope, so even though I am setting flaskcount, the plugin can't "see" it.

Many triggers and aliases are intertwined and used by other aliases and other triggers ... so I don't think I can put the flaskcount stuff in with this alias because then everything else that needs it won't have it. I guess I could make a copy of it ... and have flaskcount_two ... just for this alias ... but that seems sloppy.
Australia Forum Administrator #15
What I suggest you do is put the script into the world script file (not in "send to script" in the alias). Then just put the function name in the alias "Script" box. The function in the script file would look like this:


function myAlias (name, line, wildcards, styles)

-- your script here

end -- function


You would need some minor changes to the script. Instead of using %1 for the first wildcard (and so on) use:


wildcards [1]


The full matching line is stored in the "line" argument.

Apart from solving your problem, this will also be faster. If you use "send to script" the script has to be compiled by Lua every time it matches. This would tend to slow things down if it is long. If you use a script file the script is compiled once.
#16
Nick Gammon said:

What I suggest you do is put the script into the world script file (not in "send to script" in the alias). Then just put the function name in the alias "Script" box.


This seems to work really well for my situation. I have 3 of these level grinding scripts so far.

Moving them to the script file definitely makes things a lot easier to read and maintain. And I haven't ran into any problems so far with other things breaking as a consequence (knock on wood).

Thanks for the tip.