Reference Devices compiles

Score and Time: Wiring score_manager and timer from Verse

The score manager device is your scriptable points dispenser, and the timer device is the round clock that gives those points a deadline. This article shows you how to drive both entirely from Verse: award score with `Activate`, ramp payouts with `Increment`/`SetScoreAward`, then wire a `timer_device` around the scoring loop — start it when the round begins, pause and resume it mid-round, reset it when time runs out, and pay a bonus when a player beats the clock.

Updated Examples verified on the live UEFN compiler
Watch the Knotscore_manager_device in ~90 seconds.

Overview

The score manager device is the device you reach for whenever your game needs to give players points under script control. Instead of a static "step on this plate, get 10 points" setup, Verse lets you:

  • Decide when points are granted (Activate).
  • Decide how many points the next payout is worth (SetScoreAward, Increment, Decrement, SetToAgentScore).
  • Read a player's running total (GetCurrentScore, GetScoreAward).
  • React to payouts and to the device hitting its trigger cap (ScoreOutputEvent, MaxTriggersEvent).

Reach for it when you want a coin pickup, a kill-streak combo bonus, an objective completion reward, or a leaderboard-style scoring loop — anything where points are awarded conditionally and you want full control of the amount.

Scoring alone is only half of most game modes, though. The natural partner is the timer device: it turns open-ended point collection into a round — score all you want, but only while the clock is running. From Verse you can Start, Pause, Resume, and reset a timer_device, and react to it finishing via SuccessEvent / FailureEvent. The final section of this article wires both devices into one cooperating system: a timed score round.

A key detail: if the device's Activating Team option is set to a specific team, you should call the agent overloads (e.g. Activate(Player)), because the agent's team decides whether they're allowed to affect the device. The no-arg overloads grant to the configured default.

API Reference

score_manager_device

Used to manipulate scores using in-experience triggers. If Activating Team is set to a specific team, then you should use the agent overloads of each function. The agent's team will be used to determine if that agent is allowed to affect the state of the device.

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

score_manager_device<public> := class<concrete><final>(creative_device_base):

Events (subscribe a handler to react):

Event Signature Description
MaxTriggersEvent MaxTriggersEvent<public>:listenable(agent) Signaled when the this device reaches its maximum number of triggers as defined by Times Can Trigger. Sends the agent who last triggered the device.
ScoreOutputEvent ScoreOutputEvent<public>:listenable(agent) Signaled when the this device awards points to an agent. Sends the agent who received the points.

Methods (call these to make the device act):

Method Signature Description
Enable Enable<public>(Agent:agent):void Enables this device.
Enable Enable<public>():void Enables this device.
Disable Disable<public>(Agent:agent):void Disables this device.
Disable Disable<public>():void Disables this device.
Activate Activate<public>(Agent:agent):void Grant points to Agent.
Activate Activate<public>():void Grants points.
Increment Increment<public>(Agent:agent):void Increments the score quantity to be awarded by the next activation by 1.
Increment Increment<public>():void Increments the score quantity to be awarded by the next activation by 1.
Decrement Decrement<public>(Agent:agent):void Decrements the score quantity to be awarded by the next activation by 1.
Decrement Decrement<public>():void Decrements the score quantity to be awarded by the next activation by 1.
SetScoreAward SetScoreAward<public>(Value:int):void Sets the score to be awarded by the next activation to Value.
GetScoreAward GetScoreAward<public>()<transacts>:int Returns the score to be awarded by the next activation.
SetToAgentScore SetToAgentScore<public>(Agent:agent):void Sets the score to be awarded by the next activation to Agent's current score.
GetCurrentScore GetCurrentScore<public>(Agent:agent)<transacts>:int Returns the current score for Agent.

Walkthrough

Let's build a coin pickup combo system. A trigger_device represents a coin a player runs through. Each coin in a row makes the next coin worth 1 more point (a combo), and we read back the player's new total to show how scoring grew. We use Increment, GetScoreAward, Activate, GetCurrentScore, and we subscribe to ScoreOutputEvent.

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

# Coin combo scorer: each coin grabbed makes the next coin worth more.
coin_combo_device := class(creative_device):

    # The placed coin trigger the player runs through.
    @editable
    CoinTrigger : trigger_device = trigger_device{}

    # The placed score manager that hands out the points.
    @editable
    Scorer : score_manager_device = score_manager_device{}

    OnBegin<override>()<suspends>:void =
        # React whenever a coin is touched.
        CoinTrigger.TriggeredEvent.Subscribe(OnCoinGrabbed)
        # React whenever the score manager actually pays out.
        Scorer.ScoreOutputEvent.Subscribe(OnPointsAwarded)
        # Start the next payout worth a known amount.
        Scorer.SetScoreAward(10)

    # trigger_device hands us a ?agent — unwrap it before use.
    OnCoinGrabbed(MaybeAgent : ?agent) : void =
        if (Player := MaybeAgent?):
            # Bump the combo: next activation is worth +1.
            Scorer.Increment(Player)
            # Inspect what the next payout will be.
            NextAward := Scorer.GetScoreAward()
            Print("Combo! Next coin worth {NextAward}")
            # Grant the points to this player right now.
            Scorer.Activate(Player)

    # ScoreOutputEvent fires after points land — read the new total.
    OnPointsAwarded(Player : agent) : void =
        Total := Scorer.GetCurrentScore(Player)
        Print("Points awarded! Player total is now {Total}")

Line by line:

  • @editable CoinTrigger / @editable Scorer — these FIELDS are how Verse references the placed devices. You drop a trigger and a score manager in the level, then assign them in the device's Details panel. Without an @editable field you cannot call the device's methods.
  • OnBegin<override>()<suspends>:void — runs when the game starts. All subscriptions and setup happen here.
  • CoinTrigger.TriggeredEvent.Subscribe(OnCoinGrabbed) — wires the player stepping on the coin to our handler method.
  • Scorer.ScoreOutputEvent.Subscribe(OnPointsAwarded) — wires the device's payout signal to a second handler.
  • Scorer.SetScoreAward(10) — sets the first payout to 10 points.
  • OnCoinGrabbed(MaybeAgent : ?agent)TriggeredEvent is a listenable(?agent), so the handler receives an optional agent. if (Player := MaybeAgent?): unwraps it.
  • Scorer.Increment(Player) — adds 1 to the pending award, building the combo. We use the agent overload because the touching player's team gates the device.
  • Scorer.GetScoreAward() — reads what the next activation will pay (note the <transacts> effect; it's a pure read).
  • Scorer.Activate(Player) — actually grants the current pending award to this player.
  • OnPointsAwarded(Player : agent)ScoreOutputEvent is listenable(agent) (NOT optional), so this hands us a plain agent. We read GetCurrentScore(Player) to print the running total.

Common patterns

Fixed objective reward with SetScoreAward + Activate

A capture-point that grants a flat 250 points to whoever completes it.

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

objective_reward_device := class(creative_device):

    @editable
    CaptureButton : button_device = button_device{}

    @editable
    Scorer : score_manager_device = score_manager_device{}

    OnBegin<override>()<suspends>:void =
        CaptureButton.InteractedWithEvent.Subscribe(OnCaptured)

    OnCaptured(Player : agent) : void =
        # Lock the payout to exactly 250 then grant it.
        Scorer.SetScoreAward(250)
        Scorer.Activate(Player)

Copying one player's score onto a payout with SetToAgentScore

A "bounty" device that, when a hunter eliminates a target, awards the hunter points equal to the target's current score.

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

bounty_device := class(creative_device):

    @editable
    ClaimButton : button_device = button_device{}

    @editable
    Scorer : score_manager_device = score_manager_device{}

    OnBegin<override>()<suspends>:void =
        ClaimButton.InteractedWithEvent.Subscribe(OnClaim)

    OnClaim(Hunter : agent) : void =
        # Set the next award equal to the hunter's own score, then double it.
        Scorer.SetToAgentScore(Hunter)
        Base := Scorer.GetScoreAward()
        Print("Bounty base is {Base}")
        Scorer.Activate(Hunter)

Reacting to the trigger cap with MaxTriggersEvent + Disable

When a limited-supply reward chest has paid out its configured number of times, shut it down.

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

limited_chest_device := class(creative_device):

    @editable
    Scorer : score_manager_device = score_manager_device{}

    OnBegin<override>()<suspends>:void =
        Scorer.MaxTriggersEvent.Subscribe(OnExhausted)

    OnExhausted(Agent : agent) : void =
        Print("Chest exhausted by its last user.")
        # No more points from this device.
        Scorer.Disable()

Wiring in the timer: a timed score round

Scoring becomes a game the moment there's a clock on it. The timer device gives you that clock, and its Verse surface is a clean mirror of the score manager's: methods to drive it, events to react to.

The members we use (resolved from the live Epic digest, timer_device in Fortnite.digest.verse):

Member Signature What it does
Start / StartForAll Start<public>(Agent:agent):void / StartForAll<public>():void Starts the timer (for one agent, or for everyone).
Pause / PauseForAll Pause<public>(Agent:agent):void / PauseForAll<public>():void Freezes the clock.
Resume / ResumeForAll Resume<public>(Agent:agent):void / ResumeForAll<public>():void Lets a paused clock tick again.
Reset / ResetForAll Reset<public>():void / ResetForAll<public>():void Puts the timer back to its base time and stops it.
Complete / CompleteForAll Complete<public>(Agent:agent):void / CompleteForAll<public>():void Force-finishes the timer (fires SuccessEvent).
SuccessEvent SuccessEvent<public>:listenable(?agent) Timer completed or ended with success. Sends the activating agent, if any.
FailureEvent FailureEvent<public>:listenable(?agent) Timer completed or ended with failure (a countdown hitting zero). Sends the activating agent, if any.
StartUrgencyModeEvent StartUrgencyModeEvent<public>:listenable(?agent) The timer entered its configured Urgency Mode window.

Now the cooperating system. One device script owns both: a start button kicks off the round clock, coins pay points while it runs, a pause button freezes and unfreezes the clock, beating the clock pays a bonus, and time running out resets everything for the next round.

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

# One cooperating system: score_manager pays the points,
# timer_device decides when points can flow.
timed_score_round_device := class(creative_device):

    @editable
    StartButton : button_device = button_device{}

    @editable
    PauseButton : button_device = button_device{}

    @editable
    CoinTrigger : trigger_device = trigger_device{}

    @editable
    Scorer : score_manager_device = score_manager_device{}

    @editable
    RoundTimer : timer_device = timer_device{}

    # Tracks whether the clock is currently frozen.
    var Paused : logic = false

    OnBegin<override>()<suspends>:void =
        StartButton.InteractedWithEvent.Subscribe(OnRoundStart)
        PauseButton.InteractedWithEvent.Subscribe(OnPauseToggled)
        CoinTrigger.TriggeredEvent.Subscribe(OnCoinGrabbed)
        # The timer's finish lines: beat the clock, or run out of time.
        RoundTimer.SuccessEvent.Subscribe(OnClockBeaten)
        RoundTimer.FailureEvent.Subscribe(OnTimeUp)
        # Each coin is worth 25 during the round.
        Scorer.SetScoreAward(25)

    OnRoundStart(Player : agent) : void =
        # Reset puts the timer back to base time AND stops it,
        # so a fresh Start always runs the full round length.
        RoundTimer.ResetForAll()
        RoundTimer.StartForAll()
        set Paused = false
        Print("Round started — collect coins before time runs out!")

    OnPauseToggled(Player : agent) : void =
        if (Paused?):
            RoundTimer.ResumeForAll()
            set Paused = false
            Print("Clock resumed.")
        else:
            RoundTimer.PauseForAll()
            set Paused = true
            Print("Clock paused.")

    OnCoinGrabbed(MaybeAgent : ?agent) : void =
        if (Player := MaybeAgent?):
            # Points only matter while the round clock runs —
            # the same Activate you already know.
            Scorer.Activate(Player)

    # SuccessEvent is listenable(?agent): the finishing agent is optional.
    OnClockBeaten(MaybeAgent : ?agent) : void =
        if (Player := MaybeAgent?):
            # Beating the clock pays a flat 100-point bonus.
            Scorer.SetScoreAward(100)
            Scorer.Activate(Player)
            Total := Scorer.GetCurrentScore(Player)
            Print("Beat the clock! Total is now {Total}")
        # Next round's coins are worth 25 again.
        Scorer.SetScoreAward(25)

    OnTimeUp(MaybeAgent : ?agent) : void =
        Print("Time's up! Round over.")
        # Stop and rewind the clock so the start button
        # can launch a clean next round.
        RoundTimer.ResetForAll()

How the two devices cooperate, line by line:

  • Scorer.SetScoreAward(25) in OnBegin — the score half is configured once; every Activate(Player) during the round pays 25.
  • OnRoundStartResetForAll() stops the timer and rewinds it to its base time; the StartForAll() right after launches a full-length round. Calling Start without the reset would resume from wherever the clock last stopped.
  • OnPauseToggled — one button, two behaviors: PauseForAll() freezes the countdown, ResumeForAll() un-freezes it. The var Paused : logic field remembers which side we're on; if (Paused?): is how you branch on a logic value.
  • OnClockBeaten(MaybeAgent : ?agent) — the timer's SuccessEvent is listenable(?agent) (the timer can finish without a specific activating agent), so this handler unwraps exactly like a trigger handler does. On success we retarget the payout (SetScoreAward(100)), grant it, and read back the total with GetCurrentScore.
  • OnTimeUpFailureEvent fires when a countdown hits zero. We ResetForAll() so the system is ready for the next press of the start button. Score is untouched: players keep what they earned.
  • Division of labor: the score manager never knows about time, the timer never knows about points. The Verse device is the conductor — it listens to both and decides how they cooperate. That's the pattern to reuse for any multi-device system.

Gotchas

  • Two different event shapes. TriggeredEvent on a trigger is listenable(?agent) (optional — must unwrap with MaybeAgent?), but the score manager's own ScoreOutputEvent and MaxTriggersEvent are listenable(agent) (plain agent — no unwrap). Don't write Agent? on those or it won't compile.
  • Activate is what actually grants. SetScoreAward, Increment, Decrement, and SetToAgentScore only configure the pending amount. Nothing reaches a player until you call Activate (or Activate(Agent)).
  • Agent vs no-arg overloads. If your device's Activating Team option is a specific team, use the agent overloads so the agent's team is checked. The no-arg Activate() grants per the device's default configuration and ignores per-agent team gating.
  • GetScoreAward / GetCurrentScore are <transacts> reads. They're pure and return an int directly — no failure to handle — but you can't call them where side-effects aren't allowed in a speculative context that gets rolled back. In normal handler code they're fine.
  • Editable fields are mandatory. Calling Scorer.Activate() only works because Scorer is an @editable field bound to a placed device. A bare score_manager_device{}.Activate() does nothing and won't reference your real device.
  • No int↔float auto-convert. Score values are int. If you ever multiply by a float multiplier, you must convert explicitly — don't pass a float where SetScoreAward(Value:int) expects an int.
  • Timer finish events are optionals too. SuccessEvent, FailureEvent, and StartUrgencyModeEvent on timer_device are listenable(?agent) — the timer may finish without a specific activating agent — so their handlers take MaybeAgent : ?agent and unwrap, exactly like a trigger's TriggeredEvent (and unlike the score manager's plain-agent events).
  • Reset stops the clock; it does not restart it. Resetting a timer_device rewinds it to base time and stops it. To relaunch a round you need the pair: reset, then Start/StartForAll. And a plain Resume after Pause continues from where the clock froze — it never rewinds.
  • Timer state can be per-agent or global. Start(Agent)/Pause(Agent) drive one agent's clock; the *ForAll variants drive everyone's. Mixing them against a device configured the other way is a classic "why didn't my timer move" bug — match your calls to the device's Timer Is Per Agent setting.

Device Settings & Options

The score_manager_device User Options panel in the UEFN editor — every setting you can tune.

Score Manager Device settings and options panel in the UEFN editor — Score Value, Score Award Type
Score Manager Device — User Options in the UEFN editor: Score Value, Score Award Type
⚙️ Settings on this device (2)

Setting names read from the panel above — may be partial; the screenshots are the source of truth.

Score Value
Score Award Type

Guides & scripts that use score_manager_device

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

Build your own lesson with score_manager_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 →