Help improving a walk script

Posted by JHama on Mon 22 Nov 2010 03:48 PM — 15 posts, 46,954 views.

#0
I am new to scripting and really only know enough to tweak scripts to make them work for me (to some degree). I was browsing and found this walking script which I thought could be useful if improved upon a little. My question is how would I go about pausing the walking to attack npcs in a room, bury, then resume the walking script again?

Thank you.



<triggers>
  <trigger
   enabled="y"
   match="[Exits: *]"
   send_to="12"
   sequence="100"
  >
  <send>
-- table of inverse directions

inverse = {
  north = "south",
  south = "north",
  east = "west",
  west = "east",
  up = "down",
  down = "up",
  ne = "sw",
  sw = "ne",
  se = "nw",
  nw = "se",
  } -- end of table of inverse directions

-- split exits into a table at the comma

exits = {}

for w in string.gmatch ("%1", "[^,]+") do
  table.insert (exits, w)
end -- for

number_of_exits = table.getn (exits)

repeat

  -- choose one randomly
  which = (math.floor (MtRand () * number_of_exits)) + 1

  direction = Trim (exits [which])
 
until direction ~= inverse [last_direction] or number_of_exits == 1

-- go that way
Send (direction)

-- remember it so we don't go back
last_direction = direction

</send>
  </trigger>
</triggers>
Amended on Sat 18 Dec 2010 01:14 AM by Nick Gammon
Australia Forum Administrator #1
Check out this post:

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

I seem to recall a walk script being done before, the general idea would be to use the ideas in the post above, combined with moving, and then doing a "wait.match" to see if you have changed rooms yet (this would be the pause), or a "wait.time" to wait for, say, 5 seconds.
#2
Before i go any deeper i tested how this worked for my MUD and found an issue with the exits. This current script matches [*] which i understand to be the same for every room, just different exits. The issue with mine is there is a description before every list of exits, IE 'There are two obvious exits: north and south.' 'There are three obvious exits: north, south and east.'

Is there a simple way to solve this by ignoring everything before 'obvious exits:' ? A better question would be, where can i be directed to that shows me the basic fundamentals & how to ignore certain parts of the line and not match it entirely?
Amended on Wed 24 Nov 2010 03:59 AM by JHama
Australia Forum Administrator #3
Template:regexp
Regular expressions
  • Regular expressions (as used in triggers and aliases) are documented on the Regular expression tips forum page.
  • Also see how Lua string matching patterns work, as documented on the Lua string.find page.


In your case if there is an extra word, just make that another wildcard, eg.


There are * obvious exits: *


And maybe as well:


There is one obvious exit: *


With a regular expression you could get fancier, eg.


^There (is|are) .* obvious exits?: (.*)$

Amended on Tue 23 Nov 2010 08:24 PM by Nick Gammon
#4
Been extremely busy and just had time to get back to this. What was provided before didnt seem to work so I made a few changes and am now having issues with splitting the exits at the comma. The direction sometimes chosen includes the 'and'. IE 'northwest and southeast' may sometimes be considered one direction. Is there a way to make it a bit more conditional and split at both ',' and 'and'?

Eventually i want this to just walk around and auto attack certain npcs then bury the corpses.


<triggers>
<trigger
enabled="y"
match="There are * obvious exits:* "
send_to="12"
sequence="100"
>

<send>
-- table of inverse directions

inverse = {
north = "south",
south = "north",
east = "west",
west = "east",
up = "down",
down = "up",
ne = "sw",
sw = "ne",
se = "nw",
nw = "se",
} -- end of table of inverse directions

-- split exits into a table at the comma

exits = {}

for w in string.gmatch ("%2", "[^,]+") do
table.insert (exits, w)
end -- for

number_of_exits = table.getn (exits)

repeat

-- choose one randomly
which = (math.floor (MtRand () * number_of_exits)) + 1

direction = Trim (exits [which])

until direction ~= inverse [last_direction] or number_of_exits == 1

-- go that way
Send (direction)

-- remember it so we don't go back
last_direction = direction

</send>
</trigger>
</triggers>
Amended on Sat 18 Dec 2010 02:12 AM by JHama
Australia Forum Administrator #5
The simple thing would be just to convert "and" to a comma.

eg,


fixed_exits = string.gsub ("%2", " and ", ", ")

#6
Thank you, that worked pefectly. I was trying something similar but im use to c# syntax and was messing around with the for loop to add an or.

I took a look at the wait.time and if i understand that correctly it only pauses for a specified amount of time, the issue with that is what if i cant kill the npcs in that time? If thats the case would it be a better bet to just add another trigger that looked for npcs in the room then disabled the walking script and resumed after burying?
Australia Forum Administrator #7
In that case you want wait.match.

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

That waits for a trigger, with a timeout. So something like this:


mob = wait.match ("* attacks you.", 10)
if mob then
   -- under attack
else
   -- time elapsed
end -- if

#8
This ended up being a bit more challenging that i initially thought, scripting is not my forte. I messed around with wait.match quite a bit and it didnt seem to want to work properly (wasnt stopping at all).

The following works except for one error. It seems to attack the npc then move to the next room, sometimes it wont even attempt to attack until after i have moved to the next room.

The idea was with the autoattack trigger to pause it when seeing something "standing here" then begin attacking & not resume walking until it successfully buries.



-----auto walk trigger---
<triggers>
<trigger
   enabled="y"
   ignore_case="y"
   match="^There (.*?) obvious (.*?)\: (.*?)\.$"
   regexp="y"
   send_to="12"
   sequence="100"
   name="autowalk"
  >
  <send>require "wait"

function cr () 

-- table of inverse directions

inverse = {
north = "south",
south = "north",
east = "west",
west = "east",
up = "down",
down = "up",
ne = "sw",
sw = "ne",
se = "nw",
nw = "se",
} -- end of table of inverse directions

-- split exits into a table at the comma
wait.time (2)
exits = {}

fixed_exits = string.gsub ("%3", " and ", ",")

for w in string.gmatch (fixed_exits, "[^,]+") do
table.insert (exits, w)
end -- for

number_of_exits = table.getn (exits)

repeat
wait.time (2)
-- choose one randomly
which = (math.floor (MtRand () * number_of_exits)) + 1
direction = Trim (exits [which])
until direction ~= inverse [last_direction] or number_of_exits == 1


-- go that way
Send (direction)

-- remember it so we don't go back
last_direction = direction


end  -- end of coroutine
wait.make (cr) -- start coroutine up
</send>
  </trigger>


---------auto attack trigger----------
  <trigger
   enabled="y"
   ignore_case="y"
   match="^(.*?)standing here\.$"
   regexp="y"
   send_to="12"
   sequence="101"
   name="autoattack"
  >
  <send>require "wait"

function cr () 

  repeat
  EnableTrigger ("autowalk", false)  -- don't want it to fire again
    Send "kill all"
    line, wildcards = wait.regexp ("^You prepate to attack(.*?)$")
  until string.find (line, "You prepare")


end -- of function cr

wait.make (cr) -- start coroutine up
</send>
  </trigger>



---------attempt to bury corpses trigger----------
  <trigger
   enabled="y"
   ignore_case="y"
   match="^You killed(.*?)$"
   regexp="y"
   send_to="12"
   sequence="102"
   name="attemptbury"
  >
  <send>
    Send "bury all"
  </send>
  </trigger>


---------successful bury trigger----------
  <trigger
   enabled="y"
   ignore_case="y"
   match="^You (bury|tidy)(.*?)$"
   regexp="y"
   send_to="12"
   sequence="100"
   name="burysuccess"
  >
<send>

  EnableTrigger ("autowalk", true)  -- Resume walking
  Send "look" -- look at the room top get directions and continue walking
</send>
  </trigger>
</triggers>
Amended on Sat 18 Dec 2010 02:11 AM by JHama
Australia Forum Administrator #9
I tidied up your code to make it more readable. To do this yourself next time:

Template:codetag
To make your code more readable please use [code] tags as described here.


First thing I spot is this:


repeat
  EnableTrigger ("autowalk", false)  -- don't want it to fire again
    Send "kill all"
    line, wildcards = wait.regexp ("^You prepate to attack(.*?)$")
  until string.find (line, "You prepare")


Since you are waiting for "You prepate to attack" it will never return "You prepare".

Even fixing that, I'm not sure what you are trying to do here. What it will do is send "kill all" and the moment it gets "You prepare" back it stops looping. So why have the loop in the first place?
#10
I apologize about the unreadable code, as to the silly repeat i posted the wrong backup file of what I had been working on in a rush to get out.

--edit--
Thank you for the help! I went back and was able to get the wait.regexp/wait.match working. I knew nothing whatsoever about scripting, but after spending a lot of time reading your links and examples i managed to get this working! It has a few minor goofs at times, but its fixable.
Amended on Mon 20 Dec 2010 01:31 AM by JHama
#11
I do have one last question though involving substituting words. Is it possible to completely remove multiple different words from the list of directions such as up/down/swim direction? I do not want to go these directions so is it possible to just remove them from the list of directions by substituting them with "" so they wont appear? I looked at string.gsub and it didnt show multiple words for subsitution.

This is what I am referring to. There are four obvious exits: swim north, swim east, journey south and west.


In this case i would not want to swim east or swim west, nor would i want to journey south but rather either go 'south' or 'west'


-- table of inverse directions

inverse = {
north = "south",
south = "north",
east = "west",
west = "east",
up = "down",
down = "up",
ne = "sw",
sw = "ne",
se = "nw",
nw = "se",
} -- end of table of inverse directions

-- split exits into a table at the comma
exits = {}

fixed_exits = string.gsub ("%3", " and ", ",")


for w in string.gmatch (fixed_exits, "[^,]+") do
table.insert (exits, w)
end -- for

number_of_exits = table.getn (exits)

repeat

-- choose one randomly
which = (math.floor (MtRand () * number_of_exits)) + 1
direction = Trim (exits [which])
until direction ~= inverse [last_direction] or number_of_exits == 1
-- go that way

Send (direction)
-- remember it so we don't go back
last_direction = direction
Australia Forum Administrator #12
Well the first thing you might do is split the exits differently. There is a utils.split function that breaks up a string at commas.

http://www.gammon.com.au/scripts/doc.php?lua=utils.split

So if you use that, then your exits line will be split into the full exit (eg, "swim west") rather than "swim" and "west".


exits = utils.split (fixed_exits, ",")


Now, since "swim west" isn't in your table of inverse directions you could consider it a "not valid" exit.

For example:


repeat

  -- choose one randomly
  which = (math.floor (MtRand () * number_of_exits)) + 1

  direction = Trim (exits [which])

until (inverse [direction] and -- check valid direction
        direction ~= inverse [last_direction])
      or number_of_exits == 1
-- go that way

#13
That worked perfectly for solving the swimming issue. I might have worded the other problem i had funny, what i meant was instead of going "journey west" i want to just go "west". In this game you can still go west despite it saying journey west, however i solved it with a crude solution. Thank you again!


fixed_exits = string.gsub ("%3", " and ", ",")
fixed_exits2 = string.gsub (fixed_exits, "journey east", "east")
fixed_exits3 = string.gsub (fixed_exits2, "journey west", "west")
fixed_exits4 = string.gsub (fixed_exits3, "journey north", "north")
fixed_exits5 = string.gsub (fixed_exits4, "journey south", "south")
Australia Forum Administrator #14
Or:


fixed_exits = string.gsub (fixed_exits, "journey ", "")


That gets rid of the word "journey".