KF SDK: movers, doors, triggers and lifts
A guide to movers in KF SDK written by K-2 for the killingfloor.ru forum in 2011: creating movers, triggers and the Event > Tag system, mover properties, and a walkthrough of working examples from a simple door to a lift. Editor basics are covered in map editor basics and the mapping guide. On the same forum DiaLight posted video guides (in Russian) on doors and triggers.
Movers are objects that move during gameplay. In KF these are doors, lifts, cars, skateboards and so on. They are made from static meshes and have similar properties, plus a number of extra features.
Creating a mover
- In the Static Mesh browser, select the mesh for the future mover (a door, for example). You can also build a mover from Solid brushes by converting them to a static mesh first.
- Right-click the Add Mover Brush button and choose a plain Mover. It appears inside the builder brush, so their pivots match. In the 2D viewports a mover has a pink outline.
- The new door is in its closed position. Move it into place and adjust its size with
DrawScale3D. - The closed position is key 0 (the starting position). For the door to open, set position 1: right-click the door, Mover > Key 1, then move or rotate it to where it should be when open.
- Check it: right-click, Mover > Key 0 — the door should return to its starting position.
Movement is stored as a coordinate offset, so if you move the door while it is in its starting position, its open variant moves with it.
If you test such a door in game, it opens on direct contact with the player and closes after a set time.
Select the mesh in the mesh browser and create the mover straight away with the Mover button. If you first place a static mesh on the map, select it and press Mover, you get a mover shaped like a pistol: that is the default mesh used when nothing is selected in the browser (K-2's clarification in the comments).
Activation type (InitialState)
The activation type is set in the mover's properties on the Object tab; the key parameter here is InitialState. The relevant values:
| Value | Behavior |
|---|---|
ConstantLoop | The object moves constantly and needs no activation |
TriggerToggle | The mover changes position only when activated by an Event. Default for all doors in Killing Floor |
TriggerOpenTimed | The mover "opens" on an Event and returns to its starting position after a set time |
BumpOpenTimed | The mover "opens" on contact and "closes" after a set time. Default for Mover |
StandOpenTimed | The mover activates when someone stands on it and "closes" after a set time |
Triggers and the Event > Tag system
Triggers are activators that work on a simple Event > Tag scheme. They are essentially "buttons" that fire an event (Event), which activates anything carrying the matching label (Tag). They can start more than just movers.
Both triggers and movers have an Events tab in their properties. In the trigger's properties you type the event name into the Event field (any name you like), and in the mover's properties you put the same label into the Tag field.
Triggers are in the Actor Class browser, under Triggers. Two types suit doors:
- KFUseTrigger under UseTrigger (there is also KFElevatorTrigger for lifts);
- KFProxyTrigger under Trigger.
To place a trigger on the map, select its class in the Actor Class browser, right-click the spot on the map and choose Add Here (this is how any Actor Class object is added). For a door: Triggers → UseTrigger → KFUseTrigger, put the "eagle head" in the middle of the door and link them: type a label into the mover's Tag (for example 555) and the same label into the trigger's Event (K-2 and Gaiver5, "Triggers" thread, killingfloor.ru forum).
KFUseTrigger
Used for standard KF doors (KFDoorMover) with the TriggerToggle activation type: the doors open and close when the use key is pressed. It looks like a bird's head and goes in the middle of the door, where the weld indicator will be.
Welding is handled by the trigger itself; doors can also be key-locked. The main parameters:
| Parameter | Purpose |
|---|---|
MaxWeldStrength | Weld points needed to weld the door to 100% |
ReFireDelay | Delay in seconds before the trigger can fire again |
Message (Use Trigger tab) | On-screen message shown when the player is near the trigger and can use it. If you enter Press USE key, the standard message is shown, which is also translated in the Russian localization |
For why KFUseTrigger only works with KFDoorMover, see the mapping guide.
KFProxyTrigger
Activates on some kind of interaction with it and has more activation types, but it is not suitable for weldable doors.
| Parameter | Purpose |
|---|---|
bInitiallyActive | Whether the trigger is active from the start |
bTriggerOnceOnly | If True, the trigger can fire only once |
ClassProximityType | The class the trigger reacts to with TT_ClassProximity |
DamageTreshold | Damage needed to activate it (only when activated by shooting) |
Message | Message in the corner of the screen when the player interacts with the trigger |
RepeatTriggerTime | Interval after which the trigger's action repeats; not relevant for this trigger |
ReTriggerDelay | Delay in seconds after activation before it can be activated again |
TriggerType | The trigger's activation type (see below) |
TriggerType values:
| Value | Fires on |
|---|---|
TT_PlayerProximity | Contact with a player |
TT_PawnProximity | Contact with players, zeds and bots |
TT_ClassProximity | Contact with the class set in ClassProximityType |
TT_AnyProximity | Contact with any physical object |
TT_Shoot | Being shot; the trigger becomes solid to bullets |
TT_HumanPlayerProximity, TT_LivePlayerProximity | Contact with a human player and with a living player, which is effectively the same thing |
Mover properties
Movers are quite flexible and can themselves act as triggers by firing events. The main properties shared by all movers, on the Mover tab:
| Parameter | Purpose |
|---|---|
bDamageTriggered | If True, the mover is activated by shooting or hitting it |
bTriggerOnceOnly | If True, the mover can be activated only once |
BumpEvent | An Event the mover fires (like a trigger) when something touches it |
BumpType | What kind of touch the mover reacts to: Player — a player, Pawn — a player or AI, Any — any object |
DamageTreshold | Minimum damage to the mover needed to activate it with bDamageTriggered = True |
DelayTime | Delay before movement starts |
EncroachDamage | Damage the mover deals when it collides with something; players take half the set value |
KeyNum | The current position; also switchable from the context menu, but this parameter lets you set more than 8 positions |
MoverEncroachType | Reaction to colliding with a player or zed (see below) |
MoverGlideType | Acceleration type: GlideByTime — the mover speeds up gradually, MoveByTime — constant speed |
MoveTime | Time the mover takes to travel from one key to the next |
NumKeys | Number of key positions. Default is 2, but you can set many; each segment takes MoveTime |
PlayerBumpEvent | Like BumpEvent, but fires only on contact with a player |
StayOpenTime | How long the door stays open with the ...OpenTimed activation types |
MoverEncroachType values:
| Value | Behavior |
|---|---|
ME_StopWhenEncroach | Movement stops |
ME_ReturnWhenEncroach | The mover returns to its previous position |
ME_CrushWhenEncroach | The mover literally kills the obstacle |
ME_IgnoreWhenEncroach | The mover keeps moving |
The MoverEvents tab sets events fired at different stages of the mover's movement; the MoverSounds tab sets the sounds that accompany it.
For how ordinary movers break zed paths and why KFDoorMover delay is hard to edit, see the known errors section of the mapping guide.
KFDoorMover properties
Doors in KF are created as KFDoorMover: they can be welded, and zeds bash at them. Extra properties:
| Parameter | Purpose |
|---|---|
bBlockDamagingOfWeld | If True, the weld is indestructible and the door can be opened only with the welder |
bDisallowWeld | If True, the door cannot be welded |
bElevOuterDoorTop / bElevOuterDoorBottom | Whether the door is the top / bottom door of a lift |
bKeyLocked | Whether the door is key-locked |
bSmallArmsDamage | If True, the door can be damaged by more than just grenades |
bStartSealed | Whether the door is welded at the start of every wave |
bZombiesIgnore | Whether zeds ignore this door when it is welded |
StartSealedWeldPrc | How many percent the door is welded with bStartSealed |
ZombieDamageReductionFactor | Damage taken from zeds: the higher the value, the faster zeds break it |
The door's break sounds are also set here.
Mover examples
It all looks complicated at first, but it is not. K-2 built a small test map, KF-MoversExample, with simple examples; the movers on it are described below.
Standard weldable door
- Mover: KFDoorMover
- Trigger: KFUseTrigger
- Create a KFDoorMover with two key positions (0 and 1). The example uses the door Static Mesh from KF-Offices with the same open and close sounds.
- Place a KFUseTrigger in the middle of the door.
- Set the trigger's
Eventand the door'sTagto the same value:Door1. - In the trigger's properties set
MaxWeldStrength = 200. Everything else is default.
Double door welded at the start of every wave
- Movers: 2x KFDoorMover
- Trigger: KFUseTrigger
- Create two separate movers, each with its own keys. The example is based on the double door from KF-BioticsLab.
- Give both the same properties and the same
Tag. - Place one KFUseTrigger with its
Eventset to that tag. HereMaxWeldStrength = 500. - To have the door welded at the start of each wave, set
bStartSealed = Trueon both movers.
Key-locked door
- Mover: KFDoorMover
- Trigger: KFUseTrigger
- Make a standard door and set
bKeyLocked = TrueandbDisallowWeld = Truein its properties. - Make the door's
Tagand the trigger'sEventthe same. - Add a key: in the Actor Class browser, Actor > Pickup > KFKeyPickUp.
- In the key's properties, on the Events tab, set its
Tagto the same value as the door's.
Because of a bug, such a door can be blown open with ordinary grenades.
Trader door
- Mover: KFTraderDoor
- Trigger: none (activated by a ShopVolume)
Movers of this type cannot be broken, welded or blown up. They open and close like any other mover; in KF they are usually used at the shops. When a wave is cleared, the randomly chosen shop zone (ShopVolume) fires an Event like a trigger, and when trader time ends it fires it again, closing the door.
- Create a KFTraderDoor with keys 0 and 1 and give it a
Tag. - In the ShopVolume's properties, on the Events tab, set an
Eventmatching the door's tag. Different shops need different events.
If a shop door does not open at the end of a wave, the Event in the ShopVolume is almost always missing (from K-2's reply in the comments). Failing that, open any map with a working shop in the editor and copy its settings.
Automatic double door
- Movers: 2x Mover, activation type
TriggerOpenTimed - Triggers: 2x KFProxyTrigger, activation type
TT_PlayerProximity
- Build a double door as usual, but from Mover.
- Place a KFProxyTrigger on each side of the door with its
Eventset to the doors' tag. When a player "steps" on a trigger, the Event opens the doors. Thanks to the activation type, the mover cannot be activated again until it has "closed". - Despite
TT_PlayerProximity, zeds can use this door too. So that the door does not block their paths, setbPathColliding = Falseon the movers' Collision tab.
Door opened by shooting a button
- Movers: 2x Mover (button and door), activation type
TriggerToggle - Trigger: KFProxyTrigger, activation type
TT_Shoot
- Place a KFProxyTrigger with
Event = btandbTriggerOnceOnly = True, so it can be activated only once. - Make a button mover with
Tag = bt. - On the button's MoverEvents tab set
OpenedEvent = ShootDoor— the door mover's tag. The Event fires when the button "opens". - Make the door mover with
Tag = ShootDoorandbPathColliding = False.
Shooting the trigger presses the button, and the button opens the door.
Secret door opened by damage
- Mover: Mover, activation type
TriggerOpenTimed - Trigger: KFProxyTrigger, activation type
TT_PlayerProximity(irrelevant here)
- Make the mover from a Solid brush converted to a static mesh.
- Set
bDamageTriggered = True. - Set 3 keys (0-2) and
NumKeys = 3.
When shot, the door first slides inward a little, then opens, and closes again after a set time.
Skateboard jumping a ramp
- Mover: Mover, activation type
TriggerToggle - Trigger: none (the mover activates itself on contact with a player)
- Give the mover 9 keys so that it covers equal distances in equal time (not counting the climb and descent).
- Set
PlayerBumpEventto its ownTag: the mover starts when a player touches it. - To avoid slowing down between keys, set
MoverGlideType = MoveByTime.
It looks a bit clunky, but it is still just an ordinary mover.
Dispenser
- Movers: 4x Mover, activation type
TriggerOpenTimed - Trigger: KFProxyTrigger, activation type
TT_ClassProximity
- Inside the "receiver", place a trigger that reacts to thrown money:
ClassProximityType = Class'KFMod.CashPickup'. - The trigger's Event closes the receiver's flaps and at the same time opens others, behind which armor appears.
Making the trigger react to a specific amount is not possible with the stock tools: a trigger reacts to contact with a class, not to its properties. That would need a custom actor class with a script. You could, for example, build an "exchange point" from several triggers, each reacting to a particular thrown weapon (from K-2's replies in the comments).
Lift platform
- Mover: Mover, activation type
StandOpenTimed(fires when someone steps on it)
A lift can also be made like a door that opens vertically, but then only players can use it, and that comes with a lot of bugs.
A lift platform is the simplest working lift; they were common in UT2004. It differs from an ordinary mover only by special points: exits LiftExit and a center LiftCenter (Actor Class browser, NavigationPoint tab).
- Create the platform mover with
InitialState = StandOpenTimed. - Place LiftCenter at the "center" of the mover while it is in position 0. The point moves with the lift, and AI stand on it while the lift moves. In the LiftCenter properties, on the tab of the same name, enter the lift's
Tag. - Place LiftExit points — virtual exits that bots use after the mover stops. In their properties set the lift's
TagandSuggestedKeyFrame— the key position at which this exit is active.
Standard two-floor lift
- Movers: KFElevator, 2x KFElevatorDoorMover, 4x KFTraderDoor
- Activation type:
Elevator(lift),TriggerToggle(doors) - Triggers: 3x KFElevatorTrigger
The developers originally planned lifts for KF, which is why dedicated movers and triggers exist. But lifts came with many bugs, and none of the official maps has one. This lift can be called, and it has doors that open and close depending on the lift's position.
- Create a KFElevator mover and give it a
Tagand key positions. - In the lift's properties, KFElevator > ElevatorFloorTags, set a tag for each key, for example
BottomFloorfor the lower floor andTopFloorfor the upper one. - Place a KFElevatorTrigger inside the lift (in its starting position) and give it a
Tag, for exampleElevatorLiftTrigger. Enter the same tag in the lift's properties: KFElevator tab,ElevatorCenterTriggerfield. This trigger starts the lift from inside. - On each floor place a KFElevatorTrigger with the
Tagyou set for that floor inElevatorFloorTags. These triggers call the lift. - Add LiftExit and LiftCenter points as for the platform, but in the LiftCenter properties, besides the lift's tag, also enter the tag of the center trigger (the KFElevatorTrigger inside the lift).
- Doors. KFElevatorDoorMover has drawbacks: it can be broken or blown up. A better option is trader doors driven by KFElevatorDoorMovers. Create a top and a bottom virtual lift door as KFElevatorDoorMover and hide them somewhere outside the map, out of players' sight.
- On the bottom virtual door, KFDoorMover tab, set
bElevOuterDoorBottom = True; on the top one,bElevOuterDoorTop = True. - On the MoverEvents tab of each virtual door, set Closing and Opening events that drive the real bottom or top doors, for example
BottomDoorsfor the bottom one andTopDoorsfor the top one. - Place a pair of KFTraderDoor on the bottom floor and a pair on the top floor; give each pair the
Tagentered in the MoverEvents of the matching virtual door.
Not only players can use and call this lift.
Shredder
- Movers: 11x Mover, activation types: 10x
TriggerOpenTimed, lever —BumpOpenTimed - Trigger: none (started by the lever mover)
On serious maps aiming for the whitelist this is out of place, but it is easy to build and very spectacular. It consists of 3 pairs of crushers, 2 circular saws, 2 saw holders and 1 lever.
- On the saws and crushers set
MoverEncroachType = ME_CrushWhenEncroachand a largeEncroachDamage. - Give the lever an Event that starts the saws with their holders and the first pair of crushers.
- The first crusher pair's
OpenedEventstarts the second pair, and that one starts the third: a small chain reaction. - To make the saws spin regardless of activation, set
RotationRateon the Yaw axis on their Movement tab and setbFixedRotationDir = True.
After a set time all movers return to their starting positions and the contraption can be triggered again.
Movers are an interesting topic, and with some imagination you can build unique things with them. The game is not rich in such variety, so an unusual idea will stick with players.
K-2's answers from the "Mapping questions" threads
From two threads of questions for mappers on the killingfloor.ru forum, "Вопросы по картостроению" (Mapping questions) and "Непростые вопросы по МАППИНГУ" (Tricky MAPPING questions).
Other InitialState values (K-2 wrote these from memory and warned he might be wrong):
| Value | Behaviour |
|---|---|
LeadInOutLooper | When activated, the mover cycles between keys 0 and 1 and returns to position 0 when activated again |
TriggerAdvance | While the player is inside the trigger's "active zone", the mover moves towards its end position; if the player leaves, it stops, and on re-entering it continues from the same point |
TriggerControl | While the player keeps the trigger activated, the mover moves to its end position and stays there; if the "contact" breaks, it returns to its start position even if it has not fully "opened" |
TriggerPound | Like TriggerControl, but closes after OtherTime; each segment takes MoveTime, so a half-closed mover reaches its end position in the same time as from the start position |
LoopMove | Like ConstantLoop, but requires continuous activation by a trigger |
A barricade that cannot be welded but is restored every wave. Make it a KFDoorMover and on the KFDoorMover tab set bDisallowWeld = True and bStartSealed = True, and enter in StartSealedWeldPrc how many percent it is welded. Leave the other parameters of that tab at False. Good values for ZombieDamageReductionFactor are 0.75-0.95, the default is 0.85. The asker's barricades were indestructible until he placed triggers for them.
KFGlassMover (destructible cars and helicopters, as on KF-Abandoned-Base-MacabreDay) is a "non-placeable" class and is missing from the Add Mover Brush list. The simplest way is to copy such a mover from another map and edit it: the StaticMesh is changed on the Display tab. The fire and debris on hits most likely come from a custom Emitter set in the GlassBits and BreakGlassBits fields.
A different texture on a mover copy. Display > Texture > Use does not work for a mover; change the duplicate's texture on the Skins tab (in the Display section of the properties).
Trigger activation zone. Triggers on maps are made huge so they are easier to find and tell apart. The actual "active zone" is defined by the collision and is enlarged on the matching properties tab. To see it, enable RadiiView in the editor window (right-click the frame > Actors > RadiiView).
Spawning zeds one at a time with a ScriptedTrigger. A KFProxyTrigger with RepeatTriggerTime that fires a zed-spawning ScriptedTrigger cannot be stopped afterwards, and a repeat via GOTOACTION "loops" and cannot be cancelled either. K-2 advised making the ProxyTrigger single-use (bTriggerOnceOnly) and placing 2-4 ScriptedTriggers: give each one the needed number of spawns in its sequence (1 zed = 1 action) and put a 1-2 second interval between SpawnActor actions (Action_WAITFORTIMER). Many ScriptedTriggers on a map have practically no effect on compiling or performance.
Quiet mover sound. Imported mover sounds are barely audible even at maximum volume, while stock sounds play normally. According to K-2, the editor automatically converts sounds to stereo on import; try importing mono sounds, though there is no 100% guarantee. Gaiver5 also advised against stereo: mono works best in the SDK, but is a little quieter.