Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ MUSHclient ➜ Lua ➜ Trigger text is on 2 or more lines

Trigger text is on 2 or more lines

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


Pages: 1 2  

Posted by Blixel   (80 posts)  Bio
Date Thu 15 Sep 2011 03:26 PM (UTC)
Message
I have another question open in a different thread, but I have another question, so I'm starting this new thread.

I have a trigger that looks for a "corpse" on the ground, and if it sees one, it will send "search corpse" to world. It works really well except for one problem. Sometimes, the list of items on the ground wraps around to the next line. Here's an example:

There is a hammer, a greatsword, a pair of gloves, a rock, a pearl, a stone,
a foil, a corpse, and a corpse here.
>


The trigger text I'm using now is "^There is (.*?)corpse(.*?)"

That triggers the search corpse call in most cases, but not here due to the fact that "There is" is on the line above.

So how do I get all that text evaluated as one string?
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #1 on Thu 15 Sep 2011 09:33 PM (UTC)
Message
Can you turn off this wrapping MUD-side (eg. config linewidth 0)?

Failing that, the trigger that matches "There is ..." could check in it script if it ends with the word "here.".

If not, it enables another "catch-all" trigger that catches subsequent lines (this is normally disabled). This catch-all trigger grabs the other items until it finds "... here.". Then it disables itself.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Blixel   (80 posts)  Bio
Date Reply #2 on Fri 16 Sep 2011 07:28 PM (UTC)
Message
Nick Gammon said:

Can you turn off this wrapping MUD-side (eg. config linewidth 0)?


There's no way to control anything MUD-side that I know of. This MUD comes from the days of 2400 bps modems as the standard. (And some people still using 1200 or even 300.) So everything is pretty much 80 columns and 25 rows.


Nick Gammon said:
Failing that, the trigger that matches "There is ..." could check in it script if it ends with the word "here.".

If not, it enables another "catch-all" trigger that catches subsequent lines (this is normally disabled). This catch-all trigger grabs the other items until it finds "... here.". Then it disables itself.


I think you are saying the same kind of thing I was thinking about. My thinking was to look for the starting and closing text ... and then "patch together" everything in between. If that is the right way to go about it, then my question would be as to how to actually go about the process of patching multiple lines together.

This issue comes up in at least two different situations. One situation is when I'm looking at the items laying on the ground in a room. The other situation is when I'm looking at my own inventory.

Take the following inventory as an example:

>inv


You are carrying a mace, some platemail, a gold-ring, a jade-ring, a
glass-ring, a brass-ring, a flask, a flask, a flask, a flask, a flask, a flask,
a flask, a flask, a flask, your spellbook and 44891 gold pieces.


Something I really need to figure out is how to count the number of flasks I have so that when I'm running low, I can put up a ColourNote warning and/or automatically disable autokilling.

If I understand the regular expression syntax for this (doubtful), the starter syntax would be something like this:

^You are carrying *

and the closing syntax would be

* gold pieces\.$

But what I don't really know how to do is to say:

Send ("inventory")
some.string.match.function ("^You are carrying *" && "* gold pieces\.$")
invlist = some.string.combinelines.function (everything in between match)

Then I could say:

for invitem in string.gmatch (invlist, "%a+") do
if (invitem == "a flask") then
flaskcount = ++flaskcount ;
end
done

Then, knowing the flaskcount, I can use that as needed.

The same logic would apply for counting corpses in the room.

Top

Posted by Blixel   (80 posts)  Bio
Date Reply #3 on Fri 16 Sep 2011 10:41 PM (UTC)
Message
I've been working on this for a little while here, and I came up with something that seems to work. It's so "ugly" I can't believe it works. Surely there is a more elegant way to do this:

Here's my input:

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


My "countflasks" alias returns: 7

Which is exactly what I want.

But here is the God-awful mess that calculates the flasks.

require "wait"

flasks = 0
invlist1 = nil
invlist2 = nil
invlist3 = nil
invlist4 = nil

wait.make (function ()
  Send ("inventory")
  invlist1 = wait.regexp ("^You are carrying *",1)
  if (invlist1) then
    invlist2 = wait.regexp ("^(.*?)$", 1)

    -- I know this next line is WRONG
    -- this will never match what I want
    if not (invlist2 == "* gold pieces\.$") then
      invlist3 = wait.regexp ("^(.*?)$", 1)

      -- I know this next line is WRONG
      -- this will never match what I want
      if not (invlist3 == "* gold pieces\.$") then

        -- 4 lines of inventory should do it.
        -- We are limited to the number of items
        -- we can carry.
        invlist4 = wait.regexp ("^(.*?)$", 1)
      end
    end
  else

    -- This should never happen.
    Note ("Failed to acquire inventory list")
  end

  if (invlist1) then
    for k, v in ipairs (utils.split (invlist1, ",")) do
      if (Trim (v) == "flask") or (Trim (v) == "a flask") then
        flasks = flasks +1
      end
    end
    if (invlist2) then
      for k, v in ipairs (utils.split (invlist2, ",")) do
        if (Trim (v) == "flask") or (Trim (v) == "a flask") then
          flasks = flasks +1
        end
      end
      if (invlist3) then
        for k, v in ipairs (utils.split (invlist3, ",")) do
          if (Trim (v) == "flask") or (Trim (v) == "a flask") then
            flasks = flasks +1
          end
        end
        if (invlist4) then
          for k, v in ipairs (utils.split (invlist4, ",")) do
            if (Trim (v) == "flask") or (Trim (v) == "a flask") then
              flasks = flasks +1
            end
          end
        end
      end
    end
  end
  Note (flasks)
end)

Top

Posted by Ada   (20 posts)  Bio
Date Reply #4 on Fri 16 Sep 2011 10:45 PM (UTC)
Message
Lets say you want to capture,

Quote:

You are carrying a mace, some platemail, a gold-ring, a jade-ring, a
glass-ring, a brass-ring, a flask, a flask, a flask, a flask, a flask, a flask,
a flask, a flask, a flask, your spellbook and 44891 gold pieces.


The following trigger set should help:


<triggers>
  <trigger
   group="Inventory"
   keep_evaluating="y"
   match="^(.+)"
   name="InvFull"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>myinv = myinv .. "%0"
if string.sub(myinv, string.len(myinv) - 11, string.len(myinv)) == "gold pieces." then
  EnableTrigger("InvFull", false)
end</send>
  </trigger>
  <trigger
   enabled="y"
   group="Inventory"
   keep_evaluating="y"
   match="^You are carrying (.+)"
   name="InvStart"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>myinv = "%0"
EnableTrigger("InvFull", true)</send>
  </trigger>
</triggers>


The InvStart trigger looks for "You are carrying...", assigns the full line to the variable myinv and enables the trigger InvFull. The InvFull trigger is a catchall trigger and it'll keep adding every subsequent line to the variable myinv till the end of that variable is "gold pieces.". That's when it disables itself and you're left with myinv holding a single line of your entire inventory.

Hope that helps!
Top

Posted by Ada   (20 posts)  Bio
Date Reply #5 on Fri 16 Sep 2011 10:51 PM (UTC)
Message
Ohh, once you have the entire inventory in one line you can do something like:


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

Note("No. of flasks : " .. count)


.. to count the number of flasks you have. ^_^
Top

Posted by Blixel   (80 posts)  Bio
Date Reply #6 on Sat 17 Sep 2011 09:20 AM (UTC)
Message
Thanks Ada - that's awesome.

That's a far more elegant solution! I have a reasonable understanding of what those string functions are doing. I use to dabble with Python and came across quite a bit of string parsing stuff.

A couple of things about this solution though. The first time I use it after logging in, I always get this:

Welcome back, Trimaster, to the Vale of Grimyre!
>
Run-time error
World: Cleric
Immediate execution
[string "Alias: "]:4: bad argument #1 to 'gmatch' (string expected, got nil)
stack traceback:
        [C]: in function 'gmatch'
        [string "Alias: "]:4: in main chunk
inventory


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


At first I thought I didn't have it set up right, but when I run the command a second time, it seems to be working. So it's like something isn't being initialized. Or more likely, there is a sequence problem. Because when I drink a flask and run the routine again, it will still say I have 7 flasks. (Should be 6.)

When I run it again, it counts 6.

If I drink a flask (bringing me down to 5), it will still say I have 6. But when I run it again, then it has the count right.

I suspect this is the problem: (string expected, got nil)

The first time I run it, it has nil as the value. So there is some kind of sequence problem.

Here is the alias I made. I call it "countflasks" (with a cf alias for a shortcut)

  <alias
   match="cf"
   enabled="y"
   group="Shortcuts"
   send_to="10"
   sequence="100"
  >
  <send>countflasks</send>
  </alias>
  <alias
   match="countflasks"
   enabled="y"
   group="Misc. Routines"
   send_to="12"
   sequence="100"
  >
  <send>Send ("inventory")

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

Note("No. of flasks : " .. count)</send>
  </alias>




Top

Posted by Ada   (20 posts)  Bio
Date Reply #7 on Sat 17 Sep 2011 01:50 PM (UTC)

Amended on Sat 17 Sep 2011 02:06 PM (UTC) by Ada

Message
Erm.. in your alias,

Send ("inventory")

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

Note("No. of flasks : " .. count


.. you're doing the math right after sending the command, you have to actually wait a little and let it receive some data before you proceed with working on it. That's why when you hit the alias the first time you get the 'string expected' error followed by your actual inventory showing. After that, when you hit the alias again it still doesn't have nothing to work with but now it has the old data captured by the actions of the previous alias (thus no error but now we have the sequence problem because it's working on old data) heh. I'd recommend simply moving the flask counting bits to where you see the end of your inventory and where you disable the catchall alias. That would save you the trouble of using wait() or something like that since you've essentially chained the sequence of events as they occur. So to paste corrections:

<triggers>
  <trigger
   group="Inventory"
   keep_evaluating="y"
   match="^(.+)"
   name="InvFull"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>myinv = myinv .. "%0"
if string.sub(myinv, string.len(myinv) - 11, string.len(myinv)) == "gold pieces." then
  EnableTrigger("InvFull", false)
  local flaskcount = 0
  for word in string.gmatch(myinv, "flask") do
    flaskcount = flaskcount + 1
  end
  Note("No. of flasks : " .. flaskcount)
end</send>
  </trigger>
  <trigger
   enabled="y"
   group="Inventory"
   keep_evaluating="y"
   match="^You are carrying (.+)"
   name="InvStart"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>myinv = "%0"
EnableTrigger("InvFull", true)</send>
  </trigger>
</triggers>


..and the alias(es) become:

</aliases>
  <alias
   match="cf"
   enabled="y"
   group="Shortcuts"
   send_to="10"
   sequence="100"
  >
  <send>countflasks</send>
  </alias>
  <alias
   match="countflasks"
   enabled="y"
   group="Misc. Routines"
   send_to="12"
   sequence="100"
  >
  <send>Send ("inventory")</send>
  </alias>
</aliases>


P.S. How can I preview what I'm about to post here anyway? :/
Top

Posted by Blixel   (80 posts)  Bio
Date Reply #8 on Sat 17 Sep 2011 11:54 PM (UTC)
Message
Ah ... perfect. Thanks. It works great now. That makes sense about not adding a wait statement. I have several triggers/aliases that have wait statements, and it feels a bit crude. If there is any lag, the wait timer isn't going to work. I'll have to work on some of my other triggers/aliases to try to eliminate that waiting.

I made one small change to your set up. I have the countflasks alias turn on InvStart, and then I have InvFull shut it off the same time it shuts off itself.

That way when I do a regular "inv", it doesn't trigger the countflasks stuff.

Thanks a lot. This was a really big help. There are a couple of other things I need to do that require this exact same logic. (Looking at the items on the floor of a room as an example. The item list wraps around to the next line. So it is essentially the same thing as doing an inventory check on the room.)

P.S. I don't know how to preview my posts either.
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #9 on Sun 18 Sep 2011 12:43 AM (UTC)
Message
Blixel said:
P.S. I don't know how to preview my posts either.

Not sure you can. I just edit quickly if something's amiss. :P

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Blixel   (80 posts)  Bio
Date Reply #10 on Sun 18 Sep 2011 02:38 AM (UTC)

Amended on Sun 18 Sep 2011 02:52 AM (UTC) by Blixel

Message
Quick question.

How do I make the flaskcount variable available outside of the trigger that created it?

I thought the Expand variables checkbox might do it, but that doesn't seem to work.

I created an alias called FlaskEmergencyCheck. Here is how I'm trying to use the flaskcount variable outside of the trigger that created it.

Execute ("countflasks")
if (flaskcount == 0) then

  -- give up the fight
  giveup = true

  -- use Teleportation key to teleport to a safe place
  Send ("rub key")

  -- make sure our key didn't fail.
  EnableTrigger("TeleportSafetyCheck", true)
elseif (flaskcount == 1) then
  ColourNote ("white", "red", "==========================")
  ColourNote ("white", "red", "WARNING: 1 Flask Remaining")
  ColourNote ("white", "red", "==========================")
end


P.S. I also have a very basic regular expression question. I'm sorry I don't understand this stuff better, but I'm learning.

It is often the case that when drinking a flask (or doing other things) the game will output one or the other of the following:

You don't have one!
>You don't have one!


The only difference is that leading ">"

It should be trivial to make a regular expression that catches both, but the only way I can get it to work consistently is this:

^You don\'t have one\!$|^\>You don\'t have one\!$


I've tried things like this:

^(.*?)You don\'t have one\!$


But it consistently fails to catch one or the other. I'm not sure how to make that first ">" an optional requirement.
Top

Posted by Ada   (20 posts)  Bio
Date Reply #11 on Sun 18 Sep 2011 03:18 AM (UTC)

Amended on Sun 18 Sep 2011 03:28 AM (UTC) by Ada

Message
Blixel said:
How do I make the flaskcount variable available outside of the trigger that created it?


Remove the local keyword from before the variable, that would make it available everywhere.

Blixel said:
You don't have one!
>You don't have one!


The following regular expression should work:

^(\>)?You don\'t have one\!$


Adding a ? after a capture group () makes it optional. Have a look at http://regexpal.com/ for more simple help on this stuff.

Ohh, in your FlaskEmergencyCheck alias you're sending a command to the game and doing the math in the same place again. Computers are fast, networks are slow and your if/then code would execute -before- any data has arrived as a result of the command sent above it. It might be a better option to trigger "You sip from a flask." or whatever line you get when you use up a flask to do flaskcount - 1 and in that trigger check if flaskcount is too low and issue a warning if it is. Hope my engrish makes sense! :)
Top

Posted by Blixel   (80 posts)  Bio
Date Reply #12 on Sun 18 Sep 2011 04:14 AM (UTC)
Message
Ada said:
Remove the local keyword from before the variable, that would make it available everywhere.


Ah, yes - that does work. Thanks again. But it raises another question. (Which I see you already anticipated based on your response at the bottom.)

Also, I found that in some cases, my inventory will be such that "gold pieces." does a line wrap. Arg. So the only bit of text I can absolutely rely on is "pieces." I wish I had more than that, but I suppose it all happens so quickly there isn't any chance of other text showing up first. I changed the relevant bit to this:

if string.sub(myinv, string.len(myinv) - 6, string.len(myinv)) == "pieces." then




Ada said:
The following regular expression should work:

^(\>)?You don\'t have one\!$


Adding a ? after a capture group () makes it optional. Have a look at http://regexpal.com/ for more simple help on this stuff.


Thanks. I will try this out and check out that link. I did a google search and ran into http://www.regular-expressions.info/ ... but it wasn't really that helpful to me.


Ada said:
Ohh, in your FlaskEmergencyCheck alias you're sending a command to the game and doing the math in the same place again.


Yes - you are right. I noticed this problem almost immediately. To work around it, I added another trigger in the middle. (Which I think is what you were getting at.)

The trigger in the middle is called FlaskEmergency. It is triggered by the response to drinking a flask. "You are healed!" and it does this:

EnableTrigger("FlaskEmergency", false)
Execute ("countflasks")
EnableTrigger("FlaskEmergencyCount", true)


So we drank the flask by the time we got to this point. So now we are counting the flasks, and turning on the FlaskEmergencyCount trigger which will look for "pieces\.$"

And that trigger will do this:

EnableTrigger("FlaskEmergencyCount", false)
if (flaskcount == 0) then
  giveup = true
  Send ("rub key")
  EnableTrigger("TeleportSafetyCheck", true)
elseif (flaskcount == 1) then
  ColourNote ("white", "red", "==========================")
  ColourNote ("white", "red", "WARNING: 1 Flask Remaining")
  ColourNote ("white", "red", "==========================")
end


Feels like a long way around ... but I understand why it's necessary to do it like this. My only concern is that my trigger text will prove to be too vague in some cases. Hmmm... I wonder if the trigger text could look for "^You are carrying" AND "pieces\.$" before it would act.



Ada said:
Hope my engrish makes sense! :)


Perfect English. Far better than a lot of native English speaking people I know.
Top

Posted by Blixel   (80 posts)  Bio
Date Reply #13 on Sun 18 Sep 2011 06:26 AM (UTC)

Amended on Sun 18 Sep 2011 06:31 AM (UTC) by Blixel

Message
Ada said:
Blixel said:
You don't have one!
>You don't have one!


The following regular expression should work:

^(\>)?You don\'t have one\!$


Oddly, when I add that, I get a compile error. (Though, when I check the site you referenced, it seems to say it should work.) But here's what MUSHclient is putting up as an error:

You are standing at the foot of a rope ladder. A rune for shelter is carved on
the wall beneath an arrow pointing up.

[][]    [][]
[]  M     []
[]   up   []
[]   x    []
[]     $  []  
[][]    [][]

M - ogre

>hit ogre
You missed!
>The ogre hits you for 4 hps!
>health

You have 90/96 hitpoints and 38/38 spellpoints.
Compile error
World: Cleric
Immediate execution
[string "Trigger: "]:1: unexpected symbol near '<'
You are middle-aged.
You will need to eat within 58 minutes.
>hit ogre
Swing hits with light damage!
>The ogre hits you for 4 hps!
>health

You have 86/96 hitpoints and 38/38 spellpoints.
Compile error
World: Cleric
Immediate execution
[string "Trigger: "]:1: unexpected symbol near '<'


The line that says "The ogre hits you for 4 hps!" is a trigger itself. That trigger has been working for a long time for me.

^The (.*?) hits you for (.*?) hps\!$|^>The (.*?) hits you for (.*?) hps\!$


that triggers a health check. Simply: "health" is sent to world.

That makes it look for this text:

^(\>)?You have (.*?)\/(.*?) hitpoints(.*?)$


And that seems to be where it's bombing because when I restore that trigger to this:

^You have (.*?)\/(.*?) hitpoints(.*?)$|^>You have (.*?)\/(.*?) hitpoints(.*?)$


It works again.

Pretty weird.
Top

Posted by Ada   (20 posts)  Bio
Date Reply #14 on Sun 18 Sep 2011 07:04 AM (UTC)
Message
A trigger either matches or not matches. The compile error you're getting means it -is- matching in both cases but the associated script is not in working order. Can you paste the triggers and the text they're supposed to match here please?

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.


Also, what does sending 'health' to the game do? Is that an alias or a game command?
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.


59,967 views.

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

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

Go to topic:           Search the forum


[Go to top] top

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