starlit

game

A read-only copy of the match for this frame: all players, the local player, and the projection of a world point onto the screen.

game hands you a copy of public game state. We make the copy once for each frame, from the engine's own entity list. Every call builds fresh tables, so you can change what you got and nothing else will see the change.

Slots

A player is identified by a slot, a whole number from 1 to 64. The same number is used everywhere:

  • index in game.players()
  • the argument of entity.get(slot) and the result of ent:index()
  • the fields userid, attacker and assister of game events
  • the first argument of resolver.set_yaw(slot, degrees)

In an event, slot 0 means nobody, or the world.

Outside a match, game.in_game() is false, game.players() returns an empty table and game.local_player() returns nil.

Positions are in game units. The origin of a player is at the feet.

Functions

game.in_game

game.in_game() -> boolean

Returns true while the client has a local player in a match, false otherwise.

Errors none.

events.on_paint(function()
  if not game.in_game() then return end
  draw.text(20, 20, "in a match", 255, 255, 255)
end)

game.local_player

game.local_player() -> table or nil
game["local"]() -> table or nil

Returns a table with the fields below, or nil when you are not in a match or the local player has no body yet.

fieldtypemeaning
alivebooleantrue if the local player is alive
healthinteger0 to 100000
armorinteger0 to 100000
teamintegerthe team number the game uses; players with the same number are teammates
x, y, znumberposition of the origin
vx, vy, vznumbervelocity in units per second

Notes game["local"] is the same function. The word local is a Lua keyword, so game.local() is a syntax error and the bracket form is the way to write it. game.local_player is the name for plain dot syntax. This table has no index, name or angles. Use entity.local_player() when you need them.

events.on_paint(function()
  local me = game.local_player()
  if not me or not me.alive then return end
  draw.text(20, 300, string.format("health %d  armor %d", me.health, me.armor), 255, 255, 255)
end)

game.players

game.players() -> array of player tables

Returns an array with one table for every player the engine lists, at most 64, in order of slot. The local player is in the list. Dead players are in the list too.

fieldtypemeaning
indexintegerthe slot, 1 to 64
namestringat most 32 bytes. Control characters are removed and invalid UTF-8 bytes become ?.
teamintegerthe team number the game uses
aliveboolean
healthinteger0 to 100000
x, y, znumberposition of the origin, at the feet
yawnumberthe eye yaw the game sends to every client, in degrees, wrapped to -180 to 180
pitchnumberthe eye pitch in degrees, -180 to 180. Positive looks down.
vx, vy, vznumbervelocity in units per second, each limited to -32768 to 32768
on_groundbooleanthe on-ground flag of the player
duckingbooleanthe ducking flag of the player
sim_timenumberthe simulation time of the player in seconds. It is 0 when the engine gives no usable value.

Notes For a player that is not alive, the last eight fields (yaw to sim_time) are 0 or false. The position of a dead player has no meaning you should rely on. To find the local player in the list, compare index with entity.local_player():index().

Cost 100 instructions plus 180 for every player. Call it once for each frame and keep the result.

events.on_paint(function()
  local y = 320
  for _, p in ipairs(game.players()) do
    if p.alive then
      draw.text(20, y, string.format("%d  %s  %d", p.index, p.name, p.health), 220, 220, 220, 255, "small")
      y = y + 13
    end
  end
end)

game.to_screen

game.to_screen(x, y, z) -> sx, sy or nil
argumenttypemeaning
x, y, znumbera point in the world

Returns the pixel position of the point on the screen, in the same coordinates draw uses and screen.size() measures. The values are limited to -16384 to 16384. Returns a single nil when the point is behind the camera, when there is no camera, or when a coordinate is outside -1e6 to 1e6.

Errors a type error if an argument is not a number. NaN and infinity raise finite number expected.

Notes The result is for the current frame. A point that is on the screen can still be outside the visible area, so check it against screen.size() if you need to.

events.on_paint(function()
  for _, p in ipairs(game.players()) do
    if p.alive then
      local sx, sy = game.to_screen(p.x, p.y, p.z + 72)
      if sx then draw.circle_filled(sx, sy, 3, 255, 80, 80) end
    end
  end
end)

previous: What scripts can do · next: entity