Monster Movement Filter
Using CSBuild, you can designate a DSA to receive a 'Set 0' message whenever a monter is about to make some sort of move or attack and a 'Clear 0' message when the monster is finished with whatever action it took. Because DSAs are rather CPU hungry it is best to select the options that only activate the DSA if the monster is on the same level as the party and is close by. It is possible to specify a different DSA to be used on each level of the dungeon. If no DSA is specified for a level then the 'Global' one is used.
The DSA receives parameters that provide information about the Monster, its position, and the party's position. The DSA can then affect how the monster moves by using the &MONBLK (Monster Block) operation. This operation has no effect whatsoever outside of a Monster Movement Filter and it oly applies to the one monster that is about to move.
Here are the paramters. They can be obtained using the &PARAM@ operation.

- 0 - Monster's dungeon level
- 1 - Monster's X location (relative to level's x offset)
- 2 - Monster's Y location (relative)
- 3 - Object ID of monster
- 4 - Party's dungeon level
- 5 - Party's X location (relative)
- 6 - Party's Y location (relative)
- 7 - Clear 0 message only - Action flags 0-31
- 8 - Clear 0 message only - Action flags 32-63

Note that the Monster's level-, x-, and y-coordinates may be different on the two calls to the Filter. If the monster moves to a different cell then its new position will be indicated. If the monster is removed from the dungeon then its level will be -1. In either of these two cases, the flag MonMove_differentCell will be set.
The DSA is activated with a 'Set 0' whenever the monster is about to do something. There is no way to tell what it is up to. It may turn, move, attack, or flee. The code is impenetrable, at least to me. During the processing of the code we set 'Action Flags' to provide some information about what the code is doing and, therefore, what action the monster has taken.
enum MONSTEREVENTS
{
MDF6TI_turnMonsterTowardParty = 0,
TMAG_tunrMonsterGroup = 1,
TMAG_turnMonsterGroup = 2,
PIn_turnMonsterGroup = 3,
PIn_moveTwoSquaresSucceeded = 4,
PIn_moveTwoSquaresFailed = 5,
SF_greaterThanSmellingDistance = 6,
SF_return = 7,
SF_DeleteTimersMaybeSetFear = 8,
SF_timeFuncMinusThree = 9,
SF_TurnMonstersAsGroup = 10,
SF_IncrementTime = 11,
PIAF_processInvincible = 13,
PIAF_standardFinish = 14,
T524_possibleMove = 15,
T524_moveSucceeded = 16,
T524_moveFailed = 17,
T524_processInvincibleAndFinish = 18,
T524_mabeDeleteTimersFear6TurnIndividuals = 19,
T524_ProcessInvincibleAndFinish = 20,
IC29to41_atLeastOneMemberAlreadyDead = 21,
IC29to41_damageMonsterSucceeded = 22,
IC29to41_atLeastOneMemberAlreadDead = 23,
IC29to41_damageMonsterFailed = 24,
IC29to41_randomMoveSucceeded = 25,
IC29to41_randomMoveFailed = 26,
IC29to41_doNothing = 27,
IC29to41_exitFalse = 28,
TT29to41_TT31 = 29,
TT29to41_fear5or6 = 30,
TT29to41_TT30 = 31,
TT29to41_fear5or6doNothing = 32,
TT29to41_TT30turnAsGroup = 33,
TT29to41_TT30deleteTimersMaybeSetFear = 34,
TT29to41_TT30IncrementTimeByW52PlusRandom = 35,
TT29to41_TT30TryDirectionsD5toD4 = 36,
TT29to41_TT29 = 37,
TT29to41_TTmonsterA3 = 38,
TT29to41_blocked = 39,
TT29to41_fearNot5or6 = 40,
TT29to41_MaybeDeleteTimersFear6TurnIndividuals = 41,
TT29to41_fear0or3 = 42,
TT29to41_fear6 = 43,
TT29to41_w30w32GretaterThan3 = 44,
TT29to41_TTnot37 = 45,
TT29to41_fear5 = 46,
TT29to41_attacking = 47,
TT29to41_notAttacking = 48,
IC29to41_Not32_33_37_38 = 49,
MoveObject_NotAllowedOnLevel = 50,
MonMove_differentCell = 51,
};