[Home] [Downloads] [Search] [Help/forum]


Register forum user name Search FAQ

Gammon Forum

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Lua
. . -> [Subject]  Simple kill alias

Simple kill alias

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page


Pages: 1  2  3 4  

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #30 on Mon 19 Sep 2011 08:00 AM (UTC)

Amended on Mon 19 Sep 2011 08:01 AM (UTC) by Twisol

Message
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.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Nick Gammon   Australia  (23,000 posts)  [Biography] bio   Forum Administrator
Date Reply #31 on Mon 19 Sep 2011 08:04 AM (UTC)
Message
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.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Blixel   (80 posts)  [Biography] bio
Date Reply #32 on Mon 19 Sep 2011 08:08 AM (UTC)
Message
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.
[Go to top] top

Posted by Blixel   (80 posts)  [Biography] bio
Date Reply #33 on Mon 19 Sep 2011 08:18 AM (UTC)
Message
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?
[Go to top] top

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #34 on Mon 19 Sep 2011 04:05 PM (UTC)

Amended on Mon 19 Sep 2011 04:06 PM (UTC) by Twisol

Message
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.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Blixel   (80 posts)  [Biography] bio
Date Reply #35 on Tue 20 Sep 2011 06:52 AM (UTC)

Amended on Thu 22 Sep 2011 09:20 AM (UTC) by Blixel

Message
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
[Go to top] top

Posted by Blixel   (80 posts)  [Biography] bio
Date Reply #36 on Wed 21 Sep 2011 03:25 PM (UTC)
Message
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.
[Go to top] top

Posted by Nick Gammon   Australia  (23,000 posts)  [Biography] bio   Forum Administrator
Date Reply #37 on Thu 22 Sep 2011 03:12 AM (UTC)
Message
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.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Blixel   (80 posts)  [Biography] bio
Date Reply #38 on Thu 22 Sep 2011 07:22 AM (UTC)
Message
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



[Go to top] top

Posted by Nick Gammon   Australia  (23,000 posts)  [Biography] bio   Forum Administrator
Date Reply #39 on Thu 22 Sep 2011 08:30 AM (UTC)
Message
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?

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (23,000 posts)  [Biography] bio   Forum Administrator
Date Reply #40 on Thu 22 Sep 2011 08:32 AM (UTC)
Message
Quote:

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


or "mobillengine"? You have to get the spelling right.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (23,000 posts)  [Biography] bio   Forum Administrator
Date Reply #41 on Thu 22 Sep 2011 08:33 AM (UTC)
Message
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.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Blixel   (80 posts)  [Biography] bio
Date Reply #42 on Thu 22 Sep 2011 09:17 AM (UTC)

Amended on Thu 22 Sep 2011 09:27 AM (UTC) by Blixel

Message
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

[Go to top] top

Posted by Nick Gammon   Australia  (23,000 posts)  [Biography] bio   Forum Administrator
Date Reply #43 on Thu 22 Sep 2011 10:41 PM (UTC)
Message
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.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Blixel   (80 posts)  [Biography] bio
Date Reply #44 on Sat 24 Sep 2011 01:19 AM (UTC)

Amended on Sat 24 Sep 2011 01:20 AM (UTC) by Blixel

Message
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.

[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


102,212 views.

This is page 3, subject is 4 pages long:  [Previous page]  1  2  3 4  [Next page]

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at HostDash]