gamesteel 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/THIRD-PARTY-NOTICES.txt +0 -24
- package/dist/gamesteel.js +9787 -9574
- package/dist/pkgs/audio/dist/worker.js +299 -137
- package/dist/pkgs/model/dist/worker.js +299 -137
- package/dist/pkgs/paint/dist/worker.js +299 -137
- package/dist/pkgs/studio/dist/exported-player-25d.js +14738 -14572
- package/dist/pkgs/studio/dist/exported-player-3d.js +18160 -17957
- package/dist/pkgs/studio/dist/exported-player.js +11501 -11335
- package/dist/pkgs/studio/dist/program-look-page.js +1 -1
- package/dist/pkgs/studio/dist/server/playtest-worker.js +10491 -10306
- package/package.json +9 -9
|
@@ -26221,7 +26221,7 @@ function shouldInterruptAfterDeadline(deadline) {
|
|
|
26221
26221
|
var import_sucrase2 = __toESM(require_dist2(), 1);
|
|
26222
26222
|
|
|
26223
26223
|
// ../core/dist/version.js
|
|
26224
|
-
var ENGINE_VERSION = "0.10.
|
|
26224
|
+
var ENGINE_VERSION = "0.10.1";
|
|
26225
26225
|
|
|
26226
26226
|
// ../core/dist/sim/trig-table.js
|
|
26227
26227
|
var QUARTER_WAVE = [
|
|
@@ -27486,6 +27486,10 @@ function ticksOf(d, line = 1, column = 1) {
|
|
|
27486
27486
|
return ticks;
|
|
27487
27487
|
}
|
|
27488
27488
|
|
|
27489
|
+
// ../core/dist/script/scan.js
|
|
27490
|
+
var import_parser = __toESM(require_parser(), 1);
|
|
27491
|
+
var import_types = __toESM(require_types(), 1);
|
|
27492
|
+
|
|
27489
27493
|
// ../core/dist/home.js
|
|
27490
27494
|
import { existsSync, renameSync, symlinkSync } from "node:fs";
|
|
27491
27495
|
import { homedir } from "node:os";
|
|
@@ -29351,7 +29355,7 @@ var Parser = class {
|
|
|
29351
29355
|
return clauses;
|
|
29352
29356
|
}
|
|
29353
29357
|
};
|
|
29354
|
-
function
|
|
29358
|
+
function parse2(source2) {
|
|
29355
29359
|
return new Parser(tokenize(source2)).parse();
|
|
29356
29360
|
}
|
|
29357
29361
|
|
|
@@ -30657,7 +30661,7 @@ function checkStrings(ast, out) {
|
|
|
30657
30661
|
function checkControls(ast, out) {
|
|
30658
30662
|
const lines = ast.controls?.bindings ?? [];
|
|
30659
30663
|
const players = playerButtonsOf(ast);
|
|
30660
|
-
const mouse = ["click", "right_click", "middle_click"];
|
|
30664
|
+
const mouse = ["click", "right_click", "middle_click", "menu"];
|
|
30661
30665
|
const builtIn = /* @__PURE__ */ new Set([...BUTTONS, ...mouse, ...players]);
|
|
30662
30666
|
const buttons = [...BUTTONS, ...mouse, ...players, ...lines.map((l) => l.button).filter((b) => !builtIn.has(b))];
|
|
30663
30667
|
const own2 = lines.filter((l) => !builtIn.has(l.button));
|
|
@@ -30918,6 +30922,27 @@ function numericProps(props) {
|
|
|
30918
30922
|
return out;
|
|
30919
30923
|
}
|
|
30920
30924
|
|
|
30925
|
+
// ../core/dist/script/prefs.js
|
|
30926
|
+
var NO_PREFS_YET = { sound: true, music: true, fullscreen: false, canFullscreen: false, touch: false };
|
|
30927
|
+
var usesPrefs = (sources) => sources.some((source2) => /\.\s*prefs\b/.test(source2));
|
|
30928
|
+
var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30929
|
+
function isPrefs(value) {
|
|
30930
|
+
return isObject(value) && Object.keys(value).length === 5 && typeof value["sound"] === "boolean" && typeof value["music"] === "boolean" && typeof value["fullscreen"] === "boolean" && typeof value["canFullscreen"] === "boolean" && typeof value["touch"] === "boolean";
|
|
30931
|
+
}
|
|
30932
|
+
var CHANGEABLE = ["sound", "music", "fullscreen"];
|
|
30933
|
+
function prefsChangeOf(raw) {
|
|
30934
|
+
const said2 = "prefs.set takes sound, music and fullscreen, each true or false, like prefs.set({ music: false })";
|
|
30935
|
+
if (!isObject(raw))
|
|
30936
|
+
throw new Error(said2);
|
|
30937
|
+
const out = {};
|
|
30938
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
30939
|
+
if (!CHANGEABLE.includes(key) || typeof value !== "boolean")
|
|
30940
|
+
throw new Error(`${said2}, not ${JSON.stringify({ [key]: value })}`);
|
|
30941
|
+
out[key] = value;
|
|
30942
|
+
}
|
|
30943
|
+
return out;
|
|
30944
|
+
}
|
|
30945
|
+
|
|
30921
30946
|
// ../core/dist/script/ads.js
|
|
30922
30947
|
var AD_KINDS = ["break", "reward"];
|
|
30923
30948
|
var NO_ADS_YET = { pending: null, lastBreak: null, lastPress: null, lastPlay: null, played: false, scene: null, ready: AD_KINDS, banner: null };
|
|
@@ -30974,7 +30999,7 @@ var ONLINE_LIMITS = {
|
|
|
30974
30999
|
downloadBytes: 1e6
|
|
30975
31000
|
};
|
|
30976
31001
|
var TOO_MANY_ASKS = `a tick asks the game's server at most ${String(ONLINE_LIMITS.asksPerTick)} times: spread the calls over ticks`;
|
|
30977
|
-
var
|
|
31002
|
+
var isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30978
31003
|
var jsonBytes = (data) => {
|
|
30979
31004
|
try {
|
|
30980
31005
|
const text3 = JSON.stringify(data);
|
|
@@ -31003,7 +31028,7 @@ var uploadProblem = (ask) => {
|
|
|
31003
31028
|
};
|
|
31004
31029
|
function askProblem(ask) {
|
|
31005
31030
|
const kinds = "an online ask is a call, join, leave, send, upload, download or askPush";
|
|
31006
|
-
if (!
|
|
31031
|
+
if (!isObject2(ask))
|
|
31007
31032
|
return kinds;
|
|
31008
31033
|
switch (ask["kind"]) {
|
|
31009
31034
|
case "call":
|
|
@@ -31027,7 +31052,7 @@ function askProblem(ask) {
|
|
|
31027
31052
|
}
|
|
31028
31053
|
var usesOnline = (sources) => sources.some((source2) => /\bonline\s*\.\s*(call|join|leave|send|state|upload|uploadScreen|download|askPush)\b/.test(source2));
|
|
31029
31054
|
function isOnlineHeard(value) {
|
|
31030
|
-
if (!
|
|
31055
|
+
if (!isObject2(value))
|
|
31031
31056
|
return false;
|
|
31032
31057
|
switch (value["kind"]) {
|
|
31033
31058
|
case "answer":
|
|
@@ -31054,9 +31079,9 @@ function isOnlineHeard(value) {
|
|
|
31054
31079
|
// ../core/dist/script/purchases.js
|
|
31055
31080
|
var PURCHASE_RESULTS = ["granted", "pending", "cancelled", "unavailable", "refused"];
|
|
31056
31081
|
var PRODUCT_ID = /^[a-z0-9][a-z0-9_.]{0,39}$/;
|
|
31057
|
-
var
|
|
31082
|
+
var isObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31058
31083
|
function purchaseAskProblem(ask) {
|
|
31059
|
-
if (!
|
|
31084
|
+
if (!isObject3(ask))
|
|
31060
31085
|
return "a purchase ask is a buy of a product or a restore";
|
|
31061
31086
|
if (ask["kind"] === "restore")
|
|
31062
31087
|
return null;
|
|
@@ -31065,9 +31090,9 @@ function purchaseAskProblem(ask) {
|
|
|
31065
31090
|
const id = ask["id"];
|
|
31066
31091
|
return typeof id === "string" && PRODUCT_ID.test(id) ? null : `a product id is 1 to 40 lowercase letters, digits, _ and ., starting with a letter or digit, like coins_100, not ${JSON.stringify(id) ?? String(id)}`;
|
|
31067
31092
|
}
|
|
31068
|
-
var isProduct = (value) =>
|
|
31093
|
+
var isProduct = (value) => isObject3(value) && typeof value["id"] === "string" && typeof value["price"] === "string" && typeof value["name"] === "string";
|
|
31069
31094
|
function isPurchaseHeard(value) {
|
|
31070
|
-
if (!
|
|
31095
|
+
if (!isObject3(value))
|
|
31071
31096
|
return false;
|
|
31072
31097
|
switch (value["kind"]) {
|
|
31073
31098
|
case "products":
|
|
@@ -32104,6 +32129,16 @@ const __online = Object.freeze({
|
|
|
32104
32129
|
askPush() { __call('onlineAskPush', {}) },
|
|
32105
32130
|
get state() { return __call('onlineState', {}) },
|
|
32106
32131
|
})
|
|
32132
|
+
/** The player's settings (a game's own pause menu): read as the page last said them; a change asked of the page, which
|
|
32133
|
+
* makes it after the tick and says it on a later one. */
|
|
32134
|
+
const __prefs = Object.freeze({
|
|
32135
|
+
get sound() { return __call('prefs', {}).sound === true },
|
|
32136
|
+
get music() { return __call('prefs', {}).music === true },
|
|
32137
|
+
get fullscreen() { return __call('prefs', {}).fullscreen === true },
|
|
32138
|
+
get canFullscreen() { return __call('prefs', {}).canFullscreen === true },
|
|
32139
|
+
get touch() { return __call('prefs', {}).touch === true },
|
|
32140
|
+
set(change) { __call('prefsSet', { change: change === undefined ? null : change }) },
|
|
32141
|
+
})
|
|
32107
32142
|
/** Purchases (the online services spec, part 3): asked of the page, which asks the store; answered on a later tick as a
|
|
32108
32143
|
* 'purchase' event. */
|
|
32109
32144
|
const __purchases = Object.freeze({
|
|
@@ -32389,6 +32424,7 @@ const __game = {
|
|
|
32389
32424
|
get ui() { return __ui },
|
|
32390
32425
|
get ads() { return __ads },
|
|
32391
32426
|
get online() { return __online },
|
|
32427
|
+
get prefs() { return __prefs },
|
|
32392
32428
|
get purchases() { return __purchases },
|
|
32393
32429
|
/** The game script's own fields, read only; null without one. */
|
|
32394
32430
|
get script() { return __frozen(__revived(__call('gameScript', null))) },
|
|
@@ -32823,19 +32859,19 @@ globalThis.noise = noise
|
|
|
32823
32859
|
`;
|
|
32824
32860
|
|
|
32825
32861
|
// ../core/dist/script/top-level.js
|
|
32826
|
-
var
|
|
32862
|
+
var import_parser2 = __toESM(require_parser(), 1);
|
|
32827
32863
|
var import_tokenizer = __toESM(require_tokenizer(), 1);
|
|
32828
|
-
var
|
|
32864
|
+
var import_types2 = __toESM(require_types(), 1);
|
|
32829
32865
|
var import_keywords = __toESM(require_keywords(), 1);
|
|
32830
32866
|
var CHANGEABLE_TOP_LEVEL = "a script keeps its state in its fields: a top-level let or var lives outside the game, where a snapshot cannot hold it and a second play does not start from it; make it a field, or const if it never changes";
|
|
32831
32867
|
var PRIVATE_STATIC = "a private static field cannot be frozen, so it would keep state outside the game, shared by every object: make it an instance field, or a const at the top of the script";
|
|
32832
32868
|
var PRIVATE_MEMBER = "a private field or method (#name) cannot be kept between ticks: a script's state is its plain fields, and an object made again from them, after a restore or a failed call, has no private ones; drop the #, and keep it as a field or a method";
|
|
32833
|
-
var DECLARING = /* @__PURE__ */ new Set([
|
|
32834
|
-
var OPENING = /* @__PURE__ */ new Set([
|
|
32835
|
-
var CLOSING = /* @__PURE__ */ new Set([
|
|
32869
|
+
var DECLARING = /* @__PURE__ */ new Set([import_types2.TokenType._const, import_types2.TokenType._let, import_types2.TokenType._var, import_types2.TokenType._function, import_types2.TokenType._class, import_types2.TokenType._enum]);
|
|
32870
|
+
var OPENING = /* @__PURE__ */ new Set([import_types2.TokenType.parenL, import_types2.TokenType.bracketL, import_types2.TokenType.braceL, import_types2.TokenType.dollarBraceL]);
|
|
32871
|
+
var CLOSING = /* @__PURE__ */ new Set([import_types2.TokenType.parenR, import_types2.TokenType.bracketR, import_types2.TokenType.braceR]);
|
|
32836
32872
|
var lineAt = (source2, offset) => source2.slice(0, offset).split("\n").length;
|
|
32837
32873
|
function topLevelOf(source2) {
|
|
32838
|
-
const { tokens, scopes } = (0,
|
|
32874
|
+
const { tokens, scopes } = (0, import_parser2.parse)(source2, false, true, false);
|
|
32839
32875
|
const at2 = (i) => {
|
|
32840
32876
|
const token = tokens[i];
|
|
32841
32877
|
return { name: token === void 0 ? "" : source2.slice(token.start, token.end), line: lineAt(source2, token?.start ?? 0) };
|
|
@@ -32847,21 +32883,21 @@ function topLevelOf(source2) {
|
|
|
32847
32883
|
const functions = scopes.filter((scope) => scope.isFunctionScope && !(scope.startTokenIndex === 0 && scope.endTokenIndex >= tokens.length));
|
|
32848
32884
|
const inFunction = (i) => functions.some((scope) => scope.startTokenIndex <= i && i < scope.endTokenIndex);
|
|
32849
32885
|
for (const [i, token] of tokens.entries()) {
|
|
32850
|
-
if (token.type ===
|
|
32886
|
+
if (token.type === import_types2.TokenType._var && !inFunction(i))
|
|
32851
32887
|
changeable.push({ ...at2(i + 1), line: at2(i).line });
|
|
32852
32888
|
if (token.contextualKeyword === import_keywords.ContextualKeyword._static) {
|
|
32853
32889
|
let next = i + 1;
|
|
32854
32890
|
while (tokens[next]?.contextualKeyword === import_keywords.ContextualKeyword._readonly)
|
|
32855
32891
|
next += 1;
|
|
32856
|
-
if (tokens[next]?.type ===
|
|
32892
|
+
if (tokens[next]?.type === import_types2.TokenType.hash && tokens[next + 2]?.type !== import_types2.TokenType.parenL)
|
|
32857
32893
|
privateStatics.push({ ...at2(next + 1), name: `#${at2(next + 1).name}` });
|
|
32858
32894
|
}
|
|
32859
|
-
if (token.type ===
|
|
32895
|
+
if (token.type === import_types2.TokenType.hash) {
|
|
32860
32896
|
let back2 = i - 1;
|
|
32861
32897
|
while (tokens[back2]?.contextualKeyword === import_keywords.ContextualKeyword._readonly)
|
|
32862
32898
|
back2 -= 1;
|
|
32863
32899
|
const before2 = tokens[back2];
|
|
32864
|
-
const used = before2 !== void 0 && (before2.type ===
|
|
32900
|
+
const used = before2 !== void 0 && (before2.type === import_types2.TokenType.dot || before2.type === import_types2.TokenType.questionDot);
|
|
32865
32901
|
if (!used && before2?.contextualKeyword !== import_keywords.ContextualKeyword._static)
|
|
32866
32902
|
privateMembers.push({ ...at2(i + 1), name: `#${at2(i + 1).name}` });
|
|
32867
32903
|
}
|
|
@@ -32881,7 +32917,7 @@ function topLevelOf(source2) {
|
|
|
32881
32917
|
else if (depth <= 0 && DECLARING.has(type))
|
|
32882
32918
|
break;
|
|
32883
32919
|
}
|
|
32884
|
-
if (tokens[back]?.type ===
|
|
32920
|
+
if (tokens[back]?.type === import_types2.TokenType._let)
|
|
32885
32921
|
changeable.push(declared);
|
|
32886
32922
|
}
|
|
32887
32923
|
changeable.sort((a, b) => a.line - b.line);
|
|
@@ -33752,6 +33788,8 @@ function initialScripts(given, kinds, seed = 1, saved = {}, audio, fonts, adsOff
|
|
|
33752
33788
|
...adsOff === void 0 ? {} : { adsOff },
|
|
33753
33789
|
// A game whose scripts mention online keeps its state and call count from the first tick; any other never has them.
|
|
33754
33790
|
...usesOnline([...Object.values(sources.kinds), sources.game ?? "", ...Object.values(sources.modules ?? {})]) ? { onlineState: "off", nextCall: 1 } : {},
|
|
33791
|
+
// A game whose scripts mention the player's settings keeps them from the first tick; any other never has them.
|
|
33792
|
+
...usesPrefs([...Object.values(sources.kinds), sources.game ?? "", ...Object.values(sources.modules ?? {})]) ? { prefs: NO_PREFS_YET } : {},
|
|
33755
33793
|
// A game whose scripts mention purchases keeps its products from the first tick; any other never has them.
|
|
33756
33794
|
...usesPurchases([...Object.values(sources.kinds), sources.game ?? "", ...Object.values(sources.modules ?? {})]) ? { purchases: NO_PURCHASES_YET } : {}
|
|
33757
33795
|
};
|
|
@@ -35364,7 +35402,7 @@ type Side = 'above' | 'below' | 'side' | 'overlap'
|
|
|
35364
35402
|
type Colour = string | number
|
|
35365
35403
|
/* KindName, PropName and Button are each game's own (the whole-engine review, I11): its
|
|
35366
35404
|
* kinds; the properties it declares, or a rule or a script sets; and the buttons every game
|
|
35367
|
-
* has (left, right, up, down, jump, action,
|
|
35405
|
+
* has (left, right, up, down, jump, action, click, the left mouse button, and menu: see Prefs) with those its
|
|
35368
35406
|
* controls name. A name written
|
|
35369
35407
|
* in quotes that the game does not have is an error where it is written; a name held in a
|
|
35370
35408
|
* string (a field, a table) is checked as the game plays. */
|
|
@@ -35676,87 +35714,6 @@ interface Turns {
|
|
|
35676
35714
|
readonly round: number
|
|
35677
35715
|
}
|
|
35678
35716
|
|
|
35679
|
-
/** Where a UI element sits in what holds it (the screen, or the element its in names): one of nine points. */
|
|
35680
|
-
type UiAnchor = 'top-left' | 'top' | 'top-right' | 'left' | 'center' | 'right' | 'bottom-left' | 'bottom' | 'bottom-right'
|
|
35681
|
-
/** A UI element, in design units (480 by 270 unless ui.design says), scaled to the real screen: the design's long side to
|
|
35682
|
-
* its long side, so a phone held either way shows it at the same size, and what is wider than a narrow screen is the
|
|
35683
|
-
* game's to lay out (a playtest look with ui: true says what runs off). */
|
|
35684
|
-
interface UiSpec {
|
|
35685
|
-
/** 'panel' when left out. Only a button is hovered, pressed, clicked and focused. A row or column places the elements
|
|
35686
|
-
* whose in names it, in the order they were first set, gap apart, and is as big as them unless given a size. */
|
|
35687
|
-
kind?: 'panel' | 'button' | 'label' | 'meter' | 'icon' | 'row' | 'column'
|
|
35688
|
-
/** The point of what holds it that it sits at; 'top-left' when left out. */
|
|
35689
|
-
anchor?: UiAnchor
|
|
35690
|
-
/** Design units in from the anchored edges: { anchor: 'top-right', at: [8, 8] } sits 8 in from the top and the
|
|
35691
|
-
* right; from a middle, x moves right and y down. [0, 0] when left out. A row or column places its own. */
|
|
35692
|
-
at?: [number, number]
|
|
35693
|
-
/** [width, height] in design units: needed, but for a row or column. */
|
|
35694
|
-
size?: [number, number]
|
|
35695
|
-
/** The element it sits inside, by name: anchored in its box, or placed by it when it is a row or column. */
|
|
35696
|
-
in?: string
|
|
35697
|
-
/** Design units between what a row or column holds. */
|
|
35698
|
-
gap?: number
|
|
35699
|
-
/** Design units inside a row's or column's edge. */
|
|
35700
|
-
pad?: number
|
|
35701
|
-
/** Where what a row or column holds sits across it; 'center' when left out. */
|
|
35702
|
-
align?: 'start' | 'center' | 'end'
|
|
35703
|
-
/** Never hovered, pressed, focused or clicked; its state reads 'disabled', to draw it greyed. */
|
|
35704
|
-
disabled?: boolean
|
|
35705
|
-
/** false starts it hidden, for ui.show to bring in. */
|
|
35706
|
-
shown?: boolean
|
|
35707
|
-
}
|
|
35708
|
-
/** An element as this screen shows it, in pixels as g.screen draws. */
|
|
35709
|
-
interface UiBox {
|
|
35710
|
-
readonly x: number
|
|
35711
|
-
readonly y: number
|
|
35712
|
-
readonly w: number
|
|
35713
|
-
readonly h: number
|
|
35714
|
-
/** 0 hidden to 1 shown, eased, as ui.show moves it: draw by it for a slide, a fade or a pop. */
|
|
35715
|
-
readonly shown: number
|
|
35716
|
-
readonly state: 'disabled' | 'pressed' | 'hover' | 'focused' | 'idle'
|
|
35717
|
-
/** Screen pixels in one design unit: size what is drawn in the box by it, as 14 * b.scale. */
|
|
35718
|
-
readonly scale: number
|
|
35719
|
-
}
|
|
35720
|
-
/** Text fitted to a box: the size it fits at, its lines, and whether what did not fit was cut. */
|
|
35721
|
-
interface UiFit { readonly size: number; readonly lines: string[]; readonly width: number; readonly height: number; readonly cut: boolean }
|
|
35722
|
-
/** game.ui: the game's UI elements. The engine places them on any screen, kept clear of a phone's notch and corners,
|
|
35723
|
-
* and tracks the pointer, a finger, presses, clicks and focus. It draws nothing: each element looks as the game's draw
|
|
35724
|
-
* draws it at ui.box, so make it look like this game and no other. Declare in start (or in update: the same again
|
|
35725
|
-
* changes nothing), read clicks in update or whilePaused, draw in draw. */
|
|
35726
|
-
interface Ui {
|
|
35727
|
-
/** Declares an element, or changes one; 64 at most. Never in draw. */
|
|
35728
|
-
set(name: string, spec: UiSpec): void
|
|
35729
|
-
/** Takes an element away, with those inside it. */
|
|
35730
|
-
remove(name: string): void
|
|
35731
|
-
/** Eases it in (true) or out (false) over the seconds (0.2 when left out), on the real clock, so a pause menu slides
|
|
35732
|
-
* in while the world holds. A hidden one is never clicked. */
|
|
35733
|
-
show(name: string, shown: boolean, seconds?: number): void
|
|
35734
|
-
/** Gives the keys to a menu: up, down, left and right move focus to the nearest button that way, and jump or action
|
|
35735
|
-
* clicks it. The game still sees those buttons, so hold its own controls while ui.focused is not null; null gives
|
|
35736
|
-
* them back. */
|
|
35737
|
-
focus(name: string | null): void
|
|
35738
|
-
/** The size the elements are written in, 480 by 270 when never set. */
|
|
35739
|
-
design(width: number, height: number): void
|
|
35740
|
-
/** Where it is on this screen and how it stands; null for a name never set. update reads it at the screen played,
|
|
35741
|
-
* draw at the screen drawn. */
|
|
35742
|
-
box(name: string): UiBox | null
|
|
35743
|
-
/** How it stands: idle, hover, pressed, focused or disabled; null for a name not set, as box gives. */
|
|
35744
|
-
state(name: string): UiBox['state'] | null
|
|
35745
|
-
/** Clicked since the last update: pressed and let go on it, by the pointer or a finger, or jump or action on its
|
|
35746
|
-
* focus. Heard once. A press on a button is the UI's: input.pressed('click') never sees it. False for a name not
|
|
35747
|
-
* set, so a game reading one it removed runs on. */
|
|
35748
|
-
clicked(name: string): boolean
|
|
35749
|
-
/** The largest size, from size (16 when left out) down to min (8), at which the text wrapped to the box fits it; at
|
|
35750
|
-
* min, what still does not fit is cut, ending in an ellipsis. text's fit option does this as it draws. */
|
|
35751
|
-
fit(text: string | number, box: { w: number; h: number }, options?: { size?: number; min?: number; font?: FontName; lineHeight?: number }): UiFit
|
|
35752
|
-
/** The focused button, or null. */
|
|
35753
|
-
readonly focused: string | null
|
|
35754
|
-
/** Screen pixels in one design unit on the screen played. */
|
|
35755
|
-
readonly scale: number
|
|
35756
|
-
/** The names set, in the order they were first set. */
|
|
35757
|
-
readonly names: readonly string[]
|
|
35758
|
-
}
|
|
35759
|
-
|
|
35760
35717
|
/** A level's back layer, drawn behind the objects and darker, or its front layer, drawn over them; neither collides. */
|
|
35761
35718
|
interface TileLayerOption { layer?: 'back' | 'front' }
|
|
35762
35719
|
|
|
@@ -36066,6 +36023,8 @@ interface Game {
|
|
|
36066
36023
|
readonly ads: Ads
|
|
36067
36024
|
/** The game's own server: calls and live rooms. */
|
|
36068
36025
|
readonly online: Online
|
|
36026
|
+
/** The player's sound, music and fullscreen, for the game's own pause menu. */
|
|
36027
|
+
readonly prefs: Prefs
|
|
36069
36028
|
/** Real-money purchases in the game's store app. */
|
|
36070
36029
|
readonly purchases: Purchases
|
|
36071
36030
|
/** Opens the game's privacy policy, as a game on the app stores must from inside itself: call it when the player
|
|
@@ -36125,6 +36084,116 @@ interface Game {
|
|
|
36125
36084
|
burst(x: In3D<number, 'burst(x, y, z)'>, y: number, z: number, options?: BurstOptions): void
|
|
36126
36085
|
}
|
|
36127
36086
|
|
|
36087
|
+
/** The player's own settings, which the page keeps for every game they play: what a game's own pause menu shows and
|
|
36088
|
+
* changes. A game whose scripts read the button 'menu' draws its own pause menu: the page presses menu where it would
|
|
36089
|
+
* open its own (P, Escape, a pad's Start, the touch pause button, an app's back button), and the game pauses itself
|
|
36090
|
+
* with game.pause() and resumes with game.resume(). Read as the page last said; a change is asked of the page, which
|
|
36091
|
+
* makes it after the tick and says it on a later one. */
|
|
36092
|
+
interface Prefs {
|
|
36093
|
+
/** Sound effects on. */
|
|
36094
|
+
readonly sound: boolean
|
|
36095
|
+
/** Music on. */
|
|
36096
|
+
readonly music: boolean
|
|
36097
|
+
/** The page fills the screen. */
|
|
36098
|
+
readonly fullscreen: boolean
|
|
36099
|
+
/** The page may fill the screen: false where it cannot (a frame that forbids it, most phones' browsers, an app), so a
|
|
36100
|
+
* menu leaves its Fullscreen row out. */
|
|
36101
|
+
readonly canFullscreen: boolean
|
|
36102
|
+
/** The player is on a touch screen (a finger has touched it): show the game's own touch controls, the UI elements
|
|
36103
|
+
* with touch, and its sticks. */
|
|
36104
|
+
readonly touch: boolean
|
|
36105
|
+
/** Asks the page to change them: prefs.set({ music: !this.game.prefs.music }). Fullscreen only on a press or a click,
|
|
36106
|
+
* as browsers allow it. Never from draw. */
|
|
36107
|
+
set(change: { sound?: boolean; music?: boolean; fullscreen?: boolean }): void
|
|
36108
|
+
}
|
|
36109
|
+
|
|
36110
|
+
/** Where a UI element sits in what holds it (the screen, or the element its in names): one of nine points. */
|
|
36111
|
+
type UiAnchor = 'top-left' | 'top' | 'top-right' | 'left' | 'center' | 'right' | 'bottom-left' | 'bottom' | 'bottom-right'
|
|
36112
|
+
/** A UI element, in design units (480 by 270 unless ui.design says), scaled to the real screen: the design's long side to
|
|
36113
|
+
* its long side, so a phone held either way shows it at the same size, and what is wider than a narrow screen is the
|
|
36114
|
+
* game's to lay out (a playtest look with ui: true says what runs off). */
|
|
36115
|
+
interface UiSpec {
|
|
36116
|
+
/** 'panel' when left out. Only a button is hovered, pressed, clicked and focused. A row or column places the elements
|
|
36117
|
+
* whose in names it, in the order they were first set, gap apart, and is as big as them unless given a size. A stick
|
|
36118
|
+
* is a touch control: a finger on it (or that drifts off its edge) is player 1's left stick, -1 to 1 each way from its
|
|
36119
|
+
* middle, as input.stick('left') reads it. */
|
|
36120
|
+
kind?: 'panel' | 'button' | 'label' | 'meter' | 'icon' | 'row' | 'column' | 'stick'
|
|
36121
|
+
/** The point of what holds it that it sits at; 'top-left' when left out. */
|
|
36122
|
+
anchor?: UiAnchor
|
|
36123
|
+
/** Design units in from the anchored edges: { anchor: 'top-right', at: [8, 8] } sits 8 in from the top and the
|
|
36124
|
+
* right; from a middle, x moves right and y down. [0, 0] when left out. A row or column places its own. */
|
|
36125
|
+
at?: [number, number]
|
|
36126
|
+
/** [width, height] in design units: needed, but for a row or column. */
|
|
36127
|
+
size?: [number, number]
|
|
36128
|
+
/** The element it sits inside, by name: anchored in its box, or placed by it when it is a row or column. */
|
|
36129
|
+
in?: string
|
|
36130
|
+
/** Design units between what a row or column holds. */
|
|
36131
|
+
gap?: number
|
|
36132
|
+
/** Design units inside a row's or column's edge. */
|
|
36133
|
+
pad?: number
|
|
36134
|
+
/** Where what a row or column holds sits across it; 'center' when left out. */
|
|
36135
|
+
align?: 'start' | 'center' | 'end'
|
|
36136
|
+
/** Never hovered, pressed, focused or clicked; its state reads 'disabled', to draw it greyed. */
|
|
36137
|
+
disabled?: boolean
|
|
36138
|
+
/** false starts it hidden, for ui.show to bring in. */
|
|
36139
|
+
shown?: boolean
|
|
36140
|
+
/** A touch control (the game's own, which the page then draws none of): the button a finger on it holds, as a key
|
|
36141
|
+
* would, read by input.held and input.pressed; a finger on it, or on a stick, is never a click. Declare touch
|
|
36142
|
+
* controls shown: false and ui.show them while game.prefs.touch: a hidden one takes no finger. */
|
|
36143
|
+
touch?: Buttons
|
|
36144
|
+
}
|
|
36145
|
+
/** An element as this screen shows it, in pixels as g.screen draws. */
|
|
36146
|
+
interface UiBox {
|
|
36147
|
+
readonly x: number
|
|
36148
|
+
readonly y: number
|
|
36149
|
+
readonly w: number
|
|
36150
|
+
readonly h: number
|
|
36151
|
+
/** 0 hidden to 1 shown, eased, as ui.show moves it: draw by it for a slide, a fade or a pop. */
|
|
36152
|
+
readonly shown: number
|
|
36153
|
+
readonly state: 'disabled' | 'pressed' | 'hover' | 'focused' | 'idle'
|
|
36154
|
+
/** Screen pixels in one design unit: size what is drawn in the box by it, as 14 * b.scale. */
|
|
36155
|
+
readonly scale: number
|
|
36156
|
+
}
|
|
36157
|
+
/** Text fitted to a box: the size it fits at, its lines, and whether what did not fit was cut. */
|
|
36158
|
+
interface UiFit { readonly size: number; readonly lines: string[]; readonly width: number; readonly height: number; readonly cut: boolean }
|
|
36159
|
+
/** game.ui: the game's UI elements. The engine places them on any screen, kept clear of a phone's notch and corners,
|
|
36160
|
+
* and tracks the pointer, a finger, presses, clicks and focus. It draws nothing: each element looks as the game's draw
|
|
36161
|
+
* draws it at ui.box, so make it look like this game and no other. Declare in start (or in update: the same again
|
|
36162
|
+
* changes nothing), read clicks in update or whilePaused, draw in draw. */
|
|
36163
|
+
interface Ui {
|
|
36164
|
+
/** Declares an element, or changes one; 64 at most. Never in draw. */
|
|
36165
|
+
set(name: string, spec: UiSpec): void
|
|
36166
|
+
/** Takes an element away, with those inside it. */
|
|
36167
|
+
remove(name: string): void
|
|
36168
|
+
/** Eases it in (true) or out (false) over the seconds (0.2 when left out), on the real clock, so a pause menu slides
|
|
36169
|
+
* in while the world holds. A hidden one is never clicked. */
|
|
36170
|
+
show(name: string, shown: boolean, seconds?: number): void
|
|
36171
|
+
/** Gives the keys to a menu: up, down, left and right move focus to the nearest button that way, and jump or action
|
|
36172
|
+
* clicks it. The game still sees those buttons, so hold its own controls while ui.focused is not null; null gives
|
|
36173
|
+
* them back. */
|
|
36174
|
+
focus(name: string | null): void
|
|
36175
|
+
/** The size the elements are written in, 480 by 270 when never set. */
|
|
36176
|
+
design(width: number, height: number): void
|
|
36177
|
+
/** Where it is on this screen and how it stands; null for a name never set. update reads it at the screen played,
|
|
36178
|
+
* draw at the screen drawn. */
|
|
36179
|
+
box(name: string): UiBox | null
|
|
36180
|
+
/** How it stands: idle, hover, pressed, focused or disabled; null for a name not set, as box gives. */
|
|
36181
|
+
state(name: string): UiBox['state'] | null
|
|
36182
|
+
/** Clicked since the last update: pressed and let go on it, by the pointer or a finger, or jump or action on its
|
|
36183
|
+
* focus. Heard once. A press on a button is the UI's: input.pressed('click') never sees it, nor the game's own button
|
|
36184
|
+
* bound to Click. False for a name not set, so a game reading one it removed runs on. */
|
|
36185
|
+
clicked(name: string): boolean
|
|
36186
|
+
/** The largest size, from size (16 when left out) down to min (8), at which the text wrapped to the box fits it; at
|
|
36187
|
+
* min, what still does not fit is cut, ending in an ellipsis. text's fit option does this as it draws. */
|
|
36188
|
+
fit(text: string | number, box: { w: number; h: number }, options?: { size?: number; min?: number; font?: FontName; lineHeight?: number }): UiFit
|
|
36189
|
+
/** The focused button, or null. */
|
|
36190
|
+
readonly focused: string | null
|
|
36191
|
+
/** Screen pixels in one design unit on the screen played. */
|
|
36192
|
+
readonly scale: number
|
|
36193
|
+
/** The names set, in the order they were first set. */
|
|
36194
|
+
readonly names: readonly string[]
|
|
36195
|
+
}
|
|
36196
|
+
|
|
36128
36197
|
/** On g.screen, a drawing placed from a point of the world, a Thing's middle or a point in tiles: its x and y are then
|
|
36129
36198
|
* pixels from where that point is on the screen this frame (a health bar over an enemy, a name over a character).
|
|
36130
36199
|
* edge keeps it inside the screen by that many pixels, as an arrow to something off it does. The world layers take
|
|
@@ -36288,10 +36357,6 @@ declare const console: {
|
|
|
36288
36357
|
}
|
|
36289
36358
|
`;
|
|
36290
36359
|
|
|
36291
|
-
// ../core/dist/script/scan.js
|
|
36292
|
-
var import_parser2 = __toESM(require_parser(), 1);
|
|
36293
|
-
var import_types2 = __toESM(require_types(), 1);
|
|
36294
|
-
|
|
36295
36360
|
// ../core/dist/script/shader-wrap.js
|
|
36296
36361
|
var UNIFORM_NUMBERS = {
|
|
36297
36362
|
float: 1,
|
|
@@ -50900,12 +50965,13 @@ function rayOf(text3) {
|
|
|
50900
50965
|
var LOOK_WORDS = "which must be <dx,dy in whole pixels from -4000 to 4000, like <12,-3";
|
|
50901
50966
|
var RAY_WORDS = "which must be ?ox,oy,oz,dx,dy,dz: its origin in 256ths of a block and its direction in 10,000ths, whole numbers, like ?1280,512,0,0,-7071,7071";
|
|
50902
50967
|
function onlineKey(input) {
|
|
50903
|
-
if (input.online === void 0 && input.onlineState === void 0 && input.purchases === void 0)
|
|
50968
|
+
if (input.online === void 0 && input.onlineState === void 0 && input.purchases === void 0 && input.prefs === void 0)
|
|
50904
50969
|
return "";
|
|
50905
50970
|
const json = JSON.stringify({
|
|
50906
50971
|
...input.online === void 0 ? {} : { h: input.online },
|
|
50907
50972
|
...input.onlineState === void 0 ? {} : { s: input.onlineState },
|
|
50908
|
-
...input.purchases === void 0 ? {} : { p: input.purchases }
|
|
50973
|
+
...input.purchases === void 0 ? {} : { p: input.purchases },
|
|
50974
|
+
...input.prefs === void 0 ? {} : { f: input.prefs }
|
|
50909
50975
|
});
|
|
50910
50976
|
let text3 = "";
|
|
50911
50977
|
for (const byte of new TextEncoder().encode(json))
|
|
@@ -50921,19 +50987,22 @@ function onlineOf(text3) {
|
|
|
50921
50987
|
const read2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
50922
50988
|
if (typeof read2 !== "object" || read2 === null || Array.isArray(read2))
|
|
50923
50989
|
return null;
|
|
50924
|
-
const { h: h2, s: s2, p } = read2;
|
|
50990
|
+
const { h: h2, s: s2, p, f: f2 } = read2;
|
|
50925
50991
|
if (h2 !== void 0 && (!Array.isArray(h2) || !h2.every(isOnlineHeard)))
|
|
50926
50992
|
return null;
|
|
50927
50993
|
if (s2 !== void 0 && !ONLINE_STATES.includes(s2))
|
|
50928
50994
|
return null;
|
|
50929
50995
|
if (p !== void 0 && (!Array.isArray(p) || !p.every(isPurchaseHeard)))
|
|
50930
50996
|
return null;
|
|
50931
|
-
if (
|
|
50997
|
+
if (f2 !== void 0 && !isPrefs(f2))
|
|
50998
|
+
return null;
|
|
50999
|
+
if (h2 === void 0 && s2 === void 0 && p === void 0 && f2 === void 0)
|
|
50932
51000
|
return null;
|
|
50933
51001
|
return {
|
|
50934
51002
|
...h2 === void 0 ? {} : { online: h2 },
|
|
50935
51003
|
...s2 === void 0 ? {} : { onlineState: s2 },
|
|
50936
|
-
...p === void 0 ? {} : { purchases: p }
|
|
51004
|
+
...p === void 0 ? {} : { purchases: p },
|
|
51005
|
+
...f2 === void 0 ? {} : { prefs: f2 }
|
|
50937
51006
|
};
|
|
50938
51007
|
} catch {
|
|
50939
51008
|
return null;
|
|
@@ -52592,7 +52661,7 @@ function nextStepOf(tiles, field, from, size, diagonal) {
|
|
|
52592
52661
|
}
|
|
52593
52662
|
|
|
52594
52663
|
// ../core/dist/script/ui.js
|
|
52595
|
-
var UI_KINDS = ["panel", "button", "label", "meter", "icon", "row", "column"];
|
|
52664
|
+
var UI_KINDS = ["panel", "button", "label", "meter", "icon", "row", "column", "stick"];
|
|
52596
52665
|
var UI_ANCHORS = ["top-left", "top", "top-right", "left", "center", "right", "bottom-left", "bottom", "bottom-right"];
|
|
52597
52666
|
var MAX_UI_ELEMENTS = 64;
|
|
52598
52667
|
var MOST_CLICKED = 16;
|
|
@@ -52610,7 +52679,7 @@ var NO_UI = {
|
|
|
52610
52679
|
clicked: []
|
|
52611
52680
|
};
|
|
52612
52681
|
var NAME2 = /^[a-z][a-z0-9_-]{0,39}$/;
|
|
52613
|
-
var KEYS = ["kind", "anchor", "at", "size", "in", "gap", "pad", "align", "disabled", "shown"];
|
|
52682
|
+
var KEYS = ["kind", "anchor", "at", "size", "in", "gap", "pad", "align", "disabled", "shown", "touch"];
|
|
52614
52683
|
var words = (list2) => `${list2.slice(0, -1).map((w2) => `'${w2}'`).join(", ")} or '${list2[list2.length - 1] ?? ""}'`;
|
|
52615
52684
|
function uiName(raw, what) {
|
|
52616
52685
|
if (typeof raw === "string" && NAME2.test(raw))
|
|
@@ -52659,6 +52728,14 @@ function uiSpecOf(raw, name) {
|
|
|
52659
52728
|
throw new Error(`${label}: disabled is true or false`);
|
|
52660
52729
|
if (o2.shown !== void 0 && typeof o2.shown !== "boolean")
|
|
52661
52730
|
throw new Error(`${label}: shown is true or false`);
|
|
52731
|
+
const touch = o2.touch === void 0 || o2.touch === null ? null : o2.touch;
|
|
52732
|
+
if (touch !== null && (typeof touch !== "string" || !/^[a-z][a-z0-9_]{0,39}$/.test(touch))) {
|
|
52733
|
+
throw new Error(`${label}: touch is the name of a button a finger on it holds, like 'jump' or 'fire', not ${JSON.stringify(touch)}`);
|
|
52734
|
+
}
|
|
52735
|
+
if (touch !== null && kind === "stick")
|
|
52736
|
+
throw new Error(`${label}: a stick moves the stick, player 1's left; it holds no button, so it takes no touch`);
|
|
52737
|
+
if (touch !== null && container)
|
|
52738
|
+
throw new Error(`${label}: a row or a column holds its elements, not a button; give touch to an element inside it`);
|
|
52662
52739
|
return {
|
|
52663
52740
|
kind,
|
|
52664
52741
|
anchor,
|
|
@@ -52668,7 +52745,8 @@ function uiSpecOf(raw, name) {
|
|
|
52668
52745
|
gap: units(o2.gap, `${label}: gap`, 0),
|
|
52669
52746
|
pad: units(o2.pad, `${label}: pad`, 0),
|
|
52670
52747
|
align,
|
|
52671
|
-
disabled: o2.disabled === true
|
|
52748
|
+
disabled: o2.disabled === true,
|
|
52749
|
+
...touch === null ? {} : { touch }
|
|
52672
52750
|
};
|
|
52673
52751
|
}
|
|
52674
52752
|
function safeInsets(screen) {
|
|
@@ -52810,24 +52888,55 @@ function uiStateOf(ui, name) {
|
|
|
52810
52888
|
var sameList = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
|
|
52811
52889
|
var FOCUS_KEYS = ["left", "right", "up", "down", "jump", "action"];
|
|
52812
52890
|
var uiFrom = (input) => ({ ...NO_UI, down: input.buttons?.includes("click") === true, keys: FOCUS_KEYS.filter((key) => input[key]) });
|
|
52813
|
-
function
|
|
52891
|
+
function pressable(ui, name, real) {
|
|
52892
|
+
const spec = ui.elements[name];
|
|
52893
|
+
return spec !== void 0 && spec.kind === "button" && !spec.disabled && shownOf2(ui, name, real) > 0;
|
|
52894
|
+
}
|
|
52895
|
+
function boxHolds(boxes, name, p) {
|
|
52896
|
+
const b = boxes.get(name);
|
|
52897
|
+
return b !== void 0 && p.x >= b.x && p.x < b.x + b.w && p.y >= b.y && p.y < b.y + b.h;
|
|
52898
|
+
}
|
|
52899
|
+
function uiButtonAt(ui, point, screen, real, boxes = layoutUi(ui, screen)) {
|
|
52900
|
+
let found = null;
|
|
52901
|
+
for (const name of ui.order)
|
|
52902
|
+
if (pressable(ui, name, real) && boxHolds(boxes, name, point))
|
|
52903
|
+
found = name;
|
|
52904
|
+
return found;
|
|
52905
|
+
}
|
|
52906
|
+
function stickHolds(box, p) {
|
|
52907
|
+
return p.x >= box.x - box.w / 2 && p.x <= box.x + box.w * 1.5 && p.y >= box.y - box.h / 2 && p.y <= box.y + box.h * 1.5;
|
|
52908
|
+
}
|
|
52909
|
+
function touchedOf(ui, input, real) {
|
|
52910
|
+
const fingers = input.touches ?? [];
|
|
52911
|
+
if (fingers.length === 0)
|
|
52912
|
+
return { held: [], stick: null };
|
|
52814
52913
|
const screen = { width: input.screenSize?.w ?? SCREEN_DEFAULT.w, height: input.screenSize?.h ?? SCREEN_DEFAULT.h };
|
|
52815
52914
|
const boxes = layoutUi(ui, screen);
|
|
52816
|
-
const
|
|
52915
|
+
const held = [];
|
|
52916
|
+
let stick = null;
|
|
52917
|
+
const clamp4 = (n) => Math.max(-1, Math.min(1, Math.round(n * 100) / 100)) + 0;
|
|
52918
|
+
for (const name of ui.order) {
|
|
52817
52919
|
const spec = ui.elements[name];
|
|
52818
|
-
|
|
52819
|
-
|
|
52820
|
-
|
|
52821
|
-
|
|
52822
|
-
|
|
52823
|
-
|
|
52824
|
-
|
|
52825
|
-
|
|
52826
|
-
|
|
52827
|
-
|
|
52828
|
-
if (eligible(name) && holds2(name, pointer))
|
|
52829
|
-
hover = name;
|
|
52920
|
+
const box = boxes.get(name);
|
|
52921
|
+
if (spec === void 0 || box === void 0 || spec.disabled || shownOf2(ui, name, real) <= 0)
|
|
52922
|
+
continue;
|
|
52923
|
+
if (spec.touch !== void 0 && !held.includes(spec.touch) && fingers.some((f2) => boxHolds(boxes, name, f2)))
|
|
52924
|
+
held.push(spec.touch);
|
|
52925
|
+
if (spec.kind === "stick" && stick === null) {
|
|
52926
|
+
const finger = fingers.find((f2) => stickHolds(box, f2));
|
|
52927
|
+
if (finger !== void 0)
|
|
52928
|
+
stick = { x: clamp4((finger.x - (box.x + box.w / 2)) / (box.w / 2)), y: clamp4((finger.y - (box.y + box.h / 2)) / (box.h / 2)) };
|
|
52929
|
+
}
|
|
52830
52930
|
}
|
|
52931
|
+
return { held, stick };
|
|
52932
|
+
}
|
|
52933
|
+
function stepUi(ui, input, real) {
|
|
52934
|
+
const screen = { width: input.screenSize?.w ?? SCREEN_DEFAULT.w, height: input.screenSize?.h ?? SCREEN_DEFAULT.h };
|
|
52935
|
+
const boxes = layoutUi(ui, screen);
|
|
52936
|
+
const eligible = (name) => pressable(ui, name, real);
|
|
52937
|
+
const holds2 = (name, p) => boxHolds(boxes, name, p);
|
|
52938
|
+
const pointer = input.screenPointer ?? input.touches?.[0] ?? null;
|
|
52939
|
+
const hover = pointer === null ? null : uiButtonAt(ui, pointer, screen, real, boxes);
|
|
52831
52940
|
const held = input.buttons?.includes("click") === true;
|
|
52832
52941
|
const clicked = [...ui.clicked];
|
|
52833
52942
|
const click = (name) => {
|
|
@@ -53228,7 +53337,7 @@ var OWN_AUDIO = /^own:[a-z0-9][a-z0-9-]{0,39}$/;
|
|
|
53228
53337
|
var LIB_AUDIO = /^lib:[a-z0-9][a-z0-9-]*\/[a-z0-9][a-z0-9-]*$/;
|
|
53229
53338
|
var MOST_BURSTS = 64;
|
|
53230
53339
|
var MOST_DEFERRED = 1024;
|
|
53231
|
-
var DRAW_OPS = /* @__PURE__ */ new Set(["thing", "data", "fields", "shown", "find", "findAll", "findIn", "touching", "tileAt", "tileIn", "tileUnder", "raycast", "path", "setting", "load", "random", "log", "drawn", "clock", "running", "measure", "bodyOf", "nextStep", "vars", "shared", "gameScript", "parentOf", "levelSize", "moving", "turns", "mixer", "typing", "t", "language", "languages", "ui", "uiFit", "onlineState", "purchaseProducts", "overlap3", "blockAt", "toScreen"]);
|
|
53340
|
+
var DRAW_OPS = /* @__PURE__ */ new Set(["thing", "data", "fields", "shown", "find", "findAll", "findIn", "touching", "tileAt", "tileIn", "tileUnder", "raycast", "path", "setting", "load", "random", "log", "drawn", "clock", "running", "measure", "bodyOf", "nextStep", "vars", "shared", "gameScript", "parentOf", "levelSize", "moving", "turns", "mixer", "typing", "t", "language", "languages", "ui", "uiFit", "onlineState", "prefs", "purchaseProducts", "overlap3", "blockAt", "toScreen"]);
|
|
53232
53341
|
function screenOf2(input) {
|
|
53233
53342
|
const size = input.screenSize ?? SCREEN_DEFAULT;
|
|
53234
53343
|
return { screen: input.screenPointer ?? null, size: { width: size.w, height: size.h } };
|
|
@@ -53297,7 +53406,7 @@ function fromUnit(raw, unit, what) {
|
|
|
53297
53406
|
return fromInt(Math.round(value));
|
|
53298
53407
|
}
|
|
53299
53408
|
}
|
|
53300
|
-
var BOT_OPS = /* @__PURE__ */ new Set(["thing", "data", "fields", "shown", "find", "findAll", "findIn", "touching", "tileAt", "tileIn", "tileUnder", "raycast", "path", "setting", "load", "random", "log", "clock", "running", "measure", "bodyOf", "nextStep", "vars", "shared", "gameScript", "parentOf", "levelSize", "moving", "turns", "mixer", "typing", "t", "language", "languages", "ui", "uiFit", "onlineState", "purchaseProducts", "overlap3", "blockAt"]);
|
|
53409
|
+
var BOT_OPS = /* @__PURE__ */ new Set(["thing", "data", "fields", "shown", "find", "findAll", "findIn", "touching", "tileAt", "tileIn", "tileUnder", "raycast", "path", "setting", "load", "random", "log", "clock", "running", "measure", "bodyOf", "nextStep", "vars", "shared", "gameScript", "parentOf", "levelSize", "moving", "turns", "mixer", "typing", "t", "language", "languages", "ui", "uiFit", "onlineState", "prefs", "purchaseProducts", "overlap3", "blockAt"]);
|
|
53301
53410
|
function sidesOf(normal) {
|
|
53302
53411
|
switch (normal) {
|
|
53303
53412
|
case "a_above_b":
|
|
@@ -53418,6 +53527,9 @@ var Turn = class {
|
|
|
53418
53527
|
* game that never mentions online (the online services spec). */
|
|
53419
53528
|
online;
|
|
53420
53529
|
onlineState;
|
|
53530
|
+
/** The player's settings as the input last said, and the change of them asked this tick (a game's own pause menu). */
|
|
53531
|
+
prefs;
|
|
53532
|
+
prefsAsk;
|
|
53421
53533
|
nextCall;
|
|
53422
53534
|
/** What the scripts asked of the store this tick, and what the game keeps of its purchases, absent for a game that
|
|
53423
53535
|
* never mentions them (the online services spec, part 3). */
|
|
@@ -53489,6 +53601,8 @@ var Turn = class {
|
|
|
53489
53601
|
this.online = fresh || scripts.online === void 0 ? void 0 : [...scripts.online];
|
|
53490
53602
|
this.onlineState = scripts.onlineState;
|
|
53491
53603
|
this.nextCall = scripts.nextCall;
|
|
53604
|
+
this.prefs = scripts.prefs;
|
|
53605
|
+
this.prefsAsk = fresh ? void 0 : scripts.prefsAsk;
|
|
53492
53606
|
this.purchase = fresh ? void 0 : scripts.purchase;
|
|
53493
53607
|
this.purchases = scripts.purchases;
|
|
53494
53608
|
this.music = scripts.music;
|
|
@@ -53644,6 +53758,8 @@ var Turn = class {
|
|
|
53644
53758
|
nextCall: this.nextCall,
|
|
53645
53759
|
purchase: this.purchase,
|
|
53646
53760
|
purchases: this.purchases,
|
|
53761
|
+
prefs: this.prefs,
|
|
53762
|
+
prefsAsk: this.prefsAsk,
|
|
53647
53763
|
bursts: this.bursts.length === 0 ? [] : [...this.bursts],
|
|
53648
53764
|
screen: this.screen,
|
|
53649
53765
|
waiting: this.waiting,
|
|
@@ -53703,6 +53819,8 @@ var Turn = class {
|
|
|
53703
53819
|
this.online = was.online;
|
|
53704
53820
|
this.onlineState = was.onlineState;
|
|
53705
53821
|
this.nextCall = was.nextCall;
|
|
53822
|
+
this.prefs = was.prefs;
|
|
53823
|
+
this.prefsAsk = was.prefsAsk;
|
|
53706
53824
|
this.purchase = was.purchase;
|
|
53707
53825
|
this.purchases = was.purchases;
|
|
53708
53826
|
this.bursts = was.bursts;
|
|
@@ -55044,6 +55162,14 @@ var Turn = class {
|
|
|
55044
55162
|
return null;
|
|
55045
55163
|
case "onlineState":
|
|
55046
55164
|
return this.onlineState ?? "off";
|
|
55165
|
+
// The player's settings (a game's own pause menu): read as the input last said; a change asked of the page, which
|
|
55166
|
+
// makes it after the tick and says it on a later one.
|
|
55167
|
+
case "prefs":
|
|
55168
|
+
return this.prefs ?? NO_PREFS_YET;
|
|
55169
|
+
case "prefsSet": {
|
|
55170
|
+
this.prefsAsk = { ...this.prefsAsk ?? {}, ...prefsChangeOf(args.change) };
|
|
55171
|
+
return null;
|
|
55172
|
+
}
|
|
55047
55173
|
// Purchases (the online services spec, part 3): asked of the page, which asks the store; the answer is heard on a
|
|
55048
55174
|
// later tick, as input.
|
|
55049
55175
|
case "purchaseBuy":
|
|
@@ -55735,6 +55861,17 @@ var Turn = class {
|
|
|
55735
55861
|
throw new Error(TOO_MANY_ASKS);
|
|
55736
55862
|
this.online = [...asked, ask];
|
|
55737
55863
|
}
|
|
55864
|
+
/** The player's settings as the page said them this tick, for a game that keeps them. A tick with a finger on the
|
|
55865
|
+
* screen that says nothing of them says a touch screen, as the page does on that tick: a playtest's track, which no
|
|
55866
|
+
* page plays, shows the game's touch controls to its look. */
|
|
55867
|
+
takePrefsInput() {
|
|
55868
|
+
if (this.prefs === void 0)
|
|
55869
|
+
return;
|
|
55870
|
+
if (this.input.prefs !== void 0)
|
|
55871
|
+
this.prefs = this.input.prefs;
|
|
55872
|
+
else if (!this.prefs.touch && (this.input.touches?.length ?? 0) > 0)
|
|
55873
|
+
this.prefs = { ...this.prefs, touch: true };
|
|
55874
|
+
}
|
|
55738
55875
|
/** What the page brought back from the game's server, and whether it is online, for a game that keeps online: each
|
|
55739
55876
|
* heard as an 'online' event. A game that never mentions online ignores it. */
|
|
55740
55877
|
takeOnlineInput() {
|
|
@@ -55792,7 +55929,7 @@ var Turn = class {
|
|
|
55792
55929
|
this.events.push(name);
|
|
55793
55930
|
}
|
|
55794
55931
|
scriptsState() {
|
|
55795
|
-
const { starting: _was, loops: _loops, mixer: _mixer, typing: _typing, ui: _ui, privacy: _privacy, ad: _ad, ads: _ads, online: _online, onlineState: _onlineState, nextCall: _nextCall, purchase: _purchase, purchases: _purchases, ...before2 } = this.scripts;
|
|
55932
|
+
const { starting: _was, loops: _loops, mixer: _mixer, typing: _typing, ui: _ui, privacy: _privacy, ad: _ad, ads: _ads, online: _online, onlineState: _onlineState, nextCall: _nextCall, purchase: _purchase, purchases: _purchases, prefs: _prefs, prefsAsk: _prefsAsk, ...before2 } = this.scripts;
|
|
55796
55933
|
return {
|
|
55797
55934
|
...before2,
|
|
55798
55935
|
fields: this.fields,
|
|
@@ -55824,6 +55961,8 @@ var Turn = class {
|
|
|
55824
55961
|
...this.online === void 0 || this.online.length === 0 ? {} : { online: this.online },
|
|
55825
55962
|
...this.onlineState === void 0 ? {} : { onlineState: this.onlineState },
|
|
55826
55963
|
...this.nextCall === void 0 ? {} : { nextCall: this.nextCall },
|
|
55964
|
+
...this.prefs === void 0 ? {} : { prefs: this.prefs },
|
|
55965
|
+
...this.prefsAsk === void 0 ? {} : { prefsAsk: this.prefsAsk },
|
|
55827
55966
|
...this.purchase === void 0 ? {} : { purchase: this.purchase },
|
|
55828
55967
|
...this.purchases === void 0 ? {} : { purchases: this.purchases },
|
|
55829
55968
|
music: this.music,
|
|
@@ -55866,12 +56005,33 @@ function uiTick(state, input) {
|
|
|
55866
56005
|
return { state, input };
|
|
55867
56006
|
const stepped = stepUi(ui, input, scripts.clock.real);
|
|
55868
56007
|
const next = stepped.ui === ui ? state : { ...state, scripts: { ...scripts, ui: stepped.ui } };
|
|
55869
|
-
|
|
55870
|
-
|
|
55871
|
-
|
|
56008
|
+
const touched = withTouched(input, touchedOf(stepped.ui, input, scripts.clock.real));
|
|
56009
|
+
if (!stepped.swallow || touched.buttons?.includes("click") !== true)
|
|
56010
|
+
return { state: next, input: touched };
|
|
56011
|
+
const { buttons, ...rest } = touched;
|
|
55872
56012
|
const kept = (buttons ?? []).filter((button) => button !== "click");
|
|
55873
56013
|
return { state: next, input: kept.length === 0 ? rest : { ...rest, buttons: kept } };
|
|
55874
56014
|
}
|
|
56015
|
+
var SIX2 = /* @__PURE__ */ new Set(["left", "right", "up", "down", "jump", "action"]);
|
|
56016
|
+
function withTouched(input, touched) {
|
|
56017
|
+
if (touched.held.length === 0 && touched.stick === null)
|
|
56018
|
+
return input;
|
|
56019
|
+
let out = input;
|
|
56020
|
+
const own2 = new Set(input.buttons ?? []);
|
|
56021
|
+
for (const button of touched.held) {
|
|
56022
|
+
if (SIX2.has(button))
|
|
56023
|
+
out = { ...out, [button]: true };
|
|
56024
|
+
else
|
|
56025
|
+
own2.add(button);
|
|
56026
|
+
}
|
|
56027
|
+
if (own2.size !== (input.buttons ?? []).length)
|
|
56028
|
+
out = { ...out, buttons: [...own2].sort() };
|
|
56029
|
+
if (touched.stick !== null) {
|
|
56030
|
+
const [first, ...rest] = input.sticks ?? [];
|
|
56031
|
+
out = { ...out, sticks: [{ rx: first?.rx ?? 0, ry: first?.ry ?? 0, lx: Math.round(touched.stick.x * 100) + 0, ly: Math.round(touched.stick.y * 100) + 0 }, ...rest] };
|
|
56032
|
+
}
|
|
56033
|
+
return out;
|
|
56034
|
+
}
|
|
55875
56035
|
function heardClicks(turn) {
|
|
55876
56036
|
if (turn.ui !== void 0 && turn.ui.clicked.length > 0)
|
|
55877
56037
|
turn.ui = { ...turn.ui, clicked: [] };
|
|
@@ -55897,6 +56057,7 @@ function beginScripts(state, input) {
|
|
|
55897
56057
|
function beginTurn(turn, scripts) {
|
|
55898
56058
|
turn.takeAdInput();
|
|
55899
56059
|
turn.takeOnlineInput();
|
|
56060
|
+
turn.takePrefsInput();
|
|
55900
56061
|
turn.takePurchaseInput();
|
|
55901
56062
|
turn.bursts = turn.bursts.filter((b) => turn.now - b.step < b.life * 60);
|
|
55902
56063
|
dueChange(turn);
|
|
@@ -56008,6 +56169,7 @@ function pausedScripts(state, input) {
|
|
|
56008
56169
|
function pausedTurn(turn, scripts) {
|
|
56009
56170
|
turn.takeAdInput();
|
|
56010
56171
|
turn.takeOnlineInput();
|
|
56172
|
+
turn.takePrefsInput();
|
|
56011
56173
|
turn.takePurchaseInput();
|
|
56012
56174
|
dueChange(turn);
|
|
56013
56175
|
turn.call(null, "whilePaused", [DT]);
|
|
@@ -59284,7 +59446,7 @@ function listGames(args = {}, fallback = LIBRARY_ROOT) {
|
|
|
59284
59446
|
// ../core/dist/surface/tools/inspect.js
|
|
59285
59447
|
function compile(args) {
|
|
59286
59448
|
try {
|
|
59287
|
-
const compiled = load(
|
|
59449
|
+
const compiled = load(parse2(args.source));
|
|
59288
59450
|
const first = compiled.levels[0];
|
|
59289
59451
|
if (first === void 0)
|
|
59290
59452
|
return fail("this spec declares no levels");
|
|
@@ -59297,7 +59459,7 @@ var isResult = (v) => typeof v === "object" && v !== null && "content" in v;
|
|
|
59297
59459
|
function validate(args) {
|
|
59298
59460
|
let ast;
|
|
59299
59461
|
try {
|
|
59300
|
-
ast =
|
|
59462
|
+
ast = parse2(args.source);
|
|
59301
59463
|
} catch (e2) {
|
|
59302
59464
|
const err = e2;
|
|
59303
59465
|
return ok({
|