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.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ MUSHclient ➜ Tips and tricks ➜ Multiline triggers

Multiline triggers

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


Posted by Ked   Russia  (524 posts)  Bio
Date Mon 29 Dec 2003 02:14 AM (UTC)
Message
It is often very useful to be able to match a trigger on more than 1 line. Although Mushclient lacks this ability, it can be mimicked with scripting. I remember another post on this matter before, what this one aims at is to provide a more or less generalized way of simulating multiline triggers in Mushclient using vbs scripting. I haven't done too much testing on this, and I can see quite a few messy points in it, but it seems to work and to provide a way of matching several lines of text. That's all I wanted from it. Any input on it is very much welcome, as I'd love to have some simple and reliable function I could call to quickly check up on a few lines of output.

This particular function accepts 2 arguments: first is a number of lines you want to look back (actually that's minus 1 - if you want to match 2 lines prior to the most recent one you need to send 1 to the function as its' first argument, that's screwed up but simplifies things inside the function somewhat), second is an array of trigger names (read below). Obviously, trigger names must come in a reverse order - first the one for the most recent line - 1, then for the most recent line - 2, etc.

The function uses a dictionary in which the keys are used as "trigger labels" and items as "trigger match text". That's done to achieve the closest possible resemblance to how it works in Mushclient. If you are only using the function, then you don't need to bother figuring out how exactly this dictionary works, you only need to know what key-item pairs are in it. For an example of how those pairs are added look in the beginning of the script below.

Once again, I'd appreciate any input on any parts of this or the whole thing. Thanks in advance



option explicit

'This is a dictionary of "internal triggers" - keys are used as trigger names
'and items are trigger match strings in regexp
'
dim triggsDict
set triggsDict = CreateObject("Scripting.Dictionary")
triggsDict.Add "raze", "^(?:\d+h, \d+m \D*-|)\D+ razes your aura of weapons rebounding\."
triggsDict.Add "slash", "^(?:\d+h, \d+m \D*-|)\D+ slashes into you with a steel shortsword\."


'This is the function. It can return one of 3 values: 1, 2, and 3. Since I didn't feel like
'messing with exceptions, return value of 3 means that you've supplied an invalid
'trigger name (a triggsDict key), and that's as far as error-checking goes in this one.
'Value of 1 means that all the triggers have successfuly matched, 2 - one or more 
'didn't match. I only tested this with 2 preceding triggers and wasn't very thorough
'with it either, so you might want to do your own testing before putting this to use
'anywhere.
'
function LookBack (numberOfLines, triggers)
 dim i, regEx, line, lineCount, lineText, Match, Matches, result, trigNum
 Redim result(numberOfLines)

 for i = 0 to ubound(result)
  result(i) = 0
 next

 lineCount = world.GetLinesInBufferCount
 trigNum = 0
 for i = 0 to ubound(triggers)
  if not triggsDict.Exists(triggers(i)) then
   world.Note "Internal trigger not found: " & triggers(i) & ". Exiting function LookBack."
   LookBack = 3
   exit function
  end if
 next

 for i = 0 to numberOfLines

  if i then
   if result(i - 1) = 0 then
    LookBack = 2
    exit function
   end if
   line = line - 1
  else
   line = lineCount - 1
  end if

  do while world.GetLineInfo (line, 4)
   line = line - 1
  loop


  set regEx = new RegExp
  regEx.Pattern = triggsDict.Item(triggers(trigNum))
  trigNum = trigNum + 1
  lineText = world.GetLineInfo(line, 1)
  set Matches = regEx.Execute(lineText)
  for each Match in Matches
   result(i) = 1
  next
 world.note result(i)
 next 

 for i = 0 to ubound(result)
  if result(i) <> 1 then
   LookBack = 2
  end if
 next
 LookBack = 1
 
end function


'This is a test sub I used
'
sub TestTriggs(name, output, wildcs)
 dim trigs
 trigs = Array("slash", "raze")
 if LookBack(1, trigs) = 1 then
  world.Note "found"
 else
  world.Note "not found"
 end if
end sub
Top

Posted by Gore   (207 posts)  Bio
Date Reply #1 on Wed 07 Apr 2004 11:42 AM (UTC)
Message
Damn Ked, this sounds amazing, I don't really understand it too well, how would you call it? How would you trigger it? I've been trying to figure out a way to do this on mushclient, for anti-illusion. For zmud, I'd just do like..

^You eat a piece of ginseng$*h, *m *-

Any ideas?
Top

Posted by Ked   Russia  (524 posts)  Bio
Date Reply #2 on Wed 07 Apr 2004 01:48 PM (UTC)

Amended on Wed 07 Apr 2004 01:50 PM (UTC) by Ked

Message
To use this you'll need to first amend the LookBack function. This was done a fairly long time ago, and back then I didn't know that vbscript had a very special way of dealing with return values - assigning a return value to the function name doesn't exit the function but keeps it running, what a wonderfully colourful world Microsoft developers must be living in! So here's the amended version of the LookBack function:


function LookBack (numberOfLines, triggers)
 dim i, regEx, line, lineCount, lineText, Match, Matches, result, trigNum
 Redim result(numberOfLines)

 for i = 0 to ubound(result)
  result(i) = 0
 next

 lineCount = world.GetLinesInBufferCount
 trigNum = 0
 for i = 0 to ubound(triggers)
  if not triggsDict.Exists(triggers(i)) then
   world.Note "Internal trigger not found: " & triggers(i) & ". Exiting function LookBack."
   LookBack = 3
   exit function
  end if
 next

 for i = 0 to numberOfLines

  if i then
   if result(i - 1) = 0 then
    LookBack = 2
    exit function
   end if
   line = line - 1
  else
   line = lineCount - 1
  end if

  do while world.GetLineInfo (line, 4)
   line = line - 1
  loop


  set regEx = new RegExp
  regEx.Pattern = triggsDict.Item(triggers(trigNum))
  trigNum = trigNum + 1
  lineText = world.GetLineInfo(line, 1)
  set Matches = regEx.Execute(lineText)
  for each Match in Matches
   result(i) = 1
  next
 world.note result(i)
 next 

 for i = 0 to ubound(result)
  if result(i) <> 1 then
   LookBack = 2
   exit function
  end if
 next
 LookBack = 1
 
end function


That'll make sure that the function exits with the correct return code (2) if one or more of the triggers didn't match. It works quite simply - you pass a number of lines you want the function to look at and an array of triggers that you want it to match against those lines. The number of lines must be equal to the number of lines you want to check beyond the currently displayed one, so if you were to pass 1 as a number of lines, the function will check the most recent line in the buffer + 1 line before that (skipping notes and echos). The triggers array should include trigger names (more on that later) in the order in which you want them to match - 1st name will be matched on the most recent line, 2nd - the one before the most recent one, and so on. The function will then:

1. Get the most recently received line of text from the buffer
2. Match that line against a trigger whos name comes up first in the names array you've passed into the function. If the trigger matches, LookBack ammends its internal state to reflect that
3. Get the line which precedes the one parsed last
4. Match that line against the trigger with the name coming next in the passed array. Record result internally.
... Process more lines until the count of lines processed reaches the limit that was specified when calling the function.
5. Figure out if all processed line were successfully matched by respective triggers. If yes - return 1, if one or more lines didn't match - return 2. 3 is return if one of the trigger names wasn't found in the trigger dictionary.

Now on to the triggers. These are saved in the triggsDict dictionary in the beginning of the script in the first post. Triggers are in standard regexp syntax, which is pretty much exactly the same as what is used in Mushclient, so in 90% of the cases you can just copy the match texts from Mushclient triggers here (as long as they are regexps).

To add a trigger you need to specify its name and the match string:


triggsDict.Add "raze", "^(?:\d+h, \d+m \D*-|)\D+ razes your aura of weapons rebounding\."


Where "raze" is the name and the second argument is obviously the match expression. To use this function to match on the following exact combination of lines:


Joe arrives.
Joe sinks back into the stance of the Scorpion.
Joe unleashes a powerful upperhook at you.
He connects to the torso.


you would need to add the following triggers to the dict:


triggsDict.Add "arrival", "^.*? arrives\.$"
triggsDict.Add "scorpion_stance", "^.*? sinks back into the stance of the Scorpion\.$"
triggsDict.Add "upperhook", "^.*? unleashes a powerful upperhook at you\.$"
triggsDict.Add "torso_connect", "^.*? connects to the torso\.$"


then make a trigger in Mushclient to match on the "He connects to the torso." line, have it send to scripting and put this in the Send box (presuming the triggsDict and LookBack function are both in your main script file or in the plugin where you add the trigger):


tmp_array = Array("torso_connect", "upperhook", "scorpion_stance", "arrival")
if LookBack(3, tmp_array) = 1 then
 world.Note "Some monk just punched me in the gut!"
end if


However, to do what you seem to want it would probably be easier to use 'cascading triggers', discussed extensively or mentioned with examples in a large number of other threads. This method becomes useful when, for example, you need to match on 2 lines and the 2nd can be one of a multitude of possibilities, while the 1st stays the same or the possible candidates are few. Then it makes more sense to just look back from the 2nd line to check if it was preceeded by this certain line or not, then to bundle all the possibile candidates for the 2nd line in a group and disable/enable this group.
Top

Posted by Gore   (207 posts)  Bio
Date Reply #3 on Wed 07 Apr 2004 05:45 PM (UTC)
Message
I only found one post in reference to cascading triggers.. do you mean where I have a starting trigger that matches on:

^You eat a piece of ginseng\.$

that enables another trigger that matches:

^*h, *m *-$

?

I'm not exactly sure how I could use this for my anti-illusion. Also, it sounds like I'd have to make a -lot- of triggers for that...

Do you know how fast your lookback function would be if I did my sorta anti-illusion with it?
Top

Posted by Ked   Russia  (524 posts)  Bio
Date Reply #4 on Wed 07 Apr 2004 06:34 PM (UTC)
Message
It would be fast enough. Generally, the most overhead is generated not by scripts but by triggers that drive them, so you don't have to worry about scripts slowing you down by much.
Top

Posted by Gore   (207 posts)  Bio
Date Reply #5 on Thu 08 Apr 2004 05:52 AM (UTC)
Message
Hmm, I seem to be having a problem with your script.. I mainly just copied and pasted it, with the following triggers:

dim triggsDict
set triggsDict = CreateObject("Scripting.Dictionary")
triggsDict.Add "prompt", "^(.*?)h\, (.*?)m (.*?)-$"
triggsDict.Add "illusion", "^\*\* Illusion \*\*$"
triggsDict.Add "rightleg", "^Your right leg is greatly damaged from the beating\.$"
triggsDict.Add "leftleg", "^Your left leg is greatly damaged from the beating\.$"
triggsDict.Add "ok", "^Test$"

<triggers>
  <trigger
   enabled="y"
   match="^\*\* Illusion \*\*$"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>tmp_array = Array(&quot;illusion&quot;, &quot;ok&quot;, &quot;prompt&quot;)
if LookBack(3, tmp_array) = 1 then
 world.Note &quot;ANTI-ILLSUION BABY-&quot;
end if
</send>
  </trigger>
</triggers>


And here's the output from the mud..


2222h, 2594m ex-
Test
** Illusion **
0


2222h, 2594m ex-
** Illusion **
0
Test
** Illusion **
0

the 0's are outputted after the RegEx in your function. Could you help me with this?
Top

Posted by Ked   Russia  (524 posts)  Bio
Date Reply #6 on Thu 08 Apr 2004 08:54 AM (UTC)
Message
Ack, yes - seems like a world.note used for testing was left over in there. Here it is again, without it:


function LookBack (numberOfLines, triggers)
 dim i, regEx, line, lineCount, lineText, Match, Matches, result, trigNum
 Redim result(numberOfLines)

 for i = 0 to ubound(result)
  result(i) = 0
 next

 lineCount = world.GetLinesInBufferCount
 trigNum = 0
 for i = 0 to ubound(triggers)
  if not triggsDict.Exists(triggers(i)) then
   world.Note "Internal trigger not found: " & triggers(i) & ". Exiting function LookBack."
   LookBack = 3
   exit function
  end if
 next

 for i = 0 to numberOfLines

  if i then
   if result(i - 1) = 0 then
    LookBack = 2
    exit function
   end if
   line = line - 1
  else
   line = lineCount - 1
  end if

  do while world.GetLineInfo (line, 4)
   line = line - 1
  loop


  set regEx = new RegExp
  regEx.Pattern = triggsDict.Item(triggers(trigNum))
  trigNum = trigNum + 1
  lineText = world.GetLineInfo(line, 1)
  set Matches = regEx.Execute(lineText)
  for each Match in Matches
   result(i) = 1
  next
 next 

 for i = 0 to ubound(result)
  if result(i) <> 1 then
   LookBack = 2
   exit function
  end if
 next
 LookBack = 1
 
end function
Top

Posted by Gore   (207 posts)  Bio
Date Reply #7 on Thu 08 Apr 2004 04:06 PM (UTC)
Message
rofl, I was going to remove it myself once I understand and know your script, but that wasn't the point at -all-, the point was, that something isn't working, but I'm not exactly sure why.
Top

Posted by Gore   (207 posts)  Bio
Date Reply #8 on Thu 08 Apr 2004 04:09 PM (UTC)
Message
My apologies, I didn't explain the problem clearly enough, for your script, my output should be something like.. for this example


2222h, 2594m ex-
Test
** Illusion **
0
ANTI-ILLUSION, BABY

because if the Lookback function works, it Note's anti-illusion, baby


Top

Posted by Ked   Russia  (524 posts)  Bio
Date Reply #9 on Thu 08 Apr 2004 05:38 PM (UTC)
Message
Then the problem might be with how you call the function - you ask it to check 4 lines and provide only 3 triggers. When you say:

Lookback(3,...


it actually means "check the last line plus the 3 that came before it". So if you wanted to check exactly 3 lines, which seems to be what you want to do, you'd need to pass 2 as the first argument, not 3. It might seem kind of wierd, but on the other hand - it's perfectly consistent with the backwardness of the function itself :) Or you could just include an instruction in the function's body to decrease the value of the first argument by 1 and then do it the sane way - 3 means 3 lines and not 4.
Top

Posted by Gore   (207 posts)  Bio
Date Reply #10 on Thu 08 Apr 2004 06:52 PM (UTC)
Message
Ah damn it.. so you need to have it -exactly- how many lines you need to look back? Hm because the output could be like

Prompt
** Illusion **
IllusionLine1
IllusionLine2
** Illusion ** <-- the one I'm triggering
Prompt

Prompt
IllusionLine1
IllusionLine2
** Illusion ** <-- the one I'm triggering
Prompt

I'll fiddle with it, and post my code so you can check it out :p
Top

Posted by Gore   (207 posts)  Bio
Date Reply #11 on Thu 08 Apr 2004 07:01 PM (UTC)
Message
Ok, I -finally- found the problem

dim triggsDict
set triggsDict = CreateObject("Scripting.Dictionary")
triggsDict.Add "prompt", "^(?:\d+h, \d+m \D*-|)"
triggsDict.Add "illusion", "^\*\* Illusion \*\*$"
triggsDict.Add "test", "^Test$"

2222h, 2915m exk-
0
Test
** Illusion **

I had ^\*\* Illusion \*\*$ triggered to 

tmp_array = Array("illusion", "test", "prompt")
if LookBack(3, tmp_array) = 1 then
 world.Note "ANTI-ILLSUION BABY-"
end if

Where I should have had it set for

tmp_array = Array("test", "prompt")
if LookBack(1, tmp_array) = 1 then
 world.Note "ANTI-ILLSUION BABY-"
end if

So I thought I had to add the trigger that I'm trigger the thing from in my tmp_array :p
Top

Posted by Ked   Russia  (524 posts)  Bio
Date Reply #12 on Thu 08 Apr 2004 07:50 PM (UTC)
Message
Yes, this is meant to do just a predefined number of lines, in which sense it is quite static. That's the main reason for why I never really used it myself - the one I use is more dynamic and can check for varying number of lines. That one is in essence an anti-illusion technique. LookBack isn't very well fitted to being used for that purpose, but it's based on the same principle and if you tweak it enough you can get it to work. I am not giving out what I actually use for a very simple reason - this kind of stuff is regarded as high level in the game we both play and thus should be a personal challenge, but you found a hint :P
Top

Posted by Gore   (207 posts)  Bio
Date Reply #13 on Thu 08 Apr 2004 09:23 PM (UTC)
Message
Yes, I definately understand, and trust me, I definately appreciate your help -g- Anychance we could get together and spar sometime?
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.


34,337 views.

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.