Overview
Comparison operators in Verse are failable expressions — they either succeed (and execution continues) or fail (and the branch is skipped). This makes them a natural fit for if expressions, for filters, and any other failure context. Because they are failable, you cannot use them outside a failure context; trying to write X < Y as a standalone statement is a compile error.
Verse ships six comparison operators:
| Operator | Meaning | Supported Types |
|---|---|---|
< |
Less than | int, float |
<= |
Less than or equal | int, float |
> |
Greater than | int, float |
>= |
Greater than or equal | int, float |
= |
Equal | int, float, string, arrays/tuples of comparable elements |
<> |
Not equal | int, float, string |
Reach for comparison operators whenever you need to:
- Gate a game event behind a score or count threshold (open a door when kills ≥ 5)
- Validate a timer (trigger an alarm when seconds remaining < 10)
- Check whether a player chose the correct answer in a quiz minigame
- Compare string identifiers to route logic
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario: The Score-Gated Vault Door
A player steps on a pressure plate. Your Verse device checks their elimination count (stored in a simple counter). If they have 5 or more eliminations, the vault barrier lowers and they hear a success sound. If not, nothing happens — they need to keep playing.
This example wires up a trigger_device (the pressure plate), a barrier_device (the vault door), and uses >= to gate the unlock.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
# Tracks how many eliminations a player has earned.
# In a real project this would come from a tracker_device;
# here we keep a simple module-level counter for clarity.
vault_door_manager := class<concrete>(creative_device):
# The pressure plate the player steps on
@editable
Plate : trigger_device = trigger_device{}
# The barrier that acts as the vault door
@editable
VaultDoor : barrier_device = barrier_device{}
# Simulated elimination count — wire a real tracker in production
var PlayerEliminations : int = 0
# Required eliminations to open the vault
RequiredEliminations : int = 5
OnBegin<override>()<suspends> : void =
# Subscribe to the pressure plate
Plate.TriggeredEvent.Subscribe(OnPlateTriggered)
# Simulate earning eliminations over time so the example is self-contained
loop:
Sleep(3.0)
set PlayerEliminations += 1
if (PlayerEliminations >= 10):
break # stop accumulating after 10
# Called every time a player steps on the plate
OnPlateTriggered(Agent : ?agent) : void =
# Check the threshold — >= is failable, so it lives inside if
if (PlayerEliminations >= RequiredEliminations):
VaultDoor.Disable() # lower the barrier — vault is open!
else:
# Not enough eliminations yet — door stays up
VaultDoor.Enable()
Line-by-line breakdown:
@editablefields let you drag the realtrigger_deviceandbarrier_devicefrom the UEFN outliner into the device's property panel — without this, the device can't see them.Plate.TriggeredEvent.Subscribe(OnPlateTriggered)— registers the handler. The event fires every time a player steps on the plate.OnPlateTriggered(Agent : ?agent)— the handler signature matcheslistenable(?agent). We don't need the agent here, but the parameter must still be declared.if (PlayerEliminations >= RequiredEliminations):—>=is failable; theifprovides the failure context. If the comparison fails, theelsebranch runs.VaultDoor.Disable()/VaultDoor.Enable()— realbarrier_deviceAPI calls that lower and raise the barrier.- The
loopat the bottom simulates earning eliminations every 3 seconds so you can test the door opening without a full elimination system.
Common patterns
Pattern 1 — Timer Alarm with < (less than)
Fire a cinematic trigger when the match clock drops below 10 seconds.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
timer_alarm_device := class<concrete>(creative_device):
@editable
AlarmTrigger : trigger_device = trigger_device{}
# Countdown in whole seconds
var SecondsRemaining : int = 60
# Has the alarm already fired this round?
var AlarmFired : logic = false
OnBegin<override>()<suspends> : void =
loop:
Sleep(1.0)
if (SecondsRemaining > 0):
set SecondsRemaining -= 1
# Fire the alarm exactly once when time drops below 10
if (SecondsRemaining < 10, not AlarmFired):
set AlarmFired = true
AlarmTrigger.Trigger() # kicks off the cinematic / alarm VFX
if (SecondsRemaining = 0):
break
Key point: SecondsRemaining < 10 is failable — chaining it with , not AlarmFired inside the same if means both conditions must succeed. The comma acts as a logical AND in a failure context.
Pattern 2 — String equality = for a quiz answer check
A player interacts with a button labelled with an answer. Compare their choice to the correct answer string.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
quiz_checker_device := class<concrete>(creative_device):
# Button the player presses to submit answer "Paris"
@editable
AnswerButton : button_device = button_device{}
# The barrier that opens on a correct answer
@editable
RewardDoor : barrier_device = barrier_device{}
CorrectAnswer : string = "Paris"
PlayerAnswer : string = "Paris" # In production, set this from UI input
OnBegin<override>()<suspends> : void =
AnswerButton.InteractedWithEvent.Subscribe(OnAnswerSubmitted)
OnAnswerSubmitted(Agent : agent) : void =
# String equality is failable — must be inside a failure context
if (PlayerAnswer = CorrectAnswer):
RewardDoor.Disable() # correct — open the door
else:
RewardDoor.Enable() # wrong — keep it shut
Key point: String comparison with = is case-sensitive and code-point exact. "paris" ≠ "Paris". Normalise your strings before comparing if players type free text.
Pattern 3 — Inequality <> to detect a state change
A score tracker updates every few seconds. Broadcast a special event only when the new score is different from the previous score (i.e., something actually changed).
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
score_change_watcher := class<concrete>(creative_device):
@editable
ScoreChangedTrigger : trigger_device = trigger_device{}
var LastScore : int = 0
var CurrentScore : int = 0
OnBegin<override>()<suspends> : void =
loop:
Sleep(2.0)
# Simulate a score update (replace with real tracker polling)
set CurrentScore += 3
# <> (not equal) is failable — fires only when score actually changed
if (CurrentScore <> LastScore):
set LastScore = CurrentScore
ScoreChangedTrigger.Trigger() # notify other devices
Key point: <> is the not-equal operator. It succeeds when the two operands differ, so it's perfect for change-detection guards.
Gotchas
1. Comparisons are failable — they MUST live in a failure context
Writing X < Y as a bare statement is a compile error. Always wrap comparisons in if, for, or another failure context:
# ❌ WRONG — bare comparison, compile error
X < Y
# ✅ CORRECT
if (X < Y):
DoSomething()
2. No automatic int ↔ float conversion
Verse does not coerce types. Comparing an int to a float literal fails to compile:
var Count : int = 5
# ❌ WRONG — 5.0 is float, Count is int
if (Count < 5.0): ...
# ✅ CORRECT — keep types consistent
if (Count < 5): ...
If you genuinely need to compare across types, convert explicitly: Float(Count) < 5.0 (using the built-in Float() conversion).
3. = on strings is code-point exact and case-sensitive
"Paris" = "paris" fails. If you're comparing player-typed strings, normalise case before comparing or use a known canonical form.
4. Chaining comparisons with commas (AND logic)
Verse has no && operator. To require multiple comparisons to all succeed, chain them with commas inside the same if:
if (Score >= 10, Score < 20):
# Score is in [10, 20)
DoSomething()
Each clause is evaluated left-to-right; if any fails, the whole if fails.
5. not negates a whole failable expression, not just comparisons
To invert a comparison, wrap it with not:
if (not (Score >= 10)):
# Score is less than 10
DoSomething()
This is equivalent to Score < 10 but useful when the original expression is complex.
6. Array/tuple equality with =
Verse supports element-wise equality for arrays and tuples whose element types are comparable. Two arrays are equal only if they have the same length and every element pair is equal. This is handy for checking ordered answer sequences in puzzle games.