Variables and numbers
Variables and records#
Variables hold numbers, booleans, texts, units and players.
let p = { lives: 3, gold: 0, alive: true } is a record: a variable per field
(p.lives -= 1, if (p.alive)), nested records included. A declared type
(let p: { n: u8 } = { n: 0 }, an interface, a type) is honoured. A record handed to
a function reaches it by reference, and p = { lives: 3, gold: 0, alive: true } sets
every field at once. Variables live in the game's memory while the map is played. They
take nothing from the map: no death counters, no switches, no triggers in the list.
A number or a boolean may be undefined where TypeScript says so: what find gives when
nothing fits, an optional parameter left out, let n: number | undefined. ??,
!== undefined and ! read it. A player in a variable can be changed and compared, but
the player of an action is still one the script knows.
program(() => {
const hp = [30, 80, 55];
const strong = hp.find((h) => h > 50); // a number, or undefined
if (strong !== undefined) print(`${strong}`); // 80
let leader: Player = P1;
if (hp[0] < 50) leader = P2;
if (leader == P2) print("Player 2 leads"); // Player 2 leads
});
Whole numbers#
A number is whole unless a fraction is stored into it. A whole number is TypeScript's
as far as 32 bits go: signed, from −2 147 483 648 to 2 147 483 647. a - b is below zero
when b is larger, Math.abs, Math.min, Math.max and clamp(x, lo, hi) mean what
they say, and a number below zero is printed with its minus sign. The one difference is at
the ends: a number wraps there, as x | 0 does, where TypeScript's would go on.
Three more types hold a number that is never below zero:
| Type | Holds | At its ends |
|---|---|---|
number |
−2 147 483 648 … 2 147 483 647 | wraps, as x | 0 |
u32 |
0 … 4 294 967 295 | wraps, as x >>> 0 |
u16 |
0 … 65 535 | stops: below zero is 0, above is 65 535 |
u8 |
0 … 255 | stops: below zero is 0, above is 255 |
let lives: u8 = 3 stops at its ends after the whole sum, never between its parts, which
is what lives and cooldowns want. A u32 is for bit masks, hashes and counts past two
thousand million. Everything the game is asked (minerals(), deaths(), u.hp) is a
number. A constant its variable cannot hold is an error: let mask = 0xffffffff wants
let mask: u32.
A number and a u32 do not mix in arithmetic without saying which is meant. h + n
is an error that names the two ways out, u32(n) and i32(h), which read the same 32
bits the other way and cost nothing. A constant that fits is either, so h * 31 + 7 needs
nothing. A comparison between the two is exact.
Where the game takes nothing below zero (a u8 or u16, a unit's hit points, an
action's amount or count, random(n)'s bound, a place on the map), a number below zero
goes in as 0. u.hp -= 1000 kills, and createUnit(p, unit, n, at) with n at −3 makes
none.
Arithmetic. + − * / % between variables and constants, the compound assignments,
++ and --, and the bitwise & | ^ ~ << >> >>> over the 32 bits. >> keeps the sign
of a number and >>> never does, as in JavaScript. / of two whole numbers rounds
towards zero (-7 / 2 is −3), and % takes the sign of what is divided (-7 % 2 is −1).
Math.floor and the other rounding functions around a whole division change nothing.
Dividing by a variable that is 0 in the game gives 0; dividing by a constant 0 is an
error. a ** 2 and Math.pow(a, 3) take a power known when the script is built, and
Math.sign(n) and Math.log2(n) (rounded down) work on whole numbers.
Numbers with a fraction#
A number holds a fraction once one is stored into it: let speed = 1.5, x += 0.25,
const d = Math.cos(a). It is then a fixed number, with about four decimal places, from
about −32 768 to 32 767. fixed(n) makes a whole number one, and a parameter or variable
typed fixed is one from the start. u8, u16 and u32 stay whole, and a fraction
stored into one is an error.
- Whole numbers still divide as whole numbers:
7 / 2is 3, and7 / fixed(2)is 3.5. - Where only a whole number goes (an index, a count, a place, a unit's field), a fixed
number is an error that names
Math.floor,Math.roundandMath.trunc.x | 0isMath.trunc(x). Math.sqrt,Math.hypot,Math.sin,Math.cos,Math.tan,Math.atanandMath.atan2give fixed numbers. Angles are radians, as in JavaScript. The build adds the tablessin,cosandatan2read to the map.- A fixed number in a text is printed as a decimal of up to four places.
program(() => {
let speed = 1.5; // a fraction stored into it: a fixed number
speed += 0.25;
const across = Math.hypot(30, 40);
const half = 7 / fixed(2); // 7 / 2 alone is 3, as whole numbers divide
print(`${speed} ${across} ${half} ${Math.floor(speed * 10)}`); // 1.75 50 3.5 17
});
trigscript/math adds lerp, easing curves, distance, angleTo and Vec, a point of
two fixed numbers (Math).