scmJS docs

Functions

Arguments pass by value, as in TypeScript. A function may return a number, a boolean, a text, a unit, a record, a tuple or an array, and an instance under the rule in Classes. Parameters take defaults (step = 1) and may be optional (extra?: number). Local variables start afresh at every call, and a function declared inside another sees the outer one's parameters and locals.

function split(n: number) {
  return { big: n > 4, half: n >> 1 };
}
function around(n: number) {
  return [n - 1, n + 1] as const;
}
function advance(n: number, extra?: number) {
  return extra !== undefined ? n + extra : n + 1;
}

program(() => {
  let n = 7;
  const { big, half } = split(n);
  const [lo, hi] = around(n);
  print(`${big} ${half} ${lo}-${hi} ${advance(n)} ${advance(n, 10)}`);   // true 3 6-8 8 17
});

Written out or called#

A function used once is written out where the call stands. A function used more than once is called when it can be: one copy of its body in the map, which keeps the map smaller. The meaning is the same either way, and the hint at the end of the function's line says which it got: called ×3, or inlined ×3 with the reason when you hover it. Three things keep a function written out:

An array reaches a function as itself, and which array is settled when the script is built. So a function that takes an array is one copy for each array it is passed: total(hp) and total(shields) are two copies. The hint counts them: called ×5, 2 copies.

A function that calls itself#

A function may call itself, directly or through another: fib(n - 1) + fib(n - 2), a flood fill over a grid, two functions that call each other. Each run has its own parameters and locals, as in TypeScript. Three things are different from a JavaScript engine:

program(() => {
  const grid = [
    [0, 0, 1, 0],
    [0, 1, 1, 0],
    [0, 0, 0, 0],
  ];
  function fill(x: number, y: number): number {
    if (x < 0 || y < 0 || y >= grid.length || x >= grid[0].length) return 0;
    if (grid[y][x] != 0) return 0;
    grid[y][x] = 2;
    return 1 + fill(x + 1, y) + fill(x - 1, y) + fill(x, y + 1) + fill(x, y - 1);
  }
  let x = 0;
  print(`${fill(x, 0)} cells filled`);      // 9 cells filled
});

A loop over units cannot hold such a call. Collect what it finds into an array, and call the function from a loop over that.

Functions in other files#

A function declared at the top of any of the script's files runs in the game when a program calls it with values of the program. game() marks one that only the game runs:

// shop.ts
export const award = game((p: Player, n: number) => { setResources(p, "add", n, "ore"); });
export const canAfford = game((have: number, price: number) => have >= price);

// main.ts
import { award, canAfford } from "./shop";
program(() => {
  let gold: u8 = 10;
  if (canAfford(gold, 5)) { gold -= 5; award(P2, 3); }
});

A game() function follows a program's rules, and what it does is shown at its own file and line. It sees its parameters and what any file sees, not the calling program's variables. Calling one outside a program is an error.

Functions as values#

A function can be kept in a variable, an array, a field or a Map, and returned by another function. A call through what holds it calls whichever function is there when the line runs. A closure keeps what it captured, as in JavaScript: counter() below gives a function with a count of its own.

function heal(hp: number) { return hp + 10; }
function hurt(hp: number) { return hp - 10; }
function counter() {
  let n = 0;
  return () => { n += 1; return n; };
}

program(() => {
  const effects = [heal, hurt, (hp: number) => hp * 2];
  const next = counter();
  let hp = 40;
  let i = 0;
  while (i < effects.length) { hp = effects[i](hp); i = next(); }
  print(`${hp}`);                               // 80
});

A function handed to a method or a parameter costs nothing extra: it is copied in where it is called. A kept one is a number in the map, and a call through it picks among the functions that could be there, one test each. An async function or a generator is not kept as a value: call it where it is written, or start() it.

scmJS 0.8.5 · Generated from the repository. The source is under the MIT license, which does not cover what ATTRIBUTION.md lists. StarCraft and Brood War are trademarks of Blizzard Entertainment; this project ships none of their data.