Level Editor/Scripting/Teams and spawning

From TeamSpec Wiki
Jump to navigation Jump to search

This page covers a mode's teams: declaring them, putting players on them, letting players change team, where they spawn, and spawn rooms.

Declaring teams

A map that declares no teams plays with two, named "Team 1" and "Team 2". To choose your own, declare them in _declare() with api.declare_team:

func _declare() -> void:
	api.declare_team("Attackers")
	api.declare_team("Defenders")
	api.declare_team("Hunter", 1)
  • The first team declared is team 1, the next team 2, and so on. declare_team returns the id.
  • The second argument caps how many players the team can hold; 0 or nothing means no cap.
  • Teams can only be declared in _declare(); a later call is ignored.
  • Team 0 is not a team. It means "on no team", which covers a player who has not been placed and a spectator. api.teams never includes it.

api.team_name, api.team_maximum, api.players_on_team and api.team_of read the teams back. The client script has the same reads.

Putting players on teams

When a player joins, _player_joined(entity_id) chooses their team. By default it puts them on whichever declared team has the fewest players (the lowest-numbered on a tie), through _assign_to_smaller_team. Override it to choose differently with api.set_team_of, and call _assign_to_smaller_team(entity_id) from your version if you still want the default for some players:

func _player_joined(entity_id: int) -> void:
	if api.players_on_team(3).is_empty():
		api.set_team_of(entity_id, 3)
	else:
		_assign_to_smaller_team(entity_id)

The game places the player at _spawn_position once _player_joined returns, so the team you choose there is the one their first spawn point comes from.

Changing team during a match

Players can change team themselves with the game's team picker. The game refuses a team that does not exist or is full, then asks your _can_join_team(entity_id, team) hook, which allows everything unless you override it. Changing team costs a life unless the player is somewhere they are allowed to change class (see Spawn rooms). Leaving to spectate is never refused.

Spawn points

Place spawn points with Functional > Spawn Point and set each one's Team in the inspector (it starts at 1). api.spawn_points(team) returns their positions.

Every spawn point shows a player standing on it, facing the way the spawn faces, inside the player's collision hull: 0.813 m across and 1.829 m tall, with a faint ring at 0.914 m, the height a ducking player fits under. Use it to judge doorways, ceilings and cover while you block out. The game drops a spawning player's feet onto the floor under the spawn point, so place spawns on the floor. The figure is the editor's alone: the map never exports it. View > Show Player Figures hides them all.

Where a player appears, on joining and on every respawn, is whatever _spawn_position(entity_id) returns. By default that is a random spawn point of the player's team. A team with no spawn points spawns at the world origin, so give every team you use at least one. Override _spawn_position for spawns that move during a round, or to spawn players somewhere else entirely:

func _spawn_position(entity_id: int) -> Vector3:
	var points: PackedVector3Array = api.spawn_points(api.team_of(entity_id))
	if points.is_empty():
		return Vector3.ZERO
	return points[0]

Only read through api in _spawn_position, and always return a position; see _spawn_position only reads.

Spawn rooms

A spawn room is a zone (see Zones and area triggers) that gives its own team three things while they stand in it: immunity, a free class change, and a refill. Nobody may build in one.

const SPAWN_ROOM := &"Spawn Room"


func _start() -> void:
	for zone in api.zones_labeled(SPAWN_ROOM):
		api.forbid_building(zone)


func _zone_entered(zone: StringName, entity_id: int) -> void:
	if api.zone_label(zone) == SPAWN_ROOM and api.team_of(entity_id) == api.zone_team(zone):
		api.set_spawn_immunity(entity_id, true)
		api.set_class_change_allowed(entity_id, true)
		api.resupply(entity_id)


func _zone_exited(zone: StringName, entity_id: int) -> void:
	if api.zone_label(zone) == SPAWN_ROOM:
		api.set_spawn_immunity(entity_id, false)
		api.set_class_change_allowed(entity_id, false)

Name each team's room "Spawn Room" and set its Zone Team, so one rule serves both. Immunity and class change are states that last until you turn them off, which is why leaving turns them off for anybody. Dying inside the room counts as leaving it.

Mirrored maps

A Mirror Node copies one half of a map onto the other (see Mirrored maps). Spawn points and zones with Team Differs Per Side ticked land on the other team in the copy; untick it for something both halves share.

TeamSpec Level Editor
Basics Getting started · Interface · Viewport and camera · Selecting and hiding · Keyboard shortcuts · Settings · Map Config · Troubleshooting
Menus File · Edit · View · Tools · Functional
Panels Scene tree · Inspector · Materials · Props · Snapping · UV editor · Displacement · Terrain
Tools Move, Rotate and Scale · Box · Sphere · Cylinder · Prism · Stairs · Spiral Stairs · Spiral Tower · Arch · Path Brush · Plane · Terrain · Clip · Duplicate · Ruler and Cordon · Edit Vertex and Edge · Edit Face · Loop Cut · Material Brush · Vertex Color Brush · Displacement · Prop Path
Entities Brush · Zone · Group · Mirror Node · Prop · Spawn Point · Supply Pickup · World Boundary · Lights · Water · Sounds · Anchor Platform · Payload Track · Boss Spawn · Map Marker · World Text · Decal · Door · Button · Logic entities · 3D Skybox · Nav Region
Workflows Your first map · Brushes and CSG · Materials and UVs · Lighting and lightmaps · Bots and navigation · Mirrored maps · Outputs and logic · Custom assets · Playtesting · Exporting and publishing · Importing Source maps
Scripting Overview · Server rules · Client HUD · Bots · Teams and spawning · Zones · Pickups · Payload tracks · Map entities · Sandbox limits · Testing · King of the Hill · Team Deathmatch · API reference · What a script may use