ReferenceDevices

supply_drop_spawner_device: Aerial Loot on Command

Want a parachuting loot crate to drop in when a player captures a point — and to react when they pop the balloon or crack it open? The supply_drop_spawner_device gives you a full lifecycle of events and methods to script aerial supply drops entirely in Verse.

Updated Compile verifiedExamples verified on the live UEFN compiler
Watch the Knot — supply_drop_spawner_device in ~90 seconds.

Overview

The supply_drop_spawner_device spawns an aerial supply crate — the classic balloon-and-parachute loot box — and lets you customize and control it from Verse. It solves a very common island-design problem: getting loot to players at a dramatic, controlled moment (after a king-of-the-hill capture, when a boss dies, at the start of a round, etc.) instead of relying on natural world spawns.

Reach for it when you want to:

  • Spawn loot on cue — call Spawn() (or Spawn(Agent) to set the owning team) from any game event.
  • Gate the loot — Lock() and Unlock() decide whether players can open the crate.
  • React to the crate's lifecycle — subscribe to LandingEvent, BalloonPoppedEvent, OpenedEvent, and DestroyCrateEvent to drive scoring, VFX, or follow-up events.
  • Add drama — DestroyBalloon() cuts the parachute so the crate freefalls, and Open(Agent) force-opens it regardless of lock state.
  • Clean up — DestroySpawnedDrops() removes any drops this device spawned.

Unlike the item spawner, this device gives you the whole crate experience: balloon, descent, landing, and the moment of opening — each one a hook you can script.

API Reference

supply_drop_spawner_device

Used to spawn and configure an aerial supply drop that can provide players with customized weapons/supplies.

Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).

supply_drop_spawner_device<public> := class<concrete><final>(creative_device_base):

Events (subscribe a handler to react):

Event Signature Description
BalloonPoppedEvent BalloonPoppedEvent<public>:listenable(?agent) Signaled when the balloon on the supply crate is popped. Sends the ?agent that popped the balloon. If no agent popped the balloon returns false.
OpenedEvent OpenedEvent<public>:listenable(agent) Signaled when the supply crate is opened. Sends the agent that opened the crate.
LandingEvent LandingEvent<public>:listenable(tuple()) Signaled when the supply crate lands for the first time.
DestroyCrateEvent DestroyCrateEvent<public>:listenable(?agent) Signaled when the supply crate is destroyed. Sends the destroying agent. If no agent destroyed the crate then false is returned.

Methods (call these to make the device act):

Method Signature Description
Spawn Spawn<public>(Agent:agent):void Spawns a supply drop provided one hasn't already spawned. Owning Team is set to Agent's team.
Spawn Spawn<public>():void Spawns a supply drop provided one hasn't already spawned.
DestroyBalloon DestroyBalloon<public>():void Destroys the balloon and causes the supply crate to freefall.
Open Open<public>(Agent:agent):void Opens the supply crate, ignoring the locked or unlocked state. Agent acts as the instigator of the open action.
Lock Lock<public>():void Locks the supply crate so agents cannot open it.
Unlock Unlock<public>():void Unlocks the supply crate so agents can open it.
DestroySpawnedDrops DestroySpawnedDrops<public>():void Destroys supply drops spawned by this device.

Walkthrough

Let's build a "reward drop" scenario. When a player steps on a capture trigger, we spawn a supply drop for that player's team. The crate starts locked so nobody can grab it mid-air. The moment it lands, we unlock it. When a player opens it, we lock it again so it can't be looted twice, and we destroy the spawned drops to clear the area.

supply_drop_game := class(creative_device):

    # Drag your Supply Drop Spawner device here in the Details panel.
    @editable
    DropSpawner : supply_drop_spawner_device = supply_drop_spawner_device{}

    # A trigger the player steps on to call in the drop.
    @editable
    CaptureTrigger : trigger_device = trigger_device{}

    OnBegin<override>()<suspends>:void =
        # React to the player stepping on the capture trigger.
        CaptureTrigger.TriggeredEvent.Subscribe(OnCaptured)
        # React to the crate's lifecycle.
        DropSpawner.LandingEvent.Subscribe(OnLanded)
        DropSpawner.OpenedEvent.Subscribe(OnOpened)
        DropSpawner.BalloonPoppedEvent.Subscribe(OnBalloonPopped)

    # TriggeredEvent hands us a ?agent — unwrap it before use.
    OnCaptured(MaybeAgent : ?agent) : void =
        if (Player := MaybeAgent?):
            # Spawn the drop owned by the capturing player's team.
            DropSpawner.Spawn(Player)
            # Lock it so it can't be opened while still in the air.
            DropSpawner.Lock()

    # LandingEvent carries an empty tuple() — no agent.
    OnLanded() : void =
        # Now that it's on the ground, let players open it.
        DropSpawner.Unlock()

    # OpenedEvent hands us a plain agent (already unwrapped).
    OnOpened(Agent : agent) : void =
        # Lock it again so it can't be re-opened, then clean up.
        DropSpawner.Lock()
        DropSpawner.DestroySpawnedDrops()

    # BalloonPoppedEvent hands a ?agent (could be a stray bullet).
    OnBalloonPopped(MaybeAgent : ?agent) : void =
        if (Popper := MaybeAgent?):
            # A player shot the balloon — let it freefall the rest of the way.
            DropSpawner.DestroyBalloon()

Line by line:

  • The two @editable fields are how Verse reaches placed devices. You drop the real devices into these slots in the Details panel; a bare supply_drop_spawner_device{} default is just a placeholder until you assign one.
  • OnBegin is where all subscriptions happen. Every Subscribe call wires one of the device's events to a method on this class.
  • OnCaptured receives a ?agent because TriggeredEvent is listenable(?agent). We unwrap with if (Player := MaybeAgent?): before using it. DropSpawner.Spawn(Player) uses the team-aware overload so the crate belongs to the capturing player's team.
  • OnLanded takes no parameter — LandingEvent is listenable(tuple()), an empty payload. We Unlock() here so the crate is now openable.
  • OnOpened gets a plain agent (not optional) because OpenedEvent is listenable(agent) — no unwrap needed. We Lock() and DestroySpawnedDrops() to prevent double-looting.
  • OnBalloonPopped gets a ?agent; once a player pops the balloon we DestroyBalloon() for a fast freefall finish.

Common patterns

Force-open a crate from another event

Use Open(Agent) to crack the crate open regardless of lock state — handy when a separate "detonate" button should blow it open for whoever pressed it.

force_open_drop := class(creative_device):

    @editable
    DropSpawner : supply_drop_spawner_device = supply_drop_spawner_device{}

    @editable
    OpenButton : button_device = button_device{}

    OnBegin<override>()<suspends>:void =
        OpenButton.InteractedWithEvent.Subscribe(OnButtonPressed)

    OnButtonPressed(Agent : agent) : void =
        # Open ignores lock/unlock state; Agent is the instigator.
        DropSpawner.Open(Agent)

React to the crate being destroyed and respawn it

DestroyCrateEvent fires when the crate is gone — a great place to award points and call in a fresh drop.

respawning_drop := class(creative_device):

    @editable
    DropSpawner : supply_drop_spawner_device = supply_drop_spawner_device{}

    @editable
    ScoreManager : score_manager_device = score_manager_device{}

    OnBegin<override>()<suspends>:void =
        DropSpawner.DestroyCrateEvent.Subscribe(OnCrateDestroyed)
        # Kick off the first drop when the game starts.
        DropSpawner.Spawn()

    OnCrateDestroyed(MaybeAgent : ?agent) : void =
        if (Destroyer := MaybeAgent?):
            # Reward whoever destroyed the crate.
            ScoreManager.Activate(Destroyer)
        # Bring in a replacement drop.
        DropSpawner.Spawn()

A timed drop on a delay

Spawn a no-team drop after a delay using Sleep, then clean up old drops first so only one exists.

timed_drop := class(creative_device):

    @editable
    DropSpawner : supply_drop_spawner_device = supply_drop_spawner_device{}

    OnBegin<override>()<suspends>:void =
        # Clear anything left over, then wait and spawn.
        DropSpawner.DestroySpawnedDrops()
        Sleep(30.0)
        DropSpawner.Spawn()
        DropSpawner.Unlock()

Gotchas

  • LandingEvent has no agent. It is listenable(tuple()), so its handler must take no parameters (OnLanded() : void). Writing OnLanded(A : agent) will not match the subscription signature.
  • OpenedEvent is agent, the others are ?agent. OpenedEvent hands you a ready-to-use agent. BalloonPoppedEvent and DestroyCrateEvent hand a ?agent because a non-agent (a stray bullet, the environment) might have caused it — always unwrap with if (X := Maybe?):.
  • Spawn() is no-op if a drop already exists. The device won't spawn a second crate while one is live. Call DestroySpawnedDrops() first if you want a guaranteed fresh drop.
  • Open(Agent) ignores lock state. Lock() only blocks players from manually opening the crate — Open(Agent) will force it open anyway. Don't rely on Lock() to stop a scripted Open.
  • You must declare the device as an @editable field. Calling DropSpawner.Spawn() only works because DropSpawner is a field referencing a placed device. A bare local of type supply_drop_spawner_device{} will compile but do nothing in the world.
  • Two Spawn overloads. Spawn(Agent) sets the owning team to the agent's team; Spawn() spawns with no owning team. Pick deliberately based on whether team ownership matters for your loot rules.

Guides & scripts that use supply_drop_spawner_device

Build your own lesson with supply_drop_spawner_device

Generate a personalized, compile-checked lesson grounded in this exact reference.

Build a lesson →