Keys, the mouse and chat
What the players do is keyPressed, keyHeld, clicked, mouse and chatted. A
press, a click and a typed line are true on the one frame they arrive, so a program looks
for them in a loop that runs every frame, or listens with on.key and on.chat:
program(() => {
while (true) {
if (keyPressed(CurrentPlayer, "F8")) createUnit(CurrentPlayer, units.TerranMarine, 1, locations.Base);
if (clicked(CurrentPlayer, "right")) {
const at = mouse(CurrentPlayer); // map pixels, kept as they are now
centerLocation(locations.Cursor, at.x, at.y);
createUnit(CurrentPlayer, units.TerranMarine, 1, locations.Cursor);
}
const m = chatted(CurrentPlayer, "-spawn {n} {what:unit}");
if (m) createUnit(CurrentPlayer, m.what, m.n, locations.Base);
underMouse(CurrentPlayer, { owner: CurrentPlayer })?.heal(10);
sleep(frames(1));
}
}, { owner: AllPlayers });
The player is one of P1 … P8 or CurrentPlayer; in a per-player program, each
player's own keys, mouse and lines. All of it reaches every player's computer together, a
few frames after it happens. That is the trip between computers, and it is the same in a
game played alone.
Keys and buttons#
keyPressed(player, key)is true once per press, on the frame the press arrives, and not while the player is typing a message.keyHeld(player, key)is true on every frame the key is down.- Keys are the letters and digits,
"F1","F7"…"F12","Space","Enter","Escape","Tab","Shift","Ctrl","Alt", the arrows ("Left"…),"Backspace","Delete","Insert","Home","End","PageUp","PageDown"and"Numpad0"…"Numpad9". The game keeps F2 to F6 to itself and reports no press of them, so asking for one is an error. The game's own use of a key still happens. clicked(player, "left" | "right" | "middle")is the same askeyPressedfor a mouse button.on.key("F7", (p) => …)runs a function each time a player presses the key ({ from: P1 }for one player's).
The mouse and locations#
mouse(player)is where the player's cursor is on the map,xandyin pixels (32 to a tile).const at = mouse(p)keeps the place.centerLocation(location, x, y)moves a location there with its size kept, orcenterLocation(location, x, y, width, height), so thatcreateUnitand the other actions can happen under the cursor.bounds(location)is where a location is now:left,top,rightandbottomin pixels, read in the game, so a location that was moved is read where it went. It is written one edge at a time:const b = bounds(locations.Pen); b.left += 32; b.right += 32;slides it a tile to the right.underMouse(player, filter?)is the unit nearest the cursor and no farther thanwithinpixels from it (48 unless the filter says otherwise), ornull.
Chat#
chatted(player, pattern) is null, or what the pattern read out of the line the player
sent. on.chat("-give {n}", (p, { n }) => …) runs each time a player sends a line that
fits.
- The pattern's own words are matched exactly, and the whole line has to fit.
{n}reads a whole number, up to 1 048 575.{what:unit}reads a unit type by its name (Terran MarineorTerranMarine, or the map's custom name). It takes the rest of the line, so it comes last.{kind:ore|gas}reads one of the listed words, as its place in the list (0, 1, …).- Names and words match whatever their capitals, and a pattern reads up to three values.
- The values are typed from the pattern: after
m.the editor offersnandwhat, andm.whatis aUnitTypean action takes at once.
Start a pattern with a word of its own, such as -spawn, so ordinary talk is never taken
for it. A single-player game has no chat, so try typed lines in a multiplayer game;
hosting one alone is enough.
What input takes from the map#
Only a program that reads input takes anything for it, and nothing is a death counter, a
switch or a string: one unit-properties slot; one unit type the map does not use (the
Valkyrie, unless the map uses it); the location the build already keeps for orders; and
hidden units of Player 12 at the map's top-left corner, six for each human player and six
more when the mouse is read. Outside a program these functions are an error, where
if (keyPressed(…)) would otherwise quietly be true. Simulate presses no keys, so there
they read as nothing; a test can press them.
What only one computer knows#
local is what this computer alone knows: local.player (the player at this computer),
local.camera.x and .y (where its screen is on the map), local.mouse.x and .y (the
cursor on the screen), local.selected and local.selectionCount.
A local value may choose what is shown on this computer. It may not change the game, since
every computer would change it differently and the game would split, and the editor
refuses that. await sync(player, value) sends that player's value to every computer and
gives it back a few frames later, the same everywhere. select(P1, local.selected!) makes
this computer's selection the player's selection on every computer.
program(async () => {
let x = 0;
while (true) {
if (keyHeld(P1, "D")) x += 4;
if (local.player == P1) print(`screen at ${local.camera.x}`);
const cam = await sync(P1, local.camera.x);
if (cam > x) x = cam;
await nextFrame();
}
});