Hidden Cove Ambush: elimination_result and EliminatedEvent

In this lesson you'll learn to

  • βœ“Student can subscribe to fort_character EliminatedEvent, read elimination_result (who/by-whom), and drive game logic from eliminations.

Student can subscribe to fort_character EliminatedEvent, read elimination_result (who/by-whom), and drive game logic from eliminations.

πŸ“– Reference & full walkthrough: Hidden Cove Ambush: elimination_result and EliminatedEvent

🧩 Your capstone piece: DNF handling: eliminated racers leave the roster, feed the kill-ticker, become spectators (content/verse compile-PASSED; support tracking-player-health-shields + elimination-feed-device PASS; elimination-manager-device FAILS 1 err β€” fix as supporting ref)


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.

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 }

# Last-afloat detector: count down eliminations to find the survivor.
last_afloat_tracker := class(creative_device):

    var RemainingCount : int = 0

    OnBegin<override>()<suspends> : void =
        AllPlayers := GetPlayspace().GetPlayers()
        set RemainingCount = AllPlayers.Length
        for (RacerPlayer : AllPlayers):
            spawn { AwaitElimination(RacerPlayer) }

    AwaitElimination(RacerPlayer : player)<suspends> : void =
        if (Character := RacerPlayer.GetFortCharacter[]):
            # We only care THAT it fired here, not who did it.
            Character.EliminatedEvent().Await()
            set RemainingCount -= 1
            if (RemainingCount = 1):
                Print("One racer left afloat - time to end the round!")

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.

πŸ”’

Keep going β€” free

You've read the intro. The rest of this lesson is free for members. Sign in to continue and track your progress.

Sign in free to continue this lesson
Pass the quiz above to chart this quest in your Journal.

Sources

/guides/elimination-event
Source

Biloxi Studios original lesson

Guided course

Add this lesson to your free study plan.

🧭 The Keeper’s log

Quest complete? Chart your next heading from the πŸ¦‘ West Coves expedition.

β›΅ Take me there