littlejsengine 1.14.7 → 1.14.8
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 +15 -7
- package/dist/littlejs.esm.js +71 -54
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +71 -54
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +71 -54
- package/examples/index.html +10 -5
- package/examples/shorts/piano.js +24 -25
- package/examples/shorts/sound.js +21 -33
- package/examples/shorts/uiSystem.js +13 -6
- package/package.json +1 -1
- package/plugins/uiSystem.js +48 -41
- package/reference.md +1 -0
- package/src/engine.js +1 -1
- package/src/engineDraw.js +1 -1
- package/src/engineInput.js +7 -0
- package/src/engineObject.js +4 -4
- package/src/engineSettings.js +1 -1
- package/src/engineTileLayer.js +2 -2
- package/src/engineUtilities.js +5 -2
- package/src/engineWebGL.js +2 -2
package/dist/littlejs.min.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// LittleJS Engine - MIT License - Copyright 2021 Frank Force
|
|
2
2
|
// https://github.com/KilledByAPixel/LittleJS
|
|
3
3
|
|
|
4
|
-
const engineName="LittleJS",engineVersion="1.14.7",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=!1;function getPaused(){return paused}function setPaused(a=!0){paused=a}let frameTimeLastMS=0,frameTimeBufferMS=0,averageFPS=0;const pluginUpdateList=[],pluginRenderList=[];function engineAddPlugin(a,b){ASSERT(!pluginUpdateList.includes(a));ASSERT(!pluginRenderList.includes(b));a&&pluginUpdateList.push(a);b&&pluginRenderList.push(b)}async function engineInit(a,b,c,d,e,f=[],g=document.body){function h(m=0){function n(){if(!headlessMode){mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);overlayContext.imageSmoothingEnabled=mainContext.imageSmoothingEnabled=!tilesPixelated;glPreRender();d();engineObjects.sort((u,t)=>u.renderOrder-t.renderOrder);for(var q of engineObjects)q.destroyed||q.render();e();pluginRenderList.forEach(u=>u());touchGamepadRender();debugRender();glFlush();debugVideoCaptureUpdate();showWatermark&&!debugVideoCaptureIsActive()&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",q=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(q,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(q,mainCanvas.width-2,2));drawCount=0}}var p=m-frameTimeLastMS;frameTimeLastMS=m;if(debug||showWatermark)averageFPS=lerp(averageFPS,1e3/(p||1),.05);m=debug&&keyIsDown("Equal");const r=debug&&keyIsDown("Minus");debug&&(p*=m?10:r?.1:1);timeReal+=p/1e3;frameTimeBufferMS+=paused?0:p;m||(frameTimeBufferMS=min(frameTimeBufferMS,50));if(paused){k();for(const q of engineObjects)q.parent||q.updateTransforms();inputUpdate();pluginUpdateList.forEach(q=>q());debugUpdate();c();inputUpdatePost()}else{p=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(p=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,k(),inputUpdate(),b(),pluginUpdateList.forEach(q=>q()),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost(),debugVideoCaptureIsActive()&&n();frameTimeBufferMS+=p}debugVideoCaptureIsActive()||n();requestAnimationFrame(h)}function k(){if(!headlessMode){if(canvasFixedSize.x){mainCanvas.width=canvasFixedSize.x;mainCanvas.height=canvasFixedSize.y;const m=innerWidth/innerHeight,n=mainCanvas.width/mainCanvas.height;(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=m<n?"100%":"";(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=m<n?"":"100%"}else mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y);0<canvasClearColor.a&&(mainContext.fillStyle=canvasClearColor.toString(),mainContext.fillRect(0,0,mainCanvasSize.x,mainCanvasSize.y),mainContext.fillStyle=BLACK.toString());overlayCanvas.width=mainCanvas.width;overlayCanvas.height=mainCanvas.height;mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.lineJoin=overlayContext.lineJoin="round";mainContext.lineCap=overlayContext.lineCap="round"}}async function l(){await a();h()}ASSERT(!mainContext,"engine already initialized");ASSERT(Array.isArray(f),"pass in images as array");a||=()=>{};b||=()=>{};c||=()=>{};d||=()=>{};e||=()=>{};if(headlessMode)return l();g.style.cssText="margin:0;overflow:hidden;background:#000;user-select:none;-webkit-user-select:none;touch-action:none;-webkit-touch-callout:none";drawCanvas=mainCanvas=document.createElement("canvas");g.appendChild(mainCanvas);drawContext=mainContext=mainCanvas.getContext("2d");inputInit();audioInit();debugInit();glInit();overlayCanvas=document.createElement("canvas");g.appendChild(overlayCanvas);overlayContext=overlayCanvas.getContext("2d");mainCanvas.style.cssText=overlayCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";glCanvas&&(glCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)");setCanvasPixelated(canvasPixelated);setOverlayCanvasPixelated(overlayCanvasPixelated);k();glPreRender();workCanvas=new OffscreenCanvas(256,256);workContext=workCanvas.getContext("2d",{willReadFrequently:!0});g=f.map((m,n)=>new Promise(p=>{const r=new Image;r.onerror=r.onload=()=>{const q=new TextureInfo(r);q.createWebGLTexture();textureInfos[n]=q;p()};r.crossOrigin="anonymous";r.src=m}));f.length||g.push(new Promise(m=>{const n=new TextureInfo(new Image);textureInfos[0]=n;n.createWebGLTexture();m()}));showSplashScreen&&g.push(new Promise(m=>{function n(){inputClear();drawEngineSplashScreen(p+=.01);1<p?m():setTimeout(n,16)}let p=0;console.log(`${engineName} Engine v${engineVersion}`);n()}));await Promise.all(g);return l()}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),b.updateTransforms());engineObjects=engineObjects.filter(b=>!b.destroyed)}function engineObjectsDestroy(){for(const a of engineObjects)a.parent||a.destroy();engineObjects=engineObjects.filter(a=>!a.destroyed)}function engineObjectsCollect(a,b,c=engineObjects){const d=[];if(a)if(b instanceof Vector2)for(const e of c)isOverlapping(a,b,e.pos,e.size)&&d.push(e);else{b*=b;for(const e of c)a.distanceSquared(e.pos)<b&&d.push(e)}else for(const e of c)d.push(e);return d}function engineObjectsCallback(a,b,c,d=engineObjects){engineObjectsCollect(a,b,d).forEach(e=>c(e))}function engineObjectsRaycast(a,b,c=engineObjects){const d=[];for(const e of c)e.collideRaycast&&isIntersecting(a,b,e.pos,e.size)&&(debugRaycast&&debugRect(e.pos,e.size,"#f00"),d.push(e));debugRaycast&&debugLine(a,b,d.length?"#f00":"#00f",.02);return d}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(0,e/2,f),e).toString());g.addColorStop(1,hsl(0,0,0,e).toString());b.save();b.fillStyle=g;b.fillRect(0,0,c,d);g=(k,l,m,n,p)=>{b.beginPath();b.rect(k,l,m,p?n*h:n);(b.fillStyle=p)?b.fill():b.stroke()};f=(k,l,m,n=0,p=2*PI,r,q)=>{const u=(n+p)/2;n=h*(p-n)/2;b.beginPath();q&&b.lineTo(k,l);b.arc(k,l,m,u-n,u+n);(b.fillStyle=r)?b.fill():b.stroke()};e=(k=0,l=0)=>hsl([.98,.3,.57,.14][k%4]-10,.8,[0,.3,.5,.8,.9][l]).toString();a=wave(1,1,a);const h=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*h;c=percent(a,.1,1);b.setLineDash([99*c,99]);g(7,16,18,-8,e(2,2));g(7,8,18,4,e(2,3));g(25,8,8,8,e(2,1));g(25,8,-18,8);g(25,8,8,8);g(25,16,7,23,e());g(11,39,14,-23,e(1,1));g(11,16,14,18,e(1,2));g(11,16,14,8,e(1,3));g(25,16,-14,24);g(15,29,6,-9,e(2,2));f(15,21,5,0,PI/2,e(2,4),1);g(21,21,-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,-8,e(0,1));g(50,20,6.5,-8,e(0,2));g(50,20,3.5,-8,e(0,3));g(50,20,10,-8);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,-1,20,4,e(0,3));g(45,-1,20,8);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)*h,40),b.lineTo(53+(4+3.5*c)*h,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*h;g=0;for(c=0;c<f.length;++c)g+=b.measureText(f[c]).width;for(c=2;c--;)for(let k=0,l=41-g/2;k<f.length;++k)b.fillStyle=e(k,2),d=b.measureText(f[k]).width,b[c?"strokeText":"fillText"](f[k],l+d/2,55.5,17*h),l+=d;b.restore()}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 debugPoly(){}function debugCircle(){}function debugPoint(){}function debugLine(){}function debugOverlap(){}function debugText(){}function debugClear(){}function debugScreenshot(){}function debugSaveCanvas(){}function debugSaveText(){}function debugSaveDataURL(){}function debugShowErrors(){}function debugVideoCaptureIsActive(){return!1}function debugVideoCaptureStart(){}function debugVideoCaptureStop(){}function debugVideoCaptureUpdate(){}const PI=Math.PI;function abs(a){return Math.abs(a)}function min(...a){return Math.min(...a)}function max(...a){return Math.max(...a)}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):0}function lerp(a,b,c){0<=a&&1>=a&&(0>b||1<b)&&(0>c||1<c)&&console.warn("lerp() parameter order changed! use lerp(start, end, p)");return a+clamp(c)*(b-a)}function percentLerp(a,b,c,d,e){return lerp(d,e,percent(a,b,c))}function distanceWrap(a,b,c=1){a=(a-b)%c;return 2*a%c-a}function lerpWrap(a,b,c,d=1){0<=a&&1>=a&&(0>b||1<b)&&(0>c||1<c)&&console.warn("lerpWrap() parameter order changed! use lerpWrap(start, end, p)");return a+clamp(c)*distanceWrap(b,a,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 isPowerOfTwo(a){return!(a&a-1)}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 isIntersecting(a,b,c,d){c=c.subtract(d.scale(.5));d=c.add(d);b=b.subtract(a);c=a.subtract(c);d=a.subtract(d);a=[-b.x,b.x,-b.y,b.y];b=[c.x,-d.x,c.y,-d.y];c=0;d=1;for(let e=4;e--;)if(a[e]){const f=b[e]/a[e];if(0>a[e]){if(f>d)return!1;c=max(f,c)}else{if(f<c)return!1;d=min(f,d)}}else if(0>b[e])return!1;return!0}function wave(a=1,b=1,c=time,d=0){return b/2*(1-Math.cos(d+c*a*2*PI))}function formatTime(a){return(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0)}async function fetchJSON(a){return(await fetch(a)).json()}function isNumber(a){return"number"===typeof a&&!isNaN(a)}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return Math.floor(rand(a,b))}function randBool(a=.5){return rand()<a}function randSign(){return 2*randInt(2)-1}function randVec2(a=1){return(new Vector2).setAngle(rand(2*PI),a)}function randInCircle(a=1,b=0){return 0<a?randVec2(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=123456789){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+(this.seed>>>0)/2**32*(a-b)}int(a,b=0){return Math.floor(this.float(a,b))}bool(a=.5){return this.float()<a}sign(){return.5<this.float()?1:-1}floatSign(a=1,b=0){return this.float(a,b)*this.sign()}angle(){return this.float(-PI,PI)}vec2(a=1,b=0){return vec2(this.float(a,b),this.float(a,b))}}function vec2(a=0,b){return new Vector2(a,void 0===b?a:b)}function isVector2(a){return a instanceof Vector2&&a.isValid()}function ASSERT_VECTOR2_VALID(a){ASSERT(isVector2(a),"Vector2 is invalid.",a)}function ASSERT_NUMBER_VALID(a){ASSERT(isNumber(a),"Number is invalid.",a)}function ASSERT_VECTOR2_NORMAL(a){ASSERT_VECTOR2_VALID(a);ASSERT(.01>abs(a.lengthSquared()-1),"Vector2 is not normal.",a)}class Vector2{constructor(a=0,b=0){this.x=a;this.y=b;ASSERT(this.isValid(),"Constructed Vector2 is invalid.",this)}set(a=0,b=0){this.x=a;this.y=b;return this}copy(){return new Vector2(this.x,this.y)}add(a){return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){return new Vector2(this.x*a.x,this.y*a.y)}divide(a){return new Vector2(this.x/a.x,this.y/a.y)}scale(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){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector2(0,a)}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this}dot(a){return this.x*a.x+this.y*a.y}cross(a){return this.x*a.y-this.y*a.x}reflect(a,b=1){return this.subtract(a.scale((1+b)*this.dot(a)))}angle(){return Math.atan2(this.x,this.y)}setAngle(a=0,b=1){ASSERT_NUMBER_VALID(a);ASSERT_NUMBER_VALID(b);this.x=b*Math.sin(a);this.y=b*Math.cos(a);return this}rotate(a){ASSERT_NUMBER_VALID(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_NUMBER_VALID(a);ASSERT_NUMBER_VALID(b);a=mod(a,4);ASSERT(0===a||1===a||2===a||3===a,"Vector2.setDirection() direction must be an integer between 0 and 3.");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)}abs(){return new Vector2(abs(this.x),abs(this.y))}floor(){return new Vector2(Math.floor(this.x),Math.floor(this.y))}mod(a=1){return new Vector2(mod(this.x,a),mod(this.y,a))}area(){return abs(this.x*this.y)}lerp(a,b){ASSERT_VECTOR2_VALID(a);ASSERT_NUMBER_VALID(b);b=clamp(b);return new Vector2(a.x*b+this.x*(1-b),a.y*b+this.y*(1-b))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}toString(a=3){ASSERT_NUMBER_VALID(a);if(debug)return this.isValid()?`(${(0>this.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`:`(${this.x}, ${this.y})`}isValid(){return isNumber(this.x)&&isNumber(this.y)}}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&&a.isValid()}function ASSERT_COLOR_VALID(a){ASSERT(isColor(a),"Color is invalid.",a)}class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d;ASSERT(this.isValid(),"Constructed Color is invalid.",this)}set(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d;return this}copy(){return new Color(this.r,this.g,this.b,this.a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){ASSERT_COLOR_VALID(a);ASSERT_NUMBER_VALID(b);b=clamp(b);return new Color(a.r*b+this.r*(1-b),a.g*b+this.g*(1-b),a.b*b+this.b*(1-b),a.a*b+this.a*(1-b))}setHSLA(a=0,b=0,c=1,d=1){a=mod(a,1);b=clamp(b);c=clamp(c);b=.5>c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,g,h)=>1>6*(h=mod(h,1))?f+6*(g-f)*h:1>2*h?g:2>3*h?f+(g-f)*(4-6*h):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;ASSERT_COLOR_VALID(this);return this}HSLA(){const a=clamp(this.r),b=clamp(this.g),c=clamp(this.b),d=clamp(this.a),e=max(a,b,c),f=min(a,b,c),g=(e+f)/2;let h=0,k=0;if(e!==f){let l=e-f;k=.5<g?l/(2-e-f):l/(e+f);a===e?h=(b-c)/l+(b<c?6:0):b===e?h=(c-a)/l+2:c===e&&(h=(a-b)/l+4)}return[h/6,k,g,d]}mutate(a=.05,b=0){ASSERT_NUMBER_VALID(a);ASSERT_NUMBER_VALID(b);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){ASSERT("boolean"===typeof a,"Use alpha boolean is invalid.",a);if(debug&&!this.isValid())return"#000";const b=c=>(16>(c=255*clamp(c)|0)?"0":"")+c.toString(16);return"#"+b(this.r)+b(this.g)+b(this.b)+(a?b(this.a):"")}setHex(a){ASSERT("string"===typeof a&&"#"===a[0],"Color hex code must be a string starting with #");ASSERT([4,5,7,9].includes(a.length),"Invalid hex");6>a.length?(this.r=clamp(parseInt(a[1],16)/15),this.g=clamp(parseInt(a[2],16)/15),this.b=clamp(parseInt(a[3],16)/15),this.a=5===a.length?clamp(parseInt(a[4],16)/15):1):(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=9===a.length?clamp(parseInt(a.slice(7,9),16)/255):1);ASSERT_COLOR_VALID(this);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}isValid(){return isNumber(this.r)&&isNumber(this.g)&&isNumber(this.b)&&isNumber(this.a)}}const WHITE=rgb(),CLEAR_WHITE=rgb(1,1,1,0),BLACK=rgb(0,0,0),CLEAR_BLACK=rgb(0,0,0,0),GRAY=rgb(.5,.5,.5),RED=rgb(1,0,0),ORANGE=rgb(1,.5,0),YELLOW=rgb(1,1,0),GREEN=rgb(0,1,0),CYAN=rgb(0,1,1),BLUE=rgb(0,0,1),PURPLE=rgb(.5,0,1),MAGENTA=rgb(1,0,1);class Timer{constructor(a){ASSERT(void 0===a||isNumber(a),"Constructed Timer is invalid.",a);this.time=void 0===a?void 0:time+a;this.setTime=a}set(a=0){ASSERT(isNumber(a),"Timer is invalid.",a);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()?1-percent(this.time-time,0,this.setTime):0}getSetTime(){return this.isSet()?this.setTime: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(),cameraAngle=0,cameraScale=32,canvasColorTiles=!0,canvasClearColor=CLEAR_BLACK,canvasMaxSize=vec2(1920,1080),canvasFixedSize=vec2(),canvasPixelated=!0,overlayCanvasPixelated=!1,tilesPixelated=!0,fontDefault="arial",showSplashScreen=!1,headlessMode=!1,glEnable=!0,glCircleSides=32,tileSizeDefault=vec2(16),tileFixBleedScale=0,enablePhysicsSolver=!0,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultRestitution=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=vec2(),particleEmitRateScale=1,gamepadsEnable=!0,gamepadDirectionEmulateStick=!0,inputWASDEmulateDirection=!0,touchInputEnable=!0,touchGamepadEnable=!1,touchGamepadAnalog=!0,touchGamepadSize=99,touchGamepadAlpha=.3,vibrateEnable=!0,soundEnable=!0,soundVolume=.3,soundDefaultRange=40,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalsPreventUnlock=!1;function setCameraPos(a){cameraPos=a}function setCameraAngle(a){cameraAngle=a}function setCameraScale(a){cameraScale=a}function setCanvasColorTiles(a){canvasColorTiles=a}function setCanvasClearColor(a){canvasClearColor=a}function setCanvasMaxSize(a){canvasMaxSize=a}function setCanvasFixedSize(a){canvasFixedSize=a}function setCanvasPixelated(a){canvasPixelated=a;mainCanvas&&(mainCanvas.style.imageRendering=a?"pixelated":"");glCanvas&&(glCanvas.style.imageRendering=a?"pixelated":"")}function setOverlayCanvasPixelated(a){overlayCanvasPixelated=a;overlayCanvas&&(overlayCanvas.style.imageRendering=a?"pixelated":"")}function setTilesPixelated(a){tilesPixelated=a}function setFontDefault(a){fontDefault=a}function setShowSplashScreen(a){showSplashScreen=a}function setHeadlessMode(a){headlessMode=a}function setGLEnable(a){glEnable=a;glCanvas&&(glCanvas.style.visibility=a?"visible":"hidden")}function setGLCircleSides(a){glCircleSides=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 setObjectDefaultRestitution(a){objectDefaultRestitution=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 setTouchInputEnable(a){touchInputEnable=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;soundEnable&&!headlessMode&&audioMasterGain&&(audioMasterGain.gain.value=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 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=new Color,f=0){ASSERT(isVector2(a),"object pos should be a vec2");ASSERT(isVector2(b),"object size should be a vec2");ASSERT(!c||c instanceof TileInfo,"object tileInfo should be a TileInfo or undefined");ASSERT("number"===typeof d&&isFinite(d),"object angle should be a number");ASSERT(isColor(e),"object color should be a valid rgba color");ASSERT("number"===typeof f,"object renderOrder should be a number");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.restitution=objectDefaultRestitution;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=f;this.velocity=vec2();this.angleVelocity=0;this.spawnTime=time;this.children=[];this.clampSpeed=!0;this.parent=this.groundObject=void 0;this.localPos=vec2();this.localAngle=0;this.collideRaycast=this.isSolid=this.collideSolidObjects=this.collideTiles=!1;engineObjects.push(this)}updateTransforms(){const a=this.parent;if(a){const b=a.getMirrorSign();this.pos=this.localPos.multiply(vec2(b,1)).rotate(a.angle).add(a.pos);this.angle=b*this.localAngle+a.angle}for(const b of this.children)b.updateTransforms()}update(){if(!this.parent){this.clampSpeed&&(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed));var a=this.pos.copy();this.velocity.x*=this.damping;this.velocity.y*=this.damping;this.mass&&(this.velocity.x+=gravity.x*this.gravityScale,this.velocity.y+=gravity.y*this.gravityScale);this.pos.x+=this.velocity.x;this.pos.y+=this.velocity.y;this.angle+=this.angleVelocity*=this.angleDamping;ASSERT(0<=this.angleDamping&&1>=this.angleDamping);ASSERT(0<=this.damping&&1>=this.damping);if(enablePhysicsSolver&&this.mass){var b=0>this.velocity.y;if(this.groundObject){var c=max(this.friction,this.groundObject.friction),d=this.groundObject.velocity?this.groundObject.velocity.x:0;this.velocity.x=d+(this.velocity.x-d)*c;this.groundObject=void 0}if(this.collideSolidObjects)for(var e of engineObjectsCollide){if(!this.isSolid&&!e.isSolid||e.destroyed||e.parent||e===this)continue;if(!isOverlapping(this.pos,this.size,e.pos,e.size))continue;c=this.collideWithObject(e);d=e.collideWithObject(this);if(!c||!d)continue;if(isOverlapping(a,this.size,e.pos,e.size)){c=a.subtract(e.pos);d=c.length();c=.01>d?randVec2(.001):c.scale(.001/d);this.velocity=this.velocity.add(c);e.mass&&(e.velocity=e.velocity.subtract(c));debugPhysics&&debugOverlap(this.pos,this.size,e.pos,e.size,"#f00");continue}d=this.size.add(e.size);var f=2*(a.y-e.pos.y)>d.y+gravity.y;const h=2*abs(a.y-e.pos.y)<d.y;var g=2*abs(a.x-e.pos.x)<d.x;c=max(this.restitution,e.restitution);if(f||g||!h)if(this.pos.y=e.pos.y+(d.y/2+.001)*sign(a.y-e.pos.y),e.groundObject&&b||!e.mass)b&&(this.groundObject=e),this.velocity.y*=-c;else if(e.mass){g=(this.mass*this.velocity.y+e.mass*e.velocity.y)/(this.mass+e.mass);const k=e.velocity.y*(e.mass-this.mass)/(this.mass+e.mass)+2*this.velocity.y*this.mass/(this.mass+e.mass);this.velocity.y=lerp(g,this.velocity.y*(this.mass-e.mass)/(this.mass+e.mass)+2*e.velocity.y*e.mass/(this.mass+e.mass),c);e.velocity.y=lerp(g,k,c)}!f&&h&&(this.pos.x=e.pos.x+(d.x/2+.001)*sign(a.x-e.pos.x),e.mass?(d=(this.mass*this.velocity.x+e.mass*e.velocity.x)/(this.mass+e.mass),f=e.velocity.x*(e.mass-this.mass)/(this.mass+e.mass)+2*this.velocity.x*this.mass/(this.mass+e.mass),this.velocity.x=lerp(d,this.velocity.x*(this.mass-e.mass)/(this.mass+e.mass)+2*e.velocity.x*e.mass/(this.mass+e.mass),c),e.velocity.x=lerp(d,f,c)):this.velocity.x*=-c);debugPhysics&&debugOverlap(this.pos,this.size,e.pos,e.size,"#f0f")}if(this.collideTiles&&(e=tileCollisionTest(this.pos,this.size,this))&&!tileCollisionTest(a,this.size,this)){d=tileCollisionTest(vec2(a.x,this.pos.y),this.size,this);c=tileCollisionTest(vec2(this.pos.x,a.y),this.size,this);if(d||!c)d=max(this.restitution,e.restitution),this.velocity.y*=-d,b?(this.pos.y=(a.y-this.size.y/2|0)+this.size.y/2+1e-4,this.groundObject=e):(this.pos.y=a.y,this.groundObject=void 0);c&&(this.pos.x=a.x,this.velocity.x*=-this.restitution);debugPhysics&&debugRect(this.pos,this.size,"#f00")}}}}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.parent=0,a.destroy()}}localToWorld(a){return this.pos.add(a.rotate(this.angle))}worldToLocal(a){return a.subtract(this.pos).rotate(-this.angle)}localToWorldVector(a){return a.rotate(this.angle)}worldToLocalVector(a){return a.rotate(-this.angle)}collideWithTile(a,b){return 0<a}collideWithObject(a){return!0}getAliveTime(){return time-this.spawnTime}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyAngularAcceleration(a){this.mass&&(this.angleVelocity+=a)}applyForce(a){this.mass&&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,d=!0){ASSERT(a||!b,"solid objects must be set to collide");this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c;this.collideRaycast=d}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}}renderDebugInfo(){if(debug){var a=vec2(max(this.size.x,.2),max(this.size.y,.2)),b=rgb(this.collideTiles?1:0,this.collideSolidObjects?1:0,this.isSolid?1:0,.5);drawRect(this.pos,a,b,this.angle);this.parent&&drawRect(this.pos,a.scale(.8),rgb(1,1,1,.5),this.angle);this.parent&&drawLine(this.pos,this.parent.pos,.1,rgb(1,1,1,.5))}}}let mainCanvas,mainContext,overlayCanvas,overlayContext,drawCanvas,drawContext,workCanvas,workContext,mainCanvasSize=vec2(),textureInfos=[],drawCount;function tile(a=new Vector2,b=tileSizeDefault,c=0,d=0){if(headlessMode)return new TileInfo;"number"===typeof b&&(ASSERT(0<b),b=new Vector2(b,b));const e=new TileInfo(new Vector2,b,c,d);var f=textureInfos[c];ASSERT(!!f,"Texture not loaded");c=b.x+2*d;b=b.y+2*d;"number"===typeof a?(f=f.size.x/c|0,ASSERT(0<f,"Tile size is too big for texture"),e.pos.set(a%f*c+d,(a/f|0)*b+d)):e.pos.set(a.x*c+d,a.y*b+d);return e}class TileInfo{constructor(a=vec2(),b=tileSizeDefault,c=0,d=0,e=tileFixBleedScale){this.pos=a.copy();this.size=b.copy();this.textureIndex=c;this.padding=d;this.textureInfo=textureInfos[this.textureIndex];this.bleedScale=e}offset(a){return new TileInfo(this.pos.add(a),this.size,this.textureIndex,this.padding,this.bleedScale)}frame(a){ASSERT("number"===typeof a);return this.offset(new Vector2(a*(this.size.x+2*this.padding),0))}setFullImage(a,b){this.pos=new Vector2;this.size=new Vector2(a.width,a.height);this.textureInfo=new TextureInfo(a,b);this.bleedScale=this.padding=0;return this}}class TextureInfo{constructor(a,b){this.image=a;this.size=vec2(a.width,a.height);this.sizeInverse=vec2(1/a.width,1/a.height);this.glTexture=b}createWebGLTexture(){ASSERT(!this.glTexture);glEnable&&(this.glTexture=glCreateTexture(this.image))}}function drawTile(a,b=new Vector2(1),c,d=WHITE,e=0,f,g,h=glEnable,k,l){ASSERT(isVector2(a),"drawTile pos should be a vec2");ASSERT(isVector2(b),"drawTile size should be a vec2");ASSERT(isColor(d)&&(!g||isColor(g)),"drawTile color is invalid");ASSERT(isNumber(e),"drawTile angle should be a number");ASSERT(!l||!h,"context only supported in canvas 2D mode");const m=c&&c.textureInfo,n=c?c.bleedScale:0;if(h)if(k&&(a=screenToWorld(a),b=b.scale(1/cameraScale)),m){var p=m.sizeInverse;h=c.pos.x*p.x;k=c.pos.y*p.y;l=c.size.x*p.x;const r=c.size.y*p.y;glSetTexture(m.glTexture);if(n){const q=p.x*n;p=p.y*n;glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h+q,k+p,h-q+l,k-p+r,d.rgbaInt(),g&&g.rgbaInt())}else glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h,k,h+l,k+r,d.rgbaInt(),g&&g.rgbaInt())}else glDraw(a.x,a.y,b.x,b.y,e,0,0,0,0,0,d.rgbaInt());else++drawCount,b=new Vector2(b.x,-b.y),drawCanvas2D(a,b,e,f,r=>{if(m)drawImageColor(r,m.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1,d,g,n);else{const q=g?d.add(g):d;r.fillStyle=q.toString();r.fillRect(-.5,-.5,1,1)}},k,l)}function drawRect(a,b,c,d,e,f,g){drawTile(a,b,void 0,c,d,!1,void 0,e,f,g)}function drawRectGradient(a,b,c=WHITE,d=BLACK,e=0,f=glEnable,g=!1,h){ASSERT(isVector2(a),"drawRectGradient pos should be a vec2");ASSERT(isVector2(b),"drawRectGradient size should be a vec2");ASSERT(isColor(c)&&isColor(d),"drawRectGradient color is invalid");ASSERT(isNumber(e),"drawRectGradient angle should be a number");ASSERT(!h||!f,"context only supported in canvas 2D mode");if(f){g&&(a=screenToWorld(a),b=b.scale(1/cameraScale));f=[];g=[];h=b.x/2;b=b.y/2;const k=c.rgbaInt(),l=d.rgbaInt(),m=Math.cos(-e);e=Math.sin(-e);for(let n=4;n--;){const p=n&1?h:-h,r=n&2?b:-b,q=n&2?k:l;f.push(vec2(a.x+(p*m-r*e),a.y+(p*e+r*m)));g.push(q)}glDrawColoredPoints(f,g)}else++drawCount,b=new Vector2(b.x,-b.y),drawCanvas2D(a,b,e,!1,k=>{const l=k.createLinearGradient(0,-.5,0,.5);l.addColorStop(0,c.toString());l.addColorStop(1,d.toString());k.fillStyle=l;k.fillRect(-.5,-.5,1,1)},g,h)}function drawLineList(a,b=.1,c,d=!1,e=vec2(),f=0,g=glEnable,h,k){ASSERT(Array.isArray(a),"drawLineList points should be an array");ASSERT(isNumber(b),"drawLineList width should be a number");ASSERT(isColor(c),"drawLineList color is invalid");ASSERT(isVector2(e),"drawLineList pos should be a vec2");ASSERT(isNumber(f),"drawLineList angle should be a number");ASSERT(!k||!g,"context only supported in canvas 2D mode");g?(g=1,h&&(e=screenToWorld(e),g=1/cameraScale),glDrawOutlineTransform(a,c.rgbaInt(),b,e.x,e.y,g,g,f,d)):(++drawCount,drawCanvas2D(e,vec2(1),f,!1,l=>{l.strokeStyle=c.toString();l.lineWidth=b;l.beginPath();for(let m=0;m<a.length;++m){const n=a[m];m?l.lineTo(n.x,n.y):l.moveTo(n.x,n.y)}d&&l.closePath();l.stroke()},h,k))}function drawLine(a,b,c=.1,d,e=vec2(),f=0,g,h,k){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());e=e.add(a.add(b));f+=b.angle();drawRect(e,c,d,f,g,h,k)}function drawRegularPoly(a,b=vec2(1),c=3,d=WHITE,e=0,f=BLACK,g=0,h=glEnable,k=!1,l){ASSERT(isVector2(b),"drawRegularPoly size should be a vec2");ASSERT(isNumber(c),"drawRegularPoly sides should be a number");const m=[],n=b.x/2;b=b.y/2;for(let p=c;p--;){const r=p/c*PI*2;m.push(vec2(Math.sin(r)*n,Math.cos(r)*b))}drawPoly(m,d,e,f,a,g,h,k,l)}function drawPoly(a,b=WHITE,c=0,d=BLACK,e=vec2(),f=0,g=glEnable,h=!1,k){ASSERT(isVector2(e),"drawPoly pos should be a vec2");ASSERT(Array.isArray(a),"drawPoly points should be an array");ASSERT(isColor(b)&&isColor(d),"drawPoly color is invalid");ASSERT(isNumber(c),"drawPoly lineWidth should be a number");ASSERT(isNumber(f),"drawPoly angle should be a number");ASSERT(!k||!g,"context only supported in canvas 2D mode");g?(g=1,h&&(e=screenToWorld(e),g=1/cameraScale),glDrawPointsTransform(a,b.rgbaInt(),e.x,e.y,g,g,f),0<c&&glDrawOutlineTransform(a,d.rgbaInt(),c,e.x,e.y,g,g,f)):drawCanvas2D(e,vec2(1),f,!1,l=>{l.fillStyle=b.toString();l.beginPath();for(const m of a)l.lineTo(m.x,m.y);l.closePath();l.fill();c&&(l.strokeStyle=d.toString(),l.lineWidth=c,l.stroke())},h,k)}function drawEllipse(a,b=vec2(1),c=WHITE,d=0,e=0,f=BLACK,g=glEnable,h=!1,k){ASSERT(isVector2(a),"drawEllipse pos should be a vec2");ASSERT(isVector2(b),"drawEllipse size should be a vec2");ASSERT(isColor(c)&&isColor(f),"drawEllipse color is invalid");ASSERT(isNumber(d),"drawEllipse angle should be a number");ASSERT(isNumber(e),"drawEllipse lineWidth should be a number");ASSERT(0<=e&&e<b.x&&e<b.y,"drawEllipse invalid lineWidth");ASSERT(!k||!g,"context only supported in canvas 2D mode");g?drawRegularPoly(a,b,glCircleSides,c,e,f,d,g,h,k):drawCanvas2D(a,vec2(1),d,!1,l=>{l.fillStyle=c.toString();l.beginPath();l.ellipse(0,0,b.x/2,b.y/2,0,0,9);l.fill();e&&(l.strokeStyle=f.toString(),l.lineWidth=e,l.stroke())},h,k)}function drawCircle(a,b=1,c=WHITE,d=0,e=BLACK,f=glEnable,g=!1,h){ASSERT(isNumber(b),"drawCircle size should be a number");drawEllipse(a,vec2(b),c,0,d,e,f,g,h)}function drawCanvas2D(a,b,c=0,d=!1,e,f=!1,g=drawContext){f||(a=worldToScreen(a),b=b.scale(cameraScale));g.save();g.translate(a.x+.5,a.y+.5);g.rotate(c-cameraAngle);g.scale(d?-b.x:b.x,-b.y);e(g);g.restore()}function drawText(a,b,c=1,d,e=0,f,g,h,k,l=drawContext){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,h,k,l)}function drawTextOverlay(a,b,c=1,d,e=0,f,g,h,k){drawText(a,b,c,d,e,f,g,h,k,overlayContext)}function drawTextScreen(a,b,c=1,d=WHITE,e=0,f=BLACK,g="center",h=fontDefault,k,l=overlayContext){l.fillStyle=d.toString();l.strokeStyle=f.toString();l.lineWidth=e;l.textAlign=g;l.font=c+"px "+h;l.textBaseline="middle";a=(a+"").split("\n");let m=b.y;m-=(a.length-1)*c/2;a.forEach(n=>{e&&l.strokeText(n,b.x,m,k);l.fillText(n,b.x,m,k);m+=c})}function screenToWorld(a){let b=(a.x-mainCanvasSize.x/2+.5)/cameraScale;a=(a.y-mainCanvasSize.y/2+.5)/-cameraScale;if(cameraAngle){const c=Math.cos(-cameraAngle),d=Math.sin(-cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b+cameraPos.x,a+cameraPos.y)}function worldToScreen(a){let b=a.x-cameraPos.x;a=a.y-cameraPos.y;if(cameraAngle){const c=Math.cos(cameraAngle),d=Math.sin(cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b*cameraScale+mainCanvasSize.x/2-.5,a*-cameraScale+mainCanvasSize.y/2-.5)}function getCameraSize(){return mainCanvasSize.scale(1/cameraScale)}function setBlendMode(a=!1,b){glAdditive=a;b||=drawContext;b.globalCompositeOperation=a?"lighter":"source-over"}function combineCanvases(){glCopyToContext(mainContext);mainContext.drawImage(overlayCanvas,0,0);glClearCanvas();overlayCanvas.width|=0}function drawImageColor(a,b,c,d,e,f,g,h,k,l,m,n,p=0){function r(t){return 1<=t.r&&1<=t.g&&1<=t.b}const q=e-2*p,u=f-2*p;if(!canvasColorTiles||(n?r(m.add(n))&&0>=n.a:r(m)))a.globalAlpha=m.a,a.drawImage(b,c+p,d+p,q,u,g,h,k,l),a.globalAlpha=1;else if(workCanvas.width=e,workCanvas.height=f,workContext.drawImage(b,c,d,e,f,0,0,e,f),b=workContext.getImageData(0,0,e,f),c=b.data,!n||0>=n.r&&0>=n.g&&0>=n.b&&0>=n.a){for(n=0;n<c.length;n+=4)c[n]*=m.r,c[n+1]*=m.g,c[n+2]*=m.b;workContext.putImageData(b,0,0);a.globalAlpha=m.a;a.drawImage(workCanvas,p,p,q,u,g,h,k,l);a.globalAlpha=1}else{m=[m.r,m.g,m.b,m.a];n=[255*n.r,255*n.g,255*n.b,255*n.a];for(d=0;d<c.length;++d)c[d]=c[d]*m[d&3]+n[d&3]|0;workContext.putImageData(b,0,0);a.drawImage(workCanvas,p,p,q,u,g,h,k,l)}}function isFullscreen(){return!!document.fullscreenElement}function toggleFullscreen(){const a=mainCanvas.parentElement;isFullscreen()?document.exitFullscreen&&document.exitFullscreen():a.requestFullscreen&&a.requestFullscreen()}function setCursor(a="auto"){mainCanvas.parentElement.style.cursor=a}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d){engineFontImage||(engineFontImage=new Image,engineFontImage.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC");this.image=a||engineFontImage;this.tileSize=b;this.paddingSize=c}drawText(a,b,c=1,d,e=drawContext){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d,e)}drawTextOverlay(a,b,c=4,d){this.drawText(a,b,c,d,overlayContext)}drawTextScreen(a,b,c=4,d,e=overlayContext){e.save();const f=this.tileSize,g=f.add(this.paddingSize).scale(c),h=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((k,l)=>{const m=d?k.length*f.x*c/2|0:0;for(let r=k.length;r--;){var n=k[r].charCodeAt(0);if(32>n||127<n)n=127;var p=n-32;n=p%h;p=p/h|0;const q=b.add(vec2(r,l).multiply(g));e.drawImage(this.image,n*f.x,p*f.y,f.x,f.y,q.x-m,q.y,f.x*c,f.y*c)}});e.restore()}}function keyIsDown(a,b=0){ASSERT(void 0!==a,"key is undefined");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(void 0!==a,"key is undefined");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(void 0!==a,"key is undefined");ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&4)}function keyDirection(a="ArrowUp",b="ArrowDown",c="ArrowLeft",d="ArrowRight"){return vec2((keyIsDown(d)?1:0)-(keyIsDown(c)?1:0),(keyIsDown(a)?1:0)-(keyIsDown(b)?1:0))}function inputClear(){inputData=[[]];touchGamepadButtons=[]}function inputClearKey(a,b=0,c=!0,d=!0,e=!0){inputData[b]&&(inputData[b][a]&=~((c?1:0)|(d?2:0)|(e?4:0)))}function mouseIsDown(a){return keyIsDown(a)}function mouseWasPressed(a){return keyWasPressed(a)}function mouseWasReleased(a){return keyWasReleased(a)}let mousePos=vec2(),mousePosScreen=vec2(),mouseDelta=vec2(),mouseDeltaScreen=vec2(),mouseWheel=0,isUsingGamepad=!1,inputPreventDefault=!0;function setInputPreventDefault(a){inputPreventDefault=a}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 gamepadStickData[b]?gamepadStickData[b][a]||vec2():vec2()}let inputData=[[]];function inputUpdate(){headlessMode||(touchInputEnable&&isTouchDevice||document.hasFocus()||inputClear(),mousePos=screenToWorld(mousePosScreen),mouseDelta=mouseDeltaScreen.multiply(vec2(1,-1)).rotate(-cameraAngle),gamepadsUpdate())}function inputUpdatePost(){if(!headlessMode){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=0;mouseDelta=vec2();mouseDeltaScreen=vec2()}}function inputInit(){function a(b){return inputWASDEmulateDirection?"KeyW"===b?"ArrowUp":"KeyS"===b?"ArrowDown":"KeyA"===b?"ArrowLeft":"KeyD"===b?"ArrowRight":b:b}headlessMode||(document.addEventListener("keydown",function(b){b.repeat||(isUsingGamepad=!1,inputData[0][b.code]=3,inputWASDEmulateDirection&&(inputData[0][a(b.code)]=3))}),document.addEventListener("keyup",function(b){inputData[0][b.code]=inputData[0][b.code]&2|4;inputWASDEmulateDirection&&(inputData[0][a(b.code)]=4)}),document.addEventListener("mousedown",function(b){isTouchDevice&&touchInputEnable||(soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioContext.resume(),isUsingGamepad=!1,inputData[0][b.button]=3,mousePosScreen=mouseEventToScreen(vec2(b.x,b.y)),inputPreventDefault&&b.button&&b.preventDefault())}),document.addEventListener("mouseup",function(b){isTouchDevice&&touchInputEnable||(inputData[0][b.button]=inputData[0][b.button]&2|4)}),document.addEventListener("mousemove",function(b){mousePosScreen=mouseEventToScreen(vec2(b.x,b.y));mouseDeltaScreen=mouseDeltaScreen.add(vec2(b.movementX,b.movementY))}),document.addEventListener("wheel",function(b){mouseWheel=b.ctrlKey?0:sign(b.deltaY)}),document.addEventListener("contextmenu",function(b){b.preventDefault()}),document.addEventListener("blur",function(){inputClear()}),isTouchDevice&&touchInputEnable&&touchInputInit())}function mouseEventToScreen(a){const b=mainCanvas.getBoundingClientRect(),c=percent(a.x,b.left,b.right);a=percent(a.y,b.top,b.bottom);return vec2(c*mainCanvas.width,a*mainCanvas.height)}const gamepadStickData=[];function gamepadsUpdate(){const a=g=>{const h=k=>.3<k?percent(k,.3,.8):-.3>k?-percent(-k,.3,.8):0;return vec2(h(g.x),h(-g.y)).clampLength()};if(touchGamepadEnable&&isTouchDevice){if(!touchGamepadTimer.isSet())return;var b=gamepadStickData[0]||(gamepadStickData[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,e=gamepadIsDown(d,0);b[d]=touchGamepadButtons[c]?e?1:3:e?4:0}}if(gamepadsEnable&&navigator&&navigator.getGamepads&&(debug||document.hasFocus()))for(b=navigator.getGamepads(),c=b.length;c--;){e=b[c];const g=inputData[c+1]||(inputData[c+1]=[]);d=gamepadStickData[c]||(gamepadStickData[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 h=e.buttons[f],k=gamepadIsDown(f,c);g[f]=h.pressed?k?1:3:k?4:0;(!h.value||.9<h.value)&&!c&&h.pressed&&(isUsingGamepad=!0)}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&&!headlessMode&&navigator&&navigator.vibrate&&navigator.vibrate(a)}function vibrateStop(){vibrate(0)}const isTouchDevice=!headlessMode&&void 0!==window.ontouchstart;let touchGamepadTimer=new Timer,touchGamepadButtons=[],touchGamepadStick=vec2();function touchInputInit(){let a=function(c){if(touchInputEnable){if(touchGamepadEnable)a:{touchGamepadStick=vec2();touchGamepadButtons=[];isUsingGamepad=!0;if(c.touches.length&&(touchGamepadTimer.set(),paused&&!b)){touchGamepadButtons[9]=1;break a}var d=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),e=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),f=mainCanvasSize.scale(.5);for(const h of c.touches){var g=mouseEventToScreen(vec2(h.clientX,h.clientY));g.distance(d)<touchGamepadSize?touchGamepadStick=g.subtract(d).scale(2/touchGamepadSize).clampLength():g.distance(e)<touchGamepadSize?(g=g.subtract(e).direction(),touchGamepadButtons[g]=1):g.distance(f)<touchGamepadSize&&!b&&(touchGamepadButtons[9]=1)}}soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioContext.resume();(d=c.touches.length)?(e=vec2(c.touches[0].clientX,c.touches[0].clientY),f=mousePosScreen,mousePosScreen=mouseEventToScreen(e),b?(mouseDeltaScreen=mouseDeltaScreen.add(mousePosScreen.subtract(f)),isUsingGamepad=touchGamepadEnable):inputData[0][0]=3):b&&(inputData[0][0]=inputData[0][0]&2|4);b=d;inputPreventDefault&&document.hasFocus()&&c.preventDefault();return!0}};document.addEventListener("touchstart",c=>a(c),{passive:!1});document.addEventListener("touchmove",c=>a(c),{passive:!1});document.addEventListener("touchend",c=>a(c),{passive:!1});let b}function touchGamepadRender(){if(touchInputEnable&&isTouchDevice&&!headlessMode&&touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer.get(),4,3);if(a&&!paused){var b=overlayContext;b.save();b.globalAlpha=a*touchGamepadAlpha;b.strokeStyle="#fff";b.lineWidth=3;b.fillStyle=0<touchGamepadStick.lengthSquared()?"#fff":"#000";b.beginPath();a=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize);if(touchGamepadAnalog)b.arc(a.x,a.y,touchGamepadSize/2,0,9),b.fill();else for(var c=10;c--;){var d=c*PI/4;b.arc(a.x,a.y,.6*touchGamepadSize,d+PI/8,d+PI/8);c%2&&b.arc(a.x,a.y,.33*touchGamepadSize,d,d);1===c&&b.fill()}b.stroke();a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);for(c=4;c--;)d=a.add(vec2().setDirection(c,touchGamepadSize/2)),b.fillStyle=touchGamepadButtons[c]?"#fff":"#000",b.beginPath(),b.arc(d.x,d.y,touchGamepadSize/4,0,9),b.fill(),b.stroke();b.restore()}}}function pointerLockRequest(){isTouchDevice||mainCanvas.requestPointerLock&&mainCanvas.requestPointerLock()}function pointerLockExit(){document.exitPointerLock&&document.exitPointerLock()}function pointerLockIsActive(){return document.pointerLockElement===mainCanvas}let audioContext=new AudioContext,audioMasterGain;const audioDefaultSampleRate=44100;function audioIsRunning(){return"running"===audioContext.state}function audioInit(){soundEnable&&!headlessMode&&(audioMasterGain=audioContext.createGain(),audioMasterGain.connect(audioContext.destination),audioMasterGain.gain.value=soundVolume)}class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&!headlessMode&&(this.range=b,this.taper=c,this.randomness=0,this.sampleRate=audioDefaultSampleRate,this.loadedPercent=0,a&&(this.randomness=void 0!==a[1]?a[1]:.05,a[1]=0,this.sampleChannels=[zzfxG(...a)],this.loadedPercent=1))}play(a,b=1,c=1,d=1,e=!1,f=!1){if(soundEnable&&!headlessMode&&this.sampleChannels){var g;if(a){if(g=this.range){const h=cameraPos.distanceSquared(a);if(h>g*g)return;b*=percent(h**.5,g,g*this.taper)}g=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return new SoundInstance(this,b,a,g,e,f)}}playMusic(a=1,b=!0,c=!1){return this.play(void 0,a,1,0,b,c)}playNote(a,b,c){a=getNoteFrequency(a,1);return this.play(b,c,a,0)}getDuration(){return this.sampleChannels&&this.sampleChannels[0].length/this.sampleRate}isLoaded(){return 1===this.loadedPercent}}class SoundWave extends Sound{constructor(a,b=0,c,d,e){super(void 0,c,d);soundEnable&&!headlessMode&&(this.onloadCallback=e,this.randomness=b,this.loadSound(a))}async loadSound(a){a=await(await fetch(a)).arrayBuffer();a=await audioContext.decodeAudioData(a);const b=a.numberOfChannels,c=[];for(let d=0;d<b;d++){const e=a.getChannelData(d),f=e.length;c[d]=Array(f);let g=0;for(;g<f;){await new Promise(k=>setTimeout(k,0));const h=min(g+1e5,f);for(;g<h;g++)c[d][g]=e[g];this.loadedPercent=(d*f+g)/(b*f)}}this.sampleRate=a.sampleRate;this.sampleChannels=c;this.loadedPercent=1;if(this.onloadCallback)this.onloadCallback()}}class SoundInstance{constructor(a,b=1,c=1,d=0,e=!1,f=!1){ASSERT(a instanceof Sound,"SoundInstance requires a valid Sound object");ASSERT(0<=b,"Sound volume must be positive or zero");ASSERT(0<=c,"Sound rate must be positive or zero");ASSERT(isNumber(d),"Sound pan must be a number");this.sound=a;this.volume=b;this.rate=c;this.pan=d;this.loop=e;this.pausedTime=0;this.source=this.gainNode=this.startTime=void 0;this.onendedCallback=g=>{g===this.source&&(this.source=void 0)};f||this.start()}start(a=0){ASSERT(0<=a,"Sound start offset must be positive or zero");this.isPlaying()&&this.stop();this.gainNode=audioContext.createGain();this.source=playSamples(this.sound.sampleChannels,this.volume,this.rate,this.pan,this.loop,this.sound.sampleRate,this.gainNode,a,this.onendedCallback);this.startTime=audioContext.currentTime-a;this.pausedTime=void 0}setVolume(a){ASSERT(0<=a,"Sound volume must be positive or zero");this.volume=a;this.gainNode&&(this.gainNode.gain.value=a)}stop(a=0){ASSERT(0<=a,"Sound fade time must be positive or zero");if(this.isPlaying())if(a){const b=audioContext.currentTime;a=b+a;this.gainNode.gain.linearRampToValueAtTime(1,b);this.gainNode.gain.linearRampToValueAtTime(0,a);this.source.stop(a)}else this.source.stop();this.pausedTime=0;this.startTime=this.source=void 0}pause(){this.isPaused()||(this.pausedTime=this.getCurrentTime(),this.source.stop(),this.startTime=this.source=void 0)}resume(){this.isPaused()&&this.start(this.pausedTime)}isPlaying(){return!!this.source}isPaused(){return!this.isPlaying()}getCurrentTime(){const a=mod(audioContext.currentTime-this.startTime,this.getDuration());return this.isPlaying()?a:this.pausedTime}getDuration(){return this.sound.getDuration()/this.rate}getSource(){return this.source}}function speak(a,b="",c=1,d=1,e=1){if(soundEnable&&!headlessMode&&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)}function playSamples(a,b=1,c=1,d=0,e=!1,f=audioDefaultSampleRate,g,h=0,k){if(soundEnable&&!headlessMode){var l=audioContext.createBuffer(a.length,a[0].length,f),m=audioContext.createBufferSource();a.forEach((n,p)=>l.getChannelData(p).set(n));m.buffer=l;m.playbackRate.value=c;m.loop=e;g=g||audioContext.createGain();g.gain.value=b;g.connect(audioMasterGain);a=new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)});m.connect(a).connect(g);k&&m.addEventListener("ended",()=>k(m));if(audioIsRunning())return m.start(0,h*c),m;audioContext.resume()}}function zzfx(...a){return playSamples([zzfxG(...a)])}function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,h=1,k=0,l=0,m=0,n=0,p=0,r=0,q=0,u=0,t=0,w=1,x=0,B=0,z=0){var v=audioDefaultSampleRate;let y=2*PI,D=k*=500*y/v/v;b=c*=(1+rand(b,-b))*y/v;let G=0,J=0,H=0,E=1,K=[],F=0,A=0,C=0,O;var M=y*abs(z)*2/v,L=Math.cos(M),N=Math.sin(M)/2/2,I=1+N;M=-2*L/I;N=(1-N)/I;let P=(1+sign(z)*L)/2/I;L=-(sign(z)+L)/I;let Q=I=0,R=0,S=0;d=d*v||9;x*=v;e*=v;f*=v;t*=v;l*=500*y/v**3;q*=y/v;m*=y/v;n*=v;p=p*v|0;for(v=d+x+e+f+t|0;A<v;K[A++]=C*a)++H%(100*u|0)||(C=g?1<g?2<g?3<g?4<g?F/y%1<h/2?1:-1:Math.sin(F**3):Math.max(Math.min(Math.tan(F),1),-1):1-(2*F/y%2+2)%2:1-4*abs(Math.round(F/y)-F/y):Math.sin(F),C=(p?1-B+B*Math.sin(y*A/p):1)*(4<g?C:sign(C)*abs(C)**h)*(A<d?A/d:A<d+x?1-(A-d)/x*(1-w):A<d+x+e?w:A<v-t?(v-A-t)/f*w:0),C=t?C/2+(t>A?0:(A<v-t?1:(v-A)/t)*K[A-t|0]/2/a):C,z&&(C=S=P*I+L*(I=Q)+P*(Q=C)-N*R-M*(R=S))),O=(c+=k+=l)*Math.cos(q*G++),F+=O+O*r*Math.sin(A**5),E&&++E>n&&(c+=m,b+=m,E=0),!p||++J%p||(c=b,k=D,E||=1);return K}const tileCollisionLayers=[];function tileCollisionGetData(a){for(const b of tileCollisionLayers)if(a.arrayCheck(b.size))return b.getCollisionData(a);return 0}function tileCollisionTest(a,b=vec2(),c,d=!0){for(const e of tileCollisionLayers)if((!d||e.isSolid)&&e.collisionTest(a,b,c))return e}function tileCollisionRaycast(a,b,c,d=!0){for(const e of tileCollisionLayers)if(!d||e.isSolid){const f=e.collisionRaycast(a,b,c);if(f)return f}}function tileCollisionLoad(a,b=tile(),c=0,d,e=!0){a||(a={},a.height=a.width=50,a.layers=[{}],a.layers[0].data=Array(2500).fill(0));ASSERT(a.width&&a.height);ASSERT(a.layers&&a.layers.length);const f=[],g=vec2(a.width,a.height),h=a.layers.length;for(let m=h;m--;){const n=a.layers[m];ASSERT(n.data&&n.data.length);ASSERT(g.area()===n.data.length);var k=c-(h-1-m);k=new TileCollisionLayer(vec2(),g,b,k);f[m]=k;for(let p=g.x;p--;)for(let r=g.y;r--;){const q=vec2(p,g.y-1-r);var l=n.data[p+r*g.x];l&&(l=new TileLayerData(l-1),k.setData(q,l),m===d&&k.setCollisionData(q,1))}e&&k.redraw()}return f}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 CanvasLayer extends EngineObject{constructor(a,b,c=0,d=0,e=vec2(512)){super(a,b,void 0,c,WHITE,d);this.canvas=headlessMode?void 0:new OffscreenCanvas(e.x,e.y);this.context=headlessMode?void 0:this.canvas.getContext("2d");this.glTexture=void 0;this.gravityScale=0}destroy(){this.destroyed||(this.glTexture&&glDeleteTexture(this.glTexture),super.destroy())}render(){this.draw(this.pos,this.size,this.angle,this.color,this.mirror,this.additiveColor)}draw(a,b,c=0,d=WHITE,e=!1,f,g=!1,h){const k=glEnable&&void 0!==this.glTexture,l=(new TileInfo).setFullImage(this.canvas,this.glTexture);drawTile(a,b,l,d,c,e,f,k,g,h)}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 h=c&&c.textureInfo;h?(g.globalAlpha=d.a,g.drawImage(h.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)}useWebGL(a=!0){glEnable&&a?this.glTexture?glSetTextureData(this.glTexture,this.canvas):this.glTexture=glCreateTexture(this.canvas):this.glTexture=void 0}}class TileLayer extends CanvasLayer{constructor(a,b,c=tile(),d=vec2(1),e=0,f=glEnable){super(a,b,0,e,b);this.tileInfo=c;a=b.multiply(c.size);this.canvas=new OffscreenCanvas(a.x,a.y);this.context=this.canvas.getContext("2d");this.glTexture=f?glCreateTexture(this.canvas):void 0;this.restitution=this.friction=0;this.data=[];for(f=this.size.area();f--;)this.data.push(new TileLayerData);headlessMode&&(this.redraw=()=>{},this.render=()=>{},this.redrawStart=()=>{},this.redrawEnd=()=>{},this.drawTileData=()=>{},this.drawCanvas2D=()=>{},this.useWebGL=()=>{})}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]}render(){ASSERT(drawContext!==this.context,"must call redrawEnd() after drawing tiles!");const a=(new TileInfo).setFullImage(this.canvas,this.glTexture),b=this.pos.add(this.size.scale(.5));drawTile(b,this.size,a,WHITE,0,!1,CLEAR_BLACK,glEnable&&void 0!==this.glTexture)}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();this.glTexture&&this.useWebGL()}redrawStart(a=!1){this.savedRenderSettings=[drawCanvas,drawContext,mainCanvasSize,cameraPos,cameraScale];drawCanvas=this.canvas;drawContext=this.context;cameraPos=this.size.scale(.5);cameraScale=this.tileInfo.size.x;mainCanvasSize=this.size.multiply(this.tileInfo.size);a&&(drawCanvas.width=mainCanvasSize.x,drawCanvas.height=mainCanvasSize.y);this.context.imageSmoothingEnabled=!tilesPixelated;glPreRender()}redrawEnd(){ASSERT(drawContext===this.context,"must call redrawStart() before drawing tiles");glCopyToContext(drawContext);[drawCanvas,drawContext,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&&(ASSERT(drawContext===this.context,"must call redrawStart() before drawing tiles"),a=a.add(vec2(.5)),c=tile(b.tile,c,this.tileInfo.textureIndex,this.tileInfo.padding),drawTile(a,vec2(1),c,b.color,b.direction*PI/2,b.mirror))}}class TileCollisionLayer extends TileLayer{constructor(a,b,c=tile(),d=0,e=glEnable){const f=vec2(1);super(a,b.floor(),c,f,d,e);this.collisionData=[];this.initCollision(this.size);tileCollisionLayers.push(this);this.isSolid=!0}destroy(){if(!this.destroyed){var a=tileCollisionLayers.indexOf(this);ASSERT(0<=a,"tile collision layer not found in array");tileCollisionLayers.splice(a,1);super.destroy()}}initCollision(a){this.size=a.floor();this.collisionData=[];this.collisionData.length=a.area();this.collisionData.fill(0)}setCollisionData(a,b=1){const c=(a.y|0)*this.size.x+a.x|0;a.arrayCheck(this.size)&&(this.collisionData[c]=b)}getCollisionData(a){const b=(a.y|0)*this.size.x+a.x|0;return a.arrayCheck(this.size)?this.collisionData[b]:0}collisionTest(a,b=new Vector2,c){var d=a.x-this.pos.x,e=a.y-this.pos.y;a=max(d-b.x/2|0,0);var f=max(e-b.y/2|0,0);d=min(d+b.x/2,this.size.x);b=min(e+b.y/2,this.size.y);for(e=new Vector2;f<b;++f)for(let g=a;g<d;++g){const h=this.collisionData[f*this.size.x+g];if(h&&(!c||c.collideWithTile(h,e.set(g,f))))return!0}return!1}collisionRaycast(a,b,c){var d=b.x-this.pos.x-(a.x-this.pos.x),e=b.y-this.pos.y-(a.y-this.pos.y);const f=(d**2+e**2)**.5,g=abs(f/d),h=abs(f/e),k=a.floor(),l=sign(d),m=sign(e);d=g*(0>d?a.x-k.x:k.x-a.x+1)||0;for(e=h*(0>e?a.y-k.y:k.y-a.y+1)||0;;){const n=this.getCollisionData(k);if(n&&(!c||c.collideWithTile(n,k)))return k.x+=.5,k.y+=.5,debugRaycast&&debugLine(a,b,"#f00",.02),debugRaycast&&debugPoint(k,"#ff0"),k;if(d>=f&&e>=f)break;d>e?(k.y+=m,e+=h):(k.x+=l,d+=g)}debugRaycast&&debugLine(a,b,"#00f",.02)}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,h=new Color,k=new Color,l=new Color(1,1,1,0),m=new Color(1,1,1,0),n=.5,p=.1,r=1,q=.1,u=.05,t=1,w=1,x=0,B=PI,z=.1,v=.2,y=!1,D=!1,G=!0,J=D?1e9:0,H=!1){super(a,vec2(),g,b,void 0,J);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h;this.colorStartB=k;this.colorEndA=l;this.colorEndB=m;this.randomColorLinear=G;this.particleTime=n;this.sizeStart=p;this.sizeEnd=r;this.speed=q;this.angleSpeed=u;this.damping=t;this.angleDamping=w;this.gravityScale=x;this.particleConeAngle=B;this.fadeRate=z;this.randomness=v;this.collideTiles=y;this.additive=D;this.localSpace=H;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){var a=1/this.emitRate/particleEmitRateScale;for(this.emitTimeBuffer+=timeDelta;0<this.emitTimeBuffer;this.emitTimeBuffer-=a)this.emitParticle()}}else this.destroy();debugParticles&&(a="number"===typeof this.emitSize?vec2(this.emitSize):this.emitSize,debugRect(this.pos,a,"#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=n=>n+n*rand(c,-c);const e=d(this.particleTime),f=d(this.sizeStart),g=d(this.sizeEnd),h=d(this.speed);d=d(this.angleSpeed)*randSign();var k=rand(this.emitConeAngle,-this.emitConeAngle);const l=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),m=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);k=this.localSpace?k:this.angle+k;a=new Particle(a,this.tileInfo,b,l,m,e,f,g,this.fadeRate,this.additive,this.trailScale,this.localSpace&&this,this.particleDestroyCallback);a.velocity=vec2().setAngle(k,h);a.angleVelocity=d;this.localSpace||(a.velocity.x+=this.velocity.x,a.velocity.y+=this.velocity.y,a.angleVelocity+=this.angleVelocity);a.fadeRate=this.fadeRate;a.damping=this.damping;a.angleDamping=this.angleDamping;a.restitution=this.restitution;a.friction=this.friction;a.gravityScale=this.gravityScale;a.collideTiles=this.collideTiles;a.renderOrder=this.renderOrder;a.mirror=randBool();this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d,e,f,g,h,k,l,m,n,p){super(a,vec2(),b,c);this.colorStart=d;this.colorEndDelta=e.subtract(d);this.lifeTime=f;this.sizeStart=g;this.sizeEndDelta=h-g;this.fadeRate=k;this.additive=l;this.trailScale=m;this.localSpaceEmitter=n;this.destroyCallback=p;this.clampSpeed=!1}update(){super.update();if(this.collideTiles||this.collideSolidObjects){var a=this.velocity.lengthSquared();a>objectMaxSpeed*objectMaxSpeed&&(a=objectMaxSpeed/a**.5,this.velocity.x*=a,this.velocity.y*=a)}}render(){const a=0<this.lifeTime?min((time-this.spawnTime)/this.lifeTime,1):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||medalsForEach(b=>b.unlocked=!!localStorage[b.storageKey()]);engineAddPlugin(void 0,function(){if(medalsDisplayQueue.length){var b=medalsDisplayQueue[0],c=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(c>medalDisplayTime)medalsDisplayTimeLast=0,medalsDisplayQueue.shift();else{const d=medalDisplayTime-medalDisplaySlideTime;b.render(c<medalDisplaySlideTime?1-c/medalDisplaySlideTime:c>d?(c-d)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}})}function medalsForEach(a){Object.values(medals).forEach(b=>a(b))}class Medal{constructor(a,b,c="",d="🏆",e){ASSERT(0<=a&&!medals[a]);this.id=a;this.name=b;this.description=c;this.icon=d;this.unlocked=!1;e&&((this.image=new Image).src=e);medals[a]=this}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName,"save name must be set"),localStorage[this.storageKey()]=this.unlocked=!0,medalsDisplayQueue.push(this))}render(a=0){const b=overlayContext;var c=min(medalDisplaySize.x,mainCanvas.width);const d=medalDisplaySize.y;var e=overlayCanvas.width-c;a*=-d;b.save();b.beginPath();b.fillStyle=new Color(.9,.9,.9).toString();b.strokeStyle=BLACK.toString();b.lineWidth=3;b.rect(e,a,c,d);b.fill();b.stroke();b.clip();const f=vec2(.1,.05).scale(d),g=d-2*f.x;this.renderIcon(vec2(e+f.x+g/2,a+d/2),g);const h=.5*d,k=.3*d;e=vec2(e+g+2*f.x,a+2*f.y+h/2);c=c-g-3*f.x;drawTextScreen(this.name,e,h,BLACK,0,void 0,"left",void 0,c);e.y=a+d-2*f.y-k/2;drawTextScreen(this.description,e,k,BLACK,0,void 0,"left",void 0,c);b.restore()}renderIcon(a,b){this.image?overlayContext.drawImage(this.image,a.x-b/2,a.y-b/2,b,b):drawTextScreen(this.icon,a,.7*b,BLACK)}storageKey(){return medalsSaveName+"_"+this.id}}let glCanvas,glContext,glAntialias=!0,glShader,glPolyShader,glPolyMode,glAdditive,glBatchAdditive,glActiveTexture,glArrayBuffer,glGeometryBuffer,glPositionData,glColorData,glBatchCount;const gl_ARRAY_BUFFER_SIZE=5e5,gl_INDICES_PER_INSTANCE=11,gl_INSTANCE_BYTE_STRIDE=4*gl_INDICES_PER_INSTANCE,gl_MAX_INSTANCES=gl_ARRAY_BUFFER_SIZE/gl_INSTANCE_BYTE_STRIDE|0,gl_INDICES_PER_POLY_VERTEX=3,gl_POLY_VERTEX_BYTE_STRIDE=4*gl_INDICES_PER_POLY_VERTEX,gl_MAX_POLY_VERTEXES=gl_ARRAY_BUFFER_SIZE/gl_POLY_VERTEX_BYTE_STRIDE|0;function glInit(){if(glEnable&&!headlessMode)if(glCanvas=document.createElement("canvas"),glContext=glCanvas.getContext("webgl2",{antialias:glAntialias})){mainCanvas.parentElement.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;uniform sampler2D s;in vec2 v;in vec4 d,e;out vec4 c;void main(){c=texture(s,v)*d+e;}");glPolyShader=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 m;in vec2 p;in vec4 c;out vec4 d;void main(){gl_Position=m*vec4(p,1,1);d=c;}","#version 300 es\nprecision highp float;in vec4 d;out vec4 c;void main(){c=d;}");var a=new ArrayBuffer(gl_ARRAY_BUFFER_SIZE);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glArrayBuffer=glContext.createBuffer();glGeometryBuffer=glContext.createBuffer();a=new Float32Array([glBatchCount=0,0,1,0,0,1,1,1]);glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,a,glContext.STATIC_DRAW)}else console.warn("WebGL2 not supported, falling back to 2D canvas rendering!"),glCanvas=glContext=void 0,glEnable=!1}function glSetInstancedMode(){if(glPolyMode){glFlush();glPolyMode=!1;glContext.useProgram(glShader);var a=0,b=(c,d,e,f)=>{c=glContext.getAttribLocation(glShader,c);const g=e&&gl_INSTANCE_BYTE_STRIDE,h=e&&1,k=1===e;glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,f,d,k,g,a);glContext.vertexAttribDivisor(c,h);a+=f*e};glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);b("g",glContext.FLOAT,0,2);glContext.bindBuffer(glContext.ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,gl_ARRAY_BUFFER_SIZE,glContext.DYNAMIC_DRAW);b("p",glContext.FLOAT,4,4);b("u",glContext.FLOAT,4,4);b("c",glContext.UNSIGNED_BYTE,1,4);b("a",glContext.UNSIGNED_BYTE,1,4);b("r",glContext.FLOAT,4,1)}}function glSetPolyMode(){if(!glPolyMode){glFlush();glPolyMode=!0;glContext.useProgram(glPolyShader);var a=0,b=(c,d,e,f)=>{c=glContext.getAttribLocation(glPolyShader,c);const g=1===e,h=gl_POLY_VERTEX_BYTE_STRIDE;glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,f,d,g,h,a);glContext.vertexAttribDivisor(c,0);a+=f*e};glContext.bindBuffer(glContext.ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,gl_ARRAY_BUFFER_SIZE,glContext.DYNAMIC_DRAW);b("p",glContext.FLOAT,4,2);b("c",glContext.UNSIGNED_BYTE,1,4)}}function glPreRender(){if(glEnable&&glContext){glClearCanvas();var a=vec2(2*cameraScale).divide(mainCanvasSize),b=cameraPos.rotate(-cameraAngle);b=vec2(-1).subtract(b.multiply(a));var c=Math.cos(cameraAngle),d=Math.sin(cameraAngle);a=[a.x*c,a.y*d,0,0,-a.x*d,a.y*c,0,0,1,1,1,0,b.x,b.y,0,1];b=glPolyShader;glContext.useProgram(b);b=glContext.getUniformLocation(b,"m");glContext.uniformMatrix4fv(b,!1,a);b=glShader;glContext.useProgram(b);b=glContext.getUniformLocation(b,"m");glContext.uniformMatrix4fv(b,!1,a);glContext.activeTexture(glContext.TEXTURE0);textureInfos[0]&&(glActiveTexture=textureInfos[0].glTexture,glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture));glAdditive=glBatchAdditive=!1;glPolyMode=!0;glSetInstancedMode()}}function glClearCanvas(){glContext&&(glCanvas.width=drawCanvas.width,glCanvas.height=drawCanvas.height,glContext.viewport(0,0,glCanvas.width,glCanvas.height),glContext.clear(glContext.COLOR_BUFFER_BIT))}function glSetTexture(a,b=!1){glContext&&a!==glActiveTexture&&(glFlush(),glActiveTexture=a,glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture),a=b?glContext.REPEAT:glContext.CLAMP_TO_EDGE,glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_S,a),glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_T,a))}function glCompileShader(a,b){if(glContext){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,glContext.COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}}function glCreateProgram(a,b){if(glContext){var c=glContext.createProgram();glContext.attachShader(c,glCompileShader(a,glContext.VERTEX_SHADER));glContext.attachShader(c,glCompileShader(b,glContext.FRAGMENT_SHADER));glContext.linkProgram(c);if(debug&&!glContext.getProgramParameter(c,glContext.LINK_STATUS))throw glContext.getProgramInfoLog(c);return c}}function glCreateTexture(a){if(glContext){var b=glContext.createTexture(),c=!1;a&&a.width?(glSetTextureData(b,a),glContext.bindTexture(glContext.TEXTURE_2D,b),c=!tilesPixelated&&isPowerOfTwo(a.width)&&isPowerOfTwo(a.height)):(a=new Uint8Array([255,255,255,255]),glContext.bindTexture(glContext.TEXTURE_2D,b),glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,1,1,0,glContext.RGBA,glContext.UNSIGNED_BYTE,a));a=tilesPixelated?glContext.NEAREST:glContext.LINEAR;var d=c?glContext.LINEAR_MIPMAP_LINEAR:a;glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_MAG_FILTER,a);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_MIN_FILTER,d);c&&glContext.generateMipmap(glContext.TEXTURE_2D);glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture);return b}}function glDeleteTexture(a){glContext&&glContext.deleteTexture(a)}function glSetTextureData(a,b){glContext&&(ASSERT(!!b&&0<b.width,"Invalid image data."),glContext.bindTexture(glContext.TEXTURE_2D,a),glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,b),glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture))}function glFlush(){if(glEnable&&glContext&&glBatchCount){const a=glBatchAdditive?glContext.ONE:glContext.ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(glContext.SRC_ALPHA,a,glContext.ONE,a);glContext.enable(glContext.BLEND);glContext.bufferSubData(glContext.ARRAY_BUFFER,0,glPositionData,0,glBatchCount*(glPolyMode?gl_INDICES_PER_POLY_VERTEX:gl_INDICES_PER_INSTANCE));glPolyMode?glContext.drawArrays(glContext.TRIANGLE_STRIP,0,glBatchCount):glContext.drawArraysInstanced(glContext.TRIANGLE_STRIP,0,4,glBatchCount);drawCount+=glBatchCount;glBatchCount=0}glBatchAdditive=glAdditive}function glCopyToContext(a){glEnable&&glContext&&(glFlush(),a.drawImage(glCanvas,0,0))}function glSetAntialias(a=!0){ASSERT(!glCanvas,"must be called before engineInit");glAntialias=a}function glDraw(a,b,c,d,e=0,f=0,g=0,h=1,k=1,l=-1,m=0){(glBatchCount>=gl_MAX_INSTANCES||glBatchAdditive!==glAdditive)&&glFlush();glSetInstancedMode();glPolyMode=!1;let n=glBatchCount++*gl_INDICES_PER_INSTANCE;glPositionData[n++]=a;glPositionData[n++]=b;glPositionData[n++]=c;glPositionData[n++]=d;glPositionData[n++]=f;glPositionData[n++]=g;glPositionData[n++]=h;glPositionData[n++]=k;glColorData[n++]=l;glColorData[n++]=m;glPositionData[n++]=e}function glDrawPointsTransform(a,b,c,d,e,f,g,h=!0){const k=[];for(const l of a){a=l.x*e;const m=l.y*f,n=Math.sin(-g),p=Math.cos(-g);k.push(vec2(c+p*a-n*m,d+n*a+p*m))}c=h?glPolyStrip(k):k;glDrawPoints(c,b)}function glDrawOutlineTransform(a,b,c,d,e,f,g,h,k=!0){a=glMakeOutline(a,c,k);glDrawPointsTransform(a,b,d,e,f,g,h,!1)}function glDrawPoints(a,b){if(glEnable&&!(3>a.length)){var c=a.length+2;(glBatchCount+c>=gl_MAX_POLY_VERTEXES||glBatchAdditive!==glAdditive)&&glFlush();glSetPolyMode();var d=glBatchCount*gl_INDICES_PER_POLY_VERTEX;for(let f=c;f--;){var e=clamp(f-1,0,c-3);e=a[e];glPositionData[d++]=e.x;glPositionData[d++]=e.y;glColorData[d++]=b}glBatchCount+=c}}function glDrawColoredPoints(a,b){if(glEnable&&!(3>a.length)){var c=a.length+2;(glBatchCount+c>=gl_MAX_POLY_VERTEXES||glBatchAdditive!==glAdditive)&&glFlush();glSetPolyMode();var d=glBatchCount*gl_INDICES_PER_POLY_VERTEX;for(let f=c;f--;){var e=clamp(f-1,0,c-3);const g=a[e];e=b[e];glPositionData[d++]=g.x;glPositionData[d++]=g.y;glColorData[d++]=e}glBatchCount+=c}}function glMakeOutline(a,b,c=!0){if(2>a.length)return[];const d=b/2,e=[],f=a.length;b*=100;for(let p=0;p<f;p++){var g=a[c?(p-1+f)%f:max(p-1,0)],h=a[p],k=a[c?(p+1)%f:min(p+1,f-1)],l=h.x-g.x,m=h.y-g.y,n=(l*l+m*m)**.5;g=k.x-h.x;const r=k.y-h.y;k=(g*g+r*r)**.5;1e-6>n&&1e-6>k||(m=1e-6<n?-m/n:0,n=1e-6<n?l/n:0,l=m+(1e-6<k?-r/k:0),g=n+(1e-6<k?g/k:0),k=(l*l+g*g)**.5,1e-6>k?(l=m,g=n):(l/=k,g/=k,m=m*l+n*g,1e-6<m&&(m=min(1/m,b),l*=m,g*=m)),m=vec2(h.x-l*d,h.y-g*d),h=vec2(h.x+l*d,h.y+g*d),e.push(m),e.push(h))}1<e.length&&c&&(e.push(e[0]),e.push(e[1]));return e}function glPolyStrip(a){if(3>a.length)return[];const b=(q,u,t)=>(u.x-q.x)*(t.y-q.y)-(u.y-q.y)*(t.x-q.x);0>(q=>{let u=0;for(let t=q.length;t--;)u+=q[t].cross(q[(t+1)%q.length]);return u})(a)&&(a=a.reverse());var c=(q,u,t,w)=>{const x=b(u,t,q);t=b(t,w,q);q=b(w,u,q);return!((-1e-9>x?1:0)+(-1e-9>t?1:0)+(-1e-9>q?1:0)&&(1e-9<x?1:0)+(1e-9<t?1:0)+(1e-9<q?1:0))},d=[];for(var e=0;e<a.length;++e)d[e]=e;e=[];let f=0;const g=a.length**2+100;for(;3<d.length&&f++<g;){var h=!1;for(var k=d.length;--k;){var l=d[(k+d.length-1)%d.length],m=d[k];const q=d[(k+1)%d.length],u=a[l],t=a[m],w=a[q];if(1e-9>b(u,t,w))continue;let x=!1;for(let B=0;B<d.length;B++){const z=d[B];if(z!==l&&z!==m&&z!==q&&(x=c(a[z],u,t,w)))break}if(!x){e.push([l,m,q]);d.splice(k,1);h=!0;break}}if(!h){h=-1;k=Infinity;for(l=d.length;--l;)m=abs(b(a[d[(l+d.length-1)%d.length]],a[d[l]],a[d[(l+1)%d.length]])),m<k&&(k=m,h=l);if(0>h)break;e.push([d[(h+d.length-1)%d.length],d[h],d[(h+1)%d.length]]);d.splice(h,1)}}3===d.length&&e.push([d[0],d[1],d[2]]);if(!e.length)return[];c=[];let[n,p,r]=e[0];c.push(a[n],a[p],a[r]);for(d=1;d<e.length;d++){const[q,u,t]=e[d];c.push(a[r],a[q]);c.push(a[q],a[u],a[t]);r=t}return c}let newgrounds;class NewgroundsMedal extends Medal{constructor(a,b,c,d,e){super(a,b,c,d,e)}unlock(){super.unlock();newgrounds&&newgrounds.unlockMedal(this.id)}}class NewgroundsPlugin{constructor(a,b,c){ASSERT(!newgrounds,"there can only be one newgrounds object");ASSERT(!b||c,"must provide cryptojs if there is a cipher");newgrounds=this;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.value})`);this.scoreboards=(d=this.call("ScoreBoard.getBoards"))?d.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards);setInterval(()=>this.call("Gateway.ping",0,!0),6e4)}}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);try{b.send(a)}catch(e){debugMedals&&console.log("newgrounds call failed",e);return}debugMedals&&console.log(b.responseText);return b.responseText&&JSON.parse(b.responseText)}}let postProcess;class PostProcessPlugin{constructor(a,b=!1){ASSERT(!postProcess,"Post process already initialized");postProcess=this;headlessMode||(glEnable?(a||="void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}",this.shader=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.;}"),this.texture=glCreateTexture(),this.includeOverlay=b,engineAddPlugin(void 0,function(){if(!headlessMode){glEnable?(glFlush(),mainContext.drawImage(glCanvas,0,0)):glContext.viewport(0,0,glCanvas.width=drawCanvas.width,glCanvas.height=drawCanvas.height);postProcess.includeOverlay&&(mainContext.drawImage(overlayCanvas,0,0),overlayCanvas.width|=0);glContext.useProgram(postProcess.shader);glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL,1);glContext.disable(glContext.BLEND);glContext.activeTexture(glContext.TEXTURE0);glContext.bindTexture(glContext.TEXTURE_2D,postProcess.texture);glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,mainCanvas);var c=glContext.getAttribLocation(postProcess.shader,"p");glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,2,glContext.FLOAT,!1,8,0);glContext.uniform1i(glContext.getUniformLocation(postProcess.shader,"iChannel0"),0);glContext.uniform1f(glContext.getUniformLocation(postProcess.shader,"iTime"),time);glContext.uniform3f(glContext.getUniformLocation(postProcess.shader,"iResolution"),mainCanvas.width,mainCanvas.height,1);glContext.drawArrays(glContext.TRIANGLE_STRIP,0,4)}})):console.warn("PostProcessPlugin: WebGL not enabled!"))}}class ZzFXMusic extends Sound{constructor(a){super(void 0);soundEnable&&!headlessMode&&(this.randomness=0,this.sampleChannels=zzfxM(...a),this.sampleRate=audioDefaultSampleRate)}playMusic(a=1,b=!0){return super.play(void 0,a,1,0,b)}}function zzfxM(a,b,c,d=125){let e,f,g,h,k,l,m,n,p,r,q,u,t,w=0,x,B=[],z=[],v=[],y=0,D=0,G=1,J={},H=audioDefaultSampleRate/d*60>>2;for(;G;y++)B=[G=n=u=0],c.forEach((E,K)=>{m=b[E][y]||[0,0,0];G|=b[E][y]&&1;x=u+(b[E][0].length-2-(n?0:1))*H;t=K===c.length-1;e=2;for(g=u;e<m.length+t;n=++e){k=m[e];p=e===m.length+t-1&&t||r!==(m[0]||0)||k|0;for(f=0;f<H&&n;f++>H-99&&p&&1>q?q+=1/99:0)l=(1-q)*B[w++]/2||0,z[g]=(z[g]||0)-l*D+l,v[g]=(v[g++]||0)+l*D+l;k&&(q=k%1,D=m[1]||0,k|=0)&&(B=J[[r=m[w=0]||0,k]]=J[[r,k]]||(h=[...a[r]],h[2]=(h[2]||220)*2**(k/12-1),0<k?zzfxG(...h):[]))}u=x});return[z,v]}let uiSystem;class UISystemPlugin{constructor(a=overlayContext){ASSERT(!uiSystem,"UI system already initialized");uiSystem=this;this.defaultColor=WHITE;this.defaultTextColor=this.defaultLineColor=BLACK;this.defaultButtonColor=hsl(0,0,.7);this.defaultHoverColor=hsl(0,0,.9);this.defaultDisabledColor=hsl(0,0,.3);this.defaultLineWidth=4;this.defaultCornerRadius=0;this.defaultTextScale=.8;this.defaultFont="arial";this.defaultSoundClick=this.defaultSoundRelease=this.defaultSoundPress=void 0;this.uiObjects=[];this.uiContext=a;engineAddPlugin(function(){function b(d){for(const e of d.children)b(e);d.updateInvisible()}function c(d){if(d.visible){d.parent&&(d.pos=d.localPos.add(d.parent.pos));for(let e=d.children.length;e--;)c(d.children[e]);d.update()}else b(d)}for(let d=uiSystem.uiObjects.length;d--;){const e=uiSystem.uiObjects[d];e.parent||c(e)}},function(){function b(c){if(c.visible){c.parent&&(c.pos=c.localPos.add(c.parent.pos));c.render();for(const d of c.children)b(d)}}uiSystem.uiObjects.forEach(c=>c.parent||b(c))})}drawRect(a,b,c=uiSystem.defaultColor,d=uiSystem.defaultLineWidth,e=uiSystem.defaultLineColor,f=uiSystem.defaultCornerRadius){const g=uiSystem.uiContext;g.fillStyle=c.toString();g.beginPath();f&&g.roundRect?g.roundRect(a.x-b.x/2,a.y-b.y/2,b.x,b.y,f):g.rect(a.x-b.x/2,a.y-b.y/2,b.x,b.y);g.fill();d&&(g.strokeStyle=e.toString(),g.lineWidth=d,g.stroke())}drawLine(a,b,c=uiSystem.defaultLineWidth,d=uiSystem.defaultLineColor){const e=uiSystem.uiContext;e.strokeStyle=d.toString();e.lineWidth=c;e.beginPath();e.lineTo(a.x,a.y);e.lineTo(b.x,b.y);e.stroke()}drawTile(a,b,c,d=uiSystem.defaultColor,e=0,f=!1){drawTile(a,b,c,d,e,f,CLEAR_BLACK,!1,!0,uiSystem.uiContext)}drawText(a,b,c,d=uiSystem.defaultColor,e=uiSystem.defaultLineWidth,f=uiSystem.defaultLineColor,g="center",h=uiSystem.defaultFont,k=!0){drawTextScreen(a,b,c.y,d,e,f,g,h,k?c.x:void 0,uiSystem.uiContext)}}class UIObject{constructor(a=vec2(),b=vec2()){this.localPos=a.copy();this.pos=a.copy();this.size=b.copy();this.color=uiSystem.defaultColor;this.text=void 0;this.disabledColor=uiSystem.defaultDisabledColor;this.disabled=!1;this.textColor=uiSystem.defaultTextColor;this.hoverColor=uiSystem.defaultHoverColor;this.lineColor=uiSystem.defaultLineColor;this.lineWidth=uiSystem.defaultLineWidth;this.cornerRadius=uiSystem.defaultCornerRadius;this.font=uiSystem.defaultFont;this.textHeight=this.textWidth=void 0;this.textScale=uiSystem.defaultTextScale;this.visible=!0;this.children=[];this.parent=void 0;this.extraTouchSize=0;this.soundPress=uiSystem.defaultSoundPress;this.soundRelease=uiSystem.defaultSoundRelease;this.soundClick=uiSystem.defaultSoundClick;this.mouseIsHeld=this.interactive=this.mouseIsOver=!1;uiSystem.uiObjects.push(this)}addChild(a){ASSERT(!a.parent&&!this.children.includes(a));this.children.push(a);a.parent=this}removeChild(a){ASSERT(a.parent===this&&this.children.includes(a));this.children.splice(this.children.indexOf(a),1);a.parent=void 0}update(){const a=this.mouseIsOver,b=mouseWasPressed(0),c=mouseIsDown(0);if(b||!c||this.mouseIsHeld){const d=this.size.add(vec2(isTouchDevice&&this.extraTouchSize||0));this.mouseIsOver=isOverlapping(this.pos,d,mousePosScreen)}this.mouseIsOver&&(b&&inputClearKey(0,0,0,1,0),this.disabled||(b&&(this.interactive&&(this.onPress(),this.soundPress&&this.soundPress.play()),this.mouseIsHeld=!0),!c&&this.mouseIsHeld&&this.interactive&&(this.onClick(),this.soundClick&&this.soundClick.play())));c||(this.mouseIsHeld&&this.interactive&&(this.onRelease(),this.soundRelease&&this.soundRelease.play()),isTouchDevice&&(this.mouseIsOver=!1),this.mouseIsHeld=!1);this.mouseIsOver!==a&&(this.mouseIsOver?this.onEnter():this.onLeave())}render(){this.size.x&&this.size.y&&uiSystem.drawRect(this.pos,this.size,this.color,this.lineWidth,this.lineColor,this.cornerRadius)}updateInvisible(){this.mouseIsOver=this.mouseIsHeld=!1}getTextSize(){return vec2(this.textWidth||this.textScale*this.size.x,this.textHeight||this.textScale*this.size.y)}onEnter(){}onLeave(){}onPress(){}onRelease(){}onClick(){}onChange(){}}class UIText extends UIObject{constructor(a,b,c="",d="center",e=uiSystem.defaultFont){super(a,b);this.text=c;this.align=d;this.font=e;this.lineWidth=0}render(){const a=this.getTextSize();uiSystem.drawText(this.text,this.pos,a,this.textColor,this.lineWidth,this.lineColor,this.align,this.font)}}class UITile extends UIObject{constructor(a,b,c,d=WHITE,e=0,f=!1){super(a,b);this.tileInfo=c;this.angle=e;this.mirror=f;this.color=d}render(){uiSystem.drawTile(this.pos,this.size,this.tileInfo,this.color,this.angle,this.mirror)}}class UIButton extends UIObject{constructor(a,b,c="",d=uiSystem.defaultButtonColor){super(a,b);this.text=c;this.color=d;this.interactive=!0}render(){uiSystem.drawRect(this.pos,this.size,this.disabled?this.disabledColor:this.mouseIsOver?this.hoverColor:this.color,this.lineWidth,this.mouseIsHeld&&!this.disabled?this.color:this.lineColor,this.cornerRadius);const a=this.getTextSize();uiSystem.drawText(this.text,this.pos,a,this.textColor,0,void 0,this.align,this.font)}}class UICheckbox extends UIObject{constructor(a,b,c=!1,d="",e=uiSystem.defaultButtonColor){super(a,b);this.checked=c;this.text=d;this.color=e;this.interactive=!0}onClick(){this.checked=!this.checked;this.onChange()}render(){uiSystem.drawRect(this.pos,this.size,this.disabled?this.disabledColor:this.mouseIsOver?this.hoverColor:this.color,this.lineWidth,this.lineColor,this.cornerRadius);if(this.checked){var a=this.cornerRadius/min(this.size.x,this.size.y)*2;a=lerp(1,2**.5/2,a)/2;a=this.size.scale(a);uiSystem.drawLine(this.pos.add(a.multiply(vec2(-1))),this.pos.add(a.multiply(vec2(1))),this.lineWidth,this.lineColor);uiSystem.drawLine(this.pos.add(a.multiply(vec2(-1,1))),this.pos.add(a.multiply(vec2(1,-1))),this.lineWidth,this.lineColor)}a=this.getTextSize();const b=this.pos.add(vec2(this.size.x,0));uiSystem.drawText(this.text,b,a,this.textColor,0,void 0,"left",this.font,!1)}}class UIScrollbar extends UIObject{constructor(a,b,c=.5,d="",e=uiSystem.defaultButtonColor,f=WHITE){super(a,b);this.value=c;this.handleColor=f;this.text=d;this.color=e;this.interactive=!0}update(){super.update();if(this.mouseIsHeld&&this.interactive){var a=vec2(this.size.y);a=this.size.x-a.x;const b=this.value;this.value=percent(mousePosScreen.x,this.pos.x-a/2,this.pos.x+a/2);this.value===b||this.onChange()}}render(){uiSystem.drawRect(this.pos,this.size,this.disabled?this.disabledColor:this.interactive&&this.mouseIsHeld?this.hoverColor:this.color,this.lineWidth,this.interactive&&this.mouseIsHeld&&!this.disabled?this.color:this.lineColor,this.cornerRadius);var a=vec2(this.size.y),b=this.size.x-a.x;b=vec2(lerp(this.pos.x-b/2,this.pos.x+b/2,this.value),this.pos.y);uiSystem.drawRect(b,a,this.disabled?this.disabledColor:this.interactive&&this.mouseIsHeld?this.color:this.handleColor,this.lineWidth,this.lineColor,this.cornerRadius);a=this.getTextSize();uiSystem.drawText(this.text,this.pos,a,this.textColor,0,void 0,this.align,this.font)}}let box2d,box2dDebug=!1;function box2dSetDebug(a){box2dDebug=a}class Box2dObject extends EngineObject{constructor(a=vec2(),b,c,d=0,e,f=box2d.bodyTypeDynamic,g=0){super(a,b,c,d,e,g);b=new box2d.instance.b2BodyDef;b.set_type(f);b.set_position(box2d.vec2dTo(a));b.set_angle(-d);this.body=box2d.world.CreateBody(b);this.body.object=this;this.lineColor=BLACK}destroy(){this.body&&box2d.world.DestroyBody(this.body);this.body=0;super.destroy()}update(){this.pos=box2d.vec2From(this.body.GetPosition());this.angle=-this.body.GetAngle()}render(){this.tileInfo?super.render():this.drawFixtures(this.color,this.lineColor,this.lineWidth)}renderDebugInfo(){var a=!this.getIsAwake();const b=this.getBodyType()===box2d.bodyTypeStatic;a=rgb(a?1:0,a?1:0,b?1:0,.5);this.drawFixtures(a)}drawFixtures(a=WHITE,b,c=.1,d){this.getFixtureList().forEach(e=>box2d.drawFixture(e,this.pos,this.angle,a,b,c,d))}beginContact(a){}endContact(a){}addShape(a,b=1,c=.2,d=0,e=!1){const f=new box2d.instance.b2FixtureDef;f.set_shape(a);f.set_density(b);f.set_friction(c);f.set_restitution(d);f.set_isSensor(e);return this.body.CreateFixture(f)}addBox(a=vec2(1),b=vec2(),c=0,d,e,f,g){const h=new box2d.instance.b2PolygonShape;h.SetAsBox(a.x/2,a.y/2,box2d.vec2dTo(b),c);return this.addShape(h,d,e,f,g)}addPoly(a,b,c,d,e){ASSERT(3<=a.length&&8>=a.length);const f=new box2d.instance.b2PolygonShape;var g=box2d.instance._malloc(8*a.length);for(let h=0,k=0;h<a.length;++h)box2d.instance.HEAPF32[g+k>>2]=a[h].x,k+=4,box2d.instance.HEAPF32[g+k>>2]=a[h].y,k+=4;g=box2d.instance.wrapPointer(g,box2d.instance.b2Vec2);f.Set(g,a.length);return this.addShape(f,b,c,d,e)}addRegularPoly(a=1,b=8,c,d,e,f){const g=[];a/=2;for(let h=b;h--;)g.push(vec2(a,0).rotate((h+.5)/b*PI*2));return this.addPoly(g,c,d,e,f)}addRandomPoly(a=1,b,c,d,e){const f=randInt(3,9),g=[];a/=2;for(let h=f;h--;)g.push(vec2(rand(a/2,1.5*a),0).rotate(h/f*PI*2));return this.addPoly(g,b,c,d,e)}addCircle(a=1,b=vec2(),c,d,e,f){const g=new box2d.instance.b2CircleShape;g.set_m_p(box2d.vec2dTo(b));g.set_m_radius(a/2);return this.addShape(g,c,d,e,f)}addEdge(a,b,c,d,e,f){const g=new box2d.instance.b2EdgeShape;g.Set(box2d.vec2dTo(a),box2d.vec2dTo(b));return this.addShape(g,c,d,e,f)}addEdgeLoop(a,b,c,d,e){const f=[];for(let h=0;h<a.length;++h){var g=new box2d.instance.b2EdgeShape;g.set_m_vertex0(box2d.vec2dTo(a[mod(h-1,a.length)]));g.set_m_vertex1(box2d.vec2dTo(a[mod(h+0,a.length)]));g.set_m_vertex2(box2d.vec2dTo(a[mod(h+1,a.length)]));g.set_m_vertex3(box2d.vec2dTo(a[mod(h+2,a.length)]));g=this.addShape(g,b,c,d,e);f.push(g)}return f}addEdgeList(a,b,c,d,e){const f=[];for(let h=0;h<a.length-1;++h){var g=new box2d.instance.b2EdgeShape;a[h-1]&&g.set_m_vertex0(box2d.vec2dTo(a[h-1]));a[h+0]&&g.set_m_vertex1(box2d.vec2dTo(a[h+0]));a[h+1]&&g.set_m_vertex2(box2d.vec2dTo(a[h+1]));a[h+2]&&g.set_m_vertex3(box2d.vec2dTo(a[h+2]));g=this.addShape(g,b,c,d,e);f.push(g)}return f}getCenterOfMass(){return box2d.vec2From(this.body.GetWorldCenter())}getLinearVelocity(){return box2d.vec2From(this.body.GetLinearVelocity())}getAngularVelocity(){return this.body.GetAngularVelocity()}getMass(){return this.body.GetMass()}getInertia(){return this.body.GetInertia()}getIsAwake(){return this.body.IsAwake()}getBodyType(){return this.body.GetType()}setTransform(a,b){this.pos=a;this.angle=b;this.body.SetTransform(box2d.vec2dTo(a),b)}setPosition(a){this.setTransform(a,this.body.GetAngle())}setAngle(a){this.setTransform(box2d.vec2From(this.body.GetPosition()),-a)}setLinearVelocity(a){this.body.SetLinearVelocity(box2d.vec2dTo(a))}setAngularVelocity(a){this.body.SetAngularVelocity(a)}setLinearDamping(a){this.body.SetLinearDamping(a)}setAngularDamping(a){this.body.SetAngularDamping(a)}setGravityScale(a=1){this.body.SetGravityScale(this.gravityScale=a)}setBullet(a=!0){this.body.SetBullet(a)}setAwake(a=!0){this.body.SetAwake(a)}setBodyType(a){this.body.SetType(a)}setSleepingAllowed(a=!0){this.body.SetSleepingAllowed(a)}setFixedRotation(a=!0){this.body.SetFixedRotation(a)}setCenterOfMass(a){this.setMassData(a)}setMass(a){this.setMassData(void 0,a)}setMomentOfInertia(a){this.setMassData(void 0,void 0,a)}resetMassData(){this.body.ResetMassData()}setMassData(a,b,c){const d=new box2d.instance.b2MassData;this.body.GetMassData(d);a&&d.set_center(box2d.vec2dTo(a));b&&d.set_mass(b);c&&d.set_I(c);this.body.SetMassData(d)}setFilterData(a=0,b=0,c=0){this.getFixtureList().forEach(d=>{d=d.GetFilterData();d.set_categoryBits(a);d.set_maskBits(65535&~b);d.set_groupIndex(c)})}setSensor(a=!0){this.getFixtureList().forEach(b=>b.SetSensor(a))}applyForce(a,b){b||=this.getCenterOfMass();this.setAwake();this.body.ApplyForce(box2d.vec2dTo(a),box2d.vec2dTo(b))}applyAcceleration(a,b){b||=this.getCenterOfMass();this.setAwake();this.body.ApplyLinearImpulse(box2d.vec2dTo(a),box2d.vec2dTo(b))}applyTorque(a){this.setAwake();this.body.ApplyTorque(a)}applyAngularAcceleration(a){this.setAwake();this.body.ApplyAngularImpulse(a)}hasFixtures(){return!box2d.isNull(this.body.GetFixtureList())}getFixtureList(){const a=[];for(let b=this.body.GetFixtureList();!box2d.isNull(b);)a.push(b),b=b.GetNext();return a}hasJoints(){return!box2d.isNull(this.body.GetJointList())}getJointList(){const a=[];for(let b=this.body.GetJointList();!box2d.isNull(b);)a.push(b),b=b.get_next();return a}}class Box2dRaycastResult{constructor(a,b,c,d){this.object=a.GetBody().object;this.fixture=a;this.point=b;this.normal=c;this.fraction=d}}class Box2dJoint{constructor(a){this.box2dJoint=box2d.castObjectType(box2d.world.CreateJoint(a))}destroy(){box2d.world.DestroyJoint(this.box2dJoint);this.box2dJoint=0}getObjectA(){return this.box2dJoint.GetBodyA().object}getObjectB(){return this.box2dJoint.GetBodyB().object}getAnchorA(){return box2d.vec2From(this.box2dJoint.GetAnchorA())}getAnchorB(){return box2d.vec2From(this.box2dJoint.GetAnchorB())}getReactionForce(a){return box2d.vec2From(this.box2dJoint.GetReactionForce(1/a))}getReactionTorque(a){return this.box2dJoint.GetReactionTorque(1/a)}getCollideConnected(){return this.box2dJoint.getCollideConnected()}isActive(){return this.box2dJoint.IsActive()}}class Box2dTargetJoint extends Box2dJoint{constructor(a,b,c){a.setAwake();const d=new box2d.instance.b2MouseJointDef;d.set_bodyA(b.body);d.set_bodyB(a.body);d.set_target(box2d.vec2dTo(c));d.set_maxForce(2e3*a.getMass());super(d)}setTarget(a){this.box2dJoint.SetTarget(box2d.vec2dTo(a))}getTarget(){return box2d.vec2From(this.box2dJoint.GetTarget())}setMaxForce(a){this.box2dJoint.SetMaxForce(a)}getMaxForce(){return this.box2dJoint.GetMaxForce()}setFrequency(a){this.box2dJoint.SetFrequency(a)}getFrequency(){return this.box2dJoint.GetFrequency()}}class Box2dDistanceJoint extends Box2dJoint{constructor(a,b,c,d,e=!1){c||=box2d.vec2From(a.body.GetPosition());d||=box2d.vec2From(b.body.GetPosition());const f=a.worldToLocal(c),g=b.worldToLocal(d),h=new box2d.instance.b2DistanceJointDef;h.set_bodyA(a.body);h.set_bodyB(b.body);h.set_localAnchorA(box2d.vec2dTo(f));h.set_localAnchorB(box2d.vec2dTo(g));h.set_length(c.distance(d));h.set_collideConnected(e);super(h)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}setLength(a){this.box2dJoint.SetLength(a)}getLength(){return this.box2dJoint.GetLength()}setFrequency(a){this.box2dJoint.SetFrequency(a)}getFrequency(){return this.box2dJoint.GetFrequency()}setDampingRatio(a){this.box2dJoint.SetDampingRatio(a)}getDampingRatio(){return this.box2dJoint.GetDampingRatio()}}class Box2dPinJoint extends Box2dDistanceJoint{constructor(a,b,c=a.pos,d=!1){super(a,b,void 0,c,d)}}class Box2dRopeJoint extends Box2dJoint{constructor(a,b,c,d,e=0,f=!1){c||=box2d.vec2From(a.body.GetPosition());d||=box2d.vec2From(b.body.GetPosition());const g=a.worldToLocal(c),h=b.worldToLocal(d),k=new box2d.instance.b2RopeJointDef;k.set_bodyA(a.body);k.set_bodyB(b.body);k.set_localAnchorA(box2d.vec2dTo(g));k.set_localAnchorB(box2d.vec2dTo(h));k.set_maxLength(c.distance(d)+e);k.set_collideConnected(f);super(k)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}setMaxLength(a){this.box2dJoint.SetMaxLength(a)}getMaxLength(){return this.box2dJoint.GetMaxLength()}}class Box2dRevoluteJoint extends Box2dJoint{constructor(a,b,c,d=!1){c||=box2d.vec2From(b.body.GetPosition());const e=a.worldToLocal(c);c=b.worldToLocal(c);const f=new box2d.instance.b2RevoluteJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_localAnchorA(box2d.vec2dTo(e));f.set_localAnchorB(box2d.vec2dTo(c));f.set_referenceAngle(a.body.GetAngle()-b.body.GetAngle());f.set_collideConnected(d);super(f)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getReferenceAngle(){return this.box2dJoint.GetReferenceAngle()}getJointAngle(){return this.box2dJoint.GetJointAngle()}getJointSpeed(){return this.box2dJoint.GetJointSpeed()}isLimitEnabled(){return this.box2dJoint.IsLimitEnabled()}enableLimit(a=!0){return this.box2dJoint.enableLimit(a)}getLowerLimit(){return this.box2dJoint.GetLowerLimit()}getUpperLimit(){return this.box2dJoint.GetUpperLimit()}setLimits(a,b){return this.box2dJoint.SetLimits(a,b)}isMotorEnabled(){return this.box2dJoint.IsMotorEnabled()}enableMotor(a=!0){return this.box2dJoint.EnableMotor(a)}setMotorSpeed(a){return this.box2dJoint.SetMotorSpeed(a)}getMotorSpeed(){return this.box2dJoint.GetMotorSpeed()}setMaxMotorTorque(a){return this.box2dJoint.SetMaxMotorTorque(a)}getMaxMotorTorque(){return this.box2dJoint.GetMaxMotorTorque()}getMotorTorque(a){return this.box2dJoint.GetMotorTorque(1/a)}}class Box2dGearJoint extends Box2dJoint{constructor(a,b,c,d,e=1){const f=new box2d.instance.b2GearJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_joint1(c.box2dJoint);f.set_joint2(d.box2dJoint);f.set_ratio(e);super(f);this.joint1=c;this.joint2=d}getJoint1(){return this.joint1}getJoint2(){return this.joint2}setRatio(a){return this.box2dJoint.SetRatio(a)}getRatio(){return this.box2dJoint.GetRatio()}}class Box2dPrismaticJoint extends Box2dJoint{constructor(a,b,c,d=vec2(0,1),e=!1){c||=box2d.vec2From(b.body.GetPosition());const f=a.worldToLocal(c);c=b.worldToLocal(c);d=b.worldToLocalVector(d);const g=new box2d.instance.b2PrismaticJointDef;g.set_bodyA(a.body);g.set_bodyB(b.body);g.set_localAnchorA(box2d.vec2dTo(f));g.set_localAnchorB(box2d.vec2dTo(c));g.set_localAxisA(box2d.vec2dTo(d));g.set_referenceAngle(a.body.GetAngle()-b.body.GetAngle());g.set_collideConnected(e);super(g)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getLocalAxisA(){return box2d.vec2From(this.box2dJoint.GetLocalAxisA())}getReferenceAngle(){return this.box2dJoint.GetReferenceAngle()}getJointTranslation(){return this.box2dJoint.GetJointTranslation()}getJointSpeed(){return this.box2dJoint.GetJointSpeed()}isLimitEnabled(){return this.box2dJoint.IsLimitEnabled()}enableLimit(a=!0){return this.box2dJoint.enableLimit(a)}getLowerLimit(){return this.box2dJoint.GetLowerLimit()}getUpperLimit(){return this.box2dJoint.GetUpperLimit()}setLimits(a,b){return this.box2dJoint.SetLimits(a,b)}isMotorEnabled(){return this.box2dJoint.IsMotorEnabled()}enableMotor(a=!0){return this.box2dJoint.EnableMotor(a)}setMotorSpeed(a){return this.box2dJoint.SetMotorSpeed(a)}getMotorSpeed(){return this.box2dJoint.GetMotorSpeed()}setMaxMotorForce(a){return this.box2dJoint.SetMaxMotorForce(a)}getMaxMotorForce(){return this.box2dJoint.GetMaxMotorForce()}getMotorForce(a){return this.box2dJoint.GetMotorForce(1/a)}}class Box2dWheelJoint extends Box2dJoint{constructor(a,b,c,d=vec2(0,1),e=!1){c||=box2d.vec2From(b.body.GetPosition());const f=a.worldToLocal(c);c=b.worldToLocal(c);d=b.worldToLocalVector(d);const g=new box2d.instance.b2WheelJointDef;g.set_bodyA(a.body);g.set_bodyB(b.body);g.set_localAnchorA(box2d.vec2dTo(f));g.set_localAnchorB(box2d.vec2dTo(c));g.set_localAxisA(box2d.vec2dTo(d));g.set_collideConnected(e);super(g)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getLocalAxisA(){return box2d.vec2From(this.box2dJoint.GetLocalAxisA())}getJointTranslation(){return this.box2dJoint.GetJointTranslation()}getJointSpeed(){return this.box2dJoint.GetJointSpeed()}isMotorEnabled(){return this.box2dJoint.IsMotorEnabled()}enableMotor(a=!0){return this.box2dJoint.EnableMotor(a)}setMotorSpeed(a){return this.box2dJoint.SetMotorSpeed(a)}getMotorSpeed(){return this.box2dJoint.GetMotorSpeed()}setMaxMotorTorque(a){return this.box2dJoint.SetMaxMotorTorque(a)}getMaxMotorTorque(){return this.box2dJoint.GetMaxMotorTorque()}getMotorTorque(a){return this.box2dJoint.GetMotorTorque(1/a)}setSpringFrequencyHz(a){return this.box2dJoint.SetSpringFrequencyHz(a)}getSpringFrequencyHz(){return this.box2dJoint.GetSpringFrequencyHz()}setSpringDampingRatio(a){return this.box2dJoint.SetSpringDampingRatio(a)}getSpringDampingRatio(){return this.box2dJoint.GetSpringDampingRatio()}}class Box2dWeldJoint extends Box2dJoint{constructor(a,b,c,d=!1){c||=box2d.vec2From(b.body.GetPosition());const e=a.worldToLocal(c);c=b.worldToLocal(c);const f=new box2d.instance.b2WeldJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_localAnchorA(box2d.vec2dTo(e));f.set_localAnchorB(box2d.vec2dTo(c));f.set_referenceAngle(a.body.GetAngle()-b.body.GetAngle());f.set_collideConnected(d);super(f)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getReferenceAngle(){return this.box2dJoint.GetReferenceAngle()}setFrequency(a){return this.box2dJoint.SetFrequency(a)}getFrequency(){return this.box2dJoint.GetFrequency()}setSpringDampingRatio(a){return this.box2dJoint.SetSpringDampingRatio(a)}getSpringDampingRatio(){return this.box2dJoint.GetSpringDampingRatio()}}class Box2dFrictionJoint extends Box2dJoint{constructor(a,b,c,d=!1){c||=box2d.vec2From(b.body.GetPosition());const e=a.worldToLocal(c);c=b.worldToLocal(c);const f=new box2d.instance.b2FrictionJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_localAnchorA(box2d.vec2dTo(e));f.set_localAnchorB(box2d.vec2dTo(c));f.set_collideConnected(d);super(f)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}setMaxForce(a){this.box2dJoint.SetMaxForce(a)}getMaxForce(){return this.box2dJoint.GetMaxForce()}setMaxTorque(a){this.box2dJoint.SetMaxTorque(a)}getMaxTorque(){return this.box2dJoint.GetMaxTorque()}}class Box2dPulleyJoint extends Box2dJoint{constructor(a,b,c,d,e,f,g=1,h=!1){e||=box2d.vec2From(a.body.GetPosition());f||=box2d.vec2From(b.body.GetPosition());const k=a.worldToLocal(e),l=b.worldToLocal(f),m=new box2d.instance.b2PulleyJointDef;m.set_bodyA(a.body);m.set_bodyB(b.body);m.set_groundAnchorA(box2d.vec2dTo(c));m.set_groundAnchorB(box2d.vec2dTo(d));m.set_localAnchorA(box2d.vec2dTo(k));m.set_localAnchorB(box2d.vec2dTo(l));m.set_ratio(g);m.set_lengthA(c.distance(e));m.set_lengthB(d.distance(f));m.set_collideConnected(h);super(m)}getGroundAnchorA(){return box2d.vec2From(this.box2dJoint.GetGroundAnchorA())}getGroundAnchorB(){return box2d.vec2From(this.box2dJoint.GetGroundAnchorB())}getLengthA(){return this.box2dJoint.GetLengthA()}getLengthB(){return this.box2dJoint.GetLengthB()}getRatio(){return this.box2dJoint.GetRatio()}getCurrentLengthA(){return this.box2dJoint.GetCurrentLengthA()}getCurrentLengthB(){return this.box2dJoint.GetCurrentLengthB()}}class Box2dMotorJoint extends Box2dJoint{constructor(a,b){const c=a.worldToLocal(box2d.vec2From(b.body.GetPosition())),d=b.body.GetAngle()-a.body.GetAngle(),e=new box2d.instance.b2MotorJointDef;e.set_bodyA(a.body);e.set_bodyB(b.body);e.set_linearOffset(box2d.vec2dTo(c));e.set_angularOffset(d);super(e)}setLinearOffset(a){this.box2dJoint.SetLinearOffset(box2d.vec2dTo(a))}getLinearOffset(){return box2d.vec2From(this.box2dJoint.GetLinearOffset())}setAngularOffset(a){this.box2dJoint.SetAngularOffset(a)}getAngularOffset(){return this.box2dJoint.GetAngularOffset()}setMaxForce(a){this.box2dJoint.SetMaxForce(a)}getMaxForce(){return this.box2dJoint.GetMaxForce()}setMaxTorque(a){this.box2dJoint.SetMaxTorque(a)}getMaxTorque(){return this.box2dJoint.GetMaxTorque()}setCorrectionFactor(a){this.box2dJoint.SetCorrectionFactor(a)}getCorrectionFactor(){return this.box2dJoint.GetCorrectionFactor()}}class Box2dPlugin{constructor(a){ASSERT(!box2d,"Box2D already initialized");box2d=this;this.instance=a;this.world=new box2d.instance.b2World;this.velocityIterations=8;this.positionIterations=3;this.bodyTypeStatic=a.b2_staticBody;this.bodyTypeKinematic=a.b2_kinematicBody;this.bodyTypeDynamic=a.b2_dynamicBody;a=new box2d.instance.JSContactListener;a.BeginContact=function(b){var c=box2d.instance.wrapPointer(b,box2d.instance.b2Contact);b=c.GetFixtureA();c=c.GetFixtureB();b=b.GetBody().object;c=c.GetBody().object;b.beginContact(c);c.beginContact(b)};a.EndContact=function(b){var c=box2d.instance.wrapPointer(b,box2d.instance.b2Contact);b=c.GetFixtureA();c=c.GetFixtureB();b=b.GetBody().object;c=c.GetBody().object;b.endContact(c);c.endContact(b)};a.PreSolve=function(){};a.PostSolve=function(){};box2d.world.SetContactListener(a)}step(a=1){for(box2d.world.SetGravity(box2d.vec2dTo(gravity));a--;)box2d.world.Step(timeDelta,this.velocityIterations,this.positionIterations)}raycastAll(a,b){const c=new box2d.instance.JSRayCastCallback;c.ReportFixture=function(e,f,g,h){e=box2d.instance.wrapPointer(e,box2d.instance.b2Fixture);f=box2d.vec2FromPointer(f);g=box2d.vec2FromPointer(g);d.push(new Box2dRaycastResult(e,f,g,h));return 1};const d=[];box2d.world.RayCast(c,box2d.vec2dTo(a),box2d.vec2dTo(b));debugRaycast&&debugLine(a,b,d.length?"#f00":"#00f",.02);return d}raycast(a,b){a=box2d.raycastAll(a,b);if(a.length)return a.reduce((c,d)=>c.fraction<d.fraction?c:d)}boxCastAll(a,b){const c=new box2d.instance.JSQueryCallback;c.ReportFixture=function(f){f=box2d.instance.wrapPointer(f,box2d.instance.b2Fixture).GetBody().object;e.includes(f)||e.push(f);return!0};const d=new box2d.instance.b2AABB;d.set_lowerBound(box2d.vec2dTo(a.subtract(b.scale(.5))));d.set_upperBound(box2d.vec2dTo(a.add(b.scale(.5))));let e=[];box2d.world.QueryAABB(c,d);debugRaycast&&debugRect(a,b,e.length?"#f00":"#00f",.02);return e}boxCast(a,b){const c=new box2d.instance.JSQueryCallback;c.ReportFixture=function(f){e=box2d.instance.wrapPointer(f,box2d.instance.b2Fixture).GetBody().object;return!1};const d=new box2d.instance.b2AABB;d.set_lowerBound(box2d.vec2dTo(a.subtract(b.scale(.5))));d.set_upperBound(box2d.vec2dTo(a.add(b.scale(.5))));let e;box2d.world.QueryAABB(c,d);debugRaycast&&debugRect(a,b,e?"#f00":"#00f",.02);return e}circleCastAll(a,b){const c=(b/2)**2;return box2d.boxCastAll(a,vec2(b)).filter(d=>d.pos.distanceSquared(a)<c)}circleCast(a,b){const c=(b/2)**2;b=box2d.boxCastAll(a,vec2(b));let d,e;for(const f of b)b=f.pos.distanceSquared(a),b<c&&(!d||b<e)&&(d=f,e=b);return d}pointCast(a,b=!0){const c=new box2d.instance.JSQueryCallback;c.ReportFixture=function(f){f=box2d.instance.wrapPointer(f,box2d.instance.b2Fixture);if(b&&f.GetBody().GetType()!==box2d.instance.b2_dynamicBody||!f.TestPoint(box2d.vec2dTo(a)))return!0;e=f.GetBody().object;return!1};const d=new box2d.instance.b2AABB;d.set_lowerBound(box2d.vec2dTo(a));d.set_upperBound(box2d.vec2dTo(a));let e;box2d.world.QueryAABB(c,d);debugRaycast&&debugRect(a,vec2(),e?"#f00":"#00f",.02);return e}drawFixture(a,b,c,d=WHITE,e=BLACK,f=.1,g){a=box2d.castObjectType(a.GetShape());switch(a.GetType()){case box2d.instance.b2Shape.e_polygon:g=[];for(let h=a.GetVertexCount();h--;)g.push(box2d.vec2From(a.GetVertex(h)));drawPoly(g,d,f,e,b,c);break;case box2d.instance.b2Shape.e_circle:c=a.get_m_radius();drawCircle(b,2*c,d,f,e);break;case box2d.instance.b2Shape.e_edge:d=box2d.vec2From(a.get_m_vertex1()),a=box2d.vec2From(a.get_m_vertex2()),drawLine(d,a,f,e,b,c)}}vec2From(a){ASSERT(a instanceof box2d.instance.b2Vec2);return new Vector2(a.get_x(),a.get_y())}vec2FromPointer(a){return box2d.vec2From(box2d.instance.wrapPointer(a,box2d.instance.b2Vec2))}vec2dTo(a){ASSERT(a instanceof Vector2);return new box2d.instance.b2Vec2(a.x,a.y)}isNull(a){return!box2d.instance.getPointer(a)}castObjectType(a){switch(a.GetType()){case box2d.instance.b2Shape.e_circle:return box2d.instance.castObject(a,box2d.instance.b2CircleShape);case box2d.instance.b2Shape.e_edge:return box2d.instance.castObject(a,box2d.instance.b2EdgeShape);case box2d.instance.b2Shape.e_polygon:return box2d.instance.castObject(a,box2d.instance.b2PolygonShape);case box2d.instance.b2Shape.e_chain:return box2d.instance.castObject(a,box2d.instance.b2ChainShape);case box2d.instance.e_revoluteJoint:return box2d.instance.castObject(a,box2d.instance.b2RevoluteJoint);case box2d.instance.e_prismaticJoint:return box2d.instance.castObject(a,box2d.instance.b2PrismaticJoint);case box2d.instance.e_distanceJoint:return box2d.instance.castObject(a,box2d.instance.b2DistanceJoint);case box2d.instance.e_pulleyJoint:return box2d.instance.castObject(a,box2d.instance.b2PulleyJoint);case box2d.instance.e_mouseJoint:return box2d.instance.castObject(a,box2d.instance.b2MouseJoint);case box2d.instance.e_gearJoint:return box2d.instance.castObject(a,box2d.instance.b2GearJoint);case box2d.instance.e_wheelJoint:return box2d.instance.castObject(a,box2d.instance.b2WheelJoint);case box2d.instance.e_weldJoint:return box2d.instance.castObject(a,box2d.instance.b2WeldJoint);case box2d.instance.e_frictionJoint:return box2d.instance.castObject(a,box2d.instance.b2FrictionJoint);case box2d.instance.e_ropeJoint:return box2d.instance.castObject(a,box2d.instance.b2RopeJoint);case box2d.instance.e_motorJoint:return box2d.instance.castObject(a,box2d.instance.b2MotorJoint)}ASSERT(!1,"Unknown box2d object type")}}async function box2dInit(){new Box2dPlugin(await Box2D());(function(){const a=new box2d.instance.JSDraw,b=d=>{d=box2d.instance.wrapPointer(d,box2d.instance.b2Color);return new Color(d.get_r(),d.get_g(),d.get_b())},c=(d,e)=>{const f=[];for(;e--;)f.push(box2d.vec2FromPointer(d+8*e));return f};a.DrawSegment=function(d,e,f){f=b(f).scale(1,.8);d=box2d.vec2FromPointer(d);e=box2d.vec2FromPointer(e);drawLine(d,e,.1,f,vec2(),0,!1,!1,overlayContext)};a.DrawPolygon=function(d,e,f){f=b(f).scale(1,.8);d=c(d,e);drawPoly(d,CLEAR_WHITE,.1,f,vec2(),0,!1,!1,overlayContext)};a.DrawSolidPolygon=function(d,e,f){f=b(f).scale(1,.8);d=c(d,e);drawPoly(d,f,0,f,vec2(),0,!1,!1,overlayContext)};a.DrawCircle=function(d,e,f){f=b(f).scale(1,.8);d=box2d.vec2FromPointer(d);drawCircle(d,2*e,CLEAR_WHITE,.1,f,!1,!1,overlayContext)};a.DrawSolidCircle=function(d,e,f,g){g=b(g).scale(1,.8);d=box2d.vec2FromPointer(d);f=box2d.vec2FromPointer(f).scale(e);drawCircle(d,2*e,g,.1,g,!1,!1,overlayContext);drawLine(vec2(),f,.1,g,d,0,!1,!1,overlayContext)};a.DrawTransform=function(d){d=box2d.instance.wrapPointer(d,box2d.instance.b2Transform);const e=vec2(d.get_p());d=-d.get_q().GetAngle();const f=vec2(1,0),g=rgb(.75,0,0,.8),h=vec2(0,1),k=rgb(0,.75,0,.8);drawLine(vec2(),f,.1,g,e,d,!1,!1,overlayContext);drawLine(vec2(),h,.1,k,e,d,!1,!1,overlayContext)};a.AppendFlags(box2d.instance.b2Draw.e_shapeBit);a.AppendFlags(box2d.instance.b2Draw.e_jointBit);box2d.world.SetDebugDraw(a)})();engineAddPlugin(function(){paused||box2d.step()},function(){(box2dDebug||debugPhysics&&debugOverlay)&&box2d.world.DrawDebugData()});return box2d}function drawNineSliceScreen(a,b,c,d=32,e=2,f=0){drawNineSlice(a,b,c,WHITE,d,BLACK,e,f,!1,!0,overlayContext)}function drawNineSlice(a,b,c,d,e=1,f,g=.05,h=0,k=glEnable,l,m){const n=c.offset(c.size);var p=b.add(vec2(g-2*e));g=vec2(e);b=b.scale(.5).subtract(g.scale(.5));const r=l?-1:1,q=l?-h:h;drawTile(a,p,n,d,h,!1,f,k,l,m);for(var u=4;u--;){var t=u%2,w=b.multiply(vec2(t?1===u?1:-1:0,t?0:u?-1:1));t=vec2(t?e:p.x,t?p.y:e);const x=n.offset(c.size.multiply(vec2(1===u?1:3===u?-1:0,0===u?-r:2===u?r:0)));drawTile(a.add(w.rotate(q)),t,x,d,h,!1,f,k,l,m)}for(e=4;e--;)u=1<e,w=e&&3>e,p=b.multiply(vec2(u?-1:1,w?-1:1)),u=n.offset(c.size.multiply(vec2(u?-1:1,w?r:-r))),drawTile(a.add(p.rotate(q)),g,u,d,h,!1,f,k,l,m)}function drawThreeSliceScreen(a,b,c,d=32,e=2,f=0){drawThreeSlice(a,b,c,WHITE,d,BLACK,e,f,!1,!0,overlayContext)}function drawThreeSlice(a,b,c,d,e=1,f,g=.05,h=0,k=glEnable,l,m){const n=c.frame(0);var p=c.frame(1),r=c.frame(2),q=b.add(vec2(g-2*e));g=vec2(e);b=b.scale(.5).subtract(g.scale(.5));c=l?-1:1;const u=l?-h:h;drawTile(a,q,r,d,h,!1,f,k,l,m);for(r=4;r--;){const w=h+r*PI/2;var t=r%2;const x=b.multiply(vec2(t?1===r?1:-1:0,t?0:r?-c:c));t=vec2(t?q.y:q.x,e);drawTile(a.add(x.rotate(u)),t,p,d,w,!1,f,k,l,m)}for(e=4;e--;)p=h+e*PI/2,q=b.multiply(vec2(!e||2<e?-1:1,1<e?-c:c)),drawTile(a.add(q.rotate(u)),g,n,d,p,!1,f,k,l,m)}
|
|
4
|
+
const engineName="LittleJS",engineVersion="1.14.8",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=!1;function getPaused(){return paused}function setPaused(a=!0){paused=a}let frameTimeLastMS=0,frameTimeBufferMS=0,averageFPS=0;const pluginUpdateList=[],pluginRenderList=[];function engineAddPlugin(a,b){ASSERT(!pluginUpdateList.includes(a));ASSERT(!pluginRenderList.includes(b));a&&pluginUpdateList.push(a);b&&pluginRenderList.push(b)}async function engineInit(a,b,c,d,e,f=[],g=document.body){function h(m=0){function n(){if(!headlessMode){mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);overlayContext.imageSmoothingEnabled=mainContext.imageSmoothingEnabled=!tilesPixelated;glPreRender();d();engineObjects.sort((u,t)=>u.renderOrder-t.renderOrder);for(var q of engineObjects)q.destroyed||q.render();e();pluginRenderList.forEach(u=>u());touchGamepadRender();debugRender();glFlush();debugVideoCaptureUpdate();showWatermark&&!debugVideoCaptureIsActive()&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",q=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(q,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(q,mainCanvas.width-2,2));drawCount=0}}var p=m-frameTimeLastMS;frameTimeLastMS=m;if(debug||showWatermark)averageFPS=lerp(averageFPS,1e3/(p||1),.05);m=debug&&keyIsDown("Equal");const r=debug&&keyIsDown("Minus");debug&&(p*=m?10:r?.1:1);timeReal+=p/1e3;frameTimeBufferMS+=paused?0:p;m||(frameTimeBufferMS=min(frameTimeBufferMS,50));if(paused){k();for(const q of engineObjects)q.parent||q.updateTransforms();inputUpdate();pluginUpdateList.forEach(q=>q());debugUpdate();c();inputUpdatePost()}else{p=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(p=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,k(),inputUpdate(),b(),pluginUpdateList.forEach(q=>q()),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost(),debugVideoCaptureIsActive()&&n();frameTimeBufferMS+=p}debugVideoCaptureIsActive()||n();requestAnimationFrame(h)}function k(){if(!headlessMode){if(canvasFixedSize.x){mainCanvas.width=canvasFixedSize.x;mainCanvas.height=canvasFixedSize.y;const m=innerWidth/innerHeight,n=mainCanvas.width/mainCanvas.height;(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=m<n?"100%":"";(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=m<n?"":"100%"}else mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y);0<canvasClearColor.a&&(mainContext.fillStyle=canvasClearColor.toString(),mainContext.fillRect(0,0,mainCanvasSize.x,mainCanvasSize.y),mainContext.fillStyle=BLACK.toString());overlayCanvas.width=mainCanvas.width;overlayCanvas.height=mainCanvas.height;mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.lineJoin=overlayContext.lineJoin="round";mainContext.lineCap=overlayContext.lineCap="round"}}async function l(){await a();h()}ASSERT(!mainContext,"engine already initialized");ASSERT(Array.isArray(f),"pass in images as array");a||=()=>{};b||=()=>{};c||=()=>{};d||=()=>{};e||=()=>{};if(headlessMode)return l();g.style.cssText="margin:0;overflow:hidden;background:#000;user-select:none;-webkit-user-select:none;touch-action:none;-webkit-touch-callout:none";drawCanvas=mainCanvas=document.createElement("canvas");g.appendChild(mainCanvas);drawContext=mainContext=mainCanvas.getContext("2d");inputInit();audioInit();debugInit();glInit();overlayCanvas=document.createElement("canvas");g.appendChild(overlayCanvas);overlayContext=overlayCanvas.getContext("2d");mainCanvas.style.cssText=overlayCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";glCanvas&&(glCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)");setCanvasPixelated(canvasPixelated);setOverlayCanvasPixelated(overlayCanvasPixelated);k();glPreRender();workCanvas=new OffscreenCanvas(256,256);workContext=workCanvas.getContext("2d",{willReadFrequently:!0});g=f.map((m,n)=>new Promise(p=>{const r=new Image;r.onerror=r.onload=()=>{const q=new TextureInfo(r);q.createWebGLTexture();textureInfos[n]=q;p()};r.crossOrigin="anonymous";r.src=m}));f.length||g.push(new Promise(m=>{const n=new TextureInfo(new Image);textureInfos[0]=n;n.createWebGLTexture();m()}));showSplashScreen&&g.push(new Promise(m=>{function n(){inputClear();drawEngineSplashScreen(p+=.01);1<p?m():setTimeout(n,16)}let p=0;console.log(`${engineName} Engine v${engineVersion}`);n()}));await Promise.all(g);return l()}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),b.updateTransforms());engineObjects=engineObjects.filter(b=>!b.destroyed)}function engineObjectsDestroy(){for(const a of engineObjects)a.parent||a.destroy();engineObjects=engineObjects.filter(a=>!a.destroyed)}function engineObjectsCollect(a,b,c=engineObjects){const d=[];if(a)if(b instanceof Vector2)for(const e of c)isOverlapping(a,b,e.pos,e.size)&&d.push(e);else{b*=b;for(const e of c)a.distanceSquared(e.pos)<b&&d.push(e)}else for(const e of c)d.push(e);return d}function engineObjectsCallback(a,b,c,d=engineObjects){engineObjectsCollect(a,b,d).forEach(e=>c(e))}function engineObjectsRaycast(a,b,c=engineObjects){const d=[];for(const e of c)e.collideRaycast&&isIntersecting(a,b,e.pos,e.size)&&(debugRaycast&&debugRect(e.pos,e.size,"#f00"),d.push(e));debugRaycast&&debugLine(a,b,d.length?"#f00":"#00f",.02);return d}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(0,e/2,f),e).toString());g.addColorStop(1,hsl(0,0,0,e).toString());b.save();b.fillStyle=g;b.fillRect(0,0,c,d);g=(k,l,m,n,p)=>{b.beginPath();b.rect(k,l,m,p?n*h:n);(b.fillStyle=p)?b.fill():b.stroke()};f=(k,l,m,n=0,p=2*PI,r,q)=>{const u=(n+p)/2;n=h*(p-n)/2;b.beginPath();q&&b.lineTo(k,l);b.arc(k,l,m,u-n,u+n);(b.fillStyle=r)?b.fill():b.stroke()};e=(k=0,l=0)=>hsl([.98,.3,.57,.14][k%4]-10,.8,[0,.3,.5,.8,.9][l]).toString();a=wave(1,1,a);const h=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*h;c=percent(a,.1,1);b.setLineDash([99*c,99]);g(7,16,18,-8,e(2,2));g(7,8,18,4,e(2,3));g(25,8,8,8,e(2,1));g(25,8,-18,8);g(25,8,8,8);g(25,16,7,23,e());g(11,39,14,-23,e(1,1));g(11,16,14,18,e(1,2));g(11,16,14,8,e(1,3));g(25,16,-14,24);g(15,29,6,-9,e(2,2));f(15,21,5,0,PI/2,e(2,4),1);g(21,21,-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,-8,e(0,1));g(50,20,6.5,-8,e(0,2));g(50,20,3.5,-8,e(0,3));g(50,20,10,-8);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,-1,20,4,e(0,3));g(45,-1,20,8);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)*h,40),b.lineTo(53+(4+3.5*c)*h,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*h;g=0;for(c=0;c<f.length;++c)g+=b.measureText(f[c]).width;for(c=2;c--;)for(let k=0,l=41-g/2;k<f.length;++k)b.fillStyle=e(k,2),d=b.measureText(f[k]).width,b[c?"strokeText":"fillText"](f[k],l+d/2,55.5,17*h),l+=d;b.restore()}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 debugPoly(){}function debugCircle(){}function debugPoint(){}function debugLine(){}function debugOverlap(){}function debugText(){}function debugClear(){}function debugScreenshot(){}function debugSaveCanvas(){}function debugSaveText(){}function debugSaveDataURL(){}function debugShowErrors(){}function debugVideoCaptureIsActive(){return!1}function debugVideoCaptureStart(){}function debugVideoCaptureStop(){}function debugVideoCaptureUpdate(){}const PI=Math.PI;function abs(a){return Math.abs(a)}function min(...a){return Math.min(...a)}function max(...a){return Math.max(...a)}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):0}function lerp(a,b,c){0<=a&&1>=a&&(0>b||1<b)&&(0>c||1<c)&&console.warn("lerp() parameter order changed! use lerp(start, end, p)");return a+clamp(c)*(b-a)}function percentLerp(a,b,c,d,e){return lerp(d,e,percent(a,b,c))}function distanceWrap(a,b,c=1){a=(a-b)%c;return 2*a%c-a}function lerpWrap(a,b,c,d=1){0<=a&&1>=a&&(0>b||1<b)&&(0>c||1<c)&&console.warn("lerpWrap() parameter order changed! use lerpWrap(start, end, p)");return a+clamp(c)*distanceWrap(b,a,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 isPowerOfTwo(a){return!(a&a-1)}function nearestPowerOfTwo(a){return 2**Math.ceil(Math.log2(a))}function isOverlapping(a,b,c,d=vec2()){const e=2*(a.x-c.x);a=2*(a.y-c.y);c=b.x+d.x;b=b.y+d.y;return e>=-c&&e<c&&a>=-b&&a<b}function isIntersecting(a,b,c,d){c=c.subtract(d.scale(.5));d=c.add(d);b=b.subtract(a);c=a.subtract(c);d=a.subtract(d);a=[-b.x,b.x,-b.y,b.y];b=[c.x,-d.x,c.y,-d.y];c=0;d=1;for(let e=4;e--;)if(a[e]){const f=b[e]/a[e];if(0>a[e]){if(f>d)return!1;c=max(f,c)}else{if(f<c)return!1;d=min(f,d)}}else if(0>b[e])return!1;return!0}function wave(a=1,b=1,c=time,d=0){return b/2*(1-Math.cos(d+c*a*2*PI))}function formatTime(a){return(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0)}async function fetchJSON(a){return(await fetch(a)).json()}function isNumber(a){return"number"===typeof a&&!isNaN(a)}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return Math.floor(rand(a,b))}function randBool(a=.5){return rand()<a}function randSign(){return 2*randInt(2)-1}function randVec2(a=1){return(new Vector2).setAngle(rand(2*PI),a)}function randInCircle(a=1,b=0){return 0<a?randVec2(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=123456789){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+(this.seed>>>0)/2**32*(a-b)}int(a,b=0){return Math.floor(this.float(a,b))}bool(a=.5){return this.float()<a}sign(){return.5<this.float()?1:-1}floatSign(a=1,b=0){return this.float(a,b)*this.sign()}angle(){return this.float(-PI,PI)}vec2(a=1,b=0){return vec2(this.float(a,b),this.float(a,b))}}function vec2(a=0,b){return new Vector2(a,void 0===b?a:b)}function isVector2(a){return a instanceof Vector2&&a.isValid()}function ASSERT_VECTOR2_VALID(a){ASSERT(isVector2(a),"Vector2 is invalid.",a)}function ASSERT_NUMBER_VALID(a){ASSERT(isNumber(a),"Number is invalid.",a)}function ASSERT_VECTOR2_NORMAL(a){ASSERT_VECTOR2_VALID(a);ASSERT(.01>abs(a.lengthSquared()-1),"Vector2 is not normal.",a)}class Vector2{constructor(a=0,b=0){this.x=a;this.y=b;ASSERT(this.isValid(),"Constructed Vector2 is invalid.",this)}set(a=0,b=0){this.x=a;this.y=b;return this}copy(){return new Vector2(this.x,this.y)}add(a){return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){return new Vector2(this.x*a.x,this.y*a.y)}divide(a){return new Vector2(this.x/a.x,this.y/a.y)}scale(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){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector2(0,a)}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this}dot(a){return this.x*a.x+this.y*a.y}cross(a){return this.x*a.y-this.y*a.x}reflect(a,b=1){return this.subtract(a.scale((1+b)*this.dot(a)))}angle(){return Math.atan2(this.x,this.y)}setAngle(a=0,b=1){ASSERT_NUMBER_VALID(a);ASSERT_NUMBER_VALID(b);this.x=b*Math.sin(a);this.y=b*Math.cos(a);return this}rotate(a){ASSERT_NUMBER_VALID(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_NUMBER_VALID(a);ASSERT_NUMBER_VALID(b);a=mod(a,4);ASSERT(0===a||1===a||2===a||3===a,"Vector2.setDirection() direction must be an integer between 0 and 3.");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)}abs(){return new Vector2(abs(this.x),abs(this.y))}floor(){return new Vector2(Math.floor(this.x),Math.floor(this.y))}mod(a=1){return new Vector2(mod(this.x,a),mod(this.y,a))}area(){return abs(this.x*this.y)}lerp(a,b){ASSERT_VECTOR2_VALID(a);ASSERT_NUMBER_VALID(b);b=clamp(b);return new Vector2(a.x*b+this.x*(1-b),a.y*b+this.y*(1-b))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}toString(a=3){ASSERT_NUMBER_VALID(a);if(debug)return this.isValid()?`(${(0>this.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`:`(${this.x}, ${this.y})`}isValid(){return isNumber(this.x)&&isNumber(this.y)}}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&&a.isValid()}function ASSERT_COLOR_VALID(a){ASSERT(isColor(a),"Color is invalid.",a)}class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d;ASSERT(this.isValid(),"Constructed Color is invalid.",this)}set(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d;return this}copy(){return new Color(this.r,this.g,this.b,this.a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){ASSERT_COLOR_VALID(a);ASSERT_NUMBER_VALID(b);b=clamp(b);return new Color(a.r*b+this.r*(1-b),a.g*b+this.g*(1-b),a.b*b+this.b*(1-b),a.a*b+this.a*(1-b))}setHSLA(a=0,b=0,c=1,d=1){a=mod(a,1);b=clamp(b);c=clamp(c);b=.5>c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,g,h)=>1>6*(h=mod(h,1))?f+6*(g-f)*h:1>2*h?g:2>3*h?f+(g-f)*(4-6*h):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;ASSERT_COLOR_VALID(this);return this}HSLA(){const a=clamp(this.r),b=clamp(this.g),c=clamp(this.b),d=clamp(this.a),e=max(a,b,c),f=min(a,b,c),g=(e+f)/2;let h=0,k=0;if(e!==f){let l=e-f;k=.5<g?l/(2-e-f):l/(e+f);a===e?h=(b-c)/l+(b<c?6:0):b===e?h=(c-a)/l+2:c===e&&(h=(a-b)/l+4)}return[h/6,k,g,d]}mutate(a=.05,b=0){ASSERT_NUMBER_VALID(a);ASSERT_NUMBER_VALID(b);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){ASSERT("boolean"===typeof a,"Use alpha boolean is invalid.",a);if(debug&&!this.isValid())return"#000";const b=c=>(16>(c=255*clamp(c)|0)?"0":"")+c.toString(16);return"#"+b(this.r)+b(this.g)+b(this.b)+(a?b(this.a):"")}setHex(a){ASSERT("string"===typeof a&&"#"===a[0],"Color hex code must be a string starting with #");ASSERT([4,5,7,9].includes(a.length),"Invalid hex");6>a.length?(this.r=clamp(parseInt(a[1],16)/15),this.g=clamp(parseInt(a[2],16)/15),this.b=clamp(parseInt(a[3],16)/15),this.a=5===a.length?clamp(parseInt(a[4],16)/15):1):(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=9===a.length?clamp(parseInt(a.slice(7,9),16)/255):1);ASSERT_COLOR_VALID(this);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}isValid(){return isNumber(this.r)&&isNumber(this.g)&&isNumber(this.b)&&isNumber(this.a)}}const WHITE=rgb(),CLEAR_WHITE=rgb(1,1,1,0),BLACK=rgb(0,0,0),CLEAR_BLACK=rgb(0,0,0,0),GRAY=rgb(.5,.5,.5),RED=rgb(1,0,0),ORANGE=rgb(1,.5,0),YELLOW=rgb(1,1,0),GREEN=rgb(0,1,0),CYAN=rgb(0,1,1),BLUE=rgb(0,0,1),PURPLE=rgb(.5,0,1),MAGENTA=rgb(1,0,1);class Timer{constructor(a){ASSERT(void 0===a||isNumber(a),"Constructed Timer is invalid.",a);this.time=void 0===a?void 0:time+a;this.setTime=a}set(a=0){ASSERT(isNumber(a),"Timer is invalid.",a);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()?1-percent(this.time-time,0,this.setTime):0}getSetTime(){return this.isSet()?this.setTime: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(),cameraAngle=0,cameraScale=32,canvasColorTiles=!0,canvasClearColor=CLEAR_BLACK,canvasMaxSize=vec2(1920,1080),canvasFixedSize=vec2(),canvasPixelated=!0,overlayCanvasPixelated=!1,tilesPixelated=!0,fontDefault="arial",showSplashScreen=!1,headlessMode=!1,glEnable=!0,glCircleSides=32,tileSizeDefault=vec2(16),tileFixBleedScale=0,enablePhysicsSolver=!0,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultRestitution=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=vec2(),particleEmitRateScale=1,gamepadsEnable=!0,gamepadDirectionEmulateStick=!0,inputWASDEmulateDirection=!0,touchInputEnable=!0,touchGamepadEnable=!1,touchGamepadAnalog=!0,touchGamepadSize=99,touchGamepadAlpha=.3,vibrateEnable=!0,soundEnable=!0,soundVolume=.3,soundDefaultRange=40,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalsPreventUnlock=!1;function setCameraPos(a){cameraPos=a}function setCameraAngle(a){cameraAngle=a}function setCameraScale(a){cameraScale=a}function setCanvasColorTiles(a){canvasColorTiles=a}function setCanvasClearColor(a){canvasClearColor=a}function setCanvasMaxSize(a){canvasMaxSize=a}function setCanvasFixedSize(a){canvasFixedSize=a}function setCanvasPixelated(a){canvasPixelated=a;mainCanvas&&(mainCanvas.style.imageRendering=a?"pixelated":"");glCanvas&&(glCanvas.style.imageRendering=a?"pixelated":"")}function setOverlayCanvasPixelated(a){overlayCanvasPixelated=a;overlayCanvas&&(overlayCanvas.style.imageRendering=a?"pixelated":"")}function setTilesPixelated(a){tilesPixelated=a}function setFontDefault(a){fontDefault=a}function setShowSplashScreen(a){showSplashScreen=a}function setHeadlessMode(a){headlessMode=a}function setGLEnable(a){glEnable=a;glCanvas&&(glCanvas.style.visibility=a?"visible":"hidden")}function setGLCircleSides(a){glCircleSides=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 setObjectDefaultRestitution(a){objectDefaultRestitution=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 setTouchInputEnable(a){touchInputEnable=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;soundEnable&&!headlessMode&&audioMasterGain&&(audioMasterGain.gain.value=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 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=new Color,f=0){ASSERT(isVector2(a),"object pos should be a vec2");ASSERT(isVector2(b),"object size should be a vec2");ASSERT(!c||c instanceof TileInfo,"object tileInfo should be a TileInfo or undefined");ASSERT("number"===typeof d&&isFinite(d),"object angle should be a number");ASSERT(isColor(e),"object color should be a valid rgba color");ASSERT("number"===typeof f,"object renderOrder should be a number");this.pos=a.copy();this.size=b.copy();this.drawSize=void 0;this.tileInfo=c;this.angle=d;this.color=e.copy();this.additiveColor=void 0;this.mirror=!1;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.restitution=objectDefaultRestitution;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=f;this.velocity=vec2();this.angleVelocity=0;this.spawnTime=time;this.children=[];this.clampSpeed=!0;this.parent=this.groundObject=void 0;this.localPos=vec2();this.localAngle=0;this.collideRaycast=this.isSolid=this.collideSolidObjects=this.collideTiles=!1;engineObjects.push(this)}updateTransforms(){const a=this.parent;if(a){const b=a.getMirrorSign();this.pos=this.localPos.multiply(vec2(b,1)).rotate(a.angle).add(a.pos);this.angle=b*this.localAngle+a.angle}for(const b of this.children)b.updateTransforms()}update(){if(!this.parent){this.clampSpeed&&(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed));var a=this.pos.copy();this.velocity.x*=this.damping;this.velocity.y*=this.damping;this.mass&&(this.velocity.x+=gravity.x*this.gravityScale,this.velocity.y+=gravity.y*this.gravityScale);this.pos.x+=this.velocity.x;this.pos.y+=this.velocity.y;this.angle+=this.angleVelocity*=this.angleDamping;ASSERT(0<=this.angleDamping&&1>=this.angleDamping);ASSERT(0<=this.damping&&1>=this.damping);if(enablePhysicsSolver&&this.mass){var b=0>this.velocity.y;if(this.groundObject){var c=max(this.friction,this.groundObject.friction),d=this.groundObject.velocity?this.groundObject.velocity.x:0;this.velocity.x=d+(this.velocity.x-d)*c;this.groundObject=void 0}if(this.collideSolidObjects)for(var e of engineObjectsCollide){if(!this.isSolid&&!e.isSolid||e.destroyed||e.parent||e===this)continue;if(!isOverlapping(this.pos,this.size,e.pos,e.size))continue;c=this.collideWithObject(e);d=e.collideWithObject(this);if(!c||!d)continue;if(isOverlapping(a,this.size,e.pos,e.size)){c=a.subtract(e.pos);d=c.length();c=.01>d?randVec2(.001):c.scale(.001/d);this.velocity=this.velocity.add(c);e.mass&&(e.velocity=e.velocity.subtract(c));debugPhysics&&debugOverlap(this.pos,this.size,e.pos,e.size,"#f00");continue}d=this.size.add(e.size);var f=2*(a.y-e.pos.y)>d.y+gravity.y;const h=2*abs(a.y-e.pos.y)<d.y;var g=2*abs(a.x-e.pos.x)<d.x;c=max(this.restitution,e.restitution);if(f||g||!h)if(this.pos.y=e.pos.y+(d.y/2+.001)*sign(a.y-e.pos.y),e.groundObject&&b||!e.mass)b&&(this.groundObject=e),this.velocity.y*=-c;else if(e.mass){g=(this.mass*this.velocity.y+e.mass*e.velocity.y)/(this.mass+e.mass);const k=e.velocity.y*(e.mass-this.mass)/(this.mass+e.mass)+2*this.velocity.y*this.mass/(this.mass+e.mass);this.velocity.y=lerp(g,this.velocity.y*(this.mass-e.mass)/(this.mass+e.mass)+2*e.velocity.y*e.mass/(this.mass+e.mass),c);e.velocity.y=lerp(g,k,c)}!f&&h&&(this.pos.x=e.pos.x+(d.x/2+.001)*sign(a.x-e.pos.x),e.mass?(d=(this.mass*this.velocity.x+e.mass*e.velocity.x)/(this.mass+e.mass),f=e.velocity.x*(e.mass-this.mass)/(this.mass+e.mass)+2*this.velocity.x*this.mass/(this.mass+e.mass),this.velocity.x=lerp(d,this.velocity.x*(this.mass-e.mass)/(this.mass+e.mass)+2*e.velocity.x*e.mass/(this.mass+e.mass),c),e.velocity.x=lerp(d,f,c)):this.velocity.x*=-c);debugPhysics&&debugOverlap(this.pos,this.size,e.pos,e.size,"#f0f")}if(this.collideTiles&&(e=tileCollisionTest(this.pos,this.size,this))&&!tileCollisionTest(a,this.size,this)){d=tileCollisionTest(vec2(a.x,this.pos.y),this.size,this);c=tileCollisionTest(vec2(this.pos.x,a.y),this.size,this);if(d||!c)d=max(this.restitution,e.restitution),this.velocity.y*=-d,b?(this.pos.y=(a.y-this.size.y/2|0)+this.size.y/2+1e-4,this.groundObject=e):(this.pos.y=a.y,this.groundObject=void 0);c&&(this.pos.x=a.x,this.velocity.x*=-this.restitution);debugPhysics&&debugRect(this.pos,this.size,"#f00")}}}}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.parent=0,a.destroy()}}localToWorld(a){return this.pos.add(a.rotate(this.angle))}worldToLocal(a){return a.subtract(this.pos).rotate(-this.angle)}localToWorldVector(a){return a.rotate(this.angle)}worldToLocalVector(a){return a.rotate(-this.angle)}collideWithTile(a,b){return 0<a}collideWithObject(a){return!0}getAliveTime(){return time-this.spawnTime}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyAngularAcceleration(a){this.mass&&(this.angleVelocity+=a)}applyForce(a){this.mass&&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,d=!0){ASSERT(a||!b,"solid objects must be set to collide");this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c;this.collideRaycast=d}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}}renderDebugInfo(){if(debug){var a=vec2(max(this.size.x,.2),max(this.size.y,.2)),b=rgb(this.collideTiles?1:0,this.collideSolidObjects?1:0,this.isSolid?1:0,.5);drawRect(this.pos,a,b,this.angle);this.parent&&drawRect(this.pos,a.scale(.8),rgb(1,1,1,.5),this.angle);this.parent&&drawLine(this.pos,this.parent.pos,.1,rgb(1,1,1,.5))}}}let mainCanvas,mainContext,overlayCanvas,overlayContext,drawCanvas,drawContext,workCanvas,workContext,mainCanvasSize=vec2(),textureInfos=[],drawCount;function tile(a=new Vector2,b=tileSizeDefault,c=0,d=0){if(headlessMode)return new TileInfo;"number"===typeof b&&(ASSERT(0<b),b=new Vector2(b,b));const e=new TileInfo(new Vector2,b,c,d);var f=textureInfos[c];ASSERT(!!f,"Texture not loaded");c=b.x+2*d;b=b.y+2*d;"number"===typeof a?(f=f.size.x/c|0,ASSERT(0<f,"Tile size is too big for texture"),e.pos.set(a%f*c+d,(a/f|0)*b+d)):e.pos.set(a.x*c+d,a.y*b+d);return e}class TileInfo{constructor(a=vec2(),b=tileSizeDefault,c=0,d=0,e=tileFixBleedScale){this.pos=a.copy();this.size=b.copy();this.textureIndex=c;this.padding=d;this.textureInfo=textureInfos[this.textureIndex];this.bleedScale=e}offset(a){return new TileInfo(this.pos.add(a),this.size,this.textureIndex,this.padding,this.bleedScale)}frame(a){ASSERT("number"===typeof a);return this.offset(new Vector2(a*(this.size.x+2*this.padding),0))}setFullImage(a,b){this.pos=new Vector2;this.size=new Vector2(a.width,a.height);this.textureInfo=new TextureInfo(a,b);this.bleedScale=this.padding=0;return this}}class TextureInfo{constructor(a,b){this.image=a;this.size=vec2(a.width,a.height);this.sizeInverse=vec2(1/a.width,1/a.height);this.glTexture=b}createWebGLTexture(){ASSERT(!this.glTexture);glEnable&&(this.glTexture=glCreateTexture(this.image))}}function drawTile(a,b=new Vector2(1),c,d=WHITE,e=0,f,g,h=glEnable,k,l){ASSERT(isVector2(a),"drawTile pos should be a vec2");ASSERT(isVector2(b),"drawTile size should be a vec2");ASSERT(isColor(d)&&(!g||isColor(g)),"drawTile color is invalid");ASSERT(isNumber(e),"drawTile angle should be a number");ASSERT(!l||!h,"context only supported in canvas 2D mode");const m=c&&c.textureInfo,n=c?c.bleedScale:0;if(h)if(k&&(a=screenToWorld(a),b=b.scale(1/cameraScale)),m){var p=m.sizeInverse;h=c.pos.x*p.x;k=c.pos.y*p.y;l=c.size.x*p.x;const r=c.size.y*p.y;glSetTexture(m.glTexture);if(n){const q=p.x*n;p=p.y*n;glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h+q,k+p,h-q+l,k-p+r,d.rgbaInt(),g&&g.rgbaInt())}else glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h,k,h+l,k+r,d.rgbaInt(),g&&g.rgbaInt())}else glDraw(a.x,a.y,b.x,b.y,e,0,0,0,0,0,d.rgbaInt());else++drawCount,b=new Vector2(b.x,-b.y),drawCanvas2D(a,b,e,f,r=>{if(m)drawImageColor(r,m.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1,d,g,n);else{const q=g?d.add(g):d;r.fillStyle=q.toString();r.fillRect(-.5,-.5,1,1)}},k,l)}function drawRect(a,b,c,d,e,f,g){drawTile(a,b,void 0,c,d,!1,void 0,e,f,g)}function drawRectGradient(a,b,c=WHITE,d=BLACK,e=0,f=glEnable,g=!1,h){ASSERT(isVector2(a),"drawRectGradient pos should be a vec2");ASSERT(isVector2(b),"drawRectGradient size should be a vec2");ASSERT(isColor(c)&&isColor(d),"drawRectGradient color is invalid");ASSERT(isNumber(e),"drawRectGradient angle should be a number");ASSERT(!h||!f,"context only supported in canvas 2D mode");if(f){g&&(a=screenToWorld(a),b=b.scale(1/cameraScale));f=[];g=[];h=b.x/2;b=b.y/2;const k=c.rgbaInt(),l=d.rgbaInt(),m=Math.cos(-e);e=Math.sin(-e);for(let n=4;n--;){const p=n&1?h:-h,r=n&2?b:-b,q=n&2?k:l;f.push(vec2(a.x+(p*m-r*e),a.y+(p*e+r*m)));g.push(q)}glDrawColoredPoints(f,g)}else++drawCount,b=new Vector2(b.x,-b.y),drawCanvas2D(a,b,e,!1,k=>{const l=k.createLinearGradient(0,-.5,0,.5);l.addColorStop(0,c.toString());l.addColorStop(1,d.toString());k.fillStyle=l;k.fillRect(-.5,-.5,1,1)},g,h)}function drawLineList(a,b=.1,c,d=!1,e=vec2(),f=0,g=glEnable,h,k){ASSERT(Array.isArray(a),"drawLineList points should be an array");ASSERT(isNumber(b),"drawLineList width should be a number");ASSERT(isColor(c),"drawLineList color is invalid");ASSERT(isVector2(e),"drawLineList pos should be a vec2");ASSERT(isNumber(f),"drawLineList angle should be a number");ASSERT(!k||!g,"context only supported in canvas 2D mode");g?(g=1,h&&(e=screenToWorld(e),g=1/cameraScale),glDrawOutlineTransform(a,c.rgbaInt(),b,e.x,e.y,g,g,f,d)):(++drawCount,drawCanvas2D(e,vec2(1),f,!1,l=>{l.strokeStyle=c.toString();l.lineWidth=b;l.beginPath();for(let m=0;m<a.length;++m){const n=a[m];m?l.lineTo(n.x,n.y):l.moveTo(n.x,n.y)}d&&l.closePath();l.stroke()},h,k))}function drawLine(a,b,c=.1,d,e=vec2(),f=0,g,h,k){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());e=e.add(a.add(b));f+=b.angle();drawRect(e,c,d,f,g,h,k)}function drawRegularPoly(a,b=vec2(1),c=3,d=WHITE,e=0,f=BLACK,g=0,h=glEnable,k=!1,l){ASSERT(isVector2(b),"drawRegularPoly size should be a vec2");ASSERT(isNumber(c),"drawRegularPoly sides should be a number");const m=[],n=b.x/2;b=b.y/2;for(let p=c;p--;){const r=p/c*PI*2;m.push(vec2(Math.sin(r)*n,Math.cos(r)*b))}drawPoly(m,d,e,f,a,g,h,k,l)}function drawPoly(a,b=WHITE,c=0,d=BLACK,e=vec2(),f=0,g=glEnable,h=!1,k){ASSERT(isVector2(e),"drawPoly pos should be a vec2");ASSERT(Array.isArray(a),"drawPoly points should be an array");ASSERT(isColor(b)&&isColor(d),"drawPoly color is invalid");ASSERT(isNumber(c),"drawPoly lineWidth should be a number");ASSERT(isNumber(f),"drawPoly angle should be a number");ASSERT(!k||!g,"context only supported in canvas 2D mode");g?(g=1,h&&(e=screenToWorld(e),g=1/cameraScale),glDrawPointsTransform(a,b.rgbaInt(),e.x,e.y,g,g,f),0<c&&glDrawOutlineTransform(a,d.rgbaInt(),c,e.x,e.y,g,g,f)):drawCanvas2D(e,vec2(1),f,!1,l=>{l.fillStyle=b.toString();l.beginPath();for(const m of a)l.lineTo(m.x,m.y);l.closePath();l.fill();c&&(l.strokeStyle=d.toString(),l.lineWidth=c,l.stroke())},h,k)}function drawEllipse(a,b=vec2(1),c=WHITE,d=0,e=0,f=BLACK,g=glEnable,h=!1,k){ASSERT(isVector2(a),"drawEllipse pos should be a vec2");ASSERT(isVector2(b),"drawEllipse size should be a vec2");ASSERT(isColor(c)&&isColor(f),"drawEllipse color is invalid");ASSERT(isNumber(d),"drawEllipse angle should be a number");ASSERT(isNumber(e),"drawEllipse lineWidth should be a number");ASSERT(0<=e&&e<b.x&&e<b.y,"drawEllipse invalid lineWidth");ASSERT(!k||!g,"context only supported in canvas 2D mode");g?drawRegularPoly(a,b,glCircleSides,c,e,f,d,g,h,k):drawCanvas2D(a,vec2(1),d,!1,l=>{l.fillStyle=c.toString();l.beginPath();l.ellipse(0,0,b.x/2,b.y/2,0,0,9);l.fill();e&&(l.strokeStyle=f.toString(),l.lineWidth=e,l.stroke())},h,k)}function drawCircle(a,b=1,c=WHITE,d=0,e=BLACK,f=glEnable,g=!1,h){ASSERT(isNumber(b),"drawCircle size should be a number");drawEllipse(a,vec2(b),c,0,d,e,f,g,h)}function drawCanvas2D(a,b,c=0,d=!1,e,f=!1,g=drawContext){f||(a=worldToScreen(a),b=b.scale(cameraScale));g.save();g.translate(a.x+.5,a.y+.5);g.rotate(c-cameraAngle);g.scale(d?-b.x:b.x,-b.y);e(g);g.restore()}function drawText(a,b,c=1,d,e=0,f,g,h,k,l=drawContext){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,h,k,l)}function drawTextOverlay(a,b,c=1,d,e=0,f,g,h,k){drawText(a,b,c,d,e,f,g,h,k,overlayContext)}function drawTextScreen(a,b,c=1,d=WHITE,e=0,f=BLACK,g="center",h=fontDefault,k,l=overlayContext){l.fillStyle=d.toString();l.strokeStyle=f.toString();l.lineWidth=e;l.textAlign=g;l.font=c+"px "+h;l.textBaseline="middle";a=(a+"").split("\n");let m=b.y;m-=(a.length-1)*c/2;a.forEach(n=>{e&&l.strokeText(n,b.x,m,k);l.fillText(n,b.x,m,k);m+=c})}function screenToWorld(a){let b=(a.x-mainCanvasSize.x/2+.5)/cameraScale;a=(a.y-mainCanvasSize.y/2+.5)/-cameraScale;if(cameraAngle){const c=Math.cos(-cameraAngle),d=Math.sin(-cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b+cameraPos.x,a+cameraPos.y)}function worldToScreen(a){let b=a.x-cameraPos.x;a=a.y-cameraPos.y;if(cameraAngle){const c=Math.cos(cameraAngle),d=Math.sin(cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b*cameraScale+mainCanvasSize.x/2-.5,a*-cameraScale+mainCanvasSize.y/2-.5)}function getCameraSize(){return mainCanvasSize.scale(1/cameraScale)}function setBlendMode(a=!1,b){glAdditive=a;b||=drawContext;b.globalCompositeOperation=a?"lighter":"source-over"}function combineCanvases(){glCopyToContext(mainContext);mainContext.drawImage(overlayCanvas,0,0);glClearCanvas();overlayCanvas.width|=0}function drawImageColor(a,b,c,d,e,f,g,h,k,l,m,n,p=0){function r(t){return 1<=t.r&&1<=t.g&&1<=t.b}const q=e-2*p,u=f-2*p;if(!canvasColorTiles||(n?r(m.add(n))&&0>=n.a:r(m)))a.globalAlpha=m.a,a.drawImage(b,c+p,d+p,q,u,g,h,k,l),a.globalAlpha=1;else if(workCanvas.width=e,workCanvas.height=f,workContext.drawImage(b,c,d,e,f,0,0,e,f),b=workContext.getImageData(0,0,e,f),c=b.data,!n||0>=n.r&&0>=n.g&&0>=n.b&&0>=n.a){for(n=0;n<c.length;n+=4)c[n]*=m.r,c[n+1]*=m.g,c[n+2]*=m.b;workContext.putImageData(b,0,0);a.globalAlpha=m.a;a.drawImage(workCanvas,p,p,q,u,g,h,k,l);a.globalAlpha=1}else{m=[m.r,m.g,m.b,m.a];n=[255*n.r,255*n.g,255*n.b,255*n.a];for(d=0;d<c.length;++d)c[d]=c[d]*m[d&3]+n[d&3]|0;workContext.putImageData(b,0,0);a.drawImage(workCanvas,p,p,q,u,g,h,k,l)}}function isFullscreen(){return!!document.fullscreenElement}function toggleFullscreen(){const a=mainCanvas.parentElement;isFullscreen()?document.exitFullscreen&&document.exitFullscreen():a.requestFullscreen&&a.requestFullscreen()}function setCursor(a="auto"){mainCanvas.parentElement.style.cursor=a}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d){engineFontImage||(engineFontImage=new Image,engineFontImage.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC");this.image=a||engineFontImage;this.tileSize=b;this.paddingSize=c}drawText(a,b,c=1,d,e=drawContext){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d,e)}drawTextOverlay(a,b,c=4,d){this.drawText(a,b,c,d,overlayContext)}drawTextScreen(a,b,c=4,d,e=overlayContext){e.save();const f=this.tileSize,g=f.add(this.paddingSize).scale(c),h=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((k,l)=>{const m=d?k.length*f.x*c/2|0:0;for(let r=k.length;r--;){var n=k[r].charCodeAt(0);if(32>n||127<n)n=127;var p=n-32;n=p%h;p=p/h|0;const q=b.add(vec2(r,l).multiply(g));e.drawImage(this.image,n*f.x,p*f.y,f.x,f.y,q.x-m,q.y,f.x*c,f.y*c)}});e.restore()}}function keyIsDown(a,b=0){ASSERT(void 0!==a,"key is undefined");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(void 0!==a,"key is undefined");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(void 0!==a,"key is undefined");ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&4)}function keyDirection(a="ArrowUp",b="ArrowDown",c="ArrowLeft",d="ArrowRight"){return vec2((keyIsDown(d)?1:0)-(keyIsDown(c)?1:0),(keyIsDown(a)?1:0)-(keyIsDown(b)?1:0))}function inputClear(){inputData=[[]];touchGamepadButtons=[]}function inputClearKey(a,b=0,c=!0,d=!0,e=!0){inputData[b]&&(inputData[b][a]&=~((c?1:0)|(d?2:0)|(e?4:0)))}function mouseIsDown(a){return keyIsDown(a)}function mouseWasPressed(a){return keyWasPressed(a)}function mouseWasReleased(a){return keyWasReleased(a)}let mousePos=vec2(),mousePosScreen=vec2(),mouseDelta=vec2(),mouseDeltaScreen=vec2(),mouseWheel=0,isUsingGamepad=!1,inputPreventDefault=!0;function setInputPreventDefault(a){inputPreventDefault=a}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 gamepadStickData[b]?gamepadStickData[b][a]||vec2():vec2()}let inputData=[[]];function inputUpdate(){headlessMode||(touchInputEnable&&isTouchDevice||document.hasFocus()||inputClear(),mousePos=screenToWorld(mousePosScreen),mouseDelta=mouseDeltaScreen.multiply(vec2(1,-1)).rotate(-cameraAngle),gamepadsUpdate())}function inputUpdatePost(){if(!headlessMode){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=0;mouseDelta=vec2();mouseDeltaScreen=vec2()}}function inputInit(){function a(b){return inputWASDEmulateDirection?"KeyW"===b?"ArrowUp":"KeyS"===b?"ArrowDown":"KeyA"===b?"ArrowLeft":"KeyD"===b?"ArrowRight":b:b}headlessMode||(document.addEventListener("keydown",function(b){b.repeat||(isUsingGamepad=!1,inputData[0][b.code]=3,inputWASDEmulateDirection&&(inputData[0][a(b.code)]=3))}),document.addEventListener("keyup",function(b){inputData[0][b.code]=inputData[0][b.code]&2|4;inputWASDEmulateDirection&&(inputData[0][a(b.code)]=4)}),document.addEventListener("mousedown",function(b){isTouchDevice&&touchInputEnable||(soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioContext.resume(),isUsingGamepad=!1,inputData[0][b.button]=3,mousePosScreen=mouseEventToScreen(vec2(b.x,b.y)),inputPreventDefault&&b.button&&b.preventDefault())}),document.addEventListener("mouseup",function(b){isTouchDevice&&touchInputEnable||(inputData[0][b.button]=inputData[0][b.button]&2|4)}),document.addEventListener("mousemove",function(b){mousePosScreen=mouseEventToScreen(vec2(b.x,b.y));mouseDeltaScreen=mouseDeltaScreen.add(vec2(b.movementX,b.movementY))}),document.addEventListener("wheel",function(b){mouseWheel=b.ctrlKey?0:sign(b.deltaY)}),document.addEventListener("contextmenu",function(b){b.preventDefault()}),document.addEventListener("blur",function(){inputClear()}),document.addEventListener("mouseleave",function(){mousePosScreen=vec2(Infinity);mouseDeltaScreen=vec2(0)}),isTouchDevice&&touchInputEnable&&touchInputInit())}function mouseEventToScreen(a){const b=mainCanvas.getBoundingClientRect(),c=percent(a.x,b.left,b.right);a=percent(a.y,b.top,b.bottom);return vec2(c*mainCanvas.width,a*mainCanvas.height)}const gamepadStickData=[];function gamepadsUpdate(){const a=g=>{const h=k=>.3<k?percent(k,.3,.8):-.3>k?-percent(-k,.3,.8):0;return vec2(h(g.x),h(-g.y)).clampLength()};if(touchGamepadEnable&&isTouchDevice){if(!touchGamepadTimer.isSet())return;var b=gamepadStickData[0]||(gamepadStickData[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,e=gamepadIsDown(d,0);b[d]=touchGamepadButtons[c]?e?1:3:e?4:0}}if(gamepadsEnable&&navigator&&navigator.getGamepads&&(debug||document.hasFocus()))for(b=navigator.getGamepads(),c=b.length;c--;){e=b[c];const g=inputData[c+1]||(inputData[c+1]=[]);d=gamepadStickData[c]||(gamepadStickData[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 h=e.buttons[f],k=gamepadIsDown(f,c);g[f]=h.pressed?k?1:3:k?4:0;(!h.value||.9<h.value)&&!c&&h.pressed&&(isUsingGamepad=!0)}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&&!headlessMode&&navigator&&navigator.vibrate&&navigator.vibrate(a)}function vibrateStop(){vibrate(0)}const isTouchDevice=!headlessMode&&void 0!==window.ontouchstart;let touchGamepadTimer=new Timer,touchGamepadButtons=[],touchGamepadStick=vec2();function touchInputInit(){let a=function(c){if(touchInputEnable){if(touchGamepadEnable)a:{touchGamepadStick=vec2();touchGamepadButtons=[];isUsingGamepad=!0;if(c.touches.length&&(touchGamepadTimer.set(),paused&&!b)){touchGamepadButtons[9]=1;break a}var d=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),e=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),f=mainCanvasSize.scale(.5);for(const h of c.touches){var g=mouseEventToScreen(vec2(h.clientX,h.clientY));g.distance(d)<touchGamepadSize?touchGamepadStick=g.subtract(d).scale(2/touchGamepadSize).clampLength():g.distance(e)<touchGamepadSize?(g=g.subtract(e).direction(),touchGamepadButtons[g]=1):g.distance(f)<touchGamepadSize&&!b&&(touchGamepadButtons[9]=1)}}soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioContext.resume();(d=c.touches.length)?(e=vec2(c.touches[0].clientX,c.touches[0].clientY),f=mousePosScreen,mousePosScreen=mouseEventToScreen(e),b?(mouseDeltaScreen=mouseDeltaScreen.add(mousePosScreen.subtract(f)),isUsingGamepad=touchGamepadEnable):inputData[0][0]=3):b&&(inputData[0][0]=inputData[0][0]&2|4);b=d;inputPreventDefault&&document.hasFocus()&&c.preventDefault();return!0}};document.addEventListener("touchstart",c=>a(c),{passive:!1});document.addEventListener("touchmove",c=>a(c),{passive:!1});document.addEventListener("touchend",c=>a(c),{passive:!1});let b}function touchGamepadRender(){if(touchInputEnable&&isTouchDevice&&!headlessMode&&touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer.get(),4,3);if(a&&!paused){var b=overlayContext;b.save();b.globalAlpha=a*touchGamepadAlpha;b.strokeStyle="#fff";b.lineWidth=3;b.fillStyle=0<touchGamepadStick.lengthSquared()?"#fff":"#000";b.beginPath();a=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize);if(touchGamepadAnalog)b.arc(a.x,a.y,touchGamepadSize/2,0,9),b.fill();else for(var c=10;c--;){var d=c*PI/4;b.arc(a.x,a.y,.6*touchGamepadSize,d+PI/8,d+PI/8);c%2&&b.arc(a.x,a.y,.33*touchGamepadSize,d,d);1===c&&b.fill()}b.stroke();a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);for(c=4;c--;)d=a.add(vec2().setDirection(c,touchGamepadSize/2)),b.fillStyle=touchGamepadButtons[c]?"#fff":"#000",b.beginPath(),b.arc(d.x,d.y,touchGamepadSize/4,0,9),b.fill(),b.stroke();b.restore()}}}function pointerLockRequest(){isTouchDevice||mainCanvas.requestPointerLock&&mainCanvas.requestPointerLock()}function pointerLockExit(){document.exitPointerLock&&document.exitPointerLock()}function pointerLockIsActive(){return document.pointerLockElement===mainCanvas}let audioContext=new AudioContext,audioMasterGain;const audioDefaultSampleRate=44100;function audioIsRunning(){return"running"===audioContext.state}function audioInit(){soundEnable&&!headlessMode&&(audioMasterGain=audioContext.createGain(),audioMasterGain.connect(audioContext.destination),audioMasterGain.gain.value=soundVolume)}class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&!headlessMode&&(this.range=b,this.taper=c,this.randomness=0,this.sampleRate=audioDefaultSampleRate,this.loadedPercent=0,a&&(this.randomness=void 0!==a[1]?a[1]:.05,a[1]=0,this.sampleChannels=[zzfxG(...a)],this.loadedPercent=1))}play(a,b=1,c=1,d=1,e=!1,f=!1){if(soundEnable&&!headlessMode&&this.sampleChannels){var g;if(a){if(g=this.range){const h=cameraPos.distanceSquared(a);if(h>g*g)return;b*=percent(h**.5,g,g*this.taper)}g=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return new SoundInstance(this,b,a,g,e,f)}}playMusic(a=1,b=!0,c=!1){return this.play(void 0,a,1,0,b,c)}playNote(a,b,c){a=getNoteFrequency(a,1);return this.play(b,c,a,0)}getDuration(){return this.sampleChannels&&this.sampleChannels[0].length/this.sampleRate}isLoaded(){return 1===this.loadedPercent}}class SoundWave extends Sound{constructor(a,b=0,c,d,e){super(void 0,c,d);soundEnable&&!headlessMode&&(this.onloadCallback=e,this.randomness=b,this.loadSound(a))}async loadSound(a){a=await(await fetch(a)).arrayBuffer();a=await audioContext.decodeAudioData(a);const b=a.numberOfChannels,c=[];for(let d=0;d<b;d++){const e=a.getChannelData(d),f=e.length;c[d]=Array(f);let g=0;for(;g<f;){await new Promise(k=>setTimeout(k,0));const h=min(g+1e5,f);for(;g<h;g++)c[d][g]=e[g];this.loadedPercent=(d*f+g)/(b*f)}}this.sampleRate=a.sampleRate;this.sampleChannels=c;this.loadedPercent=1;if(this.onloadCallback)this.onloadCallback()}}class SoundInstance{constructor(a,b=1,c=1,d=0,e=!1,f=!1){ASSERT(a instanceof Sound,"SoundInstance requires a valid Sound object");ASSERT(0<=b,"Sound volume must be positive or zero");ASSERT(0<=c,"Sound rate must be positive or zero");ASSERT(isNumber(d),"Sound pan must be a number");this.sound=a;this.volume=b;this.rate=c;this.pan=d;this.loop=e;this.pausedTime=0;this.source=this.gainNode=this.startTime=void 0;this.onendedCallback=g=>{g===this.source&&(this.source=void 0)};f||this.start()}start(a=0){ASSERT(0<=a,"Sound start offset must be positive or zero");this.isPlaying()&&this.stop();this.gainNode=audioContext.createGain();this.source=playSamples(this.sound.sampleChannels,this.volume,this.rate,this.pan,this.loop,this.sound.sampleRate,this.gainNode,a,this.onendedCallback);this.startTime=audioContext.currentTime-a;this.pausedTime=void 0}setVolume(a){ASSERT(0<=a,"Sound volume must be positive or zero");this.volume=a;this.gainNode&&(this.gainNode.gain.value=a)}stop(a=0){ASSERT(0<=a,"Sound fade time must be positive or zero");if(this.isPlaying())if(a){const b=audioContext.currentTime;a=b+a;this.gainNode.gain.linearRampToValueAtTime(1,b);this.gainNode.gain.linearRampToValueAtTime(0,a);this.source.stop(a)}else this.source.stop();this.pausedTime=0;this.startTime=this.source=void 0}pause(){this.isPaused()||(this.pausedTime=this.getCurrentTime(),this.source.stop(),this.startTime=this.source=void 0)}resume(){this.isPaused()&&this.start(this.pausedTime)}isPlaying(){return!!this.source}isPaused(){return!this.isPlaying()}getCurrentTime(){const a=mod(audioContext.currentTime-this.startTime,this.getDuration());return this.isPlaying()?a:this.pausedTime}getDuration(){return this.sound.getDuration()/this.rate}getSource(){return this.source}}function speak(a,b="",c=1,d=1,e=1){if(soundEnable&&!headlessMode&&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)}function playSamples(a,b=1,c=1,d=0,e=!1,f=audioDefaultSampleRate,g,h=0,k){if(soundEnable&&!headlessMode){var l=audioContext.createBuffer(a.length,a[0].length,f),m=audioContext.createBufferSource();a.forEach((n,p)=>l.getChannelData(p).set(n));m.buffer=l;m.playbackRate.value=c;m.loop=e;g=g||audioContext.createGain();g.gain.value=b;g.connect(audioMasterGain);a=new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)});m.connect(a).connect(g);k&&m.addEventListener("ended",()=>k(m));if(audioIsRunning())return m.start(0,h*c),m;audioContext.resume()}}function zzfx(...a){return playSamples([zzfxG(...a)])}function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,h=1,k=0,l=0,m=0,n=0,p=0,r=0,q=0,u=0,t=0,w=1,x=0,B=0,z=0){var v=audioDefaultSampleRate;let y=2*PI,D=k*=500*y/v/v;b=c*=(1+rand(b,-b))*y/v;let G=0,J=0,H=0,E=1,K=[],F=0,A=0,C=0,O;var M=y*abs(z)*2/v,L=Math.cos(M),N=Math.sin(M)/2/2,I=1+N;M=-2*L/I;N=(1-N)/I;let P=(1+sign(z)*L)/2/I;L=-(sign(z)+L)/I;let Q=I=0,R=0,S=0;d=d*v||9;x*=v;e*=v;f*=v;t*=v;l*=500*y/v**3;q*=y/v;m*=y/v;n*=v;p=p*v|0;for(v=d+x+e+f+t|0;A<v;K[A++]=C*a)++H%(100*u|0)||(C=g?1<g?2<g?3<g?4<g?F/y%1<h/2?1:-1:Math.sin(F**3):Math.max(Math.min(Math.tan(F),1),-1):1-(2*F/y%2+2)%2:1-4*abs(Math.round(F/y)-F/y):Math.sin(F),C=(p?1-B+B*Math.sin(y*A/p):1)*(4<g?C:sign(C)*abs(C)**h)*(A<d?A/d:A<d+x?1-(A-d)/x*(1-w):A<d+x+e?w:A<v-t?(v-A-t)/f*w:0),C=t?C/2+(t>A?0:(A<v-t?1:(v-A)/t)*K[A-t|0]/2/a):C,z&&(C=S=P*I+L*(I=Q)+P*(Q=C)-N*R-M*(R=S))),O=(c+=k+=l)*Math.cos(q*G++),F+=O+O*r*Math.sin(A**5),E&&++E>n&&(c+=m,b+=m,E=0),!p||++J%p||(c=b,k=D,E||=1);return K}const tileCollisionLayers=[];function tileCollisionGetData(a){for(const b of tileCollisionLayers)if(a.arrayCheck(b.size))return b.getCollisionData(a);return 0}function tileCollisionTest(a,b=vec2(),c,d=!0){for(const e of tileCollisionLayers)if((!d||e.isSolid)&&e.collisionTest(a,b,c))return e}function tileCollisionRaycast(a,b,c,d=!0){for(const e of tileCollisionLayers)if(!d||e.isSolid){const f=e.collisionRaycast(a,b,c);if(f)return f}}function tileCollisionLoad(a,b=tile(),c=0,d,e=!0){a||(a={},a.height=a.width=50,a.layers=[{}],a.layers[0].data=Array(2500).fill(0));ASSERT(a.width&&a.height);ASSERT(a.layers&&a.layers.length);const f=[],g=vec2(a.width,a.height),h=a.layers.length;for(let m=h;m--;){const n=a.layers[m];ASSERT(n.data&&n.data.length);ASSERT(g.area()===n.data.length);var k=c-(h-1-m);k=new TileCollisionLayer(vec2(),g,b,k);f[m]=k;for(let p=g.x;p--;)for(let r=g.y;r--;){const q=vec2(p,g.y-1-r);var l=n.data[p+r*g.x];l&&(l=new TileLayerData(l-1),k.setData(q,l),m===d&&k.setCollisionData(q,1))}e&&k.redraw()}return f}class TileLayerData{constructor(a,b=0,c=!1,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d.copy()}clear(){this.tile=this.direction=0;this.mirror=!1;this.color=new Color}}class CanvasLayer extends EngineObject{constructor(a,b,c=0,d=0,e=vec2(512)){super(a,b,void 0,c,WHITE,d);this.canvas=headlessMode?void 0:new OffscreenCanvas(e.x,e.y);this.context=headlessMode?void 0:this.canvas.getContext("2d");this.glTexture=void 0;this.gravityScale=0}destroy(){this.destroyed||(this.glTexture&&glDeleteTexture(this.glTexture),super.destroy())}render(){this.draw(this.pos,this.size,this.angle,this.color,this.mirror,this.additiveColor)}draw(a,b,c=0,d=WHITE,e=!1,f,g=!1,h){const k=glEnable&&void 0!==this.glTexture,l=(new TileInfo).setFullImage(this.canvas,this.glTexture);drawTile(a,b,l,d,c,e,f,k,g,h)}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 h=c&&c.textureInfo;h?(g.globalAlpha=d.a,g.drawImage(h.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)}useWebGL(a=!0){glEnable&&a?this.glTexture?glSetTextureData(this.glTexture,this.canvas):this.glTexture=glCreateTexture(this.canvas):this.glTexture=void 0}}class TileLayer extends CanvasLayer{constructor(a,b,c=tile(),d=vec2(1),e=0,f=glEnable){super(a,b,0,e,b);this.tileInfo=c;a=b.multiply(c.size);this.canvas=new OffscreenCanvas(a.x,a.y);this.context=this.canvas.getContext("2d");this.glTexture=f?glCreateTexture(this.canvas):void 0;this.restitution=this.friction=0;this.data=[];for(f=this.size.area();f--;)this.data.push(new TileLayerData);headlessMode&&(this.redraw=()=>{},this.render=()=>{},this.redrawStart=()=>{},this.redrawEnd=()=>{},this.drawTileData=()=>{},this.drawCanvas2D=()=>{},this.useWebGL=()=>{})}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]}render(){ASSERT(drawContext!==this.context,"must call redrawEnd() after drawing tiles!");const a=(new TileInfo).setFullImage(this.canvas,this.glTexture),b=this.pos.add(this.size.scale(.5));drawTile(b,this.size,a,WHITE,0,!1,CLEAR_BLACK,glEnable&&void 0!==this.glTexture)}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();this.glTexture&&this.useWebGL()}redrawStart(a=!1){this.savedRenderSettings=[drawCanvas,drawContext,mainCanvasSize,cameraPos,cameraScale];drawCanvas=this.canvas;drawContext=this.context;cameraPos=this.size.scale(.5);cameraScale=this.tileInfo.size.x;mainCanvasSize=this.size.multiply(this.tileInfo.size);a&&(drawCanvas.width=mainCanvasSize.x,drawCanvas.height=mainCanvasSize.y);this.context.imageSmoothingEnabled=!tilesPixelated;glPreRender()}redrawEnd(){ASSERT(drawContext===this.context,"must call redrawStart() before drawing tiles");glCopyToContext(drawContext);[drawCanvas,drawContext,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&&(ASSERT(drawContext===this.context,"must call redrawStart() before drawing tiles"),a=a.add(vec2(.5)),c=tile(b.tile,c,this.tileInfo.textureIndex,this.tileInfo.padding),drawTile(a,vec2(1),c,b.color,b.direction*PI/2,b.mirror))}}class TileCollisionLayer extends TileLayer{constructor(a,b,c=tile(),d=0,e=glEnable){const f=vec2(1);super(a,b.floor(),c,f,d,e);this.collisionData=[];this.initCollision(this.size);tileCollisionLayers.push(this);this.isSolid=!0}destroy(){if(!this.destroyed){var a=tileCollisionLayers.indexOf(this);ASSERT(0<=a,"tile collision layer not found in array");tileCollisionLayers.splice(a,1);super.destroy()}}initCollision(a){this.size=a.floor();this.collisionData=[];this.collisionData.length=a.area();this.collisionData.fill(0)}setCollisionData(a,b=1){const c=(a.y|0)*this.size.x+a.x|0;a.arrayCheck(this.size)&&(this.collisionData[c]=b)}getCollisionData(a){const b=(a.y|0)*this.size.x+a.x|0;return a.arrayCheck(this.size)?this.collisionData[b]:0}collisionTest(a,b=new Vector2,c){var d=a.x-this.pos.x,e=a.y-this.pos.y;a=max(d-b.x/2|0,0);var f=max(e-b.y/2|0,0);d=min(d+b.x/2,this.size.x);b=min(e+b.y/2,this.size.y);for(e=new Vector2;f<b;++f)for(let g=a;g<d;++g){const h=this.collisionData[f*this.size.x+g];if(h&&(!c||c.collideWithTile(h,e.set(g,f))))return!0}return!1}collisionRaycast(a,b,c){var d=b.x-this.pos.x-(a.x-this.pos.x),e=b.y-this.pos.y-(a.y-this.pos.y);const f=(d**2+e**2)**.5,g=abs(f/d),h=abs(f/e),k=a.floor(),l=sign(d),m=sign(e);d=g*(0>d?a.x-k.x:k.x-a.x+1)||0;for(e=h*(0>e?a.y-k.y:k.y-a.y+1)||0;;){const n=this.getCollisionData(k);if(n&&(!c||c.collideWithTile(n,k)))return k.x+=.5,k.y+=.5,debugRaycast&&debugLine(a,b,"#f00",.02),debugRaycast&&debugPoint(k,"#ff0"),k;if(d>=f&&e>=f)break;d>e?(k.y+=m,e+=h):(k.x+=l,d+=g)}debugRaycast&&debugLine(a,b,"#00f",.02)}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,h=new Color,k=new Color,l=new Color(1,1,1,0),m=new Color(1,1,1,0),n=.5,p=.1,r=1,q=.1,u=.05,t=1,w=1,x=0,B=PI,z=.1,v=.2,y=!1,D=!1,G=!0,J=D?1e9:0,H=!1){super(a,vec2(),g,b,void 0,J);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h;this.colorStartB=k;this.colorEndA=l;this.colorEndB=m;this.randomColorLinear=G;this.particleTime=n;this.sizeStart=p;this.sizeEnd=r;this.speed=q;this.angleSpeed=u;this.damping=t;this.angleDamping=w;this.gravityScale=x;this.particleConeAngle=B;this.fadeRate=z;this.randomness=v;this.collideTiles=y;this.additive=D;this.localSpace=H;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){var a=1/this.emitRate/particleEmitRateScale;for(this.emitTimeBuffer+=timeDelta;0<this.emitTimeBuffer;this.emitTimeBuffer-=a)this.emitParticle()}}else this.destroy();debugParticles&&(a="number"===typeof this.emitSize?vec2(this.emitSize):this.emitSize,debugRect(this.pos,a,"#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=n=>n+n*rand(c,-c);const e=d(this.particleTime),f=d(this.sizeStart),g=d(this.sizeEnd),h=d(this.speed);d=d(this.angleSpeed)*randSign();var k=rand(this.emitConeAngle,-this.emitConeAngle);const l=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),m=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);k=this.localSpace?k:this.angle+k;a=new Particle(a,this.tileInfo,b,l,m,e,f,g,this.fadeRate,this.additive,this.trailScale,this.localSpace&&this,this.particleDestroyCallback);a.velocity=vec2().setAngle(k,h);a.angleVelocity=d;this.localSpace||(a.velocity.x+=this.velocity.x,a.velocity.y+=this.velocity.y,a.angleVelocity+=this.angleVelocity);a.fadeRate=this.fadeRate;a.damping=this.damping;a.angleDamping=this.angleDamping;a.restitution=this.restitution;a.friction=this.friction;a.gravityScale=this.gravityScale;a.collideTiles=this.collideTiles;a.renderOrder=this.renderOrder;a.mirror=randBool();this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d,e,f,g,h,k,l,m,n,p){super(a,vec2(),b,c);this.colorStart=d;this.colorEndDelta=e.subtract(d);this.lifeTime=f;this.sizeStart=g;this.sizeEndDelta=h-g;this.fadeRate=k;this.additive=l;this.trailScale=m;this.localSpaceEmitter=n;this.destroyCallback=p;this.clampSpeed=!1}update(){super.update();if(this.collideTiles||this.collideSolidObjects){var a=this.velocity.lengthSquared();a>objectMaxSpeed*objectMaxSpeed&&(a=objectMaxSpeed/a**.5,this.velocity.x*=a,this.velocity.y*=a)}}render(){const a=0<this.lifeTime?min((time-this.spawnTime)/this.lifeTime,1):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||medalsForEach(b=>b.unlocked=!!localStorage[b.storageKey()]);engineAddPlugin(void 0,function(){if(medalsDisplayQueue.length){var b=medalsDisplayQueue[0],c=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(c>medalDisplayTime)medalsDisplayTimeLast=0,medalsDisplayQueue.shift();else{const d=medalDisplayTime-medalDisplaySlideTime;b.render(c<medalDisplaySlideTime?1-c/medalDisplaySlideTime:c>d?(c-d)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}})}function medalsForEach(a){Object.values(medals).forEach(b=>a(b))}class Medal{constructor(a,b,c="",d="🏆",e){ASSERT(0<=a&&!medals[a]);this.id=a;this.name=b;this.description=c;this.icon=d;this.unlocked=!1;e&&((this.image=new Image).src=e);medals[a]=this}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName,"save name must be set"),localStorage[this.storageKey()]=this.unlocked=!0,medalsDisplayQueue.push(this))}render(a=0){const b=overlayContext;var c=min(medalDisplaySize.x,mainCanvas.width);const d=medalDisplaySize.y;var e=overlayCanvas.width-c;a*=-d;b.save();b.beginPath();b.fillStyle=new Color(.9,.9,.9).toString();b.strokeStyle=BLACK.toString();b.lineWidth=3;b.rect(e,a,c,d);b.fill();b.stroke();b.clip();const f=vec2(.1,.05).scale(d),g=d-2*f.x;this.renderIcon(vec2(e+f.x+g/2,a+d/2),g);const h=.5*d,k=.3*d;e=vec2(e+g+2*f.x,a+2*f.y+h/2);c=c-g-3*f.x;drawTextScreen(this.name,e,h,BLACK,0,void 0,"left",void 0,c);e.y=a+d-2*f.y-k/2;drawTextScreen(this.description,e,k,BLACK,0,void 0,"left",void 0,c);b.restore()}renderIcon(a,b){this.image?overlayContext.drawImage(this.image,a.x-b/2,a.y-b/2,b,b):drawTextScreen(this.icon,a,.7*b,BLACK)}storageKey(){return medalsSaveName+"_"+this.id}}let glCanvas,glContext,glAntialias=!0,glShader,glPolyShader,glPolyMode,glAdditive,glBatchAdditive,glActiveTexture,glArrayBuffer,glGeometryBuffer,glPositionData,glColorData,glBatchCount;const gl_ARRAY_BUFFER_SIZE=5e5,gl_INDICES_PER_INSTANCE=11,gl_INSTANCE_BYTE_STRIDE=4*gl_INDICES_PER_INSTANCE,gl_MAX_INSTANCES=gl_ARRAY_BUFFER_SIZE/gl_INSTANCE_BYTE_STRIDE|0,gl_INDICES_PER_POLY_VERTEX=3,gl_POLY_VERTEX_BYTE_STRIDE=4*gl_INDICES_PER_POLY_VERTEX,gl_MAX_POLY_VERTEXES=gl_ARRAY_BUFFER_SIZE/gl_POLY_VERTEX_BYTE_STRIDE|0;function glInit(){if(glEnable&&!headlessMode)if(glCanvas=document.createElement("canvas"),glContext=glCanvas.getContext("webgl2",{antialias:glAntialias})){mainCanvas.parentElement.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;uniform sampler2D s;in vec2 v;in vec4 d,e;out vec4 c;void main(){c=texture(s,v)*d+e;}");glPolyShader=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 m;in vec2 p;in vec4 c;out vec4 d;void main(){gl_Position=m*vec4(p,1,1);d=c;}","#version 300 es\nprecision highp float;in vec4 d;out vec4 c;void main(){c=d;}");var a=new ArrayBuffer(gl_ARRAY_BUFFER_SIZE);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glArrayBuffer=glContext.createBuffer();glGeometryBuffer=glContext.createBuffer();a=new Float32Array([glBatchCount=0,0,1,0,0,1,1,1]);glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,a,glContext.STATIC_DRAW)}else console.warn("WebGL2 not supported, falling back to 2D canvas rendering!"),glCanvas=glContext=void 0,glEnable=!1}function glSetInstancedMode(){if(glPolyMode){glFlush();glPolyMode=!1;glContext.useProgram(glShader);var a=0,b=(c,d,e,f)=>{c=glContext.getAttribLocation(glShader,c);const g=e&&gl_INSTANCE_BYTE_STRIDE,h=e&&1,k=1===e;glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,f,d,k,g,a);glContext.vertexAttribDivisor(c,h);a+=f*e};glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);b("g",glContext.FLOAT,0,2);glContext.bindBuffer(glContext.ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,gl_ARRAY_BUFFER_SIZE,glContext.DYNAMIC_DRAW);b("p",glContext.FLOAT,4,4);b("u",glContext.FLOAT,4,4);b("c",glContext.UNSIGNED_BYTE,1,4);b("a",glContext.UNSIGNED_BYTE,1,4);b("r",glContext.FLOAT,4,1)}}function glSetPolyMode(){if(!glPolyMode){glFlush();glPolyMode=!0;glContext.useProgram(glPolyShader);var a=0,b=(c,d,e,f)=>{c=glContext.getAttribLocation(glPolyShader,c);const g=1===e,h=gl_POLY_VERTEX_BYTE_STRIDE;glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,f,d,g,h,a);glContext.vertexAttribDivisor(c,0);a+=f*e};glContext.bindBuffer(glContext.ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,gl_ARRAY_BUFFER_SIZE,glContext.DYNAMIC_DRAW);b("p",glContext.FLOAT,4,2);b("c",glContext.UNSIGNED_BYTE,1,4)}}function glPreRender(){if(glEnable&&glContext){glClearCanvas();var a=vec2(2*cameraScale).divide(mainCanvasSize),b=cameraPos.rotate(-cameraAngle);b=vec2(-1).subtract(b.multiply(a));var c=Math.cos(cameraAngle),d=Math.sin(cameraAngle);a=[a.x*c,a.y*d,0,0,-a.x*d,a.y*c,0,0,1,1,1,0,b.x,b.y,0,1];b=glPolyShader;glContext.useProgram(b);b=glContext.getUniformLocation(b,"m");glContext.uniformMatrix4fv(b,!1,a);b=glShader;glContext.useProgram(b);b=glContext.getUniformLocation(b,"m");glContext.uniformMatrix4fv(b,!1,a);glContext.activeTexture(glContext.TEXTURE0);textureInfos[0]&&(glActiveTexture=textureInfos[0].glTexture,glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture));glAdditive=glBatchAdditive=!1;glPolyMode=!0;glSetInstancedMode()}}function glClearCanvas(){glContext&&(glCanvas.width=drawCanvas.width,glCanvas.height=drawCanvas.height,glContext.viewport(0,0,glCanvas.width,glCanvas.height),glContext.clear(glContext.COLOR_BUFFER_BIT))}function glSetTexture(a,b=!1){glContext&&a!==glActiveTexture&&(glFlush(),glActiveTexture=a,glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture),a=b?glContext.REPEAT:glContext.CLAMP_TO_EDGE,glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_S,a),glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_T,a))}function glCompileShader(a,b){if(glContext){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,glContext.COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}}function glCreateProgram(a,b){if(glContext){var c=glContext.createProgram();glContext.attachShader(c,glCompileShader(a,glContext.VERTEX_SHADER));glContext.attachShader(c,glCompileShader(b,glContext.FRAGMENT_SHADER));glContext.linkProgram(c);if(debug&&!glContext.getProgramParameter(c,glContext.LINK_STATUS))throw glContext.getProgramInfoLog(c);return c}}function glCreateTexture(a){if(glContext){var b=glContext.createTexture(),c=!1;a&&a.width?(glSetTextureData(b,a),glContext.bindTexture(glContext.TEXTURE_2D,b),c=!tilesPixelated&&isPowerOfTwo(a.width)&&isPowerOfTwo(a.height)):(a=new Uint8Array([255,255,255,255]),glContext.bindTexture(glContext.TEXTURE_2D,b),glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,1,1,0,glContext.RGBA,glContext.UNSIGNED_BYTE,a));a=tilesPixelated?glContext.NEAREST:glContext.LINEAR;var d=c?glContext.LINEAR_MIPMAP_LINEAR:a;glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_MAG_FILTER,a);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_MIN_FILTER,d);c&&glContext.generateMipmap(glContext.TEXTURE_2D);glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture);return b}}function glDeleteTexture(a){glContext&&glContext.deleteTexture(a)}function glSetTextureData(a,b){glContext&&(ASSERT(!!b&&0<b.width,"Invalid image data."),glContext.bindTexture(glContext.TEXTURE_2D,a),glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,b),glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture))}function glFlush(){if(glEnable&&glContext&&glBatchCount){const a=glBatchAdditive?glContext.ONE:glContext.ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(glContext.SRC_ALPHA,a,glContext.ONE,a);glContext.enable(glContext.BLEND);glContext.bufferSubData(glContext.ARRAY_BUFFER,0,glPositionData,0,glBatchCount*(glPolyMode?gl_INDICES_PER_POLY_VERTEX:gl_INDICES_PER_INSTANCE));glPolyMode?glContext.drawArrays(glContext.TRIANGLE_STRIP,0,glBatchCount):glContext.drawArraysInstanced(glContext.TRIANGLE_STRIP,0,4,glBatchCount);drawCount+=glBatchCount;glBatchCount=0}glBatchAdditive=glAdditive}function glCopyToContext(a){glEnable&&glContext&&(glFlush(),a.drawImage(glCanvas,0,0))}function glSetAntialias(a=!0){ASSERT(!glCanvas,"must be called before engineInit");glAntialias=a}function glDraw(a,b,c,d,e=0,f=0,g=0,h=1,k=1,l=-1,m=0){(glBatchCount>=gl_MAX_INSTANCES||glBatchAdditive!==glAdditive)&&glFlush();glSetInstancedMode();glPolyMode=!1;let n=glBatchCount++*gl_INDICES_PER_INSTANCE;glPositionData[n++]=a;glPositionData[n++]=b;glPositionData[n++]=c;glPositionData[n++]=d;glPositionData[n++]=f;glPositionData[n++]=g;glPositionData[n++]=h;glPositionData[n++]=k;glColorData[n++]=l;glColorData[n++]=m;glPositionData[n++]=e}function glDrawPointsTransform(a,b,c,d,e,f,g,h=!0){const k=[];for(const l of a){a=l.x*e;const m=l.y*f,n=Math.sin(-g),p=Math.cos(-g);k.push(vec2(c+p*a-n*m,d+n*a+p*m))}c=h?glPolyStrip(k):k;glDrawPoints(c,b)}function glDrawOutlineTransform(a,b,c,d,e,f,g,h,k=!0){a=glMakeOutline(a,c,k);glDrawPointsTransform(a,b,d,e,f,g,h,!1)}function glDrawPoints(a,b){if(glEnable&&!(3>a.length)){var c=a.length+2;(glBatchCount+c>=gl_MAX_POLY_VERTEXES||glBatchAdditive!==glAdditive)&&glFlush();glSetPolyMode();var d=glBatchCount*gl_INDICES_PER_POLY_VERTEX;for(let f=c;f--;){var e=clamp(f-1,0,c-3);e=a[e];glPositionData[d++]=e.x;glPositionData[d++]=e.y;glColorData[d++]=b}glBatchCount+=c}}function glDrawColoredPoints(a,b){if(glEnable&&!(3>a.length)){var c=a.length+2;(glBatchCount+c>=gl_MAX_POLY_VERTEXES||glBatchAdditive!==glAdditive)&&glFlush();glSetPolyMode();var d=glBatchCount*gl_INDICES_PER_POLY_VERTEX;for(let f=c;f--;){var e=clamp(f-1,0,c-3);const g=a[e];e=b[e];glPositionData[d++]=g.x;glPositionData[d++]=g.y;glColorData[d++]=e}glBatchCount+=c}}function glMakeOutline(a,b,c=!0){if(2>a.length)return[];const d=b/2,e=[],f=a.length;b*=100;for(let p=0;p<f;p++){var g=a[c?(p-1+f)%f:max(p-1,0)],h=a[p],k=a[c?(p+1)%f:min(p+1,f-1)],l=h.x-g.x,m=h.y-g.y,n=(l*l+m*m)**.5;g=k.x-h.x;const r=k.y-h.y;k=(g*g+r*r)**.5;1e-6>n&&1e-6>k||(m=1e-6<n?-m/n:0,n=1e-6<n?l/n:0,l=m+(1e-6<k?-r/k:0),g=n+(1e-6<k?g/k:0),k=(l*l+g*g)**.5,1e-6>k?(l=m,g=n):(l/=k,g/=k,m=m*l+n*g,1e-6<m&&(m=min(1/m,b),l*=m,g*=m)),m=vec2(h.x-l*d,h.y-g*d),h=vec2(h.x+l*d,h.y+g*d),e.push(m),e.push(h))}1<e.length&&c&&(e.push(e[0]),e.push(e[1]));return e}function glPolyStrip(a){if(3>a.length)return[];const b=(q,u,t)=>(u.x-q.x)*(t.y-q.y)-(u.y-q.y)*(t.x-q.x);0>(q=>{let u=0;for(let t=q.length;t--;)u+=q[t].cross(q[(t+1)%q.length]);return u})(a)&&(a=a.reverse());var c=(q,u,t,w)=>{const x=b(u,t,q);t=b(t,w,q);q=b(w,u,q);return!((-1e-9>x?1:0)+(-1e-9>t?1:0)+(-1e-9>q?1:0)&&(1e-9<x?1:0)+(1e-9<t?1:0)+(1e-9<q?1:0))},d=[];for(var e=0;e<a.length;++e)d[e]=e;e=[];let f=0;const g=a.length**2+100;for(;3<d.length&&f++<g;){var h=!1;for(var k=0;k<d.length;k++){var l=d[(k+d.length-1)%d.length],m=d[k];const q=d[(k+1)%d.length],u=a[l],t=a[m],w=a[q];if(1e-9>b(u,t,w))continue;let x=!1;for(let B=0;B<d.length;B++){const z=d[B];if(z!==l&&z!==m&&z!==q&&(x=c(a[z],u,t,w)))break}if(!x){e.push([l,m,q]);d.splice(k,1);h=!0;break}}if(!h){h=-1;k=Infinity;for(l=0;l<d.length;l++)m=abs(b(a[d[(l+d.length-1)%d.length]],a[d[l]],a[d[(l+1)%d.length]])),m<k&&(k=m,h=l);if(0>h)break;e.push([d[(h+d.length-1)%d.length],d[h],d[(h+1)%d.length]]);d.splice(h,1)}}3===d.length&&e.push([d[0],d[1],d[2]]);if(!e.length)return[];c=[];let[n,p,r]=e[0];c.push(a[n],a[p],a[r]);for(d=1;d<e.length;d++){const[q,u,t]=e[d];c.push(a[r],a[q]);c.push(a[q],a[u],a[t]);r=t}return c}let newgrounds;class NewgroundsMedal extends Medal{constructor(a,b,c,d,e){super(a,b,c,d,e)}unlock(){super.unlock();newgrounds&&newgrounds.unlockMedal(this.id)}}class NewgroundsPlugin{constructor(a,b,c){ASSERT(!newgrounds,"there can only be one newgrounds object");ASSERT(!b||c,"must provide cryptojs if there is a cipher");newgrounds=this;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.value})`);this.scoreboards=(d=this.call("ScoreBoard.getBoards"))?d.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards);setInterval(()=>this.call("Gateway.ping",0,!0),6e4)}}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);try{b.send(a)}catch(e){debugMedals&&console.log("newgrounds call failed",e);return}debugMedals&&console.log(b.responseText);return b.responseText&&JSON.parse(b.responseText)}}let postProcess;class PostProcessPlugin{constructor(a,b=!1){ASSERT(!postProcess,"Post process already initialized");postProcess=this;headlessMode||(glEnable?(a||="void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}",this.shader=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.;}"),this.texture=glCreateTexture(),this.includeOverlay=b,engineAddPlugin(void 0,function(){if(!headlessMode){glEnable?(glFlush(),mainContext.drawImage(glCanvas,0,0)):glContext.viewport(0,0,glCanvas.width=drawCanvas.width,glCanvas.height=drawCanvas.height);postProcess.includeOverlay&&(mainContext.drawImage(overlayCanvas,0,0),overlayCanvas.width|=0);glContext.useProgram(postProcess.shader);glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL,1);glContext.disable(glContext.BLEND);glContext.activeTexture(glContext.TEXTURE0);glContext.bindTexture(glContext.TEXTURE_2D,postProcess.texture);glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,mainCanvas);var c=glContext.getAttribLocation(postProcess.shader,"p");glContext.enableVertexAttribArray(c);glContext.vertexAttribPointer(c,2,glContext.FLOAT,!1,8,0);glContext.uniform1i(glContext.getUniformLocation(postProcess.shader,"iChannel0"),0);glContext.uniform1f(glContext.getUniformLocation(postProcess.shader,"iTime"),time);glContext.uniform3f(glContext.getUniformLocation(postProcess.shader,"iResolution"),mainCanvas.width,mainCanvas.height,1);glContext.drawArrays(glContext.TRIANGLE_STRIP,0,4)}})):console.warn("PostProcessPlugin: WebGL not enabled!"))}}class ZzFXMusic extends Sound{constructor(a){super(void 0);soundEnable&&!headlessMode&&(this.randomness=0,this.sampleChannels=zzfxM(...a),this.sampleRate=audioDefaultSampleRate)}playMusic(a=1,b=!0){return super.play(void 0,a,1,0,b)}}function zzfxM(a,b,c,d=125){let e,f,g,h,k,l,m,n,p,r,q,u,t,w=0,x,B=[],z=[],v=[],y=0,D=0,G=1,J={},H=audioDefaultSampleRate/d*60>>2;for(;G;y++)B=[G=n=u=0],c.forEach((E,K)=>{m=b[E][y]||[0,0,0];G|=b[E][y]&&1;x=u+(b[E][0].length-2-(n?0:1))*H;t=K===c.length-1;e=2;for(g=u;e<m.length+t;n=++e){k=m[e];p=e===m.length+t-1&&t||r!==(m[0]||0)||k|0;for(f=0;f<H&&n;f++>H-99&&p&&1>q?q+=1/99:0)l=(1-q)*B[w++]/2||0,z[g]=(z[g]||0)-l*D+l,v[g]=(v[g++]||0)+l*D+l;k&&(q=k%1,D=m[1]||0,k|=0)&&(B=J[[r=m[w=0]||0,k]]=J[[r,k]]||(h=[...a[r]],h[2]=(h[2]||220)*2**(k/12-1),0<k?zzfxG(...h):[]))}u=x});return[z,v]}let uiSystem;class UISystemPlugin{constructor(a=overlayContext){ASSERT(!uiSystem,"UI system already initialized");uiSystem=this;this.defaultColor=WHITE;this.defaultTextColor=this.defaultLineColor=BLACK;this.defaultButtonColor=hsl(0,0,.7);this.defaultHoverColor=hsl(0,0,.9);this.defaultDisabledColor=hsl(0,0,.3);this.defaultLineWidth=4;this.defaultCornerRadius=0;this.defaultTextScale=.8;this.defaultFont="arial";this.defaultSoundClick=this.defaultSoundRelease=this.defaultSoundPress=void 0;this.uiObjects=[];this.uiContext=a;this.activeObject=this.hoverObject=void 0;engineAddPlugin(function(){function b(d){for(const e of d.children)b(e);d.updateInvisible()}function c(d){if(d.visible){d.parent&&(d.pos=d.localPos.add(d.parent.pos));for(let e=d.children.length;e--;)c(d.children[e]);d.update()}else b(d)}uiSystem.hoverObject=void 0;for(let d=uiSystem.uiObjects.length;d--;){const e=uiSystem.uiObjects[d];e.parent||c(e)}},function(){function b(c){if(c.visible){c.parent&&(c.pos=c.localPos.add(c.parent.pos));c.render();for(const d of c.children)b(d)}}uiSystem.uiObjects.forEach(c=>c.parent||b(c))})}drawRect(a,b,c=uiSystem.defaultColor,d=uiSystem.defaultLineWidth,e=uiSystem.defaultLineColor,f=uiSystem.defaultCornerRadius){const g=uiSystem.uiContext;g.fillStyle=c.toString();g.beginPath();f&&g.roundRect?g.roundRect(a.x-b.x/2,a.y-b.y/2,b.x,b.y,f):g.rect(a.x-b.x/2,a.y-b.y/2,b.x,b.y);g.fill();d&&(g.strokeStyle=e.toString(),g.lineWidth=d,g.stroke())}drawLine(a,b,c=uiSystem.defaultLineWidth,d=uiSystem.defaultLineColor){const e=uiSystem.uiContext;e.strokeStyle=d.toString();e.lineWidth=c;e.beginPath();e.lineTo(a.x,a.y);e.lineTo(b.x,b.y);e.stroke()}drawTile(a,b,c,d=uiSystem.defaultColor,e=0,f=!1){drawTile(a,b,c,d,e,f,CLEAR_BLACK,!1,!0,uiSystem.uiContext)}drawText(a,b,c,d=uiSystem.defaultColor,e=uiSystem.defaultLineWidth,f=uiSystem.defaultLineColor,g="center",h=uiSystem.defaultFont,k=!0){drawTextScreen(a,b,c.y,d,e,f,g,h,k?c.x:void 0,uiSystem.uiContext)}}class UIObject{constructor(a=vec2(),b=vec2()){this.localPos=a.copy();this.pos=a.copy();this.size=b.copy();this.color=uiSystem.defaultColor;this.text=this.activeColor=void 0;this.disabledColor=uiSystem.defaultDisabledColor;this.disabled=!1;this.textColor=uiSystem.defaultTextColor;this.hoverColor=uiSystem.defaultHoverColor;this.lineColor=uiSystem.defaultLineColor;this.lineWidth=uiSystem.defaultLineWidth;this.cornerRadius=uiSystem.defaultCornerRadius;this.font=uiSystem.defaultFont;this.textHeight=this.textWidth=void 0;this.textScale=uiSystem.defaultTextScale;this.visible=!0;this.children=[];this.parent=void 0;this.extraTouchSize=0;this.soundPress=uiSystem.defaultSoundPress;this.soundRelease=uiSystem.defaultSoundRelease;this.soundClick=uiSystem.defaultSoundClick;this.dragActivate=this.interactive=!1;uiSystem.uiObjects.push(this)}addChild(a){ASSERT(!a.parent&&!this.children.includes(a));this.children.push(a);a.parent=this}removeChild(a){ASSERT(a.parent===this&&this.children.includes(a));this.children.splice(this.children.indexOf(a),1);a.parent=void 0}update(){const a=this.isHoverObject(),b=this.isActiveObject(),c=mouseIsDown(0),d=this.dragActivate?c:mouseWasPressed(0);if(!uiSystem.hoverObject&&(d||!c||b)){const e=this.size.add(vec2(isTouchDevice&&this.extraTouchSize||0));isOverlapping(this.pos,e,mousePosScreen)&&(uiSystem.hoverObject=this)}if(this.isHoverObject()&&(d&&inputClearKey(0,0,0,1,0),!this.disabled)){if(d&&this.interactive){this.onPress();this.soundPress&&this.soundPress.play();if(uiSystem.activeObject&&!b)uiSystem.activeObject.onRelease();uiSystem.activeObject=this}!c&&uiSystem.activeObject===this&&this.interactive&&(this.onClick(),this.soundClick&&this.soundClick.play())}!b||c&&this.isHoverObject()||(this.onRelease(),this.soundRelease&&this.soundRelease.play(),uiSystem.activeObject=void 0);this.isHoverObject()!==a&&(this.isHoverObject()?this.onEnter():this.onLeave())}render(){if(this.size.x&&this.size.y){var a=this.interactive&&this.isActiveObject()&&!this.disabled?this.color:this.lineColor,b=this.interactive?this.disabled?this.disabledColor:this.isActiveObject()?this.activeColor||this.color:this.isHoverObject()?this.hoverColor:this.color:this.color;uiSystem.drawRect(this.pos,this.size,b,this.lineWidth,a,this.cornerRadius)}}updateInvisible(){this.isActiveObject()&&(uiSystem.activeObject=void 0)}getTextSize(){return vec2(this.textWidth||this.textScale*this.size.x,this.textHeight||this.textScale*this.size.y)}isHoverObject(){return uiSystem.hoverObject===this}isActiveObject(){return uiSystem.activeObject===this}onEnter(){}onLeave(){}onPress(){}onRelease(){}onClick(){}onChange(){}}class UIText extends UIObject{constructor(a,b,c="",d="center",e=uiSystem.defaultFont){super(a,b);this.text=c;this.align=d;this.font=e;this.lineWidth=0}render(){const a=this.getTextSize();uiSystem.drawText(this.text,this.pos,a,this.textColor,this.lineWidth,this.lineColor,this.align,this.font)}}class UITile extends UIObject{constructor(a,b,c,d=WHITE,e=0,f=!1){super(a,b);this.tileInfo=c;this.angle=e;this.mirror=f;this.color=d}render(){uiSystem.drawTile(this.pos,this.size,this.tileInfo,this.color,this.angle,this.mirror)}}class UIButton extends UIObject{constructor(a,b,c="",d=uiSystem.defaultButtonColor){super(a,b);this.text=c;this.color=d;this.interactive=!0}render(){super.render();const a=this.getTextSize();uiSystem.drawText(this.text,this.pos,a,this.textColor,0,void 0,this.align,this.font)}}class UICheckbox extends UIObject{constructor(a,b,c=!1,d="",e=uiSystem.defaultButtonColor){super(a,b);this.checked=c;this.text=d;this.color=e;this.interactive=!0}onClick(){this.checked=!this.checked;this.onChange()}render(){super.render();if(this.checked){var a=this.cornerRadius/min(this.size.x,this.size.y)*2;a=lerp(1,2**.5/2,a)/2;a=this.size.scale(a);uiSystem.drawLine(this.pos.add(a.multiply(vec2(-1))),this.pos.add(a.multiply(vec2(1))),this.lineWidth,this.lineColor);uiSystem.drawLine(this.pos.add(a.multiply(vec2(-1,1))),this.pos.add(a.multiply(vec2(1,-1))),this.lineWidth,this.lineColor)}a=this.getTextSize();const b=this.pos.add(vec2(this.size.x,0));uiSystem.drawText(this.text,b,a,this.textColor,0,void 0,"left",this.font,!1)}}class UIScrollbar extends UIObject{constructor(a,b,c=.5,d="",e=uiSystem.defaultButtonColor,f=WHITE){super(a,b);this.value=c;this.handleColor=f;this.text=d;this.color=e;this.interactive=!0}update(){super.update();if(this.isActiveObject()&&this.interactive){var a=vec2(this.size.y);a=this.size.x-a.x;const b=this.value;this.value=percent(mousePosScreen.x,this.pos.x-a/2,this.pos.x+a/2);this.value===b||this.onChange()}}render(){super.render();var a=vec2(this.size.y),b=this.size.x-a.x;b=vec2(lerp(this.pos.x-b/2,this.pos.x+b/2,this.value),this.pos.y);const c=this.disabled?this.disabledColor:this.interactive&&this.isActiveObject()?this.color:this.handleColor;uiSystem.drawRect(b,a,c,this.lineWidth,this.lineColor,this.cornerRadius);a=this.getTextSize();uiSystem.drawText(this.text,this.pos,a,this.textColor,0,void 0,this.align,this.font)}}let box2d,box2dDebug=!1;function box2dSetDebug(a){box2dDebug=a}class Box2dObject extends EngineObject{constructor(a=vec2(),b,c,d=0,e,f=box2d.bodyTypeDynamic,g=0){super(a,b,c,d,e,g);b=new box2d.instance.b2BodyDef;b.set_type(f);b.set_position(box2d.vec2dTo(a));b.set_angle(-d);this.body=box2d.world.CreateBody(b);this.body.object=this;this.lineColor=BLACK}destroy(){this.body&&box2d.world.DestroyBody(this.body);this.body=0;super.destroy()}update(){this.pos=box2d.vec2From(this.body.GetPosition());this.angle=-this.body.GetAngle()}render(){this.tileInfo?super.render():this.drawFixtures(this.color,this.lineColor,this.lineWidth)}renderDebugInfo(){var a=!this.getIsAwake();const b=this.getBodyType()===box2d.bodyTypeStatic;a=rgb(a?1:0,a?1:0,b?1:0,.5);this.drawFixtures(a)}drawFixtures(a=WHITE,b,c=.1,d){this.getFixtureList().forEach(e=>box2d.drawFixture(e,this.pos,this.angle,a,b,c,d))}beginContact(a){}endContact(a){}addShape(a,b=1,c=.2,d=0,e=!1){const f=new box2d.instance.b2FixtureDef;f.set_shape(a);f.set_density(b);f.set_friction(c);f.set_restitution(d);f.set_isSensor(e);return this.body.CreateFixture(f)}addBox(a=vec2(1),b=vec2(),c=0,d,e,f,g){const h=new box2d.instance.b2PolygonShape;h.SetAsBox(a.x/2,a.y/2,box2d.vec2dTo(b),c);return this.addShape(h,d,e,f,g)}addPoly(a,b,c,d,e){ASSERT(3<=a.length&&8>=a.length);const f=new box2d.instance.b2PolygonShape;var g=box2d.instance._malloc(8*a.length);for(let h=0,k=0;h<a.length;++h)box2d.instance.HEAPF32[g+k>>2]=a[h].x,k+=4,box2d.instance.HEAPF32[g+k>>2]=a[h].y,k+=4;g=box2d.instance.wrapPointer(g,box2d.instance.b2Vec2);f.Set(g,a.length);return this.addShape(f,b,c,d,e)}addRegularPoly(a=1,b=8,c,d,e,f){const g=[];a/=2;for(let h=b;h--;)g.push(vec2(a,0).rotate((h+.5)/b*PI*2));return this.addPoly(g,c,d,e,f)}addRandomPoly(a=1,b,c,d,e){const f=randInt(3,9),g=[];a/=2;for(let h=f;h--;)g.push(vec2(rand(a/2,1.5*a),0).rotate(h/f*PI*2));return this.addPoly(g,b,c,d,e)}addCircle(a=1,b=vec2(),c,d,e,f){const g=new box2d.instance.b2CircleShape;g.set_m_p(box2d.vec2dTo(b));g.set_m_radius(a/2);return this.addShape(g,c,d,e,f)}addEdge(a,b,c,d,e,f){const g=new box2d.instance.b2EdgeShape;g.Set(box2d.vec2dTo(a),box2d.vec2dTo(b));return this.addShape(g,c,d,e,f)}addEdgeLoop(a,b,c,d,e){const f=[];for(let h=0;h<a.length;++h){var g=new box2d.instance.b2EdgeShape;g.set_m_vertex0(box2d.vec2dTo(a[mod(h-1,a.length)]));g.set_m_vertex1(box2d.vec2dTo(a[mod(h+0,a.length)]));g.set_m_vertex2(box2d.vec2dTo(a[mod(h+1,a.length)]));g.set_m_vertex3(box2d.vec2dTo(a[mod(h+2,a.length)]));g=this.addShape(g,b,c,d,e);f.push(g)}return f}addEdgeList(a,b,c,d,e){const f=[];for(let h=0;h<a.length-1;++h){var g=new box2d.instance.b2EdgeShape;a[h-1]&&g.set_m_vertex0(box2d.vec2dTo(a[h-1]));a[h+0]&&g.set_m_vertex1(box2d.vec2dTo(a[h+0]));a[h+1]&&g.set_m_vertex2(box2d.vec2dTo(a[h+1]));a[h+2]&&g.set_m_vertex3(box2d.vec2dTo(a[h+2]));g=this.addShape(g,b,c,d,e);f.push(g)}return f}getCenterOfMass(){return box2d.vec2From(this.body.GetWorldCenter())}getLinearVelocity(){return box2d.vec2From(this.body.GetLinearVelocity())}getAngularVelocity(){return this.body.GetAngularVelocity()}getMass(){return this.body.GetMass()}getInertia(){return this.body.GetInertia()}getIsAwake(){return this.body.IsAwake()}getBodyType(){return this.body.GetType()}setTransform(a,b){this.pos=a;this.angle=b;this.body.SetTransform(box2d.vec2dTo(a),b)}setPosition(a){this.setTransform(a,this.body.GetAngle())}setAngle(a){this.setTransform(box2d.vec2From(this.body.GetPosition()),-a)}setLinearVelocity(a){this.body.SetLinearVelocity(box2d.vec2dTo(a))}setAngularVelocity(a){this.body.SetAngularVelocity(a)}setLinearDamping(a){this.body.SetLinearDamping(a)}setAngularDamping(a){this.body.SetAngularDamping(a)}setGravityScale(a=1){this.body.SetGravityScale(this.gravityScale=a)}setBullet(a=!0){this.body.SetBullet(a)}setAwake(a=!0){this.body.SetAwake(a)}setBodyType(a){this.body.SetType(a)}setSleepingAllowed(a=!0){this.body.SetSleepingAllowed(a)}setFixedRotation(a=!0){this.body.SetFixedRotation(a)}setCenterOfMass(a){this.setMassData(a)}setMass(a){this.setMassData(void 0,a)}setMomentOfInertia(a){this.setMassData(void 0,void 0,a)}resetMassData(){this.body.ResetMassData()}setMassData(a,b,c){const d=new box2d.instance.b2MassData;this.body.GetMassData(d);a&&d.set_center(box2d.vec2dTo(a));b&&d.set_mass(b);c&&d.set_I(c);this.body.SetMassData(d)}setFilterData(a=0,b=0,c=0){this.getFixtureList().forEach(d=>{d=d.GetFilterData();d.set_categoryBits(a);d.set_maskBits(65535&~b);d.set_groupIndex(c)})}setSensor(a=!0){this.getFixtureList().forEach(b=>b.SetSensor(a))}applyForce(a,b){b||=this.getCenterOfMass();this.setAwake();this.body.ApplyForce(box2d.vec2dTo(a),box2d.vec2dTo(b))}applyAcceleration(a,b){b||=this.getCenterOfMass();this.setAwake();this.body.ApplyLinearImpulse(box2d.vec2dTo(a),box2d.vec2dTo(b))}applyTorque(a){this.setAwake();this.body.ApplyTorque(a)}applyAngularAcceleration(a){this.setAwake();this.body.ApplyAngularImpulse(a)}hasFixtures(){return!box2d.isNull(this.body.GetFixtureList())}getFixtureList(){const a=[];for(let b=this.body.GetFixtureList();!box2d.isNull(b);)a.push(b),b=b.GetNext();return a}hasJoints(){return!box2d.isNull(this.body.GetJointList())}getJointList(){const a=[];for(let b=this.body.GetJointList();!box2d.isNull(b);)a.push(b),b=b.get_next();return a}}class Box2dRaycastResult{constructor(a,b,c,d){this.object=a.GetBody().object;this.fixture=a;this.point=b;this.normal=c;this.fraction=d}}class Box2dJoint{constructor(a){this.box2dJoint=box2d.castObjectType(box2d.world.CreateJoint(a))}destroy(){box2d.world.DestroyJoint(this.box2dJoint);this.box2dJoint=0}getObjectA(){return this.box2dJoint.GetBodyA().object}getObjectB(){return this.box2dJoint.GetBodyB().object}getAnchorA(){return box2d.vec2From(this.box2dJoint.GetAnchorA())}getAnchorB(){return box2d.vec2From(this.box2dJoint.GetAnchorB())}getReactionForce(a){return box2d.vec2From(this.box2dJoint.GetReactionForce(1/a))}getReactionTorque(a){return this.box2dJoint.GetReactionTorque(1/a)}getCollideConnected(){return this.box2dJoint.getCollideConnected()}isActive(){return this.box2dJoint.IsActive()}}class Box2dTargetJoint extends Box2dJoint{constructor(a,b,c){a.setAwake();const d=new box2d.instance.b2MouseJointDef;d.set_bodyA(b.body);d.set_bodyB(a.body);d.set_target(box2d.vec2dTo(c));d.set_maxForce(2e3*a.getMass());super(d)}setTarget(a){this.box2dJoint.SetTarget(box2d.vec2dTo(a))}getTarget(){return box2d.vec2From(this.box2dJoint.GetTarget())}setMaxForce(a){this.box2dJoint.SetMaxForce(a)}getMaxForce(){return this.box2dJoint.GetMaxForce()}setFrequency(a){this.box2dJoint.SetFrequency(a)}getFrequency(){return this.box2dJoint.GetFrequency()}}class Box2dDistanceJoint extends Box2dJoint{constructor(a,b,c,d,e=!1){c||=box2d.vec2From(a.body.GetPosition());d||=box2d.vec2From(b.body.GetPosition());const f=a.worldToLocal(c),g=b.worldToLocal(d),h=new box2d.instance.b2DistanceJointDef;h.set_bodyA(a.body);h.set_bodyB(b.body);h.set_localAnchorA(box2d.vec2dTo(f));h.set_localAnchorB(box2d.vec2dTo(g));h.set_length(c.distance(d));h.set_collideConnected(e);super(h)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}setLength(a){this.box2dJoint.SetLength(a)}getLength(){return this.box2dJoint.GetLength()}setFrequency(a){this.box2dJoint.SetFrequency(a)}getFrequency(){return this.box2dJoint.GetFrequency()}setDampingRatio(a){this.box2dJoint.SetDampingRatio(a)}getDampingRatio(){return this.box2dJoint.GetDampingRatio()}}class Box2dPinJoint extends Box2dDistanceJoint{constructor(a,b,c=a.pos,d=!1){super(a,b,void 0,c,d)}}class Box2dRopeJoint extends Box2dJoint{constructor(a,b,c,d,e=0,f=!1){c||=box2d.vec2From(a.body.GetPosition());d||=box2d.vec2From(b.body.GetPosition());const g=a.worldToLocal(c),h=b.worldToLocal(d),k=new box2d.instance.b2RopeJointDef;k.set_bodyA(a.body);k.set_bodyB(b.body);k.set_localAnchorA(box2d.vec2dTo(g));k.set_localAnchorB(box2d.vec2dTo(h));k.set_maxLength(c.distance(d)+e);k.set_collideConnected(f);super(k)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}setMaxLength(a){this.box2dJoint.SetMaxLength(a)}getMaxLength(){return this.box2dJoint.GetMaxLength()}}class Box2dRevoluteJoint extends Box2dJoint{constructor(a,b,c,d=!1){c||=box2d.vec2From(b.body.GetPosition());const e=a.worldToLocal(c);c=b.worldToLocal(c);const f=new box2d.instance.b2RevoluteJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_localAnchorA(box2d.vec2dTo(e));f.set_localAnchorB(box2d.vec2dTo(c));f.set_referenceAngle(a.body.GetAngle()-b.body.GetAngle());f.set_collideConnected(d);super(f)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getReferenceAngle(){return this.box2dJoint.GetReferenceAngle()}getJointAngle(){return this.box2dJoint.GetJointAngle()}getJointSpeed(){return this.box2dJoint.GetJointSpeed()}isLimitEnabled(){return this.box2dJoint.IsLimitEnabled()}enableLimit(a=!0){return this.box2dJoint.enableLimit(a)}getLowerLimit(){return this.box2dJoint.GetLowerLimit()}getUpperLimit(){return this.box2dJoint.GetUpperLimit()}setLimits(a,b){return this.box2dJoint.SetLimits(a,b)}isMotorEnabled(){return this.box2dJoint.IsMotorEnabled()}enableMotor(a=!0){return this.box2dJoint.EnableMotor(a)}setMotorSpeed(a){return this.box2dJoint.SetMotorSpeed(a)}getMotorSpeed(){return this.box2dJoint.GetMotorSpeed()}setMaxMotorTorque(a){return this.box2dJoint.SetMaxMotorTorque(a)}getMaxMotorTorque(){return this.box2dJoint.GetMaxMotorTorque()}getMotorTorque(a){return this.box2dJoint.GetMotorTorque(1/a)}}class Box2dGearJoint extends Box2dJoint{constructor(a,b,c,d,e=1){const f=new box2d.instance.b2GearJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_joint1(c.box2dJoint);f.set_joint2(d.box2dJoint);f.set_ratio(e);super(f);this.joint1=c;this.joint2=d}getJoint1(){return this.joint1}getJoint2(){return this.joint2}setRatio(a){return this.box2dJoint.SetRatio(a)}getRatio(){return this.box2dJoint.GetRatio()}}class Box2dPrismaticJoint extends Box2dJoint{constructor(a,b,c,d=vec2(0,1),e=!1){c||=box2d.vec2From(b.body.GetPosition());const f=a.worldToLocal(c);c=b.worldToLocal(c);d=b.worldToLocalVector(d);const g=new box2d.instance.b2PrismaticJointDef;g.set_bodyA(a.body);g.set_bodyB(b.body);g.set_localAnchorA(box2d.vec2dTo(f));g.set_localAnchorB(box2d.vec2dTo(c));g.set_localAxisA(box2d.vec2dTo(d));g.set_referenceAngle(a.body.GetAngle()-b.body.GetAngle());g.set_collideConnected(e);super(g)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getLocalAxisA(){return box2d.vec2From(this.box2dJoint.GetLocalAxisA())}getReferenceAngle(){return this.box2dJoint.GetReferenceAngle()}getJointTranslation(){return this.box2dJoint.GetJointTranslation()}getJointSpeed(){return this.box2dJoint.GetJointSpeed()}isLimitEnabled(){return this.box2dJoint.IsLimitEnabled()}enableLimit(a=!0){return this.box2dJoint.enableLimit(a)}getLowerLimit(){return this.box2dJoint.GetLowerLimit()}getUpperLimit(){return this.box2dJoint.GetUpperLimit()}setLimits(a,b){return this.box2dJoint.SetLimits(a,b)}isMotorEnabled(){return this.box2dJoint.IsMotorEnabled()}enableMotor(a=!0){return this.box2dJoint.EnableMotor(a)}setMotorSpeed(a){return this.box2dJoint.SetMotorSpeed(a)}getMotorSpeed(){return this.box2dJoint.GetMotorSpeed()}setMaxMotorForce(a){return this.box2dJoint.SetMaxMotorForce(a)}getMaxMotorForce(){return this.box2dJoint.GetMaxMotorForce()}getMotorForce(a){return this.box2dJoint.GetMotorForce(1/a)}}class Box2dWheelJoint extends Box2dJoint{constructor(a,b,c,d=vec2(0,1),e=!1){c||=box2d.vec2From(b.body.GetPosition());const f=a.worldToLocal(c);c=b.worldToLocal(c);d=b.worldToLocalVector(d);const g=new box2d.instance.b2WheelJointDef;g.set_bodyA(a.body);g.set_bodyB(b.body);g.set_localAnchorA(box2d.vec2dTo(f));g.set_localAnchorB(box2d.vec2dTo(c));g.set_localAxisA(box2d.vec2dTo(d));g.set_collideConnected(e);super(g)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getLocalAxisA(){return box2d.vec2From(this.box2dJoint.GetLocalAxisA())}getJointTranslation(){return this.box2dJoint.GetJointTranslation()}getJointSpeed(){return this.box2dJoint.GetJointSpeed()}isMotorEnabled(){return this.box2dJoint.IsMotorEnabled()}enableMotor(a=!0){return this.box2dJoint.EnableMotor(a)}setMotorSpeed(a){return this.box2dJoint.SetMotorSpeed(a)}getMotorSpeed(){return this.box2dJoint.GetMotorSpeed()}setMaxMotorTorque(a){return this.box2dJoint.SetMaxMotorTorque(a)}getMaxMotorTorque(){return this.box2dJoint.GetMaxMotorTorque()}getMotorTorque(a){return this.box2dJoint.GetMotorTorque(1/a)}setSpringFrequencyHz(a){return this.box2dJoint.SetSpringFrequencyHz(a)}getSpringFrequencyHz(){return this.box2dJoint.GetSpringFrequencyHz()}setSpringDampingRatio(a){return this.box2dJoint.SetSpringDampingRatio(a)}getSpringDampingRatio(){return this.box2dJoint.GetSpringDampingRatio()}}class Box2dWeldJoint extends Box2dJoint{constructor(a,b,c,d=!1){c||=box2d.vec2From(b.body.GetPosition());const e=a.worldToLocal(c);c=b.worldToLocal(c);const f=new box2d.instance.b2WeldJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_localAnchorA(box2d.vec2dTo(e));f.set_localAnchorB(box2d.vec2dTo(c));f.set_referenceAngle(a.body.GetAngle()-b.body.GetAngle());f.set_collideConnected(d);super(f)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getReferenceAngle(){return this.box2dJoint.GetReferenceAngle()}setFrequency(a){return this.box2dJoint.SetFrequency(a)}getFrequency(){return this.box2dJoint.GetFrequency()}setSpringDampingRatio(a){return this.box2dJoint.SetSpringDampingRatio(a)}getSpringDampingRatio(){return this.box2dJoint.GetSpringDampingRatio()}}class Box2dFrictionJoint extends Box2dJoint{constructor(a,b,c,d=!1){c||=box2d.vec2From(b.body.GetPosition());const e=a.worldToLocal(c);c=b.worldToLocal(c);const f=new box2d.instance.b2FrictionJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_localAnchorA(box2d.vec2dTo(e));f.set_localAnchorB(box2d.vec2dTo(c));f.set_collideConnected(d);super(f)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}setMaxForce(a){this.box2dJoint.SetMaxForce(a)}getMaxForce(){return this.box2dJoint.GetMaxForce()}setMaxTorque(a){this.box2dJoint.SetMaxTorque(a)}getMaxTorque(){return this.box2dJoint.GetMaxTorque()}}class Box2dPulleyJoint extends Box2dJoint{constructor(a,b,c,d,e,f,g=1,h=!1){e||=box2d.vec2From(a.body.GetPosition());f||=box2d.vec2From(b.body.GetPosition());const k=a.worldToLocal(e),l=b.worldToLocal(f),m=new box2d.instance.b2PulleyJointDef;m.set_bodyA(a.body);m.set_bodyB(b.body);m.set_groundAnchorA(box2d.vec2dTo(c));m.set_groundAnchorB(box2d.vec2dTo(d));m.set_localAnchorA(box2d.vec2dTo(k));m.set_localAnchorB(box2d.vec2dTo(l));m.set_ratio(g);m.set_lengthA(c.distance(e));m.set_lengthB(d.distance(f));m.set_collideConnected(h);super(m)}getGroundAnchorA(){return box2d.vec2From(this.box2dJoint.GetGroundAnchorA())}getGroundAnchorB(){return box2d.vec2From(this.box2dJoint.GetGroundAnchorB())}getLengthA(){return this.box2dJoint.GetLengthA()}getLengthB(){return this.box2dJoint.GetLengthB()}getRatio(){return this.box2dJoint.GetRatio()}getCurrentLengthA(){return this.box2dJoint.GetCurrentLengthA()}getCurrentLengthB(){return this.box2dJoint.GetCurrentLengthB()}}class Box2dMotorJoint extends Box2dJoint{constructor(a,b){const c=a.worldToLocal(box2d.vec2From(b.body.GetPosition())),d=b.body.GetAngle()-a.body.GetAngle(),e=new box2d.instance.b2MotorJointDef;e.set_bodyA(a.body);e.set_bodyB(b.body);e.set_linearOffset(box2d.vec2dTo(c));e.set_angularOffset(d);super(e)}setLinearOffset(a){this.box2dJoint.SetLinearOffset(box2d.vec2dTo(a))}getLinearOffset(){return box2d.vec2From(this.box2dJoint.GetLinearOffset())}setAngularOffset(a){this.box2dJoint.SetAngularOffset(a)}getAngularOffset(){return this.box2dJoint.GetAngularOffset()}setMaxForce(a){this.box2dJoint.SetMaxForce(a)}getMaxForce(){return this.box2dJoint.GetMaxForce()}setMaxTorque(a){this.box2dJoint.SetMaxTorque(a)}getMaxTorque(){return this.box2dJoint.GetMaxTorque()}setCorrectionFactor(a){this.box2dJoint.SetCorrectionFactor(a)}getCorrectionFactor(){return this.box2dJoint.GetCorrectionFactor()}}class Box2dPlugin{constructor(a){ASSERT(!box2d,"Box2D already initialized");box2d=this;this.instance=a;this.world=new box2d.instance.b2World;this.velocityIterations=8;this.positionIterations=3;this.bodyTypeStatic=a.b2_staticBody;this.bodyTypeKinematic=a.b2_kinematicBody;this.bodyTypeDynamic=a.b2_dynamicBody;a=new box2d.instance.JSContactListener;a.BeginContact=function(b){var c=box2d.instance.wrapPointer(b,box2d.instance.b2Contact);b=c.GetFixtureA();c=c.GetFixtureB();b=b.GetBody().object;c=c.GetBody().object;b.beginContact(c);c.beginContact(b)};a.EndContact=function(b){var c=box2d.instance.wrapPointer(b,box2d.instance.b2Contact);b=c.GetFixtureA();c=c.GetFixtureB();b=b.GetBody().object;c=c.GetBody().object;b.endContact(c);c.endContact(b)};a.PreSolve=function(){};a.PostSolve=function(){};box2d.world.SetContactListener(a)}step(a=1){for(box2d.world.SetGravity(box2d.vec2dTo(gravity));a--;)box2d.world.Step(timeDelta,this.velocityIterations,this.positionIterations)}raycastAll(a,b){const c=new box2d.instance.JSRayCastCallback;c.ReportFixture=function(e,f,g,h){e=box2d.instance.wrapPointer(e,box2d.instance.b2Fixture);f=box2d.vec2FromPointer(f);g=box2d.vec2FromPointer(g);d.push(new Box2dRaycastResult(e,f,g,h));return 1};const d=[];box2d.world.RayCast(c,box2d.vec2dTo(a),box2d.vec2dTo(b));debugRaycast&&debugLine(a,b,d.length?"#f00":"#00f",.02);return d}raycast(a,b){a=box2d.raycastAll(a,b);if(a.length)return a.reduce((c,d)=>c.fraction<d.fraction?c:d)}boxCastAll(a,b){const c=new box2d.instance.JSQueryCallback;c.ReportFixture=function(f){f=box2d.instance.wrapPointer(f,box2d.instance.b2Fixture).GetBody().object;e.includes(f)||e.push(f);return!0};const d=new box2d.instance.b2AABB;d.set_lowerBound(box2d.vec2dTo(a.subtract(b.scale(.5))));d.set_upperBound(box2d.vec2dTo(a.add(b.scale(.5))));let e=[];box2d.world.QueryAABB(c,d);debugRaycast&&debugRect(a,b,e.length?"#f00":"#00f",.02);return e}boxCast(a,b){const c=new box2d.instance.JSQueryCallback;c.ReportFixture=function(f){e=box2d.instance.wrapPointer(f,box2d.instance.b2Fixture).GetBody().object;return!1};const d=new box2d.instance.b2AABB;d.set_lowerBound(box2d.vec2dTo(a.subtract(b.scale(.5))));d.set_upperBound(box2d.vec2dTo(a.add(b.scale(.5))));let e;box2d.world.QueryAABB(c,d);debugRaycast&&debugRect(a,b,e?"#f00":"#00f",.02);return e}circleCastAll(a,b){const c=(b/2)**2;return box2d.boxCastAll(a,vec2(b)).filter(d=>d.pos.distanceSquared(a)<c)}circleCast(a,b){const c=(b/2)**2;b=box2d.boxCastAll(a,vec2(b));let d,e;for(const f of b)b=f.pos.distanceSquared(a),b<c&&(!d||b<e)&&(d=f,e=b);return d}pointCast(a,b=!0){const c=new box2d.instance.JSQueryCallback;c.ReportFixture=function(f){f=box2d.instance.wrapPointer(f,box2d.instance.b2Fixture);if(b&&f.GetBody().GetType()!==box2d.instance.b2_dynamicBody||!f.TestPoint(box2d.vec2dTo(a)))return!0;e=f.GetBody().object;return!1};const d=new box2d.instance.b2AABB;d.set_lowerBound(box2d.vec2dTo(a));d.set_upperBound(box2d.vec2dTo(a));let e;box2d.world.QueryAABB(c,d);debugRaycast&&debugRect(a,vec2(),e?"#f00":"#00f",.02);return e}drawFixture(a,b,c,d=WHITE,e=BLACK,f=.1,g){a=box2d.castObjectType(a.GetShape());switch(a.GetType()){case box2d.instance.b2Shape.e_polygon:g=[];for(let h=a.GetVertexCount();h--;)g.push(box2d.vec2From(a.GetVertex(h)));drawPoly(g,d,f,e,b,c);break;case box2d.instance.b2Shape.e_circle:c=a.get_m_radius();drawCircle(b,2*c,d,f,e);break;case box2d.instance.b2Shape.e_edge:d=box2d.vec2From(a.get_m_vertex1()),a=box2d.vec2From(a.get_m_vertex2()),drawLine(d,a,f,e,b,c)}}vec2From(a){ASSERT(a instanceof box2d.instance.b2Vec2);return new Vector2(a.get_x(),a.get_y())}vec2FromPointer(a){return box2d.vec2From(box2d.instance.wrapPointer(a,box2d.instance.b2Vec2))}vec2dTo(a){ASSERT(a instanceof Vector2);return new box2d.instance.b2Vec2(a.x,a.y)}isNull(a){return!box2d.instance.getPointer(a)}castObjectType(a){switch(a.GetType()){case box2d.instance.b2Shape.e_circle:return box2d.instance.castObject(a,box2d.instance.b2CircleShape);case box2d.instance.b2Shape.e_edge:return box2d.instance.castObject(a,box2d.instance.b2EdgeShape);case box2d.instance.b2Shape.e_polygon:return box2d.instance.castObject(a,box2d.instance.b2PolygonShape);case box2d.instance.b2Shape.e_chain:return box2d.instance.castObject(a,box2d.instance.b2ChainShape);case box2d.instance.e_revoluteJoint:return box2d.instance.castObject(a,box2d.instance.b2RevoluteJoint);case box2d.instance.e_prismaticJoint:return box2d.instance.castObject(a,box2d.instance.b2PrismaticJoint);case box2d.instance.e_distanceJoint:return box2d.instance.castObject(a,box2d.instance.b2DistanceJoint);case box2d.instance.e_pulleyJoint:return box2d.instance.castObject(a,box2d.instance.b2PulleyJoint);case box2d.instance.e_mouseJoint:return box2d.instance.castObject(a,box2d.instance.b2MouseJoint);case box2d.instance.e_gearJoint:return box2d.instance.castObject(a,box2d.instance.b2GearJoint);case box2d.instance.e_wheelJoint:return box2d.instance.castObject(a,box2d.instance.b2WheelJoint);case box2d.instance.e_weldJoint:return box2d.instance.castObject(a,box2d.instance.b2WeldJoint);case box2d.instance.e_frictionJoint:return box2d.instance.castObject(a,box2d.instance.b2FrictionJoint);case box2d.instance.e_ropeJoint:return box2d.instance.castObject(a,box2d.instance.b2RopeJoint);case box2d.instance.e_motorJoint:return box2d.instance.castObject(a,box2d.instance.b2MotorJoint)}ASSERT(!1,"Unknown box2d object type")}}async function box2dInit(){new Box2dPlugin(await Box2D());(function(){const a=new box2d.instance.JSDraw,b=d=>{d=box2d.instance.wrapPointer(d,box2d.instance.b2Color);return new Color(d.get_r(),d.get_g(),d.get_b())},c=(d,e)=>{const f=[];for(;e--;)f.push(box2d.vec2FromPointer(d+8*e));return f};a.DrawSegment=function(d,e,f){f=b(f).scale(1,.8);d=box2d.vec2FromPointer(d);e=box2d.vec2FromPointer(e);drawLine(d,e,.1,f,vec2(),0,!1,!1,overlayContext)};a.DrawPolygon=function(d,e,f){f=b(f).scale(1,.8);d=c(d,e);drawPoly(d,CLEAR_WHITE,.1,f,vec2(),0,!1,!1,overlayContext)};a.DrawSolidPolygon=function(d,e,f){f=b(f).scale(1,.8);d=c(d,e);drawPoly(d,f,0,f,vec2(),0,!1,!1,overlayContext)};a.DrawCircle=function(d,e,f){f=b(f).scale(1,.8);d=box2d.vec2FromPointer(d);drawCircle(d,2*e,CLEAR_WHITE,.1,f,!1,!1,overlayContext)};a.DrawSolidCircle=function(d,e,f,g){g=b(g).scale(1,.8);d=box2d.vec2FromPointer(d);f=box2d.vec2FromPointer(f).scale(e);drawCircle(d,2*e,g,.1,g,!1,!1,overlayContext);drawLine(vec2(),f,.1,g,d,0,!1,!1,overlayContext)};a.DrawTransform=function(d){d=box2d.instance.wrapPointer(d,box2d.instance.b2Transform);const e=vec2(d.get_p());d=-d.get_q().GetAngle();const f=vec2(1,0),g=rgb(.75,0,0,.8),h=vec2(0,1),k=rgb(0,.75,0,.8);drawLine(vec2(),f,.1,g,e,d,!1,!1,overlayContext);drawLine(vec2(),h,.1,k,e,d,!1,!1,overlayContext)};a.AppendFlags(box2d.instance.b2Draw.e_shapeBit);a.AppendFlags(box2d.instance.b2Draw.e_jointBit);box2d.world.SetDebugDraw(a)})();engineAddPlugin(function(){paused||box2d.step()},function(){(box2dDebug||debugPhysics&&debugOverlay)&&box2d.world.DrawDebugData()});return box2d}function drawNineSliceScreen(a,b,c,d=32,e=2,f=0){drawNineSlice(a,b,c,WHITE,d,BLACK,e,f,!1,!0,overlayContext)}function drawNineSlice(a,b,c,d,e=1,f,g=.05,h=0,k=glEnable,l,m){const n=c.offset(c.size);var p=b.add(vec2(g-2*e));g=vec2(e);b=b.scale(.5).subtract(g.scale(.5));const r=l?-1:1,q=l?-h:h;drawTile(a,p,n,d,h,!1,f,k,l,m);for(var u=4;u--;){var t=u%2,w=b.multiply(vec2(t?1===u?1:-1:0,t?0:u?-1:1));t=vec2(t?e:p.x,t?p.y:e);const x=n.offset(c.size.multiply(vec2(1===u?1:3===u?-1:0,0===u?-r:2===u?r:0)));drawTile(a.add(w.rotate(q)),t,x,d,h,!1,f,k,l,m)}for(e=4;e--;)u=1<e,w=e&&3>e,p=b.multiply(vec2(u?-1:1,w?-1:1)),u=n.offset(c.size.multiply(vec2(u?-1:1,w?r:-r))),drawTile(a.add(p.rotate(q)),g,u,d,h,!1,f,k,l,m)}function drawThreeSliceScreen(a,b,c,d=32,e=2,f=0){drawThreeSlice(a,b,c,WHITE,d,BLACK,e,f,!1,!0,overlayContext)}function drawThreeSlice(a,b,c,d,e=1,f,g=.05,h=0,k=glEnable,l,m){const n=c.frame(0);var p=c.frame(1),r=c.frame(2),q=b.add(vec2(g-2*e));g=vec2(e);b=b.scale(.5).subtract(g.scale(.5));c=l?-1:1;const u=l?-h:h;drawTile(a,q,r,d,h,!1,f,k,l,m);for(r=4;r--;){const w=h+r*PI/2;var t=r%2;const x=b.multiply(vec2(t?1===r?1:-1:0,t?0:r?-c:c));t=vec2(t?q.y:q.x,e);drawTile(a.add(x.rotate(u)),t,p,d,w,!1,f,k,l,m)}for(e=4;e--;)p=h+e*PI/2,q=b.multiply(vec2(!e||2<e?-1:1,1<e?-c:c)),drawTile(a.add(q.rotate(u)),g,n,d,p,!1,f,k,l,m)}
|