Speedwalking Script Solution for Lag?

Posted by Karl_Newbie on Tue 27 Apr 2004 08:11 AM — 20 posts, 70,571 views.

USA #0
I play a mud that unfortunately will suffer bounts of lag spontenously and frequently enough to make my basic speedwalks useless.
Typical problem.
Speedwalk delay is set to a lengthy 2000
Speedwalk alias hometoschool.
s
front porch
s
road
se
road
(server lags) e se e se
(server resumes)
e
You can't go that way.
w
You can't go that way.
sw
e
(I'm not at the school when the speedwalk finishes)
Okay, so as of now, my only failsafe is to discard the speedwalk queue and finish walking the path manually.
This can be rather impractical for obvious reasons.

Is there a solution to this? (besides finding a better Mud?)
Ideally I'd love to set a trigger where:
When I speedwalk a direction the script waits until it catches a trigger of say, "Obvious Exists Are *" or "It is too dark to see" to send the next direction. Because every time I move into a new room I will see the obvious exists or the dark message.

So ideally

Speedwalk alias hometoschool.
s
front porch
obvious exits are s, se
(match on obvious exists, send "s")
s
obvious exists
(match on that again, send next direction)
road
(obvious exists * match, send next direction)
se
(obvious exits, send next direction to the mud)
e
(server lags)
(server resumes match when the obvious exists trigger catches)
sw
road (obvious exists are e, w, sw, send next direction).
No command will be sent in the script unless that 'obvious exists or 'it is dark' triggers appear.
Well, anyhow Mushclient seems to be a great client. I don't think I could even approach this subject on any other one.
Thanks all for your time reading this.
Australia Forum Administrator #1
Yes, that sounds pretty straightforward. I would do something like EvaluateSpeedwalk, get the first one, remove it, send it, and let a trigger repeat the process.

I don't have time to do an exact example tonight (it is night here) but will look into it tomorrow.
Australia Forum Administrator #2
Well, that was fun! You need an alias to start the process off, here is mine:


<aliases>
  <alias
   match="walk *"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>ArrayCreate "walks"
ArrayClear "walks"
i = 0
'
'  put speedwalk into array
'
speedwalk = EvaluateSpeedWalk ("%1")
'
'  if the speedwalk starts with an asterisk it was an error
'
if Left (speedwalk, 1) = "*" then
  ColourNote "white", "red", speedwalk
else
'
'  not an error - put into an array
'
  for each w in Split (speedwalk, vbCrLf)
    if w &lt;&gt; "" then
      ArraySet "walks", CStr (i), w
      i = i + 1
    end if
  next
'
'  if array is not empty, start walking
'
  if ArraySize ("walks") &gt; 0 then	
    ColourNote "white", "blue", "Commencing walk to: %1"
    dir = ArrayGet ("walks", "0")
    ArrayDeleteKey "walks", "0"
    ColourNote "white", "blue", "Now going: " &amp; dir
    Send dir
  end if
end if</send>
  </alias>
</aliases>



To use this type: walk (direction)

eg. walk 4s 2e

Then a trigger catches the "exits" or "it is too dark to see" message (you may need to alter it a bit to suit the exact message):


<triggers>
  <trigger
   custom_colour="2"
   enabled="y"
   match="^(Exits\: (.*?)|It is too dark to see)$"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>if ArraySize ("walks") &gt; 0 then		
  dir = ArrayGet ("walks", ArrayGetFirstKey ("walks"))
  ArrayDeleteKey "walks", ArrayGetFirstKey ("walks")
  ColourNote "white", "blue", "Now going: " &amp; dir
  Send dir
end if

</send>
  </trigger>
</triggers>



This pulls the first item out of the queue and walks it, and then waits for another such trigger to fire.
USA #3
That is AMAZING! I had been setting the global speedwalk delay based on the current lag weather of the server but this is a perfectly acceptable alternative :-)
However I can't use "*" as a wildcard in the trigger? It is no big deal. I was able to manually add the spaces into the ' Obvious exits/' trigger because in the MUD that line is centered by a left margin of several spaces and the your trigger did not catch it.
Also sometimes a command prompt '>' Starts the output before '>It is to dark to see'. But I added a |> It is to dark to see' after the first '|It is to dark' and the script is great. Fully functional but even a novice could use it.
Now I just need to find a way to add a little delay before sending the queued command so my character stops tripping from moving too fast :-)
Thanks!

Anyone who interested can easily implement this into their own speedwalks.
Simply take your current alias'd speedwalk say
'schooltohouse'
and put a 'walk' in the send, right before the speedwalk directions.
eg. walk 3(nw/se) 2w (nw/se) w (nw/se) 2w 2(nw/se)
Also change the 'Send To' from 'Speedwalk' to 'Execute'
And be sure to adjust the moving to a new room triggers eg Obvious exists)appropriately
Amended on Wed 28 Apr 2004 04:06 AM by Karl_Newbie
Australia Forum Administrator #4
Quote:

However I can't use "*" was a wildcard in the trigger?


The trigger is a regular expression - you wildcard by putting things like ".*" into it.

For instance the trigger match might be:

match="^.*(Exits\: (.*?)|It is too dark to see)$"
USA #5
Ahh got it. I'm reading the help on Regular Expressions now. Thanks again.
#6
*bump*

I am new to using MUSHclient and know little about scripting.

I have trouble with lag and speed walking too, how do I use the scripts posted above to check for the next line of exits before following the next direction?
Australia Forum Administrator #7
I've tried to do a speed walk that waits for exits a different way, to make it simpler. The alias below should accomplish that for you, providing you make Lua your scripting language, and the file "exampscript.lua" your script file (see the Scripts tab in the world configuration).



<aliases>
  <alias
   match="!*"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>do local t = coroutine.create (function (t)

local lines = {}

sw = EvaluateSpeedwalk ("%1")

-- check for valid speedwalk

if string.sub (sw, 1, 1) == "*" then
  ColourNote ("white", "red", string.sub (sw, 2))
  return
end -- if

rex.new ("(.+)"):gmatch (sw, 

-- build speedwalk lines into a table

function (m) 
  table.insert (lines, m)
end)

 -- iterate the table, sending each line to the MUD

 for i, line in ipairs (lines) do

  -- send the speedwalk

   Send (line) 

  -- now wait for an appropriate response

  line, wildcards = waitforregexp (t, 
          "^(Exits: .*\.|Alas, you cannot go that way\.)$")

  -- check we didn't get told it was impossible

  if string.sub (line, 1, 5) ~= "Exits" then
    ColourNote ("white", "red", "Speedwalk cancelled")
    return  -- give up
  end -- if

  end  -- of iterating through each speedwalk line

  -- all done!

  ColourNote ("white", "blue", "speedwalk done")

end) assert (coroutine.resume (t, t)) end

</send>
  </alias>
</aliases>



What this does is make an alias where you type "!" followed by the speedwalk string, and it then sends the lines one by one until the speedwalk is finished. It doesn't send a new line until an "Exits:" line arrives, thus making sure that each line is sent only when ready.

Eg. You type: ! 3e 2n

It also tests for the "error" message "Alas, you cannot go that way." and if received cancels the speedwalk, on the basis that you must have wandered into somewhere unexpected, and sending further speedwalks will be a waste of time.

If the "error" line is different you will need to change the line above to match what your MUD sends, escaping special characters like periods with a backslash, as is done above.

You may also need to modify the "Exits:" part above if your MUD sends something different, like "Obvious exits" or something similar.

[EDIT]

Modified to check for valid speedwalk string.
Amended on Fri 14 Oct 2005 07:07 AM by Nick Gammon
#8
Okay, hmm, I think I understand all of this.

Will the '!' work in front of the path alias?
Australia Forum Administrator #9
The ! is an alias for my special speedwalk. See the alias? It matches on "!*" which means "!" followed by anything.
#10
Sorry for dredging this thread up (I'm the OP, lost my password) but I've been redoing my aliases, timers and triggers in Lua and with Mr Gammon's alias I get this error message:

Quote:

Error number: 0
Event: Run-time error
Description: [string "Alias: "]:48: [string "Alias: "]:32: attempt to call global 'waitforregexp' (a nil value)

stack traceback:

[C]: in function 'assert'

[string "Alias: "]:48: in main chunk
Called by: Immediate execution


For example "! 2n" sends "n" but then gives the above error message

First I thought I wasn't matching the exits properly but I get the same error message even when I get the movement failed "Alas, you cannot go that way." message.
Amended on Tue 25 Mar 2008 01:42 PM by RichKK
Australia Forum Administrator #11
MUD still slow, huh, four years later? :-)

Nowadays the "wait" functionality is in a wait.lua file that comes with MUSHclient. I assume you are using a reasonably recent version?

This updated version should work (maybe you need to adjust the exits detection). It is slightly simpler than the old one, and uses wait.lua to provide the waiting functionality:


<aliases>
  <alias
   match="!*"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>

require "wait"  -- load wait.lua

wait.make (function ()  --- coroutine below here

local lines = {}

sw = EvaluateSpeedwalk ("%1")

-- check for valid speedwalk

if string.sub (sw, 1, 1) == "*" then
  ColourNote ("white", "red", string.sub (sw, 2))
  return
end -- if

rex.new ("(.+)"):gmatch (sw, 

-- build speedwalk lines into a table

function (m) 
  table.insert (lines, m)
end)

 -- iterate the table, sending each line to the MUD

 for i, line in ipairs (lines) do

  -- send the speedwalk

   Send (line) 

  -- now wait for an appropriate response

  line, wildcards = wait.regexp ("^(Exits: .*\.|Alas, you cannot go that way\.)$")

  -- check we didn't get told it was impossible

  if string.sub (line, 1, 5) ~= "Exits" then
    ColourNote ("white", "red", "Speedwalk cancelled")
    return  -- give up
  end -- if

  end  -- of iterating through each speedwalk line

  -- all done!

  ColourNote ("white", "blue", "speedwalk done")

end)  -- end of coroutine

</send>
  </alias>
</aliases>
#12
The lag isn't so bad anymore, it just has its moments, but what can I expect, 12 years in and the MUD is still in beta. The big leap was upgrading to version 4.19, version 3.32 ought to be enough MUSHclient for anybody <g>

I love this script and really made use of the old version! It was versatile enough to use for so many different situations that require waiting for a response before sending the next command in a sequence; just perfect. Thanks a ton.

Can you just show me how to include more options for the 'if... then... ~=...', I'd like to keep sending directions even I get "It is dark"

Quote:

line, wildcards = wait.regexp ("^( Obvious exits: .*\.|\>You can't go that way\.|You can't go that way\.|It is dark\.)$")

-- check we didn't get told it was impossible

if string.sub (line, 1, 18) ~= " Obvious exits" (AND WHAT I'D LIKE TO INCLUDE IS) or string.sub (line, 1, 10) ~= "It is dark" then
ColourNote ("white", "red", "Speedwalk cancelled")
return -- give up
end -- if




Amended on Wed 26 Mar 2008 03:17 AM by RichKK
Australia Forum Administrator #13
You want to "and" them, as you are testing for not the condition. In other words, we fail if it not obvious exits AND not dark.


  -- check we didn't get told it was impossible

  if string.sub (line, 1, 14) ~= " Obvious exits" and 
     string.sub (line, 1, 10) ~= "It is dark" then

    ColourNote ("white", "red", "Speedwalk cancelled")
    return  -- give up
  end -- if

#14
I'm trying to utilize this script to take me through an area, while maintaining the pause in case of lag, and to notice mobs . It should then attack them and wait until they're dead to resume the move.

Here's what I have so far, but it doesn't work.


require "wait" -- load wait.lua

wait.make (function () --- coroutine below here

local lines = {}

sw = EvaluateSpeedwalk ("%1")

-- check for valid speedwalk

if string.sub (sw, 1, 1) == "*" then
ColourNote ("white", "red", string.sub (sw, 2))
return
end -- if

rex.new ("(.+)"):gmatch (sw,

-- build speedwalk lines into a table

function (m)
table.insert (lines, m)
end)

-- iterate the table, sending each line to the MUD

for i, line in ipairs (lines) do

-- send the speedwalk

Send (line)

-- now wait for an appropriate response

line, wildcards = wait.regexp ("^(A dog is here\.|A man is here\.|Obvious exits:)$")

-- check we didn't get told it was impossible

if string.sub (line, 3, 5) == "dog" then

Send ("kill dog")
line, wildcards = wait.regexp ("^(.* is DEAD!)$")

end -- if

if string.sub (line, 3, 5) == "man" then

Send ("kill man")
line, wildcards = wait.regexp ("^(.* is DEAD!)$")

end -- if


end -- of iterating through each speedwalk line

-- all done!


end) -- end of coroutine



EDIT: I should mention what it does do. The walk works, and the attack works but it won't wait to kill them before pushing more speedwalk commands.h
Amended on Fri 25 Jul 2008 09:37 PM by DungBeetle
Australia Forum Administrator #15
I can't quite see what is wrong here. Can you post the whole alias? See:

http://mushclient.com/copying

Also paste the MUD output around when all this goes wrong.
#16
<aliases>
<alias
match="!*"
enabled="y"
send_to="12"
sequence="100"
>
<send>require "wait" -- load wait.lua

wait.make (function () --- coroutine below here

local lines = {}

sw = EvaluateSpeedwalk ("%1")

-- check for valid speedwalk

if string.sub (sw, 1, 1) == "*" then
ColourNote ("white", "red", string.sub (sw, 2))
return
end -- if

rex.new ("(.+)"):gmatch (sw,

-- build speedwalk lines into a table

function (m)
table.insert (lines, m)
end)

-- iterate the table, sending each line to the MUD

for i, line in ipairs (lines) do

-- send the speedwalk

Send (line)

-- now wait for an appropriate response

line, wildcards = wait.regexp ("^(A dog is here\.|A man is here\.|Obvious exits:)$")

-- check we didn't get told it was impossible

if string.sub (line, 3, 5) == "dog" then

Send ("kill dog")
line, wildcards = wait.regexp ("^(.* is DEAD!)$")

end -- if

if string.sub (line, 3, 5) == "man" then

Send ("kill man")
line, wildcards = wait.regexp ("^(.* is DEAD!)$")

end -- if


end -- of iterating through each speedwalk line

-- all done!


end) -- end of coroutine</send>
</alias>
</aliases>


It will move into the room with the mob and send the kill command. Then, while I'm approaching it to attack the next direction command is sent. It's like the "* is DEAD!"-wait doesn't matter.


I think the issue is right here:

Obvious exits:
sw
North - Too dark to tell
Southwest - Too dark to tell
A dog is here.
kill dog
Amended on Sat 26 Jul 2008 05:39 PM by DungBeetle
Australia Forum Administrator #17
OK I see it now.


Obvious exits:
sw
North - Too dark to tell
Southwest - Too dark to tell
A dog is here.
kill dog


As soon as it sees "Obvious exits:" it sends "sw", as you can see, as the script tells it to do.

Later it notices the dog - too late, as it has already moved.

I think you have to restructure a bit - the test for "A dog is here\.|A man is here\.|Obvious exits:" is all done after you have just sent the speedwalk. So you are pretty-much guaranteed that you have moved before you notice the dog.
#18
argh, I had it working to an extent by switching the wait trigger from 'Obvious exits' to 'Health:', but that was with just one mob. As soon as I put in the other types I might encounter the script died and sends a only one command.

Could you show me how to make it "A * is standing here" and then make the if trigger off of wildcard [1] and Send ("kill" wildcards [1]? I've been messing with it but I can't seem to get the right syntax.
Australia Forum Administrator #19
It sounds very much to me like you are writing a bot, which most MUDs frown on.

I think I'll have to let you work out the details yourself here, but suffice to say that you need to make the script do what you, as a human would. That is, let the whole room description, including exits and list of mobs appear, and *then* work out whether to move on or kill something.