Overview
Min and Max are pure mathematical functions built into the Verse standard library. They solve a problem that comes up constantly in game logic: you need a value that stays within a safe range.
Max(X, Y)returns whichever of the two values is larger.Min(X, Y)returns whichever of the two values is smaller.- Both have overloads for
intandfloat. - Both carry the
<computes>effect — they are deterministic, have no side effects, and can be called anywhere (including inside<transacts>or<decides>contexts). - For
float, if either argument isNaN, the result isNaN. Infinity is handled correctly:Max(Inf, 100.0)returnsInf.
When to reach for them:
- Clamping health, shields, ammo, or score to a valid range (
Min(CurrentHP + Heal, MaxHP)). - Picking the larger of two competing values (highest bidder, fastest lap time).
- Building a manual
Clampby chainingMinandMaxtogether. - Comparing two players' scores to decide a winner.
Because Min/Max have no device to place on the island, there is no UEFN device panel for them — you call them directly in Verse code.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario: A Healing Station That Respects a Health Cap
A player walks into a healing zone. We want to restore 50 HP, but the player's health must never exceed their maximum of 200. We also want to make sure the heal amount is never negative (in case some other system accidentally passes a bad value). We use Min to cap the result and Max to floor the heal delta at zero.
The device references a trigger_device (the healing zone boundary) and a player_counter_device to track heals given. It reads the player's current health via fort_character, applies the clamped heal, and sets the new value.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
# healing_station_device
# Place a trigger_device on the island and assign it to HealZone.
# Set MaxHealth and HealAmount in the Details panel.
healing_station_device := class(creative_device):
# The trigger the player walks into to receive healing.
@editable
HealZone : trigger_device = trigger_device{}
# The absolute maximum HP a player can have on this island.
@editable
MaxHealth : float = 200.0
# How many HP to restore on each activation.
@editable
HealAmount : float = 50.0
# Subscribe to the trigger when the game starts.
OnBegin<override>()<suspends> : void =
HealZone.TriggeredEvent.Subscribe(OnPlayerEnterHealZone)
# Called whenever a player steps on / into the trigger.
OnPlayerEnterHealZone(MaybeAgent : ?agent) : void =
# Unwrap the optional agent — the event fires with ?agent.
if (A := MaybeAgent?):
# Get the fort_character so we can read/write health.
if (Character := A.GetFortCharacter[]):
CurrentHP := Character.GetHealth()
# Ensure the heal delta is never negative.
# (Protects against a misconfigured HealAmount of -10, etc.)
SafeHeal := Max(HealAmount, 0.0)
# Add the heal, but never exceed MaxHealth.
NewHP := Min(CurrentHP + SafeHeal, MaxHealth)
# Apply the clamped value.
Character.SetHealth(NewHP)
Line-by-line explanation:
| Line | What it does |
|---|---|
HealZone.TriggeredEvent.Subscribe(OnPlayerEnterHealZone) |
Wires the trigger's event to our handler. |
if (A := MaybeAgent?) |
Safely unwraps the ?agent the event delivers. |
Character.GetHealth() |
Reads the player's current HP as a float. |
Max(HealAmount, 0.0) |
Floors the heal at zero — Max returns the larger value, so a negative HealAmount becomes 0.0. |
Min(CurrentHP + SafeHeal, MaxHealth) |
Caps the healed total — Min returns the smaller value, so we can never exceed MaxHealth. |
Character.SetHealth(NewHP) |
Writes the clamped HP back to the character. |
This is the classic clamp pattern: Min on the ceiling, Max on the floor.
Common patterns
Pattern 1 — Picking the Higher Score (int overload)
Two teams each have a score. At round end, display the winning score by picking the larger of the two with the int overload of Max.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# score_comparator_device
# Assign two score_manager_devices in the Details panel.
score_comparator_device := class(creative_device):
@editable
EndGameTrigger : trigger_device = trigger_device{}
# Simulated scores — in a real project these would come from
# score_manager_device or a shared variable.
@editable
TeamAScore : int = 0
@editable
TeamBScore : int = 0
OnBegin<override>()<suspends> : void =
EndGameTrigger.TriggeredEvent.Subscribe(OnRoundEnd)
OnRoundEnd(MaybeAgent : ?agent) : void =
# int overload — no float conversion needed.
WinningScore := Max(TeamAScore, TeamBScore)
# Use WinningScore to drive a HUD element, unlock a reward, etc.
# (Here we just store it; wire it to your own display logic.)
_ := WinningScore
Key point: The int overload of Max returns an int — no cast required. Verse does not auto-convert int to float, so keep your types consistent.
Pattern 2 — Manual Clamp for a Damage Multiplier (float, chained Min + Max)
A damage multiplier should always stay between 0.5 (half damage) and 3.0 (triple damage). Chain Max then Min to build a full clamp.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# damage_multiplier_device
# Demonstrates clamping a float to [MinMult, MaxMult] using Min + Max.
damage_multiplier_device := class(creative_device):
@editable
UpgradeTrigger : trigger_device = trigger_device{}
# Boundaries for the multiplier.
@editable
MinMult : float = 0.5
@editable
MaxMult : float = 3.0
# Current multiplier — starts at 1.0 (normal damage).
var CurrentMult : float = 1.0
OnBegin<override>()<suspends> : void =
UpgradeTrigger.TriggeredEvent.Subscribe(OnUpgrade)
OnUpgrade(MaybeAgent : ?agent) : void =
# Each upgrade adds 0.25 to the multiplier.
Raw := CurrentMult + 0.25
# Clamp: first raise the floor with Max, then lower the ceiling with Min.
Clamped := Min(Max(Raw, MinMult), MaxMult)
set CurrentMult = Clamped
Key point: Min(Max(Value, Floor), Ceiling) is the idiomatic Verse clamp. There is no dedicated Clamp function in the standard library — this two-call chain is the canonical approach.
Pattern 3 — Choosing the Closer Spawn Point (float distance comparison)
Two spawn pads exist. When a player dies, respawn them at whichever pad is closer to the center of the map by comparing distances.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# closest_spawn_device
# Shows Min used to select the smaller of two float distances.
closest_spawn_device := class(creative_device):
@editable
SpawnPadA : player_spawner_device = player_spawner_device{}
@editable
SpawnPadB : player_spawner_device = player_spawner_device{}
@editable
EliminationSource : trigger_device = trigger_device{}
# Pre-measured distances from each pad to the map centre (set in Details).
@editable
DistanceA : float = 1500.0
@editable
DistanceB : float = 2200.0
OnBegin<override>()<suspends> : void =
EliminationSource.TriggeredEvent.Subscribe(OnPlayerEliminated)
OnPlayerEliminated(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
# Min returns the smaller distance — that's the closer pad.
CloserDistance := Min(DistanceA, DistanceB)
if (CloserDistance = DistanceA):
SpawnPadA.SpawnPlayer(A)
else:
SpawnPadB.SpawnPlayer(A)
Key point: Min on floats returns the numerically smaller value. Comparing the result to each input with = lets you branch on which pad won.
Gotchas
1. int and float overloads are separate — no auto-conversion
Verse does not silently convert between int and float. Calling Max(5, 2.0) is a compile error because the two arguments have different types. Decide which type you need and be consistent:
# WRONG — mixed types
# Bad := Max(5, 2.0) # compile error
# RIGHT — both int
GoodInt := Max(5, 2)
# RIGHT — both float
GoodFloat := Max(5.0, 2.0)
2. NaN propagates through float Min/Max
If either argument to the float overload is NaN, the result is NaN. Guard against NaN when reading values from physics or external calculations before passing them into Min/Max if correctness is critical.
3. <computes> means you can call Min/Max anywhere
Because both functions carry <computes> (a subset of <reads>, no side effects, deterministic), you can call them inside <transacts> blocks, inside <decides> expressions, and in constant initializers. You never need to worry about effect mismatches.
4. Chaining is the only clamp
There is no Clamp(Value, Min, Max) function in the Verse standard library. Always use Min(Max(Value, Floor), Ceiling). Getting the order wrong (Max(Min(...))) inverts the clamp and produces nonsensical results when Floor > Ceiling.
5. Infinity is valid input
Max(Inf, 100.0) returns Inf and Min(-Inf, 100.0) returns -Inf. This is correct IEEE 754 behavior, but watch out if you're using sentinel infinity values as "unset" placeholders — they will win every comparison.