Reference Verse compiles

trigger_device & maps: Counting Coins on the Pirate Cove

The trigger_device is the humble relay at the heart of countless islands — it fires an event and lets your Verse code react. In this bright cel-shaded pirate-cove moment, we pair it with a Verse `map` so every buccaneer who steps on a dock plate gets their own coin tally added and updated.

Updated Examples verified on the live UEFN compiler

Overview

A trigger_device is a relay: something bumps it (a player, a linked device, or your own Verse code) and it fires its TriggeredEvent. You subscribe a handler to that event and run whatever game logic you want. It also carries useful runtime controls — you can Enable/Disable it, cap how many times it can fire with SetMaxTriggerCount, read the remaining fires with GetTriggerCountRemaining, and tune timing with SetResetDelay / SetTransmitDelay.

The game problem we're solving: on a sunny 2D cel-shaded pirate cove, players run across a wooden dock plate to "grab" treasure. Each pirate should have their OWN running coin count. That's a classic use for a Verse map[agent]int — where we add an entry the first time we see a player, then bump it on every later trigger. The trigger_device is the sensor; the map is the ledger.

Reach for a trigger_device whenever you want a physical spot or a code signal to kick off logic, and reach for a map whenever you need to remember something per player.

API Reference

trigger_device

Used to relay events to other linked devices.

Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from trigger_base_device.

trigger_device<public> := class<concrete><final>(trigger_base_device):

Events (subscribe a handler to react):

Event Signature Description
TriggeredEvent TriggeredEvent<public>:listenable(?agent) Signaled when an agent triggers this device. Sends the agent that used this device. Returns false if no agent triggered the action (ex: it was triggered through code).

Methods (call these to make the device act):

Method Signature Description
Trigger Trigger<public>(Agent:agent):void Triggers this device with Agent being passed as the agent that triggered the action. Use an agent reference when this device is setup to require one (for instance, you want to trigger the device only with a particular agent.
Trigger Trigger<public>():void Triggers this device, causing it to activate its TriggeredEvent event.
Enable Enable<public>():void Enables this device.
Disable Disable<public>():void Disables this device.
SetMaxTriggerCount SetMaxTriggerCount<public>(MaxCount:int):void Sets the maximum amount of times this device can trigger. * 0 can be used to indicate no limit on trigger count. * MaxCount is clamped between [0,20].
GetMaxTriggerCount GetMaxTriggerCount<public>()<transacts>:int Gets the maximum amount of times this device can trigger. * 0 indicates no limit on trigger count.
GetTriggerCountRemaining GetTriggerCountRemaining<public>()<transacts>:int Returns the number of times that this device can still be triggered before hitting GetMaxTriggerCount. Returns 0 if GetMaxTriggerCount is unlimited.
SetResetDelay SetResetDelay<public>(Time:float):void Sets the time (in seconds) after triggering, before the device can be triggered again (if MaxTrigger count allows).
GetResetDelay GetResetDelay<public>()<transacts>:float Gets the time (in seconds) before the device can be triggered again (if MaxTrigger count allows).
SetTransmitDelay SetTransmitDelay<public>(Time:float):void Sets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered.
GetTransmitDelay GetTransmitDelay<public>()<transacts>:float Gets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered.

player

Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse). Inherited members are merged from agent.

player<native><public> := class<unique><persistent><module_scoped_var_weak_map_key><epic_internal>(agent):

vector3

3-dimensional vector with float components.

Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse).

vector3<native><public> := struct<concrete><computes><persistable><uht_comparable>:

Walkthrough

Picture a dock plank on the cove. A trigger_device sits on it. When a pirate steps on, we look them up in our coin ledger. If they're not in the map yet, we add an entry for them; otherwise we increment their existing count. We also cap the plank so it can't be spammed forever, and stagger its reset.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

cove_treasure_ledger := class(creative_device):

    # The dock plank sensor placed on the cove. Drag your trigger here in the editor.
    @editable
    DockPlank : trigger_device = trigger_device{}

    # Optional: a message the whole crew can hear (localized text).
    CoinMessage<localizes>(Count:int) : message = "Arrr! Your coin count is now {Count}"

    # The per-player coin ledger. A map that starts empty.
    var CoinLedger : [agent]int = map{}

    OnBegin<override>()<suspends>:void =
        # Cap the plank so it can only fire 20 times total, then rest 1s between fires.
        DockPlank.SetMaxTriggerCount(20)
        DockPlank.SetResetDelay(1.0)
        DockPlank.Enable()

        # React whenever a pirate steps on the plank.
        DockPlank.TriggeredEvent.Subscribe(OnPlankStepped)

    OnPlankStepped(Agent : ?agent) : void =
        # The event may fire with no agent (e.g. code-triggered). Unwrap safely.
        if (Pirate := Agent?):
            AddOrBumpCoins(Pirate)

    AddOrBumpCoins(Pirate : agent) : void =
        # Look the pirate up in the ledger.
        if (Current := CoinLedger[Pirate]):
            # They already have an entry — bump it.
            if (CoinLedger[Pirate] = Current + 1):
                Print(CoinMessage(Current + 1))
        else:
            # First time we see them — ADD A NEW MAP ENTRY starting at 1.
            if (CoinLedger[Pirate] = 1):
                Print(CoinMessage(1))```

**Line by line:**
- `@editable DockPlank : trigger_device`  you MUST declare the placed device as an editable field, then drag the real trigger onto it in the editor. A bare `trigger_device{}.Trigger()` would fail with 'Unknown identifier'.
- `var CoinLedger : [agent]int = map{}`  an empty map keyed by `agent`. This is our ledger.
- In `OnBegin`, `SetMaxTriggerCount(20)` clamps how many times the plank can fire; `SetResetDelay(1.0)` forces a one-second cooldown; `Enable()` turns it on.
- `DockPlank.TriggeredEvent.Subscribe(OnPlankStepped)` wires the event to our method. `TriggeredEvent` is a `listenable(?agent)`, so the handler receives `?agent`.
- `if (Pirate := Agent?)` unwraps the optional. If the trigger fired without an agent, we skip.
- `if (Current := CoinLedger[Pirate])`  a map lookup **succeeds** if the key exists. If it does, we `set CoinLedger[Pirate] = Current + 1`. If it fails (`else`), we **add a fresh entry** with `set CoinLedger[Pirate] = 1`. That `set ...[key] = value` on a missing key is exactly how you *add* a map entry in Verse.

## Common patterns

**1. Code-trigger the plank and read remaining fires.** Sometimes a cutscene or another device should fire the plank for a specific pirate. Use the `Trigger(Agent)` overload, then check how many fires are left with `GetTriggerCountRemaining`.

```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

cove_code_trigger := class(creative_device):

    @editable
    DockPlank : trigger_device = trigger_device{}

    @editable
    Cannon : trigger_device = trigger_device{}

    OnBegin<override>()<suspends>:void =
        DockPlank.SetMaxTriggerCount(5)
        # When the cannon fires, fire the plank for that same pirate.
        Cannon.TriggeredEvent.Subscribe(OnCannonFired)

    OnCannonFired(Agent : ?agent) : void =
        if (Pirate := Agent?):
            DockPlank.Trigger(Pirate)
            Remaining := DockPlank.GetTriggerCountRemaining()
            Print("Plank fires left: {Remaining}")

2. Disable the plank once the treasure is claimed, and read timing back. Read the reset delay you configured, then shut the plank off so no one else can grab.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

cove_close_plank := class(creative_device):

    @editable
    DockPlank : trigger_device = trigger_device{}

    OnBegin<override>()<suspends>:void =
        DockPlank.SetResetDelay(2.5)
        DockPlank.SetTransmitDelay(0.5)
        DockPlank.Enable()
        DockPlank.TriggeredEvent.Subscribe(OnClaimed)

    OnClaimed(Agent : ?agent) : void =
        Delay := DockPlank.GetResetDelay()
        Transmit := DockPlank.GetTransmitDelay()
        Print("Reset {Delay}s, transmit {Transmit}s — treasure claimed, closing plank.")
        DockPlank.Disable()

3. A no-limit relay that forwards to a linked device. Set the max count to 0 for unlimited fires, then just relay every step onward by triggering another device.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

cove_relay := class(creative_device):

    @editable
    ShoreSensor : trigger_device = trigger_device{}

    @editable
    LighthouseRelay : trigger_device = trigger_device{}

    OnBegin<override>()<suspends>:void =
        ShoreSensor.SetMaxTriggerCount(0)  # 0 = no limit
        Max := ShoreSensor.GetMaxTriggerCount()
        ShoreSensor.Enable()
        ShoreSensor.TriggeredEvent.Subscribe(OnShoreStep)

    OnShoreStep(Agent : ?agent) : void =
        if (Pirate := Agent?):
            LighthouseRelay.Trigger(Pirate)
        else:
            LighthouseRelay.Trigger()

Gotchas

  • TriggeredEvent hands you a ?agent, not an agent. Always unwrap with if (Pirate := Agent?): before using it. Code-triggered fires can arrive with no agent.
  • Adding vs updating a map entry is the same set syntax. set CoinLedger[Pirate] = 1 adds the key if it's missing and overwrites it if it exists. Guard with a lookup (if (Current := CoinLedger[Pirate])) when you want different behavior for new vs existing pirates.
  • A map field must be var to change it. var CoinLedger : [agent]int = map{} — without var you can't set into it.
  • SetMaxTriggerCount is clamped to [0,20]. Passing 0 means unlimited; passing 100 quietly clamps to 20.
  • message params need localized text, not a raw string. Declare CoinMessage<localizes>(Count:int):message = "...{Count}" and call CoinMessage(3). There is no StringToMessage.
  • You cannot call a bare device. trigger_device{}.Enable() fails; the device must be an @editable field wired to a placed device in the editor.
  • No int↔float auto-convert. SetResetDelay takes a float (1.0), while SetMaxTriggerCount takes an int (20). Mixing them without the right literal won't compile.

Guides & scripts that use trigger_device

Step-by-step tutorials that put this object to work.

Build your own lesson with trigger_device

Generate a personalized, step-by-step lesson plan built around this object — grounded in this exact reference and our compile-verified knowledge base.

Build a lesson →