littlejsengine 1.2.0 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,23 +19,19 @@ LittleJS is a super lightweight JavaScript game engine with a fast hybrid render
19
19
  ## Features
20
20
 
21
21
  - Very small footprint with no dependencies
22
- - Can render 10,000+ objects at 60fps, often many times more
23
- - Object oriented system with base class engine object
24
- - Fast 2D physics and collision handling for axis aligned boxes
22
+ - Can update and render 10,000+ objects at 60fps, often many times more
23
+ - Object oriented system with fast 2D physics and collision handling for axis aligned boxes
25
24
  - Positional audio effects with [zzfx](https://killedbyapixel.github.io/ZzFX/) and music with [zzfxm](https://keithclark.github.io/ZzFXM/), mp3s, or wavs
26
25
  - Input processing system with keyboard, mouse, gamepad, and touch support
27
- - Engine helper functions and classes like Vector2, Color, and Timer
28
- - Tile layer cached rendering and collision system for level data
29
26
  - Particle effects system (particle editor/designer in progress)
30
27
  - Medal system tracks and displays achievements with Newgrounds and OS13k integration
31
28
  - Several easy to understand example projects you can build on
32
- - All example projects are compatible with mobile devices
33
29
  - Debug tools and debug rendering system
34
30
  - [Full documentation](https://killedbyapixel.github.io/LittleJS/docs) automatically generated from the source code block tags with [JSDoc](https://github.com/jsdoc/jsdoc)
35
31
  - Build system automatically combines everything, minifies, and removes unused code
36
32
  - For size coding competitions like [js13kGames](https://js13kgames.com/), starter project builds to a 7KB zip with [Roadroller](https://github.com/lifthrasiir/roadroller)
37
- - Easily build a Windows executable with [electron](https://www.electronjs.org/) for distribution on platforms like Steam
38
- - Open Source with the [MIT license](https://github.com/KilledByAPixel/LittleJS/blob/main/LICENSE) so it can be used to make commercial games
33
+ - Easily build a Windows executable with [Electron](https://www.electronjs.org/) for distribution on platforms like Steam
34
+ - Open Source with the [MIT license](https://github.com/KilledByAPixel/LittleJS/blob/main/LICENSE) so it can be used for anything you want
39
35
 
40
36
  ## Builds
41
37
 
@@ -160,7 +160,7 @@ const debugUpdate = ()=>
160
160
  {
161
161
  if (!debug)
162
162
  return;
163
-
163
+
164
164
  if (keyWasPressed(192)) // ~
165
165
  debugOverlay = !debugOverlay;
166
166
  if (debugOverlay)
@@ -1026,6 +1026,11 @@ let inputWASDEmulateDirection = 1;
1026
1026
  * @memberof Settings */
1027
1027
  let touchGamepadEnable = 0;
1028
1028
 
1029
+ /** True if touch gamepad should be analog stick or false to use if 8 way dpad
1030
+ * @default
1031
+ * @memberof Settings */
1032
+ let touchGamepadAnalog = 1;
1033
+
1029
1034
  /** Size of virutal gamepad for touch devices in pixels
1030
1035
  * @default
1031
1036
  * @memberof Settings */
@@ -1702,6 +1707,9 @@ function drawText(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new
1702
1707
  * // draw text
1703
1708
  * font.drawTextScreen("LittleJS\nHello World!", vec2(200, 50));
1704
1709
  */
1710
+
1711
+ let engineFontImage;
1712
+
1705
1713
  class FontImage
1706
1714
  {
1707
1715
  /** Create an image font
@@ -1713,14 +1721,14 @@ class FontImage
1713
1721
  */
1714
1722
  constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), startTileIndex=0, context=overlayContext)
1715
1723
  {
1716
- if (!image)
1724
+ if (!image && !engineFontImage)
1717
1725
  {
1718
- // use default font image
1719
- image = new Image();
1720
- image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6MCIBdFY+Q0PMNgf0yCgsSAaZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWw1hPWNRcEyWh2npdpBmSUBrRaN1WSlQAWXaWLF0kkwR7C/N7XUvIaQr4xpeqeQigjLwBRZ/6KkufAACcv5z7GYhvgWHII8xN/4C2hvLCkmZSVgIJMHNTxpYOsJOiitEjUQnIQAFFP+opoQfCbjWmfzWiNzCjEvxAPFARmw/Y5Te0sl2zEp4M+m7cToJjdJS7y1xcFlFT7EtWBZ8nl7uLSff7UgYewtlyY6yHM4RrjNrnsfn/W0DBK9xNZctZ7gsTeXTe5eqLqXFlKnAn+vkNXzH6TqPW10ksKoSlauKk1TcncZLSTxNnQ8Av/8RGPXOFIuMCZ/fpwIZx5vU4QIRQ44HwUyHx/QrZhm5VtXFex7ja2se0KBpnPT0DSwS4xd86uAy+SqnLBgkPY5JolhJ33ENyK6n0VyRzCnzebIkFdY/NUtM66lTdhix1KUss6q5snH5ftVJXG0QITb1gUDvzD3z/BbyOLMirwCtPzAAAAAElFTkSuQmCC';
1726
+ // load default font image
1727
+ engineFontImage = new Image();
1728
+ engineFontImage.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC';
1721
1729
  }
1722
1730
 
1723
- this.image = image;
1731
+ this.image = image || engineFontImage;
1724
1732
  this.tileSize = tileSize;
1725
1733
  this.paddingSize = paddingSize;
1726
1734
  this.startTileIndex = startTileIndex;
@@ -2087,7 +2095,7 @@ if (isTouchDevice)
2087
2095
  // touch gamepad, virtual on screen gamepad emulator for touch devices
2088
2096
 
2089
2097
  // touch input internal variables
2090
- let touchGamepadTimer = new Timer, touchGamepadButtons = [], touchGamepadStick = vec2(), touchGamepadAnalog = 1;
2098
+ let touchGamepadTimer = new Timer, touchGamepadButtons = [], touchGamepadStick = vec2();
2091
2099
 
2092
2100
  // create the touch gamepad, called automatically by the engine
2093
2101
  function touchGamepadCreate()
@@ -2134,7 +2142,7 @@ function touchGamepadCreate()
2134
2142
  {
2135
2143
  // virtual analog stick
2136
2144
  if (touchGamepadAnalog)
2137
- touchGamepadStick = touchPos.subtract(stickCenter).clampLength(touchGamepadSize/2).scale(2/touchGamepadSize);
2145
+ touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
2138
2146
  else
2139
2147
  {
2140
2148
  // 8 way dpad
@@ -2175,12 +2183,28 @@ function touchGamepadRender()
2175
2183
  overlayContext.lineWidth = 3;
2176
2184
 
2177
2185
  // draw left analog stick
2178
- overlayContext.fillStyle = gamepadStick(0).length() > 0 ? '#fff' : '#000';
2186
+ overlayContext.fillStyle = touchGamepadStick.lengthSquared() > 0 ? '#fff' : '#000';
2179
2187
  overlayContext.beginPath();
2180
- overlayContext.arc(touchGamepadSize, mainCanvasSize.y-touchGamepadSize, touchGamepadSize/2, 0,9);
2181
- overlayContext.fill();
2182
- overlayContext.stroke();
2183
2188
 
2189
+ const leftCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
2190
+ if (touchGamepadAnalog)
2191
+ {
2192
+ overlayContext.arc(leftCenter.x, leftCenter.y, touchGamepadSize/2, 0, 9);
2193
+ overlayContext.fill();
2194
+ overlayContext.stroke();
2195
+ }
2196
+ else // draw cross shaped gamepad
2197
+ {
2198
+ for(let i=10; i--;)
2199
+ {
2200
+ const angle = i*PI/4;
2201
+ overlayContext.arc(leftCenter.x, leftCenter.y,touchGamepadSize*.6, angle + PI/8, angle + PI/8);
2202
+ i%2 && overlayContext.arc(leftCenter.x, leftCenter.y, touchGamepadSize*.33, angle, angle);
2203
+ i==1 && overlayContext.fill();
2204
+ }
2205
+ overlayContext.stroke();
2206
+ }
2207
+
2184
2208
  // draw right face buttons
2185
2209
  const rightCenter = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
2186
2210
  for (let i=4; i--;)
@@ -3026,9 +3050,9 @@ class TileLayer extends EngineObject
3026
3050
  * let pos = vec2(2,3);
3027
3051
  * let particleEmiter = new ParticleEmitter
3028
3052
  * (
3029
- * pos, 1, 0, 500, PI, // pos, emitSize, emitTime, emitRate, emiteCone
3053
+ * pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
3030
3054
  * 0, vec2(16), // tileIndex, tileSize
3031
- * new Color, new Color(0,0,0), // colorStartA, colorStartB
3055
+ * new Color(1,1,1), new Color(0,0,0), // colorStartA, colorStartB
3032
3056
  * new Color(1,1,1,0), new Color(0,0,0,0), // colorEndA, colorEndB
3033
3057
  * 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
3034
3058
  * .99, 1, 1, PI, .05, // damping, angleDamping, gravityScale, particleCone, fadeRate,
@@ -3039,6 +3063,7 @@ class ParticleEmitter extends EngineObject
3039
3063
  {
3040
3064
  /** Create a particle system with the given settings
3041
3065
  * @param {Vector2} position - World space position of the emitter
3066
+ * @param {Number} [angle=0] - Angle to rotate the object
3042
3067
  * @param {Number} [emitSize=0] - World space size of the emitter (float for circle diameter, vec2 for rect)
3043
3068
  * @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
3044
3069
  * @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
@@ -3068,6 +3093,7 @@ class ParticleEmitter extends EngineObject
3068
3093
  constructor
3069
3094
  (
3070
3095
  pos,
3096
+ angle,
3071
3097
  emitSize = 0,
3072
3098
  emitTime = 0,
3073
3099
  emitRate = 100,
@@ -3095,7 +3121,7 @@ class ParticleEmitter extends EngineObject
3095
3121
  renderOrder = additive ? 1e9 : 0
3096
3122
  )
3097
3123
  {
3098
- super(pos, new Vector2, tileIndex, tileSize, 0, undefined, renderOrder);
3124
+ super(pos, new Vector2, tileIndex, tileSize, angle, undefined, renderOrder);
3099
3125
 
3100
3126
  // emitter settings
3101
3127
  /** @property {Number} - World space size of the emitter (float for circle diameter, vec2 for rect) */
@@ -3528,9 +3554,6 @@ class Newgrounds
3528
3554
  * @param {Number} value - The score value */
3529
3555
  postScore(id, value) { return this.call('ScoreBoard.postScore', {'id':id, 'value':value}, 1); }
3530
3556
 
3531
- /** Send message to log a view */
3532
- logView() { return this.call('App.logView', {'host':this.host}, 1); }
3533
-
3534
3557
  /** Get scores from a scoreboard
3535
3558
  * @param {Number} id - The scoreboard id
3536
3559
  * @param {String} [user=0] - A user's id or name
@@ -3542,6 +3565,9 @@ class Newgrounds
3542
3565
  getScores(id, user=0, social=0, skip=0, limit=10)
3543
3566
  { return this.call('ScoreBoard.getScores', {'id':id, 'user':user, 'social':social, 'skip':skip, 'limit':limit}); }
3544
3567
 
3568
+ /** Send message to log a view */
3569
+ logView() { return this.call('App.logView', {'host':this.host}, 1); }
3570
+
3545
3571
  /** Send a message to call a component of the Newgrounds API
3546
3572
  * @param {String} component - Name of the component
3547
3573
  * @param {Object} [parameters=0] - Parameters to use for call
@@ -3638,24 +3664,24 @@ function glInit()
3638
3664
 
3639
3665
  // setup vertex and fragment shaders
3640
3666
  glShader = glCreateProgram(
3641
- 'precision highp float;'+ // use highp for better accuracy, lowp for better perf
3642
- 'uniform mat4 m;'+ // transform matrix
3643
- 'attribute vec2 p,t;'+ // position, uv
3644
- 'attribute vec4 c,a;'+ // color, additiveColor
3645
- 'varying vec2 v;'+ // return uv
3646
- 'varying vec4 d,e;'+ // return color, additiveColor
3647
- 'void main(){'+ // shader entry point
3648
- 'gl_Position=m*vec4(p,1,1);'+// transform position
3649
- 'v=t;d=c;e=a;'+ // pass stuff to fragment shader
3650
- '}' // end of shader
3667
+ 'precision highp float;'+ // use highp for better accuracy, lowp for better perf
3668
+ 'uniform mat4 m;'+ // transform matrix
3669
+ 'attribute vec2 p,t;'+ // position, uv
3670
+ 'attribute vec4 c,a;'+ // color, additiveColor
3671
+ 'varying vec2 v;'+ // return uv
3672
+ 'varying vec4 d,e;'+ // return color, additiveColor
3673
+ 'void main(){'+ // shader entry point
3674
+ 'gl_Position=m*vec4(p,1,1);'+ // transform position
3675
+ 'v=t;d=c;e=a;'+ // pass stuff to fragment shader
3676
+ '}' // end of shader
3651
3677
  ,
3652
- 'precision highp float;'+ // use highp for better accuracy, lowp for better perf
3653
- 'varying vec2 v;'+ // uv
3654
- 'varying vec4 d,e;'+ // color, additiveColor
3655
- 'uniform sampler2D j;'+ // texture
3656
- 'void main(){'+ // shader entry point
3657
- 'gl_FragColor=texture2D(j,v)*d+e;'+ // modulate texture by color plus additive
3658
- '}' // end of shader
3678
+ 'precision highp float;'+ // use highp for better accuracy, lowp for better perf
3679
+ 'varying vec2 v;'+ // uv
3680
+ 'varying vec4 d,e;'+ // color, additiveColor
3681
+ 'uniform sampler2D s;'+ // texture
3682
+ 'void main(){'+ // shader entry point
3683
+ 'gl_FragColor=texture2D(s,v)*d+e;'+ // modulate texture by color plus additive
3684
+ '}' // end of shader
3659
3685
  );
3660
3686
 
3661
3687
  // init buffers
@@ -3867,44 +3893,44 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba=0xffffff
3867
3893
 
3868
3894
  // prepare to create the verts from size and angle
3869
3895
  const c = Math.cos(angle)/2, s = Math.sin(angle)/2;
3870
- const cX = c*sizeX, cY = c*sizeY, sX = s*sizeX, sY = s*sizeY;
3896
+ const cx = c*sizeX, cy = c*sizeY, sx = s*sizeX, sy = s*sizeY;
3871
3897
 
3872
3898
  // setup 2 triangles to form a quad
3873
3899
  let offset = glBatchCount++ * gl_VERTICES_PER_QUAD * gl_INDICIES_PER_VERT;
3874
3900
 
3875
3901
  // vertex 0
3876
- glPositionData[offset++] = x - cX - sY;
3877
- glPositionData[offset++] = y - cY + sX;
3902
+ glPositionData[offset++] = x - cx - sy;
3903
+ glPositionData[offset++] = y - cy + sx;
3878
3904
  glPositionData[offset++] = uv0X; glPositionData[offset++] = uv1Y;
3879
3905
  glColorData[offset++] = rgba; glColorData[offset++] = rgbaAdditive;
3880
3906
 
3881
3907
  // vertex 1
3882
- glPositionData[offset++] = x + cX + sY;
3883
- glPositionData[offset++] = y + cY - sX;
3908
+ glPositionData[offset++] = x + cx + sy;
3909
+ glPositionData[offset++] = y + cy - sx;
3884
3910
  glPositionData[offset++] = uv1X; glPositionData[offset++] = uv0Y;
3885
3911
  glColorData[offset++] = rgba; glColorData[offset++] = rgbaAdditive;
3886
3912
 
3887
3913
  // vertex 2
3888
- glPositionData[offset++] = x - cX + sY;
3889
- glPositionData[offset++] = y + cY + sX;
3914
+ glPositionData[offset++] = x - cx + sy;
3915
+ glPositionData[offset++] = y + cy + sx;
3890
3916
  glPositionData[offset++] = uv0X; glPositionData[offset++] = uv0Y;
3891
3917
  glColorData[offset++] = rgba; glColorData[offset++] = rgbaAdditive;
3892
3918
 
3893
3919
  // vertex 0
3894
- glPositionData[offset++] = x - cX - sY;
3895
- glPositionData[offset++] = y - cY + sX;
3920
+ glPositionData[offset++] = x - cx - sy;
3921
+ glPositionData[offset++] = y - cy + sx;
3896
3922
  glPositionData[offset++] = uv0X; glPositionData[offset++] = uv1Y;
3897
3923
  glColorData[offset++] = rgba; glColorData[offset++] = rgbaAdditive;
3898
3924
 
3899
3925
  // vertex 3
3900
- glPositionData[offset++] = x + cX - sY;
3901
- glPositionData[offset++] = y - cY - sX;
3926
+ glPositionData[offset++] = x + cx - sy;
3927
+ glPositionData[offset++] = y - cy - sx;
3902
3928
  glPositionData[offset++] = uv1X; glPositionData[offset++] = uv1Y;
3903
3929
  glColorData[offset++] = rgba; glColorData[offset++] = rgbaAdditive;
3904
3930
 
3905
3931
  // vertex 1
3906
- glPositionData[offset++] = x + cX + sY;
3907
- glPositionData[offset++] = y + cY - sX;
3932
+ glPositionData[offset++] = x + cx + sy;
3933
+ glPositionData[offset++] = y + cy - sx;
3908
3934
  glPositionData[offset++] = uv1X; glPositionData[offset++] = uv0Y;
3909
3935
  glColorData[offset++] = rgba; glColorData[offset++] = rgbaAdditive;
3910
3936
  }
@@ -3965,7 +3991,7 @@ gl_VERTEX_BYTE_STRIDE = (4 * 2) * 2 + (4) * 2; // vec2 * 2 + (char * 4) * 2
3965
3991
  const engineName = 'LittleJS';
3966
3992
 
3967
3993
  /** Version of engine */
3968
- const engineVersion = '1.2.0';
3994
+ const engineVersion = '1.2.3';
3969
3995
 
3970
3996
  /** Frames per second to update objects
3971
3997
  * @default */
@@ -4002,7 +4028,7 @@ let averageFPS, drawCount;
4002
4028
  // css text used for elements created by engine
4003
4029
  const styleBody = 'margin:0;overflow:hidden;background:#000' +
4004
4030
  ';touch-action:none;user-select:none;-webkit-user-select:none;-moz-user-select:none';
4005
- const styleCanvas = 'position:absolute';
4031
+ const styleCanvas = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)';
4006
4032
 
4007
4033
  ///////////////////////////////////////////////////////////////////////////////
4008
4034
 
@@ -4103,24 +4129,13 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
4103
4129
 
4104
4130
  // fit to window by adding space on top or bottom if necessary
4105
4131
  const aspect = innerWidth / innerHeight;
4106
- const fixedAspect = canvasFixedSize.x / canvasFixedSize.y;
4107
-
4108
- // clear css
4109
- mainCanvas.style.width = overlayCanvas.style.width =
4110
- mainCanvas.style.height = overlayCanvas.style.height =
4111
- mainCanvas.style.top = overlayCanvas.style.top =
4112
- mainCanvas.style.left = overlayCanvas.style.left = '';
4113
-
4114
- // letterbox center canvas
4115
- if (aspect < fixedAspect)
4116
- {
4117
- mainCanvas.style.width = overlayCanvas.style.width = innerWidth;
4118
- mainCanvas.style.top = overlayCanvas.style.top = (innerHeight - innerWidth/fixedAspect)/2;
4119
- }
4120
- else
4132
+ const fixedAspect = mainCanvas.width / mainCanvas.height;
4133
+ mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
4134
+ mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
4135
+ if (glCanvas)
4121
4136
  {
4122
- mainCanvas.style.height = overlayCanvas.style.height = innerHeight;
4123
- mainCanvas.style.left = overlayCanvas.style.left = (innerWidth - innerHeight*fixedAspect)/2;
4137
+ glCanvas.style.width = mainCanvas.style.width;
4138
+ glCanvas.style.height = mainCanvas.style.height;
4124
4139
  }
4125
4140
  }
4126
4141
  else
@@ -4128,18 +4143,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
4128
4143
  // clear and set size to same as window
4129
4144
  mainCanvas.width = min(innerWidth, canvasMaxSize.x);
4130
4145
  mainCanvas.height = min(innerHeight, canvasMaxSize.y);
4131
-
4132
- // center canvas
4133
- overlayCanvas.style.top = mainCanvas.style.top = (innerHeight - mainCanvas.height)/2;
4134
- overlayCanvas.style.left = mainCanvas.style.left = (innerWidth - mainCanvas.width)/2;
4135
- }
4136
-
4137
- if (glEnable)
4138
- {
4139
- glCanvas.style.width = mainCanvas.style.width;
4140
- glCanvas.style.height = mainCanvas.style.height;
4141
- glCanvas.style.top = mainCanvas.style.top;
4142
- glCanvas.style.left = mainCanvas.style.left;
4143
4146
  }
4144
4147
 
4145
4148
  // render sort then render while removing destroyed objects
@@ -1 +1 @@
1
- const debug=0,showWatermark=0,godMode=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0,ASSERT=()=>{},debugInit=()=>{},debugUpdate=()=>{},debugRender=()=>{},debugRect=()=>{},debugCircle=()=>{},debugPoint=()=>{},debugLine=()=>{},debugAABB=()=>{},debugText=()=>{},debugClear=()=>{},debugSaveCanvas=()=>{};"use strict";const PI=Math.PI,abs=a=>0>a?-a:a,min=(a,b)=>a<b?a:b,max=(a,b)=>a>b?a:b,sign=a=>0>a?-1:1,mod=(a,b=1)=>(a%b+b)%b,clamp=(a,b=0,c=1)=>a<b?b:a>c?c:a,percent=(a,b=0,c=1)=>c-b?clamp((a-b)/(c-b)):0,lerp=(a,b=0,c=1)=>b+clamp(a)*(c-b),smoothStep=a=>a*a*(3-2*a),nearestPowerOfTwo=a=>2**Math.ceil(Math.log2(a)),isOverlapping=(a,b,c,d)=>2*abs(a.x-c.x)<b.x+d.x&2*abs(a.y-c.y)<b.y+d.y,wave=(a=1,b=1,c=time)=>b/2*(1-Math.cos(c*a*2*PI)),formatTime=a=>(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0),rand=(a=1,b=0)=>b+(a-b)*Math.random(),randInt=(a=1,b=0)=>rand(a,b)|0,randSign=()=>2*(rand(2)|0)-1,randInCircle=(a=1,b=0)=>0<a?randVector(a*rand(b/a,1)**.5):new Vector2,randVector=(a=1)=>(new Vector2).setAngle(rand(2*PI),a),randColor=(a=new Color,b=new Color(0,0,0,1),c)=>c?a.lerp(b,rand()):new Color(rand(a.r,b.r),rand(a.g,b.g),rand(a.b,b.b),rand(a.a,b.a));let randSeed=1;const randSeeded=(a=1,b=0)=>{randSeed^=randSeed<<13;randSeed^=randSeed>>>17;randSeed^=randSeed<<5;return b+(a-b)*abs(randSeed%1e9)/1e9},vec2=(a=0,b)=>void 0==a.x?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y);class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}copy(){return new Vector2(this.x,this.y)}add(a){ASSERT(void 0!=a.x);return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){ASSERT(void 0!=a.x);return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){ASSERT(void 0!=a.x);return new Vector2(this.x*a.x,this.y*a.y)}divide(a){ASSERT(void 0!=a.x);return new Vector2(this.x/a.x,this.y/a.y)}scale(a){ASSERT(void 0==a.x);return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector2(a)}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this}dot(a){ASSERT(void 0!=a.x);return this.x*a.x+this.y*a.y}cross(a){ASSERT(void 0!=a.x);return this.x*a.y-this.y*a.x}angle(){return Math.atan2(this.x,this.y)}setAngle(a=0,b=1){this.x=b*Math.sin(a);this.y=b*Math.cos(a);return this}rotate(a){const b=Math.cos(a);a=Math.sin(a);return new Vector2(this.x*b-this.y*a,this.x*a+this.y*b)}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}invert(){return new Vector2(this.y,-this.x)}floor(){return new Vector2(Math.floor(this.x),Math.floor(this.y))}area(){return this.x*this.y}lerp(a,b){ASSERT(void 0!=a.x);return this.add(a.subtract(this).scale(clamp(b)))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}}class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d}copy(){return new Color(this.r,this.g,this.b,this.a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){return this.add(a.subtract(this).scale(clamp(b)))}setHSLA(a=0,b=0,c=1,d=1){b=.5>c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,g,h)=>(h=(h%1+1)%1)<1/6?f+6*(g-f)*h:.5>h?g:h<2/3?f+(g-f)*(2/3-h)*6:f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}mutate(a=.05,b=0){return new Color(this.r+rand(a,-a),this.g+rand(a,-a),this.b+rand(a,-a),this.a+rand(b,-b)).clamp()}rgba(){ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b&&0<=this.a&&1>=this.a);return`rgb(${255*this.r|0},${255*this.g|0},${255*this.b|0},${this.a})`}rgbaInt(){ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b&&0<=this.a&&1>=this.a);return(255*this.r|0)+(255*this.g<<8)+(255*this.b<<16)+(255*this.a<<24)}}class Timer{constructor(a){this.time=void 0==a?void 0:time+a;this.setTime=a}set(a=0){this.time=time+a;this.setTime=a}unset(){this.time=void 0}isSet(){return void 0!=this.time}active(){return time<=this.time}elapsed(){return time>this.time}get(){return this.isSet()?time-this.time:0}getPercent(){return this.isSet()?percent(this.time-time,this.setTime,0):0}}"use strict";let canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),cavasPixelated=1,fontDefault="arial",tileSizeDefault=vec2(16),tileFixBleedScale=.3,objectDefaultSize=vec2(1),objectDefaultMass=1,objectDefaultDamping=.99,objectDefaultAngleDamping=.99,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,cameraPos=vec2(),cameraScale=max(tileSizeDefault.x,tileSizeDefault.y),glEnable=1,glOverlay=1,gamepadsEnable=1,gamepadDirectionEmulateStick=1,inputWASDEmulateDirection=1,touchGamepadEnable=0,touchGamepadSize=80,touchGamepadAlpha=.3,vibrateEnable=1,soundVolume=.5,soundEnable=1,soundDefaultRange=30,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplayWidth=640,medalDisplayHeight=80,medalDisplayIconSize=50;"use strict";const engineName="LittleJS",engineVersion="1.2.0",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=0,frameTimeLastMS=0,frameTimeBufferMS=0,tileImageSize,tileImageFixBleed,averageFPS,drawCount;const styleBody="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none;-moz-user-select:none",styleCanvas="position:absolute";function engineInit(a,b,c,d,e,f){tileImage.onerror=tileImage.onload=()=>{tileImageFixBleed=vec2(tileFixBleedScale).divide(tileImageSize=vec2(tileImage.width,tileImage.height));debug&&(tileImage.onload=()=>ASSERT(1));document.body.style=styleBody;document.body.appendChild(mainCanvas=document.createElement("canvas"));mainContext=mainCanvas.getContext("2d");mainCanvas.style=styleCanvas;debugInit();glInit();document.body.appendChild(overlayCanvas=document.createElement("canvas"));overlayContext=overlayCanvas.getContext("2d");overlayCanvas.style=styleCanvas;a();touchGamepadCreate();g()};const g=(h=0)=>{requestAnimationFrame(g);var l=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS||0,1e3/(l||1));debug&&(l*=keyIsDown(107)?5:keyIsDown(109)?.2:1);timeReal+=l/1e3;frameTimeBufferMS=min(frameTimeBufferMS+!paused*l,50);if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{h=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(h=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=h}canvasFixedSize.x?(mainCanvas.width=canvasFixedSize.x,mainCanvas.height=canvasFixedSize.y,h=innerWidth/innerHeight,l=canvasFixedSize.x/canvasFixedSize.y,mainCanvas.style.width=overlayCanvas.style.width=mainCanvas.style.height=overlayCanvas.style.height=mainCanvas.style.top=overlayCanvas.style.top=mainCanvas.style.left=overlayCanvas.style.left="",h<l?(mainCanvas.style.width=overlayCanvas.style.width=innerWidth,mainCanvas.style.top=overlayCanvas.style.top=(innerHeight-innerWidth/l)/2):(mainCanvas.style.height=overlayCanvas.style.height=innerHeight,mainCanvas.style.left=overlayCanvas.style.left=(innerWidth-innerHeight*l)/2)):(mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y),overlayCanvas.style.top=mainCanvas.style.top=(innerHeight-mainCanvas.height)/2,overlayCanvas.style.left=mainCanvas.style.left=(innerWidth-mainCanvas.width)/2);glEnable&&(glCanvas.style.width=mainCanvas.style.width,glCanvas.style.height=mainCanvas.style.height,glCanvas.style.top=mainCanvas.style.top,glCanvas.style.left=mainCanvas.style.left);enginePreRender();d();engineObjects.sort((m,p)=>m.renderOrder-p.renderOrder);for(var n of engineObjects)n.destroyed||n.render();e();medalsRender();touchGamepadRender();debugRender();glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",n=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+" "+(glEnable?"GL":"2D"),overlayContext.fillText(n,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(n,mainCanvas.width-2,2),drawCount=0)};f?tileImage.src=f:tileImage.onload()}function enginePreRender(){mainCanvasSize=vec2(overlayCanvas.width=mainCanvas.width,overlayCanvas.height=mainCanvas.height);mainContext.imageSmoothingEnabled=!cavasPixelated;glPreRender(mainCanvas.width,mainCanvas.height,cameraPos.x,cameraPos.y,cameraScale)}function engineObjectsUpdate(){engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);const a=b=>{if(!b.destroyed){b.update();for(const c of b.children)a(c)}};for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed);time=++frame/frameRate}function engineObjectsDestroy(){for(const a of engineObjects)a.parent||a.destroy();engineObjects=engineObjects.filter(a=>!a.destroyed)}function engineObjectsCallback(a,b,c,d=engineObjects){if(a)if(void 0!=b.x)for(const e of d)isOverlapping(a,b,e.pos,e.size)&&c(e);else{b*=b;for(const e of d)a.distanceSquared(e.pos)<b&&c(e)}else for(const e of d)c(e)}"use strict";class EngineObject{constructor(a=vec2(),b=objectDefaultSize,c=-1,d=tileSizeDefault,e=0,f,g=0){ASSERT(a&&void 0!=a.x&&void 0!=b.x);this.pos=a.copy();this.size=b;this.drawSize;this.tileIndex=c;this.tileSize=d;this.angle=e;this.color=f;this.additiveColor;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=g;this.velocity=new Vector2;this.angleVelocity=0;this.spawnTime=time;this.children=[];this.collideTiles=1;engineObjects.push(this)}update(){var a=this.parent;if(a)this.pos=this.localPos.multiply(vec2(a.getMirrorSign(),1)).rotate(-a.angle).add(a.pos),this.angle=a.getMirrorSign()*this.localAngle+a.angle;else if(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed),a=this.pos.copy(),this.pos.x+=this.velocity.x*=this.damping,this.pos.y+=this.velocity.y=this.damping*this.velocity.y+gravity*this.gravityScale,this.angle+=this.angleVelocity*=this.angleDamping,ASSERT(0<=this.angleDamping&&1>=this.angleDamping),ASSERT(0<=this.damping&&1>=this.damping),this.mass){var b=0>this.velocity.y;if(this.groundObject){var c=this.groundObject.velocity?this.groundObject.velocity.x:0;this.velocity.x=c+(this.velocity.x-c)*this.friction;this.groundObject=0}if(this.collideSolidObjects)for(var d of engineObjectsCollide)if(!(!this.isSolid&!d.isSolid||d.destroyed||d.parent||d==this||!isOverlapping(this.pos,this.size,d.pos,d.size)||!this.collideWithObject(d)|!d.collideWithObject(this)))if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);var e=c.length();c=.01>e?randVector(.001):c.scale(.001/e);this.velocity=this.velocity.add(c);d.mass&&(d.velocity=d.velocity.subtract(c));debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f00")}else{c=this.size.add(d.size);e=2*(a.y-d.pos.y)>c.y+gravity;var f=2*abs(a.y-d.pos.y)<c.y,g=2*abs(a.x-d.pos.x)<c.x;if(e||g||!f)if(this.pos.y=d.pos.y+(c.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-this.elasticity;else if(d.mass){const h=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass),l=this.velocity.y*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.y*d.mass/(this.mass+d.mass),n=d.velocity.y*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.y*this.mass/(this.mass+d.mass),m=max(this.elasticity,d.elasticity);this.velocity.y=lerp(m,h,l);d.velocity.y=lerp(m,h,n)}e||!f&&g||(this.pos.x=d.pos.x+(c.x/2+.001)*sign(a.x-d.pos.x),d.mass?(c=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(this.mass+d.mass),e=this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass),f=d.velocity.x*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.x*this.mass/(this.mass+d.mass),g=max(this.elasticity,d.elasticity),this.velocity.x=lerp(g,c,e),d.velocity.x=lerp(g,c,f)):this.velocity.x*=-this.elasticity);debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f0f")}if(this.collideTiles&&tileCollisionTest(this.pos,this.size,this)&&!tileCollisionTest(a,this.size,this)){c=tileCollisionTest(new Vector2(a.x,this.pos.y),this.size,this);d=tileCollisionTest(new Vector2(this.pos.x,a.y),this.size,this);if(c||!d)this.groundObject=b,this.velocity.y*=-this.elasticity,b=(a.y-this.size.y/2|0)-(a.y-this.size.y/2),0>b&&b>this.damping*this.velocity.y+gravity*this.gravityScale&&(this.velocity.y=this.damping?(b-gravity*this.gravityScale)/this.damping:0),this.pos.y=a.y;d&&(this.pos.x=a.x,this.velocity.x*=-this.elasticity)}}}render(){drawTile(this.pos,this.drawSize||this.size,this.tileIndex,this.tileSize,this.color,this.angle,this.mirror,this.additiveColor)}destroy(){if(!this.destroyed){this.destroyed=1;this.parent&&this.parent.removeChild(this);for(const a of this.children)a.destroy(a.parent=0)}}collideWithTile(a,b){return 0<a}collideWithTileRaycast(a,b){return 0<a}collideWithObject(a){return 1}getAliveTime(){return time-this.spawnTime}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyForce(a){this.applyAcceleration(a.scale(1/this.mass))}getMirrorSign(){return this.mirror?-1:1}addChild(a,b=vec2(),c=0){ASSERT(!a.parent&&!this.children.includes(a));this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c}removeChild(a){ASSERT(a.parent==this&&this.children.includes(a));this.children.splice(this.children.indexOf(a),1);a.parent=0}setCollision(a=0,b=0,c=1){ASSERT(a||!b);this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c}}"use strict";const tileImage=new Image;let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2();const screenToWorld=a=>a.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos),worldToScreen=a=>a.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));function drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f=0,g,h=new Color(0,0,0,0),l=glEnable){showWatermark&&++drawCount;if(glEnable&&l)if(0>c||!tileImage.width)glDraw(a.x,a.y,b.x,b.y,f,0,0,0,0,0,e.rgbaInt());else{var n=tileImageSize.x/d.x|0;l=d.x/tileImageSize.x;const m=d.y/tileImageSize.y,p=c%n*l;n=(c/n|0)*m;glDraw(a.x,a.y,g?-b.x:b.x,b.y,f,p+tileImageFixBleed.x,n+tileImageFixBleed.y,p-tileImageFixBleed.x+l,n-tileImageFixBleed.y+m,e.rgbaInt(),h.rgbaInt())}else drawCanvas2D(a,b,f,g,m=>{if(0>c)m.fillStyle=e.rgba(),m.fillRect(-.5,-.5,1,1);else{var p=tileImageSize.x/d.x|0;const k=c%p*d.x+tileFixBleedScale;p=(c/p|0)*d.y+tileFixBleedScale;const u=d.x-2*tileFixBleedScale,v=d.y-2*tileFixBleedScale;m.globalAlpha=e.a;m.drawImage(tileImage,k,p,u,v,-.5,-.5,1,1)}})}function drawRect(a,b,c,d,e){drawTile(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawTileScreenSpace(a,b=vec2(1),c,d,e,f,g,h,l){drawTile(screenToWorld(a),b.scale(1/cameraScale),c,d,e,f,g,h,l)}function drawRectScreenSpace(a,b,c,d,e){drawTileSrceenSpace(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawLine(a,b,c=.1,d,e){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());drawRect(a.add(b),c,d,b.angle(),0,0,e)}function drawCanvas2D(a,b,c,d,e,f=mainContext){a=worldToScreen(a);b=b.scale(cameraScale);f.save();f.translate(a.x+.5|0,a.y-.5|0);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}function setBlendMode(a,b=glEnable){glEnable&&b?glSetBlendMode(a):mainContext.globalCompositeOperation=a?"lighter":"source-over"}function drawText(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",h=fontDefault){b=worldToScreen(b);overlayContext.font=c*cameraScale+"px "+h;overlayContext.textAlign=g;overlayContext.textBaseline="middle";e&&(overlayContext.lineWidth=e*cameraScale,overlayContext.strokeStyle=f.rgba(),overlayContext.strokeText(a,b.x,b.y));overlayContext.fillStyle=d.rgba();overlayContext.fillText(a,b.x,b.y)}class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=0,e=overlayContext){a||(a=new Image,a.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6MCIBdFY+Q0PMNgf0yCgsSAaZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWw1hPWNRcEyWh2npdpBmSUBrRaN1WSlQAWXaWLF0kkwR7C/N7XUvIaQr4xpeqeQigjLwBRZ/6KkufAACcv5z7GYhvgWHII8xN/4C2hvLCkmZSVgIJMHNTxpYOsJOiitEjUQnIQAFFP+opoQfCbjWmfzWiNzCjEvxAPFARmw/Y5Te0sl2zEp4M+m7cToJjdJS7y1xcFlFT7EtWBZ8nl7uLSff7UgYewtlyY6yHM4RrjNrnsfn/W0DBK9xNZctZ7gsTeXTe5eqLqXFlKnAn+vkNXzH6TqPW10ksKoSlauKk1TcncZLSTxNnQ8Av/8RGPXOFIuMCZ/fpwIZx5vU4QIRQ44HwUyHx/QrZhm5VtXFex7ja2se0KBpnPT0DSwS4xd86uAy+SqnLBgkPY5JolhJ33ENyK6n0VyRzCnzebIkFdY/NUtM66lTdhix1KUss6q5snH5ftVJXG0QITb1gUDvzD3z/BbyOLMirwCtPzAAAAAElFTkSuQmCC");this.image=a;this.tileSize=b;this.paddingSize=c;this.startTileIndex=d;this.context=e}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!cavasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),h=this.image.width/this.tileSize.x|0;a.split("\n").forEach((l,n)=>{const m=d?l.length*f.x*c/2|0:0;for(let u=l.length;u--;){var p=l[u].charCodeAt();if(32>p||127<p)p=127;var k=this.startTileIndex+p-32;p=k%h;k=k/h|0;const v=b.add(vec2(u,n).multiply(g));e.drawImage(this.image,p*f.x,k*f.y,f.x,f.y,v.x-m,v.y,f.x*c,f.y*c)}});e.restore()}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}}const isFullscreen=()=>document.fullscreenElement;function toggleFullscreen(){isFullscreen()?document.exitFullscreen?document.exitFullscreen():document.mozCancelFullScreen&&document.mozCancelFullScreen():document.body.webkitRequestFullScreen?document.body.webkitRequestFullScreen():document.body.mozRequestFullScreen&&document.body.mozRequestFullScreen()}"use strict";const keyIsDown=(a,b=0)=>inputData[b]&&inputData[b][a]&1?1:0,keyWasPressed=(a,b=0)=>inputData[b]&&inputData[b][a]&2?1:0,keyWasReleased=(a,b=0)=>inputData[b]&&inputData[b][a]&4?1:0,clearInput=()=>inputData=[[]],mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=0;const gamepadIsDown=(a,b=0)=>keyIsDown(a,b+1),gamepadWasPressed=(a,b=0)=>keyWasPressed(a,b+1),gamepadWasReleased=(a,b=0)=>keyWasReleased(a,b+1),gamepadStick=(a,b=0)=>stickData[b]?stickData[b][a]||vec2():vec2();let inputData=[[]];function inputUpdate(){document.hasFocus()||clearInput();mousePos=screenToWorld(mousePosScreen);gamepadsUpdate()}function inputUpdatePost(){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=0}onkeydown=a=>{debug&&a.target!=document.body||(a.repeat||(inputData[isUsingGamepad=0][remapKeyCode(a.keyCode)]=3),debug||a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][remapKeyCode(a.keyCode)]=4)};const remapKeyCode=a=>inputWASDEmulateDirection?87==a?38:83==a?40:65==a?37:68==a?39:a:a;onmousedown=a=>{inputData[isUsingGamepad=0][a.button]=3;onmousemove(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>a.ctrlKey||(mouseWheel=sign(a.deltaY));oncontextmenu=a=>!1;const mouseToScreen=a=>{if(!mainCanvas)return vec2();const b=mainCanvas.getBoundingClientRect();return mainCanvasSize.multiply(vec2(percent(a.x,b.left,b.right),percent(a.y,b.top,b.bottom)))},stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){(stickData[0]||(stickData[0]=[]))[0]=vec2(touchGamepadStick.x,-touchGamepadStick.y);var a=inputData[1]||(inputData[1]=[]);for(var b=10;b--;){var c=3==b?2:2==b?3:b;a[c]=touchGamepadButtons[b]?1+2*!gamepadIsDown(c,0):4*gamepadIsDown(c,0)}}if(gamepadsEnable&&navigator.getGamepads&&(document.hasFocus()||debug))for(a=navigator.getGamepads(),b=a.length;b--;){var d=a[b];const g=inputData[b+1]||(inputData[b+1]=[]);c=stickData[b]||(stickData[b]=[]);if(d){var e=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.3,.8):0;for(var f=0;f<d.axes.length-1;f+=2)c[f>>1]=vec2(e(d.axes[f]),e(-d.axes[f+1])).clampLength();for(e=d.buttons.length;e--;)f=d.buttons[e],g[e]=f.pressed?1+2*!gamepadIsDown(e,b):4*gamepadIsDown(e,b),isUsingGamepad|=!b&&f.pressed,touchGamepadEnable&&touchGamepadTimer.unset();gamepadDirectionEmulateStick&&(d=vec2(gamepadIsDown(15,b)-gamepadIsDown(14,b),gamepadIsDown(12,b)-gamepadIsDown(13,b)),d.lengthSquared()&&(c[0]=d.clampLength()))}}}const vibrate=a=>vibrateEnable&&Navigator.vibrate&&Navigator.vibrate(a),vibrateStop=()=>vibrate(0),isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a,b;ontouchstart=ontouchmove=ontouchend=c=>{c.button=0;const d=c.touches.length;d?(b||zzfx(0,b=1),c.x=c.touches[0].clientX,c.y=c.touches[0].clientY,a?onmousemove(c):onmousedown(c)):a&&onmouseup(c);a=d;return!c.cancelable}}let touchGamepadTimer=new Timer,touchGamepadButtons=[],touchGamepadStick=vec2(),touchGamepadAnalog=1;function touchGamepadCreate(){touchGamepadEnable&&isTouchDevice&&(ontouchstart=ontouchmove=ontouchend=a=>{if(touchGamepadEnable){touchGamepadStick=vec2();touchGamepadButtons=[];if(a.touches.length&&(touchGamepadTimer.isSet()||zzfx(0),isUsingGamepad=1,touchGamepadTimer.set(),paused)){touchGamepadButtons[9]=1;return}var b=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),c=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),d=mainCanvasSize.scale(.5);for(const e of a.touches)a=mouseToScreen(vec2(e.clientX,e.clientY)),a.distance(b)<touchGamepadSize?touchGamepadAnalog?touchGamepadStick=a.subtract(b).clampLength(touchGamepadSize/2).scale(2/touchGamepadSize):(a=a.subtract(b).angle(),touchGamepadStick.setAngle((4*a/PI+8.5|0)*PI/4)):a.distance(c)<touchGamepadSize?(a=a.subtract(c).direction(),touchGamepadButtons[a]=1):a.distance(d)<touchGamepadSize&&(touchGamepadButtons[9]=1)}})}function touchGamepadRender(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer.get(),4,3);if(a&&!paused){overlayContext.save();overlayContext.globalAlpha=a*touchGamepadAlpha;overlayContext.strokeStyle="#fff";overlayContext.lineWidth=3;overlayContext.fillStyle=0<gamepadStick(0).length()?"#fff":"#000";overlayContext.beginPath();overlayContext.arc(touchGamepadSize,mainCanvasSize.y-touchGamepadSize,touchGamepadSize/2,0,9);overlayContext.fill();overlayContext.stroke();a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);for(let b=4;b--;){const c=a.add((new Vector2).setAngle(b*PI/2,touchGamepadSize/2));overlayContext.fillStyle=touchGamepadButtons[b]?"#fff":"#000";overlayContext.beginPath();overlayContext.arc(c.x,c.y,touchGamepadSize/4,0,9);overlayContext.fill();overlayContext.stroke()}overlayContext.restore()}}}"use strict";class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=a[1]||0,a[1]=0,this.cachedSamples=zzfxG(...a))}play(a,b=1,c=1,d=1){if(soundEnable){var e=0;if(a){if(e=this.range){const f=cameraPos.distanceSquared(a);if(f>e*e)return;b*=percent(f**.5,e,e*this.taper)}e=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return playSamples([this.cachedSamples],b,a,e)}}playNote(a,b,c=1){if(soundEnable)return this.play(b,c,2**(a/12),0)}}class Music{constructor(a){soundEnable&&(this.cachedSamples=zzfxM(...a))}play(a=1,b=1){if(soundEnable)return playSamples(this.cachedSamples,a,1,0,b)}}function playAudioFile(a,b=1,c=1){if(soundEnable)return a=new Audio(a),a.volume=soundVolume*b,a.loop=c,a.play(),a}function speak(a,b="",c=1,d=1,e=1){if(soundEnable&&speechSynthesis)return a=new SpeechSynthesisUtterance(a),a.lang=b,a.volume=2*c*soundVolume,a.rate=d,a.pitch=e,speechSynthesis.speak(a),a}const speakStop=()=>speechSynthesis&&speechSynthesis.cancel(),getNoteFrequency=(a,b=220)=>b*2**(a/12);let audioContext;function playSamples(a,b=1,c=1,d=0,e=0){if(soundEnable&&(audioContext||(audioContext=new(window.AudioContext||webkitAudioContext)),audioContext.resume(),"running"==audioContext.state)){var f=audioContext.createBuffer(a.length,a[0].length,zzfxR),g=audioContext.createBufferSource();a.forEach((h,l)=>f.getChannelData(l).set(h));g.buffer=f;g.playbackRate.value=c;g.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);(window.StereoPannerNode?g.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})):g).connect(a);g.start();return g}}const zzfx=(...a)=>playSamples([zzfxG(...a)]),zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,h=1,l=0,n=0,m=0,p=0,k=0,u=0,v=0,A=0,r=0,B=1,x=0,C=0){let t=2*PI,E=l*=500*t/zzfxR/zzfxR,y=[];b=c*=(1+b*rand(-1,1))*t/zzfxR;let w=0,F=0,q=0,z=1,H=0,I=0,D=0,J,G;d=d*zzfxR+9;x*=zzfxR;e*=zzfxR;f*=zzfxR;r*=zzfxR;n*=500*t/zzfxR**3;v*=t/zzfxR;m*=t/zzfxR;p*=zzfxR;k=k*zzfxR|0;for(G=d+x+e+f+r|0;q<G;y[q++]=D)++I%(100*A|0)||(D=g?1<g?2<g?3<g?Math.sin((w%t)**3):Math.max(Math.min(Math.tan(w),1),-1):1-(2*w/t%2+2)%2:1-4*abs(Math.round(w/t)-w/t):Math.sin(w),D=(k?1-C+C*Math.sin(t*q/k):1)*(0<D?1:-1)*abs(D)**h*a*soundVolume*(q<d?q/d:q<d+x?1-(q-d)/x*(1-B):q<d+x+e?B:q<G-r?(G-q-r)/f*B:0),D=r?D/2+(r>q?0:(q<G-r?1:(G-q)/r)*y[q-r|0]/2):D),J=(c+=l+=n)*Math.cos(v*F++),w+=J-J*u*(1-1e9*(Math.sin(q)+1)%2),z&&++z>p&&(c+=m,b+=m,z=0),!k||++H%k||(c=b,l=E,z=z||1);return y}function zzfxM(a,b,c,d=125){let e,f,g,h,l,n,m,p,k,u,v,A,r,B=0,x,C=[],t=[],E=[],y=0,w=0,F=1,q={},z=zzfxR/d*60>>2;for(;F;y++)C=[F=p=A=0],c.forEach((H,I)=>{m=b[H][y]||[0,0,0];F|=!!b[H][y];x=A+(b[H][0].length-2-!p)*z;r=I==c.length-1;f=2;for(h=A;f<m.length+r;p=++f){l=m[f];k=f==m.length+r-1&&r||u!=(m[0]||0)|l|0;for(g=0;g<z&&p;g++>z-99&&k?v+=(1>v)/99:0)n=(1-v)*C[B++]/2||0,t[h]=(t[h]||0)-n*w+n,E[h]=(E[h++]||0)+n*w+n;l&&(v=l%1,w=m[1]||0,l|=0)&&(C=q[[u=m[B=0]||0,l]]=q[[u,l]]||(e=[...a[u]],e[2]*=2**((l-12)/12),0<l?zzfxG(...e):[]))}A=x});return[t,E]}"use strict";let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}const setTileCollisionData=(a,b=0)=>a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b),getTileCollisionData=a=>a.arrayCheck(tileCollisionSize)?tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]:0;function tileCollisionTest(a,b=vec2(),c){const d=max(a.x-b.x/2|0,0);var e=max(a.y-b.y/2|0,0);const f=min(a.x+b.x/2,tileCollisionSize.x);for(a=min(a.y+b.y/2,tileCollisionSize.y);e<a;++e)for(b=d;b<f;++b){const g=tileCollision[e*tileCollisionSize.x+b];if(g&&(!c||c.collideWithTile(g,new Vector2(b,e))))return 1}}function tileCollisionRaycast(a,b,c){a=a.floor();b=b.floor();var d=b.subtract(a);const e=abs(d.x),f=-abs(d.y),g=sign(d.x);d=sign(d.y);let h=e+f;for(let n=a.x,m=a.y;;){var l=getTileCollisionData(vec2(n,m));if(l&&(c?c.collideWithTileRaycast(l,new Vector2(n,m)):0<l))return debugRaycast&&debugLine(a,b,"#f00",.02,1),debugRaycast&&debugPoint(new Vector2(n+.5,m+.5),"#ff0",1),new Vector2(n+.5,m+.5);if(n==b.x&m==b.y)break;l=2*h;l>=f&&(h+=f,n+=g);l<=e&&(h+=e,m+=d)}debugRaycast&&debugLine(a,b,"#00f",.02,1)}class TileLayerData{constructor(a,b=0,c=0,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=this.mirror=0;color=new Color}}class TileLayer extends EngineObject{constructor(a,b=tileCollisionSize,c=tileSizeDefault,d=vec2(1),e=0){super(a,b,-1,c,0,void 0,e);this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.scale=d;this.isOverlay;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c){a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+a.x|0]=b,c&&this.drawTileData(a))}getData(a){return a.arrayCheck(this.size)&&this.data[(a.y|0)*this.size.x+a.x|0]}update(){}render(){ASSERT(mainContext!=this.context);glEnable&&!glOverlay&&!this.isOverlay&&glCopyToContext(mainContext);const a=worldToScreen(this.pos.add(vec2(0,this.size.y*this.scale.y)));(this.isOverlay?overlayContext:mainContext).drawImage(this.canvas,a.x,a.y,cameraScale*this.size.x*this.scale.x,cameraScale*this.size.y*this.scale.y)}redraw(){this.redrawStart(1);this.drawAllTileData();this.redrawEnd()}redrawStart(a=0){a&&(this.canvas.width=this.size.x*this.tileSize.x,this.canvas.height=this.size.y*this.tileSize.y);this.savedRenderSettings=[mainCanvas,mainContext,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;cameraPos=this.size.scale(.5);cameraScale=this.tileSize.x;enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context);glCopyToContext(mainContext,1);[mainCanvas,mainContext,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a){const b=a.floor().add(this.pos).add(vec2(.5));this.drawCanvas2D(b,vec2(1),0,0,c=>c.clearRect(-.5,-.5,1,1));a=this.getData(a);void 0!=a.tile&&(ASSERT(mainContext==this.context),drawTile(b,vec2(1),a.tile,this.tileSize,a.color,a.direction*PI/2,a.mirror))}drawAllTileData(){for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b))}drawCanvas2D(a,b,c=0,d,e){const f=this.context;f.save();a=a.subtract(this.pos).multiply(this.tileSize);b=b.multiply(this.tileSize);f.translate(a.x,this.canvas.height-a.y);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f,g){this.drawCanvas2D(a,b,f,g,h=>{if(0>c)h.fillStyle=e.rgba(),h.fillRect(-.5,-.5,1,1);else{const l=tileImage.width/d.x;h.globalAlpha=e.a;h.drawImage(tileImage,c%l*d.x,(c/l|0)*d.x,d.x,d.y,-.5,-.5,1,1)}})}drawRect(a,b,c,d){this.drawTile(a,b,-1,0,c,d)}}"use strict";class ParticleEmitter extends EngineObject{constructor(a,b=0,c=0,d=100,e=PI,f=-1,g=tileSizeDefault,h=new Color,l=new Color,n=new Color(1,1,1,0),m=new Color(1,1,1,0),p=.5,k=.1,u=1,v=.1,A=.05,r=1,B=1,x=0,C=PI,t=.1,E=.2,y,w,F=1,q=w?1e9:0){super(a,new Vector2,f,g,0,void 0,q);this.emitSize=b;this.emitTime=c;this.emitRate=d;this.emitConeAngle=e;this.colorStartA=h;this.colorStartB=l;this.colorEndA=n;this.colorEndB=m;this.randomColorLinear=F;this.particleTime=p;this.sizeStart=k;this.sizeEnd=u;this.speed=v;this.angleSpeed=A;this.damping=r;this.angleDamping=B;this.gravityScale=x;this.particleConeAngle=C;this.fadeRate=t;this.randomness=E;this.collideTiles=y;this.additive=w;this.emitTimeBuffer=this.trailScale=0}update(){this.parent&&super.update();if(!this.emitTime||this.getAliveTime()<=this.emitTime){if(this.emitRate*particleEmitRateScale){const a=1/this.emitRate/particleEmitRateScale;for(this.emitTimeBuffer+=timeDelta;0<this.emitTimeBuffer;this.emitTimeBuffer-=a)this.emitParticle()}}else this.destroy();debugParticles&&debugRect(this.pos,vec2(this.emitSize),"#0f0",0,this.angle)}emitParticle(){var a=void 0!=this.emitSize.x?new Vector2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle):randInCircle(.5*this.emitSize);a=new Particle(this.pos.add(a),this.tileIndex,this.tileSize,this.angle+rand(this.particleConeAngle,-this.particleConeAngle));const b=this.randomness;var c=m=>m+m*rand(b,-b);const d=c(this.particleTime),e=c(this.sizeStart),f=c(this.sizeEnd),g=c(this.speed);c=c(this.angleSpeed)*randSign();const h=rand(this.emitConeAngle,-this.emitConeAngle),l=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),n=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);a.colorStart=l;a.colorEndDelta=n.subtract(l);a.velocity=(new Vector2).setAngle(this.angle+h,g);a.angleVelocity=c;a.lifeTime=d;a.sizeStart=e;a.sizeEndDelta=f-e;a.fadeRate=this.fadeRate;a.damping=this.damping;a.angleDamping=this.angleDamping;a.elasticity=this.elasticity;a.friction=this.friction;a.gravityScale=this.gravityScale;a.collideTiles=this.collideTiles;a.additive=this.additive;a.renderOrder=this.renderOrder;a.trailScale=this.trailScale;a.mirror=.5>rand();a.destroyCallback=this.particleDestroyCallback;this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d){super(a,new Vector2,b,c,d)}render(){const a=min((time-this.spawnTime)/this.lifeTime,1);var b=this.sizeStart+a*this.sizeEndDelta;b=new Vector2(b,b);var c=this.fadeRate/2;c=new Color(this.colorStart.r+a*this.colorEndDelta.r,this.colorStart.g+a*this.colorEndDelta.g,this.colorStart.b+a*this.colorEndDelta.b,(this.colorStart.a+a*this.colorEndDelta.a)*(a<c?a/c:a>1-c?(1-a)/c:1));this.additive&&setBlendMode(1);if(this.trailScale){var d=this.velocity.length();const e=this.velocity.scale(1/d);d*=this.trailScale;b.y=max(b.x,d);this.angle=e.angle();drawTile(this.pos.add(e.multiply(vec2(0,-d/2))),b,this.tileIndex,this.tileSize,c,this.angle,this.mirror)}else drawTile(this.pos,b,this.tileIndex,this.tileSize,c,this.angle,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(this.pos,b,"#f005",0,this.angle);1==a&&(this.color=c,this.size=b,this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}}"use strict";const medals=[];let medalsPreventUnlock,newgrounds,medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast;function medalsInit(a){medalsSaveName=a;debugMedals||medals.forEach(b=>b.unlocked=1)}class Medal{constructor(a,b,c="",d="🏆",e){ASSERT(0<=a&&!medals[a]);medals[this.id=a]=this;this.name=b;this.description=c;this.icon=d;this.image=new Image;e&&(this.image.src=e)}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName),localStorage[this.storageKey()]=this.unlocked=1,medalsDisplayQueue.push(this),newgrounds&&newgrounds.unlockMedal(this.id),localStorage["OS13kTrophy,"+this.icon+","+medalsSaveName+","+this.name]=this.description)}render(a=0){const b=overlayContext,c=min(medalDisplayWidth,mainCanvas.width),d=overlayCanvas.width-c;a*=-medalDisplayHeight;b.save();b.beginPath();b.fillStyle="#ddd";b.fill(b.rect(d,a,c,medalDisplayHeight));b.strokeStyle="#000";b.lineWidth=3;b.stroke();b.clip();this.renderIcon(d+15+medalDisplayIconSize/2,a+medalDisplayHeight/2);b.textAlign="left";b.font="38px "+fontDefault;b.fillText(this.name,d+medalDisplayIconSize+30,a+28);b.font="24px "+fontDefault;b.fillText(this.description,d+medalDisplayIconSize+30,a+60);b.restore()}renderIcon(a,b,c=medalDisplayIconSize){const d=overlayContext;d.fillStyle="#000";d.textAlign="center";d.textBaseline="middle";d.font=.7*c+"px "+fontDefault;this.image.src?d.drawImage(this.image,a-c/2,b-c/2,c,c):d.fillText(this.icon,a,b)}storageKey(){return medalsSaveName+"_"+this.id}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayQueue.shift(medalsDisplayTimeLast=0);else{const c=medalDisplayTime-medalDisplaySlideTime;a.render(b<medalDisplaySlideTime?1-b/medalDisplaySlideTime:b>c?(b-c)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}}class Newgrounds{constructor(a,b){ASSERT(!newgrounds&&a);this.app_id=a;this.cipher=b;this.host=location?location.hostname:"";b&&(this.cryptoJS=CryptoJS());this.session_id=new URL(window.location.href).searchParams.get("ngio_session_id")||0;if(0!=this.session_id){this.medals=(a=this.call("Medal.getList"))?a.result.data.medals:[];debugMedals&&console.log(this.medals);for(var c of this.medals)if(a=medals[c.id])a.image.src=c.icon,a.name=c.name,a.description=c.description,a.unlocked=c.unlocked,a.difficulty=c.difficulty,a.value=c.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(c=this.call("ScoreBoard.getBoards"))?c.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards)}}unlockMedal(a){return this.call("Medal.unlock",{id:a},1)}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b},1)}logView(){return this.call("App.logView",{host:this.host},1)}getScores(a,b=0,c=0,d=0,e=10){return this.call("ScoreBoard.getScores",{id:a,user:b,social:c,skip:d,limit:e})}call(a,b=0,c=0){a={component:a,parameters:b};if(this.cipher){b=this.cryptoJS;var d=b.enc.Base64.parse(this.cipher);const e=b.lib.WordArray.random(16);d=b.AES.encrypt(JSON.stringify(a),d,{iv:e});a.secure=b.enc.Base64.stringify(e.concat(d.ciphertext));a.parameters=0}b={app_id:this.app_id,session_id:this.session_id,call:a};a=new FormData;a.append("input",JSON.stringify(b));b=new XMLHttpRequest;b.open("POST","https://newgrounds.io/gateway_v3.php",!debugMedals&&c);b.send(a);debugMedals&&console.log(b.responseText);return b.responseText&&JSON.parse(b.responseText)}}const CryptoJS=()=>eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",..."]charCodeAtUinyxpf","for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],131072,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(32768),new Uint8Array(51e6),0,0,0,0));"use strict";let glCanvas,glContext,glTileTexture,glActiveTexture,glShader,glPositionData,glColorData,glBatchCount,glBatchAdditive,glAdditive;function glInit(){if(glEnable){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl",{antialias:!1});glCanvas.style=styleCanvas;glTileTexture=glCreateTexture(tileImage);glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("precision highp float;uniform mat4 m;attribute vec2 p,t;attribute vec4 c,a;varying vec2 v;varying vec4 d,e;void main(){gl_Position=m*vec4(p,1,1);v=t;d=c;e=a;}","precision highp float;varying vec2 v;varying vec4 d,e;uniform sampler2D j;void main(){gl_FragColor=texture2D(j,v)*d+e;}");var a=new ArrayBuffer(gl_MAX_BATCH*gl_VERTICES_PER_QUAD*gl_VERTEX_BYTE_STRIDE);glCreateBuffer(gl_ARRAY_BUFFER,a.byteLength,gl_DYNAMIC_DRAW);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);var b=glBatchCount=0;a=(c,d,e,f,g=0)=>{c=glContext.getAttribLocation(glShader,c);glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,f,d,g,gl_VERTEX_BYTE_STRIDE,b);b+=f*e};a("p",gl_FLOAT,4,2);a("t",gl_FLOAT,4,2);a("c",gl_UNSIGNED_BYTE,1,4,1);a("a",gl_UNSIGNED_BYTE,1,4,1)}}function glSetBlendMode(a){glEnable&&(glAdditive=a)}function glSetTexture(a=glTileTexture){glEnable&&(a!=glActiveTexture&&glFlush(),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=a))}function glCompileShader(a,b){if(glEnable){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,gl_COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}}function glCreateProgram(a,b){if(glEnable){var c=glContext.createProgram();glContext.attachShader(c,glCompileShader(a,gl_VERTEX_SHADER));glContext.attachShader(c,glCompileShader(b,gl_FRAGMENT_SHADER));glContext.linkProgram(c);if(debug&&!glContext.getProgramParameter(c,gl_LINK_STATUS))throw glContext.getProgramInfoLog(c);return c}}function glCreateBuffer(a,b,c){if(glEnable){var d=glContext.createBuffer();glContext.bindBuffer(a,d);glContext.bufferData(a,b,c);return d}}function glCreateTexture(a){if(glEnable&&a&&a.width){var b=glContext.createTexture();glContext.bindTexture(gl_TEXTURE_2D,b);glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MIN_FILTER,cavasPixelated?gl_NEAREST:gl_LINEAR);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MAG_FILTER,cavasPixelated?gl_NEAREST:gl_LINEAR);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_S,gl_CLAMP_TO_EDGE);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_T,gl_CLAMP_TO_EDGE);return b}}function glPreRender(a,b,c,d,e){glEnable&&(glContext.viewport(0,0,glCanvas.width=a,glCanvas.height=b),glContext.clear(gl_COLOR_BUFFER_BIT),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=glTileTexture),glContext.useProgram(glShader),glSetBlendMode(),a=2*e/a,b=2*e/b,glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),0,new Float32Array([a,0,0,0,0,b,0,0,1,1,-1,1,-1-a*c,-1-b*d,0,0])))}function glFlush(){if(glEnable&&glBatchCount){var a=glBatchAdditive?gl_ONE:gl_ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(gl_SRC_ALPHA,a,gl_ONE,a);glContext.enable(gl_BLEND);glContext.bufferSubData(gl_ARRAY_BUFFER,0,glPositionData.subarray(0,glBatchCount*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT));glContext.drawArrays(gl_TRIANGLES,0,glBatchCount*gl_VERTICES_PER_QUAD);glBatchCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b){glEnable&&glBatchCount&&(glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0))}function glDraw(a,b,c,d,e,f,g,h,l,n=4294967295,m=0){if(glEnable){glBatchCount!=gl_MAX_BATCH&&glBatchAdditive==glAdditive||glFlush();var p=Math.cos(e)/2,k=Math.sin(e)/2;e=p*c;p*=d;c*=k;d*=k;k=glBatchCount++*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT;glPositionData[k++]=a-e-d;glPositionData[k++]=b-p+c;glPositionData[k++]=f;glPositionData[k++]=l;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a+e+d;glPositionData[k++]=b+p-c;glPositionData[k++]=h;glPositionData[k++]=g;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a-e+d;glPositionData[k++]=b+p+c;glPositionData[k++]=f;glPositionData[k++]=g;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a-e-d;glPositionData[k++]=b-p+c;glPositionData[k++]=f;glPositionData[k++]=l;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a+e-d;glPositionData[k++]=b-p-c;glPositionData[k++]=h;glPositionData[k++]=l;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a+e+d;glPositionData[k++]=b+p-c;glPositionData[k++]=h;glPositionData[k++]=g;glColorData[k++]=n;glColorData[k++]=m}}const gl_ONE=1,gl_TRIANGLES=4,gl_SRC_ALPHA=770,gl_ONE_MINUS_SRC_ALPHA=771,gl_BLEND=3042,gl_TEXTURE_2D=3553,gl_UNSIGNED_BYTE=5121,gl_FLOAT=5126,gl_RGBA=6408,gl_NEAREST=9728,gl_LINEAR=9729,gl_TEXTURE_MAG_FILTER=10240,gl_TEXTURE_MIN_FILTER=10241,gl_TEXTURE_WRAP_S=10242,gl_TEXTURE_WRAP_T=10243,gl_COLOR_BUFFER_BIT=16384,gl_CLAMP_TO_EDGE=33071,gl_ARRAY_BUFFER=34962,gl_DYNAMIC_DRAW=35048,gl_FRAGMENT_SHADER=35632,gl_VERTEX_SHADER=35633,gl_COMPILE_STATUS=35713,gl_LINK_STATUS=35714,gl_VERTICES_PER_QUAD=6,gl_INDICIES_PER_VERT=6,gl_MAX_BATCH=65536,gl_VERTEX_BYTE_STRIDE=24;
1
+ const debug=0,showWatermark=0,godMode=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0,ASSERT=()=>{},debugInit=()=>{},debugUpdate=()=>{},debugRender=()=>{},debugRect=()=>{},debugCircle=()=>{},debugPoint=()=>{},debugLine=()=>{},debugAABB=()=>{},debugText=()=>{},debugClear=()=>{},debugSaveCanvas=()=>{};"use strict";const PI=Math.PI,abs=a=>0>a?-a:a,min=(a,b)=>a<b?a:b,max=(a,b)=>a>b?a:b,sign=a=>0>a?-1:1,mod=(a,b=1)=>(a%b+b)%b,clamp=(a,b=0,c=1)=>a<b?b:a>c?c:a,percent=(a,b=0,c=1)=>c-b?clamp((a-b)/(c-b)):0,lerp=(a,b=0,c=1)=>b+clamp(a)*(c-b),smoothStep=a=>a*a*(3-2*a),nearestPowerOfTwo=a=>2**Math.ceil(Math.log2(a)),isOverlapping=(a,b,c,d)=>2*abs(a.x-c.x)<b.x+d.x&2*abs(a.y-c.y)<b.y+d.y,wave=(a=1,b=1,c=time)=>b/2*(1-Math.cos(c*a*2*PI)),formatTime=a=>(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0),rand=(a=1,b=0)=>b+(a-b)*Math.random(),randInt=(a=1,b=0)=>rand(a,b)|0,randSign=()=>2*(rand(2)|0)-1,randInCircle=(a=1,b=0)=>0<a?randVector(a*rand(b/a,1)**.5):new Vector2,randVector=(a=1)=>(new Vector2).setAngle(rand(2*PI),a),randColor=(a=new Color,b=new Color(0,0,0,1),c)=>c?a.lerp(b,rand()):new Color(rand(a.r,b.r),rand(a.g,b.g),rand(a.b,b.b),rand(a.a,b.a));let randSeed=1;const randSeeded=(a=1,b=0)=>{randSeed^=randSeed<<13;randSeed^=randSeed>>>17;randSeed^=randSeed<<5;return b+(a-b)*abs(randSeed%1e9)/1e9},vec2=(a=0,b)=>void 0==a.x?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y);class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}copy(){return new Vector2(this.x,this.y)}add(a){ASSERT(void 0!=a.x);return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){ASSERT(void 0!=a.x);return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){ASSERT(void 0!=a.x);return new Vector2(this.x*a.x,this.y*a.y)}divide(a){ASSERT(void 0!=a.x);return new Vector2(this.x/a.x,this.y/a.y)}scale(a){ASSERT(void 0==a.x);return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector2(a)}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this}dot(a){ASSERT(void 0!=a.x);return this.x*a.x+this.y*a.y}cross(a){ASSERT(void 0!=a.x);return this.x*a.y-this.y*a.x}angle(){return Math.atan2(this.x,this.y)}setAngle(a=0,b=1){this.x=b*Math.sin(a);this.y=b*Math.cos(a);return this}rotate(a){const b=Math.cos(a);a=Math.sin(a);return new Vector2(this.x*b-this.y*a,this.x*a+this.y*b)}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}invert(){return new Vector2(this.y,-this.x)}floor(){return new Vector2(Math.floor(this.x),Math.floor(this.y))}area(){return this.x*this.y}lerp(a,b){ASSERT(void 0!=a.x);return this.add(a.subtract(this).scale(clamp(b)))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}}class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d}copy(){return new Color(this.r,this.g,this.b,this.a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){return this.add(a.subtract(this).scale(clamp(b)))}setHSLA(a=0,b=0,c=1,d=1){b=.5>c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,g,h)=>(h=(h%1+1)%1)<1/6?f+6*(g-f)*h:.5>h?g:h<2/3?f+(g-f)*(2/3-h)*6:f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}mutate(a=.05,b=0){return new Color(this.r+rand(a,-a),this.g+rand(a,-a),this.b+rand(a,-a),this.a+rand(b,-b)).clamp()}rgba(){ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b&&0<=this.a&&1>=this.a);return`rgb(${255*this.r|0},${255*this.g|0},${255*this.b|0},${this.a})`}rgbaInt(){ASSERT(0<=this.r&&1>=this.r&&0<=this.g&&1>=this.g&&0<=this.b&&1>=this.b&&0<=this.a&&1>=this.a);return(255*this.r|0)+(255*this.g<<8)+(255*this.b<<16)+(255*this.a<<24)}}class Timer{constructor(a){this.time=void 0==a?void 0:time+a;this.setTime=a}set(a=0){this.time=time+a;this.setTime=a}unset(){this.time=void 0}isSet(){return void 0!=this.time}active(){return time<=this.time}elapsed(){return time>this.time}get(){return this.isSet()?time-this.time:0}getPercent(){return this.isSet()?percent(this.time-time,this.setTime,0):0}}"use strict";let canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),cavasPixelated=1,fontDefault="arial",tileSizeDefault=vec2(16),tileFixBleedScale=.3,objectDefaultSize=vec2(1),objectDefaultMass=1,objectDefaultDamping=.99,objectDefaultAngleDamping=.99,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,cameraPos=vec2(),cameraScale=max(tileSizeDefault.x,tileSizeDefault.y),glEnable=1,glOverlay=1,gamepadsEnable=1,gamepadDirectionEmulateStick=1,inputWASDEmulateDirection=1,touchGamepadEnable=0,touchGamepadAnalog=1,touchGamepadSize=80,touchGamepadAlpha=.3,vibrateEnable=1,soundVolume=.5,soundEnable=1,soundDefaultRange=30,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplayWidth=640,medalDisplayHeight=80,medalDisplayIconSize=50;"use strict";const engineName="LittleJS",engineVersion="1.2.3",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=0,frameTimeLastMS=0,frameTimeBufferMS=0,tileImageSize,tileImageFixBleed,averageFPS,drawCount;const styleBody="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none;-moz-user-select:none",styleCanvas="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";function engineInit(a,b,c,d,e,f){tileImage.onerror=tileImage.onload=()=>{tileImageFixBleed=vec2(tileFixBleedScale).divide(tileImageSize=vec2(tileImage.width,tileImage.height));debug&&(tileImage.onload=()=>ASSERT(1));document.body.style=styleBody;document.body.appendChild(mainCanvas=document.createElement("canvas"));mainContext=mainCanvas.getContext("2d");mainCanvas.style=styleCanvas;debugInit();glInit();document.body.appendChild(overlayCanvas=document.createElement("canvas"));overlayContext=overlayCanvas.getContext("2d");overlayCanvas.style=styleCanvas;a();touchGamepadCreate();g()};const g=(h=0)=>{requestAnimationFrame(g);var l=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS||0,1e3/(l||1));debug&&(l*=keyIsDown(107)?5:keyIsDown(109)?.2:1);timeReal+=l/1e3;frameTimeBufferMS=min(frameTimeBufferMS+!paused*l,50);if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{h=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(h=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=h}canvasFixedSize.x?(mainCanvas.width=canvasFixedSize.x,mainCanvas.height=canvasFixedSize.y,h=innerWidth/innerHeight,l=mainCanvas.width/mainCanvas.height,mainCanvas.style.width=overlayCanvas.style.width=h<l?"100%":"",mainCanvas.style.height=overlayCanvas.style.height=h<l?"":"100%",glCanvas&&(glCanvas.style.width=mainCanvas.style.width,glCanvas.style.height=mainCanvas.style.height)):(mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y));enginePreRender();d();engineObjects.sort((m,p)=>m.renderOrder-p.renderOrder);for(var n of engineObjects)n.destroyed||n.render();e();medalsRender();touchGamepadRender();debugRender();glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",n=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+" "+(glEnable?"GL":"2D"),overlayContext.fillText(n,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(n,mainCanvas.width-2,2),drawCount=0)};f?tileImage.src=f:tileImage.onload()}function enginePreRender(){mainCanvasSize=vec2(overlayCanvas.width=mainCanvas.width,overlayCanvas.height=mainCanvas.height);mainContext.imageSmoothingEnabled=!cavasPixelated;glPreRender(mainCanvas.width,mainCanvas.height,cameraPos.x,cameraPos.y,cameraScale)}function engineObjectsUpdate(){engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);const a=b=>{if(!b.destroyed){b.update();for(const c of b.children)a(c)}};for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed);time=++frame/frameRate}function engineObjectsDestroy(){for(const a of engineObjects)a.parent||a.destroy();engineObjects=engineObjects.filter(a=>!a.destroyed)}function engineObjectsCallback(a,b,c,d=engineObjects){if(a)if(void 0!=b.x)for(const e of d)isOverlapping(a,b,e.pos,e.size)&&c(e);else{b*=b;for(const e of d)a.distanceSquared(e.pos)<b&&c(e)}else for(const e of d)c(e)}"use strict";class EngineObject{constructor(a=vec2(),b=objectDefaultSize,c=-1,d=tileSizeDefault,e=0,f,g=0){ASSERT(a&&void 0!=a.x&&void 0!=b.x);this.pos=a.copy();this.size=b;this.drawSize;this.tileIndex=c;this.tileSize=d;this.angle=e;this.color=f;this.additiveColor;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=g;this.velocity=new Vector2;this.angleVelocity=0;this.spawnTime=time;this.children=[];this.collideTiles=1;engineObjects.push(this)}update(){var a=this.parent;if(a)this.pos=this.localPos.multiply(vec2(a.getMirrorSign(),1)).rotate(-a.angle).add(a.pos),this.angle=a.getMirrorSign()*this.localAngle+a.angle;else if(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed),a=this.pos.copy(),this.pos.x+=this.velocity.x*=this.damping,this.pos.y+=this.velocity.y=this.damping*this.velocity.y+gravity*this.gravityScale,this.angle+=this.angleVelocity*=this.angleDamping,ASSERT(0<=this.angleDamping&&1>=this.angleDamping),ASSERT(0<=this.damping&&1>=this.damping),this.mass){var b=0>this.velocity.y;if(this.groundObject){var c=this.groundObject.velocity?this.groundObject.velocity.x:0;this.velocity.x=c+(this.velocity.x-c)*this.friction;this.groundObject=0}if(this.collideSolidObjects)for(var d of engineObjectsCollide)if(!(!this.isSolid&!d.isSolid||d.destroyed||d.parent||d==this||!isOverlapping(this.pos,this.size,d.pos,d.size)||!this.collideWithObject(d)|!d.collideWithObject(this)))if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);var e=c.length();c=.01>e?randVector(.001):c.scale(.001/e);this.velocity=this.velocity.add(c);d.mass&&(d.velocity=d.velocity.subtract(c));debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f00")}else{c=this.size.add(d.size);e=2*(a.y-d.pos.y)>c.y+gravity;var f=2*abs(a.y-d.pos.y)<c.y,g=2*abs(a.x-d.pos.x)<c.x;if(e||g||!f)if(this.pos.y=d.pos.y+(c.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-this.elasticity;else if(d.mass){const h=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass),l=this.velocity.y*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.y*d.mass/(this.mass+d.mass),n=d.velocity.y*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.y*this.mass/(this.mass+d.mass),m=max(this.elasticity,d.elasticity);this.velocity.y=lerp(m,h,l);d.velocity.y=lerp(m,h,n)}e||!f&&g||(this.pos.x=d.pos.x+(c.x/2+.001)*sign(a.x-d.pos.x),d.mass?(c=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(this.mass+d.mass),e=this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass),f=d.velocity.x*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.x*this.mass/(this.mass+d.mass),g=max(this.elasticity,d.elasticity),this.velocity.x=lerp(g,c,e),d.velocity.x=lerp(g,c,f)):this.velocity.x*=-this.elasticity);debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f0f")}if(this.collideTiles&&tileCollisionTest(this.pos,this.size,this)&&!tileCollisionTest(a,this.size,this)){c=tileCollisionTest(new Vector2(a.x,this.pos.y),this.size,this);d=tileCollisionTest(new Vector2(this.pos.x,a.y),this.size,this);if(c||!d)this.groundObject=b,this.velocity.y*=-this.elasticity,b=(a.y-this.size.y/2|0)-(a.y-this.size.y/2),0>b&&b>this.damping*this.velocity.y+gravity*this.gravityScale&&(this.velocity.y=this.damping?(b-gravity*this.gravityScale)/this.damping:0),this.pos.y=a.y;d&&(this.pos.x=a.x,this.velocity.x*=-this.elasticity)}}}render(){drawTile(this.pos,this.drawSize||this.size,this.tileIndex,this.tileSize,this.color,this.angle,this.mirror,this.additiveColor)}destroy(){if(!this.destroyed){this.destroyed=1;this.parent&&this.parent.removeChild(this);for(const a of this.children)a.destroy(a.parent=0)}}collideWithTile(a,b){return 0<a}collideWithTileRaycast(a,b){return 0<a}collideWithObject(a){return 1}getAliveTime(){return time-this.spawnTime}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyForce(a){this.applyAcceleration(a.scale(1/this.mass))}getMirrorSign(){return this.mirror?-1:1}addChild(a,b=vec2(),c=0){ASSERT(!a.parent&&!this.children.includes(a));this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c}removeChild(a){ASSERT(a.parent==this&&this.children.includes(a));this.children.splice(this.children.indexOf(a),1);a.parent=0}setCollision(a=0,b=0,c=1){ASSERT(a||!b);this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c}}"use strict";const tileImage=new Image;let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2();const screenToWorld=a=>a.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos),worldToScreen=a=>a.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));function drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f=0,g,h=new Color(0,0,0,0),l=glEnable){showWatermark&&++drawCount;if(glEnable&&l)if(0>c||!tileImage.width)glDraw(a.x,a.y,b.x,b.y,f,0,0,0,0,0,e.rgbaInt());else{var n=tileImageSize.x/d.x|0;l=d.x/tileImageSize.x;const m=d.y/tileImageSize.y,p=c%n*l;n=(c/n|0)*m;glDraw(a.x,a.y,g?-b.x:b.x,b.y,f,p+tileImageFixBleed.x,n+tileImageFixBleed.y,p-tileImageFixBleed.x+l,n-tileImageFixBleed.y+m,e.rgbaInt(),h.rgbaInt())}else drawCanvas2D(a,b,f,g,m=>{if(0>c)m.fillStyle=e.rgba(),m.fillRect(-.5,-.5,1,1);else{var p=tileImageSize.x/d.x|0;const k=c%p*d.x+tileFixBleedScale;p=(c/p|0)*d.y+tileFixBleedScale;const u=d.x-2*tileFixBleedScale,v=d.y-2*tileFixBleedScale;m.globalAlpha=e.a;m.drawImage(tileImage,k,p,u,v,-.5,-.5,1,1)}})}function drawRect(a,b,c,d,e){drawTile(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawTileScreenSpace(a,b=vec2(1),c,d,e,f,g,h,l){drawTile(screenToWorld(a),b.scale(1/cameraScale),c,d,e,f,g,h,l)}function drawRectScreenSpace(a,b,c,d,e){drawTileSrceenSpace(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawLine(a,b,c=.1,d,e){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());drawRect(a.add(b),c,d,b.angle(),0,0,e)}function drawCanvas2D(a,b,c,d,e,f=mainContext){a=worldToScreen(a);b=b.scale(cameraScale);f.save();f.translate(a.x+.5|0,a.y-.5|0);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}function setBlendMode(a,b=glEnable){glEnable&&b?glSetBlendMode(a):mainContext.globalCompositeOperation=a?"lighter":"source-over"}function drawText(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",h=fontDefault){b=worldToScreen(b);overlayContext.font=c*cameraScale+"px "+h;overlayContext.textAlign=g;overlayContext.textBaseline="middle";e&&(overlayContext.lineWidth=e*cameraScale,overlayContext.strokeStyle=f.rgba(),overlayContext.strokeText(a,b.x,b.y));overlayContext.fillStyle=d.rgba();overlayContext.fillText(a,b.x,b.y)}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=0,e=overlayContext){a||engineFontImage||(engineFontImage=new Image,engineFontImage.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC");this.image=a||engineFontImage;this.tileSize=b;this.paddingSize=c;this.startTileIndex=d;this.context=e}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!cavasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),h=this.image.width/this.tileSize.x|0;a.split("\n").forEach((l,n)=>{const m=d?l.length*f.x*c/2|0:0;for(let u=l.length;u--;){var p=l[u].charCodeAt();if(32>p||127<p)p=127;var k=this.startTileIndex+p-32;p=k%h;k=k/h|0;const v=b.add(vec2(u,n).multiply(g));e.drawImage(this.image,p*f.x,k*f.y,f.x,f.y,v.x-m,v.y,f.x*c,f.y*c)}});e.restore()}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}}const isFullscreen=()=>document.fullscreenElement;function toggleFullscreen(){isFullscreen()?document.exitFullscreen?document.exitFullscreen():document.mozCancelFullScreen&&document.mozCancelFullScreen():document.body.webkitRequestFullScreen?document.body.webkitRequestFullScreen():document.body.mozRequestFullScreen&&document.body.mozRequestFullScreen()}"use strict";const keyIsDown=(a,b=0)=>inputData[b]&&inputData[b][a]&1?1:0,keyWasPressed=(a,b=0)=>inputData[b]&&inputData[b][a]&2?1:0,keyWasReleased=(a,b=0)=>inputData[b]&&inputData[b][a]&4?1:0,clearInput=()=>inputData=[[]],mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=0;const gamepadIsDown=(a,b=0)=>keyIsDown(a,b+1),gamepadWasPressed=(a,b=0)=>keyWasPressed(a,b+1),gamepadWasReleased=(a,b=0)=>keyWasReleased(a,b+1),gamepadStick=(a,b=0)=>stickData[b]?stickData[b][a]||vec2():vec2();let inputData=[[]];function inputUpdate(){document.hasFocus()||clearInput();mousePos=screenToWorld(mousePosScreen);gamepadsUpdate()}function inputUpdatePost(){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=0}onkeydown=a=>{debug&&a.target!=document.body||(a.repeat||(inputData[isUsingGamepad=0][remapKeyCode(a.keyCode)]=3),debug||a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][remapKeyCode(a.keyCode)]=4)};const remapKeyCode=a=>inputWASDEmulateDirection?87==a?38:83==a?40:65==a?37:68==a?39:a:a;onmousedown=a=>{inputData[isUsingGamepad=0][a.button]=3;onmousemove(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>a.ctrlKey||(mouseWheel=sign(a.deltaY));oncontextmenu=a=>!1;const mouseToScreen=a=>{if(!mainCanvas)return vec2();const b=mainCanvas.getBoundingClientRect();return mainCanvasSize.multiply(vec2(percent(a.x,b.left,b.right),percent(a.y,b.top,b.bottom)))},stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){(stickData[0]||(stickData[0]=[]))[0]=vec2(touchGamepadStick.x,-touchGamepadStick.y);var a=inputData[1]||(inputData[1]=[]);for(var b=10;b--;){var c=3==b?2:2==b?3:b;a[c]=touchGamepadButtons[b]?1+2*!gamepadIsDown(c,0):4*gamepadIsDown(c,0)}}if(gamepadsEnable&&navigator.getGamepads&&(document.hasFocus()||debug))for(a=navigator.getGamepads(),b=a.length;b--;){var d=a[b];const g=inputData[b+1]||(inputData[b+1]=[]);c=stickData[b]||(stickData[b]=[]);if(d){var e=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.3,.8):0;for(var f=0;f<d.axes.length-1;f+=2)c[f>>1]=vec2(e(d.axes[f]),e(-d.axes[f+1])).clampLength();for(e=d.buttons.length;e--;)f=d.buttons[e],g[e]=f.pressed?1+2*!gamepadIsDown(e,b):4*gamepadIsDown(e,b),isUsingGamepad|=!b&&f.pressed,touchGamepadEnable&&touchGamepadTimer.unset();gamepadDirectionEmulateStick&&(d=vec2(gamepadIsDown(15,b)-gamepadIsDown(14,b),gamepadIsDown(12,b)-gamepadIsDown(13,b)),d.lengthSquared()&&(c[0]=d.clampLength()))}}}const vibrate=a=>vibrateEnable&&Navigator.vibrate&&Navigator.vibrate(a),vibrateStop=()=>vibrate(0),isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a,b;ontouchstart=ontouchmove=ontouchend=c=>{c.button=0;const d=c.touches.length;d?(b||zzfx(0,b=1),c.x=c.touches[0].clientX,c.y=c.touches[0].clientY,a?onmousemove(c):onmousedown(c)):a&&onmouseup(c);a=d;return!c.cancelable}}let touchGamepadTimer=new Timer,touchGamepadButtons=[],touchGamepadStick=vec2();function touchGamepadCreate(){touchGamepadEnable&&isTouchDevice&&(ontouchstart=ontouchmove=ontouchend=a=>{if(touchGamepadEnable){touchGamepadStick=vec2();touchGamepadButtons=[];if(a.touches.length&&(touchGamepadTimer.isSet()||zzfx(0),isUsingGamepad=1,touchGamepadTimer.set(),paused)){touchGamepadButtons[9]=1;return}var b=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),c=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),d=mainCanvasSize.scale(.5);for(const e of a.touches)a=mouseToScreen(vec2(e.clientX,e.clientY)),a.distance(b)<touchGamepadSize?touchGamepadAnalog?touchGamepadStick=a.subtract(b).scale(2/touchGamepadSize).clampLength():(a=a.subtract(b).angle(),touchGamepadStick.setAngle((4*a/PI+8.5|0)*PI/4)):a.distance(c)<touchGamepadSize?(a=a.subtract(c).direction(),touchGamepadButtons[a]=1):a.distance(d)<touchGamepadSize&&(touchGamepadButtons[9]=1)}})}function touchGamepadRender(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer.get(),4,3);if(a&&!paused){overlayContext.save();overlayContext.globalAlpha=a*touchGamepadAlpha;overlayContext.strokeStyle="#fff";overlayContext.lineWidth=3;overlayContext.fillStyle=0<touchGamepadStick.lengthSquared()?"#fff":"#000";overlayContext.beginPath();a=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize);if(touchGamepadAnalog)overlayContext.arc(a.x,a.y,touchGamepadSize/2,0,9),overlayContext.fill();else for(var b=10;b--;){var c=b*PI/4;overlayContext.arc(a.x,a.y,.6*touchGamepadSize,c+PI/8,c+PI/8);b%2&&overlayContext.arc(a.x,a.y,.33*touchGamepadSize,c,c);1==b&&overlayContext.fill()}overlayContext.stroke();a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);for(b=4;b--;)c=a.add((new Vector2).setAngle(b*PI/2,touchGamepadSize/2)),overlayContext.fillStyle=touchGamepadButtons[b]?"#fff":"#000",overlayContext.beginPath(),overlayContext.arc(c.x,c.y,touchGamepadSize/4,0,9),overlayContext.fill(),overlayContext.stroke();overlayContext.restore()}}}"use strict";class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=a[1]||0,a[1]=0,this.cachedSamples=zzfxG(...a))}play(a,b=1,c=1,d=1){if(soundEnable){var e=0;if(a){if(e=this.range){const f=cameraPos.distanceSquared(a);if(f>e*e)return;b*=percent(f**.5,e,e*this.taper)}e=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return playSamples([this.cachedSamples],b,a,e)}}playNote(a,b,c=1){if(soundEnable)return this.play(b,c,2**(a/12),0)}}class Music{constructor(a){soundEnable&&(this.cachedSamples=zzfxM(...a))}play(a=1,b=1){if(soundEnable)return playSamples(this.cachedSamples,a,1,0,b)}}function playAudioFile(a,b=1,c=1){if(soundEnable)return a=new Audio(a),a.volume=soundVolume*b,a.loop=c,a.play(),a}function speak(a,b="",c=1,d=1,e=1){if(soundEnable&&speechSynthesis)return a=new SpeechSynthesisUtterance(a),a.lang=b,a.volume=2*c*soundVolume,a.rate=d,a.pitch=e,speechSynthesis.speak(a),a}const speakStop=()=>speechSynthesis&&speechSynthesis.cancel(),getNoteFrequency=(a,b=220)=>b*2**(a/12);let audioContext;function playSamples(a,b=1,c=1,d=0,e=0){if(soundEnable&&(audioContext||(audioContext=new(window.AudioContext||webkitAudioContext)),audioContext.resume(),"running"==audioContext.state)){var f=audioContext.createBuffer(a.length,a[0].length,zzfxR),g=audioContext.createBufferSource();a.forEach((h,l)=>f.getChannelData(l).set(h));g.buffer=f;g.playbackRate.value=c;g.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);(window.StereoPannerNode?g.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})):g).connect(a);g.start();return g}}const zzfx=(...a)=>playSamples([zzfxG(...a)]),zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,h=1,l=0,n=0,m=0,p=0,k=0,u=0,v=0,A=0,r=0,B=1,y=0,C=0){let t=2*PI,F=l*=500*t/zzfxR/zzfxR,z=[];b=c*=(1+b*rand(-1,1))*t/zzfxR;let w=0,D=0,q=0,x=1,H=0,I=0,E=0,J,G;d=d*zzfxR+9;y*=zzfxR;e*=zzfxR;f*=zzfxR;r*=zzfxR;n*=500*t/zzfxR**3;v*=t/zzfxR;m*=t/zzfxR;p*=zzfxR;k=k*zzfxR|0;for(G=d+y+e+f+r|0;q<G;z[q++]=E)++I%(100*A|0)||(E=g?1<g?2<g?3<g?Math.sin((w%t)**3):Math.max(Math.min(Math.tan(w),1),-1):1-(2*w/t%2+2)%2:1-4*abs(Math.round(w/t)-w/t):Math.sin(w),E=(k?1-C+C*Math.sin(t*q/k):1)*(0<E?1:-1)*abs(E)**h*a*soundVolume*(q<d?q/d:q<d+y?1-(q-d)/y*(1-B):q<d+y+e?B:q<G-r?(G-q-r)/f*B:0),E=r?E/2+(r>q?0:(q<G-r?1:(G-q)/r)*z[q-r|0]/2):E),J=(c+=l+=n)*Math.cos(v*D++),w+=J-J*u*(1-1e9*(Math.sin(q)+1)%2),x&&++x>p&&(c+=m,b+=m,x=0),!k||++H%k||(c=b,l=F,x=x||1);return z}function zzfxM(a,b,c,d=125){let e,f,g,h,l,n,m,p,k,u,v,A,r,B=0,y,C=[],t=[],F=[],z=0,w=0,D=1,q={},x=zzfxR/d*60>>2;for(;D;z++)C=[D=p=A=0],c.forEach((H,I)=>{m=b[H][z]||[0,0,0];D|=!!b[H][z];y=A+(b[H][0].length-2-!p)*x;r=I==c.length-1;f=2;for(h=A;f<m.length+r;p=++f){l=m[f];k=f==m.length+r-1&&r||u!=(m[0]||0)|l|0;for(g=0;g<x&&p;g++>x-99&&k?v+=(1>v)/99:0)n=(1-v)*C[B++]/2||0,t[h]=(t[h]||0)-n*w+n,F[h]=(F[h++]||0)+n*w+n;l&&(v=l%1,w=m[1]||0,l|=0)&&(C=q[[u=m[B=0]||0,l]]=q[[u,l]]||(e=[...a[u]],e[2]*=2**((l-12)/12),0<l?zzfxG(...e):[]))}A=y});return[t,F]}"use strict";let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}const setTileCollisionData=(a,b=0)=>a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b),getTileCollisionData=a=>a.arrayCheck(tileCollisionSize)?tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]:0;function tileCollisionTest(a,b=vec2(),c){const d=max(a.x-b.x/2|0,0);var e=max(a.y-b.y/2|0,0);const f=min(a.x+b.x/2,tileCollisionSize.x);for(a=min(a.y+b.y/2,tileCollisionSize.y);e<a;++e)for(b=d;b<f;++b){const g=tileCollision[e*tileCollisionSize.x+b];if(g&&(!c||c.collideWithTile(g,new Vector2(b,e))))return 1}}function tileCollisionRaycast(a,b,c){a=a.floor();b=b.floor();var d=b.subtract(a);const e=abs(d.x),f=-abs(d.y),g=sign(d.x);d=sign(d.y);let h=e+f;for(let n=a.x,m=a.y;;){var l=getTileCollisionData(vec2(n,m));if(l&&(c?c.collideWithTileRaycast(l,new Vector2(n,m)):0<l))return debugRaycast&&debugLine(a,b,"#f00",.02,1),debugRaycast&&debugPoint(new Vector2(n+.5,m+.5),"#ff0",1),new Vector2(n+.5,m+.5);if(n==b.x&m==b.y)break;l=2*h;l>=f&&(h+=f,n+=g);l<=e&&(h+=e,m+=d)}debugRaycast&&debugLine(a,b,"#00f",.02,1)}class TileLayerData{constructor(a,b=0,c=0,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=this.mirror=0;color=new Color}}class TileLayer extends EngineObject{constructor(a,b=tileCollisionSize,c=tileSizeDefault,d=vec2(1),e=0){super(a,b,-1,c,0,void 0,e);this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.scale=d;this.isOverlay;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c){a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+a.x|0]=b,c&&this.drawTileData(a))}getData(a){return a.arrayCheck(this.size)&&this.data[(a.y|0)*this.size.x+a.x|0]}update(){}render(){ASSERT(mainContext!=this.context);glEnable&&!glOverlay&&!this.isOverlay&&glCopyToContext(mainContext);const a=worldToScreen(this.pos.add(vec2(0,this.size.y*this.scale.y)));(this.isOverlay?overlayContext:mainContext).drawImage(this.canvas,a.x,a.y,cameraScale*this.size.x*this.scale.x,cameraScale*this.size.y*this.scale.y)}redraw(){this.redrawStart(1);this.drawAllTileData();this.redrawEnd()}redrawStart(a=0){a&&(this.canvas.width=this.size.x*this.tileSize.x,this.canvas.height=this.size.y*this.tileSize.y);this.savedRenderSettings=[mainCanvas,mainContext,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;cameraPos=this.size.scale(.5);cameraScale=this.tileSize.x;enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context);glCopyToContext(mainContext,1);[mainCanvas,mainContext,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a){const b=a.floor().add(this.pos).add(vec2(.5));this.drawCanvas2D(b,vec2(1),0,0,c=>c.clearRect(-.5,-.5,1,1));a=this.getData(a);void 0!=a.tile&&(ASSERT(mainContext==this.context),drawTile(b,vec2(1),a.tile,this.tileSize,a.color,a.direction*PI/2,a.mirror))}drawAllTileData(){for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b))}drawCanvas2D(a,b,c=0,d,e){const f=this.context;f.save();a=a.subtract(this.pos).multiply(this.tileSize);b=b.multiply(this.tileSize);f.translate(a.x,this.canvas.height-a.y);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f,g){this.drawCanvas2D(a,b,f,g,h=>{if(0>c)h.fillStyle=e.rgba(),h.fillRect(-.5,-.5,1,1);else{const l=tileImage.width/d.x;h.globalAlpha=e.a;h.drawImage(tileImage,c%l*d.x,(c/l|0)*d.x,d.x,d.y,-.5,-.5,1,1)}})}drawRect(a,b,c,d){this.drawTile(a,b,-1,0,c,d)}}"use strict";class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g=-1,h=tileSizeDefault,l=new Color,n=new Color,m=new Color(1,1,1,0),p=new Color(1,1,1,0),k=.5,u=.1,v=1,A=.1,r=.05,B=1,y=1,C=0,t=PI,F=.1,z=.2,w,D,q=1,x=D?1e9:0){super(a,new Vector2,g,h,b,void 0,x);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=l;this.colorStartB=n;this.colorEndA=m;this.colorEndB=p;this.randomColorLinear=q;this.particleTime=k;this.sizeStart=u;this.sizeEnd=v;this.speed=A;this.angleSpeed=r;this.damping=B;this.angleDamping=y;this.gravityScale=C;this.particleConeAngle=t;this.fadeRate=F;this.randomness=z;this.collideTiles=w;this.additive=D;this.emitTimeBuffer=this.trailScale=0}update(){this.parent&&super.update();if(!this.emitTime||this.getAliveTime()<=this.emitTime){if(this.emitRate*particleEmitRateScale){const a=1/this.emitRate/particleEmitRateScale;for(this.emitTimeBuffer+=timeDelta;0<this.emitTimeBuffer;this.emitTimeBuffer-=a)this.emitParticle()}}else this.destroy();debugParticles&&debugRect(this.pos,vec2(this.emitSize),"#0f0",0,this.angle)}emitParticle(){var a=void 0!=this.emitSize.x?new Vector2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle):randInCircle(.5*this.emitSize);a=new Particle(this.pos.add(a),this.tileIndex,this.tileSize,this.angle+rand(this.particleConeAngle,-this.particleConeAngle));const b=this.randomness;var c=m=>m+m*rand(b,-b);const d=c(this.particleTime),e=c(this.sizeStart),f=c(this.sizeEnd),g=c(this.speed);c=c(this.angleSpeed)*randSign();const h=rand(this.emitConeAngle,-this.emitConeAngle),l=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),n=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);a.colorStart=l;a.colorEndDelta=n.subtract(l);a.velocity=(new Vector2).setAngle(this.angle+h,g);a.angleVelocity=c;a.lifeTime=d;a.sizeStart=e;a.sizeEndDelta=f-e;a.fadeRate=this.fadeRate;a.damping=this.damping;a.angleDamping=this.angleDamping;a.elasticity=this.elasticity;a.friction=this.friction;a.gravityScale=this.gravityScale;a.collideTiles=this.collideTiles;a.additive=this.additive;a.renderOrder=this.renderOrder;a.trailScale=this.trailScale;a.mirror=.5>rand();a.destroyCallback=this.particleDestroyCallback;this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d){super(a,new Vector2,b,c,d)}render(){const a=min((time-this.spawnTime)/this.lifeTime,1);var b=this.sizeStart+a*this.sizeEndDelta;b=new Vector2(b,b);var c=this.fadeRate/2;c=new Color(this.colorStart.r+a*this.colorEndDelta.r,this.colorStart.g+a*this.colorEndDelta.g,this.colorStart.b+a*this.colorEndDelta.b,(this.colorStart.a+a*this.colorEndDelta.a)*(a<c?a/c:a>1-c?(1-a)/c:1));this.additive&&setBlendMode(1);if(this.trailScale){var d=this.velocity.length();const e=this.velocity.scale(1/d);d*=this.trailScale;b.y=max(b.x,d);this.angle=e.angle();drawTile(this.pos.add(e.multiply(vec2(0,-d/2))),b,this.tileIndex,this.tileSize,c,this.angle,this.mirror)}else drawTile(this.pos,b,this.tileIndex,this.tileSize,c,this.angle,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(this.pos,b,"#f005",0,this.angle);1==a&&(this.color=c,this.size=b,this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}}"use strict";const medals=[];let medalsPreventUnlock,newgrounds,medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast;function medalsInit(a){medalsSaveName=a;debugMedals||medals.forEach(b=>b.unlocked=1)}class Medal{constructor(a,b,c="",d="🏆",e){ASSERT(0<=a&&!medals[a]);medals[this.id=a]=this;this.name=b;this.description=c;this.icon=d;this.image=new Image;e&&(this.image.src=e)}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName),localStorage[this.storageKey()]=this.unlocked=1,medalsDisplayQueue.push(this),newgrounds&&newgrounds.unlockMedal(this.id),localStorage["OS13kTrophy,"+this.icon+","+medalsSaveName+","+this.name]=this.description)}render(a=0){const b=overlayContext,c=min(medalDisplayWidth,mainCanvas.width),d=overlayCanvas.width-c;a*=-medalDisplayHeight;b.save();b.beginPath();b.fillStyle="#ddd";b.fill(b.rect(d,a,c,medalDisplayHeight));b.strokeStyle="#000";b.lineWidth=3;b.stroke();b.clip();this.renderIcon(d+15+medalDisplayIconSize/2,a+medalDisplayHeight/2);b.textAlign="left";b.font="38px "+fontDefault;b.fillText(this.name,d+medalDisplayIconSize+30,a+28);b.font="24px "+fontDefault;b.fillText(this.description,d+medalDisplayIconSize+30,a+60);b.restore()}renderIcon(a,b,c=medalDisplayIconSize){const d=overlayContext;d.fillStyle="#000";d.textAlign="center";d.textBaseline="middle";d.font=.7*c+"px "+fontDefault;this.image.src?d.drawImage(this.image,a-c/2,b-c/2,c,c):d.fillText(this.icon,a,b)}storageKey(){return medalsSaveName+"_"+this.id}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayQueue.shift(medalsDisplayTimeLast=0);else{const c=medalDisplayTime-medalDisplaySlideTime;a.render(b<medalDisplaySlideTime?1-b/medalDisplaySlideTime:b>c?(b-c)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}}class Newgrounds{constructor(a,b){ASSERT(!newgrounds&&a);this.app_id=a;this.cipher=b;this.host=location?location.hostname:"";b&&(this.cryptoJS=CryptoJS());this.session_id=new URL(window.location.href).searchParams.get("ngio_session_id")||0;if(0!=this.session_id){this.medals=(a=this.call("Medal.getList"))?a.result.data.medals:[];debugMedals&&console.log(this.medals);for(var c of this.medals)if(a=medals[c.id])a.image.src=c.icon,a.name=c.name,a.description=c.description,a.unlocked=c.unlocked,a.difficulty=c.difficulty,a.value=c.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(c=this.call("ScoreBoard.getBoards"))?c.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards)}}unlockMedal(a){return this.call("Medal.unlock",{id:a},1)}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b},1)}getScores(a,b=0,c=0,d=0,e=10){return this.call("ScoreBoard.getScores",{id:a,user:b,social:c,skip:d,limit:e})}logView(){return this.call("App.logView",{host:this.host},1)}call(a,b=0,c=0){a={component:a,parameters:b};if(this.cipher){b=this.cryptoJS;var d=b.enc.Base64.parse(this.cipher);const e=b.lib.WordArray.random(16);d=b.AES.encrypt(JSON.stringify(a),d,{iv:e});a.secure=b.enc.Base64.stringify(e.concat(d.ciphertext));a.parameters=0}b={app_id:this.app_id,session_id:this.session_id,call:a};a=new FormData;a.append("input",JSON.stringify(b));b=new XMLHttpRequest;b.open("POST","https://newgrounds.io/gateway_v3.php",!debugMedals&&c);b.send(a);debugMedals&&console.log(b.responseText);return b.responseText&&JSON.parse(b.responseText)}}const CryptoJS=()=>eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",..."]charCodeAtUinyxpf","for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],131072,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(32768),new Uint8Array(51e6),0,0,0,0));"use strict";let glCanvas,glContext,glTileTexture,glActiveTexture,glShader,glPositionData,glColorData,glBatchCount,glBatchAdditive,glAdditive;function glInit(){if(glEnable){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl",{antialias:!1});glCanvas.style=styleCanvas;glTileTexture=glCreateTexture(tileImage);glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("precision highp float;uniform mat4 m;attribute vec2 p,t;attribute vec4 c,a;varying vec2 v;varying vec4 d,e;void main(){gl_Position=m*vec4(p,1,1);v=t;d=c;e=a;}","precision highp float;varying vec2 v;varying vec4 d,e;uniform sampler2D s;void main(){gl_FragColor=texture2D(s,v)*d+e;}");var a=new ArrayBuffer(gl_MAX_BATCH*gl_VERTICES_PER_QUAD*gl_VERTEX_BYTE_STRIDE);glCreateBuffer(gl_ARRAY_BUFFER,a.byteLength,gl_DYNAMIC_DRAW);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);var b=glBatchCount=0;a=(c,d,e,f,g=0)=>{c=glContext.getAttribLocation(glShader,c);glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,f,d,g,gl_VERTEX_BYTE_STRIDE,b);b+=f*e};a("p",gl_FLOAT,4,2);a("t",gl_FLOAT,4,2);a("c",gl_UNSIGNED_BYTE,1,4,1);a("a",gl_UNSIGNED_BYTE,1,4,1)}}function glSetBlendMode(a){glEnable&&(glAdditive=a)}function glSetTexture(a=glTileTexture){glEnable&&(a!=glActiveTexture&&glFlush(),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=a))}function glCompileShader(a,b){if(glEnable){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,gl_COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}}function glCreateProgram(a,b){if(glEnable){var c=glContext.createProgram();glContext.attachShader(c,glCompileShader(a,gl_VERTEX_SHADER));glContext.attachShader(c,glCompileShader(b,gl_FRAGMENT_SHADER));glContext.linkProgram(c);if(debug&&!glContext.getProgramParameter(c,gl_LINK_STATUS))throw glContext.getProgramInfoLog(c);return c}}function glCreateBuffer(a,b,c){if(glEnable){var d=glContext.createBuffer();glContext.bindBuffer(a,d);glContext.bufferData(a,b,c);return d}}function glCreateTexture(a){if(glEnable&&a&&a.width){var b=glContext.createTexture();glContext.bindTexture(gl_TEXTURE_2D,b);glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MIN_FILTER,cavasPixelated?gl_NEAREST:gl_LINEAR);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MAG_FILTER,cavasPixelated?gl_NEAREST:gl_LINEAR);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_S,gl_CLAMP_TO_EDGE);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_T,gl_CLAMP_TO_EDGE);return b}}function glPreRender(a,b,c,d,e){glEnable&&(glContext.viewport(0,0,glCanvas.width=a,glCanvas.height=b),glContext.clear(gl_COLOR_BUFFER_BIT),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=glTileTexture),glContext.useProgram(glShader),glSetBlendMode(),a=2*e/a,b=2*e/b,glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),0,new Float32Array([a,0,0,0,0,b,0,0,1,1,-1,1,-1-a*c,-1-b*d,0,0])))}function glFlush(){if(glEnable&&glBatchCount){var a=glBatchAdditive?gl_ONE:gl_ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(gl_SRC_ALPHA,a,gl_ONE,a);glContext.enable(gl_BLEND);glContext.bufferSubData(gl_ARRAY_BUFFER,0,glPositionData.subarray(0,glBatchCount*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT));glContext.drawArrays(gl_TRIANGLES,0,glBatchCount*gl_VERTICES_PER_QUAD);glBatchCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b){glEnable&&glBatchCount&&(glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0))}function glDraw(a,b,c,d,e,f,g,h,l,n=4294967295,m=0){if(glEnable){glBatchCount!=gl_MAX_BATCH&&glBatchAdditive==glAdditive||glFlush();var p=Math.cos(e)/2,k=Math.sin(e)/2;e=p*c;p*=d;c*=k;d*=k;k=glBatchCount++*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT;glPositionData[k++]=a-e-d;glPositionData[k++]=b-p+c;glPositionData[k++]=f;glPositionData[k++]=l;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a+e+d;glPositionData[k++]=b+p-c;glPositionData[k++]=h;glPositionData[k++]=g;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a-e+d;glPositionData[k++]=b+p+c;glPositionData[k++]=f;glPositionData[k++]=g;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a-e-d;glPositionData[k++]=b-p+c;glPositionData[k++]=f;glPositionData[k++]=l;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a+e-d;glPositionData[k++]=b-p-c;glPositionData[k++]=h;glPositionData[k++]=l;glColorData[k++]=n;glColorData[k++]=m;glPositionData[k++]=a+e+d;glPositionData[k++]=b+p-c;glPositionData[k++]=h;glPositionData[k++]=g;glColorData[k++]=n;glColorData[k++]=m}}const gl_ONE=1,gl_TRIANGLES=4,gl_SRC_ALPHA=770,gl_ONE_MINUS_SRC_ALPHA=771,gl_BLEND=3042,gl_TEXTURE_2D=3553,gl_UNSIGNED_BYTE=5121,gl_FLOAT=5126,gl_RGBA=6408,gl_NEAREST=9728,gl_LINEAR=9729,gl_TEXTURE_MAG_FILTER=10240,gl_TEXTURE_MIN_FILTER=10241,gl_TEXTURE_WRAP_S=10242,gl_TEXTURE_WRAP_T=10243,gl_COLOR_BUFFER_BIT=16384,gl_CLAMP_TO_EDGE=33071,gl_ARRAY_BUFFER=34962,gl_DYNAMIC_DRAW=35048,gl_FRAGMENT_SHADER=35632,gl_VERTEX_SHADER=35633,gl_COMPILE_STATUS=35713,gl_LINK_STATUS=35714,gl_VERTICES_PER_QUAD=6,gl_INDICIES_PER_VERT=6,gl_MAX_BATCH=65536,gl_VERTEX_BYTE_STRIDE=24;