Waiting and tasks
sleep#
A program runs every frame, from where it left off. Its body runs until it reaches a
sleep(), an await or its end, all within one frame, and carries on from there later.
sleep(seconds(15)) gives the frame back and resumes that much later, while other
programs and the map's triggers go on. frames(n) is the game's own clock, seconds(n)
is twenty-four frames (one second at Fastest), and minutes(n) sixty of those.
wait() inside a program is allowed, but it is the game's own Wait: it holds the rest of
its trigger, and it takes the player's one wait slot, so the player's other Waits stop
until it is free (Waits). Use it for a short pause, such as a text
and then a sound, and use sleep to pass time.
async and await#
In a program written program(async () => …), await sleep(…) is the same pause, and
await nextFrame() waits one frame. An async function may wait anywhere in its body,
and await f() goes on when it returns, with its result. await until(() => n >= 3)
checks at once, then once a frame, and goes on in the frame the answer is true;
until(bring(…)) takes a condition of the game as it is.
Tasks#
A task runs beside the program. start(f()) starts an async call and goes on at once.
The program can await the task later, ask t.running, or stop it with t.cancel(). A
task may outlive the program that started it and may start tasks of its own.
start(wave(n), { max: 4 }) lets at most four of that start's tasks run at once.
Promise.all([…]) waits for every branch, Promise.race([…]) for the first, and
Promise.any is a race. A race's losers stop where they are, where JavaScript lets
them run on. .then((v) => …) passes on what a promise gives, so
sleep(frames(3)).then(() => 0) in a race is a time limit with a value.
async function wave(n: number) {
createUnit(P2, units.ZergZergling, n * 4, locations.Spawn);
await sleep(frames(n * 5));
return n;
}
program(async () => {
let ticks = 0;
const clock = start(async () => {
while (true) { await sleep(frames(1)); ticks += 1; }
});
const first = await Promise.race([wave(1), wave(3)]);
print(`wave ${first} ended first`); // wave 1 ended first
await until(() => ticks >= 10);
clock.cancel();
print(`${ticks} ticks, running: ${clock.running}`); // 10 ticks, running: false
});
A task that ends on an error throws it where it is awaited. One that fails while nothing
awaits it is shown in red, and the program goes on. Something that keeps its own time is a
task, or another program. A sleep or an await cannot stand inside a loop over units, a
for…of over a text, or a function that calls itself.
Generators#
A function* walked by for…of puts the loop's body where each yield is, yield*
hands on another generator, and break leaves both. A class can be walked with
*[Symbol.iterator](). An async function* is walked by for await and may wait between
its values.
function* lanes(n: number) {
let i = 0;
while (i < n) { yield i * 32; i += 1; }
}
program(() => {
let total = 0;
for (const x of lanes(4)) total += x;
print(`${total}`); // 192
});
Edges#
if (rose(bring(P1, units.AnyUnit, locations.Beacon, ">=", 1))) is true on the frame the
condition becomes true, and not again until it has been false in between. once(…) is
true the first time only.