lantern-engine 0.0.0-stage → 0.4.0
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/CHANGELOG.md +101 -0
- package/LICENSE +21 -0
- package/README.md +113 -2
- package/dist/assets/takeCleanerWorker-DTcI_Jqr.js +31 -0
- package/dist/assets/takeCleanerWorker-DTcI_Jqr.js.map +1 -0
- package/dist/constants-CjYVdFid.js +252 -0
- package/dist/constants-CjYVdFid.js.map +1 -0
- package/dist/lantern-engine.js +3473 -0
- package/dist/lantern-engine.js.map +1 -0
- package/dist/pixel.js +1404 -0
- package/dist/pixel.js.map +1 -0
- package/dist/types/anim/Animator.d.ts +50 -0
- package/dist/types/anim/Animator.d.ts.map +1 -0
- package/dist/types/anim/animationSystem.d.ts +13 -0
- package/dist/types/anim/animationSystem.d.ts.map +1 -0
- package/dist/types/assets/AssetLoader.d.ts +85 -0
- package/dist/types/assets/AssetLoader.d.ts.map +1 -0
- package/dist/types/audio/MusicPlayer.d.ts +57 -0
- package/dist/types/audio/MusicPlayer.d.ts.map +1 -0
- package/dist/types/audio/SoundEngine.d.ts +42 -0
- package/dist/types/audio/SoundEngine.d.ts.map +1 -0
- package/dist/types/audio/cleanTake.d.ts +3 -0
- package/dist/types/audio/cleanTake.d.ts.map +1 -0
- package/dist/types/audio/sampleBank.d.ts +27 -0
- package/dist/types/audio/sampleBank.d.ts.map +1 -0
- package/dist/types/audio/soundTable.d.ts +14 -0
- package/dist/types/audio/soundTable.d.ts.map +1 -0
- package/dist/types/audio/synth.d.ts +34 -0
- package/dist/types/audio/synth.d.ts.map +1 -0
- package/dist/types/audio/takeCleanerWorker.d.ts +2 -0
- package/dist/types/audio/takeCleanerWorker.d.ts.map +1 -0
- package/dist/types/core/BitmapLabel.d.ts +26 -0
- package/dist/types/core/BitmapLabel.d.ts.map +1 -0
- package/dist/types/core/Camera.d.ts +90 -0
- package/dist/types/core/Camera.d.ts.map +1 -0
- package/dist/types/core/Clock.d.ts +11 -0
- package/dist/types/core/Clock.d.ts.map +1 -0
- package/dist/types/core/Graphics.d.ts +37 -0
- package/dist/types/core/Graphics.d.ts.map +1 -0
- package/dist/types/core/Group.d.ts +15 -0
- package/dist/types/core/Group.d.ts.map +1 -0
- package/dist/types/core/Image.d.ts +25 -0
- package/dist/types/core/Image.d.ts.map +1 -0
- package/dist/types/core/ObjectFactory.d.ts +34 -0
- package/dist/types/core/ObjectFactory.d.ts.map +1 -0
- package/dist/types/core/Pointer.d.ts +27 -0
- package/dist/types/core/Pointer.d.ts.map +1 -0
- package/dist/types/core/Rectangle.d.ts +26 -0
- package/dist/types/core/Rectangle.d.ts.map +1 -0
- package/dist/types/core/Stage.d.ts +58 -0
- package/dist/types/core/Stage.d.ts.map +1 -0
- package/dist/types/core/Text.d.ts +22 -0
- package/dist/types/core/Text.d.ts.map +1 -0
- package/dist/types/core/TextureRegistry.d.ts +51 -0
- package/dist/types/core/TextureRegistry.d.ts.map +1 -0
- package/dist/types/core/Tweener.d.ts +53 -0
- package/dist/types/core/Tweener.d.ts.map +1 -0
- package/dist/types/core/atlas.d.ts +16 -0
- package/dist/types/core/atlas.d.ts.map +1 -0
- package/dist/types/core/atlasPlan.d.ts +34 -0
- package/dist/types/core/atlasPlan.d.ts.map +1 -0
- package/dist/types/core/eases.d.ts +3 -0
- package/dist/types/core/eases.d.ts.map +1 -0
- package/dist/types/core/gameObject.d.ts +42 -0
- package/dist/types/core/gameObject.d.ts.map +1 -0
- package/dist/types/core/pixiPatches.d.ts +9 -0
- package/dist/types/core/pixiPatches.d.ts.map +1 -0
- package/dist/types/core/types.d.ts +4 -0
- package/dist/types/core/types.d.ts.map +1 -0
- package/dist/types/ecs/SparseSet.d.ts +25 -0
- package/dist/types/ecs/SparseSet.d.ts.map +1 -0
- package/dist/types/ecs/World.d.ts +133 -0
- package/dist/types/ecs/World.d.ts.map +1 -0
- package/dist/types/ecs/fields.d.ts +34 -0
- package/dist/types/ecs/fields.d.ts.map +1 -0
- package/dist/types/engine/Engine.d.ts +80 -0
- package/dist/types/engine/Engine.d.ts.map +1 -0
- package/dist/types/engine/FixedLoop.d.ts +32 -0
- package/dist/types/engine/FixedLoop.d.ts.map +1 -0
- package/dist/types/engine/Scene.d.ts +37 -0
- package/dist/types/engine/Scene.d.ts.map +1 -0
- package/dist/types/engine/SceneManager.d.ts +31 -0
- package/dist/types/engine/SceneManager.d.ts.map +1 -0
- package/dist/types/events/EventBus.d.ts +20 -0
- package/dist/types/events/EventBus.d.ts.map +1 -0
- package/dist/types/fx/hitStop.d.ts +20 -0
- package/dist/types/fx/hitStop.d.ts.map +1 -0
- package/dist/types/fx/viewCull.d.ts +14 -0
- package/dist/types/fx/viewCull.d.ts.map +1 -0
- package/dist/types/index.d.ts +68 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/input/Actions.d.ts +75 -0
- package/dist/types/input/Actions.d.ts.map +1 -0
- package/dist/types/input/Keyboard.d.ts +25 -0
- package/dist/types/input/Keyboard.d.ts.map +1 -0
- package/dist/types/input/aimAxis.d.ts +9 -0
- package/dist/types/input/aimAxis.d.ts.map +1 -0
- package/dist/types/input/longPress.d.ts +21 -0
- package/dist/types/input/longPress.d.ts.map +1 -0
- package/dist/types/input/stickAxis.d.ts +26 -0
- package/dist/types/input/stickAxis.d.ts.map +1 -0
- package/dist/types/input/touchDetect.d.ts +18 -0
- package/dist/types/input/touchDetect.d.ts.map +1 -0
- package/dist/types/light/LightLayer.d.ts +65 -0
- package/dist/types/light/LightLayer.d.ts.map +1 -0
- package/dist/types/net/Connection.d.ts +66 -0
- package/dist/types/net/Connection.d.ts.map +1 -0
- package/dist/types/net/InterpolationBuffer.d.ts +36 -0
- package/dist/types/net/InterpolationBuffer.d.ts.map +1 -0
- package/dist/types/net/PredictedMover.d.ts +43 -0
- package/dist/types/net/PredictedMover.d.ts.map +1 -0
- package/dist/types/net/Room.d.ts +69 -0
- package/dist/types/net/Room.d.ts.map +1 -0
- package/dist/types/net/RoomHost.d.ts +74 -0
- package/dist/types/net/RoomHost.d.ts.map +1 -0
- package/dist/types/net/cadence.d.ts +22 -0
- package/dist/types/net/cadence.d.ts.map +1 -0
- package/dist/types/net/constants.d.ts +24 -0
- package/dist/types/net/constants.d.ts.map +1 -0
- package/dist/types/net/movement.d.ts +50 -0
- package/dist/types/net/movement.d.ts.map +1 -0
- package/dist/types/net/protocol.d.ts +59 -0
- package/dist/types/net/protocol.d.ts.map +1 -0
- package/dist/types/net/serverClock.d.ts +14 -0
- package/dist/types/net/serverClock.d.ts.map +1 -0
- package/dist/types/net/snapshotCodec.d.ts +55 -0
- package/dist/types/net/snapshotCodec.d.ts.map +1 -0
- package/dist/types/pixel/Darkness.d.ts +78 -0
- package/dist/types/pixel/Darkness.d.ts.map +1 -0
- package/dist/types/pixel/Evaporation.d.ts +30 -0
- package/dist/types/pixel/Evaporation.d.ts.map +1 -0
- package/dist/types/pixel/PixelLayer.d.ts +85 -0
- package/dist/types/pixel/PixelLayer.d.ts.map +1 -0
- package/dist/types/pixel/index.d.ts +22 -0
- package/dist/types/pixel/index.d.ts.map +1 -0
- package/dist/types/pixel/lights.d.ts +34 -0
- package/dist/types/pixel/lights.d.ts.map +1 -0
- package/dist/types/pixel/palette.d.ts +54 -0
- package/dist/types/pixel/palette.d.ts.map +1 -0
- package/dist/types/pixel/pixel.d.ts +80 -0
- package/dist/types/pixel/pixel.d.ts.map +1 -0
- package/dist/types/pixel/pixelPaint.d.ts +43 -0
- package/dist/types/pixel/pixelPaint.d.ts.map +1 -0
- package/dist/types/pixel/pixelTone.d.ts +49 -0
- package/dist/types/pixel/pixelTone.d.ts.map +1 -0
- package/dist/types/pixel/propKit.d.ts +26 -0
- package/dist/types/pixel/propKit.d.ts.map +1 -0
- package/dist/types/pixel/ramp.d.ts +31 -0
- package/dist/types/pixel/ramp.d.ts.map +1 -0
- package/dist/types/pixel/selout.d.ts +3 -0
- package/dist/types/pixel/selout.d.ts.map +1 -0
- package/dist/types/pixel/spritePixels.d.ts +29 -0
- package/dist/types/pixel/spritePixels.d.ts.map +1 -0
- package/dist/types/platform/touch.d.ts +5 -0
- package/dist/types/platform/touch.d.ts.map +1 -0
- package/dist/types/rig/PosePlayer.d.ts +64 -0
- package/dist/types/rig/PosePlayer.d.ts.map +1 -0
- package/dist/types/rig/RigView.d.ts +68 -0
- package/dist/types/rig/RigView.d.ts.map +1 -0
- package/dist/types/rig/Skeleton.d.ts +14 -0
- package/dist/types/rig/Skeleton.d.ts.map +1 -0
- package/dist/types/rig/humanoid.d.ts +4 -0
- package/dist/types/rig/humanoid.d.ts.map +1 -0
- package/dist/types/rig/humanoidPoses.d.ts +117 -0
- package/dist/types/rig/humanoidPoses.d.ts.map +1 -0
- package/dist/types/rig/poseMath.d.ts +14 -0
- package/dist/types/rig/poseMath.d.ts.map +1 -0
- package/dist/types/rig/rigTypes.d.ts +82 -0
- package/dist/types/rig/rigTypes.d.ts.map +1 -0
- package/dist/types/settings.d.ts +25 -0
- package/dist/types/settings.d.ts.map +1 -0
- package/dist/types/tilemap/TilemapView.d.ts +42 -0
- package/dist/types/tilemap/TilemapView.d.ts.map +1 -0
- package/dist/types/tilemap/collision.d.ts +16 -0
- package/dist/types/tilemap/collision.d.ts.map +1 -0
- package/dist/types/tilemap/tiled.d.ts +104 -0
- package/dist/types/tilemap/tiled.d.ts.map +1 -0
- package/package.json +82 -4
|
@@ -0,0 +1,3473 @@
|
|
|
1
|
+
import { Graphics as Lt, Container as M, DynamicBitmapFont as ee, BitmapFont as se, BitmapText as ie, Sprite as R, Text as ne, CanvasSource as re, Texture as C, Rectangle as oe, TextureSource as ae, Application as he, RenderTexture as le } from "pixi.js";
|
|
2
|
+
import { G as V, a as ce, i as ue, p as de, B as fe, b as pe, C as tt, I as me, c as gt, e as q } from "./constants-CjYVdFid.js";
|
|
3
|
+
import { d as Hr, T as Ir, s as _r } from "./constants-CjYVdFid.js";
|
|
4
|
+
class Ht extends V(M) {
|
|
5
|
+
constructor(t, e, s, n = 1) {
|
|
6
|
+
super(), this.w = t, this.h = e, this.color = s, this.fillAlpha = n, this.addChild(this.g), this.redraw();
|
|
7
|
+
}
|
|
8
|
+
w;
|
|
9
|
+
h;
|
|
10
|
+
color;
|
|
11
|
+
fillAlpha;
|
|
12
|
+
g = new Lt();
|
|
13
|
+
ox = 0.5;
|
|
14
|
+
oy = 0.5;
|
|
15
|
+
get originX() {
|
|
16
|
+
return this.ox;
|
|
17
|
+
}
|
|
18
|
+
get originY() {
|
|
19
|
+
return this.oy;
|
|
20
|
+
}
|
|
21
|
+
get rectWidth() {
|
|
22
|
+
return this.w;
|
|
23
|
+
}
|
|
24
|
+
get rectHeight() {
|
|
25
|
+
return this.h;
|
|
26
|
+
}
|
|
27
|
+
get fillColor() {
|
|
28
|
+
return this.color;
|
|
29
|
+
}
|
|
30
|
+
get fillOpacity() {
|
|
31
|
+
return this.fillAlpha;
|
|
32
|
+
}
|
|
33
|
+
setOrigin(t = 0.5, e = t) {
|
|
34
|
+
return this.ox = t, this.oy = e, this.redraw();
|
|
35
|
+
}
|
|
36
|
+
setFillStyle(t, e = 1) {
|
|
37
|
+
return this.color = t, this.fillAlpha = e, this.redraw();
|
|
38
|
+
}
|
|
39
|
+
setDisplaySize(t, e) {
|
|
40
|
+
return this.setScale(t / this.w, e / this.h);
|
|
41
|
+
}
|
|
42
|
+
resize(t, e) {
|
|
43
|
+
return this.w = t, this.h = e, this.redraw();
|
|
44
|
+
}
|
|
45
|
+
redraw() {
|
|
46
|
+
return this.g.clear().rect(-this.w * this.ox, -this.h * this.oy, this.w, this.h).fill({ color: this.color, alpha: this.fillAlpha }), this;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
class ge {
|
|
50
|
+
constructor(t, e) {
|
|
51
|
+
this.world = t, this.screen = e;
|
|
52
|
+
}
|
|
53
|
+
world;
|
|
54
|
+
screen;
|
|
55
|
+
zoom = 1;
|
|
56
|
+
/** Backing pixels per screen pixel (the renderer's resolution, `zoomResolution`): what `snap` rounds to. */
|
|
57
|
+
resolution = 1;
|
|
58
|
+
/** Lands the view on whole backing pixels (pixel art); off, the world moves smoothly between them. */
|
|
59
|
+
roundPixels = !1;
|
|
60
|
+
scrollX = 0;
|
|
61
|
+
scrollY = 0;
|
|
62
|
+
width = 0;
|
|
63
|
+
height = 0;
|
|
64
|
+
bounds = null;
|
|
65
|
+
shakeUntil = 0;
|
|
66
|
+
shakeMs = 1;
|
|
67
|
+
shakeAngle = void 0;
|
|
68
|
+
shakeIntensity = 0;
|
|
69
|
+
flashRect = null;
|
|
70
|
+
flashStart = 0;
|
|
71
|
+
flashMs = 1;
|
|
72
|
+
flashPeak = 1;
|
|
73
|
+
/** Screen-layer containers laid over the world with its exact transform, shake included (see `follow`). */
|
|
74
|
+
followers = /* @__PURE__ */ new Set();
|
|
75
|
+
target = null;
|
|
76
|
+
trackOpts = { lerp: 1, deadzoneWidth: 0, deadzoneHeight: 0, offsetX: 0, offsetY: 0 };
|
|
77
|
+
lastApply = -1;
|
|
78
|
+
get worldView() {
|
|
79
|
+
const t = this.width / this.zoom, e = this.height / this.zoom;
|
|
80
|
+
return { x: this.scrollX, y: this.scrollY, width: t, height: e, right: this.scrollX + t, bottom: this.scrollY + e };
|
|
81
|
+
}
|
|
82
|
+
setZoom(t) {
|
|
83
|
+
return this.zoom = t, this;
|
|
84
|
+
}
|
|
85
|
+
/** A world coordinate snapped to the nearest backing pixel: one screen pixel, or a half at ×1.5. */
|
|
86
|
+
snap(t) {
|
|
87
|
+
const e = this.zoom * this.resolution;
|
|
88
|
+
return Math.round(t * e) / e;
|
|
89
|
+
}
|
|
90
|
+
setBounds(t, e, s, n) {
|
|
91
|
+
return this.bounds = { x: t, y: e, width: s, height: n }, this;
|
|
92
|
+
}
|
|
93
|
+
centerOn(t, e) {
|
|
94
|
+
return this.scrollX = t - this.width / this.zoom / 2, this.scrollY = e - this.height / this.zoom / 2, this.clamp(), this;
|
|
95
|
+
}
|
|
96
|
+
setScroll(t, e) {
|
|
97
|
+
return this.scrollX = t, this.scrollY = e, this.clamp(), this;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Screen shake: `intensity` is a fraction of the screen size, like before. With an `angle` (the way a blow travelled)
|
|
101
|
+
* the shake runs back and forth along it instead of at random, so a hit is felt coming from somewhere.
|
|
102
|
+
*/
|
|
103
|
+
shake(t, e, s) {
|
|
104
|
+
const n = performance.now();
|
|
105
|
+
n < this.shakeUntil && e < this.shakeIntensity || (this.shakeUntil = n + t, this.shakeMs = t, this.shakeIntensity = e, this.shakeAngle = s);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Keeps a container on the screen layer placed exactly over the world layer — zoom, scroll and this frame's
|
|
109
|
+
* shake — for things drawn in world units above the screen-layer night (fireflies). Written in `apply`, after
|
|
110
|
+
* the scene updated, so it never lags the world by a frame or misses a shake the world takes.
|
|
111
|
+
*/
|
|
112
|
+
follow(t) {
|
|
113
|
+
this.followers.add(t);
|
|
114
|
+
}
|
|
115
|
+
unfollow(t) {
|
|
116
|
+
this.followers.delete(t);
|
|
117
|
+
}
|
|
118
|
+
/** Full-screen colour flash starting at `peak` alpha and fading out over `ms`. */
|
|
119
|
+
flash(t, e, s, n, r = !1, o = 1) {
|
|
120
|
+
(!this.flashRect || this.flashRect.destroyed) && (this.flashRect = new Ht(1, 1, 16777215).setOrigin(0, 0), this.screen.addChild(this.flashRect)), this.flashRect.resize(this.width, this.height).setFillStyle(e << 16 | s << 8 | n).setAlpha(o).setVisible(!0), this.flashStart = performance.now(), this.flashMs = t, this.flashPeak = o;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Keeps `target` (anything with `x` and `y`, read every frame: an entity's position, a sprite) in view, inside the
|
|
124
|
+
* bounds if there are any. Replaces any target before.
|
|
125
|
+
*/
|
|
126
|
+
track(t, e = {}) {
|
|
127
|
+
return this.target = t, this.trackOpts = { lerp: 1, deadzoneWidth: 0, deadzoneHeight: 0, offsetX: 0, offsetY: 0, ...e }, (e.lerp ?? 1) >= 1 && this.centerOn(t.x + this.trackOpts.offsetX, t.y + this.trackOpts.offsetY), this;
|
|
128
|
+
}
|
|
129
|
+
untrack() {
|
|
130
|
+
return this.target = null, this;
|
|
131
|
+
}
|
|
132
|
+
/** Moves the view toward the tracked target for a frame `dtMs` long. */
|
|
133
|
+
follow1(t) {
|
|
134
|
+
const e = this.target;
|
|
135
|
+
if (!e) return;
|
|
136
|
+
const s = this.trackOpts, n = this.width / this.zoom, r = this.height / this.zoom, o = this.scrollX + n / 2, a = this.scrollY + r / 2, h = e.x + s.offsetX, l = e.y + s.offsetY, c = s.deadzoneWidth / 2, u = s.deadzoneHeight / 2, d = h - o > c ? h - o - c : h - o < -c ? h - o + c : 0, m = l - a > u ? l - a - u : l - a < -u ? l - a + u : 0, f = s.lerp >= 1 ? 1 : 1 - Math.pow(1 - Math.max(0, s.lerp), t / (1e3 / 60));
|
|
137
|
+
this.scrollX += d * f, this.scrollY += m * f, this.clamp();
|
|
138
|
+
}
|
|
139
|
+
/** Writes the camera into the world layer; called once per frame after the scene updated. */
|
|
140
|
+
apply(t) {
|
|
141
|
+
const e = this.lastApply < 0 ? 16.666666666666668 : Math.min(100, t - this.lastApply);
|
|
142
|
+
this.lastApply = t, this.follow1(e);
|
|
143
|
+
let s = 0, n = 0;
|
|
144
|
+
if (t < this.shakeUntil) {
|
|
145
|
+
const h = (this.shakeUntil - t) / this.shakeMs;
|
|
146
|
+
if (this.shakeAngle !== void 0) {
|
|
147
|
+
const l = Math.cos((t - (this.shakeUntil - this.shakeMs)) / 28 * Math.PI) * this.shakeIntensity * this.width * h;
|
|
148
|
+
s = Math.round(Math.cos(this.shakeAngle) * l), n = Math.round(Math.sin(this.shakeAngle) * l);
|
|
149
|
+
} else
|
|
150
|
+
s = Math.round((Math.random() * 2 - 1) * this.shakeIntensity * this.width * h), n = Math.round((Math.random() * 2 - 1) * this.shakeIntensity * this.height * h);
|
|
151
|
+
}
|
|
152
|
+
this.world.scale.set(this.zoom);
|
|
153
|
+
const r = this.zoom * this.resolution, o = this.roundPixels ? Math.round(this.scrollX * r) / this.resolution : this.scrollX * this.zoom, a = this.roundPixels ? Math.round(this.scrollY * r) / this.resolution : this.scrollY * this.zoom;
|
|
154
|
+
this.world.position.set(-o + s, -a + n);
|
|
155
|
+
for (const h of this.followers)
|
|
156
|
+
h.scale.set(this.zoom), h.position.copyFrom(this.world.position);
|
|
157
|
+
if (this.flashRect?.visible) {
|
|
158
|
+
const h = (t - this.flashStart) / this.flashMs;
|
|
159
|
+
h >= 1 ? this.flashRect.setVisible(!1) : this.flashRect.alpha = this.flashPeak * (1 - h);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
clamp() {
|
|
163
|
+
const t = this.bounds;
|
|
164
|
+
if (!t) return;
|
|
165
|
+
const e = this.width / this.zoom, s = this.height / this.zoom;
|
|
166
|
+
this.scrollX = e >= t.width ? t.x + (t.width - e) / 2 : Math.min(Math.max(this.scrollX, t.x), t.x + t.width - e), this.scrollY = s >= t.height ? t.y + (t.height - s) / 2 : Math.min(Math.max(this.scrollY, t.y), t.y + t.height - s);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
class ye {
|
|
170
|
+
now = performance.now();
|
|
171
|
+
timers = [];
|
|
172
|
+
delayedCall(t, e) {
|
|
173
|
+
const s = { at: this.now + t, fn: e, removed: !1 };
|
|
174
|
+
return this.timers.push(s), { remove: () => {
|
|
175
|
+
s.removed = !0;
|
|
176
|
+
} };
|
|
177
|
+
}
|
|
178
|
+
update(t) {
|
|
179
|
+
this.now = t;
|
|
180
|
+
const e = this.timers.filter((s) => !s.removed && s.at <= t);
|
|
181
|
+
if (e.length) {
|
|
182
|
+
this.timers = this.timers.filter((s) => !s.removed && s.at > t);
|
|
183
|
+
for (const s of e)
|
|
184
|
+
try {
|
|
185
|
+
s.fn();
|
|
186
|
+
} catch (n) {
|
|
187
|
+
console.error("[timer] failed", n);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
clear() {
|
|
192
|
+
this.timers = [];
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const yt = /* @__PURE__ */ new Set(), It = [[" ", "~"]];
|
|
196
|
+
function Hn(i) {
|
|
197
|
+
It.push(i);
|
|
198
|
+
}
|
|
199
|
+
const we = 128;
|
|
200
|
+
function xe(i, t, e, s, n, r) {
|
|
201
|
+
const o = `label|${i}|${t}|${e}|${s}|${n}|${r}`;
|
|
202
|
+
if (!yt.has(o)) {
|
|
203
|
+
const a = ee.defaultOptions, h = a.textureSize;
|
|
204
|
+
a.textureSize = we;
|
|
205
|
+
try {
|
|
206
|
+
se.install({
|
|
207
|
+
name: o,
|
|
208
|
+
chars: It,
|
|
209
|
+
resolution: r,
|
|
210
|
+
style: { fontFamily: i, fontSize: t, fill: e, stroke: { color: s, width: n, join: "round" } }
|
|
211
|
+
});
|
|
212
|
+
} finally {
|
|
213
|
+
a.textureSize = h;
|
|
214
|
+
}
|
|
215
|
+
yt.add(o);
|
|
216
|
+
}
|
|
217
|
+
return o;
|
|
218
|
+
}
|
|
219
|
+
class be extends V(ie) {
|
|
220
|
+
/**
|
|
221
|
+
* `fontFamily` must already be loaded (`document.fonts.load`), or the glyphs bake in the fallback.
|
|
222
|
+
* Styled like `worldText`: the same font, size, colour and outline, rasterised at the same resolution.
|
|
223
|
+
*/
|
|
224
|
+
constructor(t, e, s, n, r, o, a, h, l) {
|
|
225
|
+
const c = xe(n, r, o, a, h, l);
|
|
226
|
+
super({ text: s, style: { fontFamily: c, fontSize: r } }), this.position.set(t, e);
|
|
227
|
+
}
|
|
228
|
+
setOrigin(t = 0.5, e = t) {
|
|
229
|
+
return this.anchor.set(t, e), this;
|
|
230
|
+
}
|
|
231
|
+
setText(t) {
|
|
232
|
+
return this.text = t, this;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
class ve extends V(M) {
|
|
236
|
+
get list() {
|
|
237
|
+
return this.children;
|
|
238
|
+
}
|
|
239
|
+
add(t) {
|
|
240
|
+
for (const e of Array.isArray(t) ? t : [t]) this.addChild(e);
|
|
241
|
+
return this;
|
|
242
|
+
}
|
|
243
|
+
addAt(t, e) {
|
|
244
|
+
return this.addChildAt(t, Math.min(e, this.children.length)), this;
|
|
245
|
+
}
|
|
246
|
+
remove(t, e = !1) {
|
|
247
|
+
return t.parent === this && this.removeChild(t), e && t.destroy({ children: !0, context: !0 }), this;
|
|
248
|
+
}
|
|
249
|
+
/** Puts `child` directly below `other` in the draw order. */
|
|
250
|
+
moveBelow(t, e) {
|
|
251
|
+
return t.parent !== this || e.parent !== this || t === e ? this : (this.removeChild(t), this.addChildAt(t, this.getChildIndex(e)), this);
|
|
252
|
+
}
|
|
253
|
+
/** Puts `child` directly above `other` in the draw order. */
|
|
254
|
+
moveAbove(t, e) {
|
|
255
|
+
return t.parent !== this || e.parent !== this || t === e ? this : (this.removeChild(t), this.addChildAt(t, this.getChildIndex(e) + 1), this);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
class Me extends V(R) {
|
|
259
|
+
constructor(t, e, s, n, r) {
|
|
260
|
+
super(t.get(n, r)), this.registry = t, this.textureKey = n, this.frameName = r === void 0 ? "" : String(r), this.anchor.set(0.5), this.position.set(e, s);
|
|
261
|
+
}
|
|
262
|
+
registry;
|
|
263
|
+
textureKey;
|
|
264
|
+
frameName;
|
|
265
|
+
get originX() {
|
|
266
|
+
return this.anchor.x;
|
|
267
|
+
}
|
|
268
|
+
get originY() {
|
|
269
|
+
return this.anchor.y;
|
|
270
|
+
}
|
|
271
|
+
/** Width of the frame itself, unscaled. */
|
|
272
|
+
get frameWidth() {
|
|
273
|
+
return this.texture.orig.width;
|
|
274
|
+
}
|
|
275
|
+
get frameHeight() {
|
|
276
|
+
return this.texture.orig.height;
|
|
277
|
+
}
|
|
278
|
+
get displayWidth() {
|
|
279
|
+
return Math.abs(this.frameWidth * this.scaleX);
|
|
280
|
+
}
|
|
281
|
+
set displayWidth(t) {
|
|
282
|
+
this.scaleX = t / this.frameWidth;
|
|
283
|
+
}
|
|
284
|
+
get displayHeight() {
|
|
285
|
+
return Math.abs(this.frameHeight * this.scaleY);
|
|
286
|
+
}
|
|
287
|
+
set displayHeight(t) {
|
|
288
|
+
this.scaleY = t / this.frameHeight;
|
|
289
|
+
}
|
|
290
|
+
setOrigin(t = 0.5, e = t) {
|
|
291
|
+
return this.anchor.set(t, e), this;
|
|
292
|
+
}
|
|
293
|
+
setDisplaySize(t, e) {
|
|
294
|
+
return this.setScale(t / this.frameWidth, e / this.frameHeight);
|
|
295
|
+
}
|
|
296
|
+
setFrame(t) {
|
|
297
|
+
return this.frameName = String(t), this.texture = this.registry.get(this.textureKey, t), this;
|
|
298
|
+
}
|
|
299
|
+
setTexture(t, e) {
|
|
300
|
+
return this.textureKey = t, this.frameName = e === void 0 ? "" : String(e), this.texture = this.registry.get(t, e), this;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
class Ae extends V(ne) {
|
|
304
|
+
constructor(t, e, s, n) {
|
|
305
|
+
const r = {
|
|
306
|
+
fontFamily: n.fontFamily ?? "monospace",
|
|
307
|
+
fontSize: typeof n.fontSize == "string" ? parseFloat(n.fontSize) : n.fontSize,
|
|
308
|
+
fill: n.color ?? "#ffffff"
|
|
309
|
+
};
|
|
310
|
+
n.stroke && (r.stroke = { color: n.stroke, width: n.strokeThickness ?? 1, join: "round" }), n.align && (r.align = n.align), n.lineSpacing !== void 0 && (r.leading = n.lineSpacing), n.wordWrapWidth !== void 0 && (r.wordWrap = !0, r.wordWrapWidth = n.wordWrapWidth), super({ text: s, resolution: n.resolution ?? 1, style: r }), this.position.set(t, e);
|
|
311
|
+
}
|
|
312
|
+
setOrigin(t = 0.5, e = t) {
|
|
313
|
+
return this.anchor.set(t, e), this;
|
|
314
|
+
}
|
|
315
|
+
setText(t) {
|
|
316
|
+
return this.text = t, this;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
class ke {
|
|
320
|
+
constructor(t) {
|
|
321
|
+
this.stage = t;
|
|
322
|
+
}
|
|
323
|
+
stage;
|
|
324
|
+
image(t, e, s, n) {
|
|
325
|
+
return this.attach(new Me(this.stage.textures, t, e, s, n));
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* A copy of `src` as it is drawn right now (afterimages, clones). A live texture, repainted every frame, is
|
|
329
|
+
* snapshotted first, and the snapshot is freed with the copy.
|
|
330
|
+
*/
|
|
331
|
+
still(t, e, s) {
|
|
332
|
+
const n = this.stage.textures;
|
|
333
|
+
if (!n.isLive(s.textureKey)) return this.image(t, e, s.textureKey, s.frameName);
|
|
334
|
+
const r = n.snapshot(s.textureKey, s.frameName), o = this.image(t, e, r, "0");
|
|
335
|
+
return o.once("destroyed", () => n.remove(r)), o;
|
|
336
|
+
}
|
|
337
|
+
graphics(t) {
|
|
338
|
+
const e = this.attach(new ce());
|
|
339
|
+
return e.position.set(t?.x ?? 0, t?.y ?? 0), e;
|
|
340
|
+
}
|
|
341
|
+
container(t = 0, e = 0, s = []) {
|
|
342
|
+
const n = this.attach(new ve());
|
|
343
|
+
return n.position.set(t, e), n.add(s), n;
|
|
344
|
+
}
|
|
345
|
+
rectangle(t, e, s, n, r, o = 1) {
|
|
346
|
+
const a = this.attach(new Ht(s, n, r, o));
|
|
347
|
+
return a.position.set(t, e), a;
|
|
348
|
+
}
|
|
349
|
+
text(t, e, s, n) {
|
|
350
|
+
return this.attach(new Ae(t, e, s, n));
|
|
351
|
+
}
|
|
352
|
+
/** A bitmap-font label (`BitmapLabel`): cheap to change, for text rewritten many times a second. */
|
|
353
|
+
label(t, e, s, n, r, o, a, h, l) {
|
|
354
|
+
return this.attach(new be(t, e, s, n, r, o, a, h, l));
|
|
355
|
+
}
|
|
356
|
+
/** Puts an object made elsewhere on the world layer, as the factory's own are (a `PixelLayer`, a custom class). */
|
|
357
|
+
existing(t) {
|
|
358
|
+
return this.attach(t);
|
|
359
|
+
}
|
|
360
|
+
attach(t) {
|
|
361
|
+
return t.scene = this.stage, this.stage.world.addChild(t), t;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function U(i) {
|
|
365
|
+
return i === 1 ? 4 : i === 2 ? 2 : i === 0 ? 1 : 0;
|
|
366
|
+
}
|
|
367
|
+
class pt {
|
|
368
|
+
constructor(t) {
|
|
369
|
+
this.canvas = t;
|
|
370
|
+
const e = ue(), s = (n, r, o) => {
|
|
371
|
+
const a = (h) => {
|
|
372
|
+
e && h instanceof PointerEvent && h.pointerType === "touch" || o(h);
|
|
373
|
+
};
|
|
374
|
+
n.addEventListener(r, a), this.cleanup.push(() => n.removeEventListener(r, a));
|
|
375
|
+
};
|
|
376
|
+
s(t, "pointerdown", (n) => {
|
|
377
|
+
this.track(n), !pt.ignorePress?.(n) && (this.buttons |= U(n.button));
|
|
378
|
+
}), s(window, "pointermove", (n) => {
|
|
379
|
+
this.track(n), n.button >= 0 && (this.buttons = (n.buttons & U(n.button)) !== 0 ? this.buttons | U(n.button) : this.buttons & ~U(n.button));
|
|
380
|
+
}), s(window, "pointerup", (n) => {
|
|
381
|
+
this.buttons &= ~U(n.button);
|
|
382
|
+
}), s(window, "blur", () => {
|
|
383
|
+
this.buttons = 0;
|
|
384
|
+
}), s(t, "contextmenu", (n) => n.preventDefault());
|
|
385
|
+
}
|
|
386
|
+
canvas;
|
|
387
|
+
/**
|
|
388
|
+
* A press this returns true for is not counted as a held button (e.g. Shift + right-click opening a context menu
|
|
389
|
+
* instead of firing what the right button is bound to). Unset, every press counts.
|
|
390
|
+
*/
|
|
391
|
+
static ignorePress = null;
|
|
392
|
+
/** Screen position relative to the canvas, in CSS pixels. */
|
|
393
|
+
x = 0;
|
|
394
|
+
y = 0;
|
|
395
|
+
worldX = 0;
|
|
396
|
+
worldY = 0;
|
|
397
|
+
buttons = 0;
|
|
398
|
+
cleanup = [];
|
|
399
|
+
leftButtonDown() {
|
|
400
|
+
return (this.buttons & 1) !== 0;
|
|
401
|
+
}
|
|
402
|
+
rightButtonDown() {
|
|
403
|
+
return (this.buttons & 2) !== 0;
|
|
404
|
+
}
|
|
405
|
+
updateWorldPoint(t) {
|
|
406
|
+
this.worldX = t.scrollX + this.x / t.zoom, this.worldY = t.scrollY + this.y / t.zoom;
|
|
407
|
+
}
|
|
408
|
+
destroy() {
|
|
409
|
+
for (const t of this.cleanup) t();
|
|
410
|
+
this.cleanup.length = 0;
|
|
411
|
+
}
|
|
412
|
+
track(t) {
|
|
413
|
+
const e = this.canvas.getBoundingClientRect();
|
|
414
|
+
this.x = t.clientX - e.left, this.y = t.clientY - e.top;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
const _t = (i) => i, wt = {
|
|
418
|
+
Linear: _t,
|
|
419
|
+
"Quad.In": (i) => i * i,
|
|
420
|
+
"Quad.Out": (i) => i * (2 - i),
|
|
421
|
+
"Cubic.Out": (i) => 1 - Math.pow(1 - i, 3),
|
|
422
|
+
"Sine.In": (i) => 1 - Math.cos(i * Math.PI / 2),
|
|
423
|
+
"Sine.InOut": (i) => -(Math.cos(Math.PI * i) - 1) / 2,
|
|
424
|
+
"Back.Out": (i) => {
|
|
425
|
+
const e = i - 1;
|
|
426
|
+
return e * e * ((1.70158 + 1) * e + 1.70158) + 1;
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
function Se(i) {
|
|
430
|
+
if (!i) return wt["Quad.Out"];
|
|
431
|
+
const t = wt[i];
|
|
432
|
+
return t || console.warn(`[tween] unknown ease ${i}`), t ?? _t;
|
|
433
|
+
}
|
|
434
|
+
const Ee = /* @__PURE__ */ new Set([
|
|
435
|
+
"targets",
|
|
436
|
+
"duration",
|
|
437
|
+
"delay",
|
|
438
|
+
"hold",
|
|
439
|
+
"yoyo",
|
|
440
|
+
"repeat",
|
|
441
|
+
"ease",
|
|
442
|
+
"props",
|
|
443
|
+
"onStart",
|
|
444
|
+
"onUpdate",
|
|
445
|
+
"onComplete"
|
|
446
|
+
]);
|
|
447
|
+
class Fe {
|
|
448
|
+
constructor(t, e) {
|
|
449
|
+
this.cfg = t, this.ends = e;
|
|
450
|
+
const s = t.targets;
|
|
451
|
+
this.targets = Array.isArray(s) ? s : [s];
|
|
452
|
+
}
|
|
453
|
+
cfg;
|
|
454
|
+
ends;
|
|
455
|
+
tracks = null;
|
|
456
|
+
elapsed = 0;
|
|
457
|
+
plays = 0;
|
|
458
|
+
removed = !1;
|
|
459
|
+
targets;
|
|
460
|
+
/**
|
|
461
|
+
* Every target is a destroyed display object: nothing is left to move. A forever tween (`repeat: -1`) on a sprite
|
|
462
|
+
* its owner freed used to stay in the list for good, holding the sprite, and the list grew with every map loaded.
|
|
463
|
+
* A plain object (a clock a callback reads) has no `destroyed` and is never taken for one. Only a forever tween is
|
|
464
|
+
* dropped this way: a finite one still runs out and calls its `onComplete`, which may clean up more than the sprite.
|
|
465
|
+
*/
|
|
466
|
+
orphaned() {
|
|
467
|
+
if (this.cfg.repeat !== -1) return !1;
|
|
468
|
+
const t = this.targets;
|
|
469
|
+
if (t.length === 0) return !1;
|
|
470
|
+
for (const e of t) if (e.destroyed !== !0) return !1;
|
|
471
|
+
return !0;
|
|
472
|
+
}
|
|
473
|
+
remove() {
|
|
474
|
+
this.removed = !0;
|
|
475
|
+
}
|
|
476
|
+
stop() {
|
|
477
|
+
this.removed = !0;
|
|
478
|
+
}
|
|
479
|
+
/** Advances by `dt` ms; returns false once the tween is finished. */
|
|
480
|
+
step(t) {
|
|
481
|
+
if (this.removed) return !1;
|
|
482
|
+
if (this.orphaned())
|
|
483
|
+
return this.removed = !0, !1;
|
|
484
|
+
const e = this.cfg, s = e.delay ?? 0;
|
|
485
|
+
if (this.elapsed += t, this.elapsed < s) return !0;
|
|
486
|
+
if (!this.tracks) {
|
|
487
|
+
this.tracks = [];
|
|
488
|
+
for (const d of this.targets)
|
|
489
|
+
for (const [m, f] of Object.entries(this.ends)) this.tracks.push({ target: d, prop: m, from: Be(d, m), to: f });
|
|
490
|
+
e.onStart?.();
|
|
491
|
+
}
|
|
492
|
+
const n = Math.max(1, e.duration ?? 1e3), r = e.yoyo ? e.hold ?? 0 : 0, o = e.yoyo ? n * 2 + r : n;
|
|
493
|
+
let a = this.elapsed - s - this.plays * o;
|
|
494
|
+
const h = e.repeat ?? 0;
|
|
495
|
+
let l = !1;
|
|
496
|
+
a >= o && (h === -1 || this.plays < h ? (this.plays++, a -= o) : (a = o, l = !0));
|
|
497
|
+
let c;
|
|
498
|
+
e.yoyo ? a <= n ? c = a / n : a <= n + r ? c = 1 : c = 1 - (a - n - r) / n : c = a / n;
|
|
499
|
+
const u = Se(e.ease)(Math.min(1, Math.max(0, c)));
|
|
500
|
+
for (const d of this.tracks) d.target.destroyed || De(d.target, d.prop, d.from + (d.to - d.from) * u);
|
|
501
|
+
return e.onUpdate?.(), l ? (this.removed = !0, e.onComplete?.(), !1) : !0;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
function Be(i, t) {
|
|
505
|
+
const e = t === "scale" ? i.scaleX : i[t];
|
|
506
|
+
return typeof e == "number" ? e : 0;
|
|
507
|
+
}
|
|
508
|
+
function De(i, t, e) {
|
|
509
|
+
t === "scale" ? (i.scaleX = e, i.scaleY = e) : i[t] = e;
|
|
510
|
+
}
|
|
511
|
+
class Te {
|
|
512
|
+
/** Global speed factor; hit-stop slows every tween at once. */
|
|
513
|
+
timeScale = 1;
|
|
514
|
+
tweens = [];
|
|
515
|
+
add(t) {
|
|
516
|
+
const e = { ...t.props ?? {} }, s = {};
|
|
517
|
+
for (const [o, a] of Object.entries(t))
|
|
518
|
+
if (!Ee.has(o)) {
|
|
519
|
+
if (typeof a == "number") e[o] = a;
|
|
520
|
+
else if (a && typeof a == "object" && "to" in a) {
|
|
521
|
+
const h = a;
|
|
522
|
+
e[o] = h.to, h.from !== void 0 && (s[o] = h.from);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
const n = Array.isArray(t.targets) ? t.targets : [t.targets];
|
|
526
|
+
for (const o of n) for (const [a, h] of Object.entries(s)) o[a] = h;
|
|
527
|
+
const r = new Fe(t, e);
|
|
528
|
+
return this.tweens.push(r), r;
|
|
529
|
+
}
|
|
530
|
+
killTweensOf(t) {
|
|
531
|
+
const e = new Set(Array.isArray(t) ? t : [t]);
|
|
532
|
+
for (const s of this.tweens) s.targets.some((n) => e.has(n)) && s.remove();
|
|
533
|
+
}
|
|
534
|
+
update(t) {
|
|
535
|
+
const e = t * this.timeScale, s = this.tweens, n = s.length;
|
|
536
|
+
let r = 0;
|
|
537
|
+
for (let o = 0; o < n; o++) {
|
|
538
|
+
const a = s[o];
|
|
539
|
+
Re(a, e) && (s[r++] = a);
|
|
540
|
+
}
|
|
541
|
+
if (this.tweens === s) {
|
|
542
|
+
for (let o = n; o < s.length; o++) s[r++] = s[o];
|
|
543
|
+
s.length = r;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
clear() {
|
|
547
|
+
for (const t of this.tweens) t.remove();
|
|
548
|
+
this.tweens = [];
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
function Re(i, t) {
|
|
552
|
+
try {
|
|
553
|
+
return i.step(t);
|
|
554
|
+
} catch (e) {
|
|
555
|
+
return console.error("[tween] dropped after an error", e), !1;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
class H {
|
|
559
|
+
constructor(t, e) {
|
|
560
|
+
this.app = t, this.textures = e, t.stage.addChild(this.world, this.screen), this.cameras = { main: new ge(this.world, this.screen) }, this.input = { activePointer: new pt(t.canvas) }, this.syncSize();
|
|
561
|
+
}
|
|
562
|
+
app;
|
|
563
|
+
textures;
|
|
564
|
+
/** Told of every fault a guarded step caught (error telemetry, if the game sets one). */
|
|
565
|
+
static onCaught = null;
|
|
566
|
+
world = new M({ sortableChildren: !0 });
|
|
567
|
+
screen = new M();
|
|
568
|
+
add = new ke(this);
|
|
569
|
+
tweens = new Te();
|
|
570
|
+
time = new ye();
|
|
571
|
+
cameras;
|
|
572
|
+
input;
|
|
573
|
+
resizeListeners = [];
|
|
574
|
+
lastWidth = 0;
|
|
575
|
+
lastHeight = 0;
|
|
576
|
+
get width() {
|
|
577
|
+
return this.app.screen.width;
|
|
578
|
+
}
|
|
579
|
+
get height() {
|
|
580
|
+
return this.app.screen.height;
|
|
581
|
+
}
|
|
582
|
+
get fps() {
|
|
583
|
+
return this.app.ticker.FPS;
|
|
584
|
+
}
|
|
585
|
+
/** Calls `fn` whenever the window changes size; the returned function stops it (a per-map listener must). */
|
|
586
|
+
onResize(t) {
|
|
587
|
+
return this.resizeListeners.push(t), () => {
|
|
588
|
+
const e = this.resizeListeners.indexOf(t);
|
|
589
|
+
e >= 0 && this.resizeListeners.splice(e, 1);
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* One frame: game logic, then tweens and timers, then the camera. Pixi renders after. Each step is guarded: a
|
|
594
|
+
* ticker listener that throws never asks for the next animation frame, so one bad frame used to stop the world for
|
|
595
|
+
* good — the canvas frozen and no input reaching the server (seen on Android).
|
|
596
|
+
*/
|
|
597
|
+
frame(t) {
|
|
598
|
+
const e = performance.now();
|
|
599
|
+
this.guard("resize", () => this.syncSize()), this.guard("update", () => this.update(e, t)), this.guard("tweens", () => this.tweens.update(t)), this.guard("timers", () => this.time.update(e)), this.guard("camera", () => this.cameras.main.apply(e));
|
|
600
|
+
}
|
|
601
|
+
reported = /* @__PURE__ */ new Set();
|
|
602
|
+
/**
|
|
603
|
+
* Runs one step of a frame and swallows what it throws, so the steps after it still run. Subclasses guard the parts
|
|
604
|
+
* of their own `update` too: a fault before the camera follows the player used to leave the view standing on one
|
|
605
|
+
* spot while the world went on.
|
|
606
|
+
*/
|
|
607
|
+
guard(t, e) {
|
|
608
|
+
this.guarded(t, e, void 0);
|
|
609
|
+
}
|
|
610
|
+
/** `guard` for a step that answers something: `fallback` when it threw. */
|
|
611
|
+
guarded(t, e, s) {
|
|
612
|
+
try {
|
|
613
|
+
return e();
|
|
614
|
+
} catch (n) {
|
|
615
|
+
return this.caught(t, n), s;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
/** What a guarded step threw: logged once per distinct error, or a fault repeating every frame floods the log at 60 a second. */
|
|
619
|
+
caught(t, e) {
|
|
620
|
+
const s = `${t}|${e instanceof Error ? e.message : String(e)}`;
|
|
621
|
+
this.reported.has(s) || (this.reported.add(s), console.error(`[frame] ${t} failed`, e), H.onCaught?.(`[frame] ${t}`, e));
|
|
622
|
+
}
|
|
623
|
+
destroy() {
|
|
624
|
+
this.tweens.clear(), this.time.clear(), this.input.activePointer.destroy(), this.world.destroy({ children: !0, context: !0 }), this.screen.destroy({ children: !0, context: !0 });
|
|
625
|
+
}
|
|
626
|
+
syncSize() {
|
|
627
|
+
const { width: t, height: e } = this.app.screen, s = this.cameras.main;
|
|
628
|
+
if (s.width = t, s.height = e, !(t === this.lastWidth && e === this.lastHeight)) {
|
|
629
|
+
this.lastWidth = t, this.lastHeight = e;
|
|
630
|
+
for (const n of [...this.resizeListeners]) n();
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
class Oe {
|
|
635
|
+
constructor(t, e) {
|
|
636
|
+
this.key = t, this.canvas = e, this.source = new re({ resource: e, scaleMode: "nearest" }), this.whole = new C({ source: this.source });
|
|
637
|
+
}
|
|
638
|
+
key;
|
|
639
|
+
canvas;
|
|
640
|
+
frames = /* @__PURE__ */ new Map();
|
|
641
|
+
source;
|
|
642
|
+
whole;
|
|
643
|
+
get width() {
|
|
644
|
+
return this.canvas.width;
|
|
645
|
+
}
|
|
646
|
+
get height() {
|
|
647
|
+
return this.canvas.height;
|
|
648
|
+
}
|
|
649
|
+
get context() {
|
|
650
|
+
return this.canvas.getContext("2d");
|
|
651
|
+
}
|
|
652
|
+
/** Adds a frame cut from the canvas (`_source` kept for the old call shape). */
|
|
653
|
+
add(t, e, s, n, r, o) {
|
|
654
|
+
this.frames.get(t)?.destroy(), this.frames.set(t, new C({ source: this.source, frame: new oe(s, n, r, o) }));
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Registers under this texture a frame that lives on another one (an atlas page after the first), so the frame is
|
|
658
|
+
* found by this texture's key. A texture of its own over the other page's source: each side frees its own.
|
|
659
|
+
*/
|
|
660
|
+
adopt(t, e) {
|
|
661
|
+
const s = e.frames.get(t);
|
|
662
|
+
s && (this.frames.get(t)?.destroy(), this.frames.set(t, new C({ source: e.source, frame: s.frame.clone() })));
|
|
663
|
+
}
|
|
664
|
+
refresh() {
|
|
665
|
+
this.source.update();
|
|
666
|
+
}
|
|
667
|
+
destroy() {
|
|
668
|
+
for (const t of this.frames.values()) t.destroy();
|
|
669
|
+
this.frames.clear(), this.whole.destroy(), this.source.destroy();
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
class Ce {
|
|
673
|
+
textures = /* @__PURE__ */ new Map();
|
|
674
|
+
/** Textures repainted or freed while in use (a rig body, its hand): a copy of one must snapshot it first. */
|
|
675
|
+
live = /* @__PURE__ */ new Set();
|
|
676
|
+
missing = /* @__PURE__ */ new Set();
|
|
677
|
+
snapshots = 0;
|
|
678
|
+
markLive(t) {
|
|
679
|
+
this.live.add(t);
|
|
680
|
+
}
|
|
681
|
+
isLive(t) {
|
|
682
|
+
return this.live.has(t);
|
|
683
|
+
}
|
|
684
|
+
/** A new texture holding frame `frame` of `key` as it is painted right now; returns its key (one frame, '0'). */
|
|
685
|
+
snapshot(t, e) {
|
|
686
|
+
const s = this.get(t, e), { x: n, y: r, width: o, height: a } = s.frame, h = document.createElement("canvas");
|
|
687
|
+
h.width = o, h.height = a;
|
|
688
|
+
const l = this.textures.get(t)?.canvas;
|
|
689
|
+
l && h.getContext("2d").drawImage(l, n, r, o, a, 0, 0, o, a);
|
|
690
|
+
const c = `${t}#still${++this.snapshots}`;
|
|
691
|
+
return this.addCanvas(c, h).add("0", 0, 0, 0, o, a), c;
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* `snapshot` into a texture kept for reuse (`into`): its canvas is repainted in place and uploaded again, and only
|
|
695
|
+
* made anew when the frame's size changes. Frame '0' is the copy.
|
|
696
|
+
*/
|
|
697
|
+
snapshotInto(t, e, s) {
|
|
698
|
+
const n = this.get(t, e), { x: r, y: o, width: a, height: h } = n.frame;
|
|
699
|
+
let l = this.textures.get(s);
|
|
700
|
+
if (!l || l.width !== a || l.height !== h) {
|
|
701
|
+
const d = document.createElement("canvas");
|
|
702
|
+
d.width = a, d.height = h, l = this.addCanvas(s, d), l.add("0", 0, 0, 0, a, h);
|
|
703
|
+
}
|
|
704
|
+
const c = l.context;
|
|
705
|
+
c.clearRect(0, 0, a, h);
|
|
706
|
+
const u = this.textures.get(t)?.canvas;
|
|
707
|
+
u && c.drawImage(u, r, o, a, h, 0, 0, a, h), l.refresh();
|
|
708
|
+
}
|
|
709
|
+
exists(t) {
|
|
710
|
+
return this.textures.has(t);
|
|
711
|
+
}
|
|
712
|
+
addCanvas(t, e) {
|
|
713
|
+
this.remove(t);
|
|
714
|
+
const s = new Oe(t, e);
|
|
715
|
+
return this.textures.set(t, s), s;
|
|
716
|
+
}
|
|
717
|
+
/** A canvas cut into equal frames named 0, 1, 2... left to right, then row by row. */
|
|
718
|
+
addSpriteSheet(t, e, s) {
|
|
719
|
+
const n = this.addCanvas(t, e), r = Math.floor(e.width / s.frameWidth), o = Math.floor(e.height / s.frameHeight);
|
|
720
|
+
for (let a = 0; a < r * o; a++)
|
|
721
|
+
n.add(String(a), 0, a % r * s.frameWidth, Math.floor(a / r) * s.frameHeight, s.frameWidth, s.frameHeight);
|
|
722
|
+
return n;
|
|
723
|
+
}
|
|
724
|
+
createCanvas(t, e, s) {
|
|
725
|
+
const n = document.createElement("canvas");
|
|
726
|
+
return n.width = e, n.height = s, this.addCanvas(t, n);
|
|
727
|
+
}
|
|
728
|
+
remove(t) {
|
|
729
|
+
this.textures.get(t)?.destroy(), this.textures.delete(t), this.live.delete(t);
|
|
730
|
+
}
|
|
731
|
+
get(t, e) {
|
|
732
|
+
const s = this.textures.get(t);
|
|
733
|
+
return s ? e === void 0 || e === "" ? s.whole : s.frames.get(String(e)) ?? this.warn(`${t}/${e}`) : this.warn(t);
|
|
734
|
+
}
|
|
735
|
+
warn(t) {
|
|
736
|
+
return this.missing.has(t) || (this.missing.add(t), console.warn(`[textures] missing ${t}`)), C.EMPTY;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
class Pt {
|
|
740
|
+
constructor(t = (e, s) => console.error(`[events] ${String(e)} listener failed`, s)) {
|
|
741
|
+
this.onError = t;
|
|
742
|
+
}
|
|
743
|
+
onError;
|
|
744
|
+
listeners = /* @__PURE__ */ new Map();
|
|
745
|
+
/** Subscribes to `type`; returns the unsubscribe function. */
|
|
746
|
+
on(t, e) {
|
|
747
|
+
return this.listeners.set(t, [...this.listeners.get(t) ?? [], e]), () => this.off(t, e);
|
|
748
|
+
}
|
|
749
|
+
/** Subscribes for the next `type` only. */
|
|
750
|
+
once(t, e) {
|
|
751
|
+
const s = this.on(t, (n) => {
|
|
752
|
+
s(), e(n);
|
|
753
|
+
});
|
|
754
|
+
return s;
|
|
755
|
+
}
|
|
756
|
+
off(t, e) {
|
|
757
|
+
const s = this.listeners.get(t);
|
|
758
|
+
if (!s) return;
|
|
759
|
+
const n = s.filter((r) => r !== e);
|
|
760
|
+
n.length ? this.listeners.set(t, n) : this.listeners.delete(t);
|
|
761
|
+
}
|
|
762
|
+
emit(t, e) {
|
|
763
|
+
for (const s of this.listeners.get(t) ?? [])
|
|
764
|
+
try {
|
|
765
|
+
s(e);
|
|
766
|
+
} catch (n) {
|
|
767
|
+
this.onError(t, n);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
listenerCount(t) {
|
|
771
|
+
return this.listeners.get(t)?.length ?? 0;
|
|
772
|
+
}
|
|
773
|
+
clear() {
|
|
774
|
+
this.listeners.clear();
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
class Le {
|
|
778
|
+
stepMs;
|
|
779
|
+
stepSeconds;
|
|
780
|
+
maxSteps;
|
|
781
|
+
carry = 0;
|
|
782
|
+
/** Steps taken since the loop started. */
|
|
783
|
+
tick = 0;
|
|
784
|
+
constructor(t = {}) {
|
|
785
|
+
const e = t.hz ?? 60;
|
|
786
|
+
if (!(e > 0)) throw new Error(`FixedLoop: hz must be positive, got ${e}`);
|
|
787
|
+
this.stepMs = 1e3 / e, this.stepSeconds = 1 / e, this.maxSteps = Math.max(1, t.maxStepsPerFrame ?? 8);
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Feeds one frame of `deltaMs` and runs `step` as many times as it owes. Returns the share of a step left over
|
|
791
|
+
* (0–1), for interpolating what is drawn between the last two steps.
|
|
792
|
+
*/
|
|
793
|
+
advance(t, e) {
|
|
794
|
+
t > 0 && Number.isFinite(t) && (this.carry += t);
|
|
795
|
+
let s = 0;
|
|
796
|
+
for (; this.carry >= this.stepMs; ) {
|
|
797
|
+
if (s === this.maxSteps) {
|
|
798
|
+
this.carry %= this.stepMs;
|
|
799
|
+
break;
|
|
800
|
+
}
|
|
801
|
+
this.carry -= this.stepMs, s++, e(this.tick++);
|
|
802
|
+
}
|
|
803
|
+
return this.carry / this.stepMs;
|
|
804
|
+
}
|
|
805
|
+
/** Forgets any debt, e.g. after a scene change or a long load. */
|
|
806
|
+
reset() {
|
|
807
|
+
this.carry = 0;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
class He {
|
|
811
|
+
constructor(t) {
|
|
812
|
+
this.engine = t;
|
|
813
|
+
}
|
|
814
|
+
engine;
|
|
815
|
+
stack = [];
|
|
816
|
+
queue = Promise.resolve();
|
|
817
|
+
/** True while an async `onEnter` is running: nothing updates until it is done. */
|
|
818
|
+
entering = !1;
|
|
819
|
+
/** The scene that updates, if any. */
|
|
820
|
+
get current() {
|
|
821
|
+
return this.entering ? void 0 : this.stack[this.stack.length - 1];
|
|
822
|
+
}
|
|
823
|
+
/** Every scene on the stack, bottom first. */
|
|
824
|
+
get all() {
|
|
825
|
+
return this.stack;
|
|
826
|
+
}
|
|
827
|
+
/** Removes every scene and enters `scene`. */
|
|
828
|
+
replace(t) {
|
|
829
|
+
return this.enqueue(async () => {
|
|
830
|
+
for (; this.stack.length; ) this.exitTop();
|
|
831
|
+
await this.enter(t);
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
/** Pauses the current scene and enters `scene` over it. */
|
|
835
|
+
push(t) {
|
|
836
|
+
return this.enqueue(async () => {
|
|
837
|
+
this.stack[this.stack.length - 1]?.onPause(), await this.enter(t);
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
/** Leaves the current scene and resumes the one under it. */
|
|
841
|
+
pop() {
|
|
842
|
+
return this.enqueue(async () => {
|
|
843
|
+
this.stack.length && (this.exitTop(), this.stack[this.stack.length - 1]?.onResume());
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
/** Leaves every scene (the engine is shutting down). */
|
|
847
|
+
clear() {
|
|
848
|
+
return this.enqueue(async () => {
|
|
849
|
+
for (; this.stack.length; ) this.exitTop();
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
async enter(t) {
|
|
853
|
+
if (this.stack.includes(t)) throw new Error(`${t.constructor.name} is already on the scene stack`);
|
|
854
|
+
t.attach(this.engine), this.stack.push(t), this.entering = !0;
|
|
855
|
+
try {
|
|
856
|
+
await t.onEnter();
|
|
857
|
+
} finally {
|
|
858
|
+
this.entering = !1;
|
|
859
|
+
}
|
|
860
|
+
this.engine.loop.reset();
|
|
861
|
+
}
|
|
862
|
+
exitTop() {
|
|
863
|
+
const t = this.stack.pop();
|
|
864
|
+
if (t)
|
|
865
|
+
try {
|
|
866
|
+
t.onExit();
|
|
867
|
+
} finally {
|
|
868
|
+
t.detach();
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
enqueue(t) {
|
|
872
|
+
const e = this.queue.then(t);
|
|
873
|
+
return this.queue = e.catch((s) => this.engine.reportError("scene", s)), e;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
class Ie extends H {
|
|
877
|
+
constructor(t, e, s) {
|
|
878
|
+
super(t, e), this.tick = s;
|
|
879
|
+
}
|
|
880
|
+
tick;
|
|
881
|
+
update(t, e) {
|
|
882
|
+
this.tick(t, e);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
class Wt {
|
|
886
|
+
constructor(t, e, s) {
|
|
887
|
+
this.app = t, this.loop = new Le(s.hz === void 0 ? {} : { hz: s.hz }), this.stage = new Ie(t, e, (r, o) => this.tick(r, o));
|
|
888
|
+
const n = this.stage.cameras.main;
|
|
889
|
+
n.setZoom(s.zoom ?? 1), n.roundPixels = s.pixelPerfect === !0, n.resolution = t.renderer.resolution, this.scenes = new He(this), H.onCaught = (r, o) => this.events.emit("error", { where: r, error: o }), t.ticker.add(this.onTick);
|
|
890
|
+
}
|
|
891
|
+
app;
|
|
892
|
+
stage;
|
|
893
|
+
loop;
|
|
894
|
+
scenes;
|
|
895
|
+
events = new Pt();
|
|
896
|
+
running = !0;
|
|
897
|
+
destroyed = !1;
|
|
898
|
+
onTick = (t) => this.stage.frame(t.deltaMS);
|
|
899
|
+
static async create(t) {
|
|
900
|
+
const e = t.pixelPerfect === !0;
|
|
901
|
+
ae.defaultOptions.scaleMode = e ? "nearest" : "linear";
|
|
902
|
+
const s = e ? 1 : t.resolution ?? Math.min(2, typeof devicePixelRatio == "number" ? devicePixelRatio : 1);
|
|
903
|
+
de();
|
|
904
|
+
const n = new he(), r = t.width === void 0 && t.height === void 0;
|
|
905
|
+
return await n.init({
|
|
906
|
+
...r ? { resizeTo: t.parent } : { width: t.width ?? 800, height: t.height ?? 600 },
|
|
907
|
+
background: t.background ?? "#000000",
|
|
908
|
+
antialias: !e,
|
|
909
|
+
resolution: s,
|
|
910
|
+
autoDensity: !0,
|
|
911
|
+
preference: t.preference ?? "webgl"
|
|
912
|
+
}), t.parent.appendChild(n.canvas), new Wt(n, t.textures ?? new Ce(), t);
|
|
913
|
+
}
|
|
914
|
+
/** The scene that updates now, if any. */
|
|
915
|
+
get scene() {
|
|
916
|
+
return this.scenes.current;
|
|
917
|
+
}
|
|
918
|
+
/** Stops simulating and drawing; the canvas keeps its last frame. */
|
|
919
|
+
pause() {
|
|
920
|
+
this.running && (this.running = !1, this.app.ticker.stop());
|
|
921
|
+
}
|
|
922
|
+
resume() {
|
|
923
|
+
this.running || this.destroyed || (this.running = !0, this.loop.reset(), this.app.ticker.start());
|
|
924
|
+
}
|
|
925
|
+
get paused() {
|
|
926
|
+
return !this.running;
|
|
927
|
+
}
|
|
928
|
+
/** Reports a fault to `events.error` (and the console when nobody listens). */
|
|
929
|
+
reportError(t, e) {
|
|
930
|
+
this.events.listenerCount("error") === 0 && console.error(`[engine] ${t}`, e), this.events.emit("error", { where: t, error: e });
|
|
931
|
+
}
|
|
932
|
+
/** Leaves every scene, removes the canvas and frees the renderer. */
|
|
933
|
+
async destroy() {
|
|
934
|
+
this.destroyed || (this.destroyed = !0, await this.scenes.clear(), this.app.ticker.remove(this.onTick), H.onCaught && (H.onCaught = null), this.stage.destroy(), this.events.clear(), this.app.destroy({ removeView: !0 }, { children: !0 }));
|
|
935
|
+
}
|
|
936
|
+
tick(t, e) {
|
|
937
|
+
const s = this.scenes.current;
|
|
938
|
+
if (s) {
|
|
939
|
+
const n = (h, l) => this.reportError(`system ${h.name}`, l), r = this.loop.stepSeconds, o = this.loop.advance(e, () => {
|
|
940
|
+
s.world.run("fixed", { dt: r, now: t, alpha: 0 }, n), s.fixedUpdate(r);
|
|
941
|
+
}), a = e / 1e3;
|
|
942
|
+
s.world.run("frame", { dt: a, now: t, alpha: o }, n), s.update(a, o);
|
|
943
|
+
}
|
|
944
|
+
this.events.emit("frame", { now: t, dt: e / 1e3 });
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
class _e {
|
|
948
|
+
sparse = new Int32Array(64).fill(-1);
|
|
949
|
+
/** Packed entity ids, in the same order as `values`. */
|
|
950
|
+
entities = [];
|
|
951
|
+
values = [];
|
|
952
|
+
/** Bumped whenever an entity joins or leaves the set (not when a value changes): query caches key on it. */
|
|
953
|
+
version = 0;
|
|
954
|
+
get size() {
|
|
955
|
+
return this.entities.length;
|
|
956
|
+
}
|
|
957
|
+
has(t) {
|
|
958
|
+
return t < this.sparse.length && this.sparse[t] >= 0;
|
|
959
|
+
}
|
|
960
|
+
/** The value at slot `index`, or undefined. */
|
|
961
|
+
get(t) {
|
|
962
|
+
if (t >= this.sparse.length) return;
|
|
963
|
+
const e = this.sparse[t];
|
|
964
|
+
return e >= 0 ? this.values[e] : void 0;
|
|
965
|
+
}
|
|
966
|
+
set(t, e, s) {
|
|
967
|
+
this.grow(t);
|
|
968
|
+
const n = this.sparse[t];
|
|
969
|
+
if (n >= 0) {
|
|
970
|
+
this.values[n] = s, this.entities[n] = e;
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
this.sparse[t] = this.entities.length, this.version++, this.entities.push(e), this.values.push(s);
|
|
974
|
+
}
|
|
975
|
+
/** Removes slot `index`; true if it was there. */
|
|
976
|
+
delete(t, e) {
|
|
977
|
+
if (t >= this.sparse.length) return !1;
|
|
978
|
+
const s = this.sparse[t];
|
|
979
|
+
if (s < 0) return !1;
|
|
980
|
+
const n = this.entities.length - 1;
|
|
981
|
+
if (s !== n) {
|
|
982
|
+
const r = this.entities[n];
|
|
983
|
+
this.entities[s] = r, this.values[s] = this.values[n], this.sparse[e(r)] = s;
|
|
984
|
+
}
|
|
985
|
+
return this.entities.pop(), this.values.pop(), this.sparse[t] = -1, this.version++, !0;
|
|
986
|
+
}
|
|
987
|
+
clear() {
|
|
988
|
+
this.version++, this.sparse.fill(-1), this.entities.length = 0, this.values.length = 0;
|
|
989
|
+
}
|
|
990
|
+
grow(t) {
|
|
991
|
+
if (t < this.sparse.length) return;
|
|
992
|
+
let e = this.sparse.length;
|
|
993
|
+
for (; e <= t; ) e *= 2;
|
|
994
|
+
const s = new Int32Array(e).fill(-1);
|
|
995
|
+
s.set(this.sparse), this.sparse = s;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
const Pe = {
|
|
999
|
+
f32: Float32Array,
|
|
1000
|
+
f64: Float64Array,
|
|
1001
|
+
i8: Int8Array,
|
|
1002
|
+
i16: Int16Array,
|
|
1003
|
+
i32: Int32Array,
|
|
1004
|
+
u8: Uint8Array,
|
|
1005
|
+
u16: Uint16Array,
|
|
1006
|
+
u32: Uint32Array
|
|
1007
|
+
};
|
|
1008
|
+
function We(i) {
|
|
1009
|
+
return i.fields !== void 0;
|
|
1010
|
+
}
|
|
1011
|
+
function Ue(i, t, e) {
|
|
1012
|
+
const s = {};
|
|
1013
|
+
for (const [n, r] of Object.entries(i)) {
|
|
1014
|
+
const o = new Pe[r](t), a = e?.[n];
|
|
1015
|
+
a && o.set(a), s[n] = o;
|
|
1016
|
+
}
|
|
1017
|
+
return s;
|
|
1018
|
+
}
|
|
1019
|
+
let Ut = 0;
|
|
1020
|
+
function Nt(i) {
|
|
1021
|
+
return { id: Ut++, name: i };
|
|
1022
|
+
}
|
|
1023
|
+
function In(i, t) {
|
|
1024
|
+
return { id: Ut++, name: i, fields: t };
|
|
1025
|
+
}
|
|
1026
|
+
function Ne(i, t, e) {
|
|
1027
|
+
return { name: i, phase: t, run: e };
|
|
1028
|
+
}
|
|
1029
|
+
const $e = 22, Q = (1 << $e) - 1, xt = 2 ** 31, b = (i) => i & Q;
|
|
1030
|
+
class ze {
|
|
1031
|
+
/** Current generation per slot; an id is alive when its generation matches and the slot is in use. */
|
|
1032
|
+
generations = [];
|
|
1033
|
+
inUse = [];
|
|
1034
|
+
free = [];
|
|
1035
|
+
live = 0;
|
|
1036
|
+
stores = [];
|
|
1037
|
+
/** Typed-array columns of the field components, by component id. */
|
|
1038
|
+
cols = [];
|
|
1039
|
+
systems = [];
|
|
1040
|
+
pending = [];
|
|
1041
|
+
/** `slots` results by the component ids asked for, rebuilt only when one of those sets changed membership. */
|
|
1042
|
+
slotCache = /* @__PURE__ */ new Map();
|
|
1043
|
+
/** Walks (`query`, `each`, system runs) in progress: structure changes wait until it is 0. */
|
|
1044
|
+
walking = 0;
|
|
1045
|
+
/** A new entity with no components. */
|
|
1046
|
+
create() {
|
|
1047
|
+
let t;
|
|
1048
|
+
if (this.free.length)
|
|
1049
|
+
t = this.free.pop();
|
|
1050
|
+
else {
|
|
1051
|
+
if (t = this.generations.length, t > Q) throw new Error("World: too many live entities");
|
|
1052
|
+
this.generations.push(0), this.inUse.push(!1);
|
|
1053
|
+
}
|
|
1054
|
+
return this.inUse[t] = !0, this.live++, this.generations[t] * (Q + 1) + t;
|
|
1055
|
+
}
|
|
1056
|
+
/** A new entity with these components. */
|
|
1057
|
+
spawn(...t) {
|
|
1058
|
+
const e = this.create();
|
|
1059
|
+
for (const [s, n] of t) this.add(e, s, n);
|
|
1060
|
+
return e;
|
|
1061
|
+
}
|
|
1062
|
+
isAlive(t) {
|
|
1063
|
+
const e = b(t);
|
|
1064
|
+
return this.inUse[e] === !0 && this.generations[e] === Math.floor(t / (Q + 1));
|
|
1065
|
+
}
|
|
1066
|
+
/** Live entities. */
|
|
1067
|
+
get size() {
|
|
1068
|
+
return this.live;
|
|
1069
|
+
}
|
|
1070
|
+
/** Removes an entity and every component it had (deferred while a walk is in progress). */
|
|
1071
|
+
destroy(t) {
|
|
1072
|
+
if (!this.isAlive(t)) return;
|
|
1073
|
+
if (this.walking > 0) {
|
|
1074
|
+
this.pending.push({ kind: "destroy", e: t });
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
const e = b(t);
|
|
1078
|
+
for (const s of this.stores) s?.delete(e, b);
|
|
1079
|
+
this.inUse[e] = !1, this.generations[e] = (this.generations[e] + 1) % xt, this.free.push(e), this.live--;
|
|
1080
|
+
}
|
|
1081
|
+
add(t, e, s) {
|
|
1082
|
+
if (!this.isAlive(t)) throw new Error(`World.add: entity ${t} is not alive`);
|
|
1083
|
+
const n = b(t);
|
|
1084
|
+
if (We(e)) {
|
|
1085
|
+
const r = this.columnsOf(e, n + 1), o = s ?? {};
|
|
1086
|
+
for (const a of Object.keys(e.fields)) r[a][n] = o[a] ?? 0;
|
|
1087
|
+
return this.store(e).set(n, t, n), n;
|
|
1088
|
+
}
|
|
1089
|
+
return this.store(e).set(n, t, s), s;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* The typed-array columns of a field component, indexed by slot. Fetch them per system run: adding entities may
|
|
1093
|
+
* grow them into new arrays.
|
|
1094
|
+
*/
|
|
1095
|
+
columns(t) {
|
|
1096
|
+
return this.columnsOf(t, this.generations.length);
|
|
1097
|
+
}
|
|
1098
|
+
get(t, e) {
|
|
1099
|
+
if (this.isAlive(t))
|
|
1100
|
+
return this.stores[e.id]?.get(b(t));
|
|
1101
|
+
}
|
|
1102
|
+
/** The component, or an error naming what is missing: for code that knows the entity has it. */
|
|
1103
|
+
require(t, e) {
|
|
1104
|
+
const s = this.stores[e.id];
|
|
1105
|
+
if (!this.isAlive(t) || !s?.has(b(t))) throw new Error(`World.require: entity ${t} has no ${e.name}`);
|
|
1106
|
+
return s.get(b(t));
|
|
1107
|
+
}
|
|
1108
|
+
has(t, e) {
|
|
1109
|
+
return this.isAlive(t) && (this.stores[e.id]?.has(b(t)) ?? !1);
|
|
1110
|
+
}
|
|
1111
|
+
/** Takes one component off an entity (deferred while a walk is in progress). */
|
|
1112
|
+
remove(t, e) {
|
|
1113
|
+
if (this.isAlive(t)) {
|
|
1114
|
+
if (this.walking > 0) {
|
|
1115
|
+
this.pending.push({ kind: "remove", e: t, type: e });
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
this.stores[e.id]?.delete(b(t), b);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
/** How many entities hold `type`. */
|
|
1122
|
+
count(t) {
|
|
1123
|
+
return this.stores[t.id]?.size ?? 0;
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Calls `fn(entity, ...components)` for every live entity holding all of `types`. Allocates nothing per entity:
|
|
1127
|
+
* the form for systems that walk thousands of bodies every step.
|
|
1128
|
+
*/
|
|
1129
|
+
each(...t) {
|
|
1130
|
+
const e = t[t.length - 1], s = t.slice(0, -1), n = this.setsFor(s);
|
|
1131
|
+
if (!n) return;
|
|
1132
|
+
const r = nt(n), o = r.entities.length;
|
|
1133
|
+
this.walking++;
|
|
1134
|
+
try {
|
|
1135
|
+
if (n.length === 1)
|
|
1136
|
+
for (let a = o - 1; a >= 0; a--) e(r.entities[a], r.values[a]);
|
|
1137
|
+
else if (n.length === 2) {
|
|
1138
|
+
const [a, h] = n;
|
|
1139
|
+
for (let l = o - 1; l >= 0; l--) {
|
|
1140
|
+
const c = r.entities[l], u = b(c);
|
|
1141
|
+
!a.has(u) || !h.has(u) || e(c, a.get(u), h.get(u));
|
|
1142
|
+
}
|
|
1143
|
+
} else {
|
|
1144
|
+
const a = new Array(n.length);
|
|
1145
|
+
for (let h = o - 1; h >= 0; h--) {
|
|
1146
|
+
const l = r.entities[h], c = b(l);
|
|
1147
|
+
let u = !0;
|
|
1148
|
+
for (let d = 0; d < n.length; d++) {
|
|
1149
|
+
const m = n[d];
|
|
1150
|
+
if (!m.has(c)) {
|
|
1151
|
+
u = !1;
|
|
1152
|
+
break;
|
|
1153
|
+
}
|
|
1154
|
+
a[d] = m.get(c);
|
|
1155
|
+
}
|
|
1156
|
+
u && e(l, ...a);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
} finally {
|
|
1160
|
+
this.endWalk();
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* The slot index of every entity holding all of `types`, as a typed array: the fastest walk there is, made for
|
|
1165
|
+
* field components (`defineFields`), whose columns are indexed by slot.
|
|
1166
|
+
*
|
|
1167
|
+
* ```ts
|
|
1168
|
+
* const p = world.columns(Position), v = world.columns(Velocity);
|
|
1169
|
+
* const slots = world.slots(Position, Velocity);
|
|
1170
|
+
* for (let k = 0; k < slots.length; k++) { const i = slots[k]!; p.x[i]! += v.x[i]! * dt; }
|
|
1171
|
+
* ```
|
|
1172
|
+
*
|
|
1173
|
+
* The result is cached and rebuilt only when an entity joins or leaves one of those components, so asking every
|
|
1174
|
+
* step is cheap. It is a view the world owns: read it, don't keep it past the step, and fetch it again after
|
|
1175
|
+
* adding or removing components.
|
|
1176
|
+
*/
|
|
1177
|
+
slots(...t) {
|
|
1178
|
+
const e = t.map((h) => h.id).join(","), s = this.setsFor(t);
|
|
1179
|
+
if (!s) return Ge;
|
|
1180
|
+
let n = this.slotCache.get(e);
|
|
1181
|
+
if (n && n.versions.every((h, l) => h === s[l].version)) return n.view;
|
|
1182
|
+
const r = nt(s), o = n && n.slots.length >= r.size ? n.slots : new Int32Array(Math.max(16, r.size));
|
|
1183
|
+
let a = 0;
|
|
1184
|
+
for (let h = 0; h < r.entities.length; h++) {
|
|
1185
|
+
const l = b(r.entities[h]);
|
|
1186
|
+
let c = !0;
|
|
1187
|
+
for (const u of s)
|
|
1188
|
+
if (u !== r && !u.has(l)) {
|
|
1189
|
+
c = !1;
|
|
1190
|
+
break;
|
|
1191
|
+
}
|
|
1192
|
+
c && (o[a++] = l);
|
|
1193
|
+
}
|
|
1194
|
+
return n = { versions: s.map((h) => h.version), slots: o, view: o.subarray(0, a) }, this.slotCache.set(e, n), n.view;
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Every live entity holding all of `types`, with those components in the same order. Yields a fresh row per
|
|
1198
|
+
* entity: convenient, but `each` is the form for hot loops.
|
|
1199
|
+
*/
|
|
1200
|
+
*query(...t) {
|
|
1201
|
+
const e = this.setsFor(t);
|
|
1202
|
+
if (!e) return;
|
|
1203
|
+
const s = nt(e);
|
|
1204
|
+
this.walking++;
|
|
1205
|
+
try {
|
|
1206
|
+
for (let n = s.entities.length - 1; n >= 0; n--) {
|
|
1207
|
+
const r = s.entities[n], o = b(r), a = [r];
|
|
1208
|
+
let h = !0;
|
|
1209
|
+
for (const l of e) {
|
|
1210
|
+
if (!l.has(o)) {
|
|
1211
|
+
h = !1;
|
|
1212
|
+
break;
|
|
1213
|
+
}
|
|
1214
|
+
a.push(l.get(o));
|
|
1215
|
+
}
|
|
1216
|
+
h && (yield a);
|
|
1217
|
+
}
|
|
1218
|
+
} finally {
|
|
1219
|
+
this.endWalk();
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
/** The first entity matching the query, or undefined: for singletons (the player, the camera target). */
|
|
1223
|
+
first(...t) {
|
|
1224
|
+
for (const e of this.query(...t)) return e;
|
|
1225
|
+
}
|
|
1226
|
+
addSystem(t) {
|
|
1227
|
+
if (this.systems.some((e) => e.name === t.name)) throw new Error(`World.addSystem: a system named "${t.name}" is already added`);
|
|
1228
|
+
return this.systems.push(t), this;
|
|
1229
|
+
}
|
|
1230
|
+
removeSystem(t) {
|
|
1231
|
+
const e = this.systems.findIndex((n) => n.name === t);
|
|
1232
|
+
if (e < 0) return;
|
|
1233
|
+
const [s] = this.systems.splice(e, 1);
|
|
1234
|
+
s.dispose?.();
|
|
1235
|
+
}
|
|
1236
|
+
/** Runs every system of `phase` in the order added. A system that throws is reported and the rest still run. */
|
|
1237
|
+
run(t, e, s) {
|
|
1238
|
+
const n = { dt: e.dt, now: e.now, alpha: e.alpha, world: this };
|
|
1239
|
+
this.walking++;
|
|
1240
|
+
try {
|
|
1241
|
+
for (const r of this.systems)
|
|
1242
|
+
if (r.phase === t)
|
|
1243
|
+
try {
|
|
1244
|
+
r.run(n);
|
|
1245
|
+
} catch (o) {
|
|
1246
|
+
if (s) s(r, o);
|
|
1247
|
+
else throw o;
|
|
1248
|
+
}
|
|
1249
|
+
} finally {
|
|
1250
|
+
this.endWalk();
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
/** Every entity, component and system gone. */
|
|
1254
|
+
clear() {
|
|
1255
|
+
for (const t of this.systems.splice(0)) t.dispose?.();
|
|
1256
|
+
for (const t of this.stores) t?.clear();
|
|
1257
|
+
this.generations = this.generations.map((t) => (t + 1) % xt), this.inUse.fill(!1), this.free.length = 0;
|
|
1258
|
+
for (let t = this.generations.length - 1; t >= 0; t--) this.free.push(t);
|
|
1259
|
+
this.live = 0, this.pending.length = 0, this.slotCache.clear();
|
|
1260
|
+
}
|
|
1261
|
+
columnsOf(t, e) {
|
|
1262
|
+
let s = this.cols[t.id];
|
|
1263
|
+
const n = s ? Object.values(s)[0]?.length ?? 0 : 0;
|
|
1264
|
+
if (!s || n < e) {
|
|
1265
|
+
let r = Math.max(64, n);
|
|
1266
|
+
for (; r < e; ) r *= 2;
|
|
1267
|
+
s = Ue(t.fields, r, s), this.cols[t.id] = s;
|
|
1268
|
+
}
|
|
1269
|
+
return s;
|
|
1270
|
+
}
|
|
1271
|
+
store(t) {
|
|
1272
|
+
let e = this.stores[t.id];
|
|
1273
|
+
return e || (e = new _e(), this.stores[t.id] = e), e;
|
|
1274
|
+
}
|
|
1275
|
+
/** The stores for `types`, or null when one has never been used (so nothing can match). */
|
|
1276
|
+
setsFor(t) {
|
|
1277
|
+
if (t.length === 0) return null;
|
|
1278
|
+
const e = [];
|
|
1279
|
+
for (const s of t) {
|
|
1280
|
+
const n = this.stores[s.id];
|
|
1281
|
+
if (!n || n.size === 0) return null;
|
|
1282
|
+
e.push(n);
|
|
1283
|
+
}
|
|
1284
|
+
return e;
|
|
1285
|
+
}
|
|
1286
|
+
endWalk() {
|
|
1287
|
+
if (this.walking--, this.walking > 0 || this.pending.length === 0) return;
|
|
1288
|
+
const t = this.pending.splice(0);
|
|
1289
|
+
for (const e of t)
|
|
1290
|
+
e.kind === "destroy" ? this.destroy(e.e) : this.remove(e.e, e.type);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
const Ge = new Int32Array(0);
|
|
1294
|
+
function nt(i) {
|
|
1295
|
+
let t = i[0];
|
|
1296
|
+
for (const e of i) e.size < t.size && (t = e);
|
|
1297
|
+
return t;
|
|
1298
|
+
}
|
|
1299
|
+
class _n {
|
|
1300
|
+
world = new ze();
|
|
1301
|
+
/** Everything the scene draws in the world goes under this (the camera moves it). */
|
|
1302
|
+
root = new M({ sortableChildren: !0 });
|
|
1303
|
+
/** Everything the scene draws on the screen (HUD) goes under this. */
|
|
1304
|
+
hud = new M();
|
|
1305
|
+
bound = null;
|
|
1306
|
+
/** The engine running this scene; only valid between `enter` and `exit`. */
|
|
1307
|
+
get engine() {
|
|
1308
|
+
if (!this.bound) throw new Error(`${this.constructor.name}: not running in an engine`);
|
|
1309
|
+
return this.bound;
|
|
1310
|
+
}
|
|
1311
|
+
/** Called once when the scene becomes active. May be async: the scene starts updating when it resolves. */
|
|
1312
|
+
onEnter() {
|
|
1313
|
+
}
|
|
1314
|
+
/** Called when the scene is removed. The world and containers are cleared after it returns. */
|
|
1315
|
+
onExit() {
|
|
1316
|
+
}
|
|
1317
|
+
/** Called when another scene is pushed over this one. */
|
|
1318
|
+
onPause() {
|
|
1319
|
+
}
|
|
1320
|
+
/** Called when the scene over this one is popped. */
|
|
1321
|
+
onResume() {
|
|
1322
|
+
}
|
|
1323
|
+
/** Once per simulation step, `dt` in seconds. */
|
|
1324
|
+
fixedUpdate(t) {
|
|
1325
|
+
}
|
|
1326
|
+
/** Once per rendered frame, `dt` in seconds; `alpha` is the share of a step since the last one (0–1). */
|
|
1327
|
+
update(t, e) {
|
|
1328
|
+
}
|
|
1329
|
+
/** @internal Engine-side wiring; games call `engine.scenes`. */
|
|
1330
|
+
attach(t) {
|
|
1331
|
+
this.bound = t, t.stage.world.addChild(this.root), t.stage.screen.addChild(this.hud);
|
|
1332
|
+
}
|
|
1333
|
+
/** @internal Clears what the scene made but keeps its containers, so the same scene may be entered again. */
|
|
1334
|
+
detach() {
|
|
1335
|
+
this.world.clear();
|
|
1336
|
+
for (const t of [this.root, this.hud]) {
|
|
1337
|
+
for (const e of t.removeChildren()) e.destroy({ children: !0 });
|
|
1338
|
+
t.removeFromParent();
|
|
1339
|
+
}
|
|
1340
|
+
this.bound = null;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
const N = 2, qe = 1024, lt = 8192, Ye = 4096;
|
|
1344
|
+
function Pn(i) {
|
|
1345
|
+
return i === null || i >= lt ? lt : Math.min(Ye, 2 ** Math.floor(Math.log2(Math.max(1, i))));
|
|
1346
|
+
}
|
|
1347
|
+
function je(i, t) {
|
|
1348
|
+
const e = i.map((f, p) => p).sort((f, p) => i[p].h - i[f].h), s = i.reduce((f, p) => f + (p.w + N) * (p.h + N), 0), n = Math.max(1, ...i.map((f) => f.w + N)), r = Math.min(t, Math.max(qe, 2 ** Math.ceil(Math.log2(Math.max(n, Math.sqrt(s)))))), o = new Array(i.length), a = [];
|
|
1349
|
+
let h = 0, l = 0, c = 0, u = 0, d = r;
|
|
1350
|
+
const m = () => a.push({ width: d, height: c + u });
|
|
1351
|
+
for (const f of e) {
|
|
1352
|
+
const p = i[f].w + N, g = i[f].h + N;
|
|
1353
|
+
l > 0 && l + p > d && (l = 0, c += u, u = 0), c > 0 && c + g > t && (m(), h++, l = 0, c = 0, u = 0, d = r), p > d && (d = p), o[f] = { page: h, x: l, y: c }, l += p, u = Math.max(u, g);
|
|
1354
|
+
}
|
|
1355
|
+
return i.length > 0 && m(), { pages: a, places: o };
|
|
1356
|
+
}
|
|
1357
|
+
class Wn {
|
|
1358
|
+
items = [];
|
|
1359
|
+
add(t, e) {
|
|
1360
|
+
this.items.push({ name: t, canvas: e });
|
|
1361
|
+
}
|
|
1362
|
+
addSheet(t, e, s, n) {
|
|
1363
|
+
this.items.push({ name: t, canvas: e, frameWidth: s, frameHeight: n });
|
|
1364
|
+
}
|
|
1365
|
+
build(t, e, s = lt) {
|
|
1366
|
+
const n = this.items, r = je(n.map((c) => ({ w: c.canvas.width, h: c.canvas.height })), s), o = r.pages.map((c, u) => {
|
|
1367
|
+
const d = document.createElement("canvas");
|
|
1368
|
+
return d.width = c.width, d.height = c.height, { canvas: d, ctx: d.getContext("2d", { willReadFrequently: !0 }), key: u === 0 ? e : `${e}~${u}` };
|
|
1369
|
+
});
|
|
1370
|
+
n.forEach((c, u) => {
|
|
1371
|
+
const d = r.places[u];
|
|
1372
|
+
o[d.page].ctx.drawImage(c.canvas, d.x, d.y);
|
|
1373
|
+
});
|
|
1374
|
+
const a = t.addCanvas(e, o[0].canvas), h = o.map((c, u) => u === 0 ? a : t.addCanvas(c.key, c.canvas));
|
|
1375
|
+
n.forEach((c, u) => {
|
|
1376
|
+
const d = r.places[u], m = h[d.page], f = (p, g, y, w, v) => {
|
|
1377
|
+
m.add(p, 0, g, y, w, v), d.page > 0 && a.adopt(p, m);
|
|
1378
|
+
};
|
|
1379
|
+
if (c.frameWidth && c.frameHeight) {
|
|
1380
|
+
const p = Math.floor(c.canvas.width / c.frameWidth), g = Math.max(1, Math.floor(c.canvas.height / c.frameHeight));
|
|
1381
|
+
for (let y = 0; y < p * g; y++)
|
|
1382
|
+
f(`${c.name}#${y}`, d.x + y % p * c.frameWidth, d.y + Math.floor(y / p) * c.frameHeight, c.frameWidth, c.frameHeight);
|
|
1383
|
+
} else
|
|
1384
|
+
f(c.name, d.x, d.y, c.canvas.width, c.canvas.height);
|
|
1385
|
+
});
|
|
1386
|
+
const l = r.pages.map((c) => `${c.width}x${c.height}`).join(" + ");
|
|
1387
|
+
console.info(`[atlas] ${e}: ${n.length} images packed into ${l}${r.pages.length > 1 ? ` (pages of ${s})` : ""}`);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
const Ve = 2147483648, Xe = 1073741824, Je = 536870912, Ke = 536870911, $t = (i) => i & Ke;
|
|
1391
|
+
function zt(i, t) {
|
|
1392
|
+
const e = $t(t);
|
|
1393
|
+
if (e === 0) return null;
|
|
1394
|
+
let s = null;
|
|
1395
|
+
for (const n of i.tilesets) n.firstGid <= e && (!s || n.firstGid > s.firstGid) && (s = n);
|
|
1396
|
+
return !s || e - s.firstGid >= s.tileCount ? null : { tileset: s, local: e - s.firstGid };
|
|
1397
|
+
}
|
|
1398
|
+
function Ze(i, t) {
|
|
1399
|
+
const e = t % i.columns, s = Math.floor(t / i.columns);
|
|
1400
|
+
return { x: i.margin + e * (i.tileWidth + i.spacing), y: i.margin + s * (i.tileHeight + i.spacing), w: i.tileWidth, h: i.tileHeight };
|
|
1401
|
+
}
|
|
1402
|
+
function Un(i, t) {
|
|
1403
|
+
return i.layers.find((e) => e.name === t);
|
|
1404
|
+
}
|
|
1405
|
+
function Nn(i, t) {
|
|
1406
|
+
const e = [];
|
|
1407
|
+
for (const s of i.layers) if (s.kind === "objects")
|
|
1408
|
+
for (const n of s.objects) (t === void 0 || n.type === t) && e.push(n);
|
|
1409
|
+
return e;
|
|
1410
|
+
}
|
|
1411
|
+
class F extends Error {
|
|
1412
|
+
constructor(t) {
|
|
1413
|
+
super(`Tiled map: ${t}`);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
function _(i) {
|
|
1417
|
+
const t = {};
|
|
1418
|
+
if (!Array.isArray(i)) return t;
|
|
1419
|
+
for (const e of i) e && typeof e.name == "string" && ["string", "number", "boolean"].includes(typeof e.value) && (t[e.name] = e.value);
|
|
1420
|
+
return t;
|
|
1421
|
+
}
|
|
1422
|
+
function x(i, t) {
|
|
1423
|
+
if (typeof i != "number" || !Number.isFinite(i)) throw new F(`${t} must be a number`);
|
|
1424
|
+
return i;
|
|
1425
|
+
}
|
|
1426
|
+
function Qe(i) {
|
|
1427
|
+
if (typeof atob == "function") {
|
|
1428
|
+
const t = atob(i.trim()), e = new Uint8Array(t.length);
|
|
1429
|
+
for (let s = 0; s < t.length; s++) e[s] = t.charCodeAt(s);
|
|
1430
|
+
return e;
|
|
1431
|
+
}
|
|
1432
|
+
return new Uint8Array(globalThis.Buffer.from(i, "base64"));
|
|
1433
|
+
}
|
|
1434
|
+
function ts(i, t) {
|
|
1435
|
+
if (i.compression) throw new F(`layer "${i.name}" is ${i.compression}-compressed; save it as CSV or uncompressed base64`);
|
|
1436
|
+
let e;
|
|
1437
|
+
if (i.encoding === "base64") {
|
|
1438
|
+
const s = Qe(String(i.data));
|
|
1439
|
+
if (s.length !== t * 4) throw new F(`layer "${i.name}" holds ${s.length / 4} cells, not ${t}`);
|
|
1440
|
+
const n = new DataView(s.buffer, s.byteOffset, s.byteLength);
|
|
1441
|
+
e = new Uint32Array(t);
|
|
1442
|
+
for (let r = 0; r < t; r++) e[r] = n.getUint32(r * 4, !0);
|
|
1443
|
+
} else {
|
|
1444
|
+
if (!Array.isArray(i.data) || i.data.length !== t) throw new F(`layer "${i.name}" must hold ${t} cells`);
|
|
1445
|
+
e = Uint32Array.from(i.data);
|
|
1446
|
+
}
|
|
1447
|
+
return e;
|
|
1448
|
+
}
|
|
1449
|
+
function es(i) {
|
|
1450
|
+
const t = {
|
|
1451
|
+
id: x(i.id, "object id"),
|
|
1452
|
+
name: String(i.name ?? ""),
|
|
1453
|
+
type: String(i.type ?? i.class ?? ""),
|
|
1454
|
+
x: x(i.x, "object x"),
|
|
1455
|
+
y: x(i.y, "object y"),
|
|
1456
|
+
width: Number(i.width ?? 0),
|
|
1457
|
+
height: Number(i.height ?? 0),
|
|
1458
|
+
rotation: Number(i.rotation ?? 0),
|
|
1459
|
+
point: i.point === !0,
|
|
1460
|
+
ellipse: i.ellipse === !0,
|
|
1461
|
+
properties: _(i.properties)
|
|
1462
|
+
};
|
|
1463
|
+
return typeof i.gid == "number" && (t.gid = i.gid), Array.isArray(i.polygon) && (t.polygon = i.polygon.map((e) => ({ x: x(e.x, "polygon x"), y: x(e.y, "polygon y") }))), t;
|
|
1464
|
+
}
|
|
1465
|
+
function Gt(i, t, e, s = { visible: !0, opacity: 1, x: 0, y: 0 }) {
|
|
1466
|
+
if (Array.isArray(i))
|
|
1467
|
+
for (const n of i) {
|
|
1468
|
+
const r = s.visible && n.visible !== !1, o = s.opacity * (typeof n.opacity == "number" ? n.opacity : 1), a = s.x + Number(n.offsetx ?? 0), h = s.y + Number(n.offsety ?? 0);
|
|
1469
|
+
n.type === "tilelayer" ? e.push({ kind: "tiles", name: String(n.name ?? ""), data: ts(n, t.width * t.height), visible: r, opacity: o, offsetX: a, offsetY: h, properties: _(n.properties) }) : n.type === "objectgroup" ? e.push({ kind: "objects", name: String(n.name ?? ""), objects: (n.objects ?? []).map(es), visible: r, properties: _(n.properties) }) : n.type === "group" && Gt(n.layers, t, e, { visible: r, opacity: o, x: a, y: h });
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
function ss(i) {
|
|
1473
|
+
if (typeof i.source == "string") throw new F(`tileset "${i.source}" is external; embed it in the map (Map → Embed Tilesets)`);
|
|
1474
|
+
if (typeof i.image != "string") throw new F(`tileset "${i.name}" is a collection of images; use a single-image tileset`);
|
|
1475
|
+
const t = /* @__PURE__ */ new Map(), e = /* @__PURE__ */ new Map();
|
|
1476
|
+
for (const s of i.tiles ?? []) {
|
|
1477
|
+
const n = x(s.id, "tile id");
|
|
1478
|
+
s.properties && t.set(n, _(s.properties)), Array.isArray(s.animation) && e.set(n, s.animation.map((r) => ({ tileId: x(r.tileid, "animation tileid"), duration: x(r.duration, "animation duration") })));
|
|
1479
|
+
}
|
|
1480
|
+
return {
|
|
1481
|
+
name: String(i.name ?? ""),
|
|
1482
|
+
firstGid: x(i.firstgid, "tileset firstgid"),
|
|
1483
|
+
image: i.image,
|
|
1484
|
+
imageWidth: x(i.imagewidth, "tileset imagewidth"),
|
|
1485
|
+
imageHeight: x(i.imageheight, "tileset imageheight"),
|
|
1486
|
+
tileWidth: x(i.tilewidth, "tileset tilewidth"),
|
|
1487
|
+
tileHeight: x(i.tileheight, "tileset tileheight"),
|
|
1488
|
+
columns: x(i.columns, "tileset columns"),
|
|
1489
|
+
tileCount: x(i.tilecount, "tileset tilecount"),
|
|
1490
|
+
margin: Number(i.margin ?? 0),
|
|
1491
|
+
spacing: Number(i.spacing ?? 0),
|
|
1492
|
+
tileProperties: t,
|
|
1493
|
+
animations: e,
|
|
1494
|
+
properties: _(i.properties)
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
function is(i) {
|
|
1498
|
+
const t = i;
|
|
1499
|
+
if (!t || typeof t != "object") throw new F("not a JSON object");
|
|
1500
|
+
if (t.infinite) throw new F("infinite maps are not supported; uncheck Map → Map Properties → Infinite");
|
|
1501
|
+
if (t.orientation && t.orientation !== "orthogonal") throw new F(`${t.orientation} maps are not supported, only orthogonal`);
|
|
1502
|
+
const e = x(t.width, "width"), s = x(t.height, "height"), n = [];
|
|
1503
|
+
Gt(t.layers, { width: e, height: s }, n);
|
|
1504
|
+
const r = {
|
|
1505
|
+
width: e,
|
|
1506
|
+
height: s,
|
|
1507
|
+
tileWidth: x(t.tilewidth, "tilewidth"),
|
|
1508
|
+
tileHeight: x(t.tileheight, "tileheight"),
|
|
1509
|
+
layers: n,
|
|
1510
|
+
tilesets: (t.tilesets ?? []).map(ss),
|
|
1511
|
+
properties: _(t.properties)
|
|
1512
|
+
};
|
|
1513
|
+
return typeof t.backgroundcolor == "string" && (r.backgroundColor = t.backgroundcolor), r;
|
|
1514
|
+
}
|
|
1515
|
+
function bt(i, t) {
|
|
1516
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(i) || i.startsWith("/")) return i;
|
|
1517
|
+
const s = (t.slice(0, t.lastIndexOf("/") + 1) + i).split("/"), n = [];
|
|
1518
|
+
for (const r of s)
|
|
1519
|
+
r === ".." && n.length && n[n.length - 1] !== ".." && n[n.length - 1] !== "" ? n.pop() : r !== "." && n.push(r);
|
|
1520
|
+
return n.join("/");
|
|
1521
|
+
}
|
|
1522
|
+
async function ns(i) {
|
|
1523
|
+
const t = await createImageBitmap(i), e = document.createElement("canvas");
|
|
1524
|
+
e.width = t.width, e.height = t.height;
|
|
1525
|
+
const s = e.getContext("2d");
|
|
1526
|
+
if (!s) throw new Error("AssetLoader: no 2D context (out of canvas memory?)");
|
|
1527
|
+
return s.drawImage(t, 0, 0), t.close(), e;
|
|
1528
|
+
}
|
|
1529
|
+
class $n {
|
|
1530
|
+
constructor(t, e = {}) {
|
|
1531
|
+
this.textures = t, this.options = e, this.fetcher = e.fetch ?? ((s) => fetch(s)), this.toCanvas = e.toCanvas ?? ns;
|
|
1532
|
+
}
|
|
1533
|
+
textures;
|
|
1534
|
+
options;
|
|
1535
|
+
queue = [];
|
|
1536
|
+
data = /* @__PURE__ */ new Map();
|
|
1537
|
+
maps = /* @__PURE__ */ new Map();
|
|
1538
|
+
fetcher;
|
|
1539
|
+
toCanvas;
|
|
1540
|
+
total = 0;
|
|
1541
|
+
done = 0;
|
|
1542
|
+
image(t, e) {
|
|
1543
|
+
return this.add(t, async () => {
|
|
1544
|
+
this.textures.addCanvas(t, await this.toCanvas(await this.blob(e)));
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
/** An image cut into equal frames named 0, 1, 2…, left to right, then row by row. */
|
|
1548
|
+
spritesheet(t, e, s) {
|
|
1549
|
+
return this.add(t, async () => {
|
|
1550
|
+
this.textures.addSpriteSheet(t, await this.toCanvas(await this.blob(e)), s);
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
json(t, e) {
|
|
1554
|
+
return this.add(t, async () => {
|
|
1555
|
+
this.data.set(t, await (await this.request(e)).json());
|
|
1556
|
+
});
|
|
1557
|
+
}
|
|
1558
|
+
text(t, e) {
|
|
1559
|
+
return this.add(t, async () => {
|
|
1560
|
+
this.data.set(t, await (await this.request(e)).text());
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
/** A Tiled JSON map, then every tileset image it names (resolved beside the map file). */
|
|
1564
|
+
tilemap(t, e, s = {}) {
|
|
1565
|
+
return this.add(t, async () => {
|
|
1566
|
+
const n = is(await (await this.request(e)).json());
|
|
1567
|
+
this.maps.set(t, n);
|
|
1568
|
+
const r = s.textureKey ?? ((o) => o.name);
|
|
1569
|
+
for (const o of n.tilesets) this.image(r(o), bt(o.image, e));
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
/** Runs everything queued; `onProgress` after each asset. Safe to call again after queueing more. */
|
|
1573
|
+
async load(t) {
|
|
1574
|
+
const e = Math.max(1, this.options.concurrency ?? 6), s = async () => {
|
|
1575
|
+
for (let n = this.queue.shift(); n; n = this.queue.shift())
|
|
1576
|
+
await n.run(), this.done++, t?.({ done: this.done, total: this.total, key: n.key });
|
|
1577
|
+
};
|
|
1578
|
+
for (; this.queue.length; ) await Promise.all(Array.from({ length: e }, s));
|
|
1579
|
+
}
|
|
1580
|
+
/** A loaded JSON value. */
|
|
1581
|
+
getJson(t) {
|
|
1582
|
+
if (!this.data.has(t)) throw new Error(`AssetLoader: no JSON or text loaded as "${t}"`);
|
|
1583
|
+
return this.data.get(t);
|
|
1584
|
+
}
|
|
1585
|
+
/** A loaded text file. */
|
|
1586
|
+
getText(t) {
|
|
1587
|
+
return this.getJson(t);
|
|
1588
|
+
}
|
|
1589
|
+
/** A loaded Tiled map. */
|
|
1590
|
+
map(t) {
|
|
1591
|
+
const e = this.maps.get(t);
|
|
1592
|
+
if (!e) throw new Error(`AssetLoader: no tilemap loaded as "${t}"`);
|
|
1593
|
+
return e;
|
|
1594
|
+
}
|
|
1595
|
+
add(t, e) {
|
|
1596
|
+
return this.queue.push({ key: t, run: e }), this.total++, this;
|
|
1597
|
+
}
|
|
1598
|
+
async request(t) {
|
|
1599
|
+
const e = bt(t, this.options.baseUrl ?? "");
|
|
1600
|
+
let s;
|
|
1601
|
+
try {
|
|
1602
|
+
s = await this.fetcher(e);
|
|
1603
|
+
} catch (n) {
|
|
1604
|
+
throw new Error(`AssetLoader: could not fetch ${e}: ${n instanceof Error ? n.message : String(n)}`);
|
|
1605
|
+
}
|
|
1606
|
+
if (!s.ok) throw new Error(`AssetLoader: ${e} answered ${s.status}`);
|
|
1607
|
+
return s;
|
|
1608
|
+
}
|
|
1609
|
+
async blob(t) {
|
|
1610
|
+
return (await this.request(t)).blob();
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
class zn {
|
|
1614
|
+
constructor(t, e) {
|
|
1615
|
+
this.clips = t;
|
|
1616
|
+
const s = t[e];
|
|
1617
|
+
if (!s) throw new Error(`Animator: no clip "${e}"`);
|
|
1618
|
+
if (s.frames.length === 0) throw new Error(`Animator: clip "${e}" has no frames`);
|
|
1619
|
+
this.clip = s, this.name = e;
|
|
1620
|
+
}
|
|
1621
|
+
clips;
|
|
1622
|
+
clip;
|
|
1623
|
+
index = 0;
|
|
1624
|
+
elapsed = 0;
|
|
1625
|
+
ended = !1;
|
|
1626
|
+
name;
|
|
1627
|
+
/** Called when a clip that does not loop reaches its last frame. */
|
|
1628
|
+
onComplete = null;
|
|
1629
|
+
/** Playback speed multiplier (1 normal, 0 paused). */
|
|
1630
|
+
speed = 1;
|
|
1631
|
+
/** The clip playing. */
|
|
1632
|
+
get current() {
|
|
1633
|
+
return this.name;
|
|
1634
|
+
}
|
|
1635
|
+
/** The frame to show now. */
|
|
1636
|
+
get frame() {
|
|
1637
|
+
return this.clip.frames[this.index];
|
|
1638
|
+
}
|
|
1639
|
+
/** Which frame of the clip (0-based). */
|
|
1640
|
+
get frameIndex() {
|
|
1641
|
+
return this.index;
|
|
1642
|
+
}
|
|
1643
|
+
/** A non-looping clip has reached its last frame. */
|
|
1644
|
+
get finished() {
|
|
1645
|
+
return this.ended;
|
|
1646
|
+
}
|
|
1647
|
+
/** Plays `name`. The clip already playing keeps its place unless `restart`. */
|
|
1648
|
+
play(t, e = !1) {
|
|
1649
|
+
if (t === this.name && !e) return this;
|
|
1650
|
+
const s = this.clips[t];
|
|
1651
|
+
if (!s) throw new Error(`Animator: no clip "${t}"`);
|
|
1652
|
+
if (s.frames.length === 0) throw new Error(`Animator: clip "${t}" has no frames`);
|
|
1653
|
+
return this.clip = s, this.name = t, this.index = 0, this.elapsed = 0, this.ended = !1, this;
|
|
1654
|
+
}
|
|
1655
|
+
/** Advances by `dt` seconds; returns true when the frame changed. */
|
|
1656
|
+
update(t) {
|
|
1657
|
+
if (this.ended || !(t > 0) || this.speed <= 0) return !1;
|
|
1658
|
+
this.elapsed += t * 1e3 * this.speed;
|
|
1659
|
+
const e = this.index, s = this.clip.frames.length;
|
|
1660
|
+
for (let n = this.lengthOf(this.index); this.elapsed >= n; n = this.lengthOf(this.index))
|
|
1661
|
+
if (this.elapsed -= n, this.index < s - 1)
|
|
1662
|
+
this.index++;
|
|
1663
|
+
else if (this.clip.loop !== !1)
|
|
1664
|
+
this.index = 0;
|
|
1665
|
+
else {
|
|
1666
|
+
this.ended = !0, this.elapsed = 0, this.onComplete?.(this.name);
|
|
1667
|
+
break;
|
|
1668
|
+
}
|
|
1669
|
+
return this.index !== e;
|
|
1670
|
+
}
|
|
1671
|
+
lengthOf(t) {
|
|
1672
|
+
const e = this.clip.durations?.[t] ?? 1e3 / (this.clip.fps ?? 10);
|
|
1673
|
+
return Math.max(1, e);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
const rs = Nt("Sprite"), os = Nt("Animation");
|
|
1677
|
+
function Gn(i = "animation") {
|
|
1678
|
+
return Ne(i, "frame", ({ world: t, dt: e }) => {
|
|
1679
|
+
t.each(rs, os, (s, n, r) => {
|
|
1680
|
+
(r.update(e) || n.frameName !== String(r.frame)) && n.setFrame(r.frame);
|
|
1681
|
+
});
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
const vt = 0.7071067811865476;
|
|
1685
|
+
function as(i, t, e, s, n = {}) {
|
|
1686
|
+
if (s.length !== i * t)
|
|
1687
|
+
throw new Error(`collision string length ${s.length} != ${i}x${t}`);
|
|
1688
|
+
const r = new Uint8Array(i * t);
|
|
1689
|
+
for (let u = 0; u < r.length; u++) r[u] = s.charCodeAt(u) === 49 ? 1 : 0;
|
|
1690
|
+
const { ground: o } = n, a = new Set(n.shotOverTiles ?? []);
|
|
1691
|
+
let h;
|
|
1692
|
+
if (o && o.length === r.length && a.size) {
|
|
1693
|
+
h = new Uint8Array(r.length);
|
|
1694
|
+
for (let u = 0; u < r.length; u++) h[u] = r[u] && a.has(o[u]) ? 1 : 0;
|
|
1695
|
+
}
|
|
1696
|
+
const l = n.bodyHalfWidth ?? fe, c = n.bodyHalfHeight ?? pe;
|
|
1697
|
+
return h ? { width: i, height: t, tileSize: e, solid: r, shotOver: h, bodyHalfWidth: l, bodyHalfHeight: c } : { width: i, height: t, tileSize: e, solid: r, bodyHalfWidth: l, bodyHalfHeight: c };
|
|
1698
|
+
}
|
|
1699
|
+
function qn(i, t, e) {
|
|
1700
|
+
return P(i, t, e) ? i.shotOver?.[e * i.width + t] !== 1 : !1;
|
|
1701
|
+
}
|
|
1702
|
+
function qt(i, t) {
|
|
1703
|
+
return { x: i, y: t, lastDx: 1, lastDy: 0, dashLeft: 0, dashCd: 0, dashDx: 1, dashDy: 0 };
|
|
1704
|
+
}
|
|
1705
|
+
function P(i, t, e) {
|
|
1706
|
+
return t < 0 || e < 0 || t >= i.width || e >= i.height ? !0 : i.solid[e * i.width + t] === 1;
|
|
1707
|
+
}
|
|
1708
|
+
function Yn(i, t, e) {
|
|
1709
|
+
const s = i.tileSize, n = Math.floor((t - i.bodyHalfWidth) / s), r = Math.floor((t + i.bodyHalfWidth) / s), o = Math.floor((e - i.bodyHalfHeight) / s), a = Math.floor((e + i.bodyHalfHeight) / s);
|
|
1710
|
+
for (let h = o; h <= a; h++)
|
|
1711
|
+
for (let l = n; l <= r; l++)
|
|
1712
|
+
if (P(i, l, h)) return !0;
|
|
1713
|
+
return !1;
|
|
1714
|
+
}
|
|
1715
|
+
function hs(i, t, e, s) {
|
|
1716
|
+
if (s === 0) return t;
|
|
1717
|
+
const n = i.tileSize, r = t + s, o = Math.floor((e - i.bodyHalfHeight) / n), a = Math.floor((e + i.bodyHalfHeight) / n);
|
|
1718
|
+
if (s > 0) {
|
|
1719
|
+
const h = Math.floor((r + i.bodyHalfWidth) / n);
|
|
1720
|
+
for (let l = o; l <= a; l++)
|
|
1721
|
+
if (P(i, h, l)) return h * n - i.bodyHalfWidth - tt;
|
|
1722
|
+
} else {
|
|
1723
|
+
const h = Math.floor((r - i.bodyHalfWidth) / n);
|
|
1724
|
+
for (let l = o; l <= a; l++)
|
|
1725
|
+
if (P(i, h, l)) return (h + 1) * n + i.bodyHalfWidth + tt;
|
|
1726
|
+
}
|
|
1727
|
+
return r;
|
|
1728
|
+
}
|
|
1729
|
+
function ls(i, t, e, s) {
|
|
1730
|
+
if (s === 0) return e;
|
|
1731
|
+
const n = i.tileSize, r = e + s, o = Math.floor((t - i.bodyHalfWidth) / n), a = Math.floor((t + i.bodyHalfWidth) / n);
|
|
1732
|
+
if (s > 0) {
|
|
1733
|
+
const h = Math.floor((r + i.bodyHalfHeight) / n);
|
|
1734
|
+
for (let l = o; l <= a; l++)
|
|
1735
|
+
if (P(i, l, h)) return h * n - i.bodyHalfHeight - tt;
|
|
1736
|
+
} else {
|
|
1737
|
+
const h = Math.floor((r - i.bodyHalfHeight) / n);
|
|
1738
|
+
for (let l = o; l <= a; l++)
|
|
1739
|
+
if (P(i, l, h)) return (h + 1) * n + i.bodyHalfHeight + tt;
|
|
1740
|
+
}
|
|
1741
|
+
return r;
|
|
1742
|
+
}
|
|
1743
|
+
function Mt(i) {
|
|
1744
|
+
return i > 0 ? 1 : i < 0 ? -1 : 0;
|
|
1745
|
+
}
|
|
1746
|
+
function ct(i, t, e, s) {
|
|
1747
|
+
i.dashCd > 0 && i.dashCd--;
|
|
1748
|
+
const n = i.dashLeft > 0;
|
|
1749
|
+
let r = e.canMove && !n ? Mt(t[0]) : 0, o = e.canMove && !n ? Mt(t[1]) : 0;
|
|
1750
|
+
r !== 0 && o !== 0 && (r = r * vt, o = o * vt), (r !== 0 || o !== 0) && (i.lastDx = r, i.lastDy = o), (t[2] & me) !== 0 && e.canDash && e.canMove && i.dashLeft === 0 && i.dashCd === 0 && (i.dashLeft = e.dashSteps, i.dashCd = e.dashCooldownSteps, i.dashDx = i.lastDx, i.dashDy = i.lastDy);
|
|
1751
|
+
let a, h;
|
|
1752
|
+
i.dashLeft > 0 ? (a = i.dashDx * e.dashSpeed, h = i.dashDy * e.dashSpeed, i.dashLeft--) : (a = r * e.speed, h = o * e.speed), i.x = hs(s, i.x, i.y, a * gt), i.y = ls(s, i.x, i.y, h * gt);
|
|
1753
|
+
}
|
|
1754
|
+
function jn(i, t = {}) {
|
|
1755
|
+
if (i.tileWidth !== i.tileHeight) throw new Error(`Tiled map: collision needs square tiles, not ${i.tileWidth}x${i.tileHeight}`);
|
|
1756
|
+
const e = t.solid ?? (i.layers.some((h) => h.kind === "tiles" && h.name === "collision") ? "collision" : { property: "solid" }), s = i.width * i.height, n = new Uint8Array(s);
|
|
1757
|
+
if (typeof e == "string") {
|
|
1758
|
+
const h = i.layers.find((l) => l.kind === "tiles" && l.name === e);
|
|
1759
|
+
if (!h || h.kind !== "tiles") throw new Error(`Tiled map: no tile layer named "${e}"`);
|
|
1760
|
+
for (let l = 0; l < s; l++) $t(h.data[l]) !== 0 && (n[l] = 1);
|
|
1761
|
+
} else
|
|
1762
|
+
for (const h of i.layers)
|
|
1763
|
+
if (h.kind === "tiles")
|
|
1764
|
+
for (let l = 0; l < s; l++) {
|
|
1765
|
+
const c = zt(i, h.data[l]);
|
|
1766
|
+
c && c.tileset.tileProperties.get(c.local)?.[e.property] === !0 && (n[l] = 1);
|
|
1767
|
+
}
|
|
1768
|
+
let r = "";
|
|
1769
|
+
for (let h = 0; h < s; h++) r += n[h] ? "1" : "0";
|
|
1770
|
+
const { solid: o, ...a } = t;
|
|
1771
|
+
return as(i.width, i.height, i.tileWidth, r, a);
|
|
1772
|
+
}
|
|
1773
|
+
let cs = 0;
|
|
1774
|
+
class Vn {
|
|
1775
|
+
constructor(t, e, s = {}) {
|
|
1776
|
+
this.stage = t, this.map = e;
|
|
1777
|
+
const n = s.textureFor ?? ((c) => c.name), r = Math.max(1, s.chunkTiles ?? 32), o = s.baseDepth ?? -1e6, a = s.layers ? new Set(s.layers) : null, h = e.layers.filter((c) => c.kind === "tiles" && (a ? a.has(c.name) : c.visible)), l = s.parent ?? t.world;
|
|
1778
|
+
h.forEach((c, u) => {
|
|
1779
|
+
const d = typeof c.properties.depth == "number" ? c.properties.depth : o + u, m = new M();
|
|
1780
|
+
m.zIndex = d, m.alpha = c.opacity, m.position.set(c.offsetX, c.offsetY), this.layers.set(c.name, m), l.addChild(m);
|
|
1781
|
+
for (let f = 0; f < e.height; f += r)
|
|
1782
|
+
for (let p = 0; p < e.width; p += r) {
|
|
1783
|
+
const g = Math.min(r, e.width - p), y = Math.min(r, e.height - f);
|
|
1784
|
+
this.paintChunk(c, m, p, f, g, y, n);
|
|
1785
|
+
}
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
stage;
|
|
1789
|
+
map;
|
|
1790
|
+
/** One container per drawn tile layer, by name, each at its own depth among the bodies. */
|
|
1791
|
+
layers = /* @__PURE__ */ new Map();
|
|
1792
|
+
chunks = [];
|
|
1793
|
+
id = cs++;
|
|
1794
|
+
/** Shows only the chunks in the camera's view (plus a margin in world px). Call once a frame. */
|
|
1795
|
+
update(t = 32) {
|
|
1796
|
+
const e = this.stage.cameras.main.worldView;
|
|
1797
|
+
for (const s of this.chunks)
|
|
1798
|
+
s.sprite.visible = s.x < e.right + t && s.x + s.w > e.x - t && s.y < e.bottom + t && s.y + s.h > e.y - t;
|
|
1799
|
+
}
|
|
1800
|
+
/** World size of the map in px. */
|
|
1801
|
+
get widthPx() {
|
|
1802
|
+
return this.map.width * this.map.tileWidth;
|
|
1803
|
+
}
|
|
1804
|
+
get heightPx() {
|
|
1805
|
+
return this.map.height * this.map.tileHeight;
|
|
1806
|
+
}
|
|
1807
|
+
destroy() {
|
|
1808
|
+
for (const t of this.chunks) this.stage.textures.remove(t.key);
|
|
1809
|
+
this.chunks.length = 0;
|
|
1810
|
+
for (const t of this.layers.values()) t.destroy({ children: !0 });
|
|
1811
|
+
this.layers.clear();
|
|
1812
|
+
}
|
|
1813
|
+
paintChunk(t, e, s, n, r, o, a) {
|
|
1814
|
+
const { map: h } = this, l = h.tileWidth, c = h.tileHeight;
|
|
1815
|
+
let u = !1;
|
|
1816
|
+
const d = `tilemap:${this.id}:${t.name}:${s},${n}`, f = Math.max(c, ...h.tilesets.map((w) => w.tileHeight)) - c, p = this.stage.textures.createCanvas(d, r * l, o * c + f), g = p.context;
|
|
1817
|
+
g.imageSmoothingEnabled = !1;
|
|
1818
|
+
for (let w = 0; w < o; w++)
|
|
1819
|
+
for (let v = 0; v < r; v++) {
|
|
1820
|
+
const L = t.data[(n + w) * h.width + (s + v)], D = zt(h, L);
|
|
1821
|
+
if (!D) continue;
|
|
1822
|
+
const mt = this.stage.textures.exists(a(D.tileset)) ? this.stage.textures.get(a(D.tileset)).source.resource : null;
|
|
1823
|
+
if (!mt) continue;
|
|
1824
|
+
const A = Ze(D.tileset, D.local), Qt = v * l, te = f + (w + 1) * c - A.h;
|
|
1825
|
+
g.save(), g.translate(Qt + A.w / 2, te + A.h / 2), L & Je && g.transform(0, 1, 1, 0, 0, 0), g.scale(L & Ve ? -1 : 1, L & Xe ? -1 : 1), g.drawImage(mt, A.x, A.y, A.w, A.h, -A.w / 2, -A.h / 2, A.w, A.h), g.restore(), u = !0;
|
|
1826
|
+
}
|
|
1827
|
+
if (!u) {
|
|
1828
|
+
this.stage.textures.remove(d);
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
p.refresh();
|
|
1832
|
+
const y = new R(p.whole);
|
|
1833
|
+
y.position.set(s * l, n * c - f), e.addChild(y), this.chunks.push({ sprite: y, x: y.x + t.offsetX, y: y.y + t.offsetY, w: r * l, h: o * c + f, key: d });
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
const At = Math.PI / 180, X = [90, 2, 0, 2];
|
|
1837
|
+
function T(i, t, e) {
|
|
1838
|
+
return { x: i.x + t, y: i.y + e };
|
|
1839
|
+
}
|
|
1840
|
+
function J(i, t) {
|
|
1841
|
+
const [e, s, n, r] = t, o = e * At, a = (e + n) * At, h = T(i, Math.cos(o) * s, Math.sin(o) * s);
|
|
1842
|
+
return [h, T(h, Math.cos(a) * r, Math.sin(a) * r), a];
|
|
1843
|
+
}
|
|
1844
|
+
class us {
|
|
1845
|
+
def;
|
|
1846
|
+
constructor(t) {
|
|
1847
|
+
this.def = t;
|
|
1848
|
+
}
|
|
1849
|
+
solve(t, e = !1) {
|
|
1850
|
+
const s = this.def, n = e ? s.bulkyShoulder : 0, r = { x: s.chest[0], y: s.chest[1] + (t.by ?? 0) }, o = T(r, s.shoulderF[0] + n, s.shoulderF[1]), a = T(r, s.shoulderB[0] - n, s.shoulderB[1]), h = t.hipDx ?? 0, l = t.hipDy ?? 0, c = { x: s.hipF[0] + h, y: s.hipF[1] + l }, u = { x: s.hipB[0] + h, y: s.hipB[1] + l }, [d, m, f] = this.frontArm(o, t.armF ?? X), [p, g] = J(a, t.armB ?? X), [y, w] = J(c, t.legF ?? X), [v, L] = J(u, t.legB ?? X), D = T(r, t.headDx ?? 0, t.headDy ?? 0);
|
|
1851
|
+
return { chest: r, head: D, shoulderF: o, elbowF: d, wristF: m, shoulderB: a, elbowB: p, wristB: g, hipF: c, kneeF: y, ankleF: w, hipB: u, kneeB: v, ankleB: L, forearm: f };
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* Elbow, wrist and forearm direction of the front arm (or of its motion smear) hung from `shoulder`. The fist keeps
|
|
1855
|
+
* the frame's last column for its outline: an arm reaching past that (a swing, a thrust, a draw on a bulky body) is
|
|
1856
|
+
* pulled back whole, so the forearm — and the weapon laid along it — keeps its angle.
|
|
1857
|
+
*/
|
|
1858
|
+
frontArm(t, e) {
|
|
1859
|
+
const s = this.def, [n, r, o] = J(t, e), a = Math.max(0, r.x - (s.width - s.limbWidth - 1));
|
|
1860
|
+
return [T(n, -a, 0), T(r, -a, 0), o];
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
const ds = 1, fs = 20, ps = 24, ms = [10, 13], gs = [3, 1], ys = [-4, 1], ws = 1, xs = [11, 19], bs = [9, 19], vs = 2, Ms = 0.75, As = 0.72, ks = {
|
|
1864
|
+
scale: ds,
|
|
1865
|
+
width: fs,
|
|
1866
|
+
height: ps,
|
|
1867
|
+
chest: ms,
|
|
1868
|
+
shoulderF: gs,
|
|
1869
|
+
shoulderB: ys,
|
|
1870
|
+
bulkyShoulder: ws,
|
|
1871
|
+
hipF: xs,
|
|
1872
|
+
hipB: bs,
|
|
1873
|
+
limbWidth: vs,
|
|
1874
|
+
backShade: Ms,
|
|
1875
|
+
backArmShade: As
|
|
1876
|
+
}, Xn = ks;
|
|
1877
|
+
function Y(i, t, e) {
|
|
1878
|
+
return i + (t - i) * e;
|
|
1879
|
+
}
|
|
1880
|
+
function kt(i, t, e) {
|
|
1881
|
+
let s = (t - i) % 360;
|
|
1882
|
+
return s > 180 && (s -= 360), s < -180 && (s += 360), i + s * e;
|
|
1883
|
+
}
|
|
1884
|
+
function K(i, t, e) {
|
|
1885
|
+
return !i || !t ? e < 1 ? i ?? t : t ?? i : [kt(i[0], t[0], e), Y(i[1], t[1], e), kt(i[2], t[2], e), Y(i[3], t[3], e)];
|
|
1886
|
+
}
|
|
1887
|
+
function $(i, t, e) {
|
|
1888
|
+
if (!(i === void 0 && t === void 0))
|
|
1889
|
+
return Y(i ?? 0, t ?? 0, e);
|
|
1890
|
+
}
|
|
1891
|
+
function St(i, t, e) {
|
|
1892
|
+
return e <= 0 ? i : e >= 1 ? t : {
|
|
1893
|
+
...i,
|
|
1894
|
+
by: $(i.by, t.by, e),
|
|
1895
|
+
armF: K(i.armF, t.armF, e),
|
|
1896
|
+
armB: K(i.armB, t.armB, e),
|
|
1897
|
+
legF: K(i.legF, t.legF, e),
|
|
1898
|
+
legB: K(i.legB, t.legB, e),
|
|
1899
|
+
hipDx: $(i.hipDx, t.hipDx, e),
|
|
1900
|
+
hipDy: $(i.hipDy, t.hipDy, e),
|
|
1901
|
+
headDx: $(i.headDx, t.headDx, e),
|
|
1902
|
+
headDy: $(i.headDy, t.headDy, e),
|
|
1903
|
+
smearArm: i.smearArm,
|
|
1904
|
+
curl: i.curl && t.curl ? [Y(i.curl[0], t.curl[0], e), Y(i.curl[1], t.curl[1], e)] : i.curl
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
function Jn(i, t) {
|
|
1908
|
+
const e = { ...i };
|
|
1909
|
+
for (const [s, n] of Object.entries(t)) n !== void 0 && (e[s] = n);
|
|
1910
|
+
return e;
|
|
1911
|
+
}
|
|
1912
|
+
function Kn(i, t) {
|
|
1913
|
+
return {
|
|
1914
|
+
...i,
|
|
1915
|
+
by: Math.max(-1, (i.by ?? 0) + (t.by ?? 0)),
|
|
1916
|
+
legF: t.legF,
|
|
1917
|
+
legB: t.legB,
|
|
1918
|
+
hipDx: t.hipDx,
|
|
1919
|
+
hipDy: t.hipDy,
|
|
1920
|
+
// the far arm swings with the run, unless it holds the bow the action draws
|
|
1921
|
+
armB: i.armBFront ? i.armB : t.armB,
|
|
1922
|
+
trail: t.trail ?? i.trail
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
const Ss = { by: 0, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2] }, Es = { by: 0, armF: [45, 2.41, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], breathe: !0, sway: 1 }, Fs = { by: -1, armF: [45, 2.41, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], breathe: !0, sway: 1 }, Bs = { by: 0, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], sway: -1 }, Ds = { by: -1, armF: [45, 2.41, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], breathe: !0, sway: 2 }, Ts = { by: 1, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], sway: -1 }, Rs = { by: 0, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2] }, Os = { by: 1, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2] }, Cs = { by: 0, armF: [90, 1.7, 0, 0.85], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 1], legF: [45, 1.41, 45, 2], trail: 1 }, Ls = { by: -1, armF: [90, 1.7, 0, 0.85], armB: [90, 2, 0, 1], legB: [90, 1, 0, 1], legF: [90, 1, 0, 2], trail: 2 }, Hs = { by: 0, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [26.6, 2.24, 63.4, 1], legF: [153.4, 2.24, -63.4, 2], trail: 1 }, Is = { by: 0, armF: [45, 1.2, 0, 1.2], armB: [90, 1, 45, 1.41], legB: [18.4, 3.16, 71.6, 2], legF: [166, 4.12, -76, 1], trail: 1 }, _s = { by: -1, armF: [45, 1.2, 0, 1.2], armB: [90, 1, 45, 1.41], legB: [26.6, 2.24, 63.4, 2], legF: [153.4, 2.24, -63.4, 1], trail: 2 }, Ps = { by: 0, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [90, 1, 0, 2], legF: [90, 1, 0, 1], trail: 1 }, Ws = { by: 0, armF: [135, 2.41, 71.6, 1.9], armB: [21.8, 2.69, -55.5, 1.8], legB: [116.6, 2.24, 45, 3.16], legF: [90, 2, -71.6, 3.16], trail: 1 }, Us = { by: 1, armF: [135, 2.41, 71.6, 1.9], armB: [21.8, 2.69, -55.5, 1.8], legB: [153.4, 2.24, 26.6, 2], legF: [63.4, 2.24, -18.4, 1.41], trail: 1 }, Ns = { by: 0, armF: [63.4, 1.9, -108.4, 1.2], armB: [21.8, 2.69, -55.5, 1.8], legB: [90, 0, 45, 1.41], legF: [90, 2, 45, 1.41], trail: 2 }, $s = { by: -1, armF: [18.4, 2.69, -90, 2.69], armB: [21.8, 2.69, -55.5, 1.8], legB: [18.4, 3.16, -18.4, 1], legF: [153.4, 2.24, 0, 2.24], trail: 2 }, zs = { by: 0, armF: [18.4, 2.69, -90, 2.69], armB: [116.6, 1.12, 63.4, 1.5], legB: [45, 2.83, -26.6, 3.16], legF: [146.3, 3.61, 15.3, 3.16], trail: 1 }, Gs = { by: 1, armF: [18.4, 2.69, -90, 2.69], armB: [116.6, 1.12, 63.4, 1.5], legB: [33.7, 3.61, 11.3, 1.41], legF: [166, 4.12, 14, 2], trail: 1 }, qs = { by: 0, armF: [63.4, 1.9, -108.4, 1.2], armB: [116.6, 1.12, 63.4, 1.5], legB: [45, 2.83, 90, 1.41], legF: [180, 2, -45, 1.41], trail: 2 }, Ys = { by: -1, armF: [135, 2.41, 71.6, 1.9], armB: [116.6, 1.12, 63.4, 1.5], legB: [90, 1, 63.4, 2.24], legF: [45, 1.41, -45, 1], trail: 2 }, js = { by: 0, curl: [10, 18], hipDx: -1, hipDy: -1, headDx: 0, headDy: 5, legB: [14, 4.12, 57.5, 3.16], legF: [14, 4.12, 57.5, 3.16], armF: [94.4, 2.77, -17.4, 2.84], armB: [90, 2, 0, 1] }, Vs = { by: 0, curl: [10, 17], hipDx: -1, hipDy: -2, headDx: 3, headDy: 8, legB: [-9.5, 6.08, -80.5, 4], legF: [-9.5, 6.08, -80.5, 4], armF: [-45, 0.6, 63.4, 1.34], armB: [90, 2, 0, 1] }, Xs = { by: 0, curl: [9, 16], hipDx: -2, hipDy: -3, headDx: 3, headDy: 10, legB: [-39.8, 7.81, -103.3, 5], legF: [-39.8, 7.81, -103.3, 5], armF: [-114.8, 3.04, 46.6, 1.15], armB: [90, 2, 0, 1] }, Js = { by: 0, curl: [8, 16], hipDx: -3, hipDy: -3, headDx: 1, headDy: 10, legB: [-74.1, 7.28, -117.3, 5.1], legF: [-74.1, 7.28, -117.3, 5.1], armF: [-145.6, 4.9, 1.2, 1.83], armB: [90, 2, 0, 1] }, Ks = { by: 0, curl: [9, 17], hipDx: -2, hipDy: -2, headDx: 0, headDy: 8, legB: [-135, 4.24, -135, 5], legF: [-135, 4.24, -135, 5], armF: [171.5, 4.3, -21.7, 2.95], armB: [90, 2, 0, 1] }, Zs = { by: 0, curl: [10, 18], hipDx: -1, hipDy: -1, headDx: 0, headDy: 5, legB: [90, 1, 18.4, 3.16], legF: [90, 1, 18.4, 3.16], armF: [130.2, 3.62, -11.9, 3.14], armB: [90, 2, 0, 1] }, Qs = { by: 0, curl: [10, 18], hipDx: -1, hipDy: -1, headDx: 2, headDy: 7, legB: [0, 5, -45, 1.41], legF: [0, 5, -45, 1.41], armF: [81.9, 1.5, -27.4, 1.83], armB: [90, 2, 0, 1] }, ti = { by: 0, curl: [10, 17], hipDx: -1, hipDy: -2, headDx: 3, headDy: 9, legB: [-26.6, 6.71, -90, 4.47], legF: [-26.6, 6.71, -90, 4.47], armF: [-90, 1.27, 63.4, 0.95], armB: [90, 2, 0, 1] }, ei = { by: 0, curl: [9, 16], hipDx: -2, hipDy: -3, headDx: 2, headDy: 10, legB: [-56.3, 7.21, -112.4, 5.1], legF: [-56.3, 7.21, -112.4, 5.1], armF: [-130.2, 3.62, 9.3, 1.24], armB: [90, 2, 0, 1] }, si = { by: 0, curl: [9, 17], hipDx: -2, hipDy: -2, headDx: 1, headDy: 9, legB: [-101.3, 5.1, -135, 3.61], legF: [-101.3, 5.1, -135, 3.61], armF: [-170.5, 3.88, -15.2, 2.13], armB: [90, 2, 0, 1] }, ii = { by: 0, curl: [10, 18], hipDx: -1, hipDy: -1, headDx: 0, headDy: 7, legB: [-153.4, 2.24, -116.6, 4], legF: [-153.4, 2.24, -116.6, 4], armF: [144.5, 3.66, -9.5, 3.01], armB: [90, 2, 0, 1] }, ni = { by: 0, curl: [10, 18], hipDx: -1, hipDy: -1, headDx: 0, headDy: 3, legB: [45, 2.83, 45, 2], legF: [45, 2.83, 45, 2], armF: [113.2, 3.24, -15.1, 3.01], armB: [90, 2, 0, 1] }, ri = { by: 1, armF: [90, 1.7, 0, 0.85], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 1], legF: [45, 1.41, 45, 2] }, oi = { by: 0, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], face: "blink", headDx: -1 }, ai = { by: 1, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], face: "dizzy" }, hi = { by: 2, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, li = { by: 2, armF: [45, 1.2, 0, 1.2], armB: [90, 1, 45, 1.41], legB: [116.6, 2.24, 45, 3.16], legF: [26.6, 2.24, 63.4, 2] }, ci = { by: 0, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [0, 2, 63.4, 2.24], legF: [0, 1, 63.4, 2.24] }, ui = { by: 5, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], hipDy: 3, legB: [0, 2, -26.6, 2.24], legF: [0, 3, -26.6, 2.24] }, di = { by: 2, armF: [63.4, 1.9, 8.1, 2.69], armB: [90, 2, 0, 1], legB: [116.6, 2.24, 45, 3.16], legF: [26.6, 2.24, 63.4, 2] }, fi = { by: 0, armF: [45, 1.2, 45, 1.7], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], lookBack: !0 }, pi = { by: -1, armF: [-63.4, 1.9, -26.6, 1.7], armB: [-90, 2, 0, 2], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], face: "blink" }, mi = { by: -1, armF: [-63.4, 1.9, -26.6, 1.7], armB: [-90, 2, 0, 2], legB: [135, 1.41, -45, 1], legF: [90, 1, 0, 1], face: "happy" }, gi = { by: 0, armF: [-45, 2.41, -18.4, 3.8], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], face: "happy" }, yi = { by: 0, armF: [-45, 2.41, -56.3, 4.34], armB: [90, 2, 0, 1], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2], face: "happy" }, wi = { by: -1, armF: [-63.4, 1.9, -26.6, 1.7], armB: [-90, 2, 0, 2], legB: [153.4, 2.24, -63.4, 1], legF: [45, 1.41, 45, 2], face: "happy" }, xi = { by: 0, armF: [-45, 2.41, -18.4, 3.8], armB: [90, 2, 0, 1], legB: [18.4, 3.16, 71.6, 2], legF: [161.6, 3.16, -71.6, 1], face: "happy" }, bi = { by: 1, armF: [-110, 1.9, 63, 3.06], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, vi = { by: 1, armF: [-90, 1.7, 11.3, 4.34], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2], smearArm: [-110, 1.9, 63, 3.06] }, Mi = { by: 0, armF: [-33.7, 3.07, 15.3, 2.69], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Ai = { by: 1, armF: [33.7, 3.07, 22.6, 3.07], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2], smearArm: [33.7, 3.07, 11.3, 2.41] }, ki = { by: 1, armF: [33.7, 3.07, 11.3, 2.41], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Si = { by: 0, armF: [45, 2.41, 18.4, 1.9], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Ei = { by: 1, armF: [116.6, 1.9, -180, 1.9], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Fi = { by: 1, armF: [0, 2.55, 0, 2.55], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2], smearArm: [0, 1.7, 0, 1.7] }, Bi = { by: 0, armF: [45, 1.2, -90, 1.2], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2], smearArm: [116.6, 1.9, -180, 1.9] }, Di = { by: 0, armF: [0, 1.7, 0, 1.7], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Ti = { by: 0, armF: [45, 1.2, 0, 1.2], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Ri = { by: 1, armF: [-71.6, 2.69, -45, 1.9], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Oi = { by: 0, armF: [-59, 4.96, -40.4, 5.17], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Ci = { by: 0, armF: [-36.9, 4.25, 10.3, 1.9], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2], smearArm: [-59, 4.96, -40.4, 5.17] }, Li = { by: 0, armF: [-26.6, 3.8, 53.1, 1.9], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2], smearArm: [-36.9, 4.25, 10.3, 1.9] }, Hi = { by: 1, armF: [45, 1.2, 0, 1.2], armB: [90, 1, 45, 1.41], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2] }, Ii = { by: 0, armF: [-63.4, 1.9, -26.6, 1.7], armB: [-90, 2, 0, 2], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2] }, _i = { by: -1, armF: [-63.4, 1.9, -26.6, 1.7], armB: [-90, 2, 0, 2], legB: [135, 1.41, -45, 2], legF: [90, 1, 0, 2] }, Pi = { by: 1, armF: [-130, 2.41, 26.6, 2.69], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Wi = { by: 1, armF: [-123.7, 3.07, 0, 3.07], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Ui = { by: 0, armF: [-45, 2.41, 45, 1.7], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, Ni = { by: 1, armF: [-90, 3.4, 18.4, 2.69], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2], smearArm: [-135, 2.41, 26.6, 2.69] }, $i = { by: 0, armF: [26.6, 1.9, 63.4, 1.7], armB: [90, 2, 0, 1], legB: [153.4, 2.24, -63.4, 2], legF: [45, 1.41, 45, 2] }, zi = {
|
|
1926
|
+
BREATHE0: Ss,
|
|
1927
|
+
BREATHE1: Es,
|
|
1928
|
+
BREATHE2: Fs,
|
|
1929
|
+
BREATHE3: Bs,
|
|
1930
|
+
BREATHE4: Ds,
|
|
1931
|
+
BREATHE5: Ts,
|
|
1932
|
+
IDLE0: Rs,
|
|
1933
|
+
IDLE1: Os,
|
|
1934
|
+
STRIDE0: Cs,
|
|
1935
|
+
STRIDE1: Ls,
|
|
1936
|
+
STRIDE2: Hs,
|
|
1937
|
+
STRIDE3: Is,
|
|
1938
|
+
STRIDE4: _s,
|
|
1939
|
+
STRIDE5: Ps,
|
|
1940
|
+
JOG0: Ws,
|
|
1941
|
+
JOG1: Us,
|
|
1942
|
+
JOG2: Ns,
|
|
1943
|
+
JOG3: $s,
|
|
1944
|
+
JOG4: zs,
|
|
1945
|
+
JOG5: Gs,
|
|
1946
|
+
JOG6: qs,
|
|
1947
|
+
JOG7: Ys,
|
|
1948
|
+
ROLL0: js,
|
|
1949
|
+
ROLL1: Vs,
|
|
1950
|
+
ROLL2: Xs,
|
|
1951
|
+
ROLL3: Js,
|
|
1952
|
+
ROLL4: Ks,
|
|
1953
|
+
ROLL5: Zs,
|
|
1954
|
+
ROLL6: Qs,
|
|
1955
|
+
ROLL7: ti,
|
|
1956
|
+
ROLL8: ei,
|
|
1957
|
+
ROLL9: si,
|
|
1958
|
+
ROLL10: ii,
|
|
1959
|
+
ROLL11: ni,
|
|
1960
|
+
DASH: ri,
|
|
1961
|
+
HURT: oi,
|
|
1962
|
+
DIZZY: ai,
|
|
1963
|
+
CROUCH: hi,
|
|
1964
|
+
KNEEL: li,
|
|
1965
|
+
SIT: ci,
|
|
1966
|
+
SIT_GROUND: ui,
|
|
1967
|
+
PICK: di,
|
|
1968
|
+
LOOK_BACK: fi,
|
|
1969
|
+
STRETCH: pi,
|
|
1970
|
+
CHEER: mi,
|
|
1971
|
+
WAVE_A: gi,
|
|
1972
|
+
WAVE_B: yi,
|
|
1973
|
+
DANCE_A: wi,
|
|
1974
|
+
DANCE_B: xi,
|
|
1975
|
+
SLASH_READY: bi,
|
|
1976
|
+
SLASH_WIND: vi,
|
|
1977
|
+
SLASH_SWEEP: Mi,
|
|
1978
|
+
SLASH_FOLLOW: Ai,
|
|
1979
|
+
SLASH_END: ki,
|
|
1980
|
+
SLASH_RECOVER: Si,
|
|
1981
|
+
THRUST_READY: Ei,
|
|
1982
|
+
THRUST_LUNGE: Fi,
|
|
1983
|
+
THRUST_MID: Bi,
|
|
1984
|
+
THRUST_END: Di,
|
|
1985
|
+
THRUST_RECOVER: Ti,
|
|
1986
|
+
OVERHEAD_READY: Ri,
|
|
1987
|
+
OVERHEAD: Oi,
|
|
1988
|
+
OVERHEAD_MID: Ci,
|
|
1989
|
+
OVERHEAD_FALL: Li,
|
|
1990
|
+
CAST_CHARGE: Hi,
|
|
1991
|
+
CAST: Ii,
|
|
1992
|
+
CAST_RELEASE: _i,
|
|
1993
|
+
THROW_READY: Pi,
|
|
1994
|
+
THROW_WIND: Wi,
|
|
1995
|
+
THROW_RELEASE: Ui,
|
|
1996
|
+
THROW_MID: Ni,
|
|
1997
|
+
THROW_RECOVER: $i
|
|
1998
|
+
}, Zn = zi, Z = (i, t) => Array.from({ length: t }, (e, s) => `${i}${s}`), Qn = {
|
|
1999
|
+
idle: { poses: Z("BREATHE", 6), fps: 6 },
|
|
2000
|
+
walk: { poses: Z("STRIDE", 6), fps: 10 },
|
|
2001
|
+
run: { poses: Z("JOG", 8), fps: 14 },
|
|
2002
|
+
roll: { poses: Z("ROLL", 12), fps: 30, loop: !1, blend: !1 },
|
|
2003
|
+
dash: { poses: ["DASH"], fps: 1, loop: !1 },
|
|
2004
|
+
hurt: { poses: ["HURT", "BREATHE0"], fps: 5, loop: !1 },
|
|
2005
|
+
dizzy: { poses: ["DIZZY", "BREATHE0"], fps: 2 },
|
|
2006
|
+
crouch: { poses: ["CROUCH"], fps: 1, loop: !1 },
|
|
2007
|
+
kneel: { poses: ["KNEEL"], fps: 1, loop: !1 },
|
|
2008
|
+
sit: { poses: ["SIT"], fps: 1, loop: !1 },
|
|
2009
|
+
sitGround: { poses: ["SIT_GROUND"], fps: 1, loop: !1 },
|
|
2010
|
+
pick: { poses: ["CROUCH", "PICK", "CROUCH"], fps: 6, loop: !1 },
|
|
2011
|
+
lookBack: { poses: ["LOOK_BACK"], fps: 1, loop: !1 },
|
|
2012
|
+
stretch: { poses: ["BREATHE0", "STRETCH", "STRETCH", "BREATHE0"], fps: 3, loop: !1 },
|
|
2013
|
+
cheer: { poses: ["BREATHE0", "CHEER", "CHEER"], fps: 6, loop: !1 },
|
|
2014
|
+
wave: { poses: ["WAVE_A", "WAVE_B"], fps: 4 },
|
|
2015
|
+
dance: { poses: ["DANCE_A", "DANCE_B"], fps: 3 },
|
|
2016
|
+
slash: { poses: ["SLASH_READY", "SLASH_WIND", "SLASH_SWEEP", "SLASH_FOLLOW", "SLASH_END", "SLASH_RECOVER"], durations: [60, 90, 40, 60, 90, 120], loop: !1 },
|
|
2017
|
+
thrust: { poses: ["THRUST_READY", "THRUST_LUNGE", "THRUST_MID", "THRUST_END", "THRUST_RECOVER"], durations: [80, 50, 60, 100, 120], loop: !1 },
|
|
2018
|
+
overhead: { poses: ["OVERHEAD_READY", "OVERHEAD", "OVERHEAD_MID", "OVERHEAD_FALL"], durations: [90, 140, 50, 160], loop: !1 },
|
|
2019
|
+
cast: { poses: ["CAST_CHARGE", "CAST", "CAST_RELEASE"], durations: [220, 120, 200], loop: !1 },
|
|
2020
|
+
throw: { poses: ["THROW_READY", "THROW_WIND", "THROW_RELEASE", "THROW_MID", "THROW_RECOVER"], durations: [70, 110, 40, 70, 120], loop: !1 }
|
|
2021
|
+
};
|
|
2022
|
+
class tr {
|
|
2023
|
+
constructor(t, e, s) {
|
|
2024
|
+
this.library = t, this.clips = e, this.clip = this.clipOf(s), this.name = s;
|
|
2025
|
+
}
|
|
2026
|
+
library;
|
|
2027
|
+
clips;
|
|
2028
|
+
clip;
|
|
2029
|
+
name;
|
|
2030
|
+
elapsed = 0;
|
|
2031
|
+
ended = !1;
|
|
2032
|
+
/** The pose being faded out of, and how long the fade lasts and has run. */
|
|
2033
|
+
from = null;
|
|
2034
|
+
fadeMs = 0;
|
|
2035
|
+
fadeAt = 0;
|
|
2036
|
+
cached = null;
|
|
2037
|
+
speed = 1;
|
|
2038
|
+
/** Called when a clip that does not loop reaches its end. */
|
|
2039
|
+
onComplete = null;
|
|
2040
|
+
get current() {
|
|
2041
|
+
return this.name;
|
|
2042
|
+
}
|
|
2043
|
+
get finished() {
|
|
2044
|
+
return this.ended;
|
|
2045
|
+
}
|
|
2046
|
+
/** Time into the current clip, ms. */
|
|
2047
|
+
get time() {
|
|
2048
|
+
return this.elapsed;
|
|
2049
|
+
}
|
|
2050
|
+
/** Plays `name`, fading from the pose shown now over `fadeMs`. The clip already playing keeps going unless `restart`. */
|
|
2051
|
+
play(t, e = {}) {
|
|
2052
|
+
if (t === this.name && !e.restart) return this;
|
|
2053
|
+
const s = e.fadeMs ?? 0;
|
|
2054
|
+
return this.from = s > 0 ? this.pose : null, this.fadeMs = s, this.fadeAt = 0, this.clip = this.clipOf(t), this.name = t, this.elapsed = 0, this.ended = !1, this.cached = null, this;
|
|
2055
|
+
}
|
|
2056
|
+
/** Advances by `dt` seconds. */
|
|
2057
|
+
update(t) {
|
|
2058
|
+
if (!(t > 0) || this.speed <= 0) return;
|
|
2059
|
+
const e = t * 1e3 * this.speed;
|
|
2060
|
+
if (this.cached = null, this.from && (this.fadeAt += e, this.fadeAt >= this.fadeMs && (this.from = null)), this.ended) return;
|
|
2061
|
+
this.elapsed += e;
|
|
2062
|
+
const s = this.totalMs();
|
|
2063
|
+
this.elapsed >= s && (this.clip.loop !== !1 ? this.elapsed %= s : (this.elapsed = s, this.ended = !0, this.onComplete?.(this.name)));
|
|
2064
|
+
}
|
|
2065
|
+
/** The pose to show now. */
|
|
2066
|
+
get pose() {
|
|
2067
|
+
if (this.cached) return this.cached;
|
|
2068
|
+
let t = this.sample(this.elapsed);
|
|
2069
|
+
return this.from && (t = St(this.from, t, Math.min(1, this.fadeAt / this.fadeMs))), this.cached = t, t;
|
|
2070
|
+
}
|
|
2071
|
+
/** The current clip's pose at `ms` into it. */
|
|
2072
|
+
sample(t) {
|
|
2073
|
+
const e = this.clip.poses, s = e.length;
|
|
2074
|
+
let n = Math.max(0, t);
|
|
2075
|
+
for (let r = 0; r < s; r++) {
|
|
2076
|
+
const o = this.lengthOf(r);
|
|
2077
|
+
if (n < o || r === s - 1) {
|
|
2078
|
+
const a = this.resolve(e[r]), h = r === s - 1;
|
|
2079
|
+
if (this.clip.blend === !1 || s === 1 || h && this.clip.loop === !1) return a;
|
|
2080
|
+
const l = this.resolve(e[h ? 0 : r + 1]);
|
|
2081
|
+
return St(a, l, Math.min(1, n / o));
|
|
2082
|
+
}
|
|
2083
|
+
n -= o;
|
|
2084
|
+
}
|
|
2085
|
+
return this.resolve(e[s - 1]);
|
|
2086
|
+
}
|
|
2087
|
+
totalMs() {
|
|
2088
|
+
let t = 0;
|
|
2089
|
+
for (let e = 0; e < this.clip.poses.length; e++) t += this.lengthOf(e);
|
|
2090
|
+
return t;
|
|
2091
|
+
}
|
|
2092
|
+
lengthOf(t) {
|
|
2093
|
+
return Math.max(1, this.clip.durations?.[t] ?? 1e3 / (this.clip.fps ?? 8));
|
|
2094
|
+
}
|
|
2095
|
+
resolve(t) {
|
|
2096
|
+
if (typeof t != "string") return t;
|
|
2097
|
+
const e = this.library[t];
|
|
2098
|
+
if (!e) throw new Error(`PosePlayer: no pose "${t}" in the library`);
|
|
2099
|
+
return e;
|
|
2100
|
+
}
|
|
2101
|
+
clipOf(t) {
|
|
2102
|
+
const e = this.clips[t];
|
|
2103
|
+
if (!e) throw new Error(`PosePlayer: no clip "${t}"`);
|
|
2104
|
+
if (e.poses.length === 0) throw new Error(`PosePlayer: clip "${t}" has no poses`);
|
|
2105
|
+
for (const s of e.poses) this.resolve(s);
|
|
2106
|
+
return e;
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
const Et = ["upperArmB", "forearmB", "thighB", "shinB", "torso", "thighF", "shinF", "head", "upperArmF", "forearmF"], Gi = {
|
|
2110
|
+
upperArmB: 6983888,
|
|
2111
|
+
forearmB: 1578e4,
|
|
2112
|
+
thighB: 3813448,
|
|
2113
|
+
shinB: 3813448,
|
|
2114
|
+
torso: 4878256,
|
|
2115
|
+
thighF: 3813448,
|
|
2116
|
+
shinF: 3813448,
|
|
2117
|
+
head: 1578e4,
|
|
2118
|
+
upperArmF: 6983888,
|
|
2119
|
+
forearmF: 1578e4
|
|
2120
|
+
}, qi = /* @__PURE__ */ new Set(["upperArmB", "forearmB", "thighB", "shinB"]), Yi = {
|
|
2121
|
+
upperArmB: ["shoulderB", "elbowB"],
|
|
2122
|
+
forearmB: ["elbowB", "wristB"],
|
|
2123
|
+
thighB: ["hipB", "kneeB"],
|
|
2124
|
+
shinB: ["kneeB", "ankleB"],
|
|
2125
|
+
thighF: ["hipF", "kneeF"],
|
|
2126
|
+
shinF: ["kneeF", "ankleF"],
|
|
2127
|
+
upperArmF: ["shoulderF", "elbowF"],
|
|
2128
|
+
forearmF: ["elbowF", "wristF"]
|
|
2129
|
+
};
|
|
2130
|
+
function ji(i, t) {
|
|
2131
|
+
const e = Math.round((i >> 16 & 255) * t), s = Math.round((i >> 8 & 255) * t), n = Math.round((i & 255) * t);
|
|
2132
|
+
return e << 16 | s << 8 | n;
|
|
2133
|
+
}
|
|
2134
|
+
class er extends M {
|
|
2135
|
+
constructor(t, e = {}, s, n = {}) {
|
|
2136
|
+
super(), this.def = t, this.skin = e, this.skeleton = new us(t), this.scaleGrid = n.scale ?? 1, this.headRadius = n.headRadius ?? 5, this.headRise = n.headRise ?? 5.5, this.bulky = n.bulky === !0;
|
|
2137
|
+
const r = new M();
|
|
2138
|
+
r.position.set(-t.width / 2, -t.height), this.addChild(r);
|
|
2139
|
+
for (const o of Et) {
|
|
2140
|
+
const a = new M();
|
|
2141
|
+
this.layers.set(o, a), r.addChild(a);
|
|
2142
|
+
const h = e[o];
|
|
2143
|
+
if (h?.texture && s) {
|
|
2144
|
+
const l = new R(s.get(h.texture, h.frame));
|
|
2145
|
+
l.anchor.set(h.anchorX ?? 0.5, h.anchorY ?? 0), l.scale.set(1 / this.scaleGrid), this.sprites.set(o, l), a.addChild(l);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
this.scale.set(this.scaleGrid);
|
|
2149
|
+
}
|
|
2150
|
+
def;
|
|
2151
|
+
skin;
|
|
2152
|
+
skeleton;
|
|
2153
|
+
sprites = /* @__PURE__ */ new Map();
|
|
2154
|
+
layers = /* @__PURE__ */ new Map();
|
|
2155
|
+
joints = null;
|
|
2156
|
+
curl;
|
|
2157
|
+
scaleGrid;
|
|
2158
|
+
headRadius;
|
|
2159
|
+
headRise;
|
|
2160
|
+
bulky;
|
|
2161
|
+
/** 1 faces right, -1 faces left. */
|
|
2162
|
+
set facing(t) {
|
|
2163
|
+
this.scale.x = this.scaleGrid * t;
|
|
2164
|
+
}
|
|
2165
|
+
get facing() {
|
|
2166
|
+
return this.scale.x < 0 ? -1 : 1;
|
|
2167
|
+
}
|
|
2168
|
+
/** The joints of the last pose, in grid px of the rig's frame (for attaching a held item, an effect). */
|
|
2169
|
+
get lastJoints() {
|
|
2170
|
+
return this.joints;
|
|
2171
|
+
}
|
|
2172
|
+
/** Where a joint of the last pose is in this view's parent, in world px. */
|
|
2173
|
+
jointInParent(t) {
|
|
2174
|
+
if (!this.joints) return null;
|
|
2175
|
+
const e = this.joints[t];
|
|
2176
|
+
return { x: this.x + (e.x - this.def.width / 2) * this.scale.x, y: this.y + (e.y - this.def.height) * this.scale.y };
|
|
2177
|
+
}
|
|
2178
|
+
setPose(t) {
|
|
2179
|
+
const e = this.skeleton.solve(t, this.bulky);
|
|
2180
|
+
this.joints = e, this.curl = t.curl;
|
|
2181
|
+
for (const s of Et) this.place(s, e);
|
|
2182
|
+
return this;
|
|
2183
|
+
}
|
|
2184
|
+
destroy(t) {
|
|
2185
|
+
super.destroy(t ?? { children: !0 });
|
|
2186
|
+
}
|
|
2187
|
+
place(t, e) {
|
|
2188
|
+
const s = this.layers.get(t), n = this.skin[t] ?? {}, r = this.sprites.get(t), [o, a] = this.ends(t, e), h = Math.atan2(a.y - o.y, a.x - o.x);
|
|
2189
|
+
if (r) {
|
|
2190
|
+
r.position.set(o.x, o.y), r.rotation = h - Math.PI / 2, n.stretch && r.texture.height > 0 && (r.scale.y = Math.hypot(a.x - o.x, a.y - o.y) / r.texture.height);
|
|
2191
|
+
return;
|
|
2192
|
+
}
|
|
2193
|
+
let l = s.children[0];
|
|
2194
|
+
l || (l = new Lt(), s.addChild(l)), l.clear();
|
|
2195
|
+
const c = n.color ?? Gi[t], u = qi.has(t) ? ji(c, t.endsWith("ArmB") || t === "forearmB" ? this.def.backArmShade : this.def.backShade) : c, d = n.outline === void 0 ? 1709092 : n.outline, m = d === null ? null : { color: d, width: 0.6 };
|
|
2196
|
+
if (t === "head") {
|
|
2197
|
+
const p = n.width !== void 0 ? n.width / 2 : this.headRadius;
|
|
2198
|
+
l.circle(o.x, o.y, p).fill(u), m && l.stroke(m);
|
|
2199
|
+
return;
|
|
2200
|
+
}
|
|
2201
|
+
if (t === "torso") {
|
|
2202
|
+
const p = n.width ?? Math.abs(this.def.shoulderF[0] - this.def.shoulderB[0]) + 1;
|
|
2203
|
+
if (this.curl)
|
|
2204
|
+
l.circle(this.curl[0], this.curl[1], p / 2 + 1).fill(u);
|
|
2205
|
+
else {
|
|
2206
|
+
const g = Math.hypot(a.x - o.x, a.y - o.y);
|
|
2207
|
+
l.roundRect(-p / 2, -0.5, p, g + 1, Math.min(2, p / 3)).fill(u), l.position.set(o.x, o.y), l.rotation = h - Math.PI / 2, m && l.stroke(m);
|
|
2208
|
+
return;
|
|
2209
|
+
}
|
|
2210
|
+
l.position.set(0, 0), l.rotation = 0, m && l.stroke(m);
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
const f = n.width ?? this.def.limbWidth;
|
|
2214
|
+
l.position.set(0, 0), l.rotation = 0, m && l.moveTo(o.x, o.y).lineTo(a.x, a.y).stroke({ color: m.color, width: f + m.width * 2, cap: "round" }), l.moveTo(o.x, o.y).lineTo(a.x, a.y).stroke({ color: u, width: f, cap: "round" });
|
|
2215
|
+
}
|
|
2216
|
+
/** The two points a part spans: a limb's joints, the torso from chest to hips, the head's centre (twice). */
|
|
2217
|
+
ends(t, e) {
|
|
2218
|
+
if (t === "head") {
|
|
2219
|
+
const r = { x: e.head.x, y: e.head.y - this.headRise };
|
|
2220
|
+
return [r, { x: r.x, y: r.y + 1 }];
|
|
2221
|
+
}
|
|
2222
|
+
if (t === "torso") return [e.chest, { x: (e.hipF.x + e.hipB.x) / 2, y: (e.hipF.y + e.hipB.y) / 2 }];
|
|
2223
|
+
const [s, n] = Yi[t];
|
|
2224
|
+
return [e[s], e[n]];
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
let z = null;
|
|
2228
|
+
function Ft() {
|
|
2229
|
+
if (z) return z;
|
|
2230
|
+
const i = 256, t = document.createElement("canvas");
|
|
2231
|
+
t.width = t.height = i;
|
|
2232
|
+
const e = t.getContext("2d");
|
|
2233
|
+
if (!e) return C.EMPTY;
|
|
2234
|
+
const s = e.createRadialGradient(i / 2, i / 2, 0, i / 2, i / 2, i / 2);
|
|
2235
|
+
return s.addColorStop(0, "rgba(255,255,255,1)"), s.addColorStop(0.35, "rgba(255,255,255,0.75)"), s.addColorStop(0.7, "rgba(255,255,255,0.25)"), s.addColorStop(1, "rgba(255,255,255,0)"), e.fillStyle = s, e.fillRect(0, 0, i, i), z = C.from(t), z.source.scaleMode = "linear", z;
|
|
2236
|
+
}
|
|
2237
|
+
class sr {
|
|
2238
|
+
constructor(t, e = {}) {
|
|
2239
|
+
this.stage = t, this.ambient = e.ambient ?? 658468, this.darkness = e.darkness ?? 0.85, this.tint = e.tint ?? 0.35, this.squash = e.squash ?? 1, this.scratch.addChild(this.sheet, this.holes), this.rt = le.create({ width: 1, height: 1 }), this.view = new R(this.rt), this.washes.blendMode = "add", t.screen.addChild(this.view, this.washes), this.unsubscribe = t.onResize(() => this.fit()), this.fit();
|
|
2240
|
+
}
|
|
2241
|
+
stage;
|
|
2242
|
+
lights = /* @__PURE__ */ new Set();
|
|
2243
|
+
scratch = new M();
|
|
2244
|
+
sheet = new R(C.WHITE);
|
|
2245
|
+
holes = new M();
|
|
2246
|
+
washes = new M();
|
|
2247
|
+
view;
|
|
2248
|
+
rt;
|
|
2249
|
+
pool = [];
|
|
2250
|
+
ambient;
|
|
2251
|
+
darkness;
|
|
2252
|
+
tint;
|
|
2253
|
+
squash;
|
|
2254
|
+
unsubscribe;
|
|
2255
|
+
add(t) {
|
|
2256
|
+
return this.lights.add(t), t;
|
|
2257
|
+
}
|
|
2258
|
+
remove(t) {
|
|
2259
|
+
this.lights.delete(t);
|
|
2260
|
+
}
|
|
2261
|
+
clear() {
|
|
2262
|
+
this.lights.clear();
|
|
2263
|
+
}
|
|
2264
|
+
/** Changes the dark: its colour and how dark (a day/night cycle eases these). */
|
|
2265
|
+
setAmbient(t, e) {
|
|
2266
|
+
this.ambient = t, this.darkness = Math.min(1, Math.max(0, e));
|
|
2267
|
+
}
|
|
2268
|
+
/** Redraws the dark with this frame's lights. Call once a frame, after the camera moved. */
|
|
2269
|
+
update(t = performance.now()) {
|
|
2270
|
+
const e = this.darkness > 4e-3;
|
|
2271
|
+
if (this.view.visible = e, this.washes.visible = e, !e) return;
|
|
2272
|
+
const s = this.stage.cameras.main, n = s.zoom;
|
|
2273
|
+
this.sheet.tint = this.ambient, this.sheet.alpha = this.darkness;
|
|
2274
|
+
let r = 0;
|
|
2275
|
+
for (const o of this.lights) {
|
|
2276
|
+
if (o.on === !1 || o.radius <= 0) continue;
|
|
2277
|
+
const a = (o.x - s.scrollX) * n, h = (o.y - s.scrollY) * n, l = o.flicker ? 1 + Math.sin(t / 97 + o.x) * Math.sin(t / 53 + o.y) * o.flicker : 1, c = o.radius * n * l;
|
|
2278
|
+
if (a < -c || h < -c || a > s.width + c || h > s.height + c) continue;
|
|
2279
|
+
const u = this.sprites(r++), d = Math.min(1, Math.max(0, o.intensity ?? 1));
|
|
2280
|
+
for (const m of [u.hole, u.wash])
|
|
2281
|
+
m.visible = !0, m.position.set(a, h), m.width = c * 2, m.height = c * 2 * this.squash;
|
|
2282
|
+
u.hole.alpha = d, u.wash.tint = o.color ?? 16773340, u.wash.alpha = d * this.tint;
|
|
2283
|
+
}
|
|
2284
|
+
for (let o = r; o < this.pool.length; o++)
|
|
2285
|
+
this.pool[o].hole.visible = !1, this.pool[o].wash.visible = !1;
|
|
2286
|
+
this.stage.app.renderer.render({ container: this.scratch, target: this.rt, clear: !0 });
|
|
2287
|
+
}
|
|
2288
|
+
destroy() {
|
|
2289
|
+
this.unsubscribe(), this.view.destroy(), this.washes.destroy({ children: !0 }), this.scratch.destroy({ children: !0 }), this.rt.destroy(!0), this.lights.clear();
|
|
2290
|
+
}
|
|
2291
|
+
sprites(t) {
|
|
2292
|
+
let e = this.pool[t];
|
|
2293
|
+
if (!e) {
|
|
2294
|
+
const s = new R(Ft());
|
|
2295
|
+
s.anchor.set(0.5), s.blendMode = "erase";
|
|
2296
|
+
const n = new R(Ft());
|
|
2297
|
+
n.anchor.set(0.5), this.holes.addChild(s), this.washes.addChild(n), e = { hole: s, wash: n }, this.pool.push(e);
|
|
2298
|
+
}
|
|
2299
|
+
return e;
|
|
2300
|
+
}
|
|
2301
|
+
fit() {
|
|
2302
|
+
const t = Math.max(1, Math.ceil(this.stage.width)), e = Math.max(1, Math.ceil(this.stage.height));
|
|
2303
|
+
this.rt.resize(t, e), this.sheet.width = t, this.sheet.height = e;
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
function ir(i, t) {
|
|
2307
|
+
const e = Math.min(140, 40 + Math.max(0, i) * 400);
|
|
2308
|
+
return Math.round(e + (t ? 40 : 0));
|
|
2309
|
+
}
|
|
2310
|
+
function nr(i, t, e) {
|
|
2311
|
+
return i ? e ? 2 : 1 : Math.min(3, 2 + (t > 0.2 ? 1 : 0) + (e ? 1 : 0));
|
|
2312
|
+
}
|
|
2313
|
+
const rr = 120;
|
|
2314
|
+
function or(i, t) {
|
|
2315
|
+
return t >= 1 || i <= 0 ? 0 : Math.round(i * (1 - t) * (1 - t));
|
|
2316
|
+
}
|
|
2317
|
+
const Vi = 400;
|
|
2318
|
+
function ar(i, t, e) {
|
|
2319
|
+
return e ? 0 : i ? t ? 60 : 0 : t ? 140 : 70;
|
|
2320
|
+
}
|
|
2321
|
+
function hr(i) {
|
|
2322
|
+
return i ? Vi : 0;
|
|
2323
|
+
}
|
|
2324
|
+
function lr(i, t, e, s) {
|
|
2325
|
+
const n = i.width, r = i.height;
|
|
2326
|
+
if (!n || !r || !(i.zoom > 0)) return !0;
|
|
2327
|
+
const o = i.scrollX ?? 0, a = i.scrollY ?? 0;
|
|
2328
|
+
return t >= o - s && e >= a - s && t <= o + n / i.zoom + s && e <= a + r / i.zoom + s;
|
|
2329
|
+
}
|
|
2330
|
+
const Xi = 0.01, Ji = 5e-3, Ki = 0.16, Zi = 0.95, Qi = 2e-3, tn = 0.01;
|
|
2331
|
+
function en(i, t) {
|
|
2332
|
+
const e = i[0]?.length ?? 0, s = 1 / Math.max(1, i.length), n = new Float32Array(e);
|
|
2333
|
+
for (const f of i) for (let p = 0; p < e; p++) n[p] += f[p] * s;
|
|
2334
|
+
let r = 0;
|
|
2335
|
+
for (let f = 0; f < e; f++) {
|
|
2336
|
+
const p = Math.abs(n[f]);
|
|
2337
|
+
p > r && (r = p);
|
|
2338
|
+
}
|
|
2339
|
+
if (r < Ji) return null;
|
|
2340
|
+
const o = r * Xi;
|
|
2341
|
+
let a = 0;
|
|
2342
|
+
for (; a < e && Math.abs(n[a]) < o; ) a++;
|
|
2343
|
+
let h = e;
|
|
2344
|
+
for (; h > a && Math.abs(n[h - 1]) < o; ) h--;
|
|
2345
|
+
if (h <= a) return null;
|
|
2346
|
+
a = Math.max(0, a - Math.round(Qi * t));
|
|
2347
|
+
const l = n.slice(a, h);
|
|
2348
|
+
let c = 0;
|
|
2349
|
+
for (let f = 0; f < l.length; f++) c += l[f] * l[f];
|
|
2350
|
+
const u = Math.sqrt(c / l.length), d = Math.min(Ki / Math.max(u, 1e-6), Zi / r), m = Math.min(l.length, Math.round(tn * t));
|
|
2351
|
+
for (let f = 0; f < l.length; f++) {
|
|
2352
|
+
const p = l.length - f;
|
|
2353
|
+
l[f] *= d * (p < m ? p / m : 1);
|
|
2354
|
+
}
|
|
2355
|
+
return l;
|
|
2356
|
+
}
|
|
2357
|
+
const et = {};
|
|
2358
|
+
function cr(i) {
|
|
2359
|
+
for (const [t, e] of Object.entries(i)) {
|
|
2360
|
+
const s = /(?:^|\/)([a-z_]+?)(?:_\d+)?\.mp3$/.exec(t);
|
|
2361
|
+
s && (et[s[1]] ??= []).push(e);
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
const Bt = (i) => !!et[i];
|
|
2365
|
+
class sn {
|
|
2366
|
+
decoded = /* @__PURE__ */ new Map();
|
|
2367
|
+
loading = /* @__PURE__ */ new Set();
|
|
2368
|
+
last = /* @__PURE__ */ new Map();
|
|
2369
|
+
names() {
|
|
2370
|
+
return Object.keys(et);
|
|
2371
|
+
}
|
|
2372
|
+
/** A decoded take, or null while none is ready (the caller then synthesises); starts loading on first ask. */
|
|
2373
|
+
take(t, e) {
|
|
2374
|
+
const s = this.decoded.get(e);
|
|
2375
|
+
if (!s?.length)
|
|
2376
|
+
return this.load(t, e), null;
|
|
2377
|
+
let n = Math.floor(Math.random() * s.length);
|
|
2378
|
+
return s.length > 1 && n === this.last.get(e) && (n = (n + 1) % s.length), this.last.set(e, n), s[n];
|
|
2379
|
+
}
|
|
2380
|
+
load(t, e) {
|
|
2381
|
+
const s = et[e];
|
|
2382
|
+
if (!s || this.loading.has(e)) return;
|
|
2383
|
+
this.loading.add(e);
|
|
2384
|
+
const n = [];
|
|
2385
|
+
this.decoded.set(e, n);
|
|
2386
|
+
for (const r of s)
|
|
2387
|
+
fetch(r).then((o) => o.arrayBuffer()).then((o) => t.decodeAudioData(o)).then((o) => on(o)).then((o) => {
|
|
2388
|
+
if (!o) return;
|
|
2389
|
+
const a = t.createBuffer(1, o.length, t.sampleRate);
|
|
2390
|
+
a.copyToChannel(o, 0), n.push(a);
|
|
2391
|
+
}).catch(() => {
|
|
2392
|
+
});
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
let k, nn = 0;
|
|
2396
|
+
const G = /* @__PURE__ */ new Map();
|
|
2397
|
+
function rn() {
|
|
2398
|
+
if (k !== void 0) return k;
|
|
2399
|
+
try {
|
|
2400
|
+
k = new Worker(new URL(
|
|
2401
|
+
/* @vite-ignore */
|
|
2402
|
+
"/assets/takeCleanerWorker-DTcI_Jqr.js",
|
|
2403
|
+
import.meta.url
|
|
2404
|
+
), { type: "module" }), k.onmessage = (i) => {
|
|
2405
|
+
G.get(i.data.id)?.(i.data.data), G.delete(i.data.id);
|
|
2406
|
+
}, k.onerror = () => {
|
|
2407
|
+
k?.terminate(), k = null;
|
|
2408
|
+
for (const i of G.values()) i(null);
|
|
2409
|
+
G.clear();
|
|
2410
|
+
};
|
|
2411
|
+
} catch {
|
|
2412
|
+
k = null;
|
|
2413
|
+
}
|
|
2414
|
+
return k;
|
|
2415
|
+
}
|
|
2416
|
+
let Dt = Promise.resolve();
|
|
2417
|
+
function on(i) {
|
|
2418
|
+
return new Promise((t) => {
|
|
2419
|
+
Dt = Dt.then(() => new Promise((e) => setTimeout(e, 0))).then(() => {
|
|
2420
|
+
an(i).then(t, () => t(null));
|
|
2421
|
+
});
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
function an(i) {
|
|
2425
|
+
const t = Array.from({ length: i.numberOfChannels }, (n, r) => i.getChannelData(r).slice()), e = rn();
|
|
2426
|
+
if (!e) return Promise.resolve(en(t, i.sampleRate));
|
|
2427
|
+
const s = nn++;
|
|
2428
|
+
return new Promise((n) => {
|
|
2429
|
+
G.set(s, n), e.postMessage({ id: s, channels: t, sampleRate: i.sampleRate }, { transfer: t.map((r) => r.buffer) });
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
const B = { master: 1, recipes: {} };
|
|
2433
|
+
function ur(i) {
|
|
2434
|
+
i.master !== void 0 && (B.master = i.master), i.recipes && Object.assign(B.recipes, i.recipes);
|
|
2435
|
+
}
|
|
2436
|
+
const S = 22050, hn = {
|
|
2437
|
+
sine: (i) => Math.sin(i * Math.PI * 2),
|
|
2438
|
+
square: (i, t) => i < t ? 1 : -1,
|
|
2439
|
+
tri: (i) => 1 - 4 * Math.abs(i - 0.5),
|
|
2440
|
+
saw: (i) => 2 * i - 1
|
|
2441
|
+
}, rt = (i, t, e) => i > 0 && t > 0 ? i * Math.pow(t / i, e) : i + (t - i) * e;
|
|
2442
|
+
function Tt(i) {
|
|
2443
|
+
return 1 - Math.exp(-2 * Math.PI * Math.min(i, S * 0.45) / S);
|
|
2444
|
+
}
|
|
2445
|
+
function ln(i) {
|
|
2446
|
+
const t = Math.max(...i.layers.map((o) => (o.d ?? 0) + o.t)), e = new Float32Array(Math.ceil(t * S) + 1);
|
|
2447
|
+
let s = 2654435769;
|
|
2448
|
+
const n = () => (s ^= s << 13, s ^= s >>> 17, s ^= s << 5, (s >>> 0) / 4294967295 * 2 - 1);
|
|
2449
|
+
for (const o of i.layers) {
|
|
2450
|
+
const a = Math.round((o.d ?? 0) * S), h = Math.round(o.t * S), l = Math.max(1, Math.round((o.at ?? 4e-3) * S));
|
|
2451
|
+
let c = 0, u = 0, d = 0, m = 0;
|
|
2452
|
+
for (let f = 0; f < h && a + f < e.length; f++) {
|
|
2453
|
+
const p = f / h, g = o.f ? rt(o.f[0], o.f[1], p) : 0;
|
|
2454
|
+
c += g / S;
|
|
2455
|
+
const y = c - Math.floor(c);
|
|
2456
|
+
let w;
|
|
2457
|
+
o.w === "noise" ? ((!o.f || y < g / S || f === 0) && (u = n()), w = o.f ? u : n()) : w = hn[o.w](y, o.duty ?? 0.5), o.lp && (d += (w - d) * Tt(rt(o.lp[0], o.lp[1], p)), w = d), o.hp && (m += (w - m) * Tt(rt(o.hp[0], o.hp[1], p)), w -= m);
|
|
2458
|
+
const v = f < l ? f / l : Math.pow(1 - (f - l) / Math.max(1, h - l), o.c ?? 2);
|
|
2459
|
+
e[a + f] += w * v * o.g;
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
let r = 0;
|
|
2463
|
+
for (const o of e) r = Math.max(r, Math.abs(o));
|
|
2464
|
+
if (r > 0.95) for (let o = 0; o < e.length; o++) e[o] *= 0.95 / r;
|
|
2465
|
+
return e;
|
|
2466
|
+
}
|
|
2467
|
+
const ot = 480, cn = 10, un = 6, dn = 60, fn = 0.45, pn = 0.05, Rt = 80, at = [18e3, 1800], Ot = { freq: 3500, gainDb: -7 }, mn = 11e3;
|
|
2468
|
+
class gn {
|
|
2469
|
+
ctx = null;
|
|
2470
|
+
master = null;
|
|
2471
|
+
buffers = /* @__PURE__ */ new Map();
|
|
2472
|
+
samples = new sn();
|
|
2473
|
+
lastAt = /* @__PURE__ */ new Map();
|
|
2474
|
+
voices = 0;
|
|
2475
|
+
/** Where the local player stands, set by the world scene; null off the world screens. */
|
|
2476
|
+
listener = () => null;
|
|
2477
|
+
onRunning = () => {
|
|
2478
|
+
};
|
|
2479
|
+
constructor() {
|
|
2480
|
+
if (typeof window > "u") return;
|
|
2481
|
+
const t = () => {
|
|
2482
|
+
const r = this.context();
|
|
2483
|
+
if (!r || r.state === "running") return;
|
|
2484
|
+
r.resume();
|
|
2485
|
+
const o = r.createBufferSource();
|
|
2486
|
+
o.buffer = r.createBuffer(1, 1, 22050), o.connect(r.destination), o.start();
|
|
2487
|
+
}, e = ["pointerdown", "pointerup", "touchend", "keydown"], s = (r) => {
|
|
2488
|
+
for (const o of e)
|
|
2489
|
+
r ? window.addEventListener(o, t, { capture: !0 }) : window.removeEventListener(o, t, { capture: !0 });
|
|
2490
|
+
};
|
|
2491
|
+
this.onRunning = (r) => s(!r), s(!0);
|
|
2492
|
+
const n = navigator.audioSession;
|
|
2493
|
+
n && (n.type = "ambient"), q.subscribe((r) => {
|
|
2494
|
+
this.ctx && this.master && this.master.gain.setTargetAtTime(this.level(r.sfxVolume), this.ctx.currentTime, 0.02);
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
play(t, e = {}) {
|
|
2498
|
+
if (!t || !B.recipes[t] && !Bt(t) || q.getState().sfxVolume <= 0) return;
|
|
2499
|
+
const s = this.ctx;
|
|
2500
|
+
if (!s || s.state !== "running" || this.voices >= (e.minor ? un : cn)) return;
|
|
2501
|
+
let n = (e.gain ?? 1) * (e.local ? 1 : fn), r = 0, o = 0;
|
|
2502
|
+
if (e.x !== void 0 && e.y !== void 0) {
|
|
2503
|
+
const g = this.listener();
|
|
2504
|
+
if (g) {
|
|
2505
|
+
const y = e.x - g.x, w = Math.hypot(y, e.y - g.y), v = Math.min(ot, e.range ?? ot);
|
|
2506
|
+
if (w >= v) return;
|
|
2507
|
+
n *= Math.pow(1 - w / v, 1.5), o = w / ot, r = Math.max(-0.7, Math.min(0.7, y / 320));
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
if (n < 0.03) return;
|
|
2511
|
+
const a = performance.now();
|
|
2512
|
+
if (a - (this.lastAt.get(t) ?? -1e9) < dn) return;
|
|
2513
|
+
const h = this.samples.take(s, t), l = h ?? this.buffer(s, t);
|
|
2514
|
+
if (!l) return;
|
|
2515
|
+
h && (n *= B.recipes[t]?.fileGain ?? 1), this.lastAt.set(t, a);
|
|
2516
|
+
const c = s.createBufferSource();
|
|
2517
|
+
c.buffer = l;
|
|
2518
|
+
const u = B.recipes[t]?.jitter ?? pn;
|
|
2519
|
+
c.playbackRate.value = 1 + (Math.random() * 2 - 1) * u;
|
|
2520
|
+
const d = s.createGain();
|
|
2521
|
+
d.gain.value = Math.min(1, n);
|
|
2522
|
+
const m = s.createStereoPanner();
|
|
2523
|
+
m.pan.value = r;
|
|
2524
|
+
const f = s.createBiquadFilter();
|
|
2525
|
+
f.type = "lowpass", f.frequency.value = at[0] * Math.pow(at[1] / at[0], o), c.connect(f).connect(d).connect(m).connect(this.master), this.voices++, c.onended = () => {
|
|
2526
|
+
this.voices--, c.disconnect(), f.disconnect(), d.disconnect(), m.disconnect();
|
|
2527
|
+
}, c.start();
|
|
2528
|
+
const p = l.duration / c.playbackRate.value * 1e3;
|
|
2529
|
+
if (e.maxMs !== void 0 && p > e.maxMs) {
|
|
2530
|
+
const g = s.currentTime + Math.max(Rt, e.maxMs) / 1e3;
|
|
2531
|
+
d.gain.setValueAtTime(d.gain.value, g - Rt / 1e3), d.gain.linearRampToValueAtTime(0, g), c.stop(g);
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
level(t) {
|
|
2535
|
+
return Math.max(0, Math.min(1, t)) * B.master;
|
|
2536
|
+
}
|
|
2537
|
+
context() {
|
|
2538
|
+
if (this.ctx) return this.ctx;
|
|
2539
|
+
if (typeof AudioContext > "u") return null;
|
|
2540
|
+
this.ctx = new AudioContext(), this.master = this.ctx.createGain(), this.master.gain.value = this.level(q.getState().sfxVolume);
|
|
2541
|
+
const t = this.ctx.createBiquadFilter();
|
|
2542
|
+
t.type = "highshelf", t.frequency.value = Ot.freq, t.gain.value = Ot.gainDb;
|
|
2543
|
+
const e = this.ctx.createBiquadFilter();
|
|
2544
|
+
e.type = "lowpass", e.frequency.value = mn, this.master.connect(t).connect(e).connect(this.ctx.destination);
|
|
2545
|
+
const s = this.ctx, n = () => {
|
|
2546
|
+
const r = s.state === "running";
|
|
2547
|
+
this.onRunning(r), r && this.prerender(s);
|
|
2548
|
+
};
|
|
2549
|
+
return s.addEventListener("statechange", n), s.state === "running" && queueMicrotask(n), s;
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Starts decoding every recorded take and renders every recipe not rendered yet, one per task, once the context
|
|
2553
|
+
* first runs — so the first swing of a fight does not pay for its sound in that frame.
|
|
2554
|
+
*/
|
|
2555
|
+
prerender(t) {
|
|
2556
|
+
for (const n of this.samples.names()) this.samples.load(t, n);
|
|
2557
|
+
const e = Object.keys(B.recipes).filter((n) => !this.buffers.has(n) && !Bt(n)), s = () => {
|
|
2558
|
+
const n = e.shift();
|
|
2559
|
+
n !== void 0 && (this.buffer(t, n), setTimeout(s, 0));
|
|
2560
|
+
};
|
|
2561
|
+
s();
|
|
2562
|
+
}
|
|
2563
|
+
/** Rendered on first use or by `prerender` (a few ms each), then kept. */
|
|
2564
|
+
buffer(t, e) {
|
|
2565
|
+
const s = this.buffers.get(e);
|
|
2566
|
+
if (s !== void 0) return s;
|
|
2567
|
+
const n = B.recipes[e];
|
|
2568
|
+
let r = null;
|
|
2569
|
+
if (n) {
|
|
2570
|
+
const o = ln(n);
|
|
2571
|
+
r = t.createBuffer(1, o.length, S), r.getChannelData(0).set(o);
|
|
2572
|
+
}
|
|
2573
|
+
return this.buffers.set(e, r), r;
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
const dr = new gn();
|
|
2577
|
+
class yn {
|
|
2578
|
+
ctx = null;
|
|
2579
|
+
master = null;
|
|
2580
|
+
tracks = [];
|
|
2581
|
+
raf = 0;
|
|
2582
|
+
unlocked = !1;
|
|
2583
|
+
cleanup = [];
|
|
2584
|
+
constructor() {
|
|
2585
|
+
if (typeof window > "u") return;
|
|
2586
|
+
const t = () => {
|
|
2587
|
+
this.unlocked = !0, this.ctx?.resume();
|
|
2588
|
+
for (const e of this.tracks) !e.dying && e.el.paused && e.el.play().catch(() => {
|
|
2589
|
+
});
|
|
2590
|
+
};
|
|
2591
|
+
for (const e of ["pointerdown", "keydown", "touchend"])
|
|
2592
|
+
window.addEventListener(e, t, { passive: !0 }), this.cleanup.push(() => window.removeEventListener(e, t));
|
|
2593
|
+
this.cleanup.push(q.subscribe(() => this.applyVolume()));
|
|
2594
|
+
}
|
|
2595
|
+
/** The url of the track playing (or fading in), if any. */
|
|
2596
|
+
get current() {
|
|
2597
|
+
for (let t = this.tracks.length - 1; t >= 0; t--) if (!this.tracks[t].dying) return this.tracks[t].url;
|
|
2598
|
+
return null;
|
|
2599
|
+
}
|
|
2600
|
+
/** Plays `url`, crossfading from what plays now. The track already playing is left alone. */
|
|
2601
|
+
play(t, e = {}) {
|
|
2602
|
+
if (typeof Audio > "u" || this.current === t) return;
|
|
2603
|
+
const s = Math.max(0, e.fadeMs ?? 1200);
|
|
2604
|
+
this.fadeOutAll(s);
|
|
2605
|
+
const n = new Audio(t);
|
|
2606
|
+
n.loop = e.loop !== !1, n.preload = "auto", n.crossOrigin = "anonymous";
|
|
2607
|
+
const r = { url: t, el: n, gain: null, level: Math.min(1, Math.max(0, e.volume ?? 1)), fade: { from: 0, to: 1, start: performance.now(), ms: s }, dying: !1 }, o = this.context();
|
|
2608
|
+
if (o && this.master) {
|
|
2609
|
+
const a = o.createGain();
|
|
2610
|
+
a.gain.value = 0, o.createMediaElementSource(n).connect(a).connect(this.master), r.gain = a;
|
|
2611
|
+
} else
|
|
2612
|
+
n.volume = 0;
|
|
2613
|
+
this.tracks.push(r), (this.unlocked || !this.needsGesture()) && n.play().catch(() => {
|
|
2614
|
+
}), this.tick();
|
|
2615
|
+
}
|
|
2616
|
+
/** Fades the music out and stops it. */
|
|
2617
|
+
stop(t = 1200) {
|
|
2618
|
+
this.fadeOutAll(Math.max(0, t)), this.tick();
|
|
2619
|
+
}
|
|
2620
|
+
pause() {
|
|
2621
|
+
for (const t of this.tracks) t.el.pause();
|
|
2622
|
+
}
|
|
2623
|
+
resume() {
|
|
2624
|
+
for (const t of this.tracks) t.dying || t.el.play().catch(() => {
|
|
2625
|
+
});
|
|
2626
|
+
}
|
|
2627
|
+
destroy() {
|
|
2628
|
+
cancelAnimationFrame(this.raf);
|
|
2629
|
+
for (const t of this.cleanup.splice(0)) t();
|
|
2630
|
+
for (const t of this.tracks.splice(0)) this.release(t);
|
|
2631
|
+
this.ctx?.close(), this.ctx = null;
|
|
2632
|
+
}
|
|
2633
|
+
fadeOutAll(t) {
|
|
2634
|
+
const e = performance.now();
|
|
2635
|
+
for (const s of this.tracks)
|
|
2636
|
+
s.dying || (s.fade = { from: ht(s.fade, e), to: 0, start: e, ms: t }, s.dying = !0);
|
|
2637
|
+
}
|
|
2638
|
+
/** Runs the fades a frame at a time until none is left. */
|
|
2639
|
+
tick = () => {
|
|
2640
|
+
cancelAnimationFrame(this.raf);
|
|
2641
|
+
const t = performance.now();
|
|
2642
|
+
let e = !1;
|
|
2643
|
+
for (let s = this.tracks.length - 1; s >= 0; s--) {
|
|
2644
|
+
const n = this.tracks[s], r = ht(n.fade, t);
|
|
2645
|
+
if (n.dying && r <= 0) {
|
|
2646
|
+
this.release(n), this.tracks.splice(s, 1);
|
|
2647
|
+
continue;
|
|
2648
|
+
}
|
|
2649
|
+
this.setLevel(n, r), t < n.fade.start + n.fade.ms && (e = !0);
|
|
2650
|
+
}
|
|
2651
|
+
e && (this.raf = requestAnimationFrame(this.tick));
|
|
2652
|
+
};
|
|
2653
|
+
applyVolume() {
|
|
2654
|
+
const t = performance.now();
|
|
2655
|
+
for (const e of this.tracks) this.setLevel(e, ht(e.fade, t));
|
|
2656
|
+
}
|
|
2657
|
+
setLevel(t, e) {
|
|
2658
|
+
const s = Math.min(1, Math.max(0, e * t.level * q.getState().musicVolume));
|
|
2659
|
+
t.gain ? t.gain.gain.value = s : t.el.volume = s;
|
|
2660
|
+
}
|
|
2661
|
+
release(t) {
|
|
2662
|
+
t.el.pause(), t.el.removeAttribute("src"), t.el.load(), t.gain?.disconnect();
|
|
2663
|
+
}
|
|
2664
|
+
needsGesture() {
|
|
2665
|
+
return this.ctx?.state === "suspended";
|
|
2666
|
+
}
|
|
2667
|
+
context() {
|
|
2668
|
+
if (this.ctx) return this.ctx;
|
|
2669
|
+
const t = globalThis.AudioContext;
|
|
2670
|
+
return t ? (this.ctx = new t(), this.master = this.ctx.createGain(), this.master.connect(this.ctx.destination), this.ctx) : null;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
function ht(i, t) {
|
|
2674
|
+
return i.ms <= 0 || t >= i.start + i.ms ? i.to : t <= i.start ? i.from : i.from + (i.to - i.from) * (t - i.start) / i.ms;
|
|
2675
|
+
}
|
|
2676
|
+
const fr = new yn();
|
|
2677
|
+
class pr {
|
|
2678
|
+
held = /* @__PURE__ */ new Set();
|
|
2679
|
+
down = /* @__PURE__ */ new Set();
|
|
2680
|
+
up = /* @__PURE__ */ new Set();
|
|
2681
|
+
cleanup = [];
|
|
2682
|
+
constructor(t = window) {
|
|
2683
|
+
const e = (r) => {
|
|
2684
|
+
const o = r.code;
|
|
2685
|
+
r.repeat || this.held.has(o) || (this.held.add(o), this.down.add(o));
|
|
2686
|
+
}, s = (r) => {
|
|
2687
|
+
const o = r.code;
|
|
2688
|
+
this.held.delete(o) && this.up.add(o);
|
|
2689
|
+
}, n = () => {
|
|
2690
|
+
for (const r of this.held) this.up.add(r);
|
|
2691
|
+
this.held.clear();
|
|
2692
|
+
};
|
|
2693
|
+
t.addEventListener("keydown", e), t.addEventListener("keyup", s), window.addEventListener("blur", n), this.cleanup.push(
|
|
2694
|
+
() => t.removeEventListener("keydown", e),
|
|
2695
|
+
() => t.removeEventListener("keyup", s),
|
|
2696
|
+
() => window.removeEventListener("blur", n)
|
|
2697
|
+
);
|
|
2698
|
+
}
|
|
2699
|
+
isDown(t) {
|
|
2700
|
+
return this.held.has(t);
|
|
2701
|
+
}
|
|
2702
|
+
/** Any of these keys is held. */
|
|
2703
|
+
anyDown(...t) {
|
|
2704
|
+
return t.some((e) => this.held.has(e));
|
|
2705
|
+
}
|
|
2706
|
+
/** Went down since the last `endStep`. */
|
|
2707
|
+
pressed(t) {
|
|
2708
|
+
return this.down.has(t);
|
|
2709
|
+
}
|
|
2710
|
+
/** Came up since the last `endStep`. */
|
|
2711
|
+
released(t) {
|
|
2712
|
+
return this.up.has(t);
|
|
2713
|
+
}
|
|
2714
|
+
/** -1, 0 or 1 from two sets of keys: `axis(['KeyA', 'ArrowLeft'], ['KeyD', 'ArrowRight'])`. */
|
|
2715
|
+
axis(t, e) {
|
|
2716
|
+
return (this.anyDown(...e) ? 1 : 0) - (this.anyDown(...t) ? 1 : 0);
|
|
2717
|
+
}
|
|
2718
|
+
/** Forgets this step's edges; held keys stay held. */
|
|
2719
|
+
endStep() {
|
|
2720
|
+
this.down.clear(), this.up.clear();
|
|
2721
|
+
}
|
|
2722
|
+
destroy() {
|
|
2723
|
+
for (const t of this.cleanup.splice(0)) t();
|
|
2724
|
+
this.held.clear(), this.endStep();
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
const wn = ["a", "b", "x", "y", "lb", "rb", "lt", "rt", "select", "start", "ls", "rs", "up", "down", "left", "right", "home"], xn = ["lx", "ly", "rx", "ry"];
|
|
2728
|
+
class mr {
|
|
2729
|
+
constructor(t, e, s = {}) {
|
|
2730
|
+
this.keyboard = t, this.bindings = new Map(Object.entries(e)), this.deadZone = s.deadZone ?? 0.25, this.gamepads = s.gamepads ?? (() => typeof navigator < "u" && typeof navigator.getGamepads == "function" ? navigator.getGamepads() : []);
|
|
2731
|
+
}
|
|
2732
|
+
keyboard;
|
|
2733
|
+
bindings;
|
|
2734
|
+
virtual = /* @__PURE__ */ new Set();
|
|
2735
|
+
virtualDown = /* @__PURE__ */ new Set();
|
|
2736
|
+
/** Analog value of each action this step (0–1), and last step's, for edges. */
|
|
2737
|
+
now = /* @__PURE__ */ new Map();
|
|
2738
|
+
before = /* @__PURE__ */ new Map();
|
|
2739
|
+
deadZone;
|
|
2740
|
+
gamepads;
|
|
2741
|
+
/** Replaces one action's bindings (a player's rebinding). */
|
|
2742
|
+
bind(t, e) {
|
|
2743
|
+
this.bindings.set(t, [...e]);
|
|
2744
|
+
}
|
|
2745
|
+
bindingsOf(t) {
|
|
2746
|
+
return this.bindings.get(t) ?? [];
|
|
2747
|
+
}
|
|
2748
|
+
/** A touch UI's virtual button went down: `touch:<name>` bindings read it. */
|
|
2749
|
+
press(t) {
|
|
2750
|
+
this.virtual.add(t), this.virtualDown.add(t);
|
|
2751
|
+
}
|
|
2752
|
+
release(t) {
|
|
2753
|
+
this.virtual.delete(t);
|
|
2754
|
+
}
|
|
2755
|
+
/** Reads every device once; call at the start of each simulation step. */
|
|
2756
|
+
poll() {
|
|
2757
|
+
[this.before, this.now] = [this.now, this.before], this.now.clear();
|
|
2758
|
+
const t = this.gamepads().filter((e) => e !== null);
|
|
2759
|
+
for (const [e, s] of this.bindings) {
|
|
2760
|
+
let n = 0;
|
|
2761
|
+
for (const r of s) n = Math.max(n, this.read(r, t));
|
|
2762
|
+
n > 0 && this.now.set(e, n);
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
/** Held this step. */
|
|
2766
|
+
down(t) {
|
|
2767
|
+
return (this.now.get(t) ?? 0) > 0;
|
|
2768
|
+
}
|
|
2769
|
+
/** How far it is held (0–1): 1 for a key, the trigger or stick amount for analog input. */
|
|
2770
|
+
value(t) {
|
|
2771
|
+
return this.now.get(t) ?? 0;
|
|
2772
|
+
}
|
|
2773
|
+
/** Went down this step. */
|
|
2774
|
+
pressed(t) {
|
|
2775
|
+
return this.down(t) && !((this.before.get(t) ?? 0) > 0);
|
|
2776
|
+
}
|
|
2777
|
+
/** Came up this step. */
|
|
2778
|
+
released(t) {
|
|
2779
|
+
return !this.down(t) && (this.before.get(t) ?? 0) > 0;
|
|
2780
|
+
}
|
|
2781
|
+
/** `value(positive) - value(negative)`, in −1…1. */
|
|
2782
|
+
axis(t, e) {
|
|
2783
|
+
return this.value(e) - this.value(t);
|
|
2784
|
+
}
|
|
2785
|
+
/** A 2D direction from four actions, never longer than 1 (a diagonal is not faster). */
|
|
2786
|
+
vector(t, e, s, n) {
|
|
2787
|
+
const r = this.axis(t, e), o = this.axis(s, n), a = Math.hypot(r, o);
|
|
2788
|
+
return a > 1 ? [r / a, o / a] : [r, o];
|
|
2789
|
+
}
|
|
2790
|
+
/** Ends the step: the keyboard forgets its edges; virtual taps shorter than a step have now been seen. */
|
|
2791
|
+
endStep() {
|
|
2792
|
+
this.keyboard?.endStep(), this.virtualDown.clear();
|
|
2793
|
+
}
|
|
2794
|
+
read(t, e) {
|
|
2795
|
+
if (t.startsWith("touch:")) {
|
|
2796
|
+
const s = t.slice(6);
|
|
2797
|
+
return this.virtual.has(s) || this.virtualDown.has(s) ? 1 : 0;
|
|
2798
|
+
}
|
|
2799
|
+
if (t.startsWith("pad:")) {
|
|
2800
|
+
const s = t.slice(4);
|
|
2801
|
+
let n = 0;
|
|
2802
|
+
const r = s.endsWith("+") ? 1 : s.endsWith("-") ? -1 : 0;
|
|
2803
|
+
if (r !== 0) {
|
|
2804
|
+
const a = xn.indexOf(s.slice(0, -1));
|
|
2805
|
+
if (a < 0) return 0;
|
|
2806
|
+
for (const h of e) {
|
|
2807
|
+
const l = (h.axes[a] ?? 0) * r;
|
|
2808
|
+
l > this.deadZone && (n = Math.max(n, (l - this.deadZone) / (1 - this.deadZone)));
|
|
2809
|
+
}
|
|
2810
|
+
return Math.min(1, n);
|
|
2811
|
+
}
|
|
2812
|
+
const o = wn.indexOf(s);
|
|
2813
|
+
if (o < 0) return 0;
|
|
2814
|
+
for (const a of e) {
|
|
2815
|
+
const h = a.buttons[o];
|
|
2816
|
+
h?.pressed && (n = Math.max(n, h.value > 0 ? h.value : 1));
|
|
2817
|
+
}
|
|
2818
|
+
return Math.min(1, n);
|
|
2819
|
+
}
|
|
2820
|
+
return this.keyboard?.isDown(t) || this.keyboard?.pressed(t) ? 1 : 0;
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
function gr(i) {
|
|
2824
|
+
const t = Math.cos(i), e = Math.sin(i), s = Math.sin(Math.PI / 8);
|
|
2825
|
+
return { dx: Math.abs(t) > s ? Math.sign(t) : 0, dy: Math.abs(e) > s ? Math.sign(e) : 0 };
|
|
2826
|
+
}
|
|
2827
|
+
const Yt = 0.28;
|
|
2828
|
+
function yr(i, t, e) {
|
|
2829
|
+
if (e <= 0) return { x: 0, y: 0 };
|
|
2830
|
+
const s = Math.hypot(i, t);
|
|
2831
|
+
if (s === 0) return { x: 0, y: 0 };
|
|
2832
|
+
const n = s > e ? 1 / s : 1 / e;
|
|
2833
|
+
return { x: i * n, y: t * n };
|
|
2834
|
+
}
|
|
2835
|
+
function bn(i, t = Yt) {
|
|
2836
|
+
return Math.hypot(i.x, i.y) >= t;
|
|
2837
|
+
}
|
|
2838
|
+
function wr(i, t = Yt) {
|
|
2839
|
+
if (!bn(i, t)) return { dx: 0, dy: 0 };
|
|
2840
|
+
const s = Math.round(Math.atan2(i.y, i.x) / (Math.PI / 4)) * (Math.PI / 4), n = (r) => Math.abs(r) < 1e-9 ? 0 : Math.sign(r);
|
|
2841
|
+
return { dx: n(Math.cos(s)), dy: n(Math.sin(s)) };
|
|
2842
|
+
}
|
|
2843
|
+
class xr {
|
|
2844
|
+
constructor(t = 480, e = 10) {
|
|
2845
|
+
this.ms = t, this.slop = e;
|
|
2846
|
+
}
|
|
2847
|
+
ms;
|
|
2848
|
+
slop;
|
|
2849
|
+
finger = null;
|
|
2850
|
+
done = !1;
|
|
2851
|
+
down(t, e, s, n) {
|
|
2852
|
+
if (this.finger) {
|
|
2853
|
+
this.finger = null, this.done = !0;
|
|
2854
|
+
return;
|
|
2855
|
+
}
|
|
2856
|
+
this.finger = { id: t, x: e, y: s, at: n }, this.done = !1;
|
|
2857
|
+
}
|
|
2858
|
+
move(t, e, s) {
|
|
2859
|
+
const n = this.finger;
|
|
2860
|
+
n && n.id === t && Math.hypot(e - n.x, s - n.y) > this.slop && (this.finger = null);
|
|
2861
|
+
}
|
|
2862
|
+
up(t) {
|
|
2863
|
+
this.finger?.id === t && (this.finger = null), this.finger || (this.done = !1);
|
|
2864
|
+
}
|
|
2865
|
+
/** Where the press is, the first time this is asked at or after `ms`; null otherwise. */
|
|
2866
|
+
fire(t) {
|
|
2867
|
+
const e = this.finger;
|
|
2868
|
+
return !e || this.done || t - e.at < this.ms ? null : (this.done = !0, { x: e.x, y: e.y });
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
const jt = 1, I = 5, W = 16, j = 8, O = 256, Vt = Math.PI * 2;
|
|
2872
|
+
function E(i, t, e) {
|
|
2873
|
+
if (!Number.isFinite(i)) return Number.isNaN(i) ? 0 : i > 0 ? e : t;
|
|
2874
|
+
const s = Math.round(i);
|
|
2875
|
+
return s < t ? t : s > e ? e : s;
|
|
2876
|
+
}
|
|
2877
|
+
function st(i) {
|
|
2878
|
+
return E(i * j, -32768, 32767);
|
|
2879
|
+
}
|
|
2880
|
+
function Xt(i) {
|
|
2881
|
+
return Number.isFinite(i) ? (Math.round(i * O / Vt) % O + O) % O : 0;
|
|
2882
|
+
}
|
|
2883
|
+
function Jt(i) {
|
|
2884
|
+
return (i >= O / 2 ? i - O : i) * Vt / O;
|
|
2885
|
+
}
|
|
2886
|
+
function Kt(i, t, e) {
|
|
2887
|
+
i.setInt32(t, E(e[0], -2147483648, 2147483647)), i.setInt16(t + 4, st(e[1])), i.setInt16(t + 6, st(e[2])), i.setUint8(t + 8, Xt(e[3])), i.setUint8(t + 9, E(e[4], 0, 255)), i.setInt32(t + 10, E(e[5], -2147483648, 2147483647)), i.setUint16(t + 14, E(e[6], 0, 65535));
|
|
2888
|
+
}
|
|
2889
|
+
function vn(i, t) {
|
|
2890
|
+
return [
|
|
2891
|
+
i.getInt32(t),
|
|
2892
|
+
i.getInt16(t + 4) / j,
|
|
2893
|
+
i.getInt16(t + 6) / j,
|
|
2894
|
+
Jt(i.getUint8(t + 8)),
|
|
2895
|
+
i.getUint8(t + 9),
|
|
2896
|
+
i.getInt32(t + 10),
|
|
2897
|
+
i.getUint16(t + 14)
|
|
2898
|
+
];
|
|
2899
|
+
}
|
|
2900
|
+
function br(i) {
|
|
2901
|
+
const t = new Uint8Array(i.length * W), e = new DataView(t.buffer);
|
|
2902
|
+
for (let s = 0; s < i.length; s++) Kt(e, s * W, i[s]);
|
|
2903
|
+
return t;
|
|
2904
|
+
}
|
|
2905
|
+
function Mn(i) {
|
|
2906
|
+
if (i.byteLength % W !== 0) throw new Error(`update block of ${i.byteLength} bytes`);
|
|
2907
|
+
const t = new DataView(i.buffer, i.byteOffset, i.byteLength), e = [];
|
|
2908
|
+
for (let s = 0; s < i.byteLength; s += W) e.push(vn(t, s));
|
|
2909
|
+
return e;
|
|
2910
|
+
}
|
|
2911
|
+
function vr(i) {
|
|
2912
|
+
const t = new Array(i.length);
|
|
2913
|
+
for (let e = 0; e < i.length; e++) {
|
|
2914
|
+
const s = i[e];
|
|
2915
|
+
t[e] = [
|
|
2916
|
+
E(s[0], -2147483648, 2147483647) + 0,
|
|
2917
|
+
st(s[1]) / j + 0,
|
|
2918
|
+
st(s[2]) / j + 0,
|
|
2919
|
+
Jt(Xt(s[3])),
|
|
2920
|
+
E(s[4], 0, 255) + 0,
|
|
2921
|
+
E(s[5], -2147483648, 2147483647) + 0,
|
|
2922
|
+
E(s[6], 0, 65535) + 0
|
|
2923
|
+
];
|
|
2924
|
+
}
|
|
2925
|
+
return t;
|
|
2926
|
+
}
|
|
2927
|
+
const Zt = globalThis, An = new Zt.TextEncoder(), kn = new Zt.TextDecoder();
|
|
2928
|
+
function Sn(i) {
|
|
2929
|
+
const { up: t, ...e } = i, s = An.encode(JSON.stringify(e)), n = t?.length ? t.length : 0, r = new Uint8Array(I + s.byteLength + n * W), o = new DataView(r.buffer);
|
|
2930
|
+
o.setUint8(0, jt), o.setUint32(1, s.byteLength), r.set(s, I);
|
|
2931
|
+
const a = I + s.byteLength;
|
|
2932
|
+
for (let h = 0; h < n; h++) Kt(o, a + h * W, t[h]);
|
|
2933
|
+
return r;
|
|
2934
|
+
}
|
|
2935
|
+
function En(i) {
|
|
2936
|
+
const t = i instanceof Uint8Array ? i : new Uint8Array(i);
|
|
2937
|
+
if (t.byteLength < I) throw new Error("short snapshot frame");
|
|
2938
|
+
const e = new DataView(t.buffer, t.byteOffset, t.byteLength), s = e.getUint8(0);
|
|
2939
|
+
if (s !== jt) throw new Error(`unknown binary frame tag ${s}`);
|
|
2940
|
+
const n = e.getUint32(1), r = I + n;
|
|
2941
|
+
if (r > t.byteLength) throw new Error("snapshot frame JSON overruns the frame");
|
|
2942
|
+
const o = JSON.parse(kn.decode(t.subarray(I, r)));
|
|
2943
|
+
return r < t.byteLength && (o.up = Mn(t.subarray(r))), o;
|
|
2944
|
+
}
|
|
2945
|
+
const Mr = {
|
|
2946
|
+
/** A basic attack may arrive this share of its interval early. */
|
|
2947
|
+
attackEarlyShare: 0.2,
|
|
2948
|
+
/** The cast lock and the attack lock a cast leaves may be cut this short. */
|
|
2949
|
+
lockSlackMs: 60,
|
|
2950
|
+
/** A skill may be cast this long before its cooldown ends. */
|
|
2951
|
+
cooldownSlackMs: 40,
|
|
2952
|
+
/** A potion may be drunk this long before its kind's cooldown ends. */
|
|
2953
|
+
potionSlackMs: 150
|
|
2954
|
+
};
|
|
2955
|
+
function Ar(i, t, e) {
|
|
2956
|
+
return t !== void 0 && i < t - e;
|
|
2957
|
+
}
|
|
2958
|
+
function kr(i, t, e) {
|
|
2959
|
+
return Math.max(i, t ?? i) + e;
|
|
2960
|
+
}
|
|
2961
|
+
const Fn = 6e4, Bn = 2e3;
|
|
2962
|
+
let it = 0, ut = 1 / 0, dt = 0, ft = !1;
|
|
2963
|
+
function Sr() {
|
|
2964
|
+
return Date.now() + it;
|
|
2965
|
+
}
|
|
2966
|
+
function Er() {
|
|
2967
|
+
return it;
|
|
2968
|
+
}
|
|
2969
|
+
function Dn(i, t, e = Date.now()) {
|
|
2970
|
+
!Number.isFinite(i) || !Number.isFinite(t) || t < 0 || t > Bn || ft && t > ut && e - dt < Fn || (it = i + t / 2 - e, ut = t, dt = e, ft = !0);
|
|
2971
|
+
}
|
|
2972
|
+
function Fr() {
|
|
2973
|
+
it = 0, ut = 1 / 0, dt = 0, ft = !1;
|
|
2974
|
+
}
|
|
2975
|
+
function Tn(i) {
|
|
2976
|
+
return [i.x, i.y, i.lastDx, i.lastDy, i.dashLeft, i.dashCd, i.dashDx, i.dashDy];
|
|
2977
|
+
}
|
|
2978
|
+
function Rn(i, t) {
|
|
2979
|
+
return [t.x, t.y, t.lastDx, t.lastDy, t.dashLeft, t.dashCd, t.dashDx, t.dashDy] = i, t;
|
|
2980
|
+
}
|
|
2981
|
+
class Br {
|
|
2982
|
+
constructor(t, e, s, n) {
|
|
2983
|
+
this.params = s, this.grid = n, this.mover = qt(t, e);
|
|
2984
|
+
}
|
|
2985
|
+
params;
|
|
2986
|
+
grid;
|
|
2987
|
+
mover;
|
|
2988
|
+
pending = [];
|
|
2989
|
+
nextSeq = 0;
|
|
2990
|
+
/** The jump the last reconciliation made, still being eased out (world px). */
|
|
2991
|
+
offsetX = 0;
|
|
2992
|
+
offsetY = 0;
|
|
2993
|
+
/** How big the last correction was (0 when the prediction was right). */
|
|
2994
|
+
correction = 0;
|
|
2995
|
+
/** Share of a visual correction left after each 60th of a second (default 0.8). */
|
|
2996
|
+
smoothing = 0.8;
|
|
2997
|
+
/** Applies one input step now and keeps it for replay; returns its sequence number (send it with the step). */
|
|
2998
|
+
step(t) {
|
|
2999
|
+
const e = this.nextSeq++;
|
|
3000
|
+
return this.pending.push({ seq: e, step: [t[0], t[1], t[2]] }), ct(this.mover, t, this.params, this.grid), e;
|
|
3001
|
+
}
|
|
3002
|
+
/** Steps sent but not yet acknowledged. */
|
|
3003
|
+
get unacknowledged() {
|
|
3004
|
+
return this.pending.length;
|
|
3005
|
+
}
|
|
3006
|
+
/** The server's word: the body as of step `ack`. Rewinds there and replays the rest. */
|
|
3007
|
+
reconcile(t, e) {
|
|
3008
|
+
const s = this.mover.x, n = this.mover.y;
|
|
3009
|
+
let r = 0;
|
|
3010
|
+
for (; r < this.pending.length && this.pending[r].seq <= t; ) r++;
|
|
3011
|
+
r && (this.pending = this.pending.slice(r)), Rn(e, this.mover);
|
|
3012
|
+
for (const h of this.pending) ct(this.mover, h.step, this.params, this.grid);
|
|
3013
|
+
const o = s - this.mover.x, a = n - this.mover.y;
|
|
3014
|
+
this.correction = Math.hypot(o, a), this.correction > 0.01 && this.correction < 64 ? (this.offsetX += o, this.offsetY += a) : this.correction >= 64 && (this.offsetX = this.offsetY = 0);
|
|
3015
|
+
}
|
|
3016
|
+
/** Eases the visual correction out; call once a frame with its length in seconds. */
|
|
3017
|
+
smooth(t) {
|
|
3018
|
+
const e = Math.pow(this.smoothing, t * 60);
|
|
3019
|
+
this.offsetX *= e, this.offsetY *= e, Math.abs(this.offsetX) < 0.01 && (this.offsetX = 0), Math.abs(this.offsetY) < 0.01 && (this.offsetY = 0);
|
|
3020
|
+
}
|
|
3021
|
+
/** Where to draw the body: the predicted place plus the correction still being eased out. */
|
|
3022
|
+
get drawX() {
|
|
3023
|
+
return this.mover.x + this.offsetX;
|
|
3024
|
+
}
|
|
3025
|
+
get drawY() {
|
|
3026
|
+
return this.mover.y + this.offsetY;
|
|
3027
|
+
}
|
|
3028
|
+
/** New movement rules (a buff, a slow): applied to future steps and to replays. */
|
|
3029
|
+
setParams(t) {
|
|
3030
|
+
this.params = t;
|
|
3031
|
+
}
|
|
3032
|
+
setGrid(t) {
|
|
3033
|
+
this.grid = t;
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
class Dr {
|
|
3037
|
+
constructor(t = 100, e = 120, s = 30) {
|
|
3038
|
+
this.delayMs = t, this.maxExtrapolateMs = e, this.keep = s;
|
|
3039
|
+
}
|
|
3040
|
+
delayMs;
|
|
3041
|
+
maxExtrapolateMs;
|
|
3042
|
+
keep;
|
|
3043
|
+
samples = /* @__PURE__ */ new Map();
|
|
3044
|
+
/** Records every body of a snapshot taken at `time`. */
|
|
3045
|
+
push(t, e) {
|
|
3046
|
+
for (const [s, n, r, o, a, h, l] of e) {
|
|
3047
|
+
let c = this.samples.get(s);
|
|
3048
|
+
c || (c = [], this.samples.set(s, c));
|
|
3049
|
+
const u = c[c.length - 1];
|
|
3050
|
+
u && t <= u.time || (c.push({ time: t, x: n, y: r, aim: o, anim: a, hp: h, flags: l }), c.length > this.keep && c.splice(0, c.length - this.keep));
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
/** Forgets a body (it left view). */
|
|
3054
|
+
remove(t) {
|
|
3055
|
+
this.samples.delete(t);
|
|
3056
|
+
}
|
|
3057
|
+
has(t) {
|
|
3058
|
+
return this.samples.has(t);
|
|
3059
|
+
}
|
|
3060
|
+
ids() {
|
|
3061
|
+
return this.samples.keys();
|
|
3062
|
+
}
|
|
3063
|
+
/** Where body `id` should be drawn at server time `now`, or null if nothing is known of it. */
|
|
3064
|
+
sample(t, e) {
|
|
3065
|
+
const s = this.samples.get(t);
|
|
3066
|
+
if (!s || s.length === 0) return null;
|
|
3067
|
+
const n = e - this.delayMs, r = s[0];
|
|
3068
|
+
if (n <= r.time || s.length === 1) return On(r);
|
|
3069
|
+
for (let c = s.length - 1; c > 0; c--) {
|
|
3070
|
+
const u = s[c - 1], d = s[c];
|
|
3071
|
+
if (n >= u.time && n <= d.time) {
|
|
3072
|
+
const m = d.time === u.time ? 1 : (n - u.time) / (d.time - u.time);
|
|
3073
|
+
return Ct(u, d, m);
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
const o = s[s.length - 2], a = s[s.length - 1], h = Math.min(n - a.time, this.maxExtrapolateMs), l = a.time === o.time ? 1 : 1 + h / (a.time - o.time);
|
|
3077
|
+
return Ct(o, a, l);
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
function On(i) {
|
|
3081
|
+
return { x: i.x, y: i.y, aim: i.aim, anim: i.anim, hp: i.hp, flags: i.flags };
|
|
3082
|
+
}
|
|
3083
|
+
function Ct(i, t, e) {
|
|
3084
|
+
let s = t.aim - i.aim;
|
|
3085
|
+
s > Math.PI && (s -= Math.PI * 2), s < -Math.PI && (s += Math.PI * 2);
|
|
3086
|
+
const n = e < 1 ? i : t;
|
|
3087
|
+
return { x: i.x + (t.x - i.x) * e, y: i.y + (t.y - i.y) * e, aim: i.aim + s * e, anim: n.anim, hp: n.hp, flags: n.flags };
|
|
3088
|
+
}
|
|
3089
|
+
class Tr {
|
|
3090
|
+
constructor(t) {
|
|
3091
|
+
this.options = t, this.maxQueue = t.maxQueue ?? 30, this.maxSteps = t.maxStepsPerTick ?? 3, this.backlog = t.backlog ?? 4;
|
|
3092
|
+
}
|
|
3093
|
+
options;
|
|
3094
|
+
players = /* @__PURE__ */ new Map();
|
|
3095
|
+
tick = 0;
|
|
3096
|
+
known = /* @__PURE__ */ new Map();
|
|
3097
|
+
maxQueue;
|
|
3098
|
+
maxSteps;
|
|
3099
|
+
backlog;
|
|
3100
|
+
join(t, e) {
|
|
3101
|
+
if (this.players.has(t)) throw new Error(`Room: player ${t} has already joined`);
|
|
3102
|
+
const s = this.options.spawn(t, e), n = {
|
|
3103
|
+
id: t,
|
|
3104
|
+
mover: qt(s.x, s.y),
|
|
3105
|
+
data: e,
|
|
3106
|
+
params: { ...this.options.params },
|
|
3107
|
+
ack: -1,
|
|
3108
|
+
queue: [],
|
|
3109
|
+
aim: 0,
|
|
3110
|
+
anim: 0,
|
|
3111
|
+
hp: 0,
|
|
3112
|
+
flags: 0,
|
|
3113
|
+
strikes: 0
|
|
3114
|
+
};
|
|
3115
|
+
return this.players.set(t, n), this.known.set(t, /* @__PURE__ */ new Set()), n;
|
|
3116
|
+
}
|
|
3117
|
+
leave(t) {
|
|
3118
|
+
this.players.delete(t), this.known.delete(t);
|
|
3119
|
+
}
|
|
3120
|
+
/**
|
|
3121
|
+
* Input steps `seq`, `seq + 1`, … from a player. Steps already received are skipped (a resend), any step with
|
|
3122
|
+
* numbers no client sends refuses the whole message, and steps past a full queue are dropped. Returns false when
|
|
3123
|
+
* something was refused.
|
|
3124
|
+
*/
|
|
3125
|
+
input(t, e, s) {
|
|
3126
|
+
const n = this.players.get(t);
|
|
3127
|
+
if (!n) return !1;
|
|
3128
|
+
if (!Number.isInteger(e) || e < 0 || !Array.isArray(s) || s.length > this.maxQueue)
|
|
3129
|
+
return n.strikes++, !1;
|
|
3130
|
+
for (const h of s)
|
|
3131
|
+
if (!Array.isArray(h) || h.length !== 3 || !h.every((l) => Number.isFinite(l)) || Math.abs(h[0]) > 1 || Math.abs(h[1]) > 1 || !Number.isInteger(h[2]))
|
|
3132
|
+
return n.strikes++, !1;
|
|
3133
|
+
const r = n.ack + 1 + n.queue.length, o = e - r;
|
|
3134
|
+
if (o > this.maxQueue)
|
|
3135
|
+
return n.strikes++, !1;
|
|
3136
|
+
for (let h = 0; h < o; h++) n.queue.push([0, 0, 0]);
|
|
3137
|
+
let a = !0;
|
|
3138
|
+
for (let h = 0; h < s.length; h++)
|
|
3139
|
+
if (!(e + h < r)) {
|
|
3140
|
+
if (n.queue.length >= this.maxQueue) {
|
|
3141
|
+
a = !1, n.strikes++;
|
|
3142
|
+
break;
|
|
3143
|
+
}
|
|
3144
|
+
n.queue.push([s[h][0], s[h][1], s[h][2]]);
|
|
3145
|
+
}
|
|
3146
|
+
return a;
|
|
3147
|
+
}
|
|
3148
|
+
/** One simulation step for everyone. */
|
|
3149
|
+
step() {
|
|
3150
|
+
this.tick++;
|
|
3151
|
+
for (const t of this.players.values()) {
|
|
3152
|
+
const e = t.queue.length;
|
|
3153
|
+
if (e === 0) continue;
|
|
3154
|
+
const s = e > this.backlog ? Math.min(this.maxSteps, e - this.backlog + 1) : 1;
|
|
3155
|
+
for (let n = 0; n < s; n++) {
|
|
3156
|
+
const r = t.queue.shift();
|
|
3157
|
+
ct(t.mover, r, t.params, this.options.grid), t.ack++, this.options.onStep?.(t, r);
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
/** The snapshot player `id` should get now. `time` is the server's wall clock (ms). */
|
|
3162
|
+
snapshotFor(t, e) {
|
|
3163
|
+
const s = this.players.get(t), n = this.known.get(t);
|
|
3164
|
+
if (!s || !n) return null;
|
|
3165
|
+
const r = [], o = [], a = /* @__PURE__ */ new Set();
|
|
3166
|
+
for (const c of this.players.values())
|
|
3167
|
+
a.add(c.id), r.push([c.id, c.mover.x, c.mover.y, c.aim, c.anim, c.hp, c.flags]), n.has(c.id) || (n.add(c.id), o.push({ id: c.id, data: c.data }));
|
|
3168
|
+
const h = [];
|
|
3169
|
+
for (const c of n)
|
|
3170
|
+
a.has(c) || (n.delete(c), h.push(c));
|
|
3171
|
+
const l = { t: "snap", tick: this.tick, time: e, ack: s.ack, me: Tn(s.mover), up: r };
|
|
3172
|
+
return o.length && (l.sp = o), h.length && (l.rm = h), l;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
class Rr {
|
|
3176
|
+
constructor(t, e = {}) {
|
|
3177
|
+
this.room = t, this.options = e, this.stepMs = 1e3 / (e.stepRate ?? 60), this.snapEvery = Math.max(1, Math.round((e.stepRate ?? 60) / (e.snapRate ?? 20))), this.now = e.now ?? Date.now;
|
|
3178
|
+
}
|
|
3179
|
+
room;
|
|
3180
|
+
options;
|
|
3181
|
+
sockets = /* @__PURE__ */ new Map();
|
|
3182
|
+
joined = /* @__PURE__ */ new Set();
|
|
3183
|
+
nextId = 1;
|
|
3184
|
+
stepTimer = null;
|
|
3185
|
+
lastStepAt = 0;
|
|
3186
|
+
stepsDue = 0;
|
|
3187
|
+
stepMs;
|
|
3188
|
+
snapEvery;
|
|
3189
|
+
now;
|
|
3190
|
+
/** A socket connected; returns the id its messages and its close are reported under. */
|
|
3191
|
+
connect(t) {
|
|
3192
|
+
const e = this.nextId++;
|
|
3193
|
+
return this.sockets.set(e, t), e;
|
|
3194
|
+
}
|
|
3195
|
+
/** A message arrived from socket `id` (text as a string, binary as bytes). */
|
|
3196
|
+
message(t, e) {
|
|
3197
|
+
if (typeof e != "string") return;
|
|
3198
|
+
let s;
|
|
3199
|
+
try {
|
|
3200
|
+
s = JSON.parse(e);
|
|
3201
|
+
} catch {
|
|
3202
|
+
return this.strike(t);
|
|
3203
|
+
}
|
|
3204
|
+
if (!s || typeof s != "object" || typeof s.t != "string") return this.strike(t);
|
|
3205
|
+
switch (s.t) {
|
|
3206
|
+
case "hello": {
|
|
3207
|
+
if (this.joined.has(t)) return;
|
|
3208
|
+
let n;
|
|
3209
|
+
try {
|
|
3210
|
+
n = this.options.admit ? this.options.admit(s.data, t) : s.data;
|
|
3211
|
+
} catch (r) {
|
|
3212
|
+
this.sockets.get(t)?.close(4003, r instanceof Error ? r.message : "refused");
|
|
3213
|
+
return;
|
|
3214
|
+
}
|
|
3215
|
+
this.room.join(t, n), this.joined.add(t), this.sendTo(t, { t: "welcome", id: t, tick: this.room.tick, stepRate: 1e3 / this.stepMs, snapRate: 1e3 / this.stepMs / this.snapEvery }), this.options.onJoin?.(t);
|
|
3216
|
+
return;
|
|
3217
|
+
}
|
|
3218
|
+
case "input": {
|
|
3219
|
+
const n = s;
|
|
3220
|
+
if (!this.joined.has(t)) return;
|
|
3221
|
+
this.room.input(t, n.seq, n.steps) || this.checkStrikes(t);
|
|
3222
|
+
return;
|
|
3223
|
+
}
|
|
3224
|
+
case "ping": {
|
|
3225
|
+
const n = s.c;
|
|
3226
|
+
typeof n == "number" && Number.isFinite(n) && this.sendTo(t, { t: "pong", c: n, st: this.now() });
|
|
3227
|
+
return;
|
|
3228
|
+
}
|
|
3229
|
+
default:
|
|
3230
|
+
this.joined.has(t) && this.options.onMessage?.(t, s);
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
/** Socket `id` closed. */
|
|
3234
|
+
disconnect(t) {
|
|
3235
|
+
this.sockets.delete(t), this.joined.delete(t) && (this.room.leave(t), this.options.onLeave?.(t));
|
|
3236
|
+
}
|
|
3237
|
+
/** Sends one of the game's own messages to a player. */
|
|
3238
|
+
sendTo(t, e) {
|
|
3239
|
+
const s = this.sockets.get(t);
|
|
3240
|
+
s && (e.t === "snap" && e.up?.length ? s.send(Sn(e)) : s.send(JSON.stringify(e)));
|
|
3241
|
+
}
|
|
3242
|
+
/** Starts stepping on a timer. Steps are counted by the clock, so a late timer runs the steps it owes. */
|
|
3243
|
+
start() {
|
|
3244
|
+
this.stepTimer || (this.lastStepAt = this.now(), this.stepTimer = setInterval(() => {
|
|
3245
|
+
const t = this.now();
|
|
3246
|
+
for (this.stepsDue += (t - this.lastStepAt) / this.stepMs, this.lastStepAt = t, this.stepsDue = Math.min(this.stepsDue, 60); this.stepsDue >= 1; )
|
|
3247
|
+
this.stepsDue--, this.stepOnce();
|
|
3248
|
+
}, this.stepMs / 2));
|
|
3249
|
+
}
|
|
3250
|
+
stop() {
|
|
3251
|
+
this.stepTimer && clearInterval(this.stepTimer), this.stepTimer = null;
|
|
3252
|
+
}
|
|
3253
|
+
/** One step, and the snapshots when they are due. Exposed for tests and for servers that drive their own loop. */
|
|
3254
|
+
stepOnce() {
|
|
3255
|
+
if (this.room.step(), this.room.tick % this.snapEvery !== 0) return;
|
|
3256
|
+
const t = this.now();
|
|
3257
|
+
for (const e of this.joined) {
|
|
3258
|
+
const s = this.room.snapshotFor(e, t);
|
|
3259
|
+
s && this.sendTo(e, s);
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
strike(t) {
|
|
3263
|
+
const e = this.room.players.get(t);
|
|
3264
|
+
e && (e.strikes++, this.checkStrikes(t));
|
|
3265
|
+
}
|
|
3266
|
+
checkStrikes(t) {
|
|
3267
|
+
const e = this.room.players.get(t);
|
|
3268
|
+
e && e.strikes >= (this.options.maxStrikes ?? 20) && (this.sockets.get(t)?.close(4008, "too much invalid input"), this.disconnect(t));
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
class Or {
|
|
3272
|
+
constructor(t, e = {}) {
|
|
3273
|
+
this.url = t, this.options = e;
|
|
3274
|
+
}
|
|
3275
|
+
url;
|
|
3276
|
+
options;
|
|
3277
|
+
events = new Pt();
|
|
3278
|
+
/** The last measured round trip, ms. */
|
|
3279
|
+
rtt = 0;
|
|
3280
|
+
socket = null;
|
|
3281
|
+
batch = null;
|
|
3282
|
+
closedByUs = !1;
|
|
3283
|
+
attempt = 0;
|
|
3284
|
+
pingTimer = null;
|
|
3285
|
+
retryTimer = null;
|
|
3286
|
+
get open() {
|
|
3287
|
+
return this.socket?.readyState === 1;
|
|
3288
|
+
}
|
|
3289
|
+
connect() {
|
|
3290
|
+
this.closedByUs = !1;
|
|
3291
|
+
const t = this.options.WebSocket ?? globalThis.WebSocket;
|
|
3292
|
+
if (!t) throw new Error("Connection: no WebSocket in this environment");
|
|
3293
|
+
const e = new t(this.url);
|
|
3294
|
+
return e.binaryType = "arraybuffer", this.socket = e, e.onopen = () => {
|
|
3295
|
+
this.attempt = 0, this.send({ t: "hello", data: this.options.hello?.() }), this.ping(), this.pingTimer = setInterval(() => this.ping(), this.options.pingMs ?? 1e3), this.events.emit("open", void 0);
|
|
3296
|
+
}, e.onmessage = (s) => this.receive(s.data), e.onclose = (s) => {
|
|
3297
|
+
this.pingTimer && clearInterval(this.pingTimer), this.pingTimer = null, this.socket = null;
|
|
3298
|
+
const n = !this.closedByUs && this.options.reconnect !== !1;
|
|
3299
|
+
if (this.events.emit("close", { code: s.code, reason: s.reason, willRetry: n }), n) {
|
|
3300
|
+
const r = Math.min(this.options.maxBackoffMs ?? 1e4, 250 * 2 ** this.attempt++);
|
|
3301
|
+
this.retryTimer = setTimeout(() => this.connect(), r);
|
|
3302
|
+
}
|
|
3303
|
+
}, this;
|
|
3304
|
+
}
|
|
3305
|
+
/** Sends a message now (dropped while closed: input is resent by the prediction's own state, not by the socket). */
|
|
3306
|
+
send(t) {
|
|
3307
|
+
this.socket?.readyState === 1 && this.socket.send(JSON.stringify(t));
|
|
3308
|
+
}
|
|
3309
|
+
/** Adds one input step to this frame's batch; `flush` sends it. Steps must come in sequence order. */
|
|
3310
|
+
queueInput(t, e) {
|
|
3311
|
+
this.batch || (this.batch = { seq: t, steps: [] }), this.batch.steps.push([e[0], e[1], e[2]]);
|
|
3312
|
+
}
|
|
3313
|
+
/** Sends this frame's input steps as one message. Call once a frame. */
|
|
3314
|
+
flush() {
|
|
3315
|
+
this.batch && (this.send({ t: "input", seq: this.batch.seq, steps: this.batch.steps }), this.batch = null);
|
|
3316
|
+
}
|
|
3317
|
+
close() {
|
|
3318
|
+
this.closedByUs = !0, this.retryTimer && clearTimeout(this.retryTimer), this.pingTimer && clearInterval(this.pingTimer), this.socket?.close(), this.socket = null;
|
|
3319
|
+
}
|
|
3320
|
+
ping() {
|
|
3321
|
+
this.send({ t: "ping", c: Date.now() });
|
|
3322
|
+
}
|
|
3323
|
+
receive(t) {
|
|
3324
|
+
let e;
|
|
3325
|
+
try {
|
|
3326
|
+
e = typeof t == "string" ? JSON.parse(t) : En(t);
|
|
3327
|
+
} catch (s) {
|
|
3328
|
+
console.error("[net] could not read a message", s);
|
|
3329
|
+
return;
|
|
3330
|
+
}
|
|
3331
|
+
switch (e.t) {
|
|
3332
|
+
case "pong": {
|
|
3333
|
+
const s = e;
|
|
3334
|
+
this.rtt = Date.now() - s.c, Dn(s.st, this.rtt);
|
|
3335
|
+
return;
|
|
3336
|
+
}
|
|
3337
|
+
case "welcome":
|
|
3338
|
+
this.events.emit("welcome", e);
|
|
3339
|
+
return;
|
|
3340
|
+
case "snap":
|
|
3341
|
+
this.events.emit("snapshot", e);
|
|
3342
|
+
return;
|
|
3343
|
+
default:
|
|
3344
|
+
this.events.emit("message", e);
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
export {
|
|
3349
|
+
mr as Actions,
|
|
3350
|
+
os as AnimationComponent,
|
|
3351
|
+
zn as Animator,
|
|
3352
|
+
$n as AssetLoader,
|
|
3353
|
+
Wn as AtlasBuilder,
|
|
3354
|
+
pe as BODY_HALF_HEIGHT,
|
|
3355
|
+
fe as BODY_HALF_WIDTH,
|
|
3356
|
+
be as BitmapLabel,
|
|
3357
|
+
Mr as CADENCE,
|
|
3358
|
+
ge as Camera,
|
|
3359
|
+
Oe as CanvasTexture,
|
|
3360
|
+
ye as Clock,
|
|
3361
|
+
Or as Connection,
|
|
3362
|
+
vt as DIAGONAL,
|
|
3363
|
+
Wt as Engine,
|
|
3364
|
+
Pt as EventBus,
|
|
3365
|
+
Je as FLIP_D,
|
|
3366
|
+
Ve as FLIP_H,
|
|
3367
|
+
Xe as FLIP_V,
|
|
3368
|
+
Le as FixedLoop,
|
|
3369
|
+
ce as Graphics,
|
|
3370
|
+
ve as Group,
|
|
3371
|
+
Vi as HEAVY_FLASH_GAP_MS,
|
|
3372
|
+
Qn as HUMANOID_CLIPS,
|
|
3373
|
+
Zn as HUMANOID_POSES,
|
|
3374
|
+
Xn as HUMANOID_RIG,
|
|
3375
|
+
me as INPUT_FLAG_DASH,
|
|
3376
|
+
gt as INPUT_STEP_DT,
|
|
3377
|
+
Hr as INPUT_STEP_RATE,
|
|
3378
|
+
Me as Image,
|
|
3379
|
+
Dr as InterpolationBuffer,
|
|
3380
|
+
pr as Keyboard,
|
|
3381
|
+
sr as LightLayer,
|
|
3382
|
+
xr as LongPress,
|
|
3383
|
+
yn as MusicPlayer,
|
|
3384
|
+
ke as ObjectFactory,
|
|
3385
|
+
wn as PAD_BUTTONS,
|
|
3386
|
+
pt as Pointer,
|
|
3387
|
+
tr as PosePlayer,
|
|
3388
|
+
Br as PredictedMover,
|
|
3389
|
+
rr as RECOIL_MS,
|
|
3390
|
+
Et as RIG_PARTS,
|
|
3391
|
+
Ht as Rectangle,
|
|
3392
|
+
er as RigView,
|
|
3393
|
+
Tr as Room,
|
|
3394
|
+
Rr as RoomHost,
|
|
3395
|
+
Yt as STICK_DEAD_ZONE,
|
|
3396
|
+
S as SYNTH_RATE,
|
|
3397
|
+
_n as Scene,
|
|
3398
|
+
He as SceneManager,
|
|
3399
|
+
us as Skeleton,
|
|
3400
|
+
gn as SoundEngine,
|
|
3401
|
+
rs as SpriteComponent,
|
|
3402
|
+
H as Stage,
|
|
3403
|
+
Ir as TILE_SIZE,
|
|
3404
|
+
Ae as Text,
|
|
3405
|
+
Ce as TextureRegistry,
|
|
3406
|
+
Vn as TilemapView,
|
|
3407
|
+
Fe as Tween,
|
|
3408
|
+
Te as Tweener,
|
|
3409
|
+
W as UPDATE_RECORD_BYTES,
|
|
3410
|
+
ze as World,
|
|
3411
|
+
Hn as addLabelGlyphs,
|
|
3412
|
+
gr as aimAxis,
|
|
3413
|
+
Gn as animationSystem,
|
|
3414
|
+
Pn as atlasPageLimit,
|
|
3415
|
+
St as blendPose,
|
|
3416
|
+
qn as blocksShot,
|
|
3417
|
+
Yn as bodyCollides,
|
|
3418
|
+
Ar as cadenceEarly,
|
|
3419
|
+
kr as cadenceNext,
|
|
3420
|
+
jn as collisionFromTiled,
|
|
3421
|
+
as as createCollisionGrid,
|
|
3422
|
+
qt as createMover,
|
|
3423
|
+
En as decodeSnapshotFrame,
|
|
3424
|
+
Mn as decodeUpdates,
|
|
3425
|
+
Nt as defineComponent,
|
|
3426
|
+
In as defineFields,
|
|
3427
|
+
Se as easeByName,
|
|
3428
|
+
Sn as encodeSnapshotFrame,
|
|
3429
|
+
br as encodeUpdates,
|
|
3430
|
+
q as engineSettings,
|
|
3431
|
+
b as entityIndex,
|
|
3432
|
+
$t as gidOf,
|
|
3433
|
+
Bt as hasTakes,
|
|
3434
|
+
ir as hitStopMs,
|
|
3435
|
+
hr as hurtFlashGapMs,
|
|
3436
|
+
ar as hurtFlashMs,
|
|
3437
|
+
lr as inView,
|
|
3438
|
+
xe as installLabelFont,
|
|
3439
|
+
P as isSolidTile,
|
|
3440
|
+
ue as isTouchUi,
|
|
3441
|
+
Un as layerByName,
|
|
3442
|
+
hs as moveX,
|
|
3443
|
+
ls as moveY,
|
|
3444
|
+
Rn as moverFromWire,
|
|
3445
|
+
Tn as moverToWire,
|
|
3446
|
+
fr as music,
|
|
3447
|
+
Dn as noteServerTime,
|
|
3448
|
+
Nn as objectsOf,
|
|
3449
|
+
Jn as overlay,
|
|
3450
|
+
is as parseTiled,
|
|
3451
|
+
je as planAtlas,
|
|
3452
|
+
vr as quantizeUpdates,
|
|
3453
|
+
or as recoilAt,
|
|
3454
|
+
nr as recoilPx,
|
|
3455
|
+
ur as registerSounds,
|
|
3456
|
+
cr as registerTakes,
|
|
3457
|
+
ln as renderRecipe,
|
|
3458
|
+
Fr as resetServerClock,
|
|
3459
|
+
bt as resolveUrl,
|
|
3460
|
+
Sr as serverNow,
|
|
3461
|
+
Er as serverOffset,
|
|
3462
|
+
_r as setNativeShell,
|
|
3463
|
+
dr as sound,
|
|
3464
|
+
ct as stepMover,
|
|
3465
|
+
bn as stickActive,
|
|
3466
|
+
wr as stickToAxis,
|
|
3467
|
+
yr as stickVector,
|
|
3468
|
+
Ne as system,
|
|
3469
|
+
zt as tileAt,
|
|
3470
|
+
Ze as tileRect,
|
|
3471
|
+
Kn as upperOver
|
|
3472
|
+
};
|
|
3473
|
+
//# sourceMappingURL=lantern-engine.js.map
|