Dangling `=` assignment with no expressions or empty braced block `{}` on its right hand side.

Wow… so I’ve just started following the tutorial properly and its actually not that great is it. It’s outdated, missing references/devices, inconsistant formatting in the code snippets. Not great for new people trying to learn, which is pretty much everyone…

First of all, the tutorial creates a logger but doesn’t declare the indentifier for it.

# Unknown identifier `log_search_and_destroy`.
Logger: log = log { Channel := log_search_and_destroy }

So it needs this before the creative device class declaration.

log_search_and_destroy := class(log_channel){}

The next thing is on the OnBegin method, the race conditions will error for 3 reasons.

The first being that TimedObjectiveA and TimedObjectiveB are both trying to call StartedEvent, which doesn’t exist on the timed_objective_device, it’s BeganEvent.

ArmingPlayer := TimedObjectiveA.StartedEvent.Await() 
# Unknown member `StartedEvent` in `timed_objective_device`.

The same goes for the StoppedEvent, that should be EndedEvent instead.

DisarmingPlayer := TimedObjectiveA.StoppedEvent.Await()
# Unknown member `StoppedEvent` in `timed_objective_device`.

Which that then also caused the race condition to be invalid as no Async method was expressed in the condition.

Expected async expression(s) (such as a coroutine or concurrency primitive) and only found immediate expression(s) (such as an immediate function call).

The next thing is the tutorial doesn’t even mention to add beacon_devices to the world for the BombABeaconArm, BombABeaconDisarm, BombBBeaconArm and BombBBeaconDisarm.

They are included in the Verse Detonation Template that comes with UEFN, but the tutorial only tells you to reference them within the Verse device, it doesn’t have a section on setting them up. It doesn’t even mention them in the list of devices you’re going to use at the start of the tutorial.

This tutorial uses the following devices:
    8 x Explosive
    2 x Timed Objectives
    4 x Map Indicators
    1 x End Game
    ~ x Player Spawn Pad
    1 x Verse

So it’s not very helpful if you’re not using the template, which why would you if the tutorial tells you not too.

So you have to add those yourself, and it doesn’t even tell you how to configure them properly so you’ll need to copy them over from the Verse Detonation Template and paste them into your project and place them above their respective bomb sites.

But after following the tutorial, and making all those changes above, I’ve got a working game with the following script:


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

# Logs
log_search_and_destroy := class (log_channel) {}

# Types
bomb_state<public> := enum { AllUnarmed, BombAArmed, BombBArmed }

# Creative device
search_and_destroy  := class (creative_device) {
    Logger: log = log { Channel := log_search_and_destroy }

    @editable
    BombAMapIndicators: []map_indicator_device = array {}

    @editable
    BombABeaconArm: beacon_device = beacon_device {}

    @editable
    BombABeaconDisarm: beacon_device = beacon_device {}

    @editable
    BombBMapIndicators: []map_indicator_device = array {}

    @editable
    BombBBeaconArm: beacon_device = beacon_device {}

    @editable
    BombBBeaconDisarm: beacon_device = beacon_device {}

    @editable
    ExplosiveBarrelsA: []explosive_device = array {}

    @editable
    ExplosiveBarrelsB: []explosive_device = array {}

    @editable
    TimedObjectiveA: timed_objective_device = timed_objective_device {}

    @editable
    TimedObjectiveB: timed_objective_device = timed_objective_device {}

    @editable
    EndGameDevice: end_game_device = end_game_device {}

    # Set the initial bomb state to all bombs unarmed
    var BombState: bomb_state = bomb_state.AllUnarmed

    # Runs when the device is started in a running game
    # @return {void}
    OnBegin<override>()<suspends>: void = {
        # Start a race to check which bomb is armed first
        race {
            # Wait for bomb a to be armed
            block {
                # Set the player who armed bomb a
                ArmingPlayer := TimedObjectiveA.BeganEvent.Await() 
                Print("Bomb A Armed", ?Duration := 5.0)
                
                # Set the bomb state to bomb a armed
                set BombState = bomb_state.BombAArmed
                
                # Disable the other timed objective
                TimedObjectiveB.Disable(ArmingPlayer)
                
                # Iterate through all of the map indicators for bomb b
                for (MapIndicator: BombBMapIndicators) {
                    # Disable map indicator for bomb b
                    MapIndicator.Disable()
                }
            }
            
            # Wait for bomb b to be armed
            block {
                # Set the player who armed bomb b
                ArmingPlayer := TimedObjectiveB.BeganEvent.Await()
                Print("Bomb B Armed", ?Duration := 5.0)
                
                # Set the bomb state to bomb b armed
                set BombState = bomb_state.BombBArmed
                
                # Disable the other timed objective
                TimedObjectiveA.Disable(ArmingPlayer)
                
                # Iterate through all of the map indicators for bomb a
                for (MapIndicator: BombAMapIndicators) {
                    # Disable map indicator for bomb a
                    MapIndicator.Disable()
                }
            }
        }

        # Set the correct beacons to be enabled
        UpdateBeacons()

        # Start a race to check if a timed objective is completed or stopped
        race {
            # Wait for bomb a to be detonated
            block {
                # Detonate bomb a
                BombDetonated(TimedObjectiveA.CompletedEvent.Await())
            }

            # Wait for bomb b to be detonated
            block {
                # Detonate bomb b
                BombDetonated(TimedObjectiveB.CompletedEvent.Await())
            }

            # Wait for bomb a to be disarmed
            block {
                # Set the player who disarmed bomb a
                DisarmingPlayer := TimedObjectiveA.EndedEvent.Await()
                Print("Bomb Disarmed", ?Duration := 5.0)

                # Activate the end game
                EndGameDevice.Activate(DisarmingPlayer)
            }

            # Wait for bomb b to be disarmed
            block {
                # Set the player who disarmed bomb b
                DisarmingPlayer := TimedObjectiveB.EndedEvent.Await()
                Print("Bomb Disarmed", ?Duration := 5.0)

                # Activate the end game
                EndGameDevice.Activate(DisarmingPlayer)
            }
        }
    }

    # Called when a bomb is detonated.
    # @param  {agent}  Agent  The agent that detonated the bomb.
    # @return {void}
    BombDetonated(Agent: agent): void = {
        Print("Bomb Detonated", ?Duration := 5.0)

        # Check if bomb a was armed
        if (BombState = bomb_state.BombAArmed) {
            # Explode barrels for bomb a
            ExplodeBarrels(ExplosiveBarrelsA, Agent)
        } else {
            # Explode barrels for bomb b
            ExplodeBarrels(ExplosiveBarrelsB, Agent)
        }

        # Activate the end game
        EndGameDevice.Activate(Agent)
    }

    # Explode all the barrels.
    # @param  {[]explosive_device}  Barrels  The barrels to explode.
    # @param  {agent}               Agent    The agent that detonated the bomb.
    # @return {void}
    ExplodeBarrels(Barrels: []explosive_device, Agent: agent): void = {
        # Iterate through all of the barrels
        for (Barrel: Barrels) {
            # Explode the barrel
            Barrel.Explode(Agent)
        }
    }

    # Set the correct beacons to be enabled.
    # @return {void}
    UpdateBeacons(): void = {
        # Disable all arm beacons
        BombABeaconArm.Disable()
        BombBBeaconArm.Disable()

        # Check if bomb a was armed
        if (BombState = bomb_state.BombAArmed) {
            # Enable the bomb a disarm beacon
            BombABeaconDisarm.Enable()
        } else {
            # Enable the bomb b disarm beacon
            BombBBeaconDisarm.Enable()
        }
    }
}
2 Likes