Skip to content

The stock mod

The stock mod is the game’s own: its weapons, its HUD and its game modes. Every mod sits on top of it, so a mod can use any of its modules, replace one file of them, or leave them be.

main.server.luau gives every player the AK-47, the USP, a frag and a smoke grenade. The AWP and the axe in weapons/ are there for a game mode to give.

Module What it does
teams puts players on teams, tints them and gives them the team chat channel; teammates never hurt each other
spawns picks the markers players come back at
score each player’s kills, deaths and points, the teams’ scores and the clock
damage turns the engine’s hits and falls into one damage event, which a game mode may change or stop
screen the HUD: the team scores, the player’s kills and points, the clock, and the scoreboard while Tab is held, or toggled on
killfeed the last kills at the top right, while match.killfeed is true
use_hint Press [F] <hint> under the crosshair in a use trigger with a hint, and a bar while the key is held
pm /pm <player> <text>, and the reply channel
admins /mute and /unmute; tells everyone who was kicked
names a player’s name, or #<id> for none
roster the players and NPCs, by id, for a loop over a horde

A module’s <name>_lib.server.luau holds helpers the others require. They keep no state of their own: state and events are how modules talk.

Helper Gives
teams_lib set(p, n), members(n), balance(p), the smallest team, and same(a, b)
spawns_lib cycle(prefix), random(prefix) and near_team(prefix, p), each a marker whose name starts so, or nil; and respawn(p, marker)
score_lib player(field, p, amount) and team(n, amount), which emit scored; reset(field), clock(name, seconds) and left(name)
damage_lib deal(data), a game mode’s own damage, and from(hit, source, at), which fills in where it landed
names_lib of(p)
admins_lib ids(but) and shadow(from, text)
roster_lib playing(), the people and bots by id, and split(), which also gives the NPCs

Read a score as state: p.kills, match.team_scores[n].

To write one, copy gametypes/tdm/. A game mode:

  • declares its bumps;
  • sets match.team_count and match.killfeed as it starts;
  • puts a player who joins on a team;
  • preloads the files it uses at its top;
  • ends its match and calls start_match() a few seconds later, which plays the rotation’s next.

Its handlers run before the modules’, whose own take { after = true }, so a game mode may change an event or stop it.

A player who joins in the middle of a round may have to wait for the next, as in search and destroy:

local waiting = {}
on("joined", function(e)
waiting[e.player] = true
e.player:hurt(1000)
end)
on("killed", function(e)
if waiting[e.victim] then
waiting[e.victim] = nil
return false -- not counted as a death
end
end)