@sculptr/sdk 0.0.0-stage → 2.17.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 +23 -2
- package/dist/content/index.d.ts +54 -0
- package/dist/decompiled-gml.d.ts +117 -0
- package/dist/host/index.d.ts +160 -0
- package/dist/image/index.d.ts +16 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +663 -0
- package/dist/keyboard/index.d.ts +42 -0
- package/dist/resources/object.d.ts +109 -0
- package/dist/resources/script.d.ts +184 -0
- package/dist/resources/sprite.d.ts +142 -0
- package/dist/ui/index.d.ts +232 -0
- package/dist/utils.d.ts +4 -0
- package/package.json +47 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
//#region src/resources/object.ts
|
|
2
|
+
var e = function(e) {
|
|
3
|
+
let { identity: t, hostApi: n, prefix: r, objects: i, internalReceive: a, internalCreate: o, normalizeEventName: s, context: c, queue: l, scratch: u } = e, d = /* @__PURE__ */ new Map();
|
|
4
|
+
for (let e of i) for (let n of Object.keys(e.receive ?? {})) {
|
|
5
|
+
let r = s(n), i = d.get(r);
|
|
6
|
+
if (i) throw Error(`mod ${t.id}: both ${i} and ${e.name} receive ${JSON.stringify(r)}. They would race for each message; give it to one of them.`);
|
|
7
|
+
d.set(r, e.name);
|
|
8
|
+
}
|
|
9
|
+
for (let e of Object.keys(a)) d.set(e, `${r}inbox`);
|
|
10
|
+
let f = (e, t) => `while (ds_list_size(${l(e)}) > 0) {
|
|
11
|
+
${u("pl")} = ds_list_find_value(${l(e)}, 0);
|
|
12
|
+
ds_list_delete(${l(e)}, 0);
|
|
13
|
+
${t}
|
|
14
|
+
}`;
|
|
15
|
+
if (d.size > 0) {
|
|
16
|
+
let e = [...d.keys()], t = e.map((e, t) => `${t === 0 ? "if" : "else if"} (${u("ev")} == "${e}") ds_list_add(${l(e)}, ${u("pl")});`).join("\n"), i = Object.entries(a).map(([e, t]) => f(e, t)).join("\n");
|
|
17
|
+
n.resource.create({
|
|
18
|
+
kind: "object",
|
|
19
|
+
name: `${r}inbox`,
|
|
20
|
+
persistent: !0,
|
|
21
|
+
visible: !1,
|
|
22
|
+
depth: 0,
|
|
23
|
+
events: {
|
|
24
|
+
create: e.map((e) => `${l(e)} = ds_list_create();`).join("\n") + o,
|
|
25
|
+
step: i || void 0,
|
|
26
|
+
beginStep: `${n.gml.receive(u("m"))}
|
|
27
|
+
while (${u("m")} != "") {
|
|
28
|
+
${u("at")} = string_pos(" ", ${u("m")});
|
|
29
|
+
if (${u("at")} > 1) {
|
|
30
|
+
${u("ev")} = string_copy(${u("m")}, 1, ${u("at")} - 1);
|
|
31
|
+
${u("pl")} = string_delete(${u("m")}, 1, ${u("at")});
|
|
32
|
+
${t}
|
|
33
|
+
}
|
|
34
|
+
${n.gml.receive(u("m"))}
|
|
35
|
+
}`
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
for (let e of i) {
|
|
40
|
+
let t = (t) => t?.(c(e)), i = [Object.entries(e.receive ?? {}).map(([t, n]) => f(s(t), n({
|
|
41
|
+
...c(e),
|
|
42
|
+
payload: u("pl")
|
|
43
|
+
}))).join("\n"), t(e.events?.step)].filter(Boolean).join("\n"), a = {};
|
|
44
|
+
for (let [n, r] of [
|
|
45
|
+
["create", t(e.events?.create)],
|
|
46
|
+
["beginStep", t(e.events?.beginStep)],
|
|
47
|
+
["step", i || void 0],
|
|
48
|
+
["endStep", t(e.events?.endStep)],
|
|
49
|
+
["draw", t(e.events?.draw)],
|
|
50
|
+
["destroy", t(e.events?.destroy)]
|
|
51
|
+
]) r && (a[n] = r);
|
|
52
|
+
n.resource.create({
|
|
53
|
+
kind: "object",
|
|
54
|
+
name: `${r}o_${e.name}`,
|
|
55
|
+
depth: e.depth,
|
|
56
|
+
persistent: e.persistent,
|
|
57
|
+
visible: e.visible,
|
|
58
|
+
events: a
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}, t = function(e) {
|
|
62
|
+
let t = -1, n = (e) => {
|
|
63
|
+
switch (e.k) {
|
|
64
|
+
case "arg":
|
|
65
|
+
e.index !== null && e.index < 16 && (t = Math.max(t, e.index));
|
|
66
|
+
break;
|
|
67
|
+
case "field":
|
|
68
|
+
n(e.of);
|
|
69
|
+
break;
|
|
70
|
+
case "index":
|
|
71
|
+
n(e.of), e.at.forEach(n);
|
|
72
|
+
break;
|
|
73
|
+
case "op":
|
|
74
|
+
e.args.forEach(n);
|
|
75
|
+
break;
|
|
76
|
+
case "call": e.args.forEach(n);
|
|
77
|
+
}
|
|
78
|
+
}, r = (e) => {
|
|
79
|
+
for (let t of e) t.k === "assign" ? (n(t.target), n(t.value)) : t.k === "call" ? n(t.call) : t.k === "if" ? (n(t.cond), r(t.then), r(t.else)) : t.k === "with" ? (n(t.target), r(t.body)) : t.k === "loop" ? r(t.body) : t.k === "switch" ? (n(t.value), t.bodies.forEach(r)) : t.k === "exit" && t.value && n(t.value);
|
|
80
|
+
};
|
|
81
|
+
return r(e), t;
|
|
82
|
+
}, n = /^[A-Za-z][A-Za-z0-9_-]*$/u, r = /^[A-Za-z][A-Za-z0-9_]*$/u, i = /^[A-Za-z0-9_.-]+$/u, a = function(e) {
|
|
83
|
+
e.hooks.forEach(({ script: n, wrap: r }, i) => {
|
|
84
|
+
let a = `${e.prefix}__orig${i}_${n}`, o = t(e.content.scripts.find((e) => e.name === n)?.body ?? []) + 1, s = `${e.prefix}__fwd${i}`, c = `global.${e.prefix}__hc${i}`, l = `global.${e.prefix}__ha${i}`, u = `global.${e.prefix}__hi${i}`, d = Array.from({ length: 17 }, (e, t) => {
|
|
85
|
+
let n = Array.from({ length: t }, (e, t) => `${l}[${t}]`).join(", ");
|
|
86
|
+
return ` case ${t}: return ${a}(${n});`;
|
|
87
|
+
}).join("\n");
|
|
88
|
+
e.hostApi.resource.create({
|
|
89
|
+
kind: "script",
|
|
90
|
+
name: s,
|
|
91
|
+
source: `switch (${c}) {\n${d}\n}\nreturn 0;`
|
|
92
|
+
});
|
|
93
|
+
let f = r({
|
|
94
|
+
engine: e.hostApi.target.engine,
|
|
95
|
+
original: {
|
|
96
|
+
call: (...e) => e.length === 0 ? `${s}()` : `${a}(${e.join(", ")})`,
|
|
97
|
+
arg: (e) => e >= 0 && e < 16 ? `argument${e}` : `argument[${e}]`,
|
|
98
|
+
argumentCount: "argument_count"
|
|
99
|
+
},
|
|
100
|
+
send: e.send,
|
|
101
|
+
call: e.call
|
|
102
|
+
});
|
|
103
|
+
e.hostApi.resource.create({
|
|
104
|
+
kind: "hook",
|
|
105
|
+
script: n,
|
|
106
|
+
original: a,
|
|
107
|
+
source: `
|
|
108
|
+
${c} = argument_count;
|
|
109
|
+
${u} = 0;
|
|
110
|
+
while (${u} < argument_count) {
|
|
111
|
+
${l}[${u}] = argument[${u}];
|
|
112
|
+
${u} += 1;
|
|
113
|
+
}
|
|
114
|
+
${o > 0 ? `if (0) { ${l}[${o - 1}] = argument${o - 1}; }\n` : ""}${f}`
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
function o(e) {
|
|
119
|
+
switch (e.k) {
|
|
120
|
+
case "assign": return e.target.k === "var" ? `an assignment to ${e.target.name}` : "an assignment";
|
|
121
|
+
case "call": return `a call to ${e.call.name}`;
|
|
122
|
+
case "exit": return e.value ? "a return" : "an exit";
|
|
123
|
+
default: return `a ${e.k} statement`;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function s(e, t) {
|
|
127
|
+
let n = t.at.at;
|
|
128
|
+
if (n === void 0) throw Error(`mod ${e}: cannot insert at ${o(t.at)} -- this game's engine could not place it, so there is nothing to insert around. Statements without a place include the parts of a \`for\` header and temporaries a decompiler invented.`);
|
|
129
|
+
if (t.place !== "before" && t.place !== "after" && t.place !== "instead") throw Error(`mod ${e}: an insertion's place is "before", "after" or "instead", not ${JSON.stringify(t.place)}`);
|
|
130
|
+
if (t.place === "after" && t.at.k === "exit") throw Error(`mod ${e}: nothing follows ${o(t.at)}, so there is no "after" to insert at. Use "before" to run something on the way out.`);
|
|
131
|
+
return n;
|
|
132
|
+
}
|
|
133
|
+
var c = function(e) {
|
|
134
|
+
let t = /* @__PURE__ */ new Map();
|
|
135
|
+
for (let n of e.inserts) {
|
|
136
|
+
let r = n.body({
|
|
137
|
+
engine: e.hostApi.target.engine,
|
|
138
|
+
send: e.send,
|
|
139
|
+
call: e.call
|
|
140
|
+
}), i = t.get(r);
|
|
141
|
+
i === void 0 && (i = `${e.prefix}__ins${t.size}`, t.set(r, i), e.hostApi.resource.create({
|
|
142
|
+
kind: "script",
|
|
143
|
+
name: i,
|
|
144
|
+
source: r
|
|
145
|
+
})), e.hostApi.resource.create({
|
|
146
|
+
kind: "insert",
|
|
147
|
+
at: n.at,
|
|
148
|
+
place: n.place,
|
|
149
|
+
call: i
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}, l = function(e) {
|
|
153
|
+
for (let t of e.scripts) {
|
|
154
|
+
let n = {};
|
|
155
|
+
(t.args ?? []).forEach((i, a) => {
|
|
156
|
+
if (!r.test(i)) throw Error(`mod ${e.identity.id}: script ${JSON.stringify(t.name)} has an argument called ${JSON.stringify(i)}, which is not a usable name`);
|
|
157
|
+
n[i] = `argument${a}`;
|
|
158
|
+
}), e.hostApi.resource.create({
|
|
159
|
+
kind: "script",
|
|
160
|
+
name: `${e.prefix}s_${t.name}`,
|
|
161
|
+
source: t.body({
|
|
162
|
+
engine: e.hostApi.target.engine,
|
|
163
|
+
a: n,
|
|
164
|
+
send: e.send,
|
|
165
|
+
call: e.call
|
|
166
|
+
})
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}, u = 15e3, d = 2e3, f = (e) => e[0] === 137 && e[1] === 80 ? {
|
|
170
|
+
extension: "png",
|
|
171
|
+
type: "image/png"
|
|
172
|
+
} : e[0] === 255 && e[1] === 216 ? {
|
|
173
|
+
extension: "jpg",
|
|
174
|
+
type: "image/jpeg"
|
|
175
|
+
} : e[0] === 66 && e[1] === 77 ? {
|
|
176
|
+
extension: "bmp",
|
|
177
|
+
type: "image/bmp"
|
|
178
|
+
} : null, p = class extends Error {
|
|
179
|
+
constructor() {
|
|
180
|
+
super("superseded by a newer load after the game restarted");
|
|
181
|
+
}
|
|
182
|
+
}, m = async function(e) {
|
|
183
|
+
if (typeof e != "string") return e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
184
|
+
if (e.startsWith("data:")) {
|
|
185
|
+
let t = e.indexOf(",");
|
|
186
|
+
if (t < 0) throw Error("that data: URI has no comma in it");
|
|
187
|
+
let n = e.slice(0, t), r = e.slice(t + 1);
|
|
188
|
+
if (!n.endsWith(";base64")) return new TextEncoder().encode(decodeURIComponent(r));
|
|
189
|
+
let i = atob(r), a = new Uint8Array(i.length);
|
|
190
|
+
for (let e = 0; e < i.length; e += 1) a[e] = i.charCodeAt(e);
|
|
191
|
+
return a;
|
|
192
|
+
}
|
|
193
|
+
let t = await fetch(e, { cache: "no-store" });
|
|
194
|
+
if (!t.ok) throw Error(`${e}: ${t.status}`);
|
|
195
|
+
return new Uint8Array(await t.arrayBuffer());
|
|
196
|
+
}, h = async function(e, t) {
|
|
197
|
+
if (typeof OffscreenCanvas == "function" && typeof createImageBitmap == "function") {
|
|
198
|
+
let n = await Promise.all(e.map((e, t) => {
|
|
199
|
+
let n = f(e);
|
|
200
|
+
if (!n) throw Error(`frame ${t + 1} is not a PNG, JPEG or BMP`);
|
|
201
|
+
return createImageBitmap(new Blob([e], { type: n.type }));
|
|
202
|
+
})), r = n[0];
|
|
203
|
+
for (let [e, t] of n.entries()) if (t.width !== r.width || t.height !== r.height) throw Error(`frame ${e + 1} is ${t.width}x${t.height} but frame 1 is ${r.width}x${r.height}; every frame of a sprite is the same size`);
|
|
204
|
+
let i = t ? Math.min(1, t / Math.max(r.width, r.height)) : 1, a = Math.max(1, Math.round(r.width * i)), o = Math.max(1, Math.round(r.height * i)), s = new OffscreenCanvas(a * n.length, o), c = s.getContext("2d");
|
|
205
|
+
return n.forEach((e, t) => {
|
|
206
|
+
c.drawImage(e, t * a, 0, a, o), e.close();
|
|
207
|
+
}), new Uint8Array(await (await s.convertToBlob({ type: "image/png" })).arrayBuffer());
|
|
208
|
+
}
|
|
209
|
+
throw Error("this host has no canvas to compose a sprite strip with");
|
|
210
|
+
}, g = async function(e, t, n) {
|
|
211
|
+
if (typeof OffscreenCanvas == "function" && typeof createImageBitmap == "function") {
|
|
212
|
+
let r = await createImageBitmap(new Blob([e], { type: t })), i = n ? Math.min(1, n / Math.max(r.width, r.height)) : 1, a = Math.max(1, Math.round(r.width * i)), o = Math.max(1, Math.round(r.height * i)), s = new OffscreenCanvas(a, o);
|
|
213
|
+
return s.getContext("2d").drawImage(r, 0, 0, a, o), r.close(), new Uint8Array(await (await s.convertToBlob({ type: "image/png" })).arrayBuffer());
|
|
214
|
+
}
|
|
215
|
+
throw Error("this host has no canvas to re-encode a picture with");
|
|
216
|
+
}, _ = (e) => e === "gm8" ? "temp_directory + \"\\\"" : "game_save_id", v = {
|
|
217
|
+
put: "__spr_put",
|
|
218
|
+
ok: "__spr_ok",
|
|
219
|
+
failed: "__spr_failed",
|
|
220
|
+
hello: "__spr_hello",
|
|
221
|
+
where: "__spr_where"
|
|
222
|
+
}, y = function(e) {
|
|
223
|
+
let t = null, n = "", r, i = new Promise((e) => {
|
|
224
|
+
r = e;
|
|
225
|
+
}), a = Promise.resolve(), o = new Promise((t) => {
|
|
226
|
+
e.hostApi.on("start", t);
|
|
227
|
+
}), s = async function(t, n) {
|
|
228
|
+
let r = Array.isArray(t) ? t : [t];
|
|
229
|
+
if (r.length === 0) throw Error("there is no picture in that list");
|
|
230
|
+
let i = await Promise.all(r.map((e) => m(e))), a = n.frames ?? 1;
|
|
231
|
+
if (i.length > 1) return {
|
|
232
|
+
bytes: await h(i, n.maxSize),
|
|
233
|
+
extension: "png",
|
|
234
|
+
frames: i.length * a
|
|
235
|
+
};
|
|
236
|
+
let o = i[0], s = f(o);
|
|
237
|
+
if (!s) throw Error("those bytes are not a PNG, JPEG or BMP");
|
|
238
|
+
let c = e.hostApi.target.engine === "gms" && s.extension !== "png", l = n.maxSize !== void 0;
|
|
239
|
+
return !c && !l ? {
|
|
240
|
+
bytes: o,
|
|
241
|
+
extension: s.extension,
|
|
242
|
+
frames: a
|
|
243
|
+
} : {
|
|
244
|
+
bytes: await g(o, s.type, n.maxSize),
|
|
245
|
+
extension: "png",
|
|
246
|
+
frames: a
|
|
247
|
+
};
|
|
248
|
+
}, c = function(n, r, i, a) {
|
|
249
|
+
return new Promise((o, s) => {
|
|
250
|
+
let c = (e, n) => {
|
|
251
|
+
clearTimeout(d), t = null, e ? s(e) : o(n);
|
|
252
|
+
};
|
|
253
|
+
t = {
|
|
254
|
+
slot: n,
|
|
255
|
+
done: (e) => c(null, e),
|
|
256
|
+
failed: (e) => c(Error(e)),
|
|
257
|
+
abandon: () => c(new p())
|
|
258
|
+
};
|
|
259
|
+
let l = r.origin ?? {
|
|
260
|
+
x: 0,
|
|
261
|
+
y: 0
|
|
262
|
+
};
|
|
263
|
+
e.sendInternal(v.put, `${n} ${i} ${l.x} ${l.y} ${a}`);
|
|
264
|
+
let d = setTimeout(() => c(/* @__PURE__ */ Error(`the game never answered about ${a}`)), u);
|
|
265
|
+
});
|
|
266
|
+
};
|
|
267
|
+
return {
|
|
268
|
+
loadSprite: function(t, r, l, u = () => !0) {
|
|
269
|
+
let f = async () => {
|
|
270
|
+
let a = await s(l, r);
|
|
271
|
+
if (await o, await Promise.race([i, new Promise((e) => {
|
|
272
|
+
setTimeout(e, d);
|
|
273
|
+
})]), !u()) throw new p();
|
|
274
|
+
let f = await e.hostApi.files.write(`${t}.${a.extension}`, a.bytes, n);
|
|
275
|
+
if (!u()) throw new p();
|
|
276
|
+
return c(t, r, a.frames, f);
|
|
277
|
+
}, m = a.then(f, f);
|
|
278
|
+
return a = m.catch(() => {}), m;
|
|
279
|
+
},
|
|
280
|
+
where: (e) => {
|
|
281
|
+
n = e, r();
|
|
282
|
+
},
|
|
283
|
+
done: (e, n) => {
|
|
284
|
+
t?.slot === e && t.done(n);
|
|
285
|
+
},
|
|
286
|
+
failed: (e, n) => {
|
|
287
|
+
t?.slot === e && t.failed(n);
|
|
288
|
+
},
|
|
289
|
+
abandon: () => t?.abandon()
|
|
290
|
+
};
|
|
291
|
+
}, b = function(e) {
|
|
292
|
+
let { hostApi: t, prefix: n, sprites: r, payload: i, sendInternalGml: a } = e;
|
|
293
|
+
if (r.length === 0) return {};
|
|
294
|
+
let o = (e) => `global.${n}__${e}`, s = `${n}__sprfield`, c = `${n}__sprrest`;
|
|
295
|
+
t.resource.create({
|
|
296
|
+
kind: "script",
|
|
297
|
+
name: s,
|
|
298
|
+
source: `${o("fs")} = argument0;
|
|
299
|
+
${o("fn")} = 1;
|
|
300
|
+
while (${o("fn")} < argument1) {
|
|
301
|
+
${o("fat")} = string_pos(" ", ${o("fs")});
|
|
302
|
+
if (${o("fat")} == 0) return "";
|
|
303
|
+
${o("fs")} = string_delete(${o("fs")}, 1, ${o("fat")});
|
|
304
|
+
${o("fn")} += 1;
|
|
305
|
+
}
|
|
306
|
+
${o("fat")} = string_pos(" ", ${o("fs")});
|
|
307
|
+
if (${o("fat")} > 0) ${o("fs")} = string_copy(${o("fs")}, 1, ${o("fat")} - 1);
|
|
308
|
+
return ${o("fs")};`
|
|
309
|
+
}), t.resource.create({
|
|
310
|
+
kind: "script",
|
|
311
|
+
name: c,
|
|
312
|
+
source: `${o("rs")} = argument0;
|
|
313
|
+
${o("rn")} = 1;
|
|
314
|
+
while (${o("rn")} < argument1) {
|
|
315
|
+
${o("rat")} = string_pos(" ", ${o("rs")});
|
|
316
|
+
if (${o("rat")} == 0) return "";
|
|
317
|
+
${o("rs")} = string_delete(${o("rs")}, 1, ${o("rat")});
|
|
318
|
+
${o("rn")} += 1;
|
|
319
|
+
}
|
|
320
|
+
return ${o("rs")};`
|
|
321
|
+
});
|
|
322
|
+
let l = t.target.engine === "gm8" ? `if (!file_exists(${o("sprfile")})) {
|
|
323
|
+
${a(v.failed, `${o("sprslot")} + " nothing at " + ${o("sprfile")}`)}
|
|
324
|
+
exit;
|
|
325
|
+
}` : "", u = r.map(({ name: e }) => `if (${o("sprslot")} == "${e}") {
|
|
326
|
+
if (is_real(global.${n}spr_${e}) && global.${n}spr_${e} >= 0) sprite_delete(global.${n}spr_${e});
|
|
327
|
+
global.${n}spr_${e} = ${o("sprnew")};
|
|
328
|
+
}`).join(" else ");
|
|
329
|
+
return { [v.put]: `${o("sprslot")} = ${s}(${i}, 1);
|
|
330
|
+
${o("sprimgs")} = real(${s}(${i}, 2));
|
|
331
|
+
${o("sprox")} = real(${s}(${i}, 3));
|
|
332
|
+
${o("sproy")} = real(${s}(${i}, 4));
|
|
333
|
+
${o("sprfile")} = ${c}(${i}, 5);
|
|
334
|
+
${l}
|
|
335
|
+
// is_real first: a game script named sprite_add shadows the builtin.
|
|
336
|
+
${o("sprnew")} = sprite_add(${o("sprfile")}, ${o("sprimgs")}, false, false, ${o("sprox")}, ${o("sproy")});
|
|
337
|
+
if (is_real(${o("sprnew")}) && ${o("sprnew")} >= 0) {
|
|
338
|
+
${u}
|
|
339
|
+
${a(v.ok, `${o("sprslot")} + " " + string(sprite_get_width(${o("sprnew")})) + " " + string(sprite_get_height(${o("sprnew")}))`)}
|
|
340
|
+
} else {
|
|
341
|
+
${a(v.failed, `${o("sprslot")} + " sprite_add answered " + string(${o("sprnew")})`)}
|
|
342
|
+
}` };
|
|
343
|
+
}, x = function(e) {
|
|
344
|
+
let { engine: t, prefix: n, sprites: r, sendInternalGml: i } = e;
|
|
345
|
+
return r.length === 0 ? "" : `
|
|
346
|
+
${r.map(({ name: e }) => `global.${n}spr_${e} = -1;`).join("\n")}
|
|
347
|
+
${i(v.where, _(t))}
|
|
348
|
+
${i(v.hello)}`;
|
|
349
|
+
}, S = function(e) {
|
|
350
|
+
let { identity: t, sprites: n, shown: r, spriteLoader: i, handlers: a } = e;
|
|
351
|
+
if (n.length === 0) return;
|
|
352
|
+
a.set(v.where, [(e) => i.where(e)]);
|
|
353
|
+
let o = 0;
|
|
354
|
+
a.set(v.hello, [() => {
|
|
355
|
+
if (o += 1, o === 1 || r.size === 0) return;
|
|
356
|
+
i.abandon();
|
|
357
|
+
let e = o, a = () => e === o;
|
|
358
|
+
for (let [e, o] of r) {
|
|
359
|
+
let r = n.find((t) => t.name === e)?.options ?? {};
|
|
360
|
+
i.loadSprite(e, r, o, a).catch((n) => {
|
|
361
|
+
n instanceof p || console.error(`[${t.id}] sprite ${JSON.stringify(e)} is gone:`, n);
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}]), a.set(v.ok, [(e) => {
|
|
365
|
+
let [t, n, r] = e.split(" ");
|
|
366
|
+
i.done(t ?? "", {
|
|
367
|
+
width: Number(n),
|
|
368
|
+
height: Number(r)
|
|
369
|
+
});
|
|
370
|
+
}]), a.set(v.failed, [(e) => {
|
|
371
|
+
let t = e.indexOf(" ");
|
|
372
|
+
i.failed(t < 0 ? e : e.slice(0, t), t < 0 ? "the game refused the picture" : e.slice(t + 1));
|
|
373
|
+
}]);
|
|
374
|
+
}, C = {
|
|
375
|
+
up: "ArrowUp",
|
|
376
|
+
down: "ArrowDown",
|
|
377
|
+
left: "ArrowLeft",
|
|
378
|
+
right: "ArrowRight",
|
|
379
|
+
confirm: "ShiftLeft",
|
|
380
|
+
cancel: "KeyZ",
|
|
381
|
+
retry: "KeyR"
|
|
382
|
+
}, w = [
|
|
383
|
+
"up",
|
|
384
|
+
"down",
|
|
385
|
+
"left",
|
|
386
|
+
"right",
|
|
387
|
+
"confirm",
|
|
388
|
+
"cancel",
|
|
389
|
+
"retry"
|
|
390
|
+
];
|
|
391
|
+
function T(e) {
|
|
392
|
+
return /^Pad(?:Button\d{1,2}|Axis\d{1,2}(?:Plus|Minus))$/u.test(e);
|
|
393
|
+
}
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/image/index.ts
|
|
396
|
+
var E = [
|
|
397
|
+
137,
|
|
398
|
+
80,
|
|
399
|
+
78,
|
|
400
|
+
71,
|
|
401
|
+
13,
|
|
402
|
+
10,
|
|
403
|
+
26,
|
|
404
|
+
10
|
|
405
|
+
], D = function(e) {
|
|
406
|
+
if (e.length < 24 || E.some((t, n) => e[n] !== t)) throw Error("that is not a PNG");
|
|
407
|
+
let t = (t) => (e[t] << 24 | e[t + 1] << 16 | e[t + 2] << 8 | e[t + 3]) >>> 0;
|
|
408
|
+
return {
|
|
409
|
+
width: t(16),
|
|
410
|
+
height: t(20)
|
|
411
|
+
};
|
|
412
|
+
}, O = function(e, t) {
|
|
413
|
+
if (e.width <= 0 || e.height <= 0) throw Error("a slice needs a positive size");
|
|
414
|
+
if (e.x < 0 || e.y < 0 || e.x + e.width > t.width || e.y + e.height > t.height) throw Error(`slice ${e.width}x${e.height} at ${e.x},${e.y} falls outside a ${t.width}x${t.height} picture`);
|
|
415
|
+
}, k = async function(e, t) {
|
|
416
|
+
if (O(t, D(e)), typeof OffscreenCanvas == "function" && typeof createImageBitmap == "function") {
|
|
417
|
+
let n = f(e);
|
|
418
|
+
if (!n) throw Error("that is not a PNG, JPEG or BMP");
|
|
419
|
+
let r = await createImageBitmap(new Blob([e], { type: n.type }));
|
|
420
|
+
try {
|
|
421
|
+
let e = new OffscreenCanvas(t.width, t.height), n = e.getContext("2d");
|
|
422
|
+
if (!n) throw Error("no 2d context");
|
|
423
|
+
n.drawImage(r, t.x, t.y, t.width, t.height, 0, 0, t.width, t.height);
|
|
424
|
+
let i = await e.convertToBlob({ type: "image/png" });
|
|
425
|
+
return new Uint8Array(await i.arrayBuffer());
|
|
426
|
+
} finally {
|
|
427
|
+
r.close();
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
throw Error("this host has no canvas to slice a picture with");
|
|
431
|
+
};
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/decompiled-gml.ts
|
|
434
|
+
function* A(e) {
|
|
435
|
+
for (let t of e) switch (yield t, t.k) {
|
|
436
|
+
case "if":
|
|
437
|
+
yield* A(t.then), yield* A(t.else);
|
|
438
|
+
break;
|
|
439
|
+
case "with":
|
|
440
|
+
case "loop":
|
|
441
|
+
yield* A(t.body);
|
|
442
|
+
break;
|
|
443
|
+
case "switch": for (let e of t.bodies) yield* A(e);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
//#endregion
|
|
447
|
+
//#region src/keyboard/index.ts
|
|
448
|
+
var j = {
|
|
449
|
+
Backspace: 8,
|
|
450
|
+
Tab: 9,
|
|
451
|
+
Enter: 13,
|
|
452
|
+
NumpadEnter: 13,
|
|
453
|
+
ShiftLeft: 16,
|
|
454
|
+
ShiftRight: 16,
|
|
455
|
+
ControlLeft: 17,
|
|
456
|
+
ControlRight: 17,
|
|
457
|
+
AltLeft: 18,
|
|
458
|
+
AltRight: 18,
|
|
459
|
+
Pause: 19,
|
|
460
|
+
CapsLock: 20,
|
|
461
|
+
Escape: 27,
|
|
462
|
+
Space: 32,
|
|
463
|
+
PageUp: 33,
|
|
464
|
+
PageDown: 34,
|
|
465
|
+
End: 35,
|
|
466
|
+
Home: 36,
|
|
467
|
+
ArrowLeft: 37,
|
|
468
|
+
ArrowUp: 38,
|
|
469
|
+
ArrowRight: 39,
|
|
470
|
+
ArrowDown: 40,
|
|
471
|
+
Insert: 45,
|
|
472
|
+
Delete: 46,
|
|
473
|
+
NumpadMultiply: 106,
|
|
474
|
+
NumpadAdd: 107,
|
|
475
|
+
NumpadSubtract: 109,
|
|
476
|
+
NumpadDecimal: 110,
|
|
477
|
+
NumpadDivide: 111,
|
|
478
|
+
Semicolon: 186,
|
|
479
|
+
Equal: 187,
|
|
480
|
+
Comma: 188,
|
|
481
|
+
Minus: 189,
|
|
482
|
+
Period: 190,
|
|
483
|
+
Slash: 191,
|
|
484
|
+
Backquote: 192,
|
|
485
|
+
BracketLeft: 219,
|
|
486
|
+
Backslash: 220,
|
|
487
|
+
BracketRight: 221,
|
|
488
|
+
Quote: 222
|
|
489
|
+
}, M = function(e) {
|
|
490
|
+
if (!e) return 0;
|
|
491
|
+
let t = j[e];
|
|
492
|
+
if (t !== void 0) return t;
|
|
493
|
+
if (e.length === 4 && e.startsWith("Key")) {
|
|
494
|
+
let t = e.charCodeAt(3);
|
|
495
|
+
if (t >= 65 && t <= 90) return t;
|
|
496
|
+
}
|
|
497
|
+
if (e.length === 6 && e.startsWith("Digit")) {
|
|
498
|
+
let t = e.charCodeAt(5);
|
|
499
|
+
if (t >= 48 && t <= 57) return t;
|
|
500
|
+
}
|
|
501
|
+
if (e.length === 7 && e.startsWith("Numpad")) {
|
|
502
|
+
let t = e.charCodeAt(6);
|
|
503
|
+
if (t >= 48 && t <= 57) return 96 + (t - 48);
|
|
504
|
+
}
|
|
505
|
+
let n = /^F(\d{1,2})$/u.exec(e);
|
|
506
|
+
if (n) {
|
|
507
|
+
let e = Number(n[1]);
|
|
508
|
+
if (e >= 1 && e <= 24) return 111 + e;
|
|
509
|
+
}
|
|
510
|
+
return 0;
|
|
511
|
+
}, N = function(e) {
|
|
512
|
+
let t = (e.split(/[/.]/u).pop() ?? e).replaceAll(/[^A-Za-z0-9]/gu, "").slice(0, 12), n = 2166136261;
|
|
513
|
+
for (let t = 0; t < e.length; t += 1) n = Math.imul(n ^ e.charCodeAt(t), 16777619);
|
|
514
|
+
return `m${t}_${((n >>> 0) % 65536).toString(16).padStart(4, "0")}_`;
|
|
515
|
+
}, P = function(t) {
|
|
516
|
+
return { activate(o) {
|
|
517
|
+
let u = o.identity, d = N(u.id), f = [], p = [], m = [], h = [], g = [], _ = /* @__PURE__ */ new Map(), v = !0, C = (e) => {
|
|
518
|
+
if (!n.test(e)) throw Error(`mod ${u.id}: ${JSON.stringify(e)} is not a usable event name (letters, digits, - and _, starting with a letter)`);
|
|
519
|
+
return e.replaceAll("-", "_");
|
|
520
|
+
}, w = (e) => `${d}__${e}`, T = (e) => {
|
|
521
|
+
let t = {};
|
|
522
|
+
for (let n of e.vars ?? []) {
|
|
523
|
+
if (!r.test(n)) throw Error(`mod ${u.id}: ${JSON.stringify(n)} is not a usable variable name (letters, digits and _, starting with a letter)`);
|
|
524
|
+
t[n] = `${d}v_${n}`;
|
|
525
|
+
}
|
|
526
|
+
return t;
|
|
527
|
+
}, E = (e) => `global.${d}q_${e}`, D = (e, t = "") => o.send(`${e} ${t}`), O = (e, t) => o.gml.send(t ? `"${e} " + (${t})` : `"${e} "`), k = (e, t) => O(C(e), t), A = (e, ...t) => {
|
|
528
|
+
if (!p.some((t) => t.name === e)) throw Error(`mod ${u.id}: call(${JSON.stringify(e)}) names a script this mod never declared. It has: ${p.map((e) => e.name).join(", ") || "none"}`);
|
|
529
|
+
return `${d}s_${e}(${t.join(", ")})`;
|
|
530
|
+
}, j = (e) => ({
|
|
531
|
+
engine: o.target.engine,
|
|
532
|
+
v: T(e),
|
|
533
|
+
send: k,
|
|
534
|
+
call: A
|
|
535
|
+
}), M = y({
|
|
536
|
+
hostApi: o,
|
|
537
|
+
identity: u,
|
|
538
|
+
sendInternal: D
|
|
539
|
+
}), P = /* @__PURE__ */ new Map(), F = o.game;
|
|
540
|
+
t({
|
|
541
|
+
engine: o.target.engine,
|
|
542
|
+
call: A,
|
|
543
|
+
ui: o.ui,
|
|
544
|
+
getPlayer: () => o.getPlayer(),
|
|
545
|
+
onPlayerChange: (e) => o.on("player", e),
|
|
546
|
+
content: F,
|
|
547
|
+
resource: {
|
|
548
|
+
object: { create(e) {
|
|
549
|
+
if (!v) throw Error(`mod ${u.id}: objects can only be declared while the mod is built`);
|
|
550
|
+
f.push(e);
|
|
551
|
+
} },
|
|
552
|
+
script: {
|
|
553
|
+
create(e) {
|
|
554
|
+
if (!v) throw Error(`mod ${u.id}: scripts can only be declared while the mod is built`);
|
|
555
|
+
if (!r.test(e.name)) throw Error(`mod ${u.id}: ${JSON.stringify(e.name)} is not a usable script name (letters, digits and _, starting with a letter)`);
|
|
556
|
+
if (p.some((t) => t.name === e.name)) throw Error(`mod ${u.id}: two scripts are called ${JSON.stringify(e.name)}`);
|
|
557
|
+
p.push(e);
|
|
558
|
+
},
|
|
559
|
+
hook(e, t) {
|
|
560
|
+
if (!v) throw Error(`mod ${u.id}: hooks can only be declared while the mod is built`);
|
|
561
|
+
h.push({
|
|
562
|
+
script: e,
|
|
563
|
+
wrap: t
|
|
564
|
+
});
|
|
565
|
+
},
|
|
566
|
+
insert(e) {
|
|
567
|
+
if (!v) throw Error(`mod ${u.id}: insertions can only be declared while the mod is built`);
|
|
568
|
+
g.push({
|
|
569
|
+
at: s(u.id, e),
|
|
570
|
+
place: e.place,
|
|
571
|
+
body: e.body
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
},
|
|
575
|
+
sprite: { create(e, t = {}) {
|
|
576
|
+
if (!v) throw Error(`mod ${u.id}: sprites can only be declared while the mod is built`);
|
|
577
|
+
if (!r.test(e)) throw Error(`mod ${u.id}: ${JSON.stringify(e)} is not a usable sprite name (letters, digits and _, starting with a letter)`);
|
|
578
|
+
if (m.some((t) => t.name === e)) throw Error(`mod ${u.id}: two sprites are called ${JSON.stringify(e)}`);
|
|
579
|
+
return m.push({
|
|
580
|
+
name: e,
|
|
581
|
+
options: t
|
|
582
|
+
}), {
|
|
583
|
+
id: `global.${d}spr_${e}`,
|
|
584
|
+
load: (n) => (P.set(e, n), M.loadSprite(e, t, n))
|
|
585
|
+
};
|
|
586
|
+
} }
|
|
587
|
+
},
|
|
588
|
+
on(e, t) {
|
|
589
|
+
let n = C(e), r = _.get(n);
|
|
590
|
+
r ? r.push(t) : _.set(n, [t]);
|
|
591
|
+
},
|
|
592
|
+
onStart(e) {
|
|
593
|
+
o.on("start", e);
|
|
594
|
+
},
|
|
595
|
+
scratchPath(e) {
|
|
596
|
+
if (!i.test(e)) throw Error(`mod ${u.id}: ${JSON.stringify(e)} is not a usable scratch file name (letters, digits, _ . and -)`);
|
|
597
|
+
return o.target.engine === "gm8" ? `temp_directory + "\\${d}${e}"` : `"${d}${e}"`;
|
|
598
|
+
},
|
|
599
|
+
send(e, t = "") {
|
|
600
|
+
o.send(`${C(e)} ${t}`);
|
|
601
|
+
}
|
|
602
|
+
}), v = !1, c({
|
|
603
|
+
identity: u,
|
|
604
|
+
inserts: g,
|
|
605
|
+
prefix: d,
|
|
606
|
+
hostApi: o,
|
|
607
|
+
send: k,
|
|
608
|
+
call: A
|
|
609
|
+
}), l({
|
|
610
|
+
identity: u,
|
|
611
|
+
scripts: p,
|
|
612
|
+
hostApi: o,
|
|
613
|
+
prefix: d,
|
|
614
|
+
send: k,
|
|
615
|
+
call: A
|
|
616
|
+
}), a({
|
|
617
|
+
identity: u,
|
|
618
|
+
hooks: h,
|
|
619
|
+
content: F,
|
|
620
|
+
hostApi: o,
|
|
621
|
+
prefix: d,
|
|
622
|
+
send: k,
|
|
623
|
+
call: A
|
|
624
|
+
}), e({
|
|
625
|
+
identity: u,
|
|
626
|
+
hostApi: o,
|
|
627
|
+
prefix: d,
|
|
628
|
+
objects: f,
|
|
629
|
+
internalReceive: b({
|
|
630
|
+
hostApi: o,
|
|
631
|
+
prefix: d,
|
|
632
|
+
sprites: m,
|
|
633
|
+
payload: w("pl"),
|
|
634
|
+
sendInternalGml: O
|
|
635
|
+
}),
|
|
636
|
+
internalCreate: x({
|
|
637
|
+
engine: o.target.engine,
|
|
638
|
+
prefix: d,
|
|
639
|
+
sprites: m,
|
|
640
|
+
sendInternalGml: O
|
|
641
|
+
}),
|
|
642
|
+
normalizeEventName: C,
|
|
643
|
+
context: j,
|
|
644
|
+
queue: E,
|
|
645
|
+
scratch: w
|
|
646
|
+
}), S({
|
|
647
|
+
identity: u,
|
|
648
|
+
sprites: m,
|
|
649
|
+
shown: P,
|
|
650
|
+
spriteLoader: M,
|
|
651
|
+
handlers: _
|
|
652
|
+
}), o.on("message", (e) => {
|
|
653
|
+
let t = e.indexOf(" "), n = t < 0 ? e : e.slice(0, t), r = t < 0 ? "" : e.slice(t + 1), i = _.get(n);
|
|
654
|
+
if (i) for (let e of i) new Promise((t) => {
|
|
655
|
+
t(e(r));
|
|
656
|
+
}).catch((e) => {
|
|
657
|
+
console.error(`[${u.id}] handling ${n} failed:`, e);
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
} };
|
|
661
|
+
};
|
|
662
|
+
//#endregion
|
|
663
|
+
export { C as CANONICAL_CONTROL_KEYS, w as CONTROL_ACTIONS, P as createMod, M as gameMakerKey, t as highestArgument, T as isPadBinding, D as pngSize, k as sliceImage, A as walk };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a rebindable key into the number GameMaker checks.
|
|
3
|
+
*
|
|
4
|
+
* A `keybind` control hands you a `KeyboardEvent.code` -- `"KeyH"`, `"ArrowLeft"`, `"Space"` -- which
|
|
5
|
+
* names the *physical* key, so a binding made on an AZERTY keyboard stays under the same finger
|
|
6
|
+
* rather than following the letter printed on it. GML wants a number: the Windows virtual-key code,
|
|
7
|
+
* which is what `vk_left` is and what `ord("H")` comes out as.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const jump = mod.ui.state("KeyZ", { persist: "jump" });
|
|
11
|
+
*
|
|
12
|
+
* mod.resource.object.create({
|
|
13
|
+
* name: "mymod",
|
|
14
|
+
* vars: ["jumpKey"],
|
|
15
|
+
* events: {
|
|
16
|
+
* create: ({ v }) => `${v.jumpKey} = ${gameMakerKey("KeyZ")};`,
|
|
17
|
+
* step: ({ v, send }) => `
|
|
18
|
+
* if (${v.jumpKey} > 0 && keyboard_check_pressed(${v.jumpKey})) ${send("jump")}
|
|
19
|
+
* `,
|
|
20
|
+
* },
|
|
21
|
+
* receive: { key: ({ v, payload }) => `${v.jumpKey} = real(${payload});` },
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* const push = () => mod.send("key", String(gameMakerKey(jump.value)));
|
|
25
|
+
* mod.onStart(push);
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* The default in `create` matters: a game can run for a moment before the panel's first push
|
|
29
|
+
* arrives, and a key of 0 matches nothing.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* The GameMaker key code for a `KeyboardEvent.code`, or `0` when there is no sensible one.
|
|
33
|
+
*
|
|
34
|
+
* `0` rather than a throw, and rather than a guess: an unbound control and a key GameMaker has no
|
|
35
|
+
* number for should behave the same way -- nothing happens -- and neither is a reason to take a
|
|
36
|
+
* running game down. Guard with `> 0` in the GML, since `keyboard_check_pressed(0)` is not reliably
|
|
37
|
+
* false on every runner.
|
|
38
|
+
*
|
|
39
|
+
* Left and right modifiers collapse onto one code, which is what GameMaker offers: `vk_shift` is
|
|
40
|
+
* either shift. A mod that needs to tell them apart cannot, here or in GML.
|
|
41
|
+
*/
|
|
42
|
+
export declare const gameMakerKey: (code: string) => number;
|