Overview
The rng_device is UEFN's built-in random number generator. You configure a Value Limit 1 (minimum) and Value Limit 2 (maximum) plus a Winning Value threshold in the Details panel, then call Activate() to roll. Depending on what comes up, the device signals one of four events:
WinEvent— the roll was >= Winning Value.LoseEvent— the roll was < Winning Value.RolledMaxEvent— the roll hit the configured maximum exactly.RolledMinEvent— the roll hit the configured minimum exactly.
Reach for the rng_device whenever you want server-authoritative randomness without rolling your own math: a casino slot machine, a mystery reward chest, a 1-in-100 jackpot, a random spawn picker, or a coin-flip mechanic that decides which door opens. Because the device handles the threshold comparison for you, you just subscribe to the event you care about and run your game logic in the handler.
Note there are two Activate overloads: Activate(Agent:agent) (roll on behalf of a specific player — useful when you want to know who rolled) and Activate() (roll with no agent context). You can Enable/Disable the device to gate rolling, and Cancel() to stop an in-progress generation.
API Reference
rng_device
Used to generate random numbers between a minimum and maximum value. Events are signaled when numbers are generated. * Value Limit 1 is the minimum value for generation. * Value Limit 2 is the maximum value for generation.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
rng_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
WinEvent |
WinEvent<public>:listenable(tuple()) |
Signaled when the generated number >= Winning Value. |
LoseEvent |
LoseEvent<public>:listenable(tuple()) |
Signaled when the generated number < Winning Value. |
RolledMaxEvent |
RolledMaxEvent<public>:listenable(tuple()) |
Signaled when the generated number = maximum. |
RolledMinEvent |
RolledMinEvent<public>:listenable(tuple()) |
Signaled when the generated number = minimum. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
Activate |
Activate<public>(Agent:agent):void |
Randomly generate a number between Value Limit 1 and Value Limit 2. * If the number is >= Winning Value then WinEvent is fired. * If the number is < Winning Value then LoseEvent is fired. * If the number = minimum then `RolledMi |
Activate |
Activate<public>():void |
Randomly roll a number within the configured min + max value range. * If the number is >= Winning Value then WinEvent is fired. * If the number is < Winning Value then LoseEvent is fired. * If the number = minimum then `RolledMinEve |
Cancel |
Cancel<public>():void |
Cancels the active number generation. |
Walkthrough
Let's build a mystery loot crate. A trigger sits under the crate; when a player steps on it, we activate the RNG. On a WinEvent we grant a rare reward by triggering an item granter; on a LoseEvent the player gets the common reward. If they hit the absolute jackpot (RolledMaxEvent) we celebrate with a separate VFX trigger.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
loot_crate := class(creative_device):
# The RNG that decides the reward tier.
@editable
RNG : rng_device = rng_device{}
# Player steps on this to roll.
@editable
RollTrigger : trigger_device = trigger_device{}
# Fires the rare reward (e.g. an item_granter wired to its Trigger).
@editable
RareReward : trigger_device = trigger_device{}
# Fires the common reward.
@editable
CommonReward : trigger_device = trigger_device{}
# Plays jackpot celebration VFX/sound.
@editable
JackpotFX : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
# When a player steps on the plate, roll the RNG for that player.
RollTrigger.TriggeredEvent.Subscribe(OnPlayerStepped)
# React to each possible outcome.
RNG.WinEvent.Subscribe(OnWin)
RNG.LoseEvent.Subscribe(OnLose)
RNG.RolledMaxEvent.Subscribe(OnJackpot)
# TriggeredEvent hands us a (Agent : agent) — roll for that player.
OnPlayerStepped(Agent : agent):void =
RNG.Activate(Agent)
OnWin():void =
RareReward.Trigger()
OnLose():void =
CommonReward.Trigger()
OnJackpot():void =
# RolledMaxEvent ALSO fires alongside WinEvent when the max is the top,
# so use it for the extra celebration only.
JackpotFX.Trigger()
Line by line:
RNG : rng_device = rng_device{}— the@editablefield that lets you drag your placed RNG device onto this script in UEFN. Without an@editablefield, callingRNG.Activate()would fail with Unknown identifier.- The other
@editabletrigger_devicefields are how we cause real effects: granters/VFX are wired to these triggers in the editor, andTrigger()fires them. - In
OnBegin, weSubscribehandlers to the trigger and to three RNG events. Subscriptions live inOnBegin; the handlers are methods at class scope. OnPlayerStepped(Agent : agent)—TriggeredEventis alistenable(agent), so the handler receives a plainagent. We pass it straight intoRNG.Activate(Agent)so the roll is associated with that player.OnWin/OnLose/OnJackpottake no parameters because the RNG events arelistenable(tuple())— they carry no payload. We justTrigger()the appropriate reward device.
Common patterns
Coin flip with Activate() (no agent)
Use the no-arg Activate() when the roll isn't tied to a specific player — like a global coin flip that picks which of two doors opens. Wire WinEvent to the left door and LoseEvent to the right.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
coin_flip := class(creative_device):
@editable
RNG : rng_device = rng_device{}
@editable
FlipButton : button_device = button_device{}
@editable
LeftDoor : trigger_device = trigger_device{}
@editable
RightDoor : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
FlipButton.InteractedWithEvent.Subscribe(OnFlip)
RNG.WinEvent.Subscribe(OnHeads)
RNG.LoseEvent.Subscribe(OnTails)
OnFlip(Agent : agent):void =
# No agent needed — this is a global flip.
RNG.Activate()
OnHeads():void =
LeftDoor.Trigger()
OnTails():void =
RightDoor.Trigger()
Rare jackpot with RolledMinEvent and a re-roll cooldown
Here we gate rolling with Disable/Enable so a player can't spam the slot machine, and we react to RolledMinEvent for a "worst possible" consolation.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
slot_machine := class(creative_device):
@editable
RNG : rng_device = rng_device{}
@editable
PullLever : button_device = button_device{}
@editable
BadLuckFX : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
PullLever.InteractedWithEvent.Subscribe(OnPull)
RNG.RolledMinEvent.Subscribe(OnSnakeEyes)
OnPull(Agent : agent):void =
# Roll for this player, then briefly lock the machine.
RNG.Activate(Agent)
RNG.Disable()
Sleep(3.0)
RNG.Enable()
OnSnakeEyes():void =
BadLuckFX.Trigger()
Cancelling an in-progress roll
Cancel() stops the active generation — handy if you give players a "chicken out" button before the result lands.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
cancelable_roll := class(creative_device):
@editable
RNG : rng_device = rng_device{}
@editable
RollButton : button_device = button_device{}
@editable
AbortButton : button_device = button_device{}
OnBegin<override>()<suspends>:void =
RollButton.InteractedWithEvent.Subscribe(OnRoll)
AbortButton.InteractedWithEvent.Subscribe(OnAbort)
OnRoll(Agent : agent):void =
RNG.Activate(Agent)
OnAbort(Agent : agent):void =
RNG.Cancel()
Gotchas
- The RNG events carry no payload.
WinEvent,LoseEvent,RolledMaxEvent, andRolledMinEventarelistenable(tuple()), so their handlers take no parameters — writeOnWin():void, notOnWin(Agent:agent). If you need to know who rolled, capture the agent from the trigger/button handler and pass it toActivate(Agent); the win/lose events themselves won't hand it back. - Max/min events fire in addition to win/lose. If the maximum value is also above the Winning Value, then a max roll fires both
WinEventandRolledMaxEvent. Don't double-grant rewards — use the max/min events for extra flair, not the core reward logic. - Two
Activateoverloads.Activate(Agent:agent)andActivate()are different functions. Pick the agent overload only when you actually have an agent; passing nothing to the agent version won't compile. - You must declare the device as an
@editablefield. A barerng_device.Activate()fails with Unknown identifier. DeclareRNG : rng_device = rng_device{}in yourclass(creative_device)and drag your placed device onto it in UEFN. - Configure limits in the Details panel, not Verse. Value Limit 1, Value Limit 2, and Winning Value are editor properties — Verse only triggers the roll and reacts to the outcome. If your
WinEventnever fires, check that the Winning Value is reachable within your min/max range. Disable()blocks rolling. While disabled, callingActivate()does nothing. Remember toEnable()again (as in the slot-machine cooldown example) or the device stays silent.