AddToTeam - Unknown Identifier

Hi all, I am working on my first game, and hoping to publish this week but have run into an issue. To be honest I am struggling with verse and making very slow progress, what I have tried to do is create a script where all players are set to Team 4 as soon as the game launches, they can then move into a team selection area to select the team they want to play on.
This is my script:

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

team_assignment_device := class(creative_device):
OnBegin():void =
Print(“Verse Device Started!”)
AllPlayers := GetPlayspace().GetPlayers()
for ( Player : AllPlayers ):
AddToTeam(InAgent:Player, Team:4)
Print(“All players have been assigned to Team 4.”)

I am getting an error on the line AddToTeam(Inagent: Player, Team:4)

The error message is ‘unknown identifier’
If I change the line to Teams.AddToTeam… I get an error message saying I have left out using { /Fortnite.com }

if I add using {/Fortnite.com } I get the error AddToTeams unknown identifier in Teams.

I referred to the Verse API reference, which I find hard to follow and put into practice.

Any help would be much appreciated.

There are a few different errors here. First of all, I assume that you have indented your program properly and that it’s just a copy paste issue.

Secondly, the OnBegin event is part of the creative_device class, which means we must override it. We can do that pretty easily;

OnBegin<override>()<suspends>:void=

The main thing that stood out, is the syntax that you used in the calling of AddToTeam(). I think you’ve misunderstood something here;

    # Functions must specify the types of parameters 
    foo(Argument1 : string):void=
        Print(Argument1)

    OnBegin<override>()<suspends>:void=
        # But we don't have to specify them when we call the function,
        # the compiler already knows because of the definition!
        foo("Hello World")

        # NOT THIS (ERRORS)
        foo(Argument1 : "HelloWorld")

So let’s quickly change that;

AddToTeam(Player, 4)
What's a parameter and an argument?

The values that are declared within a function when the function is called are known as an argument. The variables that are defined when the function is declared are known as parameters.

(https://byjus.com/gate/difference-between-argument-and-parameter-in-c-and-c-plus-plus/)

You’ll quickly notice that it still doesn’t work! There are a few reasons for this:

  1. The compiler doesn’t know what AddToTeam is nor where it’s located
  2. The compiler doesn’t know what team 4 is

You mention the verse documentation, but most of the time it can be much quicker and sometimes more insightful to just look in the Verse/UnrealEngine/Fortnite.digest.verse files. In this case, I simply searched for AddToTeam in the Fortnite.digest.verse file and found:

This means, that AddToTeam is a part of the fort_team_collection class. It also says in the comments, that we can get the team collection from fort_playspace.GetTeamCollection().

In the function definition of AddToTeam() it says InTeam:team as one of the parameters. By the verse syntax, we know that it now wants an argument of type team to run the function - not an integer! (in your case 4)

So, with that knowledge we can now rewrite that part of the program. Keep in mind the new syntax that you learned around calling functions;

GetPlayspace().GetTeamCollection().AddToTeam(Player, ?)

So, now we only need one variable… but how do we get the fourth team? If we again look at the fort_team_collection in Fortnite.digest.verse, we’ll find the first function declared, GetTeams:

The expression after : is used to identify what the function is returning (:int, :void or in this case :[]team). That means, that it’s returning a list of teams. In this list, we would want the fourth team, which would be at index 3 (lists start at index 0).

So, to get the fourth team, we would simply write:

# keep in mind that it indexes 3 which means it
# has a risk of erroring, that we must remove in verse
Playspace.GetTeamCollection().GetTeams()[3]

Now, with a little bit of tidying up, the final script would look something like this (remember your includes!):

    OnBegin<override>():void=
        Playspace := GetPlayspace()

        # I'll make it a variable, as we use it more than once
        TeamCollection := Playspace.GetTeamCollection()

        # Get all players and loop through
        AllPlayers := Playspace.GetPlayers()
        for ( Player : AllPlayers ):
            # Get the specified team and add the player to it!
            # These are both deciding functions, which means they can error.
            # Therefore, we must wrap them in an if statement,
            # to remove any risk.
            if (
                FourthTeam := TeamCollection.GetTeams()[3], 
                TeamCollection.AddToTeam[Player, FourthTeam]) { }

Hope that helps :slight_smile:

2 Likes

thank you so much for you detailed (and easy to follow) explanation, that was an enormous help. It all works great in terms of assigning everyone to team 4, unfortunately though it did not do it prior to automatic team assignment from the engine itself, so players were spawning into the first assigned location. I could not get Player.Respawn() to work, so ended up modifying the code so that upon successful assignment, the players teleport to the team selection area. I have attached the full script in case this of use to anyone else with a similar problem. Thanks again for you help… it is much appreciated.

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


team_assignment_device := class(creative_device):
    @editable
    Teleporter: teleporter_device = teleporter_device {}
    
    OnBegin<override>():void=
        Print("TeamAssignment Device called")
        Playspace := GetPlayspace()

        # I'll make it a variable, as we use it more than once
        TeamCollection := Playspace.GetTeamCollection()

        # Get all players and loop through
        AllPlayers := Playspace.GetPlayers()
        for ( Player : AllPlayers ):
            # Get the specified team and add the player to it!
            # These are both deciding functions, which means they can error.
            # Therefore, we must wrap them in an if statement,
            # to remove any risk.
            if (FourthTeam := TeamCollection.GetTeams()[3]): 
                if (TeamCollection.AddToTeam[Player, FourthTeam]):
                    Teleporter.Teleport(Player)
                    Print("Players added to team 4 and teleported")
1 Like

do you mind if I ask you another question?

Ask away :upside_down_face:

Thanks,
I tried to modify my script so that it would be called based on a round setting device.
The theory being that if I only call it on round 1, then the selected teams etc. would persist on round 2 and 3. This did not work.

What I am trying to achieve is that once the teams have been assigned at the beginning of round 1, those teams will be the same for round 2 and 3 and the teams just respawn at the team bases. In addition inventory would remain, despite fixing all these settings the inventor resets every round.
If I use the script ti makes me choose a team every round.
If I make it conditional on the round settings device, it will not run the script on round 2 and 3, but also does not keep the same team and reassigns teams automatically.

I also tried checking to make the script conditional on whether the Player was already assigned to a team, but could not find a way to do that.

Not really sure where to go from here.

Would appreciate the help, and happy to compensate you for your time if neccessary.

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

assign_team_device := class(creative_device):
@editable
Teleporter: teleporter_device = teleporter_device {}

@editable 
RoundSetting: round_settings_device = round_settings_device {}


OnBegin<override>():void=
    Print("TeamAssignment Device initialized")
    # Subscribe to the RoundBeginEvent of the RoundSetting device
    RoundSetting.RoundBeginEvent.Subscribe(OnRoundBegin)

OnRoundBegin():void=
    Print("Round started, executing team assignment")
    AssignTeamsAndTeleport()

AssignTeamsAndTeleport():void=
    Playspace := GetPlayspace()
    TeamCollection := Playspace.GetTeamCollection()

    # Get all players and loop through
    AllPlayers := Playspace.GetPlayers()
    for (Player : AllPlayers):
        # Attempt to assign to the fourth team
        if (FourthTeam := TeamCollection.GetTeams()[3]): 
            if (TeamCollection.AddToTeam[Player, FourthTeam]):
                Teleporter.Teleport(Player)
                Print("Players added to team 4 and teleported")`

I think you’re just looking for the Team Visuals Determined At property of the island settings;

This should be set to Game Start, so Fortnite knows to keep the same teams for the entire game session.

This should also fix your inventory issue, as long as Override Keep Items Between Rounds and Keep Items Between Rounds are both checked in your round settings device :slight_smile:

image

I have the same settings and it does not appear to be working. Inventory clears and teams are not kept the same (autoassigned on new round)

update: I managed to get the inventory to remain between rounds, basically going through every single device that has influence in inventory and ensuring a default class is set. So now it’s how to save the team allocation from team 1.

My bad!! Team Visuals Determined At of course determines the team visuals, not the actual teams :man_facepalming: I think the correct way to do it, would be to instead save the class of the player with the Revert To Default Class At property in the island settings, which should be set to End of Game.

Now, classes and teams aren’t quite the same, but from what I’ve read on the forum here, the best way to go about this, is to decide the team from the class. I’m just really confused as to how to get the class, and thereby decide the team… maybe someone else knows?

I think the most common thing to do is to make the round system yourself, which is really annoying. Hopefully Epic add persistence soon. You can maybe use the save point device, but I’m yet to try it.

Banging away at different approaches, I will let you know if I figure it out :slight_smile:
Thanks for all your help and advice, much appreciated, hopefully I am in a position to help you out if you ever need it.

1 Like

OK, I solved the issue.

  1. Call the Assign Team script using Round Setting Device for Round 1 >
  2. When the player selects their team using the class selector trigger the Save Game device to Save Player on Team Change
  3. Round 2 > Load Player
  4. Round 3 > Load Player

Unfortunately the Save Game Device saves the team, but for whatever reason on Load Player, the player spawns randomly to spawn pads and it would appear to only spawn on Team 1 spawn pads. Not ideal; the Save Game Device does allow to save location and save checkpoint, so the quick fix was to add a checkpoint to each base and use that as the spawn location for rounds 2 and 3.

Although it is all working, I will reach out to Epic to see why on load player they do not spawn at the proper team location.

1 Like

This was very helpful to me as well! Thank you.
Would i write something similar to add join in progress players to the smallest of 2 teams? (3 total, 1 spectate team)