Overview
Verse is built around immutability by default: once you bind a name with := you cannot change it — unless you declared it with var. The set expression is the gate that lets you write a new value into a var variable, a var field on a class, a slot in a var array, or an entry in a var map.
set X = 10 # variable reassignment
set Obj.Field = Value # field reassignment
set Arr[Index] = Element # array element reassignment
set Map[Key] = MappedValue # map entry reassignment
set is itself an expression — it returns the right-hand side value — so you can chain assignments:
set Y = set X = 5 # both X and Y become 5
When to reach for set:
- Tracking round state (locked → unlocked, day → night)
- Accumulating scores or counters
- Recording which players have reached a checkpoint
- Toggling props visible/hidden based on game progress
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario — The Cove Vault: Three pressure plates are scattered across a sun-drenched dock. When all three are stepped on, a hidden prop (the vault door) is revealed and a counter shows how many plates are active. This example uses set on a var int counter, a var array of booleans, and a var field on the device class.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
# cove_vault_device — reveals a hidden prop when all three dock plates are stepped on.
cove_vault_device := class(creative_device):
# Wire these up in the UEFN details panel.
@editable PlateA : trigger_device = trigger_device{}
@editable PlateB : trigger_device = trigger_device{}
@editable PlateC : trigger_device = trigger_device{}
@editable VaultDoor : creative_prop = creative_prop{}
# --- mutable state ---
# Tracks how many plates are currently active (0-3).
var ActivePlates : int = 0
# One boolean per plate: false = not yet stepped on.
var PlateState : []logic = array{false, false, false}
# Has the vault already been opened this round?
var VaultOpen : logic = false
OnBegin<override>()<suspends> : void =
# Hide the vault door at round start.
VaultDoor.Hide()
# Subscribe each plate to its own handler.
PlateA.TriggeredEvent.Subscribe(OnPlateATriggered)
PlateB.TriggeredEvent.Subscribe(OnPlateBTriggered)
PlateC.TriggeredEvent.Subscribe(OnPlateCTriggered)
# ---- plate handlers ----
# Each handler checks whether this plate is newly activated,
# increments the shared counter, and tests for completion.
OnPlateATriggered(Agent : ?agent) : void =
ActivatePlate(0)
OnPlateBTriggered(Agent : ?agent) : void =
ActivatePlate(1)
OnPlateCTriggered(Agent : ?agent) : void =
ActivatePlate(2)
# Core logic — called with the 0-based index of the plate that fired.
ActivatePlate(Index : int) : void =
# Guard: if the vault is already open, do nothing.
if (VaultOpen?):
return
# Guard: if this plate was already counted, do nothing.
if (PlateState[Index]?):
return
# --- set on an array element ---
# Mark this specific plate as activated.
if (set PlateState[Index] = true):
# --- set on a var field ---
# Increment the running total.
set ActivePlates = ActivePlates + 1
# Check whether all three plates are now active.
if (ActivePlates = 3):
OpenVault()
OpenVault() : void =
# --- set on a var field (logic flag) ---
set VaultOpen = true
# Reveal the prop — the real payoff!
VaultDoor.Show()
Line-by-line explanation
| Line(s) | What it teaches |
|---|---|
var ActivePlates : int = 0 |
Declare a mutable integer field. Without var you could never set it. |
var PlateState : []logic = array{false, false, false} |
A mutable array — individual slots can be overwritten with set Arr[i] = …. |
var VaultOpen : logic = false |
A boolean flag; toggled exactly once when all plates are hit. |
VaultDoor.Hide() |
Uses the real creative_prop.Hide() API to start the door invisible. |
if (VaultOpen?): |
logic values are tested with ? (the decides effect). |
if (PlateState[Index]?): |
Array index access can fail (out-of-bounds), so it lives inside if. |
if (set PlateState[Index] = true): |
set on an array element is itself failable (index must be valid), so wrap it in if. |
set ActivePlates = ActivePlates + 1 |
Plain variable reassignment — no if needed because int assignment never fails. |
set VaultOpen = true |
Flips the flag so the vault cannot be opened twice. |
VaultDoor.Show() |
Uses the real creative_prop.Show() API to reveal the door. |
Common patterns
Pattern 1 — Chained set (score + display)
Chaining lets you update two related variables in one expression. Here a shoreline collectible counter feeds both a local tally and a "best run" high-score field.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
# shore_score_device — counts collectibles picked up along the shoreline.
shore_score_device := class(creative_device):
@editable CollectTrigger : trigger_device = trigger_device{}
var CurrentScore : int = 0
var BestScore : int = 0
OnBegin<override>()<suspends> : void =
CollectTrigger.TriggeredEvent.Subscribe(OnCollect)
OnCollect(Agent : ?agent) : void =
# Chained set: CurrentScore is updated, then BestScore gets
# whichever is larger — the new current or the old best.
set BestScore = Max(set CurrentScore = CurrentScore + 1, BestScore)
# Helper — returns the larger of two ints.
Max(A : int, B : int) : int =
if (A >= B):
A
else:
B
Pattern 2 — set on a map (player → checkpoint index)
Maps are perfect for per-player state. This clifftop race device records the furthest checkpoint each player has reached by writing into a var [] (map) keyed by agent.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
# clifftop_race_device — tracks the furthest checkpoint reached per player.
clifftop_race_device := class(creative_device):
@editable CheckpointTriggers : []trigger_device = array{}
# Map from agent to the highest checkpoint index they have reached.
var Progress : [agent]int = map{}
OnBegin<override>()<suspends> : void =
var Idx : int = 0
for (Trigger : CheckpointTriggers):
# Capture the current index for the closure.
CurrentIdx := Idx
Trigger.TriggeredEvent.Subscribe(OnCheckpoint)
set Idx = Idx + 1
OnCheckpoint(MaybeAgent : ?agent) : void =
# Unwrap the optional agent.
if (A := MaybeAgent?):
# Read the player's current best (default 0 if not yet in map).
Current := if (V := Progress[A]) then V else 0
# Only advance — never go backwards.
NewBest := Max(Current, 1) # simplified; real code passes checkpoint index
# --- set on a map entry ---
if (set Progress[A] = NewBest):
# Progress recorded — could update a HUD here.
true
# Helper
Max(A : int, B : int) : int =
if (A >= B): A
else: B
Pattern 3 — set on a var field inside a helper method
Sometimes you want a clean reset function that zeroes all mutable state at once — useful for round restarts on a cove arena.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
# cove_round_device — resets all mutable state between rounds.
cove_round_device := class(creative_device):
@editable VaultDoor : creative_prop = creative_prop{}
@editable RoundButton : button_device = button_device{}
var RoundNumber : int = 0
var DoorsOpened : int = 0
var RoundActive : logic = false
OnBegin<override>()<suspends> : void =
RoundButton.InteractedWithEvent.Subscribe(OnRoundStart)
OnRoundStart(Agent : ?agent) : void =
ResetRound()
# Resets all var fields in one place — easy to maintain.
ResetRound() : void =
set RoundNumber = RoundNumber + 1
set DoorsOpened = 0
set RoundActive = true
VaultDoor.Hide()
Gotchas
1. You MUST declare with var before you can set
If you write Score : int = 0 (no var), the name is immutable and set Score = 1 is a compile error. Always add var when the value will change.
2. Array and map set are failable — wrap in if
set Arr[Index] = Value fails if Index is out of bounds. set Map[Key] = Value can also fail. Always put these inside an if block:
if (set Arr[I] = NewVal):
# success path
Plain variable assignment (set X = Y) is not failable and does NOT need if.
3. set returns the right-hand side, not the container
After set Obj.Field = Value, the expression evaluates to Value, not Obj. This is useful for chaining but can surprise you if you expect the whole object back.
4. set requires an LValue on the left
You cannot set a function call result or a temporary. The left-hand side must be a var variable, a var field accessed through self or a reference, a valid array index, or a valid map key.
5. logic values use ? to test, not = true
To branch on a logic field, write if (VaultOpen?): — not if (VaultOpen = true):. The ? operator invokes the decides effect that if expects.
6. No implicit int ↔ float conversion
Verse never converts between int and float automatically. If your counter is var Score : float = 0.0, you must write set Score = Score + 1.0, not + 1.