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 ➜ General ➜ Triggers across lines

Triggers across lines

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


Pages: 1 2  3  4  

Posted by Zendu   (66 posts)  Bio
Date Tue 20 Apr 2004 06:58 PM (UTC)
Message
I have the text

You smile and congratulate Salazar, conferring upon him the right to wear the

red belt.

In game, and was wondering how i whould make a trigger for it? This is all i could get

^You smile and congratulate (.*?)\, conferring upon (.*?) the right to wear the \x0D\x0A(.*?) belt\.$

God im helpless
Currently using MushClient 3.46 on Win Xp pro on [url=www.aetolia.com]Aetolia[/url]
Top

Posted by Ked   Russia  (524 posts)  Bio
Date Reply #1 on Wed 21 Apr 2004 09:50 AM (UTC)

Amended on Wed 21 Apr 2004 09:51 AM (UTC) by Ked

Message
Have a trigger matching on the first line enable a trigger that's supposed to match on the second line. When the second trigger matches it should disable itself before doing anything else.
Top

Posted by Shadowfyr   USA  (1,788 posts)  Bio
Date Reply #2 on Wed 21 Apr 2004 06:23 PM (UTC)
Message
Hmm. It occures to me that you can 'fake' multiline triggering with some forethought. Basically you need:

a) main trigger.
b) pending trigger.
c) disabling the pending trigger of some different line arrives.

Imho it would be so much easier if Mushclient handled the creation of temporary triggers for multilines that either match or get deleted if no match can be found, but you can fake it:

<triggers>
  <trigger
   enabled="y"
   match="(.*?) belt\.$"
   name="Pending_belt"
   regexp="y"
   send_to="12"
   group="pending"
   sequence="0"
  >
  <send>enablescript &quot;pending_belt&quot;, 0</send>
  </trigger>
  <trigger
   enabled="y"
   match="^You smile and congratulate (.*?)\, conferring upon (.*?) the right to wear the"
   regexp="y"
   send_to="12"
   sequence="0"
  >
  <send>enabletriggergroup &quot;pending&quot;, 1</send>
  </trigger>
  <trigger
   enabled="y"
   match=".*"
   name="kill_pending"
   keep_evaluating="y"
   regexp="y"
   send_to="12"
   sequence="1"
  >
  <send>enabletriggergroup &quot;pending&quot;, 0</send>
  </trigger>
</triggers>


So, point is that if all of your triggers fail, then the last trigger disables the pending trigger. This has one 'major' flaw. If you position any trigger in between them, and one of those does not use 'keep_evaluating' then the trigger that needs to disable the one that is pending will never match and never turn off the pending trigger. This is why the sequences are set to 0 for all the multiline triggers and 1 for the one that turns them all off. You could in theory use this trick to nest dozens of lines deep, by having the second trigger enable a third, even as it disables itself, etc. until you run out of stuff to find.
Top

Posted by Ked   Russia  (524 posts)  Bio
Date Reply #3 on Wed 21 Apr 2004 07:41 PM (UTC)
Message
It would be better to keep the secondary triggers and a closing (.*) trigger in one group and disabled though. If you have several multiline triggers running at once and they are all set to the same sequences, then they can possibly interfere with each other, while if each secondary group is enabled by the openning trigger and disabled when you finish searching for a match, it is much less likely to happen.
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #4 on Thu 22 Apr 2004 07:13 AM (UTC)
Message
Perhaps it is time to revist multi-line triggers. Would anyone be interested in them? ;)

- Nick Gammon

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

Posted by Poromenos   Greece  (1,037 posts)  Bio
Date Reply #5 on Thu 22 Apr 2004 03:08 PM (UTC)
Message
Yes yes, multiline triggers please! I still don't understand why they would be that much trouble to implement... It's just two triggers in one, if the first line AND the second line matches, you trigger... Simple...

Vidi, Vici, Veni.
http://porocrom.poromenos.org/ Read it!
Top

Posted by Ked   Russia  (524 posts)  Bio
Date Reply #6 on Thu 22 Apr 2004 08:05 PM (UTC)
Message
Wasn't there a problem with lines falling out of packets or something? I am used to doing it the old-fashioned way actually, and would only be content with that changing if it wouldn't slow the client down.
Top

Posted by Shadowfyr   USA  (1,788 posts)  Bio
Date Reply #7 on Thu 22 Apr 2004 08:40 PM (UTC)
Message
Well. Lines falling out of packets may be an issue, but that is in cases where you try to match letter by letter. A system that took a trigger like:

^You have:$.*$.*$^$

in order to match:

1> You have:
2>  A floopy hat
3>  A sack of corn
4>


could be handled the way other clients do, by trying to read it all at once. *Or* you could use a special temporary trigger system:

Trigger 1: match="^You have:$" activates="Trigger 2"
Trigger 2: match=".*$" disables="Trigger 2" activates="Trigger 3"
Trigger 3: match=".*$" disables="Trigger 3" activates="Trigger 4"
Trigger 4: match="^$" disables="Trigger 4"

or at least some internal logic that does the above. There is no reason that the user needs to even be aware that each segment of the original trigger is being split up into nested triggers that will only become active if/when the first one matches. It would still work basically the same as the existing trigger system, but will automatically be terminated the moment the second pass through the trigger list is made, for the next arriving line, and it doesn't match. In effect, the moment the temporary triggers that have been nested succeed *or* fail, then disable themselves. The next trigger in the chain only gets checked on the next line 'if' the prior one in the chain did. The moment one of them doesn't, the entire chain gets disabled, except for the main trigger they are derrived from.

Of course.. *An even simpler method* would be to have a hidden 'index' in the triggers. When ever a multiple lines are detected in the trigger text, the client would automatically stop testing at the first $ it finds. The index would then be used to direct it to skip past that first $ and attempt to match the next segment when a new line arrives. Each time a segment successfully matches, the index is moved to point where the next line's trigger starts. If the match fails, the index is set back to 0. If the next index position is beyond the end of the entire match string, i.e. the entire string has been tested and the last $ isn't followed by anything, the trigger also resets the index to 0 and starts over.

Of course, for scripting it may be necessary to have a World.GetTriggerIndex ("Trigger_Name") option, so the coder can tell which set of wildcards are being returned. After all the same trigger is passing the text each time, so it will have the same name, but could have completely different wildcards. In my previous example, index 0 would return none, while index 11 and 14 would both return the entire lines, and the blank line at index 17 would also return nothing. Some triggers are bound to be far more complex, so knowing which 'section' of the trigger matched and thus what wildcards to look in for that part is very important.
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #8 on Thu 22 Apr 2004 10:13 PM (UTC)
Message
Quote:

Wasn't there a problem with lines falling out of packets or something?


No, that related to triggers matching lines before a newline was received. That has been addressed by the plugin OnPluginPartialLine callback.

I have resisted this before because I think it would be clumsy, but perhaps there is a way ...

I think what would work would be to specify a number of lines to go back, and then MUSHclient would assemble a text block consisting of "x" lines (eg. 5 lines) by working backwards through the output window, putting newlines between each line (with a linebreak) and then feed the lot into a multi-line regular expression.

Yes, it may be slower than normal triggers, but it would be optional, so it would only apply if you wanted it, and in that case would probably be *faster* than trying to do it in VBscript.

With a judicious choice of the number of lines, and the regular expression, it should be possible to match on a lot of cases (eg. multi-line room descriptions), or the case at the start of this thread, without too much trouble.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #9 on Thu 22 Apr 2004 10:19 PM (UTC)

Amended on Thu 22 Apr 2004 10:20 PM (UTC) by Nick Gammon

Message
An interesting side-issue here is what would happen with omit from output lines? Here is an example ...


The Shining Emerald
A locked display box dominates this particular shop.  Under the glass
of the box are a myriad of gems, each lying gently upon a miniscule cushion.
Hanging from the walls are various paintings, while sculptures take up the
rest of the floor space.  To the east is Darkhaven's courier, while an
opening in the tent to the north leads back out onto Market Street.

Exits: north east.
The jeweler smiles warmly.


Say you have a trigger that omits from output "Hanging from the *" (the line in bold). Then you use a multi-line trigger to match the description. Since the omitting occurred earlier (the other lines hadn't arrived yet) does the omitted line count, or not?

I think the answer is "yes" - the multi-line triggers will match what actually arrived, not what happens after other triggers get to them. I think this also simplifies the code.

- Nick Gammon

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

Posted by Shadowfyr   USA  (1,788 posts)  Bio
Date Reply #10 on Thu 22 Apr 2004 10:24 PM (UTC)
Message
Hmm. Any reason why my indexing method wouldn't work? Tracing backward takes extra time and still runs into the same issue as existing triggers, there are only so many wild cards it could return and how the heck do you deal with a situation where you need to look at the entire result of the match? By allowing the trigger to shift and index farward to the next section to match, you in effect match each line seperately and can handle those lines and wildcards in them seperately, but still use only a single trigger. What you are talking about sounds a lot more clumsy, slow and not exactly that functional.

Now my idea would require the user to 'save' wildcards themselves between matches, so that if you got two on the first line and one on the second, you could use them all together, but that is trivial imho and a lot easier that trying to make sure you don't exceed the 'per trigger' limit on wildcards.
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #11 on Thu 22 Apr 2004 10:33 PM (UTC)
Message
Er, I don't directly control the trigger match routine, that is the PCRE code which is an externally-written thing.

Thus, "stopping at a $" is not particularly easy, and indeed may not solve things like this:

^You see (.*)$^Exits lead (.*)$

The first wildcard in this example may be multiple lines - not just one. However I have to test to see if that works. :)

I think the tracing backwards can be avoided by maintaining a deque (STL double-ended queue) which is the last x lines (say, 100) which can be quickly used to build a text block of (say) 5 lines with \n between them.

- Nick Gammon

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

Posted by Shadowfyr   USA  (1,788 posts)  Bio
Date Reply #12 on Thu 22 Apr 2004 10:43 PM (UTC)
Message
Well. I am thinking in terms of adding a bit of extra logic to the triggers, something like:
if regexp = "y" then
  a = len(match)
  cmatch = right(match, a - index)
  b = instr(cmatch, "$")
  if b and b < len(cmatch) then
    regmatch = left(cmatch,b)
    index = b
  else
    regmatch = cmatch
    index = 0
  end if
  result = ParsePCRE(cmatch)
  if result then
    ... *do the stuff for a match*
  else
    index = 0
  end if
else
  ... *stuff for normal triggers*


This may add a 'tiny' bit of overhead to regular expression triggers, but it would be very minor compared the what you are thinking. Or at least I would think so.
Top

Posted by Poromenos   Greece  (1,037 posts)  Bio
Date Reply #13 on Fri 23 Apr 2004 12:17 AM (UTC)

Amended on Tue 15 Jun 2004 07:08 PM (UTC) by Poromenos

Message
About the text omitting, I would say that it should be a precedence thing, i.e. the trigger with the higher order should take precedence, but that would require a lot of extra code, so I think you would be better off just writing a rudimentary multiline trigger system for starters, which may even be adequate for everything we need. If not, you can change it later... Also, for something irrelevant, I think that MUclient versions are being released a bit slowly... How about having beta versions (i.e. v. 3.47b build whatever) which we could download and help you test. That would be like the current system where you released versions 3.46 and 3.47 on the forums, but it wouldn't change version numbers this frequently, since they would be different builds... I don't think packaging another build and uploading it is too hard to do...

Vidi, Vici, Veni.
http://porocrom.poromenos.org/ Read it!
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #14 on Fri 23 Apr 2004 01:07 AM (UTC)
Message
I don't think pulling apart the regexp at the $ signs will be a big success.

For example, here is a multi-line trigger that matches my inventory:


<triggers>
  <trigger
   enabled="y"
   lines_to_match="8"
   match="^You are carrying:$((?s)(.*))^$"
   multi_line="y"
   regexp="y"
   send_to="2"
   sequence="100"
  >
  <send>Match = %0
</send>
  </trigger>
</triggers>


The important line is the match text, which you notice contains two $ signs, however it actually matches up to 8 lines, eg.

output


You are carrying:
     a magic mushroom
     a torch
     a dragonskin
     a bag
     recall scroll


matching text



Match = You are carrying:
     a magic mushroom
     a torch
     a dragonskin
     a bag
     recall scroll


Thus %0 is a multi-line match (containing the newline character).

The (?s) is a "dot matches all" option to the regexp, which means the "." character can match newlines, which it normally doesn't.

As for release times, I should be able to release this one for testing soon.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
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.


148,875 views.

This is page 1, subject is 4 pages long: 1 2  3  4  [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.