TDM Movers: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
No edit summary
 
(3 intermediate revisions by the same user not shown)
Line 7: Line 7:
There are two base classes: '''BinaryFrobMover''' and '''MultiStateMover''', which both build on top of the vanilla Doom 3 '''idMover''' class and provides all the methods needed to make all kinds of two- or multistate movers.
There are two base classes: '''BinaryFrobMover''' and '''MultiStateMover''', which both build on top of the vanilla Doom 3 '''idMover''' class and provides all the methods needed to make all kinds of two- or multistate movers.


Each following section is dedicated to a certain subclass, listing information about spawnargs, script events as well as the C++ methods. This article is going to be long and should probably be split into pieces once the rough shape is formed.
Each following articles are dedicated to the various subclasses, listing information about spawnargs, script events as well as the C++ methods, where appropriate.


== CBinaryFrobMover ==
* [[CBinaryFrobMover]] (atdm:mover_binarymover_base)
The corresponding entityDef is '''atdm:mover_binarymover_base'''
** [[CFrobDoor]] (atdm:mover_door)
** [[CFrobDoorHandle]] (atdm:mover_door_handle)
** [[CFrobButton]] (atdm:mover_button)
*** [[CMultiStateMoverButton]] (atdm:mover_elevator_button)
** [[CFrobLever]] (atdm:mover_lever)
* [[CMultiStateMover]] (atdm:mover_multistate / atdm:mover_elevator)
* [[CMultiStateMoverPosition]] (atdm:mover_multistate_position)


This is the base class for all kind of TDM movers like doors, levers and buttons. The class is designed for movers with two final states, namely open and closed. "Open" and "closed" are abstract definitions and just refer to the "one" and the "other" state of the mover. All movers are considered to spawn "closed", until specifically specified otherwise.
{{editing}} {{sdk}}
 
The class provides a set of virtual C++ methods which can be specialised by their subclasses to implement the correct behaviour. It also supports a number if spawnargs which allow for easy customisation right in the editor.
 
=== Spawnargs ===
* '''rotate''': Describes the angles (pitch, yaw, roll) the mover will rotate from its closed to its open position (default is: "90 0 0").
* '''translate''': Describes the relative movement of the origin from the closed position to the open position (default is "0 0 0" = no movement).
* '''translate_speed''': Is the linear velocity in units per second (defaults to "0", which means that the idMover's "move_time" value is in effect).
 
* '''open''': (1/0) Specifies whether this frobmover spawns at the open position. Can be used to let doors be open right at map start (default is "0").
* '''locked''': (1/0) Specifies whether this frobmover is locked (default is "0").
 
* '''open_on_unlock''': (1/0) When set to 1, the mover will automatically open when unlocked.
* '''interruptable''': (1/0) When set to 1, the mover can be stopped by frobbing it while moving. Doors are interruptable by default, whereas levers are not.
* '''stop_when_blocked''': (1/0) Set stop_when_blocked to 0 to let this entity keep moving after the blocking entity is out of the way. Default is "1".
* '''push_player''': (1/0) Set this to 1 to let this entity push the player (default is 0). Note: belongs to idMover class.
 
* '''start_rotate''': (Angles) Defines the angles (pitch, yaw, roll) the mover should have at spawn time (to let the mover start out half-open, for instance). Defaults to "0 0 0".
* "start_position": (Vector) Defines the position the mover should have at spawn time (to let the mover start out open, for instance). Defaults to "0 0 0".
* '''first_frob_open''': (1/0) This helps to disambiguate the behaviour when a mover starts at a half-open position. When this is set to "1" the first frob will make the mover open. Defaults to "0", which means that half-open doors will close on first frob by default.
 
* '''snd_open''' (Soundshader) The sound to be played when the door starts to open after being fully closed.
* '''snd_close''' (Soundshader) The sound to be played when the door reaches its fully closed position.
* '''snd_locked''' (Soundshader)  The sound to be played when the mover becomes locked.
* '''snd_unlock''' (Soundshader)  The sound to be played when the mover unlocks.
 
* '''trigger_on_open''': (1/0) If set to "1", this binary mover will trigger its targets when it starts out completely closed and is opened. Default is "0".
* '''trigger_on_close''': (1/0) If set to 1, this binary mover will trigger its targets when it completely closes after being open. Default is "0".
* '''trigger_when_opened''': (1/0) If set to 1, this binary mover will trigger its targets when it is completely opened. Default is "0".
 
* '''auto_close_time''': Set this to something >= 0 to let the mover automatically close (again) after this time when being fully opened (measured in seconds). Defaults to -1, which means 'do not autoclose'. The event is also activated when the mover starts at the open position at map start.
* '''auto_open_time''': Set this to something >= 0 to let the mover automatically open (again) after this time when being fully closed (measured in seconds). Defaults to -1, which means 'do not autoopen'. The event is also activated when the mover starts at the closed position at map start.
 
* '''impulse_thresh_open''': (float) Defines the minimum impulse which needs to be applied to this door before it starts to open. If 0, no open impulse is defined. Default is "0".
* '''impulse_thresh_close''': (float) Defines the minimum impulse which needs to be applied to this door before it starts to close. If 0, no close impulse is defined. Default is "0".
* '''impulse_dir_open''': (vector) Defines the direction the open impulse needs to be applied in. Default is '0 0 0'.
* '''impulse_dir_close''': (vector) Defines the direction the close impulse needs to be applied in. Default is '0 0 0'.
 
* '''state_change_callback''': (script function) Defines the (global) script function which gets called when the mover changes its state. Function signature is: '''void statChangeCallback(entity self, bool open, bool locked, bool interrupted);'''
 
=== Script Events ===
 
;scriptEvent void Open();
: Opens the frobmover, regardless of its previous state. The mover will not move when it's locked.
 
;scriptEvent void Close();
: Closes the frobmover, regardless of its previous state.
 
;scriptEvent void ToggleOpen();
: Toggles the mover state. Closes when fully open, opens when fully closed. If the mover is "interrupted" (e.g. when the player frobbed the mover in between), the move direction depends on the state of the internal "intent_open" flag.
 
; scriptEvent float IsOpen();
: Returns true (nonzero) if the mover is open, which is basically the same as "not closed". A mover is considered closed when it is at its close position.
 
;scriptEvent void Lock();
: Locks the mover. Calls to Open() will not succeed after this call.
;scriptEvent void Unlock();
: Unlocks the mover. Calls to Open() will succeed after this call. Depending on the value of the spawnarg "open_on_unlock" the mover might automatically open after this call.
; scriptEvent void ToggleLock();
: Toggles the lock state. Unlocked movers will be locked and vice versa. The notes above concerning Unlock() still apply if this call unlocks the mover.
; scriptEvent float IsLocked();
: Returns true (nonzero) if the mover is currently locked.
 
=== C++ Methods and Events ===
The class declaration can be found in ''DarkMod/BinaryFrobMover.h''. Apart from the mandatory Spawn/Save/Restore triple, a set of virtual functions are defined, which can be overridden by the subclasses to specialise the mover.
 
Note: This is just an abstract. A detailed description of these events can be found in the BinaryFrobMover.h header itself.
 
As many spawnargs refer to other entities, most of the setup work can be performed after all entities have been spawned. This is why the FrobMover base class provides a virtual PostSpawn() method which can be overridden by the subclasses to do work after all map entities have been spawned. Note: don't forget to call the base class!
// Gets called 16 ms after all entities have been spawned
virtual void PostSpawn();
 
The class provides a few virtual "interceptor" methods, which can be used to prevent the mover from changing its state. These are:
virtual bool PreOpen();
virtual bool PreClose();
virtual bool PreInterrupt();
virtual bool PreLock(bool bMaster);
virtual bool PreUnlock(bool bMaster);
These functions are called when the mover is about to perform the respective action. If these are returning TRUE, the mover has green light and it will start to open/close/lock/unlock/get interrupted. Returning FALSE will prevent the calling method from continuing. An example of such a use case is the CBinaryFrobMover::PreOpen() routine, which returns FALSE when the mover is locked. It also playes the "I'm locked" sound before returning.
 
There are a couple of "state change events", which get invoked when the mover has reached a certain state:
// Gets called when the mover actually starts to move, regardless what the state was beforehand.
// The boolean tells which state the mover is heading towards.
virtual void OnMoveStart(bool open);
// Gets called when the mover is about to move towards its "open" and "closed" position, resp..
virtual void OnStartOpen(bool wasClosed, bool bMaster);
virtual void OnStartClose(bool wasOpen, bool bMaster);
// Gets called when the mover has just reached its fully open/closed position. Does not get called when the mover didn't move.
virtual void OnOpenPositionReached();
virtual void OnClosedPositionReached();
// Gets called when the mover has just been interrupted.
virtual void OnInterrupt();
// Is called when the mover has just been locked/unlocked.
virtual void OnLock(bool bMaster);
virtual void OnUnlock(bool bMaster);
 
General note on overriding these events: Althought most default implementations are empty, it's still advisable to call the base class from the overriding function. Default behaviour might be changed in the future, so always call the base class, unless you really need to prevent the default action from being executed.
 
== CFrobDoor ==
The corresponding entityDef is '''atdm:mover_door'''
 
See also the [[Doors]] article for a tutorial approach.
 
This is the most sophisticated BinaryFrobMover. A door extends the functionality by a lot of code to open/close visportals, controlling double doors, attaching handles, lockpicking and peer relationships to other doors.
 
Note: A door works closely together with the CFrobDoorHandle class, but it can function as well without a handle.
 
=== Spawnargs ===
* '''auto_setup_door_handles''' (1/0) If set to 1 (which is the default), the door will automatically search for bound door handles and set them up.
* '''auto_setup_double_door''' (1/0) If set to 1 (which is the default), the door will automatically search for double doors and add it as open_peer and lock_peer.
 
* '''door_handle''' (entity name) Set to the entity name that is a handle for this door. (Note: this is not required if '''auto_setup_door_handles''' is set to true (in which case the handle just needs to be bound to the door).
* '''door_handle_bind_flag''' (1/0) If set to "1", the entity specified in 'door_handle' will be bound to this door. Default is "1".
 
* '''open_peer_N''' (entity name) Specifies the name of another door which should be opened and closed along with this one. Multiple spawnargs are allowed, as long as their prefix is 'open_peer'.
* '''lock_peer_N''' (entity name) Specifies the name of another door which should be locked and unlocked along with this one. Multiple spawnargs are allowed, as long as their prefix is 'lock_peer'.
 
* '''pickable''' (1/0) If set to 1, is pickable by the player.
* '''used_by''' (list) Contains a list of entity names (of keys) that unlock/lock this door, separated by semicola ';'.
* '''loss_open''' (float) Soundprop: Acoustical loss applied to sounds going thru the door when it is open (default 1 dB).
* '''loss_closed''' (float) Soundprop: Acoustical loss applied to sounds going thru the door when it is completely closed (default 15 dB).
* '''loss_double_open''' (float) Soundprop: Acoustical loss applied to sounds going thru a set of double doors when one is open and the other is closed (defaults to 1 dB).
 
* '''lock_pins''' (string) Defines the number of pin patterns to be created for this lock.
* '''lockpick_pin_''' (???) (greebo: TODO)
* '''lock_picktype''' (string) This is a sequence of characters defining the lockpick types which need to be used on this door. For instance, 'bs' means that the player must use the "bent" lockpick ('b') and the "snake" lockpick ('s') - in this order - to pick this lock.
* '''lockpick_bar''' (entity name) The entity which should be used as lockpick bar. This is the moveable part which wiggles around when the player is picking the lock.
* '''lockpick_bar_bind_flag''' (1/0) If set to '1', the entity specified in 'lockpick_bar' will be bound to this door. Default is '1'.
* '''lockpick_rotate''' (angles) The full rotation angles the lockpick bar should rotate while picking. This is the full rotation, the rotation per lock pin is automatically calculated.
* '''lockpick_translate''' (vector) The full translation the lockpick bar should move while picking. This is the full translation, the translation per lock pin is automatically calculated.
 
* '''lockpick_lock_picked''' (soundshader) (greebo: TODO: Needs to be changed to use the snd_ prefix).
* '''lockpick_pin_success''' (soundshader)(greebo: TODO: Needs to be changed to use the snd_ prefix).
* '''lockpick_pin_fail''' (soundshader) (greebo: TODO: Needs to be changed to use the snd_ prefix).
* '''lockpick_pick_wrong''' (soundshader) (greebo: TODO: Needs to be changed to use the snd_ prefix).
 
* '''snd_wrong_key''' (sound shader) The sound to be played when the player is using the wrong key on this door.
 
=== Script Events ===
 
; scriptEvent void OpenDoor(float Master);
: The OpenDoor method is necessary to give the FrobDoorHandles a "low level" open routine. The CFrobDoor::Open() call is re-routed to the FrobDoorHandle::Tap() method, so there must be a way to actually let the door open. Which is what this method does.
: Note: Shouldn't be called directly by scripters, call handle->Tap() instead. Unless you know what you're doing.
; scriptEvent float IsPickable();
: Returns true (nonzero) if this door is pickable.
; scriptEvent entity GetDoorhandle();
: Returns the handle entity of this door. Can return NULL (== $null_entity)
 
=== C++ Methods and Events ===
Most of the setup work is done in the virtual override of CBinaryFrobMover::PostSpawn(). The CFrobDoor::PostSpawn() override sets up the double doors, binds the doorhandles and sets up the lock_ and open_peers.
 
== CFrobDoorHandle ==
The corresponding entityDef is '''atdm:mover_door_handle'''.
 
Door handles can be attached to doors via '''bind''' and are responsible of triggering the doors in the correct moment. Whenever a door with an attached handle is frobbed, it's the handle that receives the command and starts moving. When the handle reaches its "open" position, the open command is routed back to the door. There is no restriction concerning the movement type of door handles, they can both rotate or translate.
 
=== Spawnargs ===
* '''snd_tap_locked''' (sound shader) Called when the handle starts to move and its door is locked.
* '''snd_tap_default''' (sound shader) Called when the handle starts to move and its door is unlocked.
 
=== Script Events ===
; scriptEvent void Tap();
: Call this to make the handle move and subsequently trigger the door.
 
=== C++ Methods and Events ===
* <no special methods>
 
== CFrobButton ==
The corresponding entityDef is '''atdm:mover_button'''.
 
A button is a simple two-state button to trigger things like lights or other movers.
 
A button specialises the frobmover so that it only fires when it’s fully “pressed”. The default button snaps back to its original position after being pressed, but this behaviour can be overriden by the mapper, of course.
 
Buttons can also be activated by impulses, e.g. by shooting arrows at them.
 
=== Spawnargs ===
* <no special spawnargs>
 
=== Script Events ===
;scriptEvent void Operate();
: Call this to "press" the button.
 
=== C++ Methods and Events ===
* <no special events>
 
== CMultiStateMoverButton ==
The corresponding entityDef is '''atdm:mover_elevator_button'''.
 
This is a special button, designed for making the elevators move to a specific position.
 
Each MultiStateMoverButton carries the information about the elevator’s target position in its spawnargs (”position” = “first_floor”). The name refers to the MultiStateMoverPosition entity.
 
There are two different flavours of buttons, namely “ride” and “fetch” which are queried by the AI to know how to properly use the elevator.
 
=== Spawnargs ===
* '''ride''' (1/0) Set to 1 if this button should be used by an AI to get the elevator moving.
* '''fetch''' (1/0) Set to 1 if this button should be used by an AI to fetch the elevator from another floor.
* '''position''' (name) Names the position the elevator should move to. The name refers to the MultiStateMoverPosition entity.
 
=== Script Events ===
* <same script events as CFrobButton>
 
=== C++ Methods and Events ===
* <no special events>
 
== CFrobLever ==
The corresponding entityDef is '''atdm:mover_lever'''.
 
A simple two-state lever, to switch things on or off.
 
This class has additional code to get the trigger behaviour right. Movers of this type are uninterruptable and fire their targets only if they actually switch states. It's important for them not to fire their targets when obstructed or moving only half way to their other state.
 
=== Spawnargs ===
* <no special spawnargs>
 
=== Script Events ===
;scriptEvent void Operate();
: Call this to toggle the lever
;scriptEvent void Switch(float newState);
: Set the new lever state to the argument (0 = "off")
 
=== C++ Methods and Events ===
* <no special events>
 
== CMultiStateMover ==
The corresponding entityDefs are '''atdm:mover_multistate''' and '''atdm:mover_elevator'''.
 
This mover supports several target positions. The primary "clients" of this class are elevators, of course.
 
The positions are defined by so-called [[CMultiStateMoverPosition]] entities, which are placed by the mapper. It also takes care of triggering/activating the [[func_aas_obstacle]] entities, which are needed for the AI to pathfind on elevator stations.
 
The triggering ("activating") entity needs to carry a "position" spawnarg so that the elevator knows where to move to.
 
=== Spawnargs ===
* '''forward_direction''' (vector) This defines the "forward direction" of this elevator (default is '0 0 1', i.e. upwards). This is needed to control the gear direction of any attached movers.
* '''control_gear_direction''' (1/0) Set this to 1 to let this mover control the direction of targetted rotaters, depending on whether the mover is moving forward/backwards.
 
* '''trigger_on_reached''' (1/0) Set to 1 if the mover should trigger its targets when a position is reached.
* '''trigger_on_leave''' (1/0) Set to 1 if the mover should trigger its targets when leaving from a position.
 
* '''move_speed''' (float) is inherited from idMover. Defines the world units per second to move between floors.
* '''move_time''' (float) is inherited from idMover. Don't use this, it makes the mover slower when it's nearer at its goal.
 
=== Script Events ===
* <no special event>
 
=== C++ Methods and Events ===
The CMultiStateMover works closely together with the [[CMultiStateMoverPosition]] and [[CMultiStateMoverButton]] classes. There is a lot of communication going on between these, to handle the AAS obstacle stuff and to let AI know which buttons to use at which elevator station.
 
== CMultiStateMoverPosition ==
The corresponding entityDefs is '''atdm:mover_multistate_position'''.
 
Defines a position for a multistate mover entity. Must be targetted by the multistate mover, so that the mover knows which positions to associate with at spawn time.
 
The CMultiStateMoverPosition also knows which [[func_aas_obstacle]] entities to activate/deactivate when the mover arrives or leaves.
 
=== Spawnargs ===
* '''position''' (string) The name of the position, e.g. "second_floor"
* '''call_on_leave''' (local script function) Specifies which scriptobject function should be called when the multistatemover leaves this position.
* '''call_on_arrive''' (local script function) Specifies which scriptobject function should be called when the multistatemover arrives at this position.
* '''always_trigger_targets''' (1/0) If set to 1 the position entity will trigger its targets, when the multistatemover arrives or leaves (default is 1). Set this to 0 to let the scriptfunctions handle the triggering.
 
=== Script Events ===
* <no special script events>
 
=== C++ Methods and Events ===
; CMultiStateMoverButton* GetFetchButton();
: returns the fetch button for this elevator position. Used by AI to know which button to press.
; CMultiStateMoverButton* GetRideButton(CMultiStateMoverPosition* toPosition);
: Returns the button entity which can be used to move the associated elevator to the given 'toPosition'. Used by AI to find out which button to press when standing on an elevator.
 
;virtual void OnMultistateMoverArrive(CMultiStateMover* mover);
;virtual void OnMultistateMoverLeave(CMultiStateMover* mover);
:These two events are called when the mulitstate mover leaves/arrives the position.
 
{{coding}} {{editing}}

Latest revision as of 07:41, 30 June 2008

For The Dark Mod, we extended the existing idMover class by a set of classes specifically designed for creating maps in the medieval steampunk setting. Apart from elevators, most movers in TDM are two-state movers, meaning that they can be either in "open" or "closed" state. The class hierarchy is depicted here (I use the internal C++ class names here):



There are two base classes: BinaryFrobMover and MultiStateMover, which both build on top of the vanilla Doom 3 idMover class and provides all the methods needed to make all kinds of two- or multistate movers.

Each following articles are dedicated to the various subclasses, listing information about spawnargs, script events as well as the C++ methods, where appropriate.