Overview
The item_granter_device delivers weapons and items into a player's hands. In the editor you fill its Item List with one or more entries (a shotgun, an assault rifle, a bandage), and from Verse you decide when and to whom they're granted.
Reach for it whenever the game needs to give something:
- A button that grants a sword so the player can break a door.
- A reward chest that hands out a random weapon each open.
- A round-start loadout that arms every player at once.
- A vending machine that cycles forward/back through a weapon menu.
The device exposes three families of behavior:
- Grant —
GrantItem,GrantItemToAll,GrantItemIndexpush items to players. - Cycle / select —
CycleToNextItem,CycleToPreviousItem,CycleToRandomItem,SetNextItem,GetItemIndexmove the "selected" item. - Inventory bookkeeping —
GetItemGrantCountAtIndex,SetItemGrantCountAtIndex,RestockItems,ClearSaveDatamanage stock and counts.
And it tells you when a grant happened via ItemGrantedEvent and GrantItemWithCountEvent.
API Reference
item_granter_device
Used to grant items to
agents. Items can either be dropped at theagent's location or added directly to their inventory.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
item_granter_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
ItemGrantedEvent |
ItemGrantedEvent<public>:listenable(agent) |
Signaled when an item is granted to an agent. Sends the agent that was granted the item. |
GrantItemWithCountEvent |
GrantItemWithCountEvent<public>:listenable(tuple(agent, int)) |
Signaled when an item is granted to an agent. Sends the agent that was granted the item, as well as the number of items granted. |
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. |
ClearSaveData |
ClearSaveData<public>(Agent:agent):void |
Clears saved data for Agent, preventing them from receiving items while offline. This only works when Grant While Offline is set to Yes. |
CycleToNextItem |
CycleToNextItem<public>(Agent:agent):void |
Cycles to the next item. If Grant on Cycle is set Agent will be granted the item. |
CycleToPreviousItem |
CycleToPreviousItem<public>(Agent:agent):void |
Cycles to the previous item. If Grant on Cycle is set Agent will be granted the item. |
CycleToRandomItem |
CycleToRandomItem<public>(Agent:agent):void |
Cycles to a random item. If Grant on Cycle is set Agent will be granted the item. |
GrantItem |
GrantItem<public>(Agent:agent):void |
Grants an item to Agent. |
GrantItemToAll |
GrantItemToAll<public>():void |
Grants an item without requiring an agent reference. This only works when Receiving Players is set to All or Team Index. |
GrantItemIndex |
GrantItemIndex<public>(Agent:agent, ItemIndex:int):void |
Grants an item at a specific ItemIndex to an Agent. Index should be between 0 and the available item count - 1. If Value is out of bounds, which item is granted is determined by Cycle Behavior. |
GrantItemIndex |
GrantItemIndex<public>(ItemIndex:int):void |
Grants an item at a specific ItemIndex to all players. Only functions when Receiving Players is set to All or Team Index. Index should be between 0 and the available item count - 1. If Value is out of bounds, which item is grant |
GetItemIndex |
GetItemIndex<public>()<transacts>:int |
Returns the current Item Index that this device will grant when activated. |
GetItemGrantCountAtIndex |
GetItemGrantCountAtIndex<public>(Index:int)<transacts>:int |
Returns the number of items this Item Granter will award for the item at the specified Index. This will return 0 if Index is invalid. If Cycle Behavior is Stop, Index is clamped to the number of items in the Item Granter. If *Cycl |
SetItemGrantCountAtIndex |
SetItemGrantCountAtIndex<public>(ItemIndex:int, Count:int):void |
Sets the number of items this Item Granter will award for the item at the specified ItemIndex. Count must be greater than 0. If Cycle Behavior is Stop, ItemIndex is clamped to the number of items in the Item Granter. If *Cycle Beh |
RestockItems |
RestockItems<public>():void |
Restocks this device back to its starting inventory count. |
SetNextItem |
SetNextItem<public>(Index:int):void |
Sets the next item to be granted. * Index should be between 0 and the available item count - 1. * Calling SetNextItem with an invalid index will do nothing. |
Walkthrough
Let's build a reward terminal. A trigger (the terminal the player interacts with) grants the player whatever item is currently selected, then immediately cycles to the next item so repeated uses hand out a rotating loadout. We also subscribe to ItemGrantedEvent so we can flash a HUD message, and to GrantItemWithCountEvent so we can read how many were given.
reward_terminal := class(creative_device):
# The granter you placed and filled with an Item List.
@editable
Granter : item_granter_device = item_granter_device{}
# The trigger the player steps on / interacts with.
@editable
UseTrigger : trigger_device = trigger_device{}
# Optional HUD feedback.
@editable
FeedbackHUD : hud_message_device = hud_message_device{}
# Localized text helper — message params need a localized value, not a raw string.
Msg<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
# React when the player triggers the terminal.
UseTrigger.TriggeredEvent.Subscribe(OnUsed)
# React when ANY item is granted by this device.
Granter.ItemGrantedEvent.Subscribe(OnItemGranted)
# React with the count of items granted.
Granter.GrantItemWithCountEvent.Subscribe(OnItemGrantedWithCount)
# TriggeredEvent hands us a ?agent — unwrap before using it.
OnUsed(Agent : ?agent) : void =
if (Player := Agent?):
# Grant the currently selected item to this player.
Granter.GrantItem(Player)
# Then advance the selection so the next use gives the next item.
Granter.CycleToNextItem(Player)
# ItemGrantedEvent gives us the agent directly (listenable(agent)).
OnItemGranted(Agent : agent) : void =
# Read which index is now selected after the grant.
CurrentIndex := Granter.GetItemIndex()
FeedbackHUD.Show(Agent, Msg("Item granted! Next item index: {CurrentIndex}"))
# GrantItemWithCountEvent gives us a tuple(agent, int).
OnItemGrantedWithCount(Payload : tuple(agent, int)) : void =
Agent := Payload(0)
Count := Payload(1)
FeedbackHUD.Show(Agent, Msg("You received {Count} item(s)."))
Line by line:
@editable Granter : item_granter_device— you MUST declare the placed device as an editable field, then link it in the Details panel. CallingGranter.GrantItem(...)only works becauseGranteris a real field.Msg<localizes>(S : string) : message— HUD'sShowtakes amessage(localized text). There is noStringToMessage; this helper wraps a string into amessage.- In
OnBeginweSubscribethree handlers. Subscriptions belong inOnBegin; the handlers themselves are methods at class scope. OnUsed(Agent : ?agent)—TriggeredEventislistenable(?agent), so the parameter is an optional agent.if (Player := Agent?):unwraps it.Granter.GrantItem(Player)grants the selected item;Granter.CycleToNextItem(Player)advances the selection for next time.OnItemGranted(Agent : agent)—ItemGrantedEventislistenable(agent), so the agent arrives already unwrapped.GetItemIndex()returns the current index (it<transacts>, so it's safe to call inline).OnItemGrantedWithCount(Payload : tuple(agent, int))— read tuple elements withPayload(0)andPayload(1).
Common patterns
Arm everyone at round start with GrantItemToAll
When Receiving Players is set to All (or Team Index), you can grant without an agent reference. Great for round-start loadouts.
round_start_loadout := class(creative_device):
@editable
LoadoutGranter : item_granter_device = item_granter_device{}
# A trigger that fires when the round begins.
@editable
RoundStartTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
RoundStartTrigger.TriggeredEvent.Subscribe(OnRoundStart)
OnRoundStart(Agent : ?agent) : void =
# No agent needed — grants to all receiving players at once.
LoadoutGranter.GrantItemToAll()
A vending machine that cycles and grants a specific index
Use CycleToRandomItem for a loot-box feel, or GrantItemIndex to hand out an exact slot.
loot_vending := class(creative_device):
@editable
Granter : item_granter_device = item_granter_device{}
@editable
RandomButton : button_device = button_device{}
@editable
BandageButton : button_device = button_device{}
OnBegin<override>()<suspends> : void =
RandomButton.InteractedWithEvent.Subscribe(OnRandom)
BandageButton.InteractedWithEvent.Subscribe(OnBandage)
OnRandom(Agent : agent) : void =
# Pick a random item, then grant whatever is now selected.
Granter.CycleToRandomItem(Agent)
Granter.GrantItem(Agent)
OnBandage(Agent : agent) : void =
# Always grant the item at index 3 (e.g. a bandage) to this player.
Granter.GrantItemIndex(Agent, 3)
Restock and adjust grant counts
Granters have a finite starting inventory. Refill it with RestockItems, and tune how many of an item each grant awards with SetItemGrantCountAtIndex / GetItemGrantCountAtIndex.
ammo_resupply := class(creative_device):
@editable
AmmoGranter : item_granter_device = item_granter_device{}
@editable
ResupplyTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
# Set item 0 to hand out 30 per grant.
AmmoGranter.SetItemGrantCountAtIndex(0, 30)
ResupplyTrigger.TriggeredEvent.Subscribe(OnResupply)
OnResupply(Agent : ?agent) : void =
if (Player := Agent?):
# Refill the device to its starting stock.
AmmoGranter.RestockItems()
# Read back the configured count (returns 0 if index is invalid).
CountForSlot0 := AmmoGranter.GetItemGrantCountAtIndex(0)
# Pre-select item 0 so the next GrantItem uses it.
AmmoGranter.SetNextItem(0)
AmmoGranter.GrantItem(Player)
Gotchas
- Bare device calls fail.
item_granter_device.GrantItem(...)is an "Unknown identifier" error. You must declare an@editablefield, place + link the device, then callField.GrantItem(...). GrantItemToAlland the agent-lessGrantItemIndex(ItemIndex)need the right setting. They only work when Receiving Players is All or Team Index. With Selected you must pass an agent.- Two events, two shapes.
ItemGrantedEventislistenable(agent)— the handler gets(Agent : agent), already unwrapped.GrantItemWithCountEventislistenable(tuple(agent, int))— read it withPayload(0)/Payload(1). Don't try to unwrap theagentevent withAgent?; it isn't optional. - Trigger events ARE optional.
TriggeredEventhands you?agent, so alwaysif (P := Agent?):before using it. - Index bounds matter.
GrantItemIndexandSetNextItemexpect0to (item count − 1). An out-of-range index forGrantItemIndexfalls back to your Cycle Behavior;SetNextItemwith an invalid index simply does nothing.GetItemGrantCountAtIndexreturns0for an invalid index. - Counts must be positive.
SetItemGrantCountAtIndexrequiresCount > 0. - HUD/message params are localized. A
messagecan't take a raw string — wrap it with a<localizes>helper likeMsg(...). There is noStringToMessage. ClearSaveDataonly matters with offline grants. It clears a player's saved pending items and is a no-op unless Grant While Offline is Yes.