littlejsengine 1.9.3 → 1.9.4
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/dist/littlejs.d.ts +8 -3
- package/dist/littlejs.esm.js +49 -36
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +49 -36
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +45 -36
- package/examples/module/game.js +1 -1
- package/examples/platformer/gameCharacter.js +1 -2
- package/examples/platformer/gameLevel.js +0 -1
- package/examples/typescript/game.js +1 -1
- package/examples/typescript/game.ts +1 -1
- package/package.json +1 -1
- package/src/engine.js +2 -2
- package/src/engineAudio.js +1 -1
- package/src/engineDebug.js +4 -0
- package/src/engineDraw.js +11 -16
- package/src/engineInput.js +30 -16
- package/src/engineUtilities.js +1 -1
package/dist/littlejs.d.ts
CHANGED
|
@@ -882,7 +882,7 @@ declare module "littlejs.esm" {
|
|
|
882
882
|
setHSLA(h?: number, s?: number, l?: number, a?: number): Color;
|
|
883
883
|
/** Returns this color expressed in hsla format
|
|
884
884
|
* @return {Array} */
|
|
885
|
-
|
|
885
|
+
HSLA(): any[];
|
|
886
886
|
/** Returns a new color that has each component randomly adjusted
|
|
887
887
|
* @param {Number} [amount]
|
|
888
888
|
* @param {Number} [alphaAmount]
|
|
@@ -1011,11 +1011,16 @@ declare module "littlejs.esm" {
|
|
|
1011
1011
|
size: Vector2;
|
|
1012
1012
|
/** @property {Number} - Texture index to use */
|
|
1013
1013
|
textureIndex: number;
|
|
1014
|
-
/** Returns
|
|
1014
|
+
/** Returns a copy of this tile offset by a vector
|
|
1015
1015
|
* @param {Vector2} offset - Offset to apply in pixels
|
|
1016
1016
|
* @return {TileInfo}
|
|
1017
1017
|
*/
|
|
1018
1018
|
offset(offset: Vector2): TileInfo;
|
|
1019
|
+
/** Returns a copy of this tile offset by a number of animation frames
|
|
1020
|
+
* @param {Number} frame - Offset to apply in animation frames
|
|
1021
|
+
* @return {TileInfo}
|
|
1022
|
+
*/
|
|
1023
|
+
frame(frame: number): TileInfo;
|
|
1019
1024
|
/** Returns the texture info for this tile
|
|
1020
1025
|
* @return {TextureInfo}
|
|
1021
1026
|
*/
|
|
@@ -1473,7 +1478,7 @@ declare module "littlejs.esm" {
|
|
|
1473
1478
|
* 1, 0, 9, 1 // channel notes
|
|
1474
1479
|
* ],
|
|
1475
1480
|
* [ // channel 1
|
|
1476
|
-
* 0, 1, // instrument
|
|
1481
|
+
* 0, 1, // instrument 0, right speaker
|
|
1477
1482
|
* 0, 12, 17, -1 // channel notes
|
|
1478
1483
|
* ]
|
|
1479
1484
|
* ],
|
package/dist/littlejs.esm.js
CHANGED
|
@@ -264,6 +264,10 @@ function debugRender()
|
|
|
264
264
|
{
|
|
265
265
|
const saveContext = mainContext;
|
|
266
266
|
mainContext = overlayContext;
|
|
267
|
+
|
|
268
|
+
// draw red rectangle around screen
|
|
269
|
+
const cameraSize = getCameraSize();
|
|
270
|
+
debugRect(cameraPos, cameraSize.subtract(vec2(.1)), '#f008');
|
|
267
271
|
|
|
268
272
|
// mouse pick
|
|
269
273
|
let bestDistance = Infinity, bestObject;
|
|
@@ -1047,7 +1051,7 @@ class Color
|
|
|
1047
1051
|
|
|
1048
1052
|
/** Returns this color expressed in hsla format
|
|
1049
1053
|
* @return {Array} */
|
|
1050
|
-
|
|
1054
|
+
HSLA()
|
|
1051
1055
|
{
|
|
1052
1056
|
const r = clamp(this.r);
|
|
1053
1057
|
const g = clamp(this.g);
|
|
@@ -2137,13 +2141,23 @@ class TileInfo
|
|
|
2137
2141
|
this.textureIndex = textureIndex;
|
|
2138
2142
|
}
|
|
2139
2143
|
|
|
2140
|
-
/** Returns
|
|
2144
|
+
/** Returns a copy of this tile offset by a vector
|
|
2141
2145
|
* @param {Vector2} offset - Offset to apply in pixels
|
|
2142
2146
|
* @return {TileInfo}
|
|
2143
2147
|
*/
|
|
2144
2148
|
offset(offset)
|
|
2145
2149
|
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
|
|
2146
2150
|
|
|
2151
|
+
/** Returns a copy of this tile offset by a number of animation frames
|
|
2152
|
+
* @param {Number} frame - Offset to apply in animation frames
|
|
2153
|
+
* @return {TileInfo}
|
|
2154
|
+
*/
|
|
2155
|
+
frame(frame)
|
|
2156
|
+
{
|
|
2157
|
+
ASSERT(typeof frame == 'number');
|
|
2158
|
+
return this.offset(vec2(frame*this.size.x, 0));
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2147
2161
|
/** Returns the texture info for this tile
|
|
2148
2162
|
* @return {TextureInfo}
|
|
2149
2163
|
*/
|
|
@@ -2294,21 +2308,6 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
|
2294
2308
|
drawTile(pos, size, undefined, color, angle, false, undefined, useWebGL, screenSpace, context);
|
|
2295
2309
|
}
|
|
2296
2310
|
|
|
2297
|
-
/** Draw colored polygon using passed in points
|
|
2298
|
-
* @param {Array} points - Array of Vector2 points
|
|
2299
|
-
* @param {Color} [color=(1,1,1,1)]
|
|
2300
|
-
* @param {Boolean} [screenSpace=false]
|
|
2301
|
-
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
2302
|
-
* @memberof Draw */
|
|
2303
|
-
function drawPoly(points, color=new Color, screenSpace, context=mainContext)
|
|
2304
|
-
{
|
|
2305
|
-
context.fillStyle = color.toString();
|
|
2306
|
-
context.beginPath();
|
|
2307
|
-
for (const point of screenSpace ? points : points.map(worldToScreen))
|
|
2308
|
-
context.lineTo(point.x, point.y);
|
|
2309
|
-
context.fill();
|
|
2310
|
-
}
|
|
2311
|
-
|
|
2312
2311
|
/** Draw colored line between two points
|
|
2313
2312
|
* @param {Vector2} posA
|
|
2314
2313
|
* @param {Vector2} posB
|
|
@@ -2735,9 +2734,21 @@ function mouseToScreen(mousePos)
|
|
|
2735
2734
|
///////////////////////////////////////////////////////////////////////////////
|
|
2736
2735
|
// Gamepad input
|
|
2737
2736
|
|
|
2737
|
+
// gamepad internal variables
|
|
2738
2738
|
const stickData = [];
|
|
2739
|
+
|
|
2740
|
+
// gamepads are updated by engine every frame automatically
|
|
2739
2741
|
function gamepadsUpdate()
|
|
2740
2742
|
{
|
|
2743
|
+
const applyDeadZones = (v)=>
|
|
2744
|
+
{
|
|
2745
|
+
const min=.3, max=.8;
|
|
2746
|
+
const deadZone = (v)=>
|
|
2747
|
+
v > min ? percent( v, min, max) :
|
|
2748
|
+
v < -min ? -percent(-v, min, max) : 0;
|
|
2749
|
+
return vec2(deadZone(v.x), deadZone(-v.y)).clampLength();
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2741
2752
|
// update touch gamepad if enabled
|
|
2742
2753
|
if (touchGamepadEnable && isTouchDevice)
|
|
2743
2754
|
{
|
|
@@ -2749,7 +2760,16 @@ function gamepadsUpdate()
|
|
|
2749
2760
|
{
|
|
2750
2761
|
// read virtual analog stick
|
|
2751
2762
|
const sticks = stickData[0] || (stickData[0] = []);
|
|
2752
|
-
sticks[0] = vec2(
|
|
2763
|
+
sticks[0] = vec2();
|
|
2764
|
+
if (touchGamepadAnalog)
|
|
2765
|
+
sticks[0] = applyDeadZones(touchGamepadStick);
|
|
2766
|
+
else if (touchGamepadStick.lengthSquared() > .3)
|
|
2767
|
+
{
|
|
2768
|
+
// convert to 8 way dpad
|
|
2769
|
+
sticks[0].x = Math.round(touchGamepadStick.x);
|
|
2770
|
+
sticks[0].y = -Math.round(touchGamepadStick.y);
|
|
2771
|
+
sticks[0] = sticks[0].clampLength();
|
|
2772
|
+
}
|
|
2753
2773
|
|
|
2754
2774
|
// read virtual gamepad buttons
|
|
2755
2775
|
const data = inputData[1] || (inputData[1] = []);
|
|
@@ -2761,7 +2781,12 @@ function gamepadsUpdate()
|
|
|
2761
2781
|
}
|
|
2762
2782
|
}
|
|
2763
2783
|
|
|
2764
|
-
|
|
2784
|
+
// return if gamepads are disabled or not supported
|
|
2785
|
+
if (!gamepadsEnable || !navigator || !navigator.getGamepads)
|
|
2786
|
+
return;
|
|
2787
|
+
|
|
2788
|
+
// only poll gamepads when focused or in debug mode
|
|
2789
|
+
if (!debug && !document.hasFocus())
|
|
2765
2790
|
return;
|
|
2766
2791
|
|
|
2767
2792
|
// poll gamepads
|
|
@@ -2775,14 +2800,9 @@ function gamepadsUpdate()
|
|
|
2775
2800
|
|
|
2776
2801
|
if (gamepad)
|
|
2777
2802
|
{
|
|
2778
|
-
// read clamp dead zone of analog sticks
|
|
2779
|
-
const deadZone = .3, deadZoneMax = .8, applyDeadZone = (v)=>
|
|
2780
|
-
v > deadZone ? percent( v, deadZone, deadZoneMax) :
|
|
2781
|
-
v < -deadZone ? -percent(-v, deadZone, deadZoneMax) : 0;
|
|
2782
|
-
|
|
2783
2803
|
// read analog sticks
|
|
2784
2804
|
for (let j = 0; j < gamepad.axes.length-1; j+=2)
|
|
2785
|
-
sticks[j>>1] = vec2(
|
|
2805
|
+
sticks[j>>1] = applyDeadZones(vec2(gamepad.axes[j],gamepad.axes[j+1]));
|
|
2786
2806
|
|
|
2787
2807
|
// read buttons
|
|
2788
2808
|
for (let j = gamepad.buttons.length; j--;)
|
|
@@ -2911,14 +2931,7 @@ function createTouchGamepad()
|
|
|
2911
2931
|
if (touchPos.distance(stickCenter) < touchGamepadSize)
|
|
2912
2932
|
{
|
|
2913
2933
|
// virtual analog stick
|
|
2914
|
-
|
|
2915
|
-
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
2916
|
-
else
|
|
2917
|
-
{
|
|
2918
|
-
// 8 way dpad
|
|
2919
|
-
const angle = touchPos.subtract(stickCenter).angle();
|
|
2920
|
-
touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
|
|
2921
|
-
}
|
|
2934
|
+
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
2922
2935
|
}
|
|
2923
2936
|
else if (touchPos.distance(buttonCenter) < touchGamepadSize)
|
|
2924
2937
|
{
|
|
@@ -3177,7 +3190,7 @@ class SoundWave extends Sound
|
|
|
3177
3190
|
* 1, 0, 9, 1 // channel notes
|
|
3178
3191
|
* ],
|
|
3179
3192
|
* [ // channel 1
|
|
3180
|
-
* 0, 1, // instrument
|
|
3193
|
+
* 0, 1, // instrument 0, right speaker
|
|
3181
3194
|
* 0, 12, 17, -1 // channel notes
|
|
3182
3195
|
* ]
|
|
3183
3196
|
* ],
|
|
@@ -4987,7 +5000,7 @@ const engineName = 'LittleJS';
|
|
|
4987
5000
|
* @type {String}
|
|
4988
5001
|
* @default
|
|
4989
5002
|
* @memberof Engine */
|
|
4990
|
-
const engineVersion = '1.9.
|
|
5003
|
+
const engineVersion = '1.9.4';
|
|
4991
5004
|
|
|
4992
5005
|
/** Frames per second to update
|
|
4993
5006
|
* @type {Number}
|
|
@@ -5069,7 +5082,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5069
5082
|
timeReal += frameTimeDeltaMS / 1e3;
|
|
5070
5083
|
frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
|
|
5071
5084
|
if (!debugSpeedUp)
|
|
5072
|
-
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp
|
|
5085
|
+
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp in case of slow framerate
|
|
5073
5086
|
updateCanvas();
|
|
5074
5087
|
|
|
5075
5088
|
if (paused)
|
package/dist/littlejs.esm.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let showWatermark=0,debugKey="";const debug=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0;function ASSERT(){}function debugInit(){}function debugUpdate(){}function debugRender(){}function debugRect(){}function debugCircle(){}function debugPoint(){}function debugLine(){}function debugAABB(){}function debugText(){}function debugClear(){}function debugSaveCanvas(){}const PI=Math.PI;function abs(a){return Math.abs(a)}function min(a,b){return Math.min(a,b)}function max(a,b){return Math.max(a,b)}function sign(a){return Math.sign(a)}function mod(a,b=1){return(a%b+b)%b}function clamp(a,b=0,c=1){return a<b?b:a>c?c:a}function percent(a,b,c){return c-b?clamp((a-b)/(c-b)):0}function lerp(a,b,c){return b+clamp(a)*(c-b)}function distanceWrap(a,b,c=1){a=(a-b)%c;return 2*a%c-a}function lerpWrap(a,b,c,d=1){return c+clamp(a)*distanceWrap(b,c,d)}function distanceAngle(a,b){return distanceWrap(a,b,2*PI)}function lerpAngle(a,b,c){return lerpWrap(a,b,c,2*PI)}function smoothStep(a){return a*a*(3-2*a)}function nearestPowerOfTwo(a){return 2**Math.ceil(Math.log2(a))}function isOverlapping(a,b,c,d=vec2()){return 2*abs(a.x-c.x)<b.x+d.x&&2*abs(a.y-c.y)<b.y+d.y}function wave(a=1,b=1,c=time){return b/2*(1-Math.cos(c*a*2*PI))}function formatTime(a){return(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0)}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return Math.floor(rand(a,b))}function randSign(){return 2*randInt(2)-1}function randVector(a=1){return(new Vector2).setAngle(rand(2*PI),a)}function randInCircle(a=1,b=0){return 0<a?randVector(a*rand(b/a,1)**.5):new Vector2}function randColor(a=new Color,b=new Color(0,0,0,1),c=!1){return 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))}class RandomGenerator{constructor(a){this.seed=a}float(a=1,b=0){this.seed^=this.seed<<13;this.seed^=this.seed>>>17;this.seed^=this.seed<<5;return b+(a-b)*abs(this.seed%1e9)/1e9}int(a,b=0){return Math.floor(this.float(a,b))}sign(){return 2*this.int(2)-1}}function vec2(a=0,b){return"number"===typeof a?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y)}function isVector2(a){return a instanceof Vector2}class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}copy(){return new Vector2(this.x,this.y)}add(a){ASSERT(isVector2(a));return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){ASSERT(isVector2(a));return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){ASSERT(isVector2(a));return new Vector2(this.x*a.x,this.y*a.y)}divide(a){ASSERT(isVector2(a));return new Vector2(this.x/a.x,this.y/a.y)}scale(a){ASSERT(!isVector2(a));return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){ASSERT(isVector2(a));return this.distanceSquared(a)**.5}distanceSquared(a){ASSERT(isVector2(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(0,a)}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this}dot(a){ASSERT(isVector2(a));return this.x*a.x+this.y*a.y}cross(a){ASSERT(isVector2(a));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)}setDirection(a,b=1){ASSERT(0==a||1==a||2==a||3==a);return vec2(a%2?a-1?-b:b:0,a%2?0:a?-b: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 abs(this.x*this.y)}lerp(a,b){ASSERT(isVector2(a));return this.add(a.subtract(this).scale(clamp(b)))}arrayCheck(a){ASSERT(isVector2(a));return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}toString(a=3){if(debug)return`(${(0>this.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`}}function rgb(a,b,c,d){return new Color(a,b,c,d)}function hsl(a,b,c,d){return(new Color).setHSLA(a,b,c,d)}function isColor(a){return a instanceof Color}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){ASSERT(isColor(a));return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){ASSERT(isColor(a));return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){ASSERT(isColor(a));return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){ASSERT(isColor(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){ASSERT(isColor(a));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,k)=>(k=(k%1+1)%1)<1/6?f+6*(g-f)*k:.5>k?g:k<2/3?f+(g-f)*(2/3-k)*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}getHSLA(){const a=clamp(this.r),b=clamp(this.g),c=clamp(this.b),d=clamp(this.a),e=Math.max(a,b,c),f=Math.min(a,b,c),g=(e+f)/2;let k=0,h=0;if(e!=f){let l=e-f;h=.5<g?l/(2-e-f):l/(e+f);a==e?k=(b-c)/l+(b<c?6:0):b==e?k=(c-a)/l+2:c==e&&(k=(a-b)/l+4)}return[k/6,h,g,d]}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()}toString(a=!0){const b=c=>(16>(c=255*c|0)?"0":"")+c.toString(16);return"#"+b(this.r)+b(this.g)+b(this.b)+(a?b(this.a):"")}setHex(a){this.r=clamp(parseInt(a.slice(1,3),16)/255);this.g=clamp(parseInt(a.slice(3,5),16)/255);this.b=clamp(parseInt(a.slice(5,7),16)/255);this.a=7<a.length?clamp(parseInt(a.slice(7,9),16)/255):1;return this}rgbaInt(){const a=255*clamp(this.r)|0,b=255*clamp(this.g)<<8,c=255*clamp(this.b)<<16,d=255*clamp(this.a)<<24;return a+b+c+d}}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}toString(){if(debug)return this.isSet()?Math.abs(this.get())+" seconds "+(0>this.get()?"before":"after"):"unset"}valueOf(){return this.get()}}let cameraPos=vec2(),cameraScale=32,canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),canvasPixelated=!0,fontDefault="arial",showSplashScreen=!1,glEnable=!0,glOverlay=!0,tileSizeDefault=vec2(16),tileFixBleedScale=.1,enablePhysicsSolver=!0,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,gamepadsEnable=!0,gamepadDirectionEmulateStick=!0,inputWASDEmulateDirection=!0,touchGamepadEnable=!1,touchGamepadAnalog=!0,touchGamepadSize=99,touchGamepadAlpha=.3,vibrateEnable=!0,soundEnable=!0,soundVolume=.5,soundDefaultRange=40,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalDisplayIconSize=50,medalsPreventUnlock=!1;function setCameraPos(a){cameraPos=a}function setCameraScale(a){cameraScale=a}function setCanvasMaxSize(a){canvasMaxSize=a}function setCanvasFixedSize(a){canvasFixedSize=a}function setCanvasPixelated(a){canvasPixelated=a}function setFontDefault(a){fontDefault=a}function setShowSplashScreen(a){showSplashScreen=a}function setGlEnable(a){glEnable=a}function setGlOverlay(a){glOverlay=a}function setTileSizeDefault(a){tileSizeDefault=a}function setTileFixBleedScale(a){tileFixBleedScale=a}function setEnablePhysicsSolver(a){enablePhysicsSolver=a}function setObjectDefaultMass(a){objectDefaultMass=a}function setObjectDefaultDamping(a){objectDefaultDamping=a}function setObjectDefaultAngleDamping(a){objectDefaultAngleDamping=a}function setObjectDefaultElasticity(a){objectDefaultElasticity=a}function setObjectDefaultFriction(a){objectDefaultFriction=a}function setObjectMaxSpeed(a){objectMaxSpeed=a}function setGravity(a){gravity=a}function setParticleEmitRateScale(a){particleEmitRateScale=a}function setGamepadsEnable(a){gamepadsEnable=a}function setGamepadDirectionEmulateStick(a){gamepadDirectionEmulateStick=a}function setInputWASDEmulateDirection(a){inputWASDEmulateDirection=a}function setTouchGamepadEnable(a){touchGamepadEnable=a}function setTouchGamepadAnalog(a){touchGamepadAnalog=a}function setTouchGamepadSize(a){touchGamepadSize=a}function setTouchGamepadAlpha(a){touchGamepadAlpha=a}function setVibrateEnable(a){vibrateEnable=a}function setSoundEnable(a){soundEnable=a}function setSoundVolume(a){soundVolume=a}function setSoundDefaultRange(a){soundDefaultRange=a}function setSoundDefaultTaper(a){soundDefaultTaper=a}function setMedalDisplayTime(a){medalDisplayTime=a}function setMedalDisplaySlideTime(a){medalDisplaySlideTime=a}function setMedalDisplaySize(a){medalDisplaySize=a}function setMedalDisplayIconSize(a){medalDisplayIconSize=a}function setMedalsPreventUnlock(a){medalsPreventUnlock=a}function setShowWatermark(a){showWatermark=a}function setDebugKey(a){debugKey=a}class EngineObject{constructor(a=vec2(),b=vec2(1),c,d=0,e,f=0){ASSERT(isVector2(a)&&isVector2(b),"ensure pos and size are vec2s");ASSERT("number"!==typeof c||!c,"old style tile setup");this.pos=a.copy();this.size=b;this.drawSize=void 0;this.tileInfo=c;this.angle=d;this.color=e;this.additiveColor=void 0;this.mirror=!1;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=f;this.velocity=vec2();this.angleVelocity=0;this.spawnTime=time;this.children=[];this.parent=void 0;this.localPos=vec2();this.localAngle=0;this.isSolid=this.collideSolidObjects=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.velocity.y+=gravity*this.gravityScale,this.pos.x+=this.velocity.x*=this.damping,this.pos.y+=this.velocity.y*=this.damping,this.angle+=this.angleVelocity*=this.angleDamping,ASSERT(0<=this.angleDamping&&1>=this.angleDamping),ASSERT(0<=this.damping&&1>=this.damping),enablePhysicsSolver&&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)continue;if(!isOverlapping(this.pos,this.size,d.pos,d.size))continue;c=this.collideWithObject(d);var e=d.collideWithObject(this);if(!c||!e)continue;if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);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));debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f00");continue}e=this.size.add(d.size);var f=2*(a.y-d.pos.y)>e.y+gravity;const k=2*abs(a.y-d.pos.y)<e.y;var g=2*abs(a.x-d.pos.x)<e.x;c=max(this.elasticity,d.elasticity);if(f||g||!k)if(this.pos.y=d.pos.y+(e.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-c;else if(d.mass){g=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass);const h=d.velocity.y*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.y*this.mass/(this.mass+d.mass);this.velocity.y=lerp(c,g,this.velocity.y*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.y*d.mass/(this.mass+d.mass));d.velocity.y=lerp(c,g,h)}!f&&k&&(this.pos.x=d.pos.x+(e.x/2+.001)*sign(a.x-d.pos.x),d.mass?(e=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(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),this.velocity.x=lerp(c,e,this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass)),d.velocity.x=lerp(c,e,f)):this.velocity.x*=-c);debugOverlay&&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(vec2(a.x,this.pos.y),this.size,this);d=tileCollisionTest(vec2(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.tileInfo,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!0}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=!0){ASSERT(a||!b,"solid objects must be set to collide");this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c}toString(){if(debug){let a="type = "+this.constructor.name;if(this.pos.x||this.pos.y)a+="\npos = "+this.pos;if(this.velocity.x||this.velocity.y)a+="\nvelocity = "+this.velocity;if(this.size.x||this.size.y)a+="\nsize = "+this.size;this.angle&&(a+="\nangle = "+this.angle.toFixed(3));this.color&&(a+="\ncolor = "+this.color);return a}}}let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2(),textureInfos=[],drawCount;function tile(a=vec2(),b=tileSizeDefault,c=0){"number"===typeof b&&(ASSERT(0<b),b=vec2(b));if("number"===typeof a){var d=textureInfos[c];ASSERT(d,"Texture not loaded");d=d.size.x/b.x|0;a=vec2(a%d*b.x,(a/d|0)*b.y)}return new TileInfo(a,b,c)}class TileInfo{constructor(a=vec2(),b=tileSizeDefault,c=0){this.pos=a;this.size=b;this.textureIndex=c}offset(a){return new TileInfo(this.pos.add(a),this.size,this.textureIndex)}getTextureInfo(){return textureInfos[this.textureIndex]}}class TextureInfo{constructor(a){this.image=a;this.size=vec2(a.width,a.height);this.glTexture=glEnable&&glCreateTexture(a);this.fixBleedSize=vec2(tileFixBleedScale).divide(this.size)}}function screenToWorld(a){return new Vector2((a.x-mainCanvasSize.x/2+.5)/cameraScale+cameraPos.x,(a.y-mainCanvasSize.y/2+.5)/-cameraScale+cameraPos.y)}function worldToScreen(a){return new Vector2((a.x-cameraPos.x)*cameraScale+mainCanvasSize.x/2-.5,(a.y-cameraPos.y)*-cameraScale+mainCanvasSize.y/2-.5)}function getCameraSize(){return mainCanvasSize.scale(1/cameraScale)}function drawTile(a,b=vec2(1),c,d=new Color,e=0,f,g=new Color(0,0,0,0),k=glEnable,h,l){ASSERT(!l||!k,"context only supported in canvas 2D mode");ASSERT("number"!==typeof c||!c,"this is an old style calls, to fix replace it with tile(tileIndex, tileSize)");const n=c&&c.getTextureInfo();if(k)if(h&&(a=screenToWorld(a),b=b.scale(1/cameraScale)),n){k=c.pos.x/n.size.x;h=c.pos.y/n.size.y;l=c.size.x/n.size.x;const m=c.size.y/n.size.y,p=n.fixBleedSize;glSetTexture(n.glTexture);glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,k+p.x,h+p.y,k-p.x+l,h-p.y+m,d.rgbaInt(),g.rgbaInt())}else glDraw(a.x,a.y,b.x,b.y,e,0,0,0,0,0,d.rgbaInt());else showWatermark&&++drawCount,drawCanvas2D(a,b,e,f,m=>{if(n){const p=c.pos.x+tileFixBleedScale,t=c.pos.y+tileFixBleedScale,u=c.size.x-2*tileFixBleedScale,x=c.size.y-2*tileFixBleedScale;m.globalAlpha=d.a;m.drawImage(n.image,p,t,u,x,-.5,-.5,1,1);m.globalAlpha=1}else m.fillStyle=d,m.fillRect(-.5,-.5,1,1)},h,l)}function drawRect(a,b,c,d,e,f,g){drawTile(a,b,void 0,c,d,!1,void 0,e,f,g)}function drawPoly(a,b=new Color,c,d=mainContext){d.fillStyle=b.toString();d.beginPath();for(const e of c?a:a.map(worldToScreen))d.lineTo(e.x,e.y);d.fill()}function drawLine(a,b,c=.1,d,e,f,g){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(),e,f,g)}function drawCanvas2D(a,b,c,d,e,f,g=mainContext){f||(a=worldToScreen(a),b=b.scale(cameraScale));g.save();g.translate(a.x+.5,a.y+.5);g.rotate(c);g.scale(d?-b.x:b.x,b.y);e(g);g.restore()}function setBlendMode(a,b=glEnable,c){ASSERT(!c||!b,"context only supported in canvas 2D mode");b?glAdditive=a:(c||=mainContext,c.globalCompositeOperation=a?"lighter":"source-over")}function drawText(a,b,c=1,d,e=0,f,g,k,h){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,k,h)}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",k=fontDefault,h=overlayContext){h.fillStyle=d.toString();h.lineWidth=e;h.strokeStyle=f.toString();h.textAlign=g;h.font=c+"px "+k;h.textBaseline="middle";h.lineJoin="round";b=b.copy();(a+"").split("\n").forEach(l=>{e&&h.strokeText(l,b.x,b.y);h.fillText(l,b.x,b.y);b.y+=c})}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=overlayContext){engineFontImage||((engineFontImage=new Image).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.context=d}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!canvasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),k=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((h,l)=>{const n=d?h.length*f.x*c/2|0:0;for(let t=h.length;t--;){var m=h[t].charCodeAt(0);if(32>m||127<m)m=127;var p=m-32;m=p%k;p=p/k|0;const u=b.add(vec2(t,l).multiply(g));e.drawImage(this.image,m*f.x,p*f.y,f.x,f.y,u.x-n,u.y,f.x*c,f.y*c)}});e.restore()}}function isFullscreen(){return!!document.fullscreenElement}function toggleFullscreen(){isFullscreen()?document.exitFullscreen&&document.exitFullscreen():document.body.requestFullscreen&&document.body.requestFullscreen()}function keyIsDown(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&1)}function keyWasPressed(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&2)}function keyWasReleased(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&4)}function clearInput(){inputData=[[]]}const mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=!1,preventDefaultInput=!1;function gamepadIsDown(a,b=0){return keyIsDown(a,b+1)}function gamepadWasPressed(a,b=0){return keyWasPressed(a,b+1)}function gamepadWasReleased(a,b=0){return keyWasReleased(a,b+1)}function gamepadStick(a,b=0){return stickData[b]?stickData[b][a]||vec2():vec2()}let inputData=[[]];function inputUpdate(){isTouchDevice||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||(isUsingGamepad=!1,inputData[0][a.code]=3,inputWASDEmulateDirection&&(inputData[0][remapKey(a.code)]=3)),preventDefaultInput&&a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][a.code]=4,inputWASDEmulateDirection&&(inputData[0][remapKey(a.code)]=4))};function remapKey(a){return inputWASDEmulateDirection?"KeyW"==a?"ArrowUp":"KeyS"==a?"ArrowDown":"KeyA"==a?"ArrowLeft":"KeyD"==a?"ArrowRight":a:a}onmousedown=a=>{isUsingGamepad=!1;inputData[0][a.button]=3;mousePosScreen=mouseToScreen(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>mouseWheel=a.ctrlKey?0:sign(a.deltaY);oncontextmenu=a=>!1;function mouseToScreen(a){if(!mainCanvas)return vec2();const b=mainCanvas.getBoundingClientRect();return vec2(mainCanvas.width,mainCanvas.height).multiply(vec2(percent(a.x,b.left,b.right),percent(a.y,b.top,b.bottom)))}const stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&isTouchDevice&&(touchGamepadButtons||createTouchGamepad(),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]?gamepadIsDown(c,0)?1:3:gamepadIsDown(c,0)?4:0}}if(gamepadsEnable&&navigator&&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=k=>.3<k?percent(k,.3,.8):-.3>k?-percent(-k,.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];const k=gamepadIsDown(e,b);g[e]=f.pressed?k?1:3:k?4:0;isUsingGamepad||=!b&&f.pressed}gamepadDirectionEmulateStick&&(d=vec2((gamepadIsDown(15,b)&&1)-(gamepadIsDown(14,b)&&1),(gamepadIsDown(12,b)&&1)-(gamepadIsDown(13,b)&&1)),d.lengthSquared()&&(c[0]=d.clampLength()));touchGamepadEnable&&isUsingGamepad&&touchGamepadTimer.unset()}}}function vibrate(a=100){vibrateEnable&&navigator&&navigator.vibrate&&navigator.vibrate(a)}function vibrateStop(){vibrate(0)}const isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a;onmousedown=onmouseup=()=>0;ontouchstart=ontouchmove=ontouchend=b=>{soundEnable&&audioContext&&"running"!=audioContext.state&&zzfx(0);const c=b.touches.length;if(c){const d=vec2(b.touches[0].clientX,b.touches[0].clientY);mousePosScreen=mouseToScreen(d);a?isUsingGamepad=!1:inputData[0][0]=3}else a&&(inputData[0][0]=inputData[0][0]&2|4);a=c;document.hasFocus()&&b.preventDefault();return!0}}let touchGamepadTimer=new Timer,touchGamepadButtons,touchGamepadStick;function createTouchGamepad(){touchGamepadButtons=[];touchGamepadStick=vec2();const a=ontouchstart;ontouchstart=ontouchmove=ontouchend=b=>{touchGamepadStick=vec2();touchGamepadButtons=[];if(b.touches.length&&(touchGamepadTimer.set(),paused)){touchGamepadButtons[9]=1;return}const c=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),d=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),e=mainCanvasSize.scale(.5);for(const g of b.touches){var f=mouseToScreen(vec2(g.clientX,g.clientY));f.distance(c)<touchGamepadSize?touchGamepadAnalog?touchGamepadStick=f.subtract(c).scale(2/touchGamepadSize).clampLength():(f=f.subtract(c).angle(),touchGamepadStick.setAngle((4*f/PI+8.5|0)*PI/4)):f.distance(d)<touchGamepadSize?(f=f.subtract(d).direction(),touchGamepadButtons[f]=1):f.distance(e)<touchGamepadSize&&(touchGamepadButtons[9]=1)}a.bind(window)(b);return isUsingGamepad=!0}}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(vec2().setDirection(b,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()}}}class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=0,a&&(this.randomness=a[1]||0,a[1]=0,this.sampleChannels=[zzfxG(...a)],this.sampleRate=zzfxR))}play(a,b=1,c=1,d=1,e=!1){if(soundEnable&&this.sampleChannels){var f;if(a){if(f=this.range){const g=cameraPos.distanceSquared(a);if(g>f*f)return;b*=percent(g**.5,f,f*this.taper)}f=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return this.source=playSamples(this.sampleChannels,b,a,f,e,this.sampleRate)}}stop(){this.source&&this.source.stop();this.source=void 0}getSource(){return this.source}playNote(a,b,c){return this.play(b,c,2**(a/12),0)}getDuration(){return this.sampleChannels&&this.sampleChannels[0].length/this.sampleRate}isLoading(){return!this.sampleChannels}}class SoundWave extends Sound{constructor(a,b=0,c,d){super(void 0,c,d);this.randomness=b;soundEnable&&fetch(a).then(e=>e.arrayBuffer()).then(e=>audioContext.decodeAudioData(e)).then(e=>{this.sampleChannels=[];for(let f=e.numberOfChannels;f--;)this.sampleChannels[f]=Array.from(e.getChannelData(f));this.sampleRate=e.sampleRate})}}class Music extends Sound{constructor(a){super(void 0);soundEnable&&(this.randomness=0,this.sampleChannels=zzfxM(...a),this.sampleRate=zzfxR)}playMusic(a,b=!1){return super.play(void 0,a,1,1,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}function speakStop(){speechSynthesis&&speechSynthesis.cancel()}function getNoteFrequency(a,b=220){return b*2**(a/12)}let audioContext=new AudioContext,audioSuspended=!1;function playSamples(a,b=1,c=1,d=0,e=!1,f=zzfxR){if(soundEnable){var g=audioSuspended;if(audioSuspended="running"!=audioContext.state)if(audioContext.resume(),g)return;var k=audioContext.createBuffer(a.length,a[0].length,f);f=audioContext.createBufferSource();a.forEach((h,l)=>k.getChannelData(l).set(h));f.buffer=k;f.playbackRate.value=c;f.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);f.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})).connect(a);f.start();return f}}function zzfx(...a){return playSamples([zzfxG(...a)])}const zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,k=1,h=0,l=0,n=0,m=0,p=0,t=0,u=0,x=0,v=0,D=1,z=0,E=0,A=0){let w=2*PI;var q=zzfxR;let F=h*=500*w/q/q;b=c*=rand(1+b,1-b)*w/q;let C=[],y=0,G=0,r=0,H=1,R=0,S=0,B=0,J;var L=w*abs(A)*2/q,K=Math.cos(L),M=Math.sin(L)/2/2,I=1+M;L=-2*K/I;M=(1-M)/I;let N=(1+sign(A)*K)/2/I;K=-(sign(A)+K)/I;let O=I=0,P=0,Q=0;d=d*q+9;z*=q;e*=q;f*=q;v*=q;l*=500*w/q**3;u*=w/q;n*=w/q;m*=q;p=p*q|0;a*=soundVolume;for(J=d+z+e+f+v|0;r<J;C[r++]=B*a)++S%(100*x|0)||(B=g?1<g?2<g?3<g?Math.sin(y**3):clamp(Math.tan(y),1,-1):1-(2*y/w%2+2)%2:1-4*abs(Math.round(y/w)-y/w):Math.sin(y),B=(p?1-E+E*Math.sin(w*r/p):1)*sign(B)*abs(B)**k*(r<d?r/d:r<d+z?1-(r-d)/z*(1-D):r<d+z+e?D:r<J-v?(J-r-v)/f*D:0),B=v?B/2+(v>r?0:(r<J-v?1:(J-r)/v)*C[r-v|0]/2/a):B,A&&(B=Q=N*I+K*(I=O)+N*(O=B)-M*P-L*(P=Q))),q=(c+=h+=l)*Math.cos(u*G++),y+=q+q*t*Math.sin(r**5),H&&++H>m&&(c+=n,b+=n,H=0),!p||++R%p||(c=b,h=F,H=H||1);return C}function zzfxM(a,b,c,d=125){let e,f,g,k,h,l,n,m,p,t,u,x,v,D=0,z,E=[],A=[],w=[],q=0,F=0,C=1,y={},G=zzfxR/d*60>>2;for(;C;q++)E=[C=m=x=0],c.forEach((r,H)=>{n=b[r][q]||[0,0,0];C|=b[r][q]&&1;z=x+(b[r][0].length-2-(m?0:1))*G;v=H==c.length-1;e=2;for(g=x;e<n.length+v;m=++e){h=n[e];p=e==n.length+v-1&&v||t!=(n[0]||0)||h|0;for(f=0;f<G&&m;f++>G-99&&p&&1>u?u+=1/99:0)l=(1-u)*E[D++]/2||0,A[g]=(A[g]||0)-l*F+l,w[g]=(w[g++]||0)+l*F+l;h&&(u=h%1,F=n[1]||0,h|=0)&&(E=y[[t=n[D=0]||0,h]]=y[[t,h]]||(k=[...a[t]],k[2]*=2**((h-12)/12),0<h?zzfxG(...k):[]))}x=z});return[A,w]}let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}function setTileCollisionData(a,b=0){a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b)}function getTileCollisionData(a){return 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,vec2(b,e))))return!0}}function tileCollisionRaycast(a,b,c){const d=b.subtract(a),e=d.length();var f=d.normalize();f=vec2(abs(1/f.x),abs(1/f.y));let g=a.floor(),k=f.x*(0>d.x?a.x-g.x:g.x-a.x+1),h=f.y*(0>d.y?a.y-g.y:g.y-a.y+1);for(;;){const l=getTileCollisionData(g);if(l&&(!c||c.collideWithTile(l,g)))return debugRaycast&&debugLine(a,b,"#f00",.02),debugRaycast&&debugPoint(g.add(vec2(.5)),"#ff0"),g.add(vec2(.5));if(k>e&&h>e)break;k>h?(g.y+=sign(d.y),h+=f.y):(g.x+=sign(d.x),k+=f.x)}debugRaycast&&debugLine(a,b,"#00f",.02)}class TileLayerData{constructor(a,b=0,c=!1,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=0;this.mirror=!1;this.color=new Color}}class TileLayer extends EngineObject{constructor(a,b=tileCollisionSize,c=tile(),d=vec2(1),e=0){super(a,b,c,0,void 0,e);this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.scale=d;this.isOverlay=!1;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c=!1){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,"must call redrawEnd() after drawing tiles");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(!0);for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b),!1);this.redrawEnd()}redrawStart(a=!1){this.savedRenderSettings=[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;mainCanvasSize=this.size.multiply(this.tileInfo.size);cameraPos=this.size.scale(.5);cameraScale=this.tileInfo.size.x;a&&(mainCanvas.width=mainCanvasSize.x,mainCanvas.height=mainCanvasSize.y);enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context,"must call redrawStart() before drawing tiles");glEnable&&glCopyToContext(mainContext,!0);[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a,b=!0){var c=this.tileInfo.size;b&&(b=a.multiply(c),this.context.clearRect(b.x,this.canvas.height-b.y,c.x,-c.y));b=this.getData(a);void 0!=b.tile&&(a=this.pos.add(a).add(vec2(.5)),ASSERT(mainContext==this.context,"must call redrawStart() before drawing tiles"),c=tile(b.tile,c,this.tileInfo.textureIndex),drawTile(a,vec2(1),c,b.color,b.direction*PI/2,b.mirror))}drawCanvas2D(a,b,c,d,e){const f=this.context;f.save();a=a.subtract(this.pos).multiply(this.tileInfo.size);b=b.multiply(this.tileInfo.size);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,d=new Color,e,f){this.drawCanvas2D(a,b,e,f,g=>{const k=c&&c.getTextureInfo();k?(g.globalAlpha=d.a,g.drawImage(k.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1),g.globalAlpha=1):(g.fillStyle=d,g.fillRect(-.5,-.5,1,1))})}drawRect(a,b,c,d){this.drawTile(a,b,void 0,c,d)}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,k=new Color,h=new Color,l=new Color(1,1,1,0),n=new Color(1,1,1,0),m=.5,p=.1,t=1,u=.1,x=.05,v=1,D=1,z=0,E=PI,A=.1,w=.2,q=!1,F=!1,C=!0,y=F?1e9:0,G=!1){super(a,vec2(),g,b,void 0,y);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=k;this.colorStartB=h;this.colorEndA=l;this.colorEndB=n;this.randomColorLinear=C;this.particleTime=m;this.sizeStart=p;this.sizeEnd=t;this.speed=u;this.angleSpeed=x;this.damping=v;this.angleDamping=D;this.gravityScale=z;this.particleConeAngle=E;this.fadeRate=A;this.randomness=w;this.collideTiles=q;this.additive=F;this.localSpace=G;this.trailScale=0;this.particleCreateCallback=this.particleDestroyCallback=void 0;this.emitTimeBuffer=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="number"===typeof this.emitSize?randInCircle(this.emitSize/2):vec2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle);let b=rand(this.particleConeAngle,-this.particleConeAngle);this.localSpace||(a=this.pos.add(a),b+=this.angle);const c=this.randomness;var d=m=>m+m*rand(c,-c);const e=d(this.particleTime),f=d(this.sizeStart),g=d(this.sizeEnd),k=d(this.speed);d=d(this.angleSpeed)*randSign();var h=rand(this.emitConeAngle,-this.emitConeAngle);const l=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),n=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);h=this.localSpace?h:this.angle+h;a=new Particle(a,this.tileInfo,b,l,n,e,f,g,this.fadeRate,this.additive,this.trailScale,this.localSpace&&this,this.particleDestroyCallback);a.velocity=vec2().setAngle(h,k);a.angleVelocity=d;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.renderOrder=this.renderOrder;a.mirror=!!randInt(2);this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d,e,f,g,k,h,l,n,m,p){super(a,vec2(),b,c);this.colorStart=d;this.colorEndDelta=e.subtract(d);this.lifeTime=f;this.sizeStart=g;this.sizeEndDelta=k-g;this.fadeRate=h;this.additive=l;this.trailScale=n;this.localSpaceEmitter=m;this.destroyCallback=p}render(){const a=min((time-this.spawnTime)/this.lifeTime,1),b=vec2(this.sizeStart+a*this.sizeEndDelta);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(!0);let d=this.pos,e=this.angle;this.localSpaceEmitter&&(d=this.localSpaceEmitter.pos.add(d.rotate(-this.localSpaceEmitter.angle)),e+=this.localSpaceEmitter.angle);if(this.trailScale){var f=this.velocity;this.localSpaceEmitter&&(f=f.rotate(-this.localSpaceEmitter.angle));var g=f.length();g&&(f=f.scale(1/g),g*=this.trailScale,b.y=max(b.x,g),e=f.angle(),drawTile(d.add(f.multiply(vec2(0,-g/2))),b,this.tileInfo,c,e,this.mirror))}else drawTile(d,b,this.tileInfo,c,e,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(d,b,"#f005",0,e);1==a&&(this.color=c,this.size=b,this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}}const medals=[];let medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast;function medalsInit(a){medalsSaveName=a;debugMedals||medals.forEach(b=>b.unlocked=localStorage[b.storageKey()]|0)}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;e&&((this.image=new Image).src=e)}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName,"save name must be set"),localStorage[this.storageKey()]=this.unlocked=1,medalsDisplayQueue.push(this),newgrounds&&newgrounds.unlockMedal(this.id))}render(a=0){const b=overlayContext;var c=min(medalDisplaySize.x,mainCanvas.width);const d=overlayCanvas.width-c;a*=-medalDisplaySize.y;b.save();b.beginPath();b.fillStyle=new Color(.9,.9,.9).toString();b.strokeStyle=new Color(0,0,0).toString();b.lineWidth=3;b.rect(d,a,c,medalDisplaySize.y);b.fill();b.stroke();b.clip();this.renderIcon(vec2(d+15+medalDisplayIconSize/2,a+medalDisplaySize.y/2));c=vec2(d+medalDisplayIconSize+30,a+28);drawTextScreen(this.name,c,38,new Color(0,0,0),0,void 0,"left");c.y+=32;drawTextScreen(this.description,c,24,new Color(0,0,0),0,void 0,"left");b.restore()}renderIcon(a,b=medalDisplayIconSize){this.image?overlayContext.drawImage(this.image,a.x-b/2,a.y-b/2,b,b):drawTextScreen(this.icon,a,.7*b,new Color(0,0,0))}storageKey(){return medalsSaveName+"_"+this.id}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayTimeLast=0,medalsDisplayQueue.shift();else{const c=medalDisplayTime-medalDisplaySlideTime;a.render(b<medalDisplaySlideTime?1-b/medalDisplaySlideTime:b>c?(b-c)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}}let newgrounds;function newgroundsInit(a,b,c){newgrounds=new Newgrounds(a,b,c)}class Newgrounds{constructor(a,b,c){ASSERT(!newgrounds&&0<a,"there can only be one newgrounds object");ASSERT(!b||c,"must provide cryptojs if there is a cipher");this.app_id=a;this.cipher=b;this.cryptoJS=c;this.host=location?location.hostname:"";if(this.session_id=new URL(location.href).searchParams.get("ngio_session_id")){this.medals=(a=this.call("Medal.getList"))?a.result.data.medals:[];debugMedals&&console.log(this.medals);for(var d of this.medals)if(a=medals[d.id])a.image=new Image,a.image.src=d.icon,a.name=d.name,a.description=d.description,a.unlocked=d.unlocked,a.difficulty=d.difficulty,a.value=d.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(d=this.call("ScoreBoard.getBoards"))?d.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards);setInterval(()=>this.call("Gateway.ping",0,!0),3e5)}}unlockMedal(a){return this.call("Medal.unlock",{id:a},!0)}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b},!0)}getScores(a,b,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},!0)}call(a,b,c=!1){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)}}let glCanvas,glContext,glShader,glActiveTexture,glArrayBuffer,glGeometryBuffer,glPositionData,glColorData,glInstanceCount,glAdditive,glBatchAdditive;function glInit(){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl2");glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 m;in vec2 g;in vec4 p,u,c,a;in float r;out vec2 v;out vec4 d,e;void main(){vec2 s=(g-.5)*p.zw;gl_Position=m*vec4(p.xy+s*cos(r)-vec2(-s.y,s)*sin(r),1,1);v=mix(u.xw,u.zy,g);d=c;e=a;}","#version 300 es\nprecision highp float;in vec2 v;in vec4 d,e;uniform sampler2D s;out vec4 c;void main(){c=texture(s,v)*d+e;}");var a=new ArrayBuffer(gl_INSTANCE_BUFFER_SIZE);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glArrayBuffer=glContext.createBuffer();glGeometryBuffer=glContext.createBuffer();a=new Float32Array([glInstanceCount=0,0,1,0,0,1,1,1]);glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);glContext.bufferData(gl_ARRAY_BUFFER,a,gl_STATIC_DRAW)}function glPreRender(){glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glContext.clear(gl_COLOR_BUFFER_BIT);glContext.useProgram(glShader);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=textureInfos[0].glTexture);let a=glAdditive=glBatchAdditive=0;var b=(d,e,f,g)=>{d=glContext.getAttribLocation(glShader,d);const k=f&&gl_INSTANCE_BYTE_STRIDE,h=f&&1,l=1==f;glContext.enableVertexAttribArray(d);glContext.vertexAttribPointer(d,g,e,l,k,a);glContext.vertexAttribDivisor(d,h);a+=g*f};glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);b("g",gl_FLOAT,0,2);glContext.bindBuffer(gl_ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,gl_INSTANCE_BUFFER_SIZE,gl_DYNAMIC_DRAW);b("p",gl_FLOAT,4,4);b("u",gl_FLOAT,4,4);b("c",gl_UNSIGNED_BYTE,1,4);b("a",gl_UNSIGNED_BYTE,1,4);b("r",gl_FLOAT,4,1);b=vec2(2*cameraScale).divide(mainCanvasSize);const c=vec2(-1).subtract(cameraPos.multiply(b));glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),!1,new Float32Array([b.x,0,0,0,0,b.y,0,0,1,1,1,1,c.x,c.y,0,0]))}function glSetTexture(a){a!=glActiveTexture&&(glFlush(),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=a))}function glCompileShader(a,b){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){const 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 glCreateTexture(a){const b=glContext.createTexture();glContext.bindTexture(gl_TEXTURE_2D,b);a&&glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,a);a=canvasPixelated?gl_NEAREST:gl_LINEAR;glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MIN_FILTER,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MAG_FILTER,a);return b}function glFlush(){if(glInstanceCount){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);glContext.drawArraysInstanced(gl_TRIANGLE_STRIP,0,4,glInstanceCount);showWatermark&&(drawCount+=glInstanceCount);glInstanceCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b=!1){if(glInstanceCount||b)glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0)}function glDraw(a,b,c,d,e,f,g,k,h,l,n=0){ASSERT("number"==typeof l&&"number"==typeof n,"invalid color");(glInstanceCount>=gl_MAX_INSTANCES||glBatchAdditive!=glAdditive)&&glFlush();let m=glInstanceCount*gl_INDICIES_PER_INSTANCE;glPositionData[m++]=a;glPositionData[m++]=b;glPositionData[m++]=c;glPositionData[m++]=d;glPositionData[m++]=f;glPositionData[m++]=g;glPositionData[m++]=k;glPositionData[m++]=h;glColorData[m++]=l;glColorData[m++]=n;glPositionData[m++]=e;glInstanceCount++}let glPostShader,glPostTexture,glPostIncludeOverlay;function glInitPostProcess(a,b=!1){ASSERT(!glPostShader,"can only have 1 post effects shader");a||="void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}";glPostShader=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;void main(){gl_Position=vec4(p+p-1.,1,1);}","#version 300 es\nprecision highp float;uniform sampler2D iChannel0;uniform vec3 iResolution;uniform float iTime;out vec4 c;\n"+a+"\nvoid main(){mainImage(c,gl_FragCoord.xy);c.a=1.;}");glPostTexture=glCreateTexture(void 0);glPostIncludeOverlay=b;mainCanvas.style.visibility="hidden";glPostIncludeOverlay&&(overlayCanvas.style.visibility="hidden")}function glRenderPostProcess(){if(glPostShader){glEnable?(glFlush(),mainContext.drawImage(glCanvas,0,0)):glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glPostIncludeOverlay&&mainContext.drawImage(overlayCanvas,0,0);glContext.useProgram(glPostShader);glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL,1);glContext.disable(gl_BLEND);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glPostTexture);glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,mainCanvas);var a=glContext.getAttribLocation(glPostShader,"p");glContext.enableVertexAttribArray(a);glContext.vertexAttribPointer(a,2,gl_FLOAT,!1,8,0);glContext.uniform1i(glContext.getUniformLocation(glPostShader,"iChannel0"),0);glContext.uniform1f(glContext.getUniformLocation(glPostShader,"iTime"),time);glContext.uniform3f(glContext.getUniformLocation(glPostShader,"iResolution"),mainCanvas.width,mainCanvas.height,1);glContext.drawArrays(gl_TRIANGLE_STRIP,0,4)}}const gl_ONE=1,gl_TRIANGLE_STRIP=5,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_COLOR_BUFFER_BIT=16384,gl_TEXTURE0=33984,gl_ARRAY_BUFFER=34962,gl_STATIC_DRAW=35044,gl_DYNAMIC_DRAW=35048,gl_FRAGMENT_SHADER=35632,gl_VERTEX_SHADER=35633,gl_COMPILE_STATUS=35713,gl_LINK_STATUS=35714,gl_UNPACK_FLIP_Y_WEBGL=37440,gl_INDICIES_PER_INSTANCE=11,gl_MAX_INSTANCES=1e4,gl_INSTANCE_BYTE_STRIDE=4*gl_INDICIES_PER_INSTANCE,gl_INSTANCE_BUFFER_SIZE=gl_MAX_INSTANCES*gl_INSTANCE_BYTE_STRIDE,engineName="LittleJS",engineVersion="1.9.3",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=!1;function setPaused(a){paused=a}let frameTimeLastMS=0,frameTimeBufferMS=0,averageFPS=0;function engineInit(a,b,c,d,e,f=["tiles.png"]){function g(h=0){var l=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS,1e3/(l||1));h=debug&&keyIsDown("Equal");const n=debug&&keyIsDown("Minus");debug&&(l*=h?5:n?.2:1);timeReal+=l/1e3;frameTimeBufferMS+=paused?0:l;h||(frameTimeBufferMS=min(frameTimeBufferMS,50));k();if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{l=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(l=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=l}enginePreRender();d();engineObjects.sort((p,t)=>p.renderOrder-t.renderOrder);for(var m of engineObjects)m.destroyed||m.render();e();glRenderPostProcess();medalsRender();touchGamepadRender();debugRender();glEnable&&glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",m=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(m,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(m,mainCanvas.width-2,2),drawCount=0);requestAnimationFrame(g)}function k(){if(canvasFixedSize.x){mainCanvas.width=canvasFixedSize.x;mainCanvas.height=canvasFixedSize.y;const h=innerWidth/innerHeight,l=mainCanvas.width/mainCanvas.height;(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=h<l?"100%":"";(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=h<l?"":"100%"}else mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y);overlayCanvas.width=mainCanvas.width;overlayCanvas.height=mainCanvas.height;mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height)}ASSERT(Array.isArray(f),"pass in images as array");document.body.style.cssText="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none";document.body.appendChild(mainCanvas=document.createElement("canvas"));mainContext=mainCanvas.getContext("2d");debugInit();glEnable&&glInit();document.body.appendChild(overlayCanvas=document.createElement("canvas"));overlayContext=overlayCanvas.getContext("2d");(glCanvas||mainCanvas).style.cssText=mainCanvas.style.cssText=overlayCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";k();f=f.map((h,l)=>new Promise(n=>{const m=new Image;m.onerror=m.onload=()=>{textureInfos[l]=new TextureInfo(m);n()};m.src=h}));showSplashScreen&&f.push(new Promise(h=>{function l(){clearInput();drawEngineSplashScreen(n+=.01);1<n?h():setTimeout(l,16)}let n=0;console.log(`${engineName} Engine v${engineVersion}`);l()}));Promise.all(f).then(()=>{a();g()})}function enginePreRender(){mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.imageSmoothingEnabled=!canvasPixelated;glEnable&&glPreRender()}function engineObjectsUpdate(){function a(b){if(!b.destroyed){b.update();for(const c of b.children)a(c)}}engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed)}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("object"===typeof b)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)}function drawEngineSplashScreen(a){const b=overlayContext;var c=overlayCanvas.width=innerWidth,d=overlayCanvas.height=innerHeight,e=percent(a,1,.8),f=percent(a,0,.5),g=b.createRadialGradient(c/2,d/2,0,c/2,d/2,.7*Math.hypot(c,d));g.addColorStop(0,hsl(0,0,lerp(f,0,e/2),e).toString());g.addColorStop(1,hsl(0,0,0,e).toString());b.save();b.fillStyle=g;b.fillRect(0,0,c,d);g=(h,l,n,m,p)=>{b.beginPath();b.rect(h,l,n,p?m*k:m);(b.fillStyle=p)?b.fill():b.stroke()};f=(h,l,n,m=0,p=2*PI,t,u)=>{const x=(m+p)/2;m=k*(p-m)/2;b.beginPath();u&&b.lineTo(h,l);b.arc(h,l,n,x-m,x+m);(b.fillStyle=t)?b.fill():b.stroke()};e=(h=0,l=0)=>hsl([.98,.3,.57,.14][h%4]-10,.8,[0,.3,.5,.8,.9][l]).toString();a=wave(1,1,a);const k=percent(a,.1,.5);b.translate(c/2,d/2);c=min(6,min(c,d)/99);b.scale(c,c);b.translate(-40,-35);b.lineJoin=b.lineCap="round";b.lineWidth=.1+1.9*k;c=percent(a,.1,1);b.setLineDash([99*c,99]);g(7,17,18,-8,e(2,2));g(7,9,18,4,e(2,3));g(25,9,8,8,e(2,1));g(25,9,-18,8);g(25,9,8,8);g(25,17,7,22,e());g(11,40,14,-23,e(1,1));g(11,17,14,17,e(1,2));g(11,17,14,9,e(1,3));g(15,31,6,-9,e(2,2));f(15,23,5,0,PI/2,e(2,4),1);g(25,17,-14,23);g(21,22,-6,9);g(37,14,9,6,e(3,2));g(37,14,4.5,6,e(3,3));g(37,14,9,6);g(50,20,10,-10,e(0,1));g(50,20,6.5,-10,e(0,2));g(50,20,3.5,-10,e(0,3));g(50,20,10,-10);f(55,2,11.4,.5,PI-.5,e(3,3));f(55,2,11.4,.5,PI/2,e(3,2),1);f(55,2,11.4,.5,PI-.5);g(45,7,20,-7,e(0,2));g(45,0,20,3,e(0,3));g(45,0,20,7);for(c=5;c--;)f(60-6*c,30,9.9,0,2*PI,e(c+2,3)),f(60-6*c,30,10,-.5,PI+.5,e(c+2,2)),f(60-6*c,30,10.1,.5,PI-.5,e(c+2,1));f(36,30,10,PI/2,3*PI/2);f(48,30,10,PI/2,3*PI/2);f(60,30,10);b.beginPath();b.lineTo(36,20);b.lineTo(60,20);b.stroke();f(60,30,4,PI,3*PI,e(3,2));f(60,30,4,PI,2*PI,e(3,3));f(60,30,4,PI,3*PI);for(c=6;c--;)b.beginPath(),b.lineTo(53,54),b.lineTo(53,40),b.lineTo(53+(1+2.9*c)*k,40),b.lineTo(53+(4+3.5*c)*k,54),b.fillStyle=e(0,c%2+2),b.fill(),c%2&&b.stroke();g(6,40,5,5);g(6,40,5,5,e());g(15,54,38,-14,e());for(g=3;g--;)for(c=2;c--;)f(15*g+15,47,c?7:1,PI,3*PI,e(g,3)),b.stroke(),f(15*g+15,47,c?7:1,0,PI,e(g,2)),b.stroke();b.beginPath();b.lineTo(6,40);b.lineTo(68,40);b.stroke();b.beginPath();b.lineTo(77,54);b.lineTo(4,54);b.stroke();f=engineName;b.font="900 16px arial";b.textAlign="center";b.textBaseline="top";b.lineWidth=.1+3.9*k;g=0;for(c=0;c<f.length;++c)g+=b.measureText(f[c]).width;for(c=2;c--;)for(let h=0,l=41-g/2;h<f.length;++h)b.fillStyle=e(h,2),d=b.measureText(f[h]).width,b[c?"strokeText":"fillText"](f[h],l+d/2,55.5,17*k),l+=d;b.restore()}export{engineName,engineVersion,frameRate,timeDelta,engineObjects,frame,time,timeReal,paused,setPaused,engineInit,engineObjectsUpdate,engineObjectsDestroy,engineObjectsCallback,debug,debugOverlay,showWatermark,ASSERT,debugRect,debugCircle,debugPoint,debugLine,debugAABB,debugText,debugClear,debugSaveCanvas,cameraPos,cameraScale,canvasMaxSize,canvasFixedSize,canvasPixelated,fontDefault,showSplashScreen,tileSizeDefault,tileFixBleedScale,enablePhysicsSolver,objectDefaultMass,objectDefaultDamping,objectDefaultAngleDamping,objectDefaultElasticity,objectDefaultFriction,objectMaxSpeed,gravity,particleEmitRateScale,glEnable,glOverlay,gamepadsEnable,gamepadDirectionEmulateStick,inputWASDEmulateDirection,touchGamepadEnable,touchGamepadAnalog,touchGamepadSize,touchGamepadAlpha,vibrateEnable,soundEnable,soundVolume,soundDefaultRange,soundDefaultTaper,medalDisplayTime,medalDisplaySlideTime,medalDisplaySize,medalDisplayIconSize,setCameraPos,setCameraScale,setCanvasMaxSize,setCanvasFixedSize,setCanvasPixelated,setFontDefault,setShowSplashScreen,setGlEnable,setGlOverlay,setTileSizeDefault,setTileFixBleedScale,setEnablePhysicsSolver,setObjectDefaultMass,setObjectDefaultDamping,setObjectDefaultAngleDamping,setObjectDefaultElasticity,setObjectDefaultFriction,setObjectMaxSpeed,setGravity,setParticleEmitRateScale,setGamepadsEnable,setGamepadDirectionEmulateStick,setInputWASDEmulateDirection,setTouchGamepadEnable,setTouchGamepadAnalog,setTouchGamepadSize,setTouchGamepadAlpha,setVibrateEnable,setSoundEnable,setSoundVolume,setSoundDefaultRange,setSoundDefaultTaper,setMedalDisplayTime,setMedalDisplaySlideTime,setMedalDisplaySize,setMedalDisplayIconSize,setMedalsPreventUnlock,setShowWatermark,setDebugKey,PI,abs,min,max,sign,mod,clamp,percent,distanceWrap,lerpWrap,distanceAngle,lerpAngle,lerp,smoothStep,nearestPowerOfTwo,isOverlapping,wave,formatTime,rand,randInt,randSign,randInCircle,randVector,randColor,RandomGenerator,Vector2,Color,Timer,vec2,rgb,hsl,textureInfos,tile,TileInfo,TextureInfo,mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize,screenToWorld,worldToScreen,drawTile,drawRect,drawLine,drawCanvas2D,setBlendMode,drawTextScreen,drawText,engineFontImage,FontImage,isFullscreen,toggleFullscreen,glCanvas,glContext,glSetTexture,glCompileShader,glCreateProgram,glCreateTexture,glInitPostProcess,keyIsDown,keyWasPressed,keyWasReleased,clearInput,mouseIsDown,mouseWasPressed,mouseWasReleased,mousePos,mousePosScreen,mouseWheel,isUsingGamepad,preventDefaultInput,gamepadIsDown,gamepadWasPressed,gamepadWasReleased,gamepadStick,mouseToScreen,gamepadsUpdate,vibrate,vibrateStop,isTouchDevice,Sound,SoundWave,Music,playAudioFile,speak,speakStop,getNoteFrequency,audioContext,playSamples,zzfx,EngineObject,tileCollision,tileCollisionSize,initTileCollision,setTileCollisionData,getTileCollisionData,tileCollisionTest,tileCollisionRaycast,TileLayerData,TileLayer,ParticleEmitter,Particle,medals,medalsPreventUnlock,medalsInit,newgroundsInit,Medal,Newgrounds};
|
|
1
|
+
let showWatermark=0,debugKey="";const debug=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0;function ASSERT(){}function debugInit(){}function debugUpdate(){}function debugRender(){}function debugRect(){}function debugCircle(){}function debugPoint(){}function debugLine(){}function debugAABB(){}function debugText(){}function debugClear(){}function debugSaveCanvas(){}const PI=Math.PI;function abs(a){return Math.abs(a)}function min(a,b){return Math.min(a,b)}function max(a,b){return Math.max(a,b)}function sign(a){return Math.sign(a)}function mod(a,b=1){return(a%b+b)%b}function clamp(a,b=0,c=1){return a<b?b:a>c?c:a}function percent(a,b,c){return c-b?clamp((a-b)/(c-b)):0}function lerp(a,b,c){return b+clamp(a)*(c-b)}function distanceWrap(a,b,c=1){a=(a-b)%c;return 2*a%c-a}function lerpWrap(a,b,c,d=1){return c+clamp(a)*distanceWrap(b,c,d)}function distanceAngle(a,b){return distanceWrap(a,b,2*PI)}function lerpAngle(a,b,c){return lerpWrap(a,b,c,2*PI)}function smoothStep(a){return a*a*(3-2*a)}function nearestPowerOfTwo(a){return 2**Math.ceil(Math.log2(a))}function isOverlapping(a,b,c,d=vec2()){return 2*abs(a.x-c.x)<b.x+d.x&&2*abs(a.y-c.y)<b.y+d.y}function wave(a=1,b=1,c=time){return b/2*(1-Math.cos(c*a*2*PI))}function formatTime(a){return(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0)}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return Math.floor(rand(a,b))}function randSign(){return 2*randInt(2)-1}function randVector(a=1){return(new Vector2).setAngle(rand(2*PI),a)}function randInCircle(a=1,b=0){return 0<a?randVector(a*rand(b/a,1)**.5):new Vector2}function randColor(a=new Color,b=new Color(0,0,0,1),c=!1){return 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))}class RandomGenerator{constructor(a){this.seed=a}float(a=1,b=0){this.seed^=this.seed<<13;this.seed^=this.seed>>>17;this.seed^=this.seed<<5;return b+(a-b)*abs(this.seed%1e9)/1e9}int(a,b=0){return Math.floor(this.float(a,b))}sign(){return 2*this.int(2)-1}}function vec2(a=0,b){return"number"===typeof a?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y)}function isVector2(a){return a instanceof Vector2}class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}copy(){return new Vector2(this.x,this.y)}add(a){ASSERT(isVector2(a));return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){ASSERT(isVector2(a));return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){ASSERT(isVector2(a));return new Vector2(this.x*a.x,this.y*a.y)}divide(a){ASSERT(isVector2(a));return new Vector2(this.x/a.x,this.y/a.y)}scale(a){ASSERT(!isVector2(a));return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){ASSERT(isVector2(a));return this.distanceSquared(a)**.5}distanceSquared(a){ASSERT(isVector2(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(0,a)}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this}dot(a){ASSERT(isVector2(a));return this.x*a.x+this.y*a.y}cross(a){ASSERT(isVector2(a));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)}setDirection(a,b=1){ASSERT(0==a||1==a||2==a||3==a);return vec2(a%2?a-1?-b:b:0,a%2?0:a?-b: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 abs(this.x*this.y)}lerp(a,b){ASSERT(isVector2(a));return this.add(a.subtract(this).scale(clamp(b)))}arrayCheck(a){ASSERT(isVector2(a));return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}toString(a=3){if(debug)return`(${(0>this.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`}}function rgb(a,b,c,d){return new Color(a,b,c,d)}function hsl(a,b,c,d){return(new Color).setHSLA(a,b,c,d)}function isColor(a){return a instanceof Color}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){ASSERT(isColor(a));return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){ASSERT(isColor(a));return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){ASSERT(isColor(a));return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){ASSERT(isColor(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){ASSERT(isColor(a));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,k)=>(k=(k%1+1)%1)<1/6?f+6*(g-f)*k:.5>k?g:k<2/3?f+(g-f)*(2/3-k)*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}HSLA(){const a=clamp(this.r),b=clamp(this.g),c=clamp(this.b),d=clamp(this.a),e=Math.max(a,b,c),f=Math.min(a,b,c),g=(e+f)/2;let k=0,h=0;if(e!=f){let l=e-f;h=.5<g?l/(2-e-f):l/(e+f);a==e?k=(b-c)/l+(b<c?6:0):b==e?k=(c-a)/l+2:c==e&&(k=(a-b)/l+4)}return[k/6,h,g,d]}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()}toString(a=!0){const b=c=>(16>(c=255*c|0)?"0":"")+c.toString(16);return"#"+b(this.r)+b(this.g)+b(this.b)+(a?b(this.a):"")}setHex(a){this.r=clamp(parseInt(a.slice(1,3),16)/255);this.g=clamp(parseInt(a.slice(3,5),16)/255);this.b=clamp(parseInt(a.slice(5,7),16)/255);this.a=7<a.length?clamp(parseInt(a.slice(7,9),16)/255):1;return this}rgbaInt(){const a=255*clamp(this.r)|0,b=255*clamp(this.g)<<8,c=255*clamp(this.b)<<16,d=255*clamp(this.a)<<24;return a+b+c+d}}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}toString(){if(debug)return this.isSet()?Math.abs(this.get())+" seconds "+(0>this.get()?"before":"after"):"unset"}valueOf(){return this.get()}}let cameraPos=vec2(),cameraScale=32,canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),canvasPixelated=!0,fontDefault="arial",showSplashScreen=!1,glEnable=!0,glOverlay=!0,tileSizeDefault=vec2(16),tileFixBleedScale=.1,enablePhysicsSolver=!0,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,gamepadsEnable=!0,gamepadDirectionEmulateStick=!0,inputWASDEmulateDirection=!0,touchGamepadEnable=!1,touchGamepadAnalog=!0,touchGamepadSize=99,touchGamepadAlpha=.3,vibrateEnable=!0,soundEnable=!0,soundVolume=.5,soundDefaultRange=40,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalDisplayIconSize=50,medalsPreventUnlock=!1;function setCameraPos(a){cameraPos=a}function setCameraScale(a){cameraScale=a}function setCanvasMaxSize(a){canvasMaxSize=a}function setCanvasFixedSize(a){canvasFixedSize=a}function setCanvasPixelated(a){canvasPixelated=a}function setFontDefault(a){fontDefault=a}function setShowSplashScreen(a){showSplashScreen=a}function setGlEnable(a){glEnable=a}function setGlOverlay(a){glOverlay=a}function setTileSizeDefault(a){tileSizeDefault=a}function setTileFixBleedScale(a){tileFixBleedScale=a}function setEnablePhysicsSolver(a){enablePhysicsSolver=a}function setObjectDefaultMass(a){objectDefaultMass=a}function setObjectDefaultDamping(a){objectDefaultDamping=a}function setObjectDefaultAngleDamping(a){objectDefaultAngleDamping=a}function setObjectDefaultElasticity(a){objectDefaultElasticity=a}function setObjectDefaultFriction(a){objectDefaultFriction=a}function setObjectMaxSpeed(a){objectMaxSpeed=a}function setGravity(a){gravity=a}function setParticleEmitRateScale(a){particleEmitRateScale=a}function setGamepadsEnable(a){gamepadsEnable=a}function setGamepadDirectionEmulateStick(a){gamepadDirectionEmulateStick=a}function setInputWASDEmulateDirection(a){inputWASDEmulateDirection=a}function setTouchGamepadEnable(a){touchGamepadEnable=a}function setTouchGamepadAnalog(a){touchGamepadAnalog=a}function setTouchGamepadSize(a){touchGamepadSize=a}function setTouchGamepadAlpha(a){touchGamepadAlpha=a}function setVibrateEnable(a){vibrateEnable=a}function setSoundEnable(a){soundEnable=a}function setSoundVolume(a){soundVolume=a}function setSoundDefaultRange(a){soundDefaultRange=a}function setSoundDefaultTaper(a){soundDefaultTaper=a}function setMedalDisplayTime(a){medalDisplayTime=a}function setMedalDisplaySlideTime(a){medalDisplaySlideTime=a}function setMedalDisplaySize(a){medalDisplaySize=a}function setMedalDisplayIconSize(a){medalDisplayIconSize=a}function setMedalsPreventUnlock(a){medalsPreventUnlock=a}function setShowWatermark(a){showWatermark=a}function setDebugKey(a){debugKey=a}class EngineObject{constructor(a=vec2(),b=vec2(1),c,d=0,e,f=0){ASSERT(isVector2(a)&&isVector2(b),"ensure pos and size are vec2s");ASSERT("number"!==typeof c||!c,"old style tile setup");this.pos=a.copy();this.size=b;this.drawSize=void 0;this.tileInfo=c;this.angle=d;this.color=e;this.additiveColor=void 0;this.mirror=!1;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=f;this.velocity=vec2();this.angleVelocity=0;this.spawnTime=time;this.children=[];this.parent=void 0;this.localPos=vec2();this.localAngle=0;this.isSolid=this.collideSolidObjects=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.velocity.y+=gravity*this.gravityScale,this.pos.x+=this.velocity.x*=this.damping,this.pos.y+=this.velocity.y*=this.damping,this.angle+=this.angleVelocity*=this.angleDamping,ASSERT(0<=this.angleDamping&&1>=this.angleDamping),ASSERT(0<=this.damping&&1>=this.damping),enablePhysicsSolver&&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)continue;if(!isOverlapping(this.pos,this.size,d.pos,d.size))continue;c=this.collideWithObject(d);var e=d.collideWithObject(this);if(!c||!e)continue;if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);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));debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f00");continue}e=this.size.add(d.size);var f=2*(a.y-d.pos.y)>e.y+gravity;const k=2*abs(a.y-d.pos.y)<e.y;var g=2*abs(a.x-d.pos.x)<e.x;c=max(this.elasticity,d.elasticity);if(f||g||!k)if(this.pos.y=d.pos.y+(e.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-c;else if(d.mass){g=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass);const h=d.velocity.y*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.y*this.mass/(this.mass+d.mass);this.velocity.y=lerp(c,g,this.velocity.y*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.y*d.mass/(this.mass+d.mass));d.velocity.y=lerp(c,g,h)}!f&&k&&(this.pos.x=d.pos.x+(e.x/2+.001)*sign(a.x-d.pos.x),d.mass?(e=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(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),this.velocity.x=lerp(c,e,this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass)),d.velocity.x=lerp(c,e,f)):this.velocity.x*=-c);debugOverlay&&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(vec2(a.x,this.pos.y),this.size,this);d=tileCollisionTest(vec2(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.tileInfo,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!0}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=!0){ASSERT(a||!b,"solid objects must be set to collide");this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c}toString(){if(debug){let a="type = "+this.constructor.name;if(this.pos.x||this.pos.y)a+="\npos = "+this.pos;if(this.velocity.x||this.velocity.y)a+="\nvelocity = "+this.velocity;if(this.size.x||this.size.y)a+="\nsize = "+this.size;this.angle&&(a+="\nangle = "+this.angle.toFixed(3));this.color&&(a+="\ncolor = "+this.color);return a}}}let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2(),textureInfos=[],drawCount;function tile(a=vec2(),b=tileSizeDefault,c=0){"number"===typeof b&&(ASSERT(0<b),b=vec2(b));if("number"===typeof a){var d=textureInfos[c];ASSERT(d,"Texture not loaded");d=d.size.x/b.x|0;a=vec2(a%d*b.x,(a/d|0)*b.y)}return new TileInfo(a,b,c)}class TileInfo{constructor(a=vec2(),b=tileSizeDefault,c=0){this.pos=a;this.size=b;this.textureIndex=c}offset(a){return new TileInfo(this.pos.add(a),this.size,this.textureIndex)}frame(a){ASSERT("number"==typeof a);return this.offset(vec2(a*this.size.x,0))}getTextureInfo(){return textureInfos[this.textureIndex]}}class TextureInfo{constructor(a){this.image=a;this.size=vec2(a.width,a.height);this.glTexture=glEnable&&glCreateTexture(a);this.fixBleedSize=vec2(tileFixBleedScale).divide(this.size)}}function screenToWorld(a){return new Vector2((a.x-mainCanvasSize.x/2+.5)/cameraScale+cameraPos.x,(a.y-mainCanvasSize.y/2+.5)/-cameraScale+cameraPos.y)}function worldToScreen(a){return new Vector2((a.x-cameraPos.x)*cameraScale+mainCanvasSize.x/2-.5,(a.y-cameraPos.y)*-cameraScale+mainCanvasSize.y/2-.5)}function getCameraSize(){return mainCanvasSize.scale(1/cameraScale)}function drawTile(a,b=vec2(1),c,d=new Color,e=0,f,g=new Color(0,0,0,0),k=glEnable,h,l){ASSERT(!l||!k,"context only supported in canvas 2D mode");ASSERT("number"!==typeof c||!c,"this is an old style calls, to fix replace it with tile(tileIndex, tileSize)");const n=c&&c.getTextureInfo();if(k)if(h&&(a=screenToWorld(a),b=b.scale(1/cameraScale)),n){k=c.pos.x/n.size.x;h=c.pos.y/n.size.y;l=c.size.x/n.size.x;const m=c.size.y/n.size.y,p=n.fixBleedSize;glSetTexture(n.glTexture);glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,k+p.x,h+p.y,k-p.x+l,h-p.y+m,d.rgbaInt(),g.rgbaInt())}else glDraw(a.x,a.y,b.x,b.y,e,0,0,0,0,0,d.rgbaInt());else showWatermark&&++drawCount,drawCanvas2D(a,b,e,f,m=>{if(n){const p=c.pos.x+tileFixBleedScale,t=c.pos.y+tileFixBleedScale,u=c.size.x-2*tileFixBleedScale,x=c.size.y-2*tileFixBleedScale;m.globalAlpha=d.a;m.drawImage(n.image,p,t,u,x,-.5,-.5,1,1);m.globalAlpha=1}else m.fillStyle=d,m.fillRect(-.5,-.5,1,1)},h,l)}function drawRect(a,b,c,d,e,f,g){drawTile(a,b,void 0,c,d,!1,void 0,e,f,g)}function drawLine(a,b,c=.1,d,e,f,g){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(),e,f,g)}function drawCanvas2D(a,b,c,d,e,f,g=mainContext){f||(a=worldToScreen(a),b=b.scale(cameraScale));g.save();g.translate(a.x+.5,a.y+.5);g.rotate(c);g.scale(d?-b.x:b.x,b.y);e(g);g.restore()}function setBlendMode(a,b=glEnable,c){ASSERT(!c||!b,"context only supported in canvas 2D mode");b?glAdditive=a:(c||=mainContext,c.globalCompositeOperation=a?"lighter":"source-over")}function drawText(a,b,c=1,d,e=0,f,g,k,h){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,k,h)}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",k=fontDefault,h=overlayContext){h.fillStyle=d.toString();h.lineWidth=e;h.strokeStyle=f.toString();h.textAlign=g;h.font=c+"px "+k;h.textBaseline="middle";h.lineJoin="round";b=b.copy();(a+"").split("\n").forEach(l=>{e&&h.strokeText(l,b.x,b.y);h.fillText(l,b.x,b.y);b.y+=c})}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=overlayContext){engineFontImage||((engineFontImage=new Image).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.context=d}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!canvasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),k=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((h,l)=>{const n=d?h.length*f.x*c/2|0:0;for(let t=h.length;t--;){var m=h[t].charCodeAt(0);if(32>m||127<m)m=127;var p=m-32;m=p%k;p=p/k|0;const u=b.add(vec2(t,l).multiply(g));e.drawImage(this.image,m*f.x,p*f.y,f.x,f.y,u.x-n,u.y,f.x*c,f.y*c)}});e.restore()}}function isFullscreen(){return!!document.fullscreenElement}function toggleFullscreen(){isFullscreen()?document.exitFullscreen&&document.exitFullscreen():document.body.requestFullscreen&&document.body.requestFullscreen()}function keyIsDown(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&1)}function keyWasPressed(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&2)}function keyWasReleased(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&4)}function clearInput(){inputData=[[]]}const mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=!1,preventDefaultInput=!1;function gamepadIsDown(a,b=0){return keyIsDown(a,b+1)}function gamepadWasPressed(a,b=0){return keyWasPressed(a,b+1)}function gamepadWasReleased(a,b=0){return keyWasReleased(a,b+1)}function gamepadStick(a,b=0){return stickData[b]?stickData[b][a]||vec2():vec2()}let inputData=[[]];function inputUpdate(){isTouchDevice||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||(isUsingGamepad=!1,inputData[0][a.code]=3,inputWASDEmulateDirection&&(inputData[0][remapKey(a.code)]=3)),preventDefaultInput&&a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][a.code]=4,inputWASDEmulateDirection&&(inputData[0][remapKey(a.code)]=4))};function remapKey(a){return inputWASDEmulateDirection?"KeyW"==a?"ArrowUp":"KeyS"==a?"ArrowDown":"KeyA"==a?"ArrowLeft":"KeyD"==a?"ArrowRight":a:a}onmousedown=a=>{isUsingGamepad=!1;inputData[0][a.button]=3;mousePosScreen=mouseToScreen(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>mouseWheel=a.ctrlKey?0:sign(a.deltaY);oncontextmenu=a=>!1;function mouseToScreen(a){if(!mainCanvas)return vec2();const b=mainCanvas.getBoundingClientRect();return vec2(mainCanvas.width,mainCanvas.height).multiply(vec2(percent(a.x,b.left,b.right),percent(a.y,b.top,b.bottom)))}const stickData=[];function gamepadsUpdate(){const a=g=>{const k=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.3,.8):0;return vec2(k(g.x),k(-g.y)).clampLength()};if(touchGamepadEnable&&isTouchDevice&&(touchGamepadButtons||createTouchGamepad(),touchGamepadTimer.isSet())){var b=stickData[0]||(stickData[0]=[]);b[0]=vec2();touchGamepadAnalog?b[0]=a(touchGamepadStick):.3<touchGamepadStick.lengthSquared()&&(b[0].x=Math.round(touchGamepadStick.x),b[0].y=-Math.round(touchGamepadStick.y),b[0]=b[0].clampLength());b=inputData[1]||(inputData[1]=[]);for(var c=10;c--;){var d=3==c?2:2==c?3:c;b[d]=touchGamepadButtons[c]?gamepadIsDown(d,0)?1:3:gamepadIsDown(d,0)?4:0}}if(gamepadsEnable&&navigator&&navigator.getGamepads&&(debug||document.hasFocus()))for(b=navigator.getGamepads(),c=b.length;c--;){var e=b[c];const g=inputData[c+1]||(inputData[c+1]=[]);d=stickData[c]||(stickData[c]=[]);if(e){for(var f=0;f<e.axes.length-1;f+=2)d[f>>1]=a(vec2(e.axes[f],e.axes[f+1]));for(f=e.buttons.length;f--;){const k=e.buttons[f],h=gamepadIsDown(f,c);g[f]=k.pressed?h?1:3:h?4:0;isUsingGamepad||=!c&&k.pressed}gamepadDirectionEmulateStick&&(e=vec2((gamepadIsDown(15,c)&&1)-(gamepadIsDown(14,c)&&1),(gamepadIsDown(12,c)&&1)-(gamepadIsDown(13,c)&&1)),e.lengthSquared()&&(d[0]=e.clampLength()));touchGamepadEnable&&isUsingGamepad&&touchGamepadTimer.unset()}}}function vibrate(a=100){vibrateEnable&&navigator&&navigator.vibrate&&navigator.vibrate(a)}function vibrateStop(){vibrate(0)}const isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a;onmousedown=onmouseup=()=>0;ontouchstart=ontouchmove=ontouchend=b=>{soundEnable&&audioContext&&"running"!=audioContext.state&&zzfx(0);const c=b.touches.length;if(c){const d=vec2(b.touches[0].clientX,b.touches[0].clientY);mousePosScreen=mouseToScreen(d);a?isUsingGamepad=!1:inputData[0][0]=3}else a&&(inputData[0][0]=inputData[0][0]&2|4);a=c;document.hasFocus()&&b.preventDefault();return!0}}let touchGamepadTimer=new Timer,touchGamepadButtons,touchGamepadStick;function createTouchGamepad(){touchGamepadButtons=[];touchGamepadStick=vec2();const a=ontouchstart;ontouchstart=ontouchmove=ontouchend=b=>{touchGamepadStick=vec2();touchGamepadButtons=[];if(b.touches.length&&(touchGamepadTimer.set(),paused)){touchGamepadButtons[9]=1;return}const c=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),d=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),e=mainCanvasSize.scale(.5);for(const g of b.touches){var f=mouseToScreen(vec2(g.clientX,g.clientY));f.distance(c)<touchGamepadSize?touchGamepadStick=f.subtract(c).scale(2/touchGamepadSize).clampLength():f.distance(d)<touchGamepadSize?(f=f.subtract(d).direction(),touchGamepadButtons[f]=1):f.distance(e)<touchGamepadSize&&(touchGamepadButtons[9]=1)}a.bind(window)(b);return isUsingGamepad=!0}}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(vec2().setDirection(b,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()}}}class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=0,a&&(this.randomness=a[1]||0,a[1]=0,this.sampleChannels=[zzfxG(...a)],this.sampleRate=zzfxR))}play(a,b=1,c=1,d=1,e=!1){if(soundEnable&&this.sampleChannels){var f;if(a){if(f=this.range){const g=cameraPos.distanceSquared(a);if(g>f*f)return;b*=percent(g**.5,f,f*this.taper)}f=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return this.source=playSamples(this.sampleChannels,b,a,f,e,this.sampleRate)}}stop(){this.source&&this.source.stop();this.source=void 0}getSource(){return this.source}playNote(a,b,c){return this.play(b,c,2**(a/12),0)}getDuration(){return this.sampleChannels&&this.sampleChannels[0].length/this.sampleRate}isLoading(){return!this.sampleChannels}}class SoundWave extends Sound{constructor(a,b=0,c,d){super(void 0,c,d);this.randomness=b;soundEnable&&fetch(a).then(e=>e.arrayBuffer()).then(e=>audioContext.decodeAudioData(e)).then(e=>{this.sampleChannels=[];for(let f=e.numberOfChannels;f--;)this.sampleChannels[f]=Array.from(e.getChannelData(f));this.sampleRate=e.sampleRate})}}class Music extends Sound{constructor(a){super(void 0);soundEnable&&(this.randomness=0,this.sampleChannels=zzfxM(...a),this.sampleRate=zzfxR)}playMusic(a,b=!1){return super.play(void 0,a,1,1,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}function speakStop(){speechSynthesis&&speechSynthesis.cancel()}function getNoteFrequency(a,b=220){return b*2**(a/12)}let audioContext=new AudioContext,audioSuspended=!1;function playSamples(a,b=1,c=1,d=0,e=!1,f=zzfxR){if(soundEnable){var g=audioSuspended;if(audioSuspended="running"!=audioContext.state)if(audioContext.resume(),g)return;var k=audioContext.createBuffer(a.length,a[0].length,f);f=audioContext.createBufferSource();a.forEach((h,l)=>k.getChannelData(l).set(h));f.buffer=k;f.playbackRate.value=c;f.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);f.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})).connect(a);f.start();return f}}function zzfx(...a){return playSamples([zzfxG(...a)])}const zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,k=1,h=0,l=0,n=0,m=0,p=0,t=0,u=0,x=0,v=0,D=1,z=0,E=0,A=0){let w=2*PI;var q=zzfxR;let F=h*=500*w/q/q;b=c*=rand(1+b,1-b)*w/q;let C=[],y=0,G=0,r=0,H=1,R=0,S=0,B=0,J;var L=w*abs(A)*2/q,K=Math.cos(L),M=Math.sin(L)/2/2,I=1+M;L=-2*K/I;M=(1-M)/I;let N=(1+sign(A)*K)/2/I;K=-(sign(A)+K)/I;let O=I=0,P=0,Q=0;d=d*q+9;z*=q;e*=q;f*=q;v*=q;l*=500*w/q**3;u*=w/q;n*=w/q;m*=q;p=p*q|0;a*=soundVolume;for(J=d+z+e+f+v|0;r<J;C[r++]=B*a)++S%(100*x|0)||(B=g?1<g?2<g?3<g?Math.sin(y**3):clamp(Math.tan(y),1,-1):1-(2*y/w%2+2)%2:1-4*abs(Math.round(y/w)-y/w):Math.sin(y),B=(p?1-E+E*Math.sin(w*r/p):1)*sign(B)*abs(B)**k*(r<d?r/d:r<d+z?1-(r-d)/z*(1-D):r<d+z+e?D:r<J-v?(J-r-v)/f*D:0),B=v?B/2+(v>r?0:(r<J-v?1:(J-r)/v)*C[r-v|0]/2/a):B,A&&(B=Q=N*I+K*(I=O)+N*(O=B)-M*P-L*(P=Q))),q=(c+=h+=l)*Math.cos(u*G++),y+=q+q*t*Math.sin(r**5),H&&++H>m&&(c+=n,b+=n,H=0),!p||++R%p||(c=b,h=F,H=H||1);return C}function zzfxM(a,b,c,d=125){let e,f,g,k,h,l,n,m,p,t,u,x,v,D=0,z,E=[],A=[],w=[],q=0,F=0,C=1,y={},G=zzfxR/d*60>>2;for(;C;q++)E=[C=m=x=0],c.forEach((r,H)=>{n=b[r][q]||[0,0,0];C|=b[r][q]&&1;z=x+(b[r][0].length-2-(m?0:1))*G;v=H==c.length-1;e=2;for(g=x;e<n.length+v;m=++e){h=n[e];p=e==n.length+v-1&&v||t!=(n[0]||0)||h|0;for(f=0;f<G&&m;f++>G-99&&p&&1>u?u+=1/99:0)l=(1-u)*E[D++]/2||0,A[g]=(A[g]||0)-l*F+l,w[g]=(w[g++]||0)+l*F+l;h&&(u=h%1,F=n[1]||0,h|=0)&&(E=y[[t=n[D=0]||0,h]]=y[[t,h]]||(k=[...a[t]],k[2]*=2**((h-12)/12),0<h?zzfxG(...k):[]))}x=z});return[A,w]}let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}function setTileCollisionData(a,b=0){a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b)}function getTileCollisionData(a){return 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,vec2(b,e))))return!0}}function tileCollisionRaycast(a,b,c){const d=b.subtract(a),e=d.length();var f=d.normalize();f=vec2(abs(1/f.x),abs(1/f.y));let g=a.floor(),k=f.x*(0>d.x?a.x-g.x:g.x-a.x+1),h=f.y*(0>d.y?a.y-g.y:g.y-a.y+1);for(;;){const l=getTileCollisionData(g);if(l&&(!c||c.collideWithTile(l,g)))return debugRaycast&&debugLine(a,b,"#f00",.02),debugRaycast&&debugPoint(g.add(vec2(.5)),"#ff0"),g.add(vec2(.5));if(k>e&&h>e)break;k>h?(g.y+=sign(d.y),h+=f.y):(g.x+=sign(d.x),k+=f.x)}debugRaycast&&debugLine(a,b,"#00f",.02)}class TileLayerData{constructor(a,b=0,c=!1,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=0;this.mirror=!1;this.color=new Color}}class TileLayer extends EngineObject{constructor(a,b=tileCollisionSize,c=tile(),d=vec2(1),e=0){super(a,b,c,0,void 0,e);this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.scale=d;this.isOverlay=!1;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c=!1){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,"must call redrawEnd() after drawing tiles");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(!0);for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b),!1);this.redrawEnd()}redrawStart(a=!1){this.savedRenderSettings=[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;mainCanvasSize=this.size.multiply(this.tileInfo.size);cameraPos=this.size.scale(.5);cameraScale=this.tileInfo.size.x;a&&(mainCanvas.width=mainCanvasSize.x,mainCanvas.height=mainCanvasSize.y);enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context,"must call redrawStart() before drawing tiles");glEnable&&glCopyToContext(mainContext,!0);[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a,b=!0){var c=this.tileInfo.size;b&&(b=a.multiply(c),this.context.clearRect(b.x,this.canvas.height-b.y,c.x,-c.y));b=this.getData(a);void 0!=b.tile&&(a=this.pos.add(a).add(vec2(.5)),ASSERT(mainContext==this.context,"must call redrawStart() before drawing tiles"),c=tile(b.tile,c,this.tileInfo.textureIndex),drawTile(a,vec2(1),c,b.color,b.direction*PI/2,b.mirror))}drawCanvas2D(a,b,c,d,e){const f=this.context;f.save();a=a.subtract(this.pos).multiply(this.tileInfo.size);b=b.multiply(this.tileInfo.size);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,d=new Color,e,f){this.drawCanvas2D(a,b,e,f,g=>{const k=c&&c.getTextureInfo();k?(g.globalAlpha=d.a,g.drawImage(k.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1),g.globalAlpha=1):(g.fillStyle=d,g.fillRect(-.5,-.5,1,1))})}drawRect(a,b,c,d){this.drawTile(a,b,void 0,c,d)}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,k=new Color,h=new Color,l=new Color(1,1,1,0),n=new Color(1,1,1,0),m=.5,p=.1,t=1,u=.1,x=.05,v=1,D=1,z=0,E=PI,A=.1,w=.2,q=!1,F=!1,C=!0,y=F?1e9:0,G=!1){super(a,vec2(),g,b,void 0,y);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=k;this.colorStartB=h;this.colorEndA=l;this.colorEndB=n;this.randomColorLinear=C;this.particleTime=m;this.sizeStart=p;this.sizeEnd=t;this.speed=u;this.angleSpeed=x;this.damping=v;this.angleDamping=D;this.gravityScale=z;this.particleConeAngle=E;this.fadeRate=A;this.randomness=w;this.collideTiles=q;this.additive=F;this.localSpace=G;this.trailScale=0;this.particleCreateCallback=this.particleDestroyCallback=void 0;this.emitTimeBuffer=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="number"===typeof this.emitSize?randInCircle(this.emitSize/2):vec2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle);let b=rand(this.particleConeAngle,-this.particleConeAngle);this.localSpace||(a=this.pos.add(a),b+=this.angle);const c=this.randomness;var d=m=>m+m*rand(c,-c);const e=d(this.particleTime),f=d(this.sizeStart),g=d(this.sizeEnd),k=d(this.speed);d=d(this.angleSpeed)*randSign();var h=rand(this.emitConeAngle,-this.emitConeAngle);const l=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),n=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);h=this.localSpace?h:this.angle+h;a=new Particle(a,this.tileInfo,b,l,n,e,f,g,this.fadeRate,this.additive,this.trailScale,this.localSpace&&this,this.particleDestroyCallback);a.velocity=vec2().setAngle(h,k);a.angleVelocity=d;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.renderOrder=this.renderOrder;a.mirror=!!randInt(2);this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d,e,f,g,k,h,l,n,m,p){super(a,vec2(),b,c);this.colorStart=d;this.colorEndDelta=e.subtract(d);this.lifeTime=f;this.sizeStart=g;this.sizeEndDelta=k-g;this.fadeRate=h;this.additive=l;this.trailScale=n;this.localSpaceEmitter=m;this.destroyCallback=p}render(){const a=min((time-this.spawnTime)/this.lifeTime,1),b=vec2(this.sizeStart+a*this.sizeEndDelta);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(!0);let d=this.pos,e=this.angle;this.localSpaceEmitter&&(d=this.localSpaceEmitter.pos.add(d.rotate(-this.localSpaceEmitter.angle)),e+=this.localSpaceEmitter.angle);if(this.trailScale){var f=this.velocity;this.localSpaceEmitter&&(f=f.rotate(-this.localSpaceEmitter.angle));var g=f.length();g&&(f=f.scale(1/g),g*=this.trailScale,b.y=max(b.x,g),e=f.angle(),drawTile(d.add(f.multiply(vec2(0,-g/2))),b,this.tileInfo,c,e,this.mirror))}else drawTile(d,b,this.tileInfo,c,e,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(d,b,"#f005",0,e);1==a&&(this.color=c,this.size=b,this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}}const medals=[];let medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast;function medalsInit(a){medalsSaveName=a;debugMedals||medals.forEach(b=>b.unlocked=localStorage[b.storageKey()]|0)}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;e&&((this.image=new Image).src=e)}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName,"save name must be set"),localStorage[this.storageKey()]=this.unlocked=1,medalsDisplayQueue.push(this),newgrounds&&newgrounds.unlockMedal(this.id))}render(a=0){const b=overlayContext;var c=min(medalDisplaySize.x,mainCanvas.width);const d=overlayCanvas.width-c;a*=-medalDisplaySize.y;b.save();b.beginPath();b.fillStyle=new Color(.9,.9,.9).toString();b.strokeStyle=new Color(0,0,0).toString();b.lineWidth=3;b.rect(d,a,c,medalDisplaySize.y);b.fill();b.stroke();b.clip();this.renderIcon(vec2(d+15+medalDisplayIconSize/2,a+medalDisplaySize.y/2));c=vec2(d+medalDisplayIconSize+30,a+28);drawTextScreen(this.name,c,38,new Color(0,0,0),0,void 0,"left");c.y+=32;drawTextScreen(this.description,c,24,new Color(0,0,0),0,void 0,"left");b.restore()}renderIcon(a,b=medalDisplayIconSize){this.image?overlayContext.drawImage(this.image,a.x-b/2,a.y-b/2,b,b):drawTextScreen(this.icon,a,.7*b,new Color(0,0,0))}storageKey(){return medalsSaveName+"_"+this.id}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayTimeLast=0,medalsDisplayQueue.shift();else{const c=medalDisplayTime-medalDisplaySlideTime;a.render(b<medalDisplaySlideTime?1-b/medalDisplaySlideTime:b>c?(b-c)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}}let newgrounds;function newgroundsInit(a,b,c){newgrounds=new Newgrounds(a,b,c)}class Newgrounds{constructor(a,b,c){ASSERT(!newgrounds&&0<a,"there can only be one newgrounds object");ASSERT(!b||c,"must provide cryptojs if there is a cipher");this.app_id=a;this.cipher=b;this.cryptoJS=c;this.host=location?location.hostname:"";if(this.session_id=new URL(location.href).searchParams.get("ngio_session_id")){this.medals=(a=this.call("Medal.getList"))?a.result.data.medals:[];debugMedals&&console.log(this.medals);for(var d of this.medals)if(a=medals[d.id])a.image=new Image,a.image.src=d.icon,a.name=d.name,a.description=d.description,a.unlocked=d.unlocked,a.difficulty=d.difficulty,a.value=d.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(d=this.call("ScoreBoard.getBoards"))?d.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards);setInterval(()=>this.call("Gateway.ping",0,!0),3e5)}}unlockMedal(a){return this.call("Medal.unlock",{id:a},!0)}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b},!0)}getScores(a,b,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},!0)}call(a,b,c=!1){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)}}let glCanvas,glContext,glShader,glActiveTexture,glArrayBuffer,glGeometryBuffer,glPositionData,glColorData,glInstanceCount,glAdditive,glBatchAdditive;function glInit(){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl2");glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 m;in vec2 g;in vec4 p,u,c,a;in float r;out vec2 v;out vec4 d,e;void main(){vec2 s=(g-.5)*p.zw;gl_Position=m*vec4(p.xy+s*cos(r)-vec2(-s.y,s)*sin(r),1,1);v=mix(u.xw,u.zy,g);d=c;e=a;}","#version 300 es\nprecision highp float;in vec2 v;in vec4 d,e;uniform sampler2D s;out vec4 c;void main(){c=texture(s,v)*d+e;}");var a=new ArrayBuffer(gl_INSTANCE_BUFFER_SIZE);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glArrayBuffer=glContext.createBuffer();glGeometryBuffer=glContext.createBuffer();a=new Float32Array([glInstanceCount=0,0,1,0,0,1,1,1]);glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);glContext.bufferData(gl_ARRAY_BUFFER,a,gl_STATIC_DRAW)}function glPreRender(){glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glContext.clear(gl_COLOR_BUFFER_BIT);glContext.useProgram(glShader);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=textureInfos[0].glTexture);let a=glAdditive=glBatchAdditive=0;var b=(d,e,f,g)=>{d=glContext.getAttribLocation(glShader,d);const k=f&&gl_INSTANCE_BYTE_STRIDE,h=f&&1,l=1==f;glContext.enableVertexAttribArray(d);glContext.vertexAttribPointer(d,g,e,l,k,a);glContext.vertexAttribDivisor(d,h);a+=g*f};glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);b("g",gl_FLOAT,0,2);glContext.bindBuffer(gl_ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,gl_INSTANCE_BUFFER_SIZE,gl_DYNAMIC_DRAW);b("p",gl_FLOAT,4,4);b("u",gl_FLOAT,4,4);b("c",gl_UNSIGNED_BYTE,1,4);b("a",gl_UNSIGNED_BYTE,1,4);b("r",gl_FLOAT,4,1);b=vec2(2*cameraScale).divide(mainCanvasSize);const c=vec2(-1).subtract(cameraPos.multiply(b));glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),!1,new Float32Array([b.x,0,0,0,0,b.y,0,0,1,1,1,1,c.x,c.y,0,0]))}function glSetTexture(a){a!=glActiveTexture&&(glFlush(),glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=a))}function glCompileShader(a,b){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){const 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 glCreateTexture(a){const b=glContext.createTexture();glContext.bindTexture(gl_TEXTURE_2D,b);a&&glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,a);a=canvasPixelated?gl_NEAREST:gl_LINEAR;glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MIN_FILTER,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MAG_FILTER,a);return b}function glFlush(){if(glInstanceCount){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);glContext.drawArraysInstanced(gl_TRIANGLE_STRIP,0,4,glInstanceCount);showWatermark&&(drawCount+=glInstanceCount);glInstanceCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b=!1){if(glInstanceCount||b)glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0)}function glDraw(a,b,c,d,e,f,g,k,h,l,n=0){ASSERT("number"==typeof l&&"number"==typeof n,"invalid color");(glInstanceCount>=gl_MAX_INSTANCES||glBatchAdditive!=glAdditive)&&glFlush();let m=glInstanceCount*gl_INDICIES_PER_INSTANCE;glPositionData[m++]=a;glPositionData[m++]=b;glPositionData[m++]=c;glPositionData[m++]=d;glPositionData[m++]=f;glPositionData[m++]=g;glPositionData[m++]=k;glPositionData[m++]=h;glColorData[m++]=l;glColorData[m++]=n;glPositionData[m++]=e;glInstanceCount++}let glPostShader,glPostTexture,glPostIncludeOverlay;function glInitPostProcess(a,b=!1){ASSERT(!glPostShader,"can only have 1 post effects shader");a||="void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}";glPostShader=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;void main(){gl_Position=vec4(p+p-1.,1,1);}","#version 300 es\nprecision highp float;uniform sampler2D iChannel0;uniform vec3 iResolution;uniform float iTime;out vec4 c;\n"+a+"\nvoid main(){mainImage(c,gl_FragCoord.xy);c.a=1.;}");glPostTexture=glCreateTexture(void 0);glPostIncludeOverlay=b;mainCanvas.style.visibility="hidden";glPostIncludeOverlay&&(overlayCanvas.style.visibility="hidden")}function glRenderPostProcess(){if(glPostShader){glEnable?(glFlush(),mainContext.drawImage(glCanvas,0,0)):glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glPostIncludeOverlay&&mainContext.drawImage(overlayCanvas,0,0);glContext.useProgram(glPostShader);glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL,1);glContext.disable(gl_BLEND);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glPostTexture);glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,mainCanvas);var a=glContext.getAttribLocation(glPostShader,"p");glContext.enableVertexAttribArray(a);glContext.vertexAttribPointer(a,2,gl_FLOAT,!1,8,0);glContext.uniform1i(glContext.getUniformLocation(glPostShader,"iChannel0"),0);glContext.uniform1f(glContext.getUniformLocation(glPostShader,"iTime"),time);glContext.uniform3f(glContext.getUniformLocation(glPostShader,"iResolution"),mainCanvas.width,mainCanvas.height,1);glContext.drawArrays(gl_TRIANGLE_STRIP,0,4)}}const gl_ONE=1,gl_TRIANGLE_STRIP=5,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_COLOR_BUFFER_BIT=16384,gl_TEXTURE0=33984,gl_ARRAY_BUFFER=34962,gl_STATIC_DRAW=35044,gl_DYNAMIC_DRAW=35048,gl_FRAGMENT_SHADER=35632,gl_VERTEX_SHADER=35633,gl_COMPILE_STATUS=35713,gl_LINK_STATUS=35714,gl_UNPACK_FLIP_Y_WEBGL=37440,gl_INDICIES_PER_INSTANCE=11,gl_MAX_INSTANCES=1e4,gl_INSTANCE_BYTE_STRIDE=4*gl_INDICIES_PER_INSTANCE,gl_INSTANCE_BUFFER_SIZE=gl_MAX_INSTANCES*gl_INSTANCE_BYTE_STRIDE,engineName="LittleJS",engineVersion="1.9.4",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=!1;function setPaused(a){paused=a}let frameTimeLastMS=0,frameTimeBufferMS=0,averageFPS=0;function engineInit(a,b,c,d,e,f=["tiles.png"]){function g(h=0){var l=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS,1e3/(l||1));h=debug&&keyIsDown("Equal");const n=debug&&keyIsDown("Minus");debug&&(l*=h?5:n?.2:1);timeReal+=l/1e3;frameTimeBufferMS+=paused?0:l;h||(frameTimeBufferMS=min(frameTimeBufferMS,50));k();if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{l=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(l=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=l}enginePreRender();d();engineObjects.sort((p,t)=>p.renderOrder-t.renderOrder);for(var m of engineObjects)m.destroyed||m.render();e();glRenderPostProcess();medalsRender();touchGamepadRender();debugRender();glEnable&&glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",m=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(m,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(m,mainCanvas.width-2,2),drawCount=0);requestAnimationFrame(g)}function k(){if(canvasFixedSize.x){mainCanvas.width=canvasFixedSize.x;mainCanvas.height=canvasFixedSize.y;const h=innerWidth/innerHeight,l=mainCanvas.width/mainCanvas.height;(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=h<l?"100%":"";(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=h<l?"":"100%"}else mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y);overlayCanvas.width=mainCanvas.width;overlayCanvas.height=mainCanvas.height;mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height)}ASSERT(Array.isArray(f),"pass in images as array");document.body.style.cssText="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none";document.body.appendChild(mainCanvas=document.createElement("canvas"));mainContext=mainCanvas.getContext("2d");debugInit();glEnable&&glInit();document.body.appendChild(overlayCanvas=document.createElement("canvas"));overlayContext=overlayCanvas.getContext("2d");(glCanvas||mainCanvas).style.cssText=mainCanvas.style.cssText=overlayCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";k();f=f.map((h,l)=>new Promise(n=>{const m=new Image;m.onerror=m.onload=()=>{textureInfos[l]=new TextureInfo(m);n()};m.src=h}));showSplashScreen&&f.push(new Promise(h=>{function l(){clearInput();drawEngineSplashScreen(n+=.01);1<n?h():setTimeout(l,16)}let n=0;console.log(`${engineName} Engine v${engineVersion}`);l()}));Promise.all(f).then(()=>{a();g()})}function enginePreRender(){mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.imageSmoothingEnabled=!canvasPixelated;glEnable&&glPreRender()}function engineObjectsUpdate(){function a(b){if(!b.destroyed){b.update();for(const c of b.children)a(c)}}engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed)}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("object"===typeof b)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)}function drawEngineSplashScreen(a){const b=overlayContext;var c=overlayCanvas.width=innerWidth,d=overlayCanvas.height=innerHeight,e=percent(a,1,.8),f=percent(a,0,.5),g=b.createRadialGradient(c/2,d/2,0,c/2,d/2,.7*Math.hypot(c,d));g.addColorStop(0,hsl(0,0,lerp(f,0,e/2),e).toString());g.addColorStop(1,hsl(0,0,0,e).toString());b.save();b.fillStyle=g;b.fillRect(0,0,c,d);g=(h,l,n,m,p)=>{b.beginPath();b.rect(h,l,n,p?m*k:m);(b.fillStyle=p)?b.fill():b.stroke()};f=(h,l,n,m=0,p=2*PI,t,u)=>{const x=(m+p)/2;m=k*(p-m)/2;b.beginPath();u&&b.lineTo(h,l);b.arc(h,l,n,x-m,x+m);(b.fillStyle=t)?b.fill():b.stroke()};e=(h=0,l=0)=>hsl([.98,.3,.57,.14][h%4]-10,.8,[0,.3,.5,.8,.9][l]).toString();a=wave(1,1,a);const k=percent(a,.1,.5);b.translate(c/2,d/2);c=min(6,min(c,d)/99);b.scale(c,c);b.translate(-40,-35);b.lineJoin=b.lineCap="round";b.lineWidth=.1+1.9*k;c=percent(a,.1,1);b.setLineDash([99*c,99]);g(7,17,18,-8,e(2,2));g(7,9,18,4,e(2,3));g(25,9,8,8,e(2,1));g(25,9,-18,8);g(25,9,8,8);g(25,17,7,22,e());g(11,40,14,-23,e(1,1));g(11,17,14,17,e(1,2));g(11,17,14,9,e(1,3));g(15,31,6,-9,e(2,2));f(15,23,5,0,PI/2,e(2,4),1);g(25,17,-14,23);g(21,22,-6,9);g(37,14,9,6,e(3,2));g(37,14,4.5,6,e(3,3));g(37,14,9,6);g(50,20,10,-10,e(0,1));g(50,20,6.5,-10,e(0,2));g(50,20,3.5,-10,e(0,3));g(50,20,10,-10);f(55,2,11.4,.5,PI-.5,e(3,3));f(55,2,11.4,.5,PI/2,e(3,2),1);f(55,2,11.4,.5,PI-.5);g(45,7,20,-7,e(0,2));g(45,0,20,3,e(0,3));g(45,0,20,7);for(c=5;c--;)f(60-6*c,30,9.9,0,2*PI,e(c+2,3)),f(60-6*c,30,10,-.5,PI+.5,e(c+2,2)),f(60-6*c,30,10.1,.5,PI-.5,e(c+2,1));f(36,30,10,PI/2,3*PI/2);f(48,30,10,PI/2,3*PI/2);f(60,30,10);b.beginPath();b.lineTo(36,20);b.lineTo(60,20);b.stroke();f(60,30,4,PI,3*PI,e(3,2));f(60,30,4,PI,2*PI,e(3,3));f(60,30,4,PI,3*PI);for(c=6;c--;)b.beginPath(),b.lineTo(53,54),b.lineTo(53,40),b.lineTo(53+(1+2.9*c)*k,40),b.lineTo(53+(4+3.5*c)*k,54),b.fillStyle=e(0,c%2+2),b.fill(),c%2&&b.stroke();g(6,40,5,5);g(6,40,5,5,e());g(15,54,38,-14,e());for(g=3;g--;)for(c=2;c--;)f(15*g+15,47,c?7:1,PI,3*PI,e(g,3)),b.stroke(),f(15*g+15,47,c?7:1,0,PI,e(g,2)),b.stroke();b.beginPath();b.lineTo(6,40);b.lineTo(68,40);b.stroke();b.beginPath();b.lineTo(77,54);b.lineTo(4,54);b.stroke();f=engineName;b.font="900 16px arial";b.textAlign="center";b.textBaseline="top";b.lineWidth=.1+3.9*k;g=0;for(c=0;c<f.length;++c)g+=b.measureText(f[c]).width;for(c=2;c--;)for(let h=0,l=41-g/2;h<f.length;++h)b.fillStyle=e(h,2),d=b.measureText(f[h]).width,b[c?"strokeText":"fillText"](f[h],l+d/2,55.5,17*k),l+=d;b.restore()}export{engineName,engineVersion,frameRate,timeDelta,engineObjects,frame,time,timeReal,paused,setPaused,engineInit,engineObjectsUpdate,engineObjectsDestroy,engineObjectsCallback,debug,debugOverlay,showWatermark,ASSERT,debugRect,debugCircle,debugPoint,debugLine,debugAABB,debugText,debugClear,debugSaveCanvas,cameraPos,cameraScale,canvasMaxSize,canvasFixedSize,canvasPixelated,fontDefault,showSplashScreen,tileSizeDefault,tileFixBleedScale,enablePhysicsSolver,objectDefaultMass,objectDefaultDamping,objectDefaultAngleDamping,objectDefaultElasticity,objectDefaultFriction,objectMaxSpeed,gravity,particleEmitRateScale,glEnable,glOverlay,gamepadsEnable,gamepadDirectionEmulateStick,inputWASDEmulateDirection,touchGamepadEnable,touchGamepadAnalog,touchGamepadSize,touchGamepadAlpha,vibrateEnable,soundEnable,soundVolume,soundDefaultRange,soundDefaultTaper,medalDisplayTime,medalDisplaySlideTime,medalDisplaySize,medalDisplayIconSize,setCameraPos,setCameraScale,setCanvasMaxSize,setCanvasFixedSize,setCanvasPixelated,setFontDefault,setShowSplashScreen,setGlEnable,setGlOverlay,setTileSizeDefault,setTileFixBleedScale,setEnablePhysicsSolver,setObjectDefaultMass,setObjectDefaultDamping,setObjectDefaultAngleDamping,setObjectDefaultElasticity,setObjectDefaultFriction,setObjectMaxSpeed,setGravity,setParticleEmitRateScale,setGamepadsEnable,setGamepadDirectionEmulateStick,setInputWASDEmulateDirection,setTouchGamepadEnable,setTouchGamepadAnalog,setTouchGamepadSize,setTouchGamepadAlpha,setVibrateEnable,setSoundEnable,setSoundVolume,setSoundDefaultRange,setSoundDefaultTaper,setMedalDisplayTime,setMedalDisplaySlideTime,setMedalDisplaySize,setMedalDisplayIconSize,setMedalsPreventUnlock,setShowWatermark,setDebugKey,PI,abs,min,max,sign,mod,clamp,percent,distanceWrap,lerpWrap,distanceAngle,lerpAngle,lerp,smoothStep,nearestPowerOfTwo,isOverlapping,wave,formatTime,rand,randInt,randSign,randInCircle,randVector,randColor,RandomGenerator,Vector2,Color,Timer,vec2,rgb,hsl,textureInfos,tile,TileInfo,TextureInfo,mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize,screenToWorld,worldToScreen,drawTile,drawRect,drawLine,drawCanvas2D,setBlendMode,drawTextScreen,drawText,engineFontImage,FontImage,isFullscreen,toggleFullscreen,glCanvas,glContext,glSetTexture,glCompileShader,glCreateProgram,glCreateTexture,glInitPostProcess,keyIsDown,keyWasPressed,keyWasReleased,clearInput,mouseIsDown,mouseWasPressed,mouseWasReleased,mousePos,mousePosScreen,mouseWheel,isUsingGamepad,preventDefaultInput,gamepadIsDown,gamepadWasPressed,gamepadWasReleased,gamepadStick,mouseToScreen,gamepadsUpdate,vibrate,vibrateStop,isTouchDevice,Sound,SoundWave,Music,playAudioFile,speak,speakStop,getNoteFrequency,audioContext,playSamples,zzfx,EngineObject,tileCollision,tileCollisionSize,initTileCollision,setTileCollisionData,getTileCollisionData,tileCollisionTest,tileCollisionRaycast,TileLayerData,TileLayer,ParticleEmitter,Particle,medals,medalsPreventUnlock,medalsInit,newgroundsInit,Medal,Newgrounds};
|