New in the script engine: maths and lists
The last update gave the language a proper maths library and real list handling — building lists from scratch, searching them, and folding them down to a number. Everything is additive: your existing scripts are untouched, and nothing under the hood changed.
A few ground rules first, because they shape everything below:
- Numbers are whole numbers. There are no decimals — one 64-bit integer type, on purpose. Where you'd reach for a fraction, work in percentages or scale explicitly (more on scale below).
- Overflow stops the script rather than silently wrapping to a wrong number. A bot that quietly computed nonsense is worse than one that stopped and told you.
- A list is a value, not a box. Nothing mutates it. append hands you back a new list, so the pattern is [icode]xs = append(xs, v)[/icode].
Maths
abs(n) min(a, b) max(a, b) clamp(value, low, high) sign(n) gcd(a, b) floorDiv(a, b) floorMod(a, b) pow(base, exponent) sqrt(n) scale(value, num, den) percentOf(part, whole) parseInt(text) numberIn(text) commas(n) padded(n, width)
A percentage without a fraction in sight:
let used = percentOf(30 - invFree(), 30) uiProgress("bag", clamp(used, 0, 100), 100)
floorMod, not % — this is the one you want to cycle an index. Plain [icode]%[/icode] takes the sign of the left side, so a negative counter would run backwards off the front of your rotation. [icode]floorMod(-1, 4)[/icode] is 3.
let corner = floorMod(trips, 4)
Need "half again as long"? scale is the fixed-point workhorse — it does [icode]value * num / den[/icode] with room to spare so the middle step can't overflow:
return scale(600, 3, 2) # 900ms
And pulling a number out of a chat line (commas ignored):
on message(line, from) { let coins = numberIn(line) if coins == none { return } if coins > 1000 { print("nice:", commas(coins)) } }
Note parseInt and numberIn answer none when there's no number, the same way nearestNpc does when it finds nothing — so the checker makes you handle the miss.
Lists
Build one — the answer to "there's no list literal":
for i in range(0, 5) { # 0 1 2 3 4 print("tick", i) } # also: rangeStep(0, 100, 10) repeated(0, 5) range(0, 0) is empty
Search (numbers and text — those compare by value):
let opts = menuOptions() if contains(opts, "Attack") { print("attack sits at", indexOf(opts, "Attack")) # -1 if absent }
Reshape — first, last, append, concat, reversed (each answers a new list; first/last answer none on an empty list).
Fold to a number — sum, minOf, maxOf, mean, sorted, join:
on message(line, from) { let nums = numbersIn(line) if isEmpty(nums) { return } let avg = mean(nums) if avg == none { return } print("biggest", maxOf(nums), "- average", avg) }
What still works exactly as before
Indexing ([icode]xs[0][/icode], which answers none when out of range), [icode]for x in list[/icode], and [icode]list<T>[/icode] as a [icode]fun[/icode] parameter or return type were already in the language — the new commands just give you lists worth doing that to. Lists are capped at 4096 items so a runaway builder can't eat the client's memory.
Full command reference is in the docs. Post your favourite one-liners below.