Skip to content

Teams and scores

Two teams with their own skins and spawns, no friendly fire, and a kill score every player's HUD shows (see the score HUD).

index.ts
import { Server, Player, Color, Weapon, BodyPart } from "@sagl/server";

const server = new Server({ name: "Team Deathmatch", clientFiles: "./client" });
server.clientScripts.useClientFile("scripts/hud.js");

type Team = "grove" | "ballas";
const teams: Record<Team, { skin: number; spawn: [number, number, number]; color: number }> = {
  grove:  { skin: 105, spawn: [2495, -1687, 13.5], color: 0x40c040 },
  ballas: { skin: 102, spawn: [2181, -1494, 23.9], color: 0xa040c0 },
};
const score: Record<Team, number> = { grove: 0, ballas: 0 };
const score$ = server.channel("score");

const teamOf = (p: Player) => p.data.team as Team;

server.on("playerJoin", (player) => {
  // Put them on the smaller team.
  const count = (t: Team) => server.players.filter((p) => teamOf(p) === t).length;
  player.data.team = count("grove") <= count("ballas") ? "grove" : "ballas";
  player.send(`You're with ${player.data.team}.`, teams[teamOf(player)].color);
  score$.send(player, score);
});

server.on("playerSpawn", (player) => {
  const team = teams[teamOf(player)];
  const [x, y, z] = team.spawn;
  player.skin = team.skin;
  player.setPosition({ x, y, z });
  player.giveWeapon(Weapon.AK47, 300);
});

server.on("playerDamage", (victim, attacker, hit) => {
  if (attacker instanceof Player && teamOf(attacker) === teamOf(victim)) return false;
  if (hit.bodyPart === BodyPart.Head) return hit.damage * 1.5;
});

server.on("playerDeath", (player, killer) => {
  if (!(killer instanceof Player) || teamOf(killer) === teamOf(player)) return;
  score[teamOf(killer)] += 1;
  score$.broadcast(score);
  if (score[teamOf(killer)] >= 25) {
    server.broadcast(`${teamOf(killer)} win!`, teams[teamOf(killer)].color);
    score.grove = score.ballas = 0;
    score$.broadcast(score);
  }
});

server.listen();