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?
|
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
It is now over 60 days since the last post. This thread is closed.
Refresh page
top