Simple kill alias

Posted by Blixel on Mon 12 Sep 2011 05:41 AM — 48 posts, 168,649 views.

#0
I'm playing an old MUD. It's fun, but it requires a lot of repetitive typing for combat. To kill a zombie, you type "hit z" [enter], "hit z", [enter], "hit z" [enter] ... until it's dead.

I'm trying to set up an alias for this. "att *" which then does:
hit %1
hit %1
hit %1
hit %1

This works, but the game doesn't allow commands to be entered too fast. So the first hit lands, but the other 3 are ignored because the game says I'm inputting too fast.

How can I make the alias wait a moment between hits? Something like:

hit %1
wait
hit %1
wait
hit %1
wait
hit %1

Of course that wouldn't work because it would send the word wait to the game, and that would be an invalid command.

Ideally, the command would do some checking ... such as hit until zombie is dead and then stop hitting. But for now, I'd be content to just have my attack command hit 4 times with a small pause in between each hit.
Australia Forum Administrator #1
Doing delays is described here:

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


<aliases>
  <alias
   match="att *"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>
require "wait"
wait.make (function ()

  for i = 1, 4 do
    Send ("hit %1")
    wait.time (1)
  end -- for

end) 
</send>
  </alias>
</aliases>


Template:pasting
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.


For checking if the mob is dead, try reading this:

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

I'll let you have the fun of getting that right, but basically you want to do something like:


x = wait.match ("The * is dead!", 1)


The timeout of 1 means it will time-out after 1 second. If x is nil then it timed-out (ie. the mob isn't dead) and if x is not nil then you know you killed it.

So you might do something like this:


local x = nil
while not x do
  Send ("hit %1")
  x = wait.match ("The * is dead!", 1)  
end -- while


Of course, you change the message "The * is dead!" to whatever you see when the thing you are fighting dies.
#2
Cool, thanks. You helped me achieve my primary objective.

I have "k [letter]" doing this now:

require "wait"
wait.make (function ()

  for i = 1, 4 do
    Send ("hit %1")
    wait.time (1)
  end -- for

end)


And it works! That alone is so much nicer, but it's a "dumb" loop.

I worked with your other idea and got it working, but have questions.

require "wait"

wait.make (function ()
  local x = nil
  while not x do
    Send ("hit %1")
    x = wait.match ("The * is slain!", 1)  
  end -- while
end)




Problem 1. If the monster runs away, the condition is not met. How do I add an OR to the match? One other condition is "The * flees in panic!"

Problem 2. If the condition isn't met, the loop doesn't stop and I have to turn off scripting. What is the easiest way to kill the loop?

I'm not sure how many conditions I'll have to think of to get the loop to work flawlessly every time, so I need a quick way to kill it.
Amended on Mon 12 Sep 2011 08:00 AM by Blixel
Australia Forum Administrator #3
This is truly the fun of scripting. You keep improving your stuff!

You can make your test check for multiple things by using a regular expression and using the "or" operator which is "|".


<aliases>
  <alias
   match="k *"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>
require "wait"

wait.make (function ()
  local x = nil
  giveup = false
  while not (x or giveup) do
    Send ("hit %1")
    x = wait.regexp ("^The .* (is slain!)|(flees in panic!)", 1)  
  end -- while
end)

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


Note that wait.match has changed to wait.regexp.

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.


Also to allow for manual cancelling we also test the "giveup" variable. Now we need an alias to set it:


<aliases>
  <alias
   match="giveup"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>giveup = true</send>
  </alias>
</aliases>


Now if you type "giveup" it sets the variable "giveup" to be true, which is tested in the attack alias.
#4
A thousand thanks. With that additional OR, it seems to work every time now. (I haven't had to test the giveup condition yet.)

Wow, what a refreshing break. I've been having a ton of fun with this old MUD, but it was starting to get tedious having to type out that kill command constantly.

I'd like to explore a few more ideas with this scripting stuff ... if it isn't too insanely complicated.

A couple of ideas. How hard would it be to add a look alias that read in the monsters in the room, and then used this kill alias to eliminate them one at a time?

>look

You are standing at a bend in the path. A small pine tree has gained purchase in the wall here and grows up at a sharp angle.

[][][][][][]
M       x []
--------  []
.......|  []
.......|$ []
.......|  []

M - frostbat, lynx


Send ("look")
wait for "M - "
if "M - " not there, do nothing -- no monsters in the room
otherwise, kill $1, then kill $2, etc...

And my other idea is for a sell alias. When standing at the shop, I have to type "sell [item]" repetitively.

inv

You are carrying some platemail, a brass-ring, a bottle, a key, a glass-ring, a flask, a flask, a mace, your spellbook and 100 gold pieces.


So my idea here would be to sell items that were in some kind of trinket list, but not sell my important magical items like my brass-ring.

trinkets = {pearl, shortsword, stone, whip,} etc...

#5
I'm making a lot of progress with my triggers and aliases.

This works great:

<trigger
   enabled="y"
   group="Were-creature"
   match="^M\ -\ .*were*"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>ColourNote ("white", "green", "--------------------------------------")
ColourNote ("white", "green", "Were-creature is detected in the room!")
ColourNote ("white", "green", "--------------------------------------")</send>
  </trigger>


That message really pops out at me. A wererat, werewolf, or wearbear in the room with you is bad news. If you get bit, you suffer from Lycanthropy.

This also works really well:

<trigger
   enabled="y"
   group="Auto-Killing"
   keep_evaluating="y"
   match="^M\ -\ .*zombie*"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>require "wait"
wait.make (function ()
  local x = nil
  giveup = false
  while not (x or giveup) do
    wait.time (0.2)
    Send ("chant reeshseno")
    wait.time (0.2)
    Send ("cast light zombie")
    x = wait.regexp ("^You killed the monster!",1)
  end -- while
end)</send>
  </trigger>


If I walk into a room and there's a zombie there, my Cleric automatically casts light until the zombie dies.

But what doesn't work is this:

  <trigger
   group="Tests"
   keep_evaluating="y"
   match="^M\ -\ (.*?)"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>Note ("A %1 is here")</send>
  </trigger>


That note always outputs as "A is here"

I'm trying to figure out how to get the list of mobs in the room so I can issue a general kill command.

I don't need special triggers for all the basic monsters. Do I need to build a table or something?




Australia Forum Administrator #6
Quote:

That note always outputs as "A is here"


When matching what lines?
#7
Nick Gammon said:

Quote:

That note always outputs as "A is here"


When matching what lines?



The mob line reads like this (4 examples):

M - wolf, adder, adder

M - werewolf, zombie

M - wolf, wolf, troglodyte

M - troll

Australia Forum Administrator #8
You need to add a trailing $ sign.

The sequence ".*?" matches on the minimal amount it can, which still matches. The minimal amount of "any character" is "no characters".

However the minimal amount of "any character followed by the end of the line" is the rest of the line.


match="^M\ -\ (.*?)$"

#9
Nick Gammon said:

You need to add a trailing $ sign.

The sequence ".*?" matches on the minimal amount it can, which still matches. The minimal amount of "any character" is "no characters".

However the minimal amount of "any character followed by the end of the line" is the rest of the line.


match="^M\ -\ (.*?)$"




Confusing. I suppose I'll understand it eventually.

But why doesn't this work?

Send ("look")
local x = nil
x = match="^M\ -\ (.*?)$"


Compile error
World: FL2
Immediate execution
[string "Alias: "]:3: unexpected symbol near '='

How is that any different than what we started with (which does work).

require "wait"

wait.make (function ()
  local x = nil
  giveup = false
  while not (x or giveup) do
    Send ("hit %1")
    x = wait.regexp ("^The .* (is slain!)|(flees in panic!)|(^There is no .* here\.)|(^You can\'t attack yourself!)", 1)
  end -- while
end)


USA #10
Blixel said:
Send ("look")
local x = nil
x = match="^M\ -\ (.*?)$"


You have "x = match = <stuff>". Lua's = operator doesn't have any value of its own, so you can't chain ='s like that.
Amended on Thu 15 Sep 2011 02:33 AM by Twisol
#11
I'm trying to work this out on my own by asking indirect questions, but that isn't working. So let me try to ask the question this way.

I have a mob line that looks like this:

M - troglodyte, piercer, troll

What I want to do is cycle through that list, one mob a time, executing my kill script, until all the mobs are slain.

Currently, I am doing this by using a trigger like this:

^M\ -\ .*(adder|brigand|dervish|fox|frostbat|gnoll|highwayman|hobgoblin|icetoad|lemure|lynx|owl|piercer|robber|snowman|troglodyte|troll|weasel|wolf|wolverine).*$

roomcleared = false
ColourNote ("white", "blue", "Call autokill %1")
Execute ("autokill %1")


My autokill function will automatically look at the room when it's done killing ... which will make the above trigger activate again if there are more mobs to be killed.

However, all that extra "look" calling is unnecessary and just causes a bunch of extra screen scrolling.

It would be better to do a for or while loop, but I don't know how to turn the mob line into a list that I can cycle through.
Australia Forum Administrator #12
Just match your list of mobs (like you did earlier up) and then use something like string.gmatch:

http://www.gammon.com.au/scripts/doc.php?lua=string.gmatch

Or, utils.split:

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

The mob line reads like this (4 examples):

M - wolf, adder, adder

M - werewolf, zombie

M - wolf, wolf, troglodyte

M - troll



Oh my God, this is so aggravating. Why don't any of these match?? I want to return a moblist that is = to "wolf, adder, adder" (as in example 1), or "werewolf, zombie" (as in example 2), or "wolf, wolf, troglodyte" (as in example 3), or just "troll" as in example 4.



^M\ -\ (.*?)$
^M\ -\ .*
^M\ -\ .*$
^M\ -\ *
^M\ -\ (.*)
^M\ -\ *.*
^M\ -\ *$


Nothing works. In every case:
monsterlist = %1
Note ("monsterlist is ", monsterlist)


says monsterlist is nil



USA #14
You need to put quotes around %1.

monsterlist = "%1"
Note ("monsterlist is ", monsterlist)


You'd normally get a syntax error if you forget the ""'s, but in this case Lua sees "monsterlist = wolf, adder, adder" which is valid script... it's just not what you want. Lua sees that as taking the values of variables named wolf and adder, and assigning the first of those to monsterlist. You want to assign the string value "wolf, adder, adder" to monsterlist, so you have to put quotes around %1.
Australia Forum Administrator #15
Here is an example:


<triggers>
  <trigger
   enabled="y"
   group="Tests"
   keep_evaluating="y"
   match="^M - (.*)"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
local monsters = utils.split ("%1", ",")

for k, v in ipairs (monsters) do
  Execute ("autokill " .. Trim (v))
end -- for

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



Testing:


M - wolf, adder, adder
autokill wolf
autokill adder
autokill adder
M - werewolf, zombie
autokill werewolf
autokill zombie
M - wolf, wolf, troglodyte
autokill wolf
autokill wolf
autokill troglodyte
M - troll
autokill troll

Australia Forum Administrator #16
Or a bit shorter:


<triggers>
  <trigger
   enabled="y"
   group="Tests"
   match="M - *"
   send_to="12"
   sequence="100"
  >
  <send>

for k, v in ipairs (utils.split ("%1", ",")) do
  Execute ("autokill " .. Trim (v))
end -- for

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

#17
Thanks again Nick. I'll test out these new ideas. Here's what I'm using at the moment, which seems to work? (This is just the relevant section.)

moblist = wait.regexp ("^M\ -\ (.*)", 1)
local mob = nil    
roomcleared = false
for mob in string.gmatch (moblist, "%a+") do

  local x = nil

  if not (mob == "M") then
    while not (x or giveup) do
      Send ("kill ", mob)
      x = wait.regexp ("^The .* (is slain!)|(flees in panic!)|(^There is no .* here\.)|(^You can\'t attack yourself!)", 1.2)
    end -- while

    -- After a kill, we send a short wait to
    -- prevent a "One moment please" message
    -- from coming up.
    wait.time (0.5)

  end -- end if
end -- for



I'm going to use your new ideas to see if I can get rid of that if not (mob == "M") check. I feel like that shouldn't be in the list in the first place.

Is this regular expression the best for my mob line?
^M\ -\ (.*)

Should there be a question mark or a dollar sign in there somewhere?

#18
Nick Gammon said:



M - wolf, adder, adder
autokill wolf
autokill adder
autokill adder
M - werewolf, zombie
autokill werewolf
autokill zombie
M - wolf, wolf, troglodyte
autokill wolf
autokill wolf
autokill troglodyte
M - troll
autokill troll



How are you cutting off the "M - " part?

In my testing, I'm getting this:

ou have come to an intersection in the trail. To the south is a small cave,
with a sign over the opening that reads:"Scariton".

............
-----dn-----
 M   x    
[][]    [][]
  [] $  []
  []    []

M - frostbat

>kill M - frostbat
There is no M here.


If a room has two monsters, it will error on the first one, and the kill the second one.

You are at another bend in the trail. The makers of this path appear to have
been uncertain as to which way they wanted to go.

[]  |.......
[]  |.......
[]M |.......
[]  --------
[] x   $      
[][][][][][]

M - brigand, icetoad

>kill M - brigand
There is no M here.
>kill icetoad
You missed!


Here is my code.

if (readytokill) then

  readytokill = false
 
  require "wait"

  wait.make (function ()
    
    -- This is our failsafe. With enough logic,
    -- this should never be needed. But just in
    -- case something goes sideways, we can type
    -- giveup to force our kill loop to stop.
    giveup = false

    -- Initialize moblist to nil
    local moblist = nil
 
    -- Have a look at the room to see if there is
    -- a line that starts with "M - ".
    Send ("look")

    -- If there is, that will become our list of
    -- mobs to kill.
    moblist = wait.regexp ("^M\ -\ (.*)", 1)

    moblist = utils.split (moblist, ",")
    
    if (moblist) then

    -- The ColourNote below is useful for following
    -- the logic. But it should be disabled for
    -- normal use.
    -- ColourNote ("white", "blue", moblist)


      -- Initialize mob variable to nil
      local mob = nil    
      roomcleared = false

      for k, mob in ipairs (moblist) do
      
        -- Initialize x variable to nil
        local x = nil

        -- The ColourNote below is useful for following
        -- the logic. But it should be disabled for
        -- normal use.
        ColourNote ("white", "blue", Trim (mob))
 
        -- Our main kill loop
        while not (x or giveup) do
          
          -- Keep hitting until the mob is
          -- dead or until the mob runs away.
          Send ("kill ", Trim (mob))

          -- So far we have 4 known reasons to
          -- quit hitting.
          -- 1.) Mob is slain!
          -- 2.) Mob has run away.
          -- 3.) We have stupidly tried to hit
          --     something that isn't there.
          -- 4.) We are trying to attack ourself!
          x = wait.regexp ("^The .* (is slain!)|(flees in panic!)|(^There is no .* here\.)|(^You can\'t attack yourself!)", 1.2)
          
        end -- while
        
        -- After a kill, we send a short wait to
        -- prevent a "One moment please" message
        -- from coming up.
        wait.time (0.5)

      
      end -- for

    else
      -- There was no "M - " line in the room, so 
      -- we'll just set the roomcleared variable to
      -- true and exit.
      roomcleared = true
      ColourNote ("white", "blue", "No mobs detected")
    end -- if (moblist)

     
    -- One of our conditions has been met.
    -- The mob was killed or it ran away.
    -- In either case, we are ready to kill
    -- again. So we set the readytokill
    -- variable back to true so this routine
    -- can be called again.
    readytokill = true
  
  end) -- end wait function

end -- end main if statement



Australia Forum Administrator #19
Blixel said:

How are you cutting off the "M - " part?


Looking at the documentation for the wait module:

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

You had:


 -- If there is, that will become our list of
    -- mobs to kill.
    moblist = wait.regexp ("^M\ -\ (.*)", 1)


But wait.regexp returns 3 results:

  1. The matching line
  2. The wildcards (in a table)
  3. The style runs (in a table)


Since you are using the first result you are getting the entire matching line.

The first wildcard (the mob names) would be wildcards [1].

eg.


    line, wildcards = wait.regexp ("^M\ -\ (.*)", 1)
    if line then
      moblist = wildcards [1]

      ...

    end -- if

#20
Nick Gammon said:
But wait.regexp returns 3 results:

*The matching line
*The wildcards (in a table)
*The style runs (in a table)


Ah-ha. It took me a few minutes to get what you were talking about, but now I understand.

I finally have my general purpose autokill working exactly how I want. I can't really imagine a better way of doing this. (For this particular MUD.)

I need to set up a few exclusions, but that will be trivial I believe. (As an example, don't use this general purpose autokill for the undead. Let the Cleric turn undead and/or cast light.) Perhaps a table of exclusions. This general purpose autokill routine can then check the mob name to see if it shows up in the table. And if so, ignore mob and kill the next one on the list. Something like that. I'll figure that out later. Shouldn't be hard.


-- General purpose on/off switch for
-- the whole routine.
if (readytokill) then
  
  require "wait"

  wait.make (function ()
    
    -- This is our failsafe. With enough logic,
    -- this should never be needed. But just in
    -- case something goes sideways, we can type
    -- giveup to force our kill loop to stop.
    giveup = false

    -- Initialize moblist to nil
    local moblist = nil
 
    -- Have a look at the room to see if there is
    -- a line that starts with "M - ".
    Send ("look")

    -- If there is, that will become our list of
    -- mobs to kill.
    -- The line variable is returned by wait.regexp
    -- and will have the entire line, including the
    -- "M - " part. The wildcards variable will only
    -- include the wildcard part of our line, which
    -- in this case will be a comma separated string
    -- of monster names. (e.g. owl, wolf, icetoad)
    line, wildcards = wait.regexp ("^M\ -\ (.*)", 1)

    -- If wait.regexp didn't return a line, then there
    -- was no "M - " line in this room. Presumably,
    -- this would mean the room is clear of mobs.
    if (line) then

      -- If wait.regexp does return a line, then we
      -- set the moblist equal to the wildcards.
      moblist = wildcards [1]

      -- Initialize mob variable to nil. This is our
      -- general purpose variable name that we'll use
      -- as we step through the list of mob names.
      local mob = nil    

      -- Tells other triggers that may be
      -- watching that the room is not
      -- clear. There is killing to be done.
      roomcleared = false

      -- Split the monster list into a table
      moblist = utils.split (moblist, ",")

      -- Cycle through our monster table one
      -- mob at a time.
      for k, mob in ipairs (moblist) do
      
        -- Initialize x variable to nil
        local x = nil

        -- Our main kill loop
        while not (x or giveup) do
          
          -- Keep hitting until the mob is
          -- dead or until the mob runs away.
          -- The Trim function removes white space
          -- around the monster name. So we will
          -- "kill owl" as opposed to "kill  owl "
          Send ("kill ", Trim (mob))

          -- So far we have 6 known reasons to
          -- quit hitting.
          -- 1.) Mob is slain!
          -- 2.) Mob has run away.
          -- 3.) We have specified an invalid target.
          -- 4.) We are trying to attack ourself!
          -- 5.) We are trying to attack inside a town.
          -- 6.) We did not specify a target.
          x = wait.regexp ("^The .* (is slain!)|(flees in panic!)|(^There is no .* here\.$)|(^You can\'t attack yourself!$)|(^A being clothed in white appears before you\.$)|(^Do what\.?$)", 1.5)
          
        end -- while
        
        -- After a kill, we send a short wait to
        -- prevent a "One moment please" message
        -- from coming up.
        wait.time (0.75)

      end -- for

    else
      -- There was no "M - " line in the room
      -- ColourNote here for troubleshooting only
      -- ColourNote ("white", "blue", "No mobs detected")
    end -- if (moblist)

     
    -- One of our conditions has been met.
    -- The mob was killed or it ran away.
    -- In either case, we are ready to kill
    -- again. So we set the readytokill
    -- variable back to true so this routine
    -- can be called again.
    readytokill = true
  
  end) -- end wait function

end -- end main if statement


#21
First, I want to say that I am highly appreciative of how patient and helpful you guys have been. This forum has been one of the friendliest places I've ever visited. Very impressive.

So, thanks again.


I have another question about this kill routine. As elegant as it is (at least, that's how I feel about it), it has one shortcoming.

Sometimes a monster will enter the room after you've cleared the room. When the monster comes in, the game gives the name of the monster. The text is always in this format:

>A wererat appears suddenly and attacks!


Or, in terms of a regular expression, it's always in this format:

^\>?A (.*?) appears suddenly and attacks\!$


Did I get the regular expression right finally? Is it (.*?) or should it just be *?

At any rate, since we know the name of the monster, there is no reason to Send ("look") in order to get the "M - *" line.

My thinking was to split the kill routine into two pieces. The first piece would get the moblist and then kill the monsters in a for loop like this (I'm cutting out all my comments to make it more concise):

require "wait"

wait.make (function ()
  moblist = nil
  Send ("look")

  line, wildcards = wait.regexp ("^M\ -\ (.*)", 1)

  if (line) then
    moblist = wildcards [1]
    mob = nil
    roomcleared = false
    moblist = utils.split (moblist, ",")

    for k, mob in ipairs (moblist) do
      Execute ("autokill " .. Trim (mob))
    end

    roomcleared = true

  end -- if (line)
end) -- wait


The advantage of doing it this way is that the autokill part of the script can now accept an argument.

if (readytokill) then

  readytokill = false
 
  require "wait"
  wait.make (function ()
    giveup = false
    local x = nil
    while not (x or giveup) do
      Send ("kill %1")

      -- So far we have 6 known reasons to
      -- quit hitting.
      -- 1.) Mob is slain!
      -- 2.) Mob has run away.
      -- 3.) We have specified an invalid target.
      -- 4.) We are trying to attack ourself!
      -- 5.) We are trying to attack inside a town.
      -- 6.) We did not specify a target.
      x = wait.regexp ("^The .* (is slain!)|(flees in panic!)|(^There is no .* here\.$)|(^You can\'t attack yourself!$)|(^A being clothed in white appears before you\.$)|(^Do what\.?$)", 1.2)
          
    end -- while
        
    wait.time (0.5)
    readytokill = true
  
  end) -- end wait function

end -- end main if statement


So now, when this happens:

^\>?A (.*?) appears suddenly and attacks\!$


I can have that trigger: Execute ("autokill %1")

...without having to Send ("look")

It cuts down on screen scrolling big time.

The problem I'm running into is that my for loop isn't working. It kills the first mob in the list, and then stops.

Is that due to the fact that computers are fast and networks are slow?

My other idea is to make the original autokill script accept an argument. And then wrap it up in an If-Then statement. If an argument was given then behave this way ... if no argument was given, behave the other way. But in looking at the code, it seems like that would be more difficult ... and possibly more sloppy.

Amended on Sun 18 Sep 2011 11:04 AM by Blixel
Australia Forum Administrator #22
Quote:

Did I get the regular expression right finally? Is it (.*?) or should it just be *?


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.


The brackets make a capture group.

I would use either:


.*


That matches "anything, greedy".

or:


.*?


That matches "anything, not greedy".

Look on the regexp page for the difference between greedy and non-greedy.

So meanwhile:


(.*)


Is a greedy capture group. (ie. it becomes %1, %2 or whatever).

Which of those is best depends on what you want.
Australia Forum Administrator #23
Quote:

The problem I'm running into is that my for loop isn't working. It kills the first mob in the list, and then stops.

Is that due to the fact that computers are fast and networks are slow?


I don't see anything there that makes it loop and look for another mob. Yes, computers are faster than networks. But I don't think this is the exact problem here.
#24
Nick Gammon said:

(regexp)

The brackets make a capture group.


Ok. I'm pretty sure I get that part now. Parenthesis make it a capture group. I need it to be a capture group in that case, so I do need the parenthesis.



.*?


That matches "anything, not greedy".

Look on the regexp page for the difference between greedy and non-greedy.


I read the page all the way down to the greedy part. The first use of the ? mark I do understand.

12345? would match 1234 and it would match 12345. The 5 is optional. It wouldn't match 123 or 123456. 123 is missing the required 4, and 123456 has an extra 6 on the end.

So .*? matches everything between two points.

The .*? is attacking you.

The dog is attacking you. Matches.
The big dog is attacking you. Matches.
The really big dog is attacking you. Matches.
The big ferocious dog with snarling teeth is attacking you. Matches.
The dog seems tame. But looks can be deceiving. Upon closer inspection, you realize the dog has red glowing eyes. Before you know it, the wild animal lunges forth. Run for you life! The beast is attacking you. Matches.

And in all those cases, if we were to put the .*? in parenthesis, then everything between 'The' and 'is attacking you.' would become %1

In the last example, %1 = "dog seems tame. But looks can be deceiving. Upon closer inspection, you realize the dog has red glowing eyes. Before you know it, the wild animal lunges forth. Run for you life! The beast"

And if the question mark isn't there...

The .* is attacking you.

Then all those examples still apply anyway. So I guess the point is, there's zero difference between greedy and non-greedy in this application.
#25
Nick Gammon said:

Quote:

The problem I'm running into is that my for loop isn't working. It kills the first mob in the list, and then stops.

Is that due to the fact that computers are fast and networks are slow?


I don't see anything there that makes it loop and look for another mob. Yes, computers are faster than networks. But I don't think this is the exact problem here.


Isn't this a loop?


for k, mob in ipairs (moblist) do
  Execute ("autokill " .. Trim (mob))
end
Australia Forum Administrator #26
Hmm, yes. Can you paste the whole aliases so I can test them?

Template:copying
For advice on how to copy aliases, timers or triggers from within MUSHclient, and paste them into a forum message, please see Copying XML.
#27
Nick Gammon said:
Hmm, yes. Can you paste the whole aliases so I can test them?


Sorry about all the comments. :) I'm paranoid about forgetting what stuff does.

Here is some input text:

M - wolf, adder, adder
M - werewolf, zombie
M - wolf, wolf, troglodyte
M - troll


This alias gets the monster list and sends the list of monsters (using a for loop) to the second alias.

<aliases>
  <alias
   name="GetMobList"
   match="getmoblist"
   enabled="y"
   group="Get Monster List"
   send_to="12"
   sequence="100"
  >
  <send>require "wait"

wait.make (function ()
    
  -- Initialize moblist to nil
  moblist = nil
 
  -- Have a look at the room to see if there is
  -- a line that starts with "M - ".
  Send ("look")

  -- If there is, that will become our list of
  -- mobs to kill.
  -- The line variable is returned by wait.regexp
  -- and will have the entire line, including the
  -- "M - " part. The wildcards variable will only
  -- include the wildcard part of our line, which
  -- in this case will be a comma separated string
  -- of monster names. (e.g. owl, wolf, icetoad)
  line, wildcards = wait.regexp ("^M\ -\ (.*)", 1)

  -- If wait.regexp didn't return a line, then there
  -- was no "M - " line in this room. Presumably,
  -- this would mean the room is clear of mobs.
  if (line) then

    -- If wait.regexp does return a line, then we
    -- set the moblist equal to the wildcards.
    moblist = wildcards [1]

    -- Initialize mob variable to nil. This is our
    -- general purpose variable name that we'll use
    -- as we step through the list of mob names.
    mob = nil

    -- Tells other triggers that may be
    -- watching that the room is not
    -- clear. There is killing to be done.
    roomcleared = false

    -- Split the monster list into a table
    moblist = utils.split (moblist, ",")

    -- Cycle through our monster table one
    -- mob at a time.
    -- The Trim function removes white space
    -- around the monster name. So we will
    -- "kill owl" as opposed to "kill  owl "
    for k, mob in ipairs (moblist) do
      Execute ("mobkillengine " .. Trim (mob))
    end

    -- Room should be free of mobs by now.
    roomcleared = true

  end -- if (line)

end) -- wait</send>
  </alias>
</aliases>


It is the intention to have this next alias process the list from the first one. (Or, to allow this next alias to stand alone with user input or other trigger text [see bottom for example of other trigger text].)

<aliases>
  <alias
   name="MobKillEngine"
   match="mobkillengine *"
   enabled="y"
   group="Kill Routines"
   send_to="12"
   keep_evaluating="y"
   sequence="100"
  >
  <send>-- If autokill is disabled, then forget this
-- whole routine. Presumably, autokill was
-- disabled so we can walk around without the
-- constant interruption of killing.

-- Also, if readytokill is disabled, then we
-- forget the whole routine as well. The main
-- reason readytokill would be disabled would
-- be due to the fact that we are Already
-- killing some other mob. We don't want our
-- killing to overlap, so when we start this
-- routine, we set readytokill to off so that
-- if it gets called a second time, the second
-- instance will just ignore it until the first
-- instance is done killing.

if (readytokill) then
--if (autokill and readytokill) then

  -- Autokill is on, and we are ready to kill.
  -- The first thing we do is set readytokill
  -- to false so another instance can't overlap. 
  readytokill = false
 
  require "wait"

  wait.make (function ()
    
    -- This is our failsafe. With enough logic,
    -- this should never be needed. But just in
    -- case something goes sideways, we can type
    -- giveup to force our kill loop to stop.
    giveup = false

    -- Initialize x variable to nil
    local x = nil

    -- Our main kill loop
    while not (x or giveup) do
          
      -- Keep hitting until the mob is
      -- dead or until the mob runs away.
      Send ("kill %1")

      -- So far we have 6 known reasons to
      -- quit hitting.
      -- 1.) Mob is slain!
      -- 2.) Mob has run away.
      -- 3.) We have specified an invalid target.
      -- 4.) We are trying to attack ourself!
      -- 5.) We are trying to attack inside a town.
      -- 6.) We did not specify a target.
      x = wait.regexp ("^The .* (is slain!)|(flees in panic!)|(^There is no .* here\.$)|(^You can\'t attack yourself!$)|(^A being clothed in white appears before you\.$)|(^Do what\.?$)", 1.2)
          
    end -- while
        
    -- After a kill, we send a short wait to
    -- prevent a "One moment please" message
    -- from coming up.
    wait.time (0.5)

    -- One of our conditions has been met.
    -- The mob was killed or it ran away.
    -- In either case, we are ready to kill
    -- again. So we set the readytokill
    -- variable back to true so this routine
    -- can be called again.
    readytokill = true
  
  end) -- end wait function

end -- end main if statement</send>
  </alias>
</aliases>


Here is other trigger text that makes splitting this routine into two pieces very useful. When a mob "appears suddenly", we don't need to look at the room. The game tells us the name of the mob. So if we look at the room again anyway, it just causes lots of extra screen scrolling.

<triggers>
  <trigger
   enabled="y"
   group="Monster List for Auto-Killing"
   match="^\&gt;?A (.*?) appears suddenly and attacks!$"
   name="MobAppearsSuddenly"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>Execute ("mobkillengine %1")</send>
  </trigger>
</triggers>

Amended on Mon 19 Sep 2011 05:45 AM by Blixel
Australia Forum Administrator #28
Without actually testing it, I think this is the problem:


    -- Cycle through our monster table one
    -- mob at a time.
    -- The Trim function removes white space
    -- around the monster name. So we will
    -- "kill owl" as opposed to "kill  owl "
    for k, mob in ipairs (moblist) do
      Execute ("mobkillengine " .. Trim (mob))
    end


This alias spits out all the mobkillengine commands at once (there is no delay in that loop). So it would execute:


mobkillengine wolf
mobkillengine adder
mobkillengine adder


But you say later:


-- Also, if readytokill is disabled, then we
-- forget the whole routine as well. The main
-- reason readytokill would be disabled would
-- be due to the fact that we are Already
-- killing some other mob. We don't want our
-- killing to overlap, so when we start this
-- routine, we set readytokill to off so that
-- if it gets called a second time, the second
-- instance will just ignore it until the first
-- instance is done killing.


So you don't want to kill wolf, adder and adder all at once.

By splitting it into two aliases you have removed a crucial delay, that is, waiting for one mob to die before you attack another one.
#29
Nick Gammon said:
Without actually testing it, I think this is the problem:

...

So you don't want to kill wolf, adder and adder all at once.

By splitting it into two aliases you have removed a crucial delay, that is, waiting for one mob to die before you attack another one.


I think you're right, and that was my suspicion from the start. My question was basically to ask if there was a way to make Execute ("mobkillengine %1") wait to finish before the loop would call it again.

And I think you're telling me the answer is no.

So my solution is going to have to be to have two separate aliases that do almost exactly the same thing.

One alias will look at the room, get a mob list, and loop through it ... killing one mob at a time.

The other alias will expect an argument. It will not look at the room and create a mob list. It will kill the mob that was passed in as an argument.

I guess it's not too bad. It will just duplicate the main kill routine. If I discover more reasons to quit hitting, I'll have to update it in both places.

Thanks for your input.
USA #30
Blixel said:
And I think you're telling me the answer is no.

There is a solution in Lua's coroutines. It's simple in execution, but a little hard to explain.

Right now, you're probably used to a very linear, step-by-step execution model of programming. Coroutines add a bit of a twist, resulting in what you might call an interleaved model. That is, two lines of execution are interleaved at specific points, but they never execute at the same time (unlike threads).

Here's a bit of an abstract example:
-- Coroutine
myloop = coroutine.make(function()
  for i=1, 10 do
    coroutine.yield(i)
  end
end)

-- Main line of execution
Note(myloop.resume()) -- 1
Note(myloop.resume()) -- 2


Hopefully I can explain this right... First we create a coroutine, and its job is to go over the numbers from 1 to 10. It's not actually run at this point, it's just set up. Next we call myloop.resume(), which pauses the main coroutine and enters our myloop coroutine at the top. It begins looping, and then calls coroutine.yield(). This is where the magic happens: the coroutine is paused in the middle of the loop, and our main coroutine resumes, returning the value of i that was passed to yield().

At this stage, the myloop coroutine is paused in the middle of a loop, and it won't ever continue until we resume it again. And when we do resume it, it'll pick up right where it left off, continuing to the next iteration and yielding 2.

Now, how does this apply to your aliases? You basically want to put your getmoblist alias's for loop into a coroutine, and have your mobkillengine alias resume it after it's finished. Your mob loop will pick up right where it left off, executing the mobkillengine alias again with a new mob.

I hope I explained that decently well. Coroutines are fun and really useful, but they can be a little tough to grok at the beginning. You might be interested to know that the wait module itself is backed by coroutines; that's how it can stop in the middle of a script and pick up later. It creates a temporary trigger or timer in the background that resumes the coroutine when it fires.
Amended on Mon 19 Sep 2011 08:01 AM by Twisol
Australia Forum Administrator #31
Blixel said:

And I think you're telling me the answer is no.

So my solution is going to have to be to have two separate aliases that do almost exactly the same thing.



I think you are making a mistake by creating an alias to do what a function really should.

If you make a script file, and put mobkillengine into it as a function (not an alias), then you just call that from the first alias. That way the pauses in mobkillengine will now be incorporated into the first alias, and it will feed the kill commands in slowly.
#32
Twisol said:
I hope I explained that decently well.


Yes, you explained it well. That is very cool and that sounds like the exact solution that is needed in this case. I'm definitely going to try this. Thanks.
#33
Nick Gammon said:
I think you are making a mistake by creating an alias to do what a function really should.

If you make a script file, and put mobkillengine into it as a function (not an alias), then you just call that from the first alias. That way the pauses in mobkillengine will now be incorporated into the first alias, and it will feed the kill commands in slowly.


Hmm... this is all new to me, so I'm learning as I go here. (Look back at my very first message in this thread to see how far this idea has developed from its original inception.)

I'm familiar with functions from Pascal and C. I understand feeding a function an argument or a dataset, and having the function return a piece of data itself, or simply return 1 or 0 for successful execution or failure respectively.

But I certainly have not yet looked into setting up a function in MUSHclient. I believe I understand what you are saying though. If I have the mobkillengine as a function, then the timing issue won't be an issue. The alias will pass the mob into the mobkillengine function, and the alias won't continue until mobkillengine returns.

How does this compare with Twisol's idea of using coroutines?
USA #34
Blixel said:
How does this compare with Twisol's idea of using coroutines?

His way is simpler, but you have to make sure that you remove the wait.make() around the mobkillengine code. That's because, as I mentioned, the wait module itself is built upon coroutines. You want to pause the whole line of execution when killing a mob, not just that specific part. Otherwise you'll be back where you started: control returned to getmoblist before mobkillengine is done.
Amended on Mon 19 Sep 2011 04:06 PM by Twisol
#35
Ok, I'm working on turning mobkillengine into a function. I did a google search on LUA functions and what I read seemed pretty straightforward.

Here's what I've come up with so far. Could you steer me in the right direction?

function mobkillengine (mob)

  -- If readytokill is disabled, then we skip the
  -- whole routine. The main reason readytokill would
  -- be disabled would be due to the fact that we are
  -- already killing some other mob. We don't want our
  -- killing to overlap, so when we start this
  -- routine, we set readytokill to off so that
  -- if it gets called a second time, the second
  -- instance will just ignore it until the first
  -- instance is done killing.

  if (readytokill) then

    -- The first thing we do is set readytokill
    -- to false so another instance can't overlap. 
    readytokill = false
 
    -- This is our failsafe. With enough logic,
    -- this should never be needed. But just in
    -- case something goes sideways, we can type
    -- giveup to force our kill loop to stop.
    giveup = false

    -- Initialize x variable to nil
    local x = nil

    -- Our main kill loop
    while not (x or giveup) do
          
      -- Keep hitting until the mob is
      -- dead or until the mob runs away.
      -- Send ("kill %1")
      -- Would this be this instead:
      Send ("kill " .. mob)

      -- So far we have 6 known reasons to
      -- quit hitting.
      -- 1.) Mob is slain!
      -- 2.) Mob has run away.
      -- 3.) We have specified an invalid target.
      -- 4.) We are trying to attack ourself!
      -- 5.) We are trying to attack inside a town.
      -- 6.) We did not specify a target.

      -- Would this be match.regexp instead of wait?

      -- x = wait.regexp ("^The .*? (is slain!)|(flees in panic!)|(^There is no .*? here\.$)|(^You can\'t attack yourself!$)|
(^A being clothed in white appears before you\.$)|(^Do what\.?$)", 1)

      x = match.regexp ("^The .*? (is slain!)|(flees in panic!)|(^There is no .*? here\.$)|(^You can\'t attack yourself!$)|
(^A being clothed in white appears before you\.$)|(^Do what\.?$)")

          
    end -- while
        
    -- After a kill, we send a short wait to
    -- prevent a "One moment please" message
    -- from coming up.
    -- I can move this wait.time (1) outside of the function
    -- wait.time (1)

    -- One of our conditions has been met.
    -- The mob was killed or it ran away.
    -- In either case, we are ready to kill
    -- again. So we set the readytokill
    -- variable back to true so this routine
    -- can be called again.
    readytokill = true
  
  end -- end main if statement

end -- function
Amended on Thu 22 Sep 2011 09:20 AM by Blixel
#36
How do you match text inside of a function?

This method doesn't work:

function isroomclear ()
  Send ("look")
  line, wildcards = wait.regexp ("^M - (.*?)$", 1)
  if (line) then
    return 0
  else
    return 1
  end
end


I tried replacing wait.regexp with match.regexp (since there is no "wait" inside of the function), but that doesn't work either.

I did a google search for "lua function match regular expression" ... but it's difficult to understand all the examples other people are using in such different context.
Australia Forum Administrator #37
In what way does it not work? Error message?

It's hard to tell from snippets, the way the whole thing is assembled together is relevant.
#38
Nick Gammon said:

In what way does it not work? Error message?

It's hard to tell from snippets, the way the whole thing is assembled together is relevant.


Sorry, I thought my code would be obviously wrong in and of itself.

Using the above function, if I type "/mobkillengine("baboon") into the command input box, I get this:

Run-time error
World: Cleric
Immediate execution
[string "Command line"]:1: attempt to call global 'mobillengine' (a nil value)
stack traceback:
        [string "Command line"]:1: in main chunk


And when I try to run the greatly simplified isroomclear() function, I get this:

Run-time error
World: Cleric
Immediate execution
[string "Script file"]:73: attempt to index global 'wait' (a nil value)
stack traceback:
        [string "Script file"]:73: in function 'isroomclear'
        [string "Command line"]:1: in main chunk
Error context in script:
  69 : end -- function
  70 : 
  71 : function isroomclear ()
  72 :   Send ("look")
  73*:   line, wildcards = wait.regexp ("^M - (.*?)$", 1)
  74 :   if (line) then
  75 :     return 0
  76 :   end
  77 :   return 1


Twisol had said you can't use wait in a function. So I tried replacing wait.regexp with match.regexp and got this:

Run-time error
World: Cleric
Immediate execution
[string "Script file"]:73: attempt to index global 'match' (a nil value)
stack traceback:
        [string "Script file"]:73: in function 'isroomclear'
        [string "Command line"]:1: in main chunk
Error context in script:
  69 : end -- function
  70 : 
  71 : function isroomclear ()
  72 :   Send ("look")
  73*:   line, wildcards = match.regexp ("^M - (.*?)$")
  74 :   if (line) then
  75 :     return 0
  76 :   end
  77 :   return 1



Australia Forum Administrator #39
match.regexp? What's that?

Can you paste your code? You are just showing the tiny bits that fail. The reasons why they fail would be more related to seeing the whole.

For example, "mobillengine" - where is that defined?
Australia Forum Administrator #40
Quote:

if I type "/mobkillengine("baboon") into the command input box ...


or "mobillengine"? You have to get the spelling right.
Australia Forum Administrator #41
I need to see your structure here. Are you using a script file? What is in it? Are you using a plugin? Are you putting stuff in aliases? It can be made to work, certainly. But the devil is in the detail, as they say.
#42
Nick Gammon said:

match.regexp? What's that?

Can you paste your code? You are just showing the tiny bits that fail. The reasons why they fail would be more related to seeing the whole.

For example, "mobillengine" - where is that defined?


I'm not using a plugin.

Sorry, I had already copy/pasted the whole mobkillengine function from my script file in a previous message, so I didn't think it was necessary to paste it again.

"mobillengine" was a typo. I'm sorry.

Right now, I believe this function can stand alone ... without any other aliases or triggers.

Per one of you previous messages...

Nick Gammon said:
I think you are making a mistake by creating an alias to do what a function really should.

If you make a script file, and put mobkillengine into it as a function (not an alias), then you just call that from the first alias. That way the pauses in mobkillengine will now be incorporated into the first alias, and it will feed the kill commands in slowly.


So my goal with this function is to be able to get the moblist from the alias, and feed it into this function, 1 mob at a time.

But I don't need the alias in order to test if this function is working (fundamentally). If it doesn't work by calling it directly, then it's not going to work by having an alias "on top" of it.

With the typo corrected, the function will now hit a mob 1 time and then return. It isn't looping how I want.

Sorry to be such a pest.


function mobkillengine (mob)

  -- If readytokill is disabled, then we skip the
  -- whole routine. The main reason readytokill would
  -- be disabled would be due to the fact that we are
  -- already killing some other mob. We don't want our
  -- killing to overlap, so when we start this
  -- routine, we set readytokill to off so that
  -- if it gets called a second time, the second
  -- instance will just ignore it until the first
  -- instance is done killing.

  if (readytokill) then

    -- The first thing we do is set readytokill
    -- to false so another instance can't overlap. 
    readytokill = false
 
    -- This is our failsafe. With enough logic,
    -- this should never be needed. But just in
    -- case something goes sideways, we can type
    -- giveup to force our kill loop to stop.
    giveup = false

    -- Initialize x variable to nil
    local x = nil

    -- Our main kill loop
    while not (x or giveup) do
          
      -- Keep hitting until the mob is
      -- dead or until the mob runs away.
      -- Send ("kill %1")
      -- Would this be this instead:
      Send ("kill " .. mob)

      -- So far we have 7 known reasons to
      -- quit hitting.
      -- 1.) Mob is slain!
      -- 2.) Mob has run away.
      -- 3.) We have specified an invalid target.
      -- 4.) We are trying to attack ourself!
      -- 5.) We are trying to attack inside a town.
      -- 6.) We did not specify a target.
      -- 7.) We died.
      x = ("^The .*? (is slain!)|(flees in panic!)|(^There is no .*? here\.$)|(^You can\'t attack yourself!$)|
(^A being clothed in white appears before you\.$)|(^Do what\.?$)|(^The dead have no need to fight\.$)")

          
    end -- while
        
    -- One of our conditions has been met.
    -- The mob was killed or it ran away.
    -- In either case, we are ready to kill
    -- again. So we set the readytokill
    -- variable back to true so this routine
    -- can be called again.
    readytokill = true
  
  end -- end main if statement

end -- function

Amended on Thu 22 Sep 2011 09:27 AM by Blixel
Australia Forum Administrator #43
Quote:

But I don't need the alias in order to test if this function is working (fundamentally).


But you do if you are relying on the stuff inherited from using the wait module.

For example:



require "wait"

-- a function here to modularize things

function mobkillengine (mob)

 -- kill one mob here

end -- function mobkillengine

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

   for k, v in ipairs (utils.split ("%1", ",")) do
     mobkillengine (Trim (v))
   end -- for

end)  -- end of coroutine


If your function is using the "wait" stuff (that is, it expects to be inside a coroutine) then you can't test it stand-alone.
#44
Nick Gammon said:

Quote:

But I don't need the alias in order to test if this function is working (fundamentally).


But you do if you are relying on the stuff inherited from using the wait module.

For example:



require "wait"

-- a function here to modularize things

function mobkillengine (mob)

 -- kill one mob here

end -- function mobkillengine

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

   for k, v in ipairs (utils.split ("%1", ",")) do
     mobkillengine (Trim (v))
   end -- for

end)  -- end of coroutine


If your function is using the "wait" stuff (that is, it expects to be inside a coroutine) then you can't test it stand-alone.


I'm getting really confused here.

But first let me remind us what the point of splitting this up into two separate parts was in the first place. The point was to make mobkillengine capable of killing 1 mob - as supplied by the user. Going back to a previous message, I said:

blixel said:
I have another question about this kill routine. Sometimes a monster will enter the room after you've cleared the room. When the monster comes in, the game gives the name of the monster. The text is always in this format:

>A wererat appears suddenly and attacks!

Or, in terms of a regular expression, it's always in this format:

^\>?A (.*?) appears suddenly and attacks\!$

Since we know the name of the monster, there is no reason to Send ("look") in order to get the "M - *" line.

My thinking was to split the kill routine into two pieces.


So the first piece would be responsible for "evaluating" the room ... that is, it would look for that "M - *" line, break the monster line down into a list, and then pass the list to mobkillengine, 1 mob at a time.

And the Whole Point of doing that is so that I can Also call mobkillengine by itself ... so that - in the case when ">A wererat appears suddenly and attacks!", I can simply have a trigger that will "Execute ("mobkillengine %1")

If I can't do that, then it does absolutely no good to split this up into two separate pieces.

Hopefully that makes sense. The reason I wanted to break that up into two pieces was so that mobkillengine could be used for two different purposes. 1.) So that it could kill a single mob - when supplied with the mob name by the user via a trigger. 2.) So that it could be fed a list of mobs, 1 mob at a time, by some other function/alias in a loop.

Amended on Sat 24 Sep 2011 01:20 AM by Blixel
Australia Forum Administrator #45
What is this intended to do?


 x = ("^The .*? (is slain!)|(flees in panic!)|(^There is no .*? here\.$)|(^You can\'t attack yourself!$)|
(^A being clothed in white appears before you\.$)|(^Do what\.?$)|(^The dead have no need to fight\.$)")

#46
Nick Gammon said:

What is this intended to do?


 x = ("^The .*? (is slain!)|(flees in panic!)|(^There is no .*? here\.$)|(^You can\'t attack yourself!$)|
(^A being clothed in white appears before you\.$)|(^Do what\.?$)|(^The dead have no need to fight\.$)")




The original code for that was this:

x = wait.regexp ("^The .*? (is slain!)|(flees in panic!)|(^There is no .*? here\.$)|(^You can\'t attack yourself!$)|
(^A being clothed in white appears before you\.$)|(^Do what\.?$)", 1)


But I am to understand you can't use wait in a function, so it had to be replaced. I tried replacing it with this:

x = match.regexp ("^The .*? (is slain!)|(flees in panic!)|(^There is no .*? here\.$)|(^You can\'t attack yourself!$)|
(^A being clothed in white appears before you\.$)|(^Do what\.?$)")


I thought I had seen match.regexp used somewhere before, but apparently there's no such function.

So, I am still trying to figure out how to replace x = wait.regexp (....) with some similar code that will work in a function.
Amended on Sat 24 Sep 2011 05:13 AM by Blixel
USA #47
Blixel said:
But I am to understand you can't use wait in a function, so it had to be replaced.

Certainly it can. He's not saying that it can't be used in a function. This is the critical line that is being disagreed with:

Blixel said:
But I don't need the alias in order to test if this function is working (fundamentally). If it doesn't work by calling it directly, then it's not going to work by having an alias "on top" of it.

You need to understand that this function isn't as self-contained as it might appear. To use this function, it must be called from within a wait.make() block, because it assumes that it can use wait.match(). So it's valid to call from your alias because your alias uses the wait module. However, you can't do a naive call of the function. If you want to call it standalone, you'd need to call it like this:
wait.make(function()
  mobkillengine("dark link")
end)

If you called it straight (i.e. directly from the main line of execution instead of from a wait coroutine), it wouldn't work, because there is no active coroutine to pause and resume.