diff --git a/docs/engine/objects/zCTrigger.md b/docs/engine/objects/zCTrigger.md
new file mode 100644
index 00000000..455cc060
--- /dev/null
+++ b/docs/engine/objects/zCTrigger.md
@@ -0,0 +1,157 @@
+# zCTrigger
+
+!!! abstract inline end "Quick Infos"
+ **Type:** Virtual Object
+ **Format Name:** ZenGin Archive
+ **File Extension:** `.ZEN`
+ **Class Name:** `zCTrigger`
+ **Version Identifiers:**
+ — Gothic I: `47105`
+ — Gothic II: `47105`
+ **ZenKit Class:** `VTrigger`
+
+VObject to process and relay specific filtered events. When a `zCTrigger` receives an `OnTrigger`, `OnDamage`, or
+`OnTouch` event it checks whether the event source (an [`oCNpc`](oCNpc.md), the player or another VObject) should
+be acknowledged (see [`respondToNPC`](#respondToNPC), [`respondToPC`](#respondToPC) and
+[`respondToObject`](#respondToObject) respectively). It then verifies if it should react to the specific event by
+checking the [`reactToOnTrigger`](#reactToOnTrigger), [`reactToOnDamage`](#reactToOnDamage) and
+[`reactToOnTouch`](#reactToOnTouch) properties. If both checks succeed, an `OnTrigger` event is sent to the
+[`triggerTarget`](#triggerTarget). `zCTrigger` objects can be enabled and disabled by firing `OnEnable`, `OnDisable`
+and `OnToggleEnabled` events at them.
+
+!!! note
+ The `respondTo{Object,PC,NPC,VobName}` properties are logically linked by and "or" expression.
+
+
+
+## Properties
+
+ `triggerTarget`
+
+: The name of VObject to send `OnTrigger` and `OnUntrigger` events to after processing.
+
+ `reactToOnTrigger`
+
+: Whether this trigger should react to `OnTrigger` events.
+
+ * `TRUE` — Do react to `OnTrigger` events by sending an `OnTrigger` message to the [`triggerTarget`](#triggerTarget)
+ If [`sendUntrigger`](#sendUntrigger) is set to `TRUE`, also sends an `OnUntrigger` event to the [`triggerTarget`](#triggerTarget)
+ if the trigger receives an `OnUntrigger` event.
+ * `FALSE` — Ignore `OnTrigger` events.
+
+ `reactToOnTouch`
+
+: Whether this trigger should react to `OnTouch` events.
+
+ * `TRUE` — Do react to `OnTouch` events by sending an `OnTrigger` message to the [`triggerTarget`](#triggerTarget)
+ If [`sendUntrigger`](#sendUntrigger) is set to `TRUE`, also sends an `OnUntrigger` event to the [`triggerTarget`](#triggerTarget)
+ if the trigger receives an `OnUntouch` event.
+ * `FALSE` — Ignore `OnTouch` events.
+
+ `reactToOnDamage`
+
+: Whether this trigger should react to `OnDamage` events.
+
+ * `TRUE` — Do react to `OnDamage` events by sending an `OnTrigger` message to the [`triggerTarget`](#triggerTarget)
+ * `FALSE` — Ignore `OnDamage` events.
+
+ `respondToObject`
+
+: Whether this trigger should process events coming from inanimate objects.
+
+ * `TRUE` — Do process events from inanimate objects.
+ * `FALSE` — Ignore events from inanimate objects.
+
+ `respondToPC`
+
+: Whether this trigger should process events coming from the player.
+
+ * `TRUE` — Do process events from the player.
+ * `FALSE` — Ignore events from the player.
+
+ `respondToNPC`
+
+: Whether this trigger should process events coming from NPCs.
+
+ * `TRUE` — Do process events from NPCs.
+ * `FALSE` — Ignore events from NPCs.
+
+ `startEnabled`
+
+: Determines whether the trigger is initially enabled. Enabled triggers will process incoming events and send
+ outgoing events while disabled triggers do not. Triggers can be activated and deactivated at runtime by sending
+ them `OnEnable`, `OnDisable` or `OnToggleEnabled` events.
+
+ * `TRUE` — Enable the trigger when the world is loaded.
+ * `FALSE` — Do not enable the trigger when the world is loaded.
+
+ `respondToVobName`
+
+: Whether this trigger should process events coming from VObjects with this name. If empty, match no VObject
+ name directly.
+
+ `numCanBeActivated`
+
+: The number of times the trigger will process incoming events. If set to `-1` the trigger will process
+ an infinite number of events.
+
+ `retriggerWaitSec`
+
+: The number of seconds that have to elapse after processing an event before the trigger will process additional events.
+ All events received by the trigger during that time are ignored.
+
+ `damageThreshold`
+
+: The amount of damage which must be dealt for the trigger to react to an `OnDamage` event.
+
+ `fireDelaySec`
+
+: The number of seconds to wait before emitting the `OnTrigger` event after processing.
+
+ `sendUntrigger`
+
+: Whether to send and `OnUntrigger` event to the [`triggerTarget`](#triggerTarget) after the trigger receives an
+ `OnUntrigger` or `OnUntouch` event. Only fires the `OnUntrigger` event if [`reactToOnTrigger`](#reactToOnTrigger)
+ and [`reactToOnTouch`](#reactToOnTouch) are set to `TRUE` respectively.
+
+
+## Sources
+
+The help file for the Spacer, found [here](https://wiki.worldofgothic.de/doku.php?id=spacer:hilfedatei) and the
+Russian-language knowledge accumulator [gothic-library.ru](http://www.gothic-library.ru/publ/class_zctrigger/1-1-0-529).
diff --git a/include/zenkit/vobs/Trigger.hh b/include/zenkit/vobs/Trigger.hh
index 030197f1..3bda7dc7 100644
--- a/include/zenkit/vobs/Trigger.hh
+++ b/include/zenkit/vobs/Trigger.hh
@@ -67,18 +67,95 @@ namespace zenkit {
random ZKREM("renamed to TriggerBatchMode::RANDOM") = RANDOM,
};
- /// \brief A basic trigger VOb which does something upon the player interacting with it.
+ /// \brief VObject to process and relay specific filtered events.
+ ///
+ /// When a `zCTrigger` receives an `OnTrigger`, `OnDamage`, or `OnTouch` event it checks whether the event
+ /// source (an VNpc, the player or another VObject) should be acknowledged (see #respond_to_npc, #respond_to_pc
+ /// and #respond_to_object respectively). It then verifies if it should react to the specific event by checking
+ /// the #react_to_on_trigger, #react_to_on_touch and #react_to_on_damage properties. If both checks succeed, an
+ /// `OnTrigger` event is sent to the #target. `zCTrigger` objects can be enabled and disabled by firing `OnEnable`,
+ /// `OnDisable` and `OnToggleEnabled` events at them.
+ ///
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/
struct VTrigger : VirtualObject {
ZK_OBJECT(ObjectType::zCTrigger);
public:
+ /// \brief The name of VObject to send `OnTrigger` and `OnUntrigger` events to after processing.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#triggerTarget
std::string target;
- std::uint8_t flags;
- std::uint8_t filter_flags;
+
+ std::uint8_t ZKREM("replaced by `start_enabled` and `send_untrigger`") flags;
+
+ /// \brief Determines whether the trigger is initially enabled.
+ ///
+ /// Enabled triggers will process incoming events and send outgoing events while disabled triggers do not.
+ /// Triggers can be activated and deactivated at runtime by sending them `OnEnable`, `OnDisable` or
+ /// `OnToggleEnabled` events.
+ ///
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#startEnabled
+ bool start_enabled;
+
+ /// \brief Whether to send and `OnUntrigger` event to the #target after the trigger receives an
+ /// `OnUntrigger` or `OnUntouch` event.
+ ///
+ /// Only fires the `OnUntrigger` event if #react_to_on_trigger and #react_to_on_touch are set
+ /// to `TRUE` respectively.
+ ///
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#sendUntrigger
+ bool send_untrigger;
+
+ std::uint8_t ZKREM("replaced by `react_to_*` and `respond_to_*`") filter_flags;
+
+ /// \brief Whether this trigger should react to `OnTrigger` events.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#reactToOnTrigger
+ bool react_to_on_trigger;
+
+ /// \brief Whether this trigger should react to `OnTouch` events.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#reactToOnTouch
+ bool react_to_on_touch;
+
+ /// \brief Whether this trigger should react to `OnDamage` events.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#reactToOnDamage
+ bool react_to_on_damage;
+
+ /// \brief Whether this trigger should process events coming from inanimate objects.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#respondToObject
+ bool respond_to_object;
+
+ /// \brief Whether this trigger should process events coming from the player.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#respondToPC
+ bool respond_to_pc;
+
+ /// \brief Whether this trigger should process events coming from NPCs.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#respondToNPC
+ bool respond_to_npc;
+
+ /// \brief Whether this trigger should process events coming from VObjects with this name.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#respondToVobName
std::string vob_target;
+
+ /// \brief The number of times the trigger will process incoming events.
+ ///
+ /// If set to `-1` the trigger will process an infinite number of events.
+ ///
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#numCanBeActivated
std::int32_t max_activation_count;
+
+ /// \brief The number of seconds that have to elapse after processing an event before the trigger will
+ /// process additional events.
+ ///
+ /// All events received by the trigger during that time are ignored.
+ ///
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#retriggerWaitSec
float retrigger_delay_sec;
+
+ /// \brief The amount of damage which must be dealt for the trigger to react to an `OnDamage` event.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#damageThreshold
float damage_threshold;
+
+ /// \brief The number of seconds to wait before emitting the `OnTrigger` event after processing.
+ /// \see https://zk.gothickit.dev/engine/objects/zCTrigger/#fireDelaySec
float fire_delay_sec;
// Save-game only variables
@@ -87,17 +164,18 @@ namespace zenkit {
std::shared_ptr