First of all, there must be a delay before an action actually occurs. Partly because this makes the game more realistic (it should take time, although very little time, to pick up something from the ground). Delays also remove the risk of endless action-reaction loops stopping the whole game. Imagine a computer-controlled creature that automatically says "hi" whenever he hears anyone else say "hi". What happens if two of these guys are standing in the same room, and a player-controlled character walks in and says "hi". Endless loop, of course - the two schmucks will keep saying hi to each other for all eternity (well, at least as long as the server is running). Furthermore, all other activity in the world will freeze since none of the two characters will seize control or take a paus - they will just keep going as fast as the processor will allow them. With a slight delay the system (ie time itself) won't freeze up (although they will still stand around saying hi to each other for all of eternity).
The second reason for using action objects is that these can then be verified - certain actions might fail (I can't walk through a wall, for example). Actions might even (in certain cases) be modified. Let's say the character is drunk. He intended to take a step north, but he ended up taking a step west instead. Or he intended to say "Hi guys, what's up?" but it came out "Grblrfrthz... uh".
Let's look at two examples of Actions and their corresponding events.
If Fred says hi, a "talk" action will be created. When executed it will fire a corresponding "talk" event.
If Fred walks north, a "move" action will be created. Let's say Fred is standing in the Garden and that "north" leads to the Pub. When executed a corresponding "move" event will be fired. Several additional events will be fired as well - Fred's location has changed so a "property change" event is generated. From the Garden's point of view, it's collection of items has been reduced, so it will fire an "item holder" event stating that Fred has exited. Finally, the Pub will fire an "item holder" event stating that Fred has entered.
In both examples above there is a directly corresponding event for each action. In addition, the second action generates a few indirect or secondary events. The secondary events cannot occur "on their own" - they need a triggering action. This means that the Action classes are a subset of the Event classes, ie each Action has a directly corresponding Event, but every event does not necessarily have a corresponding action. For this reason I have decided to use the following philosophy:
Hence a direct event is equivalent to an Action. Here is the event class hierarchy.
Direct events can have up to four states:
Now the clock will tell the action to execute (remember - MoveDirectionEvent is a subclass if DirectEvent and is therefore also considered to be an action). The MoveDirectionEvent will try to move Fred north, which may or may not succeed, depending on if there is anything blocking the way. Other factors such as physical health, intoxication, darkness, etc may also affect the actual outcome of the action.
As soon as the action is complete, a number of events will usually be generated. If the MoveDirectionEvent succeeded, three indirect events will be fired in addition to the original MoveDirectionEvent (see the event propagation document for details about this):
When executing an action, each direct participant gets a chance to filter (modify) the result, or even cancel the action outright (the sack would cancel the action if the bottle couldn't fit). Some of the indirect participants may also be given the chance to filter the action, depend on the nature (and complexity) of the action. What is the difference between an Action and an Activity? Well the main difference is that Actions are "instant", or "atomic". Even though there is usually a small delay before the Action is executed, it doesn't have duration - once it is executed, it will disappear. It won't stick around and do more things for you. Activies are more like processes - Activities deliver actions and as such work kind of like souls - temporary souls. See the seperate document on activities for more on this...
When executing a skill based action such as "attack wolf", the skill level of the attacker and defender is also considered. The condition of the attacker's weapon is considered, perhaps the lighting in the room is also considered. All in all, the outcome is determined by the combined effect of all participants (both direct and indirect). This is how it's implemented:
The AttackEvent will determine which participants are allowed to filter (or modify) this result, and each of them will be asked for an ActionResultFilter. This is optional, most participants will probably accept the preliminary result. But let's say the weapon used is an OrcTrasherBlade - extra effective for whomping Orcs.
When this weapon is asked to produce an ActionResultFilter it will check if the target was an Orc. If so, it will return an ActionResultFilter (actually an AttackResultFilter, a subclass of ActionResultFilter) representing +3 damage. One important thing about ActionResultFilters is that they can be combined, so all the ActionResultFilters produced by the participants will be but together into one single, combined filter. This will then by applied on the preliminary action result, producing a final result.
The final result will then be executed, and the action will be completed. Here's a summary of what the action object does::
The good thing here is that this will be resolved in an "organized" fashion using the ActionResultFilters. When two filters are combined, possible contradictions have to be resolved, so in this case it may be defined (in the combine(...) method of AttackResultFilter) that an "always miss" filter overrides an "always hit" filter - so combining these two will result in an "always miss" filter. Or it may be defined that they cancel each other (much better in my opinion) so that it is treated as a "no effect" filter. Weights can be introduced too, like the sword is more powerful than the shield, and stuff like that.