Hidden Cove Ambush: elimination_result and EliminatedEvent
Tutorialintermediatecompiles

Hidden Cove Ambush: elimination_result and EliminatedEvent

Updated intermediateDevicesCode verified

Down in the West Coves, races do not always end at the finish line. Sometimes the storm ends them. Sometimes Inkbeard's kraken does. Either way, your game logic needs to know the moment a racer goes down - and know exactly who (if anyone) sent them swimming. In Verse, that moment is fort_character.EliminatedEvent(), and the who-did-what report it hands you is the elimination_result struct. This lesson teaches you to subscribe to eliminations per character, unwrap the optional eliminator, and drive real game logic from both.

What you will build

This is the DNF (Did Not Finish) handling piece of the Coastal Race capstone. When a racer is eliminated mid-race, three things must happen:

  1. They leave the roster. The race's live []player roster shrinks, so the finish logic never waits on a ghost.
  2. The kill ticker updates. Everyone sees a HUD line reporting the elimination and how many racers remain afloat.
  3. The eliminator gets credit - but only when the eliminator is a real character. The storm gets no points.

You will build a cove_elimination_tracker device that does all three. In the capstone (lesson 23), the same elimination signal also flips the downed racer into spectator mode - that camera work arrives in the first-person spectator lesson (21). Here we build the detection-and-bookkeeping core it plugs into.

Walkthrough

The two APIs at the heart of it

From the live UEFN 5.8 digest, on the fort_character interface (/Fortnite.com/Characters):

EliminatedEvent<public>():listenable(elimination_result)

Note the () - EliminatedEvent is a function that returns a listenable, unlike device events such as a trigger's TriggeredEvent, which are plain properties. You call it, then Subscribe(...) or Await() the result.

The payload it delivers is elimination_result (/Fortnite.com/Game):

elimination_result<native><public> := struct<epic_internal>:
    EliminatedCharacter<native><public>:fort_character
    EliminatingCharacter<native><public>:?fort_character

EliminatedCharacter is always there - somebody definitely went down. EliminatingCharacter is an option (?fort_character), because not every elimination has an author: storm damage, fall damage, and other environmental deaths deliver false here. That single ? is the whole reason this lesson exists - respect it and your scoring is fair; ignore it and your code fails the moment the storm takes its first victim.

The device

Place this device on your island, then wire a HUD Message device and a Score Manager device to its editable slots.

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

# Kill-ticker line: how many racers are still afloat.
RosterMsg<localizes>(Remaining : int) : message = "{Remaining} racers still afloat!"

# Ticker line when the island itself takes someone out - no eliminator to credit.
EnvironmentMsg<localizes> : message = "The coves claimed a racer. Nobody gets the point."

# Watches every racer's fort_character for elimination, keeps a live roster,
# feeds the kill ticker, and credits the eliminator's score when one exists.
cove_elimination_tracker := class(creative_device):

    # Shows the kill ticker to everyone.
    @editable
    KillTicker : hud_message_device = hud_message_device{}

    # Awards a point to the eliminator when there is one.
    @editable
    EliminationScore : score_manager_device = score_manager_device{}

    # The live roster: everyone still in the race.
    var Roster : []player = array{}

    OnBegin<override>()<suspends>:void =
        # One point per confirmed elimination.
        EliminationScore.SetScoreAward(1)

        # Everyone already on the island joins the roster and gets a watcher.
        for (RacerPlayer : GetPlayspace().GetPlayers()):
            AddRacer(RacerPlayer)

        # Late arrivals wash in too.
        GetPlayspace().PlayerAddedEvent().Subscribe(AddRacer)

    # Adds a player to the roster and starts watching their character.
    AddRacer(RacerPlayer : player) : void =
        set Roster += array{RacerPlayer}
        spawn { WatchRacer(RacerPlayer) }

    # Suspends until THIS racer's character is eliminated, then reacts once.
    WatchRacer(RacerPlayer : player)<suspends> : void =
        if (Character := RacerPlayer.GetFortCharacter[]):
            # Await suspends here until this fort_character is eliminated.
            Result := Character.EliminatedEvent().Await()
            HandleElimination(Result)

    # Reads the elimination_result: who went down, and who (maybe) did it.
    HandleElimination(Result : elimination_result) : void =
        # 1) Drop the eliminated racer from the roster - a DNF.
        if (ElimAgent := Result.EliminatedCharacter.GetAgent[], ElimPlayer := player[ElimAgent]):
            set Roster = for (RacerP : Roster, RacerP <> ElimPlayer) { RacerP }
        Print("Racer down. {Roster.Length} remain.")

        # 2) Credit the eliminator ONLY when a real character dealt the blow.
        # EliminatingCharacter is ?fort_character - it is false for the storm,
        # fall damage, and other environmental eliminations.
        if (Killer := Result.EliminatingCharacter?, KillerAgent := Killer.GetAgent[]):
            EliminationScore.Activate(KillerAgent)
            KillTicker.Show(RosterMsg(Roster.Length))
        else:
            KillTicker.Show(EnvironmentMsg)

How it flows

  1. OnBegin builds the roster from GetPlayspace().GetPlayers() and subscribes AddRacer to PlayerAddedEvent(), so late joiners are watched too.
  2. AddRacer appends the player to Roster and spawns a watcher task. spawn is the right tool because AddRacer is a plain (non-suspending) function - it must hand the waiting off to a concurrent task.
  3. WatchRacer gets the player's fort_character with the failable GetFortCharacter[], then parks on EliminatedEvent().Await(). The task sleeps rent-free until the elimination actually happens - no polling, which is exactly the prefer events over polling rule from lesson 15.
  4. HandleElimination does the bookkeeping. First it converts the eliminated fort_character back into a player: GetAgent[] is failable (<decides>), and player[ElimAgent] is a failable cast - both sit comfortably in one if. A filtered for comprehension rebuilds the roster without the downed racer.
  5. The option unwrap Result.EliminatingCharacter? inside the if succeeds only when a real character dealt the final blow. Then - and only then - EliminationScore.Activate(KillerAgent) awards the point. The else branch still feeds the ticker, crediting nobody.

Why per-character, not per-game?

Eliminations are signaled on each fort_character, not on the playspace. That is why we run one watcher task per racer. Keep in mind a fort_character is one incarnation of a player: if your mode respawns players, the respawned player has a new fort_character, and you must subscribe again. In a race with DNF rules that is a feature - one Await() per racer is exactly one elimination each.

Common patterns

Subscribe instead of Await

When you want a persistent handler rather than a one-shot wait - a kill feed, for example - pass a function taking elimination_result to Subscribe. This variation also shows the self-elimination check: fort_character is a <unique> interface, so <> comparison just works.

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

# Subscribe-based feed: one persistent handler instead of a one-shot Await.
elimination_feed_lite := class(creative_device):

    OnBegin<override>()<suspends> : void =
        for (RacerPlayer : GetPlayspace().GetPlayers()):
            if (Character := RacerPlayer.GetFortCharacter[]):
                Character.EliminatedEvent().Subscribe(OnEliminated)

    OnEliminated(Result : elimination_result) : void =
        if (Killer := Result.EliminatingCharacter?):
            if (Killer <> Result.EliminatedCharacter):
                Print("A racer was taken down by another racer.")
            else:
                Print("A racer took themselves out. Inkbeard is cackling.")
        else:
            Print("The island itself claimed one.")

Count down to the last racer afloat

Sometimes you do not care who eliminated whom - you only need to know when one racer remains. Await() returns the elimination_result, but nothing forces you to keep it.

Where this goes next

This tracker is the DNF backbone of the Coastal Race capstone (west-coves-coastal-race, lesson 23), which imports it directly: the capstone's state machine (lesson 19) listens for the roster hitting one survivor - or the checkpoint course completing - to leave its Racing state, and each racer this device removes from the roster gets handed to the first-person spectator camera (lesson 21) so a DNF still has a front-row seat for the finish. The kill ticker you built here becomes the race's live drama feed, and the score credit flows into the capstone's persistent win tracking. One elimination event, three systems fed - that is event-driven design, cove style.

Get the complete code — free

You've read the full walkthrough. The complete, copy-paste-ready Verse solution is free for members — sign in to unlock it.

Free with your BrainDead.TV / BrainDeadGuild Discord account. The walkthrough above is always free.

Check your understanding

Test yourself with an interactive quiz and track your progress + earn XP — free for members.

Turn this into a guided course

Add How to subscribe to fort_character EliminatedEvent, read elimination_result (who was eliminated and by whom), and drive roster, kill-ticker, and scoring logic from eliminations in UEFN to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.

Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.

Comments

    Sign in to vote, comment, or suggest an edit.Sign in