Reference Devices compiles

down_but_not_out_device: Reviving Teammates in Co-op

When a player's health hits zero, you don't always want them gone — in co-op games you want them crawling on the ground, waiting for a teammate to revive them. The down_but_not_out_device gives you full Verse control over that downed state: force someone down, revive them, and react to every pickup, drop, throw, and revenge-fueled shake down.

Updated Examples verified on the live UEFN compiler
Watch the Knotdown_but_not_out_device in ~90 seconds.

Overview

The down_but_not_out_device customizes (or prevents) the down but not out player state — the middle ground between healthy and removed from game. In this state a player is crawling and helpless but can still be revived by a teammate before a timer expires.

Reach for this device when you are building cooperative experiences — a mountain-climbing rescue game, a co-op zombie defense, an extraction heist — where players should depend on each other instead of just respawning. With Verse you can:

  • Force a player down on command (Down) — great for traps, story beats, or penalties.
  • Instantly revive a downed player (Revive) — e.g. when a medic reaches them or a team objective completes.
  • React to the whole lifecycle: AgentDownedEvent, AgentPickedUpEvent, AgentDroppedEvent, AgentThrownEvent, AgentRevivedEvent, and the two shake-down events (ShakeDownEvent for the aggressor, ShakenDownEvent for the victim).
  • Enable / Disable the whole system per-phase.

The key mental model: the device doesn't cause downs by itself in your code — players get downed naturally by damage, and you can also drive it manually. Either way, the events fire and you wire up scoring, UI, and rescue logic.

API Reference

down_but_not_out_device

Used to customize (or prevent) the 'down but not out' player state between 'healthy' and 'removed from game'.

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

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

Events (subscribe a handler to react):

Event Signature Description
AgentDownedEvent AgentDownedEvent<public>:listenable(agent) Signaled when an agent is set to the down but not out player state. Sends the agent that was downed.
AgentPickedUpEvent AgentPickedUpEvent<public>:listenable(agent) Signaled when an agent in the down but not out player state is picked up. Sends the agent that was picked up.
AgentDroppedEvent AgentDroppedEvent<public>:listenable(agent) Signaled when an agent in the down but not out player state is dropped. Sends the agent that was dropped.
AgentThrownEvent AgentThrownEvent<public>:listenable(agent) Signaled when an agent in the down but not out player state is thrown. Sends the agent that was thrown.
AgentRevivedEvent AgentRevivedEvent<public>:listenable(agent) Signaled when an agent in the down but not out player state is revived. Sends the agent that was revived.
ShakeDownEvent ShakeDownEvent<public>:listenable(agent) Signaled when an agent is the aggressor of a shake down. Sends the agent that is the aggressor.
ShakenDownEvent ShakenDownEvent<public>:listenable(agent) Signaled when an agent is the victim of a shake down. Sends the agent that is the victim.

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.
Down Down<public>(Agent:agent):void Sets the Agent to the down but not out player state.
Revive Revive<public>(Agent:agent):void Sets the Agent to the healthy player state if they are in the down but not out player state.

Walkthrough

Let's build a co-op rescue loop. When any player goes down, we light up a VFX beacon over the squad's rally point and bump a 'players down' counter on a progress mesh. When a teammate revives them, we clear the beacon. We also let players manually trigger a down for testing via a button-style flow, and reward the aggressor of a shake down with a score.

This example uses the device's real methods (Down, Revive, Enable) and subscribes to four of its real events.

using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

# Co-op rescue manager: reacts to downs/revives and drives a beacon + progress meter.
rescue_manager_device := class(creative_device):

    # The down but not out device placed in the level.
    @editable
    DBNO : down_but_not_out_device = down_but_not_out_device{}

    # A VFX beacon we light up while at least one teammate is down.
    @editable
    RescueBeacon : vfx_spawner_device = vfx_spawner_device{}

    # A progress mesh used as a visible 'downed players' meter.
    @editable
    DownedMeter : progress_based_mesh_device = progress_based_mesh_device{}

    # How many players are currently in the downed state.
    var DownedCount : int = 0

    OnBegin<override>()<suspends>:void =
        # Make sure the downed system is active for this round.
        DBNO.Enable()
        RescueBeacon.Disable()

        # Subscribe handlers to the device's real events.
        DBNO.AgentDownedEvent.Subscribe(OnAgentDowned)
        DBNO.AgentRevivedEvent.Subscribe(OnAgentRevived)
        DBNO.ShakeDownEvent.Subscribe(OnShakeDown)
        DBNO.AgentThrownEvent.Subscribe(OnAgentThrown)

    # Runs when ANY agent enters the downed state.
    OnAgentDowned(Agent : agent) : void =
        set DownedCount = DownedCount + 1
        # Light the rescue beacon the moment the first player goes down.
        if (DownedCount >= 1):
            RescueBeacon.Enable()
            RescueBeacon.Restart()
        UpdateMeter()

    # Runs when a downed agent is revived back to healthy.
    OnAgentRevived(Agent : agent) : void =
        set DownedCount = Max(0, DownedCount - 1)
        # No more downed players? Turn the beacon off.
        if (DownedCount <= 0):
            RescueBeacon.Disable()
        UpdateMeter()

    # The aggressor of a shake down (a damaging interaction on a downed player).
    OnShakeDown(Agent : agent) : void =
        # Reward the aggressor by manually downing them as a 'karma' twist —
        # purely a demo of calling Down() from an event.
        DBNO.Down(Agent)

    # A downed player was thrown — count them as freshly endangered.
    OnAgentThrown(Agent : agent) : void =
        UpdateMeter()

    # Push the current downed count into the progress mesh (0..100).
    UpdateMeter() : void =
        # Scale: each downed player fills 25% of the meter, clamped.
        Filled := Min(100, DownedCount * 25)
        set DownedMeter.CurrentProgress = Filled * 1.0

Line by line:

  • The three @editable fields are how Verse gets a handle on placed devices. Without declaring DBNO as a field, calling DBNO.Enable() would fail with Unknown identifier.
  • OnBegin runs once when the game starts. We Enable() the downed system and start with the beacon off.
  • Subscribe wires each event to a method. A listenable(agent) hands the handler an agent directly (not an ?agent), so the parameter type is agent.
  • OnAgentDowned increments our own counter, lights the beacon via Enable()/Restart(), and refreshes the meter.
  • OnAgentRevived decrements (clamped at 0 with Max) and disables the beacon when the squad is back up.
  • OnShakeDown demonstrates calling Down(Agent) from inside an event handler — the aggressor gets downed as a gameplay twist.
  • UpdateMeter writes a float into CurrentProgress; note DownedCount * 25 is an int, so we multiply by 1.0 to convert to float — Verse never auto-converts int↔float.

Common patterns

Pattern 1 — Force a player down with Down, then auto-rescue with Revive

A trap zone that knocks players down, then a friendly 'auto-medic' that revives them after a delay.

using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

auto_medic_device := class(creative_device):

    @editable
    DBNO : down_but_not_out_device = down_but_not_out_device{}

    # A trigger that, when stepped on, downs the player.
    @editable
    TrapTrigger : trigger_device = trigger_device{}

    OnBegin<override>()<suspends>:void =
        DBNO.Enable()
        TrapTrigger.TriggeredEvent.Subscribe(OnTrapped)

    OnTrapped(MaybeAgent : ?agent) : void =
        # A trigger sends ?agent — unwrap before use.
        if (Agent := MaybeAgent?):
            DBNO.Down(Agent)
            # Auto-rescue after a delay on a concurrent task.
            spawn { RescueLater(Agent) }

    RescueLater(Agent : agent)<suspends> : void =
        Sleep(5.0)
        DBNO.Revive(Agent)

Pattern 2 — Track pickups and drops to award a 'medic' score

React to AgentPickedUpEvent and AgentDroppedEvent to log when teammates carry downed players to safety.

using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

carry_tracker_device := class(creative_device):

    @editable
    DBNO : down_but_not_out_device = down_but_not_out_device{}

    # Counts how many downed players are currently being carried.
    var BeingCarried : int = 0

    OnBegin<override>()<suspends>:void =
        DBNO.Enable()
        DBNO.AgentPickedUpEvent.Subscribe(OnPickedUp)
        DBNO.AgentDroppedEvent.Subscribe(OnDropped)

    OnPickedUp(Agent : agent) : void =
        set BeingCarried = BeingCarried + 1

    OnDropped(Agent : agent) : void =
        set BeingCarried = Max(0, BeingCarried - 1)

Pattern 3 — Punish the victim of a shake down with ShakenDownEvent

Use the victim-side event to disable the whole system briefly (e.g. a 'no revives' penalty window).

using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

shakedown_penalty_device := class(creative_device):

    @editable
    DBNO : down_but_not_out_device = down_but_not_out_device{}

    OnBegin<override>()<suspends>:void =
        DBNO.Enable()
        DBNO.ShakenDownEvent.Subscribe(OnShakenDown)

    OnShakenDown(Victim : agent) : void =
        # Briefly disable, then re-enable the downed system.
        spawn { PenaltyWindow() }

    PenaltyWindow()<suspends> : void =
        DBNO.Disable()
        Sleep(10.0)
        DBNO.Enable()

Gotchas

  • The events hand you a bare agent, not ?agent. A listenable(agent) (like all the DBNO events) gives the handler (Agent : agent) directly — no unwrap needed. Only sources like trigger_device.TriggeredEvent send ?agent, which you unwrap with if (A := MaybeAgent?):.
  • Down and Revive take a plain agent. If you have a player or fort_character, pass the corresponding agent. You can check current state with fort_character.IsDownButNotOut[] (from /Fortnite.com/Characters) — note it's a failable <decides> call, so use it inside an if.
  • Revive only works on a downed agent. Calling Revive on a healthy player does nothing — it specifically sets a down but not out agent back to healthy.
  • int ↔ float never auto-converts. Writing into CurrentProgress (a float) from an int count requires an explicit conversion like Count * 1.0.
  • You must declare the device as an @editable field and assign it in the editor's Details panel. A bare down_but_not_out_device{} literal is just a placeholder for the field default — the real linkage happens in UEFN.
  • Disable stops the whole system, so any down/revive logic and events go quiet until you Enable() again. Re-enable before you expect the next down.
  • Localized text: if you later show a downed-player message via a hud_message_device, the message param needs a <localizes> value — there is no StringToMessage.

Guides & scripts that use down_but_not_out_device

Step-by-step tutorials that put this object to work.

Build your own lesson with down_but_not_out_device

Generate a personalized, step-by-step lesson plan built around this object — grounded in this exact reference and our compile-verified knowledge base.

Build a lesson →