Level Editor/Scripting/Reference/GamemodeServerScript
The base class of server.gd: the script starts with extends GamemodeServerScript.
The base class of a map's server.gd: the rules of its gamemode.
Override the hooks your mode needs and leave the rest; each one already does something sensible. Everything the script can do goes through api.
This script runs only on the server, so it is the one place that can change the match: counters, teams, respawns, pickups and the winner.
See Level Editor/Scripting/Reference for every class, and Level Editor/Scripting/Reference/Sandbox for the rest of GDScript a script may use.
Properties
api
server.gdEverything this script can do goes through api. See GamemodeServerApi.
Everything this script can do, as a GamemodeServerApi.
Hooks
_declare
server.gdDeclare every counter and team the mode uses. Runs once, before anything else, and is the only place declarations work.
void_start
server.gdThe map is live. Set up the round here. The level's supply packs are already out.
void_player_joined
server.gdA player joined. Give them a team here with api.set_team_of; the default puts them on the smallest team. Once this returns, the game places them at _spawn_position. Their first spawn is observed here: _player_spawned runs only when they come back after dying.
entity_id:intReturns:void
_assign_to_smaller_team
server.gdPuts the player with their Steam party when it is already playing and its team has room, otherwise on whichever declared team has the fewest players, the lowest team on a tie. A player who already has a team is left where they are. Call it from your own _player_joined to keep the default for some players.
entity_id:intReturns:void
_can_join_team
server.gdMay this player change to this team? Return false to refuse. Asked only after the game has checked that the team exists and is not full. The default allows everything.
Not asked when a player leaves to spectate: that is always allowed.
entity_id:intteam:intReturns:bool
_player_spawned
server.gdA player came back to life after dying, at the position _spawn_position chose. Not called for the first spawn after joining; that is _player_joined.
entity_id:intReturns:void
_player_died
server.gdA player died. They stay dead until you call api.respawn_in: pass default_seconds, the player's normal respawn time, or a different number, or nothing at all for an elimination round.
killer_id is the player who gets the kill, or -1 when nobody earned it. api.death_position() is where they died.
entity_id:intkiller_id:intdefault_seconds:floatReturns:void
_player_left
server.gdA player left the match for good. Forget anything you kept about them.
entity_id:intReturns:void
_spawn_position
server.gdWhere this player should appear, on joining and on every respawn. The default picks one of their team's spawn points at random.
Runs while the player is being placed, apart from the other hooks: only read through api here, change nothing, and always return a position.
entity_id:intReturns:Vector3
_zone_entered
server.gdA living player walked into a zone. Compare api.zone_label(zone) with the name you gave it in the editor.
zone:StringNameentity_id:intReturns:void
_zone_exited
server.gdA player is no longer in a zone: they walked out, died or left the match. Do not assume they are alive somewhere else.
zone:StringNameentity_id:intReturns:void
_zone_used
server.gdA player standing in a usable zone pressed the use key. A zone is usable when its Area Trigger has a Use Prompt, which the HUD shows to anyone inside it.
zone:StringNameentity_id:intReturns:void
_form_submitted
server.gdA player applied a tile map you opened on them with api.open_tile_map. form is the name you gave it, and values holds one option index per tile, in the order you sent them. The game has already checked that the answer fits the map you sent, but a player can apply the same map again, so make applying it twice harmless.
entity_id:intform:StringNamevalues:PackedInt32ArrayReturns:void
_left_world
server.gdA player fell out of the world: they went below the map's World Boundary. The default kills them, with nobody credited. Override it to do something else, such as putting them back.
entity_id:intReturns:void
_zone_tick
server.gdEvery server tick, for every zone, including empty ones, so a capture meter can drain when nobody is on the point. occupants are the living players inside, sorted. delta is the seconds since the last tick.
zone:StringNameoccupants:Arraydelta:floatReturns:void
_track_marker
server.gdThe cart on track passed one of its markers (see api.track_markers). forward is true when it reached the marker going forward, and false when it rolled back past it. A cart standing exactly on a marker has reached it. Several markers passed in one tick arrive in the order the cart passed them. Called before _tick, so _tick already sees what you set here. A marker the cart starts the round on or behind is not passed.
track:StringNamemarker:StringNameforward:boolReturns:void
_can_collect
server.gdMay this player take this pickup? Return false to refuse. Asked when they come close enough, and again when it reaches them. The default lets anybody take anything.
handle:intentity_id:intReturns:bool
_pickup_collected
server.gdA player took a pickup. The handle still answers api.pickup_kind, api.pickup_team and api.pickup_position during this hook; afterwards it is gone. Health and ammo packs refill the player by themselves.
handle:intentity_id:intReturns:void
_pickup_expired
server.gdA pickup ran out of lifetime and vanished untaken.
handle:intReturns:void
_entity_damaged
server.gdA boss took damage. entity is its entity id (see api.bosses), amount the health it lost, and attacker the player who dealt it, or -1 for nobody. api.entity_health already reads what it has left.
entity:intamount:floatattacker:intReturns:void
_entity_died
server.gdA boss died. killer is the player who landed the last blow, or -1 for nobody. It sinks into its pool and stays dead; what that means for the match, killing the enemy's boss wins, say, is the mode's to decide.
entity:intkiller:intReturns:void
_door_changed
server.gdA door moved to a new state: api.DOOR_OPENING when it starts to open, api.DOOR_OPEN once it is open, api.DOOR_CLOSING and api.DOOR_CLOSED the same way back. Whoever moved it, a player walking up, its own wait running out, or this script, the hook is the same.
door:StringNamestate:intReturns:void
_logic_event
server.gdA logic entity the map places (a relay, timer, counter or button, by its name in the level editor) raised event: "OnTrigger", "OnTimer", "OutValue", "OnHitMin", "OnHitMax", "OnPressed" or "OnUseLocked". activator is the player who set it off, 0 for nobody. Its outputs fire whatever this does; this is where a mode reacts to a button press or a counter filling up.
entity:StringNameevent:StringNameactivator:intReturns:void
_tick
server.gdEvery server tick, after the zone and pickup hooks. delta is the seconds since the last tick. Timers and win checks go here. Stops once a winner is declared.
delta:floatReturns:void