Skip to content

Personal vehicles

Players spawn cars by model id from the chat (/car 411), own them, can lock them, and lose them when they leave.

vehicles.ts
import { Server, Color, type Player, type Vehicle } from "@sagl/server";

export function personalVehicles(server: Server) {
  const carsOf = (p: Player) => ((p.data.cars ??= []) as Vehicle[]);

  function spawnCar(player: Player, model: number) {
    if (model < 400 || model > 611) return player.send("Models are 400-611.", Color.Red);
    const cars = carsOf(player);
    if (cars.length >= 2) cars.shift()!.destroy();          // two at most
    const { x, y, z } = player.position;
    const rad = (player.heading * Math.PI) / 180;
    const car = server.createVehicle(model, { x: x - 4 * Math.sin(rad), y: y + 4 * Math.cos(rad), z }, player.heading, {
      plate: player.name.slice(0, 8).toUpperCase(),
    });
    car.data.owner = player.name;
    cars.push(car);
  }

  // Others get thrown out of a locked car's driver's seat.
  server.on("playerEnterVehicle", (player, vehicle) => {
    if (vehicle.data.locked && vehicle.data.owner !== player.name && player.seat === 0) {
      player.removeFromVehicle();
      player.send("It's locked.", Color.Red);
    }
  });

  server.on("playerQuit", (player) => carsOf(player).forEach((c) => c.destroy()));

  return {
    spawnCar,
    toggleLock(player: Player) {
      const car = player.vehicle ?? player.lastVehicle;
      if (!car || car.data.owner !== player.name) return player.send("That's not your car.");
      car.data.locked = !car.data.locked;
      player.send(car.data.locked ? "Locked." : "Unlocked.");
    },
  };
}

Wired to chat commands:

index.ts
const cars = personalVehicles(server);
commands.set("car", (player, [model]) => cars.spawnCar(player, Number(model)));
commands.set("lock", (player) => cars.toggleLock(player));