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 ➜ General ➜ Gagging excess combat text (Multi-line trigger)

Gagging excess combat text (Multi-line trigger)

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


Posted by Tntxploshin   (4 posts)  Bio
Date Wed 02 Apr 2008 03:58 PM (UTC)
Message
First, text from the MUD:

*Sergeant Xena*'s slash >>> CASTRATES <<< Mungo! (302)
*Sergeant Xena*'s slash -*- DESOLATES -*- Mungo! (249)
*Sergeant Xena*'s slash -*- DESOLATES -*- Mungo! (298)
*Sergeant Xena*'s critical strike -=< RAVAGES >=- Mungo! (371)
*Sergeant Xena*'s critical strike -=< RAVAGES >=- Mungo! (354)
*Sergeant Xena*'s attack crashes against Mungo's shield.
*Sergeant Xena*'s life drain injures Mungo. (13)
Mungo's stab grazes *Sergeant Xena*. (
Mungo's stab grazes *Sergeant Xena*. (6)
Mungo's life drain scratches *Sergeant Xena*. (2)
Mungo's lightning bolt decimates *Sergeant Xena*. (26)
Mungo's chilling touch wounds *Sergeant Xena*. (20)
Mungo's burning hands maims *Sergeant Xena*. (34)
Captain Daikata's thwack mauls *Sergeant Xena*. (22)
Captain Daikata's thwack devastates *Sergeant Xena*. (29)
Captain Daikata's electric strike mauls *Sergeant Xena*. (22)
Captain Daikata's life drain misses *Sergeant Xena*.
Captain Daikata's critical strike DISEMBOWELS *Sergeant Xena*. (42)
Captain Daikata's thwack mauls *Sergeant Xena*. (23)
Captain Daikata's electric strike mauls *Sergeant Xena*. (22)
Captain Daikata's life drain scratches *Sergeant Xena*. (3)


That is a single round of combat, which can cause serious spam. I would like to gag all of that text, and replace it with a few single lines, like this:

Mungo damages *Sergeant Xena*. (200)
Captain Daikata damages *Sergeant Xena*. (200)
*Sergeant Xena* damages Mungo. (200)

Basically, telling attacker, target, and adding up all the numbers. The hard part is that an attacker doesn't always have the same number of attacks per round - it can vary from 1 to 7ish.

Also, there may be specific spells or attacks I might want to show in full; separate out from the main damage number.

Any pointers/code/help you all could throw my way would be great!

My initial approach would be something like this:
1. Read in combat text, attacker by attacker
2. Add up numbers for each target of the attacker
3. Display compacted combat text

Question: Would this script lag my client enough to affect performance?
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #1 on Wed 02 Apr 2008 09:52 PM (UTC)
Message
This is an interesting challenge. :)

This is my interim solution, based on your test data:


<triggers>
  <trigger
   enabled="y"


match="^(?&lt;attacker&gt;.+?)\'s .+ (&gt;&gt;&gt; CASTRATES &lt;&lt;&lt;|-\*- DESOLATES -\*-|-=&lt; RAVAGES &gt;=-|crashes against|injures|grazes|scratches|decimates|wounds|maims|mauls|devastates|DISEMBOWELS) (?&lt;target&gt;.+?)(\.|!|'s shield\.) \((?&lt;damage&gt;\d+)\)$"


   name="handle_attack"
   omit_from_output="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
-- enable summary trigger
EnableTrigger ("damage_summary", true)

-- compute extra damage
total_damage = (total_damage or 0) + %&lt;damage&gt;

-- need a regexp to tell when the attacker or target changes
if attacker ~= "%&lt;attacker&gt;" or target ~= "%&lt;target&gt;" then

  -- make regexp to see if attacker / target changes

  local re = GetTriggerInfo ("handle_attack", 1)
  local fixed_attacker = "%&lt;attacker&gt;"
  local fixed_target = "%&lt;target&gt;"

  -- attacker or target might have things like * in them, so escape them  
  fixed_attacker = string.gsub (fixed_attacker, "[^%%a%%d ]", "\\\\%%1")
  fixed_target = string.gsub (fixed_target, "[^%%a%%d ]", "\\\\%%1")

  -- er, mind the percentage signs
  re = string.gsub (re, "%%(%%?%%&lt;attacker%%&gt;%%.%%+%%?%%)", fixed_attacker)
  re = string.gsub (re, "%%(%%?%%&lt;target%%&gt;%%.%%+%%?%%)", fixed_target)

  -- regexp for use in the "damage_summary" trigger
  attack_regexp = rex.new (re)

  -- remember attacker and target
  attacker = "%&lt;attacker&gt;"
  target = "%&lt;target&gt;"
  
end -- new attacker or target

</send>
  </trigger>
  <trigger
   enabled="y"
   keep_evaluating="y"
   match="*"
   name="damage_summary"
   send_to="12"
   sequence="10"
  >
  <send>

-- See if we have a different attacker or target

if attack_regexp:match ("%1") then
  return
end -- same attacker, same target

-- note summary
Note (string.format ("%%s damages %%s. (%%d)", attacker, target, total_damage))
total_damage = 0

-- don't trigger again until re-enabled
EnableTrigger ("damage_summary", false)

</send>
  </trigger>
</triggers>



This uses two triggers - one to detect a fight message, and the second one, initially disabled, and with a lower sequence number, that is supposed to detect the end of a round with one opponent.

I am assuming that the messages appear "grouped" as in your example. If they are all intermingled then I would do it slightly differently.

The main trigger (first one above) detects a damage message, and enables the second trigger. It also adds to the current damage total (in case we get more than one in a row). Then it builds up a regular expression that matches that exact attacker/target combination.

The second trigger matches everything (*) with "keep evaluating" set. This is so that other triggers will still fire.

The second trigger detects a change in attacker/target, and if it has changed, outputs the stats for the previous attacker/target. It will also do that if a completely different message arrives (eg. a prompt).

My main problem with the main trigger was detecting the target. It isn't just the last word, as in the example "Mungo's lightning bolt decimates *Sergeant Xena*". In this case the last two words were the target.

If multiple word targets are always inside asterisks this would make it simpler, but for now I have put all the damage types (eg. injures / wounds / maims / devastates etc.) into the regular expression. There are probably more that occur, and you will need to amend it to add those.

Given the damage type, the target is then the word(s) that follow (eg. <someone>'s <attack> grazes <target>).

My triggers work OK for your test data, you will probably need to play with them a bit in practice.

On your test data I got these results:


*Sergeant Xena*'s attack crashes against Mungo's shield.
*Sergeant Xena* damages Mungo. (1574)
Mungo's stab grazes *Sergeant Xena*. (
*Sergeant Xena* damages Mungo. (13)
Captain Daikata's life drain misses *Sergeant Xena*.
Captain Daikata damages *Sergeant Xena*. (73)
Captain Daikata damages *Sergeant Xena*. (90)


The messages about "crashes against" and "misses" didn't have damage amounts in them, so didn't trigger the trigger. You could play with it to fix that.

At least, even now, the output is much shorter.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #2 on Wed 02 Apr 2008 09:54 PM (UTC)
Message
Quote:

Would this script lag my client enough to affect performance?


I tested with about 20 times your messages (about 400 lines) and didn't notice any appreciable lag.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #3 on Wed 02 Apr 2008 10:11 PM (UTC)
Message
The version below handles the messages without the damage quantity (eg. misses). It needed a bit of rejigging because you can't add a non-existent damage amount to the total.


<triggers>
  <trigger
   custom_colour="2"
   enabled="y"


match="^(?&lt;attacker&gt;.+?)\'s .+ (&gt;&gt;&gt; CASTRATES &lt;&lt;&lt;|-\*- DESOLATES -\*-|-=&lt; RAVAGES &gt;=-|crashes against|injures|grazes|scratches|decimates|wounds|maims|mauls|devastates|DISEMBOWELS|misses) (?&lt;target&gt;.+?)(\.|!|'s shield\.)( \((?&lt;damage&gt;\d+)\)){0,1}$"


   name="handle_attack"
   omit_from_output="y"
   regexp="y"
   send_to="14"
   sequence="100"
  >
  <send>
-- enable summary trigger
EnableTrigger ("damage_summary", true)

-- compute extra damage - provided damage available (eg. not a miss)

if tonumber ("%&lt;damage&gt;") then
  total_damage = (total_damage or 0) + tonumber ("%&lt;damage&gt;")
end -- if

-- need a regexp to tell when the attacker or target changes
if attacker ~= "%&lt;attacker&gt;" or target ~= "%&lt;target&gt;" then

  -- make regexp to see if attacker / target changes

  local re = GetTriggerInfo ("handle_attack", 1)
  local fixed_attacker = "%&lt;attacker&gt;"
  local fixed_target = "%&lt;target&gt;"

  -- attacker or target might have things like * in them, so escape them  
  fixed_attacker = string.gsub (fixed_attacker, "[^%%a%%d ]", "\\\\%%1")
  fixed_target = string.gsub (fixed_target, "[^%%a%%d ]", "\\\\%%1")

  -- er, mind the percentage signs
  re = string.gsub (re, "%%(%%?%%&lt;attacker%%&gt;%%.%%+%%?%%)", fixed_attacker)
  re = string.gsub (re, "%%(%%?%%&lt;target%%&gt;%%.%%+%%?%%)", fixed_target)

  -- regexp for use in the "damage_summary" trigger
  attack_regexp = rex.new (re)

  -- remember attacker and target
  attacker = "%&lt;attacker&gt;"
  target = "%&lt;target&gt;"
  
end -- new attacker or target

</send>
  </trigger>
  <trigger
   keep_evaluating="y"
   match="*"
   name="damage_summary"
   send_to="14"
   sequence="10"
  >
  <send>
-- See if we have a different attacker or target

if attack_regexp:match ("%1") then
  return
end -- same attacker, same target

-- note summary
Note (string.format ("%%s damages %%s. (%%d)", attacker, target, total_damage))
total_damage = 0

-- don't trigger again until re-enabled
EnableTrigger ("damage_summary", false)
</send>
  </trigger>
</triggers>


I fixed the line in your test data which ended in just a "(", and then got these results:


*Sergeant Xena* damages Mungo. (1587)
Mungo damages *Sergeant Xena*. (88)
Captain Daikata damages *Sergeant Xena*. (163)


- Nick Gammon

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

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #4 on Wed 02 Apr 2008 10:16 PM (UTC)
Message
I tried this timing test in the Immediate window:


for i = 1, 100 do
Simulate [[
*Sergeant Xena*'s slash >>> CASTRATES <<< Mungo! (302)
*Sergeant Xena*'s slash -*- DESOLATES -*- Mungo! (249)
*Sergeant Xena*'s slash -*- DESOLATES -*- Mungo! (298)
*Sergeant Xena*'s critical strike -=< RAVAGES >=- Mungo! (371)
*Sergeant Xena*'s critical strike -=< RAVAGES >=- Mungo! (354)
*Sergeant Xena*'s attack crashes against Mungo's shield.
*Sergeant Xena*'s life drain injures Mungo. (13)
Mungo's stab grazes *Sergeant Xena*.
Mungo's stab grazes *Sergeant Xena*. (6)
Mungo's life drain scratches *Sergeant Xena*. (2)
Mungo's lightning bolt decimates *Sergeant Xena*. (26)
Mungo's chilling touch wounds *Sergeant Xena*. (20)
Mungo's burning hands maims *Sergeant Xena*. (34)
Captain Daikata's thwack mauls *Sergeant Xena*. (22)
Captain Daikata's thwack devastates *Sergeant Xena*. (29)
Captain Daikata's electric strike mauls *Sergeant Xena*. (22)
Captain Daikata's life drain misses *Sergeant Xena*.
Captain Daikata's critical strike DISEMBOWELS *Sergeant Xena*. (42)
Captain Daikata's thwack mauls *Sergeant Xena*. (23)
Captain Daikata's electric strike mauls *Sergeant Xena*. (22)
Captain Daikata's life drain scratches *Sergeant Xena*. (3)
]]

end -- loop


This is doing your test data 100 times. With my stopwatch this took 1 second to execute, so that is probably acceptable speed - we are talking about processing 2100 messages per second.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #5 on Wed 02 Apr 2008 10:17 PM (UTC)
Message
See http://www.mushclient.com/pasting for how to copy these into the client.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #6 on Wed 02 Apr 2008 10:48 PM (UTC)

Amended on Wed 02 Apr 2008 10:51 PM (UTC) by Nick Gammon

Message
A variation is to use the script file, rather than "send to script". This will be faster, if speed is a concern, because it does not need to recompile the script every time through. In this case the triggers just look like this:


<triggers>
  <trigger
   enabled="y"


match="^(?&lt;attacker&gt;.+?)\'s .+ (&gt;&gt;&gt; CASTRATES &lt;&lt;&lt;|-\*- DESOLATES -\*-|-=&lt; RAVAGES &gt;=-|crashes against|injures|grazes|scratches|decimates|wounds|maims|mauls|devastates|DISEMBOWELS|misses) (?&lt;target&gt;.+?)(\.|!|'s shield\.)( \((?&lt;damage&gt;\d+)\)){0,1}$"


   name="handle_attack"
   omit_from_output="y"
   regexp="y"
   script="attack_script"
   sequence="100"
  >
  </trigger>

  <trigger
   keep_evaluating="y"
   match="*"
   name="damage_summary"
   script="damage_script"
   sequence="10"
  >
  </trigger>
</triggers>



Then you need to create a script file (eg. myscript.lua) and paste this into it:


function attack_script (name, line, wildcards)

  
  -- enable summary trigger
  EnableTrigger ("damage_summary", true)
  
  -- compute extra damage - provided damage available (eg. not a miss)
  
  if tonumber (wildcards.damage) then
    total_damage = (total_damage or 0) + tonumber (wildcards.damage)
  end -- if
  
  -- need a regexp to tell when the attacker or target changes
  if attacker ~= wildcards.attacker or target ~= wildcards.target then
  
    -- make regexp to see if attacker / target changes
  
    local re = GetTriggerInfo ("handle_attack", 1)
    local fixed_attacker = wildcards.attacker
    local fixed_target = wildcards.target
  
    -- attacker or target might have things like * in them, so escape them  
    fixed_attacker = string.gsub (fixed_attacker, "[^%a%d ]", "\\%1")
    fixed_target = string.gsub (fixed_target, "[^%a%d ]", "\\%1")
  
    -- fix up regexp to have actual attacker and target
    re = string.gsub (re, "%(%?%<attacker%>%.%+%?%)", fixed_attacker)
    re = string.gsub (re, "%(%?%<target%>%.%+%?%)", fixed_target)
  
    -- regexp for use in the "damage_summary" trigger
    attack_regexp = rex.new (re)
  
    -- remember attacker and target
    attacker = wildcards.attacker
    target = wildcards.target
    
  end -- new attacker or target

end -- attack_script 

function damage_script (name, line, wildcards)

  if not attack_regexp then
    return
  end -- if no regexp yet

  -- See if we have a different attacker or target
  
  if attack_regexp:match (wildcards [1]) then
    return
  end -- same attacker, same target
  
  -- note summary
  Note (string.format ("%s damages %s. (%d)", attacker, target, total_damage))
  total_damage = 0
  
  -- don't trigger again until re-enabled
  EnableTrigger ("damage_summary", false)

end -- damage_script 



This is a bit simpler because we didn't need to double the % signs where they appeared. It looks simpler and is faster.

You need to select your script file in the Scripting configuration tab.

- Nick Gammon

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

Posted by Tntxploshin   (4 posts)  Bio
Date Reply #7 on Thu 03 Apr 2008 03:28 PM (UTC)
Message
I knew it was going to be an interesting problem for you. ;) Thanks for the incredible turnaround time! Obviously, this project will take some tweaking and work to capture everything...Especially because the MUD output I put up is just the beginning. I'll keep you all posted on my (slow) progress, and check back in if I have more problems.

Also, I'm having trouble pasting the trigger you put up in the post right before mine.
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #8 on Thu 03 Apr 2008 08:40 PM (UTC)
Message
They pasted OK for me. First read this:

http://www.mushclient.com/pasting

You need to copy between the first set of lines (from <triggers> ... </triggers> ) onto the clipboard and then paste as described in the post above.

It might be wise first to copy between the second set of lines into your script file, or it might complain the script functions don't exist.

If you have further problems please paste or describe the exact error message.

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


22,021 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.