Recipes

Small, self-contained snippets that show how common game ideas look in Verge JavaScript. Server-side code owns the rules; client-side code draws the interface. Each recipe builds on the server, client, and player objects from the Scripting API, so you can drop one into a game and grow it from there.

Monster AI

Game logic runs on the tick. Here every monster looks for the closest player on its map and takes one step toward them when they come near.

// Monsters chase the nearest player on their own map.
server.onTick(function () {
  server.forEachMonster(function (mob) {
    const m = server.getEntity(mob);
    let target = null, best = 6;              // only chase players closer than 6 tiles
    server.forEachPlayer(function (p) {
      const e = server.getEntity(p);
      if (e.map !== m.map) return;
      const d = Math.abs(e.x - m.x) + Math.abs(e.y - m.y);
      if (d < best) { best = d; target = e; }
    });
    if (target) {
      const nx = m.x + Math.sign(target.x - m.x);
      const ny = m.y + Math.sign(target.y - m.y);
      server.warpEntity(mob, nx, ny);            // step one tile closer
    }
  });
});

forEachMonster and forEachPlayer walk the entities, getEntity reads a position, and warpEntity moves the monster one tile within its map. Change the distance check or the step rule to make it patrol, flee, or leash back to a spawn point.

A shop

Anything you want to remember about a player is a saved attribute. This shop reads the player's gold, checks the price, updates their gold and inventory, and saves.

// A simple shop: "/buy potion" spends gold from the player's account.
const PRICES = { potion: 25, ether: 40 };

server.onChatCommand(function (idx, text) {
  const [cmd, item] = text.split(" ");
  if (cmd !== "/buy") return;

  const price = PRICES[item];
  const player = server.getPlayer(idx);
  const gold = player.getAttribute("gold") || 0;

  if (!price)        return server.callClientFunc(idx, "shopUnknownItem");
  if (gold < price)  return server.callClientFunc(idx, "shopTooPoor");

  player.setAttribute("gold", gold - price);
  const owned = player.getAttribute(item) || 0;
  player.setAttribute(item, owned + 1);
  player.save();
});

Attributes persist with the player, so their gold and items are still there next login. callClientFunc triggers a message on the buyer's own screen when something is wrong.

A spell

A spell is a rule that spends one resource to change another. Because it runs on the server, players cannot fake their own mana.

// "/heal" spends 20 mana to restore health, then plays a client effect.
server.onChatCommand(function (idx, text) {
  if (text !== "/heal") return;

  const player = server.getPlayer(idx);
  const mana = player.getAttribute("mana") || 0;
  if (mana < 20) return server.callClientFunc(idx, "spellNoMana");

  const hp = player.getAttribute("hp") || 0;
  player.setAttribute("mana", mana - 20);
  player.setAttribute("hp", Math.min(hp + 50, 100));
  player.save();

  server.callClientFunc(idx, "castHealEffect");     // sparkle on the client
});

The same shape covers most abilities: check a cost, apply an effect, save, and ask the client to show it. Damage spells read a target instead of the caster; buffs write a timed attribute the tick handler counts down.

A HUD

Client scripts draw the interface each player sees. They are presentation only: they read the live game state and send requests back to the server.

// A tiny HUD: who you are, where you are, and a quick action.
const panel = client.createPanel(8, 8, 220, 56, {});
const line = panel.addLabel("");

panel.addButton("Recall to town", function () {
  player.setAttribute("wantRecall", true);       // ask the server to warp you
});

client.onDraw(function () {
  line.setText(player.name + "  @  " + player.map);
});

createPanel builds a retained panel you add labels, buttons, and progress bars to. onDraw refreshes it every frame from the live player global. The button's click runs on the client, and setAttribute sends a request back to the server, which decides whether to honor it.

Day & night

The server keeps a game clock you can read at any time. This watches for the moment day turns to night and tells every client to change its lighting, but only when it actually flips.

// Flip the whole world between day and night as the clock turns.
let wasNight = false;

server.onTick(function () {
  const t = server.gameTime();            // { day, hour, minute }
  const night = t.hour < 6 || t.hour >= 20;
  if (night === wasNight) return;        // only act when it flips
  wasNight = night;

  server.forEachPlayer(function (idx) {
    server.callClientFunc(idx, night ? "nightfall" : "daybreak");
  });
});

Guarding on the flip keeps you from sending an update every tick. The same pattern drives spawns by time of day, shop hours, or a boss that only appears at midnight.

Note These recipes build on the hooks and objects documented in the Scripting API and Creating games. They are starting points, not the whole toolbox: combine the same hooks, entities, attributes, and client panels to build quests, parties, crafting, and more.