Overview
The conditional_button_device solves a classic game-design problem: how do you gate progress behind item collection without writing a custom inventory system? Drop the device into your island, configure one or more key item types in its properties panel, and the device handles the item check automatically. Your Verse code only needs to react to the outcome.
Reach for this device when you need:
- A vault door that opens only when a player collects three key cards.
- A crafting station that consumes resources before granting a reward.
- A boss arena entrance that requires a specific weapon or artifact to enter.
- A dynamic HUD hint that tells players how many items they still need.
The device exposes two events (ActivatedEvent, NotEnoughItemsEvent) and a rich set of methods for reading and writing item counts, interaction text, interaction time, and item scores — all of which you can drive from Verse at runtime.
API Reference
conditional_button_device
Used to create a specialized button which can only be activated when
agents are carrying specific items.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
conditional_button_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
ActivatedEvent |
ActivatedEvent<public>:listenable(agent) |
Signaled when this device is activated. Sends the agent that activated this device. |
NotEnoughItemsEvent |
NotEnoughItemsEvent<public>:listenable(agent) |
Signaled when this device fails to activate because agent didn't have the required items. Sends the agent that attempted to activate the device. |
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 |
Activates this device. Agent is used as the instigator of the action. |
Toggle |
Toggle<public>(Agent:agent):void |
Toggles the conditional button state. Agent is used as the instigator of the action. |
SetInteractionText |
SetInteractionText<public>(Text:message):void |
Sets the text that appears when agents approach the device. Text is limited to 150 characters and will revert back to default if empty. |
SetInteractionTime |
SetInteractionTime<public>(Time:float):void |
Sets the time (in seconds) that an interaction with this device should take to complete. |
GetInteractionTime |
GetInteractionTime<public>()<transacts>:float |
Returns the time (in seconds) that an interaction with this device will take to complete. |
SetItemCountRequired |
SetItemCountRequired<public>(KeyItemIndex:int, Count:int):void |
Sets the quantity of a specific key item type that needs to be collected in order to activate the switch. KeyItemIndex ranges from 0 to number of key item types - 1. |
GetItemCountRequired |
GetItemCountRequired<public>(KeyItemIndex:int)<transacts>:int |
Returns the total quantity of a specific key item type that needs to be collected in order to activate the switch. |
GetRemainingItemCountRequired |
GetRemainingItemCountRequired<public>(KeyItemIndex:int)<transacts>:int |
Returns the remaining quantity of a specific key item type that needs to be collected in order to activate the switch. |
SetItemScore |
SetItemScore<public>(KeyItemIndex:int, Score:int):void |
Sets the score to be awarded for a key item. KeyItemIndex ranges from 0 to number of key item types - 1. |
GetItemScore |
GetItemScore<public>(KeyItemIndex:int)<transacts>:int |
Returns the score to be awarded for a key item. |
GetItemCount |
GetItemCount<public>(Agent:agent, KeyItemIndex:int):int |
Returns how many items an Agent has of the item stored at KeyItemIndex. |
HasAllItems |
HasAllItems<public>(Agent:agent)<transacts><decides>:void |
Returns if the Agent has all of the items required to interact with this Device. |
IsHoldingItem |
IsHoldingItem<public>(Agent:agent)<transacts><decides>:void |
Returns if the Agent is currently holding any of the items stored in the Device. |
IsHoldingItem |
IsHoldingItem<public>(Agent:agent, KeyItemIndex:int)<transacts><decides>:void |
Returns if the Agent is currently holding the item stored at KeyItemIndex. |
button_device
Used to create a button which can trigger other devices when an agent interacts with it.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
button_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
InteractedWithEvent |
InteractedWithEvent<public>:listenable(agent) |
Signaled when an agent successfully interacts with the button for GetInteractionTime seconds. Sends the agent that interacted with the button. |
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. |
SetInteractionText |
SetInteractionText<public>(Text:message):void |
Sets the text that displays when an agent is close to this button and looks at it. Text is limited to 64 characters. |
SetInteractionTime |
SetInteractionTime<public>(Time:float):void |
Sets the duration of the interaction required to activate this device (in seconds). |
GetInteractionTime |
GetInteractionTime<public>()<transacts>:float |
Returns the duration of the interaction required to activate this device (in seconds). |
SetMaxTriggerCount |
SetMaxTriggerCount<public>(MaxCount:int):void |
Sets the maximum amount of times this button can be interacted with before it will be disabled. * MaxCount must be between 0 and 10000. * 0 indicates no limit on trigger count. |
GetMaxTriggerCount |
GetMaxTriggerCount<public>()<transacts>:int |
Returns the maximum amount of times this button can be interacted with before it will be disabled. * GetTriggerMaxCount will be between 0 and 10000. * 0 indicates no limit on trigger count. |
GetTriggerCountRemaining |
GetTriggerCountRemaining<public>()<transacts>:int |
Returns the number of times that this button can still be interacted with before it will be disabled. Will return 0 if GetMaxTriggerCount is unlimited. |
Walkthrough
Scenario: The Crystal Vault
Players roam the island collecting Crystal Shards (key item index 0). When they approach the vault door and interact with the conditional_button_device, one of two things happens:
- They have 3 shards → the vault unlocks, a barrier lowers, and they receive a score bonus.
- They don't have enough → a hint updates the button text to show exactly how many more shards they need.
Place a conditional_button_device and a barrier_device in the scene, wire them to the Verse device via @editable fields, and set Key Item 0 required count = 3 in the device's properties panel.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# Helper to build localized messages at runtime
VaultPrompt<localizes>(S : string) : message = "{S}"
crystal_vault_manager := class(creative_device):
# The conditional button guarding the vault
@editable
VaultButton : conditional_button_device = conditional_button_device{}
# The barrier that physically blocks the vault entrance
@editable
VaultBarrier : barrier_device = barrier_device{}
# Called once when the game starts
OnBegin<override>()<suspends> : void =
# Personalise the interaction prompt and hold time
VaultButton.SetInteractionText(VaultPrompt("Insert Crystal Shards"))
VaultButton.SetInteractionTime(1.5)
# Make sure the vault is sealed at the start
VaultBarrier.Enable()
# Subscribe to both outcomes
VaultButton.ActivatedEvent.Subscribe(OnVaultUnlocked)
VaultButton.NotEnoughItemsEvent.Subscribe(OnNotEnoughShards)
# Fires when the player had all required items
OnVaultUnlocked(Agent : agent) : void =
# Lower the barrier — the vault is open!
VaultBarrier.Disable()
# Disable the button so it can't be used again
VaultButton.Disable()
# Award bonus score equal to the configured item score
# (KeyItemIndex 0 is Crystal Shards)
var Score : int = VaultButton.GetItemScore(0)
# Fires when the player tried but didn't have enough shards
OnNotEnoughShards(Agent : agent) : void =
# Find out exactly how many more the player needs
var Remaining : int = VaultButton.GetRemainingItemCountRequired(0)
# Update the button text with a dynamic hint
VaultButton.SetInteractionText(
VaultPrompt("Need {Remaining} more Crystal Shards")
)
Line-by-line explanation
| Lines | What's happening |
|---|---|
VaultPrompt<localizes> |
Verse requires message parameters to be localized values. This helper wraps a runtime string into the correct type. |
SetInteractionText |
Overrides the default button label. Limited to 150 characters; passing an empty string reverts to the device default. |
SetInteractionTime(1.5) |
Players must hold the interact key for 1.5 seconds — prevents accidental activation. |
VaultBarrier.Enable() |
Ensures the barrier is up at game start regardless of its default state. |
ActivatedEvent.Subscribe |
Registers OnVaultUnlocked as the success handler. The event sends the agent who activated the button. |
NotEnoughItemsEvent.Subscribe |
Registers OnNotEnoughShards as the failure handler. |
GetItemScore(0) |
Reads the score value configured for key item 0 in the device panel — useful for awarding points. |
GetRemainingItemCountRequired(0) |
Returns how many more of item 0 the player still needs, enabling a precise HUD hint. |
Common patterns
Pattern 1 — Runtime item count adjustment and hold-to-pay gate
Sometimes you want the vault to get harder as the game progresses. This snippet raises the required item count after the first activation and re-enables the button for the next wave.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
ScalingGatePrompt<localizes>(S : string) : message = "{S}"
scaling_gate_device := class(creative_device):
@editable
Gate : conditional_button_device = conditional_button_device{}
# Track how many times the gate has been opened
var OpenCount : int = 0
OnBegin<override>()<suspends> : void =
# Start: require 2 tokens (KeyItemIndex 0)
Gate.SetItemCountRequired(0, 2)
Gate.SetInteractionText(ScalingGatePrompt("Pay 2 Tokens to pass"))
Gate.ActivatedEvent.Subscribe(OnGateOpened)
OnGateOpened(Agent : agent) : void =
set OpenCount = OpenCount + 1
# Each wave costs one more token, up to a cap of 10
var CurrentRequired : int = Gate.GetItemCountRequired(0)
var NewRequired : int = CurrentRequired + 1
if (NewRequired <= 10):
Gate.SetItemCountRequired(0, NewRequired)
Gate.SetInteractionText(
ScalingGatePrompt("Pay {NewRequired} Tokens to pass")
)
# Re-enable so the next player can try
Gate.Enable()
Pattern 2 — Checking inventory before a programmatic activation
Sometimes you want to trigger the button from code (e.g., when a timer expires) but only if the player already has the goods. Use HasAllItems (a <decides> function) to guard the call.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
TimedVaultPrompt<localizes>(S : string) : message = "{S}"
timed_vault_device := class(creative_device):
@editable
VaultButton : conditional_button_device = conditional_button_device{}
@editable
CountdownTimer : timer_device = timer_device{}
OnBegin<override>()<suspends> : void =
VaultButton.SetInteractionText(TimedVaultPrompt("Claim your reward"))
CountdownTimer.SuccessEvent.Subscribe(OnTimerExpired)
# When the countdown ends, try to force-activate for each eligible player
OnTimerExpired(Agent : agent) : void =
# HasAllItems<decides> — only activates if the agent has every required item
if (VaultButton.HasAllItems[Agent]):
VaultButton.Activate(Agent)
Pattern 3 — Holding-item HUD and per-item inventory inspection
This snippet subscribes to NotEnoughItemsEvent and uses IsHoldingItem plus GetItemCount to give the player a granular status message about which item they're missing.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
StatusPrompt<localizes>(S : string) : message = "{S}"
inventory_inspector_device := class(creative_device):
@editable
CraftingStation : conditional_button_device = conditional_button_device{}
OnBegin<override>()<suspends> : void =
CraftingStation.SetInteractionText(StatusPrompt("Craft Item"))
CraftingStation.NotEnoughItemsEvent.Subscribe(OnCraftFailed)
CraftingStation.ActivatedEvent.Subscribe(OnCraftSuccess)
OnCraftFailed(Agent : agent) : void =
# Check item slot 0 (e.g., Wood) and item slot 1 (e.g., Metal)
var WoodCount : int = CraftingStation.GetItemCount(Agent, 0)
var MetalCount : int = CraftingStation.GetItemCount(Agent, 1)
var WoodNeeded : int = CraftingStation.GetItemCountRequired(0)
var MetalNeeded : int = CraftingStation.GetItemCountRequired(1)
# Is the player at least holding the right item type?
if (CraftingStation.IsHoldingItem[Agent, 0]):
# They have some wood but not enough
CraftingStation.SetInteractionText(
StatusPrompt("Wood: {WoodCount}/{WoodNeeded} — need more!")
)
else:
CraftingStation.SetInteractionText(
StatusPrompt("You have no Wood at all!")
)
OnCraftSuccess(Agent : agent) : void =
# Re-enable after a short delay for the next craft
CraftingStation.Disable()
CraftingStation.Enable()
Gotchas
1. SetInteractionText requires a message, not a raw string
Verse's message type is a localized value — you cannot pass a plain string literal or a string variable directly. Always declare a <localizes> helper:
MyLabel<localizes>(S : string) : message = "{S}"
// then:
Button.SetInteractionText(MyLabel("Open Vault"))
There is no StringToMessage function. Forgetting this causes a compile error.
2. HasAllItems and IsHoldingItem are <decides> functions
These are failable expressions. You must call them inside an if (or another failure context) — calling them as plain statements will not compile:
// CORRECT
if (Button.HasAllItems[Agent]):
Button.Activate(Agent)
// WRONG — compile error
Button.HasAllItems(Agent) // missing [] and failure context
3. KeyItemIndex is zero-based and must match the panel configuration
KeyItemIndex runs from 0 to (number of configured key item types − 1). If you call GetItemCount(Agent, 2) but only two key items are configured in the properties panel (indices 0 and 1), the result is undefined. Always keep your Verse index calls in sync with the device panel.
4. int and float do not auto-convert
SetInteractionTime takes a float. Passing an integer literal like 2 will cause a type error. Write 2.0 explicitly:
Button.SetInteractionTime(2.0) // correct
Button.SetInteractionTime(2) // compile error
5. NotEnoughItemsEvent fires on every failed attempt
If you update SetInteractionText inside OnNotEnoughShards, be aware it fires every time the player tries and fails — which is usually what you want for a live counter, but can cause rapid repeated calls if the player spam-interacts. Consider debouncing with a var flag if needed.
6. Disabling vs. using Toggle
Disable() makes the button completely non-interactive. Toggle(Agent) flips the button's internal active state (as if the player had activated it) — it does not simply enable/disable the widget. Use Disable()/Enable() for access control and Toggle(Agent) when you want to programmatically simulate an activation cycle.