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="^(?<attacker>.+?)\'s .+ (>>> CASTRATES <<<|-\*- DESOLATES -\*-|-=< RAVAGES >=-|crashes against|injures|grazes|scratches|decimates|wounds|maims|mauls|devastates|DISEMBOWELS) (?<target>.+?)(\.|!|'s shield\.) \((?<damage>\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) + %<damage>
-- need a regexp to tell when the attacker or target changes
if attacker ~= "%<attacker>" or target ~= "%<target>" then
-- make regexp to see if attacker / target changes
local re = GetTriggerInfo ("handle_attack", 1)
local fixed_attacker = "%<attacker>"
local fixed_target = "%<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")
-- er, mind the percentage signs
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 = "%<attacker>"
target = "%<target>"
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="^(?<attacker>.+?)\'s .+ (>>> CASTRATES <<<|-\*- DESOLATES -\*-|-=< RAVAGES >=-|crashes against|injures|grazes|scratches|decimates|wounds|maims|mauls|devastates|DISEMBOWELS|misses) (?<target>.+?)(\.|!|'s shield\.)( \((?<damage>\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 ("%<damage>") then
total_damage = (total_damage or 0) + tonumber ("%<damage>")
end -- if
-- need a regexp to tell when the attacker or target changes
if attacker ~= "%<attacker>" or target ~= "%<target>" then
-- make regexp to see if attacker / target changes
local re = GetTriggerInfo ("handle_attack", 1)
local fixed_attacker = "%<attacker>"
local fixed_target = "%<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")
-- er, mind the percentage signs
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 = "%<attacker>"
target = "%<target>"
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
| |
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="^(?<attacker>.+?)\'s .+ (>>> CASTRATES <<<|-\*- DESOLATES -\*-|-=< RAVAGES >=-|crashes against|injures|grazes|scratches|decimates|wounds|maims|mauls|devastates|DISEMBOWELS|misses) (?<target>.+?)(\.|!|'s shield\.)( \((?<damage>\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
top