Overview
Integer math is the quiet workhorse behind almost every game system that repeats: every Nth wave, every 3rd chest, a phase that loops 0→1→2→0. Verse gives you two operators for this:
- Integer division
A / B— but note: in Verse the/operator on twoints produces arational, not anint. To get a whole-number quotient you divide and floor, or you keep a running counter and use subtraction/Mod. The safe, always-intcompanion isMod. Mod—A Mod Bgives the remainder after dividingAbyB.7 Mod 3 = 1. This is the single most useful operator for cycles:Counter Mod 3walks 0,1,2,0,1,2… forever.
The game problem: imagine a pirate cove where a trigger_device fires once per incoming wave. You want every 4th wave to be a big one that starts a timer_device countdown (a warning before the tide floods the dock). That "every 4th" logic is exactly WaveCount Mod 4 = 0. Reach for integer division and Mod whenever gameplay repeats on a fixed interval.
API Reference
timer_device
Provides a way to keep track of the time something has taken, either for scoreboard purposes, or to trigger actions. It can be configured in several ways, either acting as a countdown to an event that is triggered at the end, or as a stopwatch for an action that needs to be completed before a set time runs out.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
timer_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
SuccessEvent |
SuccessEvent<public>:listenable(?agent) |
Signaled when the timer completes or ends with success. Sends the agent that activated the timer, if any. |
FailureEvent |
FailureEvent<public>:listenable(?agent) |
Signaled when the timer completes or ends with failure. Sends the agent that activated the timer, if any. |
StartUrgencyModeEvent |
StartUrgencyModeEvent<public>:listenable(?agent) |
Signaled when the timer enters Urgency Mode. Sends the agent that activated the timer, if any. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>(Agent:agent):void |
Enables this device for Agent. |
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>(Agent:agent):void |
Disables this device for Agent. While disabled this device will not receive signals. |
Disable |
Disable<public>():void |
Disables this device. While disabled this device will not receive signals. |
ResetForAll |
ResetForAll<public>(Agent:agent):void |
Resets the timer back to its base time and stops it for all agents. |
ResetForAll |
ResetForAll<public>():void |
Resets the timer back to its base time and stops it for all agents. |
Start |
Start<public>(Agent:agent):void |
Starts the timer for Agent. |
Start |
Start<public>():void |
Starts the timer. |
Pause |
Pause<public>(Agent:agent):void |
Pauses the timer for Agent. |
Pause |
Pause<public>():void |
Pauses the timer. |
Resume |
Resume<public>(Agent:agent):void |
Resumes the timer for Agent. |
Resume |
Resume<public>():void |
Resumes the timer. |
Complete |
Complete<public>(Agent:agent):void |
Completes the timer for Agent. |
Complete |
Complete<public>():void |
Completes the timer. |
StartForAll |
StartForAll<public>(Agent:agent):void |
Starts the timer for all agents. |
StartForAll |
StartForAll<public>():void |
Starts the timer for all agents. |
PauseForAll |
PauseForAll<public>(Agent:agent):void |
Pauses the timer for all agents. |
PauseForAll |
PauseForAll<public>():void |
Pauses the timer for all agents. |
ResumeForAll |
ResumeForAll<public>(Agent:agent):void |
Resumes the timer for all agents. |
ResumeForAll |
ResumeForAll<public>():void |
Resumes the timer for all agents. |
CompleteForAll |
CompleteForAll<public>(Agent:agent):void |
Completes the timer for all agents. |
CompleteForAll |
CompleteForAll<public>():void |
Completes the timer for all agents. |
Save |
Save<public>(Agent:agent):void |
Saves this device's data for Agent. |
Load |
Load<public>(Agent:agent):void |
Loads this device's saved data for Agent. |
ClearPersistenceData |
ClearPersistenceData<public>(Agent:agent):void |
Clears this device's saved data for Agent. |
ClearPersistenceDataForAll |
ClearPersistenceDataForAll<public>(Agent:agent):void |
Clears this device's saved data for all agents. |
ClearPersistenceDataForAll |
ClearPersistenceDataForAll<public>():void |
Clears this device's saved data for all agents. |
SetActiveDuration |
SetActiveDuration<public>(Time:float, Agent:agent):void |
Sets the remaining time (in seconds) on the timer, if active, on Agent. |
SetActiveDuration |
SetActiveDuration<public>(Time:float):void |
Sets the remaining time (in seconds) on the timer, if active. Use this function if the timer is set to use the same time for all agent's. |
GetActiveDuration |
GetActiveDuration<public>(Agent:agent)<transacts>:float |
Returns the remaining time (in seconds) on the timer for Agent. |
GetActiveDuration |
GetActiveDuration<public>()<transacts>:float |
Returns the remaining time (in seconds) on the timer if it is set to be global. |
SetLapTime |
SetLapTime<public>(Agent:agent):void |
Sets the lap time indicator for Agent. |
SetLapTimeForAll |
SetLapTimeForAll<public>(Agent:agent):void |
Sets the lap time indicator for all agents. |
SetLapTimeForAll |
SetLapTimeForAll<public>():void |
Sets the lap time indicator for all agents. |
SetMaxDuration |
SetMaxDuration<public>(Time:float):void |
Sets the maximum duration of the timer (in seconds). |
GetMaxDuration |
GetMaxDuration<public>()<transacts>:float |
Returns the maximum duration of the timer (in seconds). |
IsStatePerAgent |
IsStatePerAgent<public>()<transacts><decides>:void |
Succeeds if this device is tracking timer state for each individual agent independently. Fails if state is being tracked globally for all agent's. |
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. |
vector3
3-dimensional vector with
floatcomponents.
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse).
vector3<native><public> := struct<concrete><computes><persistable><uht_comparable>:
Walkthrough
Here is the full cove scenario. A trigger fires each time a wave rolls in. We keep an int counter. Every 4th wave (Mod 4 = 0) we start a countdown timer; every 8th wave we complete/reset it as a "big set" ends. We also use integer division to compute which set number we're on (WaveCount / 4, floored) and set the timer's remaining duration from it.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Verse }
cove_waves := class(creative_device):
# The plate/trigger a wave steps on each time it rolls in.
@editable
WaveTrigger : trigger_device = trigger_device{}
# The countdown shown when a big wave set arrives.
@editable
FloodTimer : timer_device = timer_device{}
# Running count of waves that have arrived this game.
var WaveCount : int = 0
OnBegin<override>()<suspends>:void =
# React to every wave that triggers the plate.
WaveTrigger.TriggeredEvent.Subscribe(OnWave)
# If the timer succeeds (survived the countdown), reset it for reuse.
FloodTimer.SuccessEvent.Subscribe(OnTimerDone)
OnWave(Agent : ?agent) : void =
# Advance the wave counter by one.
set WaveCount = WaveCount + 1
# Mod is the always-int cycle operator: 0 means "every 4th wave".
# Mod is fallible (<decides>), so bind it in a failure context first.
if (R := Mod[WaveCount, 4]):
if (R = 0):
# Integer set number: how many complete sets of 4 have passed.
# We build a floored quotient by counting down with subtraction.
SetNumber := FlooredDiv(WaveCount, 4)
# Give bigger sets a longer warning: 5 seconds per set.
Seconds := SetNumber * 5
FloodTimer.SetActiveDuration(IntToFloat(Seconds))
FloodTimer.StartForAll()
# Every 8th wave closes out the big set early.
if (R8 := Mod[WaveCount, 8]):
if (R8 = 0):
FloodTimer.CompleteForAll()
OnTimerDone(Agent : ?agent) : void =
# Countdown ended successfully — reset for the next big set.
FloodTimer.ResetForAll()
# Floored integer quotient built only from int-safe operations.
FlooredDiv(A : int, B : int) : int =
var Count : int = 0
var Remaining : int = A
loop:
if (Remaining < B):
break
set Remaining = Remaining - B
set Count = Count + 1
Count
# int -> float, since Verse does NOT auto-convert.
IntToFloat(N : int) : float =
1.0 * N```
**Line by line:**
- `@editable WaveTrigger`/`FloodTimer` — the two placed devices. You MUST declare them as fields; calling `trigger_device{}.Trigger()` on a bare literal does nothing on your map.
- `var WaveCount : int = 0` — our cycle counter. `var` because we mutate it.
- `WaveTrigger.TriggeredEvent.Subscribe(OnWave)` — every step on the plate calls `OnWave`. The event is `listenable(?agent)`, so the handler takes `(Agent : ?agent)`.
- `set WaveCount = WaveCount + 1` — advance the count.
- `WaveCount Mod 4 = 0` — the heart of it. `Mod` returns the remainder; when it's `0`, the count is an exact multiple of 4.
- `FlooredDiv(WaveCount, 4)` — a whole-number quotient. We avoid the `int/int → rational` pitfall by subtracting `B` repeatedly and counting.
- `SetNumber * 5` — int × int is fine and stays `int`.
- `FloodTimer.SetActiveDuration(IntToFloat(Seconds))` — `SetActiveDuration` wants a `float`, so we convert with `1.0 * N`.
- `FloodTimer.StartForAll()` / `CompleteForAll()` / `ResetForAll()` — real timer_device methods that make the countdown run, snap to finish, and rewind.
## Common patterns
**1. `Mod` to fire a trigger only every 3rd chest** — call `Trigger()` directly from code on the Nth event.
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
chest_bonus := class(creative_device):
@editable
ChestPlate : trigger_device = trigger_device{}
@editable
BonusTrigger : trigger_device = trigger_device{}
var Opened : int = 0
OnBegin<override>()<suspends>:void =
ChestPlate.TriggeredEvent.Subscribe(OnChest)
OnChest(Agent : ?agent) : void =
set Opened = Opened + 1
# Every 3rd chest fires the bonus device from code.
if (Opened Mod 3 = 0):
BonusTrigger.Trigger()
2. Integer division to scale trigger reset delay by tier. Fewer remaining triggers → shorter cooldown.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
cannon_cooldown := class(creative_device):
@editable
Cannon : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
Cannon.SetMaxTriggerCount(6)
Cannon.TriggeredEvent.Subscribe(OnFire)
OnFire(Agent : ?agent) : void =
Remaining := Cannon.GetTriggerCountRemaining()
# Halve the remaining count with a floored quotient, use as seconds.
Tier := FlooredDiv(Remaining, 2)
Cannon.SetResetDelay(1.0 * Tier)
FlooredDiv(A : int, B : int) : int =
var Count : int = 0
var Remaining : int = A
loop:
if (Remaining < B). { break }
set Remaining = Remaining - B
set Count = Count + 1
Count
3. Mod to cycle a timer between short/long durations each wave.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
tide_phases := class(creative_device):
@editable
Beat : trigger_device = trigger_device{}
@editable
PhaseTimer : timer_device = timer_device{}
var Phase : int = 0
OnBegin<override>()<suspends>:void =
Beat.TriggeredEvent.Subscribe(OnBeat)
OnBeat(Agent : ?agent) : void =
set Phase = Phase + 1
# 0,1,2 cycle: even phases = long tide, odd = short.
if (Phase Mod 2 = 0):
PhaseTimer.SetActiveDuration(10.0)
else:
PhaseTimer.SetActiveDuration(4.0)
PhaseTimer.StartForAll()
Gotchas
int / intis NOT anintin Verse — it's arational. If you writeWaveCount / 4expecting a whole number, you'll get a type mismatch when you try to use it where anintis required. UseModfor cycles, and build a floored quotient with repeated subtraction (as inFlooredDiv) when you truly need anintquotient.- No implicit int→float.
SetActiveDurationandSetResetDelaytakefloat. Convert with1.0 * N(or keep a float directly). Passing anintwill not compile. Modsign with negatives.Modfollows the sign of the dividend, so-7 Mod 3is not the same as7 Mod 3. Keep counters non-negative (start at 0 and only add) so your cycle logic stays predictable.?agentmust be unwrapped. The handler receives(Agent : ?agent). If you need the actual player, doif (A := Agent?):first. In the wave example we don't need the agent, so we use theForAlltimer methods instead of per-agent ones.- Bare device literals do nothing.
timer_device{}written inline is a default value for an@editablefield — it won't drive the timer you placed on the cove unless you assign the real device in the Details panel and call methods through the field. Mod 0errors. NeverModby zero. If a divisor can be data-driven, guard it (if (B > 0):) before using it.