|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sat Mar 22, 2008 7:53 am
Thoughts on an age-old problem. |
I'd never really bothered to look at multistate triggers really in-depth until today, when I wrote the help file for them. People often say they want to be able to trigger on messages like:
Quote: |
Prompt
Bob smacks you in the face.
One of your eyes puffs up a bit, blurring your vision.
Prompt
Bob smacks you in the face.
Your poor nose can't take any more, and breaks with a horrible crunch.
Prompt |
Bob's attack can do lots of different things to you - normally, we say "create a class, put everything in there, and enable it when he attacks and disable it when you get a prompt" but they seem to really want a way of doing it with a multistate trigger. It's not actually impossible, I don't think, just not very pretty and involves lots of repetition:
Code: |
#trig {Bob smacks you in the face} {}
#cond {.} {} {regex|within|param=1}
#cond {One of your eyes puffs up a bit, blurring your vision.} {afflict_me eyepuff;#state 0} {reparse}
#cond {Your poor nose can't take any more, and breaks with a horrible crunch.} {afflict_me brokennose;#state 0} {reparse} |
The cool part about doing it this way is that you can individually tailor each attack so that it only checks the things it can give. Doing it the other way, you'd have to have a class for each attack, which is a bit pants and would probably involve lots of repeated triggers. You can also individually tailor the priorities of the different afflictions for each attack - once one's matched, it'll stop searching, so your match'll be faster if you put the more common ones higher up in the trigger. Vijilante also found that triggers sitting in classes disabled still cause slowdowns, and this method reduces the number of triggers.
I'm honestly not sure which method I prefer. Using this method, it'd be quite annoying to create new attacks (you'd need to make sure you know all the messages for the new attack and then find them in your other triggers and copy them or create new ones, and put them all in the right order) compared to just turning on the class. But even if the class is using carefully-crafted patterns with priorities adjusted to find a match as fast as possible, it's still going to be slower and harder to customise for each attack.
At least there's the possibility of doing it differently. Thoughts? |
|
|
|
ReedN Wizard
Joined: 04 Jan 2006 Posts: 1279 Location: Portland, Oregon
|
Posted: Sun Mar 23, 2008 1:35 am |
So both the "one of your eyes" and "Your poor nose" lines are tested when you use the reparse option? How exactly does that reparse option operate?
|
|
|
|
Vijilante SubAdmin
Joined: 18 Nov 2001 Posts: 5182
|
Posted: Sun Mar 23, 2008 2:31 am |
The reparse actually tests immediately upon becoming the active state. In other words all of the reparse states must be tested, any that match will have thier scripts executed, and then it would go back to the original state.
I don't actually like that setup, and it was testing some thoughts about it that led to my most recent bug reports. The first thing I don't like is that once one of the reparse states matches you still have to check the rest. This is what caused me to find the problem with using #STATE to reset it.
The second thing I don't like is that you can't adjust the priority of states above the original triggers priority. Bascially after the first state you are in a position where you expect one of a select few lines. You want those expectations to be tested before anything else. That is the whole point of priorities, but the current system with states does not permit that. Perhaps if it did I would change my mind on it.
Third would be a required addition to CMud's handling of reparse states. I did a quick test and found that a reparse state will match even if the previous state has the Stop flag set. I believe that that the usage of this flag should cover all triggers on that line, meaning all reparse states after the STOP should be skipped. This addition would also really cover my first problem with it.
Otherwise I do like the design. I would suggest using %match or %regex in a script to do the same thing; but since I know some of the underlying code, and studied some tests of it I can say that reparse is a better way to go. |
|
_________________ The only good questions are the ones we have never answered before.
Search the Forums |
|
|
|
MattLofton GURU
Joined: 23 Dec 2000 Posts: 4834 Location: USA
|
Posted: Sun Mar 23, 2008 3:33 am |
Why bother with a reparse? A simple pattern state should work, and keeping track of one state is going to be a whole lot easier.
#condition {(*)} {#switch (%1 = "option1") {stuff}}
If you don't need to worry about illusions or otherwise faked messages, you might even be able to do the {@stringlist} pattern to make the match more limited. |
|
_________________ EDIT: I didn't like my old signature |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sun Mar 23, 2008 4:45 am |
Vijilante wrote: |
The reparse actually tests immediately upon becoming the active state. In other words all of the reparse states must be tested, any that match will have thier scripts executed, and then it would go back to the original state. |
You forgot to explicitly say that reparse checks the current line (the same line that matched the previous state). More info here.
Vijilante wrote: |
The first thing I don't like is that once one of the reparse states matches you still have to check the rest. This is what caused me to find the problem with using #STATE to reset it. |
My example script uses #state and works absolutely fine. You don't need to specify the ID of the trigger if the script is running inside that trigger. The Stop flag causing them to be skipped is an interesting idea, but not really necessary.
Vijilante wrote: |
The second thing I don't like is that you can't adjust the priority of states above the original triggers priority. |
That's another weakness of it, you're correct.
MattLofton wrote: |
Why bother with a reparse? |
Because it's easy to change and easy (easier, anyway) to create new ones. Changing a switch like that involves lots of careful copying and pasting, whereas this method can be clicked and dragged as much as you like. Also, if you have to do any number of %matches or %regexes, like Viji says, it'll be slower. |
|
|
|
oldguy2 Wizard
Joined: 17 Jun 2006 Posts: 1201
|
Posted: Mon Mar 23, 2009 6:21 am |
How many reparse states can you have? Lets say you have 10 different messages that could happen. Would it be a problem or slow things down?
|
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Mon Mar 23, 2009 10:18 am |
As many as you like. Whether or not this method would suit you depends on exactly what you're doing as well as your preferences, though - you might find this method not so great for large numbers of messages if you're going to need to add all 10 of those messages to a whole bunch of triggers. But you might also find that perferable to, say, a #switch.
|
|
|
|
oldguy2 Wizard
Joined: 17 Jun 2006 Posts: 1201
|
Posted: Tue Mar 24, 2009 2:02 am |
Well I figured as much and Vijilante said something about the underlying code and that this method would be faster. I actually like it and use it a lot.
|
|
|
|
|
|