Technical Documentation: Actuators
The pushbuttons, pressure pads, counters, etc. that are used in DM/CSB all have pretty much the same format and flags but their operation at runtime is very different and depends on special cases in the code. All of these devices have been named actuators (by yours truly). I have tried to outline the actual operation of each kind of actuator in the form of a sort of flowchart.
All the pushbuttons, pressure pads, counters, etc. have the same format. Also see Introduction to Actuators. But they behave very differently because of special cases in the code. Here I have tried to document the behaviour of the various actuators by drawing a sort of 'flowchart' for the code that processes each type of actuator.
Pushbuttons are very complex....they implement all sorts of seemingly different kinds of objects in the dungeon. A Wall Switch operated by an Empty Hand. A Torch Holder. A Keyhole. A wall Niche that is operated by removing a Worm Slice. All are examples of 'Pushbuttons'. So the documentation is divided into several basic types:
- Type 1 -A Simple Pushbutton...Diagram
- Type 2 - A Hand-Operated PushButton... Diagram
- Types 3 and 4 - Pushbuttons operated by special objects...Diagram
- Type 16 - Swap Object Pushbutton... Diagram
Most of the pushbuttons utilize a common function (named QueueSwitchAction) to queue the resulting action.
The Pressure Pad actuator is quite simple in structure compared to Pushbuttons. True, there are eight different varieties of Pressure Pad, each operated by a different kind of action or Object. But as the diagram indicates, these different types only change how it is decided whether the Pressure Pad has been activated and the rest of the processing is identical for all types.
Then there are the actuators that perform special functions. They are all actuated by timer messages rather than directly by party or monster actions.
class DB3:public DBCOMMON // An actuator (pressure pad, keyhole, etc.)
i16 word2; // bits 0-6 = Actuator Type
// 0 = Do nothing
// 1 = A simple wall switch that
// can be pressed with anything.
// 2 = ?
// 3 = Lock. Keys stays in hand
// 4 = Lock. Key removed from hand.
// 5 =
// Byte 8 (position) of Timer6 is bit number.
// Bits 7-15 are value. Bits in this value
// are Set/Cleared/Toggled by Timer6.
// "position" of timer6 tells which bit to
// fiddle with.
// Actuator is 'pressed' when bits 7-10 are
// equal to bits 11-14. (The first 4 bits of
// value equals second 4 bits).
// 6 =
// In a closed (stone) room
// Bits 7-15 are a 9-bit counter. A SET
// function increments and anything else
// decrements the counter. You cannot change
// a counter that equals zero. (Why?)
// The actuator is considered 'pressed'
// if the count is non-zero.
// In an open room this is a monster generator
// and is actuated by a timer event type 5.
// word 6 bits 8-15 non-zero causes once only.
// If >= 128 then a type 65 timer
// is queued to go off at
// 64 * ((word 6 bits 8-15)-126)
// (I presume to reactivate generator!).
// 7 = ?
// 8 = In open room:
// Operated only by party. Value is
// an OBJECTTYPE that we search for in the
// party's possessions. Actuated if party
// possesses such an object.
// In Stone: A missile launcher.
// Value = 0 Fireballs
// 9 = ?
// 11 = Lock. Key removed from hand.
// 14 =
// When a timer of type 6 is sent to
// an actuator of type 14 then the first
// object at the proper position in the same
// room as the actuator is removed
// from the room and launched as a missile
// in the adjacent room.
// 15 =
// When a timer of type 6 is sent to
// an actuator of type 15 then the first two
// objects at the proper position in the same
// room as the actuator are removed
// from the room and launched as missiles
// in the adjacent room.
// bits 7-15 = value
i16 word4; // bit 2 = causes bits 1-6 of word 2 to be cleared. "Once only"???
// bits 3-4 Action when switch changes state
// 0=set when closed
// 1=clear when closed
// 2=toggle when closed
// 3=set when closed, clear when opened
// bit 5 = 0=normally open; 1=normally closed
// bit 6 = make click sound
// bits 7-10 = delta time (or number of monsters+1)
// For a monster generator, a value with bit 3
// set means to generate a random number modulo
// bits 0-2.
// bit 11 = Local action only. Like increase
// bits 12-15 = wall graphic index+1
i16 word6; // (if word4 & 0x800)
// bits 4-15
// (if ! word4 & 0x800)
// bits 4-5 position????
// bits 6_10 =mapX
// bits 11_15 =mapY
// bits 4-7 hitPoint multiplier (Monster Generator)
// bits 4-11 energy remaning in missile
// bits 8_15 disable time (Monster Generator)
// bits 12-15
Actuators in DM/CSB are Objects that receive signals, process the signals to make decisions, and produce signals as a result. The signals are generally of two types:
- Actions of the party or of monsters. Examples are placing a Torch in a Torch Holder, stepping on a Pressure Pad, dropping a Screamer Slice in a Wall Niche.
- Internally generated Timer messages. These are created by other Actuators.
The entire Dungeon is pretty much controlled by Timer messages. A simple example is the process of opening a Door with a key. The keyhole is an Actuator. It is of a type that is operated by a special Object (a Gold Key, for example), has a Wall Decoration (a golden keyhole, for example), and sends a Timer message when it is activated by the proper Object (the key). The Timer message is directed at a dungeon Cell where a Door is located. The message is queued and when its time expires it causes the Door to open. Often the time will be set to zero, causing the Door to open immediately. Nevertheless, the message is the 'middle-man' between the keyhole Actuator and the Door.
The Timer messages have several parts:
- A time. Like an alarm clock. It sits and waits until its time has expired.
- A target. This is a location in the dungeon. A Level, an X and Y, and a Position. The Position is a number 0 through 3. How it is used depends on the target itself. Sometimes it is ised as a position within the cell. 0=North, 1=East, 2=South, and 3=West. Sometimes it is used for other purposes.
- An Action. Set, Clear, or Toggle. The when the target receives the message it decides what 'Set', 'Clear', and 'Toggle' mean. A door, for example, will open if it receives a 'Set', close if it receives a 'Clear', and will change its state when it receives a 'Toggle'.
When a Timer message is received at a particlar Cell in the dungeon, all Actuators and other Objects at that location receive the same message. This is very basic and useful. Because a Timer message can only be directed to a single location, how would we open a Door and close a Pit with the single action of stepping on a Pressure Pad. Commonly this is accomplished by having the Pressure Pad send a message to a Cell containing two Actuators. One of the Actuators causes the Door to open and the other Actuator causes the Pit to close.
Actuators are defined by a structure containing the following basic parts.
- Actuator Type. Like Pushbutton or Counter or Monster Generator or Disabled (do nothing).
- A 'Once-Only' flag. As soon as the Actuator sends its first message it is Disabled. This is very common for keyhole-type Actuators, for example. Once the key has been inserted, the keyhole becomes inactive. However, its decoration remains. The decoration is the reason the Actuatro is marked as Disabled rather than being removed entirely.
- Action to be performed by the resulting Timer message. Set, Clear, Toggle. But there is usually a fourth option called 'Hold'. This generally means that a 'Set' message is sent when the Actuator is activated and a 'Clear' message when the Actuator is deactivated. A common example....a Pressure Pad that 'Holds' a door open so long as a Boulder is on the pad. When the Boulder is placed on the Pressure Pad the pad is 'activated' and it sends a 'Set' message to open the Door. When the Boulder is removed the Pressure Pad is deactivated and sends a 'Clear' message to close the Door.
- A flag to reverse the operation. In the preceeding example, setting this flag would cause the Boulder to 'Hold' the door closed rather than open. In other words it causes a 'Clear' to be sent instead of a 'Set' and vise versa.
- A flag that causes a 'Click' sound when the Actuator is activated.
- A time to be set in the Timer message. This is the delay before the Timer message is delivered to its target.
- Graphic. Like Gold Keyhole (wall) or Square Pad (floor) or 'None'.
- A rather strange flag that supresses the sending of a Timer message and, instead, causes some local action to occur. One of the most clever of these 'Local Actions' is to cause the list of Actuators in the Cell to be 'Rotated'. The first Actuator is removed from the cell's list of Actuators and is put back at the end of the list. Since the last Actuator encountered in the list takes precedence for the purposes of displaying a decoration, this causes the decoration to change. A very common example is the Torch Holder. The Torch Holder is actually two! Actuators....a Pushbutton with an empty holder graphic and a Pushbutton Actuator with a full holder graphic. One Pushbutton sends a message when the Torch is taken and the other has this 'Local Action' of 'rotating' the Actuator list, thereby making it appear as if the Torch has been removed from or placed into the holder.
Notice the orthogonality of all this. All these fields are pretty much independent of one another. For example, the graphic is completely independent of the Actuator Type. A keyhole need not look like a keyhole. Instead it might look like a hole in the wall near the floor operated by a Screamer Slice. And so on. This makes for seemingly endless possibilities for the dungeon designer. A Torch Holder operated by a Gor Coin (strange, but possible). A Pressure Pad that Holds a Door open but Toggles an input to an And-Gate.
Actuators are of many basic types:
- Pushbuttons. Operated by the Party. Placed in walls. Any Wall Decoration can be specified. Some do not look like pushbuttons. Alcoves. Torch Holders. Keyholes. Alcoves are somewhat special in that they act very much like Pressure Pads.
- Pressure Pads. Operated by Party, Monsters, Objects. Any Floor Decoration can be specified.
- Object Holders. Operated by Party. Any Wall Decoration. Takes and gives. Like a Torch Holder.
- Counter. Operated by Timer message. Counts up and down and is 'Active' when the count is zero. Used, for example, when two coins are required to open a door.
- And/Or Gate. Operated by Timer message. Implements the logical operation of 'And' and/or 'Or' (no pun intended). As an example....open a door if a Mummy is standing on Pressure Pad A and a Mummy is standing on Pressure Pad B and a Mummy is standing on Pressure Pad C and a Mummy is standing on Pressure Pad D.
- Monster Generator. Operated by Timer message. This Actuator produces no Timer message (a white lie!). Instead it creates a Monster. So the fields within its definition are used somewhat differently than the other Actuator types.
- Missile Launchers. Operated by Timer message. Any Wall Decoration. Sometimes called 'Shooter'. Launches an Object (Dagger, Worm Round, etc.) or a Magic Spell (Fireball, etc).
- A non-standard Actuator known as a 'Designer Specified Actuator' (DSA). Implemented as a n-input, m-state machine that can reference and modify the dungeon state and contents. Somewhat 'script-like'.
We all know and love Pressure Pads. And they are particulary easy to understand even though they exist in many varieties. But the code is very straight-forward and the various varieties are created by a simple 'case' statement that determines whether the Pressure Pad has been 'pressed' (or 'activated'). For example, a Pressure Pad might be 'pressed' by a Screamer Slice being placed upon it. Any of the types may specify any of the possible Floor Decorations.
In all cases, one of three things can happen:
- 'Nothing'. (That was the easiest to explain.)
- The pad is 'pressed'.
- The pad is 'released'.
There are eight possilble types of Pressure Pad:
- Type 0 - An inoperative Pressure Pad. Does 'nothing'. But it is useful because it may have a Floor Decoration.
- Type 1 - Operated by anything. The pad is 'pressed' if the pad is empty and an object or monster is placed on it. Otherwise 'nothing'. What about Party????
- Type 2 - The pad is 'pressed' if the Party steps onto the Pad or a monster steps onto the pad. Otherwise 'nothing'.
- Type 4 - The pad is 'pressed' if a particular Object type (Screamer Slice, for example) is placed on the pad and it is the only Object of that type on the pad. The pad is 'released' if the last object of a particualr type is removed from the pad. Note the important fact....placing a second Object of the same type on the pad accomplishes 'nothing' and removing an Object while leaving one or more of that type accomplishes 'nothing'.
- Type 6 - The pad is 'pressed' by the party being on the pad and facing in a particular direction. This is the most complicated of the Pressure Pads. If the Party did not move or turn then 'nothing' happens. Otherwise, the specified direction can be either a particular direction (north, east, south, or west) or 'ANY'. If 'ANY' direction was specified then the pad was 'pressed' or 'released' if the party stepped onto or off the pad and 'nothing' happens if the party simply turned. If a particular direction was specified, then things get more complicated. If 'ANY' direction is specified then the party must have moved (not turned) and the pad was 'pressed' or 'released' depending on whether the party stepped onto or off the pad. If a particular direction was specified then the pad is 'released' if the party steps off the pad (irrespective of the direction it was facing.....so the pad can be 'released' over and over again without ever having been 'pressed') or if the new direction is not the specified direction and the pad is 'pressed' if the party is now on the pad facing the proper direction.
- Type 7 - The pad is 'pressed' if a monster steps onto the pad and is 'released' if a monster steps off the pad.
- Type 8 - The pad is activated if the party moves onto or off the pad or turns while standing on the pad. The pad is 'pressed' if the party possesses a particular type of object and is otherwise 'released'. Notice the anomaly----The pad will be pressed if the party steps off the pad while possessing the object and the pad will be released if the party steps onto the pad without that object.
- Type 9 - The pad is activated only if the party steps onto the pad. The pad will be 'pressed' or 'released' depending on the value specified in the actuator - if the value is less than 21 the pad will be 'pressed' else it will be 'released'. I have no idea what the designers had in mind.
Type 5 - And/Or Gate...Diagram
This actuator type is very handy for performing the logical operations of 'AND" and 'OR'. Examples of use:
- Hold a door open if two switches have been pressed. In other words, if the first switch has been pressed AND if the second switch has been pressed.
- Hold a door closed if either of two switches has not been pressed. In other words, if the first switch has not been pressed OR if the second switch has not been pressed.
- Close a pit if all four Knights have been released from their prison cells. In other words, if the first Knight has been released AND the second Knight has been released AND the third AND the forth.
- Close a pit if a Worm Round is in an Alcove OR the party possesses a Dexhelm.
- You can make up dozens more......this is one of the most common logic functions used in the dungeon.
A little thought will reveal that the first two of these examples are IDENTICAL in function. These examples are included to demonstrate that the functions of AND and OR are equivalent. You just have to reverse the inputs and outputs. In this case the inputs are 'Switch pressed' (reverse is 'Switch not pressed') and the output is 'Door open' (reverse is 'Door closed'). Therefore, you can think of this actuator as performing either an 'AND' function or an 'OR' function. This equiavalence is known as DeMorgan's theorm.
I will talk of this gate as an AND gate for simplicity. It has a four-bit 'memory'. Each bit can be 'set' to 'True' or 'Cleared' to 'False'. The values are initialized when the dungeon is designed and then are changed by sending Timer messages to the cell containing the actuator. Timer messages are directed to a cell address and a position within that cell. An And/Or gate is located at a particular position within the cell. BUT!!! In the case of an AND/Or gate, the position information is not used to locate the gate. When a Timer message arrives at a cell, it is received by ALL And/Or gates in that cell, reguardless of position. The position information in the Timer message is used, instead, to determine which of the four bits in the gate's memory will be Set (to True) or Cleared (to False).
OK. Now we have four bits of memory that can be independently initialized when the dungeon is designed and that can be independently Set or Cleared during gameplay by Timer messages. Now we will add the 'Target' values. These are four bits that are specified at design time and which cannot be changed during gameplay. So let us name the 'Memory' bits M0, M1, M2, and M3. And let us name the 'Target' bits T0, T1, T2, and T3. The And/Or actuator tests whether (M0 equals T0) AND (M1 equals T1) AND (M2 equals T2) AND (M3 equals T3). Hence the 'AND' part of its name.
That is the basic operation of the 'And/Or' Actuator. The test for equivalence of the four memory bits and the four target bits. But there are some added features that make the Actuator more versatile.
Let us talk of the Actuator as an ordinary light switch; like the one on the kitchen wall that controls the ceiling lamp. The kitchen light is on when the switch is in the 'Up' position. We will pretend that the Actuator contains an internal light switch. Here is how it works:
- When a Timer message arrives the appropriate 'Memory' bit is Set or Cleared or Toggled according to the function specified in the message.
- The (imaginary) light switch is placed in the upper position if all four 'Memory' bits are equal to their corresponding 'Target' bits.
- If the 'normally-closed' mode is specified then the switch position is reversed. This is what allows the 'Or' operation.
- If 'Input Edge Detection' was specified and no 'Memory' bit was changed then quit....do nothing.
- If 'Output Edge Detection' was specified and the switch position is the same as it was before the Timer message arrived then quit....do nothing.
Now it has been decided that we should send a Timer message of some sort. The designer specified what sort of message to send. There are four possibilities:
- Set. If the switch is 'Up' send a 'Set' Timer message. If the switch is 'Down' quit...do nothing.
- Clear. If the switch is 'Up' send a 'Clear' Timer message. If the switch is 'Down' quit...do nothing.
- Toggle. If the switch is 'Up' send a 'Toggle' Timer message. If the switch is 'Down' quit...do nothing.
- Hold. If the switch is 'Up' send a 'Set' Timer message. If the switch is 'Down' send a 'Clear' Timer message.
That is all there is to it. Except that actually sending the message is accomplished by the function 'QueueSwitchAction'. That function may disable this Actuator or perform some action other than sending a Timer message.
In the DM/CSB editor 'CSBuild' most of these details are hidden and the operation is specified in a bit more intuitive way.