Skip to content

Shops and money

A shop zone that opens the shop page when a player walks in, purchases checked and charged by the server, and a working Pay 'n' Spray.

shops.ts
import { Server, Weapon, GarageType, type Player } from "@sagl/server";

const items: Record<string, { name: string; price: number; give: (p: Player) => void }> = {
  pistol:  { name: "Pistol",       price: 200,  give: (p) => p.giveWeapon(Weapon.Pistol, 60) },
  shotgun: { name: "Shotgun",      price: 600,  give: (p) => p.giveWeapon(Weapon.Shotgun, 30) },
  armour:  { name: "Body armour",  price: 100,  give: (p) => (p.armour = 100) },
};

export function shops(server: Server) {
  // Inside Ammu-Nation: the game's door marker (downtown, 1368 -1279) takes
  // players in, and they arrive here.
  const ammu = server.createZone({ center: { x: 286, y: -40, z: 1001.5 }, radius: 5 });
  ammu.data.shop = "ammu";
  server.map.setMarker("ammu", { x: 1368, y: -1279, icon: 6, label: "Ammu-Nation" });

  const shop = server.channel("shop");

  server.on("zoneEnter", (player, zone) => {
    if (zone.data.shop) {
      shop.send(player, {
        open: true,
        items: Object.entries(items).map(([id, i]) => ({ id, name: i.name, price: i.price })),
      });
    }
  });
  server.on("zoneLeave", (player, zone) => {
    if (zone.data.shop) shop.send(player, { open: false });
  });

  // The client asks; the server decides.
  shop.on((player, data) => {
    const item = items[(data as { buy?: string }).buy ?? ""];
    if (!item) return;
    if (player.money < item.price) {
      shop.send(player, { status: "You can't afford that." });
      return;
    }
    player.giveMoney(-item.price);
    item.give(player);
    shop.send(player, { status: `Bought: ${item.name}` });
  });

  // Pay 'n' Spray: $100 for a repair and a new colour, and two stars off.
  for (const garage of server.garages.filter((g) => g.type === GarageType.PayNSpray)) {
    garage.open();
    server.on("zoneEnter", (player, zone) => {
      const car = player.vehicle;
      if (zone !== garage.zone || !car || player.seat !== 0) return;
      if (player.money < 100) return player.send("You need $100.");
      player.giveMoney(-100);
      car.repair();
      car.colors = [Math.floor(Math.random() * 127), Math.floor(Math.random() * 127)];
      player.wantedLevel = Math.max(0, player.wantedLevel - 2);
    });
  }
}