Overview
Every time you want to show text to a player in UEFN — a countdown, a score, a story beat — you will touch both types:
| Type | What it is | Where it lives | Can be shown on HUD? |
|---|---|---|---|
string |
Raw UTF-8 character data. Supports concatenation, comparison, ToString() conversion. |
Your Verse logic | ❌ Not directly |
message |
A localized text value. Produced by a <localizes> function. |
Player-facing UI / HUD devices | ✅ Yes |
Why two types?
Fortnite is a global game. The engine needs to know which strings are player-facing (and therefore candidates for translation) versus which are internal (debug labels, key lookups, log text). The message type is that contract. You cannot pass a raw string to hud_message_device.Show() or SetText() — the compiler rejects it. You must wrap it in a <localizes> function first.
The bridge: a <localizes> function
# Declare once at module scope (or class scope):
MyText<localizes>(S : string) : message = "{S}"
Now MyText("Ahoy, sailor!") produces a message you can hand to any HUD API. The {S} inside the string literal is Verse string interpolation — it embeds the value of S into the localized string at runtime.
When to reach for hud_message_device
Use it whenever you need to:
- Flash a contextual hint ("Step on the gangplank to board!")
- Show a dynamic value (remaining treasure chests, elapsed time)
- Sequence story beats without building a full UI widget
API Reference
hud_message_device
Used to show custom HUD messages to one or more
agents.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
hud_message_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
ShowMessageEvent |
ShowMessageEvent<public>:listenable(agent) |
Called when a Message has been Shown on-screen. Returns an Agent if it was Shown on a specified Agent's screen. |
HideMessageEvent |
HideMessageEvent<public>:listenable(agent) |
Called when a Message has been Hidden on-screen. Returns an Agent if it was Hidden from a specified Agent's screen. |
ClearAllMessagesEvent |
ClearAllMessagesEvent<public>:listenable(agent) |
Called when all queued Messages from all players that are affected by this HUD Message Device have been cleared. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Show |
Show<public>(Agent:agent):void |
Shows the currently set HUD Message on Agents screen. Will replace any previously active message. Use this when the device is setup to target specific agents. |
Show |
Show<public>():void |
Shows the currently set Message HUD message on screen. Will replace any previously active message. |
Hide |
Hide<public>():void |
Hides the HUD message. |
Hide |
Hide<public>(Agent:agent):void |
Hides the currently set HUD Message on Agents screen. Use this when the device is setup to target specific agents. |
Show |
Show<public>(Agent:agent, Message:message, ?DisplayTime:float |
Displays a Custom message to a specific Agent that you define.Setting DisplayTime to 0.0 will display the HUD message persistently.If not defined, or less than 0.0 the message will show for the time set on the device. |
Show |
Show<public>(Message:message, ?DisplayTime:float |
Displays a Custom message that you define for all PlayersSetting DisplayTime to 0.0 will display the HUD message persistently.If not defined, or less than 0.0 the message will show for the time set on the device. |
SetDisplayTime |
SetDisplayTime<public>(Time:float):void |
Sets the time (in seconds) the HUD message will be displayed. 0.0 will display the HUD message persistently. |
GetDisplayTime |
GetDisplayTime<public>()<transacts>:float |
Returns the time (in seconds) for which the HUD message will be displayed. 0.0 means the message is displayed persistently. |
SetText |
SetText<public>(Text:message):void |
Sets the Message to be displayed when the HUD message is activated. Text is clamped to 150 characters. |
ClearAllMessages |
ClearAllMessages<public>():void |
Clears all queued Messages from all players that are affected by this HUD Message Device. |
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. |
player
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse). Inherited members are merged from agent.
player<native><public> := class<unique><persistent><module_scoped_var_weak_map_key><epic_internal>(agent):
Walkthrough
Scenario: A cel-shaded pirate island. Three trigger pads are hidden along the dock, the shore, and the clifftop. When a player steps on each one, a unique HUD message appears. After all three are found, the HUD announces "Treasure map complete!" and clears after five seconds. A fourth trigger (a reset pad back at the ship) clears all messages and resets the sequence.
Setup in UEFN editor
- Place three
trigger_deviceprops at the dock, shore, and clifftop. - Place one
trigger_deviceat the pirate ship (reset). - Place one
hud_message_deviceanywhere on the island. - Create a new Verse device, wire the four triggers and the HUD device as
@editablefields.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
# ─────────────────────────────────────────────────────────────
# Localizes bridge — converts a runtime string into a message
# ─────────────────────────────────────────────────────────────
PirateMsg<localizes>(S : string) : message = "{S}"
# ─────────────────────────────────────────────────────────────
# Main device
# ─────────────────────────────────────────────────────────────
pirate_island_hud_device := class(creative_device):
# ── Editable fields (wire these in the UEFN editor) ──────
@editable
DockTrigger : trigger_device = trigger_device{}
@editable
ShoreTrigger : trigger_device = trigger_device{}
@editable
ClifftopTrigger : trigger_device = trigger_device{}
@editable
ResetTrigger : trigger_device = trigger_device{}
@editable
HUD : hud_message_device = hud_message_device{}
# ── Internal state ────────────────────────────────────────
var FoundCount : int = 0
# ── Lifecycle ─────────────────────────────────────────────
OnBegin<override>()<suspends> : void =
# Each trigger may only fire once per round
DockTrigger.SetMaxTriggerCount(1)
ShoreTrigger.SetMaxTriggerCount(1)
ClifftopTrigger.SetMaxTriggerCount(1)
# Display time: 4 seconds for clue messages
HUD.SetDisplayTime(4.0)
# Subscribe to each trigger
DockTrigger.TriggeredEvent.Subscribe(OnDockTriggered)
ShoreTrigger.TriggeredEvent.Subscribe(OnShoreTriggered)
ClifftopTrigger.TriggeredEvent.Subscribe(OnClifftopTriggered)
ResetTrigger.TriggeredEvent.Subscribe(OnResetTriggered)
# ── Handlers ──────────────────────────────────────────────
# TriggeredEvent sends ?agent — unwrap before using
OnDockTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
set FoundCount += 1
# Show a custom message to THIS specific agent
HUD.Show(A, PirateMsg("Dock: X marks the first spot! ({FoundCount}/3)"))
CheckComplete(A)
OnShoreTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
set FoundCount += 1
HUD.Show(A, PirateMsg("Shore: The tide hides the second clue! ({FoundCount}/3)"))
CheckComplete(A)
OnClifftopTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
set FoundCount += 1
HUD.Show(A, PirateMsg("Clifftop: The crow's nest reveals all! ({FoundCount}/3)"))
CheckComplete(A)
OnResetTriggered(MaybeAgent : ?agent) : void =
# ClearAllMessages wipes the queue for every player
HUD.ClearAllMessages()
set FoundCount = 0
# Re-enable the three clue triggers for a new round
DockTrigger.Enable()
ShoreTrigger.Enable()
ClifftopTrigger.Enable()
CheckComplete(A : agent) : void =
if (FoundCount >= 3):
# Persistent final message (DisplayTime 0.0 = forever until cleared)
HUD.Show(A, PirateMsg("Treasure map complete! Return to the ship!"), ?DisplayTime := 0.0)
Line-by-line highlights
| Line(s) | What's happening |
|---|---|
PirateMsg<localizes>(S:string):message |
The bridge function. {S} is string interpolation — the runtime value of S is embedded in the localized string. |
HUD.SetDisplayTime(4.0) |
Sets the default on-screen duration for all subsequent Show() calls that don't override it. |
DockTrigger.SetMaxTriggerCount(1) |
Clamps the trigger to fire exactly once — prevents duplicate messages. |
HUD.Show(A, PirateMsg(...)) |
The two-arg overload: shows a custom message only on agent A's screen. |
?DisplayTime := 0.0 |
Named optional argument — 0.0 means the message stays until explicitly hidden or cleared. |
HUD.ClearAllMessages() |
Wipes every queued message for all players; used on reset. |
if (A := MaybeAgent?) |
Unwraps the ?agent option type. If no agent triggered the device (code-triggered), the block is skipped safely. |
Common patterns
Pattern 1 — Dynamic float value in a HUD message (using ToString)
You often want to show a numeric value — elapsed time, distance, score. ToString<public>(Val:float)<reads>:string converts a float to a string, which you then wrap with your localizes function.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
TimerMsg<localizes>(S : string) : message = "{S}"
timer_hud_device := class(creative_device):
@editable
HUD : hud_message_device = hud_message_device{}
@editable
StartTrigger : trigger_device = trigger_device{}
var ElapsedSeconds : float = 0.0
OnBegin<override>()<suspends> : void =
StartTrigger.TriggeredEvent.Subscribe(OnStartTriggered)
OnStartTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
set ElapsedSeconds += 1.0
# ToString converts float -> string; TimerMsg wraps it as message
TimeStr : string = ToString(ElapsedSeconds)
HUD.Show(A, TimerMsg("Time at sea: {TimeStr}s"))
Pattern 2 — Broadcast to ALL players + query display time
Sometimes you want every player to see the same announcement (a wave starting, a ship sinking). Use the no-arg Show(Message) overload and verify the current display time with GetDisplayTime().
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
Announce<localizes>(S : string) : message = "{S}"
broadcast_hud_device := class(creative_device):
@editable
HUD : hud_message_device = hud_message_device{}
@editable
WaveTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
WaveTrigger.TriggeredEvent.Subscribe(OnWaveTriggered)
OnWaveTriggered(MaybeAgent : ?agent) : void =
# Check current display time before overriding it
CurrentTime : float = HUD.GetDisplayTime()
if (CurrentTime < 3.0):
HUD.SetDisplayTime(5.0)
# No-arg Show broadcasts to ALL players on the island
HUD.Show(Announce("A pirate ship approaches the lagoon!"))
Pattern 3 — Hide a message per-agent + subscribe to HideMessageEvent
Sometimes you need to react after a message disappears — for example, to re-enable a trigger only after the player has read the clue.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
ClueMsg<localizes>(S : string) : message = "{S}"
hide_aware_device := class(creative_device):
@editable
HUD : hud_message_device = hud_message_device{}
@editable
ClueTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
ClueTrigger.TriggeredEvent.Subscribe(OnClueTriggered)
# React when the HUD message is hidden for any agent
HUD.HideMessageEvent.Subscribe(OnMessageHidden)
OnClueTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
# Show for 6 seconds, then re-enable the trigger
HUD.Show(A, ClueMsg("The cove entrance is behind the waterfall."), ?DisplayTime := 6.0)
# Disable while reading
ClueTrigger.Disable()
OnMessageHidden(A : agent) : void =
# Message gone — player has had time to read it; re-enable
ClueTrigger.Enable()
Gotchas
1. string ≠ message — the compiler will not auto-convert
This fails:
# WRONG — string is not message
HUD.SetText("Ahoy!") # compile error
HUD.Show(A, "Ahoy!") # compile error
You must go through a <localizes> function:
Msg<localizes>(S : string) : message = "{S}"
HUD.SetText(Msg("Ahoy!")) # ✅
2. There is NO StringToMessage built-in
A common search. It does not exist. The <localizes> bridge pattern above is the only way to produce a message from a runtime string.
3. ?agent must be unwrapped before use
TriggeredEvent sends ?agent (an option). Passing it directly to HUD.Show(Agent, ...) fails because Show expects agent, not ?agent:
# WRONG
OnTriggered(MaybeAgent : ?agent) : void =
HUD.Show(MaybeAgent, Msg("Hi")) # compile error
# CORRECT
OnTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
HUD.Show(A, Msg("Hi")) # ✅
4. SetText vs Show — they do different things
SetText(Text:message) stores the message on the device but does not display it. You still need to call Show() afterwards. Use SetText when you want to pre-configure the message and trigger display later (e.g., from a linked device in the editor).
5. DisplayTime := 0.0 means persistent, not instant
Passing ?DisplayTime := 0.0 keeps the message on screen until you explicitly call Hide() or ClearAllMessages(). A negative value (or omitting the argument) falls back to the device's configured display time.
6. int ↔ float is not automatic
If you store a counter as int and want to show it, you cannot pass it directly to ToString(Val:float). Either store it as float, or cast: Verse has no implicit numeric coercion. Use a separate IntMsg<localizes>(I:int):message = "{I}" localizes function to embed an int directly via interpolation instead.